@nominalso/vibe-bridge 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-QAMP6I2C.js → chunk-5P74A5S7.js} +18 -2
- package/dist/chunk-5P74A5S7.js.map +1 -0
- package/dist/index.browser.cjs +17 -1
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.js +17 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +17 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.server.cjs +17 -1
- package/dist/index.server.cjs.map +1 -1
- package/dist/index.server.d.cts +2 -2
- package/dist/index.server.d.ts +2 -2
- package/dist/index.server.js +1 -1
- package/dist/{version-Cufn3-b0.d.cts → version-yG6_fNT5.d.cts} +150 -0
- package/dist/{version-Cufn3-b0.d.ts → version-yG6_fNT5.d.ts} +150 -0
- package/package.json +1 -1
- package/dist/chunk-QAMP6I2C.js.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../../protocol-types/dist/index.js","../package.json","../src/version.ts","../src/data-methods.ts","../src/timeouts.ts","../src/VibeAppBridge.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * Iframe-side SDK for **Nominal Vibe Apps** — standalone web apps (typically\n * built with Lovable) embedded in the Nominal platform via a cross-origin\n * `<iframe>`. {@link VibeAppBridge} connects your app to its Nominal host over a\n * typed `postMessage` protocol: read Nominal data, submit Close-Management task\n * outputs, upload files, and keep deep-link routing in sync.\n *\n * ## Safe to import from anywhere\n *\n * This package has a clean server/client boundary, so `import { VibeAppBridge }`\n * (and the error classes and types) is safe from **any** file — an SSR entry, a\n * React Server Component, a Cloudflare Worker, a shared util, or a client\n * component:\n *\n * - **Importing has zero side effects** and **constructing is pure** — the\n * constructor stores options and touches no browser API.\n * - The browser is only required when a **method actually runs**. Calling one\n * outside a browser throws a `BridgeError` with code `'SERVER_ENVIRONMENT'`.\n * - RSC / Worker / edge runtimes resolve (via the `react-server` / `worker` /\n * `workerd` / `edge-light` / `deno` export conditions) to a server-safe stub,\n * so a Server Component can reference the bridge without executing anything.\n * Plain Node (and jsdom/happy-dom test runners) get the real, self-guarding\n * build, so component tests run against a real `window`.\n * - `posthog-js` is an **optional dependency**, loaded lazily only when the host\n * enables session recording — never in a server bundle.\n *\n * You therefore do **not** need `createClientOnlyFn`, dynamic `import()`\n * wrappers, or `typeof window` guards around construction. Construct at the top\n * of a client component and `connect()` in an effect. See the SSR guide in the\n * README and `docs/getting-started.md`.\n *\n * Quickstart — call {@link VibeAppBridge.connect | connect()} once on init,\n * then call any data method. `connect()` must resolve before any other call.\n *\n * @example\n * ```ts\n * import { VibeAppBridge } from '@nominalso/vibe-bridge'\n *\n * const bridge = new VibeAppBridge({\n * // Optional — omit to auto-detect the embedding Nominal origin.\n * parentOrigin: import.meta.env.VITE_PARENT_ORIGIN,\n * })\n *\n * // 1. Connect — resolves with the tenant/user context. Call this first.\n * const ctx = await bridge.connect()\n * console.log(ctx.tenant, ctx.subsidiaryId, ctx.user.displayName)\n *\n * // 2. Read Nominal data (any of the ~46 named operations).\n * const accounts = await bridge.getChartOfAccounts({ path: { subsidiary_id: ctx.subsidiaryId } })\n *\n * // 3. Upload a file through the host (returns once Nominal has stored it).\n * const uploaded = await bridge.upload(file, { entityType: 'JOURNAL_ENTRY', entityId: '123' })\n *\n * // 4. Submit a Close-Management task output (the only write path into Nominal).\n * await bridge.postTaskOutput({ path: { task_instance_id: 'task-1' }, body: {} })\n *\n * // 5. Tear down on unmount.\n * bridge.destroy()\n * ```\n */\n\n// This module exists to emit the canonical type surface (`dist/index.d.ts`) that\n// both the browser and server builds share. At runtime the package resolves to\n// `index.browser.js` (browser) or `index.server.js` (server) via export\n// conditions — never to this file — so the two builds present one identical API.\nexport * from './index.browser'\n","// src/subroute.ts\nfunction normalizeSubroute(subroute) {\n const normalized = subroute.startsWith(\"/\") ? subroute : `/${subroute}`;\n const path = normalized.split(/[?#]/)[0];\n let decoded = path;\n let prev;\n do {\n prev = decoded;\n decoded = decoded.replace(/%25/gi, \"%\").replace(/%2e/gi, \".\").replace(/%2f/gi, \"/\");\n } while (decoded !== prev);\n if (decoded.split(\"/\").some((segment) => segment === \"..\")) return null;\n return normalized;\n}\n\n// src/protocol.ts\nvar PROTOCOL_ID = \"nominal-vibe-bridge\";\nvar PROTOCOL_VERSION = 2;\nvar BRIDGE_KINDS = [\"request\", \"response\", \"push\", \"command\", \"progress\"];\nvar CORRELATED_KINDS = [\"request\", \"response\", \"progress\"];\nvar BRIDGE_KINDS_SET = new Set(BRIDGE_KINDS);\nvar CORRELATED_KINDS_SET = new Set(CORRELATED_KINDS);\nfunction isBridgeMessage(data) {\n if (typeof data !== \"object\" || data === null) return false;\n const d = data;\n if (d.__protocol !== PROTOCOL_ID) return false;\n if (d.__version !== PROTOCOL_VERSION) return false;\n if (typeof d.kind !== \"string\" || !BRIDGE_KINDS_SET.has(d.kind)) return false;\n if (typeof d.type !== \"string\") return false;\n if (CORRELATED_KINDS_SET.has(d.kind) && typeof d.requestId !== \"string\") return false;\n return true;\n}\n\n// src/errors.ts\nvar BRIDGE_ERROR_BRAND = /* @__PURE__ */ Symbol.for(\"@nominalso/vibe-bridge:BridgeError\");\nvar HTTP_BRIDGE_ERROR_BRAND = /* @__PURE__ */ Symbol.for(\"@nominalso/vibe-bridge:HttpBridgeError\");\nvar BridgeError = class extends Error {\n constructor(code, message) {\n super(message);\n this.code = code;\n this.name = \"BridgeError\";\n }\n /**\n * Cross-realm-safe type guard. Prefer this over `instanceof BridgeError` when\n * an error may have been thrown by a differently-built copy of the SDK (e.g.\n * server bundle vs client bundle) — it matches on a process-global brand\n * rather than class identity.\n */\n static isBridgeError(err) {\n return typeof err === \"object\" && err !== null && err[BRIDGE_ERROR_BRAND] === true;\n }\n};\nObject.defineProperty(BridgeError.prototype, BRIDGE_ERROR_BRAND, {\n value: true,\n enumerable: false\n});\nvar HttpBridgeError = class extends BridgeError {\n constructor(status, message) {\n super(\"REQUEST_FAILED\", message);\n this.status = status;\n this.name = \"HttpBridgeError\";\n }\n /**\n * Cross-realm-safe type guard (see {@link BridgeError.isBridgeError}). Returns\n * `true` only for `HttpBridgeError` instances, not plain `BridgeError`s.\n */\n static isHttpBridgeError(err) {\n return typeof err === \"object\" && err !== null && err[HTTP_BRIDGE_ERROR_BRAND] === true;\n }\n};\nObject.defineProperty(HttpBridgeError.prototype, HTTP_BRIDGE_ERROR_BRAND, {\n value: true,\n enumerable: false\n});\n\n// src/origins.ts\nfunction isOriginPattern(entry) {\n return entry.includes(\"*\");\n}\nvar patternCache = /* @__PURE__ */ new Map();\nfunction patternToRegExp(pattern) {\n const cached = patternCache.get(pattern);\n if (cached) return cached;\n const escaped = pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const body = escaped.replace(/\\\\\\*/g, \"[^./:@?#\\\\s]+\");\n const compiled = new RegExp(`^${body}$`);\n patternCache.set(pattern, compiled);\n return compiled;\n}\nfunction matchesOrigin(origin, entry) {\n if (!isOriginPattern(entry)) return origin === entry;\n return patternToRegExp(entry).test(origin);\n}\nfunction isOriginAllowed(origin, allowlist, { allowPatterns }) {\n for (const entry of allowlist) {\n if (isOriginPattern(entry)) {\n if (allowPatterns && matchesOrigin(origin, entry)) return true;\n } else if (origin === entry) {\n return true;\n }\n }\n return false;\n}\nexport {\n BridgeError,\n HttpBridgeError,\n PROTOCOL_ID,\n PROTOCOL_VERSION,\n isBridgeMessage,\n isOriginAllowed,\n isOriginPattern,\n matchesOrigin,\n normalizeSubroute\n};\n","{\n \"name\": \"@nominalso/vibe-bridge\",\n \"version\": \"0.7.0\",\n \"description\": \"Iframe-side SDK for building Nominal Vibe Apps — connects an embedded app to its Nominal host over a typed postMessage bridge (context, data fetch, file upload, subroute deep-linking). Safe to import from SSR, React Server Components, and edge/Worker runtimes.\",\n \"license\": \"UNLICENSED\",\n \"homepage\": \"https://github.com/nominalso/vibe-apps-sdk#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/nominalso/vibe-apps-sdk/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"github:nominalso/vibe-apps-sdk\",\n \"directory\": \"packages/bridge\"\n },\n \"type\": \"module\",\n \"sideEffects\": false,\n \"types\": \"./dist/index.d.ts\",\n \"main\": \"./dist/index.browser.cjs\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"react-server\": \"./dist/index.server.js\",\n \"workerd\": \"./dist/index.server.js\",\n \"worker\": \"./dist/index.server.js\",\n \"edge-light\": \"./dist/index.server.js\",\n \"deno\": \"./dist/index.server.js\",\n \"browser\": {\n \"import\": \"./dist/index.browser.js\",\n \"require\": \"./dist/index.browser.cjs\"\n },\n \"default\": {\n \"import\": \"./dist/index.browser.js\",\n \"require\": \"./dist/index.browser.cjs\"\n }\n },\n \"./server\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.server.js\",\n \"require\": \"./dist/index.server.cjs\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\",\n \"docs\",\n \"AGENTS.md\",\n \"llms.txt\"\n ],\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org/\",\n \"access\": \"public\"\n },\n \"scripts\": {\n \"clean\": \"rm -rf dist node_modules\",\n \"build\": \"rm -rf dist && tsup\",\n \"lint\": \"eslint src\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\"\n },\n \"optionalDependencies\": {\n \"posthog-js\": \"^1.393.5\"\n },\n \"devDependencies\": {\n \"@nominalso/vibe-api-types\": \"workspace:*\",\n \"@nominalso/vibe-protocol-types\": \"workspace:*\"\n }\n}\n","import { version } from '../package.json'\n\n/**\n * Published version of this package (`@nominalso/vibe-bridge`), sent to the host\n * in the `CONNECT` handshake. Import-safe from any environment.\n */\nexport const BRIDGE_VERSION: string = version\n","import type { RequestRegistry } from '@nominalso/vibe-protocol-types'\n\nexport interface UploadOptions {\n /** Domain entity the file attaches to, e.g. `'JOURNAL_ENTRY'`. */\n entityType: string\n /** Id of the entity the file attaches to, when applicable. */\n entityId?: string | number\n /** Called with incremental progress (`0`–`100`) while the upload streams. */\n onProgress?: (p: RequestRegistry['UPLOAD_FILE']['progress']) => void\n}\n\n/**\n * The typed Nominal data methods (~46) plus {@link BridgeDataMethods.upload},\n * factored onto a base class so {@link VibeAppBridge} stays focused on\n * connection/transport. Each method is a thin typed wrapper over `request()`;\n * `VibeAppBridge` provides the concrete `request` implementation.\n */\nexport abstract class BridgeDataMethods {\n /**\n * Low-level typed request for **any** operation in {@link RequestRegistry} —\n * implemented by {@link VibeAppBridge}. The named methods below wrap this.\n */\n abstract request<K extends keyof RequestRegistry>(\n type: K,\n payload: RequestRegistry[K]['payload'],\n onProgress?: (payload: unknown) => void,\n ): Promise<RequestRegistry[K]['data']>\n\n // ---------------------------------------------------------------------------\n // Operations — Accounting: chart of accounts\n //\n // Each method is a typed wrapper over `request('<OP>', payload)`. The payload\n // and return types come straight from the Nominal API (`RequestRegistry`).\n // For any operation without a named method, call `request('<OP>', payload)`.\n // ---------------------------------------------------------------------------\n\n /**\n * Fetch the flat chart of accounts for a subsidiary.\n *\n * @example\n * ```ts\n * const ctx = await bridge.connect()\n * const accounts = await bridge.getChartOfAccounts({\n * path: { subsidiary_id: ctx.subsidiaryId },\n * })\n * ```\n */\n getChartOfAccounts(\n payload: RequestRegistry['GET_CHART_OF_ACCOUNTS']['payload'],\n ): Promise<RequestRegistry['GET_CHART_OF_ACCOUNTS']['data']> {\n return this.request('GET_CHART_OF_ACCOUNTS', payload)\n }\n\n /** Fetch the chart of accounts as a hierarchical tree for a subsidiary. */\n getCoaTree(\n payload: RequestRegistry['GET_COA_TREE']['payload'],\n ): Promise<RequestRegistry['GET_COA_TREE']['data']> {\n return this.request('GET_COA_TREE', payload)\n }\n\n /** Fetch a simplified flat chart of accounts for a subsidiary. */\n getCoaFlatSimple(\n payload: RequestRegistry['GET_COA_FLAT_SIMPLE']['payload'],\n ): Promise<RequestRegistry['GET_COA_FLAT_SIMPLE']['data']> {\n return this.request('GET_COA_FLAT_SIMPLE', payload)\n }\n\n /** Fetch the flat chart of accounts grouped by account group. */\n getCoaGrouped(\n payload: RequestRegistry['GET_COA_GROUPED']['payload'],\n ): Promise<RequestRegistry['GET_COA_GROUPED']['data']> {\n return this.request('GET_COA_GROUPED', payload)\n }\n\n /** Fetch a single chart-of-accounts account by id within a subsidiary. */\n getCoaAccount(\n payload: RequestRegistry['GET_COA_ACCOUNT']['payload'],\n ): Promise<RequestRegistry['GET_COA_ACCOUNT']['data']> {\n return this.request('GET_COA_ACCOUNT', payload)\n }\n\n /** List the currencies available to a subsidiary's chart of accounts. */\n getSubsidiaryAvailableCurrencies(\n payload: RequestRegistry['GET_SUBSIDIARY_AVAILABLE_CURRENCIES']['payload'],\n ): Promise<RequestRegistry['GET_SUBSIDIARY_AVAILABLE_CURRENCIES']['data']> {\n return this.request('GET_SUBSIDIARY_AVAILABLE_CURRENCIES', payload)\n }\n\n /** Fetch accounts at the tenant level. */\n getAccounts(\n payload: RequestRegistry['GET_ACCOUNTS']['payload'],\n ): Promise<RequestRegistry['GET_ACCOUNTS']['data']> {\n return this.request('GET_ACCOUNTS', payload)\n }\n\n /** Fetch a single account by id. */\n getAccount(\n payload: RequestRegistry['GET_ACCOUNT']['payload'],\n ): Promise<RequestRegistry['GET_ACCOUNT']['data']> {\n return this.request('GET_ACCOUNT', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Accounting: exchange rates\n // ---------------------------------------------------------------------------\n\n /** Fetch currency conversion rates for a currency. */\n getConversionRates(\n payload: RequestRegistry['GET_CONVERSION_RATES']['payload'],\n ): Promise<RequestRegistry['GET_CONVERSION_RATES']['data']> {\n return this.request('GET_CONVERSION_RATES', payload)\n }\n\n /** Fetch the effective consolidation exchange rate. */\n getEffectiveExchangeRate(\n payload: RequestRegistry['GET_EFFECTIVE_EXCHANGE_RATE']['payload'],\n ): Promise<RequestRegistry['GET_EFFECTIVE_EXCHANGE_RATE']['data']> {\n return this.request('GET_EFFECTIVE_EXCHANGE_RATE', payload)\n }\n\n /** Fetch the exchange-rate period covering a given input date. */\n getExchangeRateByDate(\n payload: RequestRegistry['GET_EXCHANGE_RATE_BY_DATE']['payload'],\n ): Promise<RequestRegistry['GET_EXCHANGE_RATE_BY_DATE']['data']> {\n return this.request('GET_EXCHANGE_RATE_BY_DATE', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Accounting: dimensions\n // ---------------------------------------------------------------------------\n\n /** List accounting dimensions. */\n getDimensions(\n payload: RequestRegistry['GET_DIMENSIONS']['payload'],\n ): Promise<RequestRegistry['GET_DIMENSIONS']['data']> {\n return this.request('GET_DIMENSIONS', payload)\n }\n\n /** List values for accounting dimensions. */\n getDimensionValues(\n payload: RequestRegistry['GET_DIMENSION_VALUES']['payload'],\n ): Promise<RequestRegistry['GET_DIMENSION_VALUES']['data']> {\n return this.request('GET_DIMENSION_VALUES', payload)\n }\n\n /** List dimension values in hierarchical form. */\n getDimensionValuesHierarchical(\n payload: RequestRegistry['GET_DIMENSION_VALUES_HIERARCHICAL']['payload'],\n ): Promise<RequestRegistry['GET_DIMENSION_VALUES_HIERARCHICAL']['data']> {\n return this.request('GET_DIMENSION_VALUES_HIERARCHICAL', payload)\n }\n\n /** List account assignments for a dimension/account pair. */\n getDimensionAccountAssignments(\n payload: RequestRegistry['GET_DIMENSION_ACCOUNT_ASSIGNMENTS']['payload'],\n ): Promise<RequestRegistry['GET_DIMENSION_ACCOUNT_ASSIGNMENTS']['data']> {\n return this.request('GET_DIMENSION_ACCOUNT_ASSIGNMENTS', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Accounting: journal entries\n // ---------------------------------------------------------------------------\n\n /**\n * Fetch journal entries for a subsidiary, optionally filtered by date range.\n *\n * @example\n * ```ts\n * const entries = await bridge.getJournalEntries({\n * path: { subsidiary_id: ctx.subsidiaryId },\n * query: { from_date: '2026-01-01', to_date: '2026-03-31' },\n * })\n * ```\n */\n getJournalEntries(\n payload: RequestRegistry['GET_JOURNAL_ENTRIES']['payload'],\n ): Promise<RequestRegistry['GET_JOURNAL_ENTRIES']['data']> {\n return this.request('GET_JOURNAL_ENTRIES', payload)\n }\n\n /** Fetch journal entry lines for a subsidiary. */\n getJournalLines(\n payload: RequestRegistry['GET_JOURNAL_LINES']['payload'],\n ): Promise<RequestRegistry['GET_JOURNAL_LINES']['data']> {\n return this.request('GET_JOURNAL_LINES', payload)\n }\n\n /** Fetch a single journal entry by id within a subsidiary. */\n getJournalEntry(\n payload: RequestRegistry['GET_JOURNAL_ENTRY']['payload'],\n ): Promise<RequestRegistry['GET_JOURNAL_ENTRY']['data']> {\n return this.request('GET_JOURNAL_ENTRY', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Activity: period instances\n // ---------------------------------------------------------------------------\n\n /** List accounting period instances. */\n getPeriods(\n payload: RequestRegistry['GET_PERIODS']['payload'],\n ): Promise<RequestRegistry['GET_PERIODS']['data']> {\n return this.request('GET_PERIODS', payload)\n }\n\n /** Fetch a single period instance by id. */\n getPeriodInstance(\n payload: RequestRegistry['GET_PERIOD_INSTANCE']['payload'],\n ): Promise<RequestRegistry['GET_PERIOD_INSTANCE']['data']> {\n return this.request('GET_PERIOD_INSTANCE', payload)\n }\n\n /** Fetch a period instance by its display slug (e.g. `\"mar-2026\"`). */\n getPeriodInstanceBySlug(\n payload: RequestRegistry['GET_PERIOD_INSTANCE_BY_SLUG']['payload'],\n ): Promise<RequestRegistry['GET_PERIOD_INSTANCE_BY_SLUG']['data']> {\n return this.request('GET_PERIOD_INSTANCE_BY_SLUG', payload)\n }\n\n /** Fetch the close-progress breakdown for a period (by slug). */\n getPeriodProgressBreakdown(\n payload: RequestRegistry['GET_PERIOD_PROGRESS_BREAKDOWN']['payload'],\n ): Promise<RequestRegistry['GET_PERIOD_PROGRESS_BREAKDOWN']['data']> {\n return this.request('GET_PERIOD_PROGRESS_BREAKDOWN', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Activity: activity definitions\n // ---------------------------------------------------------------------------\n\n /** List activity definitions. */\n getActivityDefinitions(\n payload: RequestRegistry['GET_ACTIVITY_DEFINITIONS']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_DEFINITIONS']['data']> {\n return this.request('GET_ACTIVITY_DEFINITIONS', payload)\n }\n\n /** Fetch a single activity definition by id. */\n getActivityDefinition(\n payload: RequestRegistry['GET_ACTIVITY_DEFINITION']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_DEFINITION']['data']> {\n return this.request('GET_ACTIVITY_DEFINITION', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Activity: activity instances\n // ---------------------------------------------------------------------------\n\n /** List activity instances. */\n getActivityInstances(\n payload: RequestRegistry['GET_ACTIVITY_INSTANCES']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_INSTANCES']['data']> {\n return this.request('GET_ACTIVITY_INSTANCES', payload)\n }\n\n /** Fetch a single activity instance by id. */\n getActivityInstance(\n payload: RequestRegistry['GET_ACTIVITY_INSTANCE']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_INSTANCE']['data']> {\n return this.request('GET_ACTIVITY_INSTANCE', payload)\n }\n\n /** Fetch an activity instance for a given period + activity definition. */\n getActivityInstanceByPeriod(\n payload: RequestRegistry['GET_ACTIVITY_INSTANCE_BY_PERIOD']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_INSTANCE_BY_PERIOD']['data']> {\n return this.request('GET_ACTIVITY_INSTANCE_BY_PERIOD', payload)\n }\n\n /** List task instances for an activity instance. */\n getActivityInstanceTasks(\n payload: RequestRegistry['GET_ACTIVITY_INSTANCE_TASKS']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_INSTANCE_TASKS']['data']> {\n return this.request('GET_ACTIVITY_INSTANCE_TASKS', payload)\n }\n\n /** List task instances for an activity in a given period. */\n getActivityPeriodTasks(\n payload: RequestRegistry['GET_ACTIVITY_PERIOD_TASKS']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_PERIOD_TASKS']['data']> {\n return this.request('GET_ACTIVITY_PERIOD_TASKS', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Activity: task definitions\n // ---------------------------------------------------------------------------\n\n /** List task definitions. */\n getTaskDefinitions(\n payload: RequestRegistry['GET_TASK_DEFINITIONS']['payload'],\n ): Promise<RequestRegistry['GET_TASK_DEFINITIONS']['data']> {\n return this.request('GET_TASK_DEFINITIONS', payload)\n }\n\n /** Fetch a single task definition by id. */\n getTaskDefinition(\n payload: RequestRegistry['GET_TASK_DEFINITION']['payload'],\n ): Promise<RequestRegistry['GET_TASK_DEFINITION']['data']> {\n return this.request('GET_TASK_DEFINITION', payload)\n }\n\n /** Create a task definition. */\n createTaskDefinition(\n payload: RequestRegistry['CREATE_TASK_DEFINITION']['payload'],\n ): Promise<RequestRegistry['CREATE_TASK_DEFINITION']['data']> {\n return this.request('CREATE_TASK_DEFINITION', payload)\n }\n\n /** Update a task definition by id. */\n updateTaskDefinition(\n payload: RequestRegistry['UPDATE_TASK_DEFINITION']['payload'],\n ): Promise<RequestRegistry['UPDATE_TASK_DEFINITION']['data']> {\n return this.request('UPDATE_TASK_DEFINITION', payload)\n }\n\n /** Query task definitions by filter. */\n getTaskDefinitionsByFilter(\n payload: RequestRegistry['GET_TASK_DEFINITIONS_BY_FILTER']['payload'],\n ): Promise<RequestRegistry['GET_TASK_DEFINITIONS_BY_FILTER']['data']> {\n return this.request('GET_TASK_DEFINITIONS_BY_FILTER', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Activity: task instances\n // ---------------------------------------------------------------------------\n\n /** List task instances. */\n getTaskInstances(\n payload: RequestRegistry['GET_TASK_INSTANCES']['payload'],\n ): Promise<RequestRegistry['GET_TASK_INSTANCES']['data']> {\n return this.request('GET_TASK_INSTANCES', payload)\n }\n\n /** Fetch a single task instance by id. */\n getTaskInstance(\n payload: RequestRegistry['GET_TASK_INSTANCE']['payload'],\n ): Promise<RequestRegistry['GET_TASK_INSTANCE']['data']> {\n return this.request('GET_TASK_INSTANCE', payload)\n }\n\n /**\n * Submit a Close-Management task output. This is the **only write path** back\n * into Nominal — Vibe Apps never write Nominal data directly.\n *\n * @example\n * ```ts\n * // `body` carries the task-specific output shape.\n * await bridge.postTaskOutput({\n * path: { task_instance_id: 'task-1' },\n * body: {},\n * })\n * ```\n */\n postTaskOutput(\n payload: RequestRegistry['POST_TASK_OUTPUT']['payload'],\n ): Promise<RequestRegistry['POST_TASK_OUTPUT']['data']> {\n return this.request('POST_TASK_OUTPUT', payload)\n }\n\n /** Query task instances by filter. */\n getTaskInstancesByFilter(\n payload: RequestRegistry['GET_TASK_INSTANCES_BY_FILTER']['payload'],\n ): Promise<RequestRegistry['GET_TASK_INSTANCES_BY_FILTER']['data']> {\n return this.request('GET_TASK_INSTANCES_BY_FILTER', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Audit trail\n // ---------------------------------------------------------------------------\n\n /** List audit-trail events. */\n getAuditEvents(\n payload: RequestRegistry['GET_AUDIT_EVENTS']['payload'],\n ): Promise<RequestRegistry['GET_AUDIT_EVENTS']['data']> {\n return this.request('GET_AUDIT_EVENTS', payload)\n }\n\n /** List audit-trail events for a specific entity. */\n getEntityAuditEvents(\n payload: RequestRegistry['GET_ENTITY_AUDIT_EVENTS']['payload'],\n ): Promise<RequestRegistry['GET_ENTITY_AUDIT_EVENTS']['data']> {\n return this.request('GET_ENTITY_AUDIT_EVENTS', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Period manager: fiscal calendars\n // ---------------------------------------------------------------------------\n\n /** List fiscal calendars for a subsidiary. */\n getFiscalCalendars(\n payload: RequestRegistry['GET_FISCAL_CALENDARS']['payload'],\n ): Promise<RequestRegistry['GET_FISCAL_CALENDARS']['data']> {\n return this.request('GET_FISCAL_CALENDARS', payload)\n }\n\n /** Fetch a single fiscal calendar by id. */\n getFiscalCalendar(\n payload: RequestRegistry['GET_FISCAL_CALENDAR']['payload'],\n ): Promise<RequestRegistry['GET_FISCAL_CALENDAR']['data']> {\n return this.request('GET_FISCAL_CALENDAR', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Tenancy\n // ---------------------------------------------------------------------------\n\n /** List subsidiaries for the tenant. */\n getSubsidiaries(\n payload: RequestRegistry['GET_SUBSIDIARIES']['payload'],\n ): Promise<RequestRegistry['GET_SUBSIDIARIES']['data']> {\n return this.request('GET_SUBSIDIARIES', payload)\n }\n\n /** Fetch a single subsidiary by id. */\n getSubsidiary(\n payload: RequestRegistry['GET_SUBSIDIARY']['payload'],\n ): Promise<RequestRegistry['GET_SUBSIDIARY']['data']> {\n return this.request('GET_SUBSIDIARY', payload)\n }\n\n /** List parent currencies for a subsidiary. */\n getSubsidiaryParentCurrencies(\n payload: RequestRegistry['GET_SUBSIDIARY_PARENT_CURRENCIES']['payload'],\n ): Promise<RequestRegistry['GET_SUBSIDIARY_PARENT_CURRENCIES']['data']> {\n return this.request('GET_SUBSIDIARY_PARENT_CURRENCIES', payload)\n }\n\n /** List users for the tenant. */\n getTenantUsers(\n payload: RequestRegistry['GET_TENANT_USERS']['payload'],\n ): Promise<RequestRegistry['GET_TENANT_USERS']['data']> {\n return this.request('GET_TENANT_USERS', payload)\n }\n\n /**\n * Uploads a file through the host. Converts the `File` to an `ArrayBuffer`\n * before sending — sandboxed iframes cannot pass `File` handles across\n * windows. Resolves once Nominal has stored the file.\n *\n * @example\n * ```ts\n * const input = document.querySelector<HTMLInputElement>('#file')!\n * const file = input.files![0]\n * const result = await bridge.upload(file, {\n * entityType: 'JOURNAL_ENTRY',\n * entityId: '123',\n * onProgress: (p) => console.log(`${p.progress}%`),\n * })\n * // result.attachmentId, result.name\n * ```\n */\n async upload(\n file: File,\n options: UploadOptions,\n ): Promise<RequestRegistry['UPLOAD_FILE']['data']> {\n const buffer = await file.arrayBuffer()\n const payload: RequestRegistry['UPLOAD_FILE']['payload'] = {\n buffer,\n fileName: file.name,\n fileType: file.type,\n entityType: options.entityType,\n entityId: options.entityId,\n }\n const onProgress = options.onProgress\n ? (p: unknown): void => options.onProgress!(p as RequestRegistry['UPLOAD_FILE']['progress'])\n : undefined\n return this.request('UPLOAD_FILE', payload, onProgress)\n }\n}\n","import type { RequestRegistry } from '@nominalso/vibe-protocol-types'\n\n/** Hard ceiling (ms) for `connect()` before it rejects with a `'TIMEOUT'` error. */\nexport const CONNECT_TIMEOUT_MS = 10_000\n/** Interval (ms) between `CONNECT` handshakes while `connect()` waits for the host. */\nexport const CONNECT_POLL_MS = 500\n\n/**\n * Default per-operation request timeouts (ms), mirroring nom-ui's bridge\n * protocol (`BRIDGE_TIMEOUTS`) so apps migrating off the in-tree bridge don't\n * regress. Used when `requestTimeout` is not set on the bridge options.\n */\nexport const DEFAULT_TIMEOUTS = {\n /** Typed Nominal API reads/writes (`GET_*` / `POST_*` / `CREATE_*` / ...). */\n api: 30_000,\n /** `INVALIDATE_CACHE`. */\n invalidate: 10_000,\n /** `UPLOAD_FILE` — large payloads + presigned S3 PUT take a while. */\n upload: 120_000,\n} as const\n\n/**\n * Resolves the timeout (ms) for a given operation: the explicit `requestTimeout`\n * if set, otherwise the operation-specific default from {@link DEFAULT_TIMEOUTS}.\n */\nexport function resolveRequestTimeout(\n type: keyof RequestRegistry,\n requestTimeout?: number,\n): number {\n if (requestTimeout !== undefined) return requestTimeout\n switch (type) {\n case 'UPLOAD_FILE':\n return DEFAULT_TIMEOUTS.upload\n case 'INVALIDATE_CACHE':\n return DEFAULT_TIMEOUTS.invalidate\n default:\n return DEFAULT_TIMEOUTS.api\n }\n}\n","import {\n PROTOCOL_ID,\n PROTOCOL_VERSION,\n isBridgeMessage,\n isOriginAllowed,\n isOriginPattern,\n normalizeSubroute,\n BridgeError,\n HttpBridgeError,\n type ContextPayload,\n type AuthPayload,\n type PostHogContext,\n type BridgeKind,\n type AnyBridgeMessage,\n type RequestRegistry,\n type CommandRegistry,\n type PushRegistry,\n type ResponseMessage,\n type ProgressMessage,\n type PushMessage,\n type WireRequestMessage,\n type NavigateAction,\n type SetSideNavPayload,\n type InvalidateCachePayload,\n type InvalidateResult,\n} from '@nominalso/vibe-protocol-types'\nimport { BRIDGE_VERSION } from './version'\nimport type { VibeAppBridgeOptions } from './options'\nimport { BridgeDataMethods } from './data-methods'\nimport { CONNECT_TIMEOUT_MS, CONNECT_POLL_MS, resolveRequestTimeout } from './timeouts'\n\n/**\n * Minimal shape of the parts of `posthog-js` the bridge uses. Declared locally\n * so this module never *statically* imports `posthog-js` — the real module is\n * pulled in lazily via `await import('posthog-js')` only when the host enables\n * recording (see {@link VibeAppBridge.initPostHog}), keeping the optional\n * dependency out of the import graph and out of any server bundle.\n */\ninterface PostHogLike {\n init: (token: string, config: Record<string, unknown>) => void\n identify: (distinctId: string) => void\n capture: (event: string, properties?: Record<string, unknown>) => void\n}\n\n/**\n * `posthog-js` ships a transpiled-ESM entry (`__esModule` with the singleton\n * under `.default`). Depending on how the dynamic import's interop resolves, the\n * singleton can sit one or two `.default` levels deep. Walk down `.default`\n * (always a real export, safe to read) rather than probing `.init` on the module\n * namespace — accessing a *non-exported* name on an ESM namespace throws in some\n * loaders (e.g. Vitest), which would otherwise send us down the \"not installed\"\n * path. Returns the first object that actually carries `init`, else `null`.\n */\nfunction resolvePosthog(mod: unknown): PostHogLike | null {\n const hasInit = (o: unknown): o is PostHogLike =>\n typeof (o as PostHogLike | undefined)?.init === 'function'\n // The singleton lives under `.default` (one interop wrapper deep, sometimes\n // two). Read `.default` — always a real export — before probing `.init`, so we\n // never touch a non-exported name on the module namespace (which throws in some\n // loaders, e.g. Vitest). Fall back to the value itself for bundlers that hand\n // back the singleton directly.\n const d1 = (mod as { default?: unknown } | undefined)?.default\n if (hasInit(d1)) return d1\n const d2 = (d1 as { default?: unknown } | undefined)?.default\n if (hasInit(d2)) return d2\n if (hasInit(mod)) return mod\n return null\n}\n\n/**\n * The runtime environment guard. Every bridge method that touches the DOM (or\n * drives the postMessage transport) calls this first, so a call made where there\n * is no `window` — during SSR, inside a React Server Component, or in a Worker\n * that resolved the browser build — fails loud with a coded error instead of\n * throwing an opaque `window is not defined` or silently hanging.\n *\n * Import and construction are always safe; only *calling* a browser method here\n * is gated. In practice the exports map routes server/RSC/Worker imports to the\n * server stub, so this is belt-and-suspenders for graphs that still evaluate the\n * browser build server-side (e.g. the SSR pass of a client component).\n */\nfunction serverEnvError(method: string): BridgeError {\n return new BridgeError(\n 'SERVER_ENVIRONMENT',\n `VibeAppBridge.${method} was called outside a browser (no \\`window\\`). ` +\n `The bridge only runs in the browser — call it from a client component or ` +\n `effect, not during SSR, in a React Server Component, or in a Worker.`,\n )\n}\n\nfunction assertBrowser(method: string): void {\n if (typeof window === 'undefined') throw serverEnvError(method)\n}\n\n/**\n * Global the dev-bridge Chrome extension sets inside the Lovable editor preview\n * to expose the iframe's *real* parent origin (the Lovable editor). See\n * {@link resolveOriginPolicy}.\n */\nconst PARENT_ORIGIN_OVERRIDE_KEY = '__NOM_VIBE_PARENT_ORIGIN__'\n\n/**\n * Hosts that serve a vibe app from a throwaway *preview* URL. When the app's own\n * page is served from one of these, `parentOrigin` glob patterns are honoured;\n * on any other host (a production custom domain) patterns are ignored and only\n * exact origins match. The check keys off the iframe's *own* `location.hostname`\n * — which a page framing the app cannot change — so it is fail-closed: a\n * production build silently downgrades to strict exact-match.\n */\nconst PREVIEW_HOST_RE =\n /(?:^|\\.)(?:vercel\\.app|lovable\\.app|lovable\\.dev|lovableproject\\.com)$|^(?:localhost|127\\.0\\.0\\.1)$/\n\nfunction isPreviewSelfHost(hostname: string): boolean {\n return PREVIEW_HOST_RE.test(hostname)\n}\n\n/**\n * Best-effort discovery of the iframe's *actual* parent origin, used to pick a\n * concrete `postMessage` target when `parentOrigin` is a list/pattern (you\n * cannot post to a pattern). `ancestorOrigins` is Chromium/WebKit only; the\n * `document.referrer` fallback covers other engines but can be empty under a\n * strict `Referrer-Policy`. Returns `null` when neither is available.\n */\nfunction resolveActualParentOrigin(): string | null {\n if (typeof window === 'undefined') return null\n try {\n const ancestors = window.location.ancestorOrigins\n if (ancestors && ancestors.length > 0 && ancestors[0]) return ancestors[0]\n } catch {\n // ancestorOrigins is not implemented everywhere; fall through to referrer.\n }\n try {\n if (document.referrer) return new URL(document.referrer).origin\n } catch {\n // Malformed referrer — treat as unavailable.\n }\n return null\n}\n\n/** What the bridge needs to know about origins, derived once at attach. */\ninterface OriginPolicy {\n /** Concrete origin to `postMessage` to, or `null` if none could be resolved. */\n targetOrigin: string | null\n /** Validates an inbound `event.origin`. */\n isTrusted: (origin: string) => boolean\n}\n\n/**\n * Resolves the effective origin policy from the configured `parentOrigin`.\n *\n * Reads `window`/`document`, so it is only ever called from {@link\n * VibeAppBridge.attach} (never at module load or in the constructor).\n *\n * Priority and behaviour:\n *\n * 1. **Dev-bridge override.** When `window.__NOM_VIBE_PARENT_ORIGIN__` is set\n * (the Lovable-editor extension, which relays the protocol across tabs where\n * the real `window.parent` is the editor, not the configured host), it fully\n * replaces the configured value — exact target and exact inbound check — so\n * that flow is unchanged.\n * 2. **Omitted (no `parentOrigin`):** auto-detect the actual parent and talk\n * only to it. Safe because Nominal serves Vibe Apps behind a `frame-ancestors`\n * CSP, so only nom-ui can frame the app — the discovered parent is legitimate.\n * If no parent can be detected, the target is `null` (fast `connect()` reject).\n * 3. **Single exact origin** (the common explicit case): used verbatim as the\n * target and the inbound check. No parent discovery — identical to historical\n * behaviour.\n * 4. **List and/or glob patterns:** patterns count only when the app's own page\n * is a preview host ({@link isPreviewSelfHost}, fail-closed). The concrete\n * target is the actual parent origin (discovered + validated); if discovery\n * fails it falls back to the sole exact entry, else `null` (ambiguous →\n * refuse to post, surfaced as a fast `connect()` rejection).\n */\nfunction resolveOriginPolicy(configured?: string | string[]): OriginPolicy {\n if (typeof window !== 'undefined') {\n const override = (window as unknown as Record<string, unknown>)[PARENT_ORIGIN_OVERRIDE_KEY]\n if (typeof override === 'string' && override.length > 0) {\n console.log(`[vibe-bridge] Using dev-bridge parentOrigin override: ${override}`)\n return { targetOrigin: override, isTrusted: (o) => o === override }\n }\n }\n\n // Normalize to a clean list: coerce to array, trim, drop blank entries. An\n // unset env var that resolves to `''` (a common wiring of\n // `parentOrigin: import.meta.env.VITE_PARENT_ORIGIN`) thus behaves like\n // \"omitted\" — auto-detect — instead of building a broken bridge whose target\n // is the empty string (which would never match and would throw in postMessage).\n const rawList =\n configured === undefined ? [] : Array.isArray(configured) ? configured : [configured]\n const allowlist = rawList.map((entry) => entry.trim()).filter((entry) => entry.length > 0)\n\n // No usable allowlist: trust whatever Nominal page actually embeds us. Hostile\n // framing is blocked at the edge by a `frame-ancestors` CSP, so the discovered\n // parent is legitimate — and app authors configure nothing.\n if (allowlist.length === 0) {\n const actual = resolveActualParentOrigin()\n if (actual) return { targetOrigin: actual, isTrusted: (o) => o === actual }\n console.warn(\n '[vibe-bridge] No `parentOrigin` set and the embedding host could not be ' +\n 'auto-detected (no ancestorOrigins/referrer). Pass `parentOrigin` explicitly.',\n )\n return { targetOrigin: null, isTrusted: () => false }\n }\n\n const exactEntries = allowlist.filter((entry) => !isOriginPattern(entry))\n const hasPatterns = exactEntries.length !== allowlist.length\n\n // Common path: exactly one exact origin, no patterns. Behave exactly as before\n // — post to it directly (the browser enforces the match) and trust only it.\n if (allowlist.length === 1 && !hasPatterns) {\n const only = allowlist[0]\n return { targetOrigin: only, isTrusted: (o) => o === only }\n }\n\n const allowPatterns =\n hasPatterns && typeof window !== 'undefined' && isPreviewSelfHost(window.location.hostname)\n\n const isTrusted = (o: string): boolean => isOriginAllowed(o, allowlist, { allowPatterns })\n\n const actual = resolveActualParentOrigin()\n let targetOrigin: string | null = null\n if (actual && isTrusted(actual)) {\n targetOrigin = actual\n } else if (actual === null && !allowPatterns && exactEntries.length === 1) {\n // Parent discovery genuinely failed (e.g. referrer suppressed) AND patterns\n // aren't in play, so the sole exact origin is the only trusted target — safe\n // to post to it (the browser drops the message if the real parent differs).\n // We deliberately do NOT fall back when patterns are active (a preview host):\n // the real embedder might match only a pattern, so the exact entry would be a\n // wrong guess that merely waits out the 10s timeout. A parent that WAS\n // discovered but isn't trusted, or several exact entries, are likewise\n // ambiguous → null → fast connect() reject.\n targetOrigin = exactEntries[0]\n }\n\n if (targetOrigin === null) {\n console.warn(\n '[vibe-bridge] Could not resolve a parent origin to post to. ' +\n 'Check `parentOrigin` against the embedding host' +\n (hasPatterns && !allowPatterns\n ? ' — pattern entries are ignored because this page is not served from a recognised preview host.'\n : '.'),\n )\n }\n\n return { targetOrigin, isTrusted }\n}\n\ninterface PendingRequest {\n resolve: (data: unknown) => void\n reject: (error: Error) => void\n onProgress?: (payload: unknown) => void\n}\n\n/**\n * Iframe-side bridge to the Nominal host. One instance per app: construct it,\n * `await connect()` once, then call data methods, `upload()`, and subroute\n * helpers. Tear down with `destroy()` on unmount.\n *\n * **Import- and construction-safe everywhere.** The constructor is pure — it\n * stores options and touches **no** browser API — so importing this module and\n * `new VibeAppBridge()` are safe during SSR, in a React Server Component, or in\n * a Worker. The browser is only required when a method actually *runs*: the\n * message listener, origin resolution, and history patching are all deferred to\n * the first {@link VibeAppBridge.connect} (or an explicit {@link\n * VibeAppBridge.attach}). Calling a browser method where there is no `window`\n * throws a `BridgeError` with code `'SERVER_ENVIRONMENT'`.\n *\n * Every data method delegates to {@link VibeAppBridge.request}; the ~46 named\n * methods (e.g. {@link VibeAppBridge.getChartOfAccounts}) are the typed,\n * discoverable surface, and `request('<OP>', payload)` is the escape hatch for\n * any operation in {@link RequestRegistry}.\n *\n * @example\n * ```ts\n * import { VibeAppBridge, type ContextPayload } from '@nominalso/vibe-bridge'\n *\n * const bridge = new VibeAppBridge({ parentOrigin: import.meta.env.VITE_PARENT_ORIGIN })\n *\n * const ctx: ContextPayload = await bridge.connect()\n * const accounts = await bridge.getChartOfAccounts({ path: { subsidiary_id: ctx.subsidiaryId } })\n *\n * // cleanup\n * bridge.destroy()\n * ```\n */\nexport class VibeAppBridge extends BridgeDataMethods {\n /** Configured origin option, read lazily at {@link attach} (never at construction). */\n private readonly parentOriginOption?: string | string[]\n /** Concrete origin to `postMessage` to, or `null` until resolved at {@link attach}. */\n private targetOrigin: string | null = null\n /** Validates an inbound `event.origin`; rejects everything until {@link attach}. */\n private isTrustedOrigin: (origin: string) => boolean = () => false\n private readonly requestTimeout: number | undefined\n private readonly pendingRequests = new Map<string, PendingRequest>()\n private readonly boundHandleMessage: (event: MessageEvent) => void\n /** Whether {@link attach} has installed the message listener + resolved origin. */\n private attached = false\n\n private context: ContextPayload | null = null\n /**\n * Set once {@link initPostHog} has successfully called `posthog.init()`.\n * Guards against a double-init and makes {@link track} a no-op until\n * recording is actually live.\n */\n private posthogInitialized = false\n /** The lazily-imported `posthog-js` singleton, once recording is initialized. */\n private posthogInstance: PostHogLike | null = null\n /**\n * Set for the duration of an in-flight {@link initPostHog} (which is async — it\n * awaits `import('posthog-js')`). Serializes initialization so two overlapping\n * `POSTHOG_PUSH`es can't both call `posthog.init()`.\n */\n private posthogIniting = false\n /** So the \"posthog-js not installed\" warning is logged at most once. */\n private posthogUnavailableWarned = false\n private connectPromise: Promise<ContextPayload> | null = null\n private connectPollInterval: ReturnType<typeof setInterval> | null = null\n private connectTimeout: ReturnType<typeof setTimeout> | null = null\n private onContextReceived: ((ctx: ContextPayload) => void) | null = null\n /** Rejects an in-flight connect() (used by destroy()); `null` once settled. */\n private rejectConnect: ((error: BridgeError) => void) | null = null\n /**\n * Persistent subscriber for post-connect context changes (tenant/subsidiary\n * switch, period close, …). Distinct from {@link onContextReceived}, which only\n * resolves the connect handshake and is cleared afterward. `null` until\n * {@link onContextChange} is called.\n */\n private contextChangeCallback: ((ctx: ContextPayload) => void) | null = null\n /**\n * Persistent subscriber for host auth changes (Nominal logout or\n * identity/tenant switch). `null` until {@link onAuthChange} is called.\n */\n private authChangeCallback: ((auth: AuthPayload) => void) | null = null\n\n private lastReportedSubroute: string | null = null\n private suppressSubrouteReport = false\n private subrouteCallback: ((subroute: string) => void) | null = null\n private origPushState: typeof history.pushState | null = null\n private origReplaceState: typeof history.replaceState | null = null\n private popstateHandler: (() => void) | null = null\n\n private readonly kindHandlers: Partial<Record<BridgeKind, (msg: AnyBridgeMessage) => void>> = {\n response: (msg) => this.handleResponse(msg as ResponseMessage),\n push: (msg) => this.dispatchPush(msg as PushMessage),\n progress: (msg) => this.handleProgress(msg as ProgressMessage),\n }\n\n private dispatchPush(msg: PushMessage): void {\n const handler = this.pushHandlers[msg.type] as (payload: unknown) => void\n handler(msg.payload)\n }\n\n private readonly pushHandlers: { [K in keyof PushRegistry]: (payload: PushRegistry[K]) => void } =\n {\n CONTEXT_PUSH: (payload) => {\n if (this.onContextReceived) {\n // Connect handshake: resolve connect() with the initial context.\n this.onContextReceived(payload)\n } else if (this.context) {\n // Post-connect update: refresh the cached context and notify the app so\n // it can react to a tenant/subsidiary/period change without reloading.\n this.context = payload\n this.contextChangeCallback?.(payload)\n }\n // Otherwise a push arrived before connect() was called — ignore it\n // rather than caching context, so connect() still runs its full handshake\n // (setupNavigationTracking, etc.) instead of short-circuiting.\n },\n // Persistent (not nulled after connect): the host delivers PostHog once at\n // connect via its own push, and initPostHog is idempotent, so this can run\n // whenever the message arrives, independent of how connect() resolved. Fire\n // and forget — initPostHog is async (lazy-imports posthog-js) and swallows\n // its own errors.\n POSTHOG_PUSH: (payload) => {\n void this.initPostHog(payload)\n },\n // Persistent: the host pushes auth changes (logout, identity/tenant\n // switch) at any time after connect.\n AUTH_CHANGED: (payload) => this.authChangeCallback?.(payload),\n SUBROUTE_PUSH: (payload) => {\n // Guard inbound subroutes too: a `..` segment pushed by the host must\n // not be applied to the iframe's history (matches the outbound guard).\n const safe = normalizeSubroute(payload.subroute)\n if (!safe) return\n this.withSubrouteSuppressed(() => {\n if (this.subrouteCallback) {\n this.subrouteCallback(safe)\n } else {\n history.pushState(null, '', safe)\n window.dispatchEvent(new PopStateEvent('popstate'))\n }\n this.lastReportedSubroute = safe\n })\n },\n }\n\n /**\n * Stores options only — **pure and side-effect-free**. No `window`,\n * `document`, `history`, `postMessage`, `crypto`, or `posthog-js` access\n * happens here, so constructing a bridge is safe during SSR / in a Server\n * Component / in a Worker. Browser wiring is deferred to {@link connect} /\n * {@link attach}.\n */\n constructor(options: VibeAppBridgeOptions = {}) {\n super()\n this.parentOriginOption = options.parentOrigin\n this.requestTimeout = options.requestTimeout\n // Binding a method is pure (no DOM access); the listener is only *installed*\n // in attach().\n this.boundHandleMessage = this.handleMessage.bind(this)\n }\n\n /**\n * Installs the browser wiring: resolves the parent-origin policy and starts\n * listening for host `postMessage`s. **Idempotent** and safe to call before\n * {@link connect} if you want the bridge receiving pushes early; {@link\n * connect} calls it for you, so most apps never call this directly.\n *\n * @throws `BridgeError` code `'SERVER_ENVIRONMENT'` if called where there is no\n * `window`.\n */\n attach(): void {\n assertBrowser('attach()')\n if (this.attached) return\n const policy = resolveOriginPolicy(this.parentOriginOption)\n this.targetOrigin = policy.targetOrigin\n this.isTrustedOrigin = policy.isTrusted\n window.addEventListener('message', this.boundHandleMessage)\n this.attached = true\n }\n\n /**\n * Lazily installs the browser wiring on first transport use. Keeps the\n * constructor pure while ensuring that any method reaching the wire (a data\n * `request`, a fire-and-forget command) works without an explicit prior\n * `attach()`/`connect()` — attach stays idempotent, so `connect()` is\n * unaffected.\n */\n private ensureAttached(): void {\n if (!this.attached) this.attach()\n }\n\n /**\n * Connects to the host and returns the tenant/user {@link ContextPayload}.\n * **Call this once on app init and await it before any other method** — data\n * methods, `upload()`, and subroute reporting all require an established\n * connection. Concurrent calls return the same promise.\n *\n * First {@link attach | attaches} the browser wiring (message listener +\n * origin resolution), then sends a `CONNECT` handshake, re-sending every 500ms\n * until the host replies by pushing the context (so it works even if the host\n * mounts after the iframe loads). Context is only ever delivered by push.\n * Rejects with `Bridge connect timed out` after 10 seconds if no context\n * arrives (usually a `parentOrigin` mismatch or the host hasn't mounted).\n *\n * After connecting, if the context includes an initial subroute (e.g. from\n * a deep link), the bridge navigates to it and starts auto-tracking\n * internal navigation via the history API.\n *\n * @returns The tenant/user/subsidiary context for this app session.\n * @throws Rejects with `BridgeError` code `'SERVER_ENVIRONMENT'` if called\n * where there is no `window`, `'PARENT_ORIGIN_UNRESOLVED'` if no embedding\n * origin could be resolved, or `'TIMEOUT'` if no context arrives in 10s.\n * @example\n * ```ts\n * const ctx = await bridge.connect()\n * // ctx.tenant, ctx.subsidiaryId, ctx.subsidiaries, ctx.user, ctx.lastClosedPeriodSlug\n * ```\n */\n connect(): Promise<ContextPayload> {\n if (typeof window === 'undefined') return Promise.reject(serverEnvError('connect()'))\n if (this.context) return Promise.resolve(this.context)\n if (this.connectPromise) return this.connectPromise\n\n // Install the message listener + resolve the origin policy now (idempotent).\n this.attach()\n\n // No concrete parent origin to post to — a config/embedding error, not a\n // transient timeout. Reject immediately with a clear message rather than\n // polling into the 10s TIMEOUT (resolveOriginPolicy has already warned).\n if (this.targetOrigin === null) {\n return Promise.reject(\n new BridgeError(\n 'PARENT_ORIGIN_UNRESOLVED',\n 'Could not resolve a parent origin to connect to. Check `parentOrigin` against the embedding host.',\n ),\n )\n }\n\n this.connectPromise = new Promise<ContextPayload>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.stopConnectPolling()\n this.connectPromise = null\n this.onContextReceived = null\n this.rejectConnect = null\n reject(new BridgeError('TIMEOUT', 'Bridge connect timed out'))\n }, CONNECT_TIMEOUT_MS)\n // Track on the instance so destroy() (via stopConnectPolling) clears it —\n // otherwise a destroy() before context arrives leaves this 10s timer armed\n // to fire reject() on an already-torn-down bridge.\n this.connectTimeout = timer\n\n // Lets destroy() reject an in-flight connect() so awaiting it fails fast\n // instead of hanging to the TIMEOUT.\n this.rejectConnect = (error: BridgeError) => {\n clearTimeout(timer)\n this.stopConnectPolling()\n this.connectPromise = null\n this.onContextReceived = null\n this.rejectConnect = null\n reject(error)\n }\n\n this.onContextReceived = (ctx: ContextPayload) => {\n clearTimeout(timer)\n this.stopConnectPolling()\n this.context = ctx\n this.connectPromise = null\n this.onContextReceived = null\n this.rejectConnect = null\n\n console.log(\n `[vibe-bridge] Connected — bridge: ${BRIDGE_VERSION}, host: ${ctx.hostVersion}, tenant: ${ctx.tenant}, user: ${ctx.user.displayName}`,\n )\n\n // PostHog is initialized separately, when the host's one-time\n // POSTHOG_PUSH arrives (see pushHandlers) — not from the context here.\n\n // Guard the connect-time deep link before applying it to history — a\n // `..` segment in the host's context must not traverse (matches the\n // outbound reportSubroute guard).\n const initialSubroute = ctx.subroute ? normalizeSubroute(ctx.subroute) : null\n if (initialSubroute && initialSubroute !== '/') {\n this.withSubrouteSuppressed(() => {\n history.replaceState(null, '', initialSubroute)\n window.dispatchEvent(new PopStateEvent('popstate'))\n this.lastReportedSubroute = initialSubroute\n })\n } else {\n this.lastReportedSubroute = window.location.pathname + window.location.search\n }\n\n this.setupNavigationTracking()\n this.warnMissingListeners()\n resolve(ctx)\n }\n\n // Announce readiness with a CONNECT handshake. The host validates the\n // origin and replies by pushing CONTEXT_PUSH (which resolves connect via\n // onContextReceived) — context is only ever delivered by push. Re-send on\n // an interval until that push lands, since the host may mount (start\n // listening) after the iframe loads.\n const sendConnect = (): void => {\n this.sendCommand('CONNECT', { bridgeVersion: BRIDGE_VERSION })\n }\n sendConnect()\n this.connectPollInterval = setInterval(sendConnect, CONNECT_POLL_MS)\n })\n\n return this.connectPromise\n }\n\n /**\n * Manually reports the current subroute to the host.\n * Usually not needed — navigation is auto-detected via the history API.\n * Use this for hash-based routers or non-standard navigation patterns.\n */\n reportSubroute(subroute: string, options?: { replace?: boolean }): void {\n assertBrowser('reportSubroute()')\n // Shared with the host's REPORT_SUBROUTE guard: ensures a leading slash and\n // drops path traversal, so a bad subroute is never put on the wire.\n const normalized = normalizeSubroute(subroute)\n if (normalized === null) return\n this.lastReportedSubroute = normalized\n this.sendCommand('REPORT_SUBROUTE', { subroute: normalized, replace: options?.replace })\n }\n\n /**\n * Registers a callback for host-initiated navigation (browser back/forward).\n * If no callback is registered, the SDK uses `history.pushState` + a\n * `popstate` event, which works for most SPA routers automatically.\n * Returns an unsubscribe function.\n *\n * Pure — only stores the callback, so it is safe to call before {@link connect}.\n */\n onSubrouteRequest(callback: (subroute: string) => void): () => void {\n this.subrouteCallback = callback\n return (): void => {\n this.subrouteCallback = null\n }\n }\n\n /**\n * Subscribes to post-connect context changes (tenant/subsidiary switch, period\n * close, …). The callback fires for each {@link ContextPayload} the host pushes\n * *after* connect — not for the initial context, which {@link connect} already\n * returns. Returns an unsubscribe function. Single subscriber: a second call\n * replaces the first. Wire it **before {@link connect}** (the bridge warns at\n * connect if it isn't).\n *\n * Pure — only stores the callback, so it is safe to call before {@link connect}.\n */\n onContextChange(callback: (ctx: ContextPayload) => void): () => void {\n this.contextChangeCallback = callback\n return (): void => {\n this.contextChangeCallback = null\n }\n }\n\n /**\n * Subscribes to host auth changes: a Nominal logout (`authenticated: false` —\n * sign your backend out) or an identity/tenant switch (`authenticated: true`\n * with a new `userId`/`tenant` — re-authenticate). Fires for each change the\n * host pushes after connect. Returns an unsubscribe function. Single\n * subscriber: a second call replaces the first.\n *\n * **Wire this before {@link connect}** — without it the embedded app won't\n * sign out when the user logs out of Nominal (the bridge warns at connect if\n * it isn't wired). Pure — only stores the callback.\n */\n onAuthChange(callback: (auth: AuthPayload) => void): () => void {\n this.authChangeCallback = callback\n return (): void => {\n this.authChangeCallback = null\n }\n }\n\n /**\n * At connect, nudge the app if it hasn't wired the change listeners: every\n * embedded app should react to a Nominal logout ({@link onAuthChange}) and a\n * tenant/subsidiary switch ({@link onContextChange}). Fires once during the\n * connect flow (not speculatively later), so wire both **before** `connect()`.\n * The skill/codegen does this by default; this catches hand-wired apps.\n */\n private warnMissingListeners(): void {\n if (!this.authChangeCallback) {\n console.warn(\n '[vibe-bridge] connected without onAuthChange — the app will not sign out on ' +\n 'Nominal logout or react to an identity/tenant switch. Call bridge.onAuthChange() before connect().',\n )\n }\n if (!this.contextChangeCallback) {\n console.warn(\n '[vibe-bridge] connected without onContextChange — the app will not react to a ' +\n 'tenant/subsidiary/period switch. Call bridge.onContextChange() before connect().',\n )\n }\n }\n\n // ---------------------------------------------------------------------------\n // Host navigation & UI commands\n //\n // These drive the *host* (nom-ui) chrome — its router, side nav, and\n // subsidiary switcher — rather than the iframe's own internal routing\n // (`reportSubroute`). Navigation/UI commands are fire-and-forget;\n // `invalidateCache` is awaited.\n // ---------------------------------------------------------------------------\n\n /**\n * Navigates the host to a raw path relative to this app's tenant/subsidiary\n * base. Fire-and-forget.\n *\n * @example\n * ```ts\n * bridge.navigate('/journal-entries/123')\n * bridge.navigate('/journal-entries/123', 'replace')\n * ```\n */\n navigate(path: string, action: NavigateAction = 'push'): void {\n assertBrowser('navigate()')\n this.sendCommand('NAVIGATE', { path, action })\n }\n\n /**\n * Navigates the host to a named Nominal route, with optional params for\n * placeholder segments. Fire-and-forget.\n *\n * @example\n * ```ts\n * bridge.navigateTo('CHART_OF_ACCOUNTS')\n * bridge.navigateTo('JOURNAL_ENTRY', { id: '123' }, 'replace')\n * ```\n */\n navigateTo(\n route: string,\n routeParams?: Record<string, string>,\n action: NavigateAction = 'push',\n ): void {\n assertBrowser('navigateTo()')\n this.sendCommand('NAVIGATE', { route, routeParams, action })\n }\n\n /** Refreshes the host's current route (re-fetches its server data). Fire-and-forget. */\n refresh(): void {\n assertBrowser('refresh()')\n this.sendCommand('NAVIGATE', { action: 'refresh' })\n }\n\n /**\n * Commands targeting the host's UI chrome. All fire-and-forget.\n *\n * @example\n * ```ts\n * bridge.ui.setSideNav({ collapsed: true })\n * bridge.ui.switchSubsidiary(42)\n * ```\n */\n readonly ui = {\n /** Collapse or expand the host's side navigation. */\n setSideNav: (payload: SetSideNavPayload): void => {\n assertBrowser('ui.setSideNav()')\n this.sendCommand('SET_SIDE_NAV', payload)\n },\n /** Switch the host to a different subsidiary. */\n switchSubsidiary: (subsidiaryId: number): void => {\n assertBrowser('ui.switchSubsidiary()')\n this.sendCommand('SWITCH_SUBSIDIARY', { subsidiaryId })\n },\n }\n\n /**\n * Asks the host to invalidate cached data by path prefix and/or cache tag so\n * subsequent reads see fresh values. Awaited.\n *\n * @example\n * ```ts\n * await bridge.invalidateCache({ tags: ['SUBSIDIARIES'], paths: ['/accounting/accounts'] })\n * ```\n */\n invalidateCache(payload: InvalidateCachePayload): Promise<InvalidateResult> {\n return this.request('INVALIDATE_CACHE', payload)\n }\n\n /**\n * Captures a custom product event from inside the Vibe App, attributed to the\n * same PostHog person as the host (via the `distinctId` the host supplied at\n * connect).\n *\n * **No-op until {@link connect} has resolved with PostHog enabled by the\n * host** — if the host didn't send a `posthog` block (older host, or recording\n * disabled for this env/app), or `posthog-js` isn't installed (it is an\n * optional dependency), nothing is sent. App authors don't import `posthog-js`\n * themselves; this is the supported event surface.\n *\n * The event is sent **directly** from the iframe's own PostHog instance (only\n * the session *recording* is forwarded to the parent), so it carries the\n * iframe instance's `$session_id` rather than the host's — events tie to the\n * same person, but cross-boundary event↔replay timeline correlation is a known\n * limitation.\n *\n * @param event Event name. Namespacing app events (e.g. `'vibe:<slug>:<action>'`)\n * keeps them filterable from the host's own events.\n * @param properties Optional event properties.\n * @example\n * ```ts\n * bridge.track('vibe:fixed-assets:report_exported', { format: 'csv', rows: 128 })\n * ```\n */\n track(event: string, properties?: Record<string, unknown>): void {\n assertBrowser('track()')\n if (!this.posthogInitialized || !this.posthogInstance) return\n this.posthogInstance.capture(event, properties)\n }\n\n /**\n * Tears down the bridge: stops the connect handshake, removes the message\n * listener, restores patched history methods, and rejects any in-flight calls\n * with a `'DESTROYED'` error. **Idempotent and safe on the server** — calling\n * it when {@link connect}/{@link attach} never ran (or where there is no\n * `window`) is a no-op, so it is safe as a React effect cleanup.\n */\n destroy(): void {\n this.teardownNavigationTracking()\n // Reject an in-flight connect() so awaiting it fails fast with a coded error\n // instead of hanging forever — stopConnectPolling() clears the retry/timeout\n // that would otherwise have been the only thing left to settle the promise.\n // (rejectConnect runs its own stopConnectPolling + state reset.)\n this.rejectConnect?.(new BridgeError('DESTROYED', 'Bridge destroyed'))\n this.stopConnectPolling()\n if (this.attached && typeof window !== 'undefined') {\n window.removeEventListener('message', this.boundHandleMessage)\n }\n this.attached = false\n for (const pending of this.pendingRequests.values()) {\n pending.reject(new BridgeError('DESTROYED', 'Bridge destroyed'))\n }\n this.pendingRequests.clear()\n this.context = null\n // Make track() a no-op after teardown. We deliberately don't call\n // posthog.reset() — that would clear the person/session and could disrupt an\n // in-flight recording across a remount; a fresh bridge re-inits cleanly.\n this.posthogInitialized = false\n this.posthogInstance = null\n this.posthogIniting = false\n this.connectPromise = null\n this.onContextReceived = null\n this.rejectConnect = null\n this.contextChangeCallback = null\n this.authChangeCallback = null\n this.subrouteCallback = null\n this.lastReportedSubroute = null\n }\n\n private stopConnectPolling(): void {\n if (this.connectPollInterval !== null) {\n clearInterval(this.connectPollInterval)\n this.connectPollInterval = null\n }\n if (this.connectTimeout !== null) {\n clearTimeout(this.connectTimeout)\n this.connectTimeout = null\n }\n }\n\n private warnPosthogUnavailable(): void {\n if (this.posthogUnavailableWarned) return\n this.posthogUnavailableWarned = true\n console.warn(\n '[vibe-bridge] The host enabled session recording but `posthog-js` is not ' +\n 'installed (it is an optional dependency). Recording and track() are disabled. ' +\n 'Run `npm i posthog-js` to enable them.',\n )\n }\n\n /**\n * Initializes PostHog session recording + analytics from the host-supplied\n * config carried by a one-time `POSTHOG_PUSH`, **only when the host opted in**\n * (`config.enabled`).\n *\n * `posthog-js` is an **optional dependency**, loaded lazily via `await\n * import('posthog-js')` the first time recording is enabled — so it stays out\n * of the import graph (and out of any server bundle) for apps that never\n * record. If it isn't installed, this warns once and no-ops (never throws).\n *\n * The host is the single source of truth: when it sends no `POSTHOG_PUSH`\n * (recording disabled for this env/app) or `enabled: false`, this does\n * nothing. Cross-origin replay needs `recordCrossOriginIframes` on both sides\n * so the parent receives the iframe's rrweb frames into one stitched recording,\n * and `identify()` ties the iframe's recording + events to the same person as\n * the host. Idempotent (the `posthogInitialized` guard) and wrapped in\n * try/catch so a duplicate push or a PostHog failure is harmless.\n */\n private async initPostHog(config: PostHogContext): Promise<void> {\n if (!config.enabled) return\n // Serialize: bail if recording is already live OR an init is already in\n // flight. Set synchronously (before the await below) so a second concurrent\n // POSTHOG_PUSH can't slip past this guard and run a second `posthog.init()`.\n if (this.posthogInitialized || this.posthogIniting) return\n if (typeof window === 'undefined') return\n // Defensive: a misconfigured host (enabled but blank token/host/person)\n // should be treated as \"off\" rather than wiring up a broken recorder.\n if (!config.token || !config.apiHost || !config.distinctId) {\n console.warn(\n '[vibe-bridge] PostHog enabled but token/apiHost/distinctId missing — skipping init.',\n )\n return\n }\n\n this.posthogIniting = true\n try {\n let posthog: PostHogLike | null\n try {\n posthog = resolvePosthog(await import('posthog-js'))\n } catch {\n // Optional dependency not installed — recording is simply unavailable.\n this.warnPosthogUnavailable()\n return\n }\n if (!posthog) {\n this.warnPosthogUnavailable()\n return\n }\n // Bail if the bridge was torn down while the dynamic import was in flight\n // (destroy() clears `attached`) — otherwise we'd start a recording and\n // re-arm track() on an already-destroyed bridge.\n if (!this.attached) return\n\n posthog.init(config.token, {\n api_host: config.apiHost, // absolute ingestion host, NOT a relative /ingest proxy\n person_profiles: 'identified_only',\n capture_pageview: false, // the host owns pageviews; don't double-count\n autocapture: false, // opt-in events only, via track()\n // Seed the host's session id so track() events share the host's\n // $session_id and line up with the stitched replay. Replay stitching\n // itself does not depend on this (recordCrossOriginIframes handles it).\n ...(config.sessionId ? { bootstrap: { sessionID: config.sessionId } } : {}),\n session_recording: {\n recordCrossOriginIframes: true, // REQUIRED so the parent receives our rrweb frames\n // Mirror nom-ui's posture (PostHogProvider.tsx): unmask inputs for\n // richer insight, but keep password fields masked.\n maskAllInputs: false,\n maskInputOptions: { password: true },\n },\n })\n // Link the iframe's recording + events to the SAME PostHog person as the host.\n posthog.identify(config.distinctId)\n this.posthogInstance = posthog\n this.posthogInitialized = true\n console.log('[vibe-bridge] PostHog session recording initialized')\n } catch (err) {\n // Recording is best-effort — a PostHog failure must never break connect().\n console.warn('[vibe-bridge] PostHog init failed — continuing without recording.', err)\n } finally {\n this.posthogIniting = false\n }\n }\n\n /**\n * Monkey-patches `history.pushState` and `history.replaceState` to\n * auto-detect SPA navigation and report it to the host. Called after\n * connect() resolves (so `window`/`history` are guaranteed present).\n */\n private setupNavigationTracking(): void {\n if (this.origPushState) return\n\n this.origPushState = history.pushState.bind(history)\n this.origReplaceState = history.replaceState.bind(history)\n\n const origPush = this.origPushState\n const origReplace = this.origReplaceState\n\n history.pushState = (...args: Parameters<typeof history.pushState>): void => {\n origPush(...args)\n this.reportCurrentSubroute(false)\n }\n\n history.replaceState = (...args: Parameters<typeof history.replaceState>): void => {\n origReplace(...args)\n this.reportCurrentSubroute(true)\n }\n\n this.popstateHandler = (): void => this.reportCurrentSubroute(true)\n window.addEventListener('popstate', this.popstateHandler)\n }\n\n private teardownNavigationTracking(): void {\n if (this.origPushState) {\n history.pushState = this.origPushState\n this.origPushState = null\n }\n if (this.origReplaceState) {\n history.replaceState = this.origReplaceState\n this.origReplaceState = null\n }\n if (this.popstateHandler) {\n window.removeEventListener('popstate', this.popstateHandler)\n this.popstateHandler = null\n }\n }\n\n /** Runs `fn` while suppressing subroute auto-reporting to prevent echo loops. */\n private withSubrouteSuppressed(fn: () => void): void {\n this.suppressSubrouteReport = true\n try {\n fn()\n } finally {\n this.suppressSubrouteReport = false\n }\n }\n\n private reportCurrentSubroute(replace: boolean): void {\n if (this.suppressSubrouteReport) return\n // Normalize like the explicit reportSubroute() path so what we record in\n // lastReportedSubroute matches what the host (which also guards) accepts —\n // otherwise URL sync / duplicate detection can drift.\n const subroute = normalizeSubroute(window.location.pathname + window.location.search)\n if (subroute === null) return\n if (subroute === this.lastReportedSubroute) return\n this.lastReportedSubroute = subroute\n this.sendCommand('REPORT_SUBROUTE', { subroute, replace })\n }\n\n private sendCommand<K extends keyof CommandRegistry>(type: K, payload: CommandRegistry[K]): void {\n this.ensureAttached()\n this.postToParent({\n __protocol: PROTOCOL_ID,\n __version: PROTOCOL_VERSION,\n kind: 'command',\n type,\n payload,\n })\n }\n\n /**\n * Low-level typed request for **any** operation in {@link RequestRegistry}.\n * The named methods (e.g. {@link VibeAppBridge.getChartOfAccounts}) wrap this;\n * use it directly for operations without a named method, or to pass an\n * `onProgress` callback. `type` autocompletes to every operation name and\n * narrows `payload`/return to that operation's types.\n *\n * @throws Rejects with `BridgeError` code `'SERVER_ENVIRONMENT'` if called\n * where there is no `window`.\n * @example\n * ```ts\n * const accounts = await bridge.request('GET_ACCOUNTS', { query: { account_ids: ['acc-1'] } })\n * ```\n */\n request<K extends keyof RequestRegistry>(\n type: K,\n payload: RequestRegistry[K]['payload'],\n onProgress?: (payload: unknown) => void,\n ): Promise<RequestRegistry[K]['data']> {\n if (typeof window === 'undefined') {\n return Promise.reject(serverEnvError(`request(${String(type)})`))\n }\n this.ensureAttached()\n return new Promise((resolve, reject) => {\n const requestId = crypto.randomUUID()\n\n const timer = setTimeout(\n () => {\n this.pendingRequests.delete(requestId)\n reject(new BridgeError('TIMEOUT', `Vibe bridge request timed out: ${type}`))\n },\n resolveRequestTimeout(type, this.requestTimeout),\n )\n\n this.pendingRequests.set(requestId, {\n resolve: (data) => {\n clearTimeout(timer)\n resolve(data as RequestRegistry[K]['data'])\n },\n reject: (error) => {\n clearTimeout(timer)\n reject(error)\n },\n onProgress,\n })\n\n const message: WireRequestMessage<K> = {\n __protocol: PROTOCOL_ID,\n __version: PROTOCOL_VERSION,\n kind: 'request',\n type,\n requestId,\n payload,\n }\n\n this.postToParent(message)\n })\n }\n\n /**\n * Posts to the embedding host. No-op when no concrete target origin could be\n * resolved (a config/embedding error) — `connect()` rejects fast in that case\n * so calls never silently hang waiting on a timeout.\n */\n private postToParent(message: unknown): void {\n if (this.targetOrigin === null) return\n window.parent.postMessage(message, this.targetOrigin)\n }\n\n private handleMessage(event: MessageEvent): void {\n if (!this.isTrustedOrigin(event.origin)) return\n if (!isBridgeMessage(event.data)) return\n this.kindHandlers[event.data.kind]?.(event.data)\n }\n\n private handleResponse(msg: ResponseMessage): void {\n const pending = this.pendingRequests.get(msg.requestId)\n if (!pending) return\n this.pendingRequests.delete(msg.requestId)\n\n if (msg.ok) {\n pending.resolve(msg.data)\n } else if (msg.status !== undefined) {\n // A failed Nominal API call — rehydrate as HttpBridgeError so callers can\n // branch on `err.status` (e.g. `404`).\n pending.reject(new HttpBridgeError(msg.status, msg.error))\n } else if (msg.code) {\n // Other coded host errors (e.g. `'RATE_LIMITED'`, `'FILE_TOO_LARGE'`) —\n // rehydrate as BridgeError so `catch` blocks branch on `error.code`.\n pending.reject(new BridgeError(msg.code, msg.error))\n } else {\n // No code — fall back to a plain Error.\n pending.reject(new Error(msg.error))\n }\n }\n\n private handleProgress(msg: ProgressMessage): void {\n const pending = this.pendingRequests.get(msg.requestId)\n pending?.onProgress?.(msg.payload)\n }\n}\n"],"mappings":"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","names":["actual"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../../protocol-types/dist/index.js","../package.json","../src/version.ts","../src/data-methods.ts","../src/timeouts.ts","../src/VibeAppBridge.ts"],"sourcesContent":["/**\n * @packageDocumentation\n * Iframe-side SDK for **Nominal Vibe Apps** — standalone web apps (typically\n * built with Lovable) embedded in the Nominal platform via a cross-origin\n * `<iframe>`. {@link VibeAppBridge} connects your app to its Nominal host over a\n * typed `postMessage` protocol: read Nominal data, submit Close-Management task\n * outputs, upload files, and keep deep-link routing in sync.\n *\n * ## Safe to import from anywhere\n *\n * This package has a clean server/client boundary, so `import { VibeAppBridge }`\n * (and the error classes and types) is safe from **any** file — an SSR entry, a\n * React Server Component, a Cloudflare Worker, a shared util, or a client\n * component:\n *\n * - **Importing has zero side effects** and **constructing is pure** — the\n * constructor stores options and touches no browser API.\n * - The browser is only required when a **method actually runs**. Calling one\n * outside a browser throws a `BridgeError` with code `'SERVER_ENVIRONMENT'`.\n * - RSC / Worker / edge runtimes resolve (via the `react-server` / `worker` /\n * `workerd` / `edge-light` / `deno` export conditions) to a server-safe stub,\n * so a Server Component can reference the bridge without executing anything.\n * Plain Node (and jsdom/happy-dom test runners) get the real, self-guarding\n * build, so component tests run against a real `window`.\n * - `posthog-js` is an **optional dependency**, loaded lazily only when the host\n * enables session recording — never in a server bundle.\n *\n * You therefore do **not** need `createClientOnlyFn`, dynamic `import()`\n * wrappers, or `typeof window` guards around construction. Construct at the top\n * of a client component and `connect()` in an effect. See the SSR guide in the\n * README and `docs/getting-started.md`.\n *\n * Quickstart — call {@link VibeAppBridge.connect | connect()} once on init,\n * then call any data method. `connect()` must resolve before any other call.\n *\n * @example\n * ```ts\n * import { VibeAppBridge } from '@nominalso/vibe-bridge'\n *\n * const bridge = new VibeAppBridge({\n * // Optional — omit to auto-detect the embedding Nominal origin.\n * parentOrigin: import.meta.env.VITE_PARENT_ORIGIN,\n * })\n *\n * // 1. Connect — resolves with the tenant/user context. Call this first.\n * const ctx = await bridge.connect()\n * console.log(ctx.tenant, ctx.subsidiaryId, ctx.user.displayName)\n *\n * // 2. Read Nominal data (any of the ~46 named operations).\n * const accounts = await bridge.getChartOfAccounts({ path: { subsidiary_id: ctx.subsidiaryId } })\n *\n * // 3. Upload a file through the host (returns once Nominal has stored it).\n * const uploaded = await bridge.upload(file, { entityType: 'JOURNAL_ENTRY', entityId: '123' })\n *\n * // 4. Submit a Close-Management task output (the only write path into Nominal).\n * await bridge.postTaskOutput({ path: { task_instance_id: 'task-1' }, body: {} })\n *\n * // 5. Tear down on unmount.\n * bridge.destroy()\n * ```\n */\n\n// This module exists to emit the canonical type surface (`dist/index.d.ts`) that\n// both the browser and server builds share. At runtime the package resolves to\n// `index.browser.js` (browser) or `index.server.js` (server) via export\n// conditions — never to this file — so the two builds present one identical API.\nexport * from './index.browser'\n","// src/subroute.ts\nfunction normalizeSubroute(subroute) {\n const normalized = subroute.startsWith(\"/\") ? subroute : `/${subroute}`;\n const path = normalized.split(/[?#]/)[0];\n let decoded = path;\n let prev;\n do {\n prev = decoded;\n decoded = decoded.replace(/%25/gi, \"%\").replace(/%2e/gi, \".\").replace(/%2f/gi, \"/\");\n } while (decoded !== prev);\n if (decoded.split(\"/\").some((segment) => segment === \"..\")) return null;\n return normalized;\n}\n\n// src/protocol.ts\nvar PROTOCOL_ID = \"nominal-vibe-bridge\";\nvar PROTOCOL_VERSION = 2;\nvar BRIDGE_KINDS = [\"request\", \"response\", \"push\", \"command\", \"progress\"];\nvar CORRELATED_KINDS = [\"request\", \"response\", \"progress\"];\nvar BRIDGE_KINDS_SET = new Set(BRIDGE_KINDS);\nvar CORRELATED_KINDS_SET = new Set(CORRELATED_KINDS);\nfunction isBridgeMessage(data) {\n if (typeof data !== \"object\" || data === null) return false;\n const d = data;\n if (d.__protocol !== PROTOCOL_ID) return false;\n if (d.__version !== PROTOCOL_VERSION) return false;\n if (typeof d.kind !== \"string\" || !BRIDGE_KINDS_SET.has(d.kind)) return false;\n if (typeof d.type !== \"string\") return false;\n if (CORRELATED_KINDS_SET.has(d.kind) && typeof d.requestId !== \"string\") return false;\n return true;\n}\n\n// src/errors.ts\nvar BRIDGE_ERROR_BRAND = /* @__PURE__ */ Symbol.for(\"@nominalso/vibe-bridge:BridgeError\");\nvar HTTP_BRIDGE_ERROR_BRAND = /* @__PURE__ */ Symbol.for(\"@nominalso/vibe-bridge:HttpBridgeError\");\nvar BridgeError = class extends Error {\n constructor(code, message) {\n super(message);\n this.code = code;\n this.name = \"BridgeError\";\n }\n /**\n * Cross-realm-safe type guard. Prefer this over `instanceof BridgeError` when\n * an error may have been thrown by a differently-built copy of the SDK (e.g.\n * server bundle vs client bundle) — it matches on a process-global brand\n * rather than class identity.\n */\n static isBridgeError(err) {\n return typeof err === \"object\" && err !== null && err[BRIDGE_ERROR_BRAND] === true;\n }\n};\nObject.defineProperty(BridgeError.prototype, BRIDGE_ERROR_BRAND, {\n value: true,\n enumerable: false\n});\nvar HttpBridgeError = class extends BridgeError {\n constructor(status, message) {\n super(\"REQUEST_FAILED\", message);\n this.status = status;\n this.name = \"HttpBridgeError\";\n }\n /**\n * Cross-realm-safe type guard (see {@link BridgeError.isBridgeError}). Returns\n * `true` only for `HttpBridgeError` instances, not plain `BridgeError`s.\n */\n static isHttpBridgeError(err) {\n return typeof err === \"object\" && err !== null && err[HTTP_BRIDGE_ERROR_BRAND] === true;\n }\n};\nObject.defineProperty(HttpBridgeError.prototype, HTTP_BRIDGE_ERROR_BRAND, {\n value: true,\n enumerable: false\n});\n\n// src/origins.ts\nfunction isOriginPattern(entry) {\n return entry.includes(\"*\");\n}\nvar patternCache = /* @__PURE__ */ new Map();\nfunction patternToRegExp(pattern) {\n const cached = patternCache.get(pattern);\n if (cached) return cached;\n const escaped = pattern.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const body = escaped.replace(/\\\\\\*/g, \"[^./:@?#\\\\s]+\");\n const compiled = new RegExp(`^${body}$`);\n patternCache.set(pattern, compiled);\n return compiled;\n}\nfunction matchesOrigin(origin, entry) {\n if (!isOriginPattern(entry)) return origin === entry;\n return patternToRegExp(entry).test(origin);\n}\nfunction isOriginAllowed(origin, allowlist, { allowPatterns }) {\n for (const entry of allowlist) {\n if (isOriginPattern(entry)) {\n if (allowPatterns && matchesOrigin(origin, entry)) return true;\n } else if (origin === entry) {\n return true;\n }\n }\n return false;\n}\nexport {\n BridgeError,\n HttpBridgeError,\n PROTOCOL_ID,\n PROTOCOL_VERSION,\n isBridgeMessage,\n isOriginAllowed,\n isOriginPattern,\n matchesOrigin,\n normalizeSubroute\n};\n","{\n \"name\": \"@nominalso/vibe-bridge\",\n \"version\": \"0.8.0\",\n \"description\": \"Iframe-side SDK for building Nominal Vibe Apps — connects an embedded app to its Nominal host over a typed postMessage bridge (context, data fetch, file upload, subroute deep-linking). Safe to import from SSR, React Server Components, and edge/Worker runtimes.\",\n \"license\": \"UNLICENSED\",\n \"homepage\": \"https://github.com/nominalso/vibe-apps-sdk#readme\",\n \"bugs\": {\n \"url\": \"https://github.com/nominalso/vibe-apps-sdk/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"github:nominalso/vibe-apps-sdk\",\n \"directory\": \"packages/bridge\"\n },\n \"type\": \"module\",\n \"sideEffects\": false,\n \"types\": \"./dist/index.d.ts\",\n \"main\": \"./dist/index.browser.cjs\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"react-server\": \"./dist/index.server.js\",\n \"workerd\": \"./dist/index.server.js\",\n \"worker\": \"./dist/index.server.js\",\n \"edge-light\": \"./dist/index.server.js\",\n \"deno\": \"./dist/index.server.js\",\n \"browser\": {\n \"import\": \"./dist/index.browser.js\",\n \"require\": \"./dist/index.browser.cjs\"\n },\n \"default\": {\n \"import\": \"./dist/index.browser.js\",\n \"require\": \"./dist/index.browser.cjs\"\n }\n },\n \"./server\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.server.js\",\n \"require\": \"./dist/index.server.cjs\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\",\n \"docs\",\n \"AGENTS.md\",\n \"llms.txt\"\n ],\n \"publishConfig\": {\n \"registry\": \"https://registry.npmjs.org/\",\n \"access\": \"public\"\n },\n \"scripts\": {\n \"clean\": \"rm -rf dist node_modules\",\n \"build\": \"rm -rf dist && tsup\",\n \"lint\": \"eslint src\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\"\n },\n \"optionalDependencies\": {\n \"posthog-js\": \"^1.393.5\"\n },\n \"devDependencies\": {\n \"@nominalso/vibe-api-types\": \"workspace:*\",\n \"@nominalso/vibe-protocol-types\": \"workspace:*\"\n }\n}\n","import { version } from '../package.json'\n\n/**\n * Published version of this package (`@nominalso/vibe-bridge`), sent to the host\n * in the `CONNECT` handshake. Import-safe from any environment.\n */\nexport const BRIDGE_VERSION: string = version\n","import type { RequestRegistry } from '@nominalso/vibe-protocol-types'\n\nexport interface UploadOptions {\n /** Domain entity the file attaches to, e.g. `'JOURNAL_ENTRY'`. */\n entityType: string\n /** Id of the entity the file attaches to, when applicable. */\n entityId?: string | number\n /** Called with incremental progress (`0`–`100`) while the upload streams. */\n onProgress?: (p: RequestRegistry['UPLOAD_FILE']['progress']) => void\n}\n\n/**\n * The typed Nominal data methods (~46) plus {@link BridgeDataMethods.upload},\n * factored onto a base class so {@link VibeAppBridge} stays focused on\n * connection/transport. Each method is a thin typed wrapper over `request()`;\n * `VibeAppBridge` provides the concrete `request` implementation.\n */\nexport abstract class BridgeDataMethods {\n /**\n * Low-level typed request for **any** operation in {@link RequestRegistry} —\n * implemented by {@link VibeAppBridge}. The named methods below wrap this.\n */\n abstract request<K extends keyof RequestRegistry>(\n type: K,\n payload: RequestRegistry[K]['payload'],\n onProgress?: (payload: unknown) => void,\n ): Promise<RequestRegistry[K]['data']>\n\n // ---------------------------------------------------------------------------\n // Operations — Accounting: chart of accounts\n //\n // Each method is a typed wrapper over `request('<OP>', payload)`. The payload\n // and return types come straight from the Nominal API (`RequestRegistry`).\n // For any operation without a named method, call `request('<OP>', payload)`.\n // ---------------------------------------------------------------------------\n\n /**\n * Fetch the flat chart of accounts for a subsidiary.\n *\n * @example\n * ```ts\n * const ctx = await bridge.connect()\n * const accounts = await bridge.getChartOfAccounts({\n * path: { subsidiary_id: ctx.subsidiaryId },\n * })\n * ```\n */\n getChartOfAccounts(\n payload: RequestRegistry['GET_CHART_OF_ACCOUNTS']['payload'],\n ): Promise<RequestRegistry['GET_CHART_OF_ACCOUNTS']['data']> {\n return this.request('GET_CHART_OF_ACCOUNTS', payload)\n }\n\n /** Fetch the chart of accounts as a hierarchical tree for a subsidiary. */\n getCoaTree(\n payload: RequestRegistry['GET_COA_TREE']['payload'],\n ): Promise<RequestRegistry['GET_COA_TREE']['data']> {\n return this.request('GET_COA_TREE', payload)\n }\n\n /** Fetch a simplified flat chart of accounts for a subsidiary. */\n getCoaFlatSimple(\n payload: RequestRegistry['GET_COA_FLAT_SIMPLE']['payload'],\n ): Promise<RequestRegistry['GET_COA_FLAT_SIMPLE']['data']> {\n return this.request('GET_COA_FLAT_SIMPLE', payload)\n }\n\n /** Fetch the flat chart of accounts grouped by account group. */\n getCoaGrouped(\n payload: RequestRegistry['GET_COA_GROUPED']['payload'],\n ): Promise<RequestRegistry['GET_COA_GROUPED']['data']> {\n return this.request('GET_COA_GROUPED', payload)\n }\n\n /** Fetch a single chart-of-accounts account by id within a subsidiary. */\n getCoaAccount(\n payload: RequestRegistry['GET_COA_ACCOUNT']['payload'],\n ): Promise<RequestRegistry['GET_COA_ACCOUNT']['data']> {\n return this.request('GET_COA_ACCOUNT', payload)\n }\n\n /** List the currencies available to a subsidiary's chart of accounts. */\n getSubsidiaryAvailableCurrencies(\n payload: RequestRegistry['GET_SUBSIDIARY_AVAILABLE_CURRENCIES']['payload'],\n ): Promise<RequestRegistry['GET_SUBSIDIARY_AVAILABLE_CURRENCIES']['data']> {\n return this.request('GET_SUBSIDIARY_AVAILABLE_CURRENCIES', payload)\n }\n\n /** Fetch accounts at the tenant level. */\n getAccounts(\n payload: RequestRegistry['GET_ACCOUNTS']['payload'],\n ): Promise<RequestRegistry['GET_ACCOUNTS']['data']> {\n return this.request('GET_ACCOUNTS', payload)\n }\n\n /** Fetch a single account by id. */\n getAccount(\n payload: RequestRegistry['GET_ACCOUNT']['payload'],\n ): Promise<RequestRegistry['GET_ACCOUNT']['data']> {\n return this.request('GET_ACCOUNT', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Accounting: exchange rates\n // ---------------------------------------------------------------------------\n\n /** Fetch currency conversion rates for a currency. */\n getConversionRates(\n payload: RequestRegistry['GET_CONVERSION_RATES']['payload'],\n ): Promise<RequestRegistry['GET_CONVERSION_RATES']['data']> {\n return this.request('GET_CONVERSION_RATES', payload)\n }\n\n /** Fetch the effective consolidation exchange rate. */\n getEffectiveExchangeRate(\n payload: RequestRegistry['GET_EFFECTIVE_EXCHANGE_RATE']['payload'],\n ): Promise<RequestRegistry['GET_EFFECTIVE_EXCHANGE_RATE']['data']> {\n return this.request('GET_EFFECTIVE_EXCHANGE_RATE', payload)\n }\n\n /** Fetch the exchange-rate period covering a given input date. */\n getExchangeRateByDate(\n payload: RequestRegistry['GET_EXCHANGE_RATE_BY_DATE']['payload'],\n ): Promise<RequestRegistry['GET_EXCHANGE_RATE_BY_DATE']['data']> {\n return this.request('GET_EXCHANGE_RATE_BY_DATE', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Accounting: dimensions\n // ---------------------------------------------------------------------------\n\n /** List accounting dimensions. */\n getDimensions(\n payload: RequestRegistry['GET_DIMENSIONS']['payload'],\n ): Promise<RequestRegistry['GET_DIMENSIONS']['data']> {\n return this.request('GET_DIMENSIONS', payload)\n }\n\n /** List values for accounting dimensions. */\n getDimensionValues(\n payload: RequestRegistry['GET_DIMENSION_VALUES']['payload'],\n ): Promise<RequestRegistry['GET_DIMENSION_VALUES']['data']> {\n return this.request('GET_DIMENSION_VALUES', payload)\n }\n\n /** List dimension values in hierarchical form. */\n getDimensionValuesHierarchical(\n payload: RequestRegistry['GET_DIMENSION_VALUES_HIERARCHICAL']['payload'],\n ): Promise<RequestRegistry['GET_DIMENSION_VALUES_HIERARCHICAL']['data']> {\n return this.request('GET_DIMENSION_VALUES_HIERARCHICAL', payload)\n }\n\n /** List account assignments for a dimension/account pair. */\n getDimensionAccountAssignments(\n payload: RequestRegistry['GET_DIMENSION_ACCOUNT_ASSIGNMENTS']['payload'],\n ): Promise<RequestRegistry['GET_DIMENSION_ACCOUNT_ASSIGNMENTS']['data']> {\n return this.request('GET_DIMENSION_ACCOUNT_ASSIGNMENTS', payload)\n }\n\n /** Get dimension-value balances for a dimension over a date window. */\n getDimensionBalance(\n payload: RequestRegistry['GET_DIMENSION_BALANCE']['payload'],\n ): Promise<RequestRegistry['GET_DIMENSION_BALANCE']['data']> {\n return this.request('GET_DIMENSION_BALANCE', payload)\n }\n\n /** Add a new value under an existing dimension. */\n addDimensionValue(\n payload: RequestRegistry['ADD_DIMENSION_VALUE']['payload'],\n ): Promise<RequestRegistry['ADD_DIMENSION_VALUE']['data']> {\n return this.request('ADD_DIMENSION_VALUE', payload)\n }\n\n /** Set or override the dimension value on a single journal-entry line. */\n setLineDimensionValue(\n payload: RequestRegistry['SET_LINE_DIMENSION_VALUE']['payload'],\n ): Promise<RequestRegistry['SET_LINE_DIMENSION_VALUE']['data']> {\n return this.request('SET_LINE_DIMENSION_VALUE', payload)\n }\n\n /** Bulk-assign a dimension value to many journal-entry lines at once. */\n bulkSetLineDimensionValue(\n payload: RequestRegistry['BULK_SET_LINE_DIMENSION_VALUE']['payload'],\n ): Promise<RequestRegistry['BULK_SET_LINE_DIMENSION_VALUE']['data']> {\n return this.request('BULK_SET_LINE_DIMENSION_VALUE', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Accounting: journal entries\n // ---------------------------------------------------------------------------\n\n /**\n * Fetch journal entries for a subsidiary, optionally filtered by date range.\n *\n * @example\n * ```ts\n * const entries = await bridge.getJournalEntries({\n * path: { subsidiary_id: ctx.subsidiaryId },\n * query: { from_date: '2026-01-01', to_date: '2026-03-31' },\n * })\n * ```\n */\n getJournalEntries(\n payload: RequestRegistry['GET_JOURNAL_ENTRIES']['payload'],\n ): Promise<RequestRegistry['GET_JOURNAL_ENTRIES']['data']> {\n return this.request('GET_JOURNAL_ENTRIES', payload)\n }\n\n /** Fetch journal entry lines for a subsidiary. */\n getJournalLines(\n payload: RequestRegistry['GET_JOURNAL_LINES']['payload'],\n ): Promise<RequestRegistry['GET_JOURNAL_LINES']['data']> {\n return this.request('GET_JOURNAL_LINES', payload)\n }\n\n /** Fetch a single journal entry by id within a subsidiary. */\n getJournalEntry(\n payload: RequestRegistry['GET_JOURNAL_ENTRY']['payload'],\n ): Promise<RequestRegistry['GET_JOURNAL_ENTRY']['data']> {\n return this.request('GET_JOURNAL_ENTRY', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Activity: period instances\n // ---------------------------------------------------------------------------\n\n /** List accounting period instances. */\n getPeriods(\n payload: RequestRegistry['GET_PERIODS']['payload'],\n ): Promise<RequestRegistry['GET_PERIODS']['data']> {\n return this.request('GET_PERIODS', payload)\n }\n\n /** Fetch a single period instance by id. */\n getPeriodInstance(\n payload: RequestRegistry['GET_PERIOD_INSTANCE']['payload'],\n ): Promise<RequestRegistry['GET_PERIOD_INSTANCE']['data']> {\n return this.request('GET_PERIOD_INSTANCE', payload)\n }\n\n /** Fetch a period instance by its display slug (e.g. `\"mar-2026\"`). */\n getPeriodInstanceBySlug(\n payload: RequestRegistry['GET_PERIOD_INSTANCE_BY_SLUG']['payload'],\n ): Promise<RequestRegistry['GET_PERIOD_INSTANCE_BY_SLUG']['data']> {\n return this.request('GET_PERIOD_INSTANCE_BY_SLUG', payload)\n }\n\n /** Fetch the close-progress breakdown for a period (by slug). */\n getPeriodProgressBreakdown(\n payload: RequestRegistry['GET_PERIOD_PROGRESS_BREAKDOWN']['payload'],\n ): Promise<RequestRegistry['GET_PERIOD_PROGRESS_BREAKDOWN']['data']> {\n return this.request('GET_PERIOD_PROGRESS_BREAKDOWN', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Activity: activity definitions\n // ---------------------------------------------------------------------------\n\n /** List activity definitions. */\n getActivityDefinitions(\n payload: RequestRegistry['GET_ACTIVITY_DEFINITIONS']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_DEFINITIONS']['data']> {\n return this.request('GET_ACTIVITY_DEFINITIONS', payload)\n }\n\n /** Fetch a single activity definition by id. */\n getActivityDefinition(\n payload: RequestRegistry['GET_ACTIVITY_DEFINITION']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_DEFINITION']['data']> {\n return this.request('GET_ACTIVITY_DEFINITION', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Activity: activity instances\n // ---------------------------------------------------------------------------\n\n /** List activity instances. */\n getActivityInstances(\n payload: RequestRegistry['GET_ACTIVITY_INSTANCES']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_INSTANCES']['data']> {\n return this.request('GET_ACTIVITY_INSTANCES', payload)\n }\n\n /** Fetch a single activity instance by id. */\n getActivityInstance(\n payload: RequestRegistry['GET_ACTIVITY_INSTANCE']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_INSTANCE']['data']> {\n return this.request('GET_ACTIVITY_INSTANCE', payload)\n }\n\n /** Fetch an activity instance for a given period + activity definition. */\n getActivityInstanceByPeriod(\n payload: RequestRegistry['GET_ACTIVITY_INSTANCE_BY_PERIOD']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_INSTANCE_BY_PERIOD']['data']> {\n return this.request('GET_ACTIVITY_INSTANCE_BY_PERIOD', payload)\n }\n\n /** List task instances for an activity instance. */\n getActivityInstanceTasks(\n payload: RequestRegistry['GET_ACTIVITY_INSTANCE_TASKS']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_INSTANCE_TASKS']['data']> {\n return this.request('GET_ACTIVITY_INSTANCE_TASKS', payload)\n }\n\n /** List task instances for an activity in a given period. */\n getActivityPeriodTasks(\n payload: RequestRegistry['GET_ACTIVITY_PERIOD_TASKS']['payload'],\n ): Promise<RequestRegistry['GET_ACTIVITY_PERIOD_TASKS']['data']> {\n return this.request('GET_ACTIVITY_PERIOD_TASKS', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Activity: task definitions\n // ---------------------------------------------------------------------------\n\n /** List task definitions. */\n getTaskDefinitions(\n payload: RequestRegistry['GET_TASK_DEFINITIONS']['payload'],\n ): Promise<RequestRegistry['GET_TASK_DEFINITIONS']['data']> {\n return this.request('GET_TASK_DEFINITIONS', payload)\n }\n\n /** Fetch a single task definition by id. */\n getTaskDefinition(\n payload: RequestRegistry['GET_TASK_DEFINITION']['payload'],\n ): Promise<RequestRegistry['GET_TASK_DEFINITION']['data']> {\n return this.request('GET_TASK_DEFINITION', payload)\n }\n\n /** Create a task definition. */\n createTaskDefinition(\n payload: RequestRegistry['CREATE_TASK_DEFINITION']['payload'],\n ): Promise<RequestRegistry['CREATE_TASK_DEFINITION']['data']> {\n return this.request('CREATE_TASK_DEFINITION', payload)\n }\n\n /** Update a task definition by id. */\n updateTaskDefinition(\n payload: RequestRegistry['UPDATE_TASK_DEFINITION']['payload'],\n ): Promise<RequestRegistry['UPDATE_TASK_DEFINITION']['data']> {\n return this.request('UPDATE_TASK_DEFINITION', payload)\n }\n\n /** Query task definitions by filter. */\n getTaskDefinitionsByFilter(\n payload: RequestRegistry['GET_TASK_DEFINITIONS_BY_FILTER']['payload'],\n ): Promise<RequestRegistry['GET_TASK_DEFINITIONS_BY_FILTER']['data']> {\n return this.request('GET_TASK_DEFINITIONS_BY_FILTER', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Activity: task instances\n // ---------------------------------------------------------------------------\n\n /** List task instances. */\n getTaskInstances(\n payload: RequestRegistry['GET_TASK_INSTANCES']['payload'],\n ): Promise<RequestRegistry['GET_TASK_INSTANCES']['data']> {\n return this.request('GET_TASK_INSTANCES', payload)\n }\n\n /** Fetch a single task instance by id. */\n getTaskInstance(\n payload: RequestRegistry['GET_TASK_INSTANCE']['payload'],\n ): Promise<RequestRegistry['GET_TASK_INSTANCE']['data']> {\n return this.request('GET_TASK_INSTANCE', payload)\n }\n\n /**\n * Submit a Close-Management task output. This is the **only write path** back\n * into Nominal — Vibe Apps never write Nominal data directly.\n *\n * @example\n * ```ts\n * // `body` carries the task-specific output shape.\n * await bridge.postTaskOutput({\n * path: { task_instance_id: 'task-1' },\n * body: {},\n * })\n * ```\n */\n postTaskOutput(\n payload: RequestRegistry['POST_TASK_OUTPUT']['payload'],\n ): Promise<RequestRegistry['POST_TASK_OUTPUT']['data']> {\n return this.request('POST_TASK_OUTPUT', payload)\n }\n\n /** Query task instances by filter. */\n getTaskInstancesByFilter(\n payload: RequestRegistry['GET_TASK_INSTANCES_BY_FILTER']['payload'],\n ): Promise<RequestRegistry['GET_TASK_INSTANCES_BY_FILTER']['data']> {\n return this.request('GET_TASK_INSTANCES_BY_FILTER', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Audit trail\n // ---------------------------------------------------------------------------\n\n /** List audit-trail events. */\n getAuditEvents(\n payload: RequestRegistry['GET_AUDIT_EVENTS']['payload'],\n ): Promise<RequestRegistry['GET_AUDIT_EVENTS']['data']> {\n return this.request('GET_AUDIT_EVENTS', payload)\n }\n\n /** List audit-trail events for a specific entity. */\n getEntityAuditEvents(\n payload: RequestRegistry['GET_ENTITY_AUDIT_EVENTS']['payload'],\n ): Promise<RequestRegistry['GET_ENTITY_AUDIT_EVENTS']['data']> {\n return this.request('GET_ENTITY_AUDIT_EVENTS', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Period manager: fiscal calendars\n // ---------------------------------------------------------------------------\n\n /** List fiscal calendars for a subsidiary. */\n getFiscalCalendars(\n payload: RequestRegistry['GET_FISCAL_CALENDARS']['payload'],\n ): Promise<RequestRegistry['GET_FISCAL_CALENDARS']['data']> {\n return this.request('GET_FISCAL_CALENDARS', payload)\n }\n\n /** Fetch a single fiscal calendar by id. */\n getFiscalCalendar(\n payload: RequestRegistry['GET_FISCAL_CALENDAR']['payload'],\n ): Promise<RequestRegistry['GET_FISCAL_CALENDAR']['data']> {\n return this.request('GET_FISCAL_CALENDAR', payload)\n }\n\n // ---------------------------------------------------------------------------\n // Operations — Tenancy\n // ---------------------------------------------------------------------------\n\n /** List subsidiaries for the tenant. */\n getSubsidiaries(\n payload: RequestRegistry['GET_SUBSIDIARIES']['payload'],\n ): Promise<RequestRegistry['GET_SUBSIDIARIES']['data']> {\n return this.request('GET_SUBSIDIARIES', payload)\n }\n\n /** Fetch a single subsidiary by id. */\n getSubsidiary(\n payload: RequestRegistry['GET_SUBSIDIARY']['payload'],\n ): Promise<RequestRegistry['GET_SUBSIDIARY']['data']> {\n return this.request('GET_SUBSIDIARY', payload)\n }\n\n /** List parent currencies for a subsidiary. */\n getSubsidiaryParentCurrencies(\n payload: RequestRegistry['GET_SUBSIDIARY_PARENT_CURRENCIES']['payload'],\n ): Promise<RequestRegistry['GET_SUBSIDIARY_PARENT_CURRENCIES']['data']> {\n return this.request('GET_SUBSIDIARY_PARENT_CURRENCIES', payload)\n }\n\n /** List users for the tenant. */\n getTenantUsers(\n payload: RequestRegistry['GET_TENANT_USERS']['payload'],\n ): Promise<RequestRegistry['GET_TENANT_USERS']['data']> {\n return this.request('GET_TENANT_USERS', payload)\n }\n\n /**\n * Uploads a file through the host. Converts the `File` to an `ArrayBuffer`\n * before sending — sandboxed iframes cannot pass `File` handles across\n * windows. Resolves once Nominal has stored the file.\n *\n * @example\n * ```ts\n * const input = document.querySelector<HTMLInputElement>('#file')!\n * const file = input.files![0]\n * const result = await bridge.upload(file, {\n * entityType: 'JOURNAL_ENTRY',\n * entityId: '123',\n * onProgress: (p) => console.log(`${p.progress}%`),\n * })\n * // result.attachmentId, result.name\n * ```\n */\n async upload(\n file: File,\n options: UploadOptions,\n ): Promise<RequestRegistry['UPLOAD_FILE']['data']> {\n const buffer = await file.arrayBuffer()\n const payload: RequestRegistry['UPLOAD_FILE']['payload'] = {\n buffer,\n fileName: file.name,\n fileType: file.type,\n entityType: options.entityType,\n entityId: options.entityId,\n }\n const onProgress = options.onProgress\n ? (p: unknown): void => options.onProgress!(p as RequestRegistry['UPLOAD_FILE']['progress'])\n : undefined\n return this.request('UPLOAD_FILE', payload, onProgress)\n }\n}\n","import type { RequestRegistry } from '@nominalso/vibe-protocol-types'\n\n/** Hard ceiling (ms) for `connect()` before it rejects with a `'TIMEOUT'` error. */\nexport const CONNECT_TIMEOUT_MS = 10_000\n/** Interval (ms) between `CONNECT` handshakes while `connect()` waits for the host. */\nexport const CONNECT_POLL_MS = 500\n\n/**\n * Default per-operation request timeouts (ms), mirroring nom-ui's bridge\n * protocol (`BRIDGE_TIMEOUTS`) so apps migrating off the in-tree bridge don't\n * regress. Used when `requestTimeout` is not set on the bridge options.\n */\nexport const DEFAULT_TIMEOUTS = {\n /** Typed Nominal API reads/writes (`GET_*` / `POST_*` / `CREATE_*` / ...). */\n api: 30_000,\n /** `INVALIDATE_CACHE`. */\n invalidate: 10_000,\n /** `UPLOAD_FILE` — large payloads + presigned S3 PUT take a while. */\n upload: 120_000,\n} as const\n\n/**\n * Resolves the timeout (ms) for a given operation: the explicit `requestTimeout`\n * if set, otherwise the operation-specific default from {@link DEFAULT_TIMEOUTS}.\n */\nexport function resolveRequestTimeout(\n type: keyof RequestRegistry,\n requestTimeout?: number,\n): number {\n if (requestTimeout !== undefined) return requestTimeout\n switch (type) {\n case 'UPLOAD_FILE':\n return DEFAULT_TIMEOUTS.upload\n case 'INVALIDATE_CACHE':\n return DEFAULT_TIMEOUTS.invalidate\n default:\n return DEFAULT_TIMEOUTS.api\n }\n}\n","import {\n PROTOCOL_ID,\n PROTOCOL_VERSION,\n isBridgeMessage,\n isOriginAllowed,\n isOriginPattern,\n normalizeSubroute,\n BridgeError,\n HttpBridgeError,\n type ContextPayload,\n type AuthPayload,\n type PostHogContext,\n type BridgeKind,\n type AnyBridgeMessage,\n type RequestRegistry,\n type CommandRegistry,\n type PushRegistry,\n type ResponseMessage,\n type ProgressMessage,\n type PushMessage,\n type WireRequestMessage,\n type NavigateAction,\n type SetSideNavPayload,\n type InvalidateCachePayload,\n type InvalidateResult,\n} from '@nominalso/vibe-protocol-types'\nimport { BRIDGE_VERSION } from './version'\nimport type { VibeAppBridgeOptions } from './options'\nimport { BridgeDataMethods } from './data-methods'\nimport { CONNECT_TIMEOUT_MS, CONNECT_POLL_MS, resolveRequestTimeout } from './timeouts'\n\n/**\n * Minimal shape of the parts of `posthog-js` the bridge uses. Declared locally\n * so this module never *statically* imports `posthog-js` — the real module is\n * pulled in lazily via `await import('posthog-js')` only when the host enables\n * recording (see {@link VibeAppBridge.initPostHog}), keeping the optional\n * dependency out of the import graph and out of any server bundle.\n */\ninterface PostHogLike {\n init: (token: string, config: Record<string, unknown>) => void\n identify: (distinctId: string) => void\n capture: (event: string, properties?: Record<string, unknown>) => void\n}\n\n/**\n * `posthog-js` ships a transpiled-ESM entry (`__esModule` with the singleton\n * under `.default`). Depending on how the dynamic import's interop resolves, the\n * singleton can sit one or two `.default` levels deep. Walk down `.default`\n * (always a real export, safe to read) rather than probing `.init` on the module\n * namespace — accessing a *non-exported* name on an ESM namespace throws in some\n * loaders (e.g. Vitest), which would otherwise send us down the \"not installed\"\n * path. Returns the first object that actually carries `init`, else `null`.\n */\nfunction resolvePosthog(mod: unknown): PostHogLike | null {\n const hasInit = (o: unknown): o is PostHogLike =>\n typeof (o as PostHogLike | undefined)?.init === 'function'\n // The singleton lives under `.default` (one interop wrapper deep, sometimes\n // two). Read `.default` — always a real export — before probing `.init`, so we\n // never touch a non-exported name on the module namespace (which throws in some\n // loaders, e.g. Vitest). Fall back to the value itself for bundlers that hand\n // back the singleton directly.\n const d1 = (mod as { default?: unknown } | undefined)?.default\n if (hasInit(d1)) return d1\n const d2 = (d1 as { default?: unknown } | undefined)?.default\n if (hasInit(d2)) return d2\n if (hasInit(mod)) return mod\n return null\n}\n\n/**\n * The runtime environment guard. Every bridge method that touches the DOM (or\n * drives the postMessage transport) calls this first, so a call made where there\n * is no `window` — during SSR, inside a React Server Component, or in a Worker\n * that resolved the browser build — fails loud with a coded error instead of\n * throwing an opaque `window is not defined` or silently hanging.\n *\n * Import and construction are always safe; only *calling* a browser method here\n * is gated. In practice the exports map routes server/RSC/Worker imports to the\n * server stub, so this is belt-and-suspenders for graphs that still evaluate the\n * browser build server-side (e.g. the SSR pass of a client component).\n */\nfunction serverEnvError(method: string): BridgeError {\n return new BridgeError(\n 'SERVER_ENVIRONMENT',\n `VibeAppBridge.${method} was called outside a browser (no \\`window\\`). ` +\n `The bridge only runs in the browser — call it from a client component or ` +\n `effect, not during SSR, in a React Server Component, or in a Worker.`,\n )\n}\n\nfunction assertBrowser(method: string): void {\n if (typeof window === 'undefined') throw serverEnvError(method)\n}\n\n/**\n * Global the dev-bridge Chrome extension sets inside the Lovable editor preview\n * to expose the iframe's *real* parent origin (the Lovable editor). See\n * {@link resolveOriginPolicy}.\n */\nconst PARENT_ORIGIN_OVERRIDE_KEY = '__NOM_VIBE_PARENT_ORIGIN__'\n\n/**\n * Hosts that serve a vibe app from a throwaway *preview* URL. When the app's own\n * page is served from one of these, `parentOrigin` glob patterns are honoured;\n * on any other host (a production custom domain) patterns are ignored and only\n * exact origins match. The check keys off the iframe's *own* `location.hostname`\n * — which a page framing the app cannot change — so it is fail-closed: a\n * production build silently downgrades to strict exact-match.\n */\nconst PREVIEW_HOST_RE =\n /(?:^|\\.)(?:vercel\\.app|lovable\\.app|lovable\\.dev|lovableproject\\.com)$|^(?:localhost|127\\.0\\.0\\.1)$/\n\nfunction isPreviewSelfHost(hostname: string): boolean {\n return PREVIEW_HOST_RE.test(hostname)\n}\n\n/**\n * Best-effort discovery of the iframe's *actual* parent origin, used to pick a\n * concrete `postMessage` target when `parentOrigin` is a list/pattern (you\n * cannot post to a pattern). `ancestorOrigins` is Chromium/WebKit only; the\n * `document.referrer` fallback covers other engines but can be empty under a\n * strict `Referrer-Policy`. Returns `null` when neither is available.\n */\nfunction resolveActualParentOrigin(): string | null {\n if (typeof window === 'undefined') return null\n try {\n const ancestors = window.location.ancestorOrigins\n if (ancestors && ancestors.length > 0 && ancestors[0]) return ancestors[0]\n } catch {\n // ancestorOrigins is not implemented everywhere; fall through to referrer.\n }\n try {\n if (document.referrer) return new URL(document.referrer).origin\n } catch {\n // Malformed referrer — treat as unavailable.\n }\n return null\n}\n\n/** What the bridge needs to know about origins, derived once at attach. */\ninterface OriginPolicy {\n /** Concrete origin to `postMessage` to, or `null` if none could be resolved. */\n targetOrigin: string | null\n /** Validates an inbound `event.origin`. */\n isTrusted: (origin: string) => boolean\n}\n\n/**\n * Resolves the effective origin policy from the configured `parentOrigin`.\n *\n * Reads `window`/`document`, so it is only ever called from {@link\n * VibeAppBridge.attach} (never at module load or in the constructor).\n *\n * Priority and behaviour:\n *\n * 1. **Dev-bridge override.** When `window.__NOM_VIBE_PARENT_ORIGIN__` is set\n * (the Lovable-editor extension, which relays the protocol across tabs where\n * the real `window.parent` is the editor, not the configured host), it fully\n * replaces the configured value — exact target and exact inbound check — so\n * that flow is unchanged.\n * 2. **Omitted (no `parentOrigin`):** auto-detect the actual parent and talk\n * only to it. Safe because Nominal serves Vibe Apps behind a `frame-ancestors`\n * CSP, so only nom-ui can frame the app — the discovered parent is legitimate.\n * If no parent can be detected, the target is `null` (fast `connect()` reject).\n * 3. **Single exact origin** (the common explicit case): used verbatim as the\n * target and the inbound check. No parent discovery — identical to historical\n * behaviour.\n * 4. **List and/or glob patterns:** patterns count only when the app's own page\n * is a preview host ({@link isPreviewSelfHost}, fail-closed). The concrete\n * target is the actual parent origin (discovered + validated); if discovery\n * fails it falls back to the sole exact entry, else `null` (ambiguous →\n * refuse to post, surfaced as a fast `connect()` rejection).\n */\nfunction resolveOriginPolicy(configured?: string | string[]): OriginPolicy {\n if (typeof window !== 'undefined') {\n const override = (window as unknown as Record<string, unknown>)[PARENT_ORIGIN_OVERRIDE_KEY]\n if (typeof override === 'string' && override.length > 0) {\n console.log(`[vibe-bridge] Using dev-bridge parentOrigin override: ${override}`)\n return { targetOrigin: override, isTrusted: (o) => o === override }\n }\n }\n\n // Normalize to a clean list: coerce to array, trim, drop blank entries. An\n // unset env var that resolves to `''` (a common wiring of\n // `parentOrigin: import.meta.env.VITE_PARENT_ORIGIN`) thus behaves like\n // \"omitted\" — auto-detect — instead of building a broken bridge whose target\n // is the empty string (which would never match and would throw in postMessage).\n const rawList =\n configured === undefined ? [] : Array.isArray(configured) ? configured : [configured]\n const allowlist = rawList.map((entry) => entry.trim()).filter((entry) => entry.length > 0)\n\n // No usable allowlist: trust whatever Nominal page actually embeds us. Hostile\n // framing is blocked at the edge by a `frame-ancestors` CSP, so the discovered\n // parent is legitimate — and app authors configure nothing.\n if (allowlist.length === 0) {\n const actual = resolveActualParentOrigin()\n if (actual) return { targetOrigin: actual, isTrusted: (o) => o === actual }\n console.warn(\n '[vibe-bridge] No `parentOrigin` set and the embedding host could not be ' +\n 'auto-detected (no ancestorOrigins/referrer). Pass `parentOrigin` explicitly.',\n )\n return { targetOrigin: null, isTrusted: () => false }\n }\n\n const exactEntries = allowlist.filter((entry) => !isOriginPattern(entry))\n const hasPatterns = exactEntries.length !== allowlist.length\n\n // Common path: exactly one exact origin, no patterns. Behave exactly as before\n // — post to it directly (the browser enforces the match) and trust only it.\n if (allowlist.length === 1 && !hasPatterns) {\n const only = allowlist[0]\n return { targetOrigin: only, isTrusted: (o) => o === only }\n }\n\n const allowPatterns =\n hasPatterns && typeof window !== 'undefined' && isPreviewSelfHost(window.location.hostname)\n\n const isTrusted = (o: string): boolean => isOriginAllowed(o, allowlist, { allowPatterns })\n\n const actual = resolveActualParentOrigin()\n let targetOrigin: string | null = null\n if (actual && isTrusted(actual)) {\n targetOrigin = actual\n } else if (actual === null && !allowPatterns && exactEntries.length === 1) {\n // Parent discovery genuinely failed (e.g. referrer suppressed) AND patterns\n // aren't in play, so the sole exact origin is the only trusted target — safe\n // to post to it (the browser drops the message if the real parent differs).\n // We deliberately do NOT fall back when patterns are active (a preview host):\n // the real embedder might match only a pattern, so the exact entry would be a\n // wrong guess that merely waits out the 10s timeout. A parent that WAS\n // discovered but isn't trusted, or several exact entries, are likewise\n // ambiguous → null → fast connect() reject.\n targetOrigin = exactEntries[0]\n }\n\n if (targetOrigin === null) {\n console.warn(\n '[vibe-bridge] Could not resolve a parent origin to post to. ' +\n 'Check `parentOrigin` against the embedding host' +\n (hasPatterns && !allowPatterns\n ? ' — pattern entries are ignored because this page is not served from a recognised preview host.'\n : '.'),\n )\n }\n\n return { targetOrigin, isTrusted }\n}\n\ninterface PendingRequest {\n resolve: (data: unknown) => void\n reject: (error: Error) => void\n onProgress?: (payload: unknown) => void\n}\n\n/**\n * Iframe-side bridge to the Nominal host. One instance per app: construct it,\n * `await connect()` once, then call data methods, `upload()`, and subroute\n * helpers. Tear down with `destroy()` on unmount.\n *\n * **Import- and construction-safe everywhere.** The constructor is pure — it\n * stores options and touches **no** browser API — so importing this module and\n * `new VibeAppBridge()` are safe during SSR, in a React Server Component, or in\n * a Worker. The browser is only required when a method actually *runs*: the\n * message listener, origin resolution, and history patching are all deferred to\n * the first {@link VibeAppBridge.connect} (or an explicit {@link\n * VibeAppBridge.attach}). Calling a browser method where there is no `window`\n * throws a `BridgeError` with code `'SERVER_ENVIRONMENT'`.\n *\n * Every data method delegates to {@link VibeAppBridge.request}; the ~46 named\n * methods (e.g. {@link VibeAppBridge.getChartOfAccounts}) are the typed,\n * discoverable surface, and `request('<OP>', payload)` is the escape hatch for\n * any operation in {@link RequestRegistry}.\n *\n * @example\n * ```ts\n * import { VibeAppBridge, type ContextPayload } from '@nominalso/vibe-bridge'\n *\n * const bridge = new VibeAppBridge({ parentOrigin: import.meta.env.VITE_PARENT_ORIGIN })\n *\n * const ctx: ContextPayload = await bridge.connect()\n * const accounts = await bridge.getChartOfAccounts({ path: { subsidiary_id: ctx.subsidiaryId } })\n *\n * // cleanup\n * bridge.destroy()\n * ```\n */\nexport class VibeAppBridge extends BridgeDataMethods {\n /** Configured origin option, read lazily at {@link attach} (never at construction). */\n private readonly parentOriginOption?: string | string[]\n /** Concrete origin to `postMessage` to, or `null` until resolved at {@link attach}. */\n private targetOrigin: string | null = null\n /** Validates an inbound `event.origin`; rejects everything until {@link attach}. */\n private isTrustedOrigin: (origin: string) => boolean = () => false\n private readonly requestTimeout: number | undefined\n private readonly pendingRequests = new Map<string, PendingRequest>()\n private readonly boundHandleMessage: (event: MessageEvent) => void\n /** Whether {@link attach} has installed the message listener + resolved origin. */\n private attached = false\n\n private context: ContextPayload | null = null\n /**\n * Set once {@link initPostHog} has successfully called `posthog.init()`.\n * Guards against a double-init and makes {@link track} a no-op until\n * recording is actually live.\n */\n private posthogInitialized = false\n /** The lazily-imported `posthog-js` singleton, once recording is initialized. */\n private posthogInstance: PostHogLike | null = null\n /**\n * Set for the duration of an in-flight {@link initPostHog} (which is async — it\n * awaits `import('posthog-js')`). Serializes initialization so two overlapping\n * `POSTHOG_PUSH`es can't both call `posthog.init()`.\n */\n private posthogIniting = false\n /** So the \"posthog-js not installed\" warning is logged at most once. */\n private posthogUnavailableWarned = false\n private connectPromise: Promise<ContextPayload> | null = null\n private connectPollInterval: ReturnType<typeof setInterval> | null = null\n private connectTimeout: ReturnType<typeof setTimeout> | null = null\n private onContextReceived: ((ctx: ContextPayload) => void) | null = null\n /** Rejects an in-flight connect() (used by destroy()); `null` once settled. */\n private rejectConnect: ((error: BridgeError) => void) | null = null\n /**\n * Persistent subscriber for post-connect context changes (tenant/subsidiary\n * switch, period close, …). Distinct from {@link onContextReceived}, which only\n * resolves the connect handshake and is cleared afterward. `null` until\n * {@link onContextChange} is called.\n */\n private contextChangeCallback: ((ctx: ContextPayload) => void) | null = null\n /**\n * Persistent subscriber for host auth changes (Nominal logout or\n * identity/tenant switch). `null` until {@link onAuthChange} is called.\n */\n private authChangeCallback: ((auth: AuthPayload) => void) | null = null\n\n private lastReportedSubroute: string | null = null\n private suppressSubrouteReport = false\n private subrouteCallback: ((subroute: string) => void) | null = null\n private origPushState: typeof history.pushState | null = null\n private origReplaceState: typeof history.replaceState | null = null\n private popstateHandler: (() => void) | null = null\n\n private readonly kindHandlers: Partial<Record<BridgeKind, (msg: AnyBridgeMessage) => void>> = {\n response: (msg) => this.handleResponse(msg as ResponseMessage),\n push: (msg) => this.dispatchPush(msg as PushMessage),\n progress: (msg) => this.handleProgress(msg as ProgressMessage),\n }\n\n private dispatchPush(msg: PushMessage): void {\n const handler = this.pushHandlers[msg.type] as (payload: unknown) => void\n handler(msg.payload)\n }\n\n private readonly pushHandlers: { [K in keyof PushRegistry]: (payload: PushRegistry[K]) => void } =\n {\n CONTEXT_PUSH: (payload) => {\n if (this.onContextReceived) {\n // Connect handshake: resolve connect() with the initial context.\n this.onContextReceived(payload)\n } else if (this.context) {\n // Post-connect update: refresh the cached context and notify the app so\n // it can react to a tenant/subsidiary/period change without reloading.\n this.context = payload\n this.contextChangeCallback?.(payload)\n }\n // Otherwise a push arrived before connect() was called — ignore it\n // rather than caching context, so connect() still runs its full handshake\n // (setupNavigationTracking, etc.) instead of short-circuiting.\n },\n // Persistent (not nulled after connect): the host delivers PostHog once at\n // connect via its own push, and initPostHog is idempotent, so this can run\n // whenever the message arrives, independent of how connect() resolved. Fire\n // and forget — initPostHog is async (lazy-imports posthog-js) and swallows\n // its own errors.\n POSTHOG_PUSH: (payload) => {\n void this.initPostHog(payload)\n },\n // Persistent: the host pushes auth changes (logout, identity/tenant\n // switch) at any time after connect.\n AUTH_CHANGED: (payload) => this.authChangeCallback?.(payload),\n SUBROUTE_PUSH: (payload) => {\n // Guard inbound subroutes too: a `..` segment pushed by the host must\n // not be applied to the iframe's history (matches the outbound guard).\n const safe = normalizeSubroute(payload.subroute)\n if (!safe) return\n this.withSubrouteSuppressed(() => {\n if (this.subrouteCallback) {\n this.subrouteCallback(safe)\n } else {\n history.pushState(null, '', safe)\n window.dispatchEvent(new PopStateEvent('popstate'))\n }\n this.lastReportedSubroute = safe\n })\n },\n }\n\n /**\n * Stores options only — **pure and side-effect-free**. No `window`,\n * `document`, `history`, `postMessage`, `crypto`, or `posthog-js` access\n * happens here, so constructing a bridge is safe during SSR / in a Server\n * Component / in a Worker. Browser wiring is deferred to {@link connect} /\n * {@link attach}.\n */\n constructor(options: VibeAppBridgeOptions = {}) {\n super()\n this.parentOriginOption = options.parentOrigin\n this.requestTimeout = options.requestTimeout\n // Binding a method is pure (no DOM access); the listener is only *installed*\n // in attach().\n this.boundHandleMessage = this.handleMessage.bind(this)\n }\n\n /**\n * Installs the browser wiring: resolves the parent-origin policy and starts\n * listening for host `postMessage`s. **Idempotent** and safe to call before\n * {@link connect} if you want the bridge receiving pushes early; {@link\n * connect} calls it for you, so most apps never call this directly.\n *\n * @throws `BridgeError` code `'SERVER_ENVIRONMENT'` if called where there is no\n * `window`.\n */\n attach(): void {\n assertBrowser('attach()')\n if (this.attached) return\n const policy = resolveOriginPolicy(this.parentOriginOption)\n this.targetOrigin = policy.targetOrigin\n this.isTrustedOrigin = policy.isTrusted\n window.addEventListener('message', this.boundHandleMessage)\n this.attached = true\n }\n\n /**\n * Lazily installs the browser wiring on first transport use. Keeps the\n * constructor pure while ensuring that any method reaching the wire (a data\n * `request`, a fire-and-forget command) works without an explicit prior\n * `attach()`/`connect()` — attach stays idempotent, so `connect()` is\n * unaffected.\n */\n private ensureAttached(): void {\n if (!this.attached) this.attach()\n }\n\n /**\n * Connects to the host and returns the tenant/user {@link ContextPayload}.\n * **Call this once on app init and await it before any other method** — data\n * methods, `upload()`, and subroute reporting all require an established\n * connection. Concurrent calls return the same promise.\n *\n * First {@link attach | attaches} the browser wiring (message listener +\n * origin resolution), then sends a `CONNECT` handshake, re-sending every 500ms\n * until the host replies by pushing the context (so it works even if the host\n * mounts after the iframe loads). Context is only ever delivered by push.\n * Rejects with `Bridge connect timed out` after 10 seconds if no context\n * arrives (usually a `parentOrigin` mismatch or the host hasn't mounted).\n *\n * After connecting, if the context includes an initial subroute (e.g. from\n * a deep link), the bridge navigates to it and starts auto-tracking\n * internal navigation via the history API.\n *\n * @returns The tenant/user/subsidiary context for this app session.\n * @throws Rejects with `BridgeError` code `'SERVER_ENVIRONMENT'` if called\n * where there is no `window`, `'PARENT_ORIGIN_UNRESOLVED'` if no embedding\n * origin could be resolved, or `'TIMEOUT'` if no context arrives in 10s.\n * @example\n * ```ts\n * const ctx = await bridge.connect()\n * // ctx.tenant, ctx.subsidiaryId, ctx.subsidiaries, ctx.user, ctx.lastClosedPeriodSlug\n * ```\n */\n connect(): Promise<ContextPayload> {\n if (typeof window === 'undefined') return Promise.reject(serverEnvError('connect()'))\n if (this.context) return Promise.resolve(this.context)\n if (this.connectPromise) return this.connectPromise\n\n // Install the message listener + resolve the origin policy now (idempotent).\n this.attach()\n\n // No concrete parent origin to post to — a config/embedding error, not a\n // transient timeout. Reject immediately with a clear message rather than\n // polling into the 10s TIMEOUT (resolveOriginPolicy has already warned).\n if (this.targetOrigin === null) {\n return Promise.reject(\n new BridgeError(\n 'PARENT_ORIGIN_UNRESOLVED',\n 'Could not resolve a parent origin to connect to. Check `parentOrigin` against the embedding host.',\n ),\n )\n }\n\n this.connectPromise = new Promise<ContextPayload>((resolve, reject) => {\n const timer = setTimeout(() => {\n this.stopConnectPolling()\n this.connectPromise = null\n this.onContextReceived = null\n this.rejectConnect = null\n reject(new BridgeError('TIMEOUT', 'Bridge connect timed out'))\n }, CONNECT_TIMEOUT_MS)\n // Track on the instance so destroy() (via stopConnectPolling) clears it —\n // otherwise a destroy() before context arrives leaves this 10s timer armed\n // to fire reject() on an already-torn-down bridge.\n this.connectTimeout = timer\n\n // Lets destroy() reject an in-flight connect() so awaiting it fails fast\n // instead of hanging to the TIMEOUT.\n this.rejectConnect = (error: BridgeError) => {\n clearTimeout(timer)\n this.stopConnectPolling()\n this.connectPromise = null\n this.onContextReceived = null\n this.rejectConnect = null\n reject(error)\n }\n\n this.onContextReceived = (ctx: ContextPayload) => {\n clearTimeout(timer)\n this.stopConnectPolling()\n this.context = ctx\n this.connectPromise = null\n this.onContextReceived = null\n this.rejectConnect = null\n\n console.log(\n `[vibe-bridge] Connected — bridge: ${BRIDGE_VERSION}, host: ${ctx.hostVersion}, tenant: ${ctx.tenant}, user: ${ctx.user.displayName}`,\n )\n\n // PostHog is initialized separately, when the host's one-time\n // POSTHOG_PUSH arrives (see pushHandlers) — not from the context here.\n\n // Guard the connect-time deep link before applying it to history — a\n // `..` segment in the host's context must not traverse (matches the\n // outbound reportSubroute guard).\n const initialSubroute = ctx.subroute ? normalizeSubroute(ctx.subroute) : null\n if (initialSubroute && initialSubroute !== '/') {\n this.withSubrouteSuppressed(() => {\n history.replaceState(null, '', initialSubroute)\n window.dispatchEvent(new PopStateEvent('popstate'))\n this.lastReportedSubroute = initialSubroute\n })\n } else {\n this.lastReportedSubroute = window.location.pathname + window.location.search\n }\n\n this.setupNavigationTracking()\n this.warnMissingListeners()\n resolve(ctx)\n }\n\n // Announce readiness with a CONNECT handshake. The host validates the\n // origin and replies by pushing CONTEXT_PUSH (which resolves connect via\n // onContextReceived) — context is only ever delivered by push. Re-send on\n // an interval until that push lands, since the host may mount (start\n // listening) after the iframe loads.\n const sendConnect = (): void => {\n this.sendCommand('CONNECT', { bridgeVersion: BRIDGE_VERSION })\n }\n sendConnect()\n this.connectPollInterval = setInterval(sendConnect, CONNECT_POLL_MS)\n })\n\n return this.connectPromise\n }\n\n /**\n * Manually reports the current subroute to the host.\n * Usually not needed — navigation is auto-detected via the history API.\n * Use this for hash-based routers or non-standard navigation patterns.\n */\n reportSubroute(subroute: string, options?: { replace?: boolean }): void {\n assertBrowser('reportSubroute()')\n // Shared with the host's REPORT_SUBROUTE guard: ensures a leading slash and\n // drops path traversal, so a bad subroute is never put on the wire.\n const normalized = normalizeSubroute(subroute)\n if (normalized === null) return\n this.lastReportedSubroute = normalized\n this.sendCommand('REPORT_SUBROUTE', { subroute: normalized, replace: options?.replace })\n }\n\n /**\n * Registers a callback for host-initiated navigation (browser back/forward).\n * If no callback is registered, the SDK uses `history.pushState` + a\n * `popstate` event, which works for most SPA routers automatically.\n * Returns an unsubscribe function.\n *\n * Pure — only stores the callback, so it is safe to call before {@link connect}.\n */\n onSubrouteRequest(callback: (subroute: string) => void): () => void {\n this.subrouteCallback = callback\n return (): void => {\n this.subrouteCallback = null\n }\n }\n\n /**\n * Subscribes to post-connect context changes (tenant/subsidiary switch, period\n * close, …). The callback fires for each {@link ContextPayload} the host pushes\n * *after* connect — not for the initial context, which {@link connect} already\n * returns. Returns an unsubscribe function. Single subscriber: a second call\n * replaces the first. Wire it **before {@link connect}** (the bridge warns at\n * connect if it isn't).\n *\n * Pure — only stores the callback, so it is safe to call before {@link connect}.\n */\n onContextChange(callback: (ctx: ContextPayload) => void): () => void {\n this.contextChangeCallback = callback\n return (): void => {\n this.contextChangeCallback = null\n }\n }\n\n /**\n * Subscribes to host auth changes: a Nominal logout (`authenticated: false` —\n * sign your backend out) or an identity/tenant switch (`authenticated: true`\n * with a new `userId`/`tenant` — re-authenticate). Fires for each change the\n * host pushes after connect. Returns an unsubscribe function. Single\n * subscriber: a second call replaces the first.\n *\n * **Wire this before {@link connect}** — without it the embedded app won't\n * sign out when the user logs out of Nominal (the bridge warns at connect if\n * it isn't wired). Pure — only stores the callback.\n */\n onAuthChange(callback: (auth: AuthPayload) => void): () => void {\n this.authChangeCallback = callback\n return (): void => {\n this.authChangeCallback = null\n }\n }\n\n /**\n * At connect, nudge the app if it hasn't wired the change listeners: every\n * embedded app should react to a Nominal logout ({@link onAuthChange}) and a\n * tenant/subsidiary switch ({@link onContextChange}). Fires once during the\n * connect flow (not speculatively later), so wire both **before** `connect()`.\n * The skill/codegen does this by default; this catches hand-wired apps.\n */\n private warnMissingListeners(): void {\n if (!this.authChangeCallback) {\n console.warn(\n '[vibe-bridge] connected without onAuthChange — the app will not sign out on ' +\n 'Nominal logout or react to an identity/tenant switch. Call bridge.onAuthChange() before connect().',\n )\n }\n if (!this.contextChangeCallback) {\n console.warn(\n '[vibe-bridge] connected without onContextChange — the app will not react to a ' +\n 'tenant/subsidiary/period switch. Call bridge.onContextChange() before connect().',\n )\n }\n }\n\n // ---------------------------------------------------------------------------\n // Host navigation & UI commands\n //\n // These drive the *host* (nom-ui) chrome — its router, side nav, and\n // subsidiary switcher — rather than the iframe's own internal routing\n // (`reportSubroute`). Navigation/UI commands are fire-and-forget;\n // `invalidateCache` is awaited.\n // ---------------------------------------------------------------------------\n\n /**\n * Navigates the host to a raw path relative to this app's tenant/subsidiary\n * base. Fire-and-forget.\n *\n * @example\n * ```ts\n * bridge.navigate('/journal-entries/123')\n * bridge.navigate('/journal-entries/123', 'replace')\n * ```\n */\n navigate(path: string, action: NavigateAction = 'push'): void {\n assertBrowser('navigate()')\n this.sendCommand('NAVIGATE', { path, action })\n }\n\n /**\n * Navigates the host to a named Nominal route, with optional params for\n * placeholder segments. Fire-and-forget.\n *\n * @example\n * ```ts\n * bridge.navigateTo('CHART_OF_ACCOUNTS')\n * bridge.navigateTo('JOURNAL_ENTRY', { id: '123' }, 'replace')\n * ```\n */\n navigateTo(\n route: string,\n routeParams?: Record<string, string>,\n action: NavigateAction = 'push',\n ): void {\n assertBrowser('navigateTo()')\n this.sendCommand('NAVIGATE', { route, routeParams, action })\n }\n\n /** Refreshes the host's current route (re-fetches its server data). Fire-and-forget. */\n refresh(): void {\n assertBrowser('refresh()')\n this.sendCommand('NAVIGATE', { action: 'refresh' })\n }\n\n /**\n * Commands targeting the host's UI chrome. All fire-and-forget.\n *\n * @example\n * ```ts\n * bridge.ui.setSideNav({ collapsed: true })\n * bridge.ui.switchSubsidiary(42)\n * ```\n */\n readonly ui = {\n /** Collapse or expand the host's side navigation. */\n setSideNav: (payload: SetSideNavPayload): void => {\n assertBrowser('ui.setSideNav()')\n this.sendCommand('SET_SIDE_NAV', payload)\n },\n /** Switch the host to a different subsidiary. */\n switchSubsidiary: (subsidiaryId: number): void => {\n assertBrowser('ui.switchSubsidiary()')\n this.sendCommand('SWITCH_SUBSIDIARY', { subsidiaryId })\n },\n }\n\n /**\n * Asks the host to invalidate cached data by path prefix and/or cache tag so\n * subsequent reads see fresh values. Awaited.\n *\n * @example\n * ```ts\n * await bridge.invalidateCache({ tags: ['SUBSIDIARIES'], paths: ['/accounting/accounts'] })\n * ```\n */\n invalidateCache(payload: InvalidateCachePayload): Promise<InvalidateResult> {\n return this.request('INVALIDATE_CACHE', payload)\n }\n\n /**\n * Captures a custom product event from inside the Vibe App, attributed to the\n * same PostHog person as the host (via the `distinctId` the host supplied at\n * connect).\n *\n * **No-op until {@link connect} has resolved with PostHog enabled by the\n * host** — if the host didn't send a `posthog` block (older host, or recording\n * disabled for this env/app), or `posthog-js` isn't installed (it is an\n * optional dependency), nothing is sent. App authors don't import `posthog-js`\n * themselves; this is the supported event surface.\n *\n * The event is sent **directly** from the iframe's own PostHog instance (only\n * the session *recording* is forwarded to the parent), so it carries the\n * iframe instance's `$session_id` rather than the host's — events tie to the\n * same person, but cross-boundary event↔replay timeline correlation is a known\n * limitation.\n *\n * @param event Event name. Namespacing app events (e.g. `'vibe:<slug>:<action>'`)\n * keeps them filterable from the host's own events.\n * @param properties Optional event properties.\n * @example\n * ```ts\n * bridge.track('vibe:fixed-assets:report_exported', { format: 'csv', rows: 128 })\n * ```\n */\n track(event: string, properties?: Record<string, unknown>): void {\n assertBrowser('track()')\n if (!this.posthogInitialized || !this.posthogInstance) return\n this.posthogInstance.capture(event, properties)\n }\n\n /**\n * Tears down the bridge: stops the connect handshake, removes the message\n * listener, restores patched history methods, and rejects any in-flight calls\n * with a `'DESTROYED'` error. **Idempotent and safe on the server** — calling\n * it when {@link connect}/{@link attach} never ran (or where there is no\n * `window`) is a no-op, so it is safe as a React effect cleanup.\n */\n destroy(): void {\n this.teardownNavigationTracking()\n // Reject an in-flight connect() so awaiting it fails fast with a coded error\n // instead of hanging forever — stopConnectPolling() clears the retry/timeout\n // that would otherwise have been the only thing left to settle the promise.\n // (rejectConnect runs its own stopConnectPolling + state reset.)\n this.rejectConnect?.(new BridgeError('DESTROYED', 'Bridge destroyed'))\n this.stopConnectPolling()\n if (this.attached && typeof window !== 'undefined') {\n window.removeEventListener('message', this.boundHandleMessage)\n }\n this.attached = false\n for (const pending of this.pendingRequests.values()) {\n pending.reject(new BridgeError('DESTROYED', 'Bridge destroyed'))\n }\n this.pendingRequests.clear()\n this.context = null\n // Make track() a no-op after teardown. We deliberately don't call\n // posthog.reset() — that would clear the person/session and could disrupt an\n // in-flight recording across a remount; a fresh bridge re-inits cleanly.\n this.posthogInitialized = false\n this.posthogInstance = null\n this.posthogIniting = false\n this.connectPromise = null\n this.onContextReceived = null\n this.rejectConnect = null\n this.contextChangeCallback = null\n this.authChangeCallback = null\n this.subrouteCallback = null\n this.lastReportedSubroute = null\n }\n\n private stopConnectPolling(): void {\n if (this.connectPollInterval !== null) {\n clearInterval(this.connectPollInterval)\n this.connectPollInterval = null\n }\n if (this.connectTimeout !== null) {\n clearTimeout(this.connectTimeout)\n this.connectTimeout = null\n }\n }\n\n private warnPosthogUnavailable(): void {\n if (this.posthogUnavailableWarned) return\n this.posthogUnavailableWarned = true\n console.warn(\n '[vibe-bridge] The host enabled session recording but `posthog-js` is not ' +\n 'installed (it is an optional dependency). Recording and track() are disabled. ' +\n 'Run `npm i posthog-js` to enable them.',\n )\n }\n\n /**\n * Initializes PostHog session recording + analytics from the host-supplied\n * config carried by a one-time `POSTHOG_PUSH`, **only when the host opted in**\n * (`config.enabled`).\n *\n * `posthog-js` is an **optional dependency**, loaded lazily via `await\n * import('posthog-js')` the first time recording is enabled — so it stays out\n * of the import graph (and out of any server bundle) for apps that never\n * record. If it isn't installed, this warns once and no-ops (never throws).\n *\n * The host is the single source of truth: when it sends no `POSTHOG_PUSH`\n * (recording disabled for this env/app) or `enabled: false`, this does\n * nothing. Cross-origin replay needs `recordCrossOriginIframes` on both sides\n * so the parent receives the iframe's rrweb frames into one stitched recording,\n * and `identify()` ties the iframe's recording + events to the same person as\n * the host. Idempotent (the `posthogInitialized` guard) and wrapped in\n * try/catch so a duplicate push or a PostHog failure is harmless.\n */\n private async initPostHog(config: PostHogContext): Promise<void> {\n if (!config.enabled) return\n // Serialize: bail if recording is already live OR an init is already in\n // flight. Set synchronously (before the await below) so a second concurrent\n // POSTHOG_PUSH can't slip past this guard and run a second `posthog.init()`.\n if (this.posthogInitialized || this.posthogIniting) return\n if (typeof window === 'undefined') return\n // Defensive: a misconfigured host (enabled but blank token/host/person)\n // should be treated as \"off\" rather than wiring up a broken recorder.\n if (!config.token || !config.apiHost || !config.distinctId) {\n console.warn(\n '[vibe-bridge] PostHog enabled but token/apiHost/distinctId missing — skipping init.',\n )\n return\n }\n\n this.posthogIniting = true\n try {\n let posthog: PostHogLike | null\n try {\n posthog = resolvePosthog(await import('posthog-js'))\n } catch {\n // Optional dependency not installed — recording is simply unavailable.\n this.warnPosthogUnavailable()\n return\n }\n if (!posthog) {\n this.warnPosthogUnavailable()\n return\n }\n // Bail if the bridge was torn down while the dynamic import was in flight\n // (destroy() clears `attached`) — otherwise we'd start a recording and\n // re-arm track() on an already-destroyed bridge.\n if (!this.attached) return\n\n posthog.init(config.token, {\n api_host: config.apiHost, // absolute ingestion host, NOT a relative /ingest proxy\n person_profiles: 'identified_only',\n capture_pageview: false, // the host owns pageviews; don't double-count\n autocapture: false, // opt-in events only, via track()\n // Seed the host's session id so track() events share the host's\n // $session_id and line up with the stitched replay. Replay stitching\n // itself does not depend on this (recordCrossOriginIframes handles it).\n ...(config.sessionId ? { bootstrap: { sessionID: config.sessionId } } : {}),\n session_recording: {\n recordCrossOriginIframes: true, // REQUIRED so the parent receives our rrweb frames\n // Mirror nom-ui's posture (PostHogProvider.tsx): unmask inputs for\n // richer insight, but keep password fields masked.\n maskAllInputs: false,\n maskInputOptions: { password: true },\n },\n })\n // Link the iframe's recording + events to the SAME PostHog person as the host.\n posthog.identify(config.distinctId)\n this.posthogInstance = posthog\n this.posthogInitialized = true\n console.log('[vibe-bridge] PostHog session recording initialized')\n } catch (err) {\n // Recording is best-effort — a PostHog failure must never break connect().\n console.warn('[vibe-bridge] PostHog init failed — continuing without recording.', err)\n } finally {\n this.posthogIniting = false\n }\n }\n\n /**\n * Monkey-patches `history.pushState` and `history.replaceState` to\n * auto-detect SPA navigation and report it to the host. Called after\n * connect() resolves (so `window`/`history` are guaranteed present).\n */\n private setupNavigationTracking(): void {\n if (this.origPushState) return\n\n this.origPushState = history.pushState.bind(history)\n this.origReplaceState = history.replaceState.bind(history)\n\n const origPush = this.origPushState\n const origReplace = this.origReplaceState\n\n history.pushState = (...args: Parameters<typeof history.pushState>): void => {\n origPush(...args)\n this.reportCurrentSubroute(false)\n }\n\n history.replaceState = (...args: Parameters<typeof history.replaceState>): void => {\n origReplace(...args)\n this.reportCurrentSubroute(true)\n }\n\n this.popstateHandler = (): void => this.reportCurrentSubroute(true)\n window.addEventListener('popstate', this.popstateHandler)\n }\n\n private teardownNavigationTracking(): void {\n if (this.origPushState) {\n history.pushState = this.origPushState\n this.origPushState = null\n }\n if (this.origReplaceState) {\n history.replaceState = this.origReplaceState\n this.origReplaceState = null\n }\n if (this.popstateHandler) {\n window.removeEventListener('popstate', this.popstateHandler)\n this.popstateHandler = null\n }\n }\n\n /** Runs `fn` while suppressing subroute auto-reporting to prevent echo loops. */\n private withSubrouteSuppressed(fn: () => void): void {\n this.suppressSubrouteReport = true\n try {\n fn()\n } finally {\n this.suppressSubrouteReport = false\n }\n }\n\n private reportCurrentSubroute(replace: boolean): void {\n if (this.suppressSubrouteReport) return\n // Normalize like the explicit reportSubroute() path so what we record in\n // lastReportedSubroute matches what the host (which also guards) accepts —\n // otherwise URL sync / duplicate detection can drift.\n const subroute = normalizeSubroute(window.location.pathname + window.location.search)\n if (subroute === null) return\n if (subroute === this.lastReportedSubroute) return\n this.lastReportedSubroute = subroute\n this.sendCommand('REPORT_SUBROUTE', { subroute, replace })\n }\n\n private sendCommand<K extends keyof CommandRegistry>(type: K, payload: CommandRegistry[K]): void {\n this.ensureAttached()\n this.postToParent({\n __protocol: PROTOCOL_ID,\n __version: PROTOCOL_VERSION,\n kind: 'command',\n type,\n payload,\n })\n }\n\n /**\n * Low-level typed request for **any** operation in {@link RequestRegistry}.\n * The named methods (e.g. {@link VibeAppBridge.getChartOfAccounts}) wrap this;\n * use it directly for operations without a named method, or to pass an\n * `onProgress` callback. `type` autocompletes to every operation name and\n * narrows `payload`/return to that operation's types.\n *\n * @throws Rejects with `BridgeError` code `'SERVER_ENVIRONMENT'` if called\n * where there is no `window`.\n * @example\n * ```ts\n * const accounts = await bridge.request('GET_ACCOUNTS', { query: { account_ids: ['acc-1'] } })\n * ```\n */\n request<K extends keyof RequestRegistry>(\n type: K,\n payload: RequestRegistry[K]['payload'],\n onProgress?: (payload: unknown) => void,\n ): Promise<RequestRegistry[K]['data']> {\n if (typeof window === 'undefined') {\n return Promise.reject(serverEnvError(`request(${String(type)})`))\n }\n this.ensureAttached()\n return new Promise((resolve, reject) => {\n const requestId = crypto.randomUUID()\n\n const timer = setTimeout(\n () => {\n this.pendingRequests.delete(requestId)\n reject(new BridgeError('TIMEOUT', `Vibe bridge request timed out: ${type}`))\n },\n resolveRequestTimeout(type, this.requestTimeout),\n )\n\n this.pendingRequests.set(requestId, {\n resolve: (data) => {\n clearTimeout(timer)\n resolve(data as RequestRegistry[K]['data'])\n },\n reject: (error) => {\n clearTimeout(timer)\n reject(error)\n },\n onProgress,\n })\n\n const message: WireRequestMessage<K> = {\n __protocol: PROTOCOL_ID,\n __version: PROTOCOL_VERSION,\n kind: 'request',\n type,\n requestId,\n payload,\n }\n\n this.postToParent(message)\n })\n }\n\n /**\n * Posts to the embedding host. No-op when no concrete target origin could be\n * resolved (a config/embedding error) — `connect()` rejects fast in that case\n * so calls never silently hang waiting on a timeout.\n */\n private postToParent(message: unknown): void {\n if (this.targetOrigin === null) return\n window.parent.postMessage(message, this.targetOrigin)\n }\n\n private handleMessage(event: MessageEvent): void {\n if (!this.isTrustedOrigin(event.origin)) return\n if (!isBridgeMessage(event.data)) return\n this.kindHandlers[event.data.kind]?.(event.data)\n }\n\n private handleResponse(msg: ResponseMessage): void {\n const pending = this.pendingRequests.get(msg.requestId)\n if (!pending) return\n this.pendingRequests.delete(msg.requestId)\n\n if (msg.ok) {\n pending.resolve(msg.data)\n } else if (msg.status !== undefined) {\n // A failed Nominal API call — rehydrate as HttpBridgeError so callers can\n // branch on `err.status` (e.g. `404`).\n pending.reject(new HttpBridgeError(msg.status, msg.error))\n } else if (msg.code) {\n // Other coded host errors (e.g. `'RATE_LIMITED'`, `'FILE_TOO_LARGE'`) —\n // rehydrate as BridgeError so `catch` blocks branch on `error.code`.\n pending.reject(new BridgeError(msg.code, msg.error))\n } else {\n // No code — fall back to a plain Error.\n pending.reject(new Error(msg.error))\n }\n }\n\n private handleProgress(msg: ProgressMessage): void {\n const pending = this.pendingRequests.get(msg.requestId)\n pending?.onProgress?.(msg.payload)\n }\n}\n"],"mappings":"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","names":["actual"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BridgeDataMethods, V as VibeAppBridgeOptions, C as ContextPayload, A as AuthPayload, N as NavigateAction, S as SetSideNavPayload, I as InvalidateCachePayload, a as InvalidateResult, R as RequestRegistry } from './version-
|
|
2
|
-
export { b as BRIDGE_VERSION, c as BridgeError, d as BridgeSubsidiary, H as HttpBridgeError, P as PostHogContext, U as UploadOptions, e as UploadProgress, f as UploadResponse } from './version-
|
|
1
|
+
import { B as BridgeDataMethods, V as VibeAppBridgeOptions, C as ContextPayload, A as AuthPayload, N as NavigateAction, S as SetSideNavPayload, I as InvalidateCachePayload, a as InvalidateResult, R as RequestRegistry } from './version-yG6_fNT5.cjs';
|
|
2
|
+
export { b as BRIDGE_VERSION, c as BridgeError, d as BridgeSubsidiary, H as HttpBridgeError, P as PostHogContext, U as UploadOptions, e as UploadProgress, f as UploadResponse } from './version-yG6_fNT5.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Iframe-side bridge to the Nominal host. One instance per app: construct it,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as BridgeDataMethods, V as VibeAppBridgeOptions, C as ContextPayload, A as AuthPayload, N as NavigateAction, S as SetSideNavPayload, I as InvalidateCachePayload, a as InvalidateResult, R as RequestRegistry } from './version-
|
|
2
|
-
export { b as BRIDGE_VERSION, c as BridgeError, d as BridgeSubsidiary, H as HttpBridgeError, P as PostHogContext, U as UploadOptions, e as UploadProgress, f as UploadResponse } from './version-
|
|
1
|
+
import { B as BridgeDataMethods, V as VibeAppBridgeOptions, C as ContextPayload, A as AuthPayload, N as NavigateAction, S as SetSideNavPayload, I as InvalidateCachePayload, a as InvalidateResult, R as RequestRegistry } from './version-yG6_fNT5.js';
|
|
2
|
+
export { b as BRIDGE_VERSION, c as BridgeError, d as BridgeSubsidiary, H as HttpBridgeError, P as PostHogContext, U as UploadOptions, e as UploadProgress, f as UploadResponse } from './version-yG6_fNT5.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Iframe-side bridge to the Nominal host. One instance per app: construct it,
|
package/dist/index.js
CHANGED
package/dist/index.server.cjs
CHANGED
|
@@ -158,6 +158,22 @@ var BridgeDataMethods = class {
|
|
|
158
158
|
getDimensionAccountAssignments(payload) {
|
|
159
159
|
return this.request("GET_DIMENSION_ACCOUNT_ASSIGNMENTS", payload);
|
|
160
160
|
}
|
|
161
|
+
/** Get dimension-value balances for a dimension over a date window. */
|
|
162
|
+
getDimensionBalance(payload) {
|
|
163
|
+
return this.request("GET_DIMENSION_BALANCE", payload);
|
|
164
|
+
}
|
|
165
|
+
/** Add a new value under an existing dimension. */
|
|
166
|
+
addDimensionValue(payload) {
|
|
167
|
+
return this.request("ADD_DIMENSION_VALUE", payload);
|
|
168
|
+
}
|
|
169
|
+
/** Set or override the dimension value on a single journal-entry line. */
|
|
170
|
+
setLineDimensionValue(payload) {
|
|
171
|
+
return this.request("SET_LINE_DIMENSION_VALUE", payload);
|
|
172
|
+
}
|
|
173
|
+
/** Bulk-assign a dimension value to many journal-entry lines at once. */
|
|
174
|
+
bulkSetLineDimensionValue(payload) {
|
|
175
|
+
return this.request("BULK_SET_LINE_DIMENSION_VALUE", payload);
|
|
176
|
+
}
|
|
161
177
|
// ---------------------------------------------------------------------------
|
|
162
178
|
// Operations — Accounting: journal entries
|
|
163
179
|
// ---------------------------------------------------------------------------
|
|
@@ -434,7 +450,7 @@ var VibeAppBridge = class extends BridgeDataMethods {
|
|
|
434
450
|
};
|
|
435
451
|
|
|
436
452
|
// package.json
|
|
437
|
-
var version = "0.
|
|
453
|
+
var version = "0.8.0";
|
|
438
454
|
|
|
439
455
|
// src/version.ts
|
|
440
456
|
var BRIDGE_VERSION = version;
|