Caddi
Sign inSign up

@caddi/forms-sdk

A ~1.5kB client helper for posting to a Caddi form endpoint, including presigned file uploads.

Install

bash
pnpm add @caddi/forms-sdk
# or
npm install @caddi/forms-sdk

submit(opts)

ts
import { submit } from '@caddi/forms-sdk';

type SubmitResult =
  | { ok: true; id: string }
  | { ok: false; errors: Record<string, string> };

const res = await submit({
  endpoint: process.env.NEXT_PUBLIC_CADDI_FORM_URL!,
  fields: {
    name: 'Alicia Tran',
    email: '[email protected]',
    message: 'hi',
  },
  files: [resumeFile],          // optional, browser File[] objects
  idempotencyKey: crypto.randomUUID(),
  honeypot: extraTrapField,     // optional
}) satisfies SubmitResult;

Options

  • endpoint — required. The per-project URL Caddi gave you.
  • fields — required. Plain object of strings, numbers, booleans.
  • files — optional. File[] from an <input type="file">.
  • idempotencyKey — optional. Use one per submit attempt to dedupe retries.
  • honeypot — optional. Pass any extra field to silently mark as spam.

How file uploads work

When you pass files, the SDK first POSTs metadata to your endpoint and gets back presigned R2 URLs. It uploads each file directly to R2 (no proxy through your server) and then notifies the endpoint that uploads are complete.

bash
# What the SDK does on your behalf:
1. POST {endpoint}              → { id, presigned: [{ key, url, ... }] }
2. PUT {presigned[i].url}       → file bytes, direct to R2
3. POST {endpoint}/finalize     → { ok: true }

Errors

The result is a discriminated union. On ok: false, you get a errors map keyed by field. Network errors throw — wrap in try/catch.