@nubjs/nub-linux-x64-musl 0.0.1 → 0.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.
package/bin/nub ADDED
Binary file
package/package.json CHANGED
@@ -1,10 +1,20 @@
1
1
  {
2
2
  "name": "@nubjs/nub-linux-x64-musl",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Nub binary for linux-x64-musl",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/colinhacks/nub",
7
- "os": ["linux"],
8
- "cpu": ["x64"],
9
- "files": ["bin", "runtime"]
10
- }
7
+ "os": [
8
+ "linux"
9
+ ],
10
+ "cpu": [
11
+ "x64"
12
+ ],
13
+ "files": [
14
+ "bin",
15
+ "runtime"
16
+ ],
17
+ "libc": [
18
+ "musl"
19
+ ]
20
+ }
@@ -0,0 +1,135 @@
1
+ // Web Locks API polyfill for Node 22.x (native on Node 24.5+).
2
+ // Single-process only — locks don't coordinate across workers.
3
+
4
+ if (typeof globalThis.navigator === "object" && typeof globalThis.navigator.locks === "undefined") {
5
+ // Track held locks: name → { mode, count } where count > 1 means shared holders
6
+ const held = new Map();
7
+ const queue = new Map();
8
+
9
+ class Lock {
10
+ #name;
11
+ #mode;
12
+ constructor(name, mode) {
13
+ this.#name = name;
14
+ this.#mode = mode;
15
+ }
16
+ get name() { return this.#name; }
17
+ get mode() { return this.#mode; }
18
+ }
19
+
20
+ function canAcquire(name, mode) {
21
+ const current = held.get(name);
22
+ if (!current) return true;
23
+ if (mode === "shared" && current.mode === "shared") return true;
24
+ return false;
25
+ }
26
+
27
+ function acquire(name, mode) {
28
+ const current = held.get(name);
29
+ if (current && mode === "shared" && current.mode === "shared") {
30
+ current.count++;
31
+ } else {
32
+ held.set(name, { mode, count: 1 });
33
+ }
34
+ }
35
+
36
+ function release(name) {
37
+ const current = held.get(name);
38
+ if (!current) return;
39
+ current.count--;
40
+ if (current.count <= 0) {
41
+ held.delete(name);
42
+ drainQueue(name);
43
+ }
44
+ }
45
+
46
+ function drainQueue(name) {
47
+ const q = queue.get(name);
48
+ if (!q || q.length === 0) return;
49
+
50
+ // Try to grant as many queued requests as possible.
51
+ // If the first queued is shared, grant all consecutive shared requests.
52
+ // If the first queued is exclusive, grant only that one.
53
+ const first = q[0];
54
+ if (canAcquire(name, first.mode)) {
55
+ if (first.mode === "exclusive") {
56
+ q.shift();
57
+ first.resolve();
58
+ } else {
59
+ // Grant all consecutive shared requests.
60
+ while (q.length > 0 && q[0].mode === "shared") {
61
+ const req = q.shift();
62
+ req.resolve();
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ class LockManager {
69
+ async request(name, optionsOrCallback, callback) {
70
+ let options = {};
71
+ if (typeof optionsOrCallback === "function") {
72
+ callback = optionsOrCallback;
73
+ } else {
74
+ options = optionsOrCallback || {};
75
+ }
76
+
77
+ const mode = options.mode || "exclusive";
78
+ const ifAvailable = options.ifAvailable || false;
79
+ const signal = options.signal;
80
+
81
+ if (signal?.aborted) {
82
+ throw signal.reason || new DOMException("Lock request aborted", "AbortError");
83
+ }
84
+
85
+ if (!canAcquire(name, mode)) {
86
+ if (ifAvailable) {
87
+ return callback(null);
88
+ }
89
+ await new Promise((resolve, reject) => {
90
+ if (!queue.has(name)) queue.set(name, []);
91
+ queue.get(name).push({ resolve, reject, mode });
92
+ if (signal) {
93
+ signal.addEventListener("abort", () => {
94
+ const q = queue.get(name) || [];
95
+ const idx = q.findIndex((e) => e.resolve === resolve);
96
+ if (idx !== -1) q.splice(idx, 1);
97
+ reject(signal.reason || new DOMException("Lock request aborted", "AbortError"));
98
+ }, { once: true });
99
+ }
100
+ });
101
+ }
102
+
103
+ acquire(name, mode);
104
+ const lock = new Lock(name, mode);
105
+
106
+ try {
107
+ return await callback(lock);
108
+ } finally {
109
+ release(name);
110
+ }
111
+ }
112
+
113
+ async query() {
114
+ const heldLocks = [];
115
+ for (const [name, info] of held) {
116
+ for (let i = 0; i < info.count; i++) {
117
+ heldLocks.push({ name, mode: info.mode, clientId: "" });
118
+ }
119
+ }
120
+ const pending = [];
121
+ for (const [name, q] of queue) {
122
+ for (const req of q) {
123
+ pending.push({ name, mode: req.mode, clientId: "" });
124
+ }
125
+ }
126
+ return { held: heldLocks, pending };
127
+ }
128
+ }
129
+
130
+ Object.defineProperty(globalThis.navigator, "locks", {
131
+ value: new LockManager(),
132
+ enumerable: true,
133
+ configurable: true,
134
+ });
135
+ }
@@ -0,0 +1,160 @@
1
+ // Polyfill preloads for Nub v0.1. All feature-detect and bow out
2
+ // if the global is already present. Loaded via the main preload.
3
+ //
4
+ // Node 22.15+ (our floor) already has: navigator, navigator.locks,
5
+ // navigator.hardwareConcurrency, WebSocket. No polyfills needed.
6
+ //
7
+ // Node 24+ adds: URLPattern, RegExp.escape, Error.isError, Promise.try.
8
+ // We polyfill those on Node 22.x only.
9
+ //
10
+ // No Node version ships: Temporal, reportError, browser-shape Worker.
11
+ // These need polyfills on all supported versions.
12
+
13
+ // ── reportError (WinterTC min-common-API, not in any Node) ──────────
14
+ if (typeof globalThis.reportError !== "function") {
15
+ globalThis.reportError = (err) => {
16
+ queueMicrotask(() => {
17
+ throw err;
18
+ });
19
+ };
20
+ }
21
+
22
+ // ── URLPattern (native on Node 24+, missing on 22.x) ───────────────
23
+ if (typeof globalThis.URLPattern === "undefined") {
24
+ const mod = globalThis.__nubPreloaded?.urlpattern;
25
+ const URLPattern = mod?.URLPattern;
26
+ if (URLPattern) globalThis.URLPattern = URLPattern;
27
+ }
28
+
29
+ // ── Temporal (not in any Node version) ──────────────────────────────
30
+ if (typeof globalThis.Temporal === "undefined") {
31
+ const mod = globalThis.__nubPreloaded?.temporal;
32
+ const Temporal = mod?.Temporal;
33
+ if (Temporal) globalThis.Temporal = Temporal;
34
+ }
35
+
36
+ // ── Stage 4 polyfills (native on Node 24+, missing on 22.x) ────────
37
+
38
+ // RegExp.escape
39
+ if (typeof RegExp.escape !== "function") {
40
+ const escapeRe = /[\\^$.*+?()[\]{}|]/g;
41
+ RegExp.escape = (s) => String(s).replace(escapeRe, "\\$&");
42
+ }
43
+
44
+ // Error.isError (~95% fidelity — cross-realm internal-slot unreachable)
45
+ if (typeof Error.isError !== "function") {
46
+ Error.isError = (value) => {
47
+ if (value == null || typeof value !== "object") return false;
48
+ return value instanceof Error;
49
+ };
50
+ }
51
+
52
+ // Promise.try
53
+ if (typeof Promise.try !== "function") {
54
+ Promise.try = (fn, ...args) => {
55
+ return new Promise((resolve) => resolve(fn(...args)));
56
+ };
57
+ }
58
+
59
+ // Float16Array (TC39 Stage 4, native on Node 24+)
60
+ // Partial TypedArray integration: instanceof TypedArray works via
61
+ // prototype chain setup, but ArrayBuffer.isView() returns false
62
+ // (requires V8 internal slots we can't set from userland).
63
+ if (typeof globalThis.Float16Array === "undefined") {
64
+ const TypedArray = Object.getPrototypeOf(Uint8Array);
65
+ const buf = new ArrayBuffer(2);
66
+ const f32 = new Float32Array(1);
67
+ const u32 = new Uint32Array(f32.buffer);
68
+ const u16view = new Uint16Array(buf);
69
+
70
+ function f32ToF16(val) {
71
+ f32[0] = val;
72
+ const bits = u32[0];
73
+ const sign = (bits >> 16) & 0x8000;
74
+ const exp = ((bits >> 23) & 0xff) - 127 + 15;
75
+ const frac = (bits >> 13) & 0x3ff;
76
+ if (exp <= 0) return sign;
77
+ if (exp >= 31) return sign | 0x7c00 | (frac ? 1 : 0);
78
+ return sign | (exp << 10) | frac;
79
+ }
80
+
81
+ function f16ToF32(h) {
82
+ const sign = (h & 0x8000) >> 15;
83
+ const exp = (h & 0x7c00) >> 10;
84
+ const frac = h & 0x03ff;
85
+ if (exp === 0) {
86
+ if (frac === 0) return sign ? -0 : 0;
87
+ let e = -1;
88
+ let f = frac;
89
+ while ((f & 0x400) === 0) { f <<= 1; e--; }
90
+ f &= 0x3ff;
91
+ u32[0] = (sign << 31) | ((e + 127) << 23) | (f << 13);
92
+ return f32[0];
93
+ }
94
+ if (exp === 31) {
95
+ return frac ? NaN : (sign ? -Infinity : Infinity);
96
+ }
97
+ u32[0] = (sign << 31) | ((exp - 15 + 127) << 23) | (frac << 13);
98
+ return f32[0];
99
+ }
100
+
101
+ class Float16Array {
102
+ #data;
103
+ constructor(arg) {
104
+ if (typeof arg === "number") {
105
+ this.#data = new Uint16Array(arg);
106
+ } else if (arg instanceof ArrayBuffer || arg instanceof SharedArrayBuffer) {
107
+ this.#data = new Uint16Array(arg);
108
+ } else if (ArrayBuffer.isView(arg) || Array.isArray(arg)) {
109
+ this.#data = new Uint16Array(arg.length);
110
+ for (let i = 0; i < arg.length; i++) this.#data[i] = f32ToF16(Number(arg[i]));
111
+ } else {
112
+ this.#data = new Uint16Array(0);
113
+ }
114
+ this.length = this.#data.length;
115
+ this.byteLength = this.#data.byteLength;
116
+ this.byteOffset = this.#data.byteOffset;
117
+ this.buffer = this.#data.buffer;
118
+ this.BYTES_PER_ELEMENT = 2;
119
+ return new Proxy(this, {
120
+ get(target, prop) {
121
+ if (typeof prop === "string" && /^\d+$/.test(prop)) return f16ToF32(target.#data[prop]);
122
+ return Reflect.get(target, prop);
123
+ },
124
+ set(target, prop, value) {
125
+ if (typeof prop === "string" && /^\d+$/.test(prop)) { target.#data[prop] = f32ToF16(Number(value)); return true; }
126
+ return Reflect.set(target, prop, value);
127
+ },
128
+ });
129
+ }
130
+ [Symbol.iterator]() { let i = 0; const d = this.#data; return { next: () => i < d.length ? { value: f16ToF32(d[i++]), done: false } : { done: true } }; }
131
+ static get BYTES_PER_ELEMENT() { return 2; }
132
+ }
133
+
134
+ // Set up prototype chain so `instanceof TypedArray` works.
135
+ Object.setPrototypeOf(Float16Array.prototype, TypedArray.prototype);
136
+ Object.setPrototypeOf(Float16Array, TypedArray);
137
+
138
+ globalThis.Float16Array = Float16Array;
139
+
140
+ if (typeof DataView.prototype.getFloat16 !== "function") {
141
+ DataView.prototype.getFloat16 = function (offset, le) {
142
+ return f16ToF32(this.getUint16(offset, le));
143
+ };
144
+ DataView.prototype.setFloat16 = function (offset, value, le) {
145
+ this.setUint16(offset, f32ToF16(value), le);
146
+ };
147
+ }
148
+
149
+ if (typeof Math.f16round !== "function") {
150
+ Math.f16round = (x) => f16ToF32(f32ToF16(x));
151
+ }
152
+ }
153
+
154
+ // ── navigator.locks (native on Node 24+, missing on 22.x) ──────────
155
+ if (typeof globalThis.navigator?.locks === "undefined") {
156
+ await import("./navigator-locks.mjs");
157
+ }
158
+
159
+ // ── Worker (browser-shape global, not in any Node) ──────────────────
160
+ await import("./worker-polyfill.mjs");
@@ -0,0 +1,363 @@
1
+ import module from "node:module";
2
+ import { readFileSync, writeFileSync, mkdirSync, statSync } from "node:fs";
3
+ import { fileURLToPath, pathToFileURL } from "node:url";
4
+ import { createRequire } from "node:module";
5
+ import { createHash } from "node:crypto";
6
+ import { join, dirname, resolve as pathResolve, extname as pathExtname } from "node:path";
7
+ import { transformSync } from "oxc-transform";
8
+ import { getTsconfig, createPathsMatcher } from "get-tsconfig";
9
+
10
+ const __require = createRequire(import.meta.url);
11
+
12
+ // ── Constants ───────────────────────────────────────────────────────
13
+ const TRANSPILE_EXTS = new Set([".ts", ".tsx", ".mts", ".cts", ".jsx"]);
14
+ const DATA_EXTS = { ".jsonc": "jsonc", ".json5": "json5", ".toml": "toml", ".yaml": "yaml", ".yml": "yaml", ".txt": "txt" };
15
+ const TS_PARENT_EXTS = new Set([".ts", ".tsx", ".mts", ".cts"]);
16
+
17
+ // Nub's N-API addon for data-format parsing (Rust-native YAML/TOML/JSON5/JSONC).
18
+ let nubNative = null;
19
+ for (const rel of ["./addons/nub-native.node", "../runtime/addons/nub-native.node"]) {
20
+ try { nubNative = __require(fileURLToPath(new URL(rel, import.meta.url))); break; } catch {}
21
+ }
22
+
23
+ // Packages resolved from Nub's distribution, not the user's.
24
+ const VENDORED_PACKAGES = new Set(["@oxc-project/runtime"]);
25
+
26
+ // Built-in modules provided by Nub (resolved to files in this distribution).
27
+ // connect() sockets deferred per design decision — "sockets" specifier not clobbered.
28
+ const BUILTIN_MODULES = new Map();
29
+
30
+ // Package clobbering: specifiers that resolve to a synthetic module
31
+ // re-exporting the native global instead of the userland package.
32
+ const CLOBBER_MAP = new Map([
33
+ ["@js-temporal/polyfill", () => `const T = globalThis.Temporal; export default T; export const Temporal = T;`],
34
+ ["urlpattern-polyfill", () => `export const URLPattern = globalThis.URLPattern;`],
35
+ ["abort-controller", () => `export const AbortController = globalThis.AbortController; export const AbortSignal = globalThis.AbortSignal; export default globalThis.AbortController;`],
36
+ ]);
37
+
38
+ // ── tsconfig cache ──────────────────────────────────────────────────
39
+ const tsconfigCache = new Map();
40
+
41
+ function getTsconfigForDir(dir) {
42
+ if (tsconfigCache.has(dir)) return tsconfigCache.get(dir);
43
+ const result = getTsconfig(dir);
44
+ const matcher = result ? createPathsMatcher(result) : null;
45
+ const entry = { tsconfig: result, matcher };
46
+ tsconfigCache.set(dir, entry);
47
+ return entry;
48
+ }
49
+
50
+ // ── Transpile cache ─────────────────────────────────────────────────
51
+ const NUB_VERSION = "0.1.0";
52
+ const CACHE_DISABLED = process.permission?.has !== undefined;
53
+ let cacheDir = null;
54
+
55
+ if (!CACHE_DISABLED) {
56
+ const base = process.env.XDG_CACHE_HOME || (process.env.HOME ? join(process.env.HOME, ".cache") : null);
57
+ if (base) {
58
+ cacheDir = join(base, "nub", "transpile");
59
+ try { mkdirSync(cacheDir, { recursive: true }); } catch { cacheDir = null; }
60
+ }
61
+ }
62
+
63
+ function cacheKey(source) {
64
+ return createHash("sha256").update(NUB_VERSION).update("\0").update(source).digest("hex");
65
+ }
66
+ function cacheGet(key) {
67
+ if (!cacheDir) return null;
68
+ const path = join(cacheDir, key);
69
+ const s = statSync(path, { throwIfNoEntry: false });
70
+ if (!s || !s.isFile()) return null;
71
+ return readFileSync(path, "utf8");
72
+ }
73
+ function cacheSet(key, value) {
74
+ if (!cacheDir) return;
75
+ try { writeFileSync(join(cacheDir, key), value); } catch {}
76
+ }
77
+
78
+ // ── Helpers ─────────────────────────────────────────────────────────
79
+ function extname(url) {
80
+ const path = url.includes("?") ? url.slice(0, url.indexOf("?")) : url;
81
+ const dot = path.lastIndexOf(".");
82
+ return dot === -1 ? "" : path.slice(dot);
83
+ }
84
+
85
+ function isNodeModules(url) {
86
+ return url.includes("/node_modules/") || url.includes("\\node_modules\\");
87
+ }
88
+
89
+ function fileExists(filePath) {
90
+ const s = statSync(filePath, { throwIfNoEntry: false });
91
+ return s !== undefined && s.isFile();
92
+ }
93
+
94
+ function dirExists(filePath) {
95
+ const s = statSync(filePath, { throwIfNoEntry: false });
96
+ return s !== undefined && s.isDirectory();
97
+ }
98
+
99
+ function safeRequireResolve(specifier) {
100
+ try { return __require.resolve(specifier); } catch { return null; }
101
+ }
102
+
103
+ function barePkg(specifier) {
104
+ return specifier.startsWith("@")
105
+ ? specifier.split("/").slice(0, 2).join("/")
106
+ : specifier.split("/")[0];
107
+ }
108
+
109
+ // ── Resolve hook ────────────────────────────────────────────────────
110
+ function resolve(specifier, context, nextResolve) {
111
+ // Skip node: and data: protocols.
112
+ if (specifier.startsWith("node:") || specifier.startsWith("data:")) {
113
+ return nextResolve(specifier, context);
114
+ }
115
+
116
+ // Skip Node built-in module names (without node: prefix).
117
+ if (module.builtinModules.includes(specifier)) {
118
+ return nextResolve(specifier, context);
119
+ }
120
+
121
+ // 1. Built-in modules provided by Nub.
122
+ if (BUILTIN_MODULES.has(specifier)) {
123
+ return { url: BUILTIN_MODULES.get(specifier), shortCircuit: true };
124
+ }
125
+
126
+ // 2. Vendored packages (e.g. @oxc-project/runtime).
127
+ const bare = barePkg(specifier);
128
+ if (VENDORED_PACKAGES.has(bare)) {
129
+ const resolved = safeRequireResolve(specifier);
130
+ if (resolved) return { url: pathToFileURL(resolved).href, shortCircuit: true };
131
+ }
132
+
133
+ // 2. Package clobbering.
134
+ if (CLOBBER_MAP.has(bare) && !isNodeModules(context.parentURL || "")) {
135
+ return { url: `data:text/javascript,${encodeURIComponent(CLOBBER_MAP.get(bare)())}`, shortCircuit: true };
136
+ }
137
+
138
+ // 3. tsconfig-paths (only for bare/aliased specifiers, not relative).
139
+ const parentURL = String(context.parentURL || "");
140
+ const parentExt = extname(parentURL);
141
+ if (!specifier.startsWith(".") && !specifier.startsWith("/") && !specifier.startsWith("file:") && !isNodeModules(parentURL)) {
142
+ const parentDir = parentURL.startsWith("file:") ? dirname(fileURLToPath(parentURL)) : process.cwd();
143
+ const { matcher } = getTsconfigForDir(parentDir);
144
+ if (matcher) {
145
+ const mapped = matcher(specifier);
146
+ if (mapped && mapped.length > 0) {
147
+ for (const candidate of mapped) {
148
+ const resolved = tryResolveFile(candidate, parentExt);
149
+ if (resolved) {
150
+ return { url: pathToFileURL(resolved).href, shortCircuit: true };
151
+ }
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ // 4. Extensionless probing (only when parent is a TS file).
158
+ if (TS_PARENT_EXTS.has(parentExt) && (specifier.startsWith("./") || specifier.startsWith("../"))) {
159
+ const parentDir = dirname(fileURLToPath(parentURL));
160
+ const target = pathResolve(parentDir, specifier);
161
+ const resolved = tryResolveFile(target, parentExt);
162
+ if (resolved) {
163
+ return { url: pathToFileURL(resolved).href, shortCircuit: true };
164
+ }
165
+ }
166
+
167
+ return nextResolve(specifier, context);
168
+ }
169
+
170
+ // Try to resolve a file path with extensionless probing + .js→.ts swap.
171
+ function tryResolveFile(target, parentExt) {
172
+ // If the target already has an extension and exists, use it.
173
+ const existingExt = pathExtname(target);
174
+ if (existingExt && fileExists(target)) return target;
175
+
176
+ // .js → .ts swap (tsc emit convention reversal).
177
+ if (existingExt === ".js") {
178
+ const tsSwap = target.slice(0, -3) + ".ts";
179
+ if (fileExists(tsSwap)) return tsSwap;
180
+ const tsxSwap = target.slice(0, -3) + ".tsx";
181
+ if (fileExists(tsxSwap)) return tsxSwap;
182
+ }
183
+ if (existingExt === ".jsx") {
184
+ const tsxSwap = target.slice(0, -4) + ".tsx";
185
+ if (fileExists(tsxSwap)) return tsxSwap;
186
+ }
187
+ // .mjs → .mts swap (Bun does this).
188
+ if (existingExt === ".mjs") {
189
+ const mtsSwap = target.slice(0, -4) + ".mts";
190
+ if (fileExists(mtsSwap)) return mtsSwap;
191
+ }
192
+
193
+ // Extensionless: probe in parent-ext-aware order.
194
+ if (!existingExt) {
195
+ const probeOrder = getProbeOrder(parentExt);
196
+ for (const ext of probeOrder) {
197
+ if (fileExists(target + ext)) return target + ext;
198
+ }
199
+ // Directory index probing.
200
+ if (dirExists(target)) {
201
+ for (const ext of probeOrder) {
202
+ const idx = join(target, "index" + ext);
203
+ if (fileExists(idx)) return idx;
204
+ }
205
+ }
206
+ }
207
+
208
+ return null;
209
+ }
210
+
211
+ function getProbeOrder(parentExt) {
212
+ switch (parentExt) {
213
+ case ".tsx": return [".tsx", ".ts", ".jsx", ".js", ".json"];
214
+ case ".mts": return [".mts", ".mjs"];
215
+ case ".cts": return [".cts", ".cjs"];
216
+ default: return [".ts", ".tsx", ".js", ".jsx", ".json"];
217
+ }
218
+ }
219
+
220
+ // ── Load hook ───────────────────────────────────────────────────────
221
+ function load(url, context, nextLoad) {
222
+ const ext = extname(url);
223
+
224
+ if (TRANSPILE_EXTS.has(ext)) return loadTranspile(url, ext);
225
+ if (ext in DATA_EXTS) return loadData(url, ext);
226
+
227
+ return nextLoad(url, context);
228
+ }
229
+
230
+ function loadTranspile(url, ext) {
231
+ const filePath = fileURLToPath(url);
232
+ const source = readFileSync(filePath, "utf8");
233
+ const dir = dirname(filePath);
234
+ const { tsconfig } = getTsconfigForDir(dir);
235
+ const co = tsconfig?.config?.compilerOptions;
236
+
237
+ // Cache key includes tsconfig compilerOptions so tsconfig changes invalidate.
238
+ const tsconfigHash = co ? JSON.stringify(co) : "";
239
+ const key = cacheKey(source + "\0" + ext + "\0" + tsconfigHash);
240
+ const cached = cacheGet(key);
241
+ if (cached) {
242
+ return { format: ext === ".cts" ? "commonjs" : "module", source: cached, shortCircuit: true };
243
+ }
244
+
245
+ const lang = ext === ".tsx" ? "tsx" : ext === ".jsx" ? "jsx" : "ts";
246
+ const opts = {
247
+ lang,
248
+ sourceType: ext === ".cts" ? "commonjs" : "module",
249
+ sourcemap: true,
250
+ typescript: {},
251
+ decorator: co?.experimentalDecorators !== false
252
+ ? { legacy: true, emitDecoratorMetadata: co?.emitDecoratorMetadata !== false }
253
+ : undefined,
254
+ };
255
+ if (ext === ".tsx" || ext === ".jsx") {
256
+ opts.jsx = {
257
+ runtime: co?.jsx === "react" ? "classic" : "automatic",
258
+ importSource: co?.jsxImportSource || "react",
259
+ };
260
+ if (co?.jsxFactory) opts.jsx.pragma = co.jsxFactory;
261
+ if (co?.jsxFragmentFactory) opts.jsx.pragmaFrag = co.jsxFragmentFactory;
262
+ }
263
+
264
+ const result = transformSync(filePath, source, opts);
265
+ if (result.errors.length > 0) {
266
+ const details = result.errors.map((e) => e.codeframe || e.message).join("\n\n");
267
+ throw new Error(`Transpile error in ${filePath}:\n${details}`);
268
+ }
269
+
270
+ let code = result.code;
271
+ if (result.map) {
272
+ const map = typeof result.map === "string" ? JSON.parse(result.map) : result.map;
273
+ map.sourcesContent = [source];
274
+ code += `\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(JSON.stringify(map)).toString("base64")}\n`;
275
+ }
276
+
277
+ cacheSet(key, code);
278
+ return { format: ext === ".cts" ? "commonjs" : "module", source: code, shortCircuit: true };
279
+ }
280
+
281
+ function loadData(url, ext) {
282
+ const filePath = fileURLToPath(url);
283
+ const raw = readFileSync(filePath, "utf8");
284
+ const kind = DATA_EXTS[ext];
285
+
286
+ if (kind === "txt") {
287
+ return { format: "module", source: `export default ${JSON.stringify(raw)};\n`, shortCircuit: true };
288
+ }
289
+
290
+ let parsed;
291
+ if (nubNative) {
292
+ if (kind === "yaml") parsed = nubNative.parseYaml(raw);
293
+ else if (kind === "toml") parsed = nubNative.parseToml(raw);
294
+ else if (kind === "json5") parsed = nubNative.parseJson5(raw);
295
+ else if (kind === "jsonc") parsed = nubNative.parseJsonc(raw);
296
+ } else {
297
+ if (kind === "yaml") parsed = lazyRequire("yaml").parse(raw);
298
+ else if (kind === "toml") parsed = lazyRequire("@iarna/toml").parse(raw);
299
+ else if (kind === "json5") parsed = lazyRequire("json5").parse(raw);
300
+ else if (kind === "jsonc") parsed = JSON.parse(stripJsonComments(raw));
301
+ }
302
+
303
+ if (parsed == null) {
304
+ return { format: "module", source: "export default undefined;\n", shortCircuit: true };
305
+ }
306
+
307
+ let code = `const _data = ${JSON.stringify(parsed)};\nexport default _data;\n`;
308
+ if (typeof parsed === "object" && !Array.isArray(parsed)) {
309
+ for (const key of Object.keys(parsed)) {
310
+ if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)) {
311
+ code += `export const ${key} = _data[${JSON.stringify(key)}];\n`;
312
+ }
313
+ }
314
+ }
315
+ return { format: "module", source: code, shortCircuit: true };
316
+ }
317
+
318
+ function lazyRequire(pkg) {
319
+ try { return __require(pkg); } catch {
320
+ throw new Error(`Nub: importing this file requires the "${pkg}" package.\nInstall it: npm install ${pkg}`);
321
+ }
322
+ }
323
+
324
+ function stripJsonComments(text) {
325
+ let result = "", i = 0, inString = false, escape = false;
326
+ while (i < text.length) {
327
+ const ch = text[i];
328
+ if (escape) { result += ch; escape = false; i++; continue; }
329
+ if (inString) { if (ch === "\\") escape = true; if (ch === '"') inString = false; result += ch; i++; continue; }
330
+ if (ch === '"') { inString = true; result += ch; i++; continue; }
331
+ if (ch === "/" && text[i + 1] === "/") { while (i < text.length && text[i] !== "\n") i++; continue; }
332
+ if (ch === "/" && text[i + 1] === "*") { i += 2; while (i < text.length && !(text[i] === "*" && text[i + 1] === "/")) i++; i += 2; continue; }
333
+ result += ch; i++;
334
+ }
335
+ return result;
336
+ }
337
+
338
+ // ── Pre-load clobbered polyfill packages BEFORE hooks register ──────
339
+ // Packages in CLOBBER_MAP can't be imported after hooks register because
340
+ // the resolve hook returns a synthetic module instead of the real package.
341
+ // Load them here via CJS require (which isn't yet hooked) and stash them.
342
+ const __preloadedPolyfills = {};
343
+ try { __preloadedPolyfills.temporal = __require("@js-temporal/polyfill"); } catch {}
344
+ try { __preloadedPolyfills.urlpattern = __require("urlpattern-polyfill"); } catch {}
345
+
346
+ // ── Register hooks ──────────────────────────────────────────────────
347
+ module.registerHooks({ resolve, load });
348
+
349
+ // ── Polyfill preloads ───────────────────────────────────────────────
350
+ globalThis.__nubPreloaded = __preloadedPolyfills;
351
+ await import("./polyfills.mjs");
352
+ delete globalThis.__nubPreloaded;
353
+ delete globalThis.__nubRequire;
354
+ delete globalThis.__nubRequire;
355
+
356
+ // ── Watch-mode dependency reporting ─────────────────────────────────
357
+ if (process.env.WATCH_REPORT_DEPENDENCIES === "1" && process.send) {
358
+ const deps = [];
359
+ for (const [, entry] of tsconfigCache) {
360
+ if (entry.tsconfig?.path) deps.push(entry.tsconfig.path);
361
+ }
362
+ if (deps.length > 0) process.send({ "watch:require": deps });
363
+ }
@@ -0,0 +1,91 @@
1
+ // Browser-shape Worker global polyfill for Node.js.
2
+ // Wraps node:worker_threads.Worker with EventTarget inheritance,
3
+ // real MessageEvent/ErrorEvent, and URL-only constructor (Deno shape).
4
+
5
+ import { Worker as NodeWorker, parentPort, isMainThread } from "node:worker_threads";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ if (typeof globalThis.Worker === "undefined") {
9
+ class Worker extends EventTarget {
10
+ #worker;
11
+
12
+ constructor(url, options = {}) {
13
+ super();
14
+
15
+ let workerPath;
16
+ if (url instanceof URL) {
17
+ workerPath = fileURLToPath(url);
18
+ } else if (typeof url === "string") {
19
+ if (url.startsWith("file://")) {
20
+ workerPath = fileURLToPath(url);
21
+ } else {
22
+ workerPath = url;
23
+ }
24
+ } else {
25
+ throw new TypeError("Worker constructor: url must be a string or URL");
26
+ }
27
+
28
+ const type = options.type || "module";
29
+ this.#worker = new NodeWorker(workerPath, {
30
+ ...options,
31
+ eval: false,
32
+ execArgv: process.execArgv,
33
+ });
34
+
35
+ this.#worker.on("message", (data) => {
36
+ this.dispatchEvent(new MessageEvent("message", { data }));
37
+ });
38
+
39
+ this.#worker.on("messageerror", (err) => {
40
+ this.dispatchEvent(new MessageEvent("messageerror", { data: err }));
41
+ });
42
+
43
+ this.#worker.on("error", (err) => {
44
+ this.dispatchEvent(new ErrorEvent("error", { error: err, message: err.message }));
45
+ });
46
+
47
+ this.#worker.on("exit", (code) => {
48
+ this.dispatchEvent(new Event("exit"));
49
+ });
50
+ }
51
+
52
+ postMessage(data, transfer) {
53
+ this.#worker.postMessage(data, transfer);
54
+ }
55
+
56
+ terminate() {
57
+ return this.#worker.terminate();
58
+ }
59
+
60
+ #onmessageHandler = null;
61
+ get onmessage() { return this.#onmessageHandler; }
62
+ set onmessage(fn) {
63
+ if (this.#onmessageHandler) this.removeEventListener("message", this.#onmessageHandler);
64
+ this.#onmessageHandler = fn;
65
+ if (fn) this.addEventListener("message", fn);
66
+ }
67
+
68
+ #onerrorHandler = null;
69
+ get onerror() { return this.#onerrorHandler; }
70
+ set onerror(fn) {
71
+ if (this.#onerrorHandler) this.removeEventListener("error", this.#onerrorHandler);
72
+ this.#onerrorHandler = fn;
73
+ if (fn) this.addEventListener("error", fn);
74
+ }
75
+ }
76
+
77
+ globalThis.Worker = Worker;
78
+ }
79
+
80
+ // Worker-side bootstrap: set up self, postMessage, close.
81
+ if (!isMainThread && parentPort) {
82
+ if (typeof globalThis.self === "undefined") {
83
+ globalThis.self = globalThis;
84
+ }
85
+ if (typeof globalThis.postMessage === "undefined") {
86
+ globalThis.postMessage = (data, transfer) => parentPort.postMessage(data, transfer);
87
+ }
88
+ if (typeof globalThis.close === "undefined") {
89
+ globalThis.close = () => process.exit(0);
90
+ }
91
+ }