@kadanza/extension-sdk 0.0.8 → 0.0.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/dist/extension-sdk.cjs +1 -1
- package/dist/extension-sdk.cjs.map +1 -1
- package/dist/extension-sdk.js +112 -102
- package/dist/extension-sdk.js.map +1 -1
- package/dist/index.d.cts +18 -0
- package/dist/index.d.ts +18 -0
- package/package.json +1 -1
package/dist/extension-sdk.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){if(e.startsWith(`/`))return e;let t=new URL(e);return t.hostname=`api.${t.hostname}`,t.origin}function t(t,n){if(!n.startsWith(`/`)||n.startsWith(`//`))throw Error(`API endpoint must be a root-relative path starting with a single "/".`);return`${e(t).replace(/\/+$/,``)}${n}`}async function n(e,n,r={}){let i=new Headers(r.headers);i.has(`Content-Type`)||i.set(`Content-Type`,`application/json`),i.set(`Authorization`,`Bearer ${n.authTokenJwt}`),i.set(`X-Tenant`,n.tenantDomain);let a=await fetch(t(n.baseUrl,e),{...r,headers:i});if(!a.ok){let e=a.statusText?` ${a.statusText}`:``;throw Error(`API call failed: ${a.status}${e}.`)}return await a.json()}var r={handshakeInit:`HANDSHAKE_INIT`,handshakeAck:`HANDSHAKE_ACK`,requestAuthTokenRefresh:`REQUEST_TOKEN_REFRESH`,authTokenRefresh:`TOKEN_REFRESH`,loadPageSettings:`LOAD_PAGE_SETTINGS`,updatePageSettings:`UPDATE_PAGE_SETTINGS`,pageSettingsUpdated:`PAGE_SETTINGS_UPDATED`,navigationChange:`NAVIGATION_CHANGE`};function i(e,t,n){if(!window.parent||window.parent===window)throw Error(`Extension is not running inside a parent frame.`);let r=n===void 0?{type:e}:{type:e,payload:n};window.parent.postMessage(r,t)}function a(e,t){let n=n=>{n.origin===e&&(!n.data||typeof n.data!=`object`||!(`type`in n.data)||t(n))};return window.addEventListener(`message`,n),()=>window.removeEventListener(`message`,n)}var o=new Set([`localhost`,`127.0.0.1`,`[::1]`]),s=class extends Error{constructor(e){super(e),this.name=`InvalidOriginError`}};function c(e){if(!e)throw new s(`Missing "tenantUrl" search parameter required to establish parent origin.`);let t;try{t=new URL(e)}catch{throw new s(`Invalid tenantUrl: "${e}".`)}let n=o.has(t.hostname),r=t.protocol===`https:`,i=t.protocol===`http:`&&n;if(!r&&!i)throw new s(`tenantUrl must use https (or http on localhost). Received: "${t.protocol}//${t.host}".`);return t.origin}function l(e=window.location.search){return new URLSearchParams(e).get(`tenantUrl`)}var u=1e4,d=12e4,f=3e4,p=2147483647,m=class{#e=null;#t=null;#n
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(e){if(e.startsWith(`/`))return e;let t=new URL(e);return t.hostname=`api.${t.hostname}`,t.origin}function t(t,n){if(!n.startsWith(`/`)||n.startsWith(`//`))throw Error(`API endpoint must be a root-relative path starting with a single "/".`);return`${e(t).replace(/\/+$/,``)}${n}`}async function n(e,n,r={}){let i=new Headers(r.headers);i.has(`Content-Type`)||i.set(`Content-Type`,`application/json`),i.set(`Authorization`,`Bearer ${n.authTokenJwt}`),i.set(`X-Tenant`,n.tenantDomain);let a=await fetch(t(n.baseUrl,e),{...r,headers:i});if(!a.ok){let e=a.statusText?` ${a.statusText}`:``;throw Error(`API call failed: ${a.status}${e}.`)}return await a.json()}var r={handshakeInit:`HANDSHAKE_INIT`,handshakeAck:`HANDSHAKE_ACK`,requestAuthTokenRefresh:`REQUEST_TOKEN_REFRESH`,authTokenRefresh:`TOKEN_REFRESH`,loadPageSettings:`LOAD_PAGE_SETTINGS`,updatePageSettings:`UPDATE_PAGE_SETTINGS`,pageSettingsUpdated:`PAGE_SETTINGS_UPDATED`,navigationChange:`NAVIGATION_CHANGE`};function i(e,t,n){if(!window.parent||window.parent===window)throw Error(`Extension is not running inside a parent frame.`);let r=n===void 0?{type:e}:{type:e,payload:n};window.parent.postMessage(r,t)}function a(e,t){let n=n=>{n.origin===e&&(!n.data||typeof n.data!=`object`||!(`type`in n.data)||t(n))};return window.addEventListener(`message`,n),()=>window.removeEventListener(`message`,n)}var o=new Set([`localhost`,`127.0.0.1`,`[::1]`]),s=class extends Error{constructor(e){super(e),this.name=`InvalidOriginError`}};function c(e){if(!e)throw new s(`Missing "tenantUrl" search parameter required to establish parent origin.`);let t;try{t=new URL(e)}catch{throw new s(`Invalid tenantUrl: "${e}".`)}let n=o.has(t.hostname),r=t.protocol===`https:`,i=t.protocol===`http:`&&n;if(!r&&!i)throw new s(`tenantUrl must use https (or http on localhost). Received: "${t.protocol}//${t.host}".`);return t.origin}function l(e=window.location.search){return new URLSearchParams(e).get(`tenantUrl`)}var u=1e4,d=12e4,f=3e4,p=2147483647,m=class{#e=null;#t=null;#n=null;#r=!1;#i=!1;#a=null;#o=null;#s=null;#c=null;#l=!1;#u=d;#d=null;#f=!1;#p=null;#m=null;#h=null;#g=new Set;#_=new Set;get isConnected(){return this.#r}async connect(e={}){if(this.#C(),this.#r&&this.#a&&this.#o&&this.#s)return{authToken:this.#a,extensionDetails:this.#o,designTokens:this.#s,pageSettings:this.#c};if(this.#p)throw Error(`Handshake already in progress.`);this.#T(e);let t=l();this.#e=c(t),this.#t=t,this.#n?.(),this.#n=a(this.#e,e=>this.#v(e));let n=e.timeoutMs??u,o=new Promise((e,t)=>{let r=setTimeout(()=>{this.#p=null,t(Error(`Handshake timed out after ${n}ms.`))},n);this.#p={resolve:e,reject:t,timer:r}});try{i(r.handshakeInit,this.#e)}catch(e){throw this.#M(this.#p),this.#p=null,this.#n?.(),this.#n=null,this.#e=null,this.#t=null,this.#O(),e}return o}destroy(){this.#i=!0,this.#r=!1,this.#O(),this.#l=!1,this.#f=!1,this.#n?.(),this.#n=null,this.#e=null,this.#t=null,this.#P(this.#p,Error(`SDK destroyed.`)),this.#P(this.#m,Error(`SDK destroyed.`)),this.#P(this.#h,Error(`SDK destroyed.`)),this.#p=null,this.#m=null,this.#h=null,this.#g.clear(),this.#_.clear(),this.#a=null,this.#o=null,this.#s=null,this.#c=null}getAuthToken(){return this.#a}getExtensionDetails(){return this.#o}getDesignTokens(){return this.#s}getPageSettings(){return this.#c}getAllowedOrigin(){return this.#e}getTenantUrl(){return this.#t}getApiUrl(){return this.#o?e(this.#o.baseUrl):null}async apiCall(e,t={}){return this.#w(),n(e,{baseUrl:this.#o.baseUrl,tenantDomain:this.#o.tenantDomain,authTokenJwt:this.#a.jwt},t)}async emitRequestAuthTokenRefresh(e={}){if(this.#w(),this.#m)throw Error(`Auth token refresh already in progress.`);let t=e.timeoutMs??u,n=this.#e,a=new Promise((e,n)=>{let r=setTimeout(()=>{this.#m=null,n(Error(`Auth token refresh timed out after ${t}ms.`))},t);this.#m={resolve:e,reject:n,timer:r}});return i(r.requestAuthTokenRefresh,n),a}async emitUpdatePageSettings(e,t={}){if(this.#w(),this.#h)throw Error(`Page settings update already in progress.`);let n=t.timeoutMs??u,a=this.#e,o=new Promise((e,t)=>{let r=setTimeout(()=>{this.#h=null,t(Error(`Page settings update timed out after ${n}ms.`))},n);this.#h={resolve:e,reject:t,timer:r}});return i(r.updatePageSettings,a,e),o}onLoadPageSettings(e){return this.#g.add(e),()=>{this.#g.delete(e)}}onAuthTokenRefresh(e){return this.#_.add(e),()=>{this.#_.delete(e)}}emitNavigationChange(e){this.#w(),i(r.navigationChange,this.#e,e)}#v(e){let{type:t,payload:n}=e.data;switch(t){case r.handshakeAck:this.#y(n);break;case r.authTokenRefresh:this.#b(n);break;case r.loadPageSettings:this.#x(n);break;case r.pageSettingsUpdated:this.#S(n);break;default:break}}#y(e){if(!e?.authToken||!e.extensionDetails||!e.designTokens){this.#P(this.#p,Error(`Invalid HANDSHAKE_ACK payload.`)),this.#p=null;return}this.#a=e.authToken,this.#o=e.extensionDetails,this.#s=e.designTokens,this.#c=e.pageSettings??null,this.#r=!0;let t=this.#p;this.#p=null,this.#N(t,{authToken:this.#a,extensionDetails:this.#o,designTokens:this.#s,pageSettings:this.#c}),this.#f=!1,this.#k()}#b(e){if(!e?.authToken){this.#P(this.#m,Error(`Invalid TOKEN_REFRESH payload.`)),this.#m=null;return}this.#a=e.authToken;let t=this.#m;this.#m=null,this.#N(t,this.#a);for(let e of this.#_)e(this.#a);this.#f=!1,this.#k()}#x(e){let t=e??{};this.#c=t;for(let e of this.#g)e(t)}#S(e){if(!e||typeof e.success!=`boolean`){this.#P(this.#h,Error(`Invalid PAGE_SETTINGS_UPDATED payload.`)),this.#h=null;return}let t=this.#h;this.#h=null,this.#N(t,e)}#C(){if(this.#i)throw Error(`SDK has been destroyed.`)}#w(){if(this.#C(),!this.#r||!this.#e)throw Error(`SDK is not connected. Call connect() first.`)}#T(e){if(e.authTokenBufferMs!==void 0&&(!Number.isFinite(e.authTokenBufferMs)||e.authTokenBufferMs<0))throw Error(`authTokenBufferMs must be a finite non-negative number.`);this.#l=e.authTokenAutoRefresh===!0,this.#u=e.authTokenBufferMs??d,this.#f=!1,this.#O()}#E(e){let t=Number(e.expires);return Number.isFinite(t)?t*1e3:null}#D(e){let t=this.#E(e);return t===null?null:Math.max(0,t-this.#u-Date.now())}#O(){this.#d!==null&&(clearTimeout(this.#d),this.#d=null)}#k(){if(this.#O(),!this.#l||!this.#r||this.#i||!this.#a)return;let e=this.#D(this.#a);if(e===null)return;let t=Math.min(e,p);this.#d=setTimeout(()=>{this.#d=null,this.#A()},t)}async#A(){if(!this.#l||!this.#r||this.#i||!this.#a)return;let e=this.#a,t=this.#D(e);if(t!==null){if(t>0){this.#k();return}if(this.#m){this.#j(e);return}try{await this.emitRequestAuthTokenRefresh()}catch{this.#j(e)}}}#j(e){if(!this.#l||!this.#r||this.#i||this.#a?.jwt!==e.jwt||this.#f)return;let t=this.#E(e);if(t===null)return;let n=t-Date.now();if(n<=0)return;this.#f=!0,this.#O();let r=Math.min(f,n);this.#d=setTimeout(()=>{this.#d=null,this.#A()},r)}#M(e){e&&clearTimeout(e.timer)}#N(e,t){e&&(clearTimeout(e.timer),e.resolve(t))}#P(e,t){e&&(clearTimeout(e.timer),e.reject(t))}},h=()=>new m;exports.CONNECTION_EVENTS=r,exports.ExtensionSDK=m,exports.InvalidOriginError=s,exports.createExtensionSDK=h,exports.readTenantUrlFromLocation=l,exports.resolveAllowedOrigin=c;
|
|
2
2
|
//# sourceMappingURL=extension-sdk.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension-sdk.cjs","names":["#connected","#assertNotDestroyed","#authToken","#extensionDetails","#designTokens","#pageSettings","#pendingHandshake","#configureAuthTokenAutoRefresh","#allowedOrigin","#unsubscribe","#onMessage","#clearPending","#clearProactiveAuthTokenRefreshTimer","#destroyed","#authTokenAutoRefresh","#authTokenRefreshRetryUsed","#rejectPending","#pendingAuthTokenRefresh","#pendingPageSettingsUpdate","#loadPageSettingsHandlers","#authTokenRefreshHandlers","#assertConnected","#handleHandshakeAck","#handleAuthTokenRefresh","#handleLoadPageSettings","#handlePageSettingsUpdated","#resolvePending","#scheduleProactiveAuthTokenRefresh","#authTokenBufferMs","#parseExpiresAtMs","#authTokenRefreshTimer","#getProactiveRefreshDelayMs","#runProactiveAuthTokenRefresh","#handleProactiveAuthTokenRefreshFailure"],"sources":["../src/api.ts","../src/events.ts","../src/messaging.ts","../src/origin.ts","../src/ExtensionSDK.ts","../src/index.ts"],"sourcesContent":["interface ApiRequestContext {\n baseUrl: string;\n tenantDomain: string;\n authTokenJwt: string;\n}\n\nfunction deriveApiUrl(baseUrl: string): string {\n if (baseUrl.startsWith(\"/\")) {\n return baseUrl;\n }\n\n const url = new URL(baseUrl);\n url.hostname = `api.${url.hostname}`;\n return url.origin;\n}\n\nfunction resolveApiEndpoint(baseUrl: string, endpoint: string): string {\n if (!endpoint.startsWith(\"/\") || endpoint.startsWith(\"//\")) {\n throw new Error(\n 'API endpoint must be a root-relative path starting with a single \"/\".',\n );\n }\n\n return `${deriveApiUrl(baseUrl).replace(/\\/+$/, \"\")}${endpoint}`;\n}\n\nexport async function callApi<T>(\n endpoint: string,\n context: ApiRequestContext,\n options: RequestInit = {},\n): Promise<T> {\n const headers = new Headers(options.headers);\n\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n headers.set(\"Authorization\", `Bearer ${context.authTokenJwt}`);\n headers.set(\"X-Tenant\", context.tenantDomain);\n\n const response = await fetch(resolveApiEndpoint(context.baseUrl, endpoint), {\n ...options,\n headers,\n });\n\n if (!response.ok) {\n const statusText = response.statusText ? ` ${response.statusText}` : \"\";\n throw new Error(`API call failed: ${response.status}${statusText}.`);\n }\n\n return (await response.json()) as T;\n}\n","/**\n * Wire event type strings for parent/child `postMessage` communication.\n *\n * Keys are SDK-facing names; values are the strings sent on the wire.\n * Comments mark message direction relative to the extension (child).\n */\nexport const CONNECTION_EVENTS = {\n /** Child → parent: start handshake. */\n handshakeInit: \"HANDSHAKE_INIT\",\n /** Parent → child: handshake success with auth and context. */\n handshakeAck: \"HANDSHAKE_ACK\",\n /** Child → parent: request a new auth token. */\n requestAuthTokenRefresh: \"REQUEST_TOKEN_REFRESH\",\n /** Parent → child: new auth token (reply or push). */\n authTokenRefresh: \"TOKEN_REFRESH\",\n /** Parent → child: open/load page settings UI with values. */\n loadPageSettings: \"LOAD_PAGE_SETTINGS\",\n /** Child → parent: persist updated page settings. */\n updatePageSettings: \"UPDATE_PAGE_SETTINGS\",\n /** Parent → child: result of a page settings update. */\n pageSettingsUpdated: \"PAGE_SETTINGS_UPDATED\",\n /** Child → parent: extension route changed. */\n navigationChange: \"NAVIGATION_CHANGE\",\n} as const;\n\n/** Union of all {@link CONNECTION_EVENTS} wire string values. */\nexport type ConnectionEvent =\n (typeof CONNECTION_EVENTS)[keyof typeof CONNECTION_EVENTS];\n","import type { ConnectionEvent } from \"./events\";\nimport type { ExtensionMessage } from \"./types\";\n\nexport type MessageHandler = (event: MessageEvent<ExtensionMessage>) => void;\n\nexport function postToParent(\n type: ConnectionEvent,\n allowedOrigin: string,\n payload?: unknown,\n): void {\n if (!window.parent || window.parent === window) {\n throw new Error(\"Extension is not running inside a parent frame.\");\n }\n\n const message: ExtensionMessage = payload === undefined ? { type } : { type, payload };\n window.parent.postMessage(message, allowedOrigin);\n}\n\nexport function subscribeToParentMessages(\n allowedOrigin: string,\n handler: MessageHandler,\n): () => void {\n const listener = (event: MessageEvent) => {\n if (event.origin !== allowedOrigin) {\n return;\n }\n\n if (!event.data || typeof event.data !== \"object\" || !(\"type\" in event.data)) {\n return;\n }\n\n handler(event as MessageEvent<ExtensionMessage>);\n };\n\n window.addEventListener(\"message\", listener);\n return () => window.removeEventListener(\"message\", listener);\n}\n","const LOCALHOST_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/** Thrown when `tenantUrl` is missing or not a safe postMessage origin. */\nexport class InvalidOriginError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidOriginError\";\n }\n}\n\n/**\n * Parses and validates a tenant URL into a postMessage-safe origin.\n * Allows https always; http only for localhost / 127.0.0.1 / [::1].\n *\n * @param tenantUrl - Absolute URL from the `tenantUrl` search param.\n * @returns Origin string suitable for `postMessage` targetOrigin.\n * @throws {InvalidOriginError} When missing, unparsable, or disallowed scheme/host.\n */\nexport function resolveAllowedOrigin(tenantUrl: string | null): string {\n if (!tenantUrl) {\n throw new InvalidOriginError(\n 'Missing \"tenantUrl\" search parameter required to establish parent origin.',\n );\n }\n\n let url: URL;\n try {\n url = new URL(tenantUrl);\n } catch {\n throw new InvalidOriginError(`Invalid tenantUrl: \"${tenantUrl}\".`);\n }\n\n const isLocalhost = LOCALHOST_HOSTS.has(url.hostname);\n const isHttps = url.protocol === \"https:\";\n const isLocalHttp = url.protocol === \"http:\" && isLocalhost;\n\n if (!isHttps && !isLocalHttp) {\n throw new InvalidOriginError(\n `tenantUrl must use https (or http on localhost). Received: \"${url.protocol}//${url.host}\".`,\n );\n }\n\n return url.origin;\n}\n\n/**\n * Reads the parent-supplied `tenantUrl` from a URL search string.\n *\n * The parent must pass `tenantUrl` on the iframe `src` so\n * {@link resolveAllowedOrigin} can whitelist the parent origin.\n *\n * @param search - Query string (defaults to `window.location.search`).\n */\nexport function readTenantUrlFromLocation(\n search: string = window.location.search,\n): string | null {\n return new URLSearchParams(search).get(\"tenantUrl\");\n}\n","import { callApi } from \"./api\";\nimport { CONNECTION_EVENTS } from \"./events\";\nimport { postToParent, subscribeToParentMessages } from \"./messaging\";\nimport { readTenantUrlFromLocation, resolveAllowedOrigin } from \"./origin\";\nimport type {\n AuthToken,\n AuthTokenRefreshPayload,\n ConnectOptions,\n DesignTokens,\n ExtensionDetails,\n ExtensionMessage,\n HandshakePayload,\n NavigationChangePayload,\n PageSettings,\n PageSettingsUpdatedPayload,\n RequestOptions,\n UpdatePageSettingsPayload,\n} from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_AUTH_TOKEN_BUFFER_MS = 120_000;\nconst AUTO_REFRESH_RETRY_DELAY_MS = 30_000;\n/** Largest delay `setTimeout` can reliably use in browsers. */\nconst MAX_TIMEOUT_MS = 2_147_483_647;\n\n/**\n * Public contract for talking to the Kadanza parent frame over `postMessage`.\n *\n * Requires a `tenantUrl` search param on the extension URL so\n * {@link connect} can validate the parent origin.\n */\nexport interface IExtensionSDK {\n /**\n * Establishes the parent connection and waits for `HANDSHAKE_ACK`.\n *\n * If already connected with cached handshake data, returns that payload\n * without sending another init. Concurrent calls while a handshake is\n * in progress throw.\n *\n * Opt-in proactive refresh can be enabled with\n * `authTokenAutoRefresh: true` (optional `authTokenBufferMs`).\n *\n * @param options - Handshake timeout and optional auth-token auto-refresh.\n * @throws {InvalidOriginError} When `tenantUrl` is missing or invalid.\n * @throws When not embedded in a parent frame, already handshaking,\n * destroyed, or the handshake times out / returns an invalid payload.\n */\n connect(options?: ConnectOptions): Promise<HandshakePayload>;\n\n /**\n * Tears down listeners, proactive refresh timers, and cached state.\n * Rejects any in-flight requests. The instance cannot be reused after destroy.\n */\n destroy(): void;\n\n /** Whether a successful handshake has completed and not been destroyed. */\n readonly isConnected: boolean;\n\n /** Last auth token from handshake or refresh; `null` until connected. */\n getAuthToken(): AuthToken | null;\n\n /** Extension context from handshake; `null` until connected. */\n getExtensionDetails(): ExtensionDetails | null;\n\n /** Design tokens from handshake; `null` until connected. */\n getDesignTokens(): DesignTokens | null;\n\n /**\n * Latest page settings from handshake or `LOAD_PAGE_SETTINGS`;\n * `null` until set.\n */\n getPageSettings(): PageSettings | null;\n\n /**\n * Calls the Kadanza Platform API with the current connection credentials.\n *\n * The API origin is derived from the handshake `baseUrl`. Authorization and\n * tenant headers are managed by the SDK and cannot be overridden.\n *\n * @typeParam T - Expected JSON response body.\n * @param endpoint - Root-relative API path.\n * @param options - Standard fetch options.\n * @throws When not connected, the endpoint is invalid, the request fails,\n * or the response is not successful JSON.\n */\n apiCall<T>(endpoint: string, options?: RequestInit): Promise<T>;\n\n /**\n * Asks the parent for a new auth token and waits for `TOKEN_REFRESH`.\n *\n * @param options - Optional request timeout (default 10s).\n * @throws When not connected, a refresh is already in progress,\n * or the request times out / returns an invalid payload.\n */\n emitRequestAuthTokenRefresh(\n options?: RequestOptions,\n ): Promise<AuthToken>;\n\n /**\n * Pushes page settings to the parent and waits for `PAGE_SETTINGS_UPDATED`.\n *\n * @param payload - Update payload containing the settings object.\n * @param options - Optional request timeout (default 10s).\n * @throws When not connected, an update is already in progress,\n * or the request times out / returns an invalid payload.\n */\n emitUpdatePageSettings(\n payload: UpdatePageSettingsPayload,\n options?: RequestOptions,\n ): Promise<PageSettingsUpdatedPayload>;\n\n /**\n * Registers a handler for parent-initiated `LOAD_PAGE_SETTINGS`.\n *\n * @returns Unsubscribe function.\n */\n onLoadPageSettings(handler: (settings: PageSettings) => void): () => void;\n\n /**\n * Registers a handler for auth-token updates (requested or parent-pushed).\n *\n * @returns Unsubscribe function.\n */\n onAuthTokenRefresh(handler: (authToken: AuthToken) => void): () => void;\n\n /**\n * Notifies the parent that the extension's route changed.\n *\n * Wire: `NAVIGATION_CHANGE` (fire-and-forget).\n *\n * @param payload - Navigation change payload (`path` within the extension).\n * @throws When not connected or destroyed.\n */\n emitNavigationChange(payload: NavigationChangePayload): void;\n}\n\ntype Pending<T> = {\n resolve: (value: T) => void;\n reject: (reason?: unknown) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\n/** Default {@link IExtensionSDK} implementation. Prefer {@link createExtensionSDK}. */\nexport class ExtensionSDK implements IExtensionSDK {\n #allowedOrigin: string | null = null;\n #unsubscribe: (() => void) | null = null;\n #connected = false;\n #destroyed = false;\n\n #authToken: AuthToken | null = null;\n #extensionDetails: ExtensionDetails | null = null;\n #designTokens: DesignTokens | null = null;\n #pageSettings: PageSettings | null = null;\n\n #authTokenAutoRefresh = false;\n #authTokenBufferMs = DEFAULT_AUTH_TOKEN_BUFFER_MS;\n #authTokenRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n #authTokenRefreshRetryUsed = false;\n\n #pendingHandshake: Pending<HandshakePayload> | null = null;\n #pendingAuthTokenRefresh: Pending<AuthToken> | null = null;\n #pendingPageSettingsUpdate: Pending<PageSettingsUpdatedPayload> | null = null;\n\n #loadPageSettingsHandlers = new Set<(settings: PageSettings) => void>();\n #authTokenRefreshHandlers = new Set<(authToken: AuthToken) => void>();\n\n get isConnected(): boolean {\n return this.#connected;\n }\n\n async connect(options: ConnectOptions = {}): Promise<HandshakePayload> {\n this.#assertNotDestroyed();\n\n if (this.#connected && this.#authToken && this.#extensionDetails && this.#designTokens) {\n return {\n authToken: this.#authToken,\n extensionDetails: this.#extensionDetails,\n designTokens: this.#designTokens,\n pageSettings: this.#pageSettings,\n };\n }\n\n if (this.#pendingHandshake) {\n throw new Error(\"Handshake already in progress.\");\n }\n\n this.#configureAuthTokenAutoRefresh(options);\n\n const tenantUrl = readTenantUrlFromLocation();\n this.#allowedOrigin = resolveAllowedOrigin(tenantUrl);\n\n this.#unsubscribe?.();\n this.#unsubscribe = subscribeToParentMessages(\n this.#allowedOrigin,\n (event) => this.#onMessage(event),\n );\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n const handshakePromise = new Promise<HandshakePayload>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingHandshake = null;\n reject(new Error(`Handshake timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingHandshake = { resolve, reject, timer };\n });\n\n try {\n postToParent(CONNECTION_EVENTS.handshakeInit, this.#allowedOrigin);\n } catch (error) {\n this.#clearPending(this.#pendingHandshake);\n this.#pendingHandshake = null;\n this.#unsubscribe?.();\n this.#unsubscribe = null;\n this.#allowedOrigin = null;\n this.#clearProactiveAuthTokenRefreshTimer();\n throw error;\n }\n\n return handshakePromise;\n }\n\n destroy(): void {\n this.#destroyed = true;\n this.#connected = false;\n\n this.#clearProactiveAuthTokenRefreshTimer();\n this.#authTokenAutoRefresh = false;\n this.#authTokenRefreshRetryUsed = false;\n\n this.#unsubscribe?.();\n this.#unsubscribe = null;\n this.#allowedOrigin = null;\n\n this.#rejectPending(this.#pendingHandshake, new Error(\"SDK destroyed.\"));\n this.#rejectPending(this.#pendingAuthTokenRefresh, new Error(\"SDK destroyed.\"));\n this.#rejectPending(this.#pendingPageSettingsUpdate, new Error(\"SDK destroyed.\"));\n this.#pendingHandshake = null;\n this.#pendingAuthTokenRefresh = null;\n this.#pendingPageSettingsUpdate = null;\n\n this.#loadPageSettingsHandlers.clear();\n this.#authTokenRefreshHandlers.clear();\n\n this.#authToken = null;\n this.#extensionDetails = null;\n this.#designTokens = null;\n this.#pageSettings = null;\n }\n\n getAuthToken(): AuthToken | null {\n return this.#authToken;\n }\n\n getExtensionDetails(): ExtensionDetails | null {\n return this.#extensionDetails;\n }\n\n getDesignTokens(): DesignTokens | null {\n return this.#designTokens;\n }\n\n getPageSettings(): PageSettings | null {\n return this.#pageSettings;\n }\n\n async apiCall<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n this.#assertConnected();\n\n return callApi<T>(\n endpoint,\n {\n baseUrl: this.#extensionDetails!.baseUrl,\n tenantDomain: this.#extensionDetails!.tenantDomain,\n authTokenJwt: this.#authToken!.jwt,\n },\n options,\n );\n }\n\n async emitRequestAuthTokenRefresh(\n options: RequestOptions = {},\n ): Promise<AuthToken> {\n this.#assertConnected();\n\n if (this.#pendingAuthTokenRefresh) {\n throw new Error(\"Auth token refresh already in progress.\");\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const allowedOrigin = this.#allowedOrigin!;\n\n const promise = new Promise<AuthToken>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingAuthTokenRefresh = null;\n reject(new Error(`Auth token refresh timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingAuthTokenRefresh = { resolve, reject, timer };\n });\n\n postToParent(CONNECTION_EVENTS.requestAuthTokenRefresh, allowedOrigin);\n return promise;\n }\n\n async emitUpdatePageSettings(\n payload: UpdatePageSettingsPayload,\n options: RequestOptions = {},\n ): Promise<PageSettingsUpdatedPayload> {\n this.#assertConnected();\n\n if (this.#pendingPageSettingsUpdate) {\n throw new Error(\"Page settings update already in progress.\");\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const allowedOrigin = this.#allowedOrigin!;\n\n const promise = new Promise<PageSettingsUpdatedPayload>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingPageSettingsUpdate = null;\n reject(new Error(`Page settings update timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingPageSettingsUpdate = { resolve, reject, timer };\n });\n\n postToParent(CONNECTION_EVENTS.updatePageSettings, allowedOrigin, payload);\n return promise;\n }\n\n onLoadPageSettings(handler: (settings: PageSettings) => void): () => void {\n this.#loadPageSettingsHandlers.add(handler);\n return () => {\n this.#loadPageSettingsHandlers.delete(handler);\n };\n }\n\n onAuthTokenRefresh(handler: (authToken: AuthToken) => void): () => void {\n this.#authTokenRefreshHandlers.add(handler);\n return () => {\n this.#authTokenRefreshHandlers.delete(handler);\n };\n }\n\n emitNavigationChange(payload: NavigationChangePayload): void {\n this.#assertConnected();\n postToParent(\n CONNECTION_EVENTS.navigationChange,\n this.#allowedOrigin!,\n payload,\n );\n }\n\n #onMessage(event: MessageEvent<ExtensionMessage>): void {\n const { type, payload } = event.data;\n\n switch (type) {\n case CONNECTION_EVENTS.handshakeAck:\n this.#handleHandshakeAck(payload as HandshakePayload | undefined);\n break;\n case CONNECTION_EVENTS.authTokenRefresh:\n this.#handleAuthTokenRefresh(payload as AuthTokenRefreshPayload | undefined);\n break;\n case CONNECTION_EVENTS.loadPageSettings:\n this.#handleLoadPageSettings(payload as PageSettings | undefined);\n break;\n case CONNECTION_EVENTS.pageSettingsUpdated:\n this.#handlePageSettingsUpdated(\n payload as PageSettingsUpdatedPayload | undefined,\n );\n break;\n default:\n break;\n }\n }\n\n #handleHandshakeAck(payload: HandshakePayload | undefined): void {\n if (!payload?.authToken || !payload.extensionDetails || !payload.designTokens) {\n this.#rejectPending(\n this.#pendingHandshake,\n new Error(\"Invalid HANDSHAKE_ACK payload.\"),\n );\n this.#pendingHandshake = null;\n return;\n }\n\n this.#authToken = payload.authToken;\n this.#extensionDetails = payload.extensionDetails;\n this.#designTokens = payload.designTokens;\n this.#pageSettings = payload.pageSettings ?? null;\n this.#connected = true;\n\n const pending = this.#pendingHandshake;\n this.#pendingHandshake = null;\n this.#resolvePending(pending, {\n authToken: this.#authToken,\n extensionDetails: this.#extensionDetails,\n designTokens: this.#designTokens,\n pageSettings: this.#pageSettings,\n });\n\n this.#authTokenRefreshRetryUsed = false;\n this.#scheduleProactiveAuthTokenRefresh();\n }\n\n #handleAuthTokenRefresh(payload: AuthTokenRefreshPayload | undefined): void {\n if (!payload?.authToken) {\n this.#rejectPending(\n this.#pendingAuthTokenRefresh,\n new Error(\"Invalid TOKEN_REFRESH payload.\"),\n );\n this.#pendingAuthTokenRefresh = null;\n return;\n }\n\n this.#authToken = payload.authToken;\n\n const pending = this.#pendingAuthTokenRefresh;\n this.#pendingAuthTokenRefresh = null;\n this.#resolvePending(pending, this.#authToken);\n\n for (const handler of this.#authTokenRefreshHandlers) {\n handler(this.#authToken);\n }\n\n this.#authTokenRefreshRetryUsed = false;\n this.#scheduleProactiveAuthTokenRefresh();\n }\n\n #handleLoadPageSettings(payload: PageSettings | undefined): void {\n const settings = payload ?? {};\n this.#pageSettings = settings;\n\n for (const handler of this.#loadPageSettingsHandlers) {\n handler(settings);\n }\n }\n\n #handlePageSettingsUpdated(\n payload: PageSettingsUpdatedPayload | undefined,\n ): void {\n if (!payload || typeof payload.success !== \"boolean\") {\n this.#rejectPending(\n this.#pendingPageSettingsUpdate,\n new Error(\"Invalid PAGE_SETTINGS_UPDATED payload.\"),\n );\n this.#pendingPageSettingsUpdate = null;\n return;\n }\n\n const pending = this.#pendingPageSettingsUpdate;\n this.#pendingPageSettingsUpdate = null;\n this.#resolvePending(pending, payload);\n }\n\n #assertNotDestroyed(): void {\n if (this.#destroyed) {\n throw new Error(\"SDK has been destroyed.\");\n }\n }\n\n #assertConnected(): void {\n this.#assertNotDestroyed();\n if (!this.#connected || !this.#allowedOrigin) {\n throw new Error(\"SDK is not connected. Call connect() first.\");\n }\n }\n\n #configureAuthTokenAutoRefresh(options: ConnectOptions): void {\n if (options.authTokenBufferMs !== undefined) {\n if (\n !Number.isFinite(options.authTokenBufferMs) ||\n options.authTokenBufferMs < 0\n ) {\n throw new Error(\n \"authTokenBufferMs must be a finite non-negative number.\",\n );\n }\n }\n\n this.#authTokenAutoRefresh = options.authTokenAutoRefresh === true;\n this.#authTokenBufferMs =\n options.authTokenBufferMs ?? DEFAULT_AUTH_TOKEN_BUFFER_MS;\n this.#authTokenRefreshRetryUsed = false;\n this.#clearProactiveAuthTokenRefreshTimer();\n }\n\n #parseExpiresAtMs(authToken: AuthToken): number | null {\n const expiresSec = Number(authToken.expires);\n if (!Number.isFinite(expiresSec)) {\n return null;\n }\n return expiresSec * 1000;\n }\n\n #getProactiveRefreshDelayMs(authToken: AuthToken): number | null {\n const expiresAtMs = this.#parseExpiresAtMs(authToken);\n if (expiresAtMs === null) {\n return null;\n }\n return Math.max(0, expiresAtMs - this.#authTokenBufferMs - Date.now());\n }\n\n #clearProactiveAuthTokenRefreshTimer(): void {\n if (this.#authTokenRefreshTimer !== null) {\n clearTimeout(this.#authTokenRefreshTimer);\n this.#authTokenRefreshTimer = null;\n }\n }\n\n #scheduleProactiveAuthTokenRefresh(): void {\n this.#clearProactiveAuthTokenRefreshTimer();\n\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n !this.#authToken\n ) {\n return;\n }\n\n const delayMs = this.#getProactiveRefreshDelayMs(this.#authToken);\n if (delayMs === null) {\n return;\n }\n\n const clampedDelay = Math.min(delayMs, MAX_TIMEOUT_MS);\n this.#authTokenRefreshTimer = setTimeout(() => {\n this.#authTokenRefreshTimer = null;\n void this.#runProactiveAuthTokenRefresh();\n }, clampedDelay);\n }\n\n async #runProactiveAuthTokenRefresh(): Promise<void> {\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n !this.#authToken\n ) {\n return;\n }\n\n const authTokenAtRequest = this.#authToken;\n const delayMs = this.#getProactiveRefreshDelayMs(authTokenAtRequest);\n if (delayMs === null) {\n return;\n }\n\n if (delayMs > 0) {\n this.#scheduleProactiveAuthTokenRefresh();\n return;\n }\n\n if (this.#pendingAuthTokenRefresh) {\n this.#handleProactiveAuthTokenRefreshFailure(authTokenAtRequest);\n return;\n }\n\n try {\n await this.emitRequestAuthTokenRefresh();\n } catch {\n this.#handleProactiveAuthTokenRefreshFailure(authTokenAtRequest);\n }\n }\n\n #handleProactiveAuthTokenRefreshFailure(authTokenAtRequest: AuthToken): void {\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n this.#authToken?.jwt !== authTokenAtRequest.jwt\n ) {\n return;\n }\n\n if (this.#authTokenRefreshRetryUsed) {\n return;\n }\n\n const expiresAtMs = this.#parseExpiresAtMs(authTokenAtRequest);\n if (expiresAtMs === null) {\n return;\n }\n\n const remainingMs = expiresAtMs - Date.now();\n if (remainingMs <= 0) {\n return;\n }\n\n this.#authTokenRefreshRetryUsed = true;\n this.#clearProactiveAuthTokenRefreshTimer();\n\n const retryDelay = Math.min(AUTO_REFRESH_RETRY_DELAY_MS, remainingMs);\n this.#authTokenRefreshTimer = setTimeout(() => {\n this.#authTokenRefreshTimer = null;\n void this.#runProactiveAuthTokenRefresh();\n }, retryDelay);\n }\n\n #clearPending(pending: { timer: ReturnType<typeof setTimeout> } | null): void {\n if (pending) {\n clearTimeout(pending.timer);\n }\n }\n\n #resolvePending<T>(pending: Pending<T> | null, value: T): void {\n if (!pending) {\n return;\n }\n clearTimeout(pending.timer);\n pending.resolve(value);\n }\n\n #rejectPending(\n pending: { timer: ReturnType<typeof setTimeout>; reject: (reason?: unknown) => void } | null,\n reason: unknown,\n ): void {\n if (!pending) {\n return;\n }\n clearTimeout(pending.timer);\n pending.reject(reason);\n }\n}\n","import { ExtensionSDK, type IExtensionSDK } from \"./ExtensionSDK\";\n\nexport { ExtensionSDK, type IExtensionSDK } from \"./ExtensionSDK\";\nexport { CONNECTION_EVENTS, type ConnectionEvent } from \"./events\";\nexport {\n InvalidOriginError,\n readTenantUrlFromLocation,\n resolveAllowedOrigin,\n} from \"./origin\";\nexport type {\n AuthToken,\n AuthTokenRefreshPayload,\n ConnectOptions,\n DesignTokens,\n ExtensionDetails,\n ExtensionMessage,\n HandshakePayload,\n NavigationChangePayload,\n PageSettings,\n PageSettingsUpdatedPayload,\n RequestOptions,\n UpdatePageSettingsPayload,\n} from \"./types\";\n\n/** Creates a new {@link IExtensionSDK} instance for the current extension frame. */\nexport const createExtensionSDK = (): IExtensionSDK => {\n return new ExtensionSDK();\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"extension-sdk.cjs","names":["#connected","#assertNotDestroyed","#authToken","#extensionDetails","#designTokens","#pageSettings","#pendingHandshake","#configureAuthTokenAutoRefresh","#allowedOrigin","#tenantUrl","#unsubscribe","#onMessage","#clearPending","#clearProactiveAuthTokenRefreshTimer","#destroyed","#authTokenAutoRefresh","#authTokenRefreshRetryUsed","#rejectPending","#pendingAuthTokenRefresh","#pendingPageSettingsUpdate","#loadPageSettingsHandlers","#authTokenRefreshHandlers","#assertConnected","#handleHandshakeAck","#handleAuthTokenRefresh","#handleLoadPageSettings","#handlePageSettingsUpdated","#resolvePending","#scheduleProactiveAuthTokenRefresh","#authTokenBufferMs","#parseExpiresAtMs","#authTokenRefreshTimer","#getProactiveRefreshDelayMs","#runProactiveAuthTokenRefresh","#handleProactiveAuthTokenRefreshFailure"],"sources":["../src/api.ts","../src/events.ts","../src/messaging.ts","../src/origin.ts","../src/ExtensionSDK.ts","../src/index.ts"],"sourcesContent":["interface ApiRequestContext {\n baseUrl: string;\n tenantDomain: string;\n authTokenJwt: string;\n}\n\n/** Derives the Platform API origin from handshake `baseUrl`. */\nexport function deriveApiUrl(baseUrl: string): string {\n if (baseUrl.startsWith(\"/\")) {\n return baseUrl;\n }\n\n const url = new URL(baseUrl);\n url.hostname = `api.${url.hostname}`;\n return url.origin;\n}\n\nfunction resolveApiEndpoint(baseUrl: string, endpoint: string): string {\n if (!endpoint.startsWith(\"/\") || endpoint.startsWith(\"//\")) {\n throw new Error(\n 'API endpoint must be a root-relative path starting with a single \"/\".',\n );\n }\n\n return `${deriveApiUrl(baseUrl).replace(/\\/+$/, \"\")}${endpoint}`;\n}\n\nexport async function callApi<T>(\n endpoint: string,\n context: ApiRequestContext,\n options: RequestInit = {},\n): Promise<T> {\n const headers = new Headers(options.headers);\n\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n headers.set(\"Authorization\", `Bearer ${context.authTokenJwt}`);\n headers.set(\"X-Tenant\", context.tenantDomain);\n\n const response = await fetch(resolveApiEndpoint(context.baseUrl, endpoint), {\n ...options,\n headers,\n });\n\n if (!response.ok) {\n const statusText = response.statusText ? ` ${response.statusText}` : \"\";\n throw new Error(`API call failed: ${response.status}${statusText}.`);\n }\n\n return (await response.json()) as T;\n}\n","/**\n * Wire event type strings for parent/child `postMessage` communication.\n *\n * Keys are SDK-facing names; values are the strings sent on the wire.\n * Comments mark message direction relative to the extension (child).\n */\nexport const CONNECTION_EVENTS = {\n /** Child → parent: start handshake. */\n handshakeInit: \"HANDSHAKE_INIT\",\n /** Parent → child: handshake success with auth and context. */\n handshakeAck: \"HANDSHAKE_ACK\",\n /** Child → parent: request a new auth token. */\n requestAuthTokenRefresh: \"REQUEST_TOKEN_REFRESH\",\n /** Parent → child: new auth token (reply or push). */\n authTokenRefresh: \"TOKEN_REFRESH\",\n /** Parent → child: open/load page settings UI with values. */\n loadPageSettings: \"LOAD_PAGE_SETTINGS\",\n /** Child → parent: persist updated page settings. */\n updatePageSettings: \"UPDATE_PAGE_SETTINGS\",\n /** Parent → child: result of a page settings update. */\n pageSettingsUpdated: \"PAGE_SETTINGS_UPDATED\",\n /** Child → parent: extension route changed. */\n navigationChange: \"NAVIGATION_CHANGE\",\n} as const;\n\n/** Union of all {@link CONNECTION_EVENTS} wire string values. */\nexport type ConnectionEvent =\n (typeof CONNECTION_EVENTS)[keyof typeof CONNECTION_EVENTS];\n","import type { ConnectionEvent } from \"./events\";\nimport type { ExtensionMessage } from \"./types\";\n\nexport type MessageHandler = (event: MessageEvent<ExtensionMessage>) => void;\n\nexport function postToParent(\n type: ConnectionEvent,\n allowedOrigin: string,\n payload?: unknown,\n): void {\n if (!window.parent || window.parent === window) {\n throw new Error(\"Extension is not running inside a parent frame.\");\n }\n\n const message: ExtensionMessage = payload === undefined ? { type } : { type, payload };\n window.parent.postMessage(message, allowedOrigin);\n}\n\nexport function subscribeToParentMessages(\n allowedOrigin: string,\n handler: MessageHandler,\n): () => void {\n const listener = (event: MessageEvent) => {\n if (event.origin !== allowedOrigin) {\n return;\n }\n\n if (!event.data || typeof event.data !== \"object\" || !(\"type\" in event.data)) {\n return;\n }\n\n handler(event as MessageEvent<ExtensionMessage>);\n };\n\n window.addEventListener(\"message\", listener);\n return () => window.removeEventListener(\"message\", listener);\n}\n","const LOCALHOST_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/** Thrown when `tenantUrl` is missing or not a safe postMessage origin. */\nexport class InvalidOriginError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidOriginError\";\n }\n}\n\n/**\n * Parses and validates a tenant URL into a postMessage-safe origin.\n * Allows https always; http only for localhost / 127.0.0.1 / [::1].\n *\n * @param tenantUrl - Absolute URL from the `tenantUrl` search param.\n * @returns Origin string suitable for `postMessage` targetOrigin.\n * @throws {InvalidOriginError} When missing, unparsable, or disallowed scheme/host.\n */\nexport function resolveAllowedOrigin(tenantUrl: string | null): string {\n if (!tenantUrl) {\n throw new InvalidOriginError(\n 'Missing \"tenantUrl\" search parameter required to establish parent origin.',\n );\n }\n\n let url: URL;\n try {\n url = new URL(tenantUrl);\n } catch {\n throw new InvalidOriginError(`Invalid tenantUrl: \"${tenantUrl}\".`);\n }\n\n const isLocalhost = LOCALHOST_HOSTS.has(url.hostname);\n const isHttps = url.protocol === \"https:\";\n const isLocalHttp = url.protocol === \"http:\" && isLocalhost;\n\n if (!isHttps && !isLocalHttp) {\n throw new InvalidOriginError(\n `tenantUrl must use https (or http on localhost). Received: \"${url.protocol}//${url.host}\".`,\n );\n }\n\n return url.origin;\n}\n\n/**\n * Reads the parent-supplied `tenantUrl` from a URL search string.\n *\n * The parent must pass `tenantUrl` on the iframe `src` so\n * {@link resolveAllowedOrigin} can whitelist the parent origin.\n *\n * @param search - Query string (defaults to `window.location.search`).\n */\nexport function readTenantUrlFromLocation(\n search: string = window.location.search,\n): string | null {\n return new URLSearchParams(search).get(\"tenantUrl\");\n}\n","import { callApi, deriveApiUrl } from \"./api\";\nimport { CONNECTION_EVENTS } from \"./events\";\nimport { postToParent, subscribeToParentMessages } from \"./messaging\";\nimport { readTenantUrlFromLocation, resolveAllowedOrigin } from \"./origin\";\nimport type {\n AuthToken,\n AuthTokenRefreshPayload,\n ConnectOptions,\n DesignTokens,\n ExtensionDetails,\n ExtensionMessage,\n HandshakePayload,\n NavigationChangePayload,\n PageSettings,\n PageSettingsUpdatedPayload,\n RequestOptions,\n UpdatePageSettingsPayload,\n} from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_AUTH_TOKEN_BUFFER_MS = 120_000;\nconst AUTO_REFRESH_RETRY_DELAY_MS = 30_000;\n/** Largest delay `setTimeout` can reliably use in browsers. */\nconst MAX_TIMEOUT_MS = 2_147_483_647;\n\n/**\n * Public contract for talking to the Kadanza parent frame over `postMessage`.\n *\n * Requires a `tenantUrl` search param on the extension URL so\n * {@link connect} can validate the parent origin.\n */\nexport interface IExtensionSDK {\n /**\n * Establishes the parent connection and waits for `HANDSHAKE_ACK`.\n *\n * If already connected with cached handshake data, returns that payload\n * without sending another init. Concurrent calls while a handshake is\n * in progress throw.\n *\n * Opt-in proactive refresh can be enabled with\n * `authTokenAutoRefresh: true` (optional `authTokenBufferMs`).\n *\n * @param options - Handshake timeout and optional auth-token auto-refresh.\n * @throws {InvalidOriginError} When `tenantUrl` is missing or invalid.\n * @throws When not embedded in a parent frame, already handshaking,\n * destroyed, or the handshake times out / returns an invalid payload.\n */\n connect(options?: ConnectOptions): Promise<HandshakePayload>;\n\n /**\n * Tears down listeners, proactive refresh timers, and cached state.\n * Rejects any in-flight requests. The instance cannot be reused after destroy.\n */\n destroy(): void;\n\n /** Whether a successful handshake has completed and not been destroyed. */\n readonly isConnected: boolean;\n\n /** Last auth token from handshake or refresh; `null` until connected. */\n getAuthToken(): AuthToken | null;\n\n /** Extension context from handshake; `null` until connected. */\n getExtensionDetails(): ExtensionDetails | null;\n\n /** Design tokens from handshake; `null` until connected. */\n getDesignTokens(): DesignTokens | null;\n\n /**\n * Latest page settings from handshake or `LOAD_PAGE_SETTINGS`;\n * `null` until set.\n */\n getPageSettings(): PageSettings | null;\n\n /**\n * Validated parent `postMessage` origin from `tenantUrl`;\n * `null` until `connect` resolves it.\n */\n getAllowedOrigin(): string | null;\n\n /**\n * Raw `tenantUrl` search-param value used for the allowed origin;\n * `null` until `connect` reads it.\n */\n getTenantUrl(): string | null;\n\n /**\n * Platform API origin derived from handshake `baseUrl`;\n * `null` until connected.\n */\n getApiUrl(): string | null;\n\n /**\n * Calls the Kadanza Platform API with the current connection credentials.\n *\n * The API origin is derived from the handshake `baseUrl`. Authorization and\n * tenant headers are managed by the SDK and cannot be overridden.\n *\n * @typeParam T - Expected JSON response body.\n * @param endpoint - Root-relative API path.\n * @param options - Standard fetch options.\n * @throws When not connected, the endpoint is invalid, the request fails,\n * or the response is not successful JSON.\n */\n apiCall<T>(endpoint: string, options?: RequestInit): Promise<T>;\n\n /**\n * Asks the parent for a new auth token and waits for `TOKEN_REFRESH`.\n *\n * @param options - Optional request timeout (default 10s).\n * @throws When not connected, a refresh is already in progress,\n * or the request times out / returns an invalid payload.\n */\n emitRequestAuthTokenRefresh(\n options?: RequestOptions,\n ): Promise<AuthToken>;\n\n /**\n * Pushes page settings to the parent and waits for `PAGE_SETTINGS_UPDATED`.\n *\n * @param payload - Update payload containing the settings object.\n * @param options - Optional request timeout (default 10s).\n * @throws When not connected, an update is already in progress,\n * or the request times out / returns an invalid payload.\n */\n emitUpdatePageSettings(\n payload: UpdatePageSettingsPayload,\n options?: RequestOptions,\n ): Promise<PageSettingsUpdatedPayload>;\n\n /**\n * Registers a handler for parent-initiated `LOAD_PAGE_SETTINGS`.\n *\n * @returns Unsubscribe function.\n */\n onLoadPageSettings(handler: (settings: PageSettings) => void): () => void;\n\n /**\n * Registers a handler for auth-token updates (requested or parent-pushed).\n *\n * @returns Unsubscribe function.\n */\n onAuthTokenRefresh(handler: (authToken: AuthToken) => void): () => void;\n\n /**\n * Notifies the parent that the extension's route changed.\n *\n * Wire: `NAVIGATION_CHANGE` (fire-and-forget).\n *\n * @param payload - Navigation change payload (`path` within the extension).\n * @throws When not connected or destroyed.\n */\n emitNavigationChange(payload: NavigationChangePayload): void;\n}\n\ntype Pending<T> = {\n resolve: (value: T) => void;\n reject: (reason?: unknown) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\n/** Default {@link IExtensionSDK} implementation. Prefer {@link createExtensionSDK}. */\nexport class ExtensionSDK implements IExtensionSDK {\n #allowedOrigin: string | null = null;\n #tenantUrl: string | null = null;\n #unsubscribe: (() => void) | null = null;\n #connected = false;\n #destroyed = false;\n\n #authToken: AuthToken | null = null;\n #extensionDetails: ExtensionDetails | null = null;\n #designTokens: DesignTokens | null = null;\n #pageSettings: PageSettings | null = null;\n\n #authTokenAutoRefresh = false;\n #authTokenBufferMs = DEFAULT_AUTH_TOKEN_BUFFER_MS;\n #authTokenRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n #authTokenRefreshRetryUsed = false;\n\n #pendingHandshake: Pending<HandshakePayload> | null = null;\n #pendingAuthTokenRefresh: Pending<AuthToken> | null = null;\n #pendingPageSettingsUpdate: Pending<PageSettingsUpdatedPayload> | null = null;\n\n #loadPageSettingsHandlers = new Set<(settings: PageSettings) => void>();\n #authTokenRefreshHandlers = new Set<(authToken: AuthToken) => void>();\n\n get isConnected(): boolean {\n return this.#connected;\n }\n\n async connect(options: ConnectOptions = {}): Promise<HandshakePayload> {\n this.#assertNotDestroyed();\n\n if (this.#connected && this.#authToken && this.#extensionDetails && this.#designTokens) {\n return {\n authToken: this.#authToken,\n extensionDetails: this.#extensionDetails,\n designTokens: this.#designTokens,\n pageSettings: this.#pageSettings,\n };\n }\n\n if (this.#pendingHandshake) {\n throw new Error(\"Handshake already in progress.\");\n }\n\n this.#configureAuthTokenAutoRefresh(options);\n\n const tenantUrl = readTenantUrlFromLocation();\n this.#allowedOrigin = resolveAllowedOrigin(tenantUrl);\n this.#tenantUrl = tenantUrl;\n\n this.#unsubscribe?.();\n this.#unsubscribe = subscribeToParentMessages(\n this.#allowedOrigin,\n (event) => this.#onMessage(event),\n );\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n const handshakePromise = new Promise<HandshakePayload>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingHandshake = null;\n reject(new Error(`Handshake timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingHandshake = { resolve, reject, timer };\n });\n\n try {\n postToParent(CONNECTION_EVENTS.handshakeInit, this.#allowedOrigin);\n } catch (error) {\n this.#clearPending(this.#pendingHandshake);\n this.#pendingHandshake = null;\n this.#unsubscribe?.();\n this.#unsubscribe = null;\n this.#allowedOrigin = null;\n this.#tenantUrl = null;\n this.#clearProactiveAuthTokenRefreshTimer();\n throw error;\n }\n\n return handshakePromise;\n }\n\n destroy(): void {\n this.#destroyed = true;\n this.#connected = false;\n\n this.#clearProactiveAuthTokenRefreshTimer();\n this.#authTokenAutoRefresh = false;\n this.#authTokenRefreshRetryUsed = false;\n\n this.#unsubscribe?.();\n this.#unsubscribe = null;\n this.#allowedOrigin = null;\n this.#tenantUrl = null;\n\n this.#rejectPending(this.#pendingHandshake, new Error(\"SDK destroyed.\"));\n this.#rejectPending(this.#pendingAuthTokenRefresh, new Error(\"SDK destroyed.\"));\n this.#rejectPending(this.#pendingPageSettingsUpdate, new Error(\"SDK destroyed.\"));\n this.#pendingHandshake = null;\n this.#pendingAuthTokenRefresh = null;\n this.#pendingPageSettingsUpdate = null;\n\n this.#loadPageSettingsHandlers.clear();\n this.#authTokenRefreshHandlers.clear();\n\n this.#authToken = null;\n this.#extensionDetails = null;\n this.#designTokens = null;\n this.#pageSettings = null;\n }\n\n getAuthToken(): AuthToken | null {\n return this.#authToken;\n }\n\n getExtensionDetails(): ExtensionDetails | null {\n return this.#extensionDetails;\n }\n\n getDesignTokens(): DesignTokens | null {\n return this.#designTokens;\n }\n\n getPageSettings(): PageSettings | null {\n return this.#pageSettings;\n }\n\n getAllowedOrigin(): string | null {\n return this.#allowedOrigin;\n }\n\n getTenantUrl(): string | null {\n return this.#tenantUrl;\n }\n\n getApiUrl(): string | null {\n if (!this.#extensionDetails) {\n return null;\n }\n\n return deriveApiUrl(this.#extensionDetails.baseUrl);\n }\n\n async apiCall<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n this.#assertConnected();\n\n return callApi<T>(\n endpoint,\n {\n baseUrl: this.#extensionDetails!.baseUrl,\n tenantDomain: this.#extensionDetails!.tenantDomain,\n authTokenJwt: this.#authToken!.jwt,\n },\n options,\n );\n }\n\n async emitRequestAuthTokenRefresh(\n options: RequestOptions = {},\n ): Promise<AuthToken> {\n this.#assertConnected();\n\n if (this.#pendingAuthTokenRefresh) {\n throw new Error(\"Auth token refresh already in progress.\");\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const allowedOrigin = this.#allowedOrigin!;\n\n const promise = new Promise<AuthToken>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingAuthTokenRefresh = null;\n reject(new Error(`Auth token refresh timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingAuthTokenRefresh = { resolve, reject, timer };\n });\n\n postToParent(CONNECTION_EVENTS.requestAuthTokenRefresh, allowedOrigin);\n return promise;\n }\n\n async emitUpdatePageSettings(\n payload: UpdatePageSettingsPayload,\n options: RequestOptions = {},\n ): Promise<PageSettingsUpdatedPayload> {\n this.#assertConnected();\n\n if (this.#pendingPageSettingsUpdate) {\n throw new Error(\"Page settings update already in progress.\");\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const allowedOrigin = this.#allowedOrigin!;\n\n const promise = new Promise<PageSettingsUpdatedPayload>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingPageSettingsUpdate = null;\n reject(new Error(`Page settings update timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingPageSettingsUpdate = { resolve, reject, timer };\n });\n\n postToParent(CONNECTION_EVENTS.updatePageSettings, allowedOrigin, payload);\n return promise;\n }\n\n onLoadPageSettings(handler: (settings: PageSettings) => void): () => void {\n this.#loadPageSettingsHandlers.add(handler);\n return () => {\n this.#loadPageSettingsHandlers.delete(handler);\n };\n }\n\n onAuthTokenRefresh(handler: (authToken: AuthToken) => void): () => void {\n this.#authTokenRefreshHandlers.add(handler);\n return () => {\n this.#authTokenRefreshHandlers.delete(handler);\n };\n }\n\n emitNavigationChange(payload: NavigationChangePayload): void {\n this.#assertConnected();\n postToParent(\n CONNECTION_EVENTS.navigationChange,\n this.#allowedOrigin!,\n payload,\n );\n }\n\n #onMessage(event: MessageEvent<ExtensionMessage>): void {\n const { type, payload } = event.data;\n\n switch (type) {\n case CONNECTION_EVENTS.handshakeAck:\n this.#handleHandshakeAck(payload as HandshakePayload | undefined);\n break;\n case CONNECTION_EVENTS.authTokenRefresh:\n this.#handleAuthTokenRefresh(payload as AuthTokenRefreshPayload | undefined);\n break;\n case CONNECTION_EVENTS.loadPageSettings:\n this.#handleLoadPageSettings(payload as PageSettings | undefined);\n break;\n case CONNECTION_EVENTS.pageSettingsUpdated:\n this.#handlePageSettingsUpdated(\n payload as PageSettingsUpdatedPayload | undefined,\n );\n break;\n default:\n break;\n }\n }\n\n #handleHandshakeAck(payload: HandshakePayload | undefined): void {\n if (!payload?.authToken || !payload.extensionDetails || !payload.designTokens) {\n this.#rejectPending(\n this.#pendingHandshake,\n new Error(\"Invalid HANDSHAKE_ACK payload.\"),\n );\n this.#pendingHandshake = null;\n return;\n }\n\n this.#authToken = payload.authToken;\n this.#extensionDetails = payload.extensionDetails;\n this.#designTokens = payload.designTokens;\n this.#pageSettings = payload.pageSettings ?? null;\n this.#connected = true;\n\n const pending = this.#pendingHandshake;\n this.#pendingHandshake = null;\n this.#resolvePending(pending, {\n authToken: this.#authToken,\n extensionDetails: this.#extensionDetails,\n designTokens: this.#designTokens,\n pageSettings: this.#pageSettings,\n });\n\n this.#authTokenRefreshRetryUsed = false;\n this.#scheduleProactiveAuthTokenRefresh();\n }\n\n #handleAuthTokenRefresh(payload: AuthTokenRefreshPayload | undefined): void {\n if (!payload?.authToken) {\n this.#rejectPending(\n this.#pendingAuthTokenRefresh,\n new Error(\"Invalid TOKEN_REFRESH payload.\"),\n );\n this.#pendingAuthTokenRefresh = null;\n return;\n }\n\n this.#authToken = payload.authToken;\n\n const pending = this.#pendingAuthTokenRefresh;\n this.#pendingAuthTokenRefresh = null;\n this.#resolvePending(pending, this.#authToken);\n\n for (const handler of this.#authTokenRefreshHandlers) {\n handler(this.#authToken);\n }\n\n this.#authTokenRefreshRetryUsed = false;\n this.#scheduleProactiveAuthTokenRefresh();\n }\n\n #handleLoadPageSettings(payload: PageSettings | undefined): void {\n const settings = payload ?? {};\n this.#pageSettings = settings;\n\n for (const handler of this.#loadPageSettingsHandlers) {\n handler(settings);\n }\n }\n\n #handlePageSettingsUpdated(\n payload: PageSettingsUpdatedPayload | undefined,\n ): void {\n if (!payload || typeof payload.success !== \"boolean\") {\n this.#rejectPending(\n this.#pendingPageSettingsUpdate,\n new Error(\"Invalid PAGE_SETTINGS_UPDATED payload.\"),\n );\n this.#pendingPageSettingsUpdate = null;\n return;\n }\n\n const pending = this.#pendingPageSettingsUpdate;\n this.#pendingPageSettingsUpdate = null;\n this.#resolvePending(pending, payload);\n }\n\n #assertNotDestroyed(): void {\n if (this.#destroyed) {\n throw new Error(\"SDK has been destroyed.\");\n }\n }\n\n #assertConnected(): void {\n this.#assertNotDestroyed();\n if (!this.#connected || !this.#allowedOrigin) {\n throw new Error(\"SDK is not connected. Call connect() first.\");\n }\n }\n\n #configureAuthTokenAutoRefresh(options: ConnectOptions): void {\n if (options.authTokenBufferMs !== undefined) {\n if (\n !Number.isFinite(options.authTokenBufferMs) ||\n options.authTokenBufferMs < 0\n ) {\n throw new Error(\n \"authTokenBufferMs must be a finite non-negative number.\",\n );\n }\n }\n\n this.#authTokenAutoRefresh = options.authTokenAutoRefresh === true;\n this.#authTokenBufferMs =\n options.authTokenBufferMs ?? DEFAULT_AUTH_TOKEN_BUFFER_MS;\n this.#authTokenRefreshRetryUsed = false;\n this.#clearProactiveAuthTokenRefreshTimer();\n }\n\n #parseExpiresAtMs(authToken: AuthToken): number | null {\n const expiresSec = Number(authToken.expires);\n if (!Number.isFinite(expiresSec)) {\n return null;\n }\n return expiresSec * 1000;\n }\n\n #getProactiveRefreshDelayMs(authToken: AuthToken): number | null {\n const expiresAtMs = this.#parseExpiresAtMs(authToken);\n if (expiresAtMs === null) {\n return null;\n }\n return Math.max(0, expiresAtMs - this.#authTokenBufferMs - Date.now());\n }\n\n #clearProactiveAuthTokenRefreshTimer(): void {\n if (this.#authTokenRefreshTimer !== null) {\n clearTimeout(this.#authTokenRefreshTimer);\n this.#authTokenRefreshTimer = null;\n }\n }\n\n #scheduleProactiveAuthTokenRefresh(): void {\n this.#clearProactiveAuthTokenRefreshTimer();\n\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n !this.#authToken\n ) {\n return;\n }\n\n const delayMs = this.#getProactiveRefreshDelayMs(this.#authToken);\n if (delayMs === null) {\n return;\n }\n\n const clampedDelay = Math.min(delayMs, MAX_TIMEOUT_MS);\n this.#authTokenRefreshTimer = setTimeout(() => {\n this.#authTokenRefreshTimer = null;\n void this.#runProactiveAuthTokenRefresh();\n }, clampedDelay);\n }\n\n async #runProactiveAuthTokenRefresh(): Promise<void> {\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n !this.#authToken\n ) {\n return;\n }\n\n const authTokenAtRequest = this.#authToken;\n const delayMs = this.#getProactiveRefreshDelayMs(authTokenAtRequest);\n if (delayMs === null) {\n return;\n }\n\n if (delayMs > 0) {\n this.#scheduleProactiveAuthTokenRefresh();\n return;\n }\n\n if (this.#pendingAuthTokenRefresh) {\n this.#handleProactiveAuthTokenRefreshFailure(authTokenAtRequest);\n return;\n }\n\n try {\n await this.emitRequestAuthTokenRefresh();\n } catch {\n this.#handleProactiveAuthTokenRefreshFailure(authTokenAtRequest);\n }\n }\n\n #handleProactiveAuthTokenRefreshFailure(authTokenAtRequest: AuthToken): void {\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n this.#authToken?.jwt !== authTokenAtRequest.jwt\n ) {\n return;\n }\n\n if (this.#authTokenRefreshRetryUsed) {\n return;\n }\n\n const expiresAtMs = this.#parseExpiresAtMs(authTokenAtRequest);\n if (expiresAtMs === null) {\n return;\n }\n\n const remainingMs = expiresAtMs - Date.now();\n if (remainingMs <= 0) {\n return;\n }\n\n this.#authTokenRefreshRetryUsed = true;\n this.#clearProactiveAuthTokenRefreshTimer();\n\n const retryDelay = Math.min(AUTO_REFRESH_RETRY_DELAY_MS, remainingMs);\n this.#authTokenRefreshTimer = setTimeout(() => {\n this.#authTokenRefreshTimer = null;\n void this.#runProactiveAuthTokenRefresh();\n }, retryDelay);\n }\n\n #clearPending(pending: { timer: ReturnType<typeof setTimeout> } | null): void {\n if (pending) {\n clearTimeout(pending.timer);\n }\n }\n\n #resolvePending<T>(pending: Pending<T> | null, value: T): void {\n if (!pending) {\n return;\n }\n clearTimeout(pending.timer);\n pending.resolve(value);\n }\n\n #rejectPending(\n pending: { timer: ReturnType<typeof setTimeout>; reject: (reason?: unknown) => void } | null,\n reason: unknown,\n ): void {\n if (!pending) {\n return;\n }\n clearTimeout(pending.timer);\n pending.reject(reason);\n }\n}\n","import { ExtensionSDK, type IExtensionSDK } from \"./ExtensionSDK\";\n\nexport { ExtensionSDK, type IExtensionSDK } from \"./ExtensionSDK\";\nexport { CONNECTION_EVENTS, type ConnectionEvent } from \"./events\";\nexport {\n InvalidOriginError,\n readTenantUrlFromLocation,\n resolveAllowedOrigin,\n} from \"./origin\";\nexport type {\n AuthToken,\n AuthTokenRefreshPayload,\n ConnectOptions,\n DesignTokens,\n ExtensionDetails,\n ExtensionMessage,\n HandshakePayload,\n NavigationChangePayload,\n PageSettings,\n PageSettingsUpdatedPayload,\n RequestOptions,\n UpdatePageSettingsPayload,\n} from \"./types\";\n\n/** Creates a new {@link IExtensionSDK} instance for the current extension frame. */\nexport const createExtensionSDK = (): IExtensionSDK => {\n return new ExtensionSDK();\n};\n"],"mappings":"mEAOA,SAAgB,EAAa,EAAyB,CACpD,GAAI,EAAQ,WAAW,GAAG,EACxB,OAAO,EAGT,IAAM,EAAM,IAAI,IAAI,CAAO,EAE3B,MADA,GAAI,SAAW,OAAO,EAAI,WACnB,EAAI,MACb,CAEA,SAAS,EAAmB,EAAiB,EAA0B,CACrE,GAAI,CAAC,EAAS,WAAW,GAAG,GAAK,EAAS,WAAW,IAAI,EACvD,MAAU,MACR,uEACF,EAGF,MAAO,GAAG,EAAa,CAAO,CAAC,CAAC,QAAQ,OAAQ,EAAE,IAAI,GACxD,CAEA,eAAsB,EACpB,EACA,EACA,EAAuB,CAAC,EACZ,CACZ,IAAM,EAAU,IAAI,QAAQ,EAAQ,OAAO,EAEtC,EAAQ,IAAI,cAAc,GAC7B,EAAQ,IAAI,eAAgB,kBAAkB,EAGhD,EAAQ,IAAI,gBAAiB,UAAU,EAAQ,cAAc,EAC7D,EAAQ,IAAI,WAAY,EAAQ,YAAY,EAE5C,IAAM,EAAW,MAAM,MAAM,EAAmB,EAAQ,QAAS,CAAQ,EAAG,CAC1E,GAAG,EACH,SACF,CAAC,EAED,GAAI,CAAC,EAAS,GAAI,CAChB,IAAM,EAAa,EAAS,WAAa,IAAI,EAAS,aAAe,GACrE,MAAU,MAAM,oBAAoB,EAAS,SAAS,EAAW,EAAE,CACrE,CAEA,OAAQ,MAAM,EAAS,KAAK,CAC9B,CC9CA,IAAa,EAAoB,CAE/B,cAAe,iBAEf,aAAc,gBAEd,wBAAyB,wBAEzB,iBAAkB,gBAElB,iBAAkB,qBAElB,mBAAoB,uBAEpB,oBAAqB,wBAErB,iBAAkB,mBACpB,EClBA,SAAgB,EACd,EACA,EACA,EACM,CACN,GAAI,CAAC,OAAO,QAAU,OAAO,SAAW,OACtC,MAAU,MAAM,iDAAiD,EAGnE,IAAM,EAA4B,IAAY,IAAA,GAAY,CAAE,MAAK,EAAI,CAAE,OAAM,SAAQ,EACrF,OAAO,OAAO,YAAY,EAAS,CAAa,CAClD,CAEA,SAAgB,EACd,EACA,EACY,CACZ,IAAM,EAAY,GAAwB,CACpC,EAAM,SAAW,IAIjB,CAAC,EAAM,MAAQ,OAAO,EAAM,MAAS,UAAY,EAAE,SAAU,EAAM,OAIvE,EAAQ,CAAuC,EACjD,EAGA,OADA,OAAO,iBAAiB,UAAW,CAAQ,MAC9B,OAAO,oBAAoB,UAAW,CAAQ,CAC7D,CCpCA,IAAM,EAAkB,IAAI,IAAI,CAAC,YAAa,YAAa,OAAO,CAAC,EAGtD,EAAb,cAAwC,KAAM,CAC5C,YAAY,EAAiB,CAC3B,MAAM,CAAO,EACb,KAAK,KAAO,oBACd,CACF,EAUA,SAAgB,EAAqB,EAAkC,CACrE,GAAI,CAAC,EACH,MAAM,IAAI,EACR,2EACF,EAGF,IAAI,EACJ,GAAI,CACF,EAAM,IAAI,IAAI,CAAS,CACzB,MAAQ,CACN,MAAM,IAAI,EAAmB,uBAAuB,EAAU,GAAG,CACnE,CAEA,IAAM,EAAc,EAAgB,IAAI,EAAI,QAAQ,EAC9C,EAAU,EAAI,WAAa,SAC3B,EAAc,EAAI,WAAa,SAAW,EAEhD,GAAI,CAAC,GAAW,CAAC,EACf,MAAM,IAAI,EACR,+DAA+D,EAAI,SAAS,IAAI,EAAI,KAAK,GAC3F,EAGF,OAAO,EAAI,MACb,CAUA,SAAgB,EACd,EAAiB,OAAO,SAAS,OAClB,CACf,OAAO,IAAI,gBAAgB,CAAM,CAAC,CAAC,IAAI,WAAW,CACpD,CCtCA,IAAM,EAAqB,IACrB,EAA+B,KAC/B,EAA8B,IAE9B,EAAiB,WA0IV,EAAb,KAAmD,CACjD,GAAgC,KAChC,GAA4B,KAC5B,GAAoC,KACpC,GAAa,GACb,GAAa,GAEb,GAA+B,KAC/B,GAA6C,KAC7C,GAAqC,KACrC,GAAqC,KAErC,GAAwB,GACxB,GAAqB,EACrB,GAA+D,KAC/D,GAA6B,GAE7B,GAAsD,KACtD,GAAsD,KACtD,GAAyE,KAEzE,GAA4B,IAAI,IAChC,GAA4B,IAAI,IAEhC,IAAI,aAAuB,CACzB,OAAO,KAAKA,EACd,CAEA,MAAM,QAAQ,EAA0B,CAAC,EAA8B,CAGrE,GAFA,KAAKC,GAAoB,EAErB,KAAKD,IAAc,KAAKE,IAAc,KAAKC,IAAqB,KAAKC,GACvE,MAAO,CACL,UAAW,KAAKF,GAChB,iBAAkB,KAAKC,GACvB,aAAc,KAAKC,GACnB,aAAc,KAAKC,EACrB,EAGF,GAAI,KAAKC,GACP,MAAU,MAAM,gCAAgC,EAGlD,KAAKC,GAA+B,CAAO,EAE3C,IAAM,EAAY,EAA0B,EAC5C,KAAKC,GAAiB,EAAqB,CAAS,EACpD,KAAKC,GAAa,EAElB,KAAKC,KAAe,EACpB,KAAKA,GAAe,EAClB,KAAKF,GACJ,GAAU,KAAKG,GAAW,CAAK,CAClC,EAEA,IAAM,EAAY,EAAQ,WAAa,EAEjC,EAAmB,IAAI,SAA2B,EAAS,IAAW,CAC1E,IAAM,EAAQ,eAAiB,CAC7B,KAAKL,GAAoB,KACzB,EAAW,MAAM,6BAA6B,EAAU,IAAI,CAAC,CAC/D,EAAG,CAAS,EAEZ,KAAKA,GAAoB,CAAE,UAAS,SAAQ,OAAM,CACpD,CAAC,EAED,GAAI,CACF,EAAa,EAAkB,cAAe,KAAKE,EAAc,CACnE,OAAS,EAAO,CAQd,MAPA,KAAKI,GAAc,KAAKN,EAAiB,EACzC,KAAKA,GAAoB,KACzB,KAAKI,KAAe,EACpB,KAAKA,GAAe,KACpB,KAAKF,GAAiB,KACtB,KAAKC,GAAa,KAClB,KAAKI,GAAqC,EACpC,CACR,CAEA,OAAO,CACT,CAEA,SAAgB,CACd,KAAKC,GAAa,GAClB,KAAKd,GAAa,GAElB,KAAKa,GAAqC,EAC1C,KAAKE,GAAwB,GAC7B,KAAKC,GAA6B,GAElC,KAAKN,KAAe,EACpB,KAAKA,GAAe,KACpB,KAAKF,GAAiB,KACtB,KAAKC,GAAa,KAElB,KAAKQ,GAAe,KAAKX,GAAuB,MAAM,gBAAgB,CAAC,EACvE,KAAKW,GAAe,KAAKC,GAA8B,MAAM,gBAAgB,CAAC,EAC9E,KAAKD,GAAe,KAAKE,GAAgC,MAAM,gBAAgB,CAAC,EAChF,KAAKb,GAAoB,KACzB,KAAKY,GAA2B,KAChC,KAAKC,GAA6B,KAElC,KAAKC,GAA0B,MAAM,EACrC,KAAKC,GAA0B,MAAM,EAErC,KAAKnB,GAAa,KAClB,KAAKC,GAAoB,KACzB,KAAKC,GAAgB,KACrB,KAAKC,GAAgB,IACvB,CAEA,cAAiC,CAC/B,OAAO,KAAKH,EACd,CAEA,qBAA+C,CAC7C,OAAO,KAAKC,EACd,CAEA,iBAAuC,CACrC,OAAO,KAAKC,EACd,CAEA,iBAAuC,CACrC,OAAO,KAAKC,EACd,CAEA,kBAAkC,CAChC,OAAO,KAAKG,EACd,CAEA,cAA8B,CAC5B,OAAO,KAAKC,EACd,CAEA,WAA2B,CAKzB,OAJK,KAAKN,GAIH,EAAa,KAAKA,GAAkB,OAAO,EAHzC,IAIX,CAEA,MAAM,QACJ,EACA,EAAuB,CAAC,EACZ,CAGZ,OAFA,KAAKmB,GAAiB,EAEf,EACL,EACA,CACE,QAAS,KAAKnB,GAAmB,QACjC,aAAc,KAAKA,GAAmB,aACtC,aAAc,KAAKD,GAAY,GACjC,EACA,CACF,CACF,CAEA,MAAM,4BACJ,EAA0B,CAAC,EACP,CAGpB,GAFA,KAAKoB,GAAiB,EAElB,KAAKJ,GACP,MAAU,MAAM,yCAAyC,EAG3D,IAAM,EAAY,EAAQ,WAAa,EACjC,EAAgB,KAAKV,GAErB,EAAU,IAAI,SAAoB,EAAS,IAAW,CAC1D,IAAM,EAAQ,eAAiB,CAC7B,KAAKU,GAA2B,KAChC,EAAW,MAAM,sCAAsC,EAAU,IAAI,CAAC,CACxE,EAAG,CAAS,EAEZ,KAAKA,GAA2B,CAAE,UAAS,SAAQ,OAAM,CAC3D,CAAC,EAGD,OADA,EAAa,EAAkB,wBAAyB,CAAa,EAC9D,CACT,CAEA,MAAM,uBACJ,EACA,EAA0B,CAAC,EACU,CAGrC,GAFA,KAAKI,GAAiB,EAElB,KAAKH,GACP,MAAU,MAAM,2CAA2C,EAG7D,IAAM,EAAY,EAAQ,WAAa,EACjC,EAAgB,KAAKX,GAErB,EAAU,IAAI,SAAqC,EAAS,IAAW,CAC3E,IAAM,EAAQ,eAAiB,CAC7B,KAAKW,GAA6B,KAClC,EAAW,MAAM,wCAAwC,EAAU,IAAI,CAAC,CAC1E,EAAG,CAAS,EAEZ,KAAKA,GAA6B,CAAE,UAAS,SAAQ,OAAM,CAC7D,CAAC,EAGD,OADA,EAAa,EAAkB,mBAAoB,EAAe,CAAO,EAClE,CACT,CAEA,mBAAmB,EAAuD,CAExE,OADA,KAAKC,GAA0B,IAAI,CAAO,MAC7B,CACX,KAAKA,GAA0B,OAAO,CAAO,CAC/C,CACF,CAEA,mBAAmB,EAAqD,CAEtE,OADA,KAAKC,GAA0B,IAAI,CAAO,MAC7B,CACX,KAAKA,GAA0B,OAAO,CAAO,CAC/C,CACF,CAEA,qBAAqB,EAAwC,CAC3D,KAAKC,GAAiB,EACtB,EACE,EAAkB,iBAClB,KAAKd,GACL,CACF,CACF,CAEA,GAAW,EAA6C,CACtD,GAAM,CAAE,OAAM,WAAY,EAAM,KAEhC,OAAQ,EAAR,CACE,KAAK,EAAkB,aACrB,KAAKe,GAAoB,CAAuC,EAChE,MACF,KAAK,EAAkB,iBACrB,KAAKC,GAAwB,CAA8C,EAC3E,MACF,KAAK,EAAkB,iBACrB,KAAKC,GAAwB,CAAmC,EAChE,MACF,KAAK,EAAkB,oBACrB,KAAKC,GACH,CACF,EACA,MACF,QACE,KACJ,CACF,CAEA,GAAoB,EAA6C,CAC/D,GAAI,CAAC,GAAS,WAAa,CAAC,EAAQ,kBAAoB,CAAC,EAAQ,aAAc,CAC7E,KAAKT,GACH,KAAKX,GACD,MAAM,gCAAgC,CAC5C,EACA,KAAKA,GAAoB,KACzB,MACF,CAEA,KAAKJ,GAAa,EAAQ,UAC1B,KAAKC,GAAoB,EAAQ,iBACjC,KAAKC,GAAgB,EAAQ,aAC7B,KAAKC,GAAgB,EAAQ,cAAgB,KAC7C,KAAKL,GAAa,GAElB,IAAM,EAAU,KAAKM,GACrB,KAAKA,GAAoB,KACzB,KAAKqB,GAAgB,EAAS,CAC5B,UAAW,KAAKzB,GAChB,iBAAkB,KAAKC,GACvB,aAAc,KAAKC,GACnB,aAAc,KAAKC,EACrB,CAAC,EAED,KAAKW,GAA6B,GAClC,KAAKY,GAAmC,CAC1C,CAEA,GAAwB,EAAoD,CAC1E,GAAI,CAAC,GAAS,UAAW,CACvB,KAAKX,GACH,KAAKC,GACD,MAAM,gCAAgC,CAC5C,EACA,KAAKA,GAA2B,KAChC,MACF,CAEA,KAAKhB,GAAa,EAAQ,UAE1B,IAAM,EAAU,KAAKgB,GACrB,KAAKA,GAA2B,KAChC,KAAKS,GAAgB,EAAS,KAAKzB,EAAU,EAE7C,IAAK,IAAM,KAAW,KAAKmB,GACzB,EAAQ,KAAKnB,EAAU,EAGzB,KAAKc,GAA6B,GAClC,KAAKY,GAAmC,CAC1C,CAEA,GAAwB,EAAyC,CAC/D,IAAM,EAAW,GAAW,CAAC,EAC7B,KAAKvB,GAAgB,EAErB,IAAK,IAAM,KAAW,KAAKe,GACzB,EAAQ,CAAQ,CAEpB,CAEA,GACE,EACM,CACN,GAAI,CAAC,GAAW,OAAO,EAAQ,SAAY,UAAW,CACpD,KAAKH,GACH,KAAKE,GACD,MAAM,wCAAwC,CACpD,EACA,KAAKA,GAA6B,KAClC,MACF,CAEA,IAAM,EAAU,KAAKA,GACrB,KAAKA,GAA6B,KAClC,KAAKQ,GAAgB,EAAS,CAAO,CACvC,CAEA,IAA4B,CAC1B,GAAI,KAAKb,GACP,MAAU,MAAM,yBAAyB,CAE7C,CAEA,IAAyB,CAEvB,GADA,KAAKb,GAAoB,EACrB,CAAC,KAAKD,IAAc,CAAC,KAAKQ,GAC5B,MAAU,MAAM,6CAA6C,CAEjE,CAEA,GAA+B,EAA+B,CAC5D,GAAI,EAAQ,oBAAsB,IAAA,KAE9B,CAAC,OAAO,SAAS,EAAQ,iBAAiB,GAC1C,EAAQ,kBAAoB,GAE5B,MAAU,MACR,yDACF,EAIJ,KAAKO,GAAwB,EAAQ,uBAAyB,GAC9D,KAAKc,GACH,EAAQ,mBAAqB,EAC/B,KAAKb,GAA6B,GAClC,KAAKH,GAAqC,CAC5C,CAEA,GAAkB,EAAqC,CACrD,IAAM,EAAa,OAAO,EAAU,OAAO,EAI3C,OAHK,OAAO,SAAS,CAAU,EAGxB,EAAa,IAFX,IAGX,CAEA,GAA4B,EAAqC,CAC/D,IAAM,EAAc,KAAKiB,GAAkB,CAAS,EAIpD,OAHI,IAAgB,KACX,KAEF,KAAK,IAAI,EAAG,EAAc,KAAKD,GAAqB,KAAK,IAAI,CAAC,CACvE,CAEA,IAA6C,CACvC,KAAKE,KAA2B,OAClC,aAAa,KAAKA,EAAsB,EACxC,KAAKA,GAAyB,KAElC,CAEA,IAA2C,CAGzC,GAFA,KAAKlB,GAAqC,EAGxC,CAAC,KAAKE,IACN,CAAC,KAAKf,IACN,KAAKc,IACL,CAAC,KAAKZ,GAEN,OAGF,IAAM,EAAU,KAAK8B,GAA4B,KAAK9B,EAAU,EAChE,GAAI,IAAY,KACd,OAGF,IAAM,EAAe,KAAK,IAAI,EAAS,CAAc,EACrD,KAAK6B,GAAyB,eAAiB,CAC7C,KAAKA,GAAyB,KAC9B,KAAUE,GAA8B,CAC1C,EAAG,CAAY,CACjB,CAEA,KAAMA,IAA+C,CACnD,GACE,CAAC,KAAKlB,IACN,CAAC,KAAKf,IACN,KAAKc,IACL,CAAC,KAAKZ,GAEN,OAGF,IAAM,EAAqB,KAAKA,GAC1B,EAAU,KAAK8B,GAA4B,CAAkB,EAC/D,OAAY,KAIhB,IAAI,EAAU,EAAG,CACf,KAAKJ,GAAmC,EACxC,MACF,CAEA,GAAI,KAAKV,GAA0B,CACjC,KAAKgB,GAAwC,CAAkB,EAC/D,MACF,CAEA,GAAI,CACF,MAAM,KAAK,4BAA4B,CACzC,MAAQ,CACN,KAAKA,GAAwC,CAAkB,CACjE,CAXA,CAYF,CAEA,GAAwC,EAAqC,CAU3E,GARE,CAAC,KAAKnB,IACN,CAAC,KAAKf,IACN,KAAKc,IACL,KAAKZ,IAAY,MAAQ,EAAmB,KAK1C,KAAKc,GACP,OAGF,IAAM,EAAc,KAAKc,GAAkB,CAAkB,EAC7D,GAAI,IAAgB,KAClB,OAGF,IAAM,EAAc,EAAc,KAAK,IAAI,EAC3C,GAAI,GAAe,EACjB,OAGF,KAAKd,GAA6B,GAClC,KAAKH,GAAqC,EAE1C,IAAM,EAAa,KAAK,IAAI,EAA6B,CAAW,EACpE,KAAKkB,GAAyB,eAAiB,CAC7C,KAAKA,GAAyB,KAC9B,KAAUE,GAA8B,CAC1C,EAAG,CAAU,CACf,CAEA,GAAc,EAAgE,CACxE,GACF,aAAa,EAAQ,KAAK,CAE9B,CAEA,GAAmB,EAA4B,EAAgB,CACxD,IAGL,aAAa,EAAQ,KAAK,EAC1B,EAAQ,QAAQ,CAAK,EACvB,CAEA,GACE,EACA,EACM,CACD,IAGL,aAAa,EAAQ,KAAK,EAC1B,EAAQ,OAAO,CAAM,EACvB,CACF,ECnoBa,MACJ,IAAI"}
|
package/dist/extension-sdk.js
CHANGED
|
@@ -80,40 +80,41 @@ function l(e = window.location.search) {
|
|
|
80
80
|
var u = 1e4, d = 12e4, f = 3e4, p = 2147483647, m = class {
|
|
81
81
|
#e = null;
|
|
82
82
|
#t = null;
|
|
83
|
-
#n =
|
|
83
|
+
#n = null;
|
|
84
84
|
#r = !1;
|
|
85
|
-
#i =
|
|
85
|
+
#i = !1;
|
|
86
86
|
#a = null;
|
|
87
87
|
#o = null;
|
|
88
88
|
#s = null;
|
|
89
|
-
#c =
|
|
90
|
-
#l =
|
|
91
|
-
#u =
|
|
92
|
-
#d =
|
|
93
|
-
#f =
|
|
89
|
+
#c = null;
|
|
90
|
+
#l = !1;
|
|
91
|
+
#u = d;
|
|
92
|
+
#d = null;
|
|
93
|
+
#f = !1;
|
|
94
94
|
#p = null;
|
|
95
95
|
#m = null;
|
|
96
|
-
#h =
|
|
96
|
+
#h = null;
|
|
97
97
|
#g = /* @__PURE__ */ new Set();
|
|
98
|
+
#_ = /* @__PURE__ */ new Set();
|
|
98
99
|
get isConnected() {
|
|
99
|
-
return this.#
|
|
100
|
+
return this.#r;
|
|
100
101
|
}
|
|
101
102
|
async connect(e = {}) {
|
|
102
|
-
if (this.#
|
|
103
|
-
authToken: this.#
|
|
104
|
-
extensionDetails: this.#
|
|
105
|
-
designTokens: this.#
|
|
106
|
-
pageSettings: this.#
|
|
103
|
+
if (this.#C(), this.#r && this.#a && this.#o && this.#s) return {
|
|
104
|
+
authToken: this.#a,
|
|
105
|
+
extensionDetails: this.#o,
|
|
106
|
+
designTokens: this.#s,
|
|
107
|
+
pageSettings: this.#c
|
|
107
108
|
};
|
|
108
|
-
if (this.#
|
|
109
|
-
this.#
|
|
109
|
+
if (this.#p) throw Error("Handshake already in progress.");
|
|
110
|
+
this.#T(e);
|
|
110
111
|
let t = l();
|
|
111
|
-
this.#e = c(t), this.#t?.(), this.#
|
|
112
|
+
this.#e = c(t), this.#t = t, this.#n?.(), this.#n = a(this.#e, (e) => this.#v(e));
|
|
112
113
|
let n = e.timeoutMs ?? u, o = new Promise((e, t) => {
|
|
113
114
|
let r = setTimeout(() => {
|
|
114
|
-
this.#
|
|
115
|
+
this.#p = null, t(/* @__PURE__ */ Error(`Handshake timed out after ${n}ms.`));
|
|
115
116
|
}, n);
|
|
116
|
-
this.#
|
|
117
|
+
this.#p = {
|
|
117
118
|
resolve: e,
|
|
118
119
|
reject: t,
|
|
119
120
|
timer: r
|
|
@@ -122,39 +123,48 @@ var u = 1e4, d = 12e4, f = 3e4, p = 2147483647, m = class {
|
|
|
122
123
|
try {
|
|
123
124
|
i(r.handshakeInit, this.#e);
|
|
124
125
|
} catch (e) {
|
|
125
|
-
throw this.#
|
|
126
|
+
throw this.#M(this.#p), this.#p = null, this.#n?.(), this.#n = null, this.#e = null, this.#t = null, this.#O(), e;
|
|
126
127
|
}
|
|
127
128
|
return o;
|
|
128
129
|
}
|
|
129
130
|
destroy() {
|
|
130
|
-
this.#
|
|
131
|
+
this.#i = !0, this.#r = !1, this.#O(), this.#l = !1, this.#f = !1, this.#n?.(), this.#n = null, this.#e = null, this.#t = null, this.#P(this.#p, /* @__PURE__ */ Error("SDK destroyed.")), this.#P(this.#m, /* @__PURE__ */ Error("SDK destroyed.")), this.#P(this.#h, /* @__PURE__ */ Error("SDK destroyed.")), this.#p = null, this.#m = null, this.#h = null, this.#g.clear(), this.#_.clear(), this.#a = null, this.#o = null, this.#s = null, this.#c = null;
|
|
131
132
|
}
|
|
132
133
|
getAuthToken() {
|
|
133
|
-
return this.#
|
|
134
|
+
return this.#a;
|
|
134
135
|
}
|
|
135
136
|
getExtensionDetails() {
|
|
136
|
-
return this.#
|
|
137
|
+
return this.#o;
|
|
137
138
|
}
|
|
138
139
|
getDesignTokens() {
|
|
139
|
-
return this.#
|
|
140
|
+
return this.#s;
|
|
140
141
|
}
|
|
141
142
|
getPageSettings() {
|
|
142
|
-
return this.#
|
|
143
|
+
return this.#c;
|
|
144
|
+
}
|
|
145
|
+
getAllowedOrigin() {
|
|
146
|
+
return this.#e;
|
|
147
|
+
}
|
|
148
|
+
getTenantUrl() {
|
|
149
|
+
return this.#t;
|
|
150
|
+
}
|
|
151
|
+
getApiUrl() {
|
|
152
|
+
return this.#o ? e(this.#o.baseUrl) : null;
|
|
143
153
|
}
|
|
144
154
|
async apiCall(e, t = {}) {
|
|
145
|
-
return this.#
|
|
146
|
-
baseUrl: this.#
|
|
147
|
-
tenantDomain: this.#
|
|
148
|
-
authTokenJwt: this.#
|
|
155
|
+
return this.#w(), n(e, {
|
|
156
|
+
baseUrl: this.#o.baseUrl,
|
|
157
|
+
tenantDomain: this.#o.tenantDomain,
|
|
158
|
+
authTokenJwt: this.#a.jwt
|
|
149
159
|
}, t);
|
|
150
160
|
}
|
|
151
161
|
async emitRequestAuthTokenRefresh(e = {}) {
|
|
152
|
-
if (this.#
|
|
162
|
+
if (this.#w(), this.#m) throw Error("Auth token refresh already in progress.");
|
|
153
163
|
let t = e.timeoutMs ?? u, n = this.#e, a = new Promise((e, n) => {
|
|
154
164
|
let r = setTimeout(() => {
|
|
155
|
-
this.#
|
|
165
|
+
this.#m = null, n(/* @__PURE__ */ Error(`Auth token refresh timed out after ${t}ms.`));
|
|
156
166
|
}, t);
|
|
157
|
-
this.#
|
|
167
|
+
this.#m = {
|
|
158
168
|
resolve: e,
|
|
159
169
|
reject: n,
|
|
160
170
|
timer: r
|
|
@@ -163,12 +173,12 @@ var u = 1e4, d = 12e4, f = 3e4, p = 2147483647, m = class {
|
|
|
163
173
|
return i(r.requestAuthTokenRefresh, n), a;
|
|
164
174
|
}
|
|
165
175
|
async emitUpdatePageSettings(e, t = {}) {
|
|
166
|
-
if (this.#
|
|
176
|
+
if (this.#w(), this.#h) throw Error("Page settings update already in progress.");
|
|
167
177
|
let n = t.timeoutMs ?? u, a = this.#e, o = new Promise((e, t) => {
|
|
168
178
|
let r = setTimeout(() => {
|
|
169
|
-
this.#
|
|
179
|
+
this.#h = null, t(/* @__PURE__ */ Error(`Page settings update timed out after ${n}ms.`));
|
|
170
180
|
}, n);
|
|
171
|
-
this.#
|
|
181
|
+
this.#h = {
|
|
172
182
|
resolve: e,
|
|
173
183
|
reject: t,
|
|
174
184
|
timer: r
|
|
@@ -177,142 +187,142 @@ var u = 1e4, d = 12e4, f = 3e4, p = 2147483647, m = class {
|
|
|
177
187
|
return i(r.updatePageSettings, a, e), o;
|
|
178
188
|
}
|
|
179
189
|
onLoadPageSettings(e) {
|
|
180
|
-
return this.#
|
|
181
|
-
this.#
|
|
190
|
+
return this.#g.add(e), () => {
|
|
191
|
+
this.#g.delete(e);
|
|
182
192
|
};
|
|
183
193
|
}
|
|
184
194
|
onAuthTokenRefresh(e) {
|
|
185
|
-
return this.#
|
|
186
|
-
this.#
|
|
195
|
+
return this.#_.add(e), () => {
|
|
196
|
+
this.#_.delete(e);
|
|
187
197
|
};
|
|
188
198
|
}
|
|
189
199
|
emitNavigationChange(e) {
|
|
190
|
-
this.#
|
|
200
|
+
this.#w(), i(r.navigationChange, this.#e, e);
|
|
191
201
|
}
|
|
192
|
-
#
|
|
202
|
+
#v(e) {
|
|
193
203
|
let { type: t, payload: n } = e.data;
|
|
194
204
|
switch (t) {
|
|
195
205
|
case r.handshakeAck:
|
|
196
|
-
this.#
|
|
206
|
+
this.#y(n);
|
|
197
207
|
break;
|
|
198
208
|
case r.authTokenRefresh:
|
|
199
|
-
this.#
|
|
209
|
+
this.#b(n);
|
|
200
210
|
break;
|
|
201
211
|
case r.loadPageSettings:
|
|
202
|
-
this.#
|
|
212
|
+
this.#x(n);
|
|
203
213
|
break;
|
|
204
214
|
case r.pageSettingsUpdated:
|
|
205
|
-
this.#
|
|
215
|
+
this.#S(n);
|
|
206
216
|
break;
|
|
207
217
|
default: break;
|
|
208
218
|
}
|
|
209
219
|
}
|
|
210
|
-
#
|
|
220
|
+
#y(e) {
|
|
211
221
|
if (!e?.authToken || !e.extensionDetails || !e.designTokens) {
|
|
212
|
-
this.#
|
|
222
|
+
this.#P(this.#p, /* @__PURE__ */ Error("Invalid HANDSHAKE_ACK payload.")), this.#p = null;
|
|
213
223
|
return;
|
|
214
224
|
}
|
|
215
|
-
this.#
|
|
216
|
-
let t = this.#
|
|
217
|
-
this.#
|
|
218
|
-
authToken: this.#
|
|
219
|
-
extensionDetails: this.#
|
|
220
|
-
designTokens: this.#
|
|
221
|
-
pageSettings: this.#
|
|
222
|
-
}), this.#
|
|
225
|
+
this.#a = e.authToken, this.#o = e.extensionDetails, this.#s = e.designTokens, this.#c = e.pageSettings ?? null, this.#r = !0;
|
|
226
|
+
let t = this.#p;
|
|
227
|
+
this.#p = null, this.#N(t, {
|
|
228
|
+
authToken: this.#a,
|
|
229
|
+
extensionDetails: this.#o,
|
|
230
|
+
designTokens: this.#s,
|
|
231
|
+
pageSettings: this.#c
|
|
232
|
+
}), this.#f = !1, this.#k();
|
|
223
233
|
}
|
|
224
|
-
#
|
|
234
|
+
#b(e) {
|
|
225
235
|
if (!e?.authToken) {
|
|
226
|
-
this.#
|
|
236
|
+
this.#P(this.#m, /* @__PURE__ */ Error("Invalid TOKEN_REFRESH payload.")), this.#m = null;
|
|
227
237
|
return;
|
|
228
238
|
}
|
|
229
|
-
this.#
|
|
230
|
-
let t = this.#
|
|
231
|
-
this.#
|
|
232
|
-
for (let e of this.#
|
|
233
|
-
this.#
|
|
239
|
+
this.#a = e.authToken;
|
|
240
|
+
let t = this.#m;
|
|
241
|
+
this.#m = null, this.#N(t, this.#a);
|
|
242
|
+
for (let e of this.#_) e(this.#a);
|
|
243
|
+
this.#f = !1, this.#k();
|
|
234
244
|
}
|
|
235
|
-
#
|
|
245
|
+
#x(e) {
|
|
236
246
|
let t = e ?? {};
|
|
237
|
-
this.#
|
|
238
|
-
for (let e of this.#
|
|
247
|
+
this.#c = t;
|
|
248
|
+
for (let e of this.#g) e(t);
|
|
239
249
|
}
|
|
240
|
-
#
|
|
250
|
+
#S(e) {
|
|
241
251
|
if (!e || typeof e.success != "boolean") {
|
|
242
|
-
this.#
|
|
252
|
+
this.#P(this.#h, /* @__PURE__ */ Error("Invalid PAGE_SETTINGS_UPDATED payload.")), this.#h = null;
|
|
243
253
|
return;
|
|
244
254
|
}
|
|
245
|
-
let t = this.#
|
|
246
|
-
this.#
|
|
247
|
-
}
|
|
248
|
-
#S() {
|
|
249
|
-
if (this.#r) throw Error("SDK has been destroyed.");
|
|
255
|
+
let t = this.#h;
|
|
256
|
+
this.#h = null, this.#N(t, e);
|
|
250
257
|
}
|
|
251
258
|
#C() {
|
|
252
|
-
if (this.#
|
|
259
|
+
if (this.#i) throw Error("SDK has been destroyed.");
|
|
253
260
|
}
|
|
254
|
-
#w(
|
|
255
|
-
if (
|
|
256
|
-
this.#c = e.authTokenAutoRefresh === !0, this.#l = e.authTokenBufferMs ?? d, this.#d = !1, this.#D();
|
|
261
|
+
#w() {
|
|
262
|
+
if (this.#C(), !this.#r || !this.#e) throw Error("SDK is not connected. Call connect() first.");
|
|
257
263
|
}
|
|
258
264
|
#T(e) {
|
|
259
|
-
|
|
260
|
-
|
|
265
|
+
if (e.authTokenBufferMs !== void 0 && (!Number.isFinite(e.authTokenBufferMs) || e.authTokenBufferMs < 0)) throw Error("authTokenBufferMs must be a finite non-negative number.");
|
|
266
|
+
this.#l = e.authTokenAutoRefresh === !0, this.#u = e.authTokenBufferMs ?? d, this.#f = !1, this.#O();
|
|
261
267
|
}
|
|
262
268
|
#E(e) {
|
|
263
|
-
let t =
|
|
264
|
-
return t
|
|
269
|
+
let t = Number(e.expires);
|
|
270
|
+
return Number.isFinite(t) ? t * 1e3 : null;
|
|
265
271
|
}
|
|
266
|
-
#D() {
|
|
267
|
-
|
|
272
|
+
#D(e) {
|
|
273
|
+
let t = this.#E(e);
|
|
274
|
+
return t === null ? null : Math.max(0, t - this.#u - Date.now());
|
|
268
275
|
}
|
|
269
276
|
#O() {
|
|
270
|
-
|
|
271
|
-
|
|
277
|
+
this.#d !== null && (clearTimeout(this.#d), this.#d = null);
|
|
278
|
+
}
|
|
279
|
+
#k() {
|
|
280
|
+
if (this.#O(), !this.#l || !this.#r || this.#i || !this.#a) return;
|
|
281
|
+
let e = this.#D(this.#a);
|
|
272
282
|
if (e === null) return;
|
|
273
283
|
let t = Math.min(e, p);
|
|
274
|
-
this.#
|
|
275
|
-
this.#
|
|
284
|
+
this.#d = setTimeout(() => {
|
|
285
|
+
this.#d = null, this.#A();
|
|
276
286
|
}, t);
|
|
277
287
|
}
|
|
278
|
-
async #
|
|
279
|
-
if (!this.#
|
|
280
|
-
let e = this.#
|
|
288
|
+
async #A() {
|
|
289
|
+
if (!this.#l || !this.#r || this.#i || !this.#a) return;
|
|
290
|
+
let e = this.#a, t = this.#D(e);
|
|
281
291
|
if (t !== null) {
|
|
282
292
|
if (t > 0) {
|
|
283
|
-
this.#
|
|
293
|
+
this.#k();
|
|
284
294
|
return;
|
|
285
295
|
}
|
|
286
|
-
if (this.#
|
|
287
|
-
this.#
|
|
296
|
+
if (this.#m) {
|
|
297
|
+
this.#j(e);
|
|
288
298
|
return;
|
|
289
299
|
}
|
|
290
300
|
try {
|
|
291
301
|
await this.emitRequestAuthTokenRefresh();
|
|
292
302
|
} catch {
|
|
293
|
-
this.#
|
|
303
|
+
this.#j(e);
|
|
294
304
|
}
|
|
295
305
|
}
|
|
296
306
|
}
|
|
297
|
-
#
|
|
298
|
-
if (!this.#
|
|
299
|
-
let t = this.#
|
|
307
|
+
#j(e) {
|
|
308
|
+
if (!this.#l || !this.#r || this.#i || this.#a?.jwt !== e.jwt || this.#f) return;
|
|
309
|
+
let t = this.#E(e);
|
|
300
310
|
if (t === null) return;
|
|
301
311
|
let n = t - Date.now();
|
|
302
312
|
if (n <= 0) return;
|
|
303
|
-
this.#
|
|
313
|
+
this.#f = !0, this.#O();
|
|
304
314
|
let r = Math.min(f, n);
|
|
305
|
-
this.#
|
|
306
|
-
this.#
|
|
315
|
+
this.#d = setTimeout(() => {
|
|
316
|
+
this.#d = null, this.#A();
|
|
307
317
|
}, r);
|
|
308
318
|
}
|
|
309
|
-
#
|
|
319
|
+
#M(e) {
|
|
310
320
|
e && clearTimeout(e.timer);
|
|
311
321
|
}
|
|
312
|
-
#
|
|
322
|
+
#N(e, t) {
|
|
313
323
|
e && (clearTimeout(e.timer), e.resolve(t));
|
|
314
324
|
}
|
|
315
|
-
#
|
|
325
|
+
#P(e, t) {
|
|
316
326
|
e && (clearTimeout(e.timer), e.reject(t));
|
|
317
327
|
}
|
|
318
328
|
}, h = () => new m();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension-sdk.js","names":["#connected","#assertNotDestroyed","#authToken","#extensionDetails","#designTokens","#pageSettings","#pendingHandshake","#configureAuthTokenAutoRefresh","#allowedOrigin","#unsubscribe","#onMessage","#clearPending","#clearProactiveAuthTokenRefreshTimer","#destroyed","#authTokenAutoRefresh","#authTokenRefreshRetryUsed","#rejectPending","#pendingAuthTokenRefresh","#pendingPageSettingsUpdate","#loadPageSettingsHandlers","#authTokenRefreshHandlers","#assertConnected","#handleHandshakeAck","#handleAuthTokenRefresh","#handleLoadPageSettings","#handlePageSettingsUpdated","#resolvePending","#scheduleProactiveAuthTokenRefresh","#authTokenBufferMs","#parseExpiresAtMs","#authTokenRefreshTimer","#getProactiveRefreshDelayMs","#runProactiveAuthTokenRefresh","#handleProactiveAuthTokenRefreshFailure"],"sources":["../src/api.ts","../src/events.ts","../src/messaging.ts","../src/origin.ts","../src/ExtensionSDK.ts","../src/index.ts"],"sourcesContent":["interface ApiRequestContext {\n baseUrl: string;\n tenantDomain: string;\n authTokenJwt: string;\n}\n\nfunction deriveApiUrl(baseUrl: string): string {\n if (baseUrl.startsWith(\"/\")) {\n return baseUrl;\n }\n\n const url = new URL(baseUrl);\n url.hostname = `api.${url.hostname}`;\n return url.origin;\n}\n\nfunction resolveApiEndpoint(baseUrl: string, endpoint: string): string {\n if (!endpoint.startsWith(\"/\") || endpoint.startsWith(\"//\")) {\n throw new Error(\n 'API endpoint must be a root-relative path starting with a single \"/\".',\n );\n }\n\n return `${deriveApiUrl(baseUrl).replace(/\\/+$/, \"\")}${endpoint}`;\n}\n\nexport async function callApi<T>(\n endpoint: string,\n context: ApiRequestContext,\n options: RequestInit = {},\n): Promise<T> {\n const headers = new Headers(options.headers);\n\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n headers.set(\"Authorization\", `Bearer ${context.authTokenJwt}`);\n headers.set(\"X-Tenant\", context.tenantDomain);\n\n const response = await fetch(resolveApiEndpoint(context.baseUrl, endpoint), {\n ...options,\n headers,\n });\n\n if (!response.ok) {\n const statusText = response.statusText ? ` ${response.statusText}` : \"\";\n throw new Error(`API call failed: ${response.status}${statusText}.`);\n }\n\n return (await response.json()) as T;\n}\n","/**\n * Wire event type strings for parent/child `postMessage` communication.\n *\n * Keys are SDK-facing names; values are the strings sent on the wire.\n * Comments mark message direction relative to the extension (child).\n */\nexport const CONNECTION_EVENTS = {\n /** Child → parent: start handshake. */\n handshakeInit: \"HANDSHAKE_INIT\",\n /** Parent → child: handshake success with auth and context. */\n handshakeAck: \"HANDSHAKE_ACK\",\n /** Child → parent: request a new auth token. */\n requestAuthTokenRefresh: \"REQUEST_TOKEN_REFRESH\",\n /** Parent → child: new auth token (reply or push). */\n authTokenRefresh: \"TOKEN_REFRESH\",\n /** Parent → child: open/load page settings UI with values. */\n loadPageSettings: \"LOAD_PAGE_SETTINGS\",\n /** Child → parent: persist updated page settings. */\n updatePageSettings: \"UPDATE_PAGE_SETTINGS\",\n /** Parent → child: result of a page settings update. */\n pageSettingsUpdated: \"PAGE_SETTINGS_UPDATED\",\n /** Child → parent: extension route changed. */\n navigationChange: \"NAVIGATION_CHANGE\",\n} as const;\n\n/** Union of all {@link CONNECTION_EVENTS} wire string values. */\nexport type ConnectionEvent =\n (typeof CONNECTION_EVENTS)[keyof typeof CONNECTION_EVENTS];\n","import type { ConnectionEvent } from \"./events\";\nimport type { ExtensionMessage } from \"./types\";\n\nexport type MessageHandler = (event: MessageEvent<ExtensionMessage>) => void;\n\nexport function postToParent(\n type: ConnectionEvent,\n allowedOrigin: string,\n payload?: unknown,\n): void {\n if (!window.parent || window.parent === window) {\n throw new Error(\"Extension is not running inside a parent frame.\");\n }\n\n const message: ExtensionMessage = payload === undefined ? { type } : { type, payload };\n window.parent.postMessage(message, allowedOrigin);\n}\n\nexport function subscribeToParentMessages(\n allowedOrigin: string,\n handler: MessageHandler,\n): () => void {\n const listener = (event: MessageEvent) => {\n if (event.origin !== allowedOrigin) {\n return;\n }\n\n if (!event.data || typeof event.data !== \"object\" || !(\"type\" in event.data)) {\n return;\n }\n\n handler(event as MessageEvent<ExtensionMessage>);\n };\n\n window.addEventListener(\"message\", listener);\n return () => window.removeEventListener(\"message\", listener);\n}\n","const LOCALHOST_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/** Thrown when `tenantUrl` is missing or not a safe postMessage origin. */\nexport class InvalidOriginError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidOriginError\";\n }\n}\n\n/**\n * Parses and validates a tenant URL into a postMessage-safe origin.\n * Allows https always; http only for localhost / 127.0.0.1 / [::1].\n *\n * @param tenantUrl - Absolute URL from the `tenantUrl` search param.\n * @returns Origin string suitable for `postMessage` targetOrigin.\n * @throws {InvalidOriginError} When missing, unparsable, or disallowed scheme/host.\n */\nexport function resolveAllowedOrigin(tenantUrl: string | null): string {\n if (!tenantUrl) {\n throw new InvalidOriginError(\n 'Missing \"tenantUrl\" search parameter required to establish parent origin.',\n );\n }\n\n let url: URL;\n try {\n url = new URL(tenantUrl);\n } catch {\n throw new InvalidOriginError(`Invalid tenantUrl: \"${tenantUrl}\".`);\n }\n\n const isLocalhost = LOCALHOST_HOSTS.has(url.hostname);\n const isHttps = url.protocol === \"https:\";\n const isLocalHttp = url.protocol === \"http:\" && isLocalhost;\n\n if (!isHttps && !isLocalHttp) {\n throw new InvalidOriginError(\n `tenantUrl must use https (or http on localhost). Received: \"${url.protocol}//${url.host}\".`,\n );\n }\n\n return url.origin;\n}\n\n/**\n * Reads the parent-supplied `tenantUrl` from a URL search string.\n *\n * The parent must pass `tenantUrl` on the iframe `src` so\n * {@link resolveAllowedOrigin} can whitelist the parent origin.\n *\n * @param search - Query string (defaults to `window.location.search`).\n */\nexport function readTenantUrlFromLocation(\n search: string = window.location.search,\n): string | null {\n return new URLSearchParams(search).get(\"tenantUrl\");\n}\n","import { callApi } from \"./api\";\nimport { CONNECTION_EVENTS } from \"./events\";\nimport { postToParent, subscribeToParentMessages } from \"./messaging\";\nimport { readTenantUrlFromLocation, resolveAllowedOrigin } from \"./origin\";\nimport type {\n AuthToken,\n AuthTokenRefreshPayload,\n ConnectOptions,\n DesignTokens,\n ExtensionDetails,\n ExtensionMessage,\n HandshakePayload,\n NavigationChangePayload,\n PageSettings,\n PageSettingsUpdatedPayload,\n RequestOptions,\n UpdatePageSettingsPayload,\n} from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_AUTH_TOKEN_BUFFER_MS = 120_000;\nconst AUTO_REFRESH_RETRY_DELAY_MS = 30_000;\n/** Largest delay `setTimeout` can reliably use in browsers. */\nconst MAX_TIMEOUT_MS = 2_147_483_647;\n\n/**\n * Public contract for talking to the Kadanza parent frame over `postMessage`.\n *\n * Requires a `tenantUrl` search param on the extension URL so\n * {@link connect} can validate the parent origin.\n */\nexport interface IExtensionSDK {\n /**\n * Establishes the parent connection and waits for `HANDSHAKE_ACK`.\n *\n * If already connected with cached handshake data, returns that payload\n * without sending another init. Concurrent calls while a handshake is\n * in progress throw.\n *\n * Opt-in proactive refresh can be enabled with\n * `authTokenAutoRefresh: true` (optional `authTokenBufferMs`).\n *\n * @param options - Handshake timeout and optional auth-token auto-refresh.\n * @throws {InvalidOriginError} When `tenantUrl` is missing or invalid.\n * @throws When not embedded in a parent frame, already handshaking,\n * destroyed, or the handshake times out / returns an invalid payload.\n */\n connect(options?: ConnectOptions): Promise<HandshakePayload>;\n\n /**\n * Tears down listeners, proactive refresh timers, and cached state.\n * Rejects any in-flight requests. The instance cannot be reused after destroy.\n */\n destroy(): void;\n\n /** Whether a successful handshake has completed and not been destroyed. */\n readonly isConnected: boolean;\n\n /** Last auth token from handshake or refresh; `null` until connected. */\n getAuthToken(): AuthToken | null;\n\n /** Extension context from handshake; `null` until connected. */\n getExtensionDetails(): ExtensionDetails | null;\n\n /** Design tokens from handshake; `null` until connected. */\n getDesignTokens(): DesignTokens | null;\n\n /**\n * Latest page settings from handshake or `LOAD_PAGE_SETTINGS`;\n * `null` until set.\n */\n getPageSettings(): PageSettings | null;\n\n /**\n * Calls the Kadanza Platform API with the current connection credentials.\n *\n * The API origin is derived from the handshake `baseUrl`. Authorization and\n * tenant headers are managed by the SDK and cannot be overridden.\n *\n * @typeParam T - Expected JSON response body.\n * @param endpoint - Root-relative API path.\n * @param options - Standard fetch options.\n * @throws When not connected, the endpoint is invalid, the request fails,\n * or the response is not successful JSON.\n */\n apiCall<T>(endpoint: string, options?: RequestInit): Promise<T>;\n\n /**\n * Asks the parent for a new auth token and waits for `TOKEN_REFRESH`.\n *\n * @param options - Optional request timeout (default 10s).\n * @throws When not connected, a refresh is already in progress,\n * or the request times out / returns an invalid payload.\n */\n emitRequestAuthTokenRefresh(\n options?: RequestOptions,\n ): Promise<AuthToken>;\n\n /**\n * Pushes page settings to the parent and waits for `PAGE_SETTINGS_UPDATED`.\n *\n * @param payload - Update payload containing the settings object.\n * @param options - Optional request timeout (default 10s).\n * @throws When not connected, an update is already in progress,\n * or the request times out / returns an invalid payload.\n */\n emitUpdatePageSettings(\n payload: UpdatePageSettingsPayload,\n options?: RequestOptions,\n ): Promise<PageSettingsUpdatedPayload>;\n\n /**\n * Registers a handler for parent-initiated `LOAD_PAGE_SETTINGS`.\n *\n * @returns Unsubscribe function.\n */\n onLoadPageSettings(handler: (settings: PageSettings) => void): () => void;\n\n /**\n * Registers a handler for auth-token updates (requested or parent-pushed).\n *\n * @returns Unsubscribe function.\n */\n onAuthTokenRefresh(handler: (authToken: AuthToken) => void): () => void;\n\n /**\n * Notifies the parent that the extension's route changed.\n *\n * Wire: `NAVIGATION_CHANGE` (fire-and-forget).\n *\n * @param payload - Navigation change payload (`path` within the extension).\n * @throws When not connected or destroyed.\n */\n emitNavigationChange(payload: NavigationChangePayload): void;\n}\n\ntype Pending<T> = {\n resolve: (value: T) => void;\n reject: (reason?: unknown) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\n/** Default {@link IExtensionSDK} implementation. Prefer {@link createExtensionSDK}. */\nexport class ExtensionSDK implements IExtensionSDK {\n #allowedOrigin: string | null = null;\n #unsubscribe: (() => void) | null = null;\n #connected = false;\n #destroyed = false;\n\n #authToken: AuthToken | null = null;\n #extensionDetails: ExtensionDetails | null = null;\n #designTokens: DesignTokens | null = null;\n #pageSettings: PageSettings | null = null;\n\n #authTokenAutoRefresh = false;\n #authTokenBufferMs = DEFAULT_AUTH_TOKEN_BUFFER_MS;\n #authTokenRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n #authTokenRefreshRetryUsed = false;\n\n #pendingHandshake: Pending<HandshakePayload> | null = null;\n #pendingAuthTokenRefresh: Pending<AuthToken> | null = null;\n #pendingPageSettingsUpdate: Pending<PageSettingsUpdatedPayload> | null = null;\n\n #loadPageSettingsHandlers = new Set<(settings: PageSettings) => void>();\n #authTokenRefreshHandlers = new Set<(authToken: AuthToken) => void>();\n\n get isConnected(): boolean {\n return this.#connected;\n }\n\n async connect(options: ConnectOptions = {}): Promise<HandshakePayload> {\n this.#assertNotDestroyed();\n\n if (this.#connected && this.#authToken && this.#extensionDetails && this.#designTokens) {\n return {\n authToken: this.#authToken,\n extensionDetails: this.#extensionDetails,\n designTokens: this.#designTokens,\n pageSettings: this.#pageSettings,\n };\n }\n\n if (this.#pendingHandshake) {\n throw new Error(\"Handshake already in progress.\");\n }\n\n this.#configureAuthTokenAutoRefresh(options);\n\n const tenantUrl = readTenantUrlFromLocation();\n this.#allowedOrigin = resolveAllowedOrigin(tenantUrl);\n\n this.#unsubscribe?.();\n this.#unsubscribe = subscribeToParentMessages(\n this.#allowedOrigin,\n (event) => this.#onMessage(event),\n );\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n const handshakePromise = new Promise<HandshakePayload>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingHandshake = null;\n reject(new Error(`Handshake timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingHandshake = { resolve, reject, timer };\n });\n\n try {\n postToParent(CONNECTION_EVENTS.handshakeInit, this.#allowedOrigin);\n } catch (error) {\n this.#clearPending(this.#pendingHandshake);\n this.#pendingHandshake = null;\n this.#unsubscribe?.();\n this.#unsubscribe = null;\n this.#allowedOrigin = null;\n this.#clearProactiveAuthTokenRefreshTimer();\n throw error;\n }\n\n return handshakePromise;\n }\n\n destroy(): void {\n this.#destroyed = true;\n this.#connected = false;\n\n this.#clearProactiveAuthTokenRefreshTimer();\n this.#authTokenAutoRefresh = false;\n this.#authTokenRefreshRetryUsed = false;\n\n this.#unsubscribe?.();\n this.#unsubscribe = null;\n this.#allowedOrigin = null;\n\n this.#rejectPending(this.#pendingHandshake, new Error(\"SDK destroyed.\"));\n this.#rejectPending(this.#pendingAuthTokenRefresh, new Error(\"SDK destroyed.\"));\n this.#rejectPending(this.#pendingPageSettingsUpdate, new Error(\"SDK destroyed.\"));\n this.#pendingHandshake = null;\n this.#pendingAuthTokenRefresh = null;\n this.#pendingPageSettingsUpdate = null;\n\n this.#loadPageSettingsHandlers.clear();\n this.#authTokenRefreshHandlers.clear();\n\n this.#authToken = null;\n this.#extensionDetails = null;\n this.#designTokens = null;\n this.#pageSettings = null;\n }\n\n getAuthToken(): AuthToken | null {\n return this.#authToken;\n }\n\n getExtensionDetails(): ExtensionDetails | null {\n return this.#extensionDetails;\n }\n\n getDesignTokens(): DesignTokens | null {\n return this.#designTokens;\n }\n\n getPageSettings(): PageSettings | null {\n return this.#pageSettings;\n }\n\n async apiCall<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n this.#assertConnected();\n\n return callApi<T>(\n endpoint,\n {\n baseUrl: this.#extensionDetails!.baseUrl,\n tenantDomain: this.#extensionDetails!.tenantDomain,\n authTokenJwt: this.#authToken!.jwt,\n },\n options,\n );\n }\n\n async emitRequestAuthTokenRefresh(\n options: RequestOptions = {},\n ): Promise<AuthToken> {\n this.#assertConnected();\n\n if (this.#pendingAuthTokenRefresh) {\n throw new Error(\"Auth token refresh already in progress.\");\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const allowedOrigin = this.#allowedOrigin!;\n\n const promise = new Promise<AuthToken>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingAuthTokenRefresh = null;\n reject(new Error(`Auth token refresh timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingAuthTokenRefresh = { resolve, reject, timer };\n });\n\n postToParent(CONNECTION_EVENTS.requestAuthTokenRefresh, allowedOrigin);\n return promise;\n }\n\n async emitUpdatePageSettings(\n payload: UpdatePageSettingsPayload,\n options: RequestOptions = {},\n ): Promise<PageSettingsUpdatedPayload> {\n this.#assertConnected();\n\n if (this.#pendingPageSettingsUpdate) {\n throw new Error(\"Page settings update already in progress.\");\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const allowedOrigin = this.#allowedOrigin!;\n\n const promise = new Promise<PageSettingsUpdatedPayload>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingPageSettingsUpdate = null;\n reject(new Error(`Page settings update timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingPageSettingsUpdate = { resolve, reject, timer };\n });\n\n postToParent(CONNECTION_EVENTS.updatePageSettings, allowedOrigin, payload);\n return promise;\n }\n\n onLoadPageSettings(handler: (settings: PageSettings) => void): () => void {\n this.#loadPageSettingsHandlers.add(handler);\n return () => {\n this.#loadPageSettingsHandlers.delete(handler);\n };\n }\n\n onAuthTokenRefresh(handler: (authToken: AuthToken) => void): () => void {\n this.#authTokenRefreshHandlers.add(handler);\n return () => {\n this.#authTokenRefreshHandlers.delete(handler);\n };\n }\n\n emitNavigationChange(payload: NavigationChangePayload): void {\n this.#assertConnected();\n postToParent(\n CONNECTION_EVENTS.navigationChange,\n this.#allowedOrigin!,\n payload,\n );\n }\n\n #onMessage(event: MessageEvent<ExtensionMessage>): void {\n const { type, payload } = event.data;\n\n switch (type) {\n case CONNECTION_EVENTS.handshakeAck:\n this.#handleHandshakeAck(payload as HandshakePayload | undefined);\n break;\n case CONNECTION_EVENTS.authTokenRefresh:\n this.#handleAuthTokenRefresh(payload as AuthTokenRefreshPayload | undefined);\n break;\n case CONNECTION_EVENTS.loadPageSettings:\n this.#handleLoadPageSettings(payload as PageSettings | undefined);\n break;\n case CONNECTION_EVENTS.pageSettingsUpdated:\n this.#handlePageSettingsUpdated(\n payload as PageSettingsUpdatedPayload | undefined,\n );\n break;\n default:\n break;\n }\n }\n\n #handleHandshakeAck(payload: HandshakePayload | undefined): void {\n if (!payload?.authToken || !payload.extensionDetails || !payload.designTokens) {\n this.#rejectPending(\n this.#pendingHandshake,\n new Error(\"Invalid HANDSHAKE_ACK payload.\"),\n );\n this.#pendingHandshake = null;\n return;\n }\n\n this.#authToken = payload.authToken;\n this.#extensionDetails = payload.extensionDetails;\n this.#designTokens = payload.designTokens;\n this.#pageSettings = payload.pageSettings ?? null;\n this.#connected = true;\n\n const pending = this.#pendingHandshake;\n this.#pendingHandshake = null;\n this.#resolvePending(pending, {\n authToken: this.#authToken,\n extensionDetails: this.#extensionDetails,\n designTokens: this.#designTokens,\n pageSettings: this.#pageSettings,\n });\n\n this.#authTokenRefreshRetryUsed = false;\n this.#scheduleProactiveAuthTokenRefresh();\n }\n\n #handleAuthTokenRefresh(payload: AuthTokenRefreshPayload | undefined): void {\n if (!payload?.authToken) {\n this.#rejectPending(\n this.#pendingAuthTokenRefresh,\n new Error(\"Invalid TOKEN_REFRESH payload.\"),\n );\n this.#pendingAuthTokenRefresh = null;\n return;\n }\n\n this.#authToken = payload.authToken;\n\n const pending = this.#pendingAuthTokenRefresh;\n this.#pendingAuthTokenRefresh = null;\n this.#resolvePending(pending, this.#authToken);\n\n for (const handler of this.#authTokenRefreshHandlers) {\n handler(this.#authToken);\n }\n\n this.#authTokenRefreshRetryUsed = false;\n this.#scheduleProactiveAuthTokenRefresh();\n }\n\n #handleLoadPageSettings(payload: PageSettings | undefined): void {\n const settings = payload ?? {};\n this.#pageSettings = settings;\n\n for (const handler of this.#loadPageSettingsHandlers) {\n handler(settings);\n }\n }\n\n #handlePageSettingsUpdated(\n payload: PageSettingsUpdatedPayload | undefined,\n ): void {\n if (!payload || typeof payload.success !== \"boolean\") {\n this.#rejectPending(\n this.#pendingPageSettingsUpdate,\n new Error(\"Invalid PAGE_SETTINGS_UPDATED payload.\"),\n );\n this.#pendingPageSettingsUpdate = null;\n return;\n }\n\n const pending = this.#pendingPageSettingsUpdate;\n this.#pendingPageSettingsUpdate = null;\n this.#resolvePending(pending, payload);\n }\n\n #assertNotDestroyed(): void {\n if (this.#destroyed) {\n throw new Error(\"SDK has been destroyed.\");\n }\n }\n\n #assertConnected(): void {\n this.#assertNotDestroyed();\n if (!this.#connected || !this.#allowedOrigin) {\n throw new Error(\"SDK is not connected. Call connect() first.\");\n }\n }\n\n #configureAuthTokenAutoRefresh(options: ConnectOptions): void {\n if (options.authTokenBufferMs !== undefined) {\n if (\n !Number.isFinite(options.authTokenBufferMs) ||\n options.authTokenBufferMs < 0\n ) {\n throw new Error(\n \"authTokenBufferMs must be a finite non-negative number.\",\n );\n }\n }\n\n this.#authTokenAutoRefresh = options.authTokenAutoRefresh === true;\n this.#authTokenBufferMs =\n options.authTokenBufferMs ?? DEFAULT_AUTH_TOKEN_BUFFER_MS;\n this.#authTokenRefreshRetryUsed = false;\n this.#clearProactiveAuthTokenRefreshTimer();\n }\n\n #parseExpiresAtMs(authToken: AuthToken): number | null {\n const expiresSec = Number(authToken.expires);\n if (!Number.isFinite(expiresSec)) {\n return null;\n }\n return expiresSec * 1000;\n }\n\n #getProactiveRefreshDelayMs(authToken: AuthToken): number | null {\n const expiresAtMs = this.#parseExpiresAtMs(authToken);\n if (expiresAtMs === null) {\n return null;\n }\n return Math.max(0, expiresAtMs - this.#authTokenBufferMs - Date.now());\n }\n\n #clearProactiveAuthTokenRefreshTimer(): void {\n if (this.#authTokenRefreshTimer !== null) {\n clearTimeout(this.#authTokenRefreshTimer);\n this.#authTokenRefreshTimer = null;\n }\n }\n\n #scheduleProactiveAuthTokenRefresh(): void {\n this.#clearProactiveAuthTokenRefreshTimer();\n\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n !this.#authToken\n ) {\n return;\n }\n\n const delayMs = this.#getProactiveRefreshDelayMs(this.#authToken);\n if (delayMs === null) {\n return;\n }\n\n const clampedDelay = Math.min(delayMs, MAX_TIMEOUT_MS);\n this.#authTokenRefreshTimer = setTimeout(() => {\n this.#authTokenRefreshTimer = null;\n void this.#runProactiveAuthTokenRefresh();\n }, clampedDelay);\n }\n\n async #runProactiveAuthTokenRefresh(): Promise<void> {\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n !this.#authToken\n ) {\n return;\n }\n\n const authTokenAtRequest = this.#authToken;\n const delayMs = this.#getProactiveRefreshDelayMs(authTokenAtRequest);\n if (delayMs === null) {\n return;\n }\n\n if (delayMs > 0) {\n this.#scheduleProactiveAuthTokenRefresh();\n return;\n }\n\n if (this.#pendingAuthTokenRefresh) {\n this.#handleProactiveAuthTokenRefreshFailure(authTokenAtRequest);\n return;\n }\n\n try {\n await this.emitRequestAuthTokenRefresh();\n } catch {\n this.#handleProactiveAuthTokenRefreshFailure(authTokenAtRequest);\n }\n }\n\n #handleProactiveAuthTokenRefreshFailure(authTokenAtRequest: AuthToken): void {\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n this.#authToken?.jwt !== authTokenAtRequest.jwt\n ) {\n return;\n }\n\n if (this.#authTokenRefreshRetryUsed) {\n return;\n }\n\n const expiresAtMs = this.#parseExpiresAtMs(authTokenAtRequest);\n if (expiresAtMs === null) {\n return;\n }\n\n const remainingMs = expiresAtMs - Date.now();\n if (remainingMs <= 0) {\n return;\n }\n\n this.#authTokenRefreshRetryUsed = true;\n this.#clearProactiveAuthTokenRefreshTimer();\n\n const retryDelay = Math.min(AUTO_REFRESH_RETRY_DELAY_MS, remainingMs);\n this.#authTokenRefreshTimer = setTimeout(() => {\n this.#authTokenRefreshTimer = null;\n void this.#runProactiveAuthTokenRefresh();\n }, retryDelay);\n }\n\n #clearPending(pending: { timer: ReturnType<typeof setTimeout> } | null): void {\n if (pending) {\n clearTimeout(pending.timer);\n }\n }\n\n #resolvePending<T>(pending: Pending<T> | null, value: T): void {\n if (!pending) {\n return;\n }\n clearTimeout(pending.timer);\n pending.resolve(value);\n }\n\n #rejectPending(\n pending: { timer: ReturnType<typeof setTimeout>; reject: (reason?: unknown) => void } | null,\n reason: unknown,\n ): void {\n if (!pending) {\n return;\n }\n clearTimeout(pending.timer);\n pending.reject(reason);\n }\n}\n","import { ExtensionSDK, type IExtensionSDK } from \"./ExtensionSDK\";\n\nexport { ExtensionSDK, type IExtensionSDK } from \"./ExtensionSDK\";\nexport { CONNECTION_EVENTS, type ConnectionEvent } from \"./events\";\nexport {\n InvalidOriginError,\n readTenantUrlFromLocation,\n resolveAllowedOrigin,\n} from \"./origin\";\nexport type {\n AuthToken,\n AuthTokenRefreshPayload,\n ConnectOptions,\n DesignTokens,\n ExtensionDetails,\n ExtensionMessage,\n HandshakePayload,\n NavigationChangePayload,\n PageSettings,\n PageSettingsUpdatedPayload,\n RequestOptions,\n UpdatePageSettingsPayload,\n} from \"./types\";\n\n/** Creates a new {@link IExtensionSDK} instance for the current extension frame. */\nexport const createExtensionSDK = (): IExtensionSDK => {\n return new ExtensionSDK();\n};\n"],"mappings":";AAMA,SAAS,EAAa,GAAyB;CAC7C,IAAI,EAAQ,WAAW,GAAG,GACxB,OAAO;CAGT,IAAM,IAAM,IAAI,IAAI,CAAO;CAE3B,OADA,EAAI,WAAW,OAAO,EAAI,YACnB,EAAI;AACb;AAEA,SAAS,EAAmB,GAAiB,GAA0B;CACrE,IAAI,CAAC,EAAS,WAAW,GAAG,KAAK,EAAS,WAAW,IAAI,GACvD,MAAU,MACR,yEACF;CAGF,OAAO,GAAG,EAAa,CAAO,CAAC,CAAC,QAAQ,QAAQ,EAAE,IAAI;AACxD;AAEA,eAAsB,EACpB,GACA,GACA,IAAuB,CAAC,GACZ;CACZ,IAAM,IAAU,IAAI,QAAQ,EAAQ,OAAO;CAO3C,AALK,EAAQ,IAAI,cAAc,KAC7B,EAAQ,IAAI,gBAAgB,kBAAkB,GAGhD,EAAQ,IAAI,iBAAiB,UAAU,EAAQ,cAAc,GAC7D,EAAQ,IAAI,YAAY,EAAQ,YAAY;CAE5C,IAAM,IAAW,MAAM,MAAM,EAAmB,EAAQ,SAAS,CAAQ,GAAG;EAC1E,GAAG;EACH;CACF,CAAC;CAED,IAAI,CAAC,EAAS,IAAI;EAChB,IAAM,IAAa,EAAS,aAAa,IAAI,EAAS,eAAe;EACrE,MAAU,MAAM,oBAAoB,EAAS,SAAS,EAAW,EAAE;CACrE;CAEA,OAAQ,MAAM,EAAS,KAAK;AAC9B;;;AC7CA,IAAa,IAAoB;CAE/B,eAAe;CAEf,cAAc;CAEd,yBAAyB;CAEzB,kBAAkB;CAElB,kBAAkB;CAElB,oBAAoB;CAEpB,qBAAqB;CAErB,kBAAkB;AACpB;;;AClBA,SAAgB,EACd,GACA,GACA,GACM;CACN,IAAI,CAAC,OAAO,UAAU,OAAO,WAAW,QACtC,MAAU,MAAM,iDAAiD;CAGnE,IAAM,IAA4B,MAAY,KAAA,IAAY,EAAE,QAAK,IAAI;EAAE;EAAM;CAAQ;CACrF,OAAO,OAAO,YAAY,GAAS,CAAa;AAClD;AAEA,SAAgB,EACd,GACA,GACY;CACZ,IAAM,KAAY,MAAwB;EACpC,EAAM,WAAW,MAIjB,CAAC,EAAM,QAAQ,OAAO,EAAM,QAAS,YAAY,EAAE,UAAU,EAAM,SAIvE,EAAQ,CAAuC;CACjD;CAGA,OADA,OAAO,iBAAiB,WAAW,CAAQ,SAC9B,OAAO,oBAAoB,WAAW,CAAQ;AAC7D;;;ACpCA,IAAM,oBAAkB,IAAI,IAAI;CAAC;CAAa;CAAa;AAAO,CAAC,GAGtD,IAAb,cAAwC,MAAM;CAC5C,YAAY,GAAiB;EAE3B,AADA,MAAM,CAAO,GACb,KAAK,OAAO;CACd;AACF;AAUA,SAAgB,EAAqB,GAAkC;CACrE,IAAI,CAAC,GACH,MAAM,IAAI,EACR,6EACF;CAGF,IAAI;CACJ,IAAI;EACF,IAAM,IAAI,IAAI,CAAS;CACzB,QAAQ;EACN,MAAM,IAAI,EAAmB,uBAAuB,EAAU,GAAG;CACnE;CAEA,IAAM,IAAc,EAAgB,IAAI,EAAI,QAAQ,GAC9C,IAAU,EAAI,aAAa,UAC3B,IAAc,EAAI,aAAa,WAAW;CAEhD,IAAI,CAAC,KAAW,CAAC,GACf,MAAM,IAAI,EACR,+DAA+D,EAAI,SAAS,IAAI,EAAI,KAAK,GAC3F;CAGF,OAAO,EAAI;AACb;AAUA,SAAgB,EACd,IAAiB,OAAO,SAAS,QAClB;CACf,OAAO,IAAI,gBAAgB,CAAM,CAAC,CAAC,IAAI,WAAW;AACpD;;;ACtCA,IAAM,IAAqB,KACrB,IAA+B,MAC/B,IAA8B,KAE9B,IAAiB,YAwHV,IAAb,MAAmD;CACjD,KAAgC;CAChC,KAAoC;CACpC,KAAa;CACb,KAAa;CAEb,KAA+B;CAC/B,KAA6C;CAC7C,KAAqC;CACrC,KAAqC;CAErC,KAAwB;CACxB,KAAqB;CACrB,KAA+D;CAC/D,KAA6B;CAE7B,KAAsD;CACtD,KAAsD;CACtD,KAAyE;CAEzE,qBAA4B,IAAI,IAAsC;CACtE,qBAA4B,IAAI,IAAoC;CAEpE,IAAI,cAAuB;EACzB,OAAO,KAAKA;CACd;CAEA,MAAM,QAAQ,IAA0B,CAAC,GAA8B;EAGrE,IAFA,KAAKC,GAAoB,GAErB,KAAKD,MAAc,KAAKE,MAAc,KAAKC,MAAqB,KAAKC,IACvE,OAAO;GACL,WAAW,KAAKF;GAChB,kBAAkB,KAAKC;GACvB,cAAc,KAAKC;GACnB,cAAc,KAAKC;EACrB;EAGF,IAAI,KAAKC,IACP,MAAU,MAAM,gCAAgC;EAGlD,KAAKC,GAA+B,CAAO;EAE3C,IAAM,IAAY,EAA0B;EAI5C,AAHA,KAAKC,KAAiB,EAAqB,CAAS,GAEpD,KAAKC,KAAe,GACpB,KAAKA,KAAe,EAClB,KAAKD,KACJ,MAAU,KAAKE,GAAW,CAAK,CAClC;EAEA,IAAM,IAAY,EAAQ,aAAa,GAEjC,IAAmB,IAAI,SAA2B,GAAS,MAAW;GAC1E,IAAM,IAAQ,iBAAiB;IAE7B,AADA,KAAKJ,KAAoB,MACzB,EAAO,gBAAI,MAAM,6BAA6B,EAAU,IAAI,CAAC;GAC/D,GAAG,CAAS;GAEZ,KAAKA,KAAoB;IAAE;IAAS;IAAQ;GAAM;EACpD,CAAC;EAED,IAAI;GACF,EAAa,EAAkB,eAAe,KAAKE,EAAc;EACnE,SAAS,GAAO;GAOd,MANA,KAAKG,GAAc,KAAKL,EAAiB,GACzC,KAAKA,KAAoB,MACzB,KAAKG,KAAe,GACpB,KAAKA,KAAe,MACpB,KAAKD,KAAiB,MACtB,KAAKI,GAAqC,GACpC;EACR;EAEA,OAAO;CACT;CAEA,UAAgB;EAyBd,AAxBA,KAAKC,KAAa,IAClB,KAAKb,KAAa,IAElB,KAAKY,GAAqC,GAC1C,KAAKE,KAAwB,IAC7B,KAAKC,KAA6B,IAElC,KAAKN,KAAe,GACpB,KAAKA,KAAe,MACpB,KAAKD,KAAiB,MAEtB,KAAKQ,GAAe,KAAKV,IAAmB,gBAAI,MAAM,gBAAgB,CAAC,GACvE,KAAKU,GAAe,KAAKC,IAA0B,gBAAI,MAAM,gBAAgB,CAAC,GAC9E,KAAKD,GAAe,KAAKE,IAA4B,gBAAI,MAAM,gBAAgB,CAAC,GAChF,KAAKZ,KAAoB,MACzB,KAAKW,KAA2B,MAChC,KAAKC,KAA6B,MAElC,KAAKC,GAA0B,MAAM,GACrC,KAAKC,GAA0B,MAAM,GAErC,KAAKlB,KAAa,MAClB,KAAKC,KAAoB,MACzB,KAAKC,KAAgB,MACrB,KAAKC,KAAgB;CACvB;CAEA,eAAiC;EAC/B,OAAO,KAAKH;CACd;CAEA,sBAA+C;EAC7C,OAAO,KAAKC;CACd;CAEA,kBAAuC;EACrC,OAAO,KAAKC;CACd;CAEA,kBAAuC;EACrC,OAAO,KAAKC;CACd;CAEA,MAAM,QACJ,GACA,IAAuB,CAAC,GACZ;EAGZ,OAFA,KAAKgB,GAAiB,GAEf,EACL,GACA;GACE,SAAS,KAAKlB,GAAmB;GACjC,cAAc,KAAKA,GAAmB;GACtC,cAAc,KAAKD,GAAY;EACjC,GACA,CACF;CACF;CAEA,MAAM,4BACJ,IAA0B,CAAC,GACP;EAGpB,IAFA,KAAKmB,GAAiB,GAElB,KAAKJ,IACP,MAAU,MAAM,yCAAyC;EAG3D,IAAM,IAAY,EAAQ,aAAa,GACjC,IAAgB,KAAKT,IAErB,IAAU,IAAI,SAAoB,GAAS,MAAW;GAC1D,IAAM,IAAQ,iBAAiB;IAE7B,AADA,KAAKS,KAA2B,MAChC,EAAO,gBAAI,MAAM,sCAAsC,EAAU,IAAI,CAAC;GACxE,GAAG,CAAS;GAEZ,KAAKA,KAA2B;IAAE;IAAS;IAAQ;GAAM;EAC3D,CAAC;EAGD,OADA,EAAa,EAAkB,yBAAyB,CAAa,GAC9D;CACT;CAEA,MAAM,uBACJ,GACA,IAA0B,CAAC,GACU;EAGrC,IAFA,KAAKI,GAAiB,GAElB,KAAKH,IACP,MAAU,MAAM,2CAA2C;EAG7D,IAAM,IAAY,EAAQ,aAAa,GACjC,IAAgB,KAAKV,IAErB,IAAU,IAAI,SAAqC,GAAS,MAAW;GAC3E,IAAM,IAAQ,iBAAiB;IAE7B,AADA,KAAKU,KAA6B,MAClC,EAAO,gBAAI,MAAM,wCAAwC,EAAU,IAAI,CAAC;GAC1E,GAAG,CAAS;GAEZ,KAAKA,KAA6B;IAAE;IAAS;IAAQ;GAAM;EAC7D,CAAC;EAGD,OADA,EAAa,EAAkB,oBAAoB,GAAe,CAAO,GAClE;CACT;CAEA,mBAAmB,GAAuD;EAExE,OADA,KAAKC,GAA0B,IAAI,CAAO,SAC7B;GACX,KAAKA,GAA0B,OAAO,CAAO;EAC/C;CACF;CAEA,mBAAmB,GAAqD;EAEtE,OADA,KAAKC,GAA0B,IAAI,CAAO,SAC7B;GACX,KAAKA,GAA0B,OAAO,CAAO;EAC/C;CACF;CAEA,qBAAqB,GAAwC;EAE3D,AADA,KAAKC,GAAiB,GACtB,EACE,EAAkB,kBAClB,KAAKb,IACL,CACF;CACF;CAEA,GAAW,GAA6C;EACtD,IAAM,EAAE,SAAM,eAAY,EAAM;EAEhC,QAAQ,GAAR;GACE,KAAK,EAAkB;IACrB,KAAKc,GAAoB,CAAuC;IAChE;GACF,KAAK,EAAkB;IACrB,KAAKC,GAAwB,CAA8C;IAC3E;GACF,KAAK,EAAkB;IACrB,KAAKC,GAAwB,CAAmC;IAChE;GACF,KAAK,EAAkB;IACrB,KAAKC,GACH,CACF;IACA;GACF,SACE;EACJ;CACF;CAEA,GAAoB,GAA6C;EAC/D,IAAI,CAAC,GAAS,aAAa,CAAC,EAAQ,oBAAoB,CAAC,EAAQ,cAAc;GAK7E,AAJA,KAAKT,GACH,KAAKV,IACL,gBAAI,MAAM,gCAAgC,CAC5C,GACA,KAAKA,KAAoB;GACzB;EACF;EAMA,AAJA,KAAKJ,KAAa,EAAQ,WAC1B,KAAKC,KAAoB,EAAQ,kBACjC,KAAKC,KAAgB,EAAQ,cAC7B,KAAKC,KAAgB,EAAQ,gBAAgB,MAC7C,KAAKL,KAAa;EAElB,IAAM,IAAU,KAAKM;EAUrB,AATA,KAAKA,KAAoB,MACzB,KAAKoB,GAAgB,GAAS;GAC5B,WAAW,KAAKxB;GAChB,kBAAkB,KAAKC;GACvB,cAAc,KAAKC;GACnB,cAAc,KAAKC;EACrB,CAAC,GAED,KAAKU,KAA6B,IAClC,KAAKY,GAAmC;CAC1C;CAEA,GAAwB,GAAoD;EAC1E,IAAI,CAAC,GAAS,WAAW;GAKvB,AAJA,KAAKX,GACH,KAAKC,IACL,gBAAI,MAAM,gCAAgC,CAC5C,GACA,KAAKA,KAA2B;GAChC;EACF;EAEA,KAAKf,KAAa,EAAQ;EAE1B,IAAM,IAAU,KAAKe;EAErB,AADA,KAAKA,KAA2B,MAChC,KAAKS,GAAgB,GAAS,KAAKxB,EAAU;EAE7C,KAAK,IAAM,KAAW,KAAKkB,IACzB,EAAQ,KAAKlB,EAAU;EAIzB,AADA,KAAKa,KAA6B,IAClC,KAAKY,GAAmC;CAC1C;CAEA,GAAwB,GAAyC;EAC/D,IAAM,IAAW,KAAW,CAAC;EAC7B,KAAKtB,KAAgB;EAErB,KAAK,IAAM,KAAW,KAAKc,IACzB,EAAQ,CAAQ;CAEpB;CAEA,GACE,GACM;EACN,IAAI,CAAC,KAAW,OAAO,EAAQ,WAAY,WAAW;GAKpD,AAJA,KAAKH,GACH,KAAKE,IACL,gBAAI,MAAM,wCAAwC,CACpD,GACA,KAAKA,KAA6B;GAClC;EACF;EAEA,IAAM,IAAU,KAAKA;EAErB,AADA,KAAKA,KAA6B,MAClC,KAAKQ,GAAgB,GAAS,CAAO;CACvC;CAEA,KAA4B;EAC1B,IAAI,KAAKb,IACP,MAAU,MAAM,yBAAyB;CAE7C;CAEA,KAAyB;EAEvB,IADA,KAAKZ,GAAoB,GACrB,CAAC,KAAKD,MAAc,CAAC,KAAKQ,IAC5B,MAAU,MAAM,6CAA6C;CAEjE;CAEA,GAA+B,GAA+B;EAC5D,IAAI,EAAQ,sBAAsB,KAAA,MAE9B,CAAC,OAAO,SAAS,EAAQ,iBAAiB,KAC1C,EAAQ,oBAAoB,IAE5B,MAAU,MACR,yDACF;EAQJ,AAJA,KAAKM,KAAwB,EAAQ,yBAAyB,IAC9D,KAAKc,KACH,EAAQ,qBAAqB,GAC/B,KAAKb,KAA6B,IAClC,KAAKH,GAAqC;CAC5C;CAEA,GAAkB,GAAqC;EACrD,IAAM,IAAa,OAAO,EAAU,OAAO;EAI3C,OAHK,OAAO,SAAS,CAAU,IAGxB,IAAa,MAFX;CAGX;CAEA,GAA4B,GAAqC;EAC/D,IAAM,IAAc,KAAKiB,GAAkB,CAAS;EAIpD,OAHI,MAAgB,OACX,OAEF,KAAK,IAAI,GAAG,IAAc,KAAKD,KAAqB,KAAK,IAAI,CAAC;CACvE;CAEA,KAA6C;EAC3C,AAAI,KAAKE,OAA2B,SAClC,aAAa,KAAKA,EAAsB,GACxC,KAAKA,KAAyB;CAElC;CAEA,KAA2C;EAGzC,IAFA,KAAKlB,GAAqC,GAGxC,CAAC,KAAKE,MACN,CAAC,KAAKd,MACN,KAAKa,MACL,CAAC,KAAKX,IAEN;EAGF,IAAM,IAAU,KAAK6B,GAA4B,KAAK7B,EAAU;EAChE,IAAI,MAAY,MACd;EAGF,IAAM,IAAe,KAAK,IAAI,GAAS,CAAc;EACrD,KAAK4B,KAAyB,iBAAiB;GAE7C,AADA,KAAKA,KAAyB,MAC9B,KAAUE,GAA8B;EAC1C,GAAG,CAAY;CACjB;CAEA,MAAMA,KAA+C;EACnD,IACE,CAAC,KAAKlB,MACN,CAAC,KAAKd,MACN,KAAKa,MACL,CAAC,KAAKX,IAEN;EAGF,IAAM,IAAqB,KAAKA,IAC1B,IAAU,KAAK6B,GAA4B,CAAkB;EAC/D,UAAY,MAIhB;OAAI,IAAU,GAAG;IACf,KAAKJ,GAAmC;IACxC;GACF;GAEA,IAAI,KAAKV,IAA0B;IACjC,KAAKgB,GAAwC,CAAkB;IAC/D;GACF;GAEA,IAAI;IACF,MAAM,KAAK,4BAA4B;GACzC,QAAQ;IACN,KAAKA,GAAwC,CAAkB;GACjE;EAXA;CAYF;CAEA,GAAwC,GAAqC;EAU3E,IARE,CAAC,KAAKnB,MACN,CAAC,KAAKd,MACN,KAAKa,MACL,KAAKX,IAAY,QAAQ,EAAmB,OAK1C,KAAKa,IACP;EAGF,IAAM,IAAc,KAAKc,GAAkB,CAAkB;EAC7D,IAAI,MAAgB,MAClB;EAGF,IAAM,IAAc,IAAc,KAAK,IAAI;EAC3C,IAAI,KAAe,GACjB;EAIF,AADA,KAAKd,KAA6B,IAClC,KAAKH,GAAqC;EAE1C,IAAM,IAAa,KAAK,IAAI,GAA6B,CAAW;EACpE,KAAKkB,KAAyB,iBAAiB;GAE7C,AADA,KAAKA,KAAyB,MAC9B,KAAUE,GAA8B;EAC1C,GAAG,CAAU;CACf;CAEA,GAAc,GAAgE;EAC5E,AAAI,KACF,aAAa,EAAQ,KAAK;CAE9B;CAEA,GAAmB,GAA4B,GAAgB;EACxD,MAGL,aAAa,EAAQ,KAAK,GAC1B,EAAQ,QAAQ,CAAK;CACvB;CAEA,GACE,GACA,GACM;EACD,MAGL,aAAa,EAAQ,KAAK,GAC1B,EAAQ,OAAO,CAAM;CACvB;AACF,GC7lBa,UACJ,IAAI,EAAa"}
|
|
1
|
+
{"version":3,"file":"extension-sdk.js","names":["#connected","#assertNotDestroyed","#authToken","#extensionDetails","#designTokens","#pageSettings","#pendingHandshake","#configureAuthTokenAutoRefresh","#allowedOrigin","#tenantUrl","#unsubscribe","#onMessage","#clearPending","#clearProactiveAuthTokenRefreshTimer","#destroyed","#authTokenAutoRefresh","#authTokenRefreshRetryUsed","#rejectPending","#pendingAuthTokenRefresh","#pendingPageSettingsUpdate","#loadPageSettingsHandlers","#authTokenRefreshHandlers","#assertConnected","#handleHandshakeAck","#handleAuthTokenRefresh","#handleLoadPageSettings","#handlePageSettingsUpdated","#resolvePending","#scheduleProactiveAuthTokenRefresh","#authTokenBufferMs","#parseExpiresAtMs","#authTokenRefreshTimer","#getProactiveRefreshDelayMs","#runProactiveAuthTokenRefresh","#handleProactiveAuthTokenRefreshFailure"],"sources":["../src/api.ts","../src/events.ts","../src/messaging.ts","../src/origin.ts","../src/ExtensionSDK.ts","../src/index.ts"],"sourcesContent":["interface ApiRequestContext {\n baseUrl: string;\n tenantDomain: string;\n authTokenJwt: string;\n}\n\n/** Derives the Platform API origin from handshake `baseUrl`. */\nexport function deriveApiUrl(baseUrl: string): string {\n if (baseUrl.startsWith(\"/\")) {\n return baseUrl;\n }\n\n const url = new URL(baseUrl);\n url.hostname = `api.${url.hostname}`;\n return url.origin;\n}\n\nfunction resolveApiEndpoint(baseUrl: string, endpoint: string): string {\n if (!endpoint.startsWith(\"/\") || endpoint.startsWith(\"//\")) {\n throw new Error(\n 'API endpoint must be a root-relative path starting with a single \"/\".',\n );\n }\n\n return `${deriveApiUrl(baseUrl).replace(/\\/+$/, \"\")}${endpoint}`;\n}\n\nexport async function callApi<T>(\n endpoint: string,\n context: ApiRequestContext,\n options: RequestInit = {},\n): Promise<T> {\n const headers = new Headers(options.headers);\n\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n\n headers.set(\"Authorization\", `Bearer ${context.authTokenJwt}`);\n headers.set(\"X-Tenant\", context.tenantDomain);\n\n const response = await fetch(resolveApiEndpoint(context.baseUrl, endpoint), {\n ...options,\n headers,\n });\n\n if (!response.ok) {\n const statusText = response.statusText ? ` ${response.statusText}` : \"\";\n throw new Error(`API call failed: ${response.status}${statusText}.`);\n }\n\n return (await response.json()) as T;\n}\n","/**\n * Wire event type strings for parent/child `postMessage` communication.\n *\n * Keys are SDK-facing names; values are the strings sent on the wire.\n * Comments mark message direction relative to the extension (child).\n */\nexport const CONNECTION_EVENTS = {\n /** Child → parent: start handshake. */\n handshakeInit: \"HANDSHAKE_INIT\",\n /** Parent → child: handshake success with auth and context. */\n handshakeAck: \"HANDSHAKE_ACK\",\n /** Child → parent: request a new auth token. */\n requestAuthTokenRefresh: \"REQUEST_TOKEN_REFRESH\",\n /** Parent → child: new auth token (reply or push). */\n authTokenRefresh: \"TOKEN_REFRESH\",\n /** Parent → child: open/load page settings UI with values. */\n loadPageSettings: \"LOAD_PAGE_SETTINGS\",\n /** Child → parent: persist updated page settings. */\n updatePageSettings: \"UPDATE_PAGE_SETTINGS\",\n /** Parent → child: result of a page settings update. */\n pageSettingsUpdated: \"PAGE_SETTINGS_UPDATED\",\n /** Child → parent: extension route changed. */\n navigationChange: \"NAVIGATION_CHANGE\",\n} as const;\n\n/** Union of all {@link CONNECTION_EVENTS} wire string values. */\nexport type ConnectionEvent =\n (typeof CONNECTION_EVENTS)[keyof typeof CONNECTION_EVENTS];\n","import type { ConnectionEvent } from \"./events\";\nimport type { ExtensionMessage } from \"./types\";\n\nexport type MessageHandler = (event: MessageEvent<ExtensionMessage>) => void;\n\nexport function postToParent(\n type: ConnectionEvent,\n allowedOrigin: string,\n payload?: unknown,\n): void {\n if (!window.parent || window.parent === window) {\n throw new Error(\"Extension is not running inside a parent frame.\");\n }\n\n const message: ExtensionMessage = payload === undefined ? { type } : { type, payload };\n window.parent.postMessage(message, allowedOrigin);\n}\n\nexport function subscribeToParentMessages(\n allowedOrigin: string,\n handler: MessageHandler,\n): () => void {\n const listener = (event: MessageEvent) => {\n if (event.origin !== allowedOrigin) {\n return;\n }\n\n if (!event.data || typeof event.data !== \"object\" || !(\"type\" in event.data)) {\n return;\n }\n\n handler(event as MessageEvent<ExtensionMessage>);\n };\n\n window.addEventListener(\"message\", listener);\n return () => window.removeEventListener(\"message\", listener);\n}\n","const LOCALHOST_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/** Thrown when `tenantUrl` is missing or not a safe postMessage origin. */\nexport class InvalidOriginError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"InvalidOriginError\";\n }\n}\n\n/**\n * Parses and validates a tenant URL into a postMessage-safe origin.\n * Allows https always; http only for localhost / 127.0.0.1 / [::1].\n *\n * @param tenantUrl - Absolute URL from the `tenantUrl` search param.\n * @returns Origin string suitable for `postMessage` targetOrigin.\n * @throws {InvalidOriginError} When missing, unparsable, or disallowed scheme/host.\n */\nexport function resolveAllowedOrigin(tenantUrl: string | null): string {\n if (!tenantUrl) {\n throw new InvalidOriginError(\n 'Missing \"tenantUrl\" search parameter required to establish parent origin.',\n );\n }\n\n let url: URL;\n try {\n url = new URL(tenantUrl);\n } catch {\n throw new InvalidOriginError(`Invalid tenantUrl: \"${tenantUrl}\".`);\n }\n\n const isLocalhost = LOCALHOST_HOSTS.has(url.hostname);\n const isHttps = url.protocol === \"https:\";\n const isLocalHttp = url.protocol === \"http:\" && isLocalhost;\n\n if (!isHttps && !isLocalHttp) {\n throw new InvalidOriginError(\n `tenantUrl must use https (or http on localhost). Received: \"${url.protocol}//${url.host}\".`,\n );\n }\n\n return url.origin;\n}\n\n/**\n * Reads the parent-supplied `tenantUrl` from a URL search string.\n *\n * The parent must pass `tenantUrl` on the iframe `src` so\n * {@link resolveAllowedOrigin} can whitelist the parent origin.\n *\n * @param search - Query string (defaults to `window.location.search`).\n */\nexport function readTenantUrlFromLocation(\n search: string = window.location.search,\n): string | null {\n return new URLSearchParams(search).get(\"tenantUrl\");\n}\n","import { callApi, deriveApiUrl } from \"./api\";\nimport { CONNECTION_EVENTS } from \"./events\";\nimport { postToParent, subscribeToParentMessages } from \"./messaging\";\nimport { readTenantUrlFromLocation, resolveAllowedOrigin } from \"./origin\";\nimport type {\n AuthToken,\n AuthTokenRefreshPayload,\n ConnectOptions,\n DesignTokens,\n ExtensionDetails,\n ExtensionMessage,\n HandshakePayload,\n NavigationChangePayload,\n PageSettings,\n PageSettingsUpdatedPayload,\n RequestOptions,\n UpdatePageSettingsPayload,\n} from \"./types\";\n\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_AUTH_TOKEN_BUFFER_MS = 120_000;\nconst AUTO_REFRESH_RETRY_DELAY_MS = 30_000;\n/** Largest delay `setTimeout` can reliably use in browsers. */\nconst MAX_TIMEOUT_MS = 2_147_483_647;\n\n/**\n * Public contract for talking to the Kadanza parent frame over `postMessage`.\n *\n * Requires a `tenantUrl` search param on the extension URL so\n * {@link connect} can validate the parent origin.\n */\nexport interface IExtensionSDK {\n /**\n * Establishes the parent connection and waits for `HANDSHAKE_ACK`.\n *\n * If already connected with cached handshake data, returns that payload\n * without sending another init. Concurrent calls while a handshake is\n * in progress throw.\n *\n * Opt-in proactive refresh can be enabled with\n * `authTokenAutoRefresh: true` (optional `authTokenBufferMs`).\n *\n * @param options - Handshake timeout and optional auth-token auto-refresh.\n * @throws {InvalidOriginError} When `tenantUrl` is missing or invalid.\n * @throws When not embedded in a parent frame, already handshaking,\n * destroyed, or the handshake times out / returns an invalid payload.\n */\n connect(options?: ConnectOptions): Promise<HandshakePayload>;\n\n /**\n * Tears down listeners, proactive refresh timers, and cached state.\n * Rejects any in-flight requests. The instance cannot be reused after destroy.\n */\n destroy(): void;\n\n /** Whether a successful handshake has completed and not been destroyed. */\n readonly isConnected: boolean;\n\n /** Last auth token from handshake or refresh; `null` until connected. */\n getAuthToken(): AuthToken | null;\n\n /** Extension context from handshake; `null` until connected. */\n getExtensionDetails(): ExtensionDetails | null;\n\n /** Design tokens from handshake; `null` until connected. */\n getDesignTokens(): DesignTokens | null;\n\n /**\n * Latest page settings from handshake or `LOAD_PAGE_SETTINGS`;\n * `null` until set.\n */\n getPageSettings(): PageSettings | null;\n\n /**\n * Validated parent `postMessage` origin from `tenantUrl`;\n * `null` until `connect` resolves it.\n */\n getAllowedOrigin(): string | null;\n\n /**\n * Raw `tenantUrl` search-param value used for the allowed origin;\n * `null` until `connect` reads it.\n */\n getTenantUrl(): string | null;\n\n /**\n * Platform API origin derived from handshake `baseUrl`;\n * `null` until connected.\n */\n getApiUrl(): string | null;\n\n /**\n * Calls the Kadanza Platform API with the current connection credentials.\n *\n * The API origin is derived from the handshake `baseUrl`. Authorization and\n * tenant headers are managed by the SDK and cannot be overridden.\n *\n * @typeParam T - Expected JSON response body.\n * @param endpoint - Root-relative API path.\n * @param options - Standard fetch options.\n * @throws When not connected, the endpoint is invalid, the request fails,\n * or the response is not successful JSON.\n */\n apiCall<T>(endpoint: string, options?: RequestInit): Promise<T>;\n\n /**\n * Asks the parent for a new auth token and waits for `TOKEN_REFRESH`.\n *\n * @param options - Optional request timeout (default 10s).\n * @throws When not connected, a refresh is already in progress,\n * or the request times out / returns an invalid payload.\n */\n emitRequestAuthTokenRefresh(\n options?: RequestOptions,\n ): Promise<AuthToken>;\n\n /**\n * Pushes page settings to the parent and waits for `PAGE_SETTINGS_UPDATED`.\n *\n * @param payload - Update payload containing the settings object.\n * @param options - Optional request timeout (default 10s).\n * @throws When not connected, an update is already in progress,\n * or the request times out / returns an invalid payload.\n */\n emitUpdatePageSettings(\n payload: UpdatePageSettingsPayload,\n options?: RequestOptions,\n ): Promise<PageSettingsUpdatedPayload>;\n\n /**\n * Registers a handler for parent-initiated `LOAD_PAGE_SETTINGS`.\n *\n * @returns Unsubscribe function.\n */\n onLoadPageSettings(handler: (settings: PageSettings) => void): () => void;\n\n /**\n * Registers a handler for auth-token updates (requested or parent-pushed).\n *\n * @returns Unsubscribe function.\n */\n onAuthTokenRefresh(handler: (authToken: AuthToken) => void): () => void;\n\n /**\n * Notifies the parent that the extension's route changed.\n *\n * Wire: `NAVIGATION_CHANGE` (fire-and-forget).\n *\n * @param payload - Navigation change payload (`path` within the extension).\n * @throws When not connected or destroyed.\n */\n emitNavigationChange(payload: NavigationChangePayload): void;\n}\n\ntype Pending<T> = {\n resolve: (value: T) => void;\n reject: (reason?: unknown) => void;\n timer: ReturnType<typeof setTimeout>;\n};\n\n/** Default {@link IExtensionSDK} implementation. Prefer {@link createExtensionSDK}. */\nexport class ExtensionSDK implements IExtensionSDK {\n #allowedOrigin: string | null = null;\n #tenantUrl: string | null = null;\n #unsubscribe: (() => void) | null = null;\n #connected = false;\n #destroyed = false;\n\n #authToken: AuthToken | null = null;\n #extensionDetails: ExtensionDetails | null = null;\n #designTokens: DesignTokens | null = null;\n #pageSettings: PageSettings | null = null;\n\n #authTokenAutoRefresh = false;\n #authTokenBufferMs = DEFAULT_AUTH_TOKEN_BUFFER_MS;\n #authTokenRefreshTimer: ReturnType<typeof setTimeout> | null = null;\n #authTokenRefreshRetryUsed = false;\n\n #pendingHandshake: Pending<HandshakePayload> | null = null;\n #pendingAuthTokenRefresh: Pending<AuthToken> | null = null;\n #pendingPageSettingsUpdate: Pending<PageSettingsUpdatedPayload> | null = null;\n\n #loadPageSettingsHandlers = new Set<(settings: PageSettings) => void>();\n #authTokenRefreshHandlers = new Set<(authToken: AuthToken) => void>();\n\n get isConnected(): boolean {\n return this.#connected;\n }\n\n async connect(options: ConnectOptions = {}): Promise<HandshakePayload> {\n this.#assertNotDestroyed();\n\n if (this.#connected && this.#authToken && this.#extensionDetails && this.#designTokens) {\n return {\n authToken: this.#authToken,\n extensionDetails: this.#extensionDetails,\n designTokens: this.#designTokens,\n pageSettings: this.#pageSettings,\n };\n }\n\n if (this.#pendingHandshake) {\n throw new Error(\"Handshake already in progress.\");\n }\n\n this.#configureAuthTokenAutoRefresh(options);\n\n const tenantUrl = readTenantUrlFromLocation();\n this.#allowedOrigin = resolveAllowedOrigin(tenantUrl);\n this.#tenantUrl = tenantUrl;\n\n this.#unsubscribe?.();\n this.#unsubscribe = subscribeToParentMessages(\n this.#allowedOrigin,\n (event) => this.#onMessage(event),\n );\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n const handshakePromise = new Promise<HandshakePayload>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingHandshake = null;\n reject(new Error(`Handshake timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingHandshake = { resolve, reject, timer };\n });\n\n try {\n postToParent(CONNECTION_EVENTS.handshakeInit, this.#allowedOrigin);\n } catch (error) {\n this.#clearPending(this.#pendingHandshake);\n this.#pendingHandshake = null;\n this.#unsubscribe?.();\n this.#unsubscribe = null;\n this.#allowedOrigin = null;\n this.#tenantUrl = null;\n this.#clearProactiveAuthTokenRefreshTimer();\n throw error;\n }\n\n return handshakePromise;\n }\n\n destroy(): void {\n this.#destroyed = true;\n this.#connected = false;\n\n this.#clearProactiveAuthTokenRefreshTimer();\n this.#authTokenAutoRefresh = false;\n this.#authTokenRefreshRetryUsed = false;\n\n this.#unsubscribe?.();\n this.#unsubscribe = null;\n this.#allowedOrigin = null;\n this.#tenantUrl = null;\n\n this.#rejectPending(this.#pendingHandshake, new Error(\"SDK destroyed.\"));\n this.#rejectPending(this.#pendingAuthTokenRefresh, new Error(\"SDK destroyed.\"));\n this.#rejectPending(this.#pendingPageSettingsUpdate, new Error(\"SDK destroyed.\"));\n this.#pendingHandshake = null;\n this.#pendingAuthTokenRefresh = null;\n this.#pendingPageSettingsUpdate = null;\n\n this.#loadPageSettingsHandlers.clear();\n this.#authTokenRefreshHandlers.clear();\n\n this.#authToken = null;\n this.#extensionDetails = null;\n this.#designTokens = null;\n this.#pageSettings = null;\n }\n\n getAuthToken(): AuthToken | null {\n return this.#authToken;\n }\n\n getExtensionDetails(): ExtensionDetails | null {\n return this.#extensionDetails;\n }\n\n getDesignTokens(): DesignTokens | null {\n return this.#designTokens;\n }\n\n getPageSettings(): PageSettings | null {\n return this.#pageSettings;\n }\n\n getAllowedOrigin(): string | null {\n return this.#allowedOrigin;\n }\n\n getTenantUrl(): string | null {\n return this.#tenantUrl;\n }\n\n getApiUrl(): string | null {\n if (!this.#extensionDetails) {\n return null;\n }\n\n return deriveApiUrl(this.#extensionDetails.baseUrl);\n }\n\n async apiCall<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n this.#assertConnected();\n\n return callApi<T>(\n endpoint,\n {\n baseUrl: this.#extensionDetails!.baseUrl,\n tenantDomain: this.#extensionDetails!.tenantDomain,\n authTokenJwt: this.#authToken!.jwt,\n },\n options,\n );\n }\n\n async emitRequestAuthTokenRefresh(\n options: RequestOptions = {},\n ): Promise<AuthToken> {\n this.#assertConnected();\n\n if (this.#pendingAuthTokenRefresh) {\n throw new Error(\"Auth token refresh already in progress.\");\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const allowedOrigin = this.#allowedOrigin!;\n\n const promise = new Promise<AuthToken>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingAuthTokenRefresh = null;\n reject(new Error(`Auth token refresh timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingAuthTokenRefresh = { resolve, reject, timer };\n });\n\n postToParent(CONNECTION_EVENTS.requestAuthTokenRefresh, allowedOrigin);\n return promise;\n }\n\n async emitUpdatePageSettings(\n payload: UpdatePageSettingsPayload,\n options: RequestOptions = {},\n ): Promise<PageSettingsUpdatedPayload> {\n this.#assertConnected();\n\n if (this.#pendingPageSettingsUpdate) {\n throw new Error(\"Page settings update already in progress.\");\n }\n\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const allowedOrigin = this.#allowedOrigin!;\n\n const promise = new Promise<PageSettingsUpdatedPayload>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.#pendingPageSettingsUpdate = null;\n reject(new Error(`Page settings update timed out after ${timeoutMs}ms.`));\n }, timeoutMs);\n\n this.#pendingPageSettingsUpdate = { resolve, reject, timer };\n });\n\n postToParent(CONNECTION_EVENTS.updatePageSettings, allowedOrigin, payload);\n return promise;\n }\n\n onLoadPageSettings(handler: (settings: PageSettings) => void): () => void {\n this.#loadPageSettingsHandlers.add(handler);\n return () => {\n this.#loadPageSettingsHandlers.delete(handler);\n };\n }\n\n onAuthTokenRefresh(handler: (authToken: AuthToken) => void): () => void {\n this.#authTokenRefreshHandlers.add(handler);\n return () => {\n this.#authTokenRefreshHandlers.delete(handler);\n };\n }\n\n emitNavigationChange(payload: NavigationChangePayload): void {\n this.#assertConnected();\n postToParent(\n CONNECTION_EVENTS.navigationChange,\n this.#allowedOrigin!,\n payload,\n );\n }\n\n #onMessage(event: MessageEvent<ExtensionMessage>): void {\n const { type, payload } = event.data;\n\n switch (type) {\n case CONNECTION_EVENTS.handshakeAck:\n this.#handleHandshakeAck(payload as HandshakePayload | undefined);\n break;\n case CONNECTION_EVENTS.authTokenRefresh:\n this.#handleAuthTokenRefresh(payload as AuthTokenRefreshPayload | undefined);\n break;\n case CONNECTION_EVENTS.loadPageSettings:\n this.#handleLoadPageSettings(payload as PageSettings | undefined);\n break;\n case CONNECTION_EVENTS.pageSettingsUpdated:\n this.#handlePageSettingsUpdated(\n payload as PageSettingsUpdatedPayload | undefined,\n );\n break;\n default:\n break;\n }\n }\n\n #handleHandshakeAck(payload: HandshakePayload | undefined): void {\n if (!payload?.authToken || !payload.extensionDetails || !payload.designTokens) {\n this.#rejectPending(\n this.#pendingHandshake,\n new Error(\"Invalid HANDSHAKE_ACK payload.\"),\n );\n this.#pendingHandshake = null;\n return;\n }\n\n this.#authToken = payload.authToken;\n this.#extensionDetails = payload.extensionDetails;\n this.#designTokens = payload.designTokens;\n this.#pageSettings = payload.pageSettings ?? null;\n this.#connected = true;\n\n const pending = this.#pendingHandshake;\n this.#pendingHandshake = null;\n this.#resolvePending(pending, {\n authToken: this.#authToken,\n extensionDetails: this.#extensionDetails,\n designTokens: this.#designTokens,\n pageSettings: this.#pageSettings,\n });\n\n this.#authTokenRefreshRetryUsed = false;\n this.#scheduleProactiveAuthTokenRefresh();\n }\n\n #handleAuthTokenRefresh(payload: AuthTokenRefreshPayload | undefined): void {\n if (!payload?.authToken) {\n this.#rejectPending(\n this.#pendingAuthTokenRefresh,\n new Error(\"Invalid TOKEN_REFRESH payload.\"),\n );\n this.#pendingAuthTokenRefresh = null;\n return;\n }\n\n this.#authToken = payload.authToken;\n\n const pending = this.#pendingAuthTokenRefresh;\n this.#pendingAuthTokenRefresh = null;\n this.#resolvePending(pending, this.#authToken);\n\n for (const handler of this.#authTokenRefreshHandlers) {\n handler(this.#authToken);\n }\n\n this.#authTokenRefreshRetryUsed = false;\n this.#scheduleProactiveAuthTokenRefresh();\n }\n\n #handleLoadPageSettings(payload: PageSettings | undefined): void {\n const settings = payload ?? {};\n this.#pageSettings = settings;\n\n for (const handler of this.#loadPageSettingsHandlers) {\n handler(settings);\n }\n }\n\n #handlePageSettingsUpdated(\n payload: PageSettingsUpdatedPayload | undefined,\n ): void {\n if (!payload || typeof payload.success !== \"boolean\") {\n this.#rejectPending(\n this.#pendingPageSettingsUpdate,\n new Error(\"Invalid PAGE_SETTINGS_UPDATED payload.\"),\n );\n this.#pendingPageSettingsUpdate = null;\n return;\n }\n\n const pending = this.#pendingPageSettingsUpdate;\n this.#pendingPageSettingsUpdate = null;\n this.#resolvePending(pending, payload);\n }\n\n #assertNotDestroyed(): void {\n if (this.#destroyed) {\n throw new Error(\"SDK has been destroyed.\");\n }\n }\n\n #assertConnected(): void {\n this.#assertNotDestroyed();\n if (!this.#connected || !this.#allowedOrigin) {\n throw new Error(\"SDK is not connected. Call connect() first.\");\n }\n }\n\n #configureAuthTokenAutoRefresh(options: ConnectOptions): void {\n if (options.authTokenBufferMs !== undefined) {\n if (\n !Number.isFinite(options.authTokenBufferMs) ||\n options.authTokenBufferMs < 0\n ) {\n throw new Error(\n \"authTokenBufferMs must be a finite non-negative number.\",\n );\n }\n }\n\n this.#authTokenAutoRefresh = options.authTokenAutoRefresh === true;\n this.#authTokenBufferMs =\n options.authTokenBufferMs ?? DEFAULT_AUTH_TOKEN_BUFFER_MS;\n this.#authTokenRefreshRetryUsed = false;\n this.#clearProactiveAuthTokenRefreshTimer();\n }\n\n #parseExpiresAtMs(authToken: AuthToken): number | null {\n const expiresSec = Number(authToken.expires);\n if (!Number.isFinite(expiresSec)) {\n return null;\n }\n return expiresSec * 1000;\n }\n\n #getProactiveRefreshDelayMs(authToken: AuthToken): number | null {\n const expiresAtMs = this.#parseExpiresAtMs(authToken);\n if (expiresAtMs === null) {\n return null;\n }\n return Math.max(0, expiresAtMs - this.#authTokenBufferMs - Date.now());\n }\n\n #clearProactiveAuthTokenRefreshTimer(): void {\n if (this.#authTokenRefreshTimer !== null) {\n clearTimeout(this.#authTokenRefreshTimer);\n this.#authTokenRefreshTimer = null;\n }\n }\n\n #scheduleProactiveAuthTokenRefresh(): void {\n this.#clearProactiveAuthTokenRefreshTimer();\n\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n !this.#authToken\n ) {\n return;\n }\n\n const delayMs = this.#getProactiveRefreshDelayMs(this.#authToken);\n if (delayMs === null) {\n return;\n }\n\n const clampedDelay = Math.min(delayMs, MAX_TIMEOUT_MS);\n this.#authTokenRefreshTimer = setTimeout(() => {\n this.#authTokenRefreshTimer = null;\n void this.#runProactiveAuthTokenRefresh();\n }, clampedDelay);\n }\n\n async #runProactiveAuthTokenRefresh(): Promise<void> {\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n !this.#authToken\n ) {\n return;\n }\n\n const authTokenAtRequest = this.#authToken;\n const delayMs = this.#getProactiveRefreshDelayMs(authTokenAtRequest);\n if (delayMs === null) {\n return;\n }\n\n if (delayMs > 0) {\n this.#scheduleProactiveAuthTokenRefresh();\n return;\n }\n\n if (this.#pendingAuthTokenRefresh) {\n this.#handleProactiveAuthTokenRefreshFailure(authTokenAtRequest);\n return;\n }\n\n try {\n await this.emitRequestAuthTokenRefresh();\n } catch {\n this.#handleProactiveAuthTokenRefreshFailure(authTokenAtRequest);\n }\n }\n\n #handleProactiveAuthTokenRefreshFailure(authTokenAtRequest: AuthToken): void {\n if (\n !this.#authTokenAutoRefresh ||\n !this.#connected ||\n this.#destroyed ||\n this.#authToken?.jwt !== authTokenAtRequest.jwt\n ) {\n return;\n }\n\n if (this.#authTokenRefreshRetryUsed) {\n return;\n }\n\n const expiresAtMs = this.#parseExpiresAtMs(authTokenAtRequest);\n if (expiresAtMs === null) {\n return;\n }\n\n const remainingMs = expiresAtMs - Date.now();\n if (remainingMs <= 0) {\n return;\n }\n\n this.#authTokenRefreshRetryUsed = true;\n this.#clearProactiveAuthTokenRefreshTimer();\n\n const retryDelay = Math.min(AUTO_REFRESH_RETRY_DELAY_MS, remainingMs);\n this.#authTokenRefreshTimer = setTimeout(() => {\n this.#authTokenRefreshTimer = null;\n void this.#runProactiveAuthTokenRefresh();\n }, retryDelay);\n }\n\n #clearPending(pending: { timer: ReturnType<typeof setTimeout> } | null): void {\n if (pending) {\n clearTimeout(pending.timer);\n }\n }\n\n #resolvePending<T>(pending: Pending<T> | null, value: T): void {\n if (!pending) {\n return;\n }\n clearTimeout(pending.timer);\n pending.resolve(value);\n }\n\n #rejectPending(\n pending: { timer: ReturnType<typeof setTimeout>; reject: (reason?: unknown) => void } | null,\n reason: unknown,\n ): void {\n if (!pending) {\n return;\n }\n clearTimeout(pending.timer);\n pending.reject(reason);\n }\n}\n","import { ExtensionSDK, type IExtensionSDK } from \"./ExtensionSDK\";\n\nexport { ExtensionSDK, type IExtensionSDK } from \"./ExtensionSDK\";\nexport { CONNECTION_EVENTS, type ConnectionEvent } from \"./events\";\nexport {\n InvalidOriginError,\n readTenantUrlFromLocation,\n resolveAllowedOrigin,\n} from \"./origin\";\nexport type {\n AuthToken,\n AuthTokenRefreshPayload,\n ConnectOptions,\n DesignTokens,\n ExtensionDetails,\n ExtensionMessage,\n HandshakePayload,\n NavigationChangePayload,\n PageSettings,\n PageSettingsUpdatedPayload,\n RequestOptions,\n UpdatePageSettingsPayload,\n} from \"./types\";\n\n/** Creates a new {@link IExtensionSDK} instance for the current extension frame. */\nexport const createExtensionSDK = (): IExtensionSDK => {\n return new ExtensionSDK();\n};\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -108,6 +108,9 @@ export declare class ExtensionSDK implements IExtensionSDK {
|
|
|
108
108
|
getExtensionDetails(): ExtensionDetails | null;
|
|
109
109
|
getDesignTokens(): DesignTokens | null;
|
|
110
110
|
getPageSettings(): PageSettings | null;
|
|
111
|
+
getAllowedOrigin(): string | null;
|
|
112
|
+
getTenantUrl(): string | null;
|
|
113
|
+
getApiUrl(): string | null;
|
|
111
114
|
apiCall<T>(endpoint: string, options?: RequestInit): Promise<T>;
|
|
112
115
|
emitRequestAuthTokenRefresh(options?: RequestOptions): Promise<AuthToken>;
|
|
113
116
|
emitUpdatePageSettings(payload: UpdatePageSettingsPayload, options?: RequestOptions): Promise<PageSettingsUpdatedPayload>;
|
|
@@ -165,6 +168,21 @@ export declare interface IExtensionSDK {
|
|
|
165
168
|
* `null` until set.
|
|
166
169
|
*/
|
|
167
170
|
getPageSettings(): PageSettings | null;
|
|
171
|
+
/**
|
|
172
|
+
* Validated parent `postMessage` origin from `tenantUrl`;
|
|
173
|
+
* `null` until `connect` resolves it.
|
|
174
|
+
*/
|
|
175
|
+
getAllowedOrigin(): string | null;
|
|
176
|
+
/**
|
|
177
|
+
* Raw `tenantUrl` search-param value used for the allowed origin;
|
|
178
|
+
* `null` until `connect` reads it.
|
|
179
|
+
*/
|
|
180
|
+
getTenantUrl(): string | null;
|
|
181
|
+
/**
|
|
182
|
+
* Platform API origin derived from handshake `baseUrl`;
|
|
183
|
+
* `null` until connected.
|
|
184
|
+
*/
|
|
185
|
+
getApiUrl(): string | null;
|
|
168
186
|
/**
|
|
169
187
|
* Calls the Kadanza Platform API with the current connection credentials.
|
|
170
188
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -108,6 +108,9 @@ export declare class ExtensionSDK implements IExtensionSDK {
|
|
|
108
108
|
getExtensionDetails(): ExtensionDetails | null;
|
|
109
109
|
getDesignTokens(): DesignTokens | null;
|
|
110
110
|
getPageSettings(): PageSettings | null;
|
|
111
|
+
getAllowedOrigin(): string | null;
|
|
112
|
+
getTenantUrl(): string | null;
|
|
113
|
+
getApiUrl(): string | null;
|
|
111
114
|
apiCall<T>(endpoint: string, options?: RequestInit): Promise<T>;
|
|
112
115
|
emitRequestAuthTokenRefresh(options?: RequestOptions): Promise<AuthToken>;
|
|
113
116
|
emitUpdatePageSettings(payload: UpdatePageSettingsPayload, options?: RequestOptions): Promise<PageSettingsUpdatedPayload>;
|
|
@@ -165,6 +168,21 @@ export declare interface IExtensionSDK {
|
|
|
165
168
|
* `null` until set.
|
|
166
169
|
*/
|
|
167
170
|
getPageSettings(): PageSettings | null;
|
|
171
|
+
/**
|
|
172
|
+
* Validated parent `postMessage` origin from `tenantUrl`;
|
|
173
|
+
* `null` until `connect` resolves it.
|
|
174
|
+
*/
|
|
175
|
+
getAllowedOrigin(): string | null;
|
|
176
|
+
/**
|
|
177
|
+
* Raw `tenantUrl` search-param value used for the allowed origin;
|
|
178
|
+
* `null` until `connect` reads it.
|
|
179
|
+
*/
|
|
180
|
+
getTenantUrl(): string | null;
|
|
181
|
+
/**
|
|
182
|
+
* Platform API origin derived from handshake `baseUrl`;
|
|
183
|
+
* `null` until connected.
|
|
184
|
+
*/
|
|
185
|
+
getApiUrl(): string | null;
|
|
168
186
|
/**
|
|
169
187
|
* Calls the Kadanza Platform API with the current connection credentials.
|
|
170
188
|
*
|