@tinycloud/web-sdk 3.9.0-beta.3 → 3.9.0-beta.4

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.
@@ -6,7 +6,9 @@ export declare const ACCOUNT_KID_FRAGMENT = "blockchainAccountId";
6
6
  * exact bytes it is given. That is the one place the EIP-191 prefix is applied. This module adds no prefix.
7
7
  * It verifies the returned 65-byte signature by recovering the signer over the same message, and refuses
8
8
  * unless the recovered address equals the account. `did` must be did:pkh:eip155:1, canonicalised to EIP-55.
9
- * Bytes outside the account-binding domain are refused before `sign` is called.
9
+ * It signs one thing only: `UTF8(ACCOUNT_BINDING_DOMAIN) ‖ 0x00 ‖ JCS(account binding for this account)`. Any other
10
+ * bytes (other text, a binding for another holder, a ticket-typed or non-canonical body) are refused with
11
+ * HOLDER_INVALID before `sign` is called.
10
12
  */
11
13
  export declare function createAccountHolderSigner(did: string, sign: (bytes: Uint8Array) => Promise<Uint8Array>): HolderSigner;
12
14
  //# sourceMappingURL=account-holder.d.ts.map
@@ -22,6 +22,8 @@ export interface HeldAcquireInput extends HeldIssuerPolicy {
22
22
  readonly fetch?: EmailProofOptions["fetch"];
23
23
  readonly signal?: EmailProofOptions["signal"];
24
24
  readonly now?: () => Date;
25
+ /** Per-call opt-in for the held profile (the pin stays disabled by default). Forwarded to the acquisition; without it a miss is refused PROFILE_UNAVAILABLE before any request. */
26
+ readonly allowHeldProfile?: true;
25
27
  }
