/** * pairing/pairing-handoff.ts * * One pairing exchange, carrying an OFFER SET so a freshly-paired surface can * complete several set-up steps in a single pass, each independently declinable: * - notifications, register this device for browser push (VAPID + subscribe). * - relay , connect through the rendezvous relay for off-LAN reach. * - passkey , register a WebAuthn credential for step-up. * * The QR / deep-link content is EXACTLY the `#pair=` fragment shape the * web app already consumes (goodvibes-webui `src/lib/pairing.ts` reads the * `pair` key out of the URL fragment via URLSearchParams and ignores any other * fragment keys). So the token rides in `pair=` and the offer set rides * alongside in an `offers=` key the web app harmlessly ignores today; a * bundle-aware surface reads it to know which offers to present. The fragment is * deliberate: a `#`-fragment is never sent to a server, so the one-time token * never lands in an access log or Referer header. * * This module is pure over strings, QR *rendering* and the daemon verbs live * elsewhere; it only builds and parses the link content. */ /** The set-up steps a pairing hand-off can offer. Each is independently declinable. */ export type PairingHandoffOfferKind = 'notifications' | 'relay' | 'passkey'; export declare const PAIRING_HANDOFF_OFFER_KINDS: readonly PairingHandoffOfferKind[]; /** The fragment keys the pairing deep-link uses. `pair` is the one the web app reads. */ export declare const PAIRING_FRAGMENT_KEY = "pair"; export declare const PAIRING_OFFERS_FRAGMENT_KEY = "offers"; /** Normalize/dedupe an offer list into canonical order. */ export declare function normalizeOffers(offers: readonly string[]): PairingHandoffOfferKind[]; export interface BuildPairingHandoffLinkInput { /** The web app origin the QR points at, e.g. `https://app.example` (no trailing slash needed). */ readonly webOrigin: string; /** The per-device pairing token (the one-time secret). */ readonly token: string; /** The offers this hand-off carries; empty ⇒ a plain pairing link with no offer set. */ readonly offers?: readonly PairingHandoffOfferKind[] | undefined; } /** * Build the `#pair=` deep link (optionally carrying the offer set). The * token lands in the URL fragment, never the query, so it is not sent to a * server. Extra `offers=` key is ignored by the current web app. */ export declare function buildPairingHandoffLink(input: BuildPairingHandoffLinkInput): string; /** * Build just the `#pair=` fragment (no origin), for a producer (e.g. the * TUI QR renderer) that prepends its own known web origin. */ export declare function buildPairingHandoffFragment(input: { readonly token: string; readonly offers?: readonly PairingHandoffOfferKind[] | undefined; }): string; export interface ParsedPairingHandoff { readonly token: string; readonly offers: PairingHandoffOfferKind[]; } /** * Parse a pairing deep-link's fragment back into its token + offer set. Accepts * a full URL, a bare `#pair=…` fragment, or the fragment body, the same * tolerance the web app applies. Returns null when no `pair` token is present. */ export declare function parsePairingHandoffLink(input: string): ParsedPairingHandoff | null; //# sourceMappingURL=pairing-handoff.d.ts.map