@volter/tabnode 0.5.16 → 0.5.17
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/assets/{runtime-worker-Bw8vbYik.js → runtime-worker-DCIwIWHJ.js} +3764 -251
- package/dist/code-transforms.d.ts +2 -1
- package/dist/index.mjs +3764 -244
- package/dist/node-lib/binding/zlib.d.ts +14 -1
- package/dist/shims/perf_hooks.d.ts +0 -4
- package/dist/shims/tls.d.ts +3 -1
- package/dist/shims/worker_threads.d.ts +4 -0
- package/package.json +1 -1
- package/src/code-transforms.ts +28 -13
- package/src/node-lib/binding/zlib.ts +80 -3
- package/src/node-lib/internals/runtime.ts +6 -2
- package/src/runtime.ts +59 -4
- package/src/shims/child_process.ts +26 -6
- package/src/shims/esbuild.ts +12 -1
- package/src/shims/perf_hooks.ts +18 -0
- package/src/shims/string_decoder.ts +5 -0
- package/src/shims/tls.ts +13 -1
- package/src/shims/worker_threads.ts +19 -0
|
@@ -25,10 +25,23 @@ export declare class Zlib {
|
|
|
25
25
|
/** Node asks a handle for these two after a `Z_STREAM_END`. */
|
|
26
26
|
get ended(): boolean;
|
|
27
27
|
}
|
|
28
|
+
declare class BrotliDecoderHandle {
|
|
29
|
+
#private;
|
|
30
|
+
readonly mode: number;
|
|
31
|
+
onerror: ((message: string, errno: number, code?: string) => void) | null;
|
|
32
|
+
constructor(mode: number);
|
|
33
|
+
init(_params: Uint32Array, writeState: Uint32Array, processCallback: ProcessCallback): boolean;
|
|
34
|
+
write(flush: number, inBuf: Uint8Array | null, inOff: number, inLen: number, outBuf: Uint8Array, outOff: number, outLen: number): this;
|
|
35
|
+
writeSync(flush: number, inBuf: Uint8Array | null, inOff: number, inLen: number, outBuf: Uint8Array, outOff: number, outLen: number): this;
|
|
36
|
+
params(): void;
|
|
37
|
+
reset(): void;
|
|
38
|
+
close(): void;
|
|
39
|
+
getAvailableOutput(): number;
|
|
40
|
+
}
|
|
28
41
|
export declare const zlibBinding: {
|
|
29
42
|
Zlib: typeof Zlib;
|
|
30
43
|
BrotliEncoder: new (...args: unknown[]) => never;
|
|
31
|
-
BrotliDecoder:
|
|
44
|
+
BrotliDecoder: typeof BrotliDecoderHandle;
|
|
32
45
|
ZstdCompress: new (...args: unknown[]) => never;
|
|
33
46
|
ZstdDecompress: new (...args: unknown[]) => never;
|
|
34
47
|
/** `zlib.crc32`, which is zlib's own table-driven one. */
|
package/dist/shims/tls.d.ts
CHANGED
|
@@ -291,6 +291,7 @@ export declare function createTlsModule(require?: (name: string) => any): {
|
|
|
291
291
|
};
|
|
292
292
|
createSecureContext: (_options?: unknown) => {};
|
|
293
293
|
getCiphers: () => string[];
|
|
294
|
+
getCACertificates: (type?: string) => string[];
|
|
294
295
|
DEFAULT_ECDH_CURVE: string;
|
|
295
296
|
DEFAULT_MAX_VERSION: string;
|
|
296
297
|
DEFAULT_MIN_VERSION: string;
|
|
@@ -583,6 +584,7 @@ declare const tls: {
|
|
|
583
584
|
};
|
|
584
585
|
createSecureContext: (_options?: unknown) => {};
|
|
585
586
|
getCiphers: () => string[];
|
|
587
|
+
getCACertificates: (type?: string) => string[];
|
|
586
588
|
DEFAULT_ECDH_CURVE: string;
|
|
587
589
|
DEFAULT_MAX_VERSION: string;
|
|
588
590
|
DEFAULT_MIN_VERSION: string;
|
|
@@ -868,7 +870,7 @@ export declare const TLSSocket: {
|
|
|
868
870
|
write(chunk: unknown, encoding?: unknown, callback?: unknown): boolean;
|
|
869
871
|
end(chunk?: unknown, encoding?: unknown, callback?: unknown): /*elided*/ any;
|
|
870
872
|
writable: boolean;
|
|
871
|
-
}, createSecureContext: (_options?: unknown) => {}, getCiphers: () => string[], DEFAULT_ECDH_CURVE: string, DEFAULT_MAX_VERSION: string, DEFAULT_MIN_VERSION: string, rootCertificates: string[];
|
|
873
|
+
}, createSecureContext: (_options?: unknown) => {}, getCiphers: () => string[], getCACertificates: (type?: string) => string[], DEFAULT_ECDH_CURVE: string, DEFAULT_MAX_VERSION: string, DEFAULT_MIN_VERSION: string, rootCertificates: string[];
|
|
872
874
|
export type TLSSocket = InstanceType<typeof TLSSocket>;
|
|
873
875
|
export type Server = InstanceType<typeof Server>;
|
|
874
876
|
export default tls;
|
|
@@ -44,6 +44,8 @@ export declare function receiveMessageOnPort(port: MessagePort): {
|
|
|
44
44
|
} | undefined;
|
|
45
45
|
export declare const SHARE_ENV: unique symbol;
|
|
46
46
|
export declare function markAsUntransferable(object: unknown): void;
|
|
47
|
+
export declare function markAsUncloneable(object: unknown): void;
|
|
48
|
+
export declare function isMarkedAsUncloneable(object: unknown): boolean;
|
|
47
49
|
export declare function getEnvironmentData(key: unknown): unknown;
|
|
48
50
|
export declare function setEnvironmentData(key: unknown, value: unknown): void;
|
|
49
51
|
declare const _default: {
|
|
@@ -59,6 +61,8 @@ declare const _default: {
|
|
|
59
61
|
receiveMessageOnPort: typeof receiveMessageOnPort;
|
|
60
62
|
SHARE_ENV: symbol;
|
|
61
63
|
markAsUntransferable: typeof markAsUntransferable;
|
|
64
|
+
markAsUncloneable: typeof markAsUncloneable;
|
|
65
|
+
isMarkedAsUncloneable: typeof isMarkedAsUncloneable;
|
|
62
66
|
getEnvironmentData: typeof getEnvironmentData;
|
|
63
67
|
setEnvironmentData: typeof setEnvironmentData;
|
|
64
68
|
};
|
package/package.json
CHANGED
package/src/code-transforms.ts
CHANGED
|
@@ -26,6 +26,14 @@ let __nodeLowering = false;
|
|
|
26
26
|
const __cjsExports = () => __nodeLowering ? "$exports" : "exports";
|
|
27
27
|
const __cjsModule = () => __nodeLowering ? "$module" : "module";
|
|
28
28
|
const __cjsRequire = () => __nodeLowering ? "$require" : "require";
|
|
29
|
+
// The realm's own `Object` and `Symbol`, by names a module cannot declare over.
|
|
30
|
+
// Lowered code calls them before the module's own body has run -- its exports
|
|
31
|
+
// are defined at the top -- and a module that imports a binding called `Object`
|
|
32
|
+
// (typebox does, its object type) had the lowering's `Object.defineProperty`
|
|
33
|
+
// read that import in its dead zone. The dev server's lowering of a browser
|
|
34
|
+
// module keeps the plain names, which exist where that module runs.
|
|
35
|
+
const __cjsObject = () => __nodeLowering ? "__browserRuntimeObject" : "Object";
|
|
36
|
+
const __cjsSymbol = () => __nodeLowering ? "__browserRuntimeSymbol" : "Symbol";
|
|
29
37
|
const __cjsDefault = (expression: string) => __nodeLowering ? "__browserRuntimeInteropDefault(" + expression + ")" : expression;
|
|
30
38
|
// The helper lowered code calls by bare name. It is a name on the realm, so
|
|
31
39
|
// it goes up when a guest first exists, not when this module is loaded.
|
|
@@ -33,8 +41,12 @@ forGuestRealm(() => {
|
|
|
33
41
|
if ((globalThis as Record<string, unknown>).__browserRuntimeInteropDefault) return;
|
|
34
42
|
takeFromHost(globalThis, '__browserRuntimeInteropDefault', (imported: any) => imported && imported.__esModule && "default" in imported ? imported.default : imported);
|
|
35
43
|
});
|
|
44
|
+
forGuestRealm(() => {
|
|
45
|
+
if (!(globalThis as Record<string, unknown>).__browserRuntimeObject) takeFromHost(globalThis, '__browserRuntimeObject', Object);
|
|
46
|
+
if (!(globalThis as Record<string, unknown>).__browserRuntimeSymbol) takeFromHost(globalThis, '__browserRuntimeSymbol', Symbol);
|
|
47
|
+
});
|
|
36
48
|
export const setNodeLowering = (value: boolean): void => { __nodeLowering = value; };
|
|
37
|
-
export { __cjsExports };
|
|
49
|
+
export { __cjsExports, __cjsObject };
|
|
38
50
|
|
|
39
51
|
/**
|
|
40
52
|
* Whether a module is ESM is a fact of its syntax, not of its text. Asking
|
|
@@ -175,7 +187,7 @@ function __substrateLiveImportBindings(code: any) {
|
|
|
175
187
|
// or in what it imports; an importer waits for it, as a module graph
|
|
176
188
|
// evaluates in order. The marker becomes `await` when the loader runs
|
|
177
189
|
// this body as an async function, and reads nothing otherwise.
|
|
178
|
-
parts.push("/*__substrate_await__*/(" + namespace + " && " + namespace + "[
|
|
190
|
+
parts.push("/*__substrate_await__*/(" + namespace + " && " + namespace + "[" + __cjsSymbol() + ".for(\"substrate.pending\")]);");
|
|
179
191
|
}
|
|
180
192
|
for (const imported of declaration.specifiers) {
|
|
181
193
|
const read = imported.type === "ImportDefaultSpecifier" ? __cjsDefault(namespace)
|
|
@@ -210,7 +222,10 @@ function __substrateLiveImportBindings(code: any) {
|
|
|
210
222
|
if (typeof node.type !== "string") return;
|
|
211
223
|
switch (node.type) {
|
|
212
224
|
case "ImportDeclaration": case "ImportSpecifier": case "ImportDefaultSpecifier":
|
|
213
|
-
|
|
225
|
+
// `export * as X from "…"` holds a name and a source, no reference: an
|
|
226
|
+
// imported binding also called X was rewritten into the exported name,
|
|
227
|
+
// and typebox's `export * as Guard` became `__substrateImport1`.
|
|
228
|
+
case "ImportNamespaceSpecifier": case "ExportSpecifier": case "ExportAllDeclaration": case "MetaProperty":
|
|
214
229
|
case "BreakStatement": case "ContinueStatement": case "PrivateIdentifier":
|
|
215
230
|
return;
|
|
216
231
|
case "Identifier":
|
|
@@ -368,7 +383,7 @@ function transformEsmToCjsAst(code: string): string {
|
|
|
368
383
|
// for any import (the marker becomes `await` in an async body).
|
|
369
384
|
sideEffectImports += 1;
|
|
370
385
|
const namespace = `__substrateImportSide${sideEffectImports}`;
|
|
371
|
-
replacements.push([node.start, node.end, `const ${namespace} = ${__cjsRequire()}(${JSON.stringify(source)}); /*__substrate_await__*/(${namespace} && ${namespace}[
|
|
386
|
+
replacements.push([node.start, node.end, `const ${namespace} = ${__cjsRequire()}(${JSON.stringify(source)}); /*__substrate_await__*/(${namespace} && ${namespace}[${__cjsSymbol()}.for("substrate.pending")]);`]);
|
|
372
387
|
} else {
|
|
373
388
|
const defaultSpec = specs.find((s: any) => s.type === 'ImportDefaultSpecifier');
|
|
374
389
|
const nsSpec = specs.find((s: any) => s.type === 'ImportNamespaceSpecifier');
|
|
@@ -404,7 +419,7 @@ function transformEsmToCjsAst(code: string): string {
|
|
|
404
419
|
// `module.exports = X`, which threw away every named export defined
|
|
405
420
|
// before it (readdirp exports `readdirp` by name and as the default;
|
|
406
421
|
// chokidar imports the name and found the module was the function).
|
|
407
|
-
const defineDefault = (value: string): string =>
|
|
422
|
+
const defineDefault = (value: string): string => `${__cjsObject()}.defineProperty(${__cjsExports()}, "default", { enumerable: true, configurable: true, get: function () { return ${value}; } });`;
|
|
408
423
|
if (decl.type === 'FunctionDeclaration') {
|
|
409
424
|
const funcCode = code.slice(decl.start, node.end);
|
|
410
425
|
replacements.push([node.start, node.end, decl.id ? `${funcCode}\n${defineDefault(decl.id.name)}` : `${defineDefault(`(${funcCode})`)}`]);
|
|
@@ -423,11 +438,11 @@ function transformEsmToCjsAst(code: string): string {
|
|
|
423
438
|
const name = decl.id.name;
|
|
424
439
|
const funcCode = code.slice(decl.start, node.end);
|
|
425
440
|
replacements.push([node.start, node.end, funcCode]);
|
|
426
|
-
hoisted.push(
|
|
441
|
+
hoisted.push(`${__cjsObject()}.defineProperty(${__cjsExports()}, "${name}", { enumerable: true, get: function () { return ${name}; } });`);
|
|
427
442
|
} else if (decl.type === 'ClassDeclaration') {
|
|
428
443
|
const name = decl.id.name;
|
|
429
444
|
const classCode = code.slice(decl.start, node.end);
|
|
430
|
-
replacements.push([node.start, node.end, `${classCode}\
|
|
445
|
+
replacements.push([node.start, node.end, `${classCode}\n${__cjsObject()}.defineProperty(${__cjsExports()}, "${name}", { enumerable: true, get: function () { return ${name}; } });`]);
|
|
431
446
|
} else if (decl.type === 'VariableDeclaration') {
|
|
432
447
|
// The declaration stays as written, so the module keeps a binding of
|
|
433
448
|
// its own; what follows is an export that reads that binding when
|
|
@@ -446,7 +461,7 @@ function transformEsmToCjsAst(code: string): string {
|
|
|
446
461
|
else if (pattern.type === 'RestElement') collect(pattern.argument);
|
|
447
462
|
};
|
|
448
463
|
for (const declarator of decl.declarations) collect(declarator.id);
|
|
449
|
-
for (const name of names) parts.push(
|
|
464
|
+
for (const name of names) parts.push(`${__cjsObject()}.defineProperty(${__cjsExports()}, "${name}", { enumerable: true, get: function () { return ${name}; } });`);
|
|
450
465
|
replacements.push([node.start, node.end, parts.join('\n')]);
|
|
451
466
|
}
|
|
452
467
|
} else if (node.source) {
|
|
@@ -462,9 +477,9 @@ function transformEsmToCjsAst(code: string): string {
|
|
|
462
477
|
const tmpVar = `__reexport_${node.start}`;
|
|
463
478
|
parts.push(`const ${tmpVar} = ${__cjsRequire()}(${JSON.stringify(source)})`);
|
|
464
479
|
// The re-exported module may still be settling; wait for it as for an import.
|
|
465
|
-
parts.push(`/*__substrate_await__*/(${tmpVar} && ${tmpVar}[
|
|
480
|
+
parts.push(`/*__substrate_await__*/(${tmpVar} && ${tmpVar}[${__cjsSymbol()}.for("substrate.pending")])`);
|
|
466
481
|
for (const spec of node.specifiers) {
|
|
467
|
-
parts.push(
|
|
482
|
+
parts.push(`${__cjsObject()}.defineProperty(${__cjsExports()}, "${spec.exported.name}", { enumerable: true, configurable: true, get: function () { return ${tmpVar}.${spec.local.name}; } })`);
|
|
468
483
|
}
|
|
469
484
|
replacements.push([node.start, node.end, parts.join(';\n')]);
|
|
470
485
|
} else {
|
|
@@ -472,7 +487,7 @@ function transformEsmToCjsAst(code: string): string {
|
|
|
472
487
|
// an explicit export that replaces a star's getter of the same name.
|
|
473
488
|
const parts: string[] = [];
|
|
474
489
|
for (const spec of node.specifiers) {
|
|
475
|
-
parts.push(
|
|
490
|
+
parts.push(`${__cjsObject()}.defineProperty(${__cjsExports()}, "${spec.exported.name}", { enumerable: true, configurable: true, get: function () { return ${spec.local.name}; } })`);
|
|
476
491
|
}
|
|
477
492
|
replacements.push([node.start, node.end, parts.join(';\n')]);
|
|
478
493
|
}
|
|
@@ -485,7 +500,7 @@ function transformEsmToCjsAst(code: string): string {
|
|
|
485
500
|
const source = node.source.value;
|
|
486
501
|
const name = node.exported.type === 'Identifier' ? node.exported.name : node.exported.value;
|
|
487
502
|
const tmpVar = `__reexport_${node.start}`;
|
|
488
|
-
replacements.push([node.start, node.end, `const ${tmpVar} = ${__cjsRequire()}(${JSON.stringify(source)}); /*__substrate_await__*/(${tmpVar} && ${tmpVar}[
|
|
503
|
+
replacements.push([node.start, node.end, `const ${tmpVar} = ${__cjsRequire()}(${JSON.stringify(source)}); /*__substrate_await__*/(${tmpVar} && ${tmpVar}[${__cjsSymbol()}.for("substrate.pending")]); ${__cjsObject()}.defineProperty(${__cjsExports()}, ${JSON.stringify(name)}, { enumerable: true, configurable: true, get: function () { return ${tmpVar}; } })`]);
|
|
489
504
|
} else if (node.type === 'ExportAllDeclaration') {
|
|
490
505
|
// export * from './helpers'
|
|
491
506
|
const source = node.source.value;
|
|
@@ -498,7 +513,7 @@ function transformEsmToCjsAst(code: string): string {
|
|
|
498
513
|
// module does not already export; a local export shadows a star's, as the
|
|
499
514
|
// language says.
|
|
500
515
|
const tmpVar = `__reexport_${node.start}`;
|
|
501
|
-
replacements.push([node.start, node.end, `const ${tmpVar} = ${__cjsRequire()}(${JSON.stringify(source)}); /*__substrate_await__*/(${tmpVar} && ${tmpVar}[
|
|
516
|
+
replacements.push([node.start, node.end, `const ${tmpVar} = ${__cjsRequire()}(${JSON.stringify(source)}); /*__substrate_await__*/(${tmpVar} && ${tmpVar}[${__cjsSymbol()}.for("substrate.pending")]); (function (__from, __into) { for (const __key of ${__cjsObject()}.keys(__from)) { if (__key === "default" || __key === "__esModule" || ${__cjsObject()}.prototype.hasOwnProperty.call(__into, __key)) continue; ${__cjsObject()}.defineProperty(__into, __key, { enumerable: true, configurable: true, get: function () { return __from[__key]; } }); } })(${tmpVar}, ${__cjsExports()})`]);
|
|
502
517
|
}
|
|
503
518
|
}
|
|
504
519
|
|
|
@@ -28,6 +28,9 @@
|
|
|
28
28
|
* which this product does not do. The row in BUILTINS.md says the same.
|
|
29
29
|
*/
|
|
30
30
|
import { zstream, inflateModule, deflateModule, zlibConstants } from './zlib-pako';
|
|
31
|
+
// @ts-expect-error `brotli` ships no types; its decoder takes and returns bytes.
|
|
32
|
+
import brotliDecompressUntyped from 'brotli/decompress';
|
|
33
|
+
const brotliDecompress = brotliDecompressUntyped as (input: Uint8Array) => Uint8Array;
|
|
31
34
|
|
|
32
35
|
/** Node's `zlib` modes, by the numbers `zlib.js` passes. */
|
|
33
36
|
const DEFLATE = 1;
|
|
@@ -236,9 +239,83 @@ function absentCodec(name: string, reason: string): new (...args: unknown[]) =>
|
|
|
236
239
|
} as unknown as new (...args: unknown[]) => never;
|
|
237
240
|
}
|
|
238
241
|
|
|
242
|
+
/**
|
|
243
|
+
* `BrotliDecoder`, over the engine's own Brotli decoder (`brotli`'s, pure
|
|
244
|
+
* JavaScript). That decoder takes a whole stream, so this handle collects
|
|
245
|
+
* the input it is given and decodes when `zlib.js` sends the finishing
|
|
246
|
+
* flush, then hands the output back as the caller's buffers take it: a
|
|
247
|
+
* stream is inflated, it is not inflated incrementally. A server reading a
|
|
248
|
+
* pre-compressed file through `createBrotliDecompress` is the case it serves.
|
|
249
|
+
*/
|
|
250
|
+
const BROTLI_OPERATION_FINISH = 2;
|
|
251
|
+
class BrotliDecoderHandle {
|
|
252
|
+
#writeState: Uint32Array | null = null;
|
|
253
|
+
#callback: ProcessCallback | null = null;
|
|
254
|
+
#input: Uint8Array[] = [];
|
|
255
|
+
#output: Uint8Array | null = null;
|
|
256
|
+
#outputAt = 0;
|
|
257
|
+
onerror: ((message: string, errno: number, code?: string) => void) | null = null;
|
|
258
|
+
|
|
259
|
+
constructor(public readonly mode: number) {}
|
|
260
|
+
|
|
261
|
+
init(_params: Uint32Array, writeState: Uint32Array, processCallback: ProcessCallback): boolean {
|
|
262
|
+
this.#writeState = writeState;
|
|
263
|
+
this.#callback = processCallback;
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
#run(flush: number, inBuf: Uint8Array | null, inOff: number, inLen: number, outBuf: Uint8Array, outOff: number, outLen: number): void {
|
|
268
|
+
if (inBuf && inLen > 0) this.#input.push(inBuf.slice(inOff, inOff + inLen));
|
|
269
|
+
if (flush === BROTLI_OPERATION_FINISH && this.#output === null) {
|
|
270
|
+
const total = this.#input.reduce((sum, part) => sum + part.byteLength, 0);
|
|
271
|
+
const whole = new Uint8Array(total);
|
|
272
|
+
let at = 0;
|
|
273
|
+
for (const part of this.#input) { whole.set(part, at); at += part.byteLength; }
|
|
274
|
+
this.#input = [];
|
|
275
|
+
try {
|
|
276
|
+
this.#output = brotliDecompress(whole);
|
|
277
|
+
} catch (error) {
|
|
278
|
+
this.onerror?.(`Decompression failed: ${error instanceof Error ? error.message : String(error)}`, -1, 'ERR_BROTLI_DECOMPRESSION_FAILED');
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
this.#outputAt = 0;
|
|
282
|
+
}
|
|
283
|
+
let written = 0;
|
|
284
|
+
if (this.#output) {
|
|
285
|
+
written = Math.min(outLen, this.#output.byteLength - this.#outputAt);
|
|
286
|
+
outBuf.set(this.#output.subarray(this.#outputAt, this.#outputAt + written), outOff);
|
|
287
|
+
this.#outputAt += written;
|
|
288
|
+
}
|
|
289
|
+
if (this.#writeState) {
|
|
290
|
+
this.#writeState[0] = outLen - written;
|
|
291
|
+
this.#writeState[1] = 0;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
write(flush: number, inBuf: Uint8Array | null, inOff: number, inLen: number, outBuf: Uint8Array, outOff: number, outLen: number): this {
|
|
296
|
+
const tick = (globalThis as { process?: { nextTick?: (fn: () => void) => void } }).process?.nextTick
|
|
297
|
+
?? ((fn: () => void) => { queueMicrotask(fn); });
|
|
298
|
+
tick(() => {
|
|
299
|
+
this.#run(flush, inBuf, inOff, inLen, outBuf, outOff, outLen);
|
|
300
|
+
this.#callback?.();
|
|
301
|
+
});
|
|
302
|
+
return this;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
writeSync(flush: number, inBuf: Uint8Array | null, inOff: number, inLen: number, outBuf: Uint8Array, outOff: number, outLen: number): this {
|
|
306
|
+
this.#run(flush, inBuf, inOff, inLen, outBuf, outOff, outLen);
|
|
307
|
+
return this;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
params(): void {}
|
|
311
|
+
reset(): void { this.#input = []; this.#output = null; this.#outputAt = 0; }
|
|
312
|
+
close(): void { this.reset(); this.#callback = null; }
|
|
313
|
+
getAvailableOutput(): number { return this.#output ? this.#output.byteLength - this.#outputAt : 0; }
|
|
314
|
+
}
|
|
315
|
+
|
|
239
316
|
const BROTLI_REASON =
|
|
240
|
-
'Brotli is a codec of its own, not zlib; the engine
|
|
241
|
-
'
|
|
317
|
+
'Brotli is a codec of its own, not zlib; the engine decodes it (`brotli`, pure JavaScript) but has no ' +
|
|
318
|
+
'encoder for Node\'s Brotli handle yet. `zlib.gzip`, `deflate` and `inflate` are Node\'s own here.';
|
|
242
319
|
const ZSTD_REASON =
|
|
243
320
|
'Zstandard is a codec of its own and this engine has no implementation of it at all. ' +
|
|
244
321
|
'`zlib.gzip`, `deflate` and `inflate` are Node\'s own here.';
|
|
@@ -246,7 +323,7 @@ const ZSTD_REASON =
|
|
|
246
323
|
export const zlibBinding = {
|
|
247
324
|
Zlib,
|
|
248
325
|
BrotliEncoder: absentCodec('Brotli compression', BROTLI_REASON),
|
|
249
|
-
BrotliDecoder:
|
|
326
|
+
BrotliDecoder: BrotliDecoderHandle,
|
|
250
327
|
ZstdCompress: absentCodec('Zstandard compression', ZSTD_REASON),
|
|
251
328
|
ZstdDecompress: absentCodec('Zstandard decompression', ZSTD_REASON),
|
|
252
329
|
/** `zlib.crc32`, which is zlib's own table-driven one. */
|
|
@@ -219,8 +219,9 @@ export const internalEventTarget = {
|
|
|
219
219
|
};
|
|
220
220
|
|
|
221
221
|
/**
|
|
222
|
-
* `internal/options`: the command-line options Node's `net`
|
|
223
|
-
* takes no command line of its own, so each is
|
|
222
|
+
* `internal/options`: the command-line options Node's `net`, `http` and
|
|
223
|
+
* `util` read. The engine takes no command line of its own, so each is
|
|
224
|
+
* Node's own default.
|
|
224
225
|
*/
|
|
225
226
|
const optionValues: Record<string, unknown> = {
|
|
226
227
|
'--network-family-autoselection': true,
|
|
@@ -231,6 +232,9 @@ const optionValues: Record<string, unknown> = {
|
|
|
231
232
|
'--pending-deprecation': false,
|
|
232
233
|
'--report-uncaught-exception': false,
|
|
233
234
|
'--experimental-print-required-tla': false,
|
|
235
|
+
'--max-http-header-size': 16 * 1024,
|
|
236
|
+
'--insecure-http-parser': false,
|
|
237
|
+
'--enable-source-maps': false,
|
|
234
238
|
};
|
|
235
239
|
|
|
236
240
|
export const internalOptions = {
|
package/src/runtime.ts
CHANGED
|
@@ -66,7 +66,7 @@ import * as domainShim from './shims/domain';
|
|
|
66
66
|
import { createWasiModule, type WasiHostFs, type WasiModule } from './shims/wasi';
|
|
67
67
|
|
|
68
68
|
import { resolve as resolveExports, imports as resolveImports } from 'resolve.exports';
|
|
69
|
-
import { transformEsmToCjsSimple, setNodeLowering, __cjsExports, __substrateHasEsmSyntax } from './code-transforms';
|
|
69
|
+
import { transformEsmToCjsSimple, setNodeLowering, __cjsExports, __cjsObject, __substrateHasEsmSyntax } from './code-transforms';
|
|
70
70
|
import { applySourceEdits } from './source-edits';
|
|
71
71
|
import * as acorn from 'acorn';
|
|
72
72
|
|
|
@@ -263,7 +263,12 @@ function __substrateGuestGlobal(process: Process): Record<string, unknown> {
|
|
|
263
263
|
if (key === "fetch") { fetch = value; return true; }
|
|
264
264
|
if (key === "Buffer") { buffer = value; return true; }
|
|
265
265
|
if (shadowed(target, key)) return Reflect.set(target, key, value, target);
|
|
266
|
-
|
|
266
|
+
if (Reflect.set(host, key, value, host)) return true;
|
|
267
|
+
// A global the host holds read-only (a confined realm's \`WebSocket\`) is
|
|
268
|
+
// still the guest's to replace, as Node's globals are: undici's
|
|
269
|
+
// \`install()\` assigns \`globalThis.WebSocket\` and Pi died on the refusal.
|
|
270
|
+
// The value becomes the guest's own binding; the host's is untouched.
|
|
271
|
+
return Reflect.defineProperty(target, key, { value, writable: true, configurable: true, enumerable: true });
|
|
267
272
|
},
|
|
268
273
|
has(target, key) { return isLocalGlobal(key) ? Reflect.has(target, key) : key === "global" || shadowed(target, key) || key in host; },
|
|
269
274
|
ownKeys(target) {
|
|
@@ -448,7 +453,7 @@ function transformEsmToCjsAst(code: string, filename: string): string {
|
|
|
448
453
|
transformed = transformEsmToCjsSimple(transformed);
|
|
449
454
|
|
|
450
455
|
if (hasExportDecl) {
|
|
451
|
-
transformed =
|
|
456
|
+
transformed = `${__cjsObject()}.defineProperty(${__cjsExports()}, "__esModule", { value: true });\n` + transformed;
|
|
452
457
|
}
|
|
453
458
|
}
|
|
454
459
|
|
|
@@ -476,7 +481,7 @@ function transformEsmToCjsRegexFallback(code: string, filename: string): string
|
|
|
476
481
|
if (hasImport || hasExport) {
|
|
477
482
|
transformed = transformEsmToCjsSimple(transformed);
|
|
478
483
|
if (hasExport) {
|
|
479
|
-
transformed =
|
|
484
|
+
transformed = `${__cjsObject()}.defineProperty(${__cjsExports()}, "__esModule", { value: true });\n` + transformed;
|
|
480
485
|
}
|
|
481
486
|
}
|
|
482
487
|
|
|
@@ -2680,6 +2685,56 @@ forGuestRealm(() => {
|
|
|
2680
2685
|
}
|
|
2681
2686
|
});
|
|
2682
2687
|
|
|
2688
|
+
forGuestRealm(() => {
|
|
2689
|
+
// Node's `stream.finished()` on a web stream waits on a promise Node's own
|
|
2690
|
+
// web streams carry (`nodejs.webstream.isClosedPromise`), settled when the
|
|
2691
|
+
// stream closes or errors, and undici's fetch finalizes every response that
|
|
2692
|
+
// way. The worker's streams are the browser's and carry none, so a stream a
|
|
2693
|
+
// guest constructs is given one, settled by its own controller. The
|
|
2694
|
+
// constructor stays the browser's (a proxy of it), so a stream the platform
|
|
2695
|
+
// made is still `instanceof ReadableStream`.
|
|
2696
|
+
const kIsClosedPromise = Symbol.for('nodejs.webstream.isClosedPromise');
|
|
2697
|
+
const Native = globalThis.ReadableStream;
|
|
2698
|
+
if (typeof Native !== 'function' || (Native as unknown as { __substrateClosedPromise?: boolean }).__substrateClosedPromise) return;
|
|
2699
|
+
type Source = { start?: (controller: unknown) => unknown; pull?: (controller: unknown) => unknown; cancel?: (reason: unknown) => unknown };
|
|
2700
|
+
const Tracked: typeof ReadableStream = new Proxy(Native, {
|
|
2701
|
+
construct(target, args, newTarget): object {
|
|
2702
|
+
let resolve!: () => void;
|
|
2703
|
+
let reject!: (error: unknown) => void;
|
|
2704
|
+
const promise = new Promise<void>((yes, no) => { resolve = yes; reject = no; });
|
|
2705
|
+
promise.then(undefined, () => {});
|
|
2706
|
+
const source = args[0] as Source | null | undefined;
|
|
2707
|
+
const track = (controller: { close?: (...rest: unknown[]) => unknown; error?: (...rest: unknown[]) => unknown }): void => {
|
|
2708
|
+
const close = controller.close;
|
|
2709
|
+
const error = controller.error;
|
|
2710
|
+
if (typeof close === 'function') controller.close = function (this: unknown, ...rest: unknown[]) { const result = close.apply(this, rest); resolve(); return result; };
|
|
2711
|
+
if (typeof error === 'function') controller.error = function (this: unknown, ...rest: unknown[]) { reject(rest[0]); return error.apply(this, rest); };
|
|
2712
|
+
};
|
|
2713
|
+
const failed = (cause: unknown): never => { reject(cause); throw cause; };
|
|
2714
|
+
const wrapped: Source = Object.create(source ?? null);
|
|
2715
|
+
wrapped.start = (controller) => {
|
|
2716
|
+
track(controller as Parameters<typeof track>[0]);
|
|
2717
|
+
try { return source?.start?.call(source, controller); } catch (cause) { return failed(cause); }
|
|
2718
|
+
};
|
|
2719
|
+
if (typeof source?.pull === 'function') {
|
|
2720
|
+
const pull = source.pull;
|
|
2721
|
+
wrapped.pull = (controller) => {
|
|
2722
|
+
try { return Promise.resolve(pull.call(source, controller)).catch(failed); } catch (cause) { return failed(cause); }
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2725
|
+
wrapped.cancel = (reason) => {
|
|
2726
|
+
resolve();
|
|
2727
|
+
return source?.cancel?.call(source, reason);
|
|
2728
|
+
};
|
|
2729
|
+
const stream: object = Reflect.construct(target, [wrapped, ...args.slice(1)], newTarget === Tracked ? target : newTarget);
|
|
2730
|
+
Object.defineProperty(stream, kIsClosedPromise, { value: { promise, resolve, reject }, configurable: true });
|
|
2731
|
+
return stream;
|
|
2732
|
+
},
|
|
2733
|
+
});
|
|
2734
|
+
Object.defineProperty(Tracked, '__substrateClosedPromise', { value: true });
|
|
2735
|
+
takeFromHost(globalThis, 'ReadableStream', Tracked);
|
|
2736
|
+
});
|
|
2737
|
+
|
|
2683
2738
|
// Polyfill Error.captureStackTrace/prepareStackTrace for Safari/WebKit
|
|
2684
2739
|
// (V8-specific API used by Express's depd and other npm packages)
|
|
2685
2740
|
forGuestRealm(__substrateStackTracePolyfill);
|
|
@@ -936,8 +936,10 @@ export function initChildProcess(vfs: VirtualFS): void {
|
|
|
936
936
|
// engine's own registries. A run that still holds a handle or a timer
|
|
937
937
|
// is not that -- Node's loop runs while one is open, for as long as it
|
|
938
938
|
// is open -- and cutting it at a minute ended a forked child that was
|
|
939
|
-
// a server, which is every extension host and every pty host.
|
|
940
|
-
|
|
939
|
+
// a server, which is every extension host and every pty host. Work the
|
|
940
|
+
// host holds for it (a build, a pre-bundle) is seen work too: a dev
|
|
941
|
+
// server whose start passed a minute mid pre-bundle was cut with exit 0.
|
|
942
|
+
if (!isLongRunning && !stillWorking() && heldWork().count === 0 && Date.now() - startTime >= MAX_TOTAL_MS) break;
|
|
941
943
|
}
|
|
942
944
|
|
|
943
945
|
return { stdout, stderr, exitCode: exitCalled ? exitCode : (typeof proc !== 'undefined' && typeof proc.exitCode === 'number' ? proc.exitCode : 0) };
|
|
@@ -1755,6 +1757,15 @@ function startChildRun(request: RunRequest): StartedRun {
|
|
|
1755
1757
|
const admittedNode = nodeProcessHostInstalled() && engineProgramFor(request.file, request.cwd) === 'node';
|
|
1756
1758
|
const hostTerminal = request.terminal !== undefined && hostExecutor() !== null && !admittedNode;
|
|
1757
1759
|
let wakeInput: (() => void) | undefined;
|
|
1760
|
+
/**
|
|
1761
|
+
* A piped fd 0 that stays open for a program the host runs (a program pack,
|
|
1762
|
+
* not a builtin of the engine's shell): what the parent writes reaches it
|
|
1763
|
+
* as it is written, through the same live stream a terminal gets. A
|
|
1764
|
+
* builtin reads its input once, before it runs; a server that speaks
|
|
1765
|
+
* JSON-RPC over stdio (`supercode harness serve`) read that one string,
|
|
1766
|
+
* saw EOF and exited before its client's first request.
|
|
1767
|
+
*/
|
|
1768
|
+
let liveInput = false;
|
|
1758
1769
|
const hostInput: AsyncIterable<Uint8Array> = {
|
|
1759
1770
|
async *[Symbol.asyncIterator]() {
|
|
1760
1771
|
while (!finished && !controller.signal.aborted) {
|
|
@@ -1854,6 +1865,12 @@ function startChildRun(request: RunRequest): StartedRun {
|
|
|
1854
1865
|
const begin = (): void => {
|
|
1855
1866
|
if (started || finished) return;
|
|
1856
1867
|
started = true;
|
|
1868
|
+
const engineFirst = !hostTerminal && programExists(request.file, request.cwd, request.env);
|
|
1869
|
+
liveInput = !hostTerminal && !admittedNode && request.stdinIsPipe && !engineFirst;
|
|
1870
|
+
if (liveInput) {
|
|
1871
|
+
pendingStdin.unshift(...initialStdin);
|
|
1872
|
+
initialStdin.length = 0;
|
|
1873
|
+
}
|
|
1857
1874
|
const stdin = initialStdin.length > 0 ? Buffer.concat(initialStdin).toString('utf8') : undefined;
|
|
1858
1875
|
void (async () => {
|
|
1859
1876
|
let outcome: CommandOutcome;
|
|
@@ -1867,11 +1884,11 @@ function startChildRun(request: RunRequest): StartedRun {
|
|
|
1867
1884
|
filesystem: currentVfs!, env, streams, ...(stdin !== undefined ? { stdin } : {}),
|
|
1868
1885
|
}) : await enterRun(token, () => routeCommand({
|
|
1869
1886
|
command: __substrateLineFor(request.file, request.args, request.cwd),
|
|
1870
|
-
engineFirst
|
|
1887
|
+
engineFirst,
|
|
1871
1888
|
cwd: request.cwd,
|
|
1872
1889
|
env: { ...request.env, [PROCESS_TOKEN_ENV]: token },
|
|
1873
1890
|
stdin,
|
|
1874
|
-
...(hostTerminal ? { stdinStream: hostInput, terminal: request.terminal } : {}),
|
|
1891
|
+
...(hostTerminal ? { stdinStream: hostInput, terminal: request.terminal } : liveInput ? { stdinStream: hostInput } : {}),
|
|
1875
1892
|
signal: controller.signal,
|
|
1876
1893
|
onStdout: streams.onStdout,
|
|
1877
1894
|
onStderr: streams.onStderr,
|
|
@@ -1912,18 +1929,20 @@ function startChildRun(request: RunRequest): StartedRun {
|
|
|
1912
1929
|
return 0;
|
|
1913
1930
|
},
|
|
1914
1931
|
writeStdin(bytes: Uint8Array): void | Promise<void> {
|
|
1915
|
-
if (hostTerminal) { pendingStdin.push(bytes); wakeInput?.(); wakeInput = undefined; return; }
|
|
1932
|
+
if (hostTerminal || liveInput) { pendingStdin.push(bytes); wakeInput?.(); wakeInput = undefined; return; }
|
|
1916
1933
|
if (!started) { initialStdin.push(bytes); return; }
|
|
1917
1934
|
pendingStdin.push(bytes);
|
|
1918
1935
|
return flushStdin();
|
|
1919
1936
|
},
|
|
1920
1937
|
endStdin(): void {
|
|
1921
|
-
if (hostTerminal) { pendingStdin.push(null); wakeInput?.(); wakeInput = undefined; return; }
|
|
1938
|
+
if (hostTerminal || liveInput) { pendingStdin.push(null); wakeInput?.(); wakeInput = undefined; return; }
|
|
1922
1939
|
if (!started) {
|
|
1923
1940
|
// The writer closed before the command began: the run's fd 0 is the
|
|
1924
1941
|
// string already collected and nothing more, so it is not held open.
|
|
1925
1942
|
streams.stdinOpen = false;
|
|
1926
1943
|
begin();
|
|
1944
|
+
// A live pipe closed before it began still ends where it was closed.
|
|
1945
|
+
if (liveInput) { pendingStdin.push(null); wakeInput?.(); wakeInput = undefined; }
|
|
1927
1946
|
return;
|
|
1928
1947
|
}
|
|
1929
1948
|
pendingStdin.push(null);
|
|
@@ -1951,3 +1970,4 @@ export default {
|
|
|
1951
1970
|
runCommand,
|
|
1952
1971
|
sendStdin,
|
|
1953
1972
|
};
|
|
1973
|
+
|
package/src/shims/esbuild.ts
CHANGED
|
@@ -398,6 +398,16 @@ export interface EsbuildHost {
|
|
|
398
398
|
}
|
|
399
399
|
let currentHost: EsbuildHost | null = null;
|
|
400
400
|
|
|
401
|
+
/**
|
|
402
|
+
* esbuild-wasm starts its compiler on a Worker unless told not to. A realm
|
|
403
|
+
* that runs guests may withhold `Worker` (the execution worker confines its
|
|
404
|
+
* guests that way), and there the compiler runs on the calling thread, which
|
|
405
|
+
* is esbuild's own `worker: false`.
|
|
406
|
+
*/
|
|
407
|
+
function realmCanStartWorker(): boolean {
|
|
408
|
+
return typeof (globalThis as { Worker?: unknown }).Worker === 'function';
|
|
409
|
+
}
|
|
410
|
+
|
|
401
411
|
let inlineEsbuild: Promise<typeof import('esbuild-wasm')> | null = null;
|
|
402
412
|
function ownEsbuild(): Promise<typeof import('esbuild-wasm')> {
|
|
403
413
|
// A build that brings plugins of its own, a bundler such as tsup does,
|
|
@@ -408,7 +418,7 @@ function ownEsbuild(): Promise<typeof import('esbuild-wasm')> {
|
|
|
408
418
|
/* @vite-ignore */
|
|
409
419
|
esbuildModuleURL
|
|
410
420
|
).then(async (esbuild) => {
|
|
411
|
-
await esbuild.initialize({ wasmURL });
|
|
421
|
+
await esbuild.initialize({ wasmURL, worker: realmCanStartWorker() });
|
|
412
422
|
return esbuild;
|
|
413
423
|
}).catch((cause) => {
|
|
414
424
|
// A load that failed, a page whose server was away for a moment, is not kept: the next build tries again.
|
|
@@ -527,6 +537,7 @@ export async function initialize(options?: { wasmURL?: string }): Promise<void>
|
|
|
527
537
|
|
|
528
538
|
await esbuild.initialize({
|
|
529
539
|
wasmURL: options?.wasmURL || wasmURL,
|
|
540
|
+
worker: realmCanStartWorker(),
|
|
530
541
|
});
|
|
531
542
|
|
|
532
543
|
esbuildInstance = esbuild;
|
package/src/shims/perf_hooks.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* perf_hooks shim - Performance measurement APIs
|
|
3
3
|
* Wraps browser Performance API
|
|
4
4
|
*/
|
|
5
|
+
import { forGuestRealm } from '../host-globals';
|
|
5
6
|
|
|
6
7
|
export const performance = globalThis.performance || {
|
|
7
8
|
now: () => Date.now(),
|
|
@@ -16,6 +17,23 @@ export const performance = globalThis.performance || {
|
|
|
16
17
|
clearResourceTimings: () => {},
|
|
17
18
|
};
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Node's `performance.markResourceTiming`, which a browser's `performance`
|
|
22
|
+
* does not have. undici's fetch reads it off the global `performance` at load
|
|
23
|
+
* and calls it after every response, so each fetch through an undici a
|
|
24
|
+
* program installed (Pi's does) threw once the body was read. Node records a
|
|
25
|
+
* PerformanceResourceTiming entry there; this engine keeps no resource
|
|
26
|
+
* timeline for a guest's own HTTP, so the call records nothing.
|
|
27
|
+
*/
|
|
28
|
+
forGuestRealm(() => {
|
|
29
|
+
const own = globalThis.performance as (Performance & { markResourceTiming?: unknown }) | undefined;
|
|
30
|
+
if (own && typeof own.markResourceTiming !== 'function') {
|
|
31
|
+
try {
|
|
32
|
+
Object.defineProperty(own, 'markResourceTiming', { value: () => undefined, writable: true, configurable: true, enumerable: false });
|
|
33
|
+
} catch { /* a performance object that refuses the name keeps its own shape */ }
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
19
37
|
export class PerformanceObserver {
|
|
20
38
|
private callback: (list: PerformanceObserverEntryList) => void;
|
|
21
39
|
private entryTypes: string[] = [];
|
|
@@ -308,6 +308,7 @@ function base64End(this: StringDecoder, buf?: unknown): string {
|
|
|
308
308
|
// ---------------------------------------------------------------------------
|
|
309
309
|
|
|
310
310
|
function simpleWrite(this: StringDecoder, buf: unknown): string {
|
|
311
|
+
if (typeof buf === 'string') return buf;
|
|
311
312
|
return decoderInput(this, buf).toString(this.encoding as BufferEncoding);
|
|
312
313
|
}
|
|
313
314
|
|
|
@@ -353,6 +354,10 @@ const decoderPrototype = StringDecoderImpl.prototype as unknown as StringDecoder
|
|
|
353
354
|
|
|
354
355
|
decoderPrototype.write = function write(this: unknown, buffer: unknown): string {
|
|
355
356
|
const self = assertDecoder(this);
|
|
357
|
+
// Node returns a string as it is given: readline decodes every chunk of its
|
|
358
|
+
// input, and an input stream with an encoding (`createReadStream(path,
|
|
359
|
+
// 'utf8')`) hands it strings.
|
|
360
|
+
if (typeof buffer === 'string') return buffer;
|
|
356
361
|
const buf = decoderInput(self, buffer);
|
|
357
362
|
if (buf.length === 0) return '';
|
|
358
363
|
let r: string | undefined;
|
package/src/shims/tls.ts
CHANGED
|
@@ -102,6 +102,17 @@ const DEFAULT_MIN_VERSION = 'TLSv1.2';
|
|
|
102
102
|
|
|
103
103
|
const rootCertificates: string[] = [];
|
|
104
104
|
|
|
105
|
+
// Node's certificate-store door, read by callers that build their own agents
|
|
106
|
+
// (VS Code's proxy agent, on every fetch it patches). The engine holds no
|
|
107
|
+
// store: certificates are the browser's, so every kind answers the same empty
|
|
108
|
+
// set `rootCertificates` does.
|
|
109
|
+
const getCACertificates = (type: string = 'default'): string[] => {
|
|
110
|
+
if (!['default', 'system', 'bundled', 'extra'].includes(type)) {
|
|
111
|
+
throw Object.assign(new TypeError(`The argument 'type' must be one of: 'default', 'system', 'bundled', 'extra'. Received '${String(type)}'`), { code: 'ERR_INVALID_ARG_VALUE' });
|
|
112
|
+
}
|
|
113
|
+
return [];
|
|
114
|
+
};
|
|
115
|
+
|
|
105
116
|
return {
|
|
106
117
|
TLSSocket,
|
|
107
118
|
Server,
|
|
@@ -109,6 +120,7 @@ return {
|
|
|
109
120
|
connect,
|
|
110
121
|
createSecureContext,
|
|
111
122
|
getCiphers,
|
|
123
|
+
getCACertificates,
|
|
112
124
|
DEFAULT_ECDH_CURVE,
|
|
113
125
|
DEFAULT_MAX_VERSION,
|
|
114
126
|
DEFAULT_MIN_VERSION,
|
|
@@ -117,7 +129,7 @@ return {
|
|
|
117
129
|
|
|
118
130
|
}
|
|
119
131
|
const tls = createTlsModule();
|
|
120
|
-
export const { TLSSocket, Server, createServer, connect, createSecureContext, getCiphers,
|
|
132
|
+
export const { TLSSocket, Server, createServer, connect, createSecureContext, getCiphers, getCACertificates,
|
|
121
133
|
DEFAULT_ECDH_CURVE, DEFAULT_MAX_VERSION, DEFAULT_MIN_VERSION, rootCertificates } = tls;
|
|
122
134
|
export type TLSSocket = InstanceType<typeof TLSSocket>;
|
|
123
135
|
export type Server = InstanceType<typeof Server>;
|