{"version":3,"sources":["../src/openBundle.ts"],"sourcesContent":["// Host-mediated \"open this bundle in its own tab\" (BUNDLE_EMBEDDING_SPEC §4b.9).\n//\n// Opening a bundle is not a for-result task: the reader stays, the view wants the whole\n// screen, and the bundle's files are what they work on next. So a file manager's\n// \"Open as …\" asks the host for a new tab — an ordinary session of the opener over the\n// bundle — instead of the task overlay. The tab starts in present mode, except for a local\n// dev-server source, whose tab is its editing session.\n//\n// The app names the DIRECTORY it already holds, as the same capability it would hand a\n// task, and optionally a declared view by NAME. It cannot pass a URL, a route or an app:\n// the host maps the capability to a location it can address, builds the destination from\n// its own route grammar, and the opened tab re-reads the bundle's marker and resolves the\n// opener itself. The link grants nothing.\n//\n// Not every directory has an address. A folder in a space, or on a session mount, cannot\n// be named by a URL today; the host refuses those with `unaddressable`, and the caller\n// keeps its overlay open (`invokeTask`) as the fallback.\n//\n// A host that predates this call does not refuse it — it does not answer at all, because\n// it has never heard of the request. A host that knows the request answers on the turn it\n// arrives, so the wait is bounded tightly here and its expiry (`timeout`) is the third\n// reason to fall back.\n//\n// As with `openRepository`, the open needs the HOST document's live transient user\n// activation, which the host samples rather than believes.\nimport { protocolRequest } from './sandboxUtils';\nimport { throwOnRefusal } from './protocolRefusal';\nimport { PROTOCOL_OPENBUNDLE } from './generated/protocol';\nimport { SCHEMES } from './protocolSchemes';\nimport type { DirCap } from './tasks';\n\n/** What to open: a bundle directory the app holds, and optionally one of its declared views. */\nexport interface OpenBundleTarget {\n  /** The bundle's directory, as the capability the app holds on it (`capDir(...)`). */\n  dir: DirCap;\n  /** A view the bundle's marker declares, by name. The host resolves which app shows it. */\n  view?: string;\n}\n\n/** Why a bundle did not open in a tab.\n *\n *  - `invalid-params` — `dir` is not a directory capability, or `view` is not a string.\n *  - `invalid` — `view` is not a view name.\n *  - `unaddressable` — the directory is real and the app holds it, but the host has no URL\n *    for it (a space folder, a session mount). Fall back to the overlay open.\n *  - `no-activation` — no live user gesture on the host document. Call this from a click\n *    handler, with no `await` before it.\n *  - `forbidden` — the app may not open tabs, or does not hold the directory it named.\n *  - `unsupported` — this host knows the request but has no bundle-open surface wired.\n *    Fall back to the overlay open.\n *  - `timeout` — the host did not answer within {@link OPEN_BUNDLE_REPLY_TIMEOUT_MS}. That\n *    is what a host that predates this call does. Fall back to the overlay open.\n *  - `unknown` — the host refused without naming a code.\n *\n *  The SDK throws a plain `Error` with `.code` assigned; `.code` is whatever string the\n *  host sent, so treat an unlisted code as possible. */\nexport type OpenBundleErrorCode =\n  | 'invalid-params'\n  | 'invalid'\n  | 'unaddressable'\n  | 'no-activation'\n  | 'forbidden'\n  | 'unsupported'\n  | 'timeout'\n  | 'unknown';\n\n/**\n * How long `openBundle` waits for the host's answer, in ms. A host that knows the request\n * decides it synchronously — nothing is fetched and nobody is asked — so the answer is one\n * message round trip away. A host that does not know it never answers, and a click that\n * does nothing for the default thirty seconds before falling back would read as broken.\n */\nexport const OPEN_BUNDLE_REPLY_TIMEOUT_MS = 2000;\n\nexport interface OpenBundleError extends Error {\n  code: OpenBundleErrorCode;\n}\n\n/** The wire params: the capability and the view name, and nothing else. */\ninterface OpenBundleParams {\n  dir: DirCap;\n  view?: string;\n}\n\n/** The host's reply: a refusal is a resolved `{ ok: false }`, not a transport rejection. */\ntype OpenBundleReply = { ok: true } | { ok: false; code?: string; message?: string };\n\n/**\n * Ask the host to open a bundle 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 an {@link OpenBundleError} carrying `code` otherwise.\n * On `unaddressable`, `unsupported` or `timeout`, open the bundle the way you did before\n * this call existed: the `invokeTask` you used (`open-declared` for an app-form marker or a\n * declared view, the marker's own contract for a task-form one).\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 is refused\n * `no-activation`.\n */\nexport async function openBundle(target: OpenBundleTarget): Promise<void> {\n  // Whatever was passed as `dir` is narrowed to the capability's four fields and sent: a\n  // value that is not a capability is the host's to refuse (`invalid-params`), with a code.\n  const { $cap, mountId, relPath, mode } = (target?.dir ?? {}) as DirCap;\n  const params: OpenBundleParams = { dir: { $cap, mountId, relPath, mode } };\n  if (target?.view !== undefined) params.view = target.view;\n  const res = (await protocolRequest(SCHEMES[PROTOCOL_OPENBUNDLE], 'open', [params], {\n    timeoutMs: OPEN_BUNDLE_REPLY_TIMEOUT_MS,\n  })) as OpenBundleReply;\n  throwOnRefusal(res, 'bundle open refused');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBA,0BAAgC;AAChC,6BAA+B;AAC/B,sBAAoC;AACpC,6BAAwB;AA4CjB,MAAM,+BAA+B;AA4B5C,eAAsB,WAAW,QAAyC;AAGxE,QAAM,EAAE,MAAM,SAAS,SAAS,KAAK,IAAK,QAAQ,OAAO,CAAC;AAC1D,QAAM,SAA2B,EAAE,KAAK,EAAE,MAAM,SAAS,SAAS,KAAK,EAAE;AACzE,MAAI,QAAQ,SAAS,OAAW,QAAO,OAAO,OAAO;AACrD,QAAM,MAAO,UAAM,qCAAgB,+BAAQ,mCAAmB,GAAG,QAAQ,CAAC,MAAM,GAAG;AAAA,IACjF,WAAW;AAAA,EACb,CAAC;AACD,6CAAe,KAAK,qBAAqB;AAC3C;","names":[]}