@tktchurch/auth 0.9.5 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.9.6] - 2026-07-18
6
+
7
+ ### Security
8
+
9
+ - `createPhoneOtpClient` no longer shares a single `MemoryTokenStorage` across
10
+ concurrent operations. Each `verifyPhoneOTP` and `fetchProfile` call now
11
+ builds a request-scoped `AuthClient` + storage pair, eliminating a race
12
+ where two concurrent callers on the same server surface could observe each
13
+ other's tokens (Q-052). Tests that inject `config.auth` continue to reuse
14
+ the stubbed client for call assertions.
15
+
5
16
  ## [0.9.5] - 2026-07-18
6
17
 
7
18
  ### Security
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var V=Object.defineProperty;var Ne=Object.getOwnPropertyDescriptor;var Fe=Object.getOwnPropertyNames;var Le=Object.prototype.hasOwnProperty;var Be=(e,t)=>{for(var n in t)V(e,n,{get:t[n],enumerable:!0})},Je=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Fe(t))!Le.call(e,r)&&r!==n&&V(e,r,{get:()=>t[r],enumerable:!(o=Ne(t,r))||o.enumerable});return e};var He=e=>Je(V({},"__esModule",{value:!0}),e);var kt={};Be(kt,{AuthError:()=>i,DEFAULT_AUTHORIZE_SCOPE:()=>N,DEFAULT_TOKEN_STORAGE_KEY:()=>Pe,MAX_STORED_TOKEN_BYTES:()=>B,MFARequiredAuthError:()=>S,PhoneOtpError:()=>k,assertValidAuthTokens:()=>q,createAuthClient:()=>J,createMemoryTokenStorage:()=>O,createPhoneOtpClient:()=>Me,deriveCodeChallenge:()=>Y,generateCodeVerifier:()=>K,generateNonce:()=>D,generatePkce:()=>j,generateState:()=>x,isAuthError:()=>P,isUnrecoverableAuthError:()=>ae,parseStoredAuthTokens:()=>Oe,randomUrlSafeString:()=>z,safeParseStoredJson:()=>Ie,sanitizePostAuthRedirect:()=>$e,serializeAuthTokens:()=>ze,timingSafeEqual:()=>M,validateStorageKey:()=>Ue});module.exports=He(kt);var i=class extends Error{code;status;details;constructor(t,n,o){super(n),this.name="AuthError",this.code=t,this.status=o?.status,this.details=o?.details}},S=class extends i{mfaMethods;constructor(t,n,o,r){super("mfa_required",t,{status:o,details:r}),this.name="MFARequiredAuthError",this.mfaMethods=n}};function Ve(e){switch(e){case"mfa_required":case"invalid_request":case"invalid_client":case"invalid_grant":case"unauthorized_client":case"unsupported_grant_type":case"invalid_scope":case"access_denied":case"unsupported_response_type":case"server_error":case"temporarily_unavailable":case"invalid_token":case"insufficient_scope":case"authentication_required":case"insufficient_user_authentication":return e;default:return"unknown_error"}}function Qe(e,t){if(!t)return new i("http_error",`Request failed with status ${e}`,{status:e});let n=Ve(t.error),o=t.error_description??t.reason??(t.error?`Auth error: ${t.error}`:`Request failed with status ${e}`);if(n==="mfa_required"){let r=Array.isArray(t.mfa_methods)?t.mfa_methods.filter(s=>typeof s=="string"):[];return new S(o,r,e,t)}return new i(n,o,{status:e,details:t})}async function ie(e){let t,n=await e.text();if(n)try{t=JSON.parse(n)}catch{t={reason:n}}return Qe(e.status,t)}function P(e){return e instanceof i}function ae(e){return P(e)?e.code==="invalid_client"||e.code==="invalid_grant"||e.code==="unauthorized_client"||e.code==="invalid_token":!1}function Q(e){if(!Array.isArray(e))return;let t=e.filter(n=>typeof n=="object"&&n!==null&&typeof n.type=="string");return t.length>0?t:void 0}async function f(e){let t=await e.getTokens();if(!t?.accessToken)throw new i("invalid_token","No access token is available. Authenticate first.");return t.accessToken}function m(e){return Object.fromEntries(Object.entries(e).filter(([,t])=>typeof t<"u"))}function b(e,t){let n=e.access_token,o=e.token_type,r=e.expires_in;if(typeof n!="string"||typeof o!="string"||typeof r!="number")throw new i("unknown_error","Unexpected token response payload.",{details:e});let s={accessToken:n,tokenType:o,expiresIn:r},a=typeof e.refresh_token=="string"?e.refresh_token:t;a&&(s.refreshToken=a),typeof e.scope=="string"&&(s.scope=e.scope),typeof e.id_token=="string"&&(s.idToken=e.id_token);let u=Q(e.authorization_details);return u&&(s.authorizationDetails=u),s}function We(e){return{id:String(e.id??""),deviceName:typeof e.device_name=="string"?e.device_name:void 0,deviceType:String(e.device_type??""),browser:typeof e.browser=="string"?e.browser:void 0,os:typeof e.os=="string"?e.os:void 0,ipAddress:String(e.ip_address??""),country:typeof e.country=="string"?e.country:void 0,city:typeof e.city=="string"?e.city:void 0,isActive:!!e.is_active,isCurrent:!!e.is_current,isTrusted:!!e.is_trusted,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0,createdAt:typeof e.created_at=="string"?e.created_at:void 0}}function W(e){return{id:String(e.id??""),deviceId:typeof e.device_id=="string"?e.device_id:void 0,deviceName:typeof e.device_name=="string"?e.device_name:void 0,deviceType:String(e.device_type??""),userAgent:typeof e.user_agent=="string"?e.user_agent:void 0,browser:typeof e.browser=="string"?e.browser:void 0,browserVersion:typeof e.browser_version=="string"?e.browser_version:void 0,os:typeof e.os=="string"?e.os:void 0,osVersion:typeof e.os_version=="string"?e.os_version:void 0,ipAddress:String(e.ip_address??""),country:typeof e.country=="string"?e.country:void 0,city:typeof e.city=="string"?e.city:void 0,isActive:!!e.is_active,isRevoked:!!e.is_revoked,isCurrent:!!e.is_current,isTrusted:!!e.is_trusted,requiresMfa:!!e.requires_mfa,accessTokenCount:typeof e.access_token_count=="number"?e.access_token_count:0,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0,expiresAt:typeof e.expires_at=="string"?e.expires_at:void 0,createdAt:typeof e.created_at=="string"?e.created_at:void 0,revokedAt:typeof e.revoked_at=="string"?e.revoked_at:void 0,revocationReason:typeof e.revocation_reason=="string"?e.revocation_reason:void 0}}function G(e){return{success:!!e.success,sessionsRevoked:typeof e.sessions_revoked=="number"?e.sessions_revoked:0,tokensRevoked:typeof e.tokens_revoked=="number"?e.tokens_revoked:0}}function Ge(e){let t=Array.isArray(e.items)?e.items:[],o=e.metadata&&typeof e.metadata=="object"?e.metadata:{};return{items:t.filter(r=>typeof r=="object"&&r!==null).map(We),metadata:{page:typeof o.page=="number"?o.page:1,per:typeof o.per=="number"?o.per:t.length,total:typeof o.total=="number"?o.total:t.length}}}function ue(e){return{async list(t){let n=await f(e),o=new URLSearchParams;typeof t?.page=="number"&&o.set("page",String(t.page)),typeof t?.perPage=="number"&&o.set("per_page",String(t.perPage)),t?.userId&&o.set("user_id",t.userId);let r=`/api/v1/sessions${o.size?`?${o.toString()}`:""}`,s=await e.http.request(r,{token:n});return Ge(s)},async current(){let t=await f(e),n=await e.http.request("/api/v1/sessions/current",{token:t});return W(n)},async get(t){let n=await f(e),o=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{token:n});return W(o)},async update(t,n){let o=await f(e),r=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{method:"PATCH",token:o,body:m({device_name:n.deviceName,is_trusted:n.isTrusted})});return W(r)},async revoke(t,n){let o=await f(e),r=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{method:"DELETE",token:o,body:m({reason:n?.reason})});return G(r)},async revokeAll(){let t=await f(e),n=await e.http.request("/api/v1/sessions/revoke-all",{method:"POST",token:t});return G(n)},async revokeAllDevices(){let t=await f(e),n=await e.http.request("/api/v1/sessions/revoke-all-devices",{method:"POST",token:t});return G(n)}}}function de(){let e=globalThis.crypto;if(!e?.getRandomValues)throw new i("invalid_request","Web Crypto API is unavailable in this runtime. PKCE requires globalThis.crypto.");return e}function ce(e){let t="";for(let o of e)t+=String.fromCharCode(o);if(typeof btoa!="function")throw new i("server_error","base64UrlEncode requires globalThis.btoa (Web/Deno runtime).");return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function z(e=32){if(!Number.isInteger(e)||e<=0)throw new i("invalid_request","randomUrlSafeString length must be a positive integer.");let t=new Uint8Array(e);return de().getRandomValues(t),ce(t)}function x(){return z(32)}function D(){return z(32)}function K(){return z(32)}async function Y(e){let t=de();if(!t.subtle?.digest)throw new i("invalid_request","SubtleCrypto.digest is unavailable; cannot derive an S256 code challenge.");let n=new TextEncoder().encode(e),o=await t.subtle.digest("SHA-256",n);return ce(new Uint8Array(o))}async function j(e="S256"){let t=K();if(e==="plain")return{codeVerifier:t,codeChallenge:t,codeChallengeMethod:"plain"};let n=await Y(t);return{codeVerifier:t,codeChallenge:n,codeChallengeMethod:"S256"}}function M(e,t){let n=new TextEncoder().encode(e),o=new TextEncoder().encode(t),r=Math.max(n.length,o.length),s=n.length^o.length;for(let a=0;a<r;a+=1)s|=(n[a]??0)^(o[a]??0);return s===0}function Ke(e){return{active:!!e.active,scope:typeof e.scope=="string"?e.scope:void 0,clientId:typeof e.client_id=="string"?e.client_id:void 0,username:typeof e.username=="string"?e.username:void 0,tokenType:typeof e.token_type=="string"?e.token_type:void 0,exp:typeof e.exp=="number"?e.exp:void 0,iat:typeof e.iat=="number"?e.iat:void 0,sub:typeof e.sub=="string"?e.sub:void 0,authorizationDetails:Q(e.authorization_details)}}function $(e){return{async password(t){let n=m({grant_type:"password",client_id:e.config.clientId,client_secret:e.config.clientSecret,username:t.username,email:t.email,password:t.password,scope:t.scope,mfa_code:t.mfaCode,mfa_backup_code:t.mfaBackupCode}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async refresh(t){let n=await e.getTokens(),o=t?.refreshToken??n?.refreshToken;if(!o)throw new i("invalid_request","No refresh token is available.");let r=m({grant_type:"refresh_token",client_id:e.config.clientId,client_secret:e.config.clientSecret,refresh_token:o,scope:t?.scope}),s=await e.http.request("/oauth/token",{method:"POST",body:r}),a=b(s,o);return await e.setTokens(a),a},async clientCredentials(t){let n=m({grant_type:"client_credentials",client_id:e.config.clientId,client_secret:e.config.clientSecret,scope:t?.scope}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async authorizationCode(t){let n=m({grant_type:"authorization_code",client_id:e.config.clientId,client_secret:e.config.clientSecret,code:t.code,redirect_uri:t.redirectUri,code_verifier:t.codeVerifier,scope:t.scope}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async revoke(t){let n=await e.getTokens(),o=t?.token??n?.accessToken;if(!o)throw new i("invalid_request","No token provided for revocation.");await e.http.request("/oauth/revoke",{method:"POST",body:m({client_id:e.config.clientId,client_secret:e.config.clientSecret,token:o,token_type_hint:t?.tokenTypeHint})}),n&&(o===n.accessToken||o===n.refreshToken)&&await e.clearTokens()},async introspect(t){let n=await e.http.request("/oauth/introspect",{method:"POST",body:m({client_id:e.config.clientId,client_secret:e.config.clientSecret,token:t.token})});return Ke(n)},async tokenExchange(t){let n=m({grant_type:"urn:ietf:params:oauth:grant-type:token-exchange",client_id:e.config.clientId,client_secret:e.config.clientSecret,subject_token:t.subjectToken,subject_token_type:t.subjectTokenType??"urn:ietf:params:oauth:token-type:access_token",requested_subject:t.requestedSubject,scope:t.scope,audience:t.audience}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r}}}function pe(e,t){let n=e.trim();if(!n)throw new i("invalid_request",`${t} is required.`);return n}async function h(e,t,n){let o=await f(e),r=n?.query,s=r&&Object.keys(r).length>0?`?${new URLSearchParams(Object.entries(r).filter(([,a])=>typeof a<"u").map(([a,u])=>[a,String(u)])).toString()}`:"";return e.http.request(`${t}${s}`,{method:n?.method,body:n?.body,token:o})}async function v(e,t,n){await h(e,t,n)}function A(e,t){return encodeURIComponent(pe(e,t))}function Ye(e){let t=Array.isArray(e.mfa_methods)?e.mfa_methods.filter(n=>typeof n=="string"):void 0;return{redirectUri:String(e.redirect_uri??""),code:typeof e.code=="string"?e.code:void 0,state:typeof e.state=="string"?e.state:void 0,error:typeof e.error=="string"?e.error:void 0,errorDescription:typeof e.error_description=="string"?e.error_description:void 0,mfaMethods:t,accessToken:typeof e.access_token=="string"?e.access_token:void 0,tokenType:typeof e.token_type=="string"?e.token_type:void 0,expiresIn:typeof e.expires_in=="number"?e.expires_in:void 0,scope:typeof e.scope=="string"?e.scope:void 0,idToken:typeof e.id_token=="string"?e.id_token:void 0}}function Xe(e){let t=Array.isArray(e.redirect_uris)?e.redirect_uris.filter(n=>typeof n=="string"&&n.length>0):[];return{clientId:String(e.client_id??""),name:String(e.name??""),description:typeof e.description=="string"?e.description:void 0,isFirstParty:!!e.is_first_party,redirectUris:t}}function Ze(e){let t=Array.isArray(e.mfa_methods)?e.mfa_methods.filter(o=>typeof o=="string"):void 0,n=Array.isArray(e.uncovered_scopes)?e.uncovered_scopes.filter(o=>typeof o=="string"):void 0;return{consentSatisfied:!!e.consent_satisfied,requiresMfa:!!e.requires_mfa,mfaMethods:t,uncoveredScopes:n,error:typeof e.error=="string"?e.error:void 0,errorDescription:typeof e.error_description=="string"?e.error_description:void 0}}function fe(e,t){let n=new URL(e),o=new URL(t);if(n.origin!==o.origin||n.pathname!=="/oauth/authorize/consent")throw new i("invalid_request","callbackUrl must target /oauth/authorize/consent on the configured auth server.");return n}function le(e){async function t(o,r){let s=fe(o,e.config.baseUrl),a=await e.http.request(`${s.pathname}${s.search}`,{method:"POST",body:{username:r.username,password:r.password,approved:r.approved??!0,requested_scopes:r.requestedScopes,mfa_code:r.mfaCode,mfa_backup_code:r.mfaBackupCode}}),u=Ye(a);if(u.error==="mfa_required")throw new S(u.errorDescription??"Multi-factor authentication is required",u.mfaMethods??[],void 0,a);return u}async function n(o,r){let s=fe(o,e.config.baseUrl),a=await e.http.request(`${s.pathname}/evaluate${s.search}`,{method:"POST",body:{username:r.username,password:r.password,requested_scopes:r.requestedScopes,mfa_code:r.mfaCode,mfa_backup_code:r.mfaBackupCode}}),u=Ze(a);if(u.error==="mfa_required"||u.requiresMfa)throw new S(u.errorDescription??"Multi-factor authentication is required",u.mfaMethods??[],void 0,a);return u}return{consent:t,evaluateConsent:n,consentWithCredentials(o){return t(o.callbackUrl,{username:o.username,password:o.password,approved:o.approved,requestedScopes:o.requestedScopes,mfaCode:o.mfaCode,mfaBackupCode:o.mfaBackupCode})},evaluateConsentWithCredentials(o){return n(o.callbackUrl,{username:o.username,password:o.password,requestedScopes:o.requestedScopes,mfaCode:o.mfaCode,mfaBackupCode:o.mfaBackupCode})}}}function me(e){return{async publicClient(t){let n=await e.http.request(`/oauth/clients/${encodeURIComponent(t)}/public`);return Xe(n)},async discoverAuthorizationServer(){let t=await e.http.request("/.well-known/oauth-authorization-server");return{issuer:String(t.issuer??""),authorizationEndpoint:String(t.authorization_endpoint??""),tokenEndpoint:String(t.token_endpoint??""),jwksUri:typeof t.jwks_uri=="string"?t.jwks_uri:void 0,revocationEndpoint:typeof t.revocation_endpoint=="string"?t.revocation_endpoint:void 0,introspectionEndpoint:typeof t.introspection_endpoint=="string"?t.introspection_endpoint:void 0,registrationEndpoint:typeof t.registration_endpoint=="string"?t.registration_endpoint:void 0,scopesSupported:Array.isArray(t.scopes_supported)?t.scopes_supported.filter(n=>typeof n=="string"):void 0,responseTypesSupported:Array.isArray(t.response_types_supported)?t.response_types_supported.filter(n=>typeof n=="string"):[],grantTypesSupported:Array.isArray(t.grant_types_supported)?t.grant_types_supported.filter(n=>typeof n=="string"):void 0,codeChallengeMethodsSupported:Array.isArray(t.code_challenge_methods_supported)?t.code_challenge_methods_supported.filter(n=>typeof n=="string"):void 0,pushedAuthorizationRequestEndpoint:typeof t.pushed_authorization_request_endpoint=="string"?t.pushed_authorization_request_endpoint:void 0,requirePushedAuthorizationRequests:typeof t.require_pushed_authorization_requests=="boolean"?t.require_pushed_authorization_requests:void 0,authorizationDetailsTypesSupported:Array.isArray(t.authorization_details_types_supported)?t.authorization_details_types_supported.filter(n=>typeof n=="string"):void 0,raw:t}}}}var N="openid profile email offline_access",he=new Set(["response_type","client_id","redirect_uri","scope","state","nonce","code_challenge","code_challenge_method","prompt","login_hint","authorization_details","request_uri"]);function et(e){if(typeof e=="string"){let t=e.indexOf("?"),n=t>=0?e.slice(t+1):e;return new URLSearchParams(n)}return e instanceof URLSearchParams?e:"raw"in e&&typeof e.raw=="object"?new URLSearchParams(e.raw):new URLSearchParams(e)}function ge(e){let t=et(e),n={};return t.forEach((o,r)=>{n[r]=o}),{code:t.get("code")??void 0,state:t.get("state")??void 0,error:t.get("error")??void 0,errorDescription:t.get("error_description")??void 0,errorUri:t.get("error_uri")??void 0,raw:n}}function ye(e){let t=$(e);return{...le(e),async createRequest(o){if(!o.redirectUri?.trim())throw new i("invalid_request","redirectUri is required to build an authorization request.");let r=o.scope??N,s=o.state??x(),a=o.nonce??D(),u=await j(o.codeChallengeMethod??"S256"),y=o.authorizationEndpoint??`${e.config.baseUrl}/oauth/authorize`,R=new URL(y),l=R.searchParams;l.set("response_type",o.responseType??"code"),l.set("client_id",e.config.clientId),l.set("redirect_uri",o.redirectUri),l.set("scope",r),l.set("state",s),l.set("nonce",a),l.set("code_challenge",u.codeChallenge),l.set("code_challenge_method",u.codeChallengeMethod),o.authorizationDetails&&o.authorizationDetails.length>0&&l.set("authorization_details",JSON.stringify(o.authorizationDetails)),o.prompt&&l.set("prompt",o.prompt),o.loginHint&&l.set("login_hint",o.loginHint);for(let[w,U]of Object.entries(o.extraParams??{})){if(he.has(w))throw new i("invalid_request",`extraParams may not override the reserved authorization parameter "${w}".`);l.set(w,U)}return{url:R.toString(),state:s,nonce:a,codeVerifier:u.codeVerifier,codeChallenge:u.codeChallenge,redirectUri:o.redirectUri,scope:r}},async pushAuthorizationRequest(o){if(!o.redirectUri?.trim())throw new i("invalid_request","redirectUri is required to push an authorization request.");let r=o.scope??N,s=o.state??x(),a=o.nonce??D(),u=await j(o.codeChallengeMethod??"S256"),y={response_type:o.responseType??"code",client_id:e.config.clientId,redirect_uri:o.redirectUri,scope:r,state:s,nonce:a,code_challenge:u.codeChallenge,code_challenge_method:u.codeChallengeMethod};e.config.clientSecret&&(y.client_secret=e.config.clientSecret),o.authorizationDetails&&o.authorizationDetails.length>0&&(y.authorization_details=JSON.stringify(o.authorizationDetails));for(let[c,d]of Object.entries(o.extraParams??{})){if(he.has(c))throw new i("invalid_request",`extraParams may not override the reserved authorization parameter "${c}".`);y[c]=d}let R=await e.http.request("/oauth/par",{method:"POST",body:y}),l=R.request_uri,w=R.expires_in;if(typeof l!="string"||typeof w!="number")throw new i("unknown_error","Unexpected pushed authorization response payload.",{details:R});let U=o.authorizationEndpoint??`${e.config.baseUrl}/oauth/authorize`,p=new URL(U);return p.searchParams.set("client_id",e.config.clientId),p.searchParams.set("request_uri",l),{requestUri:l,expiresIn:w,request:{url:p.toString(),state:s,nonce:a,codeVerifier:u.codeVerifier,codeChallenge:u.codeChallenge,redirectUri:o.redirectUri,scope:r,requestUri:l}}},parseCallback:ge,async probeAuthorize(o){let r=await e.http.requestRaw(o,{headers:{Accept:"application/json"},redirect:"manual"}),s=r.headers.get("location");if(s&&r.status>=300&&r.status<400)return{kind:"redirect",location:s,status:r.status};let a=await r.text(),u=a?JSON.parse(a):{};if(!r.ok)throw new i("server_error",typeof u.error_description=="string"?u.error_description:"Authorization probe failed",{status:r.status,details:u});let y=typeof u.authorization_url=="string"?u.authorization_url:void 0;return{kind:"json",status:r.status,authorizationUrl:y,payload:u}},async handleCallback(o){let s=typeof o.callback=="object"&&!(o.callback instanceof URLSearchParams)&&"raw"in o.callback?o.callback:ge(o.callback);if(s.error)throw new i("access_denied",s.errorDescription??`Authorization failed: ${s.error}`,{details:s.raw});if(!s.state||!M(s.state,o.expectedState))throw new i("invalid_request","State mismatch on authorization callback (possible CSRF).");if(!s.code)throw new i("invalid_request","Authorization callback is missing the `code` parameter.");return t.authorizationCode({code:s.code,redirectUri:o.redirectUri,codeVerifier:o.codeVerifier,scope:o.scope})}}}function E(e){let t=e.step_id,n=e.step_type,o=e.name,r=e.order,s=e.is_required,a=e.timeout;if(typeof t!="string"||typeof n!="string"||typeof o!="string"||typeof r!="number"||typeof s!="boolean"||typeof a!="number")throw new i("unknown_error","Unexpected flow step payload.",{details:e});return{stepId:t,stepType:n,name:o,description:typeof e.description=="string"?e.description:void 0,order:r,isRequired:s,timeout:a,inputSchema:e.input_schema&&typeof e.input_schema=="object"?e.input_schema:void 0}}function X(e){let t=e.current_step,n=e.remaining_steps;if(!t||typeof t!="object")throw new i("unknown_error","Missing current_step in flow response.",{details:e});let o=e.continuation_token;if(typeof o!="string"||!o)throw new i("unknown_error","Missing continuation_token in flow response.",{details:e});return{sessionId:String(e.session_id??""),flowId:String(e.flow_id??""),flowName:String(e.flow_name??""),currentStep:E(t),remainingSteps:Array.isArray(n)?n.filter(r=>typeof r=="object"&&r!==null).map(E):[],expiresAt:String(e.expires_at??""),continuationToken:o}}function tt(e){return{sessionId:String(e.session_id??""),status:String(e.status??""),purpose:String(e.purpose??""),currentStep:e.current_step&&typeof e.current_step=="object"?E(e.current_step):void 0,completedSteps:Array.isArray(e.completed_steps)?e.completed_steps.filter(t=>typeof t=="string"):[],remainingSteps:Array.isArray(e.remaining_steps)?e.remaining_steps.filter(t=>typeof t=="object"&&t!==null).map(E):[],failedAttempts:typeof e.failed_attempts=="number"?e.failed_attempts:0,expiresAt:String(e.expires_at??""),lastActivityAt:String(e.last_activity_at??"")}}async function Z(e,t){let n=t.status;if(n==="error"||typeof t.error=="string"&&n!=="in_progress"&&n!=="complete")throw new i("invalid_request",typeof t.error=="string"?t.error:"Flow step failed.",{details:t});if(n==="in_progress"){let o=t.next_step,r=t.remaining_steps;if(!o||typeof o!="object")throw new i("unknown_error","Missing next_step in flow step response.",{details:t});let s=t.debug&&typeof t.debug=="object"&&!Array.isArray(t.debug)?t.debug:void 0;return{status:"in_progress",sessionId:String(t.session_id??""),nextStep:E(o),completedSteps:Array.isArray(t.completed_steps)?t.completed_steps.filter(u=>typeof u=="string"):[],remainingSteps:Array.isArray(r)?r.filter(u=>typeof u=="object"&&u!==null).map(E):[],debug:s}}if(n==="complete"){let o=b(t);return await e.setTokens(o),{status:"complete",accessToken:o.accessToken,refreshToken:o.refreshToken,tokenType:o.tokenType,expiresIn:o.expiresIn,scope:o.scope,amr:Array.isArray(t.amr)?t.amr.filter(s=>typeof s=="string"):[],acr:typeof t.acr=="string"?t.acr:""}}throw new i("unknown_error","Unknown flow step status.",{details:t})}function _e(e){return{async initAuthentication(t){let n=await e.http.request("/oauth/authenticate/init",{method:"POST",body:m({client_id:t?.clientId??e.config.clientId,username:t?.username,flow_type:t?.flowType})});return X(n)},async executeStep(t){let n=await e.http.request("/oauth/authenticate/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return Z(e,n)},async initRegistration(t){let n=await e.http.request("/oauth/register/init",{method:"POST",body:m({client_id:t?.clientId??e.config.clientId,invite_code:t?.inviteCode,flow_type:t?.flowType})});return X(n)},async executeRegistrationStep(t){let n=await e.http.request("/oauth/register/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return Z(e,n)},async getStatus(t,n){let o=new URLSearchParams({continuation_token:n}),r=await e.http.request(`/oauth/flow/status/${encodeURIComponent(t)}?${o}`);return tt(r)},async initRecovery(t){let n=await e.http.request("/oauth/recovery/init",{method:"POST",body:m({client_id:t?.clientId??e.config.clientId,recovery_type:t?.recoveryType,redirect_uri:t?.redirectUri})});return X(n)},async executeRecoveryStep(t){let n=await e.http.request("/oauth/recovery/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return Z(e,n)}}}function F(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}function nt(e){return{issuer:String(e.issuer??""),authorizationEndpoint:String(e.authorization_endpoint??""),tokenEndpoint:String(e.token_endpoint??""),userinfoEndpoint:typeof e.userinfo_endpoint=="string"?e.userinfo_endpoint:void 0,jwksUri:String(e.jwks_uri??""),revocationEndpoint:typeof e.revocation_endpoint=="string"?e.revocation_endpoint:void 0,introspectionEndpoint:typeof e.introspection_endpoint=="string"?e.introspection_endpoint:void 0,responseTypesSupported:F(e.response_types_supported),grantTypesSupported:F(e.grant_types_supported),scopesSupported:F(e.scopes_supported),codeChallengeMethodsSupported:F(e.code_challenge_methods_supported),raw:e}}function ot(e){return{sub:String(e.sub??""),name:typeof e.name=="string"?e.name:void 0,givenName:typeof e.given_name=="string"?e.given_name:void 0,familyName:typeof e.family_name=="string"?e.family_name:void 0,middleName:typeof e.middle_name=="string"?e.middle_name:void 0,nickname:typeof e.nickname=="string"?e.nickname:void 0,preferredUsername:typeof e.preferred_username=="string"?e.preferred_username:void 0,profile:typeof e.profile=="string"?e.profile:void 0,picture:typeof e.picture=="string"?e.picture:void 0,website:typeof e.website=="string"?e.website:void 0,gender:typeof e.gender=="string"?e.gender:void 0,birthdate:typeof e.birthdate=="string"?e.birthdate:void 0,zoneinfo:typeof e.zoneinfo=="string"?e.zoneinfo:void 0,locale:typeof e.locale=="string"?e.locale:void 0,updatedAt:typeof e.updated_at=="number"?e.updated_at:void 0,email:typeof e.email=="string"?e.email:void 0,emailVerified:typeof e.email_verified=="boolean"?e.email_verified:void 0,phoneNumber:typeof e.phone_number=="string"?e.phone_number:void 0,phoneNumberVerified:typeof e.phone_number_verified=="boolean"?e.phone_number_verified:void 0}}function ke(e){return{async userInfo(){let t=await f(e),n=await e.http.request("/oauth/userinfo",{token:t});return ot(n)},async discover(){let t=await e.http.request("/.well-known/openid-configuration");return nt(t)},async jwks(){let t=await e.http.request("/oauth/jwks");return{keys:Array.isArray(t.keys)?t.keys.filter(o=>typeof o=="object"&&o!==null):[]}}}}function L(e){return{...e,id:typeof e.id=="string"?e.id:"",organizationId:typeof e.organization_id=="string"?e.organization_id:void 0,email:typeof e.email=="string"?e.email:void 0,username:typeof e.username=="string"?e.username:void 0,firstName:typeof e.first_name=="string"?e.first_name:void 0,lastName:typeof e.last_name=="string"?e.last_name:void 0,isActive:typeof e.is_active=="boolean"?e.is_active:void 0,isVerified:typeof e.is_verified=="boolean"?e.is_verified:void 0,mfaEnabled:typeof e.mfa_enabled=="boolean"?e.mfa_enabled:void 0}}function ee(e){return{id:String(e.id??""),name:typeof e.name=="string"?e.name:void 0,email:typeof e.email=="string"?e.email:void 0,phoneNumber:typeof e.phone_number=="string"?e.phone_number:void 0,relationship:typeof e.relationship=="string"?e.relationship:void 0,isVerified:typeof e.is_verified=="boolean"?e.is_verified:void 0}}function rt(e){return{id:String(e.id??""),provider:String(e.provider??""),providerUserId:typeof e.provider_user_id=="string"?e.provider_user_id:void 0,email:typeof e.email=="string"?e.email:void 0,isPrimary:typeof e.is_primary=="boolean"?e.is_primary:void 0}}function be(e){return st(e)}function st(e){return{async me(){let t=await f(e),n=await e.http.request("/api/v1/users/me",{token:t});return L(n)},async updateMe(t){let n=await h(e,"/api/v1/users/me",{method:"PATCH",body:t});return L(n)},async changePassword(t){await v(e,"/api/v1/users/me/password",{method:"POST",body:{current_password:t.currentPassword,new_password:t.newPassword}})},async deleteAvatar(){let t=await h(e,"/api/v1/users/me/avatar",{method:"DELETE"});return L(t)},async uploadAvatar(t,n="avatar.jpg"){let o=await f(e),r=new FormData,s=t instanceof Blob?t:new Blob([new Uint8Array(t)]);r.append("avatar",s,n);let a=await e.http.request("/api/v1/users/me/avatar",{method:"POST",token:o,body:r});return L(a)},async verifyPhone(t){return h(e,"/api/v1/users/me/phone/verify",{method:"POST",body:t})},async verifyRecoveryEmail(t){return h(e,"/api/v1/users/me/recovery-email/verify",{method:"POST",body:t})},async securityOverview(){return h(e,"/api/v1/users/me/security-overview")},recoveryContacts:{async list(){let t=await h(e,"/api/v1/users/me/recovery-contacts");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(ee):[]},async create(t){let n=await h(e,"/api/v1/users/me/recovery-contacts",{method:"POST",body:t});return ee(n)},async update(t,n){let o=await h(e,`/api/v1/users/me/recovery-contacts/${A(t,"contactId")}`,{method:"PATCH",body:n});return ee(o)},async delete(t){await v(e,`/api/v1/users/me/recovery-contacts/${A(t,"contactId")}`,{method:"DELETE"})}},identities:{async list(){let t=await h(e,"/api/v1/users/me/identities");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(rt):[]},async unlink(t){await v(e,`/api/v1/users/me/identities/${A(t,"identityId")}`,{method:"DELETE"})},async setPrimary(t){return h(e,`/api/v1/users/me/identities/${A(t,"identityId")}/primary`,{method:"PATCH"})}},async deleteMe(t){await v(e,"/api/v1/users/me",{method:"DELETE",body:{password:t.password}})}}}function C(e){return e&&typeof e=="object"?e:{}}function Re(e){return{async registerBegin(t){let n=await f(e),o=await e.http.request("/api/v1/users/me/webauthn/register/begin",{method:"POST",token:n,body:t});return C(o)},async registerFinish(t){let n=await f(e),o=await e.http.request("/api/v1/users/me/webauthn/register/finish",{method:"POST",token:n,body:t});return C(o)},async authenticateBegin(t){let n=await e.http.request("/api/v1/users/me/webauthn/authenticate/begin",{method:"POST",body:t});return C(n)},async authenticateFinish(t){let n=await e.http.request("/api/v1/users/me/webauthn/authenticate/finish",{method:"POST",body:t}),o=C(n);if(typeof o.access_token=="string"){let r=b(o);await e.setTokens(r)}return o},async credentials(){let t=await f(e),n=await e.http.request("/api/v1/users/me/webauthn/credentials",{token:t});return C(n)},async removeCredential(t,n){let o=await f(e);await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}`,{method:"DELETE",token:o,body:n?.password?{password:n.password}:void 0})},async renameCredential(t,n){let o=await f(e),r=await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}/rename`,{method:"PATCH",token:o,body:n});return C(r)},async setPrimaryCredential(t){let n=await f(e),o=await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}/primary`,{method:"POST",token:n});return C(o)}}}function it(e){return{isActive:!!(e.is_active??e.isActive),message:typeof e.message=="string"?e.message:void 0,scheduledStart:typeof e.scheduled_start=="string"?e.scheduled_start:void 0,scheduledEnd:typeof e.scheduled_end=="string"?e.scheduled_end:void 0,...e}}function we(e){return{async status(){let t=await e.http.request("/api/v1/maintenance/status");return it(t)}}}var at=128,te=254;function T(e,t){if(typeof e!="string")return;let n=e.trim();if(!(!n||n.length>t))return n}function Se(e){return{async request(t){let n=m({email:T(t.email,te),identifier:T(t.identifier,te),recovery_email:T(t.recoveryEmail,te),phone_number:T(t.phoneNumber,32),member_id:T(t.memberId,64),security_question:T(t.securityQuestion,256),security_answer:T(t.securityAnswer,256),redirect_uri:T(t.redirectUri,2048)}),o=await e.http.request("/oauth/password/reset/request",{method:"POST",body:n});return{ok:!!o.ok,message:String(o.message??"")}},async validate(t){let n=t.trim();if(!n)throw new i("invalid_request","token is required.");let o=await e.http.request(`/oauth/password/reset/validate?token=${encodeURIComponent(n)}`);return{ok:!!o.ok,valid:!!o.valid,expiresAt:typeof o.expires_at=="string"?o.expires_at:void 0}},async complete(t){if(!t.token.trim())throw new i("invalid_request","token is required.");if(!t.password||t.password.length>at)throw new i("invalid_request","password is required and must be <= 128 characters.");let n=await e.http.request("/oauth/password/reset/complete",{method:"POST",body:{token:t.token.trim(),password:t.password,password_confirm:t.passwordConfirm}});return{ok:!!n.ok,message:String(n.message??"")}}}}function ut(e){return{id:String(e.id??""),deviceName:String(e.device_name??""),isVerified:!!e.is_verified,isPrimary:!!e.is_primary,createdAt:typeof e.created_at=="string"?e.created_at:void 0,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0}}function ve(e){return{async setup(t){let n=t.deviceName?.trim();if(!n||n.length>128)throw new i("invalid_request","deviceName is required.");let o=await h(e,"/api/v1/users/me/mfa/setup",{method:"POST",body:{device_name:n}});return{deviceId:String(o.device_id??""),secret:String(o.secret??""),qrCodeUri:String(o.qr_code_uri??""),backupCodes:Array.isArray(o.backup_codes)?o.backup_codes.filter(r=>typeof r=="string"):[],algorithm:String(o.algorithm??""),digits:typeof o.digits=="number"?o.digits:6,period:typeof o.period=="number"?o.period:30}},async verify(t){return h(e,"/api/v1/users/me/mfa/verify",{method:"POST",body:{device_id:t.deviceId,totp_code:t.totpCode}})},async devices(){let t=await h(e,"/api/v1/users/me/mfa/devices");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(ut):[]},async removeDevice(t){await v(e,`/api/v1/users/me/mfa/devices/${A(t,"deviceId")}`,{method:"DELETE"})},async regenerateBackupCodes(){let t=await h(e,"/api/v1/users/me/mfa/backup-codes/regenerate",{method:"POST"});return{backupCodes:Array.isArray(t.backup_codes)?t.backup_codes.filter(n=>typeof n=="string"):[]}},async disable(t){await v(e,"/api/v1/users/me/mfa/disable",{method:"POST",body:m({password:t?.password})})}}}var Te="https://prod-auth.tktchurch.com",dt=new Set(["localhost","127.0.0.1","[::1]"]);function ct(e){return dt.has(e.toLowerCase())}function ne(e,t={}){let n=(e??Te).trim();if(!n)return ne(Te,t);let r=(/^https?:\/\//i.test(n)?n:`https://${n}`).replace(/\/+$/,""),s;try{s=new URL(r)}catch{throw new i("invalid_request","baseUrl must be a valid absolute URL.")}if(s.protocol==="http:"&&!t.allowInsecureTransport&&!ct(s.hostname))throw new i("invalid_request","baseUrl must use HTTPS. Set allowInsecureTransport=true only for trusted local development.");return r}function pt(e,t){if(!e&&t<=0)return{cleanup:()=>{}};let n=new AbortController,o,r=()=>{n.abort(e?.reason)};return e&&(e.aborted?n.abort(e.reason):e.addEventListener("abort",r,{once:!0})),t>0&&(o=setTimeout(()=>{n.abort(new Error(`Request timed out after ${t}ms`))},t)),{signal:n.signal,cleanup:()=>{o&&clearTimeout(o),e&&e.removeEventListener("abort",r)}}}function ft(e,t){return/^https?:\/\//i.test(t)?t:`${e}${t.startsWith("/")?t:`/${t}`}`}function lt(e,t,n){let o=new Headers(e);return t&&new Headers(t).forEach((s,a)=>{o.set(a,s)}),n&&!o.has("Authorization")&&o.set("Authorization",`Bearer ${n}`),o}function Ae(e){return{async request(t,n){let o=await this.requestRaw(t,n);if(!o.ok)throw await ie(o);if(o.status===204)return;let r=await o.text();if(r)return JSON.parse(r)},async requestRaw(t,n){let o=ft(e.baseUrl,t),r=lt(e.defaultHeaders,n?.headers,n?.token),{signal:s,cleanup:a}=pt(n?.signal,e.timeoutMs),u={method:n?.method??"GET",headers:r,signal:s,redirect:n?.redirect};typeof n?.body<"u"&&(n.body instanceof FormData?u.body=n.body:(r.has("Content-Type")||r.set("Content-Type","application/json"),u.body=JSON.stringify(n.body)));try{return await e.fetch(o,u)}catch(y){throw s?.aborted??!1?new i("timeout",`Request timed out: ${o}`,{details:y}):new i("network_error",`Network request failed: ${o}`,{details:y})}finally{a()}}}}var Pe="@tktchurch/auth/tokens",B=32768,Ee=new Set(["accessToken","tokenType","expiresIn","refreshToken","scope","idToken","authorizationDetails"]),qe=new Set(["__proto__","constructor","prototype"]),mt=/^[\w@./:-]{1,128}$/;function re(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function Ce(e){return typeof e=="string"&&e.length>0}function oe(e){return typeof e=="string"&&e.length>0?e:void 0}function q(e){if(!re(e))throw new i("invalid_request","Token storage rejected a non-object token payload.");for(let s of Object.keys(e))if(!Ee.has(s))throw new i("invalid_request",`Token storage rejected unknown field "${s}".`);if(!Ce(e.accessToken))throw new i("invalid_request","Token storage requires a non-empty accessToken.");if(!Ce(e.tokenType))throw new i("invalid_request","Token storage requires a non-empty tokenType.");if(typeof e.expiresIn!="number"||!Number.isFinite(e.expiresIn)||e.expiresIn<0)throw new i("invalid_request","Token storage requires a non-negative numeric expiresIn.");let t={accessToken:e.accessToken,tokenType:e.tokenType,expiresIn:e.expiresIn},n=oe(e.refreshToken);n&&(t.refreshToken=n);let o=oe(e.scope);o&&(t.scope=o);let r=oe(e.idToken);if(r&&(t.idToken=r),typeof e.authorizationDetails<"u"){if(!Array.isArray(e.authorizationDetails)||!e.authorizationDetails.every(s=>re(s)&&typeof s.type=="string"))throw new i("invalid_request","Token storage rejected malformed authorizationDetails.");t.authorizationDetails=e.authorizationDetails}return t}function Oe(e){if(!re(e))return null;for(let t of Object.keys(e))if(qe.has(t)||!Ee.has(t))return null;try{return q(e)}catch{return null}}function Ie(e){return JSON.parse(e,(t,n)=>{if(qe.has(t))throw new SyntaxError("Forbidden JSON key in stored token payload.");return n})}function Ue(e){let t=e.trim();if(!t)throw new i("invalid_request","Token storage key must be a non-empty string.");if(!mt.test(t))throw new i("invalid_request","Token storage key contains unsupported characters or exceeds 128 characters.");return t}function ze(e){let t=q(e),n=JSON.stringify(t);if(n.length>B)throw new i("invalid_request",`Serialized token payload exceeds ${B} bytes.`);return n}var se=class{state=null;get(){return this.state}set(t){if(!t){this.clear();return}this.state=q(t)}clear(){this.state=null}};function O(){return new se}function ht(){return typeof window<"u"&&typeof window.document<"u"}function gt(e){if(e)return e;if(typeof globalThis.fetch=="function")return globalThis.fetch.bind(globalThis);throw new i("invalid_request","No fetch implementation available. Provide config.fetch.")}function xe(e){if(!e.clientId?.trim())throw new i("invalid_request","clientId is required.");if(ht()&&e.clientSecret&&!e.allowClientSecretInBrowser)throw new i("invalid_request","clientSecret in browser runtime is blocked by default. Set allowClientSecretInBrowser=true to override.");return{clientId:e.clientId,clientSecret:e.clientSecret,baseUrl:ne(e.baseUrl,{allowInsecureTransport:e.allowInsecureTransport??!1}),fetch:gt(e.fetch),storage:e.storage??O(),timeoutMs:e.timeoutMs??15e3,defaultHeaders:e.defaultHeaders??{},autoRefresh:e.autoRefresh??!0,allowClientSecretInBrowser:e.allowClientSecretInBrowser??!1,allowInsecureTransport:e.allowInsecureTransport??!1}}function J(e){let t=xe(e),n=Ae({baseUrl:t.baseUrl,fetch:t.fetch,timeoutMs:t.timeoutMs,defaultHeaders:t.defaultHeaders}),o=async()=>await t.storage.get(),r=async u=>{await t.storage.set(u)},s=async()=>{await t.storage.clear()},a={config:t,http:n,getTokens:o,setTokens:r,clearTokens:s};return{token:$(a),flow:_e(a),oidc:ke(a),authorize:ye(a),user:be(a),sessions:ue(a),webauthn:Re(a),passwordReset:Se(a),mfa:ve(a),maintenance:we(a),oauth:me(a),tokens:{get:o,set:r,clear:s}}}var k=class extends Error{name="PhoneOtpError"};function I(e,t){return e instanceof k?e:P(e)?new k(e.message||t):e instanceof Error&&e.message?new k(e.message):new k(t)}function De(e){if(!P(e)||typeof e.status!="number")return!1;let t=e.status;return t>=400&&t<500&&t!==429}function je(e){if(e.status!=="in_progress"||!e.debug)return;let t=e.debug.verification_code;return typeof t=="string"?t:void 0}function yt(e){return{...e,id:typeof e.id=="string"?e.id:"",first_name:typeof e.first_name=="string"?e.first_name:typeof e.firstName=="string"?e.firstName:void 0,last_name:typeof e.last_name=="string"?e.last_name:typeof e.lastName=="string"?e.lastName:void 0,email:typeof e.email=="string"?e.email:void 0,phone_number:typeof e.phone_number=="string"?e.phone_number:typeof e.phoneNumber=="string"?e.phoneNumber:void 0,phone_country_code:typeof e.phone_country_code=="string"?e.phone_country_code:typeof e.phoneCountryCode=="string"?e.phoneCountryCode:void 0,phone_verified:typeof e.phone_verified=="boolean"?e.phone_verified:typeof e.phoneVerified=="boolean"?e.phoneVerified:void 0,profile_picture_url:typeof e.profile_picture_url=="string"?e.profile_picture_url:typeof e.profilePictureUrl=="string"?e.profilePictureUrl:void 0,picture:typeof e.picture=="string"?e.picture:void 0,birthdate:typeof e.birthdate=="string"?e.birthdate:void 0}}function Me(e){let t=O(),n=e.auth??J({baseUrl:e.baseUrl,clientId:e.clientId,allowInsecureTransport:e.allowInsecureTransport,timeoutMs:e.timeoutMs??2e4,storage:t,autoRefresh:!1}),o=e.guestProfile??{firstName:"Guest",lastName:"User"},r=o.emailDomain??"registrations.tktchurch.local",s=o.emailLocalPrefix??"reg";async function a(p,c){let d=await n.flow.initAuthentication({flowType:"phone_only",username:c}),g=await n.flow.executeStep({sessionId:d.sessionId,stepId:d.currentStep.stepId,continuationToken:d.continuationToken,credential:p});if(g.status!=="in_progress")throw new k("Unexpected sign-in response.");return{oauthSessionId:d.sessionId,verifyStepId:g.nextStep.stepId,mode:"authentication",continuationToken:d.continuationToken,debugCode:je(g)}}async function u(p){let c=await n.flow.initRegistration({flowType:"phone_registration"}),d=await n.flow.executeRegistrationStep({sessionId:c.sessionId,stepId:c.currentStep.stepId,continuationToken:c.continuationToken,credential:p});if(d.status!=="in_progress")throw new k("Unexpected verification response.");return{oauthSessionId:c.sessionId,verifyStepId:d.nextStep.stepId,mode:"registration",continuationToken:c.continuationToken,debugCode:je(d)}}async function y(p,c,d){let g={phone_country_code:p,phone_number:c};try{return await u(g)}catch(_){if(!De(_))throw I(_,"Could not send the code. Please try again.");try{return await a(g,d)}catch{throw I(_,"Could not send the code. Please try again.")}}}async function R(p,c,d){let g={phone_country_code:p,phone_number:c};try{return await a(g,d)}catch(_){if(!De(_))throw I(_,"Could not start sign-in.");try{return await u(g)}catch{throw I(_,"Could not start sign-in.")}}}async function l(p,c,d,g,_){return p==="registration"?await n.flow.executeRegistrationStep({sessionId:c,stepId:d,continuationToken:g,credential:_}):await n.flow.executeStep({sessionId:c,stepId:d,continuationToken:g,credential:_})}async function w(p,c){try{let d=await l(p.mode,p.oauthSessionId,p.verifyStepId,p.continuationToken,{code:c}),g=0;for(;d.status==="in_progress"&&g<6;){g++;let _=d.nextStep.stepType,H={};_==="profile_info"?H={first_name:o.firstName,last_name:o.lastName,email:`${s}+${p.oauthSessionId.slice(0,8).toLowerCase()}@${r}`}:_==="terms_acceptance"&&(H={accepted:"true"}),d=await l(p.mode,p.oauthSessionId,d.nextStep.stepId,p.continuationToken,H)}if(d.status!=="complete")throw new k("Sign-in did not complete. Please try again.");return{accessToken:d.accessToken,refreshToken:d.refreshToken,expiresIn:d.expiresIn}}catch(d){throw d instanceof k?d:I(d,"That code didn't match. Try again.")}}async function U(p){try{await t.set({accessToken:p,tokenType:"Bearer",expiresIn:3600});let c=await n.user.me();return yt(c)}catch(c){throw I(c,c instanceof i?`Profile fetch failed (${c.status??"error"})`:"Profile fetch failed")}}return{startPhoneOTP:y,startPhoneOTPForSignIn:R,verifyPhoneOTP:w,fetchProfile:U}}var _t=/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;function $e(e,t="/"){if(!e)return t;let n=e;try{n=decodeURIComponent(e)}catch{return t}return n.startsWith("/")&&!n.startsWith("//")&&!n.startsWith("/\\")&&!_t.test(n)&&!/^\/+[\\/]/.test(n)?n:t}0&&(module.exports={AuthError,DEFAULT_AUTHORIZE_SCOPE,DEFAULT_TOKEN_STORAGE_KEY,MAX_STORED_TOKEN_BYTES,MFARequiredAuthError,PhoneOtpError,assertValidAuthTokens,createAuthClient,createMemoryTokenStorage,createPhoneOtpClient,deriveCodeChallenge,generateCodeVerifier,generateNonce,generatePkce,generateState,isAuthError,isUnrecoverableAuthError,parseStoredAuthTokens,randomUrlSafeString,safeParseStoredJson,sanitizePostAuthRedirect,serializeAuthTokens,timingSafeEqual,validateStorageKey});
1
+ "use strict";var Q=Object.defineProperty;var Fe=Object.getOwnPropertyDescriptor;var Le=Object.getOwnPropertyNames;var Be=Object.prototype.hasOwnProperty;var Je=(e,t)=>{for(var n in t)Q(e,n,{get:t[n],enumerable:!0})},He=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of Le(t))!Be.call(e,r)&&r!==n&&Q(e,r,{get:()=>t[r],enumerable:!(o=Fe(t,r))||o.enumerable});return e};var Ve=e=>He(Q({},"__esModule",{value:!0}),e);var bt={};Je(bt,{AuthError:()=>i,DEFAULT_AUTHORIZE_SCOPE:()=>L,DEFAULT_TOKEN_STORAGE_KEY:()=>Ee,MAX_STORED_TOKEN_BYTES:()=>H,MFARequiredAuthError:()=>S,PhoneOtpError:()=>k,assertValidAuthTokens:()=>O,createAuthClient:()=>$,createMemoryTokenStorage:()=>P,createPhoneOtpClient:()=>$e,deriveCodeChallenge:()=>X,generateCodeVerifier:()=>Y,generateNonce:()=>j,generatePkce:()=>M,generateState:()=>D,isAuthError:()=>E,isUnrecoverableAuthError:()=>ue,parseStoredAuthTokens:()=>Ie,randomUrlSafeString:()=>x,safeParseStoredJson:()=>Ue,sanitizePostAuthRedirect:()=>Ne,serializeAuthTokens:()=>xe,timingSafeEqual:()=>N,validateStorageKey:()=>ze});module.exports=Ve(bt);var i=class extends Error{code;status;details;constructor(t,n,o){super(n),this.name="AuthError",this.code=t,this.status=o?.status,this.details=o?.details}},S=class extends i{mfaMethods;constructor(t,n,o,r){super("mfa_required",t,{status:o,details:r}),this.name="MFARequiredAuthError",this.mfaMethods=n}};function Qe(e){switch(e){case"mfa_required":case"invalid_request":case"invalid_client":case"invalid_grant":case"unauthorized_client":case"unsupported_grant_type":case"invalid_scope":case"access_denied":case"unsupported_response_type":case"server_error":case"temporarily_unavailable":case"invalid_token":case"insufficient_scope":case"authentication_required":case"insufficient_user_authentication":return e;default:return"unknown_error"}}function We(e,t){if(!t)return new i("http_error",`Request failed with status ${e}`,{status:e});let n=Qe(t.error),o=t.error_description??t.reason??(t.error?`Auth error: ${t.error}`:`Request failed with status ${e}`);if(n==="mfa_required"){let r=Array.isArray(t.mfa_methods)?t.mfa_methods.filter(s=>typeof s=="string"):[];return new S(o,r,e,t)}return new i(n,o,{status:e,details:t})}async function ae(e){let t,n=await e.text();if(n)try{t=JSON.parse(n)}catch{t={reason:n}}return We(e.status,t)}function E(e){return e instanceof i}function ue(e){return E(e)?e.code==="invalid_client"||e.code==="invalid_grant"||e.code==="unauthorized_client"||e.code==="invalid_token":!1}function W(e){if(!Array.isArray(e))return;let t=e.filter(n=>typeof n=="object"&&n!==null&&typeof n.type=="string");return t.length>0?t:void 0}async function f(e){let t=await e.getTokens();if(!t?.accessToken)throw new i("invalid_token","No access token is available. Authenticate first.");return t.accessToken}function h(e){return Object.fromEntries(Object.entries(e).filter(([,t])=>typeof t<"u"))}function b(e,t){let n=e.access_token,o=e.token_type,r=e.expires_in;if(typeof n!="string"||typeof o!="string"||typeof r!="number")throw new i("unknown_error","Unexpected token response payload.",{details:e});let s={accessToken:n,tokenType:o,expiresIn:r},a=typeof e.refresh_token=="string"?e.refresh_token:t;a&&(s.refreshToken=a),typeof e.scope=="string"&&(s.scope=e.scope),typeof e.id_token=="string"&&(s.idToken=e.id_token);let u=W(e.authorization_details);return u&&(s.authorizationDetails=u),s}function Ge(e){return{id:String(e.id??""),deviceName:typeof e.device_name=="string"?e.device_name:void 0,deviceType:String(e.device_type??""),browser:typeof e.browser=="string"?e.browser:void 0,os:typeof e.os=="string"?e.os:void 0,ipAddress:String(e.ip_address??""),country:typeof e.country=="string"?e.country:void 0,city:typeof e.city=="string"?e.city:void 0,isActive:!!e.is_active,isCurrent:!!e.is_current,isTrusted:!!e.is_trusted,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0,createdAt:typeof e.created_at=="string"?e.created_at:void 0}}function G(e){return{id:String(e.id??""),deviceId:typeof e.device_id=="string"?e.device_id:void 0,deviceName:typeof e.device_name=="string"?e.device_name:void 0,deviceType:String(e.device_type??""),userAgent:typeof e.user_agent=="string"?e.user_agent:void 0,browser:typeof e.browser=="string"?e.browser:void 0,browserVersion:typeof e.browser_version=="string"?e.browser_version:void 0,os:typeof e.os=="string"?e.os:void 0,osVersion:typeof e.os_version=="string"?e.os_version:void 0,ipAddress:String(e.ip_address??""),country:typeof e.country=="string"?e.country:void 0,city:typeof e.city=="string"?e.city:void 0,isActive:!!e.is_active,isRevoked:!!e.is_revoked,isCurrent:!!e.is_current,isTrusted:!!e.is_trusted,requiresMfa:!!e.requires_mfa,accessTokenCount:typeof e.access_token_count=="number"?e.access_token_count:0,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0,expiresAt:typeof e.expires_at=="string"?e.expires_at:void 0,createdAt:typeof e.created_at=="string"?e.created_at:void 0,revokedAt:typeof e.revoked_at=="string"?e.revoked_at:void 0,revocationReason:typeof e.revocation_reason=="string"?e.revocation_reason:void 0}}function K(e){return{success:!!e.success,sessionsRevoked:typeof e.sessions_revoked=="number"?e.sessions_revoked:0,tokensRevoked:typeof e.tokens_revoked=="number"?e.tokens_revoked:0}}function Ke(e){let t=Array.isArray(e.items)?e.items:[],o=e.metadata&&typeof e.metadata=="object"?e.metadata:{};return{items:t.filter(r=>typeof r=="object"&&r!==null).map(Ge),metadata:{page:typeof o.page=="number"?o.page:1,per:typeof o.per=="number"?o.per:t.length,total:typeof o.total=="number"?o.total:t.length}}}function de(e){return{async list(t){let n=await f(e),o=new URLSearchParams;typeof t?.page=="number"&&o.set("page",String(t.page)),typeof t?.perPage=="number"&&o.set("per_page",String(t.perPage)),t?.userId&&o.set("user_id",t.userId);let r=`/api/v1/sessions${o.size?`?${o.toString()}`:""}`,s=await e.http.request(r,{token:n});return Ke(s)},async current(){let t=await f(e),n=await e.http.request("/api/v1/sessions/current",{token:t});return G(n)},async get(t){let n=await f(e),o=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{token:n});return G(o)},async update(t,n){let o=await f(e),r=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{method:"PATCH",token:o,body:h({device_name:n.deviceName,is_trusted:n.isTrusted})});return G(r)},async revoke(t,n){let o=await f(e),r=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{method:"DELETE",token:o,body:h({reason:n?.reason})});return K(r)},async revokeAll(){let t=await f(e),n=await e.http.request("/api/v1/sessions/revoke-all",{method:"POST",token:t});return K(n)},async revokeAllDevices(){let t=await f(e),n=await e.http.request("/api/v1/sessions/revoke-all-devices",{method:"POST",token:t});return K(n)}}}function ce(){let e=globalThis.crypto;if(!e?.getRandomValues)throw new i("invalid_request","Web Crypto API is unavailable in this runtime. PKCE requires globalThis.crypto.");return e}function pe(e){let t="";for(let o of e)t+=String.fromCharCode(o);if(typeof btoa!="function")throw new i("server_error","base64UrlEncode requires globalThis.btoa (Web/Deno runtime).");return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function x(e=32){if(!Number.isInteger(e)||e<=0)throw new i("invalid_request","randomUrlSafeString length must be a positive integer.");let t=new Uint8Array(e);return ce().getRandomValues(t),pe(t)}function D(){return x(32)}function j(){return x(32)}function Y(){return x(32)}async function X(e){let t=ce();if(!t.subtle?.digest)throw new i("invalid_request","SubtleCrypto.digest is unavailable; cannot derive an S256 code challenge.");let n=new TextEncoder().encode(e),o=await t.subtle.digest("SHA-256",n);return pe(new Uint8Array(o))}async function M(e="S256"){let t=Y();if(e==="plain")return{codeVerifier:t,codeChallenge:t,codeChallengeMethod:"plain"};let n=await X(t);return{codeVerifier:t,codeChallenge:n,codeChallengeMethod:"S256"}}function N(e,t){let n=new TextEncoder().encode(e),o=new TextEncoder().encode(t),r=Math.max(n.length,o.length),s=n.length^o.length;for(let a=0;a<r;a+=1)s|=(n[a]??0)^(o[a]??0);return s===0}function Ye(e){return{active:!!e.active,scope:typeof e.scope=="string"?e.scope:void 0,clientId:typeof e.client_id=="string"?e.client_id:void 0,username:typeof e.username=="string"?e.username:void 0,tokenType:typeof e.token_type=="string"?e.token_type:void 0,exp:typeof e.exp=="number"?e.exp:void 0,iat:typeof e.iat=="number"?e.iat:void 0,sub:typeof e.sub=="string"?e.sub:void 0,authorizationDetails:W(e.authorization_details)}}function F(e){return{async password(t){let n=h({grant_type:"password",client_id:e.config.clientId,client_secret:e.config.clientSecret,username:t.username,email:t.email,password:t.password,scope:t.scope,mfa_code:t.mfaCode,mfa_backup_code:t.mfaBackupCode}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async refresh(t){let n=await e.getTokens(),o=t?.refreshToken??n?.refreshToken;if(!o)throw new i("invalid_request","No refresh token is available.");let r=h({grant_type:"refresh_token",client_id:e.config.clientId,client_secret:e.config.clientSecret,refresh_token:o,scope:t?.scope}),s=await e.http.request("/oauth/token",{method:"POST",body:r}),a=b(s,o);return await e.setTokens(a),a},async clientCredentials(t){let n=h({grant_type:"client_credentials",client_id:e.config.clientId,client_secret:e.config.clientSecret,scope:t?.scope}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async authorizationCode(t){let n=h({grant_type:"authorization_code",client_id:e.config.clientId,client_secret:e.config.clientSecret,code:t.code,redirect_uri:t.redirectUri,code_verifier:t.codeVerifier,scope:t.scope}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async revoke(t){let n=await e.getTokens(),o=t?.token??n?.accessToken;if(!o)throw new i("invalid_request","No token provided for revocation.");await e.http.request("/oauth/revoke",{method:"POST",body:h({client_id:e.config.clientId,client_secret:e.config.clientSecret,token:o,token_type_hint:t?.tokenTypeHint})}),n&&(o===n.accessToken||o===n.refreshToken)&&await e.clearTokens()},async introspect(t){let n=await e.http.request("/oauth/introspect",{method:"POST",body:h({client_id:e.config.clientId,client_secret:e.config.clientSecret,token:t.token})});return Ye(n)},async tokenExchange(t){let n=h({grant_type:"urn:ietf:params:oauth:grant-type:token-exchange",client_id:e.config.clientId,client_secret:e.config.clientSecret,subject_token:t.subjectToken,subject_token_type:t.subjectTokenType??"urn:ietf:params:oauth:token-type:access_token",requested_subject:t.requestedSubject,scope:t.scope,audience:t.audience}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r}}}function fe(e,t){let n=e.trim();if(!n)throw new i("invalid_request",`${t} is required.`);return n}async function y(e,t,n){let o=await f(e),r=n?.query,s=r&&Object.keys(r).length>0?`?${new URLSearchParams(Object.entries(r).filter(([,a])=>typeof a<"u").map(([a,u])=>[a,String(u)])).toString()}`:"";return e.http.request(`${t}${s}`,{method:n?.method,body:n?.body,token:o})}async function v(e,t,n){await y(e,t,n)}function A(e,t){return encodeURIComponent(fe(e,t))}function Xe(e){let t=Array.isArray(e.mfa_methods)?e.mfa_methods.filter(n=>typeof n=="string"):void 0;return{redirectUri:String(e.redirect_uri??""),code:typeof e.code=="string"?e.code:void 0,state:typeof e.state=="string"?e.state:void 0,error:typeof e.error=="string"?e.error:void 0,errorDescription:typeof e.error_description=="string"?e.error_description:void 0,mfaMethods:t,accessToken:typeof e.access_token=="string"?e.access_token:void 0,tokenType:typeof e.token_type=="string"?e.token_type:void 0,expiresIn:typeof e.expires_in=="number"?e.expires_in:void 0,scope:typeof e.scope=="string"?e.scope:void 0,idToken:typeof e.id_token=="string"?e.id_token:void 0}}function Ze(e){let t=Array.isArray(e.redirect_uris)?e.redirect_uris.filter(n=>typeof n=="string"&&n.length>0):[];return{clientId:String(e.client_id??""),name:String(e.name??""),description:typeof e.description=="string"?e.description:void 0,isFirstParty:!!e.is_first_party,redirectUris:t}}function et(e){let t=Array.isArray(e.mfa_methods)?e.mfa_methods.filter(o=>typeof o=="string"):void 0,n=Array.isArray(e.uncovered_scopes)?e.uncovered_scopes.filter(o=>typeof o=="string"):void 0;return{consentSatisfied:!!e.consent_satisfied,requiresMfa:!!e.requires_mfa,mfaMethods:t,uncoveredScopes:n,error:typeof e.error=="string"?e.error:void 0,errorDescription:typeof e.error_description=="string"?e.error_description:void 0}}function le(e,t){let n=new URL(e),o=new URL(t);if(n.origin!==o.origin||n.pathname!=="/oauth/authorize/consent")throw new i("invalid_request","callbackUrl must target /oauth/authorize/consent on the configured auth server.");return n}function me(e){async function t(o,r){let s=le(o,e.config.baseUrl),a=await e.http.request(`${s.pathname}${s.search}`,{method:"POST",body:{username:r.username,password:r.password,approved:r.approved??!0,requested_scopes:r.requestedScopes,mfa_code:r.mfaCode,mfa_backup_code:r.mfaBackupCode}}),u=Xe(a);if(u.error==="mfa_required")throw new S(u.errorDescription??"Multi-factor authentication is required",u.mfaMethods??[],void 0,a);return u}async function n(o,r){let s=le(o,e.config.baseUrl),a=await e.http.request(`${s.pathname}/evaluate${s.search}`,{method:"POST",body:{username:r.username,password:r.password,requested_scopes:r.requestedScopes,mfa_code:r.mfaCode,mfa_backup_code:r.mfaBackupCode}}),u=et(a);if(u.error==="mfa_required"||u.requiresMfa)throw new S(u.errorDescription??"Multi-factor authentication is required",u.mfaMethods??[],void 0,a);return u}return{consent:t,evaluateConsent:n,consentWithCredentials(o){return t(o.callbackUrl,{username:o.username,password:o.password,approved:o.approved,requestedScopes:o.requestedScopes,mfaCode:o.mfaCode,mfaBackupCode:o.mfaBackupCode})},evaluateConsentWithCredentials(o){return n(o.callbackUrl,{username:o.username,password:o.password,requestedScopes:o.requestedScopes,mfaCode:o.mfaCode,mfaBackupCode:o.mfaBackupCode})}}}function he(e){return{async publicClient(t){let n=await e.http.request(`/oauth/clients/${encodeURIComponent(t)}/public`);return Ze(n)},async discoverAuthorizationServer(){let t=await e.http.request("/.well-known/oauth-authorization-server");return{issuer:String(t.issuer??""),authorizationEndpoint:String(t.authorization_endpoint??""),tokenEndpoint:String(t.token_endpoint??""),jwksUri:typeof t.jwks_uri=="string"?t.jwks_uri:void 0,revocationEndpoint:typeof t.revocation_endpoint=="string"?t.revocation_endpoint:void 0,introspectionEndpoint:typeof t.introspection_endpoint=="string"?t.introspection_endpoint:void 0,registrationEndpoint:typeof t.registration_endpoint=="string"?t.registration_endpoint:void 0,scopesSupported:Array.isArray(t.scopes_supported)?t.scopes_supported.filter(n=>typeof n=="string"):void 0,responseTypesSupported:Array.isArray(t.response_types_supported)?t.response_types_supported.filter(n=>typeof n=="string"):[],grantTypesSupported:Array.isArray(t.grant_types_supported)?t.grant_types_supported.filter(n=>typeof n=="string"):void 0,codeChallengeMethodsSupported:Array.isArray(t.code_challenge_methods_supported)?t.code_challenge_methods_supported.filter(n=>typeof n=="string"):void 0,pushedAuthorizationRequestEndpoint:typeof t.pushed_authorization_request_endpoint=="string"?t.pushed_authorization_request_endpoint:void 0,requirePushedAuthorizationRequests:typeof t.require_pushed_authorization_requests=="boolean"?t.require_pushed_authorization_requests:void 0,authorizationDetailsTypesSupported:Array.isArray(t.authorization_details_types_supported)?t.authorization_details_types_supported.filter(n=>typeof n=="string"):void 0,raw:t}}}}var L="openid profile email offline_access",ge=new Set(["response_type","client_id","redirect_uri","scope","state","nonce","code_challenge","code_challenge_method","prompt","login_hint","authorization_details","request_uri"]);function tt(e){if(typeof e=="string"){let t=e.indexOf("?"),n=t>=0?e.slice(t+1):e;return new URLSearchParams(n)}return e instanceof URLSearchParams?e:"raw"in e&&typeof e.raw=="object"?new URLSearchParams(e.raw):new URLSearchParams(e)}function ye(e){let t=tt(e),n={};return t.forEach((o,r)=>{n[r]=o}),{code:t.get("code")??void 0,state:t.get("state")??void 0,error:t.get("error")??void 0,errorDescription:t.get("error_description")??void 0,errorUri:t.get("error_uri")??void 0,raw:n}}function _e(e){let t=F(e);return{...me(e),async createRequest(o){if(!o.redirectUri?.trim())throw new i("invalid_request","redirectUri is required to build an authorization request.");let r=o.scope??L,s=o.state??D(),a=o.nonce??j(),u=await M(o.codeChallengeMethod??"S256"),_=o.authorizationEndpoint??`${e.config.baseUrl}/oauth/authorize`,R=new URL(_),l=R.searchParams;l.set("response_type",o.responseType??"code"),l.set("client_id",e.config.clientId),l.set("redirect_uri",o.redirectUri),l.set("scope",r),l.set("state",s),l.set("nonce",a),l.set("code_challenge",u.codeChallenge),l.set("code_challenge_method",u.codeChallengeMethod),o.authorizationDetails&&o.authorizationDetails.length>0&&l.set("authorization_details",JSON.stringify(o.authorizationDetails)),o.prompt&&l.set("prompt",o.prompt),o.loginHint&&l.set("login_hint",o.loginHint);for(let[w,U]of Object.entries(o.extraParams??{})){if(ge.has(w))throw new i("invalid_request",`extraParams may not override the reserved authorization parameter "${w}".`);l.set(w,U)}return{url:R.toString(),state:s,nonce:a,codeVerifier:u.codeVerifier,codeChallenge:u.codeChallenge,redirectUri:o.redirectUri,scope:r}},async pushAuthorizationRequest(o){if(!o.redirectUri?.trim())throw new i("invalid_request","redirectUri is required to push an authorization request.");let r=o.scope??L,s=o.state??D(),a=o.nonce??j(),u=await M(o.codeChallengeMethod??"S256"),_={response_type:o.responseType??"code",client_id:e.config.clientId,redirect_uri:o.redirectUri,scope:r,state:s,nonce:a,code_challenge:u.codeChallenge,code_challenge_method:u.codeChallengeMethod};e.config.clientSecret&&(_.client_secret=e.config.clientSecret),o.authorizationDetails&&o.authorizationDetails.length>0&&(_.authorization_details=JSON.stringify(o.authorizationDetails));for(let[m,c]of Object.entries(o.extraParams??{})){if(ge.has(m))throw new i("invalid_request",`extraParams may not override the reserved authorization parameter "${m}".`);_[m]=c}let R=await e.http.request("/oauth/par",{method:"POST",body:_}),l=R.request_uri,w=R.expires_in;if(typeof l!="string"||typeof w!="number")throw new i("unknown_error","Unexpected pushed authorization response payload.",{details:R});let U=o.authorizationEndpoint??`${e.config.baseUrl}/oauth/authorize`,p=new URL(U);return p.searchParams.set("client_id",e.config.clientId),p.searchParams.set("request_uri",l),{requestUri:l,expiresIn:w,request:{url:p.toString(),state:s,nonce:a,codeVerifier:u.codeVerifier,codeChallenge:u.codeChallenge,redirectUri:o.redirectUri,scope:r,requestUri:l}}},parseCallback:ye,async probeAuthorize(o){let r=await e.http.requestRaw(o,{headers:{Accept:"application/json"},redirect:"manual"}),s=r.headers.get("location");if(s&&r.status>=300&&r.status<400)return{kind:"redirect",location:s,status:r.status};let a=await r.text(),u=a?JSON.parse(a):{};if(!r.ok)throw new i("server_error",typeof u.error_description=="string"?u.error_description:"Authorization probe failed",{status:r.status,details:u});let _=typeof u.authorization_url=="string"?u.authorization_url:void 0;return{kind:"json",status:r.status,authorizationUrl:_,payload:u}},async handleCallback(o){let s=typeof o.callback=="object"&&!(o.callback instanceof URLSearchParams)&&"raw"in o.callback?o.callback:ye(o.callback);if(s.error)throw new i("access_denied",s.errorDescription??`Authorization failed: ${s.error}`,{details:s.raw});if(!s.state||!N(s.state,o.expectedState))throw new i("invalid_request","State mismatch on authorization callback (possible CSRF).");if(!s.code)throw new i("invalid_request","Authorization callback is missing the `code` parameter.");return t.authorizationCode({code:s.code,redirectUri:o.redirectUri,codeVerifier:o.codeVerifier,scope:o.scope})}}}function q(e){let t=e.step_id,n=e.step_type,o=e.name,r=e.order,s=e.is_required,a=e.timeout;if(typeof t!="string"||typeof n!="string"||typeof o!="string"||typeof r!="number"||typeof s!="boolean"||typeof a!="number")throw new i("unknown_error","Unexpected flow step payload.",{details:e});return{stepId:t,stepType:n,name:o,description:typeof e.description=="string"?e.description:void 0,order:r,isRequired:s,timeout:a,inputSchema:e.input_schema&&typeof e.input_schema=="object"?e.input_schema:void 0}}function Z(e){let t=e.current_step,n=e.remaining_steps;if(!t||typeof t!="object")throw new i("unknown_error","Missing current_step in flow response.",{details:e});let o=e.continuation_token;if(typeof o!="string"||!o)throw new i("unknown_error","Missing continuation_token in flow response.",{details:e});return{sessionId:String(e.session_id??""),flowId:String(e.flow_id??""),flowName:String(e.flow_name??""),currentStep:q(t),remainingSteps:Array.isArray(n)?n.filter(r=>typeof r=="object"&&r!==null).map(q):[],expiresAt:String(e.expires_at??""),continuationToken:o}}function nt(e){return{sessionId:String(e.session_id??""),status:String(e.status??""),purpose:String(e.purpose??""),currentStep:e.current_step&&typeof e.current_step=="object"?q(e.current_step):void 0,completedSteps:Array.isArray(e.completed_steps)?e.completed_steps.filter(t=>typeof t=="string"):[],remainingSteps:Array.isArray(e.remaining_steps)?e.remaining_steps.filter(t=>typeof t=="object"&&t!==null).map(q):[],failedAttempts:typeof e.failed_attempts=="number"?e.failed_attempts:0,expiresAt:String(e.expires_at??""),lastActivityAt:String(e.last_activity_at??"")}}async function ee(e,t){let n=t.status;if(n==="error"||typeof t.error=="string"&&n!=="in_progress"&&n!=="complete")throw new i("invalid_request",typeof t.error=="string"?t.error:"Flow step failed.",{details:t});if(n==="in_progress"){let o=t.next_step,r=t.remaining_steps;if(!o||typeof o!="object")throw new i("unknown_error","Missing next_step in flow step response.",{details:t});let s=t.debug&&typeof t.debug=="object"&&!Array.isArray(t.debug)?t.debug:void 0;return{status:"in_progress",sessionId:String(t.session_id??""),nextStep:q(o),completedSteps:Array.isArray(t.completed_steps)?t.completed_steps.filter(u=>typeof u=="string"):[],remainingSteps:Array.isArray(r)?r.filter(u=>typeof u=="object"&&u!==null).map(q):[],debug:s}}if(n==="complete"){let o=b(t);return await e.setTokens(o),{status:"complete",accessToken:o.accessToken,refreshToken:o.refreshToken,tokenType:o.tokenType,expiresIn:o.expiresIn,scope:o.scope,amr:Array.isArray(t.amr)?t.amr.filter(s=>typeof s=="string"):[],acr:typeof t.acr=="string"?t.acr:""}}throw new i("unknown_error","Unknown flow step status.",{details:t})}function ke(e){return{async initAuthentication(t){let n=await e.http.request("/oauth/authenticate/init",{method:"POST",body:h({client_id:t?.clientId??e.config.clientId,username:t?.username,flow_type:t?.flowType})});return Z(n)},async executeStep(t){let n=await e.http.request("/oauth/authenticate/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return ee(e,n)},async initRegistration(t){let n=await e.http.request("/oauth/register/init",{method:"POST",body:h({client_id:t?.clientId??e.config.clientId,invite_code:t?.inviteCode,flow_type:t?.flowType})});return Z(n)},async executeRegistrationStep(t){let n=await e.http.request("/oauth/register/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return ee(e,n)},async getStatus(t,n){let o=new URLSearchParams({continuation_token:n}),r=await e.http.request(`/oauth/flow/status/${encodeURIComponent(t)}?${o}`);return nt(r)},async initRecovery(t){let n=await e.http.request("/oauth/recovery/init",{method:"POST",body:h({client_id:t?.clientId??e.config.clientId,recovery_type:t?.recoveryType,redirect_uri:t?.redirectUri})});return Z(n)},async executeRecoveryStep(t){let n=await e.http.request("/oauth/recovery/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return ee(e,n)}}}function B(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}function ot(e){return{issuer:String(e.issuer??""),authorizationEndpoint:String(e.authorization_endpoint??""),tokenEndpoint:String(e.token_endpoint??""),userinfoEndpoint:typeof e.userinfo_endpoint=="string"?e.userinfo_endpoint:void 0,jwksUri:String(e.jwks_uri??""),revocationEndpoint:typeof e.revocation_endpoint=="string"?e.revocation_endpoint:void 0,introspectionEndpoint:typeof e.introspection_endpoint=="string"?e.introspection_endpoint:void 0,responseTypesSupported:B(e.response_types_supported),grantTypesSupported:B(e.grant_types_supported),scopesSupported:B(e.scopes_supported),codeChallengeMethodsSupported:B(e.code_challenge_methods_supported),raw:e}}function rt(e){return{sub:String(e.sub??""),name:typeof e.name=="string"?e.name:void 0,givenName:typeof e.given_name=="string"?e.given_name:void 0,familyName:typeof e.family_name=="string"?e.family_name:void 0,middleName:typeof e.middle_name=="string"?e.middle_name:void 0,nickname:typeof e.nickname=="string"?e.nickname:void 0,preferredUsername:typeof e.preferred_username=="string"?e.preferred_username:void 0,profile:typeof e.profile=="string"?e.profile:void 0,picture:typeof e.picture=="string"?e.picture:void 0,website:typeof e.website=="string"?e.website:void 0,gender:typeof e.gender=="string"?e.gender:void 0,birthdate:typeof e.birthdate=="string"?e.birthdate:void 0,zoneinfo:typeof e.zoneinfo=="string"?e.zoneinfo:void 0,locale:typeof e.locale=="string"?e.locale:void 0,updatedAt:typeof e.updated_at=="number"?e.updated_at:void 0,email:typeof e.email=="string"?e.email:void 0,emailVerified:typeof e.email_verified=="boolean"?e.email_verified:void 0,phoneNumber:typeof e.phone_number=="string"?e.phone_number:void 0,phoneNumberVerified:typeof e.phone_number_verified=="boolean"?e.phone_number_verified:void 0}}function be(e){return{async userInfo(){let t=await f(e),n=await e.http.request("/oauth/userinfo",{token:t});return rt(n)},async discover(){let t=await e.http.request("/.well-known/openid-configuration");return ot(t)},async jwks(){let t=await e.http.request("/oauth/jwks");return{keys:Array.isArray(t.keys)?t.keys.filter(o=>typeof o=="object"&&o!==null):[]}}}}function J(e){return{...e,id:typeof e.id=="string"?e.id:"",organizationId:typeof e.organization_id=="string"?e.organization_id:void 0,email:typeof e.email=="string"?e.email:void 0,username:typeof e.username=="string"?e.username:void 0,firstName:typeof e.first_name=="string"?e.first_name:void 0,lastName:typeof e.last_name=="string"?e.last_name:void 0,isActive:typeof e.is_active=="boolean"?e.is_active:void 0,isVerified:typeof e.is_verified=="boolean"?e.is_verified:void 0,mfaEnabled:typeof e.mfa_enabled=="boolean"?e.mfa_enabled:void 0}}function te(e){return{id:String(e.id??""),name:typeof e.name=="string"?e.name:void 0,email:typeof e.email=="string"?e.email:void 0,phoneNumber:typeof e.phone_number=="string"?e.phone_number:void 0,relationship:typeof e.relationship=="string"?e.relationship:void 0,isVerified:typeof e.is_verified=="boolean"?e.is_verified:void 0}}function st(e){return{id:String(e.id??""),provider:String(e.provider??""),providerUserId:typeof e.provider_user_id=="string"?e.provider_user_id:void 0,email:typeof e.email=="string"?e.email:void 0,isPrimary:typeof e.is_primary=="boolean"?e.is_primary:void 0}}function Re(e){return it(e)}function it(e){return{async me(){let t=await f(e),n=await e.http.request("/api/v1/users/me",{token:t});return J(n)},async updateMe(t){let n=await y(e,"/api/v1/users/me",{method:"PATCH",body:t});return J(n)},async changePassword(t){await v(e,"/api/v1/users/me/password",{method:"POST",body:{current_password:t.currentPassword,new_password:t.newPassword}})},async deleteAvatar(){let t=await y(e,"/api/v1/users/me/avatar",{method:"DELETE"});return J(t)},async uploadAvatar(t,n="avatar.jpg"){let o=await f(e),r=new FormData,s=t instanceof Blob?t:new Blob([new Uint8Array(t)]);r.append("avatar",s,n);let a=await e.http.request("/api/v1/users/me/avatar",{method:"POST",token:o,body:r});return J(a)},async verifyPhone(t){return y(e,"/api/v1/users/me/phone/verify",{method:"POST",body:t})},async verifyRecoveryEmail(t){return y(e,"/api/v1/users/me/recovery-email/verify",{method:"POST",body:t})},async securityOverview(){return y(e,"/api/v1/users/me/security-overview")},recoveryContacts:{async list(){let t=await y(e,"/api/v1/users/me/recovery-contacts");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(te):[]},async create(t){let n=await y(e,"/api/v1/users/me/recovery-contacts",{method:"POST",body:t});return te(n)},async update(t,n){let o=await y(e,`/api/v1/users/me/recovery-contacts/${A(t,"contactId")}`,{method:"PATCH",body:n});return te(o)},async delete(t){await v(e,`/api/v1/users/me/recovery-contacts/${A(t,"contactId")}`,{method:"DELETE"})}},identities:{async list(){let t=await y(e,"/api/v1/users/me/identities");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(st):[]},async unlink(t){await v(e,`/api/v1/users/me/identities/${A(t,"identityId")}`,{method:"DELETE"})},async setPrimary(t){return y(e,`/api/v1/users/me/identities/${A(t,"identityId")}/primary`,{method:"PATCH"})}},async deleteMe(t){await v(e,"/api/v1/users/me",{method:"DELETE",body:{password:t.password}})}}}function C(e){return e&&typeof e=="object"?e:{}}function we(e){return{async registerBegin(t){let n=await f(e),o=await e.http.request("/api/v1/users/me/webauthn/register/begin",{method:"POST",token:n,body:t});return C(o)},async registerFinish(t){let n=await f(e),o=await e.http.request("/api/v1/users/me/webauthn/register/finish",{method:"POST",token:n,body:t});return C(o)},async authenticateBegin(t){let n=await e.http.request("/api/v1/users/me/webauthn/authenticate/begin",{method:"POST",body:t});return C(n)},async authenticateFinish(t){let n=await e.http.request("/api/v1/users/me/webauthn/authenticate/finish",{method:"POST",body:t}),o=C(n);if(typeof o.access_token=="string"){let r=b(o);await e.setTokens(r)}return o},async credentials(){let t=await f(e),n=await e.http.request("/api/v1/users/me/webauthn/credentials",{token:t});return C(n)},async removeCredential(t,n){let o=await f(e);await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}`,{method:"DELETE",token:o,body:n?.password?{password:n.password}:void 0})},async renameCredential(t,n){let o=await f(e),r=await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}/rename`,{method:"PATCH",token:o,body:n});return C(r)},async setPrimaryCredential(t){let n=await f(e),o=await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}/primary`,{method:"POST",token:n});return C(o)}}}function at(e){return{isActive:!!(e.is_active??e.isActive),message:typeof e.message=="string"?e.message:void 0,scheduledStart:typeof e.scheduled_start=="string"?e.scheduled_start:void 0,scheduledEnd:typeof e.scheduled_end=="string"?e.scheduled_end:void 0,...e}}function Se(e){return{async status(){let t=await e.http.request("/api/v1/maintenance/status");return at(t)}}}var ut=128,ne=254;function T(e,t){if(typeof e!="string")return;let n=e.trim();if(!(!n||n.length>t))return n}function ve(e){return{async request(t){let n=h({email:T(t.email,ne),identifier:T(t.identifier,ne),recovery_email:T(t.recoveryEmail,ne),phone_number:T(t.phoneNumber,32),member_id:T(t.memberId,64),security_question:T(t.securityQuestion,256),security_answer:T(t.securityAnswer,256),redirect_uri:T(t.redirectUri,2048)}),o=await e.http.request("/oauth/password/reset/request",{method:"POST",body:n});return{ok:!!o.ok,message:String(o.message??"")}},async validate(t){let n=t.trim();if(!n)throw new i("invalid_request","token is required.");let o=await e.http.request(`/oauth/password/reset/validate?token=${encodeURIComponent(n)}`);return{ok:!!o.ok,valid:!!o.valid,expiresAt:typeof o.expires_at=="string"?o.expires_at:void 0}},async complete(t){if(!t.token.trim())throw new i("invalid_request","token is required.");if(!t.password||t.password.length>ut)throw new i("invalid_request","password is required and must be <= 128 characters.");let n=await e.http.request("/oauth/password/reset/complete",{method:"POST",body:{token:t.token.trim(),password:t.password,password_confirm:t.passwordConfirm}});return{ok:!!n.ok,message:String(n.message??"")}}}}function dt(e){return{id:String(e.id??""),deviceName:String(e.device_name??""),isVerified:!!e.is_verified,isPrimary:!!e.is_primary,createdAt:typeof e.created_at=="string"?e.created_at:void 0,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0}}function Te(e){return{async setup(t){let n=t.deviceName?.trim();if(!n||n.length>128)throw new i("invalid_request","deviceName is required.");let o=await y(e,"/api/v1/users/me/mfa/setup",{method:"POST",body:{device_name:n}});return{deviceId:String(o.device_id??""),secret:String(o.secret??""),qrCodeUri:String(o.qr_code_uri??""),backupCodes:Array.isArray(o.backup_codes)?o.backup_codes.filter(r=>typeof r=="string"):[],algorithm:String(o.algorithm??""),digits:typeof o.digits=="number"?o.digits:6,period:typeof o.period=="number"?o.period:30}},async verify(t){return y(e,"/api/v1/users/me/mfa/verify",{method:"POST",body:{device_id:t.deviceId,totp_code:t.totpCode}})},async devices(){let t=await y(e,"/api/v1/users/me/mfa/devices");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(dt):[]},async removeDevice(t){await v(e,`/api/v1/users/me/mfa/devices/${A(t,"deviceId")}`,{method:"DELETE"})},async regenerateBackupCodes(){let t=await y(e,"/api/v1/users/me/mfa/backup-codes/regenerate",{method:"POST"});return{backupCodes:Array.isArray(t.backup_codes)?t.backup_codes.filter(n=>typeof n=="string"):[]}},async disable(t){await v(e,"/api/v1/users/me/mfa/disable",{method:"POST",body:h({password:t?.password})})}}}var Ae="https://prod-auth.tktchurch.com",ct=new Set(["localhost","127.0.0.1","[::1]"]);function pt(e){return ct.has(e.toLowerCase())}function oe(e,t={}){let n=(e??Ae).trim();if(!n)return oe(Ae,t);let r=(/^https?:\/\//i.test(n)?n:`https://${n}`).replace(/\/+$/,""),s;try{s=new URL(r)}catch{throw new i("invalid_request","baseUrl must be a valid absolute URL.")}if(s.protocol==="http:"&&!t.allowInsecureTransport&&!pt(s.hostname))throw new i("invalid_request","baseUrl must use HTTPS. Set allowInsecureTransport=true only for trusted local development.");return r}function ft(e,t){if(!e&&t<=0)return{cleanup:()=>{}};let n=new AbortController,o,r=()=>{n.abort(e?.reason)};return e&&(e.aborted?n.abort(e.reason):e.addEventListener("abort",r,{once:!0})),t>0&&(o=setTimeout(()=>{n.abort(new Error(`Request timed out after ${t}ms`))},t)),{signal:n.signal,cleanup:()=>{o&&clearTimeout(o),e&&e.removeEventListener("abort",r)}}}function lt(e,t){return/^https?:\/\//i.test(t)?t:`${e}${t.startsWith("/")?t:`/${t}`}`}function mt(e,t,n){let o=new Headers(e);return t&&new Headers(t).forEach((s,a)=>{o.set(a,s)}),n&&!o.has("Authorization")&&o.set("Authorization",`Bearer ${n}`),o}function Ce(e){return{async request(t,n){let o=await this.requestRaw(t,n);if(!o.ok)throw await ae(o);if(o.status===204)return;let r=await o.text();if(r)return JSON.parse(r)},async requestRaw(t,n){let o=lt(e.baseUrl,t),r=mt(e.defaultHeaders,n?.headers,n?.token),{signal:s,cleanup:a}=ft(n?.signal,e.timeoutMs),u={method:n?.method??"GET",headers:r,signal:s,redirect:n?.redirect};typeof n?.body<"u"&&(n.body instanceof FormData?u.body=n.body:(r.has("Content-Type")||r.set("Content-Type","application/json"),u.body=JSON.stringify(n.body)));try{return await e.fetch(o,u)}catch(_){throw s?.aborted??!1?new i("timeout",`Request timed out: ${o}`,{details:_}):new i("network_error",`Network request failed: ${o}`,{details:_})}finally{a()}}}}var Ee="@tktchurch/auth/tokens",H=32768,qe=new Set(["accessToken","tokenType","expiresIn","refreshToken","scope","idToken","authorizationDetails"]),Oe=new Set(["__proto__","constructor","prototype"]),ht=/^[\w@./:-]{1,128}$/;function se(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function Pe(e){return typeof e=="string"&&e.length>0}function re(e){return typeof e=="string"&&e.length>0?e:void 0}function O(e){if(!se(e))throw new i("invalid_request","Token storage rejected a non-object token payload.");for(let s of Object.keys(e))if(!qe.has(s))throw new i("invalid_request",`Token storage rejected unknown field "${s}".`);if(!Pe(e.accessToken))throw new i("invalid_request","Token storage requires a non-empty accessToken.");if(!Pe(e.tokenType))throw new i("invalid_request","Token storage requires a non-empty tokenType.");if(typeof e.expiresIn!="number"||!Number.isFinite(e.expiresIn)||e.expiresIn<0)throw new i("invalid_request","Token storage requires a non-negative numeric expiresIn.");let t={accessToken:e.accessToken,tokenType:e.tokenType,expiresIn:e.expiresIn},n=re(e.refreshToken);n&&(t.refreshToken=n);let o=re(e.scope);o&&(t.scope=o);let r=re(e.idToken);if(r&&(t.idToken=r),typeof e.authorizationDetails<"u"){if(!Array.isArray(e.authorizationDetails)||!e.authorizationDetails.every(s=>se(s)&&typeof s.type=="string"))throw new i("invalid_request","Token storage rejected malformed authorizationDetails.");t.authorizationDetails=e.authorizationDetails}return t}function Ie(e){if(!se(e))return null;for(let t of Object.keys(e))if(Oe.has(t)||!qe.has(t))return null;try{return O(e)}catch{return null}}function Ue(e){return JSON.parse(e,(t,n)=>{if(Oe.has(t))throw new SyntaxError("Forbidden JSON key in stored token payload.");return n})}function ze(e){let t=e.trim();if(!t)throw new i("invalid_request","Token storage key must be a non-empty string.");if(!ht.test(t))throw new i("invalid_request","Token storage key contains unsupported characters or exceeds 128 characters.");return t}function xe(e){let t=O(e),n=JSON.stringify(t);if(n.length>H)throw new i("invalid_request",`Serialized token payload exceeds ${H} bytes.`);return n}var ie=class{state=null;get(){return this.state}set(t){if(!t){this.clear();return}this.state=O(t)}clear(){this.state=null}};function P(){return new ie}function gt(){return typeof window<"u"&&typeof window.document<"u"}function yt(e){if(e)return e;if(typeof globalThis.fetch=="function")return globalThis.fetch.bind(globalThis);throw new i("invalid_request","No fetch implementation available. Provide config.fetch.")}function De(e){if(!e.clientId?.trim())throw new i("invalid_request","clientId is required.");if(gt()&&e.clientSecret&&!e.allowClientSecretInBrowser)throw new i("invalid_request","clientSecret in browser runtime is blocked by default. Set allowClientSecretInBrowser=true to override.");return{clientId:e.clientId,clientSecret:e.clientSecret,baseUrl:oe(e.baseUrl,{allowInsecureTransport:e.allowInsecureTransport??!1}),fetch:yt(e.fetch),storage:e.storage??P(),timeoutMs:e.timeoutMs??15e3,defaultHeaders:e.defaultHeaders??{},autoRefresh:e.autoRefresh??!0,allowClientSecretInBrowser:e.allowClientSecretInBrowser??!1,allowInsecureTransport:e.allowInsecureTransport??!1}}function $(e){let t=De(e),n=Ce({baseUrl:t.baseUrl,fetch:t.fetch,timeoutMs:t.timeoutMs,defaultHeaders:t.defaultHeaders}),o=async()=>await t.storage.get(),r=async u=>{await t.storage.set(u)},s=async()=>{await t.storage.clear()},a={config:t,http:n,getTokens:o,setTokens:r,clearTokens:s};return{token:F(a),flow:ke(a),oidc:be(a),authorize:_e(a),user:Re(a),sessions:de(a),webauthn:we(a),passwordReset:ve(a),mfa:Te(a),maintenance:Se(a),oauth:he(a),tokens:{get:o,set:r,clear:s}}}var k=class extends Error{name="PhoneOtpError"};function I(e,t){return e instanceof k?e:E(e)?new k(e.message||t):e instanceof Error&&e.message?new k(e.message):new k(t)}function je(e){if(!E(e)||typeof e.status!="number")return!1;let t=e.status;return t>=400&&t<500&&t!==429}function Me(e){if(e.status!=="in_progress"||!e.debug)return;let t=e.debug.verification_code;return typeof t=="string"?t:void 0}function _t(e){return{...e,id:typeof e.id=="string"?e.id:"",first_name:typeof e.first_name=="string"?e.first_name:typeof e.firstName=="string"?e.firstName:void 0,last_name:typeof e.last_name=="string"?e.last_name:typeof e.lastName=="string"?e.lastName:void 0,email:typeof e.email=="string"?e.email:void 0,phone_number:typeof e.phone_number=="string"?e.phone_number:typeof e.phoneNumber=="string"?e.phoneNumber:void 0,phone_country_code:typeof e.phone_country_code=="string"?e.phone_country_code:typeof e.phoneCountryCode=="string"?e.phoneCountryCode:void 0,phone_verified:typeof e.phone_verified=="boolean"?e.phone_verified:typeof e.phoneVerified=="boolean"?e.phoneVerified:void 0,profile_picture_url:typeof e.profile_picture_url=="string"?e.profile_picture_url:typeof e.profilePictureUrl=="string"?e.profilePictureUrl:void 0,picture:typeof e.picture=="string"?e.picture:void 0,birthdate:typeof e.birthdate=="string"?e.birthdate:void 0}}function $e(e){let t=e.auth,n=e.guestProfile??{firstName:"Guest",lastName:"User"},o=n.emailDomain??"registrations.tktchurch.local",r=n.emailLocalPrefix??"reg";function s(){return t||$({baseUrl:e.baseUrl,clientId:e.clientId,allowInsecureTransport:e.allowInsecureTransport,timeoutMs:e.timeoutMs??2e4,storage:P(),autoRefresh:!1})}async function a(p,m){let c=s(),d=await c.flow.initAuthentication({flowType:"phone_only",username:m}),g=await c.flow.executeStep({sessionId:d.sessionId,stepId:d.currentStep.stepId,continuationToken:d.continuationToken,credential:p});if(g.status!=="in_progress")throw new k("Unexpected sign-in response.");return{oauthSessionId:d.sessionId,verifyStepId:g.nextStep.stepId,mode:"authentication",continuationToken:d.continuationToken,debugCode:Me(g)}}async function u(p){let m=s(),c=await m.flow.initRegistration({flowType:"phone_registration"}),d=await m.flow.executeRegistrationStep({sessionId:c.sessionId,stepId:c.currentStep.stepId,continuationToken:c.continuationToken,credential:p});if(d.status!=="in_progress")throw new k("Unexpected verification response.");return{oauthSessionId:c.sessionId,verifyStepId:d.nextStep.stepId,mode:"registration",continuationToken:c.continuationToken,debugCode:Me(d)}}async function _(p,m,c){let d={phone_country_code:p,phone_number:m};try{return await u(d)}catch(g){if(!je(g))throw I(g,"Could not send the code. Please try again.");try{return await a(d,c)}catch{throw I(g,"Could not send the code. Please try again.")}}}async function R(p,m,c){let d={phone_country_code:p,phone_number:m};try{return await a(d,c)}catch(g){if(!je(g))throw I(g,"Could not start sign-in.");try{return await u(d)}catch{throw I(g,"Could not start sign-in.")}}}async function l(p,m,c,d,g,z){return m==="registration"?await p.flow.executeRegistrationStep({sessionId:c,stepId:d,continuationToken:g,credential:z}):await p.flow.executeStep({sessionId:c,stepId:d,continuationToken:g,credential:z})}async function w(p,m){let c=s();try{let d=await l(c,p.mode,p.oauthSessionId,p.verifyStepId,p.continuationToken,{code:m}),g=0;for(;d.status==="in_progress"&&g<6;){g++;let z=d.nextStep.stepType,V={};z==="profile_info"?V={first_name:n.firstName,last_name:n.lastName,email:`${r}+${p.oauthSessionId.slice(0,8).toLowerCase()}@${o}`}:z==="terms_acceptance"&&(V={accepted:"true"}),d=await l(c,p.mode,p.oauthSessionId,d.nextStep.stepId,p.continuationToken,V)}if(d.status!=="complete")throw new k("Sign-in did not complete. Please try again.");return{accessToken:d.accessToken,refreshToken:d.refreshToken,expiresIn:d.expiresIn}}catch(d){throw d instanceof k?d:I(d,"That code didn't match. Try again.")}}async function U(p){let m;if(t)m=t;else{let c=P();await c.set({accessToken:p,tokenType:"Bearer",expiresIn:3600}),m=$({baseUrl:e.baseUrl,clientId:e.clientId,allowInsecureTransport:e.allowInsecureTransport,timeoutMs:e.timeoutMs??2e4,storage:c,autoRefresh:!1})}try{let c=await m.user.me();return _t(c)}catch(c){throw I(c,c instanceof i?`Profile fetch failed (${c.status??"error"})`:"Profile fetch failed")}}return{startPhoneOTP:_,startPhoneOTPForSignIn:R,verifyPhoneOTP:w,fetchProfile:U}}var kt=/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;function Ne(e,t="/"){if(!e)return t;let n=e;try{n=decodeURIComponent(e)}catch{return t}return n.startsWith("/")&&!n.startsWith("//")&&!n.startsWith("/\\")&&!kt.test(n)&&!/^\/+[\\/]/.test(n)?n:t}0&&(module.exports={AuthError,DEFAULT_AUTHORIZE_SCOPE,DEFAULT_TOKEN_STORAGE_KEY,MAX_STORED_TOKEN_BYTES,MFARequiredAuthError,PhoneOtpError,assertValidAuthTokens,createAuthClient,createMemoryTokenStorage,createPhoneOtpClient,deriveCodeChallenge,generateCodeVerifier,generateNonce,generatePkce,generateState,isAuthError,isUnrecoverableAuthError,parseStoredAuthTokens,randomUrlSafeString,safeParseStoredJson,sanitizePostAuthRedirect,serializeAuthTokens,timingSafeEqual,validateStorageKey});
package/dist/index.d.cts CHANGED
@@ -73,6 +73,14 @@ interface PhoneOtpClient {
73
73
  * “already registered” / “no account” substrings.
74
74
  * Q-040: fall back once only on client/validation HTTP failures (4xx except
75
75
  * 429), never on 5xx / rate limits / transport errors (no loops).
76
+ *
77
+ * Q-052: server surfaces (Deno microsites, Nitro handlers, edge functions)
78
+ * routinely invoke this client from many concurrent requests. A single shared
79
+ * {@link createMemoryTokenStorage} across those requests races — one flow's
80
+ * `verifyPhoneOTP` completion (or `fetchProfile` token set) can overwrite
81
+ * another mid-request. Each public operation therefore builds its own
82
+ * {@link AuthClient} + storage pair; tests can still inject `config.auth` to
83
+ * stub the transport and keep call assertions.
76
84
  */
77
85
  declare function createPhoneOtpClient(config: PhoneOtpClientConfig): PhoneOtpClient;
78
86
 
package/dist/index.d.ts CHANGED
@@ -73,6 +73,14 @@ interface PhoneOtpClient {
73
73
  * “already registered” / “no account” substrings.
74
74
  * Q-040: fall back once only on client/validation HTTP failures (4xx except
75
75
  * 429), never on 5xx / rate limits / transport errors (no loops).
76
+ *
77
+ * Q-052: server surfaces (Deno microsites, Nitro handlers, edge functions)
78
+ * routinely invoke this client from many concurrent requests. A single shared
79
+ * {@link createMemoryTokenStorage} across those requests races — one flow's
80
+ * `verifyPhoneOTP` completion (or `fetchProfile` token set) can overwrite
81
+ * another mid-request. Each public operation therefore builds its own
82
+ * {@link AuthClient} + storage pair; tests can still inject `config.auth` to
83
+ * stub the transport and keep call assertions.
76
84
  */
77
85
  declare function createPhoneOtpClient(config: PhoneOtpClientConfig): PhoneOtpClient;
78
86
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var i=class extends Error{code;status;details;constructor(t,n,o){super(n),this.name="AuthError",this.code=t,this.status=o?.status,this.details=o?.details}},T=class extends i{mfaMethods;constructor(t,n,o,r){super("mfa_required",t,{status:o,details:r}),this.name="MFARequiredAuthError",this.mfaMethods=n}};function Oe(e){switch(e){case"mfa_required":case"invalid_request":case"invalid_client":case"invalid_grant":case"unauthorized_client":case"unsupported_grant_type":case"invalid_scope":case"access_denied":case"unsupported_response_type":case"server_error":case"temporarily_unavailable":case"invalid_token":case"insufficient_scope":case"authentication_required":case"insufficient_user_authentication":return e;default:return"unknown_error"}}function Ie(e,t){if(!t)return new i("http_error",`Request failed with status ${e}`,{status:e});let n=Oe(t.error),o=t.error_description??t.reason??(t.error?`Auth error: ${t.error}`:`Request failed with status ${e}`);if(n==="mfa_required"){let r=Array.isArray(t.mfa_methods)?t.mfa_methods.filter(s=>typeof s=="string"):[];return new T(o,r,e,t)}return new i(n,o,{status:e,details:t})}async function oe(e){let t,n=await e.text();if(n)try{t=JSON.parse(n)}catch{t={reason:n}}return Ie(e.status,t)}function O(e){return e instanceof i}function Ue(e){return O(e)?e.code==="invalid_client"||e.code==="invalid_grant"||e.code==="unauthorized_client"||e.code==="invalid_token":!1}function L(e){if(!Array.isArray(e))return;let t=e.filter(n=>typeof n=="object"&&n!==null&&typeof n.type=="string");return t.length>0?t:void 0}async function f(e){let t=await e.getTokens();if(!t?.accessToken)throw new i("invalid_token","No access token is available. Authenticate first.");return t.accessToken}function m(e){return Object.fromEntries(Object.entries(e).filter(([,t])=>typeof t<"u"))}function b(e,t){let n=e.access_token,o=e.token_type,r=e.expires_in;if(typeof n!="string"||typeof o!="string"||typeof r!="number")throw new i("unknown_error","Unexpected token response payload.",{details:e});let s={accessToken:n,tokenType:o,expiresIn:r},a=typeof e.refresh_token=="string"?e.refresh_token:t;a&&(s.refreshToken=a),typeof e.scope=="string"&&(s.scope=e.scope),typeof e.id_token=="string"&&(s.idToken=e.id_token);let u=L(e.authorization_details);return u&&(s.authorizationDetails=u),s}function ze(e){return{id:String(e.id??""),deviceName:typeof e.device_name=="string"?e.device_name:void 0,deviceType:String(e.device_type??""),browser:typeof e.browser=="string"?e.browser:void 0,os:typeof e.os=="string"?e.os:void 0,ipAddress:String(e.ip_address??""),country:typeof e.country=="string"?e.country:void 0,city:typeof e.city=="string"?e.city:void 0,isActive:!!e.is_active,isCurrent:!!e.is_current,isTrusted:!!e.is_trusted,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0,createdAt:typeof e.created_at=="string"?e.created_at:void 0}}function B(e){return{id:String(e.id??""),deviceId:typeof e.device_id=="string"?e.device_id:void 0,deviceName:typeof e.device_name=="string"?e.device_name:void 0,deviceType:String(e.device_type??""),userAgent:typeof e.user_agent=="string"?e.user_agent:void 0,browser:typeof e.browser=="string"?e.browser:void 0,browserVersion:typeof e.browser_version=="string"?e.browser_version:void 0,os:typeof e.os=="string"?e.os:void 0,osVersion:typeof e.os_version=="string"?e.os_version:void 0,ipAddress:String(e.ip_address??""),country:typeof e.country=="string"?e.country:void 0,city:typeof e.city=="string"?e.city:void 0,isActive:!!e.is_active,isRevoked:!!e.is_revoked,isCurrent:!!e.is_current,isTrusted:!!e.is_trusted,requiresMfa:!!e.requires_mfa,accessTokenCount:typeof e.access_token_count=="number"?e.access_token_count:0,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0,expiresAt:typeof e.expires_at=="string"?e.expires_at:void 0,createdAt:typeof e.created_at=="string"?e.created_at:void 0,revokedAt:typeof e.revoked_at=="string"?e.revoked_at:void 0,revocationReason:typeof e.revocation_reason=="string"?e.revocation_reason:void 0}}function J(e){return{success:!!e.success,sessionsRevoked:typeof e.sessions_revoked=="number"?e.sessions_revoked:0,tokensRevoked:typeof e.tokens_revoked=="number"?e.tokens_revoked:0}}function xe(e){let t=Array.isArray(e.items)?e.items:[],o=e.metadata&&typeof e.metadata=="object"?e.metadata:{};return{items:t.filter(r=>typeof r=="object"&&r!==null).map(ze),metadata:{page:typeof o.page=="number"?o.page:1,per:typeof o.per=="number"?o.per:t.length,total:typeof o.total=="number"?o.total:t.length}}}function re(e){return{async list(t){let n=await f(e),o=new URLSearchParams;typeof t?.page=="number"&&o.set("page",String(t.page)),typeof t?.perPage=="number"&&o.set("per_page",String(t.perPage)),t?.userId&&o.set("user_id",t.userId);let r=`/api/v1/sessions${o.size?`?${o.toString()}`:""}`,s=await e.http.request(r,{token:n});return xe(s)},async current(){let t=await f(e),n=await e.http.request("/api/v1/sessions/current",{token:t});return B(n)},async get(t){let n=await f(e),o=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{token:n});return B(o)},async update(t,n){let o=await f(e),r=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{method:"PATCH",token:o,body:m({device_name:n.deviceName,is_trusted:n.isTrusted})});return B(r)},async revoke(t,n){let o=await f(e),r=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{method:"DELETE",token:o,body:m({reason:n?.reason})});return J(r)},async revokeAll(){let t=await f(e),n=await e.http.request("/api/v1/sessions/revoke-all",{method:"POST",token:t});return J(n)},async revokeAllDevices(){let t=await f(e),n=await e.http.request("/api/v1/sessions/revoke-all-devices",{method:"POST",token:t});return J(n)}}}function se(){let e=globalThis.crypto;if(!e?.getRandomValues)throw new i("invalid_request","Web Crypto API is unavailable in this runtime. PKCE requires globalThis.crypto.");return e}function ie(e){let t="";for(let o of e)t+=String.fromCharCode(o);if(typeof btoa!="function")throw new i("server_error","base64UrlEncode requires globalThis.btoa (Web/Deno runtime).");return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function z(e=32){if(!Number.isInteger(e)||e<=0)throw new i("invalid_request","randomUrlSafeString length must be a positive integer.");let t=new Uint8Array(e);return se().getRandomValues(t),ie(t)}function x(){return z(32)}function D(){return z(32)}function ae(){return z(32)}async function ue(e){let t=se();if(!t.subtle?.digest)throw new i("invalid_request","SubtleCrypto.digest is unavailable; cannot derive an S256 code challenge.");let n=new TextEncoder().encode(e),o=await t.subtle.digest("SHA-256",n);return ie(new Uint8Array(o))}async function j(e="S256"){let t=ae();if(e==="plain")return{codeVerifier:t,codeChallenge:t,codeChallengeMethod:"plain"};let n=await ue(t);return{codeVerifier:t,codeChallenge:n,codeChallengeMethod:"S256"}}function H(e,t){let n=new TextEncoder().encode(e),o=new TextEncoder().encode(t),r=Math.max(n.length,o.length),s=n.length^o.length;for(let a=0;a<r;a+=1)s|=(n[a]??0)^(o[a]??0);return s===0}function De(e){return{active:!!e.active,scope:typeof e.scope=="string"?e.scope:void 0,clientId:typeof e.client_id=="string"?e.client_id:void 0,username:typeof e.username=="string"?e.username:void 0,tokenType:typeof e.token_type=="string"?e.token_type:void 0,exp:typeof e.exp=="number"?e.exp:void 0,iat:typeof e.iat=="number"?e.iat:void 0,sub:typeof e.sub=="string"?e.sub:void 0,authorizationDetails:L(e.authorization_details)}}function M(e){return{async password(t){let n=m({grant_type:"password",client_id:e.config.clientId,client_secret:e.config.clientSecret,username:t.username,email:t.email,password:t.password,scope:t.scope,mfa_code:t.mfaCode,mfa_backup_code:t.mfaBackupCode}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async refresh(t){let n=await e.getTokens(),o=t?.refreshToken??n?.refreshToken;if(!o)throw new i("invalid_request","No refresh token is available.");let r=m({grant_type:"refresh_token",client_id:e.config.clientId,client_secret:e.config.clientSecret,refresh_token:o,scope:t?.scope}),s=await e.http.request("/oauth/token",{method:"POST",body:r}),a=b(s,o);return await e.setTokens(a),a},async clientCredentials(t){let n=m({grant_type:"client_credentials",client_id:e.config.clientId,client_secret:e.config.clientSecret,scope:t?.scope}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async authorizationCode(t){let n=m({grant_type:"authorization_code",client_id:e.config.clientId,client_secret:e.config.clientSecret,code:t.code,redirect_uri:t.redirectUri,code_verifier:t.codeVerifier,scope:t.scope}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async revoke(t){let n=await e.getTokens(),o=t?.token??n?.accessToken;if(!o)throw new i("invalid_request","No token provided for revocation.");await e.http.request("/oauth/revoke",{method:"POST",body:m({client_id:e.config.clientId,client_secret:e.config.clientSecret,token:o,token_type_hint:t?.tokenTypeHint})}),n&&(o===n.accessToken||o===n.refreshToken)&&await e.clearTokens()},async introspect(t){let n=await e.http.request("/oauth/introspect",{method:"POST",body:m({client_id:e.config.clientId,client_secret:e.config.clientSecret,token:t.token})});return De(n)},async tokenExchange(t){let n=m({grant_type:"urn:ietf:params:oauth:grant-type:token-exchange",client_id:e.config.clientId,client_secret:e.config.clientSecret,subject_token:t.subjectToken,subject_token_type:t.subjectTokenType??"urn:ietf:params:oauth:token-type:access_token",requested_subject:t.requestedSubject,scope:t.scope,audience:t.audience}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r}}}function de(e,t){let n=e.trim();if(!n)throw new i("invalid_request",`${t} is required.`);return n}async function h(e,t,n){let o=await f(e),r=n?.query,s=r&&Object.keys(r).length>0?`?${new URLSearchParams(Object.entries(r).filter(([,a])=>typeof a<"u").map(([a,u])=>[a,String(u)])).toString()}`:"";return e.http.request(`${t}${s}`,{method:n?.method,body:n?.body,token:o})}async function S(e,t,n){await h(e,t,n)}function A(e,t){return encodeURIComponent(de(e,t))}function je(e){let t=Array.isArray(e.mfa_methods)?e.mfa_methods.filter(n=>typeof n=="string"):void 0;return{redirectUri:String(e.redirect_uri??""),code:typeof e.code=="string"?e.code:void 0,state:typeof e.state=="string"?e.state:void 0,error:typeof e.error=="string"?e.error:void 0,errorDescription:typeof e.error_description=="string"?e.error_description:void 0,mfaMethods:t,accessToken:typeof e.access_token=="string"?e.access_token:void 0,tokenType:typeof e.token_type=="string"?e.token_type:void 0,expiresIn:typeof e.expires_in=="number"?e.expires_in:void 0,scope:typeof e.scope=="string"?e.scope:void 0,idToken:typeof e.id_token=="string"?e.id_token:void 0}}function Me(e){let t=Array.isArray(e.redirect_uris)?e.redirect_uris.filter(n=>typeof n=="string"&&n.length>0):[];return{clientId:String(e.client_id??""),name:String(e.name??""),description:typeof e.description=="string"?e.description:void 0,isFirstParty:!!e.is_first_party,redirectUris:t}}function $e(e){let t=Array.isArray(e.mfa_methods)?e.mfa_methods.filter(o=>typeof o=="string"):void 0,n=Array.isArray(e.uncovered_scopes)?e.uncovered_scopes.filter(o=>typeof o=="string"):void 0;return{consentSatisfied:!!e.consent_satisfied,requiresMfa:!!e.requires_mfa,mfaMethods:t,uncoveredScopes:n,error:typeof e.error=="string"?e.error:void 0,errorDescription:typeof e.error_description=="string"?e.error_description:void 0}}function ce(e,t){let n=new URL(e),o=new URL(t);if(n.origin!==o.origin||n.pathname!=="/oauth/authorize/consent")throw new i("invalid_request","callbackUrl must target /oauth/authorize/consent on the configured auth server.");return n}function pe(e){async function t(o,r){let s=ce(o,e.config.baseUrl),a=await e.http.request(`${s.pathname}${s.search}`,{method:"POST",body:{username:r.username,password:r.password,approved:r.approved??!0,requested_scopes:r.requestedScopes,mfa_code:r.mfaCode,mfa_backup_code:r.mfaBackupCode}}),u=je(a);if(u.error==="mfa_required")throw new T(u.errorDescription??"Multi-factor authentication is required",u.mfaMethods??[],void 0,a);return u}async function n(o,r){let s=ce(o,e.config.baseUrl),a=await e.http.request(`${s.pathname}/evaluate${s.search}`,{method:"POST",body:{username:r.username,password:r.password,requested_scopes:r.requestedScopes,mfa_code:r.mfaCode,mfa_backup_code:r.mfaBackupCode}}),u=$e(a);if(u.error==="mfa_required"||u.requiresMfa)throw new T(u.errorDescription??"Multi-factor authentication is required",u.mfaMethods??[],void 0,a);return u}return{consent:t,evaluateConsent:n,consentWithCredentials(o){return t(o.callbackUrl,{username:o.username,password:o.password,approved:o.approved,requestedScopes:o.requestedScopes,mfaCode:o.mfaCode,mfaBackupCode:o.mfaBackupCode})},evaluateConsentWithCredentials(o){return n(o.callbackUrl,{username:o.username,password:o.password,requestedScopes:o.requestedScopes,mfaCode:o.mfaCode,mfaBackupCode:o.mfaBackupCode})}}}function fe(e){return{async publicClient(t){let n=await e.http.request(`/oauth/clients/${encodeURIComponent(t)}/public`);return Me(n)},async discoverAuthorizationServer(){let t=await e.http.request("/.well-known/oauth-authorization-server");return{issuer:String(t.issuer??""),authorizationEndpoint:String(t.authorization_endpoint??""),tokenEndpoint:String(t.token_endpoint??""),jwksUri:typeof t.jwks_uri=="string"?t.jwks_uri:void 0,revocationEndpoint:typeof t.revocation_endpoint=="string"?t.revocation_endpoint:void 0,introspectionEndpoint:typeof t.introspection_endpoint=="string"?t.introspection_endpoint:void 0,registrationEndpoint:typeof t.registration_endpoint=="string"?t.registration_endpoint:void 0,scopesSupported:Array.isArray(t.scopes_supported)?t.scopes_supported.filter(n=>typeof n=="string"):void 0,responseTypesSupported:Array.isArray(t.response_types_supported)?t.response_types_supported.filter(n=>typeof n=="string"):[],grantTypesSupported:Array.isArray(t.grant_types_supported)?t.grant_types_supported.filter(n=>typeof n=="string"):void 0,codeChallengeMethodsSupported:Array.isArray(t.code_challenge_methods_supported)?t.code_challenge_methods_supported.filter(n=>typeof n=="string"):void 0,pushedAuthorizationRequestEndpoint:typeof t.pushed_authorization_request_endpoint=="string"?t.pushed_authorization_request_endpoint:void 0,requirePushedAuthorizationRequests:typeof t.require_pushed_authorization_requests=="boolean"?t.require_pushed_authorization_requests:void 0,authorizationDetailsTypesSupported:Array.isArray(t.authorization_details_types_supported)?t.authorization_details_types_supported.filter(n=>typeof n=="string"):void 0,raw:t}}}}var V="openid profile email offline_access",le=new Set(["response_type","client_id","redirect_uri","scope","state","nonce","code_challenge","code_challenge_method","prompt","login_hint","authorization_details","request_uri"]);function Ne(e){if(typeof e=="string"){let t=e.indexOf("?"),n=t>=0?e.slice(t+1):e;return new URLSearchParams(n)}return e instanceof URLSearchParams?e:"raw"in e&&typeof e.raw=="object"?new URLSearchParams(e.raw):new URLSearchParams(e)}function me(e){let t=Ne(e),n={};return t.forEach((o,r)=>{n[r]=o}),{code:t.get("code")??void 0,state:t.get("state")??void 0,error:t.get("error")??void 0,errorDescription:t.get("error_description")??void 0,errorUri:t.get("error_uri")??void 0,raw:n}}function he(e){let t=M(e);return{...pe(e),async createRequest(o){if(!o.redirectUri?.trim())throw new i("invalid_request","redirectUri is required to build an authorization request.");let r=o.scope??V,s=o.state??x(),a=o.nonce??D(),u=await j(o.codeChallengeMethod??"S256"),y=o.authorizationEndpoint??`${e.config.baseUrl}/oauth/authorize`,R=new URL(y),l=R.searchParams;l.set("response_type",o.responseType??"code"),l.set("client_id",e.config.clientId),l.set("redirect_uri",o.redirectUri),l.set("scope",r),l.set("state",s),l.set("nonce",a),l.set("code_challenge",u.codeChallenge),l.set("code_challenge_method",u.codeChallengeMethod),o.authorizationDetails&&o.authorizationDetails.length>0&&l.set("authorization_details",JSON.stringify(o.authorizationDetails)),o.prompt&&l.set("prompt",o.prompt),o.loginHint&&l.set("login_hint",o.loginHint);for(let[w,q]of Object.entries(o.extraParams??{})){if(le.has(w))throw new i("invalid_request",`extraParams may not override the reserved authorization parameter "${w}".`);l.set(w,q)}return{url:R.toString(),state:s,nonce:a,codeVerifier:u.codeVerifier,codeChallenge:u.codeChallenge,redirectUri:o.redirectUri,scope:r}},async pushAuthorizationRequest(o){if(!o.redirectUri?.trim())throw new i("invalid_request","redirectUri is required to push an authorization request.");let r=o.scope??V,s=o.state??x(),a=o.nonce??D(),u=await j(o.codeChallengeMethod??"S256"),y={response_type:o.responseType??"code",client_id:e.config.clientId,redirect_uri:o.redirectUri,scope:r,state:s,nonce:a,code_challenge:u.codeChallenge,code_challenge_method:u.codeChallengeMethod};e.config.clientSecret&&(y.client_secret=e.config.clientSecret),o.authorizationDetails&&o.authorizationDetails.length>0&&(y.authorization_details=JSON.stringify(o.authorizationDetails));for(let[c,d]of Object.entries(o.extraParams??{})){if(le.has(c))throw new i("invalid_request",`extraParams may not override the reserved authorization parameter "${c}".`);y[c]=d}let R=await e.http.request("/oauth/par",{method:"POST",body:y}),l=R.request_uri,w=R.expires_in;if(typeof l!="string"||typeof w!="number")throw new i("unknown_error","Unexpected pushed authorization response payload.",{details:R});let q=o.authorizationEndpoint??`${e.config.baseUrl}/oauth/authorize`,p=new URL(q);return p.searchParams.set("client_id",e.config.clientId),p.searchParams.set("request_uri",l),{requestUri:l,expiresIn:w,request:{url:p.toString(),state:s,nonce:a,codeVerifier:u.codeVerifier,codeChallenge:u.codeChallenge,redirectUri:o.redirectUri,scope:r,requestUri:l}}},parseCallback:me,async probeAuthorize(o){let r=await e.http.requestRaw(o,{headers:{Accept:"application/json"},redirect:"manual"}),s=r.headers.get("location");if(s&&r.status>=300&&r.status<400)return{kind:"redirect",location:s,status:r.status};let a=await r.text(),u=a?JSON.parse(a):{};if(!r.ok)throw new i("server_error",typeof u.error_description=="string"?u.error_description:"Authorization probe failed",{status:r.status,details:u});let y=typeof u.authorization_url=="string"?u.authorization_url:void 0;return{kind:"json",status:r.status,authorizationUrl:y,payload:u}},async handleCallback(o){let s=typeof o.callback=="object"&&!(o.callback instanceof URLSearchParams)&&"raw"in o.callback?o.callback:me(o.callback);if(s.error)throw new i("access_denied",s.errorDescription??`Authorization failed: ${s.error}`,{details:s.raw});if(!s.state||!H(s.state,o.expectedState))throw new i("invalid_request","State mismatch on authorization callback (possible CSRF).");if(!s.code)throw new i("invalid_request","Authorization callback is missing the `code` parameter.");return t.authorizationCode({code:s.code,redirectUri:o.redirectUri,codeVerifier:o.codeVerifier,scope:o.scope})}}}function P(e){let t=e.step_id,n=e.step_type,o=e.name,r=e.order,s=e.is_required,a=e.timeout;if(typeof t!="string"||typeof n!="string"||typeof o!="string"||typeof r!="number"||typeof s!="boolean"||typeof a!="number")throw new i("unknown_error","Unexpected flow step payload.",{details:e});return{stepId:t,stepType:n,name:o,description:typeof e.description=="string"?e.description:void 0,order:r,isRequired:s,timeout:a,inputSchema:e.input_schema&&typeof e.input_schema=="object"?e.input_schema:void 0}}function Q(e){let t=e.current_step,n=e.remaining_steps;if(!t||typeof t!="object")throw new i("unknown_error","Missing current_step in flow response.",{details:e});let o=e.continuation_token;if(typeof o!="string"||!o)throw new i("unknown_error","Missing continuation_token in flow response.",{details:e});return{sessionId:String(e.session_id??""),flowId:String(e.flow_id??""),flowName:String(e.flow_name??""),currentStep:P(t),remainingSteps:Array.isArray(n)?n.filter(r=>typeof r=="object"&&r!==null).map(P):[],expiresAt:String(e.expires_at??""),continuationToken:o}}function Fe(e){return{sessionId:String(e.session_id??""),status:String(e.status??""),purpose:String(e.purpose??""),currentStep:e.current_step&&typeof e.current_step=="object"?P(e.current_step):void 0,completedSteps:Array.isArray(e.completed_steps)?e.completed_steps.filter(t=>typeof t=="string"):[],remainingSteps:Array.isArray(e.remaining_steps)?e.remaining_steps.filter(t=>typeof t=="object"&&t!==null).map(P):[],failedAttempts:typeof e.failed_attempts=="number"?e.failed_attempts:0,expiresAt:String(e.expires_at??""),lastActivityAt:String(e.last_activity_at??"")}}async function W(e,t){let n=t.status;if(n==="error"||typeof t.error=="string"&&n!=="in_progress"&&n!=="complete")throw new i("invalid_request",typeof t.error=="string"?t.error:"Flow step failed.",{details:t});if(n==="in_progress"){let o=t.next_step,r=t.remaining_steps;if(!o||typeof o!="object")throw new i("unknown_error","Missing next_step in flow step response.",{details:t});let s=t.debug&&typeof t.debug=="object"&&!Array.isArray(t.debug)?t.debug:void 0;return{status:"in_progress",sessionId:String(t.session_id??""),nextStep:P(o),completedSteps:Array.isArray(t.completed_steps)?t.completed_steps.filter(u=>typeof u=="string"):[],remainingSteps:Array.isArray(r)?r.filter(u=>typeof u=="object"&&u!==null).map(P):[],debug:s}}if(n==="complete"){let o=b(t);return await e.setTokens(o),{status:"complete",accessToken:o.accessToken,refreshToken:o.refreshToken,tokenType:o.tokenType,expiresIn:o.expiresIn,scope:o.scope,amr:Array.isArray(t.amr)?t.amr.filter(s=>typeof s=="string"):[],acr:typeof t.acr=="string"?t.acr:""}}throw new i("unknown_error","Unknown flow step status.",{details:t})}function ge(e){return{async initAuthentication(t){let n=await e.http.request("/oauth/authenticate/init",{method:"POST",body:m({client_id:t?.clientId??e.config.clientId,username:t?.username,flow_type:t?.flowType})});return Q(n)},async executeStep(t){let n=await e.http.request("/oauth/authenticate/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return W(e,n)},async initRegistration(t){let n=await e.http.request("/oauth/register/init",{method:"POST",body:m({client_id:t?.clientId??e.config.clientId,invite_code:t?.inviteCode,flow_type:t?.flowType})});return Q(n)},async executeRegistrationStep(t){let n=await e.http.request("/oauth/register/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return W(e,n)},async getStatus(t,n){let o=new URLSearchParams({continuation_token:n}),r=await e.http.request(`/oauth/flow/status/${encodeURIComponent(t)}?${o}`);return Fe(r)},async initRecovery(t){let n=await e.http.request("/oauth/recovery/init",{method:"POST",body:m({client_id:t?.clientId??e.config.clientId,recovery_type:t?.recoveryType,redirect_uri:t?.redirectUri})});return Q(n)},async executeRecoveryStep(t){let n=await e.http.request("/oauth/recovery/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return W(e,n)}}}function $(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}function Le(e){return{issuer:String(e.issuer??""),authorizationEndpoint:String(e.authorization_endpoint??""),tokenEndpoint:String(e.token_endpoint??""),userinfoEndpoint:typeof e.userinfo_endpoint=="string"?e.userinfo_endpoint:void 0,jwksUri:String(e.jwks_uri??""),revocationEndpoint:typeof e.revocation_endpoint=="string"?e.revocation_endpoint:void 0,introspectionEndpoint:typeof e.introspection_endpoint=="string"?e.introspection_endpoint:void 0,responseTypesSupported:$(e.response_types_supported),grantTypesSupported:$(e.grant_types_supported),scopesSupported:$(e.scopes_supported),codeChallengeMethodsSupported:$(e.code_challenge_methods_supported),raw:e}}function Be(e){return{sub:String(e.sub??""),name:typeof e.name=="string"?e.name:void 0,givenName:typeof e.given_name=="string"?e.given_name:void 0,familyName:typeof e.family_name=="string"?e.family_name:void 0,middleName:typeof e.middle_name=="string"?e.middle_name:void 0,nickname:typeof e.nickname=="string"?e.nickname:void 0,preferredUsername:typeof e.preferred_username=="string"?e.preferred_username:void 0,profile:typeof e.profile=="string"?e.profile:void 0,picture:typeof e.picture=="string"?e.picture:void 0,website:typeof e.website=="string"?e.website:void 0,gender:typeof e.gender=="string"?e.gender:void 0,birthdate:typeof e.birthdate=="string"?e.birthdate:void 0,zoneinfo:typeof e.zoneinfo=="string"?e.zoneinfo:void 0,locale:typeof e.locale=="string"?e.locale:void 0,updatedAt:typeof e.updated_at=="number"?e.updated_at:void 0,email:typeof e.email=="string"?e.email:void 0,emailVerified:typeof e.email_verified=="boolean"?e.email_verified:void 0,phoneNumber:typeof e.phone_number=="string"?e.phone_number:void 0,phoneNumberVerified:typeof e.phone_number_verified=="boolean"?e.phone_number_verified:void 0}}function ye(e){return{async userInfo(){let t=await f(e),n=await e.http.request("/oauth/userinfo",{token:t});return Be(n)},async discover(){let t=await e.http.request("/.well-known/openid-configuration");return Le(t)},async jwks(){let t=await e.http.request("/oauth/jwks");return{keys:Array.isArray(t.keys)?t.keys.filter(o=>typeof o=="object"&&o!==null):[]}}}}function N(e){return{...e,id:typeof e.id=="string"?e.id:"",organizationId:typeof e.organization_id=="string"?e.organization_id:void 0,email:typeof e.email=="string"?e.email:void 0,username:typeof e.username=="string"?e.username:void 0,firstName:typeof e.first_name=="string"?e.first_name:void 0,lastName:typeof e.last_name=="string"?e.last_name:void 0,isActive:typeof e.is_active=="boolean"?e.is_active:void 0,isVerified:typeof e.is_verified=="boolean"?e.is_verified:void 0,mfaEnabled:typeof e.mfa_enabled=="boolean"?e.mfa_enabled:void 0}}function G(e){return{id:String(e.id??""),name:typeof e.name=="string"?e.name:void 0,email:typeof e.email=="string"?e.email:void 0,phoneNumber:typeof e.phone_number=="string"?e.phone_number:void 0,relationship:typeof e.relationship=="string"?e.relationship:void 0,isVerified:typeof e.is_verified=="boolean"?e.is_verified:void 0}}function Je(e){return{id:String(e.id??""),provider:String(e.provider??""),providerUserId:typeof e.provider_user_id=="string"?e.provider_user_id:void 0,email:typeof e.email=="string"?e.email:void 0,isPrimary:typeof e.is_primary=="boolean"?e.is_primary:void 0}}function _e(e){return He(e)}function He(e){return{async me(){let t=await f(e),n=await e.http.request("/api/v1/users/me",{token:t});return N(n)},async updateMe(t){let n=await h(e,"/api/v1/users/me",{method:"PATCH",body:t});return N(n)},async changePassword(t){await S(e,"/api/v1/users/me/password",{method:"POST",body:{current_password:t.currentPassword,new_password:t.newPassword}})},async deleteAvatar(){let t=await h(e,"/api/v1/users/me/avatar",{method:"DELETE"});return N(t)},async uploadAvatar(t,n="avatar.jpg"){let o=await f(e),r=new FormData,s=t instanceof Blob?t:new Blob([new Uint8Array(t)]);r.append("avatar",s,n);let a=await e.http.request("/api/v1/users/me/avatar",{method:"POST",token:o,body:r});return N(a)},async verifyPhone(t){return h(e,"/api/v1/users/me/phone/verify",{method:"POST",body:t})},async verifyRecoveryEmail(t){return h(e,"/api/v1/users/me/recovery-email/verify",{method:"POST",body:t})},async securityOverview(){return h(e,"/api/v1/users/me/security-overview")},recoveryContacts:{async list(){let t=await h(e,"/api/v1/users/me/recovery-contacts");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(G):[]},async create(t){let n=await h(e,"/api/v1/users/me/recovery-contacts",{method:"POST",body:t});return G(n)},async update(t,n){let o=await h(e,`/api/v1/users/me/recovery-contacts/${A(t,"contactId")}`,{method:"PATCH",body:n});return G(o)},async delete(t){await S(e,`/api/v1/users/me/recovery-contacts/${A(t,"contactId")}`,{method:"DELETE"})}},identities:{async list(){let t=await h(e,"/api/v1/users/me/identities");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(Je):[]},async unlink(t){await S(e,`/api/v1/users/me/identities/${A(t,"identityId")}`,{method:"DELETE"})},async setPrimary(t){return h(e,`/api/v1/users/me/identities/${A(t,"identityId")}/primary`,{method:"PATCH"})}},async deleteMe(t){await S(e,"/api/v1/users/me",{method:"DELETE",body:{password:t.password}})}}}function C(e){return e&&typeof e=="object"?e:{}}function ke(e){return{async registerBegin(t){let n=await f(e),o=await e.http.request("/api/v1/users/me/webauthn/register/begin",{method:"POST",token:n,body:t});return C(o)},async registerFinish(t){let n=await f(e),o=await e.http.request("/api/v1/users/me/webauthn/register/finish",{method:"POST",token:n,body:t});return C(o)},async authenticateBegin(t){let n=await e.http.request("/api/v1/users/me/webauthn/authenticate/begin",{method:"POST",body:t});return C(n)},async authenticateFinish(t){let n=await e.http.request("/api/v1/users/me/webauthn/authenticate/finish",{method:"POST",body:t}),o=C(n);if(typeof o.access_token=="string"){let r=b(o);await e.setTokens(r)}return o},async credentials(){let t=await f(e),n=await e.http.request("/api/v1/users/me/webauthn/credentials",{token:t});return C(n)},async removeCredential(t,n){let o=await f(e);await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}`,{method:"DELETE",token:o,body:n?.password?{password:n.password}:void 0})},async renameCredential(t,n){let o=await f(e),r=await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}/rename`,{method:"PATCH",token:o,body:n});return C(r)},async setPrimaryCredential(t){let n=await f(e),o=await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}/primary`,{method:"POST",token:n});return C(o)}}}function Ve(e){return{isActive:!!(e.is_active??e.isActive),message:typeof e.message=="string"?e.message:void 0,scheduledStart:typeof e.scheduled_start=="string"?e.scheduled_start:void 0,scheduledEnd:typeof e.scheduled_end=="string"?e.scheduled_end:void 0,...e}}function be(e){return{async status(){let t=await e.http.request("/api/v1/maintenance/status");return Ve(t)}}}var Qe=128,K=254;function v(e,t){if(typeof e!="string")return;let n=e.trim();if(!(!n||n.length>t))return n}function Re(e){return{async request(t){let n=m({email:v(t.email,K),identifier:v(t.identifier,K),recovery_email:v(t.recoveryEmail,K),phone_number:v(t.phoneNumber,32),member_id:v(t.memberId,64),security_question:v(t.securityQuestion,256),security_answer:v(t.securityAnswer,256),redirect_uri:v(t.redirectUri,2048)}),o=await e.http.request("/oauth/password/reset/request",{method:"POST",body:n});return{ok:!!o.ok,message:String(o.message??"")}},async validate(t){let n=t.trim();if(!n)throw new i("invalid_request","token is required.");let o=await e.http.request(`/oauth/password/reset/validate?token=${encodeURIComponent(n)}`);return{ok:!!o.ok,valid:!!o.valid,expiresAt:typeof o.expires_at=="string"?o.expires_at:void 0}},async complete(t){if(!t.token.trim())throw new i("invalid_request","token is required.");if(!t.password||t.password.length>Qe)throw new i("invalid_request","password is required and must be <= 128 characters.");let n=await e.http.request("/oauth/password/reset/complete",{method:"POST",body:{token:t.token.trim(),password:t.password,password_confirm:t.passwordConfirm}});return{ok:!!n.ok,message:String(n.message??"")}}}}function We(e){return{id:String(e.id??""),deviceName:String(e.device_name??""),isVerified:!!e.is_verified,isPrimary:!!e.is_primary,createdAt:typeof e.created_at=="string"?e.created_at:void 0,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0}}function we(e){return{async setup(t){let n=t.deviceName?.trim();if(!n||n.length>128)throw new i("invalid_request","deviceName is required.");let o=await h(e,"/api/v1/users/me/mfa/setup",{method:"POST",body:{device_name:n}});return{deviceId:String(o.device_id??""),secret:String(o.secret??""),qrCodeUri:String(o.qr_code_uri??""),backupCodes:Array.isArray(o.backup_codes)?o.backup_codes.filter(r=>typeof r=="string"):[],algorithm:String(o.algorithm??""),digits:typeof o.digits=="number"?o.digits:6,period:typeof o.period=="number"?o.period:30}},async verify(t){return h(e,"/api/v1/users/me/mfa/verify",{method:"POST",body:{device_id:t.deviceId,totp_code:t.totpCode}})},async devices(){let t=await h(e,"/api/v1/users/me/mfa/devices");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(We):[]},async removeDevice(t){await S(e,`/api/v1/users/me/mfa/devices/${A(t,"deviceId")}`,{method:"DELETE"})},async regenerateBackupCodes(){let t=await h(e,"/api/v1/users/me/mfa/backup-codes/regenerate",{method:"POST"});return{backupCodes:Array.isArray(t.backup_codes)?t.backup_codes.filter(n=>typeof n=="string"):[]}},async disable(t){await S(e,"/api/v1/users/me/mfa/disable",{method:"POST",body:m({password:t?.password})})}}}var Se="https://prod-auth.tktchurch.com",Ge=new Set(["localhost","127.0.0.1","[::1]"]);function Ke(e){return Ge.has(e.toLowerCase())}function Y(e,t={}){let n=(e??Se).trim();if(!n)return Y(Se,t);let r=(/^https?:\/\//i.test(n)?n:`https://${n}`).replace(/\/+$/,""),s;try{s=new URL(r)}catch{throw new i("invalid_request","baseUrl must be a valid absolute URL.")}if(s.protocol==="http:"&&!t.allowInsecureTransport&&!Ke(s.hostname))throw new i("invalid_request","baseUrl must use HTTPS. Set allowInsecureTransport=true only for trusted local development.");return r}function Ye(e,t){if(!e&&t<=0)return{cleanup:()=>{}};let n=new AbortController,o,r=()=>{n.abort(e?.reason)};return e&&(e.aborted?n.abort(e.reason):e.addEventListener("abort",r,{once:!0})),t>0&&(o=setTimeout(()=>{n.abort(new Error(`Request timed out after ${t}ms`))},t)),{signal:n.signal,cleanup:()=>{o&&clearTimeout(o),e&&e.removeEventListener("abort",r)}}}function Xe(e,t){return/^https?:\/\//i.test(t)?t:`${e}${t.startsWith("/")?t:`/${t}`}`}function Ze(e,t,n){let o=new Headers(e);return t&&new Headers(t).forEach((s,a)=>{o.set(a,s)}),n&&!o.has("Authorization")&&o.set("Authorization",`Bearer ${n}`),o}function ve(e){return{async request(t,n){let o=await this.requestRaw(t,n);if(!o.ok)throw await oe(o);if(o.status===204)return;let r=await o.text();if(r)return JSON.parse(r)},async requestRaw(t,n){let o=Xe(e.baseUrl,t),r=Ze(e.defaultHeaders,n?.headers,n?.token),{signal:s,cleanup:a}=Ye(n?.signal,e.timeoutMs),u={method:n?.method??"GET",headers:r,signal:s,redirect:n?.redirect};typeof n?.body<"u"&&(n.body instanceof FormData?u.body=n.body:(r.has("Content-Type")||r.set("Content-Type","application/json"),u.body=JSON.stringify(n.body)));try{return await e.fetch(o,u)}catch(y){throw s?.aborted??!1?new i("timeout",`Request timed out: ${o}`,{details:y}):new i("network_error",`Network request failed: ${o}`,{details:y})}finally{a()}}}}var et="@tktchurch/auth/tokens",Z=32768,Ae=new Set(["accessToken","tokenType","expiresIn","refreshToken","scope","idToken","authorizationDetails"]),Ce=new Set(["__proto__","constructor","prototype"]),tt=/^[\w@./:-]{1,128}$/;function ee(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function Te(e){return typeof e=="string"&&e.length>0}function X(e){return typeof e=="string"&&e.length>0?e:void 0}function I(e){if(!ee(e))throw new i("invalid_request","Token storage rejected a non-object token payload.");for(let s of Object.keys(e))if(!Ae.has(s))throw new i("invalid_request",`Token storage rejected unknown field "${s}".`);if(!Te(e.accessToken))throw new i("invalid_request","Token storage requires a non-empty accessToken.");if(!Te(e.tokenType))throw new i("invalid_request","Token storage requires a non-empty tokenType.");if(typeof e.expiresIn!="number"||!Number.isFinite(e.expiresIn)||e.expiresIn<0)throw new i("invalid_request","Token storage requires a non-negative numeric expiresIn.");let t={accessToken:e.accessToken,tokenType:e.tokenType,expiresIn:e.expiresIn},n=X(e.refreshToken);n&&(t.refreshToken=n);let o=X(e.scope);o&&(t.scope=o);let r=X(e.idToken);if(r&&(t.idToken=r),typeof e.authorizationDetails<"u"){if(!Array.isArray(e.authorizationDetails)||!e.authorizationDetails.every(s=>ee(s)&&typeof s.type=="string"))throw new i("invalid_request","Token storage rejected malformed authorizationDetails.");t.authorizationDetails=e.authorizationDetails}return t}function nt(e){if(!ee(e))return null;for(let t of Object.keys(e))if(Ce.has(t)||!Ae.has(t))return null;try{return I(e)}catch{return null}}function ot(e){return JSON.parse(e,(t,n)=>{if(Ce.has(t))throw new SyntaxError("Forbidden JSON key in stored token payload.");return n})}function rt(e){let t=e.trim();if(!t)throw new i("invalid_request","Token storage key must be a non-empty string.");if(!tt.test(t))throw new i("invalid_request","Token storage key contains unsupported characters or exceeds 128 characters.");return t}function st(e){let t=I(e),n=JSON.stringify(t);if(n.length>Z)throw new i("invalid_request",`Serialized token payload exceeds ${Z} bytes.`);return n}var te=class{state=null;get(){return this.state}set(t){if(!t){this.clear();return}this.state=I(t)}clear(){this.state=null}};function U(){return new te}function it(){return typeof window<"u"&&typeof window.document<"u"}function at(e){if(e)return e;if(typeof globalThis.fetch=="function")return globalThis.fetch.bind(globalThis);throw new i("invalid_request","No fetch implementation available. Provide config.fetch.")}function Pe(e){if(!e.clientId?.trim())throw new i("invalid_request","clientId is required.");if(it()&&e.clientSecret&&!e.allowClientSecretInBrowser)throw new i("invalid_request","clientSecret in browser runtime is blocked by default. Set allowClientSecretInBrowser=true to override.");return{clientId:e.clientId,clientSecret:e.clientSecret,baseUrl:Y(e.baseUrl,{allowInsecureTransport:e.allowInsecureTransport??!1}),fetch:at(e.fetch),storage:e.storage??U(),timeoutMs:e.timeoutMs??15e3,defaultHeaders:e.defaultHeaders??{},autoRefresh:e.autoRefresh??!0,allowClientSecretInBrowser:e.allowClientSecretInBrowser??!1,allowInsecureTransport:e.allowInsecureTransport??!1}}function ne(e){let t=Pe(e),n=ve({baseUrl:t.baseUrl,fetch:t.fetch,timeoutMs:t.timeoutMs,defaultHeaders:t.defaultHeaders}),o=async()=>await t.storage.get(),r=async u=>{await t.storage.set(u)},s=async()=>{await t.storage.clear()},a={config:t,http:n,getTokens:o,setTokens:r,clearTokens:s};return{token:M(a),flow:ge(a),oidc:ye(a),authorize:he(a),user:_e(a),sessions:re(a),webauthn:ke(a),passwordReset:Re(a),mfa:we(a),maintenance:be(a),oauth:fe(a),tokens:{get:o,set:r,clear:s}}}var k=class extends Error{name="PhoneOtpError"};function E(e,t){return e instanceof k?e:O(e)?new k(e.message||t):e instanceof Error&&e.message?new k(e.message):new k(t)}function Ee(e){if(!O(e)||typeof e.status!="number")return!1;let t=e.status;return t>=400&&t<500&&t!==429}function qe(e){if(e.status!=="in_progress"||!e.debug)return;let t=e.debug.verification_code;return typeof t=="string"?t:void 0}function ut(e){return{...e,id:typeof e.id=="string"?e.id:"",first_name:typeof e.first_name=="string"?e.first_name:typeof e.firstName=="string"?e.firstName:void 0,last_name:typeof e.last_name=="string"?e.last_name:typeof e.lastName=="string"?e.lastName:void 0,email:typeof e.email=="string"?e.email:void 0,phone_number:typeof e.phone_number=="string"?e.phone_number:typeof e.phoneNumber=="string"?e.phoneNumber:void 0,phone_country_code:typeof e.phone_country_code=="string"?e.phone_country_code:typeof e.phoneCountryCode=="string"?e.phoneCountryCode:void 0,phone_verified:typeof e.phone_verified=="boolean"?e.phone_verified:typeof e.phoneVerified=="boolean"?e.phoneVerified:void 0,profile_picture_url:typeof e.profile_picture_url=="string"?e.profile_picture_url:typeof e.profilePictureUrl=="string"?e.profilePictureUrl:void 0,picture:typeof e.picture=="string"?e.picture:void 0,birthdate:typeof e.birthdate=="string"?e.birthdate:void 0}}function dt(e){let t=U(),n=e.auth??ne({baseUrl:e.baseUrl,clientId:e.clientId,allowInsecureTransport:e.allowInsecureTransport,timeoutMs:e.timeoutMs??2e4,storage:t,autoRefresh:!1}),o=e.guestProfile??{firstName:"Guest",lastName:"User"},r=o.emailDomain??"registrations.tktchurch.local",s=o.emailLocalPrefix??"reg";async function a(p,c){let d=await n.flow.initAuthentication({flowType:"phone_only",username:c}),g=await n.flow.executeStep({sessionId:d.sessionId,stepId:d.currentStep.stepId,continuationToken:d.continuationToken,credential:p});if(g.status!=="in_progress")throw new k("Unexpected sign-in response.");return{oauthSessionId:d.sessionId,verifyStepId:g.nextStep.stepId,mode:"authentication",continuationToken:d.continuationToken,debugCode:qe(g)}}async function u(p){let c=await n.flow.initRegistration({flowType:"phone_registration"}),d=await n.flow.executeRegistrationStep({sessionId:c.sessionId,stepId:c.currentStep.stepId,continuationToken:c.continuationToken,credential:p});if(d.status!=="in_progress")throw new k("Unexpected verification response.");return{oauthSessionId:c.sessionId,verifyStepId:d.nextStep.stepId,mode:"registration",continuationToken:c.continuationToken,debugCode:qe(d)}}async function y(p,c,d){let g={phone_country_code:p,phone_number:c};try{return await u(g)}catch(_){if(!Ee(_))throw E(_,"Could not send the code. Please try again.");try{return await a(g,d)}catch{throw E(_,"Could not send the code. Please try again.")}}}async function R(p,c,d){let g={phone_country_code:p,phone_number:c};try{return await a(g,d)}catch(_){if(!Ee(_))throw E(_,"Could not start sign-in.");try{return await u(g)}catch{throw E(_,"Could not start sign-in.")}}}async function l(p,c,d,g,_){return p==="registration"?await n.flow.executeRegistrationStep({sessionId:c,stepId:d,continuationToken:g,credential:_}):await n.flow.executeStep({sessionId:c,stepId:d,continuationToken:g,credential:_})}async function w(p,c){try{let d=await l(p.mode,p.oauthSessionId,p.verifyStepId,p.continuationToken,{code:c}),g=0;for(;d.status==="in_progress"&&g<6;){g++;let _=d.nextStep.stepType,F={};_==="profile_info"?F={first_name:o.firstName,last_name:o.lastName,email:`${s}+${p.oauthSessionId.slice(0,8).toLowerCase()}@${r}`}:_==="terms_acceptance"&&(F={accepted:"true"}),d=await l(p.mode,p.oauthSessionId,d.nextStep.stepId,p.continuationToken,F)}if(d.status!=="complete")throw new k("Sign-in did not complete. Please try again.");return{accessToken:d.accessToken,refreshToken:d.refreshToken,expiresIn:d.expiresIn}}catch(d){throw d instanceof k?d:E(d,"That code didn't match. Try again.")}}async function q(p){try{await t.set({accessToken:p,tokenType:"Bearer",expiresIn:3600});let c=await n.user.me();return ut(c)}catch(c){throw E(c,c instanceof i?`Profile fetch failed (${c.status??"error"})`:"Profile fetch failed")}}return{startPhoneOTP:y,startPhoneOTPForSignIn:R,verifyPhoneOTP:w,fetchProfile:q}}var ct=/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;function pt(e,t="/"){if(!e)return t;let n=e;try{n=decodeURIComponent(e)}catch{return t}return n.startsWith("/")&&!n.startsWith("//")&&!n.startsWith("/\\")&&!ct.test(n)&&!/^\/+[\\/]/.test(n)?n:t}export{i as AuthError,V as DEFAULT_AUTHORIZE_SCOPE,et as DEFAULT_TOKEN_STORAGE_KEY,Z as MAX_STORED_TOKEN_BYTES,T as MFARequiredAuthError,k as PhoneOtpError,I as assertValidAuthTokens,ne as createAuthClient,U as createMemoryTokenStorage,dt as createPhoneOtpClient,ue as deriveCodeChallenge,ae as generateCodeVerifier,D as generateNonce,j as generatePkce,x as generateState,O as isAuthError,Ue as isUnrecoverableAuthError,nt as parseStoredAuthTokens,z as randomUrlSafeString,ot as safeParseStoredJson,pt as sanitizePostAuthRedirect,st as serializeAuthTokens,H as timingSafeEqual,rt as validateStorageKey};
1
+ var i=class extends Error{code;status;details;constructor(t,n,o){super(n),this.name="AuthError",this.code=t,this.status=o?.status,this.details=o?.details}},T=class extends i{mfaMethods;constructor(t,n,o,r){super("mfa_required",t,{status:o,details:r}),this.name="MFARequiredAuthError",this.mfaMethods=n}};function Ie(e){switch(e){case"mfa_required":case"invalid_request":case"invalid_client":case"invalid_grant":case"unauthorized_client":case"unsupported_grant_type":case"invalid_scope":case"access_denied":case"unsupported_response_type":case"server_error":case"temporarily_unavailable":case"invalid_token":case"insufficient_scope":case"authentication_required":case"insufficient_user_authentication":return e;default:return"unknown_error"}}function Ue(e,t){if(!t)return new i("http_error",`Request failed with status ${e}`,{status:e});let n=Ie(t.error),o=t.error_description??t.reason??(t.error?`Auth error: ${t.error}`:`Request failed with status ${e}`);if(n==="mfa_required"){let r=Array.isArray(t.mfa_methods)?t.mfa_methods.filter(s=>typeof s=="string"):[];return new T(o,r,e,t)}return new i(n,o,{status:e,details:t})}async function re(e){let t,n=await e.text();if(n)try{t=JSON.parse(n)}catch{t={reason:n}}return Ue(e.status,t)}function U(e){return e instanceof i}function ze(e){return U(e)?e.code==="invalid_client"||e.code==="invalid_grant"||e.code==="unauthorized_client"||e.code==="invalid_token":!1}function J(e){if(!Array.isArray(e))return;let t=e.filter(n=>typeof n=="object"&&n!==null&&typeof n.type=="string");return t.length>0?t:void 0}async function f(e){let t=await e.getTokens();if(!t?.accessToken)throw new i("invalid_token","No access token is available. Authenticate first.");return t.accessToken}function h(e){return Object.fromEntries(Object.entries(e).filter(([,t])=>typeof t<"u"))}function b(e,t){let n=e.access_token,o=e.token_type,r=e.expires_in;if(typeof n!="string"||typeof o!="string"||typeof r!="number")throw new i("unknown_error","Unexpected token response payload.",{details:e});let s={accessToken:n,tokenType:o,expiresIn:r},a=typeof e.refresh_token=="string"?e.refresh_token:t;a&&(s.refreshToken=a),typeof e.scope=="string"&&(s.scope=e.scope),typeof e.id_token=="string"&&(s.idToken=e.id_token);let u=J(e.authorization_details);return u&&(s.authorizationDetails=u),s}function xe(e){return{id:String(e.id??""),deviceName:typeof e.device_name=="string"?e.device_name:void 0,deviceType:String(e.device_type??""),browser:typeof e.browser=="string"?e.browser:void 0,os:typeof e.os=="string"?e.os:void 0,ipAddress:String(e.ip_address??""),country:typeof e.country=="string"?e.country:void 0,city:typeof e.city=="string"?e.city:void 0,isActive:!!e.is_active,isCurrent:!!e.is_current,isTrusted:!!e.is_trusted,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0,createdAt:typeof e.created_at=="string"?e.created_at:void 0}}function H(e){return{id:String(e.id??""),deviceId:typeof e.device_id=="string"?e.device_id:void 0,deviceName:typeof e.device_name=="string"?e.device_name:void 0,deviceType:String(e.device_type??""),userAgent:typeof e.user_agent=="string"?e.user_agent:void 0,browser:typeof e.browser=="string"?e.browser:void 0,browserVersion:typeof e.browser_version=="string"?e.browser_version:void 0,os:typeof e.os=="string"?e.os:void 0,osVersion:typeof e.os_version=="string"?e.os_version:void 0,ipAddress:String(e.ip_address??""),country:typeof e.country=="string"?e.country:void 0,city:typeof e.city=="string"?e.city:void 0,isActive:!!e.is_active,isRevoked:!!e.is_revoked,isCurrent:!!e.is_current,isTrusted:!!e.is_trusted,requiresMfa:!!e.requires_mfa,accessTokenCount:typeof e.access_token_count=="number"?e.access_token_count:0,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0,expiresAt:typeof e.expires_at=="string"?e.expires_at:void 0,createdAt:typeof e.created_at=="string"?e.created_at:void 0,revokedAt:typeof e.revoked_at=="string"?e.revoked_at:void 0,revocationReason:typeof e.revocation_reason=="string"?e.revocation_reason:void 0}}function V(e){return{success:!!e.success,sessionsRevoked:typeof e.sessions_revoked=="number"?e.sessions_revoked:0,tokensRevoked:typeof e.tokens_revoked=="number"?e.tokens_revoked:0}}function De(e){let t=Array.isArray(e.items)?e.items:[],o=e.metadata&&typeof e.metadata=="object"?e.metadata:{};return{items:t.filter(r=>typeof r=="object"&&r!==null).map(xe),metadata:{page:typeof o.page=="number"?o.page:1,per:typeof o.per=="number"?o.per:t.length,total:typeof o.total=="number"?o.total:t.length}}}function se(e){return{async list(t){let n=await f(e),o=new URLSearchParams;typeof t?.page=="number"&&o.set("page",String(t.page)),typeof t?.perPage=="number"&&o.set("per_page",String(t.perPage)),t?.userId&&o.set("user_id",t.userId);let r=`/api/v1/sessions${o.size?`?${o.toString()}`:""}`,s=await e.http.request(r,{token:n});return De(s)},async current(){let t=await f(e),n=await e.http.request("/api/v1/sessions/current",{token:t});return H(n)},async get(t){let n=await f(e),o=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{token:n});return H(o)},async update(t,n){let o=await f(e),r=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{method:"PATCH",token:o,body:h({device_name:n.deviceName,is_trusted:n.isTrusted})});return H(r)},async revoke(t,n){let o=await f(e),r=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{method:"DELETE",token:o,body:h({reason:n?.reason})});return V(r)},async revokeAll(){let t=await f(e),n=await e.http.request("/api/v1/sessions/revoke-all",{method:"POST",token:t});return V(n)},async revokeAllDevices(){let t=await f(e),n=await e.http.request("/api/v1/sessions/revoke-all-devices",{method:"POST",token:t});return V(n)}}}function ie(){let e=globalThis.crypto;if(!e?.getRandomValues)throw new i("invalid_request","Web Crypto API is unavailable in this runtime. PKCE requires globalThis.crypto.");return e}function ae(e){let t="";for(let o of e)t+=String.fromCharCode(o);if(typeof btoa!="function")throw new i("server_error","base64UrlEncode requires globalThis.btoa (Web/Deno runtime).");return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function x(e=32){if(!Number.isInteger(e)||e<=0)throw new i("invalid_request","randomUrlSafeString length must be a positive integer.");let t=new Uint8Array(e);return ie().getRandomValues(t),ae(t)}function D(){return x(32)}function j(){return x(32)}function ue(){return x(32)}async function de(e){let t=ie();if(!t.subtle?.digest)throw new i("invalid_request","SubtleCrypto.digest is unavailable; cannot derive an S256 code challenge.");let n=new TextEncoder().encode(e),o=await t.subtle.digest("SHA-256",n);return ae(new Uint8Array(o))}async function M(e="S256"){let t=ue();if(e==="plain")return{codeVerifier:t,codeChallenge:t,codeChallengeMethod:"plain"};let n=await de(t);return{codeVerifier:t,codeChallenge:n,codeChallengeMethod:"S256"}}function Q(e,t){let n=new TextEncoder().encode(e),o=new TextEncoder().encode(t),r=Math.max(n.length,o.length),s=n.length^o.length;for(let a=0;a<r;a+=1)s|=(n[a]??0)^(o[a]??0);return s===0}function je(e){return{active:!!e.active,scope:typeof e.scope=="string"?e.scope:void 0,clientId:typeof e.client_id=="string"?e.client_id:void 0,username:typeof e.username=="string"?e.username:void 0,tokenType:typeof e.token_type=="string"?e.token_type:void 0,exp:typeof e.exp=="number"?e.exp:void 0,iat:typeof e.iat=="number"?e.iat:void 0,sub:typeof e.sub=="string"?e.sub:void 0,authorizationDetails:J(e.authorization_details)}}function $(e){return{async password(t){let n=h({grant_type:"password",client_id:e.config.clientId,client_secret:e.config.clientSecret,username:t.username,email:t.email,password:t.password,scope:t.scope,mfa_code:t.mfaCode,mfa_backup_code:t.mfaBackupCode}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async refresh(t){let n=await e.getTokens(),o=t?.refreshToken??n?.refreshToken;if(!o)throw new i("invalid_request","No refresh token is available.");let r=h({grant_type:"refresh_token",client_id:e.config.clientId,client_secret:e.config.clientSecret,refresh_token:o,scope:t?.scope}),s=await e.http.request("/oauth/token",{method:"POST",body:r}),a=b(s,o);return await e.setTokens(a),a},async clientCredentials(t){let n=h({grant_type:"client_credentials",client_id:e.config.clientId,client_secret:e.config.clientSecret,scope:t?.scope}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async authorizationCode(t){let n=h({grant_type:"authorization_code",client_id:e.config.clientId,client_secret:e.config.clientSecret,code:t.code,redirect_uri:t.redirectUri,code_verifier:t.codeVerifier,scope:t.scope}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r},async revoke(t){let n=await e.getTokens(),o=t?.token??n?.accessToken;if(!o)throw new i("invalid_request","No token provided for revocation.");await e.http.request("/oauth/revoke",{method:"POST",body:h({client_id:e.config.clientId,client_secret:e.config.clientSecret,token:o,token_type_hint:t?.tokenTypeHint})}),n&&(o===n.accessToken||o===n.refreshToken)&&await e.clearTokens()},async introspect(t){let n=await e.http.request("/oauth/introspect",{method:"POST",body:h({client_id:e.config.clientId,client_secret:e.config.clientSecret,token:t.token})});return je(n)},async tokenExchange(t){let n=h({grant_type:"urn:ietf:params:oauth:grant-type:token-exchange",client_id:e.config.clientId,client_secret:e.config.clientSecret,subject_token:t.subjectToken,subject_token_type:t.subjectTokenType??"urn:ietf:params:oauth:token-type:access_token",requested_subject:t.requestedSubject,scope:t.scope,audience:t.audience}),o=await e.http.request("/oauth/token",{method:"POST",body:n}),r=b(o);return await e.setTokens(r),r}}}function ce(e,t){let n=e.trim();if(!n)throw new i("invalid_request",`${t} is required.`);return n}async function y(e,t,n){let o=await f(e),r=n?.query,s=r&&Object.keys(r).length>0?`?${new URLSearchParams(Object.entries(r).filter(([,a])=>typeof a<"u").map(([a,u])=>[a,String(u)])).toString()}`:"";return e.http.request(`${t}${s}`,{method:n?.method,body:n?.body,token:o})}async function S(e,t,n){await y(e,t,n)}function A(e,t){return encodeURIComponent(ce(e,t))}function Me(e){let t=Array.isArray(e.mfa_methods)?e.mfa_methods.filter(n=>typeof n=="string"):void 0;return{redirectUri:String(e.redirect_uri??""),code:typeof e.code=="string"?e.code:void 0,state:typeof e.state=="string"?e.state:void 0,error:typeof e.error=="string"?e.error:void 0,errorDescription:typeof e.error_description=="string"?e.error_description:void 0,mfaMethods:t,accessToken:typeof e.access_token=="string"?e.access_token:void 0,tokenType:typeof e.token_type=="string"?e.token_type:void 0,expiresIn:typeof e.expires_in=="number"?e.expires_in:void 0,scope:typeof e.scope=="string"?e.scope:void 0,idToken:typeof e.id_token=="string"?e.id_token:void 0}}function $e(e){let t=Array.isArray(e.redirect_uris)?e.redirect_uris.filter(n=>typeof n=="string"&&n.length>0):[];return{clientId:String(e.client_id??""),name:String(e.name??""),description:typeof e.description=="string"?e.description:void 0,isFirstParty:!!e.is_first_party,redirectUris:t}}function Ne(e){let t=Array.isArray(e.mfa_methods)?e.mfa_methods.filter(o=>typeof o=="string"):void 0,n=Array.isArray(e.uncovered_scopes)?e.uncovered_scopes.filter(o=>typeof o=="string"):void 0;return{consentSatisfied:!!e.consent_satisfied,requiresMfa:!!e.requires_mfa,mfaMethods:t,uncoveredScopes:n,error:typeof e.error=="string"?e.error:void 0,errorDescription:typeof e.error_description=="string"?e.error_description:void 0}}function pe(e,t){let n=new URL(e),o=new URL(t);if(n.origin!==o.origin||n.pathname!=="/oauth/authorize/consent")throw new i("invalid_request","callbackUrl must target /oauth/authorize/consent on the configured auth server.");return n}function fe(e){async function t(o,r){let s=pe(o,e.config.baseUrl),a=await e.http.request(`${s.pathname}${s.search}`,{method:"POST",body:{username:r.username,password:r.password,approved:r.approved??!0,requested_scopes:r.requestedScopes,mfa_code:r.mfaCode,mfa_backup_code:r.mfaBackupCode}}),u=Me(a);if(u.error==="mfa_required")throw new T(u.errorDescription??"Multi-factor authentication is required",u.mfaMethods??[],void 0,a);return u}async function n(o,r){let s=pe(o,e.config.baseUrl),a=await e.http.request(`${s.pathname}/evaluate${s.search}`,{method:"POST",body:{username:r.username,password:r.password,requested_scopes:r.requestedScopes,mfa_code:r.mfaCode,mfa_backup_code:r.mfaBackupCode}}),u=Ne(a);if(u.error==="mfa_required"||u.requiresMfa)throw new T(u.errorDescription??"Multi-factor authentication is required",u.mfaMethods??[],void 0,a);return u}return{consent:t,evaluateConsent:n,consentWithCredentials(o){return t(o.callbackUrl,{username:o.username,password:o.password,approved:o.approved,requestedScopes:o.requestedScopes,mfaCode:o.mfaCode,mfaBackupCode:o.mfaBackupCode})},evaluateConsentWithCredentials(o){return n(o.callbackUrl,{username:o.username,password:o.password,requestedScopes:o.requestedScopes,mfaCode:o.mfaCode,mfaBackupCode:o.mfaBackupCode})}}}function le(e){return{async publicClient(t){let n=await e.http.request(`/oauth/clients/${encodeURIComponent(t)}/public`);return $e(n)},async discoverAuthorizationServer(){let t=await e.http.request("/.well-known/oauth-authorization-server");return{issuer:String(t.issuer??""),authorizationEndpoint:String(t.authorization_endpoint??""),tokenEndpoint:String(t.token_endpoint??""),jwksUri:typeof t.jwks_uri=="string"?t.jwks_uri:void 0,revocationEndpoint:typeof t.revocation_endpoint=="string"?t.revocation_endpoint:void 0,introspectionEndpoint:typeof t.introspection_endpoint=="string"?t.introspection_endpoint:void 0,registrationEndpoint:typeof t.registration_endpoint=="string"?t.registration_endpoint:void 0,scopesSupported:Array.isArray(t.scopes_supported)?t.scopes_supported.filter(n=>typeof n=="string"):void 0,responseTypesSupported:Array.isArray(t.response_types_supported)?t.response_types_supported.filter(n=>typeof n=="string"):[],grantTypesSupported:Array.isArray(t.grant_types_supported)?t.grant_types_supported.filter(n=>typeof n=="string"):void 0,codeChallengeMethodsSupported:Array.isArray(t.code_challenge_methods_supported)?t.code_challenge_methods_supported.filter(n=>typeof n=="string"):void 0,pushedAuthorizationRequestEndpoint:typeof t.pushed_authorization_request_endpoint=="string"?t.pushed_authorization_request_endpoint:void 0,requirePushedAuthorizationRequests:typeof t.require_pushed_authorization_requests=="boolean"?t.require_pushed_authorization_requests:void 0,authorizationDetailsTypesSupported:Array.isArray(t.authorization_details_types_supported)?t.authorization_details_types_supported.filter(n=>typeof n=="string"):void 0,raw:t}}}}var W="openid profile email offline_access",me=new Set(["response_type","client_id","redirect_uri","scope","state","nonce","code_challenge","code_challenge_method","prompt","login_hint","authorization_details","request_uri"]);function Fe(e){if(typeof e=="string"){let t=e.indexOf("?"),n=t>=0?e.slice(t+1):e;return new URLSearchParams(n)}return e instanceof URLSearchParams?e:"raw"in e&&typeof e.raw=="object"?new URLSearchParams(e.raw):new URLSearchParams(e)}function he(e){let t=Fe(e),n={};return t.forEach((o,r)=>{n[r]=o}),{code:t.get("code")??void 0,state:t.get("state")??void 0,error:t.get("error")??void 0,errorDescription:t.get("error_description")??void 0,errorUri:t.get("error_uri")??void 0,raw:n}}function ge(e){let t=$(e);return{...fe(e),async createRequest(o){if(!o.redirectUri?.trim())throw new i("invalid_request","redirectUri is required to build an authorization request.");let r=o.scope??W,s=o.state??D(),a=o.nonce??j(),u=await M(o.codeChallengeMethod??"S256"),_=o.authorizationEndpoint??`${e.config.baseUrl}/oauth/authorize`,R=new URL(_),l=R.searchParams;l.set("response_type",o.responseType??"code"),l.set("client_id",e.config.clientId),l.set("redirect_uri",o.redirectUri),l.set("scope",r),l.set("state",s),l.set("nonce",a),l.set("code_challenge",u.codeChallenge),l.set("code_challenge_method",u.codeChallengeMethod),o.authorizationDetails&&o.authorizationDetails.length>0&&l.set("authorization_details",JSON.stringify(o.authorizationDetails)),o.prompt&&l.set("prompt",o.prompt),o.loginHint&&l.set("login_hint",o.loginHint);for(let[w,O]of Object.entries(o.extraParams??{})){if(me.has(w))throw new i("invalid_request",`extraParams may not override the reserved authorization parameter "${w}".`);l.set(w,O)}return{url:R.toString(),state:s,nonce:a,codeVerifier:u.codeVerifier,codeChallenge:u.codeChallenge,redirectUri:o.redirectUri,scope:r}},async pushAuthorizationRequest(o){if(!o.redirectUri?.trim())throw new i("invalid_request","redirectUri is required to push an authorization request.");let r=o.scope??W,s=o.state??D(),a=o.nonce??j(),u=await M(o.codeChallengeMethod??"S256"),_={response_type:o.responseType??"code",client_id:e.config.clientId,redirect_uri:o.redirectUri,scope:r,state:s,nonce:a,code_challenge:u.codeChallenge,code_challenge_method:u.codeChallengeMethod};e.config.clientSecret&&(_.client_secret=e.config.clientSecret),o.authorizationDetails&&o.authorizationDetails.length>0&&(_.authorization_details=JSON.stringify(o.authorizationDetails));for(let[m,c]of Object.entries(o.extraParams??{})){if(me.has(m))throw new i("invalid_request",`extraParams may not override the reserved authorization parameter "${m}".`);_[m]=c}let R=await e.http.request("/oauth/par",{method:"POST",body:_}),l=R.request_uri,w=R.expires_in;if(typeof l!="string"||typeof w!="number")throw new i("unknown_error","Unexpected pushed authorization response payload.",{details:R});let O=o.authorizationEndpoint??`${e.config.baseUrl}/oauth/authorize`,p=new URL(O);return p.searchParams.set("client_id",e.config.clientId),p.searchParams.set("request_uri",l),{requestUri:l,expiresIn:w,request:{url:p.toString(),state:s,nonce:a,codeVerifier:u.codeVerifier,codeChallenge:u.codeChallenge,redirectUri:o.redirectUri,scope:r,requestUri:l}}},parseCallback:he,async probeAuthorize(o){let r=await e.http.requestRaw(o,{headers:{Accept:"application/json"},redirect:"manual"}),s=r.headers.get("location");if(s&&r.status>=300&&r.status<400)return{kind:"redirect",location:s,status:r.status};let a=await r.text(),u=a?JSON.parse(a):{};if(!r.ok)throw new i("server_error",typeof u.error_description=="string"?u.error_description:"Authorization probe failed",{status:r.status,details:u});let _=typeof u.authorization_url=="string"?u.authorization_url:void 0;return{kind:"json",status:r.status,authorizationUrl:_,payload:u}},async handleCallback(o){let s=typeof o.callback=="object"&&!(o.callback instanceof URLSearchParams)&&"raw"in o.callback?o.callback:he(o.callback);if(s.error)throw new i("access_denied",s.errorDescription??`Authorization failed: ${s.error}`,{details:s.raw});if(!s.state||!Q(s.state,o.expectedState))throw new i("invalid_request","State mismatch on authorization callback (possible CSRF).");if(!s.code)throw new i("invalid_request","Authorization callback is missing the `code` parameter.");return t.authorizationCode({code:s.code,redirectUri:o.redirectUri,codeVerifier:o.codeVerifier,scope:o.scope})}}}function P(e){let t=e.step_id,n=e.step_type,o=e.name,r=e.order,s=e.is_required,a=e.timeout;if(typeof t!="string"||typeof n!="string"||typeof o!="string"||typeof r!="number"||typeof s!="boolean"||typeof a!="number")throw new i("unknown_error","Unexpected flow step payload.",{details:e});return{stepId:t,stepType:n,name:o,description:typeof e.description=="string"?e.description:void 0,order:r,isRequired:s,timeout:a,inputSchema:e.input_schema&&typeof e.input_schema=="object"?e.input_schema:void 0}}function G(e){let t=e.current_step,n=e.remaining_steps;if(!t||typeof t!="object")throw new i("unknown_error","Missing current_step in flow response.",{details:e});let o=e.continuation_token;if(typeof o!="string"||!o)throw new i("unknown_error","Missing continuation_token in flow response.",{details:e});return{sessionId:String(e.session_id??""),flowId:String(e.flow_id??""),flowName:String(e.flow_name??""),currentStep:P(t),remainingSteps:Array.isArray(n)?n.filter(r=>typeof r=="object"&&r!==null).map(P):[],expiresAt:String(e.expires_at??""),continuationToken:o}}function Le(e){return{sessionId:String(e.session_id??""),status:String(e.status??""),purpose:String(e.purpose??""),currentStep:e.current_step&&typeof e.current_step=="object"?P(e.current_step):void 0,completedSteps:Array.isArray(e.completed_steps)?e.completed_steps.filter(t=>typeof t=="string"):[],remainingSteps:Array.isArray(e.remaining_steps)?e.remaining_steps.filter(t=>typeof t=="object"&&t!==null).map(P):[],failedAttempts:typeof e.failed_attempts=="number"?e.failed_attempts:0,expiresAt:String(e.expires_at??""),lastActivityAt:String(e.last_activity_at??"")}}async function K(e,t){let n=t.status;if(n==="error"||typeof t.error=="string"&&n!=="in_progress"&&n!=="complete")throw new i("invalid_request",typeof t.error=="string"?t.error:"Flow step failed.",{details:t});if(n==="in_progress"){let o=t.next_step,r=t.remaining_steps;if(!o||typeof o!="object")throw new i("unknown_error","Missing next_step in flow step response.",{details:t});let s=t.debug&&typeof t.debug=="object"&&!Array.isArray(t.debug)?t.debug:void 0;return{status:"in_progress",sessionId:String(t.session_id??""),nextStep:P(o),completedSteps:Array.isArray(t.completed_steps)?t.completed_steps.filter(u=>typeof u=="string"):[],remainingSteps:Array.isArray(r)?r.filter(u=>typeof u=="object"&&u!==null).map(P):[],debug:s}}if(n==="complete"){let o=b(t);return await e.setTokens(o),{status:"complete",accessToken:o.accessToken,refreshToken:o.refreshToken,tokenType:o.tokenType,expiresIn:o.expiresIn,scope:o.scope,amr:Array.isArray(t.amr)?t.amr.filter(s=>typeof s=="string"):[],acr:typeof t.acr=="string"?t.acr:""}}throw new i("unknown_error","Unknown flow step status.",{details:t})}function ye(e){return{async initAuthentication(t){let n=await e.http.request("/oauth/authenticate/init",{method:"POST",body:h({client_id:t?.clientId??e.config.clientId,username:t?.username,flow_type:t?.flowType})});return G(n)},async executeStep(t){let n=await e.http.request("/oauth/authenticate/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return K(e,n)},async initRegistration(t){let n=await e.http.request("/oauth/register/init",{method:"POST",body:h({client_id:t?.clientId??e.config.clientId,invite_code:t?.inviteCode,flow_type:t?.flowType})});return G(n)},async executeRegistrationStep(t){let n=await e.http.request("/oauth/register/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return K(e,n)},async getStatus(t,n){let o=new URLSearchParams({continuation_token:n}),r=await e.http.request(`/oauth/flow/status/${encodeURIComponent(t)}?${o}`);return Le(r)},async initRecovery(t){let n=await e.http.request("/oauth/recovery/init",{method:"POST",body:h({client_id:t?.clientId??e.config.clientId,recovery_type:t?.recoveryType,redirect_uri:t?.redirectUri})});return G(n)},async executeRecoveryStep(t){let n=await e.http.request("/oauth/recovery/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,continuation_token:t.continuationToken,credential:t.credential}});return K(e,n)}}}function N(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}function Be(e){return{issuer:String(e.issuer??""),authorizationEndpoint:String(e.authorization_endpoint??""),tokenEndpoint:String(e.token_endpoint??""),userinfoEndpoint:typeof e.userinfo_endpoint=="string"?e.userinfo_endpoint:void 0,jwksUri:String(e.jwks_uri??""),revocationEndpoint:typeof e.revocation_endpoint=="string"?e.revocation_endpoint:void 0,introspectionEndpoint:typeof e.introspection_endpoint=="string"?e.introspection_endpoint:void 0,responseTypesSupported:N(e.response_types_supported),grantTypesSupported:N(e.grant_types_supported),scopesSupported:N(e.scopes_supported),codeChallengeMethodsSupported:N(e.code_challenge_methods_supported),raw:e}}function Je(e){return{sub:String(e.sub??""),name:typeof e.name=="string"?e.name:void 0,givenName:typeof e.given_name=="string"?e.given_name:void 0,familyName:typeof e.family_name=="string"?e.family_name:void 0,middleName:typeof e.middle_name=="string"?e.middle_name:void 0,nickname:typeof e.nickname=="string"?e.nickname:void 0,preferredUsername:typeof e.preferred_username=="string"?e.preferred_username:void 0,profile:typeof e.profile=="string"?e.profile:void 0,picture:typeof e.picture=="string"?e.picture:void 0,website:typeof e.website=="string"?e.website:void 0,gender:typeof e.gender=="string"?e.gender:void 0,birthdate:typeof e.birthdate=="string"?e.birthdate:void 0,zoneinfo:typeof e.zoneinfo=="string"?e.zoneinfo:void 0,locale:typeof e.locale=="string"?e.locale:void 0,updatedAt:typeof e.updated_at=="number"?e.updated_at:void 0,email:typeof e.email=="string"?e.email:void 0,emailVerified:typeof e.email_verified=="boolean"?e.email_verified:void 0,phoneNumber:typeof e.phone_number=="string"?e.phone_number:void 0,phoneNumberVerified:typeof e.phone_number_verified=="boolean"?e.phone_number_verified:void 0}}function _e(e){return{async userInfo(){let t=await f(e),n=await e.http.request("/oauth/userinfo",{token:t});return Je(n)},async discover(){let t=await e.http.request("/.well-known/openid-configuration");return Be(t)},async jwks(){let t=await e.http.request("/oauth/jwks");return{keys:Array.isArray(t.keys)?t.keys.filter(o=>typeof o=="object"&&o!==null):[]}}}}function F(e){return{...e,id:typeof e.id=="string"?e.id:"",organizationId:typeof e.organization_id=="string"?e.organization_id:void 0,email:typeof e.email=="string"?e.email:void 0,username:typeof e.username=="string"?e.username:void 0,firstName:typeof e.first_name=="string"?e.first_name:void 0,lastName:typeof e.last_name=="string"?e.last_name:void 0,isActive:typeof e.is_active=="boolean"?e.is_active:void 0,isVerified:typeof e.is_verified=="boolean"?e.is_verified:void 0,mfaEnabled:typeof e.mfa_enabled=="boolean"?e.mfa_enabled:void 0}}function Y(e){return{id:String(e.id??""),name:typeof e.name=="string"?e.name:void 0,email:typeof e.email=="string"?e.email:void 0,phoneNumber:typeof e.phone_number=="string"?e.phone_number:void 0,relationship:typeof e.relationship=="string"?e.relationship:void 0,isVerified:typeof e.is_verified=="boolean"?e.is_verified:void 0}}function He(e){return{id:String(e.id??""),provider:String(e.provider??""),providerUserId:typeof e.provider_user_id=="string"?e.provider_user_id:void 0,email:typeof e.email=="string"?e.email:void 0,isPrimary:typeof e.is_primary=="boolean"?e.is_primary:void 0}}function ke(e){return Ve(e)}function Ve(e){return{async me(){let t=await f(e),n=await e.http.request("/api/v1/users/me",{token:t});return F(n)},async updateMe(t){let n=await y(e,"/api/v1/users/me",{method:"PATCH",body:t});return F(n)},async changePassword(t){await S(e,"/api/v1/users/me/password",{method:"POST",body:{current_password:t.currentPassword,new_password:t.newPassword}})},async deleteAvatar(){let t=await y(e,"/api/v1/users/me/avatar",{method:"DELETE"});return F(t)},async uploadAvatar(t,n="avatar.jpg"){let o=await f(e),r=new FormData,s=t instanceof Blob?t:new Blob([new Uint8Array(t)]);r.append("avatar",s,n);let a=await e.http.request("/api/v1/users/me/avatar",{method:"POST",token:o,body:r});return F(a)},async verifyPhone(t){return y(e,"/api/v1/users/me/phone/verify",{method:"POST",body:t})},async verifyRecoveryEmail(t){return y(e,"/api/v1/users/me/recovery-email/verify",{method:"POST",body:t})},async securityOverview(){return y(e,"/api/v1/users/me/security-overview")},recoveryContacts:{async list(){let t=await y(e,"/api/v1/users/me/recovery-contacts");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(Y):[]},async create(t){let n=await y(e,"/api/v1/users/me/recovery-contacts",{method:"POST",body:t});return Y(n)},async update(t,n){let o=await y(e,`/api/v1/users/me/recovery-contacts/${A(t,"contactId")}`,{method:"PATCH",body:n});return Y(o)},async delete(t){await S(e,`/api/v1/users/me/recovery-contacts/${A(t,"contactId")}`,{method:"DELETE"})}},identities:{async list(){let t=await y(e,"/api/v1/users/me/identities");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(He):[]},async unlink(t){await S(e,`/api/v1/users/me/identities/${A(t,"identityId")}`,{method:"DELETE"})},async setPrimary(t){return y(e,`/api/v1/users/me/identities/${A(t,"identityId")}/primary`,{method:"PATCH"})}},async deleteMe(t){await S(e,"/api/v1/users/me",{method:"DELETE",body:{password:t.password}})}}}function C(e){return e&&typeof e=="object"?e:{}}function be(e){return{async registerBegin(t){let n=await f(e),o=await e.http.request("/api/v1/users/me/webauthn/register/begin",{method:"POST",token:n,body:t});return C(o)},async registerFinish(t){let n=await f(e),o=await e.http.request("/api/v1/users/me/webauthn/register/finish",{method:"POST",token:n,body:t});return C(o)},async authenticateBegin(t){let n=await e.http.request("/api/v1/users/me/webauthn/authenticate/begin",{method:"POST",body:t});return C(n)},async authenticateFinish(t){let n=await e.http.request("/api/v1/users/me/webauthn/authenticate/finish",{method:"POST",body:t}),o=C(n);if(typeof o.access_token=="string"){let r=b(o);await e.setTokens(r)}return o},async credentials(){let t=await f(e),n=await e.http.request("/api/v1/users/me/webauthn/credentials",{token:t});return C(n)},async removeCredential(t,n){let o=await f(e);await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}`,{method:"DELETE",token:o,body:n?.password?{password:n.password}:void 0})},async renameCredential(t,n){let o=await f(e),r=await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}/rename`,{method:"PATCH",token:o,body:n});return C(r)},async setPrimaryCredential(t){let n=await f(e),o=await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}/primary`,{method:"POST",token:n});return C(o)}}}function Qe(e){return{isActive:!!(e.is_active??e.isActive),message:typeof e.message=="string"?e.message:void 0,scheduledStart:typeof e.scheduled_start=="string"?e.scheduled_start:void 0,scheduledEnd:typeof e.scheduled_end=="string"?e.scheduled_end:void 0,...e}}function Re(e){return{async status(){let t=await e.http.request("/api/v1/maintenance/status");return Qe(t)}}}var We=128,X=254;function v(e,t){if(typeof e!="string")return;let n=e.trim();if(!(!n||n.length>t))return n}function we(e){return{async request(t){let n=h({email:v(t.email,X),identifier:v(t.identifier,X),recovery_email:v(t.recoveryEmail,X),phone_number:v(t.phoneNumber,32),member_id:v(t.memberId,64),security_question:v(t.securityQuestion,256),security_answer:v(t.securityAnswer,256),redirect_uri:v(t.redirectUri,2048)}),o=await e.http.request("/oauth/password/reset/request",{method:"POST",body:n});return{ok:!!o.ok,message:String(o.message??"")}},async validate(t){let n=t.trim();if(!n)throw new i("invalid_request","token is required.");let o=await e.http.request(`/oauth/password/reset/validate?token=${encodeURIComponent(n)}`);return{ok:!!o.ok,valid:!!o.valid,expiresAt:typeof o.expires_at=="string"?o.expires_at:void 0}},async complete(t){if(!t.token.trim())throw new i("invalid_request","token is required.");if(!t.password||t.password.length>We)throw new i("invalid_request","password is required and must be <= 128 characters.");let n=await e.http.request("/oauth/password/reset/complete",{method:"POST",body:{token:t.token.trim(),password:t.password,password_confirm:t.passwordConfirm}});return{ok:!!n.ok,message:String(n.message??"")}}}}function Ge(e){return{id:String(e.id??""),deviceName:String(e.device_name??""),isVerified:!!e.is_verified,isPrimary:!!e.is_primary,createdAt:typeof e.created_at=="string"?e.created_at:void 0,lastUsedAt:typeof e.last_used_at=="string"?e.last_used_at:void 0}}function Se(e){return{async setup(t){let n=t.deviceName?.trim();if(!n||n.length>128)throw new i("invalid_request","deviceName is required.");let o=await y(e,"/api/v1/users/me/mfa/setup",{method:"POST",body:{device_name:n}});return{deviceId:String(o.device_id??""),secret:String(o.secret??""),qrCodeUri:String(o.qr_code_uri??""),backupCodes:Array.isArray(o.backup_codes)?o.backup_codes.filter(r=>typeof r=="string"):[],algorithm:String(o.algorithm??""),digits:typeof o.digits=="number"?o.digits:6,period:typeof o.period=="number"?o.period:30}},async verify(t){return y(e,"/api/v1/users/me/mfa/verify",{method:"POST",body:{device_id:t.deviceId,totp_code:t.totpCode}})},async devices(){let t=await y(e,"/api/v1/users/me/mfa/devices");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(Ge):[]},async removeDevice(t){await S(e,`/api/v1/users/me/mfa/devices/${A(t,"deviceId")}`,{method:"DELETE"})},async regenerateBackupCodes(){let t=await y(e,"/api/v1/users/me/mfa/backup-codes/regenerate",{method:"POST"});return{backupCodes:Array.isArray(t.backup_codes)?t.backup_codes.filter(n=>typeof n=="string"):[]}},async disable(t){await S(e,"/api/v1/users/me/mfa/disable",{method:"POST",body:h({password:t?.password})})}}}var ve="https://prod-auth.tktchurch.com",Ke=new Set(["localhost","127.0.0.1","[::1]"]);function Ye(e){return Ke.has(e.toLowerCase())}function Z(e,t={}){let n=(e??ve).trim();if(!n)return Z(ve,t);let r=(/^https?:\/\//i.test(n)?n:`https://${n}`).replace(/\/+$/,""),s;try{s=new URL(r)}catch{throw new i("invalid_request","baseUrl must be a valid absolute URL.")}if(s.protocol==="http:"&&!t.allowInsecureTransport&&!Ye(s.hostname))throw new i("invalid_request","baseUrl must use HTTPS. Set allowInsecureTransport=true only for trusted local development.");return r}function Xe(e,t){if(!e&&t<=0)return{cleanup:()=>{}};let n=new AbortController,o,r=()=>{n.abort(e?.reason)};return e&&(e.aborted?n.abort(e.reason):e.addEventListener("abort",r,{once:!0})),t>0&&(o=setTimeout(()=>{n.abort(new Error(`Request timed out after ${t}ms`))},t)),{signal:n.signal,cleanup:()=>{o&&clearTimeout(o),e&&e.removeEventListener("abort",r)}}}function Ze(e,t){return/^https?:\/\//i.test(t)?t:`${e}${t.startsWith("/")?t:`/${t}`}`}function et(e,t,n){let o=new Headers(e);return t&&new Headers(t).forEach((s,a)=>{o.set(a,s)}),n&&!o.has("Authorization")&&o.set("Authorization",`Bearer ${n}`),o}function Te(e){return{async request(t,n){let o=await this.requestRaw(t,n);if(!o.ok)throw await re(o);if(o.status===204)return;let r=await o.text();if(r)return JSON.parse(r)},async requestRaw(t,n){let o=Ze(e.baseUrl,t),r=et(e.defaultHeaders,n?.headers,n?.token),{signal:s,cleanup:a}=Xe(n?.signal,e.timeoutMs),u={method:n?.method??"GET",headers:r,signal:s,redirect:n?.redirect};typeof n?.body<"u"&&(n.body instanceof FormData?u.body=n.body:(r.has("Content-Type")||r.set("Content-Type","application/json"),u.body=JSON.stringify(n.body)));try{return await e.fetch(o,u)}catch(_){throw s?.aborted??!1?new i("timeout",`Request timed out: ${o}`,{details:_}):new i("network_error",`Network request failed: ${o}`,{details:_})}finally{a()}}}}var tt="@tktchurch/auth/tokens",te=32768,Ce=new Set(["accessToken","tokenType","expiresIn","refreshToken","scope","idToken","authorizationDetails"]),Pe=new Set(["__proto__","constructor","prototype"]),nt=/^[\w@./:-]{1,128}$/;function ne(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function Ae(e){return typeof e=="string"&&e.length>0}function ee(e){return typeof e=="string"&&e.length>0?e:void 0}function z(e){if(!ne(e))throw new i("invalid_request","Token storage rejected a non-object token payload.");for(let s of Object.keys(e))if(!Ce.has(s))throw new i("invalid_request",`Token storage rejected unknown field "${s}".`);if(!Ae(e.accessToken))throw new i("invalid_request","Token storage requires a non-empty accessToken.");if(!Ae(e.tokenType))throw new i("invalid_request","Token storage requires a non-empty tokenType.");if(typeof e.expiresIn!="number"||!Number.isFinite(e.expiresIn)||e.expiresIn<0)throw new i("invalid_request","Token storage requires a non-negative numeric expiresIn.");let t={accessToken:e.accessToken,tokenType:e.tokenType,expiresIn:e.expiresIn},n=ee(e.refreshToken);n&&(t.refreshToken=n);let o=ee(e.scope);o&&(t.scope=o);let r=ee(e.idToken);if(r&&(t.idToken=r),typeof e.authorizationDetails<"u"){if(!Array.isArray(e.authorizationDetails)||!e.authorizationDetails.every(s=>ne(s)&&typeof s.type=="string"))throw new i("invalid_request","Token storage rejected malformed authorizationDetails.");t.authorizationDetails=e.authorizationDetails}return t}function ot(e){if(!ne(e))return null;for(let t of Object.keys(e))if(Pe.has(t)||!Ce.has(t))return null;try{return z(e)}catch{return null}}function rt(e){return JSON.parse(e,(t,n)=>{if(Pe.has(t))throw new SyntaxError("Forbidden JSON key in stored token payload.");return n})}function st(e){let t=e.trim();if(!t)throw new i("invalid_request","Token storage key must be a non-empty string.");if(!nt.test(t))throw new i("invalid_request","Token storage key contains unsupported characters or exceeds 128 characters.");return t}function it(e){let t=z(e),n=JSON.stringify(t);if(n.length>te)throw new i("invalid_request",`Serialized token payload exceeds ${te} bytes.`);return n}var oe=class{state=null;get(){return this.state}set(t){if(!t){this.clear();return}this.state=z(t)}clear(){this.state=null}};function E(){return new oe}function at(){return typeof window<"u"&&typeof window.document<"u"}function ut(e){if(e)return e;if(typeof globalThis.fetch=="function")return globalThis.fetch.bind(globalThis);throw new i("invalid_request","No fetch implementation available. Provide config.fetch.")}function Ee(e){if(!e.clientId?.trim())throw new i("invalid_request","clientId is required.");if(at()&&e.clientSecret&&!e.allowClientSecretInBrowser)throw new i("invalid_request","clientSecret in browser runtime is blocked by default. Set allowClientSecretInBrowser=true to override.");return{clientId:e.clientId,clientSecret:e.clientSecret,baseUrl:Z(e.baseUrl,{allowInsecureTransport:e.allowInsecureTransport??!1}),fetch:ut(e.fetch),storage:e.storage??E(),timeoutMs:e.timeoutMs??15e3,defaultHeaders:e.defaultHeaders??{},autoRefresh:e.autoRefresh??!0,allowClientSecretInBrowser:e.allowClientSecretInBrowser??!1,allowInsecureTransport:e.allowInsecureTransport??!1}}function L(e){let t=Ee(e),n=Te({baseUrl:t.baseUrl,fetch:t.fetch,timeoutMs:t.timeoutMs,defaultHeaders:t.defaultHeaders}),o=async()=>await t.storage.get(),r=async u=>{await t.storage.set(u)},s=async()=>{await t.storage.clear()},a={config:t,http:n,getTokens:o,setTokens:r,clearTokens:s};return{token:$(a),flow:ye(a),oidc:_e(a),authorize:ge(a),user:ke(a),sessions:se(a),webauthn:be(a),passwordReset:we(a),mfa:Se(a),maintenance:Re(a),oauth:le(a),tokens:{get:o,set:r,clear:s}}}var k=class extends Error{name="PhoneOtpError"};function q(e,t){return e instanceof k?e:U(e)?new k(e.message||t):e instanceof Error&&e.message?new k(e.message):new k(t)}function qe(e){if(!U(e)||typeof e.status!="number")return!1;let t=e.status;return t>=400&&t<500&&t!==429}function Oe(e){if(e.status!=="in_progress"||!e.debug)return;let t=e.debug.verification_code;return typeof t=="string"?t:void 0}function dt(e){return{...e,id:typeof e.id=="string"?e.id:"",first_name:typeof e.first_name=="string"?e.first_name:typeof e.firstName=="string"?e.firstName:void 0,last_name:typeof e.last_name=="string"?e.last_name:typeof e.lastName=="string"?e.lastName:void 0,email:typeof e.email=="string"?e.email:void 0,phone_number:typeof e.phone_number=="string"?e.phone_number:typeof e.phoneNumber=="string"?e.phoneNumber:void 0,phone_country_code:typeof e.phone_country_code=="string"?e.phone_country_code:typeof e.phoneCountryCode=="string"?e.phoneCountryCode:void 0,phone_verified:typeof e.phone_verified=="boolean"?e.phone_verified:typeof e.phoneVerified=="boolean"?e.phoneVerified:void 0,profile_picture_url:typeof e.profile_picture_url=="string"?e.profile_picture_url:typeof e.profilePictureUrl=="string"?e.profilePictureUrl:void 0,picture:typeof e.picture=="string"?e.picture:void 0,birthdate:typeof e.birthdate=="string"?e.birthdate:void 0}}function ct(e){let t=e.auth,n=e.guestProfile??{firstName:"Guest",lastName:"User"},o=n.emailDomain??"registrations.tktchurch.local",r=n.emailLocalPrefix??"reg";function s(){return t||L({baseUrl:e.baseUrl,clientId:e.clientId,allowInsecureTransport:e.allowInsecureTransport,timeoutMs:e.timeoutMs??2e4,storage:E(),autoRefresh:!1})}async function a(p,m){let c=s(),d=await c.flow.initAuthentication({flowType:"phone_only",username:m}),g=await c.flow.executeStep({sessionId:d.sessionId,stepId:d.currentStep.stepId,continuationToken:d.continuationToken,credential:p});if(g.status!=="in_progress")throw new k("Unexpected sign-in response.");return{oauthSessionId:d.sessionId,verifyStepId:g.nextStep.stepId,mode:"authentication",continuationToken:d.continuationToken,debugCode:Oe(g)}}async function u(p){let m=s(),c=await m.flow.initRegistration({flowType:"phone_registration"}),d=await m.flow.executeRegistrationStep({sessionId:c.sessionId,stepId:c.currentStep.stepId,continuationToken:c.continuationToken,credential:p});if(d.status!=="in_progress")throw new k("Unexpected verification response.");return{oauthSessionId:c.sessionId,verifyStepId:d.nextStep.stepId,mode:"registration",continuationToken:c.continuationToken,debugCode:Oe(d)}}async function _(p,m,c){let d={phone_country_code:p,phone_number:m};try{return await u(d)}catch(g){if(!qe(g))throw q(g,"Could not send the code. Please try again.");try{return await a(d,c)}catch{throw q(g,"Could not send the code. Please try again.")}}}async function R(p,m,c){let d={phone_country_code:p,phone_number:m};try{return await a(d,c)}catch(g){if(!qe(g))throw q(g,"Could not start sign-in.");try{return await u(d)}catch{throw q(g,"Could not start sign-in.")}}}async function l(p,m,c,d,g,I){return m==="registration"?await p.flow.executeRegistrationStep({sessionId:c,stepId:d,continuationToken:g,credential:I}):await p.flow.executeStep({sessionId:c,stepId:d,continuationToken:g,credential:I})}async function w(p,m){let c=s();try{let d=await l(c,p.mode,p.oauthSessionId,p.verifyStepId,p.continuationToken,{code:m}),g=0;for(;d.status==="in_progress"&&g<6;){g++;let I=d.nextStep.stepType,B={};I==="profile_info"?B={first_name:n.firstName,last_name:n.lastName,email:`${r}+${p.oauthSessionId.slice(0,8).toLowerCase()}@${o}`}:I==="terms_acceptance"&&(B={accepted:"true"}),d=await l(c,p.mode,p.oauthSessionId,d.nextStep.stepId,p.continuationToken,B)}if(d.status!=="complete")throw new k("Sign-in did not complete. Please try again.");return{accessToken:d.accessToken,refreshToken:d.refreshToken,expiresIn:d.expiresIn}}catch(d){throw d instanceof k?d:q(d,"That code didn't match. Try again.")}}async function O(p){let m;if(t)m=t;else{let c=E();await c.set({accessToken:p,tokenType:"Bearer",expiresIn:3600}),m=L({baseUrl:e.baseUrl,clientId:e.clientId,allowInsecureTransport:e.allowInsecureTransport,timeoutMs:e.timeoutMs??2e4,storage:c,autoRefresh:!1})}try{let c=await m.user.me();return dt(c)}catch(c){throw q(c,c instanceof i?`Profile fetch failed (${c.status??"error"})`:"Profile fetch failed")}}return{startPhoneOTP:_,startPhoneOTPForSignIn:R,verifyPhoneOTP:w,fetchProfile:O}}var pt=/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;function ft(e,t="/"){if(!e)return t;let n=e;try{n=decodeURIComponent(e)}catch{return t}return n.startsWith("/")&&!n.startsWith("//")&&!n.startsWith("/\\")&&!pt.test(n)&&!/^\/+[\\/]/.test(n)?n:t}export{i as AuthError,W as DEFAULT_AUTHORIZE_SCOPE,tt as DEFAULT_TOKEN_STORAGE_KEY,te as MAX_STORED_TOKEN_BYTES,T as MFARequiredAuthError,k as PhoneOtpError,z as assertValidAuthTokens,L as createAuthClient,E as createMemoryTokenStorage,ct as createPhoneOtpClient,de as deriveCodeChallenge,ue as generateCodeVerifier,j as generateNonce,M as generatePkce,D as generateState,U as isAuthError,ze as isUnrecoverableAuthError,ot as parseStoredAuthTokens,x as randomUrlSafeString,rt as safeParseStoredJson,ft as sanitizePostAuthRedirect,it as serializeAuthTokens,Q as timingSafeEqual,st as validateStorageKey};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tktchurch/auth",
3
- "version": "0.9.5",
3
+ "version": "0.9.6",
4
4
  "description": "Framework-agnostic auth SDK for TKTChurch OAuth/AuthFlow services",
5
5
  "license": "MIT",
6
6
  "type": "module",