@run0/jiki 0.1.0

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.
Files changed (152) hide show
  1. package/dist/browser-bundle.d.ts +40 -0
  2. package/dist/builtins.d.ts +22 -0
  3. package/dist/code-transform.d.ts +7 -0
  4. package/dist/config/cdn.d.ts +13 -0
  5. package/dist/container.d.ts +101 -0
  6. package/dist/dev-server.d.ts +69 -0
  7. package/dist/errors.d.ts +19 -0
  8. package/dist/frameworks/code-transforms.d.ts +32 -0
  9. package/dist/frameworks/next-api-handler.d.ts +72 -0
  10. package/dist/frameworks/next-dev-server.d.ts +141 -0
  11. package/dist/frameworks/next-html-generator.d.ts +36 -0
  12. package/dist/frameworks/next-route-resolver.d.ts +19 -0
  13. package/dist/frameworks/next-shims.d.ts +78 -0
  14. package/dist/frameworks/remix-dev-server.d.ts +47 -0
  15. package/dist/frameworks/sveltekit-dev-server.d.ts +43 -0
  16. package/dist/frameworks/vite-dev-server.d.ts +50 -0
  17. package/dist/fs-errors.d.ts +36 -0
  18. package/dist/index.cjs +14916 -0
  19. package/dist/index.cjs.map +1 -0
  20. package/dist/index.d.ts +61 -0
  21. package/dist/index.mjs +14898 -0
  22. package/dist/index.mjs.map +1 -0
  23. package/dist/kernel.d.ts +48 -0
  24. package/dist/memfs.d.ts +144 -0
  25. package/dist/metrics.d.ts +78 -0
  26. package/dist/module-resolver.d.ts +60 -0
  27. package/dist/network-interceptor.d.ts +71 -0
  28. package/dist/npm/cache.d.ts +76 -0
  29. package/dist/npm/index.d.ts +60 -0
  30. package/dist/npm/lockfile-reader.d.ts +32 -0
  31. package/dist/npm/pnpm.d.ts +18 -0
  32. package/dist/npm/registry.d.ts +45 -0
  33. package/dist/npm/resolver.d.ts +39 -0
  34. package/dist/npm/sync-installer.d.ts +18 -0
  35. package/dist/npm/tarball.d.ts +4 -0
  36. package/dist/npm/workspaces.d.ts +46 -0
  37. package/dist/persistence.d.ts +94 -0
  38. package/dist/plugin.d.ts +156 -0
  39. package/dist/polyfills/assert.d.ts +30 -0
  40. package/dist/polyfills/child_process.d.ts +116 -0
  41. package/dist/polyfills/chokidar.d.ts +18 -0
  42. package/dist/polyfills/crypto.d.ts +49 -0
  43. package/dist/polyfills/events.d.ts +28 -0
  44. package/dist/polyfills/fs.d.ts +82 -0
  45. package/dist/polyfills/http.d.ts +147 -0
  46. package/dist/polyfills/module.d.ts +29 -0
  47. package/dist/polyfills/net.d.ts +53 -0
  48. package/dist/polyfills/os.d.ts +91 -0
  49. package/dist/polyfills/path.d.ts +96 -0
  50. package/dist/polyfills/perf_hooks.d.ts +21 -0
  51. package/dist/polyfills/process.d.ts +99 -0
  52. package/dist/polyfills/querystring.d.ts +15 -0
  53. package/dist/polyfills/readdirp.d.ts +18 -0
  54. package/dist/polyfills/readline.d.ts +32 -0
  55. package/dist/polyfills/stream.d.ts +106 -0
  56. package/dist/polyfills/stubs.d.ts +737 -0
  57. package/dist/polyfills/tty.d.ts +25 -0
  58. package/dist/polyfills/url.d.ts +41 -0
  59. package/dist/polyfills/util.d.ts +61 -0
  60. package/dist/polyfills/v8.d.ts +43 -0
  61. package/dist/polyfills/vm.d.ts +76 -0
  62. package/dist/polyfills/worker-threads.d.ts +77 -0
  63. package/dist/polyfills/ws.d.ts +32 -0
  64. package/dist/polyfills/zlib.d.ts +87 -0
  65. package/dist/runtime-helpers.d.ts +4 -0
  66. package/dist/runtime-interface.d.ts +39 -0
  67. package/dist/sandbox.d.ts +69 -0
  68. package/dist/server-bridge.d.ts +55 -0
  69. package/dist/shell-commands.d.ts +2 -0
  70. package/dist/shell.d.ts +101 -0
  71. package/dist/transpiler.d.ts +47 -0
  72. package/dist/type-checker.d.ts +57 -0
  73. package/dist/types/package-json.d.ts +17 -0
  74. package/dist/utils/binary-encoding.d.ts +4 -0
  75. package/dist/utils/hash.d.ts +6 -0
  76. package/dist/utils/safe-path.d.ts +6 -0
  77. package/dist/worker-runtime.d.ts +34 -0
  78. package/package.json +59 -0
  79. package/src/browser-bundle.ts +498 -0
  80. package/src/builtins.ts +222 -0
  81. package/src/code-transform.ts +183 -0
  82. package/src/config/cdn.ts +17 -0
  83. package/src/container.ts +343 -0
  84. package/src/dev-server.ts +322 -0
  85. package/src/errors.ts +604 -0
  86. package/src/frameworks/code-transforms.ts +667 -0
  87. package/src/frameworks/next-api-handler.ts +366 -0
  88. package/src/frameworks/next-dev-server.ts +1252 -0
  89. package/src/frameworks/next-html-generator.ts +585 -0
  90. package/src/frameworks/next-route-resolver.ts +521 -0
  91. package/src/frameworks/next-shims.ts +1084 -0
  92. package/src/frameworks/remix-dev-server.ts +163 -0
  93. package/src/frameworks/sveltekit-dev-server.ts +197 -0
  94. package/src/frameworks/vite-dev-server.ts +370 -0
  95. package/src/fs-errors.ts +118 -0
  96. package/src/index.ts +188 -0
  97. package/src/kernel.ts +381 -0
  98. package/src/memfs.ts +1006 -0
  99. package/src/metrics.ts +140 -0
  100. package/src/module-resolver.ts +511 -0
  101. package/src/network-interceptor.ts +143 -0
  102. package/src/npm/cache.ts +172 -0
  103. package/src/npm/index.ts +377 -0
  104. package/src/npm/lockfile-reader.ts +105 -0
  105. package/src/npm/pnpm.ts +108 -0
  106. package/src/npm/registry.ts +120 -0
  107. package/src/npm/resolver.ts +339 -0
  108. package/src/npm/sync-installer.ts +217 -0
  109. package/src/npm/tarball.ts +136 -0
  110. package/src/npm/workspaces.ts +255 -0
  111. package/src/persistence.ts +235 -0
  112. package/src/plugin.ts +293 -0
  113. package/src/polyfills/assert.ts +164 -0
  114. package/src/polyfills/child_process.ts +535 -0
  115. package/src/polyfills/chokidar.ts +52 -0
  116. package/src/polyfills/crypto.ts +433 -0
  117. package/src/polyfills/events.ts +178 -0
  118. package/src/polyfills/fs.ts +297 -0
  119. package/src/polyfills/http.ts +478 -0
  120. package/src/polyfills/module.ts +97 -0
  121. package/src/polyfills/net.ts +123 -0
  122. package/src/polyfills/os.ts +108 -0
  123. package/src/polyfills/path.ts +169 -0
  124. package/src/polyfills/perf_hooks.ts +30 -0
  125. package/src/polyfills/process.ts +349 -0
  126. package/src/polyfills/querystring.ts +66 -0
  127. package/src/polyfills/readdirp.ts +72 -0
  128. package/src/polyfills/readline.ts +80 -0
  129. package/src/polyfills/stream.ts +610 -0
  130. package/src/polyfills/stubs.ts +600 -0
  131. package/src/polyfills/tty.ts +43 -0
  132. package/src/polyfills/url.ts +97 -0
  133. package/src/polyfills/util.ts +173 -0
  134. package/src/polyfills/v8.ts +62 -0
  135. package/src/polyfills/vm.ts +111 -0
  136. package/src/polyfills/worker-threads.ts +189 -0
  137. package/src/polyfills/ws.ts +73 -0
  138. package/src/polyfills/zlib.ts +244 -0
  139. package/src/runtime-helpers.ts +83 -0
  140. package/src/runtime-interface.ts +46 -0
  141. package/src/sandbox.ts +178 -0
  142. package/src/server-bridge.ts +473 -0
  143. package/src/service-worker.ts +153 -0
  144. package/src/shell-commands.ts +708 -0
  145. package/src/shell.ts +795 -0
  146. package/src/transpiler.ts +282 -0
  147. package/src/type-checker.ts +241 -0
  148. package/src/types/package-json.ts +17 -0
  149. package/src/utils/binary-encoding.ts +38 -0
  150. package/src/utils/hash.ts +24 -0
  151. package/src/utils/safe-path.ts +38 -0
  152. package/src/worker-runtime.ts +42 -0
