Skip to content

Implement @singleton-sd/post-kit-client package #24

Description

@patoperpetua

Parent: #4
Depends on: #17, #23

Goal

Create packages/post-kit-client — a thin, typed npm package for trusted server-side Node.js/TypeScript consumers to call the PostKit API. Consumers use this SDK instead of hand-rolling HTTP calls, auth headers, or error handling.

Scope

Package setup

  • Path: packages/post-kit-client
  • npm name: @singleton-sd/post-kit-client
  • TypeScript ESM, Node.js >= 20, node --test, src/**/*.spec.ts convention
  • Runtime dependencies: @singleton-sd/post-kit-types only — use native fetch (no extra HTTP libraries)
  • Public npm publication under Singleton SD scope
  • Mirror tsconfig and package.json conventions of packages/post-kit-email

Desired API

import { PostKitClient } from '@singleton-sd/post-kit-client';

const postKit = new PostKitClient({
  endpoint: process.env.POSTKIT_URL!,
  apiKey: process.env.POSTKIT_API_KEY!,
});

await postKit.send({
  template: 'marketing.contact-us',
  to: 'hello@example.com',
  variables: { name, email, message },
});

Client constructor options

interface PostKitClientOptions {
  endpoint: string;           // Base URL of the PostKit API
  apiKey: string;             // Bearer token for Authorization header
  timeout?: number;           // Request timeout ms (default: 30_000)
  fetch?: typeof globalThis.fetch;  // Injectable for testing
}

send(request: SendRequest): Promise<SendResponse>

  • Sends POST {endpoint}/emails/send with Authorization: Bearer {apiKey}
  • Request body: SendRequest from @singleton-sd/post-kit-types
  • Success: returns SendResponse
  • Non-2xx: throws PostKitRequestError (see below)
  • Timeout: throws PostKitRequestError with code TIMEOUT
  • Network failure: throws PostKitRequestError with code NETWORK_ERROR

Error class

class PostKitRequestError extends Error {
  readonly status: number | undefined;    // HTTP status if available
  readonly code: string;                  // PostKitErrorCode or 'TIMEOUT' | 'NETWORK_ERROR'
  readonly correlationId: string | undefined;
}

AbortSignal / timeout

  • Accept an AbortSignal on send() options: send(request, { signal?: AbortSignal })
  • If neither signal nor client-level timeout produces a timeout, the request runs indefinitely — document this.

Browser safety

  • No automatic secret sourcing from browser globals.
  • README must clearly state this package is for trusted server-side use and include a note about public forms using a server endpoint intermediary.

Constraints

  • Keep the package thin — no business logic, no template rendering, no provider details.
  • Do not add HTTP libraries (axios, got, etc.) — native fetch only.
  • Do not duplicate type definitions — import all request/response types from @singleton-sd/post-kit-types.
  • Auth strategy (Bearer header) must be configurable without breaking the send() API surface — define it in PostKitClientOptions so it can evolve.
  • Tests must not make real HTTP calls — inject a mock fetch.

Acceptance criteria

  • PostKitClient.send() serialises a SendRequest and returns a typed SendResponse.
  • Authorization: Bearer header is set from apiKey.
  • Non-2xx responses throw PostKitRequestError with correct status, code, and correlationId.
  • Request timeout (client-level option) aborts the fetch and throws PostKitRequestError with code TIMEOUT.
  • Custom AbortSignal on send() is threaded through to fetch.
  • Injected fetch is used in tests — no real HTTP calls.
  • README documents server-side-only usage, auth config, and the public-form intermediary pattern.
  • Package compiles cleanly and exports correct types.
  • pnpm -r --if-present run test passes.
  • Package is configured for public npm publication.

Agent implementation notes

Read packages/post-kit-email/package.json and tsconfig before scaffolding. Read the send endpoint issue (#23) to confirm the exact request/response shape before finalising the client. The client should not be published until issue #23 (send endpoint) is merged — the API contract should be stable. Branch: feat/24-post-kit-client.

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-readyMeets every criterion in docs/github-source-of-truth.md, section 4 — safe for an agent to claimenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions