@tinycloud/node-sdk 3.6.0-beta.3 → 3.6.0-beta.5
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 +6 -0
- package/dist/{TinyCloudNode-N4mfZI_k.d.cts → TinyCloudNode-B5WCe_ps.d.ts} +3 -250
- package/dist/{TinyCloudNode-N4mfZI_k.d.ts → TinyCloudNode-CIGurdHw.d.cts} +3 -250
- package/dist/{authority-BgZpUFss.d.cts → authority-Beg1WM2U.d.cts} +1 -1
- package/dist/{authority-C670-9su.d.ts → authority-Vh7ike0I.d.ts} +1 -1
- package/dist/core.d.cts +3 -2
- package/dist/core.d.ts +3 -2
- package/dist/credential-pending-store.cjs +401 -0
- package/dist/credential-pending-store.cjs.map +1 -0
- package/dist/credential-pending-store.d.cts +42 -0
- package/dist/credential-pending-store.d.ts +42 -0
- package/dist/credential-pending-store.js +389 -0
- package/dist/credential-pending-store.js.map +1 -0
- package/dist/credentials-core.cjs +309 -0
- package/dist/credentials-core.cjs.map +1 -0
- package/dist/credentials-core.d.cts +337 -0
- package/dist/credentials-core.d.ts +337 -0
- package/dist/credentials-core.js +294 -0
- package/dist/credentials-core.js.map +1 -0
- package/dist/credentials.cjs +746 -0
- package/dist/credentials.cjs.map +1 -0
- package/dist/credentials.d.cts +4 -0
- package/dist/credentials.d.ts +4 -0
- package/dist/credentials.js +732 -0
- package/dist/credentials.js.map +1 -0
- package/dist/delegation-0LKZkmP2.d.cts +251 -0
- package/dist/delegation-0LKZkmP2.d.ts +251 -0
- package/dist/email-proof-Blhdm4ox.d.cts +155 -0
- package/dist/email-proof-Blhdm4ox.d.ts +155 -0
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/replication/authority.d.cts +3 -2
- package/dist/replication/authority.d.ts +3 -2
- package/package.json +18 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/credentials/interpreter.ts","../src/credentials/transport.ts","../src/credentials/email-proof.ts"],"sourcesContent":["import {\n CredentialError,\n encodeBase64Url,\n holderBindingSigningBytes,\n validateCredentialHolderBinding,\n type CredentialFlowDescriptor,\n type CredentialProgressEvent,\n type CredentialRequirement,\n} from \"@tinycloud/sdk-core\";\nimport type { CredentialAcquisitionTransport, CredentialProofSubject, CredentialSigningAdapter, InlineCredentialProofHandler, InlineCredentialProofRequest, PrimitiveStepHandler } from \"./types\";\n\nconst delay = (ms: number, signal?: AbortSignal) => new Promise<void>((resolve, reject) => {\n const timer = setTimeout(resolve, ms);\n signal?.addEventListener(\"abort\", () => { clearTimeout(timer); reject(new DOMException(\"Aborted\", \"AbortError\")); }, { once: true });\n});\n\n/** The mailbox named by an email requirement, which the issuer delivers the code to. */\nexport function mailboxSubject(requirement: CredentialRequirement): CredentialProofSubject | undefined {\n const email = requirement.claims.email;\n return typeof email === \"string\" && email.length > 0 ? Object.freeze({ kind: \"email\" as const, value: email }) : undefined;\n}\n\n/** Finite step interpreter. Dispatch is exclusively by registered primitive and version. */\nexport async function interpretCredentialFlow(input: {\n readonly descriptor: CredentialFlowDescriptor;\n readonly requirement: CredentialRequirement;\n readonly requestId: string;\n readonly verifier: string;\n readonly holderDid: string;\n readonly descriptorDigest: string;\n readonly requirementDigest: string;\n readonly openerOrigin: string;\n readonly transport: CredentialAcquisitionTransport;\n readonly signing: CredentialSigningAdapter;\n /**\n * Fallback for a host-owned surface. It receives every declared proof step,\n * including primitives added by a later protocol version.\n */\n readonly proofHandler?: InlineCredentialProofHandler;\n readonly handlers?: Partial<Record<\"collect_input\" | \"mailbox_otp\", PrimitiveStepHandler>>;\n readonly signal?: AbortSignal;\n readonly onProgress?: (event: CredentialProgressEvent) => void;\n readonly onWait?: () => Promise<void>;\n}): Promise<void> {\n const steps = new Map(input.descriptor.steps.map((step) => [step.type, step]));\n const completed = new Set<string>(); let lastTransition = \"\";\n for (;;) {\n input.signal?.throwIfAborted();\n const state = await input.transport.state(input.requestId, input.verifier, input.signal);\n if (state.requestId !== input.requestId) throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Credential request identity changed\");\n if (state.state === \"expired\") throw new CredentialError(\"REQUEST_EXPIRED\", \"Credential request expired\", { state: state.state, correlationId: state.correlationId });\n if (state.state === \"canceled\") throw new CredentialError(\"CANCELED\", \"Credential request was canceled\", { state: state.state, correlationId: state.correlationId });\n if (state.state === \"issuer_unready\") throw new CredentialError(\"ISSUER_UNREADY\", \"Credential issuer is not ready\", { retryAfterMs: state.retryAfterMs, state: state.state, correlationId: state.correlationId });\n if (state.state === \"complete\") return;\n if (state.state === \"ready_to_issue\" || state.state === \"issued\") {\n if (state.state === \"ready_to_issue\" && !completed.has(\"issue\")) { await input.transport.issue(input.requestId, input.verifier, input.signal); completed.add(\"issue\"); }\n else await (input.onWait?.() ?? delay(state.retryAfterMs ?? 50, input.signal));\n continue;\n }\n const next = state.nextStep;\n if (!next) { await (input.onWait?.() ?? delay(state.retryAfterMs ?? 50, input.signal)); continue; }\n const declared = steps.get(next.type);\n if (next.id !== next.type || !declared || declared.type !== next.type || declared.version !== next.version) throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Server selected an undeclared credential step\");\n if (completed.has(next.id) || state.transitionId === lastTransition) { await (input.onWait?.() ?? delay(state.retryAfterMs ?? 50, input.signal)); continue; }\n lastTransition = state.transitionId;\n if (next.type === \"holder_signature\") {\n input.onProgress?.({ state: \"signing\", stepId: next.id, correlationId: state.correlationId });\n const binding = validateCredentialHolderBinding(await input.transport.holderBinding(input.requestId, input.verifier, input.signal));\n if (binding.requestId !== input.requestId || binding.descriptorDigest !== input.descriptorDigest || binding.requirementDigest !== input.requirementDigest || binding.holderDid !== input.holderDid || binding.issuer !== input.descriptor.issuer.did || binding.issuerKid !== input.descriptor.issuer.kid || binding.profile !== input.descriptor.profile || binding.openerOrigin !== input.openerOrigin || binding.completionOrigin !== input.openerOrigin || binding.audience !== \"tinycloud://credentials\") throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Holder binding was substituted\");\n const bytes = holderBindingSigningBytes(binding);\n let signature = await input.signing.autoSign?.(binding, bytes, input.signal);\n if (signature === undefined) {\n if (!input.signing.requestApproval) throw new CredentialError(\"SIGNATURE_REJECTED\", \"OpenKey approval is required\");\n try { signature = await input.signing.requestApproval(binding, bytes, input.signal); } catch (cause) { if (cause instanceof CredentialError) throw cause; throw new CredentialError(\"SIGNATURE_REJECTED\", \"OpenKey approval was rejected\", { cause }); }\n }\n if (!(signature instanceof Uint8Array) || signature.length === 0) throw new CredentialError(\"SIGNATURE_REJECTED\", \"OpenKey signature is invalid\");\n await input.transport.submitHolderSignature(input.requestId, input.verifier, encodeBase64Url(signature), input.signal, input.signing.holderKey);\n } else {\n input.onProgress?.({ state: next.type === \"collect_input\" ? \"collecting\" : \"proving\", stepId: next.id, correlationId: state.correlationId });\n const handler = input.handlers?.[next.type];\n const inlineHandler = input.proofHandler;\n if (!handler && !inlineHandler) { await (input.onWait?.() ?? delay(state.retryAfterMs ?? 50, input.signal)); continue; }\n if (next.constraints.challengeRequired === true) await input.transport.beginStep(input.requestId, input.verifier, next.type, input.signal);\n if (handler) {\n const proof = await handler({ descriptor: input.descriptor, requirement: input.requirement, stepId: next.id, constraints: next.constraints, signal: input.signal });\n await input.transport.submitStep(input.requestId, input.verifier, next.id, proof, input.signal);\n } else {\n let feedback: InlineCredentialProofRequest[\"feedback\"];\n // A mistyped code is re-entered against the same challenge; the issuer\n // counts every attempt and reports when the bounded budget is spent.\n for (let attempt = 1; ; attempt += 1) {\n const proof = await inlineHandler!({\n stepId: next.id,\n constraints: next.constraints,\n display: {\n title: input.descriptor.display.title,\n description: input.descriptor.display.description,\n consent: input.descriptor.display.consent,\n progressLabel: input.descriptor.accessibility.progressLabel,\n errorLiveRegion: input.descriptor.accessibility.errorLiveRegion,\n },\n inputs: input.descriptor.inputs.map(({ id, label, schema }) => ({ id, label, schema })),\n ...(feedback === undefined ? {} : { feedback }),\n signal: input.signal,\n });\n try {\n await input.transport.submitStep(input.requestId, input.verifier, next.id, proof, input.signal);\n break;\n } catch (cause) {\n if (!(cause instanceof CredentialError) || cause.code !== \"PROOF_REJECTED\") throw cause;\n const attemptsRemaining = input.descriptor.lifecycle.maxProofAttempts - attempt;\n // Once this view stops re-prompting, the rejection is final: a\n // host must not silently start a new acquisition on its behalf.\n if (next.type !== \"mailbox_otp\" || attemptsRemaining <= 0) throw new CredentialError(\"VERIFICATION_FAILED\", \"The proof was not accepted\", { state: attemptsRemaining <= 0 ? \"proof_attempts_exhausted\" : \"proof_rejected\", cause });\n feedback = { kind: \"rejected\", attemptsRemaining };\n }\n }\n }\n }\n completed.add(next.id);\n }\n}\n","import {\n CredentialError, canonicalDigest, credentialEndpointPath, decodeBase64Url, encodeBase64Url,\n holderBindingCanonicalBytes, sha256Base64Url, validateCredentialHolderBinding,\n type CredentialFlowDescriptor, type CredentialHolderBinding, type CredentialIssuerMetadata,\n type CredentialRequirement, type IssuedCredentialEnvelope,\n} from \"@tinycloud/sdk-core\";\nimport type { CredentialAcquisitionTransport, CredentialRequestState, HolderSignatureKey, PrimitiveStepResult } from \"./types\";\n\nfunction object(value: unknown, label: string): Record<string, unknown> { if (typeof value !== \"object\" || value === null || Array.isArray(value)) throw new CredentialError(\"VERIFICATION_FAILED\", `${label} is invalid`); return value as Record<string, unknown>; }\nfunction opaque(value: unknown, label: string): string { if (typeof value !== \"string\" || !/^[A-Za-z0-9_-]{16,128}$/.test(value)) throw new CredentialError(\"REQUEST_SUBSTITUTED\", `${label} is invalid`); return value; }\nfunction timestamp(value: unknown, label: string): string { if (typeof value !== \"string\" || !Number.isFinite(Date.parse(value))) throw new CredentialError(\"VERIFICATION_FAILED\", `${label} is invalid`); return new Date(value).toISOString(); }\nfunction jwtPayload(credential: string): Record<string, unknown> { const part = credential.split(\"~\", 1)[0]?.split(\".\")[1]; if (!part) throw new CredentialError(\"VERIFICATION_FAILED\", \"Issued SD-JWT is invalid\"); try { return object(JSON.parse(new TextDecoder().decode(decodeBase64Url(part))), \"SD-JWT payload\"); } catch (cause) { if (cause instanceof CredentialError) throw cause; throw new CredentialError(\"VERIFICATION_FAILED\", \"Issued SD-JWT is invalid\", { cause }); } }\nconst SERVER_CODES = new Set([\"REQUEST_EXPIRED\", \"ISSUER_UNREADY\", \"UNSUPPORTED_PROFILE\", \"UNSUPPORTED_VERSION\", \"SIGNATURE_REJECTED\"] as const);\nfunction serverError(value: unknown, response: Response, honorServerRecoverable: boolean): CredentialError | undefined {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return undefined;\n const body = value as Record<string, unknown>;\n const keys = Object.keys(body).sort();\n if (keys.join(\",\") !== \"code,correlationId,recoverable,state,type\" || body.type !== \"tinycloud.credentials/error/v1\" || typeof body.code !== \"string\" || typeof body.recoverable !== \"boolean\" || typeof body.state !== \"string\" || typeof body.correlationId !== \"string\") return undefined;\n // A rejected proof is retryable only while the issuer still has attempts\n // left for this challenge; once exhausted the acquisition cannot finish.\n if (body.code === \"PROOF_REJECTED\") return body.recoverable\n ? new CredentialError(\"PROOF_REJECTED\", \"The proof was not accepted\", { state: body.state, correlationId: body.correlationId })\n : new CredentialError(\"VERIFICATION_FAILED\", \"The proof attempt limit was reached\", { state: \"proof_attempts_exhausted\", correlationId: body.correlationId });\n if (body.code === \"RATE_LIMITED\") return new CredentialError(\"ISSUER_UNREADY\", \"Too many verification codes were requested\", { state: \"rate_limited\", correlationId: body.correlationId, retryAfterMs: Number(response.headers.get(\"retry-after\")) * 1000 || undefined, recoverable: honorServerRecoverable ? body.recoverable : undefined });\n if (body.code === \"CHALLENGE_EXPIRED\") return new CredentialError(\"REQUEST_EXPIRED\", \"The credential challenge expired\", { state: body.state, correlationId: body.correlationId, recoverable: honorServerRecoverable ? body.recoverable : undefined });\n if (!SERVER_CODES.has(body.code as any)) return undefined;\n const code = body.code as \"REQUEST_EXPIRED\" | \"ISSUER_UNREADY\" | \"UNSUPPORTED_PROFILE\" | \"UNSUPPORTED_VERSION\" | \"SIGNATURE_REJECTED\";\n return new CredentialError(code, `OpenCredentials rejected the request: ${code}`, {\n state: body.state,\n correlationId: body.correlationId,\n retryAfterMs: Number(response.headers.get(\"retry-after\")) * 1000 || undefined,\n recoverable: honorServerRecoverable ? body.recoverable : undefined,\n });\n}\n\nexport class OpenCredentialsHttpTransport implements CredentialAcquisitionTransport {\n private readonly nonces = new Map<string, string>();\n private readonly bindings = new Map<string, CredentialHolderBinding>();\n constructor(private readonly descriptor: CredentialFlowDescriptor, private readonly fetchFn: typeof fetch = globalThis.fetch.bind(globalThis), private readonly options: { readonly honorServerRecoverable?: boolean } = {}) {}\n private url(endpoint: Parameters<typeof credentialEndpointPath>[0], id?: string): string { return new URL(credentialEndpointPath(endpoint, id), this.descriptor.issuer.origin).href; }\n private async request(endpoint: Parameters<typeof credentialEndpointPath>[0], input: { readonly id?: string; readonly method?: \"GET\" | \"POST\"; readonly verifier?: string; readonly body?: unknown; readonly signal?: AbortSignal }): Promise<unknown> {\n let response: Response;\n try { const init: RequestInit & { readonly cache: \"no-store\" } = { method: input.method ?? \"GET\", credentials: \"omit\", cache: \"no-store\", redirect: \"error\", referrerPolicy: \"no-referrer\", signal: input.signal, headers: { accept: \"application/json\", ...(input.body === undefined ? {} : { \"content-type\": \"application/json\" }), ...(input.verifier === undefined ? {} : { authorization: `Bearer ${input.verifier}` }) }, ...(input.body === undefined ? {} : { body: JSON.stringify(input.body) }) }; response = await this.fetchFn(this.url(endpoint, input.id), init); }\n catch (cause) { if (cause instanceof DOMException && cause.name === \"AbortError\") throw new CredentialError(\"CANCELED\", \"Credential acquisition was canceled\", { cause }); throw new CredentialError(\"OFFLINE\", \"OpenCredentials is unavailable\", { cause }); }\n if (!response.ok) {\n let parsed: unknown;\n try { parsed = await response.json(); } catch { parsed = undefined; }\n const typed = serverError(parsed, response, this.options.honorServerRecoverable === true);\n if (typed) throw typed;\n if (response.status === 410) throw new CredentialError(\"REQUEST_EXPIRED\", \"Credential request expired\");\n if (response.status === 409) throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Credential request was replayed or substituted\");\n if (response.status === 503) throw new CredentialError(\"ISSUER_UNREADY\", \"Credential issuer is not ready\", { retryAfterMs: Number(response.headers.get(\"retry-after\")) * 1000 || undefined });\n throw new CredentialError(\"VERIFICATION_FAILED\", \"OpenCredentials rejected the request\");\n }\n if (response.status === 204) return undefined; try { return await response.json(); } catch (cause) { throw new CredentialError(\"VERIFICATION_FAILED\", \"OpenCredentials response is invalid\", { cause }); }\n }\n async create(input: { descriptor: CredentialFlowDescriptor; descriptorDigest: string; requirement: CredentialRequirement; requirementDigest: string; holderDid: string; openerOrigin: string; completionVerifierChallenge: string; inputs?: Readonly<Record<string, string>>; signal?: AbortSignal }) {\n const body = object(await this.request(\"request\", { method: \"POST\", body: { protocol: input.descriptor.protocol, profile: input.descriptor.profile, profileVersion: input.descriptor.profileVersion, descriptorDigest: input.descriptorDigest, requirementDigest: input.requirementDigest, holderDid: input.holderDid, inputs: input.inputs ?? input.requirement.claims, audience: \"tinycloud://credentials\", openerOrigin: input.openerOrigin, completionOrigin: input.openerOrigin, completionContext: \"sdk-acquisition\", completionVerifierChallenge: input.completionVerifierChallenge }, signal: input.signal }), \"create response\");\n if (body.type !== \"tinycloud.credentials/acquisition-request/v1\" || body.protocol !== input.descriptor.protocol || body.next !== \"challenge\" || body.endpoint !== \"challenge\") throw new CredentialError(\"VERIFICATION_FAILED\", \"create response is invalid\");\n const requestId = opaque(body.requestId, \"requestId\"); return { requestId, locator: requestId, expiresAt: timestamp(body.expiresAt, \"expiresAt\"), correlationId: requestId };\n }\n private proofStep(): \"mailbox_otp\" | \"collect_input\" { return this.descriptor.steps.some((step) => step.type === \"mailbox_otp\") ? \"mailbox_otp\" : \"collect_input\"; }\n async state(id: string, verifier: string, signal?: AbortSignal): Promise<CredentialRequestState> {\n const raw = object(await this.request(\"state\", { id, verifier, signal }), \"state response\");\n if (raw.type !== \"tinycloud.credentials/acquisition-state/v1\" || raw.requestId !== id || raw.profile !== this.descriptor.profile || raw.profileVersion !== 1) throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Credential state response is substituted\");\n const base = { type: \"OpenCredentialsAcquisitionState\" as const, version: 1 as const, requestId: id, transitionId: `${String(raw.state)}:${String(raw.resultPreviouslyRead ?? false)}`, correlationId: id };\n if (raw.state === \"challenge_required\") { const type = this.proofStep(); return { ...base, state: \"pending\", nextStep: { id: type, type, version: 1, constraints: { challengeRequired: true } } }; }\n if (raw.state === \"proof_required\") { const type = this.proofStep(); this.nonces.set(id, opaque(raw.challengeNonce, \"challengeNonce\")); return { ...base, state: \"pending\", nextStep: { id: type, type, version: 1, constraints: {} } }; }\n if (raw.state === \"holder_binding_required\" || raw.state === \"holder_signature_required\") return { ...base, state: \"pending\", nextStep: { id: \"holder_signature\", type: \"holder_signature\", version: 1, constraints: {} } };\n if (raw.state === \"ready_to_issue\") return { ...base, state: \"ready_to_issue\" };\n if (raw.state === \"issued\") return { ...base, state: \"complete\" };\n throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Credential state is unsupported\");\n }\n async beginStep(id: string, verifier: string, stepId: \"collect_input\" | \"mailbox_otp\", signal?: AbortSignal): Promise<void> { const step = this.proofStep(); if (stepId !== step) throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Credential challenge step is substituted\"); const challenge = object(await this.request(\"challenge\", { id, verifier, method: \"POST\", body: { step, stepVersion: 1 }, signal }), \"challenge response\"); if (challenge.type !== \"tinycloud.credentials/challenge/v1\" || challenge.step !== step || challenge.stepVersion !== 1) throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Credential challenge is substituted\"); this.nonces.set(id, opaque(challenge.challengeNonce, \"challengeNonce\")); }\n async submitStep(id: string, verifier: string, stepId: string, proof: PrimitiveStepResult, signal?: AbortSignal): Promise<void> { const step = this.proofStep(); if (stepId !== step) throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Credential proof step is substituted\"); const nonce = this.nonces.get(id); if (!nonce) throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Credential challenge is missing\"); await this.request(\"proof\", { id, verifier, method: \"POST\", body: { step, stepVersion: 1, challengeNonce: nonce, proof }, signal }); }\n async holderBinding(id: string, verifier: string, signal?: AbortSignal): Promise<CredentialHolderBinding> { const raw = object(await this.request(\"holder_binding\", { id, verifier, signal }), \"holder binding response\"); if (raw.type !== \"tinycloud.credentials/holder-binding-request/v1\" || raw.signingDomain !== \"tinycloud.credentials/holder-binding/v1\" || raw.alg !== \"EdDSA\" || typeof raw.canonical !== \"string\") throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Holder binding response is invalid\"); const binding = validateCredentialHolderBinding(raw.binding); if (encodeBase64Url(holderBindingCanonicalBytes(binding)) !== raw.canonical) throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Holder binding canonical bytes were substituted\"); this.bindings.set(id, binding); return binding; }\n async submitHolderSignature(id: string, verifier: string, signature: string, signal?: AbortSignal, key?: HolderSignatureKey): Promise<void> { const binding = this.bindings.get(id); if (!binding) throw new CredentialError(\"REQUEST_SUBSTITUTED\", \"Holder binding was not retrieved\"); const kid = key?.kid ?? `${binding.holderDid}#${binding.holderDid.replace(\"did:key:\", \"\")}`; await this.request(\"holder_signature\", { id, verifier, method: \"POST\", body: { alg: key?.alg ?? \"EdDSA\", kid, signature }, signal }); }\n async issue(id: string, verifier: string, signal?: AbortSignal): Promise<void> { await this.request(\"issue\", { id, verifier, method: \"POST\", signal }); }\n async result(id: string, verifier: string, signal?: AbortSignal): Promise<IssuedCredentialEnvelope> {\n const raw = object(await this.request(\"result\", { id, verifier, signal }), \"result response\"); if (raw.type !== \"tinycloud.credentials/result/v1\" || raw.protocol !== this.descriptor.protocol || raw.profile !== this.descriptor.profile || raw.profileVersion !== 1 || raw.format !== \"vc+sd-jwt\" || raw.descriptorDigest !== await canonicalDigest(this.descriptor) || raw.issuer !== this.descriptor.issuer.did || raw.issuerKid !== this.descriptor.issuer.kid || typeof raw.credential !== \"string\" || await sha256Base64Url(raw.credential) !== raw.credentialDigest) throw new CredentialError(\"VERIFICATION_FAILED\", \"Issued result metadata is invalid\");\n const holder = object(raw.holderBinding, \"result holder binding\"); if (raw.subject !== holder.did || holder.signingDomain !== \"tinycloud.credentials/holder-binding/v1\") throw new CredentialError(\"HOLDER_MISMATCH\", \"Issued holder binding is invalid\");\n const claimsRaw = object(raw.claims, \"result claims\"); const claims: Record<string, string> = {}; for (const [name, value] of Object.entries(claimsRaw)) { if (typeof value !== \"string\") throw new CredentialError(\"VERIFICATION_FAILED\", \"Issued claims are invalid\"); claims[name] = value; }\n const validity = object(raw.validity, \"result validity\"); const payload = jwtPayload(raw.credential); if (typeof payload.jti !== \"string\") throw new CredentialError(\"VERIFICATION_FAILED\", \"Credential id is invalid\"); const issuedAt = timestamp(validity.issuedAt, \"issuedAt\"); const expiresAt = timestamp(validity.expiresAt, \"expiresAt\");\n const status = object(raw.status, \"result status\"); if (status.type !== \"none\" || status.freshnessSeconds !== this.descriptor.status.freshnessSeconds) throw new CredentialError(\"VERIFICATION_FAILED\", \"Credential status is invalid\");\n return { type: \"OpenCredentialsIssuedCredential\", version: 1, protocol: this.descriptor.protocol, profile: { id: this.descriptor.profile, version: 1 }, credentialType: { id: this.descriptor.format.vct, version: 1 }, schema: this.descriptor.format.vct, format: \"vc+sd-jwt\", issuerDid: raw.issuer as string, issuerKid: raw.issuerKid as string, subjectDid: raw.subject as string, holderDid: raw.subject as string, claims, claimsDigest: await canonicalDigest(claims), descriptorDigest: raw.descriptorDigest as string, credentialId: payload.jti, issuedAt, notBefore: issuedAt, expiresAt, status: { method: \"none\", freshnessSeconds: status.freshnessSeconds as number }, credential: raw.credential };\n }\n async issuerMetadata(signal?: AbortSignal): Promise<CredentialIssuerMetadata> { return await this.request(\"issuer_metadata\", { signal }) as CredentialIssuerMetadata; }\n async checkStatus(status: IssuedCredentialEnvelope[\"status\"], _signal?: AbortSignal): Promise<boolean> { return status.method === \"none\" && status.freshnessSeconds === this.descriptor.status.freshnessSeconds; }\n}\n","import {\n canonicalDigest,\n createEmailCredentialRequirement,\n credentialError,\n credentialRequirementDigest,\n CredentialError,\n descriptorSatisfiesRequirement,\n encodeBase64Url,\n sha256Base64Url,\n validateCredentialFlowDescriptor,\n verifyIssuedCredential,\n type CredentialFlowDescriptor,\n type CredentialIssuerMetadata,\n type CredentialRequirement,\n type IssuedCredentialEnvelope,\n type IssuerVerificationKey,\n type VerifiedCredential,\n} from \"@tinycloud/sdk-core\";\nimport { interpretCredentialFlow } from \"./interpreter\";\nimport { OpenCredentialsHttpTransport } from \"./transport\";\nimport type { CredentialSigningAdapter, PrimitiveStepHandler } from \"./types\";\n\n/** Production pins. Credentials verify only against these values. Tests pin them literally. */\nexport const EMAIL_PROOF_PINS = Object.freeze({\n witnessOrigin: \"https://witness.credentials.org\",\n issuerDid: \"did:web:issuer.credentials.org\",\n issuerKid: \"did:web:issuer.credentials.org#controller\",\n issuerX: \"eEJI4xEobto4HtQ7Pg9R1vBOwcpfGRTlXDG5QfqLnGQ\",\n descriptorDigest: \"1tg-qphmKBVtNwzVg9xyz-xxqt_xtMXAsQyXw46m8S0\",\n} as const);\n\nexport const EMAIL_PROOF_CREDENTIAL_TYPE = { id: \"opencredentials.email/v1\", version: 1 } as const;\n/** A pending request is never trusted beyond this window, measured from creation. */\nexport const EMAIL_PROOF_PENDING_MAX_MS = 15 * 60_000;\n\nconst DISCOVERY_URL = `${EMAIL_PROOF_PINS.witnessOrigin}/.well-known/opencredentials`;\nexport const EMAIL_PROOF_ISSUER_KEYS: readonly IssuerVerificationKey[] = [\n {\n kid: EMAIL_PROOF_PINS.issuerKid,\n alg: \"EdDSA\",\n jwk: { kty: \"OKP\", crv: \"Ed25519\", x: EMAIL_PROOF_PINS.issuerX },\n validFrom: \"2020-01-01T00:00:00Z\",\n validUntil: \"2100-01-01T00:00:00Z\",\n },\n];\n\nexport type EmailProofProfileId = \"tinycloud.email-proof/v1\";\nexport const DEFAULT_EMAIL_PROOF_PROFILE: EmailProofProfileId = \"tinycloud.email-proof/v1\";\n/** Each profile is pinned to its descriptor digest and to the mailbox step the witness must offer. */\nconst PROFILE_PINS: Readonly<Record<EmailProofProfileId, { readonly descriptorDigest: string; readonly requiredStep: \"mailbox_otp\"; readonly enabled: boolean }>> = {\n \"tinycloud.email-proof/v1\": { descriptorDigest: EMAIL_PROOF_PINS.descriptorDigest, requiredStep: \"mailbox_otp\", enabled: true },\n};\n\nconst OPENER_ORIGIN = \"https://localhost\";\nconst STEP_TIMEOUT_MS = 60_000;\nconst HOLDER_DID_PREFIX = \"did:key:\";\nconst HOLDER_DID_PATTERN = /^did:key:z6Mk[^#]+$/;\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\nconst INSPECT = Symbol.for(\"nodejs.util.inspect.custom\");\n\n/** Which part of the two-step flow failed. */\nexport type EmailProofStep = \"request\" | \"code\" | \"credential\" | \"session\";\n\n/**\n * Stable error codes. `recoverable` = the same pending request may be retried\n * (with another code, or after the network returns) before it expires.\n *\n * | code | recoverable | reason |\n * |-------------------------|-------------|--------|\n * | ADDRESS_INVALID | false | input is malformed; the same address cannot succeed |\n * | HOLDER_INVALID | false | holder key is not an Ed25519 did:key with a matching kid |\n * | CODE_INVALID | true | local format check (8 digits); no network; pending kept |\n * | RATE_LIMITED | witness | witness `recoverable` flag decides (defaults to true); retryAfterMs set |\n * | ISSUER_UNAVAILABLE | true | transient issuer outage (503); witness flag is honoured |\n * | NETWORK | true | transport failure or step timeout; pending kept |\n * | PROFILE_UNAVAILABLE | false | catalog or descriptor does not match the pinned profile |\n * | CODE_REJECTED | true | wrong code; witness flag decides whether another attempt is allowed |\n * | CODE_ATTEMPTS_EXHAUSTED | false | witness proof-attempt budget spent; pending is dead |\n * | SIGNATURE_REJECTED | true | holder binding rejected; same pending may be retried |\n * | CREDENTIAL_INVALID | false | issued credential failed local verification |\n * | SESSION_EXPIRED | false | pending window or server expiry has passed |\n * | SESSION_INVALID | false | pending does not match holder, descriptor, or requirement |\n * | CANCELED | false | caller aborted; pending is deleted |\n * | FAILED | false | unclassified failure; pending is deleted |\n */\nexport type EmailProofErrorCode =\n | \"ADDRESS_INVALID\"\n | \"HOLDER_INVALID\"\n | \"CODE_INVALID\"\n | \"RATE_LIMITED\"\n | \"ISSUER_UNAVAILABLE\"\n | \"NETWORK\"\n | \"PROFILE_UNAVAILABLE\"\n | \"CODE_REJECTED\"\n | \"CODE_ATTEMPTS_EXHAUSTED\"\n | \"SIGNATURE_REJECTED\"\n | \"CREDENTIAL_INVALID\"\n | \"SESSION_EXPIRED\"\n | \"SESSION_INVALID\"\n | \"CANCELED\"\n | \"FAILED\";\n\nconst RECOVERABILITY: Readonly<Record<EmailProofErrorCode, boolean>> = {\n ADDRESS_INVALID: false,\n HOLDER_INVALID: false,\n CODE_INVALID: true,\n RATE_LIMITED: true,\n ISSUER_UNAVAILABLE: true,\n NETWORK: true,\n PROFILE_UNAVAILABLE: false,\n CODE_REJECTED: true,\n CODE_ATTEMPTS_EXHAUSTED: false,\n SIGNATURE_REJECTED: true,\n CREDENTIAL_INVALID: false,\n SESSION_EXPIRED: false,\n SESSION_INVALID: false,\n CANCELED: false,\n FAILED: false,\n};\n\nconst MESSAGES: Record<Exclude<EmailProofErrorCode, \"RATE_LIMITED\">, string> = {\n ADDRESS_INVALID: \"Email address is invalid.\",\n HOLDER_INVALID: \"Holder must be a did:key Ed25519 identifier.\",\n CODE_INVALID: \"Verification code must be 8 digits.\",\n ISSUER_UNAVAILABLE: \"Email verification is unavailable right now.\",\n NETWORK: \"Could not reach the email verification service.\",\n PROFILE_UNAVAILABLE: \"The witness does not offer the email verification profile.\",\n CODE_REJECTED: \"Verification code was not accepted.\",\n CODE_ATTEMPTS_EXHAUSTED: \"Too many wrong codes. Request a new code.\",\n SIGNATURE_REJECTED: \"Holder signature was rejected.\",\n CREDENTIAL_INVALID: \"Issued credential failed verification.\",\n SESSION_EXPIRED: \"Email verification request expired. Request a new code.\",\n SESSION_INVALID: \"Email verification request is no longer valid. Request a new code.\",\n CANCELED: \"Email verification was canceled.\",\n FAILED: \"Email verification failed.\",\n};\n\nfunction rateLimitMessage(retryAfterMs: number | undefined): string {\n const head = \"Too many codes were requested for this address.\";\n if (retryAfterMs === undefined || !Number.isFinite(retryAfterMs) || retryAfterMs <= 0) return `${head} Try again in about an hour.`;\n const minutes = Math.max(1, Math.ceil(retryAfterMs / 60_000));\n return `${head} Try again in ${minutes} ${minutes === 1 ? \"minute\" : \"minutes\"}.`;\n}\n\n/** Stable, redaction-safe error. The message never includes the code, verifier, or key material. */\nexport class EmailProofError extends Error {\n readonly name = \"EmailProofError\";\n readonly step: EmailProofStep;\n readonly code: EmailProofErrorCode;\n readonly retryAfterMs: number | undefined;\n readonly recoverable: boolean;\n\n constructor(step: EmailProofStep, code: EmailProofErrorCode, retryAfterMs?: number, recoverable: boolean = RECOVERABILITY[code]) {\n super(code === \"RATE_LIMITED\" ? rateLimitMessage(retryAfterMs) : MESSAGES[code]);\n this.step = step;\n this.code = code;\n this.retryAfterMs = retryAfterMs;\n this.recoverable = recoverable;\n }\n}\n\nexport type HolderAlgorithm = \"EdDSA\" | \"EIP191\";\n\n/**\n * Holder key adapter. `sign` MUST return a raw signature over exactly the bytes it\n * is given: the signer does no hashing, prefixing, or domain separation. `kid` names\n * the key the witness verifies against. `completeEmailProof` rejects with\n * SESSION_INVALID unless `did === pending.holderDid`.\n */\nexport interface HolderSigner {\n readonly did: string;\n readonly alg: HolderAlgorithm;\n readonly kid: string;\n readonly sign: (bytes: Uint8Array) => Promise<Uint8Array>;\n}\n\n/**\n * Ed25519 did:key holder. Accepts `did:key:z6Mk…` or `did:key:z6Mk…#<same multibase>`\n * (the session-manager form) and normalises to the bare DID. `kid` is derived from the bare DID.\n */\nexport function createEd25519HolderSigner(did: string, sign: (bytes: Uint8Array) => Promise<Uint8Array>): HolderSigner {\n const fragment = did.indexOf(\"#\");\n const bare = fragment === -1 ? did : did.slice(0, fragment);\n if (fragment !== -1 && did.slice(fragment + 1) !== bare.slice(HOLDER_DID_PREFIX.length)) throw new EmailProofError(\"request\", \"HOLDER_INVALID\");\n if (!HOLDER_DID_PATTERN.test(bare)) throw new EmailProofError(\"request\", \"HOLDER_INVALID\");\n return { did: bare, alg: \"EdDSA\", kid: holderKid(bare), sign };\n}\n\n/** Options shared by the public steps. Issuer keys are never caller-supplied. */\nexport interface EmailProofOptions {\n readonly fetch?: typeof fetch;\n readonly signal?: AbortSignal;\n readonly now?: () => Date;\n}\n\nexport interface EmailProofRequestInput extends EmailProofOptions {\n readonly address: string;\n readonly holder: HolderSigner;\n readonly profile?: EmailProofProfileId;\n}\n\n/**\n * Durable state between `requestEmailProofCode` and `completeEmailProof`.\n * `verifier` is a bearer secret. It is a non-enumerable property, so spread\n * omits it; `toJSON` and `util.inspect` redact it. Persist it only with owner-only storage.\n */\nexport interface EmailProofPending {\n readonly type: \"TinyCloudEmailProofPending\";\n readonly version: 1;\n readonly profile: EmailProofProfileId;\n readonly address: string;\n readonly requestId: string;\n readonly verifier: string;\n readonly holderDid: string;\n readonly descriptorDigest: string;\n readonly requirementDigest: string;\n readonly openerOrigin: string;\n readonly createdAt: string;\n readonly expiresAt: string;\n}\n\n/** Holds pending requests keyed by requestId. Implementations must never return an expired request from `findLive`. */\nexport interface EmailProofPendingStore {\n /** Newest unexpired request for `address`, or undefined. */\n findLive(address: string, now: Date): Promise<EmailProofPending | undefined>;\n put(pending: EmailProofPending): Promise<void>;\n delete(requestId: string): Promise<void>;\n /** Pending request by id, or undefined if absent or past its deadline. */\n get(requestId: string, now: Date): Promise<EmailProofPending | undefined>;\n}\n\n/**\n * Rebuilds a pending request from stored fields. The result is redacted exactly like\n * one produced by `requestEmailProofCode`. Stores call this on every read.\n */\nexport function restoreEmailProofPending(fields: EmailProofPending): EmailProofPending {\n const shown = {\n type: fields.type,\n version: fields.version,\n profile: fields.profile,\n address: fields.address,\n requestId: fields.requestId,\n holderDid: fields.holderDid,\n descriptorDigest: fields.descriptorDigest,\n requirementDigest: fields.requirementDigest,\n openerOrigin: fields.openerOrigin,\n createdAt: fields.createdAt,\n expiresAt: fields.expiresAt,\n };\n const pending = { ...shown } as EmailProofPending;\n hide(pending, \"verifier\", fields.verifier);\n hide(pending, \"toJSON\", () => ({ ...shown }));\n hide(pending, INSPECT, () => ({ ...shown, verifier: \"[redacted]\" }));\n return Object.freeze(pending);\n}\n\nfunction hide(target: object, key: string | symbol, value: unknown): void {\n Object.defineProperty(target, key, { value, enumerable: false, writable: false, configurable: false });\n}\n\n/** Latest instant at which a pending request may still be completed. */\nexport function pendingDeadlineMs(pending: EmailProofPending): number {\n return Math.min(Date.parse(pending.expiresAt), Date.parse(pending.createdAt) + EMAIL_PROOF_PENDING_MAX_MS);\n}\n\n/** Process-local pending store for browsers and tests. Nothing survives a reload. */\nexport function createMemoryEmailProofPendingStore(): EmailProofPendingStore {\n const byRequest = new Map<string, EmailProofPending>();\n const prune = (now: Date) => {\n for (const [requestId, pending] of byRequest) if (pendingDeadlineMs(pending) <= now.getTime()) byRequest.delete(requestId);\n };\n return {\n async findLive(address, now) {\n prune(now);\n let newest: EmailProofPending | undefined;\n for (const pending of byRequest.values()) {\n if (pending.address === address && (!newest || Date.parse(pending.createdAt) > Date.parse(newest.createdAt))) newest = pending;\n }\n return newest;\n },\n async put(pending) { byRequest.set(pending.requestId, pending); },\n async delete(requestId) { byRequest.delete(requestId); },\n async get(requestId, now) { prune(now); return byRequest.get(requestId); },\n };\n}\n\nexport interface EmailProofResult {\n readonly envelope: IssuedCredentialEnvelope;\n readonly verified: VerifiedCredential;\n readonly credentialId: string;\n readonly issuedAt: string;\n readonly expiresAt: string;\n}\n\nexport interface EmailProofAcquireInput extends EmailProofRequestInput {\n /** Supplies the 8-digit code. Omit to only request one; the pending request is returned for a later call. */\n readonly getCode?: (context: { readonly pending: EmailProofPending }) => Promise<string>;\n /** Resumes an unexpired pending request for this address, and keeps one across recoverable failures. */\n readonly pendingStore?: EmailProofPendingStore;\n}\n\nexport type EmailProofAcquisition =\n | { readonly status: \"issued\"; readonly result: EmailProofResult; /** Non-fatal, e.g. the pending record could not be deleted after success. */ readonly warnings: readonly string[] }\n | { readonly status: \"code-requested\"; readonly pending: EmailProofPending };\n\n/** Thrown from the OTP handler to stop step 1 after the witness has sent the code. */\nclass CodeRequested extends Error {}\n\nconst pauseForCode: PrimitiveStepHandler = async () => {\n throw new CodeRequested(\"code requested\");\n};\n\n/**\n * Step 1: start an email-proof request. The witness sends an 8-digit code to\n * `address`. Returns the pending state to persist until the owner supplies the code.\n */\nexport async function requestEmailProofCode(input: EmailProofRequestInput): Promise<EmailProofPending> {\n const profile = input.profile ?? DEFAULT_EMAIL_PROOF_PROFILE;\n profilePin(profile, \"request\");\n const address = normalizeAddress(input.address);\n assertHolder(input.holder, \"request\");\n const now = input.now ?? (() => new Date());\n const signal = input.signal ?? AbortSignal.timeout(STEP_TIMEOUT_MS);\n const requirement = emailRequirement(address, profile);\n const requirementDigest = await credentialRequirementDigest(requirement);\n const descriptor = await witnessDescriptor(profile, requirement, { fetch: input.fetch, signal }, \"request\");\n const descriptorDigest = await canonicalDigest(descriptor);\n const verifier = randomVerifier();\n const transport = new OpenCredentialsHttpTransport(descriptor, input.fetch, { honorServerRecoverable: true });\n\n const createdAtMs = now().getTime();\n let created: Awaited<ReturnType<OpenCredentialsHttpTransport[\"create\"]>>;\n try {\n created = await transport.create({\n descriptor,\n descriptorDigest,\n requirement,\n requirementDigest,\n holderDid: input.holder.did,\n openerOrigin: OPENER_ORIGIN,\n completionVerifierChallenge: await sha256Base64Url(verifier),\n signal,\n });\n } catch (error) {\n throw mapError(error, \"request\", signal);\n }\n const serverExpiry = Date.parse(created.expiresAt);\n if (!Number.isFinite(serverExpiry)) throw new EmailProofError(\"request\", \"FAILED\");\n const pending = restoreEmailProofPending({\n type: \"TinyCloudEmailProofPending\",\n version: 1,\n profile,\n address,\n requestId: created.requestId,\n verifier,\n holderDid: input.holder.did,\n descriptorDigest,\n requirementDigest,\n openerOrigin: OPENER_ORIGIN,\n createdAt: new Date(createdAtMs).toISOString(),\n expiresAt: new Date(Math.min(serverExpiry, createdAtMs + EMAIL_PROOF_PENDING_MAX_MS)).toISOString(),\n });\n\n try {\n await interpretCredentialFlow({\n descriptor,\n requirement,\n requestId: created.requestId,\n verifier,\n holderDid: input.holder.did,\n descriptorDigest,\n requirementDigest,\n openerOrigin: OPENER_ORIGIN,\n transport,\n signing: holderSigning(input.holder),\n handlers: { mailbox_otp: pauseForCode },\n signal,\n });\n } catch (error) {\n if (error instanceof CodeRequested) return pending;\n throw mapError(error, \"request\", signal);\n }\n throw new EmailProofError(\"request\", \"FAILED\");\n}\n\n/**\n * Step 2: submit the owner's 8-digit code, sign the holder binding, issue, and\n * verify. The caller must delete `pending` after this call, success or failure.\n */\nexport async function completeEmailProof(input: EmailProofOptions & { readonly pending: EmailProofPending; readonly code: string; readonly holder: HolderSigner }): Promise<EmailProofResult> {\n return completeWithIssuerKeys(input, EMAIL_PROOF_ISSUER_KEYS);\n}\n\n/**\n * Internal test seam: completes with caller-supplied issuer keys. Not re-exported\n * from the package barrel. Production code uses `completeEmailProof`.\n */\nexport async function completeEmailProofWithIssuerKeys(\n input: EmailProofOptions & { readonly pending: EmailProofPending; readonly code: string; readonly holder: HolderSigner },\n issuerKeys: readonly IssuerVerificationKey[],\n): Promise<EmailProofResult> {\n return completeWithIssuerKeys(input, issuerKeys);\n}\n\nasync function completeWithIssuerKeys(\n input: EmailProofOptions & { readonly pending: EmailProofPending; readonly code: string; readonly holder: HolderSigner },\n issuerKeys: readonly IssuerVerificationKey[],\n): Promise<EmailProofResult> {\n const { pending } = input;\n const now = input.now ?? (() => new Date());\n if (!isPending(pending)) throw new EmailProofError(\"session\", \"SESSION_INVALID\");\n if (pendingDeadlineMs(pending) <= now().getTime()) throw new EmailProofError(\"session\", \"SESSION_EXPIRED\");\n if (!/^\\d{8}$/.test(input.code)) throw new EmailProofError(\"code\", \"CODE_INVALID\");\n assertHolder(input.holder, \"code\");\n if (input.holder.did !== pending.holderDid) throw new EmailProofError(\"session\", \"SESSION_INVALID\");\n const signal = input.signal ?? AbortSignal.timeout(STEP_TIMEOUT_MS);\n\n const requirement = emailRequirement(pending.address, pending.profile);\n if (await credentialRequirementDigest(requirement) !== pending.requirementDigest) throw new EmailProofError(\"session\", \"SESSION_INVALID\");\n const descriptor = await witnessDescriptor(pending.profile, requirement, { fetch: input.fetch, signal }, \"session\");\n const descriptorDigest = await canonicalDigest(descriptor);\n if (descriptorDigest !== pending.descriptorDigest) throw new EmailProofError(\"session\", \"SESSION_INVALID\");\n const transport = new OpenCredentialsHttpTransport(descriptor, input.fetch, { honorServerRecoverable: true });\n\n try {\n // The code email was sent in step 1. A challenge-required state here would make\n // the interpreter resend it, so refuse instead.\n const state = await transport.state(pending.requestId, pending.verifier, signal);\n if (state.nextStep?.constraints.challengeRequired === true) throw new EmailProofError(\"session\", \"SESSION_INVALID\");\n await interpretCredentialFlow({\n descriptor,\n requirement,\n requestId: pending.requestId,\n verifier: pending.verifier,\n holderDid: pending.holderDid,\n descriptorDigest,\n requirementDigest: pending.requirementDigest,\n openerOrigin: pending.openerOrigin,\n transport,\n signing: holderSigning(input.holder),\n handlers: { mailbox_otp: async () => ({ otp: input.code }) },\n signal,\n });\n } catch (error) {\n throw mapError(error, \"code\", signal);\n }\n\n try {\n const envelope = await transport.result(pending.requestId, pending.verifier, signal);\n const verified = await verifyIssuedCredential({\n envelope,\n descriptor,\n descriptorDigest,\n requirement,\n holderDid: pending.holderDid,\n issuerMetadata: pinnedIssuerMetadata(issuerKeys),\n now: now(),\n checkStatus: (status, statusSignal) => transport.checkStatus(status, statusSignal),\n signal,\n });\n return { envelope, verified, credentialId: verified.credentialId, issuedAt: verified.issuedAt, expiresAt: verified.expiresAt };\n } catch (error) {\n throw mapError(error, \"credential\", signal);\n }\n}\n\n/**\n * Request a code and, when `getCode` is given, complete the flow in one call.\n * With a `pendingStore`, an unexpired request for the address is resumed instead of\n * requesting a new code. A non-recoverable failure deletes the pending request.\n *\n * `store.put` throwing after the code was mailed: the code is in the owner's inbox but\n * not persisted, so the error propagates and the owner must request a new code.\n * `store.delete` failing after success: the credential is returned with a warning.\n * `store.delete` failing on a non-recoverable failure: the original error propagates.\n */\nexport async function acquireEmailProof(input: EmailProofAcquireInput): Promise<EmailProofAcquisition> {\n return acquireWithIssuerKeys(input, EMAIL_PROOF_ISSUER_KEYS);\n}\n\n/** Internal test seam, same as `completeEmailProofWithIssuerKeys`. Not re-exported from the barrel. */\nexport async function acquireEmailProofWithIssuerKeys(input: EmailProofAcquireInput, issuerKeys: readonly IssuerVerificationKey[]): Promise<EmailProofAcquisition> {\n return acquireWithIssuerKeys(input, issuerKeys);\n}\n\nasync function acquireWithIssuerKeys(input: EmailProofAcquireInput, issuerKeys: readonly IssuerVerificationKey[]): Promise<EmailProofAcquisition> {\n const address = normalizeAddress(input.address);\n const now = input.now ?? (() => new Date());\n const store = input.pendingStore;\n let pending = store ? await store.findLive(address, now()) : undefined;\n if (!pending) {\n pending = await requestEmailProofCode({ ...input, address });\n await store?.put(pending);\n }\n const shown = restoreEmailProofPending(pending);\n if (!input.getCode) return { status: \"code-requested\", pending: shown };\n\n const code = await input.getCode({ pending: shown });\n try {\n const result = await completeWithIssuerKeys({ ...input, pending, code }, issuerKeys);\n const warnings: string[] = [];\n if (store) {\n try { await store.delete(pending.requestId); } catch { warnings.push(\"The pending request could not be deleted after success; it expires at its deadline.\"); }\n }\n return { status: \"issued\", result, warnings };\n } catch (error) {\n if (!(error instanceof EmailProofError && error.recoverable)) await store?.delete(pending.requestId).catch(() => undefined);\n throw error;\n }\n}\n\nfunction normalizeAddress(address: string): string {\n const value = address.trim();\n if (value.length > 254 || !EMAIL_PATTERN.test(value)) throw new EmailProofError(\"request\", \"ADDRESS_INVALID\");\n return value;\n}\n\nfunction holderKid(did: string): string {\n return `${did}#${did.slice(HOLDER_DID_PREFIX.length)}`;\n}\n\nfunction assertHolder(holder: HolderSigner, step: EmailProofStep): void {\n if (!HOLDER_DID_PATTERN.test(holder.did) || holder.alg !== \"EdDSA\" || holder.kid !== holderKid(holder.did)) throw new EmailProofError(step, \"HOLDER_INVALID\");\n}\n\nfunction profilePin(profile: string, step: EmailProofStep): (typeof PROFILE_PINS)[EmailProofProfileId] {\n const entry = Object.prototype.hasOwnProperty.call(PROFILE_PINS, profile) ? PROFILE_PINS[profile as EmailProofProfileId] : undefined;\n if (!entry || !entry.enabled) throw new EmailProofError(step, \"PROFILE_UNAVAILABLE\");\n return entry;\n}\n\nfunction emailRequirement(address: string, profile: EmailProofProfileId): CredentialRequirement {\n return createEmailCredentialRequirement({ email: address, profile: { id: profile, version: 1 }, credentialType: EMAIL_PROOF_CREDENTIAL_TYPE });\n}\n\n/** Requirement for an email credential issued to `address` under the default profile. Storage and `show` key on its digest. */\nexport function emailProofRequirement(address: string): CredentialRequirement {\n return emailRequirement(normalizeAddress(address), DEFAULT_EMAIL_PROOF_PROFILE);\n}\n\n/** Discovers the catalog and returns the descriptor only if it matches the pinned issuer, origin, step, and digest. */\nasync function witnessDescriptor(\n profile: EmailProofProfileId,\n requirement: CredentialRequirement,\n options: { readonly fetch?: typeof fetch; readonly signal: AbortSignal },\n step: EmailProofStep,\n): Promise<CredentialFlowDescriptor> {\n const pin = profilePin(profile, step);\n let descriptor: CredentialFlowDescriptor;\n try {\n descriptor = await discoverCatalogDescriptor(requirement, DISCOVERY_URL, { fetch: options.fetch, signal: options.signal });\n } catch (error) {\n throw discoveryFailure(error, options.signal, step);\n }\n if (descriptor.issuer.origin !== EMAIL_PROOF_PINS.witnessOrigin || descriptor.issuer.did !== EMAIL_PROOF_PINS.issuerDid || !descriptor.steps.some((candidate) => candidate.type === pin.requiredStep)) {\n throw new EmailProofError(step, \"PROFILE_UNAVAILABLE\");\n }\n if (await canonicalDigest(descriptor) !== pin.descriptorDigest) throw new EmailProofError(step, \"PROFILE_UNAVAILABLE\");\n return descriptor;\n}\n\n/**\n * Fetch an OpenCredentials catalog and return the first enabled, ready profile whose\n * descriptor satisfies the requirement and matches its catalog digest.\n */\nasync function discoverCatalogDescriptor(\n requirement: CredentialRequirement,\n discoveryUrl: string,\n options: { readonly fetch?: typeof fetch; readonly signal?: AbortSignal } = {},\n): Promise<CredentialFlowDescriptor> {\n let url: URL; try { url = new URL(discoveryUrl); } catch { throw new CredentialError(\"UNSUPPORTED_PROFILE\", \"Discovery URL is invalid\"); }\n if (url.protocol !== \"https:\" || ![\"/.well-known/opencredentials\", \"/v1/credential-types\"].includes(url.pathname) || url.search || url.hash) throw new CredentialError(\"UNSUPPORTED_PROFILE\", \"Discovery URL is not an allowed catalog endpoint\");\n const init: RequestInit & { readonly cache: \"no-store\" } = { credentials: \"omit\", cache: \"no-store\", redirect: \"error\", referrerPolicy: \"no-referrer\", signal: options.signal };\n let response: Response;\n try { response = await (options.fetch ?? globalThis.fetch.bind(globalThis))(url, init); } catch (cause) { throw new CredentialError(\"OFFLINE\", \"Credential discovery is unavailable\", { cause }); }\n if (!response.ok) throw new CredentialError(response.status === 503 ? \"ISSUER_UNREADY\" : \"OFFLINE\", \"Credential discovery is unavailable\");\n const catalog = await response.json() as Record<string, unknown>;\n if (catalog.type !== \"tinycloud.credentials/catalog/v1\" || catalog.protocol !== \"tinycloud.credentials/acquisition/v1\" || catalog.catalogVersion !== 1 || !Array.isArray(catalog.profiles)) throw new CredentialError(\"DESCRIPTOR_INVALID\", \"Credential catalog is invalid\");\n for (const entryValue of catalog.profiles) {\n if (typeof entryValue !== \"object\" || entryValue === null || Array.isArray(entryValue)) continue;\n const entry = entryValue as Record<string, unknown>;\n if (entry.supported !== true || entry.enabled !== true || (entry.readiness !== \"ready\" && entry.readiness !== \"degraded\")) continue;\n try {\n const candidate = validateCredentialFlowDescriptor(entry.descriptor);\n if (descriptorSatisfiesRequirement(candidate, requirement) && entry.descriptorDigest === await canonicalDigest(candidate)) return candidate;\n } catch { /* malformed catalog entry: skip */ }\n }\n throw new CredentialError(\"UNSUPPORTED_PROFILE\", \"No available credential profile satisfies the requirement\");\n}\n\n/** A discovery abort by the caller is CANCELED. A step timeout stays NETWORK (recoverable). */\nfunction discoveryFailure(error: unknown, signal: AbortSignal, step: EmailProofStep): EmailProofError {\n if (signal.aborted && (signal.reason as { name?: string } | undefined)?.name !== \"TimeoutError\") return new EmailProofError(step, \"CANCELED\");\n return mapError(error, step, signal);\n}\n\nfunction pinnedIssuerMetadata(keys: readonly IssuerVerificationKey[]): CredentialIssuerMetadata {\n return { type: \"OpenCredentialsIssuerMetadata\", version: 1, origin: EMAIL_PROOF_PINS.witnessOrigin, issuerDid: EMAIL_PROOF_PINS.issuerDid, keys, cache: { maxAgeSeconds: 3600, etag: \"pinned\" } };\n}\n\n/** Holder signing: the signer receives the raw binding bytes and returns a raw Ed25519 signature. The kid goes on the wire. */\nfunction holderSigning(holder: HolderSigner): CredentialSigningAdapter {\n return { autoSign: async (_binding, bytes) => holder.sign(bytes), holderKey: { alg: \"EdDSA\", kid: holder.kid } };\n}\n\nfunction randomVerifier(): string {\n return encodeBase64Url(crypto.getRandomValues(new Uint8Array(32)));\n}\n\nfunction isPending(value: unknown): value is EmailProofPending {\n if (typeof value !== \"object\" || value === null) return false;\n const pending = value as EmailProofPending;\n return pending.type === \"TinyCloudEmailProofPending\"\n && pending.version === 1\n && pending.openerOrigin === OPENER_ORIGIN\n && [pending.profile, pending.address, pending.requestId, pending.verifier, pending.holderDid, pending.descriptorDigest, pending.requirementDigest, pending.openerOrigin, pending.createdAt, pending.expiresAt].every((field) => typeof field === \"string\")\n && Number.isFinite(Date.parse(pending.createdAt))\n && Number.isFinite(Date.parse(pending.expiresAt));\n}\n\n/** Maps any failure to a stable code. Caller aborts map to CANCELED; transient network failures stay recoverable. */\nfunction mapError(value: unknown, step: EmailProofStep, signal?: AbortSignal): EmailProofError {\n if (value instanceof EmailProofError) return value;\n if (value instanceof DOMException && value.name === \"TimeoutError\") return new EmailProofError(step, \"NETWORK\");\n const error = credentialError(value);\n const details = error.details;\n switch (error.code) {\n case \"ISSUER_UNREADY\":\n return details.state === \"rate_limited\"\n ? new EmailProofError(step, \"RATE_LIMITED\", details.retryAfterMs, error.recoverable)\n : new EmailProofError(step, \"ISSUER_UNAVAILABLE\", undefined, error.recoverable);\n case \"OFFLINE\":\n if (signal?.aborted && (signal.reason as { name?: string } | undefined)?.name !== \"TimeoutError\") return new EmailProofError(step, \"CANCELED\");\n return new EmailProofError(step, \"NETWORK\");\n case \"UNSUPPORTED_PROFILE\":\n case \"DESCRIPTOR_INVALID\":\n return new EmailProofError(step, \"PROFILE_UNAVAILABLE\");\n case \"PROOF_REJECTED\":\n // The transport emits PROOF_REJECTED only for a server recoverable:true response.\n return new EmailProofError(\"code\", \"CODE_REJECTED\", undefined, true);\n case \"VERIFICATION_FAILED\":\n if (details.state === \"proof_attempts_exhausted\") return new EmailProofError(\"code\", \"CODE_ATTEMPTS_EXHAUSTED\");\n if (step === \"credential\") return new EmailProofError(\"credential\", \"CREDENTIAL_INVALID\");\n // Unclassified rejection at the code step: not recoverable, so the pending is deleted.\n if (step === \"code\") return new EmailProofError(\"code\", \"CODE_REJECTED\", undefined, false);\n return new EmailProofError(step, \"FAILED\");\n case \"HOLDER_MISMATCH\":\n return new EmailProofError(\"credential\", \"CREDENTIAL_INVALID\");\n case \"REQUEST_EXPIRED\":\n return new EmailProofError(\"session\", \"SESSION_EXPIRED\");\n case \"REQUEST_SUBSTITUTED\":\n return new EmailProofError(\"session\", \"SESSION_INVALID\");\n case \"SIGNATURE_REJECTED\":\n return new EmailProofError(\"credential\", \"SIGNATURE_REJECTED\", undefined, error.recoverable);\n case \"CANCELED\":\n return new EmailProofError(step, \"CANCELED\");\n default:\n return new EmailProofError(step, \"FAILED\");\n }\n}\n"],"mappings":"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","names":["CredentialError","encodeBase64Url","validateCredentialHolderBinding","canonicalDigest","CredentialError","encodeBase64Url","sha256Base64Url","canonicalDigest","sha256Base64Url","canonicalDigest","canonicalDigest","CredentialError","encodeBase64Url"]}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { Delegation, DelegatedResource, PermissionEntry } from '@tinycloud/sdk-core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A portable delegation that can be transported between users.
|
|
5
|
+
* Extends the base Delegation type with fields required for transport.
|
|
6
|
+
*
|
|
7
|
+
* @remarks
|
|
8
|
+
* PortableDelegation adds transport fields to Delegation:
|
|
9
|
+
* - `delegationHeader`: Structured authorization header for API calls
|
|
10
|
+
* - `ownerAddress`: Space owner's address for session creation
|
|
11
|
+
* - `chainId`: Chain ID for session creation
|
|
12
|
+
* - `host`: Optional server URL
|
|
13
|
+
* - `resources`: Multi-resource grant breakdown (present when the
|
|
14
|
+
* delegation was issued via the multi-resource WASM path, i.e. one
|
|
15
|
+
* UCAN covering multiple `(service, path, actions)` entries). The
|
|
16
|
+
* flat `path` + `actions` fields mirror the first entry for
|
|
17
|
+
* single-resource callers; consumers that need the full picture
|
|
18
|
+
* read `resources`.
|
|
19
|
+
*/
|
|
20
|
+
interface PortableDelegation extends Omit<Delegation, "isRevoked"> {
|
|
21
|
+
/** The authorization header for this delegation (structured format) */
|
|
22
|
+
delegationHeader: {
|
|
23
|
+
Authorization: string;
|
|
24
|
+
};
|
|
25
|
+
/** The address of the space owner */
|
|
26
|
+
ownerAddress: string;
|
|
27
|
+
/** The chain ID */
|
|
28
|
+
chainId: number;
|
|
29
|
+
/** TinyCloud server URL where this delegation was created */
|
|
30
|
+
host?: string;
|
|
31
|
+
/** Whether the recipient is prevented from creating sub-delegations */
|
|
32
|
+
disableSubDelegation?: boolean;
|
|
33
|
+
/** Companion delegation for the user's public space (auto-created when includePublicSpace is true) */
|
|
34
|
+
publicDelegation?: PortableDelegation;
|
|
35
|
+
/**
|
|
36
|
+
* Full multi-resource grant breakdown. Present when the delegation
|
|
37
|
+
* was issued via the multi-resource WASM path; each entry describes
|
|
38
|
+
* one `(service, space, path, actions)` grant carried by the single
|
|
39
|
+
* underlying UCAN. When absent, only the flat `path` + `actions`
|
|
40
|
+
* fields are authoritative (legacy single-resource shape).
|
|
41
|
+
*/
|
|
42
|
+
resources?: DelegatedResource[];
|
|
43
|
+
/**
|
|
44
|
+
* The wallet-signed SIWE message and EIP-191 signature behind a
|
|
45
|
+
* `delegationHeader` that is a CACAO session grant (OpenKey `/delegate`,
|
|
46
|
+
* {@link TinyCloudNode.grantRuntimePermissions}) rather than a compact UCAN.
|
|
47
|
+
* Not authority: activation rebuilds the CACAO from them and accepts only
|
|
48
|
+
* byte-identical authorization bytes.
|
|
49
|
+
*/
|
|
50
|
+
siweProof?: {
|
|
51
|
+
siwe: string;
|
|
52
|
+
signature: string;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The transport shape `tc auth request --emit` produces and that an owner
|
|
57
|
+
* grants to its requester. Only the fields the grant logic needs are declared;
|
|
58
|
+
* the CLI artifact carries more (posture, captured command, ...) and remains a
|
|
59
|
+
* structural superset of this interface.
|
|
60
|
+
*/
|
|
61
|
+
interface AuthRequestArtifact {
|
|
62
|
+
kind: "tinycloud.auth.request";
|
|
63
|
+
version: 1;
|
|
64
|
+
requestId: string;
|
|
65
|
+
/** The requester's session DID — the audience the grant is issued to. */
|
|
66
|
+
sessionDid: string;
|
|
67
|
+
/** The capabilities the requester is asking the owner to delegate. */
|
|
68
|
+
requested: PermissionEntry[];
|
|
69
|
+
/** Optional lifetime override carried from the request. */
|
|
70
|
+
requestedExpiry?: string | number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The transport shape returned by {@link grantAuthRequest} (and written by
|
|
74
|
+
* `tc auth grant`). `tc auth import` accepts this artifact directly.
|
|
75
|
+
*/
|
|
76
|
+
interface AuthDelegationArtifact {
|
|
77
|
+
kind: "tinycloud.auth.delegation";
|
|
78
|
+
version: 1;
|
|
79
|
+
requestId: string;
|
|
80
|
+
delegationCid: string;
|
|
81
|
+
delegation: PortableDelegation;
|
|
82
|
+
permissions: PermissionEntry[];
|
|
83
|
+
expiry: string;
|
|
84
|
+
/** Whether issuing the delegation triggered a wallet prompt. */
|
|
85
|
+
prompted: boolean;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Minimal owner-side capability {@link grantAuthRequest} needs: the signed
|
|
89
|
+
* `delegateTo` primitive. `TinyCloudNode` satisfies this directly; web/SDK
|
|
90
|
+
* contexts can supply any object that exposes the same method.
|
|
91
|
+
*/
|
|
92
|
+
interface DelegationAuthority {
|
|
93
|
+
delegateTo(did: string, permissions: PermissionEntry[], options?: {
|
|
94
|
+
expiry?: string | number;
|
|
95
|
+
forceWalletSign?: boolean;
|
|
96
|
+
}): Promise<{
|
|
97
|
+
delegation: PortableDelegation;
|
|
98
|
+
prompted: boolean;
|
|
99
|
+
}>;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Authority that the validated runtime-delegation activation helper needs.
|
|
103
|
+
* `TinyCloudNode` implements this surface directly; keeping it structural
|
|
104
|
+
* makes the helper usable by a compatible Node wrapper without exposing node
|
|
105
|
+
* internals.
|
|
106
|
+
*/
|
|
107
|
+
interface RuntimeDelegationActivator {
|
|
108
|
+
readonly sessionDid: string;
|
|
109
|
+
readonly did?: string;
|
|
110
|
+
readonly isSessionOnly?: boolean;
|
|
111
|
+
computeDelegationCid(authorization: string): string;
|
|
112
|
+
useRuntimeDelegation(delegation: PortableDelegation): Promise<void>;
|
|
113
|
+
useDelegation?(delegation: PortableDelegation): Promise<unknown>;
|
|
114
|
+
getRuntimePermissionDelegations(): PortableDelegation[];
|
|
115
|
+
/**
|
|
116
|
+
* Verify a wallet-signed session grant issued to this runtime's live session
|
|
117
|
+
* key. Required to activate a CACAO grant; compact UCANs do not use it.
|
|
118
|
+
*/
|
|
119
|
+
verifySessionGrant?(grant: SessionGrantProof): VerifiedSessionGrant;
|
|
120
|
+
}
|
|
121
|
+
/** The installed authority returned by {@link activateValidatedRuntimeDelegation}. */
|
|
122
|
+
interface ValidatedRuntimeDelegation {
|
|
123
|
+
/** CID recomputed from the signed authorization bytes. */
|
|
124
|
+
readonly cid: string;
|
|
125
|
+
/** The authority object installed by the node runtime. */
|
|
126
|
+
readonly delegation: PortableDelegation;
|
|
127
|
+
/** Capabilities read from the signed compact UCAN attenuation or SIWE ReCap. */
|
|
128
|
+
readonly effectivePermissions: readonly PermissionEntry[];
|
|
129
|
+
/** Expiry read from the signed compact UCAN payload or SIWE. */
|
|
130
|
+
readonly expiry: Date;
|
|
131
|
+
/** Audience read from the signed compact UCAN payload or SIWE. */
|
|
132
|
+
readonly audience: string;
|
|
133
|
+
/** Host selected for, and used by, the runtime activation. */
|
|
134
|
+
readonly host: string;
|
|
135
|
+
}
|
|
136
|
+
interface CompactRuntimeDelegationInput {
|
|
137
|
+
readonly authorization: string;
|
|
138
|
+
readonly cid: string;
|
|
139
|
+
readonly host: string;
|
|
140
|
+
readonly ownerAddress: string;
|
|
141
|
+
readonly chainId: number;
|
|
142
|
+
}
|
|
143
|
+
/** A CACAO session grant and the signed SIWE proof it was built from. */
|
|
144
|
+
interface SessionGrantProof {
|
|
145
|
+
readonly delegationHeader: {
|
|
146
|
+
Authorization: string;
|
|
147
|
+
};
|
|
148
|
+
readonly delegationCid: string;
|
|
149
|
+
readonly spaceId: string;
|
|
150
|
+
readonly address: string;
|
|
151
|
+
readonly chainId: number;
|
|
152
|
+
readonly siwe: string;
|
|
153
|
+
readonly signature: string;
|
|
154
|
+
}
|
|
155
|
+
/** Authority read from a verified session grant's signed ReCap. */
|
|
156
|
+
interface VerifiedSessionGrant {
|
|
157
|
+
readonly recap: readonly {
|
|
158
|
+
service: string;
|
|
159
|
+
space: string;
|
|
160
|
+
path: string;
|
|
161
|
+
actions: string[];
|
|
162
|
+
caveats?: Record<string, unknown>[];
|
|
163
|
+
}[];
|
|
164
|
+
readonly expiresAt: Date;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Stable reasons {@link activateValidatedRuntimeDelegation} refuses a
|
|
168
|
+
* delegation for. The error message is for the caller and may quote
|
|
169
|
+
* transport fields or a node's response; the reason is safe to publish.
|
|
170
|
+
*/
|
|
171
|
+
declare const RUNTIME_DELEGATION_REJECTIONS: readonly ["host_mismatch", "expired", "cid_mismatch", "authority_invalid", "proof_missing", "proof_invalid", "owner_mismatch", "audience_mismatch", "resources_mismatch", "unsupported", "activation_rejected", "activation_unavailable", "activation_unauthenticated"];
|
|
172
|
+
type RuntimeDelegationRejection = typeof RUNTIME_DELEGATION_REJECTIONS[number];
|
|
173
|
+
declare class RuntimeDelegationRejectedError extends Error {
|
|
174
|
+
readonly reason: RuntimeDelegationRejection;
|
|
175
|
+
constructor(reason: RuntimeDelegationRejection, message: string);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The expiry a compact UCAN authorization signs: its payload's `exp`. Reads
|
|
179
|
+
* the bytes the issuer's signature covers without verifying that signature,
|
|
180
|
+
* which the node does. `undefined` when `authorization` is not a compact UCAN
|
|
181
|
+
* or its payload has no finite numeric `exp`; then no local expiry decision
|
|
182
|
+
* can be made (activation refuses such a UCAN).
|
|
183
|
+
*/
|
|
184
|
+
declare function signedCompactUcanExpiry(authorization: string): Date | undefined;
|
|
185
|
+
/**
|
|
186
|
+
* CID-bind and activate one runtime delegation.
|
|
187
|
+
*
|
|
188
|
+
* A compact UCAN's audience, expiry and permissions come from its signed
|
|
189
|
+
* payload, and its transport fields must agree with them. A CACAO session
|
|
190
|
+
* grant (OpenKey `/delegate`, `grantRuntimePermissions`) is verified from its
|
|
191
|
+
* `siweProof` against this runtime's live session key; its installed
|
|
192
|
+
* authority is exactly the verified ReCap, and its transport `resources` are
|
|
193
|
+
* display data that is never consulted. Either way the helper then invokes
|
|
194
|
+
* {@link TinyCloudNode.useRuntimeDelegation}; the node activation call remains
|
|
195
|
+
* the authority and delegation-chain validation boundary.
|
|
196
|
+
*
|
|
197
|
+
* `options.authorize`, when given, sees the signed capabilities before
|
|
198
|
+
* anything is activated or installed; returning `false` refuses the
|
|
199
|
+
* delegation.
|
|
200
|
+
*/
|
|
201
|
+
declare function activateValidatedRuntimeDelegation(node: RuntimeDelegationActivator, delegation: PortableDelegation, options: {
|
|
202
|
+
host: string;
|
|
203
|
+
authorize?: (effectivePermissions: readonly PermissionEntry[]) => boolean;
|
|
204
|
+
}): Promise<ValidatedRuntimeDelegation>;
|
|
205
|
+
/**
|
|
206
|
+
* Import compact UCAN bytes returned by an authority ceremony through the
|
|
207
|
+
* ordinary runtime-delegation activation path. All transport projections are
|
|
208
|
+
* derived from signed bytes before `/delegate` is called.
|
|
209
|
+
*/
|
|
210
|
+
declare function activateCompactRuntimeDelegation(node: RuntimeDelegationActivator, input: CompactRuntimeDelegationInput): Promise<ValidatedRuntimeDelegation>;
|
|
211
|
+
/**
|
|
212
|
+
* Project an OpenKey signed-login delegation from the same verified CACAO
|
|
213
|
+
* authority used when the runtime activates and replays it.
|
|
214
|
+
*/
|
|
215
|
+
declare function siweRuntimeDelegation(node: RuntimeDelegationActivator, input: {
|
|
216
|
+
readonly authorization: string;
|
|
217
|
+
readonly cid: string;
|
|
218
|
+
readonly spaceId: string;
|
|
219
|
+
readonly ownerAddress: string;
|
|
220
|
+
readonly chainId: number;
|
|
221
|
+
readonly siwe: string;
|
|
222
|
+
readonly signature: string;
|
|
223
|
+
readonly host: string;
|
|
224
|
+
}): PortableDelegation;
|
|
225
|
+
/**
|
|
226
|
+
* Turn a delegation REQUEST into a signed GRANT.
|
|
227
|
+
*
|
|
228
|
+
* Lifts the body of `tc auth grant` into the SDK so the request→grant
|
|
229
|
+
* handshake is callable programmatically (future SDK/web owner tooling and the
|
|
230
|
+
* KV delegation inbox), with the CLI verb reduced to a thin wrapper. The owner
|
|
231
|
+
* `authority` (a `TinyCloudNode`) signs a delegation scoped to exactly the
|
|
232
|
+
* requested caps, audienced to the requester's `sessionDid`, honoring the
|
|
233
|
+
* request's expiry. The returned artifact round-trips through `tc auth import`.
|
|
234
|
+
*
|
|
235
|
+
* Authorization is enforced cryptographically by `delegateTo`: caps that are
|
|
236
|
+
* not derivable from the owner's own session capability chain are rejected
|
|
237
|
+
* (it throws), so this never widens authority the owner doesn't hold.
|
|
238
|
+
*/
|
|
239
|
+
declare function grantAuthRequest(authority: DelegationAuthority, request: AuthRequestArtifact, options?: {
|
|
240
|
+
expiry?: string | number;
|
|
241
|
+
}): Promise<AuthDelegationArtifact>;
|
|
242
|
+
/**
|
|
243
|
+
* Serialize a PortableDelegation for transport (e.g., over network).
|
|
244
|
+
*/
|
|
245
|
+
declare function serializeDelegation(delegation: PortableDelegation): string;
|
|
246
|
+
/**
|
|
247
|
+
* Deserialize a PortableDelegation from transport.
|
|
248
|
+
*/
|
|
249
|
+
declare function deserializeDelegation(data: string): PortableDelegation;
|
|
250
|
+
|
|
251
|
+
export { type AuthDelegationArtifact as A, type CompactRuntimeDelegationInput as C, type DelegationAuthority as D, type PortableDelegation as P, RUNTIME_DELEGATION_REJECTIONS as R, type SessionGrantProof as S, type ValidatedRuntimeDelegation as V, activateCompactRuntimeDelegation as a, type AuthRequestArtifact as b, type RuntimeDelegationActivator as c, deserializeDelegation as d, RuntimeDelegationRejectedError as e, type RuntimeDelegationRejection as f, type VerifiedSessionGrant as g, activateValidatedRuntimeDelegation as h, grantAuthRequest as i, signedCompactUcanExpiry as j, siweRuntimeDelegation as k, serializeDelegation as s };
|