@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 CHANGED
@@ -750,16 +750,18 @@ including `hasNoPii`, verifier TEE (`teeAttestation.appSecret`), and
750
750
  attestor-TEE checks. The configured Builder JWKS URL supplies the
751
751
  purpose-bound result keys, its `x-reclaim-attestors` signer list, and its
752
752
  `x-reclaim-attestor-image-digests` Confidential Space image allowlist. When
753
- the JWKS publishes image digests, `verifyResultFull` automatically verifies
754
- every witness's attestor TEE `claimAttestation` — its attestor address and
755
- claim signature always, and its `attestation_report` when the witness carries
756
- one. The report is optional: production attestors sign claims without
757
- returning one, so a witness with only an address and a signature verifies, and
758
- `isAttestorTeeAttestationVerified` comes back `false` to say nothing was
759
- attested. If
760
- `proofValidation.attestorTeeAttestation.expectedImageDigests` is also set, the
761
- SDK uses the intersection: caller policy can narrow the published trust list,
762
- but can't broaden it. TEE settings preserve the same configuration objects;
753
+ the JWKS publishes image digests, `verifyResultFull` verifies any attestor TEE
754
+ `claimAttestation` a witness carries — its attestor address and claim
755
+ signature, and its `attestation_report` pinned to those digests when present.
756
+ Neither is required: like `@reclaimprotocol/js-sdk`, a witness is trusted by
757
+ its signer being in `x-reclaim-attestors`. A portal TEE proof without a bound
758
+ nonce has no `claimAttestation`, and production attestors sign without
759
+ returning a report. When nothing was attested,
760
+ `isAttestorTeeAttestationVerified` comes back `false`. Set
761
+ `proofValidation.attestorTeeAttestation` to require a `claimAttestation` on
762
+ every witness. If its `expectedImageDigests` is also set, the SDK uses the
763
+ intersection: caller policy can narrow the published trust list, but can't
764
+ broaden it. TEE settings preserve the same configuration objects;
763
765
  `verifyResultFull` does not accept injected verification hooks. The surrounding
764
766
  issuer, session, and context checks are stateless; persist accepted session IDs
765
767
  in your application to prevent replay.
