@volter/tabnode 0.5.16 → 0.5.18
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-C-l9pCp3.js} +4374 -365
- package/dist/code-transforms.d.ts +2 -1
- package/dist/index.mjs +4319 -322
- package/dist/node-lib/binding/zlib.d.ts +14 -1
- package/dist/node-lib/internals/amaro.d.ts +31 -0
- package/dist/node-lib/internals/runtime.d.ts +1 -0
- package/dist/node-lib/node-versions.d.ts +1 -0
- package/dist/node-lib/typescript-module.d.ts +11 -0
- package/dist/process-tokens.d.ts +2 -0
- package/dist/shims/perf_hooks.d.ts +0 -4
- package/dist/shims/process.d.ts +3 -0
- package/dist/shims/shell-jobs.d.ts +12 -0
- package/dist/shims/streamed-output.d.ts +14 -0
- package/dist/shims/tls.d.ts +3 -1
- package/dist/shims/worker_threads.d.ts +4 -0
- package/package.json +2 -1
- package/src/code-transforms.ts +28 -13
- package/src/node-lib/binding/zlib.ts +80 -3
- package/src/node-lib/internal/modules/typescript.js +183 -0
- package/src/node-lib/internals/amaro.ts +51 -0
- package/src/node-lib/internals/index.ts +2 -0
- package/src/node-lib/internals/runtime.ts +22 -3
- package/src/node-lib/node-versions.ts +4 -1
- package/src/node-lib/sources.ts +2 -0
- package/src/node-lib/typescript-module.ts +50 -0
- package/src/process-tokens.ts +6 -0
- package/src/runtime.ts +97 -19
- package/src/shims/child_process.ts +41 -13
- package/src/shims/esbuild.ts +12 -1
- package/src/shims/perf_hooks.ts +18 -0
- package/src/shims/process.ts +2 -2
- package/src/shims/shell-jobs.ts +451 -0
- package/src/shims/streamed-output.ts +25 -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. */
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `internal/deps/amaro/dist/index`: the type stripper Node carries.
|
|
3
|
+
*
|
|
4
|
+
* Node v22.18.0 runs a `.ts`, `.mts` or `.cts` file by erasing its types with
|
|
5
|
+
* amaro 1.1.0 (swc's stripper, built to WebAssembly), vendored under
|
|
6
|
+
* `deps/amaro`, and its own `lib/internal/modules/typescript.js` (vendored
|
|
7
|
+
* here unmodified) is what calls it. amaro is not native: it is JavaScript and
|
|
8
|
+
* WebAssembly, and this engine takes the same release as a dependency rather
|
|
9
|
+
* than writing a stripper of its own. esbuild, which the engine also carries,
|
|
10
|
+
* is not a substitute: it reprints the program (a stack's line and column move)
|
|
11
|
+
* and it transforms `enum`, `namespace` and parameter properties where Node, in
|
|
12
|
+
* strip-only mode, refuses them.
|
|
13
|
+
*
|
|
14
|
+
* amaro's glue loads its WebAssembly synchronously from bytes inlined in the
|
|
15
|
+
* package and reads `util` and `buffer`, so it is loaded through the host's own
|
|
16
|
+
* `require` where the host is Node. A browser realm has no such door: there the
|
|
17
|
+
* page supplies its stripper as `globalThis.__substrateStripTypes`, which the
|
|
18
|
+
* module loader asks first, and this answers absent.
|
|
19
|
+
*/
|
|
20
|
+
type AmaroTransform = (source: string, options: Record<string, unknown>) => {
|
|
21
|
+
code: string;
|
|
22
|
+
map?: string;
|
|
23
|
+
};
|
|
24
|
+
interface Amaro {
|
|
25
|
+
transformSync: AmaroTransform;
|
|
26
|
+
}
|
|
27
|
+
/** amaro, loaded once from beside this engine, or null where the realm cannot load it. */
|
|
28
|
+
export declare function hostAmaro(): Amaro | null;
|
|
29
|
+
/** The module Node's `typescript.js` requires; absent, the error Node raises when built without amaro. */
|
|
30
|
+
export declare function internalAmaro(): Amaro;
|
|
31
|
+
export {};
|
|
@@ -107,6 +107,7 @@ export declare const internalEventTarget: {
|
|
|
107
107
|
kNewListener: symbol;
|
|
108
108
|
kRemoveListener: symbol;
|
|
109
109
|
};
|
|
110
|
+
export declare function withOptionValues<T>(overrides: Record<string, unknown>, fn: () => T): T;
|
|
110
111
|
export declare const internalOptions: {
|
|
111
112
|
getOptionValue: (name: string) => unknown;
|
|
112
113
|
getEmbedderOptions: () => {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type RunProcess = {
|
|
2
|
+
execArgv?: readonly string[];
|
|
3
|
+
env?: Record<string, string | undefined>;
|
|
4
|
+
};
|
|
5
|
+
/** Whether this realm can erase types itself: amaro is loadable here. */
|
|
6
|
+
export declare function canStripTypes(): boolean;
|
|
7
|
+
/** Whether a process transforms TypeScript-only syntax rather than refusing it. */
|
|
8
|
+
export declare function transformsTypes(process: RunProcess): boolean;
|
|
9
|
+
/** The module's source with its types erased (or, under `--experimental-transform-types`, transformed), for this process. */
|
|
10
|
+
export declare function stripModuleTypes(source: string, filename: string, process: object): string;
|
|
11
|
+
export {};
|
package/dist/process-tokens.d.ts
CHANGED
|
@@ -96,6 +96,8 @@ export declare function runPid(token: ProcessToken | null | undefined): {
|
|
|
96
96
|
} | undefined;
|
|
97
97
|
/** A run that has ended is no longer a process; its number is nobody's. */
|
|
98
98
|
export declare function forgetRunPid(token: ProcessToken): void;
|
|
99
|
+
/** The named run a pid belongs to in this realm, for a signal sent by number (the shell's `kill`). */
|
|
100
|
+
export declare function tokenOfPid(pid: number): ProcessToken | null;
|
|
99
101
|
/** Whether a live run carries this number, which is what `kill(pid, 0)` asks. */
|
|
100
102
|
export declare function pidIsLive(pid: number): boolean;
|
|
101
103
|
/** `kill(pid, signal)` to another realm's live process; whether one took it. */
|
package/dist/shims/process.d.ts
CHANGED
|
@@ -177,6 +177,9 @@ export interface Process {
|
|
|
177
177
|
send?: (message: unknown, callback?: (error: Error | null) => void) => boolean;
|
|
178
178
|
connected?: boolean;
|
|
179
179
|
}
|
|
180
|
+
/** The signal numbers a guest sees, and the signals a tab must ignore. */
|
|
181
|
+
export declare const __substrateSignals: Record<string, number>;
|
|
182
|
+
export declare const __substrateSignalNames: Record<number, string>;
|
|
180
183
|
/**
|
|
181
184
|
* The guest's children are processes it can see. `process.kill(pid, 0)`
|
|
182
185
|
* answered ESRCH for every pid but the guest's own, so a program that keeps its
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Bash, CommandContext } from 'just-bash';
|
|
2
|
+
import { type ProcessToken } from '../process-tokens';
|
|
3
|
+
import type { RunStreams } from './child_process';
|
|
4
|
+
/** What the engine's process model gives this module. */
|
|
5
|
+
export interface ShellJobsHost {
|
|
6
|
+
runTokenOf(ctx: CommandContext): ProcessToken | null;
|
|
7
|
+
runStreamsFor(token: ProcessToken): RunStreams | undefined;
|
|
8
|
+
registerRunStreams(token: ProcessToken, streams: RunStreams): void;
|
|
9
|
+
releaseRunStreams(token: ProcessToken): void;
|
|
10
|
+
}
|
|
11
|
+
/** The engine's shell, given background jobs. */
|
|
12
|
+
export declare function installShellJobs(bash: Bash, host: ShellJobsHost): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What of a command's collected output was not already streamed.
|
|
3
|
+
*
|
|
4
|
+
* The engine's shell collects a command line's output as one text at its end;
|
|
5
|
+
* a `node` in it (or a background job) also streams its own as it writes. A
|
|
6
|
+
* caller that forwarded the streamed pieces sends the rest at the end. Cutting
|
|
7
|
+
* the collected text at the streamed length assumed the streamed pieces came
|
|
8
|
+
* first: `echo "pid=1"; node -e "console.log('fg out')"; echo end`, spawned by
|
|
9
|
+
* a guest, reached it as `fg out\ng out\nend\n` -- the builtin's line lost and
|
|
10
|
+
* the node's half repeated. Each streamed piece is taken out where it stands in
|
|
11
|
+
* the collected text, in order, and what is left is the rest; a piece the text
|
|
12
|
+
* does not hold is passed over.
|
|
13
|
+
*/
|
|
14
|
+
export declare function unstreamedOutput(total: string, streamed: readonly string[]): string;
|
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/tabnode",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.18",
|
|
4
4
|
"description": "Node's own library, in a browser tab.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@noble/hashes": "2.3.0",
|
|
55
55
|
"acorn": "^8.15.0",
|
|
56
|
+
"amaro": "1.1.0",
|
|
56
57
|
"brotli": "^1.3.3",
|
|
57
58
|
"brotli-wasm": "^3.0.1",
|
|
58
59
|
"buffer": "6.0.3",
|
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. */
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
ObjectPrototypeHasOwnProperty,
|
|
5
|
+
} = primordials;
|
|
6
|
+
const {
|
|
7
|
+
validateBoolean,
|
|
8
|
+
validateOneOf,
|
|
9
|
+
validateObject,
|
|
10
|
+
validateString,
|
|
11
|
+
} = require('internal/validators');
|
|
12
|
+
const { assertTypeScript,
|
|
13
|
+
emitExperimentalWarning,
|
|
14
|
+
getLazy,
|
|
15
|
+
isUnderNodeModules,
|
|
16
|
+
kEmptyObject } = require('internal/util');
|
|
17
|
+
const {
|
|
18
|
+
ERR_INVALID_TYPESCRIPT_SYNTAX,
|
|
19
|
+
ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING,
|
|
20
|
+
ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX,
|
|
21
|
+
} = require('internal/errors').codes;
|
|
22
|
+
const { getOptionValue } = require('internal/options');
|
|
23
|
+
const assert = require('internal/assert');
|
|
24
|
+
const { Buffer } = require('buffer');
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The TypeScript parsing mode, either 'strip-only' or 'transform'.
|
|
28
|
+
* @type {function(): TypeScriptMode}
|
|
29
|
+
*/
|
|
30
|
+
const getTypeScriptParsingMode = getLazy(() =>
|
|
31
|
+
(getOptionValue('--experimental-transform-types') ?
|
|
32
|
+
(emitExperimentalWarning('Transform Types'), 'transform') : 'strip-only'),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Load the TypeScript parser.
|
|
37
|
+
* and returns an object with a `code` property.
|
|
38
|
+
* @returns {Function} The TypeScript parser function.
|
|
39
|
+
*/
|
|
40
|
+
const loadTypeScriptParser = getLazy(() => {
|
|
41
|
+
assertTypeScript();
|
|
42
|
+
const amaro = require('internal/deps/amaro/dist/index');
|
|
43
|
+
return amaro.transformSync;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @param {string} source the source code
|
|
49
|
+
* @param {object} options the options to pass to the parser
|
|
50
|
+
* @returns {TransformOutput} an object with a `code` property.
|
|
51
|
+
*/
|
|
52
|
+
function parseTypeScript(source, options) {
|
|
53
|
+
const parse = loadTypeScriptParser();
|
|
54
|
+
try {
|
|
55
|
+
return parse(source, options);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
/**
|
|
58
|
+
* Amaro v0.3.0 (from SWC v1.10.7) throws an object with `message` and `code` properties.
|
|
59
|
+
* It allows us to distinguish between invalid syntax and unsupported syntax.
|
|
60
|
+
*/
|
|
61
|
+
switch (error?.code) {
|
|
62
|
+
case 'UnsupportedSyntax': {
|
|
63
|
+
const unsupportedSyntaxError = new ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX(error.message);
|
|
64
|
+
throw decorateErrorWithSnippet(unsupportedSyntaxError, error); /* node-do-not-add-exception-line */
|
|
65
|
+
}
|
|
66
|
+
case 'InvalidSyntax': {
|
|
67
|
+
const invalidSyntaxError = new ERR_INVALID_TYPESCRIPT_SYNTAX(error.message);
|
|
68
|
+
throw decorateErrorWithSnippet(invalidSyntaxError, error); /* node-do-not-add-exception-line */
|
|
69
|
+
}
|
|
70
|
+
default:
|
|
71
|
+
// SWC may throw strings when something goes wrong.
|
|
72
|
+
if (typeof error === 'string') { assert.fail(error); }
|
|
73
|
+
assert(error != null && ObjectPrototypeHasOwnProperty(error, 'message'));
|
|
74
|
+
assert.fail(error.message);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
*
|
|
81
|
+
* @param {Error} error the error to decorate: ERR_INVALID_TYPESCRIPT_SYNTAX, ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX
|
|
82
|
+
* @param {object} amaroError the error object from amaro
|
|
83
|
+
* @returns {Error} the decorated error
|
|
84
|
+
*/
|
|
85
|
+
function decorateErrorWithSnippet(error, amaroError) {
|
|
86
|
+
const errorHints = `${amaroError.filename}:${amaroError.startLine}\n${amaroError.snippet}`;
|
|
87
|
+
error.stack = `${errorHints}\n${error.stack}`;
|
|
88
|
+
return error;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Performs type-stripping to TypeScript source code.
|
|
93
|
+
* @param {string} code TypeScript code to parse.
|
|
94
|
+
* @param {TransformOptions} options The configuration for type stripping.
|
|
95
|
+
* @returns {string} The stripped TypeScript code.
|
|
96
|
+
*/
|
|
97
|
+
function stripTypeScriptTypes(code, options = kEmptyObject) {
|
|
98
|
+
emitExperimentalWarning('stripTypeScriptTypes');
|
|
99
|
+
validateString(code, 'code');
|
|
100
|
+
validateObject(options, 'options');
|
|
101
|
+
|
|
102
|
+
const {
|
|
103
|
+
sourceMap = false,
|
|
104
|
+
sourceUrl = '',
|
|
105
|
+
} = options;
|
|
106
|
+
let { mode = 'strip' } = options;
|
|
107
|
+
validateOneOf(mode, 'options.mode', ['strip', 'transform']);
|
|
108
|
+
validateBoolean(sourceMap, 'options.sourceMap');
|
|
109
|
+
validateString(sourceUrl, 'options.sourceUrl');
|
|
110
|
+
if (mode === 'strip') {
|
|
111
|
+
validateOneOf(sourceMap, 'options.sourceMap', [false, undefined]);
|
|
112
|
+
// Rename mode from 'strip' to 'strip-only'.
|
|
113
|
+
// The reason is to match `process.features.typescript` which returns `strip`,
|
|
114
|
+
// but the parser expects `strip-only`.
|
|
115
|
+
mode = 'strip-only';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return processTypeScriptCode(code, {
|
|
119
|
+
mode,
|
|
120
|
+
sourceMap,
|
|
121
|
+
filename: sourceUrl,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Processes TypeScript code by stripping types or transforming.
|
|
127
|
+
* Handles source maps if needed.
|
|
128
|
+
* @param {string} code TypeScript code to process.
|
|
129
|
+
* @param {object} options The configuration object.
|
|
130
|
+
* @returns {string} The processed code.
|
|
131
|
+
*/
|
|
132
|
+
function processTypeScriptCode(code, options) {
|
|
133
|
+
const { code: transformedCode, map } = parseTypeScript(code, options);
|
|
134
|
+
|
|
135
|
+
if (map) {
|
|
136
|
+
return addSourceMap(transformedCode, map);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (options.filename) {
|
|
140
|
+
return `${transformedCode}\n\n//# sourceURL=${options.filename}`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return transformedCode;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Performs type-stripping to TypeScript source code internally.
|
|
148
|
+
* It is used by internal loaders.
|
|
149
|
+
* @param {string} source TypeScript code to parse.
|
|
150
|
+
* @param {string} filename The filename of the source code.
|
|
151
|
+
* @returns {TransformOutput} The stripped TypeScript code.
|
|
152
|
+
*/
|
|
153
|
+
function stripTypeScriptModuleTypes(source, filename) {
|
|
154
|
+
assert(typeof source === 'string');
|
|
155
|
+
if (isUnderNodeModules(filename)) {
|
|
156
|
+
throw new ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING(filename);
|
|
157
|
+
}
|
|
158
|
+
const options = {
|
|
159
|
+
mode: getTypeScriptParsingMode(),
|
|
160
|
+
sourceMap: getOptionValue('--enable-source-maps'),
|
|
161
|
+
filename,
|
|
162
|
+
};
|
|
163
|
+
return processTypeScriptCode(source, options);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
*
|
|
168
|
+
* @param {string} code The compiled code.
|
|
169
|
+
* @param {string} sourceMap The source map.
|
|
170
|
+
* @returns {string} The code with the source map attached.
|
|
171
|
+
*/
|
|
172
|
+
function addSourceMap(code, sourceMap) {
|
|
173
|
+
// The base64 encoding should be https://datatracker.ietf.org/doc/html/rfc4648#section-4,
|
|
174
|
+
// not base64url https://datatracker.ietf.org/doc/html/rfc4648#section-5. See data url
|
|
175
|
+
// spec https://tools.ietf.org/html/rfc2397#section-2.
|
|
176
|
+
const base64SourceMap = Buffer.from(sourceMap).toString('base64');
|
|
177
|
+
return `${code}\n\n//# sourceMappingURL=data:application/json;base64,${base64SourceMap}`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
module.exports = {
|
|
181
|
+
stripTypeScriptModuleTypes,
|
|
182
|
+
stripTypeScriptTypes,
|
|
183
|
+
};
|