cross-tab-worker-databus 0.20.71 → 0.20.86

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 (97) hide show
  1. package/CHANGELOG.md +216 -2
  2. package/README.md +8 -0
  3. package/README.zh.md +4 -0
  4. package/dist/centrifuge-protocol.d.ts +59 -26
  5. package/dist/centrifuge-protocol.d.ts.map +1 -1
  6. package/dist/centrifuge-session.d.ts +9 -0
  7. package/dist/centrifuge-session.d.ts.map +1 -1
  8. package/dist/centrifuge.d.ts +12 -2
  9. package/dist/centrifuge.d.ts.map +1 -1
  10. package/dist/centrifuge.js +168 -88
  11. package/dist/centrifuge.js.map +3 -3
  12. package/dist/centrifuge.shared.worker.js +146 -38
  13. package/dist/centrifuge.shared.worker.js.map +3 -3
  14. package/dist/centrifuge.worker.js +140 -33
  15. package/dist/centrifuge.worker.js.map +3 -3
  16. package/dist/{chunk-D2SIT473.js → chunk-SDOV3UHG.js} +1304 -515
  17. package/dist/chunk-SDOV3UHG.js.map +7 -0
  18. package/dist/chunk-TZ7ZP7YD.js +175 -0
  19. package/dist/chunk-TZ7ZP7YD.js.map +7 -0
  20. package/dist/cjs/centrifuge.cjs +1608 -650
  21. package/dist/cjs/centrifuge.cjs.map +4 -4
  22. package/dist/cjs/hooks.cjs +37 -2
  23. package/dist/cjs/hooks.cjs.map +3 -3
  24. package/dist/cjs/index.cjs +1692 -747
  25. package/dist/cjs/index.cjs.map +4 -4
  26. package/dist/cjs/vue.cjs +45 -2
  27. package/dist/cjs/vue.cjs.map +3 -3
  28. package/dist/core/cluster.d.ts +40 -4
  29. package/dist/core/cluster.d.ts.map +1 -1
  30. package/dist/core/data-bus.d.ts +134 -77
  31. package/dist/core/data-bus.d.ts.map +1 -1
  32. package/dist/core/dedup-manager.d.ts +98 -0
  33. package/dist/core/dedup-manager.d.ts.map +1 -0
  34. package/dist/core/environment.d.ts +43 -3
  35. package/dist/core/environment.d.ts.map +1 -1
  36. package/dist/core/replay-manager.d.ts +129 -0
  37. package/dist/core/replay-manager.d.ts.map +1 -0
  38. package/dist/core/replay-persistence.d.ts +2 -1
  39. package/dist/core/replay-persistence.d.ts.map +1 -1
  40. package/dist/core/replay-pruning.d.ts +21 -0
  41. package/dist/core/replay-pruning.d.ts.map +1 -0
  42. package/dist/core/routing.d.ts +22 -3
  43. package/dist/core/routing.d.ts.map +1 -1
  44. package/dist/core/storage-batch.d.ts +0 -4
  45. package/dist/core/storage-batch.d.ts.map +1 -1
  46. package/dist/core/trace.d.ts +55 -15
  47. package/dist/core/trace.d.ts.map +1 -1
  48. package/dist/core/types.d.ts +58 -9
  49. package/dist/core/types.d.ts.map +1 -1
  50. package/dist/core/version.d.ts +2 -0
  51. package/dist/core/version.d.ts.map +1 -0
  52. package/dist/hooks.d.ts +12 -1
  53. package/dist/hooks.d.ts.map +1 -1
  54. package/dist/hooks.js +28 -2
  55. package/dist/hooks.js.map +2 -2
  56. package/dist/index.d.ts +6 -6
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +263 -166
  59. package/dist/index.js.map +3 -3
  60. package/dist/utils/constants.d.ts +170 -0
  61. package/dist/utils/constants.d.ts.map +1 -0
  62. package/dist/utils/error-utils.d.ts +28 -0
  63. package/dist/utils/error-utils.d.ts.map +1 -0
  64. package/dist/utils/metadata.d.ts +16 -0
  65. package/dist/utils/metadata.d.ts.map +1 -0
  66. package/dist/utils/storage-utils.d.ts +24 -0
  67. package/dist/utils/storage-utils.d.ts.map +1 -0
  68. package/dist/utils/validation.d.ts +76 -0
  69. package/dist/utils/validation.d.ts.map +1 -0
  70. package/dist/vue.d.ts +13 -1
  71. package/dist/vue.d.ts.map +1 -1
  72. package/dist/vue.js +36 -2
  73. package/dist/vue.js.map +2 -2
  74. package/dist/websocket.d.ts +6 -1
  75. package/dist/websocket.d.ts.map +1 -1
  76. package/dist/worker-mode.d.ts +6 -2
  77. package/dist/worker-mode.d.ts.map +1 -1
  78. package/docs/README.md +1 -0
  79. package/docs/api.md +135 -4
  80. package/docs/architecture.md +92 -1
  81. package/docs/benchmarks.md +24 -0
  82. package/docs/capabilities.md +24 -3
  83. package/docs/configuration.md +58 -0
  84. package/docs/getting-started.md +35 -0
  85. package/docs/release-checklist.md +28 -5
  86. package/docs/roadmap.md +81 -5
  87. package/docs/zh/README.md +2 -1
  88. package/docs/zh/api.md +134 -4
  89. package/docs/zh/architecture.md +61 -1
  90. package/docs/zh/benchmarks.md +24 -0
  91. package/docs/zh/capabilities.md +21 -3
  92. package/docs/zh/configuration.md +53 -0
  93. package/docs/zh/getting-started.md +35 -0
  94. package/docs/zh/release-checklist.md +29 -6
  95. package/docs/zh/roadmap.md +93 -5
  96. package/package.json +39 -16
  97. package/dist/chunk-D2SIT473.js.map +0 -7
