cross-tab-worker-databus 0.20.87 → 0.20.89
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 +22 -0
- package/dist/centrifuge-session.d.ts +1 -0
- package/dist/centrifuge-session.d.ts.map +1 -1
- package/dist/centrifuge.d.ts.map +1 -1
- package/dist/centrifuge.js +55 -8
- package/dist/centrifuge.js.map +2 -2
- package/dist/centrifuge.shared.worker.js +38 -6
- package/dist/centrifuge.shared.worker.js.map +2 -2
- package/dist/centrifuge.worker.js +38 -6
- package/dist/centrifuge.worker.js.map +2 -2
- package/dist/{chunk-ZNHJ5OMY.js → chunk-77BQELW4.js} +69 -29
- package/dist/{chunk-ZNHJ5OMY.js.map → chunk-77BQELW4.js.map} +3 -3
- package/dist/cjs/centrifuge.cjs +122 -35
- package/dist/cjs/centrifuge.cjs.map +3 -3
- package/dist/cjs/index.cjs +76 -30
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/core/data-bus.d.ts +6 -0
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/replay-manager.d.ts.map +1 -1
- package/dist/core/trace.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +2 -2
- package/dist/websocket.d.ts.map +1 -1
- package/docs/api.md +4 -4
- package/docs/architecture.md +8 -6
- package/docs/capabilities.md +1 -1
- package/docs/configuration.md +1 -1
- package/docs/roadmap.md +18 -1
- package/docs/zh/api.md +4 -4
- package/docs/zh/architecture.md +8 -6
- package/docs/zh/capabilities.md +1 -1
- package/docs/zh/configuration.md +1 -1
- package/docs/zh/roadmap.md +18 -1
- package/package.json +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -1659,8 +1659,9 @@ var DataBusTraceReporter = class {
|
|
|
1659
1659
|
/** Start the periodic metrics flush interval. No-op when mode is 'events'
|
|
1660
1660
|
* (no metrics to emit), when disabled, or when already running. */
|
|
1661
1661
|
start() {
|
|
1662
|
-
if (!this.enabled
|
|
1662
|
+
if (!this.enabled) return;
|
|
1663
1663
|
this.stopped = false;
|
|
1664
|
+
if (this.intervalHandle || this.mode === TRACE_MODE.EVENTS) return;
|
|
1664
1665
|
this.intervalStartedAt = this.now();
|
|
1665
1666
|
this.intervalHandle = setInterval(() => this.flush(), this.metricsIntervalMs);
|
|
1666
1667
|
}
|
|
@@ -1673,6 +1674,7 @@ var DataBusTraceReporter = class {
|
|
|
1673
1674
|
}
|
|
1674
1675
|
stop() {
|
|
1675
1676
|
this.stopped = true;
|
|
1677
|
+
this.pendingEvents = [];
|
|
1676
1678
|
this.pause();
|
|
1677
1679
|
}
|
|
1678
1680
|
/** Synchronous sink state for diagnostics: whether delivery is async and how
|
|
@@ -1683,7 +1685,7 @@ var DataBusTraceReporter = class {
|
|
|
1683
1685
|
}
|
|
1684
1686
|
/** Record an instantaneous trace event (lifecycle, status, error, etc.). */
|
|
1685
1687
|
event(event) {
|
|
1686
|
-
if (!this.enabled || this.mode === TRACE_MODE.METRICS) return;
|
|
1688
|
+
if (!this.enabled || this.stopped || this.mode === TRACE_MODE.METRICS) return;
|
|
1687
1689
|
this.emit({ ...event, timestamp: this.now() });
|
|
1688
1690
|
}
|
|
1689
1691
|
/** Synchronous snapshot of the current metrics window without resetting it.
|
|
@@ -1766,7 +1768,7 @@ var DataBusTraceReporter = class {
|
|
|
1766
1768
|
* Extracted so the four record / flush methods share one guard expression
|
|
1767
1769
|
* instead of repeating `!this.enabled || this.mode === 'events'` at each. */
|
|
1768
1770
|
get metricsActive() {
|
|
1769
|
-
return this.enabled && this.mode !== TRACE_MODE.EVENTS;
|
|
1771
|
+
return this.enabled && !this.stopped && this.mode !== TRACE_MODE.EVENTS;
|
|
1770
1772
|
}
|
|
1771
1773
|
/** Emit the accumulated metrics snapshot if the interval is active. */
|
|
1772
1774
|
flush() {
|
|
@@ -2068,6 +2070,8 @@ var ReplayManager = class {
|
|
|
2068
2070
|
* or stopped bus does not keep hammering the store) and stop the sweep. */
|
|
2069
2071
|
suspend() {
|
|
2070
2072
|
this.retryGeneration += 1;
|
|
2073
|
+
this.pendingReplayPersistence = [];
|
|
2074
|
+
this.retentionCutoff = null;
|
|
2071
2075
|
this.stop();
|
|
2072
2076
|
}
|
|
2073
2077
|
/** Drop all in-memory buffers (used on full teardown). */
|
|
@@ -2166,19 +2170,20 @@ var ReplayManager = class {
|
|
|
2166
2170
|
this.retentionCutoff = cutoff;
|
|
2167
2171
|
}
|
|
2168
2172
|
if (this.retentionCleanup) return;
|
|
2173
|
+
const generation = this.retryGeneration;
|
|
2169
2174
|
this.retentionCleanup = (async () => {
|
|
2170
|
-
while (this.retentionCutoff !== null) {
|
|
2175
|
+
while (this.retentionCutoff !== null && generation === this.retryGeneration) {
|
|
2171
2176
|
const nextCutoff = this.retentionCutoff;
|
|
2172
2177
|
this.retentionCutoff = null;
|
|
2173
2178
|
try {
|
|
2174
2179
|
await this.persistence.clearBefore(nextCutoff);
|
|
2175
2180
|
} catch (error) {
|
|
2176
|
-
this.onPersistenceError(error);
|
|
2181
|
+
if (generation === this.retryGeneration) this.onPersistenceError(error);
|
|
2177
2182
|
}
|
|
2178
2183
|
}
|
|
2179
2184
|
})().finally(() => {
|
|
2180
2185
|
this.retentionCleanup = null;
|
|
2181
|
-
if (this.retentionCutoff !== null) {
|
|
2186
|
+
if (this.retentionCutoff !== null && generation === this.retryGeneration) {
|
|
2182
2187
|
this.scheduleRetentionCleanup(this.retentionCutoff);
|
|
2183
2188
|
}
|
|
2184
2189
|
});
|
|
@@ -2195,7 +2200,9 @@ var ReplayManager = class {
|
|
|
2195
2200
|
attempt += 1;
|
|
2196
2201
|
try {
|
|
2197
2202
|
if (generation !== this.retryGeneration) throw new PersistenceRetryCancelledError();
|
|
2198
|
-
|
|
2203
|
+
const result = await operation();
|
|
2204
|
+
if (generation !== this.retryGeneration) throw new PersistenceRetryCancelledError();
|
|
2205
|
+
return result;
|
|
2199
2206
|
} catch (error) {
|
|
2200
2207
|
if (error instanceof PersistenceRetryCancelledError || generation !== this.retryGeneration) {
|
|
2201
2208
|
throw new PersistenceRetryCancelledError();
|
|
@@ -2329,7 +2336,7 @@ var DedupManager = class {
|
|
|
2329
2336
|
};
|
|
2330
2337
|
|
|
2331
2338
|
// src/core/version.ts
|
|
2332
|
-
var SDK_VERSION = true ? "0.20.
|
|
2339
|
+
var SDK_VERSION = true ? "0.20.89" : "";
|
|
2333
2340
|
|
|
2334
2341
|
// src/core/data-bus.ts
|
|
2335
2342
|
var DEFAULT_REPLAY_MAX_PER_TOPIC = 100;
|
|
@@ -2523,10 +2530,7 @@ var CrossTabDataBus = class {
|
|
|
2523
2530
|
this.suspendTransport();
|
|
2524
2531
|
},
|
|
2525
2532
|
onResume: () => {
|
|
2526
|
-
this.
|
|
2527
|
-
this.trace.start();
|
|
2528
|
-
this.startDedupSweep();
|
|
2529
|
-
this.replayManager.start();
|
|
2533
|
+
this.resumeSuspendedResources();
|
|
2530
2534
|
this.resumeTransport();
|
|
2531
2535
|
},
|
|
2532
2536
|
onDiagnostic: (event) => {
|
|
@@ -2556,15 +2560,19 @@ var CrossTabDataBus = class {
|
|
|
2556
2560
|
if (!transportDown) return Promise.resolve();
|
|
2557
2561
|
this.activeConfig = config;
|
|
2558
2562
|
this.resetFailureState();
|
|
2559
|
-
|
|
2563
|
+
const resumingFromSuspend = this.suspended;
|
|
2564
|
+
if (resumingFromSuspend) this.resumeSuspendedResources();
|
|
2565
|
+
const opening2 = this.reopenTransport();
|
|
2566
|
+
if (resumingFromSuspend) this.cluster.start();
|
|
2567
|
+
return opening2;
|
|
2560
2568
|
}
|
|
2561
2569
|
this.started = true;
|
|
2562
2570
|
this.stopping = false;
|
|
2563
2571
|
this.suspended = false;
|
|
2564
2572
|
this.activeConfig = config;
|
|
2565
2573
|
this.resetFailureState();
|
|
2566
|
-
this.trace.event({ type: TRACE_EVENT_TYPE.LIFECYCLE, action: TRACE_LIFECYCLE_ACTION.START });
|
|
2567
2574
|
this.trace.start();
|
|
2575
|
+
this.trace.event({ type: TRACE_EVENT_TYPE.LIFECYCLE, action: TRACE_LIFECYCLE_ACTION.START });
|
|
2568
2576
|
this.startDedupSweep();
|
|
2569
2577
|
this.replayManager.start();
|
|
2570
2578
|
this.updateStatus(WORKER_STATUS.CONNECTING);
|
|
@@ -2679,6 +2687,7 @@ var CrossTabDataBus = class {
|
|
|
2679
2687
|
this.transportReady = false;
|
|
2680
2688
|
const chainedPendingStop = this.pendingStop;
|
|
2681
2689
|
const isCurrentLifecycle = () => lifecycleEpoch === this.lifecycleEpoch;
|
|
2690
|
+
let startupInProgress = true;
|
|
2682
2691
|
return before.catch(() => void 0).then(() => {
|
|
2683
2692
|
if (!isCurrentLifecycle() || this.stopping || this.suspended) return;
|
|
2684
2693
|
if (this.pendingStop === chainedPendingStop) this.pendingStop = null;
|
|
@@ -2689,13 +2698,16 @@ var CrossTabDataBus = class {
|
|
|
2689
2698
|
if (isCurrentLifecycle()) this.handleTransportMessage(message);
|
|
2690
2699
|
},
|
|
2691
2700
|
onStatus: (status) => {
|
|
2692
|
-
if (isCurrentLifecycle())
|
|
2701
|
+
if (isCurrentLifecycle()) {
|
|
2702
|
+
this.updateStatus(status, status !== WORKER_STATUS.ERROR || !startupInProgress);
|
|
2703
|
+
}
|
|
2693
2704
|
},
|
|
2694
2705
|
onError: (error) => {
|
|
2695
2706
|
if (isCurrentLifecycle()) this.reportError(error);
|
|
2696
2707
|
}
|
|
2697
2708
|
})
|
|
2698
2709
|
).then(() => {
|
|
2710
|
+
startupInProgress = false;
|
|
2699
2711
|
if (!isCurrentLifecycle()) return;
|
|
2700
2712
|
if (this.status === WORKER_STATUS.ERROR) {
|
|
2701
2713
|
throw new Error("Transport failed during startup.");
|
|
@@ -2709,18 +2721,21 @@ var CrossTabDataBus = class {
|
|
|
2709
2721
|
});
|
|
2710
2722
|
}).catch((error) => {
|
|
2711
2723
|
if (!isCurrentLifecycle()) throw error;
|
|
2724
|
+
startupInProgress = false;
|
|
2712
2725
|
if (stopClusterOnFailure) this.started = false;
|
|
2713
2726
|
if (!this.pendingStop) {
|
|
2714
2727
|
this.pendingStop = this.createStopPromise();
|
|
2715
2728
|
}
|
|
2716
2729
|
this.transportReady = false;
|
|
2717
|
-
this.updateStatus(WORKER_STATUS.ERROR);
|
|
2718
|
-
this.reportError(error);
|
|
2719
2730
|
if (stopClusterOnFailure) {
|
|
2720
2731
|
this.stopping = true;
|
|
2721
2732
|
this.cluster.stop();
|
|
2722
2733
|
this.stopping = false;
|
|
2723
2734
|
}
|
|
2735
|
+
this.recordError(error);
|
|
2736
|
+
this.startPromise = null;
|
|
2737
|
+
this.updateStatus(WORKER_STATUS.ERROR);
|
|
2738
|
+
this.notifyError(error);
|
|
2724
2739
|
throw error;
|
|
2725
2740
|
});
|
|
2726
2741
|
}
|
|
@@ -2917,7 +2932,7 @@ var CrossTabDataBus = class {
|
|
|
2917
2932
|
getHealthSummary() {
|
|
2918
2933
|
const transport = this.transport;
|
|
2919
2934
|
const transportDown = this.status !== WORKER_STATUS.CONNECTED;
|
|
2920
|
-
const state = !this.started ? HEALTH_STATE.STOPPED : this.suspended ? HEALTH_STATE.SUSPENDED : transportDown ? this.recoveryExhausted ? HEALTH_STATE.DEGRADED : this.status === WORKER_STATUS.CONNECTING && this.recoveryAttempt === 0 ? HEALTH_STATE.STARTING : HEALTH_STATE.RECOVERING : HEALTH_STATE.HEALTHY;
|
|
2935
|
+
const state = !this.started || this.stopping ? HEALTH_STATE.STOPPED : this.suspended ? HEALTH_STATE.SUSPENDED : transportDown ? this.recoveryExhausted ? HEALTH_STATE.DEGRADED : this.status === WORKER_STATUS.CONNECTING && this.recoveryAttempt === 0 ? HEALTH_STATE.STARTING : HEALTH_STATE.RECOVERING : HEALTH_STATE.HEALTHY;
|
|
2921
2936
|
return {
|
|
2922
2937
|
healthy: state === HEALTH_STATE.HEALTHY,
|
|
2923
2938
|
state,
|
|
@@ -2988,7 +3003,7 @@ var CrossTabDataBus = class {
|
|
|
2988
3003
|
this.canceledQueuedStartToken = this.queuedStartToken;
|
|
2989
3004
|
this.queuedStart = null;
|
|
2990
3005
|
}
|
|
2991
|
-
if (this.stopPromise) return this.stopPromise;
|
|
3006
|
+
if (this.stopPromise && this.stopping) return this.stopPromise;
|
|
2992
3007
|
if (!this.started && !this.startPromise && !this.pendingStop && !this.transportReady) {
|
|
2993
3008
|
return Promise.resolve();
|
|
2994
3009
|
}
|
|
@@ -3084,7 +3099,7 @@ var CrossTabDataBus = class {
|
|
|
3084
3099
|
* Propagate a status change to the cluster, trace, and all registered
|
|
3085
3100
|
* status handlers. On reconnect, re-subscribe any topics assigned to us.
|
|
3086
3101
|
*/
|
|
3087
|
-
updateStatus(status) {
|
|
3102
|
+
updateStatus(status, notifyHandlers = true) {
|
|
3088
3103
|
const previousStatus = this.status;
|
|
3089
3104
|
this.status = status;
|
|
3090
3105
|
if (status === WORKER_STATUS.CONNECTED) this.transportHasConnected = true;
|
|
@@ -3136,9 +3151,9 @@ var CrossTabDataBus = class {
|
|
|
3136
3151
|
} else if (status === WORKER_STATUS.ERROR) {
|
|
3137
3152
|
this.releaseRecoveryGate();
|
|
3138
3153
|
}
|
|
3139
|
-
this.invokeHandlers(this.statusHandlers, (handler) => handler(status));
|
|
3154
|
+
if (notifyHandlers) this.invokeHandlers(this.statusHandlers, (handler) => handler(status));
|
|
3140
3155
|
}
|
|
3141
|
-
|
|
3156
|
+
recordError(error, source = FAILURE_SOURCE.TRANSPORT) {
|
|
3142
3157
|
const at = this.now();
|
|
3143
3158
|
if (source === FAILURE_SOURCE.TRANSPORT) {
|
|
3144
3159
|
this.lastError = error;
|
|
@@ -3158,8 +3173,14 @@ var CrossTabDataBus = class {
|
|
|
3158
3173
|
type: TRACE_EVENT_TYPE.ERROR,
|
|
3159
3174
|
source: source === FAILURE_SOURCE.TRANSPORT ? TRACE_ERROR_SOURCE.TRANSPORT : TRACE_ERROR_SOURCE.OPERATION
|
|
3160
3175
|
});
|
|
3176
|
+
}
|
|
3177
|
+
notifyError(error) {
|
|
3161
3178
|
this.invokeHandlers(this.errorHandlers, (handler) => handler(error), INVOKE_LABEL.ERROR_HANDLER);
|
|
3162
3179
|
}
|
|
3180
|
+
reportError(error, source = FAILURE_SOURCE.TRANSPORT) {
|
|
3181
|
+
this.recordError(error, source);
|
|
3182
|
+
this.notifyError(error);
|
|
3183
|
+
}
|
|
3163
3184
|
/** Report a persistence failure to the trace and the unified failure ledger,
|
|
3164
3185
|
* unless it is a {@link PersistenceRetryCancelledError} cancellation from a
|
|
3165
3186
|
* lifecycle transition (teardown should stay quiet). */
|
|
@@ -3222,6 +3243,15 @@ var CrossTabDataBus = class {
|
|
|
3222
3243
|
}
|
|
3223
3244
|
}
|
|
3224
3245
|
}
|
|
3246
|
+
/** Resume the resources paused by a pagehide suspension. Both the native
|
|
3247
|
+
* pageshow path and explicit start() must run this so an explicit resume
|
|
3248
|
+
* cannot leave trace metrics and periodic cleanup timers permanently off. */
|
|
3249
|
+
resumeSuspendedResources() {
|
|
3250
|
+
this.trace.start();
|
|
3251
|
+
this.trace.event({ type: TRACE_EVENT_TYPE.LIFECYCLE, action: TRACE_LIFECYCLE_ACTION.RESUME });
|
|
3252
|
+
this.startDedupSweep();
|
|
3253
|
+
this.replayManager.start();
|
|
3254
|
+
}
|
|
3225
3255
|
/**
|
|
3226
3256
|
* Suspend the transport when the tab goes hidden. Stops the transport and
|
|
3227
3257
|
* clears subscription state so it will be re-established on resume.
|
|
@@ -3234,8 +3264,11 @@ var CrossTabDataBus = class {
|
|
|
3234
3264
|
this.transportReady = false;
|
|
3235
3265
|
this.transportSubscribedTopics.clear();
|
|
3236
3266
|
this.updateStatus(WORKER_STATUS.DISCONNECTED);
|
|
3237
|
-
if (this.pendingStop)
|
|
3238
|
-
|
|
3267
|
+
if (this.pendingStop && (this.startPromise === null || this.startPromise === this.pendingStop)) {
|
|
3268
|
+
this.startPromise = this.pendingStop;
|
|
3269
|
+
return;
|
|
3270
|
+
}
|
|
3271
|
+
const pending = this.startPromise ?? this.pendingStop ?? Promise.resolve();
|
|
3239
3272
|
const stopping = pending.catch(() => void 0).then(() => this.transport.stop()).catch((error) => this.reportError(error));
|
|
3240
3273
|
this.startPromise = stopping;
|
|
3241
3274
|
this.pendingStop = stopping;
|
|
@@ -3330,10 +3363,17 @@ var CrossTabDataBus = class {
|
|
|
3330
3363
|
ready = this.reopenTransport();
|
|
3331
3364
|
}
|
|
3332
3365
|
if (!ready || this.stopping) return;
|
|
3333
|
-
void ready.then(
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3366
|
+
void ready.then(
|
|
3367
|
+
() => {
|
|
3368
|
+
if (!this.started || this.stopping || this.suspended) return;
|
|
3369
|
+
return operation();
|
|
3370
|
+
},
|
|
3371
|
+
// The opening promise reports its own lifecycle failure through
|
|
3372
|
+
// openTransport(). Swallowing it here prevents a stale startup
|
|
3373
|
+
// rejection from being recorded again after an onStatus/onError
|
|
3374
|
+
// callback has already started and reset the ledger for a retry.
|
|
3375
|
+
() => void 0
|
|
3376
|
+
).catch((error) => this.reportError(error));
|
|
3337
3377
|
}
|
|
3338
3378
|
/**
|
|
3339
3379
|
* Publications started after teardown begins cannot reach any transport.
|
|
@@ -3903,10 +3943,16 @@ var WebSocketTransport = class {
|
|
|
3903
3943
|
* server cannot crash the message path. */
|
|
3904
3944
|
async handleMessage(raw) {
|
|
3905
3945
|
if (typeof Blob !== "undefined" && raw instanceof Blob) {
|
|
3946
|
+
const socket = this.socket;
|
|
3947
|
+
const handlers = this.handlers;
|
|
3906
3948
|
try {
|
|
3907
|
-
|
|
3949
|
+
const buffer = await raw.arrayBuffer();
|
|
3950
|
+
if (this.socket !== socket || this.handlers !== handlers || !this.socketActive) return;
|
|
3951
|
+
await this.handleMessage(buffer);
|
|
3908
3952
|
} catch (error) {
|
|
3909
|
-
this.handlers
|
|
3953
|
+
if (this.socket === socket && this.handlers === handlers && this.socketActive) {
|
|
3954
|
+
this.handlers?.onError(error);
|
|
3955
|
+
}
|
|
3910
3956
|
}
|
|
3911
3957
|
return;
|
|
3912
3958
|
}
|