@lumibase/sdk 0.14.0 → 0.15.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.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  ACCESS_EXPORT_SCHEMA: () => ACCESS_EXPORT_SCHEMA,
24
+ AudienceClient: () => AudienceClient,
24
25
  LumiError: () => LumiError,
25
26
  RealtimeClient: () => RealtimeClient,
26
27
  checkCdcPipelineHealth: () => checkCdcPipelineHealth,
@@ -147,6 +148,165 @@ function createLumiClient(opts) {
147
148
  // src/types.ts
148
149
  var ACCESS_EXPORT_SCHEMA = "lumibase.access@v1";
149
150
 
151
+ // src/realtime/audience.ts
152
+ var WS_OPEN = 1;
153
+ var AudienceClient = class {
154
+ constructor(opts) {
155
+ this.opts = opts;
156
+ this.backoffMs = opts.initialBackoffMs ?? 1e3;
157
+ for (const c of opts.channels ?? []) this.channels.add(c);
158
+ }
159
+ opts;
160
+ ws = null;
161
+ channels = /* @__PURE__ */ new Set();
162
+ channelListeners = /* @__PURE__ */ new Set();
163
+ notificationListeners = /* @__PURE__ */ new Set();
164
+ statusListeners = /* @__PURE__ */ new Set();
165
+ reconnectTimer = null;
166
+ backoffMs;
167
+ stopped = false;
168
+ _status = "closed";
169
+ // ─── Public API ─────────────────────────────────────────────────────────────
170
+ get status() {
171
+ return this._status;
172
+ }
173
+ connect() {
174
+ this.stopped = false;
175
+ void this._connect();
176
+ return this;
177
+ }
178
+ disconnect() {
179
+ this.stopped = true;
180
+ if (this.reconnectTimer) {
181
+ clearTimeout(this.reconnectTimer);
182
+ this.reconnectTimer = null;
183
+ }
184
+ if (this.ws) {
185
+ try {
186
+ this.ws.close(1e3, "client disconnect");
187
+ } catch {
188
+ }
189
+ this.ws = null;
190
+ }
191
+ this.setStatus("closed");
192
+ }
193
+ /** Join a channel. Remembered and re-joined across reconnects. */
194
+ join(channel) {
195
+ this.channels.add(channel);
196
+ this.sendIfOpen({ type: "join", channel });
197
+ }
198
+ /** Leave a channel and stop re-joining it. */
199
+ leave(channel) {
200
+ this.channels.delete(channel);
201
+ this.sendIfOpen({ type: "leave", channel });
202
+ }
203
+ onChannelEvent(cb) {
204
+ this.channelListeners.add(cb);
205
+ return () => this.channelListeners.delete(cb);
206
+ }
207
+ onNotification(cb) {
208
+ this.notificationListeners.add(cb);
209
+ return () => this.notificationListeners.delete(cb);
210
+ }
211
+ onStatus(cb) {
212
+ this.statusListeners.add(cb);
213
+ return () => this.statusListeners.delete(cb);
214
+ }
215
+ // ─── Internal ────────────────────────────────────────────────────────────────
216
+ async _connect() {
217
+ if (this.ws) return;
218
+ this.setStatus("connecting");
219
+ const doFetch = this.opts.fetchImpl ?? fetch;
220
+ let ticket;
221
+ try {
222
+ const res = await doFetch(`${this.opts.baseUrl}/api/v1/realtime/audience-ticket`, {
223
+ method: "POST",
224
+ headers: {
225
+ Authorization: `Bearer ${this.opts.token}`,
226
+ "X-Lumi-Site": this.opts.siteId,
227
+ "Content-Type": "application/json"
228
+ },
229
+ body: JSON.stringify({ channels: Array.from(this.channels) })
230
+ });
231
+ if (!res.ok) throw new Error(`audience-ticket failed: ${res.status}`);
232
+ const body = await res.json();
233
+ if (!body.data?.ticket) throw new Error("ticket missing");
234
+ ticket = body.data.ticket;
235
+ } catch {
236
+ this.scheduleReconnect();
237
+ return;
238
+ }
239
+ if (this.stopped) return;
240
+ const wsBase = this.opts.baseUrl.replace(/^http/, "ws");
241
+ const url = `${wsBase}/api/v1/realtime?ticket=${encodeURIComponent(ticket)}`;
242
+ const factory = this.opts.webSocketFactory ?? ((u) => new WebSocket(u));
243
+ let ws;
244
+ try {
245
+ ws = factory(url);
246
+ } catch {
247
+ this.scheduleReconnect();
248
+ return;
249
+ }
250
+ this.ws = ws;
251
+ ws.addEventListener("open", () => {
252
+ this.backoffMs = this.opts.initialBackoffMs ?? 1e3;
253
+ this.setStatus("open");
254
+ for (const channel of this.channels) this.sendRaw({ type: "join", channel });
255
+ });
256
+ ws.addEventListener("message", (ev) => {
257
+ let msg;
258
+ try {
259
+ msg = JSON.parse(ev.data);
260
+ } catch {
261
+ return;
262
+ }
263
+ this.handleMessage(msg);
264
+ });
265
+ ws.addEventListener("close", () => {
266
+ this.ws = null;
267
+ this.setStatus("closed");
268
+ if (!this.stopped) this.scheduleReconnect();
269
+ });
270
+ ws.addEventListener("error", () => {
271
+ });
272
+ }
273
+ handleMessage(msg) {
274
+ switch (msg.type) {
275
+ case "ping":
276
+ this.sendRaw({ type: "pong" });
277
+ break;
278
+ case "event":
279
+ for (const cb of this.channelListeners) cb(msg);
280
+ break;
281
+ case "notification":
282
+ for (const cb of this.notificationListeners) cb(msg);
283
+ break;
284
+ }
285
+ }
286
+ scheduleReconnect() {
287
+ if (this.stopped || this.reconnectTimer) return;
288
+ this.reconnectTimer = setTimeout(() => {
289
+ this.reconnectTimer = null;
290
+ void this._connect();
291
+ this.backoffMs = Math.min(this.backoffMs * 2, this.opts.maxBackoffMs ?? 3e4);
292
+ }, this.backoffMs);
293
+ }
294
+ setStatus(status) {
295
+ if (this._status === status) return;
296
+ this._status = status;
297
+ for (const cb of this.statusListeners) cb(status);
298
+ }
299
+ sendIfOpen(data) {
300
+ if (this.ws && this.ws.readyState === WS_OPEN) this.sendRaw(data);
301
+ }
302
+ sendRaw(data) {
303
+ try {
304
+ this.ws?.send(JSON.stringify(data));
305
+ } catch {
306
+ }
307
+ }
308
+ };
309
+
150
310
  // src/realtime/index.ts
151
311
  var RealtimeClient = class {
152
312
  constructor(opts) {
@@ -1330,6 +1490,7 @@ function jsonLdScript(item) {
1330
1490
  // Annotate the CommonJS export names for ESM import in node:
1331
1491
  0 && (module.exports = {
1332
1492
  ACCESS_EXPORT_SCHEMA,
1493
+ AudienceClient,
1333
1494
  LumiError,
1334
1495
  RealtimeClient,
1335
1496
  checkCdcPipelineHealth,
package/dist/index.d.cts CHANGED
@@ -1293,6 +1293,90 @@ interface LumiClient<TSchema extends DefaultSchema = DefaultSchema> {
1293
1293
  }
1294
1294
  declare function createLumiClient<TSchema extends DefaultSchema = DefaultSchema>(opts: LumiClientOptions): LumiClient<TSchema>;
1295
1295
 
1296
+ /**
1297
+ * AudienceClient — realtime client for FRONTEND end-users (the public plane).
1298
+ *
1299
+ * End-users are addressed by a `subjectId` (mapped server-side from e.g. a
1300
+ * citizenID) and by channels they are granted at ticket time. This client:
1301
+ * - fetches a short-lived audience ticket from `/api/v1/realtime/audience-ticket`;
1302
+ * - opens the WebSocket and (re)joins channels;
1303
+ * - surfaces per-channel events and personal notifications;
1304
+ * - reconnects with exponential backoff and re-joins open channels.
1305
+ *
1306
+ * The Studio (admin) plane uses the separate `RealtimeClient` in `./index`.
1307
+ */
1308
+ interface AudienceEvent {
1309
+ type: 'event';
1310
+ channel?: string;
1311
+ collection?: string;
1312
+ action?: 'create' | 'update' | 'delete';
1313
+ itemId?: string;
1314
+ payload: unknown;
1315
+ }
1316
+ interface AudienceNotification {
1317
+ type: 'notification';
1318
+ payload: Record<string, unknown>;
1319
+ }
1320
+ type ChannelEventCallback = (event: AudienceEvent) => void;
1321
+ type NotificationCallback = (notification: AudienceNotification) => void;
1322
+ type ConnectionStatus = 'connecting' | 'open' | 'closed';
1323
+ type StatusCallback = (status: ConnectionStatus) => void;
1324
+ /** Minimal structural WebSocket — lets tests inject a fake. */
1325
+ interface WebSocketLike {
1326
+ readyState: number;
1327
+ send(data: string): void;
1328
+ close(code?: number, reason?: string): void;
1329
+ addEventListener(type: 'open' | 'message' | 'close' | 'error', handler: (ev: any) => void): void;
1330
+ }
1331
+ type WebSocketFactory = (url: string) => WebSocketLike;
1332
+ interface AudienceClientOptions {
1333
+ /** Base HTTP URL of the CMS. `wss://` is derived automatically. */
1334
+ baseUrl: string;
1335
+ /**
1336
+ * Bearer token for the authenticated FRONTEND end-user. Exchanged for a
1337
+ * short-lived audience ticket; never sent over the socket.
1338
+ */
1339
+ token: string;
1340
+ siteId: string;
1341
+ /** Channels to request access to (subject to the server-side allowlist). */
1342
+ channels?: string[];
1343
+ initialBackoffMs?: number;
1344
+ maxBackoffMs?: number;
1345
+ /** Injectable WebSocket factory (defaults to the global `WebSocket`). */
1346
+ webSocketFactory?: WebSocketFactory;
1347
+ /** Injectable fetch (defaults to the global `fetch`). */
1348
+ fetchImpl?: typeof fetch;
1349
+ }
1350
+ declare class AudienceClient {
1351
+ private readonly opts;
1352
+ private ws;
1353
+ private readonly channels;
1354
+ private readonly channelListeners;
1355
+ private readonly notificationListeners;
1356
+ private readonly statusListeners;
1357
+ private reconnectTimer;
1358
+ private backoffMs;
1359
+ private stopped;
1360
+ private _status;
1361
+ constructor(opts: AudienceClientOptions);
1362
+ get status(): ConnectionStatus;
1363
+ connect(): this;
1364
+ disconnect(): void;
1365
+ /** Join a channel. Remembered and re-joined across reconnects. */
1366
+ join(channel: string): void;
1367
+ /** Leave a channel and stop re-joining it. */
1368
+ leave(channel: string): void;
1369
+ onChannelEvent(cb: ChannelEventCallback): () => void;
1370
+ onNotification(cb: NotificationCallback): () => void;
1371
+ onStatus(cb: StatusCallback): () => void;
1372
+ private _connect;
1373
+ private handleMessage;
1374
+ private scheduleReconnect;
1375
+ private setStatus;
1376
+ private sendIfOpen;
1377
+ private sendRaw;
1378
+ }
1379
+
1296
1380
  /**
1297
1381
  * RealtimeClient — typed WebSocket client for the LumiBase realtime API.
1298
1382
  *
@@ -1311,6 +1395,7 @@ declare function createLumiClient<TSchema extends DefaultSchema = DefaultSchema>
1311
1395
  * // ... later
1312
1396
  * rt.disconnect();
1313
1397
  */
1398
+
1314
1399
  interface RealtimeEvent {
1315
1400
  type: 'event';
1316
1401
  collection: string;
@@ -1861,4 +1946,4 @@ declare function toNextMetadata(item: unknown): Record<string, unknown>;
1861
1946
  */
1862
1947
  declare function jsonLdScript(item: unknown): string | undefined;
1863
1948
 
1864
- export { ACCESS_EXPORT_SCHEMA, type AIApproval, type AIApprovalStatus, type AIChatResponse, type AIChatStatus, type AIContentAssistResult, type AIConversation, type AIFieldSuggestion, type AIMessage, type AccessConflict, type AccessConflictCheckInput, type AccessConflictReport, type AccessExportApiKey, type AccessExportBindings, type AccessExportManifest, type AccessExportPermission, type AccessExportPolicy, type AccessExportRole, type AccessImportApplyResult, type AccessImportDiff, type AccessImportDiffEntry, type AccessImportDiffSection, type AccessImportDryRunResult, type AccessImportIssue, type AccessImportMode, type AccessImportOptions, type AccessImportSummary, type ActivityResource, type AgentApprovalResource, type AgentArtifactCreateInput, type AgentArtifactResource, type AgentArtifactType, type AgentEvaluationResource, type AgentGenerateAppInput, type AgentGenerateAppResult, type AgentGoalCreateInput, type AgentGoalResource, type AgentMemoryContext, type AgentMemoryResource, type AgentMemoryWriteInput, type AgentRiskLevel, type AgentRunResource, type AgentToolResource, type ApiKeyCreateInput, type ApiKeyPolicyAttachment, type ApiKeyResource, type ApiKeyRoleAttachment, type ApiKeyRotateInput, type ApiKeySecretResult, type Brand, type CdcConnectorType, type CdcDeployInput, type CdcDeploymentResult, type CdcDeploymentStatus, type CdcDeploymentStep, type CdcDeploymentTarget, type CdcEnvValidationResult, type CdcHealthCheckResult, type CdcHealthMetricEntry, type CdcPipelineCreateInput, type CdcPipelineMetrics, type CdcPipelinePatchInput, type CdcPipelineResource, type CdcPipelineStatus, type CdcRollbackResult, type CdcValidateEnvInput, type CollectionInput, type CollectionResource, type CompiledPermission, type CreateSCIMTokenParams, type DefaultSchema, type DeliverySeo, type DeploymentResource, type DeploymentTargetResource, type ExtensionResource, type FieldDeleteOptions, type FieldInput, type FieldMutationOptions, type FieldRenameInput, type FieldResource, type FileResource, type FlowGraph, type FlowNode, type FlowResource, type FlowRun, type FlowRunResult, type FlowRunStatus, type FlowStatus, type FlowTriggerType, type FolderResource, type GenerateOptions, type GraphQLExtension, type ID, type ItemFilter, type ItemFilterOp, type ItemRow, type ListItemsParams, type ListItemsResponse, type ListMarketplaceExtensionsParams, type Locale, type LumiClient, type LumiClientOptions, LumiError, type LumiErrorBody, type LumiResponse, type MarketplaceExtension, type MarketplaceListResponse, type MaterializeDataResponse, type MaterializeProjection, type MaterializeRefreshResult, type MaterializeRefreshStrategy, type MaterializedCollection, type PermissionAction, type PermissionBundle, type PermissionCheckResult, type PermissionRow, type PolicyDetail, type PolicyResource, type PresenceCallback, type PresenceEntry, type PresetResource, type PrimaryKeyType, RealtimeClient, type RealtimeEvent, type RealtimeEventCallback, type RelationInput, type RelationResource, type RelationType, type RevisionRow, type RoleDetail, type RoleResource, type SCIMTokenCreated, type SCIMTokenMeta, type SCIMTokenRotated, type SchemaApplyInput, type SchemaApplyResult, type SchemaChangedEvent, type SchemaDiff, type SchemaDiffEntry, type SchemaDiffInput, type SchemaDiffRisk, type SchemaRuntimeImpact, type SearchHit, type SearchHitMeta, type SearchParams, type SearchResponse, type SettingResource, type ShareCreateInput, type ShareResource, type ShareSecretResult, type SiteConfigUpdate, type SiteResource, type StorageMode, type TeamMemberResource, type TeamResource, type TranslationResource, type TypegenCollection, type TypegenField, type TypegenManifest, type TypegenRelation, type TypegenSchemaFilters, type UserPreferencesPayload, type UserResource, type WebhookResource, checkCdcPipelineHealth, createAgentArtifact, createAgentGoal, createCdcPipeline, createLumiClient, decideAgentApproval, deleteCdcPipeline, deployCdc, dryRunAccessImport, evaluateAgentArtifact, exportAccessManifest, extractSeo, generateAgentApp, generateTypes, graphql, importAccessManifest, jsonLdScript, legacyRest, listAgentApprovals, listAgentArtifacts, listAgentGoals, listAgentRuns, listAgentTools, listCdcPipelines, publishAgentArtifact, readAgentMemoryContext, readCdcPipeline, readCdcPipelineMetricHistory, readCdcPipelineMetrics, readItem, readItems, retryAgentRun, rollbackAgentArtifact, rollbackCdcDeployment, search, startCdcPipeline, stopCdcPipeline, toNextMetadata, updateCdcPipeline, validateCdcDeploymentEnv, writeAgentMemory };
1949
+ export { ACCESS_EXPORT_SCHEMA, type AIApproval, type AIApprovalStatus, type AIChatResponse, type AIChatStatus, type AIContentAssistResult, type AIConversation, type AIFieldSuggestion, type AIMessage, type AccessConflict, type AccessConflictCheckInput, type AccessConflictReport, type AccessExportApiKey, type AccessExportBindings, type AccessExportManifest, type AccessExportPermission, type AccessExportPolicy, type AccessExportRole, type AccessImportApplyResult, type AccessImportDiff, type AccessImportDiffEntry, type AccessImportDiffSection, type AccessImportDryRunResult, type AccessImportIssue, type AccessImportMode, type AccessImportOptions, type AccessImportSummary, type ActivityResource, type AgentApprovalResource, type AgentArtifactCreateInput, type AgentArtifactResource, type AgentArtifactType, type AgentEvaluationResource, type AgentGenerateAppInput, type AgentGenerateAppResult, type AgentGoalCreateInput, type AgentGoalResource, type AgentMemoryContext, type AgentMemoryResource, type AgentMemoryWriteInput, type AgentRiskLevel, type AgentRunResource, type AgentToolResource, type ApiKeyCreateInput, type ApiKeyPolicyAttachment, type ApiKeyResource, type ApiKeyRoleAttachment, type ApiKeyRotateInput, type ApiKeySecretResult, AudienceClient, type AudienceClientOptions, type AudienceEvent, type AudienceNotification, type Brand, type CdcConnectorType, type CdcDeployInput, type CdcDeploymentResult, type CdcDeploymentStatus, type CdcDeploymentStep, type CdcDeploymentTarget, type CdcEnvValidationResult, type CdcHealthCheckResult, type CdcHealthMetricEntry, type CdcPipelineCreateInput, type CdcPipelineMetrics, type CdcPipelinePatchInput, type CdcPipelineResource, type CdcPipelineStatus, type CdcRollbackResult, type CdcValidateEnvInput, type ChannelEventCallback, type CollectionInput, type CollectionResource, type CompiledPermission, type ConnectionStatus, type CreateSCIMTokenParams, type DefaultSchema, type DeliverySeo, type DeploymentResource, type DeploymentTargetResource, type ExtensionResource, type FieldDeleteOptions, type FieldInput, type FieldMutationOptions, type FieldRenameInput, type FieldResource, type FileResource, type FlowGraph, type FlowNode, type FlowResource, type FlowRun, type FlowRunResult, type FlowRunStatus, type FlowStatus, type FlowTriggerType, type FolderResource, type GenerateOptions, type GraphQLExtension, type ID, type ItemFilter, type ItemFilterOp, type ItemRow, type ListItemsParams, type ListItemsResponse, type ListMarketplaceExtensionsParams, type Locale, type LumiClient, type LumiClientOptions, LumiError, type LumiErrorBody, type LumiResponse, type MarketplaceExtension, type MarketplaceListResponse, type MaterializeDataResponse, type MaterializeProjection, type MaterializeRefreshResult, type MaterializeRefreshStrategy, type MaterializedCollection, type NotificationCallback, type PermissionAction, type PermissionBundle, type PermissionCheckResult, type PermissionRow, type PolicyDetail, type PolicyResource, type PresenceCallback, type PresenceEntry, type PresetResource, type PrimaryKeyType, RealtimeClient, type RealtimeEvent, type RealtimeEventCallback, type RelationInput, type RelationResource, type RelationType, type RevisionRow, type RoleDetail, type RoleResource, type SCIMTokenCreated, type SCIMTokenMeta, type SCIMTokenRotated, type SchemaApplyInput, type SchemaApplyResult, type SchemaChangedEvent, type SchemaDiff, type SchemaDiffEntry, type SchemaDiffInput, type SchemaDiffRisk, type SchemaRuntimeImpact, type SearchHit, type SearchHitMeta, type SearchParams, type SearchResponse, type SettingResource, type ShareCreateInput, type ShareResource, type ShareSecretResult, type SiteConfigUpdate, type SiteResource, type StatusCallback, type StorageMode, type TeamMemberResource, type TeamResource, type TranslationResource, type TypegenCollection, type TypegenField, type TypegenManifest, type TypegenRelation, type TypegenSchemaFilters, type UserPreferencesPayload, type UserResource, type WebSocketFactory, type WebSocketLike, type WebhookResource, checkCdcPipelineHealth, createAgentArtifact, createAgentGoal, createCdcPipeline, createLumiClient, decideAgentApproval, deleteCdcPipeline, deployCdc, dryRunAccessImport, evaluateAgentArtifact, exportAccessManifest, extractSeo, generateAgentApp, generateTypes, graphql, importAccessManifest, jsonLdScript, legacyRest, listAgentApprovals, listAgentArtifacts, listAgentGoals, listAgentRuns, listAgentTools, listCdcPipelines, publishAgentArtifact, readAgentMemoryContext, readCdcPipeline, readCdcPipelineMetricHistory, readCdcPipelineMetrics, readItem, readItems, retryAgentRun, rollbackAgentArtifact, rollbackCdcDeployment, search, startCdcPipeline, stopCdcPipeline, toNextMetadata, updateCdcPipeline, validateCdcDeploymentEnv, writeAgentMemory };
package/dist/index.d.ts CHANGED
@@ -1293,6 +1293,90 @@ interface LumiClient<TSchema extends DefaultSchema = DefaultSchema> {
1293
1293
  }
1294
1294
  declare function createLumiClient<TSchema extends DefaultSchema = DefaultSchema>(opts: LumiClientOptions): LumiClient<TSchema>;
1295
1295
 
1296
+ /**
1297
+ * AudienceClient — realtime client for FRONTEND end-users (the public plane).
1298
+ *
1299
+ * End-users are addressed by a `subjectId` (mapped server-side from e.g. a
1300
+ * citizenID) and by channels they are granted at ticket time. This client:
1301
+ * - fetches a short-lived audience ticket from `/api/v1/realtime/audience-ticket`;
1302
+ * - opens the WebSocket and (re)joins channels;
1303
+ * - surfaces per-channel events and personal notifications;
1304
+ * - reconnects with exponential backoff and re-joins open channels.
1305
+ *
1306
+ * The Studio (admin) plane uses the separate `RealtimeClient` in `./index`.
1307
+ */
1308
+ interface AudienceEvent {
1309
+ type: 'event';
1310
+ channel?: string;
1311
+ collection?: string;
1312
+ action?: 'create' | 'update' | 'delete';
1313
+ itemId?: string;
1314
+ payload: unknown;
1315
+ }
1316
+ interface AudienceNotification {
1317
+ type: 'notification';
1318
+ payload: Record<string, unknown>;
1319
+ }
1320
+ type ChannelEventCallback = (event: AudienceEvent) => void;
1321
+ type NotificationCallback = (notification: AudienceNotification) => void;
1322
+ type ConnectionStatus = 'connecting' | 'open' | 'closed';
1323
+ type StatusCallback = (status: ConnectionStatus) => void;
1324
+ /** Minimal structural WebSocket — lets tests inject a fake. */
1325
+ interface WebSocketLike {
1326
+ readyState: number;
1327
+ send(data: string): void;
1328
+ close(code?: number, reason?: string): void;
1329
+ addEventListener(type: 'open' | 'message' | 'close' | 'error', handler: (ev: any) => void): void;
1330
+ }
1331
+ type WebSocketFactory = (url: string) => WebSocketLike;
1332
+ interface AudienceClientOptions {
1333
+ /** Base HTTP URL of the CMS. `wss://` is derived automatically. */
1334
+ baseUrl: string;
1335
+ /**
1336
+ * Bearer token for the authenticated FRONTEND end-user. Exchanged for a
1337
+ * short-lived audience ticket; never sent over the socket.
1338
+ */
1339
+ token: string;
1340
+ siteId: string;
1341
+ /** Channels to request access to (subject to the server-side allowlist). */
1342
+ channels?: string[];
1343
+ initialBackoffMs?: number;
1344
+ maxBackoffMs?: number;
1345
+ /** Injectable WebSocket factory (defaults to the global `WebSocket`). */
1346
+ webSocketFactory?: WebSocketFactory;
1347
+ /** Injectable fetch (defaults to the global `fetch`). */
1348
+ fetchImpl?: typeof fetch;
1349
+ }
1350
+ declare class AudienceClient {
1351
+ private readonly opts;
1352
+ private ws;
1353
+ private readonly channels;
1354
+ private readonly channelListeners;
1355
+ private readonly notificationListeners;
1356
+ private readonly statusListeners;
1357
+ private reconnectTimer;
1358
+ private backoffMs;
1359
+ private stopped;
1360
+ private _status;
1361
+ constructor(opts: AudienceClientOptions);
1362
+ get status(): ConnectionStatus;
1363
+ connect(): this;
1364
+ disconnect(): void;
1365
+ /** Join a channel. Remembered and re-joined across reconnects. */
1366
+ join(channel: string): void;
1367
+ /** Leave a channel and stop re-joining it. */
1368
+ leave(channel: string): void;
1369
+ onChannelEvent(cb: ChannelEventCallback): () => void;
1370
+ onNotification(cb: NotificationCallback): () => void;
1371
+ onStatus(cb: StatusCallback): () => void;
1372
+ private _connect;
1373
+ private handleMessage;
1374
+ private scheduleReconnect;
1375
+ private setStatus;
1376
+ private sendIfOpen;
1377
+ private sendRaw;
1378
+ }
1379
+
1296
1380
  /**
1297
1381
  * RealtimeClient — typed WebSocket client for the LumiBase realtime API.
1298
1382
  *
@@ -1311,6 +1395,7 @@ declare function createLumiClient<TSchema extends DefaultSchema = DefaultSchema>
1311
1395
  * // ... later
1312
1396
  * rt.disconnect();
1313
1397
  */
1398
+
1314
1399
  interface RealtimeEvent {
1315
1400
  type: 'event';
1316
1401
  collection: string;
@@ -1861,4 +1946,4 @@ declare function toNextMetadata(item: unknown): Record<string, unknown>;
1861
1946
  */
1862
1947
  declare function jsonLdScript(item: unknown): string | undefined;
1863
1948
 
1864
- export { ACCESS_EXPORT_SCHEMA, type AIApproval, type AIApprovalStatus, type AIChatResponse, type AIChatStatus, type AIContentAssistResult, type AIConversation, type AIFieldSuggestion, type AIMessage, type AccessConflict, type AccessConflictCheckInput, type AccessConflictReport, type AccessExportApiKey, type AccessExportBindings, type AccessExportManifest, type AccessExportPermission, type AccessExportPolicy, type AccessExportRole, type AccessImportApplyResult, type AccessImportDiff, type AccessImportDiffEntry, type AccessImportDiffSection, type AccessImportDryRunResult, type AccessImportIssue, type AccessImportMode, type AccessImportOptions, type AccessImportSummary, type ActivityResource, type AgentApprovalResource, type AgentArtifactCreateInput, type AgentArtifactResource, type AgentArtifactType, type AgentEvaluationResource, type AgentGenerateAppInput, type AgentGenerateAppResult, type AgentGoalCreateInput, type AgentGoalResource, type AgentMemoryContext, type AgentMemoryResource, type AgentMemoryWriteInput, type AgentRiskLevel, type AgentRunResource, type AgentToolResource, type ApiKeyCreateInput, type ApiKeyPolicyAttachment, type ApiKeyResource, type ApiKeyRoleAttachment, type ApiKeyRotateInput, type ApiKeySecretResult, type Brand, type CdcConnectorType, type CdcDeployInput, type CdcDeploymentResult, type CdcDeploymentStatus, type CdcDeploymentStep, type CdcDeploymentTarget, type CdcEnvValidationResult, type CdcHealthCheckResult, type CdcHealthMetricEntry, type CdcPipelineCreateInput, type CdcPipelineMetrics, type CdcPipelinePatchInput, type CdcPipelineResource, type CdcPipelineStatus, type CdcRollbackResult, type CdcValidateEnvInput, type CollectionInput, type CollectionResource, type CompiledPermission, type CreateSCIMTokenParams, type DefaultSchema, type DeliverySeo, type DeploymentResource, type DeploymentTargetResource, type ExtensionResource, type FieldDeleteOptions, type FieldInput, type FieldMutationOptions, type FieldRenameInput, type FieldResource, type FileResource, type FlowGraph, type FlowNode, type FlowResource, type FlowRun, type FlowRunResult, type FlowRunStatus, type FlowStatus, type FlowTriggerType, type FolderResource, type GenerateOptions, type GraphQLExtension, type ID, type ItemFilter, type ItemFilterOp, type ItemRow, type ListItemsParams, type ListItemsResponse, type ListMarketplaceExtensionsParams, type Locale, type LumiClient, type LumiClientOptions, LumiError, type LumiErrorBody, type LumiResponse, type MarketplaceExtension, type MarketplaceListResponse, type MaterializeDataResponse, type MaterializeProjection, type MaterializeRefreshResult, type MaterializeRefreshStrategy, type MaterializedCollection, type PermissionAction, type PermissionBundle, type PermissionCheckResult, type PermissionRow, type PolicyDetail, type PolicyResource, type PresenceCallback, type PresenceEntry, type PresetResource, type PrimaryKeyType, RealtimeClient, type RealtimeEvent, type RealtimeEventCallback, type RelationInput, type RelationResource, type RelationType, type RevisionRow, type RoleDetail, type RoleResource, type SCIMTokenCreated, type SCIMTokenMeta, type SCIMTokenRotated, type SchemaApplyInput, type SchemaApplyResult, type SchemaChangedEvent, type SchemaDiff, type SchemaDiffEntry, type SchemaDiffInput, type SchemaDiffRisk, type SchemaRuntimeImpact, type SearchHit, type SearchHitMeta, type SearchParams, type SearchResponse, type SettingResource, type ShareCreateInput, type ShareResource, type ShareSecretResult, type SiteConfigUpdate, type SiteResource, type StorageMode, type TeamMemberResource, type TeamResource, type TranslationResource, type TypegenCollection, type TypegenField, type TypegenManifest, type TypegenRelation, type TypegenSchemaFilters, type UserPreferencesPayload, type UserResource, type WebhookResource, checkCdcPipelineHealth, createAgentArtifact, createAgentGoal, createCdcPipeline, createLumiClient, decideAgentApproval, deleteCdcPipeline, deployCdc, dryRunAccessImport, evaluateAgentArtifact, exportAccessManifest, extractSeo, generateAgentApp, generateTypes, graphql, importAccessManifest, jsonLdScript, legacyRest, listAgentApprovals, listAgentArtifacts, listAgentGoals, listAgentRuns, listAgentTools, listCdcPipelines, publishAgentArtifact, readAgentMemoryContext, readCdcPipeline, readCdcPipelineMetricHistory, readCdcPipelineMetrics, readItem, readItems, retryAgentRun, rollbackAgentArtifact, rollbackCdcDeployment, search, startCdcPipeline, stopCdcPipeline, toNextMetadata, updateCdcPipeline, validateCdcDeploymentEnv, writeAgentMemory };
1949
+ export { ACCESS_EXPORT_SCHEMA, type AIApproval, type AIApprovalStatus, type AIChatResponse, type AIChatStatus, type AIContentAssistResult, type AIConversation, type AIFieldSuggestion, type AIMessage, type AccessConflict, type AccessConflictCheckInput, type AccessConflictReport, type AccessExportApiKey, type AccessExportBindings, type AccessExportManifest, type AccessExportPermission, type AccessExportPolicy, type AccessExportRole, type AccessImportApplyResult, type AccessImportDiff, type AccessImportDiffEntry, type AccessImportDiffSection, type AccessImportDryRunResult, type AccessImportIssue, type AccessImportMode, type AccessImportOptions, type AccessImportSummary, type ActivityResource, type AgentApprovalResource, type AgentArtifactCreateInput, type AgentArtifactResource, type AgentArtifactType, type AgentEvaluationResource, type AgentGenerateAppInput, type AgentGenerateAppResult, type AgentGoalCreateInput, type AgentGoalResource, type AgentMemoryContext, type AgentMemoryResource, type AgentMemoryWriteInput, type AgentRiskLevel, type AgentRunResource, type AgentToolResource, type ApiKeyCreateInput, type ApiKeyPolicyAttachment, type ApiKeyResource, type ApiKeyRoleAttachment, type ApiKeyRotateInput, type ApiKeySecretResult, AudienceClient, type AudienceClientOptions, type AudienceEvent, type AudienceNotification, type Brand, type CdcConnectorType, type CdcDeployInput, type CdcDeploymentResult, type CdcDeploymentStatus, type CdcDeploymentStep, type CdcDeploymentTarget, type CdcEnvValidationResult, type CdcHealthCheckResult, type CdcHealthMetricEntry, type CdcPipelineCreateInput, type CdcPipelineMetrics, type CdcPipelinePatchInput, type CdcPipelineResource, type CdcPipelineStatus, type CdcRollbackResult, type CdcValidateEnvInput, type ChannelEventCallback, type CollectionInput, type CollectionResource, type CompiledPermission, type ConnectionStatus, type CreateSCIMTokenParams, type DefaultSchema, type DeliverySeo, type DeploymentResource, type DeploymentTargetResource, type ExtensionResource, type FieldDeleteOptions, type FieldInput, type FieldMutationOptions, type FieldRenameInput, type FieldResource, type FileResource, type FlowGraph, type FlowNode, type FlowResource, type FlowRun, type FlowRunResult, type FlowRunStatus, type FlowStatus, type FlowTriggerType, type FolderResource, type GenerateOptions, type GraphQLExtension, type ID, type ItemFilter, type ItemFilterOp, type ItemRow, type ListItemsParams, type ListItemsResponse, type ListMarketplaceExtensionsParams, type Locale, type LumiClient, type LumiClientOptions, LumiError, type LumiErrorBody, type LumiResponse, type MarketplaceExtension, type MarketplaceListResponse, type MaterializeDataResponse, type MaterializeProjection, type MaterializeRefreshResult, type MaterializeRefreshStrategy, type MaterializedCollection, type NotificationCallback, type PermissionAction, type PermissionBundle, type PermissionCheckResult, type PermissionRow, type PolicyDetail, type PolicyResource, type PresenceCallback, type PresenceEntry, type PresetResource, type PrimaryKeyType, RealtimeClient, type RealtimeEvent, type RealtimeEventCallback, type RelationInput, type RelationResource, type RelationType, type RevisionRow, type RoleDetail, type RoleResource, type SCIMTokenCreated, type SCIMTokenMeta, type SCIMTokenRotated, type SchemaApplyInput, type SchemaApplyResult, type SchemaChangedEvent, type SchemaDiff, type SchemaDiffEntry, type SchemaDiffInput, type SchemaDiffRisk, type SchemaRuntimeImpact, type SearchHit, type SearchHitMeta, type SearchParams, type SearchResponse, type SettingResource, type ShareCreateInput, type ShareResource, type ShareSecretResult, type SiteConfigUpdate, type SiteResource, type StatusCallback, type StorageMode, type TeamMemberResource, type TeamResource, type TranslationResource, type TypegenCollection, type TypegenField, type TypegenManifest, type TypegenRelation, type TypegenSchemaFilters, type UserPreferencesPayload, type UserResource, type WebSocketFactory, type WebSocketLike, type WebhookResource, checkCdcPipelineHealth, createAgentArtifact, createAgentGoal, createCdcPipeline, createLumiClient, decideAgentApproval, deleteCdcPipeline, deployCdc, dryRunAccessImport, evaluateAgentArtifact, exportAccessManifest, extractSeo, generateAgentApp, generateTypes, graphql, importAccessManifest, jsonLdScript, legacyRest, listAgentApprovals, listAgentArtifacts, listAgentGoals, listAgentRuns, listAgentTools, listCdcPipelines, publishAgentArtifact, readAgentMemoryContext, readCdcPipeline, readCdcPipelineMetricHistory, readCdcPipelineMetrics, readItem, readItems, retryAgentRun, rollbackAgentArtifact, rollbackCdcDeployment, search, startCdcPipeline, stopCdcPipeline, toNextMetadata, updateCdcPipeline, validateCdcDeploymentEnv, writeAgentMemory };
package/dist/index.js CHANGED
@@ -78,6 +78,165 @@ function createLumiClient(opts) {
78
78
  // src/types.ts
79
79
  var ACCESS_EXPORT_SCHEMA = "lumibase.access@v1";
80
80
 
81
+ // src/realtime/audience.ts
82
+ var WS_OPEN = 1;
83
+ var AudienceClient = class {
84
+ constructor(opts) {
85
+ this.opts = opts;
86
+ this.backoffMs = opts.initialBackoffMs ?? 1e3;
87
+ for (const c of opts.channels ?? []) this.channels.add(c);
88
+ }
89
+ opts;
90
+ ws = null;
91
+ channels = /* @__PURE__ */ new Set();
92
+ channelListeners = /* @__PURE__ */ new Set();
93
+ notificationListeners = /* @__PURE__ */ new Set();
94
+ statusListeners = /* @__PURE__ */ new Set();
95
+ reconnectTimer = null;
96
+ backoffMs;
97
+ stopped = false;
98
+ _status = "closed";
99
+ // ─── Public API ─────────────────────────────────────────────────────────────
100
+ get status() {
101
+ return this._status;
102
+ }
103
+ connect() {
104
+ this.stopped = false;
105
+ void this._connect();
106
+ return this;
107
+ }
108
+ disconnect() {
109
+ this.stopped = true;
110
+ if (this.reconnectTimer) {
111
+ clearTimeout(this.reconnectTimer);
112
+ this.reconnectTimer = null;
113
+ }
114
+ if (this.ws) {
115
+ try {
116
+ this.ws.close(1e3, "client disconnect");
117
+ } catch {
118
+ }
119
+ this.ws = null;
120
+ }
121
+ this.setStatus("closed");
122
+ }
123
+ /** Join a channel. Remembered and re-joined across reconnects. */
124
+ join(channel) {
125
+ this.channels.add(channel);
126
+ this.sendIfOpen({ type: "join", channel });
127
+ }
128
+ /** Leave a channel and stop re-joining it. */
129
+ leave(channel) {
130
+ this.channels.delete(channel);
131
+ this.sendIfOpen({ type: "leave", channel });
132
+ }
133
+ onChannelEvent(cb) {
134
+ this.channelListeners.add(cb);
135
+ return () => this.channelListeners.delete(cb);
136
+ }
137
+ onNotification(cb) {
138
+ this.notificationListeners.add(cb);
139
+ return () => this.notificationListeners.delete(cb);
140
+ }
141
+ onStatus(cb) {
142
+ this.statusListeners.add(cb);
143
+ return () => this.statusListeners.delete(cb);
144
+ }
145
+ // ─── Internal ────────────────────────────────────────────────────────────────
146
+ async _connect() {
147
+ if (this.ws) return;
148
+ this.setStatus("connecting");
149
+ const doFetch = this.opts.fetchImpl ?? fetch;
150
+ let ticket;
151
+ try {
152
+ const res = await doFetch(`${this.opts.baseUrl}/api/v1/realtime/audience-ticket`, {
153
+ method: "POST",
154
+ headers: {
155
+ Authorization: `Bearer ${this.opts.token}`,
156
+ "X-Lumi-Site": this.opts.siteId,
157
+ "Content-Type": "application/json"
158
+ },
159
+ body: JSON.stringify({ channels: Array.from(this.channels) })
160
+ });
161
+ if (!res.ok) throw new Error(`audience-ticket failed: ${res.status}`);
162
+ const body = await res.json();
163
+ if (!body.data?.ticket) throw new Error("ticket missing");
164
+ ticket = body.data.ticket;
165
+ } catch {
166
+ this.scheduleReconnect();
167
+ return;
168
+ }
169
+ if (this.stopped) return;
170
+ const wsBase = this.opts.baseUrl.replace(/^http/, "ws");
171
+ const url = `${wsBase}/api/v1/realtime?ticket=${encodeURIComponent(ticket)}`;
172
+ const factory = this.opts.webSocketFactory ?? ((u) => new WebSocket(u));
173
+ let ws;
174
+ try {
175
+ ws = factory(url);
176
+ } catch {
177
+ this.scheduleReconnect();
178
+ return;
179
+ }
180
+ this.ws = ws;
181
+ ws.addEventListener("open", () => {
182
+ this.backoffMs = this.opts.initialBackoffMs ?? 1e3;
183
+ this.setStatus("open");
184
+ for (const channel of this.channels) this.sendRaw({ type: "join", channel });
185
+ });
186
+ ws.addEventListener("message", (ev) => {
187
+ let msg;
188
+ try {
189
+ msg = JSON.parse(ev.data);
190
+ } catch {
191
+ return;
192
+ }
193
+ this.handleMessage(msg);
194
+ });
195
+ ws.addEventListener("close", () => {
196
+ this.ws = null;
197
+ this.setStatus("closed");
198
+ if (!this.stopped) this.scheduleReconnect();
199
+ });
200
+ ws.addEventListener("error", () => {
201
+ });
202
+ }
203
+ handleMessage(msg) {
204
+ switch (msg.type) {
205
+ case "ping":
206
+ this.sendRaw({ type: "pong" });
207
+ break;
208
+ case "event":
209
+ for (const cb of this.channelListeners) cb(msg);
210
+ break;
211
+ case "notification":
212
+ for (const cb of this.notificationListeners) cb(msg);
213
+ break;
214
+ }
215
+ }
216
+ scheduleReconnect() {
217
+ if (this.stopped || this.reconnectTimer) return;
218
+ this.reconnectTimer = setTimeout(() => {
219
+ this.reconnectTimer = null;
220
+ void this._connect();
221
+ this.backoffMs = Math.min(this.backoffMs * 2, this.opts.maxBackoffMs ?? 3e4);
222
+ }, this.backoffMs);
223
+ }
224
+ setStatus(status) {
225
+ if (this._status === status) return;
226
+ this._status = status;
227
+ for (const cb of this.statusListeners) cb(status);
228
+ }
229
+ sendIfOpen(data) {
230
+ if (this.ws && this.ws.readyState === WS_OPEN) this.sendRaw(data);
231
+ }
232
+ sendRaw(data) {
233
+ try {
234
+ this.ws?.send(JSON.stringify(data));
235
+ } catch {
236
+ }
237
+ }
238
+ };
239
+
81
240
  // src/realtime/index.ts
82
241
  var RealtimeClient = class {
83
242
  constructor(opts) {
@@ -1260,6 +1419,7 @@ function jsonLdScript(item) {
1260
1419
  }
1261
1420
  export {
1262
1421
  ACCESS_EXPORT_SCHEMA,
1422
+ AudienceClient,
1263
1423
  LumiError,
1264
1424
  RealtimeClient,
1265
1425
  checkCdcPipelineHealth,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumibase/sdk",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "LumiBase JS SDK (REST + WebSocket) + typegen core. Isomorphic ESM.",
5
5
  "type": "module",
6
6
  "repository": {