@tktchurch/auth 0.9.1 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +101 -41
- package/PUBLISHING.md +34 -20
- package/README.md +66 -36
- package/SECURITY.md +47 -42
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +72 -25
- package/dist/index.d.ts +72 -25
- package/dist/index.js +1 -1
- package/dist/memory-DNWYyNSB.d.cts +1379 -0
- package/dist/memory-DNWYyNSB.d.ts +1379 -0
- package/dist/storage/memory.d.cts +1 -1
- package/dist/storage/memory.d.ts +1 -1
- package/package.json +1 -1
- package/dist/memory-CVWZvsJ0.d.cts +0 -730
- package/dist/memory-CVWZvsJ0.d.ts +0 -730
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var i=class extends Error{code;status;details;constructor(t,n,r){super(n),this.name="AuthError",this.code=t,this.status=r?.status,this.details=r?.details}},R=class extends i{mfaMethods;constructor(t,n,r,o){super("mfa_required",t,{status:r,details:o}),this.name="MFARequiredAuthError",this.mfaMethods=n}};function we(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 ve(e,t){if(!t)return new i("http_error",`Request failed with status ${e}`,{status:e});let n=we(t.error),r=t.error_description??t.reason??(t.error?`Auth error: ${t.error}`:`Request failed with status ${e}`);if(n==="mfa_required"){let o=Array.isArray(t.mfa_methods)?t.mfa_methods.filter(s=>typeof s=="string"):[];return new R(r,o,e,t)}return new i(n,r,{status:e,details:t})}async function K(e){let t,n=await e.text();if(n)try{t=JSON.parse(n)}catch{t={reason:n}}return ve(e.status,t)}function G(e){return e instanceof i}function Se(e){return G(e)?e.code==="invalid_client"||e.code==="invalid_grant"||e.code==="unauthorized_client"||e.code==="invalid_token":!1}function z(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 u(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 c(e){return Object.fromEntries(Object.entries(e).filter(([,t])=>typeof t<"u"))}function m(e,t){let n=e.access_token,r=e.token_type,o=e.expires_in;if(typeof n!="string"||typeof r!="string"||typeof o!="number")throw new i("unknown_error","Unexpected token response payload.",{details:e});let s={accessToken:n,tokenType:r,expiresIn:o},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 d=z(e.authorization_details);return d&&(s.authorizationDetails=d),s}function Ae(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 D(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 Te(e){let t=Array.isArray(e.items)?e.items:[],r=e.metadata&&typeof e.metadata=="object"?e.metadata:{};return{items:t.filter(o=>typeof o=="object"&&o!==null).map(Ae),metadata:{page:typeof r.page=="number"?r.page:1,per:typeof r.per=="number"?r.per:t.length,total:typeof r.total=="number"?r.total:t.length}}}function Y(e){return{async list(t){let n=await u(e),r=new URLSearchParams;typeof t?.page=="number"&&r.set("page",String(t.page)),typeof t?.perPage=="number"&&r.set("per_page",String(t.perPage)),t?.userId&&r.set("user_id",t.userId);let o=`/api/v1/sessions${r.size?`?${r.toString()}`:""}`,s=await e.http.request(o,{token:n});return Te(s)},async current(){let t=await u(e),n=await e.http.request("/api/v1/sessions/current",{token:t});return D(n)},async get(t){let n=await u(e),r=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{token:n});return D(r)},async update(t,n){let r=await u(e),o=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{method:"PATCH",token:r,body:c({device_name:n.deviceName,is_trusted:n.isTrusted})});return D(o)},async revoke(t,n){let r=await u(e),o=await e.http.request(`/api/v1/sessions/${encodeURIComponent(t)}`,{method:"DELETE",token:r,body:c({reason:n?.reason})});return j(o)},async revokeAll(){let t=await u(e),n=await e.http.request("/api/v1/sessions/revoke-all",{method:"POST",token:t});return j(n)},async revokeAllDevices(){let t=await u(e),n=await e.http.request("/api/v1/sessions/revoke-all-devices",{method:"POST",token:t});return j(n)}}}function X(){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 Z(e){let t="";for(let r of e)t+=String.fromCharCode(r);return(typeof btoa=="function"?btoa(t):Buffer.from(e).toString("base64")).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function S(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 X().getRandomValues(t),Z(t)}function A(){return S(32)}function T(){return S(32)}function ee(){return S(32)}async function te(e){let t=X();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),r=await t.subtle.digest("SHA-256",n);return Z(new Uint8Array(r))}async function C(e="S256"){let t=ee();if(e==="plain")return{codeVerifier:t,codeChallenge:t,codeChallengeMethod:"plain"};let n=await te(t);return{codeVerifier:t,codeChallenge:n,codeChallengeMethod:"S256"}}function x(e,t){let n=new TextEncoder().encode(e),r=new TextEncoder().encode(t),o=Math.max(n.length,r.length),s=n.length^r.length;for(let a=0;a<o;a+=1)s|=(n[a]??0)^(r[a]??0);return s===0}function Ce(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:z(e.authorization_details)}}function E(e){return{async password(t){let n=c({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}),r=await e.http.request("/oauth/token",{method:"POST",body:n}),o=m(r);return await e.setTokens(o),o},async refresh(t){let n=await e.getTokens(),r=t?.refreshToken??n?.refreshToken;if(!r)throw new i("invalid_request","No refresh token is available.");let o=c({grant_type:"refresh_token",client_id:e.config.clientId,client_secret:e.config.clientSecret,refresh_token:r,scope:t?.scope}),s=await e.http.request("/oauth/token",{method:"POST",body:o}),a=m(s,r);return await e.setTokens(a),a},async clientCredentials(t){let n=c({grant_type:"client_credentials",client_id:e.config.clientId,client_secret:e.config.clientSecret,scope:t?.scope}),r=await e.http.request("/oauth/token",{method:"POST",body:n}),o=m(r);return await e.setTokens(o),o},async authorizationCode(t){let n=c({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}),r=await e.http.request("/oauth/token",{method:"POST",body:n}),o=m(r);return await e.setTokens(o),o},async revoke(t){let n=await e.getTokens(),r=t?.token??n?.accessToken;if(!r)throw new i("invalid_request","No token provided for revocation.");await e.http.request("/oauth/revoke",{method:"POST",body:c({client_id:e.config.clientId,client_secret:e.config.clientSecret,token:r,token_type_hint:t?.tokenTypeHint})}),n&&(r===n.accessToken||r===n.refreshToken)&&await e.clearTokens()},async introspect(t){let n=await e.http.request("/oauth/introspect",{method:"POST",body:c({client_id:e.config.clientId,client_secret:e.config.clientSecret,token:t.token})});return Ce(n)},async tokenExchange(t){let n=c({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}),r=await e.http.request("/oauth/token",{method:"POST",body:n}),o=m(r);return await e.setTokens(o),o}}}function ne(e,t){let n=e.trim();if(!n)throw new i("invalid_request",`${t} is required.`);return n}async function f(e,t,n){let r=await u(e),o=n?.query,s=o&&Object.keys(o).length>0?`?${new URLSearchParams(Object.entries(o).filter(([,a])=>typeof a<"u").map(([a,d])=>[a,String(d)])).toString()}`:"";return e.http.request(`${t}${s}`,{method:n?.method,body:n?.body,token:r})}async function h(e,t,n){await f(e,t,n)}function _(e,t){return encodeURIComponent(ne(e,t))}function Ee(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 qe(e){return{clientId:String(e.client_id??""),name:String(e.name??""),description:typeof e.description=="string"?e.description:void 0,isFirstParty:!!e.is_first_party}}function Pe(e,t){let n=new URL(e),r=new URL(t);if(n.origin!==r.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 re(e){async function t(n,r){let o=Pe(n,e.config.baseUrl),s=await e.http.request(`${o.pathname}${o.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}}),a=Ee(s);if(a.error==="mfa_required")throw new R(a.errorDescription??"Multi-factor authentication is required",a.mfaMethods??[],void 0,s);return a}return{consent:t,consentWithCredentials(n){return t(n.callbackUrl,{username:n.username,password:n.password,approved:n.approved,requestedScopes:n.requestedScopes,mfaCode:n.mfaCode,mfaBackupCode:n.mfaBackupCode})}}}function oe(e){return{async publicClient(t){let n=await e.http.request(`/oauth/clients/${encodeURIComponent(t)}/public`);return qe(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 $="openid profile email offline_access",se=new Set(["response_type","client_id","redirect_uri","scope","state","nonce","code_challenge","code_challenge_method","prompt","login_hint","authorization_details","request_uri"]);function Oe(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 ie(e){let t=Oe(e),n={};return t.forEach((r,o)=>{n[o]=r}),{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 ae(e){let t=E(e);return{...re(e),async createRequest(r){if(!r.redirectUri?.trim())throw new i("invalid_request","redirectUri is required to build an authorization request.");let o=r.scope??$,s=r.state??A(),a=r.nonce??T(),d=await C(r.codeChallengeMethod??"S256"),l=r.authorizationEndpoint??`${e.config.baseUrl}/oauth/authorize`,g=new URL(l),p=g.searchParams;p.set("response_type",r.responseType??"code"),p.set("client_id",e.config.clientId),p.set("redirect_uri",r.redirectUri),p.set("scope",o),p.set("state",s),p.set("nonce",a),p.set("code_challenge",d.codeChallenge),p.set("code_challenge_method",d.codeChallengeMethod),r.authorizationDetails&&r.authorizationDetails.length>0&&p.set("authorization_details",JSON.stringify(r.authorizationDetails)),r.prompt&&p.set("prompt",r.prompt),r.loginHint&&p.set("login_hint",r.loginHint);for(let[b,O]of Object.entries(r.extraParams??{})){if(se.has(b))throw new i("invalid_request",`extraParams may not override the reserved authorization parameter "${b}".`);p.set(b,O)}return{url:g.toString(),state:s,nonce:a,codeVerifier:d.codeVerifier,codeChallenge:d.codeChallenge,redirectUri:r.redirectUri,scope:o}},async pushAuthorizationRequest(r){if(!r.redirectUri?.trim())throw new i("invalid_request","redirectUri is required to push an authorization request.");let o=r.scope??$,s=r.state??A(),a=r.nonce??T(),d=await C(r.codeChallengeMethod??"S256"),l={response_type:r.responseType??"code",client_id:e.config.clientId,redirect_uri:r.redirectUri,scope:o,state:s,nonce:a,code_challenge:d.codeChallenge,code_challenge_method:d.codeChallengeMethod};e.config.clientSecret&&(l.client_secret=e.config.clientSecret),r.authorizationDetails&&r.authorizationDetails.length>0&&(l.authorization_details=JSON.stringify(r.authorizationDetails));for(let[I,Re]of Object.entries(r.extraParams??{})){if(se.has(I))throw new i("invalid_request",`extraParams may not override the reserved authorization parameter "${I}".`);l[I]=Re}let g=await e.http.request("/oauth/par",{method:"POST",body:l}),p=g.request_uri,b=g.expires_in;if(typeof p!="string"||typeof b!="number")throw new i("unknown_error","Unexpected pushed authorization response payload.",{details:g});let O=r.authorizationEndpoint??`${e.config.baseUrl}/oauth/authorize`,U=new URL(O);return U.searchParams.set("client_id",e.config.clientId),U.searchParams.set("request_uri",p),{requestUri:p,expiresIn:b,request:{url:U.toString(),state:s,nonce:a,codeVerifier:d.codeVerifier,codeChallenge:d.codeChallenge,redirectUri:r.redirectUri,scope:o,requestUri:p}}},parseCallback:ie,async probeAuthorize(r){let o=await e.http.requestRaw(r,{headers:{Accept:"application/json"},redirect:"manual"}),s=o.headers.get("location");if(s&&o.status>=300&&o.status<400)return{kind:"redirect",location:s,status:o.status};let a=await o.text(),d=a?JSON.parse(a):{};if(!o.ok)throw new i("server_error",typeof d.error_description=="string"?d.error_description:"Authorization probe failed",{status:o.status,details:d});let l=typeof d.authorization_url=="string"?d.authorization_url:void 0;return{kind:"json",status:o.status,authorizationUrl:l,payload:d}},async handleCallback(r){let s=typeof r.callback=="object"&&!(r.callback instanceof URLSearchParams)&&"raw"in r.callback?r.callback:ie(r.callback);if(s.error)throw new i("access_denied",s.errorDescription??`Authorization failed: ${s.error}`,{details:s.raw});if(!s.state||!x(s.state,r.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:r.redirectUri,codeVerifier:r.codeVerifier,scope:r.scope})}}}function w(e){let t=e.step_id,n=e.step_type,r=e.name,o=e.order,s=e.is_required,a=e.timeout;if(typeof t!="string"||typeof n!="string"||typeof r!="string"||typeof o!="number"||typeof s!="boolean"||typeof a!="number")throw new i("unknown_error","Unexpected flow step payload.",{details:e});return{stepId:t,stepType:n,name:r,description:typeof e.description=="string"?e.description:void 0,order:o,isRequired:s,timeout:a,inputSchema:e.input_schema&&typeof e.input_schema=="object"?e.input_schema:void 0}}function M(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});return{sessionId:String(e.session_id??""),flowId:String(e.flow_id??""),flowName:String(e.flow_name??""),currentStep:w(t),remainingSteps:Array.isArray(n)?n.filter(r=>typeof r=="object"&&r!==null).map(w):[],expiresAt:String(e.expires_at??"")}}function Ue(e){return{sessionId:String(e.session_id??""),status:String(e.status??""),purpose:String(e.purpose??""),currentStep:e.current_step&&typeof e.current_step=="object"?w(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(w):[],failedAttempts:typeof e.failed_attempts=="number"?e.failed_attempts:0,expiresAt:String(e.expires_at??""),lastActivityAt:String(e.last_activity_at??"")}}async function L(e,t){let n=t.status;if(n==="in_progress"){let r=t.next_step,o=t.remaining_steps;if(!r||typeof r!="object")throw new i("unknown_error","Missing next_step in flow step response.",{details:t});return{status:"in_progress",sessionId:String(t.session_id??""),nextStep:w(r),completedSteps:Array.isArray(t.completed_steps)?t.completed_steps.filter(a=>typeof a=="string"):[],remainingSteps:Array.isArray(o)?o.filter(a=>typeof a=="object"&&a!==null).map(w):[]}}if(n==="complete"){let r=m(t);return await e.setTokens(r),{status:"complete",accessToken:r.accessToken,refreshToken:r.refreshToken,tokenType:r.tokenType,expiresIn:r.expiresIn,scope:r.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 de(e){return{async initAuthentication(t){let n=await e.http.request("/oauth/authenticate/init",{method:"POST",body:c({client_id:t?.clientId??e.config.clientId,username:t?.username})});return M(n)},async executeStep(t){let n=await e.http.request("/oauth/authenticate/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,credential:t.credential}});return L(e,n)},async initRegistration(t){let n=await e.http.request("/oauth/register/init",{method:"POST",body:c({client_id:t?.clientId??e.config.clientId,invite_code:t?.inviteCode})});return M(n)},async executeRegistrationStep(t){let n=await e.http.request("/oauth/register/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,credential:t.credential}});return L(e,n)},async getStatus(t){let n=await e.http.request(`/oauth/flow/status/${encodeURIComponent(t)}`);return Ue(n)},async initRecovery(t){let n=await e.http.request("/oauth/recovery/init",{method:"POST",body:c({client_id:t?.clientId??e.config.clientId,recovery_type:t?.recoveryType,redirect_uri:t?.redirectUri})});return M(n)},async executeRecoveryStep(t){let n=await e.http.request("/oauth/recovery/step",{method:"POST",body:{session_id:t.sessionId,step_id:t.stepId,credential:t.credential}});return L(e,n)}}}function q(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}function Ie(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:q(e.response_types_supported),grantTypesSupported:q(e.grant_types_supported),scopesSupported:q(e.scopes_supported),codeChallengeMethodsSupported:q(e.code_challenge_methods_supported),raw:e}}function ze(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 ue(e){return{async userInfo(){let t=await u(e),n=await e.http.request("/oauth/userinfo",{token:t});return ze(n)},async discover(){let t=await e.http.request("/.well-known/openid-configuration");return Ie(t)},async jwks(){let t=await e.http.request("/oauth/jwks");return{keys:Array.isArray(t.keys)?t.keys.filter(r=>typeof r=="object"&&r!==null):[]}}}}function P(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 N(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 De(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 ce(e){return je(e)}function je(e){return{async me(){let t=await u(e),n=await e.http.request("/api/v1/users/me",{token:t});return P(n)},async updateMe(t){let n=await f(e,"/api/v1/users/me",{method:"PATCH",body:t});return P(n)},async changePassword(t){await h(e,"/api/v1/users/me/password",{method:"POST",body:{current_password:t.currentPassword,new_password:t.newPassword}})},async deleteAvatar(){let t=await f(e,"/api/v1/users/me/avatar",{method:"DELETE"});return P(t)},async uploadAvatar(t,n="avatar.jpg"){let r=await u(e),o=new FormData,s=t instanceof Blob?t:new Blob([new Uint8Array(t)]);o.append("avatar",s,n);let a=await e.http.request("/api/v1/users/me/avatar",{method:"POST",token:r,body:o});return P(a)},async verifyPhone(t){return f(e,"/api/v1/users/me/phone/verify",{method:"POST",body:t})},async securityOverview(){return f(e,"/api/v1/users/me/security-overview")},recoveryContacts:{async list(){let t=await f(e,"/api/v1/users/me/recovery-contacts");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(N):[]},async create(t){let n=await f(e,"/api/v1/users/me/recovery-contacts",{method:"POST",body:t});return N(n)},async update(t,n){let r=await f(e,`/api/v1/users/me/recovery-contacts/${_(t,"contactId")}`,{method:"PATCH",body:n});return N(r)},async delete(t){await h(e,`/api/v1/users/me/recovery-contacts/${_(t,"contactId")}`,{method:"DELETE"})}},identities:{async list(){let t=await f(e,"/api/v1/users/me/identities");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(De):[]},async unlink(t){await h(e,`/api/v1/users/me/identities/${_(t,"identityId")}`,{method:"DELETE"})},async setPrimary(t){return f(e,`/api/v1/users/me/identities/${_(t,"identityId")}/primary`,{method:"PATCH"})}},async deleteMe(t){await h(e,"/api/v1/users/me",{method:"DELETE",body:{password:t.password}})}}}function k(e){return e&&typeof e=="object"?e:{}}function pe(e){return{async registerBegin(t){let n=await u(e),r=await e.http.request("/api/v1/users/me/webauthn/register/begin",{method:"POST",token:n,body:t});return k(r)},async registerFinish(t){let n=await u(e),r=await e.http.request("/api/v1/users/me/webauthn/register/finish",{method:"POST",token:n,body:t});return k(r)},async authenticateBegin(t){let n=await e.http.request("/api/v1/users/me/webauthn/authenticate/begin",{method:"POST",body:t});return k(n)},async authenticateFinish(t){let n=await e.http.request("/api/v1/users/me/webauthn/authenticate/finish",{method:"POST",body:t}),r=k(n);if(typeof r.access_token=="string"){let o=m(r);await e.setTokens(o)}return r},async credentials(){let t=await u(e),n=await e.http.request("/api/v1/users/me/webauthn/credentials",{token:t});return k(n)},async removeCredential(t,n){let r=await u(e);await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}`,{method:"DELETE",token:r,body:n?.password?{password:n.password}:void 0})},async renameCredential(t,n){let r=await u(e),o=await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}/rename`,{method:"PATCH",token:r,body:n});return k(o)},async setPrimaryCredential(t){let n=await u(e),r=await e.http.request(`/api/v1/users/me/webauthn/credentials/${encodeURIComponent(t)}/primary`,{method:"POST",token:n});return k(r)}}}function xe(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 fe(e){return{async status(){let t=await e.http.request("/api/v1/maintenance/status");return xe(t)}}}var $e=128,H=254;function y(e,t){if(typeof e!="string")return;let n=e.trim();if(!(!n||n.length>t))return n}function le(e){return{async request(t){let n=c({email:y(t.email,H),identifier:y(t.identifier,H),recovery_email:y(t.recoveryEmail,H),phone_number:y(t.phoneNumber,32),member_id:y(t.memberId,64),security_question:y(t.securityQuestion,256),security_answer:y(t.securityAnswer,256),redirect_uri:y(t.redirectUri,2048)}),r=await e.http.request("/oauth/password/reset/request",{method:"POST",body:n});return{ok:!!r.ok,message:String(r.message??"")}},async validate(t){let n=t.trim();if(!n)throw new i("invalid_request","token is required.");let r=await e.http.request(`/oauth/password/reset/validate?token=${encodeURIComponent(n)}`);return{ok:!!r.ok,valid:!!r.valid,expiresAt:typeof r.expires_at=="string"?r.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>$e)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 Me(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 me(e){return{async setup(t){let n=t.deviceName?.trim();if(!n||n.length>128)throw new i("invalid_request","deviceName is required.");let r=await f(e,"/api/v1/users/me/mfa/setup",{method:"POST",body:{device_name:n}});return{deviceId:String(r.device_id??""),secret:String(r.secret??""),qrCodeUri:String(r.qr_code_uri??""),backupCodes:Array.isArray(r.backup_codes)?r.backup_codes.filter(o=>typeof o=="string"):[],algorithm:String(r.algorithm??""),digits:typeof r.digits=="number"?r.digits:6,period:typeof r.period=="number"?r.period:30}},async verify(t){return f(e,"/api/v1/users/me/mfa/verify",{method:"POST",body:{device_id:t.deviceId,totp_code:t.totpCode}})},async devices(){let t=await f(e,"/api/v1/users/me/mfa/devices");return Array.isArray(t)?t.filter(n=>typeof n=="object"&&n!==null).map(Me):[]},async removeDevice(t){await h(e,`/api/v1/users/me/mfa/devices/${_(t,"deviceId")}`,{method:"DELETE"})},async regenerateBackupCodes(){let t=await f(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 h(e,"/api/v1/users/me/mfa/disable",{method:"POST",body:c({password:t?.password})})}}}var he="https://prod-auth.tktchurch.com",Le=new Set(["localhost","127.0.0.1","[::1]"]);function Ne(e){return Le.has(e.toLowerCase())}function J(e,t={}){let n=(e??he).trim();if(!n)return J(he,t);let o=(/^https?:\/\//i.test(n)?n:`https://${n}`).replace(/\/+$/,""),s;try{s=new URL(o)}catch{throw new i("invalid_request","baseUrl must be a valid absolute URL.")}if(s.protocol==="http:"&&!t.allowInsecureTransport&&!Ne(s.hostname))throw new i("invalid_request","baseUrl must use HTTPS. Set allowInsecureTransport=true only for trusted local development.");return o}function He(e,t){if(!e&&t<=0)return{cleanup:()=>{}};let n=new AbortController,r,o=()=>{n.abort(e?.reason)};return e&&(e.aborted?n.abort(e.reason):e.addEventListener("abort",o,{once:!0})),t>0&&(r=setTimeout(()=>{n.abort(new Error(`Request timed out after ${t}ms`))},t)),{signal:n.signal,cleanup:()=>{r&&clearTimeout(r),e&&e.removeEventListener("abort",o)}}}function Je(e,t){return/^https?:\/\//i.test(t)?t:`${e}${t.startsWith("/")?t:`/${t}`}`}function Be(e,t,n){let r=new Headers(e);return t&&new Headers(t).forEach((s,a)=>{r.set(a,s)}),n&&!r.has("Authorization")&&r.set("Authorization",`Bearer ${n}`),r}function ye(e){return{async request(t,n){let r=await this.requestRaw(t,n);if(!r.ok)throw await K(r);if(r.status===204)return;let o=await r.text();if(o)return JSON.parse(o)},async requestRaw(t,n){let r=Je(e.baseUrl,t),o=Be(e.defaultHeaders,n?.headers,n?.token),{signal:s,cleanup:a}=He(n?.signal,e.timeoutMs),d={method:n?.method??"GET",headers:o,signal:s,redirect:n?.redirect};typeof n?.body<"u"&&(n.body instanceof FormData?d.body=n.body:(o.has("Content-Type")||o.set("Content-Type","application/json"),d.body=JSON.stringify(n.body)));try{return await e.fetch(r,d)}catch(l){throw s?.aborted??!1?new i("timeout",`Request timed out: ${r}`,{details:l}):new i("network_error",`Network request failed: ${r}`,{details:l})}finally{a()}}}}var Fe="@tktchurch/auth/tokens",F=32768,_e=new Set(["accessToken","tokenType","expiresIn","refreshToken","scope","idToken","authorizationDetails"]),ke=new Set(["__proto__","constructor","prototype"]),Ve=/^[\w@./:-]{1,128}$/;function V(e){if(typeof e!="object"||e===null||Array.isArray(e))return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function ge(e){return typeof e=="string"&&e.length>0}function B(e){return typeof e=="string"&&e.length>0?e:void 0}function v(e){if(!V(e))throw new i("invalid_request","Token storage rejected a non-object token payload.");for(let s of Object.keys(e))if(!_e.has(s))throw new i("invalid_request",`Token storage rejected unknown field "${s}".`);if(!ge(e.accessToken))throw new i("invalid_request","Token storage requires a non-empty accessToken.");if(!ge(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=B(e.refreshToken);n&&(t.refreshToken=n);let r=B(e.scope);r&&(t.scope=r);let o=B(e.idToken);if(o&&(t.idToken=o),typeof e.authorizationDetails<"u"){if(!Array.isArray(e.authorizationDetails)||!e.authorizationDetails.every(s=>V(s)&&typeof s.type=="string"))throw new i("invalid_request","Token storage rejected malformed authorizationDetails.");t.authorizationDetails=e.authorizationDetails}return t}function Qe(e){if(!V(e))return null;for(let t of Object.keys(e))if(ke.has(t)||!_e.has(t))return null;try{return v(e)}catch{return null}}function We(e){return JSON.parse(e,(t,n)=>{if(ke.has(t))throw new SyntaxError("Forbidden JSON key in stored token payload.");return n})}function Ke(e){let t=e.trim();if(!t)throw new i("invalid_request","Token storage key must be a non-empty string.");if(!Ve.test(t))throw new i("invalid_request","Token storage key contains unsupported characters or exceeds 128 characters.");return t}function Ge(e){let t=v(e),n=JSON.stringify(t);if(n.length>F)throw new i("invalid_request",`Serialized token payload exceeds ${F} bytes.`);return n}var Q=class{state=null;get(){return this.state}set(t){if(!t){this.clear();return}this.state=v(t)}clear(){this.state=null}};function W(){return new Q}function Ye(){return typeof window<"u"&&typeof window.document<"u"}function Xe(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 be(e){if(!e.clientId?.trim())throw new i("invalid_request","clientId is required.");if(Ye()&&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:J(e.baseUrl,{allowInsecureTransport:e.allowInsecureTransport??!1}),fetch:Xe(e.fetch),storage:e.storage??W(),timeoutMs:e.timeoutMs??15e3,defaultHeaders:e.defaultHeaders??{},autoRefresh:e.autoRefresh??!0,allowClientSecretInBrowser:e.allowClientSecretInBrowser??!1,allowInsecureTransport:e.allowInsecureTransport??!1}}function Ze(e){let t=be(e),n=ye({baseUrl:t.baseUrl,fetch:t.fetch,timeoutMs:t.timeoutMs,defaultHeaders:t.defaultHeaders}),r=async()=>await t.storage.get(),o=async d=>{await t.storage.set(d)},s=async()=>{await t.storage.clear()},a={config:t,http:n,getTokens:r,setTokens:o,clearTokens:s};return{token:E(a),flow:de(a),oidc:ue(a),authorize:ae(a),user:ce(a),sessions:Y(a),webauthn:pe(a),passwordReset:le(a),mfa:me(a),maintenance:fe(a),oauth:oe(a),tokens:{get:r,set:o,clear:s}}}var et=/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;function tt(e,t="/"){if(!e)return t;let n=e;try{n=decodeURIComponent(e)}catch{return t}return n.startsWith("/")&&!n.startsWith("//")&&!n.startsWith("/\\")&&!et.test(n)&&!/^\/+[\\/]/.test(n)?n:t}export{i as AuthError,$ as DEFAULT_AUTHORIZE_SCOPE,Fe as DEFAULT_TOKEN_STORAGE_KEY,F as MAX_STORED_TOKEN_BYTES,R as MFARequiredAuthError,v as assertValidAuthTokens,Ze as createAuthClient,W as createMemoryTokenStorage,te as deriveCodeChallenge,ee as generateCodeVerifier,T as generateNonce,C as generatePkce,A as generateState,G as isAuthError,Se as isUnrecoverableAuthError,Qe as parseStoredAuthTokens,S as randomUrlSafeString,We as safeParseStoredJson,tt as sanitizePostAuthRedirect,Ge as serializeAuthTokens,x as timingSafeEqual,Ke 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 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};
|