@volter/tabnode 0.5.33 → 0.5.35
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 +11 -11
- package/dist/assets/{runtime-worker-b9-COQEP.js → runtime-worker-DEgP1CYS.js} +59 -0
- package/dist/index.mjs +71 -5
- package/dist/runtime.d.ts +2 -1
- package/dist/virtual-fs.d.ts +9 -0
- package/package.json +1 -1
- package/src/node-lib/binding/fs.ts +24 -0
- package/src/runtime.ts +2 -1
- package/src/virtual-fs.ts +42 -0
package/dist/__sw__.js
CHANGED
|
@@ -289,7 +289,7 @@ function handleMainMessage(host, event) {
|
|
|
289
289
|
/**
|
|
290
290
|
* Send request to main thread and wait for response
|
|
291
291
|
*/
|
|
292
|
-
async function sendRequest(host, port, method, url, headers, body) {
|
|
292
|
+
async function sendRequest(host, port, method, url, headers, body, destination = '') {
|
|
293
293
|
DEBUG && console.log('[SW] sendRequest called, host:', !!host, 'url:', url);
|
|
294
294
|
|
|
295
295
|
if (!host) {
|
|
@@ -312,7 +312,7 @@ async function sendRequest(host, port, method, url, headers, body) {
|
|
|
312
312
|
host.port.postMessage({
|
|
313
313
|
type: 'request',
|
|
314
314
|
id,
|
|
315
|
-
data: { port, method, url, headers, body },
|
|
315
|
+
data: { port, method, url, headers, body, destination },
|
|
316
316
|
});
|
|
317
317
|
});
|
|
318
318
|
}
|
|
@@ -321,7 +321,7 @@ async function sendRequest(host, port, method, url, headers, body) {
|
|
|
321
321
|
* Send streaming request to main thread
|
|
322
322
|
* Returns a ReadableStream that receives chunks from main thread
|
|
323
323
|
*/
|
|
324
|
-
async function sendStreamingRequest(host, port, method, url, headers, body) {
|
|
324
|
+
async function sendStreamingRequest(host, port, method, url, headers, body, destination = '') {
|
|
325
325
|
DEBUG && console.log('[SW] sendStreamingRequest called, url:', url);
|
|
326
326
|
|
|
327
327
|
if (!host) {
|
|
@@ -351,7 +351,7 @@ async function sendStreamingRequest(host, port, method, url, headers, body) {
|
|
|
351
351
|
host.port.postMessage({
|
|
352
352
|
type: 'request',
|
|
353
353
|
id,
|
|
354
|
-
data: { port, method, url, headers, body, streaming: true },
|
|
354
|
+
data: { port, method, url, headers, body, streaming: true, destination },
|
|
355
355
|
});
|
|
356
356
|
},
|
|
357
357
|
cancel() {
|
|
@@ -365,7 +365,7 @@ async function sendStreamingRequest(host, port, method, url, headers, body) {
|
|
|
365
365
|
// A Node HTTP producer must stop when its consumer stops reading and must
|
|
366
366
|
// observe disconnect. One pull credit bounds the service-worker response queue;
|
|
367
367
|
// this protocol requires a paired host bridge and is negotiated per port.
|
|
368
|
-
async function sendControlledRequest(host, port, method, url, headers, body, signal) {
|
|
368
|
+
async function sendControlledRequest(host, port, method, url, headers, body, signal, destination = '') {
|
|
369
369
|
if (!host) throw new Error('Service Worker not initialized');
|
|
370
370
|
if (signal.aborted) throw signal.reason;
|
|
371
371
|
const channel = host.port;
|
|
@@ -450,7 +450,7 @@ async function sendControlledRequest(host, port, method, url, headers, body, sig
|
|
|
450
450
|
signal.addEventListener('abort', abort, { once: true });
|
|
451
451
|
try {
|
|
452
452
|
channel.postMessage({ type: 'request', id,
|
|
453
|
-
data: { port, method, url, headers, body, streaming: true, flowControl: 1 } });
|
|
453
|
+
data: { port, method, url, headers, body, streaming: true, flowControl: 1, destination } });
|
|
454
454
|
if (signal.aborted) abort();
|
|
455
455
|
const head = await headersPromise;
|
|
456
456
|
const noBody = method === 'HEAD' || [204, 205, 304].includes(head.statusCode);
|
|
@@ -775,7 +775,7 @@ async function handleVirtualRequest(request, port, path, rooted = false) {
|
|
|
775
775
|
if (registration) {
|
|
776
776
|
if (host.flowControlledPorts.get(port) !== registration || host.port !== registration.channel || hosts.get(host.id) !== host)
|
|
777
777
|
throw new Error('Virtual server registration changed during upload');
|
|
778
|
-
return await sendControlledRequest(host, port, request.method, path, headers, body, request.signal);
|
|
778
|
+
return await sendControlledRequest(host, port, request.method, path, headers, body, request.signal, request.destination);
|
|
779
779
|
}
|
|
780
780
|
|
|
781
781
|
// Legacy peers retain their old selection until they negotiate flow control.
|
|
@@ -783,12 +783,12 @@ async function handleVirtualRequest(request, port, path, rooted = false) {
|
|
|
783
783
|
|
|
784
784
|
if (isStreamingCandidate) {
|
|
785
785
|
DEBUG && console.log('[SW] Using streaming mode for:', path);
|
|
786
|
-
return handleStreamingRequest(host, port, request.method, path, headers, body);
|
|
786
|
+
return handleStreamingRequest(host, port, request.method, path, headers, body, request.destination);
|
|
787
787
|
}
|
|
788
788
|
DEBUG && console.log('[SW] Using non-streaming mode for:', request.method, path);
|
|
789
789
|
|
|
790
790
|
// Send to main thread
|
|
791
|
-
const response = await sendRequest(host, port, request.method, path, headers, body);
|
|
791
|
+
const response = await sendRequest(host, port, request.method, path, headers, body, request.destination);
|
|
792
792
|
|
|
793
793
|
DEBUG && console.log('[SW] Got response from main thread:', {
|
|
794
794
|
statusCode: response.statusCode,
|
|
@@ -853,8 +853,8 @@ async function handleVirtualRequest(request, port, path, rooted = false) {
|
|
|
853
853
|
/**
|
|
854
854
|
* Handle a streaming request
|
|
855
855
|
*/
|
|
856
|
-
async function handleStreamingRequest(host, port, method, path, headers, body) {
|
|
857
|
-
const { stream, headersPromise, id } = await sendStreamingRequest(host, port, method, path, headers, body);
|
|
856
|
+
async function handleStreamingRequest(host, port, method, path, headers, body, destination = '') {
|
|
857
|
+
const { stream, headersPromise, id } = await sendStreamingRequest(host, port, method, path, headers, body, destination);
|
|
858
858
|
|
|
859
859
|
// Wait for headers to arrive
|
|
860
860
|
const responseData = await headersPromise;
|
|
@@ -8639,6 +8639,7 @@ function createFsBindings(Bytes = () => Buffer$9) {
|
|
|
8639
8639
|
// ---- writing ------------------------------------------------------------
|
|
8640
8640
|
writeBuffer(fd2, buffer2, offset2, length, position, req) {
|
|
8641
8641
|
return answer(req, () => {
|
|
8642
|
+
var _a3;
|
|
8642
8643
|
const stream = handleForFd(fd2);
|
|
8643
8644
|
if (stream instanceof LibuvStreamWrap) {
|
|
8644
8645
|
if (position !== null && position !== void 0 && position >= 0) throw createNodeError$1("ESPIPE", "write", String(fd2));
|
|
@@ -8651,6 +8652,23 @@ function createFsBindings(Bytes = () => Buffer$9) {
|
|
|
8651
8652
|
if ((file.flags & 3) === 0) throw createNodeError$1("EBADF", "write", file.path);
|
|
8652
8653
|
const tree2 = file.tree;
|
|
8653
8654
|
const slice = buffer2.subarray(offset2, offset2 + length);
|
|
8655
|
+
const held = ((_a3 = file.cached) == null ? void 0 : _a3.length) ?? (tree2.existsSync(file.path) ? tree2.statSync(file.path).size : 0);
|
|
8656
|
+
const end = (file.flags & flagBits().append) !== 0 ? held : position === null || position === void 0 || position < 0 ? file.position : position;
|
|
8657
|
+
if (end === held && typeof tree2.appendFileSync === "function") {
|
|
8658
|
+
tree2.appendFileSync(file.path, slice);
|
|
8659
|
+
if (file.cached !== void 0) {
|
|
8660
|
+
let room = file.room;
|
|
8661
|
+
if (!room || file.cached.buffer !== room.buffer || file.cached.byteOffset !== 0 || room.byteLength < held + slice.length) {
|
|
8662
|
+
room = new Uint8Array(Math.max(held + slice.length, held * 2, 4096));
|
|
8663
|
+
room.set(file.cached, 0);
|
|
8664
|
+
}
|
|
8665
|
+
room.set(slice, held);
|
|
8666
|
+
file.cached = room.subarray(0, held + slice.length);
|
|
8667
|
+
file.room = room;
|
|
8668
|
+
}
|
|
8669
|
+
if (position === null || position === void 0 || position < 0) file.position = end + slice.length;
|
|
8670
|
+
return slice.length;
|
|
8671
|
+
}
|
|
8654
8672
|
const existing = file.cached ?? (tree2.existsSync(file.path) ? tree2.readFileSync(file.path) : new Uint8Array(0));
|
|
8655
8673
|
const at3 = (file.flags & flagBits().append) !== 0 ? existing.length : position === null || position === void 0 || position < 0 ? file.position : position;
|
|
8656
8674
|
const size = Math.max(existing.length, at3 + slice.length);
|
|
@@ -31697,6 +31715,47 @@ class VirtualFS {
|
|
|
31697
31715
|
writeFileSync(path2, data2) {
|
|
31698
31716
|
this.writeFileSyncInternal(path2, data2, true);
|
|
31699
31717
|
}
|
|
31718
|
+
/**
|
|
31719
|
+
* Adds bytes at a file's end, creating it. A file grown a piece at a time
|
|
31720
|
+
* (a write stream's chunks) is kept in a buffer with room to grow, so an
|
|
31721
|
+
* append copies only what it adds: writing the whole file again for each
|
|
31722
|
+
* 1 KB chunk of a 50 MB file copied about a terabyte. A tree that keeps its
|
|
31723
|
+
* files elsewhere (its own writeFileSync) is appended to through its own
|
|
31724
|
+
* read and write unless it answers appends itself.
|
|
31725
|
+
*/
|
|
31726
|
+
appendFileSync(path2, data2) {
|
|
31727
|
+
var _a3;
|
|
31728
|
+
const bytes2 = typeof data2 === "string" ? this.encoder.encode(data2) : data2;
|
|
31729
|
+
if (this.writeFileSync !== VirtualFS.prototype.writeFileSync) {
|
|
31730
|
+
const existing = this.existsSync(path2) ? this.readFileSync(path2) : new Uint8Array(0);
|
|
31731
|
+
const whole = new Uint8Array(existing.byteLength + bytes2.byteLength);
|
|
31732
|
+
whole.set(existing, 0);
|
|
31733
|
+
whole.set(bytes2, existing.byteLength);
|
|
31734
|
+
this.writeFileSync(path2, whole);
|
|
31735
|
+
return;
|
|
31736
|
+
}
|
|
31737
|
+
const normalized = this.normalizePath(path2);
|
|
31738
|
+
const node = this.getNode(normalized);
|
|
31739
|
+
if (!node) {
|
|
31740
|
+
this.writeFileSyncInternal(normalized, bytes2.slice(), true);
|
|
31741
|
+
return;
|
|
31742
|
+
}
|
|
31743
|
+
if (node.type !== "file") throw createNodeError("EISDIR", "open", path2);
|
|
31744
|
+
this.assertWritable(normalized, "open");
|
|
31745
|
+
const current3 = node.content ?? new Uint8Array(0);
|
|
31746
|
+
const length = current3.byteLength + bytes2.byteLength;
|
|
31747
|
+
let room = node.room;
|
|
31748
|
+
if (!room || current3.buffer !== room.buffer || current3.byteOffset !== 0 || room.byteLength < length) {
|
|
31749
|
+
room = new Uint8Array(Math.max(length, current3.byteLength * 2, 4096));
|
|
31750
|
+
room.set(current3, 0);
|
|
31751
|
+
}
|
|
31752
|
+
room.set(bytes2, current3.byteLength);
|
|
31753
|
+
node.content = room.subarray(0, length);
|
|
31754
|
+
node.room = room;
|
|
31755
|
+
node.mtime = Date.now();
|
|
31756
|
+
this.notifyWatchers(normalized, "change");
|
|
31757
|
+
if ((_a3 = this.eventListeners.get("change")) == null ? void 0 : _a3.size) this.emit("change", normalized, this.decoder.decode(node.content));
|
|
31758
|
+
}
|
|
31700
31759
|
/**
|
|
31701
31760
|
* Create directory, optionally with recursive parent creation
|
|
31702
31761
|
*/
|
package/dist/index.mjs
CHANGED
|
@@ -8767,6 +8767,7 @@ function createFsBindings(Bytes = () => Buffer$9) {
|
|
|
8767
8767
|
// ---- writing ------------------------------------------------------------
|
|
8768
8768
|
writeBuffer(fd, buffer2, offset2, length, position, req) {
|
|
8769
8769
|
return answer(req, () => {
|
|
8770
|
+
var _a2;
|
|
8770
8771
|
const stream = handleForFd(fd);
|
|
8771
8772
|
if (stream instanceof LibuvStreamWrap) {
|
|
8772
8773
|
if (position !== null && position !== void 0 && position >= 0) throw createNodeError$1("ESPIPE", "write", String(fd));
|
|
@@ -8779,6 +8780,23 @@ function createFsBindings(Bytes = () => Buffer$9) {
|
|
|
8779
8780
|
if ((file.flags & 3) === 0) throw createNodeError$1("EBADF", "write", file.path);
|
|
8780
8781
|
const tree2 = file.tree;
|
|
8781
8782
|
const slice = buffer2.subarray(offset2, offset2 + length);
|
|
8783
|
+
const held = ((_a2 = file.cached) == null ? void 0 : _a2.length) ?? (tree2.existsSync(file.path) ? tree2.statSync(file.path).size : 0);
|
|
8784
|
+
const end = (file.flags & flagBits().append) !== 0 ? held : position === null || position === void 0 || position < 0 ? file.position : position;
|
|
8785
|
+
if (end === held && typeof tree2.appendFileSync === "function") {
|
|
8786
|
+
tree2.appendFileSync(file.path, slice);
|
|
8787
|
+
if (file.cached !== void 0) {
|
|
8788
|
+
let room = file.room;
|
|
8789
|
+
if (!room || file.cached.buffer !== room.buffer || file.cached.byteOffset !== 0 || room.byteLength < held + slice.length) {
|
|
8790
|
+
room = new Uint8Array(Math.max(held + slice.length, held * 2, 4096));
|
|
8791
|
+
room.set(file.cached, 0);
|
|
8792
|
+
}
|
|
8793
|
+
room.set(slice, held);
|
|
8794
|
+
file.cached = room.subarray(0, held + slice.length);
|
|
8795
|
+
file.room = room;
|
|
8796
|
+
}
|
|
8797
|
+
if (position === null || position === void 0 || position < 0) file.position = end + slice.length;
|
|
8798
|
+
return slice.length;
|
|
8799
|
+
}
|
|
8782
8800
|
const existing = file.cached ?? (tree2.existsSync(file.path) ? tree2.readFileSync(file.path) : new Uint8Array(0));
|
|
8783
8801
|
const at2 = (file.flags & flagBits().append) !== 0 ? existing.length : position === null || position === void 0 || position < 0 ? file.position : position;
|
|
8784
8802
|
const size = Math.max(existing.length, at2 + slice.length);
|
|
@@ -21284,10 +21302,17 @@ var implementation$1 = function bind2(that) {
|
|
|
21284
21302
|
var implementation = implementation$1;
|
|
21285
21303
|
var functionBind = Function.prototype.bind || implementation;
|
|
21286
21304
|
var functionCall = Function.prototype.call;
|
|
21287
|
-
var functionApply
|
|
21305
|
+
var functionApply;
|
|
21306
|
+
var hasRequiredFunctionApply;
|
|
21307
|
+
function requireFunctionApply() {
|
|
21308
|
+
if (hasRequiredFunctionApply) return functionApply;
|
|
21309
|
+
hasRequiredFunctionApply = 1;
|
|
21310
|
+
functionApply = Function.prototype.apply;
|
|
21311
|
+
return functionApply;
|
|
21312
|
+
}
|
|
21288
21313
|
var reflectApply = typeof Reflect !== "undefined" && Reflect && Reflect.apply;
|
|
21289
21314
|
var bind$2 = functionBind;
|
|
21290
|
-
var $apply$1 =
|
|
21315
|
+
var $apply$1 = requireFunctionApply();
|
|
21291
21316
|
var $call$2 = functionCall;
|
|
21292
21317
|
var $reflectApply = reflectApply;
|
|
21293
21318
|
var actualApply = $reflectApply || bind$2.call($call$2, $apply$1);
|
|
@@ -21407,7 +21432,7 @@ var hasSymbols = requireHasSymbols()();
|
|
|
21407
21432
|
var getProto = requireGetProto();
|
|
21408
21433
|
var $ObjectGPO = requireObject_getPrototypeOf();
|
|
21409
21434
|
var $ReflectGPO = requireReflect_getPrototypeOf();
|
|
21410
|
-
var $apply =
|
|
21435
|
+
var $apply = requireFunctionApply();
|
|
21411
21436
|
var $call = functionCall;
|
|
21412
21437
|
var needsEval = {};
|
|
21413
21438
|
var TypedArray = typeof Uint8Array === "undefined" || !getProto ? undefined$1 : getProto(Uint8Array);
|
|
@@ -22048,7 +22073,7 @@ function requireApplyBind() {
|
|
|
22048
22073
|
if (hasRequiredApplyBind) return applyBind;
|
|
22049
22074
|
hasRequiredApplyBind = 1;
|
|
22050
22075
|
var bind3 = functionBind;
|
|
22051
|
-
var $apply2 =
|
|
22076
|
+
var $apply2 = requireFunctionApply();
|
|
22052
22077
|
var actualApply$1 = actualApply;
|
|
22053
22078
|
applyBind = function applyBind2() {
|
|
22054
22079
|
return actualApply$1(bind3, $apply2, arguments);
|
|
@@ -31844,6 +31869,47 @@ class VirtualFS {
|
|
|
31844
31869
|
writeFileSync(path2, data2) {
|
|
31845
31870
|
this.writeFileSyncInternal(path2, data2, true);
|
|
31846
31871
|
}
|
|
31872
|
+
/**
|
|
31873
|
+
* Adds bytes at a file's end, creating it. A file grown a piece at a time
|
|
31874
|
+
* (a write stream's chunks) is kept in a buffer with room to grow, so an
|
|
31875
|
+
* append copies only what it adds: writing the whole file again for each
|
|
31876
|
+
* 1 KB chunk of a 50 MB file copied about a terabyte. A tree that keeps its
|
|
31877
|
+
* files elsewhere (its own writeFileSync) is appended to through its own
|
|
31878
|
+
* read and write unless it answers appends itself.
|
|
31879
|
+
*/
|
|
31880
|
+
appendFileSync(path2, data2) {
|
|
31881
|
+
var _a2;
|
|
31882
|
+
const bytes2 = typeof data2 === "string" ? this.encoder.encode(data2) : data2;
|
|
31883
|
+
if (this.writeFileSync !== VirtualFS.prototype.writeFileSync) {
|
|
31884
|
+
const existing = this.existsSync(path2) ? this.readFileSync(path2) : new Uint8Array(0);
|
|
31885
|
+
const whole = new Uint8Array(existing.byteLength + bytes2.byteLength);
|
|
31886
|
+
whole.set(existing, 0);
|
|
31887
|
+
whole.set(bytes2, existing.byteLength);
|
|
31888
|
+
this.writeFileSync(path2, whole);
|
|
31889
|
+
return;
|
|
31890
|
+
}
|
|
31891
|
+
const normalized = this.normalizePath(path2);
|
|
31892
|
+
const node = this.getNode(normalized);
|
|
31893
|
+
if (!node) {
|
|
31894
|
+
this.writeFileSyncInternal(normalized, bytes2.slice(), true);
|
|
31895
|
+
return;
|
|
31896
|
+
}
|
|
31897
|
+
if (node.type !== "file") throw createNodeError("EISDIR", "open", path2);
|
|
31898
|
+
this.assertWritable(normalized, "open");
|
|
31899
|
+
const current3 = node.content ?? new Uint8Array(0);
|
|
31900
|
+
const length = current3.byteLength + bytes2.byteLength;
|
|
31901
|
+
let room = node.room;
|
|
31902
|
+
if (!room || current3.buffer !== room.buffer || current3.byteOffset !== 0 || room.byteLength < length) {
|
|
31903
|
+
room = new Uint8Array(Math.max(length, current3.byteLength * 2, 4096));
|
|
31904
|
+
room.set(current3, 0);
|
|
31905
|
+
}
|
|
31906
|
+
room.set(bytes2, current3.byteLength);
|
|
31907
|
+
node.content = room.subarray(0, length);
|
|
31908
|
+
node.room = room;
|
|
31909
|
+
node.mtime = Date.now();
|
|
31910
|
+
this.notifyWatchers(normalized, "change");
|
|
31911
|
+
if ((_a2 = this.eventListeners.get("change")) == null ? void 0 : _a2.size) this.emit("change", normalized, this.decoder.decode(node.content));
|
|
31912
|
+
}
|
|
31847
31913
|
/**
|
|
31848
31914
|
* Create directory, optionally with recursive parent creation
|
|
31849
31915
|
*/
|
|
@@ -40227,7 +40293,7 @@ class WorkerRuntime {
|
|
|
40227
40293
|
this.worker = new Worker(
|
|
40228
40294
|
new URL(
|
|
40229
40295
|
/* @vite-ignore */
|
|
40230
|
-
"/assets/runtime-worker-
|
|
40296
|
+
"/assets/runtime-worker-DEgP1CYS.js",
|
|
40231
40297
|
import.meta.url
|
|
40232
40298
|
),
|
|
40233
40299
|
{ type: "module" }
|
package/dist/runtime.d.ts
CHANGED
|
@@ -14,7 +14,8 @@ export { pendingGuestTimers, stopGuestTimers } from './guest-timers';
|
|
|
14
14
|
* playwright-core's, measured in a tab, against 0.9 s under Node on the same
|
|
15
15
|
* machine. The image carries each body under the hash of the file it was made
|
|
16
16
|
* from, in this directory of the tab's filesystem, and the loader takes it in
|
|
17
|
-
* place of the passes when the file it read hashes to one.
|
|
17
|
+
* place of the passes when the file it read hashes to one. A body the loader
|
|
18
|
+
* prepares for a file the image has none for is kept there the same way.
|
|
18
19
|
*/
|
|
19
20
|
export declare const PREPARED_MODULES_DIR = "/.tabnode/prepared";
|
|
20
21
|
/** The name a prepared body goes under: the hash of the file as read, and how it is compiled. Undefined for a file no body is prepared for. */
|
package/dist/virtual-fs.d.ts
CHANGED
|
@@ -195,6 +195,15 @@ export declare class VirtualFS {
|
|
|
195
195
|
* Write data to file, creating parent directories as needed
|
|
196
196
|
*/
|
|
197
197
|
writeFileSync(path: string, data: string | Uint8Array): void;
|
|
198
|
+
/**
|
|
199
|
+
* Adds bytes at a file's end, creating it. A file grown a piece at a time
|
|
200
|
+
* (a write stream's chunks) is kept in a buffer with room to grow, so an
|
|
201
|
+
* append copies only what it adds: writing the whole file again for each
|
|
202
|
+
* 1 KB chunk of a 50 MB file copied about a terabyte. A tree that keeps its
|
|
203
|
+
* files elsewhere (its own writeFileSync) is appended to through its own
|
|
204
|
+
* read and write unless it answers appends itself.
|
|
205
|
+
*/
|
|
206
|
+
appendFileSync(path: string, data: string | Uint8Array): void;
|
|
198
207
|
/**
|
|
199
208
|
* Create directory, optionally with recursive parent creation
|
|
200
209
|
*/
|
package/package.json
CHANGED
|
@@ -157,6 +157,8 @@ interface OpenFile {
|
|
|
157
157
|
* it could send ready.
|
|
158
158
|
*/
|
|
159
159
|
cached?: Uint8Array;
|
|
160
|
+
/** The buffer `cached` views when writes have grown it a piece at a time. */
|
|
161
|
+
room?: Uint8Array;
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
/** Every descriptor this engine has open, and the next number to hand out. */
|
|
@@ -606,6 +608,28 @@ const fsBinding = {
|
|
|
606
608
|
if ((file.flags & 3) === 0) throw createNodeError('EBADF', 'write', file.path);
|
|
607
609
|
const tree = file.tree;
|
|
608
610
|
const slice = buffer.subarray(offset, offset + length);
|
|
611
|
+
// A write at the file's end is an append: the tree is given only the
|
|
612
|
+
// bytes it adds, and this descriptor's copy grows in a buffer with room.
|
|
613
|
+
// Writing the whole file again for each chunk made a 50 MB stream of
|
|
614
|
+
// 1 KB writes copy about a terabyte.
|
|
615
|
+
const held = file.cached?.length ?? (tree.existsSync(file.path) ? tree.statSync(file.path).size : 0);
|
|
616
|
+
const end = (file.flags & flagBits().append) !== 0 ? held
|
|
617
|
+
: position === null || position === undefined || position < 0 ? file.position : position;
|
|
618
|
+
if (end === held && typeof (tree as { appendFileSync?: unknown }).appendFileSync === 'function') {
|
|
619
|
+
(tree as { appendFileSync(path: string, data: Uint8Array): void }).appendFileSync(file.path, slice);
|
|
620
|
+
if (file.cached !== undefined) {
|
|
621
|
+
let room = file.room;
|
|
622
|
+
if (!room || file.cached.buffer !== room.buffer || file.cached.byteOffset !== 0 || room.byteLength < held + slice.length) {
|
|
623
|
+
room = new Uint8Array(Math.max(held + slice.length, held * 2, 4096));
|
|
624
|
+
room.set(file.cached, 0);
|
|
625
|
+
}
|
|
626
|
+
room.set(slice, held);
|
|
627
|
+
file.cached = room.subarray(0, held + slice.length);
|
|
628
|
+
file.room = room;
|
|
629
|
+
}
|
|
630
|
+
if (position === null || position === undefined || position < 0) file.position = end + slice.length;
|
|
631
|
+
return slice.length;
|
|
632
|
+
}
|
|
609
633
|
const existing = file.cached ?? (tree.existsSync(file.path) ? tree.readFileSync(file.path) as Uint8Array : new Uint8Array(0));
|
|
610
634
|
const at = (file.flags & flagBits().append) !== 0 ? existing.length
|
|
611
635
|
: position === null || position === undefined || position < 0 ? file.position : position;
|
package/src/runtime.ts
CHANGED
|
@@ -587,7 +587,8 @@ function __substratePrepareBody(rawCode: string, resolvedPath: string, format: s
|
|
|
587
587
|
* playwright-core's, measured in a tab, against 0.9 s under Node on the same
|
|
588
588
|
* machine. The image carries each body under the hash of the file it was made
|
|
589
589
|
* from, in this directory of the tab's filesystem, and the loader takes it in
|
|
590
|
-
* place of the passes when the file it read hashes to one.
|
|
590
|
+
* place of the passes when the file it read hashes to one. A body the loader
|
|
591
|
+
* prepares for a file the image has none for is kept there the same way.
|
|
591
592
|
*/
|
|
592
593
|
export const PREPARED_MODULES_DIR = '/.tabnode/prepared';
|
|
593
594
|
const PREPARED_MODULES_FORMAT = 'tabnode-prepared-2';
|
package/src/virtual-fs.ts
CHANGED
|
@@ -656,6 +656,48 @@ export class VirtualFS {
|
|
|
656
656
|
this.writeFileSyncInternal(path, data, true);
|
|
657
657
|
}
|
|
658
658
|
|
|
659
|
+
/**
|
|
660
|
+
* Adds bytes at a file's end, creating it. A file grown a piece at a time
|
|
661
|
+
* (a write stream's chunks) is kept in a buffer with room to grow, so an
|
|
662
|
+
* append copies only what it adds: writing the whole file again for each
|
|
663
|
+
* 1 KB chunk of a 50 MB file copied about a terabyte. A tree that keeps its
|
|
664
|
+
* files elsewhere (its own writeFileSync) is appended to through its own
|
|
665
|
+
* read and write unless it answers appends itself.
|
|
666
|
+
*/
|
|
667
|
+
appendFileSync(path: string, data: string | Uint8Array): void {
|
|
668
|
+
const bytes = typeof data === 'string' ? this.encoder.encode(data) : data;
|
|
669
|
+
if (this.writeFileSync !== VirtualFS.prototype.writeFileSync) {
|
|
670
|
+
const existing = this.existsSync(path) ? this.readFileSync(path) as Uint8Array : new Uint8Array(0);
|
|
671
|
+
const whole = new Uint8Array(existing.byteLength + bytes.byteLength);
|
|
672
|
+
whole.set(existing, 0);
|
|
673
|
+
whole.set(bytes, existing.byteLength);
|
|
674
|
+
this.writeFileSync(path, whole);
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
const normalized = this.normalizePath(path);
|
|
678
|
+
const node = this.getNode(normalized);
|
|
679
|
+
if (!node) {
|
|
680
|
+
this.writeFileSyncInternal(normalized, bytes.slice(), true);
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
if (node.type !== 'file') throw createNodeError('EISDIR', 'open', path);
|
|
684
|
+
this.assertWritable(normalized, 'open');
|
|
685
|
+
const current = node.content ?? new Uint8Array(0);
|
|
686
|
+
const length = current.byteLength + bytes.byteLength;
|
|
687
|
+
let room = (node as FSNode & { room?: Uint8Array }).room;
|
|
688
|
+
if (!room || current.buffer !== room.buffer || current.byteOffset !== 0 || room.byteLength < length) {
|
|
689
|
+
room = new Uint8Array(Math.max(length, current.byteLength * 2, 4096));
|
|
690
|
+
room.set(current, 0);
|
|
691
|
+
}
|
|
692
|
+
room.set(bytes, current.byteLength);
|
|
693
|
+
node.content = room.subarray(0, length);
|
|
694
|
+
(node as FSNode & { room?: Uint8Array }).room = room;
|
|
695
|
+
node.mtime = Date.now();
|
|
696
|
+
this.notifyWatchers(normalized, 'change');
|
|
697
|
+
// The change event carries the file's text; it is made only for a listener.
|
|
698
|
+
if (this.eventListeners.get('change')?.size) this.emit('change', normalized, this.decoder.decode(node.content));
|
|
699
|
+
}
|
|
700
|
+
|
|
659
701
|
/**
|
|
660
702
|
* Create directory, optionally with recursive parent creation
|
|
661
703
|
*/
|