@volter/tabnode 0.5.29 → 0.5.30

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
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Service Worker for Mini WebContainers
3
3
  * Intercepts fetch requests and routes them to virtual servers
4
- * Version: 16 - a host per page: each page's channel, servers and preview are its own
4
+ * Version: 17 - a host's document prelude: its frames' documents start with it
5
5
  */
6
6
 
7
7
  const DEBUG = false;
@@ -158,6 +158,9 @@ self.addEventListener('message', (event) => {
158
158
  if (hosts.get(host.id) === host && host.port === initializedPort) handleMainMessage(host, message);
159
159
  };
160
160
  if (data && Array.isArray(data.ownDocuments)) host.ownDocuments = new Set(data.ownDocuments.map((path) => ownPath(String(path))));
161
+ // Markup a frame's document served from this host's servers starts with
162
+ // (after its doctype): the page's first script, before the document's own.
163
+ host.documentPrelude = data && typeof data.documentPrelude === 'string' && data.documentPrelude ? data.documentPrelude : null;
161
164
  DEBUG && console.log('[SW] Initialized communication channel with transferred port');
162
165
  // Re-claim clients so that pages opened after SW activation get controlled.
163
166
  // Without this, controllerchange never fires for late-arriving pages.
@@ -664,7 +667,7 @@ self.addEventListener('fetch', (event) => {
664
667
  const targetPath = url.pathname + url.search;
665
668
  if (context.prefix === null) {
666
669
  DEBUG && console.log('[SW] Answering a root request from the virtual server:', url.pathname);
667
- return handleRootedRequest(event, context.port, targetPath);
670
+ return withDocumentPrelude(event, await handleRootedRequest(event, context.port, targetPath));
668
671
  }
669
672
  if (event.request.mode === 'navigate') {
670
673
  DEBUG && console.log('[SW] Redirecting navigation from virtual context:', url.pathname);
@@ -683,9 +686,54 @@ self.addEventListener('fetch', (event) => {
683
686
  const port = parseInt(match[1], 10);
684
687
  const path = match[2] || '/';
685
688
 
686
- event.respondWith(handleVirtualRequest(event.request, port, path + url.search));
689
+ event.respondWith(handleVirtualRequest(event.request, port, path + url.search).then((response) => withDocumentPrelude(event, response)));
687
690
  });
688
691
 
692
+ /**
693
+ * A frame's HTML document from a host's servers, with the host's prelude
694
+ * first: after a leading doctype (so the document keeps its mode), else at
695
+ * the very start, where the parser puts a script into the head it makes.
696
+ */
697
+ async function withDocumentPrelude(event, response) {
698
+ const request = event.request;
699
+ if (request.mode !== 'navigate' || (request.destination !== 'iframe' && request.destination !== 'frame')) return response;
700
+ if (!response.body || !/text\/html/i.test(response.headers.get('content-type') || '')) return response;
701
+ let host = null;
702
+ try { host = await hostForEvent(event); } catch (e) { /* no host */ }
703
+ const prelude = host && host.documentPrelude;
704
+ if (!prelude) return response;
705
+ const encoder = new TextEncoder();
706
+ const inserted = encoder.encode(prelude);
707
+ let pending = new Uint8Array(0);
708
+ let done = false;
709
+ const release = (controller, cut) => {
710
+ controller.enqueue(pending.subarray(0, cut));
711
+ controller.enqueue(inserted);
712
+ controller.enqueue(pending.subarray(cut));
713
+ pending = new Uint8Array(0);
714
+ done = true;
715
+ };
716
+ const body = response.body.pipeThrough(new TransformStream({
717
+ transform(chunk, controller) {
718
+ if (done) { controller.enqueue(chunk); return; }
719
+ const joined = new Uint8Array(pending.length + chunk.length);
720
+ joined.set(pending); joined.set(chunk, pending.length);
721
+ pending = joined;
722
+ const head = new TextDecoder().decode(pending.subarray(0, 2048));
723
+ const doctype = /^\uFEFF?\s*<!doctype[^>]*>/i.exec(head);
724
+ if (doctype) { release(controller, encoder.encode(doctype[0]).length); return; }
725
+ // A doctype still arriving waits for its end; anything else is no doctype.
726
+ const start = head.replace(/^\uFEFF?\s*/, '');
727
+ if (pending.length < 2048 && ('<!doctype'.startsWith(start.toLowerCase()) || /^<!doctype/i.test(start))) return;
728
+ release(controller, 0);
729
+ },
730
+ flush(controller) { if (!done) release(controller, 0); },
731
+ }));
732
+ const headers = new Headers(response.headers);
733
+ headers.delete('content-length');
734
+ return new Response(body, { status: response.status, statusText: response.statusText, headers });
735
+ }
736
+
689
737
  /**
690
738
  * Handle a request to a virtual server
691
739
  */
package/dist/index.mjs CHANGED
@@ -21288,17 +21288,10 @@ var implementation$1 = function bind2(that) {
21288
21288
  var implementation = implementation$1;
21289
21289
  var functionBind = Function.prototype.bind || implementation;
21290
21290
  var functionCall = Function.prototype.call;
21291
- var functionApply;
21292
- var hasRequiredFunctionApply;
21293
- function requireFunctionApply() {
21294
- if (hasRequiredFunctionApply) return functionApply;
21295
- hasRequiredFunctionApply = 1;
21296
- functionApply = Function.prototype.apply;
21297
- return functionApply;
21298
- }
21291
+ var functionApply = Function.prototype.apply;
21299
21292
  var reflectApply = typeof Reflect !== "undefined" && Reflect && Reflect.apply;
21300
21293
  var bind$2 = functionBind;
21301
- var $apply$1 = requireFunctionApply();
21294
+ var $apply$1 = functionApply;
21302
21295
  var $call$2 = functionCall;
21303
21296
  var $reflectApply = reflectApply;
21304
21297
  var actualApply = $reflectApply || bind$2.call($call$2, $apply$1);
@@ -21418,7 +21411,7 @@ var hasSymbols = requireHasSymbols()();
21418
21411
  var getProto = requireGetProto();
21419
21412
  var $ObjectGPO = requireObject_getPrototypeOf();
21420
21413
  var $ReflectGPO = requireReflect_getPrototypeOf();
21421
- var $apply = requireFunctionApply();
21414
+ var $apply = functionApply;
21422
21415
  var $call = functionCall;
21423
21416
  var needsEval = {};
21424
21417
  var TypedArray = typeof Uint8Array === "undefined" || !getProto ? undefined$1 : getProto(Uint8Array);
@@ -22059,7 +22052,7 @@ function requireApplyBind() {
22059
22052
  if (hasRequiredApplyBind) return applyBind;
22060
22053
  hasRequiredApplyBind = 1;
22061
22054
  var bind3 = functionBind;
22062
- var $apply2 = requireFunctionApply();
22055
+ var $apply2 = functionApply;
22063
22056
  var actualApply$1 = actualApply;
22064
22057
  applyBind = function applyBind2() {
22065
22058
  return actualApply$1(bind3, $apply2, arguments);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/tabnode",
3
- "version": "0.5.29",
3
+ "version": "0.5.30",
4
4
  "description": "Node's own library, in a browser tab.",
5
5
  "type": "module",
6
6
  "license": "MIT",