@sailfish-ai/recorder 1.12.5 → 1.12.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/canvas/adapters.js +382 -0
- package/dist/canvas/adapters.js.br +0 -0
- package/dist/canvas/adapters.js.gz +0 -0
- package/dist/canvas/canvasManager.js +1949 -0
- package/dist/canvas/canvasManager.js.br +0 -0
- package/dist/canvas/canvasManager.js.gz +0 -0
- package/dist/canvas/canvasPrivacy.js +233 -0
- package/dist/canvas/canvasPrivacy.js.br +0 -0
- package/dist/canvas/canvasPrivacy.js.gz +0 -0
- package/dist/canvas/codec.js +314 -0
- package/dist/canvas/codec.js.br +0 -0
- package/dist/canvas/codec.js.gz +0 -0
- package/dist/canvas/deviceClass.js +67 -0
- package/dist/canvas/deviceClass.js.br +0 -0
- package/dist/canvas/deviceClass.js.gz +0 -0
- package/dist/canvas/encodeWorker.js +284 -0
- package/dist/canvas/encodeWorker.js.br +0 -0
- package/dist/canvas/encodeWorker.js.gz +0 -0
- package/dist/canvas/governor.js +79 -0
- package/dist/canvas/governor.js.br +0 -0
- package/dist/canvas/governor.js.gz +0 -0
- package/dist/canvas/keyframes.js +183 -0
- package/dist/canvas/keyframes.js.br +0 -0
- package/dist/canvas/keyframes.js.gz +0 -0
- package/dist/canvas/mediaRecorderCapture.js +257 -0
- package/dist/canvas/mediaRecorderCapture.js.br +0 -0
- package/dist/canvas/mediaRecorderCapture.js.gz +0 -0
- package/dist/canvas/objectLog.js +150 -0
- package/dist/canvas/objectLog.js.br +0 -0
- package/dist/canvas/objectLog.js.gz +0 -0
- package/dist/canvas/patch2d.js +1302 -0
- package/dist/canvas/patch2d.js.br +0 -0
- package/dist/canvas/patch2d.js.gz +0 -0
- package/dist/canvas/patchGL.js +371 -0
- package/dist/canvas/patchGL.js.br +0 -0
- package/dist/canvas/patchGL.js.gz +0 -0
- package/dist/canvas/patchWebGPU.js +361 -0
- package/dist/canvas/patchWebGPU.js.br +0 -0
- package/dist/canvas/patchWebGPU.js.gz +0 -0
- package/dist/canvas/piiDetect.js +155 -0
- package/dist/canvas/piiDetect.js.br +0 -0
- package/dist/canvas/piiDetect.js.gz +0 -0
- package/dist/canvas/protocol.js +122 -0
- package/dist/canvas/protocol.js.br +0 -0
- package/dist/canvas/protocol.js.gz +0 -0
- package/dist/canvas/videoCapture.js +252 -0
- package/dist/canvas/videoCapture.js.br +0 -0
- package/dist/canvas/videoCapture.js.gz +0 -0
- package/dist/canvas/workerRelay.js +99 -0
- package/dist/canvas/workerRelay.js.br +0 -0
- package/dist/canvas/workerRelay.js.gz +0 -0
- package/dist/canvas/workerShim.js +227 -0
- package/dist/canvas/workerShim.js.br +0 -0
- package/dist/canvas/workerShim.js.gz +0 -0
- package/dist/canvas-worker.cjs +74 -0
- package/dist/canvas-worker.cjs.br +0 -0
- package/dist/canvas-worker.cjs.gz +0 -0
- package/dist/canvas-worker.js +78 -0
- package/dist/canvas-worker.js.br +0 -0
- package/dist/canvas-worker.js.gz +0 -0
- package/dist/canvasFrameStore.js +198 -0
- package/dist/canvasFrameStore.js.br +0 -0
- package/dist/canvasFrameStore.js.gz +0 -0
- package/dist/chunks/canvasManager-BYn3_oyo.js +1440 -0
- package/dist/chunks/canvasManager-BYn3_oyo.js.br +0 -0
- package/dist/chunks/canvasManager-BYn3_oyo.js.gz +0 -0
- package/dist/chunks/canvasManager-CoX5072G.js +1456 -0
- package/dist/chunks/canvasManager-CoX5072G.js.br +0 -0
- package/dist/chunks/canvasManager-CoX5072G.js.gz +0 -0
- package/dist/chunks/{chunkSerializer-Cd8y9tID.js → chunkSerializer-C_K0Wyk0.js} +1 -1
- package/dist/chunks/chunkSerializer-C_K0Wyk0.js.br +0 -0
- package/dist/chunks/chunkSerializer-C_K0Wyk0.js.gz +0 -0
- package/dist/chunks/{chunkSerializer-pkpgT-FH.js → chunkSerializer-CghPitF4.js} +1 -1
- package/dist/chunks/chunkSerializer-CghPitF4.js.br +0 -0
- package/dist/chunks/chunkSerializer-CghPitF4.js.gz +0 -0
- package/dist/chunks/{index-Bvd8oTpV.js → index-BIj4l3CV.js} +1025 -655
- package/dist/chunks/index-BIj4l3CV.js.br +0 -0
- package/dist/chunks/index-BIj4l3CV.js.gz +0 -0
- package/dist/chunks/{index-CXvHbLRT.js → index-DIYomvdD.js} +1115 -724
- package/dist/chunks/index-DIYomvdD.js.br +0 -0
- package/dist/chunks/index-DIYomvdD.js.gz +0 -0
- package/dist/chunks/patch2d-9voowhJ_.js +816 -0
- package/dist/chunks/patch2d-9voowhJ_.js.br +0 -0
- package/dist/chunks/patch2d-9voowhJ_.js.gz +0 -0
- package/dist/chunks/patch2d-PQxcaE6r.js +886 -0
- package/dist/chunks/patch2d-PQxcaE6r.js.br +0 -0
- package/dist/chunks/patch2d-PQxcaE6r.js.gz +0 -0
- package/dist/graphql.js +12 -1
- package/dist/graphql.js.br +0 -0
- package/dist/graphql.js.gz +0 -0
- package/dist/index.js +144 -2
- package/dist/index.js.br +0 -0
- package/dist/index.js.gz +0 -0
- package/dist/recorder.cjs +2 -2
- package/dist/recorder.cjs.br +0 -0
- package/dist/recorder.cjs.gz +0 -0
- package/dist/recorder.js +52 -41
- package/dist/recorder.js.br +0 -0
- package/dist/recorder.js.gz +0 -0
- package/dist/recorder.umd.cjs +4842 -2215
- package/dist/recorder.umd.cjs.br +0 -0
- package/dist/recorder.umd.cjs.gz +0 -0
- package/dist/recording.js +119 -10
- package/dist/recording.js.br +0 -0
- package/dist/recording.js.gz +0 -0
- package/dist/types/canvas/adapters.d.ts +71 -0
- package/dist/types/canvas/canvasManager.d.ts +273 -0
- package/dist/types/canvas/canvasPrivacy.d.ts +184 -0
- package/dist/types/canvas/codec.d.ts +27 -0
- package/dist/types/canvas/deviceClass.d.ts +40 -0
- package/dist/types/canvas/encodeWorker.d.ts +54 -0
- package/dist/types/canvas/governor.d.ts +44 -0
- package/dist/types/canvas/keyframes.d.ts +81 -0
- package/dist/types/canvas/mediaRecorderCapture.d.ts +91 -0
- package/dist/types/canvas/objectLog.d.ts +75 -0
- package/dist/types/canvas/patch2d.d.ts +339 -0
- package/dist/types/canvas/patchGL.d.ts +74 -0
- package/dist/types/canvas/patchWebGPU.d.ts +37 -0
- package/dist/types/canvas/piiDetect.d.ts +60 -0
- package/dist/types/canvas/protocol.d.ts +176 -0
- package/dist/types/canvas/videoCapture.d.ts +67 -0
- package/dist/types/canvas/workerRelay.d.ts +29 -0
- package/dist/types/canvas/workerShim.d.ts +10 -0
- package/dist/types/canvasFrameStore.d.ts +23 -0
- package/dist/types/graphql.d.ts +1 -1
- package/dist/types/index.d.ts +99 -1
- package/dist/types/types.d.ts +40 -0
- package/dist/types/websocket.d.ts +19 -0
- package/dist/websocket.js +210 -0
- package/dist/websocket.js.br +0 -0
- package/dist/websocket.js.gz +0 -0
- package/package.json +7 -1
- package/dist/chunks/chunkSerializer-Cd8y9tID.js.br +0 -0
- package/dist/chunks/chunkSerializer-Cd8y9tID.js.gz +0 -0
- package/dist/chunks/chunkSerializer-pkpgT-FH.js.br +0 -0
- package/dist/chunks/chunkSerializer-pkpgT-FH.js.gz +0 -0
- package/dist/chunks/index-Bvd8oTpV.js.br +0 -0
- package/dist/chunks/index-Bvd8oTpV.js.gz +0 -0
- package/dist/chunks/index-CXvHbLRT.js.br +0 -0
- package/dist/chunks/index-CXvHbLRT.js.gz +0 -0
package/dist/websocket.js
CHANGED
|
@@ -2,6 +2,7 @@ import ReconnectingWebSocket from "reconnecting-websocket";
|
|
|
2
2
|
import { buildEventTimeEnvelope, getClockSyncManager, monotonicNow, timeOriginMs, } from "./clockSync";
|
|
3
3
|
import { readDebugFlag } from "./env";
|
|
4
4
|
import { deleteEventsByIds, getAllIndexedEvents, saveEventsToIDB, } from "./eventStore";
|
|
5
|
+
import { deleteCanvasFramesByIds, persistCanvasFrame, readAllCanvasFrames, } from "./canvasFrameStore";
|
|
5
6
|
import { deleteNotifyMessageById, getAllNotifyMessages, saveNotifyMessageToIDB, } from "./notifyEventStore";
|
|
6
7
|
import { getOrSetSessionId } from "./session";
|
|
7
8
|
import { buildBatches, eventSize } from "./utils";
|
|
@@ -40,6 +41,18 @@ function drain() {
|
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
// Backpressure (A11): report the live socket buffer depth to the main thread on
|
|
45
|
+
// a light interval so canvas video capture can throttle frame production when a
|
|
46
|
+
// slow-but-open socket falls behind. Cheap (one number) and off the main thread.
|
|
47
|
+
var bufferedReportTimer = null;
|
|
48
|
+
function startBufferedReporting() {
|
|
49
|
+
if (bufferedReportTimer) return;
|
|
50
|
+
bufferedReportTimer = setInterval(function() {
|
|
51
|
+
var amt = (ws && ws.readyState === 1) ? (ws.bufferedAmount || 0) : 0;
|
|
52
|
+
postMessage({ type: "buffered", bufferedAmount: amt });
|
|
53
|
+
}, 250);
|
|
54
|
+
}
|
|
55
|
+
|
|
43
56
|
function connect() {
|
|
44
57
|
if (ws && (ws.readyState === 0 || ws.readyState === 1)) return;
|
|
45
58
|
try { ws = new WebSocket(wsUrl); } catch (e) { scheduleReconnect(); return; }
|
|
@@ -48,11 +61,14 @@ function connect() {
|
|
|
48
61
|
clearTimeout(tid);
|
|
49
62
|
reconnectDelay = 1000;
|
|
50
63
|
drain();
|
|
64
|
+
startBufferedReporting();
|
|
51
65
|
postMessage({ type: "open" });
|
|
52
66
|
};
|
|
53
67
|
ws.onclose = function() {
|
|
54
68
|
clearTimeout(tid);
|
|
55
69
|
ws = null;
|
|
70
|
+
if (bufferedReportTimer) { clearInterval(bufferedReportTimer); bufferedReportTimer = null; }
|
|
71
|
+
postMessage({ type: "buffered", bufferedAmount: 0 });
|
|
56
72
|
postMessage({ type: "close" });
|
|
57
73
|
scheduleReconnect();
|
|
58
74
|
};
|
|
@@ -86,6 +102,13 @@ self.onmessage = function(e) {
|
|
|
86
102
|
if (ws && ws.readyState === 1) {
|
|
87
103
|
try { ws.send(msg.payload); } catch (e) { enqueue(msg.payload); }
|
|
88
104
|
} else { enqueue(msg.payload); }
|
|
105
|
+
} else if (msg.type === "sendBinary") {
|
|
106
|
+
// Binary frames (canvas SFCV). The main thread only posts these while the
|
|
107
|
+
// socket is open; if it closed in the meantime the frame is dropped (the
|
|
108
|
+
// main-thread ring buffer covers the not-open case).
|
|
109
|
+
if (ws && ws.readyState === 1) {
|
|
110
|
+
try { ws.send(msg.payload); } catch (e) {}
|
|
111
|
+
}
|
|
89
112
|
} else if (msg.type === "close") {
|
|
90
113
|
if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
|
|
91
114
|
if (ws) { ws.close(); ws = null; }
|
|
@@ -94,9 +117,176 @@ self.onmessage = function(e) {
|
|
|
94
117
|
`;
|
|
95
118
|
let wsWorker = null;
|
|
96
119
|
let webSocket = null;
|
|
120
|
+
/** raw send on the direct (non-worker) socket — set in initializeWebSocket */
|
|
121
|
+
let directSend = null;
|
|
122
|
+
/** live socket buffer depth on the direct (non-worker) path */
|
|
123
|
+
let directBufferedAmount = null;
|
|
124
|
+
/** worker path: last reported socket buffer depth (worker posts on an interval) */
|
|
125
|
+
let _workerBufferedAmount = 0;
|
|
97
126
|
let isDraining = false;
|
|
98
127
|
let inFlightFlush = null;
|
|
99
128
|
let flushIntervalId = null;
|
|
129
|
+
// ─── Binary frame buffering (canvas SFCV frames) ─────────────────────────────
|
|
130
|
+
// While the socket is down, binary frames are held durably in IndexedDB
|
|
131
|
+
// (canvasFrameStore — survives reload, 64 MiB at-rest budget) and drained in
|
|
132
|
+
// capture order on reconnect. The 8 MiB in-memory ring below is the fallback
|
|
133
|
+
// for environments where IDB is unavailable (SSR/private mode/exotic runtimes)
|
|
134
|
+
// and for the rare frame whose async IDB write fails — there it keeps today's
|
|
135
|
+
// behavior (bounded heap, oldest-dropped). A frame lives in exactly ONE of the
|
|
136
|
+
// two (IDB on success, ring on failure), so reconnect can flush both without
|
|
137
|
+
// double-sending.
|
|
138
|
+
const BINARY_RING_MAX_BYTES = 8 * 1024 * 1024;
|
|
139
|
+
const _binaryRing = [];
|
|
140
|
+
let _binaryRingBytes = 0;
|
|
141
|
+
let _binaryDropCount = 0;
|
|
142
|
+
// True once any frame has been buffered offline — gates the periodic IDB
|
|
143
|
+
// backlog drain so the always-connected common case never touches IDB.
|
|
144
|
+
let _hadOfflineBinary = false;
|
|
145
|
+
function pushBinaryRing(buffer) {
|
|
146
|
+
_binaryRing.push(buffer);
|
|
147
|
+
_binaryRingBytes += buffer.byteLength;
|
|
148
|
+
while (_binaryRingBytes > BINARY_RING_MAX_BYTES && _binaryRing.length > 0) {
|
|
149
|
+
const dropped = _binaryRing.shift();
|
|
150
|
+
_binaryRingBytes -= dropped.byteLength;
|
|
151
|
+
_binaryDropCount++;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function flushBinaryRing() {
|
|
155
|
+
while (_binaryRing.length > 0 && isWebSocketOpen(webSocket)) {
|
|
156
|
+
const buffer = _binaryRing.shift();
|
|
157
|
+
_binaryRingBytes -= buffer.byteLength;
|
|
158
|
+
if (!_wsSendBinaryNow(buffer)) {
|
|
159
|
+
// failed — put it back at the front and stop
|
|
160
|
+
_binaryRing.unshift(buffer);
|
|
161
|
+
_binaryRingBytes += buffer.byteLength;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Drain the IDB-persisted binary backlog in capture order, deleting each frame
|
|
168
|
+
* only after it is handed to the socket. Stops at the first send failure so the
|
|
169
|
+
* remainder stays durable for the next reconnect. No-op (and cheap) when the
|
|
170
|
+
* store is empty or unavailable.
|
|
171
|
+
*/
|
|
172
|
+
async function flushPersistedBinary() {
|
|
173
|
+
if (!isWebSocketOpen(webSocket))
|
|
174
|
+
return;
|
|
175
|
+
const frames = await readAllCanvasFrames();
|
|
176
|
+
if (frames.length === 0)
|
|
177
|
+
return;
|
|
178
|
+
const sentIds = [];
|
|
179
|
+
for (const f of frames) {
|
|
180
|
+
if (!isWebSocketOpen(webSocket))
|
|
181
|
+
break;
|
|
182
|
+
if (!_wsSendBinaryNow(f.buf))
|
|
183
|
+
break; // stop; rest remain in IDB
|
|
184
|
+
if (typeof f.id === "number")
|
|
185
|
+
sentIds.push(f.id);
|
|
186
|
+
}
|
|
187
|
+
if (sentIds.length > 0)
|
|
188
|
+
void deleteCanvasFramesByIds(sentIds).catch(() => { });
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Reconnect/top-up drain of all offline binary frames. Flushes the in-memory
|
|
192
|
+
* ring (IDB-unavailable fallback frames) then the durable IDB backlog. Each
|
|
193
|
+
* frame is in exactly one place, so this never double-sends.
|
|
194
|
+
*/
|
|
195
|
+
async function flushBinaryBacklog() {
|
|
196
|
+
flushBinaryRing();
|
|
197
|
+
await flushPersistedBinary();
|
|
198
|
+
}
|
|
199
|
+
/** Count of binary frames dropped from the ring (diagnostics). */
|
|
200
|
+
export function getBinaryDropCount() {
|
|
201
|
+
return _binaryDropCount;
|
|
202
|
+
}
|
|
203
|
+
// ─── Transport backpressure (A11) ────────────────────────────────────────────
|
|
204
|
+
// The canvas video encoder can outpace a slow-but-open socket, growing
|
|
205
|
+
// WebSocket.bufferedAmount without bound (the data never lands and memory
|
|
206
|
+
// climbs). videoCapture polls isTransportSaturated() in afterRender and SKIPS
|
|
207
|
+
// producing a new VideoFrame while the socket is behind, resuming once it
|
|
208
|
+
// drains. This is best-effort throttling, never a hard block of the main thread.
|
|
209
|
+
/** ~16 MiB: above this the socket is treated as saturated and frame production
|
|
210
|
+
* pauses. Chosen above the 8 MiB max single frame so one large keyframe in
|
|
211
|
+
* flight does not by itself trip the gate. */
|
|
212
|
+
const TRANSPORT_SATURATION_BYTES = 16 * 1024 * 1024;
|
|
213
|
+
/**
|
|
214
|
+
* Current socket send-buffer depth in bytes (best effort). Worker path: the
|
|
215
|
+
* worker posts `bufferedAmount` on a light interval and we cache it. Direct
|
|
216
|
+
* path: read live. 0 when the socket is closed/unavailable.
|
|
217
|
+
*/
|
|
218
|
+
export function getBufferedAmount() {
|
|
219
|
+
if (wsWorker)
|
|
220
|
+
return _workerBufferedAmount;
|
|
221
|
+
if (directBufferedAmount && isWebSocketOpen(webSocket)) {
|
|
222
|
+
try {
|
|
223
|
+
return directBufferedAmount();
|
|
224
|
+
}
|
|
225
|
+
catch {
|
|
226
|
+
return 0;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return 0;
|
|
230
|
+
}
|
|
231
|
+
/** True when the socket's send buffer is over the saturation threshold —
|
|
232
|
+
* callers (canvas video capture) should pause producing new frames. */
|
|
233
|
+
export function isTransportSaturated() {
|
|
234
|
+
return getBufferedAmount() > TRANSPORT_SATURATION_BYTES;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Buffer a binary frame while offline: durable IDB first, falling back to the
|
|
238
|
+
* in-memory ring if the IDB write fails or IDB is unavailable. Sync-returning;
|
|
239
|
+
* the IDB write is awaited internally and routed to the ring on failure.
|
|
240
|
+
*/
|
|
241
|
+
function bufferBinaryOffline(buffer) {
|
|
242
|
+
_hadOfflineBinary = true;
|
|
243
|
+
persistCanvasFrame(buffer)
|
|
244
|
+
.then((ok) => {
|
|
245
|
+
if (!ok)
|
|
246
|
+
pushBinaryRing(buffer);
|
|
247
|
+
})
|
|
248
|
+
.catch(() => pushBinaryRing(buffer));
|
|
249
|
+
}
|
|
250
|
+
/** Direct/worker send of a binary frame; assumes the socket is open. */
|
|
251
|
+
function _wsSendBinaryNow(buffer) {
|
|
252
|
+
if (wsWorker) {
|
|
253
|
+
try {
|
|
254
|
+
wsWorker.postMessage({ type: "sendBinary", payload: buffer }, [buffer]);
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
if (directSend) {
|
|
263
|
+
directSend(buffer);
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
webSocket.send(buffer);
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Send a binary frame (canvas SFCV) over the recording WebSocket.
|
|
275
|
+
* Direct path: webSocket.send(ArrayBuffer); worker path: transferred
|
|
276
|
+
* postMessage. When the socket is not open, the frame is buffered durably in
|
|
277
|
+
* IndexedDB (surviving reload) with a memory-ring fallback, and flushed on
|
|
278
|
+
* reconnect.
|
|
279
|
+
*/
|
|
280
|
+
export function wsSendBinary(buffer) {
|
|
281
|
+
if (isDraining || !isWebSocketOpen(webSocket)) {
|
|
282
|
+
bufferBinaryOffline(buffer);
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
if (_wsSendBinaryNow(buffer))
|
|
286
|
+
return true;
|
|
287
|
+
bufferBinaryOffline(buffer);
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
100
290
|
// ─── Time sync state ─────────────────────────────────────────────────────────
|
|
101
291
|
// Periodic re-sync of the browser→server clock offset. The first burst
|
|
102
292
|
// happens in handleWsOpen so events flushed from IDB on reconnect get a
|
|
@@ -558,12 +748,19 @@ function handleWsOpen() {
|
|
|
558
748
|
finally {
|
|
559
749
|
isDraining = false; // resume live sends
|
|
560
750
|
}
|
|
751
|
+
// drain any binary frames (canvas SFCV) buffered while offline —
|
|
752
|
+
// memory-ring fallback then the durable IDB backlog (survives reload)
|
|
753
|
+
await flushBinaryBacklog();
|
|
561
754
|
// start periodic top-up flush after initial drain
|
|
562
755
|
if (flushIntervalId != null)
|
|
563
756
|
clearInterval(flushIntervalId);
|
|
564
757
|
flushIntervalId = window.setInterval(() => {
|
|
565
758
|
// fire-and-forget; single-flight guard prevents overlaps
|
|
566
759
|
void flushBufferedEvents();
|
|
760
|
+
// Top up any binary frames whose async IDB write landed after the
|
|
761
|
+
// reconnect drain. Gated so the always-connected case never hits IDB.
|
|
762
|
+
if (_hadOfflineBinary)
|
|
763
|
+
void flushBinaryBacklog();
|
|
567
764
|
}, 2000);
|
|
568
765
|
})();
|
|
569
766
|
// Seed the clock-offset estimate immediately so subsequent events get a
|
|
@@ -731,6 +928,9 @@ export function initializeWebSocket(backendApi, apiKey, sessionId, envValue, use
|
|
|
731
928
|
wsUrl += `&envValue=${encodeURIComponent(envValue)}`;
|
|
732
929
|
}
|
|
733
930
|
// ── Try Web Worker path (moves JSON.stringify + WS I/O off main thread) ──
|
|
931
|
+
directSend = null;
|
|
932
|
+
directBufferedAmount = null;
|
|
933
|
+
_workerBufferedAmount = 0;
|
|
734
934
|
wsWorker = useWsWorker ? tryCreateWsWorker() : null;
|
|
735
935
|
if (wsWorker) {
|
|
736
936
|
// Proxy object so callers can check .readyState (e.g. g.ws.readyState === 1)
|
|
@@ -757,11 +957,17 @@ export function initializeWebSocket(backendApi, apiKey, sessionId, envValue, use
|
|
|
757
957
|
}
|
|
758
958
|
else if (msg.type === "close") {
|
|
759
959
|
proxy.readyState = WebSocket.CLOSED;
|
|
960
|
+
_workerBufferedAmount = 0;
|
|
760
961
|
handleWsClose();
|
|
761
962
|
}
|
|
762
963
|
else if (msg.type === "message") {
|
|
763
964
|
handleWsMessage(msg.data);
|
|
764
965
|
}
|
|
966
|
+
else if (msg.type === "buffered") {
|
|
967
|
+
// A11 backpressure: cache the socket's send-buffer depth reported by
|
|
968
|
+
// the worker (off the main thread) for isTransportSaturated().
|
|
969
|
+
_workerBufferedAmount = typeof msg.bufferedAmount === "number" ? msg.bufferedAmount : 0;
|
|
970
|
+
}
|
|
765
971
|
};
|
|
766
972
|
wsWorker.onerror = () => {
|
|
767
973
|
// Worker crashed — fall through, events will buffer to IDB
|
|
@@ -782,6 +988,10 @@ export function initializeWebSocket(backendApi, apiKey, sessionId, envValue, use
|
|
|
782
988
|
connectionTimeout: 30000,
|
|
783
989
|
};
|
|
784
990
|
const directWs = new ReconnectingWebSocket(wsUrl, [], options);
|
|
991
|
+
directWs.binaryType = "arraybuffer";
|
|
992
|
+
directSend = (data) => directWs.send(data);
|
|
993
|
+
// A11 backpressure: expose the live socket send-buffer depth.
|
|
994
|
+
directBufferedAmount = () => directWs.bufferedAmount || 0;
|
|
785
995
|
const handle = {
|
|
786
996
|
get readyState() { return directWs.readyState; },
|
|
787
997
|
close: () => {
|
package/dist/websocket.js.br
CHANGED
|
Binary file
|
package/dist/websocket.js.gz
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sailfish-ai/recorder",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.6",
|
|
4
4
|
"publishPublicly": true,
|
|
5
5
|
"publishToCdn": {
|
|
6
6
|
"jsdelivr": true,
|
|
@@ -37,6 +37,12 @@
|
|
|
37
37
|
"require": "./dist/babel-plugin-sailfish-source.cjs",
|
|
38
38
|
"default": "./dist/babel-plugin-sailfish-source.js"
|
|
39
39
|
},
|
|
40
|
+
"./canvas-worker": {
|
|
41
|
+
"types": "./dist/types/canvas/workerShim.d.ts",
|
|
42
|
+
"import": "./dist/canvas-worker.js",
|
|
43
|
+
"require": "./dist/canvas-worker.cjs",
|
|
44
|
+
"default": "./dist/canvas-worker.js"
|
|
45
|
+
},
|
|
40
46
|
"./*": {
|
|
41
47
|
"types": "./dist/types/*.d.ts",
|
|
42
48
|
"import": "./dist/*.js",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|