@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.
- package/README.md +57 -10
- package/lib/errors.d.ts +15 -0
- package/lib/errors.js +44 -0
- package/lib/jwks.js +2 -1
- package/lib/request-proof.d.ts +10 -0
- package/lib/request-proof.js +17 -10
- package/lib/result.d.ts +20 -1
- package/lib/result.js +32 -7
- package/lib/routes.gen.d.ts +16 -0
- package/lib/routes.gen.js +5 -1
- package/lib/types/openapi.gen.d.ts +318 -23
- package/lib/types/openapi.gen.js +1 -1
- package/lib/verify-attestor-tee.d.ts +19 -4
- package/lib/verify-attestor-tee.js +10 -4
- package/package.json +1 -1
- package/src/errors.ts +52 -0
- package/src/jwks.ts +5 -1
- package/src/request-proof.ts +31 -17
- package/src/result.ts +47 -7
- package/src/routes.gen.ts +5 -1
- package/src/types/openapi.gen.ts +319 -24
- package/src/verify-attestor-tee.ts +33 -5
|
@@ -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.
|
|
2496
|
-
*
|
|
2497
|
-
*
|
|
2498
|
-
*
|
|
2499
|
-
* `
|
|
2500
|
-
*
|
|
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.
|
|
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
|
-
|
|
5802
|
-
|
|
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
|
-
/**
|
|
5809
|
-
|
|
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
|
|
5815
|
-
|
|
5816
|
-
/** @
|
|
5817
|
-
|
|
5818
|
-
|
|
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?:
|
|
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
|
-
/**
|
|
6368
|
-
|
|
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
|
-
/**
|
|
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
|
|
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
|
};
|
package/lib/types/openapi.gen.js
CHANGED
|
@@ -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:
|
|
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
|
|
62
|
-
*
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
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>
|