@nasti-toolchain/nasti 2.4.3 → 2.5.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.
package/dist/index.js CHANGED
@@ -10,10 +10,10 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
10
10
  if (typeof require !== "undefined") return require.apply(this, arguments);
11
11
  throw Error('Dynamic require of "' + x + '" is not supported');
12
12
  });
13
- var __glob = (map) => (path19) => {
14
- var fn = map[path19];
13
+ var __glob = (map) => (path21) => {
14
+ var fn = map[path21];
15
15
  if (fn) return fn();
16
- throw new Error("Module not found in bundle: " + path19);
16
+ throw new Error("Module not found in bundle: " + path21);
17
17
  };
18
18
  var __esm = (fn, res) => function __init() {
19
19
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
@@ -43,7 +43,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
43
43
  ));
44
44
 
45
45
  // src/config/defaults.ts
46
- var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaultExperimental, defaults;
46
+ var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaultExperimental, defaultReact, defaults;
47
47
  var init_defaults = __esm({
48
48
  "src/config/defaults.ts"() {
49
49
  "use strict";
@@ -96,12 +96,20 @@ var init_defaults = __esm({
96
96
  defaultExperimental = {
97
97
  bundledDev: false
98
98
  };
99
+ defaultReact = {
100
+ include: /\.[tj]sx?$/,
101
+ exclude: /node_modules/,
102
+ jsxImportSource: "react",
103
+ jsxRuntime: "automatic",
104
+ compiler: false
105
+ };
99
106
  defaults = {
100
107
  root: ".",
101
108
  base: "/",
102
109
  mode: "development",
103
110
  target: "web",
104
111
  framework: "auto",
112
+ react: defaultReact,
105
113
  resolve: defaultResolve,
106
114
  server: defaultServer,
107
115
  build: defaultBuild,
@@ -442,6 +450,13 @@ async function resolveConfig(inlineConfig = {}, command) {
442
450
  mode,
443
451
  target: merged.target ?? defaults.target,
444
452
  framework: (merged.framework ?? defaults.framework) === "auto" ? detectFramework(root) : merged.framework,
453
+ react: {
454
+ include: merged.react?.include ?? defaultReact.include,
455
+ exclude: merged.react?.exclude ?? defaultReact.exclude,
456
+ jsxImportSource: merged.react?.jsxImportSource ?? defaultReact.jsxImportSource,
457
+ jsxRuntime: merged.react?.jsxRuntime ?? defaultReact.jsxRuntime,
458
+ compiler: merged.react?.compiler === true ? {} : merged.react?.compiler ?? defaultReact.compiler
459
+ },
445
460
  command,
446
461
  resolve: {
447
462
  // tsconfig paths 优先级最低:tsconfig < defaults < user config
@@ -876,27 +891,27 @@ var require_process = __commonJS({
876
891
  var require_filesystem = __commonJS({
877
892
  "node_modules/detect-libc/lib/filesystem.js"(exports, module) {
878
893
  "use strict";
879
- var fs14 = __require("fs");
894
+ var fs16 = __require("fs");
880
895
  var LDD_PATH = "/usr/bin/ldd";
881
896
  var SELF_PATH = "/proc/self/exe";
882
897
  var MAX_LENGTH = 2048;
883
- var readFileSync = (path19) => {
884
- const fd = fs14.openSync(path19, "r");
898
+ var readFileSync = (path21) => {
899
+ const fd = fs16.openSync(path21, "r");
885
900
  const buffer = Buffer.alloc(MAX_LENGTH);
886
- const bytesRead = fs14.readSync(fd, buffer, 0, MAX_LENGTH, 0);
887
- fs14.close(fd, () => {
901
+ const bytesRead = fs16.readSync(fd, buffer, 0, MAX_LENGTH, 0);
902
+ fs16.close(fd, () => {
888
903
  });
889
904
  return buffer.subarray(0, bytesRead);
890
905
  };
891
- var readFile = (path19) => new Promise((resolve, reject) => {
892
- fs14.open(path19, "r", (err, fd) => {
906
+ var readFile = (path21) => new Promise((resolve, reject) => {
907
+ fs16.open(path21, "r", (err, fd) => {
893
908
  if (err) {
894
909
  reject(err);
895
910
  } else {
896
911
  const buffer = Buffer.alloc(MAX_LENGTH);
897
- fs14.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
912
+ fs16.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
898
913
  resolve(buffer.subarray(0, bytesRead));
899
- fs14.close(fd, () => {
914
+ fs16.close(fd, () => {
900
915
  });
901
916
  });
902
917
  }
@@ -1008,11 +1023,11 @@ var require_detect_libc = __commonJS({
1008
1023
  }
1009
1024
  return null;
1010
1025
  };
1011
- var familyFromInterpreterPath = (path19) => {
1012
- if (path19) {
1013
- if (path19.includes("/ld-musl-")) {
1026
+ var familyFromInterpreterPath = (path21) => {
1027
+ if (path21) {
1028
+ if (path21.includes("/ld-musl-")) {
1014
1029
  return MUSL;
1015
- } else if (path19.includes("/ld-linux-")) {
1030
+ } else if (path21.includes("/ld-linux-")) {
1016
1031
  return GLIBC;
1017
1032
  }
1018
1033
  }
@@ -1059,8 +1074,8 @@ var require_detect_libc = __commonJS({
1059
1074
  cachedFamilyInterpreter = null;
1060
1075
  try {
1061
1076
  const selfContent = await readFile(SELF_PATH);
1062
- const path19 = interpreterPath(selfContent);
1063
- cachedFamilyInterpreter = familyFromInterpreterPath(path19);
1077
+ const path21 = interpreterPath(selfContent);
1078
+ cachedFamilyInterpreter = familyFromInterpreterPath(path21);
1064
1079
  } catch (e) {
1065
1080
  }
1066
1081
  return cachedFamilyInterpreter;
@@ -1072,8 +1087,8 @@ var require_detect_libc = __commonJS({
1072
1087
  cachedFamilyInterpreter = null;
1073
1088
  try {
1074
1089
  const selfContent = readFileSync(SELF_PATH);
1075
- const path19 = interpreterPath(selfContent);
1076
- cachedFamilyInterpreter = familyFromInterpreterPath(path19);
1090
+ const path21 = interpreterPath(selfContent);
1091
+ cachedFamilyInterpreter = familyFromInterpreterPath(path21);
1077
1092
  } catch (e) {
1078
1093
  }
1079
1094
  return cachedFamilyInterpreter;
@@ -2174,13 +2189,88 @@ ${msg}`);
2174
2189
  map: result.map ? JSON.stringify(result.map) : null
2175
2190
  };
2176
2191
  }
2177
- var JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS;
2192
+ async function transformReactCode(filename, code, options) {
2193
+ if (!matchesReactFilter(filename, options.react.include, options.react.exclude)) {
2194
+ return null;
2195
+ }
2196
+ if (!options.react.compiler) {
2197
+ if (!shouldTransform(filename)) return null;
2198
+ return transformCode(filename, code, {
2199
+ sourcemap: options.sourcemap,
2200
+ jsxRuntime: options.react.jsxRuntime,
2201
+ jsxImportSource: options.react.jsxImportSource,
2202
+ reactRefresh: options.reactRefresh,
2203
+ target: options.target
2204
+ });
2205
+ }
2206
+ if (!shouldTransform(filename)) return null;
2207
+ const compiler2 = await loadReactCompiler();
2208
+ const compilerOptions = options.react.compiler;
2209
+ const shouldCompile = options.consumer === "client" && (compilerOptions.compilationMode === "annotation" ? /['"]use memo['"]/.test(code) : defaultReactCompilerCodeFilter.test(code));
2210
+ const result = await compiler2.transform(cleanTransformId(filename), code, {
2211
+ jsx: {
2212
+ runtime: options.react.jsxRuntime,
2213
+ development: options.development,
2214
+ importSource: options.react.jsxImportSource,
2215
+ refresh: options.consumer === "client" && !!options.reactRefresh
2216
+ },
2217
+ reactCompiler: shouldCompile ? compilerOptions : false,
2218
+ sourcemap: options.sourcemap ?? true
2219
+ });
2220
+ const diagnostics = result.errors.map(
2221
+ (error) => `${error.message}${error.codeframe ? `
2222
+ ${error.codeframe}` : ""}`
2223
+ );
2224
+ if (result.fatal) {
2225
+ throw new Error(
2226
+ diagnostics.join("\n\n") || `React Compiler transform failed for ${filename}`
2227
+ );
2228
+ }
2229
+ for (const diagnostic of diagnostics) options.onWarning?.(diagnostic);
2230
+ return {
2231
+ code: result.code,
2232
+ map: result.map ? JSON.stringify(result.map) : null
2233
+ };
2234
+ }
2235
+ function matchesReactFilter(id, include, exclude) {
2236
+ const cleanId = cleanTransformId(id);
2237
+ return matchesFilter(cleanId, include) && !matchesFilter(cleanId, exclude);
2238
+ }
2239
+ function matchesFilter(id, filter2) {
2240
+ const patterns = Array.isArray(filter2) ? filter2 : [filter2];
2241
+ return patterns.some((pattern) => {
2242
+ if (pattern instanceof RegExp) {
2243
+ pattern.lastIndex = 0;
2244
+ return pattern.test(id);
2245
+ }
2246
+ if (!pattern.includes("*")) return id.includes(pattern);
2247
+ const expression = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "\0").replace(/\*/g, "[^/]*").replace(/\0/g, ".*");
2248
+ return new RegExp(`^${expression}$`).test(id);
2249
+ });
2250
+ }
2251
+ function cleanTransformId(id) {
2252
+ return id.split(/[?#]/, 1)[0];
2253
+ }
2254
+ async function loadReactCompiler() {
2255
+ if (reactCompilerImplementation) return reactCompilerImplementation;
2256
+ try {
2257
+ reactCompilerImplementation = await import("oxc-transform-react");
2258
+ return reactCompilerImplementation;
2259
+ } catch (error) {
2260
+ throw new Error(
2261
+ '[nasti] React Compiler requires the optional "oxc-transform-react" package. Install it before setting react.compiler.' + (error instanceof Error ? `
2262
+ ${error.message}` : "")
2263
+ );
2264
+ }
2265
+ }
2266
+ var JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS, defaultReactCompilerCodeFilter, reactCompilerImplementation;
2178
2267
  var init_transformer = __esm({
2179
2268
  "src/core/transformer.ts"() {
2180
2269
  "use strict";
2181
2270
  JS_EXTENSIONS = /\.(js|mjs|cjs)$/;
2182
2271
  TS_EXTENSIONS = /\.(ts|mts|cts)$/;
2183
2272
  JSX_EXTENSIONS = /\.(jsx|tsx)$/;
2273
+ defaultReactCompilerCodeFilter = /forwardRef|memo|\b(?:[A-Z]|use[A-Z0-9])/;
2184
2274
  }
2185
2275
  });
2186
2276
 
@@ -2226,8 +2316,8 @@ function vuePlugin(config, environmentName = "client") {
2226
2316
  let cached2 = descriptorCache.get(filePath);
2227
2317
  if (!cached2) {
2228
2318
  try {
2229
- const fs14 = await import("fs");
2230
- const rawSource = fs14.readFileSync(filePath, "utf-8");
2319
+ const fs16 = await import("fs");
2320
+ const rawSource = fs16.readFileSync(filePath, "utf-8");
2231
2321
  const transformedSfc = await applySourceTransform(
2232
2322
  vueOptions.transformSfc,
2233
2323
  rawSource,
@@ -2893,6 +2983,24 @@ var init_module_graph = __esm({
2893
2983
  getModulesByFile(file) {
2894
2984
  return this.fileToModulesMap.get(file);
2895
2985
  }
2986
+ /**
2987
+ * Modules whose registered entry file lives under `dir` (inclusive).
2988
+ * Used when a non-entry source inside a prebundled workspace package changes:
2989
+ * only the package entry was registered, so getModulesByFile(changedFile)
2990
+ * misses — we invalidate every /@modules entry rooted in that package.
2991
+ */
2992
+ getModulesWithFileUnder(dir) {
2993
+ const result = /* @__PURE__ */ new Set();
2994
+ const normDir = dir.replace(/\\/g, "/");
2995
+ const normPrefix = normDir.endsWith("/") ? normDir : normDir + "/";
2996
+ for (const [file, mods] of this.fileToModulesMap) {
2997
+ const normFile = file.replace(/\\/g, "/");
2998
+ if (normFile === normDir || normFile.startsWith(normPrefix)) {
2999
+ for (const m of mods) result.add(m);
3000
+ }
3001
+ }
3002
+ return result;
3003
+ }
2896
3004
  async ensureEntryFromUrl(url) {
2897
3005
  const normalizedUrl = removeTimestampQuery(url);
2898
3006
  let mod = this.urlToModuleMap.get(normalizedUrl);
@@ -3263,6 +3371,44 @@ var init_environment = __esm({
3263
3371
  }
3264
3372
  });
3265
3373
 
3374
+ // src/plugins/react.ts
3375
+ function reactPlugin(config, environment) {
3376
+ return {
3377
+ name: "nasti:oxc-transform",
3378
+ async transform(code, id) {
3379
+ const result = await transformReactCode(id, code, {
3380
+ react: config.react,
3381
+ consumer: environment.consumer,
3382
+ development: config.mode === "development",
3383
+ sourcemap: !!environment.options.build.sourcemap,
3384
+ target: environment.options.build.target,
3385
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
3386
+ });
3387
+ if (!result) return null;
3388
+ return {
3389
+ code: result.code,
3390
+ map: result.map ? JSON.parse(result.map) : void 0
3391
+ };
3392
+ },
3393
+ handleHotUpdate(ctx) {
3394
+ for (const mod of ctx.modules) {
3395
+ if (REACT_FILE_RE.test(mod.url) && matchesReactFilter(mod.url, config.react.include, config.react.exclude)) {
3396
+ mod.isSelfAccepting = true;
3397
+ }
3398
+ }
3399
+ return ctx.modules;
3400
+ }
3401
+ };
3402
+ }
3403
+ var REACT_FILE_RE;
3404
+ var init_react = __esm({
3405
+ "src/plugins/react.ts"() {
3406
+ "use strict";
3407
+ init_transformer();
3408
+ REACT_FILE_RE = /\.[jt]sx(?:[?#].*)?$/;
3409
+ }
3410
+ });
3411
+
3266
3412
  // src/core/env.ts
3267
3413
  import path7 from "path";
3268
3414
  import fs5 from "fs";
@@ -3623,7 +3769,7 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
3623
3769
  // 相对/绝对/虚拟模块照常打包。需要内联依赖时经 rolldownOptions.external 覆盖。
3624
3770
  external: restInputOptions.external ?? ((id) => {
3625
3771
  if (NODE_BUILTINS.has(id)) return true;
3626
- return !id.startsWith(".") && !path10.isAbsolute(id) && !id.startsWith("\0");
3772
+ return !id.startsWith(".") && !path10.isAbsolute(id) && !id.startsWith("\0") && !id.startsWith("virtual:");
3627
3773
  })
3628
3774
  } : {}
3629
3775
  };
@@ -3846,6 +3992,7 @@ function resolveClientEntries(config, html) {
3846
3992
  return entryPoints;
3847
3993
  }
3848
3994
  function createOxcTransformPlugin(config, environment) {
3995
+ if (config.framework === "react") return reactPlugin(config, environment);
3849
3996
  return {
3850
3997
  name: "nasti:oxc-transform",
3851
3998
  transform(code, id) {
@@ -3866,7 +4013,7 @@ async function build(inlineConfig = {}) {
3866
4013
  const startTime = performance.now();
3867
4014
  logger.info(
3868
4015
  pc4.cyan(`
3869
- nasti v${"2.4.3"} `) + pc4.green(`building for ${config.mode}...`)
4016
+ nasti v${"2.5.0"} `) + pc4.green(`building for ${config.mode}...`)
3870
4017
  );
3871
4018
  debug5?.(`root: ${config.root}`);
3872
4019
  const buildableNames = Object.keys(config.environments).filter((name) => {
@@ -4148,6 +4295,7 @@ var init_build = __esm({
4148
4295
  init_environment();
4149
4296
  init_css_engine();
4150
4297
  init_html();
4298
+ init_react();
4151
4299
  init_transformer();
4152
4300
  init_env();
4153
4301
  init_reporter();
@@ -4203,10 +4351,124 @@ var init_ws = __esm({
4203
4351
  }
4204
4352
  });
4205
4353
 
4206
- // src/server/middleware.ts
4207
- import path12 from "path";
4354
+ // src/server/fs-allow.ts
4208
4355
  import fs9 from "fs";
4209
- import { createRequire as createRequire3 } from "module";
4356
+ import path12 from "path";
4357
+ function isUnderRoot(abs, root) {
4358
+ const rel = path12.relative(root, abs);
4359
+ return !!rel && !rel.startsWith("..") && !path12.isAbsolute(rel);
4360
+ }
4361
+ function discoverLinkedPackageRoots(projectRoot, maxDepth = 4) {
4362
+ const results = [];
4363
+ const seenReal = /* @__PURE__ */ new Set();
4364
+ const queued = /* @__PURE__ */ new Set([projectRoot]);
4365
+ const queue = [projectRoot];
4366
+ for (let depth = 0; depth < maxDepth && queue.length > 0; depth++) {
4367
+ const levelCount = queue.length;
4368
+ for (let i = 0; i < levelCount; i++) {
4369
+ const dir = queue.shift();
4370
+ const nm = path12.join(dir, "node_modules");
4371
+ let entries;
4372
+ try {
4373
+ entries = fs9.readdirSync(nm, { withFileTypes: true });
4374
+ } catch {
4375
+ continue;
4376
+ }
4377
+ for (const ent of entries) {
4378
+ if (ent.name.startsWith(".") || ent.name === "node_modules") continue;
4379
+ const pkgNames = ent.name.startsWith("@") ? listScopedPackages(nm, ent.name) : [ent.name];
4380
+ for (const pkgName of pkgNames) {
4381
+ const pkgPath = path12.join(nm, pkgName);
4382
+ let real;
4383
+ try {
4384
+ real = fs9.realpathSync(pkgPath);
4385
+ } catch {
4386
+ continue;
4387
+ }
4388
+ if (seenReal.has(real)) continue;
4389
+ seenReal.add(real);
4390
+ if (!queued.has(real)) {
4391
+ queued.add(real);
4392
+ queue.push(real);
4393
+ }
4394
+ if (real !== projectRoot && !isUnderRoot(real, projectRoot) && !real.includes(NM)) {
4395
+ results.push(real);
4396
+ }
4397
+ }
4398
+ }
4399
+ }
4400
+ }
4401
+ return results;
4402
+ }
4403
+ function listScopedPackages(nm, scope) {
4404
+ try {
4405
+ return fs9.readdirSync(path12.join(nm, scope)).filter((name) => !name.startsWith(".")).map((name) => path12.join(scope, name));
4406
+ } catch {
4407
+ return [];
4408
+ }
4409
+ }
4410
+ function getLinkedPackageRoots(projectRoot) {
4411
+ let mtimeMs = 0;
4412
+ try {
4413
+ mtimeMs = fs9.statSync(path12.join(projectRoot, "node_modules")).mtimeMs;
4414
+ } catch {
4415
+ mtimeMs = 0;
4416
+ }
4417
+ const cached2 = linkedRootsCache.get(projectRoot);
4418
+ if (cached2 && cached2.mtimeMs === mtimeMs) {
4419
+ return cached2.roots;
4420
+ }
4421
+ const roots = discoverLinkedPackageRoots(projectRoot);
4422
+ linkedRootsCache.set(projectRoot, { roots, mtimeMs });
4423
+ return roots;
4424
+ }
4425
+ function clearLinkedPackageRootsCache() {
4426
+ linkedRootsCache.clear();
4427
+ }
4428
+ function isAllowedDevModulePath(realId, projectRoot) {
4429
+ if (realId === projectRoot || isUnderRoot(realId, projectRoot)) return true;
4430
+ for (const pkgRoot of getLinkedPackageRoots(projectRoot)) {
4431
+ if (realId === pkgRoot || realId.startsWith(pkgRoot + path12.sep)) return true;
4432
+ }
4433
+ let dir = projectRoot;
4434
+ for (; ; ) {
4435
+ const nm = path12.join(dir, "node_modules");
4436
+ if (realId === nm || realId.startsWith(nm + path12.sep)) return true;
4437
+ const parent = path12.dirname(dir);
4438
+ if (parent === dir) break;
4439
+ dir = parent;
4440
+ }
4441
+ return false;
4442
+ }
4443
+ function findNearestPackageRoot(file) {
4444
+ let dir = path12.dirname(file);
4445
+ for (; ; ) {
4446
+ const pkgJson = path12.join(dir, "package.json");
4447
+ if (fs9.existsSync(pkgJson)) {
4448
+ try {
4449
+ const pkg = JSON.parse(fs9.readFileSync(pkgJson, "utf-8"));
4450
+ if (typeof pkg?.name === "string" && pkg.name) return dir;
4451
+ } catch {
4452
+ }
4453
+ }
4454
+ const parent = path12.dirname(dir);
4455
+ if (parent === dir) return null;
4456
+ dir = parent;
4457
+ }
4458
+ }
4459
+ var NM, linkedRootsCache;
4460
+ var init_fs_allow = __esm({
4461
+ "src/server/fs-allow.ts"() {
4462
+ "use strict";
4463
+ NM = `${path12.sep}node_modules${path12.sep}`;
4464
+ linkedRootsCache = /* @__PURE__ */ new Map();
4465
+ }
4466
+ });
4467
+
4468
+ // src/server/middleware.ts
4469
+ import path13 from "path";
4470
+ import fs10 from "fs";
4471
+ import { createRequire as createRequire4 } from "module";
4210
4472
  import { fileURLToPath, pathToFileURL as pathToFileURL3 } from "url";
4211
4473
  import pc6 from "picocolors";
4212
4474
  function getReactRefreshRuntimeEsm(includeBoundaryHelpers = false) {
@@ -4216,10 +4478,10 @@ function getReactRefreshRuntimeEsm(includeBoundaryHelpers = false) {
4216
4478
  let cjsPath;
4217
4479
  try {
4218
4480
  const pkgPath = __require2.resolve("react-refresh/package.json");
4219
- cjsPath = path12.join(path12.dirname(pkgPath), "cjs", "react-refresh-runtime.development.js");
4481
+ cjsPath = path13.join(path13.dirname(pkgPath), "cjs", "react-refresh-runtime.development.js");
4220
4482
  } catch (err) {
4221
- cjsPath = path12.resolve(__dirname_esm, "../../node_modules/react-refresh/cjs/react-refresh-runtime.development.js");
4222
- if (!fs9.existsSync(cjsPath)) {
4483
+ cjsPath = path13.resolve(__dirname_esm, "../../node_modules/react-refresh/cjs/react-refresh-runtime.development.js");
4484
+ if (!fs10.existsSync(cjsPath)) {
4223
4485
  const origMsg = err instanceof Error ? err.message : String(err);
4224
4486
  throw new Error(
4225
4487
  `[nasti] Missing dependency "react-refresh". Install it with: npm install react-refresh
@@ -4227,7 +4489,7 @@ Original resolve error: ${origMsg}`
4227
4489
  );
4228
4490
  }
4229
4491
  }
4230
- const cjsSource = fs9.readFileSync(cjsPath, "utf-8");
4492
+ const cjsSource = fs10.readFileSync(cjsPath, "utf-8");
4231
4493
  __refreshRuntimeCache = `// Wrapped react-refresh runtime -> ESM
4232
4494
  const exports = {};
4233
4495
  const module = { exports };
@@ -4398,8 +4660,8 @@ async function transformRequest(url, ctx) {
4398
4660
  let realIdValid = false;
4399
4661
  try {
4400
4662
  if (idParam) {
4401
- realId = fs9.realpathSync(idParam);
4402
- realIdValid = fs9.statSync(realId).isFile() && (realId.includes(`${path12.sep}node_modules${path12.sep}`) || isUnderRoot(realId, config.root));
4663
+ realId = fs10.realpathSync(idParam);
4664
+ realIdValid = fs10.statSync(realId).isFile() && isAllowedDevModulePath(realId, config.root);
4403
4665
  }
4404
4666
  } catch {
4405
4667
  realId = null;
@@ -4466,7 +4728,7 @@ async function transformRequest(url, ctx) {
4466
4728
  }
4467
4729
  }
4468
4730
  const filePath = resolveUrlToFile(url, config.root);
4469
- if (!filePath || !fs9.existsSync(filePath)) return null;
4731
+ if (!filePath || !fs10.existsSync(filePath)) return null;
4470
4732
  const mod = await moduleGraph.ensureEntryFromUrl(url);
4471
4733
  moduleGraph.registerModule(mod, filePath);
4472
4734
  const transformVersion = mod.invalidationVersion;
@@ -4477,7 +4739,7 @@ async function transformRequest(url, ctx) {
4477
4739
  return transformResult2;
4478
4740
  }
4479
4741
  const loaded = await pluginContainer.load(filePath);
4480
- let code = loaded == null ? fs9.readFileSync(filePath, "utf-8") : typeof loaded === "string" ? loaded : loaded.code;
4742
+ let code = loaded == null ? fs10.readFileSync(filePath, "utf-8") : typeof loaded === "string" ? loaded : loaded.code;
4481
4743
  let map = loaded && typeof loaded !== "string" ? loaded.map : void 0;
4482
4744
  const pluginResult = await pluginContainer.transform(code, filePath);
4483
4745
  if (pluginResult) {
@@ -4486,22 +4748,35 @@ async function transformRequest(url, ctx) {
4486
4748
  }
4487
4749
  const stableUrl = cleanReqUrl;
4488
4750
  let wrappedWithRefresh = false;
4489
- if (shouldTransform(filePath)) {
4490
- const isJsx = /\.[jt]sx$/.test(filePath);
4491
- const useRefresh = isJsx && config.framework !== "vue";
4751
+ if (config.framework === "react") {
4752
+ const refreshEnabled = (ctx.environment?.consumer ?? "client") === "client" && config.server.hmr !== false;
4753
+ const useRefresh = refreshEnabled && (!!config.react.compiler || /\.[jt]sx$/.test(filePath));
4754
+ const result = await transformReactCode(filePath, code, {
4755
+ react: config.react,
4756
+ consumer: ctx.environment?.consumer ?? "client",
4757
+ development: true,
4758
+ reactRefresh: useRefresh,
4759
+ sourcemap: true,
4760
+ target: ctx.environment?.options.build.target ?? config.build.target,
4761
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
4762
+ });
4763
+ if (result) {
4764
+ code = result.code;
4765
+ if (result.map) map = JSON.parse(result.map);
4766
+ if (useRefresh) {
4767
+ code = buildReactRefreshWrapper(stableUrl, code);
4768
+ wrappedWithRefresh = true;
4769
+ }
4770
+ }
4771
+ } else if (shouldTransform(filePath)) {
4492
4772
  const result = transformCode(filePath, code, {
4493
4773
  sourcemap: true,
4494
4774
  jsxRuntime: "automatic",
4495
- jsxImportSource: config.framework === "vue" ? "vue" : "react",
4496
- reactRefresh: useRefresh,
4775
+ jsxImportSource: "vue",
4497
4776
  target: ctx.environment?.options.build.target ?? config.build.target
4498
4777
  });
4499
4778
  code = result.code;
4500
4779
  if (result.map) map = JSON.parse(result.map);
4501
- if (useRefresh) {
4502
- code = buildReactRefreshWrapper(stableUrl, code);
4503
- wrappedWithRefresh = true;
4504
- }
4505
4780
  }
4506
4781
  const hotInfo = rewriteHotAcceptDeps(code, config, filePath);
4507
4782
  code = hotInfo.code;
@@ -4535,7 +4810,7 @@ async function loadVirtualModule(spec, ctx) {
4535
4810
  const resolved = await pluginContainer.resolveId(spec);
4536
4811
  if (resolved == null) return null;
4537
4812
  const resolvedId = typeof resolved === "string" ? resolved : resolved.id;
4538
- const looksVirtual = resolvedId.startsWith("\0") || !fs9.existsSync(resolvedId);
4813
+ const looksVirtual = resolvedId.startsWith("\0") || !fs10.existsSync(resolvedId);
4539
4814
  if (!looksVirtual) return null;
4540
4815
  const loadResult = await pluginContainer.load(resolvedId);
4541
4816
  if (loadResult == null) return null;
@@ -4549,7 +4824,7 @@ async function loadVirtualModule(spec, ctx) {
4549
4824
  config.mode,
4550
4825
  ssrDefineOverrides(ctx.environment?.consumer ?? "client")
4551
4826
  ));
4552
- const anchor = path12.join(config.root, "__nasti_virtual__.ts");
4827
+ const anchor = path13.join(config.root, "__nasti_virtual__.ts");
4553
4828
  code = rewriteImports(code, config, anchor);
4554
4829
  return { id: resolvedId, result: { code } };
4555
4830
  }
@@ -4575,7 +4850,7 @@ async function doBundlePackage(entryFile, root) {
4575
4850
  await bundle2.close();
4576
4851
  let code = result.output[0].code;
4577
4852
  code = code.replace(/process\.env\.NODE_ENV/g, '"development"');
4578
- const externalBaseDir = path12.dirname(entryFile);
4853
+ const externalBaseDir = path13.dirname(entryFile);
4579
4854
  code = code.replace(
4580
4855
  /^(import\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
4581
4856
  (_, prefix, q, spec) => `${prefix}${q}${externalSpecToModuleUrl(spec, externalBaseDir, root)}${q}`
@@ -4593,16 +4868,16 @@ async function doBundlePackage(entryFile, root) {
4593
4868
  return code;
4594
4869
  }
4595
4870
  async function tryGenerateSubpathShim(entryFile, root) {
4596
- const NM = `${path12.sep}node_modules${path12.sep}`;
4597
- if (!entryFile.includes(NM)) return null;
4871
+ const NM2 = `${path13.sep}node_modules${path13.sep}`;
4872
+ if (!entryFile.includes(NM2)) return null;
4598
4873
  let pkgDir = null;
4599
4874
  let pkgName = null;
4600
- let dir = path12.dirname(entryFile);
4875
+ let dir = path13.dirname(entryFile);
4601
4876
  while (true) {
4602
- const pkgJsonPath = path12.join(dir, "package.json");
4603
- if (fs9.existsSync(pkgJsonPath)) {
4877
+ const pkgJsonPath = path13.join(dir, "package.json");
4878
+ if (fs10.existsSync(pkgJsonPath)) {
4604
4879
  try {
4605
- const pkg = JSON.parse(fs9.readFileSync(pkgJsonPath, "utf-8"));
4880
+ const pkg = JSON.parse(fs10.readFileSync(pkgJsonPath, "utf-8"));
4606
4881
  if (typeof pkg?.name === "string" && pkg.name) {
4607
4882
  pkgDir = dir;
4608
4883
  pkgName = pkg.name;
@@ -4611,16 +4886,16 @@ async function tryGenerateSubpathShim(entryFile, root) {
4611
4886
  } catch {
4612
4887
  }
4613
4888
  }
4614
- const parent = path12.dirname(dir);
4889
+ const parent = path13.dirname(dir);
4615
4890
  if (parent === dir) return null;
4616
4891
  dir = parent;
4617
- if (!dir.includes(NM)) return null;
4892
+ if (!dir.includes(NM2)) return null;
4618
4893
  }
4619
4894
  if (!pkgDir || !pkgName) return null;
4620
- const entryExt = path12.extname(entryFile);
4895
+ const entryExt = path13.extname(entryFile);
4621
4896
  const mainEntry = pickMainEntryByExtension(pkgDir, entryExt);
4622
4897
  if (!mainEntry) return null;
4623
- if (path12.resolve(mainEntry) === path12.resolve(entryFile)) return null;
4898
+ if (path13.resolve(mainEntry) === path13.resolve(entryFile)) return null;
4624
4899
  let mainNs;
4625
4900
  let subNs;
4626
4901
  try {
@@ -4644,7 +4919,7 @@ async function tryGenerateSubpathShim(entryFile, root) {
4644
4919
  if (mainNs["default"] !== subNs["default"]) return null;
4645
4920
  }
4646
4921
  const rootMain = resolveNodeModule(root, pkgName);
4647
- const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir + path12.sep) ? `/@modules/${pkgName}` : `/@modules/${pkgName}?id=${encodeURIComponent(mainEntry)}`;
4922
+ const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir + path13.sep) ? `/@modules/${pkgName}` : `/@modules/${pkgName}?id=${encodeURIComponent(mainEntry)}`;
4648
4923
  const lines = [
4649
4924
  `// Nasti subpath shim \u2192 ${pkgName} (avoid duplicate bundling)`,
4650
4925
  `import * as __pkg from "${mainEntryUrl}";`
@@ -4658,10 +4933,10 @@ async function tryGenerateSubpathShim(entryFile, root) {
4658
4933
  return lines.join("\n") + "\n";
4659
4934
  }
4660
4935
  function pickMainEntryByExtension(pkgDir, preferredExt) {
4661
- const pkgJsonPath = path12.join(pkgDir, "package.json");
4936
+ const pkgJsonPath = path13.join(pkgDir, "package.json");
4662
4937
  let pkg;
4663
4938
  try {
4664
- pkg = JSON.parse(fs9.readFileSync(pkgJsonPath, "utf-8"));
4939
+ pkg = JSON.parse(fs10.readFileSync(pkgJsonPath, "utf-8"));
4665
4940
  } catch {
4666
4941
  return null;
4667
4942
  }
@@ -4680,14 +4955,14 @@ function pickMainEntryByExtension(pkgDir, preferredExt) {
4680
4955
  if (typeof pkg.module === "string") candidates.push(pkg.module);
4681
4956
  if (typeof pkg.main === "string") candidates.push(pkg.main);
4682
4957
  for (const cand of candidates) {
4683
- if (path12.extname(cand) === preferredExt) {
4684
- const full = path12.resolve(pkgDir, cand);
4685
- if (fs9.existsSync(full)) return full;
4958
+ if (path13.extname(cand) === preferredExt) {
4959
+ const full = path13.resolve(pkgDir, cand);
4960
+ if (fs10.existsSync(full)) return full;
4686
4961
  }
4687
4962
  }
4688
4963
  for (const cand of candidates) {
4689
- const full = path12.resolve(pkgDir, cand);
4690
- if (fs9.existsSync(full)) return full;
4964
+ const full = path13.resolve(pkgDir, cand);
4965
+ if (fs10.existsSync(full)) return full;
4691
4966
  }
4692
4967
  return null;
4693
4968
  }
@@ -4712,8 +4987,8 @@ function rewriteExternalRequires(code, baseDir, root) {
4712
4987
  }
4713
4988
  async function injectCjsNamedExports(code, entryFile) {
4714
4989
  try {
4715
- const { createRequire: createRequire7 } = await import("module");
4716
- const req = createRequire7(entryFile);
4990
+ const { createRequire: createRequire8 } = await import("module");
4991
+ const req = createRequire8(entryFile);
4717
4992
  const cjsExports = req(entryFile);
4718
4993
  if (!cjsExports || typeof cjsExports !== "object" && typeof cjsExports !== "function" || Array.isArray(cjsExports)) return code;
4719
4994
  const namedKeys = Object.keys(cjsExports).filter(
@@ -4754,11 +5029,22 @@ function rewriteImports(code, config, filePath, importedUrls, moduleGraph) {
4754
5029
  }
4755
5030
  function createModuleSpecifierResolver(config, filePath) {
4756
5031
  const root = config.root;
4757
- const fileDir = path12.dirname(filePath);
5032
+ const fileDir = path13.dirname(filePath);
4758
5033
  const aliasEntries = Object.entries(config.resolve.alias).sort(
4759
5034
  ([a], [b]) => b.length - a.length
4760
5035
  );
4761
- const toRootUrl = (abs) => "/" + path12.relative(root, abs).replace(/\\/g, "/");
5036
+ const toServableUrl = (abs) => {
5037
+ if (isUnderRoot(abs, root)) {
5038
+ return "/" + path13.relative(root, abs).replace(/\\/g, "/");
5039
+ }
5040
+ for (const pkgRoot of getLinkedPackageRoots(root)) {
5041
+ if (abs === pkgRoot || abs.startsWith(pkgRoot + path13.sep)) {
5042
+ const normalized = abs.replace(/\\/g, "/");
5043
+ return "/@fs/" + (normalized.startsWith("/") ? normalized.slice(1) : normalized);
5044
+ }
5045
+ }
5046
+ return null;
5047
+ };
4762
5048
  return (specifier) => {
4763
5049
  const suffixMatch = specifier.match(/[?#].*$/);
4764
5050
  const suffix = suffixMatch ? suffixMatch[0] : "";
@@ -4767,18 +5053,21 @@ function createModuleSpecifierResolver(config, filePath) {
4767
5053
  if (baseSpec === key || baseSpec.startsWith(key + "/")) {
4768
5054
  const aliasBase = resolveAliasTarget2(value, root);
4769
5055
  const sub = baseSpec.slice(key.length).replace(/^\//, "");
4770
- const target = sub ? path12.join(aliasBase, sub) : aliasBase;
5056
+ const target = sub ? path13.join(aliasBase, sub) : aliasBase;
4771
5057
  const resolved = tryResolveDiskPath(target);
4772
- return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
5058
+ const url = resolved ? toServableUrl(resolved) : null;
5059
+ return url ? url + suffix : specifier;
4773
5060
  }
4774
5061
  }
4775
5062
  if (baseSpec.startsWith("./") || baseSpec.startsWith("../")) {
4776
- const resolved = tryResolveDiskPath(path12.resolve(fileDir, baseSpec));
4777
- return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
5063
+ const resolved = tryResolveDiskPath(path13.resolve(fileDir, baseSpec));
5064
+ const url = resolved ? toServableUrl(resolved) : null;
5065
+ return url ? url + suffix : specifier;
4778
5066
  }
4779
5067
  if (baseSpec.startsWith("/") && !baseSpec.startsWith("/@")) {
4780
- const resolved = tryResolveDiskPath(path12.join(root, baseSpec.replace(/^\//, "")));
4781
- return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
5068
+ const resolved = tryResolveDiskPath(path13.join(root, baseSpec.replace(/^\//, "")));
5069
+ const url = resolved ? toServableUrl(resolved) : null;
5070
+ return url ? url + suffix : specifier;
4782
5071
  }
4783
5072
  if (baseSpec.startsWith("/")) return specifier;
4784
5073
  return `/@modules/${specifier}`;
@@ -4931,28 +5220,24 @@ function maskStringsAndComments(code) {
4931
5220
  return masked.join("");
4932
5221
  }
4933
5222
  function resolveAliasTarget2(value, root) {
4934
- if (path12.isAbsolute(value) && fs9.existsSync(value)) return value;
4935
- if (value.startsWith("/")) return path12.join(root, value.slice(1));
4936
- return path12.resolve(root, value);
5223
+ if (path13.isAbsolute(value) && fs10.existsSync(value)) return value;
5224
+ if (value.startsWith("/")) return path13.join(root, value.slice(1));
5225
+ return path13.resolve(root, value);
4937
5226
  }
4938
5227
  function tryResolveDiskPath(target) {
4939
- if (fs9.existsSync(target) && fs9.statSync(target).isFile()) return target;
5228
+ if (fs10.existsSync(target) && fs10.statSync(target).isFile()) return target;
4940
5229
  for (const ext of RESOLVE_EXTENSIONS) {
4941
5230
  const withExt = target + ext;
4942
- if (fs9.existsSync(withExt) && fs9.statSync(withExt).isFile()) return withExt;
5231
+ if (fs10.existsSync(withExt) && fs10.statSync(withExt).isFile()) return withExt;
4943
5232
  }
4944
- if (fs9.existsSync(target) && fs9.statSync(target).isDirectory()) {
5233
+ if (fs10.existsSync(target) && fs10.statSync(target).isDirectory()) {
4945
5234
  for (const ext of RESOLVE_EXTENSIONS) {
4946
- const idx = path12.join(target, "index" + ext);
4947
- if (fs9.existsSync(idx) && fs9.statSync(idx).isFile()) return idx;
5235
+ const idx = path13.join(target, "index" + ext);
5236
+ if (fs10.existsSync(idx) && fs10.statSync(idx).isFile()) return idx;
4948
5237
  }
4949
5238
  }
4950
5239
  return null;
4951
5240
  }
4952
- function isUnderRoot(abs, root) {
4953
- const rel = path12.relative(root, abs);
4954
- return !!rel && !rel.startsWith("..") && !path12.isAbsolute(rel);
4955
- }
4956
5241
  function appendTimestampQuery(url, timestamp) {
4957
5242
  const hashIndex = url.indexOf("#");
4958
5243
  const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";
@@ -4970,7 +5255,7 @@ function resolveNodeModule(baseDir, moduleName) {
4970
5255
  const resolved = resolveNodeModuleEntry(baseDir, moduleName);
4971
5256
  if (!resolved) return null;
4972
5257
  try {
4973
- return fs9.realpathSync(resolved);
5258
+ return fs10.realpathSync(resolved);
4974
5259
  } catch {
4975
5260
  return resolved;
4976
5261
  }
@@ -4990,21 +5275,21 @@ function resolveNodeModuleEntry(root, moduleName) {
4990
5275
  let pkgDir = null;
4991
5276
  let dir = root;
4992
5277
  for (; ; ) {
4993
- const candidate = path12.join(dir, "node_modules", pkgName);
4994
- if (fs9.existsSync(candidate)) {
5278
+ const candidate = path13.join(dir, "node_modules", pkgName);
5279
+ if (fs10.existsSync(candidate)) {
4995
5280
  pkgDir = candidate;
4996
5281
  break;
4997
5282
  }
4998
- const parent = path12.dirname(dir);
5283
+ const parent = path13.dirname(dir);
4999
5284
  if (parent === dir) break;
5000
5285
  dir = parent;
5001
5286
  }
5002
5287
  if (!pkgDir) return null;
5003
- const pkgJsonPath = path12.join(pkgDir, "package.json");
5004
- if (!fs9.existsSync(pkgJsonPath)) return null;
5288
+ const pkgJsonPath = path13.join(pkgDir, "package.json");
5289
+ if (!fs10.existsSync(pkgJsonPath)) return null;
5005
5290
  let pkg;
5006
5291
  try {
5007
- pkg = JSON.parse(fs9.readFileSync(pkgJsonPath, "utf-8"));
5292
+ pkg = JSON.parse(fs10.readFileSync(pkgJsonPath, "utf-8"));
5008
5293
  } catch {
5009
5294
  return null;
5010
5295
  }
@@ -5017,32 +5302,32 @@ function resolveNodeModuleEntry(root, moduleName) {
5017
5302
  const subDirs = [""];
5018
5303
  for (const field of ["module", "main"]) {
5019
5304
  if (typeof pkg[field] === "string") {
5020
- const dir2 = path12.dirname(pkg[field]);
5305
+ const dir2 = path13.dirname(pkg[field]);
5021
5306
  if (dir2 && dir2 !== "." && !subDirs.includes(dir2)) subDirs.push(dir2);
5022
5307
  }
5023
5308
  }
5024
5309
  for (const dir2 of subDirs) {
5025
- const direct = path12.join(pkgDir, dir2, subpath);
5026
- if (fs9.existsSync(direct) && fs9.statSync(direct).isFile()) return direct;
5310
+ const direct = path13.join(pkgDir, dir2, subpath);
5311
+ if (fs10.existsSync(direct) && fs10.statSync(direct).isFile()) return direct;
5027
5312
  for (const ext of RESOLVE_EXTENSIONS) {
5028
- if (fs9.existsSync(direct + ext)) return direct + ext;
5313
+ if (fs10.existsSync(direct + ext)) return direct + ext;
5029
5314
  }
5030
5315
  }
5031
5316
  return null;
5032
5317
  }
5033
5318
  for (const field of ["module", "jsnext:main", "jsnext", "main"]) {
5034
5319
  if (typeof pkg[field] === "string") {
5035
- const entry = path12.join(pkgDir, pkg[field]);
5036
- if (fs9.existsSync(entry)) return entry;
5320
+ const entry = path13.join(pkgDir, pkg[field]);
5321
+ if (fs10.existsSync(entry)) return entry;
5037
5322
  }
5038
5323
  }
5039
- const indexFallback = path12.join(pkgDir, "index.js");
5040
- if (fs9.existsSync(indexFallback)) return indexFallback;
5324
+ const indexFallback = path13.join(pkgDir, "index.js");
5325
+ if (fs10.existsSync(indexFallback)) return indexFallback;
5041
5326
  return null;
5042
5327
  }
5043
5328
  function resolvePackageExports(exports, key, pkgDir) {
5044
5329
  if (typeof exports === "string") {
5045
- return key === "." ? path12.join(pkgDir, exports) : null;
5330
+ return key === "." ? path13.join(pkgDir, exports) : null;
5046
5331
  }
5047
5332
  const entry = exports[key];
5048
5333
  if (entry === void 0) {
@@ -5054,7 +5339,7 @@ function resolvePackageExports(exports, key, pkgDir) {
5054
5339
  return resolveExportValue(entry, pkgDir);
5055
5340
  }
5056
5341
  function resolveExportValue(value, pkgDir) {
5057
- if (typeof value === "string") return path12.join(pkgDir, value);
5342
+ if (typeof value === "string") return path13.join(pkgDir, value);
5058
5343
  if (Array.isArray(value)) {
5059
5344
  for (const item of value) {
5060
5345
  const r = resolveExportValue(item, pkgDir);
@@ -5073,35 +5358,54 @@ function resolveExportValue(value, pkgDir) {
5073
5358
  return null;
5074
5359
  }
5075
5360
  function resolveUrlToFile(url, root) {
5076
- const cleanUrl = url.split("?")[0];
5361
+ const cleanUrl = url.split(/[?#]/)[0];
5077
5362
  if (cleanUrl.startsWith("/@modules/")) {
5078
5363
  const moduleName = cleanUrl.slice("/@modules/".length);
5079
5364
  return resolveNodeModule(root, moduleName);
5080
5365
  }
5081
- const filePath = path12.resolve(root, cleanUrl.replace(/^\//, ""));
5082
- if (fs9.existsSync(filePath) && fs9.statSync(filePath).isFile()) {
5366
+ if (cleanUrl.startsWith("/@fs/")) {
5367
+ let abs = cleanUrl.slice("/@fs/".length);
5368
+ if (process.platform === "win32") {
5369
+ abs = abs.replace(/\//g, path13.sep);
5370
+ } else if (!abs.startsWith("/")) {
5371
+ abs = "/" + abs;
5372
+ }
5373
+ try {
5374
+ const real = fs10.realpathSync(abs);
5375
+ if (fs10.statSync(real).isFile() && isAllowedDevModulePath(real, root)) return real;
5376
+ } catch {
5377
+ return null;
5378
+ }
5379
+ return null;
5380
+ }
5381
+ const filePath = path13.resolve(root, cleanUrl.replace(/^\//, ""));
5382
+ if (fs10.existsSync(filePath) && fs10.statSync(filePath).isFile()) {
5083
5383
  return filePath;
5084
5384
  }
5085
5385
  for (const ext of RESOLVE_EXTENSIONS) {
5086
5386
  const withExt = filePath + ext;
5087
- if (fs9.existsSync(withExt)) return withExt;
5387
+ if (fs10.existsSync(withExt)) return withExt;
5088
5388
  }
5089
5389
  for (const ext of RESOLVE_EXTENSIONS) {
5090
- const indexFile = path12.join(filePath, "index" + ext);
5091
- if (fs9.existsSync(indexFile)) return indexFile;
5390
+ const indexFile = path13.join(filePath, "index" + ext);
5391
+ if (fs10.existsSync(indexFile)) return indexFile;
5092
5392
  }
5093
5393
  return null;
5094
5394
  }
5095
5395
  function isModuleRequest(url, destination) {
5096
- const cleanUrl = url.split("?")[0];
5396
+ const cleanUrl = url.split(/[?#]/)[0];
5097
5397
  if (/\.(ts|tsx|jsx|js|mjs|vue|css|json)$/.test(cleanUrl)) return true;
5098
5398
  if (cleanUrl.startsWith("/@modules/")) return true;
5399
+ if (cleanUrl.startsWith("/@fs/")) return true;
5099
5400
  if (isAssetFile(cleanUrl)) {
5100
- const query = url.includes("?") ? url.slice(url.indexOf("?") + 1) : "";
5401
+ const qIdx = url.indexOf("?");
5402
+ const hIdx = url.indexOf("#");
5403
+ const queryEnd = hIdx === -1 ? url.length : hIdx;
5404
+ const query = qIdx === -1 || qIdx > queryEnd ? "" : url.slice(qIdx + 1, queryEnd);
5101
5405
  const isExplicitAssetModule = /(?:^|&)(?:url|raw)(?:&|$)/.test(query);
5102
5406
  return isExplicitAssetModule || destination === "script";
5103
5407
  }
5104
- if (!path12.extname(cleanUrl)) return true;
5408
+ if (!path13.extname(cleanUrl)) return true;
5105
5409
  return false;
5106
5410
  }
5107
5411
  function getHmrClientCode() {
@@ -5340,8 +5644,9 @@ var init_middleware = __esm({
5340
5644
  init_env();
5341
5645
  init_url();
5342
5646
  init_assets();
5343
- __dirname_esm = path12.dirname(fileURLToPath(import.meta.url));
5344
- __require2 = createRequire3(import.meta.url);
5647
+ init_fs_allow();
5648
+ __dirname_esm = path13.dirname(fileURLToPath(import.meta.url));
5649
+ __require2 = createRequire4(import.meta.url);
5345
5650
  __refreshRuntimeCache = null;
5346
5651
  REACT_REFRESH_BOUNDARY_HELPERS = `
5347
5652
  function __nastiIsPlainObject(obj) {
@@ -5421,8 +5726,8 @@ window.__vite_plugin_react_preamble_installed__ = true;
5421
5726
  });
5422
5727
 
5423
5728
  // src/server/hmr.ts
5424
- import path13 from "path";
5425
- import fs10 from "fs";
5729
+ import path14 from "path";
5730
+ import fs11 from "fs";
5426
5731
  import pc7 from "picocolors";
5427
5732
  async function handleFileChange(file, server, environmentName = "client", timestamp = Date.now()) {
5428
5733
  const { config } = server;
@@ -5432,9 +5737,26 @@ async function handleFileChange(file, server, environmentName = "client", timest
5432
5737
  }
5433
5738
  const moduleGraph = environment.moduleGraph;
5434
5739
  const logger = config.logger;
5435
- const relativePath = "/" + path13.relative(config.root, file);
5436
- const shortFile = path13.relative(config.root, file);
5437
- const mods = moduleGraph.getModulesByFile(file);
5740
+ const relativePath = "/" + path14.relative(config.root, file);
5741
+ const shortFile = path14.relative(config.root, file);
5742
+ let mods = moduleGraph.getModulesByFile(file);
5743
+ if (!mods || mods.size === 0) {
5744
+ try {
5745
+ const real = fs11.realpathSync(file);
5746
+ if (real !== file) mods = moduleGraph.getModulesByFile(real);
5747
+ if (mods && mods.size > 0) file = real;
5748
+ } catch {
5749
+ }
5750
+ }
5751
+ if (!mods || mods.size === 0) {
5752
+ const packageRoot = findNearestPackageRoot(file);
5753
+ if (packageRoot && getLinkedPackageRoots(config.root).some(
5754
+ (r) => packageRoot === r || packageRoot.startsWith(r + path14.sep)
5755
+ )) {
5756
+ const under = moduleGraph.getModulesWithFileUnder(packageRoot);
5757
+ if (under.size > 0) mods = under;
5758
+ }
5759
+ }
5438
5760
  if (!mods || mods.size === 0) {
5439
5761
  return null;
5440
5762
  }
@@ -5449,7 +5771,7 @@ async function handleFileChange(file, server, environmentName = "client", timest
5449
5771
  file,
5450
5772
  timestamp,
5451
5773
  modules: [mod],
5452
- read: () => fs10.readFileSync(file, "utf-8"),
5774
+ read: () => fs11.readFileSync(file, "utf-8"),
5453
5775
  server,
5454
5776
  environment
5455
5777
  };
@@ -5513,6 +5835,7 @@ async function handleFileChange(file, server, environmentName = "client", timest
5513
5835
  var init_hmr = __esm({
5514
5836
  "src/server/hmr.ts"() {
5515
5837
  "use strict";
5838
+ init_fs_allow();
5516
5839
  }
5517
5840
  });
5518
5841
 
@@ -5522,9 +5845,9 @@ __export(runnable_environment_exports, {
5522
5845
  NastiModuleRunner: () => NastiModuleRunner,
5523
5846
  createModuleRunner: () => createModuleRunner
5524
5847
  });
5525
- import path14 from "path";
5526
- import fs11 from "fs";
5527
- import { builtinModules as builtinModules3, createRequire as createRequire4 } from "module";
5848
+ import path15 from "path";
5849
+ import fs12 from "fs";
5850
+ import { builtinModules as builtinModules3, createRequire as createRequire5 } from "module";
5528
5851
  import { pathToFileURL as pathToFileURL4 } from "url";
5529
5852
  function createModuleRunner(environment) {
5530
5853
  if (environment.consumer !== "server") {
@@ -5557,7 +5880,7 @@ var init_runnable_environment = __esm({
5557
5880
  this.config.mode,
5558
5881
  ssrDefineOverrides(environment.consumer)
5559
5882
  );
5560
- this.require = createRequire4(path14.join(this.config.root, "package.json"));
5883
+ this.require = createRequire5(path15.join(this.config.root, "package.json"));
5561
5884
  const handlers = {
5562
5885
  fetchModule: async (id, importer) => this.fetchModule(id, importer),
5563
5886
  getBuiltins: () => [/^node:/, ...builtinModules3]
@@ -5581,9 +5904,9 @@ var init_runnable_environment = __esm({
5581
5904
  this.cache.clear();
5582
5905
  }
5583
5906
  resolveToId(rawUrl) {
5584
- if (path14.isAbsolute(rawUrl) && fs11.existsSync(rawUrl.split("?")[0])) return rawUrl;
5907
+ if (path15.isAbsolute(rawUrl) && fs12.existsSync(rawUrl.split("?")[0])) return rawUrl;
5585
5908
  const clean = rawUrl.replace(/^\//, "");
5586
- return path14.resolve(this.config.root, clean);
5909
+ return path15.resolve(this.config.root, clean);
5587
5910
  }
5588
5911
  /**
5589
5912
  * fetchModule(invoke 契约方法):环境管线产出 runner 可执行代码。
@@ -5592,14 +5915,14 @@ var init_runnable_environment = __esm({
5592
5915
  */
5593
5916
  async fetchModule(id, importer) {
5594
5917
  if (NODE_BUILTINS3.has(id)) return { externalize: id };
5595
- if (!id.startsWith(".") && !path14.isAbsolute(id) && !id.startsWith("\0")) {
5918
+ if (!id.startsWith(".") && !path15.isAbsolute(id) && !id.startsWith("\0")) {
5596
5919
  return { externalize: id };
5597
5920
  }
5598
5921
  const container = this.environment.pluginContainer;
5599
5922
  let resolvedId = id;
5600
5923
  if (id.startsWith(".") && importer) {
5601
5924
  const resolved = await container.resolveId(id, importer);
5602
- resolvedId = resolved ? typeof resolved === "string" ? resolved : resolved.id : path14.resolve(path14.dirname(importer.split("?")[0]), id);
5925
+ resolvedId = resolved ? typeof resolved === "string" ? resolved : resolved.id : path15.resolve(path15.dirname(importer.split("?")[0]), id);
5603
5926
  }
5604
5927
  resolvedId = this.completeExtension(resolvedId);
5605
5928
  const cleanId = resolvedId.split("?")[0];
@@ -5607,8 +5930,8 @@ var init_runnable_environment = __esm({
5607
5930
  const loaded = await container.load(resolvedId);
5608
5931
  if (loaded != null) {
5609
5932
  code = typeof loaded === "string" ? loaded : loaded.code;
5610
- } else if (fs11.existsSync(cleanId)) {
5611
- code = fs11.readFileSync(cleanId, "utf-8");
5933
+ } else if (fs12.existsSync(cleanId)) {
5934
+ code = fs12.readFileSync(cleanId, "utf-8");
5612
5935
  } else {
5613
5936
  throw new Error(`[nasti:ssr] cannot load module: ${resolvedId}`);
5614
5937
  }
@@ -5616,12 +5939,32 @@ var init_runnable_environment = __esm({
5616
5939
  if (transformed != null) {
5617
5940
  code = typeof transformed === "string" ? transformed : transformed.code;
5618
5941
  }
5619
- if (shouldTransform(cleanId)) {
5942
+ if (this.config.framework === "react") {
5943
+ const result = await transformReactCode(cleanId, code, {
5944
+ react: this.config.react,
5945
+ consumer: this.environment.consumer,
5946
+ development: true,
5947
+ sourcemap: false,
5948
+ target: this.environment.options.build.target,
5949
+ onWarning: (message) => this.config.logger.warn(`[nasti:react] ${message}`)
5950
+ });
5951
+ if (result) {
5952
+ code = result.code;
5953
+ } else if (shouldTransform(cleanId)) {
5954
+ const fallback = transformCode(cleanId, code, {
5955
+ sourcemap: false,
5956
+ jsxRuntime: this.config.react.jsxRuntime,
5957
+ jsxImportSource: this.config.react.jsxImportSource,
5958
+ target: this.environment.options.build.target
5959
+ });
5960
+ code = fallback.code;
5961
+ }
5962
+ } else if (shouldTransform(cleanId)) {
5620
5963
  const result = transformCode(cleanId, code, {
5621
5964
  sourcemap: false,
5622
5965
  target: this.environment.options.build.target,
5623
5966
  jsxRuntime: "automatic",
5624
- jsxImportSource: this.config.framework === "vue" ? "vue" : "react"
5967
+ jsxImportSource: "vue"
5625
5968
  });
5626
5969
  code = result.code;
5627
5970
  }
@@ -5642,19 +5985,19 @@ var init_runnable_environment = __esm({
5642
5985
  completeExtension(id) {
5643
5986
  const clean = id.split("?")[0];
5644
5987
  const query = id.includes("?") ? id.slice(id.indexOf("?")) : "";
5645
- if (fs11.existsSync(clean) && fs11.statSync(clean).isFile()) return id;
5988
+ if (fs12.existsSync(clean) && fs12.statSync(clean).isFile()) return id;
5646
5989
  const jsMatch = clean.match(/^(.*)\.([mc]?)jsx?$/);
5647
5990
  if (jsMatch) {
5648
5991
  for (const tsExt of [`.${jsMatch[2]}ts`, `.${jsMatch[2]}tsx`]) {
5649
- if (fs11.existsSync(jsMatch[1] + tsExt)) return jsMatch[1] + tsExt + query;
5992
+ if (fs12.existsSync(jsMatch[1] + tsExt)) return jsMatch[1] + tsExt + query;
5650
5993
  }
5651
5994
  }
5652
5995
  for (const ext of this.config.resolve.extensions) {
5653
- if (fs11.existsSync(clean + ext)) return clean + ext + query;
5996
+ if (fs12.existsSync(clean + ext)) return clean + ext + query;
5654
5997
  }
5655
5998
  for (const ext of this.config.resolve.extensions) {
5656
- const indexPath = path14.join(clean, `index${ext}`);
5657
- if (fs11.existsSync(indexPath)) return indexPath;
5999
+ const indexPath = path15.join(clean, `index${ext}`);
6000
+ if (fs12.existsSync(indexPath)) return indexPath;
5658
6001
  }
5659
6002
  return id;
5660
6003
  }
@@ -5681,10 +6024,10 @@ var init_runnable_environment = __esm({
5681
6024
  return;
5682
6025
  }
5683
6026
  const ssrImport = async (dep) => {
5684
- if (NODE_BUILTINS3.has(dep) || !dep.startsWith(".") && !path14.isAbsolute(dep) && !dep.startsWith("\0")) {
6027
+ if (NODE_BUILTINS3.has(dep) || !dep.startsWith(".") && !path15.isAbsolute(dep) && !dep.startsWith("\0")) {
5685
6028
  return this.importExternal(dep);
5686
6029
  }
5687
- const depId = dep.startsWith(".") ? this.completeExtension(path14.resolve(path14.dirname(fetched.id.split("?")[0]), dep)) : this.completeExtension(dep);
6030
+ const depId = dep.startsWith(".") ? this.completeExtension(path15.resolve(path15.dirname(fetched.id.split("?")[0]), dep)) : this.completeExtension(dep);
5688
6031
  return this.instantiate(depId);
5689
6032
  };
5690
6033
  const ssrExportAll = (sourceModule) => {
@@ -5716,7 +6059,7 @@ var init_runnable_environment = __esm({
5716
6059
  }
5717
6060
  async importExternal(spec) {
5718
6061
  try {
5719
- return await (spec.startsWith("node:") || !path14.isAbsolute(spec) ? import(this.resolveExternalSpecifier(spec)) : import(pathToFileURL4(spec).href));
6062
+ return await (spec.startsWith("node:") || !path15.isAbsolute(spec) ? import(this.resolveExternalSpecifier(spec)) : import(pathToFileURL4(spec).href));
5720
6063
  } catch (err) {
5721
6064
  throw new Error(`[nasti:ssr] failed to import external "${spec}": ${err.message}`);
5722
6065
  }
@@ -5742,7 +6085,7 @@ var dev_engine_exports = {};
5742
6085
  __export(dev_engine_exports, {
5743
6086
  createBundledDevServer: () => createBundledDevServer
5744
6087
  });
5745
- import path15 from "path";
6088
+ import path16 from "path";
5746
6089
  import crypto3 from "crypto";
5747
6090
  import { WebSocketServer as WsServer2 } from "ws";
5748
6091
  import pc8 from "picocolors";
@@ -5772,11 +6115,11 @@ async function createBundledDevServer(opts) {
5772
6115
  const patches = new MemoryFiles();
5773
6116
  const entryFileNames = /* @__PURE__ */ new Map();
5774
6117
  const bundledClients = /* @__PURE__ */ new Map();
5775
- const useReactRefresh = config.framework !== "vue" && refreshWrapperFn != null;
6118
+ const useReactRefresh = config.framework === "react" && config.server.hmr !== false && refreshWrapperFn != null;
5776
6119
  const rolldownPlugins = [
5777
6120
  ...useReactRefresh ? [
5778
6121
  createReactRefreshRuntimePlugin(entryPoints),
5779
- createBundledOxcRefreshPlugin()
6122
+ createBundledOxcRefreshPlugin(config)
5780
6123
  ] : [],
5781
6124
  ...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins, clientEnv)),
5782
6125
  ...useReactRefresh ? [
@@ -5827,7 +6170,7 @@ async function createBundledDevServer(opts) {
5827
6170
  }
5828
6171
  const url = `/${patchPath}`;
5829
6172
  logger.info(
5830
- pc8.green("hmr update ") + pc8.dim(changedFiles.map((f) => path15.relative(config.root, f)).join(", ")),
6173
+ pc8.green("hmr update ") + pc8.dim(changedFiles.map((f) => path16.relative(config.root, f)).join(", ")),
5831
6174
  { timestamp: true }
5832
6175
  );
5833
6176
  sendTo(clientId, { type: "hmr:update", path: url, url });
@@ -5982,7 +6325,7 @@ async function createBundledDevServer(opts) {
5982
6325
  return;
5983
6326
  }
5984
6327
  res.setHeader("ETag", hit.etag);
5985
- res.setHeader("Content-Type", MIME_TYPES[path15.extname(fileName)] ?? "application/octet-stream");
6328
+ res.setHeader("Content-Type", MIME_TYPES[path16.extname(fileName)] ?? "application/octet-stream");
5986
6329
  res.setHeader("Cache-Control", "no-cache");
5987
6330
  res.once("finish", () => {
5988
6331
  void engine.notifyPayloadDelivered(fileName).catch(
@@ -6023,7 +6366,7 @@ function stripCatchAllLoad(plugins) {
6023
6366
  );
6024
6367
  }
6025
6368
  function createReactRefreshRuntimePlugin(entryPoints) {
6026
- const entryIds = new Set(entryPoints.map((p) => path15.resolve(p)));
6369
+ const entryIds = new Set(entryPoints.map((p) => path16.resolve(p)));
6027
6370
  return {
6028
6371
  name: "nasti:bundled-react-refresh",
6029
6372
  resolveId(source) {
@@ -6041,24 +6384,27 @@ function createReactRefreshRuntimePlugin(entryPoints) {
6041
6384
  return null;
6042
6385
  },
6043
6386
  transform(code, id) {
6044
- if (!entryIds.has(path15.resolve(id.split("?")[0]))) return null;
6387
+ if (!entryIds.has(path16.resolve(id.split("?")[0]))) return null;
6045
6388
  return { code: `import ${JSON.stringify(PREAMBLE_SPEC)};
6046
6389
  ${code}`, map: null };
6047
6390
  }
6048
6391
  };
6049
6392
  }
6050
- function createBundledOxcRefreshPlugin() {
6393
+ function createBundledOxcRefreshPlugin(config) {
6051
6394
  return {
6052
6395
  name: "nasti:bundled-oxc-refresh",
6053
- transform(code, id) {
6396
+ async transform(code, id) {
6054
6397
  const clean = id.split("?")[0];
6055
- if (!/\.[jt]sx$/.test(clean) || clean.includes("/node_modules/")) return null;
6056
- const result = transformCode(clean, code, {
6398
+ const result = await transformReactCode(clean, code, {
6399
+ react: config.react,
6400
+ consumer: "client",
6401
+ development: true,
6402
+ reactRefresh: true,
6057
6403
  sourcemap: true,
6058
- jsxRuntime: "automatic",
6059
- jsxImportSource: "react",
6060
- reactRefresh: true
6404
+ target: config.build.target,
6405
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
6061
6406
  });
6407
+ if (!result) return null;
6062
6408
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
6063
6409
  }
6064
6410
  };
@@ -6212,7 +6558,7 @@ __export(server_exports, {
6212
6558
  createServer: () => createServer
6213
6559
  });
6214
6560
  import http from "http";
6215
- import path16 from "path";
6561
+ import path17 from "path";
6216
6562
  import os from "os";
6217
6563
  import connect from "connect";
6218
6564
  import sirv from "sirv";
@@ -6305,20 +6651,39 @@ async function createServer(inlineConfig = {}) {
6305
6651
  app.use(bundledServer.middleware);
6306
6652
  }
6307
6653
  const ignoredSegments = /* @__PURE__ */ new Set(["node_modules", ".git", ".nasti"]);
6308
- const outDirAbs = path16.resolve(config.root, config.build.outDir);
6309
- const watcher = watch(config.root, {
6654
+ const outDirAbs = path17.resolve(config.root, config.build.outDir);
6655
+ const linkedPackageRoots = getLinkedPackageRoots(config.root).filter(
6656
+ (r) => r !== config.root && !isUnderRoot(config.root, r)
6657
+ );
6658
+ const watchTargets = [config.root, ...linkedPackageRoots];
6659
+ const watcher = watch(watchTargets, {
6310
6660
  ignored: (filePath) => {
6311
- if (filePath === config.root) return false;
6312
- if (filePath === outDirAbs || filePath.startsWith(outDirAbs + path16.sep)) return true;
6313
- const rel = path16.relative(config.root, filePath);
6314
- if (!rel || rel.startsWith("..") || path16.isAbsolute(rel)) return false;
6315
- for (const seg of rel.split(path16.sep)) {
6316
- if (ignoredSegments.has(seg)) return true;
6661
+ if (filePath === outDirAbs || filePath.startsWith(outDirAbs + path17.sep)) return true;
6662
+ for (const watchRoot of watchTargets) {
6663
+ if (filePath === watchRoot) return false;
6664
+ const rel = path17.relative(watchRoot, filePath);
6665
+ if (!rel || rel.startsWith("..") || path17.isAbsolute(rel)) continue;
6666
+ for (const seg of rel.split(path17.sep)) {
6667
+ if (ignoredSegments.has(seg)) return true;
6668
+ }
6669
+ return false;
6317
6670
  }
6318
6671
  return false;
6319
6672
  },
6320
6673
  ignoreInitial: true
6321
6674
  });
6675
+ await new Promise((resolve, reject) => {
6676
+ const onReady = () => {
6677
+ watcher.off("error", onError);
6678
+ resolve();
6679
+ };
6680
+ const onError = (err) => {
6681
+ watcher.off("ready", onReady);
6682
+ reject(err);
6683
+ };
6684
+ watcher.once("ready", onReady);
6685
+ watcher.once("error", onError);
6686
+ });
6322
6687
  let server;
6323
6688
  const environmentServices = {};
6324
6689
  let environmentDriversStarted = false;
@@ -6430,16 +6795,25 @@ async function createServer(inlineConfig = {}) {
6430
6795
  });
6431
6796
  };
6432
6797
  watcher.on("change", (file) => {
6798
+ if (file.includes(`${path17.sep}node_modules${path17.sep}`) || file.endsWith(`${path17.sep}node_modules`)) {
6799
+ clearLinkedPackageRootsCache();
6800
+ }
6433
6801
  ssrRunner?.invalidateFile(file);
6434
6802
  queueClientEnvironmentUpdate(file);
6435
6803
  notifyEnvironmentDrivers(file, "change");
6436
6804
  });
6437
6805
  watcher.on("add", (file) => {
6806
+ if (file.includes(`${path17.sep}node_modules${path17.sep}`) || file.endsWith(`${path17.sep}node_modules`)) {
6807
+ clearLinkedPackageRootsCache();
6808
+ }
6438
6809
  ssrRunner?.invalidateFile(file);
6439
6810
  queueClientEnvironmentUpdate(file);
6440
6811
  notifyEnvironmentDrivers(file, "add");
6441
6812
  });
6442
6813
  watcher.on("unlink", (file) => {
6814
+ if (file.includes(`${path17.sep}node_modules${path17.sep}`) || file.endsWith(`${path17.sep}node_modules`)) {
6815
+ clearLinkedPackageRootsCache();
6816
+ }
6443
6817
  ssrRunner?.invalidateFile(file);
6444
6818
  notifyEnvironmentDrivers(file, "unlink");
6445
6819
  });
@@ -6469,7 +6843,7 @@ async function createServer(inlineConfig = {}) {
6469
6843
  const readyIn = Math.ceil(performance.now() - startTime);
6470
6844
  logger.info(
6471
6845
  `
6472
- ${pc9.cyan(pc9.bold("NASTI"))} ${pc9.cyan(`v${"2.4.3"}`)} ${pc9.dim("ready in")} ${pc9.bold(readyIn)} ${pc9.dim("ms")}
6846
+ ${pc9.cyan(pc9.bold("NASTI"))} ${pc9.cyan(`v${"2.5.0"}`)} ${pc9.dim("ready in")} ${pc9.bold(readyIn)} ${pc9.dim("ms")}
6473
6847
  `
6474
6848
  );
6475
6849
  printServerUrls(
@@ -6566,7 +6940,7 @@ async function createServer(inlineConfig = {}) {
6566
6940
  throw error;
6567
6941
  }
6568
6942
  app.use(transformMiddleware(transformContexts.get("client")));
6569
- const publicDir = path16.resolve(config.root, "public");
6943
+ const publicDir = path17.resolve(config.root, "public");
6570
6944
  app.use(sirv(publicDir, { dev: true, etag: true }));
6571
6945
  app.use(sirv(config.root, { dev: true, etag: true }));
6572
6946
  const postMiddlewares = [];
@@ -6605,6 +6979,7 @@ var init_server = __esm({
6605
6979
  init_builtins();
6606
6980
  init_plugin_api();
6607
6981
  init_env();
6982
+ init_fs_allow();
6608
6983
  }
6609
6984
  });
6610
6985
 
@@ -6617,6 +6992,7 @@ init_config();
6617
6992
  init_resolve();
6618
6993
  import path11 from "path";
6619
6994
  import fs8 from "fs";
6995
+ import { createRequire as createRequire3 } from "module";
6620
6996
  import { rolldown as rolldown2 } from "rolldown";
6621
6997
  import pc5 from "picocolors";
6622
6998
 
@@ -6660,7 +7036,7 @@ async function buildElectron(inlineConfig = {}) {
6660
7036
  const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
6661
7037
  const startTime = performance.now();
6662
7038
  assertElectronVersion(config);
6663
- console.log(pc5.cyan("\n\u26A1 nasti build (electron)") + pc5.dim(` v${"2.4.3"}`));
7039
+ console.log(pc5.cyan("\n\u26A1 nasti build (electron)") + pc5.dim(` v${"2.5.0"}`));
6664
7040
  console.log(pc5.dim(` root: ${config.root}`));
6665
7041
  console.log(pc5.dim(` mode: ${config.mode}`));
6666
7042
  console.log(pc5.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
@@ -6726,14 +7102,21 @@ async function bundleNode(config, entry, opts) {
6726
7102
  };
6727
7103
  const oxcTransformPlugin = {
6728
7104
  name: "nasti:oxc-transform",
6729
- transform(code, id) {
6730
- if (!shouldTransform(id)) return null;
6731
- const result = transformCode(id, code, {
7105
+ async transform(code, id) {
7106
+ const result = config.framework === "react" ? await transformReactCode(id, code, {
7107
+ react: config.react,
7108
+ consumer: "server",
7109
+ development: config.mode === "development",
7110
+ sourcemap: !!config.build.sourcemap,
7111
+ target: config.electron.nodeTarget,
7112
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
7113
+ }) : shouldTransform(id) ? transformCode(id, code, {
6732
7114
  sourcemap: !!config.build.sourcemap,
6733
7115
  jsxRuntime: "automatic",
6734
- jsxImportSource: config.framework === "vue" ? "vue" : "react",
7116
+ jsxImportSource: "vue",
6735
7117
  target: config.electron.nodeTarget
6736
- });
7118
+ }) : null;
7119
+ if (!result) return null;
6737
7120
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
6738
7121
  }
6739
7122
  };
@@ -6804,13 +7187,21 @@ function assertElectronVersion(config) {
6804
7187
  }
6805
7188
  function detectInstalledElectron(root) {
6806
7189
  try {
6807
- const pkgPath = path11.resolve(root, "node_modules/electron/package.json");
6808
- if (!fs8.existsSync(pkgPath)) return null;
7190
+ const require2 = createRequire3(path11.resolve(root, "package.json"));
7191
+ const pkgPath = require2.resolve("electron/package.json");
6809
7192
  const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
6810
7193
  const major = parseInt(String(pkg.version).split(".")[0], 10);
6811
7194
  return Number.isFinite(major) ? major : null;
6812
7195
  } catch {
6813
- return null;
7196
+ try {
7197
+ const pkgPath = path11.resolve(root, "node_modules/electron/package.json");
7198
+ if (!fs8.existsSync(pkgPath)) return null;
7199
+ const pkg = JSON.parse(fs8.readFileSync(pkgPath, "utf-8"));
7200
+ const major = parseInt(String(pkg.version).split(".")[0], 10);
7201
+ return Number.isFinite(major) ? major : null;
7202
+ } catch {
7203
+ return null;
7204
+ }
6814
7205
  }
6815
7206
  }
6816
7207
 
@@ -6819,9 +7210,9 @@ init_server();
6819
7210
 
6820
7211
  // src/server/electron-dev.ts
6821
7212
  init_config();
6822
- import path17 from "path";
6823
- import fs12 from "fs";
6824
- import { createRequire as createRequire5 } from "module";
7213
+ import path18 from "path";
7214
+ import fs13 from "fs";
7215
+ import { createRequire as createRequire6 } from "module";
6825
7216
  import { spawn } from "child_process";
6826
7217
  import chokidar from "chokidar";
6827
7218
  import pc10 from "picocolors";
@@ -6833,7 +7224,7 @@ async function startElectronDev(inlineConfig = {}) {
6833
7224
  const { noSpawn, ...rest } = inlineConfig;
6834
7225
  const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
6835
7226
  warnElectronVersion(config);
6836
- console.log(pc10.cyan("\n\u26A1 nasti electron dev") + pc10.dim(` v${"2.4.3"}`));
7227
+ console.log(pc10.cyan("\n\u26A1 nasti electron dev") + pc10.dim(` v${"2.5.0"}`));
6837
7228
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
6838
7229
  const server = await createServer2({
6839
7230
  ...rest,
@@ -6843,11 +7234,11 @@ async function startElectronDev(inlineConfig = {}) {
6843
7234
  await server.listen();
6844
7235
  const devUrl = `http://localhost:${server.config.server.port}` + electronRendererDevPath(config.electron.renderer);
6845
7236
  console.log(pc10.dim(` renderer: ${devUrl}`));
6846
- const stageDir = path17.resolve(config.root, ".nasti");
6847
- fs12.mkdirSync(stageDir, { recursive: true });
6848
- const mainEntry = path17.resolve(config.root, config.electron.main);
7237
+ const stageDir = path18.resolve(config.root, ".nasti");
7238
+ fs13.mkdirSync(stageDir, { recursive: true });
7239
+ const mainEntry = path18.resolve(config.root, config.electron.main);
6849
7240
  const preloadEntries = normalizePreload(config.electron.preload, config.root);
6850
- const builtMainFile = path17.join(stageDir, "main" + extFor(config.electron.mainFormat));
7241
+ const builtMainFile = path18.join(stageDir, "main" + extFor(config.electron.mainFormat));
6851
7242
  const builtPreloadFiles = [];
6852
7243
  const compileAll = async () => {
6853
7244
  await compileNode(config, mainEntry, {
@@ -6857,9 +7248,9 @@ async function startElectronDev(inlineConfig = {}) {
6857
7248
  });
6858
7249
  builtPreloadFiles.length = 0;
6859
7250
  for (const entry of preloadEntries) {
6860
- if (!fs12.existsSync(entry)) continue;
6861
- const base = path17.basename(entry).replace(/\.[^.]+$/, "");
6862
- const out = path17.join(stageDir, base + extFor(config.electron.preloadFormat));
7251
+ if (!fs13.existsSync(entry)) continue;
7252
+ const base = path18.basename(entry).replace(/\.[^.]+$/, "");
7253
+ const out = path18.join(stageDir, base + extFor(config.electron.preloadFormat));
6863
7254
  await compileNode(config, entry, {
6864
7255
  outFile: out,
6865
7256
  format: config.electron.preloadFormat,
@@ -6898,7 +7289,7 @@ async function startElectronDev(inlineConfig = {}) {
6898
7289
  };
6899
7290
  spawnElectron();
6900
7291
  if (config.electron.autoRestart) {
6901
- const watchTargets = [mainEntry, ...preloadEntries].filter(fs12.existsSync);
7292
+ const watchTargets = [mainEntry, ...preloadEntries].filter(fs13.existsSync);
6902
7293
  const watcher = chokidar.watch(watchTargets, { ignoreInitial: true });
6903
7294
  let restarting = null;
6904
7295
  let pending = false;
@@ -6958,14 +7349,21 @@ async function compileNode(config, entry, opts) {
6958
7349
  };
6959
7350
  const oxcTransformPlugin = {
6960
7351
  name: "nasti:oxc-transform",
6961
- transform(code, id) {
6962
- if (!shouldTransform(id)) return null;
6963
- const result = transformCode(id, code, {
7352
+ async transform(code, id) {
7353
+ const result = config.framework === "react" ? await transformReactCode(id, code, {
7354
+ react: config.react,
7355
+ consumer: "server",
7356
+ development: true,
7357
+ sourcemap: true,
7358
+ target: config.electron.nodeTarget,
7359
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
7360
+ }) : shouldTransform(id) ? transformCode(id, code, {
6964
7361
  sourcemap: true,
6965
7362
  jsxRuntime: "automatic",
6966
- jsxImportSource: config.framework === "vue" ? "vue" : "react",
7363
+ jsxImportSource: "vue",
6967
7364
  target: config.electron.nodeTarget
6968
- });
7365
+ }) : null;
7366
+ if (!result) return null;
6969
7367
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
6970
7368
  }
6971
7369
  };
@@ -6978,7 +7376,7 @@ async function compileNode(config, entry, opts) {
6978
7376
  platform: "node",
6979
7377
  plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
6980
7378
  });
6981
- fs12.mkdirSync(path17.dirname(opts.outFile), { recursive: true });
7379
+ fs13.mkdirSync(path18.dirname(opts.outFile), { recursive: true });
6982
7380
  await bundle2.write({
6983
7381
  file: opts.outFile,
6984
7382
  format: opts.format === "cjs" ? "cjs" : "esm",
@@ -6991,18 +7389,18 @@ async function compileNode(config, entry, opts) {
6991
7389
  await bundle2.close();
6992
7390
  }
6993
7391
  function electronRendererDevPath(renderer) {
6994
- const normalized = renderer.split(path17.sep).join("/").replace(/^\.?\//, "");
7392
+ const normalized = renderer.split(path18.sep).join("/").replace(/^\.?\//, "");
6995
7393
  return normalized === "index.html" ? "/" : `/${normalized}`;
6996
7394
  }
6997
7395
  function resolveElectronBinary(config) {
6998
- if (config.electron.electronPath && fs12.existsSync(config.electron.electronPath)) {
7396
+ if (config.electron.electronPath && fs13.existsSync(config.electron.electronPath)) {
6999
7397
  return config.electron.electronPath;
7000
7398
  }
7001
7399
  try {
7002
- const require2 = createRequire5(path17.resolve(config.root, "package.json"));
7400
+ const require2 = createRequire6(path18.resolve(config.root, "package.json"));
7003
7401
  const pathFile = require2.resolve("electron");
7004
7402
  const electronModule = require2(pathFile);
7005
- if (typeof electronModule === "string" && fs12.existsSync(electronModule)) {
7403
+ if (typeof electronModule === "string" && fs13.existsSync(electronModule)) {
7006
7404
  return electronModule;
7007
7405
  }
7008
7406
  } catch {
@@ -7029,10 +7427,10 @@ function warnElectronVersion(config) {
7029
7427
  }
7030
7428
 
7031
7429
  // src/plugins/monaco-editor.ts
7032
- import path18 from "path";
7033
- import fs13 from "fs";
7430
+ import path19 from "path";
7431
+ import fs14 from "fs";
7034
7432
  import crypto4 from "crypto";
7035
- import { createRequire as createRequire6 } from "module";
7433
+ import { createRequire as createRequire7 } from "module";
7036
7434
  var DEFAULT_WORKERS = {
7037
7435
  editorWorkerService: "monaco-editor/esm/vs/editor/editor.worker",
7038
7436
  css: "monaco-editor/esm/vs/language/css/css.worker",
@@ -7051,9 +7449,9 @@ function normalizePublicPath(p) {
7051
7449
  }
7052
7450
  function readMonacoVersion(root) {
7053
7451
  try {
7054
- const require2 = createRequire6(path18.resolve(root, "package.json"));
7452
+ const require2 = createRequire7(path19.resolve(root, "package.json"));
7055
7453
  const pkgJsonPath = require2.resolve("monaco-editor/package.json", { paths: [root] });
7056
- const pkg = JSON.parse(fs13.readFileSync(pkgJsonPath, "utf-8"));
7454
+ const pkg = JSON.parse(fs14.readFileSync(pkgJsonPath, "utf-8"));
7057
7455
  return typeof pkg.version === "string" ? pkg.version : "unknown";
7058
7456
  } catch {
7059
7457
  return "unknown";
@@ -7073,20 +7471,20 @@ function monacoEditorPlugin(options = {}) {
7073
7471
  let cacheDir = "";
7074
7472
  const building = /* @__PURE__ */ new Map();
7075
7473
  async function buildWorker(worker) {
7076
- const cacheFile = path18.join(cacheDir, `${worker.label}.worker.js`);
7077
- if (fs13.existsSync(cacheFile)) return cacheFile;
7474
+ const cacheFile = path19.join(cacheDir, `${worker.label}.worker.js`);
7475
+ if (fs14.existsSync(cacheFile)) return cacheFile;
7078
7476
  const existing = building.get(worker.label);
7079
7477
  if (existing) return existing;
7080
7478
  const task = (async () => {
7081
7479
  const { rolldown: rolldown4 } = await import("rolldown");
7082
- const require2 = createRequire6(path18.resolve(resolvedConfig.root, "package.json"));
7480
+ const require2 = createRequire7(path19.resolve(resolvedConfig.root, "package.json"));
7083
7481
  let entry;
7084
7482
  try {
7085
7483
  entry = require2.resolve(worker.entry, { paths: [resolvedConfig.root] });
7086
7484
  } catch {
7087
7485
  entry = require2.resolve(worker.entry + ".js", { paths: [resolvedConfig.root] });
7088
7486
  }
7089
- fs13.mkdirSync(cacheDir, { recursive: true });
7487
+ fs14.mkdirSync(cacheDir, { recursive: true });
7090
7488
  const bundle2 = await rolldown4({
7091
7489
  input: entry,
7092
7490
  platform: "browser"
@@ -7146,16 +7544,23 @@ function monacoEditorPlugin(options = {}) {
7146
7544
  resolvedConfig = config;
7147
7545
  const version = readMonacoVersion(config.root);
7148
7546
  const key = crypto4.createHash("sha1").update(version + "|" + publicPath).digest("hex").slice(0, 8);
7149
- cacheDir = path18.resolve(config.root, "node_modules/.nasti/monaco", key);
7547
+ cacheDir = path19.resolve(config.root, "node_modules/.nasti/monaco", key);
7150
7548
  },
7151
7549
  async configureServer(server) {
7152
7550
  const shouldBuild = !isCDN(publicPath) || forceBuildCDN;
7153
7551
  const watcher = server.watcher;
7154
- const monacoDir = path18.resolve(resolvedConfig.root, "node_modules/monaco-editor");
7552
+ const monacoLogical = path19.resolve(resolvedConfig.root, "node_modules/monaco-editor");
7553
+ const monacoPaths = /* @__PURE__ */ new Set([monacoLogical]);
7155
7554
  try {
7156
- watcher?.unwatch?.(monacoDir);
7555
+ monacoPaths.add(fs14.realpathSync(monacoLogical));
7157
7556
  } catch {
7158
7557
  }
7558
+ for (const monacoDir of monacoPaths) {
7559
+ try {
7560
+ watcher?.unwatch?.(monacoDir);
7561
+ } catch {
7562
+ }
7563
+ }
7159
7564
  if (!shouldBuild) return;
7160
7565
  void Promise.all(
7161
7566
  workers.map(
@@ -7181,7 +7586,7 @@ function monacoEditorPlugin(options = {}) {
7181
7586
  const file = await buildWorker(worker);
7182
7587
  res.setHeader("Content-Type", "application/javascript; charset=utf-8");
7183
7588
  res.setHeader("Cache-Control", "public, max-age=604800, immutable");
7184
- fs13.createReadStream(file).pipe(res);
7589
+ fs14.createReadStream(file).pipe(res);
7185
7590
  } catch (e) {
7186
7591
  res.statusCode = 500;
7187
7592
  res.end(`Monaco worker build failed: ${e.message}`);
@@ -7216,16 +7621,16 @@ self.monaco = monaco;`,
7216
7621
  resolvedConfig.root,
7217
7622
  resolvedConfig.build.outDir,
7218
7623
  resolvedConfig.base
7219
- ) : isCDN(publicPath) ? path18.resolve(resolvedConfig.root, resolvedConfig.build.outDir, "monaco") : path18.resolve(
7624
+ ) : isCDN(publicPath) ? path19.resolve(resolvedConfig.root, resolvedConfig.build.outDir, "monaco") : path19.resolve(
7220
7625
  resolvedConfig.root,
7221
7626
  resolvedConfig.build.outDir,
7222
7627
  publicPath.replace(/^\//, "")
7223
7628
  );
7224
- fs13.mkdirSync(outDir, { recursive: true });
7629
+ fs14.mkdirSync(outDir, { recursive: true });
7225
7630
  for (const worker of workers) {
7226
7631
  try {
7227
7632
  const cacheFile = await buildWorker(worker);
7228
- fs13.copyFileSync(cacheFile, path18.join(outDir, `${worker.label}.worker.js`));
7633
+ fs14.copyFileSync(cacheFile, path19.join(outDir, `${worker.label}.worker.js`));
7229
7634
  } catch (e) {
7230
7635
  throw new Error(
7231
7636
  `[nasti:monaco-editor] worker build failed for "${worker.label}": ${e.message}
@@ -7237,6 +7642,345 @@ ${e.stack || ""}`
7237
7642
  };
7238
7643
  }
7239
7644
 
7645
+ // src/plugins/rsc.ts
7646
+ init_transformer();
7647
+ import fs15 from "fs";
7648
+ import path20 from "path";
7649
+ import { parseSync } from "oxc-parser";
7650
+ var SERVER_RUNTIME_ID = "virtual:nasti-rsc/server-runtime";
7651
+ var CLIENT_RUNTIME_ID = "virtual:nasti-rsc/client-runtime";
7652
+ var RESOLVED_SERVER_RUNTIME_ID = `\0${SERVER_RUNTIME_ID}`;
7653
+ var RESOLVED_CLIENT_RUNTIME_ID = `\0${CLIENT_RUNTIME_ID}`;
7654
+ function rsc(options = {}) {
7655
+ const names = {
7656
+ client: options.environment?.client ?? "client",
7657
+ ssr: options.environment?.ssr ?? "ssr",
7658
+ rsc: options.environment?.rsc ?? "rsc"
7659
+ };
7660
+ const clientReferences = /* @__PURE__ */ new Map();
7661
+ const serverReferences = /* @__PURE__ */ new Map();
7662
+ let resolvedConfig;
7663
+ return {
7664
+ name: "nasti:rsc",
7665
+ enforce: "post",
7666
+ config(config, env) {
7667
+ const root = path20.resolve(config.root ?? ".");
7668
+ const include = options.include ?? config.react?.include ?? /\.[tj]sx?$/;
7669
+ const exclude = options.exclude ?? config.react?.exclude ?? /node_modules/;
7670
+ const discoveredClients = env.command === "build" ? discoverDirectiveModules(root, options.scanDirectories, include, exclude) : [];
7671
+ for (const item of discoveredClients) {
7672
+ if (item.module.useClient) {
7673
+ clientReferences.set(
7674
+ item.id,
7675
+ new Set(item.module.exports.map((entry) => entry.exported))
7676
+ );
7677
+ }
7678
+ if (item.module.useServer) {
7679
+ serverReferences.set(
7680
+ item.id,
7681
+ new Set(item.module.exports.map((entry) => entry.exported))
7682
+ );
7683
+ }
7684
+ }
7685
+ const environments = { ...config.environments ?? {} };
7686
+ if (names.client !== "client") {
7687
+ environments.client = {
7688
+ ...environments.client ?? {},
7689
+ buildEnabled: false
7690
+ };
7691
+ }
7692
+ const client = { ...environments[names.client] ?? {} };
7693
+ const clientSeeds = collectClientSeeds(root, config, client, options.entries?.client);
7694
+ const generatedClientEntries = discoveredClients.filter((item) => item.module.useClient).map((item) => item.id);
7695
+ client.consumer = "client";
7696
+ client.entry = uniqueEntries([...clientSeeds, ...generatedClientEntries]);
7697
+ environments[names.client] = client;
7698
+ const rscEnvironment = { ...environments[names.rsc] ?? {} };
7699
+ rscEnvironment.consumer = "server";
7700
+ const rscEntries = normalizeEntries(options.entries?.rsc);
7701
+ if (rscEntries.length > 0) rscEnvironment.entry = rscEntries;
7702
+ environments[names.rsc] = rscEnvironment;
7703
+ const ssrEntries = normalizeEntries(options.entries?.ssr);
7704
+ if (ssrEntries.length > 0 || environments[names.ssr]) {
7705
+ environments[names.ssr] = {
7706
+ ...environments[names.ssr] ?? {},
7707
+ consumer: "server",
7708
+ ...ssrEntries.length > 0 ? { entry: ssrEntries } : {}
7709
+ };
7710
+ }
7711
+ return { environments };
7712
+ },
7713
+ configEnvironment(name, environment) {
7714
+ if (name !== names.rsc) return;
7715
+ const conditions = environment.resolve?.conditions ?? ["node", "import", "module", "default"];
7716
+ return {
7717
+ consumer: "server",
7718
+ resolve: {
7719
+ ...environment.resolve,
7720
+ conditions: ["react-server", ...conditions.filter((item) => item !== "react-server")]
7721
+ }
7722
+ };
7723
+ },
7724
+ configResolved(config) {
7725
+ if (config.framework !== "react") {
7726
+ throw new Error('[nasti:rsc] the RSC generator requires framework: "react"');
7727
+ }
7728
+ resolvedConfig = config;
7729
+ },
7730
+ resolveId(source) {
7731
+ if (source === SERVER_RUNTIME_ID) return RESOLVED_SERVER_RUNTIME_ID;
7732
+ if (source === CLIENT_RUNTIME_ID) return RESOLVED_CLIENT_RUNTIME_ID;
7733
+ return null;
7734
+ },
7735
+ load(id) {
7736
+ if (id === RESOLVED_SERVER_RUNTIME_ID) return createServerRuntimeModule();
7737
+ if (id === RESOLVED_CLIENT_RUNTIME_ID) {
7738
+ const browser = this.environment?.name === names.client;
7739
+ return createClientRuntimeModule(browser);
7740
+ }
7741
+ return null;
7742
+ },
7743
+ transform(code, id) {
7744
+ if (!resolvedConfig || !isSourceModule(id, resolvedConfig, options)) return null;
7745
+ const cleanId = cleanModuleId(id);
7746
+ const module = scanModule(cleanId, code);
7747
+ if (!module) return null;
7748
+ if (module.useClient && module.useServer) {
7749
+ throw new Error(`[nasti:rsc] ${displayId(resolvedConfig.root, cleanId)} cannot contain both "use client" and "use server"`);
7750
+ }
7751
+ const moduleId = referenceModuleId(resolvedConfig.root, cleanId);
7752
+ if (module.useClient) {
7753
+ clientReferences.set(cleanId, new Set(module.exports.map((entry) => entry.exported)));
7754
+ if (this.environment?.name === names.rsc) {
7755
+ return {
7756
+ code: createClientReferenceProxy(moduleId, module.exports),
7757
+ map: { mappings: "" }
7758
+ };
7759
+ }
7760
+ }
7761
+ if (module.useServer) {
7762
+ serverReferences.set(cleanId, new Set(module.exports.map((entry) => entry.exported)));
7763
+ if (this.environment?.name === names.rsc) {
7764
+ return {
7765
+ code: registerServerReferences(code, moduleId, module.exports, cleanId),
7766
+ map: { mappings: "" }
7767
+ };
7768
+ }
7769
+ if (this.environment?.consumer === "client" || this.environment?.name === names.client || this.environment?.name === names.ssr) {
7770
+ return {
7771
+ code: createServerReferenceProxy(moduleId, module.exports),
7772
+ map: { mappings: "" }
7773
+ };
7774
+ }
7775
+ }
7776
+ return null;
7777
+ },
7778
+ afterBuildApp(results, _api, context) {
7779
+ if (options.manifestFile === false) return;
7780
+ const manifest = createManifest(
7781
+ names,
7782
+ resolvedConfig?.root ?? "",
7783
+ results,
7784
+ clientReferences,
7785
+ serverReferences
7786
+ );
7787
+ const output = {
7788
+ type: "asset",
7789
+ fileName: options.manifestFile ?? "rsc-manifest.json",
7790
+ source: JSON.stringify(manifest, null, 2) + "\n"
7791
+ };
7792
+ context.emitFile(output);
7793
+ }
7794
+ };
7795
+ }
7796
+ function scanModule(filename, code) {
7797
+ if (!code.includes("use client") && !code.includes("use server")) return null;
7798
+ const parsed = parseSync(filename, code);
7799
+ if (parsed.errors.length > 0) return null;
7800
+ const directives = new Set(
7801
+ parsed.program.body.filter((node) => node.type === "ExpressionStatement" && typeof node.directive === "string").map((node) => node.directive)
7802
+ );
7803
+ const useClient = directives.has("use client");
7804
+ const useServer = directives.has("use server");
7805
+ if (!useClient && !useServer) return null;
7806
+ const exports = [];
7807
+ for (const statement of parsed.module.staticExports) {
7808
+ for (const entry of statement.entries) {
7809
+ if (entry.isType) continue;
7810
+ const exported = entry.exportName.kind === "Default" ? "default" : entry.exportName.name;
7811
+ if (!exported) {
7812
+ throw new Error(
7813
+ `[nasti:rsc] ${filename} uses export * inside an RSC directive module; replace it with explicit named exports so reference identities are stable`
7814
+ );
7815
+ }
7816
+ exports.push({
7817
+ exported,
7818
+ local: entry.localName.kind === "Name" ? entry.localName.name ?? void 0 : void 0,
7819
+ reexported: entry.moduleRequest !== null
7820
+ });
7821
+ }
7822
+ }
7823
+ return { useClient, useServer, exports: dedupeExports(exports) };
7824
+ }
7825
+ function createClientReferenceProxy(moduleId, exports) {
7826
+ const lines = [
7827
+ `import { registerClientReference as __nasti_register_client__ } from ${JSON.stringify(SERVER_RUNTIME_ID)};`
7828
+ ];
7829
+ exports.forEach((entry, index2) => {
7830
+ const local = `__nasti_client_reference_${index2}__`;
7831
+ const message = `Cannot call client export ${moduleId}#${entry.exported} from the RSC server graph.`;
7832
+ lines.push(
7833
+ `const ${local} = __nasti_register_client__(function () { throw new Error(${JSON.stringify(message)}); }, ${JSON.stringify(moduleId)}, ${JSON.stringify(entry.exported)});`,
7834
+ exportLocal(local, entry.exported)
7835
+ );
7836
+ });
7837
+ return lines.join("\n") + "\n";
7838
+ }
7839
+ function registerServerReferences(code, moduleId, exports, filename) {
7840
+ const registrations = [];
7841
+ for (const entry of exports) {
7842
+ if (entry.reexported || !entry.local) {
7843
+ throw new Error(
7844
+ `[nasti:rsc] ${filename} must use named local bindings for "use server" exports; ${entry.exported} cannot be registered safely`
7845
+ );
7846
+ }
7847
+ registrations.push(
7848
+ `__nasti_register_server__(${entry.local}, ${JSON.stringify(moduleId)}, ${JSON.stringify(entry.exported)});`
7849
+ );
7850
+ }
7851
+ return [
7852
+ code,
7853
+ `import { registerServerReference as __nasti_register_server__ } from ${JSON.stringify(SERVER_RUNTIME_ID)};`,
7854
+ ...registrations,
7855
+ ""
7856
+ ].join("\n");
7857
+ }
7858
+ function createServerReferenceProxy(moduleId, exports) {
7859
+ const lines = [
7860
+ `import { createServerReference as __nasti_create_server__ } from ${JSON.stringify(CLIENT_RUNTIME_ID)};`
7861
+ ];
7862
+ exports.forEach((entry, index2) => {
7863
+ const local = `__nasti_server_reference_${index2}__`;
7864
+ lines.push(
7865
+ `const ${local} = __nasti_create_server__(${JSON.stringify(moduleId)}, ${JSON.stringify(entry.exported)});`,
7866
+ exportLocal(local, entry.exported)
7867
+ );
7868
+ });
7869
+ return lines.join("\n") + "\n";
7870
+ }
7871
+ function exportLocal(local, exported) {
7872
+ if (exported === "default") return `export default ${local};`;
7873
+ const name = /^[A-Za-z_$][\w$]*$/.test(exported) ? exported : JSON.stringify(exported);
7874
+ return `export { ${local} as ${name} };`;
7875
+ }
7876
+ function createServerRuntimeModule() {
7877
+ return [
7878
+ `export { registerClientReference, registerServerReference } from "react-server-dom-webpack/server.edge";`,
7879
+ ""
7880
+ ].join("\n");
7881
+ }
7882
+ function createClientRuntimeModule(browser) {
7883
+ const source = browser ? "react-server-dom-webpack/client.browser" : "react-server-dom-webpack/client.edge";
7884
+ return `
7885
+ import { createServerReference as __createServerReference } from ${JSON.stringify(source)};
7886
+ const __callServer = (id, args) => {
7887
+ const handler = globalThis[Symbol.for("nasti.rsc.callServer")];
7888
+ if (typeof handler !== "function") {
7889
+ throw new Error("No RSC callServer handler is installed. Set globalThis[Symbol.for('nasti.rsc.callServer')].");
7890
+ }
7891
+ return handler(id, args);
7892
+ };
7893
+ export function createServerReference(moduleId, name) {
7894
+ return __createServerReference(moduleId + "#" + name, __callServer, undefined, undefined, name);
7895
+ }
7896
+ `.trimStart();
7897
+ }
7898
+ function createManifest(names, root, results, clients, servers) {
7899
+ return {
7900
+ version: 1,
7901
+ environments: names,
7902
+ clientReferences: manifestReferences(root, results[names.client], clients),
7903
+ serverReferences: manifestReferences(root, results[names.rsc], servers)
7904
+ };
7905
+ }
7906
+ function manifestReferences(root, result, references) {
7907
+ const output = {};
7908
+ for (const [id, names] of [...references].sort(([a], [b]) => a.localeCompare(b))) {
7909
+ const chunks = Object.values(result?.chunks ?? {}).filter((chunk) => chunk.moduleIds.some((moduleId) => cleanModuleId(moduleId) === id)).map((chunk) => chunk.fileName).sort();
7910
+ for (const name of [...names].sort()) {
7911
+ const moduleId = referenceModuleId(root, id);
7912
+ output[`${moduleId}#${name}`] = { id: moduleId, name, chunks };
7913
+ }
7914
+ }
7915
+ return output;
7916
+ }
7917
+ function discoverDirectiveModules(root, scanDirectories, include, exclude) {
7918
+ const requested = scanDirectories ?? ["app", "src"];
7919
+ const roots = requested.map((directory) => path20.resolve(root, directory)).filter((directory) => fs15.existsSync(directory));
7920
+ if (roots.length === 0) roots.push(root);
7921
+ const output = [];
7922
+ for (const directory of roots) walk(directory);
7923
+ return output;
7924
+ function walk(directory) {
7925
+ for (const entry of fs15.readdirSync(directory, { withFileTypes: true })) {
7926
+ if (entry.name === "node_modules" || entry.name === ".git" || entry.name === ".nasti") continue;
7927
+ const id = path20.join(directory, entry.name);
7928
+ if (entry.isDirectory()) {
7929
+ walk(id);
7930
+ continue;
7931
+ }
7932
+ if (!entry.isFile() || !matchesReactFilter(id, include, exclude)) continue;
7933
+ const module = scanModule(id, fs15.readFileSync(id, "utf-8"));
7934
+ if (module) output.push({ id, module });
7935
+ }
7936
+ }
7937
+ }
7938
+ function collectClientSeeds(root, config, client, configured) {
7939
+ const explicit = [
7940
+ ...normalizeEntries(client.entry),
7941
+ ...normalizeEntries(configured)
7942
+ ];
7943
+ if (explicit.length > 0) return explicit;
7944
+ const htmlFile = path20.resolve(root, client.html ?? "index.html");
7945
+ if (fs15.existsSync(htmlFile)) {
7946
+ const html = fs15.readFileSync(htmlFile, "utf-8");
7947
+ const htmlDir = path20.dirname(htmlFile);
7948
+ const entries = [...html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi)].map((match) => match[1]?.split(/[?#]/, 1)[0]).filter((entry) => !!entry && !entry.startsWith("http")).map((entry) => entry.startsWith("/") ? path20.resolve(root, entry.slice(1)) : path20.resolve(htmlDir, entry));
7949
+ if (entries.length > 0) return entries;
7950
+ }
7951
+ for (const entry of ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"]) {
7952
+ if (fs15.existsSync(path20.resolve(root, entry))) return [entry];
7953
+ }
7954
+ return [];
7955
+ }
7956
+ function normalizeEntries(entries) {
7957
+ return entries == null ? [] : Array.isArray(entries) ? entries : [entries];
7958
+ }
7959
+ function uniqueEntries(entries) {
7960
+ return [...new Set(entries)];
7961
+ }
7962
+ function isSourceModule(id, config, options) {
7963
+ const cleanId = cleanModuleId(id);
7964
+ if (cleanId.startsWith("\0")) return false;
7965
+ const include = options.include ?? config.react.include;
7966
+ const exclude = options.exclude ?? config.react.exclude;
7967
+ return matchesReactFilter(cleanId, include, exclude);
7968
+ }
7969
+ function cleanModuleId(id) {
7970
+ return id.split(/[?#]/, 1)[0];
7971
+ }
7972
+ function referenceModuleId(root, id) {
7973
+ if (!root || !path20.isAbsolute(id)) return id.replaceAll(path20.sep, "/");
7974
+ const relative = path20.relative(root, id).replaceAll(path20.sep, "/");
7975
+ return relative.startsWith("../") ? id.replaceAll(path20.sep, "/") : `/${relative}`;
7976
+ }
7977
+ function displayId(root, id) {
7978
+ return referenceModuleId(root, id);
7979
+ }
7980
+ function dedupeExports(exports) {
7981
+ return [...new Map(exports.map((entry) => [entry.exported, entry])).values()];
7982
+ }
7983
+
7240
7984
  // src/index.ts
7241
7985
  init_environment();
7242
7986
  init_hot_channel();
@@ -7264,6 +8008,7 @@ export {
7264
8008
  printServerUrls,
7265
8009
  resolveConfig,
7266
8010
  resolveEnvironmentPlugins,
8011
+ rsc,
7267
8012
  ssrDefineOverrides,
7268
8013
  startElectronDev
7269
8014
  };