cross-tab-worker-databus 0.20.70 → 0.20.71
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/CHANGELOG.md +5 -0
- package/dist/centrifuge.js +1 -1
- package/dist/{chunk-IKBJIREH.js → chunk-D2SIT473.js} +20 -2
- package/dist/{chunk-IKBJIREH.js.map → chunk-D2SIT473.js.map} +2 -2
- package/dist/cjs/centrifuge.cjs +19 -1
- package/dist/cjs/centrifuge.cjs.map +2 -2
- package/dist/cjs/index.cjs +59 -1
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/core/data-bus.d.ts +3 -0
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/replay-persistence.d.ts +2 -0
- package/dist/core/replay-persistence.d.ts.map +1 -1
- package/dist/index.js +41 -1
- package/dist/index.js.map +2 -2
- package/docs/roadmap.md +5 -1
- package/docs/zh/roadmap.md +5 -1
- package/package.json +1 -1
package/dist/core/data-bus.d.ts
CHANGED
|
@@ -124,6 +124,8 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
|
|
|
124
124
|
private readonly persistenceRetryMaxAttempts;
|
|
125
125
|
private readonly persistenceRetryBackoffMs;
|
|
126
126
|
private persistenceRetryGeneration;
|
|
127
|
+
private pendingReplayPersistence;
|
|
128
|
+
private replayPersistenceFlushScheduled;
|
|
127
129
|
private readonly replayHydration;
|
|
128
130
|
private replayRetentionCleanup;
|
|
129
131
|
private replayRetentionCutoff;
|
|
@@ -274,6 +276,7 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
|
|
|
274
276
|
/** Append a dispatched publication to the topic's replay ring buffer.
|
|
275
277
|
* No-op when replay is disabled. */
|
|
276
278
|
private recordReplay;
|
|
279
|
+
private scheduleReplayPersistenceFlush;
|
|
277
280
|
private hydrateReplay;
|
|
278
281
|
private scheduleReplayRetentionCleanup;
|
|
279
282
|
private startReplayRetentionSweep;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-bus.d.ts","sourceRoot":"","sources":["../../src/core/data-bus.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"data-bus.d.ts","sourceRoot":"","sources":["../../src/core/data-bus.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,8 @@ import type { DataBusMessage } from './types';
|
|
|
3
3
|
export interface DataBusReplayPersistence<TData = unknown> {
|
|
4
4
|
load(): Promise<ReadonlyArray<DataBusMessage<TData>>>;
|
|
5
5
|
append(message: DataBusMessage<TData>): Promise<void>;
|
|
6
|
+
/** Optional bulk append used to amortize IndexedDB transaction overhead. */
|
|
7
|
+
appendBatch?(messages: ReadonlyArray<DataBusMessage<TData>>): Promise<void>;
|
|
6
8
|
/** Remove all persisted replay history. */
|
|
7
9
|
clear?(): Promise<void>;
|
|
8
10
|
/** Remove persisted replay history for one exact topic. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replay-persistence.d.ts","sourceRoot":"","sources":["../../src/core/replay-persistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,uDAAuD;AACvD,MAAM,WAAW,wBAAwB,CAAC,KAAK,GAAG,OAAO;IACvD,IAAI,IAAI,OAAO,CAAC,aAAa,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,2CAA2C;IAC3C,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,2DAA2D;IAC3D,UAAU,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,+EAA+E;IAC/E,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,iCAAiC;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,sDAAsD;AACtD,wBAAgB,gCAAgC,CAAC,KAAK,GAAG,OAAO,EAC9D,OAAO,EAAE,iCAAiC,GACzC,wBAAwB,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"replay-persistence.d.ts","sourceRoot":"","sources":["../../src/core/replay-persistence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,uDAAuD;AACvD,MAAM,WAAW,wBAAwB,CAAC,KAAK,GAAG,OAAO;IACvD,IAAI,IAAI,OAAO,CAAC,aAAa,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,4EAA4E;IAC5E,WAAW,CAAC,CAAC,QAAQ,EAAE,aAAa,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,2CAA2C;IAC3C,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,2DAA2D;IAC3D,UAAU,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,+EAA+E;IAC/E,WAAW,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,iCAAiC;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,sDAAsD;AACtD,wBAAgB,gCAAgC,CAAC,KAAK,GAAG,OAAO,EAC9D,OAAO,EAAE,iCAAiC,GACzC,wBAAwB,CAAC,KAAK,CAAC,CAqLjC"}
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
selectRebalanceTarget,
|
|
14
14
|
selectWorkerBackend,
|
|
15
15
|
topicMatchesPattern
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-D2SIT473.js";
|
|
17
17
|
|
|
18
18
|
// src/core/replay-persistence.ts
|
|
19
19
|
function createIndexedDbReplayPersistence(options) {
|
|
@@ -121,6 +121,46 @@ function createIndexedDbReplayPersistence(options) {
|
|
|
121
121
|
});
|
|
122
122
|
});
|
|
123
123
|
},
|
|
124
|
+
appendBatch(messages) {
|
|
125
|
+
if (messages.length === 0) return Promise.resolve();
|
|
126
|
+
return serializeMutation(async () => {
|
|
127
|
+
const db = await open();
|
|
128
|
+
await new Promise((resolve, reject) => {
|
|
129
|
+
let transaction;
|
|
130
|
+
try {
|
|
131
|
+
transaction = db.transaction(storeName, "readwrite");
|
|
132
|
+
} catch (error) {
|
|
133
|
+
invalidate(db);
|
|
134
|
+
reject(error);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const store = transaction.objectStore(storeName);
|
|
138
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
139
|
+
for (const message of messages) grouped.set(message.topic, [...grouped.get(message.topic) ?? [], message]);
|
|
140
|
+
for (const [topic, topicMessages] of grouped) {
|
|
141
|
+
const request = store.get(topic);
|
|
142
|
+
request.onsuccess = () => {
|
|
143
|
+
let history = (request.result?.messages ?? []).concat(topicMessages);
|
|
144
|
+
if (pruneStrategy !== "count" && retentionMs !== void 0) {
|
|
145
|
+
const cutoff = Date.now() - retentionMs;
|
|
146
|
+
history = history.filter((item) => item.timestamp === void 0 || item.timestamp >= cutoff);
|
|
147
|
+
}
|
|
148
|
+
if (pruneStrategy !== "age") history = history.slice(-maxPerTopic);
|
|
149
|
+
store.put({ topic, messages: history });
|
|
150
|
+
};
|
|
151
|
+
request.onerror = () => {
|
|
152
|
+
invalidate(db);
|
|
153
|
+
reject(request.error ?? new Error("Failed to read replay history."));
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
transaction.oncomplete = () => resolve();
|
|
157
|
+
transaction.onerror = () => {
|
|
158
|
+
invalidate(db);
|
|
159
|
+
reject(transaction.error ?? new Error("Failed to persist replay history batch."));
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
},
|
|
124
164
|
clear() {
|
|
125
165
|
return serializeMutation(async () => {
|
|
126
166
|
const db = await open();
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/core/replay-persistence.ts", "../src/websocket.ts"],
|
|
4
|
-
"sourcesContent": ["import type { DataBusMessage } from './types';\n\n/** Optional persistence backend for replay history. */\nexport interface DataBusReplayPersistence<TData = unknown> {\n load(): Promise<ReadonlyArray<DataBusMessage<TData>>>;\n append(message: DataBusMessage<TData>): Promise<void>;\n /** Remove all persisted replay history. */\n clear?(): Promise<void>;\n /** Remove persisted replay history for one exact topic. */\n clearTopic?(topic: string): Promise<void>;\n /** Remove persisted messages older than the given epoch-millisecond cutoff. */\n clearBefore?(timestamp: number): Promise<void>;\n}\n\nexport interface IndexedDbReplayPersistenceOptions {\n dbName?: string;\n maxPerTopic: number;\n pruneStrategy?: 'count' | 'age' | 'both';\n retentionMs?: number;\n}\n\n/** Create a browser IndexedDB-backed replay store. */\nexport function createIndexedDbReplayPersistence<TData = unknown>(\n options: IndexedDbReplayPersistenceOptions\n): DataBusReplayPersistence<TData> {\n const indexedDb = globalThis.indexedDB;\n if (!indexedDb) throw new Error('IndexedDB is unavailable in this environment.');\n const dbName = options.dbName ?? 'cross-tab-worker-databus';\n const storeName = 'replay';\n const maxPerTopic = options.maxPerTopic;\n const pruneStrategy = options.pruneStrategy ?? 'count';\n const retentionMs = options.retentionMs;\n if (!['count', 'age', 'both'].includes(pruneStrategy)) throw new TypeError('pruneStrategy must be count, age, or both.');\n if (retentionMs !== undefined && (!Number.isFinite(retentionMs) || retentionMs <= 0)) throw new TypeError('retentionMs must be a positive finite number.');\n if (!Number.isSafeInteger(maxPerTopic) || maxPerTopic <= 0) {\n throw new TypeError(`maxPerTopic must be a positive safe integer, got ${String(maxPerTopic)}.`);\n }\n let dbPromise: Promise<IDBDatabase> | null = null;\n const invalidate = (db: IDBDatabase): void => {\n if (dbPromise) {\n void dbPromise.then(current => {\n if (current === db) {\n current.close();\n dbPromise = null;\n }\n }, () => undefined);\n }\n };\n // IndexedDB transactions are atomic, but a read-modify-write append can\n // still lose updates when callers start several appends concurrently.\n // Serialize all mutations per adapter instance while keeping reads free.\n let mutationQueue: Promise<void> = Promise.resolve();\n const serializeMutation = (mutation: () => Promise<void>): Promise<void> => {\n const next = mutationQueue.then(mutation, mutation);\n mutationQueue = next.catch(() => undefined);\n return next;\n };\n const open = (): Promise<IDBDatabase> => {\n if (dbPromise) return dbPromise;\n const pending = new Promise<IDBDatabase>((resolve, reject) => {\n const request = indexedDb.open(dbName, 1);\n request.onupgradeneeded = () => request.result.createObjectStore(storeName, { keyPath: 'topic' });\n request.onsuccess = () => {\n const db = request.result;\n // A schema upgrade in another tab invalidates this connection. Close\n // it and clear the cached promise so the next operation reopens a\n // usable connection instead of repeatedly targeting a dead database.\n db.onversionchange = () => {\n db.close();\n if (dbPromise) dbPromise = null;\n };\n resolve(db);\n };\n request.onerror = () => reject(request.error ?? new Error('Failed to open replay database.'));\n });\n dbPromise = pending;\n // Do not permanently cache a rejected open promise. IndexedDB can fail\n // transiently (quota, private-mode initialization, a closing connection,\n // or a browser shutdown); the next operation must be able to retry.\n void pending.catch(() => {\n if (dbPromise === pending) dbPromise = null;\n });\n return pending;\n };\n return {\n async load() {\n const db = await open();\n return new Promise((resolve, reject) => {\n let request: IDBRequest;\n try {\n request = db.transaction(storeName, 'readonly').objectStore(storeName).getAll();\n } catch (error) {\n invalidate(db);\n reject(error);\n return;\n }\n request.onsuccess = () => resolve((request.result as Array<{ messages: DataBusMessage<TData>[] }>).flatMap(record => record.messages));\n request.onerror = () => {\n invalidate(db);\n reject(request.error ?? new Error('Failed to load replay history.'));\n };\n });\n },\n append(message) {\n return serializeMutation(async () => {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n let transaction: IDBTransaction;\n try { transaction = db.transaction(storeName, 'readwrite'); }\n catch (error) { invalidate(db); reject(error); return; }\n const store = transaction.objectStore(storeName);\n const request = store.get(message.topic);\n request.onsuccess = () => {\n let messages = ((request.result?.messages ?? []) as DataBusMessage<TData>[]).concat(message);\n if (pruneStrategy !== 'count' && retentionMs !== undefined) {\n const cutoff = Date.now() - retentionMs;\n messages = messages.filter(item => item.timestamp === undefined || item.timestamp >= cutoff);\n }\n if (pruneStrategy !== 'age') messages = messages.slice(-maxPerTopic);\n store.put({ topic: message.topic, messages });\n };\n request.onerror = () => { invalidate(db); reject(request.error ?? new Error('Failed to read replay history.')); };\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => { invalidate(db); reject(transaction.error ?? new Error('Failed to persist replay history.')); };\n });\n });\n },\n clear() {\n return serializeMutation(async () => {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n let transaction: IDBTransaction;\n try { transaction = db.transaction(storeName, 'readwrite'); }\n catch (error) { invalidate(db); reject(error); return; }\n transaction.objectStore(storeName).clear();\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => { invalidate(db); reject(transaction.error ?? new Error('Failed to clear replay history.')); };\n });\n });\n },\n clearTopic(topic) {\n return serializeMutation(async () => {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n let transaction: IDBTransaction;\n try { transaction = db.transaction(storeName, 'readwrite'); }\n catch (error) { invalidate(db); reject(error); return; }\n transaction.objectStore(storeName).delete(topic);\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => { invalidate(db); reject(transaction.error ?? new Error('Failed to clear topic replay history.')); };\n });\n });\n },\n clearBefore(timestamp) {\n return serializeMutation(async () => {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n let transaction: IDBTransaction;\n try { transaction = db.transaction(storeName, 'readwrite'); }\n catch (error) { invalidate(db); reject(error); return; }\n const store = transaction.objectStore(storeName);\n const request = store.getAll();\n request.onsuccess = () => {\n for (const record of request.result as Array<{ topic: string; messages: DataBusMessage<TData>[] }>) {\n const messages = record.messages.filter(message => message.timestamp === undefined || message.timestamp >= timestamp);\n if (messages.length === 0) store.delete(record.topic);\n else if (messages.length !== record.messages.length) store.put({ topic: record.topic, messages });\n }\n };\n request.onerror = () => { invalidate(db); reject(request.error ?? new Error('Failed to read replay history.')); };\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => { invalidate(db); reject(transaction.error ?? new Error('Failed to prune replay history.')); };\n });\n });\n }\n };\n}\n", "/**\n * WebSocketTransport \u2014 a dependency-free transport over a plain WebSocket.\n *\n * Validates the `DataBusTransport` abstraction with a second, minimal backend:\n * any WebSocket server that speaks the tiny JSON protocol below can back the\n * same cross-tab clustering stack (owner dedup, sticky routes, EVENT fan-out)\n * that the Centrifuge backend uses.\n *\n * Wire protocol (JSON text frames):\n * - client \u2192 server: `{\"op\":\"subscribe\"|\"unsubscribe\"|\"publish\",\"topic\":...,\"data\":...}`\n * - server \u2192 client: `{\"topic\":...,\"data\":...}` for publications; anything\n * without a string `topic` field is ignored (forward-compatible).\n */\nimport { CrossTabDataBus } from './core/data-bus';\nimport { parseDataBusPublication } from './core/publication';\nimport type { CrossTabDataBusOptions } from './core/data-bus';\nimport type {\n DataBusTransport,\n DataBusTransportHandlers,\n DataBusPublishOptions,\n DataBusMessage,\n MaybePromise,\n WorkerStatus\n} from './core/types';\n\n/** Minimal WebSocket surface used by the transport. Matches the browser\n * `WebSocket` subset the transport touches; injectable for tests and runtimes. */\nexport interface WebSocketLike {\n /** Current connection state; 1 (OPEN) means frames may be sent. */\n readonly readyState?: number;\n send(data: string | ArrayBuffer): void;\n close(code?: number, reason?: string): void;\n onopen: (() => void) | null;\n onclose: (() => void) | null;\n onerror: (() => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n}\n\n/** Connection configuration for {@link WebSocketTransport}. */\nexport interface WebSocketDataBusConfig {\n /** WebSocket endpoint, e.g. `wss://example.test/ws`. */\n url: string;\n /** Subprotocol(s) passed to the WebSocket handshake. */\n protocols?: string | string[];\n /** Custom socket factory. Defaults to the global `WebSocket`; injectable\n * for tests and non-browser runtimes. */\n webSocketFactory?: (url: string, protocols?: string | string[]) => WebSocketLike;\n}\n\n/** Options for creating a fully-configured CrossTabDataBus with a WebSocket transport. */\nexport interface CreateWebSocketDataBusOptions<TData = unknown>\n extends Omit<\n CrossTabDataBusOptions<WebSocketDataBusConfig, TData>,\n 'autoStart' | 'clusterKey' | 'initialConfig' | 'transport'\n > {\n /** WebSocket connection configuration. */\n connection: WebSocketDataBusConfig;\n /** Cluster key for cross-tab coordination. Defaults to the connection URL. */\n clusterKey?: string;\n}\n\nconst WS_OPEN = 1;\n\n/** Transport that talks a minimal JSON protocol over a plain WebSocket.\n * Connection lifecycle maps directly to the DataBus status vocabulary:\n * open \u2192 `connected`, close \u2192 `disconnected`, error \u2192 `error` (which the\n * DataBus treats as its auto-recovery trigger). The transport holds no\n * reconnection logic of its own \u2014 reopening is the DataBus's job. */\nexport class WebSocketTransport<TData = unknown>\n implements DataBusTransport<WebSocketDataBusConfig, TData>\n{\n readonly diagnosticsName = 'websocket';\n readonly diagnosticsBackend = 'native-websocket';\n private socket: WebSocketLike | null = null;\n private handlers: DataBusTransportHandlers<TData> | null = null;\n private readonly subscribedTopics = new Set<string>();\n\n constructor(private readonly connection: WebSocketDataBusConfig) {}\n\n /** Open the WebSocket and wire lifecycle listeners. A factory failure is\n * reported through `onStatus('error')` so the DataBus can recover. */\n start(config: WebSocketDataBusConfig, handlers: DataBusTransportHandlers<TData>): MaybePromise<void> {\n if (this.socket) return;\n this.handlers = handlers;\n // The factory may live on the constructor connection (createWebSocketDataBus\n // path) or on the runtime config (direct transport use) \u2014 accept both.\n const factory = config.webSocketFactory ?? this.connection.webSocketFactory ?? defaultWebSocketFactory;\n const protocols = config.protocols ?? this.connection.protocols;\n let socket: WebSocketLike;\n try {\n socket = factory(config.url, protocols);\n } catch (error) {\n handlers.onStatus('error');\n handlers.onError(error);\n return;\n }\n socket.onopen = () => {\n if (this.socket !== socket || this.handlers !== handlers) return;\n // Re-assert every topic so a reopened socket (recovery path) restores\n // the server-side subscriptions without DataBus involvement.\n for (const topic of this.subscribedTopics) {\n this.sendFrame({ op: 'subscribe', topic });\n }\n handlers.onStatus('connected');\n };\n socket.onclose = () => {\n if (this.socket === socket && this.handlers === handlers) handlers.onStatus('disconnected');\n };\n socket.onerror = () => {\n if (this.socket === socket && this.handlers === handlers) handlers.onStatus('error');\n };\n socket.onmessage = event => {\n if (this.socket === socket && this.handlers === handlers) void this.handleMessage(event.data);\n };\n this.socket = socket;\n }\n\n /** Idempotent: re-subscribing an active topic re-sends the frame but does\n * not duplicate the local tracking entry. */\n subscribe(topic: string): MaybePromise<void> {\n this.subscribedTopics.add(topic);\n this.sendFrame({ op: 'subscribe', topic });\n }\n\n /** Idempotent: unsubscribing an unknown topic is a no-op. */\n unsubscribe(topic: string): MaybePromise<void> {\n this.subscribedTopics.delete(topic);\n this.sendFrame({ op: 'unsubscribe', topic });\n }\n\n /** Publish `data` to `topic` as a JSON frame. Requires an open socket. */\n publish(topic: string, data: unknown, options?: DataBusPublishOptions): MaybePromise<void> {\n if (data instanceof ArrayBuffer) {\n this.sendBinaryFrame(topic, data, options?.messageId, options?.timestamp);\n return;\n }\n this.sendFrame({\n op: 'publish',\n topic,\n data,\n ...(options?.messageId === undefined ? {} : { messageId: options.messageId }),\n ...(options?.timestamp === undefined ? {} : { timestamp: options.timestamp })\n });\n }\n\n /** Close the socket and drop all state. Safe to call multiple times. */\n stop(): MaybePromise<void> {\n const socket = this.socket;\n this.socket = null;\n this.handlers = null;\n this.subscribedTopics.clear();\n socket?.close();\n }\n\n /** Send one JSON frame. Frames are dropped with an `onError` report when\n * the socket is not open \u2014 subscribe frames are re-sent on open, so the\n * only real loss is a publish during a disconnect window. */\n private sendFrame(payload: { op: string; topic: string; data?: unknown; messageId?: string; timestamp?: number }): void {\n if (this.socket?.readyState !== WS_OPEN) {\n this.handlers?.onError(new Error(`WebSocket is not open; dropped \"${payload.op}\" frame.`));\n return;\n }\n this.socket.send(JSON.stringify(payload));\n }\n\n private sendBinaryFrame(topic: string, data: ArrayBuffer, messageId?: string, timestamp?: number): void {\n if (messageId !== undefined || timestamp !== undefined) {\n // Binary frames retain their compact legacy shape; metadata is sent as a\n // JSON envelope so IDs are never silently lost.\n this.sendFrame({\n op: 'publish',\n topic,\n data: Array.from(new Uint8Array(data)),\n ...(messageId === undefined ? {} : { messageId }),\n ...(timestamp === undefined ? {} : { timestamp })\n });\n return;\n }\n if (this.socket?.readyState !== WS_OPEN) {\n this.handlers?.onError(new Error('WebSocket is not open; dropped \"publish\" frame.'));\n return;\n }\n const topicBytes = new TextEncoder().encode(topic);\n if (topicBytes.length > 0xffff) {\n this.handlers?.onError(new Error('WebSocket topic is too long for a binary frame.'));\n return;\n }\n const frame = new Uint8Array(3 + topicBytes.length + data.byteLength);\n frame[0] = 0xc7;\n new DataView(frame.buffer).setUint16(1, topicBytes.length);\n frame.set(topicBytes, 3);\n frame.set(new Uint8Array(data), 3 + topicBytes.length);\n this.socket.send(frame.buffer);\n }\n\n /** Parse a server frame. Only objects carrying a string `topic` are\n * publications; malformed JSON and unknown shapes are ignored so a chatty\n * server cannot crash the message path. */\n private async handleMessage(raw: unknown): Promise<void> {\n // Browser WebSockets may deliver binary frames as Blob unless\n // `binaryType = 'arraybuffer'` is explicitly configured by the host.\n // Normalize Blob asynchronously and reuse the exact ArrayBuffer parser.\n if (typeof Blob !== 'undefined' && raw instanceof Blob) {\n try {\n await this.handleMessage(await raw.arrayBuffer());\n } catch (error) {\n this.handlers?.onError(error);\n }\n return;\n }\n let parsed: unknown;\n if (raw instanceof ArrayBuffer) {\n const bytes = new Uint8Array(raw);\n if (bytes[0] !== 0xc7 || bytes.length < 3) return;\n const topicLength = new DataView(raw).getUint16(1);\n if (bytes.length < 3 + topicLength) return;\n const topic = new TextDecoder().decode(bytes.subarray(3, 3 + topicLength));\n const data = bytes.slice(3 + topicLength).buffer;\n this.handlers?.onMessage({ topic, data: data as TData });\n return;\n }\n if (typeof raw !== 'string') return;\n try {\n parsed = JSON.parse(raw);\n } catch {\n this.handlers?.onError(new Error('WebSocket server sent a non-JSON frame.'));\n return;\n }\n if (!parsed || typeof parsed !== 'object') return;\n const publication = parseDataBusPublication<TData>(parsed);\n if (publication) this.handlers?.onMessage(publication as DataBusMessage<TData>);\n }\n}\n\n/** Resolve the platform WebSocket, or null in runtimes without one (SSR/Node). */\nfunction defaultWebSocketFactory(url: string, protocols?: string | string[]): WebSocketLike {\n if (typeof WebSocket === 'undefined') {\n throw new Error('WebSocketTransport requires a WebSocket implementation.');\n }\n return new WebSocket(url, protocols) as unknown as WebSocketLike;\n}\n\n/** Create a CrossTabDataBus backed by a plain WebSocket transport.\n * Cross-tab clustering (owner dedup, sticky routes, failover) works identically\n * to the Centrifuge backend \u2014 only the transport I/O differs. */\nexport function createWebSocketDataBus<TData = unknown>(\n options: CreateWebSocketDataBusOptions<TData>\n): CrossTabDataBus<WebSocketDataBusConfig, TData> {\n const { clusterKey, connection, ...dataBusOptions } = options;\n return new CrossTabDataBus({\n ...dataBusOptions,\n autoStart: true,\n clusterKey: clusterKey ?? connection.url,\n initialConfig: connection,\n transport: new WebSocketTransport<TData>(connection)\n });\n}\n\n/** Re-export for convenience: the status type used by the transport. */\nexport type { WorkerStatus };\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;
|
|
4
|
+
"sourcesContent": ["import type { DataBusMessage } from './types';\n\n/** Optional persistence backend for replay history. */\nexport interface DataBusReplayPersistence<TData = unknown> {\n load(): Promise<ReadonlyArray<DataBusMessage<TData>>>;\n append(message: DataBusMessage<TData>): Promise<void>;\n /** Optional bulk append used to amortize IndexedDB transaction overhead. */\n appendBatch?(messages: ReadonlyArray<DataBusMessage<TData>>): Promise<void>;\n /** Remove all persisted replay history. */\n clear?(): Promise<void>;\n /** Remove persisted replay history for one exact topic. */\n clearTopic?(topic: string): Promise<void>;\n /** Remove persisted messages older than the given epoch-millisecond cutoff. */\n clearBefore?(timestamp: number): Promise<void>;\n}\n\nexport interface IndexedDbReplayPersistenceOptions {\n dbName?: string;\n maxPerTopic: number;\n pruneStrategy?: 'count' | 'age' | 'both';\n retentionMs?: number;\n}\n\n/** Create a browser IndexedDB-backed replay store. */\nexport function createIndexedDbReplayPersistence<TData = unknown>(\n options: IndexedDbReplayPersistenceOptions\n): DataBusReplayPersistence<TData> {\n const indexedDb = globalThis.indexedDB;\n if (!indexedDb) throw new Error('IndexedDB is unavailable in this environment.');\n const dbName = options.dbName ?? 'cross-tab-worker-databus';\n const storeName = 'replay';\n const maxPerTopic = options.maxPerTopic;\n const pruneStrategy = options.pruneStrategy ?? 'count';\n const retentionMs = options.retentionMs;\n if (!['count', 'age', 'both'].includes(pruneStrategy)) throw new TypeError('pruneStrategy must be count, age, or both.');\n if (retentionMs !== undefined && (!Number.isFinite(retentionMs) || retentionMs <= 0)) throw new TypeError('retentionMs must be a positive finite number.');\n if (!Number.isSafeInteger(maxPerTopic) || maxPerTopic <= 0) {\n throw new TypeError(`maxPerTopic must be a positive safe integer, got ${String(maxPerTopic)}.`);\n }\n let dbPromise: Promise<IDBDatabase> | null = null;\n const invalidate = (db: IDBDatabase): void => {\n if (dbPromise) {\n void dbPromise.then(current => {\n if (current === db) {\n current.close();\n dbPromise = null;\n }\n }, () => undefined);\n }\n };\n // IndexedDB transactions are atomic, but a read-modify-write append can\n // still lose updates when callers start several appends concurrently.\n // Serialize all mutations per adapter instance while keeping reads free.\n let mutationQueue: Promise<void> = Promise.resolve();\n const serializeMutation = (mutation: () => Promise<void>): Promise<void> => {\n const next = mutationQueue.then(mutation, mutation);\n mutationQueue = next.catch(() => undefined);\n return next;\n };\n const open = (): Promise<IDBDatabase> => {\n if (dbPromise) return dbPromise;\n const pending = new Promise<IDBDatabase>((resolve, reject) => {\n const request = indexedDb.open(dbName, 1);\n request.onupgradeneeded = () => request.result.createObjectStore(storeName, { keyPath: 'topic' });\n request.onsuccess = () => {\n const db = request.result;\n // A schema upgrade in another tab invalidates this connection. Close\n // it and clear the cached promise so the next operation reopens a\n // usable connection instead of repeatedly targeting a dead database.\n db.onversionchange = () => {\n db.close();\n if (dbPromise) dbPromise = null;\n };\n resolve(db);\n };\n request.onerror = () => reject(request.error ?? new Error('Failed to open replay database.'));\n });\n dbPromise = pending;\n // Do not permanently cache a rejected open promise. IndexedDB can fail\n // transiently (quota, private-mode initialization, a closing connection,\n // or a browser shutdown); the next operation must be able to retry.\n void pending.catch(() => {\n if (dbPromise === pending) dbPromise = null;\n });\n return pending;\n };\n return {\n async load() {\n const db = await open();\n return new Promise((resolve, reject) => {\n let request: IDBRequest;\n try {\n request = db.transaction(storeName, 'readonly').objectStore(storeName).getAll();\n } catch (error) {\n invalidate(db);\n reject(error);\n return;\n }\n request.onsuccess = () => resolve((request.result as Array<{ messages: DataBusMessage<TData>[] }>).flatMap(record => record.messages));\n request.onerror = () => {\n invalidate(db);\n reject(request.error ?? new Error('Failed to load replay history.'));\n };\n });\n },\n append(message) {\n return serializeMutation(async () => {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n let transaction: IDBTransaction;\n try { transaction = db.transaction(storeName, 'readwrite'); }\n catch (error) { invalidate(db); reject(error); return; }\n const store = transaction.objectStore(storeName);\n const request = store.get(message.topic);\n request.onsuccess = () => {\n let messages = ((request.result?.messages ?? []) as DataBusMessage<TData>[]).concat(message);\n if (pruneStrategy !== 'count' && retentionMs !== undefined) {\n const cutoff = Date.now() - retentionMs;\n messages = messages.filter(item => item.timestamp === undefined || item.timestamp >= cutoff);\n }\n if (pruneStrategy !== 'age') messages = messages.slice(-maxPerTopic);\n store.put({ topic: message.topic, messages });\n };\n request.onerror = () => { invalidate(db); reject(request.error ?? new Error('Failed to read replay history.')); };\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => { invalidate(db); reject(transaction.error ?? new Error('Failed to persist replay history.')); };\n });\n });\n },\n appendBatch(messages) {\n if (messages.length === 0) return Promise.resolve();\n return serializeMutation(async () => {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n let transaction: IDBTransaction;\n try { transaction = db.transaction(storeName, 'readwrite'); }\n catch (error) { invalidate(db); reject(error); return; }\n const store = transaction.objectStore(storeName);\n const grouped = new Map<string, DataBusMessage<TData>[]>();\n for (const message of messages) grouped.set(message.topic, [...(grouped.get(message.topic) ?? []), message]);\n for (const [topic, topicMessages] of grouped) {\n const request = store.get(topic);\n request.onsuccess = () => {\n let history = ((request.result?.messages ?? []) as DataBusMessage<TData>[]).concat(topicMessages);\n if (pruneStrategy !== 'count' && retentionMs !== undefined) {\n const cutoff = Date.now() - retentionMs;\n history = history.filter(item => item.timestamp === undefined || item.timestamp >= cutoff);\n }\n if (pruneStrategy !== 'age') history = history.slice(-maxPerTopic);\n store.put({ topic, messages: history });\n };\n request.onerror = () => { invalidate(db); reject(request.error ?? new Error('Failed to read replay history.')); };\n }\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => { invalidate(db); reject(transaction.error ?? new Error('Failed to persist replay history batch.')); };\n });\n });\n },\n clear() {\n return serializeMutation(async () => {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n let transaction: IDBTransaction;\n try { transaction = db.transaction(storeName, 'readwrite'); }\n catch (error) { invalidate(db); reject(error); return; }\n transaction.objectStore(storeName).clear();\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => { invalidate(db); reject(transaction.error ?? new Error('Failed to clear replay history.')); };\n });\n });\n },\n clearTopic(topic) {\n return serializeMutation(async () => {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n let transaction: IDBTransaction;\n try { transaction = db.transaction(storeName, 'readwrite'); }\n catch (error) { invalidate(db); reject(error); return; }\n transaction.objectStore(storeName).delete(topic);\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => { invalidate(db); reject(transaction.error ?? new Error('Failed to clear topic replay history.')); };\n });\n });\n },\n clearBefore(timestamp) {\n return serializeMutation(async () => {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n let transaction: IDBTransaction;\n try { transaction = db.transaction(storeName, 'readwrite'); }\n catch (error) { invalidate(db); reject(error); return; }\n const store = transaction.objectStore(storeName);\n const request = store.getAll();\n request.onsuccess = () => {\n for (const record of request.result as Array<{ topic: string; messages: DataBusMessage<TData>[] }>) {\n const messages = record.messages.filter(message => message.timestamp === undefined || message.timestamp >= timestamp);\n if (messages.length === 0) store.delete(record.topic);\n else if (messages.length !== record.messages.length) store.put({ topic: record.topic, messages });\n }\n };\n request.onerror = () => { invalidate(db); reject(request.error ?? new Error('Failed to read replay history.')); };\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => { invalidate(db); reject(transaction.error ?? new Error('Failed to prune replay history.')); };\n });\n });\n }\n };\n}\n", "/**\n * WebSocketTransport \u2014 a dependency-free transport over a plain WebSocket.\n *\n * Validates the `DataBusTransport` abstraction with a second, minimal backend:\n * any WebSocket server that speaks the tiny JSON protocol below can back the\n * same cross-tab clustering stack (owner dedup, sticky routes, EVENT fan-out)\n * that the Centrifuge backend uses.\n *\n * Wire protocol (JSON text frames):\n * - client \u2192 server: `{\"op\":\"subscribe\"|\"unsubscribe\"|\"publish\",\"topic\":...,\"data\":...}`\n * - server \u2192 client: `{\"topic\":...,\"data\":...}` for publications; anything\n * without a string `topic` field is ignored (forward-compatible).\n */\nimport { CrossTabDataBus } from './core/data-bus';\nimport { parseDataBusPublication } from './core/publication';\nimport type { CrossTabDataBusOptions } from './core/data-bus';\nimport type {\n DataBusTransport,\n DataBusTransportHandlers,\n DataBusPublishOptions,\n DataBusMessage,\n MaybePromise,\n WorkerStatus\n} from './core/types';\n\n/** Minimal WebSocket surface used by the transport. Matches the browser\n * `WebSocket` subset the transport touches; injectable for tests and runtimes. */\nexport interface WebSocketLike {\n /** Current connection state; 1 (OPEN) means frames may be sent. */\n readonly readyState?: number;\n send(data: string | ArrayBuffer): void;\n close(code?: number, reason?: string): void;\n onopen: (() => void) | null;\n onclose: (() => void) | null;\n onerror: (() => void) | null;\n onmessage: ((event: { data: unknown }) => void) | null;\n}\n\n/** Connection configuration for {@link WebSocketTransport}. */\nexport interface WebSocketDataBusConfig {\n /** WebSocket endpoint, e.g. `wss://example.test/ws`. */\n url: string;\n /** Subprotocol(s) passed to the WebSocket handshake. */\n protocols?: string | string[];\n /** Custom socket factory. Defaults to the global `WebSocket`; injectable\n * for tests and non-browser runtimes. */\n webSocketFactory?: (url: string, protocols?: string | string[]) => WebSocketLike;\n}\n\n/** Options for creating a fully-configured CrossTabDataBus with a WebSocket transport. */\nexport interface CreateWebSocketDataBusOptions<TData = unknown>\n extends Omit<\n CrossTabDataBusOptions<WebSocketDataBusConfig, TData>,\n 'autoStart' | 'clusterKey' | 'initialConfig' | 'transport'\n > {\n /** WebSocket connection configuration. */\n connection: WebSocketDataBusConfig;\n /** Cluster key for cross-tab coordination. Defaults to the connection URL. */\n clusterKey?: string;\n}\n\nconst WS_OPEN = 1;\n\n/** Transport that talks a minimal JSON protocol over a plain WebSocket.\n * Connection lifecycle maps directly to the DataBus status vocabulary:\n * open \u2192 `connected`, close \u2192 `disconnected`, error \u2192 `error` (which the\n * DataBus treats as its auto-recovery trigger). The transport holds no\n * reconnection logic of its own \u2014 reopening is the DataBus's job. */\nexport class WebSocketTransport<TData = unknown>\n implements DataBusTransport<WebSocketDataBusConfig, TData>\n{\n readonly diagnosticsName = 'websocket';\n readonly diagnosticsBackend = 'native-websocket';\n private socket: WebSocketLike | null = null;\n private handlers: DataBusTransportHandlers<TData> | null = null;\n private readonly subscribedTopics = new Set<string>();\n\n constructor(private readonly connection: WebSocketDataBusConfig) {}\n\n /** Open the WebSocket and wire lifecycle listeners. A factory failure is\n * reported through `onStatus('error')` so the DataBus can recover. */\n start(config: WebSocketDataBusConfig, handlers: DataBusTransportHandlers<TData>): MaybePromise<void> {\n if (this.socket) return;\n this.handlers = handlers;\n // The factory may live on the constructor connection (createWebSocketDataBus\n // path) or on the runtime config (direct transport use) \u2014 accept both.\n const factory = config.webSocketFactory ?? this.connection.webSocketFactory ?? defaultWebSocketFactory;\n const protocols = config.protocols ?? this.connection.protocols;\n let socket: WebSocketLike;\n try {\n socket = factory(config.url, protocols);\n } catch (error) {\n handlers.onStatus('error');\n handlers.onError(error);\n return;\n }\n socket.onopen = () => {\n if (this.socket !== socket || this.handlers !== handlers) return;\n // Re-assert every topic so a reopened socket (recovery path) restores\n // the server-side subscriptions without DataBus involvement.\n for (const topic of this.subscribedTopics) {\n this.sendFrame({ op: 'subscribe', topic });\n }\n handlers.onStatus('connected');\n };\n socket.onclose = () => {\n if (this.socket === socket && this.handlers === handlers) handlers.onStatus('disconnected');\n };\n socket.onerror = () => {\n if (this.socket === socket && this.handlers === handlers) handlers.onStatus('error');\n };\n socket.onmessage = event => {\n if (this.socket === socket && this.handlers === handlers) void this.handleMessage(event.data);\n };\n this.socket = socket;\n }\n\n /** Idempotent: re-subscribing an active topic re-sends the frame but does\n * not duplicate the local tracking entry. */\n subscribe(topic: string): MaybePromise<void> {\n this.subscribedTopics.add(topic);\n this.sendFrame({ op: 'subscribe', topic });\n }\n\n /** Idempotent: unsubscribing an unknown topic is a no-op. */\n unsubscribe(topic: string): MaybePromise<void> {\n this.subscribedTopics.delete(topic);\n this.sendFrame({ op: 'unsubscribe', topic });\n }\n\n /** Publish `data` to `topic` as a JSON frame. Requires an open socket. */\n publish(topic: string, data: unknown, options?: DataBusPublishOptions): MaybePromise<void> {\n if (data instanceof ArrayBuffer) {\n this.sendBinaryFrame(topic, data, options?.messageId, options?.timestamp);\n return;\n }\n this.sendFrame({\n op: 'publish',\n topic,\n data,\n ...(options?.messageId === undefined ? {} : { messageId: options.messageId }),\n ...(options?.timestamp === undefined ? {} : { timestamp: options.timestamp })\n });\n }\n\n /** Close the socket and drop all state. Safe to call multiple times. */\n stop(): MaybePromise<void> {\n const socket = this.socket;\n this.socket = null;\n this.handlers = null;\n this.subscribedTopics.clear();\n socket?.close();\n }\n\n /** Send one JSON frame. Frames are dropped with an `onError` report when\n * the socket is not open \u2014 subscribe frames are re-sent on open, so the\n * only real loss is a publish during a disconnect window. */\n private sendFrame(payload: { op: string; topic: string; data?: unknown; messageId?: string; timestamp?: number }): void {\n if (this.socket?.readyState !== WS_OPEN) {\n this.handlers?.onError(new Error(`WebSocket is not open; dropped \"${payload.op}\" frame.`));\n return;\n }\n this.socket.send(JSON.stringify(payload));\n }\n\n private sendBinaryFrame(topic: string, data: ArrayBuffer, messageId?: string, timestamp?: number): void {\n if (messageId !== undefined || timestamp !== undefined) {\n // Binary frames retain their compact legacy shape; metadata is sent as a\n // JSON envelope so IDs are never silently lost.\n this.sendFrame({\n op: 'publish',\n topic,\n data: Array.from(new Uint8Array(data)),\n ...(messageId === undefined ? {} : { messageId }),\n ...(timestamp === undefined ? {} : { timestamp })\n });\n return;\n }\n if (this.socket?.readyState !== WS_OPEN) {\n this.handlers?.onError(new Error('WebSocket is not open; dropped \"publish\" frame.'));\n return;\n }\n const topicBytes = new TextEncoder().encode(topic);\n if (topicBytes.length > 0xffff) {\n this.handlers?.onError(new Error('WebSocket topic is too long for a binary frame.'));\n return;\n }\n const frame = new Uint8Array(3 + topicBytes.length + data.byteLength);\n frame[0] = 0xc7;\n new DataView(frame.buffer).setUint16(1, topicBytes.length);\n frame.set(topicBytes, 3);\n frame.set(new Uint8Array(data), 3 + topicBytes.length);\n this.socket.send(frame.buffer);\n }\n\n /** Parse a server frame. Only objects carrying a string `topic` are\n * publications; malformed JSON and unknown shapes are ignored so a chatty\n * server cannot crash the message path. */\n private async handleMessage(raw: unknown): Promise<void> {\n // Browser WebSockets may deliver binary frames as Blob unless\n // `binaryType = 'arraybuffer'` is explicitly configured by the host.\n // Normalize Blob asynchronously and reuse the exact ArrayBuffer parser.\n if (typeof Blob !== 'undefined' && raw instanceof Blob) {\n try {\n await this.handleMessage(await raw.arrayBuffer());\n } catch (error) {\n this.handlers?.onError(error);\n }\n return;\n }\n let parsed: unknown;\n if (raw instanceof ArrayBuffer) {\n const bytes = new Uint8Array(raw);\n if (bytes[0] !== 0xc7 || bytes.length < 3) return;\n const topicLength = new DataView(raw).getUint16(1);\n if (bytes.length < 3 + topicLength) return;\n const topic = new TextDecoder().decode(bytes.subarray(3, 3 + topicLength));\n const data = bytes.slice(3 + topicLength).buffer;\n this.handlers?.onMessage({ topic, data: data as TData });\n return;\n }\n if (typeof raw !== 'string') return;\n try {\n parsed = JSON.parse(raw);\n } catch {\n this.handlers?.onError(new Error('WebSocket server sent a non-JSON frame.'));\n return;\n }\n if (!parsed || typeof parsed !== 'object') return;\n const publication = parseDataBusPublication<TData>(parsed);\n if (publication) this.handlers?.onMessage(publication as DataBusMessage<TData>);\n }\n}\n\n/** Resolve the platform WebSocket, or null in runtimes without one (SSR/Node). */\nfunction defaultWebSocketFactory(url: string, protocols?: string | string[]): WebSocketLike {\n if (typeof WebSocket === 'undefined') {\n throw new Error('WebSocketTransport requires a WebSocket implementation.');\n }\n return new WebSocket(url, protocols) as unknown as WebSocketLike;\n}\n\n/** Create a CrossTabDataBus backed by a plain WebSocket transport.\n * Cross-tab clustering (owner dedup, sticky routes, failover) works identically\n * to the Centrifuge backend \u2014 only the transport I/O differs. */\nexport function createWebSocketDataBus<TData = unknown>(\n options: CreateWebSocketDataBusOptions<TData>\n): CrossTabDataBus<WebSocketDataBusConfig, TData> {\n const { clusterKey, connection, ...dataBusOptions } = options;\n return new CrossTabDataBus({\n ...dataBusOptions,\n autoStart: true,\n clusterKey: clusterKey ?? connection.url,\n initialConfig: connection,\n transport: new WebSocketTransport<TData>(connection)\n });\n}\n\n/** Re-export for convenience: the status type used by the transport. */\nexport type { WorkerStatus };\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAwBO,SAAS,iCACd,SACiC;AACjC,QAAM,YAAY,WAAW;AAC7B,MAAI,CAAC,UAAW,OAAM,IAAI,MAAM,+CAA+C;AAC/E,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,YAAY;AAClB,QAAM,cAAc,QAAQ;AAC5B,QAAM,gBAAgB,QAAQ,iBAAiB;AAC/C,QAAM,cAAc,QAAQ;AAC5B,MAAI,CAAC,CAAC,SAAS,OAAO,MAAM,EAAE,SAAS,aAAa,EAAG,OAAM,IAAI,UAAU,4CAA4C;AACvH,MAAI,gBAAgB,WAAc,CAAC,OAAO,SAAS,WAAW,KAAK,eAAe,GAAI,OAAM,IAAI,UAAU,+CAA+C;AACzJ,MAAI,CAAC,OAAO,cAAc,WAAW,KAAK,eAAe,GAAG;AAC1D,UAAM,IAAI,UAAU,oDAAoD,OAAO,WAAW,CAAC,GAAG;AAAA,EAChG;AACA,MAAI,YAAyC;AAC7C,QAAM,aAAa,CAAC,OAA0B;AAC5C,QAAI,WAAW;AACb,WAAK,UAAU,KAAK,aAAW;AAC7B,YAAI,YAAY,IAAI;AAClB,kBAAQ,MAAM;AACd,sBAAY;AAAA,QACd;AAAA,MACF,GAAG,MAAM,MAAS;AAAA,IACpB;AAAA,EACF;AAIA,MAAI,gBAA+B,QAAQ,QAAQ;AACnD,QAAM,oBAAoB,CAAC,aAAiD;AAC1E,UAAM,OAAO,cAAc,KAAK,UAAU,QAAQ;AAClD,oBAAgB,KAAK,MAAM,MAAM,MAAS;AAC1C,WAAO;AAAA,EACT;AACA,QAAM,OAAO,MAA4B;AACvC,QAAI,UAAW,QAAO;AACtB,UAAM,UAAU,IAAI,QAAqB,CAAC,SAAS,WAAW;AAC5D,YAAM,UAAU,UAAU,KAAK,QAAQ,CAAC;AACxC,cAAQ,kBAAkB,MAAM,QAAQ,OAAO,kBAAkB,WAAW,EAAE,SAAS,QAAQ,CAAC;AAChG,cAAQ,YAAY,MAAM;AACxB,cAAM,KAAK,QAAQ;AAInB,WAAG,kBAAkB,MAAM;AACzB,aAAG,MAAM;AACT,cAAI,UAAW,aAAY;AAAA,QAC7B;AACA,gBAAQ,EAAE;AAAA,MACZ;AACA,cAAQ,UAAU,MAAM,OAAO,QAAQ,SAAS,IAAI,MAAM,iCAAiC,CAAC;AAAA,IAC9F,CAAC;AACD,gBAAY;AAIZ,SAAK,QAAQ,MAAM,MAAM;AACvB,UAAI,cAAc,QAAS,aAAY;AAAA,IACzC,CAAC;AACD,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,MAAM,OAAO;AACX,YAAM,KAAK,MAAM,KAAK;AACtB,aAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAI;AACJ,YAAI;AACF,oBAAU,GAAG,YAAY,WAAW,UAAU,EAAE,YAAY,SAAS,EAAE,OAAO;AAAA,QAChF,SAAS,OAAO;AACd,qBAAW,EAAE;AACb,iBAAO,KAAK;AACZ;AAAA,QACF;AACA,gBAAQ,YAAY,MAAM,QAAS,QAAQ,OAAwD,QAAQ,YAAU,OAAO,QAAQ,CAAC;AACrI,gBAAQ,UAAU,MAAM;AACtB,qBAAW,EAAE;AACb,iBAAO,QAAQ,SAAS,IAAI,MAAM,gCAAgC,CAAC;AAAA,QACrE;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,OAAO,SAAS;AACd,aAAO,kBAAkB,YAAY;AACnC,cAAM,KAAK,MAAM,KAAK;AACtB,cAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC7C,cAAI;AACJ,cAAI;AAAE,0BAAc,GAAG,YAAY,WAAW,WAAW;AAAA,UAAG,SACrD,OAAO;AAAE,uBAAW,EAAE;AAAG,mBAAO,KAAK;AAAG;AAAA,UAAQ;AACvD,gBAAM,QAAQ,YAAY,YAAY,SAAS;AAC/C,gBAAM,UAAU,MAAM,IAAI,QAAQ,KAAK;AACvC,kBAAQ,YAAY,MAAM;AACxB,gBAAI,YAAa,QAAQ,QAAQ,YAAY,CAAC,GAA+B,OAAO,OAAO;AAC3F,gBAAI,kBAAkB,WAAW,gBAAgB,QAAW;AAC1D,oBAAM,SAAS,KAAK,IAAI,IAAI;AAC5B,yBAAW,SAAS,OAAO,UAAQ,KAAK,cAAc,UAAa,KAAK,aAAa,MAAM;AAAA,YAC7F;AACA,gBAAI,kBAAkB,MAAO,YAAW,SAAS,MAAM,CAAC,WAAW;AACnE,kBAAM,IAAI,EAAE,OAAO,QAAQ,OAAO,SAAS,CAAC;AAAA,UAC9C;AACA,kBAAQ,UAAU,MAAM;AAAE,uBAAW,EAAE;AAAG,mBAAO,QAAQ,SAAS,IAAI,MAAM,gCAAgC,CAAC;AAAA,UAAG;AAChH,sBAAY,aAAa,MAAM,QAAQ;AACvC,sBAAY,UAAU,MAAM;AAAE,uBAAW,EAAE;AAAG,mBAAO,YAAY,SAAS,IAAI,MAAM,mCAAmC,CAAC;AAAA,UAAG;AAAA,QAC3H,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,IACA,YAAY,UAAU;AACpB,UAAI,SAAS,WAAW,EAAG,QAAO,QAAQ,QAAQ;AAClD,aAAO,kBAAkB,YAAY;AACnC,cAAM,KAAK,MAAM,KAAK;AACtB,cAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,cAAI;AACJ,cAAI;AAAE,0BAAc,GAAG,YAAY,WAAW,WAAW;AAAA,UAAG,SACrD,OAAO;AAAE,uBAAW,EAAE;AAAG,mBAAO,KAAK;AAAG;AAAA,UAAQ;AACvD,gBAAM,QAAQ,YAAY,YAAY,SAAS;AAC/C,gBAAM,UAAU,oBAAI,IAAqC;AACzD,qBAAW,WAAW,SAAU,SAAQ,IAAI,QAAQ,OAAO,CAAC,GAAI,QAAQ,IAAI,QAAQ,KAAK,KAAK,CAAC,GAAI,OAAO,CAAC;AAC3G,qBAAW,CAAC,OAAO,aAAa,KAAK,SAAS;AAC5C,kBAAM,UAAU,MAAM,IAAI,KAAK;AAC/B,oBAAQ,YAAY,MAAM;AACxB,kBAAI,WAAY,QAAQ,QAAQ,YAAY,CAAC,GAA+B,OAAO,aAAa;AAChG,kBAAI,kBAAkB,WAAW,gBAAgB,QAAW;AAC1D,sBAAM,SAAS,KAAK,IAAI,IAAI;AAC5B,0BAAU,QAAQ,OAAO,UAAQ,KAAK,cAAc,UAAa,KAAK,aAAa,MAAM;AAAA,cAC3F;AACA,kBAAI,kBAAkB,MAAO,WAAU,QAAQ,MAAM,CAAC,WAAW;AACjE,oBAAM,IAAI,EAAE,OAAO,UAAU,QAAQ,CAAC;AAAA,YACxC;AACA,oBAAQ,UAAU,MAAM;AAAE,yBAAW,EAAE;AAAG,qBAAO,QAAQ,SAAS,IAAI,MAAM,gCAAgC,CAAC;AAAA,YAAG;AAAA,UAClH;AACA,sBAAY,aAAa,MAAM,QAAQ;AACvC,sBAAY,UAAU,MAAM;AAAE,uBAAW,EAAE;AAAG,mBAAO,YAAY,SAAS,IAAI,MAAM,yCAAyC,CAAC;AAAA,UAAG;AAAA,QACnI,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,IACA,QAAQ;AACN,aAAO,kBAAkB,YAAY;AACnC,cAAM,KAAK,MAAM,KAAK;AACtB,cAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC7C,cAAI;AACJ,cAAI;AAAE,0BAAc,GAAG,YAAY,WAAW,WAAW;AAAA,UAAG,SACrD,OAAO;AAAE,uBAAW,EAAE;AAAG,mBAAO,KAAK;AAAG;AAAA,UAAQ;AACvD,sBAAY,YAAY,SAAS,EAAE,MAAM;AACzC,sBAAY,aAAa,MAAM,QAAQ;AACvC,sBAAY,UAAU,MAAM;AAAE,uBAAW,EAAE;AAAG,mBAAO,YAAY,SAAS,IAAI,MAAM,iCAAiC,CAAC;AAAA,UAAG;AAAA,QACzH,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,IACA,WAAW,OAAO;AAChB,aAAO,kBAAkB,YAAY;AACnC,cAAM,KAAK,MAAM,KAAK;AACtB,cAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC7C,cAAI;AACJ,cAAI;AAAE,0BAAc,GAAG,YAAY,WAAW,WAAW;AAAA,UAAG,SACrD,OAAO;AAAE,uBAAW,EAAE;AAAG,mBAAO,KAAK;AAAG;AAAA,UAAQ;AACvD,sBAAY,YAAY,SAAS,EAAE,OAAO,KAAK;AAC/C,sBAAY,aAAa,MAAM,QAAQ;AACvC,sBAAY,UAAU,MAAM;AAAE,uBAAW,EAAE;AAAG,mBAAO,YAAY,SAAS,IAAI,MAAM,uCAAuC,CAAC;AAAA,UAAG;AAAA,QAC/H,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,IACA,YAAY,WAAW;AACrB,aAAO,kBAAkB,YAAY;AACnC,cAAM,KAAK,MAAM,KAAK;AACtB,cAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC7C,cAAI;AACJ,cAAI;AAAE,0BAAc,GAAG,YAAY,WAAW,WAAW;AAAA,UAAG,SACrD,OAAO;AAAE,uBAAW,EAAE;AAAG,mBAAO,KAAK;AAAG;AAAA,UAAQ;AACvD,gBAAM,QAAQ,YAAY,YAAY,SAAS;AAC/C,gBAAM,UAAU,MAAM,OAAO;AAC7B,kBAAQ,YAAY,MAAM;AACxB,uBAAW,UAAU,QAAQ,QAAuE;AAClG,oBAAM,WAAW,OAAO,SAAS,OAAO,aAAW,QAAQ,cAAc,UAAa,QAAQ,aAAa,SAAS;AACpH,kBAAI,SAAS,WAAW,EAAG,OAAM,OAAO,OAAO,KAAK;AAAA,uBAC3C,SAAS,WAAW,OAAO,SAAS,OAAQ,OAAM,IAAI,EAAE,OAAO,OAAO,OAAO,SAAS,CAAC;AAAA,YAClG;AAAA,UACF;AACA,kBAAQ,UAAU,MAAM;AAAE,uBAAW,EAAE;AAAG,mBAAO,QAAQ,SAAS,IAAI,MAAM,gCAAgC,CAAC;AAAA,UAAG;AAChH,sBAAY,aAAa,MAAM,QAAQ;AACvC,sBAAY,UAAU,MAAM;AAAE,uBAAW,EAAE;AAAG,mBAAO,YAAY,SAAS,IAAI,MAAM,iCAAiC,CAAC;AAAA,UAAG;AAAA,QACzH,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AClJA,IAAM,UAAU;AAOT,IAAM,qBAAN,MAEP;AAAA,EAOE,YAA6B,YAAoC;AAApC;AAAA,EAAqC;AAAA,EANzD,kBAAkB;AAAA,EAClB,qBAAqB;AAAA,EACtB,SAA+B;AAAA,EAC/B,WAAmD;AAAA,EAC1C,mBAAmB,oBAAI,IAAY;AAAA;AAAA;AAAA,EAMpD,MAAM,QAAgC,UAA+D;AACnG,QAAI,KAAK,OAAQ;AACjB,SAAK,WAAW;AAGhB,UAAM,UAAU,OAAO,oBAAoB,KAAK,WAAW,oBAAoB;AAC/E,UAAM,YAAY,OAAO,aAAa,KAAK,WAAW;AACtD,QAAI;AACJ,QAAI;AACF,eAAS,QAAQ,OAAO,KAAK,SAAS;AAAA,IACxC,SAAS,OAAO;AACd,eAAS,SAAS,OAAO;AACzB,eAAS,QAAQ,KAAK;AACtB;AAAA,IACF;AACA,WAAO,SAAS,MAAM;AACpB,UAAI,KAAK,WAAW,UAAU,KAAK,aAAa,SAAU;AAG1D,iBAAW,SAAS,KAAK,kBAAkB;AACzC,aAAK,UAAU,EAAE,IAAI,aAAa,MAAM,CAAC;AAAA,MAC3C;AACA,eAAS,SAAS,WAAW;AAAA,IAC/B;AACA,WAAO,UAAU,MAAM;AACrB,UAAI,KAAK,WAAW,UAAU,KAAK,aAAa,SAAU,UAAS,SAAS,cAAc;AAAA,IAC5F;AACA,WAAO,UAAU,MAAM;AACrB,UAAI,KAAK,WAAW,UAAU,KAAK,aAAa,SAAU,UAAS,SAAS,OAAO;AAAA,IACrF;AACA,WAAO,YAAY,WAAS;AAC1B,UAAI,KAAK,WAAW,UAAU,KAAK,aAAa,SAAU,MAAK,KAAK,cAAc,MAAM,IAAI;AAAA,IAC9F;AACA,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA,EAIA,UAAU,OAAmC;AAC3C,SAAK,iBAAiB,IAAI,KAAK;AAC/B,SAAK,UAAU,EAAE,IAAI,aAAa,MAAM,CAAC;AAAA,EAC3C;AAAA;AAAA,EAGA,YAAY,OAAmC;AAC7C,SAAK,iBAAiB,OAAO,KAAK;AAClC,SAAK,UAAU,EAAE,IAAI,eAAe,MAAM,CAAC;AAAA,EAC7C;AAAA;AAAA,EAGA,QAAQ,OAAe,MAAe,SAAqD;AACzF,QAAI,gBAAgB,aAAa;AAC/B,WAAK,gBAAgB,OAAO,MAAM,SAAS,WAAW,SAAS,SAAS;AACxE;AAAA,IACF;AACA,SAAK,UAAU;AAAA,MACb,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,GAAI,SAAS,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;AAAA,MAC3E,GAAI,SAAS,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;AAAA,IAC7E,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,OAA2B;AACzB,UAAM,SAAS,KAAK;AACpB,SAAK,SAAS;AACd,SAAK,WAAW;AAChB,SAAK,iBAAiB,MAAM;AAC5B,YAAQ,MAAM;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAU,SAAsG;AACtH,QAAI,KAAK,QAAQ,eAAe,SAAS;AACvC,WAAK,UAAU,QAAQ,IAAI,MAAM,mCAAmC,QAAQ,EAAE,UAAU,CAAC;AACzF;AAAA,IACF;AACA,SAAK,OAAO,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,EAC1C;AAAA,EAEQ,gBAAgB,OAAe,MAAmB,WAAoB,WAA0B;AACtG,QAAI,cAAc,UAAa,cAAc,QAAW;AAGtD,WAAK,UAAU;AAAA,QACb,IAAI;AAAA,QACJ;AAAA,QACA,MAAM,MAAM,KAAK,IAAI,WAAW,IAAI,CAAC;AAAA,QACrC,GAAI,cAAc,SAAY,CAAC,IAAI,EAAE,UAAU;AAAA,QAC/C,GAAI,cAAc,SAAY,CAAC,IAAI,EAAE,UAAU;AAAA,MACjD,CAAC;AACD;AAAA,IACF;AACA,QAAI,KAAK,QAAQ,eAAe,SAAS;AACvC,WAAK,UAAU,QAAQ,IAAI,MAAM,iDAAiD,CAAC;AACnF;AAAA,IACF;AACA,UAAM,aAAa,IAAI,YAAY,EAAE,OAAO,KAAK;AACjD,QAAI,WAAW,SAAS,OAAQ;AAC9B,WAAK,UAAU,QAAQ,IAAI,MAAM,iDAAiD,CAAC;AACnF;AAAA,IACF;AACA,UAAM,QAAQ,IAAI,WAAW,IAAI,WAAW,SAAS,KAAK,UAAU;AACpE,UAAM,CAAC,IAAI;AACX,QAAI,SAAS,MAAM,MAAM,EAAE,UAAU,GAAG,WAAW,MAAM;AACzD,UAAM,IAAI,YAAY,CAAC;AACvB,UAAM,IAAI,IAAI,WAAW,IAAI,GAAG,IAAI,WAAW,MAAM;AACrD,SAAK,OAAO,KAAK,MAAM,MAAM;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cAAc,KAA6B;AAIvD,QAAI,OAAO,SAAS,eAAe,eAAe,MAAM;AACtD,UAAI;AACF,cAAM,KAAK,cAAc,MAAM,IAAI,YAAY,CAAC;AAAA,MAClD,SAAS,OAAO;AACd,aAAK,UAAU,QAAQ,KAAK;AAAA,MAC9B;AACA;AAAA,IACF;AACA,QAAI;AACJ,QAAI,eAAe,aAAa;AAC9B,YAAM,QAAQ,IAAI,WAAW,GAAG;AAChC,UAAI,MAAM,CAAC,MAAM,OAAQ,MAAM,SAAS,EAAG;AAC3C,YAAM,cAAc,IAAI,SAAS,GAAG,EAAE,UAAU,CAAC;AACjD,UAAI,MAAM,SAAS,IAAI,YAAa;AACpC,YAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,MAAM,SAAS,GAAG,IAAI,WAAW,CAAC;AACzE,YAAM,OAAO,MAAM,MAAM,IAAI,WAAW,EAAE;AAC1C,WAAK,UAAU,UAAU,EAAE,OAAO,KAAoB,CAAC;AACvD;AAAA,IACF;AACA,QAAI,OAAO,QAAQ,SAAU;AAC7B,QAAI;AACF,eAAS,KAAK,MAAM,GAAG;AAAA,IACzB,QAAQ;AACN,WAAK,UAAU,QAAQ,IAAI,MAAM,yCAAyC,CAAC;AAC3E;AAAA,IACF;AACA,QAAI,CAAC,UAAU,OAAO,WAAW,SAAU;AAC3C,UAAM,cAAc,wBAA+B,MAAM;AACzD,QAAI,YAAa,MAAK,UAAU,UAAU,WAAoC;AAAA,EAChF;AACF;AAGA,SAAS,wBAAwB,KAAa,WAA8C;AAC1F,MAAI,OAAO,cAAc,aAAa;AACpC,UAAM,IAAI,MAAM,yDAAyD;AAAA,EAC3E;AACA,SAAO,IAAI,UAAU,KAAK,SAAS;AACrC;AAKO,SAAS,uBACd,SACgD;AAChD,QAAM,EAAE,YAAY,YAAY,GAAG,eAAe,IAAI;AACtD,SAAO,IAAI,gBAAgB;AAAA,IACzB,GAAG;AAAA,IACH,WAAW;AAAA,IACX,YAAY,cAAc,WAAW;AAAA,IACrC,eAAe;AAAA,IACf,WAAW,IAAI,mBAA0B,UAAU;AAAA,EACrD,CAAC;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/docs/roadmap.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Roadmap
|
|
2
2
|
|
|
3
|
-
0.20.
|
|
3
|
+
0.20.71 is the current development line. The project is intentionally continuing through reliability-focused minor releases before a 1.0.0 stability freeze.
|
|
4
|
+
|
|
5
|
+
## 0.20.71 delivered scope
|
|
6
|
+
|
|
7
|
+
- Added optional `appendBatch` replay persistence and IndexedDB transaction coalescing for publication bursts.
|
|
4
8
|
|
|
5
9
|
## 0.20.70 delivered scope
|
|
6
10
|
|
package/docs/zh/roadmap.md
CHANGED
package/package.json
CHANGED