@authrim/core 0.1.12 → 0.1.13
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/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/config.ts","../src/types/errors.ts","../src/client/discovery.ts","../src/events/emitter.ts","../src/auth/pkce.ts","../src/utils/base64url.ts","../src/auth/state.ts","../src/utils/jwt.ts","../src/utils/timing-safe.ts","../src/auth/authorization-code.ts","../src/auth/par.ts","../src/auth/device-flow.ts","../src/security/dpop.ts","../src/types/token.ts","../src/token/manager.ts","../src/token/introspection.ts","../src/token/revocation.ts","../src/session/logout.ts","../src/session/token-api.ts","../src/session/manager.ts","../src/client/index.ts","../src/auth/silent-auth.ts","../src/auth/client-auth.ts","../src/auth/client-credentials.ts","../src/security/jar.ts","../src/security/jarm.ts","../src/token/auto-refresh.ts","../src/session/session-state.ts","../src/session/front-channel-logout.ts","../src/debug/timeline.ts","../src/debug/logger.ts","../src/debug/diagnostic-logger.ts","../src/utils/hash.ts","../src/utils/cancellation.ts","../src/utils/retry.ts"],"names":["resolveConfig","config","AuthrimError","_AuthrimError","code","message","options","error","getErrorMeta","ERROR_META_MAP","classifyError","meta","mapUserActionToRemediation","remediation","userAction","isRetryableError","classification","emitClassifiedError","emitter","severity","timestamp","source","payload","normalizeIssuer","issuer","_DiscoveryClient","normalizedIssuer","cached","discoveryUrl","doc","response","docIssuer","DiscoveryClient","EventEmitter","event","handler","onceHandler","data","handlers","authrimError","PKCEHelper","crypto","codeVerifier","codeChallenge","verifier","base64urlEncode","base64","len","i","byte1","byte2","byte3","triplet","BASE64_CHARS","base64urlDecode","str","paddingLen","outputLen","output","outputIndex","BASE64_LOOKUP","byte4","stringToBase64url","encoder","base64urlToString","base64url","STORAGE_KEYS","issuerHash","clientIdHash","state","_StateManager","storage","ttlSeconds","validatedReturnTo","stateBytes","nonceBytes","operationIdBytes","nonce","operationId","now","authState","key","returnTo","globalWindow","currentOrigin","e","parsed","stored","prefix","all","value","intervalMs","count","StateManager","decodeJwt","jwt","parts","headerB64","payloadB64","signature","header","decodeIdToken","idToken","isJwtExpired","skewSeconds","getIdTokenNonce","timingSafeEqual","a","b","aBytes","bBytes","aLen","bLen","maxLen","result","aByte","bByte","AuthorizationCodeFlow","http","clientId","logger","discovery","pkce","endpoint","params","scope","protectedParams","callbackUrl","searchParams","errorDescription","tokenEndpoint","body","errorData","tokenResponse","idTokenNonce","expiresAt","tokenSet","PARClient","request","parEndpoint","headers","parResponse","requestUri","DEFAULT_INTERVAL","DeviceFlowClient","errorCode","currentInterval","ms","signal","resolve","reject","timeout","DPoPManager","existing","method","uri","url","htu","claims","claimsB64","signingInput","signatureB64","accessToken","hash","TOKEN_TYPE_URIS","_TokenManager","tokens","expiresAtMs","warningTime","jitter","delay","expiresIn","isLeader","refreshToken","reason","attempt","willRetry","newTokens","subjectTokenType","type","TokenManager","TokenIntrospector","token","TokenRevoker","LogoutHandler","storedIdToken","storedTokens","revocationResult","endSessionEndpoint","tokenKey","idTokenKey","TokenApiClient","userinfoEndpoint","SessionManager","hashForKey","length","AuthrimClient","hashLength","tokenApiClient","pkcePair","manager","createAuthrimClient","client","INTERACTIVE_LOGIN_REQUIRED_ERRORS","SilentAuthHandler","responseUrl","buildClientAuthentication","credentials","bodyParams","encodedCredentials","generateJti","assertion","_exhaustive","ClientCredentialsClient","authHeaders","authBodyParams","JARBuilder","lifetime","protectedClaims","isJarRequired","JARMValidator","clockSkew","_AutoRefreshScheduler","tokenManager","AutoRefreshScheduler","SessionStateCalculator","salt","saltBytes","hashInput","hashBytes","sessionState","calculated","dotIndex","base64urlRegex","FrontChannelLogoutUrlBuilder","resultParams","urlObj","iss","sid","expected","SENSITIVE_KEYS","SENSITIVE_URL_PARAMS","EventTimeline","redactLevelToUse","redactedData","entry","level","obj","lowerKey","capitalizedKey","item","sensitive","param","hashParams","hashModified","createConsoleLogger","includeTimestamps","consoleMethod","consoleObj","noopLogger","createDebugLogger","DebugContext","id","DiagnosticLogger","c","r","createDiagnosticLogger","calculateDsHash","deviceSecret","leftHalf","withAbortSignal","promise","cancelledError","onAbort","createCancellableOperation","fn","controller","isCancellationError","raceWithCancellation","operations","op","DEFAULT_RETRY_OPTIONS","calculateBackoffDelay","baseDelayMs","maxDelayMs","exponentialDelay","cappedDelay","jitterRange","jitterValue","sleep","withRetry","opts","maxRetries","shouldRetry","onRetry","lastError","canRetry","delayMs","createRetryFunction","defaultOptions","parseRetryAfterHeader","retryAfter","seconds","date"],"mappings":"aAqJO,SAASA,EAAcC,CAAAA,CAA6C,CACzE,OAAO,CACL,GAAGA,CAAAA,CACH,MAAA,CAAQA,CAAAA,CAAO,MAAA,EAAU,CAAC,QAAA,CAAU,SAAS,EAC7C,UAAA,CAAYA,CAAAA,CAAO,YAAc,KAAA,CACjC,mBAAA,CAAqBA,CAAAA,CAAO,mBAAA,EAAuB,KAAO,GAAA,CAC1D,kBAAA,CAAoBA,EAAO,kBAAA,EAAsB,EAAA,CACjD,gBAAiBA,CAAAA,CAAO,eAAA,EAAmB,GAAA,CAC3C,WAAA,CAAa,CACX,UAAA,CAAYA,CAAAA,CAAO,aAAa,UAAA,EAAc,EAChD,CACF,CACF,CCgBO,IAAMC,CAAAA,CAAN,MAAMC,CAAAA,SAAqB,KAAM,CAatC,WAAA,CAAYC,CAAAA,CAAwBC,EAAiBC,CAAAA,CAA+B,CAClF,KAAA,CAAMD,CAAO,EACb,IAAA,CAAK,IAAA,CAAO,eACZ,IAAA,CAAK,IAAA,CAAOD,EACZ,IAAA,CAAK,OAAA,CAAUE,CAAAA,EAAS,OAAA,CACxB,KAAK,QAAA,CAAWA,CAAAA,EAAS,SACzB,IAAA,CAAK,KAAA,CAAQA,GAAS,MACxB,CAKA,OAAO,cAAA,CAAeC,EAIL,CAef,IAAMH,EAda,CACjB,iBAAA,CACA,sBACA,eAAA,CACA,2BAAA,CACA,eAAA,CACA,cAAA,CACA,0BACA,eAAA,CACA,eACF,CAAA,CAI0C,QAAA,CAASG,EAAM,KAAuB,CAAA,CAC3EA,CAAAA,CAAM,KAAA,CACP,kBAEJ,OAAO,IAAIJ,EAAaC,CAAAA,CAAMG,CAAAA,CAAM,mBAAqBA,CAAAA,CAAM,KAAA,CAAO,CACpE,QAAA,CAAUA,EAAM,SAAA,CAChB,OAAA,CAAS,CAAE,aAAA,CAAeA,CAAAA,CAAM,KAAM,CACxC,CAAC,CACH,CAKA,aAAuB,CACrB,OAAO,KAAK,IAAA,GAAS,eAAA,EAAmB,KAAK,IAAA,GAAS,eACxD,CAKA,IAAI,MAAyB,CAC3B,OAAOC,GAAa,IAAA,CAAK,IAAI,CAC/B,CACF,CAAA,CAKMC,EAAAA,CAA6D,CAEjE,gBAAiB,CACf,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,oBAAqB,CACnB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,cAAe,CACb,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,0BAA2B,CACzB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,EACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,EACA,YAAA,CAAc,CACZ,UAAW,IAAA,CACX,SAAA,CAAW,KACX,YAAA,CAAc,GAAA,CACd,UAAA,CAAY,CAAA,CACZ,WAAY,OAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,uBAAA,CAAyB,CACvB,SAAA,CAAW,IAAA,CACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,OAAA,CACZ,SAAU,SACZ,CAAA,CACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CAGA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,cAAA,CAAgB,CACd,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,gBAAA,CAAkB,CAChB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,eAAA,CAAiB,CACf,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,oBAAA,CAAsB,CACpB,UAAW,IAAA,CACX,SAAA,CAAW,KACX,YAAA,CAAc,GAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,OAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,aAAA,CAAe,CACb,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,GAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,eAAA,CACZ,QAAA,CAAU,OACZ,EACA,aAAA,CAAe,CACb,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,CAAA,CACZ,WAAY,OAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,gBAAiB,CACf,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,EACA,kBAAA,CAAoB,CAClB,UAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,kBACZ,QAAA,CAAU,OACZ,EACA,mBAAA,CAAqB,CACnB,UAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,kBACZ,QAAA,CAAU,OACZ,EACA,aAAA,CAAe,CACb,UAAW,IAAA,CACX,SAAA,CAAW,IAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,CAAA,CACZ,WAAY,OAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,iBAAA,CAAmB,CACjB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CAGA,SAAA,CAAW,CACT,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,WAAA,CAAa,CACX,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,YAAA,CAAc,CAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,oBAAA,CAAsB,CACpB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,YAAA,CAAc,CAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CAGA,YAAa,CACX,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,aAAc,CACZ,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,cAAe,CACb,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,EAGA,eAAA,CAAiB,CACf,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,OACZ,QAAA,CAAU,OACZ,EACA,YAAA,CAAc,CACZ,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,CAAA,CACZ,WAAY,OAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CAGA,qBAAsB,CACpB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,MAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,eAAgB,CACd,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,EAGA,mBAAA,CAAqB,CACnB,UAAW,IAAA,CACX,SAAA,CAAW,IAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,CAAA,CACZ,WAAY,OAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,gBAAA,CAAkB,CAChB,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,OAAA,CACZ,QAAA,CAAU,OACZ,EACA,yBAAA,CAA2B,CACzB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,MAAA,CACZ,QAAA,CAAU,SACZ,EACA,sBAAA,CAAwB,CACtB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,MAAA,CACZ,QAAA,CAAU,SACZ,EAGA,cAAA,CAAgB,CACd,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,EACA,oBAAA,CAAsB,CACpB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,EACA,gBAAA,CAAkB,CAChB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,EACA,0BAAA,CAA4B,CAC1B,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,EAGA,aAAA,CAAe,CACb,UAAW,IAAA,CACX,SAAA,CAAW,KACX,YAAA,CAAc,GAAA,CACd,UAAA,CAAY,CAAA,CACZ,WAAY,OAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,cAAA,CAAgB,CACd,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,cAAe,CACb,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,MAAA,CACZ,SAAU,SACZ,CAAA,CACA,aAAc,CACZ,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,iBAAkB,CAChB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,iBAAA,CACZ,SAAU,OACZ,CAAA,CACA,iBAAkB,CAChB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CAGA,kBAAmB,CACjB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,4BAA6B,CAC3B,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,KACX,YAAA,CAAc,GAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,CAAA,CACA,qBAAA,CAAuB,CACrB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,OACZ,QAAA,CAAU,SACZ,CAAA,CACA,iBAAA,CAAmB,CACjB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,2BAA4B,CAC1B,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,mBAAoB,CAClB,SAAA,CAAW,MACX,SAAA,CAAW,IAAA,CACX,aAAc,CAAA,CACd,UAAA,CAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,SACZ,EACA,kBAAA,CAAoB,CAClB,UAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,iBACZ,QAAA,CAAU,SACZ,EACA,4BAAA,CAA8B,CAC5B,UAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,OAAA,CACZ,SAAU,OACZ,CAAA,CACA,kBAAmB,CACjB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,kBAAmB,CACjB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,kBAAmB,CACjB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,EACA,iBAAA,CAAmB,CACjB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,iBACZ,QAAA,CAAU,SACZ,EACA,aAAA,CAAe,CACb,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,iBACZ,QAAA,CAAU,OACZ,EACA,kBAAA,CAAoB,CAClB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,kBACZ,QAAA,CAAU,OACZ,EACA,YAAA,CAAc,CACZ,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,iBACZ,QAAA,CAAU,SACZ,EACA,2BAAA,CAA6B,CAC3B,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,OACZ,QAAA,CAAU,SACZ,EACA,uBAAA,CAAyB,CACvB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,iBACZ,QAAA,CAAU,SACZ,EACA,YAAA,CAAc,CACZ,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,CAAA,CACZ,WAAY,OAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CAGA,oBAAqB,CACnB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,MAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CAGA,aAAc,CACZ,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,MAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,gBAAiB,CACf,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,UAAW,CACT,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,EACA,uBAAA,CAAyB,CACvB,UAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,iBACZ,QAAA,CAAU,SACZ,EAGA,gCAAA,CAAkC,CAChC,UAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,kBACZ,QAAA,CAAU,OACZ,EACA,0BAAA,CAA4B,CAC1B,UAAW,IAAA,CACX,SAAA,CAAW,IAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,CAAA,CACZ,WAAY,OAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,4BAAA,CAA8B,CAC5B,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,YAAA,CAAc,GAAA,CACd,WAAY,EAAA,CACZ,UAAA,CAAY,MAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,gBAAA,CAAkB,CAChB,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,GAAA,CACd,UAAA,CAAY,GACZ,UAAA,CAAY,MAAA,CACZ,SAAU,SACZ,CAAA,CACA,6BAA8B,CAC5B,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,qBAAsB,CACpB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CAGA,yBAA0B,CACxB,SAAA,CAAW,IAAA,CACX,SAAA,CAAW,KACX,YAAA,CAAc,GAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,CAAA,CACA,6BAAA,CAA+B,CAC7B,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,kBACZ,QAAA,CAAU,OACZ,CAAA,CACA,oBAAA,CAAsB,CACpB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,OACZ,QAAA,CAAU,OACZ,CAAA,CAGA,yBAAA,CAA2B,CACzB,SAAA,CAAW,IAAA,CACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,EACA,2BAAA,CAA6B,CAC3B,UAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,OACZ,QAAA,CAAU,OACZ,EACA,mBAAA,CAAqB,CACnB,UAAW,IAAA,CACX,SAAA,CAAW,IAAA,CACX,YAAA,CAAc,EACd,UAAA,CAAY,CAAA,CACZ,WAAY,MAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CAGA,iBAAA,CAAmB,CACjB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,YAAA,CAAc,CACZ,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,MAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CAGA,qBAAA,CAAuB,CACrB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,sBAAA,CAAwB,CACtB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CAGA,mBAAA,CAAqB,CACnB,SAAA,CAAW,MACX,SAAA,CAAW,IAAA,CACX,YAAA,CAAc,CAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,OAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CAGA,iBAAA,CAAmB,CACjB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,MAAA,CACZ,QAAA,CAAU,OACZ,CACF,EAKO,SAASD,EAAAA,CAAaJ,CAAAA,CAA0C,CACrE,OAAOK,EAAAA,CAAeL,CAAI,CAC5B,CAmBO,SAASM,CAAAA,CAAcH,EAA0C,CACtE,IAAMI,EAAOJ,CAAAA,CAAM,IAAA,CAGnB,GAAI,CAACI,EAAK,SAAA,EAAaA,CAAAA,CAAK,aAAe,iBAAA,CACzC,OAAO,CAAE,QAAA,CAAU,OAAA,CAAS,WAAA,CAAa,iBAAkB,EAI7D,GAAIA,CAAAA,CAAK,WAAa,OAAA,CACpB,OAAO,CAAE,QAAA,CAAU,OAAA,CAAS,WAAA,CAAaC,EAAAA,CAA2BD,EAAK,UAAU,CAAE,EAIvF,IAAIE,CAAAA,CAAuC,OAE3C,OAAIF,CAAAA,CAAK,SAAA,CACPE,CAAAA,CAAc,QACLF,CAAAA,CAAK,UAAA,GAAe,iBAC7BE,CAAAA,CAAc,gBAAA,CACLN,EAAM,IAAA,GAAS,eAAA,CACxBM,CAAAA,CAAc,aAAA,CACLF,EAAK,UAAA,GAAe,iBAAA,GAC7BE,EAAc,iBAAA,CAAA,CAGT,CAAE,SAAU,aAAA,CAAe,WAAA,CAAAA,CAAY,CAChD,CAKA,SAASD,EAAAA,CAA2BE,EAA6D,CAC/F,OAAQA,GACN,KAAK,OAAA,CACL,KAAK,gBACH,OAAO,OAAA,CACT,KAAK,gBAAA,CACH,OAAO,iBACT,KAAK,iBAAA,CACH,OAAO,iBAAA,CAET,QACE,OAAO,MACX,CACF,CAKO,SAASC,EAAiBR,CAAAA,CAA8B,CAC7D,IAAMS,CAAAA,CAAiBN,EAAcH,CAAK,CAAA,CAC1C,OAAOS,CAAAA,CAAe,QAAA,GAAa,eAAiBA,CAAAA,CAAe,WAAA,GAAgB,OACrF,CA6DO,SAASC,CAAAA,CACdC,CAAAA,CACAX,EACAD,CAAAA,CACM,CACN,GAAM,CAAE,QAAA,CAAAa,CAAAA,CAAU,WAAA,CAAAN,CAAY,CAAA,CAAIH,CAAAA,CAAcH,CAAK,CAAA,CAC/Ca,CAAAA,CAAY,KAAK,GAAA,EAAI,CACrBC,CAAAA,CAASf,CAAAA,CAAQ,QAAU,MAAA,CAG3BgB,CAAAA,CAAU,CACd,KAAA,CAAAf,CAAAA,CACA,SAAAY,CAAAA,CACA,WAAA,CAAAN,CAAAA,CACA,OAAA,CAASP,EAAQ,OAAA,CACjB,SAAA,CAAAc,CAAAA,CACA,MAAA,CAAAC,EACA,WAAA,CAAaf,CAAAA,CAAQ,WACvB,CAAA,CAGAY,EAAQ,IAAA,CAAK,OAAA,CAASI,CAAO,CAAA,CAGzBH,CAAAA,GAAa,cACfD,CAAAA,CAAQ,IAAA,CAAK,mBAAA,CAAqB,CAAE,GAAGI,CAAAA,CAAS,QAAA,CAAU,aAAuB,CAAC,CAAA,CAElFJ,EAAQ,IAAA,CAAK,aAAA,CAAe,CAAE,GAAGI,EAAS,QAAA,CAAU,OAAiB,CAAC,EAE1E,CCx/BO,SAASC,CAAAA,CAAgBC,CAAAA,CAAwB,CACtD,OAAOA,EAAO,OAAA,CAAQ,MAAA,CAAQ,EAAE,CAClC,CAKO,IAAMC,CAAAA,CAAN,MAAMA,CAAgB,CAQ3B,YAAYnB,CAAAA,CAAiC,CAL7C,KAAiB,KAAA,CAAsC,IAAI,IAMzD,IAAA,CAAK,IAAA,CAAOA,CAAAA,CAAQ,IAAA,CACpB,KAAK,UAAA,CAAaA,CAAAA,CAAQ,YAAcmB,CAAAA,CAAgB,qBAC1D,CASA,MAAM,QAAA,CAASD,CAAAA,CAAgD,CAC7D,IAAME,CAAAA,CAAmBH,CAAAA,CAAgBC,CAAM,CAAA,CACzCG,CAAAA,CAAS,KAAK,KAAA,CAAM,GAAA,CAAID,CAAgB,CAAA,CAG9C,GAAIC,CAAAA,EAAU,CAAC,IAAA,CAAK,SAAA,CAAUA,CAAM,CAAA,CAClC,OAAOA,CAAAA,CAAO,GAAA,CAIhB,IAAMC,CAAAA,CAAe,CAAA,EAAGF,CAAgB,CAAA,iCAAA,CAAA,CAEpCG,CAAAA,CACJ,GAAI,CACF,IAAMC,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,KAAA,CAA6BF,CAAY,CAAA,CAC1E,GAAI,CAACE,CAAAA,CAAS,EAAA,CACZ,MAAM,IAAI5B,EAAa,iBAAA,CAAmB,CAAA,0BAAA,EAA6B4B,EAAS,MAAM,CAAA,CAAA,CAAI,CACxF,OAAA,CAAS,CAAE,MAAA,CAAQA,CAAAA,CAAS,OAAQ,UAAA,CAAYA,CAAAA,CAAS,UAAW,CACtE,CAAC,EAEHD,CAAAA,CAAMC,CAAAA,CAAS,KACjB,CAAA,MAASvB,EAAO,CACd,MAAIA,aAAiBL,CAAAA,CACbK,CAAAA,CAEF,IAAIL,CAAAA,CAAa,iBAAA,CAAmB,oCAAA,CAAsC,CAC9E,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAAA,CACxC,OAAA,CAAS,CAAE,GAAA,CAAKqB,CAAa,CAC/B,CAAC,CACH,CAGA,IAAMG,EAAYR,CAAAA,CAAgBM,CAAAA,CAAI,MAAM,CAAA,CAC5C,GAAIE,CAAAA,GAAcL,CAAAA,CAChB,MAAM,IAAIxB,CAAAA,CACR,oBAAA,CACA,CAAA,iDAAA,EAAoDwB,CAAgB,CAAA,QAAA,EAAWK,CAAS,CAAA,CAAA,CAAA,CACxF,CACE,QAAS,CACP,QAAA,CAAUL,EACV,MAAA,CAAQK,CACV,CACF,CACF,CAAA,CAIF,OAAA,IAAA,CAAK,KAAA,CAAM,IAAIL,CAAAA,CAAkB,CAC/B,IAAAG,CAAAA,CACA,SAAA,CAAW,KAAK,GAAA,EAClB,CAAC,CAAA,CAEMA,CACT,CAKQ,SAAA,CAAUF,EAAkC,CAClD,OAAO,KAAK,GAAA,EAAI,CAAIA,CAAAA,CAAO,SAAA,CAAY,KAAK,UAC9C,CAKA,YAAmB,CACjB,IAAA,CAAK,MAAM,KAAA,GACb,CAOA,WAAA,CAAYH,EAAsB,CAChC,IAAA,CAAK,MAAM,MAAA,CAAOD,CAAAA,CAAgBC,CAAM,CAAC,EAC3C,CACF,CAAA,CAjGaC,EAMa,oBAAA,CAAuB,IAAA,CAAO,IANjD,IAAMO,CAAAA,CAANP,EChCA,IAAMQ,CAAAA,CAAN,KAAmB,CAAnB,cACL,IAAA,CAAQ,SAAA,CAA+E,IAAI,IAAA,CAS3F,EAAA,CAA+BC,EAAUC,CAAAA,CAA6C,CACpF,OAAK,IAAA,CAAK,UAAU,GAAA,CAAID,CAAK,GAC3B,IAAA,CAAK,SAAA,CAAU,IAAIA,CAAAA,CAAO,IAAI,GAAK,CAAA,CAErC,KAAK,SAAA,CAAU,GAAA,CAAIA,CAAK,CAAA,CAAG,GAAA,CAAIC,CAAgD,CAAA,CAGxE,IAAM,CACX,IAAA,CAAK,IAAID,CAAAA,CAAOC,CAAO,EACzB,CACF,CASA,KAAiCD,CAAAA,CAAUC,CAAAA,CAA6C,CACtF,IAAMC,GAAgBC,CAAAA,EAA2B,CAC/C,KAAK,GAAA,CAAIH,CAAAA,CAAOE,CAAW,CAAA,CAC3BD,CAAAA,CAAQE,CAAI,EACd,GAEA,OAAO,IAAA,CAAK,GAAGH,CAAAA,CAAOE,CAAW,CACnC,CAQA,GAAA,CAAgCF,CAAAA,CAAUC,CAAAA,CAAuC,CAC/E,IAAMG,CAAAA,CAAW,KAAK,SAAA,CAAU,GAAA,CAAIJ,CAAK,CAAA,CACrCI,CAAAA,GACFA,CAAAA,CAAS,MAAA,CAAOH,CAAgD,CAAA,CAC5DG,CAAAA,CAAS,OAAS,CAAA,EACpB,IAAA,CAAK,UAAU,MAAA,CAAOJ,CAAK,CAAA,EAGjC,CAQA,KAAiCA,CAAAA,CAAUG,CAAAA,CAA8B,CACvE,IAAMC,CAAAA,CAAW,KAAK,SAAA,CAAU,GAAA,CAAIJ,CAAK,CAAA,CACzC,GAAII,CAAAA,CACF,IAAA,IAAWH,CAAAA,IAAWG,CAAAA,CACpB,GAAI,CACFH,CAAAA,CAAQE,CAAI,EACd,OAAS9B,CAAAA,CAAO,CAId,GAAI2B,CAAAA,GAAU,OAAA,CAAS,CACrB,IAAMK,CAAAA,CACJhC,CAAAA,YAAiBL,CAAAA,CACbK,EACA,IAAIL,CAAAA,CAAa,sBAAuB,8BAAA,CAAgC,CACtE,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CAAA,CACP,IAAA,CAAK,KAAK,OAAA,CAAS,CACjB,MAAOgC,CAAAA,CACP,OAAA,CAAS,CAAA,4BAAA,EAA+BL,CAAK,GAC/C,CAAC,EACH,CAGF,CAGN,CAOA,mBAAmBA,CAAAA,CAAgC,CAC7CA,CAAAA,CACF,IAAA,CAAK,UAAU,MAAA,CAAOA,CAAK,EAE3B,IAAA,CAAK,SAAA,CAAU,QAEnB,CAQA,aAAA,CAAcA,CAAAA,CAAiC,CAC7C,OAAO,IAAA,CAAK,UAAU,GAAA,CAAIA,CAAK,GAAG,IAAA,EAAQ,CAC5C,CACF,MC9FaM,CAAAA,CAAN,KAAiB,CACtB,WAAA,CAA6BC,CAAAA,CAAwB,CAAxB,IAAA,CAAA,MAAA,CAAAA,EAAyB,CAStD,MAAM,cAAkC,CACtC,IAAMC,CAAAA,CAAe,MAAM,KAAK,MAAA,CAAO,oBAAA,EAAqB,CACtDC,CAAAA,CAAgB,MAAM,IAAA,CAAK,MAAA,CAAO,sBAAsBD,CAAY,CAAA,CAE1E,OAAO,CACL,YAAA,CAAAA,CAAAA,CACA,aAAA,CAAAC,EACA,mBAAA,CAAqB,MACvB,CACF,CAOA,MAAM,sBAAwC,CAC5C,OAAO,IAAA,CAAK,MAAA,CAAO,sBACrB,CAQA,MAAM,qBAAA,CAAsBC,CAAAA,CAAmC,CAC7D,OAAO,IAAA,CAAK,MAAA,CAAO,qBAAA,CAAsBA,CAAQ,CACnD,CACF,ECxDO,SAASC,CAAAA,CAAgBR,EAA0B,CAExD,IAAIS,CAAAA,CAAS,EAAA,CAGPC,EAAMV,CAAAA,CAAK,MAAA,CACjB,QAASW,CAAAA,CAAI,CAAA,CAAGA,EAAID,CAAAA,CAAKC,CAAAA,EAAK,CAAA,CAAG,CAC/B,IAAMC,CAAAA,CAAQZ,CAAAA,CAAKW,CAAC,CAAA,CACdE,CAAAA,CAAQF,EAAI,CAAA,CAAID,CAAAA,CAAMV,CAAAA,CAAKW,CAAAA,CAAI,CAAC,CAAA,CAAI,CAAA,CACpCG,EAAQH,CAAAA,CAAI,CAAA,CAAID,EAAMV,CAAAA,CAAKW,CAAAA,CAAI,CAAC,CAAA,CAAI,EAEpCI,CAAAA,CAAWH,CAAAA,EAAS,EAAA,CAAOC,CAAAA,EAAS,EAAKC,CAAAA,CAE/CL,CAAAA,EAAUO,CAAAA,CAAcD,CAAAA,EAAW,GAAM,EAAI,CAAA,CAC7CN,GAAUO,CAAAA,CAAcD,CAAAA,EAAW,GAAM,EAAI,CAAA,CAC7CN,CAAAA,EAAUE,CAAAA,CAAI,EAAID,CAAAA,CAAMM,CAAAA,CAAcD,GAAW,CAAA,CAAK,EAAI,EAAI,EAAA,CAC9DN,CAAAA,EAAUE,CAAAA,CAAI,CAAA,CAAID,EAAMM,CAAAA,CAAaD,CAAAA,CAAU,EAAI,CAAA,CAAI,GACzD,CAIA,OAAON,CAAAA,CAAO,OAAA,CAAQ,KAAA,CAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAO,GAAG,CAAA,CAAE,QAAQ,KAAA,CAAO,EAAE,CACzE,CASO,SAASQ,EAAAA,CAAgBC,CAAAA,CAAyB,CAGvD,GAAI,CAAC,mBAAmB,IAAA,CAAKA,CAAG,CAAA,CAC9B,MAAM,IAAI,KAAA,CAAM,uDAAuD,EAIzE,IAAIT,CAAAA,CAASS,EAAI,OAAA,CAAQ,IAAA,CAAM,GAAG,CAAA,CAAE,QAAQ,IAAA,CAAM,GAAG,EAGrD,KAAOT,CAAAA,CAAO,OAAS,CAAA,EACrBA,CAAAA,EAAU,GAAA,CAIZ,IAAMC,EAAMD,CAAAA,CAAO,MAAA,CACbU,EAAaV,CAAAA,CAAO,QAAA,CAAS,IAAI,CAAA,CAAI,CAAA,CAAIA,CAAAA,CAAO,QAAA,CAAS,GAAG,CAAA,CAAI,CAAA,CAAI,EACpEW,CAAAA,CAAaV,CAAAA,CAAM,EAAK,CAAA,CAAIS,CAAAA,CAC5BE,CAAAA,CAAS,IAAI,WAAWD,CAAS,CAAA,CAEnCE,EAAc,CAAA,CAClB,IAAA,IAASX,EAAI,CAAA,CAAGA,CAAAA,CAAID,CAAAA,CAAKC,CAAAA,EAAK,EAAG,CAC/B,IAAMC,EAAQW,CAAAA,CAAcd,CAAAA,CAAO,WAAWE,CAAC,CAAC,CAAA,CAC1CE,CAAAA,CAAQU,EAAcd,CAAAA,CAAO,UAAA,CAAWE,EAAI,CAAC,CAAC,EAC9CG,CAAAA,CAAQS,CAAAA,CAAcd,CAAAA,CAAO,UAAA,CAAWE,EAAI,CAAC,CAAC,EAC9Ca,CAAAA,CAAQD,CAAAA,CAAcd,EAAO,UAAA,CAAWE,CAAAA,CAAI,CAAC,CAAC,EAE9CI,CAAAA,CAAWH,CAAAA,EAAS,GAAOC,CAAAA,EAAS,EAAA,CAAOC,GAAS,CAAA,CAAKU,CAAAA,CAE3DF,CAAAA,CAAcF,CAAAA,GAAWC,EAAOC,CAAAA,EAAa,CAAA,CAAKP,GAAW,EAAA,CAAM,GAAA,CAAA,CACnEO,EAAcF,CAAAA,GAAWC,CAAAA,CAAOC,CAAAA,EAAa,CAAA,CAAKP,GAAW,CAAA,CAAK,GAAA,CAAA,CAClEO,CAAAA,CAAcF,CAAAA,GAAWC,EAAOC,CAAAA,EAAa,CAAA,CAAIP,CAAAA,CAAU,GAAA,EACjE,CAEA,OAAOM,CACT,CAQO,SAASI,CAAAA,CAAkBP,EAAqB,CACrD,IAAMQ,CAAAA,CAAU,IAAI,YACpB,OAAOlB,CAAAA,CAAgBkB,EAAQ,MAAA,CAAOR,CAAG,CAAC,CAC5C,CAQO,SAASS,CAAAA,CAAkBC,EAA2B,CAE3D,OADgB,IAAI,WAAA,EAAY,CACjB,OAAOX,EAAAA,CAAgBW,CAAS,CAAC,CAClD,CAGA,IAAMZ,CAAAA,CAAe,mEAGfO,CAAAA,CAAgB,IAAI,WAAW,GAAG,CAAA,CACxC,IAAA,IAASZ,CAAAA,CAAI,EAAGA,CAAAA,CAAIK,CAAAA,CAAa,OAAQL,CAAAA,EAAAA,CACvCY,CAAAA,CAAcP,EAAa,UAAA,CAAWL,CAAC,CAAC,CAAA,CAAIA,EC9BvC,IAAMkB,CAAAA,CAAe,CAI1B,SAAA,CAAW,CAACC,EAAoBC,CAAAA,CAAsBC,CAAAA,GACpD,CAAA,QAAA,EAAWF,CAAU,IAAIC,CAAY,CAAA,MAAA,EAASC,CAAK,CAAA,CAAA,CAKrD,MAAA,CAAQ,CAACF,CAAAA,CAAoBC,CAAAA,GAC3B,CAAA,QAAA,EAAWD,CAAU,IAAIC,CAAY,CAAA,OAAA,CAAA,CAKvC,OAAA,CAAS,CAACD,EAAoBC,CAAAA,GAC5B,CAAA,QAAA,EAAWD,CAAU,CAAA,CAAA,EAAIC,CAAY,CAAA,SAAA,CAAA,CAKvC,eAAA,CAAiB,CAACD,CAAAA,CAAoBC,CAAAA,GACpC,WAAWD,CAAU,CAAA,CAAA,EAAIC,CAAY,CAAA,MAAA,CACzC,EAKaE,CAAAA,CAAN,MAAMA,CAAa,CAgBxB,WAAA,CACmB7B,EACA8B,CAAAA,CACAJ,CAAAA,CACAC,CAAAA,CACjB,CAJiB,YAAA3B,CAAAA,CACA,IAAA,CAAA,OAAA,CAAA8B,EACA,IAAA,CAAA,UAAA,CAAAJ,CAAAA,CACA,kBAAAC,CAAAA,CANnB,IAAA,CAAQ,eAAA,CAAyD,KAO9D,CAUH,MAAM,iBAAA,CAAkB9D,EAAuD,CAC7E,IAAMkE,EAAalE,CAAAA,CAAQ,UAAA,EAAcgE,CAAAA,CAAa,mBAAA,CAGlDG,EACAnE,CAAAA,CAAQ,QAAA,GACVmE,EAAoB,IAAA,CAAK,gBAAA,CACvBnE,EAAQ,QAAA,CACRA,CAAAA,CAAQ,eAAA,EAAmB,CAAE,OAAQ,eAAgB,CACvD,GAIF,IAAMoE,CAAAA,CAAa,MAAM,IAAA,CAAK,MAAA,CAAO,WAAA,CAAYJ,CAAAA,CAAa,aAAa,CAAA,CACrEK,CAAAA,CAAa,MAAM,IAAA,CAAK,MAAA,CAAO,YAAYL,CAAAA,CAAa,aAAa,CAAA,CACrEM,CAAAA,CAAmB,MAAM,IAAA,CAAK,MAAA,CAAO,WAAA,CAAYN,CAAAA,CAAa,kBAAkB,CAAA,CAEhFD,CAAAA,CAAQxB,CAAAA,CAAgB6B,CAAU,EAClCG,CAAAA,CAAQhC,CAAAA,CAAgB8B,CAAU,CAAA,CAClCG,CAAAA,CAAcjC,EAAgB+B,CAAgB,CAAA,CAE9CG,CAAAA,CAAM,IAAA,CAAK,KAAI,CACfC,CAAAA,CAAuB,CAC3B,KAAA,CAAAX,CAAAA,CACA,MAAAQ,CAAAA,CACA,YAAA,CAAcvE,CAAAA,CAAQ,YAAA,CACtB,YAAaA,CAAAA,CAAQ,WAAA,CACrB,MAAOA,CAAAA,CAAQ,KAAA,CACf,UAAWyE,CAAAA,CACX,SAAA,CAAWA,CAAAA,CAAMP,CAAAA,CAAa,IAC9B,QAAA,CAAUC,CAAAA,CACV,YAAAK,CACF,CAAA,CAGMG,EAAMf,CAAAA,CAAa,SAAA,CAAU,IAAA,CAAK,UAAA,CAAY,KAAK,YAAA,CAAcG,CAAK,EAC5E,OAAA,MAAM,IAAA,CAAK,QAAQ,GAAA,CAAIY,CAAAA,CAAK,IAAA,CAAK,SAAA,CAAUD,CAAS,CAAC,CAAA,CAE9CA,CACT,CAUQ,gBAAA,CAAiBE,EAAkB5E,CAAAA,CAAkC,CAC3E,OAAQA,CAAAA,CAAQ,QACd,KAAK,gBAGH,GAAI4E,CAAAA,CAAS,WAAW,GAAG,CAAA,EAAK,CAACA,CAAAA,CAAS,WAAW,IAAI,CAAA,EAEnD,CAACA,CAAAA,CAAS,QAAA,CAAS,GAAG,CAAA,CACxB,OAAOA,CAAAA,CAGX,MAAM,IAAIhF,CAAAA,CACR,mBAAA,CACA,qDACF,CAAA,CAEF,KAAK,cACH,GAAI,CAGF,IAAMiF,CAAAA,CAAe,OAAO,UAAA,CAAe,GAAA,CAAe,WAAmB,MAAA,CAAS,KAAA,CAAA,CAChFC,EAAgB9E,CAAAA,CAAQ,aAAA,EAAkB6E,CAAAA,EAAc,QAAA,EAAU,OACxE,GAAI,CAACC,EACH,MAAM,IAAIlF,EACR,mBAAA,CACA,8EACF,CAAA,CAUF,GANIgF,EAAS,UAAA,CAAW,GAAG,GAAK,CAACA,CAAAA,CAAS,WAAW,IAAI,CAAA,EAK7C,IAAI,GAAA,CAAIA,CAAQ,CAAA,CACpB,MAAA,GAAWE,EACjB,OAAOF,CAEX,OAASG,CAAAA,CAAG,CACV,GAAIA,CAAAA,YAAanF,EAAc,MAAMmF,CAEvC,CACA,MAAM,IAAInF,EACR,mBAAA,CACA,iDACF,CAAA,CAEF,KAAK,YACH,GAAI,CAACI,EAAQ,cAAA,EAAkBA,CAAAA,CAAQ,eAAe,MAAA,GAAW,CAAA,CAC/D,MAAM,IAAIJ,EACR,mBAAA,CACA,wDACF,CAAA,CAIF,GAAIgF,EAAS,UAAA,CAAW,GAAG,CAAA,EAAK,CAACA,EAAS,UAAA,CAAW,IAAI,EACvD,OAAOA,CAAAA,CAGT,GAAI,CACF,IAAMI,CAAAA,CAAS,IAAI,IAAIJ,CAAQ,CAAA,CAC/B,GAAI5E,CAAAA,CAAQ,cAAA,CAAe,SAASgF,CAAAA,CAAO,MAAM,CAAA,CAC/C,OAAOJ,CAEX,CAAA,KAAQ,CAER,CACA,MAAM,IAAIhF,EACR,mBAAA,CACA,CAAA,kCAAA,EAAqCI,CAAAA,CAAQ,cAAA,CAAe,KAAK,IAAI,CAAC,EACxE,CAAA,CAEF,QACE,MAAM,IAAIJ,CAAAA,CACR,mBAAA,CACA,CAAA,yBAAA,EAA4BI,EAAQ,MAAM,CAAA,CAC5C,CACJ,CACF,CAYA,MAAM,uBAAA,CAAwB+D,CAAAA,CAAmC,CAC/D,IAAMY,EAAMf,CAAAA,CAAa,SAAA,CAAU,KAAK,UAAA,CAAY,IAAA,CAAK,aAAcG,CAAK,CAAA,CAE5E,GAAI,CACF,IAAMkB,CAAAA,CAAS,MAAM,KAAK,OAAA,CAAQ,GAAA,CAAIN,CAAG,CAAA,CAEzC,GAAI,CAACM,CAAAA,CACH,MAAM,IAAIrF,CAAAA,CAAa,gBAAiB,iCAAiC,CAAA,CAG3E,IAAI8E,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAY,KAAK,KAAA,CAAMO,CAAM,EAC/B,CAAA,KAAQ,CACN,MAAM,IAAIrF,CAAAA,CAAa,eAAA,CAAiB,sBAAsB,CAChE,CAGA,GAAI,KAAK,GAAA,EAAI,CAAI8E,EAAU,SAAA,CACzB,MAAM,IAAI9E,CAAAA,CAAa,gBAAiB,mBAAmB,CAAA,CAG7D,OAAO8E,CACT,CAAA,OAAE,CAKA,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAOC,CAAG,EAC/B,CACF,CAUA,MAAM,oBAAA,EAAsC,CAE1C,GAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,OAChB,OAGF,IAAMO,EAAStB,CAAAA,CAAa,eAAA,CAAgB,KAAK,UAAA,CAAY,IAAA,CAAK,YAAY,CAAA,CACxEuB,EAAM,MAAM,IAAA,CAAK,QAAQ,MAAA,EAAO,CAChCV,EAAM,IAAA,CAAK,GAAA,EAAI,CAErB,IAAA,GAAW,CAACE,CAAAA,CAAKS,CAAK,IAAK,MAAA,CAAO,OAAA,CAAQD,CAAG,CAAA,CAC3C,GAAKR,CAAAA,CAAI,UAAA,CAAWO,CAAM,CAAA,CAI1B,GAAI,CACF,IAAMR,EAAuB,IAAA,CAAK,KAAA,CAAMU,CAAK,CAAA,CACzCX,EAAMC,CAAAA,CAAU,SAAA,EAClB,MAAM,IAAA,CAAK,OAAA,CAAQ,OAAOC,CAAG,EAEjC,CAAA,KAAQ,CAEN,MAAM,IAAA,CAAK,OAAA,CAAQ,OAAOA,CAAG,EAC/B,CAEJ,CASA,gBAAA,CAAiBU,CAAAA,CAAqBrB,CAAAA,CAAa,4BAAmC,CACpF,IAAA,CAAK,iBAAgB,CAErB,IAAA,CAAK,gBAAkB,WAAA,CAAY,IAAM,CACvC,IAAA,CAAK,sBAAqB,CAAE,KAAA,CAAM,IAAM,CAExC,CAAC,EACH,CAAA,CAAGqB,CAAU,CAAA,CAGb,IAAA,CAAK,sBAAqB,CAAE,KAAA,CAAM,IAAM,CAExC,CAAC,EACH,CAKA,eAAA,EAAwB,CAClB,IAAA,CAAK,kBACP,aAAA,CAAc,IAAA,CAAK,eAAe,CAAA,CAClC,IAAA,CAAK,gBAAkB,IAAA,EAE3B,CASA,MAAM,mBAAA,EAAuC,CAC3C,GAAI,CAAC,KAAK,OAAA,CAAQ,MAAA,CAChB,OAAO,GAAA,CAGT,IAAMH,CAAAA,CAAStB,CAAAA,CAAa,gBAAgB,IAAA,CAAK,UAAA,CAAY,KAAK,YAAY,CAAA,CACxEuB,EAAM,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,GAE3BG,CAAAA,CAAQ,CAAA,CACZ,QAAWX,CAAAA,IAAO,MAAA,CAAO,KAAKQ,CAAG,CAAA,CAC3BR,CAAAA,CAAI,UAAA,CAAWO,CAAM,CAAA,EACvBI,CAAAA,EAAAA,CAIJ,OAAOA,CACT,CACF,EAvSatB,CAAAA,CAEa,mBAAA,CAAsB,GAAA,CAFnCA,CAAAA,CAKa,cAAgB,EAAA,CAL7BA,CAAAA,CAQa,mBAAqB,EAAA,CARlCA,CAAAA,CAWa,4BAA8B,GAAA,CAXjD,IAAMuB,CAAAA,CAANvB,ECnEA,SAASwB,EAAAA,CAAuCC,CAAAA,CAA4B,CACjF,IAAMC,CAAAA,CAAQD,EAAI,KAAA,CAAM,GAAG,CAAA,CAC3B,GAAIC,EAAM,MAAA,GAAW,CAAA,CACnB,MAAM,IAAI,KAAA,CAAM,sCAAsC,CAAA,CAGxD,GAAM,CAACC,CAAAA,CAAWC,EAAYC,CAAS,CAAA,CAAIH,EAE3C,GAAI,CACF,IAAMI,CAAAA,CAAS,IAAA,CAAK,KAAA,CAAMpC,CAAAA,CAAkBiC,CAAS,CAAC,CAAA,CAChD3E,EAAU,IAAA,CAAK,KAAA,CAAM0C,EAAkBkC,CAAU,CAAC,CAAA,CAExD,OAAO,CACL,MAAA,CAAAE,CAAAA,CACA,OAAA,CAAA9E,CAAAA,CACA,UAAA6E,CACF,CACF,CAAA,KAAQ,CACN,MAAM,IAAI,KAAA,CAAM,sCAAsC,CACxD,CACF,CAWO,SAASE,EAAAA,CAAcC,CAAAA,CAAgC,CAE5D,OADgBR,EAAAA,CAAyBQ,CAAO,EACjC,OACjB,CASO,SAASC,EAAAA,CAAajF,CAAAA,CAA2BkF,CAAAA,CAAsB,CAAA,CAAY,CACxF,GAAIlF,CAAAA,CAAQ,MAAQ,MAAA,CAClB,OAAO,OAGT,IAAMyD,CAAAA,CAAM,IAAA,CAAK,KAAA,CAAM,KAAK,GAAA,EAAI,CAAI,GAAI,CAAA,CACxC,OAAOzD,EAAQ,GAAA,CAAMkF,CAAAA,CAAczB,CACrC,CAQO,SAAS0B,CAAAA,CAAgBH,CAAAA,CAAqC,CACnE,GAAI,CAEF,OADeD,EAAAA,CAAcC,CAAO,CAAA,CACtB,KAChB,MAAQ,CACN,MACF,CACF,CCzFO,SAASI,EAAgBC,CAAAA,CAAWC,CAAAA,CAAoB,CAE7D,IAAM7C,EAAU,IAAI,WAAA,CACd8C,EAAS9C,CAAAA,CAAQ,MAAA,CAAO4C,CAAC,CAAA,CACzBG,CAAAA,CAAS/C,CAAAA,CAAQ,MAAA,CAAO6C,CAAC,CAAA,CAGzBG,CAAAA,CAAOF,CAAAA,CAAO,MAAA,CACdG,EAAOF,CAAAA,CAAO,MAAA,CAGdG,CAAAA,CAAS,IAAA,CAAK,IAAIF,CAAAA,CAAMC,CAAI,EAG9BE,CAAAA,CAASH,CAAAA,CAAOC,EAGpB,IAAA,IAAShE,CAAAA,CAAI,CAAA,CAAGA,CAAAA,CAAIiE,EAAQjE,CAAAA,EAAAA,CAAK,CAC/B,IAAMmE,CAAAA,CAAQnE,CAAAA,CAAI+D,EAAOF,CAAAA,CAAO7D,CAAC,CAAA,CAAI,CAAA,CAC/BoE,EAAQpE,CAAAA,CAAIgE,CAAAA,CAAOF,EAAO9D,CAAC,CAAA,CAAI,EACrCkE,CAAAA,EAAUC,CAAAA,CAAQC,EACpB,CAEA,OAAOF,CAAAA,GAAW,CACpB,CCqEO,IAAMG,CAAAA,CAAN,KAA4B,CAGjC,WAAA,CACmBC,CAAAA,CACAC,CAAAA,CACjB,CAFiB,IAAA,CAAA,IAAA,CAAAD,CAAAA,CACA,cAAAC,EAChB,CAKH,oBAAoBC,CAAAA,CAAoD,CACtE,IAAA,CAAK,gBAAA,CAAmBA,EAC1B,CAYA,qBAAA,CACEC,EACAzC,CAAAA,CACA0C,CAAAA,CACApH,EACwB,CAExB,GAAImH,CAAAA,CAAU,qCAAA,EAAyC,CAACnH,CAAAA,CAAQ,MAAA,CAC9D,MAAM,IAAIJ,CAAAA,CACR,eACA,qFACF,CAAA,CAIF,GAAIuH,CAAAA,CAAU,+BAAiC,CAACnH,CAAAA,CAAQ,MAAA,CACtD,MAAM,IAAIJ,CAAAA,CACR,cAAA,CACA,0FACF,CAAA,CAGF,IAAMyH,CAAAA,CAAWF,CAAAA,CAAU,uBACrBG,CAAAA,CAAS,IAAI,gBAGnBA,CAAAA,CAAO,GAAA,CAAI,WAAA,CAAa,IAAA,CAAK,QAAQ,CAAA,CACrCA,CAAAA,CAAO,IAAI,eAAA,CAAiBtH,CAAAA,CAAQ,cAAgB,MAAM,CAAA,CAC1DsH,CAAAA,CAAO,GAAA,CAAI,eAAgBtH,CAAAA,CAAQ,WAAW,EAC9CsH,CAAAA,CAAO,GAAA,CAAI,QAAS5C,CAAAA,CAAU,KAAK,CAAA,CACnC4C,CAAAA,CAAO,IAAI,OAAA,CAAS5C,CAAAA,CAAU,KAAK,CAAA,CAGnC4C,CAAAA,CAAO,IAAI,gBAAA,CAAkBF,CAAAA,CAAK,aAAa,CAAA,CAC/CE,EAAO,GAAA,CAAI,uBAAA,CAAyBF,EAAK,mBAAmB,CAAA,CAG5D,IAAMG,CAAAA,CAAQvH,CAAAA,CAAQ,KAAA,EAAS,gBAAA,CAe/B,GAdAsH,CAAAA,CAAO,GAAA,CAAI,QAASC,CAAK,CAAA,CAGrBvH,EAAQ,MAAA,EACVsH,CAAAA,CAAO,GAAA,CAAI,QAAA,CAAUtH,EAAQ,MAAM,CAAA,CAEjCA,EAAQ,SAAA,EACVsH,CAAAA,CAAO,IAAI,YAAA,CAActH,CAAAA,CAAQ,SAAS,CAAA,CAExCA,EAAQ,SAAA,EACVsH,CAAAA,CAAO,IAAI,YAAA,CAActH,CAAAA,CAAQ,SAAS,CAAA,CAIxCA,CAAAA,CAAQ,WAAA,CAAa,CAEvB,IAAMwH,CAAAA,CAAkB,IAAI,IAAI,CAC9B,WAAA,CACA,gBACA,cAAA,CACA,OAAA,CACA,OAAA,CACA,gBAAA,CACA,wBACA,OACF,CAAC,EAED,IAAA,GAAW,CAAC7C,EAAKS,CAAK,CAAA,GAAK,MAAA,CAAO,OAAA,CAAQpF,EAAQ,WAAW,CAAA,CACvDwH,EAAgB,GAAA,CAAI7C,CAAAA,CAAI,aAAa,CAAA,EAKzC2C,CAAAA,CAAO,GAAA,CAAI3C,EAAKS,CAAK,EAEzB,CAKA,IAAMwB,CAAAA,CAAiC,CAAE,GAAA,CAH7B,CAAA,EAAGS,CAAQ,CAAA,CAAA,EAAIC,EAAO,QAAA,EAAU,EAGC,CAAA,CAE7C,OAAItH,EAAQ,WAAA,GACV4G,CAAAA,CAAO,KAAA,CAAQlC,CAAAA,CAAU,MACzBkC,CAAAA,CAAO,KAAA,CAAQlC,EAAU,KAAA,CAAA,CAGpBkC,CACT,CAWA,aAAA,CAAca,CAAAA,CAAsD,CAClE,IAAIC,EAGAD,CAAAA,CAAY,QAAA,CAAS,GAAG,CAAA,CAI1BC,CAAAA,CAAAA,CAHYD,EAAY,UAAA,CAAW,MAAM,CAAA,CACrC,IAAI,IAAIA,CAAW,CAAA,CACnB,IAAI,GAAA,CAAIA,EAAa,qBAAqB,CAAA,EAC3B,YAAA,CAEnBC,CAAAA,CAAe,IAAI,eAAA,CAAgBD,CAAW,EAIhD,IAAMxH,CAAAA,CAAQyH,EAAa,GAAA,CAAI,OAAO,CAAA,CACtC,GAAIzH,EAAO,CACT,IAAM0H,EAAmBD,CAAAA,CAAa,GAAA,CAAI,mBAAmB,CAAA,EAAK,sBAAA,CAClE,MAAM,IAAI9H,EAAa,aAAA,CAAe+H,CAAAA,CAAkB,CACtD,OAAA,CAAS,CACP,MAAA1H,CAAAA,CACA,iBAAA,CAAmB0H,CAAAA,CACnB,SAAA,CAAWD,EAAa,GAAA,CAAI,WAAW,CACzC,CACF,CAAC,CACH,CAGA,IAAM5H,CAAAA,CAAO4H,CAAAA,CAAa,IAAI,MAAM,CAAA,CAC9B3D,EAAQ2D,CAAAA,CAAa,GAAA,CAAI,OAAO,CAAA,CAEtC,GAAI,CAAC5H,CAAAA,CACH,MAAM,IAAIF,CAAAA,CAAa,eAAgB,0CAA0C,CAAA,CAEnF,GAAI,CAACmE,CAAAA,CACH,MAAM,IAAInE,EAAa,eAAA,CAAiB,uCAAuC,EAGjF,OAAO,CAAE,KAAAE,CAAAA,CAAM,KAAA,CAAAiE,CAAM,CACvB,CAYA,MAAM,YAAA,CACJoD,CAAAA,CACAnH,CAAAA,CACmB,CACnB,IAAM4H,CAAAA,CAAgBT,CAAAA,CAAU,cAAA,CAG1BU,EAAO,IAAI,eAAA,CAAgB,CAC/B,UAAA,CAAY,oBAAA,CACZ,UAAW,IAAA,CAAK,QAAA,CAChB,IAAA,CAAM7H,CAAAA,CAAQ,KACd,YAAA,CAAcA,CAAAA,CAAQ,YACtB,aAAA,CAAeA,CAAAA,CAAQ,YACzB,CAAC,CAAA,CAGGwB,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,KAAA,CAAqBoG,EAAe,CAC7D,MAAA,CAAQ,MAAA,CACR,OAAA,CAAS,CACP,cAAA,CAAgB,mCAClB,EACA,IAAA,CAAMC,CAAAA,CAAK,UACb,CAAC,EACH,CAAA,MAAS5H,EAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,eAAA,CAAiB,uBAAwB,CAC9D,KAAA,CAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMsG,EAAYtG,CAAAA,CAAS,IAAA,CAC3B,MAAM,IAAI5B,CAAAA,CAAa,cAAe,uBAAA,CAAyB,CAC7D,OAAA,CAAS,CACP,OAAQ4B,CAAAA,CAAS,MAAA,CACjB,KAAA,CAAOsG,CAAAA,EAAW,MAClB,iBAAA,CAAmBA,CAAAA,EAAW,iBAChC,CACF,CAAC,CACH,CAEA,IAAMC,CAAAA,CAAgBvG,CAAAA,CAAS,KAM/B,GAHwBxB,CAAAA,CAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA,CAAE,QAAA,CAAS,QAAQ,CAAA,EAG3C,CAAC+H,EAAc,QAAA,CACpC,MAAM,IAAInI,CAAAA,CACR,mBACA,qFACF,CAAA,CAIF,GAAImI,CAAAA,CAAc,QAAA,CAAU,CAC1B,IAAMC,CAAAA,CAAe7B,CAAAA,CAAgB4B,CAAAA,CAAc,QAAQ,CAAA,CAG3D,GAAIC,IAAiB,MAAA,CAEnB,MAAA,IAAA,CAAK,kBAAkB,kBAAA,CAAmB,CACxC,IAAA,CAAM,aAAA,CACN,UAAW,UAAA,CACX,MAAA,CAAQ,OACR,QAAA,CAAU,qBAAA,CACV,OAAQ,qBAAA,CACR,YAAA,CAAc,uEAChB,CAAC,EAEK,IAAIpI,CAAAA,CACR,gBACA,uEACF,CAAA,CAGF,GAAI,CAACwG,CAAAA,CAAgB4B,CAAAA,CAAchI,CAAAA,CAAQ,KAAK,CAAA,CAE9C,MAAA,IAAA,CAAK,kBAAkB,kBAAA,CAAmB,CACxC,KAAM,aAAA,CACN,SAAA,CAAW,UAAA,CACX,MAAA,CAAQ,OACR,YAAA,CAAc,8CAChB,CAAC,CAAA,CAGK,IAAIJ,EAAa,gBAAA,CAAkB,8CAA8C,CAAA,CAIzF,IAAA,CAAK,kBAAkB,kBAAA,CAAmB,CACxC,KAAM,aAAA,CACN,SAAA,CAAW,WACX,MAAA,CAAQ,MACV,CAAC,EACH,CAGA,IAAM6E,CAAAA,CAAM,KAAK,KAAA,CAAM,IAAA,CAAK,KAAI,CAAI,GAAI,CAAA,CAClCwD,CAAAA,CAAYF,EAAc,UAAA,CAAatD,CAAAA,CAAMsD,EAAc,UAAA,CAAatD,CAAAA,CAAM,KAG9EyD,CAAAA,CAAqB,CACzB,WAAA,CAAaH,CAAAA,CAAc,aAC3B,SAAA,CAAYA,CAAAA,CAAc,YAA2B,QAAA,CACrD,SAAA,CAAAE,EACA,YAAA,CAAcF,CAAAA,CAAc,aAAA,CAC5B,OAAA,CAASA,EAAc,QAAA,CACvB,KAAA,CAAOA,EAAc,KACvB,CAAA,CAGA,YAAK,gBAAA,EAAkB,eAAA,CAAgB,CACrC,QAAA,CAAU,QACV,MAAA,CAAQ,0DAAA,CACR,KAAM,oBAAA,CACN,OAAA,CAAS,CACP,cAAA,CAAgB,CAAC,CAACG,CAAAA,CAAS,YAC3B,eAAA,CAAiB,CAAC,CAACA,CAAAA,CAAS,YAAA,CAC5B,WAAY,CAAC,CAACA,CAAAA,CAAS,OAAA,CACvB,MAAOA,CAAAA,CAAS,KAClB,CACF,CAAC,EAEMA,CACT,CACF,EChYO,IAAMC,EAAN,KAAgB,CACrB,YACmBnB,CAAAA,CACAC,CAAAA,CACAjH,EACjB,CAHiB,IAAA,CAAA,IAAA,CAAAgH,CAAAA,CACA,IAAA,CAAA,QAAA,CAAAC,EACA,IAAA,CAAA,OAAA,CAAAjH,EAChB,CAWH,MAAM,wBAAA,CACJmH,EACAiB,CAAAA,CACoB,CACpB,IAAMC,CAAAA,CAAclB,EAAU,qCAAA,CAE9B,GAAI,CAACkB,CAAAA,CACH,MAAM,IAAIzI,CAAAA,CACR,iBAAA,CACA,kDACF,CAAA,CAIF,IAAMiI,CAAAA,CAAO,IAAI,gBA0BjB,GAvBAA,CAAAA,CAAK,IAAI,WAAA,CAAa,IAAA,CAAK,QAAQ,CAAA,CACnCA,EAAK,GAAA,CAAI,eAAA,CAAiBO,EAAQ,YAAA,EAAgB,MAAM,EACxDP,CAAAA,CAAK,GAAA,CAAI,cAAA,CAAgBO,CAAAA,CAAQ,WAAW,CAAA,CAC5CP,CAAAA,CAAK,IAAI,OAAA,CAASO,CAAAA,CAAQ,KAAK,CAAA,CAC/BP,CAAAA,CAAK,GAAA,CAAI,OAAA,CAASO,EAAQ,KAAK,CAAA,CAC/BP,EAAK,GAAA,CAAI,gBAAA,CAAkBO,EAAQ,aAAa,CAAA,CAChDP,CAAAA,CAAK,GAAA,CAAI,wBAAyBO,CAAAA,CAAQ,mBAAmB,CAAA,CAG7DP,CAAAA,CAAK,IAAI,OAAA,CAASO,CAAAA,CAAQ,KAAA,EAAS,gBAAgB,EAG/CA,CAAAA,CAAQ,MAAA,EACVP,EAAK,GAAA,CAAI,QAAA,CAAUO,EAAQ,MAAM,CAAA,CAE/BA,CAAAA,CAAQ,SAAA,EACVP,EAAK,GAAA,CAAI,YAAA,CAAcO,EAAQ,SAAS,CAAA,CAEtCA,EAAQ,SAAA,EACVP,CAAAA,CAAK,GAAA,CAAI,YAAA,CAAcO,EAAQ,SAAS,CAAA,CAItCA,EAAQ,WAAA,CAAa,CACvB,IAAMZ,CAAAA,CAAkB,IAAI,GAAA,CAAI,CAC9B,YACA,eAAA,CACA,cAAA,CACA,QACA,OAAA,CACA,gBAAA,CACA,wBACA,OACF,CAAC,CAAA,CAED,IAAA,GAAW,CAAC7C,CAAAA,CAAKS,CAAK,IAAK,MAAA,CAAO,OAAA,CAAQgD,EAAQ,WAAW,CAAA,CACvDZ,CAAAA,CAAgB,GAAA,CAAI7C,EAAI,WAAA,EAAa,GAGzCkD,CAAAA,CAAK,GAAA,CAAIlD,EAAKS,CAAK,EAEvB,CAGA,IAAMkD,EAAkC,CACtC,cAAA,CAAgB,oCAChB,GAAG,IAAA,CAAK,SAAS,OACnB,CAAA,CAGI9G,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,IAAA,CAAK,MAAmB6G,CAAAA,CAAa,CACzD,MAAA,CAAQ,MAAA,CACR,QAAAC,CAAAA,CACA,IAAA,CAAMT,EAAK,QAAA,EACb,CAAC,EACH,CAAA,MAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,gBAAiB,oBAAA,CAAsB,CAC5D,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,CAAAA,CAAS,GAAI,CAChB,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,KAC3B,MAAM,IAAI5B,EAAa,WAAA,CAAa,oBAAA,CAAsB,CACxD,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,OACjB,KAAA,CAAOsG,CAAAA,EAAW,MAClB,iBAAA,CAAmBA,CAAAA,EAAW,iBAChC,CACF,CAAC,CACH,CAEA,IAAMS,CAAAA,CAAc/G,CAAAA,CAAS,KAG7B,GAAI,CAAC+G,EAAY,WAAA,CACf,MAAM,IAAI3I,CAAAA,CAAa,YAAa,kCAAkC,CAAA,CAExE,GAAI,OAAO2I,CAAAA,CAAY,YAAe,QAAA,CACpC,MAAM,IAAI3I,CAAAA,CAAa,YAAa,4CAA4C,CAAA,CAKlF,IAAMqI,CAAAA,CADM,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,EAAI,CAAI,GAAI,EAChBM,CAAAA,CAAY,UAAA,CAEpC,OAAO,CACL,UAAA,CAAYA,EAAY,WAAA,CACxB,SAAA,CAAAN,CACF,CACF,CASA,4BAAA,CACEd,CAAAA,CACAqB,EACQ,CACR,IAAMlB,EAAS,IAAI,eAAA,CACnB,OAAAA,CAAAA,CAAO,IAAI,WAAA,CAAa,IAAA,CAAK,QAAQ,CAAA,CACrCA,CAAAA,CAAO,IAAI,aAAA,CAAekB,CAAU,CAAA,CAE7B,CAAA,EAAGrB,EAAU,sBAAsB,CAAA,CAAA,EAAIG,EAAO,QAAA,EAAU,EACjE,CACF,EC5IA,IAAMmB,EAAAA,CAAmB,EAOZC,CAAAA,CAAN,KAAuB,CAC5B,WAAA,CACmB1B,CAAAA,CACAC,EACjB,CAFiB,IAAA,CAAA,IAAA,CAAAD,CAAAA,CACA,IAAA,CAAA,QAAA,CAAAC,EAChB,CAaH,MAAM,yBACJE,CAAAA,CACAnH,CAAAA,CAC0B,CAC1B,IAAMqH,CAAAA,CAAWF,CAAAA,CAAU,6BAAA,CAE3B,GAAI,CAACE,CAAAA,CACH,MAAM,IAAIzH,CAAAA,CACR,mCACA,mEACF,CAAA,CAIF,IAAMiI,CAAAA,CAAO,IAAI,eAAA,CAAgB,CAC/B,SAAA,CAAW,IAAA,CAAK,QAClB,CAAC,CAAA,CAOD,GALI7H,CAAAA,EAAS,OACX6H,CAAAA,CAAK,GAAA,CAAI,QAAS7H,CAAAA,CAAQ,KAAK,EAI7BA,CAAAA,EAAS,WAAA,CAAa,CACxB,IAAMwH,EAAkB,IAAI,GAAA,CAAI,CAAC,WAAA,CAAa,OAAO,CAAC,CAAA,CAEtD,IAAA,GAAW,CAAC7C,CAAAA,CAAKS,CAAK,CAAA,GAAK,MAAA,CAAO,QAAQpF,CAAAA,CAAQ,WAAW,EACvDwH,CAAAA,CAAgB,GAAA,CAAI7C,CAAAA,CAAI,WAAA,EAAa,CAAA,EAGzCkD,CAAAA,CAAK,IAAIlD,CAAAA,CAAKS,CAAK,EAEvB,CAGA,IAAI5D,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,KAAA,CAAmC6F,EAAU,CACtE,MAAA,CAAQ,MAAA,CACR,OAAA,CAAS,CACP,cAAA,CAAgB,mCAClB,EACA,IAAA,CAAMQ,CAAAA,CAAK,UACb,CAAC,EACH,CAAA,MAAS5H,EAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,eAAA,CAAiB,sCAAuC,CAC7E,KAAA,CAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,KAC3B,MAAM,IAAI5B,EAAa,4BAAA,CAA8B,qCAAA,CAAuC,CAC1F,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,OACjB,KAAA,CAAOsG,CAAAA,EAAW,MAClB,iBAAA,CAAmBA,CAAAA,EAAW,iBAChC,CACF,CAAC,CACH,CAEA,IAAM/F,CAAAA,CAAOP,CAAAA,CAAS,KAGtB,GAAI,CAACO,CAAAA,CAAK,WAAA,EAAe,CAACA,CAAAA,CAAK,SAAA,EAAa,CAACA,CAAAA,CAAK,gBAAA,CAChD,MAAM,IAAInC,CAAAA,CACR,4BAAA,CACA,gEACF,EAKF,IAAMqI,CAAAA,CADM,KAAK,KAAA,CAAM,IAAA,CAAK,KAAI,CAAI,GAAI,CAAA,CAChBlG,CAAAA,CAAK,WAE7B,OAAO,CACL,WAAYA,CAAAA,CAAK,WAAA,CACjB,SAAUA,CAAAA,CAAK,SAAA,CACf,eAAA,CAAiBA,CAAAA,CAAK,iBACtB,uBAAA,CAAyBA,CAAAA,CAAK,0BAC9B,SAAA,CAAAkG,CAAAA,CACA,SAAUlG,CAAAA,CAAK,QAAA,EAAY0G,EAC7B,CACF,CAgBA,MAAM,QAAA,CACJtB,CAAAA,CACApD,CAAAA,CAC+B,CAE/B,IAAMU,CAAAA,CAAM,IAAA,CAAK,KAAA,CAAM,KAAK,GAAA,EAAI,CAAI,GAAI,CAAA,CACxC,GAAIA,GAAOV,CAAAA,CAAM,SAAA,CACf,OAAO,CAAE,OAAQ,SAAU,CAAA,CAG7B,IAAM6D,CAAAA,CAAgBT,CAAAA,CAAU,eAG1BU,CAAAA,CAAO,IAAI,eAAA,CAAgB,CAC/B,WAAY,8CAAA,CACZ,WAAA,CAAa9D,EAAM,UAAA,CACnB,SAAA,CAAW,KAAK,QAClB,CAAC,CAAA,CAGGvC,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,IAAA,CAAK,MACzBoG,CAAAA,CACA,CACE,MAAA,CAAQ,MAAA,CACR,QAAS,CACP,cAAA,CAAgB,mCAClB,CAAA,CACA,IAAA,CAAMC,EAAK,QAAA,EACb,CACF,EACF,OAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,gBAAiB,kCAAA,CAAoC,CAC1E,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAGA,GAAI,CAACuB,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,KACrBmH,CAAAA,CAAYb,CAAAA,EAAW,MAE7B,OAAQa,CAAAA,EACN,KAAK,wBAEH,OAAO,CACL,OAAQ,SAAA,CACR,UAAA,CAAY5E,EAAM,QACpB,CAAA,CAEF,KAAK,WAAA,CAEH,OAAO,CACL,MAAA,CAAQ,YACR,UAAA,CAAYA,CAAAA,CAAM,SAAW,CAC/B,CAAA,CAEF,KAAK,eAAA,CAEH,OAAO,CAAE,MAAA,CAAQ,SAAU,CAAA,CAE7B,KAAK,gBAEH,OAAO,CAAE,MAAA,CAAQ,eAAgB,EAEnC,QAEE,MAAM,IAAInE,CAAAA,CAAa,4BAAA,CAA8B,mCAAoC,CACvF,OAAA,CAAS,CACP,MAAA,CAAQ4B,EAAS,MAAA,CACjB,KAAA,CAAOmH,EACP,iBAAA,CAAmBb,CAAAA,EAAW,iBAChC,CACF,CAAC,CACL,CACF,CAGA,IAAMC,CAAAA,CAAgBvG,EAAS,IAAA,CAGzByG,CAAAA,CAAYF,EAAc,UAAA,CAAatD,CAAAA,CAAMsD,CAAAA,CAAc,UAAA,CAAatD,EAAM,IAAA,CAWpF,OAAO,CACL,MAAA,CAAQ,WAAA,CACR,OAXuB,CACvB,WAAA,CAAasD,CAAAA,CAAc,YAAA,CAC3B,UAAYA,CAAAA,CAAc,UAAA,EAA2B,QAAA,CACrD,SAAA,CAAAE,EACA,YAAA,CAAcF,CAAAA,CAAc,aAAA,CAC5B,OAAA,CAASA,EAAc,QAAA,CACvB,KAAA,CAAOA,EAAc,KACvB,CAKA,CACF,CAcA,MAAM,iBAAA,CACJZ,CAAAA,CACApD,EACA/D,CAAAA,CACmB,CACnB,IAAI4I,CAAAA,CAAkB7E,CAAAA,CAAM,SAG5B,OAAa,CAEX,GAAI/D,CAAAA,EAAS,QAAQ,OAAA,CACnB,MAAM,IAAIJ,CAAAA,CAAa,4BAAA,CAA8B,6BAA6B,CAAA,CAGpF,IAAMgH,CAAAA,CAAS,MAAM,KAAK,QAAA,CAASO,CAAAA,CAAWpD,CAAK,CAAA,CAEnD,OAAQ6C,EAAO,MAAA,EACb,KAAK,WAAA,CACH,OAAOA,CAAAA,CAAO,MAAA,CAEhB,KAAK,SAAA,CAEH,MAAM,KAAK,KAAA,CAAMA,CAAAA,CAAO,UAAA,CAAa,GAAA,CAAM5G,GAAS,MAAM,CAAA,CAC1D,SAEF,KAAK,WAAA,CAEH4I,EAAkBhC,CAAAA,CAAO,UAAA,CAEzB7C,CAAAA,CAAM,QAAA,CAAW6E,EACjB,MAAM,IAAA,CAAK,MAAMA,CAAAA,CAAkB,GAAA,CAAM5I,GAAS,MAAM,CAAA,CACxD,SAEF,KAAK,UACH,MAAM,IAAIJ,CAAAA,CACR,8BAAA,CACA,qEACF,CAAA,CAEF,KAAK,eAAA,CACH,MAAM,IAAIA,CAAAA,CACR,sBAAA,CACA,8CACF,CACJ,CACF,CACF,CAOQ,KAAA,CAAMiJ,CAAAA,CAAYC,CAAAA,CAAqC,CAC7D,OAAO,IAAI,QAAQ,CAACC,CAAAA,CAASC,IAAW,CACtC,IAAMC,CAAAA,CAAU,UAAA,CAAWF,EAASF,CAAE,CAAA,CAElCC,GACFA,CAAAA,CAAO,gBAAA,CACL,QACA,IAAM,CACJ,YAAA,CAAaG,CAAO,EACpBD,CAAAA,CAAO,IAAIpJ,EAAa,4BAAA,CAA8B,6BAA6B,CAAC,EACtF,CAAA,CACA,CAAE,IAAA,CAAM,IAAK,CACf,EAEJ,CAAC,CACH,CACF,ECzSO,IAAMsJ,CAAAA,CAAN,KAAkB,CAMvB,YACE/G,CAAAA,CACAxC,CAAAA,CACA,CANF,IAAA,CAAQ,OAAA,CAA8B,KACtC,IAAA,CAAQ,WAAA,CAA6B,IAAA,CAMnC,IAAA,CAAK,OAASwC,CAAAA,CACd,IAAA,CAAK,OAASxC,CAAAA,EAAU,GAC1B,CASA,MAAM,UAAA,EAA4B,CAEhC,GAAI,CAAC,IAAA,CAAK,MAAA,CAAO,mBAAA,CACf,MAAM,IAAIC,CAAAA,CACR,2BAAA,CACA,qDACF,EAIF,GAAI,IAAA,CAAK,OAAO,cAAA,CAAgB,CAC9B,IAAMuJ,CAAAA,CAAW,MAAM,IAAA,CAAK,MAAA,CAAO,gBAAe,CAClD,GAAIA,EAAU,CACZ,IAAA,CAAK,QAAUA,CAAAA,CACf,MACF,CACF,CAGA,GAAI,CACF,IAAA,CAAK,QAAU,MAAM,IAAA,CAAK,OAAO,mBAAA,CAC/B,IAAA,CAAK,MAAA,CAAO,SAAA,EAAa,OAC3B,EACF,CAAA,MAASlJ,EAAO,CACd,MAAM,IAAIL,CAAAA,CACR,2BAAA,CACA,kCAAA,CACA,CAAE,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAAU,CACtD,CACF,CACF,CAKA,aAAA,EAAyB,CACvB,OAAO,IAAA,CAAK,OAAA,GAAY,IAC1B,CAaA,MAAM,cACJmJ,CAAAA,CACAC,CAAAA,CACArJ,CAAAA,CACiB,CACjB,GAAI,CAAC,IAAA,CAAK,QACR,MAAM,IAAIJ,EACR,6BAAA,CACA,wDACF,CAAA,CAIF,IAAM0J,EAAM,IAAI,GAAA,CAAID,CAAG,CAAA,CACjBE,CAAAA,CAAM,GAAGD,CAAAA,CAAI,QAAQ,CAAA,EAAA,EAAKA,CAAAA,CAAI,IAAI,CAAA,EAAGA,CAAAA,CAAI,QAAQ,CAAA,CAAA,CAGjDxD,CAAAA,CAA0B,CAC9B,GAAA,CAAK,UAAA,CACL,GAAA,CAAK,IAAA,CAAK,QAAQ,SAAA,CAClB,GAAA,CAAK,KAAK,OAAA,CAAQ,YACpB,EAGMrB,CAAAA,CAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,KAAI,CAAI,GAAI,EAClC+E,CAAAA,CAA0B,CAC9B,IAAK,IAAA,CAAK,WAAA,EAAY,CACtB,GAAA,CAAKJ,EAAO,WAAA,EAAY,CACxB,IAAAG,CAAAA,CACA,GAAA,CAAK9E,CACP,CAAA,CAGIzE,CAAAA,EAAS,eAAA,GACXwJ,CAAAA,CAAO,IAAMxJ,CAAAA,CAAQ,eAAA,CAAA,CAAA,CAEnBA,GAAS,KAAA,EAAS,IAAA,CAAK,eACzBwJ,CAAAA,CAAO,KAAA,CAAQxJ,CAAAA,EAAS,KAAA,EAAS,KAAK,WAAA,EAAe,MAAA,CAAA,CAIvD,GAAI,CACF,IAAM2F,EAAYnC,CAAAA,CAAkB,IAAA,CAAK,SAAA,CAAUsC,CAAM,CAAC,CAAA,CACpD2D,CAAAA,CAAYjG,EAAkB,IAAA,CAAK,SAAA,CAAUgG,CAAM,CAAC,CAAA,CACpDE,CAAAA,CAAe,CAAA,EAAG/D,CAAS,CAAA,CAAA,EAAI8D,CAAS,CAAA,CAAA,CAExC5D,CAAAA,CAAY,MAAM,IAAA,CAAK,OAAA,CAAQ,IAAA,CACnC,IAAI,aAAY,CAAE,MAAA,CAAO6D,CAAY,CACvC,CAAA,CACMC,EAAepH,CAAAA,CAAgBsD,CAAS,CAAA,CAE9C,OAAO,GAAG6D,CAAY,CAAA,CAAA,EAAIC,CAAY,CAAA,CACxC,CAAA,MAAS1J,EAAO,CACd,MAAM,IAAIL,CAAAA,CACR,8BACA,+BAAA,CACA,CAAE,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAAU,CACtD,CACF,CACF,CAUA,mBAAA,CAAoBsE,CAAAA,CAAqB,CACvC,IAAA,CAAK,WAAA,CAAcA,EACrB,CAKA,cAAA,EAAgC,CAC9B,OAAO,KAAK,WACd,CAKA,kBAAyB,CACvB,IAAA,CAAK,YAAc,KACrB,CAOA,eAAA,EAA8B,CAC5B,OAAO,IAAA,CAAK,OAAA,EAAS,cAAgB,IACvC,CAOA,eAA+B,CAC7B,OAAO,IAAA,CAAK,OAAA,EAAS,YAAc,IACrC,CAQA,MAAM,wBAAA,CAAyBqF,CAAAA,CAAsC,CACnE,IAAMC,CAAAA,CAAO,MAAM,IAAA,CAAK,OAAO,MAAA,CAAOD,CAAW,CAAA,CACjD,OAAOrH,EAAgBsH,CAAI,CAC7B,CAOA,MAAM,OAAuB,CACvB,IAAA,CAAK,OAAO,gBAAA,EACd,MAAM,KAAK,MAAA,CAAO,gBAAA,EAAiB,CAErC,IAAA,CAAK,QAAU,IAAA,CACf,IAAA,CAAK,YAAc,KACrB,CAKQ,aAAsB,CAC5B,OAAI,OAAO,MAAA,CAAW,KAAe,MAAA,CAAO,UAAA,CACnC,OAAO,UAAA,EAAW,CAEpB,GAAG,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,KAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,UAAU,CAAA,CAAG,EAAE,CAAC,CAAA,CACrE,CACF,ECrKO,IAAMC,EAAkB,CAC7B,YAAA,CAAc,gDACd,aAAA,CAAe,gDAAA,CACf,QAAA,CAAU,2CACZ,EC/BO,IAAMC,CAAAA,CAAN,MAAMA,CAAa,CAmCxB,YAAY/J,CAAAA,CAA8B,CAvB1C,IAAA,CAAQ,cAAA,CAA2C,KAGnD,IAAA,CAAQ,SAAA,CAA0C,KAGlD,IAAA,CAAQ,eAAA,CAAwD,KAGhE,IAAA,CAAQ,WAAA,CAAc,IAAA,CAGtB,IAAA,CAAQ,mBAAoC,IAAA,CAY1C,IAAA,CAAK,IAAA,CAAOA,CAAAA,CAAQ,KACpB,IAAA,CAAK,OAAA,CAAUA,CAAAA,CAAQ,OAAA,CACvB,KAAK,QAAA,CAAWA,CAAAA,CAAQ,SACxB,IAAA,CAAK,UAAA,CAAaA,EAAQ,UAAA,CAC1B,IAAA,CAAK,YAAA,CAAeA,CAAAA,CAAQ,aAC5B,IAAA,CAAK,kBAAA,CACHA,EAAQ,kBAAA,EAAsB+J,CAAAA,CAAa,6BAC7C,IAAA,CAAK,YAAA,CAAe/J,CAAAA,CAAQ,YAAA,CAC5B,KAAK,mBAAA,CAAA,CACFA,CAAAA,CAAQ,0BAA4B+J,CAAAA,CAAa,kCAAA,EAAsC,IAC1F,IAAA,CAAK,gBAAA,CAAmB/J,CAAAA,CAAQ,gBAAA,EAAoB+J,EAAa,2BACnE,CAKA,aAAa5C,CAAAA,CAAwC,CACnD,KAAK,SAAA,CAAYA,EACnB,CAKA,IAAY,UAAmB,CAC7B,OAAOvD,EAAa,MAAA,CAAO,IAAA,CAAK,WAAY,IAAA,CAAK,YAAY,CAC/D,CAKA,IAAY,UAAA,EAAqB,CAC/B,OAAOA,CAAAA,CAAa,OAAA,CAAQ,KAAK,UAAA,CAAY,IAAA,CAAK,YAAY,CAChE,CAOA,MAAM,SAAA,EAAsC,CAC1C,IAAMqB,CAAAA,CAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,QAAQ,CAAA,CACnD,GAAI,CAACA,CAAAA,CACH,OAAO,KAGT,GAAI,CACF,OAAO,IAAA,CAAK,MAAMA,CAAM,CAC1B,MAAQ,CAEN,OAAA,MAAM,KAAK,WAAA,EAAY,CAChB,IACT,CACF,CAOA,MAAM,UAAA,CAAW+E,EAAiC,CAChD,MAAM,KAAK,OAAA,CAAQ,GAAA,CAAI,IAAA,CAAK,QAAA,CAAU,KAAK,SAAA,CAAUA,CAAM,CAAC,CAAA,CAGxDA,CAAAA,CAAO,SACT,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,KAAK,UAAA,CAAYA,CAAAA,CAAO,OAAO,CAAA,CAIxD,IAAA,CAAK,sBAAsBA,CAAAA,CAAO,SAAS,EAC7C,CAOQ,sBAAsB/B,CAAAA,CAAyB,CAQrD,GANI,IAAA,CAAK,eAAA,GACP,aAAa,IAAA,CAAK,eAAe,CAAA,CACjC,IAAA,CAAK,gBAAkB,IAAA,CAAA,CAIrB,CAAC,KAAK,WAAA,CACR,OAGF,IAAMgC,CAAAA,CAAchC,CAAAA,CAAY,GAAA,CAC1BiC,CAAAA,CAAcD,EAAc,IAAA,CAAK,mBAAA,CAGjCE,EAAS,IAAA,CAAK,MAAA,GAAW,IAAA,CAAK,gBAAA,CAAmB,CAAA,CAAI,IAAA,CAAK,iBAC1DC,CAAAA,CAAQF,CAAAA,CAAc,IAAA,CAAK,GAAA,GAAQC,CAAAA,CAGrCC,CAAAA,CAAQ,CAAA,GACV,IAAA,CAAK,gBAAkB,UAAA,CAAW,IAAM,CACtC,IAAM3F,CAAAA,CAAM,KAAK,GAAA,EAAI,CACf4F,CAAAA,CAAY,IAAA,CAAK,IAAI,CAAA,CAAG,IAAA,CAAK,OAAOJ,CAAAA,CAAcxF,CAAAA,EAAO,GAAI,CAAC,CAAA,CAEpE,IAAA,CAAK,YAAA,EAAc,KAAK,gBAAA,CAAkB,CACxC,UAAAwD,CAAAA,CACA,SAAA,CAAAoC,EACA,SAAA,CAAW5F,CAAAA,CACX,MAAA,CAAQ,MACV,CAAC,EACH,CAAA,CAAG2F,CAAK,CAAA,EAEZ,CAUA,aAAaE,CAAAA,CAAyB,CACpC,IAAA,CAAK,WAAA,CAAcA,EAEf,CAACA,CAAAA,EAAY,KAAK,eAAA,GACpB,YAAA,CAAa,KAAK,eAAe,CAAA,CACjC,IAAA,CAAK,eAAA,CAAkB,MAE3B,CAKA,cAAA,CAAe9F,EAAkC,CAC/C,IAAA,CAAK,mBAAqBA,EAC5B,CAKA,cAAA,EAAgC,CAC9B,OAAO,IAAA,CAAK,kBACd,CAKA,MAAM,WAAA,EAA6B,CACjC,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,KAAK,QAAQ,CAAA,CACvC,MAAM,IAAA,CAAK,QAAQ,MAAA,CAAO,IAAA,CAAK,UAAU,EAC3C,CAYA,MAAM,cAAA,EAAkC,CACtC,IAAMwF,CAAAA,CAAS,MAAM,IAAA,CAAK,SAAA,EAAU,CAEpC,GAAI,CAACA,CAAAA,CACH,MAAM,IAAIpK,CAAAA,CAAa,WAAA,CAAa,iDAAiD,CAAA,CAIvF,GAAI,IAAA,CAAK,aAAA,CAAcoK,CAAM,CAAA,CAAG,CAC9B,GAAI,CAACA,CAAAA,CAAO,aACV,MAAM,IAAIpK,CAAAA,CACR,eAAA,CACA,qDACF,CAAA,CAEF,OAAO,KAAK,eAAA,CAAgBoK,CAAAA,CAAO,YAAY,CACjD,CAEA,OAAOA,CAAAA,CAAO,WAChB,CAOA,MAAM,YAAqC,CAEzC,OAAA,CADe,MAAM,IAAA,CAAK,SAAA,EAAU,GACrB,OAAA,EAAW,IAC5B,CAQQ,aAAA,CAAcA,EAA2B,CAC/C,IAAMvF,EAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,GAAQ,GAAI,CAAA,CACxC,OAAOuF,CAAAA,CAAO,SAAA,CAAY,KAAK,kBAAA,EAAsBvF,CACvD,CAYA,MAAc,gBACZ8F,CAAAA,CACAC,CAAAA,CAA6D,WAAA,CAC5C,CAEjB,GAAI,IAAA,CAAK,cAAA,CAEP,OAAA,CADe,MAAM,KAAK,cAAA,EACZ,WAAA,CAIhB,KAAK,cAAA,CAAiB,IAAA,CAAK,mBAAmBD,CAAAA,CAAcC,CAAM,CAAA,CAElE,GAAI,CAEF,OAAA,CADe,MAAM,KAAK,cAAA,EACZ,WAChB,QAAE,CAEA,IAAA,CAAK,cAAA,CAAiB,KACxB,CACF,CAQA,MAAM,SAA6B,CACjC,IAAMR,EAAS,MAAM,IAAA,CAAK,SAAA,EAAU,CACpC,GAAI,CAACA,CAAAA,EAAQ,aACX,MAAM,IAAIpK,EAAa,WAAA,CAAa,4BAA4B,CAAA,CAIlE,GAAI,KAAK,cAAA,CACP,OAAO,KAAK,cAAA,CAGd,IAAA,CAAK,eAAiB,IAAA,CAAK,kBAAA,CAAmBoK,CAAAA,CAAO,YAAA,CAAc,QAAQ,CAAA,CAE3E,GAAI,CACF,OAAO,MAAM,KAAK,cACpB,CAAA,OAAE,CACA,IAAA,CAAK,eAAiB,KACxB,CACF,CAUA,MAAc,kBAAA,CACZO,EACAC,CAAAA,CAA6D,WAAA,CAC7DC,CAAAA,CAAU,CAAA,CACS,CAEnB,IAAM3J,CAAAA,CAAY,KAAK,GAAA,EAAI,CAGvB2J,IAAY,CAAA,EACd,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,mBAAoB,CAC1C,MAAA,CAAAD,EACA,SAAA,CAAA1J,CAAAA,CACA,OAAQ,MAAA,CACR,WAAA,CAAa,IAAA,CAAK,kBAAA,EAAsB,MAC1C,CAAC,CAAA,CAGH,GAAI,CACF,OAAO,MAAM,IAAA,CAAK,SAAA,CAAUyJ,CAAY,CAC1C,OAAStK,CAAAA,CAAO,CACd,IAAMgC,CAAAA,CAAehC,CAAAA,YAAiBL,EAClCK,CAAAA,CACA,IAAIL,CAAAA,CAAa,eAAA,CAAiB,uBAAwB,CACxD,KAAA,CAAOK,aAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CAAA,CAECyK,CAAAA,CAAYD,CAAAA,CAAU,GAAchK,CAAAA,CAAiBwB,CAAY,EAavE,GAVA,IAAA,CAAK,cAAc,IAAA,CAAK,sBAAA,CAAwB,CAC9C,KAAA,CAAOA,EACP,SAAA,CAAAyI,CAAAA,CACA,QAAAD,CAAAA,CACA,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,MAAA,CAAQ,MAAA,CACR,YAAa,IAAA,CAAK,kBAAA,EAAsB,MAC1C,CAAC,CAAA,CAGGC,EACF,OAAO,IAAA,CAAK,kBAAA,CAAmBH,CAAAA,CAAcC,EAAQC,CAAAA,CAAU,CAAC,CAAA,CAIlE,MAAKhK,EAAiBwB,CAAY,CAAA,EAChC,IAAA,CAAK,YAAA,EAAc,KAAK,eAAA,CAAiB,CACvC,OAAQ,gBAAA,CACR,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,MAAA,CAAQ,MAAA,CACR,YAAa,IAAA,CAAK,kBAAA,EAAsB,MAC1C,CAAC,CAAA,CAGGhC,CACR,CACF,CAQA,MAAc,SAAA,CAAUsK,EAAyC,CAC/D,GAAI,CAAC,IAAA,CAAK,SAAA,CACR,MAAM,IAAI3K,CAAAA,CAAa,cAAA,CAAgB,4BAA4B,EAGrE,IAAMgI,CAAAA,CAAgB,KAAK,SAAA,CAAU,cAAA,CAG/BC,EAAO,IAAI,eAAA,CAAgB,CAC/B,UAAA,CAAY,gBACZ,SAAA,CAAW,IAAA,CAAK,SAChB,aAAA,CAAe0C,CACjB,CAAC,CAAA,CAEG/I,CAAAA,CACJ,GAAI,CACFA,EAAW,MAAM,IAAA,CAAK,KAAK,KAAA,CAAqBoG,CAAAA,CAAe,CAC7D,MAAA,CAAQ,MAAA,CACR,OAAA,CAAS,CACP,eAAgB,mCAClB,CAAA,CACA,KAAMC,CAAAA,CAAK,QAAA,EACb,CAAC,EACH,CAAA,MAAS5H,CAAAA,CAAO,CACd,IAAMgC,CAAAA,CAAe,IAAIrC,CAAAA,CAAa,eAAA,CAAiB,+BAAgC,CACrF,KAAA,CAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAC1C,CAAC,EACD,MAAA,IAAA,CAAK,YAAA,EAAc,KAAK,aAAA,CAAe,CACrC,KAAA,CAAOgC,CAAAA,CACP,QAAS,SAAA,CACT,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,OAAQ,MACV,CAAC,CAAA,CAEG,IAAA,CAAK,cACPtB,CAAAA,CAAoB,IAAA,CAAK,aAAcsB,CAAAA,CAAc,CAAE,QAAS,SAAU,CAAC,CAAA,CAEvEA,CACR,CAEA,GAAI,CAACT,EAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,IAAA,CACrBS,CAAAA,CAAe,IAAIrC,CAAAA,CAAa,eAAA,CAAiB,uBAAwB,CAC7E,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,MAAA,CACjB,KAAA,CAAOsG,GAAW,KAAA,CAClB,iBAAA,CAAmBA,GAAW,iBAChC,CACF,CAAC,CAAA,CACD,MAAA,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,cAAe,CACrC,KAAA,CAAO7F,EACP,OAAA,CAAS,SAAA,CACT,UAAW,IAAA,CAAK,GAAA,EAAI,CACpB,MAAA,CAAQ,MACV,CAAC,CAAA,CAEG,IAAA,CAAK,YAAA,EACPtB,EAAoB,IAAA,CAAK,YAAA,CAAcsB,CAAAA,CAAc,CAAE,QAAS,SAAU,CAAC,EAEvEA,CACR,CAEA,IAAM8F,CAAAA,CAAgBvG,CAAAA,CAAS,IAAA,CAGzBiD,CAAAA,CAAM,KAAK,KAAA,CAAM,IAAA,CAAK,KAAI,CAAI,GAAI,EAClCwD,CAAAA,CAAYF,CAAAA,CAAc,UAAA,CAAatD,CAAAA,CAAMsD,EAAc,UAAA,CAAatD,CAAAA,CAAM,KAG9EkG,CAAAA,CAAsB,CAC1B,YAAa5C,CAAAA,CAAc,YAAA,CAC3B,SAAA,CAAYA,CAAAA,CAAc,YAA2B,QAAA,CACrD,SAAA,CAAAE,EACA,YAAA,CAAcF,CAAAA,CAAc,eAAiBwC,CAAAA,CAC7C,OAAA,CAASxC,CAAAA,CAAc,QAAA,CACvB,MAAOA,CAAAA,CAAc,KACvB,EAGA,OAAA,MAAM,IAAA,CAAK,WAAW4C,CAAS,CAAA,CAG/B,IAAA,CAAK,YAAA,EAAc,KAAK,iBAAA,CAAmB,CACzC,eAAgB,CAAC,CAACA,EAAU,WAAA,CAC5B,eAAA,CAAiB,CAAC,CAACA,EAAU,YAAA,CAC7B,UAAA,CAAY,CAAC,CAACA,CAAAA,CAAU,QACxB,SAAA,CAAWA,CAAAA,CAAU,SAAA,CACrB,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,OAAQ,MAAA,CACR,WAAA,CAAa,KAAK,kBAAA,EAAsB,MAC1C,CAAC,CAAA,CAEMA,CACT,CAOA,MAAM,iBAAoC,CACxC,IAAMX,EAAS,MAAM,IAAA,CAAK,SAAA,EAAU,CACpC,GAAI,CAACA,CAAAA,CACH,OAAO,MAAA,CAIT,IAAMvF,EAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,GAAQ,GAAI,CAAA,CACxC,OAAIuF,CAAAA,CAAO,SAAA,EAAavF,EAEf,CAAC,CAACuF,CAAAA,CAAO,YAAA,CAGX,IACT,CAYA,MAAM,cAAc5B,CAAAA,CAA6D,CAC/E,GAAI,CAAC,IAAA,CAAK,SAAA,CACR,MAAM,IAAIxI,CAAAA,CAAa,cAAA,CAAgB,4BAA4B,CAAA,CAGrE,IAAMgI,EAAgB,IAAA,CAAK,SAAA,CAAU,cAAA,CAG/BgD,CAAAA,CAAmB,KAAK,iBAAA,CAAkBxC,CAAAA,CAAQ,kBAAoB,cAAc,CAAA,CAGpFP,EAAO,IAAI,eAAA,CAAgB,CAC/B,UAAA,CAAY,kDACZ,SAAA,CAAW,IAAA,CAAK,SAChB,aAAA,CAAeO,CAAAA,CAAQ,aACvB,kBAAA,CAAoBwC,CACtB,CAAC,CAAA,CAGGxC,EAAQ,QAAA,EACVP,CAAAA,CAAK,GAAA,CAAI,UAAA,CAAYO,EAAQ,QAAQ,CAAA,CAEnCA,CAAAA,CAAQ,KAAA,EACVP,EAAK,GAAA,CAAI,OAAA,CAASO,EAAQ,KAAK,CAAA,CAE7BA,EAAQ,kBAAA,EACVP,CAAAA,CAAK,GAAA,CAAI,sBAAA,CAAwB,KAAK,iBAAA,CAAkBO,CAAAA,CAAQ,kBAAkB,CAAC,CAAA,CAEjFA,EAAQ,UAAA,GACVP,CAAAA,CAAK,GAAA,CAAI,aAAA,CAAeO,EAAQ,UAAU,CAAA,CACtCA,EAAQ,cAAA,EACVP,CAAAA,CAAK,IAAI,kBAAA,CAAoB,IAAA,CAAK,iBAAA,CAAkBO,CAAAA,CAAQ,cAAc,CAAC,CAAA,CAAA,CAI/E,IAAI5G,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,IAAA,CAAK,MAA6BoG,CAAAA,CAAe,CACrE,OAAQ,MAAA,CACR,OAAA,CAAS,CACP,cAAA,CAAgB,mCAClB,CAAA,CACA,IAAA,CAAMC,EAAK,QAAA,EACb,CAAC,EACH,CAAA,MAAS5H,EAAO,CACd,IAAMgC,CAAAA,CAAe,IAAIrC,EAAa,eAAA,CAAiB,+BAAA,CAAiC,CACtF,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CAAA,CACD,WAAK,YAAA,EAAc,IAAA,CAAK,aAAA,CAAe,CACrC,MAAOgC,CAAAA,CACP,OAAA,CAAS,UAAA,CACT,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,OAAQ,MACV,CAAC,EAEG,IAAA,CAAK,YAAA,EACPtB,CAAAA,CAAoB,IAAA,CAAK,aAAcsB,CAAAA,CAAc,CAAE,QAAS,UAAW,CAAC,EAExEA,CACR,CAEA,GAAI,CAACT,EAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,KACrBS,CAAAA,CAAe,IAAIrC,CAAAA,CAAa,sBAAA,CAAwB,wBAAyB,CACrF,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,OACjB,KAAA,CAAOsG,CAAAA,EAAW,KAAA,CAClB,iBAAA,CAAmBA,GAAW,iBAChC,CACF,CAAC,CAAA,CACD,MAAA,IAAA,CAAK,cAAc,IAAA,CAAK,aAAA,CAAe,CACrC,KAAA,CAAO7F,EACP,OAAA,CAAS,UAAA,CACT,UAAW,IAAA,CAAK,GAAA,GAChB,MAAA,CAAQ,MACV,CAAC,CAAA,CAEG,KAAK,YAAA,EACPtB,CAAAA,CAAoB,KAAK,YAAA,CAAcsB,CAAAA,CAAc,CAAE,OAAA,CAAS,UAAW,CAAC,CAAA,CAExEA,CACR,CAEA,IAAM8F,CAAAA,CAAgBvG,CAAAA,CAAS,KAGzBiD,CAAAA,CAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,KAAI,CAAI,GAAI,EAClCwD,CAAAA,CAAYF,CAAAA,CAAc,WAAatD,CAAAA,CAAMsD,CAAAA,CAAc,UAAA,CAAatD,CAAAA,CAAM,KAE9EuF,CAAAA,CAAmB,CACvB,YAAajC,CAAAA,CAAc,YAAA,CAC3B,UAAYA,CAAAA,CAAc,UAAA,EAA2B,QAAA,CACrD,SAAA,CAAAE,EACA,YAAA,CAAcF,CAAAA,CAAc,cAC5B,OAAA,CAASA,CAAAA,CAAc,SACvB,KAAA,CAAOA,CAAAA,CAAc,KACvB,CAAA,CAEMnB,EAA8B,CAClC,MAAA,CAAAoD,EACA,eAAA,CAAiBjC,CAAAA,CAAc,iBACjC,CAAA,CAGA,OAAA,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,kBAAmB,CACzC,cAAA,CAAgB,CAAC,CAACiC,CAAAA,CAAO,YACzB,eAAA,CAAiB,CAAC,CAACA,CAAAA,CAAO,aAC1B,eAAA,CAAiBjC,CAAAA,CAAc,kBAC/B,SAAA,CAAW,IAAA,CAAK,KAAI,CACpB,MAAA,CAAQ,MAAA,CACR,WAAA,CAAa,KAAK,kBAAA,EAAsB,MAC1C,CAAC,CAAA,CAEMnB,CACT,CAKQ,iBAAA,CAAkBiE,CAAAA,CAA6D,CACrF,OAAOf,EAAgBe,CAAI,CAC7B,CAKA,OAAA,EAAgB,CACV,KAAK,eAAA,GACP,YAAA,CAAa,IAAA,CAAK,eAAe,EACjC,IAAA,CAAK,eAAA,CAAkB,MAE3B,CACF,CAAA,CAlnBad,EA2Ba,4BAAA,CAA+B,EAAA,CA3B5CA,CAAAA,CA8Ba,kCAAA,CAAqC,IA9BlDA,CAAAA,CAiCa,0BAAA,CAA6B,IAjChD,IAAMe,CAAAA,CAANf,ECqBA,IAAMgB,CAAAA,CAAN,KAAwB,CAI7B,YAAY/K,CAAAA,CAAmC,CAC7C,KAAK,IAAA,CAAOA,CAAAA,CAAQ,KACpB,IAAA,CAAK,QAAA,CAAWA,CAAAA,CAAQ,SAC1B,CAcA,MAAM,UAAA,CACJmH,EACAnH,CAAAA,CACgC,CAChC,IAAMqH,CAAAA,CAAWF,CAAAA,CAAU,sBAAA,CAE3B,GAAI,CAACE,CAAAA,CACH,MAAM,IAAIzH,CAAAA,CACR,2BAAA,CACA,2DACF,CAAA,CAGF,OAAO,IAAA,CAAK,sBAAA,CAAuByH,EAAUrH,CAAO,CACtD,CAYA,MAAM,sBAAA,CACJqH,EACArH,CAAAA,CACgC,CAEhC,IAAM6H,CAAAA,CAAO,IAAI,eAAA,CAAgB,CAC/B,UAAW,IAAA,CAAK,QAAA,CAChB,MAAO7H,CAAAA,CAAQ,KACjB,CAAC,CAAA,CAEGA,EAAQ,aAAA,EACV6H,CAAAA,CAAK,GAAA,CAAI,iBAAA,CAAmB7H,EAAQ,aAAa,CAAA,CAGnD,IAAIwB,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,IAAA,CAAK,MAAkD6F,CAAAA,CAAU,CACrF,MAAA,CAAQ,MAAA,CACR,QAAS,CACP,cAAA,CAAgB,mCAClB,CAAA,CACA,IAAA,CAAMQ,EAAK,QAAA,EACb,CAAC,EACH,OAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,gBAAiB,oCAAA,CAAsC,CAC5E,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,KAC3B,MAAM,IAAI5B,EAAa,qBAAA,CAAuB,4BAAA,CAA8B,CAC1E,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,OACjB,KAAA,CAAOsG,CAAAA,EAAW,MAClB,iBAAA,CAAmBA,CAAAA,EAAW,iBAChC,CACF,CAAC,CACH,CAEA,OAAOtG,CAAAA,CAAS,IAClB,CAWA,MAAM,QAAA,CAAS2F,CAAAA,CAAkC6D,CAAAA,CAAiC,CAEhF,OAAA,CADe,MAAM,IAAA,CAAK,UAAA,CAAW7D,EAAW,CAAE,KAAA,CAAA6D,CAAM,CAAC,GAC3C,MAChB,CACF,ECvIO,IAAMC,CAAAA,CAAN,KAAmB,CAIxB,WAAA,CAAYjL,CAAAA,CAA8B,CACxC,KAAK,IAAA,CAAOA,CAAAA,CAAQ,KACpB,IAAA,CAAK,QAAA,CAAWA,EAAQ,SAC1B,CAcA,MAAM,MAAA,CAAOmH,EAAkCnH,CAAAA,CAA4C,CACzF,IAAMqH,CAAAA,CAAWF,CAAAA,CAAU,oBAE3B,GAAI,CAACE,CAAAA,CACH,MAAM,IAAIzH,CAAAA,CACR,wBAAA,CACA,wDACF,CAAA,CAIF,IAAMiI,EAAO,IAAI,eAAA,CAAgB,CAC/B,SAAA,CAAW,KAAK,QAAA,CAChB,KAAA,CAAO7H,EAAQ,KACjB,CAAC,EAEGA,CAAAA,CAAQ,aAAA,EACV6H,CAAAA,CAAK,GAAA,CAAI,kBAAmB7H,CAAAA,CAAQ,aAAa,EAGnD,IAAIwB,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,KAAK,KAAA,CAAiC6F,CAAAA,CAAU,CACpE,MAAA,CAAQ,MAAA,CACR,QAAS,CACP,cAAA,CAAgB,mCAClB,CAAA,CACA,KAAMQ,CAAAA,CAAK,QAAA,EACb,CAAC,EACH,CAAA,MAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,eAAA,CAAiB,kCAAmC,CACzE,KAAA,CAAOK,aAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAGA,GAAIuB,EAAS,EAAA,CACX,OAIF,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,IAAA,CAC3B,MAAM,IAAI5B,CAAAA,CAAa,kBAAA,CAAoB,0BAA2B,CACpE,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,MAAA,CACjB,KAAA,CAAOsG,GAAW,KAAA,CAClB,iBAAA,CAAmBA,GAAW,iBAChC,CACF,CAAC,CACH,CAWA,MAAM,kBAAA,CAAmBT,EAAkBrH,CAAAA,CAA4C,CAErF,IAAM6H,CAAAA,CAAO,IAAI,gBAAgB,CAC/B,SAAA,CAAW,IAAA,CAAK,QAAA,CAChB,MAAO7H,CAAAA,CAAQ,KACjB,CAAC,CAAA,CAEGA,CAAAA,CAAQ,eACV6H,CAAAA,CAAK,GAAA,CAAI,iBAAA,CAAmB7H,CAAAA,CAAQ,aAAa,CAAA,CAGnD,IAAIwB,EACJ,GAAI,CACFA,EAAW,MAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAiC6F,EAAU,CACpE,MAAA,CAAQ,OACR,OAAA,CAAS,CACP,eAAgB,mCAClB,CAAA,CACA,IAAA,CAAMQ,CAAAA,CAAK,UACb,CAAC,EACH,CAAA,MAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,eAAA,CAAiB,kCAAmC,CACzE,KAAA,CAAOK,aAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAIuB,EAAS,EAAA,CACX,OAGF,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,KAC3B,MAAM,IAAI5B,CAAAA,CAAa,kBAAA,CAAoB,0BAA2B,CACpE,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,OACjB,KAAA,CAAOsG,CAAAA,EAAW,KAAA,CAClB,iBAAA,CAAmBA,GAAW,iBAChC,CACF,CAAC,CACH,CACF,ECvFO,IAAMoD,CAAAA,CAAN,KAAoB,CASzB,YAAYlL,CAAAA,CAA+B,CACzC,KAAK,OAAA,CAAUA,CAAAA,CAAQ,QACvB,IAAA,CAAK,QAAA,CAAWA,CAAAA,CAAQ,QAAA,CACxB,KAAK,UAAA,CAAaA,CAAAA,CAAQ,WAC1B,IAAA,CAAK,YAAA,CAAeA,EAAQ,YAAA,CAC5B,IAAA,CAAK,YAAA,CAAeA,CAAAA,CAAQ,aAC5B,IAAA,CAAK,SAAA,CAAYA,CAAAA,CAAQ,SAAA,CACzB,KAAK,YAAA,CAAe,IAAIiL,CAAAA,CAAa,CACnC,KAAMjL,CAAAA,CAAQ,IAAA,CACd,SAAUA,CAAAA,CAAQ,QACpB,CAAC,EACH,CAcA,MAAM,MAAA,CACJmH,EACAnH,CAAAA,CACuB,CAEvB,IAAMmL,CAAAA,CAAgB,MAAM,KAAK,gBAAA,EAAiB,CAC5CC,CAAAA,CAAe,MAAM,KAAK,eAAA,EAAgB,CAG5CC,EACArL,CAAAA,EAAS,YAAA,EAAgBmH,GAAW,mBAAA,EAAuBiE,CAAAA,GAC7DC,CAAAA,CAAmB,MAAM,KAAK,YAAA,CAAalE,CAAAA,CAAWiE,CAAY,CAAA,CAAA,CAIpE,MAAM,KAAK,WAAA,EAAY,CAGvB,IAAA,CAAK,YAAA,EAAc,KAAK,eAAA,CAAiB,CACvC,OAAQ,QAAA,CACR,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,MAAA,CAAQ,MACV,CAAC,CAAA,CAID,IAAIE,EAUJ,GARI,IAAA,CAAK,WAAW,UAAA,GAAe,MAAA,CAEjCA,CAAAA,CAAqB,IAAA,CAAK,UAAU,UAAA,CAC3BnE,CAAAA,GACTmE,EAAqBnE,CAAAA,CAAU,oBAAA,CAAA,CAI7B,CAACmE,CAAAA,CACH,OAAO,CAAE,SAAA,CAAW,KAAM,UAAA,CAAYD,CAAiB,CAAA,CAIzD,IAAMrF,EAAUhG,CAAAA,EAAS,WAAA,EAAemL,CAAAA,CAElC7D,CAAAA,CAAS,IAAI,eAAA,CAAgB,CACjC,UAAW,IAAA,CAAK,QAClB,CAAC,CAAA,CAED,OAAItB,CAAAA,EACFsB,CAAAA,CAAO,IAAI,eAAA,CAAiBtB,CAAO,EAEjChG,CAAAA,EAAS,qBAAA,EACXsH,EAAO,GAAA,CAAI,0BAAA,CAA4BtH,CAAAA,CAAQ,qBAAqB,EAElEA,CAAAA,EAAS,KAAA,EACXsH,EAAO,GAAA,CAAI,OAAA,CAAStH,EAAQ,KAAK,CAAA,CAG5B,CACL,SAAA,CAAW,GAAGsL,CAAkB,CAAA,CAAA,EAAIhE,EAAO,QAAA,EAAU,GACrD,SAAA,CAAW,KAAA,CACX,UAAA,CAAY+D,CACd,CACF,CAWA,MAAc,aACZlE,CAAAA,CACA6C,CAAAA,CACkD,CAClD,IAAMpD,CAAAA,CAAkD,CACtD,SAAA,CAAW,IACb,CAAA,CAEA,GAAI,CAEEoD,CAAAA,CAAO,YAAA,GACT,MAAM,IAAA,CAAK,YAAA,CAAa,MAAA,CAAO7C,CAAAA,CAAW,CACxC,KAAA,CAAO6C,CAAAA,CAAO,aACd,aAAA,CAAe,eACjB,CAAC,CAAA,CACDpD,CAAAA,CAAO,mBAAA,CAAsB,CAAA,CAAA,CAAA,CAI/B,MAAM,IAAA,CAAK,YAAA,CAAa,MAAA,CAAOO,CAAAA,CAAW,CACxC,KAAA,CAAO6C,CAAAA,CAAO,WAAA,CACd,aAAA,CAAe,cACjB,CAAC,CAAA,CACDpD,EAAO,kBAAA,CAAqB,CAAA,EAC9B,OAAS3G,CAAAA,CAAO,CACd2G,CAAAA,CAAO,KAAA,CAAQ3G,aAAiB,KAAA,CAAQA,CAAAA,CAAQ,IAAI,KAAA,CAAM,MAAA,CAAOA,CAAK,CAAC,EACzE,CAEA,OAAO2G,CACT,CAKA,MAAc,aAA6B,CACzC,IAAM2E,EAAW3H,CAAAA,CAAa,MAAA,CAAO,IAAA,CAAK,UAAA,CAAY,KAAK,YAAY,CAAA,CACjE4H,EAAa5H,CAAAA,CAAa,OAAA,CAAQ,KAAK,UAAA,CAAY,IAAA,CAAK,YAAY,CAAA,CAE1E,MAAM,IAAA,CAAK,OAAA,CAAQ,OAAO2H,CAAQ,CAAA,CAClC,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAOC,CAAU,EACtC,CAKA,MAAc,kBAA2C,CACvD,IAAMA,EAAa5H,CAAAA,CAAa,OAAA,CAAQ,IAAA,CAAK,UAAA,CAAY,KAAK,YAAY,CAAA,CAC1E,OAAO,IAAA,CAAK,OAAA,CAAQ,IAAI4H,CAAU,CACpC,CAKA,MAAc,iBAA4C,CACxD,IAAMD,EAAW3H,CAAAA,CAAa,MAAA,CAAO,KAAK,UAAA,CAAY,IAAA,CAAK,YAAY,CAAA,CACjEqB,EAAS,MAAM,IAAA,CAAK,QAAQ,GAAA,CAAIsG,CAAQ,EAC9C,GAAI,CAACtG,CAAAA,CACH,OAAO,KAET,GAAI,CACF,OAAO,IAAA,CAAK,KAAA,CAAMA,CAAM,CAC1B,CAAA,KAAQ,CACN,OAAO,IACT,CACF,CACF,EClNO,IAAMwG,CAAAA,CAAN,KAAqB,CAG1B,WAAA,CAAYzL,CAAAA,CAAgC,CAC1C,KAAK,IAAA,CAAOA,CAAAA,CAAQ,KACtB,CASA,MAAM,aACJmH,CAAAA,CACAyC,CAAAA,CAC6B,CAC7B,IAAM8B,EAAmBvE,CAAAA,CAAU,iBAAA,CAEnC,GAAI,CAACuE,CAAAA,CACH,OAAO,CACL,KAAA,CAAO,KAAA,CACP,KAAA,CAAO,IAAI9L,CAAAA,CAAa,sBAAA,CAAwB,iCAAiC,CACnF,CAAA,CAGF,GAAI,CACF,IAAM4B,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,KAAA,CAAgBkK,EAAkB,CACjE,MAAA,CAAQ,MACR,OAAA,CAAS,CACP,aAAA,CAAe,CAAA,OAAA,EAAU9B,CAAW,CAAA,CACtC,CACF,CAAC,CAAA,CAED,OAAKpI,CAAAA,CAAS,EAAA,CAiBP,CACL,KAAA,CAAO,GACP,IAAA,CAAMA,CAAAA,CAAS,IACjB,CAAA,CAlBMA,CAAAA,CAAS,SAAW,GAAA,CACf,CACL,KAAA,CAAO,CAAA,CAAA,CACP,MAAO,IAAI5B,CAAAA,CAAa,kBAAmB,qBAAqB,CAClE,EAGK,CACL,KAAA,CAAO,CAAA,CAAA,CACP,KAAA,CAAO,IAAIA,CAAAA,CAAa,sBAAA,CAAwB,uBAAwB,CACtE,OAAA,CAAS,CAAE,MAAA,CAAQ4B,CAAAA,CAAS,MAAO,CACrC,CAAC,CACH,CAOJ,OAASvB,CAAAA,CAAO,CACd,OAAO,CACL,KAAA,CAAO,KAAA,CACP,KAAA,CAAO,IAAIL,CAAAA,CAAa,eAAA,CAAiB,0BAA2B,CAClE,KAAA,CAAOK,aAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CACF,CACF,CAUA,MAAM,WAAA,CAAYkH,EAAkCyC,CAAAA,CAAwC,CAC1F,IAAM8B,CAAAA,CAAmBvE,EAAU,iBAAA,CAEnC,GAAI,CAACuE,CAAAA,CACH,MAAM,IAAI9L,CAAAA,CAAa,sBAAA,CAAwB,iCAAiC,CAAA,CAGlF,IAAI4B,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAgBkK,CAAAA,CAAkB,CAC3D,MAAA,CAAQ,KAAA,CACR,QAAS,CACP,aAAA,CAAe,UAAU9B,CAAW,CAAA,CACtC,CACF,CAAC,EACH,CAAA,MAAS3J,CAAAA,CAAO,CACd,MAAM,IAAIL,EAAa,eAAA,CAAiB,2BAAA,CAA6B,CACnE,KAAA,CAAOK,aAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,CAAAA,CAAS,EAAA,CACZ,MAAM,IAAI5B,CAAAA,CAAa,iBAAkB,yBAAA,CAA2B,CAClE,QAAS,CAAE,MAAA,CAAQ4B,CAAAA,CAAS,MAAO,CACrC,CAAC,CAAA,CAGH,OAAOA,CAAAA,CAAS,IAClB,CACF,ECjHO,IAAMmK,CAAAA,CAAN,KAAqB,CAO1B,WAAA,CAAY3L,CAAAA,CAAgC,CAF5C,IAAA,CAAQ,SAAA,CAA0C,KAGhD,IAAA,CAAK,YAAA,CAAeA,CAAAA,CAAQ,YAAA,CAC5B,KAAK,cAAA,CAAiBA,CAAAA,CAAQ,eAChC,CAKA,YAAA,CAAamH,EAAwC,CACnD,IAAA,CAAK,SAAA,CAAYA,EACnB,CAUA,MAAM,eAAA,EAAoC,CACxC,OAAO,KAAK,YAAA,CAAa,eAAA,EAC3B,CASA,MAAM,YAAA,EAA4C,CAChD,GAAI,CAAC,IAAA,CAAK,UACR,OAAO,CACL,KAAA,CAAO,KAAA,CACP,MAAO,IAAIvH,CAAAA,CAAa,eAAgB,kCAAkC,CAC5E,EAGF,GAAI,CACF,IAAMgK,CAAAA,CAAc,MAAM,IAAA,CAAK,YAAA,CAAa,gBAAe,CAC3D,OAAO,KAAK,cAAA,CAAe,YAAA,CAAa,IAAA,CAAK,SAAA,CAAWA,CAAW,CACrE,CAAA,MAAS3J,EAAO,CACd,OAAIA,aAAiBL,CAAAA,CACZ,CAAE,KAAA,CAAO,KAAA,CAAO,MAAAK,CAAM,CAAA,CAExB,CACL,KAAA,CAAO,KAAA,CACP,MAAO,IAAIL,CAAAA,CAAa,sBAAA,CAAwB,yBAAA,CAA2B,CACzE,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CACF,CACF,CAUA,MAAM,OAAA,EAA6B,CACjC,GAAI,CAAC,IAAA,CAAK,UACR,MAAM,IAAIL,CAAAA,CAAa,cAAA,CAAgB,kCAAkC,CAAA,CAG3E,IAAMgK,EAAc,MAAM,IAAA,CAAK,aAAa,cAAA,EAAe,CAC3D,OAAO,IAAA,CAAK,eAAe,WAAA,CAAY,IAAA,CAAK,UAAWA,CAAW,CACpE,CACF,ECvDA,eAAegC,EAAAA,CACbzJ,CAAAA,CACAiD,EACAyG,CAAAA,CAAS,EAAA,CACQ,CACjB,IAAMhC,CAAAA,CAAO,MAAM1H,CAAAA,CAAO,MAAA,CAAOiD,CAAK,CAAA,CACtC,OAAO7C,CAAAA,CAAgBsH,CAAI,EAAE,KAAA,CAAM,CAAA,CAAGgC,CAAM,CAC9C,CAKO,IAAMC,CAAAA,CAAN,KAAoB,CAsEzB,WAAA,CAAYnM,EAA6B,CA5CzC,IAAA,CAAQ,YAAkC,IAAA,CA2B1C,IAAA,CAAQ,WAAA,CAAc,KAAA,CAGtB,KAAQ,gBAAA,CAA6C,IAAA,CAenD,KAAK,MAAA,CAASD,CAAAA,CAAcC,CAAM,CAAA,CAClC,IAAA,CAAK,gBAAA,CAAmBsB,CAAAA,CAAgBtB,EAAO,MAAM,CAAA,CAGrD,KAAK,MAAA,CAAS,IAAIgC,EAElB,IAAA,CAAK,eAAA,CAAkB,IAAID,CAAAA,CAAgB,CACzC,IAAA,CAAM,IAAA,CAAK,OAAO,IAAA,CAClB,UAAA,CAAY,KAAK,MAAA,CAAO,mBAC1B,CAAC,CAAA,CAED,KAAK,IAAA,CAAO,IAAIQ,CAAAA,CAAW,IAAA,CAAK,OAAO,MAAM,CAAA,CAE7C,IAAA,CAAK,YAAA,CAAe,IAAI6E,CAAAA,CAAsB,IAAA,CAAK,OAAO,IAAA,CAAM,IAAA,CAAK,OAAO,QAAQ,CAAA,CAEpF,IAAA,CAAK,SAAA,CAAY,IAAIoB,CAAAA,CAAU,IAAA,CAAK,OAAO,IAAA,CAAM,IAAA,CAAK,OAAO,QAAQ,CAAA,CAErE,IAAA,CAAK,gBAAA,CAAmB,IAAIO,CAAAA,CAAiB,IAAA,CAAK,OAAO,IAAA,CAAM,IAAA,CAAK,OAAO,QAAQ,EACrF,CA5BA,IAAI,cAA6B,CAC/B,OAAO,KAAK,MACd,CAiCA,MAAM,UAAA,EAA4B,CAChC,GAAI,IAAA,CAAK,YACP,OAIF,IAAMqD,EAAa,IAAA,CAAK,MAAA,CAAO,YAAY,UAAA,CAC3C,IAAA,CAAK,UAAA,CAAa,MAAMH,GAAW,IAAA,CAAK,MAAA,CAAO,OAAQ,IAAA,CAAK,gBAAA,CAAkBG,CAAU,CAAA,CACxF,IAAA,CAAK,YAAA,CAAe,MAAMH,GAAW,IAAA,CAAK,MAAA,CAAO,OAAQ,IAAA,CAAK,MAAA,CAAO,SAAUG,CAAU,CAAA,CAGzF,IAAA,CAAK,YAAA,CAAe,IAAIxG,CAAAA,CACtB,IAAA,CAAK,MAAA,CAAO,MAAA,CACZ,KAAK,MAAA,CAAO,OAAA,CACZ,IAAA,CAAK,UAAA,CACL,KAAK,YACP,CAAA,CAGA,KAAK,YAAA,CAAe,IAAIuF,EAAa,CACnC,IAAA,CAAM,IAAA,CAAK,MAAA,CAAO,KAClB,OAAA,CAAS,IAAA,CAAK,OAAO,OAAA,CACrB,QAAA,CAAU,KAAK,MAAA,CAAO,QAAA,CACtB,UAAA,CAAY,IAAA,CAAK,WACjB,YAAA,CAAc,IAAA,CAAK,aACnB,kBAAA,CAAoB,IAAA,CAAK,OAAO,kBAAA,CAChC,YAAA,CAAc,IAAA,CAAK,MACrB,CAAC,CAAA,CAGD,IAAA,CAAK,cAAgB,IAAII,CAAAA,CAAc,CACrC,OAAA,CAAS,IAAA,CAAK,MAAA,CAAO,OAAA,CACrB,KAAM,IAAA,CAAK,MAAA,CAAO,KAClB,QAAA,CAAU,IAAA,CAAK,OAAO,QAAA,CACtB,UAAA,CAAY,IAAA,CAAK,UAAA,CACjB,aAAc,IAAA,CAAK,YAAA,CACnB,aAAc,IAAA,CAAK,MAAA,CACnB,UAAW,IAAA,CAAK,MAAA,CAAO,SACzB,CAAC,EAGD,IAAA,CAAK,iBAAA,CAAoB,IAAIH,CAAAA,CAAkB,CAC7C,KAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAClB,QAAA,CAAU,KAAK,MAAA,CAAO,QACxB,CAAC,CAAA,CAGD,KAAK,YAAA,CAAe,IAAIE,CAAAA,CAAa,CACnC,KAAM,IAAA,CAAK,MAAA,CAAO,KAClB,QAAA,CAAU,IAAA,CAAK,OAAO,QACxB,CAAC,CAAA,CAGD,IAAMe,EAAiB,IAAIP,CAAAA,CAAe,CACxC,IAAA,CAAM,IAAA,CAAK,OAAO,IACpB,CAAC,CAAA,CAGD,IAAA,CAAK,eAAiB,IAAIE,CAAAA,CAAe,CACvC,YAAA,CAAc,IAAA,CAAK,aACnB,cAAA,CAAAK,CACF,CAAC,CAAA,CAGD,MAAM,IAAA,CAAK,YAAA,CAAa,sBAAqB,CAE7C,IAAA,CAAK,YAAc,KACrB,CAKQ,iBAAA,EAA0B,CAChC,GAAI,CAAC,IAAA,CAAK,YACR,MAAM,IAAIpM,EACR,iBAAA,CACA,oDACF,CAEJ,CAOA,MAAM,QAAA,EAA2C,CAC/C,IAAMuH,CAAAA,CAAY,MAAM,KAAK,eAAA,CAAgB,QAAA,CAAS,IAAA,CAAK,gBAAgB,EAG3E,OAAA,IAAA,CAAK,YAAA,CAAa,aAAaA,CAAS,CAAA,CACxC,KAAK,cAAA,CAAe,YAAA,CAAaA,CAAS,CAAA,CAEnCA,CACT,CAeA,MAAM,sBACJnH,CAAAA,CACiC,CACjC,KAAK,iBAAA,EAAkB,CAEvB,IAAMmH,CAAAA,CAAY,MAAM,IAAA,CAAK,QAAA,GAGvB8E,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,YAAA,EAAa,CAGxC1E,CAAAA,CAAQvH,EAAQ,KAAA,EAAS,gBAAA,CAGzB0E,EAAY,MAAM,IAAA,CAAK,aAAa,iBAAA,CAAkB,CAC1D,WAAA,CAAa1E,CAAAA,CAAQ,YACrB,YAAA,CAAciM,CAAAA,CAAS,aACvB,KAAA,CAAA1E,CAAAA,CACA,WAAY,IAAA,CAAK,MAAA,CAAO,eAC1B,CAAC,EAGKX,CAAAA,CAAS,IAAA,CAAK,aAAa,qBAAA,CAAsBO,CAAAA,CAAWzC,EAAWuH,CAAAA,CAAUjM,CAAO,CAAA,CAG9F,OAAA,IAAA,CAAK,OAAO,IAAA,CAAK,kBAAA,CAAoB,CACnC,GAAA,CAAK4G,CAAAA,CAAO,IACZ,SAAA,CAAW,IAAA,CAAK,GAAA,EAAI,CACpB,OAAQ,MAAA,CACR,WAAA,CAAalC,EAAU,WACzB,CAAC,EAEMkC,CACT,CAWA,MAAM,cAAA,CAAea,EAAwC,CAC3D,IAAA,CAAK,mBAAkB,CAGvB,GAAM,CAAE,IAAA,CAAA3H,CAAAA,CAAM,KAAA,CAAAiE,CAAM,EAAI,IAAA,CAAK,YAAA,CAAa,aAAA,CAAc0D,CAAW,EAG7D/C,CAAAA,CAAY,MAAM,IAAA,CAAK,YAAA,CAAa,wBAAwBX,CAAK,CAAA,CACjES,EAAcE,CAAAA,CAAU,WAAA,CAG9B,KAAK,MAAA,CAAO,IAAA,CAAK,eAAA,CAAiB,CAChC,KAAA5E,CAAAA,CACA,KAAA,CAAAiE,EACA,SAAA,CAAW,IAAA,CAAK,KAAI,CACpB,MAAA,CAAQ,MAAA,CACR,WAAA,CAAAS,CACF,CAAC,CAAA,CAGD,KAAK,MAAA,CAAO,IAAA,CAAK,2BAA4B,CAC3C,KAAA,CAAAT,CAAAA,CACA,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,OAAQ,MAAA,CACR,WAAA,CAAAS,CACF,CAAC,CAAA,CAED,GAAI,CAEF,IAAM2C,CAAAA,CAAY,MAAM,KAAK,QAAA,EAAS,CAGhC6C,EAAS,MAAM,IAAA,CAAK,YAAA,CAAa,YAAA,CAAa7C,EAAW,CAC7D,IAAA,CAAArH,EACA,KAAA,CAAAiE,CAAAA,CACA,YAAaW,CAAAA,CAAU,WAAA,CACvB,YAAA,CAAcA,CAAAA,CAAU,aACxB,KAAA,CAAOA,CAAAA,CAAU,MACjB,KAAA,CAAOA,CAAAA,CAAU,KACnB,CAAC,CAAA,CAGD,OAAA,MAAM,IAAA,CAAK,aAAa,UAAA,CAAWsF,CAAM,CAAA,CAGzC,IAAA,CAAK,OAAO,IAAA,CAAK,wBAAA,CAA0B,CACzC,OAAA,CAAS,GACT,SAAA,CAAW,IAAA,CAAK,KAAI,CACpB,MAAA,CAAQ,OACR,WAAA,CAAAxF,CACF,CAAC,CAAA,CAEMwF,CACT,CAAA,MAAS/J,CAAAA,CAAO,CAEd,MAAA,IAAA,CAAK,MAAA,CAAO,KAAK,wBAAA,CAA0B,CACzC,OAAA,CAAS,KAAA,CACT,UAAW,IAAA,CAAK,GAAA,GAChB,MAAA,CAAQ,MAAA,CACR,YAAAuE,CACF,CAAC,CAAA,CACKvE,CACR,CACF,CAaA,IAAI,KAAM,CACR,OAAO,CAOL,IAAA,CAAM,MAAOD,CAAAA,EAA8D,CACzE,KAAK,iBAAA,EAAkB,CACvB,IAAMmH,CAAAA,CAAY,MAAM,KAAK,QAAA,EAAS,CAGhC8E,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,YAAA,GAC3B1E,CAAAA,CAAQvH,CAAAA,CAAQ,OAAS,gBAAA,CACzB0E,CAAAA,CAAY,MAAM,IAAA,CAAK,aAAa,iBAAA,CAAkB,CAC1D,YAAa1E,CAAAA,CAAQ,WAAA,CACrB,aAAciM,CAAAA,CAAS,YAAA,CACvB,KAAA,CAAA1E,CAAAA,CACA,WAAY,IAAA,CAAK,MAAA,CAAO,eAC1B,CAAC,EAGD,OAAO,IAAA,CAAK,SAAA,CAAU,wBAAA,CAAyBJ,EAAW,CACxD,WAAA,CAAanH,EAAQ,WAAA,CACrB,KAAA,CAAAuH,EACA,KAAA,CAAO7C,CAAAA,CAAU,KAAA,CACjB,KAAA,CAAOA,EAAU,KAAA,CACjB,aAAA,CAAeuH,EAAS,aAAA,CACxB,mBAAA,CAAqB,OACrB,MAAA,CAAQjM,CAAAA,CAAQ,MAAA,CAChB,SAAA,CAAWA,EAAQ,SAAA,CACnB,SAAA,CAAWA,EAAQ,SAAA,CACnB,WAAA,CAAaA,EAAQ,WACvB,CAAC,CACH,CAAA,CAQA,sBAAuB,MAAOwI,CAAAA,EAAwC,CACpE,IAAMrB,CAAAA,CAAY,MAAM,IAAA,CAAK,QAAA,EAAS,CACtC,OAAO,KAAK,SAAA,CAAU,4BAAA,CAA6BA,EAAWqB,CAAU,CAC1E,EAOA,WAAA,CAAa,SAEJ,CAAC,CAAA,CADU,MAAM,IAAA,CAAK,QAAA,IACV,qCAAA,CAQrB,UAAA,CAAY,UACQ,MAAM,IAAA,CAAK,QAAA,EAAS,EACrB,wCAA0C,IAE/D,CACF,CAYA,IAAI,UAAA,EAAa,CACf,OAAO,CAOL,KAAA,CAAO,MAAOxI,GAA+D,CAC3E,IAAA,CAAK,mBAAkB,CACvB,IAAMmH,EAAY,MAAM,IAAA,CAAK,QAAA,EAAS,CACtC,OAAO,IAAA,CAAK,gBAAA,CAAiB,yBAAyBA,CAAAA,CAAWnH,CAAO,CAC1E,CAAA,CAQA,QAAA,CAAU,MAAO+D,CAAAA,EAA0D,CACzE,IAAMoD,CAAAA,CAAY,MAAM,IAAA,CAAK,QAAA,GAC7B,OAAO,IAAA,CAAK,gBAAA,CAAiB,QAAA,CAASA,EAAWpD,CAAK,CACxD,EASA,iBAAA,CAAmB,MACjBA,EACA/D,CAAAA,GACsB,CACtB,IAAMmH,CAAAA,CAAY,MAAM,IAAA,CAAK,QAAA,GACvB6C,CAAAA,CAAS,MAAM,KAAK,gBAAA,CAAiB,iBAAA,CAAkB7C,CAAAA,CAAWpD,CAAAA,CAAO/D,CAAO,CAAA,CAGtF,OAAA,MAAM,KAAK,YAAA,CAAa,UAAA,CAAWgK,CAAM,CAAA,CAElCA,CACT,CAAA,CAOA,WAAA,CAAa,SAEJ,CAAC,CAAA,CADU,MAAM,IAAA,CAAK,QAAA,IACV,6BAEvB,CACF,CAkBA,IAAI,MAAO,CAGT,GAAI,CADmB,IAAA,CAAK,MAAA,CAAO,OACf,mBAAA,CAClB,OAIG,IAAA,CAAK,WAAA,GAER,KAAK,WAAA,CAAc,IAAId,CAAAA,CACrB,IAAA,CAAK,OAAO,MACd,CAAA,CAAA,CAGF,IAAMgD,CAAAA,CAAU,KAAK,WAAA,CAErB,OAAO,CAIL,UAAA,CAAY,IAAMA,EAAQ,UAAA,EAAW,CAKrC,aAAA,CAAe,IAAMA,EAAQ,aAAA,EAAc,CAU3C,cAAe,CACb9C,CAAAA,CACAC,EACArJ,CAAAA,GACGkM,CAAAA,CAAQ,aAAA,CAAc9C,CAAAA,CAAQC,EAAKrJ,CAAO,CAAA,CAO/C,oBAAsBuE,CAAAA,EAAkB2H,CAAAA,CAAQ,oBAAoB3H,CAAK,CAAA,CAQzE,wBAAA,CAA2BqF,CAAAA,EACzBsC,EAAQ,wBAAA,CAAyBtC,CAAW,EAK9C,eAAA,CAAiB,IAAMsC,EAAQ,eAAA,EAAgB,CAK/C,aAAA,CAAe,IAAMA,EAAQ,aAAA,EAAc,CAK3C,MAAO,IAAMA,CAAAA,CAAQ,OAAM,CAO3B,iBAAA,CAAmB,SAA8B,CAC/C,IAAM/E,CAAAA,CAAY,MAAM,KAAK,QAAA,EAAS,CACtC,OAAO,KAAA,CAAM,OAAA,CAAQA,CAAAA,CAAU,iCAAiC,GAC9DA,CAAAA,CAAU,iCAAA,CAAkC,OAAS,CACzD,CACF,CACF,CASA,IAAI,KAAA,EAAQ,CACV,YAAK,iBAAA,EAAkB,CAChB,CAIL,cAAA,CAAgB,IAAM,IAAA,CAAK,YAAA,CAAa,cAAA,EAAe,CAKvD,UAAW,IAAM,IAAA,CAAK,aAAa,SAAA,EAAU,CAK7C,WAAY,IAAM,IAAA,CAAK,YAAA,CAAa,UAAA,GAKpC,eAAA,CAAiB,IAAM,KAAK,YAAA,CAAa,eAAA,GAczC,QAAA,CAAU,MAAOiB,CAAAA,GAEf,MAAM,KAAK,QAAA,EAAS,CACb,KAAK,YAAA,CAAa,aAAA,CAAcA,CAAO,CAAA,CAAA,CAahD,UAAA,CAAY,MAAOpI,CAAAA,EAAoE,CACrF,IAAMmH,CAAAA,CAAY,MAAM,IAAA,CAAK,QAAA,GAC7B,OAAO,IAAA,CAAK,iBAAA,CAAkB,UAAA,CAAWA,EAAWnH,CAAO,CAC7D,EAWA,MAAA,CAAQ,MAAOA,GAA+C,CAC5D,IAAMmH,CAAAA,CAAY,MAAM,KAAK,QAAA,EAAS,CACtC,OAAO,IAAA,CAAK,YAAA,CAAa,OAAOA,CAAAA,CAAWnH,CAAO,CACpD,CACF,CACF,CASA,IAAI,SAAU,CACZ,OAAA,IAAA,CAAK,mBAAkB,CAChB,CAIL,eAAA,CAAiB,IAAM,KAAK,cAAA,CAAe,eAAA,EAAgB,CAK3D,KAAA,CAAO,IAAM,IAAA,CAAK,cAAA,CAAe,YAAA,EACnC,CACF,CAOA,MAAM,iBAAoC,CACxC,OAAA,IAAA,CAAK,mBAAkB,CAChB,IAAA,CAAK,YAAA,CAAa,eAAA,EAC3B,CAOA,MAAM,SAA6B,CACjC,OAAA,IAAA,CAAK,mBAAkB,CAChB,IAAA,CAAK,cAAA,CAAe,OAAA,EAC7B,CAcA,MAAM,OAAOA,CAAAA,CAAgD,CAC3D,KAAK,iBAAA,EAAkB,CAEvB,IAAImH,CAAAA,CAA0C,KAC9C,GAAI,CACFA,EAAY,MAAM,IAAA,CAAK,WACzB,CAAA,KAAQ,CAER,CAEA,OAAO,IAAA,CAAK,aAAA,CAAc,OAAOA,CAAAA,CAAWnH,CAAO,CACrD,CAcA,mBAAA,CAAoBkH,CAAAA,CAAwC,CAC1D,KAAK,gBAAA,CAAmBA,CAAAA,CAGxB,KAAK,YAAA,CAAa,mBAAA,CAAoBA,CAAM,EAC9C,CAUA,sBAAA,EAAwC,CACtC,OAAO,IAAA,CAAK,gBAAA,EAAkB,wBAAuB,EAAK,IAC5D,CAaA,EAAA,CAA+BtF,CAAAA,CAAUC,CAAAA,CAA6C,CACpF,OAAO,IAAA,CAAK,MAAA,CAAO,GAAGD,CAAAA,CAAOC,CAAO,CACtC,CASA,IAAA,CAAiCD,CAAAA,CAAUC,CAAAA,CAA6C,CACtF,OAAO,IAAA,CAAK,OAAO,IAAA,CAAKD,CAAAA,CAAOC,CAAO,CACxC,CAQA,GAAA,CAAgCD,CAAAA,CAAUC,EAAuC,CAC/E,IAAA,CAAK,OAAO,GAAA,CAAID,CAAAA,CAAOC,CAAO,EAChC,CACF,EAWA,eAAsBsK,GAAoBxM,CAAAA,CAAqD,CAC7F,IAAMyM,CAAAA,CAAS,IAAIN,EAAcnM,CAAM,CAAA,CACvC,OAAA,MAAMyM,CAAAA,CAAO,YAAW,CACjBA,CACT,CC1wBA,IAAMC,EAAAA,CAAoC,IAAI,GAAA,CAAI,CAChD,gBAAA,CACA,sBAAA,CACA,mBACA,4BACF,CAAC,EAQYC,CAAAA,CAAN,KAAwB,CAC7B,WAAA,CAA6BrF,CAAAA,CAAkB,CAAlB,IAAA,CAAA,QAAA,CAAAA,EAAmB,CAahD,kBAAA,CACEE,EACAzC,CAAAA,CACA0C,CAAAA,CACApH,EACqB,CACrB,IAAMqH,CAAAA,CAAWF,CAAAA,CAAU,uBACrBG,CAAAA,CAAS,IAAI,gBAGnBA,CAAAA,CAAO,GAAA,CAAI,YAAa,IAAA,CAAK,QAAQ,CAAA,CACrCA,CAAAA,CAAO,IAAI,eAAA,CAAiBtH,CAAAA,CAAQ,YAAA,EAAgB,MAAM,EAC1DsH,CAAAA,CAAO,GAAA,CAAI,cAAA,CAAgBtH,CAAAA,CAAQ,WAAW,CAAA,CAC9CsH,CAAAA,CAAO,IAAI,OAAA,CAAS5C,CAAAA,CAAU,KAAK,CAAA,CACnC4C,CAAAA,CAAO,GAAA,CAAI,OAAA,CAAS5C,EAAU,KAAK,CAAA,CAGnC4C,EAAO,GAAA,CAAI,QAAA,CAAU,MAAM,CAAA,CAG3BA,CAAAA,CAAO,GAAA,CAAI,gBAAA,CAAkBF,EAAK,aAAa,CAAA,CAC/CE,EAAO,GAAA,CAAI,uBAAA,CAAyBF,EAAK,mBAAmB,CAAA,CAG5D,IAAMG,CAAAA,CAAQvH,EAAQ,KAAA,EAAS,QAAA,CAY/B,GAXAsH,CAAAA,CAAO,GAAA,CAAI,QAASC,CAAK,CAAA,CAGrBvH,CAAAA,CAAQ,SAAA,EACVsH,EAAO,GAAA,CAAI,YAAA,CAActH,EAAQ,SAAS,CAAA,CAExCA,EAAQ,WAAA,EACVsH,CAAAA,CAAO,GAAA,CAAI,eAAA,CAAiBtH,EAAQ,WAAW,CAAA,CAI7CA,EAAQ,WAAA,CAAa,CACvB,IAAMwH,CAAAA,CAAkB,IAAI,GAAA,CAAI,CAC9B,YACA,eAAA,CACA,cAAA,CACA,QACA,OAAA,CACA,gBAAA,CACA,wBACA,OAAA,CACA,QACF,CAAC,CAAA,CAED,OAAW,CAAC7C,CAAAA,CAAKS,CAAK,CAAA,GAAK,MAAA,CAAO,QAAQpF,CAAAA,CAAQ,WAAW,CAAA,CACvDwH,CAAAA,CAAgB,IAAI7C,CAAAA,CAAI,WAAA,EAAa,CAAA,EAGzC2C,CAAAA,CAAO,IAAI3C,CAAAA,CAAKS,CAAK,EAEzB,CAIA,IAAMwB,CAAAA,CAA8B,CAAE,IAF1B,CAAA,EAAGS,CAAQ,IAAIC,CAAAA,CAAO,QAAA,EAAU,CAAA,CAEF,EAE1C,OAAItH,CAAAA,CAAQ,cACV4G,CAAAA,CAAO,KAAA,CAAQlC,EAAU,KAAA,CACzBkC,CAAAA,CAAO,KAAA,CAAQlC,CAAAA,CAAU,OAGpBkC,CACT,CAWA,wBAAwB2F,CAAAA,CAOtB,CACA,IAAI7E,CAAAA,CAGA6E,CAAAA,CAAY,QAAA,CAAS,GAAG,EAI1B7E,CAAAA,CAAAA,CAHY6E,CAAAA,CAAY,WAAW,MAAM,CAAA,CACrC,IAAI,GAAA,CAAIA,CAAW,CAAA,CACnB,IAAI,IAAIA,CAAAA,CAAa,qBAAqB,GAC3B,YAAA,CAEnB7E,CAAAA,CAAe,IAAI,eAAA,CAAgB6E,CAAW,CAAA,CAIhD,IAAMtM,EAAQyH,CAAAA,CAAa,GAAA,CAAI,OAAO,CAAA,CACtC,GAAIzH,EAAO,CACT,IAAM0H,CAAAA,CAAmBD,CAAAA,CAAa,IAAI,mBAAmB,CAAA,CACvDiB,CAAAA,CAAY,IAAA,CAAK,mBAAmB1I,CAAK,CAAA,CAE/C,OAAO,CACL,QAAS,KAAA,CACT,KAAA,CAAO,IAAIL,CAAAA,CAAa+I,CAAAA,CAAWhB,GAAoB,IAAA,CAAK,sBAAA,CAAuB1H,CAAK,CAAA,CAAG,CACzF,OAAA,CAAS,CACP,MAAAA,CAAAA,CACA,iBAAA,CAAmB0H,EACnB,SAAA,CAAWD,CAAAA,CAAa,GAAA,CAAI,WAAW,CACzC,CACF,CAAC,CACH,CACF,CAGA,IAAM5H,CAAAA,CAAO4H,CAAAA,CAAa,GAAA,CAAI,MAAM,EAC9B3D,CAAAA,CAAQ2D,CAAAA,CAAa,IAAI,OAAO,CAAA,CAEtC,OAAK5H,CAAAA,CAMAiE,CAAAA,CAOE,CAAE,OAAA,CAAS,KAAM,IAAA,CAAAjE,CAAAA,CAAM,MAAAiE,CAAM,CAAA,CAN3B,CACL,OAAA,CAAS,KAAA,CACT,KAAA,CAAO,IAAInE,EAAa,eAAA,CAAiB,mDAAmD,CAC9F,CAAA,CATO,CACL,QAAS,KAAA,CACT,KAAA,CAAO,IAAIA,CAAAA,CAAa,eAAgB,sDAAsD,CAChG,CAUJ,CAQA,0BAAA,CAA2BK,EAA8B,CACvD,OAAOoM,EAAAA,CAAkC,GAAA,CAAIpM,EAAM,IAAI,CACzD,CAKQ,kBAAA,CACNA,CAAAA,CAC+G,CAC/G,OAAIoM,EAAAA,CAAkC,GAAA,CAAIpM,CAAK,EACtCA,CAAAA,CAEF,aACT,CAKQ,sBAAA,CAAuBA,CAAAA,CAAuB,CACpD,OAAQA,CAAAA,EACN,KAAK,iBACH,OAAO,4CAAA,CACT,KAAK,sBAAA,CACH,OAAO,4BACT,KAAK,kBAAA,CACH,OAAO,uBAAA,CACT,KAAK,4BAAA,CACH,OAAO,8BACT,QACE,OAAO,8BACX,CACF,CACF,ECrPA,eAAsBuM,EACpBC,CAAAA,CACAxF,CAAAA,CACAW,EAC2B,CAC3B,IAAMU,EAAkC,EAAC,CACnCoE,CAAAA,CAAqC,GAE3C,OAAQD,CAAAA,CAAY,QAClB,KAAK,sBAAuB,CAE1B,IAAME,CAAAA,CAAqB,IAAA,CAAK,GAAG1F,CAAQ,CAAA,CAAA,EAAIwF,EAAY,YAAY,CAAA,CAAE,EACzEnE,CAAAA,CAAQ,aAAA,CAAmB,CAAA,MAAA,EAASqE,CAAkB,GACtD,KACF,CAEA,KAAK,oBAAA,CAAsB,CAEzBD,EAAW,SAAA,CAAezF,CAAAA,CAC1ByF,CAAAA,CAAW,aAAA,CAAmBD,EAAY,YAAA,CAC1C,KACF,CAEA,KAAK,kBAAmB,CAEtB,IAAMhI,CAAAA,CAAM,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,GAAQ,GAAI,CAAA,CAElC+E,EAAgC,CACpC,GAAA,CAAKvC,CAAAA,CACL,GAAA,CAAKA,EACL,GAAA,CAAKW,CAAAA,CACL,IAAKgF,EAAAA,EAAY,CACjB,IAAKnI,CAAAA,CAAM,GAAA,CACX,GAAA,CAAKA,CACP,EAEIoI,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAY,MAAMJ,EAAY,OAAA,CAAQjD,CAAM,EAC9C,CAAA,MAASvJ,EAAO,CACd,MAAM,IAAIL,CAAAA,CACR,+BAAA,CACA,sCACA,CAAE,KAAA,CAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAAU,CACtD,CACF,CAEAyM,CAAAA,CAAW,UAAezF,CAAAA,CAC1ByF,CAAAA,CAAW,qBAAA,CAA2B,wDAAA,CACtCA,EAAW,gBAAA,CAAsBG,CAAAA,CACjC,KACF,CAEA,KAAK,OAAQ,CAGX,GAAI,EAAE,0BAAA,GAA8BJ,IAAgBA,CAAAA,CAAY,wBAAA,GAA6B,KAC3F,MAAM,IAAI7M,EACR,sBAAA,CACA,6EACF,CAAA,CAEF8M,CAAAA,CAAW,UAAezF,CAAAA,CAC1B,KACF,CAEA,QAAS,CAEP,IAAM6F,CAAAA,CAAqBL,CAAAA,CAC3B,MAAM,IAAI7M,CAAAA,CACR,+BAAA,CACA,yCAA0CkN,CAAAA,CAAkC,MAAM,EACpF,CACF,CACF,CAEA,OAAO,CAAE,OAAA,CAAAxE,CAAAA,CAAS,WAAAoE,CAAW,CAC/B,CAOA,SAASE,EAAAA,EAAsB,CAC7B,OAAI,OAAO,MAAA,CAAW,GAAA,EAAe,OAAO,UAAA,CACnC,MAAA,CAAO,YAAW,CAGpB,CAAA,EAAG,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,SAAA,CAAU,CAAA,CAAG,EAAE,CAAC,CAAA,CACrE,KCzEaG,EAAAA,CAAN,KAA8B,CAKnC,WAAA,CAAY/M,CAAAA,CAAyC,CACnD,IAAA,CAAK,KAAOA,CAAAA,CAAQ,IAAA,CACpB,KAAK,QAAA,CAAWA,CAAAA,CAAQ,SACxB,IAAA,CAAK,WAAA,CAAcA,CAAAA,CAAQ,YAC7B,CAUA,MAAM,QAAA,CACJmH,EACAnH,CAAAA,CACmB,CACnB,IAAM4H,CAAAA,CAAgBT,CAAAA,CAAU,cAAA,CAG1B,CAAE,QAAS6F,CAAAA,CAAa,UAAA,CAAYC,CAAe,CAAA,CACvD,MAAMT,CAAAA,CAA0B,IAAA,CAAK,WAAA,CAAa,IAAA,CAAK,SAAU5E,CAAa,CAAA,CAG1EC,EAAO,IAAI,eAAA,CAAgB,CAC/B,UAAA,CAAY,oBAAA,CACZ,GAAGoF,CACL,CAAC,CAAA,CAWD,GARIjN,GAAS,KAAA,EACX6H,CAAAA,CAAK,IAAI,OAAA,CAAS7H,CAAAA,CAAQ,KAAK,CAAA,CAE7BA,GAAS,QAAA,EACX6H,CAAAA,CAAK,IAAI,UAAA,CAAY7H,CAAAA,CAAQ,QAAQ,CAAA,CAInCA,CAAAA,EAAS,WAAA,CAAa,CACxB,IAAMwH,CAAAA,CAAkB,IAAI,IAAI,CAC9B,YAAA,CACA,YACA,eAAA,CACA,kBAAA,CACA,uBAAA,CACA,OAAA,CACA,UACF,CAAC,CAAA,CAED,OAAW,CAAC7C,CAAAA,CAAKS,EAAK,CAAA,GAAK,MAAA,CAAO,OAAA,CAAQpF,CAAAA,CAAQ,WAAW,CAAA,CACvDwH,CAAAA,CAAgB,IAAI7C,CAAAA,CAAI,WAAA,EAAa,CAAA,EAGzCkD,CAAAA,CAAK,GAAA,CAAIlD,CAAAA,CAAKS,EAAK,EAEvB,CAGA,IAAMkD,CAAAA,CAAkC,CACtC,eAAgB,mCAAA,CAChB,GAAG0E,CACL,CAAA,CAGIxL,EACJ,GAAI,CACFA,EAAW,MAAM,IAAA,CAAK,KAAK,KAAA,CAAqBoG,CAAAA,CAAe,CAC7D,MAAA,CAAQ,OACR,OAAA,CAAAU,CAAAA,CACA,KAAMT,CAAAA,CAAK,QAAA,EACb,CAAC,EACH,CAAA,MAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,EAAa,eAAA,CAAiB,yCAAA,CAA2C,CACjF,KAAA,CAAOK,CAAAA,YAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,EAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,EAAS,IAAA,CAC3B,MAAM,IAAI5B,CAAAA,CAAa,0BAAA,CAA4B,0CAA2C,CAC5F,OAAA,CAAS,CACP,MAAA,CAAQ4B,EAAS,MAAA,CACjB,KAAA,CAAOsG,GAAW,KAAA,CAClB,iBAAA,CAAmBA,GAAW,iBAChC,CACF,CAAC,CACH,CAEA,IAAMC,CAAAA,CAAgBvG,EAAS,IAAA,CAGzBiD,CAAAA,CAAM,KAAK,KAAA,CAAM,IAAA,CAAK,GAAA,EAAI,CAAI,GAAI,CAAA,CAClCwD,CAAAA,CAAYF,EAAc,UAAA,CAAatD,CAAAA,CAAMsD,EAAc,UAAA,CAAatD,CAAAA,CAAM,IAAA,CAYpF,OAR2B,CACzB,WAAA,CAAasD,CAAAA,CAAc,YAAA,CAC3B,SAAA,CAAYA,EAAc,UAAA,EAA2B,QAAA,CACrD,SAAA,CAAAE,CAAAA,CACA,aAAcF,CAAAA,CAAc,aAAA,CAC5B,MAAOA,CAAAA,CAAc,KACvB,CAGF,CACF,ECtIO,IAAMmF,EAAAA,CAAN,KAAiB,CAGtB,WAAA,CAAYvN,EAA0B,CACpC,IAAA,CAAK,OAASA,EAChB,CASA,MAAM,kBAAA,CAAmBK,EAA6C,CACpE,IAAMyE,EAAM,IAAA,CAAK,KAAA,CAAM,KAAK,GAAA,EAAI,CAAI,GAAI,CAAA,CAClC0I,EAAW,IAAA,CAAK,MAAA,CAAO,UAAY,GAAA,CAGnCrH,CAAAA,CAAkC,CACtC,GAAA,CAAK,IAAA,CAAK,MAAA,CAAO,SAAA,EAAa,QAC9B,GAAA,CAAK,qBACP,EAEI,IAAA,CAAK,MAAA,CAAO,QACdA,CAAAA,CAAO,GAAA,CAAS,IAAA,CAAK,MAAA,CAAO,OAI9B,IAAM0D,CAAAA,CAAiC,CACrC,GAAA,CAAKxJ,CAAAA,CAAQ,SACb,GAAA,CAAKA,CAAAA,CAAQ,MAAA,CACb,aAAA,CAAeA,EAAQ,YAAA,EAAgB,MAAA,CACvC,UAAWA,CAAAA,CAAQ,QAAA,CACnB,aAAcA,CAAAA,CAAQ,WAAA,CACtB,KAAA,CAAOA,CAAAA,CAAQ,MACf,KAAA,CAAOA,CAAAA,CAAQ,KAAA,CACf,KAAA,CAAOA,EAAQ,KAAA,CACf,cAAA,CAAgBA,CAAAA,CAAQ,aAAA,CACxB,sBAAuBA,CAAAA,CAAQ,mBAAA,CAC/B,IAAKyE,CAAAA,CACL,GAAA,CAAKA,EAAM0I,CAAAA,CACX,GAAA,CAAK,IAAA,CAAK,WAAA,EACZ,CAAA,CAcA,GAXInN,EAAQ,MAAA,GACVwJ,CAAAA,CAAO,OAASxJ,CAAAA,CAAQ,MAAA,CAAA,CAEtBA,CAAAA,CAAQ,SAAA,GACVwJ,EAAO,UAAA,CAAaxJ,CAAAA,CAAQ,WAE1BA,CAAAA,CAAQ,SAAA,GACVwJ,EAAO,UAAA,CAAaxJ,CAAAA,CAAQ,SAAA,CAAA,CAI1BA,CAAAA,CAAQ,YAAa,CACvB,IAAMoN,EAAkB,IAAI,GAAA,CAAI,CAC9B,KAAA,CACA,KAAA,CACA,eAAA,CACA,WAAA,CACA,eACA,OAAA,CACA,OAAA,CACA,QACA,gBAAA,CACA,uBAAA,CACA,MACA,KAAA,CACA,KAAA,CACA,KACF,CAAC,EAED,IAAA,GAAW,CAACzI,EAAKS,CAAK,CAAA,GAAK,OAAO,OAAA,CAAQpF,CAAAA,CAAQ,WAAW,CAAA,CACtDoN,EAAgB,GAAA,CAAIzI,CAAG,IAC1B6E,CAAAA,CAAO7E,CAAG,EAAIS,CAAAA,EAGpB,CAGA,GAAI,CACF,OAAO,MAAM,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQU,EAAQ0D,CAAM,CACjD,CAAA,MAASvJ,CAAAA,CAAO,CACd,MAAM,IAAIL,EACR,mBAAA,CACA,mCAAA,CACA,CAAE,KAAA,CAAOK,CAAAA,YAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAAU,CACtD,CACF,CACF,CAKQ,WAAA,EAAsB,CAC5B,OAAI,OAAO,MAAA,CAAW,GAAA,EAAe,OAAO,UAAA,CACnC,MAAA,CAAO,YAAW,CAEpB,CAAA,EAAG,KAAK,GAAA,EAAK,CAAA,CAAA,EAAI,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,SAAA,CAAU,EAAG,EAAE,CAAC,CAAA,CACrE,CACF,EAQO,SAASoN,EAAAA,CAAclG,EAAiE,CAC7F,OAAOA,EAAU,6BAAA,GAAkC,IACrD,CC9GO,IAAMmG,GAAN,KAAoB,CAGzB,YAAY3N,CAAAA,CAA6B,CACvC,KAAK,MAAA,CAASA,EAChB,CAYA,MAAM,iBACJwH,CAAAA,CACA3F,CAAAA,CACAxB,EAC+B,CAC/B,IAAMuN,EAAYvN,CAAAA,CAAQ,gBAAA,EAAoB,EAAA,CAG1CwJ,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAS,MAAM,IAAA,CAAK,MAAA,CAAO,UAAUhI,CAAAA,CAAU2F,CAAAA,CAAU,MAAM,EACjE,OAASlH,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CACR,yBACA,0CAAA,CACA,CAAE,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAAU,CACtD,CACF,CAGA,GAAIuJ,CAAAA,CAAO,GAAA,GAAQrC,CAAAA,CAAU,MAAA,CAC3B,MAAM,IAAIvH,CAAAA,CACR,wBACA,sDAAA,CACA,CACE,QAAS,CACP,QAAA,CAAUuH,CAAAA,CAAU,MAAA,CACpB,OAAQqC,CAAAA,CAAO,GACjB,CACF,CACF,CAAA,CAKF,GAAI,CAAA,CADa,KAAA,CAAM,OAAA,CAAQA,CAAAA,CAAO,GAAG,CAAA,CAAIA,CAAAA,CAAO,IAAM,CAACA,CAAAA,CAAO,GAAG,CAAA,EACvD,QAAA,CAASxJ,CAAAA,CAAQ,QAAQ,EACrC,MAAM,IAAIJ,EACR,uBAAA,CACA,iDAAA,CACA,CACE,OAAA,CAAS,CACP,QAAA,CAAUI,CAAAA,CAAQ,SAClB,MAAA,CAAQwJ,CAAAA,CAAO,GACjB,CACF,CACF,EAIF,IAAM/E,CAAAA,CAAM,IAAA,CAAK,KAAA,CAAM,KAAK,GAAA,EAAI,CAAI,GAAI,CAAA,CACxC,GAAI+E,CAAAA,CAAO,GAAA,EAAOA,CAAAA,CAAO,GAAA,CAAM+D,EAAY9I,CAAAA,CACzC,MAAM,IAAI7E,CAAAA,CACR,uBAAA,CACA,2BACF,CAAA,CAIF,GAAI4J,CAAAA,CAAO,GAAA,EAAOA,EAAO,GAAA,CAAM+D,CAAAA,CAAY9I,EACzC,MAAM,IAAI7E,EACR,uBAAA,CACA,oCACF,CAAA,CAIF,GAAI4J,EAAO,KAAA,CACT,MAAM,IAAI5J,CAAAA,CAAa,aAAA,CAAe4J,EAAO,iBAAA,EAAqBA,CAAAA,CAAO,KAAA,CAAO,CAC9E,QAAS,CACP,KAAA,CAAOA,EAAO,KAAA,CACd,iBAAA,CAAmBA,EAAO,iBAAA,CAC1B,SAAA,CAAWA,CAAAA,CAAO,SACpB,CACF,CAAC,CAAA,CAIH,GAAI,CAACA,CAAAA,CAAO,MACV,MAAM,IAAI5J,CAAAA,CACR,uBAAA,CACA,sCACF,CAAA,CAEF,GAAI,CAACwG,CAAAA,CAAgBoD,CAAAA,CAAO,MAAOxJ,CAAAA,CAAQ,aAAa,CAAA,CACtD,MAAM,IAAIJ,CAAAA,CACR,uBAAA,CACA,mDACF,CAAA,CAIF,GAAI,CAAC4J,CAAAA,CAAO,IAAA,CACV,MAAM,IAAI5J,EACR,uBAAA,CACA,6CACF,CAAA,CAGF,OAAO,CACL,IAAA,CAAM4J,CAAAA,CAAO,IAAA,CACb,KAAA,CAAOA,EAAO,KAChB,CACF,CAUA,OAAO,2BAAA,CAA4B/B,EAAoC,CACrE,IAAIC,CAAAA,CAEJ,OAAID,EAAY,QAAA,CAAS,GAAG,EAI1BC,CAAAA,CAAAA,CAHYD,CAAAA,CAAY,WAAW,MAAM,CAAA,CACrC,IAAI,GAAA,CAAIA,CAAW,CAAA,CACnB,IAAI,IAAIA,CAAAA,CAAa,qBAAqB,GAC3B,YAAA,CAEnBC,CAAAA,CAAe,IAAI,eAAA,CAAgBD,CAAW,CAAA,CAGzCC,CAAAA,CAAa,IAAI,UAAU,CACpC,CACF,EChJO,IAAM8F,CAAAA,CAAN,MAAMA,CAAqB,CAahC,WAAA,CAAYxN,EAA8B,CAZ1C,IAAA,CAAQ,aAAoC,IAAA,CAE5C,IAAA,CAAQ,aAAA,CAAuD,IAAA,CAC/D,KAAQ,eAAA,CAA0C,IAAA,CAClD,KAAQ,SAAA,CAAY,KAAA,CASlB,KAAK,OAAA,CAAU,CACb,gBAAA,CAAkBA,CAAAA,EAAS,kBAAoBwN,CAAAA,CAAqB,yBAAA,CACpE,gBAAiBxN,CAAAA,EAAS,eAAA,EAAmBwN,EAAqB,yBAAA,CAClE,YAAA,CAAcxN,CAAAA,EAAS,YACzB,EACF,CAOA,KAAA,CAAMyN,CAAAA,CAAkC,CAClC,KAAK,SAAA,GAIT,IAAA,CAAK,YAAA,CAAeA,CAAAA,CACpB,KAAK,eAAA,CAAkB,IAAI,gBAC3B,IAAA,CAAK,SAAA,CAAY,KAGjB,IAAA,CAAK,aAAA,CAAgB,WAAA,CAAY,IAAM,CACrC,IAAA,CAAK,eAAA,GAAkB,KAAA,CAAM,IAAM,CAEnC,CAAC,EACH,CAAA,CAAG,IAAA,CAAK,QAAQ,eAAe,CAAA,CAG/B,KAAK,eAAA,EAAgB,CAAE,MAAM,IAAM,CAEnC,CAAC,CAAA,EACH,CAKA,IAAA,EAAa,CACN,KAAK,SAAA,GAIV,IAAA,CAAK,UAAY,KAAA,CAEb,IAAA,CAAK,aAAA,GACP,aAAA,CAAc,KAAK,aAAa,CAAA,CAChC,KAAK,aAAA,CAAgB,IAAA,CAAA,CAGnB,KAAK,eAAA,GACP,IAAA,CAAK,eAAA,CAAgB,KAAA,GACrB,IAAA,CAAK,eAAA,CAAkB,MAGzB,IAAA,CAAK,YAAA,CAAe,MACtB,CAKA,IAAI,OAAA,EAAmB,CACrB,OAAO,IAAA,CAAK,SACd,CAKA,IAAI,MAAA,EAA6B,CAC/B,OAAO,IAAA,CAAK,eAAA,EAAiB,MAAA,EAAU,IACzC,CAKA,MAAc,iBAAiC,CAC7C,GAAI,GAAC,IAAA,CAAK,YAAA,EAAgB,CAAC,IAAA,CAAK,WAIhC,GAAI,CACF,IAAMzD,CAAAA,CAAS,MAAM,KAAK,YAAA,CAAa,SAAA,EAAU,CACjD,GAAI,CAACA,CAAAA,CACH,OAGF,IAAMvF,CAAAA,CAAM,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,EAAI,CAAI,GAAI,EACtBuF,CAAAA,CAAO,SAAA,CAAYvF,GAGpB,IAAA,CAAK,OAAA,CAAQ,kBAAoBuF,CAAAA,CAAO,YAAA,EAEvD,MAAM,IAAA,CAAK,aAAa,OAAA,GAE5B,MAAgB,CAGhB,CACF,CAKA,MAAM,UAAA,EAA4B,CAChC,MAAM,KAAK,eAAA,GACb,CACF,CAAA,CAvHawD,CAAAA,CAQa,0BAA4B,EAAA,CARzCA,CAAAA,CAWa,yBAAA,CAA4B,GAAA,KAXzCE,EAAAA,CAANF,MCkDMG,EAAAA,CAAN,KAA6B,CAGlC,WAAA,CAAY3N,CAAAA,CAAwC,CAClD,IAAA,CAAK,OAASA,CAAAA,CAAQ,OACxB,CAWA,MAAM,SAAA,CAAUsH,EAAyD,CAEvE,IAAIsG,CAAAA,CAAOtG,CAAAA,CAAO,KAClB,GAAI,CAACsG,CAAAA,CAAM,CACT,IAAMC,CAAAA,CAAY,MAAM,IAAA,CAAK,MAAA,CAAO,YAAY,EAAE,CAAA,CAClDD,EAAOrL,CAAAA,CAAgBsL,CAAS,EAClC,CAIA,IAAMC,CAAAA,CACJxG,CAAAA,CAAO,SAAW,GAAA,CAAMA,CAAAA,CAAO,OAAS,GAAA,CAAMA,CAAAA,CAAO,eAAiBsG,CAAAA,CAGlEG,CAAAA,CAAY,MAAM,IAAA,CAAK,OAAO,MAAA,CAAOD,CAAS,EAC9CjE,CAAAA,CAAOtH,CAAAA,CAAgBwL,CAAS,CAAA,CAKtC,OAAO,CACL,YAAA,CAHmBlE,EAAO,GAAA,CAAM+D,CAAAA,CAIhC,KAAA/D,CAAAA,CACA,IAAA,CAAA+D,CACF,CACF,CAWA,MAAM,QAAA,CACJI,EACA1G,CAAAA,CACkB,CAClB,IAAMtC,CAAAA,CAAS,IAAA,CAAK,MAAMgJ,CAAY,CAAA,CACtC,GAAI,CAAChJ,EACH,OAAO,MAAA,CAIT,IAAMiJ,CAAAA,CAAa,MAAM,KAAK,SAAA,CAAU,CACtC,GAAG3G,CAAAA,CACH,KAAMtC,CAAAA,CAAO,IACf,CAAC,CAAA,CAGD,OAAOoB,EAAgB6H,CAAAA,CAAW,YAAA,CAAcD,CAAY,CAC9D,CAQA,KAAA,CAAMA,CAAAA,CAA6D,CAYjE,GALI,CAACA,CAAAA,EAAgB,OAAOA,CAAAA,EAAiB,QAAA,EAKzCA,EAAa,MAAA,CAAS,GAAA,CACxB,OAAO,IAAA,CAGT,IAAME,EAAWF,CAAAA,CAAa,WAAA,CAAY,GAAG,CAAA,CAC7C,GAAIE,CAAAA,GAAa,EAAA,EAAMA,IAAa,CAAA,EAAKA,CAAAA,GAAaF,EAAa,MAAA,CAAS,CAAA,CAC1E,OAAO,IAAA,CAGT,IAAMnE,CAAAA,CAAOmE,CAAAA,CAAa,UAAU,CAAA,CAAGE,CAAQ,EACzCN,CAAAA,CAAOI,CAAAA,CAAa,SAAA,CAAUE,CAAAA,CAAW,CAAC,CAAA,CAQhD,GALI,CAACrE,CAAAA,EAAQ,CAAC+D,GAKV/D,CAAAA,CAAK,MAAA,CAAS,GAAA,EAAmB+D,CAAAA,CAAK,OAAS,GAAA,CACjD,OAAO,KAIT,IAAMO,CAAAA,CAAiB,mBACvB,OAAI,CAACA,CAAAA,CAAe,IAAA,CAAKtE,CAAI,CAAA,EAAK,CAACsE,EAAe,IAAA,CAAKP,CAAI,EAClD,IAAA,CAGF,CAAE,IAAA,CAAA/D,CAAAA,CAAM,KAAA+D,CAAK,CACtB,CACF,EChHO,IAAMQ,GAAN,KAAmC,CAQxC,KAAA,CACEpO,CAAAA,CACAsH,EAC6B,CAC7B,IAAMgC,CAAAA,CAAM,IAAI,IAAItJ,CAAAA,CAAQ,SAAS,CAAA,CAC/BqO,CAAAA,CAAyC,EAAC,CAEhD,OAAIrO,EAAQ,aAAA,EAAiBsH,CAAAA,CAAO,MAClCgC,CAAAA,CAAI,YAAA,CAAa,GAAA,CAAI,KAAA,CAAOhC,EAAO,GAAG,CAAA,CACtC+G,EAAa,GAAA,CAAM/G,CAAAA,CAAO,KAGxBtH,CAAAA,CAAQ,gBAAA,EAAoBsH,CAAAA,CAAO,GAAA,GACrCgC,EAAI,YAAA,CAAa,GAAA,CAAI,MAAOhC,CAAAA,CAAO,GAAG,EACtC+G,CAAAA,CAAa,GAAA,CAAM/G,CAAAA,CAAO,GAAA,CAAA,CAGrB,CACL,GAAA,CAAKgC,CAAAA,CAAI,UAAS,CAClB,MAAA,CAAQ+E,CACV,CACF,CAQA,WAAA,CAAY/E,CAAAA,CAA6C,CACvD,IAAMgF,CAAAA,CAAS,OAAOhF,CAAAA,EAAQ,QAAA,CAAW,IAAI,GAAA,CAAIA,CAAG,CAAA,CAAIA,CAAAA,CAClDhC,EAAmC,EAAC,CAEpCiH,EAAMD,CAAAA,CAAO,YAAA,CAAa,IAAI,KAAK,CAAA,CACrCC,CAAAA,GACFjH,CAAAA,CAAO,IAAMiH,CAAAA,CAAAA,CAGf,IAAMC,EAAMF,CAAAA,CAAO,YAAA,CAAa,IAAI,KAAK,CAAA,CACzC,OAAIE,CAAAA,GACFlH,EAAO,GAAA,CAAMkH,CAAAA,CAAAA,CAGRlH,CACT,CAWA,eAAA,CACEgC,EACAmF,CAAAA,CAAgD,EAAC,CACb,CACpC,IAAInH,CAAAA,CAEJ,GAAI,CACFA,CAAAA,CAAS,IAAA,CAAK,YAAYgC,CAAG,EAC/B,CAAA,KAAQ,CACN,OAAO,CACL,KAAA,CAAO,MACP,KAAA,CAAO,oBACT,CACF,CAGA,OAAImF,CAAAA,CAAS,UAAA,EAAc,CAACnH,CAAAA,CAAO,GAAA,CAC1B,CACL,KAAA,CAAO,KAAA,CACP,MAAO,gCACT,CAAA,CAGEmH,CAAAA,CAAS,UAAA,EAAc,CAACnH,CAAAA,CAAO,GAAA,CAC1B,CACL,KAAA,CAAO,KAAA,CACP,MAAO,gCACT,CAAA,CAKEmH,CAAAA,CAAS,MAAA,EAAUnH,EAAO,GAAA,EAAO,CAAClB,EAAgBkB,CAAAA,CAAO,GAAA,CAAKmH,EAAS,MAAM,CAAA,CACxE,CACL,KAAA,CAAO,MACP,KAAA,CAAO,0BACT,EAKEA,CAAAA,CAAS,SAAA,EAAanH,EAAO,GAAA,EAAO,CAAClB,CAAAA,CAAgBkB,CAAAA,CAAO,IAAKmH,CAAAA,CAAS,SAAS,EAC9E,CACL,KAAA,CAAO,MACP,KAAA,CAAO,8BACT,CAAA,CAGK,CACL,MAAO,IAAA,CACP,MAAA,CAAAnH,CACF,CACF,CACF,EC5LA,IAAMoH,EAAAA,CAAiB,CACrB,cACA,cAAA,CACA,SAAA,CACA,QACA,MAAA,CACA,UAAA,CACA,SACA,aAAA,CACA,eAAA,CACA,QAAA,CACA,cAAA,CACA,gBACA,eACF,CAAA,CAKMC,GAAuB,CAC3B,MAAA,CACA,QACA,OAAA,CACA,UAAA,CACA,cAAA,CACA,eAAA,CACA,OACF,CAAA,CAQaC,CAAAA,CAAN,KAAoB,CAKzB,WAAA,CAAY5O,EAA6D,CAJzE,IAAA,CAAQ,OAAA,CAA2B,GAKjC,IAAA,CAAK,SAAA,CAAYA,GAAS,SAAA,EAAa,GAAA,CACvC,KAAK,WAAA,CAAcA,CAAAA,EAAS,WAAA,EAAe,UAC7C,CAWA,MAAA,CACE6K,CAAAA,CACA9I,EACA/B,CAAAA,CACM,CACN,IAAM6O,CAAAA,CAAmB7O,CAAAA,EAAS,MAAA,EAAU,IAAA,CAAK,YAC3C8O,CAAAA,CAAe,IAAA,CAAK,WAAW/M,CAAAA,CAAM8M,CAAgB,EAErDE,CAAAA,CAAuB,CAC3B,IAAA,CAAAlE,CAAAA,CACA,UAAW,IAAA,CAAK,GAAA,GAChB,WAAA,CAAa7K,CAAAA,EAAS,YACtB,IAAA,CAAM8O,CACR,CAAA,CAKA,IAHA,KAAK,OAAA,CAAQ,IAAA,CAAKC,CAAK,CAAA,CAGhB,KAAK,OAAA,CAAQ,MAAA,CAAS,IAAA,CAAK,SAAA,EAChC,KAAK,OAAA,CAAQ,KAAA,GAEjB,CAQA,SAAA,CAAUzJ,EAAiC,CACzC,OAAIA,CAAAA,GAAU,MAAA,CACL,CAAC,GAAG,IAAA,CAAK,OAAO,CAAA,CAElB,IAAA,CAAK,QAAQ,KAAA,CAAM,CAACA,CAAK,CAClC,CAQA,gBAAA,CAAiBd,CAAAA,CAAsC,CACrD,OAAO,IAAA,CAAK,QAAQ,MAAA,CAAQuK,CAAAA,EAAUA,CAAAA,CAAM,WAAA,GAAgBvK,CAAW,CACzE,CAQA,UAAUqG,CAAAA,CAA+B,CACvC,OAAO,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAQkE,CAAAA,EAAUA,EAAM,IAAA,GAASlE,CAAI,CAC3D,CAKA,KAAA,EAAc,CACZ,IAAA,CAAK,OAAA,CAAU,GACjB,CAKA,IAAI,MAAA,EAAiB,CACnB,OAAO,IAAA,CAAK,QAAQ,MACtB,CAKA,MAAA,EAAiB,CACf,OAAO,IAAA,CAAK,SAAA,CAAU,KAAK,OAAA,CAAS,IAAA,CAAM,CAAC,CAC7C,CAKA,cAAA,CAAemE,CAAAA,CAA0B,CACvC,IAAA,CAAK,WAAA,CAAcA,EACrB,CAKQ,WACNjN,CAAAA,CACAiN,CAAAA,CACqC,CAKrC,OAJIA,IAAU,MAAA,EAAUjN,CAAAA,GAAS,QAAaA,CAAAA,GAAS,IAAA,EAInD,OAAOA,CAAAA,EAAS,QAAA,CACXA,CAAAA,CAGQ,IAAA,CAAK,WAAWA,CAAAA,CAAiCiN,CAAK,CAEzE,CAKQ,UAAA,CACNC,EACAD,CAAAA,CACyB,CACzB,IAAMpI,CAAAA,CAAkC,EAAC,CAEzC,IAAA,GAAW,CAACjC,CAAAA,CAAKS,CAAK,IAAK,MAAA,CAAO,OAAA,CAAQ6J,CAAG,CAAA,CAAG,CAC9C,IAAMC,CAAAA,CAAWvK,EAAI,WAAA,EAAY,CAGjC,GAAI,IAAA,CAAK,cAAA,CAAeuK,CAAQ,CAAA,CAAG,CAEjC,IAAMC,CAAAA,CAAiBxK,EAAI,MAAA,CAAO,CAAC,EAAE,WAAA,EAAY,CAAIA,CAAAA,CAAI,KAAA,CAAM,CAAC,CAAA,CAChEiC,CAAAA,CAAO,MAAMuI,CAAc,CAAA,CAAE,EAA2B/J,CAAAA,EAAU,IAAA,CAClEwB,CAAAA,CAAOjC,CAAG,EAAI,YAAA,CACd,QACF,CAGA,GAAIqK,CAAAA,GAAU,cAAgBE,CAAAA,GAAa,KAAA,EAAS,OAAO9J,CAAAA,EAAU,SAAU,CAC7EwB,CAAAA,CAAOjC,CAAG,CAAA,CAAI,IAAA,CAAK,UAAUS,CAAK,CAAA,CAClC,QACF,CAGA,GAAIA,CAAAA,GAAU,IAAA,EAAQ,OAAOA,CAAAA,EAAU,QAAA,EAAY,CAAC,KAAA,CAAM,OAAA,CAAQA,CAAK,CAAA,CAAG,CACxEwB,CAAAA,CAAOjC,CAAG,EAAI,IAAA,CAAK,UAAA,CAAWS,EAAkC4J,CAAK,CAAA,CACrE,QACF,CAGA,GAAI,KAAA,CAAM,OAAA,CAAQ5J,CAAK,CAAA,CAAG,CACxBwB,EAAOjC,CAAG,CAAA,CAAIS,CAAAA,CAAM,GAAA,CAAKgK,GACnBA,CAAAA,GAAS,IAAA,EAAQ,OAAOA,CAAAA,EAAS,QAAA,CAC5B,KAAK,UAAA,CAAWA,CAAAA,CAAiCJ,CAAK,CAAA,CAExDI,CACR,CAAA,CACD,QACF,CAGAxI,CAAAA,CAAOjC,CAAG,EAAIS,EAChB,CAEA,OAAOwB,CACT,CAKQ,cAAA,CAAejC,CAAAA,CAAsB,CAC3C,OAAO+J,EAAAA,CAAe,KACnBW,CAAAA,EAAc1K,CAAAA,GAAQ0K,CAAAA,CAAU,WAAA,IAAiB1K,CAAAA,CAAI,QAAA,CAAS0K,EAAU,WAAA,EAAa,CACxF,CACF,CAKQ,SAAA,CAAU/F,CAAAA,CAAqB,CACrC,GAAI,CACF,IAAMtE,CAAAA,CAAS,IAAI,GAAA,CAAIsE,CAAG,CAAA,CAE1B,IAAA,IAAWgG,KAASX,EAAAA,CACd3J,CAAAA,CAAO,aAAa,GAAA,CAAIsK,CAAK,GAC/BtK,CAAAA,CAAO,YAAA,CAAa,GAAA,CAAIsK,CAAAA,CAAO,YAAY,CAAA,CAK/C,GAAItK,EAAO,IAAA,CAAM,CACf,IAAMuK,CAAAA,CAAa,IAAI,eAAA,CAAgBvK,CAAAA,CAAO,KAAK,KAAA,CAAM,CAAC,CAAC,CAAA,CACvDwK,CAAAA,CAAe,GAEnB,IAAA,IAAWF,CAAAA,IAASX,EAAAA,CACdY,CAAAA,CAAW,IAAID,CAAK,CAAA,GACtBC,EAAW,GAAA,CAAID,CAAAA,CAAO,YAAY,CAAA,CAClCE,CAAAA,CAAe,CAAA,CAAA,CAAA,CAIfA,CAAAA,GACFxK,EAAO,IAAA,CAAO,GAAA,CAAMuK,EAAW,QAAA,EAAS,EAE5C,CAEA,OAAOvK,CAAAA,CAAO,QAAA,EAChB,MAAQ,CAEN,OAAOsE,EAAI,OAAA,CAAQ,wCAAA,CAA0C,iBAAiB,CAChF,CACF,CACF,EC5PO,SAASmG,EAAAA,CAAoBzP,CAAAA,CAEpB,CACd,IAAM0P,CAAAA,CAAoB1P,GAAS,UAAA,EAAc,KAAA,CAEjD,OAAO,CACL,IAAIgP,CAAAA,CAAsBjP,CAAAA,CAAiBgC,CAAAA,CAAsB,CAC/D,IAAMmD,CAAAA,CAASwK,CAAAA,CACX,CAAA,SAAA,EAAYV,CAAAA,CAAM,aAAa,CAAA,CAAA,EAAI,IAAI,IAAA,EAAK,CAAE,aAAa,CAAA,CAAA,CAAA,CAC3D,CAAA,SAAA,EAAYA,CAAAA,CAAM,aAAa,CAAA,CAAA,CAAA,CAE7BW,EAAgBX,CAAAA,GAAU,OAAA,CAAU,MAAQA,CAAAA,CAG5CY,CAAAA,CAAa,OAAO,OAAA,CAAY,IAAc,OAAA,CAAU,IAAA,CACzDA,IAED7N,CAAAA,GAAS,MAAA,CACX6N,EAAWD,CAAa,CAAA,GAAIzK,CAAAA,CAAQnF,CAAAA,CAASgC,CAAI,CAAA,CAEjD6N,CAAAA,CAAWD,CAAa,CAAA,GAAIzK,CAAAA,CAAQnF,CAAO,CAAA,EAE/C,CACF,CACF,KAKa8P,EAAAA,CAA0B,CACrC,KAAY,CAEZ,CACF,EAKO,SAASC,EAAAA,CAAkB9P,CAAAA,CAAoC,CACpE,OAAKA,CAAAA,CAAQ,OAAA,CAITA,EAAQ,MAAA,CACHA,CAAAA,CAAQ,OAGVyP,EAAAA,CAAoB,CACzB,UAAA,CAAYzP,CAAAA,CAAQ,aACtB,CAAC,CAAA,CATQ6P,EAUX,CAKO,IAAME,EAAN,KAAmB,CAKxB,WAAA,CAAY7I,CAAAA,CAAqBlH,EAAiC,CAFlE,IAAA,CAAQ,WAAA,CAA6B,IAAA,CAGnC,KAAK,MAAA,CAASkH,CAAAA,CACd,IAAA,CAAK,OAAA,CAAUlH,GAAS,OAAA,EAAW,MACrC,CAKA,cAAA,CAAegQ,CAAAA,CAAyB,CACtC,IAAA,CAAK,WAAA,CAAcA,EACrB,CAKA,gBAAgC,CAC9B,OAAO,KAAK,WACd,CAKA,MAAMjQ,CAAAA,CAAiBgC,CAAAA,CAAsB,CACvC,IAAA,CAAK,SACP,IAAA,CAAK,MAAA,CAAO,IAAI,OAAA,CAAS,IAAA,CAAK,cAAchC,CAAO,CAAA,CAAGgC,CAAI,EAE9D,CAKA,IAAA,CAAKhC,CAAAA,CAAiBgC,EAAsB,CAC1C,IAAA,CAAK,OAAO,GAAA,CAAI,MAAA,CAAQ,IAAA,CAAK,aAAA,CAAchC,CAAO,CAAA,CAAGgC,CAAI,EAC3D,CAKA,IAAA,CAAKhC,EAAiBgC,CAAAA,CAAsB,CAC1C,IAAA,CAAK,MAAA,CAAO,IAAI,MAAA,CAAQ,IAAA,CAAK,cAAchC,CAAO,CAAA,CAAGgC,CAAI,EAC3D,CAKA,KAAA,CAAMhC,CAAAA,CAAiBgC,EAAsB,CAC3C,IAAA,CAAK,OAAO,GAAA,CAAI,OAAA,CAAS,KAAK,aAAA,CAAchC,CAAO,CAAA,CAAGgC,CAAI,EAC5D,CAKQ,aAAA,CAAchC,EAAyB,CAC7C,OAAI,KAAK,WAAA,CACA,CAAA,CAAA,EAAI,IAAA,CAAK,WAAA,CAAY,MAAM,CAAA,CAAG,CAAC,CAAC,CAAA,EAAA,EAAKA,CAAO,GAE9CA,CACT,CACF,ECoCO,IAAMkQ,EAAN,KAAoD,CAQzD,YAAYjQ,CAAAA,CAAkC,CAF9C,KAAQ,IAAA,CAA6B,EAAC,CAGpC,IAAA,CAAK,oBAAsB,IAAA,CAAK,iBAAA,GAChC,IAAA,CAAK,OAAA,CAAUA,EAAQ,OAAA,CACvB,IAAA,CAAK,WAAA,CAAcA,CAAAA,CAAQ,YAC3B,IAAA,CAAK,WAAA,CAAcA,EAAQ,WAAA,EAAe,KAAA,CAC1C,KAAK,OAAA,CAAUA,CAAAA,CAAQ,OAAA,EAAW,IACpC,CAQA,sBAAA,EAAiC,CAC/B,OAAO,IAAA,CAAK,mBACd,CAKA,SAAA,EAAqB,CACnB,OAAO,IAAA,CAAK,OACd,CAKA,kBAAA,CAAmBA,EAQV,CACP,GAAI,CAAC,IAAA,CAAK,OAAA,CAAS,OAEnB,IAAM+O,EAAiC,CACrC,EAAA,CAAI,KAAK,eAAA,EAAgB,CACzB,oBAAqB,IAAA,CAAK,mBAAA,CAC1B,QAAA,CAAU,kBAAA,CACV,MAAO/O,CAAAA,CAAQ,MAAA,GAAW,MAAA,CAAS,OAAA,CAAU,QAC7C,SAAA,CAAW,IAAA,CAAK,GAAA,EAAI,CACpB,KAAMA,CAAAA,CAAQ,IAAA,CACd,UAAWA,CAAAA,CAAQ,SAAA,CACnB,OAAQA,CAAAA,CAAQ,MAAA,CAChB,QAAA,CAAUA,CAAAA,CAAQ,SAClB,MAAA,CAAQA,CAAAA,CAAQ,OAChB,YAAA,CAAcA,CAAAA,CAAQ,aACtB,OAAA,CAASA,CAAAA,CAAQ,OACnB,CAAA,CAEA,KAAK,QAAA,CAAS+O,CAAK,EACrB,CAKA,eAAA,CAAgB/O,EAKP,CACP,GAAI,CAAC,IAAA,CAAK,QAAS,OAEnB,IAAM+O,EAA8B,CAClC,EAAA,CAAI,KAAK,eAAA,EAAgB,CACzB,mBAAA,CAAqB,IAAA,CAAK,oBAC1B,QAAA,CAAU,eAAA,CACV,MAAO/O,CAAAA,CAAQ,QAAA,GAAa,OAAS,MAAA,CAAS,MAAA,CAC9C,SAAA,CAAW,IAAA,CAAK,KAAI,CACpB,QAAA,CAAUA,EAAQ,QAAA,CAClB,MAAA,CAAQA,EAAQ,MAAA,CAChB,IAAA,CAAMA,CAAAA,CAAQ,IAAA,CACd,QAASA,CAAAA,CAAQ,OACnB,EAEA,IAAA,CAAK,QAAA,CAAS+O,CAAK,EACrB,CAKA,OAAA,EAAgC,CAC9B,OAAO,CAAC,GAAG,IAAA,CAAK,IAAI,CACtB,CAKA,UAAA,EAAqB,CACnB,OAAO,KAAK,SAAA,CAAU,IAAA,CAAK,KAAM,IAAA,CAAM,CAAC,CAC1C,CAKA,SAAA,EAAkB,CAChB,IAAA,CAAK,KAAO,GACd,CAKQ,QAAA,CAASA,CAAAA,CAAiC,CAE5C,IAAA,CAAK,WAAA,EACP,IAAA,CAAK,WAAA,CAAY,IAAIA,CAAAA,CAAM,KAAA,CAAO,gBAAgBA,CAAAA,CAAM,QAAQ,GAAIA,CAAK,CAAA,CAIvE,IAAA,CAAK,WAAA,GACP,KAAK,IAAA,CAAK,IAAA,CAAKA,CAAK,CAAA,CAGhB,IAAA,CAAK,KAAK,MAAA,CAAS,IAAA,CAAK,OAAA,EAC1B,IAAA,CAAK,KAAK,KAAA,EAAM,EAGtB,CAKQ,iBAAA,EAA4B,CAElC,OAAI,OAAO,MAAA,CAAW,GAAA,EAAe,MAAA,CAAO,WACnC,MAAA,CAAO,UAAA,GAIT,sCAAA,CAAuC,OAAA,CAAQ,QAAUmB,CAAAA,EAAM,CACpE,IAAMC,CAAAA,CAAK,KAAK,MAAA,EAAO,CAAI,GAAM,CAAA,CAEjC,OAAA,CADUD,IAAM,GAAA,CAAMC,CAAAA,CAAKA,CAAAA,CAAI,CAAA,CAAO,GAC7B,QAAA,CAAS,EAAE,CACtB,CAAC,CACH,CAKQ,eAAA,EAA0B,CAChC,OAAO,GAAG,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,UAAU,CAAA,CAAG,CAAC,CAAC,CAAA,CACpE,CACF,EAQO,SAASC,EAAAA,CACdpQ,CAAAA,CACyB,CACzB,OAAKA,CAAAA,CAAQ,OAAA,CAIN,IAAIiQ,CAAAA,CAAiBjQ,CAAO,EAH1B,IAIX,CCpTA,eAAsBqQ,EAAAA,CACpBC,EACAnO,CAAAA,CACiB,CAEjB,IAAM0H,CAAAA,CAAO,MAAM1H,EAAO,MAAA,CAAOmO,CAAY,CAAA,CAGvCC,CAAAA,CAAW1G,EAAK,KAAA,CAAM,CAAA,CAAGA,EAAK,MAAA,CAAS,CAAC,EAG9C,OAAOtH,CAAAA,CAAgBgO,CAAQ,CACjC,CCzBO,SAASC,EAAAA,CACdC,EACA3H,CAAAA,CACY,CACZ,OAAO,IAAI,OAAA,CAAQ,CAACC,CAAAA,CAASC,IAAW,CACtC,IAAM0H,EAAiB,IAAI9Q,CAAAA,CACzB,sBACA,yBACF,CAAA,CAGA,GAAIkJ,CAAAA,CAAO,QAAS,CAClBE,CAAAA,CAAO0H,CAAc,CAAA,CACrB,MACF,CAEA,IAAMC,CAAAA,CAAU,IAAM,CACpB3H,EAAO0H,CAAc,EACvB,EAEA5H,CAAAA,CAAO,gBAAA,CAAiB,QAAS6H,CAAAA,CAAS,CAAE,IAAA,CAAM,IAAK,CAAC,CAAA,CAExDF,CAAAA,CACG,KAAK1H,CAAO,CAAA,CACZ,MAAMC,CAAM,CAAA,CACZ,OAAA,CAAQ,IAAM,CACbF,CAAAA,CAAO,mBAAA,CAAoB,QAAS6H,CAAO,EAC7C,CAAC,EACL,CAAC,CACH,CAWO,SAASC,EAAAA,CACdC,CAAAA,CAKA,CACA,IAAMC,CAAAA,CAAa,IAAI,eAAA,CAEvB,OAAO,CACL,OAAA,CAASD,EAAGC,CAAAA,CAAW,MAAM,EAC7B,MAAA,CAAQ,IAAMA,EAAW,KAAA,EAAM,CAC/B,MAAA,CAAQA,CAAAA,CAAW,MACrB,CACF,CAKO,SAASC,EAAAA,CAAoB9Q,CAAAA,CAAyB,CAC3D,OAAOA,CAAAA,YAAiBL,CAAAA,EAAgBK,CAAAA,CAAM,OAAS,qBACzD,CAUA,eAAsB+Q,EAAAA,CACpBC,CAAAA,CAIY,CACZ,GAAI,CACF,IAAMrK,CAAAA,CAAS,MAAM,OAAA,CAAQ,IAAA,CAAKqK,CAAAA,CAAW,GAAA,CAAKC,GAAOA,CAAAA,CAAG,OAAO,CAAC,CAAA,CAEpE,OAAAD,CAAAA,CAAW,OAAA,CAASC,GAAOA,CAAAA,CAAG,MAAA,EAAQ,CAAA,CAC/BtK,CACT,CAAA,MAAS3G,CAAAA,CAAO,CAEd,MAAAgR,CAAAA,CAAW,QAASC,CAAAA,EAAOA,CAAAA,CAAG,QAAQ,CAAA,CAChCjR,CACR,CACF,CCzEA,IAAMkR,EAAAA,CAA4F,CAChG,UAAA,CAAY,CAAA,CACZ,YAAa,GAAA,CACb,UAAA,CAAY,GAAA,CACZ,MAAA,CAAQ,IACV,CAAA,CAWO,SAASC,GACd3G,CAAAA,CACA4G,CAAAA,CACAC,EACAnH,CAAAA,CACQ,CAER,IAAMoH,CAAAA,CAAmBF,EAAc,IAAA,CAAK,GAAA,CAAI,EAAG5G,CAAO,CAAA,CAGpD+G,EAAc,IAAA,CAAK,GAAA,CAAID,CAAAA,CAAkBD,CAAU,EAGzD,GAAInH,CAAAA,CAAQ,CACV,IAAMsH,CAAAA,CAAcD,EAAc,EAAA,CAC5BE,CAAAA,CAAc,IAAA,CAAK,MAAA,GAAWD,CAAAA,CAAcA,CAAAA,CAAc,EAChE,OAAO,IAAA,CAAK,IAAI,CAAA,CAAG,IAAA,CAAK,KAAA,CAAMD,CAAAA,CAAcE,CAAW,CAAC,CAC1D,CAEA,OAAOF,CACT,CAQO,SAASG,EAAAA,CAAM9I,CAAAA,CAAYC,CAAAA,CAAqC,CACrE,OAAO,IAAI,QAAQ,CAACC,CAAAA,CAASC,IAAW,CACtC,GAAIF,CAAAA,EAAQ,OAAA,CAAS,CACnBE,CAAAA,CAAO,IAAIpJ,EAAa,qBAAA,CAAuB,qBAAqB,CAAC,CAAA,CACrE,MACF,CAEA,IAAMqJ,EAAU,UAAA,CAAWF,CAAAA,CAASF,CAAE,CAAA,CAEtC,GAAIC,EAAQ,CACV,IAAM6H,CAAAA,CAAU,IAAM,CACpB,YAAA,CAAa1H,CAAO,EACpBD,CAAAA,CAAO,IAAIpJ,EAAa,qBAAA,CAAuB,qBAAqB,CAAC,EACvE,EACAkJ,CAAAA,CAAO,gBAAA,CAAiB,QAAS6H,CAAAA,CAAS,CAAE,KAAM,IAAK,CAAC,EAC1D,CACF,CAAC,CACH,CASA,eAAsBiB,EAAAA,CACpBf,CAAAA,CACA7Q,EACY,CACZ,IAAM6R,CAAAA,CAAO,CAAE,GAAGV,EAAAA,CAAuB,GAAGnR,CAAQ,CAAA,CAC9C,CAAE,WAAA8R,CAAAA,CAAY,WAAA,CAAAT,CAAAA,CAAa,UAAA,CAAAC,EAAY,MAAA,CAAAnH,CAAAA,CAAQ,MAAA,CAAArB,CAAAA,CAAQ,YAAAiJ,CAAAA,CAAa,OAAA,CAAAC,CAAQ,CAAA,CAAIH,EAElFI,CAAAA,CAEJ,IAAA,IAASxH,EAAU,CAAA,CAAGA,CAAAA,EAAWqH,EAAYrH,CAAAA,EAAAA,CAC3C,GAAI,CAEF,GAAI3B,GAAQ,OAAA,CACV,MAAM,IAAIlJ,CAAAA,CAAa,qBAAA,CAAuB,yBAAyB,CAAA,CAGzE,OAAO,MAAMiR,CAAAA,EACf,CAAA,MAAS5Q,CAAAA,CAAO,CAId,GAHAgS,CAAAA,CAAYhS,EAGR8Q,EAAAA,CAAoB9Q,CAAK,CAAA,CAC3B,MAAMA,EAIR,IAAMiS,CAAAA,CAAWH,EACbA,CAAAA,CAAY9R,CAAAA,CAAOwK,CAAO,CAAA,CAC1BxK,CAAAA,YAAiBL,CAAAA,EAAgBa,CAAAA,CAAiBR,CAAK,CAAA,CAG3D,GAAIwK,GAAWqH,CAAAA,EAAc,CAACI,EAC5B,MAAMjS,CAAAA,CAIR,IAAMkS,CAAAA,CAAUf,GAAsB3G,CAAAA,CAAS4G,CAAAA,CAAaC,EAAYnH,CAAM,CAAA,CAG9E6H,IAAU/R,CAAAA,CAAOwK,CAAAA,CAAU,CAAA,CAAG0H,CAAO,EAGrC,MAAMR,EAAAA,CAAMQ,EAASrJ,CAAM,EAC7B,CAIF,MAAMmJ,CACR,CAUO,SAASG,GACdC,CAAAA,CACiE,CACjE,OAAO,CAAIxB,CAAAA,CAAsB7Q,IACxB4R,EAAAA,CAAUf,CAAAA,CAAI,CAAE,GAAGwB,EAAgB,GAAGrS,CAAQ,CAAC,CAE1D,CAUO,SAASsS,EAAAA,CACdhK,CAAAA,CACe,CACf,IAAMiK,EAAajK,CAAAA,YAAmB,OAAA,CAClCA,EAAQ,GAAA,CAAI,aAAa,EACzBA,CAAAA,CAAQ,aAAa,CAAA,EAAKA,CAAAA,CAAQ,aAAa,CAAA,CAEnD,GAAI,CAACiK,CAAAA,CACH,OAAO,KAIT,IAAMC,CAAAA,CAAU,QAAA,CAASD,CAAAA,CAAY,EAAE,CAAA,CACvC,GAAI,CAAC,KAAA,CAAMC,CAAO,EAChB,OAAOA,CAAAA,CAAU,GAAA,CAInB,IAAMC,EAAO,IAAI,IAAA,CAAKF,CAAU,CAAA,CAChC,GAAI,CAAC,KAAA,CAAME,CAAAA,CAAK,OAAA,EAAS,EAAG,CAC1B,IAAMN,EAAUM,CAAAA,CAAK,OAAA,GAAY,IAAA,CAAK,GAAA,EAAI,CAC1C,OAAO,KAAK,GAAA,CAAI,CAAA,CAAGN,CAAO,CAC5B,CAEA,OAAO,IACT","file":"index.cjs","sourcesContent":["/**\n * Client Configuration\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport type { AuthrimStorage } from '../providers/storage.js';\n\n/**\n * Endpoint overrides\n */\nexport interface EndpointOverrides {\n /** Authorization endpoint */\n authorization?: string;\n /** Token endpoint */\n token?: string;\n /** UserInfo endpoint */\n userinfo?: string;\n /** Revocation endpoint */\n revocation?: string;\n /** End session endpoint (null to disable) */\n endSession?: string | null;\n}\n\n/**\n * Hash options for storage key generation\n */\nexport interface HashOptions {\n /**\n * Hash length for storage keys\n *\n * Default: 16 characters (96 bits)\n * Alternative: 22 characters (132 bits) for lower collision risk\n */\n hashLength?: number;\n}\n\n/**\n * Authrim Client Configuration\n */\nexport interface AuthrimClientConfig {\n /**\n * OpenID Connect issuer URL\n *\n * This is used to fetch the discovery document and validate tokens.\n * Trailing slashes are automatically normalized.\n */\n issuer: string;\n\n /**\n * OAuth 2.0 client ID\n */\n clientId: string;\n\n /**\n * HTTP client implementation\n *\n * Required for @authrim/core.\n * @authrim/web provides a default browser implementation.\n */\n http: HttpClient;\n\n /**\n * Crypto provider implementation\n *\n * Required for @authrim/core.\n * @authrim/web provides a default browser implementation.\n */\n crypto: CryptoProvider;\n\n /**\n * Storage provider implementation\n *\n * Required for @authrim/core.\n * @authrim/web provides localStorage/sessionStorage implementations.\n */\n storage: AuthrimStorage;\n\n /**\n * Default redirect URI for authorization requests\n */\n redirectUri?: string;\n\n /**\n * Default scopes to request\n *\n * Default: ['openid', 'profile']\n */\n scopes?: string[];\n\n /**\n * Manual endpoint overrides\n *\n * Use these to override discovery document endpoints.\n * Set endSession to null to disable logout redirect.\n */\n endpoints?: EndpointOverrides;\n\n /**\n * Enable Flow Engine (server-driven UI)\n *\n * Default: false\n * Set to true to enable server-driven UI flows.\n * Note: Both SDK and server must have Flow Engine enabled for it to work.\n */\n flowEngine?: boolean;\n\n /**\n * Discovery cache TTL in milliseconds\n *\n * Default: 3600000 (1 hour)\n */\n discoveryCacheTtlMs?: number;\n\n /**\n * Token refresh skew in seconds\n *\n * Refresh tokens this many seconds before expiration.\n * Default: 30\n */\n refreshSkewSeconds?: number;\n\n /**\n * State/nonce TTL in seconds\n *\n * Default: 600 (10 minutes)\n */\n stateTtlSeconds?: number;\n\n /**\n * Hash options for storage key generation\n */\n hashOptions?: HashOptions;\n}\n\n/**\n * Resolved configuration with defaults applied\n */\nexport interface ResolvedConfig extends Required<\n Omit<AuthrimClientConfig, 'endpoints' | 'redirectUri' | 'hashOptions'>\n> {\n endpoints?: EndpointOverrides;\n redirectUri?: string;\n hashOptions: Required<HashOptions>;\n}\n\n/**\n * Apply defaults to configuration\n */\nexport function resolveConfig(config: AuthrimClientConfig): ResolvedConfig {\n return {\n ...config,\n scopes: config.scopes ?? ['openid', 'profile'],\n flowEngine: config.flowEngine ?? false,\n discoveryCacheTtlMs: config.discoveryCacheTtlMs ?? 3600 * 1000,\n refreshSkewSeconds: config.refreshSkewSeconds ?? 30,\n stateTtlSeconds: config.stateTtlSeconds ?? 600,\n hashOptions: {\n hashLength: config.hashOptions?.hashLength ?? 16,\n },\n };\n}\n","/**\n * Authrim SDK Error Types\n */\n\n/**\n * User action recommended for error recovery\n */\nexport type AuthrimErrorUserAction =\n | 'retry'\n | 'reauthenticate'\n | 'contact_support'\n | 'check_network'\n | 'none';\n\n/**\n * Error severity level (legacy - 3 levels)\n */\nexport type AuthrimErrorSeverity = 'fatal' | 'error' | 'warning';\n\n/**\n * Error remediation action\n *\n * Specifies what action should be taken to recover from an error.\n * Separated from severity for clearer decision making.\n */\nexport type AuthrimErrorRemediation =\n | 'retry' // Retry the same operation\n | 'reauthenticate' // Re-authentication required\n | 'switch_flow' // Switch to different flow (e.g., popup → redirect)\n | 'contact_support' // Contact support\n | 'none'; // No action needed (informational)\n\n/**\n * Error metadata for recovery information\n */\nexport interface AuthrimErrorMeta {\n /** Whether this is a transient error */\n transient: boolean;\n /** Whether automatic retry is possible */\n retryable: boolean;\n /** Suggested retry wait time in milliseconds */\n retryAfterMs?: number;\n /** Maximum number of retry attempts */\n maxRetries?: number;\n /** Recommended user action */\n userAction: AuthrimErrorUserAction;\n /** Error severity level */\n severity: AuthrimErrorSeverity;\n}\n\n/**\n * Error codes used by the SDK\n */\nexport type AuthrimErrorCode =\n // OAuth 2.0 / OIDC standard errors\n | 'invalid_request'\n | 'unauthorized_client'\n | 'access_denied'\n | 'unsupported_response_type'\n | 'invalid_scope'\n | 'server_error'\n | 'temporarily_unavailable'\n | 'invalid_grant'\n | 'invalid_token'\n // SDK-specific errors\n | 'invalid_state'\n | 'expired_state'\n | 'invalid_nonce'\n | 'nonce_mismatch'\n | 'missing_nonce'\n | 'missing_id_token'\n | 'session_expired'\n | 'session_check_failed'\n | 'network_error'\n | 'timeout_error'\n | 'discovery_error'\n | 'discovery_mismatch'\n | 'configuration_error'\n | 'storage_error'\n | 'flow_engine_error'\n // Token errors\n | 'no_tokens'\n | 'token_expired'\n | 'token_error'\n | 'refresh_error'\n | 'token_exchange_error'\n // Callback errors\n | 'oauth_error'\n | 'missing_code'\n | 'missing_state'\n // Initialization errors\n | 'not_initialized'\n | 'no_discovery'\n // Session errors\n | 'no_userinfo_endpoint'\n | 'userinfo_error'\n // Token introspection/revocation errors\n | 'introspection_error'\n | 'revocation_error'\n | 'no_introspection_endpoint'\n | 'no_revocation_endpoint'\n // Silent auth errors (OIDC prompt=none)\n | 'login_required'\n | 'interaction_required'\n | 'consent_required'\n | 'account_selection_required'\n // Browser/Popup auth errors (@authrim/web)\n | 'dom_not_ready'\n | 'state_mismatch'\n | 'popup_blocked'\n | 'popup_closed'\n | 'invalid_response'\n | 'invalid_callback'\n // Direct Auth errors\n | 'passkey_not_found'\n | 'passkey_verification_failed'\n | 'passkey_not_supported'\n | 'passkey_cancelled'\n | 'passkey_invalid_credential'\n | 'email_code_invalid'\n | 'email_code_expired'\n | 'email_code_too_many_attempts'\n | 'challenge_expired'\n | 'challenge_invalid'\n | 'auth_code_invalid'\n | 'auth_code_expired'\n | 'pkce_mismatch'\n | 'origin_not_allowed'\n | 'mfa_required'\n | 'email_verification_required'\n | 'consent_required_direct'\n | 'rate_limited'\n // Event errors\n | 'event_handler_error'\n // PAR errors (RFC 9126)\n | 'par_required'\n | 'no_par_endpoint'\n | 'par_error'\n | 'par_request_uri_expired'\n // Device Flow errors (RFC 8628)\n | 'no_device_authorization_endpoint'\n | 'device_authorization_error'\n | 'device_authorization_pending'\n | 'device_slow_down'\n | 'device_authorization_expired'\n | 'device_access_denied'\n // Client Credentials errors\n | 'client_credentials_error'\n | 'invalid_client_authentication'\n | 'insecure_client_auth'\n // DPoP errors (RFC 9449)\n | 'dpop_key_generation_error'\n | 'dpop_proof_generation_error'\n | 'dpop_nonce_required'\n // JAR errors (RFC 9101)\n | 'jar_signing_error'\n | 'jar_required'\n // JARM errors\n | 'jarm_validation_error'\n | 'jarm_signature_invalid'\n // Operation errors\n | 'operation_cancelled'\n // returnTo errors\n | 'invalid_return_to';\n\n/**\n * Options for creating an AuthrimError\n */\nexport interface AuthrimErrorOptions {\n details?: Record<string, unknown>;\n errorUri?: string;\n cause?: Error;\n}\n\n/**\n * Authrim SDK Error class\n */\nexport class AuthrimError extends Error {\n /** Error code for programmatic handling */\n readonly code: AuthrimErrorCode;\n\n /** Additional error details */\n readonly details?: Record<string, unknown>;\n\n /** OAuth error_uri if provided */\n readonly errorUri?: string;\n\n /** Underlying cause */\n readonly cause?: Error;\n\n constructor(code: AuthrimErrorCode, message: string, options?: AuthrimErrorOptions) {\n super(message);\n this.name = 'AuthrimError';\n this.code = code;\n this.details = options?.details;\n this.errorUri = options?.errorUri;\n this.cause = options?.cause;\n }\n\n /**\n * Create an AuthrimError from an OAuth error response\n */\n static fromOAuthError(error: {\n error: string;\n error_description?: string;\n error_uri?: string;\n }): AuthrimError {\n const oauthCodes = [\n 'invalid_request',\n 'unauthorized_client',\n 'access_denied',\n 'unsupported_response_type',\n 'invalid_scope',\n 'server_error',\n 'temporarily_unavailable',\n 'invalid_grant',\n 'invalid_token',\n ] as const;\n\n type OAuthErrorCode = (typeof oauthCodes)[number];\n\n const code: AuthrimErrorCode = oauthCodes.includes(error.error as OAuthErrorCode)\n ? (error.error as OAuthErrorCode)\n : 'invalid_request';\n\n return new AuthrimError(code, error.error_description ?? error.error, {\n errorUri: error.error_uri,\n details: { originalError: error.error },\n });\n }\n\n /**\n * Check if an error is retryable (e.g., network errors)\n */\n isRetryable(): boolean {\n return this.code === 'network_error' || this.code === 'timeout_error';\n }\n\n /**\n * Get error metadata for recovery guidance\n */\n get meta(): AuthrimErrorMeta {\n return getErrorMeta(this.code);\n }\n}\n\n/**\n * Error metadata mapping for each error code\n */\nconst ERROR_META_MAP: Record<AuthrimErrorCode, AuthrimErrorMeta> = {\n // OAuth 2.0 / OIDC standard errors\n invalid_request: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'error',\n },\n unauthorized_client: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n access_denied: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n unsupported_response_type: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n invalid_scope: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'error',\n },\n server_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 5000,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'error',\n },\n temporarily_unavailable: {\n transient: true,\n retryable: true,\n retryAfterMs: 10000,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'warning',\n },\n invalid_grant: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n invalid_token: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // SDK-specific errors\n invalid_state: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n expired_state: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n invalid_nonce: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n nonce_mismatch: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n missing_nonce: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n missing_id_token: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n session_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n session_check_failed: {\n transient: true,\n retryable: true,\n retryAfterMs: 3000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'warning',\n },\n network_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 3,\n userAction: 'check_network',\n severity: 'error',\n },\n timeout_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 3000,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'warning',\n },\n discovery_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 5000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n discovery_mismatch: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n configuration_error: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n storage_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 1000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n flow_engine_error: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'error',\n },\n\n // Token errors\n no_tokens: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n token_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n token_error: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n refresh_error: {\n transient: false,\n retryable: false,\n retryAfterMs: 0,\n maxRetries: 0,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n token_exchange_error: {\n transient: false,\n retryable: false,\n retryAfterMs: 0,\n maxRetries: 0,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // Callback errors\n oauth_error: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n missing_code: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n missing_state: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // Initialization errors\n not_initialized: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'fatal',\n },\n no_discovery: {\n transient: true,\n retryable: true,\n retryAfterMs: 3000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n\n // Session errors\n no_userinfo_endpoint: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n userinfo_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n\n // Token introspection/revocation errors\n introspection_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n revocation_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n no_introspection_endpoint: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n no_revocation_endpoint: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n\n // Silent auth errors\n login_required: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n interaction_required: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n consent_required: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n account_selection_required: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n\n // Browser/Popup auth errors (@authrim/web)\n dom_not_ready: {\n transient: true,\n retryable: true,\n retryAfterMs: 100,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'error',\n },\n state_mismatch: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n popup_blocked: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n popup_closed: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n invalid_response: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'error',\n },\n invalid_callback: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // Direct Auth errors\n passkey_not_found: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n passkey_verification_failed: {\n transient: false,\n retryable: true,\n retryAfterMs: 1000,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'error',\n },\n passkey_not_supported: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n passkey_cancelled: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n passkey_invalid_credential: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n email_code_invalid: {\n transient: false,\n retryable: true,\n retryAfterMs: 0,\n maxRetries: 5,\n userAction: 'retry',\n severity: 'warning',\n },\n email_code_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n email_code_too_many_attempts: {\n transient: false,\n retryable: false,\n retryAfterMs: 300000,\n userAction: 'retry',\n severity: 'error',\n },\n challenge_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n challenge_invalid: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n auth_code_invalid: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n auth_code_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n pkce_mismatch: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n origin_not_allowed: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n mfa_required: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n email_verification_required: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n consent_required_direct: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n rate_limited: {\n transient: true,\n retryable: true,\n retryAfterMs: 60000,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'warning',\n },\n\n // Event errors\n event_handler_error: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n\n // PAR errors (RFC 9126)\n par_required: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'fatal',\n },\n no_par_endpoint: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n par_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n par_request_uri_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n\n // Device Flow errors (RFC 8628)\n no_device_authorization_endpoint: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n device_authorization_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n device_authorization_pending: {\n transient: true,\n retryable: true,\n retryAfterMs: 5000,\n maxRetries: 60,\n userAction: 'none',\n severity: 'warning',\n },\n device_slow_down: {\n transient: true,\n retryable: true,\n retryAfterMs: 10000,\n maxRetries: 60,\n userAction: 'none',\n severity: 'warning',\n },\n device_authorization_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n device_access_denied: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // Client Credentials errors\n client_credentials_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n invalid_client_authentication: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n insecure_client_auth: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'fatal',\n },\n\n // DPoP errors (RFC 9449)\n dpop_key_generation_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 1000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n dpop_proof_generation_error: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'error',\n },\n dpop_nonce_required: {\n transient: true,\n retryable: true,\n retryAfterMs: 0,\n maxRetries: 1,\n userAction: 'none',\n severity: 'warning',\n },\n\n // JAR errors (RFC 9101)\n jar_signing_error: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'error',\n },\n jar_required: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'fatal',\n },\n\n // JARM errors\n jarm_validation_error: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n jarm_signature_invalid: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // Operation errors\n operation_cancelled: {\n transient: false,\n retryable: true,\n retryAfterMs: 0,\n maxRetries: 1,\n userAction: 'retry',\n severity: 'warning',\n },\n\n // returnTo errors\n invalid_return_to: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'error',\n },\n};\n\n/**\n * Get error metadata for a given error code\n */\nexport function getErrorMeta(code: AuthrimErrorCode): AuthrimErrorMeta {\n return ERROR_META_MAP[code];\n}\n\n/**\n * Error classification result\n */\nexport interface ErrorClassification {\n /** Severity: recoverable or fatal */\n severity: 'recoverable' | 'fatal';\n /** Recommended remediation action */\n remediation: AuthrimErrorRemediation;\n}\n\n/**\n * Classify an error by severity and remediation\n *\n * This provides a simplified 2-axis classification for UI decision making:\n * - severity: Is this recoverable or fatal?\n * - remediation: What action should be taken?\n */\nexport function classifyError(error: AuthrimError): ErrorClassification {\n const meta = error.meta;\n\n // Fatal: not retryable AND user action is contact_support\n if (!meta.retryable && meta.userAction === 'contact_support') {\n return { severity: 'fatal', remediation: 'contact_support' };\n }\n\n // Fatal: severity is 'fatal' in meta\n if (meta.severity === 'fatal') {\n return { severity: 'fatal', remediation: mapUserActionToRemediation(meta.userAction) };\n }\n\n // Recoverable: determine remediation\n let remediation: AuthrimErrorRemediation = 'none';\n\n if (meta.retryable) {\n remediation = 'retry';\n } else if (meta.userAction === 'reauthenticate') {\n remediation = 'reauthenticate';\n } else if (error.code === 'popup_blocked') {\n remediation = 'switch_flow';\n } else if (meta.userAction === 'contact_support') {\n remediation = 'contact_support';\n }\n\n return { severity: 'recoverable', remediation };\n}\n\n/**\n * Map user action to remediation (internal helper)\n */\nfunction mapUserActionToRemediation(userAction: AuthrimErrorUserAction): AuthrimErrorRemediation {\n switch (userAction) {\n case 'retry':\n case 'check_network':\n return 'retry';\n case 'reauthenticate':\n return 'reauthenticate';\n case 'contact_support':\n return 'contact_support';\n case 'none':\n default:\n return 'none';\n }\n}\n\n/**\n * Check if an error is retryable based on classification\n */\nexport function isRetryableError(error: AuthrimError): boolean {\n const classification = classifyError(error);\n return classification.severity === 'recoverable' && classification.remediation === 'retry';\n}\n\n/**\n * Event emitter interface for error emission\n *\n * Minimal interface required by emitClassifiedError\n */\nexport interface ErrorEventEmitter {\n emit(event: 'error', payload: {\n error: AuthrimError;\n severity: 'recoverable' | 'fatal';\n remediation: AuthrimErrorRemediation;\n context: string;\n timestamp: number;\n source: 'core' | 'web';\n operationId?: string;\n }): void;\n emit(event: 'error:recoverable', payload: {\n error: AuthrimError;\n severity: 'recoverable';\n remediation: AuthrimErrorRemediation;\n context: string;\n timestamp: number;\n source: 'core' | 'web';\n operationId?: string;\n }): void;\n emit(event: 'error:fatal', payload: {\n error: AuthrimError;\n severity: 'fatal';\n remediation: AuthrimErrorRemediation;\n context: string;\n timestamp: number;\n source: 'core' | 'web';\n operationId?: string;\n }): void;\n}\n\n/**\n * Options for emitting classified errors\n */\nexport interface EmitClassifiedErrorOptions {\n /** Operation context where the error occurred */\n context: string;\n /** Operation tracking ID */\n operationId?: string;\n /** Event source (defaults to 'core') */\n source?: 'core' | 'web';\n}\n\n/**\n * Emit error events with proper classification\n *\n * Emits three events:\n * 1. 'error' - Legacy event for backward compatibility\n * 2. 'error:recoverable' - If severity is recoverable\n * 3. 'error:fatal' - If severity is fatal\n *\n * @param emitter - Event emitter instance\n * @param error - The error to emit\n * @param options - Emission options (context, operationId, source)\n */\nexport function emitClassifiedError(\n emitter: ErrorEventEmitter,\n error: AuthrimError,\n options: EmitClassifiedErrorOptions\n): void {\n const { severity, remediation } = classifyError(error);\n const timestamp = Date.now();\n const source = options.source ?? 'core';\n\n // Common payload\n const payload = {\n error,\n severity,\n remediation,\n context: options.context,\n timestamp,\n source,\n operationId: options.operationId,\n };\n\n // Legacy error event (backward compatibility)\n emitter.emit('error', payload);\n\n // Severity-specific events\n if (severity === 'recoverable') {\n emitter.emit('error:recoverable', { ...payload, severity: 'recoverable' as const });\n } else {\n emitter.emit('error:fatal', { ...payload, severity: 'fatal' as const });\n }\n}\n","/**\n * OIDC Discovery Client\n *\n * Fetches and caches OIDC Discovery documents from the authorization server.\n * https://openid.net/specs/openid-connect-discovery-1_0.html\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Cached discovery document with timestamp\n */\ninterface CachedDiscovery {\n doc: OIDCDiscoveryDocument;\n fetchedAt: number;\n}\n\n/**\n * Discovery client options\n */\nexport interface DiscoveryClientOptions {\n /** HTTP client for making requests */\n http: HttpClient;\n /** Cache TTL in milliseconds (default: 1 hour) */\n cacheTtlMs?: number;\n}\n\n/**\n * Normalize issuer URL\n *\n * Removes trailing slashes to ensure consistent comparison.\n *\n * @param issuer - Issuer URL\n * @returns Normalized issuer URL\n */\nexport function normalizeIssuer(issuer: string): string {\n return issuer.replace(/\\/+$/, '');\n}\n\n/**\n * OIDC Discovery Client\n */\nexport class DiscoveryClient {\n private readonly http: HttpClient;\n private readonly cacheTtlMs: number;\n private readonly cache: Map<string, CachedDiscovery> = new Map();\n\n /** Default cache TTL: 1 hour */\n private static readonly DEFAULT_CACHE_TTL_MS = 3600 * 1000;\n\n constructor(options: DiscoveryClientOptions) {\n this.http = options.http;\n this.cacheTtlMs = options.cacheTtlMs ?? DiscoveryClient.DEFAULT_CACHE_TTL_MS;\n }\n\n /**\n * Fetch the OIDC Discovery document for an issuer\n *\n * @param issuer - Issuer URL\n * @returns Discovery document\n * @throws AuthrimError if discovery fails or issuer mismatch\n */\n async discover(issuer: string): Promise<OIDCDiscoveryDocument> {\n const normalizedIssuer = normalizeIssuer(issuer);\n const cached = this.cache.get(normalizedIssuer);\n\n // Return cached document if still valid\n if (cached && !this.isExpired(cached)) {\n return cached.doc;\n }\n\n // Fetch discovery document\n const discoveryUrl = `${normalizedIssuer}/.well-known/openid-configuration`;\n\n let doc: OIDCDiscoveryDocument;\n try {\n const response = await this.http.fetch<OIDCDiscoveryDocument>(discoveryUrl);\n if (!response.ok) {\n throw new AuthrimError('discovery_error', `Discovery request failed: ${response.status}`, {\n details: { status: response.status, statusText: response.statusText },\n });\n }\n doc = response.data;\n } catch (error) {\n if (error instanceof AuthrimError) {\n throw error;\n }\n throw new AuthrimError('discovery_error', 'Failed to fetch discovery document', {\n cause: error instanceof Error ? error : undefined,\n details: { url: discoveryUrl },\n });\n }\n\n // Validate issuer matches (security check)\n const docIssuer = normalizeIssuer(doc.issuer);\n if (docIssuer !== normalizedIssuer) {\n throw new AuthrimError(\n 'discovery_mismatch',\n `Issuer mismatch in discovery document: expected \"${normalizedIssuer}\", got \"${docIssuer}\"`,\n {\n details: {\n expected: normalizedIssuer,\n actual: docIssuer,\n },\n }\n );\n }\n\n // Cache the document\n this.cache.set(normalizedIssuer, {\n doc,\n fetchedAt: Date.now(),\n });\n\n return doc;\n }\n\n /**\n * Check if a cached document has expired\n */\n private isExpired(cached: CachedDiscovery): boolean {\n return Date.now() - cached.fetchedAt > this.cacheTtlMs;\n }\n\n /**\n * Clear the discovery cache (useful for testing)\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Clear a specific issuer from the cache\n *\n * @param issuer - Issuer URL to clear\n */\n clearIssuer(issuer: string): void {\n this.cache.delete(normalizeIssuer(issuer));\n }\n}\n","/**\n * Event Emitter\n *\n * Simple typed event emitter for SDK events.\n */\n\nimport type { AuthrimEvents, AuthrimEventName, AuthrimEventHandler } from './types.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Typed Event Emitter\n */\nexport class EventEmitter {\n private listeners: Map<AuthrimEventName, Set<AuthrimEventHandler<AuthrimEventName>>> = new Map();\n\n /**\n * Subscribe to an event\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n */\n on<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as AuthrimEventHandler<AuthrimEventName>);\n\n // Return unsubscribe function\n return () => {\n this.off(event, handler);\n };\n }\n\n /**\n * Subscribe to an event (one-time)\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n */\n once<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): () => void {\n const onceHandler = ((data: AuthrimEvents[T]) => {\n this.off(event, onceHandler);\n handler(data);\n }) as AuthrimEventHandler<T>;\n\n return this.on(event, onceHandler);\n }\n\n /**\n * Unsubscribe from an event\n *\n * @param event - Event name\n * @param handler - Event handler to remove\n */\n off<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.delete(handler as AuthrimEventHandler<AuthrimEventName>);\n if (handlers.size === 0) {\n this.listeners.delete(event);\n }\n }\n }\n\n /**\n * Emit an event\n *\n * @param event - Event name\n * @param data - Event data\n */\n emit<T extends AuthrimEventName>(event: T, data: AuthrimEvents[T]): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(data);\n } catch (error) {\n // Don't throw - one handler failure shouldn't affect others\n // For non-error events, emit an 'error' event\n // For 'error' events, silently ignore to prevent infinite recursion\n if (event !== 'error') {\n const authrimError =\n error instanceof AuthrimError\n ? error\n : new AuthrimError('event_handler_error', 'Event handler threw an error', {\n cause: error instanceof Error ? error : undefined,\n });\n this.emit('error', {\n error: authrimError,\n context: `Error in event handler for '${event}'`,\n });\n }\n // For 'error' event handlers that throw, we silently ignore\n // to maintain platform-agnostic behavior (no console dependency)\n }\n }\n }\n }\n\n /**\n * Remove all listeners for an event (or all events)\n *\n * @param event - Event name (optional, removes all if not specified)\n */\n removeAllListeners(event?: AuthrimEventName): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n\n /**\n * Get the number of listeners for an event\n *\n * @param event - Event name\n * @returns Number of listeners\n */\n listenerCount(event: AuthrimEventName): number {\n return this.listeners.get(event)?.size ?? 0;\n }\n}\n","/**\n * PKCE (Proof Key for Code Exchange) Helper\n *\n * Implements RFC 7636 for Authorization Code Flow security.\n * https://tools.ietf.org/html/rfc7636\n */\n\nimport type { CryptoProvider } from '../providers/crypto.js';\n\n/**\n * PKCE challenge method\n */\nexport type CodeChallengeMethod = 'S256' | 'plain';\n\n/**\n * PKCE pair (verifier and challenge)\n */\nexport interface PKCEPair {\n /** Code verifier (high-entropy random string) */\n codeVerifier: string;\n /** Code challenge (derived from verifier) */\n codeChallenge: string;\n /** Challenge method used */\n codeChallengeMethod: CodeChallengeMethod;\n}\n\n/**\n * PKCE Helper class\n */\nexport class PKCEHelper {\n constructor(private readonly crypto: CryptoProvider) {}\n\n /**\n * Generate a PKCE pair (verifier + challenge)\n *\n * Uses S256 method (SHA-256 hash, base64url-encoded).\n *\n * @returns PKCE pair\n */\n async generatePKCE(): Promise<PKCEPair> {\n const codeVerifier = await this.crypto.generateCodeVerifier();\n const codeChallenge = await this.crypto.generateCodeChallenge(codeVerifier);\n\n return {\n codeVerifier,\n codeChallenge,\n codeChallengeMethod: 'S256',\n };\n }\n\n /**\n * Generate only the code verifier\n *\n * @returns Code verifier string\n */\n async generateCodeVerifier(): Promise<string> {\n return this.crypto.generateCodeVerifier();\n }\n\n /**\n * Generate a code challenge from a verifier\n *\n * @param verifier - Code verifier\n * @returns Code challenge (base64url-encoded SHA-256 hash)\n */\n async generateCodeChallenge(verifier: string): Promise<string> {\n return this.crypto.generateCodeChallenge(verifier);\n }\n}\n","/**\n * Base64URL Encoding/Decoding Utilities\n *\n * Implements RFC 4648 Section 5 (Base64 URL and Filename Safe Alphabet)\n */\n\n/**\n * Encode a Uint8Array to base64url string\n *\n * @param data - Bytes to encode\n * @returns Base64URL encoded string (no padding)\n */\nexport function base64urlEncode(data: Uint8Array): string {\n // Convert to base64\n let base64 = '';\n\n // Use platform-agnostic conversion\n const len = data.length;\n for (let i = 0; i < len; i += 3) {\n const byte1 = data[i];\n const byte2 = i + 1 < len ? data[i + 1] : 0;\n const byte3 = i + 2 < len ? data[i + 2] : 0;\n\n const triplet = (byte1 << 16) | (byte2 << 8) | byte3;\n\n base64 += BASE64_CHARS[(triplet >> 18) & 0x3f];\n base64 += BASE64_CHARS[(triplet >> 12) & 0x3f];\n base64 += i + 1 < len ? BASE64_CHARS[(triplet >> 6) & 0x3f] : '';\n base64 += i + 2 < len ? BASE64_CHARS[triplet & 0x3f] : '';\n }\n\n // Convert to base64url (replace + with -, / with _)\n // Remove padding (=)\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Decode a base64url string to Uint8Array\n *\n * @param str - Base64URL encoded string\n * @returns Decoded bytes\n * @throws Error if the input contains invalid characters\n */\nexport function base64urlDecode(str: string): Uint8Array {\n // Validate input contains only valid base64url characters\n // Valid: A-Z, a-z, 0-9, -, _\n if (!/^[A-Za-z0-9_-]*$/.test(str)) {\n throw new Error('Invalid base64url string: contains invalid characters');\n }\n\n // Convert base64url to base64\n let base64 = str.replace(/-/g, '+').replace(/_/g, '/');\n\n // Add padding if needed\n while (base64.length % 4) {\n base64 += '=';\n }\n\n // Decode base64\n const len = base64.length;\n const paddingLen = base64.endsWith('==') ? 2 : base64.endsWith('=') ? 1 : 0;\n const outputLen = (len * 3) / 4 - paddingLen;\n const output = new Uint8Array(outputLen);\n\n let outputIndex = 0;\n for (let i = 0; i < len; i += 4) {\n const byte1 = BASE64_LOOKUP[base64.charCodeAt(i)];\n const byte2 = BASE64_LOOKUP[base64.charCodeAt(i + 1)];\n const byte3 = BASE64_LOOKUP[base64.charCodeAt(i + 2)];\n const byte4 = BASE64_LOOKUP[base64.charCodeAt(i + 3)];\n\n const triplet = (byte1 << 18) | (byte2 << 12) | (byte3 << 6) | byte4;\n\n if (outputIndex < outputLen) output[outputIndex++] = (triplet >> 16) & 0xff;\n if (outputIndex < outputLen) output[outputIndex++] = (triplet >> 8) & 0xff;\n if (outputIndex < outputLen) output[outputIndex++] = triplet & 0xff;\n }\n\n return output;\n}\n\n/**\n * Encode a string to base64url\n *\n * @param str - String to encode (UTF-8)\n * @returns Base64URL encoded string\n */\nexport function stringToBase64url(str: string): string {\n const encoder = new TextEncoder();\n return base64urlEncode(encoder.encode(str));\n}\n\n/**\n * Decode a base64url string to string\n *\n * @param base64url - Base64URL encoded string\n * @returns Decoded string (UTF-8)\n */\nexport function base64urlToString(base64url: string): string {\n const decoder = new TextDecoder();\n return decoder.decode(base64urlDecode(base64url));\n}\n\n// Base64 character set\nconst BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n// Lookup table for decoding\nconst BASE64_LOOKUP = new Uint8Array(256);\nfor (let i = 0; i < BASE64_CHARS.length; i++) {\n BASE64_LOOKUP[BASE64_CHARS.charCodeAt(i)] = i;\n}\n","/**\n * State/Nonce Manager\n *\n * Manages CSRF protection (state) and replay attack prevention (nonce)\n * for Authorization Code Flow.\n */\n\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport type { AuthrimStorage } from '../providers/storage.js';\nimport { AuthrimError } from '../types/errors.js';\nimport { base64urlEncode } from '../utils/base64url.js';\n\n/**\n * Auth state stored in storage\n */\nexport interface AuthState {\n /** State parameter (CSRF protection) */\n state: string;\n /** Nonce parameter (replay attack prevention) */\n nonce: string;\n /** PKCE code verifier */\n codeVerifier: string;\n /** Redirect URI used for this auth request */\n redirectUri: string;\n /** Requested scope (for validation) */\n scope: string;\n /** Timestamp when state was created */\n createdAt: number;\n /** Timestamp when state expires */\n expiresAt: number;\n /** Return URL after authentication (validated) */\n returnTo?: string;\n /** Operation tracking ID (for event correlation) */\n operationId: string;\n}\n\n/**\n * ReturnTo URL policy\n *\n * Controls which returnTo URLs are accepted to prevent open redirect attacks.\n */\nexport type ReturnToPolicy =\n | 'relative_only' // Default: relative paths only (/dashboard)\n | 'same_origin' // Same origin only\n | 'allowlist'; // Explicit allowlist\n\n/**\n * ReturnTo URL options\n */\nexport interface ReturnToOptions {\n /** Validation policy */\n policy: ReturnToPolicy;\n /** Allowed origins (required when policy is 'allowlist') */\n allowedOrigins?: string[];\n /** Current origin for same_origin check (required in non-browser environments) */\n currentOrigin?: string;\n}\n\n/**\n * Options for generating auth state\n */\nexport interface GenerateAuthStateOptions {\n /** Redirect URI for this auth request */\n redirectUri: string;\n /** Code verifier for PKCE */\n codeVerifier: string;\n /** Requested scope (for validation) */\n scope: string;\n /** TTL in seconds (default: 600 = 10 minutes) */\n ttlSeconds?: number;\n /** Return URL after authentication */\n returnTo?: string;\n /** ReturnTo URL validation options */\n returnToOptions?: ReturnToOptions;\n}\n\n/**\n * Storage keys factory\n */\nexport const STORAGE_KEYS = {\n /**\n * Auth state key (state-specific)\n */\n authState: (issuerHash: string, clientIdHash: string, state: string): string =>\n `authrim:${issuerHash}:${clientIdHash}:auth:${state}`,\n\n /**\n * Token storage key\n */\n tokens: (issuerHash: string, clientIdHash: string): string =>\n `authrim:${issuerHash}:${clientIdHash}:tokens`,\n\n /**\n * ID token storage key\n */\n idToken: (issuerHash: string, clientIdHash: string): string =>\n `authrim:${issuerHash}:${clientIdHash}:id_token`,\n\n /**\n * Auth state prefix for cleanup\n */\n authStatePrefix: (issuerHash: string, clientIdHash: string): string =>\n `authrim:${issuerHash}:${clientIdHash}:auth:`,\n} as const;\n\n/**\n * State Manager\n */\nexport class StateManager {\n /** Default TTL: 10 minutes */\n private static readonly DEFAULT_TTL_SECONDS = 600;\n\n /** Entropy bytes for state/nonce generation (256 bits = 32 bytes) */\n private static readonly ENTROPY_BYTES = 32;\n\n /** Entropy bytes for operationId (128 bits = 16 bytes, enough for tracking) */\n private static readonly OPERATION_ID_BYTES = 16;\n\n /** Auto cleanup interval (5 minutes) */\n private static readonly DEFAULT_CLEANUP_INTERVAL_MS = 300000;\n\n /** Cleanup interval handle */\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n\n constructor(\n private readonly crypto: CryptoProvider,\n private readonly storage: AuthrimStorage,\n private readonly issuerHash: string,\n private readonly clientIdHash: string\n ) {}\n\n /**\n * Generate and store auth state\n *\n * Creates state, nonce, stores them with the code verifier.\n *\n * @param options - Generation options\n * @returns Generated state string\n */\n async generateAuthState(options: GenerateAuthStateOptions): Promise<AuthState> {\n const ttlSeconds = options.ttlSeconds ?? StateManager.DEFAULT_TTL_SECONDS;\n\n // Validate returnTo URL if provided\n let validatedReturnTo: string | undefined;\n if (options.returnTo) {\n validatedReturnTo = this.validateReturnTo(\n options.returnTo,\n options.returnToOptions ?? { policy: 'relative_only' }\n );\n }\n\n // Generate random state, nonce, and operationId (256-bit entropy each)\n const stateBytes = await this.crypto.randomBytes(StateManager.ENTROPY_BYTES);\n const nonceBytes = await this.crypto.randomBytes(StateManager.ENTROPY_BYTES);\n const operationIdBytes = await this.crypto.randomBytes(StateManager.OPERATION_ID_BYTES);\n\n const state = base64urlEncode(stateBytes);\n const nonce = base64urlEncode(nonceBytes);\n const operationId = base64urlEncode(operationIdBytes);\n\n const now = Date.now();\n const authState: AuthState = {\n state,\n nonce,\n codeVerifier: options.codeVerifier,\n redirectUri: options.redirectUri,\n scope: options.scope,\n createdAt: now,\n expiresAt: now + ttlSeconds * 1000,\n returnTo: validatedReturnTo,\n operationId,\n };\n\n // Store in storage\n const key = STORAGE_KEYS.authState(this.issuerHash, this.clientIdHash, state);\n await this.storage.set(key, JSON.stringify(authState));\n\n return authState;\n }\n\n /**\n * Validate returnTo URL against policy (Open Redirect Protection)\n *\n * @param returnTo - URL to validate\n * @param options - Validation options\n * @returns Validated URL\n * @throws AuthrimError if URL is invalid\n */\n private validateReturnTo(returnTo: string, options: ReturnToOptions): string {\n switch (options.policy) {\n case 'relative_only':\n // Only allow relative paths starting with /\n // Reject absolute URLs and protocol-relative URLs (//)\n if (returnTo.startsWith('/') && !returnTo.startsWith('//')) {\n // Additional check: ensure no protocol in the path\n if (!returnTo.includes(':')) {\n return returnTo;\n }\n }\n throw new AuthrimError(\n 'invalid_return_to',\n 'returnTo must be a relative path (e.g., /dashboard)'\n );\n\n case 'same_origin':\n try {\n // For non-browser environments, currentOrigin must be provided\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const globalWindow = typeof globalThis !== 'undefined' ? (globalThis as any).window : undefined;\n const currentOrigin = options.currentOrigin ?? (globalWindow?.location?.origin);\n if (!currentOrigin) {\n throw new AuthrimError(\n 'invalid_return_to',\n 'currentOrigin is required for same_origin policy in non-browser environments'\n );\n }\n\n // Handle relative URLs\n if (returnTo.startsWith('/') && !returnTo.startsWith('//')) {\n return returnTo;\n }\n\n // Check absolute URL\n const url = new URL(returnTo);\n if (url.origin === currentOrigin) {\n return returnTo;\n }\n } catch (e) {\n if (e instanceof AuthrimError) throw e;\n // URL parsing failed\n }\n throw new AuthrimError(\n 'invalid_return_to',\n 'returnTo must be same origin or a relative path'\n );\n\n case 'allowlist':\n if (!options.allowedOrigins || options.allowedOrigins.length === 0) {\n throw new AuthrimError(\n 'invalid_return_to',\n 'allowedOrigins is required when using allowlist policy'\n );\n }\n\n // Allow relative URLs\n if (returnTo.startsWith('/') && !returnTo.startsWith('//')) {\n return returnTo;\n }\n\n try {\n const parsed = new URL(returnTo);\n if (options.allowedOrigins.includes(parsed.origin)) {\n return returnTo;\n }\n } catch {\n // URL parsing failed\n }\n throw new AuthrimError(\n 'invalid_return_to',\n `returnTo origin not in allowlist: ${options.allowedOrigins.join(', ')}`\n );\n\n default:\n throw new AuthrimError(\n 'invalid_return_to',\n `Unknown returnTo policy: ${options.policy}`\n );\n }\n }\n\n /**\n * Validate and consume state\n *\n * Retrieves, validates, and ALWAYS deletes the state (success or failure).\n * This ensures replay attack prevention and GC.\n *\n * @param state - State parameter from callback\n * @returns Auth state if valid\n * @throws AuthrimError if state is invalid or expired\n */\n async validateAndConsumeState(state: string): Promise<AuthState> {\n const key = STORAGE_KEYS.authState(this.issuerHash, this.clientIdHash, state);\n\n try {\n const stored = await this.storage.get(key);\n\n if (!stored) {\n throw new AuthrimError('invalid_state', 'State not found or already used');\n }\n\n let authState: AuthState;\n try {\n authState = JSON.parse(stored);\n } catch {\n throw new AuthrimError('invalid_state', 'Malformed state data');\n }\n\n // Check expiration (no skew - strict)\n if (Date.now() > authState.expiresAt) {\n throw new AuthrimError('expired_state', 'State has expired');\n }\n\n return authState;\n } finally {\n // ALWAYS delete (success, failure, or exception)\n // This is critical for:\n // 1. Replay attack prevention\n // 2. GC of used/expired states\n await this.storage.remove(key);\n }\n }\n\n /**\n * Clean up expired states\n *\n * This is a best-effort cleanup. Only works if storage.getAll() is available.\n * The primary GC mechanism is validateAndConsumeState()'s finally delete.\n *\n * Safe to call at startup or periodically.\n */\n async cleanupExpiredStates(): Promise<void> {\n // Only works if storage supports getAll()\n if (!this.storage.getAll) {\n return;\n }\n\n const prefix = STORAGE_KEYS.authStatePrefix(this.issuerHash, this.clientIdHash);\n const all = await this.storage.getAll();\n const now = Date.now();\n\n for (const [key, value] of Object.entries(all)) {\n if (!key.startsWith(prefix)) {\n continue;\n }\n\n try {\n const authState: AuthState = JSON.parse(value);\n if (now > authState.expiresAt) {\n await this.storage.remove(key);\n }\n } catch {\n // Parse failure - delete corrupted entry\n await this.storage.remove(key);\n }\n }\n }\n\n /**\n * Start automatic cleanup of expired states\n *\n * Runs cleanup every 5 minutes by default.\n *\n * @param intervalMs - Cleanup interval in milliseconds (default: 300000 = 5 minutes)\n */\n startAutoCleanup(intervalMs: number = StateManager.DEFAULT_CLEANUP_INTERVAL_MS): void {\n this.stopAutoCleanup();\n\n this.cleanupInterval = setInterval(() => {\n this.cleanupExpiredStates().catch(() => {\n // Ignore cleanup errors\n });\n }, intervalMs);\n\n // Run initial cleanup\n this.cleanupExpiredStates().catch(() => {\n // Ignore cleanup errors\n });\n }\n\n /**\n * Stop automatic cleanup\n */\n stopAutoCleanup(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n\n /**\n * Get the number of stored auth states\n *\n * Only works if storage.getAll() is available.\n *\n * @returns Number of stored states, or -1 if not supported\n */\n async getStoredStateCount(): Promise<number> {\n if (!this.storage.getAll) {\n return -1;\n }\n\n const prefix = STORAGE_KEYS.authStatePrefix(this.issuerHash, this.clientIdHash);\n const all = await this.storage.getAll();\n\n let count = 0;\n for (const key of Object.keys(all)) {\n if (key.startsWith(prefix)) {\n count++;\n }\n }\n\n return count;\n }\n}\n","/**\n * JWT Utilities\n *\n * Note: This module only provides decoding (parsing) functionality.\n * JWT signature verification MUST be performed by the server.\n * Never trust decoded JWT claims without server-side verification.\n */\n\nimport { base64urlToString } from './base64url.js';\nimport type { IdTokenClaims } from '../types/oidc.js';\n\n/**\n * JWT Header\n */\nexport interface JwtHeader {\n alg: string;\n typ?: string;\n kid?: string;\n [key: string]: unknown;\n}\n\n/**\n * Decoded JWT structure\n */\nexport interface DecodedJwt<T = Record<string, unknown>> {\n header: JwtHeader;\n payload: T;\n signature: string;\n}\n\n/**\n * Decode a JWT without verifying the signature\n *\n * WARNING: This function does NOT verify the JWT signature.\n * Use this only for reading claims after the token has been\n * validated by the authorization server.\n *\n * @param jwt - JWT string to decode\n * @returns Decoded JWT parts\n * @throws Error if the JWT format is invalid\n */\nexport function decodeJwt<T = Record<string, unknown>>(jwt: string): DecodedJwt<T> {\n const parts = jwt.split('.');\n if (parts.length !== 3) {\n throw new Error('Invalid JWT format: expected 3 parts');\n }\n\n const [headerB64, payloadB64, signature] = parts;\n\n try {\n const header = JSON.parse(base64urlToString(headerB64)) as JwtHeader;\n const payload = JSON.parse(base64urlToString(payloadB64)) as T;\n\n return {\n header,\n payload,\n signature,\n };\n } catch {\n throw new Error('Invalid JWT format: failed to decode');\n }\n}\n\n/**\n * Decode an ID token and extract claims\n *\n * WARNING: This function does NOT verify the ID token.\n * The token MUST be verified by the authorization server before use.\n *\n * @param idToken - ID token string\n * @returns ID token claims\n */\nexport function decodeIdToken(idToken: string): IdTokenClaims {\n const decoded = decodeJwt<IdTokenClaims>(idToken);\n return decoded.payload;\n}\n\n/**\n * Check if a JWT is expired\n *\n * @param jwt - Decoded JWT payload with exp claim\n * @param skewSeconds - Clock skew tolerance in seconds (default: 0)\n * @returns true if expired\n */\nexport function isJwtExpired(payload: { exp?: number }, skewSeconds: number = 0): boolean {\n if (payload.exp === undefined) {\n return false; // No expiration\n }\n\n const now = Math.floor(Date.now() / 1000);\n return payload.exp + skewSeconds < now;\n}\n\n/**\n * Get the nonce claim from an ID token\n *\n * @param idToken - ID token string\n * @returns nonce value or undefined\n */\nexport function getIdTokenNonce(idToken: string): string | undefined {\n try {\n const claims = decodeIdToken(idToken);\n return claims.nonce;\n } catch {\n return undefined;\n }\n}\n","/**\n * Timing-Safe Comparison Utilities\n *\n * Provides constant-time string comparison to prevent timing attacks.\n * Used for comparing security-sensitive values like nonces and states.\n */\n\n/**\n * Compare two strings in constant time\n *\n * This function always takes the same amount of time regardless of\n * where the strings differ, preventing timing attacks.\n *\n * @param a - First string\n * @param b - Second string\n * @returns true if strings are equal, false otherwise\n */\nexport function timingSafeEqual(a: string, b: string): boolean {\n // Encode strings to bytes for comparison\n const encoder = new TextEncoder();\n const aBytes = encoder.encode(a);\n const bBytes = encoder.encode(b);\n\n // Use byte array lengths for comparison\n const aLen = aBytes.length;\n const bLen = bBytes.length;\n\n // Use the longer length to ensure we compare all bytes\n const maxLen = Math.max(aLen, bLen);\n\n // XOR accumulator - will be non-zero if any bytes differ\n let result = aLen ^ bLen; // Start with length comparison\n\n // Compare all bytes, using 0 for out-of-bounds access\n for (let i = 0; i < maxLen; i++) {\n const aByte = i < aLen ? aBytes[i] : 0;\n const bByte = i < bLen ? bBytes[i] : 0;\n result |= aByte ^ bByte;\n }\n\n return result === 0;\n}\n","/**\n * Authorization Code Flow\n *\n * Implements OAuth 2.0 Authorization Code Flow with PKCE.\n * Uses 2-step pattern: buildAuthorizationUrl() + handleCallback()\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { TokenSet, TokenResponse } from '../types/token.js';\nimport type { AuthState } from './state.js';\nimport type { PKCEPair } from './pkce.js';\nimport { AuthrimError } from '../types/errors.js';\nimport { getIdTokenNonce } from '../utils/jwt.js';\nimport { timingSafeEqual } from '../utils/timing-safe.js';\nimport type { IDiagnosticLogger } from '../debug/diagnostic-logger.js';\n\n/**\n * Options for building authorization URL\n */\nexport interface BuildAuthorizationUrlOptions {\n /** Redirect URI (required) */\n redirectUri: string;\n /** Scopes to request (default: 'openid profile') */\n scope?: string;\n /**\n * Response type (default: 'code')\n *\n * Use 'none' for session check without token issuance\n * (OAuth 2.0 Multiple Response Types 1.0 §5)\n */\n responseType?: 'code' | 'none';\n /** Prompt behavior */\n prompt?: 'none' | 'login' | 'consent' | 'select_account';\n /** Hint about the login identifier */\n loginHint?: string;\n /** Requested Authentication Context Class Reference values */\n acrValues?: string;\n /** Additional custom parameters */\n extraParams?: Record<string, string>;\n /**\n * Expose state/nonce in result (for SSR/external storage)\n *\n * Default: false (security: state/nonce stay internal)\n * Set to true only when you need to store state externally\n * (e.g., cookie, server-side session)\n */\n exposeState?: boolean;\n /**\n * Use PAR (Pushed Authorization Request - RFC 9126)\n *\n * When true, authorization parameters are first pushed to the PAR endpoint,\n * and the resulting request_uri is used in the authorization URL.\n *\n * Required when server sets require_pushed_authorization_requests=true.\n */\n usePar?: boolean;\n /**\n * Use JAR (JWT Secured Authorization Request - RFC 9101)\n *\n * When true, authorization parameters are encoded in a signed JWT.\n *\n * Required when server sets require_signed_request_object=true.\n */\n useJar?: boolean;\n}\n\n/**\n * Result of buildAuthorizationUrl\n */\nexport interface AuthorizationUrlResult {\n /** Authorization URL to redirect to */\n url: string;\n /** State parameter (only if exposeState: true) */\n state?: string;\n /** Nonce parameter (only if exposeState: true) */\n nonce?: string;\n}\n\n/**\n * Internal authorization context (stored by StateManager)\n */\nexport interface AuthorizationContext {\n /** Auth state object */\n authState: AuthState;\n /** PKCE pair */\n pkce: PKCEPair;\n}\n\n/**\n * Options for exchanging authorization code\n */\nexport interface ExchangeCodeOptions {\n /** Authorization code */\n code: string;\n /** State parameter (for validation) */\n state: string;\n /** Redirect URI used in authorization request */\n redirectUri: string;\n /** Code verifier for PKCE */\n codeVerifier: string;\n /** Nonce to validate in ID token */\n nonce: string;\n /** Requested scope (for validation) */\n scope: string;\n}\n\n/**\n * Authorization Code Flow helper\n */\nexport class AuthorizationCodeFlow {\n private diagnosticLogger?: IDiagnosticLogger | null;\n\n constructor(\n private readonly http: HttpClient,\n private readonly clientId: string\n ) {}\n\n /**\n * Set diagnostic logger for this flow\n */\n setDiagnosticLogger(logger: IDiagnosticLogger | null | undefined): void {\n this.diagnosticLogger = logger;\n }\n\n /**\n * Build authorization URL\n *\n * @param discovery - OIDC discovery document\n * @param authState - Auth state from StateManager\n * @param pkce - PKCE pair\n * @param options - Authorization options\n * @returns Authorization URL result\n * @throws AuthrimError with code 'par_required' if server requires PAR but usePar is not enabled\n */\n buildAuthorizationUrl(\n discovery: OIDCDiscoveryDocument,\n authState: AuthState,\n pkce: PKCEPair,\n options: BuildAuthorizationUrlOptions\n ): AuthorizationUrlResult {\n // PAR enforcement guard: fail if server requires PAR but usePar is not enabled\n if (discovery.require_pushed_authorization_requests && !options.usePar) {\n throw new AuthrimError(\n 'par_required',\n 'Server requires PAR (Pushed Authorization Request) but usePar option is not enabled'\n );\n }\n\n // JAR enforcement guard: fail if server requires JAR but useJar is not enabled\n if (discovery.require_signed_request_object && !options.useJar) {\n throw new AuthrimError(\n 'jar_required',\n 'Server requires JAR (JWT Secured Authorization Request) but useJar option is not enabled'\n );\n }\n\n const endpoint = discovery.authorization_endpoint;\n const params = new URLSearchParams();\n\n // Required parameters\n params.set('client_id', this.clientId);\n params.set('response_type', options.responseType ?? 'code');\n params.set('redirect_uri', options.redirectUri);\n params.set('state', authState.state);\n params.set('nonce', authState.nonce);\n\n // PKCE parameters\n params.set('code_challenge', pkce.codeChallenge);\n params.set('code_challenge_method', pkce.codeChallengeMethod);\n\n // Scopes\n const scope = options.scope ?? 'openid profile';\n params.set('scope', scope);\n\n // Optional parameters\n if (options.prompt) {\n params.set('prompt', options.prompt);\n }\n if (options.loginHint) {\n params.set('login_hint', options.loginHint);\n }\n if (options.acrValues) {\n params.set('acr_values', options.acrValues);\n }\n\n // Extra custom parameters (with security parameter protection)\n if (options.extraParams) {\n // Security parameters that MUST NOT be overwritten\n const protectedParams = new Set([\n 'client_id',\n 'response_type',\n 'redirect_uri',\n 'state',\n 'nonce',\n 'code_challenge',\n 'code_challenge_method',\n 'scope',\n ]);\n\n for (const [key, value] of Object.entries(options.extraParams)) {\n if (protectedParams.has(key.toLowerCase())) {\n // Silently ignore attempts to override security parameters\n // This prevents CSRF, PKCE bypass, and other attacks\n continue;\n }\n params.set(key, value);\n }\n }\n\n const url = `${endpoint}?${params.toString()}`;\n\n // Build result\n const result: AuthorizationUrlResult = { url };\n\n if (options.exposeState) {\n result.state = authState.state;\n result.nonce = authState.nonce;\n }\n\n return result;\n }\n\n /**\n * Parse callback URL and extract code/state\n *\n * @param callbackUrl - Callback URL or query string\n * @returns Parsed code and state\n * @throws AuthrimError with code 'oauth_error' if OAuth error response is present\n * @throws AuthrimError with code 'missing_code' if authorization code is not found\n * @throws AuthrimError with code 'missing_state' if state parameter is not found\n */\n parseCallback(callbackUrl: string): { code: string; state: string } {\n let searchParams: URLSearchParams;\n\n // Support both full URL and query string\n if (callbackUrl.includes('?')) {\n const url = callbackUrl.startsWith('http')\n ? new URL(callbackUrl)\n : new URL(callbackUrl, 'https://dummy.local');\n searchParams = url.searchParams;\n } else {\n searchParams = new URLSearchParams(callbackUrl);\n }\n\n // Check for OAuth error response\n const error = searchParams.get('error');\n if (error) {\n const errorDescription = searchParams.get('error_description') ?? 'Authorization failed';\n throw new AuthrimError('oauth_error', errorDescription, {\n details: {\n error,\n error_description: errorDescription,\n error_uri: searchParams.get('error_uri'),\n },\n });\n }\n\n // Extract code and state\n const code = searchParams.get('code');\n const state = searchParams.get('state');\n\n if (!code) {\n throw new AuthrimError('missing_code', 'Authorization code not found in callback');\n }\n if (!state) {\n throw new AuthrimError('missing_state', 'State parameter not found in callback');\n }\n\n return { code, state };\n }\n\n /**\n * Exchange authorization code for tokens\n *\n * @param discovery - OIDC discovery document\n * @param options - Exchange options\n * @returns Token set\n * @throws AuthrimError with code 'network_error' if token request fails\n * @throws AuthrimError with code 'token_error' if token exchange fails\n * @throws AuthrimError with code 'nonce_mismatch' if ID token nonce validation fails\n */\n async exchangeCode(\n discovery: OIDCDiscoveryDocument,\n options: ExchangeCodeOptions\n ): Promise<TokenSet> {\n const tokenEndpoint = discovery.token_endpoint;\n\n // Build token request body\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: this.clientId,\n code: options.code,\n redirect_uri: options.redirectUri,\n code_verifier: options.codeVerifier,\n });\n\n // Make token request\n let response;\n try {\n response = await this.http.fetch<TokenResponse>(tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Token request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n throw new AuthrimError('token_error', 'Token exchange failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n const tokenResponse = response.data;\n\n // Check if openid scope was requested\n const requestedOpenId = options.scope.split(' ').includes('openid');\n\n // OIDC compliance: If openid scope was requested, id_token MUST be present\n if (requestedOpenId && !tokenResponse.id_token) {\n throw new AuthrimError(\n 'missing_id_token',\n 'ID token required when openid scope is requested but was not returned by the server'\n );\n }\n\n // Validate nonce in ID token (using constant-time comparison to prevent timing attacks)\n if (tokenResponse.id_token) {\n const idTokenNonce = getIdTokenNonce(tokenResponse.id_token);\n\n // Security: nonce MUST be present in id_token when it was sent in the request\n if (idTokenNonce === undefined) {\n // Log diagnostic\n this.diagnosticLogger?.logTokenValidation({\n step: 'nonce-check',\n tokenType: 'id_token',\n result: 'fail',\n expected: 'nonce claim present',\n actual: 'nonce claim missing',\n errorMessage: 'ID token nonce claim is missing but was sent in authorization request',\n });\n\n throw new AuthrimError(\n 'missing_nonce',\n 'ID token nonce claim is missing but was sent in authorization request'\n );\n }\n\n if (!timingSafeEqual(idTokenNonce, options.nonce)) {\n // Log diagnostic (without exposing nonce values)\n this.diagnosticLogger?.logTokenValidation({\n step: 'nonce-check',\n tokenType: 'id_token',\n result: 'fail',\n errorMessage: 'ID token nonce does not match expected value',\n });\n\n // Do not include nonce values in error details (security sensitive)\n throw new AuthrimError('nonce_mismatch', 'ID token nonce does not match expected value');\n }\n\n // Log successful nonce validation\n this.diagnosticLogger?.logTokenValidation({\n step: 'nonce-check',\n tokenType: 'id_token',\n result: 'pass',\n });\n }\n\n // Calculate expiresAt (epoch seconds)\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = tokenResponse.expires_in ? now + tokenResponse.expires_in : now + 3600; // Default to 1 hour if not provided\n\n // Build token set\n const tokenSet: TokenSet = {\n accessToken: tokenResponse.access_token,\n tokenType: (tokenResponse.token_type as 'Bearer') ?? 'Bearer',\n expiresAt,\n refreshToken: tokenResponse.refresh_token,\n idToken: tokenResponse.id_token,\n scope: tokenResponse.scope,\n };\n\n // Log successful authentication\n this.diagnosticLogger?.logAuthDecision({\n decision: 'allow',\n reason: 'Token exchange successful and ID token validation passed',\n flow: 'authorization_code',\n context: {\n hasAccessToken: !!tokenSet.accessToken,\n hasRefreshToken: !!tokenSet.refreshToken,\n hasIdToken: !!tokenSet.idToken,\n scope: tokenSet.scope,\n },\n });\n\n return tokenSet;\n }\n}\n","/**\n * PAR (Pushed Authorization Request) Client\n * RFC 9126: OAuth 2.0 Pushed Authorization Requests\n *\n * PAR allows the client to push the authorization request payload\n * to the authorization server via a direct POST request, receiving\n * a request_uri to use in the authorization URL.\n *\n * Benefits:\n * - Integrity protection of authorization request\n * - Confidentiality of authorization request parameters\n * - Support for large request parameters\n * - Required for FAPI 2.0 compliance\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { PARRequest, PARResponse, PARResult, PARClientOptions } from '../types/par.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * PAR Client\n *\n * Handles Pushed Authorization Requests per RFC 9126.\n */\nexport class PARClient {\n constructor(\n private readonly http: HttpClient,\n private readonly clientId: string,\n private readonly options?: PARClientOptions\n ) {}\n\n /**\n * Push authorization request to the server\n *\n * @param discovery - OIDC discovery document\n * @param request - PAR request parameters\n * @returns PAR result with request_uri and expiration\n * @throws AuthrimError with code 'no_par_endpoint' if PAR endpoint not available\n * @throws AuthrimError with code 'par_error' if PAR request fails\n */\n async pushAuthorizationRequest(\n discovery: OIDCDiscoveryDocument,\n request: PARRequest\n ): Promise<PARResult> {\n const parEndpoint = discovery.pushed_authorization_request_endpoint;\n\n if (!parEndpoint) {\n throw new AuthrimError(\n 'no_par_endpoint',\n 'PAR endpoint not available in discovery document'\n );\n }\n\n // Build PAR request body\n const body = new URLSearchParams();\n\n // Required parameters\n body.set('client_id', this.clientId);\n body.set('response_type', request.responseType ?? 'code');\n body.set('redirect_uri', request.redirectUri);\n body.set('state', request.state);\n body.set('nonce', request.nonce);\n body.set('code_challenge', request.codeChallenge);\n body.set('code_challenge_method', request.codeChallengeMethod);\n\n // Scopes\n body.set('scope', request.scope ?? 'openid profile');\n\n // Optional parameters\n if (request.prompt) {\n body.set('prompt', request.prompt);\n }\n if (request.loginHint) {\n body.set('login_hint', request.loginHint);\n }\n if (request.acrValues) {\n body.set('acr_values', request.acrValues);\n }\n\n // Extra custom parameters (with security parameter protection)\n if (request.extraParams) {\n const protectedParams = new Set([\n 'client_id',\n 'response_type',\n 'redirect_uri',\n 'state',\n 'nonce',\n 'code_challenge',\n 'code_challenge_method',\n 'scope',\n ]);\n\n for (const [key, value] of Object.entries(request.extraParams)) {\n if (protectedParams.has(key.toLowerCase())) {\n continue; // Silently ignore protected params\n }\n body.set(key, value);\n }\n }\n\n // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n ...this.options?.headers,\n };\n\n // Make PAR request\n let response;\n try {\n response = await this.http.fetch<PARResponse>(parEndpoint, {\n method: 'POST',\n headers,\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'PAR request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n throw new AuthrimError('par_error', 'PAR request failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n const parResponse = response.data;\n\n // Validate response\n if (!parResponse.request_uri) {\n throw new AuthrimError('par_error', 'PAR response missing request_uri');\n }\n if (typeof parResponse.expires_in !== 'number') {\n throw new AuthrimError('par_error', 'PAR response missing or invalid expires_in');\n }\n\n // Calculate absolute expiration\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = now + parResponse.expires_in;\n\n return {\n requestUri: parResponse.request_uri,\n expiresAt,\n };\n }\n\n /**\n * Build authorization URL using request_uri from PAR\n *\n * @param discovery - OIDC discovery document\n * @param requestUri - Request URI from PAR response\n * @returns Authorization URL\n */\n buildAuthorizationUrlWithPar(\n discovery: OIDCDiscoveryDocument,\n requestUri: string\n ): string {\n const params = new URLSearchParams();\n params.set('client_id', this.clientId);\n params.set('request_uri', requestUri);\n\n return `${discovery.authorization_endpoint}?${params.toString()}`;\n }\n}\n","/**\n * Device Authorization Flow\n * RFC 8628: OAuth 2.0 Device Authorization Grant\n *\n * Used for devices with limited input capabilities where the user\n * authenticates on a separate device (phone, computer).\n *\n * Flow:\n * 1. Client requests device code from authorization server\n * 2. User goes to verification URI and enters user code\n * 3. Client polls token endpoint until user completes auth\n *\n * NOTE: This core SDK returns \"facts\" only - UX events like\n * 'device:started' or 'device:pending' are the responsibility\n * of upper-layer SDKs (web/react/svelte).\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { TokenSet, TokenResponse } from '../types/token.js';\nimport type {\n DeviceAuthorizationResponse,\n DeviceFlowState,\n DeviceFlowPollResult,\n DeviceFlowStartOptions,\n} from '../types/device-flow.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/** Default polling interval in seconds (RFC 8628 §3.2) */\nconst DEFAULT_INTERVAL = 5;\n\n/**\n * Device Flow Client\n *\n * Handles the OAuth 2.0 Device Authorization Grant (RFC 8628).\n */\nexport class DeviceFlowClient {\n constructor(\n private readonly http: HttpClient,\n private readonly clientId: string\n ) {}\n\n /**\n * Start device authorization\n *\n * Requests a device code and user code from the authorization server.\n *\n * @param discovery - OIDC discovery document\n * @param options - Start options (scope, etc.)\n * @returns Device flow state with codes and URIs\n * @throws AuthrimError with code 'no_device_authorization_endpoint' if endpoint not available\n * @throws AuthrimError with code 'device_authorization_error' if request fails\n */\n async startDeviceAuthorization(\n discovery: OIDCDiscoveryDocument,\n options?: DeviceFlowStartOptions\n ): Promise<DeviceFlowState> {\n const endpoint = discovery.device_authorization_endpoint;\n\n if (!endpoint) {\n throw new AuthrimError(\n 'no_device_authorization_endpoint',\n 'Device authorization endpoint not available in discovery document'\n );\n }\n\n // Build request body\n const body = new URLSearchParams({\n client_id: this.clientId,\n });\n\n if (options?.scope) {\n body.set('scope', options.scope);\n }\n\n // Add extra parameters\n if (options?.extraParams) {\n const protectedParams = new Set(['client_id', 'scope']);\n\n for (const [key, value] of Object.entries(options.extraParams)) {\n if (protectedParams.has(key.toLowerCase())) {\n continue;\n }\n body.set(key, value);\n }\n }\n\n // Make request\n let response;\n try {\n response = await this.http.fetch<DeviceAuthorizationResponse>(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Device authorization request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n throw new AuthrimError('device_authorization_error', 'Device authorization request failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n const data = response.data;\n\n // Validate required fields\n if (!data.device_code || !data.user_code || !data.verification_uri) {\n throw new AuthrimError(\n 'device_authorization_error',\n 'Invalid device authorization response: missing required fields'\n );\n }\n\n // Calculate expiration\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = now + data.expires_in;\n\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n verificationUri: data.verification_uri,\n verificationUriComplete: data.verification_uri_complete,\n expiresAt,\n interval: data.interval ?? DEFAULT_INTERVAL,\n };\n }\n\n /**\n * Poll the token endpoint once\n *\n * Returns the current state of the authorization:\n * - 'pending': User hasn't completed auth yet\n * - 'completed': Auth complete, tokens received\n * - 'slow_down': Polling too fast, increase interval\n * - 'expired': Device code expired\n * - 'access_denied': User denied the request\n *\n * @param discovery - OIDC discovery document\n * @param state - Device flow state from startDeviceAuthorization\n * @returns Poll result\n */\n async pollOnce(\n discovery: OIDCDiscoveryDocument,\n state: DeviceFlowState\n ): Promise<DeviceFlowPollResult> {\n // Check if expired\n const now = Math.floor(Date.now() / 1000);\n if (now >= state.expiresAt) {\n return { status: 'expired' };\n }\n\n const tokenEndpoint = discovery.token_endpoint;\n\n // Build request body\n const body = new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: state.deviceCode,\n client_id: this.clientId,\n });\n\n // Make token request\n let response;\n try {\n response = await this.http.fetch<TokenResponse | { error: string; error_description?: string }>(\n tokenEndpoint,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n }\n );\n } catch (error) {\n throw new AuthrimError('network_error', 'Device flow token request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n // Handle error responses (RFC 8628 §3.5)\n if (!response.ok) {\n const errorData = response.data as { error: string; error_description?: string };\n const errorCode = errorData?.error;\n\n switch (errorCode) {\n case 'authorization_pending':\n // User hasn't completed the authorization yet\n return {\n status: 'pending',\n retryAfter: state.interval,\n };\n\n case 'slow_down':\n // Polling too frequently - increase interval by 5 seconds (RFC 8628 §3.5)\n return {\n status: 'slow_down',\n retryAfter: state.interval + 5,\n };\n\n case 'expired_token':\n // Device code has expired\n return { status: 'expired' };\n\n case 'access_denied':\n // User denied the authorization request\n return { status: 'access_denied' };\n\n default:\n // Unknown error\n throw new AuthrimError('device_authorization_error', 'Device flow token request failed', {\n details: {\n status: response.status,\n error: errorCode,\n error_description: errorData?.error_description,\n },\n });\n }\n }\n\n // Success - tokens received\n const tokenResponse = response.data as TokenResponse;\n\n // Calculate expiresAt (epoch seconds)\n const expiresAt = tokenResponse.expires_in ? now + tokenResponse.expires_in : now + 3600;\n\n const tokens: TokenSet = {\n accessToken: tokenResponse.access_token,\n tokenType: (tokenResponse.token_type as 'Bearer') ?? 'Bearer',\n expiresAt,\n refreshToken: tokenResponse.refresh_token,\n idToken: tokenResponse.id_token,\n scope: tokenResponse.scope,\n };\n\n return {\n status: 'completed',\n tokens,\n };\n }\n\n /**\n * Poll until authorization is complete or expires\n *\n * Automatically handles polling interval and retries.\n *\n * @param discovery - OIDC discovery document\n * @param state - Device flow state from startDeviceAuthorization\n * @param options - Polling options\n * @returns Token set on success\n * @throws AuthrimError with code 'device_authorization_expired' if device code expires\n * @throws AuthrimError with code 'device_access_denied' if user denies authorization\n */\n async pollUntilComplete(\n discovery: OIDCDiscoveryDocument,\n state: DeviceFlowState,\n options?: { signal?: AbortSignal }\n ): Promise<TokenSet> {\n let currentInterval = state.interval;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n // Check for abort\n if (options?.signal?.aborted) {\n throw new AuthrimError('device_authorization_error', 'Device flow polling aborted');\n }\n\n const result = await this.pollOnce(discovery, state);\n\n switch (result.status) {\n case 'completed':\n return result.tokens;\n\n case 'pending':\n // Wait and continue polling\n await this.sleep(result.retryAfter * 1000, options?.signal);\n continue;\n\n case 'slow_down':\n // Increase interval and continue polling\n currentInterval = result.retryAfter;\n // Update state for future polls\n state.interval = currentInterval;\n await this.sleep(currentInterval * 1000, options?.signal);\n continue;\n\n case 'expired':\n throw new AuthrimError(\n 'device_authorization_expired',\n 'Device authorization has expired. Please start a new authorization.'\n );\n\n case 'access_denied':\n throw new AuthrimError(\n 'device_access_denied',\n 'User denied the device authorization request'\n );\n }\n }\n }\n\n /**\n * Sleep for a given number of milliseconds\n * @param ms - Milliseconds to sleep\n * @param signal - Optional abort signal\n */\n private sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(resolve, ms);\n\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timeout);\n reject(new AuthrimError('device_authorization_error', 'Device flow polling aborted'));\n },\n { once: true }\n );\n }\n });\n }\n}\n","/**\n * DPoP Manager\n * RFC 9449: OAuth 2.0 Demonstrating Proof of Possession (DPoP)\n *\n * DPoP provides sender-constrained access tokens by binding them\n * to a cryptographic key held by the client. This prevents token theft\n * and replay attacks.\n *\n * NOTE: DPoP proofs are required for:\n * - Token requests (authorization code exchange, refresh)\n * - PAR requests\n * - UserInfo requests\n * - Any protected resource request\n *\n * Future consideration: HttpClient-level middleware for automatic DPoP proof attachment.\n */\n\nimport type {\n DPoPKeyPair,\n DPoPProofHeader,\n DPoPProofClaims,\n DPoPProofOptions,\n DPoPManagerConfig,\n DPoPCryptoProvider,\n JWK,\n} from '../types/dpop.js';\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport { AuthrimError } from '../types/errors.js';\nimport { base64urlEncode, stringToBase64url } from '../utils/base64url.js';\n\n/**\n * DPoP Manager\n *\n * Manages DPoP key pairs and generates DPoP proofs for requests.\n */\nexport class DPoPManager {\n private readonly crypto: CryptoProvider & DPoPCryptoProvider;\n private readonly config: DPoPManagerConfig;\n private keyPair: DPoPKeyPair | null = null;\n private serverNonce: string | null = null;\n\n constructor(\n crypto: CryptoProvider & DPoPCryptoProvider,\n config?: DPoPManagerConfig\n ) {\n this.crypto = crypto;\n this.config = config ?? {};\n }\n\n /**\n * Initialize the DPoP manager\n *\n * Generates or retrieves a DPoP key pair.\n *\n * @throws AuthrimError with code 'dpop_key_generation_error' if key generation fails\n */\n async initialize(): Promise<void> {\n // Check if crypto provider supports DPoP\n if (!this.crypto.generateDPoPKeyPair) {\n throw new AuthrimError(\n 'dpop_key_generation_error',\n 'CryptoProvider does not support DPoP key generation'\n );\n }\n\n // Try to get existing key pair\n if (this.crypto.getDPoPKeyPair) {\n const existing = await this.crypto.getDPoPKeyPair();\n if (existing) {\n this.keyPair = existing;\n return;\n }\n }\n\n // Generate new key pair\n try {\n this.keyPair = await this.crypto.generateDPoPKeyPair(\n this.config.algorithm ?? 'ES256'\n );\n } catch (error) {\n throw new AuthrimError(\n 'dpop_key_generation_error',\n 'Failed to generate DPoP key pair',\n { cause: error instanceof Error ? error : undefined }\n );\n }\n }\n\n /**\n * Check if DPoP is initialized\n */\n isInitialized(): boolean {\n return this.keyPair !== null;\n }\n\n /**\n * Generate a DPoP proof\n *\n * Creates a signed JWT proof for the specified HTTP method and URI.\n *\n * @param method - HTTP method (GET, POST, etc.)\n * @param uri - Full request URI (https://example.com/path)\n * @param options - Additional options (access token hash, nonce)\n * @returns Signed DPoP proof JWT\n * @throws AuthrimError with code 'dpop_proof_generation_error' if proof generation fails\n */\n async generateProof(\n method: string,\n uri: string,\n options?: DPoPProofOptions\n ): Promise<string> {\n if (!this.keyPair) {\n throw new AuthrimError(\n 'dpop_proof_generation_error',\n 'DPoP manager not initialized. Call initialize() first.'\n );\n }\n\n // Parse URI to get htu (without query and fragment)\n const url = new URL(uri);\n const htu = `${url.protocol}//${url.host}${url.pathname}`;\n\n // Build JWT header\n const header: DPoPProofHeader = {\n typ: 'dpop+jwt',\n alg: this.keyPair.algorithm,\n jwk: this.keyPair.publicKeyJwk,\n };\n\n // Build JWT claims\n const now = Math.floor(Date.now() / 1000);\n const claims: DPoPProofClaims = {\n jti: this.generateJti(),\n htm: method.toUpperCase(),\n htu,\n iat: now,\n };\n\n // Add optional claims\n if (options?.accessTokenHash) {\n claims.ath = options.accessTokenHash;\n }\n if (options?.nonce ?? this.serverNonce) {\n claims.nonce = options?.nonce ?? this.serverNonce ?? undefined;\n }\n\n // Encode and sign\n try {\n const headerB64 = stringToBase64url(JSON.stringify(header));\n const claimsB64 = stringToBase64url(JSON.stringify(claims));\n const signingInput = `${headerB64}.${claimsB64}`;\n\n const signature = await this.keyPair.sign(\n new TextEncoder().encode(signingInput)\n );\n const signatureB64 = base64urlEncode(signature);\n\n return `${signingInput}.${signatureB64}`;\n } catch (error) {\n throw new AuthrimError(\n 'dpop_proof_generation_error',\n 'Failed to generate DPoP proof',\n { cause: error instanceof Error ? error : undefined }\n );\n }\n }\n\n /**\n * Handle a DPoP-Nonce response from the server\n *\n * When the server returns a use_dpop_nonce error or includes\n * a DPoP-Nonce header, this method stores the nonce for future proofs.\n *\n * @param nonce - Server-provided nonce value\n */\n handleNonceResponse(nonce: string): void {\n this.serverNonce = nonce;\n }\n\n /**\n * Get the current server nonce\n */\n getServerNonce(): string | null {\n return this.serverNonce;\n }\n\n /**\n * Clear the server nonce\n */\n clearServerNonce(): void {\n this.serverNonce = null;\n }\n\n /**\n * Get the public key JWK\n *\n * @returns Public key in JWK format, or null if not initialized\n */\n getPublicKeyJwk(): JWK | null {\n return this.keyPair?.publicKeyJwk ?? null;\n }\n\n /**\n * Get the JWK thumbprint\n *\n * @returns Base64url-encoded thumbprint, or null if not initialized\n */\n getThumbprint(): string | null {\n return this.keyPair?.thumbprint ?? null;\n }\n\n /**\n * Calculate access token hash for ath claim\n *\n * @param accessToken - Access token to hash\n * @returns Base64url-encoded SHA-256 hash\n */\n async calculateAccessTokenHash(accessToken: string): Promise<string> {\n const hash = await this.crypto.sha256(accessToken);\n return base64urlEncode(hash);\n }\n\n /**\n * Clear the DPoP key pair\n *\n * Should be called on logout to clean up key material.\n */\n async clear(): Promise<void> {\n if (this.crypto.clearDPoPKeyPair) {\n await this.crypto.clearDPoPKeyPair();\n }\n this.keyPair = null;\n this.serverNonce = null;\n }\n\n /**\n * Generate a unique JWT ID (jti)\n */\n private generateJti(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n }\n}\n","/**\n * Token Types\n */\n\n/**\n * Token set returned from token endpoint\n *\n * Note: expiresAt is epoch seconds (not milliseconds)\n */\nexport interface TokenSet {\n /** Access token */\n accessToken: string;\n /** Refresh token (if provided) */\n refreshToken?: string;\n /** ID token (if openid scope was requested) */\n idToken?: string;\n /** Token type (always 'Bearer' for OAuth 2.0) */\n tokenType: 'Bearer';\n /**\n * Token expiration time as epoch seconds\n *\n * Calculated from expires_in at token exchange time:\n * expiresAt = Math.floor(Date.now() / 1000) + expires_in\n */\n expiresAt: number;\n /** Scope granted (may differ from requested scope) */\n scope?: string;\n}\n\n/**\n * Token endpoint response (raw)\n */\nexport interface TokenEndpointResponse {\n access_token: string;\n token_type: string;\n expires_in?: number;\n refresh_token?: string;\n id_token?: string;\n scope?: string;\n}\n\n/**\n * Alias for TokenEndpointResponse\n */\nexport type TokenResponse = TokenEndpointResponse;\n\n/**\n * Token exchange request (RFC 8693)\n */\nexport interface TokenExchangeRequest {\n /** The subject token to exchange */\n subjectToken: string;\n /** Subject token type (default: access_token) */\n subjectTokenType?: 'access_token' | 'refresh_token' | 'id_token';\n /** Target audience for the new token */\n audience?: string;\n /** Requested scope for the new token */\n scope?: string;\n /** Requested token type (default: access_token) */\n requestedTokenType?: 'access_token' | 'refresh_token' | 'id_token';\n /** Actor token (for delegation) */\n actorToken?: string;\n /** Actor token type */\n actorTokenType?: 'access_token' | 'id_token';\n}\n\n/**\n * Token exchange response (RFC 8693)\n *\n * Extends standard token response with issued_token_type\n */\nexport interface TokenExchangeResponse extends TokenEndpointResponse {\n /** URI of the issued token type */\n issued_token_type: string;\n}\n\n/**\n * Token type URIs (RFC 8693)\n */\nexport const TOKEN_TYPE_URIS = {\n access_token: 'urn:ietf:params:oauth:token-type:access_token',\n refresh_token: 'urn:ietf:params:oauth:token-type:refresh_token',\n id_token: 'urn:ietf:params:oauth:token-type:id_token',\n} as const;\n\n/**\n * Token type URI type\n */\nexport type TokenTypeUri = (typeof TOKEN_TYPE_URIS)[keyof typeof TOKEN_TYPE_URIS];\n\n/**\n * Token exchange result\n */\nexport interface TokenExchangeResult {\n /** Token set from exchange */\n tokens: TokenSet;\n /** Issued token type URI */\n issuedTokenType: TokenTypeUri | string;\n}\n","/**\n * Token Manager\n *\n * Manages token storage, retrieval, and automatic refresh.\n * Implements in-flight request coalescing for concurrent refresh requests.\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { AuthrimStorage } from '../providers/storage.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type {\n TokenSet,\n TokenResponse,\n TokenExchangeRequest,\n TokenExchangeResponse,\n TokenExchangeResult,\n} from '../types/token.js';\nimport { TOKEN_TYPE_URIS } from '../types/token.js';\nimport type { EventEmitter } from '../events/emitter.js';\nimport { AuthrimError, isRetryableError, emitClassifiedError } from '../types/errors.js';\nimport { STORAGE_KEYS } from '../auth/state.js';\n\n/**\n * Token manager options\n */\nexport interface TokenManagerOptions {\n /** HTTP client */\n http: HttpClient;\n /** Storage provider */\n storage: AuthrimStorage;\n /** Client ID */\n clientId: string;\n /** Issuer hash for storage keys */\n issuerHash: string;\n /** Client ID hash for storage keys */\n clientIdHash: string;\n /** Refresh skew in seconds (default: 30) */\n refreshSkewSeconds?: number;\n /** Event emitter for token events */\n eventEmitter?: EventEmitter;\n /** Token expiring warning threshold in seconds (default: 300 = 5 minutes) */\n expiringThresholdSeconds?: number;\n /** Jitter for expiring event in milliseconds (default: 30000 = ±30 seconds) */\n expiringJitterMs?: number;\n}\n\n/**\n * Token Manager\n *\n * Handles token storage, retrieval, and automatic refresh with\n * concurrent request coalescing.\n */\nexport class TokenManager {\n private readonly http: HttpClient;\n private readonly storage: AuthrimStorage;\n private readonly clientId: string;\n private readonly issuerHash: string;\n private readonly clientIdHash: string;\n private readonly refreshSkewSeconds: number;\n private readonly eventEmitter?: EventEmitter;\n private readonly expiringThresholdMs: number;\n private readonly expiringJitterMs: number;\n\n /** In-flight refresh promise for request coalescing */\n private refreshPromise: Promise<TokenSet> | null = null;\n\n /** Discovery document (set externally) */\n private discovery: OIDCDiscoveryDocument | null = null;\n\n /** Timer for token expiring event */\n private expiringTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /** Whether this tab is the leader for refresh scheduling */\n private isLeaderTab = true;\n\n /** Current operation ID for event tracking */\n private currentOperationId: string | null = null;\n\n /** Default refresh skew: 30 seconds */\n private static readonly DEFAULT_REFRESH_SKEW_SECONDS = 30;\n\n /** Default expiring threshold: 5 minutes */\n private static readonly DEFAULT_EXPIRING_THRESHOLD_SECONDS = 300;\n\n /** Default expiring jitter: ±30 seconds */\n private static readonly DEFAULT_EXPIRING_JITTER_MS = 30000;\n\n constructor(options: TokenManagerOptions) {\n this.http = options.http;\n this.storage = options.storage;\n this.clientId = options.clientId;\n this.issuerHash = options.issuerHash;\n this.clientIdHash = options.clientIdHash;\n this.refreshSkewSeconds =\n options.refreshSkewSeconds ?? TokenManager.DEFAULT_REFRESH_SKEW_SECONDS;\n this.eventEmitter = options.eventEmitter;\n this.expiringThresholdMs =\n (options.expiringThresholdSeconds ?? TokenManager.DEFAULT_EXPIRING_THRESHOLD_SECONDS) * 1000;\n this.expiringJitterMs = options.expiringJitterMs ?? TokenManager.DEFAULT_EXPIRING_JITTER_MS;\n }\n\n /**\n * Set discovery document\n */\n setDiscovery(discovery: OIDCDiscoveryDocument): void {\n this.discovery = discovery;\n }\n\n /**\n * Get storage key for tokens\n */\n private get tokenKey(): string {\n return STORAGE_KEYS.tokens(this.issuerHash, this.clientIdHash);\n }\n\n /**\n * Get storage key for ID token\n */\n private get idTokenKey(): string {\n return STORAGE_KEYS.idToken(this.issuerHash, this.clientIdHash);\n }\n\n /**\n * Get current tokens from storage\n *\n * @returns Token set or null if not found\n */\n async getTokens(): Promise<TokenSet | null> {\n const stored = await this.storage.get(this.tokenKey);\n if (!stored) {\n return null;\n }\n\n try {\n return JSON.parse(stored) as TokenSet;\n } catch {\n // Corrupted data - clear and return null\n await this.clearTokens();\n return null;\n }\n }\n\n /**\n * Save tokens to storage\n *\n * @param tokens - Token set to save\n */\n async saveTokens(tokens: TokenSet): Promise<void> {\n await this.storage.set(this.tokenKey, JSON.stringify(tokens));\n\n // Also save ID token separately for logout\n if (tokens.idToken) {\n await this.storage.set(this.idTokenKey, tokens.idToken);\n }\n\n // Schedule expiring event\n this.scheduleExpiringEvent(tokens.expiresAt);\n }\n\n /**\n * Schedule token:expiring event with jitter\n *\n * @param expiresAt - Token expiration timestamp (epoch seconds)\n */\n private scheduleExpiringEvent(expiresAt: number): void {\n // Clear existing timeout\n if (this.expiringTimeout) {\n clearTimeout(this.expiringTimeout);\n this.expiringTimeout = null;\n }\n\n // Only schedule if we're the leader tab\n if (!this.isLeaderTab) {\n return;\n }\n\n const expiresAtMs = expiresAt * 1000;\n const warningTime = expiresAtMs - this.expiringThresholdMs;\n\n // Add jitter: random value between -jitter and +jitter\n const jitter = Math.random() * this.expiringJitterMs * 2 - this.expiringJitterMs;\n const delay = warningTime - Date.now() + jitter;\n\n // Only schedule if the warning time is in the future\n if (delay > 0) {\n this.expiringTimeout = setTimeout(() => {\n const now = Date.now();\n const expiresIn = Math.max(0, Math.floor((expiresAtMs - now) / 1000));\n\n this.eventEmitter?.emit('token:expiring', {\n expiresAt,\n expiresIn,\n timestamp: now,\n source: 'core',\n });\n }, delay);\n }\n }\n\n /**\n * Set leader tab status\n *\n * When not the leader, expiring event scheduling is disabled\n * to prevent multiple tabs from triggering simultaneous refreshes.\n *\n * @param isLeader - Whether this tab is the leader\n */\n setLeaderTab(isLeader: boolean): void {\n this.isLeaderTab = isLeader;\n\n if (!isLeader && this.expiringTimeout) {\n clearTimeout(this.expiringTimeout);\n this.expiringTimeout = null;\n }\n }\n\n /**\n * Set current operation ID for event tracking\n */\n setOperationId(operationId: string | null): void {\n this.currentOperationId = operationId;\n }\n\n /**\n * Get current operation ID\n */\n getOperationId(): string | null {\n return this.currentOperationId;\n }\n\n /**\n * Clear all tokens from storage\n */\n async clearTokens(): Promise<void> {\n await this.storage.remove(this.tokenKey);\n await this.storage.remove(this.idTokenKey);\n }\n\n /**\n * Get access token, refreshing if necessary\n *\n * This method coalesces concurrent refresh requests - if multiple\n * calls are made while a refresh is in-flight, they all share the\n * same refresh operation.\n *\n * @returns Access token\n * @throws AuthrimError if no tokens available or refresh fails\n */\n async getAccessToken(): Promise<string> {\n const tokens = await this.getTokens();\n\n if (!tokens) {\n throw new AuthrimError('no_tokens', 'No tokens available. Please authenticate first.');\n }\n\n // Check if token needs refresh (with skew)\n if (this.shouldRefresh(tokens)) {\n if (!tokens.refreshToken) {\n throw new AuthrimError(\n 'token_expired',\n 'Access token expired and no refresh token available'\n );\n }\n return this.refreshWithLock(tokens.refreshToken);\n }\n\n return tokens.accessToken;\n }\n\n /**\n * Get ID token\n *\n * @returns ID token or null\n */\n async getIdToken(): Promise<string | null> {\n const tokens = await this.getTokens();\n return tokens?.idToken ?? null;\n }\n\n /**\n * Check if token needs refresh\n *\n * @param tokens - Token set to check\n * @returns True if token should be refreshed\n */\n private shouldRefresh(tokens: TokenSet): boolean {\n const now = Math.floor(Date.now() / 1000);\n return tokens.expiresAt - this.refreshSkewSeconds <= now;\n }\n\n /**\n * Refresh token with in-flight request coalescing\n *\n * If a refresh is already in progress, wait for it instead of\n * starting a new one.\n *\n * @param refreshToken - Refresh token to use\n * @param reason - Reason for refresh\n * @returns Access token from new token set\n */\n private async refreshWithLock(\n refreshToken: string,\n reason: 'expiring' | 'manual' | 'on_demand' | 'background' = 'on_demand'\n ): Promise<string> {\n // If refresh is already in-flight, wait for it\n if (this.refreshPromise) {\n const tokens = await this.refreshPromise;\n return tokens.accessToken;\n }\n\n // Start new refresh operation\n this.refreshPromise = this.doRefreshWithRetry(refreshToken, reason);\n\n try {\n const tokens = await this.refreshPromise;\n return tokens.accessToken;\n } finally {\n // ALWAYS clear promise (success or failure)\n this.refreshPromise = null;\n }\n }\n\n /**\n * Manually refresh tokens\n *\n * @returns New token set\n * @throws AuthrimError if refresh fails\n */\n async refresh(): Promise<TokenSet> {\n const tokens = await this.getTokens();\n if (!tokens?.refreshToken) {\n throw new AuthrimError('no_tokens', 'No refresh token available');\n }\n\n // Start new refresh with manual reason\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.refreshPromise = this.doRefreshWithRetry(tokens.refreshToken, 'manual');\n\n try {\n return await this.refreshPromise;\n } finally {\n this.refreshPromise = null;\n }\n }\n\n /**\n * Perform refresh with retry for network errors\n *\n * @param refreshToken - Refresh token to use\n * @param reason - Reason for refresh\n * @param attempt - Current retry attempt (0-indexed)\n * @returns New token set\n */\n private async doRefreshWithRetry(\n refreshToken: string,\n reason: 'expiring' | 'manual' | 'on_demand' | 'background' = 'on_demand',\n attempt = 0\n ): Promise<TokenSet> {\n const maxRetries = 1;\n const timestamp = Date.now();\n\n // Emit refreshing event on first attempt\n if (attempt === 0) {\n this.eventEmitter?.emit('token:refreshing', {\n reason,\n timestamp,\n source: 'core',\n operationId: this.currentOperationId ?? undefined,\n });\n }\n\n try {\n return await this.doRefresh(refreshToken);\n } catch (error) {\n const authrimError = error instanceof AuthrimError\n ? error\n : new AuthrimError('refresh_error', 'Token refresh failed', {\n cause: error instanceof Error ? error : undefined,\n });\n\n const willRetry = attempt < maxRetries && isRetryableError(authrimError);\n\n // Emit refresh failed event\n this.eventEmitter?.emit('token:refresh:failed', {\n error: authrimError,\n willRetry,\n attempt,\n timestamp: Date.now(),\n source: 'core',\n operationId: this.currentOperationId ?? undefined,\n });\n\n // Retry once for retryable errors\n if (willRetry) {\n return this.doRefreshWithRetry(refreshToken, reason, attempt + 1);\n }\n\n // Emit auth:required if refresh failed and not retryable\n if (!isRetryableError(authrimError)) {\n this.eventEmitter?.emit('auth:required', {\n reason: 'refresh_failed',\n timestamp: Date.now(),\n source: 'core',\n operationId: this.currentOperationId ?? undefined,\n });\n }\n\n throw error;\n }\n }\n\n /**\n * Perform the actual token refresh\n *\n * @param refreshToken - Refresh token to use\n * @returns New token set\n */\n private async doRefresh(refreshToken: string): Promise<TokenSet> {\n if (!this.discovery) {\n throw new AuthrimError('no_discovery', 'Discovery document not set');\n }\n\n const tokenEndpoint = this.discovery.token_endpoint;\n\n // Build refresh request\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.clientId,\n refresh_token: refreshToken,\n });\n\n let response;\n try {\n response = await this.http.fetch<TokenResponse>(tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n const authrimError = new AuthrimError('network_error', 'Token refresh request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n this.eventEmitter?.emit('token:error', {\n error: authrimError,\n context: 'refresh',\n timestamp: Date.now(),\n source: 'core',\n });\n // Also emit classified error events (error:recoverable or error:fatal)\n if (this.eventEmitter) {\n emitClassifiedError(this.eventEmitter, authrimError, { context: 'refresh' });\n }\n throw authrimError;\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n const authrimError = new AuthrimError('refresh_error', 'Token refresh failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n this.eventEmitter?.emit('token:error', {\n error: authrimError,\n context: 'refresh',\n timestamp: Date.now(),\n source: 'core',\n });\n // Also emit classified error events (error:recoverable or error:fatal)\n if (this.eventEmitter) {\n emitClassifiedError(this.eventEmitter, authrimError, { context: 'refresh' });\n }\n throw authrimError;\n }\n\n const tokenResponse = response.data;\n\n // Calculate expiresAt\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = tokenResponse.expires_in ? now + tokenResponse.expires_in : now + 3600;\n\n // Build new token set (preserve old refresh token if new one not provided)\n const newTokens: TokenSet = {\n accessToken: tokenResponse.access_token,\n tokenType: (tokenResponse.token_type as 'Bearer') ?? 'Bearer',\n expiresAt,\n refreshToken: tokenResponse.refresh_token ?? refreshToken,\n idToken: tokenResponse.id_token,\n scope: tokenResponse.scope,\n };\n\n // Save new tokens\n await this.saveTokens(newTokens);\n\n // Emit event with new format (no token values for security)\n this.eventEmitter?.emit('token:refreshed', {\n hasAccessToken: !!newTokens.accessToken,\n hasRefreshToken: !!newTokens.refreshToken,\n hasIdToken: !!newTokens.idToken,\n expiresAt: newTokens.expiresAt,\n timestamp: Date.now(),\n source: 'core',\n operationId: this.currentOperationId ?? undefined,\n });\n\n return newTokens;\n }\n\n /**\n * Check if user is authenticated\n *\n * @returns True if valid tokens exist\n */\n async isAuthenticated(): Promise<boolean> {\n const tokens = await this.getTokens();\n if (!tokens) {\n return false;\n }\n\n // Check if access token is expired (without skew)\n const now = Math.floor(Date.now() / 1000);\n if (tokens.expiresAt <= now) {\n // Token expired - check if we have refresh token\n return !!tokens.refreshToken;\n }\n\n return true;\n }\n\n /**\n * Exchange a token using RFC 8693 Token Exchange\n *\n * This allows exchanging tokens for different audiences or scopes,\n * delegation scenarios, and cross-service token acquisition.\n *\n * @param request - Token exchange request parameters\n * @returns Token exchange result with new tokens and issued token type\n * @throws AuthrimError if exchange fails\n */\n async exchangeToken(request: TokenExchangeRequest): Promise<TokenExchangeResult> {\n if (!this.discovery) {\n throw new AuthrimError('no_discovery', 'Discovery document not set');\n }\n\n const tokenEndpoint = this.discovery.token_endpoint;\n\n // Map short token type names to URIs\n const subjectTokenType = this.mapTokenTypeToUri(request.subjectTokenType ?? 'access_token');\n\n // Build token exchange request\n const body = new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n client_id: this.clientId,\n subject_token: request.subjectToken,\n subject_token_type: subjectTokenType,\n });\n\n // Optional parameters\n if (request.audience) {\n body.set('audience', request.audience);\n }\n if (request.scope) {\n body.set('scope', request.scope);\n }\n if (request.requestedTokenType) {\n body.set('requested_token_type', this.mapTokenTypeToUri(request.requestedTokenType));\n }\n if (request.actorToken) {\n body.set('actor_token', request.actorToken);\n if (request.actorTokenType) {\n body.set('actor_token_type', this.mapTokenTypeToUri(request.actorTokenType));\n }\n }\n\n let response;\n try {\n response = await this.http.fetch<TokenExchangeResponse>(tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n const authrimError = new AuthrimError('network_error', 'Token exchange request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n this.eventEmitter?.emit('token:error', {\n error: authrimError,\n context: 'exchange',\n timestamp: Date.now(),\n source: 'core',\n });\n // Also emit classified error events (error:recoverable or error:fatal)\n if (this.eventEmitter) {\n emitClassifiedError(this.eventEmitter, authrimError, { context: 'exchange' });\n }\n throw authrimError;\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n const authrimError = new AuthrimError('token_exchange_error', 'Token exchange failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n this.eventEmitter?.emit('token:error', {\n error: authrimError,\n context: 'exchange',\n timestamp: Date.now(),\n source: 'core',\n });\n // Also emit classified error events (error:recoverable or error:fatal)\n if (this.eventEmitter) {\n emitClassifiedError(this.eventEmitter, authrimError, { context: 'exchange' });\n }\n throw authrimError;\n }\n\n const tokenResponse = response.data;\n\n // Calculate expiresAt\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = tokenResponse.expires_in ? now + tokenResponse.expires_in : now + 3600;\n\n const tokens: TokenSet = {\n accessToken: tokenResponse.access_token,\n tokenType: (tokenResponse.token_type as 'Bearer') ?? 'Bearer',\n expiresAt,\n refreshToken: tokenResponse.refresh_token,\n idToken: tokenResponse.id_token,\n scope: tokenResponse.scope,\n };\n\n const result: TokenExchangeResult = {\n tokens,\n issuedTokenType: tokenResponse.issued_token_type,\n };\n\n // Emit event with new format (no token values for security)\n this.eventEmitter?.emit('token:exchanged', {\n hasAccessToken: !!tokens.accessToken,\n hasRefreshToken: !!tokens.refreshToken,\n issuedTokenType: tokenResponse.issued_token_type,\n timestamp: Date.now(),\n source: 'core',\n operationId: this.currentOperationId ?? undefined,\n });\n\n return result;\n }\n\n /**\n * Map short token type to URI (RFC 8693)\n */\n private mapTokenTypeToUri(type: 'access_token' | 'refresh_token' | 'id_token'): string {\n return TOKEN_TYPE_URIS[type];\n }\n\n /**\n * Clean up resources\n */\n destroy(): void {\n if (this.expiringTimeout) {\n clearTimeout(this.expiringTimeout);\n this.expiringTimeout = null;\n }\n }\n}\n","/**\n * Token Introspection (RFC 7662)\n *\n * Implements OAuth 2.0 Token Introspection to validate tokens server-side.\n * https://datatracker.ietf.org/doc/html/rfc7662\n */\n\nimport type { HttpClient, OAuthErrorResponse } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Token type hint for introspection\n */\nexport type IntrospectionTokenTypeHint = 'access_token' | 'refresh_token';\n\n/**\n * Token introspection response (RFC 7662)\n */\nexport interface IntrospectionResponse {\n /** Whether the token is active */\n active: boolean;\n /** Space-separated list of scopes (if active) */\n scope?: string;\n /** Client identifier (if active) */\n client_id?: string;\n /** Human-readable username (if active) */\n username?: string;\n /** Token type (e.g., \"Bearer\") */\n token_type?: string;\n /** Expiration time (Unix timestamp) */\n exp?: number;\n /** Issued at time (Unix timestamp) */\n iat?: number;\n /** Not before time (Unix timestamp) */\n nbf?: number;\n /** Subject identifier */\n sub?: string;\n /** Audience (single string or array) */\n aud?: string | string[];\n /** Issuer identifier */\n iss?: string;\n /** JWT ID */\n jti?: string;\n /** Additional claims */\n [key: string]: unknown;\n}\n\n/**\n * Token introspection options\n */\nexport interface IntrospectTokenOptions {\n /** Token to introspect */\n token: string;\n /** Hint about the token type (optional, helps server optimize lookup) */\n tokenTypeHint?: IntrospectionTokenTypeHint;\n}\n\n/**\n * Token introspector options\n */\nexport interface TokenIntrospectorOptions {\n /** HTTP client */\n http: HttpClient;\n /** Client ID */\n clientId: string;\n}\n\n/**\n * Token Introspector\n *\n * Handles token introspection requests to the authorization server.\n */\nexport class TokenIntrospector {\n private readonly http: HttpClient;\n private readonly clientId: string;\n\n constructor(options: TokenIntrospectorOptions) {\n this.http = options.http;\n this.clientId = options.clientId;\n }\n\n /**\n * Introspect a token\n *\n * Per RFC 7662, the introspection endpoint returns:\n * - { active: true, ... } for valid tokens with additional metadata\n * - { active: false } for invalid, expired, or revoked tokens\n *\n * @param discovery - OIDC discovery document\n * @param options - Introspection options\n * @returns Introspection response\n * @throws AuthrimError if introspection endpoint is not available or request fails\n */\n async introspect(\n discovery: OIDCDiscoveryDocument,\n options: IntrospectTokenOptions\n ): Promise<IntrospectionResponse> {\n const endpoint = discovery.introspection_endpoint;\n\n if (!endpoint) {\n throw new AuthrimError(\n 'no_introspection_endpoint',\n 'Authorization server does not support token introspection'\n );\n }\n\n return this.introspectWithEndpoint(endpoint, options);\n }\n\n /**\n * Introspect a token directly using the endpoint URL\n *\n * Use this when you have the endpoint URL but not the full discovery document.\n *\n * @param endpoint - Introspection endpoint URL\n * @param options - Introspection options\n * @returns Introspection response\n * @throws AuthrimError if request fails\n */\n async introspectWithEndpoint(\n endpoint: string,\n options: IntrospectTokenOptions\n ): Promise<IntrospectionResponse> {\n // Build introspection request\n const body = new URLSearchParams({\n client_id: this.clientId,\n token: options.token,\n });\n\n if (options.tokenTypeHint) {\n body.set('token_type_hint', options.tokenTypeHint);\n }\n\n let response;\n try {\n response = await this.http.fetch<IntrospectionResponse | OAuthErrorResponse>(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Token introspection request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n const errorData = response.data as OAuthErrorResponse | undefined;\n throw new AuthrimError('introspection_error', 'Token introspection failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n return response.data as IntrospectionResponse;\n }\n\n /**\n * Check if a token is active\n *\n * Convenience method that returns only the active status.\n *\n * @param discovery - OIDC discovery document\n * @param token - Token to check\n * @returns True if token is active\n */\n async isActive(discovery: OIDCDiscoveryDocument, token: string): Promise<boolean> {\n const result = await this.introspect(discovery, { token });\n return result.active;\n }\n}\n","/**\n * Token Revocation (RFC 7009)\n *\n * Implements OAuth 2.0 Token Revocation to explicitly invalidate tokens.\n * https://datatracker.ietf.org/doc/html/rfc7009\n */\n\nimport type { HttpClient, OAuthErrorResponse } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Token type hint for revocation\n */\nexport type TokenTypeHint = 'access_token' | 'refresh_token';\n\n/**\n * Token revocation options\n */\nexport interface RevokeTokenOptions {\n /** Token to revoke */\n token: string;\n /** Hint about the token type (optional, helps server optimize lookup) */\n tokenTypeHint?: TokenTypeHint;\n}\n\n/**\n * Token revoker options\n */\nexport interface TokenRevokerOptions {\n /** HTTP client */\n http: HttpClient;\n /** Client ID */\n clientId: string;\n}\n\n/**\n * Token Revoker\n *\n * Handles token revocation requests to the authorization server.\n */\nexport class TokenRevoker {\n private readonly http: HttpClient;\n private readonly clientId: string;\n\n constructor(options: TokenRevokerOptions) {\n this.http = options.http;\n this.clientId = options.clientId;\n }\n\n /**\n * Revoke a token\n *\n * Per RFC 7009, the revocation endpoint:\n * - Returns 200 OK on success (even if token was already invalid)\n * - Returns 400 for invalid requests\n * - Returns 503 if temporarily unavailable\n *\n * @param discovery - OIDC discovery document\n * @param options - Revocation options\n * @throws AuthrimError if revocation endpoint is not available or request fails\n */\n async revoke(discovery: OIDCDiscoveryDocument, options: RevokeTokenOptions): Promise<void> {\n const endpoint = discovery.revocation_endpoint;\n\n if (!endpoint) {\n throw new AuthrimError(\n 'no_revocation_endpoint',\n 'Authorization server does not support token revocation'\n );\n }\n\n // Build revocation request\n const body = new URLSearchParams({\n client_id: this.clientId,\n token: options.token,\n });\n\n if (options.tokenTypeHint) {\n body.set('token_type_hint', options.tokenTypeHint);\n }\n\n let response;\n try {\n response = await this.http.fetch<OAuthErrorResponse | void>(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Token revocation request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n // RFC 7009: 200 OK means success (even if token was already invalid)\n if (response.ok) {\n return;\n }\n\n // Handle error response\n const errorData = response.data as OAuthErrorResponse | undefined;\n throw new AuthrimError('revocation_error', 'Token revocation failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n /**\n * Revoke a token directly using the endpoint URL\n *\n * Use this when you have the endpoint URL but not the full discovery document.\n *\n * @param endpoint - Revocation endpoint URL\n * @param options - Revocation options\n * @throws AuthrimError if request fails\n */\n async revokeWithEndpoint(endpoint: string, options: RevokeTokenOptions): Promise<void> {\n // Build revocation request\n const body = new URLSearchParams({\n client_id: this.clientId,\n token: options.token,\n });\n\n if (options.tokenTypeHint) {\n body.set('token_type_hint', options.tokenTypeHint);\n }\n\n let response;\n try {\n response = await this.http.fetch<OAuthErrorResponse | void>(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Token revocation request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (response.ok) {\n return;\n }\n\n const errorData = response.data as OAuthErrorResponse | undefined;\n throw new AuthrimError('revocation_error', 'Token revocation failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n}\n","/**\n * Logout Handler\n *\n * Implements RP-Initiated Logout (OpenID Connect RP-Initiated Logout 1.0)\n * https://openid.net/specs/openid-connect-rpinitiated-1_0.html\n */\n\nimport type { AuthrimStorage } from '../providers/storage.js';\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { TokenSet } from '../types/token.js';\nimport type { EventEmitter } from '../events/emitter.js';\nimport type { EndpointOverrides } from '../client/config.js';\nimport { STORAGE_KEYS } from '../auth/state.js';\nimport { TokenRevoker } from '../token/revocation.js';\n\n/**\n * Logout options\n */\nexport interface LogoutOptions {\n /** URI to redirect to after logout */\n postLogoutRedirectUri?: string;\n /** ID token hint (optional, uses stored ID token if not provided) */\n idTokenHint?: string;\n /** State parameter for post-logout redirect */\n state?: string;\n /** Whether to revoke tokens before logout (requires revocation_endpoint) */\n revokeTokens?: boolean;\n}\n\n/**\n * Logout result\n */\nexport interface LogoutResult {\n /** Logout URL to redirect to (if IdP supports end_session_endpoint) */\n logoutUrl?: string;\n /** True if only local logout was performed (IdP doesn't support RP-Initiated Logout) */\n localOnly: boolean;\n /** Token revocation result (if revokeTokens was true) */\n revocation?: {\n /** Whether revocation was attempted */\n attempted: boolean;\n /** Whether access token revocation succeeded */\n accessTokenRevoked?: boolean;\n /** Whether refresh token revocation succeeded */\n refreshTokenRevoked?: boolean;\n /** Error if revocation failed (logout still proceeds) */\n error?: Error;\n };\n}\n\n/**\n * Logout handler options\n */\nexport interface LogoutHandlerOptions {\n /** Storage provider */\n storage: AuthrimStorage;\n /** HTTP client (for token revocation) */\n http: HttpClient;\n /** Client ID */\n clientId: string;\n /** Issuer hash for storage keys */\n issuerHash: string;\n /** Client ID hash for storage keys */\n clientIdHash: string;\n /** Event emitter */\n eventEmitter?: EventEmitter;\n /** Endpoint overrides */\n endpoints?: EndpointOverrides;\n}\n\n/**\n * Logout Handler\n */\nexport class LogoutHandler {\n private readonly storage: AuthrimStorage;\n private readonly clientId: string;\n private readonly issuerHash: string;\n private readonly clientIdHash: string;\n private readonly eventEmitter?: EventEmitter;\n private readonly endpoints?: EndpointOverrides;\n private readonly tokenRevoker: TokenRevoker;\n\n constructor(options: LogoutHandlerOptions) {\n this.storage = options.storage;\n this.clientId = options.clientId;\n this.issuerHash = options.issuerHash;\n this.clientIdHash = options.clientIdHash;\n this.eventEmitter = options.eventEmitter;\n this.endpoints = options.endpoints;\n this.tokenRevoker = new TokenRevoker({\n http: options.http,\n clientId: options.clientId,\n });\n }\n\n /**\n * Perform logout\n *\n * 1. Optionally revokes tokens at the authorization server (if revokeTokens=true)\n * 2. Clears local tokens (always)\n * 3. Emits session:ended event\n * 4. Builds logout URL if IdP supports end_session_endpoint\n *\n * @param discovery - OIDC discovery document\n * @param options - Logout options\n * @returns Logout result\n */\n async logout(\n discovery: OIDCDiscoveryDocument | null,\n options?: LogoutOptions\n ): Promise<LogoutResult> {\n // Get stored tokens BEFORE clearing (for revocation and logout URL)\n const storedIdToken = await this.getStoredIdToken();\n const storedTokens = await this.getStoredTokens();\n\n // Revoke tokens if requested\n let revocationResult: LogoutResult['revocation'];\n if (options?.revokeTokens && discovery?.revocation_endpoint && storedTokens) {\n revocationResult = await this.revokeTokens(discovery, storedTokens);\n }\n\n // Clear local tokens\n await this.clearTokens();\n\n // Emit session ended event\n this.eventEmitter?.emit('session:ended', {\n reason: 'logout',\n timestamp: Date.now(),\n source: 'core',\n });\n\n // Determine end_session_endpoint\n // Priority: config override > discovery > null\n let endSessionEndpoint: string | null | undefined;\n\n if (this.endpoints?.endSession !== undefined) {\n // Explicit override (can be null to disable)\n endSessionEndpoint = this.endpoints.endSession;\n } else if (discovery) {\n endSessionEndpoint = discovery.end_session_endpoint;\n }\n\n // If no end_session_endpoint, return local-only logout\n if (!endSessionEndpoint) {\n return { localOnly: true, revocation: revocationResult };\n }\n\n // Build logout URL (use stored token if not provided in options)\n const idToken = options?.idTokenHint ?? storedIdToken;\n\n const params = new URLSearchParams({\n client_id: this.clientId,\n });\n\n if (idToken) {\n params.set('id_token_hint', idToken);\n }\n if (options?.postLogoutRedirectUri) {\n params.set('post_logout_redirect_uri', options.postLogoutRedirectUri);\n }\n if (options?.state) {\n params.set('state', options.state);\n }\n\n return {\n logoutUrl: `${endSessionEndpoint}?${params.toString()}`,\n localOnly: false,\n revocation: revocationResult,\n };\n }\n\n /**\n * Revoke tokens at the authorization server\n *\n * Best-effort: if revocation fails, logout still proceeds\n *\n * @param discovery - OIDC discovery document\n * @param tokens - Tokens to revoke\n * @returns Revocation result\n */\n private async revokeTokens(\n discovery: OIDCDiscoveryDocument,\n tokens: TokenSet\n ): Promise<NonNullable<LogoutResult['revocation']>> {\n const result: NonNullable<LogoutResult['revocation']> = {\n attempted: true,\n };\n\n try {\n // Revoke refresh token first (if present) - this often invalidates access token too\n if (tokens.refreshToken) {\n await this.tokenRevoker.revoke(discovery, {\n token: tokens.refreshToken,\n tokenTypeHint: 'refresh_token',\n });\n result.refreshTokenRevoked = true;\n }\n\n // Revoke access token\n await this.tokenRevoker.revoke(discovery, {\n token: tokens.accessToken,\n tokenTypeHint: 'access_token',\n });\n result.accessTokenRevoked = true;\n } catch (error) {\n result.error = error instanceof Error ? error : new Error(String(error));\n }\n\n return result;\n }\n\n /**\n * Clear all tokens from storage\n */\n private async clearTokens(): Promise<void> {\n const tokenKey = STORAGE_KEYS.tokens(this.issuerHash, this.clientIdHash);\n const idTokenKey = STORAGE_KEYS.idToken(this.issuerHash, this.clientIdHash);\n\n await this.storage.remove(tokenKey);\n await this.storage.remove(idTokenKey);\n }\n\n /**\n * Get stored ID token\n */\n private async getStoredIdToken(): Promise<string | null> {\n const idTokenKey = STORAGE_KEYS.idToken(this.issuerHash, this.clientIdHash);\n return this.storage.get(idTokenKey);\n }\n\n /**\n * Get stored tokens\n */\n private async getStoredTokens(): Promise<TokenSet | null> {\n const tokenKey = STORAGE_KEYS.tokens(this.issuerHash, this.clientIdHash);\n const stored = await this.storage.get(tokenKey);\n if (!stored) {\n return null;\n }\n try {\n return JSON.parse(stored) as TokenSet;\n } catch {\n return null;\n }\n }\n}\n","/**\n * Token API Client\n *\n * Provides session verification against the authorization server.\n * Uses the UserInfo endpoint or custom session check endpoint.\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument, UserInfo } from '../types/oidc.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Session check result\n */\nexport interface SessionCheckResult {\n /** Whether session is valid */\n valid: boolean;\n /** User info if session is valid */\n user?: UserInfo;\n /** Error if session is invalid */\n error?: AuthrimError;\n}\n\n/**\n * Token API client options\n */\nexport interface TokenApiClientOptions {\n /** HTTP client */\n http: HttpClient;\n}\n\n/**\n * Token API Client\n *\n * Verifies session status with the authorization server.\n */\nexport class TokenApiClient {\n private readonly http: HttpClient;\n\n constructor(options: TokenApiClientOptions) {\n this.http = options.http;\n }\n\n /**\n * Check session validity by calling UserInfo endpoint\n *\n * @param discovery - OIDC discovery document\n * @param accessToken - Access token to verify\n * @returns Session check result\n */\n async checkSession(\n discovery: OIDCDiscoveryDocument,\n accessToken: string\n ): Promise<SessionCheckResult> {\n const userinfoEndpoint = discovery.userinfo_endpoint;\n\n if (!userinfoEndpoint) {\n return {\n valid: false,\n error: new AuthrimError('no_userinfo_endpoint', 'UserInfo endpoint not available'),\n };\n }\n\n try {\n const response = await this.http.fetch<UserInfo>(userinfoEndpoint, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (!response.ok) {\n // 401 means token is invalid/expired\n if (response.status === 401) {\n return {\n valid: false,\n error: new AuthrimError('session_expired', 'Session has expired'),\n };\n }\n\n return {\n valid: false,\n error: new AuthrimError('session_check_failed', 'Session check failed', {\n details: { status: response.status },\n }),\n };\n }\n\n return {\n valid: true,\n user: response.data,\n };\n } catch (error) {\n return {\n valid: false,\n error: new AuthrimError('network_error', 'Failed to check session', {\n cause: error instanceof Error ? error : undefined,\n }),\n };\n }\n }\n\n /**\n * Get user info from the authorization server\n *\n * @param discovery - OIDC discovery document\n * @param accessToken - Access token\n * @returns User info\n * @throws AuthrimError if request fails\n */\n async getUserInfo(discovery: OIDCDiscoveryDocument, accessToken: string): Promise<UserInfo> {\n const userinfoEndpoint = discovery.userinfo_endpoint;\n\n if (!userinfoEndpoint) {\n throw new AuthrimError('no_userinfo_endpoint', 'UserInfo endpoint not available');\n }\n\n let response;\n try {\n response = await this.http.fetch<UserInfo>(userinfoEndpoint, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Failed to fetch user info', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n throw new AuthrimError('userinfo_error', 'Failed to get user info', {\n details: { status: response.status },\n });\n }\n\n return response.data;\n }\n}\n","/**\n * Session Manager\n *\n * Coordinates session-related operations including checking\n * session status and retrieving user information.\n */\n\nimport type { OIDCDiscoveryDocument, UserInfo } from '../types/oidc.js';\nimport type { TokenManager } from '../token/manager.js';\nimport { TokenApiClient, type SessionCheckResult } from './token-api.js';\nexport type { SessionCheckResult };\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Session manager options\n */\nexport interface SessionManagerOptions {\n /** Token manager */\n tokenManager: TokenManager;\n /** Token API client */\n tokenApiClient: TokenApiClient;\n}\n\n/**\n * Session Manager\n */\nexport class SessionManager {\n private readonly tokenManager: TokenManager;\n private readonly tokenApiClient: TokenApiClient;\n\n /** Discovery document */\n private discovery: OIDCDiscoveryDocument | null = null;\n\n constructor(options: SessionManagerOptions) {\n this.tokenManager = options.tokenManager;\n this.tokenApiClient = options.tokenApiClient;\n }\n\n /**\n * Set discovery document\n */\n setDiscovery(discovery: OIDCDiscoveryDocument): void {\n this.discovery = discovery;\n }\n\n /**\n * Check if user is authenticated locally\n *\n * This checks if valid tokens exist in storage.\n * Does not verify with the authorization server.\n *\n * @returns True if tokens exist\n */\n async isAuthenticated(): Promise<boolean> {\n return this.tokenManager.isAuthenticated();\n }\n\n /**\n * Check session validity with authorization server\n *\n * Calls the UserInfo endpoint to verify the session is still valid.\n *\n * @returns Session check result\n */\n async checkSession(): Promise<SessionCheckResult> {\n if (!this.discovery) {\n return {\n valid: false,\n error: new AuthrimError('no_discovery', 'Discovery document not available'),\n };\n }\n\n try {\n const accessToken = await this.tokenManager.getAccessToken();\n return this.tokenApiClient.checkSession(this.discovery, accessToken);\n } catch (error) {\n if (error instanceof AuthrimError) {\n return { valid: false, error };\n }\n return {\n valid: false,\n error: new AuthrimError('session_check_failed', 'Failed to check session', {\n cause: error instanceof Error ? error : undefined,\n }),\n };\n }\n }\n\n /**\n * Get user information\n *\n * Fetches user info from the UserInfo endpoint.\n *\n * @returns User info\n * @throws AuthrimError if not authenticated or request fails\n */\n async getUser(): Promise<UserInfo> {\n if (!this.discovery) {\n throw new AuthrimError('no_discovery', 'Discovery document not available');\n }\n\n const accessToken = await this.tokenManager.getAccessToken();\n return this.tokenApiClient.getUserInfo(this.discovery, accessToken);\n }\n}\n","/**\n * Authrim Client\n *\n * Main entry point for the Authrim SDK.\n */\n\nimport type { AuthrimClientConfig, ResolvedConfig } from './config.js';\nimport type { OIDCDiscoveryDocument, UserInfo } from '../types/oidc.js';\nimport type { TokenSet, TokenExchangeRequest, TokenExchangeResult } from '../types/token.js';\nimport type { AuthrimEventName, AuthrimEventHandler } from '../events/types.js';\nimport type { DeviceFlowState, DeviceFlowPollResult, DeviceFlowStartOptions } from '../types/device-flow.js';\nimport type { PARResult } from '../types/par.js';\nimport type { DPoPCryptoProvider } from '../types/dpop.js';\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport { resolveConfig } from './config.js';\nimport { DiscoveryClient, normalizeIssuer } from './discovery.js';\nimport { EventEmitter } from '../events/emitter.js';\nimport { PKCEHelper } from '../auth/pkce.js';\nimport { StateManager } from '../auth/state.js';\nimport {\n AuthorizationCodeFlow,\n type BuildAuthorizationUrlOptions,\n type AuthorizationUrlResult,\n} from '../auth/authorization-code.js';\nimport { PARClient } from '../auth/par.js';\nimport { DeviceFlowClient } from '../auth/device-flow.js';\nimport { DPoPManager } from '../security/dpop.js';\nimport { TokenManager } from '../token/manager.js';\nimport {\n TokenIntrospector,\n type IntrospectionResponse,\n type IntrospectTokenOptions,\n} from '../token/introspection.js';\nimport { TokenRevoker, type RevokeTokenOptions } from '../token/revocation.js';\nimport { LogoutHandler, type LogoutOptions, type LogoutResult } from '../session/logout.js';\nimport { TokenApiClient } from '../session/token-api.js';\nimport { SessionManager } from '../session/manager.js';\nimport { base64urlEncode } from '../utils/base64url.js';\nimport { AuthrimError } from '../types/errors.js';\nimport type { IDiagnosticLogger } from '../debug/diagnostic-logger.js';\n\n/**\n * Hash a value for use in storage keys\n *\n * @param crypto - Crypto provider\n * @param value - Value to hash\n * @param length - Hash length (default: 16 = 96 bits)\n * @returns Base64url-encoded hash\n */\nasync function hashForKey(\n crypto: AuthrimClientConfig['crypto'],\n value: string,\n length = 16\n): Promise<string> {\n const hash = await crypto.sha256(value);\n return base64urlEncode(hash).slice(0, length);\n}\n\n/**\n * Authrim Client\n */\nexport class AuthrimClient {\n /** Resolved configuration */\n private readonly config: ResolvedConfig;\n\n /** Event emitter */\n private readonly events: EventEmitter;\n\n /** Discovery client */\n private readonly discoveryClient: DiscoveryClient;\n\n /** PKCE helper */\n private readonly pkce: PKCEHelper;\n\n /** State manager (initialized in initialize()) */\n private stateManager!: StateManager;\n\n /** Authorization code flow helper */\n private readonly authCodeFlow: AuthorizationCodeFlow;\n\n /** PAR client */\n private readonly parClient: PARClient;\n\n /** Device Flow client */\n private readonly deviceFlowClient: DeviceFlowClient;\n\n /** DPoP manager (lazily initialized) */\n private dpopManager: DPoPManager | null = null;\n\n /** Token manager (initialized in initialize()) */\n private tokenManager!: TokenManager;\n\n /** Logout handler (initialized in initialize()) */\n private logoutHandler!: LogoutHandler;\n\n /** Session manager (initialized in initialize()) */\n private sessionManager!: SessionManager;\n\n /** Token introspector */\n private tokenIntrospector!: TokenIntrospector;\n\n /** Token revoker */\n private tokenRevoker!: TokenRevoker;\n\n /** Issuer hash for storage keys */\n private issuerHash!: string;\n\n /** Client ID hash for storage keys */\n private clientIdHash!: string;\n\n /** Normalized issuer URL */\n private readonly normalizedIssuer: string;\n\n /** Whether the client has been initialized */\n private initialized = false;\n\n /** Diagnostic logger (optional, for OIDF conformance testing) */\n private diagnosticLogger: IDiagnosticLogger | null = null;\n\n /**\n * Get the event emitter for subscribing to SDK events\n */\n get eventEmitter(): EventEmitter {\n return this.events;\n }\n\n /**\n * Create a new Authrim client\n *\n * @internal Use createAuthrimClient() instead\n */\n constructor(config: AuthrimClientConfig) {\n this.config = resolveConfig(config);\n this.normalizedIssuer = normalizeIssuer(config.issuer);\n\n // Initialize components that don't need hashes\n this.events = new EventEmitter();\n\n this.discoveryClient = new DiscoveryClient({\n http: this.config.http,\n cacheTtlMs: this.config.discoveryCacheTtlMs,\n });\n\n this.pkce = new PKCEHelper(this.config.crypto);\n\n this.authCodeFlow = new AuthorizationCodeFlow(this.config.http, this.config.clientId);\n\n this.parClient = new PARClient(this.config.http, this.config.clientId);\n\n this.deviceFlowClient = new DeviceFlowClient(this.config.http, this.config.clientId);\n }\n\n /**\n * Initialize the client\n *\n * @internal Called by createAuthrimClient()\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n // Calculate hashes for storage keys\n const hashLength = this.config.hashOptions.hashLength;\n this.issuerHash = await hashForKey(this.config.crypto, this.normalizedIssuer, hashLength);\n this.clientIdHash = await hashForKey(this.config.crypto, this.config.clientId, hashLength);\n\n // Initialize state manager\n this.stateManager = new StateManager(\n this.config.crypto,\n this.config.storage,\n this.issuerHash,\n this.clientIdHash\n );\n\n // Initialize token manager\n this.tokenManager = new TokenManager({\n http: this.config.http,\n storage: this.config.storage,\n clientId: this.config.clientId,\n issuerHash: this.issuerHash,\n clientIdHash: this.clientIdHash,\n refreshSkewSeconds: this.config.refreshSkewSeconds,\n eventEmitter: this.events,\n });\n\n // Initialize logout handler\n this.logoutHandler = new LogoutHandler({\n storage: this.config.storage,\n http: this.config.http,\n clientId: this.config.clientId,\n issuerHash: this.issuerHash,\n clientIdHash: this.clientIdHash,\n eventEmitter: this.events,\n endpoints: this.config.endpoints,\n });\n\n // Initialize token introspector\n this.tokenIntrospector = new TokenIntrospector({\n http: this.config.http,\n clientId: this.config.clientId,\n });\n\n // Initialize token revoker\n this.tokenRevoker = new TokenRevoker({\n http: this.config.http,\n clientId: this.config.clientId,\n });\n\n // Initialize token API client\n const tokenApiClient = new TokenApiClient({\n http: this.config.http,\n });\n\n // Initialize session manager\n this.sessionManager = new SessionManager({\n tokenManager: this.tokenManager,\n tokenApiClient,\n });\n\n // Clean up expired states (best-effort)\n await this.stateManager.cleanupExpiredStates();\n\n this.initialized = true;\n }\n\n /**\n * Ensure client is initialized\n */\n private ensureInitialized(): void {\n if (!this.initialized) {\n throw new AuthrimError(\n 'not_initialized',\n 'Client not initialized. Use createAuthrimClient().'\n );\n }\n }\n\n /**\n * Get OIDC discovery document\n *\n * @returns Discovery document\n */\n async discover(): Promise<OIDCDiscoveryDocument> {\n const discovery = await this.discoveryClient.discover(this.normalizedIssuer);\n\n // Update dependent components\n this.tokenManager.setDiscovery(discovery);\n this.sessionManager.setDiscovery(discovery);\n\n return discovery;\n }\n\n // ============================================================\n // Authorization Code Flow\n // ============================================================\n\n /**\n * Build authorization URL\n *\n * Generates the URL to redirect the user to for authentication.\n * Stores state, nonce, and code_verifier in storage.\n *\n * @param options - Authorization options\n * @returns Authorization URL result\n */\n async buildAuthorizationUrl(\n options: BuildAuthorizationUrlOptions\n ): Promise<AuthorizationUrlResult> {\n this.ensureInitialized();\n\n const discovery = await this.discover();\n\n // Generate PKCE pair\n const pkcePair = await this.pkce.generatePKCE();\n\n // Determine scope (default: 'openid profile')\n const scope = options.scope ?? 'openid profile';\n\n // Generate auth state (including scope for validation during callback)\n const authState = await this.stateManager.generateAuthState({\n redirectUri: options.redirectUri,\n codeVerifier: pkcePair.codeVerifier,\n scope,\n ttlSeconds: this.config.stateTtlSeconds,\n });\n\n // Build URL\n const result = this.authCodeFlow.buildAuthorizationUrl(discovery, authState, pkcePair, options);\n\n // Emit event with operationId for tracking\n this.events.emit('auth:redirecting', {\n url: result.url,\n timestamp: Date.now(),\n source: 'core',\n operationId: authState.operationId,\n });\n\n return result;\n }\n\n /**\n * Handle authorization callback\n *\n * Processes the callback URL, validates state/nonce, and exchanges\n * the authorization code for tokens.\n *\n * @param callbackUrl - Callback URL or query string\n * @returns Token set\n */\n async handleCallback(callbackUrl: string): Promise<TokenSet> {\n this.ensureInitialized();\n\n // Parse callback\n const { code, state } = this.authCodeFlow.parseCallback(callbackUrl);\n\n // Validate and consume state (always deletes) - do this first to get operationId\n const authState = await this.stateManager.validateAndConsumeState(state);\n const operationId = authState.operationId;\n\n // Emit callback received event with operationId\n this.events.emit('auth:callback', {\n code,\n state,\n timestamp: Date.now(),\n source: 'core',\n operationId,\n });\n\n // Emit callback processing event\n this.events.emit('auth:callback:processing', {\n state,\n timestamp: Date.now(),\n source: 'core',\n operationId,\n });\n\n try {\n // Get discovery\n const discovery = await this.discover();\n\n // Exchange code for tokens\n const tokens = await this.authCodeFlow.exchangeCode(discovery, {\n code,\n state,\n redirectUri: authState.redirectUri,\n codeVerifier: authState.codeVerifier,\n nonce: authState.nonce,\n scope: authState.scope,\n });\n\n // Save tokens\n await this.tokenManager.saveTokens(tokens);\n\n // Emit callback complete event\n this.events.emit('auth:callback:complete', {\n success: true,\n timestamp: Date.now(),\n source: 'core',\n operationId,\n });\n\n return tokens;\n } catch (error) {\n // Emit callback complete event with failure\n this.events.emit('auth:callback:complete', {\n success: false,\n timestamp: Date.now(),\n source: 'core',\n operationId,\n });\n throw error;\n }\n }\n\n // ============================================================\n // PAR API (Pushed Authorization Request - RFC 9126)\n // ============================================================\n\n /**\n * PAR API accessor\n *\n * Provides access to Pushed Authorization Request functionality.\n * PAR allows pushing authorization request parameters to a dedicated endpoint,\n * receiving a request_uri to use in the authorization URL.\n */\n get par() {\n return {\n /**\n * Push authorization request and get request_uri\n *\n * @param options - Authorization options\n * @returns PAR result with request_uri and expiration\n */\n push: async (options: BuildAuthorizationUrlOptions): Promise<PARResult> => {\n this.ensureInitialized();\n const discovery = await this.discover();\n\n // Generate PKCE and state\n const pkcePair = await this.pkce.generatePKCE();\n const scope = options.scope ?? 'openid profile';\n const authState = await this.stateManager.generateAuthState({\n redirectUri: options.redirectUri,\n codeVerifier: pkcePair.codeVerifier,\n scope,\n ttlSeconds: this.config.stateTtlSeconds,\n });\n\n // Push to PAR endpoint\n return this.parClient.pushAuthorizationRequest(discovery, {\n redirectUri: options.redirectUri,\n scope,\n state: authState.state,\n nonce: authState.nonce,\n codeChallenge: pkcePair.codeChallenge,\n codeChallengeMethod: 'S256',\n prompt: options.prompt,\n loginHint: options.loginHint,\n acrValues: options.acrValues,\n extraParams: options.extraParams,\n });\n },\n\n /**\n * Build authorization URL using request_uri from PAR\n *\n * @param requestUri - Request URI from PAR response\n * @returns Authorization URL\n */\n buildAuthorizationUrl: async (requestUri: string): Promise<string> => {\n const discovery = await this.discover();\n return this.parClient.buildAuthorizationUrlWithPar(discovery, requestUri);\n },\n\n /**\n * Check if PAR is available\n *\n * @returns True if PAR endpoint is available\n */\n isAvailable: async (): Promise<boolean> => {\n const discovery = await this.discover();\n return !!discovery.pushed_authorization_request_endpoint;\n },\n\n /**\n * Check if PAR is required by the server\n *\n * @returns True if server requires PAR\n */\n isRequired: async (): Promise<boolean> => {\n const discovery = await this.discover();\n return discovery.require_pushed_authorization_requests === true;\n },\n };\n }\n\n // ============================================================\n // Device Flow API (RFC 8628)\n // ============================================================\n\n /**\n * Device Flow API accessor\n *\n * Provides access to Device Authorization Grant functionality.\n * Used for devices with limited input capabilities (TVs, CLIs, IoT).\n */\n get deviceFlow() {\n return {\n /**\n * Start device authorization\n *\n * @param options - Start options (scope, etc.)\n * @returns Device flow state with codes and URIs\n */\n start: async (options?: DeviceFlowStartOptions): Promise<DeviceFlowState> => {\n this.ensureInitialized();\n const discovery = await this.discover();\n return this.deviceFlowClient.startDeviceAuthorization(discovery, options);\n },\n\n /**\n * Poll once for token\n *\n * @param state - Device flow state\n * @returns Poll result\n */\n pollOnce: async (state: DeviceFlowState): Promise<DeviceFlowPollResult> => {\n const discovery = await this.discover();\n return this.deviceFlowClient.pollOnce(discovery, state);\n },\n\n /**\n * Poll until complete or expired\n *\n * @param state - Device flow state\n * @param options - Polling options (signal for abort)\n * @returns Token set on success\n */\n pollUntilComplete: async (\n state: DeviceFlowState,\n options?: { signal?: AbortSignal }\n ): Promise<TokenSet> => {\n const discovery = await this.discover();\n const tokens = await this.deviceFlowClient.pollUntilComplete(discovery, state, options);\n\n // Save tokens\n await this.tokenManager.saveTokens(tokens);\n\n return tokens;\n },\n\n /**\n * Check if Device Flow is available\n *\n * @returns True if device authorization endpoint is available\n */\n isAvailable: async (): Promise<boolean> => {\n const discovery = await this.discover();\n return !!discovery.device_authorization_endpoint;\n },\n };\n }\n\n // ============================================================\n // DPoP API (RFC 9449)\n // ============================================================\n\n /**\n * DPoP API accessor\n *\n * Provides access to DPoP (Demonstrating Proof of Possession) functionality.\n * DPoP binds access tokens to a cryptographic key held by the client,\n * preventing token theft and replay attacks.\n *\n * NOTE: The CryptoProvider must implement DPoPCryptoProvider interface\n * for DPoP to be available.\n *\n * @returns DPoP API accessor, or undefined if not supported\n */\n get dpop() {\n // Check if crypto provider supports DPoP\n const cryptoWithDPoP = this.config.crypto as DPoPCryptoProvider;\n if (!cryptoWithDPoP.generateDPoPKeyPair) {\n return undefined;\n }\n\n // Lazily initialize DPoP manager\n if (!this.dpopManager) {\n // Cast to the combined type that DPoPManager expects\n this.dpopManager = new DPoPManager(\n this.config.crypto as CryptoProvider & DPoPCryptoProvider\n );\n }\n\n const manager = this.dpopManager;\n\n return {\n /**\n * Initialize DPoP (generates or retrieves key pair)\n */\n initialize: () => manager.initialize(),\n\n /**\n * Check if DPoP is initialized\n */\n isInitialized: () => manager.isInitialized(),\n\n /**\n * Generate a DPoP proof for a request\n *\n * @param method - HTTP method (GET, POST, etc.)\n * @param uri - Full request URI\n * @param options - Additional options (access token hash, nonce)\n * @returns Signed DPoP proof JWT\n */\n generateProof: (\n method: string,\n uri: string,\n options?: { accessTokenHash?: string; nonce?: string }\n ) => manager.generateProof(method, uri, options),\n\n /**\n * Handle DPoP-Nonce response from server\n *\n * @param nonce - Server-provided nonce\n */\n handleNonceResponse: (nonce: string) => manager.handleNonceResponse(nonce),\n\n /**\n * Calculate access token hash for ath claim\n *\n * @param accessToken - Access token to hash\n * @returns Base64url-encoded SHA-256 hash\n */\n calculateAccessTokenHash: (accessToken: string) =>\n manager.calculateAccessTokenHash(accessToken),\n\n /**\n * Get the public key JWK\n */\n getPublicKeyJwk: () => manager.getPublicKeyJwk(),\n\n /**\n * Get the JWK thumbprint\n */\n getThumbprint: () => manager.getThumbprint(),\n\n /**\n * Clear DPoP key pair (call on logout)\n */\n clear: () => manager.clear(),\n\n /**\n * Check if DPoP is supported by the server\n *\n * @returns True if server advertises DPoP support\n */\n isServerSupported: async (): Promise<boolean> => {\n const discovery = await this.discover();\n return Array.isArray(discovery.dpop_signing_alg_values_supported) &&\n discovery.dpop_signing_alg_values_supported.length > 0;\n },\n };\n }\n\n // ============================================================\n // Token API\n // ============================================================\n\n /**\n * Token API accessor\n */\n get token() {\n this.ensureInitialized();\n return {\n /**\n * Get access token (refreshes if needed)\n */\n getAccessToken: () => this.tokenManager.getAccessToken(),\n\n /**\n * Get current tokens\n */\n getTokens: () => this.tokenManager.getTokens(),\n\n /**\n * Get ID token\n */\n getIdToken: () => this.tokenManager.getIdToken(),\n\n /**\n * Check if authenticated\n */\n isAuthenticated: () => this.tokenManager.isAuthenticated(),\n\n /**\n * Exchange token (RFC 8693)\n *\n * Exchanges a token for a new token with different audience, scope,\n * or delegation. Useful for:\n * - Cross-service token acquisition\n * - Delegation (actor token)\n * - Scope reduction\n *\n * @param request - Token exchange request parameters\n * @returns Token exchange result\n */\n exchange: async (request: TokenExchangeRequest): Promise<TokenExchangeResult> => {\n // Ensure discovery is loaded\n await this.discover();\n return this.tokenManager.exchangeToken(request);\n },\n\n /**\n * Introspect a token (RFC 7662)\n *\n * Validates a token server-side and returns its metadata.\n * Useful for resource servers to validate access tokens.\n *\n * @param options - Introspection options (token and optional type hint)\n * @returns Introspection response with token metadata\n * @throws AuthrimError if introspection endpoint not available or request fails\n */\n introspect: async (options: IntrospectTokenOptions): Promise<IntrospectionResponse> => {\n const discovery = await this.discover();\n return this.tokenIntrospector.introspect(discovery, options);\n },\n\n /**\n * Revoke a token (RFC 7009)\n *\n * Explicitly invalidates a token at the authorization server.\n * Use this when you want to ensure a token can no longer be used.\n *\n * @param options - Revocation options (token and optional type hint)\n * @throws AuthrimError if revocation endpoint not available or request fails\n */\n revoke: async (options: RevokeTokenOptions): Promise<void> => {\n const discovery = await this.discover();\n return this.tokenRevoker.revoke(discovery, options);\n },\n };\n }\n\n // ============================================================\n // Session API\n // ============================================================\n\n /**\n * Session API accessor\n */\n get session() {\n this.ensureInitialized();\n return {\n /**\n * Check if authenticated locally\n */\n isAuthenticated: () => this.sessionManager.isAuthenticated(),\n\n /**\n * Check session with authorization server\n */\n check: () => this.sessionManager.checkSession(),\n };\n }\n\n /**\n * Check if user is authenticated\n *\n * @returns True if tokens exist\n */\n async isAuthenticated(): Promise<boolean> {\n this.ensureInitialized();\n return this.tokenManager.isAuthenticated();\n }\n\n /**\n * Get user information\n *\n * @returns User info\n */\n async getUser(): Promise<UserInfo> {\n this.ensureInitialized();\n return this.sessionManager.getUser();\n }\n\n // ============================================================\n // Logout\n // ============================================================\n\n /**\n * Log out the user\n *\n * Clears local tokens and optionally redirects to IdP for logout.\n *\n * @param options - Logout options\n * @returns Logout result\n */\n async logout(options?: LogoutOptions): Promise<LogoutResult> {\n this.ensureInitialized();\n\n let discovery: OIDCDiscoveryDocument | null = null;\n try {\n discovery = await this.discover();\n } catch {\n // Discovery failure is OK for logout - we can still do local logout\n }\n\n return this.logoutHandler.logout(discovery, options);\n }\n\n // ============================================================\n // Diagnostic Logging\n // ============================================================\n\n /**\n * Set diagnostic logger for OIDF conformance testing\n *\n * When a diagnostic logger is set, the SDK will log token validation steps,\n * authentication decisions, and other diagnostic information.\n *\n * @param logger - Diagnostic logger instance (or null to disable)\n */\n setDiagnosticLogger(logger: IDiagnosticLogger | null): void {\n this.diagnosticLogger = logger;\n\n // Set diagnostic logger on authorization code flow\n this.authCodeFlow.setDiagnosticLogger(logger);\n }\n\n /**\n * Get diagnostic session ID (if diagnostic logging is enabled)\n *\n * This ID should be sent to the server via X-Diagnostic-Session-Id header\n * to correlate SDK logs with server logs.\n *\n * @returns Diagnostic session ID or null if diagnostic logging is disabled\n */\n getDiagnosticSessionId(): string | null {\n return this.diagnosticLogger?.getDiagnosticSessionId() ?? null;\n }\n\n // ============================================================\n // Events\n // ============================================================\n\n /**\n * Subscribe to an event\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n */\n on<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): () => void {\n return this.events.on(event, handler);\n }\n\n /**\n * Subscribe to an event (one-time)\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n */\n once<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): () => void {\n return this.events.once(event, handler);\n }\n\n /**\n * Unsubscribe from an event\n *\n * @param event - Event name\n * @param handler - Event handler\n */\n off<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): void {\n this.events.off(event, handler);\n }\n}\n\n/**\n * Create an Authrim client\n *\n * This is the main entry point for creating a client.\n * The client is fully initialized when returned.\n *\n * @param config - Client configuration\n * @returns Initialized Authrim client\n */\nexport async function createAuthrimClient(config: AuthrimClientConfig): Promise<AuthrimClient> {\n const client = new AuthrimClient(config);\n await client.initialize();\n return client;\n}\n","/**\n * Silent Authentication (prompt=none)\n *\n * Foundation for silent authentication using OIDC prompt=none.\n * This module provides the core logic for building silent auth requests\n * and parsing responses. The actual iframe/hidden frame implementation\n * is platform-specific and should be implemented in @authrim/web or similar.\n *\n * Silent authentication allows checking if a user has an active session\n * with the authorization server without user interaction.\n */\n\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { TokenSet } from '../types/token.js';\nimport type { AuthState } from './state.js';\nimport type { PKCEPair } from './pkce.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Silent authentication options\n */\nexport interface SilentAuthOptions {\n /** Redirect URI for silent auth response (often an iframe callback page) */\n redirectUri: string;\n /** Scopes to request (default: 'openid') */\n scope?: string;\n /**\n * Response type (default: 'code')\n *\n * Use 'none' for session check without token issuance\n * (OAuth 2.0 Multiple Response Types 1.0 §5)\n */\n responseType?: 'code' | 'none';\n /** Hint about the login identifier */\n loginHint?: string;\n /** ID token hint (helps IdP identify the user) */\n idTokenHint?: string;\n /** Additional custom parameters */\n extraParams?: Record<string, string>;\n /**\n * Expose state/nonce in result (for SSR/external storage)\n *\n * Default: false (security: state/nonce stay internal)\n */\n exposeState?: boolean;\n}\n\n/**\n * Result of building silent auth URL\n */\nexport interface SilentAuthUrlResult {\n /** Authorization URL with prompt=none */\n url: string;\n /** State parameter (only if exposeState: true) */\n state?: string;\n /** Nonce parameter (only if exposeState: true) */\n nonce?: string;\n}\n\n/**\n * Silent authentication result\n */\nexport interface SilentAuthResult {\n /** Whether silent auth succeeded */\n success: boolean;\n /** Tokens if successful */\n tokens?: TokenSet;\n /** Error if failed (e.g., login_required) */\n error?: AuthrimError;\n}\n\n/**\n * Silent auth error codes that indicate interactive login is needed\n */\nconst INTERACTIVE_LOGIN_REQUIRED_ERRORS = new Set([\n 'login_required',\n 'interaction_required',\n 'consent_required',\n 'account_selection_required',\n]);\n\n/**\n * Silent Authentication Handler\n *\n * Provides core logic for silent authentication. Platform-specific\n * implementations (iframe, hidden frame, etc.) should use this class.\n */\nexport class SilentAuthHandler {\n constructor(private readonly clientId: string) {}\n\n /**\n * Build silent authentication URL\n *\n * Creates an authorization URL with prompt=none for silent authentication.\n *\n * @param discovery - OIDC discovery document\n * @param authState - Auth state from StateManager\n * @param pkce - PKCE pair\n * @param options - Silent auth options\n * @returns Silent auth URL result\n */\n buildSilentAuthUrl(\n discovery: OIDCDiscoveryDocument,\n authState: AuthState,\n pkce: PKCEPair,\n options: SilentAuthOptions\n ): SilentAuthUrlResult {\n const endpoint = discovery.authorization_endpoint;\n const params = new URLSearchParams();\n\n // Required parameters\n params.set('client_id', this.clientId);\n params.set('response_type', options.responseType ?? 'code');\n params.set('redirect_uri', options.redirectUri);\n params.set('state', authState.state);\n params.set('nonce', authState.nonce);\n\n // Silent auth specific - MUST be prompt=none\n params.set('prompt', 'none');\n\n // PKCE parameters\n params.set('code_challenge', pkce.codeChallenge);\n params.set('code_challenge_method', pkce.codeChallengeMethod);\n\n // Scopes (default to openid only for silent auth)\n const scope = options.scope ?? 'openid';\n params.set('scope', scope);\n\n // Optional parameters\n if (options.loginHint) {\n params.set('login_hint', options.loginHint);\n }\n if (options.idTokenHint) {\n params.set('id_token_hint', options.idTokenHint);\n }\n\n // Extra custom parameters (with security parameter protection)\n if (options.extraParams) {\n const protectedParams = new Set([\n 'client_id',\n 'response_type',\n 'redirect_uri',\n 'state',\n 'nonce',\n 'code_challenge',\n 'code_challenge_method',\n 'scope',\n 'prompt', // Protect prompt=none\n ]);\n\n for (const [key, value] of Object.entries(options.extraParams)) {\n if (protectedParams.has(key.toLowerCase())) {\n continue;\n }\n params.set(key, value);\n }\n }\n\n const url = `${endpoint}?${params.toString()}`;\n\n const result: SilentAuthUrlResult = { url };\n\n if (options.exposeState) {\n result.state = authState.state;\n result.nonce = authState.nonce;\n }\n\n return result;\n }\n\n /**\n * Parse silent authentication response URL\n *\n * Parses the callback URL from silent authentication and returns\n * either the authorization code (for token exchange) or an error.\n *\n * @param responseUrl - Response URL from silent auth (iframe callback)\n * @returns Parsed result with code/state or error\n */\n parseSilentAuthResponse(responseUrl: string): {\n success: true;\n code: string;\n state: string;\n } | {\n success: false;\n error: AuthrimError;\n } {\n let searchParams: URLSearchParams;\n\n // Support both full URL and query string\n if (responseUrl.includes('?')) {\n const url = responseUrl.startsWith('http')\n ? new URL(responseUrl)\n : new URL(responseUrl, 'https://dummy.local');\n searchParams = url.searchParams;\n } else {\n searchParams = new URLSearchParams(responseUrl);\n }\n\n // Check for OAuth error response\n const error = searchParams.get('error');\n if (error) {\n const errorDescription = searchParams.get('error_description');\n const errorCode = this.mapSilentAuthError(error);\n\n return {\n success: false,\n error: new AuthrimError(errorCode, errorDescription ?? this.getDefaultErrorMessage(error), {\n details: {\n error,\n error_description: errorDescription,\n error_uri: searchParams.get('error_uri'),\n },\n }),\n };\n }\n\n // Extract code and state\n const code = searchParams.get('code');\n const state = searchParams.get('state');\n\n if (!code) {\n return {\n success: false,\n error: new AuthrimError('missing_code', 'Authorization code not found in silent auth response'),\n };\n }\n if (!state) {\n return {\n success: false,\n error: new AuthrimError('missing_state', 'State parameter not found in silent auth response'),\n };\n }\n\n return { success: true, code, state };\n }\n\n /**\n * Check if an error indicates interactive login is required\n *\n * @param error - Error to check\n * @returns True if interactive login is needed\n */\n isInteractiveLoginRequired(error: AuthrimError): boolean {\n return INTERACTIVE_LOGIN_REQUIRED_ERRORS.has(error.code);\n }\n\n /**\n * Map OAuth error to AuthrimErrorCode\n */\n private mapSilentAuthError(\n error: string\n ): 'login_required' | 'interaction_required' | 'consent_required' | 'account_selection_required' | 'oauth_error' {\n if (INTERACTIVE_LOGIN_REQUIRED_ERRORS.has(error)) {\n return error as 'login_required' | 'interaction_required' | 'consent_required' | 'account_selection_required';\n }\n return 'oauth_error';\n }\n\n /**\n * Get default error message for silent auth errors\n */\n private getDefaultErrorMessage(error: string): string {\n switch (error) {\n case 'login_required':\n return 'User must log in - no active session found';\n case 'interaction_required':\n return 'User interaction required';\n case 'consent_required':\n return 'User consent required';\n case 'account_selection_required':\n return 'User must select an account';\n default:\n return 'Silent authentication failed';\n }\n }\n}\n","/**\n * Client Authentication Utilities\n * RFC 6749 §2.3, RFC 7521, RFC 7523\n *\n * Provides utilities for building client authentication headers and body parameters\n * for various authentication methods.\n */\n\nimport type { ClientCredentials, ClientAssertionClaims } from '../types/client-auth.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Client authentication result\n */\nexport interface ClientAuthResult {\n /** Headers to include in the request */\n headers: Record<string, string>;\n /** Body parameters to include in the request */\n bodyParams: Record<string, string>;\n}\n\n/**\n * Build client authentication headers and body parameters\n *\n * @param credentials - Client credentials configuration\n * @param clientId - Client ID\n * @param tokenEndpoint - Token endpoint URL (used as audience for private_key_jwt)\n * @returns Headers and body parameters for authentication\n * @throws AuthrimError with code 'insecure_client_auth' if method='none' without dangerouslyAllowInsecure\n * @throws AuthrimError with code 'invalid_client_authentication' for invalid credentials\n */\nexport async function buildClientAuthentication(\n credentials: ClientCredentials,\n clientId: string,\n tokenEndpoint: string\n): Promise<ClientAuthResult> {\n const headers: Record<string, string> = {};\n const bodyParams: Record<string, string> = {};\n\n switch (credentials.method) {\n case 'client_secret_basic': {\n // RFC 6749 §2.3.1 - HTTP Basic Authentication\n const encodedCredentials = btoa(`${clientId}:${credentials.clientSecret}`);\n headers['Authorization'] = `Basic ${encodedCredentials}`;\n break;\n }\n\n case 'client_secret_post': {\n // RFC 6749 §2.3.1 - Client credentials in request body\n bodyParams['client_id'] = clientId;\n bodyParams['client_secret'] = credentials.clientSecret;\n break;\n }\n\n case 'private_key_jwt': {\n // RFC 7521, RFC 7523 - JWT Client Authentication\n const now = Math.floor(Date.now() / 1000);\n\n const claims: ClientAssertionClaims = {\n iss: clientId,\n sub: clientId,\n aud: tokenEndpoint,\n jti: generateJti(),\n exp: now + 300, // 5 minutes expiry\n iat: now,\n };\n\n let assertion: string;\n try {\n assertion = await credentials.signJwt(claims);\n } catch (error) {\n throw new AuthrimError(\n 'invalid_client_authentication',\n 'Failed to sign client assertion JWT',\n { cause: error instanceof Error ? error : undefined }\n );\n }\n\n bodyParams['client_id'] = clientId;\n bodyParams['client_assertion_type'] = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer';\n bodyParams['client_assertion'] = assertion;\n break;\n }\n\n case 'none': {\n // Public client - only client_id in body\n // SECURITY: Require explicit opt-in for insecure auth\n if (!('dangerouslyAllowInsecure' in credentials) || credentials.dangerouslyAllowInsecure !== true) {\n throw new AuthrimError(\n 'insecure_client_auth',\n 'Client authentication method \"none\" requires dangerouslyAllowInsecure: true'\n );\n }\n bodyParams['client_id'] = clientId;\n break;\n }\n\n default: {\n // Exhaustive check\n const _exhaustive: never = credentials;\n throw new AuthrimError(\n 'invalid_client_authentication',\n `Unknown client authentication method: ${(_exhaustive as ClientCredentials).method}`\n );\n }\n }\n\n return { headers, bodyParams };\n}\n\n/**\n * Generate a unique JWT ID (jti)\n *\n * Uses crypto.randomUUID if available, falls back to timestamp + random.\n */\nfunction generateJti(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for environments without crypto.randomUUID\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n","/**\n * Client Credentials Flow\n * RFC 6749 §4.4\n *\n * The client credentials grant is used for machine-to-machine (M2M) authentication\n * where no user is involved. The client authenticates directly with the authorization\n * server using its own credentials.\n *\n * IMPORTANT: This flow should only be used in secure environments (server-side)\n * where client credentials can be kept confidential.\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { TokenSet, TokenResponse } from '../types/token.js';\nimport type { ClientCredentials } from '../types/client-auth.js';\nimport { buildClientAuthentication } from './client-auth.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Options for ClientCredentialsClient constructor\n */\nexport interface ClientCredentialsClientOptions {\n /** HTTP client */\n http: HttpClient;\n /** Client ID */\n clientId: string;\n /** Client credentials */\n credentials: ClientCredentials;\n}\n\n/**\n * Options for getting a token\n */\nexport interface ClientCredentialsTokenOptions {\n /** Scopes to request */\n scope?: string;\n /** Target audience (resource server identifier) */\n audience?: string;\n /** Additional parameters */\n extraParams?: Record<string, string>;\n}\n\n/**\n * Client Credentials Flow Client\n *\n * Handles machine-to-machine authentication using the client credentials grant.\n */\nexport class ClientCredentialsClient {\n private readonly http: HttpClient;\n private readonly clientId: string;\n private readonly credentials: ClientCredentials;\n\n constructor(options: ClientCredentialsClientOptions) {\n this.http = options.http;\n this.clientId = options.clientId;\n this.credentials = options.credentials;\n }\n\n /**\n * Get an access token using client credentials\n *\n * @param discovery - OIDC discovery document\n * @param options - Token request options\n * @returns Token set\n * @throws AuthrimError with code 'client_credentials_error' if token request fails\n */\n async getToken(\n discovery: OIDCDiscoveryDocument,\n options?: ClientCredentialsTokenOptions\n ): Promise<TokenSet> {\n const tokenEndpoint = discovery.token_endpoint;\n\n // Build client authentication\n const { headers: authHeaders, bodyParams: authBodyParams } =\n await buildClientAuthentication(this.credentials, this.clientId, tokenEndpoint);\n\n // Build request body\n const body = new URLSearchParams({\n grant_type: 'client_credentials',\n ...authBodyParams,\n });\n\n // Add optional parameters\n if (options?.scope) {\n body.set('scope', options.scope);\n }\n if (options?.audience) {\n body.set('audience', options.audience);\n }\n\n // Add extra parameters (with protection for core params)\n if (options?.extraParams) {\n const protectedParams = new Set([\n 'grant_type',\n 'client_id',\n 'client_secret',\n 'client_assertion',\n 'client_assertion_type',\n 'scope',\n 'audience',\n ]);\n\n for (const [key, value] of Object.entries(options.extraParams)) {\n if (protectedParams.has(key.toLowerCase())) {\n continue;\n }\n body.set(key, value);\n }\n }\n\n // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n ...authHeaders,\n };\n\n // Make token request\n let response;\n try {\n response = await this.http.fetch<TokenResponse>(tokenEndpoint, {\n method: 'POST',\n headers,\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Client credentials token request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n throw new AuthrimError('client_credentials_error', 'Client credentials token request failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n const tokenResponse = response.data;\n\n // Calculate expiresAt (epoch seconds)\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = tokenResponse.expires_in ? now + tokenResponse.expires_in : now + 3600;\n\n // Build token set\n // Note: Client credentials flow typically doesn't return refresh_token or id_token\n const tokenSet: TokenSet = {\n accessToken: tokenResponse.access_token,\n tokenType: (tokenResponse.token_type as 'Bearer') ?? 'Bearer',\n expiresAt,\n refreshToken: tokenResponse.refresh_token,\n scope: tokenResponse.scope,\n };\n\n return tokenSet;\n }\n}\n","/**\n * JAR Builder\n * RFC 9101: JWT-Secured Authorization Request (JAR)\n *\n * JAR provides a way to send authorization request parameters\n * in a signed (and optionally encrypted) JWT, ensuring:\n * - Integrity protection of parameters\n * - Non-repudiation\n * - Confidentiality (when encrypted)\n *\n * The signed JWT is sent as the 'request' parameter in the authorization URL,\n * or can be passed by reference using the 'request_uri' parameter (with PAR).\n */\n\nimport type {\n JARBuilderConfig,\n JARRequestOptions,\n JARRequestObjectClaims,\n} from '../types/jar.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * JAR Builder\n *\n * Builds signed JWT request objects for authorization requests.\n */\nexport class JARBuilder {\n private readonly config: JARBuilderConfig;\n\n constructor(config: JARBuilderConfig) {\n this.config = config;\n }\n\n /**\n * Build a signed request object\n *\n * @param options - Request options\n * @returns Signed JWT request object\n * @throws AuthrimError with code 'jar_signing_error' if signing fails\n */\n async buildRequestObject(options: JARRequestOptions): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const lifetime = this.config.lifetime ?? 300; // 5 minutes default\n\n // Build JWT header\n const header: Record<string, unknown> = {\n alg: this.config.algorithm ?? 'RS256',\n typ: 'oauth-authz-req+jwt',\n };\n\n if (this.config.keyId) {\n header['kid'] = this.config.keyId;\n }\n\n // Build JWT claims (request object)\n const claims: JARRequestObjectClaims = {\n iss: options.clientId,\n aud: options.issuer,\n response_type: options.responseType ?? 'code',\n client_id: options.clientId,\n redirect_uri: options.redirectUri,\n scope: options.scope,\n state: options.state,\n nonce: options.nonce,\n code_challenge: options.codeChallenge,\n code_challenge_method: options.codeChallengeMethod,\n iat: now,\n exp: now + lifetime,\n jti: this.generateJti(),\n };\n\n // Add optional OIDC parameters\n if (options.prompt) {\n claims.prompt = options.prompt;\n }\n if (options.loginHint) {\n claims.login_hint = options.loginHint;\n }\n if (options.acrValues) {\n claims.acr_values = options.acrValues;\n }\n\n // Add extra claims (with protection for core claims)\n if (options.extraClaims) {\n const protectedClaims = new Set([\n 'iss',\n 'aud',\n 'response_type',\n 'client_id',\n 'redirect_uri',\n 'scope',\n 'state',\n 'nonce',\n 'code_challenge',\n 'code_challenge_method',\n 'iat',\n 'exp',\n 'jti',\n 'nbf',\n ]);\n\n for (const [key, value] of Object.entries(options.extraClaims)) {\n if (!protectedClaims.has(key)) {\n claims[key] = value;\n }\n }\n }\n\n // Sign the JWT\n try {\n return await this.config.signJwt(header, claims);\n } catch (error) {\n throw new AuthrimError(\n 'jar_signing_error',\n 'Failed to sign JAR request object',\n { cause: error instanceof Error ? error : undefined }\n );\n }\n }\n\n /**\n * Generate a unique JWT ID (jti)\n */\n private generateJti(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n }\n}\n\n/**\n * Check if JAR is required by the authorization server\n *\n * @param discovery - OIDC discovery document\n * @returns True if require_signed_request_object is true\n */\nexport function isJarRequired(discovery: { require_signed_request_object?: boolean }): boolean {\n return discovery.require_signed_request_object === true;\n}\n","/**\n * JARM Validator\n * JWT Secured Authorization Response Mode (JARM)\n *\n * JARM allows authorization servers to return authorization response\n * parameters in a signed JWT, providing:\n * - Response integrity protection\n * - Response authenticity verification\n * - Confidentiality (when encrypted)\n *\n * The response JWT is returned in the 'response' parameter of the\n * authorization callback.\n */\n\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type {\n JARMResponseClaims,\n JARMValidationOptions,\n JARMValidationResult,\n JARMValidatorConfig,\n} from '../types/jarm.js';\nimport { AuthrimError } from '../types/errors.js';\nimport { timingSafeEqual } from '../utils/timing-safe.js';\n\n/**\n * JARM Validator\n *\n * Validates JWT-secured authorization responses.\n */\nexport class JARMValidator {\n private readonly config: JARMValidatorConfig;\n\n constructor(config: JARMValidatorConfig) {\n this.config = config;\n }\n\n /**\n * Validate a JARM response\n *\n * @param discovery - OIDC discovery document\n * @param response - The JWT response string from the 'response' parameter\n * @param options - Validation options\n * @returns Validated authorization code and state\n * @throws AuthrimError with code 'jarm_validation_error' if validation fails\n * @throws AuthrimError with code 'jarm_signature_invalid' if signature verification fails\n */\n async validateResponse(\n discovery: OIDCDiscoveryDocument,\n response: string,\n options: JARMValidationOptions\n ): Promise<JARMValidationResult> {\n const clockSkew = options.clockSkewSeconds ?? 60;\n\n // Verify JWT signature and get claims\n let claims: JARMResponseClaims;\n try {\n claims = await this.config.verifyJwt(response, discovery.issuer);\n } catch (error) {\n throw new AuthrimError(\n 'jarm_signature_invalid',\n 'Failed to verify JARM response signature',\n { cause: error instanceof Error ? error : undefined }\n );\n }\n\n // Validate issuer\n if (claims.iss !== discovery.issuer) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response issuer does not match discovery issuer',\n {\n details: {\n expected: discovery.issuer,\n actual: claims.iss,\n },\n }\n );\n }\n\n // Validate audience (must be client_id or array containing client_id)\n const audience = Array.isArray(claims.aud) ? claims.aud : [claims.aud];\n if (!audience.includes(options.clientId)) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response audience does not match client_id',\n {\n details: {\n expected: options.clientId,\n actual: claims.aud,\n },\n }\n );\n }\n\n // Validate expiration\n const now = Math.floor(Date.now() / 1000);\n if (claims.exp && claims.exp + clockSkew < now) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response has expired'\n );\n }\n\n // Validate iat if present (not in the future)\n if (claims.iat && claims.iat - clockSkew > now) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response iat is in the future'\n );\n }\n\n // Check for OAuth error in response\n if (claims.error) {\n throw new AuthrimError('oauth_error', claims.error_description ?? claims.error, {\n details: {\n error: claims.error,\n error_description: claims.error_description,\n error_uri: claims.error_uri,\n },\n });\n }\n\n // Validate state (constant-time comparison)\n if (!claims.state) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response is missing state claim'\n );\n }\n if (!timingSafeEqual(claims.state, options.expectedState)) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response state does not match expected state'\n );\n }\n\n // Validate code is present\n if (!claims.code) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response is missing authorization code'\n );\n }\n\n return {\n code: claims.code,\n state: claims.state,\n };\n }\n\n /**\n * Parse a JARM response from callback URL\n *\n * Extracts the 'response' parameter from the callback URL.\n *\n * @param callbackUrl - Full callback URL or query string\n * @returns The response JWT, or null if not present\n */\n static extractResponseFromCallback(callbackUrl: string): string | null {\n let searchParams: URLSearchParams;\n\n if (callbackUrl.includes('?')) {\n const url = callbackUrl.startsWith('http')\n ? new URL(callbackUrl)\n : new URL(callbackUrl, 'https://dummy.local');\n searchParams = url.searchParams;\n } else {\n searchParams = new URLSearchParams(callbackUrl);\n }\n\n return searchParams.get('response');\n }\n}\n","/**\n * Auto Refresh Scheduler\n *\n * Automatically refreshes tokens before they expire.\n * Supports cancellation via AbortController.\n */\n\nimport type { TokenManager } from './manager.js';\nimport type { EventEmitter } from '../events/emitter.js';\n\n/**\n * Auto refresh options\n */\nexport interface AutoRefreshOptions {\n /** Refresh threshold in seconds before expiry (default: 60) */\n thresholdSeconds?: number;\n /** Check interval in milliseconds (default: 30000 = 30 seconds) */\n checkIntervalMs?: number;\n /** Event emitter for logging/debugging */\n eventEmitter?: EventEmitter;\n}\n\n/**\n * Auto Refresh Scheduler\n *\n * Schedules automatic token refresh before expiration.\n * Can be stopped and started as needed.\n */\nexport class AutoRefreshScheduler {\n private tokenManager: TokenManager | null = null;\n private options: Required<Omit<AutoRefreshOptions, 'eventEmitter'>> & { eventEmitter?: EventEmitter };\n private checkInterval: ReturnType<typeof setInterval> | null = null;\n private abortController: AbortController | null = null;\n private isRunning = false;\n\n /** Default refresh threshold: 60 seconds */\n private static readonly DEFAULT_THRESHOLD_SECONDS = 60;\n\n /** Default check interval: 30 seconds */\n private static readonly DEFAULT_CHECK_INTERVAL_MS = 30000;\n\n constructor(options?: AutoRefreshOptions) {\n this.options = {\n thresholdSeconds: options?.thresholdSeconds ?? AutoRefreshScheduler.DEFAULT_THRESHOLD_SECONDS,\n checkIntervalMs: options?.checkIntervalMs ?? AutoRefreshScheduler.DEFAULT_CHECK_INTERVAL_MS,\n eventEmitter: options?.eventEmitter,\n };\n }\n\n /**\n * Start auto-refresh scheduling\n *\n * @param tokenManager - Token manager instance\n */\n start(tokenManager: TokenManager): void {\n if (this.isRunning) {\n return;\n }\n\n this.tokenManager = tokenManager;\n this.abortController = new AbortController();\n this.isRunning = true;\n\n // Start periodic check\n this.checkInterval = setInterval(() => {\n this.checkAndRefresh().catch(() => {\n // Errors are handled within checkAndRefresh\n });\n }, this.options.checkIntervalMs);\n\n // Initial check\n this.checkAndRefresh().catch(() => {\n // Errors are handled within checkAndRefresh\n });\n }\n\n /**\n * Stop auto-refresh scheduling\n */\n stop(): void {\n if (!this.isRunning) {\n return;\n }\n\n this.isRunning = false;\n\n if (this.checkInterval) {\n clearInterval(this.checkInterval);\n this.checkInterval = null;\n }\n\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n\n this.tokenManager = null;\n }\n\n /**\n * Check if scheduler is running\n */\n get running(): boolean {\n return this.isRunning;\n }\n\n /**\n * Get the abort signal for external cancellation support\n */\n get signal(): AbortSignal | null {\n return this.abortController?.signal ?? null;\n }\n\n /**\n * Check if token needs refresh and perform if needed\n */\n private async checkAndRefresh(): Promise<void> {\n if (!this.tokenManager || !this.isRunning) {\n return;\n }\n\n try {\n const tokens = await this.tokenManager.getTokens();\n if (!tokens) {\n return;\n }\n\n const now = Math.floor(Date.now() / 1000);\n const expiresIn = tokens.expiresAt - now;\n\n // Check if token is within threshold\n if (expiresIn <= this.options.thresholdSeconds && tokens.refreshToken) {\n // Perform background refresh\n await this.tokenManager.refresh();\n }\n } catch (error) {\n // Log error but don't stop the scheduler\n // The tokenManager will emit appropriate events\n }\n }\n\n /**\n * Force an immediate refresh check\n */\n async forceCheck(): Promise<void> {\n await this.checkAndRefresh();\n }\n}\n","/**\n * Session State Calculator\n *\n * Implements OIDC Session Management 1.0 specification\n * https://openid.net/specs/openid-connect-session-1_0.html\n *\n * session_state = hash(client_id + \" \" + origin + \" \" + browser_state + salt) + \".\" + salt\n */\n\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport { base64urlEncode } from '../utils/base64url.js';\nimport { timingSafeEqual } from '../utils/timing-safe.js';\n\n/**\n * Parameters for calculating session_state\n */\nexport interface SessionStateParams {\n /** OAuth client_id */\n clientId: string;\n /** RP origin (e.g., \"https://example.com\") */\n origin: string;\n /**\n * OP-managed browser state (opaque value)\n *\n * Per OIDC Session Management 1.0 spec, this is called \"browser_state\" but is actually\n * an opaque value managed by the OP to identify the session at the OP.\n * It is NOT a value managed by the RP's browser.\n */\n opBrowserState: string;\n /** Optional salt (generated if not provided) */\n salt?: string;\n}\n\n/**\n * Result of session_state calculation\n */\nexport interface SessionStateResult {\n /** Full session_state value (hash.salt) */\n sessionState: string;\n /** Hash portion of session_state */\n hash: string;\n /** Salt used in calculation */\n salt: string;\n}\n\n/**\n * Options for SessionStateCalculator\n */\nexport interface SessionStateCalculatorOptions {\n /** Crypto provider for hashing */\n crypto: CryptoProvider;\n}\n\n/**\n * Session State Calculator\n *\n * Calculates and validates session_state values per OIDC Session Management 1.0.\n *\n * Usage (OP side - calculating session_state to include in auth response):\n * ```typescript\n * const calculator = new SessionStateCalculator({ crypto });\n * const result = await calculator.calculate({\n * clientId: 'my-client',\n * origin: 'https://rp.example.com',\n * opBrowserState: 'op-session-id-xyz'\n * });\n * // result.sessionState -> include in auth response\n * ```\n *\n * Usage (RP check_session_iframe - validating session state):\n * ```typescript\n * const isValid = await calculator.validate(sessionState, {\n * clientId: 'my-client',\n * origin: 'https://rp.example.com',\n * opBrowserState: 'op-session-id-xyz'\n * });\n * ```\n */\nexport class SessionStateCalculator {\n private readonly crypto: CryptoProvider;\n\n constructor(options: SessionStateCalculatorOptions) {\n this.crypto = options.crypto;\n }\n\n /**\n * Calculate session_state\n *\n * Per OIDC Session Management 1.0:\n * session_state = hash(client_id + \" \" + origin + \" \" + browser_state + salt) + \".\" + salt\n *\n * @param params - Parameters for calculation\n * @returns Session state result\n */\n async calculate(params: SessionStateParams): Promise<SessionStateResult> {\n // Generate salt if not provided (16 random bytes, base64url encoded)\n let salt = params.salt;\n if (!salt) {\n const saltBytes = await this.crypto.randomBytes(16);\n salt = base64urlEncode(saltBytes);\n }\n\n // Build the string to hash\n // Note: The spec uses space as delimiter\n const hashInput =\n params.clientId + ' ' + params.origin + ' ' + params.opBrowserState + salt;\n\n // Compute SHA-256 hash\n const hashBytes = await this.crypto.sha256(hashInput);\n const hash = base64urlEncode(hashBytes);\n\n // session_state = hash + \".\" + salt\n const sessionState = hash + '.' + salt;\n\n return {\n sessionState,\n hash,\n salt,\n };\n }\n\n /**\n * Validate session_state\n *\n * Uses constant-time comparison to prevent timing attacks.\n *\n * @param sessionState - session_state value to validate\n * @param params - Parameters that should match (without salt, extracted from sessionState)\n * @returns true if valid\n */\n async validate(\n sessionState: string,\n params: Omit<SessionStateParams, 'salt'>\n ): Promise<boolean> {\n const parsed = this.parse(sessionState);\n if (!parsed) {\n return false;\n }\n\n // Recalculate with the extracted salt\n const calculated = await this.calculate({\n ...params,\n salt: parsed.salt,\n });\n\n // Use constant-time comparison to prevent timing attacks\n return timingSafeEqual(calculated.sessionState, sessionState);\n }\n\n /**\n * Parse session_state into hash and salt components\n *\n * @param sessionState - session_state value to parse\n * @returns Parsed components or null if invalid format\n */\n parse(sessionState: string): { hash: string; salt: string } | null {\n // Maximum lengths to prevent DoS via oversized input\n // SHA-256 base64url is ~43 chars, salt is typically ~22 chars\n const MAX_SESSION_STATE_LENGTH = 512;\n const MAX_HASH_LENGTH = 256;\n const MAX_SALT_LENGTH = 128;\n\n if (!sessionState || typeof sessionState !== 'string') {\n return null;\n }\n\n // Length validation to prevent DoS\n if (sessionState.length > MAX_SESSION_STATE_LENGTH) {\n return null;\n }\n\n const dotIndex = sessionState.lastIndexOf('.');\n if (dotIndex === -1 || dotIndex === 0 || dotIndex === sessionState.length - 1) {\n return null;\n }\n\n const hash = sessionState.substring(0, dotIndex);\n const salt = sessionState.substring(dotIndex + 1);\n\n // Basic validation - both parts should be non-empty and look like base64url\n if (!hash || !salt) {\n return null;\n }\n\n // Length validation for individual components\n if (hash.length > MAX_HASH_LENGTH || salt.length > MAX_SALT_LENGTH) {\n return null;\n }\n\n // Base64url validation: only A-Z, a-z, 0-9, -, _ allowed\n const base64urlRegex = /^[A-Za-z0-9_-]+$/;\n if (!base64urlRegex.test(hash) || !base64urlRegex.test(salt)) {\n return null;\n }\n\n return { hash, salt };\n }\n}\n","/**\n * Front-Channel Logout URL Builder\n *\n * Implements OpenID Connect Front-Channel Logout 1.0\n * https://openid.net/specs/openid-connect-frontchannel-1_0.html\n *\n * Front-channel logout allows the OP to notify RPs of logout events\n * via browser redirects (iframes loaded by the OP's logout page).\n */\n\nimport type { FrontChannelLogoutParams, FrontChannelLogoutUrlOptions } from '../types/session-management.js';\nimport { timingSafeEqual } from '../utils/timing-safe.js';\n\n/**\n * Result of building a front-channel logout URL\n */\nexport interface FrontChannelLogoutUrlResult {\n /** Complete logout URL with query parameters */\n url: string;\n /** Parameters included in the URL */\n params: FrontChannelLogoutParams;\n}\n\n/**\n * Parameters for building a front-channel logout URL\n */\nexport interface FrontChannelLogoutBuildParams {\n /** Issuer identifier to include (optional) */\n iss?: string;\n /** Session ID to include (optional) */\n sid?: string;\n}\n\n/**\n * Validation options for front-channel logout requests\n */\nexport interface FrontChannelLogoutValidationOptions {\n /** Expected issuer (for validation) */\n issuer?: string;\n /** Expected session ID (for validation) */\n sessionId?: string;\n /** Require issuer parameter */\n requireIss?: boolean;\n /** Require session ID parameter */\n requireSid?: boolean;\n}\n\n/**\n * Result of front-channel logout request validation\n */\nexport interface FrontChannelLogoutValidationResult {\n /** Whether the request is valid */\n valid: boolean;\n /** Parsed parameters (if valid) */\n params?: FrontChannelLogoutParams;\n /** Error message (if invalid) */\n error?: string;\n}\n\n/**\n * Front-Channel Logout URL Builder\n *\n * Builds and validates front-channel logout URLs per OIDC Front-Channel Logout 1.0.\n *\n * Usage (OP side - building logout URL to load in iframe):\n * ```typescript\n * const builder = new FrontChannelLogoutUrlBuilder();\n * const result = builder.build(\n * { logoutUri: 'https://rp.example.com/logout', includeIssuer: true, includeSessionId: true },\n * { iss: 'https://op.example.com', sid: 'session-123' }\n * );\n * // result.url -> load in iframe\n * ```\n *\n * Usage (RP side - validating incoming logout request):\n * ```typescript\n * const result = builder.validateRequest(window.location.href, {\n * issuer: 'https://op.example.com',\n * requireIss: true\n * });\n * if (result.valid) {\n * // Perform local logout\n * }\n * ```\n */\nexport class FrontChannelLogoutUrlBuilder {\n /**\n * Build a front-channel logout URL\n *\n * @param options - URL configuration options\n * @param params - Parameters to include in the URL\n * @returns Built URL and included parameters\n */\n build(\n options: FrontChannelLogoutUrlOptions,\n params: FrontChannelLogoutBuildParams\n ): FrontChannelLogoutUrlResult {\n const url = new URL(options.logoutUri);\n const resultParams: FrontChannelLogoutParams = {};\n\n if (options.includeIssuer && params.iss) {\n url.searchParams.set('iss', params.iss);\n resultParams.iss = params.iss;\n }\n\n if (options.includeSessionId && params.sid) {\n url.searchParams.set('sid', params.sid);\n resultParams.sid = params.sid;\n }\n\n return {\n url: url.toString(),\n params: resultParams,\n };\n }\n\n /**\n * Parse parameters from a front-channel logout URL\n *\n * @param url - URL or URL string to parse\n * @returns Parsed parameters\n */\n parseParams(url: string | URL): FrontChannelLogoutParams {\n const urlObj = typeof url === 'string' ? new URL(url) : url;\n const params: FrontChannelLogoutParams = {};\n\n const iss = urlObj.searchParams.get('iss');\n if (iss) {\n params.iss = iss;\n }\n\n const sid = urlObj.searchParams.get('sid');\n if (sid) {\n params.sid = sid;\n }\n\n return params;\n }\n\n /**\n * Validate a front-channel logout request\n *\n * Uses constant-time comparison for security-sensitive values to prevent timing attacks.\n *\n * @param url - URL to validate\n * @param expected - Expected values and requirements\n * @returns Validation result\n */\n validateRequest(\n url: string | URL,\n expected: FrontChannelLogoutValidationOptions = {}\n ): FrontChannelLogoutValidationResult {\n let params: FrontChannelLogoutParams;\n\n try {\n params = this.parseParams(url);\n } catch {\n return {\n valid: false,\n error: 'Invalid URL format',\n };\n }\n\n // Check required parameters\n if (expected.requireIss && !params.iss) {\n return {\n valid: false,\n error: 'Missing required iss parameter',\n };\n }\n\n if (expected.requireSid && !params.sid) {\n return {\n valid: false,\n error: 'Missing required sid parameter',\n };\n }\n\n // Validate issuer if provided and expected\n // Use constant-time comparison to prevent timing attacks\n if (expected.issuer && params.iss && !timingSafeEqual(params.iss, expected.issuer)) {\n return {\n valid: false,\n error: 'Issuer validation failed',\n };\n }\n\n // Validate session ID if provided and expected\n // Use constant-time comparison to prevent timing attacks\n if (expected.sessionId && params.sid && !timingSafeEqual(params.sid, expected.sessionId)) {\n return {\n valid: false,\n error: 'Session ID validation failed',\n };\n }\n\n return {\n valid: true,\n params,\n };\n }\n}\n","/**\n * Event Timeline\n *\n * Records SDK events for debugging and observability.\n * All sensitive data is automatically redacted.\n */\n\nimport type { TimelineEntry } from '../events/types.js';\nimport type { RedactLevel } from './types.js';\n\n/**\n * Sensitive keys that should always be redacted\n */\nconst SENSITIVE_KEYS = [\n 'accessToken',\n 'refreshToken',\n 'idToken',\n 'token',\n 'code',\n 'password',\n 'secret',\n 'credentials',\n 'authorization',\n 'bearer',\n 'codeVerifier',\n 'code_verifier',\n 'client_secret',\n];\n\n/**\n * URL parameters that should be redacted in aggressive mode\n */\nconst SENSITIVE_URL_PARAMS = [\n 'code',\n 'state',\n 'nonce',\n 'id_token',\n 'access_token',\n 'refresh_token',\n 'token',\n];\n\n/**\n * Event Timeline for debugging\n *\n * Records events with automatic redaction of sensitive data.\n * Safe to use in production - no sensitive data is stored.\n */\nexport class EventTimeline {\n private entries: TimelineEntry[] = [];\n private maxEvents: number;\n private redactLevel: RedactLevel;\n\n constructor(options?: { maxEvents?: number; redactLevel?: RedactLevel }) {\n this.maxEvents = options?.maxEvents ?? 100;\n this.redactLevel = options?.redactLevel ?? 'default';\n }\n\n /**\n * Record an event to the timeline\n *\n * Data is automatically redacted based on redact level.\n *\n * @param type - Event type\n * @param data - Event data (will be redacted)\n * @param options - Recording options\n */\n record(\n type: string,\n data?: unknown,\n options?: { operationId?: string; redact?: RedactLevel }\n ): void {\n const redactLevelToUse = options?.redact ?? this.redactLevel;\n const redactedData = this.redactData(data, redactLevelToUse);\n\n const entry: TimelineEntry = {\n type,\n timestamp: Date.now(),\n operationId: options?.operationId,\n data: redactedData,\n };\n\n this.entries.push(entry);\n\n // Trim to max events\n while (this.entries.length > this.maxEvents) {\n this.entries.shift();\n }\n }\n\n /**\n * Get recent entries\n *\n * @param count - Number of entries to return (default: all)\n * @returns Recent timeline entries\n */\n getRecent(count?: number): TimelineEntry[] {\n if (count === undefined) {\n return [...this.entries];\n }\n return this.entries.slice(-count);\n }\n\n /**\n * Get entries for a specific operation\n *\n * @param operationId - Operation ID to filter by\n * @returns Entries for the operation\n */\n getByOperationId(operationId: string): TimelineEntry[] {\n return this.entries.filter((entry) => entry.operationId === operationId);\n }\n\n /**\n * Get entries by event type\n *\n * @param type - Event type to filter by\n * @returns Entries matching the type\n */\n getByType(type: string): TimelineEntry[] {\n return this.entries.filter((entry) => entry.type === type);\n }\n\n /**\n * Clear all entries\n */\n clear(): void {\n this.entries = [];\n }\n\n /**\n * Get entry count\n */\n get length(): number {\n return this.entries.length;\n }\n\n /**\n * Convert timeline to JSON string (for export/logging)\n */\n toJSON(): string {\n return JSON.stringify(this.entries, null, 2);\n }\n\n /**\n * Set redaction level\n */\n setRedactLevel(level: RedactLevel): void {\n this.redactLevel = level;\n }\n\n /**\n * Redact sensitive data from event payload\n */\n private redactData(\n data: unknown,\n level: RedactLevel\n ): Record<string, unknown> | undefined {\n if (level === 'none' || data === undefined || data === null) {\n return data as Record<string, unknown> | undefined;\n }\n\n if (typeof data !== 'object') {\n return data as Record<string, unknown>;\n }\n\n const redacted = this.deepRedact(data as Record<string, unknown>, level);\n return redacted;\n }\n\n /**\n * Deep redact an object\n */\n private deepRedact(\n obj: Record<string, unknown>,\n level: RedactLevel\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const lowerKey = key.toLowerCase();\n\n // Check if this is a sensitive key\n if (this.isSensitiveKey(lowerKey)) {\n // Add existence flag instead of value\n const capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1);\n result[`has${capitalizedKey}`] = value !== undefined && value !== null;\n result[key] = '[REDACTED]';\n continue;\n }\n\n // Handle URL redaction in aggressive mode\n if (level === 'aggressive' && lowerKey === 'url' && typeof value === 'string') {\n result[key] = this.redactUrl(value);\n continue;\n }\n\n // Recursively redact nested objects\n if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n result[key] = this.deepRedact(value as Record<string, unknown>, level);\n continue;\n }\n\n // Recursively redact arrays\n if (Array.isArray(value)) {\n result[key] = value.map((item) => {\n if (item !== null && typeof item === 'object') {\n return this.deepRedact(item as Record<string, unknown>, level);\n }\n return item;\n });\n continue;\n }\n\n // Keep non-sensitive values\n result[key] = value;\n }\n\n return result;\n }\n\n /**\n * Check if a key is sensitive\n */\n private isSensitiveKey(key: string): boolean {\n return SENSITIVE_KEYS.some(\n (sensitive) => key === sensitive.toLowerCase() || key.includes(sensitive.toLowerCase())\n );\n }\n\n /**\n * Redact sensitive URL parameters\n */\n private redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n\n for (const param of SENSITIVE_URL_PARAMS) {\n if (parsed.searchParams.has(param)) {\n parsed.searchParams.set(param, '[REDACTED]');\n }\n }\n\n // Also check hash fragment\n if (parsed.hash) {\n const hashParams = new URLSearchParams(parsed.hash.slice(1));\n let hashModified = false;\n\n for (const param of SENSITIVE_URL_PARAMS) {\n if (hashParams.has(param)) {\n hashParams.set(param, '[REDACTED]');\n hashModified = true;\n }\n }\n\n if (hashModified) {\n parsed.hash = '#' + hashParams.toString();\n }\n }\n\n return parsed.toString();\n } catch {\n // If URL parsing fails, return with basic redaction\n return url.replace(/([?&])(code|token|state|nonce)=[^&]*/gi, '$1$2=[REDACTED]');\n }\n }\n}\n","/**\n * Debug Logger\n *\n * Platform-agnostic logging infrastructure for SDK debugging.\n */\n\nimport type { DebugLogger, DebugLogLevel, DebugOptions } from './types.js';\n\n/**\n * Create a console-based debug logger\n *\n * This logger writes to console with Authrim-prefixed messages.\n * Safe to use with any console implementation.\n */\nexport function createConsoleLogger(options?: {\n timestamps?: boolean;\n}): DebugLogger {\n const includeTimestamps = options?.timestamps ?? false;\n\n return {\n log(level: DebugLogLevel, message: string, data?: unknown): void {\n const prefix = includeTimestamps\n ? `[Authrim:${level.toUpperCase()} ${new Date().toISOString()}]`\n : `[Authrim:${level.toUpperCase()}]`;\n\n const consoleMethod = level === 'debug' ? 'log' : level;\n\n // Use globalThis.console to ensure platform compatibility\n const consoleObj = typeof console !== 'undefined' ? console : null;\n if (!consoleObj) return;\n\n if (data !== undefined) {\n consoleObj[consoleMethod]?.(prefix, message, data);\n } else {\n consoleObj[consoleMethod]?.(prefix, message);\n }\n },\n };\n}\n\n/**\n * No-op logger for when debug mode is disabled\n */\nexport const noopLogger: DebugLogger = {\n log(): void {\n // Intentionally empty\n },\n};\n\n/**\n * Create a debug logger based on options\n */\nexport function createDebugLogger(options: DebugOptions): DebugLogger {\n if (!options.enabled) {\n return noopLogger;\n }\n\n if (options.logger) {\n return options.logger;\n }\n\n return createConsoleLogger({\n timestamps: options.logTimestamps,\n });\n}\n\n/**\n * Debug context for tracking operations\n */\nexport class DebugContext {\n private logger: DebugLogger;\n private verbose: boolean;\n private operationId: string | null = null;\n\n constructor(logger: DebugLogger, options?: { verbose?: boolean }) {\n this.logger = logger;\n this.verbose = options?.verbose ?? false;\n }\n\n /**\n * Set current operation ID for log correlation\n */\n setOperationId(id: string | null): void {\n this.operationId = id;\n }\n\n /**\n * Get current operation ID\n */\n getOperationId(): string | null {\n return this.operationId;\n }\n\n /**\n * Log a debug message (verbose mode only)\n */\n debug(message: string, data?: unknown): void {\n if (this.verbose) {\n this.logger.log('debug', this.formatMessage(message), data);\n }\n }\n\n /**\n * Log an info message\n */\n info(message: string, data?: unknown): void {\n this.logger.log('info', this.formatMessage(message), data);\n }\n\n /**\n * Log a warning message\n */\n warn(message: string, data?: unknown): void {\n this.logger.log('warn', this.formatMessage(message), data);\n }\n\n /**\n * Log an error message\n */\n error(message: string, data?: unknown): void {\n this.logger.log('error', this.formatMessage(message), data);\n }\n\n /**\n * Format message with operation ID if available\n */\n private formatMessage(message: string): string {\n if (this.operationId) {\n return `[${this.operationId.slice(0, 8)}] ${message}`;\n }\n return message;\n }\n}\n","/**\n * Diagnostic Logger for SDK\n *\n * Provides diagnostic logging capabilities for debugging, troubleshooting,\n * and OIDF conformance testing. Integrates with server-side diagnostic logs\n * via diagnosticSessionId.\n *\n * Features:\n * - ID Token validation step logging\n * - Authentication decision logging\n * - Session ID correlation with server logs\n * - Console output and optional collection\n */\n\nimport type { DebugLogger } from './types.js';\n\n/**\n * Diagnostic log level\n */\nexport type DiagnosticLogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/**\n * Token validation step\n */\nexport type TokenValidationStep =\n | 'issuer-check'\n | 'audience-check'\n | 'expiry-check'\n | 'nonce-check'\n | 'signature-check'\n | 'hash-check';\n\n/**\n * Base diagnostic log entry\n */\nexport interface BaseDiagnosticLogEntry {\n /** Unique log entry ID */\n id: string;\n\n /** Diagnostic session ID (for correlation with server logs) */\n diagnosticSessionId: string;\n\n /** Log category */\n category: string;\n\n /** Log level */\n level: DiagnosticLogLevel;\n\n /** Timestamp (Unix epoch in milliseconds) */\n timestamp: number;\n\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Token Validation Log Entry\n */\nexport interface TokenValidationLogEntry extends BaseDiagnosticLogEntry {\n category: 'token-validation';\n\n /** Validation step */\n step: TokenValidationStep;\n\n /** Token type (id_token, access_token, etc.) */\n tokenType: string;\n\n /** Validation result */\n result: 'pass' | 'fail';\n\n /** Expected value (for validation) */\n expected?: unknown;\n\n /** Actual value (for validation) */\n actual?: unknown;\n\n /** Error message (if failed) */\n errorMessage?: string;\n\n /** Additional validation details */\n details?: Record<string, unknown>;\n}\n\n/**\n * Authentication Decision Log Entry\n */\nexport interface AuthDecisionLogEntry extends BaseDiagnosticLogEntry {\n category: 'auth-decision';\n\n /** Final authentication decision */\n decision: 'allow' | 'deny';\n\n /** Reason for the decision */\n reason: string;\n\n /** Authentication flow */\n flow?: string;\n\n /** Additional decision context */\n context?: Record<string, unknown>;\n}\n\n/**\n * Union type of all diagnostic log entries\n */\nexport type DiagnosticLogEntry = TokenValidationLogEntry | AuthDecisionLogEntry;\n\n/**\n * Common interface for diagnostic loggers\n *\n * This interface allows different diagnostic logger implementations\n * (Core SDK, Web SDK, Node SDK) to be used interchangeably.\n */\nexport interface IDiagnosticLogger {\n /**\n * Get diagnostic session ID\n */\n getDiagnosticSessionId(): string;\n\n /**\n * Check if diagnostic logging is enabled\n */\n isEnabled(): boolean;\n\n /**\n * Log token validation step\n */\n logTokenValidation(options: {\n step: TokenValidationStep;\n tokenType: string;\n result: 'pass' | 'fail';\n expected?: unknown;\n actual?: unknown;\n errorMessage?: string;\n details?: Record<string, unknown>;\n }): void;\n\n /**\n * Log authentication decision\n */\n logAuthDecision(options: {\n decision: 'allow' | 'deny';\n reason: string;\n flow?: string;\n context?: Record<string, unknown>;\n }): void;\n}\n\n/**\n * Diagnostic logger options\n */\nexport interface DiagnosticLoggerOptions {\n /** Enable diagnostic logging */\n enabled: boolean;\n\n /** Underlying debug logger */\n debugLogger?: DebugLogger;\n\n /** Collect logs in memory for export */\n collectLogs?: boolean;\n\n /** Maximum number of logs to collect (default: 1000) */\n maxLogs?: number;\n}\n\n/**\n * Diagnostic Logger for SDK\n */\nexport class DiagnosticLogger implements IDiagnosticLogger {\n private diagnosticSessionId: string;\n private enabled: boolean;\n private debugLogger?: DebugLogger;\n private collectLogs: boolean;\n private maxLogs: number;\n private logs: DiagnosticLogEntry[] = [];\n\n constructor(options: DiagnosticLoggerOptions) {\n this.diagnosticSessionId = this.generateSessionId();\n this.enabled = options.enabled;\n this.debugLogger = options.debugLogger;\n this.collectLogs = options.collectLogs ?? false;\n this.maxLogs = options.maxLogs ?? 1000;\n }\n\n /**\n * Get diagnostic session ID\n *\n * This ID should be sent to the server via X-Diagnostic-Session-Id header\n * to correlate SDK logs with server logs.\n */\n getDiagnosticSessionId(): string {\n return this.diagnosticSessionId;\n }\n\n /**\n * Check if diagnostic logging is enabled\n */\n isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Log token validation step\n */\n logTokenValidation(options: {\n step: TokenValidationStep;\n tokenType: string;\n result: 'pass' | 'fail';\n expected?: unknown;\n actual?: unknown;\n errorMessage?: string;\n details?: Record<string, unknown>;\n }): void {\n if (!this.enabled) return;\n\n const entry: TokenValidationLogEntry = {\n id: this.generateEntryId(),\n diagnosticSessionId: this.diagnosticSessionId,\n category: 'token-validation',\n level: options.result === 'fail' ? 'error' : 'debug',\n timestamp: Date.now(),\n step: options.step,\n tokenType: options.tokenType,\n result: options.result,\n expected: options.expected,\n actual: options.actual,\n errorMessage: options.errorMessage,\n details: options.details,\n };\n\n this.writeLog(entry);\n }\n\n /**\n * Log authentication decision\n */\n logAuthDecision(options: {\n decision: 'allow' | 'deny';\n reason: string;\n flow?: string;\n context?: Record<string, unknown>;\n }): void {\n if (!this.enabled) return;\n\n const entry: AuthDecisionLogEntry = {\n id: this.generateEntryId(),\n diagnosticSessionId: this.diagnosticSessionId,\n category: 'auth-decision',\n level: options.decision === 'deny' ? 'warn' : 'info',\n timestamp: Date.now(),\n decision: options.decision,\n reason: options.reason,\n flow: options.flow,\n context: options.context,\n };\n\n this.writeLog(entry);\n }\n\n /**\n * Get all collected logs\n */\n getLogs(): DiagnosticLogEntry[] {\n return [...this.logs];\n }\n\n /**\n * Export logs as JSON string\n */\n exportLogs(): string {\n return JSON.stringify(this.logs, null, 2);\n }\n\n /**\n * Clear collected logs\n */\n clearLogs(): void {\n this.logs = [];\n }\n\n /**\n * Write log entry (internal)\n */\n private writeLog(entry: DiagnosticLogEntry): void {\n // Output to debug logger\n if (this.debugLogger) {\n this.debugLogger.log(entry.level, `[DIAGNOSTIC] ${entry.category}`, entry);\n }\n\n // Collect in memory\n if (this.collectLogs) {\n this.logs.push(entry);\n\n // Trim if exceeds max\n if (this.logs.length > this.maxLogs) {\n this.logs.shift();\n }\n }\n }\n\n /**\n * Generate diagnostic session ID\n */\n private generateSessionId(): string {\n // Use crypto.randomUUID if available (modern browsers/Node.js)\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback: generate UUID v4\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n\n /**\n * Generate log entry ID\n */\n private generateEntryId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n}\n\n/**\n * Create a diagnostic logger\n *\n * @param options - Logger options\n * @returns DiagnosticLogger instance or null if disabled\n */\nexport function createDiagnosticLogger(\n options: DiagnosticLoggerOptions\n): DiagnosticLogger | null {\n if (!options.enabled) {\n return null;\n }\n\n return new DiagnosticLogger(options);\n}\n","/**\n * Hash Utilities\n *\n * Provides hash calculation utilities for OIDC specifications.\n */\n\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport { base64urlEncode } from './base64url.js';\n\n/**\n * Calculate ds_hash for Native SSO device_secret verification\n *\n * Algorithm: BASE64URL(left half of SHA-256(device_secret))\n * Reference: OIDC Native SSO 1.0 specification\n *\n * This is the same algorithm used for at_hash and c_hash in OIDC Core,\n * applied to the device_secret value.\n *\n * @param deviceSecret - The device_secret value to hash\n * @param crypto - Platform-specific crypto provider\n * @returns ds_hash value (BASE64URL encoded)\n *\n * @example\n * ```typescript\n * const dsHash = await calculateDsHash(deviceSecret, cryptoProvider);\n * // Compare with id_token.ds_hash claim\n * if (idToken.ds_hash === dsHash) {\n * // device_secret is valid\n * }\n * ```\n */\nexport async function calculateDsHash(\n deviceSecret: string,\n crypto: CryptoProvider\n): Promise<string> {\n // 1. Compute SHA-256 hash (32 bytes)\n const hash = await crypto.sha256(deviceSecret);\n\n // 2. Take the left half (16 bytes for SHA-256)\n const leftHalf = hash.slice(0, hash.length / 2);\n\n // 3. BASE64URL encode\n return base64urlEncode(leftHalf);\n}\n","/**\n * Cancellation Utilities\n *\n * Provides AbortController-based cancellation for async operations.\n */\n\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Wrap a promise with AbortSignal support\n *\n * If the signal is aborted, the promise will reject with an\n * 'operation_cancelled' error which is recoverable and retryable.\n *\n * @param promise - Promise to wrap\n * @param signal - AbortSignal to use for cancellation\n * @returns Promise that can be cancelled\n */\nexport function withAbortSignal<T>(\n promise: Promise<T>,\n signal: AbortSignal\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const cancelledError = new AuthrimError(\n 'operation_cancelled',\n 'Operation was cancelled'\n );\n\n // Already aborted\n if (signal.aborted) {\n reject(cancelledError);\n return;\n }\n\n const onAbort = () => {\n reject(cancelledError);\n };\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n promise\n .then(resolve)\n .catch(reject)\n .finally(() => {\n signal.removeEventListener('abort', onAbort);\n });\n });\n}\n\n/**\n * Create a cancellable operation wrapper\n *\n * Returns an object with the promise and a cancel function.\n * Useful for creating operations that can be externally cancelled.\n *\n * @param fn - Async function to execute\n * @returns Object with promise and cancel function\n */\nexport function createCancellableOperation<T>(\n fn: (signal: AbortSignal) => Promise<T>\n): {\n promise: Promise<T>;\n cancel: () => void;\n signal: AbortSignal;\n} {\n const controller = new AbortController();\n\n return {\n promise: fn(controller.signal),\n cancel: () => controller.abort(),\n signal: controller.signal,\n };\n}\n\n/**\n * Check if an error is a cancellation error\n */\nexport function isCancellationError(error: unknown): boolean {\n return error instanceof AuthrimError && error.code === 'operation_cancelled';\n}\n\n/**\n * Race multiple promises with cancellation support\n *\n * When one promise resolves, other operations are cancelled.\n *\n * @param operations - Array of operations with their signals\n * @returns Result of the first successful operation\n */\nexport async function raceWithCancellation<T>(\n operations: Array<{\n promise: Promise<T>;\n cancel: () => void;\n }>\n): Promise<T> {\n try {\n const result = await Promise.race(operations.map((op) => op.promise));\n // Cancel all other operations\n operations.forEach((op) => op.cancel());\n return result;\n } catch (error) {\n // Cancel all operations on error\n operations.forEach((op) => op.cancel());\n throw error;\n }\n}\n","/**\n * Retry Utilities\n *\n * Provides exponential backoff retry logic with jitter.\n */\n\nimport { AuthrimError, isRetryableError } from '../types/errors.js';\nimport { isCancellationError } from './cancellation.js';\n\n/**\n * Retry options\n */\nexport interface RetryOptions {\n /** Maximum number of retry attempts (default: 3) */\n maxRetries?: number;\n /** Base delay in milliseconds (default: 1000) */\n baseDelayMs?: number;\n /** Maximum delay in milliseconds (default: 30000) */\n maxDelayMs?: number;\n /** Enable jitter for delay randomization (default: true) */\n jitter?: boolean;\n /** AbortSignal for cancellation */\n signal?: AbortSignal;\n /** Custom retry condition (default: check isRetryableError) */\n shouldRetry?: (error: unknown, attempt: number) => boolean;\n /** Callback for each retry attempt */\n onRetry?: (error: unknown, attempt: number, delayMs: number) => void;\n}\n\n/**\n * Default retry options\n */\nconst DEFAULT_RETRY_OPTIONS: Required<Omit<RetryOptions, 'signal' | 'shouldRetry' | 'onRetry'>> = {\n maxRetries: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30000,\n jitter: true,\n};\n\n/**\n * Calculate delay with exponential backoff and optional jitter\n *\n * @param attempt - Current attempt number (0-indexed)\n * @param baseDelayMs - Base delay in milliseconds\n * @param maxDelayMs - Maximum delay in milliseconds\n * @param jitter - Whether to add jitter\n * @returns Delay in milliseconds\n */\nexport function calculateBackoffDelay(\n attempt: number,\n baseDelayMs: number,\n maxDelayMs: number,\n jitter: boolean\n): number {\n // Exponential backoff: baseDelay * 2^attempt\n const exponentialDelay = baseDelayMs * Math.pow(2, attempt);\n\n // Cap at max delay\n const cappedDelay = Math.min(exponentialDelay, maxDelayMs);\n\n // Add jitter if enabled (±25% of delay)\n if (jitter) {\n const jitterRange = cappedDelay * 0.5; // ±25%\n const jitterValue = Math.random() * jitterRange - jitterRange / 2;\n return Math.max(0, Math.floor(cappedDelay + jitterValue));\n }\n\n return cappedDelay;\n}\n\n/**\n * Sleep for a specified duration\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal for cancellation\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new AuthrimError('operation_cancelled', 'Sleep was cancelled'));\n return;\n }\n\n const timeout = setTimeout(resolve, ms);\n\n if (signal) {\n const onAbort = () => {\n clearTimeout(timeout);\n reject(new AuthrimError('operation_cancelled', 'Sleep was cancelled'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }\n });\n}\n\n/**\n * Execute a function with exponential backoff retry\n *\n * @param fn - Function to execute\n * @param options - Retry options\n * @returns Result of the function\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options?: RetryOptions\n): Promise<T> {\n const opts = { ...DEFAULT_RETRY_OPTIONS, ...options };\n const { maxRetries, baseDelayMs, maxDelayMs, jitter, signal, shouldRetry, onRetry } = opts;\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n // Check for cancellation before each attempt\n if (signal?.aborted) {\n throw new AuthrimError('operation_cancelled', 'Operation was cancelled');\n }\n\n return await fn();\n } catch (error) {\n lastError = error;\n\n // Don't retry cancellation errors\n if (isCancellationError(error)) {\n throw error;\n }\n\n // Check if we should retry\n const canRetry = shouldRetry\n ? shouldRetry(error, attempt)\n : error instanceof AuthrimError && isRetryableError(error);\n\n // Don't retry if max attempts reached or error is not retryable\n if (attempt >= maxRetries || !canRetry) {\n throw error;\n }\n\n // Calculate delay\n const delayMs = calculateBackoffDelay(attempt, baseDelayMs, maxDelayMs, jitter);\n\n // Notify retry callback\n onRetry?.(error, attempt + 1, delayMs);\n\n // Wait before retry\n await sleep(delayMs, signal);\n }\n }\n\n // This should not be reached, but just in case\n throw lastError;\n}\n\n/**\n * Create a retry function with preset options\n *\n * Useful for creating specialized retry functions for specific use cases.\n *\n * @param defaultOptions - Default options for all retries\n * @returns Retry function with preset options\n */\nexport function createRetryFunction(\n defaultOptions: RetryOptions\n): <T>(fn: () => Promise<T>, options?: RetryOptions) => Promise<T> {\n return <T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T> => {\n return withRetry(fn, { ...defaultOptions, ...options });\n };\n}\n\n/**\n * Extract Retry-After header value\n *\n * Supports both HTTP-date and delay-seconds formats.\n *\n * @param headers - Response headers\n * @returns Delay in milliseconds, or null if not found\n */\nexport function parseRetryAfterHeader(\n headers: Headers | Record<string, string>\n): number | null {\n const retryAfter = headers instanceof Headers\n ? headers.get('retry-after')\n : headers['retry-after'] ?? headers['Retry-After'];\n\n if (!retryAfter) {\n return null;\n }\n\n // Try parsing as seconds (most common)\n const seconds = parseInt(retryAfter, 10);\n if (!isNaN(seconds)) {\n return seconds * 1000;\n }\n\n // Try parsing as HTTP-date\n const date = new Date(retryAfter);\n if (!isNaN(date.getTime())) {\n const delayMs = date.getTime() - Date.now();\n return Math.max(0, delayMs);\n }\n\n return null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/config.ts","../src/types/errors.ts","../src/client/discovery.ts","../src/events/emitter.ts","../src/auth/pkce.ts","../src/utils/base64url.ts","../src/auth/state.ts","../src/utils/jwt.ts","../src/utils/timing-safe.ts","../src/auth/authorization-code.ts","../src/auth/par.ts","../src/auth/device-flow.ts","../src/security/dpop.ts","../src/types/token.ts","../src/token/manager.ts","../src/token/introspection.ts","../src/token/revocation.ts","../src/session/logout.ts","../src/session/token-api.ts","../src/session/manager.ts","../src/client/index.ts","../src/auth/silent-auth.ts","../src/auth/client-auth.ts","../src/auth/client-credentials.ts","../src/security/jar.ts","../src/security/jarm.ts","../src/token/auto-refresh.ts","../src/session/session-state.ts","../src/session/front-channel-logout.ts","../src/debug/timeline.ts","../src/debug/logger.ts","../src/debug/diagnostic-logger.ts","../src/utils/hash.ts","../src/utils/cancellation.ts","../src/utils/retry.ts"],"names":["resolveConfig","config","AuthrimError","_AuthrimError","code","message","options","error","getErrorMeta","ERROR_META_MAP","classifyError","meta","mapUserActionToRemediation","remediation","userAction","isRetryableError","classification","emitClassifiedError","emitter","severity","timestamp","source","payload","normalizeIssuer","issuer","_DiscoveryClient","normalizedIssuer","cached","discoveryUrl","doc","response","docIssuer","DiscoveryClient","EventEmitter","event","handler","onceHandler","data","handlers","authrimError","PKCEHelper","crypto","codeVerifier","codeChallenge","verifier","base64urlEncode","base64","len","i","byte1","byte2","byte3","triplet","BASE64_CHARS","base64urlDecode","str","paddingLen","outputLen","output","outputIndex","BASE64_LOOKUP","byte4","stringToBase64url","encoder","base64urlToString","base64url","STORAGE_KEYS","issuerHash","clientIdHash","state","_StateManager","storage","ttlSeconds","validatedReturnTo","stateBytes","nonceBytes","operationIdBytes","nonce","operationId","now","authState","key","returnTo","globalWindow","currentOrigin","e","parsed","stored","prefix","all","value","intervalMs","count","StateManager","decodeJwt","jwt","parts","headerB64","payloadB64","signature","header","decodeIdToken","idToken","isJwtExpired","skewSeconds","getIdTokenNonce","timingSafeEqual","a","b","aBytes","bBytes","aLen","bLen","maxLen","result","aByte","bByte","AuthorizationCodeFlow","http","clientId","logger","discovery","pkce","endpoint","params","scope","protectedParams","callbackUrl","searchParams","errorDescription","tokenEndpoint","body","errorData","tokenResponse","idTokenNonce","expiresAt","tokenSet","PARClient","request","parEndpoint","headers","parResponse","requestUri","DEFAULT_INTERVAL","DeviceFlowClient","errorCode","currentInterval","ms","signal","resolve","reject","timeout","DPoPManager","existing","method","uri","url","htu","claims","claimsB64","signingInput","signatureB64","accessToken","hash","TOKEN_TYPE_URIS","_TokenManager","tokens","expiresAtMs","warningTime","jitter","delay","expiresIn","isLeader","refreshToken","reason","attempt","willRetry","newTokens","subjectTokenType","type","TokenManager","TokenIntrospector","token","TokenRevoker","LogoutHandler","storedIdToken","storedTokens","revocationResult","endSessionEndpoint","tokenKey","idTokenKey","TokenApiClient","userinfoEndpoint","SessionManager","hashForKey","length","AuthrimClient","hashLength","tokenApiClient","pkcePair","manager","createAuthrimClient","client","INTERACTIVE_LOGIN_REQUIRED_ERRORS","SilentAuthHandler","responseUrl","buildClientAuthentication","credentials","bodyParams","encodedCredentials","generateJti","assertion","_exhaustive","ClientCredentialsClient","authHeaders","authBodyParams","JARBuilder","lifetime","protectedClaims","isJarRequired","JARMValidator","clockSkew","_AutoRefreshScheduler","tokenManager","AutoRefreshScheduler","SessionStateCalculator","salt","saltBytes","hashInput","hashBytes","sessionState","calculated","dotIndex","base64urlRegex","FrontChannelLogoutUrlBuilder","resultParams","urlObj","iss","sid","expected","SENSITIVE_KEYS","SENSITIVE_URL_PARAMS","EventTimeline","redactLevelToUse","redactedData","entry","level","obj","lowerKey","capitalizedKey","item","sensitive","param","hashParams","hashModified","createConsoleLogger","includeTimestamps","consoleMethod","consoleObj","noopLogger","createDebugLogger","DebugContext","id","DiagnosticLogger","logsToSend","logs","log","l","c","r","createDiagnosticLogger","calculateDsHash","deviceSecret","leftHalf","withAbortSignal","promise","cancelledError","onAbort","createCancellableOperation","fn","controller","isCancellationError","raceWithCancellation","operations","op","DEFAULT_RETRY_OPTIONS","calculateBackoffDelay","baseDelayMs","maxDelayMs","exponentialDelay","cappedDelay","jitterRange","jitterValue","sleep","withRetry","opts","maxRetries","shouldRetry","onRetry","lastError","canRetry","delayMs","createRetryFunction","defaultOptions","parseRetryAfterHeader","retryAfter","seconds","date"],"mappings":"aAqJO,SAASA,EAAcC,CAAAA,CAA6C,CACzE,OAAO,CACL,GAAGA,EACH,MAAA,CAAQA,CAAAA,CAAO,MAAA,EAAU,CAAC,SAAU,SAAS,CAAA,CAC7C,WAAYA,CAAAA,CAAO,UAAA,EAAc,MACjC,mBAAA,CAAqBA,CAAAA,CAAO,mBAAA,EAAuB,IAAA,CAAO,IAC1D,kBAAA,CAAoBA,CAAAA,CAAO,oBAAsB,EAAA,CACjD,eAAA,CAAiBA,EAAO,eAAA,EAAmB,GAAA,CAC3C,WAAA,CAAa,CACX,WAAYA,CAAAA,CAAO,WAAA,EAAa,YAAc,EAChD,CACF,CACF,CCgBO,IAAMC,CAAAA,CAAN,MAAMC,UAAqB,KAAM,CAatC,YAAYC,CAAAA,CAAwBC,CAAAA,CAAiBC,EAA+B,CAClF,KAAA,CAAMD,CAAO,CAAA,CACb,KAAK,IAAA,CAAO,cAAA,CACZ,KAAK,IAAA,CAAOD,CAAAA,CACZ,KAAK,OAAA,CAAUE,CAAAA,EAAS,OAAA,CACxB,IAAA,CAAK,SAAWA,CAAAA,EAAS,QAAA,CACzB,KAAK,KAAA,CAAQA,CAAAA,EAAS,MACxB,CAKA,OAAO,eAAeC,CAAAA,CAIL,CAef,IAAMH,CAAAA,CAda,CACjB,kBACA,qBAAA,CACA,eAAA,CACA,4BACA,eAAA,CACA,cAAA,CACA,yBAAA,CACA,eAAA,CACA,eACF,CAAA,CAI0C,QAAA,CAASG,EAAM,KAAuB,CAAA,CAC3EA,EAAM,KAAA,CACP,iBAAA,CAEJ,OAAO,IAAIJ,EAAaC,CAAAA,CAAMG,CAAAA,CAAM,mBAAqBA,CAAAA,CAAM,KAAA,CAAO,CACpE,QAAA,CAAUA,CAAAA,CAAM,SAAA,CAChB,OAAA,CAAS,CAAE,aAAA,CAAeA,CAAAA,CAAM,KAAM,CACxC,CAAC,CACH,CAKA,WAAA,EAAuB,CACrB,OAAO,KAAK,IAAA,GAAS,eAAA,EAAmB,KAAK,IAAA,GAAS,eACxD,CAKA,IAAI,IAAA,EAAyB,CAC3B,OAAOC,GAAa,IAAA,CAAK,IAAI,CAC/B,CACF,CAAA,CAKMC,GAA6D,CAEjE,eAAA,CAAiB,CACf,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,mBAAA,CAAqB,CACnB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,aAAA,CAAe,CACb,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,iBACZ,QAAA,CAAU,OACZ,EACA,yBAAA,CAA2B,CACzB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,kBACZ,QAAA,CAAU,OACZ,EACA,aAAA,CAAe,CACb,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,kBACZ,QAAA,CAAU,OACZ,EACA,YAAA,CAAc,CACZ,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,CAAA,CACZ,WAAY,OAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,wBAAyB,CACvB,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,SACZ,EACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,iBACZ,QAAA,CAAU,OACZ,EACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,iBACZ,QAAA,CAAU,OACZ,EAGA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,cAAe,CACb,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,cAAe,CACb,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,eAAgB,CACd,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,cAAe,CACb,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,gBAAA,CAAkB,CAChB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,eAAA,CAAiB,CACf,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,oBAAA,CAAsB,CACpB,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,GAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,OAAA,CACZ,SAAU,SACZ,CAAA,CACA,cAAe,CACb,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,eAAA,CACZ,SAAU,OACZ,CAAA,CACA,aAAA,CAAe,CACb,UAAW,IAAA,CACX,SAAA,CAAW,KACX,YAAA,CAAc,GAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,OAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,eAAA,CAAiB,CACf,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,GAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,OAAA,CACZ,SAAU,OACZ,CAAA,CACA,mBAAoB,CAClB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,iBAAA,CACZ,SAAU,OACZ,CAAA,CACA,oBAAqB,CACnB,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,iBAAA,CACZ,SAAU,OACZ,CAAA,CACA,cAAe,CACb,SAAA,CAAW,IAAA,CACX,SAAA,CAAW,KACX,YAAA,CAAc,GAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,CAAA,CACA,iBAAA,CAAmB,CACjB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,kBACZ,QAAA,CAAU,OACZ,EAGA,SAAA,CAAW,CACT,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,WAAA,CAAa,CACX,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,aAAA,CAAe,CACb,UAAW,KAAA,CACX,SAAA,CAAW,MACX,YAAA,CAAc,CAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,oBAAA,CAAsB,CACpB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,YAAA,CAAc,CAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CAGA,YAAa,CACX,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,aAAc,CACZ,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,cAAe,CACb,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CAGA,eAAA,CAAiB,CACf,SAAA,CAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,WAAY,MAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,YAAA,CAAc,CACZ,SAAA,CAAW,IAAA,CACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,OAAA,CACZ,SAAU,OACZ,CAAA,CAGA,oBAAA,CAAsB,CACpB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,MAAA,CACZ,SAAU,SACZ,CAAA,CACA,cAAA,CAAgB,CACd,UAAW,IAAA,CACX,SAAA,CAAW,KACX,YAAA,CAAc,GAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,OAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CAGA,mBAAA,CAAqB,CACnB,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,GAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,OAAA,CACZ,SAAU,OACZ,CAAA,CACA,iBAAkB,CAChB,SAAA,CAAW,IAAA,CACX,SAAA,CAAW,KACX,YAAA,CAAc,GAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,EACA,yBAAA,CAA2B,CACzB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,MAAA,CACZ,SAAU,SACZ,CAAA,CACA,sBAAA,CAAwB,CACtB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,MAAA,CACZ,SAAU,SACZ,CAAA,CAGA,cAAA,CAAgB,CACd,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,oBAAA,CAAsB,CACpB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,iBAAkB,CAChB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,0BAAA,CAA4B,CAC1B,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CAGA,aAAA,CAAe,CACb,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,OAAA,CACZ,QAAA,CAAU,OACZ,EACA,cAAA,CAAgB,CACd,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,cAAe,CACb,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,MAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,aAAc,CACZ,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,iBAAkB,CAChB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,iBAAkB,CAChB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CAGA,kBAAmB,CACjB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,4BAA6B,CAC3B,SAAA,CAAW,MACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,EACA,qBAAA,CAAuB,CACrB,UAAW,KAAA,CACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,OACZ,QAAA,CAAU,SACZ,EACA,iBAAA,CAAmB,CACjB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,2BAA4B,CAC1B,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,mBAAoB,CAClB,SAAA,CAAW,MACX,SAAA,CAAW,IAAA,CACX,YAAA,CAAc,CAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,SACZ,EACA,kBAAA,CAAoB,CAClB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,iBACZ,QAAA,CAAU,SACZ,EACA,4BAAA,CAA8B,CAC5B,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,OAAA,CACZ,SAAU,OACZ,CAAA,CACA,iBAAA,CAAmB,CACjB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,iBAAA,CAAmB,CACjB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,iBAAA,CAAmB,CACjB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CACA,kBAAmB,CACjB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,aAAA,CAAe,CACb,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,kBAAA,CAAoB,CAClB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,YAAA,CAAc,CACZ,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,2BAAA,CAA6B,CAC3B,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,MAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,uBAAA,CAAyB,CACvB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,gBAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,YAAA,CAAc,CACZ,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,OAAA,CACZ,QAAA,CAAU,SACZ,EAGA,mBAAA,CAAqB,CACnB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,MAAA,CACZ,SAAU,SACZ,CAAA,CAGA,aAAc,CACZ,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,MAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,gBAAiB,CACf,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,iBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,UAAW,CACT,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,aAAc,GAAA,CACd,UAAA,CAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,EACA,uBAAA,CAAyB,CACvB,UAAW,KAAA,CACX,SAAA,CAAW,MACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CAGA,iCAAkC,CAChC,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,iBAAA,CACZ,SAAU,OACZ,CAAA,CACA,2BAA4B,CAC1B,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,YAAA,CAAc,GAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,EACA,4BAAA,CAA8B,CAC5B,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,EAAA,CACZ,WAAY,MAAA,CACZ,QAAA,CAAU,SACZ,CAAA,CACA,gBAAA,CAAkB,CAChB,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,EAAA,CACZ,UAAA,CAAY,MAAA,CACZ,SAAU,SACZ,CAAA,CACA,6BAA8B,CAC5B,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,SAAU,SACZ,CAAA,CACA,qBAAsB,CACpB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,SAAU,OACZ,CAAA,CAGA,yBAA0B,CACxB,SAAA,CAAW,KACX,SAAA,CAAW,IAAA,CACX,YAAA,CAAc,GAAA,CACd,WAAY,CAAA,CACZ,UAAA,CAAY,QACZ,QAAA,CAAU,OACZ,EACA,6BAAA,CAA+B,CAC7B,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,kBACZ,QAAA,CAAU,OACZ,EACA,oBAAA,CAAsB,CACpB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,OACZ,QAAA,CAAU,OACZ,EAGA,yBAAA,CAA2B,CACzB,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,IACd,UAAA,CAAY,CAAA,CACZ,WAAY,OAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,2BAAA,CAA6B,CAC3B,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,OACZ,QAAA,CAAU,OACZ,CAAA,CACA,mBAAA,CAAqB,CACnB,SAAA,CAAW,IAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,EACd,UAAA,CAAY,CAAA,CACZ,UAAA,CAAY,MAAA,CACZ,SAAU,SACZ,CAAA,CAGA,kBAAmB,CACjB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,UAAA,CAAY,iBAAA,CACZ,SAAU,OACZ,CAAA,CACA,aAAc,CACZ,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,MAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CAGA,qBAAA,CAAuB,CACrB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CACA,sBAAA,CAAwB,CACtB,SAAA,CAAW,KAAA,CACX,UAAW,KAAA,CACX,UAAA,CAAY,gBAAA,CACZ,QAAA,CAAU,OACZ,CAAA,CAGA,mBAAA,CAAqB,CACnB,SAAA,CAAW,KAAA,CACX,UAAW,IAAA,CACX,YAAA,CAAc,CAAA,CACd,UAAA,CAAY,EACZ,UAAA,CAAY,OAAA,CACZ,SAAU,SACZ,CAAA,CAGA,kBAAmB,CACjB,SAAA,CAAW,MACX,SAAA,CAAW,KAAA,CACX,WAAY,MAAA,CACZ,QAAA,CAAU,OACZ,CACF,EAKO,SAASD,EAAAA,CAAaJ,CAAAA,CAA0C,CACrE,OAAOK,GAAeL,CAAI,CAC5B,CAmBO,SAASM,CAAAA,CAAcH,EAA0C,CACtE,IAAMI,CAAAA,CAAOJ,CAAAA,CAAM,KAGnB,GAAI,CAACI,EAAK,SAAA,EAAaA,CAAAA,CAAK,aAAe,iBAAA,CACzC,OAAO,CAAE,QAAA,CAAU,QAAS,WAAA,CAAa,iBAAkB,EAI7D,GAAIA,CAAAA,CAAK,WAAa,OAAA,CACpB,OAAO,CAAE,QAAA,CAAU,QAAS,WAAA,CAAaC,EAAAA,CAA2BD,EAAK,UAAU,CAAE,EAIvF,IAAIE,CAAAA,CAAuC,MAAA,CAE3C,OAAIF,EAAK,SAAA,CACPE,CAAAA,CAAc,QACLF,CAAAA,CAAK,UAAA,GAAe,iBAC7BE,CAAAA,CAAc,gBAAA,CACLN,CAAAA,CAAM,IAAA,GAAS,gBACxBM,CAAAA,CAAc,aAAA,CACLF,EAAK,UAAA,GAAe,iBAAA,GAC7BE,EAAc,iBAAA,CAAA,CAGT,CAAE,QAAA,CAAU,aAAA,CAAe,YAAAA,CAAY,CAChD,CAKA,SAASD,EAAAA,CAA2BE,EAA6D,CAC/F,OAAQA,GACN,KAAK,QACL,KAAK,eAAA,CACH,OAAO,OAAA,CACT,KAAK,iBACH,OAAO,gBAAA,CACT,KAAK,iBAAA,CACH,OAAO,iBAAA,CAET,QACE,OAAO,MACX,CACF,CAKO,SAASC,CAAAA,CAAiBR,CAAAA,CAA8B,CAC7D,IAAMS,CAAAA,CAAiBN,CAAAA,CAAcH,CAAK,CAAA,CAC1C,OAAOS,EAAe,QAAA,GAAa,aAAA,EAAiBA,CAAAA,CAAe,WAAA,GAAgB,OACrF,CA6DO,SAASC,EACdC,CAAAA,CACAX,CAAAA,CACAD,EACM,CACN,GAAM,CAAE,QAAA,CAAAa,CAAAA,CAAU,YAAAN,CAAY,CAAA,CAAIH,EAAcH,CAAK,CAAA,CAC/Ca,EAAY,IAAA,CAAK,GAAA,EAAI,CACrBC,CAAAA,CAASf,EAAQ,MAAA,EAAU,MAAA,CAG3BgB,EAAU,CACd,KAAA,CAAAf,EACA,QAAA,CAAAY,CAAAA,CACA,WAAA,CAAAN,CAAAA,CACA,QAASP,CAAAA,CAAQ,OAAA,CACjB,UAAAc,CAAAA,CACA,MAAA,CAAAC,EACA,WAAA,CAAaf,CAAAA,CAAQ,WACvB,CAAA,CAGAY,EAAQ,IAAA,CAAK,OAAA,CAASI,CAAO,CAAA,CAGzBH,CAAAA,GAAa,cACfD,CAAAA,CAAQ,IAAA,CAAK,oBAAqB,CAAE,GAAGI,EAAS,QAAA,CAAU,aAAuB,CAAC,CAAA,CAElFJ,CAAAA,CAAQ,KAAK,aAAA,CAAe,CAAE,GAAGI,CAAAA,CAAS,SAAU,OAAiB,CAAC,EAE1E,CCx/BO,SAASC,EAAgBC,CAAAA,CAAwB,CACtD,OAAOA,CAAAA,CAAO,QAAQ,MAAA,CAAQ,EAAE,CAClC,CAKO,IAAMC,EAAN,MAAMA,CAAgB,CAQ3B,WAAA,CAAYnB,EAAiC,CAL7C,IAAA,CAAiB,MAAsC,IAAI,GAAA,CAMzD,KAAK,IAAA,CAAOA,CAAAA,CAAQ,IAAA,CACpB,IAAA,CAAK,WAAaA,CAAAA,CAAQ,UAAA,EAAcmB,EAAgB,qBAC1D,CASA,MAAM,QAAA,CAASD,CAAAA,CAAgD,CAC7D,IAAME,EAAmBH,CAAAA,CAAgBC,CAAM,EACzCG,CAAAA,CAAS,IAAA,CAAK,MAAM,GAAA,CAAID,CAAgB,CAAA,CAG9C,GAAIC,GAAU,CAAC,IAAA,CAAK,UAAUA,CAAM,CAAA,CAClC,OAAOA,CAAAA,CAAO,GAAA,CAIhB,IAAMC,CAAAA,CAAe,GAAGF,CAAgB,CAAA,iCAAA,CAAA,CAEpCG,EACJ,GAAI,CACF,IAAMC,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,KAAA,CAA6BF,CAAY,CAAA,CAC1E,GAAI,CAACE,CAAAA,CAAS,EAAA,CACZ,MAAM,IAAI5B,CAAAA,CAAa,iBAAA,CAAmB,CAAA,0BAAA,EAA6B4B,EAAS,MAAM,CAAA,CAAA,CAAI,CACxF,OAAA,CAAS,CAAE,OAAQA,CAAAA,CAAS,MAAA,CAAQ,UAAA,CAAYA,CAAAA,CAAS,UAAW,CACtE,CAAC,EAEHD,CAAAA,CAAMC,CAAAA,CAAS,KACjB,CAAA,MAASvB,CAAAA,CAAO,CACd,MAAIA,aAAiBL,CAAAA,CACbK,CAAAA,CAEF,IAAIL,CAAAA,CAAa,iBAAA,CAAmB,qCAAsC,CAC9E,KAAA,CAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAAA,CACxC,OAAA,CAAS,CAAE,GAAA,CAAKqB,CAAa,CAC/B,CAAC,CACH,CAGA,IAAMG,EAAYR,CAAAA,CAAgBM,CAAAA,CAAI,MAAM,CAAA,CAC5C,GAAIE,IAAcL,CAAAA,CAChB,MAAM,IAAIxB,CAAAA,CACR,qBACA,CAAA,iDAAA,EAAoDwB,CAAgB,WAAWK,CAAS,CAAA,CAAA,CAAA,CACxF,CACE,OAAA,CAAS,CACP,QAAA,CAAUL,CAAAA,CACV,OAAQK,CACV,CACF,CACF,CAAA,CAIF,OAAA,IAAA,CAAK,MAAM,GAAA,CAAIL,CAAAA,CAAkB,CAC/B,GAAA,CAAAG,CAAAA,CACA,UAAW,IAAA,CAAK,GAAA,EAClB,CAAC,CAAA,CAEMA,CACT,CAKQ,SAAA,CAAUF,CAAAA,CAAkC,CAClD,OAAO,IAAA,CAAK,GAAA,GAAQA,CAAAA,CAAO,SAAA,CAAY,KAAK,UAC9C,CAKA,UAAA,EAAmB,CACjB,KAAK,KAAA,CAAM,KAAA,GACb,CAOA,WAAA,CAAYH,EAAsB,CAChC,IAAA,CAAK,KAAA,CAAM,MAAA,CAAOD,EAAgBC,CAAM,CAAC,EAC3C,CACF,CAAA,CAjGaC,EAMa,oBAAA,CAAuB,IAAA,CAAO,GAAA,CANjD,IAAMO,EAANP,EChCA,IAAMQ,EAAN,KAAmB,CAAnB,cACL,IAAA,CAAQ,SAAA,CAA+E,IAAI,IAAA,CAS3F,GAA+BC,CAAAA,CAAUC,CAAAA,CAA6C,CACpF,OAAK,IAAA,CAAK,UAAU,GAAA,CAAID,CAAK,CAAA,EAC3B,IAAA,CAAK,UAAU,GAAA,CAAIA,CAAAA,CAAO,IAAI,GAAK,CAAA,CAErC,KAAK,SAAA,CAAU,GAAA,CAAIA,CAAK,CAAA,CAAG,IAAIC,CAAgD,CAAA,CAGxE,IAAM,CACX,IAAA,CAAK,IAAID,CAAAA,CAAOC,CAAO,EACzB,CACF,CASA,KAAiCD,CAAAA,CAAUC,CAAAA,CAA6C,CACtF,IAAMC,CAAAA,EAAgBC,GAA2B,CAC/C,IAAA,CAAK,GAAA,CAAIH,CAAAA,CAAOE,CAAW,CAAA,CAC3BD,CAAAA,CAAQE,CAAI,EACd,CAAA,CAAA,CAEA,OAAO,IAAA,CAAK,EAAA,CAAGH,CAAAA,CAAOE,CAAW,CACnC,CAQA,GAAA,CAAgCF,EAAUC,CAAAA,CAAuC,CAC/E,IAAMG,CAAAA,CAAW,IAAA,CAAK,SAAA,CAAU,GAAA,CAAIJ,CAAK,CAAA,CACrCI,CAAAA,GACFA,EAAS,MAAA,CAAOH,CAAgD,EAC5DG,CAAAA,CAAS,IAAA,GAAS,GACpB,IAAA,CAAK,SAAA,CAAU,OAAOJ,CAAK,CAAA,EAGjC,CAQA,IAAA,CAAiCA,CAAAA,CAAUG,EAA8B,CACvE,IAAMC,CAAAA,CAAW,IAAA,CAAK,UAAU,GAAA,CAAIJ,CAAK,EACzC,GAAII,CAAAA,CACF,QAAWH,CAAAA,IAAWG,CAAAA,CACpB,GAAI,CACFH,EAAQE,CAAI,EACd,OAAS9B,CAAAA,CAAO,CAId,GAAI2B,CAAAA,GAAU,OAAA,CAAS,CACrB,IAAMK,EACJhC,CAAAA,YAAiBL,CAAAA,CACbK,EACA,IAAIL,CAAAA,CAAa,sBAAuB,8BAAA,CAAgC,CACtE,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAC1C,CAAC,EACP,IAAA,CAAK,IAAA,CAAK,QAAS,CACjB,KAAA,CAAOgC,CAAAA,CACP,OAAA,CAAS,+BAA+BL,CAAK,CAAA,CAAA,CAC/C,CAAC,EACH,CAGF,CAGN,CAOA,kBAAA,CAAmBA,CAAAA,CAAgC,CAC7CA,EACF,IAAA,CAAK,SAAA,CAAU,OAAOA,CAAK,CAAA,CAE3B,KAAK,SAAA,CAAU,KAAA,GAEnB,CAQA,cAAcA,CAAAA,CAAiC,CAC7C,OAAO,IAAA,CAAK,SAAA,CAAU,IAAIA,CAAK,CAAA,EAAG,IAAA,EAAQ,CAC5C,CACF,EC9FO,IAAMM,EAAN,KAAiB,CACtB,YAA6BC,CAAAA,CAAwB,CAAxB,IAAA,CAAA,MAAA,CAAAA,EAAyB,CAStD,MAAM,YAAA,EAAkC,CACtC,IAAMC,CAAAA,CAAe,MAAM,IAAA,CAAK,MAAA,CAAO,oBAAA,EAAqB,CACtDC,EAAgB,MAAM,IAAA,CAAK,OAAO,qBAAA,CAAsBD,CAAY,EAE1E,OAAO,CACL,YAAA,CAAAA,CAAAA,CACA,cAAAC,CAAAA,CACA,mBAAA,CAAqB,MACvB,CACF,CAOA,MAAM,oBAAA,EAAwC,CAC5C,OAAO,IAAA,CAAK,MAAA,CAAO,sBACrB,CAQA,MAAM,qBAAA,CAAsBC,CAAAA,CAAmC,CAC7D,OAAO,IAAA,CAAK,MAAA,CAAO,qBAAA,CAAsBA,CAAQ,CACnD,CACF,ECxDO,SAASC,CAAAA,CAAgBR,EAA0B,CAExD,IAAIS,CAAAA,CAAS,EAAA,CAGPC,EAAMV,CAAAA,CAAK,MAAA,CACjB,QAASW,CAAAA,CAAI,CAAA,CAAGA,EAAID,CAAAA,CAAKC,CAAAA,EAAK,CAAA,CAAG,CAC/B,IAAMC,CAAAA,CAAQZ,CAAAA,CAAKW,CAAC,CAAA,CACdE,CAAAA,CAAQF,EAAI,CAAA,CAAID,CAAAA,CAAMV,EAAKW,CAAAA,CAAI,CAAC,EAAI,CAAA,CACpCG,CAAAA,CAAQH,EAAI,CAAA,CAAID,CAAAA,CAAMV,EAAKW,CAAAA,CAAI,CAAC,CAAA,CAAI,CAAA,CAEpCI,EAAWH,CAAAA,EAAS,EAAA,CAAOC,GAAS,CAAA,CAAKC,CAAAA,CAE/CL,GAAUO,CAAAA,CAAcD,CAAAA,EAAW,EAAA,CAAM,EAAI,EAC7CN,CAAAA,EAAUO,CAAAA,CAAcD,GAAW,EAAA,CAAM,EAAI,EAC7CN,CAAAA,EAAUE,CAAAA,CAAI,CAAA,CAAID,CAAAA,CAAMM,EAAcD,CAAAA,EAAW,CAAA,CAAK,EAAI,CAAA,CAAI,EAAA,CAC9DN,GAAUE,CAAAA,CAAI,CAAA,CAAID,EAAMM,CAAAA,CAAaD,CAAAA,CAAU,EAAI,CAAA,CAAI,GACzD,CAIA,OAAON,CAAAA,CAAO,QAAQ,KAAA,CAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAO,GAAG,CAAA,CAAE,QAAQ,KAAA,CAAO,EAAE,CACzE,CASO,SAASQ,EAAAA,CAAgBC,CAAAA,CAAyB,CAGvD,GAAI,CAAC,mBAAmB,IAAA,CAAKA,CAAG,EAC9B,MAAM,IAAI,KAAA,CAAM,uDAAuD,EAIzE,IAAIT,CAAAA,CAASS,EAAI,OAAA,CAAQ,IAAA,CAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,IAAA,CAAM,GAAG,EAGrD,KAAOT,CAAAA,CAAO,OAAS,CAAA,EACrBA,CAAAA,EAAU,IAIZ,IAAMC,CAAAA,CAAMD,CAAAA,CAAO,MAAA,CACbU,EAAaV,CAAAA,CAAO,QAAA,CAAS,IAAI,CAAA,CAAI,CAAA,CAAIA,EAAO,QAAA,CAAS,GAAG,CAAA,CAAI,CAAA,CAAI,EACpEW,CAAAA,CAAaV,CAAAA,CAAM,EAAK,CAAA,CAAIS,CAAAA,CAC5BE,EAAS,IAAI,UAAA,CAAWD,CAAS,CAAA,CAEnCE,EAAc,CAAA,CAClB,IAAA,IAASX,EAAI,CAAA,CAAGA,CAAAA,CAAID,EAAKC,CAAAA,EAAK,CAAA,CAAG,CAC/B,IAAMC,CAAAA,CAAQW,EAAcd,CAAAA,CAAO,UAAA,CAAWE,CAAC,CAAC,CAAA,CAC1CE,EAAQU,CAAAA,CAAcd,CAAAA,CAAO,UAAA,CAAWE,CAAAA,CAAI,CAAC,CAAC,CAAA,CAC9CG,EAAQS,CAAAA,CAAcd,CAAAA,CAAO,WAAWE,CAAAA,CAAI,CAAC,CAAC,CAAA,CAC9Ca,EAAQD,CAAAA,CAAcd,CAAAA,CAAO,WAAWE,CAAAA,CAAI,CAAC,CAAC,CAAA,CAE9CI,CAAAA,CAAWH,CAAAA,EAAS,EAAA,CAAOC,GAAS,EAAA,CAAOC,CAAAA,EAAS,EAAKU,CAAAA,CAE3DF,CAAAA,CAAcF,IAAWC,CAAAA,CAAOC,CAAAA,EAAa,EAAKP,CAAAA,EAAW,EAAA,CAAM,KACnEO,CAAAA,CAAcF,CAAAA,GAAWC,EAAOC,CAAAA,EAAa,CAAA,CAAKP,GAAW,CAAA,CAAK,GAAA,CAAA,CAClEO,CAAAA,CAAcF,CAAAA,GAAWC,EAAOC,CAAAA,EAAa,CAAA,CAAIP,EAAU,GAAA,EACjE,CAEA,OAAOM,CACT,CAQO,SAASI,CAAAA,CAAkBP,EAAqB,CACrD,IAAMQ,EAAU,IAAI,WAAA,CACpB,OAAOlB,CAAAA,CAAgBkB,CAAAA,CAAQ,MAAA,CAAOR,CAAG,CAAC,CAC5C,CAQO,SAASS,CAAAA,CAAkBC,CAAAA,CAA2B,CAE3D,OADgB,IAAI,aAAY,CACjB,MAAA,CAAOX,GAAgBW,CAAS,CAAC,CAClD,CAGA,IAAMZ,EAAe,kEAAA,CAGfO,CAAAA,CAAgB,IAAI,UAAA,CAAW,GAAG,CAAA,CACxC,IAAA,IAASZ,EAAI,CAAA,CAAGA,CAAAA,CAAIK,EAAa,MAAA,CAAQL,CAAAA,EAAAA,CACvCY,CAAAA,CAAcP,CAAAA,CAAa,WAAWL,CAAC,CAAC,EAAIA,CAAAA,CC9BvC,IAAMkB,EAAe,CAI1B,SAAA,CAAW,CAACC,CAAAA,CAAoBC,EAAsBC,CAAAA,GACpD,CAAA,QAAA,EAAWF,CAAU,CAAA,CAAA,EAAIC,CAAY,SAASC,CAAK,CAAA,CAAA,CAKrD,MAAA,CAAQ,CAACF,EAAoBC,CAAAA,GAC3B,CAAA,QAAA,EAAWD,CAAU,CAAA,CAAA,EAAIC,CAAY,UAKvC,OAAA,CAAS,CAACD,CAAAA,CAAoBC,CAAAA,GAC5B,WAAWD,CAAU,CAAA,CAAA,EAAIC,CAAY,CAAA,SAAA,CAAA,CAKvC,eAAA,CAAiB,CAACD,CAAAA,CAAoBC,CAAAA,GACpC,CAAA,QAAA,EAAWD,CAAU,IAAIC,CAAY,CAAA,MAAA,CACzC,EAKaE,CAAAA,CAAN,MAAMA,CAAa,CAgBxB,WAAA,CACmB7B,CAAAA,CACA8B,CAAAA,CACAJ,EACAC,CAAAA,CACjB,CAJiB,YAAA3B,CAAAA,CACA,IAAA,CAAA,OAAA,CAAA8B,EACA,IAAA,CAAA,UAAA,CAAAJ,CAAAA,CACA,kBAAAC,CAAAA,CANnB,IAAA,CAAQ,gBAAyD,KAO9D,CAUH,MAAM,iBAAA,CAAkB9D,CAAAA,CAAuD,CAC7E,IAAMkE,CAAAA,CAAalE,CAAAA,CAAQ,UAAA,EAAcgE,EAAa,mBAAA,CAGlDG,CAAAA,CACAnE,EAAQ,QAAA,GACVmE,CAAAA,CAAoB,KAAK,gBAAA,CACvBnE,CAAAA,CAAQ,QAAA,CACRA,CAAAA,CAAQ,iBAAmB,CAAE,MAAA,CAAQ,eAAgB,CACvD,CAAA,CAAA,CAIF,IAAMoE,CAAAA,CAAa,MAAM,IAAA,CAAK,MAAA,CAAO,YAAYJ,CAAAA,CAAa,aAAa,EACrEK,CAAAA,CAAa,MAAM,KAAK,MAAA,CAAO,WAAA,CAAYL,CAAAA,CAAa,aAAa,EACrEM,CAAAA,CAAmB,MAAM,KAAK,MAAA,CAAO,WAAA,CAAYN,EAAa,kBAAkB,CAAA,CAEhFD,CAAAA,CAAQxB,CAAAA,CAAgB6B,CAAU,CAAA,CAClCG,CAAAA,CAAQhC,EAAgB8B,CAAU,CAAA,CAClCG,EAAcjC,CAAAA,CAAgB+B,CAAgB,CAAA,CAE9CG,CAAAA,CAAM,KAAK,GAAA,EAAI,CACfC,EAAuB,CAC3B,KAAA,CAAAX,EACA,KAAA,CAAAQ,CAAAA,CACA,YAAA,CAAcvE,CAAAA,CAAQ,aACtB,WAAA,CAAaA,CAAAA,CAAQ,YACrB,KAAA,CAAOA,CAAAA,CAAQ,MACf,SAAA,CAAWyE,CAAAA,CACX,UAAWA,CAAAA,CAAMP,CAAAA,CAAa,IAC9B,QAAA,CAAUC,CAAAA,CACV,YAAAK,CACF,CAAA,CAGMG,EAAMf,CAAAA,CAAa,SAAA,CAAU,IAAA,CAAK,UAAA,CAAY,KAAK,YAAA,CAAcG,CAAK,EAC5E,OAAA,MAAM,IAAA,CAAK,QAAQ,GAAA,CAAIY,CAAAA,CAAK,IAAA,CAAK,SAAA,CAAUD,CAAS,CAAC,CAAA,CAE9CA,CACT,CAUQ,gBAAA,CAAiBE,EAAkB5E,CAAAA,CAAkC,CAC3E,OAAQA,CAAAA,CAAQ,QACd,KAAK,gBAGH,GAAI4E,CAAAA,CAAS,WAAW,GAAG,CAAA,EAAK,CAACA,CAAAA,CAAS,WAAW,IAAI,CAAA,EAEnD,CAACA,CAAAA,CAAS,QAAA,CAAS,GAAG,CAAA,CACxB,OAAOA,CAAAA,CAGX,MAAM,IAAIhF,CAAAA,CACR,mBAAA,CACA,qDACF,CAAA,CAEF,KAAK,cACH,GAAI,CAGF,IAAMiF,CAAAA,CAAe,OAAO,UAAA,CAAe,GAAA,CAAe,WAAmB,MAAA,CAAS,KAAA,CAAA,CAChFC,EAAgB9E,CAAAA,CAAQ,aAAA,EAAkB6E,CAAAA,EAAc,QAAA,EAAU,OACxE,GAAI,CAACC,EACH,MAAM,IAAIlF,EACR,mBAAA,CACA,8EACF,EAUF,GANIgF,CAAAA,CAAS,WAAW,GAAG,CAAA,EAAK,CAACA,CAAAA,CAAS,UAAA,CAAW,IAAI,CAAA,EAK7C,IAAI,GAAA,CAAIA,CAAQ,EACpB,MAAA,GAAWE,CAAAA,CACjB,OAAOF,CAEX,CAAA,MAASG,EAAG,CACV,GAAIA,CAAAA,YAAanF,CAAAA,CAAc,MAAMmF,CAEvC,CACA,MAAM,IAAInF,CAAAA,CACR,oBACA,iDACF,CAAA,CAEF,KAAK,WAAA,CACH,GAAI,CAACI,CAAAA,CAAQ,gBAAkBA,CAAAA,CAAQ,cAAA,CAAe,SAAW,CAAA,CAC/D,MAAM,IAAIJ,CAAAA,CACR,mBAAA,CACA,wDACF,CAAA,CAIF,GAAIgF,EAAS,UAAA,CAAW,GAAG,GAAK,CAACA,CAAAA,CAAS,UAAA,CAAW,IAAI,EACvD,OAAOA,CAAAA,CAGT,GAAI,CACF,IAAMI,EAAS,IAAI,GAAA,CAAIJ,CAAQ,CAAA,CAC/B,GAAI5E,CAAAA,CAAQ,cAAA,CAAe,SAASgF,CAAAA,CAAO,MAAM,EAC/C,OAAOJ,CAEX,CAAA,KAAQ,CAER,CACA,MAAM,IAAIhF,EACR,mBAAA,CACA,CAAA,kCAAA,EAAqCI,EAAQ,cAAA,CAAe,IAAA,CAAK,IAAI,CAAC,CAAA,CACxE,EAEF,QACE,MAAM,IAAIJ,CAAAA,CACR,mBAAA,CACA,4BAA4BI,CAAAA,CAAQ,MAAM,CAAA,CAC5C,CACJ,CACF,CAYA,MAAM,wBAAwB+D,CAAAA,CAAmC,CAC/D,IAAMY,CAAAA,CAAMf,CAAAA,CAAa,SAAA,CAAU,IAAA,CAAK,WAAY,IAAA,CAAK,YAAA,CAAcG,CAAK,CAAA,CAE5E,GAAI,CACF,IAAMkB,CAAAA,CAAS,MAAM,IAAA,CAAK,QAAQ,GAAA,CAAIN,CAAG,EAEzC,GAAI,CAACM,EACH,MAAM,IAAIrF,CAAAA,CAAa,eAAA,CAAiB,iCAAiC,CAAA,CAG3E,IAAI8E,EACJ,GAAI,CACFA,EAAY,IAAA,CAAK,KAAA,CAAMO,CAAM,EAC/B,MAAQ,CACN,MAAM,IAAIrF,CAAAA,CAAa,eAAA,CAAiB,sBAAsB,CAChE,CAGA,GAAI,IAAA,CAAK,KAAI,CAAI8E,CAAAA,CAAU,UACzB,MAAM,IAAI9E,EAAa,eAAA,CAAiB,mBAAmB,CAAA,CAG7D,OAAO8E,CACT,CAAA,OAAE,CAKA,MAAM,IAAA,CAAK,OAAA,CAAQ,OAAOC,CAAG,EAC/B,CACF,CAUA,MAAM,sBAAsC,CAE1C,GAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,OAChB,OAGF,IAAMO,CAAAA,CAAStB,CAAAA,CAAa,gBAAgB,IAAA,CAAK,UAAA,CAAY,KAAK,YAAY,CAAA,CACxEuB,EAAM,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,GACzBV,CAAAA,CAAM,IAAA,CAAK,KAAI,CAErB,IAAA,GAAW,CAACE,CAAAA,CAAKS,CAAK,CAAA,GAAK,MAAA,CAAO,QAAQD,CAAG,CAAA,CAC3C,GAAKR,CAAAA,CAAI,UAAA,CAAWO,CAAM,CAAA,CAI1B,GAAI,CACF,IAAMR,CAAAA,CAAuB,KAAK,KAAA,CAAMU,CAAK,EACzCX,CAAAA,CAAMC,CAAAA,CAAU,WAClB,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAOC,CAAG,EAEjC,CAAA,KAAQ,CAEN,MAAM,IAAA,CAAK,QAAQ,MAAA,CAAOA,CAAG,EAC/B,CAEJ,CASA,gBAAA,CAAiBU,CAAAA,CAAqBrB,EAAa,2BAAA,CAAmC,CACpF,KAAK,eAAA,EAAgB,CAErB,IAAA,CAAK,eAAA,CAAkB,YAAY,IAAM,CACvC,KAAK,oBAAA,EAAqB,CAAE,MAAM,IAAM,CAExC,CAAC,EACH,CAAA,CAAGqB,CAAU,CAAA,CAGb,IAAA,CAAK,sBAAqB,CAAE,KAAA,CAAM,IAAM,CAExC,CAAC,EACH,CAKA,iBAAwB,CAClB,IAAA,CAAK,kBACP,aAAA,CAAc,IAAA,CAAK,eAAe,CAAA,CAClC,IAAA,CAAK,eAAA,CAAkB,IAAA,EAE3B,CASA,MAAM,mBAAA,EAAuC,CAC3C,GAAI,CAAC,KAAK,OAAA,CAAQ,MAAA,CAChB,OAAO,GAAA,CAGT,IAAMH,CAAAA,CAAStB,CAAAA,CAAa,gBAAgB,IAAA,CAAK,UAAA,CAAY,KAAK,YAAY,CAAA,CACxEuB,CAAAA,CAAM,MAAM,KAAK,OAAA,CAAQ,MAAA,GAE3BG,CAAAA,CAAQ,CAAA,CACZ,QAAWX,CAAAA,IAAO,MAAA,CAAO,IAAA,CAAKQ,CAAG,EAC3BR,CAAAA,CAAI,UAAA,CAAWO,CAAM,CAAA,EACvBI,CAAAA,EAAAA,CAIJ,OAAOA,CACT,CACF,EAvSatB,CAAAA,CAEa,oBAAsB,GAAA,CAFnCA,CAAAA,CAKa,cAAgB,EAAA,CAL7BA,CAAAA,CAQa,mBAAqB,EAAA,CARlCA,CAAAA,CAWa,2BAAA,CAA8B,GAAA,KAX3CuB,CAAAA,CAANvB,ECnEA,SAASwB,EAAAA,CAAuCC,CAAAA,CAA4B,CACjF,IAAMC,CAAAA,CAAQD,EAAI,KAAA,CAAM,GAAG,EAC3B,GAAIC,CAAAA,CAAM,SAAW,CAAA,CACnB,MAAM,IAAI,KAAA,CAAM,sCAAsC,CAAA,CAGxD,GAAM,CAACC,CAAAA,CAAWC,CAAAA,CAAYC,CAAS,CAAA,CAAIH,CAAAA,CAE3C,GAAI,CACF,IAAMI,CAAAA,CAAS,IAAA,CAAK,MAAMpC,CAAAA,CAAkBiC,CAAS,CAAC,CAAA,CAChD3E,CAAAA,CAAU,KAAK,KAAA,CAAM0C,CAAAA,CAAkBkC,CAAU,CAAC,EAExD,OAAO,CACL,OAAAE,CAAAA,CACA,OAAA,CAAA9E,EACA,SAAA,CAAA6E,CACF,CACF,CAAA,KAAQ,CACN,MAAM,IAAI,KAAA,CAAM,sCAAsC,CACxD,CACF,CAWO,SAASE,EAAAA,CAAcC,CAAAA,CAAgC,CAE5D,OADgBR,EAAAA,CAAyBQ,CAAO,EACjC,OACjB,CASO,SAASC,EAAAA,CAAajF,CAAAA,CAA2BkF,CAAAA,CAAsB,CAAA,CAAY,CACxF,GAAIlF,CAAAA,CAAQ,MAAQ,MAAA,CAClB,OAAO,OAGT,IAAMyD,CAAAA,CAAM,IAAA,CAAK,KAAA,CAAM,KAAK,GAAA,EAAI,CAAI,GAAI,CAAA,CACxC,OAAOzD,EAAQ,GAAA,CAAMkF,CAAAA,CAAczB,CACrC,CAQO,SAAS0B,EAAgBH,CAAAA,CAAqC,CACnE,GAAI,CAEF,OADeD,GAAcC,CAAO,CAAA,CACtB,KAChB,CAAA,KAAQ,CACN,MACF,CACF,CCzFO,SAASI,CAAAA,CAAgBC,EAAWC,CAAAA,CAAoB,CAE7D,IAAM7C,CAAAA,CAAU,IAAI,WAAA,CACd8C,CAAAA,CAAS9C,EAAQ,MAAA,CAAO4C,CAAC,EACzBG,CAAAA,CAAS/C,CAAAA,CAAQ,MAAA,CAAO6C,CAAC,EAGzBG,CAAAA,CAAOF,CAAAA,CAAO,OACdG,CAAAA,CAAOF,CAAAA,CAAO,OAGdG,CAAAA,CAAS,IAAA,CAAK,GAAA,CAAIF,CAAAA,CAAMC,CAAI,CAAA,CAG9BE,CAAAA,CAASH,EAAOC,CAAAA,CAGpB,IAAA,IAAShE,EAAI,CAAA,CAAGA,CAAAA,CAAIiE,CAAAA,CAAQjE,CAAAA,EAAAA,CAAK,CAC/B,IAAMmE,CAAAA,CAAQnE,EAAI+D,CAAAA,CAAOF,CAAAA,CAAO7D,CAAC,CAAA,CAAI,CAAA,CAC/BoE,CAAAA,CAAQpE,CAAAA,CAAIgE,EAAOF,CAAAA,CAAO9D,CAAC,EAAI,CAAA,CACrCkE,CAAAA,EAAUC,EAAQC,EACpB,CAEA,OAAOF,CAAAA,GAAW,CACpB,CCqEO,IAAMG,EAAN,KAA4B,CAGjC,YACmBC,CAAAA,CACAC,CAAAA,CACjB,CAFiB,IAAA,CAAA,IAAA,CAAAD,CAAAA,CACA,cAAAC,EAChB,CAKH,oBAAoBC,CAAAA,CAAoD,CACtE,KAAK,gBAAA,CAAmBA,EAC1B,CAYA,qBAAA,CACEC,EACAzC,CAAAA,CACA0C,CAAAA,CACApH,EACwB,CAExB,GAAImH,EAAU,qCAAA,EAAyC,CAACnH,CAAAA,CAAQ,MAAA,CAC9D,MAAM,IAAIJ,CAAAA,CACR,eACA,qFACF,CAAA,CAIF,GAAIuH,CAAAA,CAAU,6BAAA,EAAiC,CAACnH,CAAAA,CAAQ,OACtD,MAAM,IAAIJ,EACR,cAAA,CACA,0FACF,EAGF,IAAMyH,CAAAA,CAAWF,CAAAA,CAAU,sBAAA,CACrBG,EAAS,IAAI,eAAA,CAGnBA,EAAO,GAAA,CAAI,WAAA,CAAa,KAAK,QAAQ,CAAA,CACrCA,CAAAA,CAAO,GAAA,CAAI,gBAAiBtH,CAAAA,CAAQ,YAAA,EAAgB,MAAM,CAAA,CAC1DsH,CAAAA,CAAO,IAAI,cAAA,CAAgBtH,CAAAA,CAAQ,WAAW,CAAA,CAC9CsH,EAAO,GAAA,CAAI,OAAA,CAAS5C,EAAU,KAAK,CAAA,CACnC4C,EAAO,GAAA,CAAI,OAAA,CAAS5C,CAAAA,CAAU,KAAK,EAGnC4C,CAAAA,CAAO,GAAA,CAAI,iBAAkBF,CAAAA,CAAK,aAAa,EAC/CE,CAAAA,CAAO,GAAA,CAAI,wBAAyBF,CAAAA,CAAK,mBAAmB,EAG5D,IAAMG,CAAAA,CAAQvH,EAAQ,KAAA,EAAS,gBAAA,CAe/B,GAdAsH,CAAAA,CAAO,GAAA,CAAI,OAAA,CAASC,CAAK,EAGrBvH,CAAAA,CAAQ,MAAA,EACVsH,EAAO,GAAA,CAAI,QAAA,CAAUtH,EAAQ,MAAM,CAAA,CAEjCA,CAAAA,CAAQ,SAAA,EACVsH,EAAO,GAAA,CAAI,YAAA,CAActH,EAAQ,SAAS,CAAA,CAExCA,EAAQ,SAAA,EACVsH,CAAAA,CAAO,GAAA,CAAI,YAAA,CAActH,EAAQ,SAAS,CAAA,CAIxCA,EAAQ,WAAA,CAAa,CAEvB,IAAMwH,CAAAA,CAAkB,IAAI,GAAA,CAAI,CAC9B,YACA,eAAA,CACA,cAAA,CACA,QACA,OAAA,CACA,gBAAA,CACA,wBACA,OACF,CAAC,CAAA,CAED,IAAA,GAAW,CAAC7C,CAAAA,CAAKS,CAAK,IAAK,MAAA,CAAO,OAAA,CAAQpF,EAAQ,WAAW,CAAA,CACvDwH,CAAAA,CAAgB,GAAA,CAAI7C,EAAI,WAAA,EAAa,GAKzC2C,CAAAA,CAAO,GAAA,CAAI3C,EAAKS,CAAK,EAEzB,CAKA,IAAMwB,EAAiC,CAAE,GAAA,CAH7B,GAAGS,CAAQ,CAAA,CAAA,EAAIC,EAAO,QAAA,EAAU,EAGC,CAAA,CAE7C,OAAItH,EAAQ,WAAA,GACV4G,CAAAA,CAAO,MAAQlC,CAAAA,CAAU,KAAA,CACzBkC,EAAO,KAAA,CAAQlC,CAAAA,CAAU,KAAA,CAAA,CAGpBkC,CACT,CAWA,aAAA,CAAca,CAAAA,CAAsD,CAClE,IAAIC,CAAAA,CAGAD,EAAY,QAAA,CAAS,GAAG,CAAA,CAI1BC,CAAAA,CAAAA,CAHYD,EAAY,UAAA,CAAW,MAAM,EACrC,IAAI,GAAA,CAAIA,CAAW,CAAA,CACnB,IAAI,GAAA,CAAIA,CAAAA,CAAa,qBAAqB,CAAA,EAC3B,YAAA,CAEnBC,EAAe,IAAI,eAAA,CAAgBD,CAAW,CAAA,CAIhD,IAAMxH,EAAQyH,CAAAA,CAAa,GAAA,CAAI,OAAO,CAAA,CACtC,GAAIzH,EAAO,CACT,IAAM0H,EAAmBD,CAAAA,CAAa,GAAA,CAAI,mBAAmB,CAAA,EAAK,uBAClE,MAAM,IAAI9H,EAAa,aAAA,CAAe+H,CAAAA,CAAkB,CACtD,OAAA,CAAS,CACP,KAAA,CAAA1H,CAAAA,CACA,kBAAmB0H,CAAAA,CACnB,SAAA,CAAWD,EAAa,GAAA,CAAI,WAAW,CACzC,CACF,CAAC,CACH,CAGA,IAAM5H,CAAAA,CAAO4H,CAAAA,CAAa,IAAI,MAAM,CAAA,CAC9B3D,EAAQ2D,CAAAA,CAAa,GAAA,CAAI,OAAO,CAAA,CAEtC,GAAI,CAAC5H,CAAAA,CACH,MAAM,IAAIF,CAAAA,CAAa,cAAA,CAAgB,0CAA0C,CAAA,CAEnF,GAAI,CAACmE,CAAAA,CACH,MAAM,IAAInE,CAAAA,CAAa,gBAAiB,uCAAuC,CAAA,CAGjF,OAAO,CAAE,IAAA,CAAAE,CAAAA,CAAM,KAAA,CAAAiE,CAAM,CACvB,CAYA,MAAM,YAAA,CACJoD,CAAAA,CACAnH,EACmB,CACnB,IAAM4H,CAAAA,CAAgBT,CAAAA,CAAU,eAG1BU,CAAAA,CAAO,IAAI,gBAAgB,CAC/B,UAAA,CAAY,qBACZ,SAAA,CAAW,IAAA,CAAK,QAAA,CAChB,IAAA,CAAM7H,EAAQ,IAAA,CACd,YAAA,CAAcA,EAAQ,WAAA,CACtB,aAAA,CAAeA,EAAQ,YACzB,CAAC,CAAA,CAGGwB,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,IAAA,CAAK,MAAqBoG,CAAAA,CAAe,CAC7D,MAAA,CAAQ,MAAA,CACR,QAAS,CACP,cAAA,CAAgB,mCAClB,CAAA,CACA,IAAA,CAAMC,EAAK,QAAA,EACb,CAAC,EACH,OAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,gBAAiB,sBAAA,CAAwB,CAC9D,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMsG,EAAYtG,CAAAA,CAAS,IAAA,CAC3B,MAAM,IAAI5B,CAAAA,CAAa,cAAe,uBAAA,CAAyB,CAC7D,OAAA,CAAS,CACP,OAAQ4B,CAAAA,CAAS,MAAA,CACjB,MAAOsG,CAAAA,EAAW,KAAA,CAClB,kBAAmBA,CAAAA,EAAW,iBAChC,CACF,CAAC,CACH,CAEA,IAAMC,EAAgBvG,CAAAA,CAAS,IAAA,CAM/B,GAHwBxB,CAAAA,CAAQ,KAAA,CAAM,MAAM,GAAG,CAAA,CAAE,SAAS,QAAQ,CAAA,EAG3C,CAAC+H,CAAAA,CAAc,QAAA,CACpC,MAAM,IAAInI,CAAAA,CACR,kBAAA,CACA,qFACF,EAIF,GAAImI,CAAAA,CAAc,SAAU,CAC1B,IAAMC,EAAe7B,CAAAA,CAAgB4B,CAAAA,CAAc,QAAQ,CAAA,CAG3D,GAAIC,CAAAA,GAAiB,MAAA,CAEnB,WAAK,gBAAA,EAAkB,kBAAA,CAAmB,CACxC,IAAA,CAAM,aAAA,CACN,SAAA,CAAW,UAAA,CACX,OAAQ,MAAA,CACR,QAAA,CAAU,sBACV,MAAA,CAAQ,qBAAA,CACR,aAAc,uEAChB,CAAC,EAEK,IAAIpI,CAAAA,CACR,gBACA,uEACF,CAAA,CAGF,GAAI,CAACwG,CAAAA,CAAgB4B,EAAchI,CAAAA,CAAQ,KAAK,CAAA,CAE9C,MAAA,IAAA,CAAK,kBAAkB,kBAAA,CAAmB,CACxC,KAAM,aAAA,CACN,SAAA,CAAW,WACX,MAAA,CAAQ,MAAA,CACR,YAAA,CAAc,8CAChB,CAAC,CAAA,CAGK,IAAIJ,EAAa,gBAAA,CAAkB,8CAA8C,EAIzF,IAAA,CAAK,gBAAA,EAAkB,kBAAA,CAAmB,CACxC,KAAM,aAAA,CACN,SAAA,CAAW,WACX,MAAA,CAAQ,MACV,CAAC,EACH,CAGA,IAAM6E,CAAAA,CAAM,KAAK,KAAA,CAAM,IAAA,CAAK,KAAI,CAAI,GAAI,EAClCwD,CAAAA,CAAYF,CAAAA,CAAc,UAAA,CAAatD,CAAAA,CAAMsD,EAAc,UAAA,CAAatD,CAAAA,CAAM,KAG9EyD,CAAAA,CAAqB,CACzB,YAAaH,CAAAA,CAAc,YAAA,CAC3B,SAAA,CAAYA,CAAAA,CAAc,YAA2B,QAAA,CACrD,SAAA,CAAAE,EACA,YAAA,CAAcF,CAAAA,CAAc,cAC5B,OAAA,CAASA,CAAAA,CAAc,QAAA,CACvB,KAAA,CAAOA,EAAc,KACvB,CAAA,CAGA,YAAK,gBAAA,EAAkB,eAAA,CAAgB,CACrC,QAAA,CAAU,OAAA,CACV,OAAQ,0DAAA,CACR,IAAA,CAAM,qBACN,OAAA,CAAS,CACP,eAAgB,CAAC,CAACG,EAAS,WAAA,CAC3B,eAAA,CAAiB,CAAC,CAACA,EAAS,YAAA,CAC5B,UAAA,CAAY,CAAC,CAACA,CAAAA,CAAS,QACvB,KAAA,CAAOA,CAAAA,CAAS,KAClB,CACF,CAAC,CAAA,CAEMA,CACT,CACF,EChYO,IAAMC,EAAN,KAAgB,CACrB,WAAA,CACmBnB,CAAAA,CACAC,EACAjH,CAAAA,CACjB,CAHiB,UAAAgH,CAAAA,CACA,IAAA,CAAA,QAAA,CAAAC,EACA,IAAA,CAAA,OAAA,CAAAjH,EAChB,CAWH,MAAM,wBAAA,CACJmH,EACAiB,CAAAA,CACoB,CACpB,IAAMC,CAAAA,CAAclB,CAAAA,CAAU,sCAE9B,GAAI,CAACkB,CAAAA,CACH,MAAM,IAAIzI,CAAAA,CACR,iBAAA,CACA,kDACF,CAAA,CAIF,IAAMiI,EAAO,IAAI,eAAA,CA0BjB,GAvBAA,CAAAA,CAAK,IAAI,WAAA,CAAa,IAAA,CAAK,QAAQ,CAAA,CACnCA,CAAAA,CAAK,IAAI,eAAA,CAAiBO,CAAAA,CAAQ,YAAA,EAAgB,MAAM,EACxDP,CAAAA,CAAK,GAAA,CAAI,eAAgBO,CAAAA,CAAQ,WAAW,EAC5CP,CAAAA,CAAK,GAAA,CAAI,QAASO,CAAAA,CAAQ,KAAK,EAC/BP,CAAAA,CAAK,GAAA,CAAI,QAASO,CAAAA,CAAQ,KAAK,EAC/BP,CAAAA,CAAK,GAAA,CAAI,gBAAA,CAAkBO,CAAAA,CAAQ,aAAa,CAAA,CAChDP,CAAAA,CAAK,IAAI,uBAAA,CAAyBO,CAAAA,CAAQ,mBAAmB,CAAA,CAG7DP,CAAAA,CAAK,GAAA,CAAI,OAAA,CAASO,EAAQ,KAAA,EAAS,gBAAgB,EAG/CA,CAAAA,CAAQ,MAAA,EACVP,EAAK,GAAA,CAAI,QAAA,CAAUO,CAAAA,CAAQ,MAAM,EAE/BA,CAAAA,CAAQ,SAAA,EACVP,EAAK,GAAA,CAAI,YAAA,CAAcO,EAAQ,SAAS,CAAA,CAEtCA,CAAAA,CAAQ,SAAA,EACVP,EAAK,GAAA,CAAI,YAAA,CAAcO,EAAQ,SAAS,CAAA,CAItCA,EAAQ,WAAA,CAAa,CACvB,IAAMZ,CAAAA,CAAkB,IAAI,GAAA,CAAI,CAC9B,YACA,eAAA,CACA,cAAA,CACA,QACA,OAAA,CACA,gBAAA,CACA,uBAAA,CACA,OACF,CAAC,CAAA,CAED,IAAA,GAAW,CAAC7C,CAAAA,CAAKS,CAAK,IAAK,MAAA,CAAO,OAAA,CAAQgD,CAAAA,CAAQ,WAAW,EACvDZ,CAAAA,CAAgB,GAAA,CAAI7C,EAAI,WAAA,EAAa,GAGzCkD,CAAAA,CAAK,GAAA,CAAIlD,EAAKS,CAAK,EAEvB,CAGA,IAAMkD,CAAAA,CAAkC,CACtC,cAAA,CAAgB,mCAAA,CAChB,GAAG,IAAA,CAAK,OAAA,EAAS,OACnB,CAAA,CAGI9G,EACJ,GAAI,CACFA,EAAW,MAAM,IAAA,CAAK,KAAK,KAAA,CAAmB6G,CAAAA,CAAa,CACzD,MAAA,CAAQ,OACR,OAAA,CAAAC,CAAAA,CACA,KAAMT,CAAAA,CAAK,QAAA,EACb,CAAC,EACH,CAAA,MAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,EAAa,eAAA,CAAiB,oBAAA,CAAsB,CAC5D,KAAA,CAAOK,CAAAA,YAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,EAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,EAAS,IAAA,CAC3B,MAAM,IAAI5B,CAAAA,CAAa,WAAA,CAAa,qBAAsB,CACxD,OAAA,CAAS,CACP,MAAA,CAAQ4B,EAAS,MAAA,CACjB,KAAA,CAAOsG,GAAW,KAAA,CAClB,iBAAA,CAAmBA,GAAW,iBAChC,CACF,CAAC,CACH,CAEA,IAAMS,CAAAA,CAAc/G,EAAS,IAAA,CAG7B,GAAI,CAAC+G,CAAAA,CAAY,WAAA,CACf,MAAM,IAAI3I,CAAAA,CAAa,YAAa,kCAAkC,CAAA,CAExE,GAAI,OAAO2I,CAAAA,CAAY,YAAe,QAAA,CACpC,MAAM,IAAI3I,CAAAA,CAAa,YAAa,4CAA4C,CAAA,CAKlF,IAAMqI,CAAAA,CADM,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,EAAI,CAAI,GAAI,EAChBM,CAAAA,CAAY,UAAA,CAEpC,OAAO,CACL,UAAA,CAAYA,EAAY,WAAA,CACxB,SAAA,CAAAN,CACF,CACF,CASA,4BAAA,CACEd,CAAAA,CACAqB,EACQ,CACR,IAAMlB,EAAS,IAAI,eAAA,CACnB,OAAAA,CAAAA,CAAO,IAAI,WAAA,CAAa,IAAA,CAAK,QAAQ,CAAA,CACrCA,CAAAA,CAAO,IAAI,aAAA,CAAekB,CAAU,CAAA,CAE7B,CAAA,EAAGrB,EAAU,sBAAsB,CAAA,CAAA,EAAIG,EAAO,QAAA,EAAU,EACjE,CACF,EC5IA,IAAMmB,EAAAA,CAAmB,EAOZC,CAAAA,CAAN,KAAuB,CAC5B,WAAA,CACmB1B,CAAAA,CACAC,EACjB,CAFiB,IAAA,CAAA,IAAA,CAAAD,CAAAA,CACA,IAAA,CAAA,QAAA,CAAAC,EAChB,CAaH,MAAM,yBACJE,CAAAA,CACAnH,CAAAA,CAC0B,CAC1B,IAAMqH,CAAAA,CAAWF,EAAU,6BAAA,CAE3B,GAAI,CAACE,CAAAA,CACH,MAAM,IAAIzH,CAAAA,CACR,kCAAA,CACA,mEACF,CAAA,CAIF,IAAMiI,CAAAA,CAAO,IAAI,gBAAgB,CAC/B,SAAA,CAAW,KAAK,QAClB,CAAC,EAOD,GALI7H,CAAAA,EAAS,KAAA,EACX6H,CAAAA,CAAK,IAAI,OAAA,CAAS7H,CAAAA,CAAQ,KAAK,CAAA,CAI7BA,CAAAA,EAAS,YAAa,CACxB,IAAMwH,CAAAA,CAAkB,IAAI,IAAI,CAAC,WAAA,CAAa,OAAO,CAAC,CAAA,CAEtD,OAAW,CAAC7C,CAAAA,CAAKS,CAAK,CAAA,GAAK,MAAA,CAAO,QAAQpF,CAAAA,CAAQ,WAAW,EACvDwH,CAAAA,CAAgB,GAAA,CAAI7C,EAAI,WAAA,EAAa,CAAA,EAGzCkD,CAAAA,CAAK,IAAIlD,CAAAA,CAAKS,CAAK,EAEvB,CAGA,IAAI5D,EACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,KAAA,CAAmC6F,EAAU,CACtE,MAAA,CAAQ,OACR,OAAA,CAAS,CACP,cAAA,CAAgB,mCAClB,EACA,IAAA,CAAMQ,CAAAA,CAAK,UACb,CAAC,EACH,CAAA,MAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,EAAa,eAAA,CAAiB,qCAAA,CAAuC,CAC7E,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,EAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,IAAA,CAC3B,MAAM,IAAI5B,CAAAA,CAAa,4BAAA,CAA8B,sCAAuC,CAC1F,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,MAAA,CACjB,KAAA,CAAOsG,GAAW,KAAA,CAClB,iBAAA,CAAmBA,GAAW,iBAChC,CACF,CAAC,CACH,CAEA,IAAM/F,CAAAA,CAAOP,EAAS,IAAA,CAGtB,GAAI,CAACO,CAAAA,CAAK,WAAA,EAAe,CAACA,CAAAA,CAAK,SAAA,EAAa,CAACA,CAAAA,CAAK,iBAChD,MAAM,IAAInC,EACR,4BAAA,CACA,gEACF,EAKF,IAAMqI,CAAAA,CADM,IAAA,CAAK,KAAA,CAAM,KAAK,GAAA,EAAI,CAAI,GAAI,CAAA,CAChBlG,CAAAA,CAAK,WAE7B,OAAO,CACL,UAAA,CAAYA,CAAAA,CAAK,YACjB,QAAA,CAAUA,CAAAA,CAAK,UACf,eAAA,CAAiBA,CAAAA,CAAK,iBACtB,uBAAA,CAAyBA,CAAAA,CAAK,0BAC9B,SAAA,CAAAkG,CAAAA,CACA,SAAUlG,CAAAA,CAAK,QAAA,EAAY0G,EAC7B,CACF,CAgBA,MAAM,QAAA,CACJtB,CAAAA,CACApD,CAAAA,CAC+B,CAE/B,IAAMU,CAAAA,CAAM,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,GAAQ,GAAI,CAAA,CACxC,GAAIA,CAAAA,EAAOV,EAAM,SAAA,CACf,OAAO,CAAE,MAAA,CAAQ,SAAU,EAG7B,IAAM6D,CAAAA,CAAgBT,CAAAA,CAAU,cAAA,CAG1BU,EAAO,IAAI,eAAA,CAAgB,CAC/B,UAAA,CAAY,8CAAA,CACZ,YAAa9D,CAAAA,CAAM,UAAA,CACnB,UAAW,IAAA,CAAK,QAClB,CAAC,CAAA,CAGGvC,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CACzBoG,CAAAA,CACA,CACE,MAAA,CAAQ,MAAA,CACR,QAAS,CACP,cAAA,CAAgB,mCAClB,CAAA,CACA,IAAA,CAAMC,CAAAA,CAAK,QAAA,EACb,CACF,EACF,OAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,eAAA,CAAiB,kCAAA,CAAoC,CAC1E,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAGA,GAAI,CAACuB,CAAAA,CAAS,GAAI,CAChB,IAAMsG,EAAYtG,CAAAA,CAAS,IAAA,CACrBmH,EAAYb,CAAAA,EAAW,KAAA,CAE7B,OAAQa,CAAAA,EACN,KAAK,uBAAA,CAEH,OAAO,CACL,MAAA,CAAQ,UACR,UAAA,CAAY5E,CAAAA,CAAM,QACpB,CAAA,CAEF,KAAK,WAAA,CAEH,OAAO,CACL,MAAA,CAAQ,WAAA,CACR,WAAYA,CAAAA,CAAM,QAAA,CAAW,CAC/B,CAAA,CAEF,KAAK,eAAA,CAEH,OAAO,CAAE,MAAA,CAAQ,SAAU,EAE7B,KAAK,eAAA,CAEH,OAAO,CAAE,OAAQ,eAAgB,CAAA,CAEnC,QAEE,MAAM,IAAInE,EAAa,4BAAA,CAA8B,kCAAA,CAAoC,CACvF,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,OACjB,KAAA,CAAOmH,CAAAA,CACP,kBAAmBb,CAAAA,EAAW,iBAChC,CACF,CAAC,CACL,CACF,CAGA,IAAMC,CAAAA,CAAgBvG,CAAAA,CAAS,KAGzByG,CAAAA,CAAYF,CAAAA,CAAc,UAAA,CAAatD,CAAAA,CAAMsD,EAAc,UAAA,CAAatD,CAAAA,CAAM,KAWpF,OAAO,CACL,OAAQ,WAAA,CACR,MAAA,CAXuB,CACvB,WAAA,CAAasD,CAAAA,CAAc,aAC3B,SAAA,CAAYA,CAAAA,CAAc,YAA2B,QAAA,CACrD,SAAA,CAAAE,EACA,YAAA,CAAcF,CAAAA,CAAc,aAAA,CAC5B,OAAA,CAASA,EAAc,QAAA,CACvB,KAAA,CAAOA,EAAc,KACvB,CAKA,CACF,CAcA,MAAM,iBAAA,CACJZ,CAAAA,CACApD,EACA/D,CAAAA,CACmB,CACnB,IAAI4I,CAAAA,CAAkB7E,CAAAA,CAAM,SAG5B,OAAa,CAEX,GAAI/D,CAAAA,EAAS,QAAQ,OAAA,CACnB,MAAM,IAAIJ,CAAAA,CAAa,4BAAA,CAA8B,6BAA6B,CAAA,CAGpF,IAAMgH,EAAS,MAAM,IAAA,CAAK,SAASO,CAAAA,CAAWpD,CAAK,EAEnD,OAAQ6C,CAAAA,CAAO,QACb,KAAK,WAAA,CACH,OAAOA,EAAO,MAAA,CAEhB,KAAK,UAEH,MAAM,IAAA,CAAK,MAAMA,CAAAA,CAAO,UAAA,CAAa,GAAA,CAAM5G,CAAAA,EAAS,MAAM,CAAA,CAC1D,SAEF,KAAK,WAAA,CAEH4I,CAAAA,CAAkBhC,EAAO,UAAA,CAEzB7C,CAAAA,CAAM,QAAA,CAAW6E,CAAAA,CACjB,MAAM,IAAA,CAAK,KAAA,CAAMA,EAAkB,GAAA,CAAM5I,CAAAA,EAAS,MAAM,CAAA,CACxD,SAEF,KAAK,SAAA,CACH,MAAM,IAAIJ,CAAAA,CACR,8BAAA,CACA,qEACF,CAAA,CAEF,KAAK,gBACH,MAAM,IAAIA,CAAAA,CACR,sBAAA,CACA,8CACF,CACJ,CACF,CACF,CAOQ,KAAA,CAAMiJ,EAAYC,CAAAA,CAAqC,CAC7D,OAAO,IAAI,QAAQ,CAACC,CAAAA,CAASC,IAAW,CACtC,IAAMC,EAAU,UAAA,CAAWF,CAAAA,CAASF,CAAE,CAAA,CAElCC,GACFA,CAAAA,CAAO,gBAAA,CACL,QACA,IAAM,CACJ,aAAaG,CAAO,CAAA,CACpBD,CAAAA,CAAO,IAAIpJ,EAAa,4BAAA,CAA8B,6BAA6B,CAAC,EACtF,CAAA,CACA,CAAE,IAAA,CAAM,IAAK,CACf,EAEJ,CAAC,CACH,CACF,ECzSO,IAAMsJ,CAAAA,CAAN,KAAkB,CAMvB,WAAA,CACE/G,CAAAA,CACAxC,CAAAA,CACA,CANF,IAAA,CAAQ,OAAA,CAA8B,KACtC,IAAA,CAAQ,WAAA,CAA6B,KAMnC,IAAA,CAAK,MAAA,CAASwC,CAAAA,CACd,IAAA,CAAK,OAASxC,CAAAA,EAAU,GAC1B,CASA,MAAM,YAA4B,CAEhC,GAAI,CAAC,IAAA,CAAK,MAAA,CAAO,oBACf,MAAM,IAAIC,EACR,2BAAA,CACA,qDACF,EAIF,GAAI,IAAA,CAAK,MAAA,CAAO,cAAA,CAAgB,CAC9B,IAAMuJ,CAAAA,CAAW,MAAM,IAAA,CAAK,MAAA,CAAO,gBAAe,CAClD,GAAIA,CAAAA,CAAU,CACZ,KAAK,OAAA,CAAUA,CAAAA,CACf,MACF,CACF,CAGA,GAAI,CACF,IAAA,CAAK,OAAA,CAAU,MAAM,KAAK,MAAA,CAAO,mBAAA,CAC/B,KAAK,MAAA,CAAO,SAAA,EAAa,OAC3B,EACF,CAAA,MAASlJ,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CACR,4BACA,kCAAA,CACA,CAAE,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAAU,CACtD,CACF,CACF,CAKA,aAAA,EAAyB,CACvB,OAAO,IAAA,CAAK,OAAA,GAAY,IAC1B,CAaA,MAAM,aAAA,CACJmJ,CAAAA,CACAC,EACArJ,CAAAA,CACiB,CACjB,GAAI,CAAC,IAAA,CAAK,OAAA,CACR,MAAM,IAAIJ,CAAAA,CACR,6BAAA,CACA,wDACF,CAAA,CAIF,IAAM0J,EAAM,IAAI,GAAA,CAAID,CAAG,CAAA,CACjBE,CAAAA,CAAM,GAAGD,CAAAA,CAAI,QAAQ,KAAKA,CAAAA,CAAI,IAAI,GAAGA,CAAAA,CAAI,QAAQ,CAAA,CAAA,CAGjDxD,CAAAA,CAA0B,CAC9B,GAAA,CAAK,UAAA,CACL,IAAK,IAAA,CAAK,OAAA,CAAQ,UAClB,GAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,YACpB,EAGMrB,CAAAA,CAAM,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,GAAQ,GAAI,CAAA,CAClC+E,CAAAA,CAA0B,CAC9B,IAAK,IAAA,CAAK,WAAA,GACV,GAAA,CAAKJ,CAAAA,CAAO,aAAY,CACxB,GAAA,CAAAG,CAAAA,CACA,GAAA,CAAK9E,CACP,CAAA,CAGIzE,CAAAA,EAAS,kBACXwJ,CAAAA,CAAO,GAAA,CAAMxJ,EAAQ,eAAA,CAAA,CAAA,CAEnBA,CAAAA,EAAS,KAAA,EAAS,IAAA,CAAK,eACzBwJ,CAAAA,CAAO,KAAA,CAAQxJ,GAAS,KAAA,EAAS,IAAA,CAAK,aAAe,MAAA,CAAA,CAIvD,GAAI,CACF,IAAM2F,EAAYnC,CAAAA,CAAkB,IAAA,CAAK,UAAUsC,CAAM,CAAC,EACpD2D,CAAAA,CAAYjG,CAAAA,CAAkB,IAAA,CAAK,SAAA,CAAUgG,CAAM,CAAC,CAAA,CACpDE,EAAe,CAAA,EAAG/D,CAAS,IAAI8D,CAAS,CAAA,CAAA,CAExC5D,EAAY,MAAM,IAAA,CAAK,QAAQ,IAAA,CACnC,IAAI,aAAY,CAAE,MAAA,CAAO6D,CAAY,CACvC,CAAA,CACMC,CAAAA,CAAepH,CAAAA,CAAgBsD,CAAS,CAAA,CAE9C,OAAO,GAAG6D,CAAY,CAAA,CAAA,EAAIC,CAAY,CAAA,CACxC,CAAA,MAAS1J,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CACR,8BACA,+BAAA,CACA,CAAE,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAAU,CACtD,CACF,CACF,CAUA,mBAAA,CAAoBsE,CAAAA,CAAqB,CACvC,IAAA,CAAK,WAAA,CAAcA,EACrB,CAKA,cAAA,EAAgC,CAC9B,OAAO,IAAA,CAAK,WACd,CAKA,gBAAA,EAAyB,CACvB,IAAA,CAAK,WAAA,CAAc,KACrB,CAOA,iBAA8B,CAC5B,OAAO,KAAK,OAAA,EAAS,YAAA,EAAgB,IACvC,CAOA,aAAA,EAA+B,CAC7B,OAAO,KAAK,OAAA,EAAS,UAAA,EAAc,IACrC,CAQA,MAAM,yBAAyBqF,CAAAA,CAAsC,CACnE,IAAMC,CAAAA,CAAO,MAAM,IAAA,CAAK,MAAA,CAAO,OAAOD,CAAW,CAAA,CACjD,OAAOrH,CAAAA,CAAgBsH,CAAI,CAC7B,CAOA,MAAM,OAAuB,CACvB,IAAA,CAAK,OAAO,gBAAA,EACd,MAAM,KAAK,MAAA,CAAO,gBAAA,EAAiB,CAErC,IAAA,CAAK,QAAU,IAAA,CACf,IAAA,CAAK,YAAc,KACrB,CAKQ,aAAsB,CAC5B,OAAI,OAAO,MAAA,CAAW,KAAe,MAAA,CAAO,UAAA,CACnC,OAAO,UAAA,EAAW,CAEpB,GAAG,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,KAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,UAAU,CAAA,CAAG,EAAE,CAAC,CAAA,CACrE,CACF,ECrKO,IAAMC,EAAkB,CAC7B,YAAA,CAAc,gDACd,aAAA,CAAe,gDAAA,CACf,QAAA,CAAU,2CACZ,EC/BO,IAAMC,CAAAA,CAAN,MAAMA,CAAa,CAmCxB,YAAY/J,CAAAA,CAA8B,CAvB1C,IAAA,CAAQ,cAAA,CAA2C,KAGnD,IAAA,CAAQ,SAAA,CAA0C,KAGlD,IAAA,CAAQ,eAAA,CAAwD,KAGhE,IAAA,CAAQ,WAAA,CAAc,IAAA,CAGtB,IAAA,CAAQ,mBAAoC,IAAA,CAY1C,IAAA,CAAK,KAAOA,CAAAA,CAAQ,IAAA,CACpB,KAAK,OAAA,CAAUA,CAAAA,CAAQ,QACvB,IAAA,CAAK,QAAA,CAAWA,EAAQ,QAAA,CACxB,IAAA,CAAK,WAAaA,CAAAA,CAAQ,UAAA,CAC1B,KAAK,YAAA,CAAeA,CAAAA,CAAQ,YAAA,CAC5B,IAAA,CAAK,mBACHA,CAAAA,CAAQ,kBAAA,EAAsB+J,EAAa,4BAAA,CAC7C,IAAA,CAAK,aAAe/J,CAAAA,CAAQ,YAAA,CAC5B,IAAA,CAAK,mBAAA,CAAA,CACFA,EAAQ,wBAAA,EAA4B+J,CAAAA,CAAa,oCAAsC,GAAA,CAC1F,IAAA,CAAK,iBAAmB/J,CAAAA,CAAQ,gBAAA,EAAoB+J,CAAAA,CAAa,2BACnE,CAKA,YAAA,CAAa5C,CAAAA,CAAwC,CACnD,IAAA,CAAK,SAAA,CAAYA,EACnB,CAKA,IAAY,UAAmB,CAC7B,OAAOvD,EAAa,MAAA,CAAO,IAAA,CAAK,WAAY,IAAA,CAAK,YAAY,CAC/D,CAKA,IAAY,UAAA,EAAqB,CAC/B,OAAOA,CAAAA,CAAa,OAAA,CAAQ,KAAK,UAAA,CAAY,IAAA,CAAK,YAAY,CAChE,CAOA,MAAM,SAAA,EAAsC,CAC1C,IAAMqB,CAAAA,CAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,IAAI,IAAA,CAAK,QAAQ,CAAA,CACnD,GAAI,CAACA,CAAAA,CACH,OAAO,KAGT,GAAI,CACF,OAAO,IAAA,CAAK,KAAA,CAAMA,CAAM,CAC1B,CAAA,KAAQ,CAEN,OAAA,MAAM,IAAA,CAAK,aAAY,CAChB,IACT,CACF,CAOA,MAAM,UAAA,CAAW+E,CAAAA,CAAiC,CAChD,MAAM,IAAA,CAAK,QAAQ,GAAA,CAAI,IAAA,CAAK,SAAU,IAAA,CAAK,SAAA,CAAUA,CAAM,CAAC,EAGxDA,CAAAA,CAAO,OAAA,EACT,MAAM,IAAA,CAAK,OAAA,CAAQ,IAAI,IAAA,CAAK,UAAA,CAAYA,CAAAA,CAAO,OAAO,EAIxD,IAAA,CAAK,qBAAA,CAAsBA,EAAO,SAAS,EAC7C,CAOQ,qBAAA,CAAsB/B,CAAAA,CAAyB,CAQrD,GANI,KAAK,eAAA,GACP,YAAA,CAAa,KAAK,eAAe,CAAA,CACjC,KAAK,eAAA,CAAkB,IAAA,CAAA,CAIrB,CAAC,IAAA,CAAK,YACR,OAGF,IAAMgC,EAAchC,CAAAA,CAAY,GAAA,CAC1BiC,EAAcD,CAAAA,CAAc,IAAA,CAAK,mBAAA,CAGjCE,CAAAA,CAAS,KAAK,MAAA,EAAO,CAAI,KAAK,gBAAA,CAAmB,CAAA,CAAI,KAAK,gBAAA,CAC1DC,CAAAA,CAAQF,CAAAA,CAAc,IAAA,CAAK,KAAI,CAAIC,CAAAA,CAGrCC,EAAQ,CAAA,GACV,IAAA,CAAK,gBAAkB,UAAA,CAAW,IAAM,CACtC,IAAM3F,CAAAA,CAAM,KAAK,GAAA,EAAI,CACf4F,EAAY,IAAA,CAAK,GAAA,CAAI,EAAG,IAAA,CAAK,KAAA,CAAA,CAAOJ,CAAAA,CAAcxF,CAAAA,EAAO,GAAI,CAAC,CAAA,CAEpE,KAAK,YAAA,EAAc,IAAA,CAAK,iBAAkB,CACxC,SAAA,CAAAwD,CAAAA,CACA,SAAA,CAAAoC,EACA,SAAA,CAAW5F,CAAAA,CACX,OAAQ,MACV,CAAC,EACH,CAAA,CAAG2F,CAAK,CAAA,EAEZ,CAUA,aAAaE,CAAAA,CAAyB,CACpC,KAAK,WAAA,CAAcA,CAAAA,CAEf,CAACA,CAAAA,EAAY,IAAA,CAAK,kBACpB,YAAA,CAAa,IAAA,CAAK,eAAe,CAAA,CACjC,IAAA,CAAK,gBAAkB,IAAA,EAE3B,CAKA,eAAe9F,CAAAA,CAAkC,CAC/C,IAAA,CAAK,kBAAA,CAAqBA,EAC5B,CAKA,cAAA,EAAgC,CAC9B,OAAO,IAAA,CAAK,kBACd,CAKA,MAAM,WAAA,EAA6B,CACjC,MAAM,IAAA,CAAK,OAAA,CAAQ,OAAO,IAAA,CAAK,QAAQ,EACvC,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,KAAK,UAAU,EAC3C,CAYA,MAAM,cAAA,EAAkC,CACtC,IAAMwF,CAAAA,CAAS,MAAM,IAAA,CAAK,SAAA,GAE1B,GAAI,CAACA,EACH,MAAM,IAAIpK,EAAa,WAAA,CAAa,iDAAiD,CAAA,CAIvF,GAAI,KAAK,aAAA,CAAcoK,CAAM,EAAG,CAC9B,GAAI,CAACA,CAAAA,CAAO,YAAA,CACV,MAAM,IAAIpK,EACR,eAAA,CACA,qDACF,EAEF,OAAO,IAAA,CAAK,gBAAgBoK,CAAAA,CAAO,YAAY,CACjD,CAEA,OAAOA,CAAAA,CAAO,WAChB,CAOA,MAAM,UAAA,EAAqC,CAEzC,OAAA,CADe,MAAM,IAAA,CAAK,SAAA,KACX,OAAA,EAAW,IAC5B,CAQQ,aAAA,CAAcA,CAAAA,CAA2B,CAC/C,IAAMvF,CAAAA,CAAM,IAAA,CAAK,KAAA,CAAM,KAAK,GAAA,EAAI,CAAI,GAAI,CAAA,CACxC,OAAOuF,EAAO,SAAA,CAAY,IAAA,CAAK,kBAAA,EAAsBvF,CACvD,CAYA,MAAc,eAAA,CACZ8F,EACAC,CAAAA,CAA6D,WAAA,CAC5C,CAEjB,GAAI,IAAA,CAAK,cAAA,CAEP,OAAA,CADe,MAAM,IAAA,CAAK,cAAA,EACZ,YAIhB,IAAA,CAAK,cAAA,CAAiB,KAAK,kBAAA,CAAmBD,CAAAA,CAAcC,CAAM,CAAA,CAElE,GAAI,CAEF,OAAA,CADe,MAAM,KAAK,cAAA,EACZ,WAChB,QAAE,CAEA,IAAA,CAAK,cAAA,CAAiB,KACxB,CACF,CAQA,MAAM,SAA6B,CACjC,IAAMR,EAAS,MAAM,IAAA,CAAK,SAAA,EAAU,CACpC,GAAI,CAACA,CAAAA,EAAQ,aACX,MAAM,IAAIpK,EAAa,WAAA,CAAa,4BAA4B,CAAA,CAIlE,GAAI,KAAK,cAAA,CACP,OAAO,KAAK,cAAA,CAGd,IAAA,CAAK,eAAiB,IAAA,CAAK,kBAAA,CAAmBoK,CAAAA,CAAO,YAAA,CAAc,QAAQ,CAAA,CAE3E,GAAI,CACF,OAAO,MAAM,KAAK,cACpB,CAAA,OAAE,CACA,IAAA,CAAK,eAAiB,KACxB,CACF,CAUA,MAAc,kBAAA,CACZO,EACAC,CAAAA,CAA6D,WAAA,CAC7DC,CAAAA,CAAU,CAAA,CACS,CAEnB,IAAM3J,CAAAA,CAAY,KAAK,GAAA,EAAI,CAGvB2J,IAAY,CAAA,EACd,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,mBAAoB,CAC1C,MAAA,CAAAD,EACA,SAAA,CAAA1J,CAAAA,CACA,OAAQ,MAAA,CACR,WAAA,CAAa,KAAK,kBAAA,EAAsB,MAC1C,CAAC,CAAA,CAGH,GAAI,CACF,OAAO,MAAM,KAAK,SAAA,CAAUyJ,CAAY,CAC1C,CAAA,MAAStK,EAAO,CACd,IAAMgC,EAAehC,CAAAA,YAAiBL,CAAAA,CAClCK,EACA,IAAIL,CAAAA,CAAa,eAAA,CAAiB,sBAAA,CAAwB,CACxD,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CAAA,CAECyK,CAAAA,CAAYD,CAAAA,CAAU,CAAA,EAAchK,EAAiBwB,CAAY,CAAA,CAavE,GAVA,IAAA,CAAK,YAAA,EAAc,KAAK,sBAAA,CAAwB,CAC9C,KAAA,CAAOA,CAAAA,CACP,UAAAyI,CAAAA,CACA,OAAA,CAAAD,EACA,SAAA,CAAW,IAAA,CAAK,KAAI,CACpB,MAAA,CAAQ,MAAA,CACR,WAAA,CAAa,KAAK,kBAAA,EAAsB,MAC1C,CAAC,CAAA,CAGGC,CAAAA,CACF,OAAO,IAAA,CAAK,kBAAA,CAAmBH,CAAAA,CAAcC,CAAAA,CAAQC,EAAU,CAAC,CAAA,CAIlE,MAAKhK,CAAAA,CAAiBwB,CAAY,GAChC,IAAA,CAAK,YAAA,EAAc,IAAA,CAAK,eAAA,CAAiB,CACvC,MAAA,CAAQ,gBAAA,CACR,UAAW,IAAA,CAAK,GAAA,GAChB,MAAA,CAAQ,MAAA,CACR,YAAa,IAAA,CAAK,kBAAA,EAAsB,MAC1C,CAAC,CAAA,CAGGhC,CACR,CACF,CAQA,MAAc,SAAA,CAAUsK,CAAAA,CAAyC,CAC/D,GAAI,CAAC,IAAA,CAAK,SAAA,CACR,MAAM,IAAI3K,CAAAA,CAAa,eAAgB,4BAA4B,CAAA,CAGrE,IAAMgI,CAAAA,CAAgB,KAAK,SAAA,CAAU,cAAA,CAG/BC,EAAO,IAAI,eAAA,CAAgB,CAC/B,UAAA,CAAY,eAAA,CACZ,SAAA,CAAW,IAAA,CAAK,SAChB,aAAA,CAAe0C,CACjB,CAAC,CAAA,CAEG/I,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,IAAA,CAAK,MAAqBoG,CAAAA,CAAe,CAC7D,OAAQ,MAAA,CACR,OAAA,CAAS,CACP,cAAA,CAAgB,mCAClB,CAAA,CACA,IAAA,CAAMC,EAAK,QAAA,EACb,CAAC,EACH,CAAA,MAAS5H,EAAO,CACd,IAAMgC,CAAAA,CAAe,IAAIrC,EAAa,eAAA,CAAiB,8BAAA,CAAgC,CACrF,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CAAA,CACD,WAAK,YAAA,EAAc,IAAA,CAAK,cAAe,CACrC,KAAA,CAAOgC,EACP,OAAA,CAAS,SAAA,CACT,UAAW,IAAA,CAAK,GAAA,GAChB,MAAA,CAAQ,MACV,CAAC,CAAA,CAEG,IAAA,CAAK,cACPtB,CAAAA,CAAoB,IAAA,CAAK,YAAA,CAAcsB,CAAAA,CAAc,CAAE,OAAA,CAAS,SAAU,CAAC,CAAA,CAEvEA,CACR,CAEA,GAAI,CAACT,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,EAAS,IAAA,CACrBS,CAAAA,CAAe,IAAIrC,CAAAA,CAAa,eAAA,CAAiB,sBAAA,CAAwB,CAC7E,QAAS,CACP,MAAA,CAAQ4B,EAAS,MAAA,CACjB,KAAA,CAAOsG,GAAW,KAAA,CAClB,iBAAA,CAAmBA,CAAAA,EAAW,iBAChC,CACF,CAAC,CAAA,CACD,WAAK,YAAA,EAAc,IAAA,CAAK,cAAe,CACrC,KAAA,CAAO7F,CAAAA,CACP,OAAA,CAAS,UACT,SAAA,CAAW,IAAA,CAAK,KAAI,CACpB,MAAA,CAAQ,MACV,CAAC,CAAA,CAEG,IAAA,CAAK,YAAA,EACPtB,EAAoB,IAAA,CAAK,YAAA,CAAcsB,EAAc,CAAE,OAAA,CAAS,SAAU,CAAC,CAAA,CAEvEA,CACR,CAEA,IAAM8F,CAAAA,CAAgBvG,CAAAA,CAAS,KAGzBiD,CAAAA,CAAM,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,GAAQ,GAAI,CAAA,CAClCwD,EAAYF,CAAAA,CAAc,UAAA,CAAatD,EAAMsD,CAAAA,CAAc,UAAA,CAAatD,EAAM,IAAA,CAG9EkG,CAAAA,CAAsB,CAC1B,WAAA,CAAa5C,EAAc,YAAA,CAC3B,SAAA,CAAYA,EAAc,UAAA,EAA2B,QAAA,CACrD,UAAAE,CAAAA,CACA,YAAA,CAAcF,CAAAA,CAAc,aAAA,EAAiBwC,EAC7C,OAAA,CAASxC,CAAAA,CAAc,SACvB,KAAA,CAAOA,CAAAA,CAAc,KACvB,CAAA,CAGA,OAAA,MAAM,IAAA,CAAK,UAAA,CAAW4C,CAAS,CAAA,CAG/B,IAAA,CAAK,cAAc,IAAA,CAAK,iBAAA,CAAmB,CACzC,cAAA,CAAgB,CAAC,CAACA,CAAAA,CAAU,WAAA,CAC5B,gBAAiB,CAAC,CAACA,EAAU,YAAA,CAC7B,UAAA,CAAY,CAAC,CAACA,CAAAA,CAAU,OAAA,CACxB,SAAA,CAAWA,EAAU,SAAA,CACrB,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,OAAQ,MAAA,CACR,WAAA,CAAa,IAAA,CAAK,kBAAA,EAAsB,MAC1C,CAAC,CAAA,CAEMA,CACT,CAOA,MAAM,iBAAoC,CACxC,IAAMX,CAAAA,CAAS,MAAM,KAAK,SAAA,EAAU,CACpC,GAAI,CAACA,CAAAA,CACH,OAAO,MAAA,CAIT,IAAMvF,EAAM,IAAA,CAAK,KAAA,CAAM,KAAK,GAAA,EAAI,CAAI,GAAI,CAAA,CACxC,OAAIuF,EAAO,SAAA,EAAavF,CAAAA,CAEf,CAAC,CAACuF,EAAO,YAAA,CAGX,IACT,CAYA,MAAM,aAAA,CAAc5B,EAA6D,CAC/E,GAAI,CAAC,IAAA,CAAK,UACR,MAAM,IAAIxI,EAAa,cAAA,CAAgB,4BAA4B,EAGrE,IAAMgI,CAAAA,CAAgB,IAAA,CAAK,SAAA,CAAU,eAG/BgD,CAAAA,CAAmB,IAAA,CAAK,kBAAkBxC,CAAAA,CAAQ,gBAAA,EAAoB,cAAc,CAAA,CAGpFP,CAAAA,CAAO,IAAI,eAAA,CAAgB,CAC/B,UAAA,CAAY,iDAAA,CACZ,UAAW,IAAA,CAAK,QAAA,CAChB,cAAeO,CAAAA,CAAQ,YAAA,CACvB,kBAAA,CAAoBwC,CACtB,CAAC,CAAA,CAGGxC,CAAAA,CAAQ,UACVP,CAAAA,CAAK,GAAA,CAAI,WAAYO,CAAAA,CAAQ,QAAQ,CAAA,CAEnCA,CAAAA,CAAQ,OACVP,CAAAA,CAAK,GAAA,CAAI,QAASO,CAAAA,CAAQ,KAAK,EAE7BA,CAAAA,CAAQ,kBAAA,EACVP,CAAAA,CAAK,GAAA,CAAI,uBAAwB,IAAA,CAAK,iBAAA,CAAkBO,EAAQ,kBAAkB,CAAC,EAEjFA,CAAAA,CAAQ,UAAA,GACVP,EAAK,GAAA,CAAI,aAAA,CAAeO,EAAQ,UAAU,CAAA,CACtCA,EAAQ,cAAA,EACVP,CAAAA,CAAK,IAAI,kBAAA,CAAoB,IAAA,CAAK,iBAAA,CAAkBO,CAAAA,CAAQ,cAAc,CAAC,CAAA,CAAA,CAI/E,IAAI5G,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,IAAA,CAAK,MAA6BoG,CAAAA,CAAe,CACrE,OAAQ,MAAA,CACR,OAAA,CAAS,CACP,cAAA,CAAgB,mCAClB,CAAA,CACA,IAAA,CAAMC,EAAK,QAAA,EACb,CAAC,EACH,CAAA,MAAS5H,EAAO,CACd,IAAMgC,EAAe,IAAIrC,CAAAA,CAAa,gBAAiB,+BAAA,CAAiC,CACtF,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAC1C,CAAC,CAAA,CACD,MAAA,IAAA,CAAK,cAAc,IAAA,CAAK,aAAA,CAAe,CACrC,KAAA,CAAOgC,CAAAA,CACP,QAAS,UAAA,CACT,SAAA,CAAW,IAAA,CAAK,GAAA,GAChB,MAAA,CAAQ,MACV,CAAC,CAAA,CAEG,IAAA,CAAK,cACPtB,CAAAA,CAAoB,IAAA,CAAK,YAAA,CAAcsB,CAAAA,CAAc,CAAE,OAAA,CAAS,UAAW,CAAC,CAAA,CAExEA,CACR,CAEA,GAAI,CAACT,EAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,KACrBS,CAAAA,CAAe,IAAIrC,EAAa,sBAAA,CAAwB,uBAAA,CAAyB,CACrF,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,OACjB,KAAA,CAAOsG,CAAAA,EAAW,MAClB,iBAAA,CAAmBA,CAAAA,EAAW,iBAChC,CACF,CAAC,CAAA,CACD,MAAA,IAAA,CAAK,cAAc,IAAA,CAAK,aAAA,CAAe,CACrC,KAAA,CAAO7F,CAAAA,CACP,OAAA,CAAS,UAAA,CACT,UAAW,IAAA,CAAK,GAAA,GAChB,MAAA,CAAQ,MACV,CAAC,CAAA,CAEG,IAAA,CAAK,YAAA,EACPtB,CAAAA,CAAoB,KAAK,YAAA,CAAcsB,CAAAA,CAAc,CAAE,OAAA,CAAS,UAAW,CAAC,CAAA,CAExEA,CACR,CAEA,IAAM8F,EAAgBvG,CAAAA,CAAS,IAAA,CAGzBiD,EAAM,IAAA,CAAK,KAAA,CAAM,KAAK,GAAA,EAAI,CAAI,GAAI,CAAA,CAClCwD,EAAYF,CAAAA,CAAc,UAAA,CAAatD,EAAMsD,CAAAA,CAAc,UAAA,CAAatD,EAAM,IAAA,CAE9EuF,CAAAA,CAAmB,CACvB,WAAA,CAAajC,EAAc,YAAA,CAC3B,SAAA,CAAYA,EAAc,UAAA,EAA2B,QAAA,CACrD,UAAAE,CAAAA,CACA,YAAA,CAAcF,EAAc,aAAA,CAC5B,OAAA,CAASA,EAAc,QAAA,CACvB,KAAA,CAAOA,EAAc,KACvB,CAAA,CAEMnB,EAA8B,CAClC,MAAA,CAAAoD,CAAAA,CACA,eAAA,CAAiBjC,EAAc,iBACjC,CAAA,CAGA,YAAK,YAAA,EAAc,IAAA,CAAK,kBAAmB,CACzC,cAAA,CAAgB,CAAC,CAACiC,EAAO,WAAA,CACzB,eAAA,CAAiB,CAAC,CAACA,CAAAA,CAAO,aAC1B,eAAA,CAAiBjC,CAAAA,CAAc,iBAAA,CAC/B,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,OAAQ,MAAA,CACR,WAAA,CAAa,KAAK,kBAAA,EAAsB,MAC1C,CAAC,CAAA,CAEMnB,CACT,CAKQ,iBAAA,CAAkBiE,EAA6D,CACrF,OAAOf,EAAgBe,CAAI,CAC7B,CAKA,OAAA,EAAgB,CACV,IAAA,CAAK,eAAA,GACP,aAAa,IAAA,CAAK,eAAe,EACjC,IAAA,CAAK,eAAA,CAAkB,IAAA,EAE3B,CACF,EAlnBad,CAAAA,CA2Ba,4BAAA,CAA+B,GA3B5CA,CAAAA,CA8Ba,kCAAA,CAAqC,IA9BlDA,CAAAA,CAiCa,0BAAA,CAA6B,GAAA,CAjChD,IAAMe,EAANf,ECqBA,IAAMgB,EAAN,KAAwB,CAI7B,YAAY/K,CAAAA,CAAmC,CAC7C,KAAK,IAAA,CAAOA,CAAAA,CAAQ,KACpB,IAAA,CAAK,QAAA,CAAWA,EAAQ,SAC1B,CAcA,MAAM,UAAA,CACJmH,CAAAA,CACAnH,CAAAA,CACgC,CAChC,IAAMqH,CAAAA,CAAWF,CAAAA,CAAU,uBAE3B,GAAI,CAACE,EACH,MAAM,IAAIzH,CAAAA,CACR,2BAAA,CACA,2DACF,CAAA,CAGF,OAAO,KAAK,sBAAA,CAAuByH,CAAAA,CAAUrH,CAAO,CACtD,CAYA,MAAM,sBAAA,CACJqH,EACArH,CAAAA,CACgC,CAEhC,IAAM6H,CAAAA,CAAO,IAAI,gBAAgB,CAC/B,SAAA,CAAW,IAAA,CAAK,QAAA,CAChB,MAAO7H,CAAAA,CAAQ,KACjB,CAAC,CAAA,CAEGA,CAAAA,CAAQ,eACV6H,CAAAA,CAAK,GAAA,CAAI,iBAAA,CAAmB7H,CAAAA,CAAQ,aAAa,CAAA,CAGnD,IAAIwB,EACJ,GAAI,CACFA,EAAW,MAAM,IAAA,CAAK,IAAA,CAAK,KAAA,CAAkD6F,EAAU,CACrF,MAAA,CAAQ,OACR,OAAA,CAAS,CACP,eAAgB,mCAClB,CAAA,CACA,IAAA,CAAMQ,CAAAA,CAAK,UACb,CAAC,EACH,CAAA,MAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,EAAa,eAAA,CAAiB,oCAAA,CAAsC,CAC5E,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,EAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,KAC3B,MAAM,IAAI5B,CAAAA,CAAa,qBAAA,CAAuB,6BAA8B,CAC1E,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,OACjB,KAAA,CAAOsG,CAAAA,EAAW,KAAA,CAClB,iBAAA,CAAmBA,GAAW,iBAChC,CACF,CAAC,CACH,CAEA,OAAOtG,CAAAA,CAAS,IAClB,CAWA,MAAM,QAAA,CAAS2F,EAAkC6D,CAAAA,CAAiC,CAEhF,QADe,MAAM,IAAA,CAAK,WAAW7D,CAAAA,CAAW,CAAE,KAAA,CAAA6D,CAAM,CAAC,CAAA,EAC3C,MAChB,CACF,ECvIO,IAAMC,EAAN,KAAmB,CAIxB,WAAA,CAAYjL,CAAAA,CAA8B,CACxC,IAAA,CAAK,IAAA,CAAOA,EAAQ,IAAA,CACpB,IAAA,CAAK,SAAWA,CAAAA,CAAQ,SAC1B,CAcA,MAAM,OAAOmH,CAAAA,CAAkCnH,CAAAA,CAA4C,CACzF,IAAMqH,CAAAA,CAAWF,EAAU,mBAAA,CAE3B,GAAI,CAACE,CAAAA,CACH,MAAM,IAAIzH,CAAAA,CACR,wBAAA,CACA,wDACF,CAAA,CAIF,IAAMiI,EAAO,IAAI,eAAA,CAAgB,CAC/B,SAAA,CAAW,KAAK,QAAA,CAChB,KAAA,CAAO7H,EAAQ,KACjB,CAAC,EAEGA,CAAAA,CAAQ,aAAA,EACV6H,CAAAA,CAAK,GAAA,CAAI,kBAAmB7H,CAAAA,CAAQ,aAAa,EAGnD,IAAIwB,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,IAAA,CAAK,KAAK,KAAA,CAAiC6F,CAAAA,CAAU,CACpE,MAAA,CAAQ,MAAA,CACR,QAAS,CACP,cAAA,CAAgB,mCAClB,CAAA,CACA,KAAMQ,CAAAA,CAAK,QAAA,EACb,CAAC,EACH,OAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,EAAa,eAAA,CAAiB,iCAAA,CAAmC,CACzE,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAGA,GAAIuB,CAAAA,CAAS,GACX,OAIF,IAAMsG,EAAYtG,CAAAA,CAAS,IAAA,CAC3B,MAAM,IAAI5B,EAAa,kBAAA,CAAoB,yBAAA,CAA2B,CACpE,OAAA,CAAS,CACP,OAAQ4B,CAAAA,CAAS,MAAA,CACjB,MAAOsG,CAAAA,EAAW,KAAA,CAClB,kBAAmBA,CAAAA,EAAW,iBAChC,CACF,CAAC,CACH,CAWA,MAAM,kBAAA,CAAmBT,CAAAA,CAAkBrH,CAAAA,CAA4C,CAErF,IAAM6H,CAAAA,CAAO,IAAI,eAAA,CAAgB,CAC/B,UAAW,IAAA,CAAK,QAAA,CAChB,KAAA,CAAO7H,CAAAA,CAAQ,KACjB,CAAC,CAAA,CAEGA,EAAQ,aAAA,EACV6H,CAAAA,CAAK,IAAI,iBAAA,CAAmB7H,CAAAA,CAAQ,aAAa,CAAA,CAGnD,IAAIwB,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,KAAA,CAAiC6F,EAAU,CACpE,MAAA,CAAQ,OACR,OAAA,CAAS,CACP,eAAgB,mCAClB,CAAA,CACA,KAAMQ,CAAAA,CAAK,QAAA,EACb,CAAC,EACH,CAAA,MAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,EAAa,eAAA,CAAiB,iCAAA,CAAmC,CACzE,KAAA,CAAOK,aAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAIuB,CAAAA,CAAS,EAAA,CACX,OAGF,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,KAC3B,MAAM,IAAI5B,EAAa,kBAAA,CAAoB,yBAAA,CAA2B,CACpE,OAAA,CAAS,CACP,OAAQ4B,CAAAA,CAAS,MAAA,CACjB,MAAOsG,CAAAA,EAAW,KAAA,CAClB,kBAAmBA,CAAAA,EAAW,iBAChC,CACF,CAAC,CACH,CACF,MCvFaoD,CAAAA,CAAN,KAAoB,CASzB,WAAA,CAAYlL,CAAAA,CAA+B,CACzC,IAAA,CAAK,QAAUA,CAAAA,CAAQ,OAAA,CACvB,KAAK,QAAA,CAAWA,CAAAA,CAAQ,SACxB,IAAA,CAAK,UAAA,CAAaA,CAAAA,CAAQ,UAAA,CAC1B,KAAK,YAAA,CAAeA,CAAAA,CAAQ,aAC5B,IAAA,CAAK,YAAA,CAAeA,EAAQ,YAAA,CAC5B,IAAA,CAAK,SAAA,CAAYA,CAAAA,CAAQ,UACzB,IAAA,CAAK,YAAA,CAAe,IAAIiL,CAAAA,CAAa,CACnC,KAAMjL,CAAAA,CAAQ,IAAA,CACd,QAAA,CAAUA,CAAAA,CAAQ,QACpB,CAAC,EACH,CAcA,MAAM,MAAA,CACJmH,EACAnH,CAAAA,CACuB,CAEvB,IAAMmL,CAAAA,CAAgB,MAAM,IAAA,CAAK,gBAAA,GAC3BC,CAAAA,CAAe,MAAM,KAAK,eAAA,EAAgB,CAG5CC,CAAAA,CACArL,CAAAA,EAAS,cAAgBmH,CAAAA,EAAW,mBAAA,EAAuBiE,IAC7DC,CAAAA,CAAmB,MAAM,KAAK,YAAA,CAAalE,CAAAA,CAAWiE,CAAY,CAAA,CAAA,CAIpE,MAAM,KAAK,WAAA,EAAY,CAGvB,KAAK,YAAA,EAAc,IAAA,CAAK,gBAAiB,CACvC,MAAA,CAAQ,QAAA,CACR,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,OAAQ,MACV,CAAC,EAID,IAAIE,CAAAA,CAUJ,GARI,IAAA,CAAK,WAAW,UAAA,GAAe,MAAA,CAEjCA,EAAqB,IAAA,CAAK,SAAA,CAAU,WAC3BnE,CAAAA,GACTmE,CAAAA,CAAqBnE,CAAAA,CAAU,oBAAA,CAAA,CAI7B,CAACmE,CAAAA,CACH,OAAO,CAAE,SAAA,CAAW,IAAA,CAAM,WAAYD,CAAiB,CAAA,CAIzD,IAAMrF,CAAAA,CAAUhG,CAAAA,EAAS,aAAemL,CAAAA,CAElC7D,CAAAA,CAAS,IAAI,eAAA,CAAgB,CACjC,UAAW,IAAA,CAAK,QAClB,CAAC,CAAA,CAED,OAAItB,CAAAA,EACFsB,CAAAA,CAAO,IAAI,eAAA,CAAiBtB,CAAO,EAEjChG,CAAAA,EAAS,qBAAA,EACXsH,CAAAA,CAAO,GAAA,CAAI,2BAA4BtH,CAAAA,CAAQ,qBAAqB,EAElEA,CAAAA,EAAS,KAAA,EACXsH,EAAO,GAAA,CAAI,OAAA,CAAStH,CAAAA,CAAQ,KAAK,EAG5B,CACL,SAAA,CAAW,GAAGsL,CAAkB,CAAA,CAAA,EAAIhE,EAAO,QAAA,EAAU,GACrD,SAAA,CAAW,KAAA,CACX,WAAY+D,CACd,CACF,CAWA,MAAc,YAAA,CACZlE,EACA6C,CAAAA,CACkD,CAClD,IAAMpD,CAAAA,CAAkD,CACtD,SAAA,CAAW,IACb,EAEA,GAAI,CAEEoD,EAAO,YAAA,GACT,MAAM,IAAA,CAAK,YAAA,CAAa,OAAO7C,CAAAA,CAAW,CACxC,MAAO6C,CAAAA,CAAO,YAAA,CACd,cAAe,eACjB,CAAC,CAAA,CACDpD,CAAAA,CAAO,oBAAsB,CAAA,CAAA,CAAA,CAI/B,MAAM,KAAK,YAAA,CAAa,MAAA,CAAOO,EAAW,CACxC,KAAA,CAAO6C,CAAAA,CAAO,WAAA,CACd,cAAe,cACjB,CAAC,EACDpD,CAAAA,CAAO,kBAAA,CAAqB,GAC9B,CAAA,MAAS3G,CAAAA,CAAO,CACd2G,CAAAA,CAAO,MAAQ3G,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,IAAI,KAAA,CAAM,OAAOA,CAAK,CAAC,EACzE,CAEA,OAAO2G,CACT,CAKA,MAAc,WAAA,EAA6B,CACzC,IAAM2E,CAAAA,CAAW3H,CAAAA,CAAa,MAAA,CAAO,IAAA,CAAK,WAAY,IAAA,CAAK,YAAY,EACjE4H,CAAAA,CAAa5H,CAAAA,CAAa,QAAQ,IAAA,CAAK,UAAA,CAAY,KAAK,YAAY,CAAA,CAE1E,MAAM,IAAA,CAAK,OAAA,CAAQ,OAAO2H,CAAQ,CAAA,CAClC,MAAM,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAOC,CAAU,EACtC,CAKA,MAAc,kBAA2C,CACvD,IAAMA,EAAa5H,CAAAA,CAAa,OAAA,CAAQ,IAAA,CAAK,UAAA,CAAY,KAAK,YAAY,CAAA,CAC1E,OAAO,IAAA,CAAK,OAAA,CAAQ,IAAI4H,CAAU,CACpC,CAKA,MAAc,iBAA4C,CACxD,IAAMD,EAAW3H,CAAAA,CAAa,MAAA,CAAO,KAAK,UAAA,CAAY,IAAA,CAAK,YAAY,CAAA,CACjEqB,EAAS,MAAM,IAAA,CAAK,QAAQ,GAAA,CAAIsG,CAAQ,EAC9C,GAAI,CAACtG,CAAAA,CACH,OAAO,KAET,GAAI,CACF,OAAO,IAAA,CAAK,KAAA,CAAMA,CAAM,CAC1B,CAAA,KAAQ,CACN,OAAO,IACT,CACF,CACF,EClNO,IAAMwG,CAAAA,CAAN,KAAqB,CAG1B,WAAA,CAAYzL,CAAAA,CAAgC,CAC1C,KAAK,IAAA,CAAOA,CAAAA,CAAQ,KACtB,CASA,MAAM,aACJmH,CAAAA,CACAyC,CAAAA,CAC6B,CAC7B,IAAM8B,CAAAA,CAAmBvE,EAAU,iBAAA,CAEnC,GAAI,CAACuE,CAAAA,CACH,OAAO,CACL,KAAA,CAAO,KAAA,CACP,KAAA,CAAO,IAAI9L,EAAa,sBAAA,CAAwB,iCAAiC,CACnF,CAAA,CAGF,GAAI,CACF,IAAM4B,CAAAA,CAAW,MAAM,IAAA,CAAK,KAAK,KAAA,CAAgBkK,CAAAA,CAAkB,CACjE,MAAA,CAAQ,KAAA,CACR,QAAS,CACP,aAAA,CAAe,CAAA,OAAA,EAAU9B,CAAW,EACtC,CACF,CAAC,EAED,OAAKpI,CAAAA,CAAS,GAiBP,CACL,KAAA,CAAO,CAAA,CAAA,CACP,IAAA,CAAMA,EAAS,IACjB,CAAA,CAlBMA,EAAS,MAAA,GAAW,GAAA,CACf,CACL,KAAA,CAAO,CAAA,CAAA,CACP,KAAA,CAAO,IAAI5B,EAAa,iBAAA,CAAmB,qBAAqB,CAClE,CAAA,CAGK,CACL,MAAO,CAAA,CAAA,CACP,KAAA,CAAO,IAAIA,CAAAA,CAAa,uBAAwB,sBAAA,CAAwB,CACtE,QAAS,CAAE,MAAA,CAAQ4B,EAAS,MAAO,CACrC,CAAC,CACH,CAOJ,CAAA,MAASvB,CAAAA,CAAO,CACd,OAAO,CACL,MAAO,KAAA,CACP,KAAA,CAAO,IAAIL,CAAAA,CAAa,eAAA,CAAiB,0BAA2B,CAClE,KAAA,CAAOK,aAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CACF,CACF,CAUA,MAAM,WAAA,CAAYkH,EAAkCyC,CAAAA,CAAwC,CAC1F,IAAM8B,CAAAA,CAAmBvE,CAAAA,CAAU,iBAAA,CAEnC,GAAI,CAACuE,CAAAA,CACH,MAAM,IAAI9L,CAAAA,CAAa,sBAAA,CAAwB,iCAAiC,CAAA,CAGlF,IAAI4B,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,KAAA,CAAgBkK,EAAkB,CAC3D,MAAA,CAAQ,MACR,OAAA,CAAS,CACP,cAAe,CAAA,OAAA,EAAU9B,CAAW,EACtC,CACF,CAAC,EACH,CAAA,MAAS3J,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,eAAA,CAAiB,4BAA6B,CACnE,KAAA,CAAOK,aAAiB,KAAA,CAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,CAAAA,CAAS,EAAA,CACZ,MAAM,IAAI5B,CAAAA,CAAa,gBAAA,CAAkB,yBAAA,CAA2B,CAClE,OAAA,CAAS,CAAE,OAAQ4B,CAAAA,CAAS,MAAO,CACrC,CAAC,CAAA,CAGH,OAAOA,CAAAA,CAAS,IAClB,CACF,ECjHO,IAAMmK,EAAN,KAAqB,CAO1B,YAAY3L,CAAAA,CAAgC,CAF5C,IAAA,CAAQ,SAAA,CAA0C,KAGhD,IAAA,CAAK,YAAA,CAAeA,EAAQ,YAAA,CAC5B,IAAA,CAAK,eAAiBA,CAAAA,CAAQ,eAChC,CAKA,YAAA,CAAamH,EAAwC,CACnD,IAAA,CAAK,UAAYA,EACnB,CAUA,MAAM,eAAA,EAAoC,CACxC,OAAO,IAAA,CAAK,aAAa,eAAA,EAC3B,CASA,MAAM,YAAA,EAA4C,CAChD,GAAI,CAAC,IAAA,CAAK,SAAA,CACR,OAAO,CACL,KAAA,CAAO,MACP,KAAA,CAAO,IAAIvH,EAAa,cAAA,CAAgB,kCAAkC,CAC5E,CAAA,CAGF,GAAI,CACF,IAAMgK,EAAc,MAAM,IAAA,CAAK,aAAa,cAAA,EAAe,CAC3D,OAAO,IAAA,CAAK,eAAe,YAAA,CAAa,IAAA,CAAK,UAAWA,CAAW,CACrE,OAAS3J,CAAAA,CAAO,CACd,OAAIA,CAAAA,YAAiBL,EACZ,CAAE,KAAA,CAAO,MAAO,KAAA,CAAAK,CAAM,EAExB,CACL,KAAA,CAAO,MACP,KAAA,CAAO,IAAIL,EAAa,sBAAA,CAAwB,yBAAA,CAA2B,CACzE,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CACF,CACF,CAUA,MAAM,OAAA,EAA6B,CACjC,GAAI,CAAC,IAAA,CAAK,SAAA,CACR,MAAM,IAAIL,CAAAA,CAAa,cAAA,CAAgB,kCAAkC,CAAA,CAG3E,IAAMgK,EAAc,MAAM,IAAA,CAAK,YAAA,CAAa,cAAA,GAC5C,OAAO,IAAA,CAAK,eAAe,WAAA,CAAY,IAAA,CAAK,UAAWA,CAAW,CACpE,CACF,ECvDA,eAAegC,GACbzJ,CAAAA,CACAiD,CAAAA,CACAyG,EAAS,EAAA,CACQ,CACjB,IAAMhC,CAAAA,CAAO,MAAM1H,CAAAA,CAAO,MAAA,CAAOiD,CAAK,CAAA,CACtC,OAAO7C,EAAgBsH,CAAI,CAAA,CAAE,MAAM,CAAA,CAAGgC,CAAM,CAC9C,KAKaC,CAAAA,CAAN,KAAoB,CAsEzB,WAAA,CAAYnM,CAAAA,CAA6B,CA5CzC,IAAA,CAAQ,WAAA,CAAkC,IAAA,CA2B1C,IAAA,CAAQ,YAAc,KAAA,CAGtB,IAAA,CAAQ,iBAA6C,IAAA,CAenD,IAAA,CAAK,OAASD,CAAAA,CAAcC,CAAM,EAClC,IAAA,CAAK,gBAAA,CAAmBsB,EAAgBtB,CAAAA,CAAO,MAAM,EAGrD,IAAA,CAAK,MAAA,CAAS,IAAIgC,CAAAA,CAElB,IAAA,CAAK,eAAA,CAAkB,IAAID,EAAgB,CACzC,IAAA,CAAM,KAAK,MAAA,CAAO,IAAA,CAClB,WAAY,IAAA,CAAK,MAAA,CAAO,mBAC1B,CAAC,EAED,IAAA,CAAK,IAAA,CAAO,IAAIQ,CAAAA,CAAW,IAAA,CAAK,OAAO,MAAM,CAAA,CAE7C,IAAA,CAAK,YAAA,CAAe,IAAI6E,CAAAA,CAAsB,IAAA,CAAK,OAAO,IAAA,CAAM,IAAA,CAAK,OAAO,QAAQ,CAAA,CAEpF,IAAA,CAAK,SAAA,CAAY,IAAIoB,CAAAA,CAAU,IAAA,CAAK,OAAO,IAAA,CAAM,IAAA,CAAK,OAAO,QAAQ,CAAA,CAErE,IAAA,CAAK,gBAAA,CAAmB,IAAIO,CAAAA,CAAiB,IAAA,CAAK,OAAO,IAAA,CAAM,IAAA,CAAK,OAAO,QAAQ,EACrF,CA5BA,IAAI,cAA6B,CAC/B,OAAO,KAAK,MACd,CAiCA,MAAM,UAAA,EAA4B,CAChC,GAAI,IAAA,CAAK,YACP,OAIF,IAAMqD,EAAa,IAAA,CAAK,MAAA,CAAO,YAAY,UAAA,CAC3C,IAAA,CAAK,WAAa,MAAMH,EAAAA,CAAW,KAAK,MAAA,CAAO,MAAA,CAAQ,KAAK,gBAAA,CAAkBG,CAAU,EACxF,IAAA,CAAK,YAAA,CAAe,MAAMH,EAAAA,CAAW,KAAK,MAAA,CAAO,MAAA,CAAQ,KAAK,MAAA,CAAO,QAAA,CAAUG,CAAU,CAAA,CAGzF,IAAA,CAAK,YAAA,CAAe,IAAIxG,EACtB,IAAA,CAAK,MAAA,CAAO,OACZ,IAAA,CAAK,MAAA,CAAO,QACZ,IAAA,CAAK,UAAA,CACL,IAAA,CAAK,YACP,EAGA,IAAA,CAAK,YAAA,CAAe,IAAIuF,CAAAA,CAAa,CACnC,KAAM,IAAA,CAAK,MAAA,CAAO,KAClB,OAAA,CAAS,IAAA,CAAK,OAAO,OAAA,CACrB,QAAA,CAAU,KAAK,MAAA,CAAO,QAAA,CACtB,WAAY,IAAA,CAAK,UAAA,CACjB,YAAA,CAAc,IAAA,CAAK,aACnB,kBAAA,CAAoB,IAAA,CAAK,OAAO,kBAAA,CAChC,YAAA,CAAc,KAAK,MACrB,CAAC,CAAA,CAGD,IAAA,CAAK,cAAgB,IAAII,CAAAA,CAAc,CACrC,OAAA,CAAS,IAAA,CAAK,OAAO,OAAA,CACrB,IAAA,CAAM,IAAA,CAAK,MAAA,CAAO,KAClB,QAAA,CAAU,IAAA,CAAK,OAAO,QAAA,CACtB,UAAA,CAAY,KAAK,UAAA,CACjB,YAAA,CAAc,KAAK,YAAA,CACnB,YAAA,CAAc,KAAK,MAAA,CACnB,SAAA,CAAW,KAAK,MAAA,CAAO,SACzB,CAAC,CAAA,CAGD,IAAA,CAAK,iBAAA,CAAoB,IAAIH,EAAkB,CAC7C,IAAA,CAAM,KAAK,MAAA,CAAO,IAAA,CAClB,SAAU,IAAA,CAAK,MAAA,CAAO,QACxB,CAAC,EAGD,IAAA,CAAK,YAAA,CAAe,IAAIE,CAAAA,CAAa,CACnC,KAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAClB,QAAA,CAAU,KAAK,MAAA,CAAO,QACxB,CAAC,CAAA,CAGD,IAAMe,EAAiB,IAAIP,CAAAA,CAAe,CACxC,IAAA,CAAM,KAAK,MAAA,CAAO,IACpB,CAAC,CAAA,CAGD,IAAA,CAAK,eAAiB,IAAIE,CAAAA,CAAe,CACvC,YAAA,CAAc,KAAK,YAAA,CACnB,cAAA,CAAAK,CACF,CAAC,CAAA,CAGD,MAAM,IAAA,CAAK,YAAA,CAAa,oBAAA,EAAqB,CAE7C,KAAK,WAAA,CAAc,KACrB,CAKQ,iBAAA,EAA0B,CAChC,GAAI,CAAC,IAAA,CAAK,WAAA,CACR,MAAM,IAAIpM,CAAAA,CACR,iBAAA,CACA,oDACF,CAEJ,CAOA,MAAM,QAAA,EAA2C,CAC/C,IAAMuH,CAAAA,CAAY,MAAM,KAAK,eAAA,CAAgB,QAAA,CAAS,KAAK,gBAAgB,CAAA,CAG3E,YAAK,YAAA,CAAa,YAAA,CAAaA,CAAS,CAAA,CACxC,KAAK,cAAA,CAAe,YAAA,CAAaA,CAAS,CAAA,CAEnCA,CACT,CAeA,MAAM,qBAAA,CACJnH,CAAAA,CACiC,CACjC,KAAK,iBAAA,EAAkB,CAEvB,IAAMmH,CAAAA,CAAY,MAAM,KAAK,QAAA,EAAS,CAGhC8E,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,YAAA,GAG3B1E,CAAAA,CAAQvH,CAAAA,CAAQ,OAAS,gBAAA,CAGzB0E,CAAAA,CAAY,MAAM,IAAA,CAAK,aAAa,iBAAA,CAAkB,CAC1D,YAAa1E,CAAAA,CAAQ,WAAA,CACrB,aAAciM,CAAAA,CAAS,YAAA,CACvB,KAAA,CAAA1E,CAAAA,CACA,WAAY,IAAA,CAAK,MAAA,CAAO,eAC1B,CAAC,CAAA,CAGKX,EAAS,IAAA,CAAK,YAAA,CAAa,qBAAA,CAAsBO,CAAAA,CAAWzC,EAAWuH,CAAAA,CAAUjM,CAAO,EAG9F,OAAA,IAAA,CAAK,MAAA,CAAO,KAAK,kBAAA,CAAoB,CACnC,GAAA,CAAK4G,CAAAA,CAAO,IACZ,SAAA,CAAW,IAAA,CAAK,KAAI,CACpB,MAAA,CAAQ,OACR,WAAA,CAAalC,CAAAA,CAAU,WACzB,CAAC,CAAA,CAEMkC,CACT,CAWA,MAAM,eAAea,CAAAA,CAAwC,CAC3D,KAAK,iBAAA,EAAkB,CAGvB,GAAM,CAAE,KAAA3H,CAAAA,CAAM,KAAA,CAAAiE,CAAM,CAAA,CAAI,IAAA,CAAK,aAAa,aAAA,CAAc0D,CAAW,CAAA,CAG7D/C,CAAAA,CAAY,MAAM,IAAA,CAAK,YAAA,CAAa,wBAAwBX,CAAK,CAAA,CACjES,EAAcE,CAAAA,CAAU,WAAA,CAG9B,IAAA,CAAK,MAAA,CAAO,KAAK,eAAA,CAAiB,CAChC,KAAA5E,CAAAA,CACA,KAAA,CAAAiE,EACA,SAAA,CAAW,IAAA,CAAK,GAAA,EAAI,CACpB,OAAQ,MAAA,CACR,WAAA,CAAAS,CACF,CAAC,CAAA,CAGD,KAAK,MAAA,CAAO,IAAA,CAAK,0BAAA,CAA4B,CAC3C,MAAAT,CAAAA,CACA,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,OAAQ,MAAA,CACR,WAAA,CAAAS,CACF,CAAC,EAED,GAAI,CAEF,IAAM2C,CAAAA,CAAY,MAAM,KAAK,QAAA,EAAS,CAGhC6C,CAAAA,CAAS,MAAM,KAAK,YAAA,CAAa,YAAA,CAAa7C,EAAW,CAC7D,IAAA,CAAArH,EACA,KAAA,CAAAiE,CAAAA,CACA,YAAaW,CAAAA,CAAU,WAAA,CACvB,aAAcA,CAAAA,CAAU,YAAA,CACxB,MAAOA,CAAAA,CAAU,KAAA,CACjB,MAAOA,CAAAA,CAAU,KACnB,CAAC,CAAA,CAGD,aAAM,IAAA,CAAK,YAAA,CAAa,WAAWsF,CAAM,CAAA,CAGzC,KAAK,MAAA,CAAO,IAAA,CAAK,wBAAA,CAA0B,CACzC,QAAS,CAAA,CAAA,CACT,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,OAAQ,MAAA,CACR,WAAA,CAAAxF,CACF,CAAC,EAEMwF,CACT,CAAA,MAAS/J,EAAO,CAEd,MAAA,IAAA,CAAK,OAAO,IAAA,CAAK,wBAAA,CAA0B,CACzC,OAAA,CAAS,KAAA,CACT,UAAW,IAAA,CAAK,GAAA,GAChB,MAAA,CAAQ,MAAA,CACR,YAAAuE,CACF,CAAC,CAAA,CACKvE,CACR,CACF,CAaA,IAAI,KAAM,CACR,OAAO,CAOL,IAAA,CAAM,MAAOD,CAAAA,EAA8D,CACzE,KAAK,iBAAA,EAAkB,CACvB,IAAMmH,CAAAA,CAAY,MAAM,KAAK,QAAA,EAAS,CAGhC8E,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,YAAA,GAC3B1E,CAAAA,CAAQvH,CAAAA,CAAQ,OAAS,gBAAA,CACzB0E,CAAAA,CAAY,MAAM,IAAA,CAAK,YAAA,CAAa,kBAAkB,CAC1D,WAAA,CAAa1E,EAAQ,WAAA,CACrB,YAAA,CAAciM,EAAS,YAAA,CACvB,KAAA,CAAA1E,CAAAA,CACA,UAAA,CAAY,KAAK,MAAA,CAAO,eAC1B,CAAC,CAAA,CAGD,OAAO,KAAK,SAAA,CAAU,wBAAA,CAAyBJ,CAAAA,CAAW,CACxD,YAAanH,CAAAA,CAAQ,WAAA,CACrB,MAAAuH,CAAAA,CACA,KAAA,CAAO7C,EAAU,KAAA,CACjB,KAAA,CAAOA,CAAAA,CAAU,KAAA,CACjB,cAAeuH,CAAAA,CAAS,aAAA,CACxB,oBAAqB,MAAA,CACrB,MAAA,CAAQjM,EAAQ,MAAA,CAChB,SAAA,CAAWA,CAAAA,CAAQ,SAAA,CACnB,UAAWA,CAAAA,CAAQ,SAAA,CACnB,YAAaA,CAAAA,CAAQ,WACvB,CAAC,CACH,CAAA,CAQA,qBAAA,CAAuB,MAAOwI,GAAwC,CACpE,IAAMrB,EAAY,MAAM,IAAA,CAAK,UAAS,CACtC,OAAO,IAAA,CAAK,SAAA,CAAU,6BAA6BA,CAAAA,CAAWqB,CAAU,CAC1E,CAAA,CAOA,WAAA,CAAa,SAEJ,CAAC,CAAA,CADU,MAAM,IAAA,CAAK,UAAS,EACnB,qCAAA,CAQrB,WAAY,SAAA,CACQ,MAAM,KAAK,QAAA,EAAS,EACrB,wCAA0C,IAE/D,CACF,CAYA,IAAI,UAAA,EAAa,CACf,OAAO,CAOL,MAAO,MAAOxI,CAAAA,EAA+D,CAC3E,IAAA,CAAK,mBAAkB,CACvB,IAAMmH,EAAY,MAAM,IAAA,CAAK,UAAS,CACtC,OAAO,IAAA,CAAK,gBAAA,CAAiB,yBAAyBA,CAAAA,CAAWnH,CAAO,CAC1E,CAAA,CAQA,QAAA,CAAU,MAAO+D,CAAAA,EAA0D,CACzE,IAAMoD,CAAAA,CAAY,MAAM,IAAA,CAAK,QAAA,GAC7B,OAAO,IAAA,CAAK,iBAAiB,QAAA,CAASA,CAAAA,CAAWpD,CAAK,CACxD,CAAA,CASA,kBAAmB,MACjBA,CAAAA,CACA/D,IACsB,CACtB,IAAMmH,EAAY,MAAM,IAAA,CAAK,QAAA,EAAS,CAChC6C,EAAS,MAAM,IAAA,CAAK,iBAAiB,iBAAA,CAAkB7C,CAAAA,CAAWpD,EAAO/D,CAAO,CAAA,CAGtF,OAAA,MAAM,IAAA,CAAK,aAAa,UAAA,CAAWgK,CAAM,EAElCA,CACT,CAAA,CAOA,YAAa,SAEJ,CAAC,CAAA,CADU,MAAM,KAAK,QAAA,EAAS,EACnB,6BAEvB,CACF,CAkBA,IAAI,IAAA,EAAO,CAGT,GAAI,CADmB,IAAA,CAAK,OAAO,MAAA,CACf,mBAAA,CAClB,OAIG,IAAA,CAAK,WAAA,GAER,KAAK,WAAA,CAAc,IAAId,CAAAA,CACrB,IAAA,CAAK,OAAO,MACd,CAAA,CAAA,CAGF,IAAMgD,CAAAA,CAAU,IAAA,CAAK,YAErB,OAAO,CAIL,UAAA,CAAY,IAAMA,EAAQ,UAAA,EAAW,CAKrC,cAAe,IAAMA,CAAAA,CAAQ,eAAc,CAU3C,aAAA,CAAe,CACb9C,CAAAA,CACAC,EACArJ,CAAAA,GACGkM,CAAAA,CAAQ,cAAc9C,CAAAA,CAAQC,CAAAA,CAAKrJ,CAAO,CAAA,CAO/C,mBAAA,CAAsBuE,CAAAA,EAAkB2H,CAAAA,CAAQ,oBAAoB3H,CAAK,CAAA,CAQzE,yBAA2BqF,CAAAA,EACzBsC,CAAAA,CAAQ,yBAAyBtC,CAAW,CAAA,CAK9C,eAAA,CAAiB,IAAMsC,EAAQ,eAAA,EAAgB,CAK/C,cAAe,IAAMA,CAAAA,CAAQ,eAAc,CAK3C,KAAA,CAAO,IAAMA,CAAAA,CAAQ,OAAM,CAO3B,iBAAA,CAAmB,SAA8B,CAC/C,IAAM/E,EAAY,MAAM,IAAA,CAAK,QAAA,EAAS,CACtC,OAAO,KAAA,CAAM,OAAA,CAAQA,EAAU,iCAAiC,CAAA,EAC9DA,EAAU,iCAAA,CAAkC,MAAA,CAAS,CACzD,CACF,CACF,CASA,IAAI,KAAA,EAAQ,CACV,OAAA,IAAA,CAAK,iBAAA,GACE,CAIL,cAAA,CAAgB,IAAM,IAAA,CAAK,aAAa,cAAA,EAAe,CAKvD,UAAW,IAAM,IAAA,CAAK,aAAa,SAAA,EAAU,CAK7C,UAAA,CAAY,IAAM,KAAK,YAAA,CAAa,UAAA,GAKpC,eAAA,CAAiB,IAAM,KAAK,YAAA,CAAa,eAAA,EAAgB,CAczD,QAAA,CAAU,MAAOiB,CAAAA,GAEf,MAAM,KAAK,QAAA,EAAS,CACb,KAAK,YAAA,CAAa,aAAA,CAAcA,CAAO,CAAA,CAAA,CAahD,UAAA,CAAY,MAAOpI,CAAAA,EAAoE,CACrF,IAAMmH,CAAAA,CAAY,MAAM,KAAK,QAAA,EAAS,CACtC,OAAO,IAAA,CAAK,kBAAkB,UAAA,CAAWA,CAAAA,CAAWnH,CAAO,CAC7D,CAAA,CAWA,OAAQ,MAAOA,CAAAA,EAA+C,CAC5D,IAAMmH,EAAY,MAAM,IAAA,CAAK,UAAS,CACtC,OAAO,KAAK,YAAA,CAAa,MAAA,CAAOA,CAAAA,CAAWnH,CAAO,CACpD,CACF,CACF,CASA,IAAI,OAAA,EAAU,CACZ,OAAA,IAAA,CAAK,iBAAA,GACE,CAIL,eAAA,CAAiB,IAAM,IAAA,CAAK,cAAA,CAAe,iBAAgB,CAK3D,KAAA,CAAO,IAAM,IAAA,CAAK,cAAA,CAAe,YAAA,EACnC,CACF,CAOA,MAAM,iBAAoC,CACxC,OAAA,IAAA,CAAK,mBAAkB,CAChB,IAAA,CAAK,YAAA,CAAa,eAAA,EAC3B,CAOA,MAAM,SAA6B,CACjC,OAAA,IAAA,CAAK,mBAAkB,CAChB,IAAA,CAAK,cAAA,CAAe,OAAA,EAC7B,CAcA,MAAM,OAAOA,CAAAA,CAAgD,CAC3D,KAAK,iBAAA,EAAkB,CAEvB,IAAImH,CAAAA,CAA0C,KAC9C,GAAI,CACFA,EAAY,MAAM,IAAA,CAAK,WACzB,CAAA,KAAQ,CAER,CAEA,OAAO,IAAA,CAAK,aAAA,CAAc,OAAOA,CAAAA,CAAWnH,CAAO,CACrD,CAcA,mBAAA,CAAoBkH,CAAAA,CAAwC,CAC1D,KAAK,gBAAA,CAAmBA,CAAAA,CAGxB,KAAK,YAAA,CAAa,mBAAA,CAAoBA,CAAM,EAC9C,CAUA,sBAAA,EAAwC,CACtC,OAAO,IAAA,CAAK,gBAAA,EAAkB,wBAAuB,EAAK,IAC5D,CAaA,EAAA,CAA+BtF,CAAAA,CAAUC,EAA6C,CACpF,OAAO,KAAK,MAAA,CAAO,EAAA,CAAGD,EAAOC,CAAO,CACtC,CASA,IAAA,CAAiCD,CAAAA,CAAUC,CAAAA,CAA6C,CACtF,OAAO,IAAA,CAAK,MAAA,CAAO,KAAKD,CAAAA,CAAOC,CAAO,CACxC,CAQA,GAAA,CAAgCD,CAAAA,CAAUC,CAAAA,CAAuC,CAC/E,IAAA,CAAK,MAAA,CAAO,IAAID,CAAAA,CAAOC,CAAO,EAChC,CACF,EAWA,eAAsBsK,EAAAA,CAAoBxM,EAAqD,CAC7F,IAAMyM,EAAS,IAAIN,CAAAA,CAAcnM,CAAM,CAAA,CACvC,OAAA,MAAMyM,CAAAA,CAAO,UAAA,GACNA,CACT,KC1wBMC,EAAAA,CAAoC,IAAI,IAAI,CAChD,gBAAA,CACA,sBAAA,CACA,kBAAA,CACA,4BACF,CAAC,CAAA,CAQYC,EAAN,KAAwB,CAC7B,YAA6BrF,CAAAA,CAAkB,CAAlB,IAAA,CAAA,QAAA,CAAAA,EAAmB,CAahD,kBAAA,CACEE,CAAAA,CACAzC,EACA0C,CAAAA,CACApH,CAAAA,CACqB,CACrB,IAAMqH,CAAAA,CAAWF,CAAAA,CAAU,sBAAA,CACrBG,EAAS,IAAI,eAAA,CAGnBA,EAAO,GAAA,CAAI,WAAA,CAAa,KAAK,QAAQ,CAAA,CACrCA,EAAO,GAAA,CAAI,eAAA,CAAiBtH,EAAQ,YAAA,EAAgB,MAAM,EAC1DsH,CAAAA,CAAO,GAAA,CAAI,eAAgBtH,CAAAA,CAAQ,WAAW,CAAA,CAC9CsH,CAAAA,CAAO,IAAI,OAAA,CAAS5C,CAAAA,CAAU,KAAK,CAAA,CACnC4C,CAAAA,CAAO,IAAI,OAAA,CAAS5C,CAAAA,CAAU,KAAK,CAAA,CAGnC4C,EAAO,GAAA,CAAI,QAAA,CAAU,MAAM,CAAA,CAG3BA,CAAAA,CAAO,IAAI,gBAAA,CAAkBF,CAAAA,CAAK,aAAa,CAAA,CAC/CE,EAAO,GAAA,CAAI,uBAAA,CAAyBF,EAAK,mBAAmB,CAAA,CAG5D,IAAMG,CAAAA,CAAQvH,CAAAA,CAAQ,KAAA,EAAS,QAAA,CAY/B,GAXAsH,CAAAA,CAAO,GAAA,CAAI,QAASC,CAAK,CAAA,CAGrBvH,EAAQ,SAAA,EACVsH,CAAAA,CAAO,GAAA,CAAI,YAAA,CAActH,EAAQ,SAAS,CAAA,CAExCA,EAAQ,WAAA,EACVsH,CAAAA,CAAO,IAAI,eAAA,CAAiBtH,CAAAA,CAAQ,WAAW,CAAA,CAI7CA,EAAQ,WAAA,CAAa,CACvB,IAAMwH,CAAAA,CAAkB,IAAI,IAAI,CAC9B,WAAA,CACA,eAAA,CACA,cAAA,CACA,QACA,OAAA,CACA,gBAAA,CACA,wBACA,OAAA,CACA,QACF,CAAC,CAAA,CAED,IAAA,GAAW,CAAC7C,CAAAA,CAAKS,CAAK,IAAK,MAAA,CAAO,OAAA,CAAQpF,EAAQ,WAAW,CAAA,CACvDwH,EAAgB,GAAA,CAAI7C,CAAAA,CAAI,WAAA,EAAa,GAGzC2C,CAAAA,CAAO,GAAA,CAAI3C,EAAKS,CAAK,EAEzB,CAIA,IAAMwB,CAAAA,CAA8B,CAAE,GAAA,CAF1B,GAAGS,CAAQ,CAAA,CAAA,EAAIC,EAAO,QAAA,EAAU,EAEF,CAAA,CAE1C,OAAItH,CAAAA,CAAQ,WAAA,GACV4G,EAAO,KAAA,CAAQlC,CAAAA,CAAU,MACzBkC,CAAAA,CAAO,KAAA,CAAQlC,EAAU,KAAA,CAAA,CAGpBkC,CACT,CAWA,uBAAA,CAAwB2F,CAAAA,CAOtB,CACA,IAAI7E,CAAAA,CAGA6E,EAAY,QAAA,CAAS,GAAG,EAI1B7E,CAAAA,CAAAA,CAHY6E,CAAAA,CAAY,UAAA,CAAW,MAAM,EACrC,IAAI,GAAA,CAAIA,CAAW,CAAA,CACnB,IAAI,IAAIA,CAAAA,CAAa,qBAAqB,CAAA,EAC3B,YAAA,CAEnB7E,EAAe,IAAI,eAAA,CAAgB6E,CAAW,CAAA,CAIhD,IAAMtM,EAAQyH,CAAAA,CAAa,GAAA,CAAI,OAAO,CAAA,CACtC,GAAIzH,CAAAA,CAAO,CACT,IAAM0H,CAAAA,CAAmBD,CAAAA,CAAa,IAAI,mBAAmB,CAAA,CACvDiB,EAAY,IAAA,CAAK,kBAAA,CAAmB1I,CAAK,CAAA,CAE/C,OAAO,CACL,OAAA,CAAS,KAAA,CACT,MAAO,IAAIL,CAAAA,CAAa+I,CAAAA,CAAWhB,CAAAA,EAAoB,KAAK,sBAAA,CAAuB1H,CAAK,EAAG,CACzF,OAAA,CAAS,CACP,KAAA,CAAAA,CAAAA,CACA,iBAAA,CAAmB0H,CAAAA,CACnB,UAAWD,CAAAA,CAAa,GAAA,CAAI,WAAW,CACzC,CACF,CAAC,CACH,CACF,CAGA,IAAM5H,EAAO4H,CAAAA,CAAa,GAAA,CAAI,MAAM,CAAA,CAC9B3D,CAAAA,CAAQ2D,EAAa,GAAA,CAAI,OAAO,CAAA,CAEtC,OAAK5H,EAMAiE,CAAAA,CAOE,CAAE,QAAS,IAAA,CAAM,IAAA,CAAAjE,EAAM,KAAA,CAAAiE,CAAM,CAAA,CAN3B,CACL,QAAS,KAAA,CACT,KAAA,CAAO,IAAInE,CAAAA,CAAa,eAAA,CAAiB,mDAAmD,CAC9F,CAAA,CATO,CACL,OAAA,CAAS,MACT,KAAA,CAAO,IAAIA,EAAa,cAAA,CAAgB,sDAAsD,CAChG,CAUJ,CAQA,0BAAA,CAA2BK,CAAAA,CAA8B,CACvD,OAAOoM,EAAAA,CAAkC,IAAIpM,CAAAA,CAAM,IAAI,CACzD,CAKQ,kBAAA,CACNA,EAC+G,CAC/G,OAAIoM,GAAkC,GAAA,CAAIpM,CAAK,EACtCA,CAAAA,CAEF,aACT,CAKQ,sBAAA,CAAuBA,CAAAA,CAAuB,CACpD,OAAQA,GACN,KAAK,iBACH,OAAO,4CAAA,CACT,KAAK,sBAAA,CACH,OAAO,2BAAA,CACT,KAAK,mBACH,OAAO,uBAAA,CACT,KAAK,4BAAA,CACH,OAAO,8BACT,QACE,OAAO,8BACX,CACF,CACF,ECrPA,eAAsBuM,EACpBC,CAAAA,CACAxF,CAAAA,CACAW,EAC2B,CAC3B,IAAMU,EAAkC,EAAC,CACnCoE,EAAqC,EAAC,CAE5C,OAAQD,CAAAA,CAAY,MAAA,EAClB,KAAK,qBAAA,CAAuB,CAE1B,IAAME,EAAqB,IAAA,CAAK,CAAA,EAAG1F,CAAQ,CAAA,CAAA,EAAIwF,CAAAA,CAAY,YAAY,CAAA,CAAE,CAAA,CACzEnE,CAAAA,CAAQ,aAAA,CAAmB,SAASqE,CAAkB,CAAA,CAAA,CACtD,KACF,CAEA,KAAK,qBAAsB,CAEzBD,CAAAA,CAAW,SAAA,CAAezF,CAAAA,CAC1ByF,EAAW,aAAA,CAAmBD,CAAAA,CAAY,aAC1C,KACF,CAEA,KAAK,iBAAA,CAAmB,CAEtB,IAAMhI,CAAAA,CAAM,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,GAAQ,GAAI,CAAA,CAElC+E,EAAgC,CACpC,GAAA,CAAKvC,CAAAA,CACL,GAAA,CAAKA,EACL,GAAA,CAAKW,CAAAA,CACL,IAAKgF,EAAAA,EAAY,CACjB,IAAKnI,CAAAA,CAAM,GAAA,CACX,GAAA,CAAKA,CACP,EAEIoI,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAY,MAAMJ,EAAY,OAAA,CAAQjD,CAAM,EAC9C,CAAA,MAASvJ,EAAO,CACd,MAAM,IAAIL,CAAAA,CACR,+BAAA,CACA,sCACA,CAAE,KAAA,CAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAAU,CACtD,CACF,CAEAyM,CAAAA,CAAW,UAAezF,CAAAA,CAC1ByF,CAAAA,CAAW,qBAAA,CAA2B,wDAAA,CACtCA,EAAW,gBAAA,CAAsBG,CAAAA,CACjC,KACF,CAEA,KAAK,OAAQ,CAGX,GAAI,EAAE,0BAAA,GAA8BJ,IAAgBA,CAAAA,CAAY,wBAAA,GAA6B,KAC3F,MAAM,IAAI7M,EACR,sBAAA,CACA,6EACF,CAAA,CAEF8M,CAAAA,CAAW,UAAezF,CAAAA,CAC1B,KACF,CAEA,QAAS,CAEP,IAAM6F,CAAAA,CAAqBL,CAAAA,CAC3B,MAAM,IAAI7M,CAAAA,CACR,gCACA,CAAA,sCAAA,EAA0CkN,CAAAA,CAAkC,MAAM,CAAA,CACpF,CACF,CACF,CAEA,OAAO,CAAE,OAAA,CAAAxE,EAAS,UAAA,CAAAoE,CAAW,CAC/B,CAOA,SAASE,IAAsB,CAC7B,OAAI,OAAO,MAAA,CAAW,KAAe,MAAA,CAAO,UAAA,CACnC,OAAO,UAAA,EAAW,CAGpB,GAAG,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,KAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,UAAU,CAAA,CAAG,EAAE,CAAC,CAAA,CACrE,KCzEaG,EAAAA,CAAN,KAA8B,CAKnC,WAAA,CAAY/M,CAAAA,CAAyC,CACnD,IAAA,CAAK,IAAA,CAAOA,CAAAA,CAAQ,IAAA,CACpB,KAAK,QAAA,CAAWA,CAAAA,CAAQ,SACxB,IAAA,CAAK,WAAA,CAAcA,EAAQ,YAC7B,CAUA,MAAM,QAAA,CACJmH,EACAnH,CAAAA,CACmB,CACnB,IAAM4H,CAAAA,CAAgBT,CAAAA,CAAU,eAG1B,CAAE,OAAA,CAAS6F,CAAAA,CAAa,UAAA,CAAYC,CAAe,CAAA,CACvD,MAAMT,EAA0B,IAAA,CAAK,WAAA,CAAa,KAAK,QAAA,CAAU5E,CAAa,EAG1EC,CAAAA,CAAO,IAAI,gBAAgB,CAC/B,UAAA,CAAY,qBACZ,GAAGoF,CACL,CAAC,CAAA,CAWD,GARIjN,CAAAA,EAAS,KAAA,EACX6H,EAAK,GAAA,CAAI,OAAA,CAAS7H,EAAQ,KAAK,CAAA,CAE7BA,GAAS,QAAA,EACX6H,CAAAA,CAAK,GAAA,CAAI,UAAA,CAAY7H,EAAQ,QAAQ,CAAA,CAInCA,GAAS,WAAA,CAAa,CACxB,IAAMwH,CAAAA,CAAkB,IAAI,GAAA,CAAI,CAC9B,aACA,WAAA,CACA,eAAA,CACA,mBACA,uBAAA,CACA,OAAA,CACA,UACF,CAAC,CAAA,CAED,IAAA,GAAW,CAAC7C,EAAKS,EAAK,CAAA,GAAK,OAAO,OAAA,CAAQpF,CAAAA,CAAQ,WAAW,CAAA,CACvDwH,CAAAA,CAAgB,GAAA,CAAI7C,CAAAA,CAAI,aAAa,CAAA,EAGzCkD,EAAK,GAAA,CAAIlD,CAAAA,CAAKS,EAAK,EAEvB,CAGA,IAAMkD,CAAAA,CAAkC,CACtC,cAAA,CAAgB,mCAAA,CAChB,GAAG0E,CACL,CAAA,CAGIxL,EACJ,GAAI,CACFA,CAAAA,CAAW,MAAM,KAAK,IAAA,CAAK,KAAA,CAAqBoG,EAAe,CAC7D,MAAA,CAAQ,OACR,OAAA,CAAAU,CAAAA,CACA,KAAMT,CAAAA,CAAK,QAAA,EACb,CAAC,EACH,OAAS5H,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CAAa,eAAA,CAAiB,yCAAA,CAA2C,CACjF,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAC1C,CAAC,CACH,CAEA,GAAI,CAACuB,EAAS,EAAA,CAAI,CAChB,IAAMsG,CAAAA,CAAYtG,CAAAA,CAAS,KAC3B,MAAM,IAAI5B,CAAAA,CAAa,0BAAA,CAA4B,0CAA2C,CAC5F,OAAA,CAAS,CACP,MAAA,CAAQ4B,CAAAA,CAAS,OACjB,KAAA,CAAOsG,CAAAA,EAAW,KAAA,CAClB,iBAAA,CAAmBA,GAAW,iBAChC,CACF,CAAC,CACH,CAEA,IAAMC,CAAAA,CAAgBvG,CAAAA,CAAS,IAAA,CAGzBiD,CAAAA,CAAM,KAAK,KAAA,CAAM,IAAA,CAAK,KAAI,CAAI,GAAI,EAClCwD,CAAAA,CAAYF,CAAAA,CAAc,UAAA,CAAatD,CAAAA,CAAMsD,EAAc,UAAA,CAAatD,CAAAA,CAAM,KAYpF,OAR2B,CACzB,YAAasD,CAAAA,CAAc,YAAA,CAC3B,SAAA,CAAYA,CAAAA,CAAc,YAA2B,QAAA,CACrD,SAAA,CAAAE,EACA,YAAA,CAAcF,CAAAA,CAAc,cAC5B,KAAA,CAAOA,CAAAA,CAAc,KACvB,CAGF,CACF,ECtIO,IAAMmF,EAAAA,CAAN,KAAiB,CAGtB,WAAA,CAAYvN,EAA0B,CACpC,IAAA,CAAK,MAAA,CAASA,EAChB,CASA,MAAM,kBAAA,CAAmBK,EAA6C,CACpE,IAAMyE,EAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,GAAQ,GAAI,CAAA,CAClC0I,EAAW,IAAA,CAAK,MAAA,CAAO,UAAY,GAAA,CAGnCrH,CAAAA,CAAkC,CACtC,GAAA,CAAK,KAAK,MAAA,CAAO,SAAA,EAAa,QAC9B,GAAA,CAAK,qBACP,EAEI,IAAA,CAAK,MAAA,CAAO,KAAA,GACdA,CAAAA,CAAO,IAAS,IAAA,CAAK,MAAA,CAAO,OAI9B,IAAM0D,CAAAA,CAAiC,CACrC,GAAA,CAAKxJ,CAAAA,CAAQ,QAAA,CACb,GAAA,CAAKA,EAAQ,MAAA,CACb,aAAA,CAAeA,EAAQ,YAAA,EAAgB,MAAA,CACvC,UAAWA,CAAAA,CAAQ,QAAA,CACnB,YAAA,CAAcA,CAAAA,CAAQ,YACtB,KAAA,CAAOA,CAAAA,CAAQ,MACf,KAAA,CAAOA,CAAAA,CAAQ,MACf,KAAA,CAAOA,CAAAA,CAAQ,KAAA,CACf,cAAA,CAAgBA,EAAQ,aAAA,CACxB,qBAAA,CAAuBA,EAAQ,mBAAA,CAC/B,GAAA,CAAKyE,EACL,GAAA,CAAKA,CAAAA,CAAM0I,EACX,GAAA,CAAK,IAAA,CAAK,aACZ,CAAA,CAcA,GAXInN,CAAAA,CAAQ,MAAA,GACVwJ,EAAO,MAAA,CAASxJ,CAAAA,CAAQ,MAAA,CAAA,CAEtBA,CAAAA,CAAQ,YACVwJ,CAAAA,CAAO,UAAA,CAAaxJ,EAAQ,SAAA,CAAA,CAE1BA,CAAAA,CAAQ,YACVwJ,CAAAA,CAAO,UAAA,CAAaxJ,CAAAA,CAAQ,SAAA,CAAA,CAI1BA,EAAQ,WAAA,CAAa,CACvB,IAAMoN,CAAAA,CAAkB,IAAI,IAAI,CAC9B,KAAA,CACA,KAAA,CACA,eAAA,CACA,YACA,cAAA,CACA,OAAA,CACA,QACA,OAAA,CACA,gBAAA,CACA,wBACA,KAAA,CACA,KAAA,CACA,MACA,KACF,CAAC,EAED,IAAA,GAAW,CAACzI,EAAKS,CAAK,CAAA,GAAK,OAAO,OAAA,CAAQpF,CAAAA,CAAQ,WAAW,CAAA,CACtDoN,EAAgB,GAAA,CAAIzI,CAAG,IAC1B6E,CAAAA,CAAO7E,CAAG,EAAIS,CAAAA,EAGpB,CAGA,GAAI,CACF,OAAO,MAAM,IAAA,CAAK,OAAO,OAAA,CAAQU,CAAAA,CAAQ0D,CAAM,CACjD,CAAA,MAASvJ,CAAAA,CAAO,CACd,MAAM,IAAIL,CAAAA,CACR,oBACA,mCAAA,CACA,CAAE,MAAOK,CAAAA,YAAiB,KAAA,CAAQA,EAAQ,MAAU,CACtD,CACF,CACF,CAKQ,aAAsB,CAC5B,OAAI,OAAO,MAAA,CAAW,GAAA,EAAe,MAAA,CAAO,UAAA,CACnC,OAAO,UAAA,EAAW,CAEpB,GAAG,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,IAAA,CAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,UAAU,CAAA,CAAG,EAAE,CAAC,CAAA,CACrE,CACF,EAQO,SAASoN,GAAclG,CAAAA,CAAiE,CAC7F,OAAOA,CAAAA,CAAU,6BAAA,GAAkC,IACrD,CC9GO,IAAMmG,EAAAA,CAAN,KAAoB,CAGzB,WAAA,CAAY3N,CAAAA,CAA6B,CACvC,IAAA,CAAK,MAAA,CAASA,EAChB,CAYA,MAAM,gBAAA,CACJwH,CAAAA,CACA3F,EACAxB,CAAAA,CAC+B,CAC/B,IAAMuN,CAAAA,CAAYvN,CAAAA,CAAQ,kBAAoB,EAAA,CAG1CwJ,CAAAA,CACJ,GAAI,CACFA,EAAS,MAAM,IAAA,CAAK,OAAO,SAAA,CAAUhI,CAAAA,CAAU2F,EAAU,MAAM,EACjE,CAAA,MAASlH,CAAAA,CAAO,CACd,MAAM,IAAIL,EACR,wBAAA,CACA,0CAAA,CACA,CAAE,KAAA,CAAOK,CAAAA,YAAiB,MAAQA,CAAAA,CAAQ,MAAU,CACtD,CACF,CAGA,GAAIuJ,CAAAA,CAAO,GAAA,GAAQrC,EAAU,MAAA,CAC3B,MAAM,IAAIvH,CAAAA,CACR,wBACA,sDAAA,CACA,CACE,QAAS,CACP,QAAA,CAAUuH,EAAU,MAAA,CACpB,MAAA,CAAQqC,CAAAA,CAAO,GACjB,CACF,CACF,CAAA,CAKF,GAAI,CAAA,CADa,KAAA,CAAM,QAAQA,CAAAA,CAAO,GAAG,CAAA,CAAIA,CAAAA,CAAO,IAAM,CAACA,CAAAA,CAAO,GAAG,CAAA,EACvD,QAAA,CAASxJ,EAAQ,QAAQ,CAAA,CACrC,MAAM,IAAIJ,CAAAA,CACR,wBACA,iDAAA,CACA,CACE,QAAS,CACP,QAAA,CAAUI,EAAQ,QAAA,CAClB,MAAA,CAAQwJ,CAAAA,CAAO,GACjB,CACF,CACF,CAAA,CAIF,IAAM/E,CAAAA,CAAM,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,EAAI,CAAI,GAAI,EACxC,GAAI+E,CAAAA,CAAO,KAAOA,CAAAA,CAAO,GAAA,CAAM+D,EAAY9I,CAAAA,CACzC,MAAM,IAAI7E,CAAAA,CACR,wBACA,2BACF,CAAA,CAIF,GAAI4J,CAAAA,CAAO,GAAA,EAAOA,EAAO,GAAA,CAAM+D,CAAAA,CAAY9I,EACzC,MAAM,IAAI7E,EACR,uBAAA,CACA,oCACF,EAIF,GAAI4J,CAAAA,CAAO,MACT,MAAM,IAAI5J,CAAAA,CAAa,aAAA,CAAe4J,EAAO,iBAAA,EAAqBA,CAAAA,CAAO,MAAO,CAC9E,OAAA,CAAS,CACP,KAAA,CAAOA,CAAAA,CAAO,KAAA,CACd,iBAAA,CAAmBA,EAAO,iBAAA,CAC1B,SAAA,CAAWA,EAAO,SACpB,CACF,CAAC,CAAA,CAIH,GAAI,CAACA,CAAAA,CAAO,MACV,MAAM,IAAI5J,EACR,uBAAA,CACA,sCACF,EAEF,GAAI,CAACwG,CAAAA,CAAgBoD,CAAAA,CAAO,MAAOxJ,CAAAA,CAAQ,aAAa,EACtD,MAAM,IAAIJ,EACR,uBAAA,CACA,mDACF,CAAA,CAIF,GAAI,CAAC4J,CAAAA,CAAO,IAAA,CACV,MAAM,IAAI5J,CAAAA,CACR,wBACA,6CACF,CAAA,CAGF,OAAO,CACL,KAAM4J,CAAAA,CAAO,IAAA,CACb,MAAOA,CAAAA,CAAO,KAChB,CACF,CAUA,OAAO,2BAAA,CAA4B/B,CAAAA,CAAoC,CACrE,IAAIC,CAAAA,CAEJ,OAAID,CAAAA,CAAY,QAAA,CAAS,GAAG,CAAA,CAI1BC,CAAAA,CAAAA,CAHYD,EAAY,UAAA,CAAW,MAAM,EACrC,IAAI,GAAA,CAAIA,CAAW,CAAA,CACnB,IAAI,IAAIA,CAAAA,CAAa,qBAAqB,CAAA,EAC3B,YAAA,CAEnBC,EAAe,IAAI,eAAA,CAAgBD,CAAW,CAAA,CAGzCC,CAAAA,CAAa,IAAI,UAAU,CACpC,CACF,EChJO,IAAM8F,CAAAA,CAAN,MAAMA,CAAqB,CAahC,WAAA,CAAYxN,EAA8B,CAZ1C,IAAA,CAAQ,YAAA,CAAoC,IAAA,CAE5C,KAAQ,aAAA,CAAuD,IAAA,CAC/D,KAAQ,eAAA,CAA0C,IAAA,CAClD,KAAQ,SAAA,CAAY,KAAA,CASlB,KAAK,OAAA,CAAU,CACb,iBAAkBA,CAAAA,EAAS,gBAAA,EAAoBwN,EAAqB,yBAAA,CACpE,eAAA,CAAiBxN,GAAS,eAAA,EAAmBwN,CAAAA,CAAqB,yBAAA,CAClE,YAAA,CAAcxN,GAAS,YACzB,EACF,CAOA,KAAA,CAAMyN,CAAAA,CAAkC,CAClC,IAAA,CAAK,SAAA,GAIT,IAAA,CAAK,YAAA,CAAeA,EACpB,IAAA,CAAK,eAAA,CAAkB,IAAI,eAAA,CAC3B,IAAA,CAAK,UAAY,IAAA,CAGjB,IAAA,CAAK,aAAA,CAAgB,WAAA,CAAY,IAAM,CACrC,IAAA,CAAK,iBAAgB,CAAE,KAAA,CAAM,IAAM,CAEnC,CAAC,EACH,CAAA,CAAG,IAAA,CAAK,QAAQ,eAAe,CAAA,CAG/B,KAAK,eAAA,EAAgB,CAAE,MAAM,IAAM,CAEnC,CAAC,CAAA,EACH,CAKA,IAAA,EAAa,CACN,KAAK,SAAA,GAIV,IAAA,CAAK,UAAY,KAAA,CAEb,IAAA,CAAK,aAAA,GACP,aAAA,CAAc,KAAK,aAAa,CAAA,CAChC,KAAK,aAAA,CAAgB,IAAA,CAAA,CAGnB,KAAK,eAAA,GACP,IAAA,CAAK,eAAA,CAAgB,KAAA,GACrB,IAAA,CAAK,eAAA,CAAkB,MAGzB,IAAA,CAAK,YAAA,CAAe,MACtB,CAKA,IAAI,OAAA,EAAmB,CACrB,OAAO,IAAA,CAAK,SACd,CAKA,IAAI,MAAA,EAA6B,CAC/B,OAAO,IAAA,CAAK,eAAA,EAAiB,MAAA,EAAU,IACzC,CAKA,MAAc,iBAAiC,CAC7C,GAAI,GAAC,IAAA,CAAK,YAAA,EAAgB,CAAC,IAAA,CAAK,WAIhC,GAAI,CACF,IAAMzD,CAAAA,CAAS,MAAM,KAAK,YAAA,CAAa,SAAA,EAAU,CACjD,GAAI,CAACA,CAAAA,CACH,OAGF,IAAMvF,CAAAA,CAAM,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,GAAQ,GAAI,CAAA,CACtBuF,EAAO,SAAA,CAAYvF,CAAAA,EAGpB,KAAK,OAAA,CAAQ,gBAAA,EAAoBuF,EAAO,YAAA,EAEvD,MAAM,IAAA,CAAK,YAAA,CAAa,UAE5B,CAAA,KAAgB,CAGhB,CACF,CAKA,MAAM,UAAA,EAA4B,CAChC,MAAM,IAAA,CAAK,kBACb,CACF,EAvHawD,CAAAA,CAQa,yBAAA,CAA4B,GARzCA,CAAAA,CAWa,yBAAA,CAA4B,GAAA,CAX/C,IAAME,GAANF,ECkDA,IAAMG,GAAN,KAA6B,CAGlC,YAAY3N,CAAAA,CAAwC,CAClD,IAAA,CAAK,MAAA,CAASA,EAAQ,OACxB,CAWA,MAAM,SAAA,CAAUsH,CAAAA,CAAyD,CAEvE,IAAIsG,CAAAA,CAAOtG,CAAAA,CAAO,IAAA,CAClB,GAAI,CAACsG,CAAAA,CAAM,CACT,IAAMC,CAAAA,CAAY,MAAM,IAAA,CAAK,MAAA,CAAO,WAAA,CAAY,EAAE,EAClDD,CAAAA,CAAOrL,CAAAA,CAAgBsL,CAAS,EAClC,CAIA,IAAMC,CAAAA,CACJxG,CAAAA,CAAO,QAAA,CAAW,GAAA,CAAMA,EAAO,MAAA,CAAS,GAAA,CAAMA,EAAO,cAAA,CAAiBsG,CAAAA,CAGlEG,EAAY,MAAM,IAAA,CAAK,OAAO,MAAA,CAAOD,CAAS,EAC9CjE,CAAAA,CAAOtH,CAAAA,CAAgBwL,CAAS,CAAA,CAKtC,OAAO,CACL,YAAA,CAHmBlE,CAAAA,CAAO,GAAA,CAAM+D,CAAAA,CAIhC,KAAA/D,CAAAA,CACA,IAAA,CAAA+D,CACF,CACF,CAWA,MAAM,QAAA,CACJI,CAAAA,CACA1G,CAAAA,CACkB,CAClB,IAAMtC,CAAAA,CAAS,IAAA,CAAK,MAAMgJ,CAAY,CAAA,CACtC,GAAI,CAAChJ,CAAAA,CACH,OAAO,MAAA,CAIT,IAAMiJ,CAAAA,CAAa,MAAM,KAAK,SAAA,CAAU,CACtC,GAAG3G,CAAAA,CACH,IAAA,CAAMtC,CAAAA,CAAO,IACf,CAAC,CAAA,CAGD,OAAOoB,EAAgB6H,CAAAA,CAAW,YAAA,CAAcD,CAAY,CAC9D,CAQA,KAAA,CAAMA,CAAAA,CAA6D,CAYjE,GALI,CAACA,GAAgB,OAAOA,CAAAA,EAAiB,UAKzCA,CAAAA,CAAa,MAAA,CAAS,GAAA,CACxB,OAAO,KAGT,IAAME,CAAAA,CAAWF,EAAa,WAAA,CAAY,GAAG,EAC7C,GAAIE,CAAAA,GAAa,EAAA,EAAMA,CAAAA,GAAa,GAAKA,CAAAA,GAAaF,CAAAA,CAAa,OAAS,CAAA,CAC1E,OAAO,KAGT,IAAMnE,CAAAA,CAAOmE,EAAa,SAAA,CAAU,CAAA,CAAGE,CAAQ,CAAA,CACzCN,CAAAA,CAAOI,EAAa,SAAA,CAAUE,CAAAA,CAAW,CAAC,CAAA,CAQhD,GALI,CAACrE,CAAAA,EAAQ,CAAC+D,CAAAA,EAKV/D,CAAAA,CAAK,OAAS,GAAA,EAAmB+D,CAAAA,CAAK,OAAS,GAAA,CACjD,OAAO,IAAA,CAIT,IAAMO,EAAiB,kBAAA,CACvB,OAAI,CAACA,CAAAA,CAAe,IAAA,CAAKtE,CAAI,CAAA,EAAK,CAACsE,CAAAA,CAAe,IAAA,CAAKP,CAAI,CAAA,CAClD,IAAA,CAGF,CAAE,IAAA,CAAA/D,CAAAA,CAAM,KAAA+D,CAAK,CACtB,CACF,EChHO,IAAMQ,GAAN,KAAmC,CAQxC,MACEpO,CAAAA,CACAsH,CAAAA,CAC6B,CAC7B,IAAMgC,CAAAA,CAAM,IAAI,GAAA,CAAItJ,EAAQ,SAAS,CAAA,CAC/BqO,EAAyC,EAAC,CAEhD,OAAIrO,CAAAA,CAAQ,aAAA,EAAiBsH,CAAAA,CAAO,GAAA,GAClCgC,EAAI,YAAA,CAAa,GAAA,CAAI,MAAOhC,CAAAA,CAAO,GAAG,EACtC+G,CAAAA,CAAa,GAAA,CAAM/G,CAAAA,CAAO,GAAA,CAAA,CAGxBtH,EAAQ,gBAAA,EAAoBsH,CAAAA,CAAO,MACrCgC,CAAAA,CAAI,YAAA,CAAa,IAAI,KAAA,CAAOhC,CAAAA,CAAO,GAAG,CAAA,CACtC+G,CAAAA,CAAa,IAAM/G,CAAAA,CAAO,GAAA,CAAA,CAGrB,CACL,GAAA,CAAKgC,CAAAA,CAAI,UAAS,CAClB,MAAA,CAAQ+E,CACV,CACF,CAQA,WAAA,CAAY/E,CAAAA,CAA6C,CACvD,IAAMgF,CAAAA,CAAS,OAAOhF,CAAAA,EAAQ,QAAA,CAAW,IAAI,GAAA,CAAIA,CAAG,CAAA,CAAIA,CAAAA,CAClDhC,EAAmC,EAAC,CAEpCiH,EAAMD,CAAAA,CAAO,YAAA,CAAa,GAAA,CAAI,KAAK,EACrCC,CAAAA,GACFjH,CAAAA,CAAO,IAAMiH,CAAAA,CAAAA,CAGf,IAAMC,EAAMF,CAAAA,CAAO,YAAA,CAAa,GAAA,CAAI,KAAK,EACzC,OAAIE,CAAAA,GACFlH,EAAO,GAAA,CAAMkH,CAAAA,CAAAA,CAGRlH,CACT,CAWA,eAAA,CACEgC,CAAAA,CACAmF,CAAAA,CAAgD,EAAC,CACb,CACpC,IAAInH,CAAAA,CAEJ,GAAI,CACFA,CAAAA,CAAS,IAAA,CAAK,WAAA,CAAYgC,CAAG,EAC/B,CAAA,KAAQ,CACN,OAAO,CACL,KAAA,CAAO,MACP,KAAA,CAAO,oBACT,CACF,CAGA,OAAImF,CAAAA,CAAS,UAAA,EAAc,CAACnH,CAAAA,CAAO,GAAA,CAC1B,CACL,KAAA,CAAO,KAAA,CACP,MAAO,gCACT,CAAA,CAGEmH,EAAS,UAAA,EAAc,CAACnH,EAAO,GAAA,CAC1B,CACL,MAAO,KAAA,CACP,KAAA,CAAO,gCACT,CAAA,CAKEmH,EAAS,MAAA,EAAUnH,CAAAA,CAAO,KAAO,CAAClB,CAAAA,CAAgBkB,EAAO,GAAA,CAAKmH,CAAAA,CAAS,MAAM,CAAA,CACxE,CACL,KAAA,CAAO,KAAA,CACP,MAAO,0BACT,CAAA,CAKEA,EAAS,SAAA,EAAanH,CAAAA,CAAO,GAAA,EAAO,CAAClB,EAAgBkB,CAAAA,CAAO,GAAA,CAAKmH,EAAS,SAAS,CAAA,CAC9E,CACL,KAAA,CAAO,KAAA,CACP,MAAO,8BACT,CAAA,CAGK,CACL,KAAA,CAAO,IAAA,CACP,OAAAnH,CACF,CACF,CACF,EC5LA,IAAMoH,EAAAA,CAAiB,CACrB,cACA,cAAA,CACA,SAAA,CACA,QACA,MAAA,CACA,UAAA,CACA,SACA,aAAA,CACA,eAAA,CACA,QAAA,CACA,cAAA,CACA,gBACA,eACF,CAAA,CAKMC,GAAuB,CAC3B,MAAA,CACA,QACA,OAAA,CACA,UAAA,CACA,cAAA,CACA,eAAA,CACA,OACF,CAAA,CAQaC,CAAAA,CAAN,KAAoB,CAKzB,WAAA,CAAY5O,EAA6D,CAJzE,IAAA,CAAQ,QAA2B,EAAC,CAKlC,KAAK,SAAA,CAAYA,CAAAA,EAAS,WAAa,GAAA,CACvC,IAAA,CAAK,YAAcA,CAAAA,EAAS,WAAA,EAAe,UAC7C,CAWA,OACE6K,CAAAA,CACA9I,CAAAA,CACA/B,EACM,CACN,IAAM6O,EAAmB7O,CAAAA,EAAS,MAAA,EAAU,IAAA,CAAK,WAAA,CAC3C8O,EAAe,IAAA,CAAK,UAAA,CAAW/M,EAAM8M,CAAgB,CAAA,CAErDE,EAAuB,CAC3B,IAAA,CAAAlE,CAAAA,CACA,SAAA,CAAW,KAAK,GAAA,EAAI,CACpB,YAAa7K,CAAAA,EAAS,WAAA,CACtB,KAAM8O,CACR,CAAA,CAKA,IAHA,IAAA,CAAK,QAAQ,IAAA,CAAKC,CAAK,EAGhB,IAAA,CAAK,OAAA,CAAQ,OAAS,IAAA,CAAK,SAAA,EAChC,IAAA,CAAK,OAAA,CAAQ,QAEjB,CAQA,UAAUzJ,CAAAA,CAAiC,CACzC,OAAIA,CAAAA,GAAU,MAAA,CACL,CAAC,GAAG,KAAK,OAAO,CAAA,CAElB,KAAK,OAAA,CAAQ,KAAA,CAAM,CAACA,CAAK,CAClC,CAQA,gBAAA,CAAiBd,EAAsC,CACrD,OAAO,KAAK,OAAA,CAAQ,MAAA,CAAQuK,GAAUA,CAAAA,CAAM,WAAA,GAAgBvK,CAAW,CACzE,CAQA,UAAUqG,CAAAA,CAA+B,CACvC,OAAO,IAAA,CAAK,OAAA,CAAQ,OAAQkE,CAAAA,EAAUA,CAAAA,CAAM,IAAA,GAASlE,CAAI,CAC3D,CAKA,KAAA,EAAc,CACZ,IAAA,CAAK,OAAA,CAAU,GACjB,CAKA,IAAI,MAAA,EAAiB,CACnB,OAAO,IAAA,CAAK,QAAQ,MACtB,CAKA,QAAiB,CACf,OAAO,IAAA,CAAK,SAAA,CAAU,KAAK,OAAA,CAAS,IAAA,CAAM,CAAC,CAC7C,CAKA,eAAemE,CAAAA,CAA0B,CACvC,KAAK,WAAA,CAAcA,EACrB,CAKQ,UAAA,CACNjN,CAAAA,CACAiN,EACqC,CAKrC,OAJIA,IAAU,MAAA,EAAUjN,CAAAA,GAAS,MAAA,EAAaA,CAAAA,GAAS,MAInD,OAAOA,CAAAA,EAAS,SACXA,CAAAA,CAGQ,IAAA,CAAK,WAAWA,CAAAA,CAAiCiN,CAAK,CAEzE,CAKQ,WACNC,CAAAA,CACAD,CAAAA,CACyB,CACzB,IAAMpI,CAAAA,CAAkC,EAAC,CAEzC,IAAA,GAAW,CAACjC,CAAAA,CAAKS,CAAK,CAAA,GAAK,MAAA,CAAO,QAAQ6J,CAAG,CAAA,CAAG,CAC9C,IAAMC,CAAAA,CAAWvK,EAAI,WAAA,EAAY,CAGjC,GAAI,IAAA,CAAK,cAAA,CAAeuK,CAAQ,CAAA,CAAG,CAEjC,IAAMC,CAAAA,CAAiBxK,CAAAA,CAAI,MAAA,CAAO,CAAC,EAAE,WAAA,EAAY,CAAIA,EAAI,KAAA,CAAM,CAAC,EAChEiC,CAAAA,CAAO,CAAA,GAAA,EAAMuI,CAAc,CAAA,CAAE,EAA2B/J,CAAAA,EAAU,IAAA,CAClEwB,EAAOjC,CAAG,CAAA,CAAI,aACd,QACF,CAGA,GAAIqK,CAAAA,GAAU,cAAgBE,CAAAA,GAAa,KAAA,EAAS,OAAO9J,CAAAA,EAAU,QAAA,CAAU,CAC7EwB,CAAAA,CAAOjC,CAAG,CAAA,CAAI,IAAA,CAAK,UAAUS,CAAK,CAAA,CAClC,QACF,CAGA,GAAIA,IAAU,IAAA,EAAQ,OAAOA,CAAAA,EAAU,QAAA,EAAY,CAAC,KAAA,CAAM,OAAA,CAAQA,CAAK,CAAA,CAAG,CACxEwB,EAAOjC,CAAG,CAAA,CAAI,IAAA,CAAK,UAAA,CAAWS,EAAkC4J,CAAK,CAAA,CACrE,QACF,CAGA,GAAI,MAAM,OAAA,CAAQ5J,CAAK,CAAA,CAAG,CACxBwB,EAAOjC,CAAG,CAAA,CAAIS,EAAM,GAAA,CAAKgK,CAAAA,EACnBA,IAAS,IAAA,EAAQ,OAAOA,GAAS,QAAA,CAC5B,IAAA,CAAK,WAAWA,CAAAA,CAAiCJ,CAAK,EAExDI,CACR,CAAA,CACD,QACF,CAGAxI,CAAAA,CAAOjC,CAAG,CAAA,CAAIS,EAChB,CAEA,OAAOwB,CACT,CAKQ,cAAA,CAAejC,EAAsB,CAC3C,OAAO+J,EAAAA,CAAe,IAAA,CACnBW,GAAc1K,CAAAA,GAAQ0K,CAAAA,CAAU,aAAY,EAAK1K,CAAAA,CAAI,SAAS0K,CAAAA,CAAU,WAAA,EAAa,CACxF,CACF,CAKQ,SAAA,CAAU/F,EAAqB,CACrC,GAAI,CACF,IAAMtE,CAAAA,CAAS,IAAI,GAAA,CAAIsE,CAAG,CAAA,CAE1B,IAAA,IAAWgG,KAASX,EAAAA,CACd3J,CAAAA,CAAO,aAAa,GAAA,CAAIsK,CAAK,CAAA,EAC/BtK,CAAAA,CAAO,aAAa,GAAA,CAAIsK,CAAAA,CAAO,YAAY,CAAA,CAK/C,GAAItK,EAAO,IAAA,CAAM,CACf,IAAMuK,CAAAA,CAAa,IAAI,eAAA,CAAgBvK,CAAAA,CAAO,KAAK,KAAA,CAAM,CAAC,CAAC,CAAA,CACvDwK,CAAAA,CAAe,CAAA,CAAA,CAEnB,IAAA,IAAWF,KAASX,EAAAA,CACdY,CAAAA,CAAW,IAAID,CAAK,CAAA,GACtBC,EAAW,GAAA,CAAID,CAAAA,CAAO,YAAY,CAAA,CAClCE,CAAAA,CAAe,IAIfA,CAAAA,GACFxK,CAAAA,CAAO,KAAO,GAAA,CAAMuK,CAAAA,CAAW,UAAS,EAE5C,CAEA,OAAOvK,CAAAA,CAAO,UAChB,CAAA,KAAQ,CAEN,OAAOsE,CAAAA,CAAI,QAAQ,wCAAA,CAA0C,iBAAiB,CAChF,CACF,CACF,EC5PO,SAASmG,GAAoBzP,CAAAA,CAEpB,CACd,IAAM0P,CAAAA,CAAoB1P,CAAAA,EAAS,UAAA,EAAc,KAAA,CAEjD,OAAO,CACL,GAAA,CAAIgP,EAAsBjP,CAAAA,CAAiBgC,CAAAA,CAAsB,CAC/D,IAAMmD,CAAAA,CAASwK,CAAAA,CACX,CAAA,SAAA,EAAYV,EAAM,WAAA,EAAa,IAAI,IAAI,IAAA,GAAO,WAAA,EAAa,CAAA,CAAA,CAAA,CAC3D,CAAA,SAAA,EAAYA,EAAM,WAAA,EAAa,IAE7BW,CAAAA,CAAgBX,CAAAA,GAAU,QAAU,KAAA,CAAQA,CAAAA,CAG5CY,CAAAA,CAAa,OAAO,QAAY,GAAA,CAAc,OAAA,CAAU,KACzDA,CAAAA,GAED7N,CAAAA,GAAS,OACX6N,CAAAA,CAAWD,CAAa,CAAA,GAAIzK,CAAAA,CAAQnF,EAASgC,CAAI,CAAA,CAEjD6N,EAAWD,CAAa,CAAA,GAAIzK,EAAQnF,CAAO,CAAA,EAE/C,CACF,CACF,KAKa8P,EAAAA,CAA0B,CACrC,KAAY,CAEZ,CACF,EAKO,SAASC,EAAAA,CAAkB9P,CAAAA,CAAoC,CACpE,OAAKA,CAAAA,CAAQ,OAAA,CAITA,EAAQ,MAAA,CACHA,CAAAA,CAAQ,OAGVyP,EAAAA,CAAoB,CACzB,UAAA,CAAYzP,CAAAA,CAAQ,aACtB,CAAC,CAAA,CATQ6P,EAUX,CAKO,IAAME,EAAN,KAAmB,CAKxB,WAAA,CAAY7I,CAAAA,CAAqBlH,EAAiC,CAFlE,IAAA,CAAQ,YAA6B,IAAA,CAGnC,IAAA,CAAK,OAASkH,CAAAA,CACd,IAAA,CAAK,QAAUlH,CAAAA,EAAS,OAAA,EAAW,MACrC,CAKA,cAAA,CAAegQ,EAAyB,CACtC,IAAA,CAAK,YAAcA,EACrB,CAKA,cAAA,EAAgC,CAC9B,OAAO,IAAA,CAAK,WACd,CAKA,KAAA,CAAMjQ,CAAAA,CAAiBgC,EAAsB,CACvC,IAAA,CAAK,OAAA,EACP,IAAA,CAAK,OAAO,GAAA,CAAI,OAAA,CAAS,KAAK,aAAA,CAAchC,CAAO,EAAGgC,CAAI,EAE9D,CAKA,IAAA,CAAKhC,EAAiBgC,CAAAA,CAAsB,CAC1C,KAAK,MAAA,CAAO,GAAA,CAAI,OAAQ,IAAA,CAAK,aAAA,CAAchC,CAAO,CAAA,CAAGgC,CAAI,EAC3D,CAKA,IAAA,CAAKhC,EAAiBgC,CAAAA,CAAsB,CAC1C,KAAK,MAAA,CAAO,GAAA,CAAI,MAAA,CAAQ,IAAA,CAAK,cAAchC,CAAO,CAAA,CAAGgC,CAAI,EAC3D,CAKA,MAAMhC,CAAAA,CAAiBgC,CAAAA,CAAsB,CAC3C,IAAA,CAAK,OAAO,GAAA,CAAI,OAAA,CAAS,KAAK,aAAA,CAAchC,CAAO,EAAGgC,CAAI,EAC5D,CAKQ,aAAA,CAAchC,EAAyB,CAC7C,OAAI,KAAK,WAAA,CACA,CAAA,CAAA,EAAI,KAAK,WAAA,CAAY,KAAA,CAAM,CAAA,CAAG,CAAC,CAAC,CAAA,EAAA,EAAKA,CAAO,GAE9CA,CACT,CACF,ECsDO,IAAMkQ,CAAAA,CAAN,KAAoD,CAqBzD,YAAYjQ,CAAAA,CAAkC,CAf9C,KAAQ,IAAA,CAA6B,GAWrC,IAAA,CAAQ,UAAA,CAAmC,EAAC,CAE5C,KAAQ,UAAA,CAAa,KAAA,CAGnB,KAAK,mBAAA,CAAsB,IAAA,CAAK,mBAAkB,CAClD,IAAA,CAAK,OAAA,CAAUA,CAAAA,CAAQ,QACvB,IAAA,CAAK,WAAA,CAAcA,EAAQ,WAAA,CAC3B,IAAA,CAAK,YAAcA,CAAAA,CAAQ,WAAA,EAAe,MAC1C,IAAA,CAAK,OAAA,CAAUA,EAAQ,OAAA,EAAW,GAAA,CAGlC,KAAK,YAAA,CAAeA,CAAAA,CAAQ,cAAgB,KAAA,CAC5C,IAAA,CAAK,SAAA,CAAYA,CAAAA,CAAQ,UACzB,IAAA,CAAK,QAAA,CAAWA,EAAQ,QAAA,CACxB,IAAA,CAAK,aAAeA,CAAAA,CAAQ,YAAA,CAC5B,IAAA,CAAK,SAAA,CAAYA,EAAQ,SAAA,EAAa,EAAA,CACtC,KAAK,eAAA,CAAkBA,CAAAA,CAAQ,iBAAmB,GAAA,CAG9C,IAAA,CAAK,YAAA,GAAiB,CAAC,KAAK,SAAA,EAAa,CAAC,KAAK,QAAA,CAAA,GAC7C,IAAA,CAAK,aACP,IAAA,CAAK,WAAA,CAAY,IACf,MAAA,CACA,qGACF,EAEF,IAAA,CAAK,YAAA,CAAe,OAExB,CAQA,sBAAA,EAAiC,CAC/B,OAAO,IAAA,CAAK,mBACd,CAKA,WAAqB,CACnB,OAAO,KAAK,OACd,CAKA,mBAAmBA,CAAAA,CAQV,CACP,GAAI,CAAC,KAAK,OAAA,CAAS,OAEnB,IAAM+O,CAAAA,CAAiC,CACrC,GAAI,IAAA,CAAK,eAAA,EAAgB,CACzB,mBAAA,CAAqB,KAAK,mBAAA,CAC1B,QAAA,CAAU,mBACV,KAAA,CAAO/O,CAAAA,CAAQ,SAAW,MAAA,CAAS,OAAA,CAAU,QAC7C,SAAA,CAAW,IAAA,CAAK,KAAI,CACpB,IAAA,CAAMA,EAAQ,IAAA,CACd,SAAA,CAAWA,EAAQ,SAAA,CACnB,MAAA,CAAQA,CAAAA,CAAQ,MAAA,CAChB,SAAUA,CAAAA,CAAQ,QAAA,CAClB,OAAQA,CAAAA,CAAQ,MAAA,CAChB,aAAcA,CAAAA,CAAQ,YAAA,CACtB,OAAA,CAASA,CAAAA,CAAQ,OACnB,CAAA,CAEA,IAAA,CAAK,SAAS+O,CAAK,EACrB,CAKA,eAAA,CAAgB/O,CAAAA,CAKP,CACP,GAAI,CAAC,IAAA,CAAK,OAAA,CAAS,OAEnB,IAAM+O,CAAAA,CAA8B,CAClC,EAAA,CAAI,IAAA,CAAK,eAAA,EAAgB,CACzB,oBAAqB,IAAA,CAAK,mBAAA,CAC1B,SAAU,eAAA,CACV,KAAA,CAAO/O,EAAQ,QAAA,GAAa,MAAA,CAAS,MAAA,CAAS,MAAA,CAC9C,UAAW,IAAA,CAAK,GAAA,GAChB,QAAA,CAAUA,CAAAA,CAAQ,SAClB,MAAA,CAAQA,CAAAA,CAAQ,MAAA,CAChB,IAAA,CAAMA,EAAQ,IAAA,CACd,OAAA,CAASA,EAAQ,OACnB,CAAA,CAEA,KAAK,QAAA,CAAS+O,CAAK,EACrB,CAKA,SAAgC,CAC9B,OAAO,CAAC,GAAG,IAAA,CAAK,IAAI,CACtB,CAKA,YAAqB,CACnB,OAAO,KAAK,SAAA,CAAU,IAAA,CAAK,KAAM,IAAA,CAAM,CAAC,CAC1C,CAKA,SAAA,EAAkB,CAChB,IAAA,CAAK,KAAO,GACd,CAKA,oBAAA,EAA+B,CAC7B,OAAO,IAAA,CAAK,UAAA,CAAW,MACzB,CAKQ,SAASA,CAAAA,CAAiC,CAE5C,KAAK,WAAA,EACP,IAAA,CAAK,YAAY,GAAA,CAAIA,CAAAA,CAAM,KAAA,CAAO,CAAA,aAAA,EAAgBA,EAAM,QAAQ,CAAA,CAAA,CAAIA,CAAK,CAAA,CAIvE,IAAA,CAAK,cACP,IAAA,CAAK,IAAA,CAAK,KAAKA,CAAK,CAAA,CAGhB,KAAK,IAAA,CAAK,MAAA,CAAS,KAAK,OAAA,EAC1B,IAAA,CAAK,KAAK,KAAA,EAAM,CAAA,CAKhB,IAAA,CAAK,YAAA,EACP,KAAK,SAAA,CAAUA,CAAK,EAExB,CAKQ,SAAA,CAAUA,EAAiC,CACjD,IAAA,CAAK,UAAA,CAAW,IAAA,CAAKA,CAAK,CAAA,CAGtB,IAAA,CAAK,WAAW,MAAA,EAAU,IAAA,CAAK,UAC5B,IAAA,CAAK,KAAA,EAAM,CAGhB,IAAA,CAAK,gBAET,CAKQ,eAAsB,CAExB,IAAA,CAAK,YACP,YAAA,CAAa,IAAA,CAAK,UAAU,CAAA,CAI9B,IAAA,CAAK,WAAa,UAAA,CAAW,IAAM,CAC5B,IAAA,CAAK,KAAA,GACZ,CAAA,CAAG,IAAA,CAAK,eAAe,EACzB,CAKA,MAAM,KAAA,EAAuB,CAE3B,GAAI,IAAA,CAAK,YAAc,IAAA,CAAK,UAAA,CAAW,MAAA,GAAW,CAAA,CAChD,OAIE,IAAA,CAAK,UAAA,GACP,aAAa,IAAA,CAAK,UAAU,EAC5B,IAAA,CAAK,UAAA,CAAa,MAAA,CAAA,CAGpB,IAAA,CAAK,WAAa,IAAA,CAGlB,IAAMmB,EAAa,CAAC,GAAG,KAAK,UAAU,CAAA,CACtC,IAAA,CAAK,UAAA,CAAa,EAAC,CAEnB,GAAI,CACF,IAAM1O,CAAAA,CAAW,MAAM,KAAA,CAAM,CAAA,EAAG,IAAA,CAAK,SAAS,iCAAkC,CAC9E,MAAA,CAAQ,OACR,OAAA,CAAS,CACP,eAAgB,kBAAA,CAChB,yBAAA,CAA2B,IAAA,CAAK,mBAClC,EACA,IAAA,CAAM,IAAA,CAAK,UAAU,CACnB,IAAA,CAAM0O,EACN,SAAA,CAAW,IAAA,CAAK,QAAA,CAChB,aAAA,CAAe,KAAK,YACtB,CAAC,CACH,CAAC,CAAA,CAEI1O,EAAS,EAAA,CAGR,IAAA,CAAK,aACP,IAAA,CAAK,WAAA,CAAY,IAAI,OAAA,CAAS,CAAA,kBAAA,EAAqB0O,EAAW,MAAM,CAAA,eAAA,CAAiB,EAHvF,IAAA,CAAK,iBAAA,CAAkBA,CAAAA,CAAY,CAAA,KAAA,EAAQ1O,EAAS,MAAM,CAAA,EAAA,EAAKA,EAAS,UAAU,CAAA,CAAE,EAMxF,CAAA,MAASvB,CAAAA,CAAO,CACd,IAAA,CAAK,kBAAkBiQ,CAAAA,CAAYjQ,CAAAA,YAAiB,MAAQA,CAAAA,CAAM,OAAA,CAAU,OAAOA,CAAK,CAAC,EAC3F,CAAA,OAAE,CACA,IAAA,CAAK,UAAA,CAAa,MACpB,CACF,CAKQ,kBAAkBkQ,CAAAA,CAA4B3F,CAAAA,CAAsB,CAM1E,GALI,KAAK,WAAA,EACP,IAAA,CAAK,YAAY,GAAA,CAAI,MAAA,CAAQ,+CAA+CA,CAAM,CAAA,CAAE,CAAA,CAIlF,IAAA,CAAK,YACP,IAAA,IAAW4F,CAAAA,IAAOD,EAEX,IAAA,CAAK,IAAA,CAAK,KAAME,CAAAA,EAAMA,CAAAA,CAAE,EAAA,GAAOD,CAAAA,CAAI,EAAE,CAAA,GACxC,IAAA,CAAK,KAAK,IAAA,CAAKA,CAAG,EAGd,IAAA,CAAK,IAAA,CAAK,MAAA,CAAS,IAAA,CAAK,SAC1B,IAAA,CAAK,IAAA,CAAK,OAAM,EAK1B,CAKQ,mBAA4B,CAElC,OAAI,OAAO,MAAA,CAAW,GAAA,EAAe,OAAO,UAAA,CACnC,MAAA,CAAO,YAAW,CAIpB,sCAAA,CAAuC,QAAQ,OAAA,CAAUE,CAAAA,EAAM,CACpE,IAAMC,EAAK,IAAA,CAAK,MAAA,GAAW,EAAA,CAAM,CAAA,CAEjC,QADUD,CAAAA,GAAM,GAAA,CAAMC,CAAAA,CAAKA,CAAAA,CAAI,EAAO,CAAA,EAC7B,QAAA,CAAS,EAAE,CACtB,CAAC,CACH,CAKQ,eAAA,EAA0B,CAChC,OAAO,GAAG,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA,EAAI,IAAA,CAAK,QAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,UAAU,CAAA,CAAG,CAAC,CAAC,CAAA,CACpE,CACF,EAQO,SAASC,EAAAA,CAAuBxQ,CAAAA,CAA2D,CAChG,OAAKA,CAAAA,CAAQ,OAAA,CAIN,IAAIiQ,CAAAA,CAAiBjQ,CAAO,EAH1B,IAIX,CCvdA,eAAsByQ,EAAAA,CACpBC,EACAvO,CAAAA,CACiB,CAEjB,IAAM0H,CAAAA,CAAO,MAAM1H,EAAO,MAAA,CAAOuO,CAAY,CAAA,CAGvCC,CAAAA,CAAW9G,EAAK,KAAA,CAAM,CAAA,CAAGA,EAAK,MAAA,CAAS,CAAC,EAG9C,OAAOtH,CAAAA,CAAgBoO,CAAQ,CACjC,CCzBO,SAASC,EAAAA,CACdC,CAAAA,CACA/H,EACY,CACZ,OAAO,IAAI,OAAA,CAAQ,CAACC,CAAAA,CAASC,CAAAA,GAAW,CACtC,IAAM8H,CAAAA,CAAiB,IAAIlR,CAAAA,CACzB,qBAAA,CACA,yBACF,CAAA,CAGA,GAAIkJ,CAAAA,CAAO,OAAA,CAAS,CAClBE,CAAAA,CAAO8H,CAAc,EACrB,MACF,CAEA,IAAMC,CAAAA,CAAU,IAAM,CACpB/H,CAAAA,CAAO8H,CAAc,EACvB,CAAA,CAEAhI,EAAO,gBAAA,CAAiB,OAAA,CAASiI,EAAS,CAAE,IAAA,CAAM,IAAK,CAAC,CAAA,CAExDF,EACG,IAAA,CAAK9H,CAAO,EACZ,KAAA,CAAMC,CAAM,EACZ,OAAA,CAAQ,IAAM,CACbF,CAAAA,CAAO,oBAAoB,OAAA,CAASiI,CAAO,EAC7C,CAAC,EACL,CAAC,CACH,CAWO,SAASC,EAAAA,CACdC,EAKA,CACA,IAAMC,EAAa,IAAI,eAAA,CAEvB,OAAO,CACL,OAAA,CAASD,CAAAA,CAAGC,CAAAA,CAAW,MAAM,CAAA,CAC7B,MAAA,CAAQ,IAAMA,CAAAA,CAAW,KAAA,GACzB,MAAA,CAAQA,CAAAA,CAAW,MACrB,CACF,CAKO,SAASC,EAAAA,CAAoBlR,CAAAA,CAAyB,CAC3D,OAAOA,CAAAA,YAAiBL,GAAgBK,CAAAA,CAAM,IAAA,GAAS,qBACzD,CAUA,eAAsBmR,EAAAA,CACpBC,CAAAA,CAIY,CACZ,GAAI,CACF,IAAMzK,CAAAA,CAAS,MAAM,OAAA,CAAQ,IAAA,CAAKyK,EAAW,GAAA,CAAKC,CAAAA,EAAOA,EAAG,OAAO,CAAC,EAEpE,OAAAD,CAAAA,CAAW,OAAA,CAASC,CAAAA,EAAOA,EAAG,MAAA,EAAQ,EAC/B1K,CACT,CAAA,MAAS3G,EAAO,CAEd,MAAAoR,CAAAA,CAAW,OAAA,CAASC,GAAOA,CAAAA,CAAG,MAAA,EAAQ,CAAA,CAChCrR,CACR,CACF,CCzEA,IAAMsR,EAAAA,CAA4F,CAChG,WAAY,CAAA,CACZ,WAAA,CAAa,IACb,UAAA,CAAY,GAAA,CACZ,OAAQ,IACV,CAAA,CAWO,SAASC,EAAAA,CACd/G,EACAgH,CAAAA,CACAC,CAAAA,CACAvH,EACQ,CAER,IAAMwH,EAAmBF,CAAAA,CAAc,IAAA,CAAK,GAAA,CAAI,CAAA,CAAGhH,CAAO,CAAA,CAGpDmH,CAAAA,CAAc,KAAK,GAAA,CAAID,CAAAA,CAAkBD,CAAU,CAAA,CAGzD,GAAIvH,EAAQ,CACV,IAAM0H,EAAcD,CAAAA,CAAc,EAAA,CAC5BE,EAAc,IAAA,CAAK,MAAA,GAAWD,CAAAA,CAAcA,CAAAA,CAAc,CAAA,CAChE,OAAO,KAAK,GAAA,CAAI,CAAA,CAAG,KAAK,KAAA,CAAMD,CAAAA,CAAcE,CAAW,CAAC,CAC1D,CAEA,OAAOF,CACT,CAQO,SAASG,GAAMlJ,CAAAA,CAAYC,CAAAA,CAAqC,CACrE,OAAO,IAAI,OAAA,CAAQ,CAACC,EAASC,CAAAA,GAAW,CACtC,GAAIF,CAAAA,EAAQ,OAAA,CAAS,CACnBE,CAAAA,CAAO,IAAIpJ,EAAa,qBAAA,CAAuB,qBAAqB,CAAC,CAAA,CACrE,MACF,CAEA,IAAMqJ,CAAAA,CAAU,WAAWF,CAAAA,CAASF,CAAE,CAAA,CAEtC,GAAIC,EAAQ,CACV,IAAMiI,EAAU,IAAM,CACpB,aAAa9H,CAAO,CAAA,CACpBD,CAAAA,CAAO,IAAIpJ,EAAa,qBAAA,CAAuB,qBAAqB,CAAC,EACvE,CAAA,CACAkJ,EAAO,gBAAA,CAAiB,OAAA,CAASiI,CAAAA,CAAS,CAAE,KAAM,IAAK,CAAC,EAC1D,CACF,CAAC,CACH,CASA,eAAsBiB,GACpBf,CAAAA,CACAjR,CAAAA,CACY,CACZ,IAAMiS,CAAAA,CAAO,CAAE,GAAGV,EAAAA,CAAuB,GAAGvR,CAAQ,CAAA,CAC9C,CAAE,UAAA,CAAAkS,EAAY,WAAA,CAAAT,CAAAA,CAAa,WAAAC,CAAAA,CAAY,MAAA,CAAAvH,EAAQ,MAAA,CAAArB,CAAAA,CAAQ,WAAA,CAAAqJ,CAAAA,CAAa,QAAAC,CAAQ,CAAA,CAAIH,EAElFI,CAAAA,CAEJ,IAAA,IAAS5H,EAAU,CAAA,CAAGA,CAAAA,EAAWyH,CAAAA,CAAYzH,CAAAA,EAAAA,CAC3C,GAAI,CAEF,GAAI3B,GAAQ,OAAA,CACV,MAAM,IAAIlJ,CAAAA,CAAa,qBAAA,CAAuB,yBAAyB,CAAA,CAGzE,OAAO,MAAMqR,CAAAA,EACf,CAAA,MAAShR,CAAAA,CAAO,CAId,GAHAoS,CAAAA,CAAYpS,CAAAA,CAGRkR,EAAAA,CAAoBlR,CAAK,CAAA,CAC3B,MAAMA,EAIR,IAAMqS,CAAAA,CAAWH,EACbA,CAAAA,CAAYlS,CAAAA,CAAOwK,CAAO,CAAA,CAC1BxK,aAAiBL,CAAAA,EAAgBa,CAAAA,CAAiBR,CAAK,CAAA,CAG3D,GAAIwK,GAAWyH,CAAAA,EAAc,CAACI,CAAAA,CAC5B,MAAMrS,EAIR,IAAMsS,CAAAA,CAAUf,GAAsB/G,CAAAA,CAASgH,CAAAA,CAAaC,EAAYvH,CAAM,CAAA,CAG9EiI,IAAUnS,CAAAA,CAAOwK,CAAAA,CAAU,EAAG8H,CAAO,CAAA,CAGrC,MAAMR,EAAAA,CAAMQ,CAAAA,CAASzJ,CAAM,EAC7B,CAIF,MAAMuJ,CACR,CAUO,SAASG,EAAAA,CACdC,EACiE,CACjE,OAAO,CAAIxB,CAAAA,CAAsBjR,CAAAA,GACxBgS,EAAAA,CAAUf,CAAAA,CAAI,CAAE,GAAGwB,CAAAA,CAAgB,GAAGzS,CAAQ,CAAC,CAE1D,CAUO,SAAS0S,EAAAA,CACdpK,CAAAA,CACe,CACf,IAAMqK,CAAAA,CAAarK,aAAmB,OAAA,CAClCA,CAAAA,CAAQ,IAAI,aAAa,CAAA,CACzBA,EAAQ,aAAa,CAAA,EAAKA,EAAQ,aAAa,CAAA,CAEnD,GAAI,CAACqK,CAAAA,CACH,OAAO,IAAA,CAIT,IAAMC,CAAAA,CAAU,QAAA,CAASD,EAAY,EAAE,CAAA,CACvC,GAAI,CAAC,KAAA,CAAMC,CAAO,CAAA,CAChB,OAAOA,CAAAA,CAAU,GAAA,CAInB,IAAMC,CAAAA,CAAO,IAAI,KAAKF,CAAU,CAAA,CAChC,GAAI,CAAC,KAAA,CAAME,CAAAA,CAAK,OAAA,EAAS,CAAA,CAAG,CAC1B,IAAMN,CAAAA,CAAUM,CAAAA,CAAK,SAAQ,CAAI,IAAA,CAAK,KAAI,CAC1C,OAAO,KAAK,GAAA,CAAI,CAAA,CAAGN,CAAO,CAC5B,CAEA,OAAO,IACT","file":"index.cjs","sourcesContent":["/**\n * Client Configuration\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport type { AuthrimStorage } from '../providers/storage.js';\n\n/**\n * Endpoint overrides\n */\nexport interface EndpointOverrides {\n /** Authorization endpoint */\n authorization?: string;\n /** Token endpoint */\n token?: string;\n /** UserInfo endpoint */\n userinfo?: string;\n /** Revocation endpoint */\n revocation?: string;\n /** End session endpoint (null to disable) */\n endSession?: string | null;\n}\n\n/**\n * Hash options for storage key generation\n */\nexport interface HashOptions {\n /**\n * Hash length for storage keys\n *\n * Default: 16 characters (96 bits)\n * Alternative: 22 characters (132 bits) for lower collision risk\n */\n hashLength?: number;\n}\n\n/**\n * Authrim Client Configuration\n */\nexport interface AuthrimClientConfig {\n /**\n * OpenID Connect issuer URL\n *\n * This is used to fetch the discovery document and validate tokens.\n * Trailing slashes are automatically normalized.\n */\n issuer: string;\n\n /**\n * OAuth 2.0 client ID\n */\n clientId: string;\n\n /**\n * HTTP client implementation\n *\n * Required for @authrim/core.\n * @authrim/web provides a default browser implementation.\n */\n http: HttpClient;\n\n /**\n * Crypto provider implementation\n *\n * Required for @authrim/core.\n * @authrim/web provides a default browser implementation.\n */\n crypto: CryptoProvider;\n\n /**\n * Storage provider implementation\n *\n * Required for @authrim/core.\n * @authrim/web provides localStorage/sessionStorage implementations.\n */\n storage: AuthrimStorage;\n\n /**\n * Default redirect URI for authorization requests\n */\n redirectUri?: string;\n\n /**\n * Default scopes to request\n *\n * Default: ['openid', 'profile']\n */\n scopes?: string[];\n\n /**\n * Manual endpoint overrides\n *\n * Use these to override discovery document endpoints.\n * Set endSession to null to disable logout redirect.\n */\n endpoints?: EndpointOverrides;\n\n /**\n * Enable Flow Engine (server-driven UI)\n *\n * Default: false\n * Set to true to enable server-driven UI flows.\n * Note: Both SDK and server must have Flow Engine enabled for it to work.\n */\n flowEngine?: boolean;\n\n /**\n * Discovery cache TTL in milliseconds\n *\n * Default: 3600000 (1 hour)\n */\n discoveryCacheTtlMs?: number;\n\n /**\n * Token refresh skew in seconds\n *\n * Refresh tokens this many seconds before expiration.\n * Default: 30\n */\n refreshSkewSeconds?: number;\n\n /**\n * State/nonce TTL in seconds\n *\n * Default: 600 (10 minutes)\n */\n stateTtlSeconds?: number;\n\n /**\n * Hash options for storage key generation\n */\n hashOptions?: HashOptions;\n}\n\n/**\n * Resolved configuration with defaults applied\n */\nexport interface ResolvedConfig extends Required<\n Omit<AuthrimClientConfig, 'endpoints' | 'redirectUri' | 'hashOptions'>\n> {\n endpoints?: EndpointOverrides;\n redirectUri?: string;\n hashOptions: Required<HashOptions>;\n}\n\n/**\n * Apply defaults to configuration\n */\nexport function resolveConfig(config: AuthrimClientConfig): ResolvedConfig {\n return {\n ...config,\n scopes: config.scopes ?? ['openid', 'profile'],\n flowEngine: config.flowEngine ?? false,\n discoveryCacheTtlMs: config.discoveryCacheTtlMs ?? 3600 * 1000,\n refreshSkewSeconds: config.refreshSkewSeconds ?? 30,\n stateTtlSeconds: config.stateTtlSeconds ?? 600,\n hashOptions: {\n hashLength: config.hashOptions?.hashLength ?? 16,\n },\n };\n}\n","/**\n * Authrim SDK Error Types\n */\n\n/**\n * User action recommended for error recovery\n */\nexport type AuthrimErrorUserAction =\n | 'retry'\n | 'reauthenticate'\n | 'contact_support'\n | 'check_network'\n | 'none';\n\n/**\n * Error severity level (legacy - 3 levels)\n */\nexport type AuthrimErrorSeverity = 'fatal' | 'error' | 'warning';\n\n/**\n * Error remediation action\n *\n * Specifies what action should be taken to recover from an error.\n * Separated from severity for clearer decision making.\n */\nexport type AuthrimErrorRemediation =\n | 'retry' // Retry the same operation\n | 'reauthenticate' // Re-authentication required\n | 'switch_flow' // Switch to different flow (e.g., popup → redirect)\n | 'contact_support' // Contact support\n | 'none'; // No action needed (informational)\n\n/**\n * Error metadata for recovery information\n */\nexport interface AuthrimErrorMeta {\n /** Whether this is a transient error */\n transient: boolean;\n /** Whether automatic retry is possible */\n retryable: boolean;\n /** Suggested retry wait time in milliseconds */\n retryAfterMs?: number;\n /** Maximum number of retry attempts */\n maxRetries?: number;\n /** Recommended user action */\n userAction: AuthrimErrorUserAction;\n /** Error severity level */\n severity: AuthrimErrorSeverity;\n}\n\n/**\n * Error codes used by the SDK\n */\nexport type AuthrimErrorCode =\n // OAuth 2.0 / OIDC standard errors\n | 'invalid_request'\n | 'unauthorized_client'\n | 'access_denied'\n | 'unsupported_response_type'\n | 'invalid_scope'\n | 'server_error'\n | 'temporarily_unavailable'\n | 'invalid_grant'\n | 'invalid_token'\n // SDK-specific errors\n | 'invalid_state'\n | 'expired_state'\n | 'invalid_nonce'\n | 'nonce_mismatch'\n | 'missing_nonce'\n | 'missing_id_token'\n | 'session_expired'\n | 'session_check_failed'\n | 'network_error'\n | 'timeout_error'\n | 'discovery_error'\n | 'discovery_mismatch'\n | 'configuration_error'\n | 'storage_error'\n | 'flow_engine_error'\n // Token errors\n | 'no_tokens'\n | 'token_expired'\n | 'token_error'\n | 'refresh_error'\n | 'token_exchange_error'\n // Callback errors\n | 'oauth_error'\n | 'missing_code'\n | 'missing_state'\n // Initialization errors\n | 'not_initialized'\n | 'no_discovery'\n // Session errors\n | 'no_userinfo_endpoint'\n | 'userinfo_error'\n // Token introspection/revocation errors\n | 'introspection_error'\n | 'revocation_error'\n | 'no_introspection_endpoint'\n | 'no_revocation_endpoint'\n // Silent auth errors (OIDC prompt=none)\n | 'login_required'\n | 'interaction_required'\n | 'consent_required'\n | 'account_selection_required'\n // Browser/Popup auth errors (@authrim/web)\n | 'dom_not_ready'\n | 'state_mismatch'\n | 'popup_blocked'\n | 'popup_closed'\n | 'invalid_response'\n | 'invalid_callback'\n // Direct Auth errors\n | 'passkey_not_found'\n | 'passkey_verification_failed'\n | 'passkey_not_supported'\n | 'passkey_cancelled'\n | 'passkey_invalid_credential'\n | 'email_code_invalid'\n | 'email_code_expired'\n | 'email_code_too_many_attempts'\n | 'challenge_expired'\n | 'challenge_invalid'\n | 'auth_code_invalid'\n | 'auth_code_expired'\n | 'pkce_mismatch'\n | 'origin_not_allowed'\n | 'mfa_required'\n | 'email_verification_required'\n | 'consent_required_direct'\n | 'rate_limited'\n // Event errors\n | 'event_handler_error'\n // PAR errors (RFC 9126)\n | 'par_required'\n | 'no_par_endpoint'\n | 'par_error'\n | 'par_request_uri_expired'\n // Device Flow errors (RFC 8628)\n | 'no_device_authorization_endpoint'\n | 'device_authorization_error'\n | 'device_authorization_pending'\n | 'device_slow_down'\n | 'device_authorization_expired'\n | 'device_access_denied'\n // Client Credentials errors\n | 'client_credentials_error'\n | 'invalid_client_authentication'\n | 'insecure_client_auth'\n // DPoP errors (RFC 9449)\n | 'dpop_key_generation_error'\n | 'dpop_proof_generation_error'\n | 'dpop_nonce_required'\n // JAR errors (RFC 9101)\n | 'jar_signing_error'\n | 'jar_required'\n // JARM errors\n | 'jarm_validation_error'\n | 'jarm_signature_invalid'\n // Operation errors\n | 'operation_cancelled'\n // returnTo errors\n | 'invalid_return_to';\n\n/**\n * Options for creating an AuthrimError\n */\nexport interface AuthrimErrorOptions {\n details?: Record<string, unknown>;\n errorUri?: string;\n cause?: Error;\n}\n\n/**\n * Authrim SDK Error class\n */\nexport class AuthrimError extends Error {\n /** Error code for programmatic handling */\n readonly code: AuthrimErrorCode;\n\n /** Additional error details */\n readonly details?: Record<string, unknown>;\n\n /** OAuth error_uri if provided */\n readonly errorUri?: string;\n\n /** Underlying cause */\n readonly cause?: Error;\n\n constructor(code: AuthrimErrorCode, message: string, options?: AuthrimErrorOptions) {\n super(message);\n this.name = 'AuthrimError';\n this.code = code;\n this.details = options?.details;\n this.errorUri = options?.errorUri;\n this.cause = options?.cause;\n }\n\n /**\n * Create an AuthrimError from an OAuth error response\n */\n static fromOAuthError(error: {\n error: string;\n error_description?: string;\n error_uri?: string;\n }): AuthrimError {\n const oauthCodes = [\n 'invalid_request',\n 'unauthorized_client',\n 'access_denied',\n 'unsupported_response_type',\n 'invalid_scope',\n 'server_error',\n 'temporarily_unavailable',\n 'invalid_grant',\n 'invalid_token',\n ] as const;\n\n type OAuthErrorCode = (typeof oauthCodes)[number];\n\n const code: AuthrimErrorCode = oauthCodes.includes(error.error as OAuthErrorCode)\n ? (error.error as OAuthErrorCode)\n : 'invalid_request';\n\n return new AuthrimError(code, error.error_description ?? error.error, {\n errorUri: error.error_uri,\n details: { originalError: error.error },\n });\n }\n\n /**\n * Check if an error is retryable (e.g., network errors)\n */\n isRetryable(): boolean {\n return this.code === 'network_error' || this.code === 'timeout_error';\n }\n\n /**\n * Get error metadata for recovery guidance\n */\n get meta(): AuthrimErrorMeta {\n return getErrorMeta(this.code);\n }\n}\n\n/**\n * Error metadata mapping for each error code\n */\nconst ERROR_META_MAP: Record<AuthrimErrorCode, AuthrimErrorMeta> = {\n // OAuth 2.0 / OIDC standard errors\n invalid_request: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'error',\n },\n unauthorized_client: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n access_denied: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n unsupported_response_type: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n invalid_scope: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'error',\n },\n server_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 5000,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'error',\n },\n temporarily_unavailable: {\n transient: true,\n retryable: true,\n retryAfterMs: 10000,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'warning',\n },\n invalid_grant: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n invalid_token: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // SDK-specific errors\n invalid_state: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n expired_state: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n invalid_nonce: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n nonce_mismatch: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n missing_nonce: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n missing_id_token: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n session_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n session_check_failed: {\n transient: true,\n retryable: true,\n retryAfterMs: 3000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'warning',\n },\n network_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 3,\n userAction: 'check_network',\n severity: 'error',\n },\n timeout_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 3000,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'warning',\n },\n discovery_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 5000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n discovery_mismatch: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n configuration_error: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n storage_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 1000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n flow_engine_error: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'error',\n },\n\n // Token errors\n no_tokens: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n token_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n token_error: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n refresh_error: {\n transient: false,\n retryable: false,\n retryAfterMs: 0,\n maxRetries: 0,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n token_exchange_error: {\n transient: false,\n retryable: false,\n retryAfterMs: 0,\n maxRetries: 0,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // Callback errors\n oauth_error: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n missing_code: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n missing_state: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // Initialization errors\n not_initialized: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'fatal',\n },\n no_discovery: {\n transient: true,\n retryable: true,\n retryAfterMs: 3000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n\n // Session errors\n no_userinfo_endpoint: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n userinfo_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n\n // Token introspection/revocation errors\n introspection_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n revocation_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n no_introspection_endpoint: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n no_revocation_endpoint: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n\n // Silent auth errors\n login_required: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n interaction_required: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n consent_required: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n account_selection_required: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n\n // Browser/Popup auth errors (@authrim/web)\n dom_not_ready: {\n transient: true,\n retryable: true,\n retryAfterMs: 100,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'error',\n },\n state_mismatch: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n popup_blocked: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n popup_closed: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n invalid_response: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'error',\n },\n invalid_callback: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // Direct Auth errors\n passkey_not_found: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n passkey_verification_failed: {\n transient: false,\n retryable: true,\n retryAfterMs: 1000,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'error',\n },\n passkey_not_supported: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n passkey_cancelled: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n passkey_invalid_credential: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n email_code_invalid: {\n transient: false,\n retryable: true,\n retryAfterMs: 0,\n maxRetries: 5,\n userAction: 'retry',\n severity: 'warning',\n },\n email_code_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n email_code_too_many_attempts: {\n transient: false,\n retryable: false,\n retryAfterMs: 300000,\n userAction: 'retry',\n severity: 'error',\n },\n challenge_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n challenge_invalid: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n auth_code_invalid: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n auth_code_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n pkce_mismatch: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n origin_not_allowed: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n mfa_required: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n email_verification_required: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n consent_required_direct: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n rate_limited: {\n transient: true,\n retryable: true,\n retryAfterMs: 60000,\n maxRetries: 3,\n userAction: 'retry',\n severity: 'warning',\n },\n\n // Event errors\n event_handler_error: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'warning',\n },\n\n // PAR errors (RFC 9126)\n par_required: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'fatal',\n },\n no_par_endpoint: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n par_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n par_request_uri_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n\n // Device Flow errors (RFC 8628)\n no_device_authorization_endpoint: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n device_authorization_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n device_authorization_pending: {\n transient: true,\n retryable: true,\n retryAfterMs: 5000,\n maxRetries: 60,\n userAction: 'none',\n severity: 'warning',\n },\n device_slow_down: {\n transient: true,\n retryable: true,\n retryAfterMs: 10000,\n maxRetries: 60,\n userAction: 'none',\n severity: 'warning',\n },\n device_authorization_expired: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'warning',\n },\n device_access_denied: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // Client Credentials errors\n client_credentials_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 2000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n invalid_client_authentication: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'fatal',\n },\n insecure_client_auth: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'fatal',\n },\n\n // DPoP errors (RFC 9449)\n dpop_key_generation_error: {\n transient: true,\n retryable: true,\n retryAfterMs: 1000,\n maxRetries: 2,\n userAction: 'retry',\n severity: 'error',\n },\n dpop_proof_generation_error: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'error',\n },\n dpop_nonce_required: {\n transient: true,\n retryable: true,\n retryAfterMs: 0,\n maxRetries: 1,\n userAction: 'none',\n severity: 'warning',\n },\n\n // JAR errors (RFC 9101)\n jar_signing_error: {\n transient: false,\n retryable: false,\n userAction: 'contact_support',\n severity: 'error',\n },\n jar_required: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'fatal',\n },\n\n // JARM errors\n jarm_validation_error: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n jarm_signature_invalid: {\n transient: false,\n retryable: false,\n userAction: 'reauthenticate',\n severity: 'error',\n },\n\n // Operation errors\n operation_cancelled: {\n transient: false,\n retryable: true,\n retryAfterMs: 0,\n maxRetries: 1,\n userAction: 'retry',\n severity: 'warning',\n },\n\n // returnTo errors\n invalid_return_to: {\n transient: false,\n retryable: false,\n userAction: 'none',\n severity: 'error',\n },\n};\n\n/**\n * Get error metadata for a given error code\n */\nexport function getErrorMeta(code: AuthrimErrorCode): AuthrimErrorMeta {\n return ERROR_META_MAP[code];\n}\n\n/**\n * Error classification result\n */\nexport interface ErrorClassification {\n /** Severity: recoverable or fatal */\n severity: 'recoverable' | 'fatal';\n /** Recommended remediation action */\n remediation: AuthrimErrorRemediation;\n}\n\n/**\n * Classify an error by severity and remediation\n *\n * This provides a simplified 2-axis classification for UI decision making:\n * - severity: Is this recoverable or fatal?\n * - remediation: What action should be taken?\n */\nexport function classifyError(error: AuthrimError): ErrorClassification {\n const meta = error.meta;\n\n // Fatal: not retryable AND user action is contact_support\n if (!meta.retryable && meta.userAction === 'contact_support') {\n return { severity: 'fatal', remediation: 'contact_support' };\n }\n\n // Fatal: severity is 'fatal' in meta\n if (meta.severity === 'fatal') {\n return { severity: 'fatal', remediation: mapUserActionToRemediation(meta.userAction) };\n }\n\n // Recoverable: determine remediation\n let remediation: AuthrimErrorRemediation = 'none';\n\n if (meta.retryable) {\n remediation = 'retry';\n } else if (meta.userAction === 'reauthenticate') {\n remediation = 'reauthenticate';\n } else if (error.code === 'popup_blocked') {\n remediation = 'switch_flow';\n } else if (meta.userAction === 'contact_support') {\n remediation = 'contact_support';\n }\n\n return { severity: 'recoverable', remediation };\n}\n\n/**\n * Map user action to remediation (internal helper)\n */\nfunction mapUserActionToRemediation(userAction: AuthrimErrorUserAction): AuthrimErrorRemediation {\n switch (userAction) {\n case 'retry':\n case 'check_network':\n return 'retry';\n case 'reauthenticate':\n return 'reauthenticate';\n case 'contact_support':\n return 'contact_support';\n case 'none':\n default:\n return 'none';\n }\n}\n\n/**\n * Check if an error is retryable based on classification\n */\nexport function isRetryableError(error: AuthrimError): boolean {\n const classification = classifyError(error);\n return classification.severity === 'recoverable' && classification.remediation === 'retry';\n}\n\n/**\n * Event emitter interface for error emission\n *\n * Minimal interface required by emitClassifiedError\n */\nexport interface ErrorEventEmitter {\n emit(event: 'error', payload: {\n error: AuthrimError;\n severity: 'recoverable' | 'fatal';\n remediation: AuthrimErrorRemediation;\n context: string;\n timestamp: number;\n source: 'core' | 'web';\n operationId?: string;\n }): void;\n emit(event: 'error:recoverable', payload: {\n error: AuthrimError;\n severity: 'recoverable';\n remediation: AuthrimErrorRemediation;\n context: string;\n timestamp: number;\n source: 'core' | 'web';\n operationId?: string;\n }): void;\n emit(event: 'error:fatal', payload: {\n error: AuthrimError;\n severity: 'fatal';\n remediation: AuthrimErrorRemediation;\n context: string;\n timestamp: number;\n source: 'core' | 'web';\n operationId?: string;\n }): void;\n}\n\n/**\n * Options for emitting classified errors\n */\nexport interface EmitClassifiedErrorOptions {\n /** Operation context where the error occurred */\n context: string;\n /** Operation tracking ID */\n operationId?: string;\n /** Event source (defaults to 'core') */\n source?: 'core' | 'web';\n}\n\n/**\n * Emit error events with proper classification\n *\n * Emits three events:\n * 1. 'error' - Legacy event for backward compatibility\n * 2. 'error:recoverable' - If severity is recoverable\n * 3. 'error:fatal' - If severity is fatal\n *\n * @param emitter - Event emitter instance\n * @param error - The error to emit\n * @param options - Emission options (context, operationId, source)\n */\nexport function emitClassifiedError(\n emitter: ErrorEventEmitter,\n error: AuthrimError,\n options: EmitClassifiedErrorOptions\n): void {\n const { severity, remediation } = classifyError(error);\n const timestamp = Date.now();\n const source = options.source ?? 'core';\n\n // Common payload\n const payload = {\n error,\n severity,\n remediation,\n context: options.context,\n timestamp,\n source,\n operationId: options.operationId,\n };\n\n // Legacy error event (backward compatibility)\n emitter.emit('error', payload);\n\n // Severity-specific events\n if (severity === 'recoverable') {\n emitter.emit('error:recoverable', { ...payload, severity: 'recoverable' as const });\n } else {\n emitter.emit('error:fatal', { ...payload, severity: 'fatal' as const });\n }\n}\n","/**\n * OIDC Discovery Client\n *\n * Fetches and caches OIDC Discovery documents from the authorization server.\n * https://openid.net/specs/openid-connect-discovery-1_0.html\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Cached discovery document with timestamp\n */\ninterface CachedDiscovery {\n doc: OIDCDiscoveryDocument;\n fetchedAt: number;\n}\n\n/**\n * Discovery client options\n */\nexport interface DiscoveryClientOptions {\n /** HTTP client for making requests */\n http: HttpClient;\n /** Cache TTL in milliseconds (default: 1 hour) */\n cacheTtlMs?: number;\n}\n\n/**\n * Normalize issuer URL\n *\n * Removes trailing slashes to ensure consistent comparison.\n *\n * @param issuer - Issuer URL\n * @returns Normalized issuer URL\n */\nexport function normalizeIssuer(issuer: string): string {\n return issuer.replace(/\\/+$/, '');\n}\n\n/**\n * OIDC Discovery Client\n */\nexport class DiscoveryClient {\n private readonly http: HttpClient;\n private readonly cacheTtlMs: number;\n private readonly cache: Map<string, CachedDiscovery> = new Map();\n\n /** Default cache TTL: 1 hour */\n private static readonly DEFAULT_CACHE_TTL_MS = 3600 * 1000;\n\n constructor(options: DiscoveryClientOptions) {\n this.http = options.http;\n this.cacheTtlMs = options.cacheTtlMs ?? DiscoveryClient.DEFAULT_CACHE_TTL_MS;\n }\n\n /**\n * Fetch the OIDC Discovery document for an issuer\n *\n * @param issuer - Issuer URL\n * @returns Discovery document\n * @throws AuthrimError if discovery fails or issuer mismatch\n */\n async discover(issuer: string): Promise<OIDCDiscoveryDocument> {\n const normalizedIssuer = normalizeIssuer(issuer);\n const cached = this.cache.get(normalizedIssuer);\n\n // Return cached document if still valid\n if (cached && !this.isExpired(cached)) {\n return cached.doc;\n }\n\n // Fetch discovery document\n const discoveryUrl = `${normalizedIssuer}/.well-known/openid-configuration`;\n\n let doc: OIDCDiscoveryDocument;\n try {\n const response = await this.http.fetch<OIDCDiscoveryDocument>(discoveryUrl);\n if (!response.ok) {\n throw new AuthrimError('discovery_error', `Discovery request failed: ${response.status}`, {\n details: { status: response.status, statusText: response.statusText },\n });\n }\n doc = response.data;\n } catch (error) {\n if (error instanceof AuthrimError) {\n throw error;\n }\n throw new AuthrimError('discovery_error', 'Failed to fetch discovery document', {\n cause: error instanceof Error ? error : undefined,\n details: { url: discoveryUrl },\n });\n }\n\n // Validate issuer matches (security check)\n const docIssuer = normalizeIssuer(doc.issuer);\n if (docIssuer !== normalizedIssuer) {\n throw new AuthrimError(\n 'discovery_mismatch',\n `Issuer mismatch in discovery document: expected \"${normalizedIssuer}\", got \"${docIssuer}\"`,\n {\n details: {\n expected: normalizedIssuer,\n actual: docIssuer,\n },\n }\n );\n }\n\n // Cache the document\n this.cache.set(normalizedIssuer, {\n doc,\n fetchedAt: Date.now(),\n });\n\n return doc;\n }\n\n /**\n * Check if a cached document has expired\n */\n private isExpired(cached: CachedDiscovery): boolean {\n return Date.now() - cached.fetchedAt > this.cacheTtlMs;\n }\n\n /**\n * Clear the discovery cache (useful for testing)\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Clear a specific issuer from the cache\n *\n * @param issuer - Issuer URL to clear\n */\n clearIssuer(issuer: string): void {\n this.cache.delete(normalizeIssuer(issuer));\n }\n}\n","/**\n * Event Emitter\n *\n * Simple typed event emitter for SDK events.\n */\n\nimport type { AuthrimEvents, AuthrimEventName, AuthrimEventHandler } from './types.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Typed Event Emitter\n */\nexport class EventEmitter {\n private listeners: Map<AuthrimEventName, Set<AuthrimEventHandler<AuthrimEventName>>> = new Map();\n\n /**\n * Subscribe to an event\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n */\n on<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(handler as AuthrimEventHandler<AuthrimEventName>);\n\n // Return unsubscribe function\n return () => {\n this.off(event, handler);\n };\n }\n\n /**\n * Subscribe to an event (one-time)\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n */\n once<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): () => void {\n const onceHandler = ((data: AuthrimEvents[T]) => {\n this.off(event, onceHandler);\n handler(data);\n }) as AuthrimEventHandler<T>;\n\n return this.on(event, onceHandler);\n }\n\n /**\n * Unsubscribe from an event\n *\n * @param event - Event name\n * @param handler - Event handler to remove\n */\n off<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n handlers.delete(handler as AuthrimEventHandler<AuthrimEventName>);\n if (handlers.size === 0) {\n this.listeners.delete(event);\n }\n }\n }\n\n /**\n * Emit an event\n *\n * @param event - Event name\n * @param data - Event data\n */\n emit<T extends AuthrimEventName>(event: T, data: AuthrimEvents[T]): void {\n const handlers = this.listeners.get(event);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(data);\n } catch (error) {\n // Don't throw - one handler failure shouldn't affect others\n // For non-error events, emit an 'error' event\n // For 'error' events, silently ignore to prevent infinite recursion\n if (event !== 'error') {\n const authrimError =\n error instanceof AuthrimError\n ? error\n : new AuthrimError('event_handler_error', 'Event handler threw an error', {\n cause: error instanceof Error ? error : undefined,\n });\n this.emit('error', {\n error: authrimError,\n context: `Error in event handler for '${event}'`,\n });\n }\n // For 'error' event handlers that throw, we silently ignore\n // to maintain platform-agnostic behavior (no console dependency)\n }\n }\n }\n }\n\n /**\n * Remove all listeners for an event (or all events)\n *\n * @param event - Event name (optional, removes all if not specified)\n */\n removeAllListeners(event?: AuthrimEventName): void {\n if (event) {\n this.listeners.delete(event);\n } else {\n this.listeners.clear();\n }\n }\n\n /**\n * Get the number of listeners for an event\n *\n * @param event - Event name\n * @returns Number of listeners\n */\n listenerCount(event: AuthrimEventName): number {\n return this.listeners.get(event)?.size ?? 0;\n }\n}\n","/**\n * PKCE (Proof Key for Code Exchange) Helper\n *\n * Implements RFC 7636 for Authorization Code Flow security.\n * https://tools.ietf.org/html/rfc7636\n */\n\nimport type { CryptoProvider } from '../providers/crypto.js';\n\n/**\n * PKCE challenge method\n */\nexport type CodeChallengeMethod = 'S256' | 'plain';\n\n/**\n * PKCE pair (verifier and challenge)\n */\nexport interface PKCEPair {\n /** Code verifier (high-entropy random string) */\n codeVerifier: string;\n /** Code challenge (derived from verifier) */\n codeChallenge: string;\n /** Challenge method used */\n codeChallengeMethod: CodeChallengeMethod;\n}\n\n/**\n * PKCE Helper class\n */\nexport class PKCEHelper {\n constructor(private readonly crypto: CryptoProvider) {}\n\n /**\n * Generate a PKCE pair (verifier + challenge)\n *\n * Uses S256 method (SHA-256 hash, base64url-encoded).\n *\n * @returns PKCE pair\n */\n async generatePKCE(): Promise<PKCEPair> {\n const codeVerifier = await this.crypto.generateCodeVerifier();\n const codeChallenge = await this.crypto.generateCodeChallenge(codeVerifier);\n\n return {\n codeVerifier,\n codeChallenge,\n codeChallengeMethod: 'S256',\n };\n }\n\n /**\n * Generate only the code verifier\n *\n * @returns Code verifier string\n */\n async generateCodeVerifier(): Promise<string> {\n return this.crypto.generateCodeVerifier();\n }\n\n /**\n * Generate a code challenge from a verifier\n *\n * @param verifier - Code verifier\n * @returns Code challenge (base64url-encoded SHA-256 hash)\n */\n async generateCodeChallenge(verifier: string): Promise<string> {\n return this.crypto.generateCodeChallenge(verifier);\n }\n}\n","/**\n * Base64URL Encoding/Decoding Utilities\n *\n * Implements RFC 4648 Section 5 (Base64 URL and Filename Safe Alphabet)\n */\n\n/**\n * Encode a Uint8Array to base64url string\n *\n * @param data - Bytes to encode\n * @returns Base64URL encoded string (no padding)\n */\nexport function base64urlEncode(data: Uint8Array): string {\n // Convert to base64\n let base64 = '';\n\n // Use platform-agnostic conversion\n const len = data.length;\n for (let i = 0; i < len; i += 3) {\n const byte1 = data[i];\n const byte2 = i + 1 < len ? data[i + 1] : 0;\n const byte3 = i + 2 < len ? data[i + 2] : 0;\n\n const triplet = (byte1 << 16) | (byte2 << 8) | byte3;\n\n base64 += BASE64_CHARS[(triplet >> 18) & 0x3f];\n base64 += BASE64_CHARS[(triplet >> 12) & 0x3f];\n base64 += i + 1 < len ? BASE64_CHARS[(triplet >> 6) & 0x3f] : '';\n base64 += i + 2 < len ? BASE64_CHARS[triplet & 0x3f] : '';\n }\n\n // Convert to base64url (replace + with -, / with _)\n // Remove padding (=)\n return base64.replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\n/**\n * Decode a base64url string to Uint8Array\n *\n * @param str - Base64URL encoded string\n * @returns Decoded bytes\n * @throws Error if the input contains invalid characters\n */\nexport function base64urlDecode(str: string): Uint8Array {\n // Validate input contains only valid base64url characters\n // Valid: A-Z, a-z, 0-9, -, _\n if (!/^[A-Za-z0-9_-]*$/.test(str)) {\n throw new Error('Invalid base64url string: contains invalid characters');\n }\n\n // Convert base64url to base64\n let base64 = str.replace(/-/g, '+').replace(/_/g, '/');\n\n // Add padding if needed\n while (base64.length % 4) {\n base64 += '=';\n }\n\n // Decode base64\n const len = base64.length;\n const paddingLen = base64.endsWith('==') ? 2 : base64.endsWith('=') ? 1 : 0;\n const outputLen = (len * 3) / 4 - paddingLen;\n const output = new Uint8Array(outputLen);\n\n let outputIndex = 0;\n for (let i = 0; i < len; i += 4) {\n const byte1 = BASE64_LOOKUP[base64.charCodeAt(i)];\n const byte2 = BASE64_LOOKUP[base64.charCodeAt(i + 1)];\n const byte3 = BASE64_LOOKUP[base64.charCodeAt(i + 2)];\n const byte4 = BASE64_LOOKUP[base64.charCodeAt(i + 3)];\n\n const triplet = (byte1 << 18) | (byte2 << 12) | (byte3 << 6) | byte4;\n\n if (outputIndex < outputLen) output[outputIndex++] = (triplet >> 16) & 0xff;\n if (outputIndex < outputLen) output[outputIndex++] = (triplet >> 8) & 0xff;\n if (outputIndex < outputLen) output[outputIndex++] = triplet & 0xff;\n }\n\n return output;\n}\n\n/**\n * Encode a string to base64url\n *\n * @param str - String to encode (UTF-8)\n * @returns Base64URL encoded string\n */\nexport function stringToBase64url(str: string): string {\n const encoder = new TextEncoder();\n return base64urlEncode(encoder.encode(str));\n}\n\n/**\n * Decode a base64url string to string\n *\n * @param base64url - Base64URL encoded string\n * @returns Decoded string (UTF-8)\n */\nexport function base64urlToString(base64url: string): string {\n const decoder = new TextDecoder();\n return decoder.decode(base64urlDecode(base64url));\n}\n\n// Base64 character set\nconst BASE64_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n// Lookup table for decoding\nconst BASE64_LOOKUP = new Uint8Array(256);\nfor (let i = 0; i < BASE64_CHARS.length; i++) {\n BASE64_LOOKUP[BASE64_CHARS.charCodeAt(i)] = i;\n}\n","/**\n * State/Nonce Manager\n *\n * Manages CSRF protection (state) and replay attack prevention (nonce)\n * for Authorization Code Flow.\n */\n\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport type { AuthrimStorage } from '../providers/storage.js';\nimport { AuthrimError } from '../types/errors.js';\nimport { base64urlEncode } from '../utils/base64url.js';\n\n/**\n * Auth state stored in storage\n */\nexport interface AuthState {\n /** State parameter (CSRF protection) */\n state: string;\n /** Nonce parameter (replay attack prevention) */\n nonce: string;\n /** PKCE code verifier */\n codeVerifier: string;\n /** Redirect URI used for this auth request */\n redirectUri: string;\n /** Requested scope (for validation) */\n scope: string;\n /** Timestamp when state was created */\n createdAt: number;\n /** Timestamp when state expires */\n expiresAt: number;\n /** Return URL after authentication (validated) */\n returnTo?: string;\n /** Operation tracking ID (for event correlation) */\n operationId: string;\n}\n\n/**\n * ReturnTo URL policy\n *\n * Controls which returnTo URLs are accepted to prevent open redirect attacks.\n */\nexport type ReturnToPolicy =\n | 'relative_only' // Default: relative paths only (/dashboard)\n | 'same_origin' // Same origin only\n | 'allowlist'; // Explicit allowlist\n\n/**\n * ReturnTo URL options\n */\nexport interface ReturnToOptions {\n /** Validation policy */\n policy: ReturnToPolicy;\n /** Allowed origins (required when policy is 'allowlist') */\n allowedOrigins?: string[];\n /** Current origin for same_origin check (required in non-browser environments) */\n currentOrigin?: string;\n}\n\n/**\n * Options for generating auth state\n */\nexport interface GenerateAuthStateOptions {\n /** Redirect URI for this auth request */\n redirectUri: string;\n /** Code verifier for PKCE */\n codeVerifier: string;\n /** Requested scope (for validation) */\n scope: string;\n /** TTL in seconds (default: 600 = 10 minutes) */\n ttlSeconds?: number;\n /** Return URL after authentication */\n returnTo?: string;\n /** ReturnTo URL validation options */\n returnToOptions?: ReturnToOptions;\n}\n\n/**\n * Storage keys factory\n */\nexport const STORAGE_KEYS = {\n /**\n * Auth state key (state-specific)\n */\n authState: (issuerHash: string, clientIdHash: string, state: string): string =>\n `authrim:${issuerHash}:${clientIdHash}:auth:${state}`,\n\n /**\n * Token storage key\n */\n tokens: (issuerHash: string, clientIdHash: string): string =>\n `authrim:${issuerHash}:${clientIdHash}:tokens`,\n\n /**\n * ID token storage key\n */\n idToken: (issuerHash: string, clientIdHash: string): string =>\n `authrim:${issuerHash}:${clientIdHash}:id_token`,\n\n /**\n * Auth state prefix for cleanup\n */\n authStatePrefix: (issuerHash: string, clientIdHash: string): string =>\n `authrim:${issuerHash}:${clientIdHash}:auth:`,\n} as const;\n\n/**\n * State Manager\n */\nexport class StateManager {\n /** Default TTL: 10 minutes */\n private static readonly DEFAULT_TTL_SECONDS = 600;\n\n /** Entropy bytes for state/nonce generation (256 bits = 32 bytes) */\n private static readonly ENTROPY_BYTES = 32;\n\n /** Entropy bytes for operationId (128 bits = 16 bytes, enough for tracking) */\n private static readonly OPERATION_ID_BYTES = 16;\n\n /** Auto cleanup interval (5 minutes) */\n private static readonly DEFAULT_CLEANUP_INTERVAL_MS = 300000;\n\n /** Cleanup interval handle */\n private cleanupInterval: ReturnType<typeof setInterval> | null = null;\n\n constructor(\n private readonly crypto: CryptoProvider,\n private readonly storage: AuthrimStorage,\n private readonly issuerHash: string,\n private readonly clientIdHash: string\n ) {}\n\n /**\n * Generate and store auth state\n *\n * Creates state, nonce, stores them with the code verifier.\n *\n * @param options - Generation options\n * @returns Generated state string\n */\n async generateAuthState(options: GenerateAuthStateOptions): Promise<AuthState> {\n const ttlSeconds = options.ttlSeconds ?? StateManager.DEFAULT_TTL_SECONDS;\n\n // Validate returnTo URL if provided\n let validatedReturnTo: string | undefined;\n if (options.returnTo) {\n validatedReturnTo = this.validateReturnTo(\n options.returnTo,\n options.returnToOptions ?? { policy: 'relative_only' }\n );\n }\n\n // Generate random state, nonce, and operationId (256-bit entropy each)\n const stateBytes = await this.crypto.randomBytes(StateManager.ENTROPY_BYTES);\n const nonceBytes = await this.crypto.randomBytes(StateManager.ENTROPY_BYTES);\n const operationIdBytes = await this.crypto.randomBytes(StateManager.OPERATION_ID_BYTES);\n\n const state = base64urlEncode(stateBytes);\n const nonce = base64urlEncode(nonceBytes);\n const operationId = base64urlEncode(operationIdBytes);\n\n const now = Date.now();\n const authState: AuthState = {\n state,\n nonce,\n codeVerifier: options.codeVerifier,\n redirectUri: options.redirectUri,\n scope: options.scope,\n createdAt: now,\n expiresAt: now + ttlSeconds * 1000,\n returnTo: validatedReturnTo,\n operationId,\n };\n\n // Store in storage\n const key = STORAGE_KEYS.authState(this.issuerHash, this.clientIdHash, state);\n await this.storage.set(key, JSON.stringify(authState));\n\n return authState;\n }\n\n /**\n * Validate returnTo URL against policy (Open Redirect Protection)\n *\n * @param returnTo - URL to validate\n * @param options - Validation options\n * @returns Validated URL\n * @throws AuthrimError if URL is invalid\n */\n private validateReturnTo(returnTo: string, options: ReturnToOptions): string {\n switch (options.policy) {\n case 'relative_only':\n // Only allow relative paths starting with /\n // Reject absolute URLs and protocol-relative URLs (//)\n if (returnTo.startsWith('/') && !returnTo.startsWith('//')) {\n // Additional check: ensure no protocol in the path\n if (!returnTo.includes(':')) {\n return returnTo;\n }\n }\n throw new AuthrimError(\n 'invalid_return_to',\n 'returnTo must be a relative path (e.g., /dashboard)'\n );\n\n case 'same_origin':\n try {\n // For non-browser environments, currentOrigin must be provided\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const globalWindow = typeof globalThis !== 'undefined' ? (globalThis as any).window : undefined;\n const currentOrigin = options.currentOrigin ?? (globalWindow?.location?.origin);\n if (!currentOrigin) {\n throw new AuthrimError(\n 'invalid_return_to',\n 'currentOrigin is required for same_origin policy in non-browser environments'\n );\n }\n\n // Handle relative URLs\n if (returnTo.startsWith('/') && !returnTo.startsWith('//')) {\n return returnTo;\n }\n\n // Check absolute URL\n const url = new URL(returnTo);\n if (url.origin === currentOrigin) {\n return returnTo;\n }\n } catch (e) {\n if (e instanceof AuthrimError) throw e;\n // URL parsing failed\n }\n throw new AuthrimError(\n 'invalid_return_to',\n 'returnTo must be same origin or a relative path'\n );\n\n case 'allowlist':\n if (!options.allowedOrigins || options.allowedOrigins.length === 0) {\n throw new AuthrimError(\n 'invalid_return_to',\n 'allowedOrigins is required when using allowlist policy'\n );\n }\n\n // Allow relative URLs\n if (returnTo.startsWith('/') && !returnTo.startsWith('//')) {\n return returnTo;\n }\n\n try {\n const parsed = new URL(returnTo);\n if (options.allowedOrigins.includes(parsed.origin)) {\n return returnTo;\n }\n } catch {\n // URL parsing failed\n }\n throw new AuthrimError(\n 'invalid_return_to',\n `returnTo origin not in allowlist: ${options.allowedOrigins.join(', ')}`\n );\n\n default:\n throw new AuthrimError(\n 'invalid_return_to',\n `Unknown returnTo policy: ${options.policy}`\n );\n }\n }\n\n /**\n * Validate and consume state\n *\n * Retrieves, validates, and ALWAYS deletes the state (success or failure).\n * This ensures replay attack prevention and GC.\n *\n * @param state - State parameter from callback\n * @returns Auth state if valid\n * @throws AuthrimError if state is invalid or expired\n */\n async validateAndConsumeState(state: string): Promise<AuthState> {\n const key = STORAGE_KEYS.authState(this.issuerHash, this.clientIdHash, state);\n\n try {\n const stored = await this.storage.get(key);\n\n if (!stored) {\n throw new AuthrimError('invalid_state', 'State not found or already used');\n }\n\n let authState: AuthState;\n try {\n authState = JSON.parse(stored);\n } catch {\n throw new AuthrimError('invalid_state', 'Malformed state data');\n }\n\n // Check expiration (no skew - strict)\n if (Date.now() > authState.expiresAt) {\n throw new AuthrimError('expired_state', 'State has expired');\n }\n\n return authState;\n } finally {\n // ALWAYS delete (success, failure, or exception)\n // This is critical for:\n // 1. Replay attack prevention\n // 2. GC of used/expired states\n await this.storage.remove(key);\n }\n }\n\n /**\n * Clean up expired states\n *\n * This is a best-effort cleanup. Only works if storage.getAll() is available.\n * The primary GC mechanism is validateAndConsumeState()'s finally delete.\n *\n * Safe to call at startup or periodically.\n */\n async cleanupExpiredStates(): Promise<void> {\n // Only works if storage supports getAll()\n if (!this.storage.getAll) {\n return;\n }\n\n const prefix = STORAGE_KEYS.authStatePrefix(this.issuerHash, this.clientIdHash);\n const all = await this.storage.getAll();\n const now = Date.now();\n\n for (const [key, value] of Object.entries(all)) {\n if (!key.startsWith(prefix)) {\n continue;\n }\n\n try {\n const authState: AuthState = JSON.parse(value);\n if (now > authState.expiresAt) {\n await this.storage.remove(key);\n }\n } catch {\n // Parse failure - delete corrupted entry\n await this.storage.remove(key);\n }\n }\n }\n\n /**\n * Start automatic cleanup of expired states\n *\n * Runs cleanup every 5 minutes by default.\n *\n * @param intervalMs - Cleanup interval in milliseconds (default: 300000 = 5 minutes)\n */\n startAutoCleanup(intervalMs: number = StateManager.DEFAULT_CLEANUP_INTERVAL_MS): void {\n this.stopAutoCleanup();\n\n this.cleanupInterval = setInterval(() => {\n this.cleanupExpiredStates().catch(() => {\n // Ignore cleanup errors\n });\n }, intervalMs);\n\n // Run initial cleanup\n this.cleanupExpiredStates().catch(() => {\n // Ignore cleanup errors\n });\n }\n\n /**\n * Stop automatic cleanup\n */\n stopAutoCleanup(): void {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n this.cleanupInterval = null;\n }\n }\n\n /**\n * Get the number of stored auth states\n *\n * Only works if storage.getAll() is available.\n *\n * @returns Number of stored states, or -1 if not supported\n */\n async getStoredStateCount(): Promise<number> {\n if (!this.storage.getAll) {\n return -1;\n }\n\n const prefix = STORAGE_KEYS.authStatePrefix(this.issuerHash, this.clientIdHash);\n const all = await this.storage.getAll();\n\n let count = 0;\n for (const key of Object.keys(all)) {\n if (key.startsWith(prefix)) {\n count++;\n }\n }\n\n return count;\n }\n}\n","/**\n * JWT Utilities\n *\n * Note: This module only provides decoding (parsing) functionality.\n * JWT signature verification MUST be performed by the server.\n * Never trust decoded JWT claims without server-side verification.\n */\n\nimport { base64urlToString } from './base64url.js';\nimport type { IdTokenClaims } from '../types/oidc.js';\n\n/**\n * JWT Header\n */\nexport interface JwtHeader {\n alg: string;\n typ?: string;\n kid?: string;\n [key: string]: unknown;\n}\n\n/**\n * Decoded JWT structure\n */\nexport interface DecodedJwt<T = Record<string, unknown>> {\n header: JwtHeader;\n payload: T;\n signature: string;\n}\n\n/**\n * Decode a JWT without verifying the signature\n *\n * WARNING: This function does NOT verify the JWT signature.\n * Use this only for reading claims after the token has been\n * validated by the authorization server.\n *\n * @param jwt - JWT string to decode\n * @returns Decoded JWT parts\n * @throws Error if the JWT format is invalid\n */\nexport function decodeJwt<T = Record<string, unknown>>(jwt: string): DecodedJwt<T> {\n const parts = jwt.split('.');\n if (parts.length !== 3) {\n throw new Error('Invalid JWT format: expected 3 parts');\n }\n\n const [headerB64, payloadB64, signature] = parts;\n\n try {\n const header = JSON.parse(base64urlToString(headerB64)) as JwtHeader;\n const payload = JSON.parse(base64urlToString(payloadB64)) as T;\n\n return {\n header,\n payload,\n signature,\n };\n } catch {\n throw new Error('Invalid JWT format: failed to decode');\n }\n}\n\n/**\n * Decode an ID token and extract claims\n *\n * WARNING: This function does NOT verify the ID token.\n * The token MUST be verified by the authorization server before use.\n *\n * @param idToken - ID token string\n * @returns ID token claims\n */\nexport function decodeIdToken(idToken: string): IdTokenClaims {\n const decoded = decodeJwt<IdTokenClaims>(idToken);\n return decoded.payload;\n}\n\n/**\n * Check if a JWT is expired\n *\n * @param jwt - Decoded JWT payload with exp claim\n * @param skewSeconds - Clock skew tolerance in seconds (default: 0)\n * @returns true if expired\n */\nexport function isJwtExpired(payload: { exp?: number }, skewSeconds: number = 0): boolean {\n if (payload.exp === undefined) {\n return false; // No expiration\n }\n\n const now = Math.floor(Date.now() / 1000);\n return payload.exp + skewSeconds < now;\n}\n\n/**\n * Get the nonce claim from an ID token\n *\n * @param idToken - ID token string\n * @returns nonce value or undefined\n */\nexport function getIdTokenNonce(idToken: string): string | undefined {\n try {\n const claims = decodeIdToken(idToken);\n return claims.nonce;\n } catch {\n return undefined;\n }\n}\n","/**\n * Timing-Safe Comparison Utilities\n *\n * Provides constant-time string comparison to prevent timing attacks.\n * Used for comparing security-sensitive values like nonces and states.\n */\n\n/**\n * Compare two strings in constant time\n *\n * This function always takes the same amount of time regardless of\n * where the strings differ, preventing timing attacks.\n *\n * @param a - First string\n * @param b - Second string\n * @returns true if strings are equal, false otherwise\n */\nexport function timingSafeEqual(a: string, b: string): boolean {\n // Encode strings to bytes for comparison\n const encoder = new TextEncoder();\n const aBytes = encoder.encode(a);\n const bBytes = encoder.encode(b);\n\n // Use byte array lengths for comparison\n const aLen = aBytes.length;\n const bLen = bBytes.length;\n\n // Use the longer length to ensure we compare all bytes\n const maxLen = Math.max(aLen, bLen);\n\n // XOR accumulator - will be non-zero if any bytes differ\n let result = aLen ^ bLen; // Start with length comparison\n\n // Compare all bytes, using 0 for out-of-bounds access\n for (let i = 0; i < maxLen; i++) {\n const aByte = i < aLen ? aBytes[i] : 0;\n const bByte = i < bLen ? bBytes[i] : 0;\n result |= aByte ^ bByte;\n }\n\n return result === 0;\n}\n","/**\n * Authorization Code Flow\n *\n * Implements OAuth 2.0 Authorization Code Flow with PKCE.\n * Uses 2-step pattern: buildAuthorizationUrl() + handleCallback()\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { TokenSet, TokenResponse } from '../types/token.js';\nimport type { AuthState } from './state.js';\nimport type { PKCEPair } from './pkce.js';\nimport { AuthrimError } from '../types/errors.js';\nimport { getIdTokenNonce } from '../utils/jwt.js';\nimport { timingSafeEqual } from '../utils/timing-safe.js';\nimport type { IDiagnosticLogger } from '../debug/diagnostic-logger.js';\n\n/**\n * Options for building authorization URL\n */\nexport interface BuildAuthorizationUrlOptions {\n /** Redirect URI (required) */\n redirectUri: string;\n /** Scopes to request (default: 'openid profile') */\n scope?: string;\n /**\n * Response type (default: 'code')\n *\n * Use 'none' for session check without token issuance\n * (OAuth 2.0 Multiple Response Types 1.0 §5)\n */\n responseType?: 'code' | 'none';\n /** Prompt behavior */\n prompt?: 'none' | 'login' | 'consent' | 'select_account';\n /** Hint about the login identifier */\n loginHint?: string;\n /** Requested Authentication Context Class Reference values */\n acrValues?: string;\n /** Additional custom parameters */\n extraParams?: Record<string, string>;\n /**\n * Expose state/nonce in result (for SSR/external storage)\n *\n * Default: false (security: state/nonce stay internal)\n * Set to true only when you need to store state externally\n * (e.g., cookie, server-side session)\n */\n exposeState?: boolean;\n /**\n * Use PAR (Pushed Authorization Request - RFC 9126)\n *\n * When true, authorization parameters are first pushed to the PAR endpoint,\n * and the resulting request_uri is used in the authorization URL.\n *\n * Required when server sets require_pushed_authorization_requests=true.\n */\n usePar?: boolean;\n /**\n * Use JAR (JWT Secured Authorization Request - RFC 9101)\n *\n * When true, authorization parameters are encoded in a signed JWT.\n *\n * Required when server sets require_signed_request_object=true.\n */\n useJar?: boolean;\n}\n\n/**\n * Result of buildAuthorizationUrl\n */\nexport interface AuthorizationUrlResult {\n /** Authorization URL to redirect to */\n url: string;\n /** State parameter (only if exposeState: true) */\n state?: string;\n /** Nonce parameter (only if exposeState: true) */\n nonce?: string;\n}\n\n/**\n * Internal authorization context (stored by StateManager)\n */\nexport interface AuthorizationContext {\n /** Auth state object */\n authState: AuthState;\n /** PKCE pair */\n pkce: PKCEPair;\n}\n\n/**\n * Options for exchanging authorization code\n */\nexport interface ExchangeCodeOptions {\n /** Authorization code */\n code: string;\n /** State parameter (for validation) */\n state: string;\n /** Redirect URI used in authorization request */\n redirectUri: string;\n /** Code verifier for PKCE */\n codeVerifier: string;\n /** Nonce to validate in ID token */\n nonce: string;\n /** Requested scope (for validation) */\n scope: string;\n}\n\n/**\n * Authorization Code Flow helper\n */\nexport class AuthorizationCodeFlow {\n private diagnosticLogger?: IDiagnosticLogger | null;\n\n constructor(\n private readonly http: HttpClient,\n private readonly clientId: string\n ) {}\n\n /**\n * Set diagnostic logger for this flow\n */\n setDiagnosticLogger(logger: IDiagnosticLogger | null | undefined): void {\n this.diagnosticLogger = logger;\n }\n\n /**\n * Build authorization URL\n *\n * @param discovery - OIDC discovery document\n * @param authState - Auth state from StateManager\n * @param pkce - PKCE pair\n * @param options - Authorization options\n * @returns Authorization URL result\n * @throws AuthrimError with code 'par_required' if server requires PAR but usePar is not enabled\n */\n buildAuthorizationUrl(\n discovery: OIDCDiscoveryDocument,\n authState: AuthState,\n pkce: PKCEPair,\n options: BuildAuthorizationUrlOptions\n ): AuthorizationUrlResult {\n // PAR enforcement guard: fail if server requires PAR but usePar is not enabled\n if (discovery.require_pushed_authorization_requests && !options.usePar) {\n throw new AuthrimError(\n 'par_required',\n 'Server requires PAR (Pushed Authorization Request) but usePar option is not enabled'\n );\n }\n\n // JAR enforcement guard: fail if server requires JAR but useJar is not enabled\n if (discovery.require_signed_request_object && !options.useJar) {\n throw new AuthrimError(\n 'jar_required',\n 'Server requires JAR (JWT Secured Authorization Request) but useJar option is not enabled'\n );\n }\n\n const endpoint = discovery.authorization_endpoint;\n const params = new URLSearchParams();\n\n // Required parameters\n params.set('client_id', this.clientId);\n params.set('response_type', options.responseType ?? 'code');\n params.set('redirect_uri', options.redirectUri);\n params.set('state', authState.state);\n params.set('nonce', authState.nonce);\n\n // PKCE parameters\n params.set('code_challenge', pkce.codeChallenge);\n params.set('code_challenge_method', pkce.codeChallengeMethod);\n\n // Scopes\n const scope = options.scope ?? 'openid profile';\n params.set('scope', scope);\n\n // Optional parameters\n if (options.prompt) {\n params.set('prompt', options.prompt);\n }\n if (options.loginHint) {\n params.set('login_hint', options.loginHint);\n }\n if (options.acrValues) {\n params.set('acr_values', options.acrValues);\n }\n\n // Extra custom parameters (with security parameter protection)\n if (options.extraParams) {\n // Security parameters that MUST NOT be overwritten\n const protectedParams = new Set([\n 'client_id',\n 'response_type',\n 'redirect_uri',\n 'state',\n 'nonce',\n 'code_challenge',\n 'code_challenge_method',\n 'scope',\n ]);\n\n for (const [key, value] of Object.entries(options.extraParams)) {\n if (protectedParams.has(key.toLowerCase())) {\n // Silently ignore attempts to override security parameters\n // This prevents CSRF, PKCE bypass, and other attacks\n continue;\n }\n params.set(key, value);\n }\n }\n\n const url = `${endpoint}?${params.toString()}`;\n\n // Build result\n const result: AuthorizationUrlResult = { url };\n\n if (options.exposeState) {\n result.state = authState.state;\n result.nonce = authState.nonce;\n }\n\n return result;\n }\n\n /**\n * Parse callback URL and extract code/state\n *\n * @param callbackUrl - Callback URL or query string\n * @returns Parsed code and state\n * @throws AuthrimError with code 'oauth_error' if OAuth error response is present\n * @throws AuthrimError with code 'missing_code' if authorization code is not found\n * @throws AuthrimError with code 'missing_state' if state parameter is not found\n */\n parseCallback(callbackUrl: string): { code: string; state: string } {\n let searchParams: URLSearchParams;\n\n // Support both full URL and query string\n if (callbackUrl.includes('?')) {\n const url = callbackUrl.startsWith('http')\n ? new URL(callbackUrl)\n : new URL(callbackUrl, 'https://dummy.local');\n searchParams = url.searchParams;\n } else {\n searchParams = new URLSearchParams(callbackUrl);\n }\n\n // Check for OAuth error response\n const error = searchParams.get('error');\n if (error) {\n const errorDescription = searchParams.get('error_description') ?? 'Authorization failed';\n throw new AuthrimError('oauth_error', errorDescription, {\n details: {\n error,\n error_description: errorDescription,\n error_uri: searchParams.get('error_uri'),\n },\n });\n }\n\n // Extract code and state\n const code = searchParams.get('code');\n const state = searchParams.get('state');\n\n if (!code) {\n throw new AuthrimError('missing_code', 'Authorization code not found in callback');\n }\n if (!state) {\n throw new AuthrimError('missing_state', 'State parameter not found in callback');\n }\n\n return { code, state };\n }\n\n /**\n * Exchange authorization code for tokens\n *\n * @param discovery - OIDC discovery document\n * @param options - Exchange options\n * @returns Token set\n * @throws AuthrimError with code 'network_error' if token request fails\n * @throws AuthrimError with code 'token_error' if token exchange fails\n * @throws AuthrimError with code 'nonce_mismatch' if ID token nonce validation fails\n */\n async exchangeCode(\n discovery: OIDCDiscoveryDocument,\n options: ExchangeCodeOptions\n ): Promise<TokenSet> {\n const tokenEndpoint = discovery.token_endpoint;\n\n // Build token request body\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: this.clientId,\n code: options.code,\n redirect_uri: options.redirectUri,\n code_verifier: options.codeVerifier,\n });\n\n // Make token request\n let response;\n try {\n response = await this.http.fetch<TokenResponse>(tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Token request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n throw new AuthrimError('token_error', 'Token exchange failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n const tokenResponse = response.data;\n\n // Check if openid scope was requested\n const requestedOpenId = options.scope.split(' ').includes('openid');\n\n // OIDC compliance: If openid scope was requested, id_token MUST be present\n if (requestedOpenId && !tokenResponse.id_token) {\n throw new AuthrimError(\n 'missing_id_token',\n 'ID token required when openid scope is requested but was not returned by the server'\n );\n }\n\n // Validate nonce in ID token (using constant-time comparison to prevent timing attacks)\n if (tokenResponse.id_token) {\n const idTokenNonce = getIdTokenNonce(tokenResponse.id_token);\n\n // Security: nonce MUST be present in id_token when it was sent in the request\n if (idTokenNonce === undefined) {\n // Log diagnostic\n this.diagnosticLogger?.logTokenValidation({\n step: 'nonce-check',\n tokenType: 'id_token',\n result: 'fail',\n expected: 'nonce claim present',\n actual: 'nonce claim missing',\n errorMessage: 'ID token nonce claim is missing but was sent in authorization request',\n });\n\n throw new AuthrimError(\n 'missing_nonce',\n 'ID token nonce claim is missing but was sent in authorization request'\n );\n }\n\n if (!timingSafeEqual(idTokenNonce, options.nonce)) {\n // Log diagnostic (without exposing nonce values)\n this.diagnosticLogger?.logTokenValidation({\n step: 'nonce-check',\n tokenType: 'id_token',\n result: 'fail',\n errorMessage: 'ID token nonce does not match expected value',\n });\n\n // Do not include nonce values in error details (security sensitive)\n throw new AuthrimError('nonce_mismatch', 'ID token nonce does not match expected value');\n }\n\n // Log successful nonce validation\n this.diagnosticLogger?.logTokenValidation({\n step: 'nonce-check',\n tokenType: 'id_token',\n result: 'pass',\n });\n }\n\n // Calculate expiresAt (epoch seconds)\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = tokenResponse.expires_in ? now + tokenResponse.expires_in : now + 3600; // Default to 1 hour if not provided\n\n // Build token set\n const tokenSet: TokenSet = {\n accessToken: tokenResponse.access_token,\n tokenType: (tokenResponse.token_type as 'Bearer') ?? 'Bearer',\n expiresAt,\n refreshToken: tokenResponse.refresh_token,\n idToken: tokenResponse.id_token,\n scope: tokenResponse.scope,\n };\n\n // Log successful authentication\n this.diagnosticLogger?.logAuthDecision({\n decision: 'allow',\n reason: 'Token exchange successful and ID token validation passed',\n flow: 'authorization_code',\n context: {\n hasAccessToken: !!tokenSet.accessToken,\n hasRefreshToken: !!tokenSet.refreshToken,\n hasIdToken: !!tokenSet.idToken,\n scope: tokenSet.scope,\n },\n });\n\n return tokenSet;\n }\n}\n","/**\n * PAR (Pushed Authorization Request) Client\n * RFC 9126: OAuth 2.0 Pushed Authorization Requests\n *\n * PAR allows the client to push the authorization request payload\n * to the authorization server via a direct POST request, receiving\n * a request_uri to use in the authorization URL.\n *\n * Benefits:\n * - Integrity protection of authorization request\n * - Confidentiality of authorization request parameters\n * - Support for large request parameters\n * - Required for FAPI 2.0 compliance\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { PARRequest, PARResponse, PARResult, PARClientOptions } from '../types/par.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * PAR Client\n *\n * Handles Pushed Authorization Requests per RFC 9126.\n */\nexport class PARClient {\n constructor(\n private readonly http: HttpClient,\n private readonly clientId: string,\n private readonly options?: PARClientOptions\n ) {}\n\n /**\n * Push authorization request to the server\n *\n * @param discovery - OIDC discovery document\n * @param request - PAR request parameters\n * @returns PAR result with request_uri and expiration\n * @throws AuthrimError with code 'no_par_endpoint' if PAR endpoint not available\n * @throws AuthrimError with code 'par_error' if PAR request fails\n */\n async pushAuthorizationRequest(\n discovery: OIDCDiscoveryDocument,\n request: PARRequest\n ): Promise<PARResult> {\n const parEndpoint = discovery.pushed_authorization_request_endpoint;\n\n if (!parEndpoint) {\n throw new AuthrimError(\n 'no_par_endpoint',\n 'PAR endpoint not available in discovery document'\n );\n }\n\n // Build PAR request body\n const body = new URLSearchParams();\n\n // Required parameters\n body.set('client_id', this.clientId);\n body.set('response_type', request.responseType ?? 'code');\n body.set('redirect_uri', request.redirectUri);\n body.set('state', request.state);\n body.set('nonce', request.nonce);\n body.set('code_challenge', request.codeChallenge);\n body.set('code_challenge_method', request.codeChallengeMethod);\n\n // Scopes\n body.set('scope', request.scope ?? 'openid profile');\n\n // Optional parameters\n if (request.prompt) {\n body.set('prompt', request.prompt);\n }\n if (request.loginHint) {\n body.set('login_hint', request.loginHint);\n }\n if (request.acrValues) {\n body.set('acr_values', request.acrValues);\n }\n\n // Extra custom parameters (with security parameter protection)\n if (request.extraParams) {\n const protectedParams = new Set([\n 'client_id',\n 'response_type',\n 'redirect_uri',\n 'state',\n 'nonce',\n 'code_challenge',\n 'code_challenge_method',\n 'scope',\n ]);\n\n for (const [key, value] of Object.entries(request.extraParams)) {\n if (protectedParams.has(key.toLowerCase())) {\n continue; // Silently ignore protected params\n }\n body.set(key, value);\n }\n }\n\n // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n ...this.options?.headers,\n };\n\n // Make PAR request\n let response;\n try {\n response = await this.http.fetch<PARResponse>(parEndpoint, {\n method: 'POST',\n headers,\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'PAR request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n throw new AuthrimError('par_error', 'PAR request failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n const parResponse = response.data;\n\n // Validate response\n if (!parResponse.request_uri) {\n throw new AuthrimError('par_error', 'PAR response missing request_uri');\n }\n if (typeof parResponse.expires_in !== 'number') {\n throw new AuthrimError('par_error', 'PAR response missing or invalid expires_in');\n }\n\n // Calculate absolute expiration\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = now + parResponse.expires_in;\n\n return {\n requestUri: parResponse.request_uri,\n expiresAt,\n };\n }\n\n /**\n * Build authorization URL using request_uri from PAR\n *\n * @param discovery - OIDC discovery document\n * @param requestUri - Request URI from PAR response\n * @returns Authorization URL\n */\n buildAuthorizationUrlWithPar(\n discovery: OIDCDiscoveryDocument,\n requestUri: string\n ): string {\n const params = new URLSearchParams();\n params.set('client_id', this.clientId);\n params.set('request_uri', requestUri);\n\n return `${discovery.authorization_endpoint}?${params.toString()}`;\n }\n}\n","/**\n * Device Authorization Flow\n * RFC 8628: OAuth 2.0 Device Authorization Grant\n *\n * Used for devices with limited input capabilities where the user\n * authenticates on a separate device (phone, computer).\n *\n * Flow:\n * 1. Client requests device code from authorization server\n * 2. User goes to verification URI and enters user code\n * 3. Client polls token endpoint until user completes auth\n *\n * NOTE: This core SDK returns \"facts\" only - UX events like\n * 'device:started' or 'device:pending' are the responsibility\n * of upper-layer SDKs (web/react/svelte).\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { TokenSet, TokenResponse } from '../types/token.js';\nimport type {\n DeviceAuthorizationResponse,\n DeviceFlowState,\n DeviceFlowPollResult,\n DeviceFlowStartOptions,\n} from '../types/device-flow.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/** Default polling interval in seconds (RFC 8628 §3.2) */\nconst DEFAULT_INTERVAL = 5;\n\n/**\n * Device Flow Client\n *\n * Handles the OAuth 2.0 Device Authorization Grant (RFC 8628).\n */\nexport class DeviceFlowClient {\n constructor(\n private readonly http: HttpClient,\n private readonly clientId: string\n ) {}\n\n /**\n * Start device authorization\n *\n * Requests a device code and user code from the authorization server.\n *\n * @param discovery - OIDC discovery document\n * @param options - Start options (scope, etc.)\n * @returns Device flow state with codes and URIs\n * @throws AuthrimError with code 'no_device_authorization_endpoint' if endpoint not available\n * @throws AuthrimError with code 'device_authorization_error' if request fails\n */\n async startDeviceAuthorization(\n discovery: OIDCDiscoveryDocument,\n options?: DeviceFlowStartOptions\n ): Promise<DeviceFlowState> {\n const endpoint = discovery.device_authorization_endpoint;\n\n if (!endpoint) {\n throw new AuthrimError(\n 'no_device_authorization_endpoint',\n 'Device authorization endpoint not available in discovery document'\n );\n }\n\n // Build request body\n const body = new URLSearchParams({\n client_id: this.clientId,\n });\n\n if (options?.scope) {\n body.set('scope', options.scope);\n }\n\n // Add extra parameters\n if (options?.extraParams) {\n const protectedParams = new Set(['client_id', 'scope']);\n\n for (const [key, value] of Object.entries(options.extraParams)) {\n if (protectedParams.has(key.toLowerCase())) {\n continue;\n }\n body.set(key, value);\n }\n }\n\n // Make request\n let response;\n try {\n response = await this.http.fetch<DeviceAuthorizationResponse>(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Device authorization request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n throw new AuthrimError('device_authorization_error', 'Device authorization request failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n const data = response.data;\n\n // Validate required fields\n if (!data.device_code || !data.user_code || !data.verification_uri) {\n throw new AuthrimError(\n 'device_authorization_error',\n 'Invalid device authorization response: missing required fields'\n );\n }\n\n // Calculate expiration\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = now + data.expires_in;\n\n return {\n deviceCode: data.device_code,\n userCode: data.user_code,\n verificationUri: data.verification_uri,\n verificationUriComplete: data.verification_uri_complete,\n expiresAt,\n interval: data.interval ?? DEFAULT_INTERVAL,\n };\n }\n\n /**\n * Poll the token endpoint once\n *\n * Returns the current state of the authorization:\n * - 'pending': User hasn't completed auth yet\n * - 'completed': Auth complete, tokens received\n * - 'slow_down': Polling too fast, increase interval\n * - 'expired': Device code expired\n * - 'access_denied': User denied the request\n *\n * @param discovery - OIDC discovery document\n * @param state - Device flow state from startDeviceAuthorization\n * @returns Poll result\n */\n async pollOnce(\n discovery: OIDCDiscoveryDocument,\n state: DeviceFlowState\n ): Promise<DeviceFlowPollResult> {\n // Check if expired\n const now = Math.floor(Date.now() / 1000);\n if (now >= state.expiresAt) {\n return { status: 'expired' };\n }\n\n const tokenEndpoint = discovery.token_endpoint;\n\n // Build request body\n const body = new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: state.deviceCode,\n client_id: this.clientId,\n });\n\n // Make token request\n let response;\n try {\n response = await this.http.fetch<TokenResponse | { error: string; error_description?: string }>(\n tokenEndpoint,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n }\n );\n } catch (error) {\n throw new AuthrimError('network_error', 'Device flow token request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n // Handle error responses (RFC 8628 §3.5)\n if (!response.ok) {\n const errorData = response.data as { error: string; error_description?: string };\n const errorCode = errorData?.error;\n\n switch (errorCode) {\n case 'authorization_pending':\n // User hasn't completed the authorization yet\n return {\n status: 'pending',\n retryAfter: state.interval,\n };\n\n case 'slow_down':\n // Polling too frequently - increase interval by 5 seconds (RFC 8628 §3.5)\n return {\n status: 'slow_down',\n retryAfter: state.interval + 5,\n };\n\n case 'expired_token':\n // Device code has expired\n return { status: 'expired' };\n\n case 'access_denied':\n // User denied the authorization request\n return { status: 'access_denied' };\n\n default:\n // Unknown error\n throw new AuthrimError('device_authorization_error', 'Device flow token request failed', {\n details: {\n status: response.status,\n error: errorCode,\n error_description: errorData?.error_description,\n },\n });\n }\n }\n\n // Success - tokens received\n const tokenResponse = response.data as TokenResponse;\n\n // Calculate expiresAt (epoch seconds)\n const expiresAt = tokenResponse.expires_in ? now + tokenResponse.expires_in : now + 3600;\n\n const tokens: TokenSet = {\n accessToken: tokenResponse.access_token,\n tokenType: (tokenResponse.token_type as 'Bearer') ?? 'Bearer',\n expiresAt,\n refreshToken: tokenResponse.refresh_token,\n idToken: tokenResponse.id_token,\n scope: tokenResponse.scope,\n };\n\n return {\n status: 'completed',\n tokens,\n };\n }\n\n /**\n * Poll until authorization is complete or expires\n *\n * Automatically handles polling interval and retries.\n *\n * @param discovery - OIDC discovery document\n * @param state - Device flow state from startDeviceAuthorization\n * @param options - Polling options\n * @returns Token set on success\n * @throws AuthrimError with code 'device_authorization_expired' if device code expires\n * @throws AuthrimError with code 'device_access_denied' if user denies authorization\n */\n async pollUntilComplete(\n discovery: OIDCDiscoveryDocument,\n state: DeviceFlowState,\n options?: { signal?: AbortSignal }\n ): Promise<TokenSet> {\n let currentInterval = state.interval;\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n // Check for abort\n if (options?.signal?.aborted) {\n throw new AuthrimError('device_authorization_error', 'Device flow polling aborted');\n }\n\n const result = await this.pollOnce(discovery, state);\n\n switch (result.status) {\n case 'completed':\n return result.tokens;\n\n case 'pending':\n // Wait and continue polling\n await this.sleep(result.retryAfter * 1000, options?.signal);\n continue;\n\n case 'slow_down':\n // Increase interval and continue polling\n currentInterval = result.retryAfter;\n // Update state for future polls\n state.interval = currentInterval;\n await this.sleep(currentInterval * 1000, options?.signal);\n continue;\n\n case 'expired':\n throw new AuthrimError(\n 'device_authorization_expired',\n 'Device authorization has expired. Please start a new authorization.'\n );\n\n case 'access_denied':\n throw new AuthrimError(\n 'device_access_denied',\n 'User denied the device authorization request'\n );\n }\n }\n }\n\n /**\n * Sleep for a given number of milliseconds\n * @param ms - Milliseconds to sleep\n * @param signal - Optional abort signal\n */\n private sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(resolve, ms);\n\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timeout);\n reject(new AuthrimError('device_authorization_error', 'Device flow polling aborted'));\n },\n { once: true }\n );\n }\n });\n }\n}\n","/**\n * DPoP Manager\n * RFC 9449: OAuth 2.0 Demonstrating Proof of Possession (DPoP)\n *\n * DPoP provides sender-constrained access tokens by binding them\n * to a cryptographic key held by the client. This prevents token theft\n * and replay attacks.\n *\n * NOTE: DPoP proofs are required for:\n * - Token requests (authorization code exchange, refresh)\n * - PAR requests\n * - UserInfo requests\n * - Any protected resource request\n *\n * Future consideration: HttpClient-level middleware for automatic DPoP proof attachment.\n */\n\nimport type {\n DPoPKeyPair,\n DPoPProofHeader,\n DPoPProofClaims,\n DPoPProofOptions,\n DPoPManagerConfig,\n DPoPCryptoProvider,\n JWK,\n} from '../types/dpop.js';\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport { AuthrimError } from '../types/errors.js';\nimport { base64urlEncode, stringToBase64url } from '../utils/base64url.js';\n\n/**\n * DPoP Manager\n *\n * Manages DPoP key pairs and generates DPoP proofs for requests.\n */\nexport class DPoPManager {\n private readonly crypto: CryptoProvider & DPoPCryptoProvider;\n private readonly config: DPoPManagerConfig;\n private keyPair: DPoPKeyPair | null = null;\n private serverNonce: string | null = null;\n\n constructor(\n crypto: CryptoProvider & DPoPCryptoProvider,\n config?: DPoPManagerConfig\n ) {\n this.crypto = crypto;\n this.config = config ?? {};\n }\n\n /**\n * Initialize the DPoP manager\n *\n * Generates or retrieves a DPoP key pair.\n *\n * @throws AuthrimError with code 'dpop_key_generation_error' if key generation fails\n */\n async initialize(): Promise<void> {\n // Check if crypto provider supports DPoP\n if (!this.crypto.generateDPoPKeyPair) {\n throw new AuthrimError(\n 'dpop_key_generation_error',\n 'CryptoProvider does not support DPoP key generation'\n );\n }\n\n // Try to get existing key pair\n if (this.crypto.getDPoPKeyPair) {\n const existing = await this.crypto.getDPoPKeyPair();\n if (existing) {\n this.keyPair = existing;\n return;\n }\n }\n\n // Generate new key pair\n try {\n this.keyPair = await this.crypto.generateDPoPKeyPair(\n this.config.algorithm ?? 'ES256'\n );\n } catch (error) {\n throw new AuthrimError(\n 'dpop_key_generation_error',\n 'Failed to generate DPoP key pair',\n { cause: error instanceof Error ? error : undefined }\n );\n }\n }\n\n /**\n * Check if DPoP is initialized\n */\n isInitialized(): boolean {\n return this.keyPair !== null;\n }\n\n /**\n * Generate a DPoP proof\n *\n * Creates a signed JWT proof for the specified HTTP method and URI.\n *\n * @param method - HTTP method (GET, POST, etc.)\n * @param uri - Full request URI (https://example.com/path)\n * @param options - Additional options (access token hash, nonce)\n * @returns Signed DPoP proof JWT\n * @throws AuthrimError with code 'dpop_proof_generation_error' if proof generation fails\n */\n async generateProof(\n method: string,\n uri: string,\n options?: DPoPProofOptions\n ): Promise<string> {\n if (!this.keyPair) {\n throw new AuthrimError(\n 'dpop_proof_generation_error',\n 'DPoP manager not initialized. Call initialize() first.'\n );\n }\n\n // Parse URI to get htu (without query and fragment)\n const url = new URL(uri);\n const htu = `${url.protocol}//${url.host}${url.pathname}`;\n\n // Build JWT header\n const header: DPoPProofHeader = {\n typ: 'dpop+jwt',\n alg: this.keyPair.algorithm,\n jwk: this.keyPair.publicKeyJwk,\n };\n\n // Build JWT claims\n const now = Math.floor(Date.now() / 1000);\n const claims: DPoPProofClaims = {\n jti: this.generateJti(),\n htm: method.toUpperCase(),\n htu,\n iat: now,\n };\n\n // Add optional claims\n if (options?.accessTokenHash) {\n claims.ath = options.accessTokenHash;\n }\n if (options?.nonce ?? this.serverNonce) {\n claims.nonce = options?.nonce ?? this.serverNonce ?? undefined;\n }\n\n // Encode and sign\n try {\n const headerB64 = stringToBase64url(JSON.stringify(header));\n const claimsB64 = stringToBase64url(JSON.stringify(claims));\n const signingInput = `${headerB64}.${claimsB64}`;\n\n const signature = await this.keyPair.sign(\n new TextEncoder().encode(signingInput)\n );\n const signatureB64 = base64urlEncode(signature);\n\n return `${signingInput}.${signatureB64}`;\n } catch (error) {\n throw new AuthrimError(\n 'dpop_proof_generation_error',\n 'Failed to generate DPoP proof',\n { cause: error instanceof Error ? error : undefined }\n );\n }\n }\n\n /**\n * Handle a DPoP-Nonce response from the server\n *\n * When the server returns a use_dpop_nonce error or includes\n * a DPoP-Nonce header, this method stores the nonce for future proofs.\n *\n * @param nonce - Server-provided nonce value\n */\n handleNonceResponse(nonce: string): void {\n this.serverNonce = nonce;\n }\n\n /**\n * Get the current server nonce\n */\n getServerNonce(): string | null {\n return this.serverNonce;\n }\n\n /**\n * Clear the server nonce\n */\n clearServerNonce(): void {\n this.serverNonce = null;\n }\n\n /**\n * Get the public key JWK\n *\n * @returns Public key in JWK format, or null if not initialized\n */\n getPublicKeyJwk(): JWK | null {\n return this.keyPair?.publicKeyJwk ?? null;\n }\n\n /**\n * Get the JWK thumbprint\n *\n * @returns Base64url-encoded thumbprint, or null if not initialized\n */\n getThumbprint(): string | null {\n return this.keyPair?.thumbprint ?? null;\n }\n\n /**\n * Calculate access token hash for ath claim\n *\n * @param accessToken - Access token to hash\n * @returns Base64url-encoded SHA-256 hash\n */\n async calculateAccessTokenHash(accessToken: string): Promise<string> {\n const hash = await this.crypto.sha256(accessToken);\n return base64urlEncode(hash);\n }\n\n /**\n * Clear the DPoP key pair\n *\n * Should be called on logout to clean up key material.\n */\n async clear(): Promise<void> {\n if (this.crypto.clearDPoPKeyPair) {\n await this.crypto.clearDPoPKeyPair();\n }\n this.keyPair = null;\n this.serverNonce = null;\n }\n\n /**\n * Generate a unique JWT ID (jti)\n */\n private generateJti(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n }\n}\n","/**\n * Token Types\n */\n\n/**\n * Token set returned from token endpoint\n *\n * Note: expiresAt is epoch seconds (not milliseconds)\n */\nexport interface TokenSet {\n /** Access token */\n accessToken: string;\n /** Refresh token (if provided) */\n refreshToken?: string;\n /** ID token (if openid scope was requested) */\n idToken?: string;\n /** Token type (always 'Bearer' for OAuth 2.0) */\n tokenType: 'Bearer';\n /**\n * Token expiration time as epoch seconds\n *\n * Calculated from expires_in at token exchange time:\n * expiresAt = Math.floor(Date.now() / 1000) + expires_in\n */\n expiresAt: number;\n /** Scope granted (may differ from requested scope) */\n scope?: string;\n}\n\n/**\n * Token endpoint response (raw)\n */\nexport interface TokenEndpointResponse {\n access_token: string;\n token_type: string;\n expires_in?: number;\n refresh_token?: string;\n id_token?: string;\n scope?: string;\n}\n\n/**\n * Alias for TokenEndpointResponse\n */\nexport type TokenResponse = TokenEndpointResponse;\n\n/**\n * Token exchange request (RFC 8693)\n */\nexport interface TokenExchangeRequest {\n /** The subject token to exchange */\n subjectToken: string;\n /** Subject token type (default: access_token) */\n subjectTokenType?: 'access_token' | 'refresh_token' | 'id_token';\n /** Target audience for the new token */\n audience?: string;\n /** Requested scope for the new token */\n scope?: string;\n /** Requested token type (default: access_token) */\n requestedTokenType?: 'access_token' | 'refresh_token' | 'id_token';\n /** Actor token (for delegation) */\n actorToken?: string;\n /** Actor token type */\n actorTokenType?: 'access_token' | 'id_token';\n}\n\n/**\n * Token exchange response (RFC 8693)\n *\n * Extends standard token response with issued_token_type\n */\nexport interface TokenExchangeResponse extends TokenEndpointResponse {\n /** URI of the issued token type */\n issued_token_type: string;\n}\n\n/**\n * Token type URIs (RFC 8693)\n */\nexport const TOKEN_TYPE_URIS = {\n access_token: 'urn:ietf:params:oauth:token-type:access_token',\n refresh_token: 'urn:ietf:params:oauth:token-type:refresh_token',\n id_token: 'urn:ietf:params:oauth:token-type:id_token',\n} as const;\n\n/**\n * Token type URI type\n */\nexport type TokenTypeUri = (typeof TOKEN_TYPE_URIS)[keyof typeof TOKEN_TYPE_URIS];\n\n/**\n * Token exchange result\n */\nexport interface TokenExchangeResult {\n /** Token set from exchange */\n tokens: TokenSet;\n /** Issued token type URI */\n issuedTokenType: TokenTypeUri | string;\n}\n","/**\n * Token Manager\n *\n * Manages token storage, retrieval, and automatic refresh.\n * Implements in-flight request coalescing for concurrent refresh requests.\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { AuthrimStorage } from '../providers/storage.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type {\n TokenSet,\n TokenResponse,\n TokenExchangeRequest,\n TokenExchangeResponse,\n TokenExchangeResult,\n} from '../types/token.js';\nimport { TOKEN_TYPE_URIS } from '../types/token.js';\nimport type { EventEmitter } from '../events/emitter.js';\nimport { AuthrimError, isRetryableError, emitClassifiedError } from '../types/errors.js';\nimport { STORAGE_KEYS } from '../auth/state.js';\n\n/**\n * Token manager options\n */\nexport interface TokenManagerOptions {\n /** HTTP client */\n http: HttpClient;\n /** Storage provider */\n storage: AuthrimStorage;\n /** Client ID */\n clientId: string;\n /** Issuer hash for storage keys */\n issuerHash: string;\n /** Client ID hash for storage keys */\n clientIdHash: string;\n /** Refresh skew in seconds (default: 30) */\n refreshSkewSeconds?: number;\n /** Event emitter for token events */\n eventEmitter?: EventEmitter;\n /** Token expiring warning threshold in seconds (default: 300 = 5 minutes) */\n expiringThresholdSeconds?: number;\n /** Jitter for expiring event in milliseconds (default: 30000 = ±30 seconds) */\n expiringJitterMs?: number;\n}\n\n/**\n * Token Manager\n *\n * Handles token storage, retrieval, and automatic refresh with\n * concurrent request coalescing.\n */\nexport class TokenManager {\n private readonly http: HttpClient;\n private readonly storage: AuthrimStorage;\n private readonly clientId: string;\n private readonly issuerHash: string;\n private readonly clientIdHash: string;\n private readonly refreshSkewSeconds: number;\n private readonly eventEmitter?: EventEmitter;\n private readonly expiringThresholdMs: number;\n private readonly expiringJitterMs: number;\n\n /** In-flight refresh promise for request coalescing */\n private refreshPromise: Promise<TokenSet> | null = null;\n\n /** Discovery document (set externally) */\n private discovery: OIDCDiscoveryDocument | null = null;\n\n /** Timer for token expiring event */\n private expiringTimeout: ReturnType<typeof setTimeout> | null = null;\n\n /** Whether this tab is the leader for refresh scheduling */\n private isLeaderTab = true;\n\n /** Current operation ID for event tracking */\n private currentOperationId: string | null = null;\n\n /** Default refresh skew: 30 seconds */\n private static readonly DEFAULT_REFRESH_SKEW_SECONDS = 30;\n\n /** Default expiring threshold: 5 minutes */\n private static readonly DEFAULT_EXPIRING_THRESHOLD_SECONDS = 300;\n\n /** Default expiring jitter: ±30 seconds */\n private static readonly DEFAULT_EXPIRING_JITTER_MS = 30000;\n\n constructor(options: TokenManagerOptions) {\n this.http = options.http;\n this.storage = options.storage;\n this.clientId = options.clientId;\n this.issuerHash = options.issuerHash;\n this.clientIdHash = options.clientIdHash;\n this.refreshSkewSeconds =\n options.refreshSkewSeconds ?? TokenManager.DEFAULT_REFRESH_SKEW_SECONDS;\n this.eventEmitter = options.eventEmitter;\n this.expiringThresholdMs =\n (options.expiringThresholdSeconds ?? TokenManager.DEFAULT_EXPIRING_THRESHOLD_SECONDS) * 1000;\n this.expiringJitterMs = options.expiringJitterMs ?? TokenManager.DEFAULT_EXPIRING_JITTER_MS;\n }\n\n /**\n * Set discovery document\n */\n setDiscovery(discovery: OIDCDiscoveryDocument): void {\n this.discovery = discovery;\n }\n\n /**\n * Get storage key for tokens\n */\n private get tokenKey(): string {\n return STORAGE_KEYS.tokens(this.issuerHash, this.clientIdHash);\n }\n\n /**\n * Get storage key for ID token\n */\n private get idTokenKey(): string {\n return STORAGE_KEYS.idToken(this.issuerHash, this.clientIdHash);\n }\n\n /**\n * Get current tokens from storage\n *\n * @returns Token set or null if not found\n */\n async getTokens(): Promise<TokenSet | null> {\n const stored = await this.storage.get(this.tokenKey);\n if (!stored) {\n return null;\n }\n\n try {\n return JSON.parse(stored) as TokenSet;\n } catch {\n // Corrupted data - clear and return null\n await this.clearTokens();\n return null;\n }\n }\n\n /**\n * Save tokens to storage\n *\n * @param tokens - Token set to save\n */\n async saveTokens(tokens: TokenSet): Promise<void> {\n await this.storage.set(this.tokenKey, JSON.stringify(tokens));\n\n // Also save ID token separately for logout\n if (tokens.idToken) {\n await this.storage.set(this.idTokenKey, tokens.idToken);\n }\n\n // Schedule expiring event\n this.scheduleExpiringEvent(tokens.expiresAt);\n }\n\n /**\n * Schedule token:expiring event with jitter\n *\n * @param expiresAt - Token expiration timestamp (epoch seconds)\n */\n private scheduleExpiringEvent(expiresAt: number): void {\n // Clear existing timeout\n if (this.expiringTimeout) {\n clearTimeout(this.expiringTimeout);\n this.expiringTimeout = null;\n }\n\n // Only schedule if we're the leader tab\n if (!this.isLeaderTab) {\n return;\n }\n\n const expiresAtMs = expiresAt * 1000;\n const warningTime = expiresAtMs - this.expiringThresholdMs;\n\n // Add jitter: random value between -jitter and +jitter\n const jitter = Math.random() * this.expiringJitterMs * 2 - this.expiringJitterMs;\n const delay = warningTime - Date.now() + jitter;\n\n // Only schedule if the warning time is in the future\n if (delay > 0) {\n this.expiringTimeout = setTimeout(() => {\n const now = Date.now();\n const expiresIn = Math.max(0, Math.floor((expiresAtMs - now) / 1000));\n\n this.eventEmitter?.emit('token:expiring', {\n expiresAt,\n expiresIn,\n timestamp: now,\n source: 'core',\n });\n }, delay);\n }\n }\n\n /**\n * Set leader tab status\n *\n * When not the leader, expiring event scheduling is disabled\n * to prevent multiple tabs from triggering simultaneous refreshes.\n *\n * @param isLeader - Whether this tab is the leader\n */\n setLeaderTab(isLeader: boolean): void {\n this.isLeaderTab = isLeader;\n\n if (!isLeader && this.expiringTimeout) {\n clearTimeout(this.expiringTimeout);\n this.expiringTimeout = null;\n }\n }\n\n /**\n * Set current operation ID for event tracking\n */\n setOperationId(operationId: string | null): void {\n this.currentOperationId = operationId;\n }\n\n /**\n * Get current operation ID\n */\n getOperationId(): string | null {\n return this.currentOperationId;\n }\n\n /**\n * Clear all tokens from storage\n */\n async clearTokens(): Promise<void> {\n await this.storage.remove(this.tokenKey);\n await this.storage.remove(this.idTokenKey);\n }\n\n /**\n * Get access token, refreshing if necessary\n *\n * This method coalesces concurrent refresh requests - if multiple\n * calls are made while a refresh is in-flight, they all share the\n * same refresh operation.\n *\n * @returns Access token\n * @throws AuthrimError if no tokens available or refresh fails\n */\n async getAccessToken(): Promise<string> {\n const tokens = await this.getTokens();\n\n if (!tokens) {\n throw new AuthrimError('no_tokens', 'No tokens available. Please authenticate first.');\n }\n\n // Check if token needs refresh (with skew)\n if (this.shouldRefresh(tokens)) {\n if (!tokens.refreshToken) {\n throw new AuthrimError(\n 'token_expired',\n 'Access token expired and no refresh token available'\n );\n }\n return this.refreshWithLock(tokens.refreshToken);\n }\n\n return tokens.accessToken;\n }\n\n /**\n * Get ID token\n *\n * @returns ID token or null\n */\n async getIdToken(): Promise<string | null> {\n const tokens = await this.getTokens();\n return tokens?.idToken ?? null;\n }\n\n /**\n * Check if token needs refresh\n *\n * @param tokens - Token set to check\n * @returns True if token should be refreshed\n */\n private shouldRefresh(tokens: TokenSet): boolean {\n const now = Math.floor(Date.now() / 1000);\n return tokens.expiresAt - this.refreshSkewSeconds <= now;\n }\n\n /**\n * Refresh token with in-flight request coalescing\n *\n * If a refresh is already in progress, wait for it instead of\n * starting a new one.\n *\n * @param refreshToken - Refresh token to use\n * @param reason - Reason for refresh\n * @returns Access token from new token set\n */\n private async refreshWithLock(\n refreshToken: string,\n reason: 'expiring' | 'manual' | 'on_demand' | 'background' = 'on_demand'\n ): Promise<string> {\n // If refresh is already in-flight, wait for it\n if (this.refreshPromise) {\n const tokens = await this.refreshPromise;\n return tokens.accessToken;\n }\n\n // Start new refresh operation\n this.refreshPromise = this.doRefreshWithRetry(refreshToken, reason);\n\n try {\n const tokens = await this.refreshPromise;\n return tokens.accessToken;\n } finally {\n // ALWAYS clear promise (success or failure)\n this.refreshPromise = null;\n }\n }\n\n /**\n * Manually refresh tokens\n *\n * @returns New token set\n * @throws AuthrimError if refresh fails\n */\n async refresh(): Promise<TokenSet> {\n const tokens = await this.getTokens();\n if (!tokens?.refreshToken) {\n throw new AuthrimError('no_tokens', 'No refresh token available');\n }\n\n // Start new refresh with manual reason\n if (this.refreshPromise) {\n return this.refreshPromise;\n }\n\n this.refreshPromise = this.doRefreshWithRetry(tokens.refreshToken, 'manual');\n\n try {\n return await this.refreshPromise;\n } finally {\n this.refreshPromise = null;\n }\n }\n\n /**\n * Perform refresh with retry for network errors\n *\n * @param refreshToken - Refresh token to use\n * @param reason - Reason for refresh\n * @param attempt - Current retry attempt (0-indexed)\n * @returns New token set\n */\n private async doRefreshWithRetry(\n refreshToken: string,\n reason: 'expiring' | 'manual' | 'on_demand' | 'background' = 'on_demand',\n attempt = 0\n ): Promise<TokenSet> {\n const maxRetries = 1;\n const timestamp = Date.now();\n\n // Emit refreshing event on first attempt\n if (attempt === 0) {\n this.eventEmitter?.emit('token:refreshing', {\n reason,\n timestamp,\n source: 'core',\n operationId: this.currentOperationId ?? undefined,\n });\n }\n\n try {\n return await this.doRefresh(refreshToken);\n } catch (error) {\n const authrimError = error instanceof AuthrimError\n ? error\n : new AuthrimError('refresh_error', 'Token refresh failed', {\n cause: error instanceof Error ? error : undefined,\n });\n\n const willRetry = attempt < maxRetries && isRetryableError(authrimError);\n\n // Emit refresh failed event\n this.eventEmitter?.emit('token:refresh:failed', {\n error: authrimError,\n willRetry,\n attempt,\n timestamp: Date.now(),\n source: 'core',\n operationId: this.currentOperationId ?? undefined,\n });\n\n // Retry once for retryable errors\n if (willRetry) {\n return this.doRefreshWithRetry(refreshToken, reason, attempt + 1);\n }\n\n // Emit auth:required if refresh failed and not retryable\n if (!isRetryableError(authrimError)) {\n this.eventEmitter?.emit('auth:required', {\n reason: 'refresh_failed',\n timestamp: Date.now(),\n source: 'core',\n operationId: this.currentOperationId ?? undefined,\n });\n }\n\n throw error;\n }\n }\n\n /**\n * Perform the actual token refresh\n *\n * @param refreshToken - Refresh token to use\n * @returns New token set\n */\n private async doRefresh(refreshToken: string): Promise<TokenSet> {\n if (!this.discovery) {\n throw new AuthrimError('no_discovery', 'Discovery document not set');\n }\n\n const tokenEndpoint = this.discovery.token_endpoint;\n\n // Build refresh request\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: this.clientId,\n refresh_token: refreshToken,\n });\n\n let response;\n try {\n response = await this.http.fetch<TokenResponse>(tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n const authrimError = new AuthrimError('network_error', 'Token refresh request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n this.eventEmitter?.emit('token:error', {\n error: authrimError,\n context: 'refresh',\n timestamp: Date.now(),\n source: 'core',\n });\n // Also emit classified error events (error:recoverable or error:fatal)\n if (this.eventEmitter) {\n emitClassifiedError(this.eventEmitter, authrimError, { context: 'refresh' });\n }\n throw authrimError;\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n const authrimError = new AuthrimError('refresh_error', 'Token refresh failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n this.eventEmitter?.emit('token:error', {\n error: authrimError,\n context: 'refresh',\n timestamp: Date.now(),\n source: 'core',\n });\n // Also emit classified error events (error:recoverable or error:fatal)\n if (this.eventEmitter) {\n emitClassifiedError(this.eventEmitter, authrimError, { context: 'refresh' });\n }\n throw authrimError;\n }\n\n const tokenResponse = response.data;\n\n // Calculate expiresAt\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = tokenResponse.expires_in ? now + tokenResponse.expires_in : now + 3600;\n\n // Build new token set (preserve old refresh token if new one not provided)\n const newTokens: TokenSet = {\n accessToken: tokenResponse.access_token,\n tokenType: (tokenResponse.token_type as 'Bearer') ?? 'Bearer',\n expiresAt,\n refreshToken: tokenResponse.refresh_token ?? refreshToken,\n idToken: tokenResponse.id_token,\n scope: tokenResponse.scope,\n };\n\n // Save new tokens\n await this.saveTokens(newTokens);\n\n // Emit event with new format (no token values for security)\n this.eventEmitter?.emit('token:refreshed', {\n hasAccessToken: !!newTokens.accessToken,\n hasRefreshToken: !!newTokens.refreshToken,\n hasIdToken: !!newTokens.idToken,\n expiresAt: newTokens.expiresAt,\n timestamp: Date.now(),\n source: 'core',\n operationId: this.currentOperationId ?? undefined,\n });\n\n return newTokens;\n }\n\n /**\n * Check if user is authenticated\n *\n * @returns True if valid tokens exist\n */\n async isAuthenticated(): Promise<boolean> {\n const tokens = await this.getTokens();\n if (!tokens) {\n return false;\n }\n\n // Check if access token is expired (without skew)\n const now = Math.floor(Date.now() / 1000);\n if (tokens.expiresAt <= now) {\n // Token expired - check if we have refresh token\n return !!tokens.refreshToken;\n }\n\n return true;\n }\n\n /**\n * Exchange a token using RFC 8693 Token Exchange\n *\n * This allows exchanging tokens for different audiences or scopes,\n * delegation scenarios, and cross-service token acquisition.\n *\n * @param request - Token exchange request parameters\n * @returns Token exchange result with new tokens and issued token type\n * @throws AuthrimError if exchange fails\n */\n async exchangeToken(request: TokenExchangeRequest): Promise<TokenExchangeResult> {\n if (!this.discovery) {\n throw new AuthrimError('no_discovery', 'Discovery document not set');\n }\n\n const tokenEndpoint = this.discovery.token_endpoint;\n\n // Map short token type names to URIs\n const subjectTokenType = this.mapTokenTypeToUri(request.subjectTokenType ?? 'access_token');\n\n // Build token exchange request\n const body = new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',\n client_id: this.clientId,\n subject_token: request.subjectToken,\n subject_token_type: subjectTokenType,\n });\n\n // Optional parameters\n if (request.audience) {\n body.set('audience', request.audience);\n }\n if (request.scope) {\n body.set('scope', request.scope);\n }\n if (request.requestedTokenType) {\n body.set('requested_token_type', this.mapTokenTypeToUri(request.requestedTokenType));\n }\n if (request.actorToken) {\n body.set('actor_token', request.actorToken);\n if (request.actorTokenType) {\n body.set('actor_token_type', this.mapTokenTypeToUri(request.actorTokenType));\n }\n }\n\n let response;\n try {\n response = await this.http.fetch<TokenExchangeResponse>(tokenEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n const authrimError = new AuthrimError('network_error', 'Token exchange request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n this.eventEmitter?.emit('token:error', {\n error: authrimError,\n context: 'exchange',\n timestamp: Date.now(),\n source: 'core',\n });\n // Also emit classified error events (error:recoverable or error:fatal)\n if (this.eventEmitter) {\n emitClassifiedError(this.eventEmitter, authrimError, { context: 'exchange' });\n }\n throw authrimError;\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n const authrimError = new AuthrimError('token_exchange_error', 'Token exchange failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n this.eventEmitter?.emit('token:error', {\n error: authrimError,\n context: 'exchange',\n timestamp: Date.now(),\n source: 'core',\n });\n // Also emit classified error events (error:recoverable or error:fatal)\n if (this.eventEmitter) {\n emitClassifiedError(this.eventEmitter, authrimError, { context: 'exchange' });\n }\n throw authrimError;\n }\n\n const tokenResponse = response.data;\n\n // Calculate expiresAt\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = tokenResponse.expires_in ? now + tokenResponse.expires_in : now + 3600;\n\n const tokens: TokenSet = {\n accessToken: tokenResponse.access_token,\n tokenType: (tokenResponse.token_type as 'Bearer') ?? 'Bearer',\n expiresAt,\n refreshToken: tokenResponse.refresh_token,\n idToken: tokenResponse.id_token,\n scope: tokenResponse.scope,\n };\n\n const result: TokenExchangeResult = {\n tokens,\n issuedTokenType: tokenResponse.issued_token_type,\n };\n\n // Emit event with new format (no token values for security)\n this.eventEmitter?.emit('token:exchanged', {\n hasAccessToken: !!tokens.accessToken,\n hasRefreshToken: !!tokens.refreshToken,\n issuedTokenType: tokenResponse.issued_token_type,\n timestamp: Date.now(),\n source: 'core',\n operationId: this.currentOperationId ?? undefined,\n });\n\n return result;\n }\n\n /**\n * Map short token type to URI (RFC 8693)\n */\n private mapTokenTypeToUri(type: 'access_token' | 'refresh_token' | 'id_token'): string {\n return TOKEN_TYPE_URIS[type];\n }\n\n /**\n * Clean up resources\n */\n destroy(): void {\n if (this.expiringTimeout) {\n clearTimeout(this.expiringTimeout);\n this.expiringTimeout = null;\n }\n }\n}\n","/**\n * Token Introspection (RFC 7662)\n *\n * Implements OAuth 2.0 Token Introspection to validate tokens server-side.\n * https://datatracker.ietf.org/doc/html/rfc7662\n */\n\nimport type { HttpClient, OAuthErrorResponse } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Token type hint for introspection\n */\nexport type IntrospectionTokenTypeHint = 'access_token' | 'refresh_token';\n\n/**\n * Token introspection response (RFC 7662)\n */\nexport interface IntrospectionResponse {\n /** Whether the token is active */\n active: boolean;\n /** Space-separated list of scopes (if active) */\n scope?: string;\n /** Client identifier (if active) */\n client_id?: string;\n /** Human-readable username (if active) */\n username?: string;\n /** Token type (e.g., \"Bearer\") */\n token_type?: string;\n /** Expiration time (Unix timestamp) */\n exp?: number;\n /** Issued at time (Unix timestamp) */\n iat?: number;\n /** Not before time (Unix timestamp) */\n nbf?: number;\n /** Subject identifier */\n sub?: string;\n /** Audience (single string or array) */\n aud?: string | string[];\n /** Issuer identifier */\n iss?: string;\n /** JWT ID */\n jti?: string;\n /** Additional claims */\n [key: string]: unknown;\n}\n\n/**\n * Token introspection options\n */\nexport interface IntrospectTokenOptions {\n /** Token to introspect */\n token: string;\n /** Hint about the token type (optional, helps server optimize lookup) */\n tokenTypeHint?: IntrospectionTokenTypeHint;\n}\n\n/**\n * Token introspector options\n */\nexport interface TokenIntrospectorOptions {\n /** HTTP client */\n http: HttpClient;\n /** Client ID */\n clientId: string;\n}\n\n/**\n * Token Introspector\n *\n * Handles token introspection requests to the authorization server.\n */\nexport class TokenIntrospector {\n private readonly http: HttpClient;\n private readonly clientId: string;\n\n constructor(options: TokenIntrospectorOptions) {\n this.http = options.http;\n this.clientId = options.clientId;\n }\n\n /**\n * Introspect a token\n *\n * Per RFC 7662, the introspection endpoint returns:\n * - { active: true, ... } for valid tokens with additional metadata\n * - { active: false } for invalid, expired, or revoked tokens\n *\n * @param discovery - OIDC discovery document\n * @param options - Introspection options\n * @returns Introspection response\n * @throws AuthrimError if introspection endpoint is not available or request fails\n */\n async introspect(\n discovery: OIDCDiscoveryDocument,\n options: IntrospectTokenOptions\n ): Promise<IntrospectionResponse> {\n const endpoint = discovery.introspection_endpoint;\n\n if (!endpoint) {\n throw new AuthrimError(\n 'no_introspection_endpoint',\n 'Authorization server does not support token introspection'\n );\n }\n\n return this.introspectWithEndpoint(endpoint, options);\n }\n\n /**\n * Introspect a token directly using the endpoint URL\n *\n * Use this when you have the endpoint URL but not the full discovery document.\n *\n * @param endpoint - Introspection endpoint URL\n * @param options - Introspection options\n * @returns Introspection response\n * @throws AuthrimError if request fails\n */\n async introspectWithEndpoint(\n endpoint: string,\n options: IntrospectTokenOptions\n ): Promise<IntrospectionResponse> {\n // Build introspection request\n const body = new URLSearchParams({\n client_id: this.clientId,\n token: options.token,\n });\n\n if (options.tokenTypeHint) {\n body.set('token_type_hint', options.tokenTypeHint);\n }\n\n let response;\n try {\n response = await this.http.fetch<IntrospectionResponse | OAuthErrorResponse>(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Token introspection request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n const errorData = response.data as OAuthErrorResponse | undefined;\n throw new AuthrimError('introspection_error', 'Token introspection failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n return response.data as IntrospectionResponse;\n }\n\n /**\n * Check if a token is active\n *\n * Convenience method that returns only the active status.\n *\n * @param discovery - OIDC discovery document\n * @param token - Token to check\n * @returns True if token is active\n */\n async isActive(discovery: OIDCDiscoveryDocument, token: string): Promise<boolean> {\n const result = await this.introspect(discovery, { token });\n return result.active;\n }\n}\n","/**\n * Token Revocation (RFC 7009)\n *\n * Implements OAuth 2.0 Token Revocation to explicitly invalidate tokens.\n * https://datatracker.ietf.org/doc/html/rfc7009\n */\n\nimport type { HttpClient, OAuthErrorResponse } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Token type hint for revocation\n */\nexport type TokenTypeHint = 'access_token' | 'refresh_token';\n\n/**\n * Token revocation options\n */\nexport interface RevokeTokenOptions {\n /** Token to revoke */\n token: string;\n /** Hint about the token type (optional, helps server optimize lookup) */\n tokenTypeHint?: TokenTypeHint;\n}\n\n/**\n * Token revoker options\n */\nexport interface TokenRevokerOptions {\n /** HTTP client */\n http: HttpClient;\n /** Client ID */\n clientId: string;\n}\n\n/**\n * Token Revoker\n *\n * Handles token revocation requests to the authorization server.\n */\nexport class TokenRevoker {\n private readonly http: HttpClient;\n private readonly clientId: string;\n\n constructor(options: TokenRevokerOptions) {\n this.http = options.http;\n this.clientId = options.clientId;\n }\n\n /**\n * Revoke a token\n *\n * Per RFC 7009, the revocation endpoint:\n * - Returns 200 OK on success (even if token was already invalid)\n * - Returns 400 for invalid requests\n * - Returns 503 if temporarily unavailable\n *\n * @param discovery - OIDC discovery document\n * @param options - Revocation options\n * @throws AuthrimError if revocation endpoint is not available or request fails\n */\n async revoke(discovery: OIDCDiscoveryDocument, options: RevokeTokenOptions): Promise<void> {\n const endpoint = discovery.revocation_endpoint;\n\n if (!endpoint) {\n throw new AuthrimError(\n 'no_revocation_endpoint',\n 'Authorization server does not support token revocation'\n );\n }\n\n // Build revocation request\n const body = new URLSearchParams({\n client_id: this.clientId,\n token: options.token,\n });\n\n if (options.tokenTypeHint) {\n body.set('token_type_hint', options.tokenTypeHint);\n }\n\n let response;\n try {\n response = await this.http.fetch<OAuthErrorResponse | void>(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Token revocation request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n // RFC 7009: 200 OK means success (even if token was already invalid)\n if (response.ok) {\n return;\n }\n\n // Handle error response\n const errorData = response.data as OAuthErrorResponse | undefined;\n throw new AuthrimError('revocation_error', 'Token revocation failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n /**\n * Revoke a token directly using the endpoint URL\n *\n * Use this when you have the endpoint URL but not the full discovery document.\n *\n * @param endpoint - Revocation endpoint URL\n * @param options - Revocation options\n * @throws AuthrimError if request fails\n */\n async revokeWithEndpoint(endpoint: string, options: RevokeTokenOptions): Promise<void> {\n // Build revocation request\n const body = new URLSearchParams({\n client_id: this.clientId,\n token: options.token,\n });\n\n if (options.tokenTypeHint) {\n body.set('token_type_hint', options.tokenTypeHint);\n }\n\n let response;\n try {\n response = await this.http.fetch<OAuthErrorResponse | void>(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Token revocation request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (response.ok) {\n return;\n }\n\n const errorData = response.data as OAuthErrorResponse | undefined;\n throw new AuthrimError('revocation_error', 'Token revocation failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n}\n","/**\n * Logout Handler\n *\n * Implements RP-Initiated Logout (OpenID Connect RP-Initiated Logout 1.0)\n * https://openid.net/specs/openid-connect-rpinitiated-1_0.html\n */\n\nimport type { AuthrimStorage } from '../providers/storage.js';\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { TokenSet } from '../types/token.js';\nimport type { EventEmitter } from '../events/emitter.js';\nimport type { EndpointOverrides } from '../client/config.js';\nimport { STORAGE_KEYS } from '../auth/state.js';\nimport { TokenRevoker } from '../token/revocation.js';\n\n/**\n * Logout options\n */\nexport interface LogoutOptions {\n /** URI to redirect to after logout */\n postLogoutRedirectUri?: string;\n /** ID token hint (optional, uses stored ID token if not provided) */\n idTokenHint?: string;\n /** State parameter for post-logout redirect */\n state?: string;\n /** Whether to revoke tokens before logout (requires revocation_endpoint) */\n revokeTokens?: boolean;\n}\n\n/**\n * Logout result\n */\nexport interface LogoutResult {\n /** Logout URL to redirect to (if IdP supports end_session_endpoint) */\n logoutUrl?: string;\n /** True if only local logout was performed (IdP doesn't support RP-Initiated Logout) */\n localOnly: boolean;\n /** Token revocation result (if revokeTokens was true) */\n revocation?: {\n /** Whether revocation was attempted */\n attempted: boolean;\n /** Whether access token revocation succeeded */\n accessTokenRevoked?: boolean;\n /** Whether refresh token revocation succeeded */\n refreshTokenRevoked?: boolean;\n /** Error if revocation failed (logout still proceeds) */\n error?: Error;\n };\n}\n\n/**\n * Logout handler options\n */\nexport interface LogoutHandlerOptions {\n /** Storage provider */\n storage: AuthrimStorage;\n /** HTTP client (for token revocation) */\n http: HttpClient;\n /** Client ID */\n clientId: string;\n /** Issuer hash for storage keys */\n issuerHash: string;\n /** Client ID hash for storage keys */\n clientIdHash: string;\n /** Event emitter */\n eventEmitter?: EventEmitter;\n /** Endpoint overrides */\n endpoints?: EndpointOverrides;\n}\n\n/**\n * Logout Handler\n */\nexport class LogoutHandler {\n private readonly storage: AuthrimStorage;\n private readonly clientId: string;\n private readonly issuerHash: string;\n private readonly clientIdHash: string;\n private readonly eventEmitter?: EventEmitter;\n private readonly endpoints?: EndpointOverrides;\n private readonly tokenRevoker: TokenRevoker;\n\n constructor(options: LogoutHandlerOptions) {\n this.storage = options.storage;\n this.clientId = options.clientId;\n this.issuerHash = options.issuerHash;\n this.clientIdHash = options.clientIdHash;\n this.eventEmitter = options.eventEmitter;\n this.endpoints = options.endpoints;\n this.tokenRevoker = new TokenRevoker({\n http: options.http,\n clientId: options.clientId,\n });\n }\n\n /**\n * Perform logout\n *\n * 1. Optionally revokes tokens at the authorization server (if revokeTokens=true)\n * 2. Clears local tokens (always)\n * 3. Emits session:ended event\n * 4. Builds logout URL if IdP supports end_session_endpoint\n *\n * @param discovery - OIDC discovery document\n * @param options - Logout options\n * @returns Logout result\n */\n async logout(\n discovery: OIDCDiscoveryDocument | null,\n options?: LogoutOptions\n ): Promise<LogoutResult> {\n // Get stored tokens BEFORE clearing (for revocation and logout URL)\n const storedIdToken = await this.getStoredIdToken();\n const storedTokens = await this.getStoredTokens();\n\n // Revoke tokens if requested\n let revocationResult: LogoutResult['revocation'];\n if (options?.revokeTokens && discovery?.revocation_endpoint && storedTokens) {\n revocationResult = await this.revokeTokens(discovery, storedTokens);\n }\n\n // Clear local tokens\n await this.clearTokens();\n\n // Emit session ended event\n this.eventEmitter?.emit('session:ended', {\n reason: 'logout',\n timestamp: Date.now(),\n source: 'core',\n });\n\n // Determine end_session_endpoint\n // Priority: config override > discovery > null\n let endSessionEndpoint: string | null | undefined;\n\n if (this.endpoints?.endSession !== undefined) {\n // Explicit override (can be null to disable)\n endSessionEndpoint = this.endpoints.endSession;\n } else if (discovery) {\n endSessionEndpoint = discovery.end_session_endpoint;\n }\n\n // If no end_session_endpoint, return local-only logout\n if (!endSessionEndpoint) {\n return { localOnly: true, revocation: revocationResult };\n }\n\n // Build logout URL (use stored token if not provided in options)\n const idToken = options?.idTokenHint ?? storedIdToken;\n\n const params = new URLSearchParams({\n client_id: this.clientId,\n });\n\n if (idToken) {\n params.set('id_token_hint', idToken);\n }\n if (options?.postLogoutRedirectUri) {\n params.set('post_logout_redirect_uri', options.postLogoutRedirectUri);\n }\n if (options?.state) {\n params.set('state', options.state);\n }\n\n return {\n logoutUrl: `${endSessionEndpoint}?${params.toString()}`,\n localOnly: false,\n revocation: revocationResult,\n };\n }\n\n /**\n * Revoke tokens at the authorization server\n *\n * Best-effort: if revocation fails, logout still proceeds\n *\n * @param discovery - OIDC discovery document\n * @param tokens - Tokens to revoke\n * @returns Revocation result\n */\n private async revokeTokens(\n discovery: OIDCDiscoveryDocument,\n tokens: TokenSet\n ): Promise<NonNullable<LogoutResult['revocation']>> {\n const result: NonNullable<LogoutResult['revocation']> = {\n attempted: true,\n };\n\n try {\n // Revoke refresh token first (if present) - this often invalidates access token too\n if (tokens.refreshToken) {\n await this.tokenRevoker.revoke(discovery, {\n token: tokens.refreshToken,\n tokenTypeHint: 'refresh_token',\n });\n result.refreshTokenRevoked = true;\n }\n\n // Revoke access token\n await this.tokenRevoker.revoke(discovery, {\n token: tokens.accessToken,\n tokenTypeHint: 'access_token',\n });\n result.accessTokenRevoked = true;\n } catch (error) {\n result.error = error instanceof Error ? error : new Error(String(error));\n }\n\n return result;\n }\n\n /**\n * Clear all tokens from storage\n */\n private async clearTokens(): Promise<void> {\n const tokenKey = STORAGE_KEYS.tokens(this.issuerHash, this.clientIdHash);\n const idTokenKey = STORAGE_KEYS.idToken(this.issuerHash, this.clientIdHash);\n\n await this.storage.remove(tokenKey);\n await this.storage.remove(idTokenKey);\n }\n\n /**\n * Get stored ID token\n */\n private async getStoredIdToken(): Promise<string | null> {\n const idTokenKey = STORAGE_KEYS.idToken(this.issuerHash, this.clientIdHash);\n return this.storage.get(idTokenKey);\n }\n\n /**\n * Get stored tokens\n */\n private async getStoredTokens(): Promise<TokenSet | null> {\n const tokenKey = STORAGE_KEYS.tokens(this.issuerHash, this.clientIdHash);\n const stored = await this.storage.get(tokenKey);\n if (!stored) {\n return null;\n }\n try {\n return JSON.parse(stored) as TokenSet;\n } catch {\n return null;\n }\n }\n}\n","/**\n * Token API Client\n *\n * Provides session verification against the authorization server.\n * Uses the UserInfo endpoint or custom session check endpoint.\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument, UserInfo } from '../types/oidc.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Session check result\n */\nexport interface SessionCheckResult {\n /** Whether session is valid */\n valid: boolean;\n /** User info if session is valid */\n user?: UserInfo;\n /** Error if session is invalid */\n error?: AuthrimError;\n}\n\n/**\n * Token API client options\n */\nexport interface TokenApiClientOptions {\n /** HTTP client */\n http: HttpClient;\n}\n\n/**\n * Token API Client\n *\n * Verifies session status with the authorization server.\n */\nexport class TokenApiClient {\n private readonly http: HttpClient;\n\n constructor(options: TokenApiClientOptions) {\n this.http = options.http;\n }\n\n /**\n * Check session validity by calling UserInfo endpoint\n *\n * @param discovery - OIDC discovery document\n * @param accessToken - Access token to verify\n * @returns Session check result\n */\n async checkSession(\n discovery: OIDCDiscoveryDocument,\n accessToken: string\n ): Promise<SessionCheckResult> {\n const userinfoEndpoint = discovery.userinfo_endpoint;\n\n if (!userinfoEndpoint) {\n return {\n valid: false,\n error: new AuthrimError('no_userinfo_endpoint', 'UserInfo endpoint not available'),\n };\n }\n\n try {\n const response = await this.http.fetch<UserInfo>(userinfoEndpoint, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (!response.ok) {\n // 401 means token is invalid/expired\n if (response.status === 401) {\n return {\n valid: false,\n error: new AuthrimError('session_expired', 'Session has expired'),\n };\n }\n\n return {\n valid: false,\n error: new AuthrimError('session_check_failed', 'Session check failed', {\n details: { status: response.status },\n }),\n };\n }\n\n return {\n valid: true,\n user: response.data,\n };\n } catch (error) {\n return {\n valid: false,\n error: new AuthrimError('network_error', 'Failed to check session', {\n cause: error instanceof Error ? error : undefined,\n }),\n };\n }\n }\n\n /**\n * Get user info from the authorization server\n *\n * @param discovery - OIDC discovery document\n * @param accessToken - Access token\n * @returns User info\n * @throws AuthrimError if request fails\n */\n async getUserInfo(discovery: OIDCDiscoveryDocument, accessToken: string): Promise<UserInfo> {\n const userinfoEndpoint = discovery.userinfo_endpoint;\n\n if (!userinfoEndpoint) {\n throw new AuthrimError('no_userinfo_endpoint', 'UserInfo endpoint not available');\n }\n\n let response;\n try {\n response = await this.http.fetch<UserInfo>(userinfoEndpoint, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${accessToken}`,\n },\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Failed to fetch user info', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n throw new AuthrimError('userinfo_error', 'Failed to get user info', {\n details: { status: response.status },\n });\n }\n\n return response.data;\n }\n}\n","/**\n * Session Manager\n *\n * Coordinates session-related operations including checking\n * session status and retrieving user information.\n */\n\nimport type { OIDCDiscoveryDocument, UserInfo } from '../types/oidc.js';\nimport type { TokenManager } from '../token/manager.js';\nimport { TokenApiClient, type SessionCheckResult } from './token-api.js';\nexport type { SessionCheckResult };\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Session manager options\n */\nexport interface SessionManagerOptions {\n /** Token manager */\n tokenManager: TokenManager;\n /** Token API client */\n tokenApiClient: TokenApiClient;\n}\n\n/**\n * Session Manager\n */\nexport class SessionManager {\n private readonly tokenManager: TokenManager;\n private readonly tokenApiClient: TokenApiClient;\n\n /** Discovery document */\n private discovery: OIDCDiscoveryDocument | null = null;\n\n constructor(options: SessionManagerOptions) {\n this.tokenManager = options.tokenManager;\n this.tokenApiClient = options.tokenApiClient;\n }\n\n /**\n * Set discovery document\n */\n setDiscovery(discovery: OIDCDiscoveryDocument): void {\n this.discovery = discovery;\n }\n\n /**\n * Check if user is authenticated locally\n *\n * This checks if valid tokens exist in storage.\n * Does not verify with the authorization server.\n *\n * @returns True if tokens exist\n */\n async isAuthenticated(): Promise<boolean> {\n return this.tokenManager.isAuthenticated();\n }\n\n /**\n * Check session validity with authorization server\n *\n * Calls the UserInfo endpoint to verify the session is still valid.\n *\n * @returns Session check result\n */\n async checkSession(): Promise<SessionCheckResult> {\n if (!this.discovery) {\n return {\n valid: false,\n error: new AuthrimError('no_discovery', 'Discovery document not available'),\n };\n }\n\n try {\n const accessToken = await this.tokenManager.getAccessToken();\n return this.tokenApiClient.checkSession(this.discovery, accessToken);\n } catch (error) {\n if (error instanceof AuthrimError) {\n return { valid: false, error };\n }\n return {\n valid: false,\n error: new AuthrimError('session_check_failed', 'Failed to check session', {\n cause: error instanceof Error ? error : undefined,\n }),\n };\n }\n }\n\n /**\n * Get user information\n *\n * Fetches user info from the UserInfo endpoint.\n *\n * @returns User info\n * @throws AuthrimError if not authenticated or request fails\n */\n async getUser(): Promise<UserInfo> {\n if (!this.discovery) {\n throw new AuthrimError('no_discovery', 'Discovery document not available');\n }\n\n const accessToken = await this.tokenManager.getAccessToken();\n return this.tokenApiClient.getUserInfo(this.discovery, accessToken);\n }\n}\n","/**\n * Authrim Client\n *\n * Main entry point for the Authrim SDK.\n */\n\nimport type { AuthrimClientConfig, ResolvedConfig } from './config.js';\nimport type { OIDCDiscoveryDocument, UserInfo } from '../types/oidc.js';\nimport type { TokenSet, TokenExchangeRequest, TokenExchangeResult } from '../types/token.js';\nimport type { AuthrimEventName, AuthrimEventHandler } from '../events/types.js';\nimport type { DeviceFlowState, DeviceFlowPollResult, DeviceFlowStartOptions } from '../types/device-flow.js';\nimport type { PARResult } from '../types/par.js';\nimport type { DPoPCryptoProvider } from '../types/dpop.js';\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport { resolveConfig } from './config.js';\nimport { DiscoveryClient, normalizeIssuer } from './discovery.js';\nimport { EventEmitter } from '../events/emitter.js';\nimport { PKCEHelper } from '../auth/pkce.js';\nimport { StateManager } from '../auth/state.js';\nimport {\n AuthorizationCodeFlow,\n type BuildAuthorizationUrlOptions,\n type AuthorizationUrlResult,\n} from '../auth/authorization-code.js';\nimport { PARClient } from '../auth/par.js';\nimport { DeviceFlowClient } from '../auth/device-flow.js';\nimport { DPoPManager } from '../security/dpop.js';\nimport { TokenManager } from '../token/manager.js';\nimport {\n TokenIntrospector,\n type IntrospectionResponse,\n type IntrospectTokenOptions,\n} from '../token/introspection.js';\nimport { TokenRevoker, type RevokeTokenOptions } from '../token/revocation.js';\nimport { LogoutHandler, type LogoutOptions, type LogoutResult } from '../session/logout.js';\nimport { TokenApiClient } from '../session/token-api.js';\nimport { SessionManager } from '../session/manager.js';\nimport { base64urlEncode } from '../utils/base64url.js';\nimport { AuthrimError } from '../types/errors.js';\nimport type { IDiagnosticLogger } from '../debug/diagnostic-logger.js';\n\n/**\n * Hash a value for use in storage keys\n *\n * @param crypto - Crypto provider\n * @param value - Value to hash\n * @param length - Hash length (default: 16 = 96 bits)\n * @returns Base64url-encoded hash\n */\nasync function hashForKey(\n crypto: AuthrimClientConfig['crypto'],\n value: string,\n length = 16\n): Promise<string> {\n const hash = await crypto.sha256(value);\n return base64urlEncode(hash).slice(0, length);\n}\n\n/**\n * Authrim Client\n */\nexport class AuthrimClient {\n /** Resolved configuration */\n private readonly config: ResolvedConfig;\n\n /** Event emitter */\n private readonly events: EventEmitter;\n\n /** Discovery client */\n private readonly discoveryClient: DiscoveryClient;\n\n /** PKCE helper */\n private readonly pkce: PKCEHelper;\n\n /** State manager (initialized in initialize()) */\n private stateManager!: StateManager;\n\n /** Authorization code flow helper */\n private readonly authCodeFlow: AuthorizationCodeFlow;\n\n /** PAR client */\n private readonly parClient: PARClient;\n\n /** Device Flow client */\n private readonly deviceFlowClient: DeviceFlowClient;\n\n /** DPoP manager (lazily initialized) */\n private dpopManager: DPoPManager | null = null;\n\n /** Token manager (initialized in initialize()) */\n private tokenManager!: TokenManager;\n\n /** Logout handler (initialized in initialize()) */\n private logoutHandler!: LogoutHandler;\n\n /** Session manager (initialized in initialize()) */\n private sessionManager!: SessionManager;\n\n /** Token introspector */\n private tokenIntrospector!: TokenIntrospector;\n\n /** Token revoker */\n private tokenRevoker!: TokenRevoker;\n\n /** Issuer hash for storage keys */\n private issuerHash!: string;\n\n /** Client ID hash for storage keys */\n private clientIdHash!: string;\n\n /** Normalized issuer URL */\n private readonly normalizedIssuer: string;\n\n /** Whether the client has been initialized */\n private initialized = false;\n\n /** Diagnostic logger (optional, for OIDF conformance testing) */\n private diagnosticLogger: IDiagnosticLogger | null = null;\n\n /**\n * Get the event emitter for subscribing to SDK events\n */\n get eventEmitter(): EventEmitter {\n return this.events;\n }\n\n /**\n * Create a new Authrim client\n *\n * @internal Use createAuthrimClient() instead\n */\n constructor(config: AuthrimClientConfig) {\n this.config = resolveConfig(config);\n this.normalizedIssuer = normalizeIssuer(config.issuer);\n\n // Initialize components that don't need hashes\n this.events = new EventEmitter();\n\n this.discoveryClient = new DiscoveryClient({\n http: this.config.http,\n cacheTtlMs: this.config.discoveryCacheTtlMs,\n });\n\n this.pkce = new PKCEHelper(this.config.crypto);\n\n this.authCodeFlow = new AuthorizationCodeFlow(this.config.http, this.config.clientId);\n\n this.parClient = new PARClient(this.config.http, this.config.clientId);\n\n this.deviceFlowClient = new DeviceFlowClient(this.config.http, this.config.clientId);\n }\n\n /**\n * Initialize the client\n *\n * @internal Called by createAuthrimClient()\n */\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n // Calculate hashes for storage keys\n const hashLength = this.config.hashOptions.hashLength;\n this.issuerHash = await hashForKey(this.config.crypto, this.normalizedIssuer, hashLength);\n this.clientIdHash = await hashForKey(this.config.crypto, this.config.clientId, hashLength);\n\n // Initialize state manager\n this.stateManager = new StateManager(\n this.config.crypto,\n this.config.storage,\n this.issuerHash,\n this.clientIdHash\n );\n\n // Initialize token manager\n this.tokenManager = new TokenManager({\n http: this.config.http,\n storage: this.config.storage,\n clientId: this.config.clientId,\n issuerHash: this.issuerHash,\n clientIdHash: this.clientIdHash,\n refreshSkewSeconds: this.config.refreshSkewSeconds,\n eventEmitter: this.events,\n });\n\n // Initialize logout handler\n this.logoutHandler = new LogoutHandler({\n storage: this.config.storage,\n http: this.config.http,\n clientId: this.config.clientId,\n issuerHash: this.issuerHash,\n clientIdHash: this.clientIdHash,\n eventEmitter: this.events,\n endpoints: this.config.endpoints,\n });\n\n // Initialize token introspector\n this.tokenIntrospector = new TokenIntrospector({\n http: this.config.http,\n clientId: this.config.clientId,\n });\n\n // Initialize token revoker\n this.tokenRevoker = new TokenRevoker({\n http: this.config.http,\n clientId: this.config.clientId,\n });\n\n // Initialize token API client\n const tokenApiClient = new TokenApiClient({\n http: this.config.http,\n });\n\n // Initialize session manager\n this.sessionManager = new SessionManager({\n tokenManager: this.tokenManager,\n tokenApiClient,\n });\n\n // Clean up expired states (best-effort)\n await this.stateManager.cleanupExpiredStates();\n\n this.initialized = true;\n }\n\n /**\n * Ensure client is initialized\n */\n private ensureInitialized(): void {\n if (!this.initialized) {\n throw new AuthrimError(\n 'not_initialized',\n 'Client not initialized. Use createAuthrimClient().'\n );\n }\n }\n\n /**\n * Get OIDC discovery document\n *\n * @returns Discovery document\n */\n async discover(): Promise<OIDCDiscoveryDocument> {\n const discovery = await this.discoveryClient.discover(this.normalizedIssuer);\n\n // Update dependent components\n this.tokenManager.setDiscovery(discovery);\n this.sessionManager.setDiscovery(discovery);\n\n return discovery;\n }\n\n // ============================================================\n // Authorization Code Flow\n // ============================================================\n\n /**\n * Build authorization URL\n *\n * Generates the URL to redirect the user to for authentication.\n * Stores state, nonce, and code_verifier in storage.\n *\n * @param options - Authorization options\n * @returns Authorization URL result\n */\n async buildAuthorizationUrl(\n options: BuildAuthorizationUrlOptions\n ): Promise<AuthorizationUrlResult> {\n this.ensureInitialized();\n\n const discovery = await this.discover();\n\n // Generate PKCE pair\n const pkcePair = await this.pkce.generatePKCE();\n\n // Determine scope (default: 'openid profile')\n const scope = options.scope ?? 'openid profile';\n\n // Generate auth state (including scope for validation during callback)\n const authState = await this.stateManager.generateAuthState({\n redirectUri: options.redirectUri,\n codeVerifier: pkcePair.codeVerifier,\n scope,\n ttlSeconds: this.config.stateTtlSeconds,\n });\n\n // Build URL\n const result = this.authCodeFlow.buildAuthorizationUrl(discovery, authState, pkcePair, options);\n\n // Emit event with operationId for tracking\n this.events.emit('auth:redirecting', {\n url: result.url,\n timestamp: Date.now(),\n source: 'core',\n operationId: authState.operationId,\n });\n\n return result;\n }\n\n /**\n * Handle authorization callback\n *\n * Processes the callback URL, validates state/nonce, and exchanges\n * the authorization code for tokens.\n *\n * @param callbackUrl - Callback URL or query string\n * @returns Token set\n */\n async handleCallback(callbackUrl: string): Promise<TokenSet> {\n this.ensureInitialized();\n\n // Parse callback\n const { code, state } = this.authCodeFlow.parseCallback(callbackUrl);\n\n // Validate and consume state (always deletes) - do this first to get operationId\n const authState = await this.stateManager.validateAndConsumeState(state);\n const operationId = authState.operationId;\n\n // Emit callback received event with operationId\n this.events.emit('auth:callback', {\n code,\n state,\n timestamp: Date.now(),\n source: 'core',\n operationId,\n });\n\n // Emit callback processing event\n this.events.emit('auth:callback:processing', {\n state,\n timestamp: Date.now(),\n source: 'core',\n operationId,\n });\n\n try {\n // Get discovery\n const discovery = await this.discover();\n\n // Exchange code for tokens\n const tokens = await this.authCodeFlow.exchangeCode(discovery, {\n code,\n state,\n redirectUri: authState.redirectUri,\n codeVerifier: authState.codeVerifier,\n nonce: authState.nonce,\n scope: authState.scope,\n });\n\n // Save tokens\n await this.tokenManager.saveTokens(tokens);\n\n // Emit callback complete event\n this.events.emit('auth:callback:complete', {\n success: true,\n timestamp: Date.now(),\n source: 'core',\n operationId,\n });\n\n return tokens;\n } catch (error) {\n // Emit callback complete event with failure\n this.events.emit('auth:callback:complete', {\n success: false,\n timestamp: Date.now(),\n source: 'core',\n operationId,\n });\n throw error;\n }\n }\n\n // ============================================================\n // PAR API (Pushed Authorization Request - RFC 9126)\n // ============================================================\n\n /**\n * PAR API accessor\n *\n * Provides access to Pushed Authorization Request functionality.\n * PAR allows pushing authorization request parameters to a dedicated endpoint,\n * receiving a request_uri to use in the authorization URL.\n */\n get par() {\n return {\n /**\n * Push authorization request and get request_uri\n *\n * @param options - Authorization options\n * @returns PAR result with request_uri and expiration\n */\n push: async (options: BuildAuthorizationUrlOptions): Promise<PARResult> => {\n this.ensureInitialized();\n const discovery = await this.discover();\n\n // Generate PKCE and state\n const pkcePair = await this.pkce.generatePKCE();\n const scope = options.scope ?? 'openid profile';\n const authState = await this.stateManager.generateAuthState({\n redirectUri: options.redirectUri,\n codeVerifier: pkcePair.codeVerifier,\n scope,\n ttlSeconds: this.config.stateTtlSeconds,\n });\n\n // Push to PAR endpoint\n return this.parClient.pushAuthorizationRequest(discovery, {\n redirectUri: options.redirectUri,\n scope,\n state: authState.state,\n nonce: authState.nonce,\n codeChallenge: pkcePair.codeChallenge,\n codeChallengeMethod: 'S256',\n prompt: options.prompt,\n loginHint: options.loginHint,\n acrValues: options.acrValues,\n extraParams: options.extraParams,\n });\n },\n\n /**\n * Build authorization URL using request_uri from PAR\n *\n * @param requestUri - Request URI from PAR response\n * @returns Authorization URL\n */\n buildAuthorizationUrl: async (requestUri: string): Promise<string> => {\n const discovery = await this.discover();\n return this.parClient.buildAuthorizationUrlWithPar(discovery, requestUri);\n },\n\n /**\n * Check if PAR is available\n *\n * @returns True if PAR endpoint is available\n */\n isAvailable: async (): Promise<boolean> => {\n const discovery = await this.discover();\n return !!discovery.pushed_authorization_request_endpoint;\n },\n\n /**\n * Check if PAR is required by the server\n *\n * @returns True if server requires PAR\n */\n isRequired: async (): Promise<boolean> => {\n const discovery = await this.discover();\n return discovery.require_pushed_authorization_requests === true;\n },\n };\n }\n\n // ============================================================\n // Device Flow API (RFC 8628)\n // ============================================================\n\n /**\n * Device Flow API accessor\n *\n * Provides access to Device Authorization Grant functionality.\n * Used for devices with limited input capabilities (TVs, CLIs, IoT).\n */\n get deviceFlow() {\n return {\n /**\n * Start device authorization\n *\n * @param options - Start options (scope, etc.)\n * @returns Device flow state with codes and URIs\n */\n start: async (options?: DeviceFlowStartOptions): Promise<DeviceFlowState> => {\n this.ensureInitialized();\n const discovery = await this.discover();\n return this.deviceFlowClient.startDeviceAuthorization(discovery, options);\n },\n\n /**\n * Poll once for token\n *\n * @param state - Device flow state\n * @returns Poll result\n */\n pollOnce: async (state: DeviceFlowState): Promise<DeviceFlowPollResult> => {\n const discovery = await this.discover();\n return this.deviceFlowClient.pollOnce(discovery, state);\n },\n\n /**\n * Poll until complete or expired\n *\n * @param state - Device flow state\n * @param options - Polling options (signal for abort)\n * @returns Token set on success\n */\n pollUntilComplete: async (\n state: DeviceFlowState,\n options?: { signal?: AbortSignal }\n ): Promise<TokenSet> => {\n const discovery = await this.discover();\n const tokens = await this.deviceFlowClient.pollUntilComplete(discovery, state, options);\n\n // Save tokens\n await this.tokenManager.saveTokens(tokens);\n\n return tokens;\n },\n\n /**\n * Check if Device Flow is available\n *\n * @returns True if device authorization endpoint is available\n */\n isAvailable: async (): Promise<boolean> => {\n const discovery = await this.discover();\n return !!discovery.device_authorization_endpoint;\n },\n };\n }\n\n // ============================================================\n // DPoP API (RFC 9449)\n // ============================================================\n\n /**\n * DPoP API accessor\n *\n * Provides access to DPoP (Demonstrating Proof of Possession) functionality.\n * DPoP binds access tokens to a cryptographic key held by the client,\n * preventing token theft and replay attacks.\n *\n * NOTE: The CryptoProvider must implement DPoPCryptoProvider interface\n * for DPoP to be available.\n *\n * @returns DPoP API accessor, or undefined if not supported\n */\n get dpop() {\n // Check if crypto provider supports DPoP\n const cryptoWithDPoP = this.config.crypto as DPoPCryptoProvider;\n if (!cryptoWithDPoP.generateDPoPKeyPair) {\n return undefined;\n }\n\n // Lazily initialize DPoP manager\n if (!this.dpopManager) {\n // Cast to the combined type that DPoPManager expects\n this.dpopManager = new DPoPManager(\n this.config.crypto as CryptoProvider & DPoPCryptoProvider\n );\n }\n\n const manager = this.dpopManager;\n\n return {\n /**\n * Initialize DPoP (generates or retrieves key pair)\n */\n initialize: () => manager.initialize(),\n\n /**\n * Check if DPoP is initialized\n */\n isInitialized: () => manager.isInitialized(),\n\n /**\n * Generate a DPoP proof for a request\n *\n * @param method - HTTP method (GET, POST, etc.)\n * @param uri - Full request URI\n * @param options - Additional options (access token hash, nonce)\n * @returns Signed DPoP proof JWT\n */\n generateProof: (\n method: string,\n uri: string,\n options?: { accessTokenHash?: string; nonce?: string }\n ) => manager.generateProof(method, uri, options),\n\n /**\n * Handle DPoP-Nonce response from server\n *\n * @param nonce - Server-provided nonce\n */\n handleNonceResponse: (nonce: string) => manager.handleNonceResponse(nonce),\n\n /**\n * Calculate access token hash for ath claim\n *\n * @param accessToken - Access token to hash\n * @returns Base64url-encoded SHA-256 hash\n */\n calculateAccessTokenHash: (accessToken: string) =>\n manager.calculateAccessTokenHash(accessToken),\n\n /**\n * Get the public key JWK\n */\n getPublicKeyJwk: () => manager.getPublicKeyJwk(),\n\n /**\n * Get the JWK thumbprint\n */\n getThumbprint: () => manager.getThumbprint(),\n\n /**\n * Clear DPoP key pair (call on logout)\n */\n clear: () => manager.clear(),\n\n /**\n * Check if DPoP is supported by the server\n *\n * @returns True if server advertises DPoP support\n */\n isServerSupported: async (): Promise<boolean> => {\n const discovery = await this.discover();\n return Array.isArray(discovery.dpop_signing_alg_values_supported) &&\n discovery.dpop_signing_alg_values_supported.length > 0;\n },\n };\n }\n\n // ============================================================\n // Token API\n // ============================================================\n\n /**\n * Token API accessor\n */\n get token() {\n this.ensureInitialized();\n return {\n /**\n * Get access token (refreshes if needed)\n */\n getAccessToken: () => this.tokenManager.getAccessToken(),\n\n /**\n * Get current tokens\n */\n getTokens: () => this.tokenManager.getTokens(),\n\n /**\n * Get ID token\n */\n getIdToken: () => this.tokenManager.getIdToken(),\n\n /**\n * Check if authenticated\n */\n isAuthenticated: () => this.tokenManager.isAuthenticated(),\n\n /**\n * Exchange token (RFC 8693)\n *\n * Exchanges a token for a new token with different audience, scope,\n * or delegation. Useful for:\n * - Cross-service token acquisition\n * - Delegation (actor token)\n * - Scope reduction\n *\n * @param request - Token exchange request parameters\n * @returns Token exchange result\n */\n exchange: async (request: TokenExchangeRequest): Promise<TokenExchangeResult> => {\n // Ensure discovery is loaded\n await this.discover();\n return this.tokenManager.exchangeToken(request);\n },\n\n /**\n * Introspect a token (RFC 7662)\n *\n * Validates a token server-side and returns its metadata.\n * Useful for resource servers to validate access tokens.\n *\n * @param options - Introspection options (token and optional type hint)\n * @returns Introspection response with token metadata\n * @throws AuthrimError if introspection endpoint not available or request fails\n */\n introspect: async (options: IntrospectTokenOptions): Promise<IntrospectionResponse> => {\n const discovery = await this.discover();\n return this.tokenIntrospector.introspect(discovery, options);\n },\n\n /**\n * Revoke a token (RFC 7009)\n *\n * Explicitly invalidates a token at the authorization server.\n * Use this when you want to ensure a token can no longer be used.\n *\n * @param options - Revocation options (token and optional type hint)\n * @throws AuthrimError if revocation endpoint not available or request fails\n */\n revoke: async (options: RevokeTokenOptions): Promise<void> => {\n const discovery = await this.discover();\n return this.tokenRevoker.revoke(discovery, options);\n },\n };\n }\n\n // ============================================================\n // Session API\n // ============================================================\n\n /**\n * Session API accessor\n */\n get session() {\n this.ensureInitialized();\n return {\n /**\n * Check if authenticated locally\n */\n isAuthenticated: () => this.sessionManager.isAuthenticated(),\n\n /**\n * Check session with authorization server\n */\n check: () => this.sessionManager.checkSession(),\n };\n }\n\n /**\n * Check if user is authenticated\n *\n * @returns True if tokens exist\n */\n async isAuthenticated(): Promise<boolean> {\n this.ensureInitialized();\n return this.tokenManager.isAuthenticated();\n }\n\n /**\n * Get user information\n *\n * @returns User info\n */\n async getUser(): Promise<UserInfo> {\n this.ensureInitialized();\n return this.sessionManager.getUser();\n }\n\n // ============================================================\n // Logout\n // ============================================================\n\n /**\n * Log out the user\n *\n * Clears local tokens and optionally redirects to IdP for logout.\n *\n * @param options - Logout options\n * @returns Logout result\n */\n async logout(options?: LogoutOptions): Promise<LogoutResult> {\n this.ensureInitialized();\n\n let discovery: OIDCDiscoveryDocument | null = null;\n try {\n discovery = await this.discover();\n } catch {\n // Discovery failure is OK for logout - we can still do local logout\n }\n\n return this.logoutHandler.logout(discovery, options);\n }\n\n // ============================================================\n // Diagnostic Logging\n // ============================================================\n\n /**\n * Set diagnostic logger for OIDF conformance testing\n *\n * When a diagnostic logger is set, the SDK will log token validation steps,\n * authentication decisions, and other diagnostic information.\n *\n * @param logger - Diagnostic logger instance (or null to disable)\n */\n setDiagnosticLogger(logger: IDiagnosticLogger | null): void {\n this.diagnosticLogger = logger;\n\n // Set diagnostic logger on authorization code flow\n this.authCodeFlow.setDiagnosticLogger(logger);\n }\n\n /**\n * Get diagnostic session ID (if diagnostic logging is enabled)\n *\n * This ID should be sent to the server via X-Diagnostic-Session-Id header\n * to correlate SDK logs with server logs.\n *\n * @returns Diagnostic session ID or null if diagnostic logging is disabled\n */\n getDiagnosticSessionId(): string | null {\n return this.diagnosticLogger?.getDiagnosticSessionId() ?? null;\n }\n\n // ============================================================\n // Events\n // ============================================================\n\n /**\n * Subscribe to an event\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n */\n on<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): () => void {\n return this.events.on(event, handler);\n }\n\n /**\n * Subscribe to an event (one-time)\n *\n * @param event - Event name\n * @param handler - Event handler\n * @returns Unsubscribe function\n */\n once<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): () => void {\n return this.events.once(event, handler);\n }\n\n /**\n * Unsubscribe from an event\n *\n * @param event - Event name\n * @param handler - Event handler\n */\n off<T extends AuthrimEventName>(event: T, handler: AuthrimEventHandler<T>): void {\n this.events.off(event, handler);\n }\n}\n\n/**\n * Create an Authrim client\n *\n * This is the main entry point for creating a client.\n * The client is fully initialized when returned.\n *\n * @param config - Client configuration\n * @returns Initialized Authrim client\n */\nexport async function createAuthrimClient(config: AuthrimClientConfig): Promise<AuthrimClient> {\n const client = new AuthrimClient(config);\n await client.initialize();\n return client;\n}\n","/**\n * Silent Authentication (prompt=none)\n *\n * Foundation for silent authentication using OIDC prompt=none.\n * This module provides the core logic for building silent auth requests\n * and parsing responses. The actual iframe/hidden frame implementation\n * is platform-specific and should be implemented in @authrim/web or similar.\n *\n * Silent authentication allows checking if a user has an active session\n * with the authorization server without user interaction.\n */\n\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { TokenSet } from '../types/token.js';\nimport type { AuthState } from './state.js';\nimport type { PKCEPair } from './pkce.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Silent authentication options\n */\nexport interface SilentAuthOptions {\n /** Redirect URI for silent auth response (often an iframe callback page) */\n redirectUri: string;\n /** Scopes to request (default: 'openid') */\n scope?: string;\n /**\n * Response type (default: 'code')\n *\n * Use 'none' for session check without token issuance\n * (OAuth 2.0 Multiple Response Types 1.0 §5)\n */\n responseType?: 'code' | 'none';\n /** Hint about the login identifier */\n loginHint?: string;\n /** ID token hint (helps IdP identify the user) */\n idTokenHint?: string;\n /** Additional custom parameters */\n extraParams?: Record<string, string>;\n /**\n * Expose state/nonce in result (for SSR/external storage)\n *\n * Default: false (security: state/nonce stay internal)\n */\n exposeState?: boolean;\n}\n\n/**\n * Result of building silent auth URL\n */\nexport interface SilentAuthUrlResult {\n /** Authorization URL with prompt=none */\n url: string;\n /** State parameter (only if exposeState: true) */\n state?: string;\n /** Nonce parameter (only if exposeState: true) */\n nonce?: string;\n}\n\n/**\n * Silent authentication result\n */\nexport interface SilentAuthResult {\n /** Whether silent auth succeeded */\n success: boolean;\n /** Tokens if successful */\n tokens?: TokenSet;\n /** Error if failed (e.g., login_required) */\n error?: AuthrimError;\n}\n\n/**\n * Silent auth error codes that indicate interactive login is needed\n */\nconst INTERACTIVE_LOGIN_REQUIRED_ERRORS = new Set([\n 'login_required',\n 'interaction_required',\n 'consent_required',\n 'account_selection_required',\n]);\n\n/**\n * Silent Authentication Handler\n *\n * Provides core logic for silent authentication. Platform-specific\n * implementations (iframe, hidden frame, etc.) should use this class.\n */\nexport class SilentAuthHandler {\n constructor(private readonly clientId: string) {}\n\n /**\n * Build silent authentication URL\n *\n * Creates an authorization URL with prompt=none for silent authentication.\n *\n * @param discovery - OIDC discovery document\n * @param authState - Auth state from StateManager\n * @param pkce - PKCE pair\n * @param options - Silent auth options\n * @returns Silent auth URL result\n */\n buildSilentAuthUrl(\n discovery: OIDCDiscoveryDocument,\n authState: AuthState,\n pkce: PKCEPair,\n options: SilentAuthOptions\n ): SilentAuthUrlResult {\n const endpoint = discovery.authorization_endpoint;\n const params = new URLSearchParams();\n\n // Required parameters\n params.set('client_id', this.clientId);\n params.set('response_type', options.responseType ?? 'code');\n params.set('redirect_uri', options.redirectUri);\n params.set('state', authState.state);\n params.set('nonce', authState.nonce);\n\n // Silent auth specific - MUST be prompt=none\n params.set('prompt', 'none');\n\n // PKCE parameters\n params.set('code_challenge', pkce.codeChallenge);\n params.set('code_challenge_method', pkce.codeChallengeMethod);\n\n // Scopes (default to openid only for silent auth)\n const scope = options.scope ?? 'openid';\n params.set('scope', scope);\n\n // Optional parameters\n if (options.loginHint) {\n params.set('login_hint', options.loginHint);\n }\n if (options.idTokenHint) {\n params.set('id_token_hint', options.idTokenHint);\n }\n\n // Extra custom parameters (with security parameter protection)\n if (options.extraParams) {\n const protectedParams = new Set([\n 'client_id',\n 'response_type',\n 'redirect_uri',\n 'state',\n 'nonce',\n 'code_challenge',\n 'code_challenge_method',\n 'scope',\n 'prompt', // Protect prompt=none\n ]);\n\n for (const [key, value] of Object.entries(options.extraParams)) {\n if (protectedParams.has(key.toLowerCase())) {\n continue;\n }\n params.set(key, value);\n }\n }\n\n const url = `${endpoint}?${params.toString()}`;\n\n const result: SilentAuthUrlResult = { url };\n\n if (options.exposeState) {\n result.state = authState.state;\n result.nonce = authState.nonce;\n }\n\n return result;\n }\n\n /**\n * Parse silent authentication response URL\n *\n * Parses the callback URL from silent authentication and returns\n * either the authorization code (for token exchange) or an error.\n *\n * @param responseUrl - Response URL from silent auth (iframe callback)\n * @returns Parsed result with code/state or error\n */\n parseSilentAuthResponse(responseUrl: string): {\n success: true;\n code: string;\n state: string;\n } | {\n success: false;\n error: AuthrimError;\n } {\n let searchParams: URLSearchParams;\n\n // Support both full URL and query string\n if (responseUrl.includes('?')) {\n const url = responseUrl.startsWith('http')\n ? new URL(responseUrl)\n : new URL(responseUrl, 'https://dummy.local');\n searchParams = url.searchParams;\n } else {\n searchParams = new URLSearchParams(responseUrl);\n }\n\n // Check for OAuth error response\n const error = searchParams.get('error');\n if (error) {\n const errorDescription = searchParams.get('error_description');\n const errorCode = this.mapSilentAuthError(error);\n\n return {\n success: false,\n error: new AuthrimError(errorCode, errorDescription ?? this.getDefaultErrorMessage(error), {\n details: {\n error,\n error_description: errorDescription,\n error_uri: searchParams.get('error_uri'),\n },\n }),\n };\n }\n\n // Extract code and state\n const code = searchParams.get('code');\n const state = searchParams.get('state');\n\n if (!code) {\n return {\n success: false,\n error: new AuthrimError('missing_code', 'Authorization code not found in silent auth response'),\n };\n }\n if (!state) {\n return {\n success: false,\n error: new AuthrimError('missing_state', 'State parameter not found in silent auth response'),\n };\n }\n\n return { success: true, code, state };\n }\n\n /**\n * Check if an error indicates interactive login is required\n *\n * @param error - Error to check\n * @returns True if interactive login is needed\n */\n isInteractiveLoginRequired(error: AuthrimError): boolean {\n return INTERACTIVE_LOGIN_REQUIRED_ERRORS.has(error.code);\n }\n\n /**\n * Map OAuth error to AuthrimErrorCode\n */\n private mapSilentAuthError(\n error: string\n ): 'login_required' | 'interaction_required' | 'consent_required' | 'account_selection_required' | 'oauth_error' {\n if (INTERACTIVE_LOGIN_REQUIRED_ERRORS.has(error)) {\n return error as 'login_required' | 'interaction_required' | 'consent_required' | 'account_selection_required';\n }\n return 'oauth_error';\n }\n\n /**\n * Get default error message for silent auth errors\n */\n private getDefaultErrorMessage(error: string): string {\n switch (error) {\n case 'login_required':\n return 'User must log in - no active session found';\n case 'interaction_required':\n return 'User interaction required';\n case 'consent_required':\n return 'User consent required';\n case 'account_selection_required':\n return 'User must select an account';\n default:\n return 'Silent authentication failed';\n }\n }\n}\n","/**\n * Client Authentication Utilities\n * RFC 6749 §2.3, RFC 7521, RFC 7523\n *\n * Provides utilities for building client authentication headers and body parameters\n * for various authentication methods.\n */\n\nimport type { ClientCredentials, ClientAssertionClaims } from '../types/client-auth.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Client authentication result\n */\nexport interface ClientAuthResult {\n /** Headers to include in the request */\n headers: Record<string, string>;\n /** Body parameters to include in the request */\n bodyParams: Record<string, string>;\n}\n\n/**\n * Build client authentication headers and body parameters\n *\n * @param credentials - Client credentials configuration\n * @param clientId - Client ID\n * @param tokenEndpoint - Token endpoint URL (used as audience for private_key_jwt)\n * @returns Headers and body parameters for authentication\n * @throws AuthrimError with code 'insecure_client_auth' if method='none' without dangerouslyAllowInsecure\n * @throws AuthrimError with code 'invalid_client_authentication' for invalid credentials\n */\nexport async function buildClientAuthentication(\n credentials: ClientCredentials,\n clientId: string,\n tokenEndpoint: string\n): Promise<ClientAuthResult> {\n const headers: Record<string, string> = {};\n const bodyParams: Record<string, string> = {};\n\n switch (credentials.method) {\n case 'client_secret_basic': {\n // RFC 6749 §2.3.1 - HTTP Basic Authentication\n const encodedCredentials = btoa(`${clientId}:${credentials.clientSecret}`);\n headers['Authorization'] = `Basic ${encodedCredentials}`;\n break;\n }\n\n case 'client_secret_post': {\n // RFC 6749 §2.3.1 - Client credentials in request body\n bodyParams['client_id'] = clientId;\n bodyParams['client_secret'] = credentials.clientSecret;\n break;\n }\n\n case 'private_key_jwt': {\n // RFC 7521, RFC 7523 - JWT Client Authentication\n const now = Math.floor(Date.now() / 1000);\n\n const claims: ClientAssertionClaims = {\n iss: clientId,\n sub: clientId,\n aud: tokenEndpoint,\n jti: generateJti(),\n exp: now + 300, // 5 minutes expiry\n iat: now,\n };\n\n let assertion: string;\n try {\n assertion = await credentials.signJwt(claims);\n } catch (error) {\n throw new AuthrimError(\n 'invalid_client_authentication',\n 'Failed to sign client assertion JWT',\n { cause: error instanceof Error ? error : undefined }\n );\n }\n\n bodyParams['client_id'] = clientId;\n bodyParams['client_assertion_type'] = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer';\n bodyParams['client_assertion'] = assertion;\n break;\n }\n\n case 'none': {\n // Public client - only client_id in body\n // SECURITY: Require explicit opt-in for insecure auth\n if (!('dangerouslyAllowInsecure' in credentials) || credentials.dangerouslyAllowInsecure !== true) {\n throw new AuthrimError(\n 'insecure_client_auth',\n 'Client authentication method \"none\" requires dangerouslyAllowInsecure: true'\n );\n }\n bodyParams['client_id'] = clientId;\n break;\n }\n\n default: {\n // Exhaustive check\n const _exhaustive: never = credentials;\n throw new AuthrimError(\n 'invalid_client_authentication',\n `Unknown client authentication method: ${(_exhaustive as ClientCredentials).method}`\n );\n }\n }\n\n return { headers, bodyParams };\n}\n\n/**\n * Generate a unique JWT ID (jti)\n *\n * Uses crypto.randomUUID if available, falls back to timestamp + random.\n */\nfunction generateJti(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for environments without crypto.randomUUID\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n","/**\n * Client Credentials Flow\n * RFC 6749 §4.4\n *\n * The client credentials grant is used for machine-to-machine (M2M) authentication\n * where no user is involved. The client authenticates directly with the authorization\n * server using its own credentials.\n *\n * IMPORTANT: This flow should only be used in secure environments (server-side)\n * where client credentials can be kept confidential.\n */\n\nimport type { HttpClient } from '../providers/http.js';\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type { TokenSet, TokenResponse } from '../types/token.js';\nimport type { ClientCredentials } from '../types/client-auth.js';\nimport { buildClientAuthentication } from './client-auth.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Options for ClientCredentialsClient constructor\n */\nexport interface ClientCredentialsClientOptions {\n /** HTTP client */\n http: HttpClient;\n /** Client ID */\n clientId: string;\n /** Client credentials */\n credentials: ClientCredentials;\n}\n\n/**\n * Options for getting a token\n */\nexport interface ClientCredentialsTokenOptions {\n /** Scopes to request */\n scope?: string;\n /** Target audience (resource server identifier) */\n audience?: string;\n /** Additional parameters */\n extraParams?: Record<string, string>;\n}\n\n/**\n * Client Credentials Flow Client\n *\n * Handles machine-to-machine authentication using the client credentials grant.\n */\nexport class ClientCredentialsClient {\n private readonly http: HttpClient;\n private readonly clientId: string;\n private readonly credentials: ClientCredentials;\n\n constructor(options: ClientCredentialsClientOptions) {\n this.http = options.http;\n this.clientId = options.clientId;\n this.credentials = options.credentials;\n }\n\n /**\n * Get an access token using client credentials\n *\n * @param discovery - OIDC discovery document\n * @param options - Token request options\n * @returns Token set\n * @throws AuthrimError with code 'client_credentials_error' if token request fails\n */\n async getToken(\n discovery: OIDCDiscoveryDocument,\n options?: ClientCredentialsTokenOptions\n ): Promise<TokenSet> {\n const tokenEndpoint = discovery.token_endpoint;\n\n // Build client authentication\n const { headers: authHeaders, bodyParams: authBodyParams } =\n await buildClientAuthentication(this.credentials, this.clientId, tokenEndpoint);\n\n // Build request body\n const body = new URLSearchParams({\n grant_type: 'client_credentials',\n ...authBodyParams,\n });\n\n // Add optional parameters\n if (options?.scope) {\n body.set('scope', options.scope);\n }\n if (options?.audience) {\n body.set('audience', options.audience);\n }\n\n // Add extra parameters (with protection for core params)\n if (options?.extraParams) {\n const protectedParams = new Set([\n 'grant_type',\n 'client_id',\n 'client_secret',\n 'client_assertion',\n 'client_assertion_type',\n 'scope',\n 'audience',\n ]);\n\n for (const [key, value] of Object.entries(options.extraParams)) {\n if (protectedParams.has(key.toLowerCase())) {\n continue;\n }\n body.set(key, value);\n }\n }\n\n // Build headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n ...authHeaders,\n };\n\n // Make token request\n let response;\n try {\n response = await this.http.fetch<TokenResponse>(tokenEndpoint, {\n method: 'POST',\n headers,\n body: body.toString(),\n });\n } catch (error) {\n throw new AuthrimError('network_error', 'Client credentials token request failed', {\n cause: error instanceof Error ? error : undefined,\n });\n }\n\n if (!response.ok) {\n const errorData = response.data as unknown as Record<string, unknown>;\n throw new AuthrimError('client_credentials_error', 'Client credentials token request failed', {\n details: {\n status: response.status,\n error: errorData?.error,\n error_description: errorData?.error_description,\n },\n });\n }\n\n const tokenResponse = response.data;\n\n // Calculate expiresAt (epoch seconds)\n const now = Math.floor(Date.now() / 1000);\n const expiresAt = tokenResponse.expires_in ? now + tokenResponse.expires_in : now + 3600;\n\n // Build token set\n // Note: Client credentials flow typically doesn't return refresh_token or id_token\n const tokenSet: TokenSet = {\n accessToken: tokenResponse.access_token,\n tokenType: (tokenResponse.token_type as 'Bearer') ?? 'Bearer',\n expiresAt,\n refreshToken: tokenResponse.refresh_token,\n scope: tokenResponse.scope,\n };\n\n return tokenSet;\n }\n}\n","/**\n * JAR Builder\n * RFC 9101: JWT-Secured Authorization Request (JAR)\n *\n * JAR provides a way to send authorization request parameters\n * in a signed (and optionally encrypted) JWT, ensuring:\n * - Integrity protection of parameters\n * - Non-repudiation\n * - Confidentiality (when encrypted)\n *\n * The signed JWT is sent as the 'request' parameter in the authorization URL,\n * or can be passed by reference using the 'request_uri' parameter (with PAR).\n */\n\nimport type {\n JARBuilderConfig,\n JARRequestOptions,\n JARRequestObjectClaims,\n} from '../types/jar.js';\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * JAR Builder\n *\n * Builds signed JWT request objects for authorization requests.\n */\nexport class JARBuilder {\n private readonly config: JARBuilderConfig;\n\n constructor(config: JARBuilderConfig) {\n this.config = config;\n }\n\n /**\n * Build a signed request object\n *\n * @param options - Request options\n * @returns Signed JWT request object\n * @throws AuthrimError with code 'jar_signing_error' if signing fails\n */\n async buildRequestObject(options: JARRequestOptions): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const lifetime = this.config.lifetime ?? 300; // 5 minutes default\n\n // Build JWT header\n const header: Record<string, unknown> = {\n alg: this.config.algorithm ?? 'RS256',\n typ: 'oauth-authz-req+jwt',\n };\n\n if (this.config.keyId) {\n header['kid'] = this.config.keyId;\n }\n\n // Build JWT claims (request object)\n const claims: JARRequestObjectClaims = {\n iss: options.clientId,\n aud: options.issuer,\n response_type: options.responseType ?? 'code',\n client_id: options.clientId,\n redirect_uri: options.redirectUri,\n scope: options.scope,\n state: options.state,\n nonce: options.nonce,\n code_challenge: options.codeChallenge,\n code_challenge_method: options.codeChallengeMethod,\n iat: now,\n exp: now + lifetime,\n jti: this.generateJti(),\n };\n\n // Add optional OIDC parameters\n if (options.prompt) {\n claims.prompt = options.prompt;\n }\n if (options.loginHint) {\n claims.login_hint = options.loginHint;\n }\n if (options.acrValues) {\n claims.acr_values = options.acrValues;\n }\n\n // Add extra claims (with protection for core claims)\n if (options.extraClaims) {\n const protectedClaims = new Set([\n 'iss',\n 'aud',\n 'response_type',\n 'client_id',\n 'redirect_uri',\n 'scope',\n 'state',\n 'nonce',\n 'code_challenge',\n 'code_challenge_method',\n 'iat',\n 'exp',\n 'jti',\n 'nbf',\n ]);\n\n for (const [key, value] of Object.entries(options.extraClaims)) {\n if (!protectedClaims.has(key)) {\n claims[key] = value;\n }\n }\n }\n\n // Sign the JWT\n try {\n return await this.config.signJwt(header, claims);\n } catch (error) {\n throw new AuthrimError(\n 'jar_signing_error',\n 'Failed to sign JAR request object',\n { cause: error instanceof Error ? error : undefined }\n );\n }\n }\n\n /**\n * Generate a unique JWT ID (jti)\n */\n private generateJti(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n }\n}\n\n/**\n * Check if JAR is required by the authorization server\n *\n * @param discovery - OIDC discovery document\n * @returns True if require_signed_request_object is true\n */\nexport function isJarRequired(discovery: { require_signed_request_object?: boolean }): boolean {\n return discovery.require_signed_request_object === true;\n}\n","/**\n * JARM Validator\n * JWT Secured Authorization Response Mode (JARM)\n *\n * JARM allows authorization servers to return authorization response\n * parameters in a signed JWT, providing:\n * - Response integrity protection\n * - Response authenticity verification\n * - Confidentiality (when encrypted)\n *\n * The response JWT is returned in the 'response' parameter of the\n * authorization callback.\n */\n\nimport type { OIDCDiscoveryDocument } from '../types/oidc.js';\nimport type {\n JARMResponseClaims,\n JARMValidationOptions,\n JARMValidationResult,\n JARMValidatorConfig,\n} from '../types/jarm.js';\nimport { AuthrimError } from '../types/errors.js';\nimport { timingSafeEqual } from '../utils/timing-safe.js';\n\n/**\n * JARM Validator\n *\n * Validates JWT-secured authorization responses.\n */\nexport class JARMValidator {\n private readonly config: JARMValidatorConfig;\n\n constructor(config: JARMValidatorConfig) {\n this.config = config;\n }\n\n /**\n * Validate a JARM response\n *\n * @param discovery - OIDC discovery document\n * @param response - The JWT response string from the 'response' parameter\n * @param options - Validation options\n * @returns Validated authorization code and state\n * @throws AuthrimError with code 'jarm_validation_error' if validation fails\n * @throws AuthrimError with code 'jarm_signature_invalid' if signature verification fails\n */\n async validateResponse(\n discovery: OIDCDiscoveryDocument,\n response: string,\n options: JARMValidationOptions\n ): Promise<JARMValidationResult> {\n const clockSkew = options.clockSkewSeconds ?? 60;\n\n // Verify JWT signature and get claims\n let claims: JARMResponseClaims;\n try {\n claims = await this.config.verifyJwt(response, discovery.issuer);\n } catch (error) {\n throw new AuthrimError(\n 'jarm_signature_invalid',\n 'Failed to verify JARM response signature',\n { cause: error instanceof Error ? error : undefined }\n );\n }\n\n // Validate issuer\n if (claims.iss !== discovery.issuer) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response issuer does not match discovery issuer',\n {\n details: {\n expected: discovery.issuer,\n actual: claims.iss,\n },\n }\n );\n }\n\n // Validate audience (must be client_id or array containing client_id)\n const audience = Array.isArray(claims.aud) ? claims.aud : [claims.aud];\n if (!audience.includes(options.clientId)) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response audience does not match client_id',\n {\n details: {\n expected: options.clientId,\n actual: claims.aud,\n },\n }\n );\n }\n\n // Validate expiration\n const now = Math.floor(Date.now() / 1000);\n if (claims.exp && claims.exp + clockSkew < now) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response has expired'\n );\n }\n\n // Validate iat if present (not in the future)\n if (claims.iat && claims.iat - clockSkew > now) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response iat is in the future'\n );\n }\n\n // Check for OAuth error in response\n if (claims.error) {\n throw new AuthrimError('oauth_error', claims.error_description ?? claims.error, {\n details: {\n error: claims.error,\n error_description: claims.error_description,\n error_uri: claims.error_uri,\n },\n });\n }\n\n // Validate state (constant-time comparison)\n if (!claims.state) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response is missing state claim'\n );\n }\n if (!timingSafeEqual(claims.state, options.expectedState)) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response state does not match expected state'\n );\n }\n\n // Validate code is present\n if (!claims.code) {\n throw new AuthrimError(\n 'jarm_validation_error',\n 'JARM response is missing authorization code'\n );\n }\n\n return {\n code: claims.code,\n state: claims.state,\n };\n }\n\n /**\n * Parse a JARM response from callback URL\n *\n * Extracts the 'response' parameter from the callback URL.\n *\n * @param callbackUrl - Full callback URL or query string\n * @returns The response JWT, or null if not present\n */\n static extractResponseFromCallback(callbackUrl: string): string | null {\n let searchParams: URLSearchParams;\n\n if (callbackUrl.includes('?')) {\n const url = callbackUrl.startsWith('http')\n ? new URL(callbackUrl)\n : new URL(callbackUrl, 'https://dummy.local');\n searchParams = url.searchParams;\n } else {\n searchParams = new URLSearchParams(callbackUrl);\n }\n\n return searchParams.get('response');\n }\n}\n","/**\n * Auto Refresh Scheduler\n *\n * Automatically refreshes tokens before they expire.\n * Supports cancellation via AbortController.\n */\n\nimport type { TokenManager } from './manager.js';\nimport type { EventEmitter } from '../events/emitter.js';\n\n/**\n * Auto refresh options\n */\nexport interface AutoRefreshOptions {\n /** Refresh threshold in seconds before expiry (default: 60) */\n thresholdSeconds?: number;\n /** Check interval in milliseconds (default: 30000 = 30 seconds) */\n checkIntervalMs?: number;\n /** Event emitter for logging/debugging */\n eventEmitter?: EventEmitter;\n}\n\n/**\n * Auto Refresh Scheduler\n *\n * Schedules automatic token refresh before expiration.\n * Can be stopped and started as needed.\n */\nexport class AutoRefreshScheduler {\n private tokenManager: TokenManager | null = null;\n private options: Required<Omit<AutoRefreshOptions, 'eventEmitter'>> & { eventEmitter?: EventEmitter };\n private checkInterval: ReturnType<typeof setInterval> | null = null;\n private abortController: AbortController | null = null;\n private isRunning = false;\n\n /** Default refresh threshold: 60 seconds */\n private static readonly DEFAULT_THRESHOLD_SECONDS = 60;\n\n /** Default check interval: 30 seconds */\n private static readonly DEFAULT_CHECK_INTERVAL_MS = 30000;\n\n constructor(options?: AutoRefreshOptions) {\n this.options = {\n thresholdSeconds: options?.thresholdSeconds ?? AutoRefreshScheduler.DEFAULT_THRESHOLD_SECONDS,\n checkIntervalMs: options?.checkIntervalMs ?? AutoRefreshScheduler.DEFAULT_CHECK_INTERVAL_MS,\n eventEmitter: options?.eventEmitter,\n };\n }\n\n /**\n * Start auto-refresh scheduling\n *\n * @param tokenManager - Token manager instance\n */\n start(tokenManager: TokenManager): void {\n if (this.isRunning) {\n return;\n }\n\n this.tokenManager = tokenManager;\n this.abortController = new AbortController();\n this.isRunning = true;\n\n // Start periodic check\n this.checkInterval = setInterval(() => {\n this.checkAndRefresh().catch(() => {\n // Errors are handled within checkAndRefresh\n });\n }, this.options.checkIntervalMs);\n\n // Initial check\n this.checkAndRefresh().catch(() => {\n // Errors are handled within checkAndRefresh\n });\n }\n\n /**\n * Stop auto-refresh scheduling\n */\n stop(): void {\n if (!this.isRunning) {\n return;\n }\n\n this.isRunning = false;\n\n if (this.checkInterval) {\n clearInterval(this.checkInterval);\n this.checkInterval = null;\n }\n\n if (this.abortController) {\n this.abortController.abort();\n this.abortController = null;\n }\n\n this.tokenManager = null;\n }\n\n /**\n * Check if scheduler is running\n */\n get running(): boolean {\n return this.isRunning;\n }\n\n /**\n * Get the abort signal for external cancellation support\n */\n get signal(): AbortSignal | null {\n return this.abortController?.signal ?? null;\n }\n\n /**\n * Check if token needs refresh and perform if needed\n */\n private async checkAndRefresh(): Promise<void> {\n if (!this.tokenManager || !this.isRunning) {\n return;\n }\n\n try {\n const tokens = await this.tokenManager.getTokens();\n if (!tokens) {\n return;\n }\n\n const now = Math.floor(Date.now() / 1000);\n const expiresIn = tokens.expiresAt - now;\n\n // Check if token is within threshold\n if (expiresIn <= this.options.thresholdSeconds && tokens.refreshToken) {\n // Perform background refresh\n await this.tokenManager.refresh();\n }\n } catch (error) {\n // Log error but don't stop the scheduler\n // The tokenManager will emit appropriate events\n }\n }\n\n /**\n * Force an immediate refresh check\n */\n async forceCheck(): Promise<void> {\n await this.checkAndRefresh();\n }\n}\n","/**\n * Session State Calculator\n *\n * Implements OIDC Session Management 1.0 specification\n * https://openid.net/specs/openid-connect-session-1_0.html\n *\n * session_state = hash(client_id + \" \" + origin + \" \" + browser_state + salt) + \".\" + salt\n */\n\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport { base64urlEncode } from '../utils/base64url.js';\nimport { timingSafeEqual } from '../utils/timing-safe.js';\n\n/**\n * Parameters for calculating session_state\n */\nexport interface SessionStateParams {\n /** OAuth client_id */\n clientId: string;\n /** RP origin (e.g., \"https://example.com\") */\n origin: string;\n /**\n * OP-managed browser state (opaque value)\n *\n * Per OIDC Session Management 1.0 spec, this is called \"browser_state\" but is actually\n * an opaque value managed by the OP to identify the session at the OP.\n * It is NOT a value managed by the RP's browser.\n */\n opBrowserState: string;\n /** Optional salt (generated if not provided) */\n salt?: string;\n}\n\n/**\n * Result of session_state calculation\n */\nexport interface SessionStateResult {\n /** Full session_state value (hash.salt) */\n sessionState: string;\n /** Hash portion of session_state */\n hash: string;\n /** Salt used in calculation */\n salt: string;\n}\n\n/**\n * Options for SessionStateCalculator\n */\nexport interface SessionStateCalculatorOptions {\n /** Crypto provider for hashing */\n crypto: CryptoProvider;\n}\n\n/**\n * Session State Calculator\n *\n * Calculates and validates session_state values per OIDC Session Management 1.0.\n *\n * Usage (OP side - calculating session_state to include in auth response):\n * ```typescript\n * const calculator = new SessionStateCalculator({ crypto });\n * const result = await calculator.calculate({\n * clientId: 'my-client',\n * origin: 'https://rp.example.com',\n * opBrowserState: 'op-session-id-xyz'\n * });\n * // result.sessionState -> include in auth response\n * ```\n *\n * Usage (RP check_session_iframe - validating session state):\n * ```typescript\n * const isValid = await calculator.validate(sessionState, {\n * clientId: 'my-client',\n * origin: 'https://rp.example.com',\n * opBrowserState: 'op-session-id-xyz'\n * });\n * ```\n */\nexport class SessionStateCalculator {\n private readonly crypto: CryptoProvider;\n\n constructor(options: SessionStateCalculatorOptions) {\n this.crypto = options.crypto;\n }\n\n /**\n * Calculate session_state\n *\n * Per OIDC Session Management 1.0:\n * session_state = hash(client_id + \" \" + origin + \" \" + browser_state + salt) + \".\" + salt\n *\n * @param params - Parameters for calculation\n * @returns Session state result\n */\n async calculate(params: SessionStateParams): Promise<SessionStateResult> {\n // Generate salt if not provided (16 random bytes, base64url encoded)\n let salt = params.salt;\n if (!salt) {\n const saltBytes = await this.crypto.randomBytes(16);\n salt = base64urlEncode(saltBytes);\n }\n\n // Build the string to hash\n // Note: The spec uses space as delimiter\n const hashInput =\n params.clientId + ' ' + params.origin + ' ' + params.opBrowserState + salt;\n\n // Compute SHA-256 hash\n const hashBytes = await this.crypto.sha256(hashInput);\n const hash = base64urlEncode(hashBytes);\n\n // session_state = hash + \".\" + salt\n const sessionState = hash + '.' + salt;\n\n return {\n sessionState,\n hash,\n salt,\n };\n }\n\n /**\n * Validate session_state\n *\n * Uses constant-time comparison to prevent timing attacks.\n *\n * @param sessionState - session_state value to validate\n * @param params - Parameters that should match (without salt, extracted from sessionState)\n * @returns true if valid\n */\n async validate(\n sessionState: string,\n params: Omit<SessionStateParams, 'salt'>\n ): Promise<boolean> {\n const parsed = this.parse(sessionState);\n if (!parsed) {\n return false;\n }\n\n // Recalculate with the extracted salt\n const calculated = await this.calculate({\n ...params,\n salt: parsed.salt,\n });\n\n // Use constant-time comparison to prevent timing attacks\n return timingSafeEqual(calculated.sessionState, sessionState);\n }\n\n /**\n * Parse session_state into hash and salt components\n *\n * @param sessionState - session_state value to parse\n * @returns Parsed components or null if invalid format\n */\n parse(sessionState: string): { hash: string; salt: string } | null {\n // Maximum lengths to prevent DoS via oversized input\n // SHA-256 base64url is ~43 chars, salt is typically ~22 chars\n const MAX_SESSION_STATE_LENGTH = 512;\n const MAX_HASH_LENGTH = 256;\n const MAX_SALT_LENGTH = 128;\n\n if (!sessionState || typeof sessionState !== 'string') {\n return null;\n }\n\n // Length validation to prevent DoS\n if (sessionState.length > MAX_SESSION_STATE_LENGTH) {\n return null;\n }\n\n const dotIndex = sessionState.lastIndexOf('.');\n if (dotIndex === -1 || dotIndex === 0 || dotIndex === sessionState.length - 1) {\n return null;\n }\n\n const hash = sessionState.substring(0, dotIndex);\n const salt = sessionState.substring(dotIndex + 1);\n\n // Basic validation - both parts should be non-empty and look like base64url\n if (!hash || !salt) {\n return null;\n }\n\n // Length validation for individual components\n if (hash.length > MAX_HASH_LENGTH || salt.length > MAX_SALT_LENGTH) {\n return null;\n }\n\n // Base64url validation: only A-Z, a-z, 0-9, -, _ allowed\n const base64urlRegex = /^[A-Za-z0-9_-]+$/;\n if (!base64urlRegex.test(hash) || !base64urlRegex.test(salt)) {\n return null;\n }\n\n return { hash, salt };\n }\n}\n","/**\n * Front-Channel Logout URL Builder\n *\n * Implements OpenID Connect Front-Channel Logout 1.0\n * https://openid.net/specs/openid-connect-frontchannel-1_0.html\n *\n * Front-channel logout allows the OP to notify RPs of logout events\n * via browser redirects (iframes loaded by the OP's logout page).\n */\n\nimport type { FrontChannelLogoutParams, FrontChannelLogoutUrlOptions } from '../types/session-management.js';\nimport { timingSafeEqual } from '../utils/timing-safe.js';\n\n/**\n * Result of building a front-channel logout URL\n */\nexport interface FrontChannelLogoutUrlResult {\n /** Complete logout URL with query parameters */\n url: string;\n /** Parameters included in the URL */\n params: FrontChannelLogoutParams;\n}\n\n/**\n * Parameters for building a front-channel logout URL\n */\nexport interface FrontChannelLogoutBuildParams {\n /** Issuer identifier to include (optional) */\n iss?: string;\n /** Session ID to include (optional) */\n sid?: string;\n}\n\n/**\n * Validation options for front-channel logout requests\n */\nexport interface FrontChannelLogoutValidationOptions {\n /** Expected issuer (for validation) */\n issuer?: string;\n /** Expected session ID (for validation) */\n sessionId?: string;\n /** Require issuer parameter */\n requireIss?: boolean;\n /** Require session ID parameter */\n requireSid?: boolean;\n}\n\n/**\n * Result of front-channel logout request validation\n */\nexport interface FrontChannelLogoutValidationResult {\n /** Whether the request is valid */\n valid: boolean;\n /** Parsed parameters (if valid) */\n params?: FrontChannelLogoutParams;\n /** Error message (if invalid) */\n error?: string;\n}\n\n/**\n * Front-Channel Logout URL Builder\n *\n * Builds and validates front-channel logout URLs per OIDC Front-Channel Logout 1.0.\n *\n * Usage (OP side - building logout URL to load in iframe):\n * ```typescript\n * const builder = new FrontChannelLogoutUrlBuilder();\n * const result = builder.build(\n * { logoutUri: 'https://rp.example.com/logout', includeIssuer: true, includeSessionId: true },\n * { iss: 'https://op.example.com', sid: 'session-123' }\n * );\n * // result.url -> load in iframe\n * ```\n *\n * Usage (RP side - validating incoming logout request):\n * ```typescript\n * const result = builder.validateRequest(window.location.href, {\n * issuer: 'https://op.example.com',\n * requireIss: true\n * });\n * if (result.valid) {\n * // Perform local logout\n * }\n * ```\n */\nexport class FrontChannelLogoutUrlBuilder {\n /**\n * Build a front-channel logout URL\n *\n * @param options - URL configuration options\n * @param params - Parameters to include in the URL\n * @returns Built URL and included parameters\n */\n build(\n options: FrontChannelLogoutUrlOptions,\n params: FrontChannelLogoutBuildParams\n ): FrontChannelLogoutUrlResult {\n const url = new URL(options.logoutUri);\n const resultParams: FrontChannelLogoutParams = {};\n\n if (options.includeIssuer && params.iss) {\n url.searchParams.set('iss', params.iss);\n resultParams.iss = params.iss;\n }\n\n if (options.includeSessionId && params.sid) {\n url.searchParams.set('sid', params.sid);\n resultParams.sid = params.sid;\n }\n\n return {\n url: url.toString(),\n params: resultParams,\n };\n }\n\n /**\n * Parse parameters from a front-channel logout URL\n *\n * @param url - URL or URL string to parse\n * @returns Parsed parameters\n */\n parseParams(url: string | URL): FrontChannelLogoutParams {\n const urlObj = typeof url === 'string' ? new URL(url) : url;\n const params: FrontChannelLogoutParams = {};\n\n const iss = urlObj.searchParams.get('iss');\n if (iss) {\n params.iss = iss;\n }\n\n const sid = urlObj.searchParams.get('sid');\n if (sid) {\n params.sid = sid;\n }\n\n return params;\n }\n\n /**\n * Validate a front-channel logout request\n *\n * Uses constant-time comparison for security-sensitive values to prevent timing attacks.\n *\n * @param url - URL to validate\n * @param expected - Expected values and requirements\n * @returns Validation result\n */\n validateRequest(\n url: string | URL,\n expected: FrontChannelLogoutValidationOptions = {}\n ): FrontChannelLogoutValidationResult {\n let params: FrontChannelLogoutParams;\n\n try {\n params = this.parseParams(url);\n } catch {\n return {\n valid: false,\n error: 'Invalid URL format',\n };\n }\n\n // Check required parameters\n if (expected.requireIss && !params.iss) {\n return {\n valid: false,\n error: 'Missing required iss parameter',\n };\n }\n\n if (expected.requireSid && !params.sid) {\n return {\n valid: false,\n error: 'Missing required sid parameter',\n };\n }\n\n // Validate issuer if provided and expected\n // Use constant-time comparison to prevent timing attacks\n if (expected.issuer && params.iss && !timingSafeEqual(params.iss, expected.issuer)) {\n return {\n valid: false,\n error: 'Issuer validation failed',\n };\n }\n\n // Validate session ID if provided and expected\n // Use constant-time comparison to prevent timing attacks\n if (expected.sessionId && params.sid && !timingSafeEqual(params.sid, expected.sessionId)) {\n return {\n valid: false,\n error: 'Session ID validation failed',\n };\n }\n\n return {\n valid: true,\n params,\n };\n }\n}\n","/**\n * Event Timeline\n *\n * Records SDK events for debugging and observability.\n * All sensitive data is automatically redacted.\n */\n\nimport type { TimelineEntry } from '../events/types.js';\nimport type { RedactLevel } from './types.js';\n\n/**\n * Sensitive keys that should always be redacted\n */\nconst SENSITIVE_KEYS = [\n 'accessToken',\n 'refreshToken',\n 'idToken',\n 'token',\n 'code',\n 'password',\n 'secret',\n 'credentials',\n 'authorization',\n 'bearer',\n 'codeVerifier',\n 'code_verifier',\n 'client_secret',\n];\n\n/**\n * URL parameters that should be redacted in aggressive mode\n */\nconst SENSITIVE_URL_PARAMS = [\n 'code',\n 'state',\n 'nonce',\n 'id_token',\n 'access_token',\n 'refresh_token',\n 'token',\n];\n\n/**\n * Event Timeline for debugging\n *\n * Records events with automatic redaction of sensitive data.\n * Safe to use in production - no sensitive data is stored.\n */\nexport class EventTimeline {\n private entries: TimelineEntry[] = [];\n private maxEvents: number;\n private redactLevel: RedactLevel;\n\n constructor(options?: { maxEvents?: number; redactLevel?: RedactLevel }) {\n this.maxEvents = options?.maxEvents ?? 100;\n this.redactLevel = options?.redactLevel ?? 'default';\n }\n\n /**\n * Record an event to the timeline\n *\n * Data is automatically redacted based on redact level.\n *\n * @param type - Event type\n * @param data - Event data (will be redacted)\n * @param options - Recording options\n */\n record(\n type: string,\n data?: unknown,\n options?: { operationId?: string; redact?: RedactLevel }\n ): void {\n const redactLevelToUse = options?.redact ?? this.redactLevel;\n const redactedData = this.redactData(data, redactLevelToUse);\n\n const entry: TimelineEntry = {\n type,\n timestamp: Date.now(),\n operationId: options?.operationId,\n data: redactedData,\n };\n\n this.entries.push(entry);\n\n // Trim to max events\n while (this.entries.length > this.maxEvents) {\n this.entries.shift();\n }\n }\n\n /**\n * Get recent entries\n *\n * @param count - Number of entries to return (default: all)\n * @returns Recent timeline entries\n */\n getRecent(count?: number): TimelineEntry[] {\n if (count === undefined) {\n return [...this.entries];\n }\n return this.entries.slice(-count);\n }\n\n /**\n * Get entries for a specific operation\n *\n * @param operationId - Operation ID to filter by\n * @returns Entries for the operation\n */\n getByOperationId(operationId: string): TimelineEntry[] {\n return this.entries.filter((entry) => entry.operationId === operationId);\n }\n\n /**\n * Get entries by event type\n *\n * @param type - Event type to filter by\n * @returns Entries matching the type\n */\n getByType(type: string): TimelineEntry[] {\n return this.entries.filter((entry) => entry.type === type);\n }\n\n /**\n * Clear all entries\n */\n clear(): void {\n this.entries = [];\n }\n\n /**\n * Get entry count\n */\n get length(): number {\n return this.entries.length;\n }\n\n /**\n * Convert timeline to JSON string (for export/logging)\n */\n toJSON(): string {\n return JSON.stringify(this.entries, null, 2);\n }\n\n /**\n * Set redaction level\n */\n setRedactLevel(level: RedactLevel): void {\n this.redactLevel = level;\n }\n\n /**\n * Redact sensitive data from event payload\n */\n private redactData(\n data: unknown,\n level: RedactLevel\n ): Record<string, unknown> | undefined {\n if (level === 'none' || data === undefined || data === null) {\n return data as Record<string, unknown> | undefined;\n }\n\n if (typeof data !== 'object') {\n return data as Record<string, unknown>;\n }\n\n const redacted = this.deepRedact(data as Record<string, unknown>, level);\n return redacted;\n }\n\n /**\n * Deep redact an object\n */\n private deepRedact(\n obj: Record<string, unknown>,\n level: RedactLevel\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n const lowerKey = key.toLowerCase();\n\n // Check if this is a sensitive key\n if (this.isSensitiveKey(lowerKey)) {\n // Add existence flag instead of value\n const capitalizedKey = key.charAt(0).toUpperCase() + key.slice(1);\n result[`has${capitalizedKey}`] = value !== undefined && value !== null;\n result[key] = '[REDACTED]';\n continue;\n }\n\n // Handle URL redaction in aggressive mode\n if (level === 'aggressive' && lowerKey === 'url' && typeof value === 'string') {\n result[key] = this.redactUrl(value);\n continue;\n }\n\n // Recursively redact nested objects\n if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n result[key] = this.deepRedact(value as Record<string, unknown>, level);\n continue;\n }\n\n // Recursively redact arrays\n if (Array.isArray(value)) {\n result[key] = value.map((item) => {\n if (item !== null && typeof item === 'object') {\n return this.deepRedact(item as Record<string, unknown>, level);\n }\n return item;\n });\n continue;\n }\n\n // Keep non-sensitive values\n result[key] = value;\n }\n\n return result;\n }\n\n /**\n * Check if a key is sensitive\n */\n private isSensitiveKey(key: string): boolean {\n return SENSITIVE_KEYS.some(\n (sensitive) => key === sensitive.toLowerCase() || key.includes(sensitive.toLowerCase())\n );\n }\n\n /**\n * Redact sensitive URL parameters\n */\n private redactUrl(url: string): string {\n try {\n const parsed = new URL(url);\n\n for (const param of SENSITIVE_URL_PARAMS) {\n if (parsed.searchParams.has(param)) {\n parsed.searchParams.set(param, '[REDACTED]');\n }\n }\n\n // Also check hash fragment\n if (parsed.hash) {\n const hashParams = new URLSearchParams(parsed.hash.slice(1));\n let hashModified = false;\n\n for (const param of SENSITIVE_URL_PARAMS) {\n if (hashParams.has(param)) {\n hashParams.set(param, '[REDACTED]');\n hashModified = true;\n }\n }\n\n if (hashModified) {\n parsed.hash = '#' + hashParams.toString();\n }\n }\n\n return parsed.toString();\n } catch {\n // If URL parsing fails, return with basic redaction\n return url.replace(/([?&])(code|token|state|nonce)=[^&]*/gi, '$1$2=[REDACTED]');\n }\n }\n}\n","/**\n * Debug Logger\n *\n * Platform-agnostic logging infrastructure for SDK debugging.\n */\n\nimport type { DebugLogger, DebugLogLevel, DebugOptions } from './types.js';\n\n/**\n * Create a console-based debug logger\n *\n * This logger writes to console with Authrim-prefixed messages.\n * Safe to use with any console implementation.\n */\nexport function createConsoleLogger(options?: {\n timestamps?: boolean;\n}): DebugLogger {\n const includeTimestamps = options?.timestamps ?? false;\n\n return {\n log(level: DebugLogLevel, message: string, data?: unknown): void {\n const prefix = includeTimestamps\n ? `[Authrim:${level.toUpperCase()} ${new Date().toISOString()}]`\n : `[Authrim:${level.toUpperCase()}]`;\n\n const consoleMethod = level === 'debug' ? 'log' : level;\n\n // Use globalThis.console to ensure platform compatibility\n const consoleObj = typeof console !== 'undefined' ? console : null;\n if (!consoleObj) return;\n\n if (data !== undefined) {\n consoleObj[consoleMethod]?.(prefix, message, data);\n } else {\n consoleObj[consoleMethod]?.(prefix, message);\n }\n },\n };\n}\n\n/**\n * No-op logger for when debug mode is disabled\n */\nexport const noopLogger: DebugLogger = {\n log(): void {\n // Intentionally empty\n },\n};\n\n/**\n * Create a debug logger based on options\n */\nexport function createDebugLogger(options: DebugOptions): DebugLogger {\n if (!options.enabled) {\n return noopLogger;\n }\n\n if (options.logger) {\n return options.logger;\n }\n\n return createConsoleLogger({\n timestamps: options.logTimestamps,\n });\n}\n\n/**\n * Debug context for tracking operations\n */\nexport class DebugContext {\n private logger: DebugLogger;\n private verbose: boolean;\n private operationId: string | null = null;\n\n constructor(logger: DebugLogger, options?: { verbose?: boolean }) {\n this.logger = logger;\n this.verbose = options?.verbose ?? false;\n }\n\n /**\n * Set current operation ID for log correlation\n */\n setOperationId(id: string | null): void {\n this.operationId = id;\n }\n\n /**\n * Get current operation ID\n */\n getOperationId(): string | null {\n return this.operationId;\n }\n\n /**\n * Log a debug message (verbose mode only)\n */\n debug(message: string, data?: unknown): void {\n if (this.verbose) {\n this.logger.log('debug', this.formatMessage(message), data);\n }\n }\n\n /**\n * Log an info message\n */\n info(message: string, data?: unknown): void {\n this.logger.log('info', this.formatMessage(message), data);\n }\n\n /**\n * Log a warning message\n */\n warn(message: string, data?: unknown): void {\n this.logger.log('warn', this.formatMessage(message), data);\n }\n\n /**\n * Log an error message\n */\n error(message: string, data?: unknown): void {\n this.logger.log('error', this.formatMessage(message), data);\n }\n\n /**\n * Format message with operation ID if available\n */\n private formatMessage(message: string): string {\n if (this.operationId) {\n return `[${this.operationId.slice(0, 8)}] ${message}`;\n }\n return message;\n }\n}\n","/**\n * Diagnostic Logger for SDK\n *\n * Provides diagnostic logging capabilities for debugging, troubleshooting,\n * and OIDF conformance testing. Integrates with server-side diagnostic logs\n * via diagnosticSessionId.\n *\n * Features:\n * - ID Token validation step logging\n * - Authentication decision logging\n * - Session ID correlation with server logs\n * - Console output and optional collection\n */\n\nimport type { DebugLogger } from './types.js';\n\n/**\n * Diagnostic log level\n */\nexport type DiagnosticLogLevel = 'debug' | 'info' | 'warn' | 'error';\n\n/**\n * Token validation step\n */\nexport type TokenValidationStep =\n | 'issuer-check'\n | 'audience-check'\n | 'expiry-check'\n | 'nonce-check'\n | 'signature-check'\n | 'hash-check';\n\n/**\n * Base diagnostic log entry\n */\nexport interface BaseDiagnosticLogEntry {\n /** Unique log entry ID */\n id: string;\n\n /** Diagnostic session ID (for correlation with server logs) */\n diagnosticSessionId: string;\n\n /** Log category */\n category: string;\n\n /** Log level */\n level: DiagnosticLogLevel;\n\n /** Timestamp (Unix epoch in milliseconds) */\n timestamp: number;\n\n /** Additional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Token Validation Log Entry\n */\nexport interface TokenValidationLogEntry extends BaseDiagnosticLogEntry {\n category: 'token-validation';\n\n /** Validation step */\n step: TokenValidationStep;\n\n /** Token type (id_token, access_token, etc.) */\n tokenType: string;\n\n /** Validation result */\n result: 'pass' | 'fail';\n\n /** Expected value (for validation) */\n expected?: unknown;\n\n /** Actual value (for validation) */\n actual?: unknown;\n\n /** Error message (if failed) */\n errorMessage?: string;\n\n /** Additional validation details */\n details?: Record<string, unknown>;\n}\n\n/**\n * Authentication Decision Log Entry\n */\nexport interface AuthDecisionLogEntry extends BaseDiagnosticLogEntry {\n category: 'auth-decision';\n\n /** Final authentication decision */\n decision: 'allow' | 'deny';\n\n /** Reason for the decision */\n reason: string;\n\n /** Authentication flow */\n flow?: string;\n\n /** Additional decision context */\n context?: Record<string, unknown>;\n}\n\n/**\n * Union type of all diagnostic log entries\n */\nexport type DiagnosticLogEntry = TokenValidationLogEntry | AuthDecisionLogEntry;\n\n/**\n * Common interface for diagnostic loggers\n *\n * This interface allows different diagnostic logger implementations\n * (Core SDK, Web SDK, Node SDK) to be used interchangeably.\n */\nexport interface IDiagnosticLogger {\n /**\n * Get diagnostic session ID\n */\n getDiagnosticSessionId(): string;\n\n /**\n * Check if diagnostic logging is enabled\n */\n isEnabled(): boolean;\n\n /**\n * Log token validation step\n */\n logTokenValidation(options: {\n step: TokenValidationStep;\n tokenType: string;\n result: 'pass' | 'fail';\n expected?: unknown;\n actual?: unknown;\n errorMessage?: string;\n details?: Record<string, unknown>;\n }): void;\n\n /**\n * Log authentication decision\n */\n logAuthDecision(options: {\n decision: 'allow' | 'deny';\n reason: string;\n flow?: string;\n context?: Record<string, unknown>;\n }): void;\n}\n\n/**\n * Diagnostic logger options\n */\nexport interface DiagnosticLoggerOptions {\n /** Enable diagnostic logging */\n enabled: boolean;\n\n /** Underlying debug logger */\n debugLogger?: DebugLogger;\n\n /** Collect logs in memory for export */\n collectLogs?: boolean;\n\n /** Maximum number of logs to collect (default: 1000) */\n maxLogs?: number;\n\n /** Send logs to server (default: false) */\n sendToServer?: boolean;\n\n /** Server URL for sending logs */\n serverUrl?: string;\n\n /** Client ID for authentication */\n clientId?: string;\n\n /** Client secret for authentication (confidential clients only) */\n clientSecret?: string;\n\n /** Batch size for sending logs (default: 50) */\n batchSize?: number;\n\n /** Flush interval in milliseconds (default: 5000) */\n flushIntervalMs?: number;\n}\n\n/**\n * Diagnostic Logger for SDK\n */\nexport class DiagnosticLogger implements IDiagnosticLogger {\n private diagnosticSessionId: string;\n private enabled: boolean;\n private debugLogger?: DebugLogger;\n private collectLogs: boolean;\n private maxLogs: number;\n private logs: DiagnosticLogEntry[] = [];\n\n // Server sending options\n private sendToServer: boolean;\n private serverUrl?: string;\n private clientId?: string;\n private clientSecret?: string;\n private batchSize: number;\n private flushIntervalMs: number;\n\n // Buffering for batch sending\n private sendBuffer: DiagnosticLogEntry[] = [];\n private flushTimer?: ReturnType<typeof setTimeout>;\n private isFlushing = false;\n\n constructor(options: DiagnosticLoggerOptions) {\n this.diagnosticSessionId = this.generateSessionId();\n this.enabled = options.enabled;\n this.debugLogger = options.debugLogger;\n this.collectLogs = options.collectLogs ?? false;\n this.maxLogs = options.maxLogs ?? 1000;\n\n // Server sending options\n this.sendToServer = options.sendToServer ?? false;\n this.serverUrl = options.serverUrl;\n this.clientId = options.clientId;\n this.clientSecret = options.clientSecret;\n this.batchSize = options.batchSize ?? 50;\n this.flushIntervalMs = options.flushIntervalMs ?? 5000;\n\n // Validate server sending config\n if (this.sendToServer && (!this.serverUrl || !this.clientId)) {\n if (this.debugLogger) {\n this.debugLogger.log(\n 'warn',\n '[DIAGNOSTIC] sendToServer is enabled but serverUrl or clientId is missing. Server sending disabled.'\n );\n }\n this.sendToServer = false;\n }\n }\n\n /**\n * Get diagnostic session ID\n *\n * This ID should be sent to the server via X-Diagnostic-Session-Id header\n * to correlate SDK logs with server logs.\n */\n getDiagnosticSessionId(): string {\n return this.diagnosticSessionId;\n }\n\n /**\n * Check if diagnostic logging is enabled\n */\n isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Log token validation step\n */\n logTokenValidation(options: {\n step: TokenValidationStep;\n tokenType: string;\n result: 'pass' | 'fail';\n expected?: unknown;\n actual?: unknown;\n errorMessage?: string;\n details?: Record<string, unknown>;\n }): void {\n if (!this.enabled) return;\n\n const entry: TokenValidationLogEntry = {\n id: this.generateEntryId(),\n diagnosticSessionId: this.diagnosticSessionId,\n category: 'token-validation',\n level: options.result === 'fail' ? 'error' : 'debug',\n timestamp: Date.now(),\n step: options.step,\n tokenType: options.tokenType,\n result: options.result,\n expected: options.expected,\n actual: options.actual,\n errorMessage: options.errorMessage,\n details: options.details,\n };\n\n this.writeLog(entry);\n }\n\n /**\n * Log authentication decision\n */\n logAuthDecision(options: {\n decision: 'allow' | 'deny';\n reason: string;\n flow?: string;\n context?: Record<string, unknown>;\n }): void {\n if (!this.enabled) return;\n\n const entry: AuthDecisionLogEntry = {\n id: this.generateEntryId(),\n diagnosticSessionId: this.diagnosticSessionId,\n category: 'auth-decision',\n level: options.decision === 'deny' ? 'warn' : 'info',\n timestamp: Date.now(),\n decision: options.decision,\n reason: options.reason,\n flow: options.flow,\n context: options.context,\n };\n\n this.writeLog(entry);\n }\n\n /**\n * Get all collected logs\n */\n getLogs(): DiagnosticLogEntry[] {\n return [...this.logs];\n }\n\n /**\n * Export logs as JSON string\n */\n exportLogs(): string {\n return JSON.stringify(this.logs, null, 2);\n }\n\n /**\n * Clear collected logs\n */\n clearLogs(): void {\n this.logs = [];\n }\n\n /**\n * Get buffered logs count (for debugging)\n */\n getBufferedLogsCount(): number {\n return this.sendBuffer.length;\n }\n\n /**\n * Write log entry (internal)\n */\n private writeLog(entry: DiagnosticLogEntry): void {\n // Output to debug logger\n if (this.debugLogger) {\n this.debugLogger.log(entry.level, `[DIAGNOSTIC] ${entry.category}`, entry);\n }\n\n // Collect in memory\n if (this.collectLogs) {\n this.logs.push(entry);\n\n // Trim if exceeds max\n if (this.logs.length > this.maxLogs) {\n this.logs.shift();\n }\n }\n\n // Buffer for server sending\n if (this.sendToServer) {\n this.bufferLog(entry);\n }\n }\n\n /**\n * Buffer log entry for batch sending\n */\n private bufferLog(entry: DiagnosticLogEntry): void {\n this.sendBuffer.push(entry);\n\n // Flush if batch size reached\n if (this.sendBuffer.length >= this.batchSize) {\n void this.flush();\n } else {\n // Schedule flush\n this.scheduleFlush();\n }\n }\n\n /**\n * Schedule automatic flush\n */\n private scheduleFlush(): void {\n // Clear existing timer\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n }\n\n // Set new timer\n this.flushTimer = setTimeout(() => {\n void this.flush();\n }, this.flushIntervalMs);\n }\n\n /**\n * Flush buffered logs to server\n */\n async flush(): Promise<void> {\n // Skip if already flushing or buffer is empty\n if (this.isFlushing || this.sendBuffer.length === 0) {\n return;\n }\n\n // Clear scheduled flush\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = undefined;\n }\n\n this.isFlushing = true;\n\n // Take logs from buffer\n const logsToSend = [...this.sendBuffer];\n this.sendBuffer = [];\n\n try {\n const response = await fetch(`${this.serverUrl}/api/v1/diagnostic-logs/ingest`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Diagnostic-Session-Id': this.diagnosticSessionId,\n },\n body: JSON.stringify({\n logs: logsToSend,\n client_id: this.clientId,\n client_secret: this.clientSecret,\n }),\n });\n\n if (!response.ok) {\n this.handleSendFailure(logsToSend, `HTTP ${response.status}: ${response.statusText}`);\n } else {\n if (this.debugLogger) {\n this.debugLogger.log('debug', `[DIAGNOSTIC] Sent ${logsToSend.length} logs to server`);\n }\n }\n } catch (error) {\n this.handleSendFailure(logsToSend, error instanceof Error ? error.message : String(error));\n } finally {\n this.isFlushing = false;\n }\n }\n\n /**\n * Handle send failure\n */\n private handleSendFailure(logs: DiagnosticLogEntry[], reason: string): void {\n if (this.debugLogger) {\n this.debugLogger.log('warn', `[DIAGNOSTIC] Failed to send logs to server: ${reason}`);\n }\n\n // If collectLogs is enabled, keep logs locally\n if (this.collectLogs) {\n for (const log of logs) {\n // Add to local collection if not already there\n if (!this.logs.some((l) => l.id === log.id)) {\n this.logs.push(log);\n\n // Trim if exceeds max\n if (this.logs.length > this.maxLogs) {\n this.logs.shift();\n }\n }\n }\n }\n }\n\n /**\n * Generate diagnostic session ID\n */\n private generateSessionId(): string {\n // Use crypto.randomUUID if available (modern browsers/Node.js)\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n\n // Fallback: generate UUID v4\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n const v = c === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n\n /**\n * Generate log entry ID\n */\n private generateEntryId(): string {\n return `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n}\n\n/**\n * Create a diagnostic logger\n *\n * @param options - Logger options\n * @returns DiagnosticLogger instance or null if disabled\n */\nexport function createDiagnosticLogger(options: DiagnosticLoggerOptions): DiagnosticLogger | null {\n if (!options.enabled) {\n return null;\n }\n\n return new DiagnosticLogger(options);\n}\n","/**\n * Hash Utilities\n *\n * Provides hash calculation utilities for OIDC specifications.\n */\n\nimport type { CryptoProvider } from '../providers/crypto.js';\nimport { base64urlEncode } from './base64url.js';\n\n/**\n * Calculate ds_hash for Native SSO device_secret verification\n *\n * Algorithm: BASE64URL(left half of SHA-256(device_secret))\n * Reference: OIDC Native SSO 1.0 specification\n *\n * This is the same algorithm used for at_hash and c_hash in OIDC Core,\n * applied to the device_secret value.\n *\n * @param deviceSecret - The device_secret value to hash\n * @param crypto - Platform-specific crypto provider\n * @returns ds_hash value (BASE64URL encoded)\n *\n * @example\n * ```typescript\n * const dsHash = await calculateDsHash(deviceSecret, cryptoProvider);\n * // Compare with id_token.ds_hash claim\n * if (idToken.ds_hash === dsHash) {\n * // device_secret is valid\n * }\n * ```\n */\nexport async function calculateDsHash(\n deviceSecret: string,\n crypto: CryptoProvider\n): Promise<string> {\n // 1. Compute SHA-256 hash (32 bytes)\n const hash = await crypto.sha256(deviceSecret);\n\n // 2. Take the left half (16 bytes for SHA-256)\n const leftHalf = hash.slice(0, hash.length / 2);\n\n // 3. BASE64URL encode\n return base64urlEncode(leftHalf);\n}\n","/**\n * Cancellation Utilities\n *\n * Provides AbortController-based cancellation for async operations.\n */\n\nimport { AuthrimError } from '../types/errors.js';\n\n/**\n * Wrap a promise with AbortSignal support\n *\n * If the signal is aborted, the promise will reject with an\n * 'operation_cancelled' error which is recoverable and retryable.\n *\n * @param promise - Promise to wrap\n * @param signal - AbortSignal to use for cancellation\n * @returns Promise that can be cancelled\n */\nexport function withAbortSignal<T>(\n promise: Promise<T>,\n signal: AbortSignal\n): Promise<T> {\n return new Promise((resolve, reject) => {\n const cancelledError = new AuthrimError(\n 'operation_cancelled',\n 'Operation was cancelled'\n );\n\n // Already aborted\n if (signal.aborted) {\n reject(cancelledError);\n return;\n }\n\n const onAbort = () => {\n reject(cancelledError);\n };\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n promise\n .then(resolve)\n .catch(reject)\n .finally(() => {\n signal.removeEventListener('abort', onAbort);\n });\n });\n}\n\n/**\n * Create a cancellable operation wrapper\n *\n * Returns an object with the promise and a cancel function.\n * Useful for creating operations that can be externally cancelled.\n *\n * @param fn - Async function to execute\n * @returns Object with promise and cancel function\n */\nexport function createCancellableOperation<T>(\n fn: (signal: AbortSignal) => Promise<T>\n): {\n promise: Promise<T>;\n cancel: () => void;\n signal: AbortSignal;\n} {\n const controller = new AbortController();\n\n return {\n promise: fn(controller.signal),\n cancel: () => controller.abort(),\n signal: controller.signal,\n };\n}\n\n/**\n * Check if an error is a cancellation error\n */\nexport function isCancellationError(error: unknown): boolean {\n return error instanceof AuthrimError && error.code === 'operation_cancelled';\n}\n\n/**\n * Race multiple promises with cancellation support\n *\n * When one promise resolves, other operations are cancelled.\n *\n * @param operations - Array of operations with their signals\n * @returns Result of the first successful operation\n */\nexport async function raceWithCancellation<T>(\n operations: Array<{\n promise: Promise<T>;\n cancel: () => void;\n }>\n): Promise<T> {\n try {\n const result = await Promise.race(operations.map((op) => op.promise));\n // Cancel all other operations\n operations.forEach((op) => op.cancel());\n return result;\n } catch (error) {\n // Cancel all operations on error\n operations.forEach((op) => op.cancel());\n throw error;\n }\n}\n","/**\n * Retry Utilities\n *\n * Provides exponential backoff retry logic with jitter.\n */\n\nimport { AuthrimError, isRetryableError } from '../types/errors.js';\nimport { isCancellationError } from './cancellation.js';\n\n/**\n * Retry options\n */\nexport interface RetryOptions {\n /** Maximum number of retry attempts (default: 3) */\n maxRetries?: number;\n /** Base delay in milliseconds (default: 1000) */\n baseDelayMs?: number;\n /** Maximum delay in milliseconds (default: 30000) */\n maxDelayMs?: number;\n /** Enable jitter for delay randomization (default: true) */\n jitter?: boolean;\n /** AbortSignal for cancellation */\n signal?: AbortSignal;\n /** Custom retry condition (default: check isRetryableError) */\n shouldRetry?: (error: unknown, attempt: number) => boolean;\n /** Callback for each retry attempt */\n onRetry?: (error: unknown, attempt: number, delayMs: number) => void;\n}\n\n/**\n * Default retry options\n */\nconst DEFAULT_RETRY_OPTIONS: Required<Omit<RetryOptions, 'signal' | 'shouldRetry' | 'onRetry'>> = {\n maxRetries: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30000,\n jitter: true,\n};\n\n/**\n * Calculate delay with exponential backoff and optional jitter\n *\n * @param attempt - Current attempt number (0-indexed)\n * @param baseDelayMs - Base delay in milliseconds\n * @param maxDelayMs - Maximum delay in milliseconds\n * @param jitter - Whether to add jitter\n * @returns Delay in milliseconds\n */\nexport function calculateBackoffDelay(\n attempt: number,\n baseDelayMs: number,\n maxDelayMs: number,\n jitter: boolean\n): number {\n // Exponential backoff: baseDelay * 2^attempt\n const exponentialDelay = baseDelayMs * Math.pow(2, attempt);\n\n // Cap at max delay\n const cappedDelay = Math.min(exponentialDelay, maxDelayMs);\n\n // Add jitter if enabled (±25% of delay)\n if (jitter) {\n const jitterRange = cappedDelay * 0.5; // ±25%\n const jitterValue = Math.random() * jitterRange - jitterRange / 2;\n return Math.max(0, Math.floor(cappedDelay + jitterValue));\n }\n\n return cappedDelay;\n}\n\n/**\n * Sleep for a specified duration\n *\n * @param ms - Duration in milliseconds\n * @param signal - Optional AbortSignal for cancellation\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(new AuthrimError('operation_cancelled', 'Sleep was cancelled'));\n return;\n }\n\n const timeout = setTimeout(resolve, ms);\n\n if (signal) {\n const onAbort = () => {\n clearTimeout(timeout);\n reject(new AuthrimError('operation_cancelled', 'Sleep was cancelled'));\n };\n signal.addEventListener('abort', onAbort, { once: true });\n }\n });\n}\n\n/**\n * Execute a function with exponential backoff retry\n *\n * @param fn - Function to execute\n * @param options - Retry options\n * @returns Result of the function\n */\nexport async function withRetry<T>(\n fn: () => Promise<T>,\n options?: RetryOptions\n): Promise<T> {\n const opts = { ...DEFAULT_RETRY_OPTIONS, ...options };\n const { maxRetries, baseDelayMs, maxDelayMs, jitter, signal, shouldRetry, onRetry } = opts;\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n // Check for cancellation before each attempt\n if (signal?.aborted) {\n throw new AuthrimError('operation_cancelled', 'Operation was cancelled');\n }\n\n return await fn();\n } catch (error) {\n lastError = error;\n\n // Don't retry cancellation errors\n if (isCancellationError(error)) {\n throw error;\n }\n\n // Check if we should retry\n const canRetry = shouldRetry\n ? shouldRetry(error, attempt)\n : error instanceof AuthrimError && isRetryableError(error);\n\n // Don't retry if max attempts reached or error is not retryable\n if (attempt >= maxRetries || !canRetry) {\n throw error;\n }\n\n // Calculate delay\n const delayMs = calculateBackoffDelay(attempt, baseDelayMs, maxDelayMs, jitter);\n\n // Notify retry callback\n onRetry?.(error, attempt + 1, delayMs);\n\n // Wait before retry\n await sleep(delayMs, signal);\n }\n }\n\n // This should not be reached, but just in case\n throw lastError;\n}\n\n/**\n * Create a retry function with preset options\n *\n * Useful for creating specialized retry functions for specific use cases.\n *\n * @param defaultOptions - Default options for all retries\n * @returns Retry function with preset options\n */\nexport function createRetryFunction(\n defaultOptions: RetryOptions\n): <T>(fn: () => Promise<T>, options?: RetryOptions) => Promise<T> {\n return <T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T> => {\n return withRetry(fn, { ...defaultOptions, ...options });\n };\n}\n\n/**\n * Extract Retry-After header value\n *\n * Supports both HTTP-date and delay-seconds formats.\n *\n * @param headers - Response headers\n * @returns Delay in milliseconds, or null if not found\n */\nexport function parseRetryAfterHeader(\n headers: Headers | Record<string, string>\n): number | null {\n const retryAfter = headers instanceof Headers\n ? headers.get('retry-after')\n : headers['retry-after'] ?? headers['Retry-After'];\n\n if (!retryAfter) {\n return null;\n }\n\n // Try parsing as seconds (most common)\n const seconds = parseInt(retryAfter, 10);\n if (!isNaN(seconds)) {\n return seconds * 1000;\n }\n\n // Try parsing as HTTP-date\n const date = new Date(retryAfter);\n if (!isNaN(date.getTime())) {\n const delayMs = date.getTime() - Date.now();\n return Math.max(0, delayMs);\n }\n\n return null;\n}\n"]}
|