26
28
  export interface HeldCredentialResult {
27
29
  /** The verified SD-JWT, as stored. */
@@ -4,6 +4,11 @@ import type { CredentialClient, CredentialsAcquireOptions, CredentialsEnsureOpti
4
4
  export declare class CredentialsService {
5
5
  private readonly client;
6
6
  constructor(client: CredentialClient);
7
+ /**
8
+ * The held (account-bound) profile is acquired through `acquireHeldCredential` only. This service refuses a held requirement or an
9
+ * `account_is_subject` descriptor with UNSUPPORTED_PROFILE before any witness call (TC-2254 A2.5). `validateCredentialFlowDescriptor`
10
+ * is shape-only, so the refusal is made here, in the consumer.
11
+ */
7
12
  private descriptor;
8
13
  find(requirementValue: CredentialRequirement, options?: CredentialsOperationOptions): Promise<StoredCredentialRecord | undefined>;
9
14
  verify(envelope: IssuedCredentialEnvelope, input: {
@@ -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:()=>C,OpenCredentialsHttpTransport:()=>c,acquireEmailProof:()=>x,acquireHeldCredential:()=>ye,completeEmailProof:()=>U,createAccountHolderSigner:()=>z,createEd25519HolderSigner:()=>T,createMemoryEmailProofPendingStore:()=>b,findHeldCredential:()=>he,interpretCredentialFlow:()=>n,listHeldEmailCredentials:()=>we,requestEmailProofCode:()=>L,storeHeldCredential:()=>le,verifyStoredEmailProof:()=>$});const r=require("@tinycloud/sdk-core");var i=(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 n(e){const t=new Map(e.descriptor.steps.map(e=>[e.type,e])),n=new Set;let s="";for(;;){e.signal?.throwIfAborted();const o=await e.transport.state(e.requestId,e.verifier,e.signal);if(o.requestId!==e.requestId)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential request identity changed");if("expired"===o.state)throw new r.CredentialError("REQUEST_EXPIRED","Credential request expired",{state:o.state,correlationId:o.correlationId});if("canceled"===o.state)throw new r.CredentialError("CANCELED","Credential request was canceled",{state:o.state,correlationId:o.correlationId});if("issuer_unready"===o.state)throw new r.CredentialError("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:o.retryAfterMs,state:o.state,correlationId:o.correlationId});if("complete"===o.state)return;if("ready_to_issue"===o.state||"issued"===o.state){"ready_to_issue"!==o.state||n.has("issue")?await(e.onWait?.()??i(o.retryAfterMs??50,e.signal)):(await e.transport.issue(e.requestId,e.verifier,e.signal),n.add("issue"));continue}const a=o.nextStep;if(!a){await(e.onWait?.()??i(o.retryAfterMs??50,e.signal));continue}const d=t.get(a.type);if(a.id!==a.type||!d||d.type!==a.type||d.version!==a.version)throw new r.CredentialError("REQUEST_SUBSTITUTED","Server selected an undeclared credential step");if(n.has(a.id)||o.transitionId===s)await(e.onWait?.()??i(o.retryAfterMs??50,e.signal));else{if(s=o.transitionId,"holder_signature"===a.type){e.onProgress?.({state:"signing",stepId:a.id,correlationId:o.correlationId});const t=(0,r.validateCredentialHolderBinding)(await e.transport.holderBinding(e.requestId,e.verifier,e.signal));if(t.requestId!==e.requestId||t.descriptorDigest!==e.descriptorDigest||t.requirementDigest!==e.requirementDigest||t.holderDid!==e.holderDid||t.issuer!==e.descriptor.issuer.did||t.issuerKid!==e.descriptor.issuer.kid||t.profile!==e.descriptor.profile||t.openerOrigin!==e.openerOrigin||t.completionOrigin!==e.openerOrigin||"tinycloud://credentials"!==t.audience)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding was substituted");const i=(0,r.holderBindingSigningBytes)(t);let n=await(e.signing.autoSign?.(t,i,e.signal));if(void 0===n){if(!e.signing.requestApproval)throw new r.CredentialError("SIGNATURE_REJECTED","OpenKey approval is required");try{n=await e.signing.requestApproval(t,i,e.signal)}catch(e){if(e instanceof r.CredentialError)throw e;throw new r.CredentialError("SIGNATURE_REJECTED","OpenKey approval was rejected",{cause:e})}}if(!(n instanceof Uint8Array)||0===n.length)throw new r.CredentialError("SIGNATURE_REJECTED","OpenKey signature is invalid");await e.transport.submitHolderSignature(e.requestId,e.verifier,(0,r.encodeBase64Url)(n),e.signal,e.signing.holderKey)}else{e.onProgress?.({state:"collect_input"===a.type?"collecting":"proving",stepId:a.id,correlationId:o.correlationId});const t=e.handlers?.[a.type],n=e.proofHandler;if(!t&&!n){await(e.onWait?.()??i(o.retryAfterMs??50,e.signal));continue}if(!0===a.constraints.challengeRequired&&await e.transport.beginStep(e.requestId,e.verifier,a.type,e.signal),t){const r=await t({descriptor:e.descriptor,requirement:e.requirement,stepId:a.id,constraints:a.constraints,signal:e.signal});await e.transport.submitStep(e.requestId,e.verifier,a.id,r,e.signal)}else{let t;for(let i=1;;i+=1){const s=await n({stepId:a.id,constraints:a.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,a.id,s,e.signal);break}catch(n){if(!(n instanceof r.CredentialError)||"PROOF_REJECTED"!==n.code)throw n;const s=e.descriptor.lifecycle.maxProofAttempts-i;if("mailbox_otp"!==a.type||s<=0)throw new r.CredentialError("VERIFICATION_FAILED","The proof was not accepted",{state:s<=0?"proof_attempts_exhausted":"proof_rejected",cause:n});t={kind:"rejected",attemptsRemaining:s}}}}}n.add(a.id)}}}function s(e,t){if("object"!=typeof e||null===e||Array.isArray(e))throw new r.CredentialError("VERIFICATION_FAILED",`${t} is invalid`);return e}function o(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 a(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 d=new Set(["REQUEST_EXPIRED","ISSUER_UNREADY","UNSUPPORTED_PROFILE","UNSUPPORTED_VERSION","SIGNATURE_REJECTED"]),c=class{constructor(e,t=globalThis.fetch.bind(globalThis),r={}){this.descriptor=e,this.fetchFn=t,this.options=r,this.nonces=new Map,this.bindings=new Map}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(!d.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=s(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:"tinycloud://credentials",openerOrigin:e.openerOrigin,completionOrigin:e.openerOrigin,completionContext:"sdk-acquisition",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=o(t.requestId,"requestId");return{requestId:i,locator:i,expiresAt:a(t.expiresAt,"expiresAt"),correlationId:i}}proofStep(){return this.descriptor.steps.some(e=>"mailbox_otp"===e.type)?"mailbox_otp":"collect_input"}async state(e,t,i){const n=s(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 a={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{...a,state:"pending",nextStep:{id:e,type:e,version:1,constraints:{challengeRequired:!0}}}}if("proof_required"===n.state){const t=this.proofStep();return this.nonces.set(e,o(n.challengeNonce,"challengeNonce")),{...a,state:"pending",nextStep:{id:t,type:t,version:1,constraints:{}}}}if("holder_binding_required"===n.state||"holder_signature_required"===n.state)return{...a,state:"pending",nextStep:{id:"holder_signature",type:"holder_signature",version:1,constraints:{}}};if("ready_to_issue"===n.state)return{...a,state:"ready_to_issue"};if("issued"===n.state)return{...a,state:"complete"};throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential state is unsupported")}async beginStep(e,t,i,n){const a=this.proofStep();if(i!==a)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential challenge step is substituted");const d=s(await this.request("challenge",{id:e,verifier:t,method:"POST",body:{step:a,stepVersion:1},signal:n}),"challenge response");if("tinycloud.credentials/challenge/v1"!==d.type||d.step!==a||1!==d.stepVersion)throw new r.CredentialError("REQUEST_SUBSTITUTED","Credential challenge is substituted");this.nonces.set(e,o(d.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=s(await this.request("holder_binding",{id:e,verifier:t,signal:i}),"holder binding response");if("tinycloud.credentials/holder-binding-request/v1"!==n.type||"tinycloud.credentials/holder-binding/v1"!==n.signingDomain||"EdDSA"!==n.alg||"string"!=typeof n.canonical)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding response is invalid");const o=(0,r.validateCredentialHolderBinding)(n.binding);if((0,r.encodeBase64Url)((0,r.holderBindingCanonicalBytes)(o))!==n.canonical)throw new r.CredentialError("REQUEST_SUBSTITUTED","Holder binding canonical bytes were substituted");return this.bindings.set(e,o),o}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");const a=s?.kid??`${o.holderDid}#${o.holderDid.replace("did:key:","")}`;await this.request("holder_signature",{id:e,verifier:t,method:"POST",body:{alg:s?.alg??"EdDSA",kid:a,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=s(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 o=s(n.holderBinding,"result holder binding");if(n.subject!==o.did||"tinycloud.credentials/holder-binding/v1"!==o.signingDomain)throw new r.CredentialError("HOLDER_MISMATCH","Issued holder binding is invalid");const d=s(n.claims,"result claims"),c={};for(const[e,t]of Object.entries(d)){if("string"!=typeof t)throw new r.CredentialError("VERIFICATION_FAILED","Issued claims are invalid");c[e]=t}const l=s(n.validity,"result validity"),u=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 s(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 u.jti)throw new r.CredentialError("VERIFICATION_FAILED","Credential id is invalid");const p=a(l.issuedAt,"issuedAt"),E=a(l.expiresAt,"expiresAt"),f=s(n.status,"result status");if("none"!==f.type||f.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:c,claimsDigest:await(0,r.canonicalDigest)(c),descriptorDigest:n.descriptorDigest,credentialId:u.jti,issuedAt:p,notBefore:p,expiresAt:E,status:{method:"none",freshnessSeconds:f.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}},l=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"}),u={id:"opencredentials.email/v1",version:1},p=9e5,E=`${l.witnessOrigin}/.well-known/opencredentials`,f=[{kid:l.issuerKid,alg:"EdDSA",jwk:{kty:"OKP",crv:"Ed25519",x:l.issuerX},validFrom:"2020-01-01T00:00:00Z",validUntil:"2100-01-01T00:00:00Z"}],h="tinycloud.email-proof/v1",w={"tinycloud.email-proof/v1":{descriptorDigest:l.descriptorDigest,requiredStep:"mailbox_otp",enabled:!0},"tinycloud.email-held/v1":{descriptorDigest:"dc3_DuvzipXwYkTfjKqTaK1c3VS0YSPnaBsYSQriC0w",requiredStep:"mailbox_otp",enabled:!1}},g="https://localhost",I=6e4,D="did:key:",y=/^did:key:z6Mk[^#]+$/,A=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,S=Symbol.for("nodejs.util.inspect.custom"),v={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,CANCELED:!1,FAILED:!1},m={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.",CANCELED:"Email verification was canceled.",FAILED:"Email verification failed."},C=class extends Error{constructor(e,t,r,i=v[t]){super("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):m[t]),this.name="EmailProofError",this.step=e,this.code=t,this.retryAfterMs=r,this.recoverable=i}};function T(e,t){const r=e.indexOf("#"),i=-1===r?e:e.slice(0,r);if(-1!==r&&e.slice(r+1)!==i.slice(D.length))throw new C("request","HOLDER_INVALID");if(!y.test(i))throw new C("request","HOLDER_INVALID");return{did:i,alg:"EdDSA",kid:V(i),sign:t}}function _(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},r={...t};return R(r,"verifier",e.verifier),R(r,"toJSON",()=>({...t})),R(r,S,()=>({...t,verifier:"[redacted]"})),Object.freeze(r)}function R(e,t,r){Object.defineProperty(e,t,{value:r,enumerable:!1,writable:!1,configurable:!1})}function O(e){return Math.min(Date.parse(e.expiresAt),Date.parse(e.createdAt)+p)}function b(){const e=new Map,t=t=>{for(const[r,i]of e)O(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 N=class extends Error{},q=async()=>{throw new N("code requested")};async function L(e){const t=e.profile??h;H(t,"request");const i=P(e.address);k(e.holder,"request");const s=e.now??(()=>new Date),o=e.signal??AbortSignal.timeout(I),a=M(i,t),d=await(0,r.credentialRequirementDigest)(a),l=await B(t,a,{fetch:e.fetch,signal:o},"request"),u=await(0,r.canonicalDigest)(l),E=(0,r.encodeBase64Url)(crypto.getRandomValues(new Uint8Array(32))),f=new c(l,e.fetch,{honorServerRecoverable:!0}),w=s().getTime();let D;try{D=await f.create({descriptor:l,descriptorDigest:u,requirement:a,requirementDigest:d,holderDid:e.holder.did,openerOrigin:g,completionVerifierChallenge:await(0,r.sha256Base64Url)(E),signal:o})}catch(e){throw Q(e,"request",o)}const y=Date.parse(D.expiresAt);if(!Number.isFinite(y))throw new C("request","FAILED");const A=_({type:"TinyCloudEmailProofPending",version:1,profile:t,address:i,requestId:D.requestId,verifier:E,holderDid:e.holder.did,descriptorDigest:u,requirementDigest:d,openerOrigin:g,createdAt:new Date(w).toISOString(),expiresAt:new Date(Math.min(y,w+p)).toISOString()});try{await n({descriptor:l,requirement:a,requestId:D.requestId,verifier:E,holderDid:e.holder.did,descriptorDigest:u,requirementDigest:d,openerOrigin:g,transport:f,signing:J(e.holder),handlers:{mailbox_otp:q},signal:o})}catch(e){if(e instanceof N)return A;throw Q(e,"request",o)}throw new C("request","FAILED")}async function U(e){return F(e,f)}async function F(e,t){const{pending:i}=e,s=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===g&&[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))}(i))throw new C("session","SESSION_INVALID");if(O(i)<=s().getTime())throw new C("session","SESSION_EXPIRED");if(!/^\d{8}$/.test(e.code))throw new C("code","CODE_INVALID");if(k(e.holder,"code"),e.holder.did!==i.holderDid)throw new C("session","SESSION_INVALID");const o=e.signal??AbortSignal.timeout(I),a=M(i.address,i.profile);if(await(0,r.credentialRequirementDigest)(a)!==i.requirementDigest)throw new C("session","SESSION_INVALID");const d=await B(i.profile,a,{fetch:e.fetch,signal:o},"session"),l=await(0,r.canonicalDigest)(d);if(l!==i.descriptorDigest)throw new C("session","SESSION_INVALID");const u=new c(d,e.fetch,{honorServerRecoverable:!0});try{const t=await u.state(i.requestId,i.verifier,o);if(!0===t.nextStep?.constraints.challengeRequired)throw new C("session","SESSION_INVALID");await n({descriptor:d,requirement:a,requestId:i.requestId,verifier:i.verifier,holderDid:i.holderDid,descriptorDigest:l,requirementDigest:i.requirementDigest,openerOrigin:i.openerOrigin,transport:u,signing:J(e.holder),handlers:{mailbox_otp:async()=>({otp:e.code})},signal:o})}catch(e){throw Q(e,"code",o)}try{const e=await u.result(i.requestId,i.verifier,o),n=await(0,r.verifyIssuedCredential)({envelope:e,descriptor:d,descriptorDigest:l,requirement:a,holderDid:i.holderDid,issuerMetadata:j(t),now:s(),checkStatus:(e,t)=>u.checkStatus(e,t),signal:o});return{envelope:e,verified:n,credentialId:n.credentialId,issuedAt:n.issuedAt,expiresAt:n.expiresAt,descriptor:d}}catch(e){throw Q(e,"credential",o)}}async function x(e){return async function(e,t){const r=P(e.address),i=e.now??(()=>new Date),n=e.pendingStore,s=e.profile??h,o=n?await n.findLive(r,i()):void 0;let a=o?.profile===s?o:void 0;a||(a=await L({...e,address:r}),await(n?.put(a)));const d=_(a);if(!e.getCode)return{status:"code-requested",pending:d};const c=await e.getCode({pending:d});try{const r=await F({...e,pending:a,code:c},t),i=[];if(n)try{await n.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 C&&e.recoverable||await(n?.delete(a.requestId).catch(()=>{})),e}}(e,f)}function P(e){const t=e.trim();if(t.length>254||!A.test(t))throw new C("request","ADDRESS_INVALID");return t}function V(e){return`${e}#${e.slice(D.length)}`}function k(e,t){if(!y.test(e.did)||"EdDSA"!==e.alg||e.kid!==V(e.did))throw new C(t,"HOLDER_INVALID")}function H(e,t){const r=Object.prototype.hasOwnProperty.call(w,e)?w[e]:void 0;if(!r||!r.enabled)throw new C(t,"PROFILE_UNAVAILABLE");return r}function M(e,t){return(0,r.createEmailCredentialRequirement)({email:e,profile:{id:t,version:1},credentialType:u})}async function B(e,t,i,n){const s=H(e,n);let o;try{o=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,E,{fetch:i.fetch,signal:i.signal})}catch(e){throw function(e,t,r){return t.aborted&&"TimeoutError"!==t.reason?.name?new C(r,"CANCELED"):Q(e,r,t)}(e,i.signal,n)}if(o.issuer.origin!==l.witnessOrigin||o.issuer.did!==l.issuerDid||!o.steps.some(e=>e.type===s.requiredStep))throw new C(n,"PROFILE_UNAVAILABLE");if(await(0,r.canonicalDigest)(o)!==s.descriptorDigest)throw new C(n,"PROFILE_UNAVAILABLE");return o}function j(e){return{type:"OpenCredentialsIssuerMetadata",version:1,origin:l.witnessOrigin,issuerDid:l.issuerDid,keys:e,cache:{maxAgeSeconds:3600,etag:"pinned"}}}async function $(e){return async function(e,t){const{record:i,requirement:n,holderDid:s}=e,o=i.descriptor;if(i.descriptorDigest!==l.descriptorDigest||await(0,r.canonicalDigest)(o)!==l.descriptorDigest)throw new r.CredentialError("VERIFICATION_FAILED","stored descriptor does not match the pinned descriptor digest");const a={type:"OpenCredentialsIssuedCredential",version:1,protocol:o.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},d=await(0,r.verifyIssuedCredential)({envelope:a,descriptor:o,descriptorDigest:l.descriptorDigest,requirement:n,holderDid:s,issuerMetadata:j(t),now:e.now,checkStatus:async e=>"none"===e.method&&e.freshnessSeconds===o.status.freshnessSeconds,signal:e.signal});if(i.holderDid!==s||i.ownerDid!==s)throw new r.CredentialError("HOLDER_MISMATCH","stored record belongs to another holder");if(i.credentialDigest!==d.credentialDigest)throw new r.CredentialError("VERIFICATION_FAILED","stored credential digest does not match the verified credential");if(i.requirementDigest!==await(0,r.credentialRequirementDigest)(n))throw new r.CredentialError("VERIFICATION_FAILED","stored requirement digest does not match the requirement");if(i.recordId!==await(0,r.canonicalDigest)({credentialDigest:d.credentialDigest,holderDid:i.ownerDid}))throw new r.CredentialError("VERIFICATION_FAILED","stored record id does not match its credential");return d}(e,f)}function J(e){return{autoSign:async(t,r)=>e.sign(r),holderKey:{alg:"EdDSA",kid:e.kid}}}function Q(e,t,i){if(e instanceof C)return e;if(e instanceof DOMException&&"TimeoutError"===e.name)return new C(t,"NETWORK");const n=(0,r.credentialError)(e),s=n.details;switch(n.code){case"ISSUER_UNREADY":return"rate_limited"===s.state?new C(t,"RATE_LIMITED",s.retryAfterMs,n.recoverable):new C(t,"ISSUER_UNAVAILABLE",void 0,n.recoverable);case"OFFLINE":return i?.aborted&&"TimeoutError"!==i.reason?.name?new C(t,"CANCELED"):new C(t,"NETWORK");case"UNSUPPORTED_PROFILE":case"DESCRIPTOR_INVALID":return new C(t,"PROFILE_UNAVAILABLE");case"PROOF_REJECTED":return new C("code","CODE_REJECTED",void 0,!0);case"VERIFICATION_FAILED":return"proof_attempts_exhausted"===s.state?new C("code","CODE_ATTEMPTS_EXHAUSTED"):"credential"===t?new C("credential","CREDENTIAL_INVALID"):"code"===t?new C("code","CODE_REJECTED",void 0,!1):new C(t,"FAILED");case"HOLDER_MISMATCH":return new C("credential","CREDENTIAL_INVALID");case"REQUEST_EXPIRED":return new C("session","SESSION_EXPIRED");case"REQUEST_SUBSTITUTED":return new C("session","SESSION_INVALID");case"SIGNATURE_REJECTED":return new C("credential","SIGNATURE_REJECTED",void 0,n.recoverable);case"CANCELED":return new C(t,"CANCELED");default:return new C(t,"FAILED")}}const K=require("@tinycloud/sdk-core/held-credentials"),X="blockchainAccountId",G="1",W=0;function Y(){return new C("request","HOLDER_INVALID")}function z(e,t){const i=(0,K.parsePkhDid)(e);if(null===i||i.chainId!==G)throw Y();const n=(0,K.toChecksumAddress)(i.address),s=`did:pkh:eip155:${G}:${n}`;return{did:s,alg:"EIP191",kid:`${s}#${X}`,sign:async e=>{!function(e){const t=(new TextEncoder).encode(K.ACCOUNT_BINDING_DOMAIN);if(e.length<=t.length+1||e[t.length]!==W)throw Y();for(let r=0;r<t.length;r++)if(e[r]!==t[r])throw Y()}(e);const i=function(e){try{return new TextDecoder("utf-8",{fatal:!0}).decode(e)}catch{throw Y()}}(e),s=await t(e),o=s[64];if(65!==s.length||27!==o&&28!==o)throw Y();if(!await(0,r.verifyEip191MessageSignature)(i,function(e){return`0x${Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}`}(s),n))throw Y();return s}}}const Z=6e5;function ee(e,t){return e.getTime()-t.getTime()>Z}const te=50,re="1",ie="KV_NOT_FOUND";function ne(e){const t=(0,K.parsePkhDid)(e);if(null===t)throw new r.CredentialError("ACTIVE_SESSION_REQUIRED","Held credentials require a did:pkh:eip155 account owner");if(t.chainId!==re)throw new r.CredentialError("ACTIVE_SESSION_REQUIRED","Held credentials require an Ethereum mainnet (chain 1) account owner");return`did:pkh:eip155:${re}:${(0,K.toChecksumAddress)(t.address)}`}function se(e){return`v1/held/${(0,K.registryKey)(e)}/`}function oe(e,t){return`${se(e)}${t}`}function ae(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 de(e,t,r){return{issuerSet:e.issuerSet,acceptedIssuers:e.acceptedIssuers,didMethods:e.didMethods,now:t,owner:r}}async function ce(e){return{type:"TinyCloudHeldStorageReceipt",version:1,ownerDid:e.ownerDid,recordId:e.recordId,recordDigest:await(0,r.canonicalDigest)(e),storedAt:e.storedAt}}async function le(e){const t=e.now??new Date,i=ne(e.ownerDid);let n;try{n=(0,K.verifyHeldEmailCredential)(e.sdJwt,de(e,t,i))}catch(e){throw function(e){if(!(e instanceof K.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 s=e.sdJwt;if("string"!=typeof s)throw new r.CredentialError("VERIFICATION_FAILED","Held credential must be an SD-JWT string");if("string"!=typeof n.claims.email)throw new r.CredentialError("VERIFICATION_FAILED","Held credential must disclose an email claim");if(!ee(n.expiresAt,t))throw new r.CredentialError("VERIFICATION_FAILED","Held credential expires within the reuse margin");const o=await(0,r.canonicalDigest)(s),a=await(0,r.canonicalDigest)({credentialDigest:o,holderDid:i}),d={type:"TinyCloudHeldCredential",version:1,ownerDid:i,recordId:a,credentialDigest:o,credential:s,storedAt:t.toISOString()},c=await async function(e,t,i){const n=()=>new r.CredentialError("VERIFIED_NOT_SAVED","Held credential could not be confirmed in storage"),s=await e.batchPut([{key:t,value:i}]).catch(()=>{});if(!0!==s?.ok)throw n();const o=await e.get(t).catch(()=>{}),a=!0===o?.ok?o.data.data:void 0;if(!ae(a)||a.recordId!==i.recordId||a.credentialDigest!==i.credentialDigest||a.credential!==i.credential||!(0,K.pkhPrincipalsEqual)(a.ownerDid,i.ownerDid))throw n();return a}(e.kv,oe(i,a),d);return{record:c,receipt:await ce(c),verified:n}}async function ue(e,t,r,i,n){const s=await e.get(t);return pe(s.ok?s.data.data:void 0,t,r,i,n)}async function pe(e,t,i,n,s){if(!ae(e))return{kind:"invalid"};if(!(0,K.pkhPrincipalsEqual)(e.ownerDid,i))return{kind:"invalid"};const o=await(0,r.canonicalDigest)(e.credential),a=await(0,r.canonicalDigest)({credentialDigest:o,holderDid:i});if(e.credentialDigest!==o||e.recordId!==a||t!==oe(i,a))return{kind:"invalid"};let d;try{d=(0,K.verifyHeldEmailCredential)(e.credential,de(n,s,i))}catch(e){if(!(e instanceof K.HeldCredentialError)||"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 Ee extends r.CredentialError{}async function fe(e,t){const i=[];let n;for(let s=0;s<te;s+=1){const s=await e.list(void 0===n?{prefix:t}:{prefix:t,cursor:n});if(!s.ok)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 Ee("VERIFICATION_FAILED","Held listing exceeds the page limit")}async function he(e){const t=e.now??new Date,r=ne(e.ownerDid),i=await fe(e.kv,se(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 ue(e.kv,o,r,e,t);if("verified"!==i.kind||i.email!==n)continue;const a=i.match.verified.expiresAt.getTime();ee(i.match.verified.expiresAt,t)&&(void 0===s||a>s.verified.expiresAt.getTime())&&(s=i.match)}return s}async function we(e){const t=e.now??new Date,i=ne(e.ownerDid),n=await fe(e.kv,se(i));if(void 0===n)throw new r.CredentialError("OFFLINE","Held credentials could not be listed");const s=[];for(const o of n){const n=await e.kv.get(o);if(!n.ok){if("error"in n&&n.error.code===ie)continue;throw new r.CredentialError("OFFLINE","A held credential could not be read")}let a;try{a=await pe(n.data.data,o,i,e,t)}catch(e){if(e instanceof K.HeldCredentialError&&"bad-config"===e.code)throw e;continue}"verified"===a.kind&&ee(a.match.verified.expiresAt,t)&&s.push(a.match)}return s.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 ge="tinycloud.email-held/v1";class Ie extends Error{constructor(e,t){super(t),this.retryable=!1,this.name="HeldSourceError",this.code=e}}const De="Saved held credentials list is too long to read; clear old ones";async function ye(e){return async function(e,t){const{kv:i,address:n,holder:s,sessionDid:o,getCode:a,pendingStore:d,fetch:c,signal:l,now:u,...p}=e,E=u??(()=>new Date),f=ne(s.did);if(void 0!==o&&!(0,K.pkhPrincipalsEqual)(o,f))throw new r.CredentialError("HOLDER_MISMATCH","Held acquisition holder must be the session account");const h=await async function(e,t,r,i,n){try{return await he({...t,kv:e,ownerDid:r,email:i,now:n()})}catch(e){if(!(e instanceof Ee))throw e}try{return await async function(e){const t=e.now??new Date,r=ne(e.ownerDid),i=await fe(e.kv,se(r));if(void 0===i)return[];const n=[],s=new Map;for(const o of i){const i=await ue(e.kv,o,r,e,t);if("invalid"===i.kind)continue;if("expired"===i.kind){n.push(o);continue}const a={key:o,recordId:i.match.record.recordId,expiresAt:i.match.verified.expiresAt.getTime()},d=s.get(i.email);if(void 0===d){s.set(i.email,a);continue}const c=a.expiresAt>d.expiresAt||a.expiresAt===d.expiresAt&&a.recordId>d.recordId;s.set(i.email,c?a:d),n.push(c?d.key:a.key)}const o=[];for(const t of n)(await e.kv.delete(t)).ok&&o.push(t);return o}({...t,kv:e,ownerDid:r,now:n()}),await he({...t,kv:e,ownerDid:r,email:i,now:n()})}catch(e){if(e instanceof Ee)throw new Ie("held-store-listing-limit",De);throw e}}(i,p,f,n,E);if(void 0!==h)return{credential:h.record.credential,holderDid:f,expiresAt:h.verified.expiresAt};const w=await t({address:n,holder:s,profile:ge,getCode:a,pendingStore:Ae(d,f,E),fetch:c,signal:l,now:E});if("issued"!==w.status)throw new r.CredentialError("PROOF_REJECTED","Held acquisition did not issue a credential");const g=w.result.envelope.credential;let I;try{I=await le({...p,kv:i,ownerDid:f,sdJwt:g,now:E()})}catch{throw new r.CredentialError("VERIFIED_NOT_SAVED","Verified held credential could not be stored")}return{credential:g,holderDid:f,expiresAt:I.verified.expiresAt}}(e,x)}function Ae(e,t,r){if(void 0===e)return;const i=e=>void 0!==e&&e.profile===ge&&(0,K.pkhPrincipalsEqual)(e.holderDid,t);return{async findLive(t,r){const n=await e.findLive(t,r);return i(n)?n:void 0},put:t=>e.put(t),async delete(t){i(await e.get(t,r()))&&await e.delete(t)},async get(t,r){const n=await e.get(t,r);return i(n)?n: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:()=>U,OpenCredentialsHttpTransport:()=>h,acquireEmailProof:()=>$,acquireHeldCredential:()=>Ve,completeEmailProof:()=>M,createAccountHolderSigner:()=>Ee,createEd25519HolderSigner:()=>x,createMemoryEmailProofPendingStore:()=>V,findHeldCredential:()=>qe,interpretCredentialFlow:()=>c,listHeldEmailCredentials:()=>Le,requestEmailProofCode:()=>B,storeHeldCredential:()=>_e,verifyStoredEmailProof:()=>te});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=class extends Error{constructor(e,t,r,i=q[t]){super("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 x(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 U("request","HOLDER_INVALID");if(!R.test(i))throw new U("request","HOLDER_INVALID");return{did:i,alg:"EdDSA",kid:X(i),sign:t}}function P(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 F(r,"verifier",e.verifier),F(r,"toJSON",()=>({...t})),F(r,N,()=>({...t,verifier:"[redacted]"})),Object.freeze(r)}function F(e,t,r){Object.defineProperty(e,t,{value:r,enumerable:!1,writable:!1,configurable:!1})}function k(e){return Math.min(Date.parse(e.expiresAt),Date.parse(e.createdAt)+w)}function V(){const e=new Map,t=t=>{for(const[r,i]of e)k(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 H=class extends Error{},j=async()=>{throw new H("code requested")};async function B(e){const t=e.profile??D;W(t,"request",e.allowHeldProfile);const i=t===y;i&&G(e.holder,"request",t);const n=Q(e.address,t);i||G(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 Z(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 ie(e,"request",o)}const I=Date.parse(g.expiresAt);if(!Number.isFinite(I))throw new U("request","FAILED");const m=I-T;if(i&&m-s().getTime()>C)throw new U("request","CLIENT_CLOCK_SKEW");const S=P({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:re(e.holder,i),handlers:{mailbox_otp:j},signal:o})}catch(e){if(e instanceof H)return S;throw ie(e,"request",o)}throw new U("request","FAILED")}async function M(e){return K(e,I)}async function K(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 U("session","SESSION_INVALID");W(s.profile,"session",e.allowHeldProfile);const a=s.profile===y;if(a&&!Number.isFinite(Date.parse(s.serverExpiresAt??"")))throw new U("session","SESSION_INVALID");if(k(s)<=o().getTime())throw new U("session","SESSION_EXPIRED");if(!/^\d{8}$/.test(e.code))throw new U("code","CODE_INVALID");if(G(e.holder,"code",s.profile),e.holder.did!==s.holderDid)throw new U("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 U("session","SESSION_INVALID");const u=await Z(s.profile,l,{fetch:e.fetch,signal:d},"session",e.allowHeldProfile),p=await(0,r.canonicalDigest)(u);if(p!==s.descriptorDigest)throw new U("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 U("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:re(e.holder,a),handlers:{mailbox_otp:async()=>({otp:e.code})},signal:d})}catch(e){throw ie(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:ee(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 ie(e,"credential",d)}}async function $(e){return async function(e,t){const r=e.profile??D;W(r,"request",e.allowHeldProfile);const i=Q(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 U("session","SESSION_INVALID");a||(a=await B({...e,address:i}),await(s?.put(a)));const d=P(a);if(!e.getCode)return{status:"code-requested",pending:d};const c=await e.getCode({pending:d});try{const r=await K({...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 U&&e.recoverable||await(s?.delete(a.requestId).catch(()=>{})),e}}(e,I)}function Q(e,t){if(t===y)return function(e){const t=()=>new U("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||!J.test(s)||s.startsWith("+"))throw t();if(o.length>253||!o.includes(".")||!o.split(".").every(e=>e.length<=63&&z.test(e)))throw t();return i}(e);const r=e.trim();if(r.length>254||!b.test(r))throw new U("request","ADDRESS_INVALID");return r}var J=/^[a-z0-9!#$%&'*+\-/=?^_`{|}~]+(\.[a-z0-9!#$%&'*+\-/=?^_`{|}~]+)*$/,z=/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;function X(e){return`${e}#${e.slice(O.length)}`}function G(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 U(t,"HOLDER_INVALID")}(e,t);if(!R.test(e.did)||"EdDSA"!==e.alg||e.kid!==X(e.did))throw new U(t,"HOLDER_INVALID")}function W(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 U(t,"PROFILE_UNAVAILABLE");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 Z(e,t,i,s,o){const a=W(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 U(r,"CANCELED"):ie(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 U(s,"PROFILE_UNAVAILABLE");if(await(0,r.canonicalDigest)(d)!==a.descriptorDigest)throw new U(s,"PROFILE_UNAVAILABLE");return d}function ee(e){return{type:"OpenCredentialsIssuerMetadata",version:1,origin:n.witnessOrigin,issuerDid:n.issuerDid,keys:e,cache:{maxAgeSeconds:3600,etag:"pinned"}}}async function te(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:ee(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 re(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 U||r)throw e;throw new U("credential","SIGNATURE_REJECTED")}},holderKey:{alg:e.alg,kid:e.kid}}}function ie(e,t,i){if(e instanceof U)return e;if(e instanceof DOMException&&"TimeoutError"===e.name)return new U(t,"NETWORK");const n=(0,r.credentialError)(e),s=n.details;switch(n.code){case"ISSUER_UNREADY":return"rate_limited"===s.state?new U(t,"RATE_LIMITED",s.retryAfterMs,n.recoverable):new U(t,"ISSUER_UNAVAILABLE",void 0,n.recoverable);case"OFFLINE":return i?.aborted&&"TimeoutError"!==i.reason?.name?new U(t,"CANCELED"):new U(t,"NETWORK");case"UNSUPPORTED_PROFILE":case"UNSUPPORTED_VERSION":case"DESCRIPTOR_INVALID":return new U(t,"PROFILE_UNAVAILABLE");case"PROOF_REJECTED":return new U("code","CODE_REJECTED",void 0,!0);case"VERIFICATION_FAILED":return"proof_attempts_exhausted"===s.state?new U("code","CODE_ATTEMPTS_EXHAUSTED"):"credential"===t?new U("credential","CREDENTIAL_INVALID"):"code"===t?new U("code","CODE_REJECTED",void 0,!1):new U(t,"FAILED");case"HOLDER_MISMATCH":return new U("credential","CREDENTIAL_INVALID");case"REQUEST_EXPIRED":return new U("session","SESSION_EXPIRED");case"REQUEST_SUBSTITUTED":return new U("session","SESSION_INVALID");case"SIGNATURE_REJECTED":return new U("credential","SIGNATURE_REJECTED",void 0,n.recoverable);case"CANCELED":return new U(t,"CANCELED");default:return new U(t,"FAILED")}}const ne="blockchainAccountId",se="1",oe=0;function ae(){return new U("request","HOLDER_INVALID")}const de=["audience","challengeNonce","completionContext","completionOrigin","credentialLifetimeSeconds","descriptorDigest","expiresAt","holderDid","issuedAt","issuer","issuerKid","jti","normalizedClaimsDigest","openerOrigin","profile","profileVersion","protocol","requestId","requirementDigest","type"],ce=/^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,le=/^[A-Za-z0-9_-]{32}$/,ue=/^[A-Za-z0-9_-]{43}$/,pe=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/,fe=6e5;function he(e){try{return new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(e)}catch{throw ae()}}function Ee(e,t){const n=(0,i.parsePkhDid)(e);if(null===n||n.chainId!==se)throw ae();const o=(0,i.toChecksumAddress)(n.address),a=`did:pkh:eip155:${se}:${o}`;return{did:a,alg:"EIP191",kid:`${a}#${ne}`,sign:async e=>{const n=new Uint8Array(e);!function(e,t){const n=he(e);let o,a;try{o=JSON.parse(n),a=(0,r.jcsCanonicalize)(o)}catch{throw ae()}if(a!==n||"object"!=typeof o||null===o||Array.isArray(o))throw ae();const d=o;if(Object.keys(d).sort().join()!==de.join())throw ae();for(const e of de)if("profileVersion"!==e&&"credentialLifetimeSeconds"!==e&&("string"!=typeof d[e]||""===d[e]))throw ae();const c=e=>d[e];if(Object.keys(s).some(e=>d[e]!==s[e])||!(0,i.pkhPrincipalsEqual)(d.holderDid,t)||!ce.test(c("jti"))||!le.test(c("requestId"))||!le.test(c("challengeNonce"))||!ue.test(c("requirementDigest"))||!ue.test(c("normalizedClaimsDigest"))||!pe.test(c("issuedAt"))||!pe.test(c("expiresAt"))||Date.parse(c("expiresAt"))-Date.parse(c("issuedAt"))!==fe)throw ae()}(function(e){const t=(new TextEncoder).encode(i.ACCOUNT_BINDING_DOMAIN);if(e.length<=t.length+1||e[t.length]!==oe)throw ae();for(let r=0;r<t.length;r++)if(e[r]!==t[r])throw ae();return e.subarray(t.length+1)}(n),a);const d=he(n),c=await t(n),l=c[64];if(65!==c.length||27!==l&&28!==l)throw ae();if(!await(0,r.verifyEip191MessageSignature)(d,function(e){return`0x${Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}`}(c),o))throw ae();return c}}}const we=6e5;function ge(e,t){return e.getTime()-t.getTime()>we}const Ie=50,De="1",me="KV_NOT_FOUND";function Ae(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!==De)throw new r.CredentialError("ACTIVE_SESSION_REQUIRED","Held credentials require an Ethereum mainnet (chain 1) account owner");return`did:pkh:eip155:${De}:${(0,i.toChecksumAddress)(t.address)}`}function ye(e){return`v1/held/${(0,i.registryKey)(e)}/`}function Se(e,t){return`${ye(e)}${t}`}function ve(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 Te(e,t,r){return{issuerSet:e.issuerSet,acceptedIssuers:e.acceptedIssuers,didMethods:e.didMethods,now:t,owner:r}}async function Ce(e){return{type:"TinyCloudHeldStorageReceipt",version:1,ownerDid:e.ownerDid,recordId:e.recordId,recordDigest:await(0,r.canonicalDigest)(e),storedAt:e.storedAt}}async function _e(e){const t=e.now??new Date,n=Ae(e.ownerDid);let s;try{s=(0,i.verifyHeldEmailCredential)(e.sdJwt,Te(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(!ge(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=()=>new r.CredentialError("VERIFIED_NOT_SAVED","Held credential could not be confirmed in storage"),o=await e.batchPut([{key:t,value:n}]).catch(()=>{});if(!0!==o?.ok)throw s();const a=await e.get(t).catch(()=>{}),d=!0===a?.ok?a.data.data:void 0;if(!ve(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,Se(n,d),c);return{record:l,receipt:await Ce(l),verified:s}}async function Oe(e,t,r,i,n){const s=await e.get(t);return Re(s.ok?s.data.data:void 0,t,r,i,n)}async function Re(e,t,n,s,o){if(!ve(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!==Se(n,d))return{kind:"invalid"};let c;try{c=(0,i.verifyHeldEmailCredential)(e.credential,Te(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 be extends r.CredentialError{}async function Ne(e,t){const i=[];let n;for(let s=0;s<Ie;s+=1){const s=await e.list(void 0===n?{prefix:t}:{prefix:t,cursor:n});if(!s.ok)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 be("VERIFICATION_FAILED","Held listing exceeds the page limit")}async function qe(e){const t=e.now??new Date,r=Ae(e.ownerDid),i=await Ne(e.kv,ye(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 Oe(e.kv,o,r,e,t);if("verified"!==i.kind||i.email!==n)continue;const a=i.match.verified.expiresAt.getTime();ge(i.match.verified.expiresAt,t)&&(void 0===s||a>s.verified.expiresAt.getTime())&&(s=i.match)}return s}async function Le(e){const t=e.now??new Date,n=Ae(e.ownerDid),s=await Ne(e.kv,ye(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===me)continue;throw new r.CredentialError("OFFLINE","A held credential could not be read")}let d;try{d=await Re(s.data.data,a,n,e,t)}catch(e){if(e instanceof i.HeldCredentialError&&"bad-config"===e.code)throw e;continue}"verified"===d.kind&&ge(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 Ue="tinycloud.email-held/v1",xe="opencredentials.email/v1",Pe=3e5;class Fe extends Error{constructor(e,t){super(t),this.retryable=!1,this.name="HeldSourceError",this.code=e}}const ke="Saved held credentials list is too long to read; clear old ones";async function Ve(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=Ae(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 Le({...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()+Pe))).filter(e=>e.email===a));try{return await d()}catch(e){if(!(e instanceof be))throw e}try{return await async function(e){const t=e.now??new Date,r=Ae(e.ownerDid),i=await Ne(e.kv,ye(r));if(void 0===i)return[];const n=[],s=new Map;for(const o of i){const i=await Oe(e.kv,o,r,e,t);if("invalid"===i.kind)continue;if("expired"===i.kind){n.push(o);continue}const a={key:o,recordId:i.match.record.recordId,expiresAt:i.match.verified.expiresAt.getTime()},d=s.get(i.email);if(void 0===d){s.set(i.email,a);continue}const c=a.expiresAt>d.expiresAt||a.expiresAt===d.expiresAt&&a.recordId>d.recordId;s.set(i.email,c?a:d),n.push(c?d.key:a.key)}const o=[];for(const t of n)(await e.kv.delete(t)).ok&&o.push(t);return o}({...t,kv:e,ownerDid:n,now:o()}),await d()}catch(e){if(e instanceof be)throw new Fe("held-store-listing-limit",ke);throw e}}(s,E,g,o,w)}catch(e){if(I||!(e instanceof r.CredentialError&&"OFFLINE"===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(xe)||!d.profiles.includes(Ue)||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:Ue,getCode:c,pendingStore:He(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>Pe)throw new r.CredentialError("VERIFICATION_FAILED","client clock is more than 5 minutes behind the issuer");let v;try{v=await _e({...E,kv:s,ownerDid:g,sdJwt:A,now:new Date(Math.max(y,S))})}catch{throw new r.CredentialError("VERIFIED_NOT_SAVED","Verified held credential could not be stored")}return{credential:A,holderDid:g,expiresAt:v.verified.expiresAt}}(e,$)}function He(e,t,r){if(void 0===e)return;const n=e=>void 0!==e&&e.profile===Ue&&(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 +1 @@
1
- import{CredentialError as e,canonicalDigest as t,createEmailCredentialRequirement as i,credentialEndpointPath as r,credentialError as n,credentialRequirementDigest as s,decodeBase64Url as o,descriptorSatisfiesRequirement as a,encodeBase64Url as d,holderBindingCanonicalBytes as c,holderBindingSigningBytes as l,sha256Base64Url as u,validateCredentialFlowDescriptor as p,validateCredentialHolderBinding as f,verifyEip191MessageSignature as h,verifyIssuedCredential as w}from"@tinycloud/sdk-core";import{ACCOUNT_BINDING_DOMAIN as E,HeldCredentialError as I,parsePkhDid as g,pkhPrincipalsEqual as D,registryKey as A,toChecksumAddress as y,verifyHeldEmailCredential as S}from"@tinycloud/sdk-core/held-credentials";var v=(e,t)=>new Promise((i,r)=>{const n=setTimeout(i,e);t?.addEventListener("abort",()=>{clearTimeout(n),r(new DOMException("Aborted","AbortError"))},{once:!0})});async function T(t){const i=new Map(t.descriptor.steps.map(e=>[e.type,e])),r=new Set;let n="";for(;;){t.signal?.throwIfAborted();const s=await t.transport.state(t.requestId,t.verifier,t.signal);if(s.requestId!==t.requestId)throw new e("REQUEST_SUBSTITUTED","Credential request identity changed");if("expired"===s.state)throw new e("REQUEST_EXPIRED","Credential request expired",{state:s.state,correlationId:s.correlationId});if("canceled"===s.state)throw new e("CANCELED","Credential request was canceled",{state:s.state,correlationId:s.correlationId});if("issuer_unready"===s.state)throw new e("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:s.retryAfterMs,state:s.state,correlationId:s.correlationId});if("complete"===s.state)return;if("ready_to_issue"===s.state||"issued"===s.state){"ready_to_issue"!==s.state||r.has("issue")?await(t.onWait?.()??v(s.retryAfterMs??50,t.signal)):(await t.transport.issue(t.requestId,t.verifier,t.signal),r.add("issue"));continue}const o=s.nextStep;if(!o){await(t.onWait?.()??v(s.retryAfterMs??50,t.signal));continue}const a=i.get(o.type);if(o.id!==o.type||!a||a.type!==o.type||a.version!==o.version)throw new e("REQUEST_SUBSTITUTED","Server selected an undeclared credential step");if(r.has(o.id)||s.transitionId===n)await(t.onWait?.()??v(s.retryAfterMs??50,t.signal));else{if(n=s.transitionId,"holder_signature"===o.type){t.onProgress?.({state:"signing",stepId:o.id,correlationId:s.correlationId});const i=f(await t.transport.holderBinding(t.requestId,t.verifier,t.signal));if(i.requestId!==t.requestId||i.descriptorDigest!==t.descriptorDigest||i.requirementDigest!==t.requirementDigest||i.holderDid!==t.holderDid||i.issuer!==t.descriptor.issuer.did||i.issuerKid!==t.descriptor.issuer.kid||i.profile!==t.descriptor.profile||i.openerOrigin!==t.openerOrigin||i.completionOrigin!==t.openerOrigin||"tinycloud://credentials"!==i.audience)throw new e("REQUEST_SUBSTITUTED","Holder binding was substituted");const r=l(i);let n=await(t.signing.autoSign?.(i,r,t.signal));if(void 0===n){if(!t.signing.requestApproval)throw new e("SIGNATURE_REJECTED","OpenKey approval is required");try{n=await t.signing.requestApproval(i,r,t.signal)}catch(t){if(t instanceof e)throw t;throw new e("SIGNATURE_REJECTED","OpenKey approval was rejected",{cause:t})}}if(!(n instanceof Uint8Array)||0===n.length)throw new e("SIGNATURE_REJECTED","OpenKey signature is invalid");await t.transport.submitHolderSignature(t.requestId,t.verifier,d(n),t.signal,t.signing.holderKey)}else{t.onProgress?.({state:"collect_input"===o.type?"collecting":"proving",stepId:o.id,correlationId:s.correlationId});const i=t.handlers?.[o.type],r=t.proofHandler;if(!i&&!r){await(t.onWait?.()??v(s.retryAfterMs??50,t.signal));continue}if(!0===o.constraints.challengeRequired&&await t.transport.beginStep(t.requestId,t.verifier,o.type,t.signal),i){const e=await i({descriptor:t.descriptor,requirement:t.requirement,stepId:o.id,constraints:o.constraints,signal:t.signal});await t.transport.submitStep(t.requestId,t.verifier,o.id,e,t.signal)}else{let i;for(let n=1;;n+=1){const s=await r({stepId:o.id,constraints:o.constraints,display:{title:t.descriptor.display.title,description:t.descriptor.display.description,consent:t.descriptor.display.consent,progressLabel:t.descriptor.accessibility.progressLabel,errorLiveRegion:t.descriptor.accessibility.errorLiveRegion},inputs:t.descriptor.inputs.map(({id:e,label:t,schema:i})=>({id:e,label:t,schema:i})),...void 0===i?{}:{feedback:i},signal:t.signal});try{await t.transport.submitStep(t.requestId,t.verifier,o.id,s,t.signal);break}catch(r){if(!(r instanceof e)||"PROOF_REJECTED"!==r.code)throw r;const s=t.descriptor.lifecycle.maxProofAttempts-n;if("mailbox_otp"!==o.type||s<=0)throw new e("VERIFICATION_FAILED","The proof was not accepted",{state:s<=0?"proof_attempts_exhausted":"proof_rejected",cause:r});i={kind:"rejected",attemptsRemaining:s}}}}}r.add(o.id)}}}function m(t,i){if("object"!=typeof t||null===t||Array.isArray(t))throw new e("VERIFICATION_FAILED",`${i} is invalid`);return t}function _(t,i){if("string"!=typeof t||!/^[A-Za-z0-9_-]{16,128}$/.test(t))throw new e("REQUEST_SUBSTITUTED",`${i} is invalid`);return t}function R(t,i){if("string"!=typeof t||!Number.isFinite(Date.parse(t)))throw new e("VERIFICATION_FAILED",`${i} is invalid`);return new Date(t).toISOString()}var O=new Set(["REQUEST_EXPIRED","ISSUER_UNREADY","UNSUPPORTED_PROFILE","UNSUPPORTED_VERSION","SIGNATURE_REJECTED"]),b=class{constructor(e,t=globalThis.fetch.bind(globalThis),i={}){this.descriptor=e,this.fetchFn=t,this.options=i,this.nonces=new Map,this.bindings=new Map}url(e,t){return new URL(r(e,t),this.descriptor.issuer.origin).href}async request(t,i){let r;try{const e={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(t,i.id),e)}catch(t){if(t instanceof DOMException&&"AbortError"===t.name)throw new e("CANCELED","Credential acquisition was canceled",{cause:t});throw new e("OFFLINE","OpenCredentials is unavailable",{cause:t})}if(!r.ok){let t;try{t=await r.json()}catch{t=void 0}const i=function(t,i,r){if("object"!=typeof t||null===t||Array.isArray(t))return;const n=t;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 e("PROOF_REJECTED","The proof was not accepted",{state:n.state,correlationId:n.correlationId}):new e("VERIFICATION_FAILED","The proof attempt limit was reached",{state:"proof_attempts_exhausted",correlationId:n.correlationId});if("RATE_LIMITED"===n.code)return new e("ISSUER_UNREADY","Too many verification codes were requested",{state:"rate_limited",correlationId:n.correlationId,retryAfterMs:1e3*Number(i.headers.get("retry-after"))||void 0,recoverable:r?n.recoverable:void 0});if("CHALLENGE_EXPIRED"===n.code)return new e("REQUEST_EXPIRED","The credential challenge expired",{state:n.state,correlationId:n.correlationId,recoverable:r?n.recoverable:void 0});if(!O.has(n.code))return;const s=n.code;return new e(s,`OpenCredentials rejected the request: ${s}`,{state:n.state,correlationId:n.correlationId,retryAfterMs:1e3*Number(i.headers.get("retry-after"))||void 0,recoverable:r?n.recoverable:void 0})}(t,r,!0===this.options.honorServerRecoverable);if(i)throw i;if(410===r.status)throw new e("REQUEST_EXPIRED","Credential request expired");if(409===r.status)throw new e("REQUEST_SUBSTITUTED","Credential request was replayed or substituted");if(503===r.status)throw new e("ISSUER_UNREADY","Credential issuer is not ready",{retryAfterMs:1e3*Number(r.headers.get("retry-after"))||void 0});throw new e("VERIFICATION_FAILED","OpenCredentials rejected the request")}if(204!==r.status)try{return await r.json()}catch(t){throw new e("VERIFICATION_FAILED","OpenCredentials response is invalid",{cause:t})}}async create(t){const i=m(await this.request("request",{method:"POST",body:{protocol:t.descriptor.protocol,profile:t.descriptor.profile,profileVersion:t.descriptor.profileVersion,descriptorDigest:t.descriptorDigest,requirementDigest:t.requirementDigest,holderDid:t.holderDid,inputs:t.inputs??t.requirement.claims,audience:"tinycloud://credentials",openerOrigin:t.openerOrigin,completionOrigin:t.openerOrigin,completionContext:"sdk-acquisition",completionVerifierChallenge:t.completionVerifierChallenge},signal:t.signal}),"create response");if("tinycloud.credentials/acquisition-request/v1"!==i.type||i.protocol!==t.descriptor.protocol||"challenge"!==i.next||"challenge"!==i.endpoint)throw new e("VERIFICATION_FAILED","create response is invalid");const r=_(i.requestId,"requestId");return{requestId:r,locator:r,expiresAt:R(i.expiresAt,"expiresAt"),correlationId:r}}proofStep(){return this.descriptor.steps.some(e=>"mailbox_otp"===e.type)?"mailbox_otp":"collect_input"}async state(t,i,r){const n=m(await this.request("state",{id:t,verifier:i,signal:r}),"state response");if("tinycloud.credentials/acquisition-state/v1"!==n.type||n.requestId!==t||n.profile!==this.descriptor.profile||1!==n.profileVersion)throw new e("REQUEST_SUBSTITUTED","Credential state response is substituted");const s={type:"OpenCredentialsAcquisitionState",version:1,requestId:t,transitionId:`${String(n.state)}:${String(n.resultPreviouslyRead??!1)}`,correlationId:t};if("challenge_required"===n.state){const e=this.proofStep();return{...s,state:"pending",nextStep:{id:e,type:e,version:1,constraints:{challengeRequired:!0}}}}if("proof_required"===n.state){const e=this.proofStep();return this.nonces.set(t,_(n.challengeNonce,"challengeNonce")),{...s,state:"pending",nextStep:{id:e,type:e,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 e("REQUEST_SUBSTITUTED","Credential state is unsupported")}async beginStep(t,i,r,n){const s=this.proofStep();if(r!==s)throw new e("REQUEST_SUBSTITUTED","Credential challenge step is substituted");const o=m(await this.request("challenge",{id:t,verifier:i,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 e("REQUEST_SUBSTITUTED","Credential challenge is substituted");this.nonces.set(t,_(o.challengeNonce,"challengeNonce"))}async submitStep(t,i,r,n,s){const o=this.proofStep();if(r!==o)throw new e("REQUEST_SUBSTITUTED","Credential proof step is substituted");const a=this.nonces.get(t);if(!a)throw new e("REQUEST_SUBSTITUTED","Credential challenge is missing");await this.request("proof",{id:t,verifier:i,method:"POST",body:{step:o,stepVersion:1,challengeNonce:a,proof:n},signal:s})}async holderBinding(t,i,r){const n=m(await this.request("holder_binding",{id:t,verifier:i,signal:r}),"holder binding response");if("tinycloud.credentials/holder-binding-request/v1"!==n.type||"tinycloud.credentials/holder-binding/v1"!==n.signingDomain||"EdDSA"!==n.alg||"string"!=typeof n.canonical)throw new e("REQUEST_SUBSTITUTED","Holder binding response is invalid");const s=f(n.binding);if(d(c(s))!==n.canonical)throw new e("REQUEST_SUBSTITUTED","Holder binding canonical bytes were substituted");return this.bindings.set(t,s),s}async submitHolderSignature(t,i,r,n,s){const o=this.bindings.get(t);if(!o)throw new e("REQUEST_SUBSTITUTED","Holder binding was not retrieved");const a=s?.kid??`${o.holderDid}#${o.holderDid.replace("did:key:","")}`;await this.request("holder_signature",{id:t,verifier:i,method:"POST",body:{alg:s?.alg??"EdDSA",kid:a,signature:r},signal:n})}async issue(e,t,i){await this.request("issue",{id:e,verifier:t,method:"POST",signal:i})}async result(i,r,n){const s=m(await this.request("result",{id:i,verifier:r,signal:n}),"result response");if("tinycloud.credentials/result/v1"!==s.type||s.protocol!==this.descriptor.protocol||s.profile!==this.descriptor.profile||1!==s.profileVersion||"vc+sd-jwt"!==s.format||s.descriptorDigest!==await t(this.descriptor)||s.issuer!==this.descriptor.issuer.did||s.issuerKid!==this.descriptor.issuer.kid||"string"!=typeof s.credential||await u(s.credential)!==s.credentialDigest)throw new e("VERIFICATION_FAILED","Issued result metadata is invalid");const a=m(s.holderBinding,"result holder binding");if(s.subject!==a.did||"tinycloud.credentials/holder-binding/v1"!==a.signingDomain)throw new e("HOLDER_MISMATCH","Issued holder binding is invalid");const d=m(s.claims,"result claims"),c={};for(const[t,i]of Object.entries(d)){if("string"!=typeof i)throw new e("VERIFICATION_FAILED","Issued claims are invalid");c[t]=i}const l=m(s.validity,"result validity"),p=function(t){const i=t.split("~",1)[0]?.split(".")[1];if(!i)throw new e("VERIFICATION_FAILED","Issued SD-JWT is invalid");try{return m(JSON.parse((new TextDecoder).decode(o(i))),"SD-JWT payload")}catch(t){if(t instanceof e)throw t;throw new e("VERIFICATION_FAILED","Issued SD-JWT is invalid",{cause:t})}}(s.credential);if("string"!=typeof p.jti)throw new e("VERIFICATION_FAILED","Credential id is invalid");const f=R(l.issuedAt,"issuedAt"),h=R(l.expiresAt,"expiresAt"),w=m(s.status,"result status");if("none"!==w.type||w.freshnessSeconds!==this.descriptor.status.freshnessSeconds)throw new e("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:s.issuer,issuerKid:s.issuerKid,subjectDid:s.subject,holderDid:s.subject,claims:c,claimsDigest:await t(c),descriptorDigest:s.descriptorDigest,credentialId:p.jti,issuedAt:f,notBefore:f,expiresAt:h,status:{method:"none",freshnessSeconds:w.freshnessSeconds},credential:s.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}},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"}),C={id:"opencredentials.email/v1",version:1},L=9e5,q=`${N.witnessOrigin}/.well-known/opencredentials`,U=[{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"}],F="tinycloud.email-proof/v1",x={"tinycloud.email-proof/v1":{descriptorDigest:N.descriptorDigest,requiredStep:"mailbox_otp",enabled:!0},"tinycloud.email-held/v1":{descriptorDigest:"dc3_DuvzipXwYkTfjKqTaK1c3VS0YSPnaBsYSQriC0w",requiredStep:"mailbox_otp",enabled:!1}},V="https://localhost",k=/^did:key:z6Mk[^#]+$/,P=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,M=Symbol.for("nodejs.util.inspect.custom"),H={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,CANCELED:!1,FAILED:!1},B={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.",CANCELED:"Email verification was canceled.",FAILED:"Email verification failed."},j=class extends Error{constructor(e,t,i,r=H[t]){super("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):B[t]),this.name="EmailProofError",this.step=e,this.code=t,this.retryAfterMs=i,this.recoverable=r}};function J(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 j("request","HOLDER_INVALID");if(!k.test(r))throw new j("request","HOLDER_INVALID");return{did:r,alg:"EdDSA",kid:ie(r),sign:t}}function Q(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},i={...t};return $(i,"verifier",e.verifier),$(i,"toJSON",()=>({...t})),$(i,M,()=>({...t,verifier:"[redacted]"})),Object.freeze(i)}function $(e,t,i){Object.defineProperty(e,t,{value:i,enumerable:!1,writable:!1,configurable:!1})}function K(e){return Math.min(Date.parse(e.expiresAt),Date.parse(e.createdAt)+L)}function X(){const e=new Map,t=t=>{for(const[i,r]of e)K(r)<=t.getTime()&&e.delete(i)};return{async findLive(i,r){let n;t(r);for(const t of e.values())t.address===i&&(!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(i,r)=>(t(r),e.get(i))}}var G=class extends Error{},W=async()=>{throw new G("code requested")};async function Y(e){const i=e.profile??F;ne(i,"request");const r=te(e.address);re(e.holder,"request");const n=e.now??(()=>new Date),o=e.signal??AbortSignal.timeout(6e4),a=se(r,i),c=await s(a),l=await oe(i,a,{fetch:e.fetch,signal:o},"request"),p=await t(l),f=d(crypto.getRandomValues(new Uint8Array(32))),h=new b(l,e.fetch,{honorServerRecoverable:!0}),w=n().getTime();let E;try{E=await h.create({descriptor:l,descriptorDigest:p,requirement:a,requirementDigest:c,holderDid:e.holder.did,openerOrigin:V,completionVerifierChallenge:await u(f),signal:o})}catch(e){throw le(e,"request",o)}const I=Date.parse(E.expiresAt);if(!Number.isFinite(I))throw new j("request","FAILED");const g=Q({type:"TinyCloudEmailProofPending",version:1,profile:i,address:r,requestId:E.requestId,verifier:f,holderDid:e.holder.did,descriptorDigest:p,requirementDigest:c,openerOrigin:V,createdAt:new Date(w).toISOString(),expiresAt:new Date(Math.min(I,w+L)).toISOString()});try{await T({descriptor:l,requirement:a,requestId:E.requestId,verifier:f,holderDid:e.holder.did,descriptorDigest:p,requirementDigest:c,openerOrigin:V,transport:h,signing:ce(e.holder),handlers:{mailbox_otp:W},signal:o})}catch(e){if(e instanceof G)return g;throw le(e,"request",o)}throw new j("request","FAILED")}async function z(e){return Z(e,U)}async function Z(e,i){const{pending:r}=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===V&&[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))}(r))throw new j("session","SESSION_INVALID");if(K(r)<=n().getTime())throw new j("session","SESSION_EXPIRED");if(!/^\d{8}$/.test(e.code))throw new j("code","CODE_INVALID");if(re(e.holder,"code"),e.holder.did!==r.holderDid)throw new j("session","SESSION_INVALID");const o=e.signal??AbortSignal.timeout(6e4),a=se(r.address,r.profile);if(await s(a)!==r.requirementDigest)throw new j("session","SESSION_INVALID");const d=await oe(r.profile,a,{fetch:e.fetch,signal:o},"session"),c=await t(d);if(c!==r.descriptorDigest)throw new j("session","SESSION_INVALID");const l=new b(d,e.fetch,{honorServerRecoverable:!0});try{const t=await l.state(r.requestId,r.verifier,o);if(!0===t.nextStep?.constraints.challengeRequired)throw new j("session","SESSION_INVALID");await T({descriptor:d,requirement:a,requestId:r.requestId,verifier:r.verifier,holderDid:r.holderDid,descriptorDigest:c,requirementDigest:r.requirementDigest,openerOrigin:r.openerOrigin,transport:l,signing:ce(e.holder),handlers:{mailbox_otp:async()=>({otp:e.code})},signal:o})}catch(e){throw le(e,"code",o)}try{const e=await l.result(r.requestId,r.verifier,o),t=await w({envelope:e,descriptor:d,descriptorDigest:c,requirement:a,holderDid:r.holderDid,issuerMetadata:ae(i),now:n(),checkStatus:(e,t)=>l.checkStatus(e,t),signal:o});return{envelope:e,verified:t,credentialId:t.credentialId,issuedAt:t.issuedAt,expiresAt:t.expiresAt,descriptor:d}}catch(e){throw le(e,"credential",o)}}async function ee(e){return async function(e,t){const i=te(e.address),r=e.now??(()=>new Date),n=e.pendingStore,s=e.profile??F,o=n?await n.findLive(i,r()):void 0;let a=o?.profile===s?o:void 0;a||(a=await Y({...e,address:i}),await(n?.put(a)));const d=Q(a);if(!e.getCode)return{status:"code-requested",pending:d};const c=await e.getCode({pending:d});try{const i=await Z({...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 j&&e.recoverable||await(n?.delete(a.requestId).catch(()=>{})),e}}(e,U)}function te(e){const t=e.trim();if(t.length>254||!P.test(t))throw new j("request","ADDRESS_INVALID");return t}function ie(e){return`${e}#${e.slice(8)}`}function re(e,t){if(!k.test(e.did)||"EdDSA"!==e.alg||e.kid!==ie(e.did))throw new j(t,"HOLDER_INVALID")}function ne(e,t){const i=Object.prototype.hasOwnProperty.call(x,e)?x[e]:void 0;if(!i||!i.enabled)throw new j(t,"PROFILE_UNAVAILABLE");return i}function se(e,t){return i({email:e,profile:{id:t,version:1},credentialType:C})}async function oe(i,r,n,s){const o=ne(i,s);let d;try{d=await async function(i,r,n={}){let s;try{s=new URL(r)}catch{throw new e("UNSUPPORTED_PROFILE","Discovery URL is invalid")}if("https:"!==s.protocol||!["/.well-known/opencredentials","/v1/credential-types"].includes(s.pathname)||s.search||s.hash)throw new e("UNSUPPORTED_PROFILE","Discovery URL is not an allowed catalog endpoint");const o={credentials:"omit",cache:"no-store",redirect:"error",referrerPolicy:"no-referrer",signal:n.signal};let d;try{d=await(n.fetch??globalThis.fetch.bind(globalThis))(s,o)}catch(t){throw new e("OFFLINE","Credential discovery is unavailable",{cause:t})}if(!d.ok)throw new e(503===d.status?"ISSUER_UNREADY":"OFFLINE","Credential discovery is unavailable");const c=await d.json();if("tinycloud.credentials/catalog/v1"!==c.type||"tinycloud.credentials/acquisition/v1"!==c.protocol||1!==c.catalogVersion||!Array.isArray(c.profiles))throw new e("DESCRIPTOR_INVALID","Credential catalog is invalid");for(const e of c.profiles){if("object"!=typeof e||null===e||Array.isArray(e))continue;const r=e;if(!0===r.supported&&!0===r.enabled&&("ready"===r.readiness||"degraded"===r.readiness))try{const e=p(r.descriptor);if(a(e,i)&&r.descriptorDigest===await t(e))return e}catch{}}throw new e("UNSUPPORTED_PROFILE","No available credential profile satisfies the requirement")}(r,q,{fetch:n.fetch,signal:n.signal})}catch(e){throw function(e,t,i){return t.aborted&&"TimeoutError"!==t.reason?.name?new j(i,"CANCELED"):le(e,i,t)}(e,n.signal,s)}if(d.issuer.origin!==N.witnessOrigin||d.issuer.did!==N.issuerDid||!d.steps.some(e=>e.type===o.requiredStep))throw new j(s,"PROFILE_UNAVAILABLE");if(await t(d)!==o.descriptorDigest)throw new j(s,"PROFILE_UNAVAILABLE");return d}function ae(e){return{type:"OpenCredentialsIssuerMetadata",version:1,origin:N.witnessOrigin,issuerDid:N.issuerDid,keys:e,cache:{maxAgeSeconds:3600,etag:"pinned"}}}async function de(i){return async function(i,r){const{record:n,requirement:o,holderDid:a}=i,d=n.descriptor;if(n.descriptorDigest!==N.descriptorDigest||await t(d)!==N.descriptorDigest)throw new e("VERIFICATION_FAILED","stored descriptor does not match the pinned descriptor digest");const c={type:"OpenCredentialsIssuedCredential",version:1,protocol:d.protocol,profile:n.profile,credentialType:n.credentialType,schema:n.schema,format:"vc+sd-jwt",issuerDid:n.issuerDid,issuerKid:n.issuerKid,subjectDid:n.subjectDid,holderDid:n.holderDid,claims:n.claims,claimsDigest:n.claimsDigest,descriptorDigest:n.descriptorDigest,credentialId:n.credentialId,issuedAt:n.issuedAt,notBefore:n.notBefore,expiresAt:n.expiresAt,status:n.status,credential:n.credential},l=await w({envelope:c,descriptor:d,descriptorDigest:N.descriptorDigest,requirement:o,holderDid:a,issuerMetadata:ae(r),now:i.now,checkStatus:async e=>"none"===e.method&&e.freshnessSeconds===d.status.freshnessSeconds,signal:i.signal});if(n.holderDid!==a||n.ownerDid!==a)throw new e("HOLDER_MISMATCH","stored record belongs to another holder");if(n.credentialDigest!==l.credentialDigest)throw new e("VERIFICATION_FAILED","stored credential digest does not match the verified credential");if(n.requirementDigest!==await s(o))throw new e("VERIFICATION_FAILED","stored requirement digest does not match the requirement");if(n.recordId!==await t({credentialDigest:l.credentialDigest,holderDid:n.ownerDid}))throw new e("VERIFICATION_FAILED","stored record id does not match its credential");return l}(i,U)}function ce(e){return{autoSign:async(t,i)=>e.sign(i),holderKey:{alg:"EdDSA",kid:e.kid}}}function le(e,t,i){if(e instanceof j)return e;if(e instanceof DOMException&&"TimeoutError"===e.name)return new j(t,"NETWORK");const r=n(e),s=r.details;switch(r.code){case"ISSUER_UNREADY":return"rate_limited"===s.state?new j(t,"RATE_LIMITED",s.retryAfterMs,r.recoverable):new j(t,"ISSUER_UNAVAILABLE",void 0,r.recoverable);case"OFFLINE":return i?.aborted&&"TimeoutError"!==i.reason?.name?new j(t,"CANCELED"):new j(t,"NETWORK");case"UNSUPPORTED_PROFILE":case"DESCRIPTOR_INVALID":return new j(t,"PROFILE_UNAVAILABLE");case"PROOF_REJECTED":return new j("code","CODE_REJECTED",void 0,!0);case"VERIFICATION_FAILED":return"proof_attempts_exhausted"===s.state?new j("code","CODE_ATTEMPTS_EXHAUSTED"):"credential"===t?new j("credential","CREDENTIAL_INVALID"):"code"===t?new j("code","CODE_REJECTED",void 0,!1):new j(t,"FAILED");case"HOLDER_MISMATCH":return new j("credential","CREDENTIAL_INVALID");case"REQUEST_EXPIRED":return new j("session","SESSION_EXPIRED");case"REQUEST_SUBSTITUTED":return new j("session","SESSION_INVALID");case"SIGNATURE_REJECTED":return new j("credential","SIGNATURE_REJECTED",void 0,r.recoverable);case"CANCELED":return new j(t,"CANCELED");default:return new j(t,"FAILED")}}function ue(){return new j("request","HOLDER_INVALID")}function pe(e,t){const i=g(e);if(null===i||"1"!==i.chainId)throw ue();const r=y(i.address),n=`did:pkh:eip155:1:${r}`;return{did:n,alg:"EIP191",kid:`${n}#blockchainAccountId`,sign:async e=>{!function(e){const t=(new TextEncoder).encode(E);if(e.length<=t.length+1||0!==e[t.length])throw ue();for(let i=0;i<t.length;i++)if(e[i]!==t[i])throw ue()}(e);const i=function(e){try{return new TextDecoder("utf-8",{fatal:!0}).decode(e)}catch{throw ue()}}(e),n=await t(e),s=n[64];if(65!==n.length||27!==s&&28!==s)throw ue();if(!await h(i,function(e){return`0x${Array.from(e,e=>e.toString(16).padStart(2,"0")).join("")}`}(n),r))throw ue();return n}}}function fe(e,t){return e.getTime()-t.getTime()>6e5}function he(t){const i=g(t);if(null===i)throw new e("ACTIVE_SESSION_REQUIRED","Held credentials require a did:pkh:eip155 account owner");if("1"!==i.chainId)throw new e("ACTIVE_SESSION_REQUIRED","Held credentials require an Ethereum mainnet (chain 1) account owner");return`did:pkh:eip155:1:${y(i.address)}`}function we(e){return`v1/held/${A(e)}/`}function Ee(e,t){return`${we(e)}${t}`}function Ie(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 ge(e,t,i){return{issuerSet:e.issuerSet,acceptedIssuers:e.acceptedIssuers,didMethods:e.didMethods,now:t,owner:i}}async function De(e){return{type:"TinyCloudHeldStorageReceipt",version:1,ownerDid:e.ownerDid,recordId:e.recordId,recordDigest:await t(e),storedAt:e.storedAt}}async function Ae(i){const r=i.now??new Date,n=he(i.ownerDid);let s;try{s=S(i.sdJwt,ge(i,r,n))}catch(t){throw function(t){if(!(t instanceof I))return t;const i="nonce-account-mismatch"===t.code?"HOLDER_MISMATCH":"VERIFICATION_FAILED";return new e(i,t.message,{cause:t})}(t)}const o=i.sdJwt;if("string"!=typeof o)throw new e("VERIFICATION_FAILED","Held credential must be an SD-JWT string");if("string"!=typeof s.claims.email)throw new e("VERIFICATION_FAILED","Held credential must disclose an email claim");if(!fe(s.expiresAt,r))throw new e("VERIFICATION_FAILED","Held credential expires within the reuse margin");const a=await t(o),d=await t({credentialDigest:a,holderDid:n}),c={type:"TinyCloudHeldCredential",version:1,ownerDid:n,recordId:d,credentialDigest:a,credential:o,storedAt:r.toISOString()},l=await async function(t,i,r){const n=()=>new e("VERIFIED_NOT_SAVED","Held credential could not be confirmed in storage"),s=await t.batchPut([{key:i,value:r}]).catch(()=>{});if(!0!==s?.ok)throw n();const o=await t.get(i).catch(()=>{}),a=!0===o?.ok?o.data.data:void 0;if(!Ie(a)||a.recordId!==r.recordId||a.credentialDigest!==r.credentialDigest||a.credential!==r.credential||!D(a.ownerDid,r.ownerDid))throw n();return a}(i.kv,Ee(n,d),c);return{record:l,receipt:await De(l),verified:s}}async function ye(e,t,i,r,n){const s=await e.get(t);return Se(s.ok?s.data.data:void 0,t,i,r,n)}async function Se(e,i,r,n,s){if(!Ie(e))return{kind:"invalid"};if(!D(e.ownerDid,r))return{kind:"invalid"};const o=await t(e.credential),a=await t({credentialDigest:o,holderDid:r});if(e.credentialDigest!==o||e.recordId!==a||i!==Ee(r,a))return{kind:"invalid"};let d;try{d=S(e.credential,ge(n,s,r))}catch(e){if(!(e instanceof I)||"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 ve extends e{}async function Te(t,i){const r=[];let n;for(let s=0;s<50;s+=1){const s=await t.list(void 0===n?{prefix:i}:{prefix:i,cursor:n});if(!s.ok)return;if(r.push(...s.data.keys),!s.data.truncated)return[...new Set(r)];const o=s.data.nextCursor;if(void 0===o||""===o)throw new e("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 me(e){const t=e.now??new Date,i=he(e.ownerDid),r=await Te(e.kv,we(i));if(void 0===r)return;const n=e.email.replace(/[A-Z]+/g,e=>e.toLowerCase());let s;for(const o of r){const r=await ye(e.kv,o,i,e,t);if("verified"!==r.kind||r.email!==n)continue;const a=r.match.verified.expiresAt.getTime();fe(r.match.verified.expiresAt,t)&&(void 0===s||a>s.verified.expiresAt.getTime())&&(s=r.match)}return s}async function _e(t){const i=t.now??new Date,r=he(t.ownerDid),n=await Te(t.kv,we(r));if(void 0===n)throw new e("OFFLINE","Held credentials could not be listed");const s=[];for(const o of n){const n=await t.kv.get(o);if(!n.ok){if("error"in n&&"KV_NOT_FOUND"===n.error.code)continue;throw new e("OFFLINE","A held credential could not be read")}let a;try{a=await Se(n.data.data,o,r,t,i)}catch(e){if(e instanceof I&&"bad-config"===e.code)throw e;continue}"verified"===a.kind&&fe(a.match.verified.expiresAt,i)&&s.push(a.match)}return s.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 Re="tinycloud.email-held/v1";class Oe extends Error{constructor(e,t){super(t),this.retryable=!1,this.name="HeldSourceError",this.code=e}}async function be(t){return async function(t,i){const{kv:r,address:n,holder:s,sessionDid:o,getCode:a,pendingStore:d,fetch:c,signal:l,now:u,...p}=t,f=u??(()=>new Date),h=he(s.did);if(void 0!==o&&!D(o,h))throw new e("HOLDER_MISMATCH","Held acquisition holder must be the session account");const w=await async function(e,t,i,r,n){try{return await me({...t,kv:e,ownerDid:i,email:r,now:n()})}catch(e){if(!(e instanceof ve))throw e}try{return await async function(e){const t=e.now??new Date,i=he(e.ownerDid),r=await Te(e.kv,we(i));if(void 0===r)return[];const n=[],s=new Map;for(const o of r){const r=await ye(e.kv,o,i,e,t);if("invalid"===r.kind)continue;if("expired"===r.kind){n.push(o);continue}const a={key:o,recordId:r.match.record.recordId,expiresAt:r.match.verified.expiresAt.getTime()},d=s.get(r.email);if(void 0===d){s.set(r.email,a);continue}const c=a.expiresAt>d.expiresAt||a.expiresAt===d.expiresAt&&a.recordId>d.recordId;s.set(r.email,c?a:d),n.push(c?d.key:a.key)}const o=[];for(const t of n)(await e.kv.delete(t)).ok&&o.push(t);return o}({...t,kv:e,ownerDid:i,now:n()}),await me({...t,kv:e,ownerDid:i,email:r,now:n()})}catch(e){if(e instanceof ve)throw new Oe("held-store-listing-limit","Saved held credentials list is too long to read; clear old ones");throw e}}(r,p,h,n,f);if(void 0!==w)return{credential:w.record.credential,holderDid:h,expiresAt:w.verified.expiresAt};const E=await i({address:n,holder:s,profile:Re,getCode:a,pendingStore:Ne(d,h,f),fetch:c,signal:l,now:f});if("issued"!==E.status)throw new e("PROOF_REJECTED","Held acquisition did not issue a credential");const I=E.result.envelope.credential;let g;try{g=await Ae({...p,kv:r,ownerDid:h,sdJwt:I,now:f()})}catch{throw new e("VERIFIED_NOT_SAVED","Verified held credential could not be stored")}return{credential:I,holderDid:h,expiresAt:g.verified.expiresAt}}(t,ee)}function Ne(e,t,i){if(void 0===e)return;const r=e=>void 0!==e&&e.profile===Re&&D(e.holderDid,t);return{async findLive(t,i){const n=await e.findLive(t,i);return r(n)?n: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 n=await e.get(t,i);return r(n)?n:void 0}}}export{j as EmailProofError,b as OpenCredentialsHttpTransport,ee as acquireEmailProof,be as acquireHeldCredential,z as completeEmailProof,pe as createAccountHolderSigner,J as createEd25519HolderSigner,X as createMemoryEmailProofPendingStore,me as findHeldCredential,T as interpretCredentialFlow,_e as listHeldEmailCredentials,Y as requestEmailProofCode,Ae 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 y,parsePkhDid as S,pkhPrincipalsEqual as T,registryKey as v,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"]),V=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}},P={id:"opencredentials.email/v1",version:1},k=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]){super("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)+k)}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 V(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,k):Math.min(E,g+k)).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 V(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:[P.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");return r}function ge(e,t){return t===$?g({type:"TinyCloudCredentialRequirement",version:1,profile:{id:t,version:1},credentialType:P,claims:{email:e},maxAgeSeconds:31536e3}):r({email:e,profile:{id:t,version:1},credentialType:P})}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")}const Se=["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}$/,ve=/^[A-Za-z0-9_-]{32}$/,_e=/^[A-Za-z0-9_-]{43}$/,Oe=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;function Re(e){try{return new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}).decode(e)}catch{throw ye()}}function be(e,t){const i=S(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=Re(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()!==Se.join())throw ye();for(const e of Se)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])||!T(n.holderDid,t)||!Te.test(o("jti"))||!ve.test(o("requestId"))||!ve.test(o("challengeNonce"))||!_e.test(o("requirementDigest"))||!_e.test(o("normalizedClaimsDigest"))||!Oe.test(o("issuedAt"))||!Oe.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=Re(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 Ne(e,t){return e.getTime()-t.getTime()>6e5}function Ce(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 Le(e){return`v1/held/${v(e)}/`}function qe(e,t){return`${Le(e)}${t}`}function Ue(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 xe(e,t,i){return{issuerSet:e.issuerSet,acceptedIssuers:e.acceptedIssuers,didMethods:e.didMethods,now:t,owner:i}}async function Fe(e){return{type:"TinyCloudHeldStorageReceipt",version:1,ownerDid:e.ownerDid,recordId:e.recordId,recordDigest:await i(e),storedAt:e.storedAt}}async function Ve(e){const r=e.now??new Date,s=Ce(e.ownerDid);let n;try{n=O(e.sdJwt,xe(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(!Ne(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=()=>new t("VERIFIED_NOT_SAVED","Held credential could not be confirmed in storage"),n=await e.batchPut([{key:i,value:r}]).catch(()=>{});if(!0!==n?.ok)throw s();const o=await e.get(i).catch(()=>{}),a=!0===o?.ok?o.data.data:void 0;if(!Ue(a)||a.recordId!==r.recordId||a.credentialDigest!==r.credentialDigest||a.credential!==r.credential||!T(a.ownerDid,r.ownerDid))throw s();return a}(e.kv,qe(s,d),c);return{record:l,receipt:await Fe(l),verified:n}}async function Pe(e,t,i,r,s){const n=await e.get(t);return ke(n.ok?n.data.data:void 0,t,i,r,s)}async function ke(e,t,r,s,n){if(!Ue(e))return{kind:"invalid"};if(!T(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!==qe(r,a))return{kind:"invalid"};let d;try{d=O(e.credential,xe(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 Be(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)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 He(e){const t=e.now??new Date,i=Ce(e.ownerDid),r=await Be(e.kv,Le(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 Pe(e.kv,o,i,e,t);if("verified"!==r.kind||r.email!==s)continue;const a=r.match.verified.expiresAt.getTime();Ne(r.match.verified.expiresAt,t)&&(void 0===n||a>n.verified.expiresAt.getTime())&&(n=r.match)}return n}async function Me(e){const i=e.now??new Date,r=Ce(e.ownerDid),s=await Be(e.kv,Le(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;throw new t("OFFLINE","A held credential could not be read")}let a;try{a=await ke(s.data.data,o,r,e,i)}catch(e){if(e instanceof A&&"bad-config"===e.code)throw e;continue}"verified"===a.kind&&Ne(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 Ke="tinycloud.email-held/v1",$e=3e5;class Qe extends Error{constructor(e,t){super(t),this.retryable=!1,this.name="HeldSourceError",this.code=e}}async function Je(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=Ce(n.did);if(void 0!==o&&!T(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 Me({...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()+$e))).filter(e=>e.email===o));try{return await a()}catch(e){if(!(e instanceof je))throw e}try{return await async function(e){const t=e.now??new Date,i=Ce(e.ownerDid),r=await Be(e.kv,Le(i));if(void 0===r)return[];const s=[],n=new Map;for(const o of r){const r=await Pe(e.kv,o,i,e,t);if("invalid"===r.kind)continue;if("expired"===r.kind){s.push(o);continue}const a={key:o,recordId:r.match.record.recordId,expiresAt:r.match.verified.expiresAt.getTime()},d=n.get(r.email);if(void 0===d){n.set(r.email,a);continue}const c=a.expiresAt>d.expiresAt||a.expiresAt===d.expiresAt&&a.recordId>d.recordId;n.set(r.email,c?a:d),s.push(c?d.key:a.key)}const o=[];for(const t of s)(await e.kv.delete(t)).ok&&o.push(t);return o}({...i,kv:e,ownerDid:r,now:n()}),await a()}catch(e){if(e instanceof je)throw new Qe("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))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(Ke)||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:Ke,getCode:d,pendingStore:ze(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(),v=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(v-S>$e)throw new t("VERIFICATION_FAILED","client clock is more than 5 minutes behind the issuer");let _;try{_=await Ve({...h,kv:r,ownerDid:g,sdJwt:y,now:new Date(Math.max(S,v))})}catch{throw new t("VERIFIED_NOT_SAVED","Verified held credential could not be stored")}return{credential:y,holderDid:g,expiresAt:_.verified.expiresAt}}(e,ce)}function ze(e,t,i){if(void 0===e)return;const r=e=>void 0!==e&&e.profile===Ke&&T(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,V as OpenCredentialsHttpTransport,ce as acquireEmailProof,Je as acquireHeldCredential,ae as completeEmailProof,be as createAccountHolderSigner,Z as createEd25519HolderSigner,re as createMemoryEmailProofPendingStore,He as findHeldCredential,L as interpretCredentialFlow,Me as listHeldEmailCredentials,oe as requestEmailProofCode,Ve as storeHeldCredential,De as verifyStoredEmailProof};