@nominalso/vibe-bridge 0.3.0 → 0.5.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/AGENTS.md +6 -3
- package/README.md +24 -2
- package/dist/index.cjs +206 -47
- package/dist/index.d.cts +168 -26
- package/dist/index.d.ts +168 -26
- package/dist/index.js +196 -47
- package/docs/connect-lifecycle.md +10 -0
- package/docs/getting-started.md +1 -1
- package/llms.txt +2 -2
- package/package.json +4 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var version = "0.
|
|
1
|
+
var version = "0.5.0";
|
|
2
2
|
|
|
3
3
|
type AccountingAccountDimensionValues = {
|
|
4
4
|
account_id: string;
|
|
@@ -1392,6 +1392,7 @@ type ActivityProviderOperationErrorType = 'Connection Error' | 'Authentication E
|
|
|
1392
1392
|
type ActivityReconciliationDefinitionData = {
|
|
1393
1393
|
type: ActivityReconciliationType;
|
|
1394
1394
|
task_definition_id: string;
|
|
1395
|
+
currency?: ActivityCurrency | null;
|
|
1395
1396
|
side_a_entity_type: ActivityReconciliationEntityType;
|
|
1396
1397
|
side_a_entity_id: string;
|
|
1397
1398
|
side_b_entity_type: ActivityReconciliationEntityType;
|
|
@@ -1405,7 +1406,6 @@ type ActivityReconciliationInstanceDataInput = {
|
|
|
1405
1406
|
task_instance_id: string;
|
|
1406
1407
|
start_date: string;
|
|
1407
1408
|
end_date: string;
|
|
1408
|
-
currency?: ActivityCurrency | null;
|
|
1409
1409
|
side_a_value?: number | string | null;
|
|
1410
1410
|
side_b_value?: number | string | null;
|
|
1411
1411
|
reconciling_items_balance?: number | string | null;
|
|
@@ -1419,7 +1419,6 @@ type ActivityReconciliationInstanceDataOutput = {
|
|
|
1419
1419
|
task_instance_id: string;
|
|
1420
1420
|
start_date: string;
|
|
1421
1421
|
end_date: string;
|
|
1422
|
-
currency?: ActivityCurrency | null;
|
|
1423
1422
|
side_a_value?: string | null;
|
|
1424
1423
|
side_b_value?: string | null;
|
|
1425
1424
|
reconciling_items_balance?: string | null;
|
|
@@ -3182,6 +3181,76 @@ interface BridgeSubsidiary {
|
|
|
3182
3181
|
id: number;
|
|
3183
3182
|
displayName: string;
|
|
3184
3183
|
}
|
|
3184
|
+
/**
|
|
3185
|
+
* PostHog configuration the host supplies so the iframe can record a session
|
|
3186
|
+
* replay (stitched into the host's recording via `recordCrossOriginIframes`)
|
|
3187
|
+
* and emit custom events, all attributed to the **same PostHog person** as
|
|
3188
|
+
* nom-ui.
|
|
3189
|
+
*
|
|
3190
|
+
* The host (nom-ui) is the single source of truth for these values — it knows
|
|
3191
|
+
* the project key, the env-aware ingestion host, and the resolved person — and
|
|
3192
|
+
* delivers it over the bridge (as a one-time `POSTHOG_PUSH`, separate from
|
|
3193
|
+
* {@link ContextPayload}) so the iframe never hardcodes any of it. When the host
|
|
3194
|
+
* has no PostHog config (recording disabled for this env/app), it sends no
|
|
3195
|
+
* `POSTHOG_PUSH` and the bridge initializes nothing.
|
|
3196
|
+
*/
|
|
3197
|
+
interface PostHogContext {
|
|
3198
|
+
/** Project API key — the same PostHog project the host (nom-ui) uses. */
|
|
3199
|
+
token: string;
|
|
3200
|
+
/**
|
|
3201
|
+
* **Absolute** ingestion host, e.g. `"https://us.i.posthog.com"`.
|
|
3202
|
+
*
|
|
3203
|
+
* Must NOT be the host's relative `/ingest` reverse-proxy path: a relative
|
|
3204
|
+
* path resolves against the iframe's *own* (cross-origin) host and 404s.
|
|
3205
|
+
*/
|
|
3206
|
+
apiHost: string;
|
|
3207
|
+
/**
|
|
3208
|
+
* Host-resolved PostHog distinct id. The bridge calls `identify()` with it so
|
|
3209
|
+
* the iframe's recording and events attribute to the same person as the host.
|
|
3210
|
+
*/
|
|
3211
|
+
distinctId: string;
|
|
3212
|
+
/**
|
|
3213
|
+
* **Optional.** The host's current PostHog session id (from
|
|
3214
|
+
* `posthog.get_session_id()`). When provided, the bridge seeds it as the
|
|
3215
|
+
* iframe instance's session via `bootstrap.sessionID`, so custom events from
|
|
3216
|
+
* `bridge.track()` share the **same `$session_id`** as the host — letting them
|
|
3217
|
+
* line up with the stitched session replay on one timeline.
|
|
3218
|
+
*
|
|
3219
|
+
* Not needed for *replay* stitching itself (that works via
|
|
3220
|
+
* `recordCrossOriginIframes` on both sides regardless). Must be a valid UUID
|
|
3221
|
+
* v7 — PostHog session ids already are. It is a one-time seed at connect, so
|
|
3222
|
+
* if the host's session later rotates the two can diverge; alignment is
|
|
3223
|
+
* best-effort for the session in progress.
|
|
3224
|
+
*/
|
|
3225
|
+
sessionId?: string;
|
|
3226
|
+
/**
|
|
3227
|
+
* Master switch, env- and/or app-gated by the host. The bridge only calls
|
|
3228
|
+
* `posthog.init()` when this is `true`; it stays the kill-switch even though
|
|
3229
|
+
* `posthog-js` is bundled into the bridge.
|
|
3230
|
+
*/
|
|
3231
|
+
enabled: boolean;
|
|
3232
|
+
}
|
|
3233
|
+
/**
|
|
3234
|
+
* Authentication-state change the host pushes to the iframe via `AUTH_CHANGED`.
|
|
3235
|
+
* It carries the security principal the embedded app authenticates and scopes
|
|
3236
|
+
* its own data by. Sent when the Nominal session changes: a logout
|
|
3237
|
+
* (`authenticated: false`) or an identity/tenant switch (`authenticated: true`
|
|
3238
|
+
* with a new `userId`/`tenant`). The initial state is implicit at connect — the
|
|
3239
|
+
* iframe only loads when authenticated, and the current identity/tenant are
|
|
3240
|
+
* {@link ContextPayload.user} / {@link ContextPayload.tenant}, so apps baseline
|
|
3241
|
+
* off those and react to this push.
|
|
3242
|
+
*
|
|
3243
|
+
* Subsidiary/period and other view-level state are NOT here — they ride the
|
|
3244
|
+
* follow-up `CONTEXT_PUSH` (`onContextChange`), per "auth change, then context".
|
|
3245
|
+
*/
|
|
3246
|
+
interface AuthPayload {
|
|
3247
|
+
/** Whether the Nominal user is still authenticated. */
|
|
3248
|
+
authenticated: boolean;
|
|
3249
|
+
/** The effective Nominal user id when authenticated; omitted on logout. */
|
|
3250
|
+
userId?: string;
|
|
3251
|
+
/** The tenant the user is acting in — the app's data-scoping key (RLS). */
|
|
3252
|
+
tenant?: string;
|
|
3253
|
+
}
|
|
3185
3254
|
interface ContextPayload {
|
|
3186
3255
|
tenant: string;
|
|
3187
3256
|
subsidiaryId: number;
|
|
@@ -3197,11 +3266,6 @@ interface ContextPayload {
|
|
|
3197
3266
|
/** Version of the host SDK (@nominalso/vibe-host) running in nom-ui. */
|
|
3198
3267
|
hostVersion: string;
|
|
3199
3268
|
}
|
|
3200
|
-
/** Payload sent by the bridge when requesting context from the host. */
|
|
3201
|
-
interface GetContextPayload {
|
|
3202
|
-
/** Version of the bridge SDK (@nominalso/vibe-bridge) running in the iframe. */
|
|
3203
|
-
bridgeVersion: string;
|
|
3204
|
-
}
|
|
3205
3269
|
|
|
3206
3270
|
interface UploadPayload {
|
|
3207
3271
|
buffer: ArrayBuffer;
|
|
@@ -3435,10 +3499,6 @@ interface RequestRegistry {
|
|
|
3435
3499
|
payload: InvalidateCachePayload;
|
|
3436
3500
|
data: InvalidateResult;
|
|
3437
3501
|
};
|
|
3438
|
-
GET_CONTEXT: {
|
|
3439
|
-
payload: GetContextPayload;
|
|
3440
|
-
data: ContextPayload;
|
|
3441
|
-
};
|
|
3442
3502
|
UPLOAD_FILE: {
|
|
3443
3503
|
payload: UploadPayload;
|
|
3444
3504
|
data: UploadResponse;
|
|
@@ -3693,9 +3753,9 @@ interface VibeAppBridgeOptions {
|
|
|
3693
3753
|
*
|
|
3694
3754
|
* When omitted, each operation uses an operation-specific default tuned to
|
|
3695
3755
|
* how long it realistically takes (API reads `30000`, `UPLOAD_FILE`
|
|
3696
|
-
* `120000`, `INVALIDATE_CACHE` `10000
|
|
3697
|
-
*
|
|
3698
|
-
*
|
|
3756
|
+
* `120000`, `INVALIDATE_CACHE` `10000`). Setting this overrides all of them
|
|
3757
|
+
* with a single value — only do that if you have a specific reason; the
|
|
3758
|
+
* defaults already match the host's expectations.
|
|
3699
3759
|
*/
|
|
3700
3760
|
requestTimeout?: number;
|
|
3701
3761
|
}
|
|
@@ -3731,17 +3791,30 @@ declare class VibeAppBridge extends BridgeDataMethods {
|
|
|
3731
3791
|
private readonly pendingRequests;
|
|
3732
3792
|
private readonly boundHandleMessage;
|
|
3733
3793
|
private context;
|
|
3794
|
+
/**
|
|
3795
|
+
* Set once {@link initPostHog} has successfully called `posthog.init()`.
|
|
3796
|
+
* Guards against a double-init and makes {@link track} a no-op until
|
|
3797
|
+
* recording is actually live.
|
|
3798
|
+
*/
|
|
3799
|
+
private posthogInitialized;
|
|
3734
3800
|
private connectPromise;
|
|
3735
3801
|
private connectPollInterval;
|
|
3736
3802
|
private connectTimeout;
|
|
3737
3803
|
private onContextReceived;
|
|
3738
|
-
|
|
3804
|
+
/** Rejects an in-flight connect() (used by destroy()); `null` once settled. */
|
|
3805
|
+
private rejectConnect;
|
|
3806
|
+
/**
|
|
3807
|
+
* Persistent subscriber for post-connect context changes (tenant/subsidiary
|
|
3808
|
+
* switch, period close, …). Distinct from {@link onContextReceived}, which only
|
|
3809
|
+
* resolves the connect handshake and is cleared afterward. `null` until
|
|
3810
|
+
* {@link onContextChange} is called.
|
|
3811
|
+
*/
|
|
3812
|
+
private contextChangeCallback;
|
|
3739
3813
|
/**
|
|
3740
|
-
*
|
|
3741
|
-
*
|
|
3742
|
-
* resolve/reject the new one (a stale error could reject a healthy reconnect).
|
|
3814
|
+
* Persistent subscriber for host auth changes (Nominal logout or
|
|
3815
|
+
* identity/tenant switch). `null` until {@link onAuthChange} is called.
|
|
3743
3816
|
*/
|
|
3744
|
-
private
|
|
3817
|
+
private authChangeCallback;
|
|
3745
3818
|
private lastReportedSubroute;
|
|
3746
3819
|
private suppressSubrouteReport;
|
|
3747
3820
|
private subrouteCallback;
|
|
@@ -3758,11 +3831,11 @@ declare class VibeAppBridge extends BridgeDataMethods {
|
|
|
3758
3831
|
* methods, `upload()`, and subroute reporting all require an established
|
|
3759
3832
|
* connection. Concurrent calls return the same promise.
|
|
3760
3833
|
*
|
|
3761
|
-
*
|
|
3762
|
-
*
|
|
3763
|
-
*
|
|
3764
|
-
* after 10 seconds if no context arrives (usually a
|
|
3765
|
-
* or the host hasn't mounted).
|
|
3834
|
+
* Sends a `CONNECT` handshake, re-sending every 500ms until the host replies
|
|
3835
|
+
* by pushing the context (so it works even if the host mounts after the
|
|
3836
|
+
* iframe loads). Context is only ever delivered by push. Rejects with `Bridge
|
|
3837
|
+
* connect timed out` after 10 seconds if no context arrives (usually a
|
|
3838
|
+
* `parentOrigin` mismatch or the host hasn't mounted).
|
|
3766
3839
|
*
|
|
3767
3840
|
* After connecting, if the context includes an initial subroute (e.g. from
|
|
3768
3841
|
* a deep link), the bridge navigates to it and starts auto-tracking
|
|
@@ -3792,6 +3865,35 @@ declare class VibeAppBridge extends BridgeDataMethods {
|
|
|
3792
3865
|
* Returns an unsubscribe function.
|
|
3793
3866
|
*/
|
|
3794
3867
|
onSubrouteRequest(callback: (subroute: string) => void): () => void;
|
|
3868
|
+
/**
|
|
3869
|
+
* Subscribes to post-connect context changes (tenant/subsidiary switch, period
|
|
3870
|
+
* close, …). The callback fires for each {@link ContextPayload} the host pushes
|
|
3871
|
+
* *after* connect — not for the initial context, which {@link connect} already
|
|
3872
|
+
* returns. Returns an unsubscribe function. Single subscriber: a second call
|
|
3873
|
+
* replaces the first. Wire it **before {@link connect}** (the bridge warns at
|
|
3874
|
+
* connect if it isn't).
|
|
3875
|
+
*/
|
|
3876
|
+
onContextChange(callback: (ctx: ContextPayload) => void): () => void;
|
|
3877
|
+
/**
|
|
3878
|
+
* Subscribes to host auth changes: a Nominal logout (`authenticated: false` —
|
|
3879
|
+
* sign your backend out) or an identity/tenant switch (`authenticated: true`
|
|
3880
|
+
* with a new `userId`/`tenant` — re-authenticate). Fires for each change the
|
|
3881
|
+
* host pushes after connect. Returns an unsubscribe function. Single
|
|
3882
|
+
* subscriber: a second call replaces the first.
|
|
3883
|
+
*
|
|
3884
|
+
* **Wire this before {@link connect}** — without it the embedded app won't
|
|
3885
|
+
* sign out when the user logs out of Nominal (the bridge warns at connect if
|
|
3886
|
+
* it isn't wired).
|
|
3887
|
+
*/
|
|
3888
|
+
onAuthChange(callback: (auth: AuthPayload) => void): () => void;
|
|
3889
|
+
/**
|
|
3890
|
+
* At connect, nudge the app if it hasn't wired the change listeners: every
|
|
3891
|
+
* embedded app should react to a Nominal logout ({@link onAuthChange}) and a
|
|
3892
|
+
* tenant/subsidiary switch ({@link onContextChange}). Fires once during the
|
|
3893
|
+
* connect flow (not speculatively later), so wire both **before** `connect()`.
|
|
3894
|
+
* The skill/codegen does this by default; this catches hand-wired apps.
|
|
3895
|
+
*/
|
|
3896
|
+
private warnMissingListeners;
|
|
3795
3897
|
/**
|
|
3796
3898
|
* Navigates the host to a raw path relative to this app's tenant/subsidiary
|
|
3797
3899
|
* base. Fire-and-forget.
|
|
@@ -3841,8 +3943,48 @@ declare class VibeAppBridge extends BridgeDataMethods {
|
|
|
3841
3943
|
* ```
|
|
3842
3944
|
*/
|
|
3843
3945
|
invalidateCache(payload: InvalidateCachePayload): Promise<InvalidateResult>;
|
|
3946
|
+
/**
|
|
3947
|
+
* Captures a custom product event from inside the Vibe App, attributed to the
|
|
3948
|
+
* same PostHog person as the host (via the `distinctId` the host supplied at
|
|
3949
|
+
* connect).
|
|
3950
|
+
*
|
|
3951
|
+
* **No-op until {@link connect} has resolved with PostHog enabled by the
|
|
3952
|
+
* host** — if the host didn't send a `posthog` block (older host, or recording
|
|
3953
|
+
* disabled for this env/app), nothing is sent. App authors don't import
|
|
3954
|
+
* `posthog-js` themselves; this is the supported event surface.
|
|
3955
|
+
*
|
|
3956
|
+
* The event is sent **directly** from the iframe's own PostHog instance (only
|
|
3957
|
+
* the session *recording* is forwarded to the parent), so it carries the
|
|
3958
|
+
* iframe instance's `$session_id` rather than the host's — events tie to the
|
|
3959
|
+
* same person, but cross-boundary event↔replay timeline correlation is a known
|
|
3960
|
+
* limitation.
|
|
3961
|
+
*
|
|
3962
|
+
* @param event Event name. Namespacing app events (e.g. `'vibe:<slug>:<action>'`)
|
|
3963
|
+
* keeps them filterable from the host's own events.
|
|
3964
|
+
* @param properties Optional event properties.
|
|
3965
|
+
* @example
|
|
3966
|
+
* ```ts
|
|
3967
|
+
* bridge.track('vibe:fixed-assets:report_exported', { format: 'csv', rows: 128 })
|
|
3968
|
+
* ```
|
|
3969
|
+
*/
|
|
3970
|
+
track(event: string, properties?: Record<string, unknown>): void;
|
|
3844
3971
|
destroy(): void;
|
|
3845
3972
|
private stopConnectPolling;
|
|
3973
|
+
/**
|
|
3974
|
+
* Initializes PostHog session recording + analytics from the host-supplied
|
|
3975
|
+
* config carried by a one-time `POSTHOG_PUSH`, **only when the host opted in**
|
|
3976
|
+
* (`config.enabled`).
|
|
3977
|
+
*
|
|
3978
|
+
* The host is the single source of truth: when it sends no `POSTHOG_PUSH`
|
|
3979
|
+
* (recording disabled for this env/app) or `enabled: false`, this does
|
|
3980
|
+
* nothing — `enabled` is the kill-switch even though `posthog-js` is bundled
|
|
3981
|
+
* into the bridge. Cross-origin replay needs `recordCrossOriginIframes` on both
|
|
3982
|
+
* sides so the parent receives the iframe's rrweb frames into one stitched
|
|
3983
|
+
* recording, and `identify()` ties the iframe's recording + events to the same
|
|
3984
|
+
* person as the host. Idempotent (the `posthogInitialized` guard) and wrapped
|
|
3985
|
+
* in try/catch so a duplicate push or a PostHog failure is harmless.
|
|
3986
|
+
*/
|
|
3987
|
+
private initPostHog;
|
|
3846
3988
|
/**
|
|
3847
3989
|
* Monkey-patches `history.pushState` and `history.replaceState` to
|
|
3848
3990
|
* auto-detect SPA navigation and report it to the host. Called after
|
|
@@ -3878,4 +4020,4 @@ declare class VibeAppBridge extends BridgeDataMethods {
|
|
|
3878
4020
|
private handleProgress;
|
|
3879
4021
|
}
|
|
3880
4022
|
|
|
3881
|
-
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 };
|
|
4023
|
+
export { version as BRIDGE_VERSION, BridgeError, type BridgeSubsidiary, type ContextPayload, HttpBridgeError, type InvalidateCachePayload, type InvalidateResult, type NavigateAction, type PostHogContext, type RequestRegistry, type SetSideNavPayload, type UploadOptions, type UploadProgress, type UploadResponse, VibeAppBridge, type VibeAppBridgeOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var version = "0.
|
|
1
|
+
var version = "0.5.0";
|
|
2
2
|
|
|
3
3
|
type AccountingAccountDimensionValues = {
|
|
4
4
|
account_id: string;
|
|
@@ -1392,6 +1392,7 @@ type ActivityProviderOperationErrorType = 'Connection Error' | 'Authentication E
|
|
|
1392
1392
|
type ActivityReconciliationDefinitionData = {
|
|
1393
1393
|
type: ActivityReconciliationType;
|
|
1394
1394
|
task_definition_id: string;
|
|
1395
|
+
currency?: ActivityCurrency | null;
|
|
1395
1396
|
side_a_entity_type: ActivityReconciliationEntityType;
|
|
1396
1397
|
side_a_entity_id: string;
|
|
1397
1398
|
side_b_entity_type: ActivityReconciliationEntityType;
|
|
@@ -1405,7 +1406,6 @@ type ActivityReconciliationInstanceDataInput = {
|
|
|
1405
1406
|
task_instance_id: string;
|
|
1406
1407
|
start_date: string;
|
|
1407
1408
|
end_date: string;
|
|
1408
|
-
currency?: ActivityCurrency | null;
|
|
1409
1409
|
side_a_value?: number | string | null;
|
|
1410
1410
|
side_b_value?: number | string | null;
|
|
1411
1411
|
reconciling_items_balance?: number | string | null;
|
|
@@ -1419,7 +1419,6 @@ type ActivityReconciliationInstanceDataOutput = {
|
|
|
1419
1419
|
task_instance_id: string;
|
|
1420
1420
|
start_date: string;
|
|
1421
1421
|
end_date: string;
|
|
1422
|
-
currency?: ActivityCurrency | null;
|
|
1423
1422
|
side_a_value?: string | null;
|
|
1424
1423
|
side_b_value?: string | null;
|
|
1425
1424
|
reconciling_items_balance?: string | null;
|
|
@@ -3182,6 +3181,76 @@ interface BridgeSubsidiary {
|
|
|
3182
3181
|
id: number;
|
|
3183
3182
|
displayName: string;
|
|
3184
3183
|
}
|
|
3184
|
+
/**
|
|
3185
|
+
* PostHog configuration the host supplies so the iframe can record a session
|
|
3186
|
+
* replay (stitched into the host's recording via `recordCrossOriginIframes`)
|
|
3187
|
+
* and emit custom events, all attributed to the **same PostHog person** as
|
|
3188
|
+
* nom-ui.
|
|
3189
|
+
*
|
|
3190
|
+
* The host (nom-ui) is the single source of truth for these values — it knows
|
|
3191
|
+
* the project key, the env-aware ingestion host, and the resolved person — and
|
|
3192
|
+
* delivers it over the bridge (as a one-time `POSTHOG_PUSH`, separate from
|
|
3193
|
+
* {@link ContextPayload}) so the iframe never hardcodes any of it. When the host
|
|
3194
|
+
* has no PostHog config (recording disabled for this env/app), it sends no
|
|
3195
|
+
* `POSTHOG_PUSH` and the bridge initializes nothing.
|
|
3196
|
+
*/
|
|
3197
|
+
interface PostHogContext {
|
|
3198
|
+
/** Project API key — the same PostHog project the host (nom-ui) uses. */
|
|
3199
|
+
token: string;
|
|
3200
|
+
/**
|
|
3201
|
+
* **Absolute** ingestion host, e.g. `"https://us.i.posthog.com"`.
|
|
3202
|
+
*
|
|
3203
|
+
* Must NOT be the host's relative `/ingest` reverse-proxy path: a relative
|
|
3204
|
+
* path resolves against the iframe's *own* (cross-origin) host and 404s.
|
|
3205
|
+
*/
|
|
3206
|
+
apiHost: string;
|
|
3207
|
+
/**
|
|
3208
|
+
* Host-resolved PostHog distinct id. The bridge calls `identify()` with it so
|
|
3209
|
+
* the iframe's recording and events attribute to the same person as the host.
|
|
3210
|
+
*/
|
|
3211
|
+
distinctId: string;
|
|
3212
|
+
/**
|
|
3213
|
+
* **Optional.** The host's current PostHog session id (from
|
|
3214
|
+
* `posthog.get_session_id()`). When provided, the bridge seeds it as the
|
|
3215
|
+
* iframe instance's session via `bootstrap.sessionID`, so custom events from
|
|
3216
|
+
* `bridge.track()` share the **same `$session_id`** as the host — letting them
|
|
3217
|
+
* line up with the stitched session replay on one timeline.
|
|
3218
|
+
*
|
|
3219
|
+
* Not needed for *replay* stitching itself (that works via
|
|
3220
|
+
* `recordCrossOriginIframes` on both sides regardless). Must be a valid UUID
|
|
3221
|
+
* v7 — PostHog session ids already are. It is a one-time seed at connect, so
|
|
3222
|
+
* if the host's session later rotates the two can diverge; alignment is
|
|
3223
|
+
* best-effort for the session in progress.
|
|
3224
|
+
*/
|
|
3225
|
+
sessionId?: string;
|
|
3226
|
+
/**
|
|
3227
|
+
* Master switch, env- and/or app-gated by the host. The bridge only calls
|
|
3228
|
+
* `posthog.init()` when this is `true`; it stays the kill-switch even though
|
|
3229
|
+
* `posthog-js` is bundled into the bridge.
|
|
3230
|
+
*/
|
|
3231
|
+
enabled: boolean;
|
|
3232
|
+
}
|
|
3233
|
+
/**
|
|
3234
|
+
* Authentication-state change the host pushes to the iframe via `AUTH_CHANGED`.
|
|
3235
|
+
* It carries the security principal the embedded app authenticates and scopes
|
|
3236
|
+
* its own data by. Sent when the Nominal session changes: a logout
|
|
3237
|
+
* (`authenticated: false`) or an identity/tenant switch (`authenticated: true`
|
|
3238
|
+
* with a new `userId`/`tenant`). The initial state is implicit at connect — the
|
|
3239
|
+
* iframe only loads when authenticated, and the current identity/tenant are
|
|
3240
|
+
* {@link ContextPayload.user} / {@link ContextPayload.tenant}, so apps baseline
|
|
3241
|
+
* off those and react to this push.
|
|
3242
|
+
*
|
|
3243
|
+
* Subsidiary/period and other view-level state are NOT here — they ride the
|
|
3244
|
+
* follow-up `CONTEXT_PUSH` (`onContextChange`), per "auth change, then context".
|
|
3245
|
+
*/
|
|
3246
|
+
interface AuthPayload {
|
|
3247
|
+
/** Whether the Nominal user is still authenticated. */
|
|
3248
|
+
authenticated: boolean;
|
|
3249
|
+
/** The effective Nominal user id when authenticated; omitted on logout. */
|
|
3250
|
+
userId?: string;
|
|
3251
|
+
/** The tenant the user is acting in — the app's data-scoping key (RLS). */
|
|
3252
|
+
tenant?: string;
|
|
3253
|
+
}
|
|
3185
3254
|
interface ContextPayload {
|
|
3186
3255
|
tenant: string;
|
|
3187
3256
|
subsidiaryId: number;
|
|
@@ -3197,11 +3266,6 @@ interface ContextPayload {
|
|
|
3197
3266
|
/** Version of the host SDK (@nominalso/vibe-host) running in nom-ui. */
|
|
3198
3267
|
hostVersion: string;
|
|
3199
3268
|
}
|
|
3200
|
-
/** Payload sent by the bridge when requesting context from the host. */
|
|
3201
|
-
interface GetContextPayload {
|
|
3202
|
-
/** Version of the bridge SDK (@nominalso/vibe-bridge) running in the iframe. */
|
|
3203
|
-
bridgeVersion: string;
|
|
3204
|
-
}
|
|
3205
3269
|
|
|
3206
3270
|
interface UploadPayload {
|
|
3207
3271
|
buffer: ArrayBuffer;
|
|
@@ -3435,10 +3499,6 @@ interface RequestRegistry {
|
|
|
3435
3499
|
payload: InvalidateCachePayload;
|
|
3436
3500
|
data: InvalidateResult;
|
|
3437
3501
|
};
|
|
3438
|
-
GET_CONTEXT: {
|
|
3439
|
-
payload: GetContextPayload;
|
|
3440
|
-
data: ContextPayload;
|
|
3441
|
-
};
|
|
3442
3502
|
UPLOAD_FILE: {
|
|
3443
3503
|
payload: UploadPayload;
|
|
3444
3504
|
data: UploadResponse;
|
|
@@ -3693,9 +3753,9 @@ interface VibeAppBridgeOptions {
|
|
|
3693
3753
|
*
|
|
3694
3754
|
* When omitted, each operation uses an operation-specific default tuned to
|
|
3695
3755
|
* how long it realistically takes (API reads `30000`, `UPLOAD_FILE`
|
|
3696
|
-
* `120000`, `INVALIDATE_CACHE` `10000
|
|
3697
|
-
*
|
|
3698
|
-
*
|
|
3756
|
+
* `120000`, `INVALIDATE_CACHE` `10000`). Setting this overrides all of them
|
|
3757
|
+
* with a single value — only do that if you have a specific reason; the
|
|
3758
|
+
* defaults already match the host's expectations.
|
|
3699
3759
|
*/
|
|
3700
3760
|
requestTimeout?: number;
|
|
3701
3761
|
}
|
|
@@ -3731,17 +3791,30 @@ declare class VibeAppBridge extends BridgeDataMethods {
|
|
|
3731
3791
|
private readonly pendingRequests;
|
|
3732
3792
|
private readonly boundHandleMessage;
|
|
3733
3793
|
private context;
|
|
3794
|
+
/**
|
|
3795
|
+
* Set once {@link initPostHog} has successfully called `posthog.init()`.
|
|
3796
|
+
* Guards against a double-init and makes {@link track} a no-op until
|
|
3797
|
+
* recording is actually live.
|
|
3798
|
+
*/
|
|
3799
|
+
private posthogInitialized;
|
|
3734
3800
|
private connectPromise;
|
|
3735
3801
|
private connectPollInterval;
|
|
3736
3802
|
private connectTimeout;
|
|
3737
3803
|
private onContextReceived;
|
|
3738
|
-
|
|
3804
|
+
/** Rejects an in-flight connect() (used by destroy()); `null` once settled. */
|
|
3805
|
+
private rejectConnect;
|
|
3806
|
+
/**
|
|
3807
|
+
* Persistent subscriber for post-connect context changes (tenant/subsidiary
|
|
3808
|
+
* switch, period close, …). Distinct from {@link onContextReceived}, which only
|
|
3809
|
+
* resolves the connect handshake and is cleared afterward. `null` until
|
|
3810
|
+
* {@link onContextChange} is called.
|
|
3811
|
+
*/
|
|
3812
|
+
private contextChangeCallback;
|
|
3739
3813
|
/**
|
|
3740
|
-
*
|
|
3741
|
-
*
|
|
3742
|
-
* resolve/reject the new one (a stale error could reject a healthy reconnect).
|
|
3814
|
+
* Persistent subscriber for host auth changes (Nominal logout or
|
|
3815
|
+
* identity/tenant switch). `null` until {@link onAuthChange} is called.
|
|
3743
3816
|
*/
|
|
3744
|
-
private
|
|
3817
|
+
private authChangeCallback;
|
|
3745
3818
|
private lastReportedSubroute;
|
|
3746
3819
|
private suppressSubrouteReport;
|
|
3747
3820
|
private subrouteCallback;
|
|
@@ -3758,11 +3831,11 @@ declare class VibeAppBridge extends BridgeDataMethods {
|
|
|
3758
3831
|
* methods, `upload()`, and subroute reporting all require an established
|
|
3759
3832
|
* connection. Concurrent calls return the same promise.
|
|
3760
3833
|
*
|
|
3761
|
-
*
|
|
3762
|
-
*
|
|
3763
|
-
*
|
|
3764
|
-
* after 10 seconds if no context arrives (usually a
|
|
3765
|
-
* or the host hasn't mounted).
|
|
3834
|
+
* Sends a `CONNECT` handshake, re-sending every 500ms until the host replies
|
|
3835
|
+
* by pushing the context (so it works even if the host mounts after the
|
|
3836
|
+
* iframe loads). Context is only ever delivered by push. Rejects with `Bridge
|
|
3837
|
+
* connect timed out` after 10 seconds if no context arrives (usually a
|
|
3838
|
+
* `parentOrigin` mismatch or the host hasn't mounted).
|
|
3766
3839
|
*
|
|
3767
3840
|
* After connecting, if the context includes an initial subroute (e.g. from
|
|
3768
3841
|
* a deep link), the bridge navigates to it and starts auto-tracking
|
|
@@ -3792,6 +3865,35 @@ declare class VibeAppBridge extends BridgeDataMethods {
|
|
|
3792
3865
|
* Returns an unsubscribe function.
|
|
3793
3866
|
*/
|
|
3794
3867
|
onSubrouteRequest(callback: (subroute: string) => void): () => void;
|
|
3868
|
+
/**
|
|
3869
|
+
* Subscribes to post-connect context changes (tenant/subsidiary switch, period
|
|
3870
|
+
* close, …). The callback fires for each {@link ContextPayload} the host pushes
|
|
3871
|
+
* *after* connect — not for the initial context, which {@link connect} already
|
|
3872
|
+
* returns. Returns an unsubscribe function. Single subscriber: a second call
|
|
3873
|
+
* replaces the first. Wire it **before {@link connect}** (the bridge warns at
|
|
3874
|
+
* connect if it isn't).
|
|
3875
|
+
*/
|
|
3876
|
+
onContextChange(callback: (ctx: ContextPayload) => void): () => void;
|
|
3877
|
+
/**
|
|
3878
|
+
* Subscribes to host auth changes: a Nominal logout (`authenticated: false` —
|
|
3879
|
+
* sign your backend out) or an identity/tenant switch (`authenticated: true`
|
|
3880
|
+
* with a new `userId`/`tenant` — re-authenticate). Fires for each change the
|
|
3881
|
+
* host pushes after connect. Returns an unsubscribe function. Single
|
|
3882
|
+
* subscriber: a second call replaces the first.
|
|
3883
|
+
*
|
|
3884
|
+
* **Wire this before {@link connect}** — without it the embedded app won't
|
|
3885
|
+
* sign out when the user logs out of Nominal (the bridge warns at connect if
|
|
3886
|
+
* it isn't wired).
|
|
3887
|
+
*/
|
|
3888
|
+
onAuthChange(callback: (auth: AuthPayload) => void): () => void;
|
|
3889
|
+
/**
|
|
3890
|
+
* At connect, nudge the app if it hasn't wired the change listeners: every
|
|
3891
|
+
* embedded app should react to a Nominal logout ({@link onAuthChange}) and a
|
|
3892
|
+
* tenant/subsidiary switch ({@link onContextChange}). Fires once during the
|
|
3893
|
+
* connect flow (not speculatively later), so wire both **before** `connect()`.
|
|
3894
|
+
* The skill/codegen does this by default; this catches hand-wired apps.
|
|
3895
|
+
*/
|
|
3896
|
+
private warnMissingListeners;
|
|
3795
3897
|
/**
|
|
3796
3898
|
* Navigates the host to a raw path relative to this app's tenant/subsidiary
|
|
3797
3899
|
* base. Fire-and-forget.
|
|
@@ -3841,8 +3943,48 @@ declare class VibeAppBridge extends BridgeDataMethods {
|
|
|
3841
3943
|
* ```
|
|
3842
3944
|
*/
|
|
3843
3945
|
invalidateCache(payload: InvalidateCachePayload): Promise<InvalidateResult>;
|
|
3946
|
+
/**
|
|
3947
|
+
* Captures a custom product event from inside the Vibe App, attributed to the
|
|
3948
|
+
* same PostHog person as the host (via the `distinctId` the host supplied at
|
|
3949
|
+
* connect).
|
|
3950
|
+
*
|
|
3951
|
+
* **No-op until {@link connect} has resolved with PostHog enabled by the
|
|
3952
|
+
* host** — if the host didn't send a `posthog` block (older host, or recording
|
|
3953
|
+
* disabled for this env/app), nothing is sent. App authors don't import
|
|
3954
|
+
* `posthog-js` themselves; this is the supported event surface.
|
|
3955
|
+
*
|
|
3956
|
+
* The event is sent **directly** from the iframe's own PostHog instance (only
|
|
3957
|
+
* the session *recording* is forwarded to the parent), so it carries the
|
|
3958
|
+
* iframe instance's `$session_id` rather than the host's — events tie to the
|
|
3959
|
+
* same person, but cross-boundary event↔replay timeline correlation is a known
|
|
3960
|
+
* limitation.
|
|
3961
|
+
*
|
|
3962
|
+
* @param event Event name. Namespacing app events (e.g. `'vibe:<slug>:<action>'`)
|
|
3963
|
+
* keeps them filterable from the host's own events.
|
|
3964
|
+
* @param properties Optional event properties.
|
|
3965
|
+
* @example
|
|
3966
|
+
* ```ts
|
|
3967
|
+
* bridge.track('vibe:fixed-assets:report_exported', { format: 'csv', rows: 128 })
|
|
3968
|
+
* ```
|
|
3969
|
+
*/
|
|
3970
|
+
track(event: string, properties?: Record<string, unknown>): void;
|
|
3844
3971
|
destroy(): void;
|
|
3845
3972
|
private stopConnectPolling;
|
|
3973
|
+
/**
|
|
3974
|
+
* Initializes PostHog session recording + analytics from the host-supplied
|
|
3975
|
+
* config carried by a one-time `POSTHOG_PUSH`, **only when the host opted in**
|
|
3976
|
+
* (`config.enabled`).
|
|
3977
|
+
*
|
|
3978
|
+
* The host is the single source of truth: when it sends no `POSTHOG_PUSH`
|
|
3979
|
+
* (recording disabled for this env/app) or `enabled: false`, this does
|
|
3980
|
+
* nothing — `enabled` is the kill-switch even though `posthog-js` is bundled
|
|
3981
|
+
* into the bridge. Cross-origin replay needs `recordCrossOriginIframes` on both
|
|
3982
|
+
* sides so the parent receives the iframe's rrweb frames into one stitched
|
|
3983
|
+
* recording, and `identify()` ties the iframe's recording + events to the same
|
|
3984
|
+
* person as the host. Idempotent (the `posthogInitialized` guard) and wrapped
|
|
3985
|
+
* in try/catch so a duplicate push or a PostHog failure is harmless.
|
|
3986
|
+
*/
|
|
3987
|
+
private initPostHog;
|
|
3846
3988
|
/**
|
|
3847
3989
|
* Monkey-patches `history.pushState` and `history.replaceState` to
|
|
3848
3990
|
* auto-detect SPA navigation and report it to the host. Called after
|
|
@@ -3878,4 +4020,4 @@ declare class VibeAppBridge extends BridgeDataMethods {
|
|
|
3878
4020
|
private handleProgress;
|
|
3879
4021
|
}
|
|
3880
4022
|
|
|
3881
|
-
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 };
|
|
4023
|
+
export { version as BRIDGE_VERSION, BridgeError, type BridgeSubsidiary, type ContextPayload, HttpBridgeError, type InvalidateCachePayload, type InvalidateResult, type NavigateAction, type PostHogContext, type RequestRegistry, type SetSideNavPayload, type UploadOptions, type UploadProgress, type UploadResponse, VibeAppBridge, type VibeAppBridgeOptions };
|