@nominalso/vibe-bridge 0.0.1 → 0.2.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/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- var version = "0.0.1";
1
+ var version = "0.2.0";
2
2
 
3
3
  type AccountingAccountDimensionValues = {
4
4
  account_id: string;
@@ -3203,15 +3203,6 @@ interface GetContextPayload {
3203
3203
  bridgeVersion: string;
3204
3204
  }
3205
3205
 
3206
- /**
3207
- * All operations the iframe can invoke on the host, each with a typed request
3208
- * payload and a typed response. Adding a new operation here is all that's
3209
- * required — message union types and handler types below are derived
3210
- * automatically.
3211
- *
3212
- * Operations that also emit intermediate progress events should include a
3213
- * `progress` field with the progress payload type.
3214
- */
3215
3206
  interface UploadPayload {
3216
3207
  buffer: ArrayBuffer;
3217
3208
  fileName: string;
@@ -3222,11 +3213,39 @@ interface UploadPayload {
3222
3213
  interface UploadResponse {
3223
3214
  attachmentId: string;
3224
3215
  name: string;
3216
+ /** Public/presigned URL of the stored file, when the host returns one. */
3217
+ url?: string;
3225
3218
  }
3226
3219
  interface UploadProgress {
3227
3220
  attachmentId: string;
3228
3221
  progress: number;
3229
3222
  }
3223
+ /** How the host should apply a navigation. Defaults to `'push'`. */
3224
+ type NavigateAction = 'push' | 'replace' | 'refresh';
3225
+ /** Collapse/expand the host's side navigation. */
3226
+ interface SetSideNavPayload {
3227
+ collapsed: boolean;
3228
+ }
3229
+ /** Targets for a host cache invalidation. */
3230
+ interface InvalidateCachePayload {
3231
+ /** API path prefixes to invalidate, e.g. `['/accounting/accounts']`. */
3232
+ paths?: string[];
3233
+ /** Cache tag keys to invalidate, e.g. `['REPORTS', 'SUBSIDIARIES']`. */
3234
+ tags?: string[];
3235
+ }
3236
+ /** Result of a host cache invalidation. */
3237
+ interface InvalidateResult {
3238
+ invalidated: boolean;
3239
+ }
3240
+
3241
+ /**
3242
+ * All operations the iframe can invoke on the host, each with a typed request
3243
+ * payload and a typed response. Adding a new operation here is all that's
3244
+ * required — message union types and handler types are derived automatically.
3245
+ *
3246
+ * Operations that also emit intermediate progress events should include a
3247
+ * `progress` field with the progress payload type.
3248
+ */
3230
3249
  interface RequestRegistry {
3231
3250
  GET_CHART_OF_ACCOUNTS: {
3232
3251
  payload: Omit<GetCoaFlatApiAccountingSubsidiarySubsidiaryIdCoaAccountGetData, 'url'>;
@@ -3412,6 +3431,10 @@ interface RequestRegistry {
3412
3431
  payload: Omit<GetTenantUsersApiTenancyTenantTenantIdOrNameUsersGetData, 'url'>;
3413
3432
  data: GetTenantUsersApiTenancyTenantTenantIdOrNameUsersGetResponse;
3414
3433
  };
3434
+ INVALIDATE_CACHE: {
3435
+ payload: InvalidateCachePayload;
3436
+ data: InvalidateResult;
3437
+ };
3415
3438
  GET_CONTEXT: {
3416
3439
  payload: GetContextPayload;
3417
3440
  data: ContextPayload;
@@ -3423,16 +3446,262 @@ interface RequestRegistry {
3423
3446
  };
3424
3447
  }
3425
3448
 
3426
- interface VibeAppBridgeOptions {
3427
- parentOrigin: string;
3428
- requestTimeout?: number;
3449
+ /**
3450
+ * An error that crossed the bridge, carrying a machine-readable {@link code}
3451
+ * alongside the human-readable message.
3452
+ *
3453
+ * The host attaches a `code` to failed responses (e.g. `'RATE_LIMITED'`,
3454
+ * `'FILE_TOO_LARGE'`, `'REQUEST_FAILED'`); the bridge rehydrates it into a
3455
+ * `BridgeError` so app `catch` blocks can branch on `error.code` instead of
3456
+ * string-matching `error.message`. A failed Nominal API call rehydrates as the
3457
+ * {@link HttpBridgeError} subtype, which adds the HTTP `status`.
3458
+ *
3459
+ * @example
3460
+ * ```ts
3461
+ * try {
3462
+ * await bridge.getAccounts({})
3463
+ * } catch (err) {
3464
+ * if (err instanceof BridgeError && err.code === 'RATE_LIMITED') {
3465
+ * // back off and retry
3466
+ * }
3467
+ * }
3468
+ * ```
3469
+ */
3470
+ declare class BridgeError extends Error {
3471
+ readonly code: string;
3472
+ constructor(code: string, message: string);
3429
3473
  }
3474
+ /**
3475
+ * A {@link BridgeError} for a failed Nominal API call. Its `code` is always
3476
+ * `'REQUEST_FAILED'`; the HTTP {@link status} is carried as a structured field
3477
+ * so callers can branch on it (e.g. `err.status === 404`) instead of parsing
3478
+ * the code string.
3479
+ *
3480
+ * @example
3481
+ * ```ts
3482
+ * try {
3483
+ * await bridge.getAccount({ path: { account_id: 'missing' } })
3484
+ * } catch (err) {
3485
+ * if (err instanceof HttpBridgeError && err.status === 404) {
3486
+ * // handle not-found
3487
+ * }
3488
+ * }
3489
+ * ```
3490
+ */
3491
+ declare class HttpBridgeError extends BridgeError {
3492
+ readonly status: number;
3493
+ constructor(status: number, message: string);
3494
+ }
3495
+
3430
3496
  interface UploadOptions {
3497
+ /** Domain entity the file attaches to, e.g. `'JOURNAL_ENTRY'`. */
3431
3498
  entityType: string;
3499
+ /** Id of the entity the file attaches to, when applicable. */
3432
3500
  entityId?: string | number;
3501
+ /** Called with incremental progress (`0`–`100`) while the upload streams. */
3433
3502
  onProgress?: (p: RequestRegistry['UPLOAD_FILE']['progress']) => void;
3434
3503
  }
3435
- declare class VibeAppBridge {
3504
+ /**
3505
+ * The typed Nominal data methods (~46) plus {@link BridgeDataMethods.upload},
3506
+ * factored onto a base class so {@link VibeAppBridge} stays focused on
3507
+ * connection/transport. Each method is a thin typed wrapper over `request()`;
3508
+ * `VibeAppBridge` provides the concrete `request` implementation.
3509
+ */
3510
+ declare abstract class BridgeDataMethods {
3511
+ /**
3512
+ * Low-level typed request for **any** operation in {@link RequestRegistry} —
3513
+ * implemented by {@link VibeAppBridge}. The named methods below wrap this.
3514
+ */
3515
+ abstract request<K extends keyof RequestRegistry>(type: K, payload: RequestRegistry[K]['payload'], onProgress?: (payload: unknown) => void): Promise<RequestRegistry[K]['data']>;
3516
+ /**
3517
+ * Fetch the flat chart of accounts for a subsidiary.
3518
+ *
3519
+ * @example
3520
+ * ```ts
3521
+ * const ctx = await bridge.connect()
3522
+ * const accounts = await bridge.getChartOfAccounts({
3523
+ * path: { subsidiary_id: ctx.subsidiaryId },
3524
+ * })
3525
+ * ```
3526
+ */
3527
+ getChartOfAccounts(payload: RequestRegistry['GET_CHART_OF_ACCOUNTS']['payload']): Promise<RequestRegistry['GET_CHART_OF_ACCOUNTS']['data']>;
3528
+ /** Fetch the chart of accounts as a hierarchical tree for a subsidiary. */
3529
+ getCoaTree(payload: RequestRegistry['GET_COA_TREE']['payload']): Promise<RequestRegistry['GET_COA_TREE']['data']>;
3530
+ /** Fetch a simplified flat chart of accounts for a subsidiary. */
3531
+ getCoaFlatSimple(payload: RequestRegistry['GET_COA_FLAT_SIMPLE']['payload']): Promise<RequestRegistry['GET_COA_FLAT_SIMPLE']['data']>;
3532
+ /** Fetch the flat chart of accounts grouped by account group. */
3533
+ getCoaGrouped(payload: RequestRegistry['GET_COA_GROUPED']['payload']): Promise<RequestRegistry['GET_COA_GROUPED']['data']>;
3534
+ /** Fetch a single chart-of-accounts account by id within a subsidiary. */
3535
+ getCoaAccount(payload: RequestRegistry['GET_COA_ACCOUNT']['payload']): Promise<RequestRegistry['GET_COA_ACCOUNT']['data']>;
3536
+ /** List the currencies available to a subsidiary's chart of accounts. */
3537
+ getSubsidiaryAvailableCurrencies(payload: RequestRegistry['GET_SUBSIDIARY_AVAILABLE_CURRENCIES']['payload']): Promise<RequestRegistry['GET_SUBSIDIARY_AVAILABLE_CURRENCIES']['data']>;
3538
+ /** Fetch accounts at the tenant level. */
3539
+ getAccounts(payload: RequestRegistry['GET_ACCOUNTS']['payload']): Promise<RequestRegistry['GET_ACCOUNTS']['data']>;
3540
+ /** Fetch a single account by id. */
3541
+ getAccount(payload: RequestRegistry['GET_ACCOUNT']['payload']): Promise<RequestRegistry['GET_ACCOUNT']['data']>;
3542
+ /** Fetch currency conversion rates for a currency. */
3543
+ getConversionRates(payload: RequestRegistry['GET_CONVERSION_RATES']['payload']): Promise<RequestRegistry['GET_CONVERSION_RATES']['data']>;
3544
+ /** Fetch the effective consolidation exchange rate. */
3545
+ getEffectiveExchangeRate(payload: RequestRegistry['GET_EFFECTIVE_EXCHANGE_RATE']['payload']): Promise<RequestRegistry['GET_EFFECTIVE_EXCHANGE_RATE']['data']>;
3546
+ /** Fetch the exchange-rate period covering a given input date. */
3547
+ getExchangeRateByDate(payload: RequestRegistry['GET_EXCHANGE_RATE_BY_DATE']['payload']): Promise<RequestRegistry['GET_EXCHANGE_RATE_BY_DATE']['data']>;
3548
+ /** List accounting dimensions. */
3549
+ getDimensions(payload: RequestRegistry['GET_DIMENSIONS']['payload']): Promise<RequestRegistry['GET_DIMENSIONS']['data']>;
3550
+ /** List values for accounting dimensions. */
3551
+ getDimensionValues(payload: RequestRegistry['GET_DIMENSION_VALUES']['payload']): Promise<RequestRegistry['GET_DIMENSION_VALUES']['data']>;
3552
+ /** List dimension values in hierarchical form. */
3553
+ getDimensionValuesHierarchical(payload: RequestRegistry['GET_DIMENSION_VALUES_HIERARCHICAL']['payload']): Promise<RequestRegistry['GET_DIMENSION_VALUES_HIERARCHICAL']['data']>;
3554
+ /** List account assignments for a dimension/account pair. */
3555
+ getDimensionAccountAssignments(payload: RequestRegistry['GET_DIMENSION_ACCOUNT_ASSIGNMENTS']['payload']): Promise<RequestRegistry['GET_DIMENSION_ACCOUNT_ASSIGNMENTS']['data']>;
3556
+ /**
3557
+ * Fetch journal entries for a subsidiary, optionally filtered by date range.
3558
+ *
3559
+ * @example
3560
+ * ```ts
3561
+ * const entries = await bridge.getJournalEntries({
3562
+ * path: { subsidiary_id: ctx.subsidiaryId },
3563
+ * query: { from_date: '2026-01-01', to_date: '2026-03-31' },
3564
+ * })
3565
+ * ```
3566
+ */
3567
+ getJournalEntries(payload: RequestRegistry['GET_JOURNAL_ENTRIES']['payload']): Promise<RequestRegistry['GET_JOURNAL_ENTRIES']['data']>;
3568
+ /** Fetch journal entry lines for a subsidiary. */
3569
+ getJournalLines(payload: RequestRegistry['GET_JOURNAL_LINES']['payload']): Promise<RequestRegistry['GET_JOURNAL_LINES']['data']>;
3570
+ /** Fetch a single journal entry by id within a subsidiary. */
3571
+ getJournalEntry(payload: RequestRegistry['GET_JOURNAL_ENTRY']['payload']): Promise<RequestRegistry['GET_JOURNAL_ENTRY']['data']>;
3572
+ /** List accounting period instances. */
3573
+ getPeriods(payload: RequestRegistry['GET_PERIODS']['payload']): Promise<RequestRegistry['GET_PERIODS']['data']>;
3574
+ /** Fetch a single period instance by id. */
3575
+ getPeriodInstance(payload: RequestRegistry['GET_PERIOD_INSTANCE']['payload']): Promise<RequestRegistry['GET_PERIOD_INSTANCE']['data']>;
3576
+ /** Fetch a period instance by its display slug (e.g. `"mar-2026"`). */
3577
+ getPeriodInstanceBySlug(payload: RequestRegistry['GET_PERIOD_INSTANCE_BY_SLUG']['payload']): Promise<RequestRegistry['GET_PERIOD_INSTANCE_BY_SLUG']['data']>;
3578
+ /** Fetch the close-progress breakdown for a period (by slug). */
3579
+ getPeriodProgressBreakdown(payload: RequestRegistry['GET_PERIOD_PROGRESS_BREAKDOWN']['payload']): Promise<RequestRegistry['GET_PERIOD_PROGRESS_BREAKDOWN']['data']>;
3580
+ /** List activity definitions. */
3581
+ getActivityDefinitions(payload: RequestRegistry['GET_ACTIVITY_DEFINITIONS']['payload']): Promise<RequestRegistry['GET_ACTIVITY_DEFINITIONS']['data']>;
3582
+ /** Fetch a single activity definition by id. */
3583
+ getActivityDefinition(payload: RequestRegistry['GET_ACTIVITY_DEFINITION']['payload']): Promise<RequestRegistry['GET_ACTIVITY_DEFINITION']['data']>;
3584
+ /** List activity instances. */
3585
+ getActivityInstances(payload: RequestRegistry['GET_ACTIVITY_INSTANCES']['payload']): Promise<RequestRegistry['GET_ACTIVITY_INSTANCES']['data']>;
3586
+ /** Fetch a single activity instance by id. */
3587
+ getActivityInstance(payload: RequestRegistry['GET_ACTIVITY_INSTANCE']['payload']): Promise<RequestRegistry['GET_ACTIVITY_INSTANCE']['data']>;
3588
+ /** Fetch an activity instance for a given period + activity definition. */
3589
+ getActivityInstanceByPeriod(payload: RequestRegistry['GET_ACTIVITY_INSTANCE_BY_PERIOD']['payload']): Promise<RequestRegistry['GET_ACTIVITY_INSTANCE_BY_PERIOD']['data']>;
3590
+ /** List task instances for an activity instance. */
3591
+ getActivityInstanceTasks(payload: RequestRegistry['GET_ACTIVITY_INSTANCE_TASKS']['payload']): Promise<RequestRegistry['GET_ACTIVITY_INSTANCE_TASKS']['data']>;
3592
+ /** List task instances for an activity in a given period. */
3593
+ getActivityPeriodTasks(payload: RequestRegistry['GET_ACTIVITY_PERIOD_TASKS']['payload']): Promise<RequestRegistry['GET_ACTIVITY_PERIOD_TASKS']['data']>;
3594
+ /** List task definitions. */
3595
+ getTaskDefinitions(payload: RequestRegistry['GET_TASK_DEFINITIONS']['payload']): Promise<RequestRegistry['GET_TASK_DEFINITIONS']['data']>;
3596
+ /** Fetch a single task definition by id. */
3597
+ getTaskDefinition(payload: RequestRegistry['GET_TASK_DEFINITION']['payload']): Promise<RequestRegistry['GET_TASK_DEFINITION']['data']>;
3598
+ /** Create a task definition. */
3599
+ createTaskDefinition(payload: RequestRegistry['CREATE_TASK_DEFINITION']['payload']): Promise<RequestRegistry['CREATE_TASK_DEFINITION']['data']>;
3600
+ /** Update a task definition by id. */
3601
+ updateTaskDefinition(payload: RequestRegistry['UPDATE_TASK_DEFINITION']['payload']): Promise<RequestRegistry['UPDATE_TASK_DEFINITION']['data']>;
3602
+ /** Query task definitions by filter. */
3603
+ getTaskDefinitionsByFilter(payload: RequestRegistry['GET_TASK_DEFINITIONS_BY_FILTER']['payload']): Promise<RequestRegistry['GET_TASK_DEFINITIONS_BY_FILTER']['data']>;
3604
+ /** List task instances. */
3605
+ getTaskInstances(payload: RequestRegistry['GET_TASK_INSTANCES']['payload']): Promise<RequestRegistry['GET_TASK_INSTANCES']['data']>;
3606
+ /** Fetch a single task instance by id. */
3607
+ getTaskInstance(payload: RequestRegistry['GET_TASK_INSTANCE']['payload']): Promise<RequestRegistry['GET_TASK_INSTANCE']['data']>;
3608
+ /**
3609
+ * Submit a Close-Management task output. This is the **only write path** back
3610
+ * into Nominal — Vibe Apps never write Nominal data directly.
3611
+ *
3612
+ * @example
3613
+ * ```ts
3614
+ * // `body` carries the task-specific output shape.
3615
+ * await bridge.postTaskOutput({
3616
+ * path: { task_instance_id: 'task-1' },
3617
+ * body: {},
3618
+ * })
3619
+ * ```
3620
+ */
3621
+ postTaskOutput(payload: RequestRegistry['POST_TASK_OUTPUT']['payload']): Promise<RequestRegistry['POST_TASK_OUTPUT']['data']>;
3622
+ /** Query task instances by filter. */
3623
+ getTaskInstancesByFilter(payload: RequestRegistry['GET_TASK_INSTANCES_BY_FILTER']['payload']): Promise<RequestRegistry['GET_TASK_INSTANCES_BY_FILTER']['data']>;
3624
+ /** List audit-trail events. */
3625
+ getAuditEvents(payload: RequestRegistry['GET_AUDIT_EVENTS']['payload']): Promise<RequestRegistry['GET_AUDIT_EVENTS']['data']>;
3626
+ /** List audit-trail events for a specific entity. */
3627
+ getEntityAuditEvents(payload: RequestRegistry['GET_ENTITY_AUDIT_EVENTS']['payload']): Promise<RequestRegistry['GET_ENTITY_AUDIT_EVENTS']['data']>;
3628
+ /** List fiscal calendars for a subsidiary. */
3629
+ getFiscalCalendars(payload: RequestRegistry['GET_FISCAL_CALENDARS']['payload']): Promise<RequestRegistry['GET_FISCAL_CALENDARS']['data']>;
3630
+ /** Fetch a single fiscal calendar by id. */
3631
+ getFiscalCalendar(payload: RequestRegistry['GET_FISCAL_CALENDAR']['payload']): Promise<RequestRegistry['GET_FISCAL_CALENDAR']['data']>;
3632
+ /** List subsidiaries for the tenant. */
3633
+ getSubsidiaries(payload: RequestRegistry['GET_SUBSIDIARIES']['payload']): Promise<RequestRegistry['GET_SUBSIDIARIES']['data']>;
3634
+ /** Fetch a single subsidiary by id. */
3635
+ getSubsidiary(payload: RequestRegistry['GET_SUBSIDIARY']['payload']): Promise<RequestRegistry['GET_SUBSIDIARY']['data']>;
3636
+ /** List parent currencies for a subsidiary. */
3637
+ getSubsidiaryParentCurrencies(payload: RequestRegistry['GET_SUBSIDIARY_PARENT_CURRENCIES']['payload']): Promise<RequestRegistry['GET_SUBSIDIARY_PARENT_CURRENCIES']['data']>;
3638
+ /** List users for the tenant. */
3639
+ getTenantUsers(payload: RequestRegistry['GET_TENANT_USERS']['payload']): Promise<RequestRegistry['GET_TENANT_USERS']['data']>;
3640
+ /**
3641
+ * Uploads a file through the host. Converts the `File` to an `ArrayBuffer`
3642
+ * before sending — sandboxed iframes cannot pass `File` handles across
3643
+ * windows. Resolves once Nominal has stored the file.
3644
+ *
3645
+ * @example
3646
+ * ```ts
3647
+ * const input = document.querySelector<HTMLInputElement>('#file')!
3648
+ * const file = input.files![0]
3649
+ * const result = await bridge.upload(file, {
3650
+ * entityType: 'JOURNAL_ENTRY',
3651
+ * entityId: '123',
3652
+ * onProgress: (p) => console.log(`${p.progress}%`),
3653
+ * })
3654
+ * // result.attachmentId, result.name
3655
+ * ```
3656
+ */
3657
+ upload(file: File, options: UploadOptions): Promise<RequestRegistry['UPLOAD_FILE']['data']>;
3658
+ }
3659
+
3660
+ interface VibeAppBridgeOptions {
3661
+ /**
3662
+ * Origin of the Nominal app embedding this iframe (e.g.
3663
+ * `https://app.nominal.so` or `http://localhost:3000`). Must match the host
3664
+ * origin **exactly** — messages from any other origin are ignored, and the
3665
+ * bridge only `postMessage`s to this origin. Drive it from an env var so the
3666
+ * same code works locally and in production.
3667
+ */
3668
+ parentOrigin: string;
3669
+ /**
3670
+ * Global per-request timeout in milliseconds before a call rejects with a
3671
+ * `BridgeError` whose `code` is `'TIMEOUT'`.
3672
+ *
3673
+ * When omitted, each operation uses an operation-specific default tuned to
3674
+ * how long it realistically takes (API reads `30000`, `UPLOAD_FILE`
3675
+ * `120000`, `INVALIDATE_CACHE` `10000`, `GET_CONTEXT` `5000`). Setting this
3676
+ * overrides all of them with a single value — only do that if you have a
3677
+ * specific reason; the defaults already match the host's expectations.
3678
+ */
3679
+ requestTimeout?: number;
3680
+ }
3681
+ /**
3682
+ * Iframe-side bridge to the Nominal host. One instance per app: construct it,
3683
+ * `await connect()` once, then call data methods, `upload()`, and subroute
3684
+ * helpers. Tear down with `destroy()` on unmount.
3685
+ *
3686
+ * Every data method delegates to {@link VibeAppBridge.request}; the ~46 named
3687
+ * methods (e.g. {@link VibeAppBridge.getChartOfAccounts}) are the typed,
3688
+ * discoverable surface, and `request('<OP>', payload)` is the escape hatch for
3689
+ * any operation in {@link RequestRegistry}.
3690
+ *
3691
+ * @example
3692
+ * ```ts
3693
+ * import { VibeAppBridge, type ContextPayload } from '@nominalso/vibe-bridge'
3694
+ *
3695
+ * const bridge = new VibeAppBridge({ parentOrigin: import.meta.env.VITE_PARENT_ORIGIN })
3696
+ *
3697
+ * const ctx: ContextPayload = await bridge.connect()
3698
+ * const accounts = await bridge.getChartOfAccounts({ path: { subsidiary_id: ctx.subsidiaryId } })
3699
+ *
3700
+ * // cleanup
3701
+ * bridge.destroy()
3702
+ * ```
3703
+ */
3704
+ declare class VibeAppBridge extends BridgeDataMethods {
3436
3705
  private readonly parentOrigin;
3437
3706
  private readonly requestTimeout;
3438
3707
  private readonly pendingRequests;
@@ -3441,6 +3710,13 @@ declare class VibeAppBridge {
3441
3710
  private connectPromise;
3442
3711
  private connectPollInterval;
3443
3712
  private onContextReceived;
3713
+ private onContextError;
3714
+ /**
3715
+ * Request ids of the current connect()'s GET_CONTEXT polls. Used to ignore a
3716
+ * late response from a *previous* connect attempt, which would otherwise
3717
+ * resolve/reject the new one (a stale error could reject a healthy reconnect).
3718
+ */
3719
+ private readonly connectPollIds;
3444
3720
  private lastReportedSubroute;
3445
3721
  private suppressSubrouteReport;
3446
3722
  private subrouteCallback;
@@ -3452,29 +3728,30 @@ declare class VibeAppBridge {
3452
3728
  private readonly pushHandlers;
3453
3729
  constructor({ parentOrigin, requestTimeout }: VibeAppBridgeOptions);
3454
3730
  /**
3455
- * Connects to the host and returns the tenant/user context.
3456
- * Call once on app init concurrent calls return the same promise.
3731
+ * Connects to the host and returns the tenant/user {@link ContextPayload}.
3732
+ * **Call this once on app init and await it before any other method** — data
3733
+ * methods, `upload()`, and subroute reporting all require an established
3734
+ * connection. Concurrent calls return the same promise.
3457
3735
  *
3458
3736
  * Actively polls the host every 500ms until a response arrives, which
3459
3737
  * handles the race condition where the host's initial context push arrives
3460
- * before this listener is ready.
3738
+ * before this listener is ready. Rejects with `Bridge connect timed out`
3739
+ * after 10 seconds if no context arrives (usually a `parentOrigin` mismatch
3740
+ * or the host hasn't mounted).
3461
3741
  *
3462
3742
  * After connecting, if the context includes an initial subroute (e.g. from
3463
3743
  * a deep link), the bridge navigates to it and starts auto-tracking
3464
3744
  * internal navigation via the history API.
3745
+ *
3746
+ * @returns The tenant/user/subsidiary context for this app session.
3747
+ * @throws If no context is received within 10 seconds.
3748
+ * @example
3749
+ * ```ts
3750
+ * const ctx = await bridge.connect()
3751
+ * // ctx.tenant, ctx.subsidiaryId, ctx.subsidiaries, ctx.user, ctx.lastClosedPeriodSlug
3752
+ * ```
3465
3753
  */
3466
3754
  connect(): Promise<ContextPayload>;
3467
- getChartOfAccounts(payload: RequestRegistry['GET_CHART_OF_ACCOUNTS']['payload']): Promise<RequestRegistry['GET_CHART_OF_ACCOUNTS']['data']>;
3468
- getSubsidiaries(payload: RequestRegistry['GET_SUBSIDIARIES']['payload']): Promise<RequestRegistry['GET_SUBSIDIARIES']['data']>;
3469
- getPeriods(payload: RequestRegistry['GET_PERIODS']['payload']): Promise<RequestRegistry['GET_PERIODS']['data']>;
3470
- postTaskOutput(payload: RequestRegistry['POST_TASK_OUTPUT']['payload']): Promise<RequestRegistry['POST_TASK_OUTPUT']['data']>;
3471
- getJournalEntries(payload: RequestRegistry['GET_JOURNAL_ENTRIES']['payload']): Promise<RequestRegistry['GET_JOURNAL_ENTRIES']['data']>;
3472
- getJournalLines(payload: RequestRegistry['GET_JOURNAL_LINES']['payload']): Promise<RequestRegistry['GET_JOURNAL_LINES']['data']>;
3473
- /**
3474
- * Uploads a file through the host. Converts the File to an ArrayBuffer
3475
- * before sending — sandboxed iframes cannot pass File handles across windows.
3476
- */
3477
- upload(file: File, options: UploadOptions): Promise<RequestRegistry['UPLOAD_FILE']['data']>;
3478
3755
  /**
3479
3756
  * Manually reports the current subroute to the host.
3480
3757
  * Usually not needed — navigation is auto-detected via the history API.
@@ -3490,6 +3767,55 @@ declare class VibeAppBridge {
3490
3767
  * Returns an unsubscribe function.
3491
3768
  */
3492
3769
  onSubrouteRequest(callback: (subroute: string) => void): () => void;
3770
+ /**
3771
+ * Navigates the host to a raw path relative to this app's tenant/subsidiary
3772
+ * base. Fire-and-forget.
3773
+ *
3774
+ * @example
3775
+ * ```ts
3776
+ * bridge.navigate('/journal-entries/123')
3777
+ * bridge.navigate('/journal-entries/123', 'replace')
3778
+ * ```
3779
+ */
3780
+ navigate(path: string, action?: NavigateAction): void;
3781
+ /**
3782
+ * Navigates the host to a named Nominal route, with optional params for
3783
+ * placeholder segments. Fire-and-forget.
3784
+ *
3785
+ * @example
3786
+ * ```ts
3787
+ * bridge.navigateTo('CHART_OF_ACCOUNTS')
3788
+ * bridge.navigateTo('JOURNAL_ENTRY', { id: '123' }, 'replace')
3789
+ * ```
3790
+ */
3791
+ navigateTo(route: string, routeParams?: Record<string, string>, action?: NavigateAction): void;
3792
+ /** Refreshes the host's current route (re-fetches its server data). Fire-and-forget. */
3793
+ refresh(): void;
3794
+ /**
3795
+ * Commands targeting the host's UI chrome. All fire-and-forget.
3796
+ *
3797
+ * @example
3798
+ * ```ts
3799
+ * bridge.ui.setSideNav({ collapsed: true })
3800
+ * bridge.ui.switchSubsidiary(42)
3801
+ * ```
3802
+ */
3803
+ readonly ui: {
3804
+ /** Collapse or expand the host's side navigation. */
3805
+ setSideNav: (payload: SetSideNavPayload) => void;
3806
+ /** Switch the host to a different subsidiary. */
3807
+ switchSubsidiary: (subsidiaryId: number) => void;
3808
+ };
3809
+ /**
3810
+ * Asks the host to invalidate cached data by path prefix and/or cache tag so
3811
+ * subsequent reads see fresh values. Awaited.
3812
+ *
3813
+ * @example
3814
+ * ```ts
3815
+ * await bridge.invalidateCache({ tags: ['SUBSIDIARIES'], paths: ['/accounting/accounts'] })
3816
+ * ```
3817
+ */
3818
+ invalidateCache(payload: InvalidateCachePayload): Promise<InvalidateResult>;
3493
3819
  destroy(): void;
3494
3820
  private stopConnectPolling;
3495
3821
  /**
@@ -3503,10 +3829,22 @@ declare class VibeAppBridge {
3503
3829
  private withSubrouteSuppressed;
3504
3830
  private reportCurrentSubroute;
3505
3831
  private sendCommand;
3832
+ /**
3833
+ * Low-level typed request for **any** operation in {@link RequestRegistry}.
3834
+ * The named methods (e.g. {@link VibeAppBridge.getChartOfAccounts}) wrap this;
3835
+ * use it directly for operations without a named method, or to pass an
3836
+ * `onProgress` callback. `type` autocompletes to every operation name and
3837
+ * narrows `payload`/return to that operation's types.
3838
+ *
3839
+ * @example
3840
+ * ```ts
3841
+ * const accounts = await bridge.request('GET_ACCOUNTS', { query: { account_ids: ['acc-1'] } })
3842
+ * ```
3843
+ */
3506
3844
  request<K extends keyof RequestRegistry>(type: K, payload: RequestRegistry[K]['payload'], onProgress?: (payload: unknown) => void): Promise<RequestRegistry[K]['data']>;
3507
3845
  private handleMessage;
3508
3846
  private handleResponse;
3509
3847
  private handleProgress;
3510
3848
  }
3511
3849
 
3512
- export { version as BRIDGE_VERSION, VibeAppBridge, type VibeAppBridgeOptions };
3850
+ export { version as BRIDGE_VERSION, BridgeError, type BridgeSubsidiary, type ContextPayload, HttpBridgeError, type InvalidateCachePayload, type InvalidateResult, type NavigateAction, type RequestRegistry, type SetSideNavPayload, type UploadOptions, type UploadProgress, type UploadResponse, VibeAppBridge, type VibeAppBridgeOptions };