@fork-api/chat-sdk 0.1.131 → 0.1.133

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.cts CHANGED
@@ -131,6 +131,52 @@ interface ForkSlotProps {
131
131
  }
132
132
  type ForkState = "idle" | "prompting" | "running" | "complete" | "error";
133
133
 
134
+ type PreviewTargetKind = "slot" | "module";
135
+
136
+ /**
137
+ * Phase 4 — preview-session client state, persistence, and pub/sub.
138
+ *
139
+ * One module owns:
140
+ * 1. sessionStorage I/O (namespaced by apiKey so multiple tenants can
141
+ * coexist on the same origin without trampling each other).
142
+ * 2. A tiny subscribe/notify model so React components — banner, provider
143
+ * hooks, sidebar — all share one source of truth and stay in lockstep
144
+ * across mount/unmount cycles.
145
+ *
146
+ * Why sessionStorage (not localStorage): a preview session is bound to a
147
+ * single tab. Closing the tab cancels the session; opening a second tab
148
+ * should NOT inherit somebody else's authoring state. sessionStorage
149
+ * mirrors that lifetime exactly.
150
+ *
151
+ * Why pub/sub over React context alone: the banner is mounted into a
152
+ * detached Shadow DOM root (separate render tree). It can't read context
153
+ * from the ForkProvider tree, so it subscribes to this module directly.
154
+ */
155
+
156
+ interface PreviewSessionPayload {
157
+ preview_session_id: string;
158
+ tenant_id: string;
159
+ app_id: string;
160
+ target: {
161
+ kind: PreviewTargetKind;
162
+ id: string;
163
+ };
164
+ target_user_id: string;
165
+ operator_id: number;
166
+ container_id?: string | null;
167
+ /** Human-readable container label for preview UI. Older sessions may not
168
+ * have this; callers should fall back to target_user_id. */
169
+ container_name?: string | null;
170
+ /** Seeded from activate(); the SDK updates it when authoring creates a
171
+ * new fork. Null when the operator just landed and hasn't authored. */
172
+ fork_id: string | null;
173
+ /** ISO-8601 expiration. The banner ticks against this; once past, the
174
+ * module clears storage on next access. */
175
+ expires_at: string;
176
+ }
177
+
178
+ declare function usePreviewSession(): PreviewSessionPayload | null;
179
+
134
180
  declare function ForkProvider(props: ForkProviderProps): react_jsx_runtime.JSX.Element;
135
181
 
136
182
  declare function ForkSlot({ slotId, props, children, allowedFetches, githubRepo, callbacks, mode, shared, events }: ForkSlotProps): react_jsx_runtime.JSX.Element;
