{"version":3,"sources":["../src/openExternal.ts"],"sourcesContent":["// Host-mediated \"open this external link in a new tab\" (R3-619).\n//\n// An app frame cannot open an ordinary top-level tab itself for a destination that has to\n// act as itself: a `window.open` or `<a target=\"_blank\">` from inside the sandboxed frame\n// inherits the sandbox (`allow-popups` without `allow-popups-to-escape-sandbox`), so the\n// opened tab runs at the same opaque origin and anything that signs in or posts fails.\n//\n// Unlike `openRepository`, the app here names a URL, not coordinates — the destination is\n// arbitrary, not a platform route. So the host validates the URL and confirms every call\n// (the full destination in its own chrome, opened only on the user's click). The app never\n// receives a `Window` handle; it asks, and the host decides whether and how to open.\n//\n// The same two host-side conditions as `openRepository` hold, and neither is something this\n// call can assert for itself: the confirmation needs the HOST document's live transient\n// user activation (a real click, which the host samples rather than believes), and the\n// confirmation must not consume that activation before the open. Both surface here as\n// ordinary coded refusals.\nimport { protocolRequest } from './sandboxUtils';\nimport { throwOnRefusal } from './protocolRefusal';\nimport { PROTOCOL_OPENLINK } from './generated/protocol';\nimport { SCHEMES } from './protocolSchemes';\n\n/** Why the host refused to open the link.\n *\n *  - `invalid` — the URL is not a clean `https:` external destination (scheme, credentials,\n *    length, or the host's own origin).\n *  - `no-activation` — no live user gesture on the host document. Call this from a click\n *    handler; a timer or a boot path will always get this.\n *  - `declined` — the host showed the confirmation and the user did not confirm.\n *  - `forbidden` — the app does not hold the baseline `link:open` capability.\n *  - `unsupported` — this host has no outward-link surface wired (an older host).\n *  - `unknown` — the host refused without naming a code.\n *\n *  **What you actually catch.** The SDK throws a plain `Error` with `.code` assigned — a\n *  `CodedRefusalError` from `protocolRefusal.ts` — never a distinct class. These are the\n *  `.code` VALUES the host sends. Nothing enforces the union at runtime — `.code` is\n *  whatever string arrived — so treat an unlisted code as possible and `instanceof Error`\n *  as the only reliable test.\n *\n *  (This note is on the code alias rather than on the interface because the alias is where\n *  the codes are documented. Every doclink in this file names the INTERFACE, so a reader\n *  following one lands a hop away from this — a wart, not a plan. Stated without a\n *  direction on purpose: two earlier revisions of this sentence asserted a positional\n *  claim, and both were wrong.) */\nexport type OpenExternalErrorCode = 'invalid' | 'no-activation' | 'declined' | 'forbidden' | 'unsupported' | 'unknown';\n\nexport interface OpenExternalError extends Error {\n  code: OpenExternalErrorCode;\n}\n\n/** The host's reply: the envelope resolves inside the promise, so a refusal is a resolved\n *  `{ ok: false }` rather than a rejection at the transport layer. */\ntype OpenExternalReply = { ok: true; url?: string } | { ok: false; code?: string; message?: string };\n\n/**\n * Ask the host to open an external link in a new browser tab.\n *\n * Resolves once the host has performed the open; it does not wait for — and cannot observe —\n * the opened tab loading. Rejects with a typed {@link OpenExternalError} carrying `code` when\n * the host refuses.\n *\n * Call it directly from a user gesture. The host samples its own transient activation when\n * the request arrives, so anything that defers the call past the gesture (an `await` before\n * it, a `setTimeout`, a retry) will be refused `no-activation`. None of the refusals are\n * worth retrying: each names a condition a retry cannot change.\n */\nexport async function openExternal(url: string): Promise<void> {\n  const res = (await protocolRequest(SCHEMES[PROTOCOL_OPENLINK], 'open', [{ url }])) as OpenExternalReply;\n  throwOnRefusal(res, 'external link open refused');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,0BAAgC;AAChC,6BAA+B;AAC/B,sBAAkC;AAClC,6BAAwB;AA8CxB,eAAsB,aAAa,KAA4B;AAC7D,QAAM,MAAO,UAAM,qCAAgB,+BAAQ,iCAAiB,GAAG,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;AAChF,6CAAe,KAAK,4BAA4B;AAClD;","names":[]}