@coana-tech/cli 15.0.1 → 15.0.2

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.
@@ -0,0 +1,131 @@
1
+ // Hint collection for approximate interpretation.
2
+ // Adapted from Jelly's src/approx/hints.ts.
3
+ // Save native functions before user code can overwrite them.
4
+ const arrayFrom = Array.from.bind(Array);
5
+ const arrayFlat = Array.prototype.flat;
6
+ function flattenValues(map) {
7
+ return arrayFlat.call(arrayFrom(map.values()));
8
+ }
9
+ function mapArrayAddNoDuplicates(key, value, map, eq) {
10
+ let arr = map.get(key);
11
+ if (!arr) {
12
+ arr = [];
13
+ map.set(key, arr);
14
+ }
15
+ if (!arr.some(v => eq(v, value)))
16
+ arr.push(value);
17
+ }
18
+ function mapArraySize(map) {
19
+ let c = 0;
20
+ for (const v of map.values())
21
+ c += v.length;
22
+ return c;
23
+ }
24
+ export class Hints {
25
+ /**
26
+ * Names of modules (including eval code) that have been executed dynamically.
27
+ */
28
+ modules = [];
29
+ /**
30
+ * Map from module name to index in LocationJSON strings.
31
+ */
32
+ moduleIndex = new Map();
33
+ /**
34
+ * Functions that have been visited (either via module execution or by forced execution).
35
+ */
36
+ functions = new Set();
37
+ /**
38
+ * Read hints grouped by location of the read operation.
39
+ */
40
+ reads = new Map();
41
+ /**
42
+ * Write hints grouped by location of the write operation.
43
+ */
44
+ writes = new Map();
45
+ /**
46
+ * Require/import hints grouped by location of the require/import operation.
47
+ */
48
+ requires = new Map();
49
+ /**
50
+ * Eval/Function hints grouped by the location of the eval/Function operation.
51
+ */
52
+ evals = new Map();
53
+ addModule(m) {
54
+ let idx = this.moduleIndex.get(m);
55
+ if (idx !== undefined)
56
+ return idx;
57
+ idx = this.modules.length;
58
+ this.modules.push(m);
59
+ this.moduleIndex.set(m, idx);
60
+ return idx;
61
+ }
62
+ addFunction(f) {
63
+ this.functions.add(f);
64
+ }
65
+ addReadHint(h) {
66
+ mapArrayAddNoDuplicates(h.loc, h, this.reads, (v1, v2) => v1.prop === v2.prop && v1.valLoc === v2.valLoc && v1.valType === v2.valType);
67
+ }
68
+ addWriteHint(h) {
69
+ mapArrayAddNoDuplicates(h.loc, h, this.writes, (v1, v2) => v1.type === v2.type && v1.baseLoc === v2.baseLoc && v1.baseType === v2.baseType &&
70
+ v1.prop === v2.prop && v1.valLoc === v2.valLoc && v1.valType === v2.valType);
71
+ }
72
+ addRequireHint(h) {
73
+ mapArrayAddNoDuplicates(h.loc, h, this.requires, (v1, v2) => v1.str === v2.str);
74
+ }
75
+ addEvalHint(h) {
76
+ mapArrayAddNoDuplicates(h.loc, h, this.evals, (v1, v2) => v1.str === v2.str);
77
+ }
78
+ add(newHints) {
79
+ const moduleReindex = new Map();
80
+ for (const [i, s] of newHints.modules.entries())
81
+ moduleReindex.set(i, this.addModule(s));
82
+ const convert = (loc) => `${moduleReindex.get(parseInt(loc))}${loc.substring(loc.indexOf(":"))}`;
83
+ for (const f of newHints.functions)
84
+ this.addFunction(convert(f));
85
+ for (const { loc, prop, valLoc, valType } of newHints.reads) {
86
+ this.addReadHint({
87
+ loc: convert(loc),
88
+ prop,
89
+ valLoc: convert(valLoc),
90
+ valType
91
+ });
92
+ }
93
+ for (const { type, loc, baseLoc, baseType, prop, valLoc, valType } of newHints.writes) {
94
+ this.addWriteHint({
95
+ type,
96
+ loc: convert(loc),
97
+ baseLoc: convert(baseLoc),
98
+ baseType,
99
+ prop,
100
+ valLoc: convert(valLoc),
101
+ valType
102
+ });
103
+ }
104
+ for (const { loc, str } of newHints.requires)
105
+ this.addRequireHint({
106
+ loc: convert(loc),
107
+ str
108
+ });
109
+ for (const { loc, str } of newHints.evals)
110
+ this.addEvalHint({
111
+ loc: convert(loc),
112
+ str
113
+ });
114
+ }
115
+ toJSON() {
116
+ return {
117
+ modules: this.modules,
118
+ functions: arrayFrom(this.functions),
119
+ reads: flattenValues(this.reads),
120
+ writes: flattenValues(this.writes),
121
+ requires: flattenValues(this.requires),
122
+ evals: flattenValues(this.evals)
123
+ };
124
+ }
125
+ clearHints() {
126
+ this.reads.clear();
127
+ this.writes.clear();
128
+ this.requires.clear();
129
+ this.evals.clear();
130
+ }
131
+ }
@@ -0,0 +1,172 @@
1
+ // ESM module loader hooks for approximate interpretation.
2
+ // Adapted from Jelly's src/approx/hooks.ts.
3
+ // Code transformation is requested directly from the Rust parent process,
4
+ // bypassing the main thread to avoid deadlocks.
5
+ //
6
+ // IPC: writes transform requests to the IPC FIFO (shared with main thread),
7
+ // reads responses from the hooks FIFO (dedicated channel from Rust parent).
8
+ import Module, { createRequire } from "module";
9
+ import { extname } from "path";
10
+ import { WHITELISTED } from "./sandbox.js";
11
+ import { fileURLToPath } from "url";
12
+ import { openSync, readFileSync, readSync, realpathSync, writeSync } from "fs";
13
+ const PREFIX = "_J$";
14
+ let port2;
15
+ /** Basedir for filtering modules. */
16
+ let resolvedBasedir = "";
17
+ /** File descriptor for writing to the IPC FIFO (Node.js → Rust). */
18
+ let ipcFd;
19
+ /** File descriptor for reading from the hooks FIFO (Rust → hooks). */
20
+ let hooksFd;
21
+ const responseBuffer = Buffer.alloc(65536);
22
+ let responseLeftover = "";
23
+ /**
24
+ * Synchronous line read from the hooks response FIFO.
25
+ */
26
+ function readLineSync() {
27
+ while (true) {
28
+ const nlIdx = responseLeftover.indexOf('\n');
29
+ if (nlIdx !== -1) {
30
+ const line = responseLeftover.substring(0, nlIdx);
31
+ responseLeftover = responseLeftover.substring(nlIdx + 1);
32
+ return line;
33
+ }
34
+ const bytesRead = readSync(hooksFd, responseBuffer);
35
+ if (bytesRead === 0)
36
+ throw new Error("hooks response FIFO closed unexpectedly");
37
+ responseLeftover += responseBuffer.toString("utf8", 0, bytesRead);
38
+ }
39
+ }
40
+ /**
41
+ * Sends a JSON message to the Rust parent via the IPC FIFO.
42
+ */
43
+ function sendToParent(msg) {
44
+ const json = JSON.stringify(msg) + '\n';
45
+ writeSync(ipcFd, json);
46
+ }
47
+ /**
48
+ * Requests code transformation from the Rust parent process.
49
+ * Synchronous: sends request on IPC FIFO, reads response from hooks FIFO.
50
+ */
51
+ function requestTransform(file, source) {
52
+ sendToParent({ transform: file, source, sourceType: "module", hooks: true });
53
+ const line = readLineSync();
54
+ const resp = JSON.parse(line);
55
+ return resp.transformed;
56
+ }
57
+ /**
58
+ * Instruments an ESM module by requesting transformation from the Rust parent.
59
+ */
60
+ function transformModule(filename, code) {
61
+ let resolvedFilename = filename;
62
+ try {
63
+ resolvedFilename = realpathSync(filename);
64
+ }
65
+ catch { }
66
+ if (!resolvedFilename.startsWith(resolvedBasedir)) {
67
+ log("verbose", `Ignoring module outside basedir: ${filename}`);
68
+ return "";
69
+ }
70
+ log("info", `Loading module ${filename} (${Math.ceil(code.length / 1024)}KB)`);
71
+ log("verbose", `Instrumenting ${filename}`);
72
+ const transformed = requestTransform(filename, code);
73
+ // Send code size metadata back to the main thread
74
+ port2.postMessage({ type: "metadata", codeSize: code.length });
75
+ return transformed;
76
+ }
77
+ /**
78
+ * Module hooks initialization.
79
+ * (Registered in approx.ts.)
80
+ */
81
+ export async function initialize({ opts, port2: p2, ipcFifoPath, hooksFifoPath }) {
82
+ port2 = p2;
83
+ const basedir = opts.basedir;
84
+ try {
85
+ resolvedBasedir = realpathSync(basedir);
86
+ }
87
+ catch {
88
+ resolvedBasedir = basedir;
89
+ }
90
+ ipcFd = openSync(ipcFifoPath, "w");
91
+ hooksFd = openSync(hooksFifoPath, "r");
92
+ }
93
+ /**
94
+ * Module resolve hook.
95
+ */
96
+ export async function resolve(specifier, context, nextResolve) {
97
+ if (context.parentURL === `file://${import.meta.dirname}/approx.js`)
98
+ context.parentURL = undefined; // approx.js is entry
99
+ log("verbose", `Resolving ${specifier}${context.parentURL ? ` from ${context.parentURL}` : " (entry)"}`);
100
+ const str = specifier.startsWith("node:") ? specifier.substring(5) : specifier;
101
+ if (Module.isBuiltin(str) && !WHITELISTED.has(str))
102
+ return {
103
+ format: "commonjs",
104
+ url: `node:${str}`, // signals to load hook that this is a sandboxed builtin
105
+ shortCircuit: true
106
+ };
107
+ // Simplified: no TypeScript module resolution (unlike Jelly)
108
+ return nextResolve(str);
109
+ }
110
+ /**
111
+ * Module loading hook.
112
+ */
113
+ export async function load(url, context, nextLoad) {
114
+ try {
115
+ const ext = extname(url);
116
+ if ([".ts", ".tsx", ".mts", ".cts", ".jsx"].includes(ext))
117
+ context.format = "module";
118
+ else if (ext === "" && url.startsWith("file://")) {
119
+ try {
120
+ const content = readFileSync(fileURLToPath(url), "utf8");
121
+ if (content.startsWith("#!"))
122
+ context.format = "commonjs";
123
+ }
124
+ catch { }
125
+ }
126
+ const sandboxedBuiltin = url.startsWith("node:");
127
+ log("verbose", `Loading ${url} (ESM loader, format: ${sandboxedBuiltin ? "sandboxed builtin" : context.format})`);
128
+ const res = await nextLoad(url, context); // TODO: fails with ERR_UNSUPPORTED_ESM_URL_SCHEME on https and http
129
+ if (sandboxedBuiltin) {
130
+ const m = url.substring(5);
131
+ log("verbose", `Intercepting import "${m}"`);
132
+ res.source = `const m = globalThis.${PREFIX}builtin["${m}"];`;
133
+ for (const p of Object.getOwnPropertyNames(require(m)))
134
+ res.source += `module.exports["${p}"] = m["${p}"];`;
135
+ return res;
136
+ }
137
+ if (res.format === "builtin" || res.format === "commonjs" || res.format === "json")
138
+ return res;
139
+ if (res.format !== "module")
140
+ log("warn", `Ignoring ${url} (format: ${res.format})`);
141
+ else if (!url.startsWith("file://"))
142
+ log("error", `Error: Unsupported URL scheme ${url}`);
143
+ else if (!(res.source instanceof Uint8Array))
144
+ log("error", `Error: Unexpected source type for ${url}`);
145
+ else {
146
+ const filename = fileURLToPath(url);
147
+ const source = new TextDecoder().decode(res.source);
148
+ const transformed = transformModule(filename, source);
149
+ return {
150
+ format: "module",
151
+ shortCircuit: true,
152
+ source: transformed
153
+ };
154
+ }
155
+ }
156
+ catch (err) {
157
+ log("error", `Suppressed exception at module load: ${err instanceof Error ? err.stack : err}`);
158
+ }
159
+ return {
160
+ format: "commonjs",
161
+ shortCircuit: true,
162
+ source: `module.exports = ${PREFIX}proxy`
163
+ };
164
+ }
165
+ /**
166
+ * TTY doesn't work for hooks thread, so logging is done via the approximate interpretation thread.
167
+ * Note: the logging from this thread is asynchronous so the messages may be written delayed to the log!
168
+ */
169
+ function log(level, str) {
170
+ port2.postMessage({ type: "log", level, str });
171
+ }
172
+ const require = createRequire(import.meta.url);
@@ -0,0 +1,66 @@
1
+ // Logger that writes to stdout (matching Jelly).
2
+ // IPC uses dedicated FIFOs, so stdout is free for logging.
3
+ import { openSync, truncateSync, writeSync } from "fs";
4
+ const LEVELS = {
5
+ error: 0,
6
+ warn: 1,
7
+ info: 2,
8
+ verbose: 3,
9
+ debug: 4,
10
+ };
11
+ const COLORS = {
12
+ error: "\x1b[31m", // red
13
+ warn: "\x1b[33m", // yellow
14
+ verbose: "\x1b[32m", // green
15
+ debug: "\x1b[36m", // cyan
16
+ };
17
+ const RESET = "\x1b[0m";
18
+ const WHITE = "\x1b[97m";
19
+ const BOLD = "\x1b[1m";
20
+ const CLEAR = "\x1b[0K";
21
+ // Save stdout before sandboxing patches it.
22
+ const stdout = process.stdout;
23
+ let useColors = stdout.isTTY ?? false;
24
+ let currentLevel = LEVELS.info;
25
+ let logFd;
26
+ function shouldLog(level) {
27
+ return (LEVELS[level] ?? 0) <= currentLevel;
28
+ }
29
+ function log(level, msg) {
30
+ if (shouldLog(level)) {
31
+ if (logFd !== undefined) {
32
+ writeSync(logFd, `${msg}\n`);
33
+ }
34
+ else {
35
+ const color = useColors ? (COLORS[level] ?? "") : "";
36
+ const reset = color ? RESET : "";
37
+ stdout.write(`${color}${msg}${reset}\n`);
38
+ }
39
+ }
40
+ }
41
+ const logger = {
42
+ get level() { return Object.entries(LEVELS).find(([_, v]) => v === currentLevel)?.[0] ?? "info"; },
43
+ set level(l) { currentLevel = LEVELS[l] ?? LEVELS.info; },
44
+ error: (msg) => log("error", msg),
45
+ warn: (msg) => log("warn", msg),
46
+ warning: (msg) => log("warn", msg),
47
+ info: (msg) => log("info", msg),
48
+ verbose: (msg) => log("verbose", msg),
49
+ debug: (msg) => log("debug", msg),
50
+ isInfoEnabled: () => shouldLog("info"),
51
+ isVerboseEnabled: () => shouldLog("verbose"),
52
+ isDebugEnabled: () => shouldLog("debug"),
53
+ };
54
+ export default logger;
55
+ export function logToFile(path) {
56
+ truncateSync(path, 0);
57
+ logFd = openSync(path, "w");
58
+ useColors = false;
59
+ }
60
+ function writeStdOut(s) {
61
+ stdout.write(WHITE + BOLD + s.substring(0, stdout.columns) + RESET + CLEAR + "\r");
62
+ }
63
+ export function writeStdOutIfActive(s) {
64
+ if (!logFd && useColors && currentLevel === LEVELS.info)
65
+ writeStdOut(s);
66
+ }
@@ -0,0 +1,10 @@
1
+ // Options received from the parent Rust process via argv[2].
2
+ export const options = {
3
+ basedir: "",
4
+ loglevel: "info",
5
+ logfile: undefined,
6
+ printProgress: false,
7
+ };
8
+ export function setOptions(opts) {
9
+ Object.assign(options, opts);
10
+ }
@@ -0,0 +1,119 @@
1
+ // Proxy objects for untracked values during approximate interpretation.
2
+ // Copied from Jelly's src/approx/proxy.ts.
3
+ const handler = {
4
+ get(target, p, receiver) {
5
+ switch (p) {
6
+ case "length":
7
+ if (receiver === theArgumentsProxy)
8
+ return 10; // number of mock arguments provided at forced execution of functions
9
+ else
10
+ return 1; // value for other array lengths
11
+ case Symbol.toPrimitive:
12
+ return function (hint) {
13
+ switch (hint) {
14
+ case "number":
15
+ return 0;
16
+ case "string":
17
+ return "";
18
+ case "default":
19
+ return "0"; // TODO: appropriate value?
20
+ }
21
+ };
22
+ case Symbol.iterator:
23
+ return function () {
24
+ let index = 0;
25
+ return {
26
+ next: () => {
27
+ if (index++ < 3)
28
+ return { value: theProxy, done: false };
29
+ else
30
+ return { value: undefined, done: true };
31
+ }
32
+ };
33
+ };
34
+ // TODO: other standard symbols that should be modeled? see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
35
+ default:
36
+ const desc = Object.getOwnPropertyDescriptor(target, p);
37
+ if (desc && !desc.configurable && !desc.writable) // non-writable, non-configurable properties must return target value
38
+ return target[p];
39
+ return theProxy;
40
+ }
41
+ },
42
+ set() {
43
+ return false; // if returning true, some native functions get stuck in proxy loop
44
+ },
45
+ has() {
46
+ return true;
47
+ },
48
+ apply() {
49
+ return theProxy;
50
+ },
51
+ construct() {
52
+ return theProxy;
53
+ },
54
+ defineProperty() {
55
+ return false;
56
+ },
57
+ deleteProperty() {
58
+ return true;
59
+ },
60
+ getOwnPropertyDescriptor(target, property) {
61
+ if (property === "prototype")
62
+ return Object.getOwnPropertyDescriptor(target, property);
63
+ return {
64
+ configurable: true,
65
+ enumerable: true,
66
+ value: theProxy,
67
+ writable: true
68
+ };
69
+ },
70
+ isExtensible() {
71
+ return true;
72
+ },
73
+ setPrototypeOf() {
74
+ return false;
75
+ }
76
+ };
77
+ export const theProxy = new Proxy(function theProxy() { }, handler);
78
+ export const theArgumentsProxy = new Proxy([], handler);
79
+ export function makeBaseProxy(target) {
80
+ if (!target || !(typeof target === "object" || typeof target === "function"))
81
+ return theProxy;
82
+ return new Proxy(target, {
83
+ get(target, prop, receiver) {
84
+ if (prop in target)
85
+ return Reflect.get(target, prop, receiver);
86
+ else {
87
+ const desc = Object.getOwnPropertyDescriptor(target, prop);
88
+ if (desc && !desc.configurable && !desc.writable) // non-writable, non-configurable properties must return target value
89
+ return target[prop];
90
+ return theProxy;
91
+ }
92
+ },
93
+ has(_target, _prop) {
94
+ return true;
95
+ }
96
+ });
97
+ }
98
+ export function isProxy(x) {
99
+ return x === theProxy || x === theArgumentsProxy;
100
+ }
101
+ export function stdlibProxy(obj) {
102
+ return new Proxy(obj, {
103
+ get: function (target, prop) {
104
+ const desc = Object.getOwnPropertyDescriptor(target, prop);
105
+ if (desc && !desc.configurable && !desc.writable) // non-writable, non-configurable properties must return target value
106
+ return target[prop];
107
+ if (typeof desc?.value === "function")
108
+ return theProxy;
109
+ return desc?.value;
110
+ }
111
+ });
112
+ }
113
+ export function makeModuleProxy(target) {
114
+ return new Proxy(target, {
115
+ get(target, prop, _receiver) {
116
+ return prop === "constructor" ? theProxy : target[prop];
117
+ }
118
+ });
119
+ }
@@ -0,0 +1,84 @@
1
+ // Sandboxes global builtins for approximate interpretation.
2
+ // Adapted from Jelly's src/approx/sandbox.ts.
3
+ import Module from "module";
4
+ import { theProxy } from "./proxy.js";
5
+ /** Prefix for special global variables. */
6
+ const PREFIX = "_J$";
7
+ /**
8
+ * Names of the special _J$* globals that should be frozen. */
9
+ const SPECIALS = new Set(["start", "pw", "dpr", "alloc", "init", "method", "comp", "new", "enter", "catch", "loop", "eval", "cr", "freeze", "fun", "require", "this"]
10
+ .map(s => PREFIX + s));
11
+ /**
12
+ * Standard library modules that are not mocked.
13
+ */
14
+ export const WHITELISTED = new Set([
15
+ "events", "buffer", "assert", "assert/strict", "constants", "crypto",
16
+ "string_decoder", "util", "util/types", "path", "url", "tty", "sys"
17
+ ]);
18
+ /**
19
+ * Sandboxes global builtins.
20
+ */
21
+ export function patchGlobalBuiltins() {
22
+ const emptyFunction = function () { };
23
+ const invokeCallbackWithArgs = function (cb, ...args) { cb(...args); };
24
+ const invokeCallbackWithArgs2 = function (cb, _c, ...args) { cb(...args); };
25
+ // replace globals
26
+ const g = globalThis;
27
+ g.clearImmediate = g.clearInterval = g.clearTimeout = g.fetch = emptyFunction;
28
+ g.setImmediate = g.queueMicrotask = invokeCallbackWithArgs;
29
+ g.setInterval = g.setTimeout = invokeCallbackWithArgs2;
30
+ // replace process.*
31
+ const p = process;
32
+ p.on = p.send = p.chdir = p.exit = p.reallyExit = p.abort = p.dlopen = p.kill = p.openStdin = p.binding = p._linkedBinding = p.removeAllListeners = p.removeListener = p.off = theProxy;
33
+ p.nextTick = invokeCallbackWithArgs;
34
+ for (const prop of ["stdin", "stdout", "stderr"])
35
+ Object.defineProperty(p, prop, { value: theProxy });
36
+ // replace console.*
37
+ const c = console;
38
+ for (const p of Object.getOwnPropertyNames(Object.getPrototypeOf(console)))
39
+ if (typeof c[p] === "function")
40
+ c[p] = emptyFunction;
41
+ c._stdout = c._stderr = theProxy;
42
+ // replace Error.*, Atomics.*, Module.*
43
+ Error.captureStackTrace = emptyFunction; // TODO: Error (parser writes to Error.prepareStackTrace)
44
+ Atomics.wait = Atomics.waitAsync = theProxy;
45
+ Module.register = function () { };
46
+ // replace Module._load
47
+ const realLoad = Module._load;
48
+ Module._load = function (request, parent, isMain) {
49
+ const result = realLoad.call(this, request, parent, isMain);
50
+ const name = request.startsWith("node:") ? request.substring(5) : request;
51
+ if (Module.isBuiltin(name) && !WHITELISTED.has(name))
52
+ return globalThis[PREFIX + "builtin"]?.[name] ?? theProxy;
53
+ return result;
54
+ };
55
+ // define typical test framework functions
56
+ g.describe = g.it = g.before = g.beforeAll = g.beforeEach = g.after = g.afterAll = g.afterEach = g.test = g.define = emptyFunction;
57
+ g.describe.skip = emptyFunction;
58
+ g.expect = theProxy;
59
+ // TODO: assign theProxy to all undeclared variables?
60
+ g.Worker = theProxy;
61
+ // DOM specific interface
62
+ g.window = g.document = theProxy;
63
+ // freeze objects and properties
64
+ for (const x of [
65
+ Array, ArrayBuffer, BigInt, Boolean, DataView, Date, Error, AggregateError, EvalError, RangeError, ReferenceError,
66
+ SyntaxError, TypeError, URIError, Intl, Int8Array, Uint8Array, Uint16Array, Int16Array, Uint32Array, Int32Array,
67
+ Float32Array, Float64Array, Uint8ClampedArray, BigUint64Array, BigInt64Array, FinalizationRegistry, JSON, Map,
68
+ Math, Number, Object, Promise, Proxy, Reflect, RegExp, Set, String, Symbol, WeakMap, WeakRef, WeakSet
69
+ ]) {
70
+ Object.freeze(x);
71
+ if ("prototype" in x)
72
+ Object.freeze(x.prototype);
73
+ }
74
+ Object.freeze(Function);
75
+ for (const p of ["apply", "bind", "call"]) // must allow overwriting toString at functions
76
+ Object.defineProperty(Function.prototype, p, { configurable: false, writable: false });
77
+ for (const p of ["globalThis", "global", "Infinity", "NaN", "undefined", "eval", "isFinite", "isNaN", "parseFloat", "parseInt", ...SPECIALS, "$log"])
78
+ Object.defineProperty(g, p, { configurable: false, writable: false });
79
+ Object.freeze(Module._extensions);
80
+ Object.freeze(Module);
81
+ Object.freeze(Module.prototype);
82
+ Object.freeze(process);
83
+ Object.freeze(console);
84
+ }
@@ -0,0 +1,3 @@
1
+ // Type definitions for IPC messages and hint data structures.
2
+ // Based on Jelly's typings/hints.ts and misc/util.ts.
3
+ export {};