cross-tab-worker-databus 0.20.71 → 0.20.85
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 +204 -2
- package/README.md +8 -0
- package/README.zh.md +4 -0
- package/dist/centrifuge-protocol.d.ts +59 -26
- package/dist/centrifuge-protocol.d.ts.map +1 -1
- package/dist/centrifuge-session.d.ts +9 -0
- package/dist/centrifuge-session.d.ts.map +1 -1
- package/dist/centrifuge.d.ts +12 -2
- package/dist/centrifuge.d.ts.map +1 -1
- package/dist/centrifuge.js +168 -88
- package/dist/centrifuge.js.map +3 -3
- package/dist/centrifuge.shared.worker.js +146 -38
- package/dist/centrifuge.shared.worker.js.map +3 -3
- package/dist/centrifuge.worker.js +140 -33
- package/dist/centrifuge.worker.js.map +3 -3
- package/dist/{chunk-D2SIT473.js → chunk-PW63EWIK.js} +1090 -494
- package/dist/chunk-PW63EWIK.js.map +7 -0
- package/dist/chunk-TZ7ZP7YD.js +175 -0
- package/dist/chunk-TZ7ZP7YD.js.map +7 -0
- package/dist/cjs/centrifuge.cjs +1403 -637
- package/dist/cjs/centrifuge.cjs.map +4 -4
- package/dist/cjs/hooks.cjs +37 -2
- package/dist/cjs/hooks.cjs.map +3 -3
- package/dist/cjs/index.cjs +1453 -730
- package/dist/cjs/index.cjs.map +4 -4
- package/dist/cjs/vue.cjs +45 -2
- package/dist/cjs/vue.cjs.map +3 -3
- package/dist/core/cluster.d.ts +40 -4
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/data-bus.d.ts +93 -69
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/core/dedup-manager.d.ts +98 -0
- package/dist/core/dedup-manager.d.ts.map +1 -0
- package/dist/core/environment.d.ts +43 -3
- package/dist/core/environment.d.ts.map +1 -1
- package/dist/core/replay-manager.d.ts +128 -0
- package/dist/core/replay-manager.d.ts.map +1 -0
- package/dist/core/replay-persistence.d.ts +2 -1
- package/dist/core/replay-persistence.d.ts.map +1 -1
- package/dist/core/routing.d.ts +22 -3
- package/dist/core/routing.d.ts.map +1 -1
- package/dist/core/storage-batch.d.ts +0 -4
- package/dist/core/storage-batch.d.ts.map +1 -1
- package/dist/core/trace.d.ts +55 -15
- package/dist/core/trace.d.ts.map +1 -1
- package/dist/core/types.d.ts +58 -9
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/version.d.ts +2 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/hooks.d.ts +12 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +28 -2
- package/dist/hooks.js.map +2 -2
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +228 -162
- package/dist/index.js.map +3 -3
- package/dist/utils/constants.d.ts +170 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/error-utils.d.ts +28 -0
- package/dist/utils/error-utils.d.ts.map +1 -0
- package/dist/utils/metadata.d.ts +16 -0
- package/dist/utils/metadata.d.ts.map +1 -0
- package/dist/utils/storage-utils.d.ts +24 -0
- package/dist/utils/storage-utils.d.ts.map +1 -0
- package/dist/utils/validation.d.ts +76 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/vue.d.ts +13 -1
- package/dist/vue.d.ts.map +1 -1
- package/dist/vue.js +36 -2
- package/dist/vue.js.map +2 -2
- package/dist/websocket.d.ts +6 -1
- package/dist/websocket.d.ts.map +1 -1
- package/dist/worker-mode.d.ts +6 -2
- package/dist/worker-mode.d.ts.map +1 -1
- package/docs/README.md +1 -0
- package/docs/api.md +122 -2
- package/docs/architecture.md +80 -0
- package/docs/benchmarks.md +24 -0
- package/docs/capabilities.md +24 -3
- package/docs/configuration.md +58 -0
- package/docs/getting-started.md +35 -0
- package/docs/release-checklist.md +28 -5
- package/docs/roadmap.md +74 -5
- package/docs/zh/README.md +2 -1
- package/docs/zh/api.md +121 -2
- package/docs/zh/architecture.md +49 -0
- package/docs/zh/benchmarks.md +24 -0
- package/docs/zh/capabilities.md +21 -3
- package/docs/zh/configuration.md +53 -0
- package/docs/zh/getting-started.md +35 -0
- package/docs/zh/release-checklist.md +29 -6
- package/docs/zh/roadmap.md +86 -5
- package/package.json +39 -16
- package/dist/chunk-D2SIT473.js.map +0 -7
package/dist/index.js
CHANGED
|
@@ -2,8 +2,14 @@ import {
|
|
|
2
2
|
CrossTabDataBus,
|
|
3
3
|
DEFAULT_MAX_ACTIVE_WORKERS,
|
|
4
4
|
WorkerClusterRuntime,
|
|
5
|
+
approximatePayloadBytes,
|
|
6
|
+
assertPositiveFiniteNumber,
|
|
7
|
+
assertPositiveSafeInteger,
|
|
8
|
+
assertPruneStrategy,
|
|
5
9
|
createBrowserEnvironment,
|
|
6
10
|
createOpaqueKey,
|
|
11
|
+
createStorageEventChannel,
|
|
12
|
+
effectiveWorkerLoad,
|
|
7
13
|
getOrCreateTabId,
|
|
8
14
|
hasActiveOwner,
|
|
9
15
|
isWildcardTopic,
|
|
@@ -13,22 +19,26 @@ import {
|
|
|
13
19
|
selectRebalanceTarget,
|
|
14
20
|
selectWorkerBackend,
|
|
15
21
|
topicMatchesPattern
|
|
16
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-PW63EWIK.js";
|
|
23
|
+
import {
|
|
24
|
+
DEFAULT_STORAGE_PREFIX,
|
|
25
|
+
PRUNE_STRATEGY,
|
|
26
|
+
WORKER_STATUS,
|
|
27
|
+
WS_OP
|
|
28
|
+
} from "./chunk-TZ7ZP7YD.js";
|
|
17
29
|
|
|
18
30
|
// src/core/replay-persistence.ts
|
|
19
31
|
function createIndexedDbReplayPersistence(options) {
|
|
20
32
|
const indexedDb = globalThis.indexedDB;
|
|
21
33
|
if (!indexedDb) throw new Error("IndexedDB is unavailable in this environment.");
|
|
22
|
-
const dbName = options.dbName ??
|
|
34
|
+
const dbName = options.dbName ?? DEFAULT_STORAGE_PREFIX;
|
|
23
35
|
const storeName = "replay";
|
|
24
36
|
const maxPerTopic = options.maxPerTopic;
|
|
25
|
-
const pruneStrategy = options.pruneStrategy ??
|
|
37
|
+
const pruneStrategy = options.pruneStrategy ?? PRUNE_STRATEGY.COUNT;
|
|
26
38
|
const retentionMs = options.retentionMs;
|
|
27
|
-
|
|
28
|
-
if (retentionMs !== void 0
|
|
29
|
-
|
|
30
|
-
throw new TypeError(`maxPerTopic must be a positive safe integer, got ${String(maxPerTopic)}.`);
|
|
31
|
-
}
|
|
39
|
+
assertPruneStrategy(pruneStrategy);
|
|
40
|
+
if (retentionMs !== void 0) assertPositiveFiniteNumber(retentionMs, "retentionMs");
|
|
41
|
+
assertPositiveSafeInteger(maxPerTopic, "maxPerTopic");
|
|
32
42
|
let dbPromise = null;
|
|
33
43
|
const invalidate = (db) => {
|
|
34
44
|
if (dbPromise) {
|
|
@@ -40,15 +50,100 @@ function createIndexedDbReplayPersistence(options) {
|
|
|
40
50
|
}, () => void 0);
|
|
41
51
|
}
|
|
42
52
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
const pending = [];
|
|
54
|
+
let draining = false;
|
|
55
|
+
const drain = async () => {
|
|
56
|
+
if (draining) return;
|
|
57
|
+
draining = true;
|
|
58
|
+
try {
|
|
59
|
+
await Promise.resolve();
|
|
60
|
+
while (pending.length > 0) {
|
|
61
|
+
const head = pending[0].mutation;
|
|
62
|
+
if (head.kind === "batch") {
|
|
63
|
+
const merged = [];
|
|
64
|
+
const entries = [];
|
|
65
|
+
while (pending.length > 0) {
|
|
66
|
+
const next = pending[0].mutation;
|
|
67
|
+
if (next.kind !== "batch") break;
|
|
68
|
+
merged.push(...next.messages);
|
|
69
|
+
entries.push({ resolve: pending[0].resolve, reject: pending[0].reject });
|
|
70
|
+
pending.shift();
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
await appendTransaction(merged);
|
|
74
|
+
for (const entry of entries) entry.resolve();
|
|
75
|
+
} catch (error) {
|
|
76
|
+
for (const entry of entries) entry.reject(error);
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
const entry = pending.shift();
|
|
80
|
+
try {
|
|
81
|
+
await head.run();
|
|
82
|
+
entry.resolve();
|
|
83
|
+
} catch (error) {
|
|
84
|
+
entry.reject(error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
} finally {
|
|
89
|
+
draining = false;
|
|
90
|
+
}
|
|
48
91
|
};
|
|
92
|
+
const enqueue = (mutation) => new Promise((resolve, reject) => {
|
|
93
|
+
pending.push({ mutation, resolve, reject });
|
|
94
|
+
void drain();
|
|
95
|
+
});
|
|
96
|
+
const appendTransaction = (messages) => (async () => {
|
|
97
|
+
const db = await open();
|
|
98
|
+
return new Promise((resolve, reject) => {
|
|
99
|
+
let transaction;
|
|
100
|
+
try {
|
|
101
|
+
transaction = db.transaction(storeName, "readwrite");
|
|
102
|
+
} catch (error) {
|
|
103
|
+
invalidate(db);
|
|
104
|
+
reject(error);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const store = transaction.objectStore(storeName);
|
|
108
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
109
|
+
for (const message of messages) {
|
|
110
|
+
grouped.set(message.topic, [...grouped.get(message.topic) ?? [], message]);
|
|
111
|
+
}
|
|
112
|
+
let hasError = false;
|
|
113
|
+
for (const [topic, topicMessages] of grouped) {
|
|
114
|
+
const request = store.get(topic);
|
|
115
|
+
request.onsuccess = () => {
|
|
116
|
+
if (hasError) return;
|
|
117
|
+
let history = (request.result?.messages ?? []).concat(topicMessages);
|
|
118
|
+
const ageBounded = pruneStrategy !== PRUNE_STRATEGY.COUNT && retentionMs !== void 0;
|
|
119
|
+
if (ageBounded) {
|
|
120
|
+
const cutoff = Date.now() - retentionMs;
|
|
121
|
+
history = history.filter((item) => item.timestamp === void 0 || item.timestamp >= cutoff);
|
|
122
|
+
}
|
|
123
|
+
if (pruneStrategy !== PRUNE_STRATEGY.AGE || !ageBounded) history = history.slice(-maxPerTopic);
|
|
124
|
+
store.put({ topic, messages: history });
|
|
125
|
+
};
|
|
126
|
+
request.onerror = () => {
|
|
127
|
+
if (hasError) return;
|
|
128
|
+
hasError = true;
|
|
129
|
+
invalidate(db);
|
|
130
|
+
reject(request.error ?? new Error("Failed to read replay history."));
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
transaction.oncomplete = () => {
|
|
134
|
+
if (!hasError) resolve();
|
|
135
|
+
};
|
|
136
|
+
transaction.onerror = () => {
|
|
137
|
+
if (hasError) return;
|
|
138
|
+
hasError = true;
|
|
139
|
+
invalidate(db);
|
|
140
|
+
reject(transaction.error ?? new Error("Failed to persist replay history."));
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
})();
|
|
49
144
|
const open = () => {
|
|
50
145
|
if (dbPromise) return dbPromise;
|
|
51
|
-
const
|
|
146
|
+
const pending2 = new Promise((resolve, reject) => {
|
|
52
147
|
const request = indexedDb.open(dbName, 1);
|
|
53
148
|
request.onupgradeneeded = () => request.result.createObjectStore(storeName, { keyPath: "topic" });
|
|
54
149
|
request.onsuccess = () => {
|
|
@@ -61,11 +156,11 @@ function createIndexedDbReplayPersistence(options) {
|
|
|
61
156
|
};
|
|
62
157
|
request.onerror = () => reject(request.error ?? new Error("Failed to open replay database."));
|
|
63
158
|
});
|
|
64
|
-
dbPromise =
|
|
65
|
-
void
|
|
66
|
-
if (dbPromise ===
|
|
159
|
+
dbPromise = pending2;
|
|
160
|
+
void pending2.catch(() => {
|
|
161
|
+
if (dbPromise === pending2) dbPromise = null;
|
|
67
162
|
});
|
|
68
|
-
return
|
|
163
|
+
return pending2;
|
|
69
164
|
};
|
|
70
165
|
return {
|
|
71
166
|
async load() {
|
|
@@ -87,153 +182,94 @@ function createIndexedDbReplayPersistence(options) {
|
|
|
87
182
|
});
|
|
88
183
|
},
|
|
89
184
|
append(message) {
|
|
90
|
-
return
|
|
91
|
-
const db = await open();
|
|
92
|
-
await new Promise((resolve, reject) => {
|
|
93
|
-
let transaction;
|
|
94
|
-
try {
|
|
95
|
-
transaction = db.transaction(storeName, "readwrite");
|
|
96
|
-
} catch (error) {
|
|
97
|
-
invalidate(db);
|
|
98
|
-
reject(error);
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
const store = transaction.objectStore(storeName);
|
|
102
|
-
const request = store.get(message.topic);
|
|
103
|
-
request.onsuccess = () => {
|
|
104
|
-
let messages = (request.result?.messages ?? []).concat(message);
|
|
105
|
-
if (pruneStrategy !== "count" && retentionMs !== void 0) {
|
|
106
|
-
const cutoff = Date.now() - retentionMs;
|
|
107
|
-
messages = messages.filter((item) => item.timestamp === void 0 || item.timestamp >= cutoff);
|
|
108
|
-
}
|
|
109
|
-
if (pruneStrategy !== "age") messages = messages.slice(-maxPerTopic);
|
|
110
|
-
store.put({ topic: message.topic, messages });
|
|
111
|
-
};
|
|
112
|
-
request.onerror = () => {
|
|
113
|
-
invalidate(db);
|
|
114
|
-
reject(request.error ?? new Error("Failed to read replay history."));
|
|
115
|
-
};
|
|
116
|
-
transaction.oncomplete = () => resolve();
|
|
117
|
-
transaction.onerror = () => {
|
|
118
|
-
invalidate(db);
|
|
119
|
-
reject(transaction.error ?? new Error("Failed to persist replay history."));
|
|
120
|
-
};
|
|
121
|
-
});
|
|
122
|
-
});
|
|
185
|
+
return enqueue({ kind: "batch", messages: [message] });
|
|
123
186
|
},
|
|
124
187
|
appendBatch(messages) {
|
|
125
188
|
if (messages.length === 0) return Promise.resolve();
|
|
126
|
-
return
|
|
127
|
-
const db = await open();
|
|
128
|
-
await new Promise((resolve, reject) => {
|
|
129
|
-
let transaction;
|
|
130
|
-
try {
|
|
131
|
-
transaction = db.transaction(storeName, "readwrite");
|
|
132
|
-
} catch (error) {
|
|
133
|
-
invalidate(db);
|
|
134
|
-
reject(error);
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
const store = transaction.objectStore(storeName);
|
|
138
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
139
|
-
for (const message of messages) grouped.set(message.topic, [...grouped.get(message.topic) ?? [], message]);
|
|
140
|
-
for (const [topic, topicMessages] of grouped) {
|
|
141
|
-
const request = store.get(topic);
|
|
142
|
-
request.onsuccess = () => {
|
|
143
|
-
let history = (request.result?.messages ?? []).concat(topicMessages);
|
|
144
|
-
if (pruneStrategy !== "count" && retentionMs !== void 0) {
|
|
145
|
-
const cutoff = Date.now() - retentionMs;
|
|
146
|
-
history = history.filter((item) => item.timestamp === void 0 || item.timestamp >= cutoff);
|
|
147
|
-
}
|
|
148
|
-
if (pruneStrategy !== "age") history = history.slice(-maxPerTopic);
|
|
149
|
-
store.put({ topic, messages: history });
|
|
150
|
-
};
|
|
151
|
-
request.onerror = () => {
|
|
152
|
-
invalidate(db);
|
|
153
|
-
reject(request.error ?? new Error("Failed to read replay history."));
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
transaction.oncomplete = () => resolve();
|
|
157
|
-
transaction.onerror = () => {
|
|
158
|
-
invalidate(db);
|
|
159
|
-
reject(transaction.error ?? new Error("Failed to persist replay history batch."));
|
|
160
|
-
};
|
|
161
|
-
});
|
|
162
|
-
});
|
|
189
|
+
return enqueue({ kind: "batch", messages });
|
|
163
190
|
},
|
|
164
191
|
clear() {
|
|
165
|
-
return
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
192
|
+
return enqueue({
|
|
193
|
+
kind: "run",
|
|
194
|
+
run: () => (async () => {
|
|
195
|
+
const db = await open();
|
|
196
|
+
return new Promise((resolve, reject) => {
|
|
197
|
+
let transaction;
|
|
198
|
+
try {
|
|
199
|
+
transaction = db.transaction(storeName, "readwrite");
|
|
200
|
+
} catch (error) {
|
|
201
|
+
invalidate(db);
|
|
202
|
+
reject(error);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
transaction.objectStore(storeName).clear();
|
|
206
|
+
transaction.oncomplete = () => resolve();
|
|
207
|
+
transaction.onerror = () => {
|
|
208
|
+
invalidate(db);
|
|
209
|
+
reject(transaction.error ?? new Error("Failed to clear replay history."));
|
|
210
|
+
};
|
|
211
|
+
});
|
|
212
|
+
})()
|
|
183
213
|
});
|
|
184
214
|
},
|
|
185
215
|
clearTopic(topic) {
|
|
186
|
-
return
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
216
|
+
return enqueue({
|
|
217
|
+
kind: "run",
|
|
218
|
+
run: () => (async () => {
|
|
219
|
+
const db = await open();
|
|
220
|
+
return new Promise((resolve, reject) => {
|
|
221
|
+
let transaction;
|
|
222
|
+
try {
|
|
223
|
+
transaction = db.transaction(storeName, "readwrite");
|
|
224
|
+
} catch (error) {
|
|
225
|
+
invalidate(db);
|
|
226
|
+
reject(error);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
transaction.objectStore(storeName).delete(topic);
|
|
230
|
+
transaction.oncomplete = () => resolve();
|
|
231
|
+
transaction.onerror = () => {
|
|
232
|
+
invalidate(db);
|
|
233
|
+
reject(transaction.error ?? new Error("Failed to clear topic replay history."));
|
|
234
|
+
};
|
|
235
|
+
});
|
|
236
|
+
})()
|
|
204
237
|
});
|
|
205
238
|
},
|
|
206
239
|
clearBefore(timestamp) {
|
|
207
|
-
return
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const request = store.getAll();
|
|
220
|
-
request.onsuccess = () => {
|
|
221
|
-
for (const record of request.result) {
|
|
222
|
-
const messages = record.messages.filter((message) => message.timestamp === void 0 || message.timestamp >= timestamp);
|
|
223
|
-
if (messages.length === 0) store.delete(record.topic);
|
|
224
|
-
else if (messages.length !== record.messages.length) store.put({ topic: record.topic, messages });
|
|
240
|
+
return enqueue({
|
|
241
|
+
kind: "run",
|
|
242
|
+
run: () => (async () => {
|
|
243
|
+
const db = await open();
|
|
244
|
+
return new Promise((resolve, reject) => {
|
|
245
|
+
let transaction;
|
|
246
|
+
try {
|
|
247
|
+
transaction = db.transaction(storeName, "readwrite");
|
|
248
|
+
} catch (error) {
|
|
249
|
+
invalidate(db);
|
|
250
|
+
reject(error);
|
|
251
|
+
return;
|
|
225
252
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
253
|
+
const store = transaction.objectStore(storeName);
|
|
254
|
+
const request = store.getAll();
|
|
255
|
+
request.onsuccess = () => {
|
|
256
|
+
for (const record of request.result) {
|
|
257
|
+
const messages = record.messages.filter((message) => message.timestamp === void 0 || message.timestamp >= timestamp);
|
|
258
|
+
if (messages.length === 0) store.delete(record.topic);
|
|
259
|
+
else if (messages.length !== record.messages.length) store.put({ topic: record.topic, messages });
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
request.onerror = () => {
|
|
263
|
+
invalidate(db);
|
|
264
|
+
reject(request.error ?? new Error("Failed to read replay history."));
|
|
265
|
+
};
|
|
266
|
+
transaction.oncomplete = () => resolve();
|
|
267
|
+
transaction.onerror = () => {
|
|
268
|
+
invalidate(db);
|
|
269
|
+
reject(transaction.error ?? new Error("Failed to prune replay history."));
|
|
270
|
+
};
|
|
271
|
+
});
|
|
272
|
+
})()
|
|
237
273
|
});
|
|
238
274
|
}
|
|
239
275
|
};
|
|
@@ -245,6 +281,7 @@ var WebSocketTransport = class {
|
|
|
245
281
|
constructor(connection) {
|
|
246
282
|
this.connection = connection;
|
|
247
283
|
}
|
|
284
|
+
connection;
|
|
248
285
|
diagnosticsName = "websocket";
|
|
249
286
|
diagnosticsBackend = "native-websocket";
|
|
250
287
|
socket = null;
|
|
@@ -261,22 +298,22 @@ var WebSocketTransport = class {
|
|
|
261
298
|
try {
|
|
262
299
|
socket = factory(config.url, protocols);
|
|
263
300
|
} catch (error) {
|
|
264
|
-
handlers.onStatus(
|
|
301
|
+
handlers.onStatus(WORKER_STATUS.ERROR);
|
|
265
302
|
handlers.onError(error);
|
|
266
303
|
return;
|
|
267
304
|
}
|
|
268
305
|
socket.onopen = () => {
|
|
269
306
|
if (this.socket !== socket || this.handlers !== handlers) return;
|
|
270
307
|
for (const topic of this.subscribedTopics) {
|
|
271
|
-
this.sendFrame({ op:
|
|
308
|
+
this.sendFrame({ op: WS_OP.SUBSCRIBE, topic });
|
|
272
309
|
}
|
|
273
|
-
handlers.onStatus(
|
|
310
|
+
handlers.onStatus(WORKER_STATUS.CONNECTED);
|
|
274
311
|
};
|
|
275
312
|
socket.onclose = () => {
|
|
276
|
-
if (this.socket === socket && this.handlers === handlers) handlers.onStatus(
|
|
313
|
+
if (this.socket === socket && this.handlers === handlers) handlers.onStatus(WORKER_STATUS.DISCONNECTED);
|
|
277
314
|
};
|
|
278
315
|
socket.onerror = () => {
|
|
279
|
-
if (this.socket === socket && this.handlers === handlers) handlers.onStatus(
|
|
316
|
+
if (this.socket === socket && this.handlers === handlers) handlers.onStatus(WORKER_STATUS.ERROR);
|
|
280
317
|
};
|
|
281
318
|
socket.onmessage = (event) => {
|
|
282
319
|
if (this.socket === socket && this.handlers === handlers) void this.handleMessage(event.data);
|
|
@@ -287,12 +324,12 @@ var WebSocketTransport = class {
|
|
|
287
324
|
* not duplicate the local tracking entry. */
|
|
288
325
|
subscribe(topic) {
|
|
289
326
|
this.subscribedTopics.add(topic);
|
|
290
|
-
this.sendFrame({ op:
|
|
327
|
+
this.sendFrame({ op: WS_OP.SUBSCRIBE, topic });
|
|
291
328
|
}
|
|
292
329
|
/** Idempotent: unsubscribing an unknown topic is a no-op. */
|
|
293
330
|
unsubscribe(topic) {
|
|
294
331
|
this.subscribedTopics.delete(topic);
|
|
295
|
-
this.sendFrame({ op:
|
|
332
|
+
this.sendFrame({ op: WS_OP.UNSUBSCRIBE, topic });
|
|
296
333
|
}
|
|
297
334
|
/** Publish `data` to `topic` as a JSON frame. Requires an open socket. */
|
|
298
335
|
publish(topic, data, options) {
|
|
@@ -301,13 +338,39 @@ var WebSocketTransport = class {
|
|
|
301
338
|
return;
|
|
302
339
|
}
|
|
303
340
|
this.sendFrame({
|
|
304
|
-
op:
|
|
341
|
+
op: WS_OP.PUBLISH,
|
|
305
342
|
topic,
|
|
306
343
|
data,
|
|
307
344
|
...options?.messageId === void 0 ? {} : { messageId: options.messageId },
|
|
308
345
|
...options?.timestamp === void 0 ? {} : { timestamp: options.timestamp }
|
|
309
346
|
});
|
|
310
347
|
}
|
|
348
|
+
/** Publish many items for one topic as a single wire frame. One-item
|
|
349
|
+
* batches delegate to `publish` so the legacy single-publication frame
|
|
350
|
+
* shape (including binary framing) is preserved. */
|
|
351
|
+
publishBatch(topic, items) {
|
|
352
|
+
if (items.length === 0) return;
|
|
353
|
+
if (items.length === 1) {
|
|
354
|
+
const single = items[0];
|
|
355
|
+
return this.publish(topic, single.data, {
|
|
356
|
+
...single.messageId === void 0 ? {} : { messageId: single.messageId },
|
|
357
|
+
...single.timestamp === void 0 ? {} : { timestamp: single.timestamp }
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
if (this.socket?.readyState !== WS_OPEN) {
|
|
361
|
+
this.handlers?.onError(new Error('WebSocket is not open; dropped "publishBatch" frame.'));
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
this.socket.send(JSON.stringify({
|
|
365
|
+
op: WS_OP.PUBLISH_BATCH,
|
|
366
|
+
topic,
|
|
367
|
+
items: items.map((item) => ({
|
|
368
|
+
data: item.data instanceof ArrayBuffer ? Array.from(new Uint8Array(item.data)) : item.data,
|
|
369
|
+
...item.messageId === void 0 ? {} : { messageId: item.messageId },
|
|
370
|
+
...item.timestamp === void 0 ? {} : { timestamp: item.timestamp }
|
|
371
|
+
}))
|
|
372
|
+
}));
|
|
373
|
+
}
|
|
311
374
|
/** Close the socket and drop all state. Safe to call multiple times. */
|
|
312
375
|
stop() {
|
|
313
376
|
const socket = this.socket;
|
|
@@ -329,7 +392,7 @@ var WebSocketTransport = class {
|
|
|
329
392
|
sendBinaryFrame(topic, data, messageId, timestamp) {
|
|
330
393
|
if (messageId !== void 0 || timestamp !== void 0) {
|
|
331
394
|
this.sendFrame({
|
|
332
|
-
op:
|
|
395
|
+
op: WS_OP.PUBLISH,
|
|
333
396
|
topic,
|
|
334
397
|
data: Array.from(new Uint8Array(data)),
|
|
335
398
|
...messageId === void 0 ? {} : { messageId },
|
|
@@ -409,10 +472,13 @@ export {
|
|
|
409
472
|
DEFAULT_MAX_ACTIVE_WORKERS,
|
|
410
473
|
WebSocketTransport,
|
|
411
474
|
WorkerClusterRuntime,
|
|
475
|
+
approximatePayloadBytes,
|
|
412
476
|
createBrowserEnvironment,
|
|
413
477
|
createIndexedDbReplayPersistence,
|
|
414
478
|
createOpaqueKey,
|
|
479
|
+
createStorageEventChannel,
|
|
415
480
|
createWebSocketDataBus,
|
|
481
|
+
effectiveWorkerLoad,
|
|
416
482
|
getOrCreateTabId,
|
|
417
483
|
hasActiveOwner,
|
|
418
484
|
isWildcardTopic,
|