@nubjs/nub-darwin-x64 0.1.13 → 0.1.14

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 CHANGED
Binary file
package/bin/nubx CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nubjs/nub-darwin-x64",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Nub binary for darwin-x64",
5
5
  "license": "MIT",
6
6
  "repository": "https://github.com/nubjs/nub",
Binary file
@@ -257,6 +257,76 @@ function registerLoaderWorker(specifier, parentURL, options) {
257
257
  }
258
258
  }
259
259
 
260
+ // Is this error Node's "an async `module.register` loader cannot service a SYNCHRONOUS
261
+ // resolve/load" stub? On Node 22.15–~24.11 the async-hooks proxy's `resolveSync`/
262
+ // `loadSync` are stubs that unconditionally `throw new ERR_METHOD_NOT_IMPLEMENTED(...)`.
263
+ // nub's fast-tier SYNC `module.registerHooks` hooks force EVERY resolve/load onto the
264
+ // synchronous chain; when a USER async loader (e.g. @tailwindcss/node's
265
+ // esm-cache.loader.mjs under Turbopack) is ALSO registered, the chain's default step
266
+ // reaches that stub and throws — killing the build. We must detect this WITHOUT the
267
+ // `userAsyncLoaderActive()` flag: the very FIRST throwing resolution is the loader
268
+ // module's own specifier, resolved DURING `module.register` before the detector flag is
269
+ // observable, so the flag is false exactly when recovery is needed. The error code +
270
+ // message is the reliable signal. (Node 24.12+/25.2+/26 implement these methods, so the
271
+ // stub never throws there and this never fires.)
272
+ function isAsyncLoaderSyncStub(err) {
273
+ if (!err || typeof err.message !== "string") return false;
274
+ // Two shapes across the affected Node band: (a) the method exists but is a stub that
275
+ // throws ERR_METHOD_NOT_IMPLEMENTED('resolveSync()'/'loadSync()') (e.g. 24.3); (b) the
276
+ // method is ENTIRELY ABSENT, so Node's `this[#customizations].resolveSync/loadSync(...)`
277
+ // throws a TypeError "... is not a function" (e.g. 22.16/24.11). Match both.
278
+ if (err.code === "ERR_METHOD_NOT_IMPLEMENTED" &&
279
+ (err.message.includes("resolveSync") || err.message.includes("loadSync"))) {
280
+ return true;
281
+ }
282
+ return err instanceof TypeError &&
283
+ (err.message.includes("resolveSync is not a function") ||
284
+ err.message.includes("loadSync is not a function"));
285
+ }
286
+
287
+ // Resolve a specifier to a URL the registerHooks resolve chain can return, as the
288
+ // recovery path when Node's default resolve step throws the async-loader stub (see
289
+ // isAsyncLoaderSyncStub). Returns `{ url, shortCircuit }`, or null if it cannot resolve
290
+ // (caller re-throws the original error so behavior is unchanged).
291
+ //
292
+ // Uses the parent's CommonJS resolver (`createRequire().resolve`) — the only fully-sync,
293
+ // conditions-capable resolver available in this `--require` CJS preload. It honors
294
+ // `node_modules`, package `exports`, relative + absolute paths, and bare/scoped
295
+ // specifiers, but under the REQUIRE condition; a DUAL package whose `exports` differ by
296
+ // `import`/`require` gets its `require` build where Node's default ESM resolve would
297
+ // return the `import` build (latent — the in-the-wild trigger resolves non-dual internal
298
+ // modules). Builtins MUST be mapped back to `node:`: `require.resolve("fs")` returns the
299
+ // bare name `"fs"`, which must not become a bogus `file://<cwd>/fs` URL.
300
+ function resolveViaParentRequire(specifier, parentURL) {
301
+ try {
302
+ // An ALREADY-RESOLVED specifier needs no resolution — return it verbatim. This is the
303
+ // common Turbopack/Tailwind trigger: Node resolves the loader module's OWN absolute
304
+ // `file://` URL (`@tailwindcss/node/dist/esm-cache.loader.mjs`) synchronously during
305
+ // `module.register`, with `parentURL` = `data:` (no useful base). `require.resolve`
306
+ // cannot take a `file://` URL string, so pass these through directly. Builtins and
307
+ // `data:` specifiers are likewise already-resolved.
308
+ if (specifier.startsWith("file:") || specifier.startsWith("data:")) {
309
+ return { url: specifier, shortCircuit: true };
310
+ }
311
+ if (specifier.startsWith("node:") || module_.isBuiltin(specifier)) {
312
+ return { url: specifier.startsWith("node:") ? specifier : `node:${specifier}`, shortCircuit: true };
313
+ }
314
+ const base = parentURL && String(parentURL).startsWith("file:")
315
+ ? String(parentURL)
316
+ : pathToFileURL(join(process.cwd(), "noop.js")).href;
317
+ const resolved = module_.createRequire(base).resolve(specifier);
318
+ if (module_.isBuiltin(resolved)) {
319
+ return { url: resolved.startsWith("node:") ? resolved : `node:${resolved}`, shortCircuit: true };
320
+ }
321
+ const url = resolved.startsWith("node:") || resolved.startsWith("data:")
322
+ ? resolved
323
+ : pathToFileURL(resolved).href;
324
+ return { url, shortCircuit: true };
325
+ } catch {
326
+ return null;
327
+ }
328
+ }
329
+
260
330
  function makeHooks(core, watchReporting) {
261
331
  installUserHookDetector();
262
332
  installUserAsyncLoaderDetector();
@@ -278,7 +348,41 @@ function makeHooks(core, watchReporting) {
278
348
  if (res) return res;
279
349
  } catch { /* fall through to Node's resolver */ }
280
350
  }
