@scelar/nodepod 1.0.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 (134) hide show
  1. package/LICENSE +43 -0
  2. package/README.md +240 -0
  3. package/dist/child_process-BJOMsZje.js +8233 -0
  4. package/dist/child_process-BJOMsZje.js.map +1 -0
  5. package/dist/child_process-Cj8vOcuc.cjs +7434 -0
  6. package/dist/child_process-Cj8vOcuc.cjs.map +1 -0
  7. package/dist/index-Cb1Cgdnd.js +35308 -0
  8. package/dist/index-Cb1Cgdnd.js.map +1 -0
  9. package/dist/index-DsMGS-xc.cjs +37195 -0
  10. package/dist/index-DsMGS-xc.cjs.map +1 -0
  11. package/dist/index.cjs +65 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.mjs +59 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/package.json +95 -0
  16. package/src/__tests__/smoke.test.ts +11 -0
  17. package/src/constants/cdn-urls.ts +18 -0
  18. package/src/constants/config.ts +236 -0
  19. package/src/cross-origin.ts +26 -0
  20. package/src/engine-factory.ts +176 -0
  21. package/src/engine-types.ts +56 -0
  22. package/src/helpers/byte-encoding.ts +39 -0
  23. package/src/helpers/digest.ts +9 -0
  24. package/src/helpers/event-loop.ts +96 -0
  25. package/src/helpers/wasm-cache.ts +133 -0
  26. package/src/iframe-sandbox.ts +141 -0
  27. package/src/index.ts +192 -0
  28. package/src/isolation-helpers.ts +148 -0
  29. package/src/memory-volume.ts +941 -0
  30. package/src/module-transformer.ts +368 -0
  31. package/src/packages/archive-extractor.ts +248 -0
  32. package/src/packages/browser-bundler.ts +284 -0
  33. package/src/packages/installer.ts +396 -0
  34. package/src/packages/registry-client.ts +131 -0
  35. package/src/packages/version-resolver.ts +411 -0
  36. package/src/polyfills/assert.ts +384 -0
  37. package/src/polyfills/async_hooks.ts +144 -0
  38. package/src/polyfills/buffer.ts +628 -0
  39. package/src/polyfills/child_process.ts +2288 -0
  40. package/src/polyfills/chokidar.ts +336 -0
  41. package/src/polyfills/cluster.ts +106 -0
  42. package/src/polyfills/console.ts +136 -0
  43. package/src/polyfills/constants.ts +123 -0
  44. package/src/polyfills/crypto.ts +885 -0
  45. package/src/polyfills/dgram.ts +87 -0
  46. package/src/polyfills/diagnostics_channel.ts +76 -0
  47. package/src/polyfills/dns.ts +134 -0
  48. package/src/polyfills/domain.ts +68 -0
  49. package/src/polyfills/esbuild.ts +854 -0
  50. package/src/polyfills/events.ts +276 -0
  51. package/src/polyfills/fs.ts +2888 -0
  52. package/src/polyfills/fsevents.ts +79 -0
  53. package/src/polyfills/http.ts +1449 -0
  54. package/src/polyfills/http2.ts +199 -0
  55. package/src/polyfills/https.ts +76 -0
  56. package/src/polyfills/inspector.ts +62 -0
  57. package/src/polyfills/lightningcss.ts +105 -0
  58. package/src/polyfills/module.ts +191 -0
  59. package/src/polyfills/net.ts +353 -0
  60. package/src/polyfills/os.ts +238 -0
  61. package/src/polyfills/path.ts +206 -0
  62. package/src/polyfills/perf_hooks.ts +102 -0
  63. package/src/polyfills/process.ts +690 -0
  64. package/src/polyfills/punycode.ts +159 -0
  65. package/src/polyfills/querystring.ts +93 -0
  66. package/src/polyfills/quic.ts +118 -0
  67. package/src/polyfills/readdirp.ts +229 -0
  68. package/src/polyfills/readline.ts +692 -0
  69. package/src/polyfills/repl.ts +134 -0
  70. package/src/polyfills/rollup.ts +119 -0
  71. package/src/polyfills/sea.ts +33 -0
  72. package/src/polyfills/sqlite.ts +78 -0
  73. package/src/polyfills/stream.ts +1620 -0
  74. package/src/polyfills/string_decoder.ts +25 -0
  75. package/src/polyfills/tailwindcss-oxide.ts +309 -0
  76. package/src/polyfills/test.ts +197 -0
  77. package/src/polyfills/timers.ts +32 -0
  78. package/src/polyfills/tls.ts +105 -0
  79. package/src/polyfills/trace_events.ts +50 -0
  80. package/src/polyfills/tty.ts +71 -0
  81. package/src/polyfills/url.ts +174 -0
  82. package/src/polyfills/util.ts +559 -0
  83. package/src/polyfills/v8.ts +126 -0
  84. package/src/polyfills/vm.ts +132 -0
  85. package/src/polyfills/volume-registry.ts +15 -0
  86. package/src/polyfills/wasi.ts +44 -0
  87. package/src/polyfills/worker_threads.ts +326 -0
  88. package/src/polyfills/ws.ts +595 -0
  89. package/src/polyfills/zlib.ts +881 -0
  90. package/src/request-proxy.ts +716 -0
  91. package/src/script-engine.ts +3375 -0
  92. package/src/sdk/nodepod-fs.ts +93 -0
  93. package/src/sdk/nodepod-process.ts +86 -0
  94. package/src/sdk/nodepod-terminal.ts +350 -0
  95. package/src/sdk/nodepod.ts +509 -0
  96. package/src/sdk/types.ts +70 -0
  97. package/src/shell/commands/bun.ts +121 -0
  98. package/src/shell/commands/directory.ts +297 -0
  99. package/src/shell/commands/file-ops.ts +525 -0
  100. package/src/shell/commands/git.ts +2142 -0
  101. package/src/shell/commands/node.ts +80 -0
  102. package/src/shell/commands/npm.ts +198 -0
  103. package/src/shell/commands/pm-types.ts +45 -0
  104. package/src/shell/commands/pnpm.ts +82 -0
  105. package/src/shell/commands/search.ts +264 -0
  106. package/src/shell/commands/shell-env.ts +352 -0
  107. package/src/shell/commands/text-processing.ts +1152 -0
  108. package/src/shell/commands/yarn.ts +84 -0
  109. package/src/shell/shell-builtins.ts +19 -0
  110. package/src/shell/shell-helpers.ts +250 -0
  111. package/src/shell/shell-interpreter.ts +514 -0
  112. package/src/shell/shell-parser.ts +429 -0
  113. package/src/shell/shell-types.ts +85 -0
  114. package/src/syntax-transforms.ts +561 -0
  115. package/src/threading/engine-worker.ts +64 -0
  116. package/src/threading/inline-worker.ts +372 -0
  117. package/src/threading/offload-types.ts +112 -0
  118. package/src/threading/offload-worker.ts +383 -0
  119. package/src/threading/offload.ts +271 -0
  120. package/src/threading/process-context.ts +92 -0
  121. package/src/threading/process-handle.ts +275 -0
  122. package/src/threading/process-manager.ts +956 -0
  123. package/src/threading/process-worker-entry.ts +854 -0
  124. package/src/threading/shared-vfs.ts +352 -0
  125. package/src/threading/sync-channel.ts +135 -0
  126. package/src/threading/task-queue.ts +177 -0
  127. package/src/threading/vfs-bridge.ts +231 -0
  128. package/src/threading/worker-pool.ts +233 -0
  129. package/src/threading/worker-protocol.ts +358 -0
  130. package/src/threading/worker-vfs.ts +218 -0
  131. package/src/types/externals.d.ts +38 -0
  132. package/src/types/fs-streams.ts +142 -0
  133. package/src/types/manifest.ts +17 -0
  134. package/src/worker-sandbox.ts +90 -0