@@ -173,7 +219,7 @@ interface ForkPanelProps {
173
219
  targetLabel?: string;
174
220
  historyMode?: "slot" | "boundary" | "none";
175
221
  examplePrompts?: string[];
176
- onSubmit: (prompt: string, targetId: string) => void;
222
+ onSubmit: (prompt: string, targetId: string, containerId?: string | null) => void;
177
223
  onUndo?: (targetId: string) => Promise<any>;
178
224
  onClose: () => void;
179
225
  baseUrl?: string;
@@ -198,7 +244,7 @@ declare function useFork(): {
198
244
  error: string | null;
199
245
  open: () => void;
200
246
  close: () => void;
201
- startFork: (prompt: string, slotId?: string) => Promise<void>;
247
+ startFork: (prompt: string, slotId?: string, containerId?: string | null) => Promise<void>;
202
248
  undoFork: (slotId: string) => Promise<any>;
203
249
  };
204
250
 
@@ -209,7 +255,7 @@ declare function useBoundaryFork(boundaryId: string): {
209
255
  error: string | null;
210
256
  open: () => void;
211
257
  close: () => void;
212
- startFork: (prompt: string) => Promise<void>;
258
+ startFork: (prompt: string, containerId?: string | null) => Promise<void>;
213
259
  undoFork: () => Promise<any>;
214
260
  };
215
261
 
@@ -218,13 +264,13 @@ declare function useForkChatPanel(options: ForkChatPanelOptions): {
218
264
  targetId: string;
219
265
  targetLabel: string | undefined;
220
266
  historyMode: "slot" | "boundary";
221
- submit: (prompt: string, submittedTargetId?: string) => Promise<void>;
267
+ submit: (prompt: string, submittedTargetId?: string, containerId?: string | null) => Promise<void>;
222
268
  undo: (submittedTargetId?: string) => Promise<any>;
223
269
  buttonProps: {
224
270
  onClick: () => void;
225
271
  };
226
272
  panelProps: {
227
- onSubmit: (prompt: string, submittedTargetId?: string) => Promise<void>;
273
+ onSubmit: (prompt: string, submittedTargetId?: string, containerId?: string | null) => Promise<void>;
228
274
  onUndo: (submittedTargetId?: string) => Promise<any>;
229
275
  onClose: () => void;
230
276
  baseUrl: string;
@@ -240,7 +286,7 @@ declare function useForkChatPanel(options: ForkChatPanelOptions): {
240
286
  events: ForkEvent[];
241
287
  error: string | null;
242
288
  } | {
243
- onSubmit: (prompt: string, submittedTargetId?: string) => Promise<void>;
289
+ onSubmit: (prompt: string, submittedTargetId?: string, containerId?: string | null) => Promise<void>;
244
290
  onUndo: (submittedTargetId?: string) => Promise<any>;
245
291
  onClose: () => void;
246
292
  baseUrl: string;
@@ -265,4 +311,99 @@ declare function useForkChatPanel(options: ForkChatPanelOptions): {
265
311
  close: () => void;
266
312
  };
267
313
 
268
- export { type Fork, type ForkBoundaryDefinition, ForkBoundaryUI, ForkButton, ForkChatInterface, type ForkChatInterfaceProps, type ForkChatPanelOptions, type ForkChatTarget, type ForkEvent, ForkPanel, ForkProvider, type ForkProviderProps, type ForkSharedRegistry, ForkSlot, type ForkSlotProps, type ForkState, ForkUI, forkable, registerForkShared, useBoundaryFork, useFork, useForkChatPanel };
314
+ /**
315
+ * Containers v2 — SDK-side manifest client.
316
+ *
317
+ * Resolves every slot + module fork for an end-user in a single round trip
318
+ * (vs. the per-slot fan-out the legacy /api/v1/forks/active path does), and
319
+ * provides stale-while-revalidate caching against localStorage so repeat
320
+ * visits paint with zero network latency.
321
+ *
322
+ * ForkProvider uses this for the normal end-user runtime path and for
323
+ * container-bound previews. Legacy preview sessions without a container still
324
+ * use the preview-aware overlay endpoints.
325
+ *
326
+ * Usage sketch:
327
+ *
328
+ * const cached = readCachedManifest(tenantId, appId, userId);
329
+ * if (cached) renderFrom(cached); // instant first paint
330
+ * loadManifest({...}).then((fresh) => {
331
+ * if (etagDiffers(cached, fresh)) renderFrom(fresh);
332
+ * writeCachedManifest(tenantId, appId, userId, fresh);
333
+ * });
334
+ *
335
+ * See §14 of docs/containers-independent-plan.html for the budget this
336
+ * module is built to hit (p99 ≤ 50ms cold, ≤ 30ms warm; perceptual instant
337
+ * on repeat visits).
338
+ */
339
+ interface ManifestEntry {
340
+ forkId: string;
341
+ /** Immutable, build-keyed URL — safe to cache forever in the browser. */
342
+ bundleUrl: string | null;
343
+ /** Pre-v2 bundle URL (mutable). Kept around so a partial-rollback SDK
344
+ * can still resolve forks that don't have a build_id yet. */
345
+ legacyBundleUrl: string | null;
346
+ buildId: string | null;
347
+ updatedAt: string;
348
+ }
349
+ interface ManifestModuleEntry {
350
+ forkId: string;
351
+ /** Immutable, build-keyed module URL when available. */
352
+ moduleUrl: string | null;
353
+ /** Pre-v2 module URL from module_overrides.module_url. */
354
+ legacyModuleUrl: string | null;
355
+ /** Back-compat aliases while API and SDK versions overlap. */
356
+ bundleUrl?: string | null;
357
+ legacyBundleUrl?: string | null;
358
+ cssUrls: string[];
359
+ integrity?: string;
360
+ metadata?: Record<string, unknown>;
361
+ buildId: string | null;
362
+ updatedAt: string;
363
+ }
364
+ interface Manifest {
365
+ containerId: string | null;
366
+ slots: Record<string, ManifestEntry>;
367
+ modules: Record<string, ManifestModuleEntry>;
368
+ generatedAt: string;
369
+ /** Server-supplied ETag (from response header). Used to short-circuit the
370
+ * background refresh when nothing's changed. */
371
+ etag?: string;
372
+ }
373
+ interface LoadManifestInput {
374
+ /** Base URL of the Fork API. Pass without trailing slash. */
375
+ baseUrl: string;
376
+ /** Publishable key (pk_fork_…) — passed as Bearer. */
377
+ apiKey: string;
378
+ appId: string;
379
+ /** Verified user id. The server requires either this or a userHash. */
380
+ userId: string;
381
+ /** Optional userHash for HMAC verification. */
382
+ userHash?: string;
383
+ /** Authorized explicit container lookup, used for container-bound previews. */
384
+ containerId?: string;
385
+ /** Additional trusted headers, e.g. preview session headers. */
386
+ extraHeaders?: Record<string, string>;
387
+ /** Previous manifest, if any — its etag is sent as If-None-Match. */
388
+ previous?: Manifest;
389
+ /** AbortSignal for cancellation. */
390
+ signal?: AbortSignal;
391
+ }
392
+ /**
393
+ * Fetch the manifest. Returns null when the server replies 304 Not Modified
394
+ * (caller keeps the previous manifest). Throws on network/HTTP errors.
395
+ */
396
+ declare function loadManifest(input: LoadManifestInput): Promise<Manifest | null>;
397
+ /** Read a previously-cached manifest. Returns null if absent or corrupted. */
398
+ declare function readCachedManifest(tenantId: string, appId: string, userId: string): Manifest | null;
399
+ /** Write a manifest to the cache. Best-effort — quota errors are swallowed. */
400
+ declare function writeCachedManifest(tenantId: string, appId: string, userId: string, manifest: Manifest): void;
401
+ /** Clear the cached manifest for a (tenant, app, user). */
402
+ declare function clearCachedManifest(tenantId: string, appId: string, userId: string): void;
403
+ /**
404
+ * Compare the resolved fork ids + build ids of two manifests. Returns true
405
+ * when anything user-visible has changed (so the caller should hot-swap).
406
+ */
407
+ declare function manifestDiffers(a: Manifest | null, b: Manifest | null): boolean;
408
+
409
+ export { type Fork, type ForkBoundaryDefinition, ForkBoundaryUI, ForkButton, ForkChatInterface, type ForkChatInterfaceProps, type ForkChatPanelOptions, type ForkChatTarget, type ForkEvent, ForkPanel, ForkProvider, type ForkProviderProps, type ForkSharedRegistry, ForkSlot, type ForkSlotProps, type ForkState, ForkUI, type LoadManifestInput, type Manifest, type ManifestEntry, type ManifestModuleEntry, type PreviewSessionPayload, clearCachedManifest, forkable, loadManifest, manifestDiffers, readCachedManifest, registerForkShared, useBoundaryFork, useFork, useForkChatPanel, usePreviewSession, writeCachedManifest };
package/dist/index.d.ts CHANGED
@@ -131,6 +131,52 @@ interface ForkSlotProps {
131
131
  }
132
132
  type ForkState = "idle" | "prompting" | "running" | "complete" | "error";
133
133
 
134
+ type PreviewTargetKind = "slot" | "module";
135
+
136
+ /**
137
+ * Phase 4 — preview-session client state, persistence, and pub/sub.
138
+ *
139
+ * One module owns:
140
+ * 1. sessionStorage I/O (namespaced by apiKey so multiple tenants can
141
+ * coexist on the same origin without trampling each other).
142
+ * 2. A tiny subscribe/notify model so React components — banner, provider
143
+ * hooks, sidebar — all share one source of truth and stay in lockstep
144
+ * across mount/unmount cycles.
145
+ *
146
+ * Why sessionStorage (not localStorage): a preview session is bound to a
147
+ * single tab. Closing the tab cancels the session; opening a second tab
148
+ * should NOT inherit somebody else's authoring state. sessionStorage
149
+ * mirrors that lifetime exactly.
150
+ *
151
+ * Why pub/sub over React context alone: the banner is mounted into a
152
+ * detached Shadow DOM root (separate render tree). It can't read context
153
+ * from the ForkProvider tree, so it subscribes to this module directly.
154
+ */
155
+
156
+ interface PreviewSessionPayload {
157
+ preview_session_id: string;
158
+ tenant_id: string;
159
+ app_id: string;
160
+ target: {
161
+ kind: PreviewTargetKind;
162
+ id: string;
163
+ };
164
+ target_user_id: string;
165
+ operator_id: number;
166
+ container_id?: string | null;
167
+ /** Human-readable container label for preview UI. Older sessions may not
168
+ * have this; callers should fall back to target_user_id. */
169
+ container_name?: string | null;
170
+ /** Seeded from activate(); the SDK updates it when authoring creates a
171
+ * new fork. Null when the operator just landed and hasn't authored. */
172
+ fork_id: string | null;
173
+ /** ISO-8601 expiration. The banner ticks against this; once past, the
174
+ * module clears storage on next access. */
175
+ expires_at: string;
176
+ }
177
+
178
+ declare function usePreviewSession(): PreviewSessionPayload | null;
179
+
134
180
  declare function ForkProvider(props: ForkProviderProps): react_jsx_runtime.JSX.Element;
135
181
 
136
182
  declare function ForkSlot({ slotId, props, children, allowedFetches, githubRepo, callbacks, mode, shared, events }: ForkSlotProps): react_jsx_runtime.JSX.Element;
@@ -173,7 +219,7 @@ interface ForkPanelProps {
173
219
  targetLabel?: string;
174
220
  historyMode?: "slot" | "boundary" | "none";
175
221
  examplePrompts?: string[];
176
- onSubmit: (prompt: string, targetId: string) => void;
222
+ onSubmit: (prompt: string, targetId: string, containerId?: string | null) => void;
177
223
  onUndo?: (targetId: string) => Promise<any>;
178
224
  onClose: () => void;
179
225
  baseUrl?: string;
@@ -198,7 +244,7 @@ declare function useFork(): {
198
244
  error: string | null;
199
245
  open: () => void;
200
246
  close: () => void;
201
- startFork: (prompt: string, slotId?: string) => Promise<void>;
247
+ startFork: (prompt: string, slotId?: string, containerId?: string | null) => Promise<void>;
202
248
  undoFork: (slotId: string) => Promise<any>;
203
249
  };
204
250
 
@@ -209,7 +255,7 @@ declare function useBoundaryFork(boundaryId: string): {
209
255
  error: string | null;
210
256
  open: () => void;
211
257
  close: () => void;
212
- startFork: (prompt: string) => Promise<void>;
258
+ startFork: (prompt: string, containerId?: string | null) => Promise<void>;
213
259
  undoFork: () => Promise<any>;
214
260
  };
215
261
 
@@ -218,13 +264,13 @@ declare function useForkChatPanel(options: ForkChatPanelOptions): {
218
264
  targetId: string;
219
265
  targetLabel: string | undefined;
220
266
  historyMode: "slot" | "boundary";
221
- submit: (prompt: string, submittedTargetId?: string) => Promise<void>;
267
+ submit: (prompt: string, submittedTargetId?: string, containerId?: string | null) => Promise<void>;
222
268
  undo: (submittedTargetId?: string) => Promise<any>;
223
269
  buttonProps: {
224
270
  onClick: () => void;
225
271
  };
226
272
  panelProps: {
227
- onSubmit: (prompt: string, submittedTargetId?: string) => Promise<void>;
273
+ onSubmit: (prompt: string, submittedTargetId?: string, containerId?: string | null) => Promise<void>;
228
274
  onUndo: (submittedTargetId?: string) => Promise<any>;
229
275
  onClose: () => void;
230
276
  baseUrl: string;
@@ -240,7 +286,7 @@ declare function useForkChatPanel(options: ForkChatPanelOptions): {
240
286
  events: ForkEvent[];
241
287
  error: string | null;
242
288
  } | {
243
- onSubmit: (prompt: string, submittedTargetId?: string) => Promise<void>;
289
+ onSubmit: (prompt: string, submittedTargetId?: string, containerId?: string | null) => Promise<void>;
244
290
  onUndo: (submittedTargetId?: string) => Promise<any>;
245
291
  onClose: () => void;
246
292
  baseUrl: string;
@@ -265,4 +311,99 @@ declare function useForkChatPanel(options: ForkChatPanelOptions): {
265
311
  close: () => void;
266
312
  };
267
313
 
268
- export { type Fork, type ForkBoundaryDefinition, ForkBoundaryUI, ForkButton, ForkChatInterface, type ForkChatInterfaceProps, type ForkChatPanelOptions, type ForkChatTarget, type ForkEvent, ForkPanel, ForkProvider, type ForkProviderProps, type ForkSharedRegistry, ForkSlot, type ForkSlotProps, type ForkState, ForkUI, forkable, registerForkShared, useBoundaryFork, useFork, useForkChatPanel };
314
+ /**
315
+ * Containers v2 — SDK-side manifest client.
316
+ *
317
+ * Resolves every slot + module fork for an end-user in a single round trip
318
+ * (vs. the per-slot fan-out the legacy /api/v1/forks/active path does), and
319
+ * provides stale-while-revalidate caching against localStorage so repeat
320
+ * visits paint with zero network latency.
321
+ *
322
+ * ForkProvider uses this for the normal end-user runtime path and for
323
+ * container-bound previews. Legacy preview sessions without a container still
324
+ * use the preview-aware overlay endpoints.
325
+ *
326
+ * Usage sketch:
327
+ *
328
+ * const cached = readCachedManifest(tenantId, appId, userId);
329
+ * if (cached) renderFrom(cached); // instant first paint
330
+ * loadManifest({...}).then((fresh) => {
331
+ * if (etagDiffers(cached, fresh)) renderFrom(fresh);
332
+ * writeCachedManifest(tenantId, appId, userId, fresh);
333
+ * });
334
+ *
335
+ * See §14 of docs/containers-independent-plan.html for the budget this
336
+ * module is built to hit (p99 ≤ 50ms cold, ≤ 30ms warm; perceptual instant
337
+ * on repeat visits).
338
+ */
339
+ interface ManifestEntry {
340
+ forkId: string;
341
+ /** Immutable, build-keyed URL — safe to cache forever in the browser. */
342
+ bundleUrl: string | null;
343
+ /** Pre-v2 bundle URL (mutable). Kept around so a partial-rollback SDK
344
+ * can still resolve forks that don't have a build_id yet. */
345
+ legacyBundleUrl: string | null;
346
+ buildId: string | null;
347
+ updatedAt: string;
348
+ }
349
+ interface ManifestModuleEntry {
350
+ forkId: string;
351
+ /** Immutable, build-keyed module URL when available. */
352
+ moduleUrl: string | null;
353
+ /** Pre-v2 module URL from module_overrides.module_url. */
354
+ legacyModuleUrl: string | null;
355
+ /** Back-compat aliases while API and SDK versions overlap. */
356
+ bundleUrl?: string | null;
357
+ legacyBundleUrl?: string | null;
358
+ cssUrls: string[];
359
+ integrity?: string;
360
+ metadata?: Record<string, unknown>;
361
+ buildId: string | null;
362
+ updatedAt: string;
363
+ }
364
+ interface Manifest {
365
+ containerId: string | null;
366
+ slots: Record<string, ManifestEntry>;
367
+ modules: Record<string, ManifestModuleEntry>;
368
+ generatedAt: string;
369
+ /** Server-supplied ETag (from response header). Used to short-circuit the
370
+ * background refresh when nothing's changed. */
371
+ etag?: string;
372
+ }
373
+ interface LoadManifestInput {
374
+ /** Base URL of the Fork API. Pass without trailing slash. */
375
+ baseUrl: string;
376
+ /** Publishable key (pk_fork_…) — passed as Bearer. */
377
+ apiKey: string;
378
+ appId: string;
379
+ /** Verified user id. The server requires either this or a userHash. */
380
+ userId: string;
381
+ /** Optional userHash for HMAC verification. */
382
+ userHash?: string;
383
+ /** Authorized explicit container lookup, used for container-bound previews. */
384
+ containerId?: string;
385
+ /** Additional trusted headers, e.g. preview session headers. */
386
+ extraHeaders?: Record<string, string>;
387
+ /** Previous manifest, if any — its etag is sent as If-None-Match. */
388
+ previous?: Manifest;
389
+ /** AbortSignal for cancellation. */
390
+ signal?: AbortSignal;
391
+ }
392
+ /**
393
+ * Fetch the manifest. Returns null when the server replies 304 Not Modified
394
+ * (caller keeps the previous manifest). Throws on network/HTTP errors.
395
+ */
396
+ declare function loadManifest(input: LoadManifestInput): Promise<Manifest | null>;
397
+ /** Read a previously-cached manifest. Returns null if absent or corrupted. */
398
+ declare function readCachedManifest(tenantId: string, appId: string, userId: string): Manifest | null;
399
+ /** Write a manifest to the cache. Best-effort — quota errors are swallowed. */
400
+ declare function writeCachedManifest(tenantId: string, appId: string, userId: string, manifest: Manifest): void;
401
+ /** Clear the cached manifest for a (tenant, app, user). */
402
+ declare function clearCachedManifest(tenantId: string, appId: string, userId: string): void;
403
+ /**
404
+ * Compare the resolved fork ids + build ids of two manifests. Returns true
405
+ * when anything user-visible has changed (so the caller should hot-swap).
406
+ */
407
+ declare function manifestDiffers(a: Manifest | null, b: Manifest | null): boolean;
408
+
409
+ export { type Fork, type ForkBoundaryDefinition, ForkBoundaryUI, ForkButton, ForkChatInterface, type ForkChatInterfaceProps, type ForkChatPanelOptions, type ForkChatTarget, type ForkEvent, ForkPanel, ForkProvider, type ForkProviderProps, type ForkSharedRegistry, ForkSlot, type ForkSlotProps, type ForkState, ForkUI, type LoadManifestInput, type Manifest, type ManifestEntry, type ManifestModuleEntry, type PreviewSessionPayload, clearCachedManifest, forkable, loadManifest, manifestDiffers, readCachedManifest, registerForkShared, useBoundaryFork, useFork, useForkChatPanel, usePreviewSession, writeCachedManifest };