@reclaimprotocol/client 0.1.34 → 0.1.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1347,6 +1347,26 @@ export interface paths {
1347
1347
  patch?: never;
1348
1348
  trace?: never;
1349
1349
  };
1350
+ "/docs/agent-installation.md": {
1351
+ parameters: {
1352
+ query?: never;
1353
+ header?: never;
1354
+ path?: never;
1355
+ cookie?: never;
1356
+ };
1357
+ /**
1358
+ * Agent installation instructions
1359
+ * @description How to install the Reclaim MCP server in each supported coding agent, as Markdown for a coding agent to read: the exact commands or configuration per agent, how to verify the installation, and troubleshooting. It tells the agent to follow only the section for the client it runs in. Public.
1360
+ */
1361
+ get: operations["AgentInstallationMarkdown"];
1362
+ put?: never;
1363
+ post?: never;
1364
+ delete?: never;
1365
+ options?: never;
1366
+ head?: never;
1367
+ patch?: never;
1368
+ trace?: never;
1369
+ };
1350
1370
  "/login": {
1351
1371
  parameters: {
1352
1372
  query?: never;
@@ -2492,12 +2512,26 @@ export interface paths {
2492
2512
  /**
2493
2513
  * Register a callback subscription
2494
2514
  * @description Registers a destination for verification results on the organization
2495
- * the presented `OrgToken` resolves to. The body is just `callbackUrl`
2496
- * and `events`. At least one subscription must exist for the org before a
2497
- * verification session can be created. Delivery is scoped by org: terminal
2498
- * results are ECIES-encrypted to the org's eth public key when its
2499
- * `canEncryptResult` is enabled (see `PUT /orgs/{orgId}/keypair`), else
2500
- * delivered as plaintext.
2515
+ * the presented `OrgToken` resolves to. At least one subscription must
2516
+ * exist for the org before you can create a verification session.
2517
+ * Delivery is scoped by org: terminal results are ECIES-encrypted to the
2518
+ * org's eth public key when its `canEncryptResult` is enabled (see
2519
+ * `PUT /orgs/{orgId}/keypair`), else delivered as plaintext.
2520
+ *
2521
+ * To receive results at a URL, send `callbackUrl` and `events`. Builder
2522
+ * POSTs each delivery to that URL.
2523
+ *
2524
+ * To read results without a public URL during local development, send
2525
+ * `deliveryMode: "pull"`. Builder keeps the deliveries and you read them
2526
+ * with `GET /verifications/callback-events`. A pull subscription is a
2527
+ * 90-second lease: it receives events and satisfies the session-creation
2528
+ * check only while the lease is unexpired. Send the same request about
2529
+ * every 30 seconds to renew it, and call
2530
+ * `POST /verifications/callback-listener/release` when you stop. Production
2531
+ * needs a webhook subscription. An org has at most one pull subscription.
2532
+ * If it already exists, Builder renews it and returns it with status 200.
2533
+ * If the body includes `events`, they replace the subscription's events;
2534
+ * if it omits them, the existing events are kept.
2501
2535
  */
2502
2536
  post: operations["CreateCallbackSubscription"];
2503
2537
  delete?: never;
@@ -2506,6 +2540,86 @@ export interface paths {
2506
2540
  patch?: never;
2507
2541
  trace?: never;
2508
2542
  };
2543
+ "/verifications/callback-listener/release": {
2544
+ parameters: {
2545
+ query?: never;
2546
+ header?: never;
2547
+ path?: never;
2548
+ cookie?: never;
2549
+ };
2550
+ get?: never;
2551
+ put?: never;
2552
+ /**
2553
+ * Release the pull listener
2554
+ * @description Expires the organization's pull subscription lease immediately, so it stops receiving events and no longer satisfies the session-creation check. Stored events stay readable. Call it when the coding agent stops. It succeeds when no pull subscription exists or the lease has already expired.
2555
+ */
2556
+ post: operations["ReleaseCallbackListener"];
2557
+ delete?: never;
2558
+ options?: never;
2559
+ head?: never;
2560
+ patch?: never;
2561
+ trace?: never;
2562
+ };
2563
+ "/verifications/callback-events": {
2564
+ parameters: {
2565
+ query?: never;
2566
+ header?: never;
2567
+ path?: never;
2568
+ cookie?: never;
2569
+ };
2570
+ /**
2571
+ * List events from the pull subscription
2572
+ * @description Lists the deliveries of the organization's pull subscription, oldest
2573
+ * first. Use it to read verification results without a public URL.
2574
+ * Create the pull subscription with `POST /verifications/callback-subscriptions`
2575
+ * and `deliveryMode: "pull"`.
2576
+ *
2577
+ * Each item's `envelope` is the body that Builder POSTs to a webhook
2578
+ * subscription, so you handle both the same way. For a pull
2579
+ * subscription, `envelope.timestamp` is the time Builder created the
2580
+ * delivery.
2581
+ *
2582
+ * To poll, pass the previous response's `next` as `after`. `next` is
2583
+ * always set, and equals `after` when no new events exist. Treat cursors
2584
+ * as opaque. A cursor read is not complete: a delivery that commits after
2585
+ * a later one can be missed, because the cursor has already moved past
2586
+ * it. The reliable path is `pending=true` plus
2587
+ * `POST /verifications/callback-events/acknowledge`: acknowledge each
2588
+ * event you handled, and read `pending=true` without `after` so anything
2589
+ * missed shows up on the next read.
2590
+ *
2591
+ * Builder keeps result payloads for seven days. Acknowledged events stay
2592
+ * readable until then.
2593
+ */
2594
+ get: operations["ListCallbackEvents"];
2595
+ put?: never;
2596
+ post?: never;
2597
+ delete?: never;
2598
+ options?: never;
2599
+ head?: never;
2600
+ patch?: never;
2601
+ trace?: never;
2602
+ };
2603
+ "/verifications/callback-events/acknowledge": {
2604
+ parameters: {
2605
+ query?: never;
2606
+ header?: never;
2607
+ path?: never;
2608
+ cookie?: never;
2609
+ };
2610
+ get?: never;
2611
+ put?: never;
2612
+ /**
2613
+ * Acknowledge events from the pull subscription
2614
+ * @description Marks pull deliveries as `delivered` so `GET /verifications/callback-events` with `pending=true` stops returning them. Builder keeps the payloads until the seven-day retention limit. Ids that are unknown, belong to another organization, or are already acknowledged are ignored.
2615
+ */
2616
+ post: operations["AcknowledgeCallbackEvents"];
2617
+ delete?: never;
2618
+ options?: never;
2619
+ head?: never;
2620
+ patch?: never;
2621
+ trace?: never;
2622
+ };
2509
2623
  "/verifications/callback-subscriptions/{subscriptionId}": {
2510
2624
  parameters: {
2511
2625
  query?: never;
@@ -2541,7 +2655,8 @@ export interface paths {
2541
2655
  put?: never;
2542
2656
  /**
2543
2657
  * Register a callback subscription on an organization
2544
- * @description Registers a destination for verification results on the organization. Caller must be an active member of the org. The body is just `callbackUrl` and `events`; delivery is scoped to the org and encrypted as an ECIES ciphertext (base64url) to the org's encryption credential when set, else delivered as plaintext.
2658
+ * @description Registers a destination for verification results on the organization. Caller must be an active member of the org. Delivery is scoped to the org and encrypted as an ECIES ciphertext (base64url) to the org's encryption credential when set, else delivered as plaintext.
2659
+ * Send `callbackUrl` and `events` to receive results at a URL. Send `deliveryMode: "pull"` to keep results for reading with `GET /verifications/callback-events`. A pull subscription works only while its 90-second lease is unexpired, and each repeated request renews it. An org has at most one pull subscription. If it already exists, Builder returns it with status 200.
2545
2660
  */
2546
2661
  post: operations["CreateOrgCallbackSubscription"];
2547
2662
  delete?: never;
@@ -2989,6 +3104,7 @@ export interface paths {
2989
3104
  /**
2990
3105
  * Submit exact proofs as a managed Builder result
2991
3106
  * @description Accepts exact `Proof` objects from a claimant-facing `api=2` client. Builder atomically records the first terminal outcome, checks it against the submitted status, signs the outer Builder JWS with its managed key, optionally encrypts it for matching callback subscriptions, and enqueues delivery. Retrying the same terminal outcome is idempotent. This is the only result-submission endpoint; Verification Clients never receive signing or encryption keys.
3107
+ * Before it accepts a `success` result, Builder verifies every proof with the same trust a default `@reclaimprotocol/client` consumer uses: Builder's attestor addresses and image digests, the session recipe's provider hashes, and the session binding. If a proof fails, Builder records the session as a terminal `error` with a `problem` whose `reasonCode` is `invalid-proof`, enqueues the `verification_error` delivery, and returns `422`. Don't retry a `422`; the session is already terminal.
2992
3108
  */
2993
3109
  post: operations["SubmitVerificationClientResult"];
2994
3110
  delete?: never;
@@ -5798,24 +5914,59 @@ export interface components {
5798
5914
  * @description The organization that owns this callback subscription.
5799
5915
  */
5800
5916
  orgId: string;
5801
- /** @description HTTP(S) endpoint that receives the event. It may contain `{{sessionId}}` and top-level session-context placeholders such as `{{orderId}}`. The Builder URI-encodes each value and stores the expanded URL when it creates the delivery. */
5802
- callbackUrl: string;
5917
+ deliveryMode: components["schemas"]["CallbackDeliveryMode"];
5918
+ /** @description HTTP(S) endpoint that receives the event. It may contain `{{sessionId}}` and top-level session-context placeholders such as `{{orderId}}`. The Builder URI-encodes each value and stores the expanded URL when it creates the delivery. Absent when `deliveryMode` is `pull`. */
5919
+ callbackUrl?: string;
5920
+ /** @description Present when `deliveryMode` is `pull`. The pull subscription receives events and satisfies the session-creation check only until this time. Renew it by repeating the create request. */
5921
+ listenerExpiresAt?: components["schemas"]["Timestamp"];
5803
5922
  /** @description Events this subscription wants delivered — any subset of `VerificationEvent`. Builder terminal events are `verification_success`, `verification_rejected`, `verification_error`, `verification_cancelled`, and `session_expired`. Terminal result deliveries contain the signed result when one is available; non-terminal events deliver a plaintext notification. */
5804
5923
  events: components["schemas"]["VerificationEvent"][];
5805
5924
  createdAt: components["schemas"]["Timestamp"];
5806
5925
  updatedAt: components["schemas"]["Timestamp"];
5807
5926
  };
5808
- /** @description Body for `POST /verifications/callback-subscriptions`. The owning organization is resolved from the presented `OrgToken`; delivery is scoped to that org and encrypted to its credential when set. */
5809
- CreateCallbackSubscriptionRequest: {
5927
+ /**
5928
+ * @description How Builder delivers events. `webhook` POSTs each one to `callbackUrl`. `pull` keeps them for you to read with `GET /verifications/callback-events`.
5929
+ * @enum {string}
5930
+ */
5931
+ CallbackDeliveryMode: "webhook" | "pull";
5932
+ /** @description A subscription that Builder POSTs each delivery to. */
5933
+ WebhookCallbackSubscriptionRequest: {
5934
+ /**
5935
+ * @description Omit it or send `webhook`.
5936
+ * @enum {string}
5937
+ */
5938
+ deliveryMode?: "webhook";
5810
5939
  /** @description Callback URL or template. Supported placeholders are `{{sessionId}}` and top-level scalar context keys. */
5811
5940
  callbackUrl: string;
5812
5941
  events: components["schemas"]["VerificationEvent"][];
5813
5942
  };
5814
- /** @description Body for `POST /orgs/{orgId}/callback-subscriptions`. The owning organization comes from the path; bearer-authenticated and gated on org membership. Delivery is scoped to the org and encrypted to its credential when set. */
5815
- CreateOrgCallbackSubscriptionRequest: {
5816
- /** @description Callback URL or template. Supported placeholders are `{{sessionId}}` and top-level scalar context keys. */
5817
- callbackUrl: string;
5818
- events: components["schemas"]["VerificationEvent"][];
5943
+ /** @description A subscription whose deliveries wait for you to read them. It has no URL. An org has at most one. */
5944
+ PullCallbackSubscriptionRequest: {
5945
+ /** @enum {string} */
5946
+ deliveryMode: "pull";
5947
+ /** @description Not allowed. A pull subscription has no URL. */
5948
+ callbackUrl?: unknown;
5949
+ /** @description Events to keep. Defaults to every event. */
5950
+ events?: components["schemas"]["VerificationEvent"][];
5951
+ };
5952
+ /** @description Body for `POST /verifications/callback-subscriptions`. The owning organization is resolved from the presented `OrgToken`; delivery is scoped to that org and encrypted to its credential when set. Send `callbackUrl` for a webhook, or `deliveryMode: "pull"` for a subscription you read. */
5953
+ CreateCallbackSubscriptionRequest: components["schemas"]["WebhookCallbackSubscriptionRequest"] | components["schemas"]["PullCallbackSubscriptionRequest"];
5954
+ /** @description Body for `POST /orgs/{orgId}/callback-subscriptions`. The owning organization comes from the path; bearer-authenticated and gated on org membership. Delivery is scoped to the org and encrypted to its credential when set. Send `callbackUrl` for a webhook, or `deliveryMode: "pull"` for a subscription you read. */
5955
+ CreateOrgCallbackSubscriptionRequest: components["schemas"]["WebhookCallbackSubscriptionRequest"] | components["schemas"]["PullCallbackSubscriptionRequest"];
5956
+ /** @description One delivery waiting on the organization's pull subscription. */
5957
+ CallbackEvent: {
5958
+ /**
5959
+ * Format: uuid
5960
+ * @description Pass it to `POST /verifications/callback-events/acknowledge`.
5961
+ */
5962
+ id: string;
5963
+ subscriptionId: components["schemas"]["SubscriptionID"];
5964
+ sessionId: components["schemas"]["SessionID"];
5965
+ event: components["schemas"]["VerificationEvent"];
5966
+ /** @description `pending` until you acknowledge the event, then `delivered`. */
5967
+ deliveryStatus: components["schemas"]["CallbackDeliveryStatus"];
5968
+ createdAt: components["schemas"]["Timestamp"];
5969
+ envelope: components["schemas"]["VerificationResultDelivery"];
5819
5970
  };
5820
5971
  /** @description Present only when the session's `mode` is `SANDBOX`. */
5821
5972
  SandboxLimits: {
@@ -6216,7 +6367,7 @@ export interface components {
6216
6367
  signature: string;
6217
6368
  }[];
6218
6369
  };
6219
- /** @description The JSON envelope POSTed to a callback subscription's `callbackUrl` (see the `verificationResult` webhook). `sessionId`, `event` and `timestamp` are unauthenticated plaintext routing hints; branch on `event` for the shape of `data`. **Terminal result events** carry the signed result — an ECIES ciphertext (base64url, secp256k1 + AES-256-GCM) wrapping the signed JWS when the org has an encryption credential, else the plaintext signed JWS — act only on the signature-verified contents. **Non-terminal events** carry a plaintext, **unsigned** progress notification — advisory only; the signed terminal result is the source of truth. */
6370
+ /** @description The JSON envelope POSTed to a callback subscription's `callbackUrl` (see the `verificationResult` webhook), and returned as `envelope` by `GET /verifications/callback-events` for a pull subscription. `sessionId`, `event` and `timestamp` are unauthenticated plaintext routing hints; branch on `event` for the shape of `data`. **Terminal result events** carry the signed result — an ECIES ciphertext (base64url, secp256k1 + AES-256-GCM) wrapping the signed JWS when the org has an encryption credential, else the plaintext signed JWS — act only on the signature-verified contents. **Non-terminal events** carry a plaintext, **unsigned** progress notification — advisory only; the signed terminal result is the source of truth. */
6220
6371
  VerificationResultDelivery: {
6221
6372
  sessionId: components["schemas"]["SessionID"];
6222
6373
  /** @description The event that produced this delivery. */
@@ -6230,7 +6381,18 @@ export interface components {
6230
6381
  /** @enum {string} */
6231
6382
  status: "success" | "rejected" | "error" | "cancelled";
6232
6383
  results: components["schemas"]["VerificationClientProviderResult"][];
6233
- problem?: components["schemas"]["Problem"] | null;
6384
+ problem?: ({
6385
+ /** @description Stable machine-readable failure code. Builder records `invalid-proof` when a submitted proof fails its verification. */
6386
+ reasonCode?: string;
6387
+ retryable?: boolean;
6388
+ /** @description Builder-recorded proof failures, one per provider. Present with `reasonCode: invalid-proof`. */
6389
+ proofs?: {
6390
+ providerId?: string;
6391
+ resolvedVersion?: string;
6392
+ requestIds?: string[];
6393
+ reason?: string;
6394
+ }[];
6395
+ } & components["schemas"]["Problem"]) | null;
6234
6396
  };
6235
6397
  VerificationClientProviderResult: {
6236
6398
  providerId: components["schemas"]["ProviderID"];
@@ -6364,8 +6526,11 @@ export interface components {
6364
6526
  VerificationDelivery: {
6365
6527
  subscriptionId: components["schemas"]["SubscriptionID"];
6366
6528
  event: components["schemas"]["VerificationEvent"];
6367
- /** Format: uri */
6368
- callbackUrl: string;
6529
+ /**
6530
+ * Format: uri
6531
+ * @description Absent for deliveries to a pull subscription.
6532
+ */
6533
+ callbackUrl?: string;
6369
6534
  deliveryStatus: components["schemas"]["CallbackDeliveryStatus"];
6370
6535
  attempts: number;
6371
6536
  lastAttemptAt?: components["schemas"]["Timestamp"];
@@ -8515,6 +8680,27 @@ export interface operations {
8515
8680
  default: components["responses"]["ProblemResponse"];
8516
8681
  };
8517
8682
  };
8683
+ AgentInstallationMarkdown: {
8684
+ parameters: {
8685
+ query?: never;
8686
+ header?: never;
8687
+ path?: never;
8688
+ cookie?: never;
8689
+ };
8690
+ requestBody?: never;
8691
+ responses: {
8692
+ /** @description The guide as Markdown. */
8693
+ 200: {
8694
+ headers: {
8695
+ [name: string]: unknown;
8696
+ };
8697
+ content: {
8698
+ "text/markdown": string;
8699
+ };
8700
+ };
8701
+ default: components["responses"]["ProblemResponse"];
8702
+ };
8703
+ };
8518
8704
  LoginPage: {
8519
8705
  parameters: {
8520
8706
  query?: {
@@ -8860,9 +9046,12 @@ export interface operations {
8860
9046
  tab?: "overview" | "connect" | "integrate" | "providers" | "members" | "themes" | "settings" | "sessions" | "billing";
8861
9047
  /** @description Integrate tab only. Which integration path to show: a coding agent over MCP, the client package, or plain HTTP. */
8862
9048
  track?: "agent" | "sdk" | "http";
8863
- /** @description Integrate tab, agent track only. Which coding agent's install command to show. */
9049
+ /**
9050
+ * @deprecated
9051
+ * @description Ignored.
9052
+ */
8864
9053
  agent?: "claude" | "copilot" | "cursor" | "omp" | "opencode" | "codex" | "antigravity" | "others";
8865
- /** @description Integrate tab, agent track only. What users prove, as typed into the prompt's goal field; kept when another agent is picked. */
9054
+ /** @description Integrate tab, agent track only. What users prove, as typed into the prompt's goal field. */
8866
9055
  goal?: string;
8867
9056
  /** @description Integrate tab: the providers to show in the examples in place of placeholder ids, for example when arriving from a provider page or a build page. Repeat to pass several. Dashboard tab: scopes the report to sessions that ran this provider (the first one); options come from `GET /orgs/{orgId}/providers/used`. */
8868
9057
  providerId?: components["schemas"]["ProviderID"][];
@@ -10677,6 +10866,15 @@ export interface operations {
10677
10866
  };
10678
10867
  };
10679
10868
  responses: {
10869
+ /** @description The org's existing pull subscription */
10870
+ 200: {
10871
+ headers: {
10872
+ [name: string]: unknown;
10873
+ };
10874
+ content: {
10875
+ "application/json": components["schemas"]["CallbackSubscription"];
10876
+ };
10877
+ };
10680
10878
  /** @description Subscription created */
10681
10879
  201: {
10682
10880
  headers: {
@@ -10689,6 +10887,85 @@ export interface operations {
10689
10887
  default: components["responses"]["ProblemResponse"];
10690
10888
  };
10691
10889
  };
10890
+ ReleaseCallbackListener: {
10891
+ parameters: {
10892
+ query?: never;
10893
+ header?: never;
10894
+ path?: never;
10895
+ cookie?: never;
10896
+ };
10897
+ requestBody?: never;
10898
+ responses: {
10899
+ /** @description Released */
10900
+ 204: {
10901
+ headers: {
10902
+ [name: string]: unknown;
10903
+ };
10904
+ content?: never;
10905
+ };
10906
+ default: components["responses"]["ProblemResponse"];
10907
+ };
10908
+ };
10909
+ ListCallbackEvents: {
10910
+ parameters: {
10911
+ query?: {
10912
+ /** @description Cursor from the `next` field of a previous response. Returns only events after it. Omit it to start from the oldest event. */
10913
+ after?: string;
10914
+ /** @description Maximum number of events to return. Defaults to 50. */
10915
+ limit?: number;
10916
+ /** @description Returns only events of this verification session. */
10917
+ sessionId?: components["schemas"]["SessionID"];
10918
+ /** @description When `true`, returns only events you have not acknowledged. Defaults to `false`. */
10919
+ pending?: boolean;
10920
+ };
10921
+ header?: never;
10922
+ path?: never;
10923
+ cookie?: never;
10924
+ };
10925
+ requestBody?: never;
10926
+ responses: {
10927
+ /** @description Ok */
10928
+ 200: {
10929
+ headers: {
10930
+ [name: string]: unknown;
10931
+ };
10932
+ content: {
10933
+ "application/json": {
10934
+ items: components["schemas"]["CallbackEvent"][];
10935
+ /** @description Cursor to pass as `after` on the next request. Equals `after` when `items` is empty, and `0` when you passed no `after`. */
10936
+ next: string;
10937
+ };
10938
+ };
10939
+ };
10940
+ default: components["responses"]["ProblemResponse"];
10941
+ };
10942
+ };
10943
+ AcknowledgeCallbackEvents: {
10944
+ parameters: {
10945
+ query?: never;
10946
+ header?: never;
10947
+ path?: never;
10948
+ cookie?: never;
10949
+ };
10950
+ requestBody: {
10951
+ content: {
10952
+ "application/json": {
10953
+ /** @description The `id` of each `CallbackEvent` to acknowledge. */
10954
+ ids: string[];
10955
+ };
10956
+ };
10957
+ };
10958
+ responses: {
10959
+ /** @description Acknowledged */
10960
+ 204: {
10961
+ headers: {
10962
+ [name: string]: unknown;
10963
+ };
10964
+ content?: never;
10965
+ };
10966
+ default: components["responses"]["ProblemResponse"];
10967
+ };
10968
+ };
10692
10969
  DeleteCallbackSubscription: {
10693
10970
  parameters: {
10694
10971
  query?: never;
@@ -10753,6 +11030,15 @@ export interface operations {
10753
11030
  };
10754
11031
  };
10755
11032
  responses: {
11033
+ /** @description The org's existing pull subscription */
11034
+ 200: {
11035
+ headers: {
11036
+ [name: string]: unknown;
11037
+ };
11038
+ content: {
11039
+ "application/json": components["schemas"]["CallbackSubscription"];
11040
+ };
11041
+ };
10756
11042
  /** @description Subscription created */
10757
11043
  201: {
10758
11044
  headers: {
@@ -11027,7 +11313,7 @@ export interface operations {
11027
11313
  "application/problem+json": components["schemas"]["Problem"];
11028
11314
  };
11029
11315
  };
11030
- /** @description No callback subscription exists for the organization. Register one first via `POST /verifications/callback-subscriptions` (or `POST /orgs/{orgId}/callback-subscriptions`). */
11316
+ /** @description No callback subscription exists for the organization. Register one first via `POST /verifications/callback-subscriptions` (or `POST /orgs/{orgId}/callback-subscriptions`). A pull subscription satisfies this check only while its listener lease is unexpired. */
11031
11317
  409: {
11032
11318
  headers: {
11033
11319
  [name: string]: unknown;
@@ -11289,6 +11575,15 @@ export interface operations {
11289
11575
  };
11290
11576
  400: components["responses"]["ProblemResponse"];
11291
11577
  409: components["responses"]["ProblemResponse"];
11578
+ /** @description A submitted proof failed Builder verification. Builder recorded the session as a terminal `error` and enqueued `verification_error`. */
11579
+ 422: {
11580
+ headers: {
11581
+ [name: string]: unknown;
11582
+ };
11583
+ content: {
11584
+ "application/problem+json": components["schemas"]["Problem"];
11585
+ };
11586
+ };
11292
11587
  default: components["responses"]["ProblemResponse"];
11293
11588
  };
11294
11589
  };
@@ -1,5 +1,5 @@
1
1
  // AUTO-GENERATED by packages/app/scripts/openapi-typegen.ts
2
- // from packages/app/openapi.yaml (spec v0.1.0, source sha256:e2db795ab15c).
2
+ // from packages/app/openapi.yaml (spec v0.1.0, source sha256:96339e8dff91).
3
3
  // The hash catches drift the version misses (a spec can change without a
4
4
  // version bump) — do not remove it as "redundant" with the version.
5
5
  // Run `npm run openapi:gen --workspace=packages/app` to regenerate. Do not edit by hand.
@@ -51,6 +51,18 @@ export type AttestorTeeAttestationConfig = {
51
51
  */
52
52
  expectedImageDigests?: string[];
53
53
  };
54
+ /** How strictly `runAttestorTeeVerification` treats witnesses without a
55
+ * `claimAttestation`. */
56
+ export interface AttestorTeeVerificationOptions {
57
+ /**
58
+ * Default `true`: every witness must carry a `claimAttestation`. `false`
59
+ * counts a witness without one as unattested, which is how
60
+ * `@reclaimprotocol/js-sdk` verifies by default — its claim signature is
61
+ * still checked against the trusted attestors by the caller. Portal TEE
62
+ * proofs without a bound nonce have no envelope.
63
+ */
64
+ requireClaimAttestation?: boolean;
65
+ }
54
66
  /** A witness's attestation kind. Required: every client sets it explicitly. */
55
67
  export declare function claimAttestationType(att: AttestorClaimAttestation): ClaimAttestationType;
56
68
  /** What `runAttestorTeeVerification` actually checked, per witness. */
@@ -58,8 +70,9 @@ export interface AttestorTeeVerificationSummary {
58
70
  /** Witnesses whose `attestation_report` was verified (and pinned, when
59
71
  * `expectedImageDigests` was set). */
60
72
  verified: number;
61
- /** Witnesses that carried no `attestation_report`. Their attestor address
62
- * and claim signature were still verified. */
73
+ /** Witnesses that carried no `attestation_report`, or no
74
+ * `claimAttestation` when it isn't required. Their attestor address and
75
+ * claim signature were still verified. */
63
76
  unattested: number;
64
77
  }
65
78
  /**
@@ -67,7 +80,8 @@ export interface AttestorTeeVerificationSummary {
67
80
  * provided proof. Throws `AttestorTeeVerificationError` on the first
68
81
  * failure.
69
82
  *
70
- * Each witness must carry a `claimAttestation`. For each one, this:
83
+ * Each witness must carry a `claimAttestation` unless
84
+ * `options.requireClaimAttestation` is `false`. For each one, this:
71
85
  * 1. Asserts `attestor_address` matches `witness.id`.
72
86
  * 2. Asserts `claim_signature` is present in `proof.signatures`.
73
87
  * 3. Recovers the signer of `claim_signature` from the claim data and
@@ -89,5 +103,6 @@ export interface AttestorTeeVerificationSummary {
89
103
  *
90
104
  * @param proofs - The proofs to verify.
91
105
  * @param config - Optional config; see {@link AttestorTeeAttestationConfig}.
106
+ * @param options - See {@link AttestorTeeVerificationOptions}.
92
107
  */
93
- export declare function runAttestorTeeVerification(proofs: Proof[], config?: AttestorTeeAttestationConfig): Promise<AttestorTeeVerificationSummary>;
108
+ export declare function runAttestorTeeVerification(proofs: Proof[], config?: AttestorTeeAttestationConfig, { requireClaimAttestation }?: AttestorTeeVerificationOptions): Promise<AttestorTeeVerificationSummary>;
@@ -165,7 +165,7 @@ function normalizeAttestorAddress(address) {
165
165
  function normalizeSignature(sig) {
166
166
  return sig.trim().toLowerCase();
167
167
  }
168
- async function verifyAttestorTeeForProof(proof, config, summary) {
168
+ async function verifyAttestorTeeForProof(proof, config, requireClaimAttestation, summary) {
169
169
  if (!proof.witnesses || proof.witnesses.length === 0) {
170
170
  throw new AttestorTeeVerificationError('Proof has no witnesses');
171
171
  }
@@ -174,6 +174,10 @@ async function verifyAttestorTeeForProof(proof, config, summary) {
174
174
  const claimSignData = createSignDataForClaim(proof.claimData);
175
175
  for (const witness of proof.witnesses) {
176
176
  const att = witness.claimAttestation;
177
+ if (!att && !requireClaimAttestation) {
178
+ summary.unattested++;
179
+ continue;
180
+ }
177
181
  if (!att) {
178
182
  throw new AttestorTeeVerificationError(`Witness ${witness.id} is missing claimAttestation`);
179
183
  }
@@ -233,7 +237,8 @@ async function verifyAttestorTeeForProof(proof, config, summary) {
233
237
  * provided proof. Throws `AttestorTeeVerificationError` on the first
234
238
  * failure.
235
239
  *
236
- * Each witness must carry a `claimAttestation`. For each one, this:
240
+ * Each witness must carry a `claimAttestation` unless
241
+ * `options.requireClaimAttestation` is `false`. For each one, this:
237
242
  * 1. Asserts `attestor_address` matches `witness.id`.
238
243
  * 2. Asserts `claim_signature` is present in `proof.signatures`.
239
244
  * 3. Recovers the signer of `claim_signature` from the claim data and
@@ -255,8 +260,9 @@ async function verifyAttestorTeeForProof(proof, config, summary) {
255
260
  *
256
261
  * @param proofs - The proofs to verify.
257
262
  * @param config - Optional config; see {@link AttestorTeeAttestationConfig}.
263
+ * @param options - See {@link AttestorTeeVerificationOptions}.
258
264
  */
259
- export async function runAttestorTeeVerification(proofs, config = {}) {
265
+ export async function runAttestorTeeVerification(proofs, config = {}, { requireClaimAttestation = true } = {}) {
260
266
  if (!proofs || proofs.length === 0) {
261
267
  throw new AttestorTeeVerificationError('No proofs provided for attestor TEE verification');
262
268
  }
@@ -266,7 +272,7 @@ export async function runAttestorTeeVerification(proofs, config = {}) {
266
272
  };
267
273
  try {
268
274
  for (const proof of proofs) {
269
- await verifyAttestorTeeForProof(proof, config, summary);
275
+ await verifyAttestorTeeForProof(proof, config, requireClaimAttestation, summary);
270
276
  }
271
277
  return summary;
272
278
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@reclaimprotocol/client",
3
3
  "title": "Reclaim Client",
4
- "version": "0.1.34",
4
+ "version": "0.1.36",
5
5
  "description": "Typed SDK/HTTP client SDK for the Reclaim Protocol — the programmatic way to use Reclaim Protocol to verify **data points** about your users (a follower count, an account balance, an order). Can be directly integrated by apps to request verification for their users using Reclaim Protocol and verify the results.",
6
6
  "type": "module",
7
7
  "sideEffects": false,
package/src/errors.ts CHANGED
@@ -44,6 +44,58 @@ export function isProblemError(error: unknown): error is ProblemError {
44
44
  && isProblemErrorOutput(error.output)
45
45
  }
46
46
 
47
+ /**
48
+ * Whether retrying the same request later can succeed: a network failure, a
49
+ * timeout, or an HTTP 5xx, 408, or 429 from Builder (a {@link ProblemError}
50
+ * or a plain error carrying the HTTP `status`). Everything else, such as a
51
+ * malformed response, won't change on retry.
52
+ */
53
+ export function isTransientError(error: unknown): boolean {
54
+ // `fetch` rejects with a TypeError when the network fails.
55
+ if(error instanceof TypeError) {
56
+ return true
57
+ }
58
+
59
+ if(
60
+ error instanceof Error
61
+ && (error.name === 'TimeoutError' || error.name === 'AbortError')
62
+ ) {
63
+ return true
64
+ }
65
+
66
+ const status = isProblemError(error)
67
+ ? error.output.statusCode
68
+ : isRecord(error) ? error.status : undefined
69
+ return typeof status === 'number'
70
+ && (status >= 500 || status === 408 || status === 429)
71
+ }
72
+
73
+ // Errors thrown by a network step and judged transient. Tracked by identity
74
+ // so a content check that throws, say, a TypeError is never mistaken for one.
75
+ const TRANSIENT_ERRORS = new WeakSet<object>()
76
+
77
+ /**
78
+ * Runs one network step, such as a JWKS fetch or a session or provider
79
+ * lookup, and marks a transient failure so {@link isTransientFailure} can
80
+ * tell it apart from a failed content check.
81
+ */
82
+ export async function networkStep<T>(step: () => Promise<T> | T): Promise<T> {
83
+ try {
84
+ return await step()
85
+ } catch(error) {
86
+ if(error instanceof Error && isTransientError(error)) {
87
+ TRANSIENT_ERRORS.add(error)
88
+ }
89
+
90
+ throw error
91
+ }
92
+ }
93
+
94
+ /** Whether `error` came from a {@link networkStep} and a retry can succeed. */
95
+ export function isTransientFailure(error: unknown): boolean {
96
+ return error instanceof Error && TRANSIENT_ERRORS.has(error)
97
+ }
98
+
47
99
  /** Returns whether a value follows the RFC 9457 problem-details schema. */
48
100
  export function isProblemDetails(value: unknown): value is ProblemDetails {
49
101
  if(!isRecord(value)) {
package/src/jwks.ts CHANGED
@@ -95,7 +95,11 @@ export async function fetchReclaimJwks(
95
95
  assertSecureJwksUrl(url)
96
96
  const res = await fetchImpl(url)
97
97
  if(!res.ok) {
98
- throw new Error(`JWKS fetch failed for ${url}: HTTP ${res.status}`)
98
+ // `status` lets callers tell a temporary Builder outage from a bad URL.
99
+ throw Object.assign(
100
+ new Error(`JWKS fetch failed for ${url}: HTTP ${res.status}`),
101
+ { status: res.status },
102
+ )
99
103
  }
100
104
 
101
105
  const body = (await res.json()) as Partial<ReclaimJwks>