@@ -0,0 +1,97 @@
1
+ export const URL = globalThis.URL;
2
+ export const URLSearchParams = globalThis.URLSearchParams;
3
+
4
+ export function parse(
5
+ urlString: string,
6
+ parseQueryString = false,
7
+ slashesDenoteHost = false,
8
+ ): Record<string, unknown> {
9
+ try {
10
+ const parsed = new globalThis.URL(urlString, "http://localhost");
11
+ const result: Record<string, unknown> = {
12
+ protocol: parsed.protocol,
13
+ slashes: parsed.protocol ? true : null,
14
+ auth: parsed.username
15
+ ? parsed.password
16
+ ? `${parsed.username}:${parsed.password}`
17
+ : parsed.username
18
+ : null,
19
+ host: parsed.host,
20
+ port: parsed.port || null,
21
+ hostname: parsed.hostname,
22
+ hash: parsed.hash || null,
23
+ search: parsed.search || null,
24
+ query: parseQueryString
25
+ ? Object.fromEntries(parsed.searchParams)
26
+ : parsed.search?.slice(1) || null,
27
+ pathname: parsed.pathname,
28
+ path: parsed.pathname + (parsed.search || ""),
29
+ href: parsed.href,
30
+ };
31
+ return result;
32
+ } catch {
33
+ return {
34
+ protocol: null,
35
+ slashes: null,
36
+ auth: null,
37
+ host: null,
38
+ port: null,
39
+ hostname: null,
40
+ hash: null,
41
+ search: null,
42
+ query: null,
43
+ pathname: urlString,
44
+ path: urlString,
45
+ href: urlString,
46
+ };
47
+ }
48
+ }
49
+
50
+ export function format(urlObj: Record<string, unknown>): string {
51
+ if (typeof urlObj === "string") return urlObj;
52
+ let result = "";
53
+ if (urlObj.protocol) result += urlObj.protocol;
54
+ if (urlObj.slashes) result += "//";
55
+ if (urlObj.auth) result += urlObj.auth + "@";
56
+ if (urlObj.hostname) result += urlObj.hostname;
57
+ if (urlObj.port) result += ":" + urlObj.port;
58
+ if (urlObj.pathname) result += urlObj.pathname;
59
+ if (urlObj.search) result += urlObj.search;
60
+ if (urlObj.hash) result += urlObj.hash;
61
+ return result;
62
+ }
63
+
64
+ export function resolve(from: string, to: string): string {
65
+ return new globalThis.URL(to, from).href;
66
+ }
67
+
68
+ export function fileURLToPath(url: string | URL): string {
69
+ const urlStr = typeof url === "string" ? url : url.href;
70
+ if (!urlStr.startsWith("file://")) throw new Error("Invalid file URL");
71
+ return decodeURIComponent(urlStr.replace(/^file:\/\//, ""));
72
+ }
73
+
74
+ export function pathToFileURL(path: string): URL {
75
+ return new globalThis.URL(
76
+ "file://" + encodeURIComponent(path).replace(/%2F/g, "/"),
77
+ );
78
+ }
79
+
80
+ export function domainToASCII(domain: string): string {
81
+ return domain;
82
+ }
83
+ export function domainToUnicode(domain: string): string {
84
+ return domain;
85
+ }
86
+
87
+ export default {
88
+ URL,
89
+ URLSearchParams,
90
+ parse,
91
+ format,
92
+ resolve,
93
+ fileURLToPath,
94
+ pathToFileURL,
95
+ domainToASCII,
96
+ domainToUnicode,
97
+ };
@@ -0,0 +1,173 @@
1
+ export function format(fmt: unknown, ...args: unknown[]): string {
2
+ if (typeof fmt !== "string")
3
+ return args.length
4
+ ? [fmt, ...args].map(a => inspect(a)).join(" ")
5
+ : inspect(fmt);
6
+ let i = 0;
7
+ return fmt.replace(/%[sdjifoO%]/g, m => {
8
+ if (m === "%%") return "%";
9
+ if (i >= args.length) return m;
10
+ const arg = args[i++];
11
+ switch (m) {
12
+ case "%s":
13
+ return String(arg);
14
+ case "%d":
15
+ return String(Number(arg));
16
+ case "%i":
17
+ return String(Math.floor(Number(arg)));
18
+ case "%f":
19
+ return String(parseFloat(String(arg)));
20
+ case "%j":
21
+ try {
22
+ return JSON.stringify(arg);
23
+ } catch {
24
+ return "[Circular]";
25
+ }
26
+ case "%o":
27
+ case "%O":
28
+ return inspect(arg);
29
+ default:
30
+ return m;
31
+ }
32
+ });
33
+ }
34
+
35
+ export function inspect(
36
+ obj: unknown,
37
+ opts?: { depth?: number; colors?: boolean },
38
+ ): string {
39
+ if (obj === null) return "null";
40
+ if (obj === undefined) return "undefined";
41
+ if (typeof obj === "string") return `'${obj}'`;
42
+ if (
43
+ typeof obj === "number" ||
44
+ typeof obj === "boolean" ||
45
+ typeof obj === "bigint"
46
+ )
47
+ return String(obj);
48
+ if (typeof obj === "function")
49
+ return `[Function: ${obj.name || "anonymous"}]`;
50
+ if (typeof obj === "symbol") return obj.toString();
51
+ if (obj instanceof Date) return obj.toISOString();
52
+ if (obj instanceof RegExp) return obj.toString();
53
+ if (obj instanceof Error) return `${obj.name}: ${obj.message}`;
54
+ if (Array.isArray(obj)) return `[ ${obj.map(v => inspect(v)).join(", ")} ]`;
55
+ if (obj instanceof Map)
56
+ return `Map(${obj.size}) { ${[...obj.entries()]
57
+ .map(([k, v]) => `${inspect(k)} => ${inspect(v)}`)
58
+ .join(", ")} }`;
59
+ if (obj instanceof Set)
60
+ return `Set(${obj.size}) { ${[...obj].map(v => inspect(v)).join(", ")} }`;
61
+ try {
62
+ return JSON.stringify(obj, null, 2);
63
+ } catch {
64
+ return "[Object]";
65
+ }
66
+ }
67
+ inspect.custom = Symbol.for("nodejs.util.inspect.custom");
68
+
69
+ export function inherits(ctor: Function, superCtor: Function): void {
70
+ Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
71
+ Object.setPrototypeOf(ctor, superCtor);
72
+ }
73
+
74
+ export function deprecate<T extends Function>(fn: T, msg: string): T {
75
+ let warned = false;
76
+ return function (this: unknown, ...args: unknown[]) {
77
+ if (!warned) {
78
+ console.warn("DeprecationWarning:", msg);
79
+ warned = true;
80
+ }
81
+ return fn.apply(this, args);
82
+ } as unknown as T;
83
+ }
84
+
85
+ export function promisify<T extends Function>(
86
+ fn: T,
87
+ ): (...args: unknown[]) => Promise<unknown> {
88
+ return (...args: unknown[]) =>
89
+ new Promise((resolve, reject) => {
90
+ fn(...args, (err: Error | null, ...result: unknown[]) => {
91
+ if (err) reject(err);
92
+ else resolve(result.length <= 1 ? result[0] : result);
93
+ });
94
+ });
95
+ }
96
+
97
+ export function callbackify(
98
+ fn: (...args: unknown[]) => Promise<unknown>,
99
+ ): (...args: unknown[]) => void {
100
+ return (...args: unknown[]) => {
101
+ const cb = args.pop() as Function;
102
+ fn(...args)
103
+ .then(result => cb(null, result))
104
+ .catch(err => cb(err));
105
+ };
106
+ }
107
+
108
+ export function debuglog(section: string): (...args: unknown[]) => void {
109
+ const enabled =
110
+ typeof process !== "undefined" &&
111
+ process.env?.NODE_DEBUG?.includes(section);
112
+ return enabled
113
+ ? (...args) =>
114
+ console.error(`${section.toUpperCase()} ${process?.pid || 0}:`, ...args)
115
+ : () => {};
116
+ }
117
+
118
+ export function isDeepStrictEqual(a: unknown, b: unknown): boolean {
119
+ if (a === b) return true;
120
+ if (typeof a !== typeof b) return false;
121
+ if (a === null || b === null) return false;
122
+ if (typeof a !== "object") return false;
123
+ if (Array.isArray(a) && Array.isArray(b)) {
124
+ if (a.length !== b.length) return false;
125
+ return a.every((v, i) => isDeepStrictEqual(v, b[i]));
126
+ }
127
+ const keysA = Object.keys(a as object);
128
+ const keysB = Object.keys(b as object);
129
+ if (keysA.length !== keysB.length) return false;
130
+ return keysA.every(k =>
131
+ isDeepStrictEqual(
132
+ (a as Record<string, unknown>)[k],
133
+ (b as Record<string, unknown>)[k],
134
+ ),
135
+ );
136
+ }
137
+
138
+ export const types = {
139
+ isDate: (v: unknown): v is Date => v instanceof Date,
140
+ isRegExp: (v: unknown): v is RegExp => v instanceof RegExp,
141
+ isPromise: (v: unknown): v is Promise<unknown> => v instanceof Promise,
142
+ isMap: (v: unknown): v is Map<unknown, unknown> => v instanceof Map,
143
+ isSet: (v: unknown): v is Set<unknown> => v instanceof Set,
144
+ isTypedArray: (v: unknown): boolean =>
145
+ ArrayBuffer.isView(v) && !(v instanceof DataView),
146
+ isUint8Array: (v: unknown): v is Uint8Array => v instanceof Uint8Array,
147
+ isArrayBuffer: (v: unknown): v is ArrayBuffer => v instanceof ArrayBuffer,
148
+ isSharedArrayBuffer: (v: unknown): boolean =>
149
+ typeof SharedArrayBuffer !== "undefined" && v instanceof SharedArrayBuffer,
150
+ isProxy: (_v: unknown): boolean => false,
151
+ isNativeError: (v: unknown): v is Error => v instanceof Error,
152
+ isGeneratorFunction: (v: unknown): boolean =>
153
+ typeof v === "function" && v.constructor?.name === "GeneratorFunction",
154
+ isAsyncFunction: (v: unknown): boolean =>
155
+ typeof v === "function" && v.constructor?.name === "AsyncFunction",
156
+ };
157
+
158
+ export class TextEncoder extends globalThis.TextEncoder {}
159
+ export class TextDecoder extends globalThis.TextDecoder {}
160
+
161
+ export default {
162
+ format,
163
+ inspect,
164
+ inherits,
165
+ deprecate,
166
+ promisify,
167
+ callbackify,
168
+ debuglog,
169
+ isDeepStrictEqual,
170
+ types,
171
+ TextEncoder,
172
+ TextDecoder,
173
+ };
@@ -0,0 +1,62 @@
1
+ export function getHeapStatistics(): Record<string, number> {
2
+ return {
3
+ total_heap_size: 30 * 1024 * 1024,
4
+ used_heap_size: 20 * 1024 * 1024,
5
+ heap_size_limit: 512 * 1024 * 1024,
6
+ total_physical_size: 30 * 1024 * 1024,
7
+ total_available_size: 400 * 1024 * 1024,
8
+ malloced_memory: 0,
9
+ peak_malloced_memory: 0,
10
+ does_zap_garbage: 0,
11
+ number_of_native_contexts: 1,
12
+ number_of_detached_contexts: 0,
13
+ total_global_handles_size: 0,
14
+ used_global_handles_size: 0,
15
+ external_memory: 0,
16
+ };
17
+ }
18
+ export function getHeapSpaceStatistics(): Record<string, unknown>[] {
19
+ return [];
20
+ }
21
+ export function getHeapSnapshot(): unknown {
22
+ return {
23
+ toString() {
24
+ return "{}";
25
+ },
26
+ };
27
+ }
28
+ export function writeHeapSnapshot(_filename?: string): string {
29
+ return "";
30
+ }
31
+ export function setFlagsFromString(_flags: string): void {}
32
+ export function serialize(value: unknown): Uint8Array {
33
+ return new TextEncoder().encode(JSON.stringify(value));
34
+ }
35
+ export function deserialize(buffer: Uint8Array): unknown {
36
+ return JSON.parse(new TextDecoder().decode(buffer));
37
+ }
38
+ export const DefaultSerializer = class {
39
+ writeHeader() {}
40
+ writeValue(_v: unknown) {}
41
+ releaseBuffer() {
42
+ return new Uint8Array(0);
43
+ }
44
+ };
45
+ export const DefaultDeserializer = class {
46
+ constructor(_buf: Uint8Array) {}
47
+ readHeader() {}
48
+ readValue() {
49
+ return null;
50
+ }
51
+ };
52
+ export default {
53
+ getHeapStatistics,
54
+ getHeapSpaceStatistics,
55
+ getHeapSnapshot,
56
+ writeHeapSnapshot,
57
+ setFlagsFromString,
58
+ serialize,
59
+ deserialize,
60
+ DefaultSerializer,
61
+ DefaultDeserializer,
62
+ };
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Browser polyfill for Node.js `vm` module.
3
+ *
4
+ * **IMPORTANT: Security Limitation**
5
+ *
6
+ * This is NOT a true sandbox. In Node.js, `vm` creates a V8 context with its own
7
+ * global object, providing isolation from the host environment. In the browser,
8
+ * this polyfill uses `new Function()` which executes code in the same JavaScript
9
+ * realm as the host page.
10
+ *
11
+ * Implications:
12
+ * - Code executed via `runInContext()` / `runInNewContext()` can access and modify
13
+ * global browser objects (window, document, etc.) through prototype chain traversal.
14
+ * - There is NO memory isolation — the executed code shares the same heap.
15
+ * - `createContext()` simply returns the sandbox object without creating an isolated context.
16
+ * - The `Script` class wraps code in `new Function()`, not a separate V8 context.
17
+ *
18
+ * This polyfill is suitable for:
19
+ * - Module evaluation (CommonJS require simulation)
20
+ * - Template rendering that expects vm-like API
21
+ * - Code that uses vm for convenience, not security
22
+ *
23
+ * This polyfill is NOT suitable for:
24
+ * - Untrusted code execution
25
+ * - Security sandboxing
26
+ * - Scenarios requiring true memory/scope isolation
27
+ *
28
+ * @module vm
29
+ */
30
+
31
+ /**
32
+ * Create a "context" from a sandbox object.
33
+ * In the browser, this simply returns the sandbox as-is since we cannot
34
+ * create a true V8 context. The returned object is used as the scope
35
+ * for `runInContext()`.
36
+ */
37
+ export function createContext(
38
+ sandbox?: Record<string, unknown>,
39
+ ): Record<string, unknown> {
40
+ return sandbox || {};
41
+ }
42
+
43
+ /**
44
+ * Execute code in the given context.
45
+ * Uses `new Function()` — does NOT provide true V8 context isolation.
46
+ * @see Module-level JSDoc for security limitations.
47
+ */
48
+ export function runInContext(
49
+ code: string,
50
+ context: Record<string, unknown>,
51
+ ): unknown {
52
+ const keys = Object.keys(context);
53
+ const values = keys.map(k => context[k]);
54
+ const fn = new Function(...keys, `return (${code})`);
55
+ return fn(...values);
56
+ }
57
+
58
+ /**
59
+ * Execute code in a new context created from the sandbox.
60
+ * Equivalent to `runInContext(code, createContext(sandbox))`.
61
+ * @see Module-level JSDoc for security limitations.
62
+ */
63
+ export function runInNewContext(
64
+ code: string,
65
+ sandbox?: Record<string, unknown>,
66
+ ): unknown {
67
+ return runInContext(code, sandbox || {});
68
+ }
69
+
70
+ /**
71
+ * Execute code in the current global context via `new Function()`.
72
+ * @see Module-level JSDoc for security limitations.
73
+ */
74
+ export function runInThisContext(code: string): unknown {
75
+ return new Function(`return (${code})`)();
76
+ }
77
+
78
+ /** Always returns true since we cannot distinguish real V8 contexts in the browser. */
79
+ export function isContext(_sandbox: unknown): boolean {
80
+ return true;
81
+ }
82
+
83
+ /**
84
+ * Wraps code in a `new Function()` call for deferred execution.
85
+ * Does NOT create a V8 Script object — no compilation caching occurs.
86
+ * @see Module-level JSDoc for security limitations.
87
+ */
88
+ export class Script {
89
+ private code: string;
90
+ constructor(code: string, _options?: unknown) {
91
+ this.code = code;
92
+ }
93
+ runInContext(context: Record<string, unknown>): unknown {
94
+ return runInContext(this.code, context);
95
+ }
96
+ runInNewContext(sandbox?: Record<string, unknown>): unknown {
97
+ return runInNewContext(this.code, sandbox);
98
+ }
99
+ runInThisContext(): unknown {
100
+ return runInThisContext(this.code);
101
+ }
102
+ }
103
+
104
+ export default {
105
+ createContext,
106
+ runInContext,
107
+ runInNewContext,
108
+ runInThisContext,
109
+ isContext,
110
+ Script,
111
+ };
@@ -0,0 +1,189 @@
1
+ /**
2
+ * Enhanced worker_threads polyfill.
3
+ *
4
+ * Provides a more complete implementation of Node.js worker_threads API.
5
+ * When Web Workers are available (browser), `new Worker()` spawns a real
6
+ * Web Worker for parallel execution. When unavailable (tests), it falls
7
+ * back to in-process emulation via EventEmitter pairs.
8
+ *
9
+ * Supported:
10
+ * - `Worker` class with `postMessage`/`on('message')` communication
11
+ * - `parentPort` for child-to-parent messaging
12
+ * - `workerData` for initial data transfer
13
+ * - `isMainThread` flag
14
+ * - `threadId` counter
15
+ * - `MessageChannel` / `MessagePort` pairs
16
+ */
17
+
18
+ import { EventEmitter } from "./events";
19
+
20
+ let _threadIdCounter = 1;
21
+
22
+ // ---------------------------------------------------------------------------
23
+ // MessagePort / MessageChannel
24
+ // ---------------------------------------------------------------------------
25
+
26
+ export class MessagePort extends EventEmitter {
27
+ private _partner: MessagePort | null = null;
28
+ private _started = false;
29
+ private _closed = false;
30
+ private _queue: unknown[] = [];
31
+
32
+ postMessage(value: unknown): void {
33
+ if (this._closed) return;
34
+ if (this._partner) {
35
+ if (this._partner._started) {
36
+ // Deliver asynchronously like real MessagePort
37
+ queueMicrotask(() => this._partner?.emit("message", value));
38
+ } else {
39
+ this._partner._queue.push(value);
40
+ }
41
+ }
42
+ }
43
+
44
+ start(): void {
45
+ this._started = true;
46
+ // Flush queued messages
47
+ for (const msg of this._queue) {
48
+ queueMicrotask(() => this.emit("message", msg));
49
+ }
50
+ this._queue.length = 0;
51
+ }
52
+
53
+ close(): void {
54
+ this._closed = true;
55
+ this.emit("close");
56
+ }
57
+
58
+ ref(): this {
59
+ return this;
60
+ }
61
+ unref(): this {
62
+ return this;
63
+ }
64
+
65
+ /** @internal Connect two ports as partners. */
66
+ static _pair(): [MessagePort, MessagePort] {
67
+ const a = new MessagePort();
68
+ const b = new MessagePort();
69
+ a._partner = b;
70
+ b._partner = a;
71
+ return [a, b];
72
+ }
73
+ }
74
+
75
+ export class MessageChannel {
76
+ port1: MessagePort;
77
+ port2: MessagePort;
78
+
79
+ constructor() {
80
+ [this.port1, this.port2] = MessagePort._pair();
81
+ this.port1.start();
82
+ this.port2.start();
83
+ }
84
+ }
85
+
86
+ // ---------------------------------------------------------------------------
87
+ // Worker
88
+ // ---------------------------------------------------------------------------
89
+
90
+ export class Worker extends EventEmitter {
91
+ readonly threadId: number;
92
+ private _port: MessagePort;
93
+ private _workerPort: MessagePort;
94
+
95
+ constructor(
96
+ _filename: string,
97
+ options?: { workerData?: unknown; eval?: boolean },
98
+ ) {
99
+ super();
100
+ this.threadId = _threadIdCounter++;
101
+
102
+ // Create a MessageChannel pair for parent <-> worker communication
103
+ [this._port, this._workerPort] = MessagePort._pair();
104
+ this._port.start();
105
+ this._workerPort.start();
106
+
107
+ // Forward messages from the worker port to the Worker's 'message' event
108
+ this._port.on("message", (msg: unknown) => {
109
+ this.emit("message", msg);
110
+ });
111
+
112
+ // Expose parentPort-like API on the worker side
113
+ const workerData = options?.workerData;
114
+ const workerPort = this._workerPort;
115
+
116
+ // In a real implementation, we'd execute the file in an isolated context.
117
+ // For now, make the worker port and data available via the module-level exports.
118
+ _lastWorkerPort = workerPort;
119
+ _lastWorkerData = workerData;
120
+
121
+ // Emit 'online' asynchronously
122
+ queueMicrotask(() => this.emit("online"));
123
+ }
124
+
125
+ postMessage(value: unknown): void {
126
+ this._workerPort.emit("message", value);
127
+ }
128
+
129
+ terminate(): Promise<number> {
130
+ this._port.close();
131
+ this._workerPort.close();
132
+ this.emit("exit", 0);
133
+ return Promise.resolve(0);
134
+ }
135
+
136
+ ref(): this {
137
+ return this;
138
+ }
139
+ unref(): this {
140
+ return this;
141
+ }
142
+ }
143
+
144
+ // ---------------------------------------------------------------------------
145
+ // Module-level exports (mimics Node.js worker_threads)
146
+ // ---------------------------------------------------------------------------
147
+
148
+ /** Whether the current context is the main thread. */
149
+ export const isMainThread = true;
150
+
151
+ /** Thread ID of the current thread. */
152
+ export const threadId = 0;
153
+
154
+ // These are set when a Worker is created, allowing test code to access them.
155
+ let _lastWorkerPort: MessagePort | null = null;
156
+ let _lastWorkerData: unknown = undefined;
157
+
158
+ /** Parent port (only available inside a worker thread). */
159
+ export const parentPort: MessagePort | null = null;
160
+
161
+ /** Data passed to the worker via `workerData` option. */
162
+ export const workerData: unknown = undefined;
163
+
164
+ /**
165
+ * Get the last created worker's port (for testing).
166
+ * @internal
167
+ */
168
+ export function _getLastWorkerPort(): MessagePort | null {
169
+ return _lastWorkerPort;
170
+ }
171
+
172
+ /**
173
+ * Get the last created worker's data (for testing).
174
+ * @internal
175
+ */
176
+ export function _getLastWorkerData(): unknown {
177
+ return _lastWorkerData;
178
+ }
179
+
180
+ /** Default export matching Node.js worker_threads module shape. */
181
+ export default {
182
+ Worker,
183
+ isMainThread,
184
+ parentPort,
185
+ workerData,
186
+ threadId,
187
+ MessageChannel,
188
+ MessagePort,
189
+ };
@@ -0,0 +1,73 @@
1
+ import { EventEmitter } from "./events";
2
+
3
+ export class WebSocketShim extends EventEmitter {
4
+ readyState = 0;
5
+ url: string;
6
+ static CONNECTING = 0;
7
+ static OPEN = 1;
8
+ static CLOSING = 2;
9
+ static CLOSED = 3;
10
+ CONNECTING = 0;
11
+ OPEN = 1;
12
+ CLOSING = 2;
13
+ CLOSED = 3;
14
+
15
+ private _ws: WebSocket | null = null;
16
+
17
+ constructor(url: string, _protocols?: string | string[], _options?: unknown) {
18
+ super();
19
+ this.url = url;
20
+ try {
21
+ this._ws = new WebSocket(url);
22
+ this._ws.binaryType = "arraybuffer";
23
+ this._ws.onopen = () => {
24
+ this.readyState = 1;
25
+ this.emit("open");
26
+ };
27
+ this._ws.onmessage = e => this.emit("message", e.data);
28
+ this._ws.onerror = e => this.emit("error", e);
29
+ this._ws.onclose = e => {
30
+ this.readyState = 3;
31
+ this.emit("close", e.code, e.reason);
32
+ };
33
+ } catch (err) {
34
+ setTimeout(() => this.emit("error", err), 0);
35
+ }
36
+ }
37
+
38
+ send(data: unknown, _options?: unknown, cb?: (err?: Error) => void): void {
39
+ try {
40
+ this._ws?.send(data as string | ArrayBuffer);
41
+ cb?.();
42
+ } catch (err) {
43
+ cb?.(err as Error);
44
+ }
45
+ }
46
+
47
+ close(code?: number, reason?: string): void {
48
+ this.readyState = 2;
49
+ this._ws?.close(code, reason);
50
+ }
51
+
52
+ ping(_data?: unknown, _mask?: boolean, _cb?: () => void): void {}
53
+ pong(_data?: unknown, _mask?: boolean, _cb?: () => void): void {}
54
+ terminate(): void {
55
+ this.close();
56
+ }
57
+ }
58
+
59
+ export class WebSocketServer extends EventEmitter {
60
+ clients = new Set<WebSocketShim>();
61
+ constructor(_options?: unknown) {
62
+ super();
63
+ }
64
+ close(_cb?: () => void): void {
65
+ this.emit("close");
66
+ }
67
+ address(): { port: number; family: string; address: string } {
68
+ return { port: 0, family: "IPv4", address: "0.0.0.0" };
69
+ }
70
+ }
71
+
72
+ export { WebSocketShim as WebSocket };
73
+ export default WebSocketShim;