@nubjs/nub-win32-arm64 0.0.4 → 0.0.7
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.exe +0 -0
- package/package.json +1 -1
- package/runtime/addons/nub-native.node +0 -0
- package/runtime/cache-evict.mjs +69 -0
- package/runtime/node_modules/@oxc-parser/binding-win32-arm64-msvc/README.md +3 -0
- package/runtime/node_modules/@oxc-parser/binding-win32-arm64-msvc/package.json +39 -0
- package/runtime/node_modules/@oxc-parser/binding-win32-arm64-msvc/parser.win32-arm64-msvc.node +0 -0
- package/runtime/node_modules/@oxc-transform/binding-win32-arm64-msvc/README.md +3 -0
- package/runtime/node_modules/@oxc-transform/binding-win32-arm64-msvc/package.json +41 -0
- package/runtime/node_modules/@oxc-transform/binding-win32-arm64-msvc/transform.win32-arm64-msvc.node +0 -0
- package/runtime/polyfills.mjs +73 -97
- package/runtime/preload-async-hooks.mjs +50 -0
- package/runtime/preload.mjs +274 -320
- package/runtime/transform-core.mjs +762 -0
- package/runtime/version.mjs +12 -0
- package/runtime/worker-polyfill.mjs +147 -9
- package/runtime/node_modules/get-tsconfig/LICENSE +0 -21
- package/runtime/node_modules/get-tsconfig/README.md +0 -268
- package/runtime/node_modules/get-tsconfig/dist/index.cjs +0 -7
- package/runtime/node_modules/get-tsconfig/dist/index.d.cts +0 -2116
- package/runtime/node_modules/get-tsconfig/dist/index.d.mts +0 -2116
- package/runtime/node_modules/get-tsconfig/dist/index.mjs +0 -7
- package/runtime/node_modules/get-tsconfig/package.json +0 -46
- package/runtime/node_modules/oxc-transform/LICENSE +0 -22
- package/runtime/node_modules/oxc-transform/README.md +0 -84
- package/runtime/node_modules/oxc-transform/browser.js +0 -1
- package/runtime/node_modules/oxc-transform/index.d.ts +0 -658
- package/runtime/node_modules/oxc-transform/index.js +0 -598
- package/runtime/node_modules/oxc-transform/package.json +0 -114
- package/runtime/node_modules/oxc-transform/webcontainer-fallback.cjs +0 -21
- package/runtime/node_modules/resolve-pkg-maps/LICENSE +0 -21
- package/runtime/node_modules/resolve-pkg-maps/README.md +0 -216
- package/runtime/node_modules/resolve-pkg-maps/dist/index.cjs +0 -1
- package/runtime/node_modules/resolve-pkg-maps/dist/index.d.cts +0 -11
- package/runtime/node_modules/resolve-pkg-maps/dist/index.d.mts +0 -11
- package/runtime/node_modules/resolve-pkg-maps/dist/index.mjs +0 -1
- package/runtime/node_modules/resolve-pkg-maps/package.json +0 -42
package/runtime/preload.mjs
CHANGED
|
@@ -1,363 +1,317 @@
|
|
|
1
|
+
// Nub fast-path preload — Node 22.15+ (sync `module.registerHooks`).
|
|
2
|
+
//
|
|
3
|
+
// This file is the main-thread `--import` preload for ALL tiers. It owns only
|
|
4
|
+
// the tier-specific wiring; every resolution + transpile primitive lives in
|
|
5
|
+
// runtime/transform-core.mjs (shared verbatim with the compat-tier loader
|
|
6
|
+
// worker, so the two can never drift). What stays here:
|
|
7
|
+
// - watch-mode dependency IPC (main-thread only),
|
|
8
|
+
// - the thin resolve/load hooks that delegate to the core,
|
|
9
|
+
// - the main-thread CommonJS `require()` shim (Module._resolveFilename +
|
|
10
|
+
// require.extensions), installed on BOTH tiers — `module.register` hooks ESM
|
|
11
|
+
// but not require, and `module.registerHooks`' require coverage is incomplete
|
|
12
|
+
// before ~Node 24 (e.g. require-from-`.cts` on 22.15),
|
|
13
|
+
// - clobbered-polyfill preloading + the Temporal lazy global,
|
|
14
|
+
// - tier dispatch (registerHooks vs register).
|
|
15
|
+
|
|
1
16
|
import module from "node:module";
|
|
2
|
-
import {
|
|
17
|
+
import { readdirSync } from "node:fs";
|
|
3
18
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
19
|
import { createRequire } from "node:module";
|
|
5
|
-
import { createHash } from "node:crypto";
|
|
6
20
|
import { join, dirname, resolve as pathResolve, extname as pathExtname } from "node:path";
|
|
7
|
-
import {
|
|
8
|
-
|
|
21
|
+
import {
|
|
22
|
+
TRANSPILE_EXTS, DATA_EXTS, TS_PARENT_EXTS,
|
|
23
|
+
extname, isNodeModules, getTsconfigForDir, getPackageType,
|
|
24
|
+
resolveSpec, resolveCjsPath, requireTargetIsEsm, loadTranspile, loadData,
|
|
25
|
+
maybeSweepCache, setWatchHooks, ensureParser,
|
|
26
|
+
} from "./transform-core.mjs";
|
|
9
27
|
|
|
10
28
|
const __require = createRequire(import.meta.url);
|
|
11
29
|
|
|
12
|
-
// ──
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
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;
|
|
30
|
+
// ── Watch-mode dependency reporting ─────────────────────────────────
|
|
31
|
+
// Under `nub watch`, Node's FilesWatcher only watches files in the import graph;
|
|
32
|
+
// config files (tsconfig.json, package.json) and `.env*` are NOT in any graph,
|
|
33
|
+
// so an edit to them otherwise goes stale. Node accepts incremental
|
|
34
|
+
// `process.send({'watch:require': [...]})` over its WATCH_REPORT_DEPENDENCIES
|
|
35
|
+
// IPC at ANY point in the child's life (it adds each path to the watch set), so
|
|
36
|
+
// we report config paths AS the core loader discovers them. The reporters are
|
|
37
|
+
// injected into the core via setWatchHooks (below) so getTsconfigForDir /
|
|
38
|
+
// getPackageType self-report. The flush is coalesced via setImmediate.
|
|
39
|
+
const WATCH_REPORTING = process.env.WATCH_REPORT_DEPENDENCIES === "1" && typeof process.send === "function";
|
|
40
|
+
const watchReported = new Set();
|
|
41
|
+
const watchPending = [];
|
|
42
|
+
let watchFlushScheduled = false;
|
|
43
|
+
function flushWatchDeps() {
|
|
44
|
+
watchFlushScheduled = false;
|
|
45
|
+
if (watchPending.length === 0) return;
|
|
46
|
+
const batch = watchPending.splice(0, watchPending.length);
|
|
47
|
+
try { process.send({ "watch:require": batch }); } catch {}
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
try { mkdirSync(cacheDir, { recursive: true }); } catch { cacheDir = null; }
|
|
49
|
+
function reportWatchDep(path) {
|
|
50
|
+
if (!WATCH_REPORTING || !path || watchReported.has(path)) return;
|
|
51
|
+
watchReported.add(path);
|
|
52
|
+
watchPending.push(path);
|
|
53
|
+
if (!watchFlushScheduled) {
|
|
54
|
+
watchFlushScheduled = true;
|
|
55
|
+
// A scheduled immediate is drained before the loop would exit, so even a
|
|
56
|
+
// script that finishes synchronously flushes its deps. (Don't unref: an
|
|
57
|
+
// unref'd immediate is skipped on a synchronous exit, dropping the report.)
|
|
58
|
+
setImmediate(flushWatchDeps);
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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; }
|
|
61
|
+
// Report a directory's `.env*` files (the natural watch targets). Scanned once
|
|
62
|
+
// per directory, lazily.
|
|
63
|
+
const watchEnvScannedDirs = new Set();
|
|
64
|
+
function reportEnvFilesIn(dir) {
|
|
65
|
+
if (!WATCH_REPORTING || watchEnvScannedDirs.has(dir)) return;
|
|
66
|
+
watchEnvScannedDirs.add(dir);
|
|
67
|
+
let entries;
|
|
68
|
+
try { entries = readdirSync(dir); } catch { return; }
|
|
69
|
+
for (const name of entries) {
|
|
70
|
+
if (name === ".env" || name.startsWith(".env.")) reportWatchDep(join(dir, name));
|
|
71
|
+
}
|
|
101
72
|
}
|
|
73
|
+
setWatchHooks({ reportDep: reportWatchDep, reportEnvDir: reportEnvFilesIn });
|
|
102
74
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
? specifier.split("/").slice(0, 2).join("/")
|
|
106
|
-
: specifier.split("/")[0];
|
|
107
|
-
}
|
|
75
|
+
// Best-effort bounded-cache eviction (main thread only; the core guards on it).
|
|
76
|
+
maybeSweepCache();
|
|
108
77
|
|
|
109
78
|
// ── Resolve hook ────────────────────────────────────────────────────
|
|
110
79
|
function resolve(specifier, context, nextResolve) {
|
|
111
|
-
|
|
112
|
-
|
|
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
|
-
}
|
|
80
|
+
const r = resolveSpec(specifier, context.parentURL);
|
|
81
|
+
return r ?? nextResolve(specifier, context);
|
|
218
82
|
}
|
|
219
83
|
|
|
220
84
|
// ── Load hook ───────────────────────────────────────────────────────
|
|
221
85
|
function load(url, context, nextLoad) {
|
|
222
86
|
const ext = extname(url);
|
|
223
87
|
|
|
88
|
+
// Watch mode: surface this file's nearest config files (tsconfig.json,
|
|
89
|
+
// package.json) + sibling `.env*` so edits to them restart the run. Done for
|
|
90
|
+
// every user file (not just transpiled ones) — getTsconfigForDir/getPackageType
|
|
91
|
+
// self-report via the injected watch hooks.
|
|
92
|
+
if (WATCH_REPORTING && url.startsWith("file:") && !isNodeModules(url)) {
|
|
93
|
+
try {
|
|
94
|
+
const dir = dirname(fileURLToPath(url));
|
|
95
|
+
getTsconfigForDir(dir);
|
|
96
|
+
getPackageType(dir);
|
|
97
|
+
} catch {}
|
|
98
|
+
}
|
|
99
|
+
|
|
224
100
|
if (TRANSPILE_EXTS.has(ext)) return loadTranspile(url, ext);
|
|
225
101
|
if (ext in DATA_EXTS) return loadData(url, ext);
|
|
226
102
|
|
|
227
103
|
return nextLoad(url, context);
|
|
228
104
|
}
|
|
229
105
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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 };
|
|
106
|
+
// ── CommonJS require() augmentation (BOTH tiers) ────────────────────
|
|
107
|
+
// `module.registerHooks`' CJS-`require()` coverage is INCOMPLETE before ~Node 24:
|
|
108
|
+
// on Node 22.15 a `require()` from a `.cts` parent (which Node loads via the ESM
|
|
109
|
+
// translator's special-require) hits native Module._resolveFilename with no
|
|
110
|
+
// tsconfig/extensionless handling — a `require('@alias')` or `require('./x')` of a
|
|
111
|
+
// `.ts` target throws MODULE_NOT_FOUND, while the same code works on Node 26 (where
|
|
112
|
+
// registerHooks does cover it) and on the fast `import` path. On the compat tier
|
|
113
|
+
// (18.19–22.14) the only hook surface is `module.register`, which intercepts the
|
|
114
|
+
// ESM loader ONLY — so `require()` is entirely unaugmented there. Both gaps have
|
|
115
|
+
// the same closure: install this main-thread CJS shim, reusing the core's canonical
|
|
116
|
+
// resolveCjsPath / loadTranspile (no drift). It tries nub's resolution first and
|
|
117
|
+
// FALLS THROUGH to native on a miss, so it is a safe no-op on the versions where
|
|
118
|
+
// registerHooks already covers require (Node 24+/26). Mechanism stays within the
|
|
119
|
+
// augmenter rules: exactly what `--require`-installing the ts-node / tsx CJS shim
|
|
120
|
+
// has always done. So it runs on the fast tier too — registerHooks is necessary
|
|
121
|
+
// but, below ~Node 24, not sufficient for require().
|
|
122
|
+
// This error is surfaced ONLY on Node versions without native require(esm)
|
|
123
|
+
// (< 20.19 / 22.0–22.11), where require() of an ES module genuinely cannot work.
|
|
124
|
+
// On every require(esm)-capable Node, Node loads the ES module itself and this is
|
|
125
|
+
// never reached. The message is user-facing: no internal mechanism names.
|
|
126
|
+
function requireEsmError(filename) {
|
|
127
|
+
const err = new Error(
|
|
128
|
+
`Cannot require() this file — it is an ES module.\n` +
|
|
129
|
+
` ${filename}\n` +
|
|
130
|
+
`It uses \`import\`/\`export\`, so it loads as an ES module, and this version of ` +
|
|
131
|
+
`Node can't require() an ES module. Load it with \`import(...)\` instead, rename ` +
|
|
132
|
+
`it to .cts for a CommonJS module, or upgrade Node.`,
|
|
133
|
+
);
|
|
134
|
+
err.code = "ERR_REQUIRE_ESM";
|
|
135
|
+
return err;
|
|
279
136
|
}
|
|
280
137
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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`;
|
|
138
|
+
// `withClassicTranspile` — also install the `require.extensions` (classic CommonJS
|
|
139
|
+
// loader) transpile hook. This is needed ONLY on Node WITHOUT native require(esm)
|
|
140
|
+
// (< 20.19 / 22.0–22.11): there, `module.register`'s ESM-loader hooks can't reach a
|
|
141
|
+
// `require()`, AND an ES module simply can't be require()d, so we transpile CJS
|
|
142
|
+
// content classically and surface a clean error for ESM content. On require(esm)-
|
|
143
|
+
// capable Node we DON'T install it — registering `require.extensions['.ts']` would
|
|
144
|
+
// shadow Node's own native require(esm) of ES-module `.ts` files (breaking
|
|
145
|
+
// `require("./esm.ts")`), and the resolve shim below plus the tier's load hook
|
|
146
|
+
// already cover resolution + transpile.
|
|
147
|
+
function installCjsRequireHooks(withClassicTranspile) {
|
|
148
|
+
// Module._resolveFilename: try nub's resolution first (tsconfig paths,
|
|
149
|
+
// extensionless .ts, .js→.ts). If the target is an ES-module TS file AND this
|
|
150
|
+
// Node can't require(esm), throw a clean error HERE — before Node's special-
|
|
151
|
+
// require (used for require() from a CJS module loaded via the ESM translator)
|
|
152
|
+
// crashes with an opaque `cjsCache.get(...)` TypeError. On require(esm)-capable
|
|
153
|
+
// Node, return the path and let Node load the ES module itself. On miss/own
|
|
154
|
+
// error, fall through to Node (augmentation never masks Node's diagnostics).
|
|
155
|
+
const origResolveFilename = module._resolveFilename;
|
|
156
|
+
module._resolveFilename = function (request, parent, isMain, options) {
|
|
157
|
+
let resolved = null;
|
|
158
|
+
try {
|
|
159
|
+
const parentPath = parent && typeof parent.filename === "string" ? parent.filename : null;
|
|
160
|
+
resolved = resolveCjsPath(request, parentPath);
|
|
161
|
+
} catch { /* fall through to Node */ }
|
|
162
|
+
if (resolved) {
|
|
163
|
+
if (withClassicTranspile && requireTargetIsEsm(resolved, pathExtname(resolved))) {
|
|
164
|
+
throw requireEsmError(resolved);
|
|
312
165
|
}
|
|
166
|
+
return resolved;
|
|
313
167
|
}
|
|
314
|
-
|
|
315
|
-
|
|
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
|
-
}
|
|
168
|
+
return origResolveFilename.call(this, request, parent, isMain, options);
|
|
169
|
+
};
|
|
323
170
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
171
|
+
if (!withClassicTranspile) return;
|
|
172
|
+
|
|
173
|
+
// require.extensions: transpile via the SAME loadTranspile the load hook uses —
|
|
174
|
+
// target:'es2022' lowering (`using`), tsconfig, source maps, the Stage-3
|
|
175
|
+
// decorator guard, and module-format detection are all identical to the fast
|
|
176
|
+
// tier. The path is already a real TS file (Module._resolveFilename ran first).
|
|
177
|
+
// A module-format source can't be _compile'd as CJS — same clean error as above.
|
|
178
|
+
const transpileExtension = (mod, filename) => {
|
|
179
|
+
const { source, format } = loadTranspile(pathToFileURL(filename).href, pathExtname(filename));
|
|
180
|
+
if (format === "module") throw requireEsmError(filename);
|
|
181
|
+
mod._compile(source, filename);
|
|
182
|
+
};
|
|
183
|
+
for (const ext of [".ts", ".cts", ".mts", ".tsx", ".jsx"]) {
|
|
184
|
+
module._extensions[ext] = transpileExtension;
|
|
334
185
|
}
|
|
335
|
-
return result;
|
|
336
186
|
}
|
|
337
187
|
|
|
338
188
|
// ── Pre-load clobbered polyfill packages BEFORE hooks register ──────
|
|
339
|
-
// Packages in CLOBBER_MAP can't be imported after hooks register
|
|
340
|
-
// the resolve hook returns a synthetic module instead of the real
|
|
341
|
-
// Load them here via CJS require (
|
|
189
|
+
// Packages in the core's CLOBBER_MAP can't be imported after hooks register
|
|
190
|
+
// because the resolve hook returns a synthetic module instead of the real
|
|
191
|
+
// package. Load them here via CJS require (not yet hooked) and stash them.
|
|
192
|
+
// Temporal is the exception (A37): the polyfill is ~18ms to load and most scripts
|
|
193
|
+
// never touch it, so we only RESOLVE its path now (cheap) and defer the load to a
|
|
194
|
+
// lazy global getter (below). Requiring it later by absolute path bypasses the
|
|
195
|
+
// CLOBBER_MAP resolve-hook entry, which keys on the "@js-temporal/polyfill"
|
|
196
|
+
// specifier — not the resolved path.
|
|
342
197
|
const __preloadedPolyfills = {};
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
198
|
+
// Feature-detect before requiring (A39): URLPattern is native on Node 24+, so
|
|
199
|
+
// skip loading the polyfill there. On 22.x it's absent → load it.
|
|
200
|
+
if (typeof globalThis.URLPattern === "undefined") {
|
|
201
|
+
try { __preloadedPolyfills.urlpattern = __require("urlpattern-polyfill"); } catch {}
|
|
202
|
+
}
|
|
203
|
+
// Float16Array: native on Node 24+, absent on the 22.x floor.
|
|
204
|
+
if (typeof globalThis.Float16Array === "undefined") {
|
|
205
|
+
try { __preloadedPolyfills.float16 = __require("@petamoriken/float16"); } catch {}
|
|
206
|
+
}
|
|
207
|
+
let __temporalPath;
|
|
208
|
+
try { __temporalPath = __require.resolve("@js-temporal/polyfill"); } catch {}
|
|
209
|
+
|
|
210
|
+
// ── Tier dispatch ───────────────────────────────────────────────────
|
|
211
|
+
// Three tiers per wiki/research/supported-node-versions.md:
|
|
212
|
+
// - >= 22.15.0: sync module.registerHooks (fast path, in-thread)
|
|
213
|
+
// - >= 18.19.0 < 22.15: async module.register (loader worker) + main-thread
|
|
214
|
+
// CJS require() shim (module.register is ESM-only)
|
|
215
|
+
// - < 18.19.0: unsupported (Rust spawn path hard-errors; defensive log)
|
|
216
|
+
//
|
|
217
|
+
// No user-visible distinction between the two augmentation tiers — both deliver
|
|
218
|
+
// the identical feature surface, silently. The compat-mode notice was dropped
|
|
219
|
+
// 2026-05-29 (it labeled a purely internal mechanism choice).
|
|
220
|
+
const __nodeVersionParts = process.versions.node.split(".").map((n) => parseInt(n, 10));
|
|
221
|
+
const __nodeMajor = __nodeVersionParts[0] || 0;
|
|
222
|
+
const __nodeMinor = __nodeVersionParts[1] || 0;
|
|
223
|
+
const __isAugmentedTier = __nodeMajor > 22 || (__nodeMajor === 22 && __nodeMinor >= 15);
|
|
224
|
+
const __isCompatTier = !__isAugmentedTier && (__nodeMajor > 18 || (__nodeMajor === 18 && __nodeMinor >= 19));
|
|
225
|
+
// Native TypeScript support (`process.features.typescript` is "strip"/"transform"
|
|
226
|
+
// — Node 22.18+/24+). Where present, Node loads `.ts` from require() itself,
|
|
227
|
+
// INCLUDING ES-module `.ts` via native require(esm); registering the classic
|
|
228
|
+
// `require.extensions['.ts']` shim there would shadow that and break
|
|
229
|
+
// `require("./esm.ts")`. Where absent (≤ 22.17 / the whole compat tier), Node can't
|
|
230
|
+
// load a required `.ts` on its own, so the shim is required — it transpiles CJS
|
|
231
|
+
// content and surfaces a clean error for ES-module content (which require() can't
|
|
232
|
+
// load there anyway). Feature-detected, not version-gated.
|
|
233
|
+
const __hasNativeTs = !!process.features?.typescript;
|
|
234
|
+
|
|
235
|
+
if (__isAugmentedTier) {
|
|
236
|
+
// Fast path: sync, in-thread hooks. Same realm as user code; covers `import` and
|
|
237
|
+
// (Node 24+) `require`. registerHooks' require RESOLUTION is incomplete on
|
|
238
|
+
// 22.15–24, so also install the main-thread resolve shim. Install the classic
|
|
239
|
+
// require.extensions transpile shim only on 22.15–22.17 (no native `.ts`); on
|
|
240
|
+
// 22.18+/24+ skip it so Node's native require() of `.ts` — incl. ES modules —
|
|
241
|
+
// isn't shadowed (see installCjsRequireHooks).
|
|
242
|
+
module.registerHooks({ resolve, load });
|
|
243
|
+
installCjsRequireHooks(!__hasNativeTs);
|
|
244
|
+
} else if (__isCompatTier) {
|
|
245
|
+
// Compat path: ESM `import` hooks run in a dedicated loader worker thread.
|
|
246
|
+
module.register("./preload-async-hooks.mjs", import.meta.url);
|
|
247
|
+
// The main-thread CommonJS require() shim's format detection is synchronous and
|
|
248
|
+
// reaches down to Node 18.19, where `require("oxc-parser")` (ESM-only) fails —
|
|
249
|
+
// so preload the parser via dynamic import now, while we can still await.
|
|
250
|
+
await ensureParser();
|
|
251
|
+
// module.register() is ESM-loader-only; augment CommonJS require() on the main
|
|
252
|
+
// thread too. The compat tier never has native `.ts`, so it always installs the
|
|
253
|
+
// classic transpile shim (CJS transpile + clean error for ES-module require()).
|
|
254
|
+
installCjsRequireHooks(!__hasNativeTs);
|
|
255
|
+
} else {
|
|
256
|
+
// Defensive: Rust spawn path hard-errors on < 18.19 before reaching here. If
|
|
257
|
+
// invoked directly via `node --import`, emit a clear message and skip hook
|
|
258
|
+
// registration rather than throw (throwing breaks user-invoked --import flows).
|
|
259
|
+
process.stderr.write(
|
|
260
|
+
`Nub requires Node 18.19 or newer for runtime augmentation; got ${process.versions.node}. Preload is inactive.\n`,
|
|
261
|
+
);
|
|
262
|
+
}
|
|
348
263
|
|
|
349
|
-
// ── Polyfill preloads
|
|
264
|
+
// ── Polyfill preloads (tier-independent) ────────────────────────────
|
|
265
|
+
// Polyfills install identically on both augmented and compat paths.
|
|
350
266
|
globalThis.__nubPreloaded = __preloadedPolyfills;
|
|
351
267
|
await import("./polyfills.mjs");
|
|
352
268
|
delete globalThis.__nubPreloaded;
|
|
353
|
-
delete globalThis.__nubRequire;
|
|
354
|
-
delete globalThis.__nubRequire;
|
|
355
269
|
|
|
356
|
-
// ──
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
270
|
+
// ── Temporal: lazy global (A37) ─────────────────────────────────────
|
|
271
|
+
// Temporal ships in no supported Node, so nub always provides it — but the
|
|
272
|
+
// polyfill is ~18ms to load and rarely used, so install a lazy getter that loads
|
|
273
|
+
// it (by resolved path, bypassing the clobber) on first access. The CLOBBER
|
|
274
|
+
// re-export of `import "@js-temporal/polyfill"` reads globalThis.Temporal, so a
|
|
275
|
+
// user importing the package triggers this same one-time load. A plain assignment
|
|
276
|
+
// (`globalThis.Temporal = …`) replaces the accessor with the value.
|
|
277
|
+
if (typeof globalThis.Temporal === "undefined" && __temporalPath) {
|
|
278
|
+
const defineTemporal = (value) =>
|
|
279
|
+
Object.defineProperty(globalThis, "Temporal", {
|
|
280
|
+
value,
|
|
281
|
+
configurable: true,
|
|
282
|
+
writable: true,
|
|
283
|
+
enumerable: false,
|
|
284
|
+
});
|
|
285
|
+
Object.defineProperty(globalThis, "Temporal", {
|
|
286
|
+
configurable: true,
|
|
287
|
+
enumerable: false,
|
|
288
|
+
get() {
|
|
289
|
+
const polyfill = __require(__temporalPath);
|
|
290
|
+
// @js-temporal/polyfill exports `toTemporalInstant` as a function but does
|
|
291
|
+
// NOT auto-install it on Date.prototype (you assign it yourself). Install it
|
|
292
|
+
// here so that on the floor (no native Temporal) `date.toTemporalInstant()`
|
|
293
|
+
// AND the package clobber's re-export of `Date.prototype.toTemporalInstant`
|
|
294
|
+
// both work — matching native Node. Guarded so we never replace a native
|
|
295
|
+
// implementation on a runtime that ships Temporal.
|
|
296
|
+
if (
|
|
297
|
+
typeof Date.prototype.toTemporalInstant !== "function" &&
|
|
298
|
+
typeof polyfill.toTemporalInstant === "function"
|
|
299
|
+
) {
|
|
300
|
+
Object.defineProperty(Date.prototype, "toTemporalInstant", {
|
|
301
|
+
value: polyfill.toTemporalInstant,
|
|
302
|
+
configurable: true,
|
|
303
|
+
writable: true,
|
|
304
|
+
enumerable: false,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
const T = polyfill.Temporal;
|
|
308
|
+
defineTemporal(T);
|
|
309
|
+
return T;
|
|
310
|
+
},
|
|
311
|
+
set: defineTemporal,
|
|
312
|
+
});
|
|
363
313
|
}
|
|
314
|
+
|
|
315
|
+
// Watch-mode dependency reporting is incremental — see reportWatchDep + the
|
|
316
|
+
// injected core hooks. Config deps are reported as the loader discovers each user
|
|
317
|
+
// file, plus their `.env*` siblings.
|