@reclaimprotocol/client 0.1.29 → 0.1.31

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.
Files changed (110) hide show
  1. package/README.md +255 -234
  2. package/lib/api.d.ts +2 -0
  3. package/lib/api.js +2 -0
  4. package/lib/client.js +2 -0
  5. package/lib/enckeys.d.ts +1 -1
  6. package/lib/enckeys.js +2 -2
  7. package/lib/encoding.d.ts +4 -0
  8. package/lib/encoding.js +10 -0
  9. package/lib/feature-flags.d.ts +9 -0
  10. package/lib/feature-flags.js +19 -0
  11. package/lib/index.d.ts +4 -4
  12. package/lib/index.js +4 -4
  13. package/lib/jwks.d.ts +8 -8
  14. package/lib/jwks.js +38 -17
  15. package/lib/launch/destination.d.ts +14 -0
  16. package/lib/launch/destination.js +89 -0
  17. package/lib/launch/device.d.ts +30 -0
  18. package/lib/launch/device.js +168 -0
  19. package/lib/launch/environment.d.ts +224 -0
  20. package/lib/launch/environment.js +98 -0
  21. package/lib/launch/errors.d.ts +20 -0
  22. package/lib/launch/errors.js +25 -0
  23. package/lib/launch/extension.d.ts +42 -0
  24. package/lib/launch/extension.js +72 -0
  25. package/lib/launch/flow.d.ts +82 -0
  26. package/lib/launch/flow.js +222 -0
  27. package/lib/launch/index.d.ts +16 -0
  28. package/lib/launch/index.js +12 -0
  29. package/lib/launch/mobile.d.ts +77 -0
  30. package/lib/launch/mobile.js +124 -0
  31. package/lib/launch/modal.d.ts +50 -0
  32. package/lib/launch/modal.js +258 -0
  33. package/lib/launch/options.d.ts +74 -0
  34. package/lib/launch/options.js +20 -0
  35. package/lib/launch/portal.d.ts +28 -0
  36. package/lib/launch/portal.js +68 -0
  37. package/lib/launch/qr.d.ts +5 -0
  38. package/lib/launch/qr.js +28 -0
  39. package/lib/launch/target.d.ts +46 -0
  40. package/lib/launch/target.js +128 -0
  41. package/lib/launch/vendor/qrcodegen.d.ts +134 -0
  42. package/lib/launch/vendor/qrcodegen.js +822 -0
  43. package/lib/legacy-proof.d.ts +2 -0
  44. package/lib/legacy-proof.js +37 -7
  45. package/lib/proof-hash.d.ts +5 -5
  46. package/lib/proof-hash.js +1 -1
  47. package/lib/proof-recipe.d.ts +3 -3
  48. package/lib/proof-recipe.js +1 -1
  49. package/lib/proof-types.d.ts +35 -8
  50. package/lib/reclaim.d.ts +81 -70
  51. package/lib/reclaim.js +79 -130
  52. package/lib/request-proof.d.ts +60 -0
  53. package/lib/request-proof.js +241 -0
  54. package/lib/result.d.ts +46 -38
  55. package/lib/result.js +160 -100
  56. package/lib/routes.gen.d.ts +76 -28
  57. package/lib/routes.gen.js +24 -11
  58. package/lib/tee-binding.d.ts +1 -1
  59. package/lib/types/openapi.d.ts +1 -0
  60. package/lib/types/openapi.gen.d.ts +1594 -488
  61. package/lib/types/openapi.gen.js +5 -0
  62. package/lib/verification-clients.d.ts +28 -14
  63. package/lib/verification-clients.js +31 -11
  64. package/lib/verify-attestor-tee.d.ts +19 -2
  65. package/lib/verify-attestor-tee.js +40 -4
  66. package/lib/verify-tee.d.ts +10 -1
  67. package/lib/verify-tee.js +34 -10
  68. package/package.json +5 -1
  69. package/src/api.ts +9 -0
  70. package/src/client.ts +2 -0
  71. package/src/enckeys.ts +2 -2
  72. package/src/encoding.ts +12 -0
  73. package/src/feature-flags.ts +39 -0
  74. package/src/index.ts +13 -14
  75. package/src/jwks.ts +52 -30
  76. package/src/launch/destination.ts +111 -0
  77. package/src/launch/device.ts +242 -0
  78. package/src/launch/environment.ts +337 -0
  79. package/src/launch/errors.ts +49 -0
  80. package/src/launch/extension.ts +124 -0
  81. package/src/launch/flow.ts +369 -0
  82. package/src/launch/index.ts +42 -0
  83. package/src/launch/mobile.ts +184 -0
  84. package/src/launch/modal.ts +378 -0
  85. package/src/launch/options.ts +99 -0
  86. package/src/launch/portal.ts +104 -0
  87. package/src/launch/qr.ts +37 -0
  88. package/src/launch/target.ts +150 -0
  89. package/src/launch/vendor/qrcodegen.ts +1034 -0
  90. package/src/proof-hash.ts +6 -6
  91. package/src/proof-recipe.ts +3 -3
  92. package/src/proof-types.ts +36 -8
  93. package/src/reclaim.ts +185 -218
  94. package/src/{legacy-proof.ts → request-proof.ts} +81 -36
  95. package/src/result.ts +238 -172
  96. package/src/routes.gen.ts +24 -11
  97. package/src/tee-binding.ts +1 -1
  98. package/src/types/openapi.gen.ts +1599 -488
  99. package/src/types/openapi.ts +3 -1
  100. package/src/verification-clients.ts +33 -19
  101. package/src/verify-attestor-tee.ts +66 -8
  102. package/src/verify-tee.ts +44 -13
  103. package/lib/api-client.d.ts +0 -31
  104. package/lib/api-client.js +0 -112
  105. package/lib/api-consts.d.ts +0 -4
  106. package/lib/api-consts.js +0 -4
  107. package/lib/api-errors.d.ts +0 -13
  108. package/lib/api-errors.js +0 -30
  109. package/lib/eip712.d.ts +0 -20
  110. package/lib/eip712.js +0 -108
