cross-tab-worker-databus 0.10.0 → 0.20.6
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 +222 -0
- package/README.md +1 -0
- package/README.zh.md +1 -0
- package/dist/centrifuge.js +1 -1
- package/dist/centrifuge.shared.worker.js +4 -2
- package/dist/centrifuge.shared.worker.js.map +2 -2
- package/dist/centrifuge.worker.js +4 -2
- package/dist/centrifuge.worker.js.map +2 -2
- package/dist/{chunk-ZOPNTR4E.js → chunk-LPS4XOK4.js} +177 -19
- package/dist/{chunk-ZOPNTR4E.js.map → chunk-LPS4XOK4.js.map} +2 -2
- package/dist/cjs/centrifuge.cjs +176 -18
- package/dist/cjs/centrifuge.cjs.map +2 -2
- package/dist/cjs/hooks.cjs +4 -1
- package/dist/cjs/hooks.cjs.map +2 -2
- package/dist/cjs/index.cjs +326 -67
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/cjs/vue.cjs +7 -1
- package/dist/cjs/vue.cjs.map +2 -2
- package/dist/core/data-bus.d.ts +35 -0
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/publication.d.ts.map +1 -1
- package/dist/core/replay-persistence.d.ts.map +1 -1
- package/dist/core/trace.d.ts +11 -1
- package/dist/core/trace.d.ts.map +1 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +4 -1
- package/dist/hooks.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +151 -50
- package/dist/index.js.map +2 -2
- package/dist/vue.d.ts.map +1 -1
- package/dist/vue.js +7 -1
- package/dist/vue.js.map +2 -2
- package/dist/websocket.d.ts.map +1 -1
- package/docs/README.md +1 -0
- package/docs/api.md +11 -4
- package/docs/architecture.md +4 -0
- package/docs/capabilities.md +2 -2
- package/docs/configuration.md +21 -1
- package/docs/release-checklist.md +20 -0
- package/docs/roadmap.md +144 -2
- package/docs/zh/README.md +1 -0
- package/docs/zh/api.md +11 -4
- package/docs/zh/architecture.md +4 -0
- package/docs/zh/capabilities.md +2 -2
- package/docs/zh/configuration.md +21 -1
- package/docs/zh/release-checklist.md +20 -0
- package/docs/zh/roadmap.md +132 -2
- package/package.json +2 -1
package/dist/cjs/vue.cjs
CHANGED
|
@@ -29,6 +29,7 @@ var import_vue = require("vue");
|
|
|
29
29
|
function useCrossTabDataBus(create, deps = []) {
|
|
30
30
|
const bus = (0, import_vue.shallowRef)(null);
|
|
31
31
|
let instance = null;
|
|
32
|
+
let lifecycleGeneration = 0;
|
|
32
33
|
const stop = async () => {
|
|
33
34
|
const current = instance;
|
|
34
35
|
instance = null;
|
|
@@ -36,7 +37,9 @@ function useCrossTabDataBus(create, deps = []) {
|
|
|
36
37
|
if (current) await current.stop();
|
|
37
38
|
};
|
|
38
39
|
const start = () => {
|
|
40
|
+
const generation = ++lifecycleGeneration;
|
|
39
41
|
void stop().then(() => {
|
|
42
|
+
if (generation !== lifecycleGeneration) return;
|
|
40
43
|
const next = create();
|
|
41
44
|
instance = next;
|
|
42
45
|
bus.value = next;
|
|
@@ -53,20 +56,23 @@ function useCrossTabDataBus(create, deps = []) {
|
|
|
53
56
|
}
|
|
54
57
|
function useCrossTabSubscription(bus, topic, handler) {
|
|
55
58
|
let currentBus = null;
|
|
59
|
+
let currentTopic = null;
|
|
56
60
|
let cleanup;
|
|
57
61
|
let latestHandler = handler;
|
|
58
62
|
const stop = () => {
|
|
59
63
|
cleanup?.();
|
|
60
64
|
cleanup = void 0;
|
|
61
65
|
currentBus = null;
|
|
66
|
+
currentTopic = null;
|
|
62
67
|
};
|
|
63
68
|
const sync = () => {
|
|
64
69
|
const nextBus = bus.value;
|
|
65
70
|
const nextTopic = typeof topic === "string" ? topic : topic.value;
|
|
66
|
-
if (nextBus === currentBus && cleanup) return;
|
|
71
|
+
if (nextBus === currentBus && currentTopic === nextTopic && cleanup) return;
|
|
67
72
|
stop();
|
|
68
73
|
if (!nextBus) return;
|
|
69
74
|
currentBus = nextBus;
|
|
75
|
+
currentTopic = nextTopic;
|
|
70
76
|
cleanup = nextBus.subscribe(nextTopic, (message) => latestHandler(message));
|
|
71
77
|
};
|
|
72
78
|
(0, import_vue.watch)(bus, sync, { immediate: true });
|
package/dist/cjs/vue.cjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/vue.ts"],
|
|
4
|
-
"sourcesContent": ["/** Vue 3 composables adapter for cross-tab-worker-databus.\n * Vue is an optional peer dependency; this module is a separate entry point.\n */\nimport { onBeforeUnmount, onMounted, ref, shallowRef, watch, type Ref } from 'vue';\nimport type { CrossTabDataBus } from './core/data-bus';\nimport type { DataBusMessage, WorkerStatus } from './core/types';\n\nexport function useCrossTabDataBus<TConfig, TData>(\n create: () => CrossTabDataBus<TConfig, TData>,\n deps: ReadonlyArray<Ref<unknown> | (() => unknown)> = []\n): Ref<CrossTabDataBus<TConfig, TData> | null> {\n const bus = shallowRef<CrossTabDataBus<TConfig, TData> | null>(null);\n let instance: CrossTabDataBus<TConfig, TData> | null = null;\n const stop = async () => { const current = instance; instance = null; bus.value = null; if (current) await current.stop(); };\n const start = () => { void stop().then(() => { const next = create()
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,iBAA6E;AAItE,SAAS,mBACd,QACA,OAAsD,CAAC,GACV;AAC7C,QAAM,UAAM,uBAAmD,IAAI;AACnE,MAAI,WAAmD;AACvD,QAAM,OAAO,YAAY;AAAE,UAAM,UAAU;AAAU,eAAW;AAAM,QAAI,QAAQ;AAAM,QAAI,QAAS,OAAM,QAAQ,KAAK;AAAA,EAAG;AAC3H,QAAM,QAAQ,MAAM;
|
|
4
|
+
"sourcesContent": ["/** Vue 3 composables adapter for cross-tab-worker-databus.\n * Vue is an optional peer dependency; this module is a separate entry point.\n */\nimport { onBeforeUnmount, onMounted, ref, shallowRef, watch, type Ref } from 'vue';\nimport type { CrossTabDataBus } from './core/data-bus';\nimport type { DataBusMessage, WorkerStatus } from './core/types';\n\nexport function useCrossTabDataBus<TConfig, TData>(\n create: () => CrossTabDataBus<TConfig, TData>,\n deps: ReadonlyArray<Ref<unknown> | (() => unknown)> = []\n): Ref<CrossTabDataBus<TConfig, TData> | null> {\n const bus = shallowRef<CrossTabDataBus<TConfig, TData> | null>(null);\n let instance: CrossTabDataBus<TConfig, TData> | null = null;\n let lifecycleGeneration = 0;\n const stop = async () => { const current = instance; instance = null; bus.value = null; if (current) await current.stop(); };\n const start = () => {\n const generation = ++lifecycleGeneration;\n void stop().then(() => {\n if (generation !== lifecycleGeneration) return;\n const next = create();\n instance = next;\n bus.value = next;\n void next.ready().catch(() => {});\n });\n };\n onMounted(start);\n onBeforeUnmount(() => { void stop(); });\n if (deps.length > 0) watch(deps, start);\n return bus as Ref<CrossTabDataBus<TConfig, TData> | null>;\n}\n\nexport function useCrossTabSubscription<TConfig, TData>(\n bus: Ref<CrossTabDataBus<TConfig, TData> | null>, topic: Ref<string> | string,\n handler: (message: DataBusMessage<TData>) => void\n): void {\n let currentBus: CrossTabDataBus<TConfig, TData> | null = null;\n let currentTopic: string | null = null;\n let cleanup: (() => void) | undefined;\n let latestHandler = handler;\n const stop = () => { cleanup?.(); cleanup = undefined; currentBus = null; currentTopic = null; };\n const sync = () => {\n const nextBus = bus.value;\n const nextTopic = typeof topic === 'string' ? topic : topic.value;\n if (nextBus === currentBus && currentTopic === nextTopic && cleanup) return;\n stop();\n if (!nextBus) return;\n currentBus = nextBus;\n currentTopic = nextTopic;\n cleanup = nextBus.subscribe(nextTopic, message => latestHandler(message));\n };\n watch(bus, sync, { immediate: true });\n if (typeof topic !== 'string') watch(topic, sync);\n watch(() => handler, value => { latestHandler = value; });\n onBeforeUnmount(stop);\n}\n\nexport function useCrossTabStatus<TConfig, TData>(\n bus: Ref<CrossTabDataBus<TConfig, TData> | null>\n): Ref<WorkerStatus> {\n const status = ref<WorkerStatus>('connecting');\n let cleanup: (() => void) | undefined;\n watch(bus, next => {\n cleanup?.(); cleanup = undefined;\n status.value = next?.getStatus() ?? 'connecting';\n if (next) cleanup = next.onStatus(value => { status.value = value; });\n }, { immediate: true });\n onBeforeUnmount(() => cleanup?.());\n return status;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA,iBAA6E;AAItE,SAAS,mBACd,QACA,OAAsD,CAAC,GACV;AAC7C,QAAM,UAAM,uBAAmD,IAAI;AACnE,MAAI,WAAmD;AACvD,MAAI,sBAAsB;AAC1B,QAAM,OAAO,YAAY;AAAE,UAAM,UAAU;AAAU,eAAW;AAAM,QAAI,QAAQ;AAAM,QAAI,QAAS,OAAM,QAAQ,KAAK;AAAA,EAAG;AAC3H,QAAM,QAAQ,MAAM;AAClB,UAAM,aAAa,EAAE;AACrB,SAAK,KAAK,EAAE,KAAK,MAAM;AACrB,UAAI,eAAe,oBAAqB;AACxC,YAAM,OAAO,OAAO;AACpB,iBAAW;AACX,UAAI,QAAQ;AACZ,WAAK,KAAK,MAAM,EAAE,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IAClC,CAAC;AAAA,EACH;AACA,4BAAU,KAAK;AACf,kCAAgB,MAAM;AAAE,SAAK,KAAK;AAAA,EAAG,CAAC;AACtC,MAAI,KAAK,SAAS,EAAG,uBAAM,MAAM,KAAK;AACtC,SAAO;AACT;AAEO,SAAS,wBACd,KAAkD,OAClD,SACM;AACN,MAAI,aAAqD;AACzD,MAAI,eAA8B;AAClC,MAAI;AACJ,MAAI,gBAAgB;AACpB,QAAM,OAAO,MAAM;AAAE,cAAU;AAAG,cAAU;AAAW,iBAAa;AAAM,mBAAe;AAAA,EAAM;AAC/F,QAAM,OAAO,MAAM;AACjB,UAAM,UAAU,IAAI;AACpB,UAAM,YAAY,OAAO,UAAU,WAAW,QAAQ,MAAM;AAC5D,QAAI,YAAY,cAAc,iBAAiB,aAAa,QAAS;AACrE,SAAK;AACL,QAAI,CAAC,QAAS;AACd,iBAAa;AACb,mBAAe;AACf,cAAU,QAAQ,UAAU,WAAW,aAAW,cAAc,OAAO,CAAC;AAAA,EAC1E;AACA,wBAAM,KAAK,MAAM,EAAE,WAAW,KAAK,CAAC;AACpC,MAAI,OAAO,UAAU,SAAU,uBAAM,OAAO,IAAI;AAChD,wBAAM,MAAM,SAAS,WAAS;AAAE,oBAAgB;AAAA,EAAO,CAAC;AACxD,kCAAgB,IAAI;AACtB;AAEO,SAAS,kBACd,KACmB;AACnB,QAAM,aAAS,gBAAkB,YAAY;AAC7C,MAAI;AACJ,wBAAM,KAAK,UAAQ;AACjB,cAAU;AAAG,cAAU;AACvB,WAAO,QAAQ,MAAM,UAAU,KAAK;AACpC,QAAI,KAAM,WAAU,KAAK,SAAS,WAAS;AAAE,aAAO,QAAQ;AAAA,IAAO,CAAC;AAAA,EACtE,GAAG,EAAE,WAAW,KAAK,CAAC;AACtB,kCAAgB,MAAM,UAAU,CAAC;AACjC,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/core/data-bus.d.ts
CHANGED
|
@@ -16,11 +16,27 @@ export interface DataBusReplayOptions<TData = unknown> {
|
|
|
16
16
|
maxPerTopic?: number;
|
|
17
17
|
/** Optional durable history backend. Defaults to in-memory only. */
|
|
18
18
|
persistence?: DataBusReplayPersistence<TData>;
|
|
19
|
+
/** Optional producer-timestamp retention window in milliseconds. */
|
|
20
|
+
retentionMs?: number;
|
|
21
|
+
/** Optional periodic sweep interval for durable retention cleanup. */
|
|
22
|
+
retentionSweepMs?: number;
|
|
23
|
+
/** Optional bounded retry policy for transient persistence failures. */
|
|
24
|
+
persistenceRetry?: DataBusPersistenceRetryOptions;
|
|
25
|
+
}
|
|
26
|
+
export interface DataBusPersistenceRetryOptions {
|
|
27
|
+
/** Total attempts including the initial operation. Default 1. */
|
|
28
|
+
maxAttempts?: number;
|
|
29
|
+
/** Initial delay between attempts. Default 50ms. */
|
|
30
|
+
backoffMs?: number;
|
|
19
31
|
}
|
|
20
32
|
/** Opt-in bounded duplicate suppression for publications carrying `messageId`. */
|
|
21
33
|
export interface DataBusDedupOptions {
|
|
22
34
|
maxEntries?: number;
|
|
23
35
|
ttlMs?: number;
|
|
36
|
+
/** Optional periodic sweep interval for quiet-topic expiry. */
|
|
37
|
+
sweepMs?: number;
|
|
38
|
+
/** Injectable epoch clock for deterministic tests and non-wall-clock hosts. */
|
|
39
|
+
now?: () => number;
|
|
24
40
|
}
|
|
25
41
|
export interface DataBusDedupStats {
|
|
26
42
|
enabled: boolean;
|
|
@@ -56,13 +72,24 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
|
|
|
56
72
|
private readonly replayBuffers;
|
|
57
73
|
private readonly replayMaxPerTopic;
|
|
58
74
|
private readonly replayPersistence;
|
|
75
|
+
private readonly replayRetentionMs;
|
|
76
|
+
private readonly replayRetentionSweepMs;
|
|
77
|
+
private readonly persistenceRetryMaxAttempts;
|
|
78
|
+
private readonly persistenceRetryBackoffMs;
|
|
79
|
+
private persistenceRetryGeneration;
|
|
59
80
|
private readonly replayHydration;
|
|
81
|
+
private replayRetentionCleanup;
|
|
82
|
+
private replayRetentionCutoff;
|
|
83
|
+
private replayRetentionTimer;
|
|
60
84
|
private readonly initialConfig;
|
|
61
85
|
private readonly hasInitialConfig;
|
|
62
86
|
private readonly trace;
|
|
63
87
|
private readonly dedupMaxEntries;
|
|
64
88
|
private readonly dedupTtlMs;
|
|
89
|
+
private readonly dedupSweepMs;
|
|
90
|
+
private dedupSweepTimer;
|
|
65
91
|
private readonly dedupEnabled;
|
|
92
|
+
private readonly now;
|
|
66
93
|
private readonly seenMessageIds;
|
|
67
94
|
private dedupSuppressed;
|
|
68
95
|
private dedupAccepted;
|
|
@@ -146,6 +173,9 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
|
|
|
146
173
|
*/
|
|
147
174
|
private handleTransportMessage;
|
|
148
175
|
private isDuplicate;
|
|
176
|
+
private startDedupSweep;
|
|
177
|
+
private stopDedupSweep;
|
|
178
|
+
private pruneExpiredDedup;
|
|
149
179
|
/** Deliver a message to every local handler registered for its topic,
|
|
150
180
|
* plus every handler registered with a wildcard subscription that matches
|
|
151
181
|
* (e.g. a handler subscribed to "chat.*" receives "chat.room.1"). */
|
|
@@ -154,6 +184,10 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
|
|
|
154
184
|
* No-op when replay is disabled. */
|
|
155
185
|
private recordReplay;
|
|
156
186
|
private hydrateReplay;
|
|
187
|
+
private scheduleReplayRetentionCleanup;
|
|
188
|
+
private startReplayRetentionSweep;
|
|
189
|
+
private stopReplayRetentionSweep;
|
|
190
|
+
private withPersistenceRetry;
|
|
157
191
|
/** Deliver buffered history to a newly-registered handler. For an exact
|
|
158
192
|
* topic this is that topic's ring; for a wildcard subscription every
|
|
159
193
|
* buffered topic matching the pattern contributes (in buffer insertion
|
|
@@ -166,6 +200,7 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
|
|
|
166
200
|
*/
|
|
167
201
|
private updateStatus;
|
|
168
202
|
private reportError;
|
|
203
|
+
private reportPersistenceError;
|
|
169
204
|
private traceSubscription;
|
|
170
205
|
/** Ask the transport to subscribe to a topic (idempotent). */
|
|
171
206
|
private subscribeTransport;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-bus.d.ts","sourceRoot":"","sources":["../../src/core/data-bus.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEtD,OAAO,KAAK,EACV,mBAAmB,EAEnB,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACb,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"data-bus.d.ts","sourceRoot":"","sources":["../../src/core/data-bus.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publication.d.ts","sourceRoot":"","sources":["../../src/core/publication.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,GAAG,OAAO,EACrD,KAAK,EAAE,OAAO,EACd,aAAa,CAAC,EAAE,MAAM,GACrB,kBAAkB,CAAC,KAAK,CAAC,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"publication.d.ts","sourceRoot":"","sources":["../../src/core/publication.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,GAAG,OAAO,EACrD,KAAK,EAAE,OAAO,EACd,aAAa,CAAC,EAAE,MAAM,GACrB,kBAAkB,CAAC,KAAK,CAAC,GAAG,IAAI,CAgClC"}
|
|
@@ -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;CACrB;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,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;CACrB;AAED,sDAAsD;AACtD,wBAAgB,gCAAgC,CAAC,KAAK,GAAG,OAAO,EAC9D,OAAO,EAAE,iCAAiC,GACzC,wBAAwB,CAAC,KAAK,CAAC,CA+IjC"}
|
package/dist/core/trace.d.ts
CHANGED
|
@@ -51,8 +51,9 @@ export interface DataBusErrorTraceEvent {
|
|
|
51
51
|
/** Bounded reliability diagnostics for recovery, acknowledgments, and migrations. */
|
|
52
52
|
export interface DataBusReliabilityTraceEvent {
|
|
53
53
|
type: 'reliability';
|
|
54
|
-
operation: 'transport_recovery' | 'route_ack' | 'route_migration' | 'persistence_cleanup' | 'dedup_suppressed';
|
|
54
|
+
operation: 'transport_recovery' | 'route_ack' | 'route_migration' | 'persistence_cleanup' | 'persistence_retry' | 'dedup_suppressed';
|
|
55
55
|
topic?: string;
|
|
56
|
+
persistenceOperation?: 'load' | 'append' | 'clear' | 'clearTopic' | 'clearBefore';
|
|
56
57
|
attempt?: number;
|
|
57
58
|
durationMs?: number;
|
|
58
59
|
timestamp: number;
|
|
@@ -73,6 +74,8 @@ export interface DataBusMetricsTraceEvent {
|
|
|
73
74
|
dispatchP50Ms: number;
|
|
74
75
|
dispatchP95Ms: number;
|
|
75
76
|
dispatchMaxMs: number;
|
|
77
|
+
dedupAccepted: number;
|
|
78
|
+
dedupSuppressed: number;
|
|
76
79
|
timestamp: number;
|
|
77
80
|
}
|
|
78
81
|
export type DataBusTraceEvent = DataBusLifecycleTraceEvent | DataBusStatusTraceEvent | DataBusSubscriptionTraceEvent | DataBusCoordinationTraceEvent | DataBusErrorTraceEvent | DataBusReliabilityTraceEvent | DataBusMetricsTraceEvent;
|
|
@@ -87,6 +90,8 @@ export interface DataBusTraceOptions {
|
|
|
87
90
|
mode?: DataBusTraceMode;
|
|
88
91
|
/** Aggregation window for `message_metrics` events. Default 5 s. */
|
|
89
92
|
metricsIntervalMs?: number;
|
|
93
|
+
/** Injectable epoch clock for deterministic metrics and lifecycle tests. */
|
|
94
|
+
now?: () => number;
|
|
90
95
|
/** Callback invoked for each emitted trace event. */
|
|
91
96
|
sink: (event: DataBusTraceEvent) => void;
|
|
92
97
|
}
|
|
@@ -112,6 +117,8 @@ export declare class DataBusTraceReporter {
|
|
|
112
117
|
private readonly receivedAt;
|
|
113
118
|
private readonly latencyBuckets;
|
|
114
119
|
private latencySumMs;
|
|
120
|
+
private dedupAccepted;
|
|
121
|
+
private dedupSuppressed;
|
|
115
122
|
constructor(options?: DataBusTraceOptions, now?: () => number);
|
|
116
123
|
/** Start the periodic metrics flush interval. No-op when mode is 'events'
|
|
117
124
|
* (no metrics to emit), when disabled, or when already running. */
|
|
@@ -136,6 +143,9 @@ export declare class DataBusTraceReporter {
|
|
|
136
143
|
* as dispatched but do not produce a latency sample.
|
|
137
144
|
*/
|
|
138
145
|
recordDispatched(topic: string): void;
|
|
146
|
+
/** Record deduplication outcomes for the next metrics window. */
|
|
147
|
+
recordDedupAccepted(): void;
|
|
148
|
+
recordDedupSuppressed(): void;
|
|
139
149
|
/** True when metrics recording is active: enabled and mode includes metrics.
|
|
140
150
|
* Extracted so the four record / flush methods share one guard expression
|
|
141
151
|
* instead of repeating `!this.enabled || this.mode === 'events'` at each. */
|
package/dist/core/trace.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/core/trace.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,uEAAuE;AACvE;;;yDAGyD;AACzD,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,CAAC;AAE5D,oEAAoE;AACpE,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IAChD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,4DAA4D;AAC5D,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,6DAA6D;AAC7D,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,WAAW,GAAG,aAAa,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,sFAAsF;AACtF,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0DAA0D;AAC1D,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,WAAW,GAAG,WAAW,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qFAAqF;AACrF,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,EAAE,oBAAoB,GAAG,WAAW,GAAG,iBAAiB,GAAG,qBAAqB,GAAG,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/core/trace.ts"],"names":[],"mappings":"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"}
|
package/dist/hooks.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjE;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAC/C,MAAM,EAAE,MAAM,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,EAC7C,IAAI,GAAE,cAAmB,GACxB,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjE;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,KAAK,EAC/C,MAAM,EAAE,MAAM,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,EAC7C,IAAI,GAAE,cAAmB,GACxB,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,IAAI,CAiBxC;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,KAAK,EACpD,GAAG,EAAE,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,IAAI,EAC3C,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,KAAK,IAAI,GAChD,IAAI,CAON;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,KAAK,EAC9C,GAAG,EAAE,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,IAAI,GAC1C,YAAY,CAWd"}
|
package/dist/hooks.js
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
import { useEffect, useRef, useState } from "react";
|
|
3
3
|
function useCrossTabDataBus(create, deps = []) {
|
|
4
4
|
const [bus, setBus] = useState(null);
|
|
5
|
+
const lifecycleGeneration = useRef(0);
|
|
5
6
|
useEffect(() => {
|
|
7
|
+
const generation = ++lifecycleGeneration.current;
|
|
6
8
|
const instance = create();
|
|
9
|
+
if (generation !== lifecycleGeneration.current) return;
|
|
7
10
|
setBus(instance);
|
|
8
11
|
void instance.ready().catch(() => {
|
|
9
12
|
});
|
|
10
13
|
return () => {
|
|
11
|
-
setBus(null);
|
|
14
|
+
if (generation === lifecycleGeneration.current) setBus(null);
|
|
12
15
|
void instance.stop();
|
|
13
16
|
};
|
|
14
17
|
}, deps);
|
package/dist/hooks.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/hooks.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * React hooks adapter for cross-tab-worker-databus.\n *\n * A thin, transport-agnostic bridge between the imperative CrossTabDataBus\n * API and React component lifecycles. React is an optional peer dependency \u2014\n * this module is a separate entry point so consumers who don't use React\n * never load it.\n *\n * - `useCrossTabDataBus` owns the bus lifecycle: created on mount, stopped on\n * unmount. It is StrictMode-safe: the double-invoked effect exercises the\n * same stop/recreate path as BFCache suspend/resume.\n * - `useCrossTabSubscription` attaches a message handler with automatic\n * cleanup; the handler is read through a ref, so you can pass inline\n * closures without resubscribing on every render.\n * - `useCrossTabStatus` mirrors `bus.onStatus()` into React state.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport type { DependencyList } from 'react';\nimport type { CrossTabDataBus } from './core/data-bus';\nimport type { DataBusMessage, WorkerStatus } from './core/types';\n\n/**\n * Create a CrossTabDataBus for the component's lifetime.\n *\n * @param create Factory invoked once per effect run. Return a fresh bus \u2014\n * do not share a bus instance between effects, or StrictMode's\n * mount \u2192 stop \u2192 mount cycle will stop the shared instance out from\n * under the second mount.\n * @param deps Re-create the bus when these change (default: create once).\n * @returns The active bus, or `null` before the first effect has run (SSR\n * and the initial render).\n */\nexport function useCrossTabDataBus<TConfig, TData>(\n create: () => CrossTabDataBus<TConfig, TData>,\n deps: DependencyList = []\n): CrossTabDataBus<TConfig, TData> | null {\n const [bus, setBus] = useState<CrossTabDataBus<TConfig, TData> | null>(null);\n useEffect(() => {\n const instance = create();\n setBus(instance);\n void instance.ready().catch(() => {});\n return () => {\n setBus(null);\n void instance.stop();\n };\n // The factory is intentionally not a dependency: callers pass an inline\n // closure and key recreation through `deps` instead.\n }, deps);\n return bus;\n}\n\n/**\n * Subscribe to `topic` for the component's lifetime. The handler is read\n * through a ref on each delivery, so inline closures are safe without\n * unsubscribing/resubscribing on re-renders.\n *\n * When `bus` is null (not yet created) the subscription is queued until the\n * bus appears \u2014 the bus itself queues it until the transport is ready.\n */\nexport function useCrossTabSubscription<TConfig, TData>(\n bus: CrossTabDataBus<TConfig, TData> | null,\n topic: string,\n handler: (message: DataBusMessage<TData>) => void\n): void {\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n useEffect(() => {\n if (!bus) return;\n return bus.subscribe(topic, message => handlerRef.current(message));\n }, [bus, topic]);\n}\n\n/**\n * Mirror the bus connection status into React state. Reports the live value\n * via `onStatus` and reads the current value synchronously whenever `bus`\n * changes identity.\n */\nexport function useCrossTabStatus<TConfig, TData>(\n bus: CrossTabDataBus<TConfig, TData> | null\n): WorkerStatus {\n const [status, setStatus] = useState<WorkerStatus>('connecting');\n useEffect(() => {\n if (!bus) {\n setStatus('connecting');\n return;\n }\n setStatus(bus.getStatus());\n return bus.onStatus(setStatus);\n }, [bus]);\n return status;\n}\n"],
|
|
5
|
-
"mappings": ";AAgBA,SAAS,WAAW,QAAQ,gBAAgB;AAgBrC,SAAS,mBACd,QACA,OAAuB,CAAC,GACgB;AACxC,QAAM,CAAC,KAAK,MAAM,IAAI,SAAiD,IAAI;AAC3E,YAAU,MAAM;AACd,UAAM,WAAW,OAAO;AACxB,WAAO,QAAQ;AACf,SAAK,SAAS,MAAM,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACpC,WAAO,MAAM;AACX,
|
|
4
|
+
"sourcesContent": ["/**\n * React hooks adapter for cross-tab-worker-databus.\n *\n * A thin, transport-agnostic bridge between the imperative CrossTabDataBus\n * API and React component lifecycles. React is an optional peer dependency \u2014\n * this module is a separate entry point so consumers who don't use React\n * never load it.\n *\n * - `useCrossTabDataBus` owns the bus lifecycle: created on mount, stopped on\n * unmount. It is StrictMode-safe: the double-invoked effect exercises the\n * same stop/recreate path as BFCache suspend/resume.\n * - `useCrossTabSubscription` attaches a message handler with automatic\n * cleanup; the handler is read through a ref, so you can pass inline\n * closures without resubscribing on every render.\n * - `useCrossTabStatus` mirrors `bus.onStatus()` into React state.\n */\nimport { useEffect, useRef, useState } from 'react';\nimport type { DependencyList } from 'react';\nimport type { CrossTabDataBus } from './core/data-bus';\nimport type { DataBusMessage, WorkerStatus } from './core/types';\n\n/**\n * Create a CrossTabDataBus for the component's lifetime.\n *\n * @param create Factory invoked once per effect run. Return a fresh bus \u2014\n * do not share a bus instance between effects, or StrictMode's\n * mount \u2192 stop \u2192 mount cycle will stop the shared instance out from\n * under the second mount.\n * @param deps Re-create the bus when these change (default: create once).\n * @returns The active bus, or `null` before the first effect has run (SSR\n * and the initial render).\n */\nexport function useCrossTabDataBus<TConfig, TData>(\n create: () => CrossTabDataBus<TConfig, TData>,\n deps: DependencyList = []\n): CrossTabDataBus<TConfig, TData> | null {\n const [bus, setBus] = useState<CrossTabDataBus<TConfig, TData> | null>(null);\n const lifecycleGeneration = useRef(0);\n useEffect(() => {\n const generation = ++lifecycleGeneration.current;\n const instance = create();\n if (generation !== lifecycleGeneration.current) return;\n setBus(instance);\n void instance.ready().catch(() => {});\n return () => {\n if (generation === lifecycleGeneration.current) setBus(null);\n void instance.stop();\n };\n // The factory is intentionally not a dependency: callers pass an inline\n // closure and key recreation through `deps` instead.\n }, deps);\n return bus;\n}\n\n/**\n * Subscribe to `topic` for the component's lifetime. The handler is read\n * through a ref on each delivery, so inline closures are safe without\n * unsubscribing/resubscribing on re-renders.\n *\n * When `bus` is null (not yet created) the subscription is queued until the\n * bus appears \u2014 the bus itself queues it until the transport is ready.\n */\nexport function useCrossTabSubscription<TConfig, TData>(\n bus: CrossTabDataBus<TConfig, TData> | null,\n topic: string,\n handler: (message: DataBusMessage<TData>) => void\n): void {\n const handlerRef = useRef(handler);\n handlerRef.current = handler;\n useEffect(() => {\n if (!bus) return;\n return bus.subscribe(topic, message => handlerRef.current(message));\n }, [bus, topic]);\n}\n\n/**\n * Mirror the bus connection status into React state. Reports the live value\n * via `onStatus` and reads the current value synchronously whenever `bus`\n * changes identity.\n */\nexport function useCrossTabStatus<TConfig, TData>(\n bus: CrossTabDataBus<TConfig, TData> | null\n): WorkerStatus {\n const [status, setStatus] = useState<WorkerStatus>('connecting');\n useEffect(() => {\n if (!bus) {\n setStatus('connecting');\n return;\n }\n setStatus(bus.getStatus());\n return bus.onStatus(setStatus);\n }, [bus]);\n return status;\n}\n"],
|
|
5
|
+
"mappings": ";AAgBA,SAAS,WAAW,QAAQ,gBAAgB;AAgBrC,SAAS,mBACd,QACA,OAAuB,CAAC,GACgB;AACxC,QAAM,CAAC,KAAK,MAAM,IAAI,SAAiD,IAAI;AAC3E,QAAM,sBAAsB,OAAO,CAAC;AACpC,YAAU,MAAM;AACd,UAAM,aAAa,EAAE,oBAAoB;AACzC,UAAM,WAAW,OAAO;AACxB,QAAI,eAAe,oBAAoB,QAAS;AAChD,WAAO,QAAQ;AACf,SAAK,SAAS,MAAM,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AACpC,WAAO,MAAM;AACX,UAAI,eAAe,oBAAoB,QAAS,QAAO,IAAI;AAC3D,WAAK,SAAS,KAAK;AAAA,IACrB;AAAA,EAGF,GAAG,IAAI;AACP,SAAO;AACT;AAUO,SAAS,wBACd,KACA,OACA,SACM;AACN,QAAM,aAAa,OAAO,OAAO;AACjC,aAAW,UAAU;AACrB,YAAU,MAAM;AACd,QAAI,CAAC,IAAK;AACV,WAAO,IAAI,UAAU,OAAO,aAAW,WAAW,QAAQ,OAAO,CAAC;AAAA,EACpE,GAAG,CAAC,KAAK,KAAK,CAAC;AACjB;AAOO,SAAS,kBACd,KACc;AACd,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAuB,YAAY;AAC/D,YAAU,MAAM;AACd,QAAI,CAAC,KAAK;AACR,gBAAU,YAAY;AACtB;AAAA,IACF;AACA,cAAU,IAAI,UAAU,CAAC;AACzB,WAAO,IAAI,SAAS,SAAS;AAAA,EAC/B,GAAG,CAAC,GAAG,CAAC;AACR,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* ```
|
|
10
10
|
*/
|
|
11
11
|
export { CrossTabDataBus } from './core/data-bus';
|
|
12
|
-
export type { CrossTabDataBusOptions, DataBusDedupOptions, DataBusDedupStats, DataBusReplayOptions } from './core/data-bus';
|
|
12
|
+
export type { CrossTabDataBusOptions, DataBusDedupOptions, DataBusDedupStats, DataBusPersistenceRetryOptions, DataBusReplayOptions } from './core/data-bus';
|
|
13
13
|
export { createIndexedDbReplayPersistence } from './core/replay-persistence';
|
|
14
14
|
export type { DataBusReplayPersistence, IndexedDbReplayPersistenceOptions } from './core/replay-persistence';
|
|
15
15
|
export type { DataBusCoordinationTraceEvent, DataBusErrorTraceEvent, DataBusLifecycleTraceEvent, DataBusMetricsTraceEvent, DataBusReliabilityTraceEvent, DataBusStatusTraceEvent, DataBusSubscriptionTraceEvent, DataBusTraceEvent, DataBusTraceMode, DataBusTraceOptions } from './core/trace';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,8BAA8B,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5J,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC;AAC7E,YAAY,EAAE,wBAAwB,EAAE,iCAAiC,EAAE,MAAM,2BAA2B,CAAC;AAC7G,YAAY,EACV,6BAA6B,EAC7B,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,4BAA4B,EAC5B,uBAAuB,EACvB,6BAA6B,EAC7B,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AACtD,YAAY,EACV,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAChF,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,6BAA6B,EAC7B,sBAAsB,EACtB,aAAa,EACd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,EACL,0BAA0B,EAC1B,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,0BAA0B,EAC1B,0BAA0B,EAC1B,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,YAAY,EACZ,kBAAkB,EAClB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,WAAW,EACX,YAAY,EACb,MAAM,cAAc,CAAC"}
|
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-LPS4XOK4.js";
|
|
17
17
|
|
|
18
18
|
// src/core/replay-persistence.ts
|
|
19
19
|
function createIndexedDbReplayPersistence(options) {
|
|
@@ -26,74 +26,165 @@ function createIndexedDbReplayPersistence(options) {
|
|
|
26
26
|
throw new TypeError(`maxPerTopic must be a positive safe integer, got ${String(maxPerTopic)}.`);
|
|
27
27
|
}
|
|
28
28
|
let dbPromise = null;
|
|
29
|
+
const invalidate = (db) => {
|
|
30
|
+
if (dbPromise) {
|
|
31
|
+
void dbPromise.then((current) => {
|
|
32
|
+
if (current === db) {
|
|
33
|
+
current.close();
|
|
34
|
+
dbPromise = null;
|
|
35
|
+
}
|
|
36
|
+
}, () => void 0);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
let mutationQueue = Promise.resolve();
|
|
40
|
+
const serializeMutation = (mutation) => {
|
|
41
|
+
const next = mutationQueue.then(mutation, mutation);
|
|
42
|
+
mutationQueue = next.catch(() => void 0);
|
|
43
|
+
return next;
|
|
44
|
+
};
|
|
29
45
|
const open = () => {
|
|
30
46
|
if (dbPromise) return dbPromise;
|
|
31
|
-
|
|
47
|
+
const pending = new Promise((resolve, reject) => {
|
|
32
48
|
const request = indexedDb.open(dbName, 1);
|
|
33
49
|
request.onupgradeneeded = () => request.result.createObjectStore(storeName, { keyPath: "topic" });
|
|
34
|
-
request.onsuccess = () =>
|
|
50
|
+
request.onsuccess = () => {
|
|
51
|
+
const db = request.result;
|
|
52
|
+
db.onversionchange = () => {
|
|
53
|
+
db.close();
|
|
54
|
+
if (dbPromise) dbPromise = null;
|
|
55
|
+
};
|
|
56
|
+
resolve(db);
|
|
57
|
+
};
|
|
35
58
|
request.onerror = () => reject(request.error ?? new Error("Failed to open replay database."));
|
|
36
59
|
});
|
|
37
|
-
|
|
60
|
+
dbPromise = pending;
|
|
61
|
+
void pending.catch(() => {
|
|
62
|
+
if (dbPromise === pending) dbPromise = null;
|
|
63
|
+
});
|
|
64
|
+
return pending;
|
|
38
65
|
};
|
|
39
66
|
return {
|
|
40
67
|
async load() {
|
|
41
68
|
const db = await open();
|
|
42
69
|
return new Promise((resolve, reject) => {
|
|
43
|
-
|
|
70
|
+
let request;
|
|
71
|
+
try {
|
|
72
|
+
request = db.transaction(storeName, "readonly").objectStore(storeName).getAll();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
invalidate(db);
|
|
75
|
+
reject(error);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
44
78
|
request.onsuccess = () => resolve(request.result.flatMap((record) => record.messages));
|
|
45
|
-
request.onerror = () =>
|
|
79
|
+
request.onerror = () => {
|
|
80
|
+
invalidate(db);
|
|
81
|
+
reject(request.error ?? new Error("Failed to load replay history."));
|
|
82
|
+
};
|
|
46
83
|
});
|
|
47
84
|
},
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
85
|
+
append(message) {
|
|
86
|
+
return serializeMutation(async () => {
|
|
87
|
+
const db = await open();
|
|
88
|
+
await new Promise((resolve, reject) => {
|
|
89
|
+
let transaction;
|
|
90
|
+
try {
|
|
91
|
+
transaction = db.transaction(storeName, "readwrite");
|
|
92
|
+
} catch (error) {
|
|
93
|
+
invalidate(db);
|
|
94
|
+
reject(error);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const store = transaction.objectStore(storeName);
|
|
98
|
+
const request = store.get(message.topic);
|
|
99
|
+
request.onsuccess = () => {
|
|
100
|
+
const messages = (request.result?.messages ?? []).concat(message).slice(-maxPerTopic);
|
|
101
|
+
store.put({ topic: message.topic, messages });
|
|
102
|
+
};
|
|
103
|
+
request.onerror = () => {
|
|
104
|
+
invalidate(db);
|
|
105
|
+
reject(request.error ?? new Error("Failed to read replay history."));
|
|
106
|
+
};
|
|
107
|
+
transaction.oncomplete = () => resolve();
|
|
108
|
+
transaction.onerror = () => {
|
|
109
|
+
invalidate(db);
|
|
110
|
+
reject(transaction.error ?? new Error("Failed to persist replay history."));
|
|
111
|
+
};
|
|
112
|
+
});
|
|
61
113
|
});
|
|
62
114
|
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
115
|
+
clear() {
|
|
116
|
+
return serializeMutation(async () => {
|
|
117
|
+
const db = await open();
|
|
118
|
+
await new Promise((resolve, reject) => {
|
|
119
|
+
let transaction;
|
|
120
|
+
try {
|
|
121
|
+
transaction = db.transaction(storeName, "readwrite");
|
|
122
|
+
} catch (error) {
|
|
123
|
+
invalidate(db);
|
|
124
|
+
reject(error);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
transaction.objectStore(storeName).clear();
|
|
128
|
+
transaction.oncomplete = () => resolve();
|
|
129
|
+
transaction.onerror = () => {
|
|
130
|
+
invalidate(db);
|
|
131
|
+
reject(transaction.error ?? new Error("Failed to clear replay history."));
|
|
132
|
+
};
|
|
133
|
+
});
|
|
70
134
|
});
|
|
71
135
|
},
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
136
|
+
clearTopic(topic) {
|
|
137
|
+
return serializeMutation(async () => {
|
|
138
|
+
const db = await open();
|
|
139
|
+
await new Promise((resolve, reject) => {
|
|
140
|
+
let transaction;
|
|
141
|
+
try {
|
|
142
|
+
transaction = db.transaction(storeName, "readwrite");
|
|
143
|
+
} catch (error) {
|
|
144
|
+
invalidate(db);
|
|
145
|
+
reject(error);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
transaction.objectStore(storeName).delete(topic);
|
|
149
|
+
transaction.oncomplete = () => resolve();
|
|
150
|
+
transaction.onerror = () => {
|
|
151
|
+
invalidate(db);
|
|
152
|
+
reject(transaction.error ?? new Error("Failed to clear topic replay history."));
|
|
153
|
+
};
|
|
154
|
+
});
|
|
79
155
|
});
|
|
80
156
|
},
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
157
|
+
clearBefore(timestamp) {
|
|
158
|
+
return serializeMutation(async () => {
|
|
159
|
+
const db = await open();
|
|
160
|
+
await new Promise((resolve, reject) => {
|
|
161
|
+
let transaction;
|
|
162
|
+
try {
|
|
163
|
+
transaction = db.transaction(storeName, "readwrite");
|
|
164
|
+
} catch (error) {
|
|
165
|
+
invalidate(db);
|
|
166
|
+
reject(error);
|
|
167
|
+
return;
|
|
92
168
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
169
|
+
const store = transaction.objectStore(storeName);
|
|
170
|
+
const request = store.getAll();
|
|
171
|
+
request.onsuccess = () => {
|
|
172
|
+
for (const record of request.result) {
|
|
173
|
+
const messages = record.messages.filter((message) => message.timestamp === void 0 || message.timestamp >= timestamp);
|
|
174
|
+
if (messages.length === 0) store.delete(record.topic);
|
|
175
|
+
else if (messages.length !== record.messages.length) store.put({ topic: record.topic, messages });
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
request.onerror = () => {
|
|
179
|
+
invalidate(db);
|
|
180
|
+
reject(request.error ?? new Error("Failed to read replay history."));
|
|
181
|
+
};
|
|
182
|
+
transaction.oncomplete = () => resolve();
|
|
183
|
+
transaction.onerror = () => {
|
|
184
|
+
invalidate(db);
|
|
185
|
+
reject(transaction.error ?? new Error("Failed to prune replay history."));
|
|
186
|
+
};
|
|
187
|
+
});
|
|
97
188
|
});
|
|
98
189
|
}
|
|
99
190
|
};
|
|
@@ -131,7 +222,9 @@ var WebSocketTransport = class {
|
|
|
131
222
|
};
|
|
132
223
|
socket.onclose = () => handlers.onStatus("disconnected");
|
|
133
224
|
socket.onerror = () => handlers.onStatus("error");
|
|
134
|
-
socket.onmessage = (event) =>
|
|
225
|
+
socket.onmessage = (event) => {
|
|
226
|
+
void this.handleMessage(event.data);
|
|
227
|
+
};
|
|
135
228
|
this.socket = socket;
|
|
136
229
|
}
|
|
137
230
|
/** Idempotent: re-subscribing an active topic re-sends the frame but does
|
|
@@ -207,7 +300,15 @@ var WebSocketTransport = class {
|
|
|
207
300
|
/** Parse a server frame. Only objects carrying a string `topic` are
|
|
208
301
|
* publications; malformed JSON and unknown shapes are ignored so a chatty
|
|
209
302
|
* server cannot crash the message path. */
|
|
210
|
-
handleMessage(raw) {
|
|
303
|
+
async handleMessage(raw) {
|
|
304
|
+
if (typeof Blob !== "undefined" && raw instanceof Blob) {
|
|
305
|
+
try {
|
|
306
|
+
await this.handleMessage(await raw.arrayBuffer());
|
|
307
|
+
} catch (error) {
|
|
308
|
+
this.handlers?.onError(error);
|
|
309
|
+
}
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
211
312
|
let parsed;
|
|
212
313
|
if (raw instanceof ArrayBuffer) {
|
|
213
314
|
const bytes = new Uint8Array(raw);
|