cross-tab-worker-databus 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +1 -0
  3. package/README.zh.md +1 -0
  4. package/dist/centrifuge-protocol.d.ts +4 -0
  5. package/dist/centrifuge-protocol.d.ts.map +1 -1
  6. package/dist/centrifuge-session.d.ts.map +1 -1
  7. package/dist/centrifuge.js +29 -11
  8. package/dist/centrifuge.js.map +2 -2
  9. package/dist/centrifuge.shared.worker.js +37 -6
  10. package/dist/centrifuge.shared.worker.js.map +3 -3
  11. package/dist/centrifuge.worker.js +37 -6
  12. package/dist/centrifuge.worker.js.map +3 -3
  13. package/dist/{chunk-WWUY2FV2.js → chunk-ZOPNTR4E.js} +110 -25
  14. package/dist/chunk-ZOPNTR4E.js.map +7 -0
  15. package/dist/cjs/centrifuge.cjs +137 -34
  16. package/dist/cjs/centrifuge.cjs.map +4 -4
  17. package/dist/cjs/index.cjs +145 -37
  18. package/dist/cjs/index.cjs.map +3 -3
  19. package/dist/core/cluster.d.ts +3 -2
  20. package/dist/core/cluster.d.ts.map +1 -1
  21. package/dist/core/data-bus.d.ts +16 -0
  22. package/dist/core/data-bus.d.ts.map +1 -1
  23. package/dist/core/publication.d.ts +10 -0
  24. package/dist/core/publication.d.ts.map +1 -0
  25. package/dist/core/replay-persistence.d.ts +2 -0
  26. package/dist/core/replay-persistence.d.ts.map +1 -1
  27. package/dist/core/types.d.ts +19 -7
  28. package/dist/core/types.d.ts.map +1 -1
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +39 -14
  32. package/dist/index.js.map +2 -2
  33. package/dist/websocket.d.ts.map +1 -1
  34. package/docs/api.md +25 -4
  35. package/docs/architecture.md +3 -1
  36. package/docs/transports.md +9 -5
  37. package/docs/zh/api.md +25 -4
  38. package/docs/zh/architecture.md +3 -1
  39. package/docs/zh/transports.md +8 -4
  40. package/package.json +1 -1
  41. package/dist/chunk-WWUY2FV2.js.map +0 -7
@@ -1,9 +1,9 @@
1
1
  import type { ClusterEnvironment } from './environment';
2
- import type { WorkerControlAction, WorkerRecord, WorkerRoute, WorkerStatus } from './types';
2
+ import type { DataBusPublicationMetadata, WorkerControlAction, WorkerRecord, WorkerRoute, WorkerStatus } from './types';
3
3
  /** Callbacks the cluster invokes to drive the transport and lifecycle. */
