@tinycloud/web-sdk 3.9.1 → 3.10.0-beta.0
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.
|
@@ -122,15 +122,33 @@ export type ListHeldEmailCredentialsInput = Omit<FindHeldCredentialInput, "email
|
|
|
122
122
|
* `record` is the raw stored value; only the `verified` fields and the summary above are authoritative.
|
|
123
123
|
*/
|
|
124
124
|
export declare function listHeldEmailCredentials(input: ListHeldEmailCredentialsInput): Promise<readonly HeldMatch[]>;
|
|
125
|
+
export interface DeleteHeldCredentialInput {
|
|
126
|
+
readonly kv: IKVService;
|
|
127
|
+
readonly ownerDid: unknown;
|
|
128
|
+
/** The record's id (a 43-character base64url digest), as listed by `listHeldEmailCredentials`. */
|
|
129
|
+
readonly recordId: string;
|
|
130
|
+
}
|
|
125
131
|
/**
|
|
126
132
|
* Deletes the named record key only. The recordId is validated first, so a caller-supplied value cannot
|
|
127
|
-
* address another key. Copies outside this store remain valid until their own expiry.
|
|
133
|
+
* address another key. Copies outside this store remain valid until their own expiry. Needs `kv del` on `v1/held/`.
|
|
134
|
+
* Returns true when the record is gone from the store, false for a failed delete that is not a permission failure; a delete the app session
|
|
135
|
+
* may not make (a typed 401 or 403 from kv) throws `PERMISSION_DENIED`.
|
|
128
136
|
*/
|
|
129
|
-
export declare function deleteHeldCredential(input:
|
|
137
|
+
export declare function deleteHeldCredential(input: DeleteHeldCredentialInput): Promise<boolean>;
|
|
138
|
+
export interface ProbeHeldStoreAccessInput {
|
|
130
139
|
readonly kv: IKVService;
|
|
131
140
|
readonly ownerDid: unknown;
|
|
132
|
-
|
|
133
|
-
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Asks whether this session may LIST the owner's held credentials, with ONE `kv.list` of `v1/held/<registryKey>/` and nothing else: no cursor is
|
|
144
|
+
* followed, no record is read (`kv.get`), nothing is verified, written or deleted. Resolves when the list is ok (an empty store, entries, or a
|
|
145
|
+
* truncated page all resolve). A typed 401 or 403 from kv is `PERMISSION_DENIED` (the same text as the read functions); any other failure, or a
|
|
146
|
+
* kv that throws, is `OFFLINE`. A non-mainnet or non-did:pkh owner is refused (`ACTIVE_SESSION_REQUIRED`) before any kv call.
|
|
147
|
+
*
|
|
148
|
+
* It checks LIST access only. A session that can list but not `get` passes the probe and fails later, when a record is read. The permission text
|
|
149
|
+
* names both because the usual missing grant lacks both `get` and `list` on `v1/held/`.
|
|
150
|
+
*/
|
|
151
|
+
export declare function probeHeldStoreAccess(input: ProbeHeldStoreAccessInput): Promise<void>;
|
|
134
152
|
export interface PruneHeldCredentialsInput extends HeldIssuerPolicy {
|
|
135
153
|
readonly kv: IKVService;
|
|
136
154
|
readonly ownerDid: unknown;
|
|
@@ -4,8 +4,8 @@ export type { CredentialAcquisitionTransport, CredentialRequestState, Credential
|
|
|
4
4
|
export { acquireEmailProof, completeEmailProof, createEd25519HolderSigner, createMemoryEmailProofPendingStore, EmailProofError, requestEmailProofCode, verifyStoredEmailProof, } from "@tinycloud/node-sdk/credentials";
|
|
5
5
|
export type { EmailProofAcquireInput, EmailProofAcquisition, EmailProofErrorCode, EmailProofOptions, EmailProofPending, EmailProofPendingStore, EmailProofProfileId, EmailProofRequestInput, EmailProofResult, EmailProofStep, HolderAlgorithm, HolderSigner, StoredEmailProofInput, StoredEmailProofRecord, } from "@tinycloud/node-sdk/credentials";
|
|
6
6
|
export { createAccountHolderSigner } from "./credentials/account-holder";
|
|
7
|
-
export { findHeldCredential, listHeldEmailCredentials, storeHeldCredential, } from "./credentials/held-store";
|
|
8
|
-
export type { FindHeldCredentialInput, HeldCredentialRecord, HeldIssuerPolicy, HeldMatch, HeldStorageReceipt, ListHeldEmailCredentialsInput, StoreHeldCredentialInput, } from "./credentials/held-store";
|
|
7
|
+
export { deleteHeldCredential, findHeldCredential, listHeldEmailCredentials, probeHeldStoreAccess, storeHeldCredential, } from "./credentials/held-store";
|
|
8
|
+
export type { DeleteHeldCredentialInput, FindHeldCredentialInput, HeldCredentialRecord, HeldIssuerPolicy, HeldMatch, HeldStorageReceipt, ListHeldEmailCredentialsInput, ProbeHeldStoreAccessInput, StoreHeldCredentialInput, } from "./credentials/held-store";
|
|
9
9
|
export { acquireHeldCredential } from "./credentials/held-source";
|
|
10
10
|
export type { HeldAcquireInput, HeldCredentialResult } from "./credentials/held-source";
|
|
11
11
|
//# sourceMappingURL=credentials-subpath.d.ts.map
|
package/dist/credentials.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e={d:(t,r)=>{for(var i in r)e.o(r,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:r[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{EmailProofError:()=>x,OpenCredentialsHttpTransport:()=>h,acquireEmailProof:()=>Q,acquireHeldCredential:()=>Qe,completeEmailProof:()=>K,createAccountHolderSigner:()=>Ie,createEd25519HolderSigner:()=>P,createMemoryEmailProofPendingStore:()=>H,findHeldCredential:()=>Ve,interpretCredentialFlow:()=>c,listHeldEmailCredentials:()=>He,requestEmailProofCode:()=>M,storeHeldCredential:()=>Ue,verifyStoredEmailProof:()=>re});const r=require("@tinycloud/sdk-core"),i=require("@tinycloud/sdk-core/held-credentials");var n=Object.freeze({witnessOrigin:"https://witness.credentials.org",issuerDid:"did:web:issuer.credentials.org",issuerKid:"did:web:issuer.credentials.org#controller",issuerX:"eEJI4xEobto4HtQ7Pg9R1vBOwcpfGRTlXDG5QfqLnGQ",descriptorDigest:"1tg-qphmKBVtNwzVg9xyz-xxqt_xtMXAsQyXw46m8S0"}),s=Object.freeze({type:r.ACCOUNT_HOLDER_BINDING_DOMAIN,protocol:"tinycloud.credentials/acquisition/v1",profile:"tinycloud.email-held/v1",profileVersion:1,descriptorDigest:"dc3_DuvzipXwYkTfjKqTaK1c3VS0YSPnaBsYSQriC0w",issuer:n.issuerDid,issuerKid:n.issuerKid,audience:"tinycloud://credentials",openerOrigin:"https://localhost",completionOrigin:"https://localhost",completionContext:"sdk-acquisition",credentialLifetimeSeconds:31536e3}),o=6e5,a=()=>new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was substituted"),d=(e,t)=>new Promise((r,i)=>{const n=setTimeout(r,e);t?.addEventListener("abort",()=>{clearTimeout(n),i(new DOMException("Aborted","AbortError"))},{once:!0})});async function c(e){const t="account_is_subject"===e.descriptor.subjectRelationship;if(t&&!0!==e.allowAccountSubject)throw new r.CredentialError("UNSUPPORTED_PROFILE","The held credential profile requires an explicit opt-in");const i=new Map(e.descriptor.steps.map(e=>[e.type,e])),n=new Set;let c="";const l=async t=>{const i=(0,r.validateCredentialHolderBinding)(t);if(i.requestId!==e.requestId||i.descriptorDigest!==e.descriptorDigest||i.requirementDigest!==e.requirementDigest||i.holderDid!==e.holderDid||i.issuer!==e.descriptor.issuer.did||i.issuerKid!==e.descriptor.issuer.kid||i.profile!==e.descriptor.profile||i.openerOrigin!==e.openerOrigin||i.completionOrigin!==e.openerOrigin||"tinycloud://credentials"!==i.audience)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was substituted");const n=e.descriptor.holderBinding.alg;if(i.type!==e.descriptor.holderBinding.domain||"EIP191"===n&&!e.transport.challengeNonce)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was substituted");return"EIP191"===n&&await async function(e,t){const{descriptor:i}=t;if("EIP191"!==i.holderBinding.alg||e.type!==i.holderBinding.domain||e.requestId!==t.requestId||e.descriptorDigest!==t.descriptorDigest||e.requirementDigest!==t.requirementDigest||e.holderDid!==t.holderDid||e.issuer!==i.issuer.did||e.issuerKid!==i.issuer.kid||e.profile!==i.profile||e.openerOrigin!==t.openerOrigin||e.completionOrigin!==t.openerOrigin||e.audience!==s.audience||e.completionContext!==s.completionContext||e.type!==s.type||e.protocol!==s.protocol||e.profile!==s.profile||e.profileVersion!==s.profileVersion||e.descriptorDigest!==s.descriptorDigest||e.issuer!==s.issuer||e.issuerKid!==s.issuerKid||e.openerOrigin!==s.openerOrigin||e.completionOrigin!==s.completionOrigin||e.credentialLifetimeSeconds!==s.credentialLifetimeSeconds)throw a();if(void 0===t.challengeNonce||e.challengeNonce!==t.challengeNonce)throw a();if(e.normalizedClaimsDigest!==await(0,r.canonicalDigest)(t.requirement.claims))throw a();const n=Date.parse(e.expiresAt);if(void 0===t.serverExpiresAt||n!==Date.parse(t.serverExpiresAt)||Date.parse(e.issuedAt)!==n-o)throw a()}(i,{descriptor:e.descriptor,requirement:e.requirement,requestId:e.requestId,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,holderDid:e.holderDid,openerOrigin:e.openerOrigin,challengeNonce:e.transport.challengeNonce(e.requestId),serverExpiresAt:e.expiresAt}),i},u=async()=>{t&&void 0===e.transport.signedBinding?.(e.requestId)&&await l(await e.transport.holderBinding(e.requestId,e.verifier,e.signal))};for(;;){e.signal?.throwIfAborted();const t=await e.transport.state(e.requestId,e.verifier,e.signal);if(t.requestId!==e.requestId)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential request identity changed");if("expired"===t.state)throw new r.CredentialError("REQUEST_EXPIRED","Credential request expired",{state:t.state,correlationId:t.correlationId});if("canceled"===t.state)throw new r.CredentialError("CANCELED","Credential request was canceled",{state:t.state,correlationId:t.correlationId});if("issuer_unready"===t.state)throw new r.CredentialError("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:t.retryAfterMs,state:t.state,correlationId:t.correlationId});if("complete"===t.state)return void await u();if("ready_to_issue"===t.state||"issued"===t.state){await u(),"ready_to_issue"!==t.state||n.has("issue")?await(e.onWait?.()??d(t.retryAfterMs??50,e.signal)):(await e.transport.issue(e.requestId,e.verifier,e.signal),n.add("issue"));continue}const s=t.nextStep;if(!s){await(e.onWait?.()??d(t.retryAfterMs??50,e.signal));continue}const o=i.get(s.type);if(s.id!==s.type||!o||o.type!==s.type||o.version!==s.version)throw new r.CredentialError("REQUEST_SUBSTITUTED","Server selected an undeclared credential step");if(n.has(s.id)||t.transitionId===c)await(e.onWait?.()??d(t.retryAfterMs??50,e.signal));else{if(c=t.transitionId,"holder_signature"===s.type){e.onProgress?.({state:"signing",stepId:s.id,correlationId:t.correlationId});const i=await l(await e.transport.holderBinding(e.requestId,e.verifier,e.signal)),n=e.descriptor.holderBinding.alg;if("EIP191"===n!=("EIP191"===e.signing.holderKey?.alg))throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was substituted");const o=(0,r.holderBindingSigningBytes)(i);let a=await(e.signing.autoSign?.(i,o,e.signal));if(void 0===a){if(!e.signing.requestApproval)throw new r.CredentialError("SIGNATURE_REJECTED","OpenKey approval is required");try{a=await e.signing.requestApproval(i,o,e.signal)}catch(e){if(e instanceof r.CredentialError)throw e;throw new r.CredentialError("SIGNATURE_REJECTED","OpenKey approval was rejected",{cause:e})}}if(!(a instanceof Uint8Array)||0===a.length)throw new r.CredentialError("SIGNATURE_REJECTED","OpenKey signature is invalid");await e.transport.submitHolderSignature(e.requestId,e.verifier,"EIP191"===n?`0x${Array.from(a,e=>e.toString(16).padStart(2,"0")).join("")}`:(0,r.encodeBase64Url)(a),e.signal,e.signing.holderKey)}else{e.onProgress?.({state:"collect_input"===s.type?"collecting":"proving",stepId:s.id,correlationId:t.correlationId});const i=e.handlers?.[s.type],n=e.proofHandler;if(!i&&!n){await(e.onWait?.()??d(t.retryAfterMs??50,e.signal));continue}if(!0===s.constraints.challengeRequired&&await e.transport.beginStep(e.requestId,e.verifier,s.type,e.signal),i){const t=await i({descriptor:e.descriptor,requirement:e.requirement,stepId:s.id,constraints:s.constraints,signal:e.signal});await e.transport.submitStep(e.requestId,e.verifier,s.id,t,e.signal)}else{let t;for(let i=1;;i+=1){const o=await n({stepId:s.id,constraints:s.constraints,display:{title:e.descriptor.display.title,description:e.descriptor.display.description,consent:e.descriptor.display.consent,progressLabel:e.descriptor.accessibility.progressLabel,errorLiveRegion:e.descriptor.accessibility.errorLiveRegion},inputs:e.descriptor.inputs.map(({id:e,label:t,schema:r})=>({id:e,label:t,schema:r})),...void 0===t?{}:{feedback:t},signal:e.signal});try{await e.transport.submitStep(e.requestId,e.verifier,s.id,o,e.signal);break}catch(n){if(!(n instanceof r.CredentialError)||"PROOF_REJECTED"!==n.code)throw n;const o=e.descriptor.lifecycle.maxProofAttempts-i;if("mailbox_otp"!==s.type||o<=0)throw new r.CredentialError("VERIFICATION_FAILED","The proof was not accepted",{state:o<=0?"proof_attempts_exhausted":"proof_rejected",cause:n});t={kind:"rejected",attemptsRemaining:o}}}}}n.add(s.id)}}}function l(e,t){if("object"!=typeof e||null===e||Array.isArray(e))throw new r.CredentialError("VERIFICATION_FAILED",`${t} is invalid`);return e}function u(e,t){if("string"!=typeof e||!/^[A-Za-z0-9_-]{16,128}$/.test(e))throw new r.CredentialError("REQUEST_SUBSTITUTED",`${t} is invalid`);return e}function p(e,t){if("string"!=typeof e||!Number.isFinite(Date.parse(e)))throw new r.CredentialError("VERIFICATION_FAILED",`${t} is invalid`);return new Date(e).toISOString()}var f=new Set(["REQUEST_EXPIRED","ISSUER_UNREADY","UNSUPPORTED_PROFILE","UNSUPPORTED_VERSION","SIGNATURE_REJECTED"]),h=class{constructor(e,t=globalThis.fetch.bind(globalThis),i={}){if(this.descriptor=e,this.fetchFn=t,this.options=i,this.nonces=new Map,this.bindings=new Map,"account_is_subject"===e.subjectRelationship&&!0!==i.allowAccountSubject)throw new r.CredentialError("UNSUPPORTED_PROFILE","The held credential profile requires an explicit opt-in")}url(e,t){return new URL((0,r.credentialEndpointPath)(e,t),this.descriptor.issuer.origin).href}async request(e,t){let i;try{const r={method:t.method??"GET",credentials:"omit",cache:"no-store",redirect:"error",referrerPolicy:"no-referrer",signal:t.signal,headers:{accept:"application/json",...void 0===t.body?{}:{"content-type":"application/json"},...void 0===t.verifier?{}:{authorization:`Bearer ${t.verifier}`}},...void 0===t.body?{}:{body:JSON.stringify(t.body)}};i=await this.fetchFn(this.url(e,t.id),r)}catch(e){if(e instanceof DOMException&&"AbortError"===e.name)throw new r.CredentialError("CANCELED","Credential acquisition was canceled",{cause:e});throw new r.CredentialError("OFFLINE","OpenCredentials is unavailable",{cause:e})}if(!i.ok){let e;try{e=await i.json()}catch{e=void 0}const t=function(e,t,i){if("object"!=typeof e||null===e||Array.isArray(e))return;const n=e;if("code,correlationId,recoverable,state,type"!==Object.keys(n).sort().join(",")||"tinycloud.credentials/error/v1"!==n.type||"string"!=typeof n.code||"boolean"!=typeof n.recoverable||"string"!=typeof n.state||"string"!=typeof n.correlationId)return;if("PROOF_REJECTED"===n.code)return n.recoverable?new r.CredentialError("PROOF_REJECTED","The proof was not accepted",{state:n.state,correlationId:n.correlationId}):new r.CredentialError("VERIFICATION_FAILED","The proof attempt limit was reached",{state:"proof_attempts_exhausted",correlationId:n.correlationId});if("RATE_LIMITED"===n.code)return new r.CredentialError("ISSUER_UNREADY","Too many verification codes were requested",{state:"rate_limited",correlationId:n.correlationId,retryAfterMs:1e3*Number(t.headers.get("retry-after"))||void 0,recoverable:i?n.recoverable:void 0});if("CHALLENGE_EXPIRED"===n.code)return new r.CredentialError("REQUEST_EXPIRED","The credential challenge expired",{state:n.state,correlationId:n.correlationId,recoverable:i?n.recoverable:void 0});if("DESCRIPTOR_MISMATCH"===n.code&&(n.code="UNSUPPORTED_PROFILE"),!f.has(n.code))return;const s=n.code;return new r.CredentialError(s,`OpenCredentials rejected the request: ${s}`,{state:n.state,correlationId:n.correlationId,retryAfterMs:1e3*Number(t.headers.get("retry-after"))||void 0,recoverable:i?n.recoverable:void 0})}(e,i,!0===this.options.honorServerRecoverable);if(t)throw t;if(410===i.status)throw new r.CredentialError("REQUEST_EXPIRED","Credential request expired");if(409===i.status)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential request was replayed or substituted");if(503===i.status)throw new r.CredentialError("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:1e3*Number(i.headers.get("retry-after"))||void 0});throw new r.CredentialError("VERIFICATION_FAILED","OpenCredentials rejected the request")}if(204!==i.status)try{return await i.json()}catch(e){throw new r.CredentialError("VERIFICATION_FAILED","OpenCredentials response is invalid",{cause:e})}}async create(e){const t=l(await this.request("request",{method:"POST",body:{protocol:e.descriptor.protocol,profile:e.descriptor.profile,profileVersion:e.descriptor.profileVersion,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,holderDid:e.holderDid,inputs:e.inputs??e.requirement.claims,audience:s.audience,openerOrigin:e.openerOrigin,completionOrigin:e.openerOrigin,completionContext:s.completionContext,completionVerifierChallenge:e.completionVerifierChallenge},signal:e.signal}),"create response");if("tinycloud.credentials/acquisition-request/v1"!==t.type||t.protocol!==e.descriptor.protocol||"challenge"!==t.next||"challenge"!==t.endpoint)throw new r.CredentialError("VERIFICATION_FAILED","create response is invalid");const i=u(t.requestId,"requestId");return{requestId:i,locator:i,expiresAt:p(t.expiresAt,"expiresAt"),correlationId:i}}challengeNonce(e){return this.nonces.get(e)}signedBinding(e){return this.bindings.get(e)}proofStep(){return this.descriptor.steps.some(e=>"mailbox_otp"===e.type)?"mailbox_otp":"collect_input"}async state(e,t,i){const n=l(await this.request("state",{id:e,verifier:t,signal:i}),"state response");if("tinycloud.credentials/acquisition-state/v1"!==n.type||n.requestId!==e||n.profile!==this.descriptor.profile||1!==n.profileVersion)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential state response is substituted");const s={type:"OpenCredentialsAcquisitionState",version:1,requestId:e,transitionId:`${String(n.state)}:${String(n.resultPreviouslyRead??!1)}`,correlationId:e};if("challenge_required"===n.state){const e=this.proofStep();return{...s,state:"pending",nextStep:{id:e,type:e,version:1,constraints:{challengeRequired:!0}}}}if("account_is_subject"===this.descriptor.subjectRelationship&&("proof_required"===n.state||"holder_binding_required"===n.state||"holder_signature_required"===n.state||"ready_to_issue"===n.state||"issued"===n.state)){const t=n.challengeNonce,i=this.nonces.get(e);if("string"!=typeof t||""===t||void 0!==i&&i!==t)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential challenge nonce is missing or changed");this.nonces.set(e,u(t,"challengeNonce"))}if("proof_required"===n.state){const t=this.proofStep();return"account_is_subject"!==this.descriptor.subjectRelationship&&this.nonces.set(e,u(n.challengeNonce,"challengeNonce")),{...s,state:"pending",nextStep:{id:t,type:t,version:1,constraints:{}}}}if("holder_binding_required"===n.state||"holder_signature_required"===n.state)return{...s,state:"pending",nextStep:{id:"holder_signature",type:"holder_signature",version:1,constraints:{}}};if("ready_to_issue"===n.state)return{...s,state:"ready_to_issue"};if("issued"===n.state)return{...s,state:"complete"};throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential state is unsupported")}async beginStep(e,t,i,n){const s=this.proofStep();if(i!==s)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential challenge step is substituted");const o=l(await this.request("challenge",{id:e,verifier:t,method:"POST",body:{step:s,stepVersion:1},signal:n}),"challenge response");if("tinycloud.credentials/challenge/v1"!==o.type||o.step!==s||1!==o.stepVersion)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential challenge is substituted");this.nonces.set(e,u(o.challengeNonce,"challengeNonce"))}async submitStep(e,t,i,n,s){const o=this.proofStep();if(i!==o)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential proof step is substituted");const a=this.nonces.get(e);if(!a)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential challenge is missing");await this.request("proof",{id:e,verifier:t,method:"POST",body:{step:o,stepVersion:1,challengeNonce:a,proof:n},signal:s})}async holderBinding(e,t,i){const n=l(await this.request("holder_binding",{id:e,verifier:t,signal:i}),"holder binding response");if("tinycloud.credentials/holder-binding-request/v1"!==n.type||n.signingDomain!==this.descriptor.holderBinding.domain||n.alg!==this.descriptor.holderBinding.alg||"string"!=typeof n.canonical)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding response is invalid");const s=(0,r.validateCredentialHolderBinding)(n.binding);if(s.type!==n.signingDomain)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding type does not match its signing domain");if((0,r.encodeBase64Url)((0,r.holderBindingCanonicalBytes)(s))!==n.canonical)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding canonical bytes were substituted");return this.bindings.set(e,s),s}async submitHolderSignature(e,t,i,n,s){const o=this.bindings.get(e);if(!o)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was not retrieved");if("EIP191"===this.descriptor.holderBinding.alg&&!s)throw new r.CredentialError("REQUEST_SUBSTITUTED","An account holder must name its key and algorithm");const a=s?.alg??"EdDSA",d=s?.kid??`${o.holderDid}#${o.holderDid.replace("did:key:","")}`;await this.request("holder_signature",{id:e,verifier:t,method:"POST",body:{alg:a,kid:d,signature:i},signal:n})}async issue(e,t,r){await this.request("issue",{id:e,verifier:t,method:"POST",signal:r})}async result(e,t,i){const n=l(await this.request("result",{id:e,verifier:t,signal:i}),"result response");if("tinycloud.credentials/result/v1"!==n.type||n.protocol!==this.descriptor.protocol||n.profile!==this.descriptor.profile||1!==n.profileVersion||"vc+sd-jwt"!==n.format||n.descriptorDigest!==await(0,r.canonicalDigest)(this.descriptor)||n.issuer!==this.descriptor.issuer.did||n.issuerKid!==this.descriptor.issuer.kid||"string"!=typeof n.credential||await(0,r.sha256Base64Url)(n.credential)!==n.credentialDigest)throw new r.CredentialError("VERIFICATION_FAILED","Issued result metadata is invalid");const s=l(n.holderBinding,"result holder binding");if(n.subject!==s.did||s.signingDomain!==this.descriptor.holderBinding.domain)throw new r.CredentialError("HOLDER_MISMATCH","Issued holder binding is invalid");const o=l(n.claims,"result claims"),a={};for(const[e,t]of Object.entries(o)){if("string"!=typeof t)throw new r.CredentialError("VERIFICATION_FAILED","Issued claims are invalid");a[e]=t}const d=l(n.validity,"result validity"),c=function(e){const t=e.split("~",1)[0]?.split(".")[1];if(!t)throw new r.CredentialError("VERIFICATION_FAILED","Issued SD-JWT is invalid");try{return l(JSON.parse((new TextDecoder).decode((0,r.decodeBase64Url)(t))),"SD-JWT payload")}catch(e){if(e instanceof r.CredentialError)throw e;throw new r.CredentialError("VERIFICATION_FAILED","Issued SD-JWT is invalid",{cause:e})}}(n.credential);if("string"!=typeof c.jti)throw new r.CredentialError("VERIFICATION_FAILED","Credential id is invalid");const u=p(d.issuedAt,"issuedAt"),f=p(d.expiresAt,"expiresAt"),h=l(n.status,"result status");if("none"!==h.type||h.freshnessSeconds!==this.descriptor.status.freshnessSeconds)throw new r.CredentialError("VERIFICATION_FAILED","Credential status is invalid");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:n.issuer,issuerKid:n.issuerKid,subjectDid:n.subject,holderDid:n.subject,claims:a,claimsDigest:await(0,r.canonicalDigest)(a),descriptorDigest:n.descriptorDigest,credentialId:c.jti,issuedAt:u,notBefore:u,expiresAt:f,status:{method:"none",freshnessSeconds:h.freshnessSeconds},credential:n.credential}}async issuerMetadata(e){return await this.request("issuer_metadata",{signal:e})}async checkStatus(e,t){return"none"===e.method&&e.freshnessSeconds===this.descriptor.status.freshnessSeconds}},E={id:"opencredentials.email/v1",version:1},w=9e5,g=`${n.witnessOrigin}/.well-known/opencredentials`,I=[{kid:n.issuerKid,alg:"EdDSA",jwk:{kty:"OKP",crv:"Ed25519",x:n.issuerX},validFrom:"2020-01-01T00:00:00Z",validUntil:"2100-01-01T00:00:00Z"}],D="tinycloud.email-proof/v1",m={"tinycloud.email-proof/v1":{descriptorDigest:n.descriptorDigest,requiredStep:"mailbox_otp",enabled:!0},"tinycloud.email-held/v1":{descriptorDigest:s.descriptorDigest,requiredStep:"mailbox_otp",enabled:!1}},A=s.openerOrigin,y="tinycloud.email-held/v1",S="blockchainAccountId",v=31536e3,T=6e5,C=3e5,_=6e4,O="did:key:",R=/^did:key:z6Mk[^#]+$/,b=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,N=Symbol.for("nodejs.util.inspect.custom"),q={ADDRESS_INVALID:!1,HOLDER_INVALID:!1,CODE_INVALID:!0,RATE_LIMITED:!0,ISSUER_UNAVAILABLE:!0,NETWORK:!0,PROFILE_UNAVAILABLE:!1,CODE_REJECTED:!0,CODE_ATTEMPTS_EXHAUSTED:!1,SIGNATURE_REJECTED:!0,CREDENTIAL_INVALID:!1,SESSION_EXPIRED:!1,SESSION_INVALID:!1,CLIENT_CLOCK_SKEW:!1,CANCELED:!1,FAILED:!1},L={ADDRESS_INVALID:"Email address is invalid.",HOLDER_INVALID:"Holder must be a did:key Ed25519 identifier.",CODE_INVALID:"Verification code must be 8 digits.",ISSUER_UNAVAILABLE:"Email verification is unavailable right now.",NETWORK:"Could not reach the email verification service.",PROFILE_UNAVAILABLE:"The witness does not offer the email verification profile.",CODE_REJECTED:"Verification code was not accepted.",CODE_ATTEMPTS_EXHAUSTED:"Too many wrong codes. Request a new code.",SIGNATURE_REJECTED:"Holder signature was rejected.",CREDENTIAL_INVALID:"Issued credential failed verification.",SESSION_EXPIRED:"Email verification request expired. Request a new code.",SESSION_INVALID:"Email verification request is no longer valid. Request a new code.",CLIENT_CLOCK_SKEW:"Your device clock is more than 5 minutes behind. Correct it and try again.",CANCELED:"Email verification was canceled.",FAILED:"Email verification failed."},U="This SDK build doesn't enable the email verification profile.",x=class extends Error{constructor(e,t,r,i=q[t],n){super(n??("RATE_LIMITED"===t?function(e){const t="Too many codes were requested for this address.";if(void 0===e||!Number.isFinite(e)||e<=0)return`${t} Try again in about an hour.`;const r=Math.max(1,Math.ceil(e/6e4));return`${t} Try again in ${r} ${1===r?"minute":"minutes"}.`}(r):L[t])),this.name="EmailProofError",this.step=e,this.code=t,this.retryAfterMs=r,this.recoverable=i}};function P(e,t){const r=e.indexOf("#"),i=-1===r?e:e.slice(0,r);if(-1!==r&&e.slice(r+1)!==i.slice(O.length))throw new x("request","HOLDER_INVALID");if(!R.test(i))throw new x("request","HOLDER_INVALID");return{did:i,alg:"EdDSA",kid:G(i),sign:t}}function F(e){const t={type:e.type,version:e.version,profile:e.profile,address:e.address,requestId:e.requestId,holderDid:e.holderDid,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,openerOrigin:e.openerOrigin,createdAt:e.createdAt,expiresAt:e.expiresAt,...void 0===e.serverExpiresAt?{}:{serverExpiresAt:e.serverExpiresAt}},r={...t};return k(r,"verifier",e.verifier),k(r,"toJSON",()=>({...t})),k(r,N,()=>({...t,verifier:"[redacted]"})),Object.freeze(r)}function k(e,t,r){Object.defineProperty(e,t,{value:r,enumerable:!1,writable:!1,configurable:!1})}function V(e){return Math.min(Date.parse(e.expiresAt),Date.parse(e.createdAt)+w)}function H(){const e=new Map,t=t=>{for(const[r,i]of e)V(i)<=t.getTime()&&e.delete(r)};return{async findLive(r,i){let n;t(i);for(const t of e.values())t.address===r&&(!n||Date.parse(t.createdAt)>Date.parse(n.createdAt))&&(n=t);return n},async put(t){e.set(t.requestId,t)},async delete(t){e.delete(t)},get:async(r,i)=>(t(i),e.get(r))}}var j=class extends Error{},B=async()=>{throw new j("code requested")};async function M(e){const t=e.profile??D;Y(t,"request",e.allowHeldProfile);const i=t===y;i&&W(e.holder,"request",t);const n=J(e.address,t);i||W(e.holder,"request",t);const s=e.now??(()=>new Date),o=e.signal??AbortSignal.timeout(_),a=Z(n,t),d=await(0,r.credentialRequirementDigest)(a),l=await ee(t,a,{fetch:e.fetch,signal:o},"request",e.allowHeldProfile),u=await(0,r.canonicalDigest)(l),p=(0,r.encodeBase64Url)(crypto.getRandomValues(new Uint8Array(32))),f=new h(l,e.fetch,{honorServerRecoverable:!0,...i?{allowAccountSubject:!0}:{}}),E=s().getTime();let g;try{g=await f.create({descriptor:l,descriptorDigest:u,requirement:a,requirementDigest:d,holderDid:e.holder.did,openerOrigin:A,completionVerifierChallenge:await(0,r.sha256Base64Url)(p),signal:o})}catch(e){throw ne(e,"request",o)}const I=Date.parse(g.expiresAt);if(!Number.isFinite(I))throw new x("request","FAILED");const m=I-T;if(i&&m-s().getTime()>C)throw new x("request","CLIENT_CLOCK_SKEW");const S=F({type:"TinyCloudEmailProofPending",version:1,profile:t,address:n,requestId:g.requestId,verifier:p,holderDid:e.holder.did,descriptorDigest:u,requirementDigest:d,openerOrigin:A,createdAt:new Date(E).toISOString(),expiresAt:new Date(i?E+Math.min(I-m,w):Math.min(I,E+w)).toISOString(),...i?{serverExpiresAt:g.expiresAt}:{}});try{await c({descriptor:l,...i?{allowAccountSubject:!0}:{},requirement:a,requestId:g.requestId,verifier:p,holderDid:e.holder.did,descriptorDigest:u,requirementDigest:d,openerOrigin:A,...i?{expiresAt:g.expiresAt}:{},transport:f,signing:ie(e.holder,i),handlers:{mailbox_otp:B},signal:o})}catch(e){if(e instanceof j)return S;throw ne(e,"request",o)}throw new x("request","FAILED")}async function K(e){return $(e,I)}async function $(e,t){const{pending:s}=e,o=e.now??(()=>new Date);if(!function(e){if("object"!=typeof e||null===e)return!1;const t=e;return"TinyCloudEmailProofPending"===t.type&&1===t.version&&t.openerOrigin===A&&[t.profile,t.address,t.requestId,t.verifier,t.holderDid,t.descriptorDigest,t.requirementDigest,t.openerOrigin,t.createdAt,t.expiresAt].every(e=>"string"==typeof e)&&Number.isFinite(Date.parse(t.createdAt))&&Number.isFinite(Date.parse(t.expiresAt))}(s))throw new x("session","SESSION_INVALID");Y(s.profile,"session",e.allowHeldProfile);const a=s.profile===y;if(a&&!Number.isFinite(Date.parse(s.serverExpiresAt??"")))throw new x("session","SESSION_INVALID");if(V(s)<=o().getTime())throw new x("session","SESSION_EXPIRED");if(!/^\d{8}$/.test(e.code))throw new x("code","CODE_INVALID");if(W(e.holder,"code",s.profile),e.holder.did!==s.holderDid)throw new x("session","SESSION_INVALID");const d=e.signal??AbortSignal.timeout(_),l=Z(s.address,s.profile);if(await(0,r.credentialRequirementDigest)(l)!==s.requirementDigest)throw new x("session","SESSION_INVALID");const u=await ee(s.profile,l,{fetch:e.fetch,signal:d},"session",e.allowHeldProfile),p=await(0,r.canonicalDigest)(u);if(p!==s.descriptorDigest)throw new x("session","SESSION_INVALID");const f=new h(u,e.fetch,{honorServerRecoverable:!0,...a?{allowAccountSubject:!0}:{}});try{const t=await f.state(s.requestId,s.verifier,d);if(!0===t.nextStep?.constraints.challengeRequired)throw new x("session","SESSION_INVALID");await c({descriptor:u,...a?{allowAccountSubject:!0}:{},requirement:l,requestId:s.requestId,verifier:s.verifier,holderDid:s.holderDid,descriptorDigest:p,requirementDigest:s.requirementDigest,openerOrigin:s.openerOrigin,...a?{expiresAt:s.serverExpiresAt}:{},transport:f,signing:ie(e.holder,a),handlers:{mailbox_otp:async()=>({otp:e.code})},signal:d})}catch(e){throw ne(e,"code",d)}try{const e=await f.result(s.requestId,s.verifier,d);if(a){const a=await async function(e){const{envelope:t,pending:s,descriptor:o}=e,a=e=>new r.CredentialError("VERIFICATION_FAILED",e),d=Date.parse(t.issuedAt),c=e.now().getTime();if(!Number.isFinite(d)||d-c>C)throw a("client clock is more than 5 minutes behind the issuer");const l=e.issuerKeys.find(e=>e.kid===n.issuerKid);if(!l)throw a("no pinned issuer key");const u=(0,i.parseIssuerSet)({format:"tinycloud.credentials-issuers/v1",version:1,issuers:[{issuerDid:n.issuerDid,kid:n.issuerKid,alg:"EdDSA",publicKey:l.jwk.x,vcts:[E.id],profiles:[y],notBefore:"2020-01-01T00:00:00Z",retiredAt:null,notAfter:null}]},{didMethods:{issuer:["web"]}}),p=(0,i.verifyHeldEmailCredential)(t.credential,{now:new Date(Math.max(c,d)),owner:s.holderDid,didMethods:{issuer:["web"]},acceptedIssuers:[{issuerDid:n.issuerDid,kid:n.issuerKid}],issuerSet:u}),f=e.transport.signedBinding(s.requestId),h=Object.keys(t.claims).sort().join(),w=e=>Math.floor(e/1e3);if(t.subjectDid!==s.holderDid||t.holderDid!==s.holderDid||"email,emailDomain"!==h||t.claims.email!==p.claims.email||t.claims.emailDomain!==p.claims.emailDomain||t.claims.email!==s.address||w(Date.parse(t.issuedAt))!==w(p.issuedAt.getTime())||w(Date.parse(t.expiresAt))!==w(p.expiresAt.getTime())||t.descriptorDigest!==e.descriptorDigest||t.profile.id!==y||1!==t.profile.version||t.issuerDid!==n.issuerDid||t.issuerKid!==n.issuerKid||"vc+sd-jwt"!==t.format||"none"!==t.status.method||t.status.freshnessSeconds!==o.status.freshnessSeconds)throw a("issued credential does not match the request");if(f?.type!==o.holderBinding.domain||!("credentialLifetimeSeconds"in f))throw a("signed binding is missing");if(p.credentialId!==f.jti||(p.expiresAt.getTime()-p.issuedAt.getTime())/1e3!==f.credentialLifetimeSeconds)throw a("credential does not match the binding the account signed");return p}({envelope:e,pending:s,descriptor:u,descriptorDigest:p,transport:f,issuerKeys:t,now:o});return{envelope:e,verified:a,credentialId:a.credentialId,issuedAt:a.issuedAt.toISOString(),expiresAt:a.expiresAt.toISOString(),descriptor:u}}const c=await(0,r.verifyIssuedCredential)({envelope:e,descriptor:u,descriptorDigest:p,requirement:l,holderDid:s.holderDid,issuerMetadata:te(t),now:o(),checkStatus:(e,t)=>f.checkStatus(e,t),signal:d});return{envelope:e,verified:c,credentialId:c.credentialId,issuedAt:c.issuedAt,expiresAt:c.expiresAt,descriptor:u}}catch(e){throw ne(e,"credential",d)}}async function Q(e){return async function(e,t){const r=e.profile??D;Y(r,"request",e.allowHeldProfile);const i=J(e.address,r),n=e.now??(()=>new Date),s=e.pendingStore,o=s?await s.findLive(i,n()):void 0;let a=o?.profile===r?o:void 0;if(a&&r===y&&!Number.isFinite(Date.parse(a.serverExpiresAt??"")))throw await(s?.delete(a.requestId).catch(()=>{})),new x("session","SESSION_INVALID");a||(a=await M({...e,address:i}),await(s?.put(a)));const d=F(a);if(!e.getCode)return{status:"code-requested",pending:d};const c=await e.getCode({pending:d});try{const r=await $({...e,pending:a,code:c},t),i=[];if(s)try{await s.delete(a.requestId)}catch{i.push("The pending request could not be deleted after success; it expires at its deadline.")}return{status:"issued",result:r,warnings:i}}catch(e){throw e instanceof x&&e.recoverable||await(s?.delete(a.requestId).catch(()=>{})),e}}(e,I)}function J(e,t){if(t===y)return function(e){const t=()=>new x("request","ADDRESS_INVALID"),r=e.trim();if(/[^\x00-\x7f]/.test(r))throw t();const i=r.toLowerCase(),n=i.split("@");if(i.length<3||i.length>254||2!==n.length||/[^\x21-\x7e]/.test(i))throw t();const[s,o]=n;if(s.length>64||!z.test(s)||s.startsWith("+"))throw t();if(o.length>253||!o.includes(".")||!o.split(".").every(e=>e.length<=63&&X.test(e)))throw t();return i}(e);const r=e.trim();if(r.length>254||!b.test(r))throw new x("request","ADDRESS_INVALID");return r}var z=/^[a-z0-9!#$%&'*+\-/=?^_`{|}~]+(\.[a-z0-9!#$%&'*+\-/=?^_`{|}~]+)*$/,X=/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;function G(e){return`${e}#${e.slice(O.length)}`}function W(e,t,r){if(r===y)return function(e,t){const r=(0,i.parsePkhDid)(e.did),n=null!==r&&"1"===r.chainId?`did:pkh:eip155:1:${(0,i.toChecksumAddress)(r.address)}`:void 0;if(void 0===n||e.did!==n||"EIP191"!==e.alg||e.kid!==`${n}#${S}`)throw new x(t,"HOLDER_INVALID")}(e,t);if(!R.test(e.did)||"EdDSA"!==e.alg||e.kid!==G(e.did))throw new x(t,"HOLDER_INVALID")}function Y(e,t,r){const i=Object.prototype.hasOwnProperty.call(m,e)?m[e]:void 0;if(!i||!i.enabled&&(!0!==r||e!==y))throw new x(t,"PROFILE_UNAVAILABLE",void 0,void 0,U);return i}function Z(e,t){return t===y?(0,r.validateCredentialRequirement)({type:"TinyCloudCredentialRequirement",version:1,profile:{id:t,version:1},credentialType:E,claims:{email:e},maxAgeSeconds:v}):(0,r.createEmailCredentialRequirement)({email:e,profile:{id:t,version:1},credentialType:E})}async function ee(e,t,i,s,o){const a=Y(e,s,o);let d;try{d=await async function(e,t,i={}){let n;try{n=new URL(t)}catch{throw new r.CredentialError("UNSUPPORTED_PROFILE","Discovery URL is invalid")}if("https:"!==n.protocol||!["/.well-known/opencredentials","/v1/credential-types"].includes(n.pathname)||n.search||n.hash)throw new r.CredentialError("UNSUPPORTED_PROFILE","Discovery URL is not an allowed catalog endpoint");const s={credentials:"omit",cache:"no-store",redirect:"error",referrerPolicy:"no-referrer",signal:i.signal};let o;try{o=await(i.fetch??globalThis.fetch.bind(globalThis))(n,s)}catch(e){throw new r.CredentialError("OFFLINE","Credential discovery is unavailable",{cause:e})}if(!o.ok)throw new r.CredentialError(503===o.status?"ISSUER_UNREADY":"OFFLINE","Credential discovery is unavailable");const a=await o.json();if("tinycloud.credentials/catalog/v1"!==a.type||"tinycloud.credentials/acquisition/v1"!==a.protocol||1!==a.catalogVersion||!Array.isArray(a.profiles))throw new r.CredentialError("DESCRIPTOR_INVALID","Credential catalog is invalid");for(const t of a.profiles){if("object"!=typeof t||null===t||Array.isArray(t))continue;const i=t;if(!0===i.supported&&!0===i.enabled&&("ready"===i.readiness||"degraded"===i.readiness))try{const t=(0,r.validateCredentialFlowDescriptor)(i.descriptor);if((0,r.descriptorSatisfiesRequirement)(t,e)&&i.descriptorDigest===await(0,r.canonicalDigest)(t))return t}catch{}}throw new r.CredentialError("UNSUPPORTED_PROFILE","No available credential profile satisfies the requirement")}(t,g,{fetch:i.fetch,signal:i.signal})}catch(e){throw function(e,t,r){return t.aborted&&"TimeoutError"!==t.reason?.name?new x(r,"CANCELED"):ne(e,r,t)}(e,i.signal,s)}if(d.issuer.origin!==n.witnessOrigin||d.issuer.did!==n.issuerDid||!d.steps.some(e=>e.type===a.requiredStep))throw new x(s,"PROFILE_UNAVAILABLE");if(await(0,r.canonicalDigest)(d)!==a.descriptorDigest)throw new x(s,"PROFILE_UNAVAILABLE");return d}function te(e){return{type:"OpenCredentialsIssuerMetadata",version:1,origin:n.witnessOrigin,issuerDid:n.issuerDid,keys:e,cache:{maxAgeSeconds:3600,etag:"pinned"}}}async function re(e){return async function(e,t){const{record:i,requirement:s,holderDid:o}=e,a=i.descriptor;if(i.descriptorDigest!==n.descriptorDigest||await(0,r.canonicalDigest)(a)!==n.descriptorDigest)throw new r.CredentialError("VERIFICATION_FAILED","stored descriptor does not match the pinned descriptor digest");const d={type:"OpenCredentialsIssuedCredential",version:1,protocol:a.protocol,profile:i.profile,credentialType:i.credentialType,schema:i.schema,format:"vc+sd-jwt",issuerDid:i.issuerDid,issuerKid:i.issuerKid,subjectDid:i.subjectDid,holderDid:i.holderDid,claims:i.claims,claimsDigest:i.claimsDigest,descriptorDigest:i.descriptorDigest,credentialId:i.credentialId,issuedAt:i.issuedAt,notBefore:i.notBefore,expiresAt:i.expiresAt,status:i.status,credential:i.credential},c=await(0,r.verifyIssuedCredential)({envelope:d,descriptor:a,descriptorDigest:n.descriptorDigest,requirement:s,holderDid:o,issuerMetadata:te(t),now:e.now,checkStatus:async e=>"none"===e.method&&e.freshnessSeconds===a.status.freshnessSeconds,signal:e.signal});if(i.holderDid!==o||i.ownerDid!==o)throw new r.CredentialError("HOLDER_MISMATCH","stored record belongs to another holder");if(i.credentialDigest!==c.credentialDigest)throw new r.CredentialError("VERIFICATION_FAILED","stored credential digest does not match the verified credential");if(i.requirementDigest!==await(0,r.credentialRequirementDigest)(s))throw new r.CredentialError("VERIFICATION_FAILED","stored requirement digest does not match the requirement");if(i.recordId!==await(0,r.canonicalDigest)({credentialDigest:c.credentialDigest,holderDid:i.ownerDid}))throw new r.CredentialError("VERIFICATION_FAILED","stored record id does not match its credential");return c}(e,I)}function ie(e,t){return{autoSign:async(r,i)=>{try{return await e.sign(i)}catch(e){const r=e instanceof DOMException&&("TimeoutError"===e.name||"AbortError"===e.name);if(!t||e instanceof x||r)throw e;throw new x("credential","SIGNATURE_REJECTED")}},holderKey:{alg:e.alg,kid:e.kid}}}function ne(e,t,i){if(e instanceof x)return e;if(e instanceof DOMException&&"TimeoutError"===e.name)return new x(t,"NETWORK");const n=(0,r.credentialError)(e),s=n.details;switch(n.code){case"ISSUER_UNREADY":return"rate_limited"===s.state?new x(t,"RATE_LIMITED",s.retryAfterMs,n.recoverable):new x(t,"ISSUER_UNAVAILABLE",void 0,n.recoverable);case"OFFLINE":return i?.aborted&&"TimeoutError"!==i.reason?.name?new x(t,"CANCELED"):new x(t,"NETWORK");case"UNSUPPORTED_PROFILE":case"UNSUPPORTED_VERSION":case"DESCRIPTOR_INVALID":return new x(t,"PROFILE_UNAVAILABLE");case"PROOF_REJECTED":return new x("code","CODE_REJECTED",void 0,!0);case"VERIFICATION_FAILED":return"proof_attempts_exhausted"===s.state?new x("code","CODE_ATTEMPTS_EXHAUSTED"):"credential"===t?new x("credential","CREDENTIAL_INVALID"):"code"===t?new x("code","CODE_REJECTED",void 0,!1):new x(t,"FAILED");case"HOLDER_MISMATCH":return new x("credential","CREDENTIAL_INVALID");case"REQUEST_EXPIRED":return new x("session","SESSION_EXPIRED");case"REQUEST_SUBSTITUTED":return new x("session","SESSION_INVALID");case"SIGNATURE_REJECTED":return new x("credential","SIGNATURE_REJECTED",void 0,n.recoverable);case"CANCELED":return new x(t,"CANCELED");default:return new x(t,"FAILED")}}const se="blockchainAccountId",oe="1",ae=0,de="The wallet signer signs only the exact account binding for this request.";function ce(){return new x("request","HOLDER_INVALID",void 0,void 0,de)}function le(){return new x("request","HOLDER_INVALID")}const ue=["audience","challengeNonce","completionContext","completionOrigin","credentialLifetimeSeconds","descriptorDigest","expiresAt","holderDid","issuedAt","issuer","issuerKid","jti","normalizedClaimsDigest","openerOrigin","profile","profileVersion","protocol","requestId","requirementDigest","type"],pe=/^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,fe=/^[A-Za-z0-9_-]{32}$/,he=/^[A-Za-z0-9_-]{43}$/,Ee=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/,we=6e5;function ge(e){try{return new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(e)}catch{throw ce()}}function Ie(e,t){const n=(0,i.parsePkhDid)(e);if(null===n||n.chainId!==oe)throw le();const o=(0,i.toChecksumAddress)(n.address),a=`did:pkh:eip155:${oe}:${o}`;return{did:a,alg:"EIP191",kid:`${a}#${se}`,sign:async e=>{const n=new Uint8Array(e);!function(e,t){const n=ge(e);let o,a;try{o=JSON.parse(n),a=(0,r.jcsCanonicalize)(o)}catch{throw ce()}if(a!==n||"object"!=typeof o||null===o||Array.isArray(o))throw ce();const d=o;if(Object.keys(d).sort().join()!==ue.join())throw ce();for(const e of ue)if("profileVersion"!==e&&"credentialLifetimeSeconds"!==e&&("string"!=typeof d[e]||""===d[e]))throw ce();const c=e=>d[e];if(Object.keys(s).some(e=>d[e]!==s[e])||!(0,i.pkhPrincipalsEqual)(d.holderDid,t)||!pe.test(c("jti"))||!fe.test(c("requestId"))||!fe.test(c("challengeNonce"))||!he.test(c("requirementDigest"))||!he.test(c("normalizedClaimsDigest"))||!Ee.test(c("issuedAt"))||!Ee.test(c("expiresAt"))||Date.parse(c("expiresAt"))-Date.parse(c("issuedAt"))!==we)throw ce()}(function(e){const t=(new TextEncoder).encode(i.ACCOUNT_BINDING_DOMAIN);if(e.length<=t.length+1||e[t.length]!==ae)throw ce();for(let r=0;r<t.length;r++)if(e[r]!==t[r])throw ce();return e.subarray(t.length+1)}(n),a);const d=ge(n),c=await t(n),l=c[64];if(65!==c.length||27!==l&&28!==l)throw le();if(!await(0,r.verifyEip191MessageSignature)(d,function(e){return`0x${Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}`}(c),o))throw le();return c}}}const De=6e5;function me(e,t){return e.getTime()-t.getTime()>De}const Ae=50,ye="1",Se="KV_NOT_FOUND",ve="This app can't read held credentials: the session may lack kv get and list on v1/held/ (skipPrefix), or may need to sign in again.",Te="This app can't delete held credentials: the session may lack kv del on v1/held/ (skipPrefix), or may need to sign in again.",Ce="permission_denied";function _e(e){let t="object"==typeof e&&null!==e&&"error"in e?e.error:void 0,r=!1;for(let e=0;e<8&&"object"==typeof t&&null!==t;e+=1){const e=t,i=e.meta,n=[e.status,e.statusCode,"object"==typeof i&&null!==i?i.status:void 0].find(e=>"number"==typeof e&&Number.isInteger(e)&&e>=400&&e<=599);if(void 0!==n)return 401===n||403===n;"AUTH_UNAUTHORIZED"===e.code&&(r=!0),t=e.cause}return r}function Oe(e){const t=(0,i.parsePkhDid)(e);if(null===t)throw new r.CredentialError("ACTIVE_SESSION_REQUIRED","Held credentials require a did:pkh:eip155 account owner");if(t.chainId!==ye)throw new r.CredentialError("ACTIVE_SESSION_REQUIRED","Held credentials require an Ethereum mainnet (chain 1) account owner");return`did:pkh:eip155:${ye}:${(0,i.toChecksumAddress)(t.address)}`}function Re(e){return`v1/held/${(0,i.registryKey)(e)}/`}function be(e,t){return`${Re(e)}${t}`}function Ne(e){if("object"!=typeof e||null===e)return!1;const t=e;return"TinyCloudHeldCredential"===t.type&&1===t.version&&"string"==typeof t.ownerDid&&"string"==typeof t.recordId&&"string"==typeof t.credentialDigest&&"string"==typeof t.credential&&"string"==typeof t.storedAt}function qe(e,t,r){return{issuerSet:e.issuerSet,acceptedIssuers:e.acceptedIssuers,didMethods:e.didMethods,now:t,owner:r}}async function Le(e){return{type:"TinyCloudHeldStorageReceipt",version:1,ownerDid:e.ownerDid,recordId:e.recordId,recordDigest:await(0,r.canonicalDigest)(e),storedAt:e.storedAt}}async function Ue(e){const t=e.now??new Date,n=Oe(e.ownerDid);let s;try{s=(0,i.verifyHeldEmailCredential)(e.sdJwt,qe(e,t,n))}catch(e){throw function(e){if(!(e instanceof i.HeldCredentialError))return e;const t="nonce-account-mismatch"===e.code?"HOLDER_MISMATCH":"VERIFICATION_FAILED";return new r.CredentialError(t,e.message,{cause:e})}(e)}const o=e.sdJwt;if("string"!=typeof o)throw new r.CredentialError("VERIFICATION_FAILED","Held credential must be an SD-JWT string");if("string"!=typeof s.claims.email)throw new r.CredentialError("VERIFICATION_FAILED","Held credential must disclose an email claim");if(!me(s.expiresAt,t))throw new r.CredentialError("VERIFICATION_FAILED","Held credential expires within the reuse margin");const a=await(0,r.canonicalDigest)(o),d=await(0,r.canonicalDigest)({credentialDigest:a,holderDid:n}),c={type:"TinyCloudHeldCredential",version:1,ownerDid:n,recordId:d,credentialDigest:a,credential:o,storedAt:t.toISOString()},l=await async function(e,t,n){const s=(e=!1)=>new r.CredentialError("VERIFIED_NOT_SAVED","Held credential could not be confirmed in storage",e?{state:Ce}:{}),o=await e.batchPut([{key:t,value:n}]).catch(()=>{});if(!0!==o?.ok)throw s(void 0!==o&&_e(o));const a=await e.get(t).catch(()=>{});if(void 0!==a&&!a.ok&&_e(a))throw s(!0);const d=!0===a?.ok?a.data.data:void 0;if(!Ne(d)||d.recordId!==n.recordId||d.credentialDigest!==n.credentialDigest||d.credential!==n.credential||!(0,i.pkhPrincipalsEqual)(d.ownerDid,n.ownerDid))throw s();return d}(e.kv,be(n,d),c);return{record:l,receipt:await Le(l),verified:s}}async function xe(e,t,i,n,s){const o=await e.get(t);if(!o.ok&&_e(o))throw new r.CredentialError("PERMISSION_DENIED",ve);return Pe(o.ok?o.data.data:void 0,t,i,n,s)}async function Pe(e,t,n,s,o){if(!Ne(e))return{kind:"invalid"};if(!(0,i.pkhPrincipalsEqual)(e.ownerDid,n))return{kind:"invalid"};const a=await(0,r.canonicalDigest)(e.credential),d=await(0,r.canonicalDigest)({credentialDigest:a,holderDid:n});if(e.credentialDigest!==a||e.recordId!==d||t!==be(n,d))return{kind:"invalid"};let c;try{c=(0,i.verifyHeldEmailCredential)(e.credential,qe(s,o,n))}catch(e){if(!(e instanceof i.HeldCredentialError)||"bad-config"===e.code)throw e;return{kind:"expired"===e.code?"expired":"invalid"}}const l=c.claims.email;return"string"!=typeof l?{kind:"invalid"}:{kind:"verified",email:l,match:{record:e,verified:c,recordId:d,email:l,issuedAt:c.issuedAt,expiresAt:c.expiresAt,issuer:c.issuer}}}class Fe extends r.CredentialError{}async function ke(e,t){const i=[];let n;for(let s=0;s<Ae;s+=1){const s=await e.list(void 0===n?{prefix:t}:{prefix:t,cursor:n});if(!s.ok){if(_e(s))throw new r.CredentialError("PERMISSION_DENIED",ve);return}if(i.push(...s.data.keys),!s.data.truncated)return[...new Set(i)];const o=s.data.nextCursor;if(void 0===o||""===o)throw new r.CredentialError("VERIFICATION_FAILED","Held listing is truncated without a continuation cursor");n=o}throw new Fe("VERIFICATION_FAILED","Held listing exceeds the page limit")}async function Ve(e){const t=e.now??new Date,r=Oe(e.ownerDid),i=await ke(e.kv,Re(r));if(void 0===i)return;const n=e.email.replace(/[A-Z]+/g,e=>e.toLowerCase());let s;for(const o of i){const i=await xe(e.kv,o,r,e,t);if("verified"!==i.kind||i.email!==n)continue;const a=i.match.verified.expiresAt.getTime();me(i.match.verified.expiresAt,t)&&(void 0===s||a>s.verified.expiresAt.getTime())&&(s=i.match)}return s}async function He(e){const t=e.now??new Date,n=Oe(e.ownerDid),s=await ke(e.kv,Re(n));if(void 0===s)throw new r.CredentialError("OFFLINE","Held credentials could not be listed");const o=[];for(const a of s){const s=await e.kv.get(a);if(!s.ok){if("error"in s&&s.error.code===Se)continue;if(_e(s))throw new r.CredentialError("PERMISSION_DENIED",ve);throw new r.CredentialError("OFFLINE","A held credential could not be read")}let d;try{d=await Pe(s.data.data,a,n,e,t)}catch(e){if(e instanceof i.HeldCredentialError&&"bad-config"===e.code)throw e;continue}"verified"===d.kind&&me(d.match.verified.expiresAt,t)&&o.push(d.match)}return o.sort((e,t)=>{const r=t.issuedAt.getTime()-e.issuedAt.getTime();return 0!==r?r:e.recordId<t.recordId?-1:e.recordId>t.recordId?1:0})}const je="tinycloud.email-held/v1",Be="opencredentials.email/v1",Me=3e5;class Ke extends Error{constructor(e,t){super(t),this.retryable=!1,this.name="HeldSourceError",this.code=e}}const $e="Saved held credentials list is too long to read; clear old ones";async function Qe(e){return async function(e,t){const{kv:s,address:o,holder:a,sessionDid:d,getCode:c,pendingStore:l,fetch:u,signal:p,now:f,allowHeldProfile:h,...E}=e,w=f??(()=>new Date),g=Oe(a.did);if(void 0!==d&&!(0,i.pkhPrincipalsEqual)(d,g))throw new r.CredentialError("HOLDER_MISMATCH","Held acquisition holder must be the session account");const I=!0===h;let D;try{D=await async function(e,t,n,s,o){const a=s.trim().replace(/[A-Z]+/g,e=>e.toLowerCase()),d=async()=>function(e){let t;for(const r of e)(void 0===t||r.expiresAt.getTime()>t.expiresAt.getTime())&&(t=r);return t}((await async function(e,t,n,s){try{return await He({...t,kv:e,ownerDid:n,now:s})}catch(e){if(e instanceof r.CredentialError||e instanceof i.HeldCredentialError)throw e;throw new r.CredentialError("OFFLINE","Held credentials could not be read",{cause:e})}}(e,t,n,new Date(o().getTime()+Me))).filter(e=>e.email===a));try{return await d()}catch(e){if(!(e instanceof Fe))throw e}try{return await async function(e){const t=e.now??new Date,i=Oe(e.ownerDid),n=await ke(e.kv,Re(i));if(void 0===n)return[];const s=[],o=new Map;for(const r of n){const n=await xe(e.kv,r,i,e,t);if("invalid"===n.kind)continue;if("expired"===n.kind){s.push(r);continue}const a={key:r,recordId:n.match.record.recordId,expiresAt:n.match.verified.expiresAt.getTime()},d=o.get(n.email);if(void 0===d){o.set(n.email,a);continue}const c=a.expiresAt>d.expiresAt||a.expiresAt===d.expiresAt&&a.recordId>d.recordId;o.set(n.email,c?a:d),s.push(c?d.key:a.key)}const a=[];for(const t of s){const i=await e.kv.delete(t);if(!i.ok&&_e(i))throw new r.CredentialError("PERMISSION_DENIED",Te);i.ok&&a.push(t)}return a}({...t,kv:e,ownerDid:n,now:o()}),await d()}catch(e){if(e instanceof Fe)throw new Ke("held-store-listing-limit",$e);throw e}}(s,E,g,o,w)}catch(e){if(I||!(e instanceof r.CredentialError)||"OFFLINE"!==e.code&&"PERMISSION_DENIED"!==e.code)throw e}if(void 0!==D)return{credential:D.record.credential,holderDid:g,expiresAt:D.verified.expiresAt};I&&function(e,t){const s=()=>new r.CredentialError("VERIFICATION_FAILED","The issuer policy does not accept the held credential issuer"),{issuerDid:o,issuerKid:a}=n;if(!Array.isArray(e.acceptedIssuers)||!e.acceptedIssuers.some(e=>e.issuerDid===o&&(void 0===e.kid||e.kid===a)))throw s();if(!i.IssuerSet.is(e.issuerSet))throw s();const d=e.issuerSet.resolveIssuer(o,a),c=t.getTime();if(!d||!d.vcts.includes(Be)||!d.profiles.includes(je)||c<d.notBefore||null!==d.retiredAt&&c>=d.retiredAt||null!==d.notAfter&&c>=d.notAfter)throw s()}(E,w());const m=await t({address:o,holder:a,profile:je,getCode:c,pendingStore:Je(l,g,w),fetch:u,signal:p,now:w,allowHeldProfile:h});if("issued"!==m.status)throw new r.CredentialError("PROOF_REJECTED","Held acquisition did not issue a credential");const A=m.result.envelope.credential,y=w().getTime(),S=function(e){try{const t=JSON.parse((new TextDecoder).decode((0,r.decodeBase64Url)(e.split("~")[0].split(".")[1]))),i="object"==typeof t&&null!==t&&"iat"in t?t.iat:void 0;if("number"==typeof i&&Number.isSafeInteger(i))return 1e3*i}catch{}throw new r.CredentialError("VERIFICATION_FAILED","Issued credential is not readable")}(A);if(S-y>Me)throw new r.CredentialError("VERIFICATION_FAILED","client clock is more than 5 minutes behind the issuer");let v;try{v=await Ue({...E,kv:s,ownerDid:g,sdJwt:A,now:new Date(Math.max(y,S))})}catch(e){const t=e instanceof r.CredentialError&&e.details.state===Ce;throw new r.CredentialError("VERIFIED_NOT_SAVED","Verified held credential could not be stored",t?{state:Ce}:{})}return{credential:A,holderDid:g,expiresAt:v.verified.expiresAt}}(e,Q)}function Je(e,t,r){if(void 0===e)return;const n=e=>void 0!==e&&e.profile===je&&(0,i.pkhPrincipalsEqual)(e.holderDid,t);return{async findLive(t,r){const i=await e.findLive(t,r);return n(i)?i:void 0},put:t=>e.put(t),async delete(t){n(await e.get(t,r()))&&await e.delete(t)},async get(t,r){const i=await e.get(t,r);return n(i)?i:void 0}}}module.exports=t})();
|
|
1
|
+
(()=>{"use strict";var e={d:(t,r)=>{for(var i in r)e.o(r,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:r[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};e.r(t),e.d(t,{EmailProofError:()=>x,OpenCredentialsHttpTransport:()=>h,acquireEmailProof:()=>Q,acquireHeldCredential:()=>Ge,completeEmailProof:()=>K,createAccountHolderSigner:()=>Ie,createEd25519HolderSigner:()=>P,createMemoryEmailProofPendingStore:()=>H,deleteHeldCredential:()=>Me,findHeldCredential:()=>je,interpretCredentialFlow:()=>c,listHeldEmailCredentials:()=>Be,probeHeldStoreAccess:()=>Ke,requestEmailProofCode:()=>M,storeHeldCredential:()=>Pe,verifyStoredEmailProof:()=>re});const r=require("@tinycloud/sdk-core"),i=require("@tinycloud/sdk-core/held-credentials");var n=Object.freeze({witnessOrigin:"https://witness.credentials.org",issuerDid:"did:web:issuer.credentials.org",issuerKid:"did:web:issuer.credentials.org#controller",issuerX:"eEJI4xEobto4HtQ7Pg9R1vBOwcpfGRTlXDG5QfqLnGQ",descriptorDigest:"1tg-qphmKBVtNwzVg9xyz-xxqt_xtMXAsQyXw46m8S0"}),s=Object.freeze({type:r.ACCOUNT_HOLDER_BINDING_DOMAIN,protocol:"tinycloud.credentials/acquisition/v1",profile:"tinycloud.email-held/v1",profileVersion:1,descriptorDigest:"dc3_DuvzipXwYkTfjKqTaK1c3VS0YSPnaBsYSQriC0w",issuer:n.issuerDid,issuerKid:n.issuerKid,audience:"tinycloud://credentials",openerOrigin:"https://localhost",completionOrigin:"https://localhost",completionContext:"sdk-acquisition",credentialLifetimeSeconds:31536e3}),o=6e5,a=()=>new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was substituted"),d=(e,t)=>new Promise((r,i)=>{const n=setTimeout(r,e);t?.addEventListener("abort",()=>{clearTimeout(n),i(new DOMException("Aborted","AbortError"))},{once:!0})});async function c(e){const t="account_is_subject"===e.descriptor.subjectRelationship;if(t&&!0!==e.allowAccountSubject)throw new r.CredentialError("UNSUPPORTED_PROFILE","The held credential profile requires an explicit opt-in");const i=new Map(e.descriptor.steps.map(e=>[e.type,e])),n=new Set;let c="";const l=async t=>{const i=(0,r.validateCredentialHolderBinding)(t);if(i.requestId!==e.requestId||i.descriptorDigest!==e.descriptorDigest||i.requirementDigest!==e.requirementDigest||i.holderDid!==e.holderDid||i.issuer!==e.descriptor.issuer.did||i.issuerKid!==e.descriptor.issuer.kid||i.profile!==e.descriptor.profile||i.openerOrigin!==e.openerOrigin||i.completionOrigin!==e.openerOrigin||"tinycloud://credentials"!==i.audience)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was substituted");const n=e.descriptor.holderBinding.alg;if(i.type!==e.descriptor.holderBinding.domain||"EIP191"===n&&!e.transport.challengeNonce)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was substituted");return"EIP191"===n&&await async function(e,t){const{descriptor:i}=t;if("EIP191"!==i.holderBinding.alg||e.type!==i.holderBinding.domain||e.requestId!==t.requestId||e.descriptorDigest!==t.descriptorDigest||e.requirementDigest!==t.requirementDigest||e.holderDid!==t.holderDid||e.issuer!==i.issuer.did||e.issuerKid!==i.issuer.kid||e.profile!==i.profile||e.openerOrigin!==t.openerOrigin||e.completionOrigin!==t.openerOrigin||e.audience!==s.audience||e.completionContext!==s.completionContext||e.type!==s.type||e.protocol!==s.protocol||e.profile!==s.profile||e.profileVersion!==s.profileVersion||e.descriptorDigest!==s.descriptorDigest||e.issuer!==s.issuer||e.issuerKid!==s.issuerKid||e.openerOrigin!==s.openerOrigin||e.completionOrigin!==s.completionOrigin||e.credentialLifetimeSeconds!==s.credentialLifetimeSeconds)throw a();if(void 0===t.challengeNonce||e.challengeNonce!==t.challengeNonce)throw a();if(e.normalizedClaimsDigest!==await(0,r.canonicalDigest)(t.requirement.claims))throw a();const n=Date.parse(e.expiresAt);if(void 0===t.serverExpiresAt||n!==Date.parse(t.serverExpiresAt)||Date.parse(e.issuedAt)!==n-o)throw a()}(i,{descriptor:e.descriptor,requirement:e.requirement,requestId:e.requestId,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,holderDid:e.holderDid,openerOrigin:e.openerOrigin,challengeNonce:e.transport.challengeNonce(e.requestId),serverExpiresAt:e.expiresAt}),i},u=async()=>{t&&void 0===e.transport.signedBinding?.(e.requestId)&&await l(await e.transport.holderBinding(e.requestId,e.verifier,e.signal))};for(;;){e.signal?.throwIfAborted();const t=await e.transport.state(e.requestId,e.verifier,e.signal);if(t.requestId!==e.requestId)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential request identity changed");if("expired"===t.state)throw new r.CredentialError("REQUEST_EXPIRED","Credential request expired",{state:t.state,correlationId:t.correlationId});if("canceled"===t.state)throw new r.CredentialError("CANCELED","Credential request was canceled",{state:t.state,correlationId:t.correlationId});if("issuer_unready"===t.state)throw new r.CredentialError("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:t.retryAfterMs,state:t.state,correlationId:t.correlationId});if("complete"===t.state)return void await u();if("ready_to_issue"===t.state||"issued"===t.state){await u(),"ready_to_issue"!==t.state||n.has("issue")?await(e.onWait?.()??d(t.retryAfterMs??50,e.signal)):(await e.transport.issue(e.requestId,e.verifier,e.signal),n.add("issue"));continue}const s=t.nextStep;if(!s){await(e.onWait?.()??d(t.retryAfterMs??50,e.signal));continue}const o=i.get(s.type);if(s.id!==s.type||!o||o.type!==s.type||o.version!==s.version)throw new r.CredentialError("REQUEST_SUBSTITUTED","Server selected an undeclared credential step");if(n.has(s.id)||t.transitionId===c)await(e.onWait?.()??d(t.retryAfterMs??50,e.signal));else{if(c=t.transitionId,"holder_signature"===s.type){e.onProgress?.({state:"signing",stepId:s.id,correlationId:t.correlationId});const i=await l(await e.transport.holderBinding(e.requestId,e.verifier,e.signal)),n=e.descriptor.holderBinding.alg;if("EIP191"===n!=("EIP191"===e.signing.holderKey?.alg))throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was substituted");const o=(0,r.holderBindingSigningBytes)(i);let a=await(e.signing.autoSign?.(i,o,e.signal));if(void 0===a){if(!e.signing.requestApproval)throw new r.CredentialError("SIGNATURE_REJECTED","OpenKey approval is required");try{a=await e.signing.requestApproval(i,o,e.signal)}catch(e){if(e instanceof r.CredentialError)throw e;throw new r.CredentialError("SIGNATURE_REJECTED","OpenKey approval was rejected",{cause:e})}}if(!(a instanceof Uint8Array)||0===a.length)throw new r.CredentialError("SIGNATURE_REJECTED","OpenKey signature is invalid");await e.transport.submitHolderSignature(e.requestId,e.verifier,"EIP191"===n?`0x${Array.from(a,e=>e.toString(16).padStart(2,"0")).join("")}`:(0,r.encodeBase64Url)(a),e.signal,e.signing.holderKey)}else{e.onProgress?.({state:"collect_input"===s.type?"collecting":"proving",stepId:s.id,correlationId:t.correlationId});const i=e.handlers?.[s.type],n=e.proofHandler;if(!i&&!n){await(e.onWait?.()??d(t.retryAfterMs??50,e.signal));continue}if(!0===s.constraints.challengeRequired&&await e.transport.beginStep(e.requestId,e.verifier,s.type,e.signal),i){const t=await i({descriptor:e.descriptor,requirement:e.requirement,stepId:s.id,constraints:s.constraints,signal:e.signal});await e.transport.submitStep(e.requestId,e.verifier,s.id,t,e.signal)}else{let t;for(let i=1;;i+=1){const o=await n({stepId:s.id,constraints:s.constraints,display:{title:e.descriptor.display.title,description:e.descriptor.display.description,consent:e.descriptor.display.consent,progressLabel:e.descriptor.accessibility.progressLabel,errorLiveRegion:e.descriptor.accessibility.errorLiveRegion},inputs:e.descriptor.inputs.map(({id:e,label:t,schema:r})=>({id:e,label:t,schema:r})),...void 0===t?{}:{feedback:t},signal:e.signal});try{await e.transport.submitStep(e.requestId,e.verifier,s.id,o,e.signal);break}catch(n){if(!(n instanceof r.CredentialError)||"PROOF_REJECTED"!==n.code)throw n;const o=e.descriptor.lifecycle.maxProofAttempts-i;if("mailbox_otp"!==s.type||o<=0)throw new r.CredentialError("VERIFICATION_FAILED","The proof was not accepted",{state:o<=0?"proof_attempts_exhausted":"proof_rejected",cause:n});t={kind:"rejected",attemptsRemaining:o}}}}}n.add(s.id)}}}function l(e,t){if("object"!=typeof e||null===e||Array.isArray(e))throw new r.CredentialError("VERIFICATION_FAILED",`${t} is invalid`);return e}function u(e,t){if("string"!=typeof e||!/^[A-Za-z0-9_-]{16,128}$/.test(e))throw new r.CredentialError("REQUEST_SUBSTITUTED",`${t} is invalid`);return e}function p(e,t){if("string"!=typeof e||!Number.isFinite(Date.parse(e)))throw new r.CredentialError("VERIFICATION_FAILED",`${t} is invalid`);return new Date(e).toISOString()}var f=new Set(["REQUEST_EXPIRED","ISSUER_UNREADY","UNSUPPORTED_PROFILE","UNSUPPORTED_VERSION","SIGNATURE_REJECTED"]),h=class{constructor(e,t=globalThis.fetch.bind(globalThis),i={}){if(this.descriptor=e,this.fetchFn=t,this.options=i,this.nonces=new Map,this.bindings=new Map,"account_is_subject"===e.subjectRelationship&&!0!==i.allowAccountSubject)throw new r.CredentialError("UNSUPPORTED_PROFILE","The held credential profile requires an explicit opt-in")}url(e,t){return new URL((0,r.credentialEndpointPath)(e,t),this.descriptor.issuer.origin).href}async request(e,t){let i;try{const r={method:t.method??"GET",credentials:"omit",cache:"no-store",redirect:"error",referrerPolicy:"no-referrer",signal:t.signal,headers:{accept:"application/json",...void 0===t.body?{}:{"content-type":"application/json"},...void 0===t.verifier?{}:{authorization:`Bearer ${t.verifier}`}},...void 0===t.body?{}:{body:JSON.stringify(t.body)}};i=await this.fetchFn(this.url(e,t.id),r)}catch(e){if(e instanceof DOMException&&"AbortError"===e.name)throw new r.CredentialError("CANCELED","Credential acquisition was canceled",{cause:e});throw new r.CredentialError("OFFLINE","OpenCredentials is unavailable",{cause:e})}if(!i.ok){let e;try{e=await i.json()}catch{e=void 0}const t=function(e,t,i){if("object"!=typeof e||null===e||Array.isArray(e))return;const n=e;if("code,correlationId,recoverable,state,type"!==Object.keys(n).sort().join(",")||"tinycloud.credentials/error/v1"!==n.type||"string"!=typeof n.code||"boolean"!=typeof n.recoverable||"string"!=typeof n.state||"string"!=typeof n.correlationId)return;if("PROOF_REJECTED"===n.code)return n.recoverable?new r.CredentialError("PROOF_REJECTED","The proof was not accepted",{state:n.state,correlationId:n.correlationId}):new r.CredentialError("VERIFICATION_FAILED","The proof attempt limit was reached",{state:"proof_attempts_exhausted",correlationId:n.correlationId});if("RATE_LIMITED"===n.code)return new r.CredentialError("ISSUER_UNREADY","Too many verification codes were requested",{state:"rate_limited",correlationId:n.correlationId,retryAfterMs:1e3*Number(t.headers.get("retry-after"))||void 0,recoverable:i?n.recoverable:void 0});if("CHALLENGE_EXPIRED"===n.code)return new r.CredentialError("REQUEST_EXPIRED","The credential challenge expired",{state:n.state,correlationId:n.correlationId,recoverable:i?n.recoverable:void 0});if("DESCRIPTOR_MISMATCH"===n.code&&(n.code="UNSUPPORTED_PROFILE"),!f.has(n.code))return;const s=n.code;return new r.CredentialError(s,`OpenCredentials rejected the request: ${s}`,{state:n.state,correlationId:n.correlationId,retryAfterMs:1e3*Number(t.headers.get("retry-after"))||void 0,recoverable:i?n.recoverable:void 0})}(e,i,!0===this.options.honorServerRecoverable);if(t)throw t;if(410===i.status)throw new r.CredentialError("REQUEST_EXPIRED","Credential request expired");if(409===i.status)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential request was replayed or substituted");if(503===i.status)throw new r.CredentialError("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:1e3*Number(i.headers.get("retry-after"))||void 0});throw new r.CredentialError("VERIFICATION_FAILED","OpenCredentials rejected the request")}if(204!==i.status)try{return await i.json()}catch(e){throw new r.CredentialError("VERIFICATION_FAILED","OpenCredentials response is invalid",{cause:e})}}async create(e){const t=l(await this.request("request",{method:"POST",body:{protocol:e.descriptor.protocol,profile:e.descriptor.profile,profileVersion:e.descriptor.profileVersion,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,holderDid:e.holderDid,inputs:e.inputs??e.requirement.claims,audience:s.audience,openerOrigin:e.openerOrigin,completionOrigin:e.openerOrigin,completionContext:s.completionContext,completionVerifierChallenge:e.completionVerifierChallenge},signal:e.signal}),"create response");if("tinycloud.credentials/acquisition-request/v1"!==t.type||t.protocol!==e.descriptor.protocol||"challenge"!==t.next||"challenge"!==t.endpoint)throw new r.CredentialError("VERIFICATION_FAILED","create response is invalid");const i=u(t.requestId,"requestId");return{requestId:i,locator:i,expiresAt:p(t.expiresAt,"expiresAt"),correlationId:i}}challengeNonce(e){return this.nonces.get(e)}signedBinding(e){return this.bindings.get(e)}proofStep(){return this.descriptor.steps.some(e=>"mailbox_otp"===e.type)?"mailbox_otp":"collect_input"}async state(e,t,i){const n=l(await this.request("state",{id:e,verifier:t,signal:i}),"state response");if("tinycloud.credentials/acquisition-state/v1"!==n.type||n.requestId!==e||n.profile!==this.descriptor.profile||1!==n.profileVersion)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential state response is substituted");const s={type:"OpenCredentialsAcquisitionState",version:1,requestId:e,transitionId:`${String(n.state)}:${String(n.resultPreviouslyRead??!1)}`,correlationId:e};if("challenge_required"===n.state){const e=this.proofStep();return{...s,state:"pending",nextStep:{id:e,type:e,version:1,constraints:{challengeRequired:!0}}}}if("account_is_subject"===this.descriptor.subjectRelationship&&("proof_required"===n.state||"holder_binding_required"===n.state||"holder_signature_required"===n.state||"ready_to_issue"===n.state||"issued"===n.state)){const t=n.challengeNonce,i=this.nonces.get(e);if("string"!=typeof t||""===t||void 0!==i&&i!==t)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential challenge nonce is missing or changed");this.nonces.set(e,u(t,"challengeNonce"))}if("proof_required"===n.state){const t=this.proofStep();return"account_is_subject"!==this.descriptor.subjectRelationship&&this.nonces.set(e,u(n.challengeNonce,"challengeNonce")),{...s,state:"pending",nextStep:{id:t,type:t,version:1,constraints:{}}}}if("holder_binding_required"===n.state||"holder_signature_required"===n.state)return{...s,state:"pending",nextStep:{id:"holder_signature",type:"holder_signature",version:1,constraints:{}}};if("ready_to_issue"===n.state)return{...s,state:"ready_to_issue"};if("issued"===n.state)return{...s,state:"complete"};throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential state is unsupported")}async beginStep(e,t,i,n){const s=this.proofStep();if(i!==s)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential challenge step is substituted");const o=l(await this.request("challenge",{id:e,verifier:t,method:"POST",body:{step:s,stepVersion:1},signal:n}),"challenge response");if("tinycloud.credentials/challenge/v1"!==o.type||o.step!==s||1!==o.stepVersion)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential challenge is substituted");this.nonces.set(e,u(o.challengeNonce,"challengeNonce"))}async submitStep(e,t,i,n,s){const o=this.proofStep();if(i!==o)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential proof step is substituted");const a=this.nonces.get(e);if(!a)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential challenge is missing");await this.request("proof",{id:e,verifier:t,method:"POST",body:{step:o,stepVersion:1,challengeNonce:a,proof:n},signal:s})}async holderBinding(e,t,i){const n=l(await this.request("holder_binding",{id:e,verifier:t,signal:i}),"holder binding response");if("tinycloud.credentials/holder-binding-request/v1"!==n.type||n.signingDomain!==this.descriptor.holderBinding.domain||n.alg!==this.descriptor.holderBinding.alg||"string"!=typeof n.canonical)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding response is invalid");const s=(0,r.validateCredentialHolderBinding)(n.binding);if(s.type!==n.signingDomain)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding type does not match its signing domain");if((0,r.encodeBase64Url)((0,r.holderBindingCanonicalBytes)(s))!==n.canonical)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding canonical bytes were substituted");return this.bindings.set(e,s),s}async submitHolderSignature(e,t,i,n,s){const o=this.bindings.get(e);if(!o)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was not retrieved");if("EIP191"===this.descriptor.holderBinding.alg&&!s)throw new r.CredentialError("REQUEST_SUBSTITUTED","An account holder must name its key and algorithm");const a=s?.alg??"EdDSA",d=s?.kid??`${o.holderDid}#${o.holderDid.replace("did:key:","")}`;await this.request("holder_signature",{id:e,verifier:t,method:"POST",body:{alg:a,kid:d,signature:i},signal:n})}async issue(e,t,r){await this.request("issue",{id:e,verifier:t,method:"POST",signal:r})}async result(e,t,i){const n=l(await this.request("result",{id:e,verifier:t,signal:i}),"result response");if("tinycloud.credentials/result/v1"!==n.type||n.protocol!==this.descriptor.protocol||n.profile!==this.descriptor.profile||1!==n.profileVersion||"vc+sd-jwt"!==n.format||n.descriptorDigest!==await(0,r.canonicalDigest)(this.descriptor)||n.issuer!==this.descriptor.issuer.did||n.issuerKid!==this.descriptor.issuer.kid||"string"!=typeof n.credential||await(0,r.sha256Base64Url)(n.credential)!==n.credentialDigest)throw new r.CredentialError("VERIFICATION_FAILED","Issued result metadata is invalid");const s=l(n.holderBinding,"result holder binding");if(n.subject!==s.did||s.signingDomain!==this.descriptor.holderBinding.domain)throw new r.CredentialError("HOLDER_MISMATCH","Issued holder binding is invalid");const o=l(n.claims,"result claims"),a={};for(const[e,t]of Object.entries(o)){if("string"!=typeof t)throw new r.CredentialError("VERIFICATION_FAILED","Issued claims are invalid");a[e]=t}const d=l(n.validity,"result validity"),c=function(e){const t=e.split("~",1)[0]?.split(".")[1];if(!t)throw new r.CredentialError("VERIFICATION_FAILED","Issued SD-JWT is invalid");try{return l(JSON.parse((new TextDecoder).decode((0,r.decodeBase64Url)(t))),"SD-JWT payload")}catch(e){if(e instanceof r.CredentialError)throw e;throw new r.CredentialError("VERIFICATION_FAILED","Issued SD-JWT is invalid",{cause:e})}}(n.credential);if("string"!=typeof c.jti)throw new r.CredentialError("VERIFICATION_FAILED","Credential id is invalid");const u=p(d.issuedAt,"issuedAt"),f=p(d.expiresAt,"expiresAt"),h=l(n.status,"result status");if("none"!==h.type||h.freshnessSeconds!==this.descriptor.status.freshnessSeconds)throw new r.CredentialError("VERIFICATION_FAILED","Credential status is invalid");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:n.issuer,issuerKid:n.issuerKid,subjectDid:n.subject,holderDid:n.subject,claims:a,claimsDigest:await(0,r.canonicalDigest)(a),descriptorDigest:n.descriptorDigest,credentialId:c.jti,issuedAt:u,notBefore:u,expiresAt:f,status:{method:"none",freshnessSeconds:h.freshnessSeconds},credential:n.credential}}async issuerMetadata(e){return await this.request("issuer_metadata",{signal:e})}async checkStatus(e,t){return"none"===e.method&&e.freshnessSeconds===this.descriptor.status.freshnessSeconds}},E={id:"opencredentials.email/v1",version:1},w=9e5,g=`${n.witnessOrigin}/.well-known/opencredentials`,I=[{kid:n.issuerKid,alg:"EdDSA",jwk:{kty:"OKP",crv:"Ed25519",x:n.issuerX},validFrom:"2020-01-01T00:00:00Z",validUntil:"2100-01-01T00:00:00Z"}],D="tinycloud.email-proof/v1",m={"tinycloud.email-proof/v1":{descriptorDigest:n.descriptorDigest,requiredStep:"mailbox_otp",enabled:!0},"tinycloud.email-held/v1":{descriptorDigest:s.descriptorDigest,requiredStep:"mailbox_otp",enabled:!1}},A=s.openerOrigin,y="tinycloud.email-held/v1",S="blockchainAccountId",v=31536e3,T=6e5,C=3e5,_=6e4,O="did:key:",R=/^did:key:z6Mk[^#]+$/,b=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,N=Symbol.for("nodejs.util.inspect.custom"),q={ADDRESS_INVALID:!1,HOLDER_INVALID:!1,CODE_INVALID:!0,RATE_LIMITED:!0,ISSUER_UNAVAILABLE:!0,NETWORK:!0,PROFILE_UNAVAILABLE:!1,CODE_REJECTED:!0,CODE_ATTEMPTS_EXHAUSTED:!1,SIGNATURE_REJECTED:!0,CREDENTIAL_INVALID:!1,SESSION_EXPIRED:!1,SESSION_INVALID:!1,CLIENT_CLOCK_SKEW:!1,CANCELED:!1,FAILED:!1},L={ADDRESS_INVALID:"Email address is invalid.",HOLDER_INVALID:"Holder must be a did:key Ed25519 identifier.",CODE_INVALID:"Verification code must be 8 digits.",ISSUER_UNAVAILABLE:"Email verification is unavailable right now.",NETWORK:"Could not reach the email verification service.",PROFILE_UNAVAILABLE:"The witness does not offer the email verification profile.",CODE_REJECTED:"Verification code was not accepted.",CODE_ATTEMPTS_EXHAUSTED:"Too many wrong codes. Request a new code.",SIGNATURE_REJECTED:"Holder signature was rejected.",CREDENTIAL_INVALID:"Issued credential failed verification.",SESSION_EXPIRED:"Email verification request expired. Request a new code.",SESSION_INVALID:"Email verification request is no longer valid. Request a new code.",CLIENT_CLOCK_SKEW:"Your device clock is more than 5 minutes behind. Correct it and try again.",CANCELED:"Email verification was canceled.",FAILED:"Email verification failed."},U="This SDK build doesn't enable the email verification profile.",x=class extends Error{constructor(e,t,r,i=q[t],n){super(n??("RATE_LIMITED"===t?function(e){const t="Too many codes were requested for this address.";if(void 0===e||!Number.isFinite(e)||e<=0)return`${t} Try again in about an hour.`;const r=Math.max(1,Math.ceil(e/6e4));return`${t} Try again in ${r} ${1===r?"minute":"minutes"}.`}(r):L[t])),this.name="EmailProofError",this.step=e,this.code=t,this.retryAfterMs=r,this.recoverable=i}};function P(e,t){const r=e.indexOf("#"),i=-1===r?e:e.slice(0,r);if(-1!==r&&e.slice(r+1)!==i.slice(O.length))throw new x("request","HOLDER_INVALID");if(!R.test(i))throw new x("request","HOLDER_INVALID");return{did:i,alg:"EdDSA",kid:G(i),sign:t}}function F(e){const t={type:e.type,version:e.version,profile:e.profile,address:e.address,requestId:e.requestId,holderDid:e.holderDid,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,openerOrigin:e.openerOrigin,createdAt:e.createdAt,expiresAt:e.expiresAt,...void 0===e.serverExpiresAt?{}:{serverExpiresAt:e.serverExpiresAt}},r={...t};return k(r,"verifier",e.verifier),k(r,"toJSON",()=>({...t})),k(r,N,()=>({...t,verifier:"[redacted]"})),Object.freeze(r)}function k(e,t,r){Object.defineProperty(e,t,{value:r,enumerable:!1,writable:!1,configurable:!1})}function V(e){return Math.min(Date.parse(e.expiresAt),Date.parse(e.createdAt)+w)}function H(){const e=new Map,t=t=>{for(const[r,i]of e)V(i)<=t.getTime()&&e.delete(r)};return{async findLive(r,i){let n;t(i);for(const t of e.values())t.address===r&&(!n||Date.parse(t.createdAt)>Date.parse(n.createdAt))&&(n=t);return n},async put(t){e.set(t.requestId,t)},async delete(t){e.delete(t)},get:async(r,i)=>(t(i),e.get(r))}}var j=class extends Error{},B=async()=>{throw new j("code requested")};async function M(e){const t=e.profile??D;Z(t,"request",e.allowHeldProfile);const i=t===y;i&&W(e.holder,"request",t);const n=J(e.address,t);i||W(e.holder,"request",t);const s=e.now??(()=>new Date),o=e.signal??AbortSignal.timeout(_),a=Y(n,t),d=await(0,r.credentialRequirementDigest)(a),l=await ee(t,a,{fetch:e.fetch,signal:o},"request",e.allowHeldProfile),u=await(0,r.canonicalDigest)(l),p=(0,r.encodeBase64Url)(crypto.getRandomValues(new Uint8Array(32))),f=new h(l,e.fetch,{honorServerRecoverable:!0,...i?{allowAccountSubject:!0}:{}}),E=s().getTime();let g;try{g=await f.create({descriptor:l,descriptorDigest:u,requirement:a,requirementDigest:d,holderDid:e.holder.did,openerOrigin:A,completionVerifierChallenge:await(0,r.sha256Base64Url)(p),signal:o})}catch(e){throw ne(e,"request",o)}const I=Date.parse(g.expiresAt);if(!Number.isFinite(I))throw new x("request","FAILED");const m=I-T;if(i&&m-s().getTime()>C)throw new x("request","CLIENT_CLOCK_SKEW");const S=F({type:"TinyCloudEmailProofPending",version:1,profile:t,address:n,requestId:g.requestId,verifier:p,holderDid:e.holder.did,descriptorDigest:u,requirementDigest:d,openerOrigin:A,createdAt:new Date(E).toISOString(),expiresAt:new Date(i?E+Math.min(I-m,w):Math.min(I,E+w)).toISOString(),...i?{serverExpiresAt:g.expiresAt}:{}});try{await c({descriptor:l,...i?{allowAccountSubject:!0}:{},requirement:a,requestId:g.requestId,verifier:p,holderDid:e.holder.did,descriptorDigest:u,requirementDigest:d,openerOrigin:A,...i?{expiresAt:g.expiresAt}:{},transport:f,signing:ie(e.holder,i),handlers:{mailbox_otp:B},signal:o})}catch(e){if(e instanceof j)return S;throw ne(e,"request",o)}throw new x("request","FAILED")}async function K(e){return $(e,I)}async function $(e,t){const{pending:s}=e,o=e.now??(()=>new Date);if(!function(e){if("object"!=typeof e||null===e)return!1;const t=e;return"TinyCloudEmailProofPending"===t.type&&1===t.version&&t.openerOrigin===A&&[t.profile,t.address,t.requestId,t.verifier,t.holderDid,t.descriptorDigest,t.requirementDigest,t.openerOrigin,t.createdAt,t.expiresAt].every(e=>"string"==typeof e)&&Number.isFinite(Date.parse(t.createdAt))&&Number.isFinite(Date.parse(t.expiresAt))}(s))throw new x("session","SESSION_INVALID");Z(s.profile,"session",e.allowHeldProfile);const a=s.profile===y;if(a&&!Number.isFinite(Date.parse(s.serverExpiresAt??"")))throw new x("session","SESSION_INVALID");if(V(s)<=o().getTime())throw new x("session","SESSION_EXPIRED");if(!/^\d{8}$/.test(e.code))throw new x("code","CODE_INVALID");if(W(e.holder,"code",s.profile),e.holder.did!==s.holderDid)throw new x("session","SESSION_INVALID");const d=e.signal??AbortSignal.timeout(_),l=Y(s.address,s.profile);if(await(0,r.credentialRequirementDigest)(l)!==s.requirementDigest)throw new x("session","SESSION_INVALID");const u=await ee(s.profile,l,{fetch:e.fetch,signal:d},"session",e.allowHeldProfile),p=await(0,r.canonicalDigest)(u);if(p!==s.descriptorDigest)throw new x("session","SESSION_INVALID");const f=new h(u,e.fetch,{honorServerRecoverable:!0,...a?{allowAccountSubject:!0}:{}});try{const t=await f.state(s.requestId,s.verifier,d);if(!0===t.nextStep?.constraints.challengeRequired)throw new x("session","SESSION_INVALID");await c({descriptor:u,...a?{allowAccountSubject:!0}:{},requirement:l,requestId:s.requestId,verifier:s.verifier,holderDid:s.holderDid,descriptorDigest:p,requirementDigest:s.requirementDigest,openerOrigin:s.openerOrigin,...a?{expiresAt:s.serverExpiresAt}:{},transport:f,signing:ie(e.holder,a),handlers:{mailbox_otp:async()=>({otp:e.code})},signal:d})}catch(e){throw ne(e,"code",d)}try{const e=await f.result(s.requestId,s.verifier,d);if(a){const a=await async function(e){const{envelope:t,pending:s,descriptor:o}=e,a=e=>new r.CredentialError("VERIFICATION_FAILED",e),d=Date.parse(t.issuedAt),c=e.now().getTime();if(!Number.isFinite(d)||d-c>C)throw a("client clock is more than 5 minutes behind the issuer");const l=e.issuerKeys.find(e=>e.kid===n.issuerKid);if(!l)throw a("no pinned issuer key");const u=(0,i.parseIssuerSet)({format:"tinycloud.credentials-issuers/v1",version:1,issuers:[{issuerDid:n.issuerDid,kid:n.issuerKid,alg:"EdDSA",publicKey:l.jwk.x,vcts:[E.id],profiles:[y],notBefore:"2020-01-01T00:00:00Z",retiredAt:null,notAfter:null}]},{didMethods:{issuer:["web"]}}),p=(0,i.verifyHeldEmailCredential)(t.credential,{now:new Date(Math.max(c,d)),owner:s.holderDid,didMethods:{issuer:["web"]},acceptedIssuers:[{issuerDid:n.issuerDid,kid:n.issuerKid}],issuerSet:u}),f=e.transport.signedBinding(s.requestId),h=Object.keys(t.claims).sort().join(),w=e=>Math.floor(e/1e3);if(t.subjectDid!==s.holderDid||t.holderDid!==s.holderDid||"email,emailDomain"!==h||t.claims.email!==p.claims.email||t.claims.emailDomain!==p.claims.emailDomain||t.claims.email!==s.address||w(Date.parse(t.issuedAt))!==w(p.issuedAt.getTime())||w(Date.parse(t.expiresAt))!==w(p.expiresAt.getTime())||t.descriptorDigest!==e.descriptorDigest||t.profile.id!==y||1!==t.profile.version||t.issuerDid!==n.issuerDid||t.issuerKid!==n.issuerKid||"vc+sd-jwt"!==t.format||"none"!==t.status.method||t.status.freshnessSeconds!==o.status.freshnessSeconds)throw a("issued credential does not match the request");if(f?.type!==o.holderBinding.domain||!("credentialLifetimeSeconds"in f))throw a("signed binding is missing");if(p.credentialId!==f.jti||(p.expiresAt.getTime()-p.issuedAt.getTime())/1e3!==f.credentialLifetimeSeconds)throw a("credential does not match the binding the account signed");return p}({envelope:e,pending:s,descriptor:u,descriptorDigest:p,transport:f,issuerKeys:t,now:o});return{envelope:e,verified:a,credentialId:a.credentialId,issuedAt:a.issuedAt.toISOString(),expiresAt:a.expiresAt.toISOString(),descriptor:u}}const c=await(0,r.verifyIssuedCredential)({envelope:e,descriptor:u,descriptorDigest:p,requirement:l,holderDid:s.holderDid,issuerMetadata:te(t),now:o(),checkStatus:(e,t)=>f.checkStatus(e,t),signal:d});return{envelope:e,verified:c,credentialId:c.credentialId,issuedAt:c.issuedAt,expiresAt:c.expiresAt,descriptor:u}}catch(e){throw ne(e,"credential",d)}}async function Q(e){return async function(e,t){const r=e.profile??D;Z(r,"request",e.allowHeldProfile);const i=J(e.address,r),n=e.now??(()=>new Date),s=e.pendingStore,o=s?await s.findLive(i,n()):void 0;let a=o?.profile===r?o:void 0;if(a&&r===y&&!Number.isFinite(Date.parse(a.serverExpiresAt??"")))throw await(s?.delete(a.requestId).catch(()=>{})),new x("session","SESSION_INVALID");a||(a=await M({...e,address:i}),await(s?.put(a)));const d=F(a);if(!e.getCode)return{status:"code-requested",pending:d};const c=await e.getCode({pending:d});try{const r=await $({...e,pending:a,code:c},t),i=[];if(s)try{await s.delete(a.requestId)}catch{i.push("The pending request could not be deleted after success; it expires at its deadline.")}return{status:"issued",result:r,warnings:i}}catch(e){throw e instanceof x&&e.recoverable||await(s?.delete(a.requestId).catch(()=>{})),e}}(e,I)}function J(e,t){if(t===y)return function(e){const t=()=>new x("request","ADDRESS_INVALID"),r=e.trim();if(/[^\x00-\x7f]/.test(r))throw t();const i=r.toLowerCase(),n=i.split("@");if(i.length<3||i.length>254||2!==n.length||/[^\x21-\x7e]/.test(i))throw t();const[s,o]=n;if(s.length>64||!z.test(s)||s.startsWith("+"))throw t();if(o.length>253||!o.includes(".")||!o.split(".").every(e=>e.length<=63&&X.test(e)))throw t();return i}(e);const r=e.trim();if(r.length>254||!b.test(r))throw new x("request","ADDRESS_INVALID");return r}var z=/^[a-z0-9!#$%&'*+\-/=?^_`{|}~]+(\.[a-z0-9!#$%&'*+\-/=?^_`{|}~]+)*$/,X=/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;function G(e){return`${e}#${e.slice(O.length)}`}function W(e,t,r){if(r===y)return function(e,t){const r=(0,i.parsePkhDid)(e.did),n=null!==r&&"1"===r.chainId?`did:pkh:eip155:1:${(0,i.toChecksumAddress)(r.address)}`:void 0;if(void 0===n||e.did!==n||"EIP191"!==e.alg||e.kid!==`${n}#${S}`)throw new x(t,"HOLDER_INVALID")}(e,t);if(!R.test(e.did)||"EdDSA"!==e.alg||e.kid!==G(e.did))throw new x(t,"HOLDER_INVALID")}function Z(e,t,r){const i=Object.prototype.hasOwnProperty.call(m,e)?m[e]:void 0;if(!i||!i.enabled&&(!0!==r||e!==y))throw new x(t,"PROFILE_UNAVAILABLE",void 0,void 0,U);return i}function Y(e,t){return t===y?(0,r.validateCredentialRequirement)({type:"TinyCloudCredentialRequirement",version:1,profile:{id:t,version:1},credentialType:E,claims:{email:e},maxAgeSeconds:v}):(0,r.createEmailCredentialRequirement)({email:e,profile:{id:t,version:1},credentialType:E})}async function ee(e,t,i,s,o){const a=Z(e,s,o);let d;try{d=await async function(e,t,i={}){let n;try{n=new URL(t)}catch{throw new r.CredentialError("UNSUPPORTED_PROFILE","Discovery URL is invalid")}if("https:"!==n.protocol||!["/.well-known/opencredentials","/v1/credential-types"].includes(n.pathname)||n.search||n.hash)throw new r.CredentialError("UNSUPPORTED_PROFILE","Discovery URL is not an allowed catalog endpoint");const s={credentials:"omit",cache:"no-store",redirect:"error",referrerPolicy:"no-referrer",signal:i.signal};let o;try{o=await(i.fetch??globalThis.fetch.bind(globalThis))(n,s)}catch(e){throw new r.CredentialError("OFFLINE","Credential discovery is unavailable",{cause:e})}if(!o.ok)throw new r.CredentialError(503===o.status?"ISSUER_UNREADY":"OFFLINE","Credential discovery is unavailable");const a=await o.json();if("tinycloud.credentials/catalog/v1"!==a.type||"tinycloud.credentials/acquisition/v1"!==a.protocol||1!==a.catalogVersion||!Array.isArray(a.profiles))throw new r.CredentialError("DESCRIPTOR_INVALID","Credential catalog is invalid");for(const t of a.profiles){if("object"!=typeof t||null===t||Array.isArray(t))continue;const i=t;if(!0===i.supported&&!0===i.enabled&&("ready"===i.readiness||"degraded"===i.readiness))try{const t=(0,r.validateCredentialFlowDescriptor)(i.descriptor);if((0,r.descriptorSatisfiesRequirement)(t,e)&&i.descriptorDigest===await(0,r.canonicalDigest)(t))return t}catch{}}throw new r.CredentialError("UNSUPPORTED_PROFILE","No available credential profile satisfies the requirement")}(t,g,{fetch:i.fetch,signal:i.signal})}catch(e){throw function(e,t,r){return t.aborted&&"TimeoutError"!==t.reason?.name?new x(r,"CANCELED"):ne(e,r,t)}(e,i.signal,s)}if(d.issuer.origin!==n.witnessOrigin||d.issuer.did!==n.issuerDid||!d.steps.some(e=>e.type===a.requiredStep))throw new x(s,"PROFILE_UNAVAILABLE");if(await(0,r.canonicalDigest)(d)!==a.descriptorDigest)throw new x(s,"PROFILE_UNAVAILABLE");return d}function te(e){return{type:"OpenCredentialsIssuerMetadata",version:1,origin:n.witnessOrigin,issuerDid:n.issuerDid,keys:e,cache:{maxAgeSeconds:3600,etag:"pinned"}}}async function re(e){return async function(e,t){const{record:i,requirement:s,holderDid:o}=e,a=i.descriptor;if(i.descriptorDigest!==n.descriptorDigest||await(0,r.canonicalDigest)(a)!==n.descriptorDigest)throw new r.CredentialError("VERIFICATION_FAILED","stored descriptor does not match the pinned descriptor digest");const d={type:"OpenCredentialsIssuedCredential",version:1,protocol:a.protocol,profile:i.profile,credentialType:i.credentialType,schema:i.schema,format:"vc+sd-jwt",issuerDid:i.issuerDid,issuerKid:i.issuerKid,subjectDid:i.subjectDid,holderDid:i.holderDid,claims:i.claims,claimsDigest:i.claimsDigest,descriptorDigest:i.descriptorDigest,credentialId:i.credentialId,issuedAt:i.issuedAt,notBefore:i.notBefore,expiresAt:i.expiresAt,status:i.status,credential:i.credential},c=await(0,r.verifyIssuedCredential)({envelope:d,descriptor:a,descriptorDigest:n.descriptorDigest,requirement:s,holderDid:o,issuerMetadata:te(t),now:e.now,checkStatus:async e=>"none"===e.method&&e.freshnessSeconds===a.status.freshnessSeconds,signal:e.signal});if(i.holderDid!==o||i.ownerDid!==o)throw new r.CredentialError("HOLDER_MISMATCH","stored record belongs to another holder");if(i.credentialDigest!==c.credentialDigest)throw new r.CredentialError("VERIFICATION_FAILED","stored credential digest does not match the verified credential");if(i.requirementDigest!==await(0,r.credentialRequirementDigest)(s))throw new r.CredentialError("VERIFICATION_FAILED","stored requirement digest does not match the requirement");if(i.recordId!==await(0,r.canonicalDigest)({credentialDigest:c.credentialDigest,holderDid:i.ownerDid}))throw new r.CredentialError("VERIFICATION_FAILED","stored record id does not match its credential");return c}(e,I)}function ie(e,t){return{autoSign:async(r,i)=>{try{return await e.sign(i)}catch(e){const r=e instanceof DOMException&&("TimeoutError"===e.name||"AbortError"===e.name);if(!t||e instanceof x||r)throw e;throw new x("credential","SIGNATURE_REJECTED")}},holderKey:{alg:e.alg,kid:e.kid}}}function ne(e,t,i){if(e instanceof x)return e;if(e instanceof DOMException&&"TimeoutError"===e.name)return new x(t,"NETWORK");const n=(0,r.credentialError)(e),s=n.details;switch(n.code){case"ISSUER_UNREADY":return"rate_limited"===s.state?new x(t,"RATE_LIMITED",s.retryAfterMs,n.recoverable):new x(t,"ISSUER_UNAVAILABLE",void 0,n.recoverable);case"OFFLINE":return i?.aborted&&"TimeoutError"!==i.reason?.name?new x(t,"CANCELED"):new x(t,"NETWORK");case"UNSUPPORTED_PROFILE":case"UNSUPPORTED_VERSION":case"DESCRIPTOR_INVALID":return new x(t,"PROFILE_UNAVAILABLE");case"PROOF_REJECTED":return new x("code","CODE_REJECTED",void 0,!0);case"VERIFICATION_FAILED":return"proof_attempts_exhausted"===s.state?new x("code","CODE_ATTEMPTS_EXHAUSTED"):"credential"===t?new x("credential","CREDENTIAL_INVALID"):"code"===t?new x("code","CODE_REJECTED",void 0,!1):new x(t,"FAILED");case"HOLDER_MISMATCH":return new x("credential","CREDENTIAL_INVALID");case"REQUEST_EXPIRED":return new x("session","SESSION_EXPIRED");case"REQUEST_SUBSTITUTED":return new x("session","SESSION_INVALID");case"SIGNATURE_REJECTED":return new x("credential","SIGNATURE_REJECTED",void 0,n.recoverable);case"CANCELED":return new x(t,"CANCELED");default:return new x(t,"FAILED")}}const se="blockchainAccountId",oe="1",ae=0,de="The wallet signer signs only the exact account binding for this request.";function ce(){return new x("request","HOLDER_INVALID",void 0,void 0,de)}function le(){return new x("request","HOLDER_INVALID")}const ue=["audience","challengeNonce","completionContext","completionOrigin","credentialLifetimeSeconds","descriptorDigest","expiresAt","holderDid","issuedAt","issuer","issuerKid","jti","normalizedClaimsDigest","openerOrigin","profile","profileVersion","protocol","requestId","requirementDigest","type"],pe=/^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,fe=/^[A-Za-z0-9_-]{32}$/,he=/^[A-Za-z0-9_-]{43}$/,Ee=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/,we=6e5;function ge(e){try{return new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(e)}catch{throw ce()}}function Ie(e,t){const n=(0,i.parsePkhDid)(e);if(null===n||n.chainId!==oe)throw le();const o=(0,i.toChecksumAddress)(n.address),a=`did:pkh:eip155:${oe}:${o}`;return{did:a,alg:"EIP191",kid:`${a}#${se}`,sign:async e=>{const n=new Uint8Array(e);!function(e,t){const n=ge(e);let o,a;try{o=JSON.parse(n),a=(0,r.jcsCanonicalize)(o)}catch{throw ce()}if(a!==n||"object"!=typeof o||null===o||Array.isArray(o))throw ce();const d=o;if(Object.keys(d).sort().join()!==ue.join())throw ce();for(const e of ue)if("profileVersion"!==e&&"credentialLifetimeSeconds"!==e&&("string"!=typeof d[e]||""===d[e]))throw ce();const c=e=>d[e];if(Object.keys(s).some(e=>d[e]!==s[e])||!(0,i.pkhPrincipalsEqual)(d.holderDid,t)||!pe.test(c("jti"))||!fe.test(c("requestId"))||!fe.test(c("challengeNonce"))||!he.test(c("requirementDigest"))||!he.test(c("normalizedClaimsDigest"))||!Ee.test(c("issuedAt"))||!Ee.test(c("expiresAt"))||Date.parse(c("expiresAt"))-Date.parse(c("issuedAt"))!==we)throw ce()}(function(e){const t=(new TextEncoder).encode(i.ACCOUNT_BINDING_DOMAIN);if(e.length<=t.length+1||e[t.length]!==ae)throw ce();for(let r=0;r<t.length;r++)if(e[r]!==t[r])throw ce();return e.subarray(t.length+1)}(n),a);const d=ge(n),c=await t(n),l=c[64];if(65!==c.length||27!==l&&28!==l)throw le();if(!await(0,r.verifyEip191MessageSignature)(d,function(e){return`0x${Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}`}(c),o))throw le();return c}}}const De=6e5;function me(e,t){return e.getTime()-t.getTime()>De}const Ae=50,ye="1",Se=/^[A-Za-z0-9_-]{43}$/,ve="KV_NOT_FOUND",Te="This app can't read held credentials: the session may lack kv get and list on v1/held/ (skipPrefix), or may need to sign in again.",Ce="This app can't delete held credentials: the session may lack kv del on v1/held/ (skipPrefix), or may need to sign in again.",_e="Held credentials could not be listed",Oe="permission_denied";function Re(e){let t="object"==typeof e&&null!==e&&"error"in e?e.error:void 0,r=!1;for(let e=0;e<8&&"object"==typeof t&&null!==t;e+=1){const e=t,i=e.meta,n=[e.status,e.statusCode,"object"==typeof i&&null!==i?i.status:void 0].find(e=>"number"==typeof e&&Number.isInteger(e)&&e>=400&&e<=599);if(void 0!==n)return 401===n||403===n;"AUTH_UNAUTHORIZED"===e.code&&(r=!0),t=e.cause}return r}function be(e){const t=(0,i.parsePkhDid)(e);if(null===t)throw new r.CredentialError("ACTIVE_SESSION_REQUIRED","Held credentials require a did:pkh:eip155 account owner");if(t.chainId!==ye)throw new r.CredentialError("ACTIVE_SESSION_REQUIRED","Held credentials require an Ethereum mainnet (chain 1) account owner");return`did:pkh:eip155:${ye}:${(0,i.toChecksumAddress)(t.address)}`}function Ne(e){return`v1/held/${(0,i.registryKey)(e)}/`}function qe(e,t){return`${Ne(e)}${t}`}function Le(e){if("object"!=typeof e||null===e)return!1;const t=e;return"TinyCloudHeldCredential"===t.type&&1===t.version&&"string"==typeof t.ownerDid&&"string"==typeof t.recordId&&"string"==typeof t.credentialDigest&&"string"==typeof t.credential&&"string"==typeof t.storedAt}function Ue(e,t,r){return{issuerSet:e.issuerSet,acceptedIssuers:e.acceptedIssuers,didMethods:e.didMethods,now:t,owner:r}}async function xe(e){return{type:"TinyCloudHeldStorageReceipt",version:1,ownerDid:e.ownerDid,recordId:e.recordId,recordDigest:await(0,r.canonicalDigest)(e),storedAt:e.storedAt}}async function Pe(e){const t=e.now??new Date,n=be(e.ownerDid);let s;try{s=(0,i.verifyHeldEmailCredential)(e.sdJwt,Ue(e,t,n))}catch(e){throw function(e){if(!(e instanceof i.HeldCredentialError))return e;const t="nonce-account-mismatch"===e.code?"HOLDER_MISMATCH":"VERIFICATION_FAILED";return new r.CredentialError(t,e.message,{cause:e})}(e)}const o=e.sdJwt;if("string"!=typeof o)throw new r.CredentialError("VERIFICATION_FAILED","Held credential must be an SD-JWT string");if("string"!=typeof s.claims.email)throw new r.CredentialError("VERIFICATION_FAILED","Held credential must disclose an email claim");if(!me(s.expiresAt,t))throw new r.CredentialError("VERIFICATION_FAILED","Held credential expires within the reuse margin");const a=await(0,r.canonicalDigest)(o),d=await(0,r.canonicalDigest)({credentialDigest:a,holderDid:n}),c={type:"TinyCloudHeldCredential",version:1,ownerDid:n,recordId:d,credentialDigest:a,credential:o,storedAt:t.toISOString()},l=await async function(e,t,n){const s=(e=!1)=>new r.CredentialError("VERIFIED_NOT_SAVED","Held credential could not be confirmed in storage",e?{state:Oe}:{}),o=await e.batchPut([{key:t,value:n}]).catch(()=>{});if(!0!==o?.ok)throw s(void 0!==o&&Re(o));const a=await e.get(t).catch(()=>{});if(void 0!==a&&!a.ok&&Re(a))throw s(!0);const d=!0===a?.ok?a.data.data:void 0;if(!Le(d)||d.recordId!==n.recordId||d.credentialDigest!==n.credentialDigest||d.credential!==n.credential||!(0,i.pkhPrincipalsEqual)(d.ownerDid,n.ownerDid))throw s();return d}(e.kv,qe(n,d),c);return{record:l,receipt:await xe(l),verified:s}}async function Fe(e,t,i,n,s){const o=await e.get(t);if(!o.ok&&Re(o))throw new r.CredentialError("PERMISSION_DENIED",Te);return ke(o.ok?o.data.data:void 0,t,i,n,s)}async function ke(e,t,n,s,o){if(!Le(e))return{kind:"invalid"};if(!(0,i.pkhPrincipalsEqual)(e.ownerDid,n))return{kind:"invalid"};const a=await(0,r.canonicalDigest)(e.credential),d=await(0,r.canonicalDigest)({credentialDigest:a,holderDid:n});if(e.credentialDigest!==a||e.recordId!==d||t!==qe(n,d))return{kind:"invalid"};let c;try{c=(0,i.verifyHeldEmailCredential)(e.credential,Ue(s,o,n))}catch(e){if(!(e instanceof i.HeldCredentialError)||"bad-config"===e.code)throw e;return{kind:"expired"===e.code?"expired":"invalid"}}const l=c.claims.email;return"string"!=typeof l?{kind:"invalid"}:{kind:"verified",email:l,match:{record:e,verified:c,recordId:d,email:l,issuedAt:c.issuedAt,expiresAt:c.expiresAt,issuer:c.issuer}}}class Ve extends r.CredentialError{}async function He(e,t){const i=[];let n;for(let s=0;s<Ae;s+=1){const s=await e.list(void 0===n?{prefix:t}:{prefix:t,cursor:n});if(!s.ok){if(Re(s))throw new r.CredentialError("PERMISSION_DENIED",Te);return}if(i.push(...s.data.keys),!s.data.truncated)return[...new Set(i)];const o=s.data.nextCursor;if(void 0===o||""===o)throw new r.CredentialError("VERIFICATION_FAILED","Held listing is truncated without a continuation cursor");n=o}throw new Ve("VERIFICATION_FAILED","Held listing exceeds the page limit")}async function je(e){const t=e.now??new Date,r=be(e.ownerDid),i=await He(e.kv,Ne(r));if(void 0===i)return;const n=e.email.replace(/[A-Z]+/g,e=>e.toLowerCase());let s;for(const o of i){const i=await Fe(e.kv,o,r,e,t);if("verified"!==i.kind||i.email!==n)continue;const a=i.match.verified.expiresAt.getTime();me(i.match.verified.expiresAt,t)&&(void 0===s||a>s.verified.expiresAt.getTime())&&(s=i.match)}return s}async function Be(e){const t=e.now??new Date,n=be(e.ownerDid),s=await He(e.kv,Ne(n));if(void 0===s)throw new r.CredentialError("OFFLINE",_e);const o=[];for(const a of s){const s=await e.kv.get(a);if(!s.ok){if("error"in s&&s.error.code===ve)continue;if(Re(s))throw new r.CredentialError("PERMISSION_DENIED",Te);throw new r.CredentialError("OFFLINE","A held credential could not be read")}let d;try{d=await ke(s.data.data,a,n,e,t)}catch(e){if(e instanceof i.HeldCredentialError&&"bad-config"===e.code)throw e;continue}"verified"===d.kind&&me(d.match.verified.expiresAt,t)&&o.push(d.match)}return o.sort((e,t)=>{const r=t.issuedAt.getTime()-e.issuedAt.getTime();return 0!==r?r:e.recordId<t.recordId?-1:e.recordId>t.recordId?1:0})}async function Me(e){const t=be(e.ownerDid);if(!Se.test(e.recordId))throw new r.CredentialError("DESCRIPTOR_INVALID","recordId must be a 43-character base64url digest");const i=await e.kv.delete(qe(t,e.recordId));if(!i.ok&&Re(i))throw new r.CredentialError("PERMISSION_DENIED",Ce);return i.ok}async function Ke(e){const t=be(e.ownerDid);let i;try{i=await e.kv.list({prefix:Ne(t)})}catch{throw new r.CredentialError("OFFLINE",_e)}if(!i.ok){if(Re(i))throw new r.CredentialError("PERMISSION_DENIED",Te);throw new r.CredentialError("OFFLINE",_e)}}const $e="tinycloud.email-held/v1",Qe="opencredentials.email/v1",Je=3e5;class ze extends Error{constructor(e,t){super(t),this.retryable=!1,this.name="HeldSourceError",this.code=e}}const Xe="Saved held credentials list is too long to read; clear old ones";async function Ge(e){return async function(e,t){const{kv:s,address:o,holder:a,sessionDid:d,getCode:c,pendingStore:l,fetch:u,signal:p,now:f,allowHeldProfile:h,...E}=e,w=f??(()=>new Date),g=be(a.did);if(void 0!==d&&!(0,i.pkhPrincipalsEqual)(d,g))throw new r.CredentialError("HOLDER_MISMATCH","Held acquisition holder must be the session account");const I=!0===h;let D;try{D=await async function(e,t,n,s,o){const a=s.trim().replace(/[A-Z]+/g,e=>e.toLowerCase()),d=async()=>function(e){let t;for(const r of e)(void 0===t||r.expiresAt.getTime()>t.expiresAt.getTime())&&(t=r);return t}((await async function(e,t,n,s){try{return await Be({...t,kv:e,ownerDid:n,now:s})}catch(e){if(e instanceof r.CredentialError||e instanceof i.HeldCredentialError)throw e;throw new r.CredentialError("OFFLINE","Held credentials could not be read",{cause:e})}}(e,t,n,new Date(o().getTime()+Je))).filter(e=>e.email===a));try{return await d()}catch(e){if(!(e instanceof Ve))throw e}try{return await async function(e){const t=e.now??new Date,i=be(e.ownerDid),n=await He(e.kv,Ne(i));if(void 0===n)return[];const s=[],o=new Map;for(const r of n){const n=await Fe(e.kv,r,i,e,t);if("invalid"===n.kind)continue;if("expired"===n.kind){s.push(r);continue}const a={key:r,recordId:n.match.record.recordId,expiresAt:n.match.verified.expiresAt.getTime()},d=o.get(n.email);if(void 0===d){o.set(n.email,a);continue}const c=a.expiresAt>d.expiresAt||a.expiresAt===d.expiresAt&&a.recordId>d.recordId;o.set(n.email,c?a:d),s.push(c?d.key:a.key)}const a=[];for(const t of s){const i=await e.kv.delete(t);if(!i.ok&&Re(i))throw new r.CredentialError("PERMISSION_DENIED",Ce);i.ok&&a.push(t)}return a}({...t,kv:e,ownerDid:n,now:o()}),await d()}catch(e){if(e instanceof Ve)throw new ze("held-store-listing-limit",Xe);throw e}}(s,E,g,o,w)}catch(e){if(I||!(e instanceof r.CredentialError)||"OFFLINE"!==e.code&&"PERMISSION_DENIED"!==e.code)throw e}if(void 0!==D)return{credential:D.record.credential,holderDid:g,expiresAt:D.verified.expiresAt};I&&function(e,t){const s=()=>new r.CredentialError("VERIFICATION_FAILED","The issuer policy does not accept the held credential issuer"),{issuerDid:o,issuerKid:a}=n;if(!Array.isArray(e.acceptedIssuers)||!e.acceptedIssuers.some(e=>e.issuerDid===o&&(void 0===e.kid||e.kid===a)))throw s();if(!i.IssuerSet.is(e.issuerSet))throw s();const d=e.issuerSet.resolveIssuer(o,a),c=t.getTime();if(!d||!d.vcts.includes(Qe)||!d.profiles.includes($e)||c<d.notBefore||null!==d.retiredAt&&c>=d.retiredAt||null!==d.notAfter&&c>=d.notAfter)throw s()}(E,w());const m=await t({address:o,holder:a,profile:$e,getCode:c,pendingStore:We(l,g,w),fetch:u,signal:p,now:w,allowHeldProfile:h});if("issued"!==m.status)throw new r.CredentialError("PROOF_REJECTED","Held acquisition did not issue a credential");const A=m.result.envelope.credential,y=w().getTime(),S=function(e){try{const t=JSON.parse((new TextDecoder).decode((0,r.decodeBase64Url)(e.split("~")[0].split(".")[1]))),i="object"==typeof t&&null!==t&&"iat"in t?t.iat:void 0;if("number"==typeof i&&Number.isSafeInteger(i))return 1e3*i}catch{}throw new r.CredentialError("VERIFICATION_FAILED","Issued credential is not readable")}(A);if(S-y>Je)throw new r.CredentialError("VERIFICATION_FAILED","client clock is more than 5 minutes behind the issuer");let v;try{v=await Pe({...E,kv:s,ownerDid:g,sdJwt:A,now:new Date(Math.max(y,S))})}catch(e){const t=e instanceof r.CredentialError&&e.details.state===Oe;throw new r.CredentialError("VERIFIED_NOT_SAVED","Verified held credential could not be stored",t?{state:Oe}:{})}return{credential:A,holderDid:g,expiresAt:v.verified.expiresAt}}(e,Q)}function We(e,t,r){if(void 0===e)return;const n=e=>void 0!==e&&e.profile===$e&&(0,i.pkhPrincipalsEqual)(e.holderDid,t);return{async findLive(t,r){const i=await e.findLive(t,r);return n(i)?i:void 0},put:t=>e.put(t),async delete(t){n(await e.get(t,r()))&&await e.delete(t)},async get(t,r){const i=await e.get(t,r);return n(i)?i:void 0}}}module.exports=t})();
|
package/dist/credentials.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ACCOUNT_HOLDER_BINDING_DOMAIN as e,CredentialError as t,canonicalDigest as i,createEmailCredentialRequirement as r,credentialEndpointPath as s,credentialError as n,credentialRequirementDigest as o,decodeBase64Url as a,descriptorSatisfiesRequirement as d,encodeBase64Url as c,holderBindingCanonicalBytes as l,holderBindingSigningBytes as u,jcsCanonicalize as p,sha256Base64Url as f,validateCredentialFlowDescriptor as h,validateCredentialHolderBinding as w,validateCredentialRequirement as g,verifyEip191MessageSignature as I,verifyIssuedCredential as E}from"@tinycloud/sdk-core";import{ACCOUNT_BINDING_DOMAIN as D,HeldCredentialError as A,IssuerSet as m,parseIssuerSet as y,parsePkhDid as S,pkhPrincipalsEqual as v,registryKey as T,toChecksumAddress as _,verifyHeldEmailCredential as O}from"@tinycloud/sdk-core/held-credentials";var R=Object.freeze({witnessOrigin:"https://witness.credentials.org",issuerDid:"did:web:issuer.credentials.org",issuerKid:"did:web:issuer.credentials.org#controller",issuerX:"eEJI4xEobto4HtQ7Pg9R1vBOwcpfGRTlXDG5QfqLnGQ",descriptorDigest:"1tg-qphmKBVtNwzVg9xyz-xxqt_xtMXAsQyXw46m8S0"}),b=Object.freeze({type:e,protocol:"tinycloud.credentials/acquisition/v1",profile:"tinycloud.email-held/v1",profileVersion:1,descriptorDigest:"dc3_DuvzipXwYkTfjKqTaK1c3VS0YSPnaBsYSQriC0w",issuer:R.issuerDid,issuerKid:R.issuerKid,audience:"tinycloud://credentials",openerOrigin:"https://localhost",completionOrigin:"https://localhost",completionContext:"sdk-acquisition",credentialLifetimeSeconds:31536e3}),N=()=>new t("REQUEST_SUBSTITUTED","Holder binding was substituted"),C=(e,t)=>new Promise((i,r)=>{const s=setTimeout(i,e);t?.addEventListener("abort",()=>{clearTimeout(s),r(new DOMException("Aborted","AbortError"))},{once:!0})});async function L(e){const r="account_is_subject"===e.descriptor.subjectRelationship;if(r&&!0!==e.allowAccountSubject)throw new t("UNSUPPORTED_PROFILE","The held credential profile requires an explicit opt-in");const s=new Map(e.descriptor.steps.map(e=>[e.type,e])),n=new Set;let o="";const a=async r=>{const s=w(r);if(s.requestId!==e.requestId||s.descriptorDigest!==e.descriptorDigest||s.requirementDigest!==e.requirementDigest||s.holderDid!==e.holderDid||s.issuer!==e.descriptor.issuer.did||s.issuerKid!==e.descriptor.issuer.kid||s.profile!==e.descriptor.profile||s.openerOrigin!==e.openerOrigin||s.completionOrigin!==e.openerOrigin||"tinycloud://credentials"!==s.audience)throw new t("REQUEST_SUBSTITUTED","Holder binding was substituted");const n=e.descriptor.holderBinding.alg;if(s.type!==e.descriptor.holderBinding.domain||"EIP191"===n&&!e.transport.challengeNonce)throw new t("REQUEST_SUBSTITUTED","Holder binding was substituted");return"EIP191"===n&&await async function(e,t){const{descriptor:r}=t;if("EIP191"!==r.holderBinding.alg||e.type!==r.holderBinding.domain||e.requestId!==t.requestId||e.descriptorDigest!==t.descriptorDigest||e.requirementDigest!==t.requirementDigest||e.holderDid!==t.holderDid||e.issuer!==r.issuer.did||e.issuerKid!==r.issuer.kid||e.profile!==r.profile||e.openerOrigin!==t.openerOrigin||e.completionOrigin!==t.openerOrigin||e.audience!==b.audience||e.completionContext!==b.completionContext||e.type!==b.type||e.protocol!==b.protocol||e.profile!==b.profile||e.profileVersion!==b.profileVersion||e.descriptorDigest!==b.descriptorDigest||e.issuer!==b.issuer||e.issuerKid!==b.issuerKid||e.openerOrigin!==b.openerOrigin||e.completionOrigin!==b.completionOrigin||e.credentialLifetimeSeconds!==b.credentialLifetimeSeconds)throw N();if(void 0===t.challengeNonce||e.challengeNonce!==t.challengeNonce)throw N();if(e.normalizedClaimsDigest!==await i(t.requirement.claims))throw N();const s=Date.parse(e.expiresAt);if(void 0===t.serverExpiresAt||s!==Date.parse(t.serverExpiresAt)||Date.parse(e.issuedAt)!==s-6e5)throw N()}(s,{descriptor:e.descriptor,requirement:e.requirement,requestId:e.requestId,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,holderDid:e.holderDid,openerOrigin:e.openerOrigin,challengeNonce:e.transport.challengeNonce(e.requestId),serverExpiresAt:e.expiresAt}),s},d=async()=>{r&&void 0===e.transport.signedBinding?.(e.requestId)&&await a(await e.transport.holderBinding(e.requestId,e.verifier,e.signal))};for(;;){e.signal?.throwIfAborted();const i=await e.transport.state(e.requestId,e.verifier,e.signal);if(i.requestId!==e.requestId)throw new t("REQUEST_SUBSTITUTED","Credential request identity changed");if("expired"===i.state)throw new t("REQUEST_EXPIRED","Credential request expired",{state:i.state,correlationId:i.correlationId});if("canceled"===i.state)throw new t("CANCELED","Credential request was canceled",{state:i.state,correlationId:i.correlationId});if("issuer_unready"===i.state)throw new t("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:i.retryAfterMs,state:i.state,correlationId:i.correlationId});if("complete"===i.state)return void await d();if("ready_to_issue"===i.state||"issued"===i.state){await d(),"ready_to_issue"!==i.state||n.has("issue")?await(e.onWait?.()??C(i.retryAfterMs??50,e.signal)):(await e.transport.issue(e.requestId,e.verifier,e.signal),n.add("issue"));continue}const r=i.nextStep;if(!r){await(e.onWait?.()??C(i.retryAfterMs??50,e.signal));continue}const l=s.get(r.type);if(r.id!==r.type||!l||l.type!==r.type||l.version!==r.version)throw new t("REQUEST_SUBSTITUTED","Server selected an undeclared credential step");if(n.has(r.id)||i.transitionId===o)await(e.onWait?.()??C(i.retryAfterMs??50,e.signal));else{if(o=i.transitionId,"holder_signature"===r.type){e.onProgress?.({state:"signing",stepId:r.id,correlationId:i.correlationId});const s=await a(await e.transport.holderBinding(e.requestId,e.verifier,e.signal)),n=e.descriptor.holderBinding.alg;if("EIP191"===n!=("EIP191"===e.signing.holderKey?.alg))throw new t("REQUEST_SUBSTITUTED","Holder binding was substituted");const o=u(s);let d=await(e.signing.autoSign?.(s,o,e.signal));if(void 0===d){if(!e.signing.requestApproval)throw new t("SIGNATURE_REJECTED","OpenKey approval is required");try{d=await e.signing.requestApproval(s,o,e.signal)}catch(e){if(e instanceof t)throw e;throw new t("SIGNATURE_REJECTED","OpenKey approval was rejected",{cause:e})}}if(!(d instanceof Uint8Array)||0===d.length)throw new t("SIGNATURE_REJECTED","OpenKey signature is invalid");await e.transport.submitHolderSignature(e.requestId,e.verifier,"EIP191"===n?`0x${Array.from(d,e=>e.toString(16).padStart(2,"0")).join("")}`:c(d),e.signal,e.signing.holderKey)}else{e.onProgress?.({state:"collect_input"===r.type?"collecting":"proving",stepId:r.id,correlationId:i.correlationId});const s=e.handlers?.[r.type],n=e.proofHandler;if(!s&&!n){await(e.onWait?.()??C(i.retryAfterMs??50,e.signal));continue}if(!0===r.constraints.challengeRequired&&await e.transport.beginStep(e.requestId,e.verifier,r.type,e.signal),s){const t=await s({descriptor:e.descriptor,requirement:e.requirement,stepId:r.id,constraints:r.constraints,signal:e.signal});await e.transport.submitStep(e.requestId,e.verifier,r.id,t,e.signal)}else{let i;for(let s=1;;s+=1){const o=await n({stepId:r.id,constraints:r.constraints,display:{title:e.descriptor.display.title,description:e.descriptor.display.description,consent:e.descriptor.display.consent,progressLabel:e.descriptor.accessibility.progressLabel,errorLiveRegion:e.descriptor.accessibility.errorLiveRegion},inputs:e.descriptor.inputs.map(({id:e,label:t,schema:i})=>({id:e,label:t,schema:i})),...void 0===i?{}:{feedback:i},signal:e.signal});try{await e.transport.submitStep(e.requestId,e.verifier,r.id,o,e.signal);break}catch(n){if(!(n instanceof t)||"PROOF_REJECTED"!==n.code)throw n;const o=e.descriptor.lifecycle.maxProofAttempts-s;if("mailbox_otp"!==r.type||o<=0)throw new t("VERIFICATION_FAILED","The proof was not accepted",{state:o<=0?"proof_attempts_exhausted":"proof_rejected",cause:n});i={kind:"rejected",attemptsRemaining:o}}}}}n.add(r.id)}}}function q(e,i){if("object"!=typeof e||null===e||Array.isArray(e))throw new t("VERIFICATION_FAILED",`${i} is invalid`);return e}function U(e,i){if("string"!=typeof e||!/^[A-Za-z0-9_-]{16,128}$/.test(e))throw new t("REQUEST_SUBSTITUTED",`${i} is invalid`);return e}function x(e,i){if("string"!=typeof e||!Number.isFinite(Date.parse(e)))throw new t("VERIFICATION_FAILED",`${i} is invalid`);return new Date(e).toISOString()}var F=new Set(["REQUEST_EXPIRED","ISSUER_UNREADY","UNSUPPORTED_PROFILE","UNSUPPORTED_VERSION","SIGNATURE_REJECTED"]),P=class{constructor(e,i=globalThis.fetch.bind(globalThis),r={}){if(this.descriptor=e,this.fetchFn=i,this.options=r,this.nonces=new Map,this.bindings=new Map,"account_is_subject"===e.subjectRelationship&&!0!==r.allowAccountSubject)throw new t("UNSUPPORTED_PROFILE","The held credential profile requires an explicit opt-in")}url(e,t){return new URL(s(e,t),this.descriptor.issuer.origin).href}async request(e,i){let r;try{const t={method:i.method??"GET",credentials:"omit",cache:"no-store",redirect:"error",referrerPolicy:"no-referrer",signal:i.signal,headers:{accept:"application/json",...void 0===i.body?{}:{"content-type":"application/json"},...void 0===i.verifier?{}:{authorization:`Bearer ${i.verifier}`}},...void 0===i.body?{}:{body:JSON.stringify(i.body)}};r=await this.fetchFn(this.url(e,i.id),t)}catch(e){if(e instanceof DOMException&&"AbortError"===e.name)throw new t("CANCELED","Credential acquisition was canceled",{cause:e});throw new t("OFFLINE","OpenCredentials is unavailable",{cause:e})}if(!r.ok){let e;try{e=await r.json()}catch{e=void 0}const i=function(e,i,r){if("object"!=typeof e||null===e||Array.isArray(e))return;const s=e;if("code,correlationId,recoverable,state,type"!==Object.keys(s).sort().join(",")||"tinycloud.credentials/error/v1"!==s.type||"string"!=typeof s.code||"boolean"!=typeof s.recoverable||"string"!=typeof s.state||"string"!=typeof s.correlationId)return;if("PROOF_REJECTED"===s.code)return s.recoverable?new t("PROOF_REJECTED","The proof was not accepted",{state:s.state,correlationId:s.correlationId}):new t("VERIFICATION_FAILED","The proof attempt limit was reached",{state:"proof_attempts_exhausted",correlationId:s.correlationId});if("RATE_LIMITED"===s.code)return new t("ISSUER_UNREADY","Too many verification codes were requested",{state:"rate_limited",correlationId:s.correlationId,retryAfterMs:1e3*Number(i.headers.get("retry-after"))||void 0,recoverable:r?s.recoverable:void 0});if("CHALLENGE_EXPIRED"===s.code)return new t("REQUEST_EXPIRED","The credential challenge expired",{state:s.state,correlationId:s.correlationId,recoverable:r?s.recoverable:void 0});if("DESCRIPTOR_MISMATCH"===s.code&&(s.code="UNSUPPORTED_PROFILE"),!F.has(s.code))return;const n=s.code;return new t(n,`OpenCredentials rejected the request: ${n}`,{state:s.state,correlationId:s.correlationId,retryAfterMs:1e3*Number(i.headers.get("retry-after"))||void 0,recoverable:r?s.recoverable:void 0})}(e,r,!0===this.options.honorServerRecoverable);if(i)throw i;if(410===r.status)throw new t("REQUEST_EXPIRED","Credential request expired");if(409===r.status)throw new t("REQUEST_SUBSTITUTED","Credential request was replayed or substituted");if(503===r.status)throw new t("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:1e3*Number(r.headers.get("retry-after"))||void 0});throw new t("VERIFICATION_FAILED","OpenCredentials rejected the request")}if(204!==r.status)try{return await r.json()}catch(e){throw new t("VERIFICATION_FAILED","OpenCredentials response is invalid",{cause:e})}}async create(e){const i=q(await this.request("request",{method:"POST",body:{protocol:e.descriptor.protocol,profile:e.descriptor.profile,profileVersion:e.descriptor.profileVersion,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,holderDid:e.holderDid,inputs:e.inputs??e.requirement.claims,audience:b.audience,openerOrigin:e.openerOrigin,completionOrigin:e.openerOrigin,completionContext:b.completionContext,completionVerifierChallenge:e.completionVerifierChallenge},signal:e.signal}),"create response");if("tinycloud.credentials/acquisition-request/v1"!==i.type||i.protocol!==e.descriptor.protocol||"challenge"!==i.next||"challenge"!==i.endpoint)throw new t("VERIFICATION_FAILED","create response is invalid");const r=U(i.requestId,"requestId");return{requestId:r,locator:r,expiresAt:x(i.expiresAt,"expiresAt"),correlationId:r}}challengeNonce(e){return this.nonces.get(e)}signedBinding(e){return this.bindings.get(e)}proofStep(){return this.descriptor.steps.some(e=>"mailbox_otp"===e.type)?"mailbox_otp":"collect_input"}async state(e,i,r){const s=q(await this.request("state",{id:e,verifier:i,signal:r}),"state response");if("tinycloud.credentials/acquisition-state/v1"!==s.type||s.requestId!==e||s.profile!==this.descriptor.profile||1!==s.profileVersion)throw new t("REQUEST_SUBSTITUTED","Credential state response is substituted");const n={type:"OpenCredentialsAcquisitionState",version:1,requestId:e,transitionId:`${String(s.state)}:${String(s.resultPreviouslyRead??!1)}`,correlationId:e};if("challenge_required"===s.state){const e=this.proofStep();return{...n,state:"pending",nextStep:{id:e,type:e,version:1,constraints:{challengeRequired:!0}}}}if("account_is_subject"===this.descriptor.subjectRelationship&&("proof_required"===s.state||"holder_binding_required"===s.state||"holder_signature_required"===s.state||"ready_to_issue"===s.state||"issued"===s.state)){const i=s.challengeNonce,r=this.nonces.get(e);if("string"!=typeof i||""===i||void 0!==r&&r!==i)throw new t("REQUEST_SUBSTITUTED","Credential challenge nonce is missing or changed");this.nonces.set(e,U(i,"challengeNonce"))}if("proof_required"===s.state){const t=this.proofStep();return"account_is_subject"!==this.descriptor.subjectRelationship&&this.nonces.set(e,U(s.challengeNonce,"challengeNonce")),{...n,state:"pending",nextStep:{id:t,type:t,version:1,constraints:{}}}}if("holder_binding_required"===s.state||"holder_signature_required"===s.state)return{...n,state:"pending",nextStep:{id:"holder_signature",type:"holder_signature",version:1,constraints:{}}};if("ready_to_issue"===s.state)return{...n,state:"ready_to_issue"};if("issued"===s.state)return{...n,state:"complete"};throw new t("REQUEST_SUBSTITUTED","Credential state is unsupported")}async beginStep(e,i,r,s){const n=this.proofStep();if(r!==n)throw new t("REQUEST_SUBSTITUTED","Credential challenge step is substituted");const o=q(await this.request("challenge",{id:e,verifier:i,method:"POST",body:{step:n,stepVersion:1},signal:s}),"challenge response");if("tinycloud.credentials/challenge/v1"!==o.type||o.step!==n||1!==o.stepVersion)throw new t("REQUEST_SUBSTITUTED","Credential challenge is substituted");this.nonces.set(e,U(o.challengeNonce,"challengeNonce"))}async submitStep(e,i,r,s,n){const o=this.proofStep();if(r!==o)throw new t("REQUEST_SUBSTITUTED","Credential proof step is substituted");const a=this.nonces.get(e);if(!a)throw new t("REQUEST_SUBSTITUTED","Credential challenge is missing");await this.request("proof",{id:e,verifier:i,method:"POST",body:{step:o,stepVersion:1,challengeNonce:a,proof:s},signal:n})}async holderBinding(e,i,r){const s=q(await this.request("holder_binding",{id:e,verifier:i,signal:r}),"holder binding response");if("tinycloud.credentials/holder-binding-request/v1"!==s.type||s.signingDomain!==this.descriptor.holderBinding.domain||s.alg!==this.descriptor.holderBinding.alg||"string"!=typeof s.canonical)throw new t("REQUEST_SUBSTITUTED","Holder binding response is invalid");const n=w(s.binding);if(n.type!==s.signingDomain)throw new t("REQUEST_SUBSTITUTED","Holder binding type does not match its signing domain");if(c(l(n))!==s.canonical)throw new t("REQUEST_SUBSTITUTED","Holder binding canonical bytes were substituted");return this.bindings.set(e,n),n}async submitHolderSignature(e,i,r,s,n){const o=this.bindings.get(e);if(!o)throw new t("REQUEST_SUBSTITUTED","Holder binding was not retrieved");if("EIP191"===this.descriptor.holderBinding.alg&&!n)throw new t("REQUEST_SUBSTITUTED","An account holder must name its key and algorithm");const a=n?.alg??"EdDSA",d=n?.kid??`${o.holderDid}#${o.holderDid.replace("did:key:","")}`;await this.request("holder_signature",{id:e,verifier:i,method:"POST",body:{alg:a,kid:d,signature:r},signal:s})}async issue(e,t,i){await this.request("issue",{id:e,verifier:t,method:"POST",signal:i})}async result(e,r,s){const n=q(await this.request("result",{id:e,verifier:r,signal:s}),"result response");if("tinycloud.credentials/result/v1"!==n.type||n.protocol!==this.descriptor.protocol||n.profile!==this.descriptor.profile||1!==n.profileVersion||"vc+sd-jwt"!==n.format||n.descriptorDigest!==await i(this.descriptor)||n.issuer!==this.descriptor.issuer.did||n.issuerKid!==this.descriptor.issuer.kid||"string"!=typeof n.credential||await f(n.credential)!==n.credentialDigest)throw new t("VERIFICATION_FAILED","Issued result metadata is invalid");const o=q(n.holderBinding,"result holder binding");if(n.subject!==o.did||o.signingDomain!==this.descriptor.holderBinding.domain)throw new t("HOLDER_MISMATCH","Issued holder binding is invalid");const d=q(n.claims,"result claims"),c={};for(const[e,i]of Object.entries(d)){if("string"!=typeof i)throw new t("VERIFICATION_FAILED","Issued claims are invalid");c[e]=i}const l=q(n.validity,"result validity"),u=function(e){const i=e.split("~",1)[0]?.split(".")[1];if(!i)throw new t("VERIFICATION_FAILED","Issued SD-JWT is invalid");try{return q(JSON.parse((new TextDecoder).decode(a(i))),"SD-JWT payload")}catch(e){if(e instanceof t)throw e;throw new t("VERIFICATION_FAILED","Issued SD-JWT is invalid",{cause:e})}}(n.credential);if("string"!=typeof u.jti)throw new t("VERIFICATION_FAILED","Credential id is invalid");const p=x(l.issuedAt,"issuedAt"),h=x(l.expiresAt,"expiresAt"),w=q(n.status,"result status");if("none"!==w.type||w.freshnessSeconds!==this.descriptor.status.freshnessSeconds)throw new t("VERIFICATION_FAILED","Credential status is invalid");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:n.issuer,issuerKid:n.issuerKid,subjectDid:n.subject,holderDid:n.subject,claims:c,claimsDigest:await i(c),descriptorDigest:n.descriptorDigest,credentialId:u.jti,issuedAt:p,notBefore:p,expiresAt:h,status:{method:"none",freshnessSeconds:w.freshnessSeconds},credential:n.credential}}async issuerMetadata(e){return await this.request("issuer_metadata",{signal:e})}async checkStatus(e,t){return"none"===e.method&&e.freshnessSeconds===this.descriptor.status.freshnessSeconds}},k={id:"opencredentials.email/v1",version:1},V=9e5,j=`${R.witnessOrigin}/.well-known/opencredentials`,B=[{kid:R.issuerKid,alg:"EdDSA",jwk:{kty:"OKP",crv:"Ed25519",x:R.issuerX},validFrom:"2020-01-01T00:00:00Z",validUntil:"2100-01-01T00:00:00Z"}],H="tinycloud.email-proof/v1",M={"tinycloud.email-proof/v1":{descriptorDigest:R.descriptorDigest,requiredStep:"mailbox_otp",enabled:!0},"tinycloud.email-held/v1":{descriptorDigest:b.descriptorDigest,requiredStep:"mailbox_otp",enabled:!1}},K=b.openerOrigin,$="tinycloud.email-held/v1",Q=3e5,J=/^did:key:z6Mk[^#]+$/,z=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,X=Symbol.for("nodejs.util.inspect.custom"),G={ADDRESS_INVALID:!1,HOLDER_INVALID:!1,CODE_INVALID:!0,RATE_LIMITED:!0,ISSUER_UNAVAILABLE:!0,NETWORK:!0,PROFILE_UNAVAILABLE:!1,CODE_REJECTED:!0,CODE_ATTEMPTS_EXHAUSTED:!1,SIGNATURE_REJECTED:!0,CREDENTIAL_INVALID:!1,SESSION_EXPIRED:!1,SESSION_INVALID:!1,CLIENT_CLOCK_SKEW:!1,CANCELED:!1,FAILED:!1},W={ADDRESS_INVALID:"Email address is invalid.",HOLDER_INVALID:"Holder must be a did:key Ed25519 identifier.",CODE_INVALID:"Verification code must be 8 digits.",ISSUER_UNAVAILABLE:"Email verification is unavailable right now.",NETWORK:"Could not reach the email verification service.",PROFILE_UNAVAILABLE:"The witness does not offer the email verification profile.",CODE_REJECTED:"Verification code was not accepted.",CODE_ATTEMPTS_EXHAUSTED:"Too many wrong codes. Request a new code.",SIGNATURE_REJECTED:"Holder signature was rejected.",CREDENTIAL_INVALID:"Issued credential failed verification.",SESSION_EXPIRED:"Email verification request expired. Request a new code.",SESSION_INVALID:"Email verification request is no longer valid. Request a new code.",CLIENT_CLOCK_SKEW:"Your device clock is more than 5 minutes behind. Correct it and try again.",CANCELED:"Email verification was canceled.",FAILED:"Email verification failed."},Y=class extends Error{constructor(e,t,i,r=G[t],s){super(s??("RATE_LIMITED"===t?function(e){const t="Too many codes were requested for this address.";if(void 0===e||!Number.isFinite(e)||e<=0)return`${t} Try again in about an hour.`;const i=Math.max(1,Math.ceil(e/6e4));return`${t} Try again in ${i} ${1===i?"minute":"minutes"}.`}(i):W[t])),this.name="EmailProofError",this.step=e,this.code=t,this.retryAfterMs=i,this.recoverable=r}};function Z(e,t){const i=e.indexOf("#"),r=-1===i?e:e.slice(0,i);if(-1!==i&&e.slice(i+1)!==r.slice(8))throw new Y("request","HOLDER_INVALID");if(!J.test(r))throw new Y("request","HOLDER_INVALID");return{did:r,alg:"EdDSA",kid:fe(r),sign:t}}function ee(e){const t={type:e.type,version:e.version,profile:e.profile,address:e.address,requestId:e.requestId,holderDid:e.holderDid,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,openerOrigin:e.openerOrigin,createdAt:e.createdAt,expiresAt:e.expiresAt,...void 0===e.serverExpiresAt?{}:{serverExpiresAt:e.serverExpiresAt}},i={...t};return te(i,"verifier",e.verifier),te(i,"toJSON",()=>({...t})),te(i,X,()=>({...t,verifier:"[redacted]"})),Object.freeze(i)}function te(e,t,i){Object.defineProperty(e,t,{value:i,enumerable:!1,writable:!1,configurable:!1})}function ie(e){return Math.min(Date.parse(e.expiresAt),Date.parse(e.createdAt)+V)}function re(){const e=new Map,t=t=>{for(const[i,r]of e)ie(r)<=t.getTime()&&e.delete(i)};return{async findLive(i,r){let s;t(r);for(const t of e.values())t.address===i&&(!s||Date.parse(t.createdAt)>Date.parse(s.createdAt))&&(s=t);return s},async put(t){e.set(t.requestId,t)},async delete(t){e.delete(t)},get:async(i,r)=>(t(r),e.get(i))}}var se=class extends Error{},ne=async()=>{throw new se("code requested")};async function oe(e){const t=e.profile??H;we(t,"request",e.allowHeldProfile);const r=t===$;r&&he(e.holder,"request",t);const s=le(e.address,t);r||he(e.holder,"request",t);const n=e.now??(()=>new Date),a=e.signal??AbortSignal.timeout(6e4),d=ge(s,t),l=await o(d),u=await Ie(t,d,{fetch:e.fetch,signal:a},"request",e.allowHeldProfile),p=await i(u),h=c(crypto.getRandomValues(new Uint8Array(32))),w=new P(u,e.fetch,{honorServerRecoverable:!0,...r?{allowAccountSubject:!0}:{}}),g=n().getTime();let I;try{I=await w.create({descriptor:u,descriptorDigest:p,requirement:d,requirementDigest:l,holderDid:e.holder.did,openerOrigin:K,completionVerifierChallenge:await f(h),signal:a})}catch(e){throw me(e,"request",a)}const E=Date.parse(I.expiresAt);if(!Number.isFinite(E))throw new Y("request","FAILED");const D=E-6e5;if(r&&D-n().getTime()>Q)throw new Y("request","CLIENT_CLOCK_SKEW");const A=ee({type:"TinyCloudEmailProofPending",version:1,profile:t,address:s,requestId:I.requestId,verifier:h,holderDid:e.holder.did,descriptorDigest:p,requirementDigest:l,openerOrigin:K,createdAt:new Date(g).toISOString(),expiresAt:new Date(r?g+Math.min(E-D,V):Math.min(E,g+V)).toISOString(),...r?{serverExpiresAt:I.expiresAt}:{}});try{await L({descriptor:u,...r?{allowAccountSubject:!0}:{},requirement:d,requestId:I.requestId,verifier:h,holderDid:e.holder.did,descriptorDigest:p,requirementDigest:l,openerOrigin:K,...r?{expiresAt:I.expiresAt}:{},transport:w,signing:Ae(e.holder,r),handlers:{mailbox_otp:ne},signal:a})}catch(e){if(e instanceof se)return A;throw me(e,"request",a)}throw new Y("request","FAILED")}async function ae(e){return de(e,B)}async function de(e,r){const{pending:s}=e,n=e.now??(()=>new Date);if(!function(e){if("object"!=typeof e||null===e)return!1;const t=e;return"TinyCloudEmailProofPending"===t.type&&1===t.version&&t.openerOrigin===K&&[t.profile,t.address,t.requestId,t.verifier,t.holderDid,t.descriptorDigest,t.requirementDigest,t.openerOrigin,t.createdAt,t.expiresAt].every(e=>"string"==typeof e)&&Number.isFinite(Date.parse(t.createdAt))&&Number.isFinite(Date.parse(t.expiresAt))}(s))throw new Y("session","SESSION_INVALID");we(s.profile,"session",e.allowHeldProfile);const a=s.profile===$;if(a&&!Number.isFinite(Date.parse(s.serverExpiresAt??"")))throw new Y("session","SESSION_INVALID");if(ie(s)<=n().getTime())throw new Y("session","SESSION_EXPIRED");if(!/^\d{8}$/.test(e.code))throw new Y("code","CODE_INVALID");if(he(e.holder,"code",s.profile),e.holder.did!==s.holderDid)throw new Y("session","SESSION_INVALID");const d=e.signal??AbortSignal.timeout(6e4),c=ge(s.address,s.profile);if(await o(c)!==s.requirementDigest)throw new Y("session","SESSION_INVALID");const l=await Ie(s.profile,c,{fetch:e.fetch,signal:d},"session",e.allowHeldProfile),u=await i(l);if(u!==s.descriptorDigest)throw new Y("session","SESSION_INVALID");const p=new P(l,e.fetch,{honorServerRecoverable:!0,...a?{allowAccountSubject:!0}:{}});try{const t=await p.state(s.requestId,s.verifier,d);if(!0===t.nextStep?.constraints.challengeRequired)throw new Y("session","SESSION_INVALID");await L({descriptor:l,...a?{allowAccountSubject:!0}:{},requirement:c,requestId:s.requestId,verifier:s.verifier,holderDid:s.holderDid,descriptorDigest:u,requirementDigest:s.requirementDigest,openerOrigin:s.openerOrigin,...a?{expiresAt:s.serverExpiresAt}:{},transport:p,signing:Ae(e.holder,a),handlers:{mailbox_otp:async()=>({otp:e.code})},signal:d})}catch(e){throw me(e,"code",d)}try{const e=await p.result(s.requestId,s.verifier,d);if(a){const i=await async function(e){const{envelope:i,pending:r,descriptor:s}=e,n=e=>new t("VERIFICATION_FAILED",e),o=Date.parse(i.issuedAt),a=e.now().getTime();if(!Number.isFinite(o)||o-a>Q)throw n("client clock is more than 5 minutes behind the issuer");const d=e.issuerKeys.find(e=>e.kid===R.issuerKid);if(!d)throw n("no pinned issuer key");const c=y({format:"tinycloud.credentials-issuers/v1",version:1,issuers:[{issuerDid:R.issuerDid,kid:R.issuerKid,alg:"EdDSA",publicKey:d.jwk.x,vcts:[k.id],profiles:[$],notBefore:"2020-01-01T00:00:00Z",retiredAt:null,notAfter:null}]},{didMethods:{issuer:["web"]}}),l=O(i.credential,{now:new Date(Math.max(a,o)),owner:r.holderDid,didMethods:{issuer:["web"]},acceptedIssuers:[{issuerDid:R.issuerDid,kid:R.issuerKid}],issuerSet:c}),u=e.transport.signedBinding(r.requestId),p=Object.keys(i.claims).sort().join(),f=e=>Math.floor(e/1e3);if(i.subjectDid!==r.holderDid||i.holderDid!==r.holderDid||"email,emailDomain"!==p||i.claims.email!==l.claims.email||i.claims.emailDomain!==l.claims.emailDomain||i.claims.email!==r.address||f(Date.parse(i.issuedAt))!==f(l.issuedAt.getTime())||f(Date.parse(i.expiresAt))!==f(l.expiresAt.getTime())||i.descriptorDigest!==e.descriptorDigest||i.profile.id!==$||1!==i.profile.version||i.issuerDid!==R.issuerDid||i.issuerKid!==R.issuerKid||"vc+sd-jwt"!==i.format||"none"!==i.status.method||i.status.freshnessSeconds!==s.status.freshnessSeconds)throw n("issued credential does not match the request");if(u?.type!==s.holderBinding.domain||!("credentialLifetimeSeconds"in u))throw n("signed binding is missing");if(l.credentialId!==u.jti||(l.expiresAt.getTime()-l.issuedAt.getTime())/1e3!==u.credentialLifetimeSeconds)throw n("credential does not match the binding the account signed");return l}({envelope:e,pending:s,descriptor:l,descriptorDigest:u,transport:p,issuerKeys:r,now:n});return{envelope:e,verified:i,credentialId:i.credentialId,issuedAt:i.issuedAt.toISOString(),expiresAt:i.expiresAt.toISOString(),descriptor:l}}const i=await E({envelope:e,descriptor:l,descriptorDigest:u,requirement:c,holderDid:s.holderDid,issuerMetadata:Ee(r),now:n(),checkStatus:(e,t)=>p.checkStatus(e,t),signal:d});return{envelope:e,verified:i,credentialId:i.credentialId,issuedAt:i.issuedAt,expiresAt:i.expiresAt,descriptor:l}}catch(e){throw me(e,"credential",d)}}async function ce(e){return async function(e,t){const i=e.profile??H;we(i,"request",e.allowHeldProfile);const r=le(e.address,i),s=e.now??(()=>new Date),n=e.pendingStore,o=n?await n.findLive(r,s()):void 0;let a=o?.profile===i?o:void 0;if(a&&i===$&&!Number.isFinite(Date.parse(a.serverExpiresAt??"")))throw await(n?.delete(a.requestId).catch(()=>{})),new Y("session","SESSION_INVALID");a||(a=await oe({...e,address:r}),await(n?.put(a)));const d=ee(a);if(!e.getCode)return{status:"code-requested",pending:d};const c=await e.getCode({pending:d});try{const i=await de({...e,pending:a,code:c},t),r=[];if(n)try{await n.delete(a.requestId)}catch{r.push("The pending request could not be deleted after success; it expires at its deadline.")}return{status:"issued",result:i,warnings:r}}catch(e){throw e instanceof Y&&e.recoverable||await(n?.delete(a.requestId).catch(()=>{})),e}}(e,B)}function le(e,t){if(t===$)return function(e){const t=()=>new Y("request","ADDRESS_INVALID"),i=e.trim();if(/[^\x00-\x7f]/.test(i))throw t();const r=i.toLowerCase(),s=r.split("@");if(r.length<3||r.length>254||2!==s.length||/[^\x21-\x7e]/.test(r))throw t();const[n,o]=s;if(n.length>64||!ue.test(n)||n.startsWith("+"))throw t();if(o.length>253||!o.includes(".")||!o.split(".").every(e=>e.length<=63&&pe.test(e)))throw t();return r}(e);const i=e.trim();if(i.length>254||!z.test(i))throw new Y("request","ADDRESS_INVALID");return i}var ue=/^[a-z0-9!#$%&'*+\-/=?^_`{|}~]+(\.[a-z0-9!#$%&'*+\-/=?^_`{|}~]+)*$/,pe=/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;function fe(e){return`${e}#${e.slice(8)}`}function he(e,t,i){if(i===$)return function(e,t){const i=S(e.did),r=null!==i&&"1"===i.chainId?`did:pkh:eip155:1:${_(i.address)}`:void 0;if(void 0===r||e.did!==r||"EIP191"!==e.alg||e.kid!==`${r}#blockchainAccountId`)throw new Y(t,"HOLDER_INVALID")}(e,t);if(!J.test(e.did)||"EdDSA"!==e.alg||e.kid!==fe(e.did))throw new Y(t,"HOLDER_INVALID")}function we(e,t,i){const r=Object.prototype.hasOwnProperty.call(M,e)?M[e]:void 0;if(!r||!r.enabled&&(!0!==i||e!==$))throw new Y(t,"PROFILE_UNAVAILABLE",void 0,void 0,"This SDK build doesn't enable the email verification profile.");return r}function ge(e,t){return t===$?g({type:"TinyCloudCredentialRequirement",version:1,profile:{id:t,version:1},credentialType:k,claims:{email:e},maxAgeSeconds:31536e3}):r({email:e,profile:{id:t,version:1},credentialType:k})}async function Ie(e,r,s,n,o){const a=we(e,n,o);let c;try{c=await async function(e,r,s={}){let n;try{n=new URL(r)}catch{throw new t("UNSUPPORTED_PROFILE","Discovery URL is invalid")}if("https:"!==n.protocol||!["/.well-known/opencredentials","/v1/credential-types"].includes(n.pathname)||n.search||n.hash)throw new t("UNSUPPORTED_PROFILE","Discovery URL is not an allowed catalog endpoint");const o={credentials:"omit",cache:"no-store",redirect:"error",referrerPolicy:"no-referrer",signal:s.signal};let a;try{a=await(s.fetch??globalThis.fetch.bind(globalThis))(n,o)}catch(e){throw new t("OFFLINE","Credential discovery is unavailable",{cause:e})}if(!a.ok)throw new t(503===a.status?"ISSUER_UNREADY":"OFFLINE","Credential discovery is unavailable");const c=await a.json();if("tinycloud.credentials/catalog/v1"!==c.type||"tinycloud.credentials/acquisition/v1"!==c.protocol||1!==c.catalogVersion||!Array.isArray(c.profiles))throw new t("DESCRIPTOR_INVALID","Credential catalog is invalid");for(const t of c.profiles){if("object"!=typeof t||null===t||Array.isArray(t))continue;const r=t;if(!0===r.supported&&!0===r.enabled&&("ready"===r.readiness||"degraded"===r.readiness))try{const t=h(r.descriptor);if(d(t,e)&&r.descriptorDigest===await i(t))return t}catch{}}throw new t("UNSUPPORTED_PROFILE","No available credential profile satisfies the requirement")}(r,j,{fetch:s.fetch,signal:s.signal})}catch(e){throw function(e,t,i){return t.aborted&&"TimeoutError"!==t.reason?.name?new Y(i,"CANCELED"):me(e,i,t)}(e,s.signal,n)}if(c.issuer.origin!==R.witnessOrigin||c.issuer.did!==R.issuerDid||!c.steps.some(e=>e.type===a.requiredStep))throw new Y(n,"PROFILE_UNAVAILABLE");if(await i(c)!==a.descriptorDigest)throw new Y(n,"PROFILE_UNAVAILABLE");return c}function Ee(e){return{type:"OpenCredentialsIssuerMetadata",version:1,origin:R.witnessOrigin,issuerDid:R.issuerDid,keys:e,cache:{maxAgeSeconds:3600,etag:"pinned"}}}async function De(e){return async function(e,r){const{record:s,requirement:n,holderDid:a}=e,d=s.descriptor;if(s.descriptorDigest!==R.descriptorDigest||await i(d)!==R.descriptorDigest)throw new t("VERIFICATION_FAILED","stored descriptor does not match the pinned descriptor digest");const c={type:"OpenCredentialsIssuedCredential",version:1,protocol:d.protocol,profile:s.profile,credentialType:s.credentialType,schema:s.schema,format:"vc+sd-jwt",issuerDid:s.issuerDid,issuerKid:s.issuerKid,subjectDid:s.subjectDid,holderDid:s.holderDid,claims:s.claims,claimsDigest:s.claimsDigest,descriptorDigest:s.descriptorDigest,credentialId:s.credentialId,issuedAt:s.issuedAt,notBefore:s.notBefore,expiresAt:s.expiresAt,status:s.status,credential:s.credential},l=await E({envelope:c,descriptor:d,descriptorDigest:R.descriptorDigest,requirement:n,holderDid:a,issuerMetadata:Ee(r),now:e.now,checkStatus:async e=>"none"===e.method&&e.freshnessSeconds===d.status.freshnessSeconds,signal:e.signal});if(s.holderDid!==a||s.ownerDid!==a)throw new t("HOLDER_MISMATCH","stored record belongs to another holder");if(s.credentialDigest!==l.credentialDigest)throw new t("VERIFICATION_FAILED","stored credential digest does not match the verified credential");if(s.requirementDigest!==await o(n))throw new t("VERIFICATION_FAILED","stored requirement digest does not match the requirement");if(s.recordId!==await i({credentialDigest:l.credentialDigest,holderDid:s.ownerDid}))throw new t("VERIFICATION_FAILED","stored record id does not match its credential");return l}(e,B)}function Ae(e,t){return{autoSign:async(i,r)=>{try{return await e.sign(r)}catch(e){const i=e instanceof DOMException&&("TimeoutError"===e.name||"AbortError"===e.name);if(!t||e instanceof Y||i)throw e;throw new Y("credential","SIGNATURE_REJECTED")}},holderKey:{alg:e.alg,kid:e.kid}}}function me(e,t,i){if(e instanceof Y)return e;if(e instanceof DOMException&&"TimeoutError"===e.name)return new Y(t,"NETWORK");const r=n(e),s=r.details;switch(r.code){case"ISSUER_UNREADY":return"rate_limited"===s.state?new Y(t,"RATE_LIMITED",s.retryAfterMs,r.recoverable):new Y(t,"ISSUER_UNAVAILABLE",void 0,r.recoverable);case"OFFLINE":return i?.aborted&&"TimeoutError"!==i.reason?.name?new Y(t,"CANCELED"):new Y(t,"NETWORK");case"UNSUPPORTED_PROFILE":case"UNSUPPORTED_VERSION":case"DESCRIPTOR_INVALID":return new Y(t,"PROFILE_UNAVAILABLE");case"PROOF_REJECTED":return new Y("code","CODE_REJECTED",void 0,!0);case"VERIFICATION_FAILED":return"proof_attempts_exhausted"===s.state?new Y("code","CODE_ATTEMPTS_EXHAUSTED"):"credential"===t?new Y("credential","CREDENTIAL_INVALID"):"code"===t?new Y("code","CODE_REJECTED",void 0,!1):new Y(t,"FAILED");case"HOLDER_MISMATCH":return new Y("credential","CREDENTIAL_INVALID");case"REQUEST_EXPIRED":return new Y("session","SESSION_EXPIRED");case"REQUEST_SUBSTITUTED":return new Y("session","SESSION_INVALID");case"SIGNATURE_REJECTED":return new Y("credential","SIGNATURE_REJECTED",void 0,r.recoverable);case"CANCELED":return new Y(t,"CANCELED");default:return new Y(t,"FAILED")}}function ye(){return new Y("request","HOLDER_INVALID",void 0,void 0,"The wallet signer signs only the exact account binding for this request.")}function Se(){return new Y("request","HOLDER_INVALID")}const ve=["audience","challengeNonce","completionContext","completionOrigin","credentialLifetimeSeconds","descriptorDigest","expiresAt","holderDid","issuedAt","issuer","issuerKid","jti","normalizedClaimsDigest","openerOrigin","profile","profileVersion","protocol","requestId","requirementDigest","type"],Te=/^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,_e=/^[A-Za-z0-9_-]{32}$/,Oe=/^[A-Za-z0-9_-]{43}$/,Re=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;function be(e){try{return new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(e)}catch{throw ye()}}function Ne(e,t){const i=S(e);if(null===i||"1"!==i.chainId)throw Se();const r=_(i.address),s=`did:pkh:eip155:1:${r}`;return{did:s,alg:"EIP191",kid:`${s}#blockchainAccountId`,sign:async e=>{const i=new Uint8Array(e);!function(e,t){const i=be(e);let r,s;try{r=JSON.parse(i),s=p(r)}catch{throw ye()}if(s!==i||"object"!=typeof r||null===r||Array.isArray(r))throw ye();const n=r;if(Object.keys(n).sort().join()!==ve.join())throw ye();for(const e of ve)if("profileVersion"!==e&&"credentialLifetimeSeconds"!==e&&("string"!=typeof n[e]||""===n[e]))throw ye();const o=e=>n[e];if(Object.keys(b).some(e=>n[e]!==b[e])||!v(n.holderDid,t)||!Te.test(o("jti"))||!_e.test(o("requestId"))||!_e.test(o("challengeNonce"))||!Oe.test(o("requirementDigest"))||!Oe.test(o("normalizedClaimsDigest"))||!Re.test(o("issuedAt"))||!Re.test(o("expiresAt"))||Date.parse(o("expiresAt"))-Date.parse(o("issuedAt"))!==6e5)throw ye()}(function(e){const t=(new TextEncoder).encode(D);if(e.length<=t.length+1||0!==e[t.length])throw ye();for(let i=0;i<t.length;i++)if(e[i]!==t[i])throw ye();return e.subarray(t.length+1)}(i),s);const n=be(i),o=await t(i),a=o[64];if(65!==o.length||27!==a&&28!==a)throw Se();if(!await I(n,function(e){return`0x${Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}`}(o),r))throw Se();return o}}}function Ce(e,t){return e.getTime()-t.getTime()>6e5}const Le="This app can't read held credentials: the session may lack kv get and list on v1/held/ (skipPrefix), or may need to sign in again.",qe="permission_denied";function Ue(e){let t="object"==typeof e&&null!==e&&"error"in e?e.error:void 0,i=!1;for(let e=0;e<8&&"object"==typeof t&&null!==t;e+=1){const e=t,r=e.meta,s=[e.status,e.statusCode,"object"==typeof r&&null!==r?r.status:void 0].find(e=>"number"==typeof e&&Number.isInteger(e)&&e>=400&&e<=599);if(void 0!==s)return 401===s||403===s;"AUTH_UNAUTHORIZED"===e.code&&(i=!0),t=e.cause}return i}function xe(e){const i=S(e);if(null===i)throw new t("ACTIVE_SESSION_REQUIRED","Held credentials require a did:pkh:eip155 account owner");if("1"!==i.chainId)throw new t("ACTIVE_SESSION_REQUIRED","Held credentials require an Ethereum mainnet (chain 1) account owner");return`did:pkh:eip155:1:${_(i.address)}`}function Fe(e){return`v1/held/${T(e)}/`}function Pe(e,t){return`${Fe(e)}${t}`}function ke(e){if("object"!=typeof e||null===e)return!1;const t=e;return"TinyCloudHeldCredential"===t.type&&1===t.version&&"string"==typeof t.ownerDid&&"string"==typeof t.recordId&&"string"==typeof t.credentialDigest&&"string"==typeof t.credential&&"string"==typeof t.storedAt}function Ve(e,t,i){return{issuerSet:e.issuerSet,acceptedIssuers:e.acceptedIssuers,didMethods:e.didMethods,now:t,owner:i}}async function je(e){return{type:"TinyCloudHeldStorageReceipt",version:1,ownerDid:e.ownerDid,recordId:e.recordId,recordDigest:await i(e),storedAt:e.storedAt}}async function Be(e){const r=e.now??new Date,s=xe(e.ownerDid);let n;try{n=O(e.sdJwt,Ve(e,r,s))}catch(e){throw function(e){if(!(e instanceof A))return e;const i="nonce-account-mismatch"===e.code?"HOLDER_MISMATCH":"VERIFICATION_FAILED";return new t(i,e.message,{cause:e})}(e)}const o=e.sdJwt;if("string"!=typeof o)throw new t("VERIFICATION_FAILED","Held credential must be an SD-JWT string");if("string"!=typeof n.claims.email)throw new t("VERIFICATION_FAILED","Held credential must disclose an email claim");if(!Ce(n.expiresAt,r))throw new t("VERIFICATION_FAILED","Held credential expires within the reuse margin");const a=await i(o),d=await i({credentialDigest:a,holderDid:s}),c={type:"TinyCloudHeldCredential",version:1,ownerDid:s,recordId:d,credentialDigest:a,credential:o,storedAt:r.toISOString()},l=await async function(e,i,r){const s=(e=!1)=>new t("VERIFIED_NOT_SAVED","Held credential could not be confirmed in storage",e?{state:qe}:{}),n=await e.batchPut([{key:i,value:r}]).catch(()=>{});if(!0!==n?.ok)throw s(void 0!==n&&Ue(n));const o=await e.get(i).catch(()=>{});if(void 0!==o&&!o.ok&&Ue(o))throw s(!0);const a=!0===o?.ok?o.data.data:void 0;if(!ke(a)||a.recordId!==r.recordId||a.credentialDigest!==r.credentialDigest||a.credential!==r.credential||!v(a.ownerDid,r.ownerDid))throw s();return a}(e.kv,Pe(s,d),c);return{record:l,receipt:await je(l),verified:n}}async function He(e,i,r,s,n){const o=await e.get(i);if(!o.ok&&Ue(o))throw new t("PERMISSION_DENIED",Le);return Me(o.ok?o.data.data:void 0,i,r,s,n)}async function Me(e,t,r,s,n){if(!ke(e))return{kind:"invalid"};if(!v(e.ownerDid,r))return{kind:"invalid"};const o=await i(e.credential),a=await i({credentialDigest:o,holderDid:r});if(e.credentialDigest!==o||e.recordId!==a||t!==Pe(r,a))return{kind:"invalid"};let d;try{d=O(e.credential,Ve(s,n,r))}catch(e){if(!(e instanceof A)||"bad-config"===e.code)throw e;return{kind:"expired"===e.code?"expired":"invalid"}}const c=d.claims.email;return"string"!=typeof c?{kind:"invalid"}:{kind:"verified",email:c,match:{record:e,verified:d,recordId:a,email:c,issuedAt:d.issuedAt,expiresAt:d.expiresAt,issuer:d.issuer}}}class Ke extends t{}async function $e(e,i){const r=[];let s;for(let n=0;n<50;n+=1){const n=await e.list(void 0===s?{prefix:i}:{prefix:i,cursor:s});if(!n.ok){if(Ue(n))throw new t("PERMISSION_DENIED",Le);return}if(r.push(...n.data.keys),!n.data.truncated)return[...new Set(r)];const o=n.data.nextCursor;if(void 0===o||""===o)throw new t("VERIFICATION_FAILED","Held listing is truncated without a continuation cursor");s=o}throw new Ke("VERIFICATION_FAILED","Held listing exceeds the page limit")}async function Qe(e){const t=e.now??new Date,i=xe(e.ownerDid),r=await $e(e.kv,Fe(i));if(void 0===r)return;const s=e.email.replace(/[A-Z]+/g,e=>e.toLowerCase());let n;for(const o of r){const r=await He(e.kv,o,i,e,t);if("verified"!==r.kind||r.email!==s)continue;const a=r.match.verified.expiresAt.getTime();Ce(r.match.verified.expiresAt,t)&&(void 0===n||a>n.verified.expiresAt.getTime())&&(n=r.match)}return n}async function Je(e){const i=e.now??new Date,r=xe(e.ownerDid),s=await $e(e.kv,Fe(r));if(void 0===s)throw new t("OFFLINE","Held credentials could not be listed");const n=[];for(const o of s){const s=await e.kv.get(o);if(!s.ok){if("error"in s&&"KV_NOT_FOUND"===s.error.code)continue;if(Ue(s))throw new t("PERMISSION_DENIED",Le);throw new t("OFFLINE","A held credential could not be read")}let a;try{a=await Me(s.data.data,o,r,e,i)}catch(e){if(e instanceof A&&"bad-config"===e.code)throw e;continue}"verified"===a.kind&&Ce(a.match.verified.expiresAt,i)&&n.push(a.match)}return n.sort((e,t)=>{const i=t.issuedAt.getTime()-e.issuedAt.getTime();return 0!==i?i:e.recordId<t.recordId?-1:e.recordId>t.recordId?1:0})}const ze="tinycloud.email-held/v1",Xe=3e5;class Ge extends Error{constructor(e,t){super(t),this.retryable=!1,this.name="HeldSourceError",this.code=e}}async function We(e){return async function(e,i){const{kv:r,address:s,holder:n,sessionDid:o,getCode:d,pendingStore:c,fetch:l,signal:u,now:p,allowHeldProfile:f,...h}=e,w=p??(()=>new Date),g=xe(n.did);if(void 0!==o&&!v(o,g))throw new t("HOLDER_MISMATCH","Held acquisition holder must be the session account");const I=!0===f;let E;try{E=await async function(e,i,r,s,n){const o=s.trim().replace(/[A-Z]+/g,e=>e.toLowerCase()),a=async()=>function(e){let t;for(const i of e)(void 0===t||i.expiresAt.getTime()>t.expiresAt.getTime())&&(t=i);return t}((await async function(e,i,r,s){try{return await Je({...i,kv:e,ownerDid:r,now:s})}catch(e){if(e instanceof t||e instanceof A)throw e;throw new t("OFFLINE","Held credentials could not be read",{cause:e})}}(e,i,r,new Date(n().getTime()+Xe))).filter(e=>e.email===o));try{return await a()}catch(e){if(!(e instanceof Ke))throw e}try{return await async function(e){const i=e.now??new Date,r=xe(e.ownerDid),s=await $e(e.kv,Fe(r));if(void 0===s)return[];const n=[],o=new Map;for(const t of s){const s=await He(e.kv,t,r,e,i);if("invalid"===s.kind)continue;if("expired"===s.kind){n.push(t);continue}const a={key:t,recordId:s.match.record.recordId,expiresAt:s.match.verified.expiresAt.getTime()},d=o.get(s.email);if(void 0===d){o.set(s.email,a);continue}const c=a.expiresAt>d.expiresAt||a.expiresAt===d.expiresAt&&a.recordId>d.recordId;o.set(s.email,c?a:d),n.push(c?d.key:a.key)}const a=[];for(const i of n){const r=await e.kv.delete(i);if(!r.ok&&Ue(r))throw new t("PERMISSION_DENIED","This app can't delete held credentials: the session may lack kv del on v1/held/ (skipPrefix), or may need to sign in again.");r.ok&&a.push(i)}return a}({...i,kv:e,ownerDid:r,now:n()}),await a()}catch(e){if(e instanceof Ke)throw new Ge("held-store-listing-limit","Saved held credentials list is too long to read; clear old ones");throw e}}(r,h,g,s,w)}catch(e){if(I||!(e instanceof t)||"OFFLINE"!==e.code&&"PERMISSION_DENIED"!==e.code)throw e}if(void 0!==E)return{credential:E.record.credential,holderDid:g,expiresAt:E.verified.expiresAt};I&&function(e,i){const r=()=>new t("VERIFICATION_FAILED","The issuer policy does not accept the held credential issuer"),{issuerDid:s,issuerKid:n}=R;if(!Array.isArray(e.acceptedIssuers)||!e.acceptedIssuers.some(e=>e.issuerDid===s&&(void 0===e.kid||e.kid===n)))throw r();if(!m.is(e.issuerSet))throw r();const o=e.issuerSet.resolveIssuer(s,n),a=i.getTime();if(!o||!o.vcts.includes("opencredentials.email/v1")||!o.profiles.includes(ze)||a<o.notBefore||null!==o.retiredAt&&a>=o.retiredAt||null!==o.notAfter&&a>=o.notAfter)throw r()}(h,w());const D=await i({address:s,holder:n,profile:ze,getCode:d,pendingStore:Ye(c,g,w),fetch:l,signal:u,now:w,allowHeldProfile:f});if("issued"!==D.status)throw new t("PROOF_REJECTED","Held acquisition did not issue a credential");const y=D.result.envelope.credential,S=w().getTime(),T=function(e){try{const t=JSON.parse((new TextDecoder).decode(a(e.split("~")[0].split(".")[1]))),i="object"==typeof t&&null!==t&&"iat"in t?t.iat:void 0;if("number"==typeof i&&Number.isSafeInteger(i))return 1e3*i}catch{}throw new t("VERIFICATION_FAILED","Issued credential is not readable")}(y);if(T-S>Xe)throw new t("VERIFICATION_FAILED","client clock is more than 5 minutes behind the issuer");let _;try{_=await Be({...h,kv:r,ownerDid:g,sdJwt:y,now:new Date(Math.max(S,T))})}catch(e){const i=e instanceof t&&e.details.state===qe;throw new t("VERIFIED_NOT_SAVED","Verified held credential could not be stored",i?{state:qe}:{})}return{credential:y,holderDid:g,expiresAt:_.verified.expiresAt}}(e,ce)}function Ye(e,t,i){if(void 0===e)return;const r=e=>void 0!==e&&e.profile===ze&&v(e.holderDid,t);return{async findLive(t,i){const s=await e.findLive(t,i);return r(s)?s:void 0},put:t=>e.put(t),async delete(t){r(await e.get(t,i()))&&await e.delete(t)},async get(t,i){const s=await e.get(t,i);return r(s)?s:void 0}}}export{Y as EmailProofError,P as OpenCredentialsHttpTransport,ce as acquireEmailProof,We as acquireHeldCredential,ae as completeEmailProof,Ne as createAccountHolderSigner,Z as createEd25519HolderSigner,re as createMemoryEmailProofPendingStore,Qe as findHeldCredential,L as interpretCredentialFlow,Je as listHeldEmailCredentials,oe as requestEmailProofCode,Be as storeHeldCredential,De as verifyStoredEmailProof};
|
|
1
|
+
import{ACCOUNT_HOLDER_BINDING_DOMAIN as e,CredentialError as t,canonicalDigest as i,createEmailCredentialRequirement as r,credentialEndpointPath as s,credentialError as n,credentialRequirementDigest as o,decodeBase64Url as a,descriptorSatisfiesRequirement as d,encodeBase64Url as c,holderBindingCanonicalBytes as l,holderBindingSigningBytes as u,jcsCanonicalize as p,sha256Base64Url as f,validateCredentialFlowDescriptor as h,validateCredentialHolderBinding as w,validateCredentialRequirement as g,verifyEip191MessageSignature as I,verifyIssuedCredential as E}from"@tinycloud/sdk-core";import{ACCOUNT_BINDING_DOMAIN as D,HeldCredentialError as A,IssuerSet as m,parseIssuerSet as S,parsePkhDid as y,pkhPrincipalsEqual as v,registryKey as T,toChecksumAddress as _,verifyHeldEmailCredential as O}from"@tinycloud/sdk-core/held-credentials";var R=Object.freeze({witnessOrigin:"https://witness.credentials.org",issuerDid:"did:web:issuer.credentials.org",issuerKid:"did:web:issuer.credentials.org#controller",issuerX:"eEJI4xEobto4HtQ7Pg9R1vBOwcpfGRTlXDG5QfqLnGQ",descriptorDigest:"1tg-qphmKBVtNwzVg9xyz-xxqt_xtMXAsQyXw46m8S0"}),N=Object.freeze({type:e,protocol:"tinycloud.credentials/acquisition/v1",profile:"tinycloud.email-held/v1",profileVersion:1,descriptorDigest:"dc3_DuvzipXwYkTfjKqTaK1c3VS0YSPnaBsYSQriC0w",issuer:R.issuerDid,issuerKid:R.issuerKid,audience:"tinycloud://credentials",openerOrigin:"https://localhost",completionOrigin:"https://localhost",completionContext:"sdk-acquisition",credentialLifetimeSeconds:31536e3}),b=()=>new t("REQUEST_SUBSTITUTED","Holder binding was substituted"),C=(e,t)=>new Promise((i,r)=>{const s=setTimeout(i,e);t?.addEventListener("abort",()=>{clearTimeout(s),r(new DOMException("Aborted","AbortError"))},{once:!0})});async function L(e){const r="account_is_subject"===e.descriptor.subjectRelationship;if(r&&!0!==e.allowAccountSubject)throw new t("UNSUPPORTED_PROFILE","The held credential profile requires an explicit opt-in");const s=new Map(e.descriptor.steps.map(e=>[e.type,e])),n=new Set;let o="";const a=async r=>{const s=w(r);if(s.requestId!==e.requestId||s.descriptorDigest!==e.descriptorDigest||s.requirementDigest!==e.requirementDigest||s.holderDid!==e.holderDid||s.issuer!==e.descriptor.issuer.did||s.issuerKid!==e.descriptor.issuer.kid||s.profile!==e.descriptor.profile||s.openerOrigin!==e.openerOrigin||s.completionOrigin!==e.openerOrigin||"tinycloud://credentials"!==s.audience)throw new t("REQUEST_SUBSTITUTED","Holder binding was substituted");const n=e.descriptor.holderBinding.alg;if(s.type!==e.descriptor.holderBinding.domain||"EIP191"===n&&!e.transport.challengeNonce)throw new t("REQUEST_SUBSTITUTED","Holder binding was substituted");return"EIP191"===n&&await async function(e,t){const{descriptor:r}=t;if("EIP191"!==r.holderBinding.alg||e.type!==r.holderBinding.domain||e.requestId!==t.requestId||e.descriptorDigest!==t.descriptorDigest||e.requirementDigest!==t.requirementDigest||e.holderDid!==t.holderDid||e.issuer!==r.issuer.did||e.issuerKid!==r.issuer.kid||e.profile!==r.profile||e.openerOrigin!==t.openerOrigin||e.completionOrigin!==t.openerOrigin||e.audience!==N.audience||e.completionContext!==N.completionContext||e.type!==N.type||e.protocol!==N.protocol||e.profile!==N.profile||e.profileVersion!==N.profileVersion||e.descriptorDigest!==N.descriptorDigest||e.issuer!==N.issuer||e.issuerKid!==N.issuerKid||e.openerOrigin!==N.openerOrigin||e.completionOrigin!==N.completionOrigin||e.credentialLifetimeSeconds!==N.credentialLifetimeSeconds)throw b();if(void 0===t.challengeNonce||e.challengeNonce!==t.challengeNonce)throw b();if(e.normalizedClaimsDigest!==await i(t.requirement.claims))throw b();const s=Date.parse(e.expiresAt);if(void 0===t.serverExpiresAt||s!==Date.parse(t.serverExpiresAt)||Date.parse(e.issuedAt)!==s-6e5)throw b()}(s,{descriptor:e.descriptor,requirement:e.requirement,requestId:e.requestId,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,holderDid:e.holderDid,openerOrigin:e.openerOrigin,challengeNonce:e.transport.challengeNonce(e.requestId),serverExpiresAt:e.expiresAt}),s},d=async()=>{r&&void 0===e.transport.signedBinding?.(e.requestId)&&await a(await e.transport.holderBinding(e.requestId,e.verifier,e.signal))};for(;;){e.signal?.throwIfAborted();const i=await e.transport.state(e.requestId,e.verifier,e.signal);if(i.requestId!==e.requestId)throw new t("REQUEST_SUBSTITUTED","Credential request identity changed");if("expired"===i.state)throw new t("REQUEST_EXPIRED","Credential request expired",{state:i.state,correlationId:i.correlationId});if("canceled"===i.state)throw new t("CANCELED","Credential request was canceled",{state:i.state,correlationId:i.correlationId});if("issuer_unready"===i.state)throw new t("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:i.retryAfterMs,state:i.state,correlationId:i.correlationId});if("complete"===i.state)return void await d();if("ready_to_issue"===i.state||"issued"===i.state){await d(),"ready_to_issue"!==i.state||n.has("issue")?await(e.onWait?.()??C(i.retryAfterMs??50,e.signal)):(await e.transport.issue(e.requestId,e.verifier,e.signal),n.add("issue"));continue}const r=i.nextStep;if(!r){await(e.onWait?.()??C(i.retryAfterMs??50,e.signal));continue}const l=s.get(r.type);if(r.id!==r.type||!l||l.type!==r.type||l.version!==r.version)throw new t("REQUEST_SUBSTITUTED","Server selected an undeclared credential step");if(n.has(r.id)||i.transitionId===o)await(e.onWait?.()??C(i.retryAfterMs??50,e.signal));else{if(o=i.transitionId,"holder_signature"===r.type){e.onProgress?.({state:"signing",stepId:r.id,correlationId:i.correlationId});const s=await a(await e.transport.holderBinding(e.requestId,e.verifier,e.signal)),n=e.descriptor.holderBinding.alg;if("EIP191"===n!=("EIP191"===e.signing.holderKey?.alg))throw new t("REQUEST_SUBSTITUTED","Holder binding was substituted");const o=u(s);let d=await(e.signing.autoSign?.(s,o,e.signal));if(void 0===d){if(!e.signing.requestApproval)throw new t("SIGNATURE_REJECTED","OpenKey approval is required");try{d=await e.signing.requestApproval(s,o,e.signal)}catch(e){if(e instanceof t)throw e;throw new t("SIGNATURE_REJECTED","OpenKey approval was rejected",{cause:e})}}if(!(d instanceof Uint8Array)||0===d.length)throw new t("SIGNATURE_REJECTED","OpenKey signature is invalid");await e.transport.submitHolderSignature(e.requestId,e.verifier,"EIP191"===n?`0x${Array.from(d,e=>e.toString(16).padStart(2,"0")).join("")}`:c(d),e.signal,e.signing.holderKey)}else{e.onProgress?.({state:"collect_input"===r.type?"collecting":"proving",stepId:r.id,correlationId:i.correlationId});const s=e.handlers?.[r.type],n=e.proofHandler;if(!s&&!n){await(e.onWait?.()??C(i.retryAfterMs??50,e.signal));continue}if(!0===r.constraints.challengeRequired&&await e.transport.beginStep(e.requestId,e.verifier,r.type,e.signal),s){const t=await s({descriptor:e.descriptor,requirement:e.requirement,stepId:r.id,constraints:r.constraints,signal:e.signal});await e.transport.submitStep(e.requestId,e.verifier,r.id,t,e.signal)}else{let i;for(let s=1;;s+=1){const o=await n({stepId:r.id,constraints:r.constraints,display:{title:e.descriptor.display.title,description:e.descriptor.display.description,consent:e.descriptor.display.consent,progressLabel:e.descriptor.accessibility.progressLabel,errorLiveRegion:e.descriptor.accessibility.errorLiveRegion},inputs:e.descriptor.inputs.map(({id:e,label:t,schema:i})=>({id:e,label:t,schema:i})),...void 0===i?{}:{feedback:i},signal:e.signal});try{await e.transport.submitStep(e.requestId,e.verifier,r.id,o,e.signal);break}catch(n){if(!(n instanceof t)||"PROOF_REJECTED"!==n.code)throw n;const o=e.descriptor.lifecycle.maxProofAttempts-s;if("mailbox_otp"!==r.type||o<=0)throw new t("VERIFICATION_FAILED","The proof was not accepted",{state:o<=0?"proof_attempts_exhausted":"proof_rejected",cause:n});i={kind:"rejected",attemptsRemaining:o}}}}}n.add(r.id)}}}function q(e,i){if("object"!=typeof e||null===e||Array.isArray(e))throw new t("VERIFICATION_FAILED",`${i} is invalid`);return e}function U(e,i){if("string"!=typeof e||!/^[A-Za-z0-9_-]{16,128}$/.test(e))throw new t("REQUEST_SUBSTITUTED",`${i} is invalid`);return e}function x(e,i){if("string"!=typeof e||!Number.isFinite(Date.parse(e)))throw new t("VERIFICATION_FAILED",`${i} is invalid`);return new Date(e).toISOString()}var F=new Set(["REQUEST_EXPIRED","ISSUER_UNREADY","UNSUPPORTED_PROFILE","UNSUPPORTED_VERSION","SIGNATURE_REJECTED"]),P=class{constructor(e,i=globalThis.fetch.bind(globalThis),r={}){if(this.descriptor=e,this.fetchFn=i,this.options=r,this.nonces=new Map,this.bindings=new Map,"account_is_subject"===e.subjectRelationship&&!0!==r.allowAccountSubject)throw new t("UNSUPPORTED_PROFILE","The held credential profile requires an explicit opt-in")}url(e,t){return new URL(s(e,t),this.descriptor.issuer.origin).href}async request(e,i){let r;try{const t={method:i.method??"GET",credentials:"omit",cache:"no-store",redirect:"error",referrerPolicy:"no-referrer",signal:i.signal,headers:{accept:"application/json",...void 0===i.body?{}:{"content-type":"application/json"},...void 0===i.verifier?{}:{authorization:`Bearer ${i.verifier}`}},...void 0===i.body?{}:{body:JSON.stringify(i.body)}};r=await this.fetchFn(this.url(e,i.id),t)}catch(e){if(e instanceof DOMException&&"AbortError"===e.name)throw new t("CANCELED","Credential acquisition was canceled",{cause:e});throw new t("OFFLINE","OpenCredentials is unavailable",{cause:e})}if(!r.ok){let e;try{e=await r.json()}catch{e=void 0}const i=function(e,i,r){if("object"!=typeof e||null===e||Array.isArray(e))return;const s=e;if("code,correlationId,recoverable,state,type"!==Object.keys(s).sort().join(",")||"tinycloud.credentials/error/v1"!==s.type||"string"!=typeof s.code||"boolean"!=typeof s.recoverable||"string"!=typeof s.state||"string"!=typeof s.correlationId)return;if("PROOF_REJECTED"===s.code)return s.recoverable?new t("PROOF_REJECTED","The proof was not accepted",{state:s.state,correlationId:s.correlationId}):new t("VERIFICATION_FAILED","The proof attempt limit was reached",{state:"proof_attempts_exhausted",correlationId:s.correlationId});if("RATE_LIMITED"===s.code)return new t("ISSUER_UNREADY","Too many verification codes were requested",{state:"rate_limited",correlationId:s.correlationId,retryAfterMs:1e3*Number(i.headers.get("retry-after"))||void 0,recoverable:r?s.recoverable:void 0});if("CHALLENGE_EXPIRED"===s.code)return new t("REQUEST_EXPIRED","The credential challenge expired",{state:s.state,correlationId:s.correlationId,recoverable:r?s.recoverable:void 0});if("DESCRIPTOR_MISMATCH"===s.code&&(s.code="UNSUPPORTED_PROFILE"),!F.has(s.code))return;const n=s.code;return new t(n,`OpenCredentials rejected the request: ${n}`,{state:s.state,correlationId:s.correlationId,retryAfterMs:1e3*Number(i.headers.get("retry-after"))||void 0,recoverable:r?s.recoverable:void 0})}(e,r,!0===this.options.honorServerRecoverable);if(i)throw i;if(410===r.status)throw new t("REQUEST_EXPIRED","Credential request expired");if(409===r.status)throw new t("REQUEST_SUBSTITUTED","Credential request was replayed or substituted");if(503===r.status)throw new t("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:1e3*Number(r.headers.get("retry-after"))||void 0});throw new t("VERIFICATION_FAILED","OpenCredentials rejected the request")}if(204!==r.status)try{return await r.json()}catch(e){throw new t("VERIFICATION_FAILED","OpenCredentials response is invalid",{cause:e})}}async create(e){const i=q(await this.request("request",{method:"POST",body:{protocol:e.descriptor.protocol,profile:e.descriptor.profile,profileVersion:e.descriptor.profileVersion,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,holderDid:e.holderDid,inputs:e.inputs??e.requirement.claims,audience:N.audience,openerOrigin:e.openerOrigin,completionOrigin:e.openerOrigin,completionContext:N.completionContext,completionVerifierChallenge:e.completionVerifierChallenge},signal:e.signal}),"create response");if("tinycloud.credentials/acquisition-request/v1"!==i.type||i.protocol!==e.descriptor.protocol||"challenge"!==i.next||"challenge"!==i.endpoint)throw new t("VERIFICATION_FAILED","create response is invalid");const r=U(i.requestId,"requestId");return{requestId:r,locator:r,expiresAt:x(i.expiresAt,"expiresAt"),correlationId:r}}challengeNonce(e){return this.nonces.get(e)}signedBinding(e){return this.bindings.get(e)}proofStep(){return this.descriptor.steps.some(e=>"mailbox_otp"===e.type)?"mailbox_otp":"collect_input"}async state(e,i,r){const s=q(await this.request("state",{id:e,verifier:i,signal:r}),"state response");if("tinycloud.credentials/acquisition-state/v1"!==s.type||s.requestId!==e||s.profile!==this.descriptor.profile||1!==s.profileVersion)throw new t("REQUEST_SUBSTITUTED","Credential state response is substituted");const n={type:"OpenCredentialsAcquisitionState",version:1,requestId:e,transitionId:`${String(s.state)}:${String(s.resultPreviouslyRead??!1)}`,correlationId:e};if("challenge_required"===s.state){const e=this.proofStep();return{...n,state:"pending",nextStep:{id:e,type:e,version:1,constraints:{challengeRequired:!0}}}}if("account_is_subject"===this.descriptor.subjectRelationship&&("proof_required"===s.state||"holder_binding_required"===s.state||"holder_signature_required"===s.state||"ready_to_issue"===s.state||"issued"===s.state)){const i=s.challengeNonce,r=this.nonces.get(e);if("string"!=typeof i||""===i||void 0!==r&&r!==i)throw new t("REQUEST_SUBSTITUTED","Credential challenge nonce is missing or changed");this.nonces.set(e,U(i,"challengeNonce"))}if("proof_required"===s.state){const t=this.proofStep();return"account_is_subject"!==this.descriptor.subjectRelationship&&this.nonces.set(e,U(s.challengeNonce,"challengeNonce")),{...n,state:"pending",nextStep:{id:t,type:t,version:1,constraints:{}}}}if("holder_binding_required"===s.state||"holder_signature_required"===s.state)return{...n,state:"pending",nextStep:{id:"holder_signature",type:"holder_signature",version:1,constraints:{}}};if("ready_to_issue"===s.state)return{...n,state:"ready_to_issue"};if("issued"===s.state)return{...n,state:"complete"};throw new t("REQUEST_SUBSTITUTED","Credential state is unsupported")}async beginStep(e,i,r,s){const n=this.proofStep();if(r!==n)throw new t("REQUEST_SUBSTITUTED","Credential challenge step is substituted");const o=q(await this.request("challenge",{id:e,verifier:i,method:"POST",body:{step:n,stepVersion:1},signal:s}),"challenge response");if("tinycloud.credentials/challenge/v1"!==o.type||o.step!==n||1!==o.stepVersion)throw new t("REQUEST_SUBSTITUTED","Credential challenge is substituted");this.nonces.set(e,U(o.challengeNonce,"challengeNonce"))}async submitStep(e,i,r,s,n){const o=this.proofStep();if(r!==o)throw new t("REQUEST_SUBSTITUTED","Credential proof step is substituted");const a=this.nonces.get(e);if(!a)throw new t("REQUEST_SUBSTITUTED","Credential challenge is missing");await this.request("proof",{id:e,verifier:i,method:"POST",body:{step:o,stepVersion:1,challengeNonce:a,proof:s},signal:n})}async holderBinding(e,i,r){const s=q(await this.request("holder_binding",{id:e,verifier:i,signal:r}),"holder binding response");if("tinycloud.credentials/holder-binding-request/v1"!==s.type||s.signingDomain!==this.descriptor.holderBinding.domain||s.alg!==this.descriptor.holderBinding.alg||"string"!=typeof s.canonical)throw new t("REQUEST_SUBSTITUTED","Holder binding response is invalid");const n=w(s.binding);if(n.type!==s.signingDomain)throw new t("REQUEST_SUBSTITUTED","Holder binding type does not match its signing domain");if(c(l(n))!==s.canonical)throw new t("REQUEST_SUBSTITUTED","Holder binding canonical bytes were substituted");return this.bindings.set(e,n),n}async submitHolderSignature(e,i,r,s,n){const o=this.bindings.get(e);if(!o)throw new t("REQUEST_SUBSTITUTED","Holder binding was not retrieved");if("EIP191"===this.descriptor.holderBinding.alg&&!n)throw new t("REQUEST_SUBSTITUTED","An account holder must name its key and algorithm");const a=n?.alg??"EdDSA",d=n?.kid??`${o.holderDid}#${o.holderDid.replace("did:key:","")}`;await this.request("holder_signature",{id:e,verifier:i,method:"POST",body:{alg:a,kid:d,signature:r},signal:s})}async issue(e,t,i){await this.request("issue",{id:e,verifier:t,method:"POST",signal:i})}async result(e,r,s){const n=q(await this.request("result",{id:e,verifier:r,signal:s}),"result response");if("tinycloud.credentials/result/v1"!==n.type||n.protocol!==this.descriptor.protocol||n.profile!==this.descriptor.profile||1!==n.profileVersion||"vc+sd-jwt"!==n.format||n.descriptorDigest!==await i(this.descriptor)||n.issuer!==this.descriptor.issuer.did||n.issuerKid!==this.descriptor.issuer.kid||"string"!=typeof n.credential||await f(n.credential)!==n.credentialDigest)throw new t("VERIFICATION_FAILED","Issued result metadata is invalid");const o=q(n.holderBinding,"result holder binding");if(n.subject!==o.did||o.signingDomain!==this.descriptor.holderBinding.domain)throw new t("HOLDER_MISMATCH","Issued holder binding is invalid");const d=q(n.claims,"result claims"),c={};for(const[e,i]of Object.entries(d)){if("string"!=typeof i)throw new t("VERIFICATION_FAILED","Issued claims are invalid");c[e]=i}const l=q(n.validity,"result validity"),u=function(e){const i=e.split("~",1)[0]?.split(".")[1];if(!i)throw new t("VERIFICATION_FAILED","Issued SD-JWT is invalid");try{return q(JSON.parse((new TextDecoder).decode(a(i))),"SD-JWT payload")}catch(e){if(e instanceof t)throw e;throw new t("VERIFICATION_FAILED","Issued SD-JWT is invalid",{cause:e})}}(n.credential);if("string"!=typeof u.jti)throw new t("VERIFICATION_FAILED","Credential id is invalid");const p=x(l.issuedAt,"issuedAt"),h=x(l.expiresAt,"expiresAt"),w=q(n.status,"result status");if("none"!==w.type||w.freshnessSeconds!==this.descriptor.status.freshnessSeconds)throw new t("VERIFICATION_FAILED","Credential status is invalid");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:n.issuer,issuerKid:n.issuerKid,subjectDid:n.subject,holderDid:n.subject,claims:c,claimsDigest:await i(c),descriptorDigest:n.descriptorDigest,credentialId:u.jti,issuedAt:p,notBefore:p,expiresAt:h,status:{method:"none",freshnessSeconds:w.freshnessSeconds},credential:n.credential}}async issuerMetadata(e){return await this.request("issuer_metadata",{signal:e})}async checkStatus(e,t){return"none"===e.method&&e.freshnessSeconds===this.descriptor.status.freshnessSeconds}},k={id:"opencredentials.email/v1",version:1},V=9e5,j=`${R.witnessOrigin}/.well-known/opencredentials`,M=[{kid:R.issuerKid,alg:"EdDSA",jwk:{kty:"OKP",crv:"Ed25519",x:R.issuerX},validFrom:"2020-01-01T00:00:00Z",validUntil:"2100-01-01T00:00:00Z"}],B="tinycloud.email-proof/v1",H={"tinycloud.email-proof/v1":{descriptorDigest:R.descriptorDigest,requiredStep:"mailbox_otp",enabled:!0},"tinycloud.email-held/v1":{descriptorDigest:N.descriptorDigest,requiredStep:"mailbox_otp",enabled:!1}},K=N.openerOrigin,$="tinycloud.email-held/v1",Q=3e5,J=/^did:key:z6Mk[^#]+$/,z=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,X=Symbol.for("nodejs.util.inspect.custom"),G={ADDRESS_INVALID:!1,HOLDER_INVALID:!1,CODE_INVALID:!0,RATE_LIMITED:!0,ISSUER_UNAVAILABLE:!0,NETWORK:!0,PROFILE_UNAVAILABLE:!1,CODE_REJECTED:!0,CODE_ATTEMPTS_EXHAUSTED:!1,SIGNATURE_REJECTED:!0,CREDENTIAL_INVALID:!1,SESSION_EXPIRED:!1,SESSION_INVALID:!1,CLIENT_CLOCK_SKEW:!1,CANCELED:!1,FAILED:!1},W={ADDRESS_INVALID:"Email address is invalid.",HOLDER_INVALID:"Holder must be a did:key Ed25519 identifier.",CODE_INVALID:"Verification code must be 8 digits.",ISSUER_UNAVAILABLE:"Email verification is unavailable right now.",NETWORK:"Could not reach the email verification service.",PROFILE_UNAVAILABLE:"The witness does not offer the email verification profile.",CODE_REJECTED:"Verification code was not accepted.",CODE_ATTEMPTS_EXHAUSTED:"Too many wrong codes. Request a new code.",SIGNATURE_REJECTED:"Holder signature was rejected.",CREDENTIAL_INVALID:"Issued credential failed verification.",SESSION_EXPIRED:"Email verification request expired. Request a new code.",SESSION_INVALID:"Email verification request is no longer valid. Request a new code.",CLIENT_CLOCK_SKEW:"Your device clock is more than 5 minutes behind. Correct it and try again.",CANCELED:"Email verification was canceled.",FAILED:"Email verification failed."},Z=class extends Error{constructor(e,t,i,r=G[t],s){super(s??("RATE_LIMITED"===t?function(e){const t="Too many codes were requested for this address.";if(void 0===e||!Number.isFinite(e)||e<=0)return`${t} Try again in about an hour.`;const i=Math.max(1,Math.ceil(e/6e4));return`${t} Try again in ${i} ${1===i?"minute":"minutes"}.`}(i):W[t])),this.name="EmailProofError",this.step=e,this.code=t,this.retryAfterMs=i,this.recoverable=r}};function Y(e,t){const i=e.indexOf("#"),r=-1===i?e:e.slice(0,i);if(-1!==i&&e.slice(i+1)!==r.slice(8))throw new Z("request","HOLDER_INVALID");if(!J.test(r))throw new Z("request","HOLDER_INVALID");return{did:r,alg:"EdDSA",kid:fe(r),sign:t}}function ee(e){const t={type:e.type,version:e.version,profile:e.profile,address:e.address,requestId:e.requestId,holderDid:e.holderDid,descriptorDigest:e.descriptorDigest,requirementDigest:e.requirementDigest,openerOrigin:e.openerOrigin,createdAt:e.createdAt,expiresAt:e.expiresAt,...void 0===e.serverExpiresAt?{}:{serverExpiresAt:e.serverExpiresAt}},i={...t};return te(i,"verifier",e.verifier),te(i,"toJSON",()=>({...t})),te(i,X,()=>({...t,verifier:"[redacted]"})),Object.freeze(i)}function te(e,t,i){Object.defineProperty(e,t,{value:i,enumerable:!1,writable:!1,configurable:!1})}function ie(e){return Math.min(Date.parse(e.expiresAt),Date.parse(e.createdAt)+V)}function re(){const e=new Map,t=t=>{for(const[i,r]of e)ie(r)<=t.getTime()&&e.delete(i)};return{async findLive(i,r){let s;t(r);for(const t of e.values())t.address===i&&(!s||Date.parse(t.createdAt)>Date.parse(s.createdAt))&&(s=t);return s},async put(t){e.set(t.requestId,t)},async delete(t){e.delete(t)},get:async(i,r)=>(t(r),e.get(i))}}var se=class extends Error{},ne=async()=>{throw new se("code requested")};async function oe(e){const t=e.profile??B;we(t,"request",e.allowHeldProfile);const r=t===$;r&&he(e.holder,"request",t);const s=le(e.address,t);r||he(e.holder,"request",t);const n=e.now??(()=>new Date),a=e.signal??AbortSignal.timeout(6e4),d=ge(s,t),l=await o(d),u=await Ie(t,d,{fetch:e.fetch,signal:a},"request",e.allowHeldProfile),p=await i(u),h=c(crypto.getRandomValues(new Uint8Array(32))),w=new P(u,e.fetch,{honorServerRecoverable:!0,...r?{allowAccountSubject:!0}:{}}),g=n().getTime();let I;try{I=await w.create({descriptor:u,descriptorDigest:p,requirement:d,requirementDigest:l,holderDid:e.holder.did,openerOrigin:K,completionVerifierChallenge:await f(h),signal:a})}catch(e){throw me(e,"request",a)}const E=Date.parse(I.expiresAt);if(!Number.isFinite(E))throw new Z("request","FAILED");const D=E-6e5;if(r&&D-n().getTime()>Q)throw new Z("request","CLIENT_CLOCK_SKEW");const A=ee({type:"TinyCloudEmailProofPending",version:1,profile:t,address:s,requestId:I.requestId,verifier:h,holderDid:e.holder.did,descriptorDigest:p,requirementDigest:l,openerOrigin:K,createdAt:new Date(g).toISOString(),expiresAt:new Date(r?g+Math.min(E-D,V):Math.min(E,g+V)).toISOString(),...r?{serverExpiresAt:I.expiresAt}:{}});try{await L({descriptor:u,...r?{allowAccountSubject:!0}:{},requirement:d,requestId:I.requestId,verifier:h,holderDid:e.holder.did,descriptorDigest:p,requirementDigest:l,openerOrigin:K,...r?{expiresAt:I.expiresAt}:{},transport:w,signing:Ae(e.holder,r),handlers:{mailbox_otp:ne},signal:a})}catch(e){if(e instanceof se)return A;throw me(e,"request",a)}throw new Z("request","FAILED")}async function ae(e){return de(e,M)}async function de(e,r){const{pending:s}=e,n=e.now??(()=>new Date);if(!function(e){if("object"!=typeof e||null===e)return!1;const t=e;return"TinyCloudEmailProofPending"===t.type&&1===t.version&&t.openerOrigin===K&&[t.profile,t.address,t.requestId,t.verifier,t.holderDid,t.descriptorDigest,t.requirementDigest,t.openerOrigin,t.createdAt,t.expiresAt].every(e=>"string"==typeof e)&&Number.isFinite(Date.parse(t.createdAt))&&Number.isFinite(Date.parse(t.expiresAt))}(s))throw new Z("session","SESSION_INVALID");we(s.profile,"session",e.allowHeldProfile);const a=s.profile===$;if(a&&!Number.isFinite(Date.parse(s.serverExpiresAt??"")))throw new Z("session","SESSION_INVALID");if(ie(s)<=n().getTime())throw new Z("session","SESSION_EXPIRED");if(!/^\d{8}$/.test(e.code))throw new Z("code","CODE_INVALID");if(he(e.holder,"code",s.profile),e.holder.did!==s.holderDid)throw new Z("session","SESSION_INVALID");const d=e.signal??AbortSignal.timeout(6e4),c=ge(s.address,s.profile);if(await o(c)!==s.requirementDigest)throw new Z("session","SESSION_INVALID");const l=await Ie(s.profile,c,{fetch:e.fetch,signal:d},"session",e.allowHeldProfile),u=await i(l);if(u!==s.descriptorDigest)throw new Z("session","SESSION_INVALID");const p=new P(l,e.fetch,{honorServerRecoverable:!0,...a?{allowAccountSubject:!0}:{}});try{const t=await p.state(s.requestId,s.verifier,d);if(!0===t.nextStep?.constraints.challengeRequired)throw new Z("session","SESSION_INVALID");await L({descriptor:l,...a?{allowAccountSubject:!0}:{},requirement:c,requestId:s.requestId,verifier:s.verifier,holderDid:s.holderDid,descriptorDigest:u,requirementDigest:s.requirementDigest,openerOrigin:s.openerOrigin,...a?{expiresAt:s.serverExpiresAt}:{},transport:p,signing:Ae(e.holder,a),handlers:{mailbox_otp:async()=>({otp:e.code})},signal:d})}catch(e){throw me(e,"code",d)}try{const e=await p.result(s.requestId,s.verifier,d);if(a){const i=await async function(e){const{envelope:i,pending:r,descriptor:s}=e,n=e=>new t("VERIFICATION_FAILED",e),o=Date.parse(i.issuedAt),a=e.now().getTime();if(!Number.isFinite(o)||o-a>Q)throw n("client clock is more than 5 minutes behind the issuer");const d=e.issuerKeys.find(e=>e.kid===R.issuerKid);if(!d)throw n("no pinned issuer key");const c=S({format:"tinycloud.credentials-issuers/v1",version:1,issuers:[{issuerDid:R.issuerDid,kid:R.issuerKid,alg:"EdDSA",publicKey:d.jwk.x,vcts:[k.id],profiles:[$],notBefore:"2020-01-01T00:00:00Z",retiredAt:null,notAfter:null}]},{didMethods:{issuer:["web"]}}),l=O(i.credential,{now:new Date(Math.max(a,o)),owner:r.holderDid,didMethods:{issuer:["web"]},acceptedIssuers:[{issuerDid:R.issuerDid,kid:R.issuerKid}],issuerSet:c}),u=e.transport.signedBinding(r.requestId),p=Object.keys(i.claims).sort().join(),f=e=>Math.floor(e/1e3);if(i.subjectDid!==r.holderDid||i.holderDid!==r.holderDid||"email,emailDomain"!==p||i.claims.email!==l.claims.email||i.claims.emailDomain!==l.claims.emailDomain||i.claims.email!==r.address||f(Date.parse(i.issuedAt))!==f(l.issuedAt.getTime())||f(Date.parse(i.expiresAt))!==f(l.expiresAt.getTime())||i.descriptorDigest!==e.descriptorDigest||i.profile.id!==$||1!==i.profile.version||i.issuerDid!==R.issuerDid||i.issuerKid!==R.issuerKid||"vc+sd-jwt"!==i.format||"none"!==i.status.method||i.status.freshnessSeconds!==s.status.freshnessSeconds)throw n("issued credential does not match the request");if(u?.type!==s.holderBinding.domain||!("credentialLifetimeSeconds"in u))throw n("signed binding is missing");if(l.credentialId!==u.jti||(l.expiresAt.getTime()-l.issuedAt.getTime())/1e3!==u.credentialLifetimeSeconds)throw n("credential does not match the binding the account signed");return l}({envelope:e,pending:s,descriptor:l,descriptorDigest:u,transport:p,issuerKeys:r,now:n});return{envelope:e,verified:i,credentialId:i.credentialId,issuedAt:i.issuedAt.toISOString(),expiresAt:i.expiresAt.toISOString(),descriptor:l}}const i=await E({envelope:e,descriptor:l,descriptorDigest:u,requirement:c,holderDid:s.holderDid,issuerMetadata:Ee(r),now:n(),checkStatus:(e,t)=>p.checkStatus(e,t),signal:d});return{envelope:e,verified:i,credentialId:i.credentialId,issuedAt:i.issuedAt,expiresAt:i.expiresAt,descriptor:l}}catch(e){throw me(e,"credential",d)}}async function ce(e){return async function(e,t){const i=e.profile??B;we(i,"request",e.allowHeldProfile);const r=le(e.address,i),s=e.now??(()=>new Date),n=e.pendingStore,o=n?await n.findLive(r,s()):void 0;let a=o?.profile===i?o:void 0;if(a&&i===$&&!Number.isFinite(Date.parse(a.serverExpiresAt??"")))throw await(n?.delete(a.requestId).catch(()=>{})),new Z("session","SESSION_INVALID");a||(a=await oe({...e,address:r}),await(n?.put(a)));const d=ee(a);if(!e.getCode)return{status:"code-requested",pending:d};const c=await e.getCode({pending:d});try{const i=await de({...e,pending:a,code:c},t),r=[];if(n)try{await n.delete(a.requestId)}catch{r.push("The pending request could not be deleted after success; it expires at its deadline.")}return{status:"issued",result:i,warnings:r}}catch(e){throw e instanceof Z&&e.recoverable||await(n?.delete(a.requestId).catch(()=>{})),e}}(e,M)}function le(e,t){if(t===$)return function(e){const t=()=>new Z("request","ADDRESS_INVALID"),i=e.trim();if(/[^\x00-\x7f]/.test(i))throw t();const r=i.toLowerCase(),s=r.split("@");if(r.length<3||r.length>254||2!==s.length||/[^\x21-\x7e]/.test(r))throw t();const[n,o]=s;if(n.length>64||!ue.test(n)||n.startsWith("+"))throw t();if(o.length>253||!o.includes(".")||!o.split(".").every(e=>e.length<=63&&pe.test(e)))throw t();return r}(e);const i=e.trim();if(i.length>254||!z.test(i))throw new Z("request","ADDRESS_INVALID");return i}var ue=/^[a-z0-9!#$%&'*+\-/=?^_`{|}~]+(\.[a-z0-9!#$%&'*+\-/=?^_`{|}~]+)*$/,pe=/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;function fe(e){return`${e}#${e.slice(8)}`}function he(e,t,i){if(i===$)return function(e,t){const i=y(e.did),r=null!==i&&"1"===i.chainId?`did:pkh:eip155:1:${_(i.address)}`:void 0;if(void 0===r||e.did!==r||"EIP191"!==e.alg||e.kid!==`${r}#blockchainAccountId`)throw new Z(t,"HOLDER_INVALID")}(e,t);if(!J.test(e.did)||"EdDSA"!==e.alg||e.kid!==fe(e.did))throw new Z(t,"HOLDER_INVALID")}function we(e,t,i){const r=Object.prototype.hasOwnProperty.call(H,e)?H[e]:void 0;if(!r||!r.enabled&&(!0!==i||e!==$))throw new Z(t,"PROFILE_UNAVAILABLE",void 0,void 0,"This SDK build doesn't enable the email verification profile.");return r}function ge(e,t){return t===$?g({type:"TinyCloudCredentialRequirement",version:1,profile:{id:t,version:1},credentialType:k,claims:{email:e},maxAgeSeconds:31536e3}):r({email:e,profile:{id:t,version:1},credentialType:k})}async function Ie(e,r,s,n,o){const a=we(e,n,o);let c;try{c=await async function(e,r,s={}){let n;try{n=new URL(r)}catch{throw new t("UNSUPPORTED_PROFILE","Discovery URL is invalid")}if("https:"!==n.protocol||!["/.well-known/opencredentials","/v1/credential-types"].includes(n.pathname)||n.search||n.hash)throw new t("UNSUPPORTED_PROFILE","Discovery URL is not an allowed catalog endpoint");const o={credentials:"omit",cache:"no-store",redirect:"error",referrerPolicy:"no-referrer",signal:s.signal};let a;try{a=await(s.fetch??globalThis.fetch.bind(globalThis))(n,o)}catch(e){throw new t("OFFLINE","Credential discovery is unavailable",{cause:e})}if(!a.ok)throw new t(503===a.status?"ISSUER_UNREADY":"OFFLINE","Credential discovery is unavailable");const c=await a.json();if("tinycloud.credentials/catalog/v1"!==c.type||"tinycloud.credentials/acquisition/v1"!==c.protocol||1!==c.catalogVersion||!Array.isArray(c.profiles))throw new t("DESCRIPTOR_INVALID","Credential catalog is invalid");for(const t of c.profiles){if("object"!=typeof t||null===t||Array.isArray(t))continue;const r=t;if(!0===r.supported&&!0===r.enabled&&("ready"===r.readiness||"degraded"===r.readiness))try{const t=h(r.descriptor);if(d(t,e)&&r.descriptorDigest===await i(t))return t}catch{}}throw new t("UNSUPPORTED_PROFILE","No available credential profile satisfies the requirement")}(r,j,{fetch:s.fetch,signal:s.signal})}catch(e){throw function(e,t,i){return t.aborted&&"TimeoutError"!==t.reason?.name?new Z(i,"CANCELED"):me(e,i,t)}(e,s.signal,n)}if(c.issuer.origin!==R.witnessOrigin||c.issuer.did!==R.issuerDid||!c.steps.some(e=>e.type===a.requiredStep))throw new Z(n,"PROFILE_UNAVAILABLE");if(await i(c)!==a.descriptorDigest)throw new Z(n,"PROFILE_UNAVAILABLE");return c}function Ee(e){return{type:"OpenCredentialsIssuerMetadata",version:1,origin:R.witnessOrigin,issuerDid:R.issuerDid,keys:e,cache:{maxAgeSeconds:3600,etag:"pinned"}}}async function De(e){return async function(e,r){const{record:s,requirement:n,holderDid:a}=e,d=s.descriptor;if(s.descriptorDigest!==R.descriptorDigest||await i(d)!==R.descriptorDigest)throw new t("VERIFICATION_FAILED","stored descriptor does not match the pinned descriptor digest");const c={type:"OpenCredentialsIssuedCredential",version:1,protocol:d.protocol,profile:s.profile,credentialType:s.credentialType,schema:s.schema,format:"vc+sd-jwt",issuerDid:s.issuerDid,issuerKid:s.issuerKid,subjectDid:s.subjectDid,holderDid:s.holderDid,claims:s.claims,claimsDigest:s.claimsDigest,descriptorDigest:s.descriptorDigest,credentialId:s.credentialId,issuedAt:s.issuedAt,notBefore:s.notBefore,expiresAt:s.expiresAt,status:s.status,credential:s.credential},l=await E({envelope:c,descriptor:d,descriptorDigest:R.descriptorDigest,requirement:n,holderDid:a,issuerMetadata:Ee(r),now:e.now,checkStatus:async e=>"none"===e.method&&e.freshnessSeconds===d.status.freshnessSeconds,signal:e.signal});if(s.holderDid!==a||s.ownerDid!==a)throw new t("HOLDER_MISMATCH","stored record belongs to another holder");if(s.credentialDigest!==l.credentialDigest)throw new t("VERIFICATION_FAILED","stored credential digest does not match the verified credential");if(s.requirementDigest!==await o(n))throw new t("VERIFICATION_FAILED","stored requirement digest does not match the requirement");if(s.recordId!==await i({credentialDigest:l.credentialDigest,holderDid:s.ownerDid}))throw new t("VERIFICATION_FAILED","stored record id does not match its credential");return l}(e,M)}function Ae(e,t){return{autoSign:async(i,r)=>{try{return await e.sign(r)}catch(e){const i=e instanceof DOMException&&("TimeoutError"===e.name||"AbortError"===e.name);if(!t||e instanceof Z||i)throw e;throw new Z("credential","SIGNATURE_REJECTED")}},holderKey:{alg:e.alg,kid:e.kid}}}function me(e,t,i){if(e instanceof Z)return e;if(e instanceof DOMException&&"TimeoutError"===e.name)return new Z(t,"NETWORK");const r=n(e),s=r.details;switch(r.code){case"ISSUER_UNREADY":return"rate_limited"===s.state?new Z(t,"RATE_LIMITED",s.retryAfterMs,r.recoverable):new Z(t,"ISSUER_UNAVAILABLE",void 0,r.recoverable);case"OFFLINE":return i?.aborted&&"TimeoutError"!==i.reason?.name?new Z(t,"CANCELED"):new Z(t,"NETWORK");case"UNSUPPORTED_PROFILE":case"UNSUPPORTED_VERSION":case"DESCRIPTOR_INVALID":return new Z(t,"PROFILE_UNAVAILABLE");case"PROOF_REJECTED":return new Z("code","CODE_REJECTED",void 0,!0);case"VERIFICATION_FAILED":return"proof_attempts_exhausted"===s.state?new Z("code","CODE_ATTEMPTS_EXHAUSTED"):"credential"===t?new Z("credential","CREDENTIAL_INVALID"):"code"===t?new Z("code","CODE_REJECTED",void 0,!1):new Z(t,"FAILED");case"HOLDER_MISMATCH":return new Z("credential","CREDENTIAL_INVALID");case"REQUEST_EXPIRED":return new Z("session","SESSION_EXPIRED");case"REQUEST_SUBSTITUTED":return new Z("session","SESSION_INVALID");case"SIGNATURE_REJECTED":return new Z("credential","SIGNATURE_REJECTED",void 0,r.recoverable);case"CANCELED":return new Z(t,"CANCELED");default:return new Z(t,"FAILED")}}function Se(){return new Z("request","HOLDER_INVALID",void 0,void 0,"The wallet signer signs only the exact account binding for this request.")}function ye(){return new Z("request","HOLDER_INVALID")}const ve=["audience","challengeNonce","completionContext","completionOrigin","credentialLifetimeSeconds","descriptorDigest","expiresAt","holderDid","issuedAt","issuer","issuerKid","jti","normalizedClaimsDigest","openerOrigin","profile","profileVersion","protocol","requestId","requirementDigest","type"],Te=/^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,_e=/^[A-Za-z0-9_-]{32}$/,Oe=/^[A-Za-z0-9_-]{43}$/,Re=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;function Ne(e){try{return new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(e)}catch{throw Se()}}function be(e,t){const i=y(e);if(null===i||"1"!==i.chainId)throw ye();const r=_(i.address),s=`did:pkh:eip155:1:${r}`;return{did:s,alg:"EIP191",kid:`${s}#blockchainAccountId`,sign:async e=>{const i=new Uint8Array(e);!function(e,t){const i=Ne(e);let r,s;try{r=JSON.parse(i),s=p(r)}catch{throw Se()}if(s!==i||"object"!=typeof r||null===r||Array.isArray(r))throw Se();const n=r;if(Object.keys(n).sort().join()!==ve.join())throw Se();for(const e of ve)if("profileVersion"!==e&&"credentialLifetimeSeconds"!==e&&("string"!=typeof n[e]||""===n[e]))throw Se();const o=e=>n[e];if(Object.keys(N).some(e=>n[e]!==N[e])||!v(n.holderDid,t)||!Te.test(o("jti"))||!_e.test(o("requestId"))||!_e.test(o("challengeNonce"))||!Oe.test(o("requirementDigest"))||!Oe.test(o("normalizedClaimsDigest"))||!Re.test(o("issuedAt"))||!Re.test(o("expiresAt"))||Date.parse(o("expiresAt"))-Date.parse(o("issuedAt"))!==6e5)throw Se()}(function(e){const t=(new TextEncoder).encode(D);if(e.length<=t.length+1||0!==e[t.length])throw Se();for(let i=0;i<t.length;i++)if(e[i]!==t[i])throw Se();return e.subarray(t.length+1)}(i),s);const n=Ne(i),o=await t(i),a=o[64];if(65!==o.length||27!==a&&28!==a)throw ye();if(!await I(n,function(e){return`0x${Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}`}(o),r))throw ye();return o}}}function Ce(e,t){return e.getTime()-t.getTime()>6e5}const Le=/^[A-Za-z0-9_-]{43}$/,qe="This app can't read held credentials: the session may lack kv get and list on v1/held/ (skipPrefix), or may need to sign in again.",Ue="This app can't delete held credentials: the session may lack kv del on v1/held/ (skipPrefix), or may need to sign in again.",xe="Held credentials could not be listed",Fe="permission_denied";function Pe(e){let t="object"==typeof e&&null!==e&&"error"in e?e.error:void 0,i=!1;for(let e=0;e<8&&"object"==typeof t&&null!==t;e+=1){const e=t,r=e.meta,s=[e.status,e.statusCode,"object"==typeof r&&null!==r?r.status:void 0].find(e=>"number"==typeof e&&Number.isInteger(e)&&e>=400&&e<=599);if(void 0!==s)return 401===s||403===s;"AUTH_UNAUTHORIZED"===e.code&&(i=!0),t=e.cause}return i}function ke(e){const i=y(e);if(null===i)throw new t("ACTIVE_SESSION_REQUIRED","Held credentials require a did:pkh:eip155 account owner");if("1"!==i.chainId)throw new t("ACTIVE_SESSION_REQUIRED","Held credentials require an Ethereum mainnet (chain 1) account owner");return`did:pkh:eip155:1:${_(i.address)}`}function Ve(e){return`v1/held/${T(e)}/`}function je(e,t){return`${Ve(e)}${t}`}function Me(e){if("object"!=typeof e||null===e)return!1;const t=e;return"TinyCloudHeldCredential"===t.type&&1===t.version&&"string"==typeof t.ownerDid&&"string"==typeof t.recordId&&"string"==typeof t.credentialDigest&&"string"==typeof t.credential&&"string"==typeof t.storedAt}function Be(e,t,i){return{issuerSet:e.issuerSet,acceptedIssuers:e.acceptedIssuers,didMethods:e.didMethods,now:t,owner:i}}async function He(e){return{type:"TinyCloudHeldStorageReceipt",version:1,ownerDid:e.ownerDid,recordId:e.recordId,recordDigest:await i(e),storedAt:e.storedAt}}async function Ke(e){const r=e.now??new Date,s=ke(e.ownerDid);let n;try{n=O(e.sdJwt,Be(e,r,s))}catch(e){throw function(e){if(!(e instanceof A))return e;const i="nonce-account-mismatch"===e.code?"HOLDER_MISMATCH":"VERIFICATION_FAILED";return new t(i,e.message,{cause:e})}(e)}const o=e.sdJwt;if("string"!=typeof o)throw new t("VERIFICATION_FAILED","Held credential must be an SD-JWT string");if("string"!=typeof n.claims.email)throw new t("VERIFICATION_FAILED","Held credential must disclose an email claim");if(!Ce(n.expiresAt,r))throw new t("VERIFICATION_FAILED","Held credential expires within the reuse margin");const a=await i(o),d=await i({credentialDigest:a,holderDid:s}),c={type:"TinyCloudHeldCredential",version:1,ownerDid:s,recordId:d,credentialDigest:a,credential:o,storedAt:r.toISOString()},l=await async function(e,i,r){const s=(e=!1)=>new t("VERIFIED_NOT_SAVED","Held credential could not be confirmed in storage",e?{state:Fe}:{}),n=await e.batchPut([{key:i,value:r}]).catch(()=>{});if(!0!==n?.ok)throw s(void 0!==n&&Pe(n));const o=await e.get(i).catch(()=>{});if(void 0!==o&&!o.ok&&Pe(o))throw s(!0);const a=!0===o?.ok?o.data.data:void 0;if(!Me(a)||a.recordId!==r.recordId||a.credentialDigest!==r.credentialDigest||a.credential!==r.credential||!v(a.ownerDid,r.ownerDid))throw s();return a}(e.kv,je(s,d),c);return{record:l,receipt:await He(l),verified:n}}async function $e(e,i,r,s,n){const o=await e.get(i);if(!o.ok&&Pe(o))throw new t("PERMISSION_DENIED",qe);return Qe(o.ok?o.data.data:void 0,i,r,s,n)}async function Qe(e,t,r,s,n){if(!Me(e))return{kind:"invalid"};if(!v(e.ownerDid,r))return{kind:"invalid"};const o=await i(e.credential),a=await i({credentialDigest:o,holderDid:r});if(e.credentialDigest!==o||e.recordId!==a||t!==je(r,a))return{kind:"invalid"};let d;try{d=O(e.credential,Be(s,n,r))}catch(e){if(!(e instanceof A)||"bad-config"===e.code)throw e;return{kind:"expired"===e.code?"expired":"invalid"}}const c=d.claims.email;return"string"!=typeof c?{kind:"invalid"}:{kind:"verified",email:c,match:{record:e,verified:d,recordId:a,email:c,issuedAt:d.issuedAt,expiresAt:d.expiresAt,issuer:d.issuer}}}class Je extends t{}async function ze(e,i){const r=[];let s;for(let n=0;n<50;n+=1){const n=await e.list(void 0===s?{prefix:i}:{prefix:i,cursor:s});if(!n.ok){if(Pe(n))throw new t("PERMISSION_DENIED",qe);return}if(r.push(...n.data.keys),!n.data.truncated)return[...new Set(r)];const o=n.data.nextCursor;if(void 0===o||""===o)throw new t("VERIFICATION_FAILED","Held listing is truncated without a continuation cursor");s=o}throw new Je("VERIFICATION_FAILED","Held listing exceeds the page limit")}async function Xe(e){const t=e.now??new Date,i=ke(e.ownerDid),r=await ze(e.kv,Ve(i));if(void 0===r)return;const s=e.email.replace(/[A-Z]+/g,e=>e.toLowerCase());let n;for(const o of r){const r=await $e(e.kv,o,i,e,t);if("verified"!==r.kind||r.email!==s)continue;const a=r.match.verified.expiresAt.getTime();Ce(r.match.verified.expiresAt,t)&&(void 0===n||a>n.verified.expiresAt.getTime())&&(n=r.match)}return n}async function Ge(e){const i=e.now??new Date,r=ke(e.ownerDid),s=await ze(e.kv,Ve(r));if(void 0===s)throw new t("OFFLINE",xe);const n=[];for(const o of s){const s=await e.kv.get(o);if(!s.ok){if("error"in s&&"KV_NOT_FOUND"===s.error.code)continue;if(Pe(s))throw new t("PERMISSION_DENIED",qe);throw new t("OFFLINE","A held credential could not be read")}let a;try{a=await Qe(s.data.data,o,r,e,i)}catch(e){if(e instanceof A&&"bad-config"===e.code)throw e;continue}"verified"===a.kind&&Ce(a.match.verified.expiresAt,i)&&n.push(a.match)}return n.sort((e,t)=>{const i=t.issuedAt.getTime()-e.issuedAt.getTime();return 0!==i?i:e.recordId<t.recordId?-1:e.recordId>t.recordId?1:0})}async function We(e){const i=ke(e.ownerDid);if(!Le.test(e.recordId))throw new t("DESCRIPTOR_INVALID","recordId must be a 43-character base64url digest");const r=await e.kv.delete(je(i,e.recordId));if(!r.ok&&Pe(r))throw new t("PERMISSION_DENIED",Ue);return r.ok}async function Ze(e){const i=ke(e.ownerDid);let r;try{r=await e.kv.list({prefix:Ve(i)})}catch{throw new t("OFFLINE",xe)}if(!r.ok){if(Pe(r))throw new t("PERMISSION_DENIED",qe);throw new t("OFFLINE",xe)}}const Ye="tinycloud.email-held/v1",et=3e5;class tt extends Error{constructor(e,t){super(t),this.retryable=!1,this.name="HeldSourceError",this.code=e}}async function it(e){return async function(e,i){const{kv:r,address:s,holder:n,sessionDid:o,getCode:d,pendingStore:c,fetch:l,signal:u,now:p,allowHeldProfile:f,...h}=e,w=p??(()=>new Date),g=ke(n.did);if(void 0!==o&&!v(o,g))throw new t("HOLDER_MISMATCH","Held acquisition holder must be the session account");const I=!0===f;let E;try{E=await async function(e,i,r,s,n){const o=s.trim().replace(/[A-Z]+/g,e=>e.toLowerCase()),a=async()=>function(e){let t;for(const i of e)(void 0===t||i.expiresAt.getTime()>t.expiresAt.getTime())&&(t=i);return t}((await async function(e,i,r,s){try{return await Ge({...i,kv:e,ownerDid:r,now:s})}catch(e){if(e instanceof t||e instanceof A)throw e;throw new t("OFFLINE","Held credentials could not be read",{cause:e})}}(e,i,r,new Date(n().getTime()+et))).filter(e=>e.email===o));try{return await a()}catch(e){if(!(e instanceof Je))throw e}try{return await async function(e){const i=e.now??new Date,r=ke(e.ownerDid),s=await ze(e.kv,Ve(r));if(void 0===s)return[];const n=[],o=new Map;for(const t of s){const s=await $e(e.kv,t,r,e,i);if("invalid"===s.kind)continue;if("expired"===s.kind){n.push(t);continue}const a={key:t,recordId:s.match.record.recordId,expiresAt:s.match.verified.expiresAt.getTime()},d=o.get(s.email);if(void 0===d){o.set(s.email,a);continue}const c=a.expiresAt>d.expiresAt||a.expiresAt===d.expiresAt&&a.recordId>d.recordId;o.set(s.email,c?a:d),n.push(c?d.key:a.key)}const a=[];for(const i of n){const r=await e.kv.delete(i);if(!r.ok&&Pe(r))throw new t("PERMISSION_DENIED",Ue);r.ok&&a.push(i)}return a}({...i,kv:e,ownerDid:r,now:n()}),await a()}catch(e){if(e instanceof Je)throw new tt("held-store-listing-limit","Saved held credentials list is too long to read; clear old ones");throw e}}(r,h,g,s,w)}catch(e){if(I||!(e instanceof t)||"OFFLINE"!==e.code&&"PERMISSION_DENIED"!==e.code)throw e}if(void 0!==E)return{credential:E.record.credential,holderDid:g,expiresAt:E.verified.expiresAt};I&&function(e,i){const r=()=>new t("VERIFICATION_FAILED","The issuer policy does not accept the held credential issuer"),{issuerDid:s,issuerKid:n}=R;if(!Array.isArray(e.acceptedIssuers)||!e.acceptedIssuers.some(e=>e.issuerDid===s&&(void 0===e.kid||e.kid===n)))throw r();if(!m.is(e.issuerSet))throw r();const o=e.issuerSet.resolveIssuer(s,n),a=i.getTime();if(!o||!o.vcts.includes("opencredentials.email/v1")||!o.profiles.includes(Ye)||a<o.notBefore||null!==o.retiredAt&&a>=o.retiredAt||null!==o.notAfter&&a>=o.notAfter)throw r()}(h,w());const D=await i({address:s,holder:n,profile:Ye,getCode:d,pendingStore:rt(c,g,w),fetch:l,signal:u,now:w,allowHeldProfile:f});if("issued"!==D.status)throw new t("PROOF_REJECTED","Held acquisition did not issue a credential");const S=D.result.envelope.credential,y=w().getTime(),T=function(e){try{const t=JSON.parse((new TextDecoder).decode(a(e.split("~")[0].split(".")[1]))),i="object"==typeof t&&null!==t&&"iat"in t?t.iat:void 0;if("number"==typeof i&&Number.isSafeInteger(i))return 1e3*i}catch{}throw new t("VERIFICATION_FAILED","Issued credential is not readable")}(S);if(T-y>et)throw new t("VERIFICATION_FAILED","client clock is more than 5 minutes behind the issuer");let _;try{_=await Ke({...h,kv:r,ownerDid:g,sdJwt:S,now:new Date(Math.max(y,T))})}catch(e){const i=e instanceof t&&e.details.state===Fe;throw new t("VERIFIED_NOT_SAVED","Verified held credential could not be stored",i?{state:Fe}:{})}return{credential:S,holderDid:g,expiresAt:_.verified.expiresAt}}(e,ce)}function rt(e,t,i){if(void 0===e)return;const r=e=>void 0!==e&&e.profile===Ye&&v(e.holderDid,t);return{async findLive(t,i){const s=await e.findLive(t,i);return r(s)?s:void 0},put:t=>e.put(t),async delete(t){r(await e.get(t,i()))&&await e.delete(t)},async get(t,i){const s=await e.get(t,i);return r(s)?s:void 0}}}export{Z as EmailProofError,P as OpenCredentialsHttpTransport,ce as acquireEmailProof,it as acquireHeldCredential,ae as completeEmailProof,be as createAccountHolderSigner,Y as createEd25519HolderSigner,re as createMemoryEmailProofPendingStore,We as deleteHeldCredential,Xe as findHeldCredential,L as interpretCredentialFlow,Ge as listHeldEmailCredentials,Ze as probeHeldStoreAccess,oe as requestEmailProofCode,Ke as storeHeldCredential,De as verifyStoredEmailProof};
|