Skip to content

feat(sdk-claim): PR-A3 — claim.ts implementation against api.foxbook.dev#56

Merged
cloakmaster merged 2 commits intomainfrom
chore/pra3-sdk-claim-impl
May 1, 2026
Merged

feat(sdk-claim): PR-A3 — claim.ts implementation against api.foxbook.dev#56
cloakmaster merged 2 commits intomainfrom
chore/pra3-sdk-claim-impl

Conversation

@cloakmaster
Copy link
Copy Markdown
Owner

Implements the three claim primitives (claimStart / claimVerifyGist / claimRevoke) of the SDK against the deployed api.foxbook.dev (Fly.io, PR-A1). All three return discriminated unions; network / non-JSON / unexpected-HTTP paths fold into {status: "error"} so callers always get a typed result rather than an exception.

Wiring

  • DEFAULT_API_BASE set to https://api.foxbook.dev (bare hostname; routes prepend /api/v1 internally).
  • URLs as ${apiBase}/api/v1/claim/<verb>. Trailing slash on apiBase tolerated.

Status mappings (server apps/api/src/claim/route.ts → SDK)

claimStart: 201 → ok, 409 → asset-conflict, else → error

claimVerifyGist:

  • 200 + tier=1tier1-verified (synthesises inclusion_proof_url pointing at transparency.foxbook.dev/inclusion/<idx>)
  • 200 + status:still-pendingstill-pending
  • 200 + status:not-foundnot-found
  • 200 + status:errorerror
  • 404 not-found-claim → not-found
  • 409 identity-mismatch → identity-mismatch
  • 400 bad-request / wrong-asset-type → error

claimRevoke:

  • 200 revoked → revoked
  • 404 → not-found
  • 403 (mismatch / signature-invalid) → signature-invalid
  • 400 / 422 / unexpected → error

Field-name boundary at claimRevoke: SDK consumer-facing field is recovery_key_signature; server reads revocation_record_jws. Mapping happens at the wire boundary.

Type changes (pre-publish, no consumer break)

  • ClaimStartResult becomes a discriminated union (was a plain object). Adds asset-conflict + error branches. SDK is at v0.0.0 / private — no published version yet.

Test plan

  • pnpm --filter @foxbook/sdk-claim typecheck — green
  • pnpm --filter @foxbook/sdk-claim test31 passed, 0 failed
  • pnpm --filter @foxbook/sdk-claim test:coverage on claim.ts:
    • 100% statements (66/66)
    • 100% lines (58/58)
    • 100% functions (5/5)
    • 85.54% branches (71/83) — exceeds 80% target
  • CI green
  • Squash-merge

Day-9 plan correspondence

PR-A3 from /Users/tester/.claude/plans/focus-deeply-and-use-nifty-swan.md. Next: PR-A4 (verify.ts implementation against transparency.foxbook.dev + by-handle endpoint), then PR-A5 (npm publish v0.1.0 + tag release).

ADR conformance

  • ADR 0001: globalThis.fetch only, no adapter imports, no provider literals. Pure service-agnostic-core compliant.
  • ADR 0005: SDK is a client; canonical bytes live on the server.
  • ADR 0007: SDK doesn't set Cache-Control (request-side); server does.

Ben added 2 commits May 1, 2026 08:03
Implements the three claim primitives (claimStart / claimVerifyGist /
claimRevoke). All three return discriminated unions; network / non-JSON
/ unexpected HTTP code paths fold into {status: "error"} so callers
always get a typed result rather than an exception.

## Wiring

- `DEFAULT_API_BASE` set to `https://api.foxbook.dev` (PR-A1's Fly deploy).
- URLs constructed as `${apiBase}/api/v1/claim/<verb>` — base is the
  bare hostname, routes own the `/api/v1` prefix internally.
- Trailing slash on apiBase is tolerated.

## Status mappings (per server route in apps/api/src/claim/route.ts)

claimStart:
  201 → ok
  409 → asset-conflict
  network/unexpected → error

claimVerifyGist:
  200 + tier=1 → tier1-verified (synthesises inclusion_proof_url
                  pointing at transparency.foxbook.dev/inclusion/<idx>)
  200 + status:still-pending → still-pending
  200 + status:not-found → not-found (gist URL unreachable)
  200 + status:error → error
  404 not-found-claim → not-found
  409 identity-mismatch → identity-mismatch
  400 bad-request / wrong-asset-type → error

claimRevoke:
  200 revoked → revoked
  404 → not-found
  403 recovery-key-mismatch / signature-invalid → signature-invalid
  400 bad-state / 422 invalid-leaf / unexpected → error

Field-name boundary: SDK exposes `recovery_key_signature` to consumers;
server reads `revocation_record_jws`. The wire mapping happens in
claimRevoke at the boundary, keeping the SDK consumer's mental model
clean.

## Type changes

- `ClaimStartResult` becomes a discriminated union (was a plain object).
  Adds `asset-conflict` + `error` branches. Pre-publish so no consumer
  break — sdk-claim hasn't shipped to npm yet.

## Tests

- `packages/sdk-claim/__tests__/claim.test.ts` — 31 cases mocking
  globalThis.fetch.
- Coverage: 100% statements / 100% lines / 100% functions /
  85.54% branches on claim.ts. Exceeds the 80% target.
- Cases include: URL/header/body shape, apiBase override + trailing
  slash, all discriminated branches per function, network failure,
  non-JSON response, missing-required-fields on success.

## ADR conformance

- ADR 0001: globalThis.fetch only, no adapter imports, no provider
  literals. Pure service-agnostic-core compliant.
- ADR 0005: SDK is a client; canonical bytes live on the server.
- ADR 0007: SDK doesn't set Cache-Control (request-side); the server
  does (response-side).
@cloakmaster cloakmaster merged commit e31ff83 into main May 1, 2026
3 checks passed
@cloakmaster cloakmaster deleted the chore/pra3-sdk-claim-impl branch May 1, 2026 06:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant