"use strict"; (() => { // src/shared/auth-config.ts var defaultAuthConfig = { apiResource: "https://talent-search.intelligrow.cn", appId: "i4jkllbvih0554r4n0fd3", enableDevAuthPanel: false, logtoEndpoint: "https://login-api.intelligrow.cn", scopes: ["openid", "profile", "offline_access", "talent-search:read"] }; function readAuthConfig(overrides = {}) { const nextConfig = { ...defaultAuthConfig, ...overrides }; if (!nextConfig.logtoEndpoint.trim()) { throw new Error("auth config logtoEndpoint is required"); } if (!nextConfig.appId.trim()) { throw new Error("auth config appId is required"); } if (!nextConfig.apiResource.trim()) { throw new Error("auth config apiResource is required"); } return nextConfig; } // src/background/auth/state.ts function createLoggedOutAuthState(config) { return { isAuthenticated: false, resource: config?.apiResource ?? null }; } function createLoggedInAuthState(claims, config) { return { accessTokenExpiresAt: null, isAuthenticated: true, resource: config?.apiResource ?? null, scopes: config?.scopes ?? [], tokenAvailable: true, userInfo: { email: readStringClaim(claims, "email"), name: readStringClaim(claims, "name"), sub: readStringClaim(claims, "sub"), username: readStringClaim(claims, "username") } }; } function readStringClaim(claims, key) { const value = claims?.[key]; return typeof value === "string" ? value : void 0; } // src/background/auth/controller.ts function createAuthController(options) { const config = options.config ?? readAuthConfig(); return { async getAccessToken() { return options.authClient.getAccessToken(config.apiResource); }, async getAuthState() { const isAuthenticated = await options.authClient.isAuthenticated(); if (!isAuthenticated) { return createLoggedOutAuthState(config); } const claims = await options.authClient.getIdTokenClaims(); return createLoggedInAuthState(claims, config); }, async signIn() { await options.authClient.signIn(); }, async signOut() { await options.authClient.signOut(); } }; } // node_modules/map-obj/index.js var isObject = (value) => typeof value === "object" && value !== null; var isObjectCustom = (value) => isObject(value) && !(value instanceof RegExp) && !(value instanceof Error) && !(value instanceof Date); var mapObjectSkip = /* @__PURE__ */ Symbol("mapObjectSkip"); var _mapObject = (object, mapper, options, isSeen = /* @__PURE__ */ new WeakMap()) => { options = { deep: false, target: {}, ...options }; if (isSeen.has(object)) { return isSeen.get(object); } isSeen.set(object, options.target); const { target } = options; delete options.target; const mapArray = (array) => array.map((element) => isObjectCustom(element) ? _mapObject(element, mapper, options, isSeen) : element); if (Array.isArray(object)) { return mapArray(object); } for (const [key, value] of Object.entries(object)) { const mapResult = mapper(key, value, object); if (mapResult === mapObjectSkip) { continue; } let [newKey, newValue, { shouldRecurse = true } = {}] = mapResult; if (newKey === "__proto__") { continue; } if (options.deep && shouldRecurse && isObjectCustom(newValue)) { newValue = Array.isArray(newValue) ? mapArray(newValue) : _mapObject(newValue, mapper, options, isSeen); } target[newKey] = newValue; } return target; }; function mapObject(object, mapper, options) { if (!isObject(object)) { throw new TypeError(`Expected an object, got \`${object}\` (${typeof object})`); } return _mapObject(object, mapper, options); } // node_modules/camelcase/index.js var UPPERCASE = /[\p{Lu}]/u; var LOWERCASE = /[\p{Ll}]/u; var LEADING_CAPITAL = /^[\p{Lu}](?![\p{Lu}])/gu; var IDENTIFIER = /([\p{Alpha}\p{N}_]|$)/u; var SEPARATORS = /[_.\- ]+/; var LEADING_SEPARATORS = new RegExp("^" + SEPARATORS.source); var SEPARATORS_AND_IDENTIFIER = new RegExp(SEPARATORS.source + IDENTIFIER.source, "gu"); var NUMBERS_AND_IDENTIFIER = new RegExp("\\d+" + IDENTIFIER.source, "gu"); var preserveCamelCase = (string, toLowerCase, toUpperCase, preserveConsecutiveUppercase2) => { let isLastCharLower = false; let isLastCharUpper = false; let isLastLastCharUpper = false; let isLastLastCharPreserved = false; for (let index = 0; index < string.length; index++) { const character = string[index]; isLastLastCharPreserved = index > 2 ? string[index - 3] === "-" : true; if (isLastCharLower && UPPERCASE.test(character)) { string = string.slice(0, index) + "-" + string.slice(index); isLastCharLower = false; isLastLastCharUpper = isLastCharUpper; isLastCharUpper = true; index++; } else if (isLastCharUpper && isLastLastCharUpper && LOWERCASE.test(character) && (!isLastLastCharPreserved || preserveConsecutiveUppercase2)) { string = string.slice(0, index - 1) + "-" + string.slice(index - 1); isLastLastCharUpper = isLastCharUpper; isLastCharUpper = false; isLastCharLower = true; } else { isLastCharLower = toLowerCase(character) === character && toUpperCase(character) !== character; isLastLastCharUpper = isLastCharUpper; isLastCharUpper = toUpperCase(character) === character && toLowerCase(character) !== character; } } return string; }; var preserveConsecutiveUppercase = (input, toLowerCase) => { LEADING_CAPITAL.lastIndex = 0; return input.replaceAll(LEADING_CAPITAL, (match) => toLowerCase(match)); }; var postProcess = (input, toUpperCase) => { SEPARATORS_AND_IDENTIFIER.lastIndex = 0; NUMBERS_AND_IDENTIFIER.lastIndex = 0; return input.replaceAll(NUMBERS_AND_IDENTIFIER, (match, pattern, offset) => ["_", "-"].includes(input.charAt(offset + match.length)) ? match : toUpperCase(match)).replaceAll(SEPARATORS_AND_IDENTIFIER, (_, identifier) => toUpperCase(identifier)); }; function camelCase(input, options) { if (!(typeof input === "string" || Array.isArray(input))) { throw new TypeError("Expected the input to be `string | string[]`"); } options = { pascalCase: false, preserveConsecutiveUppercase: false, ...options }; if (Array.isArray(input)) { input = input.map((x) => x.trim()).filter((x) => x.length).join("-"); } else { input = input.trim(); } if (input.length === 0) { return ""; } const toLowerCase = options.locale === false ? (string) => string.toLowerCase() : (string) => string.toLocaleLowerCase(options.locale); const toUpperCase = options.locale === false ? (string) => string.toUpperCase() : (string) => string.toLocaleUpperCase(options.locale); if (input.length === 1) { if (SEPARATORS.test(input)) { return ""; } return options.pascalCase ? toUpperCase(input) : toLowerCase(input); } const hasUpperCase = input !== toLowerCase(input); if (hasUpperCase) { input = preserveCamelCase(input, toLowerCase, toUpperCase, options.preserveConsecutiveUppercase); } input = input.replace(LEADING_SEPARATORS, ""); input = options.preserveConsecutiveUppercase ? preserveConsecutiveUppercase(input, toLowerCase) : toLowerCase(input); if (options.pascalCase) { input = toUpperCase(input.charAt(0)) + input.slice(1); } return postProcess(input, toUpperCase); } // node_modules/quick-lru/index.js var QuickLRU = class extends Map { constructor(options = {}) { super(); if (!(options.maxSize && options.maxSize > 0)) { throw new TypeError("`maxSize` must be a number greater than 0"); } if (typeof options.maxAge === "number" && options.maxAge === 0) { throw new TypeError("`maxAge` must be a number greater than 0"); } this.maxSize = options.maxSize; this.maxAge = options.maxAge || Number.POSITIVE_INFINITY; this.onEviction = options.onEviction; this.cache = /* @__PURE__ */ new Map(); this.oldCache = /* @__PURE__ */ new Map(); this._size = 0; } // TODO: Use private class methods when targeting Node.js 16. _emitEvictions(cache2) { if (typeof this.onEviction !== "function") { return; } for (const [key, item] of cache2) { this.onEviction(key, item.value); } } _deleteIfExpired(key, item) { if (typeof item.expiry === "number" && item.expiry <= Date.now()) { if (typeof this.onEviction === "function") { this.onEviction(key, item.value); } return this.delete(key); } return false; } _getOrDeleteIfExpired(key, item) { const deleted = this._deleteIfExpired(key, item); if (deleted === false) { return item.value; } } _getItemValue(key, item) { return item.expiry ? this._getOrDeleteIfExpired(key, item) : item.value; } _peek(key, cache2) { const item = cache2.get(key); return this._getItemValue(key, item); } _set(key, value) { this.cache.set(key, value); this._size++; if (this._size >= this.maxSize) { this._size = 0; this._emitEvictions(this.oldCache); this.oldCache = this.cache; this.cache = /* @__PURE__ */ new Map(); } } _moveToRecent(key, item) { this.oldCache.delete(key); this._set(key, item); } *_entriesAscending() { for (const item of this.oldCache) { const [key, value] = item; if (!this.cache.has(key)) { const deleted = this._deleteIfExpired(key, value); if (deleted === false) { yield item; } } } for (const item of this.cache) { const [key, value] = item; const deleted = this._deleteIfExpired(key, value); if (deleted === false) { yield item; } } } get(key) { if (this.cache.has(key)) { const item = this.cache.get(key); return this._getItemValue(key, item); } if (this.oldCache.has(key)) { const item = this.oldCache.get(key); if (this._deleteIfExpired(key, item) === false) { this._moveToRecent(key, item); return item.value; } } } set(key, value, { maxAge = this.maxAge } = {}) { const expiry = typeof maxAge === "number" && maxAge !== Number.POSITIVE_INFINITY ? Date.now() + maxAge : void 0; if (this.cache.has(key)) { this.cache.set(key, { value, expiry }); } else { this._set(key, { value, expiry }); } return this; } has(key) { if (this.cache.has(key)) { return !this._deleteIfExpired(key, this.cache.get(key)); } if (this.oldCache.has(key)) { return !this._deleteIfExpired(key, this.oldCache.get(key)); } return false; } peek(key) { if (this.cache.has(key)) { return this._peek(key, this.cache); } if (this.oldCache.has(key)) { return this._peek(key, this.oldCache); } } delete(key) { const deleted = this.cache.delete(key); if (deleted) { this._size--; } return this.oldCache.delete(key) || deleted; } clear() { this.cache.clear(); this.oldCache.clear(); this._size = 0; } resize(newSize) { if (!(newSize && newSize > 0)) { throw new TypeError("`maxSize` must be a number greater than 0"); } const items = [...this._entriesAscending()]; const removeCount = items.length - newSize; if (removeCount < 0) { this.cache = new Map(items); this.oldCache = /* @__PURE__ */ new Map(); this._size = items.length; } else { if (removeCount > 0) { this._emitEvictions(items.slice(0, removeCount)); } this.oldCache = new Map(items.slice(removeCount)); this.cache = /* @__PURE__ */ new Map(); this._size = 0; } this.maxSize = newSize; } *keys() { for (const [key] of this) { yield key; } } *values() { for (const [, value] of this) { yield value; } } *[Symbol.iterator]() { for (const item of this.cache) { const [key, value] = item; const deleted = this._deleteIfExpired(key, value); if (deleted === false) { yield [key, value.value]; } } for (const item of this.oldCache) { const [key, value] = item; if (!this.cache.has(key)) { const deleted = this._deleteIfExpired(key, value); if (deleted === false) { yield [key, value.value]; } } } } *entriesDescending() { let items = [...this.cache]; for (let i = items.length - 1; i >= 0; --i) { const item = items[i]; const [key, value] = item; const deleted = this._deleteIfExpired(key, value); if (deleted === false) { yield [key, value.value]; } } items = [...this.oldCache]; for (let i = items.length - 1; i >= 0; --i) { const item = items[i]; const [key, value] = item; if (!this.cache.has(key)) { const deleted = this._deleteIfExpired(key, value); if (deleted === false) { yield [key, value.value]; } } } } *entriesAscending() { for (const [key, value] of this._entriesAscending()) { yield [key, value.value]; } } get size() { if (!this._size) { return this.oldCache.size; } let oldCacheSize = 0; for (const key of this.oldCache.keys()) { if (!this.cache.has(key)) { oldCacheSize++; } } return Math.min(this._size + oldCacheSize, this.maxSize); } entries() { return this.entriesAscending(); } forEach(callbackFunction, thisArgument = this) { for (const [key, value] of this.entriesAscending()) { callbackFunction.call(thisArgument, value, key, this); } } get [Symbol.toStringTag]() { return JSON.stringify([...this.entriesAscending()]); } }; // node_modules/camelcase-keys/index.js var has = (array, key) => array.some((element) => { if (typeof element === "string") { return element === key; } element.lastIndex = 0; return element.test(key); }); var cache = new QuickLRU({ maxSize: 1e5 }); var isObject2 = (value) => typeof value === "object" && value !== null && !(value instanceof RegExp) && !(value instanceof Error) && !(value instanceof Date); var transform = (input, options = {}) => { if (!isObject2(input)) { return input; } const { exclude, pascalCase = false, stopPaths, deep = false, preserveConsecutiveUppercase: preserveConsecutiveUppercase2 = false } = options; const stopPathsSet = new Set(stopPaths); const makeMapper = (parentPath) => (key, value) => { if (deep && isObject2(value)) { const path = parentPath === void 0 ? key : `${parentPath}.${key}`; if (!stopPathsSet.has(path)) { value = mapObject(value, makeMapper(path)); } } if (!(exclude && has(exclude, key))) { const cacheKey = pascalCase ? `${key}_` : key; if (cache.has(cacheKey)) { key = cache.get(cacheKey); } else { const returnValue = camelCase(key, { pascalCase, locale: false, preserveConsecutiveUppercase: preserveConsecutiveUppercase2 }); if (key.length < 100) { cache.set(cacheKey, returnValue); } key = returnValue; } } return [key, value]; }; return mapObject(input, makeMapper(void 0)); }; function camelcaseKeys(input, options) { if (Array.isArray(input)) { return Object.keys(input).map((key) => transform(input[key], options)); } return transform(input, options); } // node_modules/@logto/js/lib/consts/openid.js var ReservedScope; (function(ReservedScope2) { ReservedScope2["OpenId"] = "openid"; ReservedScope2["OfflineAccess"] = "offline_access"; })(ReservedScope || (ReservedScope = {})); var ReservedResource; (function(ReservedResource2) { ReservedResource2["Organization"] = "urn:logto:resource:organizations"; })(ReservedResource || (ReservedResource = {})); var UserScope; (function(UserScope2) { UserScope2["Profile"] = "profile"; UserScope2["Email"] = "email"; UserScope2["Phone"] = "phone"; UserScope2["Address"] = "address"; UserScope2["CustomData"] = "custom_data"; UserScope2["Identities"] = "identities"; UserScope2["Roles"] = "roles"; UserScope2["Organizations"] = "urn:logto:scope:organizations"; UserScope2["OrganizationRoles"] = "urn:logto:scope:organization_roles"; UserScope2["Sessions"] = "urn:logto:scope:sessions"; })(UserScope || (UserScope = {})); var idTokenClaims = Object.freeze({ [UserScope.Profile]: ["name", "picture", "username"], [UserScope.Email]: ["email", "email_verified"], [UserScope.Phone]: ["phone_number", "phone_number_verified"], [UserScope.Address]: [], [UserScope.Roles]: ["roles"], [UserScope.Organizations]: ["organizations"], [UserScope.OrganizationRoles]: ["organization_roles"], [UserScope.CustomData]: [], [UserScope.Identities]: [], [UserScope.Sessions]: [] }); var userinfoClaims = Object.freeze({ [UserScope.Profile]: [], [UserScope.Email]: [], [UserScope.Phone]: [], [UserScope.Address]: [], [UserScope.Roles]: [], [UserScope.Organizations]: [], [UserScope.OrganizationRoles]: [], [UserScope.CustomData]: ["custom_data"], [UserScope.Identities]: ["identities"], [UserScope.Sessions]: [] }); var userClaims = Object.freeze( // Hard to infer type directly, use `as` for a workaround. // eslint-disable-next-line no-restricted-syntax Object.fromEntries(Object.values(UserScope).map((current) => [ current, [...idTokenClaims[current], ...userinfoClaims[current]] ])) ); // node_modules/@logto/js/lib/consts/index.js var ContentType = { formUrlEncoded: { "Content-Type": "application/x-www-form-urlencoded" } }; var TokenGrantType; (function(TokenGrantType2) { TokenGrantType2["AuthorizationCode"] = "authorization_code"; TokenGrantType2["RefreshToken"] = "refresh_token"; })(TokenGrantType || (TokenGrantType = {})); var QueryKey; (function(QueryKey2) { QueryKey2["ClientId"] = "client_id"; QueryKey2["Code"] = "code"; QueryKey2["CodeChallenge"] = "code_challenge"; QueryKey2["CodeChallengeMethod"] = "code_challenge_method"; QueryKey2["CodeVerifier"] = "code_verifier"; QueryKey2["Error"] = "error"; QueryKey2["ErrorDescription"] = "error_description"; QueryKey2["GrantType"] = "grant_type"; QueryKey2["IdToken"] = "id_token"; QueryKey2["IdTokenHint"] = "id_token_hint"; QueryKey2["LoginHint"] = "login_hint"; QueryKey2["PostLogoutRedirectUri"] = "post_logout_redirect_uri"; QueryKey2["Prompt"] = "prompt"; QueryKey2["RedirectUri"] = "redirect_uri"; QueryKey2["RefreshToken"] = "refresh_token"; QueryKey2["Resource"] = "resource"; QueryKey2["ResponseType"] = "response_type"; QueryKey2["Scope"] = "scope"; QueryKey2["State"] = "state"; QueryKey2["Token"] = "token"; QueryKey2["InteractionMode"] = "interaction_mode"; QueryKey2["OrganizationId"] = "organization_id"; QueryKey2["FirstScreen"] = "first_screen"; QueryKey2["Identifier"] = "identifier"; QueryKey2["DirectSignIn"] = "direct_sign_in"; QueryKey2["OneTimeToken"] = "one_time_token"; })(QueryKey || (QueryKey = {})); var Prompt; (function(Prompt2) { Prompt2["None"] = "none"; Prompt2["Consent"] = "consent"; Prompt2["Login"] = "login"; })(Prompt || (Prompt = {})); // node_modules/@logto/js/lib/core/fetch-token.js var fetchTokenByAuthorizationCode = async ({ clientId, tokenEndpoint, redirectUri, codeVerifier, code, resource }, requester) => { const parameters = new URLSearchParams(); parameters.append(QueryKey.ClientId, clientId); parameters.append(QueryKey.Code, code); parameters.append(QueryKey.CodeVerifier, codeVerifier); parameters.append(QueryKey.RedirectUri, redirectUri); parameters.append(QueryKey.GrantType, TokenGrantType.AuthorizationCode); if (resource) { parameters.append(QueryKey.Resource, resource); } const snakeCaseCodeTokenResponse = await requester(tokenEndpoint, { method: "POST", headers: ContentType.formUrlEncoded, body: parameters.toString() }); return camelcaseKeys(snakeCaseCodeTokenResponse); }; var fetchTokenByRefreshToken = async (params, requester) => { const { clientId, tokenEndpoint, refreshToken, resource, organizationId, scopes } = params; const parameters = new URLSearchParams(); parameters.append(QueryKey.ClientId, clientId); parameters.append(QueryKey.RefreshToken, refreshToken); parameters.append(QueryKey.GrantType, TokenGrantType.RefreshToken); if (resource) { parameters.append(QueryKey.Resource, resource); } if (organizationId) { parameters.append(QueryKey.OrganizationId, organizationId); } if (scopes?.length) { parameters.append(QueryKey.Scope, scopes.join(" ")); } const snakeCaseRefreshTokenTokenResponse = await requester(tokenEndpoint, { method: "POST", headers: ContentType.formUrlEncoded, body: parameters.toString() }); return camelcaseKeys(snakeCaseRefreshTokenTokenResponse); }; // node_modules/@logto/js/lib/core/oidc-config.js var discoveryPath = "/oidc/.well-known/openid-configuration"; var fetchOidcConfig = async (endpoint, requester) => camelcaseKeys(await requester(endpoint)); // node_modules/@logto/js/lib/core/revoke.js var revoke = async (revocationEndpoint, clientId, token, requester) => requester(revocationEndpoint, { method: "POST", headers: ContentType.formUrlEncoded, body: new URLSearchParams({ [QueryKey.ClientId]: clientId, [QueryKey.Token]: token }).toString() }); // node_modules/@logto/js/lib/utils/scopes.js var withReservedScopes = (originalScopes) => { const reservedScopes = Object.values(ReservedScope); const uniqueScopes = /* @__PURE__ */ new Set([...reservedScopes, UserScope.Profile, ...originalScopes ?? []]); return Array.from(uniqueScopes).join(" "); }; // node_modules/@logto/js/lib/core/sign-in.js var codeChallengeMethod = "S256"; var responseType = "code"; var buildPrompt = (prompt) => { if (Array.isArray(prompt)) { return prompt.join(" "); } return prompt ?? Prompt.Consent; }; var generateSignInUri = ({ authorizationEndpoint, clientId, redirectUri, codeChallenge, state, scopes, resources, prompt, firstScreen, identifiers: identifier, interactionMode, loginHint, directSignIn, oneTimeToken, extraParams, includeReservedScopes = true }) => { const urlSearchParameters = new URLSearchParams({ [QueryKey.ClientId]: clientId, [QueryKey.RedirectUri]: redirectUri, [QueryKey.CodeChallenge]: codeChallenge, [QueryKey.CodeChallengeMethod]: codeChallengeMethod, [QueryKey.State]: state, [QueryKey.ResponseType]: responseType, [QueryKey.Prompt]: buildPrompt(prompt) }); const computedScopes = includeReservedScopes ? withReservedScopes(scopes) : scopes?.join(" "); if (computedScopes) { urlSearchParameters.append(QueryKey.Scope, computedScopes); } if (loginHint) { urlSearchParameters.append(QueryKey.LoginHint, loginHint); } if (directSignIn) { urlSearchParameters.append(QueryKey.DirectSignIn, `${directSignIn.method}:${directSignIn.target}`); } for (const resource of resources ?? []) { urlSearchParameters.append(QueryKey.Resource, resource); } if (firstScreen) { urlSearchParameters.append(QueryKey.FirstScreen, firstScreen); } else if (interactionMode) { urlSearchParameters.append(QueryKey.InteractionMode, interactionMode); } if (identifier && identifier.length > 0) { urlSearchParameters.append(QueryKey.Identifier, identifier.join(" ")); } if (oneTimeToken) { urlSearchParameters.append(QueryKey.OneTimeToken, oneTimeToken); } if (extraParams) { for (const [key, value] of Object.entries(extraParams)) { urlSearchParameters.append(key, value); } } return `${authorizationEndpoint}?${urlSearchParameters.toString()}`; }; // node_modules/@logto/js/lib/core/sign-out.js var generateSignOutUri = ({ endSessionEndpoint, clientId, postLogoutRedirectUri }) => { const urlSearchParameters = new URLSearchParams({ [QueryKey.ClientId]: clientId }); if (postLogoutRedirectUri) { urlSearchParameters.append(QueryKey.PostLogoutRedirectUri, postLogoutRedirectUri); } return `${endSessionEndpoint}?${urlSearchParameters.toString()}`; }; // node_modules/@logto/js/lib/core/user-info.js var fetchUserInfo = async (userInfoEndpoint, accessToken, requester) => requester(userInfoEndpoint, { headers: { Authorization: `Bearer ${accessToken}` } }); // node_modules/@silverhand/essentials/lib/utilities/array.js var deduplicate = (array) => [...new Set(array)]; // node_modules/@silverhand/essentials/lib/utilities/assertions.js var notFalsy = (value) => Boolean(value); // node_modules/@silverhand/essentials/lib/utilities/conditional.js var conditional = (exp) => notFalsy(exp) ? exp : void 0; var conditionalString = (exp) => notFalsy(exp) ? String(exp) : ""; // node_modules/@silverhand/essentials/lib/utilities/function.js var isPromise = (value) => value !== null && (typeof value === "object" || typeof value === "function") && "then" in value && typeof value.then === "function"; var trySafe = (exec, onError) => { try { const unwrapped = typeof exec === "function" ? exec() : exec; return isPromise(unwrapped) ? ( // eslint-disable-next-line promise/prefer-await-to-then unwrapped.catch((error) => { onError?.(error); }) ) : unwrapped; } catch (error) { onError?.(error); } }; // node_modules/@silverhand/essentials/lib/utilities/string.js var replaceNonUrlSafeCharacters = (base64String) => base64String.replaceAll("+", "-").replaceAll("/", "_").replaceAll(/=+$/g, ""); var restoreNonUrlSafeCharacters = (base64String) => base64String.replaceAll("-", "+").replaceAll("_", "/"); var urlSafeBase64 = { isSafe: (input) => /^[\w-]*$/.test(input), encode: (rawString) => { const encodedString = btoa(unescape(encodeURIComponent(rawString))); return replaceNonUrlSafeCharacters(encodedString); }, decode: (encodedString) => { const nonUrlSafeEncodedString = restoreNonUrlSafeCharacters(encodedString); return decodeURIComponent(escape(atob(nonUrlSafeEncodedString))); }, replaceNonUrlSafeCharacters, restoreNonUrlSafeCharacters }; // node_modules/@silverhand/essentials/lib/utilities/url.js var joinPath = (...segments) => { const result = []; for (const segment of segments.join("/").split("/")) { if (!segment || segment === ".") { continue; } if ([...segment].every((char) => char === ".")) { result.pop(); continue; } result.push(segment); } return "/" + result.join("/"); }; var appendPath = (baseUrl, ...pathnames) => new URL(joinPath(baseUrl.pathname, ...pathnames), baseUrl); // node_modules/@logto/js/lib/utils/arbitrary-object.js var isArbitraryObject = (data) => typeof data === "object" && data !== null; // node_modules/@logto/js/lib/utils/errors.js var logtoErrorCodes = Object.freeze({ "id_token.invalid_iat": "Invalid issued at time in the ID token", "id_token.invalid_token": "Invalid ID token", "callback_uri_verification.redirect_uri_mismatched": "The callback URI mismatches the redirect URI.", "callback_uri_verification.error_found": "Error found in the callback URI", "callback_uri_verification.missing_state": "Missing state in the callback URI", "callback_uri_verification.state_mismatched": "State mismatched in the callback URI", "callback_uri_verification.missing_code": "Missing code in the callback URI", crypto_subtle_unavailable: "Crypto.subtle is unavailable in insecure contexts (non-HTTPS).", unexpected_response_error: "Unexpected response error from the server." }); var LogtoError = class extends Error { constructor(code, data) { super(logtoErrorCodes[code]); this.code = code; this.data = data; this.name = "LogtoError"; } }; var isLogtoRequestErrorJson = (data) => { if (!isArbitraryObject(data)) { return false; } return typeof data.code === "string" && typeof data.message === "string"; }; var LogtoRequestError = class extends Error { constructor(code, message2, cause) { super(message2); this.code = code; this.cause = cause; this.name = "LogtoRequestError"; } }; var OidcError = class { constructor(error, errorDescription) { this.error = error; this.errorDescription = errorDescription; this.name = "OidcError"; } }; // node_modules/@logto/js/lib/utils/callback-uri.js var parseUriParameters = (uri) => { const [, queryString = ""] = uri.split("?"); return new URLSearchParams(queryString); }; var verifyAndParseCodeFromCallbackUri = (callbackUri, redirectUri, state) => { if (!callbackUri.startsWith(redirectUri)) { throw new LogtoError("callback_uri_verification.redirect_uri_mismatched"); } const uriParameters = parseUriParameters(callbackUri); const error = conditional(uriParameters.get(QueryKey.Error)); const errorDescription = conditional(uriParameters.get(QueryKey.ErrorDescription)); if (error) { throw new LogtoError("callback_uri_verification.error_found", new OidcError(error, errorDescription)); } const stateFromCallbackUri = uriParameters.get(QueryKey.State); if (!stateFromCallbackUri) { throw new LogtoError("callback_uri_verification.missing_state"); } if (stateFromCallbackUri !== state) { throw new LogtoError("callback_uri_verification.state_mismatched"); } const code = uriParameters.get(QueryKey.Code); if (!code) { throw new LogtoError("callback_uri_verification.missing_code"); } return code; }; // node_modules/@logto/js/lib/utils/id-token.js function assertIdTokenClaims(data) { if (!isArbitraryObject(data)) { throw new TypeError("IdToken is expected to be an object"); } for (const key of ["iss", "sub", "aud"]) { if (typeof data[key] !== "string") { throw new TypeError(`At path: IdToken.${key}: expected a string`); } } for (const key of ["exp", "iat"]) { if (typeof data[key] !== "number") { throw new TypeError(`At path: IdToken.${key}: expected a number`); } } for (const key of ["at_hash", "name", "username", "picture", "email", "phone_number"]) { if (data[key] === void 0) { continue; } if (typeof data[key] !== "string" && data[key] !== null) { throw new TypeError(`At path: IdToken.${key}: expected null or a string`); } } for (const key of ["email_verified", "phone_number_verified"]) { if (data[key] === void 0) { continue; } if (typeof data[key] !== "boolean") { throw new TypeError(`At path: IdToken.${key}: expected a boolean`); } } } var decodeIdToken = (token) => { const { 1: encodedPayload } = token.split("."); if (!encodedPayload) { throw new LogtoError("id_token.invalid_token"); } const json = urlSafeBase64.decode(encodedPayload); const idTokenClaims2 = JSON.parse(json); assertIdTokenClaims(idTokenClaims2); return idTokenClaims2; }; // node_modules/@logto/js/lib/utils/access-token.js function assertAccessTokenClaims(data) { if (!isArbitraryObject(data)) { throw new TypeError("AccessToken is expected to be an object"); } for (const key of ["jti", "iss", "sub", "aud", "client_id", "scope"]) { if (data[key] === void 0) { continue; } if (typeof data[key] !== "string" && data[key] !== null) { throw new TypeError(`At path: AccessToken.${key}: expected null or a string`); } } for (const key of ["exp", "iat"]) { if (data[key] === void 0) { continue; } if (typeof data[key] !== "number" && data[key] !== null) { throw new TypeError(`At path: AccessToken.${key}: expected null or a number`); } } } var decodeAccessToken = (accessToken) => { const { 1: encodedPayload } = accessToken.split("."); if (!encodedPayload) { return {}; } const json = urlSafeBase64.decode(encodedPayload); const accessTokenClaims = JSON.parse(json); assertAccessTokenClaims(accessTokenClaims); return accessTokenClaims; }; // node_modules/jose/dist/browser/runtime/webcrypto.js var webcrypto_default = crypto; var isCryptoKey = (key) => key instanceof CryptoKey; // node_modules/jose/dist/browser/lib/buffer_utils.js var encoder = new TextEncoder(); var decoder = new TextDecoder(); var MAX_INT32 = 2 ** 32; function concat(...buffers) { const size = buffers.reduce((acc, { length }) => acc + length, 0); const buf = new Uint8Array(size); let i = 0; for (const buffer of buffers) { buf.set(buffer, i); i += buffer.length; } return buf; } // node_modules/jose/dist/browser/runtime/base64url.js var decodeBase64 = (encoded) => { const binary = atob(encoded); const bytes = new Uint8Array(binary.length); for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } return bytes; }; var decode = (input) => { let encoded = input; if (encoded instanceof Uint8Array) { encoded = decoder.decode(encoded); } encoded = encoded.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, ""); try { return decodeBase64(encoded); } catch { throw new TypeError("The input to be decoded is not correctly encoded."); } }; // node_modules/jose/dist/browser/util/errors.js var JOSEError = class extends Error { constructor(message2, options) { super(message2, options); this.code = "ERR_JOSE_GENERIC"; this.name = this.constructor.name; Error.captureStackTrace?.(this, this.constructor); } }; JOSEError.code = "ERR_JOSE_GENERIC"; var JWTClaimValidationFailed = class extends JOSEError { constructor(message2, payload, claim = "unspecified", reason = "unspecified") { super(message2, { cause: { claim, reason, payload } }); this.code = "ERR_JWT_CLAIM_VALIDATION_FAILED"; this.claim = claim; this.reason = reason; this.payload = payload; } }; JWTClaimValidationFailed.code = "ERR_JWT_CLAIM_VALIDATION_FAILED"; var JWTExpired = class extends JOSEError { constructor(message2, payload, claim = "unspecified", reason = "unspecified") { super(message2, { cause: { claim, reason, payload } }); this.code = "ERR_JWT_EXPIRED"; this.claim = claim; this.reason = reason; this.payload = payload; } }; JWTExpired.code = "ERR_JWT_EXPIRED"; var JOSEAlgNotAllowed = class extends JOSEError { constructor() { super(...arguments); this.code = "ERR_JOSE_ALG_NOT_ALLOWED"; } }; JOSEAlgNotAllowed.code = "ERR_JOSE_ALG_NOT_ALLOWED"; var JOSENotSupported = class extends JOSEError { constructor() { super(...arguments); this.code = "ERR_JOSE_NOT_SUPPORTED"; } }; JOSENotSupported.code = "ERR_JOSE_NOT_SUPPORTED"; var JWEDecryptionFailed = class extends JOSEError { constructor(message2 = "decryption operation failed", options) { super(message2, options); this.code = "ERR_JWE_DECRYPTION_FAILED"; } }; JWEDecryptionFailed.code = "ERR_JWE_DECRYPTION_FAILED"; var JWEInvalid = class extends JOSEError { constructor() { super(...arguments); this.code = "ERR_JWE_INVALID"; } }; JWEInvalid.code = "ERR_JWE_INVALID"; var JWSInvalid = class extends JOSEError { constructor() { super(...arguments); this.code = "ERR_JWS_INVALID"; } }; JWSInvalid.code = "ERR_JWS_INVALID"; var JWTInvalid = class extends JOSEError { constructor() { super(...arguments); this.code = "ERR_JWT_INVALID"; } }; JWTInvalid.code = "ERR_JWT_INVALID"; var JWKInvalid = class extends JOSEError { constructor() { super(...arguments); this.code = "ERR_JWK_INVALID"; } }; JWKInvalid.code = "ERR_JWK_INVALID"; var JWKSInvalid = class extends JOSEError { constructor() { super(...arguments); this.code = "ERR_JWKS_INVALID"; } }; JWKSInvalid.code = "ERR_JWKS_INVALID"; var JWKSNoMatchingKey = class extends JOSEError { constructor(message2 = "no applicable key found in the JSON Web Key Set", options) { super(message2, options); this.code = "ERR_JWKS_NO_MATCHING_KEY"; } }; JWKSNoMatchingKey.code = "ERR_JWKS_NO_MATCHING_KEY"; var JWKSMultipleMatchingKeys = class extends JOSEError { constructor(message2 = "multiple matching keys found in the JSON Web Key Set", options) { super(message2, options); this.code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS"; } }; JWKSMultipleMatchingKeys.code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS"; var JWKSTimeout = class extends JOSEError { constructor(message2 = "request timed out", options) { super(message2, options); this.code = "ERR_JWKS_TIMEOUT"; } }; JWKSTimeout.code = "ERR_JWKS_TIMEOUT"; var JWSSignatureVerificationFailed = class extends JOSEError { constructor(message2 = "signature verification failed", options) { super(message2, options); this.code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED"; } }; JWSSignatureVerificationFailed.code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED"; // node_modules/jose/dist/browser/lib/crypto_key.js function unusable(name, prop = "algorithm.name") { return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`); } function isAlgorithm(algorithm, name) { return algorithm.name === name; } function getHashLength(hash) { return parseInt(hash.name.slice(4), 10); } function getNamedCurve(alg) { switch (alg) { case "ES256": return "P-256"; case "ES384": return "P-384"; case "ES512": return "P-521"; default: throw new Error("unreachable"); } } function checkUsage(key, usages) { if (usages.length && !usages.some((expected) => key.usages.includes(expected))) { let msg = "CryptoKey does not support this operation, its usages must include "; if (usages.length > 2) { const last = usages.pop(); msg += `one of ${usages.join(", ")}, or ${last}.`; } else if (usages.length === 2) { msg += `one of ${usages[0]} or ${usages[1]}.`; } else { msg += `${usages[0]}.`; } throw new TypeError(msg); } } function checkSigCryptoKey(key, alg, ...usages) { switch (alg) { case "HS256": case "HS384": case "HS512": { if (!isAlgorithm(key.algorithm, "HMAC")) throw unusable("HMAC"); const expected = parseInt(alg.slice(2), 10); const actual = getHashLength(key.algorithm.hash); if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash"); break; } case "RS256": case "RS384": case "RS512": { if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5")) throw unusable("RSASSA-PKCS1-v1_5"); const expected = parseInt(alg.slice(2), 10); const actual = getHashLength(key.algorithm.hash); if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash"); break; } case "PS256": case "PS384": case "PS512": { if (!isAlgorithm(key.algorithm, "RSA-PSS")) throw unusable("RSA-PSS"); const expected = parseInt(alg.slice(2), 10); const actual = getHashLength(key.algorithm.hash); if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash"); break; } case "EdDSA": { if (key.algorithm.name !== "Ed25519" && key.algorithm.name !== "Ed448") { throw unusable("Ed25519 or Ed448"); } break; } case "Ed25519": { if (!isAlgorithm(key.algorithm, "Ed25519")) throw unusable("Ed25519"); break; } case "ES256": case "ES384": case "ES512": { if (!isAlgorithm(key.algorithm, "ECDSA")) throw unusable("ECDSA"); const expected = getNamedCurve(alg); const actual = key.algorithm.namedCurve; if (actual !== expected) throw unusable(expected, "algorithm.namedCurve"); break; } default: throw new TypeError("CryptoKey does not support this operation"); } checkUsage(key, usages); } // node_modules/jose/dist/browser/lib/invalid_key_input.js function message(msg, actual, ...types2) { types2 = types2.filter(Boolean); if (types2.length > 2) { const last = types2.pop(); msg += `one of type ${types2.join(", ")}, or ${last}.`; } else if (types2.length === 2) { msg += `one of type ${types2[0]} or ${types2[1]}.`; } else { msg += `of type ${types2[0]}.`; } if (actual == null) { msg += ` Received ${actual}`; } else if (typeof actual === "function" && actual.name) { msg += ` Received function ${actual.name}`; } else if (typeof actual === "object" && actual != null) { if (actual.constructor?.name) { msg += ` Received an instance of ${actual.constructor.name}`; } } return msg; } var invalid_key_input_default = (actual, ...types2) => { return message("Key must be ", actual, ...types2); }; function withAlg(alg, actual, ...types2) { return message(`Key for the ${alg} algorithm must be `, actual, ...types2); } // node_modules/jose/dist/browser/runtime/is_key_like.js var is_key_like_default = (key) => { if (isCryptoKey(key)) { return true; } return key?.[Symbol.toStringTag] === "KeyObject"; }; var types = ["CryptoKey"]; // node_modules/jose/dist/browser/lib/is_disjoint.js var isDisjoint = (...headers) => { const sources = headers.filter(Boolean); if (sources.length === 0 || sources.length === 1) { return true; } let acc; for (const header of sources) { const parameters = Object.keys(header); if (!acc || acc.size === 0) { acc = new Set(parameters); continue; } for (const parameter of parameters) { if (acc.has(parameter)) { return false; } acc.add(parameter); } } return true; }; var is_disjoint_default = isDisjoint; // node_modules/jose/dist/browser/lib/is_object.js function isObjectLike(value) { return typeof value === "object" && value !== null; } function isObject4(input) { if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") { return false; } if (Object.getPrototypeOf(input) === null) { return true; } let proto = input; while (Object.getPrototypeOf(proto) !== null) { proto = Object.getPrototypeOf(proto); } return Object.getPrototypeOf(input) === proto; } // node_modules/jose/dist/browser/runtime/check_key_length.js var check_key_length_default = (alg, key) => { if (alg.startsWith("RS") || alg.startsWith("PS")) { const { modulusLength } = key.algorithm; if (typeof modulusLength !== "number" || modulusLength < 2048) { throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`); } } }; // node_modules/jose/dist/browser/lib/is_jwk.js function isJWK(key) { return isObject4(key) && typeof key.kty === "string"; } function isPrivateJWK(key) { return key.kty !== "oct" && typeof key.d === "string"; } function isPublicJWK(key) { return key.kty !== "oct" && typeof key.d === "undefined"; } function isSecretJWK(key) { return isJWK(key) && key.kty === "oct" && typeof key.k === "string"; } // node_modules/jose/dist/browser/runtime/jwk_to_key.js function subtleMapping(jwk) { let algorithm; let keyUsages; switch (jwk.kty) { case "RSA": { switch (jwk.alg) { case "PS256": case "PS384": case "PS512": algorithm = { name: "RSA-PSS", hash: `SHA-${jwk.alg.slice(-3)}` }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "RS256": case "RS384": case "RS512": algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${jwk.alg.slice(-3)}` }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "RSA-OAEP": case "RSA-OAEP-256": case "RSA-OAEP-384": case "RSA-OAEP-512": algorithm = { name: "RSA-OAEP", hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}` }; keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"]; break; default: throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value'); } break; } case "EC": { switch (jwk.alg) { case "ES256": algorithm = { name: "ECDSA", namedCurve: "P-256" }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "ES384": algorithm = { name: "ECDSA", namedCurve: "P-384" }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "ES512": algorithm = { name: "ECDSA", namedCurve: "P-521" }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "ECDH-ES": case "ECDH-ES+A128KW": case "ECDH-ES+A192KW": case "ECDH-ES+A256KW": algorithm = { name: "ECDH", namedCurve: jwk.crv }; keyUsages = jwk.d ? ["deriveBits"] : []; break; default: throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value'); } break; } case "OKP": { switch (jwk.alg) { case "Ed25519": algorithm = { name: "Ed25519" }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "EdDSA": algorithm = { name: jwk.crv }; keyUsages = jwk.d ? ["sign"] : ["verify"]; break; case "ECDH-ES": case "ECDH-ES+A128KW": case "ECDH-ES+A192KW": case "ECDH-ES+A256KW": algorithm = { name: jwk.crv }; keyUsages = jwk.d ? ["deriveBits"] : []; break; default: throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value'); } break; } default: throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value'); } return { algorithm, keyUsages }; } var parse = async (jwk) => { if (!jwk.alg) { throw new TypeError('"alg" argument is required when "jwk.alg" is not present'); } const { algorithm, keyUsages } = subtleMapping(jwk); const rest = [ algorithm, jwk.ext ?? false, jwk.key_ops ?? keyUsages ]; const keyData = { ...jwk }; delete keyData.alg; delete keyData.use; return webcrypto_default.subtle.importKey("jwk", keyData, ...rest); }; var jwk_to_key_default = parse; // node_modules/jose/dist/browser/runtime/normalize_key.js var exportKeyValue = (k) => decode(k); var privCache; var pubCache; var isKeyObject = (key) => { return key?.[Symbol.toStringTag] === "KeyObject"; }; var importAndCache = async (cache2, key, jwk, alg, freeze = false) => { let cached = cache2.get(key); if (cached?.[alg]) { return cached[alg]; } const cryptoKey = await jwk_to_key_default({ ...jwk, alg }); if (freeze) Object.freeze(key); if (!cached) { cache2.set(key, { [alg]: cryptoKey }); } else { cached[alg] = cryptoKey; } return cryptoKey; }; var normalizePublicKey = (key, alg) => { if (isKeyObject(key)) { let jwk = key.export({ format: "jwk" }); delete jwk.d; delete jwk.dp; delete jwk.dq; delete jwk.p; delete jwk.q; delete jwk.qi; if (jwk.k) { return exportKeyValue(jwk.k); } pubCache || (pubCache = /* @__PURE__ */ new WeakMap()); return importAndCache(pubCache, key, jwk, alg); } if (isJWK(key)) { if (key.k) return decode(key.k); pubCache || (pubCache = /* @__PURE__ */ new WeakMap()); const cryptoKey = importAndCache(pubCache, key, key, alg, true); return cryptoKey; } return key; }; var normalizePrivateKey = (key, alg) => { if (isKeyObject(key)) { let jwk = key.export({ format: "jwk" }); if (jwk.k) { return exportKeyValue(jwk.k); } privCache || (privCache = /* @__PURE__ */ new WeakMap()); return importAndCache(privCache, key, jwk, alg); } if (isJWK(key)) { if (key.k) return decode(key.k); privCache || (privCache = /* @__PURE__ */ new WeakMap()); const cryptoKey = importAndCache(privCache, key, key, alg, true); return cryptoKey; } return key; }; var normalize_key_default = { normalizePublicKey, normalizePrivateKey }; // node_modules/jose/dist/browser/key/import.js async function importJWK(jwk, alg) { if (!isObject4(jwk)) { throw new TypeError("JWK must be an object"); } alg || (alg = jwk.alg); switch (jwk.kty) { case "oct": if (typeof jwk.k !== "string" || !jwk.k) { throw new TypeError('missing "k" (Key Value) Parameter value'); } return decode(jwk.k); case "RSA": if ("oth" in jwk && jwk.oth !== void 0) { throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported'); } case "EC": case "OKP": return jwk_to_key_default({ ...jwk, alg }); default: throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value'); } } // node_modules/jose/dist/browser/lib/check_key_type.js var tag = (key) => key?.[Symbol.toStringTag]; var jwkMatchesOp = (alg, key, usage) => { if (key.use !== void 0 && key.use !== "sig") { throw new TypeError("Invalid key for this operation, when present its use must be sig"); } if (key.key_ops !== void 0 && key.key_ops.includes?.(usage) !== true) { throw new TypeError(`Invalid key for this operation, when present its key_ops must include ${usage}`); } if (key.alg !== void 0 && key.alg !== alg) { throw new TypeError(`Invalid key for this operation, when present its alg must be ${alg}`); } return true; }; var symmetricTypeCheck = (alg, key, usage, allowJwk) => { if (key instanceof Uint8Array) return; if (allowJwk && isJWK(key)) { if (isSecretJWK(key) && jwkMatchesOp(alg, key, usage)) return; throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`); } if (!is_key_like_default(key)) { throw new TypeError(withAlg(alg, key, ...types, "Uint8Array", allowJwk ? "JSON Web Key" : null)); } if (key.type !== "secret") { throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`); } }; var asymmetricTypeCheck = (alg, key, usage, allowJwk) => { if (allowJwk && isJWK(key)) { switch (usage) { case "sign": if (isPrivateJWK(key) && jwkMatchesOp(alg, key, usage)) return; throw new TypeError(`JSON Web Key for this operation be a private JWK`); case "verify": if (isPublicJWK(key) && jwkMatchesOp(alg, key, usage)) return; throw new TypeError(`JSON Web Key for this operation be a public JWK`); } } if (!is_key_like_default(key)) { throw new TypeError(withAlg(alg, key, ...types, allowJwk ? "JSON Web Key" : null)); } if (key.type === "secret") { throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`); } if (usage === "sign" && key.type === "public") { throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`); } if (usage === "decrypt" && key.type === "public") { throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`); } if (key.algorithm && usage === "verify" && key.type === "private") { throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type "public"`); } if (key.algorithm && usage === "encrypt" && key.type === "private") { throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type "public"`); } }; function checkKeyType(allowJwk, alg, key, usage) { const symmetric = alg.startsWith("HS") || alg === "dir" || alg.startsWith("PBES2") || /^A\d{3}(?:GCM)?KW$/.test(alg); if (symmetric) { symmetricTypeCheck(alg, key, usage, allowJwk); } else { asymmetricTypeCheck(alg, key, usage, allowJwk); } } var check_key_type_default = checkKeyType.bind(void 0, false); var checkKeyTypeWithJwk = checkKeyType.bind(void 0, true); // node_modules/jose/dist/browser/lib/validate_crit.js function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) { if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) { throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); } if (!protectedHeader || protectedHeader.crit === void 0) { return /* @__PURE__ */ new Set(); } if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) { throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present'); } let recognized; if (recognizedOption !== void 0) { recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]); } else { recognized = recognizedDefault; } for (const parameter of protectedHeader.crit) { if (!recognized.has(parameter)) { throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); } if (joseHeader[parameter] === void 0) { throw new Err(`Extension Header Parameter "${parameter}" is missing`); } if (recognized.get(parameter) && protectedHeader[parameter] === void 0) { throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); } } return new Set(protectedHeader.crit); } var validate_crit_default = validateCrit; // node_modules/jose/dist/browser/lib/validate_algorithms.js var validateAlgorithms = (option, algorithms) => { if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== "string"))) { throw new TypeError(`"${option}" option must be an array of strings`); } if (!algorithms) { return void 0; } return new Set(algorithms); }; var validate_algorithms_default = validateAlgorithms; // node_modules/jose/dist/browser/runtime/subtle_dsa.js function subtleDsa(alg, algorithm) { const hash = `SHA-${alg.slice(-3)}`; switch (alg) { case "HS256": case "HS384": case "HS512": return { hash, name: "HMAC" }; case "PS256": case "PS384": case "PS512": return { hash, name: "RSA-PSS", saltLength: alg.slice(-3) >> 3 }; case "RS256": case "RS384": case "RS512": return { hash, name: "RSASSA-PKCS1-v1_5" }; case "ES256": case "ES384": case "ES512": return { hash, name: "ECDSA", namedCurve: algorithm.namedCurve }; case "Ed25519": return { name: "Ed25519" }; case "EdDSA": return { name: algorithm.name }; default: throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`); } } // node_modules/jose/dist/browser/runtime/get_sign_verify_key.js async function getCryptoKey(alg, key, usage) { if (usage === "sign") { key = await normalize_key_default.normalizePrivateKey(key, alg); } if (usage === "verify") { key = await normalize_key_default.normalizePublicKey(key, alg); } if (isCryptoKey(key)) { checkSigCryptoKey(key, alg, usage); return key; } if (key instanceof Uint8Array) { if (!alg.startsWith("HS")) { throw new TypeError(invalid_key_input_default(key, ...types)); } return webcrypto_default.subtle.importKey("raw", key, { hash: `SHA-${alg.slice(-3)}`, name: "HMAC" }, false, [usage]); } throw new TypeError(invalid_key_input_default(key, ...types, "Uint8Array", "JSON Web Key")); } // node_modules/jose/dist/browser/runtime/verify.js var verify = async (alg, key, signature, data) => { const cryptoKey = await getCryptoKey(alg, key, "verify"); check_key_length_default(alg, cryptoKey); const algorithm = subtleDsa(alg, cryptoKey.algorithm); try { return await webcrypto_default.subtle.verify(algorithm, cryptoKey, signature, data); } catch { return false; } }; var verify_default = verify; // node_modules/jose/dist/browser/jws/flattened/verify.js async function flattenedVerify(jws, key, options) { if (!isObject4(jws)) { throw new JWSInvalid("Flattened JWS must be an object"); } if (jws.protected === void 0 && jws.header === void 0) { throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members'); } if (jws.protected !== void 0 && typeof jws.protected !== "string") { throw new JWSInvalid("JWS Protected Header incorrect type"); } if (jws.payload === void 0) { throw new JWSInvalid("JWS Payload missing"); } if (typeof jws.signature !== "string") { throw new JWSInvalid("JWS Signature missing or incorrect type"); } if (jws.header !== void 0 && !isObject4(jws.header)) { throw new JWSInvalid("JWS Unprotected Header incorrect type"); } let parsedProt = {}; if (jws.protected) { try { const protectedHeader = decode(jws.protected); parsedProt = JSON.parse(decoder.decode(protectedHeader)); } catch { throw new JWSInvalid("JWS Protected Header is invalid"); } } if (!is_disjoint_default(parsedProt, jws.header)) { throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint"); } const joseHeader = { ...parsedProt, ...jws.header }; const extensions = validate_crit_default(JWSInvalid, /* @__PURE__ */ new Map([["b64", true]]), options?.crit, parsedProt, joseHeader); let b64 = true; if (extensions.has("b64")) { b64 = parsedProt.b64; if (typeof b64 !== "boolean") { throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); } } const { alg } = joseHeader; if (typeof alg !== "string" || !alg) { throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); } const algorithms = options && validate_algorithms_default("algorithms", options.algorithms); if (algorithms && !algorithms.has(alg)) { throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed'); } if (b64) { if (typeof jws.payload !== "string") { throw new JWSInvalid("JWS Payload must be a string"); } } else if (typeof jws.payload !== "string" && !(jws.payload instanceof Uint8Array)) { throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance"); } let resolvedKey = false; if (typeof key === "function") { key = await key(parsedProt, jws); resolvedKey = true; checkKeyTypeWithJwk(alg, key, "verify"); if (isJWK(key)) { key = await importJWK(key, alg); } } else { checkKeyTypeWithJwk(alg, key, "verify"); } const data = concat(encoder.encode(jws.protected ?? ""), encoder.encode("."), typeof jws.payload === "string" ? encoder.encode(jws.payload) : jws.payload); let signature; try { signature = decode(jws.signature); } catch { throw new JWSInvalid("Failed to base64url decode the signature"); } const verified = await verify_default(alg, key, signature, data); if (!verified) { throw new JWSSignatureVerificationFailed(); } let payload; if (b64) { try { payload = decode(jws.payload); } catch { throw new JWSInvalid("Failed to base64url decode the payload"); } } else if (typeof jws.payload === "string") { payload = encoder.encode(jws.payload); } else { payload = jws.payload; } const result = { payload }; if (jws.protected !== void 0) { result.protectedHeader = parsedProt; } if (jws.header !== void 0) { result.unprotectedHeader = jws.header; } if (resolvedKey) { return { ...result, key }; } return result; } // node_modules/jose/dist/browser/jws/compact/verify.js async function compactVerify(jws, key, options) { if (jws instanceof Uint8Array) { jws = decoder.decode(jws); } if (typeof jws !== "string") { throw new JWSInvalid("Compact JWS must be a string or Uint8Array"); } const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split("."); if (length !== 3) { throw new JWSInvalid("Invalid Compact JWS"); } const verified = await flattenedVerify({ payload, protected: protectedHeader, signature }, key, options); const result = { payload: verified.payload, protectedHeader: verified.protectedHeader }; if (typeof key === "function") { return { ...result, key: verified.key }; } return result; } // node_modules/jose/dist/browser/lib/epoch.js var epoch_default = (date) => Math.floor(date.getTime() / 1e3); // node_modules/jose/dist/browser/lib/secs.js var minute = 60; var hour = minute * 60; var day = hour * 24; var week = day * 7; var year = day * 365.25; var REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i; var secs_default = (str) => { const matched = REGEX.exec(str); if (!matched || matched[4] && matched[1]) { throw new TypeError("Invalid time period format"); } const value = parseFloat(matched[2]); const unit = matched[3].toLowerCase(); let numericDate; switch (unit) { case "sec": case "secs": case "second": case "seconds": case "s": numericDate = Math.round(value); break; case "minute": case "minutes": case "min": case "mins": case "m": numericDate = Math.round(value * minute); break; case "hour": case "hours": case "hr": case "hrs": case "h": numericDate = Math.round(value * hour); break; case "day": case "days": case "d": numericDate = Math.round(value * day); break; case "week": case "weeks": case "w": numericDate = Math.round(value * week); break; default: numericDate = Math.round(value * year); break; } if (matched[1] === "-" || matched[4] === "ago") { return -numericDate; } return numericDate; }; // node_modules/jose/dist/browser/lib/jwt_claims_set.js var normalizeTyp = (value) => value.toLowerCase().replace(/^application\//, ""); var checkAudiencePresence = (audPayload, audOption) => { if (typeof audPayload === "string") { return audOption.includes(audPayload); } if (Array.isArray(audPayload)) { return audOption.some(Set.prototype.has.bind(new Set(audPayload))); } return false; }; var jwt_claims_set_default = (protectedHeader, encodedPayload, options = {}) => { let payload; try { payload = JSON.parse(decoder.decode(encodedPayload)); } catch { } if (!isObject4(payload)) { throw new JWTInvalid("JWT Claims Set must be a top-level JSON object"); } const { typ } = options; if (typ && (typeof protectedHeader.typ !== "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) { throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, "typ", "check_failed"); } const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options; const presenceCheck = [...requiredClaims]; if (maxTokenAge !== void 0) presenceCheck.push("iat"); if (audience !== void 0) presenceCheck.push("aud"); if (subject !== void 0) presenceCheck.push("sub"); if (issuer !== void 0) presenceCheck.push("iss"); for (const claim of new Set(presenceCheck.reverse())) { if (!(claim in payload)) { throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing"); } } if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) { throw new JWTClaimValidationFailed('unexpected "iss" claim value', payload, "iss", "check_failed"); } if (subject && payload.sub !== subject) { throw new JWTClaimValidationFailed('unexpected "sub" claim value', payload, "sub", "check_failed"); } if (audience && !checkAudiencePresence(payload.aud, typeof audience === "string" ? [audience] : audience)) { throw new JWTClaimValidationFailed('unexpected "aud" claim value', payload, "aud", "check_failed"); } let tolerance; switch (typeof options.clockTolerance) { case "string": tolerance = secs_default(options.clockTolerance); break; case "number": tolerance = options.clockTolerance; break; case "undefined": tolerance = 0; break; default: throw new TypeError("Invalid clockTolerance option type"); } const { currentDate } = options; const now = epoch_default(currentDate || /* @__PURE__ */ new Date()); if ((payload.iat !== void 0 || maxTokenAge) && typeof payload.iat !== "number") { throw new JWTClaimValidationFailed('"iat" claim must be a number', payload, "iat", "invalid"); } if (payload.nbf !== void 0) { if (typeof payload.nbf !== "number") { throw new JWTClaimValidationFailed('"nbf" claim must be a number', payload, "nbf", "invalid"); } if (payload.nbf > now + tolerance) { throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, "nbf", "check_failed"); } } if (payload.exp !== void 0) { if (typeof payload.exp !== "number") { throw new JWTClaimValidationFailed('"exp" claim must be a number', payload, "exp", "invalid"); } if (payload.exp <= now - tolerance) { throw new JWTExpired('"exp" claim timestamp check failed', payload, "exp", "check_failed"); } } if (maxTokenAge) { const age = now - payload.iat; const max = typeof maxTokenAge === "number" ? maxTokenAge : secs_default(maxTokenAge); if (age - tolerance > max) { throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, "iat", "check_failed"); } if (age < 0 - tolerance) { throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", "check_failed"); } } return payload; }; // node_modules/jose/dist/browser/jwt/verify.js async function jwtVerify(jwt, key, options) { const verified = await compactVerify(jwt, key, options); if (verified.protectedHeader.crit?.includes("b64") && verified.protectedHeader.b64 === false) { throw new JWTInvalid("JWTs MUST NOT use unencoded payload"); } const payload = jwt_claims_set_default(verified.protectedHeader, verified.payload, options); const result = { payload, protectedHeader: verified.protectedHeader }; if (typeof key === "function") { return { ...result, key: verified.key }; } return result; } // node_modules/jose/dist/browser/jwks/local.js function getKtyFromAlg(alg) { switch (typeof alg === "string" && alg.slice(0, 2)) { case "RS": case "PS": return "RSA"; case "ES": return "EC"; case "Ed": return "OKP"; default: throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set'); } } function isJWKSLike(jwks) { return jwks && typeof jwks === "object" && Array.isArray(jwks.keys) && jwks.keys.every(isJWKLike); } function isJWKLike(key) { return isObject4(key); } function clone(obj) { if (typeof structuredClone === "function") { return structuredClone(obj); } return JSON.parse(JSON.stringify(obj)); } var LocalJWKSet = class { constructor(jwks) { this._cached = /* @__PURE__ */ new WeakMap(); if (!isJWKSLike(jwks)) { throw new JWKSInvalid("JSON Web Key Set malformed"); } this._jwks = clone(jwks); } async getKey(protectedHeader, token) { const { alg, kid } = { ...protectedHeader, ...token?.header }; const kty = getKtyFromAlg(alg); const candidates = this._jwks.keys.filter((jwk2) => { let candidate = kty === jwk2.kty; if (candidate && typeof kid === "string") { candidate = kid === jwk2.kid; } if (candidate && typeof jwk2.alg === "string") { candidate = alg === jwk2.alg; } if (candidate && typeof jwk2.use === "string") { candidate = jwk2.use === "sig"; } if (candidate && Array.isArray(jwk2.key_ops)) { candidate = jwk2.key_ops.includes("verify"); } if (candidate) { switch (alg) { case "ES256": candidate = jwk2.crv === "P-256"; break; case "ES256K": candidate = jwk2.crv === "secp256k1"; break; case "ES384": candidate = jwk2.crv === "P-384"; break; case "ES512": candidate = jwk2.crv === "P-521"; break; case "Ed25519": candidate = jwk2.crv === "Ed25519"; break; case "EdDSA": candidate = jwk2.crv === "Ed25519" || jwk2.crv === "Ed448"; break; } } return candidate; }); const { 0: jwk, length } = candidates; if (length === 0) { throw new JWKSNoMatchingKey(); } if (length !== 1) { const error = new JWKSMultipleMatchingKeys(); const { _cached } = this; error[Symbol.asyncIterator] = async function* () { for (const jwk2 of candidates) { try { yield await importWithAlgCache(_cached, jwk2, alg); } catch { } } }; throw error; } return importWithAlgCache(this._cached, jwk, alg); } }; async function importWithAlgCache(cache2, jwk, alg) { const cached = cache2.get(jwk) || cache2.set(jwk, {}).get(jwk); if (cached[alg] === void 0) { const key = await importJWK({ ...jwk, ext: true }, alg); if (key instanceof Uint8Array || key.type !== "public") { throw new JWKSInvalid("JSON Web Key Set members must be public keys"); } cached[alg] = key; } return cached[alg]; } function createLocalJWKSet(jwks) { const set = new LocalJWKSet(jwks); const localJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token); Object.defineProperties(localJWKSet, { jwks: { value: () => clone(set._jwks), enumerable: true, configurable: false, writable: false } }); return localJWKSet; } // node_modules/jose/dist/browser/runtime/fetch_jwks.js var fetchJwks = async (url, timeout, options) => { let controller; let id; let timedOut = false; if (typeof AbortController === "function") { controller = new AbortController(); id = setTimeout(() => { timedOut = true; controller.abort(); }, timeout); } const response = await fetch(url.href, { signal: controller ? controller.signal : void 0, redirect: "manual", headers: options.headers }).catch((err) => { if (timedOut) throw new JWKSTimeout(); throw err; }); if (id !== void 0) clearTimeout(id); if (response.status !== 200) { throw new JOSEError("Expected 200 OK from the JSON Web Key Set HTTP response"); } try { return await response.json(); } catch { throw new JOSEError("Failed to parse the JSON Web Key Set HTTP response as JSON"); } }; var fetch_jwks_default = fetchJwks; // node_modules/jose/dist/browser/jwks/remote.js function isCloudflareWorkers() { return typeof WebSocketPair !== "undefined" || typeof navigator !== "undefined" && navigator.userAgent === "Cloudflare-Workers" || typeof EdgeRuntime !== "undefined" && EdgeRuntime === "vercel"; } var USER_AGENT; if (typeof navigator === "undefined" || !navigator.userAgent?.startsWith?.("Mozilla/5.0 ")) { const NAME = "jose"; const VERSION = "v5.10.0"; USER_AGENT = `${NAME}/${VERSION}`; } var jwksCache = /* @__PURE__ */ Symbol(); function isFreshJwksCache(input, cacheMaxAge) { if (typeof input !== "object" || input === null) { return false; } if (!("uat" in input) || typeof input.uat !== "number" || Date.now() - input.uat >= cacheMaxAge) { return false; } if (!("jwks" in input) || !isObject4(input.jwks) || !Array.isArray(input.jwks.keys) || !Array.prototype.every.call(input.jwks.keys, isObject4)) { return false; } return true; } var RemoteJWKSet = class { constructor(url, options) { if (!(url instanceof URL)) { throw new TypeError("url must be an instance of URL"); } this._url = new URL(url.href); this._options = { agent: options?.agent, headers: options?.headers }; this._timeoutDuration = typeof options?.timeoutDuration === "number" ? options?.timeoutDuration : 5e3; this._cooldownDuration = typeof options?.cooldownDuration === "number" ? options?.cooldownDuration : 3e4; this._cacheMaxAge = typeof options?.cacheMaxAge === "number" ? options?.cacheMaxAge : 6e5; if (options?.[jwksCache] !== void 0) { this._cache = options?.[jwksCache]; if (isFreshJwksCache(options?.[jwksCache], this._cacheMaxAge)) { this._jwksTimestamp = this._cache.uat; this._local = createLocalJWKSet(this._cache.jwks); } } } coolingDown() { return typeof this._jwksTimestamp === "number" ? Date.now() < this._jwksTimestamp + this._cooldownDuration : false; } fresh() { return typeof this._jwksTimestamp === "number" ? Date.now() < this._jwksTimestamp + this._cacheMaxAge : false; } async getKey(protectedHeader, token) { if (!this._local || !this.fresh()) { await this.reload(); } try { return await this._local(protectedHeader, token); } catch (err) { if (err instanceof JWKSNoMatchingKey) { if (this.coolingDown() === false) { await this.reload(); return this._local(protectedHeader, token); } } throw err; } } async reload() { if (this._pendingFetch && isCloudflareWorkers()) { this._pendingFetch = void 0; } const headers = new Headers(this._options.headers); if (USER_AGENT && !headers.has("User-Agent")) { headers.set("User-Agent", USER_AGENT); this._options.headers = Object.fromEntries(headers.entries()); } this._pendingFetch || (this._pendingFetch = fetch_jwks_default(this._url, this._timeoutDuration, this._options).then((json) => { this._local = createLocalJWKSet(json); if (this._cache) { this._cache.uat = Date.now(); this._cache.jwks = json; } this._jwksTimestamp = Date.now(); this._pendingFetch = void 0; }).catch((err) => { this._pendingFetch = void 0; throw err; })); await this._pendingFetch; } }; function createRemoteJWKSet(url, options) { const set = new RemoteJWKSet(url, options); const remoteJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token); Object.defineProperties(remoteJWKSet, { coolingDown: { get: () => set.coolingDown(), enumerable: true, configurable: false }, fresh: { get: () => set.fresh(), enumerable: true, configurable: false }, reload: { value: () => set.reload(), enumerable: true, configurable: false, writable: false }, reloading: { get: () => !!set._pendingFetch, enumerable: true, configurable: false }, jwks: { value: () => set._local?.jwks(), enumerable: true, configurable: false, writable: false } }); return remoteJWKSet; } // node_modules/@logto/client/lib/adapter/defaults.js var defaultClockTolerance = 300; var verifyIdToken = async (idToken, clientId, issuer, jwks, clockTolerance = defaultClockTolerance) => { const result = await jwtVerify(idToken, jwks, { audience: clientId, issuer, clockTolerance }); if (Math.abs((result.payload.iat ?? 0) - Date.now() / 1e3) > clockTolerance) { throw new LogtoError("id_token.invalid_iat"); } }; var DefaultJwtVerifier = class { constructor(client, clockTolerance = defaultClockTolerance) { this.client = client; this.clockTolerance = clockTolerance; } async verifyIdToken(idToken) { const { appId } = this.client.logtoConfig; const { issuer, jwksUri } = await this.client.getOidcConfig(); this.getJwtVerifyGetKey ||= createRemoteJWKSet(new URL(jwksUri)); await verifyIdToken(idToken, appId, issuer, this.getJwtVerifyGetKey, this.clockTolerance); } }; // node_modules/@logto/client/lib/adapter/types.js var PersistKey; (function(PersistKey2) { PersistKey2["IdToken"] = "idToken"; PersistKey2["RefreshToken"] = "refreshToken"; PersistKey2["AccessToken"] = "accessToken"; PersistKey2["SignInSession"] = "signInSession"; })(PersistKey || (PersistKey = {})); var CacheKey; (function(CacheKey2) { CacheKey2["OpenidConfig"] = "openidConfiguration"; CacheKey2["Jwks"] = "jwks"; })(CacheKey || (CacheKey = {})); // node_modules/@logto/client/lib/adapter/index.js var ClientAdapterInstance = class { /* END OF IMPLEMENTATION */ constructor(adapter) { Object.assign(this, adapter); } async setStorageItem(key, value) { if (!value) { await this.storage.removeItem(key); return; } await this.storage.setItem(key, value); } /** * Try to get the string value from the cache and parse as JSON. * Return the parsed value if it is an object, return `undefined` otherwise. * * @param key The cache key to get value from. */ async getCachedObject(key) { const cached = await trySafe(async () => { const data = await this.unstable_cache?.getItem(key); return conditional(data && JSON.parse(data)); }); if (cached && typeof cached === "object") { return cached; } } /** * Try to get the value from the cache first, if it doesn't exist in cache, * run the getter function and store the result into cache. * * @param key The cache key to get value from. */ async getWithCache(key, getter) { const cached = await this.getCachedObject(key); if (cached) { return cached; } const result = await getter(); await this.unstable_cache?.setItem(key, JSON.stringify(result)); return result; } }; // node_modules/@logto/client/lib/errors.js var logtoClientErrorCodes = Object.freeze({ "sign_in_session.invalid": "Invalid sign-in session.", "sign_in_session.not_found": "Sign-in session not found.", not_authenticated: "Not authenticated.", fetch_user_info_failed: "Unable to fetch user info. The access token may be invalid.", user_cancelled: "The user cancelled the action.", missing_scope_organizations: `The \`${UserScope.Organizations}\` scope is required` }); var LogtoClientError = class extends Error { constructor(code, data) { super(logtoClientErrorCodes[code]); this.name = "LogtoClientError"; this.code = code; this.data = data; } }; // node_modules/@logto/client/lib/types/index.js var normalizeLogtoConfig = (config) => { const { prompt = Prompt.Consent, scopes = [], resources, ...rest } = config; const includeReservedScopes = config.includeReservedScopes ?? true; return { ...rest, prompt, scopes: includeReservedScopes ? withReservedScopes(scopes).split(" ") : scopes, resources: scopes.includes(UserScope.Organizations) ? deduplicate([...resources ?? [], ReservedResource.Organization]) : resources, includeReservedScopes }; }; var isLogtoSignInSessionItem = (data) => { if (!isArbitraryObject(data)) { return false; } return ["redirectUri", "codeVerifier", "state"].every((key) => typeof data[key] === "string"); }; var isLogtoAccessTokenMap = (data) => { if (!isArbitraryObject(data)) { return false; } return Object.values(data).every((value) => { if (!isArbitraryObject(value)) { return false; } return typeof value.token === "string" && typeof value.scope === "string" && typeof value.expiresAt === "number"; }); }; // node_modules/@logto/client/lib/utils/index.js var buildAccessTokenKey = (resource = "", organizationId, scopes = []) => `${scopes.slice().sort().join(" ")}@${resource}${conditionalString(organizationId && `#${organizationId}`)}`; var getDiscoveryEndpoint = (endpoint) => appendPath(new URL(endpoint), discoveryPath).toString(); // node_modules/@logto/client/lib/utils/memoize.js function memoize(run) { const promiseCache = /* @__PURE__ */ new Map(); const memoized = async function(...args) { const promiseKey = JSON.stringify(args); const cachedPromise = promiseCache.get(promiseKey); if (cachedPromise) { return cachedPromise; } const promise = (async () => { try { return await run.apply(this, args); } finally { promiseCache.delete(promiseKey); } })(); promiseCache.set(promiseKey, promise); return promise; }; return memoized; } // node_modules/@logto/client/lib/utils/once.js function once2(function_) { let called = false; let result; return function(...args) { if (!called) { called = true; result = function_.apply(this, args); } return result; }; } // node_modules/@logto/client/lib/client.js var StandardLogtoClient = class { get jwtVerifier() { return this.jwtVerifierInstance; } constructor(logtoConfig, adapter, buildJwtVerifier) { this.getOidcConfig = once2(this.#getOidcConfig); this.getAccessToken = memoize(this.#getAccessToken); this.getOrganizationToken = memoize(this.#getOrganizationToken); this.clearAccessToken = memoize(this.#clearAccessToken); this.clearAllTokens = memoize(this.#clearAllTokens); this.handleSignInCallback = memoize(this.#handleSignInCallback); this.accessTokenMap = /* @__PURE__ */ new Map(); this.logtoConfig = normalizeLogtoConfig(logtoConfig); this.adapter = new ClientAdapterInstance(adapter); this.jwtVerifierInstance = buildJwtVerifier(this); void this.loadAccessTokenMap(); } /** * Set the JWT verifier for the client. * @param buildJwtVerifier The JWT verifier instance or a function that returns the JWT verifier instance. */ setJwtVerifier(buildJwtVerifier) { this.jwtVerifierInstance = typeof buildJwtVerifier === "function" ? buildJwtVerifier(this) : buildJwtVerifier; } /** * Check if the user is authenticated by checking if the ID token exists. */ async isAuthenticated() { return Boolean(await this.getIdToken()); } /** * Get the Refresh Token from the storage. */ async getRefreshToken() { return this.adapter.storage.getItem("refreshToken"); } /** * Get the ID Token from the storage. If you want to get the ID Token claims, * use {@link getIdTokenClaims} instead. */ async getIdToken() { return this.adapter.storage.getItem("idToken"); } /** * Get the ID Token claims. */ async getIdTokenClaims() { const idToken = await this.getIdToken(); if (!idToken) { throw new LogtoClientError("not_authenticated", "ID token not found"); } return decodeIdToken(idToken); } /** * Get the access token claims for the specified resource. * * @param resource The resource that the access token is granted for. If not * specified, the access token will be used for OpenID Connect or the default * resource, as specified in the Logto Console. */ async getAccessTokenClaims(resource) { const accessToken = await this.getAccessToken(resource); return decodeAccessToken(accessToken); } /** * Get the organization token claims for the specified organization. * * @param organizationId The ID of the organization that the access token is granted for. */ async getOrganizationTokenClaims(organizationId) { const accessToken = await this.getOrganizationToken(organizationId); return decodeAccessToken(accessToken); } /** * Get the user information from the Userinfo Endpoint. * * Note the Userinfo Endpoint will return more claims than the ID Token. See * {@link https://docs.logto.io/docs/recipes/integrate-logto/vanilla-js/#fetch-user-information | Fetch user information} * for more information. * * @returns The user information. * @throws LogtoClientError if the user is not authenticated. */ async fetchUserInfo() { const { userinfoEndpoint } = await this.getOidcConfig(); const accessToken = await this.getAccessToken(); if (!accessToken) { throw new LogtoClientError("fetch_user_info_failed"); } return fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester); } async signIn(options, mode, hint) { const { redirectUri: redirectUriUrl, postRedirectUri: postRedirectUriUrl, firstScreen, identifiers, interactionMode, loginHint, directSignIn, extraParams, prompt, clearTokens } = typeof options === "string" || options instanceof URL ? { redirectUri: options, postRedirectUri: void 0, firstScreen: void 0, identifiers: void 0, interactionMode: mode, loginHint: hint, directSignIn: void 0, extraParams: void 0, prompt: void 0, clearTokens: true } : options; const redirectUri = redirectUriUrl.toString(); const postRedirectUri = postRedirectUriUrl?.toString(); const { appId: clientId, prompt: promptViaConfig, resources, scopes, includeReservedScopes } = this.logtoConfig; const { authorizationEndpoint } = await this.getOidcConfig(); const [codeVerifier, state] = await Promise.all([ this.adapter.generateCodeVerifier(), this.adapter.generateState() ]); const codeChallenge = await this.adapter.generateCodeChallenge(codeVerifier); const signInUri = generateSignInUri({ authorizationEndpoint, clientId, redirectUri: redirectUri.toString(), codeChallenge, state, scopes, resources, prompt: prompt ?? promptViaConfig, firstScreen, identifiers, interactionMode, loginHint, directSignIn, extraParams, includeReservedScopes }); await Promise.all([ this.setSignInSession({ redirectUri, postRedirectUri, codeVerifier, state }), clearTokens === false ? void 0 : this.clearAllTokens() ]); await this.adapter.navigate(signInUri, { redirectUri, for: "sign-in" }); } /** * Check if the user is redirected from the sign-in page by checking if the * current URL matches the redirect URI in the sign-in session. * * If there's no sign-in session, it will return `false`. * * @param url The current URL. */ async isSignInRedirected(url) { const signInSession = await this.getSignInSession(); if (!signInSession) { return false; } const { redirectUri } = signInSession; const { origin, pathname } = new URL(url); return `${origin}${pathname}` === redirectUri; } /** * Start the sign-out flow with the specified redirect URI. The URI must be * registered in the Logto Console. * * It will also revoke all the tokens and clean up the storage. * * The user will be redirected that URI after the sign-out flow is completed. * If the `postLogoutRedirectUri` is not specified, the user will be redirected * to a default page. */ async signOut(postLogoutRedirectUri) { const { appId: clientId } = this.logtoConfig; const { endSessionEndpoint, revocationEndpoint } = await this.getOidcConfig(); const refreshToken = await this.getRefreshToken(); if (refreshToken) { try { await revoke(revocationEndpoint, clientId, refreshToken, this.adapter.requester); } catch { } } const url = generateSignOutUri({ endSessionEndpoint, postLogoutRedirectUri, clientId }); await this.clearAllTokens(); await this.adapter.navigate(url, { redirectUri: postLogoutRedirectUri, for: "sign-out" }); } async getSignInSession() { const jsonItem = await this.adapter.storage.getItem("signInSession"); if (!jsonItem) { return null; } const item = JSON.parse(jsonItem); if (!isLogtoSignInSessionItem(item)) { throw new LogtoClientError("sign_in_session.invalid"); } return item; } async setSignInSession(value) { return this.adapter.setStorageItem(PersistKey.SignInSession, value && JSON.stringify(value)); } async setIdToken(value) { return this.adapter.setStorageItem(PersistKey.IdToken, value); } async setRefreshToken(value) { return this.adapter.setStorageItem(PersistKey.RefreshToken, value); } async getAccessTokenByRefreshToken(resource, organizationId) { const currentRefreshToken = await this.getRefreshToken(); if (!currentRefreshToken) { throw new LogtoClientError("not_authenticated", "Refresh token not found"); } const accessTokenKey = buildAccessTokenKey(resource, organizationId); const { appId: clientId } = this.logtoConfig; const { tokenEndpoint } = await this.getOidcConfig(); const requestedAt = Math.round(Date.now() / 1e3); const { accessToken, refreshToken, idToken, scope, expiresIn } = await fetchTokenByRefreshToken({ clientId, tokenEndpoint, refreshToken: currentRefreshToken, resource, organizationId }, this.adapter.requester); this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, /** The `expiresAt` variable provides an approximate estimation of the actual `exp` property * in the token claims. It is utilized by the client to determine if the cached access token * has expired and when a new access token should be requested. */ expiresAt: requestedAt + expiresIn }); await this.saveAccessTokenMap(); if (refreshToken) { await this.setRefreshToken(refreshToken); } if (idToken) { await this.jwtVerifier.verifyIdToken(idToken); await this.setIdToken(idToken); } return accessToken; } async saveAccessTokenMap() { const data = {}; for (const [key, accessToken] of this.accessTokenMap.entries()) { data[key] = accessToken; } await this.adapter.storage.setItem("accessToken", JSON.stringify(data)); } async loadAccessTokenMap() { const raw = await this.adapter.storage.getItem("accessToken"); if (!raw) { return; } try { const json = JSON.parse(raw); if (!isLogtoAccessTokenMap(json)) { return; } this.accessTokenMap.clear(); for (const [key, accessToken] of Object.entries(json)) { this.accessTokenMap.set(key, accessToken); } } catch (error) { console.warn(error); } } async #getOidcConfig() { return this.adapter.getWithCache(CacheKey.OpenidConfig, async () => { return fetchOidcConfig(getDiscoveryEndpoint(this.logtoConfig.endpoint), this.adapter.requester); }); } async #getAccessToken(resource, organizationId) { if (!await this.isAuthenticated()) { throw new LogtoClientError("not_authenticated"); } const accessTokenKey = buildAccessTokenKey(resource, organizationId); const accessToken = this.accessTokenMap.get(accessTokenKey); if (accessToken && accessToken.expiresAt > Date.now() / 1e3) { return accessToken.token; } if (accessToken) { this.accessTokenMap.delete(accessTokenKey); } return this.getAccessTokenByRefreshToken(resource, organizationId); } async #getOrganizationToken(organizationId) { if (!this.logtoConfig.scopes?.includes(UserScope.Organizations)) { throw new LogtoClientError("missing_scope_organizations"); } return this.getAccessToken(void 0, organizationId); } async #clearAccessToken() { this.accessTokenMap.clear(); await this.adapter.storage.removeItem("accessToken"); } async #clearAllTokens() { await Promise.all([this.setRefreshToken(null), this.setIdToken(null), this.clearAccessToken()]); } async #handleSignInCallback(callbackUri) { const signInSession = await this.getSignInSession(); if (!signInSession) { throw new LogtoClientError("sign_in_session.not_found"); } const { redirectUri, postRedirectUri, state, codeVerifier } = signInSession; const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state); const accessTokenKey = buildAccessTokenKey(); const { appId: clientId } = this.logtoConfig; const { tokenEndpoint } = await this.getOidcConfig(); const requestedAt = Math.round(Date.now() / 1e3); const { idToken, refreshToken, accessToken, scope, expiresIn } = await fetchTokenByAuthorizationCode({ clientId, tokenEndpoint, redirectUri, codeVerifier, code }, this.adapter.requester); await this.jwtVerifier.verifyIdToken(idToken); await this.setRefreshToken(refreshToken ?? null); await this.setIdToken(idToken); this.accessTokenMap.set(accessTokenKey, { token: accessToken, scope, /** The `expiresAt` variable provides an approximate estimation of the actual `exp` property * in the token claims. It is utilized by the client to determine if the cached access token * has expired and when a new access token should be requested. */ expiresAt: requestedAt + expiresIn }); await this.saveAccessTokenMap(); await this.setSignInSession(null); if (postRedirectUri) { await this.adapter.navigate(postRedirectUri, { for: "post-sign-in" }); } } }; // node_modules/@logto/client/lib/utils/requester.js var createRequester = (fetchFunction) => { return async (...args) => { const response = await fetchFunction(...args); if (!response.ok) { const cloned = response.clone(); const responseJson = await response.json(); console.error(`Logto requester error: [status=${response.status}]`, responseJson); if (!isLogtoRequestErrorJson(responseJson)) { throw new LogtoError("unexpected_response_error", responseJson); } const { code, message: message2 } = responseJson; throw new LogtoRequestError(code, message2, cloned); } return response.json(); }; }; // node_modules/@logto/client/lib/index.js var LogtoClient = class extends StandardLogtoClient { constructor(logtoConfig, adapter, buildJwtVerifier) { super(logtoConfig, adapter, buildJwtVerifier ?? ((client) => new DefaultJwtVerifier(client))); } }; // node_modules/js-base64/base64.mjs var _hasBuffer = typeof Buffer === "function"; var _TD = typeof TextDecoder === "function" ? new TextDecoder() : void 0; var _TE = typeof TextEncoder === "function" ? new TextEncoder() : void 0; var b64ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var b64chs = Array.prototype.slice.call(b64ch); var b64tab = ((a) => { let tab = {}; a.forEach((c, i) => tab[c] = i); return tab; })(b64chs); var _fromCC = String.fromCharCode.bind(String); var _U8Afrom = typeof Uint8Array.from === "function" ? Uint8Array.from.bind(Uint8Array) : (it) => new Uint8Array(Array.prototype.slice.call(it, 0)); var _mkUriSafe = (src) => src.replace(/=/g, "").replace(/[+\/]/g, (m0) => m0 == "+" ? "-" : "_"); var btoaPolyfill = (bin) => { let u32, c0, c1, c2, asc = ""; const pad = bin.length % 3; for (let i = 0; i < bin.length; ) { if ((c0 = bin.charCodeAt(i++)) > 255 || (c1 = bin.charCodeAt(i++)) > 255 || (c2 = bin.charCodeAt(i++)) > 255) throw new TypeError("invalid character found"); u32 = c0 << 16 | c1 << 8 | c2; asc += b64chs[u32 >> 18 & 63] + b64chs[u32 >> 12 & 63] + b64chs[u32 >> 6 & 63] + b64chs[u32 & 63]; } return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc; }; var _btoa = typeof btoa === "function" ? (bin) => btoa(bin) : _hasBuffer ? (bin) => Buffer.from(bin, "binary").toString("base64") : btoaPolyfill; var _fromUint8Array = _hasBuffer ? (u8a) => Buffer.from(u8a).toString("base64") : (u8a) => { const maxargs = 4096; let strs = []; for (let i = 0, l = u8a.length; i < l; i += maxargs) { strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs))); } return _btoa(strs.join("")); }; var fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a); // node_modules/@logto/browser/lib/utils/generators.js var generateRandomString = (length = 64) => fromUint8Array(crypto.getRandomValues(new Uint8Array(length)), true); var generateState = () => generateRandomString(); var generateCodeVerifier = () => generateRandomString(); var generateCodeChallenge = async (codeVerifier) => { if (crypto.subtle === void 0) { throw new LogtoError("crypto_subtle_unavailable"); } const encodedCodeVerifier = new TextEncoder().encode(codeVerifier); const codeChallenge = new Uint8Array(await crypto.subtle.digest("SHA-256", encodedCodeVerifier)); return fromUint8Array(codeChallenge, true); }; // node_modules/@logto/chrome-extension/lib/storage.js var keyPrefix = `logto`; var ChromeExtensionStorage = class { constructor(appId) { this.appId = appId; } getKey(item) { if (item === void 0) { return `${keyPrefix}:${this.appId}`; } return `${keyPrefix}:${this.appId}:${item}`; } // eslint-disable-next-line @typescript-eslint/ban-types async getItem(key) { const storageKey = this.getKey(key); const object = await chrome.storage.local.get(storageKey); return object[storageKey] ? String(object[storageKey]) : null; } async setItem(key, value) { await chrome.storage.local.set({ [this.getKey(key)]: value }); } async removeItem(key) { await chrome.storage.local.remove(this.getKey(key)); } }; // node_modules/@logto/chrome-extension/lib/index.js var LogtoClient2 = class extends LogtoClient { /** * @param config The configuration object for the client. */ constructor(config) { const requester = createRequester(fetch); const navigate = async (url, params) => { switch (params.for) { case "sign-in": { const responseUrl = await chrome.identity.launchWebAuthFlow({ url, interactive: true }); if (!responseUrl) { throw new LogtoClientError("user_cancelled"); } await this.handleSignInCallback(responseUrl); break; } case "sign-out": { await chrome.identity.launchWebAuthFlow({ url, interactive: false, abortOnLoadForNonInteractive: false, timeoutMsForNonInteractive: 1e4 }); break; } default: { throw new Error(`Unsupported navigation for ${params.for}`); } } }; super(config, { requester, navigate, storage: new ChromeExtensionStorage(config.appId), generateCodeChallenge, generateCodeVerifier, generateState }); } }; // src/background/auth/client.ts function createLogtoAuthClient() { const config = readAuthConfig(); const client = new LogtoClient2({ appId: config.appId, endpoint: config.logtoEndpoint, resources: [config.apiResource], scopes: config.scopes }); return { getAccessToken(resource) { return client.getAccessToken(resource); }, getIdTokenClaims() { return client.getIdTokenClaims(); }, isAuthenticated() { return client.isAuthenticated(); }, signIn() { return client.signIn(readChromeIdentity().getRedirectURL("/callback")); }, signOut() { return client.signOut(readChromeIdentity().getRedirectURL()); } }; } function readChromeIdentity() { const identity = globalThis.chrome?.identity; if (typeof identity?.getRedirectURL !== "function") { throw new Error("chrome.identity.getRedirectURL is unavailable"); } return { getRedirectURL: identity.getRedirectURL.bind(identity) }; } // src/shared/auth-messages.ts var authRequestTypes = /* @__PURE__ */ new Set([ "auth:get-state", "auth:sign-in", "auth:sign-out", "auth:get-access-token" ]); function isAuthRequestMessage(value) { if (!value || typeof value !== "object") { return false; } const candidate = value; return typeof candidate.type === "string" && authRequestTypes.has(candidate.type); } function isAuthResponseMessage(value) { if (!value || typeof value !== "object") { return false; } const candidate = value; if (candidate.ok === false) { return candidate.type === "auth:error" && typeof candidate.error === "string"; } if (candidate.ok !== true || typeof candidate.type !== "string") { return false; } if (candidate.type === "auth:ack") { return true; } if (candidate.type === "auth:token") { return Boolean( candidate.value && typeof candidate.value === "object" && typeof candidate.value.accessToken === "string" ); } if (candidate.type === "auth:state") { return Boolean( candidate.value && typeof candidate.value === "object" && typeof candidate.value.isAuthenticated === "boolean" ); } return false; } // src/shared/batch-submit-config.ts var DEFAULT_BATCH_SUBMIT_BASE_URL = "http://192.168.31.21:8083"; // src/shared/batch-submit-client.ts function createBatchSubmitClient(options) { const baseUrl = options.baseUrl ?? DEFAULT_BATCH_SUBMIT_BASE_URL; const fetchImpl = options.fetchImpl ?? fetch; const getAccessToken = options.getAccessToken ?? (() => readAccessToken(options.sendMessage)); return { async submitBatch(payload) { const token = await getAccessToken(); const response = await fetchImpl( buildBatchSubmitUrl(baseUrl), { body: JSON.stringify(payload), headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" }, method: "POST" } ); if (response.status === 401 || response.status === 403) { throw new Error("batch submit unauthorized"); } if (!response.ok) { throw new Error(`batch submit failed: ${response.status}`); } return readBatchSubmitResponse(await response.json()); } }; } function buildBatchSubmitUrl(baseUrl) { return new URL("/api/v1/batch-status/batches", baseUrl).toString(); } async function readAccessToken(sendMessage) { const response = await sendMessage({ type: "auth:get-access-token" }); if (!isAuthResponseMessage(response) || !response.ok || response.type !== "auth:token" || !response.value.accessToken.trim()) { throw new Error("batch submit token unavailable"); } return response.value.accessToken; } function readBatchSubmitResponse(payload) { if (!isRecord(payload)) { throw new Error("batch submit response is invalid"); } if (payload.success !== true) { const message2 = typeof payload.msg === "string" && payload.msg.trim() ? payload.msg : "batch submit failed"; throw new Error(message2); } return "data" in payload ? payload.data : payload; } function isRecord(value) { return typeof value === "object" && value !== null; } // src/shared/backend-metrics-config.ts var DEFAULT_BACKEND_METRICS_BASE_URL = "https://talent-search.intelligrow.cn"; // src/shared/backend-metrics-client.ts function createBackendMetricsClient(options) { const baseUrl = options.baseUrl ?? DEFAULT_BACKEND_METRICS_BASE_URL; const fetchImpl = options.fetchImpl ?? defaultFetch; return { async searchByStarIds(starIds) { const response = await fetchImpl(buildBackendMetricsSearchUrl(baseUrl), { body: JSON.stringify(buildBackendMetricsSearchRequestBody(starIds)), headers: { Authorization: `Bearer ${await options.getAccessToken()}`, "Content-Type": "application/json" }, method: "POST" }); if (!response.ok) { throw new Error("backend metrics request failed"); } return mapBackendMetricsSearchResponse(await response.json()); } }; } function buildBackendMetricsSearchUrl(baseUrl) { return new URL("/api/v1/history/talents/search", baseUrl).toString(); } function buildBackendMetricsSearchRequestBody(starIds) { return { page: 1, size: Math.max(20, starIds.length), type: "star_id", values: starIds }; } function mapBackendMetricsSearchResponse(payload) { const rows = readResponseRows(payload); if (!rows) { throw new Error("backend metrics response is invalid"); } return rows.flatMap((row) => { if (!isRecord2(row) || typeof row.star_id !== "string") { return []; } return [ { a3IncreaseCount: formatDecimalValue( readAverageA3IncreaseCount(row) ), afterViewSearchCount: formatDecimalValue(row.avg_after_view_search_cnt), afterViewSearchRate: formatRateValue(row.avg_after_view_search_rate), cpSearch: formatDecimalValue(row.cp_search), cpa3: formatDecimalValue(readCpa3Value(row)), newA3Rate: formatRateValue(row.avg_new_a3_rate), starId: row.star_id } ]; }); } function readAverageA3IncreaseCount(row) { const directAverage = readFiniteNumber(row.avg_a3_increase_cnt); if (directAverage !== null) { return directAverage; } const totalNewA3 = readTotalNewA3Value(row); const videoCount = readFiniteNumber(row.video_count) ?? readNestedVideoCount(row.videos); if (totalNewA3 === null || videoCount === null || videoCount <= 0) { return null; } return totalNewA3 / videoCount; } function readCpa3Value(row) { const directCpa3 = readFiniteNumber(row.cpa3); if (directCpa3 !== null) { return directCpa3; } const totalCost = readFiniteNumber(row.total_estimated_video_cost); const totalNewA3 = readTotalNewA3Value(row); if (totalCost === null || totalNewA3 === null || totalNewA3 <= 0) { return null; } return totalCost / totalNewA3; } function readTotalNewA3Value(row) { const derivedFromTotals = deriveTotalNewA3FromTotals(row); if (derivedFromTotals !== null) { return derivedFromTotals; } return deriveTotalNewA3FromVideos(row.videos); } function deriveTotalNewA3FromTotals(row) { const totalPlayCount = readFiniteNumber(row.total_play_cnt); const averageNewA3Rate = readFiniteNumber(row.avg_new_a3_rate); if (totalPlayCount === null || averageNewA3Rate === null) { return null; } return totalPlayCount * averageNewA3Rate; } function deriveTotalNewA3FromVideos(value) { if (!Array.isArray(value)) { return null; } let total = 0; let hasFiniteValue = false; value.forEach((video) => { if (!isRecord2(video)) { return; } const newA3 = readFiniteNumber(video.new_a3); if (newA3 === null) { return; } hasFiniteValue = true; total += newA3; }); return hasFiniteValue ? total : null; } function readNestedVideoCount(value) { return Array.isArray(value) ? value.length : null; } function readResponseRows(payload) { if (!isRecord2(payload) || payload.success !== true) { return null; } const topLevelData = isRecord2(payload.data) ? payload.data : null; return Array.isArray(topLevelData?.data) ? topLevelData.data : null; } function formatRateValue(value) { const number = typeof value === "number" ? value : Number(value); if (Number.isFinite(number)) { const percentage = number * 100; const formatted = new Intl.NumberFormat("en-US", { maximumFractionDigits: 2, minimumFractionDigits: percentage % 1 === 0 ? 0 : 2 }).format(percentage); return `${formatted}%`; } return ""; } function formatDecimalValue(value) { const number = typeof value === "number" ? value : Number(value); if (!Number.isFinite(number)) { return ""; } return new Intl.NumberFormat("en-US", { maximumFractionDigits: 2, minimumFractionDigits: 2 }).format(number); } async function defaultFetch(input, init) { return fetch(input, init); } function isRecord2(value) { return typeof value === "object" && value !== null; } function readFiniteNumber(value) { const number = typeof value === "number" ? value : Number(value); return Number.isFinite(number) ? number : null; } // src/shared/backend-metrics-messages.ts function isBackendMetricsSearchRequestMessage(value) { if (!value || typeof value !== "object") { return false; } const candidate = value; return candidate.type === "backend-metrics:search" && Boolean( candidate.value && typeof candidate.value === "object" && Array.isArray(candidate.value.starIds) && candidate.value.starIds.every( (starId) => typeof starId === "string" ) ); } // src/background/index.ts function registerBackgroundMessageHandler(chromeLike = readChromeLike(), dependencies = {}) { let authController = dependencies.authController; let searchBackendMetrics = dependencies.searchBackendMetrics; let submitBatch = dependencies.submitBatch; chromeLike.runtime?.onMessage?.addListener((message2, _sender, sendResponse) => { if (isDownloadMarketCsvMessage(message2)) { void triggerCsvDownload(chromeLike, message2).then(() => { sendResponse({ ok: true }); }).catch((error) => { sendResponse({ error: error instanceof Error ? error.message : String(error), ok: false }); }); return true; } if (isBatchSubmitMessage(message2)) { authController ??= createAuthController({ authClient: createLogtoAuthClient() }); submitBatch ??= createBatchSubmitClient({ baseUrl: DEFAULT_BATCH_SUBMIT_BASE_URL, getAccessToken: () => authController.getAccessToken(), sendMessage: () => Promise.reject(new Error("background batch submit does not use sendMessage")) }).submitBatch; void submitBatch(message2.payload).then((value) => { sendResponse({ ok: true, type: "batch:ack", value }); }).catch((error) => { sendResponse({ error: error instanceof Error ? error.message : String(error), ok: false, type: "batch:error" }); }); return true; } if (isBackendMetricsSearchRequestMessage(message2)) { authController ??= createAuthController({ authClient: createLogtoAuthClient() }); searchBackendMetrics ??= createBackendMetricsClient({ baseUrl: DEFAULT_BACKEND_METRICS_BASE_URL, getAccessToken: () => authController.getAccessToken() }).searchByStarIds; void searchBackendMetrics(message2.value.starIds).then((rows) => { sendResponse({ ok: true, type: "backend-metrics:result", value: { rows } }); }).catch((error) => { sendResponse({ error: error instanceof Error ? error.message : String(error), ok: false, type: "backend-metrics:error" }); }); return true; } if (!isAuthRequestMessage(message2)) { return; } authController ??= createAuthController({ authClient: createLogtoAuthClient() }); void handleAuthMessage(authController, message2).then((response) => { sendResponse(response); }).catch((error) => { sendResponse({ error: error instanceof Error ? error.message : String(error), ok: false, type: "auth:error" }); }); return true; }); } async function handleAuthMessage(authController, message2) { if (message2.type === "auth:get-state") { return { ok: true, type: "auth:state", value: await authController.getAuthState() }; } if (message2.type === "auth:get-access-token") { return { ok: true, type: "auth:token", value: { accessToken: await authController.getAccessToken() } }; } if (message2.type === "auth:sign-in") { await authController.signIn(); return { ok: true, type: "auth:ack" }; } await authController.signOut(); return { ok: true, type: "auth:ack" }; } function readChromeLike() { return globalThis.chrome ?? {}; } async function triggerCsvDownload(chromeLike, message2) { if (!chromeLike.downloads?.download) { throw new Error("chrome.downloads.download is unavailable"); } const csvUrl = `data:text/csv;charset=utf-8,${encodeURIComponent(`\uFEFF${message2.csv}`)}`; await Promise.resolve( chromeLike.downloads.download({ filename: message2.filename, saveAs: false, url: csvUrl }) ); } function isDownloadMarketCsvMessage(message2) { if (!message2 || typeof message2 !== "object") { return false; } const candidate = message2; return candidate.type === "download-market-csv" && typeof candidate.csv === "string" && typeof candidate.filename === "string"; } function isBatchSubmitMessage(message2) { if (!message2 || typeof message2 !== "object") { return false; } const candidate = message2; return candidate.type === "batch:submit" && "payload" in candidate; } registerBackgroundMessageHandler(); })(); /*! Bundled license information: @silverhand/essentials/lib/utilities/assertions.js: (*! * is-plain-object * * Copyright (c) 2014-2017, Jon Schlinkert. * Released under the MIT License. *) */