@volter/tabnode 0.5.50 → 0.5.51

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/dist/__sw__.js CHANGED
@@ -99,6 +99,16 @@ let requestId = 0;
99
99
  const controlledUploads = new Set();
100
100
  const MAX_STREAM_CHUNK_BYTES = 65536;
101
101
 
102
+ // A response chunk as the host sent it: its bytes, transferred, from a bridge this worker told it
103
+ // takes them (`sw-capabilities`), or base64 from one that predates that. Base64 cost the page's
104
+ // own thread an encode of every byte a virtual server sent (5.4 s of 46 while a 307 MB document
105
+ // crossed, measured in the hosted model editor) and left a third more garbage than the bytes.
106
+ function chunkBytes(data) {
107
+ if (data?.chunk instanceof Uint8Array) return data.chunk;
108
+ if (typeof data?.chunkBase64 === 'string') return base64ToBytes(data.chunkBase64);
109
+ return null;
110
+ }
111
+
102
112
  function updateFlowControl(host, type, data) {
103
113
  if (type === 'server-registered' || type === 'server-unregistered') {
104
114
  for (const upload of controlledUploads) {
@@ -157,6 +167,7 @@ self.addEventListener('message', (event) => {
157
167
  mainPort.onmessage = (message) => {
158
168
  if (hosts.get(host.id) === host && host.port === initializedPort) handleMainMessage(host, message);
159
169
  };
170
+ mainPort.postMessage({ type: 'sw-capabilities', data: { binaryChunks: 1 } });
160
171
  if (data && Array.isArray(data.ownDocuments)) host.ownDocuments = new Set(data.ownDocuments.map((path) => ownPath(String(path))));
161
172
  // Markup a frame's document served from this host's servers starts with
162
173
  // (after its doctype): the page's first script, before the document's own.
@@ -257,9 +268,8 @@ function handleMainMessage(host, event) {
257
268
  const pending = pendingRequests.get(id);
258
269
  if (pending && pending.streamController) {
259
270
  try {
260
- // Decode base64 chunk and enqueue
261
- if (data.chunkBase64) {
262
- const bytes = base64ToBytes(data.chunkBase64);
271
+ const bytes = chunkBytes(data);
272
+ if (bytes && bytes.byteLength > 0) {
263
273
  pending.streamController.enqueue(bytes);
264
274
  DEBUG && console.log('[SW] chunk enqueued, bytes:', bytes.length);
265
275
  }
@@ -428,10 +438,11 @@ async function sendControlledRequest(host, port, method, url, headers, body, sig
428
438
  clearTimeout(headerTimeout);
429
439
  resolveHeaders(data);
430
440
  } else if (type === 'stream-chunk' && headed && credited) {
431
- if (typeof data?.chunkBase64 !== 'string'
432
- || data.chunkBase64.length > Math.ceil(MAX_STREAM_CHUNK_BYTES / 3) * 4)
441
+ if (typeof data?.chunkBase64 === 'string'
442
+ && data.chunkBase64.length > Math.ceil(MAX_STREAM_CHUNK_BYTES / 3) * 4)
433
443
  throw new Error('Stream chunk exceeds transport limit');
434
- const bytes = base64ToBytes(data.chunkBase64);
444
+ const bytes = chunkBytes(data);
445
+ if (!bytes) throw new Error('Stream chunk carries no bytes');
435
446
  if (bytes.byteLength > MAX_STREAM_CHUNK_BYTES)
436
447
  throw new Error('Stream chunk exceeds transport limit');
437
448
  credited = false;
package/dist/index.mjs CHANGED
@@ -18,8 +18,8 @@ var __privateWrapper = (obj, member, setter, getter) => ({
18
18
  }
19
19
  });
20
20
  var _a, _b, _asyncId, _triggerAsyncId, _c, _d, _e, _f, _g, _h, _i, _j, _ptr, _type, _maxHeaderSize, _headerBytes, _headers, _field, _value, _readingValue, _url, _statusMessage, _headersSent, _paused, _buffer, _bufferPtr, _bufferSize, _connections, _HTTPParser_instances, reset_fn, copyIn_fn, pushHeader_fn, countHeaderBytes_fn, _parsers, _strm, _writeState, _callback, _level, _strategy, _windowBits, _memLevel, _dictionary, _ended, _Zlib_instances, inflating_get, windowFor_fn, start_fn, fail_fn, report_fn, run_fn, end_fn, _writeState2, _callback2, _input, _output, _outputAt, _BrotliDecoderHandle_instances, run_fn2, _k, _resolveChain, _loadChain, _initializing, _initializeFailure, _RunModuleHooks_instances, run_fn3;
21
- import { u as uint8ToBase64, b as base64ToUint8, a as uint8ToBinaryString, c as uint8ToHex, P as PortBridge } from "./port-bridge-CixAESwA.js";
22
- import { g } from "./port-bridge-CixAESwA.js";
21
+ import { u as uint8ToBase64, b as base64ToUint8, a as uint8ToBinaryString, c as uint8ToHex, P as PortBridge } from "./port-bridge-Cergvxli.js";
22
+ import { g } from "./port-bridge-Cergvxli.js";
23
23
  import { defineCommand, Bash, getCommandNames } from "just-bash";
24
24
  import { imports, resolve as resolve$3 } from "resolve.exports";
25
25
  import { wrap, proxy } from "comlink";
@@ -100,6 +100,11 @@ const _PortBridge = class _PortBridge extends BridgeEvents {
100
100
  /** The server the service worker answers at the origin's root, the preview's; null for none. */
101
101
  __publicField(this, "primaryPort", null);
102
102
  __publicField(this, "ownDocuments");
103
+ /**
104
+ * Handle messages from Service Worker
105
+ */
106
+ /** The channels whose worker takes a response chunk as transferred bytes (`sw-capabilities`). */
107
+ __publicField(this, "binaryChunkPorts", /* @__PURE__ */ new WeakSet());
103
108
  /** Flow-controlled requests in flight: a pull is one chunk's credit, a cancel ends the upstream. */
104
109
  __publicField(this, "controlledStreams", /* @__PURE__ */ new Map());
105
110
  this.options = options;
@@ -275,12 +280,20 @@ const _PortBridge = class _PortBridge extends BridgeEvents {
275
280
  this.announceServers();
276
281
  this.emit("sw-ready");
277
282
  }
278
- /**
279
- * Handle messages from Service Worker
280
- */
283
+ /** One response chunk on `port`: its bytes transferred where the worker said it takes them,
284
+ * base64 to a worker that predates that. `bytes` must be the chunk's own buffer. */
285
+ postChunk(port, id, bytes) {
286
+ if (!port) return;
287
+ if (this.binaryChunkPorts.has(port)) port.postMessage({ type: "stream-chunk", id, data: { chunk: bytes } }, [bytes.buffer]);
288
+ else port.postMessage({ type: "stream-chunk", id, data: { chunkBase64: uint8ToBase64(bytes) } });
289
+ }
281
290
  async handleServiceWorkerMessage(event) {
282
291
  var _a, _b, _c;
283
292
  const { type, id, data } = event.data;
293
+ if (type === "sw-capabilities") {
294
+ if ((data == null ? void 0 : data.binaryChunks) === 1 && event.target instanceof MessagePort) this.binaryChunkPorts.add(event.target);
295
+ return;
296
+ }
284
297
  _PortBridge.DEBUG && console.log("[ServerBridge] SW message:", type, id, data == null ? void 0 : data.url);
285
298
  if (type === "stream-pull" || type === "stream-cancel") {
286
299
  const stream = this.controlledStreams.get(id);
@@ -445,14 +458,9 @@ const _PortBridge = class _PortBridge extends BridgeEvents {
445
458
  // onChunk - called for each chunk
446
459
  (chunk) => {
447
460
  var _a2;
448
- const bytes = typeof chunk === "string" ? _encoder.encode(chunk) : chunk;
449
- const chunkBase64 = uint8ToBase64(bytes);
450
- _PortBridge.DEBUG && console.log("[ServerBridge] 🟡 onChunk called, sending stream-chunk, size:", chunkBase64.length);
451
- (_a2 = this.messageChannel) == null ? void 0 : _a2.port1.postMessage({
452
- type: "stream-chunk",
453
- id,
454
- data: { chunkBase64 }
455
- });
461
+ const bytes = typeof chunk === "string" ? _encoder.encode(chunk) : ownedBytes(chunk);
462
+ _PortBridge.DEBUG && console.log("[ServerBridge] 🟡 onChunk called, sending stream-chunk, size:", bytes.byteLength);
463
+ this.postChunk((_a2 = this.messageChannel) == null ? void 0 : _a2.port1, id, bytes);
456
464
  },
457
465
  // onEnd - called when response is complete
458
466
  () => {
@@ -474,12 +482,8 @@ const _PortBridge = class _PortBridge extends BridgeEvents {
474
482
  }
475
483
  });
476
484
  if (response.body && response.body.length > 0) {
477
- const bytes = response.body instanceof Uint8Array ? response.body : new Uint8Array(0);
478
- (_d = this.messageChannel) == null ? void 0 : _d.port1.postMessage({
479
- type: "stream-chunk",
480
- id,
481
- data: { chunkBase64: uint8ToBase64(bytes) }
482
- });
485
+ const bytes = response.body instanceof Uint8Array ? ownedBytes(response.body) : new Uint8Array(0);
486
+ this.postChunk((_d = this.messageChannel) == null ? void 0 : _d.port1, id, bytes);
483
487
  }
484
488
  (_e = this.messageChannel) == null ? void 0 : _e.port1.postMessage({ type: "stream-end", id });
485
489
  }
@@ -521,7 +525,7 @@ const _PortBridge = class _PortBridge extends BridgeEvents {
521
525
  if (finished) return;
522
526
  while (credits > 0 && queue.length > 0) {
523
527
  credits -= 1;
524
- post("stream-chunk", { chunkBase64: uint8ToBase64(queue.shift()) });
528
+ this.postChunk(channel == null ? void 0 : channel.port1, id, queue.shift());
525
529
  }
526
530
  if (upstreamEnded && queue.length === 0) {
527
531
  post("stream-end");
@@ -122,6 +122,11 @@ export declare class PortBridge extends BridgeEvents {
122
122
  /**
123
123
  * Handle messages from Service Worker
124
124
  */
125
+ /** The channels whose worker takes a response chunk as transferred bytes (`sw-capabilities`). */
126
+ private readonly binaryChunkPorts;
127
+ /** One response chunk on `port`: its bytes transferred where the worker said it takes them,
128
+ * base64 to a worker that predates that. `bytes` must be the chunk's own buffer. */
129
+ private postChunk;
125
130
  private handleServiceWorkerMessage;
126
131
  /**
127
132
  * Handle a streaming request - sends chunks as they arrive
@@ -1,4 +1,4 @@
1
- import { P, g, o } from "./port-bridge-CixAESwA.js";
1
+ import { P, g, o } from "./port-bridge-Cergvxli.js";
2
2
  export {
3
3
  P as PortBridge,
4
4
  g as getPortBridge,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/tabnode",
3
- "version": "0.5.50",
3
+ "version": "0.5.51",
4
4
  "description": "Node's own library, in a browser tab.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -378,8 +378,23 @@ export class PortBridge extends BridgeEvents {
378
378
  /**
379
379
  * Handle messages from Service Worker
380
380
  */
381
+ /** The channels whose worker takes a response chunk as transferred bytes (`sw-capabilities`). */
382
+ private readonly binaryChunkPorts = new WeakSet<MessagePort>();
383
+
384
+ /** One response chunk on `port`: its bytes transferred where the worker said it takes them,
385
+ * base64 to a worker that predates that. `bytes` must be the chunk's own buffer. */
386
+ private postChunk(port: MessagePort | undefined, id: number, bytes: Uint8Array): void {
387
+ if (!port) return;
388
+ if (this.binaryChunkPorts.has(port)) port.postMessage({ type: 'stream-chunk', id, data: { chunk: bytes } }, [bytes.buffer]);
389
+ else port.postMessage({ type: 'stream-chunk', id, data: { chunkBase64: uint8ToBase64(bytes) } });
390
+ }
391
+
381
392
  private async handleServiceWorkerMessage(event: MessageEvent): Promise<void> {
382
393
  const { type, id, data } = event.data;
394
+ if (type === 'sw-capabilities') {
395
+ if (data?.binaryChunks === 1 && event.target instanceof MessagePort) this.binaryChunkPorts.add(event.target);
396
+ return;
397
+ }
383
398
 
384
399
  PortBridge.DEBUG && console.log('[ServerBridge] SW message:', type, id, data?.url);
385
400
 
@@ -578,14 +593,9 @@ export class PortBridge extends BridgeEvents {
578
593
  },
579
594
  // onChunk - called for each chunk
580
595
  (chunk: string | Uint8Array) => {
581
- const bytes = typeof chunk === 'string' ? _encoder.encode(chunk) : chunk;
582
- const chunkBase64 = uint8ToBase64(bytes);
583
- PortBridge.DEBUG && console.log('[ServerBridge] 🟡 onChunk called, sending stream-chunk, size:', chunkBase64.length);
584
- this.messageChannel?.port1.postMessage({
585
- type: 'stream-chunk',
586
- id,
587
- data: { chunkBase64 },
588
- });
596
+ const bytes = typeof chunk === 'string' ? _encoder.encode(chunk) : ownedBytes(chunk);
597
+ PortBridge.DEBUG && console.log('[ServerBridge] 🟡 onChunk called, sending stream-chunk, size:', bytes.byteLength);
598
+ this.postChunk(this.messageChannel?.port1, id, bytes);
589
599
  },
590
600
  // onEnd - called when response is complete
591
601
  () => {
@@ -610,12 +620,8 @@ export class PortBridge extends BridgeEvents {
610
620
  });
611
621
 
612
622
  if (response.body && response.body.length > 0) {
613
- const bytes = response.body instanceof Uint8Array ? response.body : new Uint8Array(0);
614
- this.messageChannel?.port1.postMessage({
615
- type: 'stream-chunk',
616
- id,
617
- data: { chunkBase64: uint8ToBase64(bytes) },
618
- });
623
+ const bytes = response.body instanceof Uint8Array ? ownedBytes(response.body) : new Uint8Array(0);
624
+ this.postChunk(this.messageChannel?.port1, id, bytes);
619
625
  }
620
626
 
621
627
  this.messageChannel?.port1.postMessage({ type: 'stream-end', id });
@@ -664,7 +670,7 @@ export class PortBridge extends BridgeEvents {
664
670
  if (finished) return;
665
671
  while (credits > 0 && queue.length > 0) {
666
672
  credits -= 1;
667
- post('stream-chunk', { chunkBase64: uint8ToBase64(queue.shift()!) });
673
+ this.postChunk(channel?.port1, id, queue.shift()!);
668
674
  }
669
675
  if (upstreamEnded && queue.length === 0) { post('stream-end'); finish(); return; }
670
676
  // a few chunks may wait for credit; more than that, and the server waits