4
4
  export interface WorkerClusterHandlers {
5
5
  /** A SUBSCRIBE/UNSUBSCRIBE/PUBLISH control action was received for this worker. */
6
- onControl: (action: WorkerControlAction, topic: string, data?: unknown, messageId?: string) => void;
6
+ onControl: (action: WorkerControlAction, topic: string, data?: unknown, messageId?: string, timestamp?: number) => void;
7
7
  /** A fan-out publication event was received from another Worker. */
8
8
  onEvent: (eventType: string, payload: unknown, sourceWorkerId: string) => void;
9
9
  /** The cluster suspended (tab hidden / pagehide). */
@@ -137,6 +137,7 @@ export declare class WorkerClusterRuntime {
137
137
  * silently dropping the publication.
138
138
  */
139
139
  publish(topic: string, data: unknown, messageId?: string): boolean;
140
+ publish(topic: string, data: unknown, metadata?: DataBusPublicationMetadata): boolean;
140
141
  /** True when `route` exists and its owner worker is among `workers`.
141
142
  * Shared by subscribe (skip re-assignment) and publish (route to owner).
142
143
  * Intentionally returns a plain boolean (not a type guard) so the caller
@@ -1 +1 @@
1
- {"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../../src/core/cluster.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cluster.d.ts","sourceRoot":"","sources":["../../src/core/cluster.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,12 @@ export interface DataBusDedupOptions {
22
22
  maxEntries?: number;
23
23
  ttlMs?: number;
24
24
  }
25
+ export interface DataBusDedupStats {
26
+ enabled: boolean;
27
+ tracked: number;
28
+ suppressed: number;
29
+ accepted: number;
30
+ }
25
31
  export interface CrossTabDataBusOptions<TConfig, TData> extends Omit<WorkerClusterOptions, 'handlers'> {
26
32
  transport: DataBusTransport<TConfig, TData>;
27
33
  initialConfig?: TConfig;
@@ -58,6 +64,8 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
58
64
  private readonly dedupTtlMs;
59
65
  private readonly dedupEnabled;
60
66
  private readonly seenMessageIds;
67
+ private dedupSuppressed;
68
+ private dedupAccepted;
61
69
  private activeConfig;
62
70
  private status;
63
71
  private started;
@@ -106,6 +114,14 @@ export declare class CrossTabDataBus<TConfig = unknown, TData = unknown> {
106
114
  unsubscribe(topic: string, handler?: DataBusMessageHandler<TData>): void;
107
115
  /** Clear all in-memory replay buffers and, when supported, durable history. */
108
116
  clearReplay(): Promise<void>;
117
+ /** Clear replay history for one exact topic, including durable storage. */
118
+ clearReplayTopic(topic: string): Promise<void>;
119
+ /** Remove replay entries older than an epoch-millisecond cutoff. */
120
+ clearReplayBefore(timestamp: number): Promise<void>;
121
+ /** Return bounded deduplication counters for diagnostics and health checks. */
122
+ getDedupStats(): DataBusDedupStats;
123
+ /** Drop all remembered IDs and reset dedup counters. */
124
+ resetDedup(): void;
109
125
  /** Publish a message to `topic`. The owning Worker delivers it to the transport. */
110
126
  publish(topic: string, data: unknown, options?: DataBusPublishOptions): void;
111
127
  /** Register a handler that fires on every transport status change. Immediately invoked with the current status. */
@@ -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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"}
@@ -0,0 +1,10 @@
1
+ import type { DataBusPublication } from './types';
2
+ /**
3
+ * Normalize legacy flat publications, metadata payload envelopes, and the
4
+ * canonical `{ op: 'publication', publication: ... }` shape.
5
+ *
6
+ * `fallbackTopic` is used by transports such as Centrifuge where the channel
7
+ * is supplied out-of-band by the client library rather than inside the data.
8
+ */
9
+ export declare function parseDataBusPublication<TData = unknown>(value: unknown, fallbackTopic?: string): DataBusPublication<TData> | null;
10
+ //# sourceMappingURL=publication.d.ts.map
@@ -0,0 +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,CA0BlC"}
@@ -7,6 +7,8 @@ export interface DataBusReplayPersistence<TData = unknown> {
7
7
  clear?(): Promise<void>;
8
8
  /** Remove persisted replay history for one exact topic. */
9
9
  clearTopic?(topic: string): Promise<void>;
10
+ /** Remove persisted messages older than the given epoch-millisecond cutoff. */
11
+ clearBefore?(timestamp: number): Promise<void>;
10
12
  }
11
13
  export interface IndexedDbReplayPersistenceOptions {
12
14
  dbName?: string;
@@ -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;CAC3C;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+DjC"}
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,CAiFjC"}
@@ -19,10 +19,24 @@ export type WorkerStatus = 'connecting' | 'connected' | 'disconnected' | 'error'
19
19
  /** Control-plane actions routed between Workers via BroadcastChannel.
20
20
  * These are the three operations a subscriber asks the owning worker to perform. */
21
21
  export type WorkerControlAction = 'SUBSCRIBE' | 'UNSUBSCRIBE' | 'PUBLISH';
22
- /** Optional metadata attached to an outbound publication. */
23
- export interface DataBusPublishOptions {
22
+ /** Transport-neutral metadata attached to a publication. */
23
+ export interface DataBusPublicationMetadata {
24
24
  /** Stable caller/server identifier propagated through the cluster and wire protocol. */
25
25
  messageId?: string;
26
+ /** Producer-assigned Unix timestamp in milliseconds, used by retention policies. */
27
+ timestamp?: number;
28
+ }
29
+ /** Optional metadata attached to an outbound publication. */
30
+ export type DataBusPublishOptions = DataBusPublicationMetadata;
31
+ /** Canonical transport-neutral publication shape. */
32
+ export interface DataBusPublication<TData = unknown> extends DataBusPublicationMetadata {
33
+ topic: string;
34
+ data: TData;
35
+ }
36
+ /** Forward-compatible JSON envelope accepted from WebSocket-style servers. */
37
+ export interface DataBusPublicationEnvelope<TData = unknown> {
38
+ op: 'publication';
39
+ publication: DataBusPublication<TData>;
26
40
  }
27
41
  /** Whether the tab is currently visible to the user. Only influences placement
28
42
  * of NEW topic routes; existing routes are sticky and never migrated on hide. */
@@ -101,6 +115,8 @@ export type WorkerClusterMessage<TEvent = unknown> =
101
115
  data?: unknown;
102
116
  /** Optional stable identifier for the publication. */
103
117
  messageId?: string;
118
+ /** Optional producer timestamp propagated with PUBLISH actions. */
119
+ timestamp?: number;
104
120
  }
105
121
  /** The owning worker fans out a publication to every tab. `eventType`
106
122
  * distinguishes databus publications from future event types. */
@@ -128,11 +144,7 @@ export type WorkerClusterMessage<TEvent = unknown> =
128
144
  };
129
145
  /** A publication delivered to a topic handler: the topic name and the
130
146
  * structured-clone-safe payload. */
131
- export interface DataBusMessage<TData = unknown> {
132
- topic: string;
133
- data: TData;
134
- /** Optional caller/server supplied stable identifier used by opt-in dedup. */
135
- messageId?: string;
147
+ export interface DataBusMessage<TData = unknown> extends DataBusPublication<TData> {
136
148
  /** True when this delivery is a historical replay (see the `replay`
137
149
  * subscription option) rather than a live publication. */
138
150
  replayed?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
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, DataBusReplayOptions } from './core/data-bus';
12
+ export type { CrossTabDataBusOptions, DataBusDedupOptions, DataBusDedupStats, 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';
@@ -23,5 +23,5 @@ export type { CreateWebSocketDataBusOptions, WebSocketDataBusConfig, WebSocketLi
23
23
  export { selectWorkerBackend } from './worker-mode';
24
24
  export type { WorkerBackend, WorkerMode } from './worker-mode';
25
25
  export { DEFAULT_MAX_ACTIVE_WORKERS, hasActiveOwner, isWildcardTopic, selectActiveWorkers, selectLeastLoadedWorker, selectRebalanceTarget, topicMatchesPattern } from './core/routing';
26
- export type { DataBusErrorHandler, DataBusMessage, DataBusPublishOptions, DataBusMessageHandler, DataBusStatusHandler, DataBusTransport, DataBusTransportHandlers, MaybePromise, TabVisibilityState, TopicSubscriberRecord, WorkerClusterMessage, WorkerControlAction, WorkerRecord, WorkerRole, WorkerRoute, WorkerStatus } from './core/types';
26
+ export type { DataBusErrorHandler, DataBusMessage, DataBusPublication, DataBusPublicationEnvelope, DataBusPublicationMetadata, DataBusPublishOptions, DataBusMessageHandler, DataBusStatusHandler, DataBusTransport, DataBusTransportHandlers, MaybePromise, TabVisibilityState, TopicSubscriberRecord, WorkerClusterMessage, WorkerControlAction, WorkerRecord, WorkerRole, WorkerRoute, WorkerStatus } from './core/types';
27
27
  //# sourceMappingURL=index.d.ts.map
@@ -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,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACzG,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,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"}
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;AAC5H,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
@@ -7,12 +7,13 @@ import {
7
7
  getOrCreateTabId,
8
8
  hasActiveOwner,
9
9
  isWildcardTopic,
10
+ parseDataBusPublication,
10
11
  selectActiveWorkers,
11
12
  selectLeastLoadedWorker,
12
13
  selectRebalanceTarget,
13
14
  selectWorkerBackend,
14
15
  topicMatchesPattern
15
- } from "./chunk-WWUY2FV2.js";
16
+ } from "./chunk-ZOPNTR4E.js";
16
17
 
17
18
  // src/core/replay-persistence.ts
18
19
  function createIndexedDbReplayPersistence(options) {
@@ -76,6 +77,24 @@ function createIndexedDbReplayPersistence(options) {
76
77
  transaction.oncomplete = () => resolve();
77
78
  transaction.onerror = () => reject(transaction.error ?? new Error("Failed to clear topic replay history."));
78
79
  });
80
+ },
81
+ async clearBefore(timestamp) {
82
+ const db = await open();
83
+ await new Promise((resolve, reject) => {
84
+ const transaction = db.transaction(storeName, "readwrite");
85
+ const store = transaction.objectStore(storeName);
86
+ const request = store.getAll();
87
+ request.onsuccess = () => {
88
+ for (const record of request.result) {
89
+ const messages = record.messages.filter((message) => (message.timestamp ?? 0) >= timestamp);
90
+ if (messages.length === 0) store.delete(record.topic);
91
+ else if (messages.length !== record.messages.length) store.put({ topic: record.topic, messages });
92
+ }
93
+ };
94
+ request.onerror = () => reject(request.error ?? new Error("Failed to read replay history."));
95
+ transaction.oncomplete = () => resolve();
96
+ transaction.onerror = () => reject(transaction.error ?? new Error("Failed to prune replay history."));
97
+ });
79
98
  }
80
99
  };
81
100
  }
@@ -129,10 +148,16 @@ var WebSocketTransport = class {
129
148
  /** Publish `data` to `topic` as a JSON frame. Requires an open socket. */
130
149
  publish(topic, data, options) {
131
150
  if (data instanceof ArrayBuffer) {
132
- this.sendBinaryFrame(topic, data, options?.messageId);
151
+ this.sendBinaryFrame(topic, data, options?.messageId, options?.timestamp);
133
152
  return;
134
153
  }
135
- this.sendFrame({ op: "publish", topic, data, ...options?.messageId ? { messageId: options.messageId } : {} });
154
+ this.sendFrame({
155
+ op: "publish",
156
+ topic,
157
+ data,
158
+ ...options?.messageId === void 0 ? {} : { messageId: options.messageId },
159
+ ...options?.timestamp === void 0 ? {} : { timestamp: options.timestamp }
160
+ });
136
161
  }
137
162
  /** Close the socket and drop all state. Safe to call multiple times. */
138
163
  stop() {
@@ -152,9 +177,15 @@ var WebSocketTransport = class {
152
177
  }
153
178
  this.socket.send(JSON.stringify(payload));
154
179
  }
155
- sendBinaryFrame(topic, data, messageId) {
156
- if (messageId) {
157
- this.sendFrame({ op: "publish", topic, data: Array.from(new Uint8Array(data)), messageId });
180
+ sendBinaryFrame(topic, data, messageId, timestamp) {
181
+ if (messageId !== void 0 || timestamp !== void 0) {
182
+ this.sendFrame({
183
+ op: "publish",
184
+ topic,
185
+ data: Array.from(new Uint8Array(data)),
186
+ ...messageId === void 0 ? {} : { messageId },
187
+ ...timestamp === void 0 ? {} : { timestamp }
188
+ });
158
189
  return;
159
190
  }
160
191
  if (this.socket?.readyState !== WS_OPEN) {
@@ -196,14 +227,8 @@ var WebSocketTransport = class {
196
227
  return;
197
228
  }
198
229
  if (!parsed || typeof parsed !== "object") return;
199
- const frame = parsed;
200
- if (typeof frame.topic !== "string") return;
201
- const message = {
202
- topic: frame.topic,
203
- data: frame.data,
204
- ...typeof frame.messageId === "string" ? { messageId: frame.messageId } : {}
205
- };
206
- this.handlers?.onMessage(message);
230
+ const publication = parseDataBusPublication(parsed);
231
+ if (publication) this.handlers?.onMessage(publication);
207
232
  }
208
233
  };
209
234
  function defaultWebSocketFactory(url, protocols) {
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}\n\nexport interface IndexedDbReplayPersistenceOptions {\n dbName?: string;\n maxPerTopic: 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 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 open = (): Promise<IDBDatabase> => {\n if (dbPromise) return dbPromise;\n dbPromise = new Promise((resolve, reject) => {\n const request = indexedDb.open(dbName, 1);\n request.onupgradeneeded = () => request.result.createObjectStore(storeName, { keyPath: 'topic' });\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new Error('Failed to open replay database.'));\n });\n return dbPromise;\n };\n return {\n async load() {\n const db = await open();\n return new Promise((resolve, reject) => {\n const request = db.transaction(storeName, 'readonly').objectStore(storeName).getAll();\n request.onsuccess = () => resolve(request.result.flatMap(record => record.messages as DataBusMessage<TData>[]));\n request.onerror = () => reject(request.error ?? new Error('Failed to load replay history.'));\n });\n },\n async append(message) {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n const transaction = db.transaction(storeName, 'readwrite');\n const store = transaction.objectStore(storeName);\n const request = store.get(message.topic);\n request.onsuccess = () => {\n const messages = ((request.result?.messages ?? []) as DataBusMessage<TData>[]).concat(message).slice(-maxPerTopic);\n store.put({ topic: message.topic, messages });\n };\n request.onerror = () => reject(request.error ?? new Error('Failed to read replay history.'));\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error ?? new Error('Failed to persist replay history.'));\n });\n },\n async clear() {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n const transaction = db.transaction(storeName, 'readwrite');\n transaction.objectStore(storeName).clear();\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error ?? new Error('Failed to clear replay history.'));\n });\n },\n async clearTopic(topic) {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n const transaction = db.transaction(storeName, 'readwrite');\n transaction.objectStore(storeName).delete(topic);\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error ?? new Error('Failed to clear topic replay history.'));\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 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 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 // 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 = () => handlers.onStatus('disconnected');\n socket.onerror = () => handlers.onStatus('error');\n socket.onmessage = event => this.handleMessage(event.data);\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);\n return;\n }\n this.sendFrame({ op: 'publish', topic, data, ...(options?.messageId ? { messageId: options.messageId } : {}) });\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 }): 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): void {\n if (messageId) {\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({ op: 'publish', topic, data: Array.from(new Uint8Array(data)), messageId });\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 handleMessage(raw: unknown): void {\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 frame = parsed as Record<string, unknown>;\n if (typeof frame.topic !== 'string') return;\n const message: DataBusMessage<TData> = {\n topic: frame.topic,\n data: frame.data as TData,\n ...(typeof frame.messageId === 'string' ? { messageId: frame.messageId } : {})\n };\n this.handlers?.onMessage(message);\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": "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",
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}\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 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 open = (): Promise<IDBDatabase> => {\n if (dbPromise) return dbPromise;\n dbPromise = new Promise((resolve, reject) => {\n const request = indexedDb.open(dbName, 1);\n request.onupgradeneeded = () => request.result.createObjectStore(storeName, { keyPath: 'topic' });\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new Error('Failed to open replay database.'));\n });\n return dbPromise;\n };\n return {\n async load() {\n const db = await open();\n return new Promise((resolve, reject) => {\n const request = db.transaction(storeName, 'readonly').objectStore(storeName).getAll();\n request.onsuccess = () => resolve(request.result.flatMap(record => record.messages as DataBusMessage<TData>[]));\n request.onerror = () => reject(request.error ?? new Error('Failed to load replay history.'));\n });\n },\n async append(message) {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n const transaction = db.transaction(storeName, 'readwrite');\n const store = transaction.objectStore(storeName);\n const request = store.get(message.topic);\n request.onsuccess = () => {\n const messages = ((request.result?.messages ?? []) as DataBusMessage<TData>[]).concat(message).slice(-maxPerTopic);\n store.put({ topic: message.topic, messages });\n };\n request.onerror = () => reject(request.error ?? new Error('Failed to read replay history.'));\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error ?? new Error('Failed to persist replay history.'));\n });\n },\n async clear() {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n const transaction = db.transaction(storeName, 'readwrite');\n transaction.objectStore(storeName).clear();\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error ?? new Error('Failed to clear replay history.'));\n });\n },\n async clearTopic(topic) {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n const transaction = db.transaction(storeName, 'readwrite');\n transaction.objectStore(storeName).delete(topic);\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error ?? new Error('Failed to clear topic replay history.'));\n });\n },\n async clearBefore(timestamp) {\n const db = await open();\n await new Promise<void>((resolve, reject) => {\n const transaction = db.transaction(storeName, 'readwrite');\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 ?? 0) >= 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 = () => reject(request.error ?? new Error('Failed to read replay history.'));\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error ?? new Error('Failed to prune replay history.'));\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 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 // 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 = () => handlers.onStatus('disconnected');\n socket.onerror = () => handlers.onStatus('error');\n socket.onmessage = event => this.handleMessage(event.data);\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 handleMessage(raw: unknown): void {\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": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../src/websocket.ts"],"names":[],"mappings":"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"}
package/docs/api.md CHANGED
@@ -102,7 +102,11 @@ Prefer using the cleanup function returned by `subscribe` to avoid accidentally
102
102
  ### `publish(topic, data, options?)`
103
103
 
104
104
  ```ts
105
- publish(topic: string, data: unknown, options?: { messageId?: string }): void
105
+ publish(
106
+ topic: string,
107
+ data: unknown,
108
+ options?: { messageId?: string; timestamp?: number }
109
+ ): void
106
110
  ```
107
111
 
108
112
  Routes the publish operation to the current topic owner; uses the current Worker when no valid route exists.
@@ -113,7 +117,17 @@ When the owning Worker is a remote Tab and the publish control message cannot be
113
117
 
114
118
  Incoming messages may include a caller/server supplied `messageId`. Enable bounded duplicate suppression with `dedup: { maxEntries, ttlMs }`; repeated IDs within the window are ignored. This is disabled by default and does not provide an exactly-once server guarantee.
115
119
 
116
- When supplied, `options.messageId` is propagated through cross-tab routing and supported transports. It is metadata only; the server must echo or otherwise preserve it for inbound deduplication.
120
+ When supplied, `options.messageId` and `options.timestamp` are propagated through cross-tab routing, Worker boundaries, and supported transports. The server must echo or otherwise preserve them for inbound deduplication and replay retention.
121
+
122
+ `DataBusMessage` and `DataBusPublication` expose the same optional metadata.
123
+ `DataBusPublicationEnvelope<TData>` is the canonical JSON envelope type:
124
+
125
+ ```ts
126
+ {
127
+ op: 'publication',
128
+ publication: { topic, data, messageId?, timestamp? }
129
+ }
130
+ ```
117
131
 
118
132
  ### `clearReplay()`
119
133
 
@@ -123,6 +137,10 @@ clearReplay(): Promise<void>
123
137
 
124
138
  Clears in-memory replay buffers and invokes the persistence adapter's optional `clear()` hook. Useful for retention policies, logout, or tenant switching. Durable history is otherwise preserved across `stop()`.
125
139
 
140
+ `clearReplayTopic(topic)` applies the same cleanup to one exact topic. `getDedupStats()` returns bounded counters (`enabled`, `tracked`, `accepted`, `suppressed`), and `resetDedup()` clears remembered IDs and counters without changing configuration.
141
+
142
+ `clearReplayBefore(timestamp)` removes entries older than an epoch-millisecond cutoff from memory and from adapters that implement optional `clearBefore(timestamp)`. Incoming messages receive a bus timestamp when the transport does not provide one.
143
+
126
144
  ### `onStatus(handler)`
127
145
 
128
146
  ```ts
@@ -285,8 +303,11 @@ Implements `DataBusTransport`. Connection lifecycle maps to the DataBus status v
285
303
 
286
304
  JSON text frames:
287
305
 
288
- - client → server: `{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...}`
289
- - server → client: `{"topic":"...","data":...}` for publications. Frames without a string `topic` field are ignored; malformed JSON surfaces via `handlers.onError` without throwing.
306
+ - client → server: `{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...,"messageId"?:...,"timestamp"?:...}`
307
+ - server → client (canonical): `{"op":"publication","publication":{"topic":"...","data":...,"messageId"?:...,"timestamp"?:...}}`
308
+ - server → client (legacy, still accepted): `{"topic":"...","data":...}`
309
+
310
+ Frames without a string publication `topic` are ignored; malformed JSON surfaces via `handlers.onError` without throwing.
290
311
 
291
312
  A pattern-aware server may deliver publications tagged with the concrete topic (recommended); publications tagged with the pattern itself are delivered through the exact-match path.
292
313
 
@@ -384,6 +384,8 @@ A publication travels publisher → current Topic owner → transport/server →
384
384
  4. The owner broadcasts `EVENT/DATABUS_PUBLICATION` over the BroadcastChannel and, if its own Tab also has a local subscription, dispatches once directly. BroadcastChannel never echoes to the sender, so there is no duplicate dispatch.
385
385
  5. Every other Tab receives the `EVENT` but invokes its local handlers only when it holds a `subscriber:{topicKey}:{tabId}` record for that topic; Tabs without a local subscription drop the message.
386
386
 
387
+ Optional publication metadata (`messageId` and `timestamp`) follows the same path as the payload: `CONTROL/PUBLISH` → transport/server → `DataBusMessage` → `EVENT` fan-out. It is never written to coordination storage. Transports normalize legacy payloads and the canonical `DataBusPublicationEnvelope` before the three dispatch gates.
388
+
387
389
  At the transport layer, a Centrifuge client can emit a publication both on the `client` object and on the matching `Subscription` object. To avoid dispatching the same server publication twice, the Centrifuge session only handles the client-level `publication` for topics that have **no active client-side subscription** (server-side subscriptions); topics with an active subscription are delivered solely through the subscription-level listener.
388
390
 
389
391
  ```mermaid
@@ -407,7 +409,7 @@ sequenceDiagram
407
409
 
408
410
  BroadcastChannel does not echo to its sender, so the owner receives no `EVENT` back for its own broadcast — its local dispatch is the only local delivery.
409
411
 
410
- Publications are not written to localStorage. Message data only exists in the BroadcastChannel in-memory event and within the transport; batch writes only cover coordination metadata.
412
+ Publications are not written to localStorage. Message data and publication metadata only exist in the BroadcastChannel in-memory event and within the transport; batch writes only cover coordination metadata.
411
413
 
412
414
  ### Dispatch flow: three gates
413
415
 
@@ -141,14 +141,18 @@ const bus = createWebSocketDataBus({
141
141
 
142
142
  Wire protocol (JSON text frames):
143
143
 
144
- - client → server: `{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...}`
145
- - server → client: publications are `{"topic":"...","data":...}`. Frames
146
- without a string `topic` are ignored; malformed JSON is reported through
147
- `handlers.onError` without throwing.
144
+ - client → server: `{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...,"messageId"?:"...","timestamp"?:123}`
145
+ - server → client: the canonical publication is `{"op":"publication","publication":{"topic":"...","data":...,"messageId"?:"...","timestamp"?:123}}`. The legacy flat `{"topic":"...","data":...}` frame remains accepted. Frames without a string topic are ignored; malformed JSON is reported through `handlers.onError` without throwing.
148
146
 
149
147
  When `data` is an `ArrayBuffer`, publish uses a binary frame with a small
150
148
  header (`0xc7`, UTF-8 topic length, topic, payload). Servers may echo the same
151
- frame unchanged; JSON remains the compatibility path for all other payloads.
149
+ frame unchanged. A binary publication carrying metadata uses the JSON-compatible
150
+ byte-array envelope so `messageId` and `timestamp` are not lost.
151
+
152
+ The Centrifuge session applies the same transport-neutral contract. Payloads
153
+ without metadata keep their original shape. Metadata-bearing publishes use
154
+ `{ data, messageId?, timestamp? }`, while inbound publications additionally
155
+ accept the canonical nested `DataBusPublicationEnvelope`.
152
156
 
153
157
  Lifecycle mapping: `open` → `connected`, `close` → `disconnected`,
154
158
  `error` → `error` (DataBus auto-recovery). Subscribe frames are re-sent when
package/docs/zh/api.md CHANGED
@@ -102,7 +102,11 @@ unsubscribe(topic: string, handler?: DataBusMessageHandler<TData>): void
102
102
  ### `publish(topic, data, options?)`
103
103
 
104
104
  ```ts
105
- publish(topic: string, data: unknown, options?: { messageId?: string }): void
105
+ publish(
106
+ topic: string,
107
+ data: unknown,
108
+ options?: { messageId?: string; timestamp?: number }
109
+ ): void
106
110
  ```
107
111
 
108
112
  将发布操作路由到当前 Topic owner;没有有效路由时使用当前 Worker。
@@ -111,7 +115,17 @@ publish(topic: string, data: unknown, options?: { messageId?: string }): void
111
115
 
112
116
  当 owner 是远端 Tab、且发布控制消息无法投递时(例如 BroadcastChannel 无法克隆 payload),`publish()` 会通过 `onError` 上报失败,而不是静默丢弃。
113
117
 
114
- 传入 `options.messageId` 后,ID 会经过跨 Tab 路由并由支持的 transport 透传。它只是元数据;服务端需要回显或保留该 ID,入站 dedup 才能生效。
118
+ 传入 `options.messageId` `options.timestamp` 后,元数据会穿过跨 Tab 路由、Worker 边界和支持的 transport。服务端必须回显或以其他方式保留它们,入站去重和 replay retention 才能使用。
119
+
120
+ `DataBusMessage` 与 `DataBusPublication` 暴露相同的可选元数据。
121
+ `DataBusPublicationEnvelope<TData>` 是标准 JSON envelope 类型:
122
+
123
+ ```ts
124
+ {
125
+ op: 'publication',
126
+ publication: { topic, data, messageId?, timestamp? }
127
+ }
128
+ ```
115
129
 
116
130
  ### `clearReplay()`
117
131
 
@@ -121,6 +135,10 @@ clearReplay(): Promise<void>
121
135
 
122
136
  清空内存 replay 缓冲,并调用持久化适配器可选的 `clear()`。适合留存策略、退出登录或租户切换;普通 `stop()` 仍会保留 durable history。
123
137
 
138
+ `clearReplayTopic(topic)` 只清理一个精确 topic。`getDedupStats()` 返回 `enabled`、`tracked`、`accepted`、`suppressed` 四项有界统计;`resetDedup()` 清除已记忆 ID 和计数,不改变 dedup 配置。
139
+
140
+ `clearReplayBefore(timestamp)` 按毫秒时间戳清理旧记录;实现可选 `clearBefore()` 的持久化适配器会同步执行该清理。
141
+
124
142
  ### `onStatus(handler)`
125
143
 
126
144
  ```ts
@@ -283,8 +301,11 @@ new WebSocketTransport<TData>(connection: WebSocketDataBusConfig)
283
301
 
284
302
  JSON 文本帧:
285
303
 
286
- - client → server:`{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...}`
287
- - server → client:发布为 `{"topic":"...","data":...}`。没有字符串 `topic` 字段的帧被忽略;非法 JSON 通过 `handlers.onError` 上报而不会抛出。
304
+ - client → server:`{"op":"subscribe"|"unsubscribe"|"publish","topic":"...","data":...,"messageId"?:...,"timestamp"?:...}`
305
+ - server → client(标准):`{"op":"publication","publication":{"topic":"...","data":...,"messageId"?:...,"timestamp"?:...}}`
306
+ - server → client(旧格式,继续兼容):`{"topic":"...","data":...}`
307
+
308
+ 没有字符串 publication `topic` 的帧会被忽略;非法 JSON 通过 `handlers.onError` 上报而不会抛出。
288
309
 
289
310
  支持 pattern 的服务器建议以具体 topic 标注发布;以 pattern 本身标注的发布走精确匹配路径投递。
290
311