/** * Connection-param handshake between the embedding host and the app frame. * * An embedded app needs three things to open its back-connection: the gateway * URL, its own `appId`, and a session identity token. The token is a **secret**, * so it must not ride in the iframe `src` — the preview surface that serves the * app is unauthenticated, and a URL lands in access logs, `Referer` headers, and * browser history. Instead the host posts it over `postMessage`, and the app * asks for it with a ready ping once its script is running. * * The host cannot simply post on iframe `load`: it has no way to know when the * app's script is listening. So the app speaks first. * * ```text * app → host { type: 'skaile_app_ready', appId } targetOrigin = parentOrigin * host → app { type: 'skaile_app_params', appId, url, token } targetOrigin = appOrigin * ``` * * Both sides pin the peer: the app checks `event.origin === parentOrigin` and * that the message came from its own parent; the host checks the origin and that * `event.source` is the very iframe it rendered. The app learns the expected * parent origin from a **non-secret** query param on its `src` * ({@link PARENT_ORIGIN_QUERY_PARAM}), which is safe to leak precisely because it * is not a credential. * * @category App SDK * @since 3.5.0 */ /** * Query param on the app's iframe `src` carrying the embedder's origin. Not a * secret — it is the value the app pins its `postMessage` peer to. */ export declare const PARENT_ORIGIN_QUERY_PARAM = "skaileParentOrigin"; /** Default timeout waiting for the host's params reply. */ export declare const DEFAULT_PARAMS_TIMEOUT_MS = 10000; /** First gap between ready pings. Grows by {@link PING_BACKOFF_FACTOR} up to {@link MAX_PING_INTERVAL_MS}. */ export declare const INITIAL_PING_INTERVAL_MS = 100; /** * Ceiling for the ready-ping gap. The host mints a fresh single-use ticket for * *every* ping it answers, so pinging is not free — back off rather than hammer. */ export declare const MAX_PING_INTERVAL_MS = 1000; /** App → host. Announces the app frame is listening and wants its params. */ export type SkaileAppReadyMessage = { type: "skaile_app_ready"; /** The app asking. The host answers only for an app it actually embedded. */ appId: string; }; /** Host → app. Carries the gateway URL and the single-use session identity token. */ export type SkaileAppParamsMessage = { type: "skaile_app_params"; /** Echoed back so a frame embedding several apps can disambiguate. */ appId: string; /** The gateway app-channel URL, e.g. `wss://platform/app-connect`. */ url: string; /** Single-use session identity token. Consumed by the gateway at `app_hello`. */ token: string; }; /** Resolved params, ready to hand to `createWebSocketAppTransport` + `createSkaileApp`. */ export type AppConnectionParams = { url: string; appId: string; token: string; }; /** The subset of `postMessage` targets this module needs. */ export type PostMessageTarget = { postMessage(message: unknown, targetOrigin: string): void; }; /** Structural view of a `MessageEvent`, so tests need no DOM. */ export type MessageEventLike = { readonly origin: string; readonly source: unknown; readonly data: unknown; }; /** Structural view of the `window` bits this module needs. Injectable for tests. */ export type AppWindowLike = { readonly parent: PostMessageTarget | null; readonly location: { readonly search: string; }; addEventListener(type: "message", handler: (event: MessageEventLike) => void): void; removeEventListener(type: "message", handler: (event: MessageEventLike) => void): void; }; /** * Options for {@link resolveAppConnectionParams}. * * @category App SDK * @since 3.5.0 */ export interface ResolveAppConnectionParamsOptions { /** The embedded app's stable id. Must match the params the host replies with. */ appId: string; /** * Expected origin of the embedding host. Defaults to the * {@link PARENT_ORIGIN_QUERY_PARAM} query param on the current URL. Never `"*"` * or `"null"` — an unpinned peer defeats the point of not putting the token in * the URL. */ parentOrigin?: string; /** How long to wait for the host's reply. Defaults to {@link DEFAULT_PARAMS_TIMEOUT_MS}. */ timeoutMs?: number; /** Window to listen and post on. Defaults to the global. Injectable for tests. */ windowRef?: AppWindowLike; } /** * Ask the embedding host for this app's connection params. * * Posts a {@link SkaileAppReadyMessage} to the parent and resolves with the * matching {@link SkaileAppParamsMessage}. Messages from any other origin, from * any window other than the parent, or for another `appId` are ignored — not * rejected — because a page may legitimately receive unrelated `postMessage` * traffic. * * Call it again to re-request a fresh token: the token is single-use, so a * reconnecting transport needs a new one (see `createSkaileApp`'s `reconnect`). * * @throws when not embedded, when the parent origin cannot be determined or is * unpinnable, or when the host does not reply within `timeoutMs`. * * @category App SDK * @since 3.5.0 */ export declare function resolveAppConnectionParams(options: ResolveAppConnectionParamsOptions): Promise; //# sourceMappingURL=connection-params.d.ts.map