@@ -808,6 +810,51 @@ try {
808
810
  A non-terminal `event` delivery is not a result and never throws. It returns
809
811
  `{ kind: 'event', … }`.
810
812
 
813
+ #### Respond to a callback delivery
814
+
815
+ Builder retries a delivery until your callback route answers 2xx, and a
816
+ delivery that never succeeds holds back that session's later events. If
817
+ retrying the same body can't help, answer 2xx. If the failure is temporary,
818
+ answer 5xx.
819
+
820
+ `ResultVerificationError.retryable` tells you which case you're in. It's
821
+ `true` only when a temporary condition caused the failure:
822
+ Builder's JWKS or provider recipe couldn't be fetched because of a network
823
+ error, a timeout, an HTTP 5xx, or rate limiting (`jwks-fetch-failed`,
824
+ `session-resolution-failed`, or an `invalid-proof` whose proofs all failed
825
+ this way). It's `false` for everything about the result itself, including
826
+ `bad-signature`, `issuer-not-trusted`, `aud-mismatch`,
827
+ `reclaimSessionId-mismatch`, `expired`, and an `invalid-proof` with any
828
+ genuinely invalid proof.
829
+
830
+ ```ts
831
+ app.post('/reclaim/callback', async (req, res) => {
832
+ try {
833
+ const { result } = await reclaim.results.receive(req.body, {
834
+ orgEthPrivateKey,
835
+ reclaimSessionId,
836
+ })
837
+ await markVerificationComplete(result)
838
+ res.sendStatus(200)
839
+ } catch (err) {
840
+ if (err instanceof ResultVerificationError) {
841
+ await storeFailure(err.reason, err.outcome)
842
+ // Retrying a bad result can't help, so only ask for a retry when the
843
+ // failure is temporary.
844
+ res.sendStatus(err.retryable ? 503 : 200)
845
+ return
846
+ }
847
+ throw err
848
+ }
849
+ })
850
+ ```
851
+
852
+ `results.receive` can also throw an ordinary `Error` instead of
853
+ `ResultVerificationError`, for example when `orgEthPrivateKey` is missing or
854
+ doesn't match the key the result was encrypted to. Treat it as a
855
+ configuration problem: log it and answer 5xx, so the delivery succeeds once
856
+ you fix the key. Builder holds an undelivered result for 7 days.
857
+
811
858
  ### `reclaim.api` — escape hatch
812
859
 
813
860
  ```ts
package/lib/errors.d.ts CHANGED
@@ -22,6 +22,21 @@ export type ProblemError = Error & {
22
22
  };
23
23
  /** Returns whether a thrown value is a Builder {@link ProblemError}. */
24
24
  export declare function isProblemError(error: unknown): error is ProblemError;
25
+ /**
26
+ * Whether retrying the same request later can succeed: a network failure, a
27
+ * timeout, or an HTTP 5xx, 408, or 429 from Builder (a {@link ProblemError}
28
+ * or a plain error carrying the HTTP `status`). Everything else, such as a
29
+ * malformed response, won't change on retry.
30
+ */
31
+ export declare function isTransientError(error: unknown): boolean;
32
+ /**
33
+ * Runs one network step, such as a JWKS fetch or a session or provider
34
+ * lookup, and marks a transient failure so {@link isTransientFailure} can
35
+ * tell it apart from a failed content check.
36
+ */
37
+ export declare function networkStep<T>(step: () => Promise<T> | T): Promise<T>;
38
+ /** Whether `error` came from a {@link networkStep} and a retry can succeed. */
39
+ export declare function isTransientFailure(error: unknown): boolean;
25
40
  /** Returns whether a value follows the RFC 9457 problem-details schema. */
26
41
  export declare function isProblemDetails(value: unknown): value is ProblemDetails;
27
42
  /** Reads an RFC 9457 response, with a status-only fallback for other bodies. */
package/lib/errors.js CHANGED
@@ -14,6 +14,50 @@ export function isProblemError(error) {
14
14
  return isProblemDetails(error.data)
15
15
  && isProblemErrorOutput(error.output);
16
16
  }
17
+ /**
18
+ * Whether retrying the same request later can succeed: a network failure, a
19
+ * timeout, or an HTTP 5xx, 408, or 429 from Builder (a {@link ProblemError}
20
+ * or a plain error carrying the HTTP `status`). Everything else, such as a
21
+ * malformed response, won't change on retry.
22
+ */
23
+ export function isTransientError(error) {
24
+ // `fetch` rejects with a TypeError when the network fails.
25
+ if (error instanceof TypeError) {
26
+ return true;
27
+ }
28
+ if (error instanceof Error
29
+ && (error.name === 'TimeoutError' || error.name === 'AbortError')) {
30
+ return true;
31
+ }
32
+ const status = isProblemError(error)
33
+ ? error.output.statusCode
34
+ : isRecord(error) ? error.status : undefined;
35
+ return typeof status === 'number'
36
+ && (status >= 500 || status === 408 || status === 429);
37
+ }
38
+ // Errors thrown by a network step and judged transient. Tracked by identity
39
+ // so a content check that throws, say, a TypeError is never mistaken for one.
40
+ const TRANSIENT_ERRORS = new WeakSet();
41
+ /**
42
+ * Runs one network step, such as a JWKS fetch or a session or provider
43
+ * lookup, and marks a transient failure so {@link isTransientFailure} can
44
+ * tell it apart from a failed content check.
45
+ */
46
+ export async function networkStep(step) {
47
+ try {
48
+ return await step();
49
+ }
50
+ catch (error) {
51
+ if (error instanceof Error && isTransientError(error)) {
52
+ TRANSIENT_ERRORS.add(error);
53
+ }
54
+ throw error;
55
+ }
56
+ }
57
+ /** Whether `error` came from a {@link networkStep} and a retry can succeed. */
58
+ export function isTransientFailure(error) {
59
+ return error instanceof Error && TRANSIENT_ERRORS.has(error);
60
+ }
17
61
  /** Returns whether a value follows the RFC 9457 problem-details schema. */
18
62
  export function isProblemDetails(value) {
19
63
  if (!isRecord(value)) {
package/lib/jwks.js CHANGED
@@ -47,7 +47,8 @@ export async function fetchReclaimJwks(url, fetchImpl = fetch) {
47
47
  assertSecureJwksUrl(url);
48
48
  const res = await fetchImpl(url);
49
49
  if (!res.ok) {
50
- throw new Error(`JWKS fetch failed for ${url}: HTTP ${res.status}`);
50
+ // `status` lets callers tell a temporary Builder outage from a bad URL.
51
+ throw Object.assign(new Error(`JWKS fetch failed for ${url}: HTTP ${res.status}`), { status: res.status });
51
52
  }
52
53
  const body = (await res.json());
53
54
  return {
@@ -25,9 +25,15 @@ export interface VerifyRequestProofOptions {
25
25
  /** Read `providerHash` from context, while still verifying signatures. */
26
26
  hasNoPii?: true;
27
27
  teeAttestation?: TeeAttestationConfig;
28
+ /** Require every witness to carry a `claimAttestation`, and verify any
29
+ * `attestation_report` against `expectedImageDigests`. */
28
30
  attestorTeeAttestation?: AttestorTeeAttestationConfig;
29
31
  /** Explicit trusted attestor ETH addresses. */
30
32
  attestorAddresses?: string[];
33
+ /** Trusted attestor image digests, like `x-reclaim-attestor-image-digests`.
34
+ * Pin any `attestation_report` a witness carries without requiring one,
35
+ * matching `@reclaimprotocol/js-sdk`'s default. */
36
+ attestorImageDigests?: string[];
31
37
  /** Trusted Builder JWKS registry containing attestor-purpose keys. */
32
38
  attestorJwksUrl?: string;
33
39
  fetchImpl?: typeof fetch;
@@ -43,6 +49,10 @@ export interface VerifyRequestProofOptions {
43
49
  export interface ReclaimRequestProofOutcome {
44
50
  valid: boolean;
45
51
  reason?: string;
52
+ /** On failure: true when a temporary condition caused it, such as a
53
+ * network error while resolving the session or provider. A retry can
54
+ * succeed. */
55
+ transient?: boolean;
46
56
  proofHashes?: string[];
47
57
  isTeeAttestationVerified?: boolean;
48
58
  /** True when at least one witness's `attestation_report` verified; false
@@ -1,5 +1,6 @@
1
1
  import { createSignDataForClaim } from '@reclaimprotocol/attestor-core';
2
2
  import { recoverEip191Address } from "./eip191.js";
3
+ import { isTransientFailure, networkStep } from "./errors.js";
3
4
  import { fetchReclaimJwks, trustedAttestorAddresses } from "./jwks.js";
4
5
  import { assertValidProofHashes, getHashFromProof } from "./proof-hash.js";
5
6
  import { runAttestorTeeVerification, } from "./verify-attestor-tee.js";
@@ -31,11 +32,13 @@ export async function verifyRequestProof(proofOrProofs, config) {
31
32
  let isAttestorTeeAttestationVerified;
32
33
  const attestorTeeAttestation = resolveAttestorTeeAttestation(effective.attestorTeeAttestation, trust.imageDigests);
33
34
  if (attestorTeeAttestation) {
35
+ // Only a caller-configured check requires an envelope on every
36
+ // witness; registry digests alone pin the reports that exist.
34
37
  // `verified` counts witnesses whose attestation report was checked.
35
38
  // A proof whose witnesses carry no report still passes the address
36
39
  // and signature bindings, but nothing was attested — say so rather
37
40
  // than reporting a TEE attestation that never happened.
38
- const summary = await runAttestorTeeVerification(proofs, attestorTeeAttestation);
41
+ const summary = await runAttestorTeeVerification(proofs, attestorTeeAttestation, { requireClaimAttestation: !!effective.attestorTeeAttestation });
39
42
  isAttestorTeeAttestationVerified = summary.verified > 0;
40
43
  }
41
44
  return {
@@ -51,27 +54,30 @@ export async function verifyRequestProof(proofOrProofs, config) {
51
54
  return {
52
55
  valid: false,
53
56
  reason: failureReason(error),
57
+ transient: isTransientFailure(error),
54
58
  };
55
59
  }
56
60
  }
57
61
  async function resolveValidation(config, proofs) {
58
62
  let effective = config;
59
- if (config.sessionId && !hasContentValidation(config)) {
60
- if (!config.resolveSession) {
63
+ const { sessionId, resolveSession } = config;
64
+ if (sessionId && !hasContentValidation(config)) {
65
+ if (!resolveSession) {
61
66
  throw new Error('session-resolver-required');
62
67
  }
63
68
  effective = {
64
69
  ...config,
65
- ...await config.resolveSession(config.sessionId, proofs),
70
+ ...await networkStep(() => resolveSession(sessionId, proofs)),
66
71
  };
67
72
  }
68
73
  return effective;
69
74
  }
70
75
  async function resolveAttestorTrust(config) {
71
76
  const addresses = config.attestorAddresses?.map(normalized) ?? [];
72
- const imageDigests = [];
73
- if (config.attestorJwksUrl) {
74
- const registry = await fetchReclaimJwks(config.attestorJwksUrl, config.fetchImpl);
77
+ const imageDigests = config.attestorImageDigests?.map(normalized) ?? [];
78
+ const { attestorJwksUrl, fetchImpl } = config;
79
+ if (attestorJwksUrl) {
80
+ const registry = await networkStep(() => (fetchReclaimJwks(attestorJwksUrl, fetchImpl)));
75
81
  addresses.push(...(registry['x-reclaim-attestors'] ?? []), ...trustedAttestorAddresses(registry.keys));
76
82
  imageDigests.push(...(registry['x-reclaim-attestor-image-digests'] ?? []));
77
83
  }
@@ -131,11 +137,12 @@ async function assertContent(proofs, config) {
131
137
  assertValidProofHashes(proofs, config.hashes, config.hasNoPii);
132
138
  return;
133
139
  }
134
- if (config.providerId) {
135
- if (!config.resolveProvider) {
140
+ const { providerId, providerVersion, allowedTags, resolveProvider } = config;
141
+ if (providerId) {
142
+ if (!resolveProvider) {
136
143
  throw new Error('provider-resolver-required');
137
144
  }
138
- const candidates = await config.resolveProvider(config.providerId, config.providerVersion, config.allowedTags, proofs);
145
+ const candidates = await networkStep(() => (resolveProvider(providerId, providerVersion, allowedTags, proofs)));
139
146
  if (!candidates.length) {
140
147
  throw new Error('provider-not-found');
141
148
  }
package/lib/result.d.ts CHANGED
@@ -132,6 +132,9 @@ export interface ResultProofOutcome {
132
132
  proof?: ReclaimRequestProof;
133
133
  proofValid: boolean;
134
134
  reason?: string;
135
+ /** On failure: true when a temporary condition caused it, such as a
136
+ * network error while resolving the provider. */
137
+ transient?: boolean;
135
138
  /** @deprecated Use `attestorAddresses`; retained for compatibility. */
136
139
  attestorAddress?: string;
137
140
  /** Every attestor address declared by the proof. */
@@ -157,11 +160,17 @@ export interface VerifyResultFullOutcome extends VerifyResultOutcome {
157
160
  }
158
161
  export interface ResultVerificationFailure extends VerifyResultFullOutcome {
159
162
  reason: string;
163
+ /** True when a temporary condition caused the failure. Set by the
164
+ * verifier; read it as {@link ResultVerificationError.retryable}. */
165
+ retryable?: boolean;
160
166
  }
161
167
  /**
162
168
  * Thrown by {@link verifyResult} / {@link verifyResultFull} (and therefore
163
169
  * `reclaim.results.verify`/`receive`) when a result fails verification. Carries
164
- * the full invalid outcome so callers can inspect it in a `catch`:
170
+ * the full invalid outcome so callers can inspect it in a `catch`.
171
+ *
172
+ * In a callback handler, answer 2xx when `retryable` is `false` (Builder
173
+ * retrying the same delivery can't help) and 5xx when it's `true`:
165
174
  *
166
175
  * try {
167
176
  * const { result } = await reclaim.results.receive(body, {
@@ -172,6 +181,7 @@ export interface ResultVerificationFailure extends VerifyResultFullOutcome {
172
181
  * if (err instanceof ResultVerificationError) {
173
182
  * // for example, 'expired', { payload, … }
174
183
  * console.error(err.reason, err.outcome)
184
+ * res.sendStatus(err.retryable ? 503 : 200)
175
185
  * }
176
186
  * }
177
187
  */
@@ -182,6 +192,15 @@ export declare class ResultVerificationError extends Error {
182
192
  /** The full (invalid) outcome: `payload`, `reclaimSessionId`, and per-proof
183
193
  * detail (`proofs`) when verification got that far. */
184
194
  readonly outcome: ResultVerificationFailure;
195
+ /**
196
+ * Whether a retry can succeed. `true` only for a temporary condition on
197
+ * the verifier's side: Builder's JWKS or recipe couldn't be fetched
198
+ * (network error, timeout, 5xx, 429). `false` when the result itself is
199
+ * wrong (signature, issuer, audience, session, expiry, invalid proof), so
200
+ * redelivering the same body fails the same way. Respond 5xx to a
201
+ * callback only when `true`.
202
+ */
203
+ readonly retryable: boolean;
185
204
  constructor(outcome: ResultVerificationFailure);
186
205
  }
187
206
  /**
package/lib/result.js CHANGED
@@ -13,6 +13,7 @@
13
13
  import { sha256 } from '@noble/hashes/sha2.js';
14
14
  import { decrypt as eciesDecrypt, encrypt as eciesEncrypt } from 'eciesjs';
15
15
  import { b64url, base64urlToBytes, hexToBytes, stripTrailingSlashes, } from "./encoding.js";
16
+ import { isTransientError } from "./errors.js";
16
17
  import { fetchReclaimJwks, jwkToUncompressedPublicKey, selectVerificationResultKey, } from "./jwks.js";
17
18
  import { getHashFromProof } from "./proof-hash.js";
18
19
  import { proofHashesFromBuilderRecipe, } from "./proof-recipe.js";
@@ -145,7 +146,10 @@ export function verifyJwsSignature(jws, signerPublicKey) {
145
146
  /**
146
147
  * Thrown by {@link verifyResult} / {@link verifyResultFull} (and therefore
147
148
  * `reclaim.results.verify`/`receive`) when a result fails verification. Carries
148
- * the full invalid outcome so callers can inspect it in a `catch`:
149
+ * the full invalid outcome so callers can inspect it in a `catch`.
150
+ *
151
+ * In a callback handler, answer 2xx when `retryable` is `false` (Builder
152
+ * retrying the same delivery can't help) and 5xx when it's `true`:
149
153
  *
150
154
  * try {
151
155
  * const { result } = await reclaim.results.receive(body, {
@@ -156,6 +160,7 @@ export function verifyJwsSignature(jws, signerPublicKey) {
156
160
  * if (err instanceof ResultVerificationError) {
157
161
  * // for example, 'expired', { payload, … }
158
162
  * console.error(err.reason, err.outcome)
163
+ * res.sendStatus(err.retryable ? 503 : 200)
159
164
  * }
160
165
  * }
161
166
  */
@@ -165,6 +170,7 @@ export class ResultVerificationError extends Error {
165
170
  this.name = 'ResultVerificationError';
166
171
  this.reason = outcome.reason;
167
172
  this.outcome = outcome;
173
+ this.retryable = outcome.retryable ?? false;
168
174
  }
169
175
  }
170
176
  /**
@@ -230,8 +236,10 @@ export async function verifyResultFull(jws, opts = {}) {
230
236
  jwksAttestorImageDigests =
231
237
  registry['x-reclaim-attestor-image-digests'] ?? [];
232
238
  }
233
- catch {
234
- return fail('jwks-fetch-failed');
239
+ catch (error) {
240
+ return fail('jwks-fetch-failed', {
241
+ retryable: isTransientError(error),
242
+ });
235
243
  }
236
244
  const jwk = selectVerificationResultKey(keys, String(header.kid ?? ''));
237
245
  if (!jwk) {
@@ -348,7 +356,12 @@ export async function verifyResultFull(jws, opts = {}) {
348
356
  else if (configuredImageDigests?.length) {
349
357
  expectedImageDigests = configuredImageDigests;
350
358
  }
351
- const attestorTeeAttestation = expectedImageDigests.length
359
+ // A caller-configured check requires a `claimAttestation` on every
360
+ // witness. Registry digests alone only pin the attestor reports that
361
+ // are present, as `@reclaimprotocol/js-sdk` does by default — a portal
362
+ // TEE proof without a bound nonce carries no envelope.
363
+ const attestorTeeAttestation = configuredAttestorTee
364
+ && expectedImageDigests.length
352
365
  ? { ...configuredAttestorTee, expectedImageDigests }
353
366
  : configuredAttestorTee;
354
367
  const commonValidation = {
@@ -360,6 +373,9 @@ export async function verifyResultFull(jws, opts = {}) {
360
373
  ...(attestorTeeAttestation
361
374
  ? { attestorTeeAttestation }
362
375
  : {}),
376
+ ...(expectedImageDigests.length
377
+ ? { attestorImageDigests: expectedImageDigests }
378
+ : {}),
363
379
  ...(expectedSessionId
364
380
  ? {
365
381
  expectedSessionId,
@@ -375,7 +391,12 @@ export async function verifyResultFull(jws, opts = {}) {
375
391
  }
376
392
  }
377
393
  if (!proofs.every((p) => p.proofValid)) {
378
- return fail('invalid-proof', { proofs });
394
+ // Retry only when every failure is transient; one genuinely invalid
395
+ // proof makes redelivery pointless.
396
+ return fail('invalid-proof', {
397
+ proofs,
398
+ retryable: proofs.every((p) => p.proofValid || p.transient),
399
+ });
379
400
  }
380
401
  return { payload, reclaimSessionId, proofs };
381
402
  async function verifyRequestProofGroup(group, validation) {
@@ -403,6 +424,7 @@ export async function verifyResultFull(jws, opts = {}) {
403
424
  for (const { outcomeIndex } of group) {
404
425
  proofs[outcomeIndex].proofValid = false;
405
426
  proofs[outcomeIndex].reason = requestProofOutcome.reason;
427
+ proofs[outcomeIndex].transient = requestProofOutcome.transient;
406
428
  }
407
429
  }
408
430
  async function verifyByResolvedRecipes(common, expectedSessionId) {
@@ -412,8 +434,11 @@ export async function verifyResultFull(jws, opts = {}) {
412
434
  const resolved = await opts.resolveSession(expectedSessionId);
413
435
  recipes = resolved.recipes;
414
436
  }
415
- catch {
416
- return fail('session-resolution-failed', { proofs });
437
+ catch (error) {
438
+ return fail('session-resolution-failed', {
439
+ proofs,
440
+ retryable: isTransientError(error),
441
+ });
417
442
  }
418
443
  }
419
444
  const groups = Map.groupBy(proofGroups, proofGroupKey);
@@ -3,6 +3,10 @@ export declare const ROUTES: {
3
3
  readonly method: "post";
4
4
  readonly path: "/orgs/{orgId}/invite";
5
5
  };
6
+ readonly AcknowledgeCallbackEvents: {
7
+ readonly method: "post";
8
+ readonly path: "/verifications/callback-events/acknowledge";
9
+ };
6
10
  readonly AddOrgMember: {
7
11
  readonly method: "post";
8
12
  readonly path: "/orgs/{orgId}/members";
@@ -91,6 +95,10 @@ export declare const ROUTES: {
91
95
  readonly method: "post";
92
96
  readonly path: "/admin/orgs/{orgId}/credits/{grantId}/void";
93
97
  };
98
+ readonly AgentInstallationMarkdown: {
99
+ readonly method: "get";
100
+ readonly path: "/docs/agent-installation.md";
101
+ };
94
102
  readonly AppleAppSiteAssociation: {
95
103
  readonly method: "get";
96
104
  readonly path: "/.well-known/apple-app-site-association";
@@ -391,6 +399,10 @@ export declare const ROUTES: {
391
399
  readonly method: "get";
392
400
  readonly path: "/verifications/callback-dlq";
393
401
  };
402
+ readonly ListCallbackEvents: {
403
+ readonly method: "get";
404
+ readonly path: "/verifications/callback-events";
405
+ };
394
406
  readonly ListCallbackSubscriptions: {
395
407
  readonly method: "get";
396
408
  readonly path: "/verifications/callback-subscriptions";
@@ -495,6 +507,10 @@ export declare const ROUTES: {
495
507
  readonly method: "post";
496
508
  readonly path: "/admin/billing/transactions/{txId}/refund";
497
509
  };
510
+ readonly ReleaseCallbackListener: {
511
+ readonly method: "post";
512
+ readonly path: "/verifications/callback-listener/release";
513
+ };
498
514
  readonly RemoveOrgMember: {
499
515
  readonly method: "delete";
500
516
  readonly path: "/orgs/{orgId}/members/{memberId}";
package/lib/routes.gen.js CHANGED
@@ -1,10 +1,11 @@
1
1
  // AUTO-GENERATED by packages/app/scripts/mcp-tools-gen.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.
6
6
  export const ROUTES = {
7
7
  "AcceptOrgInvite": { "method": "post", "path": "/orgs/{orgId}/invite" },
8
+ "AcknowledgeCallbackEvents": { "method": "post", "path": "/verifications/callback-events/acknowledge" },
8
9
  "AddOrgMember": { "method": "post", "path": "/orgs/{orgId}/members" },
9
10
  "AddProviderContributionComment": { "method": "post", "path": "/providers/{providerId}/contributions/{campaignId}/comments" },
10
11
  "AddStaffMember": { "method": "post", "path": "/admin/staff" },
@@ -27,6 +28,7 @@ export const ROUTES = {
27
28
  "AdminUsers": { "method": "get", "path": "/admin/users" },
28
29
  "AdminVerificationClients": { "method": "get", "path": "/admin/verification-clients" },
29
30
  "AdminVoidOrgCredit": { "method": "post", "path": "/admin/orgs/{orgId}/credits/{grantId}/void" },
31
+ "AgentInstallationMarkdown": { "method": "get", "path": "/docs/agent-installation.md" },
30
32
  "AppleAppSiteAssociation": { "method": "get", "path": "/.well-known/apple-app-site-association" },
31
33
  "AssetLinksJson": { "method": "get", "path": "/.well-known/assetlinks.json" },
32
34
  "BindVerificationSessionTeeNonce": { "method": "put", "path": "/verifications/sessions/{sessionId}/tee-nonce" },
@@ -102,6 +104,7 @@ export const ROUTES = {
102
104
  "JwksJson": { "method": "get", "path": "/.well-known/jwks.json" },
103
105
  "ListBillingPlans": { "method": "get", "path": "/billing/plans" },
104
106
  "ListCallbackDlq": { "method": "get", "path": "/verifications/callback-dlq" },
107
+ "ListCallbackEvents": { "method": "get", "path": "/verifications/callback-events" },
105
108
  "ListCallbackSubscriptions": { "method": "get", "path": "/verifications/callback-subscriptions" },
106
109
  "ListFeatureFlagRevisions": { "method": "get", "path": "/admin/feature-flags/{flagKey}/revisions" },
107
110
  "ListOrgCallbackSubscriptions": { "method": "get", "path": "/orgs/{orgId}/callback-subscriptions" },
@@ -128,6 +131,7 @@ export const ROUTES = {
128
131
  "PublishProviderVersion": { "method": "post", "path": "/providers/{providerId}/versions/{version}/publish" },
129
132
  "RefreshBillingPlans": { "method": "post", "path": "/admin/billing/plans/refresh" },
130
133
  "RefundTransaction": { "method": "post", "path": "/admin/billing/transactions/{txId}/refund" },
134
+ "ReleaseCallbackListener": { "method": "post", "path": "/verifications/callback-listener/release" },
131
135
  "RemoveOrgMember": { "method": "delete", "path": "/orgs/{orgId}/members/{memberId}" },
132
136
  "RemoveStaffMember": { "method": "delete", "path": "/admin/staff/{email}" },
133
137
  "ReportClaimant": { "method": "post", "path": "/v/{sessionId}/claimant" },