@schibsted/account-sdk-browser 6.0.0-alpha.7 → 6.0.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -273
- package/dist/account.d.ts +19 -7
- package/dist/identity.d.ts +25 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +41 -26
- package/dist/index.js.map +1 -1
- package/dist/session-response.d.ts +24 -0
- package/dist/types/account.d.ts +6 -4
- package/dist/types/session.d.ts +2 -5
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/account.ts +39 -8
- package/src/has-access-response.ts +1 -1
- package/src/identity.ts +66 -7
- package/src/index.ts +8 -0
- package/src/session-response.ts +25 -4
- package/src/types/account.ts +6 -4
- package/src/types/session.ts +2 -5
- package/src/version.ts +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["#identity","#monetization"],"sources":["../src/sdk-error.ts","../src/cache.ts","../src/config.ts","../src/validate.ts","../src/object.ts","../src/popup.ts","../src/url.ts","../src/rest-client.ts","../src/rest-clients.ts","../src/session-response.ts","../src/spid-talk.ts","../src/types/login.ts","../src/version.ts","../src/identity.ts","../src/has-access-response.ts","../src/monetization.ts","../src/resolve-browser-window.ts","../src/account.ts","../src/account-sdk.ts"],"sourcesContent":["/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\n/*\n * Note: this module can't have any internal dependencies because it's used in ./validate which\n * in turn is used as a dependency to a lot of other modules. Doing so may create a circular\n * dependency that's hard to debug in Node.\n */\n\nconst STRINGIFY_TYPES = ['boolean', 'number', 'string'];\n\n/**\n * Custom error class thrown by all SDK methods on failure.\n *\n * All rejected promises from API calls reject with an instance of this class.\n *\n * @group Errors\n */\nexport default class SDKError extends Error {\n /** HTTP status code from the server error payload;\n * declared explicitly to allow numeric comparisons without type-casting.\n */\n code?: number;\n /**\n * Properties copied from the server error object.\n * @internal\n */\n [key: string]: unknown;\n\n /**\n * @param message - Human-readable error message\n * @param errorObject - Optional server error payload. All enumerable properties are\n * shallow-copied onto this instance.\n */\n constructor(message: string, errorObject?: Record<string, unknown>) {\n super(message);\n this.name = 'SDKError';\n\n if (errorObject) {\n try {\n Object.assign(this, errorObject);\n } catch {\n // silent\n }\n }\n }\n\n /**\n * Returns a multi-line string with the error name, message, and any other properties copied\n * from the server error payload.\n */\n toString(): string {\n const ret = `${this.name}: ${this.message}`;\n const additionalInfo = Object.keys(this)\n .filter((key) => key !== 'name' && STRINGIFY_TYPES.includes(typeof this[key]))\n .map((key) => ` ${key}: ${this[key]}`)\n .join('\\n');\n return additionalInfo ? `${ret}\\n${additionalInfo}` : ret;\n }\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport SDKError from './sdk-error.js';\n\n/**\n * Check whether we are able to use web storage\n * @param storeProvider - A function to return a WebStorage instance (either\n * `sessionStorage` or `localStorage` from a `Window` object)\n * @private\n */\nfunction webStorageWorks(storeProvider: (() => Storage) | undefined): boolean {\n if (!storeProvider) {\n return false;\n }\n try {\n const store = storeProvider();\n const randomKey = 'x-x-x-x'.replace(/x/g, () => String(Math.random()));\n const testValue = 'TEST-VALUE';\n store.setItem(randomKey, testValue);\n const val = store.getItem(randomKey);\n store.removeItem(randomKey);\n return val === testValue;\n } catch {\n return false;\n }\n}\n\n/**\n * Cache implementation used when web storage is available. Wraps a `Storage` instance.\n * @private\n */\nclass WebStorageCache {\n store: Storage;\n get: (key: string) => string | null;\n set: (key: string, value: string) => void;\n delete: (key: string) => void;\n\n /**\n * Create web storage cache object\n * @param store - A reference to either `sessionStorage` or `localStorage` from a\n * `Window` object\n */\n constructor(store: Storage) {\n this.store = store;\n this.get = (key) => this.store.getItem(key);\n this.set = (key, value) => this.store.setItem(key, value);\n this.delete = (key) => this.store.removeItem(key);\n }\n}\n\n/**\n * Cache implementation used when web storage is not available. Stores entries in an in-memory object.\n * @private\n */\nclass LiteralCache {\n store: Record<string, string>;\n get: (key: string) => string | undefined;\n set: (key: string, value: string) => void;\n delete: (key: string) => void;\n\n /**\n * Create JS object literal cache object\n */\n constructor() {\n this.store = {};\n this.get = (key) => this.store[key];\n this.set = (key, value) => {\n this.store[key] = value;\n };\n this.delete = (key) => {\n delete this.store[key];\n };\n }\n}\n\ntype CacheEntry = { expiresOn: number; value: unknown };\n\nconst maxExpiresIn = 2 ** 31 - 1;\n\n/**\n * Cache class that attempts WebStorage (session/local storage), and falls back to JS object literal\n * @private\n */\nexport default class Cache {\n cache: WebStorageCache | LiteralCache;\n type: string;\n\n /**\n * @param storeProvider - A function to return a WebStorage instance (either\n * `sessionStorage` or `localStorage` from a `Window` object)\n * @throws {SDKError} - If sessionStorage or localStorage are not accessible\n */\n constructor(storeProvider?: () => Storage) {\n if (storeProvider && webStorageWorks(storeProvider)) {\n this.cache = new WebStorageCache(storeProvider());\n this.type = 'WebStorage';\n } else {\n this.cache = new LiteralCache();\n this.type = 'ObjectLiteralStorage';\n }\n }\n\n /**\n * Get a value from cache (checks that the object has not expired)\n * @param key\n * @private\n */\n get(key: string): unknown {\n /**\n * JSON.parse safe wrapper\n * @param raw\n */\n function getObj(raw: string | null | undefined): CacheEntry | null {\n if (raw == null) {\n return null;\n }\n try {\n return JSON.parse(raw);\n } catch {\n return null;\n }\n }\n\n try {\n const raw = this.cache.get(key);\n const obj = getObj(raw);\n if (obj && Number.isInteger(obj.expiresOn) && obj.expiresOn > Date.now()) {\n return obj.value;\n }\n this.delete(key);\n return null;\n } catch (e) {\n throw new SDKError(String(e));\n }\n }\n\n /**\n * Set a cache entry\n * @param key\n * @param value\n * @param expiresIn - Value in milliseconds until the entry expires\n * @private\n */\n set(key: string, value: unknown, expiresIn = 0): void {\n if (expiresIn <= 0) {\n return;\n }\n expiresIn = Math.min(maxExpiresIn, expiresIn);\n\n try {\n const expiresOn = Math.floor(Date.now() + expiresIn);\n this.cache.set(key, JSON.stringify({ expiresOn, value }));\n setTimeout(() => this.delete(key), expiresIn);\n } catch (e) {\n throw new SDKError(String(e));\n }\n }\n\n /**\n * Delete a cache entry\n * @param key\n * @private\n */\n delete(key: string): void {\n try {\n this.cache.delete(key);\n } catch (e) {\n throw new SDKError(String(e));\n }\n }\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\n/*\n * This file declares configs that are essentially part of how the SDK works and interacts with our\n * backend servers.\n *\n * What goes here?\n * - The configurations that are likely to change over time\n * - Constants that are otherwise obscure (for example 7000 for a TIMEOUT)\n *\n * What doesn't go here?\n * - options that the users of the SDK are supposed to set or provide as a parameter to functions\n * and classes.\n */\n\n/**\n * Core configuration used by the SDK.\n * - `ENDPOINTS.SPiD` — SPiD endpoints per environment\n * - `ENDPOINTS.BFF` — Endpoints used with new GDPR-compliant web flows\n * - `ENDPOINTS.SESSION_SERVICE` — Endpoints to check global user session data\n *\n */\nconst config = {\n ENDPOINTS: {\n SPiD: {\n LOCAL: 'http://id.localhost',\n DEV: 'https://identity-dev.schibsted.com',\n PRE: 'https://identity-pre.schibsted.com',\n PRO: 'https://login.schibsted.com',\n PRO_NO: 'https://payment.schibsted.no',\n PRO_FI: 'https://login.schibsted.fi',\n PRO_DK: 'https://login.schibsted.dk',\n },\n BFF: {\n LOCAL: 'http://id.localhost/authn/',\n DEV: 'https://identity-dev.schibsted.com/authn/',\n PRE: 'https://identity-pre.schibsted.com/authn/',\n PRO: 'https://login.schibsted.com/authn/',\n PRO_NO: 'https://payment.schibsted.no/authn/',\n PRO_FI: 'https://login.schibsted.fi/authn/',\n PRO_DK: 'https://login.schibsted.dk/authn/',\n },\n SESSION_SERVICE: {\n LOCAL: 'http://session-service.id.localhost',\n DEV: 'https://session-service.identity-dev.schibsted.com',\n PRE: 'https://session-service.identity-pre.schibsted.com',\n PRO: 'https://session-service.login.schibsted.com',\n PRO_NO: 'https://session-service.payment.schibsted.no',\n PRO_FI: 'https://session-service.login.schibsted.fi',\n PRO_DK: 'https://session-service.login.schibsted.dk',\n },\n },\n NAMESPACE: {\n LOCAL: 'id.localhost',\n DEV: 'schibsted.com',\n PRE: 'schibsted.com',\n PRO: 'schibsted.com',\n PRO_NO: 'spid.no',\n PRO_FI: 'schibsted.fi',\n PRO_DK: 'schibsted.dk',\n },\n} as const;\n\nexport default config;\nexport const ENDPOINTS = config.ENDPOINTS;\nexport const NAMESPACE = config.NAMESPACE;\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport SDKError from './sdk-error.js';\n\n/*\n * This module defines a set of validation functions which are used in the rest of the SDK.\n * Why make our own validation module?\n * 1. To implement the validations that we specifically need for the SDK\n * 2. To have one less dependency\n */\n\n/**\n * A utility function that throws an SDKError if an assertion fails. It's mostly useful for\n * validating function inputs.\n *\n * Narrows `condition` for the rest of the enclosing scope (TypeScript assertion signature).\n * @param condition - The condition that we're asserting\n * @param message - The error message\n * @throws {SDKError} - If the condition is falsy it throws the appropriate error\n */\nexport function assert(condition: boolean, message = 'Assertion failed'): asserts condition {\n if (!condition) {\n throw new SDKError(message);\n }\n}\n\n/**\n * Checks if a value is a string or not\n * @param value - The value to check\n */\nexport function isStr(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n/**\n * Checks if a value is a non-empty string\n * @param value - The value to check\n */\nexport function isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\n/**\n * checks if a given value is an object (but not null)\n * @param value - The value to check\n */\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Checks if a given value is an object with at least one own key\n * @param value - The value to check\n */\nexport function isNonEmptyObj(value: unknown): value is Record<string, unknown> {\n return isObject(value) && Object.keys(value).length > 0;\n}\n\n/**\n * Checks if a given string is a valid URL\n * @param value - The string to be tested\n * @param mandatoryFields - A list of mandatory fields that should exist in the parsed\n * `URL` object\n */\nexport function isUrl(value: string, ...mandatoryFields: (keyof URL)[]): boolean {\n try {\n const parsedUrl = new URL(value);\n return mandatoryFields.every((f) => parsedUrl[f]);\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if a given value is a function\n * @param value - The value to check\n */\nexport function isFunction(value: unknown): value is (...args: unknown[]) => unknown {\n return typeof value === 'function';\n}\n\n/**\n * Checks if a string matches any of the strings in a set of possibilities\n * @param value\n * @param possibilities - An array of strings that'll be used to check the string\n * inclusion. Note that for performance reasons, we don't validate this parameter.\n * @param caseSensitive - Should the check be case sensitive\n */\nexport function isStrIn(value: string, possibilities: string[], caseSensitive = false): boolean {\n const _isSameStrCaseInsensitive = (str: string) =>\n isStr(str) && value.toUpperCase() === str.toUpperCase();\n if (!(isStr(value) && Array.isArray(possibilities))) {\n return false;\n }\n if (caseSensitive) {\n return possibilities.indexOf(value) !== -1;\n }\n return possibilities.some(_isSameStrCaseInsensitive);\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\n/**\n * @summary Some routines that work on javascript objects\n * @private\n */\n\nimport SDKError from './sdk-error.js';\nimport { assert, isNonEmptyObj, isObject } from './validate.js';\n\n/**\n * Similar to Object.assign({}, src) but only clones the keys of an object that have non-undefined\n * values.\n * Please note that the values in the rightmost parameters can overwrite the values of the earlier\n * parameters so the order of the parameters matters.\n * @example\n * cloneDefined({foo: 1, bar: 2}, {foo: 2}) // returns {foo: 2, bar: 2}\n *\n * @param sources - one or more sources. Their defined properties will override the ones\n * that came before it. For example if `source1.foo = 'bar'` and `source2.foo = 'baz'`, the\n * result will include `{ foo: 'baz' }`\n */\nexport function cloneDefined(...sources: object[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n if (!(sources && sources.length)) {\n throw new SDKError('No objects to clone');\n }\n sources.forEach((source) => {\n assert(isObject(source));\n if (isNonEmptyObj(source)) {\n Object.entries(source).forEach(([key, value]) => {\n if (typeof value !== 'undefined') {\n result[key] = isObject(value) ? cloneDeep(value) : value;\n }\n });\n }\n });\n return result;\n}\n\n/**\n * Deep copies an object. This is handy for immutability.\n * @param obj - An object, array or null.\n * @throws {SDKError} - if the obj is not an accepted type or is not\n * stringifiable by JSON for example if it has loops\n */\nexport function cloneDeep<T extends object | null>(obj: T): T {\n assert(typeof obj === 'object', `obj should be an object (even null) but it is ${obj}`);\n return JSON.parse(JSON.stringify(obj)) || obj;\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport { cloneDefined } from './object.js';\nimport { assert, isFunction, isObject, isUrl } from './validate.js';\n\n/**\n * Serializes an object to string.\n * @private\n * @param obj - for example {a: 'b', c: 1}\n */\nfunction serialize(obj: Record<string, unknown>): string {\n assert(isObject(obj), `Object must be an object but it is '${obj}'`);\n return Object.keys(obj)\n .map((key) => `${key}=${obj[key]}`)\n .join(',');\n}\n\nconst defaultWindowFeatures = {\n scrollbars: 'yes',\n location: 'yes',\n status: 'no',\n menubar: 'no',\n toolbar: 'no',\n resizable: 'yes',\n};\n\n/**\n * Opens a popup\n * @param parentWindow - A reference to the window that will open the popup\n * @param url - The URL that the popup will open\n * @param windowName - A name for the window\n * @param windowFeatures - Window features for the popup (default ones are usually ok)\n * @private\n */\nexport function open(\n parentWindow: Window,\n url: string,\n windowName = '',\n windowFeatures: Record<string, string | number> = {},\n): Window | null {\n assert(isObject(parentWindow), `window was supposed to be an object but it is ${parentWindow}`);\n assert(\n isObject(parentWindow.screen),\n `window should be a valid Window object but it lacks a 'screen' property`,\n );\n assert(\n isFunction(parentWindow.open),\n `window should be a valid Window object but it lacks an 'open' function`,\n );\n assert(isUrl(url), 'Invalid URL for popup');\n\n const { height, width } = parentWindow.screen;\n\n const mergedFeatures = cloneDefined(defaultWindowFeatures, windowFeatures);\n const { width: featureWidth, height: featureHeight } = mergedFeatures;\n if (\n typeof featureWidth === 'number' &&\n Number.isFinite(featureWidth) &&\n Number.isFinite(width)\n ) {\n mergedFeatures.left = (width - featureWidth) / 2;\n }\n if (\n typeof featureHeight === 'number' &&\n Number.isFinite(featureHeight) &&\n Number.isFinite(height)\n ) {\n mergedFeatures.top = (height - featureHeight) / 2;\n }\n const features = serialize(mergedFeatures);\n return parentWindow.open(url, windowName, features);\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport { assert, isNonEmptyObj, isNonEmptyString, isUrl } from './validate.js';\n\n/**\n * A simple utility function that allows looking up URLs from a dictionary\n * @param url - A url like http://example.com, or a key used for lookup\n * @param urlMap - A map of URLs like `{ DEV: 'http://dev.example.com' }`\n * @returns The resolved URL: the mapped value when `url` is a known key, otherwise `url` itself\n * @throws {SDKError} - If the url is not a string or is an empty string\n */\nexport function urlMapper(url: string, urlMap: Record<string, string>): string {\n assert(isNonEmptyString(url), `\"url\" param must be a non empty string: ${typeof url}`);\n if (isNonEmptyObj(urlMap) && isUrl(urlMap[url])) {\n return urlMap[url];\n }\n assert(isUrl(url, 'hostname'), `Bad URL given: '${url}'`);\n return url;\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport { cloneDefined } from './object.js';\nimport SDKError from './sdk-error.js';\nimport type { LogFunction } from './types/common.js';\nimport { urlMapper } from './url.js';\nimport { assert, isFunction, isNonEmptyString, isObject, isStr } from './validate.js';\n\n/**\n * Converts a series of parameters of various types to a string that's suitable for logging.\n * @private\n * @param msg - The values to format; objects are stringified to JSON\n */\nconst logString = (msg: unknown[]): string =>\n msg.map((m) => (isObject(m) ? JSON.stringify(m, null, 2) : m)).join(' ');\n\nconst logFn = (fn: LogFunction | undefined, ...msg: unknown[]): void => {\n if (fn) {\n fn(logString(msg));\n }\n};\n\n/**\n * Encode a string like URLSearchParams would do\n * @private\n * @param str - The input\n */\nfunction encode(str: string): string {\n const replace: Record<string, string> = {\n '!': '%21',\n \"'\": '%27',\n '(': '%28',\n ')': '%29',\n '~': '%7E',\n '%20': '+',\n '%00': '\\x00',\n };\n return encodeURIComponent(str).replace(/[!'()~]|%20|%00/g, (match) => replace[match]);\n}\ntype FetchFunction = (input: RequestInfo, init?: RequestInit) => Promise<Response>;\nconst globalFetch = () => window.fetch && window.fetch.bind(window);\nconst noFetch: FetchFunction = () => {\n throw new SDKError('fetch is not available in this environment');\n};\n\n/**\n * The value of a single query parameter; `undefined` entries are skipped.\n */\ntype QueryValue = string | number | boolean | undefined;\n\n/**\n * Query parameters appended to a request URL.\n */\ntype QueryParams = Record<string, QueryValue>;\n\n/**\n * HTTP method used for a request.\n */\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\ntype JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };\n\ntype ResponseParser<T> = (value: JsonValue) => T;\n\ntype RESTRequestOptions<T = JsonValue> = {\n method: HttpMethod;\n pathname: string;\n data?: QueryParams;\n headers?: Record<string, string>;\n useDefaultParams?: boolean;\n fetchOptions?: RequestInit;\n parseResponse?: ResponseParser<T>;\n};\n\n/**\n * This class can be used for creating a wrapper around a server and all its endpoints.\n * Its functionality is extended by {@link JSONPClient}\n * Creates a client to a REST server. While useful stand-alone, it's also used for some other\n * types of client that change some functionalities.\n * @throws {SDKError} - If any of options are invalid\n * @summary The simplest way to communicate to a REST endpoint without any\n * special authentication\n * @private\n */\nexport class RESTClient {\n url: URL;\n defaultParams: QueryParams;\n log?: LogFunction;\n fetch: FetchFunction;\n\n /**\n * @param options\n * @param options.serverUrl - The URL to the server eg.\n * https://login.schibsted.com or a URL key like 'DEV' in combination with {@link envDic}.\n * @param options.envDic - A dictionary that will be used for looking up\n * {@link serverUrl} keys. If serverUrl is always a URL, you don't need this.\n * @param options.fetch - The fetch function to use. It can be native\n * or a polyfill\n * @param options.log - A function that will be called with log messages about\n * request and response\n * @param options.defaultParams - Query parameters added to every request\n */\n constructor({\n serverUrl = 'PRE',\n envDic,\n fetch = globalFetch() ?? noFetch,\n log,\n defaultParams = {},\n }: {\n serverUrl?: string;\n envDic?: Record<string, string>;\n fetch?: FetchFunction;\n log?: LogFunction;\n defaultParams?: QueryParams;\n }) {\n assert(isObject(defaultParams), `defaultParams should be a non-null object`);\n\n const mappedUrl = urlMapper(serverUrl, envDic ?? {});\n const handledServerUrl = mappedUrl.endsWith('/') ? mappedUrl : `${mappedUrl}/`;\n this.url = new URL(handledServerUrl);\n\n this.defaultParams = defaultParams;\n\n if (log) {\n assert(isFunction(log), `log must be a function but it is ${log}`);\n this.log = log;\n }\n\n this.fetch = fetch;\n }\n\n /**\n * Makes the actual call to the server and deals with headers, data objects and the edge cases.\n * Please note that this method expects the response to be in JSON format. However, it'll not\n * parse the response if its code is not in the 200 range.\n * @param options - An obligatory options object\n * @param options.method - The HTTP request method, e.g. 'GET' or 'POST'\n * @param options.pathname - The path to the endpoint like 'api/2/endpoint-name'\n * @param options.data - Query parameters added to the request URL\n * @param options.headers - Request headers as a plain key/value map\n * @param options.useDefaultParams - Should we add the defaultParams to the query?\n * @param options.fetchOptions - Additional fetch options\n * @throws {SDKError} - If the call can't be made for whatever reason.\n */\n // Overloads describe the two supported modes:\n // - without a parser: return the parsed JSON response as-is;\n // - with a parser: return the parser's typed result.\n async go(options: RESTRequestOptions): Promise<JsonValue>;\n async go<T>(options: RESTRequestOptions<T> & { parseResponse: ResponseParser<T> }): Promise<T>;\n\n // TypeScript requires one implementation signature for the overloads above.\n async go<T = JsonValue>(options: RESTRequestOptions<T>): Promise<JsonValue | T> {\n const {\n method,\n headers,\n pathname,\n data = {},\n useDefaultParams = true,\n fetchOptions = { method: options.method, credentials: 'include' },\n parseResponse,\n } = options;\n assert(isNonEmptyString(method), `Method must be a non empty string but it is \"${method}\"`);\n assert(isNonEmptyString(pathname), `Pathname must be string but it is \"${pathname}\"`);\n assert(isObject(data), `data must be a non-null object`);\n\n fetchOptions.headers = isObject(headers) ? headers : {};\n const fullUrl = this.makeUrl(pathname, data, useDefaultParams);\n\n logFn(this.log, 'Request:', method.toUpperCase(), fullUrl);\n logFn(this.log, 'Request Headers:', fetchOptions.headers);\n logFn(this.log, 'Request Body:', fetchOptions.body);\n try {\n const response = await this.fetch(fullUrl, fetchOptions);\n logFn(this.log, 'Response Code:', response.status, response.statusText);\n if (!response.ok) {\n // status code not in range 200-299\n throw new SDKError(response.statusText, { code: response.status });\n }\n const responseObject: JsonValue = await response.json();\n logFn(this.log, 'Response Parsed:', responseObject);\n return parseResponse ? parseResponse(responseObject) : responseObject;\n } catch (err: unknown) {\n let msg = isStr(err) ? err : 'Unknown RESTClient error';\n if (isObject(err) && isStr(err.message)) {\n msg = err.message;\n }\n const errorObject = isObject(err) ? err : undefined;\n throw new SDKError(`Failed to '${method}' '${fullUrl}': '${msg}'`, errorObject);\n }\n }\n\n /**\n * Creates a url that points to an endpoint in the server\n * @param pathname - WHATWG pathname ie. 'api/2/endpoint-name'\n * @param query - Query parameters to serialize into the query string\n * @param useDefaultParams - Should we add the defaultParams to the query?\n */\n makeUrl(pathname = '', query: QueryParams = {}, useDefaultParams = true): string {\n const handledPathname = pathname.startsWith('/') ? pathname.slice(1) : pathname;\n\n const url = new URL(handledPathname, this.url);\n url.search = RESTClient.search(query, useDefaultParams, this.defaultParams);\n return url.href;\n }\n\n /**\n * Make a GET request\n * @param pathname - WHATWG pathname ie. 'api/2/endpoint-name'\n * @param data - Query parameters\n */\n // Mirrors `go()` overloads for the common GET helper.\n get(pathname: string, data?: QueryParams): Promise<JsonValue>;\n get<T>(\n pathname: string,\n data: QueryParams | undefined,\n parseResponse: ResponseParser<T>,\n ): Promise<T>;\n\n // TypeScript requires one implementation signature for the overloads above.\n get<T>(\n pathname: string,\n data?: QueryParams,\n parseResponse?: ResponseParser<T>,\n ): Promise<JsonValue | T> {\n if (parseResponse) {\n return this.go({ method: 'GET', pathname, data, parseResponse });\n }\n return this.go({ method: 'GET', pathname, data });\n }\n\n /**\n * Construct query string for WHATWG urls\n * @private\n * @param query - Query parameters to generate the query string from\n * @param useDefaultParams - Use defaultParams or not\n * @param defaultParams - Default params\n */\n private static search(\n query: QueryParams,\n useDefaultParams: boolean,\n defaultParams: QueryParams,\n ): string {\n const params = useDefaultParams ? cloneDefined(defaultParams, query) : cloneDefined(query);\n return Object.keys(params)\n .filter((p) => params[p] !== '')\n .map((p) => `${encode(p)}=${encode(String(params[p]))}`)\n .join('&');\n }\n}\n\nexport default RESTClient;\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport { NAMESPACE } from './config.js';\nimport RESTClient from './rest-client.js';\nimport type { LogFunction } from './types/common.js';\nimport { assert, isNonEmptyString } from './validate.js';\n\ntype AccountRestClientOptions = {\n serverUrl: string;\n log?: LogFunction;\n defaultParams: Record<string, string | number | boolean | undefined>;\n};\n\nconst isKnownNamespace = (env: string): env is keyof typeof NAMESPACE =>\n Object.hasOwn(NAMESPACE, env);\n\nexport const buildClientSdrn = (env: string, clientId: string): string => {\n assert(isNonEmptyString(clientId), 'clientId parameter is required');\n assert(isKnownNamespace(env), `env parameter is invalid: ${env}`);\n\n return `sdrn:${NAMESPACE[env]}:client:${clientId}`;\n};\n\nexport const createAccountRestClient = ({\n serverUrl,\n log,\n defaultParams,\n}: AccountRestClientOptions): RESTClient => new RESTClient({ serverUrl, log, defaultParams });\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport type {\n ConnectedSessionResponse,\n ConnectedSessionWithUserIdResponse,\n NormalizedSessionPayload,\n RedirectSessionPayload,\n SessionFailureResponse,\n SessionResponse,\n SessionSuccessResponse,\n} from './types/session.js';\nimport { isObject, isStr } from './validate.js';\n\nexport function isSessionSuccessResponse(value: unknown): value is SessionSuccessResponse {\n return isObject(value) && typeof value.result === 'boolean';\n}\n\nexport function isConnectedSessionResponse(value: unknown): value is ConnectedSessionResponse {\n return isSessionSuccessResponse(value) && value.result === true;\n}\n\nexport function isSessionFailureResponse(value: unknown): value is SessionFailureResponse {\n return isObject(value) && Boolean(value.error);\n}\n\nexport function isRedirectSessionPayload(value: unknown): value is RedirectSessionPayload {\n return isObject(value) && Object.keys(value).length === 1 && isStr(value.redirectURL);\n}\n\nexport function isConnectedSessionWithUserIdResponse(\n value: SessionResponse,\n): value is ConnectedSessionWithUserIdResponse {\n return (\n isConnectedSessionResponse(value) &&\n (typeof value.userId === 'number' || typeof value.userId === 'string')\n );\n}\n\n/**\n * Converts an unknown Session Service `hasSession` payload into one of the shapes the SDK knows how\n * to handle.\n *\n * This function is intentionally tolerant because `hasSession()` historically resolved unknown\n * object payloads instead of rejecting them. The SDK relies on that behavior for backwards\n * compatibility with clients that check the raw response themselves.\n *\n * The normal cases are:\n * - regular success payloads with a boolean `result`;\n * - failure payloads wrapped as `{ error, response? }`;\n * - Safari/session-refresh redirect payloads shaped as `{ redirectURL }`.\n *\n * Any other object is preserved as an unrecognized response so callers can still receive it.\n * Non-object values are normalized to `{}`, matching the old \"empty response\" fallback used by\n * `hasSession()` and cached-session reads.\n *\n * This is used both for network responses parsed by `RESTClient` and for values restored from the\n * session cache, so the rest of the Identity flow can switch on typed guards instead of repeatedly\n * re-validating unknown data.\n *\n * @internal\n */\nexport function normalizeSessionResponse(value: unknown): NormalizedSessionPayload {\n if (isRedirectSessionPayload(value)) {\n return value;\n }\n if (isSessionFailureResponse(value)) {\n return value;\n }\n if (isSessionSuccessResponse(value)) {\n return value;\n }\n if (isObject(value)) {\n return value;\n }\n\n return {};\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\n/**\n * A workaround for how Schibsted account handles JSONP calls in the browser\n * @private\n */\n\nimport './globals.js';\nimport { isFunction } from './validate.js';\n\n/**\n * This is a workaround for making the old SPiD/hassession on JSONP APIs compatible with more common\n * JSONP convention where the callback function is expected to exist in the global object.\n *\n * How does it work?\n * =================\n * The old SPiD JSONP APIs relied on SPiD.Talk.response(callbackName, data) but fetch-jsonp merely\n * calls window[callbackName](data) which is more common practice. This module simply acts as an\n * adapter to modernize the old mechanism until we support CORS. To see how the SPiD solution works,\n * try to run a simple JSONP request or debug it in the network tab. This module will be removed\n * when CORS is supported.\n * @param global - A reference to the global object, typically the `Window`.\n */\nexport function emulate(global: Window): void {\n if (!global.SPiD || typeof global.SPiD !== 'object') {\n global.SPiD = {};\n }\n if (!global.SPiD.Talk || typeof global.SPiD.Talk !== 'object') {\n global.SPiD.Talk = {};\n }\n if (!isFunction(global.SPiD.Talk.response)) {\n global.SPiD.Talk.response = (callbackName: string, data: unknown) =>\n (global as any)[callbackName](data);\n }\n}\n","/**\n * Options accepted by {@link Account#login} and related login URL helpers.\n *\n * @group Login & Widget\n */\nexport type LoginOptions = {\n /**\n * An opaque value used by the client to maintain state between the request and callback.\n * It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}\n */\n state: string;\n /**\n * Authentication Context Class Reference values. If omitted, the default account flow is used.\n * Supported values include `password`, `otp`, `sms`, `otp-email`, `eid`, `eid-no`, `eid-se`,\n * `eid-fi`, and `eid-dk`. Values other than `otp-email` may be combined as a space-separated\n * string. Verify the AMR (Authentication Methods References) claim in the ID token on your\n * backend if you need to enforce a completed authentication method.\n */\n acrValues?:\n | 'password'\n | 'otp'\n | 'sms'\n | 'eid-dk'\n | 'eid-no'\n | 'eid-se'\n | 'eid-fi'\n | 'eid'\n | 'otp-email'\n | (string & {});\n /**\n * The OAuth scopes for the tokens. This is a list of scopes, separated by space. If the list\n * of scopes contains `openid`, the generated tokens includes the id token which can be useful\n * for getting information about the user. Omitting scope is allowed, while `invalid_scope` is\n * returned when the client asks for a scope you aren't allowed to request.\n * {@link https://tools.ietf.org/html/rfc6749#section-3.3}\n * Defaults to `openid`.\n */\n scope?: 'openid' | (string & {});\n /**\n * Redirect uri that will receive the code. Must exactly match a redirectUri from your client\n * in self-service\n */\n redirectUri?: string;\n /** Should we try to open a popup window? Defaults to `false`. */\n preferPopup?: boolean;\n /** user email or UUID hint */\n loginHint?: string;\n /** Pulse tag */\n tag?: string;\n /** Teaser slug. Teaser with given slug will be displayed in place of default teaser */\n teaser?: string;\n /**\n * Specifies the allowable elapsed time in seconds since the last time the End-User was actively\n * authenticated. If last authentication time is more than maxAge seconds in the past,\n * re-authentication will be required. See the OpenID Connect spec section 3.1.2.1 for more\n * information. Prefer a number of seconds; strings remain accepted for legacy callers.\n */\n maxAge?: number | string;\n /**\n * Optional parameter to overwrite client locale setting.\n * New flows supports nb_NO, fi_FI, sv_SE, en_US\n */\n locale?: 'nb_NO' | 'fi_FI' | 'sv_SE' | 'en_US';\n /** display username and password on one screen. Defaults to `false`. */\n oneStepLogin?: boolean;\n /**\n * String that specifies whether the Authorization Server prompts the End-User for\n * reauthentication or confirm account screen. Supported values: `select_account` or `login`.\n * Defaults to `select_account`.\n */\n prompt?: 'select_account' | 'login';\n /** Identifier for cross-domain tracking in Pulse */\n xDomainId?: string;\n /** Environment for cross-domain tracking in Pulse */\n xEnvironmentId?: string;\n /** Campaign identifier for tracking in Pulse */\n originCampaign?: string;\n};\n\n/**\n * Identical to {@link LoginOptions} except that `state` may also be a (possibly async) function;\n * all other fields reuse the `LoginOptions` documentation.\n *\n * @group Login & Widget\n */\nexport type SimplifiedLoginWidgetLoginOptions = Omit<LoginOptions, 'state'> & {\n /**\n * An opaque value used by the client to maintain state between the request and callback.\n * It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}\n */\n state: string | (() => string | Promise<string>);\n};\n\n/**\n * Minimal user information used by the simplified login widget flow.\n *\n * @group Login & Widget\n */\nexport type SimplifiedLoginData = {\n /** Deprecated: User UUID used as `loginHint` for {@link Account#login}. */\n identifier: string;\n /** Human-readable user identifier */\n display_text: string;\n /** Client name */\n client_name: string;\n /** Provider id used by the simplified login widget when supplied by the backend. */\n provider_id?: string;\n};\n\n/**\n * Configuration options for {@link Account#showSimplifiedLoginWidget}.\n *\n * @group Login & Widget\n */\nexport type SimplifiedLoginWidgetOptions = {\n /** expected encoding of simplified login widget. Could be utf-8 (default), iso-8859-1 or iso-8859-15 */\n encoding?: string;\n /**\n * expected locale of simplified login widget. Should be provided in a short format like 'nb',\n * 'sv'. If not set, a value from the env variable is used.\n */\n locale?: 'nb' | 'sv' | 'fi' | 'da' | 'en';\n};\n\nexport type SimplifiedLoginWidgetInitialParams = {\n displayText: string;\n env: string;\n clientName: string;\n clientId: string;\n providerId?: string;\n locale?: SimplifiedLoginWidgetOptions['locale'];\n windowWidth: () => number;\n windowOnResize: (handler: () => void) => void;\n};\n\nexport type SimplifiedLoginWidgetHandler = () => void | Promise<void>;\n\nexport type OpenSimplifiedLoginWidget = (\n initialParams: SimplifiedLoginWidgetInitialParams,\n loginHandler: SimplifiedLoginWidgetHandler,\n loginNotYouHandler: SimplifiedLoginWidgetHandler,\n initHandler: SimplifiedLoginWidgetHandler,\n cancelLoginHandler: SimplifiedLoginWidgetHandler,\n) => unknown;\n\nexport const hasOpenSimplifiedLoginWidget = (\n targetWindow: Window,\n): targetWindow is Window & { openSimplifiedLoginWidget: OpenSimplifiedLoginWidget } => {\n return typeof targetWindow.openSimplifiedLoginWidget === 'function';\n};\n","// Version is bumped automatically by release-please. See release-please-config.json.\n\nconst version = '6.0.0-alpha.7'; // x-release-please-version\nexport default version;\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport Cache from './cache.js';\nimport { ENDPOINTS } from './config.js';\nimport { cloneDeep } from './object.js';\nimport * as popup from './popup.js';\nimport type RESTClient from './rest-client.js';\nimport { buildClientSdrn, createAccountRestClient } from './rest-clients.js';\nimport SDKError from './sdk-error.js';\nimport {\n isConnectedSessionResponse,\n isConnectedSessionWithUserIdResponse,\n isRedirectSessionPayload,\n isSessionFailureResponse,\n isSessionSuccessResponse,\n normalizeSessionResponse,\n} from './session-response.js';\nimport * as spidTalk from './spid-talk.js';\nimport type { AccountEventName } from './types/account.js';\nimport type { LogFunction } from './types/common.js';\nimport type {\n IdentityBeforeRedirectCallback,\n IdentityOptions,\n VarnishCookieOptions,\n} from './types/identity.js';\nimport {\n hasOpenSimplifiedLoginWidget,\n type LoginOptions,\n type OpenSimplifiedLoginWidget,\n type SimplifiedLoginData,\n type SimplifiedLoginWidgetInitialParams,\n type SimplifiedLoginWidgetLoginOptions,\n type SimplifiedLoginWidgetOptions,\n} from './types/login.js';\nimport type {\n ConnectedSessionResponse,\n NormalizedSessionPayload,\n SessionObjectResponse,\n SessionResponse,\n} from './types/session.js';\nimport { urlMapper } from './url.js';\nimport { assert, isNonEmptyString, isObject, isStr, isStrIn, isUrl } from './validate.js';\nimport version from './version.js';\n\ndeclare global {\n interface Window {\n openSimplifiedLoginWidget?: OpenSimplifiedLoginWidget;\n }\n}\n\nconst HAS_SESSION_CACHE_KEY = 'hasSession-cache';\nconst SESSION_CALL_BLOCKED_CACHE_KEY = 'sessionCallBlocked-cache';\nconst SESSION_CALL_BLOCKED_TTL = 1000 * 60 * 5;\n\nconst TAB_ID_KEY = 'tab-id-cache';\nconst TAB_ID = Math.floor(Math.random() * 100000);\nconst TAB_ID_TTL = 1000 * 60 * 60 * 24 * 30;\n\nconst globalWindow = () => window;\n\n/**\n * Provides Identity functionalty to a web page\n */\nexport class Identity {\n // Event bus\n private readonly eventTarget = new EventTarget();\n\n // Configuration\n private readonly window: Window;\n private readonly clientId: string;\n private readonly redirectUri: string;\n private readonly env: string;\n private readonly log?: LogFunction;\n private readonly callbackBeforeRedirect: IdentityBeforeRedirectCallback;\n\n // Caches\n private readonly sessionStorageCache: Cache;\n private readonly localStorageCache: Cache;\n private enableSessionCaching: boolean;\n\n // REST clients\n private readonly spid: RESTClient;\n private readonly oauthService: RESTClient;\n private readonly bffService: RESTClient;\n private readonly sessionService: RESTClient;\n private readonly globalSessionService: RESTClient;\n private readonly usedSessionServiceGetSessionEndpoint: 'v2/session' | 'session';\n\n // Session state\n /**\n * @internal Starts as `{}` before the first `hasSession()` call, then stores the latest\n * object response from hasSession().\n */\n private session: SessionObjectResponse;\n private hasSessionInProgress?: false | Promise<SessionResponse>;\n\n // Popup & Varnish cookie state\n private popup?: Window | null;\n private setVarnishCookie?: boolean;\n private varnishExpiresIn?: number;\n private varnishCookieDomain?: string;\n\n /**\n * @param options\n * @param options.clientId - Example: \"1234567890abcdef12345678\"\n * @param options.sessionDomain - Example: \"https://id.site.com\"\n * @param options.redirectUri - Example: \"https://site.com\"\n * @param options.env - Schibsted account environment: `PRE` (default), `PRO`, `PRO_NO`, `PRO_FI` or `PRO_DK`\n * @param options.log - A function that receives debug log information. If not set,\n * no logging will be done\n * @param options.window - window object\n * @param options.callbackBeforeRedirect - callback triggered before session refresh redirect happen\n * @throws {SDKError} - If any of options are invalid\n */\n constructor({\n clientId,\n redirectUri,\n sessionDomain,\n env = 'PRE',\n log,\n window = globalWindow(),\n callbackBeforeRedirect = () => {},\n }: IdentityOptions) {\n assert(isNonEmptyString(clientId), 'clientId parameter is required');\n assert(isObject(window), 'The reference to window is missing');\n assert(!redirectUri || isUrl(redirectUri), 'redirectUri parameter is invalid');\n assert(\n isNonEmptyString(sessionDomain) && isUrl(sessionDomain),\n 'sessionDomain parameter is not a valid URL',\n );\n assert(isStr(env), `env parameter is invalid: ${env}`);\n\n spidTalk.emulate(window);\n this.window = window;\n this.clientId = clientId;\n this.redirectUri = redirectUri;\n this.env = env;\n this.log = log;\n this.callbackBeforeRedirect = callbackBeforeRedirect;\n\n this.sessionStorageCache = new Cache(() => this.window && this.window.sessionStorage);\n this.localStorageCache = new Cache(() => this.window && this.window.localStorage);\n // Internal hack: set to false to always refresh from hassession\n this.enableSessionCaching = true;\n\n this.session = {};\n\n const accountClientParams = { client_id: this.clientId, redirect_uri: this.redirectUri };\n const clientSdrn = buildClientSdrn(this.env, this.clientId);\n\n this.spid = createAccountRestClient({\n serverUrl: urlMapper(env, ENDPOINTS.SPiD),\n log: this.log,\n defaultParams: accountClientParams,\n });\n this.oauthService = createAccountRestClient({\n serverUrl: urlMapper(env, ENDPOINTS.SPiD),\n log: this.log,\n defaultParams: accountClientParams,\n });\n this.bffService = createAccountRestClient({\n serverUrl: urlMapper(env, ENDPOINTS.BFF),\n log: this.log,\n defaultParams: accountClientParams,\n });\n this.sessionService = createAccountRestClient({\n serverUrl: sessionDomain,\n log: this.log,\n defaultParams: {\n client_sdrn: clientSdrn,\n redirect_uri: this.redirectUri,\n sdk_version: version,\n },\n });\n this.globalSessionService = createAccountRestClient({\n serverUrl: urlMapper(env, ENDPOINTS.SESSION_SERVICE),\n log: this.log,\n defaultParams: { client_sdrn: clientSdrn, sdk_version: version },\n });\n this.usedSessionServiceGetSessionEndpoint =\n this.sessionService.url.pathname && this.sessionService.url.pathname.length <= 1\n ? 'v2/session'\n : 'session';\n\n this._unblockSessionCall();\n }\n\n addEventListener(type: AccountEventName, listener: EventListener): void {\n this.eventTarget.addEventListener(type, listener);\n }\n\n removeEventListener(type: AccountEventName, listener: EventListener): void {\n this.eventTarget.removeEventListener(type, listener);\n }\n\n /**\n * Read tabId from session storage\n * @private\n */\n _getTabId(): number | undefined {\n if (this.enableSessionCaching) {\n const tabId = this.sessionStorageCache.get(TAB_ID_KEY);\n if (typeof tabId !== 'number') {\n this.sessionStorageCache.set(TAB_ID_KEY, TAB_ID, TAB_ID_TTL);\n return TAB_ID;\n }\n\n return tabId;\n }\n }\n\n /**\n * Checks if getting session is blocked\n * @private\n *\n */\n _isSessionCallBlocked(): boolean {\n return Boolean(this.localStorageCache.get(SESSION_CALL_BLOCKED_CACHE_KEY));\n }\n\n /**\n * Block calls to get session\n * @private\n *\n */\n _blockSessionCall(): void {\n const SESSION_CALL_BLOCKED = true;\n\n this.localStorageCache.set(\n SESSION_CALL_BLOCKED_CACHE_KEY,\n SESSION_CALL_BLOCKED,\n SESSION_CALL_BLOCKED_TTL,\n );\n }\n\n /**\n * Unblocks calls to get session\n * @private\n *\n */\n _unblockSessionCall(): void {\n this.localStorageCache.delete(SESSION_CALL_BLOCKED_CACHE_KEY);\n }\n\n /**\n * Close this.popup if it exists and is open\n * @private\n */\n _closePopup(): void {\n if (this.popup) {\n if (!this.popup.closed) {\n this.popup.close();\n }\n this.popup = null;\n }\n }\n\n /**\n * Set the Varnish cookie (`SP_ID`) when hasSession() is called. Note that most browsers require\n * that you are on a \"real domain\" for this to work — so, **not** `localhost`\n * @param options\n * @param options.expiresIn Override this to set number of seconds before the varnish\n * cookie expires. The default is to use the same time that hasSession responses are cached for\n * @param options.domain Override cookie domain. E.g. «vg.no» instead of «www.vg.no»\n */\n enableVarnishCookie(options: VarnishCookieOptions): void {\n if (typeof options !== 'object') {\n throw new SDKError('VarnishCookieOptions must be an object');\n }\n\n const { expiresIn = 0, domain } = options;\n\n assert(Number.isInteger(expiresIn), `'expiresIn' must be an integer`);\n assert(expiresIn >= 0, `'expiresIn' cannot be negative`);\n this.setVarnishCookie = true;\n this.varnishExpiresIn = expiresIn;\n this.varnishCookieDomain = domain;\n }\n\n /**\n * Set the Varnish cookie if configured\n * @private\n * @param sessionData\n */\n _maybeSetVarnishCookie(sessionData: object): void {\n if (!this.setVarnishCookie || !isSessionSuccessResponse(sessionData)) {\n return;\n }\n const date = new Date();\n const validExpires =\n this.varnishExpiresIn ||\n (typeof sessionData.expiresIn === 'number' && sessionData.expiresIn > 0);\n if (validExpires) {\n const expires = this.varnishExpiresIn || sessionData.expiresIn || 0;\n date.setTime(date.getTime() + expires * 1000);\n } else {\n date.setTime(0);\n }\n\n // If the domain is missing or of the wrong type, we'll use document.domain\n const domain =\n this.varnishCookieDomain ||\n (typeof sessionData.baseDomain === 'string'\n ? sessionData.baseDomain\n : this.window.location.hostname) ||\n '';\n\n const cookie = [\n `SP_ID=${sessionData.sp_id}`,\n `expires=${date.toUTCString()}`,\n `path=/`,\n `domain=.${domain}`,\n ].join('; ');\n document.cookie = cookie;\n }\n\n /**\n * Clear the Varnish cookie if configured\n * @private\n */\n _maybeClearVarnishCookie(): void {\n if (this.setVarnishCookie) {\n this._clearVarnishCookie();\n }\n }\n\n /**\n * Clear the Varnish cookie\n * @private\n */\n _clearVarnishCookie(): void {\n const baseDomain =\n this.session &&\n isSessionSuccessResponse(this.session) &&\n typeof this.session.baseDomain === 'string'\n ? this.session.baseDomain\n : this.window.location.hostname;\n\n const domain = this.varnishCookieDomain || baseDomain || '';\n\n document.cookie = `SP_ID=nothing; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;\n }\n\n /**\n * @summary Queries the hassession endpoint and returns information about the status of the user\n * @remarks When we send a request to this endpoint, cookies sent along with the request\n * determines the status of the user.\n * @throws {SDKError} - If the call to the hasSession service fails in any way (this will happen\n * if, say, the user is not logged in)\n */\n hasSession(): Promise<SessionResponse> {\n const isSessionCallBlocked = this._isSessionCallBlocked();\n\n if (isSessionCallBlocked) {\n const sessionData = normalizeSessionResponse(this.session);\n return Promise.resolve(isRedirectSessionPayload(sessionData) ? {} : sessionData);\n }\n\n if (this.hasSessionInProgress) {\n return this.hasSessionInProgress;\n }\n\n const _postProcess = (sessionData: SessionObjectResponse): SessionObjectResponse => {\n if (isSessionFailureResponse(sessionData)) {\n const errorObject = isObject(sessionData.error)\n ? sessionData.error\n : { description: String(sessionData.error) };\n throw new SDKError('HasSession failed', errorObject);\n }\n this._maybeSetVarnishCookie(sessionData);\n this.session = sessionData;\n return sessionData;\n };\n\n const _getCachedSession = (): NormalizedSessionPayload | null => {\n const cachedSession = this.sessionStorageCache.get(HAS_SESSION_CACHE_KEY);\n return cachedSession ? normalizeSessionResponse(cachedSession) : null;\n };\n\n const _getSession = async (): Promise<SessionResponse> => {\n if (this.enableSessionCaching) {\n // Try to resolve from cache (it has a TTL)\n const cachedSession = _getCachedSession();\n if (cachedSession) {\n if (isRedirectSessionPayload(cachedSession)) {\n return {};\n }\n return _postProcess(cachedSession);\n }\n }\n let sessionData: NormalizedSessionPayload | null = null;\n try {\n sessionData = await this.sessionService.get(\n this.usedSessionServiceGetSessionEndpoint,\n { tabId: this._getTabId() },\n normalizeSessionResponse,\n );\n } catch (err: unknown) {\n const cacheableError = isObject(err) ? err : undefined;\n if (cacheableError?.code === 400 && this.enableSessionCaching) {\n const errorExpiresIn =\n typeof cacheableError.expiresIn === 'number'\n ? cacheableError.expiresIn\n : 300;\n const expiresIn = 1000 * errorExpiresIn;\n this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, { error: err }, expiresIn);\n } else if (\n cacheableError &&\n typeof cacheableError.code === 'number' &&\n cacheableError.code >= 500 &&\n cacheableError.code < 600 &&\n this.enableSessionCaching\n ) {\n // Temporary fix: 30 seconds cache to limit number of calls when service is unavailable\n this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, { error: err }, 30 * 1000);\n }\n throw err;\n }\n\n if (sessionData) {\n // for expiring session and safari browser do full page redirect to gain new session\n if (isRedirectSessionPayload(sessionData)) {\n this._blockSessionCall();\n\n await this.callbackBeforeRedirect();\n\n const redirectUrl = this.sessionService.makeUrl(sessionData.redirectURL, {\n tabId: this._getTabId(),\n });\n return redirectUrl;\n }\n\n if (this.enableSessionCaching) {\n const expiresIn =\n 1000 *\n (isSessionSuccessResponse(sessionData)\n ? sessionData.expiresIn || 300\n : 300);\n this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, sessionData, expiresIn);\n }\n }\n\n return _postProcess(sessionData ?? {});\n };\n this.hasSessionInProgress = _getSession().then(\n (sessionData) => {\n this.hasSessionInProgress = false;\n if (typeof sessionData === 'string') {\n this.window.location.href = sessionData;\n }\n return sessionData;\n },\n (err) => {\n this.hasSessionInProgress = false;\n throw new SDKError('HasSession failed', err);\n },\n );\n\n return this.hasSessionInProgress;\n }\n\n /**\n * @summary Allows the client app to check if the user is logged in to Schibsted account\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n */\n async isLoggedIn(): Promise<boolean> {\n try {\n const data = await this.hasSession();\n return isSessionSuccessResponse(data);\n } catch (_) {\n return false;\n }\n }\n\n /**\n * Enables or disables caching for subsequent session lookups.\n *\n * Changing this setting does not remove an existing cached session. Use\n * {@link Identity#clearCachedUserSession} to clear the cache explicitly.\n */\n setSessionCachingEnabled(enabled: boolean): void {\n this.enableSessionCaching = enabled;\n }\n\n /**\n * Removes the cached user session.\n */\n clearCachedUserSession(): void {\n this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);\n }\n\n /**\n * @summary Allows the caller to check if the current user is connected to the client_id in\n * Schibsted account. Being connected means that the user has agreed for their account to be\n * used by your web app and have accepted the required terms\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @summary Check if the user is connected to the client_id\n */\n async isConnected(): Promise<boolean> {\n try {\n return isConnectedSessionResponse(await this.hasSession());\n } catch (_) {\n return false;\n }\n }\n\n /**\n * @summary Returns information about the user\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @throws {SDKError} If the user isn't connected to the merchant\n * @throws {SDKError} If we couldn't get the user\n */\n async getUser(): Promise<ConnectedSessionResponse> {\n const user = await this.hasSession();\n if (!isConnectedSessionResponse(user)) {\n throw new SDKError('The user is not connected to this merchant');\n }\n return cloneDeep(user);\n }\n /**\n * @summary\n * In Schibsted account, there are multiple ways of identifying a user; the `userId` or `uuid`.\n * There are reasons for them all to exist. The `userId` is a numeric identifier, but\n * since Schibsted account is deployed separately in Norway and Sweden, there are a lot of\n * duplicates. The `userId` was introduced early, so many sites still need to use them for\n * legacy reasons. The `uuid` is universally unique, and so — if we could disregard a lot of\n * Schibsted components depending on the numeric `userId` — it would be a good identifier to use\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @throws {SDKError} If the user isn't connected to the merchant\n * @return The `userId` field (not to be confused with the `uuid`)\n */\n async getUserId(): Promise<string> {\n const user = await this.hasSession();\n if (isConnectedSessionWithUserIdResponse(user)) {\n return String(user.userId);\n }\n throw new SDKError('The user is not connected to this merchant');\n }\n\n /**\n * @summary Enables brands to programmatically get the current the SDRN based on the user's session.\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @throws {SDKError} If the SDRN is missing in user session object.\n */\n async getUserSDRN(): Promise<string> {\n const user = await this.hasSession();\n if (isSessionSuccessResponse(user) && user.sdrn) {\n return user.sdrn;\n }\n throw new SDKError('Failed to get SDRN from user session');\n }\n\n /**\n * @summary In Schibsted account, there are two ways of identifying a user; the `userId` and the\n * `uuid`. There are reasons for them both existing. The `userId` is a numeric identifier, but\n * since Schibsted account is deployed separately in Norway and Sweden, there are a lot of\n * duplicates. The `userId` was introduced early, so many sites still need to use them for\n * legacy reasons. The `uuid` is universally unique, and so — if we could disregard a lot of\n * Schibsted components depending on the numeric `userId` — it would be a good identifier to use\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @throws {SDKError} If the user isn't connected to the merchant\n * @return The `uuid` field (not to be confused with the `userId`)\n */\n async getUserUuid(): Promise<string> {\n const user = await this.hasSession();\n if (isSessionSuccessResponse(user) && user.uuid && user.result) {\n return user.uuid;\n }\n throw new SDKError('The user is not connected to this merchant');\n }\n\n /**\n * @summary Get basic information about any user currently logged-in to their Schibsted account\n * in this browser. Can be used to provide context in a continue-as prompt.\n * @remarks This function relies on the global Schibsted account user session cookie, which\n * is a third-party cookie and hence might be blocked by the browser (for example due to ITP in\n * Safari). So there's no guarantee any data is returned, even though a user is logged-in in\n * the current browser.\n */\n async getUserContextData(): Promise<SimplifiedLoginData | null> {\n try {\n return await this.globalSessionService.get('user-context', undefined, (value) =>\n isObject(value) && isStr(value.identifier)\n ? {\n identifier: value.identifier,\n display_text: isStr(value.display_text) ? value.display_text : '',\n client_name: isStr(value.client_name) ? value.client_name : '',\n provider_id: isStr(value.provider_id) ? value.provider_id : undefined,\n }\n : null,\n );\n } catch (_) {\n return null;\n }\n }\n\n /**\n * If a popup is desired, this function needs to be called in response to a user event (like\n * click or tap) in order to work correctly. Otherwise the popup will be blocked by the\n * browser's popup blockers and has to be explicitly authorized to be shown.\n * @summary Perform a login, either using a full-page redirect or a popup\n * @see https://tools.ietf.org/html/rfc6749#section-4.1.1\n *\n * @param options\n * @param options.state\n * @param options.acrValues\n * @param options.scope\n * @param options.redirectUri\n * @param options.preferPopup\n * @param options.loginHint\n * @param options.tag\n * @param options.teaser\n * @param options.maxAge\n * @param options.locale\n * @param options.oneStepLogin\n * @param options.prompt\n * @param options.xDomainId\n * @param options.xEnvironmentId\n * @param options.originCampaign\n * @fires Identity#login\n * @return - Reference to popup window if created (or `null` otherwise)\n */\n login({\n state,\n acrValues,\n scope = 'openid',\n redirectUri = this.redirectUri,\n preferPopup = false,\n loginHint = '',\n tag = '',\n teaser = '',\n maxAge = '',\n locale,\n oneStepLogin = false,\n prompt = 'select_account',\n xDomainId = '',\n xEnvironmentId = '',\n originCampaign = '',\n }: LoginOptions): Window | null {\n this._closePopup();\n this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);\n const url = this.loginUrl({\n state,\n acrValues,\n scope,\n redirectUri,\n loginHint,\n tag,\n teaser,\n maxAge,\n locale,\n oneStepLogin,\n prompt,\n xDomainId,\n xEnvironmentId,\n originCampaign,\n });\n\n if (preferPopup) {\n this.popup = popup.open(this.window, url, 'Schibsted account', {\n width: 360,\n height: 570,\n });\n\n if (this.popup) {\n this.eventTarget.dispatchEvent(\n new CustomEvent('login', {\n detail: { url, method: 'popup' },\n }),\n );\n\n return this.popup;\n }\n }\n\n this.eventTarget.dispatchEvent(\n new CustomEvent('login', {\n detail: { url, method: 'default' },\n }),\n );\n this.window.location.href = url;\n\n return null;\n }\n\n /**\n * @summary Retrieve the sp_id (Varnish ID)\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @return - The sp_id string or null (if the server didn't return it)\n */\n async getSpId(): Promise<string | null> {\n try {\n const user = await this.hasSession();\n if (isSessionSuccessResponse(user)) {\n return user.sp_id || null;\n }\n const spId = isObject(user) && 'sp_id' in user ? user.sp_id : undefined;\n return isStr(spId) ? spId : null;\n } catch (_) {\n return null;\n }\n }\n\n /**\n * @summary Logs the user out from the Identity platform\n * @param redirectUri - Where to redirect the browser after logging out of Schibsted account\n * @fires Identity#logout\n */\n logout(redirectUri: string = this.redirectUri): void {\n this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);\n this._maybeClearVarnishCookie();\n const url = this.logoutUrl(redirectUri);\n this.eventTarget.dispatchEvent(\n new CustomEvent('logout', {\n detail: { url },\n }),\n );\n this.window.location.href = url;\n }\n\n /**\n * Generates the link to the new login page that'll be used in the popup or redirect flow\n * @param options\n * @param options.state\n * @param options.acrValues\n * @param options.scope\n * @param options.redirectUri\n * @param options.loginHint\n * @param options.tag\n * @param options.teaser\n * @param options.maxAge\n * @param options.locale\n * @param options.oneStepLogin\n * @param options.prompt\n * @param options.xDomainId\n * @param options.xEnvironmentId\n * @param options.originCampaign\n * @return - The url\n */\n loginUrl({\n state,\n acrValues = '',\n scope = 'openid',\n redirectUri = this.redirectUri,\n loginHint = '',\n tag = '',\n teaser = '',\n maxAge = '',\n locale,\n oneStepLogin = false,\n prompt = 'select_account',\n xDomainId = '',\n xEnvironmentId = '',\n originCampaign = '',\n }: LoginOptions): string {\n const isValidAcrValue = (acrValue: string) =>\n isStrIn(\n acrValue,\n ['password', 'otp', 'sms', 'eid-dk', 'eid-no', 'eid-se', 'eid-fi', 'eid'],\n true,\n );\n assert(\n !acrValues ||\n isStrIn(acrValues, ['', 'otp-email'], true) ||\n acrValues.split(' ').every(isValidAcrValue),\n `The acrValues parameter is not acceptable: ${acrValues}`,\n );\n assert(\n isUrl(redirectUri),\n `loginUrl(): redirectUri must be a valid url but is ${redirectUri}`,\n );\n assert(\n isNonEmptyString(state),\n `the state parameter should be a non empty string but it is ${state}`,\n );\n\n return this.oauthService.makeUrl('oauth/authorize', {\n response_type: 'code',\n redirect_uri: redirectUri,\n scope,\n state,\n acr_values: acrValues,\n login_hint: loginHint,\n tag,\n teaser,\n max_age: maxAge,\n locale,\n one_step_login: oneStepLogin || '',\n prompt: acrValues ? '' : prompt,\n x_domain_id: xDomainId,\n x_env_id: xEnvironmentId,\n utm_campaign: originCampaign,\n });\n }\n\n /**\n * The url for logging the user out\n * @param redirectUri\n * @return url\n */\n logoutUrl(redirectUri: string = this.redirectUri): string {\n assert(isUrl(redirectUri), `logoutUrl(): redirectUri is invalid`);\n const params = { redirect_uri: redirectUri };\n return this.sessionService.makeUrl('logout', params);\n }\n\n /**\n * The account summary page url\n * @param redirectUri\n */\n accountUrl(redirectUri: string = this.redirectUri): string {\n return this.spid.makeUrl('profile-pages', {\n response_type: 'code',\n redirect_uri: redirectUri,\n });\n }\n\n /**\n * Function responsible for loading and displaying simplified login widget. How often\n * widget will be display is up to you. Preferred way would be to show it once per user,\n * and store that info in localStorage. Widget will be display only if user is logged in to SSO.\n *\n * @param loginParams - the same as `options` param for login function. Login will be called on user\n * continue action. `state` might be string or async function.\n * @param options - additional configuration of Simplified Login Widget\n * @fires Identity#simplifiedLoginOpened\n * @fires Identity#simplifiedLoginCancelled\n * @throws {SDKError} - If user context data is missing or the widget script cannot be loaded\n * @return - will resolve to true if widget will be displayed\n */\n async showSimplifiedLoginWidget(\n loginParams: SimplifiedLoginWidgetLoginOptions,\n options?: SimplifiedLoginWidgetOptions,\n ): Promise<boolean> {\n // getUserContextData doesn't throw exception\n const userData = await this.getUserContextData();\n\n const queryParams: Record<string, string> = { client_id: this.clientId };\n if (options && options.encoding) {\n queryParams.encoding = options.encoding;\n }\n const widgetUrl = this.bffService.makeUrl('simplified-login-widget', queryParams, false);\n\n const prepareLoginParams = async (\n loginParams: SimplifiedLoginWidgetLoginOptions,\n ): Promise<LoginOptions> => {\n const state =\n typeof loginParams.state === 'function'\n ? await loginParams.state()\n : loginParams.state;\n\n return {\n ...loginParams,\n state,\n };\n };\n\n return new Promise<boolean>((resolve, reject) => {\n if (!userData?.display_text || !userData.identifier) {\n reject(new SDKError('Missing user data'));\n return;\n }\n\n const initialParams: SimplifiedLoginWidgetInitialParams = {\n displayText: userData.display_text,\n env: this.env,\n clientName: userData.client_name || '',\n clientId: this.clientId,\n providerId: userData.provider_id,\n windowWidth: () => window.innerWidth,\n windowOnResize: (f: () => void) => {\n window.onresize = f;\n },\n };\n\n if (options && options.locale) {\n initialParams.locale = options.locale;\n }\n\n const loginHandler = async () => {\n this.login(\n Object.assign(await prepareLoginParams(loginParams), {\n loginHint: userData.identifier,\n }) as LoginOptions,\n );\n };\n\n const loginNotYouHandler = async () => {\n this.login(\n Object.assign(await prepareLoginParams(loginParams), {\n loginHint: userData.identifier,\n prompt: 'login',\n }) as LoginOptions,\n );\n };\n\n const initHandler = () => {\n /**\n * Emitted when the simplified login widget is displayed on the screen\n * @event Identity#simplifiedLoginOpened\n */\n this.eventTarget.dispatchEvent(new Event('simplifiedLoginOpened'));\n };\n\n const cancelLoginHandler = () => {\n this.eventTarget.dispatchEvent(new Event('simplifiedLoginCancelled'));\n };\n\n if (hasOpenSimplifiedLoginWidget(window)) {\n window.openSimplifiedLoginWidget(\n initialParams,\n loginHandler,\n loginNotYouHandler,\n initHandler,\n cancelLoginHandler,\n );\n return resolve(true);\n }\n\n const simplifiedLoginWidget = document.createElement('script');\n simplifiedLoginWidget.type = 'text/javascript';\n simplifiedLoginWidget.src = widgetUrl;\n simplifiedLoginWidget.onload = () => {\n if (!hasOpenSimplifiedLoginWidget(window)) {\n reject(new SDKError('Error when loading simplified login widget content'));\n return;\n }\n window.openSimplifiedLoginWidget(\n initialParams,\n loginHandler,\n loginNotYouHandler,\n initHandler,\n cancelLoginHandler,\n );\n resolve(true);\n };\n simplifiedLoginWidget.onerror = () => {\n reject(new SDKError('Error when loading simplified login widget content'));\n };\n document.getElementsByTagName('body')[0].appendChild(simplifiedLoginWidget);\n });\n }\n}\n\nexport default Identity;\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport SDKError from './sdk-error.js';\nimport type { HasAccessResult } from './types/monetization.js';\nimport { isObject, isStr } from './validate.js';\n\nexport function parseHasAccessResult(value: unknown): HasAccessResult {\n if (!isObject(value)) {\n throw new SDKError('Invalid hasAccess response');\n }\n\n const { entitled, ttl, allowedFeatures, userId, uuid, sig } = value;\n\n if (\n typeof entitled !== 'boolean' ||\n typeof ttl !== 'number' ||\n !Array.isArray(allowedFeatures) ||\n (typeof userId !== 'number' && typeof userId !== 'string') ||\n !isStr(uuid) ||\n !isStr(sig)\n ) {\n throw new SDKError('Invalid hasAccess response');\n }\n\n return {\n entitled,\n ttl,\n allowedFeatures: allowedFeatures.filter(isStr),\n userId,\n uuid,\n sig,\n };\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport Cache from './cache.js';\nimport { parseHasAccessResult } from './has-access-response.js';\nimport type RESTClient from './rest-client.js';\nimport { buildClientSdrn, createAccountRestClient } from './rest-clients.js';\nimport SDKError from './sdk-error.js';\nimport * as spidTalk from './spid-talk.js';\nimport type { HasAccessResult, MonetizationOptions } from './types/monetization.js';\nimport type { SessionUserId } from './types/session.js';\nimport { assert, isNonEmptyString, isStr, isUrl } from './validate.js';\nimport version from './version.js';\n\nconst globalWindow = () => window;\n\n/**\n * Provides features related to monetization\n */\nexport class Monetization {\n private readonly cache: Cache;\n private readonly sessionService?: RESTClient;\n private readonly pendingHasAccessRequests: Record<string, Promise<HasAccessResult>>;\n\n /**\n * @param options - Monetization configuration\n * @throws {SDKError} - If any of options are invalid\n */\n constructor({\n clientId,\n redirectUri,\n env = 'PRE',\n sessionDomain,\n window = globalWindow(),\n }: MonetizationOptions) {\n spidTalk.emulate(window);\n assert(isNonEmptyString(clientId), 'clientId parameter is required');\n assert(isStr(env), `env parameter is invalid: ${env}`);\n const clientSdrn = buildClientSdrn(env, clientId);\n\n this.cache = new Cache(() => window && window.sessionStorage);\n this.pendingHasAccessRequests = {};\n\n if (sessionDomain) {\n assert(isUrl(sessionDomain), 'sessionDomain parameter is not a valid URL');\n this.sessionService = createAccountRestClient({\n serverUrl: sessionDomain,\n defaultParams: {\n client_sdrn: clientSdrn,\n redirect_uri: redirectUri,\n sdk_version: version,\n },\n });\n }\n }\n\n /**\n * Checks if the user has access to a set of products or features.\n * @param productIds - which products/features to check\n * @param userId - id of currently logged in user\n * @throws {SDKError} - If the input is incorrect, or a network call fails in any way\n * (this will happen if, say, the user is not logged in)\n * @returns The data object returned from Schibsted account (or `null` if the user\n * doesn't have access to any of the given products/features)\n */\n async hasAccess(productIds: string[], userId: SessionUserId): Promise<HasAccessResult | null> {\n if (!this.sessionService) {\n throw new SDKError(`hasAccess can only be called if 'sessionDomain' is configured`);\n }\n if (!userId) {\n throw new SDKError(`'userId' must be specified`);\n }\n if (!Array.isArray(productIds)) {\n throw new SDKError(`'productIds' must be an array`);\n }\n\n const sortedIds = [...productIds].sort();\n const cacheKey = this.accessCacheKey(sortedIds, userId);\n let data = this.cache.get(cacheKey) as HasAccessResult | null;\n if (!data) {\n if (!this.pendingHasAccessRequests[cacheKey]) {\n this.pendingHasAccessRequests[cacheKey] = this.sessionService.get(\n `/hasAccess/${sortedIds.join(',')}`,\n undefined,\n parseHasAccessResult,\n );\n }\n const promise = this.pendingHasAccessRequests[cacheKey];\n try {\n data = await promise;\n const expiresSeconds = data.ttl;\n this.cache.set(cacheKey, data, expiresSeconds * 1000);\n } finally {\n if (this.pendingHasAccessRequests[cacheKey] === promise) {\n delete this.pendingHasAccessRequests[cacheKey];\n }\n }\n }\n\n if (!data.entitled) {\n return null;\n }\n\n return data;\n }\n\n /**\n * Removes the cached access result.\n * @param productIds - which products/features to check\n * @param userId - id of currently logged in user\n */\n clearCachedAccessResult(productIds: string[], userId: SessionUserId): void {\n this.cache.delete(this.accessCacheKey(productIds, userId));\n }\n\n /**\n * Compute \"has access\" cache key for the given product ids and user id.\n * @private\n * @param productIds - which products/features to check\n * @param userId - id of currently logged in user\n */\n private accessCacheKey(productIds: string[], userId: SessionUserId): string {\n return `prd_${[...productIds].sort()}_${userId}`;\n }\n}\n\nexport default Monetization;\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nexport const resolveBrowserWindow = (providedWindow?: Window): Window | undefined => {\n if (providedWindow) {\n return providedWindow;\n }\n\n return typeof window === 'undefined' ? undefined : window;\n};\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport Identity from './identity.js';\nimport Monetization from './monetization.js';\nimport { resolveBrowserWindow } from './resolve-browser-window.js';\nimport SDKError from './sdk-error.js';\nimport type { AccountConfig, AccountEventListener, AccountEventName } from './types/account.js';\nimport type {\n LoginOptions,\n SimplifiedLoginData,\n SimplifiedLoginWidgetLoginOptions,\n SimplifiedLoginWidgetOptions,\n} from './types/login.js';\nimport type { HasAccessResult } from './types/monetization.js';\nimport type { ConnectedSessionResponse, SessionResponse, SessionUserId } from './types/session.js';\n\n/**\n * Unified client-side interface for a configured Schibsted Account integration.\n *\n * Create an instance with `createAccountSdk()` unless you explicitly need to construct it\n * yourself. The instance coordinates identity, login, session, and access-check features for one\n * configured client.\n *\n * @group Core API\n */\nexport class Account {\n #identity: Identity;\n #monetization: Monetization;\n\n constructor(config: AccountConfig) {\n const browserWindow = resolveBrowserWindow(config.window);\n\n if (!browserWindow) {\n throw new SDKError('Schibsted Account SDK is not available in this browser context');\n }\n\n if (browserWindow.schAccount) {\n throw new SDKError('Schibsted Account SDK has already been initialized');\n }\n\n const { log, callbackBeforeRedirect, varnish } = config;\n const sharedConfig = {\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n sessionDomain: config.sessionDomain,\n env: config.env,\n window: browserWindow,\n };\n\n this.#identity = new Identity({\n ...sharedConfig,\n log,\n callbackBeforeRedirect,\n });\n\n if (varnish) {\n if (typeof varnish !== 'object' || Array.isArray(varnish)) {\n throw new SDKError('Account varnish config must be an object');\n }\n this.#identity.enableVarnishCookie(varnish);\n }\n\n this.#monetization = new Monetization(sharedConfig);\n\n browserWindow.schAccount = this;\n browserWindow.dispatchEvent(\n new CustomEvent('schAccount:ready', { detail: { instance: this } }),\n );\n }\n\n /**\n * Queries Session Service and returns the current browser session state.\n *\n * This call may trigger a full-page session refresh redirect. Configure\n * `callbackBeforeRedirect` if your app needs to persist state before that navigation.\n *\n * @throws {SDKError} If the Session Service call fails.\n */\n hasSession(): Promise<SessionResponse> {\n return this.#identity.hasSession();\n }\n\n /**\n * Checks whether the browser currently has a Schibsted Account session.\n *\n * Returns `false` instead of throwing when the session lookup fails.\n */\n isLoggedIn(): Promise<boolean> {\n return this.#identity.isLoggedIn();\n }\n\n /**\n * Checks whether the current user is connected to the configured client.\n *\n * A user can be logged in to Schibsted Account without being connected to your client, for\n * example before accepting required terms.\n */\n isConnected(): Promise<boolean> {\n return this.#identity.isConnected();\n }\n\n /**\n * Returns the connected user session data.\n *\n * @throws {SDKError} If the user is not connected to the configured client.\n */\n getUser(): Promise<ConnectedSessionResponse> {\n return this.#identity.getUser();\n }\n\n /**\n * Returns the realm-specific Schibsted Account user id as a string.\n *\n * Use `getUserUuid()` when you need the globally unique user id.\n *\n * @throws {SDKError} If the user is not connected to the configured client.\n */\n getUserId(): Promise<string> {\n return this.#identity.getUserId();\n }\n\n /**\n * Returns the globally unique user id from the current session.\n *\n * @throws {SDKError} If the user is not connected to the configured client.\n */\n getUserUuid(): Promise<string> {\n return this.#identity.getUserUuid();\n }\n\n /**\n * Returns the user SDRN from the current session.\n *\n * @throws {SDKError} If the SDRN is missing from the session response.\n */\n getUserSDRN(): Promise<string> {\n return this.#identity.getUserSDRN();\n }\n\n /**\n * Returns minimal user context for simplified login prompts.\n *\n * Returns `null` if the global account session cannot be read.\n */\n getUserContextData(): Promise<SimplifiedLoginData | null> {\n return this.#identity.getUserContextData();\n }\n\n /**\n * Returns the Varnish `sp_id` value from the current session when present.\n */\n getSpId(): Promise<string | null> {\n return this.#identity.getSpId();\n }\n\n /**\n * Starts the login flow with either a full-page redirect or a popup.\n *\n * Call this from a user gesture when `preferPopup` is enabled, otherwise browser popup blockers\n * may block the popup and the SDK will fall back to redirect navigation.\n *\n * @param options - Login URL parameters.\n * @returns A popup window reference when a popup is opened; otherwise `null`.\n */\n login(options: LoginOptions): Window | null {\n return this.#identity.login(options);\n }\n\n /**\n * Logs the user out from the brand Session Service session and redirects the browser.\n *\n * @param redirectUri - Where Session Service should redirect the browser after logout.\n */\n logout(redirectUri?: string): void {\n this.#identity.logout(redirectUri);\n }\n\n /**\n * Builds the login URL without navigating the browser.\n *\n * @param options - Login URL parameters.\n */\n loginUrl(options: LoginOptions): string {\n return this.#identity.loginUrl(options);\n }\n\n /**\n * Builds the logout URL without navigating the browser.\n *\n * @param redirectUri - Where Session Service should redirect the browser after logout.\n */\n logoutUrl(redirectUri?: string): string {\n return this.#identity.logoutUrl(redirectUri);\n }\n\n /**\n * Builds the Schibsted Account profile page URL.\n *\n * @param redirectUri - Where the account page should redirect the browser afterwards.\n */\n accountUrl(redirectUri?: string): string {\n return this.#identity.accountUrl(redirectUri);\n }\n\n /**\n * Loads and displays the simplified login widget when user context is available.\n *\n * Your application decides how often to call this method. The `state` field in `loginParams`\n * may be a string or a function that resolves to a string.\n * Widget open and cancel events can be observed with `on()`.\n *\n * @returns `true` when the widget was displayed.\n * @throws {SDKError} If user context data is missing or the widget script cannot be loaded.\n */\n showSimplifiedLoginWidget(\n loginParams: SimplifiedLoginWidgetLoginOptions,\n options?: SimplifiedLoginWidgetOptions,\n ): Promise<boolean> {\n return this.#identity.showSimplifiedLoginWidget(loginParams, options);\n }\n\n /**\n * Enables or disables caching for subsequent session lookups.\n *\n * Changing this setting does not remove an existing cached session.\n */\n setSessionCachingEnabled(enabled: boolean): void {\n this.#identity.setSessionCachingEnabled(enabled);\n }\n\n /**\n * Removes the cached Session Service user session response.\n */\n clearCachedUserSession(): void {\n this.#identity.clearCachedUserSession();\n }\n\n /**\n * Checks whether a user has access to any of the requested products or features.\n *\n * Results are cached according to the TTL returned by Session Service.\n *\n * @param productIds - Product or feature ids to check.\n * @param userId - Current user id, usually from `getUserId()`.\n * @returns Access data, or `null` when the user is not entitled.\n * @throws {SDKError} If `sessionDomain` is missing, input is invalid, or the request fails.\n */\n hasAccess(productIds: string[], userId: SessionUserId): Promise<HasAccessResult | null> {\n return this.#monetization.hasAccess(productIds, userId);\n }\n\n /**\n * Removes a cached access-check result.\n *\n * @param productIds - Product or feature ids used for the cached lookup.\n * @param userId - User id used for the cached lookup.\n */\n clearCachedAccessResult(productIds: string[], userId: SessionUserId): void {\n this.#monetization.clearCachedAccessResult(productIds, userId);\n }\n\n /**\n * Subscribes to Account events.\n *\n * Supported event names are defined by {@link AccountEventName}.\n *\n * @param event - Event name.\n * @param listener - Listener that receives an `Event` or `CustomEvent`.\n */\n on<EventName extends AccountEventName>(\n event: EventName,\n listener: AccountEventListener<EventName>,\n ): this;\n on(event: AccountEventName, listener: EventListener): this {\n this.#identity.addEventListener(event, listener);\n\n return this;\n }\n\n /**\n * Unsubscribes from Account events.\n *\n * Supported event names are defined by {@link AccountEventName}.\n *\n * @param event - Event name.\n * @param listener - Listener to remove.\n */\n off<EventName extends AccountEventName>(\n event: EventName,\n listener: AccountEventListener<EventName>,\n ): this;\n off(event: AccountEventName, listener: EventListener): this {\n this.#identity.removeEventListener(event, listener);\n\n return this;\n }\n}\n\nexport default Account;\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport { Account } from './account.js';\nimport { resolveBrowserWindow } from './resolve-browser-window.js';\nimport type { AccountConfig } from './types/account.js';\n\nconst ACCOUNT_READY_EVENT = 'schAccount:ready';\nconst GET_ACCOUNT_SDK_TIMEOUT_MS = 4000;\n\nlet pendingAccountPromise: Promise<Account> | undefined;\n\nconst createUnavailableError = (): Error =>\n new Error('Schibsted Account SDK is not available in this browser context');\n\nconst createTimeoutError = (): Error =>\n new Error(`Schibsted Account SDK was not initialized within ${GET_ACCOUNT_SDK_TIMEOUT_MS} ms`);\n\n/**\n * Creates and registers the single Account SDK instance for the current browser window.\n *\n * The created instance is stored on `window.schAccount` and the SDK emits\n * `schAccount:ready` with the instance in `event.detail.instance`.\n *\n * @param config - Client, redirect, environment, and Session Service configuration.\n * @throws {SDKError} If the SDK cannot run in the current browser context, if an Account instance\n * has already been initialized, or if configuration validation fails.\n * @group Core API\n */\nexport function createAccountSdk(config: AccountConfig): Account {\n return new Account(config);\n}\n\n/**\n * Resolves the Account SDK instance registered by `createAccountSdk()`.\n *\n * If the instance already exists, the promise resolves immediately. Otherwise it waits for\n * `schAccount:ready` and rejects if initialization does not happen within the SDK timeout.\n * @group Core API\n */\nexport function getAccountSdk(): Promise<Account> {\n const browserWindow = resolveBrowserWindow();\n\n if (!browserWindow) {\n const error = createUnavailableError();\n console.error(error.message);\n return Promise.reject(error);\n }\n\n if (browserWindow.schAccount) {\n return Promise.resolve(browserWindow.schAccount);\n }\n\n if (pendingAccountPromise) {\n return pendingAccountPromise;\n }\n\n pendingAccountPromise = new Promise<Account>((resolve, reject) => {\n let timeoutId: number | undefined;\n\n const cleanup = () => {\n browserWindow.removeEventListener(ACCOUNT_READY_EVENT, resolveRegisteredAccount);\n if (timeoutId !== undefined) {\n browserWindow.clearTimeout(timeoutId);\n }\n pendingAccountPromise = undefined;\n };\n\n const resolveRegisteredAccount = () => {\n const account = browserWindow.schAccount;\n if (!account) {\n return;\n }\n\n cleanup();\n resolve(account);\n };\n\n browserWindow.addEventListener(ACCOUNT_READY_EVENT, resolveRegisteredAccount);\n timeoutId = browserWindow.setTimeout(() => {\n const error = createTimeoutError();\n console.error(error.message);\n cleanup();\n reject(error);\n }, GET_ACCOUNT_SDK_TIMEOUT_MS);\n\n resolveRegisteredAccount();\n });\n\n return pendingAccountPromise;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["#identity","#defaultProductIds","#monetization"],"sources":["../src/sdk-error.ts","../src/cache.ts","../src/config.ts","../src/validate.ts","../src/object.ts","../src/popup.ts","../src/url.ts","../src/rest-client.ts","../src/rest-clients.ts","../src/session-response.ts","../src/spid-talk.ts","../src/types/login.ts","../src/version.ts","../src/identity.ts","../src/has-access-response.ts","../src/monetization.ts","../src/resolve-browser-window.ts","../src/account.ts","../src/account-sdk.ts"],"sourcesContent":["/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\n/*\n * Note: this module can't have any internal dependencies because it's used in ./validate which\n * in turn is used as a dependency to a lot of other modules. Doing so may create a circular\n * dependency that's hard to debug in Node.\n */\n\nconst STRINGIFY_TYPES = ['boolean', 'number', 'string'];\n\n/**\n * Custom error class thrown by all SDK methods on failure.\n *\n * All rejected promises from API calls reject with an instance of this class.\n *\n * @group Errors\n */\nexport default class SDKError extends Error {\n /** HTTP status code from the server error payload;\n * declared explicitly to allow numeric comparisons without type-casting.\n */\n code?: number;\n /**\n * Properties copied from the server error object.\n * @internal\n */\n [key: string]: unknown;\n\n /**\n * @param message - Human-readable error message\n * @param errorObject - Optional server error payload. All enumerable properties are\n * shallow-copied onto this instance.\n */\n constructor(message: string, errorObject?: Record<string, unknown>) {\n super(message);\n this.name = 'SDKError';\n\n if (errorObject) {\n try {\n Object.assign(this, errorObject);\n } catch {\n // silent\n }\n }\n }\n\n /**\n * Returns a multi-line string with the error name, message, and any other properties copied\n * from the server error payload.\n */\n toString(): string {\n const ret = `${this.name}: ${this.message}`;\n const additionalInfo = Object.keys(this)\n .filter((key) => key !== 'name' && STRINGIFY_TYPES.includes(typeof this[key]))\n .map((key) => ` ${key}: ${this[key]}`)\n .join('\\n');\n return additionalInfo ? `${ret}\\n${additionalInfo}` : ret;\n }\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport SDKError from './sdk-error.js';\n\n/**\n * Check whether we are able to use web storage\n * @param storeProvider - A function to return a WebStorage instance (either\n * `sessionStorage` or `localStorage` from a `Window` object)\n * @private\n */\nfunction webStorageWorks(storeProvider: (() => Storage) | undefined): boolean {\n if (!storeProvider) {\n return false;\n }\n try {\n const store = storeProvider();\n const randomKey = 'x-x-x-x'.replace(/x/g, () => String(Math.random()));\n const testValue = 'TEST-VALUE';\n store.setItem(randomKey, testValue);\n const val = store.getItem(randomKey);\n store.removeItem(randomKey);\n return val === testValue;\n } catch {\n return false;\n }\n}\n\n/**\n * Cache implementation used when web storage is available. Wraps a `Storage` instance.\n * @private\n */\nclass WebStorageCache {\n store: Storage;\n get: (key: string) => string | null;\n set: (key: string, value: string) => void;\n delete: (key: string) => void;\n\n /**\n * Create web storage cache object\n * @param store - A reference to either `sessionStorage` or `localStorage` from a\n * `Window` object\n */\n constructor(store: Storage) {\n this.store = store;\n this.get = (key) => this.store.getItem(key);\n this.set = (key, value) => this.store.setItem(key, value);\n this.delete = (key) => this.store.removeItem(key);\n }\n}\n\n/**\n * Cache implementation used when web storage is not available. Stores entries in an in-memory object.\n * @private\n */\nclass LiteralCache {\n store: Record<string, string>;\n get: (key: string) => string | undefined;\n set: (key: string, value: string) => void;\n delete: (key: string) => void;\n\n /**\n * Create JS object literal cache object\n */\n constructor() {\n this.store = {};\n this.get = (key) => this.store[key];\n this.set = (key, value) => {\n this.store[key] = value;\n };\n this.delete = (key) => {\n delete this.store[key];\n };\n }\n}\n\ntype CacheEntry = { expiresOn: number; value: unknown };\n\nconst maxExpiresIn = 2 ** 31 - 1;\n\n/**\n * Cache class that attempts WebStorage (session/local storage), and falls back to JS object literal\n * @private\n */\nexport default class Cache {\n cache: WebStorageCache | LiteralCache;\n type: string;\n\n /**\n * @param storeProvider - A function to return a WebStorage instance (either\n * `sessionStorage` or `localStorage` from a `Window` object)\n * @throws {SDKError} - If sessionStorage or localStorage are not accessible\n */\n constructor(storeProvider?: () => Storage) {\n if (storeProvider && webStorageWorks(storeProvider)) {\n this.cache = new WebStorageCache(storeProvider());\n this.type = 'WebStorage';\n } else {\n this.cache = new LiteralCache();\n this.type = 'ObjectLiteralStorage';\n }\n }\n\n /**\n * Get a value from cache (checks that the object has not expired)\n * @param key\n * @private\n */\n get(key: string): unknown {\n /**\n * JSON.parse safe wrapper\n * @param raw\n */\n function getObj(raw: string | null | undefined): CacheEntry | null {\n if (raw == null) {\n return null;\n }\n try {\n return JSON.parse(raw);\n } catch {\n return null;\n }\n }\n\n try {\n const raw = this.cache.get(key);\n const obj = getObj(raw);\n if (obj && Number.isInteger(obj.expiresOn) && obj.expiresOn > Date.now()) {\n return obj.value;\n }\n this.delete(key);\n return null;\n } catch (e) {\n throw new SDKError(String(e));\n }\n }\n\n /**\n * Set a cache entry\n * @param key\n * @param value\n * @param expiresIn - Value in milliseconds until the entry expires\n * @private\n */\n set(key: string, value: unknown, expiresIn = 0): void {\n if (expiresIn <= 0) {\n return;\n }\n expiresIn = Math.min(maxExpiresIn, expiresIn);\n\n try {\n const expiresOn = Math.floor(Date.now() + expiresIn);\n this.cache.set(key, JSON.stringify({ expiresOn, value }));\n setTimeout(() => this.delete(key), expiresIn);\n } catch (e) {\n throw new SDKError(String(e));\n }\n }\n\n /**\n * Delete a cache entry\n * @param key\n * @private\n */\n delete(key: string): void {\n try {\n this.cache.delete(key);\n } catch (e) {\n throw new SDKError(String(e));\n }\n }\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\n/*\n * This file declares configs that are essentially part of how the SDK works and interacts with our\n * backend servers.\n *\n * What goes here?\n * - The configurations that are likely to change over time\n * - Constants that are otherwise obscure (for example 7000 for a TIMEOUT)\n *\n * What doesn't go here?\n * - options that the users of the SDK are supposed to set or provide as a parameter to functions\n * and classes.\n */\n\n/**\n * Core configuration used by the SDK.\n * - `ENDPOINTS.SPiD` — SPiD endpoints per environment\n * - `ENDPOINTS.BFF` — Endpoints used with new GDPR-compliant web flows\n * - `ENDPOINTS.SESSION_SERVICE` — Endpoints to check global user session data\n *\n */\nconst config = {\n ENDPOINTS: {\n SPiD: {\n LOCAL: 'http://id.localhost',\n DEV: 'https://identity-dev.schibsted.com',\n PRE: 'https://identity-pre.schibsted.com',\n PRO: 'https://login.schibsted.com',\n PRO_NO: 'https://payment.schibsted.no',\n PRO_FI: 'https://login.schibsted.fi',\n PRO_DK: 'https://login.schibsted.dk',\n },\n BFF: {\n LOCAL: 'http://id.localhost/authn/',\n DEV: 'https://identity-dev.schibsted.com/authn/',\n PRE: 'https://identity-pre.schibsted.com/authn/',\n PRO: 'https://login.schibsted.com/authn/',\n PRO_NO: 'https://payment.schibsted.no/authn/',\n PRO_FI: 'https://login.schibsted.fi/authn/',\n PRO_DK: 'https://login.schibsted.dk/authn/',\n },\n SESSION_SERVICE: {\n LOCAL: 'http://session-service.id.localhost',\n DEV: 'https://session-service.identity-dev.schibsted.com',\n PRE: 'https://session-service.identity-pre.schibsted.com',\n PRO: 'https://session-service.login.schibsted.com',\n PRO_NO: 'https://session-service.payment.schibsted.no',\n PRO_FI: 'https://session-service.login.schibsted.fi',\n PRO_DK: 'https://session-service.login.schibsted.dk',\n },\n },\n NAMESPACE: {\n LOCAL: 'id.localhost',\n DEV: 'schibsted.com',\n PRE: 'schibsted.com',\n PRO: 'schibsted.com',\n PRO_NO: 'spid.no',\n PRO_FI: 'schibsted.fi',\n PRO_DK: 'schibsted.dk',\n },\n} as const;\n\nexport default config;\nexport const ENDPOINTS = config.ENDPOINTS;\nexport const NAMESPACE = config.NAMESPACE;\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport SDKError from './sdk-error.js';\n\n/*\n * This module defines a set of validation functions which are used in the rest of the SDK.\n * Why make our own validation module?\n * 1. To implement the validations that we specifically need for the SDK\n * 2. To have one less dependency\n */\n\n/**\n * A utility function that throws an SDKError if an assertion fails. It's mostly useful for\n * validating function inputs.\n *\n * Narrows `condition` for the rest of the enclosing scope (TypeScript assertion signature).\n * @param condition - The condition that we're asserting\n * @param message - The error message\n * @throws {SDKError} - If the condition is falsy it throws the appropriate error\n */\nexport function assert(condition: boolean, message = 'Assertion failed'): asserts condition {\n if (!condition) {\n throw new SDKError(message);\n }\n}\n\n/**\n * Checks if a value is a string or not\n * @param value - The value to check\n */\nexport function isStr(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n/**\n * Checks if a value is a non-empty string\n * @param value - The value to check\n */\nexport function isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\n/**\n * checks if a given value is an object (but not null)\n * @param value - The value to check\n */\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Checks if a given value is an object with at least one own key\n * @param value - The value to check\n */\nexport function isNonEmptyObj(value: unknown): value is Record<string, unknown> {\n return isObject(value) && Object.keys(value).length > 0;\n}\n\n/**\n * Checks if a given string is a valid URL\n * @param value - The string to be tested\n * @param mandatoryFields - A list of mandatory fields that should exist in the parsed\n * `URL` object\n */\nexport function isUrl(value: string, ...mandatoryFields: (keyof URL)[]): boolean {\n try {\n const parsedUrl = new URL(value);\n return mandatoryFields.every((f) => parsedUrl[f]);\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if a given value is a function\n * @param value - The value to check\n */\nexport function isFunction(value: unknown): value is (...args: unknown[]) => unknown {\n return typeof value === 'function';\n}\n\n/**\n * Checks if a string matches any of the strings in a set of possibilities\n * @param value\n * @param possibilities - An array of strings that'll be used to check the string\n * inclusion. Note that for performance reasons, we don't validate this parameter.\n * @param caseSensitive - Should the check be case sensitive\n */\nexport function isStrIn(value: string, possibilities: string[], caseSensitive = false): boolean {\n const _isSameStrCaseInsensitive = (str: string) =>\n isStr(str) && value.toUpperCase() === str.toUpperCase();\n if (!(isStr(value) && Array.isArray(possibilities))) {\n return false;\n }\n if (caseSensitive) {\n return possibilities.indexOf(value) !== -1;\n }\n return possibilities.some(_isSameStrCaseInsensitive);\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\n/**\n * @summary Some routines that work on javascript objects\n * @private\n */\n\nimport SDKError from './sdk-error.js';\nimport { assert, isNonEmptyObj, isObject } from './validate.js';\n\n/**\n * Similar to Object.assign({}, src) but only clones the keys of an object that have non-undefined\n * values.\n * Please note that the values in the rightmost parameters can overwrite the values of the earlier\n * parameters so the order of the parameters matters.\n * @example\n * cloneDefined({foo: 1, bar: 2}, {foo: 2}) // returns {foo: 2, bar: 2}\n *\n * @param sources - one or more sources. Their defined properties will override the ones\n * that came before it. For example if `source1.foo = 'bar'` and `source2.foo = 'baz'`, the\n * result will include `{ foo: 'baz' }`\n */\nexport function cloneDefined(...sources: object[]): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n if (!(sources && sources.length)) {\n throw new SDKError('No objects to clone');\n }\n sources.forEach((source) => {\n assert(isObject(source));\n if (isNonEmptyObj(source)) {\n Object.entries(source).forEach(([key, value]) => {\n if (typeof value !== 'undefined') {\n result[key] = isObject(value) ? cloneDeep(value) : value;\n }\n });\n }\n });\n return result;\n}\n\n/**\n * Deep copies an object. This is handy for immutability.\n * @param obj - An object, array or null.\n * @throws {SDKError} - if the obj is not an accepted type or is not\n * stringifiable by JSON for example if it has loops\n */\nexport function cloneDeep<T extends object | null>(obj: T): T {\n assert(typeof obj === 'object', `obj should be an object (even null) but it is ${obj}`);\n return JSON.parse(JSON.stringify(obj)) || obj;\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport { cloneDefined } from './object.js';\nimport { assert, isFunction, isObject, isUrl } from './validate.js';\n\n/**\n * Serializes an object to string.\n * @private\n * @param obj - for example {a: 'b', c: 1}\n */\nfunction serialize(obj: Record<string, unknown>): string {\n assert(isObject(obj), `Object must be an object but it is '${obj}'`);\n return Object.keys(obj)\n .map((key) => `${key}=${obj[key]}`)\n .join(',');\n}\n\nconst defaultWindowFeatures = {\n scrollbars: 'yes',\n location: 'yes',\n status: 'no',\n menubar: 'no',\n toolbar: 'no',\n resizable: 'yes',\n};\n\n/**\n * Opens a popup\n * @param parentWindow - A reference to the window that will open the popup\n * @param url - The URL that the popup will open\n * @param windowName - A name for the window\n * @param windowFeatures - Window features for the popup (default ones are usually ok)\n * @private\n */\nexport function open(\n parentWindow: Window,\n url: string,\n windowName = '',\n windowFeatures: Record<string, string | number> = {},\n): Window | null {\n assert(isObject(parentWindow), `window was supposed to be an object but it is ${parentWindow}`);\n assert(\n isObject(parentWindow.screen),\n `window should be a valid Window object but it lacks a 'screen' property`,\n );\n assert(\n isFunction(parentWindow.open),\n `window should be a valid Window object but it lacks an 'open' function`,\n );\n assert(isUrl(url), 'Invalid URL for popup');\n\n const { height, width } = parentWindow.screen;\n\n const mergedFeatures = cloneDefined(defaultWindowFeatures, windowFeatures);\n const { width: featureWidth, height: featureHeight } = mergedFeatures;\n if (\n typeof featureWidth === 'number' &&\n Number.isFinite(featureWidth) &&\n Number.isFinite(width)\n ) {\n mergedFeatures.left = (width - featureWidth) / 2;\n }\n if (\n typeof featureHeight === 'number' &&\n Number.isFinite(featureHeight) &&\n Number.isFinite(height)\n ) {\n mergedFeatures.top = (height - featureHeight) / 2;\n }\n const features = serialize(mergedFeatures);\n return parentWindow.open(url, windowName, features);\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport { assert, isNonEmptyObj, isNonEmptyString, isUrl } from './validate.js';\n\n/**\n * A simple utility function that allows looking up URLs from a dictionary\n * @param url - A url like http://example.com, or a key used for lookup\n * @param urlMap - A map of URLs like `{ DEV: 'http://dev.example.com' }`\n * @returns The resolved URL: the mapped value when `url` is a known key, otherwise `url` itself\n * @throws {SDKError} - If the url is not a string or is an empty string\n */\nexport function urlMapper(url: string, urlMap: Record<string, string>): string {\n assert(isNonEmptyString(url), `\"url\" param must be a non empty string: ${typeof url}`);\n if (isNonEmptyObj(urlMap) && isUrl(urlMap[url])) {\n return urlMap[url];\n }\n assert(isUrl(url, 'hostname'), `Bad URL given: '${url}'`);\n return url;\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport { cloneDefined } from './object.js';\nimport SDKError from './sdk-error.js';\nimport type { LogFunction } from './types/common.js';\nimport { urlMapper } from './url.js';\nimport { assert, isFunction, isNonEmptyString, isObject, isStr } from './validate.js';\n\n/**\n * Converts a series of parameters of various types to a string that's suitable for logging.\n * @private\n * @param msg - The values to format; objects are stringified to JSON\n */\nconst logString = (msg: unknown[]): string =>\n msg.map((m) => (isObject(m) ? JSON.stringify(m, null, 2) : m)).join(' ');\n\nconst logFn = (fn: LogFunction | undefined, ...msg: unknown[]): void => {\n if (fn) {\n fn(logString(msg));\n }\n};\n\n/**\n * Encode a string like URLSearchParams would do\n * @private\n * @param str - The input\n */\nfunction encode(str: string): string {\n const replace: Record<string, string> = {\n '!': '%21',\n \"'\": '%27',\n '(': '%28',\n ')': '%29',\n '~': '%7E',\n '%20': '+',\n '%00': '\\x00',\n };\n return encodeURIComponent(str).replace(/[!'()~]|%20|%00/g, (match) => replace[match]);\n}\ntype FetchFunction = (input: RequestInfo, init?: RequestInit) => Promise<Response>;\nconst globalFetch = () => window.fetch && window.fetch.bind(window);\nconst noFetch: FetchFunction = () => {\n throw new SDKError('fetch is not available in this environment');\n};\n\n/**\n * The value of a single query parameter; `undefined` entries are skipped.\n */\ntype QueryValue = string | number | boolean | undefined;\n\n/**\n * Query parameters appended to a request URL.\n */\ntype QueryParams = Record<string, QueryValue>;\n\n/**\n * HTTP method used for a request.\n */\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n\ntype JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };\n\ntype ResponseParser<T> = (value: JsonValue) => T;\n\ntype RESTRequestOptions<T = JsonValue> = {\n method: HttpMethod;\n pathname: string;\n data?: QueryParams;\n headers?: Record<string, string>;\n useDefaultParams?: boolean;\n fetchOptions?: RequestInit;\n parseResponse?: ResponseParser<T>;\n};\n\n/**\n * This class can be used for creating a wrapper around a server and all its endpoints.\n * Its functionality is extended by {@link JSONPClient}\n * Creates a client to a REST server. While useful stand-alone, it's also used for some other\n * types of client that change some functionalities.\n * @throws {SDKError} - If any of options are invalid\n * @summary The simplest way to communicate to a REST endpoint without any\n * special authentication\n * @private\n */\nexport class RESTClient {\n url: URL;\n defaultParams: QueryParams;\n log?: LogFunction;\n fetch: FetchFunction;\n\n /**\n * @param options\n * @param options.serverUrl - The URL to the server eg.\n * https://login.schibsted.com or a URL key like 'DEV' in combination with {@link envDic}.\n * @param options.envDic - A dictionary that will be used for looking up\n * {@link serverUrl} keys. If serverUrl is always a URL, you don't need this.\n * @param options.fetch - The fetch function to use. It can be native\n * or a polyfill\n * @param options.log - A function that will be called with log messages about\n * request and response\n * @param options.defaultParams - Query parameters added to every request\n */\n constructor({\n serverUrl = 'PRE',\n envDic,\n fetch = globalFetch() ?? noFetch,\n log,\n defaultParams = {},\n }: {\n serverUrl?: string;\n envDic?: Record<string, string>;\n fetch?: FetchFunction;\n log?: LogFunction;\n defaultParams?: QueryParams;\n }) {\n assert(isObject(defaultParams), `defaultParams should be a non-null object`);\n\n const mappedUrl = urlMapper(serverUrl, envDic ?? {});\n const handledServerUrl = mappedUrl.endsWith('/') ? mappedUrl : `${mappedUrl}/`;\n this.url = new URL(handledServerUrl);\n\n this.defaultParams = defaultParams;\n\n if (log) {\n assert(isFunction(log), `log must be a function but it is ${log}`);\n this.log = log;\n }\n\n this.fetch = fetch;\n }\n\n /**\n * Makes the actual call to the server and deals with headers, data objects and the edge cases.\n * Please note that this method expects the response to be in JSON format. However, it'll not\n * parse the response if its code is not in the 200 range.\n * @param options - An obligatory options object\n * @param options.method - The HTTP request method, e.g. 'GET' or 'POST'\n * @param options.pathname - The path to the endpoint like 'api/2/endpoint-name'\n * @param options.data - Query parameters added to the request URL\n * @param options.headers - Request headers as a plain key/value map\n * @param options.useDefaultParams - Should we add the defaultParams to the query?\n * @param options.fetchOptions - Additional fetch options\n * @throws {SDKError} - If the call can't be made for whatever reason.\n */\n // Overloads describe the two supported modes:\n // - without a parser: return the parsed JSON response as-is;\n // - with a parser: return the parser's typed result.\n async go(options: RESTRequestOptions): Promise<JsonValue>;\n async go<T>(options: RESTRequestOptions<T> & { parseResponse: ResponseParser<T> }): Promise<T>;\n\n // TypeScript requires one implementation signature for the overloads above.\n async go<T = JsonValue>(options: RESTRequestOptions<T>): Promise<JsonValue | T> {\n const {\n method,\n headers,\n pathname,\n data = {},\n useDefaultParams = true,\n fetchOptions = { method: options.method, credentials: 'include' },\n parseResponse,\n } = options;\n assert(isNonEmptyString(method), `Method must be a non empty string but it is \"${method}\"`);\n assert(isNonEmptyString(pathname), `Pathname must be string but it is \"${pathname}\"`);\n assert(isObject(data), `data must be a non-null object`);\n\n fetchOptions.headers = isObject(headers) ? headers : {};\n const fullUrl = this.makeUrl(pathname, data, useDefaultParams);\n\n logFn(this.log, 'Request:', method.toUpperCase(), fullUrl);\n logFn(this.log, 'Request Headers:', fetchOptions.headers);\n logFn(this.log, 'Request Body:', fetchOptions.body);\n try {\n const response = await this.fetch(fullUrl, fetchOptions);\n logFn(this.log, 'Response Code:', response.status, response.statusText);\n if (!response.ok) {\n // status code not in range 200-299\n throw new SDKError(response.statusText, { code: response.status });\n }\n const responseObject: JsonValue = await response.json();\n logFn(this.log, 'Response Parsed:', responseObject);\n return parseResponse ? parseResponse(responseObject) : responseObject;\n } catch (err: unknown) {\n let msg = isStr(err) ? err : 'Unknown RESTClient error';\n if (isObject(err) && isStr(err.message)) {\n msg = err.message;\n }\n const errorObject = isObject(err) ? err : undefined;\n throw new SDKError(`Failed to '${method}' '${fullUrl}': '${msg}'`, errorObject);\n }\n }\n\n /**\n * Creates a url that points to an endpoint in the server\n * @param pathname - WHATWG pathname ie. 'api/2/endpoint-name'\n * @param query - Query parameters to serialize into the query string\n * @param useDefaultParams - Should we add the defaultParams to the query?\n */\n makeUrl(pathname = '', query: QueryParams = {}, useDefaultParams = true): string {\n const handledPathname = pathname.startsWith('/') ? pathname.slice(1) : pathname;\n\n const url = new URL(handledPathname, this.url);\n url.search = RESTClient.search(query, useDefaultParams, this.defaultParams);\n return url.href;\n }\n\n /**\n * Make a GET request\n * @param pathname - WHATWG pathname ie. 'api/2/endpoint-name'\n * @param data - Query parameters\n */\n // Mirrors `go()` overloads for the common GET helper.\n get(pathname: string, data?: QueryParams): Promise<JsonValue>;\n get<T>(\n pathname: string,\n data: QueryParams | undefined,\n parseResponse: ResponseParser<T>,\n ): Promise<T>;\n\n // TypeScript requires one implementation signature for the overloads above.\n get<T>(\n pathname: string,\n data?: QueryParams,\n parseResponse?: ResponseParser<T>,\n ): Promise<JsonValue | T> {\n if (parseResponse) {\n return this.go({ method: 'GET', pathname, data, parseResponse });\n }\n return this.go({ method: 'GET', pathname, data });\n }\n\n /**\n * Construct query string for WHATWG urls\n * @private\n * @param query - Query parameters to generate the query string from\n * @param useDefaultParams - Use defaultParams or not\n * @param defaultParams - Default params\n */\n private static search(\n query: QueryParams,\n useDefaultParams: boolean,\n defaultParams: QueryParams,\n ): string {\n const params = useDefaultParams ? cloneDefined(defaultParams, query) : cloneDefined(query);\n return Object.keys(params)\n .filter((p) => params[p] !== '')\n .map((p) => `${encode(p)}=${encode(String(params[p]))}`)\n .join('&');\n }\n}\n\nexport default RESTClient;\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport { NAMESPACE } from './config.js';\nimport RESTClient from './rest-client.js';\nimport type { LogFunction } from './types/common.js';\nimport { assert, isNonEmptyString } from './validate.js';\n\ntype AccountRestClientOptions = {\n serverUrl: string;\n log?: LogFunction;\n defaultParams: Record<string, string | number | boolean | undefined>;\n};\n\nconst isKnownNamespace = (env: string): env is keyof typeof NAMESPACE =>\n Object.hasOwn(NAMESPACE, env);\n\nexport const buildClientSdrn = (env: string, clientId: string): string => {\n assert(isNonEmptyString(clientId), 'clientId parameter is required');\n assert(isKnownNamespace(env), `env parameter is invalid: ${env}`);\n\n return `sdrn:${NAMESPACE[env]}:client:${clientId}`;\n};\n\nexport const createAccountRestClient = ({\n serverUrl,\n log,\n defaultParams,\n}: AccountRestClientOptions): RESTClient => new RESTClient({ serverUrl, log, defaultParams });\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport type {\n ConnectedSessionResponse,\n ConnectedSessionWithUserIdResponse,\n NormalizedSessionPayload,\n RedirectSessionPayload,\n SessionFailureResponse,\n SessionResponse,\n SessionSuccessResponse,\n} from './types/session.js';\nimport { isObject, isStr } from './validate.js';\n\n/**\n * Checks whether a value is a successful session response.\n *\n * @param value - The value to check.\n * @group Session\n */\nexport function isSessionSuccessResponse(value: unknown): value is SessionSuccessResponse {\n return isObject(value) && typeof value.result === 'boolean';\n}\n\n/**\n * Checks whether a successful session response represents a user connected to the merchant.\n *\n * @param value - The value to check.\n * @group Session\n */\nexport function isConnectedSessionResponse(value: unknown): value is ConnectedSessionResponse {\n return isSessionSuccessResponse(value) && value.result === true;\n}\n\n/**\n * Checks whether a value is a session failure response.\n *\n * @param value - The value to check.\n * @group Session\n */\nexport function isSessionFailureResponse(value: unknown): value is SessionFailureResponse {\n return isObject(value) && Boolean(value.error);\n}\n\nexport function isRedirectSessionPayload(value: unknown): value is RedirectSessionPayload {\n return isObject(value) && Object.keys(value).length === 1 && isStr(value.redirectURL);\n}\n\n/**\n * Checks whether a connected session response contains a usable user id.\n *\n * @param value - The value to check.\n * @group Session\n */\nexport function isConnectedSessionWithUserIdResponse(\n value: SessionResponse,\n): value is ConnectedSessionWithUserIdResponse {\n return isConnectedSessionResponse(value) && typeof value.userId === 'number';\n}\n\n/**\n * Converts an unknown Session Service `hasSession` payload into one of the shapes the SDK knows how\n * to handle.\n *\n * This function is intentionally tolerant because `hasSession()` historically resolved unknown\n * object payloads instead of rejecting them. The SDK relies on that behavior for backwards\n * compatibility with clients that check the raw response themselves.\n *\n * The normal cases are:\n * - regular success payloads with a boolean `result`;\n * - failure payloads wrapped as `{ error, response? }`;\n * - Safari/session-refresh redirect payloads shaped as `{ redirectURL }`.\n *\n * Any other object is preserved as an unrecognized response so callers can still receive it.\n * Non-object values are normalized to `{}`, matching the old \"empty response\" fallback used by\n * `hasSession()` and cached-session reads.\n *\n * This is used both for network responses parsed by `RESTClient` and for values restored from the\n * session cache, so the rest of the Identity flow can switch on typed guards instead of repeatedly\n * re-validating unknown data.\n *\n * @internal\n */\nexport function normalizeSessionResponse(value: unknown): NormalizedSessionPayload {\n if (isRedirectSessionPayload(value)) {\n return value;\n }\n if (isSessionFailureResponse(value)) {\n return value;\n }\n if (isSessionSuccessResponse(value)) {\n return value;\n }\n if (isObject(value)) {\n return value;\n }\n\n return {};\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\n/**\n * A workaround for how Schibsted account handles JSONP calls in the browser\n * @private\n */\n\nimport './globals.js';\nimport { isFunction } from './validate.js';\n\n/**\n * This is a workaround for making the old SPiD/hassession on JSONP APIs compatible with more common\n * JSONP convention where the callback function is expected to exist in the global object.\n *\n * How does it work?\n * =================\n * The old SPiD JSONP APIs relied on SPiD.Talk.response(callbackName, data) but fetch-jsonp merely\n * calls window[callbackName](data) which is more common practice. This module simply acts as an\n * adapter to modernize the old mechanism until we support CORS. To see how the SPiD solution works,\n * try to run a simple JSONP request or debug it in the network tab. This module will be removed\n * when CORS is supported.\n * @param global - A reference to the global object, typically the `Window`.\n */\nexport function emulate(global: Window): void {\n if (!global.SPiD || typeof global.SPiD !== 'object') {\n global.SPiD = {};\n }\n if (!global.SPiD.Talk || typeof global.SPiD.Talk !== 'object') {\n global.SPiD.Talk = {};\n }\n if (!isFunction(global.SPiD.Talk.response)) {\n global.SPiD.Talk.response = (callbackName: string, data: unknown) =>\n (global as any)[callbackName](data);\n }\n}\n","/**\n * Options accepted by {@link Account#login} and related login URL helpers.\n *\n * @group Login & Widget\n */\nexport type LoginOptions = {\n /**\n * An opaque value used by the client to maintain state between the request and callback.\n * It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}\n */\n state: string;\n /**\n * Authentication Context Class Reference values. If omitted, the default account flow is used.\n * Supported values include `password`, `otp`, `sms`, `otp-email`, `eid`, `eid-no`, `eid-se`,\n * `eid-fi`, and `eid-dk`. Values other than `otp-email` may be combined as a space-separated\n * string. Verify the AMR (Authentication Methods References) claim in the ID token on your\n * backend if you need to enforce a completed authentication method.\n */\n acrValues?:\n | 'password'\n | 'otp'\n | 'sms'\n | 'eid-dk'\n | 'eid-no'\n | 'eid-se'\n | 'eid-fi'\n | 'eid'\n | 'otp-email'\n | (string & {});\n /**\n * The OAuth scopes for the tokens. This is a list of scopes, separated by space. If the list\n * of scopes contains `openid`, the generated tokens includes the id token which can be useful\n * for getting information about the user. Omitting scope is allowed, while `invalid_scope` is\n * returned when the client asks for a scope you aren't allowed to request.\n * {@link https://tools.ietf.org/html/rfc6749#section-3.3}\n * Defaults to `openid`.\n */\n scope?: 'openid' | (string & {});\n /**\n * Redirect uri that will receive the code. Must exactly match a redirectUri from your client\n * in self-service\n */\n redirectUri?: string;\n /** Should we try to open a popup window? Defaults to `false`. */\n preferPopup?: boolean;\n /** user email or UUID hint */\n loginHint?: string;\n /** Pulse tag */\n tag?: string;\n /** Teaser slug. Teaser with given slug will be displayed in place of default teaser */\n teaser?: string;\n /**\n * Specifies the allowable elapsed time in seconds since the last time the End-User was actively\n * authenticated. If last authentication time is more than maxAge seconds in the past,\n * re-authentication will be required. See the OpenID Connect spec section 3.1.2.1 for more\n * information. Prefer a number of seconds; strings remain accepted for legacy callers.\n */\n maxAge?: number | string;\n /**\n * Optional parameter to overwrite client locale setting.\n * New flows supports nb_NO, fi_FI, sv_SE, en_US\n */\n locale?: 'nb_NO' | 'fi_FI' | 'sv_SE' | 'en_US';\n /** display username and password on one screen. Defaults to `false`. */\n oneStepLogin?: boolean;\n /**\n * String that specifies whether the Authorization Server prompts the End-User for\n * reauthentication or confirm account screen. Supported values: `select_account` or `login`.\n * Defaults to `select_account`.\n */\n prompt?: 'select_account' | 'login';\n /** Identifier for cross-domain tracking in Pulse */\n xDomainId?: string;\n /** Environment for cross-domain tracking in Pulse */\n xEnvironmentId?: string;\n /** Campaign identifier for tracking in Pulse */\n originCampaign?: string;\n};\n\n/**\n * Identical to {@link LoginOptions} except that `state` may also be a (possibly async) function;\n * all other fields reuse the `LoginOptions` documentation.\n *\n * @group Login & Widget\n */\nexport type SimplifiedLoginWidgetLoginOptions = Omit<LoginOptions, 'state'> & {\n /**\n * An opaque value used by the client to maintain state between the request and callback.\n * It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}\n */\n state: string | (() => string | Promise<string>);\n};\n\n/**\n * Minimal user information used by the simplified login widget flow.\n *\n * @group Login & Widget\n */\nexport type SimplifiedLoginData = {\n /** Deprecated: User UUID used as `loginHint` for {@link Account#login}. */\n identifier: string;\n /** Human-readable user identifier */\n display_text: string;\n /** Client name */\n client_name: string;\n /** Provider id used by the simplified login widget when supplied by the backend. */\n provider_id?: string;\n};\n\n/**\n * Configuration options for {@link Account#showSimplifiedLoginWidget}.\n *\n * @group Login & Widget\n */\nexport type SimplifiedLoginWidgetOptions = {\n /** expected encoding of simplified login widget. Could be utf-8 (default), iso-8859-1 or iso-8859-15 */\n encoding?: string;\n /**\n * expected locale of simplified login widget. Should be provided in a short format like 'nb',\n * 'sv'. If not set, a value from the env variable is used.\n */\n locale?: 'nb' | 'sv' | 'fi' | 'da' | 'en';\n};\n\nexport type SimplifiedLoginWidgetInitialParams = {\n displayText: string;\n env: string;\n clientName: string;\n clientId: string;\n providerId?: string;\n locale?: SimplifiedLoginWidgetOptions['locale'];\n windowWidth: () => number;\n windowOnResize: (handler: () => void) => void;\n};\n\nexport type SimplifiedLoginWidgetHandler = () => void | Promise<void>;\n\nexport type OpenSimplifiedLoginWidget = (\n initialParams: SimplifiedLoginWidgetInitialParams,\n loginHandler: SimplifiedLoginWidgetHandler,\n loginNotYouHandler: SimplifiedLoginWidgetHandler,\n initHandler: SimplifiedLoginWidgetHandler,\n cancelLoginHandler: SimplifiedLoginWidgetHandler,\n) => unknown;\n\nexport const hasOpenSimplifiedLoginWidget = (\n targetWindow: Window,\n): targetWindow is Window & { openSimplifiedLoginWidget: OpenSimplifiedLoginWidget } => {\n return typeof targetWindow.openSimplifiedLoginWidget === 'function';\n};\n","// Version is bumped automatically by release-please. See release-please-config.json.\n\nconst version = '6.0.0-alpha.9'; // x-release-please-version\nexport default version;\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport Cache from './cache.js';\nimport { ENDPOINTS } from './config.js';\nimport { cloneDeep } from './object.js';\nimport * as popup from './popup.js';\nimport type RESTClient from './rest-client.js';\nimport { buildClientSdrn, createAccountRestClient } from './rest-clients.js';\nimport SDKError from './sdk-error.js';\nimport {\n isConnectedSessionResponse,\n isConnectedSessionWithUserIdResponse,\n isRedirectSessionPayload,\n isSessionFailureResponse,\n isSessionSuccessResponse,\n normalizeSessionResponse,\n} from './session-response.js';\nimport * as spidTalk from './spid-talk.js';\nimport type { AccountEventName } from './types/account.js';\nimport type { LogFunction } from './types/common.js';\nimport type {\n IdentityBeforeRedirectCallback,\n IdentityOptions,\n VarnishCookieOptions,\n} from './types/identity.js';\nimport {\n hasOpenSimplifiedLoginWidget,\n type LoginOptions,\n type OpenSimplifiedLoginWidget,\n type SimplifiedLoginData,\n type SimplifiedLoginWidgetInitialParams,\n type SimplifiedLoginWidgetLoginOptions,\n type SimplifiedLoginWidgetOptions,\n} from './types/login.js';\nimport type {\n ConnectedSessionResponse,\n NormalizedSessionPayload,\n SessionObjectResponse,\n SessionResponse,\n} from './types/session.js';\nimport { urlMapper } from './url.js';\nimport { assert, isNonEmptyString, isObject, isStr, isStrIn, isUrl } from './validate.js';\nimport version from './version.js';\n\ndeclare global {\n interface Window {\n openSimplifiedLoginWidget?: OpenSimplifiedLoginWidget;\n }\n}\n\nconst HAS_SESSION_CACHE_KEY = 'hasSession-cache';\nconst SESSION_CALL_BLOCKED_CACHE_KEY = 'sessionCallBlocked-cache';\nconst SESSION_CALL_BLOCKED_TTL = 1000 * 60 * 5;\n\nconst TAB_ID_KEY = 'tab-id-cache';\nconst TAB_ID = Math.floor(Math.random() * 100000);\nconst TAB_ID_TTL = 1000 * 60 * 60 * 24 * 30;\n\nconst globalWindow = () => window;\n\n/**\n * Provides Identity functionalty to a web page\n */\nexport class Identity {\n // Event bus\n private readonly eventTarget = new EventTarget();\n\n // Configuration\n private readonly window: Window;\n private readonly clientId: string;\n private readonly redirectUri: string;\n private readonly env: string;\n private readonly log?: LogFunction;\n private readonly callbackBeforeRedirect: IdentityBeforeRedirectCallback;\n\n // Caches\n private readonly sessionStorageCache: Cache;\n private readonly localStorageCache: Cache;\n private enableSessionCaching: boolean;\n\n // REST clients\n private readonly spid: RESTClient;\n private readonly oauthService: RESTClient;\n private readonly bffService: RESTClient;\n private readonly sessionService: RESTClient;\n private readonly globalSessionService: RESTClient;\n private readonly usedSessionServiceGetSessionEndpoint: 'v2/session' | 'session';\n\n // Session state\n /**\n * @internal Starts as `{}` before the first `hasSession()` call, then stores the latest\n * object response from hasSession().\n */\n private session: SessionObjectResponse;\n private hasSessionInProgress?: false | Promise<SessionResponse>;\n\n // Popup & Varnish cookie state\n private popup?: Window | null;\n private setVarnishCookie?: boolean;\n private varnishExpiresIn?: number;\n private varnishCookieDomain?: string;\n\n /**\n * @param options\n * @param options.clientId - Example: \"1234567890abcdef12345678\"\n * @param options.sessionDomain - Example: \"https://id.site.com\"\n * @param options.redirectUri - Example: \"https://site.com\"\n * @param options.env - Schibsted account environment: `PRE` (default), `PRO`, `PRO_NO`, `PRO_FI` or `PRO_DK`\n * @param options.log - A function that receives debug log information. If not set,\n * no logging will be done\n * @param options.window - window object\n * @param options.callbackBeforeRedirect - callback triggered before session refresh redirect happen\n * @throws {SDKError} - If any of options are invalid\n */\n constructor({\n clientId,\n redirectUri,\n sessionDomain,\n env = 'PRE',\n log,\n window = globalWindow(),\n callbackBeforeRedirect = () => {},\n }: IdentityOptions) {\n assert(isNonEmptyString(clientId), 'clientId parameter is required');\n assert(isObject(window), 'The reference to window is missing');\n assert(!redirectUri || isUrl(redirectUri), 'redirectUri parameter is invalid');\n assert(\n isNonEmptyString(sessionDomain) && isUrl(sessionDomain),\n 'sessionDomain parameter is not a valid URL',\n );\n assert(isStr(env), `env parameter is invalid: ${env}`);\n\n spidTalk.emulate(window);\n this.window = window;\n this.clientId = clientId;\n this.redirectUri = redirectUri;\n this.env = env;\n this.log = log;\n this.callbackBeforeRedirect = callbackBeforeRedirect;\n\n this.sessionStorageCache = new Cache(() => this.window && this.window.sessionStorage);\n this.localStorageCache = new Cache(() => this.window && this.window.localStorage);\n // Internal hack: set to false to always refresh from hassession\n this.enableSessionCaching = true;\n\n this.session = {};\n\n const accountClientParams = { client_id: this.clientId, redirect_uri: this.redirectUri };\n const clientSdrn = buildClientSdrn(this.env, this.clientId);\n\n this.spid = createAccountRestClient({\n serverUrl: urlMapper(env, ENDPOINTS.SPiD),\n log: this.log,\n defaultParams: accountClientParams,\n });\n this.oauthService = createAccountRestClient({\n serverUrl: urlMapper(env, ENDPOINTS.SPiD),\n log: this.log,\n defaultParams: accountClientParams,\n });\n this.bffService = createAccountRestClient({\n serverUrl: urlMapper(env, ENDPOINTS.BFF),\n log: this.log,\n defaultParams: accountClientParams,\n });\n this.sessionService = createAccountRestClient({\n serverUrl: sessionDomain,\n log: this.log,\n defaultParams: {\n client_sdrn: clientSdrn,\n redirect_uri: this.redirectUri,\n sdk_version: version,\n },\n });\n this.globalSessionService = createAccountRestClient({\n serverUrl: urlMapper(env, ENDPOINTS.SESSION_SERVICE),\n log: this.log,\n defaultParams: { client_sdrn: clientSdrn, sdk_version: version },\n });\n this.usedSessionServiceGetSessionEndpoint =\n this.sessionService.url.pathname && this.sessionService.url.pathname.length <= 1\n ? 'v2/session'\n : 'session';\n\n this._unblockSessionCall();\n }\n\n addEventListener(type: AccountEventName, listener: EventListener): void {\n this.eventTarget.addEventListener(type, listener);\n }\n\n removeEventListener(type: AccountEventName, listener: EventListener): void {\n this.eventTarget.removeEventListener(type, listener);\n }\n\n /**\n * Read tabId from session storage\n * @private\n */\n _getTabId(): number | undefined {\n if (this.enableSessionCaching) {\n const tabId = this.sessionStorageCache.get(TAB_ID_KEY);\n if (typeof tabId !== 'number') {\n this.sessionStorageCache.set(TAB_ID_KEY, TAB_ID, TAB_ID_TTL);\n return TAB_ID;\n }\n\n return tabId;\n }\n }\n\n /**\n * Checks if getting session is blocked\n * @private\n *\n */\n _isSessionCallBlocked(): boolean {\n return Boolean(this.localStorageCache.get(SESSION_CALL_BLOCKED_CACHE_KEY));\n }\n\n /**\n * Block calls to get session\n * @private\n *\n */\n _blockSessionCall(): void {\n const SESSION_CALL_BLOCKED = true;\n\n this.localStorageCache.set(\n SESSION_CALL_BLOCKED_CACHE_KEY,\n SESSION_CALL_BLOCKED,\n SESSION_CALL_BLOCKED_TTL,\n );\n }\n\n /**\n * Unblocks calls to get session\n * @private\n *\n */\n _unblockSessionCall(): void {\n this.localStorageCache.delete(SESSION_CALL_BLOCKED_CACHE_KEY);\n }\n\n /**\n * Close this.popup if it exists and is open\n * @private\n */\n _closePopup(): void {\n if (this.popup) {\n if (!this.popup.closed) {\n this.popup.close();\n }\n this.popup = null;\n }\n }\n\n /**\n * Set the Varnish cookie (`SP_ID`) when hasSession() is called. Note that most browsers require\n * that you are on a \"real domain\" for this to work — so, **not** `localhost`\n * @param options\n * @param options.expiresIn Override this to set number of seconds before the varnish\n * cookie expires. The default is to use the same time that hasSession responses are cached for\n * @param options.domain Override cookie domain. E.g. «vg.no» instead of «www.vg.no»\n */\n enableVarnishCookie(options: VarnishCookieOptions): void {\n if (typeof options !== 'object') {\n throw new SDKError('VarnishCookieOptions must be an object');\n }\n\n const { expiresIn = 0, domain } = options;\n\n assert(Number.isInteger(expiresIn), `'expiresIn' must be an integer`);\n assert(expiresIn >= 0, `'expiresIn' cannot be negative`);\n this.setVarnishCookie = true;\n this.varnishExpiresIn = expiresIn;\n this.varnishCookieDomain = domain;\n }\n\n /**\n * Set the Varnish cookie if configured\n * @private\n * @param sessionData\n */\n _maybeSetVarnishCookie(sessionData: object): void {\n if (!this.setVarnishCookie || !isSessionSuccessResponse(sessionData)) {\n return;\n }\n const date = new Date();\n const validExpires =\n this.varnishExpiresIn ||\n (typeof sessionData.expiresIn === 'number' && sessionData.expiresIn > 0);\n if (validExpires) {\n const expires = this.varnishExpiresIn || sessionData.expiresIn || 0;\n date.setTime(date.getTime() + expires * 1000);\n } else {\n date.setTime(0);\n }\n\n // If the domain is missing or of the wrong type, we'll use document.domain\n const domain =\n this.varnishCookieDomain ||\n (typeof sessionData.baseDomain === 'string'\n ? sessionData.baseDomain\n : this.window.location.hostname) ||\n '';\n\n const cookie = [\n `SP_ID=${sessionData.sp_id}`,\n `expires=${date.toUTCString()}`,\n `path=/`,\n `domain=.${domain}`,\n ].join('; ');\n document.cookie = cookie;\n }\n\n /**\n * Clear the Varnish cookie if configured\n * @private\n */\n _maybeClearVarnishCookie(): void {\n if (this.setVarnishCookie) {\n this._clearVarnishCookie();\n }\n }\n\n /**\n * Clear the Varnish cookie\n * @private\n */\n _clearVarnishCookie(): void {\n const baseDomain =\n this.session &&\n isSessionSuccessResponse(this.session) &&\n typeof this.session.baseDomain === 'string'\n ? this.session.baseDomain\n : this.window.location.hostname;\n\n const domain = this.varnishCookieDomain || baseDomain || '';\n\n document.cookie = `SP_ID=nothing; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;\n }\n\n /**\n * @summary Queries the hassession endpoint and returns information about the status of the user\n * @remarks When we send a request to this endpoint, cookies sent along with the request\n * determines the status of the user.\n * @throws {SDKError} - If the call to the hasSession service fails in any way (this will happen\n * if, say, the user is not logged in)\n */\n hasSession(): Promise<SessionResponse> {\n const isSessionCallBlocked = this._isSessionCallBlocked();\n\n if (isSessionCallBlocked) {\n const sessionData = normalizeSessionResponse(this.session);\n return Promise.resolve(isRedirectSessionPayload(sessionData) ? {} : sessionData);\n }\n\n if (this.hasSessionInProgress) {\n return this.hasSessionInProgress;\n }\n\n const _postProcess = (sessionData: SessionObjectResponse): SessionObjectResponse => {\n if (isSessionFailureResponse(sessionData)) {\n const errorObject = isObject(sessionData.error)\n ? sessionData.error\n : { description: String(sessionData.error) };\n throw new SDKError('HasSession failed', errorObject);\n }\n this._maybeSetVarnishCookie(sessionData);\n this.session = sessionData;\n return sessionData;\n };\n\n const _getCachedSession = (): NormalizedSessionPayload | null => {\n const cachedSession = this.sessionStorageCache.get(HAS_SESSION_CACHE_KEY);\n return cachedSession ? normalizeSessionResponse(cachedSession) : null;\n };\n\n const _getSession = async (): Promise<SessionResponse> => {\n if (this.enableSessionCaching) {\n // Try to resolve from cache (it has a TTL)\n const cachedSession = _getCachedSession();\n if (cachedSession) {\n if (isRedirectSessionPayload(cachedSession)) {\n return {};\n }\n return _postProcess(cachedSession);\n }\n }\n let sessionData: NormalizedSessionPayload | null = null;\n try {\n sessionData = await this.sessionService.get(\n this.usedSessionServiceGetSessionEndpoint,\n { tabId: this._getTabId() },\n normalizeSessionResponse,\n );\n } catch (err: unknown) {\n const cacheableError = isObject(err) ? err : undefined;\n if (cacheableError?.code === 400 && this.enableSessionCaching) {\n const errorExpiresIn =\n typeof cacheableError.expiresIn === 'number'\n ? cacheableError.expiresIn\n : 300;\n const expiresIn = 1000 * errorExpiresIn;\n this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, { error: err }, expiresIn);\n } else if (\n cacheableError &&\n typeof cacheableError.code === 'number' &&\n cacheableError.code >= 500 &&\n cacheableError.code < 600 &&\n this.enableSessionCaching\n ) {\n // Temporary fix: 30 seconds cache to limit number of calls when service is unavailable\n this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, { error: err }, 30 * 1000);\n }\n throw err;\n }\n\n if (sessionData) {\n // for expiring session and safari browser do full page redirect to gain new session\n if (isRedirectSessionPayload(sessionData)) {\n this._blockSessionCall();\n\n await this.callbackBeforeRedirect();\n\n const redirectUrl = this.sessionService.makeUrl(sessionData.redirectURL, {\n tabId: this._getTabId(),\n });\n return redirectUrl;\n }\n\n if (this.enableSessionCaching) {\n const expiresIn =\n 1000 *\n (isSessionSuccessResponse(sessionData)\n ? sessionData.expiresIn || 300\n : 300);\n this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, sessionData, expiresIn);\n }\n }\n\n return _postProcess(sessionData ?? {});\n };\n this.hasSessionInProgress = _getSession().then(\n (sessionData) => {\n this.hasSessionInProgress = false;\n if (typeof sessionData === 'string') {\n this.window.location.href = sessionData;\n }\n return sessionData;\n },\n (err) => {\n this.hasSessionInProgress = false;\n throw new SDKError('HasSession failed', err);\n },\n );\n\n return this.hasSessionInProgress;\n }\n\n /**\n * @summary Allows the client app to check if the user is logged in to Schibsted account\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n */\n async isLoggedIn(): Promise<boolean> {\n try {\n const data = await this.hasSession();\n return isSessionSuccessResponse(data);\n } catch (_) {\n return false;\n }\n }\n\n /**\n * Enables or disables caching for subsequent session lookups.\n *\n * Changing this setting does not remove an existing cached session. Use\n * {@link Identity#clearCachedUserSession} to clear the cache explicitly.\n */\n setSessionCachingEnabled(enabled: boolean): void {\n this.enableSessionCaching = enabled;\n }\n\n /**\n * Removes the cached user session.\n */\n clearCachedUserSession(): void {\n this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);\n }\n\n /**\n * @summary Allows the caller to check if the current user is connected to the client_id in\n * Schibsted account. Being connected means that the user has agreed for their account to be\n * used by your web app and have accepted the required terms\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @summary Check if the user is connected to the client_id\n */\n async isConnected(): Promise<boolean> {\n try {\n return isConnectedSessionResponse(await this.hasSession());\n } catch (_) {\n return false;\n }\n }\n\n /**\n * @summary Returns information about the user\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @throws {SDKError} If the user isn't connected to the merchant\n * @throws {SDKError} If we couldn't get the user\n */\n async getUser(): Promise<ConnectedSessionResponse> {\n const user = await this.hasSession();\n if (!isConnectedSessionResponse(user)) {\n throw new SDKError('The user is not connected to this merchant');\n }\n return cloneDeep(user);\n }\n /**\n * @summary\n * In Schibsted account, there are multiple ways of identifying a user; the `userId` or `uuid`.\n * There are reasons for them all to exist. The `userId` is a numeric identifier, but\n * since Schibsted account is deployed separately in Norway and Sweden, there are a lot of\n * duplicates. The `userId` was introduced early, so many sites still need to use them for\n * legacy reasons. The `uuid` is universally unique, and so — if we could disregard a lot of\n * Schibsted components depending on the numeric `userId` — it would be a good identifier to use\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @throws {SDKError} If the user isn't connected to the merchant\n * @return The `userId` field (not to be confused with the `uuid`)\n */\n async getUserId(): Promise<number> {\n const user = await this.hasSession();\n if (isConnectedSessionWithUserIdResponse(user)) {\n return user.userId;\n }\n throw new SDKError('The user is not connected to this merchant');\n }\n\n /**\n * @function\n * @summary\n * Retrieves the external identifier (`externalId`) for the authenticated user.\n *\n * In Schibsted Account there are multiple ways of identifying users, however for integrations with\n * third-parties it's recommended to use `externalId` as it does not disclose\n * any critical data whilst allowing for user identification.\n *\n * `externalId` is merchant-scoped using a pairwise identifier (`pairId`),\n * meaning the same user's ID will differ between merchants.\n * Additionally, this identifier is bound to the external party provided as argument.\n *\n * @param externalParty\n * @param optionalSuffix\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @throws {SDKError} If the `pairId` is missing in user session.\n * @throws {SDKError} If the `externalParty` is not defined\n * @return The merchant- and 3rd-party-specific `externalId`\n */\n async getExternalId(externalParty: string, optionalSuffix: string = ''): Promise<string> {\n const user = await this.hasSession();\n const pairId = isSessionSuccessResponse(user) ? user.pairId : undefined;\n\n if (!pairId) throw new SDKError('pairId missing in user session!');\n\n if (!externalParty || externalParty.length === 0) {\n throw new SDKError('externalParty cannot be empty');\n }\n const _toHexDigest = (hashBuffer: ArrayBuffer) => {\n // convert buffer to byte array\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n // convert bytes to hex string\n return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');\n };\n\n const _getSha256Digest = (data: BufferSource) => {\n return crypto.subtle.digest('SHA-256', data);\n };\n\n const _hashMessage = async (message: string) => {\n const msgUint8 = new TextEncoder().encode(message);\n return _getSha256Digest(msgUint8).then((it) => _toHexDigest(it));\n };\n\n const _constructMessage = (\n pairId: string,\n externalParty: string,\n optionalSuffix: string,\n ) => {\n return optionalSuffix\n ? `${pairId}:${externalParty}:${optionalSuffix}`\n : `${pairId}:${externalParty}`;\n };\n\n return _hashMessage(_constructMessage(pairId, externalParty, optionalSuffix));\n }\n\n /**\n * @summary Enables brands to programmatically get the current the SDRN based on the user's session.\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @throws {SDKError} If the SDRN is missing in user session object.\n */\n async getUserSDRN(): Promise<string> {\n const user = await this.hasSession();\n if (isSessionSuccessResponse(user) && user.sdrn) {\n return user.sdrn;\n }\n throw new SDKError('Failed to get SDRN from user session');\n }\n\n /**\n * @summary In Schibsted account, there are two ways of identifying a user; the `userId` and the\n * `uuid`. There are reasons for them both existing. The `userId` is a numeric identifier, but\n * since Schibsted account is deployed separately in Norway and Sweden, there are a lot of\n * duplicates. The `userId` was introduced early, so many sites still need to use them for\n * legacy reasons. The `uuid` is universally unique, and so — if we could disregard a lot of\n * Schibsted components depending on the numeric `userId` — it would be a good identifier to use\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @throws {SDKError} If the user isn't connected to the merchant\n * @return The `uuid` field (not to be confused with the `userId`)\n */\n async getUserUuid(): Promise<string> {\n const user = await this.hasSession();\n if (isSessionSuccessResponse(user) && user.uuid && user.result) {\n return user.uuid;\n }\n throw new SDKError('The user is not connected to this merchant');\n }\n\n /**\n * @summary Get basic information about any user currently logged-in to their Schibsted account\n * in this browser. Can be used to provide context in a continue-as prompt.\n * @remarks This function relies on the global Schibsted account user session cookie, which\n * is a third-party cookie and hence might be blocked by the browser (for example due to ITP in\n * Safari). So there's no guarantee any data is returned, even though a user is logged-in in\n * the current browser.\n */\n async getUserContextData(): Promise<SimplifiedLoginData | null> {\n try {\n return await this.globalSessionService.get('user-context', undefined, (value) =>\n isObject(value) && isStr(value.identifier)\n ? {\n identifier: value.identifier,\n display_text: isStr(value.display_text) ? value.display_text : '',\n client_name: isStr(value.client_name) ? value.client_name : '',\n provider_id: isStr(value.provider_id) ? value.provider_id : undefined,\n }\n : null,\n );\n } catch (_) {\n return null;\n }\n }\n\n /**\n * If a popup is desired, this function needs to be called in response to a user event (like\n * click or tap) in order to work correctly. Otherwise the popup will be blocked by the\n * browser's popup blockers and has to be explicitly authorized to be shown.\n * @summary Perform a login, either using a full-page redirect or a popup\n * @see https://tools.ietf.org/html/rfc6749#section-4.1.1\n *\n * @param options\n * @param options.state\n * @param options.acrValues\n * @param options.scope\n * @param options.redirectUri\n * @param options.preferPopup\n * @param options.loginHint\n * @param options.tag\n * @param options.teaser\n * @param options.maxAge\n * @param options.locale\n * @param options.oneStepLogin\n * @param options.prompt\n * @param options.xDomainId\n * @param options.xEnvironmentId\n * @param options.originCampaign\n * @fires Identity#loginRequested\n * @return - Reference to popup window if created (or `null` otherwise)\n */\n login({\n state,\n acrValues,\n scope = 'openid',\n redirectUri = this.redirectUri,\n preferPopup = false,\n loginHint = '',\n tag = '',\n teaser = '',\n maxAge = '',\n locale,\n oneStepLogin = false,\n prompt = 'select_account',\n xDomainId = '',\n xEnvironmentId = '',\n originCampaign = '',\n }: LoginOptions): Window | null {\n this._closePopup();\n this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);\n const url = this.loginUrl({\n state,\n acrValues,\n scope,\n redirectUri,\n loginHint,\n tag,\n teaser,\n maxAge,\n locale,\n oneStepLogin,\n prompt,\n xDomainId,\n xEnvironmentId,\n originCampaign,\n });\n\n if (preferPopup) {\n this.popup = popup.open(this.window, url, 'Schibsted account', {\n width: 360,\n height: 570,\n });\n\n if (this.popup) {\n this.eventTarget.dispatchEvent(\n new CustomEvent('loginRequested', {\n detail: { url, method: 'popup' },\n }),\n );\n\n return this.popup;\n }\n }\n\n this.eventTarget.dispatchEvent(\n new CustomEvent('loginRequested', {\n detail: { url, method: 'default' },\n }),\n );\n this.window.location.href = url;\n\n return null;\n }\n\n /**\n * @summary Retrieve the sp_id (Varnish ID)\n * @remarks This function calls {@link Identity#hasSession} internally and thus has the side\n * effect that it might perform an auto-login on the user\n * @return - The sp_id string or null (if the server didn't return it)\n */\n async getSpId(): Promise<string | null> {\n try {\n const user = await this.hasSession();\n if (isSessionSuccessResponse(user)) {\n return user.sp_id || null;\n }\n const spId = isObject(user) && 'sp_id' in user ? user.sp_id : undefined;\n return isStr(spId) ? spId : null;\n } catch (_) {\n return null;\n }\n }\n\n /**\n * @summary Logs the user out from the Identity platform\n * @param redirectUri - Where to redirect the browser after logging out of Schibsted account\n * @fires Identity#logoutRequested\n */\n logout(redirectUri: string = this.redirectUri): void {\n this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);\n this._maybeClearVarnishCookie();\n const url = this.logoutUrl(redirectUri);\n this.eventTarget.dispatchEvent(\n new CustomEvent('logoutRequested', {\n detail: { url },\n }),\n );\n this.window.location.href = url;\n }\n\n /**\n * Generates the link to the new login page that'll be used in the popup or redirect flow\n * @param options\n * @param options.state\n * @param options.acrValues\n * @param options.scope\n * @param options.redirectUri\n * @param options.loginHint\n * @param options.tag\n * @param options.teaser\n * @param options.maxAge\n * @param options.locale\n * @param options.oneStepLogin\n * @param options.prompt\n * @param options.xDomainId\n * @param options.xEnvironmentId\n * @param options.originCampaign\n * @return - The url\n */\n loginUrl({\n state,\n acrValues = '',\n scope = 'openid',\n redirectUri = this.redirectUri,\n loginHint = '',\n tag = '',\n teaser = '',\n maxAge = '',\n locale,\n oneStepLogin = false,\n prompt = 'select_account',\n xDomainId = '',\n xEnvironmentId = '',\n originCampaign = '',\n }: LoginOptions): string {\n const isValidAcrValue = (acrValue: string) =>\n isStrIn(\n acrValue,\n ['password', 'otp', 'sms', 'eid-dk', 'eid-no', 'eid-se', 'eid-fi', 'eid'],\n true,\n );\n assert(\n !acrValues ||\n isStrIn(acrValues, ['', 'otp-email'], true) ||\n acrValues.split(' ').every(isValidAcrValue),\n `The acrValues parameter is not acceptable: ${acrValues}`,\n );\n assert(\n isUrl(redirectUri),\n `loginUrl(): redirectUri must be a valid url but is ${redirectUri}`,\n );\n assert(\n isNonEmptyString(state),\n `the state parameter should be a non empty string but it is ${state}`,\n );\n\n return this.oauthService.makeUrl('oauth/authorize', {\n response_type: 'code',\n redirect_uri: redirectUri,\n scope,\n state,\n acr_values: acrValues,\n login_hint: loginHint,\n tag,\n teaser,\n max_age: maxAge,\n locale,\n one_step_login: oneStepLogin || '',\n prompt: acrValues ? '' : prompt,\n x_domain_id: xDomainId,\n x_env_id: xEnvironmentId,\n utm_campaign: originCampaign,\n });\n }\n\n /**\n * The url for logging the user out\n * @param redirectUri\n * @return url\n */\n logoutUrl(redirectUri: string = this.redirectUri): string {\n assert(isUrl(redirectUri), `logoutUrl(): redirectUri is invalid`);\n const params = { redirect_uri: redirectUri };\n return this.sessionService.makeUrl('logout', params);\n }\n\n /**\n * The account summary page url\n * @param redirectUri\n */\n accountUrl(redirectUri: string = this.redirectUri): string {\n return this.spid.makeUrl('profile-pages', {\n response_type: 'code',\n redirect_uri: redirectUri,\n });\n }\n\n /**\n * Function responsible for loading and displaying simplified login widget. How often\n * widget will be display is up to you. Preferred way would be to show it once per user,\n * and store that info in localStorage. Widget will be display only if user is logged in to SSO.\n *\n * @param loginParams - the same as `options` param for login function. Login will be called on user\n * continue action. `state` might be string or async function.\n * @param options - additional configuration of Simplified Login Widget\n * @fires Identity#simplifiedLoginOpened\n * @fires Identity#simplifiedLoginCancelled\n * @throws {SDKError} - If user context data is missing or the widget script cannot be loaded\n * @return - will resolve to true if widget will be displayed\n */\n async showSimplifiedLoginWidget(\n loginParams: SimplifiedLoginWidgetLoginOptions,\n options?: SimplifiedLoginWidgetOptions,\n ): Promise<boolean> {\n // getUserContextData doesn't throw exception\n const userData = await this.getUserContextData();\n\n const queryParams: Record<string, string> = { client_id: this.clientId };\n if (options && options.encoding) {\n queryParams.encoding = options.encoding;\n }\n const widgetUrl = this.bffService.makeUrl('simplified-login-widget', queryParams, false);\n\n const prepareLoginParams = async (\n loginParams: SimplifiedLoginWidgetLoginOptions,\n ): Promise<LoginOptions> => {\n const state =\n typeof loginParams.state === 'function'\n ? await loginParams.state()\n : loginParams.state;\n\n return {\n ...loginParams,\n state,\n };\n };\n\n return new Promise<boolean>((resolve, reject) => {\n if (!userData?.display_text || !userData.identifier) {\n reject(new SDKError('Missing user data'));\n return;\n }\n\n const initialParams: SimplifiedLoginWidgetInitialParams = {\n displayText: userData.display_text,\n env: this.env,\n clientName: userData.client_name || '',\n clientId: this.clientId,\n providerId: userData.provider_id,\n windowWidth: () => window.innerWidth,\n windowOnResize: (f: () => void) => {\n window.onresize = f;\n },\n };\n\n if (options && options.locale) {\n initialParams.locale = options.locale;\n }\n\n const loginHandler = async () => {\n this.login(\n Object.assign(await prepareLoginParams(loginParams), {\n loginHint: userData.identifier,\n }) as LoginOptions,\n );\n };\n\n const loginNotYouHandler = async () => {\n this.login(\n Object.assign(await prepareLoginParams(loginParams), {\n loginHint: userData.identifier,\n prompt: 'login',\n }) as LoginOptions,\n );\n };\n\n const initHandler = () => {\n /**\n * Emitted when the simplified login widget is displayed on the screen\n * @event Identity#simplifiedLoginOpened\n */\n this.eventTarget.dispatchEvent(new Event('simplifiedLoginOpened'));\n };\n\n const cancelLoginHandler = () => {\n this.eventTarget.dispatchEvent(new Event('simplifiedLoginCancelled'));\n };\n\n if (hasOpenSimplifiedLoginWidget(window)) {\n window.openSimplifiedLoginWidget(\n initialParams,\n loginHandler,\n loginNotYouHandler,\n initHandler,\n cancelLoginHandler,\n );\n return resolve(true);\n }\n\n const simplifiedLoginWidget = document.createElement('script');\n simplifiedLoginWidget.type = 'text/javascript';\n simplifiedLoginWidget.src = widgetUrl;\n simplifiedLoginWidget.onload = () => {\n if (!hasOpenSimplifiedLoginWidget(window)) {\n reject(new SDKError('Error when loading simplified login widget content'));\n return;\n }\n window.openSimplifiedLoginWidget(\n initialParams,\n loginHandler,\n loginNotYouHandler,\n initHandler,\n cancelLoginHandler,\n );\n resolve(true);\n };\n simplifiedLoginWidget.onerror = () => {\n reject(new SDKError('Error when loading simplified login widget content'));\n };\n document.getElementsByTagName('body')[0].appendChild(simplifiedLoginWidget);\n });\n }\n}\n\nexport default Identity;\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport SDKError from './sdk-error.js';\nimport type { HasAccessResult } from './types/monetization.js';\nimport { isObject, isStr } from './validate.js';\n\nexport function parseHasAccessResult(value: unknown): HasAccessResult {\n if (!isObject(value)) {\n throw new SDKError('Invalid hasAccess response');\n }\n\n const { entitled, ttl, allowedFeatures, userId, uuid, sig } = value;\n\n if (\n typeof entitled !== 'boolean' ||\n typeof ttl !== 'number' ||\n !Array.isArray(allowedFeatures) ||\n typeof userId !== 'number' ||\n !isStr(uuid) ||\n !isStr(sig)\n ) {\n throw new SDKError('Invalid hasAccess response');\n }\n\n return {\n entitled,\n ttl,\n allowedFeatures: allowedFeatures.filter(isStr),\n userId,\n uuid,\n sig,\n };\n}\n","/* Copyright 2024 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport Cache from './cache.js';\nimport { parseHasAccessResult } from './has-access-response.js';\nimport type RESTClient from './rest-client.js';\nimport { buildClientSdrn, createAccountRestClient } from './rest-clients.js';\nimport SDKError from './sdk-error.js';\nimport * as spidTalk from './spid-talk.js';\nimport type { HasAccessResult, MonetizationOptions } from './types/monetization.js';\nimport type { SessionUserId } from './types/session.js';\nimport { assert, isNonEmptyString, isStr, isUrl } from './validate.js';\nimport version from './version.js';\n\nconst globalWindow = () => window;\n\n/**\n * Provides features related to monetization\n */\nexport class Monetization {\n private readonly cache: Cache;\n private readonly sessionService?: RESTClient;\n private readonly pendingHasAccessRequests: Record<string, Promise<HasAccessResult>>;\n\n /**\n * @param options - Monetization configuration\n * @throws {SDKError} - If any of options are invalid\n */\n constructor({\n clientId,\n redirectUri,\n env = 'PRE',\n sessionDomain,\n window = globalWindow(),\n }: MonetizationOptions) {\n spidTalk.emulate(window);\n assert(isNonEmptyString(clientId), 'clientId parameter is required');\n assert(isStr(env), `env parameter is invalid: ${env}`);\n const clientSdrn = buildClientSdrn(env, clientId);\n\n this.cache = new Cache(() => window && window.sessionStorage);\n this.pendingHasAccessRequests = {};\n\n if (sessionDomain) {\n assert(isUrl(sessionDomain), 'sessionDomain parameter is not a valid URL');\n this.sessionService = createAccountRestClient({\n serverUrl: sessionDomain,\n defaultParams: {\n client_sdrn: clientSdrn,\n redirect_uri: redirectUri,\n sdk_version: version,\n },\n });\n }\n }\n\n /**\n * Checks if the user has access to a set of products or features.\n * @param productIds - which products/features to check\n * @param userId - id of currently logged in user\n * @throws {SDKError} - If the input is incorrect, or a network call fails in any way\n * (this will happen if, say, the user is not logged in)\n * @returns The data object returned from Schibsted account (or `null` if the user\n * doesn't have access to any of the given products/features)\n */\n async hasAccess(productIds: string[], userId: SessionUserId): Promise<HasAccessResult | null> {\n if (!this.sessionService) {\n throw new SDKError(`hasAccess can only be called if 'sessionDomain' is configured`);\n }\n if (!userId) {\n throw new SDKError(`'userId' must be specified`);\n }\n if (!Array.isArray(productIds)) {\n throw new SDKError(`'productIds' must be an array`);\n }\n\n const sortedIds = [...productIds].sort();\n const cacheKey = this.accessCacheKey(sortedIds, userId);\n let data = this.cache.get(cacheKey) as HasAccessResult | null;\n if (!data) {\n if (!this.pendingHasAccessRequests[cacheKey]) {\n this.pendingHasAccessRequests[cacheKey] = this.sessionService.get(\n `/hasAccess/${sortedIds.join(',')}`,\n undefined,\n parseHasAccessResult,\n );\n }\n const promise = this.pendingHasAccessRequests[cacheKey];\n try {\n data = await promise;\n const expiresSeconds = data.ttl;\n this.cache.set(cacheKey, data, expiresSeconds * 1000);\n } finally {\n if (this.pendingHasAccessRequests[cacheKey] === promise) {\n delete this.pendingHasAccessRequests[cacheKey];\n }\n }\n }\n\n if (!data.entitled) {\n return null;\n }\n\n return data;\n }\n\n /**\n * Removes the cached access result.\n * @param productIds - which products/features to check\n * @param userId - id of currently logged in user\n */\n clearCachedAccessResult(productIds: string[], userId: SessionUserId): void {\n this.cache.delete(this.accessCacheKey(productIds, userId));\n }\n\n /**\n * Compute \"has access\" cache key for the given product ids and user id.\n * @private\n * @param productIds - which products/features to check\n * @param userId - id of currently logged in user\n */\n private accessCacheKey(productIds: string[], userId: SessionUserId): string {\n return `prd_${[...productIds].sort()}_${userId}`;\n }\n}\n\nexport default Monetization;\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nexport const resolveBrowserWindow = (providedWindow?: Window): Window | undefined => {\n if (providedWindow) {\n return providedWindow;\n }\n\n return typeof window === 'undefined' ? undefined : window;\n};\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport Identity from './identity.js';\nimport Monetization from './monetization.js';\nimport { resolveBrowserWindow } from './resolve-browser-window.js';\nimport SDKError from './sdk-error.js';\nimport type { AccountConfig, AccountEventListener, AccountEventName } from './types/account.js';\nimport type {\n LoginOptions,\n SimplifiedLoginData,\n SimplifiedLoginWidgetLoginOptions,\n SimplifiedLoginWidgetOptions,\n} from './types/login.js';\nimport type { HasAccessResult } from './types/monetization.js';\nimport type { ConnectedSessionResponse, SessionResponse, SessionUserId } from './types/session.js';\n\n/**\n * Unified client-side interface for a configured Schibsted Account integration.\n *\n * Create an instance with `createAccountSdk()` unless you explicitly need to construct it\n * yourself. The instance coordinates identity, login, session, and access-check features for one\n * configured client.\n *\n * @group Core API\n */\nexport class Account {\n #identity: Identity;\n #monetization: Monetization;\n #defaultProductIds?: string[];\n\n constructor(config: AccountConfig) {\n const browserWindow = resolveBrowserWindow(config.window);\n\n if (!browserWindow) {\n throw new SDKError('Schibsted Account SDK is not available in this browser context');\n }\n\n if (browserWindow.schAccount) {\n throw new SDKError('Schibsted Account SDK has already been initialized');\n }\n\n const { log, callbackBeforeRedirect, defaultProductIds, varnish } = config;\n const sharedConfig = {\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n sessionDomain: config.sessionDomain,\n env: config.env,\n window: browserWindow,\n };\n\n this.#identity = new Identity({\n ...sharedConfig,\n log,\n callbackBeforeRedirect,\n });\n\n if (defaultProductIds !== undefined && !Array.isArray(defaultProductIds)) {\n throw new SDKError('Account defaultProductIds config must be an array');\n }\n this.#defaultProductIds = defaultProductIds;\n\n if (varnish) {\n if (typeof varnish !== 'object' || Array.isArray(varnish)) {\n throw new SDKError('Account varnish config must be an object');\n }\n this.#identity.enableVarnishCookie(varnish);\n }\n\n this.#monetization = new Monetization(sharedConfig);\n\n browserWindow.schAccount = this;\n browserWindow.dispatchEvent(\n new CustomEvent('schAccount:ready', { detail: { instance: this } }),\n );\n }\n\n /**\n * Queries Session Service and returns the current browser session state.\n *\n * This call may trigger a full-page session refresh redirect. Configure\n * `callbackBeforeRedirect` if your app needs to persist state before that navigation.\n *\n * @throws {SDKError} If the Session Service call fails.\n */\n hasSession(): Promise<SessionResponse> {\n return this.#identity.hasSession();\n }\n\n /**\n * Checks whether the browser currently has a Schibsted Account session.\n *\n * Returns `false` instead of throwing when the session lookup fails.\n */\n isLoggedIn(): Promise<boolean> {\n return this.#identity.isLoggedIn();\n }\n\n /**\n * Checks whether the current user is connected to the configured client.\n *\n * A user can be logged in to Schibsted Account without being connected to your client, for\n * example before accepting required terms.\n */\n isConnected(): Promise<boolean> {\n return this.#identity.isConnected();\n }\n\n /**\n * Returns the connected user session data.\n *\n * @throws {SDKError} If the user is not connected to the configured client.\n */\n getUser(): Promise<ConnectedSessionResponse> {\n return this.#identity.getUser();\n }\n\n /**\n * Returns the realm-specific Schibsted Account user id as a number.\n *\n * Use `getUserUuid()` when you need the globally unique user id.\n *\n * @throws {SDKError} If the user is not connected to the configured client.\n */\n getUserId(): Promise<number> {\n return this.#identity.getUserId();\n }\n\n /**\n * Returns an external identifier for the authenticated user, scoped to the configured client\n * and external party.\n *\n * @param externalParty - External party for which the identifier is generated.\n * @param optionalSuffix - Optional suffix included when generating the identifier.\n * @throws {SDKError} If the session lookup fails, the session does not contain a `pairId`, or\n * `externalParty` is empty.\n * @deprecated Retained for compatibility with existing integrations. Avoid new usage.\n */\n getExternalId(externalParty: string, optionalSuffix: string = ''): Promise<string> {\n return this.#identity.getExternalId(externalParty, optionalSuffix);\n }\n\n /**\n * Returns the globally unique user id from the current session.\n *\n * @throws {SDKError} If the user is not connected to the configured client.\n */\n getUserUuid(): Promise<string> {\n return this.#identity.getUserUuid();\n }\n\n /**\n * Returns the user SDRN from the current session.\n *\n * @throws {SDKError} If the SDRN is missing from the session response.\n */\n getUserSDRN(): Promise<string> {\n return this.#identity.getUserSDRN();\n }\n\n /**\n * Returns minimal user context for simplified login prompts.\n *\n * Returns `null` if the global account session cannot be read.\n */\n getUserContextData(): Promise<SimplifiedLoginData | null> {\n return this.#identity.getUserContextData();\n }\n\n /**\n * Returns the Varnish `sp_id` value from the current session when present.\n */\n getSpId(): Promise<string | null> {\n return this.#identity.getSpId();\n }\n\n /**\n * Starts the login flow with either a full-page redirect or a popup.\n *\n * Call this from a user gesture when `preferPopup` is enabled, otherwise browser popup blockers\n * may block the popup and the SDK will fall back to redirect navigation.\n *\n * @param options - Login URL parameters.\n * @returns A popup window reference when a popup is opened; otherwise `null`.\n */\n login(options: LoginOptions): Window | null {\n return this.#identity.login(options);\n }\n\n /**\n * Logs the user out from the brand Session Service session and redirects the browser.\n *\n * @param redirectUri - Where Session Service should redirect the browser after logout.\n */\n logout(redirectUri?: string): void {\n this.#identity.logout(redirectUri);\n }\n\n /**\n * Builds the login URL without navigating the browser.\n *\n * @param options - Login URL parameters.\n */\n loginUrl(options: LoginOptions): string {\n return this.#identity.loginUrl(options);\n }\n\n /**\n * Builds the logout URL without navigating the browser.\n *\n * @param redirectUri - Where Session Service should redirect the browser after logout.\n */\n logoutUrl(redirectUri?: string): string {\n return this.#identity.logoutUrl(redirectUri);\n }\n\n /**\n * Builds the Schibsted Account profile page URL.\n *\n * @param redirectUri - Where the account page should redirect the browser afterwards.\n */\n accountUrl(redirectUri?: string): string {\n return this.#identity.accountUrl(redirectUri);\n }\n\n /**\n * Loads and displays the simplified login widget when user context is available.\n *\n * Your application decides how often to call this method. The `state` field in `loginParams`\n * may be a string or a function that resolves to a string.\n * Widget open and cancel events can be observed with `on()`.\n *\n * @returns `true` when the widget was displayed.\n * @throws {SDKError} If user context data is missing or the widget script cannot be loaded.\n */\n showSimplifiedLoginWidget(\n loginParams: SimplifiedLoginWidgetLoginOptions,\n options?: SimplifiedLoginWidgetOptions,\n ): Promise<boolean> {\n return this.#identity.showSimplifiedLoginWidget(loginParams, options);\n }\n\n /**\n * Enables or disables caching for subsequent session lookups.\n *\n * Changing this setting does not remove an existing cached session.\n */\n setSessionCachingEnabled(enabled: boolean): void {\n this.#identity.setSessionCachingEnabled(enabled);\n }\n\n /**\n * Removes the cached Session Service user session response.\n */\n clearCachedUserSession(): void {\n this.#identity.clearCachedUserSession();\n }\n\n /**\n * Checks whether the current user has access to any of the requested products or features.\n *\n * When `productIds` is omitted, the ids configured as `defaultProductIds` are used.\n * Results are cached according to the TTL returned by Session Service.\n *\n * @param productIds - Product or feature ids to check instead of the configured defaults.\n * @returns Access data, or `null` when the user is not entitled.\n * @throws {SDKError} If product ids are not provided or configured, `sessionDomain` is missing,\n * the current user cannot be resolved, input is invalid, or the request fails.\n */\n async hasAccess(productIds = this.#defaultProductIds): Promise<HasAccessResult | null> {\n if (!productIds) {\n throw new SDKError(\n 'hasAccess requires productIds or defaultProductIds in the Account config',\n );\n }\n if (productIds.length === 0) {\n return null;\n }\n\n const userId = await this.#identity.getUserId();\n return this.#monetization.hasAccess(productIds, userId);\n }\n\n /**\n * Removes a cached access-check result.\n *\n * @param productIds - Product or feature ids used for the cached lookup.\n * @param userId - User id used for the cached lookup.\n */\n clearCachedAccessResult(productIds: string[], userId: SessionUserId): void {\n this.#monetization.clearCachedAccessResult(productIds, userId);\n }\n\n /**\n * Subscribes to Account events.\n *\n * Supported event names are defined by {@link AccountEventName}.\n *\n * @param event - Event name.\n * @param listener - Listener that receives an `Event` or `CustomEvent`.\n */\n on<EventName extends AccountEventName>(\n event: EventName,\n listener: AccountEventListener<EventName>,\n ): this;\n on(event: AccountEventName, listener: EventListener): this {\n this.#identity.addEventListener(event, listener);\n\n return this;\n }\n\n /**\n * Unsubscribes from Account events.\n *\n * Supported event names are defined by {@link AccountEventName}.\n *\n * @param event - Event name.\n * @param listener - Listener to remove.\n */\n off<EventName extends AccountEventName>(\n event: EventName,\n listener: AccountEventListener<EventName>,\n ): this;\n off(event: AccountEventName, listener: EventListener): this {\n this.#identity.removeEventListener(event, listener);\n\n return this;\n }\n}\n\nexport default Account;\n","/* Copyright 2026 Schibsted Products & Technology AS. Licensed under the terms of the MIT license.\n * See LICENSE.md in the project root.\n */\n\nimport { Account } from './account.js';\nimport { resolveBrowserWindow } from './resolve-browser-window.js';\nimport type { AccountConfig } from './types/account.js';\n\nconst ACCOUNT_READY_EVENT = 'schAccount:ready';\nconst GET_ACCOUNT_SDK_TIMEOUT_MS = 4000;\n\nlet pendingAccountPromise: Promise<Account> | undefined;\n\nconst createUnavailableError = (): Error =>\n new Error('Schibsted Account SDK is not available in this browser context');\n\nconst createTimeoutError = (): Error =>\n new Error(`Schibsted Account SDK was not initialized within ${GET_ACCOUNT_SDK_TIMEOUT_MS} ms`);\n\n/**\n * Creates and registers the single Account SDK instance for the current browser window.\n *\n * The created instance is stored on `window.schAccount` and the SDK emits\n * `schAccount:ready` with the instance in `event.detail.instance`.\n *\n * @param config - Client, redirect, environment, and Session Service configuration.\n * @throws {SDKError} If the SDK cannot run in the current browser context, if an Account instance\n * has already been initialized, or if configuration validation fails.\n * @group Core API\n */\nexport function createAccountSdk(config: AccountConfig): Account {\n return new Account(config);\n}\n\n/**\n * Resolves the Account SDK instance registered by `createAccountSdk()`.\n *\n * If the instance already exists, the promise resolves immediately. Otherwise it waits for\n * `schAccount:ready` and rejects if initialization does not happen within the SDK timeout.\n * @group Core API\n */\nexport function getAccountSdk(): Promise<Account> {\n const browserWindow = resolveBrowserWindow();\n\n if (!browserWindow) {\n const error = createUnavailableError();\n console.error(error.message);\n return Promise.reject(error);\n }\n\n if (browserWindow.schAccount) {\n return Promise.resolve(browserWindow.schAccount);\n }\n\n if (pendingAccountPromise) {\n return pendingAccountPromise;\n }\n\n pendingAccountPromise = new Promise<Account>((resolve, reject) => {\n let timeoutId: number | undefined;\n\n const cleanup = () => {\n browserWindow.removeEventListener(ACCOUNT_READY_EVENT, resolveRegisteredAccount);\n if (timeoutId !== undefined) {\n browserWindow.clearTimeout(timeoutId);\n }\n pendingAccountPromise = undefined;\n };\n\n const resolveRegisteredAccount = () => {\n const account = browserWindow.schAccount;\n if (!account) {\n return;\n }\n\n cleanup();\n resolve(account);\n };\n\n browserWindow.addEventListener(ACCOUNT_READY_EVENT, resolveRegisteredAccount);\n timeoutId = browserWindow.setTimeout(() => {\n const error = createTimeoutError();\n console.error(error.message);\n cleanup();\n reject(error);\n }, GET_ACCOUNT_SDK_TIMEOUT_MS);\n\n resolveRegisteredAccount();\n });\n\n return pendingAccountPromise;\n}\n"],"mappings":";AAUA,IAAM,IAAkB;CAAC;CAAW;CAAU;AAAQ,GASjC,IAArB,cAAsC,MAAM;CAIxC;CAYA,YAAY,GAAiB,GAAuC;EAIhE,IAHA,MAAM,CAAO,GACb,KAAK,OAAO,YAER,GACA,IAAI;GACA,OAAO,OAAO,MAAM,CAAW;EACnC,QAAQ,CAER;CAER;CAMA,WAAmB;EACf,IAAM,IAAM,GAAG,KAAK,KAAK,IAAI,KAAK,WAC5B,IAAiB,OAAO,KAAK,IAAI,EAClC,QAAQ,MAAQ,MAAQ,UAAU,EAAgB,SAAS,OAAO,KAAK,EAAI,CAAC,EAC5E,KAAK,MAAQ,OAAO,EAAI,IAAI,KAAK,IAAM,EACvC,KAAK,IAAI;EACd,OAAO,IAAiB,GAAG,EAAI,IAAI,MAAmB;CAC1D;AACJ;;;AChDA,SAAS,EAAgB,GAAqD;CAC1E,IAAI,CAAC,GACD,OAAO;CAEX,IAAI;EACA,IAAM,IAAQ,EAAc,GACtB,IAAY,UAAU,QAAQ,YAAY,OAAO,KAAK,OAAO,CAAC,CAAC,GAC/D,IAAY;EAClB,EAAM,QAAQ,GAAW,CAAS;EAClC,IAAM,IAAM,EAAM,QAAQ,CAAS;EAEnC,OADA,EAAM,WAAW,CAAS,GACnB,MAAQ;CACnB,QAAQ;EACJ,OAAO;CACX;AACJ;AAMA,IAAM,IAAN,MAAsB;CAClB;CACA;CACA;CACA;CAOA,YAAY,GAAgB;EAIxB,AAHA,KAAK,QAAQ,GACb,KAAK,OAAO,MAAQ,KAAK,MAAM,QAAQ,CAAG,GAC1C,KAAK,OAAO,GAAK,MAAU,KAAK,MAAM,QAAQ,GAAK,CAAK,GACxD,KAAK,UAAU,MAAQ,KAAK,MAAM,WAAW,CAAG;CACpD;AACJ,GAMM,IAAN,MAAmB;CACf;CACA;CACA;CACA;CAKA,cAAc;EAMV,AALA,KAAK,QAAQ,CAAC,GACd,KAAK,OAAO,MAAQ,KAAK,MAAM,IAC/B,KAAK,OAAO,GAAK,MAAU;GACvB,KAAK,MAAM,KAAO;EACtB,GACA,KAAK,UAAU,MAAQ;GACnB,OAAO,KAAK,MAAM;EACtB;CACJ;AACJ,GAIM,IAAe,KAAK,KAAK,GAMV,IAArB,MAA2B;CACvB;CACA;CAOA,YAAY,GAA+B;EACvC,AAAI,KAAiB,EAAgB,CAAa,KAC9C,KAAK,QAAQ,IAAI,EAAgB,EAAc,CAAC,GAChD,KAAK,OAAO,iBAEZ,KAAK,QAAQ,IAAI,EAAa,GAC9B,KAAK,OAAO;CAEpB;CAOA,IAAI,GAAsB;EAKtB,SAAS,EAAO,GAAmD;GAC/D,IAAI,KAAO,MACP,OAAO;GAEX,IAAI;IACA,OAAO,KAAK,MAAM,CAAG;GACzB,QAAQ;IACJ,OAAO;GACX;EACJ;EAEA,IAAI;GAEA,IAAM,IAAM,EADA,KAAK,MAAM,IAAI,CACR,CAAG;GAKtB,OAJI,KAAO,OAAO,UAAU,EAAI,SAAS,KAAK,EAAI,YAAY,KAAK,IAAI,IAC5D,EAAI,SAEf,KAAK,OAAO,CAAG,GACR;EACX,SAAS,GAAG;GACR,MAAM,IAAI,EAAS,OAAO,CAAC,CAAC;EAChC;CACJ;CASA,IAAI,GAAa,GAAgB,IAAY,GAAS;EAC9C,WAAa,IAGjB;OAAY,KAAK,IAAI,GAAc,CAAS;GAE5C,IAAI;IACA,IAAM,IAAY,KAAK,MAAM,KAAK,IAAI,IAAI,CAAS;IAEnD,AADA,KAAK,MAAM,IAAI,GAAK,KAAK,UAAU;KAAE;KAAW;IAAM,CAAC,CAAC,GACxD,iBAAiB,KAAK,OAAO,CAAG,GAAG,CAAS;GAChD,SAAS,GAAG;IACR,MAAM,IAAI,EAAS,OAAO,CAAC,CAAC;GAChC;EAR4C;CAShD;CAOA,OAAO,GAAmB;EACtB,IAAI;GACA,KAAK,MAAM,OAAO,CAAG;EACzB,SAAS,GAAG;GACR,MAAM,IAAI,EAAS,OAAO,CAAC,CAAC;EAChC;CACJ;AACJ,GCpJM,IAAS;CACX,WAAW;EACP,MAAM;GACF,OAAO;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,QAAQ;GACR,QAAQ;GACR,QAAQ;EACZ;EACA,KAAK;GACD,OAAO;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,QAAQ;GACR,QAAQ;GACR,QAAQ;EACZ;EACA,iBAAiB;GACb,OAAO;GACP,KAAK;GACL,KAAK;GACL,KAAK;GACL,QAAQ;GACR,QAAQ;GACR,QAAQ;EACZ;CACJ;CACA,WAAW;EACP,OAAO;EACP,KAAK;EACL,KAAK;EACL,KAAK;EACL,QAAQ;EACR,QAAQ;EACR,QAAQ;CACZ;AACJ,GAGa,IAAY,EAAO,WACnB,IAAY,EAAO;;;AC7ChC,SAAgB,EAAO,GAAoB,IAAU,oBAAuC;CACxF,IAAI,CAAC,GACD,MAAM,IAAI,EAAS,CAAO;AAElC;AAMA,SAAgB,EAAM,GAAiC;CACnD,OAAO,OAAO,KAAU;AAC5B;AAMA,SAAgB,EAAiB,GAAiC;CAC9D,OAAO,OAAO,KAAU,YAAY,EAAM,SAAS;AACvD;AAMA,SAAgB,EAAS,GAAkD;CACvE,OAAO,OAAO,KAAU,cAAY;AACxC;AAMA,SAAgB,EAAc,GAAkD;CAC5E,OAAO,EAAS,CAAK,KAAK,OAAO,KAAK,CAAK,EAAE,SAAS;AAC1D;AAQA,SAAgB,EAAM,GAAe,GAAG,GAAyC;CAC7E,IAAI;EACA,IAAM,IAAY,IAAI,IAAI,CAAK;EAC/B,OAAO,EAAgB,OAAO,MAAM,EAAU,EAAE;CACpD,QAAQ;EACJ,OAAO;CACX;AACJ;AAMA,SAAgB,EAAW,GAA0D;CACjF,OAAO,OAAO,KAAU;AAC5B;AASA,SAAgB,EAAQ,GAAe,GAAyB,IAAgB,IAAgB;CAS5F,OANM,EAAM,CAAK,KAAK,MAAM,QAAQ,CAAa,IAG7C,IACO,EAAc,QAAQ,CAAK,MAAM,KAErC,EAAc,MARc,MAC/B,EAAM,CAAG,KAAK,EAAM,YAAY,MAAM,EAAI,YAAY,CAOP,IALxC;AAMf;;;AC5EA,SAAgB,EAAa,GAAG,GAA4C;CACxE,IAAM,IAAkC,CAAC;CACzC,IAAI,EAAE,KAAW,EAAQ,SACrB,MAAM,IAAI,EAAS,qBAAqB;CAY5C,OAVA,EAAQ,SAAS,MAAW;EAExB,AADA,EAAO,EAAS,CAAM,CAAC,GACnB,EAAc,CAAM,KACpB,OAAO,QAAQ,CAAM,EAAE,SAAS,CAAC,GAAK,OAAW;GAC7C,AAAW,MAAU,WACjB,EAAO,KAAO,EAAS,CAAK,IAAI,EAAU,CAAK,IAAI;EAE3D,CAAC;CAET,CAAC,GACM;AACX;AAQA,SAAgB,EAAmC,GAAW;CAE1D,OADA,EAAO,OAAO,KAAQ,UAAU,iDAAiD,GAAK,GAC/E,KAAK,MAAM,KAAK,UAAU,CAAG,CAAC,KAAK;AAC9C;;;ACvCA,SAAS,EAAU,GAAsC;CAErD,OADA,EAAO,EAAS,CAAG,GAAG,uCAAuC,EAAI,EAAE,GAC5D,OAAO,KAAK,CAAG,EACjB,KAAK,MAAQ,GAAG,EAAI,GAAG,EAAI,IAAM,EACjC,KAAK,GAAG;AACjB;AAEA,IAAM,KAAwB;CAC1B,YAAY;CACZ,UAAU;CACV,QAAQ;CACR,SAAS;CACT,SAAS;CACT,WAAW;AACf;AAUA,SAAgB,GACZ,GACA,GACA,IAAa,IACb,IAAkD,CAAC,GACtC;CAUb,AATA,EAAO,EAAS,CAAY,GAAG,iDAAiD,GAAc,GAC9F,EACI,EAAS,EAAa,MAAM,GAC5B,yEACJ,GACA,EACI,EAAW,EAAa,IAAI,GAC5B,wEACJ,GACA,EAAO,EAAM,CAAG,GAAG,uBAAuB;CAE1C,IAAM,EAAE,WAAQ,aAAU,EAAa,QAEjC,IAAiB,EAAa,IAAuB,CAAc,GACnE,EAAE,OAAO,GAAc,QAAQ,MAAkB;CAQvD,AANI,OAAO,KAAiB,YACxB,OAAO,SAAS,CAAY,KAC5B,OAAO,SAAS,CAAK,MAErB,EAAe,QAAQ,IAAQ,KAAgB,IAG/C,OAAO,KAAkB,YACzB,OAAO,SAAS,CAAa,KAC7B,OAAO,SAAS,CAAM,MAEtB,EAAe,OAAO,IAAS,KAAiB;CAEpD,IAAM,IAAW,EAAU,CAAc;CACzC,OAAO,EAAa,KAAK,GAAK,GAAY,CAAQ;AACtD;;;AC5DA,SAAgB,EAAU,GAAa,GAAwC;CAM3E,OALA,EAAO,EAAiB,CAAG,GAAG,2CAA2C,OAAO,GAAK,GACjF,EAAc,CAAM,KAAK,EAAM,EAAO,EAAI,IACnC,EAAO,MAElB,EAAO,EAAM,GAAK,UAAU,GAAG,mBAAmB,EAAI,EAAE,GACjD;AACX;;;ACLA,IAAM,MAAa,MACf,EAAI,KAAK,MAAO,EAAS,CAAC,IAAI,KAAK,UAAU,GAAG,MAAM,CAAC,IAAI,CAAE,EAAE,KAAK,GAAG,GAErE,KAAS,GAA6B,GAAG,MAAyB;CACpE,AAAI,KACA,EAAG,GAAU,CAAG,CAAC;AAEzB;AAOA,SAAS,EAAO,GAAqB;CACjC,IAAM,IAAkC;EACpC,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,OAAO;EACP,OAAO;CACX;CACA,OAAO,mBAAmB,CAAG,EAAE,QAAQ,qBAAqB,MAAU,EAAQ,EAAM;AACxF;AAEA,IAAM,WAAoB,OAAO,SAAS,OAAO,MAAM,KAAK,MAAM,GAC5D,UAA+B;CACjC,MAAM,IAAI,EAAS,4CAA4C;AACnE,GAyCa,IAAb,MAAa,EAAW;CACpB;CACA;CACA;CACA;CAcA,YAAY,EACR,eAAY,OACZ,WACA,WAAQ,GAAY,KAAK,GACzB,QACA,mBAAgB,CAAC,KAOlB;EACC,EAAO,EAAS,CAAa,GAAG,2CAA2C;EAE3E,IAAM,IAAY,EAAU,GAAW,KAAU,CAAC,CAAC,GAC7C,IAAmB,EAAU,SAAS,GAAG,IAAI,IAAY,GAAG,EAAU;EAU5E,AATA,KAAK,MAAM,IAAI,IAAI,CAAgB,GAEnC,KAAK,gBAAgB,GAEjB,MACA,EAAO,EAAW,CAAG,GAAG,oCAAoC,GAAK,GACjE,KAAK,MAAM,IAGf,KAAK,QAAQ;CACjB;CAsBA,MAAM,GAAkB,GAAwD;EAC5E,IAAM,EACF,WACA,YACA,aACA,UAAO,CAAC,GACR,sBAAmB,IACnB,kBAAe;GAAE,QAAQ,EAAQ;GAAQ,aAAa;EAAU,GAChE,qBACA;EAKJ,AAJA,EAAO,EAAiB,CAAM,GAAG,gDAAgD,EAAO,EAAE,GAC1F,EAAO,EAAiB,CAAQ,GAAG,sCAAsC,EAAS,EAAE,GACpF,EAAO,EAAS,CAAI,GAAG,gCAAgC,GAEvD,EAAa,UAAU,EAAS,CAAO,IAAI,IAAU,CAAC;EACtD,IAAM,IAAU,KAAK,QAAQ,GAAU,GAAM,CAAgB;EAI7D,AAFA,EAAM,KAAK,KAAK,YAAY,EAAO,YAAY,GAAG,CAAO,GACzD,EAAM,KAAK,KAAK,oBAAoB,EAAa,OAAO,GACxD,EAAM,KAAK,KAAK,iBAAiB,EAAa,IAAI;EAClD,IAAI;GACA,IAAM,IAAW,MAAM,KAAK,MAAM,GAAS,CAAY;GAEvD,IADA,EAAM,KAAK,KAAK,kBAAkB,EAAS,QAAQ,EAAS,UAAU,GAClE,CAAC,EAAS,IAEV,MAAM,IAAI,EAAS,EAAS,YAAY,EAAE,MAAM,EAAS,OAAO,CAAC;GAErE,IAAM,IAA4B,MAAM,EAAS,KAAK;GAEtD,OADA,EAAM,KAAK,KAAK,oBAAoB,CAAc,GAC3C,IAAgB,EAAc,CAAc,IAAI;EAC3D,SAAS,GAAc;GACnB,IAAI,IAAM,EAAM,CAAG,IAAI,IAAM;GAC7B,AAAI,EAAS,CAAG,KAAK,EAAM,EAAI,OAAO,MAClC,IAAM,EAAI;GAEd,IAAM,IAAc,EAAS,CAAG,IAAI,IAAM,KAAA;GAC1C,MAAM,IAAI,EAAS,cAAc,EAAO,KAAK,EAAQ,MAAM,EAAI,IAAI,CAAW;EAClF;CACJ;CAQA,QAAQ,IAAW,IAAI,IAAqB,CAAC,GAAG,IAAmB,IAAc;EAC7E,IAAM,IAAkB,EAAS,WAAW,GAAG,IAAI,EAAS,MAAM,CAAC,IAAI,GAEjE,IAAM,IAAI,IAAI,GAAiB,KAAK,GAAG;EAE7C,OADA,EAAI,SAAS,EAAW,OAAO,GAAO,GAAkB,KAAK,aAAa,GACnE,EAAI;CACf;CAgBA,IACI,GACA,GACA,GACsB;EAItB,OAHI,IACO,KAAK,GAAG;GAAE,QAAQ;GAAO;GAAU;GAAM;EAAc,CAAC,IAE5D,KAAK,GAAG;GAAE,QAAQ;GAAO;GAAU;EAAK,CAAC;CACpD;CASA,OAAe,OACX,GACA,GACA,GACM;EACN,IAAM,IAAS,IAAmB,EAAa,GAAe,CAAK,IAAI,EAAa,CAAK;EACzF,OAAO,OAAO,KAAK,CAAM,EACpB,QAAQ,MAAM,EAAO,OAAO,EAAE,EAC9B,KAAK,MAAM,GAAG,EAAO,CAAC,EAAE,GAAG,EAAO,OAAO,EAAO,EAAE,CAAC,GAAG,EACtD,KAAK,GAAG;CACjB;AACJ,GC3OM,KAAoB,MACtB,OAAO,OAAO,GAAW,CAAG,GAEnB,KAAmB,GAAa,OACzC,EAAO,EAAiB,CAAQ,GAAG,gCAAgC,GACnE,EAAO,EAAiB,CAAG,GAAG,6BAA6B,GAAK,GAEzD,QAAQ,EAAU,GAAK,UAAU,MAG/B,KAA2B,EACpC,cACA,QACA,uBACwC,IAAI,EAAW;CAAE;CAAW;CAAK;AAAc,CAAC;;;ACR5F,SAAgB,EAAyB,GAAiD;CACtF,OAAO,EAAS,CAAK,KAAK,OAAO,EAAM,UAAW;AACtD;AAQA,SAAgB,EAA2B,GAAmD;CAC1F,OAAO,EAAyB,CAAK,KAAK,EAAM,WAAW;AAC/D;AAQA,SAAgB,EAAyB,GAAiD;CACtF,OAAO,EAAS,CAAK,KAAK,EAAQ,EAAM;AAC5C;AAEA,SAAgB,EAAyB,GAAiD;CACtF,OAAO,EAAS,CAAK,KAAK,OAAO,KAAK,CAAK,EAAE,WAAW,KAAK,EAAM,EAAM,WAAW;AACxF;AAQA,SAAgB,EACZ,GAC2C;CAC3C,OAAO,EAA2B,CAAK,KAAK,OAAO,EAAM,UAAW;AACxE;AAyBA,SAAgB,EAAyB,GAA0C;CAc/E,OAbI,EAAyB,CAAK,KAG9B,EAAyB,CAAK,KAG9B,EAAyB,CAAK,KAG9B,EAAS,CAAK,IACP,IAGJ,CAAC;AACZ;;;AC1EA,SAAgB,EAAQ,GAAsB;CAO1C,CANI,CAAC,EAAO,QAAQ,OAAO,EAAO,QAAS,cACvC,EAAO,OAAO,CAAC,KAEf,CAAC,EAAO,KAAK,QAAQ,OAAO,EAAO,KAAK,QAAS,cACjD,EAAO,KAAK,OAAO,CAAC,IAEnB,EAAW,EAAO,KAAK,KAAK,QAAQ,MACrC,EAAO,KAAK,KAAK,YAAY,GAAsB,MAC9C,EAAe,GAAc,CAAI;AAE9C;;;AC6GA,IAAa,KACT,MAEO,OAAO,EAAa,6BAA8B,YClJvD,IAAU,iBCkDV,IAAwB,oBACxB,IAAiC,4BACjC,IAA2B,MAAO,KAAK,GAEvC,IAAa,gBACb,IAAS,KAAK,MAAM,KAAK,OAAO,IAAI,GAAM,GAC1C,IAAa,MAAO,KAAK,KAAK,KAAK,IAEnC,UAAqB,QAKd,IAAb,MAAsB;CAElB,cAA+B,IAAI,YAAY;CAG/C;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CAOA;CACA;CAGA;CACA;CACA;CACA;CAcA,YAAY,EACR,aACA,gBACA,kBACA,SAAM,OACN,QACA,YAAS,EAAa,GACtB,kCAA+B,CAAC,KAChB;EAuBhB,AAtBA,EAAO,EAAiB,CAAQ,GAAG,gCAAgC,GACnE,EAAO,EAAS,CAAM,GAAG,oCAAoC,GAC7D,EAAO,CAAC,KAAe,EAAM,CAAW,GAAG,kCAAkC,GAC7E,EACI,EAAiB,CAAa,KAAK,EAAM,CAAa,GACtD,4CACJ,GACA,EAAO,EAAM,CAAG,GAAG,6BAA6B,GAAK,GAErD,EAAiB,CAAM,GACvB,KAAK,SAAS,GACd,KAAK,WAAW,GAChB,KAAK,cAAc,GACnB,KAAK,MAAM,GACX,KAAK,MAAM,GACX,KAAK,yBAAyB,GAE9B,KAAK,sBAAsB,IAAI,QAAY,KAAK,UAAU,KAAK,OAAO,cAAc,GACpF,KAAK,oBAAoB,IAAI,QAAY,KAAK,UAAU,KAAK,OAAO,YAAY,GAEhF,KAAK,uBAAuB,IAE5B,KAAK,UAAU,CAAC;EAEhB,IAAM,IAAsB;GAAE,WAAW,KAAK;GAAU,cAAc,KAAK;EAAY,GACjF,IAAa,EAAgB,KAAK,KAAK,KAAK,QAAQ;EAoC1D,AAlCA,KAAK,OAAO,EAAwB;GAChC,WAAW,EAAU,GAAK,EAAU,IAAI;GACxC,KAAK,KAAK;GACV,eAAe;EACnB,CAAC,GACD,KAAK,eAAe,EAAwB;GACxC,WAAW,EAAU,GAAK,EAAU,IAAI;GACxC,KAAK,KAAK;GACV,eAAe;EACnB,CAAC,GACD,KAAK,aAAa,EAAwB;GACtC,WAAW,EAAU,GAAK,EAAU,GAAG;GACvC,KAAK,KAAK;GACV,eAAe;EACnB,CAAC,GACD,KAAK,iBAAiB,EAAwB;GAC1C,WAAW;GACX,KAAK,KAAK;GACV,eAAe;IACX,aAAa;IACb,cAAc,KAAK;IACnB,aAAa;GACjB;EACJ,CAAC,GACD,KAAK,uBAAuB,EAAwB;GAChD,WAAW,EAAU,GAAK,EAAU,eAAe;GACnD,KAAK,KAAK;GACV,eAAe;IAAE,aAAa;IAAY,aAAa;GAAQ;EACnE,CAAC,GACD,KAAK,uCACD,KAAK,eAAe,IAAI,YAAY,KAAK,eAAe,IAAI,SAAS,UAAU,IACzE,eACA,WAEV,KAAK,oBAAoB;CAC7B;CAEA,iBAAiB,GAAwB,GAA+B;EACpE,KAAK,YAAY,iBAAiB,GAAM,CAAQ;CACpD;CAEA,oBAAoB,GAAwB,GAA+B;EACvE,KAAK,YAAY,oBAAoB,GAAM,CAAQ;CACvD;CAMA,YAAgC;EAC5B,IAAI,KAAK,sBAAsB;GAC3B,IAAM,IAAQ,KAAK,oBAAoB,IAAI,CAAU;GAMrD,OALI,OAAO,KAAU,WAKd,KAJH,KAAK,oBAAoB,IAAI,GAAY,GAAQ,CAAU,GACpD;EAIf;CACJ;CAOA,wBAAiC;EAC7B,OAAO,EAAQ,KAAK,kBAAkB,IAAI,CAA8B;CAC5E;CAOA,oBAA0B;EAGtB,KAAK,kBAAkB,IACnB,GACA,IACA,CACJ;CACJ;CAOA,sBAA4B;EACxB,KAAK,kBAAkB,OAAO,CAA8B;CAChE;CAMA,cAAoB;EAChB,AAII,KAAK,WAHA,KAAK,MAAM,UACZ,KAAK,MAAM,MAAM,GAER;CAErB;CAUA,oBAAoB,GAAqC;EACrD,IAAI,OAAO,KAAY,UACnB,MAAM,IAAI,EAAS,wCAAwC;EAG/D,IAAM,EAAE,eAAY,GAAG,cAAW;EAMlC,AAJA,EAAO,OAAO,UAAU,CAAS,GAAG,gCAAgC,GACpE,EAAO,KAAa,GAAG,gCAAgC,GACvD,KAAK,mBAAmB,IACxB,KAAK,mBAAmB,GACxB,KAAK,sBAAsB;CAC/B;CAOA,uBAAuB,GAA2B;EAC9C,IAAI,CAAC,KAAK,oBAAoB,CAAC,EAAyB,CAAW,GAC/D;EAEJ,IAAM,oBAAO,IAAI,KAAK;EAItB,IAFI,KAAK,oBACJ,OAAO,EAAY,aAAc,YAAY,EAAY,YAAY,GACxD;GACd,IAAM,IAAU,KAAK,oBAAoB,EAAY,aAAa;GAClE,EAAK,QAAQ,EAAK,QAAQ,IAAI,IAAU,GAAI;EAChD,OACI,EAAK,QAAQ,CAAC;EAIlB,IAAM,IACF,KAAK,wBACJ,OAAO,EAAY,cAAe,WAC7B,EAAY,aACZ,KAAK,OAAO,SAAS,aAC3B,IAEE,IAAS;GACX,SAAS,EAAY;GACrB,WAAW,EAAK,YAAY;GAC5B;GACA,WAAW;EACf,EAAE,KAAK,IAAI;EACX,SAAS,SAAS;CACtB;CAMA,2BAAiC;EAC7B,AAAI,KAAK,oBACL,KAAK,oBAAoB;CAEjC;CAMA,sBAA4B;EACxB,IAAM,IACF,KAAK,WACL,EAAyB,KAAK,OAAO,KACrC,OAAO,KAAK,QAAQ,cAAe,WAC7B,KAAK,QAAQ,aACb,KAAK,OAAO,SAAS,UAEzB,IAAS,KAAK,uBAAuB,KAAc;EAEzD,SAAS,SAAS,yEAAyE;CAC/F;CASA,aAAuC;EAGnC,IAF6B,KAAK,sBAE9B,GAAsB;GACtB,IAAM,IAAc,EAAyB,KAAK,OAAO;GACzD,OAAO,QAAQ,QAAQ,EAAyB,CAAW,IAAI,CAAC,IAAI,CAAW;EACnF;EAEA,IAAI,KAAK,sBACL,OAAO,KAAK;EAGhB,IAAM,KAAgB,MAA8D;GAChF,IAAI,EAAyB,CAAW,GAIpC,MAAM,IAAI,EAAS,qBAHC,EAAS,EAAY,KAAK,IACxC,EAAY,QACZ,EAAE,aAAa,OAAO,EAAY,KAAK,EAAE,CACI;GAIvD,OAFA,KAAK,uBAAuB,CAAW,GACvC,KAAK,UAAU,GACR;EACX,GAEM,UAA2D;GAC7D,IAAM,IAAgB,KAAK,oBAAoB,IAAI,CAAqB;GACxE,OAAO,IAAgB,EAAyB,CAAa,IAAI;EACrE,GAEM,IAAc,YAAsC;GACtD,IAAI,KAAK,sBAAsB;IAE3B,IAAM,IAAgB,EAAkB;IACxC,IAAI,GAIA,OAHI,EAAyB,CAAa,IAC/B,CAAC,IAEL,EAAa,CAAa;GAEzC;GACA,IAAI,IAA+C;GACnD,IAAI;IACA,IAAc,MAAM,KAAK,eAAe,IACpC,KAAK,sCACL,EAAE,OAAO,KAAK,UAAU,EAAE,GAC1B,CACJ;GACJ,SAAS,GAAc;IACnB,IAAM,IAAiB,EAAS,CAAG,IAAI,IAAM,KAAA;IAC7C,IAAI,GAAgB,SAAS,OAAO,KAAK,sBAAsB;KAK3D,IAAM,IAAY,OAHd,OAAO,EAAe,aAAc,WAC9B,EAAe,YACf;KAEV,KAAK,oBAAoB,IAAI,GAAuB,EAAE,OAAO,EAAI,GAAG,CAAS;IACjF,OAAO,AACH,KACA,OAAO,EAAe,QAAS,YAC/B,EAAe,QAAQ,OACvB,EAAe,OAAO,OACtB,KAAK,wBAGL,KAAK,oBAAoB,IAAI,GAAuB,EAAE,OAAO,EAAI,GAAG,KAAK,GAAI;IAEjF,MAAM;GACV;GAEA,IAAI,GAAa;IAEb,IAAI,EAAyB,CAAW,GAQpC,OAPA,KAAK,kBAAkB,GAEvB,MAAM,KAAK,uBAAuB,GAEd,KAAK,eAAe,QAAQ,EAAY,aAAa,EACrE,OAAO,KAAK,UAAU,EAC1B,CACO;IAGX,IAAI,KAAK,sBAAsB;KAC3B,IAAM,IACF,OACC,EAAyB,CAAW,KAC/B,EAAY,aACZ;KACV,KAAK,oBAAoB,IAAI,GAAuB,GAAa,CAAS;IAC9E;GACJ;GAEA,OAAO,EAAa,KAAe,CAAC,CAAC;EACzC;EAeA,OAdA,KAAK,uBAAuB,EAAY,EAAE,MACrC,OACG,KAAK,uBAAuB,IACxB,OAAO,KAAgB,aACvB,KAAK,OAAO,SAAS,OAAO,IAEzB,KAEV,MAAQ;GAEL,MADA,KAAK,uBAAuB,IACtB,IAAI,EAAS,qBAAqB,CAAG;EAC/C,CACJ,GAEO,KAAK;CAChB;CAOA,MAAM,aAA+B;EACjC,IAAI;GAEA,OAAO,EAAyB,MADb,KAAK,WAAW,CACC;EACxC,QAAY;GACR,OAAO;EACX;CACJ;CAQA,yBAAyB,GAAwB;EAC7C,KAAK,uBAAuB;CAChC;CAKA,yBAA+B;EAC3B,KAAK,oBAAoB,OAAO,CAAqB;CACzD;CAUA,MAAM,cAAgC;EAClC,IAAI;GACA,OAAO,EAA2B,MAAM,KAAK,WAAW,CAAC;EAC7D,QAAY;GACR,OAAO;EACX;CACJ;CASA,MAAM,UAA6C;EAC/C,IAAM,IAAO,MAAM,KAAK,WAAW;EACnC,IAAI,CAAC,EAA2B,CAAI,GAChC,MAAM,IAAI,EAAS,4CAA4C;EAEnE,OAAO,EAAU,CAAI;CACzB;CAcA,MAAM,YAA6B;EAC/B,IAAM,IAAO,MAAM,KAAK,WAAW;EACnC,IAAI,EAAqC,CAAI,GACzC,OAAO,EAAK;EAEhB,MAAM,IAAI,EAAS,4CAA4C;CACnE;CAuBA,MAAM,cAAc,GAAuB,IAAyB,IAAqB;EACrF,IAAM,IAAO,MAAM,KAAK,WAAW,GAC7B,IAAS,EAAyB,CAAI,IAAI,EAAK,SAAS,KAAA;EAE9D,IAAI,CAAC,GAAQ,MAAM,IAAI,EAAS,iCAAiC;EAEjE,IAAI,CAAC,KAAiB,EAAc,WAAW,GAC3C,MAAM,IAAI,EAAS,+BAA+B;EAEtD,IAAM,KAAgB,MAEA,MAAM,KAAK,IAAI,WAAW,CAAU,CAE/C,EAAU,KAAK,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE,GAGlE,KAAoB,MACf,OAAO,OAAO,OAAO,WAAW,CAAI;EAkB/C,QAAO,OAfqB,MAEjB,EADU,IAAI,YAAY,EAAE,OAAO,CAClB,CAAQ,EAAE,MAAM,MAAO,EAAa,CAAE,CAAC,KAI/D,GACA,GACA,MAEO,IACD,GAAG,EAAO,GAAG,EAAc,GAAG,MAC9B,GAAG,EAAO,GAAG,KAGe,GAAQ,GAAe,CAAc,CAAC;CAChF;CAQA,MAAM,cAA+B;EACjC,IAAM,IAAO,MAAM,KAAK,WAAW;EACnC,IAAI,EAAyB,CAAI,KAAK,EAAK,MACvC,OAAO,EAAK;EAEhB,MAAM,IAAI,EAAS,sCAAsC;CAC7D;CAcA,MAAM,cAA+B;EACjC,IAAM,IAAO,MAAM,KAAK,WAAW;EACnC,IAAI,EAAyB,CAAI,KAAK,EAAK,QAAQ,EAAK,QACpD,OAAO,EAAK;EAEhB,MAAM,IAAI,EAAS,4CAA4C;CACnE;CAUA,MAAM,qBAA0D;EAC5D,IAAI;GACA,OAAO,MAAM,KAAK,qBAAqB,IAAI,gBAAgB,KAAA,IAAY,MACnE,EAAS,CAAK,KAAK,EAAM,EAAM,UAAU,IACnC;IACI,YAAY,EAAM;IAClB,cAAc,EAAM,EAAM,YAAY,IAAI,EAAM,eAAe;IAC/D,aAAa,EAAM,EAAM,WAAW,IAAI,EAAM,cAAc;IAC5D,aAAa,EAAM,EAAM,WAAW,IAAI,EAAM,cAAc,KAAA;GAChE,IACA,IACV;EACJ,QAAY;GACR,OAAO;EACX;CACJ;CA4BA,MAAM,EACF,UACA,cACA,WAAQ,UACR,iBAAc,KAAK,aACnB,iBAAc,IACd,eAAY,IACZ,SAAM,IACN,YAAS,IACT,YAAS,IACT,WACA,kBAAe,IACf,YAAS,kBACT,eAAY,IACZ,oBAAiB,IACjB,oBAAiB,MACW;EAE5B,AADA,KAAK,YAAY,GACjB,KAAK,oBAAoB,OAAO,CAAqB;EACrD,IAAM,IAAM,KAAK,SAAS;GACtB;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACJ,CAAC;EA0BD,OAxBI,MACA,KAAK,QAAQ,GAAW,KAAK,QAAQ,GAAK,qBAAqB;GAC3D,OAAO;GACP,QAAQ;EACZ,CAAC,GAEG,KAAK,UACL,KAAK,YAAY,cACb,IAAI,YAAY,kBAAkB,EAC9B,QAAQ;GAAE;GAAK,QAAQ;EAAQ,EACnC,CAAC,CACL,GAEO,KAAK,UAIpB,KAAK,YAAY,cACb,IAAI,YAAY,kBAAkB,EAC9B,QAAQ;GAAE;GAAK,QAAQ;EAAU,EACrC,CAAC,CACL,GACA,KAAK,OAAO,SAAS,OAAO,GAErB;CACX;CAQA,MAAM,UAAkC;EACpC,IAAI;GACA,IAAM,IAAO,MAAM,KAAK,WAAW;GACnC,IAAI,EAAyB,CAAI,GAC7B,OAAO,EAAK,SAAS;GAEzB,IAAM,IAAO,EAAS,CAAI,KAAK,WAAW,IAAO,EAAK,QAAQ,KAAA;GAC9D,OAAO,EAAM,CAAI,IAAI,IAAO;EAChC,QAAY;GACR,OAAO;EACX;CACJ;CAOA,OAAO,IAAsB,KAAK,aAAmB;EAEjD,AADA,KAAK,oBAAoB,OAAO,CAAqB,GACrD,KAAK,yBAAyB;EAC9B,IAAM,IAAM,KAAK,UAAU,CAAW;EAMtC,AALA,KAAK,YAAY,cACb,IAAI,YAAY,mBAAmB,EAC/B,QAAQ,EAAE,OAAI,EAClB,CAAC,CACL,GACA,KAAK,OAAO,SAAS,OAAO;CAChC;CAqBA,SAAS,EACL,UACA,eAAY,IACZ,WAAQ,UACR,iBAAc,KAAK,aACnB,eAAY,IACZ,SAAM,IACN,YAAS,IACT,YAAS,IACT,WACA,kBAAe,IACf,YAAS,kBACT,eAAY,IACZ,oBAAiB,IACjB,oBAAiB,MACI;EAsBrB,OAfA,EACI,CAAC,KACG,EAAQ,GAAW,CAAC,IAAI,WAAW,GAAG,EAAI,KAC1C,EAAU,MAAM,GAAG,EAAE,OATJ,MACrB,EACI,GACA;GAAC;GAAY;GAAO;GAAO;GAAU;GAAU;GAAU;GAAU;EAAK,GACxE,EACJ,CAI8C,GAC9C,8CAA8C,GAClD,GACA,EACI,EAAM,CAAW,GACjB,sDAAsD,GAC1D,GACA,EACI,EAAiB,CAAK,GACtB,8DAA8D,GAClE,GAEO,KAAK,aAAa,QAAQ,mBAAmB;GAChD,eAAe;GACf,cAAc;GACd;GACA;GACA,YAAY;GACZ,YAAY;GACZ;GACA;GACA,SAAS;GACT;GACA,gBAAgB,KAAgB;GAChC,QAAQ,IAAY,KAAK;GACzB,aAAa;GACb,UAAU;GACV,cAAc;EAClB,CAAC;CACL;CAOA,UAAU,IAAsB,KAAK,aAAqB;EACtD,EAAO,EAAM,CAAW,GAAG,qCAAqC;EAChE,IAAM,IAAS,EAAE,cAAc,EAAY;EAC3C,OAAO,KAAK,eAAe,QAAQ,UAAU,CAAM;CACvD;CAMA,WAAW,IAAsB,KAAK,aAAqB;EACvD,OAAO,KAAK,KAAK,QAAQ,iBAAiB;GACtC,eAAe;GACf,cAAc;EAClB,CAAC;CACL;CAeA,MAAM,0BACF,GACA,GACgB;EAEhB,IAAM,IAAW,MAAM,KAAK,mBAAmB,GAEzC,IAAsC,EAAE,WAAW,KAAK,SAAS;EACvE,AAAI,KAAW,EAAQ,aACnB,EAAY,WAAW,EAAQ;EAEnC,IAAM,IAAY,KAAK,WAAW,QAAQ,2BAA2B,GAAa,EAAK,GAEjF,IAAqB,OACvB,MACwB;GACxB,IAAM,IACF,OAAO,EAAY,SAAU,aACvB,MAAM,EAAY,MAAM,IACxB,EAAY;GAEtB,OAAO;IACH,GAAG;IACH;GACJ;EACJ;EAEA,OAAO,IAAI,SAAkB,GAAS,MAAW;GAC7C,IAAI,CAAC,GAAU,gBAAgB,CAAC,EAAS,YAAY;IACjD,EAAO,IAAI,EAAS,mBAAmB,CAAC;IACxC;GACJ;GAEA,IAAM,IAAoD;IACtD,aAAa,EAAS;IACtB,KAAK,KAAK;IACV,YAAY,EAAS,eAAe;IACpC,UAAU,KAAK;IACf,YAAY,EAAS;IACrB,mBAAmB,OAAO;IAC1B,iBAAiB,MAAkB;KAC/B,OAAO,WAAW;IACtB;GACJ;GAEA,AAAI,KAAW,EAAQ,WACnB,EAAc,SAAS,EAAQ;GAGnC,IAAM,IAAe,YAAY;IAC7B,KAAK,MACD,OAAO,OAAO,MAAM,EAAmB,CAAW,GAAG,EACjD,WAAW,EAAS,WACxB,CAAC,CACL;GACJ,GAEM,IAAqB,YAAY;IACnC,KAAK,MACD,OAAO,OAAO,MAAM,EAAmB,CAAW,GAAG;KACjD,WAAW,EAAS;KACpB,QAAQ;IACZ,CAAC,CACL;GACJ,GAEM,UAAoB;IAKtB,KAAK,YAAY,cAAc,IAAI,MAAM,uBAAuB,CAAC;GACrE,GAEM,UAA2B;IAC7B,KAAK,YAAY,cAAc,IAAI,MAAM,0BAA0B,CAAC;GACxE;GAEA,IAAI,EAA6B,MAAM,GAQnC,OAPA,OAAO,0BACH,GACA,GACA,GACA,GACA,CACJ,GACO,EAAQ,EAAI;GAGvB,IAAM,IAAwB,SAAS,cAAc,QAAQ;GAoB7D,AAnBA,EAAsB,OAAO,mBAC7B,EAAsB,MAAM,GAC5B,EAAsB,eAAe;IACjC,IAAI,CAAC,EAA6B,MAAM,GAAG;KACvC,EAAO,IAAI,EAAS,oDAAoD,CAAC;KACzE;IACJ;IAQA,AAPA,OAAO,0BACH,GACA,GACA,GACA,GACA,CACJ,GACA,EAAQ,EAAI;GAChB,GACA,EAAsB,gBAAgB;IAClC,EAAO,IAAI,EAAS,oDAAoD,CAAC;GAC7E,GACA,SAAS,qBAAqB,MAAM,EAAE,GAAG,YAAY,CAAqB;EAC9E,CAAC;CACL;AACJ;;;AC1+BA,SAAgB,EAAqB,GAAiC;CAClE,IAAI,CAAC,EAAS,CAAK,GACf,MAAM,IAAI,EAAS,4BAA4B;CAGnD,IAAM,EAAE,aAAU,QAAK,oBAAiB,WAAQ,SAAM,WAAQ;CAE9D,IACI,OAAO,KAAa,aACpB,OAAO,KAAQ,YACf,CAAC,MAAM,QAAQ,CAAe,KAC9B,OAAO,KAAW,YAClB,CAAC,EAAM,CAAI,KACX,CAAC,EAAM,CAAG,GAEV,MAAM,IAAI,EAAS,4BAA4B;CAGnD,OAAO;EACH;EACA;EACA,iBAAiB,EAAgB,OAAO,CAAK;EAC7C;EACA;EACA;CACJ;AACJ;;;ACnBA,IAAM,UAAqB,QAKd,IAAb,MAA0B;CACtB;CACA;CACA;CAMA,YAAY,EACR,aACA,gBACA,SAAM,OACN,kBACA,YAAS,EAAa,KACF;EAGpB,AAFA,EAAiB,CAAM,GACvB,EAAO,EAAiB,CAAQ,GAAG,gCAAgC,GACnE,EAAO,EAAM,CAAG,GAAG,6BAA6B,GAAK;EACrD,IAAM,IAAa,EAAgB,GAAK,CAAQ;EAKhD,AAHA,KAAK,QAAQ,IAAI,QAAY,KAAU,EAAO,cAAc,GAC5D,KAAK,2BAA2B,CAAC,GAE7B,MACA,EAAO,EAAM,CAAa,GAAG,4CAA4C,GACzE,KAAK,iBAAiB,EAAwB;GAC1C,WAAW;GACX,eAAe;IACX,aAAa;IACb,cAAc;IACd,aAAa;GACjB;EACJ,CAAC;CAET;CAWA,MAAM,UAAU,GAAsB,GAAwD;EAC1F,IAAI,CAAC,KAAK,gBACN,MAAM,IAAI,EAAS,+DAA+D;EAEtF,IAAI,CAAC,GACD,MAAM,IAAI,EAAS,4BAA4B;EAEnD,IAAI,CAAC,MAAM,QAAQ,CAAU,GACzB,MAAM,IAAI,EAAS,+BAA+B;EAGtD,IAAM,IAAY,CAAC,GAAG,CAAU,EAAE,KAAK,GACjC,IAAW,KAAK,eAAe,GAAW,CAAM,GAClD,IAAO,KAAK,MAAM,IAAI,CAAQ;EAClC,IAAI,CAAC,GAAM;GACP,AAAK,KAAK,yBAAyB,OAC/B,KAAK,yBAAyB,KAAY,KAAK,eAAe,IAC1D,cAAc,EAAU,KAAK,GAAG,KAChC,KAAA,GACA,CACJ;GAEJ,IAAM,IAAU,KAAK,yBAAyB;GAC9C,IAAI;IACA,IAAO,MAAM;IACb,IAAM,IAAiB,EAAK;IAC5B,KAAK,MAAM,IAAI,GAAU,GAAM,IAAiB,GAAI;GACxD,UAAU;IACN,AAAI,KAAK,yBAAyB,OAAc,KAC5C,OAAO,KAAK,yBAAyB;GAE7C;EACJ;EAMA,OAJK,EAAK,WAIH,IAHI;CAIf;CAOA,wBAAwB,GAAsB,GAA6B;EACvE,KAAK,MAAM,OAAO,KAAK,eAAe,GAAY,CAAM,CAAC;CAC7D;CAQA,eAAuB,GAAsB,GAA+B;EACxE,OAAO,OAAO,CAAC,GAAG,CAAU,EAAE,KAAK,EAAE,GAAG;CAC5C;AACJ,GCzHa,KAAwB,MAC7B,MAIG,OAAO,SAAW,MAAc,KAAA,IAAY,SCkB1C,IAAb,MAAqB;CACjB;CACA;CACA;CAEA,YAAY,GAAuB;EAC/B,IAAM,IAAgB,EAAqB,EAAO,MAAM;EAExD,IAAI,CAAC,GACD,MAAM,IAAI,EAAS,gEAAgE;EAGvF,IAAI,EAAc,YACd,MAAM,IAAI,EAAS,oDAAoD;EAG3E,IAAM,EAAE,QAAK,2BAAwB,sBAAmB,eAAY,GAC9D,IAAe;GACjB,UAAU,EAAO;GACjB,aAAa,EAAO;GACpB,eAAe,EAAO;GACtB,KAAK,EAAO;GACZ,QAAQ;EACZ;EAQA,IANA,KAAKA,KAAY,IAAI,EAAS;GAC1B,GAAG;GACH;GACA;EACJ,CAAC,GAEG,MAAsB,KAAA,KAAa,CAAC,MAAM,QAAQ,CAAiB,GACnE,MAAM,IAAI,EAAS,mDAAmD;EAI1E,IAFA,KAAKC,KAAqB,GAEtB,GAAS;GACT,IAAI,OAAO,KAAY,YAAY,MAAM,QAAQ,CAAO,GACpD,MAAM,IAAI,EAAS,0CAA0C;GAEjE,KAAKD,GAAU,oBAAoB,CAAO;EAC9C;EAKA,AAHA,KAAKE,KAAgB,IAAI,EAAa,CAAY,GAElD,EAAc,aAAa,MAC3B,EAAc,cACV,IAAI,YAAY,oBAAoB,EAAE,QAAQ,EAAE,UAAU,KAAK,EAAE,CAAC,CACtE;CACJ;CAUA,aAAuC;EACnC,OAAO,KAAKF,GAAU,WAAW;CACrC;CAOA,aAA+B;EAC3B,OAAO,KAAKA,GAAU,WAAW;CACrC;CAQA,cAAgC;EAC5B,OAAO,KAAKA,GAAU,YAAY;CACtC;CAOA,UAA6C;EACzC,OAAO,KAAKA,GAAU,QAAQ;CAClC;CASA,YAA6B;EACzB,OAAO,KAAKA,GAAU,UAAU;CACpC;CAYA,cAAc,GAAuB,IAAyB,IAAqB;EAC/E,OAAO,KAAKA,GAAU,cAAc,GAAe,CAAc;CACrE;CAOA,cAA+B;EAC3B,OAAO,KAAKA,GAAU,YAAY;CACtC;CAOA,cAA+B;EAC3B,OAAO,KAAKA,GAAU,YAAY;CACtC;CAOA,qBAA0D;EACtD,OAAO,KAAKA,GAAU,mBAAmB;CAC7C;CAKA,UAAkC;EAC9B,OAAO,KAAKA,GAAU,QAAQ;CAClC;CAWA,MAAM,GAAsC;EACxC,OAAO,KAAKA,GAAU,MAAM,CAAO;CACvC;CAOA,OAAO,GAA4B;EAC/B,KAAKA,GAAU,OAAO,CAAW;CACrC;CAOA,SAAS,GAA+B;EACpC,OAAO,KAAKA,GAAU,SAAS,CAAO;CAC1C;CAOA,UAAU,GAA8B;EACpC,OAAO,KAAKA,GAAU,UAAU,CAAW;CAC/C;CAOA,WAAW,GAA8B;EACrC,OAAO,KAAKA,GAAU,WAAW,CAAW;CAChD;CAYA,0BACI,GACA,GACgB;EAChB,OAAO,KAAKA,GAAU,0BAA0B,GAAa,CAAO;CACxE;CAOA,yBAAyB,GAAwB;EAC7C,KAAKA,GAAU,yBAAyB,CAAO;CACnD;CAKA,yBAA+B;EAC3B,KAAKA,GAAU,uBAAuB;CAC1C;CAaA,MAAM,UAAU,IAAa,KAAKC,IAAqD;EACnF,IAAI,CAAC,GACD,MAAM,IAAI,EACN,0EACJ;EAEJ,IAAI,EAAW,WAAW,GACtB,OAAO;EAGX,IAAM,IAAS,MAAM,KAAKD,GAAU,UAAU;EAC9C,OAAO,KAAKE,GAAc,UAAU,GAAY,CAAM;CAC1D;CAQA,wBAAwB,GAAsB,GAA6B;EACvE,KAAKA,GAAc,wBAAwB,GAAY,CAAM;CACjE;CAcA,GAAG,GAAyB,GAA+B;EAGvD,OAFA,KAAKF,GAAU,iBAAiB,GAAO,CAAQ,GAExC;CACX;CAcA,IAAI,GAAyB,GAA+B;EAGxD,OAFA,KAAKA,GAAU,oBAAoB,GAAO,CAAQ,GAE3C;CACX;AACJ,GCjUM,IAAsB,oBACtB,IAA6B,KAE/B,GAEE,WACF,gBAAI,MAAM,gEAAgE,GAExE,WACF,gBAAI,MAAM,oDAAoD,EAA2B,IAAI;AAajG,SAAgB,GAAiB,GAAgC;CAC7D,OAAO,IAAI,EAAQ,CAAM;AAC7B;AASA,SAAgB,KAAkC;CAC9C,IAAM,IAAgB,EAAqB;CAE3C,IAAI,CAAC,GAAe;EAChB,IAAM,IAAQ,GAAuB;EAErC,OADA,QAAQ,MAAM,EAAM,OAAO,GACpB,QAAQ,OAAO,CAAK;CAC/B;CA0CA,OAxCI,EAAc,aACP,QAAQ,QAAQ,EAAc,UAAU,IAG/C,MAIJ,IAAwB,IAAI,SAAkB,GAAS,MAAW;EAC9D,IAAI,GAEE,UAAgB;GAKlB,AAJA,EAAc,oBAAoB,GAAqB,CAAwB,GAC3E,MAAc,KAAA,KACd,EAAc,aAAa,CAAS,GAExC,IAAwB,KAAA;EAC5B,GAEM,UAAiC;GACnC,IAAM,IAAU,EAAc;GACzB,MAIL,EAAQ,GACR,EAAQ,CAAO;EACnB;EAUA,AARA,EAAc,iBAAiB,GAAqB,CAAwB,GAC5E,IAAY,EAAc,iBAAiB;GACvC,IAAM,IAAQ,GAAmB;GAGjC,AAFA,QAAQ,MAAM,EAAM,OAAO,GAC3B,EAAQ,GACR,EAAO,CAAK;EAChB,GAAG,CAA0B,GAE7B,EAAyB;CAC7B,CAAC,GAEM;AACX"}
|