@@ -5003,50 +5003,140 @@ function parseDataBusPublication(value, fallbackTopic) {
5003
5003
  };
5004
5004
  }
5005
5005
 
5006
+ // src/utils/constants.ts
5007
+ var WORKER_STATUS = {
5008
+ CONNECTING: "connecting",
5009
+ CONNECTED: "connected",
5010
+ DISCONNECTED: "disconnected",
5011
+ ERROR: "error"
5012
+ };
5013
+ var DEFAULT_STORAGE_PREFIX = "cross-tab-worker-databus";
5014
+ var STORAGE_CHANNEL_PREFIX = `${DEFAULT_STORAGE_PREFIX}:channel:`;
5015
+ var TAB_ID_STORAGE_KEY = `${DEFAULT_STORAGE_PREFIX}:tab-id`;
5016
+ var CENTRIFUGE_INPUT_TYPE = {
5017
+ INIT: "INIT",
5018
+ SUBSCRIBE: "SUBSCRIBE",
5019
+ UNSUBSCRIBE: "UNSUBSCRIBE",
5020
+ PUBLISH: "PUBLISH",
5021
+ PUBLISH_BIN: "PUBLISH_BIN",
5022
+ PING: "PING",
5023
+ STOP: "STOP",
5024
+ TOKEN_RESPONSE: "TOKEN_RESPONSE",
5025
+ TOKEN_ERROR: "TOKEN_ERROR"
5026
+ };
5027
+ var CENTRIFUGE_OUTPUT_TYPE = {
5028
+ STATUS: "STATUS",
5029
+ MESSAGE: "MESSAGE",
5030
+ MESSAGE_BIN: "MESSAGE_BIN",
5031
+ ERROR: "ERROR",
5032
+ TOKEN_REQUEST: "TOKEN_REQUEST"
5033
+ };
5034
+
5035
+ // src/utils/metadata.ts
5036
+ function publicationMetadata(messageId, timestamp) {
5037
+ if (messageId === void 0 && timestamp === void 0) return void 0;
5038
+ return {
5039
+ ...messageId === void 0 ? {} : { messageId },
5040
+ ...timestamp === void 0 ? {} : { timestamp }
5041
+ };
5042
+ }
5043
+
5044
+ // src/utils/error-utils.ts
5045
+ function serializeError(error) {
5046
+ if (error instanceof Error) {
5047
+ return {
5048
+ name: error.name,
5049
+ message: error.message,
5050
+ ...error.stack ? { stack: error.stack } : {}
5051
+ };
5052
+ }
5053
+ const context = error === void 0 ? void 0 : error;
5054
+ return {
5055
+ name: "CentrifugeError",
5056
+ message: typeof error === "string" ? error : "Centrifuge worker operation failed.",
5057
+ ...context === void 0 || !isStructuredCloneable(context) ? {} : { context }
5058
+ };
5059
+ }
5060
+ function isStructuredCloneable(value) {
5061
+ if (typeof structuredClone !== "function") return true;
5062
+ try {
5063
+ structuredClone(value);
5064
+ return true;
5065
+ } catch {
5066
+ return false;
5067
+ }
5068
+ }
5069
+ function deserializeWorkerError(error) {
5070
+ const result = new Error(error.message);
5071
+ result.name = error.name;
5072
+ if (error.stack) result.stack = error.stack;
5073
+ if (error.context !== void 0) Object.assign(result, { context: error.context });
5074
+ return result;
5075
+ }
5076
+
5006
5077
  // src/centrifuge-session.ts