@@ -44,6 +44,8 @@ export interface LegacyProofOutcome {
44
44
  reason?: string;
45
45
  proofHashes?: string[];
46
46
  isTeeAttestationVerified?: boolean;
47
+ /** True when at least one witness's `attestation_report` verified; false
48
+ * when the check ran and no witness carried one. */
47
49
  isAttestorTeeAttestationVerified?: boolean;
48
50
  data?: TrustedData[];
49
51
  publicData?: unknown[];
@@ -20,8 +20,8 @@ export async function verifyProof(proofOrProofs, config) {
20
20
  try {
21
21
  const effective = await resolveValidation(config, proofs);
22
22
  assertSessionAndContext(proofs, effective);
23
- const attestors = await resolveTrustedAttestors(effective);
24
- assertVerifiedSignatures(proofs, attestors);
23
+ const trust = await resolveAttestorTrust(effective);
24
+ assertVerifiedSignatures(proofs, trust.addresses);
25
25
  await assertContent(proofs, effective);
26
26
  let isTeeAttestationVerified;
27
27
  if (effective.teeAttestation) {
@@ -29,9 +29,14 @@ export async function verifyProof(proofOrProofs, config) {
29
29
  isTeeAttestationVerified = true;
30
30
  }
31
31
  let isAttestorTeeAttestationVerified;
32
- if (effective.attestorTeeAttestation) {
33
- await runAttestorTeeVerification(proofs, effective.attestorTeeAttestation);
34
- isAttestorTeeAttestationVerified = true;
32
+ const attestorTeeAttestation = resolveAttestorTeeAttestation(effective.attestorTeeAttestation, trust.imageDigests);
33
+ if (attestorTeeAttestation) {
34
+ // `verified` counts witnesses whose attestation report was checked.
35
+ // A proof whose witnesses carry no report still passes the address
36
+ // and signature bindings, but nothing was attested — say so rather
37
+ // than reporting a TEE attestation that never happened.
38
+ const summary = await runAttestorTeeVerification(proofs, attestorTeeAttestation);
39
+ isAttestorTeeAttestationVerified = summary.verified > 0;
35
40
  }
36
41
  return {
37
42
  valid: true,
@@ -62,17 +67,42 @@ async function resolveValidation(config, proofs) {
62
67
  }
63
68
  return effective;
64
69
  }
65
- async function resolveTrustedAttestors(config) {
70
+ async function resolveAttestorTrust(config) {
66
71
  const addresses = config.attestorAddresses?.map(normalized) ?? [];
72
+ const imageDigests = [];
67
73
  if (config.attestorJwksUrl) {
68
74
  const registry = await fetchReclaimJwks(config.attestorJwksUrl, config.fetchImpl);
69
75
  addresses.push(...(registry['x-reclaim-attestors'] ?? []), ...trustedAttestorAddresses(registry.keys));
76
+ imageDigests.push(...(registry['x-reclaim-attestor-image-digests'] ?? []));
70
77
  }
71
78
  const unique = [...new Set(addresses)];
72
79
  if (!unique.length) {
73
80
  throw new Error('attestor-trust-required');
74
81
  }
75
- return unique;
82
+ return {
83
+ addresses: unique,
84
+ imageDigests: [...new Set(imageDigests)],
85
+ };
86
+ }
87
+ function resolveAttestorTeeAttestation(configured, registryImageDigests) {
88
+ if (!registryImageDigests.length) {
89
+ return configured;
90
+ }
91
+ const configuredDigests = configured?.expectedImageDigests;
92
+ if (configuredDigests?.length) {
93
+ const registry = new Set(registryImageDigests);
94
+ const expectedImageDigests = [...new Set(configuredDigests
95
+ .map((digest) => digest.trim().toLowerCase())
96
+ .filter((digest) => registry.has(digest)))];
97
+ if (!expectedImageDigests.length) {
98
+ throw new Error('attestor-image-trust-mismatch');
99
+ }
100
+ return { ...configured, expectedImageDigests };
101
+ }
102
+ return {
103
+ ...configured,
104
+ expectedImageDigests: registryImageDigests,
105
+ };
76
106
  }
77
107
  function assertVerifiedSignatures(proofs, trustedAttestors) {
78
108
  for (const proof of proofs) {
@@ -1,4 +1,4 @@
1
- import type { HashRequirement, LegacyProof } from './proof-types.ts';
1
+ import type { HashRequirement, ReclaimRequestProof } from './proof-types.ts';
2
2
  export interface HttpProofParams {
3
3
  url: string;
4
4
  method: string;
@@ -27,9 +27,9 @@ export interface ProofRequestSpec extends HttpProofParams {
27
27
  templateParams?: string[];
28
28
  templateParamsMode?: 'separate' | 'merge';
29
29
  }
30
- /** Exact legacy canonical HTTP-provider hashes, including optional matches. */
30
+ /** Exact canonical HTTP-provider hashes, including optional matches. */
31
31
  export declare function hashProofClaimParams(params: HttpProofParams): string[];
32
- export declare function getHashFromProof(proof: LegacyProof, hasNoPii?: boolean): string[];
32
+ export declare function getHashFromProof(proof: ReclaimRequestProof, hasNoPii?: boolean): string[];
33
33
  export declare function hashRequestSpec(request: ProofRequestSpec): HashRequirement;
34
- export declare function hashRequirementsFromSpecs(requestData: ProofRequestSpec[], allowedInjectedRequestData: ProofRequestSpec[], proofs: LegacyProof[]): HashRequirement[];
35
- export declare function assertValidProofHashes(proofs: LegacyProof[], requirements: Array<string | HashRequirement>, hasNoPii?: boolean): void;
34
+ export declare function hashRequirementsFromSpecs(requestData: ProofRequestSpec[], allowedInjectedRequestData: ProofRequestSpec[], proofs: ReclaimRequestProof[]): HashRequirement[];
35
+ export declare function assertValidProofHashes(proofs: ReclaimRequestProof[], requirements: Array<string | HashRequirement>, hasNoPii?: boolean): void;
package/lib/proof-hash.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { keccak_256 } from '@noble/hashes/sha3.js';
2
2
  import { canonicalJson as canonical } from "./canonical.js";
3
3
  import { bytesToHex } from "./encoding.js";
4
- /** Exact legacy canonical HTTP-provider hashes, including optional matches. */
4
+ /** Exact canonical HTTP-provider hashes, including optional matches. */
5
5
  export function hashProofClaimParams(params) {
6
6
  return canonicalProofParams(params).map((serialized) => ('0x' + bytesToHex(keccak_256(new TextEncoder().encode(serialized)))));
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import type { components } from './types/openapi.gen.ts';
2
- import type { LegacyProof } from './proof-types.ts';
2
+ import type { ReclaimRequestProof } from './proof-types.ts';
3
3
  type RequestSelection = components['schemas']['RequestSelection'];
4
4
  type RequestSelectionTemplate = components['schemas']['RequestSelectionTemplate'];
5
5
  /** Resolved Builder provider recipe returned for a verification session. */
@@ -11,8 +11,8 @@ export interface BuilderProofRecipe {
11
11
  allowedJsRequests?: RequestSelectionTemplate[];
12
12
  }
13
13
  /**
14
- * Derive the exact hash requirements consumed by legacy `verifyProof` from a
14
+ * Derive the exact hash requirements consumed by `verifyRequestProof` from a
15
15
  * resolved Builder recipe. Builder's fixed requests are required once each.
16
16
  */
17
- export declare function proofHashesFromBuilderRecipe(recipe: BuilderProofRecipe, proofs: LegacyProof[]): import("./proof-types.ts").HashRequirement[];
17
+ export declare function proofHashesFromBuilderRecipe(recipe: BuilderProofRecipe, proofs: ReclaimRequestProof[]): import("./proof-types.ts").HashRequirement[];
18
18
  export {};
@@ -1,6 +1,6 @@
1
1
  import { hashRequirementsFromSpecs, } from "./proof-hash.js";
2
2
  /**
3
- * Derive the exact hash requirements consumed by legacy `verifyProof` from a
3
+ * Derive the exact hash requirements consumed by `verifyRequestProof` from a
4
4
  * resolved Builder recipe. Builder's fixed requests are required once each.
5
5
  */
6
6
  export function proofHashesFromBuilderRecipe(recipe, proofs) {
@@ -1,15 +1,19 @@
1
- /** Exact legacy proof structures carried inside Builder result envelopes. */
2
- export interface LegacyProof {
1
+ /** Exact proof structure for one verified request, carried inside Builder
2
+ * result envelopes. Every Verification Client — the in-app SDK, the browser
3
+ * extension, portals, and Builder's own client — emits this shape. */
4
+ export interface ReclaimRequestProof {
3
5
  identifier: string;
4
- claimData: LegacyClaimData;
6
+ claimData: RequestClaimData;
5
7
  signatures: string[];
6
- witnesses: LegacyWitness[];
8
+ witnesses: RequestWitness[];
7
9
  extractedParameterValues: unknown;
8
10
  publicData?: unknown;
9
11
  taskId?: number;
10
- teeAttestation?: TeeAttestation | string;
12
+ /** Client-specific legacy TEE data. Verification validates a supported
13
+ * representation only when TEE verification is requested. */
14
+ teeAttestation?: unknown;
11
15
  }
12
- export interface LegacyClaimData {
16
+ export interface RequestClaimData {
13
17
  provider: string;
14
18
  parameters: string;
15
19
  owner: string;
@@ -18,15 +22,38 @@ export interface LegacyClaimData {
18
22
  identifier: string;
19
23
  epoch: number;
20
24
  }
21
- export interface LegacyWitness {
25
+ export interface RequestWitness {
22
26
  id: string;
23
27
  url: string;
24
28
  claimAttestation?: AttestorClaimAttestation;
25
29
  }
30
+ /**
31
+ * Which kind of attestation a witness carries.
32
+ *
33
+ * `embedded-attestor` — the in-app SDK and the browser extension. The attestor
34
+ * signs the claim and, on a TEE run, may also return its own
35
+ * `attestation_report`.
36
+ *
37
+ * `confidential-space` — portals. The browser runtime signs the claim inside a
38
+ * GCP Confidential Space and returns `tee_attestation`, bound to the claim
39
+ * through `context.attestationNonce`.
40
+ */
41
+ export type ClaimAttestationType = 'embedded-attestor' | 'confidential-space';
26
42
  export interface AttestorClaimAttestation {
43
+ type: ClaimAttestationType;
27
44
  attestor_address: string;
28
45
  claim_signature: string;
29
- attestation_report: string;
46
+ /** `embedded-attestor` only, and optional even then: the attestor's own GCP
47
+ * Confidential Space attestation (an RS256 JWT). Attestors in production
48
+ * sign claims without returning one, so a witness routinely carries only
49
+ * the address and the claim signature. */
50
+ attestation_report?: string;
51
+ /** `confidential-space` only: the same payload legacy proofs carry in the
52
+ * proof's top-level `teeAttestation`, and typed the same way. It comes
53
+ * from an external producer and is preserved verbatim, so callers validate
54
+ * it at runtime — `verifyTeeAttestation` does — rather than trusting a
55
+ * shape the wire does not guarantee. */
56
+ tee_attestation?: unknown;
30
57
  }
31
58
  export interface TeeAttestation {
32
59
  proof_version?: 'v2' | 'v3';
package/lib/reclaim.d.ts CHANGED
@@ -1,20 +1,19 @@
1
1
  /**
2
2
  * Declarative entry point for the consumer SDK. The ONLY config is the org
3
3
  * secret (`rorg_…`) — it authenticates every call and identifies the org
4
- * server-side. Everything else is passed where it's actually used: the `orgId`
5
- * to the org-scoped `keypair.set`/`get`, and the eth decryption key to
6
- * `results.decrypt`/`receive` (only when results arrive encrypted):
4
+ * server-side. Pass the optional organization ETH private key only to the
5
+ * operation that needs it:
7
6
  *
8
- * const reclaim = createReclaim({ orgSecret })
9
- * // one-time setup:
10
- * await reclaim.callbacks.register({ callbackUrl })
11
- * // enable encryption (eth public key, hex):
12
- * await reclaim.keypair.set(orgId, { publicKey, canEncryptResult: true })
13
- * const session = await reclaim.sessions.create({ providers, context })
7
+ * const reclaim = ReclaimVerification.create({ orgSecret })
8
+ * const session = await reclaim.sessions.create({
9
+ * providers,
10
+ * context,
11
+ * orgEthPrivateKey, // optional TEE session binding
12
+ * })
14
13
  * // …end-user completes session.verificationUrl…
15
14
  * const outcome = await reclaim.results.receive(callbackBody, {
16
- * credential: ethPrivateKeyHex, // omit for plaintext
17
- * expectedReclaimSessionId: session.id,
15
+ * orgEthPrivateKey, // optional decryption and TEE proof verification
16
+ * reclaimSessionId: session.id,
18
17
  * })
19
18
  *
20
19
  * Built by composition over the package's pure helpers (`decryptCallback`,
@@ -26,17 +25,9 @@ import { ReclaimClient } from './client.ts';
26
25
  import { type DecryptionKeyInput } from './enckeys.ts';
27
26
  import { type CallbackBody, type Jws, type VerifyResultFullOptions, type VerifyResultFullOutcome } from './result.ts';
28
27
  import { type LegacyTeeNonceMode } from './tee-binding.ts';
29
- type CallbackSubscription = components['schemas']['CallbackSubscription'];
30
28
  type VerificationSession = components['schemas']['VerificationSession'];
31
29
  type VerificationEvent = components['schemas']['VerificationEvent'];
32
30
  type VerificationEventRecord = components['schemas']['VerificationEventRecord'];
33
- type OrgKeypair = components['schemas']['OrgKeypair'];
34
- /** Terminal lifecycle events selected by default for callback subscriptions. */
35
- export declare const TERMINAL_EVENTS: readonly ["verification_success", "verification_rejected", "verification_error", "verification_cancelled", "session_expired"];
36
- export interface RegisterCallbackInput {
37
- callbackUrl: string;
38
- events: VerificationEvent[];
39
- }
40
31
  export interface CreateSessionInput {
41
32
  /** Providers to verify, in run order. The end-user proves each (one browser
42
33
  * session) and one combined result is delivered; all are required. */
@@ -45,32 +36,34 @@ export interface CreateSessionInput {
45
36
  version?: string;
46
37
  }[];
47
38
  context: Record<string, unknown>;
48
- /** Exact registered Verification Client base URL. It may contain a
39
+ /** Exact registered Verification Client base URL. Defaults to the Portal.
40
+ * It may contain a
49
41
  * `{sessionId}` placeholder; Builder otherwise adds the session id as a
50
42
  * query parameter. Open the returned `verificationUrl`, not this base
51
43
  * URL. */
52
- verificationClientUrl: string;
53
- /** Optional legacy-compatible TEE session binding. The app secret is the
54
- * organization's verification private key and never leaves this process.
44
+ verificationClientUrl?: string;
45
+ /** Optional legacy-compatible TEE session binding. The organization's ETH
46
+ * private key never leaves this process.
55
47
  * Session creation returns only after Builder stores the signed binding. */
56
- teeAttestation?: CreateSessionTeeAttestation;
48
+ orgEthPrivateKey?: string;
49
+ /** Override the legacy TEE nonce mode when binding a session. */
50
+ teeNonceMode?: LegacyTeeNonceMode;
51
+ /** Opt this session into diagnostic mode: more event detail, including
52
+ * personal data such as the claimant's IP addresses. Builder builds
53
+ * `verificationUrl` with `diag=1` for a diagnostic session — do not
54
+ * append `diag` to the URL directly, since Builder strips it and derives
55
+ * the parameter from this flag instead. Treat a diagnostic
56
+ * `verificationUrl` as sensitive. */
57
+ diagnostics?: boolean;
57
58
  }
58
- /** Options intentionally mirror legacy `verifyProof`'s `teeAttestation`
59
- * vocabulary. `timestamp` is decimal Unix milliseconds; omit it to use now. */
60
- export interface CreateSessionTeeAttestation {
61
- appSecret: string;
59
+ /** Input for explicitly binding a session's legacy-compatible TEE context. */
60
+ export interface BindSessionTeeNonceInput {
61
+ orgEthPrivateKey: string;
62
62
  timestamp?: string;
63
63
  /** `hash` is the default. Use `signature` only for an older Verification
64
64
  * Client that expects the 65-byte EIP-191 nonce. */
65
- nonceMode?: LegacyTeeNonceMode;
65
+ teeNonceMode?: LegacyTeeNonceMode;
66
66
  }
67
- /** Input for `keypair.set`: the org's eth public key as uncompressed hex
68
- * (`publicKey`, the form wallets/ethers emit) OR as a secp256k1 JWK
69
- * (`publicKeyJwk`); keep the matching eth private key to decrypt results.
70
- * `canEncryptResult` toggles ECIES encryption (default off). The two request
71
- * shapes are the spec's `OrgKeypairRequest` union members, relaxed to optional
72
- * so the SDK caller supplies just one key form. */
73
- export type SetKeypairInput = Partial<components['schemas']['OrgKeypairHexRequest']> & Partial<components['schemas']['OrgKeypairJwkRequest']>;
74
67
  export interface ReclaimConfig {
75
68
  /** The org secret (`rorg_…`). Authenticates ALL API calls and identifies
76
69
  * the org server-side. The only required config. */
@@ -82,62 +75,75 @@ export interface ReclaimConfig {
82
75
  /** Extra headers merged into every request. */
83
76
  headers?: Record<string, string>;
84
77
  }
78
+ /** Serializable SDK configuration.
79
+ * Credentials and runtime hooks are omitted. */
80
+ export interface ReclaimVerificationState {
81
+ version: 1;
82
+ baseUrl: string;
83
+ }
84
+ /** Runtime-only values required to restore serialized SDK configuration. */
85
+ export type ImportReclaimVerificationConfig = Omit<ReclaimConfig, 'baseUrl'>;
85
86
  /** Options for `results.receive` — the verification options plus an optional
86
87
  * eth decryption key (the org's eth private key as `0x`-hex). The key is
87
88
  * needed only when the delivery is an ECIES ciphertext. */
88
- export type ReceiveOptions = VerifyResultFullOptions & {
89
- credential?: DecryptionKeyInput;
90
- };
91
- export interface Reclaim {
89
+ export type ReceiveOptions = VerifyResultFullOptions;
90
+ /** A thin backend-side handle on a session's `verificationUrl` — see
91
+ * `reclaim.flow`. Not the browser launcher: this holds no device
92
+ * detection or launch mechanism, only the URL the browser needs. The
93
+ * browser-only `ReclaimFlow.from(session)` in
94
+ * `@reclaimprotocol/client/launch` is the counterpart that actually
95
+ * resolves how to open it. */
96
+ export interface SessionFlow {
97
+ /** `session.verificationUrl`. A `Promise` so backend code calling this
98
+ * doesn't need to special-case it against the browser `ReclaimFlow`'s
99
+ * `getUrl()`, which does real async work. */
100
+ getUrl(): Promise<string>;
101
+ readonly session: VerificationSession;
102
+ }
103
+ /** `reclaim.flow(session)` wraps a session already created via
104
+ * `sessions.create`/`sessions.get`; `reclaim.flow.create(input)` creates one
105
+ * and wraps it in the same step. */
106
+ export interface ReclaimFlowFactory {
107
+ (session: VerificationSession): SessionFlow;
108
+ create(input: CreateSessionInput): Promise<SessionFlow>;
109
+ }
110
+ export interface ReclaimVerification {
111
+ /** Serialize non-secret configuration. Credentials, headers, and custom
112
+ * fetch implementations are never included. */
113
+ export(): string;
92
114
  /** Typed escape hatch: `reclaim.api('OperationId', args)` for any spec
93
115
  * operation. */
94
116
  api: ReclaimClient['call'];
95
117
  sessions: {
96
118
  /** Create a verification session. `verificationClientUrl` defaults to
97
- * the Builder's own `/v/{sessionId}` page. */
98
- create(input: Omit<CreateSessionInput, 'verificationClientUrl'> & Partial<Pick<CreateSessionInput, 'verificationClientUrl'>>): Promise<VerificationSession>;
119
+ * the Portal, `VerificationClient.portals`. */
120
+ create(input: CreateSessionInput): Promise<VerificationSession>;
99
121
  /** Add the immutable legacy-compatible TEE context after session
100
122
  * creation. Normally use
101
- * `sessions.create({ teeAttestation: { appSecret } })`; this method
123
+ * `sessions.create({ orgEthPrivateKey })`; this method
102
124
  * supports retrying or explicitly orchestrating the two-step flow. */
103
- bindTeeNonce(sessionId: string, input: CreateSessionTeeAttestation): Promise<VerificationSession>;
104
- get(sessionId: string): Promise<VerificationSession>;
105
- listEvents(sessionId: string): Promise<VerificationEventRecord[]>;
106
- };
107
- callbacks: {
108
- /** Register a callback subscription (one-time setup). Delivery is scoped
109
- * to the token's org; results are ECIES-encrypted to the org's eth key
110
- * when `canEncryptResult` is enabled (see `keypair.set`), else plaintext.
111
- * `events` defaults to all terminal lifecycle events. */
112
- register(input: Partial<RegisterCallbackInput> & Pick<RegisterCallbackInput, 'callbackUrl'>): Promise<CallbackSubscription>;
113
- list(): Promise<CallbackSubscription[]>;
114
- remove(subscriptionId: string): Promise<void>;
115
- };
116
- keypair: {
117
- /** Set/rotate org `orgId`'s single eth encryption keypair. When
118
- * `canEncryptResult` is enabled, terminal results are delivered as an
119
- * ECIES ciphertext encrypted to it. */
120
- set(orgId: string, input: SetKeypairInput): Promise<OrgKeypair>;
121
- /** Get org `orgId`'s encryption keypair, or `undefined` when none is set
122
- * (the org is keyless ⇒ plaintext delivery). */
123
- get(orgId: string): Promise<OrgKeypair | undefined>;
125
+ bindTeeNonce(reclaimSessionId: string, input: BindSessionTeeNonceInput): Promise<VerificationSession>;
126
+ get(reclaimSessionId: string): Promise<VerificationSession>;
127
+ listEvents(reclaimSessionId: string): Promise<VerificationEventRecord[]>;
124
128
  };
125
129
  results: {
126
130
  /** Decrypt a callback body (ECIES ciphertext or plaintext JWS) to the
127
- * signed JWS. Pass the eth `credential` (`0x`-hex private key) only when
128
- * the delivery is encrypted. */
129
- decrypt(body: CallbackBody, credential?: DecryptionKeyInput): Promise<Jws>;
131
+ * signed JWS. Pass `orgEthPrivateKey` only when the delivery is
132
+ * encrypted. */
133
+ decrypt(body: CallbackBody, orgEthPrivateKey?: DecryptionKeyInput): Promise<Jws>;
130
134
  /** Verify a decrypted JWS: JWKS discovery, ES256K signature,
131
- * `reclaimSessionId`/`aud`, any legacy `exp`, and exact legacy proofs. */
135
+ * `reclaimSessionId`/`aud`, any legacy `exp`, and exact proofs. */
132
136
  verify(jws: Jws, opts?: VerifyResultFullOptions): Promise<VerifyResultFullOutcome>;
133
137
  /** Handle any callback delivery in one call — the 90% path. Branches on
134
138
  * the envelope's `event`: a terminal event is decrypted (with
135
- * `opts.credential` when encrypted) + verified into a `result`; a
139
+ * `opts.orgEthPrivateKey` when encrypted) and verified into a `result`; a
136
140
  * non-terminal event is returned as a plaintext (unsigned) `event`
137
141
  * notification without decryption. (A raw JWE/JWS body with no envelope
138
142
  * `event` is treated as a terminal result.) */
139
143
  receive(body: CallbackBody, opts?: ReceiveOptions): Promise<ReceivedDelivery>;
140
144
  };
145
+ /** `reclaim.flow(session)` — see `ReclaimFlowFactory`. */
146
+ flow: ReclaimFlowFactory;
141
147
  }
142
148
  /** Outcome of `results.receive` — a verified terminal result or a plaintext
143
149
  * non-terminal progress notification. Branch on `kind`. */
@@ -149,5 +155,10 @@ export type ReceivedDelivery = {
149
155
  event: VerificationEvent;
150
156
  eventData: Record<string, unknown>;
151
157
  };
152
- export declare function createReclaim(config: ReclaimConfig): Reclaim;
158
+ export declare const ReclaimVerification: Readonly<{
159
+ create: typeof createReclaimVerification;
160
+ import: typeof importReclaimVerification;
161
+ }>;
162
+ declare function importReclaimVerification(serialized: string, config: ImportReclaimVerificationConfig): ReclaimVerification;
163
+ declare function createReclaimVerification(config: ReclaimConfig): ReclaimVerification;
153
164
  export {};