{"version":3,"sources":["../src/openRepository.ts"],"sourcesContent":["// Host-mediated \"open this repository in a new tab\" (R3-476).\n//\n// An app frame cannot open a first-party tab itself. A `window.open` from inside the\n// sandboxed frame inherits the sandbox — the opened tab runs at the same opaque origin and\n// cannot load the host — and `target=\"_top\"` would replace the app's own frame rather than\n// open a tab. So the app asks the host, and the host performs the open from its own context.\n//\n// The app names COORDINATES and nothing else. It cannot pass a URL, a route prefix or a\n// path: the host builds the destination from its own route grammar, so this call can only\n// ever reach one of the platform's own repository routes. That is the point of the shape —\n// an app that could spell the destination could open anything.\n//\n// R3-1033: an optional REVEAL rides the open — a closed chrome enum, never a destination.\n// The app still cannot pass a URL, a route prefix or a path; the host decides what the\n// reveal means (which surface of ITS chrome opens) and builds every URL itself. A future\n// panel joins the `RepositoryReveal` union deliberately, never by a free string.\n//\n// Two more conditions hold on the host side, and neither is something this call can assert\n// for itself: the open needs the HOST document's live transient user activation (a real\n// click, which the host samples rather than believes), and one gesture opens exactly one\n// tab. Both surface here as ordinary coded refusals.\nimport { protocolRequest } from './sandboxUtils';\nimport { throwOnRefusal } from './protocolRefusal';\nimport { PROTOCOL_OPENREPO } from './generated/protocol';\nimport { SCHEMES } from './protocolSchemes';\n\n/** Where a repository lives. The same three fields a `RecentProject` carries — this is a\n *  location the user may already have navigated to under their own authority. */\nexport interface RepositoryCoordinates {\n  provider: string;\n  namespace: string;\n  repository: string;\n}\n\n/** A chrome reveal that may ride an open (R3-1033) — the host's own surface to open at the\n *  destination, never a destination the app names. `'agent'` is the conversations panel;\n *  the value set is closed on purpose (see the header). */\nexport interface RepositoryReveal {\n  panel: 'agent';\n}\n\n/** The `open` wire params — the coordinates plus the optional reveal. Typed as a named\n *  interface (not an inline literal) so the protocol-snapshot extractor resolves the wire\n *  shape from the type; see `openRepository` below. */\ninterface OpenRepositoryOpenParams extends RepositoryCoordinates {\n  reveal?: RepositoryReveal;\n}\n\n/** Why the host refused to open a tab.\n *\n *  - `invalid` — the coordinates are not three clean path segments.\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. A SECOND call inside one gesture\n *    also lands here: `window.open` consumes the host's transient activation, so one click\n *    buys exactly one tab and the next needs a real second click.\n *  - `forbidden` — the app does not hold the baseline `route:read` capability.\n *  - `unsupported` — this host has no repository-open surface wired.\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 OpenRepositoryErrorCode = 'invalid' | 'no-activation' | 'forbidden' | 'unsupported' | 'unknown';\n\nexport interface OpenRepositoryError extends Error {\n  code: OpenRepositoryErrorCode;\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 OpenRepositoryReply = { ok: true; url?: string } | { ok: false; code?: string; message?: string };\n\n/**\n * Ask the host to open a repository in a new browser tab.\n *\n * `reveal` (R3-1033) optionally asks the host to open one of its own chrome surfaces at\n * the destination — a closed enum (`RepositoryReveal`), never a destination. Omitted,\n * the open lands exactly as before.\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 OpenRepositoryError} carrying `code`\n * when 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 openRepository(coordinates: RepositoryCoordinates, reveal?: RepositoryReveal): Promise<void> {\n  const { provider, namespace, repository } = coordinates;\n  // The reveal rides the one wire arg when the caller asked for it; a caller omitting it\n  // sends no field at all (never `undefined` on the wire — the host validates what arrives).\n  // Typed as OpenRepositoryOpenParams (the named interface) so the protocol-snapshot\n  // extractor resolves the wire shape from the type — an intersection or a bare Record\n  // would read shapeless and the check would flag a reshape that is not one.\n  const params: OpenRepositoryOpenParams = { provider, namespace, repository };\n  if (reveal !== undefined) params.reveal = reveal;\n  const res = (await protocolRequest(SCHEMES[PROTOCOL_OPENREPO], 'open', [params])) as OpenRepositoryReply;\n  throwOnRefusal(res, 'repository open refused');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA,0BAAgC;AAChC,6BAA+B;AAC/B,sBAAkC;AAClC,6BAAwB;AAwExB,eAAsB,eAAe,aAAoC,QAA0C;AACjH,QAAM,EAAE,UAAU,WAAW,WAAW,IAAI;AAM5C,QAAM,SAAmC,EAAE,UAAU,WAAW,WAAW;AAC3E,MAAI,WAAW,OAAW,QAAO,SAAS;AAC1C,QAAM,MAAO,UAAM,qCAAgB,+BAAQ,iCAAiB,GAAG,QAAQ,CAAC,MAAM,CAAC;AAC/E,6CAAe,KAAK,yBAAyB;AAC/C;","names":[]}