@@ -0,0 +1,25 @@
1
+ // StringDecoder for decoding Buffer/Uint8Array to strings
2
+
3
+
4
+ export interface StringDecoder {
5
+ encoding: string;
6
+ write(buf: Uint8Array | Buffer): string;
7
+ end(buf?: Uint8Array | Buffer): string;
8
+ }
9
+
10
+ export const StringDecoder = function StringDecoder(this: any, encoding?: string) {
11
+ if (!this) return;
12
+ this.encoding = encoding || "utf8";
13
+ } as unknown as { new(encoding?: string): StringDecoder; prototype: any };
14
+
15
+ StringDecoder.prototype.write = function write(buf: Uint8Array | Buffer): string {
16
+ if (!buf || buf.length === 0) return "";
17
+ const bytes = buf instanceof Uint8Array ? buf : new Uint8Array(buf);
18
+ return new TextDecoder(this.encoding).decode(bytes);
19
+ };
20
+
21
+ StringDecoder.prototype.end = function end(buf?: Uint8Array | Buffer): string {
22
+ return buf ? this.write(buf) : "";
23
+ };
24
+
25
+ export default { StringDecoder };
@@ -0,0 +1,309 @@
1
+ // Pure JS replacement for @tailwindcss/oxide (native Rust binaries can't load in browser).
2
+ // Regex-based scanner that extracts Tailwind CSS utility class candidates from VFS files.
3
+
4
+ // Intentionally broad to avoid false negatives -- Tailwind's compiler filters out non-matches
5
+ const CANDIDATE_RE =
6
+ /[!\-]?(?:[a-z@][a-z0-9]*(?:-[a-z0-9/._]+)*(?:\[[^\]]+\])?(?:\/[a-z0-9._%-]+)?(?:\:[a-z@!][a-z0-9]*(?:-[a-z0-9/._]+)*(?:\[[^\]]+\])?(?:\/[a-z0-9._%-]+)?)*)/gi;
7
+
8
+ const SPLIT_RE = /[\s'"`;{}()\[\]]+/;
9
+
10
+ function extractCandidates(content: string): string[] {
11
+ const seen = new Set<string>();
12
+ const matches = content.match(CANDIDATE_RE);
13
+ if (matches) {
14
+ for (const m of matches) {
15
+ if (m.length >= 2 && m.length <= 200) seen.add(m);
16
+ }
17
+ }
18
+ // fallback: split on whitespace/quotes and keep plausible tokens
19
+ const tokens = content.split(SPLIT_RE);
20
+ for (const tok of tokens) {
21
+ const t = tok.trim();
22
+ if (t.length >= 2 && t.length <= 200 && /^[!@\-]?[a-z]/.test(t) && !t.includes("//") && !t.includes("/*")) {
23
+ seen.add(t);
24
+ }
25
+ }
26
+ return Array.from(seen);
27
+ }
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Glob matching (minimal)
31
+ // ---------------------------------------------------------------------------
32
+
33
+ function matchGlob(pattern: string, path: string): boolean {
34
+ // Convert glob pattern to regex
35
+ let re = "^";
36
+ let i = 0;
37
+ while (i < pattern.length) {
38
+ const ch = pattern[i];
39
+ if (ch === "*" && pattern[i + 1] === "*") {
40
+ re += ".*";
41
+ i += 2;
42
+ if (pattern[i] === "/") i++;
43
+ } else if (ch === "*") {
44
+ re += "[^/]*";
45
+ i++;
46
+ } else if (ch === "?") {
47
+ re += "[^/]";
48
+ i++;
49
+ } else if (ch === "{") {
50
+ re += "(";
51
+ i++;
52
+ } else if (ch === "}") {
53
+ re += ")";
54
+ i++;
55
+ } else if (ch === ",") {
56
+ re += "|";
57
+ i++;
58
+ } else if (".+^$|()[]\\".includes(ch)) {
59
+ re += "\\" + ch;
60
+ i++;
61
+ } else {
62
+ re += ch;
63
+ i++;
64
+ }
65
+ }
66
+ re += "$";
67
+ try {
68
+ return new RegExp(re).test(path);
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+
74
+ // ---------------------------------------------------------------------------
75
+ // VFS access — try to use globalThis.__nodepod_volume or require('fs')
76
+ // ---------------------------------------------------------------------------
77
+
78
+ function getFs(): any {
79
+ // Access the VFS through globalThis.__nodepodVolume (set by script-engine.ts)
80
+ const g = globalThis as any;
81
+ if (g.__nodepodVolume) return g.__nodepodVolume;
82
+ return null;
83
+ }
84
+
85
+ function readDir(fs: any, dir: string): string[] {
86
+ try {
87
+ if (!fs.existsSync(dir)) return [];
88
+ return fs.readdirSync(dir);
89
+ } catch {
90
+ return [];
91
+ }
92
+ }
93
+
94
+ function walkDir(fs: any, dir: string, results: string[]): void {
95
+ const entries = readDir(fs, dir);
96
+ for (const entry of entries) {
97
+ if (entry === "node_modules" || entry === ".git" || entry === ".next" || entry === "dist") continue;
98
+ const full = dir.endsWith("/") ? dir + entry : dir + "/" + entry;
99
+ try {
100
+ const stat = fs.statSync(full);
101
+ if (stat.isDirectory()) {
102
+ walkDir(fs, full, results);
103
+ } else {
104
+ results.push(full);
105
+ }
106
+ } catch {
107
+ // Skip unreadable entries
108
+ }
109
+ }
110
+ }
111
+
112
+ // ---------------------------------------------------------------------------
113
+ // Source entry type
114
+ // ---------------------------------------------------------------------------
115
+
116
+ interface SourceEntry {
117
+ base: string;
118
+ pattern: string;
119
+ negated?: boolean;
120
+ }
121
+
122
+ interface ChangedContent {
123
+ file?: string;
124
+ content?: string;
125
+ extension: string;
126
+ }
127
+
128
+ // File extensions that likely contain Tailwind class names
129
+ const SCANNABLE_EXTENSIONS = new Set([
130
+ ".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs",
131
+ ".html", ".vue", ".svelte", ".astro", ".mdx", ".md",
132
+ ".php", ".blade.php", ".erb", ".haml", ".slim",
133
+ ".twig", ".pug", ".jade", ".hbs", ".ejs",
134
+ ]);
135
+
136
+ // ---------------------------------------------------------------------------
137
+ // Scanner class
138
+ // ---------------------------------------------------------------------------
139
+
140
+ export interface Scanner {
141
+ _sources: SourceEntry[];
142
+ _fileList: string[] | null;
143
+ _scannedCandidates: string[] | null;
144
+ _collectFiles(): string[];
145
+ scan(): string[];
146
+ scanFiles(changedContent: ChangedContent[]): string[];
147
+ getCandidatesWithPositions(changedContent: ChangedContent[]): Array<{ candidate: string; position: number }>;
148
+ readonly files: string[];
149
+ readonly globs: Array<{ base: string; pattern: string }>;
150
+ readonly normalizedSources: SourceEntry[];
151
+ }
152
+
153
+ interface ScannerConstructor {
154
+ new (opts?: { sources?: SourceEntry[] }): Scanner;
155
+ (this: any, opts?: { sources?: SourceEntry[] }): void;
156
+ prototype: any;
157
+ }
158
+
159
+ export const Scanner = function Scanner(this: any, opts?: { sources?: SourceEntry[] }) {
160
+ if (!this) return;
161
+ this._sources = opts?.sources || [];
162
+ this._fileList = null;
163
+ this._scannedCandidates = null;
164
+ } as unknown as ScannerConstructor;
165
+
166
+ Scanner.prototype._collectFiles = function _collectFiles(this: any): string[] {
167
+ if (this._fileList) return this._fileList;
168
+
169
+ const fs = getFs();
170
+ if (!fs) {
171
+ this._fileList = [];
172
+ return this._fileList;
173
+ }
174
+
175
+ const files: string[] = [];
176
+ const negatedPatterns: string[] = [];
177
+
178
+ for (const source of this._sources) {
179
+ if (source.negated) {
180
+ negatedPatterns.push(source.pattern);
181
+ continue;
182
+ }
183
+
184
+ const base = source.base || ".";
185
+ const allFiles: string[] = [];
186
+ walkDir(fs, base, allFiles);
187
+
188
+ for (const file of allFiles) {
189
+ const relPath = file.startsWith(base) ? file.slice(base.length).replace(/^\//, "") : file;
190
+ const ext = file.substring(file.lastIndexOf("."));
191
+ if (!SCANNABLE_EXTENSIONS.has(ext)) continue;
192
+ if (source.pattern && !matchGlob(source.pattern, relPath)) continue;
193
+
194
+ // Check against negated patterns
195
+ let negated = false;
196
+ for (const neg of negatedPatterns) {
197
+ if (matchGlob(neg, relPath)) {
198
+ negated = true;
199
+ break;
200
+ }
201
+ }
202
+ if (!negated) files.push(file);
203
+ }
204
+ }
205
+
206
+ this._fileList = files;
207
+ return files;
208
+ };
209
+
210
+ Scanner.prototype.scan = function scan(this: any): string[] {
211
+ if (this._scannedCandidates) return this._scannedCandidates;
212
+
213
+ const fs = getFs();
214
+ if (!fs) {
215
+ this._scannedCandidates = [];
216
+ return this._scannedCandidates;
217
+ }
218
+
219
+ const files = this._collectFiles();
220
+ const allCandidates = new Set<string>();
221
+
222
+ for (const file of files) {
223
+ try {
224
+ const content = fs.readFileSync(file, "utf8");
225
+ const candidates = extractCandidates(content);
226
+ for (const c of candidates) allCandidates.add(c);
227
+ } catch {
228
+ // Skip unreadable files
229
+ }
230
+ }
231
+
232
+ this._scannedCandidates = Array.from(allCandidates);
233
+ return this._scannedCandidates;
234
+ };
235
+
236
+ Scanner.prototype.scanFiles = function scanFiles(this: any, changedContent: ChangedContent[]): string[] {
237
+ const allCandidates = new Set<string>();
238
+ const fs = getFs();
239
+
240
+ for (const entry of changedContent) {
241
+ let content = entry.content;
242
+ if (!content && entry.file && fs) {
243
+ try {
244
+ content = fs.readFileSync(entry.file, "utf8");
245
+ } catch {
246
+ continue;
247
+ }
248
+ }
249
+ if (content) {
250
+ const candidates = extractCandidates(content);
251
+ for (const c of candidates) allCandidates.add(c);
252
+ }
253
+ }
254
+
255
+ // Invalidate cached scan results since files changed
256
+ this._scannedCandidates = null;
257
+
258
+ return Array.from(allCandidates);
259
+ };
260
+
261
+ Scanner.prototype.getCandidatesWithPositions = function getCandidatesWithPositions(this: any, changedContent: ChangedContent[]): Array<{ candidate: string; position: number }> {
262
+ const results: Array<{ candidate: string; position: number }> = [];
263
+ const fs = getFs();
264
+
265
+ for (const entry of changedContent) {
266
+ let content = entry.content;
267
+ if (!content && entry.file && fs) {
268
+ try {
269
+ content = fs.readFileSync(entry.file, "utf8");
270
+ } catch {
271
+ continue;
272
+ }
273
+ }
274
+ if (!content) continue;
275
+
276
+ let match: RegExpExecArray | null;
277
+ CANDIDATE_RE.lastIndex = 0;
278
+ while ((match = CANDIDATE_RE.exec(content)) !== null) {
279
+ results.push({ candidate: match[0], position: match.index });
280
+ }
281
+ }
282
+
283
+ return results;
284
+ };
285
+
286
+ Object.defineProperty(Scanner.prototype, "files", {
287
+ get: function(this: any): string[] {
288
+ return this._collectFiles();
289
+ },
290
+ configurable: true,
291
+ });
292
+
293
+ Object.defineProperty(Scanner.prototype, "globs", {
294
+ get: function(this: any): Array<{ base: string; pattern: string }> {
295
+ return this._sources
296
+ .filter((s: SourceEntry) => !s.negated)
297
+ .map((s: SourceEntry) => ({ base: s.base, pattern: s.pattern }));
298
+ },
299
+ configurable: true,
300
+ });
301
+
302
+ Object.defineProperty(Scanner.prototype, "normalizedSources", {
303
+ get: function(this: any): SourceEntry[] {
304
+ return this._sources;
305
+ },
306
+ configurable: true,
307
+ });
308
+
309
+ export default { Scanner };
@@ -0,0 +1,197 @@
1
+ // lightweight node:test polyfill with describe/it/test, hooks, and basic mocks
2
+
3
+ export interface TestContext {
4
+ name: string;
5
+ signal: AbortSignal;
6
+ _controller: AbortController;
7
+ diagnostic(msg: string): void;
8
+ plan(_count: number): void;
9
+ todo(msg?: string): void;
10
+ skip(msg?: string): void;
11
+ abort(): void;
12
+ }
13
+
14
+ interface TestContextConstructor {
15
+ new (name: string): TestContext;
16
+ (this: any, name: string): void;
17
+ prototype: any;
18
+ }
19
+
20
+ export const TestContext = function TestContext(this: any, name: string) {
21
+ if (!this) return;
22
+ this.name = name;
23
+ this._controller = new AbortController();
24
+ this.signal = this._controller.signal;
25
+ } as unknown as TestContextConstructor;
26
+
27
+ TestContext.prototype.diagnostic = function diagnostic(this: any, msg: string): void {
28
+ globalThis.console.log(`# ${msg}`);
29
+ };
30
+
31
+ TestContext.prototype.plan = function plan(_count: number): void {
32
+ };
33
+
34
+ TestContext.prototype.todo = function todo(msg?: string): void {
35
+ globalThis.console.log(`# TODO${msg ? ": " + msg : ""}`);
36
+ };
37
+
38
+ TestContext.prototype.skip = function skip(msg?: string): void {
39
+ globalThis.console.log(`# SKIP${msg ? ": " + msg : ""}`);
40
+ };
41
+
42
+ TestContext.prototype.abort = function abort(this: any): void {
43
+ this._controller.abort();
44
+ };
45
+
46
+ type TestFn = (t: TestContext) => void | Promise<void>;
47
+ type HookFn = () => void | Promise<void>;
48
+
49
+ interface TestOpts {
50
+ name: string;
51
+ skip?: boolean;
52
+ todo?: boolean;
53
+ only?: boolean;
54
+ }
55
+
56
+ export function describe(name: string, fn: () => void | Promise<void>): void;
57
+ export function describe(
58
+ options: TestOpts,
59
+ fn: () => void | Promise<void>,
60
+ ): void;
61
+ export function describe(
62
+ nameOrOpts: string | TestOpts,
63
+ fn?: () => void | Promise<void>,
64
+ ): void {
65
+ const name = typeof nameOrOpts === "string" ? nameOrOpts : nameOrOpts.name;
66
+ const opts: TestOpts = typeof nameOrOpts === "object" ? nameOrOpts : { name };
67
+ const body = fn!;
68
+
69
+ if (opts.skip) {
70
+ globalThis.console.log(`# SKIP - ${name}`);
71
+ return;
72
+ }
73
+ if (opts.todo) {
74
+ globalThis.console.log(`# TODO - ${name}`);
75
+ return;
76
+ }
77
+
78
+ try {
79
+ const result = body();
80
+ if (result && typeof (result as Promise<void>).then === "function") {
81
+ (result as Promise<void>).catch((err) => {
82
+ globalThis.console.error(`Suite "${name}" failed:`, err);
83
+ });
84
+ }
85
+ } catch (err) {
86
+ globalThis.console.error(`Suite "${name}" failed:`, err);
87
+ }
88
+ }
89
+
90
+ export function it(name: string, fn?: TestFn): void;
91
+ export function it(options: TestOpts, fn?: TestFn): void;
92
+ export function it(nameOrOpts: string | TestOpts, fn?: TestFn): void {
93
+ const name = typeof nameOrOpts === "string" ? nameOrOpts : nameOrOpts.name;
94
+ const opts: TestOpts = typeof nameOrOpts === "object" ? nameOrOpts : { name };
95
+
96
+ if (opts.skip || !fn) {
97
+ globalThis.console.log(`# SKIP - ${name}`);
98
+ return;
99
+ }
100
+ if (opts.todo) {
101
+ globalThis.console.log(`# TODO - ${name}`);
102
+ return;
103
+ }
104
+
105
+ const ctx = new TestContext(name);
106
+ try {
107
+ const result = fn(ctx);
108
+ if (result && typeof (result as Promise<void>).then === "function") {
109
+ (result as Promise<void>).catch((err) => {
110
+ globalThis.console.error(`Test "${name}" failed:`, err);
111
+ });
112
+ }
113
+ } catch (err) {
114
+ globalThis.console.error(`Test "${name}" failed:`, err);
115
+ }
116
+ }
117
+
118
+ export { it as test };
119
+
120
+ export function before(fn: HookFn): void {
121
+ try {
122
+ fn();
123
+ } catch {
124
+ }
125
+ }
126
+
127
+ export function after(fn: HookFn): void {
128
+ try {
129
+ fn();
130
+ } catch {
131
+ }
132
+ }
133
+
134
+ export function beforeEach(fn: HookFn): void {
135
+ try {
136
+ fn();
137
+ } catch {
138
+ }
139
+ }
140
+
141
+ export function afterEach(fn: HookFn): void {
142
+ try {
143
+ fn();
144
+ } catch {
145
+ }
146
+ }
147
+
148
+ export function skip(name?: string, _fn?: TestFn): void {
149
+ if (name) globalThis.console.log(`# SKIP - ${name}`);
150
+ }
151
+
152
+ export function todo(name?: string, _fn?: TestFn): void {
153
+ if (name) globalThis.console.log(`# TODO - ${name}`);
154
+ }
155
+
156
+ export const mock = {
157
+ fn(impl?: Function): Function {
158
+ const calls: unknown[][] = [];
159
+ const mockFn = (...args: unknown[]) => {
160
+ calls.push(args);
161
+ return impl ? impl(...args) : undefined;
162
+ };
163
+ (mockFn as any).mock = { calls, callCount: () => calls.length };
164
+ return mockFn;
165
+ },
166
+
167
+ method(
168
+ obj: Record<string, unknown>,
169
+ methodName: string,
170
+ impl?: Function,
171
+ ): Function {
172
+ const original = obj[methodName];
173
+ const mocked = mock.fn(impl || (original as Function));
174
+ obj[methodName] = mocked;
175
+ return mocked;
176
+ },
177
+
178
+ reset(): void {
179
+ },
180
+
181
+ restoreAll(): void {
182
+ },
183
+ };
184
+
185
+ export default {
186
+ describe,
187
+ it,
188
+ test: it,
189
+ before,
190
+ after,
191
+ beforeEach,
192
+ afterEach,
193
+ skip,
194
+ todo,
195
+ mock,
196
+ TestContext,
197
+ };
@@ -0,0 +1,32 @@
1
+ // Timer functions mapped to browser equivalents, includes setImmediate polyfill
2
+
3
+
4
+ export const setTimeout = globalThis.setTimeout;
5
+ export const setInterval = globalThis.setInterval;
6
+ export const setImmediate = (fn: (...args: unknown[]) => void, ...args: unknown[]) =>
7
+ globalThis.setTimeout(fn, 0, ...args);
8
+ export const clearTimeout = globalThis.clearTimeout;
9
+ export const clearInterval = globalThis.clearInterval;
10
+ export const clearImmediate = globalThis.clearTimeout;
11
+
12
+ // timers/promises API
13
+ export const promises = {
14
+ setTimeout: (ms: number, value?: unknown) =>
15
+ new Promise((resolve) => globalThis.setTimeout(() => resolve(value), ms)),
16
+ setInterval: globalThis.setInterval,
17
+ setImmediate: (value?: unknown) =>
18
+ new Promise((resolve) => globalThis.setTimeout(() => resolve(value), 0)),
19
+ scheduler: {
20
+ wait: (ms: number) =>
21
+ new Promise((resolve) => globalThis.setTimeout(resolve, ms)),
22
+ },
23
+ };
24
+
25
+ export default {
26
+ setTimeout,
27
+ setInterval,
28
+ setImmediate,
29
+ clearTimeout,
30
+ clearInterval,
31
+ clearImmediate,
32
+ };
@@ -0,0 +1,105 @@
1
+ // stub - not available in browser
2
+
3
+ import { EventEmitter } from "./events";
4
+
5
+ export interface TLSSocket extends EventEmitter {
6
+ authorized: boolean;
7
+ encrypted: boolean;
8
+ getPeerCertificate(_detailed?: boolean): object;
9
+ getCipher(): { name: string; version: string } | null;
10
+ getProtocol(): string | null;
11
+ setServername(_name: string): void;
12
+ renegotiate(_opts: unknown, _cb: (err: Error | null) => void): boolean;
13
+ }
14
+
15
+ export const TLSSocket = function TLSSocket(this: any, _sock?: unknown, _opts?: unknown) {
16
+ if (!this) return;
17
+ EventEmitter.call(this);
18
+ this.authorized = false;
19
+ this.encrypted = true;
20
+ } as unknown as { new(_sock?: unknown, _opts?: unknown): TLSSocket; prototype: any };
21
+
22
+ Object.setPrototypeOf(TLSSocket.prototype, EventEmitter.prototype);
23
+
24
+ TLSSocket.prototype.getPeerCertificate = function getPeerCertificate(_detailed?: boolean): object {
25
+ return {};
26
+ };
27
+ TLSSocket.prototype.getCipher = function getCipher(): { name: string; version: string } | null {
28
+ return null;
29
+ };
30
+ TLSSocket.prototype.getProtocol = function getProtocol(): string | null {
31
+ return null;
32
+ };
33
+ TLSSocket.prototype.setServername = function setServername(_name: string): void {};
34
+ TLSSocket.prototype.renegotiate = function renegotiate(_opts: unknown, _cb: (err: Error | null) => void): boolean {
35
+ return false;
36
+ };
37
+
38
+ export interface Server extends EventEmitter {
39
+ listen(..._args: unknown[]): this;
40
+ close(_cb?: (err?: Error) => void): this;
41
+ address(): { port: number; family: string; address: string } | string | null;
42
+ getTicketKeys(): Uint8Array;
43
+ setTicketKeys(_keys: Uint8Array): void;
44
+ setSecureContext(_opts: unknown): void;
45
+ }
46
+
47
+ export const Server = function Server(this: any, _opts?: unknown, _handler?: (sock: TLSSocket) => void) {
48
+ if (!this) return;
49
+ EventEmitter.call(this);
50
+ } as unknown as { new(_opts?: unknown, _handler?: (sock: TLSSocket) => void): Server; prototype: any };
51
+
52
+ Object.setPrototypeOf(Server.prototype, EventEmitter.prototype);
53
+
54
+ Server.prototype.listen = function listen(..._args: unknown[]) { return this; };
55
+ Server.prototype.close = function close(_cb?: (err?: Error) => void) { return this; };
56
+ Server.prototype.address = function address(): { port: number; family: string; address: string } | string | null {
57
+ return null;
58
+ };
59
+ Server.prototype.getTicketKeys = function getTicketKeys(): Uint8Array {
60
+ return new Uint8Array(0);
61
+ };
62
+ Server.prototype.setTicketKeys = function setTicketKeys(_keys: Uint8Array): void {};
63
+ Server.prototype.setSecureContext = function setSecureContext(_opts: unknown): void {};
64
+
65
+ export function createServer(
66
+ _opts?: unknown,
67
+ _handler?: (sock: TLSSocket) => void,
68
+ ): Server {
69
+ return new Server(_opts, _handler);
70
+ }
71
+
72
+ export function connect(_opts: unknown, _cb?: () => void): TLSSocket {
73
+ const sock = new TLSSocket();
74
+ if (_cb) setTimeout(_cb, 0);
75
+ return sock;
76
+ }
77
+
78
+ export function createSecureContext(_opts?: unknown): object {
79
+ return {};
80
+ }
81
+
82
+ export type SecureContext = object;
83
+
84
+ export const getCiphers = (): string[] => [
85
+ "TLS_AES_256_GCM_SHA384",
86
+ "TLS_AES_128_GCM_SHA256",
87
+ ];
88
+
89
+ export const DEFAULT_ECDH_CURVE = "auto";
90
+ export const DEFAULT_MAX_VERSION = "TLSv1.3";
91
+ export const DEFAULT_MIN_VERSION = "TLSv1.2";
92
+ export const rootCertificates: string[] = [];
93
+
94
+ export default {
95
+ TLSSocket,
96
+ Server,
97
+ createServer,
98
+ connect,
99
+ createSecureContext,
100
+ getCiphers,
101
+ DEFAULT_ECDH_CURVE,
102
+ DEFAULT_MAX_VERSION,
103
+ DEFAULT_MIN_VERSION,
104
+ rootCertificates,
105
+ };