5007
5078
  var CentrifugeSession = class {
5008
5079
  constructor(sink) {
5009
5080
  this.sink = sink;
5010
5081
  }
5082
+ sink;
5011
5083
  client = null;
5012
5084
  subscriptions = /* @__PURE__ */ new Map();
5013
5085
  transferable = false;
5086
+ tokenBridge = false;
5087
+ nextRequestId = 1;
5088
+ pendingTokenRequests = /* @__PURE__ */ new Map();
5014
5089
  /** Dispatch an incoming Worker message to the matching operation.
5015
5090
  * Unknown message types are ignored rather than thrown, so a future protocol
5016
5091
  * extension adding a new variant cannot crash an older session. */
5017
5092
  handle(message) {
5018
5093
  switch (message.type) {
5019
- case "INIT":
5020
- this.initialize(message.url, message.config, message.transferable === true);
5094
+ case CENTRIFUGE_INPUT_TYPE.INIT:
5095
+ this.initialize(message.url, message.config, message.transferable === true, message.tokenBridge === true);
5021
5096
  return;
5022
- case "SUBSCRIBE":
5097
+ case CENTRIFUGE_INPUT_TYPE.SUBSCRIBE:
5023
5098
  this.subscribe(message.topic);
5024
5099
  return;
5025
- case "UNSUBSCRIBE":
5100
+ case CENTRIFUGE_INPUT_TYPE.UNSUBSCRIBE:
5026
5101
  this.unsubscribe(message.topic);
5027
5102
  return;
5028
- case "PUBLISH":
5029
- case "PUBLISH_BIN":
5103
+ case CENTRIFUGE_INPUT_TYPE.PUBLISH:
5104
+ case CENTRIFUGE_INPUT_TYPE.PUBLISH_BIN:
5030
5105
  this.publish(message.topic, message.data, message.messageId, message.timestamp);
5031
5106
  return;
5032
- case "STOP":
5107
+ case CENTRIFUGE_INPUT_TYPE.STOP:
5033
5108
  this.stop();
5034
5109
  return;
5110
+ case CENTRIFUGE_INPUT_TYPE.TOKEN_RESPONSE:
5111
+ this.resolveToken(message.requestId, message.token);
5112
+ return;
5113
+ case CENTRIFUGE_INPUT_TYPE.TOKEN_ERROR:
5114
+ this.rejectToken(message.requestId, deserializeWorkerError(message.error));
5115
+ return;
5035
5116
  default:
5036
5117
  return;
5037
5118
  }
5038
5119
  }
5039
5120
  /** Create the Centrifuge client, wire up lifecycle listeners, and connect. */
5040
- initialize(url, config, transferable) {
5121
+ initialize(url, config, transferable, tokenBridge) {
5041
5122
  if (this.client) return;
5042
5123
  this.transferable = transferable;
5043
- const client = new Centrifuge(url, config);
5124
+ this.tokenBridge = tokenBridge;
5125
+ const clientOptions = tokenBridge ? {
5126
+ ...config,
5127
+ // Route credential fetches back to the main thread, where the
5128
+ // application's credentialProvider lives (config must stay
5129
+ // structured-cloneable, so functions cannot cross the boundary).
5130
+ getToken: () => this.requestToken("token"),
5131
+ getChannelToken: (channel) => this.requestToken("channelToken", channel)
5132
+ } : config;
5133
+ const client = new Centrifuge(url, clientOptions);
5044
5134
  this.client = client;
5045
5135
  client.on("state", (context) => {
5046
- this.post({ type: "STATUS", status: normalizeStatus(context.newState) });
5136
+ this.post({ type: CENTRIFUGE_OUTPUT_TYPE.STATUS, status: normalizeStatus(context.newState) });
5047
5137
  });
5048
- client.on("connected", () => this.post({ type: "STATUS", status: "connected" }));
5049
- client.on("disconnected", () => this.post({ type: "STATUS", status: "disconnected" }));
5138
+ client.on("connected", () => this.post({ type: CENTRIFUGE_OUTPUT_TYPE.STATUS, status: WORKER_STATUS.CONNECTED }));
5139
+ client.on("disconnected", () => this.post({ type: CENTRIFUGE_OUTPUT_TYPE.STATUS, status: WORKER_STATUS.DISCONNECTED }));
5050
5140
  client.on("error", (context) => this.postError(context));
5051
5141
  client.on("publication", (context) => {
5052
5142
  const topic = context.channel || getPayloadTopic(context.data);
@@ -5109,25 +5199,56 @@ var CentrifugeSession = class {
5109
5199
  postPublication(topic, data) {
5110
5200
  if (!topic) return;
5111
5201
  if (this.transferable && data instanceof ArrayBuffer) {
5112
- this.post({ type: "MESSAGE_BIN", topic, data }, [data]);
5202
+ this.post({ type: CENTRIFUGE_OUTPUT_TYPE.MESSAGE_BIN, topic, data }, [data]);
5113
5203
  return;
5114
5204
  }
5115
5205
  const publication = parseDataBusPublication(data, topic);
5116
5206
  if (!publication) return;
5117
5207
  this.post({
5118
- type: "MESSAGE",
5208
+ type: CENTRIFUGE_OUTPUT_TYPE.MESSAGE,
5119
5209
  topic: publication.topic,
5120
5210
  data: publication.data,
5121
- ...publication.messageId === void 0 ? {} : { messageId: publication.messageId },
5122
- ...publication.timestamp === void 0 ? {} : { timestamp: publication.timestamp }
5211
+ ...publicationMetadata(publication.messageId, publication.timestamp)
5123
5212
  });
5124
5213
  }
5125
5214
  /** Disconnect the client and clear all subscriptions. */
5126
5215
  stop() {
5216
+ for (const [, pending] of this.pendingTokenRequests) {
5217
+ pending.reject(new Error("Centrifuge session stopped before the credential was resolved."));
5218
+ }
5219
+ this.pendingTokenRequests.clear();
5127
5220
  this.client?.disconnect();
5128
5221
  this.subscriptions.clear();
5129
5222
  this.client = null;
5130
- this.post({ type: "STATUS", status: "disconnected" });
5223
+ this.post({ type: CENTRIFUGE_OUTPUT_TYPE.STATUS, status: WORKER_STATUS.DISCONNECTED });
5224
+ }
5225
+ /** Issue a credential request to the main thread and await the response.
5226
+ * Used as Centrifuge's `getToken` / `getChannelToken` when token bridging is
5227
+ * enabled; resolved or rejected by a matching TOKEN_RESPONSE / TOKEN_ERROR. */
5228
+ requestToken(kind, channel) {
5229
+ const requestId = this.nextRequestId;
5230
+ this.nextRequestId += 1;
5231
+ return new Promise((resolve, reject) => {
5232
+ this.pendingTokenRequests.set(requestId, { resolve, reject });
5233
+ this.post({
5234
+ type: CENTRIFUGE_OUTPUT_TYPE.TOKEN_REQUEST,
5235
+ requestId,
5236
+ kind,
5237
+ ...channel === void 0 ? {} : { channel }
5238
+ });
5239
+ });
5240
+ }
5241
+ resolveToken(requestId, token) {
5242
+ const pending = this.pendingTokenRequests.get(requestId);
5243
+ if (!pending) return;
5244
+ this.pendingTokenRequests.delete(requestId);
5245
+ pending.resolve(token);
5246
+ }
5247
+ rejectToken(requestId, error) {
5248
+ const pending = this.pendingTokenRequests.get(requestId);
5249
+ if (!pending) return;
5250
+ this.pendingTokenRequests.delete(requestId);
5251
+ pending.reject(error);
5131
5252
  }
5132
5253
  /** Forward a message to the sink (the transport layer). */
5133
5254
  post(message, transfer) {
@@ -5139,7 +5260,7 @@ var CentrifugeSession = class {
5139
5260
  * Fatal errors are distinguished by the client eventually emitting
5140
5261
  * `disconnected` without a subsequent `connected`. */
5141
5262
  postError(error) {
5142
- this.post({ type: "ERROR", error: serializeError(error) });
5263
+ this.post({ type: CENTRIFUGE_OUTPUT_TYPE.ERROR, error: serializeError(error) });
5143
5264
  }
5144
5265
  };
5145
5266
  function getPayloadTopic(data) {
@@ -5150,24 +5271,10 @@ function getPayloadTopic(data) {
5150
5271
  const topic = nested ?? payload.channel;
5151
5272
  return typeof topic === "string" ? topic : "";
5152
5273
  }
5153
- var LIVE_STATES = /* @__PURE__ */ new Set(["connecting", "connected"]);
5274
+ var LIVE_STATES = /* @__PURE__ */ new Set([WORKER_STATUS.CONNECTING, WORKER_STATUS.CONNECTED]);
5154
5275
  function normalizeStatus(status) {
5155
5276
  return LIVE_STATES.has(status) ? status : "disconnected";
5156
5277
  }
5157
- function serializeError(error) {
5158
- if (error instanceof Error) {
5159
- return {
5160
- name: error.name,
5161
- message: error.message,
5162
- ...error.stack ? { stack: error.stack } : {}
5163
- };
5164
- }
5165
- return {
5166
- name: "CentrifugeError",
5167
- message: typeof error === "string" ? error : "Centrifuge worker operation failed.",
5168
- ...error === void 0 ? {} : { context: error }
5169
- };
5170
- }
5171
5278
 
5172
5279
  // src/workers/centrifuge.worker.ts
5173
5280
  var workerScope = self;