feat(sdk-claim): PR-A3 — claim.ts implementation against api.foxbook.dev#56
Merged
cloakmaster merged 2 commits intomainfrom May 1, 2026
Merged
feat(sdk-claim): PR-A3 — claim.ts implementation against api.foxbook.dev#56cloakmaster merged 2 commits intomainfrom
cloakmaster merged 2 commits intomainfrom
Conversation
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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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_BASEset tohttps://api.foxbook.dev(bare hostname; routes prepend/api/v1internally).${apiBase}/api/v1/claim/<verb>. Trailing slash onapiBasetolerated.Status mappings (server
apps/api/src/claim/route.ts→ SDK)claimStart: 201 →
ok, 409 →asset-conflict, else →errorclaimVerifyGist:
tier=1→tier1-verified(synthesisesinclusion_proof_urlpointing attransparency.foxbook.dev/inclusion/<idx>)status:still-pending→still-pendingstatus:not-found→not-foundstatus:error→errornot-foundidentity-mismatcherrorclaimRevoke:
revokednot-foundsignature-invaliderrorField-name boundary at
claimRevoke: SDK consumer-facing field isrecovery_key_signature; server readsrevocation_record_jws. Mapping happens at the wire boundary.Type changes (pre-publish, no consumer break)
ClaimStartResultbecomes a discriminated union (was a plain object). Addsasset-conflict+errorbranches. SDK is at v0.0.0 / private — no published version yet.Test plan
pnpm --filter @foxbook/sdk-claim typecheck— greenpnpm --filter @foxbook/sdk-claim test— 31 passed, 0 failedpnpm --filter @foxbook/sdk-claim test:coverageonclaim.ts: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