281
- return nextResolve(specifier, context);
351
+ try {
352
+ return nextResolve(specifier, context);
353
+ } catch (err) {
354
+ if (isAsyncLoaderSyncStub(err)) {
355
+ const fallback = resolveViaParentRequire(specifier, context.parentURL);
356
+ if (fallback) return fallback;
357
+ }
358
+ throw err;
359
+ }
360
+ }
361
+
362
+ // Recovery for the async-loader `loadSync` stub: load a `file:` module ourselves when
363
+ // Node's default load step throws ERR_METHOD_NOT_IMPLEMENTED (see isAsyncLoaderSyncStub).
364
+ // Reads source from disk and derives the format from extension + nearest package `type`
365
+ // (nub's own moduleFormatFor — the same source-of-truth as the transpile path). For a
366
+ // transpilable TS/JSX file outside node_modules, route through nub's transpiler; for a
367
+ // data-extension, through loadData; otherwise hand back raw source with the derived
368
+ // format. Returns null if it cannot (caller re-throws). A CJS result keeps source:null
369
+ // and hands off to the native CommonJS loader, matching the default-load contract.
370
+ function loadViaDisk(url, ext) {
371
+ try {
372
+ const path = fileURLToPath(url);
373
+ if (core.TRANSPILE_EXTS.has(ext) && !core.isNodeModules(url)) {
374
+ return core.loadTranspile(url, ext);
375
+ }
376
+ if (ext in core.DATA_EXTS) return core.loadData(url, ext);
377
+ const { readFileSync } = require("node:fs");
378
+ const source = readFileSync(path);
379
+ const pkgType = core.getPackageType(dirname(path));
380
+ const format = core.moduleFormatFor(ext, pkgType, path, source.toString("utf8"));
381
+ if (format === "commonjs") return { format: "commonjs", source: null, shortCircuit: true };
382
+ return { format, source, shortCircuit: true };
383
+ } catch {
384
+ return null;
385
+ }
282
386
  }
283
387
 
284
388
  function load(url, context, nextLoad) {
@@ -354,7 +458,31 @@ function makeHooks(core, watchReporting) {
354
458
  return { format: undefined, source: "", shortCircuit: true };
355
459
  }
356
460
 
357
- const r = nextLoad(url, context);
461
+ let r;
462
+ try {
463
+ r = nextLoad(url, context);
464
+ } catch (err) {
465
+ // Async-loader `loadSync` stub (the load-hook twin of the resolve recovery): with a
466
+ // USER async `module.register` loader present, nub's sync load hook forces the default
467
+ // step onto the synchronous chain, which calls the async-hooks `loadSync` stub →
468
+ // ERR_METHOD_NOT_IMPLEMENTED. Recover by loading the module ourselves: read source
469
+ // from disk and derive the format from the URL/extension (the same source-of-truth
470
+ // nub's own transpile path uses), so the synchronous module-job gets real source
471
+ // instead of crashing. node:/data:/non-file URLs and the no-format case fall through
472
+ // to a re-throw (we can't synthesize those here). Re-throw anything that isn't the stub.
473
+ if (isAsyncLoaderSyncStub(err) && typeof url === "string") {
474
+ // Builtins: hand back the `builtin` format with no source — Node loads them
475
+ // natively (a `node:`-scheme module the default load would have returned builtin for).
476
+ if (url.startsWith("node:") || module_.isBuiltin(url)) {
477
+ return { format: "builtin", source: null, shortCircuit: true };
478
+ }
479
+ if (url.startsWith("file:")) {
480
+ const recovered = loadViaDisk(url, ext);
481
+ if (recovered) return recovered;
482
+ }
483
+ }
484
+ throw err;
485
+ }
358
486
 
359
487
  // #18 — relabel a `commonjs` result as `commonjs-sync` for `file:` URLs ON THE
360
488
  // `import()`-OF-CJS PATH so the module (and its inner require()s) routes through
@@ -9,4 +9,4 @@
9
9
  // previously lived as a literal inside preload.mjs, which `make version` patched,
10
10
  // while the worker carried a hand-maintained "…-compat" copy that `make version`
11
11
  // never touched — a latent staleness bug this module closes.)
12
- export const NUB_VERSION = "0.1.13";
12
+ export const NUB_VERSION = "0.1.14";