@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.cjs CHANGED
@@ -5,10 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __glob = (map) => (path19) => {
9
- var fn = map[path19];
8
+ var __glob = (map) => (path21) => {
9
+ var fn = map[path21];
10
10
  if (fn) return fn();
11
- throw new Error("Module not found in bundle: " + path19);
11
+ throw new Error("Module not found in bundle: " + path21);
12
12
  };
13
13
  var __esm = (fn, res) => function __init() {
14
14
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
@@ -39,7 +39,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
39
39
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
40
40
 
41
41
  // src/config/defaults.ts
42
- var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaultExperimental, defaults;
42
+ var defaultResolve, defaultServer, defaultBuild, defaultElectron, defaultExperimental, defaultReact, defaults;
43
43
  var init_defaults = __esm({
44
44
  "src/config/defaults.ts"() {
45
45
  "use strict";
@@ -92,12 +92,20 @@ var init_defaults = __esm({
92
92
  defaultExperimental = {
93
93
  bundledDev: false
94
94
  };
95
+ defaultReact = {
96
+ include: /\.[tj]sx?$/,
97
+ exclude: /node_modules/,
98
+ jsxImportSource: "react",
99
+ jsxRuntime: "automatic",
100
+ compiler: false
101
+ };
95
102
  defaults = {
96
103
  root: ".",
97
104
  base: "/",
98
105
  mode: "development",
99
106
  target: "web",
100
107
  framework: "auto",
108
+ react: defaultReact,
101
109
  resolve: defaultResolve,
102
110
  server: defaultServer,
103
111
  build: defaultBuild,
@@ -435,6 +443,13 @@ async function resolveConfig(inlineConfig = {}, command) {
435
443
  mode,
436
444
  target: merged.target ?? defaults.target,
437
445
  framework: (merged.framework ?? defaults.framework) === "auto" ? detectFramework(root) : merged.framework,
446
+ react: {
447
+ include: merged.react?.include ?? defaultReact.include,
448
+ exclude: merged.react?.exclude ?? defaultReact.exclude,
449
+ jsxImportSource: merged.react?.jsxImportSource ?? defaultReact.jsxImportSource,
450
+ jsxRuntime: merged.react?.jsxRuntime ?? defaultReact.jsxRuntime,
451
+ compiler: merged.react?.compiler === true ? {} : merged.react?.compiler ?? defaultReact.compiler
452
+ },
438
453
  command,
439
454
  resolve: {
440
455
  // tsconfig paths 优先级最低:tsconfig < defaults < user config
@@ -873,27 +888,27 @@ var require_process = __commonJS({
873
888
  var require_filesystem = __commonJS({
874
889
  "node_modules/detect-libc/lib/filesystem.js"(exports2, module2) {
875
890
  "use strict";
876
- var fs14 = require("fs");
891
+ var fs16 = require("fs");
877
892
  var LDD_PATH = "/usr/bin/ldd";
878
893
  var SELF_PATH = "/proc/self/exe";
879
894
  var MAX_LENGTH = 2048;
880
- var readFileSync = (path19) => {
881
- const fd = fs14.openSync(path19, "r");
895
+ var readFileSync = (path21) => {
896
+ const fd = fs16.openSync(path21, "r");
882
897
  const buffer = Buffer.alloc(MAX_LENGTH);
883
- const bytesRead = fs14.readSync(fd, buffer, 0, MAX_LENGTH, 0);
884
- fs14.close(fd, () => {
898
+ const bytesRead = fs16.readSync(fd, buffer, 0, MAX_LENGTH, 0);
899
+ fs16.close(fd, () => {
885
900
  });
886
901
  return buffer.subarray(0, bytesRead);
887
902
  };
888
- var readFile = (path19) => new Promise((resolve, reject) => {
889
- fs14.open(path19, "r", (err, fd) => {
903
+ var readFile = (path21) => new Promise((resolve, reject) => {
904
+ fs16.open(path21, "r", (err, fd) => {
890
905
  if (err) {
891
906
  reject(err);
892
907
  } else {
893
908
  const buffer = Buffer.alloc(MAX_LENGTH);
894
- fs14.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
909
+ fs16.read(fd, buffer, 0, MAX_LENGTH, 0, (_, bytesRead) => {
895
910
  resolve(buffer.subarray(0, bytesRead));
896
- fs14.close(fd, () => {
911
+ fs16.close(fd, () => {
897
912
  });
898
913
  });
899
914
  }
@@ -1005,11 +1020,11 @@ var require_detect_libc = __commonJS({
1005
1020
  }
1006
1021
  return null;
1007
1022
  };
1008
- var familyFromInterpreterPath = (path19) => {
1009
- if (path19) {
1010
- if (path19.includes("/ld-musl-")) {
1023
+ var familyFromInterpreterPath = (path21) => {
1024
+ if (path21) {
1025
+ if (path21.includes("/ld-musl-")) {
1011
1026
  return MUSL;
1012
- } else if (path19.includes("/ld-linux-")) {
1027
+ } else if (path21.includes("/ld-linux-")) {
1013
1028
  return GLIBC;
1014
1029
  }
1015
1030
  }
@@ -1056,8 +1071,8 @@ var require_detect_libc = __commonJS({
1056
1071
  cachedFamilyInterpreter = null;
1057
1072
  try {
1058
1073
  const selfContent = await readFile(SELF_PATH);
1059
- const path19 = interpreterPath(selfContent);
1060
- cachedFamilyInterpreter = familyFromInterpreterPath(path19);
1074
+ const path21 = interpreterPath(selfContent);
1075
+ cachedFamilyInterpreter = familyFromInterpreterPath(path21);
1061
1076
  } catch (e) {
1062
1077
  }
1063
1078
  return cachedFamilyInterpreter;
@@ -1069,8 +1084,8 @@ var require_detect_libc = __commonJS({
1069
1084
  cachedFamilyInterpreter = null;
1070
1085
  try {
1071
1086
  const selfContent = readFileSync(SELF_PATH);
1072
- const path19 = interpreterPath(selfContent);
1073
- cachedFamilyInterpreter = familyFromInterpreterPath(path19);
1087
+ const path21 = interpreterPath(selfContent);
1088
+ cachedFamilyInterpreter = familyFromInterpreterPath(path21);
1074
1089
  } catch (e) {
1075
1090
  }
1076
1091
  return cachedFamilyInterpreter;
@@ -2171,7 +2186,81 @@ ${msg}`);
2171
2186
  map: result.map ? JSON.stringify(result.map) : null
2172
2187
  };
2173
2188
  }
2174
- var import_oxc_transform, JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS;
2189
+ async function transformReactCode(filename, code, options) {
2190
+ if (!matchesReactFilter(filename, options.react.include, options.react.exclude)) {
2191
+ return null;
2192
+ }
2193
+ if (!options.react.compiler) {
2194
+ if (!shouldTransform(filename)) return null;
2195
+ return transformCode(filename, code, {
2196
+ sourcemap: options.sourcemap,
2197
+ jsxRuntime: options.react.jsxRuntime,
2198
+ jsxImportSource: options.react.jsxImportSource,
2199
+ reactRefresh: options.reactRefresh,
2200
+ target: options.target
2201
+ });
2202
+ }
2203
+ if (!shouldTransform(filename)) return null;
2204
+ const compiler2 = await loadReactCompiler();
2205
+ const compilerOptions = options.react.compiler;
2206
+ const shouldCompile = options.consumer === "client" && (compilerOptions.compilationMode === "annotation" ? /['"]use memo['"]/.test(code) : defaultReactCompilerCodeFilter.test(code));
2207
+ const result = await compiler2.transform(cleanTransformId(filename), code, {
2208
+ jsx: {
2209
+ runtime: options.react.jsxRuntime,
2210
+ development: options.development,
2211
+ importSource: options.react.jsxImportSource,
2212
+ refresh: options.consumer === "client" && !!options.reactRefresh
2213
+ },
2214
+ reactCompiler: shouldCompile ? compilerOptions : false,
2215
+ sourcemap: options.sourcemap ?? true
2216
+ });
2217
+ const diagnostics = result.errors.map(
2218
+ (error) => `${error.message}${error.codeframe ? `
2219
+ ${error.codeframe}` : ""}`
2220
+ );
2221
+ if (result.fatal) {
2222
+ throw new Error(
2223
+ diagnostics.join("\n\n") || `React Compiler transform failed for ${filename}`
2224
+ );
2225
+ }
2226
+ for (const diagnostic of diagnostics) options.onWarning?.(diagnostic);
2227
+ return {
2228
+ code: result.code,
2229
+ map: result.map ? JSON.stringify(result.map) : null
2230
+ };
2231
+ }
2232
+ function matchesReactFilter(id, include, exclude) {
2233
+ const cleanId = cleanTransformId(id);
2234
+ return matchesFilter(cleanId, include) && !matchesFilter(cleanId, exclude);
2235
+ }
2236
+ function matchesFilter(id, filter2) {
2237
+ const patterns = Array.isArray(filter2) ? filter2 : [filter2];
2238
+ return patterns.some((pattern) => {
2239
+ if (pattern instanceof RegExp) {
2240
+ pattern.lastIndex = 0;
2241
+ return pattern.test(id);
2242
+ }
2243
+ if (!pattern.includes("*")) return id.includes(pattern);
2244
+ const expression = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "\0").replace(/\*/g, "[^/]*").replace(/\0/g, ".*");
2245
+ return new RegExp(`^${expression}$`).test(id);
2246
+ });
2247
+ }
2248
+ function cleanTransformId(id) {
2249
+ return id.split(/[?#]/, 1)[0];
2250
+ }
2251
+ async function loadReactCompiler() {
2252
+ if (reactCompilerImplementation) return reactCompilerImplementation;
2253
+ try {
2254
+ reactCompilerImplementation = await import("oxc-transform-react");
2255
+ return reactCompilerImplementation;
2256
+ } catch (error) {
2257
+ throw new Error(
2258
+ '[nasti] React Compiler requires the optional "oxc-transform-react" package. Install it before setting react.compiler.' + (error instanceof Error ? `
2259
+ ${error.message}` : "")
2260
+ );
2261
+ }
2262
+ }
2263
+ var import_oxc_transform, JS_EXTENSIONS, TS_EXTENSIONS, JSX_EXTENSIONS, defaultReactCompilerCodeFilter, reactCompilerImplementation;
2175
2264
  var init_transformer = __esm({
2176
2265
  "src/core/transformer.ts"() {
2177
2266
  "use strict";
@@ -2179,6 +2268,7 @@ var init_transformer = __esm({
2179
2268
  JS_EXTENSIONS = /\.(js|mjs|cjs)$/;
2180
2269
  TS_EXTENSIONS = /\.(ts|mts|cts)$/;
2181
2270
  JSX_EXTENSIONS = /\.(jsx|tsx)$/;
2271
+ defaultReactCompilerCodeFilter = /forwardRef|memo|\b(?:[A-Z]|use[A-Z0-9])/;
2182
2272
  }
2183
2273
  });
2184
2274
 
@@ -2218,8 +2308,8 @@ function vuePlugin(config, environmentName = "client") {
2218
2308
  let cached2 = descriptorCache.get(filePath);
2219
2309
  if (!cached2) {
2220
2310
  try {
2221
- const fs14 = await import("fs");
2222
- const rawSource = fs14.readFileSync(filePath, "utf-8");
2311
+ const fs16 = await import("fs");
2312
+ const rawSource = fs16.readFileSync(filePath, "utf-8");
2223
2313
  const transformedSfc = await applySourceTransform(
2224
2314
  vueOptions.transformSfc,
2225
2315
  rawSource,
@@ -2887,6 +2977,24 @@ var init_module_graph = __esm({
2887
2977
  getModulesByFile(file) {
2888
2978
  return this.fileToModulesMap.get(file);
2889
2979
  }
2980
+ /**
2981
+ * Modules whose registered entry file lives under `dir` (inclusive).
2982
+ * Used when a non-entry source inside a prebundled workspace package changes:
2983
+ * only the package entry was registered, so getModulesByFile(changedFile)
2984
+ * misses — we invalidate every /@modules entry rooted in that package.
2985
+ */
2986
+ getModulesWithFileUnder(dir) {
2987
+ const result = /* @__PURE__ */ new Set();
2988
+ const normDir = dir.replace(/\\/g, "/");
2989
+ const normPrefix = normDir.endsWith("/") ? normDir : normDir + "/";
2990
+ for (const [file, mods] of this.fileToModulesMap) {
2991
+ const normFile = file.replace(/\\/g, "/");
2992
+ if (normFile === normDir || normFile.startsWith(normPrefix)) {
2993
+ for (const m of mods) result.add(m);
2994
+ }
2995
+ }
2996
+ return result;
2997
+ }
2890
2998
  async ensureEntryFromUrl(url) {
2891
2999
  const normalizedUrl = removeTimestampQuery(url);
2892
3000
  let mod = this.urlToModuleMap.get(normalizedUrl);
@@ -3257,6 +3365,44 @@ var init_environment = __esm({
3257
3365
  }
3258
3366
  });
3259
3367
 
3368
+ // src/plugins/react.ts
3369
+ function reactPlugin(config, environment) {
3370
+ return {
3371
+ name: "nasti:oxc-transform",
3372
+ async transform(code, id) {
3373
+ const result = await transformReactCode(id, code, {
3374
+ react: config.react,
3375
+ consumer: environment.consumer,
3376
+ development: config.mode === "development",
3377
+ sourcemap: !!environment.options.build.sourcemap,
3378
+ target: environment.options.build.target,
3379
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
3380
+ });
3381
+ if (!result) return null;
3382
+ return {
3383
+ code: result.code,
3384
+ map: result.map ? JSON.parse(result.map) : void 0
3385
+ };
3386
+ },
3387
+ handleHotUpdate(ctx) {
3388
+ for (const mod of ctx.modules) {
3389
+ if (REACT_FILE_RE.test(mod.url) && matchesReactFilter(mod.url, config.react.include, config.react.exclude)) {
3390
+ mod.isSelfAccepting = true;
3391
+ }
3392
+ }
3393
+ return ctx.modules;
3394
+ }
3395
+ };
3396
+ }
3397
+ var REACT_FILE_RE;
3398
+ var init_react = __esm({
3399
+ "src/plugins/react.ts"() {
3400
+ "use strict";
3401
+ init_transformer();
3402
+ REACT_FILE_RE = /\.[jt]sx(?:[?#].*)?$/;
3403
+ }
3404
+ });
3405
+
3260
3406
  // src/core/env.ts
3261
3407
  function loadEnv(mode, root, prefixes) {
3262
3408
  const envFiles = [
@@ -3614,7 +3760,7 @@ function getRolldownOptions(environment, entryPoints, rolldownPlugins) {
3614
3760
  // 相对/绝对/虚拟模块照常打包。需要内联依赖时经 rolldownOptions.external 覆盖。
3615
3761
  external: restInputOptions.external ?? ((id) => {
3616
3762
  if (NODE_BUILTINS.has(id)) return true;
3617
- return !id.startsWith(".") && !import_node_path10.default.isAbsolute(id) && !id.startsWith("\0");
3763
+ return !id.startsWith(".") && !import_node_path10.default.isAbsolute(id) && !id.startsWith("\0") && !id.startsWith("virtual:");
3618
3764
  })
3619
3765
  } : {}
3620
3766
  };
@@ -3837,6 +3983,7 @@ function resolveClientEntries(config, html) {
3837
3983
  return entryPoints;
3838
3984
  }
3839
3985
  function createOxcTransformPlugin(config, environment) {
3986
+ if (config.framework === "react") return reactPlugin(config, environment);
3840
3987
  return {
3841
3988
  name: "nasti:oxc-transform",
3842
3989
  transform(code, id) {
@@ -3857,7 +4004,7 @@ async function build(inlineConfig = {}) {
3857
4004
  const startTime = performance.now();
3858
4005
  logger.info(
3859
4006
  import_picocolors4.default.cyan(`
3860
- nasti v${"2.4.3"} `) + import_picocolors4.default.green(`building for ${config.mode}...`)
4007
+ nasti v${"2.5.0"} `) + import_picocolors4.default.green(`building for ${config.mode}...`)
3861
4008
  );
3862
4009
  debug5?.(`root: ${config.root}`);
3863
4010
  const buildableNames = Object.keys(config.environments).filter((name) => {
@@ -4143,6 +4290,7 @@ var init_build = __esm({
4143
4290
  init_environment();
4144
4291
  init_css_engine();
4145
4292
  init_html();
4293
+ init_react();
4146
4294
  init_transformer();
4147
4295
  init_env();
4148
4296
  init_reporter();
@@ -4200,6 +4348,120 @@ var init_ws = __esm({
4200
4348
  }
4201
4349
  });
4202
4350
 
4351
+ // src/server/fs-allow.ts
4352
+ function isUnderRoot(abs, root) {
4353
+ const rel = import_node_path12.default.relative(root, abs);
4354
+ return !!rel && !rel.startsWith("..") && !import_node_path12.default.isAbsolute(rel);
4355
+ }
4356
+ function discoverLinkedPackageRoots(projectRoot, maxDepth = 4) {
4357
+ const results = [];
4358
+ const seenReal = /* @__PURE__ */ new Set();
4359
+ const queued = /* @__PURE__ */ new Set([projectRoot]);
4360
+ const queue = [projectRoot];
4361
+ for (let depth = 0; depth < maxDepth && queue.length > 0; depth++) {
4362
+ const levelCount = queue.length;
4363
+ for (let i = 0; i < levelCount; i++) {
4364
+ const dir = queue.shift();
4365
+ const nm = import_node_path12.default.join(dir, "node_modules");
4366
+ let entries;
4367
+ try {
4368
+ entries = import_node_fs9.default.readdirSync(nm, { withFileTypes: true });
4369
+ } catch {
4370
+ continue;
4371
+ }
4372
+ for (const ent of entries) {
4373
+ if (ent.name.startsWith(".") || ent.name === "node_modules") continue;
4374
+ const pkgNames = ent.name.startsWith("@") ? listScopedPackages(nm, ent.name) : [ent.name];
4375
+ for (const pkgName of pkgNames) {
4376
+ const pkgPath = import_node_path12.default.join(nm, pkgName);
4377
+ let real;
4378
+ try {
4379
+ real = import_node_fs9.default.realpathSync(pkgPath);
4380
+ } catch {
4381
+ continue;
4382
+ }
4383
+ if (seenReal.has(real)) continue;
4384
+ seenReal.add(real);
4385
+ if (!queued.has(real)) {
4386
+ queued.add(real);
4387
+ queue.push(real);
4388
+ }
4389
+ if (real !== projectRoot && !isUnderRoot(real, projectRoot) && !real.includes(NM)) {
4390
+ results.push(real);
4391
+ }
4392
+ }
4393
+ }
4394
+ }
4395
+ }
4396
+ return results;
4397
+ }
4398
+ function listScopedPackages(nm, scope) {
4399
+ try {
4400
+ return import_node_fs9.default.readdirSync(import_node_path12.default.join(nm, scope)).filter((name) => !name.startsWith(".")).map((name) => import_node_path12.default.join(scope, name));
4401
+ } catch {
4402
+ return [];
4403
+ }
4404
+ }
4405
+ function getLinkedPackageRoots(projectRoot) {
4406
+ let mtimeMs = 0;
4407
+ try {
4408
+ mtimeMs = import_node_fs9.default.statSync(import_node_path12.default.join(projectRoot, "node_modules")).mtimeMs;
4409
+ } catch {
4410
+ mtimeMs = 0;
4411
+ }
4412
+ const cached2 = linkedRootsCache.get(projectRoot);
4413
+ if (cached2 && cached2.mtimeMs === mtimeMs) {
4414
+ return cached2.roots;
4415
+ }
4416
+ const roots = discoverLinkedPackageRoots(projectRoot);
4417
+ linkedRootsCache.set(projectRoot, { roots, mtimeMs });
4418
+ return roots;
4419
+ }
4420
+ function clearLinkedPackageRootsCache() {
4421
+ linkedRootsCache.clear();
4422
+ }
4423
+ function isAllowedDevModulePath(realId, projectRoot) {
4424
+ if (realId === projectRoot || isUnderRoot(realId, projectRoot)) return true;
4425
+ for (const pkgRoot of getLinkedPackageRoots(projectRoot)) {
4426
+ if (realId === pkgRoot || realId.startsWith(pkgRoot + import_node_path12.default.sep)) return true;
4427
+ }
4428
+ let dir = projectRoot;
4429
+ for (; ; ) {
4430
+ const nm = import_node_path12.default.join(dir, "node_modules");
4431
+ if (realId === nm || realId.startsWith(nm + import_node_path12.default.sep)) return true;
4432
+ const parent = import_node_path12.default.dirname(dir);
4433
+ if (parent === dir) break;
4434
+ dir = parent;
4435
+ }
4436
+ return false;
4437
+ }
4438
+ function findNearestPackageRoot(file) {
4439
+ let dir = import_node_path12.default.dirname(file);
4440
+ for (; ; ) {
4441
+ const pkgJson = import_node_path12.default.join(dir, "package.json");
4442
+ if (import_node_fs9.default.existsSync(pkgJson)) {
4443
+ try {
4444
+ const pkg = JSON.parse(import_node_fs9.default.readFileSync(pkgJson, "utf-8"));
4445
+ if (typeof pkg?.name === "string" && pkg.name) return dir;
4446
+ } catch {
4447
+ }
4448
+ }
4449
+ const parent = import_node_path12.default.dirname(dir);
4450
+ if (parent === dir) return null;
4451
+ dir = parent;
4452
+ }
4453
+ }
4454
+ var import_node_fs9, import_node_path12, NM, linkedRootsCache;
4455
+ var init_fs_allow = __esm({
4456
+ "src/server/fs-allow.ts"() {
4457
+ "use strict";
4458
+ import_node_fs9 = __toESM(require("fs"), 1);
4459
+ import_node_path12 = __toESM(require("path"), 1);
4460
+ NM = `${import_node_path12.default.sep}node_modules${import_node_path12.default.sep}`;
4461
+ linkedRootsCache = /* @__PURE__ */ new Map();
4462
+ }
4463
+ });
4464
+
4203
4465
  // src/server/middleware.ts
4204
4466
  function getReactRefreshRuntimeEsm(includeBoundaryHelpers = false) {
4205
4467
  if (__refreshRuntimeCache) {
@@ -4208,10 +4470,10 @@ function getReactRefreshRuntimeEsm(includeBoundaryHelpers = false) {
4208
4470
  let cjsPath;
4209
4471
  try {
4210
4472
  const pkgPath = __require.resolve("react-refresh/package.json");
4211
- cjsPath = import_node_path12.default.join(import_node_path12.default.dirname(pkgPath), "cjs", "react-refresh-runtime.development.js");
4473
+ cjsPath = import_node_path13.default.join(import_node_path13.default.dirname(pkgPath), "cjs", "react-refresh-runtime.development.js");
4212
4474
  } catch (err) {
4213
- cjsPath = import_node_path12.default.resolve(__dirname_esm, "../../node_modules/react-refresh/cjs/react-refresh-runtime.development.js");
4214
- if (!import_node_fs9.default.existsSync(cjsPath)) {
4475
+ cjsPath = import_node_path13.default.resolve(__dirname_esm, "../../node_modules/react-refresh/cjs/react-refresh-runtime.development.js");
4476
+ if (!import_node_fs10.default.existsSync(cjsPath)) {
4215
4477
  const origMsg = err instanceof Error ? err.message : String(err);
4216
4478
  throw new Error(
4217
4479
  `[nasti] Missing dependency "react-refresh". Install it with: npm install react-refresh
@@ -4219,7 +4481,7 @@ Original resolve error: ${origMsg}`
4219
4481
  );
4220
4482
  }
4221
4483
  }
4222
- const cjsSource = import_node_fs9.default.readFileSync(cjsPath, "utf-8");
4484
+ const cjsSource = import_node_fs10.default.readFileSync(cjsPath, "utf-8");
4223
4485
  __refreshRuntimeCache = `// Wrapped react-refresh runtime -> ESM
4224
4486
  const exports = {};
4225
4487
  const module = { exports };
@@ -4390,8 +4652,8 @@ async function transformRequest(url, ctx) {
4390
4652
  let realIdValid = false;
4391
4653
  try {
4392
4654
  if (idParam) {
4393
- realId = import_node_fs9.default.realpathSync(idParam);
4394
- realIdValid = import_node_fs9.default.statSync(realId).isFile() && (realId.includes(`${import_node_path12.default.sep}node_modules${import_node_path12.default.sep}`) || isUnderRoot(realId, config.root));
4655
+ realId = import_node_fs10.default.realpathSync(idParam);
4656
+ realIdValid = import_node_fs10.default.statSync(realId).isFile() && isAllowedDevModulePath(realId, config.root);
4395
4657
  }
4396
4658
  } catch {
4397
4659
  realId = null;
@@ -4458,7 +4720,7 @@ async function transformRequest(url, ctx) {
4458
4720
  }
4459
4721
  }
4460
4722
  const filePath = resolveUrlToFile(url, config.root);
4461
- if (!filePath || !import_node_fs9.default.existsSync(filePath)) return null;
4723
+ if (!filePath || !import_node_fs10.default.existsSync(filePath)) return null;
4462
4724
  const mod = await moduleGraph.ensureEntryFromUrl(url);
4463
4725
  moduleGraph.registerModule(mod, filePath);
4464
4726
  const transformVersion = mod.invalidationVersion;
@@ -4469,7 +4731,7 @@ async function transformRequest(url, ctx) {
4469
4731
  return transformResult2;
4470
4732
  }
4471
4733
  const loaded = await pluginContainer.load(filePath);
4472
- let code = loaded == null ? import_node_fs9.default.readFileSync(filePath, "utf-8") : typeof loaded === "string" ? loaded : loaded.code;
4734
+ let code = loaded == null ? import_node_fs10.default.readFileSync(filePath, "utf-8") : typeof loaded === "string" ? loaded : loaded.code;
4473
4735
  let map = loaded && typeof loaded !== "string" ? loaded.map : void 0;
4474
4736
  const pluginResult = await pluginContainer.transform(code, filePath);
4475
4737
  if (pluginResult) {
@@ -4478,22 +4740,35 @@ async function transformRequest(url, ctx) {
4478
4740
  }
4479
4741
  const stableUrl = cleanReqUrl;
4480
4742
  let wrappedWithRefresh = false;
4481
- if (shouldTransform(filePath)) {
4482
- const isJsx = /\.[jt]sx$/.test(filePath);
4483
- const useRefresh = isJsx && config.framework !== "vue";
4743
+ if (config.framework === "react") {
4744
+ const refreshEnabled = (ctx.environment?.consumer ?? "client") === "client" && config.server.hmr !== false;
4745
+ const useRefresh = refreshEnabled && (!!config.react.compiler || /\.[jt]sx$/.test(filePath));
4746
+ const result = await transformReactCode(filePath, code, {
4747
+ react: config.react,
4748
+ consumer: ctx.environment?.consumer ?? "client",
4749
+ development: true,
4750
+ reactRefresh: useRefresh,
4751
+ sourcemap: true,
4752
+ target: ctx.environment?.options.build.target ?? config.build.target,
4753
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
4754
+ });
4755
+ if (result) {
4756
+ code = result.code;
4757
+ if (result.map) map = JSON.parse(result.map);
4758
+ if (useRefresh) {
4759
+ code = buildReactRefreshWrapper(stableUrl, code);
4760
+ wrappedWithRefresh = true;
4761
+ }
4762
+ }
4763
+ } else if (shouldTransform(filePath)) {
4484
4764
  const result = transformCode(filePath, code, {
4485
4765
  sourcemap: true,
4486
4766
  jsxRuntime: "automatic",
4487
- jsxImportSource: config.framework === "vue" ? "vue" : "react",
4488
- reactRefresh: useRefresh,
4767
+ jsxImportSource: "vue",
4489
4768
  target: ctx.environment?.options.build.target ?? config.build.target
4490
4769
  });
4491
4770
  code = result.code;
4492
4771
  if (result.map) map = JSON.parse(result.map);
4493
- if (useRefresh) {
4494
- code = buildReactRefreshWrapper(stableUrl, code);
4495
- wrappedWithRefresh = true;
4496
- }
4497
4772
  }
4498
4773
  const hotInfo = rewriteHotAcceptDeps(code, config, filePath);
4499
4774
  code = hotInfo.code;
@@ -4527,7 +4802,7 @@ async function loadVirtualModule(spec, ctx) {
4527
4802
  const resolved = await pluginContainer.resolveId(spec);
4528
4803
  if (resolved == null) return null;
4529
4804
  const resolvedId = typeof resolved === "string" ? resolved : resolved.id;
4530
- const looksVirtual = resolvedId.startsWith("\0") || !import_node_fs9.default.existsSync(resolvedId);
4805
+ const looksVirtual = resolvedId.startsWith("\0") || !import_node_fs10.default.existsSync(resolvedId);
4531
4806
  if (!looksVirtual) return null;
4532
4807
  const loadResult = await pluginContainer.load(resolvedId);
4533
4808
  if (loadResult == null) return null;
@@ -4541,7 +4816,7 @@ async function loadVirtualModule(spec, ctx) {
4541
4816
  config.mode,
4542
4817
  ssrDefineOverrides(ctx.environment?.consumer ?? "client")
4543
4818
  ));
4544
- const anchor = import_node_path12.default.join(config.root, "__nasti_virtual__.ts");
4819
+ const anchor = import_node_path13.default.join(config.root, "__nasti_virtual__.ts");
4545
4820
  code = rewriteImports(code, config, anchor);
4546
4821
  return { id: resolvedId, result: { code } };
4547
4822
  }
@@ -4567,7 +4842,7 @@ async function doBundlePackage(entryFile, root) {
4567
4842
  await bundle2.close();
4568
4843
  let code = result.output[0].code;
4569
4844
  code = code.replace(/process\.env\.NODE_ENV/g, '"development"');
4570
- const externalBaseDir = import_node_path12.default.dirname(entryFile);
4845
+ const externalBaseDir = import_node_path13.default.dirname(entryFile);
4571
4846
  code = code.replace(
4572
4847
  /^(import\b[^;'"]*?\bfrom\s+)(['"])([^'"./][^'"]*)(\2)/gm,
4573
4848
  (_, prefix, q, spec) => `${prefix}${q}${externalSpecToModuleUrl(spec, externalBaseDir, root)}${q}`
@@ -4585,16 +4860,16 @@ async function doBundlePackage(entryFile, root) {
4585
4860
  return code;
4586
4861
  }
4587
4862
  async function tryGenerateSubpathShim(entryFile, root) {
4588
- const NM = `${import_node_path12.default.sep}node_modules${import_node_path12.default.sep}`;
4589
- if (!entryFile.includes(NM)) return null;
4863
+ const NM2 = `${import_node_path13.default.sep}node_modules${import_node_path13.default.sep}`;
4864
+ if (!entryFile.includes(NM2)) return null;
4590
4865
  let pkgDir = null;
4591
4866
  let pkgName = null;
4592
- let dir = import_node_path12.default.dirname(entryFile);
4867
+ let dir = import_node_path13.default.dirname(entryFile);
4593
4868
  while (true) {
4594
- const pkgJsonPath = import_node_path12.default.join(dir, "package.json");
4595
- if (import_node_fs9.default.existsSync(pkgJsonPath)) {
4869
+ const pkgJsonPath = import_node_path13.default.join(dir, "package.json");
4870
+ if (import_node_fs10.default.existsSync(pkgJsonPath)) {
4596
4871
  try {
4597
- const pkg = JSON.parse(import_node_fs9.default.readFileSync(pkgJsonPath, "utf-8"));
4872
+ const pkg = JSON.parse(import_node_fs10.default.readFileSync(pkgJsonPath, "utf-8"));
4598
4873
  if (typeof pkg?.name === "string" && pkg.name) {
4599
4874
  pkgDir = dir;
4600
4875
  pkgName = pkg.name;
@@ -4603,16 +4878,16 @@ async function tryGenerateSubpathShim(entryFile, root) {
4603
4878
  } catch {
4604
4879
  }
4605
4880
  }
4606
- const parent = import_node_path12.default.dirname(dir);
4881
+ const parent = import_node_path13.default.dirname(dir);
4607
4882
  if (parent === dir) return null;
4608
4883
  dir = parent;
4609
- if (!dir.includes(NM)) return null;
4884
+ if (!dir.includes(NM2)) return null;
4610
4885
  }
4611
4886
  if (!pkgDir || !pkgName) return null;
4612
- const entryExt = import_node_path12.default.extname(entryFile);
4887
+ const entryExt = import_node_path13.default.extname(entryFile);
4613
4888
  const mainEntry = pickMainEntryByExtension(pkgDir, entryExt);
4614
4889
  if (!mainEntry) return null;
4615
- if (import_node_path12.default.resolve(mainEntry) === import_node_path12.default.resolve(entryFile)) return null;
4890
+ if (import_node_path13.default.resolve(mainEntry) === import_node_path13.default.resolve(entryFile)) return null;
4616
4891
  let mainNs;
4617
4892
  let subNs;
4618
4893
  try {
@@ -4636,7 +4911,7 @@ async function tryGenerateSubpathShim(entryFile, root) {
4636
4911
  if (mainNs["default"] !== subNs["default"]) return null;
4637
4912
  }
4638
4913
  const rootMain = resolveNodeModule(root, pkgName);
4639
- const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir + import_node_path12.default.sep) ? `/@modules/${pkgName}` : `/@modules/${pkgName}?id=${encodeURIComponent(mainEntry)}`;
4914
+ const mainEntryUrl = rootMain && rootMain.startsWith(pkgDir + import_node_path13.default.sep) ? `/@modules/${pkgName}` : `/@modules/${pkgName}?id=${encodeURIComponent(mainEntry)}`;
4640
4915
  const lines = [
4641
4916
  `// Nasti subpath shim \u2192 ${pkgName} (avoid duplicate bundling)`,
4642
4917
  `import * as __pkg from "${mainEntryUrl}";`
@@ -4650,10 +4925,10 @@ async function tryGenerateSubpathShim(entryFile, root) {
4650
4925
  return lines.join("\n") + "\n";
4651
4926
  }
4652
4927
  function pickMainEntryByExtension(pkgDir, preferredExt) {
4653
- const pkgJsonPath = import_node_path12.default.join(pkgDir, "package.json");
4928
+ const pkgJsonPath = import_node_path13.default.join(pkgDir, "package.json");
4654
4929
  let pkg;
4655
4930
  try {
4656
- pkg = JSON.parse(import_node_fs9.default.readFileSync(pkgJsonPath, "utf-8"));
4931
+ pkg = JSON.parse(import_node_fs10.default.readFileSync(pkgJsonPath, "utf-8"));
4657
4932
  } catch {
4658
4933
  return null;
4659
4934
  }
@@ -4672,14 +4947,14 @@ function pickMainEntryByExtension(pkgDir, preferredExt) {
4672
4947
  if (typeof pkg.module === "string") candidates.push(pkg.module);
4673
4948
  if (typeof pkg.main === "string") candidates.push(pkg.main);
4674
4949
  for (const cand of candidates) {
4675
- if (import_node_path12.default.extname(cand) === preferredExt) {
4676
- const full = import_node_path12.default.resolve(pkgDir, cand);
4677
- if (import_node_fs9.default.existsSync(full)) return full;
4950
+ if (import_node_path13.default.extname(cand) === preferredExt) {
4951
+ const full = import_node_path13.default.resolve(pkgDir, cand);
4952
+ if (import_node_fs10.default.existsSync(full)) return full;
4678
4953
  }
4679
4954
  }
4680
4955
  for (const cand of candidates) {
4681
- const full = import_node_path12.default.resolve(pkgDir, cand);
4682
- if (import_node_fs9.default.existsSync(full)) return full;
4956
+ const full = import_node_path13.default.resolve(pkgDir, cand);
4957
+ if (import_node_fs10.default.existsSync(full)) return full;
4683
4958
  }
4684
4959
  return null;
4685
4960
  }
@@ -4704,8 +4979,8 @@ function rewriteExternalRequires(code, baseDir, root) {
4704
4979
  }
4705
4980
  async function injectCjsNamedExports(code, entryFile) {
4706
4981
  try {
4707
- const { createRequire: createRequire7 } = await import("module");
4708
- const req = createRequire7(entryFile);
4982
+ const { createRequire: createRequire8 } = await import("module");
4983
+ const req = createRequire8(entryFile);
4709
4984
  const cjsExports = req(entryFile);
4710
4985
  if (!cjsExports || typeof cjsExports !== "object" && typeof cjsExports !== "function" || Array.isArray(cjsExports)) return code;
4711
4986
  const namedKeys = Object.keys(cjsExports).filter(
@@ -4746,11 +5021,22 @@ function rewriteImports(code, config, filePath, importedUrls, moduleGraph) {
4746
5021
  }
4747
5022
  function createModuleSpecifierResolver(config, filePath) {
4748
5023
  const root = config.root;
4749
- const fileDir = import_node_path12.default.dirname(filePath);
5024
+ const fileDir = import_node_path13.default.dirname(filePath);
4750
5025
  const aliasEntries = Object.entries(config.resolve.alias).sort(
4751
5026
  ([a], [b]) => b.length - a.length
4752
5027
  );
4753
- const toRootUrl = (abs) => "/" + import_node_path12.default.relative(root, abs).replace(/\\/g, "/");
5028
+ const toServableUrl = (abs) => {
5029
+ if (isUnderRoot(abs, root)) {
5030
+ return "/" + import_node_path13.default.relative(root, abs).replace(/\\/g, "/");
5031
+ }
5032
+ for (const pkgRoot of getLinkedPackageRoots(root)) {
5033
+ if (abs === pkgRoot || abs.startsWith(pkgRoot + import_node_path13.default.sep)) {
5034
+ const normalized = abs.replace(/\\/g, "/");
5035
+ return "/@fs/" + (normalized.startsWith("/") ? normalized.slice(1) : normalized);
5036
+ }
5037
+ }
5038
+ return null;
5039
+ };
4754
5040
  return (specifier) => {
4755
5041
  const suffixMatch = specifier.match(/[?#].*$/);
4756
5042
  const suffix = suffixMatch ? suffixMatch[0] : "";
@@ -4759,18 +5045,21 @@ function createModuleSpecifierResolver(config, filePath) {
4759
5045
  if (baseSpec === key || baseSpec.startsWith(key + "/")) {
4760
5046
  const aliasBase = resolveAliasTarget2(value, root);
4761
5047
  const sub = baseSpec.slice(key.length).replace(/^\//, "");
4762
- const target = sub ? import_node_path12.default.join(aliasBase, sub) : aliasBase;
5048
+ const target = sub ? import_node_path13.default.join(aliasBase, sub) : aliasBase;
4763
5049
  const resolved = tryResolveDiskPath(target);
4764
- return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
5050
+ const url = resolved ? toServableUrl(resolved) : null;
5051
+ return url ? url + suffix : specifier;
4765
5052
  }
4766
5053
  }
4767
5054
  if (baseSpec.startsWith("./") || baseSpec.startsWith("../")) {
4768
- const resolved = tryResolveDiskPath(import_node_path12.default.resolve(fileDir, baseSpec));
4769
- return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
5055
+ const resolved = tryResolveDiskPath(import_node_path13.default.resolve(fileDir, baseSpec));
5056
+ const url = resolved ? toServableUrl(resolved) : null;
5057
+ return url ? url + suffix : specifier;
4770
5058
  }
4771
5059
  if (baseSpec.startsWith("/") && !baseSpec.startsWith("/@")) {
4772
- const resolved = tryResolveDiskPath(import_node_path12.default.join(root, baseSpec.replace(/^\//, "")));
4773
- return resolved && isUnderRoot(resolved, root) ? toRootUrl(resolved) + suffix : specifier;
5060
+ const resolved = tryResolveDiskPath(import_node_path13.default.join(root, baseSpec.replace(/^\//, "")));
5061
+ const url = resolved ? toServableUrl(resolved) : null;
5062
+ return url ? url + suffix : specifier;
4774
5063
  }
4775
5064
  if (baseSpec.startsWith("/")) return specifier;
4776
5065
  return `/@modules/${specifier}`;
@@ -4923,28 +5212,24 @@ function maskStringsAndComments(code) {
4923
5212
  return masked.join("");
4924
5213
  }
4925
5214
  function resolveAliasTarget2(value, root) {
4926
- if (import_node_path12.default.isAbsolute(value) && import_node_fs9.default.existsSync(value)) return value;
4927
- if (value.startsWith("/")) return import_node_path12.default.join(root, value.slice(1));
4928
- return import_node_path12.default.resolve(root, value);
5215
+ if (import_node_path13.default.isAbsolute(value) && import_node_fs10.default.existsSync(value)) return value;
5216
+ if (value.startsWith("/")) return import_node_path13.default.join(root, value.slice(1));
5217
+ return import_node_path13.default.resolve(root, value);
4929
5218
  }
4930
5219
  function tryResolveDiskPath(target) {
4931
- if (import_node_fs9.default.existsSync(target) && import_node_fs9.default.statSync(target).isFile()) return target;
5220
+ if (import_node_fs10.default.existsSync(target) && import_node_fs10.default.statSync(target).isFile()) return target;
4932
5221
  for (const ext of RESOLVE_EXTENSIONS) {
4933
5222
  const withExt = target + ext;
4934
- if (import_node_fs9.default.existsSync(withExt) && import_node_fs9.default.statSync(withExt).isFile()) return withExt;
5223
+ if (import_node_fs10.default.existsSync(withExt) && import_node_fs10.default.statSync(withExt).isFile()) return withExt;
4935
5224
  }
4936
- if (import_node_fs9.default.existsSync(target) && import_node_fs9.default.statSync(target).isDirectory()) {
5225
+ if (import_node_fs10.default.existsSync(target) && import_node_fs10.default.statSync(target).isDirectory()) {
4937
5226
  for (const ext of RESOLVE_EXTENSIONS) {
4938
- const idx = import_node_path12.default.join(target, "index" + ext);
4939
- if (import_node_fs9.default.existsSync(idx) && import_node_fs9.default.statSync(idx).isFile()) return idx;
5227
+ const idx = import_node_path13.default.join(target, "index" + ext);
5228
+ if (import_node_fs10.default.existsSync(idx) && import_node_fs10.default.statSync(idx).isFile()) return idx;
4940
5229
  }
4941
5230
  }
4942
5231
  return null;
4943
5232
  }
4944
- function isUnderRoot(abs, root) {
4945
- const rel = import_node_path12.default.relative(root, abs);
4946
- return !!rel && !rel.startsWith("..") && !import_node_path12.default.isAbsolute(rel);
4947
- }
4948
5233
  function appendTimestampQuery(url, timestamp) {
4949
5234
  const hashIndex = url.indexOf("#");
4950
5235
  const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";
@@ -4962,7 +5247,7 @@ function resolveNodeModule(baseDir, moduleName) {
4962
5247
  const resolved = resolveNodeModuleEntry(baseDir, moduleName);
4963
5248
  if (!resolved) return null;
4964
5249
  try {
4965
- return import_node_fs9.default.realpathSync(resolved);
5250
+ return import_node_fs10.default.realpathSync(resolved);
4966
5251
  } catch {
4967
5252
  return resolved;
4968
5253
  }
@@ -4982,21 +5267,21 @@ function resolveNodeModuleEntry(root, moduleName) {
4982
5267
  let pkgDir = null;
4983
5268
  let dir = root;
4984
5269
  for (; ; ) {
4985
- const candidate = import_node_path12.default.join(dir, "node_modules", pkgName);
4986
- if (import_node_fs9.default.existsSync(candidate)) {
5270
+ const candidate = import_node_path13.default.join(dir, "node_modules", pkgName);
5271
+ if (import_node_fs10.default.existsSync(candidate)) {
4987
5272
  pkgDir = candidate;
4988
5273
  break;
4989
5274
  }
4990
- const parent = import_node_path12.default.dirname(dir);
5275
+ const parent = import_node_path13.default.dirname(dir);
4991
5276
  if (parent === dir) break;
4992
5277
  dir = parent;
4993
5278
  }
4994
5279
  if (!pkgDir) return null;
4995
- const pkgJsonPath = import_node_path12.default.join(pkgDir, "package.json");
4996
- if (!import_node_fs9.default.existsSync(pkgJsonPath)) return null;
5280
+ const pkgJsonPath = import_node_path13.default.join(pkgDir, "package.json");
5281
+ if (!import_node_fs10.default.existsSync(pkgJsonPath)) return null;
4997
5282
  let pkg;
4998
5283
  try {
4999
- pkg = JSON.parse(import_node_fs9.default.readFileSync(pkgJsonPath, "utf-8"));
5284
+ pkg = JSON.parse(import_node_fs10.default.readFileSync(pkgJsonPath, "utf-8"));
5000
5285
  } catch {
5001
5286
  return null;
5002
5287
  }
@@ -5009,32 +5294,32 @@ function resolveNodeModuleEntry(root, moduleName) {
5009
5294
  const subDirs = [""];
5010
5295
  for (const field of ["module", "main"]) {
5011
5296
  if (typeof pkg[field] === "string") {
5012
- const dir2 = import_node_path12.default.dirname(pkg[field]);
5297
+ const dir2 = import_node_path13.default.dirname(pkg[field]);
5013
5298
  if (dir2 && dir2 !== "." && !subDirs.includes(dir2)) subDirs.push(dir2);
5014
5299
  }
5015
5300
  }
5016
5301
  for (const dir2 of subDirs) {
5017
- const direct = import_node_path12.default.join(pkgDir, dir2, subpath);
5018
- if (import_node_fs9.default.existsSync(direct) && import_node_fs9.default.statSync(direct).isFile()) return direct;
5302
+ const direct = import_node_path13.default.join(pkgDir, dir2, subpath);
5303
+ if (import_node_fs10.default.existsSync(direct) && import_node_fs10.default.statSync(direct).isFile()) return direct;
5019
5304
  for (const ext of RESOLVE_EXTENSIONS) {
5020
- if (import_node_fs9.default.existsSync(direct + ext)) return direct + ext;
5305
+ if (import_node_fs10.default.existsSync(direct + ext)) return direct + ext;
5021
5306
  }
5022
5307
  }
5023
5308
  return null;
5024
5309
  }
5025
5310
  for (const field of ["module", "jsnext:main", "jsnext", "main"]) {
5026
5311
  if (typeof pkg[field] === "string") {
5027
- const entry = import_node_path12.default.join(pkgDir, pkg[field]);
5028
- if (import_node_fs9.default.existsSync(entry)) return entry;
5312
+ const entry = import_node_path13.default.join(pkgDir, pkg[field]);
5313
+ if (import_node_fs10.default.existsSync(entry)) return entry;
5029
5314
  }
5030
5315
  }
5031
- const indexFallback = import_node_path12.default.join(pkgDir, "index.js");
5032
- if (import_node_fs9.default.existsSync(indexFallback)) return indexFallback;
5316
+ const indexFallback = import_node_path13.default.join(pkgDir, "index.js");
5317
+ if (import_node_fs10.default.existsSync(indexFallback)) return indexFallback;
5033
5318
  return null;
5034
5319
  }
5035
5320
  function resolvePackageExports(exports2, key, pkgDir) {
5036
5321
  if (typeof exports2 === "string") {
5037
- return key === "." ? import_node_path12.default.join(pkgDir, exports2) : null;
5322
+ return key === "." ? import_node_path13.default.join(pkgDir, exports2) : null;
5038
5323
  }
5039
5324
  const entry = exports2[key];
5040
5325
  if (entry === void 0) {
@@ -5046,7 +5331,7 @@ function resolvePackageExports(exports2, key, pkgDir) {
5046
5331
  return resolveExportValue(entry, pkgDir);
5047
5332
  }
5048
5333
  function resolveExportValue(value, pkgDir) {
5049
- if (typeof value === "string") return import_node_path12.default.join(pkgDir, value);
5334
+ if (typeof value === "string") return import_node_path13.default.join(pkgDir, value);
5050
5335
  if (Array.isArray(value)) {
5051
5336
  for (const item of value) {
5052
5337
  const r = resolveExportValue(item, pkgDir);
@@ -5065,35 +5350,54 @@ function resolveExportValue(value, pkgDir) {
5065
5350
  return null;
5066
5351
  }
5067
5352
  function resolveUrlToFile(url, root) {
5068
- const cleanUrl = url.split("?")[0];
5353
+ const cleanUrl = url.split(/[?#]/)[0];
5069
5354
  if (cleanUrl.startsWith("/@modules/")) {
5070
5355
  const moduleName = cleanUrl.slice("/@modules/".length);
5071
5356
  return resolveNodeModule(root, moduleName);
5072
5357
  }
5073
- const filePath = import_node_path12.default.resolve(root, cleanUrl.replace(/^\//, ""));
5074
- if (import_node_fs9.default.existsSync(filePath) && import_node_fs9.default.statSync(filePath).isFile()) {
5358
+ if (cleanUrl.startsWith("/@fs/")) {
5359
+ let abs = cleanUrl.slice("/@fs/".length);
5360
+ if (process.platform === "win32") {
5361
+ abs = abs.replace(/\//g, import_node_path13.default.sep);
5362
+ } else if (!abs.startsWith("/")) {
5363
+ abs = "/" + abs;
5364
+ }
5365
+ try {
5366
+ const real = import_node_fs10.default.realpathSync(abs);
5367
+ if (import_node_fs10.default.statSync(real).isFile() && isAllowedDevModulePath(real, root)) return real;
5368
+ } catch {
5369
+ return null;
5370
+ }
5371
+ return null;
5372
+ }
5373
+ const filePath = import_node_path13.default.resolve(root, cleanUrl.replace(/^\//, ""));
5374
+ if (import_node_fs10.default.existsSync(filePath) && import_node_fs10.default.statSync(filePath).isFile()) {
5075
5375
  return filePath;
5076
5376
  }
5077
5377
  for (const ext of RESOLVE_EXTENSIONS) {
5078
5378
  const withExt = filePath + ext;
5079
- if (import_node_fs9.default.existsSync(withExt)) return withExt;
5379
+ if (import_node_fs10.default.existsSync(withExt)) return withExt;
5080
5380
  }
5081
5381
  for (const ext of RESOLVE_EXTENSIONS) {
5082
- const indexFile = import_node_path12.default.join(filePath, "index" + ext);
5083
- if (import_node_fs9.default.existsSync(indexFile)) return indexFile;
5382
+ const indexFile = import_node_path13.default.join(filePath, "index" + ext);
5383
+ if (import_node_fs10.default.existsSync(indexFile)) return indexFile;
5084
5384
  }
5085
5385
  return null;
5086
5386
  }
5087
5387
  function isModuleRequest(url, destination) {
5088
- const cleanUrl = url.split("?")[0];
5388
+ const cleanUrl = url.split(/[?#]/)[0];
5089
5389
  if (/\.(ts|tsx|jsx|js|mjs|vue|css|json)$/.test(cleanUrl)) return true;
5090
5390
  if (cleanUrl.startsWith("/@modules/")) return true;
5391
+ if (cleanUrl.startsWith("/@fs/")) return true;
5091
5392
  if (isAssetFile(cleanUrl)) {
5092
- const query = url.includes("?") ? url.slice(url.indexOf("?") + 1) : "";
5393
+ const qIdx = url.indexOf("?");
5394
+ const hIdx = url.indexOf("#");
5395
+ const queryEnd = hIdx === -1 ? url.length : hIdx;
5396
+ const query = qIdx === -1 || qIdx > queryEnd ? "" : url.slice(qIdx + 1, queryEnd);
5093
5397
  const isExplicitAssetModule = /(?:^|&)(?:url|raw)(?:&|$)/.test(query);
5094
5398
  return isExplicitAssetModule || destination === "script";
5095
5399
  }
5096
- if (!import_node_path12.default.extname(cleanUrl)) return true;
5400
+ if (!import_node_path13.default.extname(cleanUrl)) return true;
5097
5401
  return false;
5098
5402
  }
5099
5403
  function getHmrClientCode() {
@@ -5323,13 +5627,13 @@ function clearCustomListeners(ownerPath) {
5323
5627
  }
5324
5628
  `;
5325
5629
  }
5326
- var import_node_path12, import_node_fs9, import_node_module5, import_node_url3, import_picocolors6, import_meta, __dirname_esm, __require, __refreshRuntimeCache, REACT_REFRESH_BOUNDARY_HELPERS, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
5630
+ var import_node_path13, import_node_fs10, import_node_module6, import_node_url3, import_picocolors6, import_meta, __dirname_esm, __require, __refreshRuntimeCache, REACT_REFRESH_BOUNDARY_HELPERS, REACT_REFRESH_GLOBAL_PREAMBLE, esmBundleCache, VALID_IDENT, RESOLVE_EXTENSIONS, ESM_CONDITIONS;
5327
5631
  var init_middleware = __esm({
5328
5632
  "src/server/middleware.ts"() {
5329
5633
  "use strict";
5330
- import_node_path12 = __toESM(require("path"), 1);
5331
- import_node_fs9 = __toESM(require("fs"), 1);
5332
- import_node_module5 = require("module");
5634
+ import_node_path13 = __toESM(require("path"), 1);
5635
+ import_node_fs10 = __toESM(require("fs"), 1);
5636
+ import_node_module6 = require("module");
5333
5637
  import_node_url3 = require("url");
5334
5638
  import_picocolors6 = __toESM(require("picocolors"), 1);
5335
5639
  init_transformer();
@@ -5337,9 +5641,10 @@ var init_middleware = __esm({
5337
5641
  init_env();
5338
5642
  init_url();
5339
5643
  init_assets();
5644
+ init_fs_allow();
5340
5645
  import_meta = {};
5341
- __dirname_esm = import_node_path12.default.dirname((0, import_node_url3.fileURLToPath)(import_meta.url));
5342
- __require = (0, import_node_module5.createRequire)(import_meta.url);
5646
+ __dirname_esm = import_node_path13.default.dirname((0, import_node_url3.fileURLToPath)(import_meta.url));
5647
+ __require = (0, import_node_module6.createRequire)(import_meta.url);
5343
5648
  __refreshRuntimeCache = null;
5344
5649
  REACT_REFRESH_BOUNDARY_HELPERS = `
5345
5650
  function __nastiIsPlainObject(obj) {
@@ -5427,9 +5732,26 @@ async function handleFileChange(file, server, environmentName = "client", timest
5427
5732
  }
5428
5733
  const moduleGraph = environment.moduleGraph;
5429
5734
  const logger = config.logger;
5430
- const relativePath = "/" + import_node_path13.default.relative(config.root, file);
5431
- const shortFile = import_node_path13.default.relative(config.root, file);
5432
- const mods = moduleGraph.getModulesByFile(file);
5735
+ const relativePath = "/" + import_node_path14.default.relative(config.root, file);
5736
+ const shortFile = import_node_path14.default.relative(config.root, file);
5737
+ let mods = moduleGraph.getModulesByFile(file);
5738
+ if (!mods || mods.size === 0) {
5739
+ try {
5740
+ const real = import_node_fs11.default.realpathSync(file);
5741
+ if (real !== file) mods = moduleGraph.getModulesByFile(real);
5742
+ if (mods && mods.size > 0) file = real;
5743
+ } catch {
5744
+ }
5745
+ }
5746
+ if (!mods || mods.size === 0) {
5747
+ const packageRoot = findNearestPackageRoot(file);
5748
+ if (packageRoot && getLinkedPackageRoots(config.root).some(
5749
+ (r) => packageRoot === r || packageRoot.startsWith(r + import_node_path14.default.sep)
5750
+ )) {
5751
+ const under = moduleGraph.getModulesWithFileUnder(packageRoot);
5752
+ if (under.size > 0) mods = under;
5753
+ }
5754
+ }
5433
5755
  if (!mods || mods.size === 0) {
5434
5756
  return null;
5435
5757
  }
@@ -5444,7 +5766,7 @@ async function handleFileChange(file, server, environmentName = "client", timest
5444
5766
  file,
5445
5767
  timestamp,
5446
5768
  modules: [mod],
5447
- read: () => import_node_fs10.default.readFileSync(file, "utf-8"),
5769
+ read: () => import_node_fs11.default.readFileSync(file, "utf-8"),
5448
5770
  server,
5449
5771
  environment
5450
5772
  };
@@ -5505,13 +5827,14 @@ async function handleFileChange(file, server, environmentName = "client", timest
5505
5827
  fullReload
5506
5828
  };
5507
5829
  }
5508
- var import_node_path13, import_node_fs10, import_picocolors7;
5830
+ var import_node_path14, import_node_fs11, import_picocolors7;
5509
5831
  var init_hmr = __esm({
5510
5832
  "src/server/hmr.ts"() {
5511
5833
  "use strict";
5512
- import_node_path13 = __toESM(require("path"), 1);
5513
- import_node_fs10 = __toESM(require("fs"), 1);
5834
+ import_node_path14 = __toESM(require("path"), 1);
5835
+ import_node_fs11 = __toESM(require("fs"), 1);
5514
5836
  import_picocolors7 = __toESM(require("picocolors"), 1);
5837
+ init_fs_allow();
5515
5838
  }
5516
5839
  });
5517
5840
 
@@ -5529,19 +5852,19 @@ function createModuleRunner(environment) {
5529
5852
  }
5530
5853
  return new NastiModuleRunner(environment);
5531
5854
  }
5532
- var import_node_path14, import_node_fs11, import_node_module6, import_node_url4, debug6, NODE_BUILTINS3, NastiModuleRunner, AsyncFunction;
5855
+ var import_node_path15, import_node_fs12, import_node_module7, import_node_url4, debug6, NODE_BUILTINS3, NastiModuleRunner, AsyncFunction;
5533
5856
  var init_runnable_environment = __esm({
5534
5857
  "src/server/runnable-environment.ts"() {
5535
5858
  "use strict";
5536
- import_node_path14 = __toESM(require("path"), 1);
5537
- import_node_fs11 = __toESM(require("fs"), 1);
5538
- import_node_module6 = require("module");
5859
+ import_node_path15 = __toESM(require("path"), 1);
5860
+ import_node_fs12 = __toESM(require("fs"), 1);
5861
+ import_node_module7 = require("module");
5539
5862
  import_node_url4 = require("url");
5540
5863
  init_transformer();
5541
5864
  init_env();
5542
5865
  init_debug();
5543
5866
  debug6 = createDebugger("nasti:ssr");
5544
- NODE_BUILTINS3 = /* @__PURE__ */ new Set([...import_node_module6.builtinModules, ...import_node_module6.builtinModules.map((m) => `node:${m}`)]);
5867
+ NODE_BUILTINS3 = /* @__PURE__ */ new Set([...import_node_module7.builtinModules, ...import_node_module7.builtinModules.map((m) => `node:${m}`)]);
5545
5868
  NastiModuleRunner = class {
5546
5869
  environment;
5547
5870
  config;
@@ -5556,10 +5879,10 @@ var init_runnable_environment = __esm({
5556
5879
  this.config.mode,
5557
5880
  ssrDefineOverrides(environment.consumer)
5558
5881
  );
5559
- this.require = (0, import_node_module6.createRequire)(import_node_path14.default.join(this.config.root, "package.json"));
5882
+ this.require = (0, import_node_module7.createRequire)(import_node_path15.default.join(this.config.root, "package.json"));
5560
5883
  const handlers = {
5561
5884
  fetchModule: async (id, importer) => this.fetchModule(id, importer),
5562
- getBuiltins: () => [/^node:/, ...import_node_module6.builtinModules]
5885
+ getBuiltins: () => [/^node:/, ...import_node_module7.builtinModules]
5563
5886
  };
5564
5887
  environment.hot.setInvokeHandler?.(handlers);
5565
5888
  }
@@ -5580,9 +5903,9 @@ var init_runnable_environment = __esm({
5580
5903
  this.cache.clear();
5581
5904
  }
5582
5905
  resolveToId(rawUrl) {
5583
- if (import_node_path14.default.isAbsolute(rawUrl) && import_node_fs11.default.existsSync(rawUrl.split("?")[0])) return rawUrl;
5906
+ if (import_node_path15.default.isAbsolute(rawUrl) && import_node_fs12.default.existsSync(rawUrl.split("?")[0])) return rawUrl;
5584
5907
  const clean = rawUrl.replace(/^\//, "");
5585
- return import_node_path14.default.resolve(this.config.root, clean);
5908
+ return import_node_path15.default.resolve(this.config.root, clean);
5586
5909
  }
5587
5910
  /**
5588
5911
  * fetchModule(invoke 契约方法):环境管线产出 runner 可执行代码。
@@ -5591,14 +5914,14 @@ var init_runnable_environment = __esm({
5591
5914
  */
5592
5915
  async fetchModule(id, importer) {
5593
5916
  if (NODE_BUILTINS3.has(id)) return { externalize: id };
5594
- if (!id.startsWith(".") && !import_node_path14.default.isAbsolute(id) && !id.startsWith("\0")) {
5917
+ if (!id.startsWith(".") && !import_node_path15.default.isAbsolute(id) && !id.startsWith("\0")) {
5595
5918
  return { externalize: id };
5596
5919
  }
5597
5920
  const container = this.environment.pluginContainer;
5598
5921
  let resolvedId = id;
5599
5922
  if (id.startsWith(".") && importer) {
5600
5923
  const resolved = await container.resolveId(id, importer);
5601
- resolvedId = resolved ? typeof resolved === "string" ? resolved : resolved.id : import_node_path14.default.resolve(import_node_path14.default.dirname(importer.split("?")[0]), id);
5924
+ resolvedId = resolved ? typeof resolved === "string" ? resolved : resolved.id : import_node_path15.default.resolve(import_node_path15.default.dirname(importer.split("?")[0]), id);
5602
5925
  }
5603
5926
  resolvedId = this.completeExtension(resolvedId);
5604
5927
  const cleanId = resolvedId.split("?")[0];
@@ -5606,8 +5929,8 @@ var init_runnable_environment = __esm({
5606
5929
  const loaded = await container.load(resolvedId);
5607
5930
  if (loaded != null) {
5608
5931
  code = typeof loaded === "string" ? loaded : loaded.code;
5609
- } else if (import_node_fs11.default.existsSync(cleanId)) {
5610
- code = import_node_fs11.default.readFileSync(cleanId, "utf-8");
5932
+ } else if (import_node_fs12.default.existsSync(cleanId)) {
5933
+ code = import_node_fs12.default.readFileSync(cleanId, "utf-8");
5611
5934
  } else {
5612
5935
  throw new Error(`[nasti:ssr] cannot load module: ${resolvedId}`);
5613
5936
  }
@@ -5615,12 +5938,32 @@ var init_runnable_environment = __esm({
5615
5938
  if (transformed != null) {
5616
5939
  code = typeof transformed === "string" ? transformed : transformed.code;
5617
5940
  }
5618
- if (shouldTransform(cleanId)) {
5941
+ if (this.config.framework === "react") {
5942
+ const result = await transformReactCode(cleanId, code, {
5943
+ react: this.config.react,
5944
+ consumer: this.environment.consumer,
5945
+ development: true,
5946
+ sourcemap: false,
5947
+ target: this.environment.options.build.target,
5948
+ onWarning: (message) => this.config.logger.warn(`[nasti:react] ${message}`)
5949
+ });
5950
+ if (result) {
5951
+ code = result.code;
5952
+ } else if (shouldTransform(cleanId)) {
5953
+ const fallback = transformCode(cleanId, code, {
5954
+ sourcemap: false,
5955
+ jsxRuntime: this.config.react.jsxRuntime,
5956
+ jsxImportSource: this.config.react.jsxImportSource,
5957
+ target: this.environment.options.build.target
5958
+ });
5959
+ code = fallback.code;
5960
+ }
5961
+ } else if (shouldTransform(cleanId)) {
5619
5962
  const result = transformCode(cleanId, code, {
5620
5963
  sourcemap: false,
5621
5964
  target: this.environment.options.build.target,
5622
5965
  jsxRuntime: "automatic",
5623
- jsxImportSource: this.config.framework === "vue" ? "vue" : "react"
5966
+ jsxImportSource: "vue"
5624
5967
  });
5625
5968
  code = result.code;
5626
5969
  }
@@ -5641,19 +5984,19 @@ var init_runnable_environment = __esm({
5641
5984
  completeExtension(id) {
5642
5985
  const clean = id.split("?")[0];
5643
5986
  const query = id.includes("?") ? id.slice(id.indexOf("?")) : "";
5644
- if (import_node_fs11.default.existsSync(clean) && import_node_fs11.default.statSync(clean).isFile()) return id;
5987
+ if (import_node_fs12.default.existsSync(clean) && import_node_fs12.default.statSync(clean).isFile()) return id;
5645
5988
  const jsMatch = clean.match(/^(.*)\.([mc]?)jsx?$/);
5646
5989
  if (jsMatch) {
5647
5990
  for (const tsExt of [`.${jsMatch[2]}ts`, `.${jsMatch[2]}tsx`]) {
5648
- if (import_node_fs11.default.existsSync(jsMatch[1] + tsExt)) return jsMatch[1] + tsExt + query;
5991
+ if (import_node_fs12.default.existsSync(jsMatch[1] + tsExt)) return jsMatch[1] + tsExt + query;
5649
5992
  }
5650
5993
  }
5651
5994
  for (const ext of this.config.resolve.extensions) {
5652
- if (import_node_fs11.default.existsSync(clean + ext)) return clean + ext + query;
5995
+ if (import_node_fs12.default.existsSync(clean + ext)) return clean + ext + query;
5653
5996
  }
5654
5997
  for (const ext of this.config.resolve.extensions) {
5655
- const indexPath = import_node_path14.default.join(clean, `index${ext}`);
5656
- if (import_node_fs11.default.existsSync(indexPath)) return indexPath;
5998
+ const indexPath = import_node_path15.default.join(clean, `index${ext}`);
5999
+ if (import_node_fs12.default.existsSync(indexPath)) return indexPath;
5657
6000
  }
5658
6001
  return id;
5659
6002
  }
@@ -5680,10 +6023,10 @@ var init_runnable_environment = __esm({
5680
6023
  return;
5681
6024
  }
5682
6025
  const ssrImport = async (dep) => {
5683
- if (NODE_BUILTINS3.has(dep) || !dep.startsWith(".") && !import_node_path14.default.isAbsolute(dep) && !dep.startsWith("\0")) {
6026
+ if (NODE_BUILTINS3.has(dep) || !dep.startsWith(".") && !import_node_path15.default.isAbsolute(dep) && !dep.startsWith("\0")) {
5684
6027
  return this.importExternal(dep);
5685
6028
  }
5686
- const depId = dep.startsWith(".") ? this.completeExtension(import_node_path14.default.resolve(import_node_path14.default.dirname(fetched.id.split("?")[0]), dep)) : this.completeExtension(dep);
6029
+ const depId = dep.startsWith(".") ? this.completeExtension(import_node_path15.default.resolve(import_node_path15.default.dirname(fetched.id.split("?")[0]), dep)) : this.completeExtension(dep);
5687
6030
  return this.instantiate(depId);
5688
6031
  };
5689
6032
  const ssrExportAll = (sourceModule) => {
@@ -5715,7 +6058,7 @@ var init_runnable_environment = __esm({
5715
6058
  }
5716
6059
  async importExternal(spec) {
5717
6060
  try {
5718
- return await (spec.startsWith("node:") || !import_node_path14.default.isAbsolute(spec) ? import(this.resolveExternalSpecifier(spec)) : import((0, import_node_url4.pathToFileURL)(spec).href));
6061
+ return await (spec.startsWith("node:") || !import_node_path15.default.isAbsolute(spec) ? import(this.resolveExternalSpecifier(spec)) : import((0, import_node_url4.pathToFileURL)(spec).href));
5719
6062
  } catch (err) {
5720
6063
  throw new Error(`[nasti:ssr] failed to import external "${spec}": ${err.message}`);
5721
6064
  }
@@ -5767,11 +6110,11 @@ async function createBundledDevServer(opts) {
5767
6110
  const patches = new MemoryFiles();
5768
6111
  const entryFileNames = /* @__PURE__ */ new Map();
5769
6112
  const bundledClients = /* @__PURE__ */ new Map();
5770
- const useReactRefresh = config.framework !== "vue" && refreshWrapperFn != null;
6113
+ const useReactRefresh = config.framework === "react" && config.server.hmr !== false && refreshWrapperFn != null;
5771
6114
  const rolldownPlugins = [
5772
6115
  ...useReactRefresh ? [
5773
6116
  createReactRefreshRuntimePlugin(entryPoints),
5774
- createBundledOxcRefreshPlugin()
6117
+ createBundledOxcRefreshPlugin(config)
5775
6118
  ] : [],
5776
6119
  ...stripCatchAllLoad(toRolldownPlugins(clientEnv.plugins, clientEnv)),
5777
6120
  ...useReactRefresh ? [
@@ -5822,7 +6165,7 @@ async function createBundledDevServer(opts) {
5822
6165
  }
5823
6166
  const url = `/${patchPath}`;
5824
6167
  logger.info(
5825
- import_picocolors8.default.green("hmr update ") + import_picocolors8.default.dim(changedFiles.map((f) => import_node_path15.default.relative(config.root, f)).join(", ")),
6168
+ import_picocolors8.default.green("hmr update ") + import_picocolors8.default.dim(changedFiles.map((f) => import_node_path16.default.relative(config.root, f)).join(", ")),
5826
6169
  { timestamp: true }
5827
6170
  );
5828
6171
  sendTo(clientId, { type: "hmr:update", path: url, url });
@@ -5977,7 +6320,7 @@ async function createBundledDevServer(opts) {
5977
6320
  return;
5978
6321
  }
5979
6322
  res.setHeader("ETag", hit.etag);
5980
- res.setHeader("Content-Type", MIME_TYPES[import_node_path15.default.extname(fileName)] ?? "application/octet-stream");
6323
+ res.setHeader("Content-Type", MIME_TYPES[import_node_path16.default.extname(fileName)] ?? "application/octet-stream");
5981
6324
  res.setHeader("Cache-Control", "no-cache");
5982
6325
  res.once("finish", () => {
5983
6326
  void engine.notifyPayloadDelivered(fileName).catch(
@@ -6018,7 +6361,7 @@ function stripCatchAllLoad(plugins) {
6018
6361
  );
6019
6362
  }
6020
6363
  function createReactRefreshRuntimePlugin(entryPoints) {
6021
- const entryIds = new Set(entryPoints.map((p) => import_node_path15.default.resolve(p)));
6364
+ const entryIds = new Set(entryPoints.map((p) => import_node_path16.default.resolve(p)));
6022
6365
  return {
6023
6366
  name: "nasti:bundled-react-refresh",
6024
6367
  resolveId(source) {
@@ -6036,24 +6379,27 @@ function createReactRefreshRuntimePlugin(entryPoints) {
6036
6379
  return null;
6037
6380
  },
6038
6381
  transform(code, id) {
6039
- if (!entryIds.has(import_node_path15.default.resolve(id.split("?")[0]))) return null;
6382
+ if (!entryIds.has(import_node_path16.default.resolve(id.split("?")[0]))) return null;
6040
6383
  return { code: `import ${JSON.stringify(PREAMBLE_SPEC)};
6041
6384
  ${code}`, map: null };
6042
6385
  }
6043
6386
  };
6044
6387
  }
6045
- function createBundledOxcRefreshPlugin() {
6388
+ function createBundledOxcRefreshPlugin(config) {
6046
6389
  return {
6047
6390
  name: "nasti:bundled-oxc-refresh",
6048
- transform(code, id) {
6391
+ async transform(code, id) {
6049
6392
  const clean = id.split("?")[0];
6050
- if (!/\.[jt]sx$/.test(clean) || clean.includes("/node_modules/")) return null;
6051
- const result = transformCode(clean, code, {
6393
+ const result = await transformReactCode(clean, code, {
6394
+ react: config.react,
6395
+ consumer: "client",
6396
+ development: true,
6397
+ reactRefresh: true,
6052
6398
  sourcemap: true,
6053
- jsxRuntime: "automatic",
6054
- jsxImportSource: "react",
6055
- reactRefresh: true
6399
+ target: config.build.target,
6400
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
6056
6401
  });
6402
+ if (!result) return null;
6057
6403
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
6058
6404
  }
6059
6405
  };
@@ -6083,11 +6429,11 @@ async function renderBundledIndexHtml(html, config, entryFileNames) {
6083
6429
  }
6084
6430
  return processed;
6085
6431
  }
6086
- var import_node_path15, import_node_crypto3, import_ws2, import_picocolors8, debug7, MIME_TYPES, MemoryFiles, PREAMBLE_SPEC, RESOLVED_PREAMBLE_ID, REFRESH_RUNTIME_URL, BUNDLED_PREAMBLE_CODE, WRAPPER_RUNTIME_HELPERS;
6432
+ var import_node_path16, import_node_crypto3, import_ws2, import_picocolors8, debug7, MIME_TYPES, MemoryFiles, PREAMBLE_SPEC, RESOLVED_PREAMBLE_ID, REFRESH_RUNTIME_URL, BUNDLED_PREAMBLE_CODE, WRAPPER_RUNTIME_HELPERS;
6087
6433
  var init_dev_engine = __esm({
6088
6434
  "src/server/bundled/dev-engine.ts"() {
6089
6435
  "use strict";
6090
- import_node_path15 = __toESM(require("path"), 1);
6436
+ import_node_path16 = __toESM(require("path"), 1);
6091
6437
  import_node_crypto3 = __toESM(require("crypto"), 1);
6092
6438
  import_ws2 = require("ws");
6093
6439
  import_picocolors8 = __toESM(require("picocolors"), 1);
@@ -6297,20 +6643,39 @@ async function createServer(inlineConfig = {}) {
6297
6643
  app.use(bundledServer.middleware);
6298
6644
  }
6299
6645
  const ignoredSegments = /* @__PURE__ */ new Set(["node_modules", ".git", ".nasti"]);
6300
- const outDirAbs = import_node_path16.default.resolve(config.root, config.build.outDir);
6301
- const watcher = (0, import_chokidar.watch)(config.root, {
6646
+ const outDirAbs = import_node_path17.default.resolve(config.root, config.build.outDir);
6647
+ const linkedPackageRoots = getLinkedPackageRoots(config.root).filter(
6648
+ (r) => r !== config.root && !isUnderRoot(config.root, r)
6649
+ );
6650
+ const watchTargets = [config.root, ...linkedPackageRoots];
6651
+ const watcher = (0, import_chokidar.watch)(watchTargets, {
6302
6652
  ignored: (filePath) => {
6303
- if (filePath === config.root) return false;
6304
- if (filePath === outDirAbs || filePath.startsWith(outDirAbs + import_node_path16.default.sep)) return true;
6305
- const rel = import_node_path16.default.relative(config.root, filePath);
6306
- if (!rel || rel.startsWith("..") || import_node_path16.default.isAbsolute(rel)) return false;
6307
- for (const seg of rel.split(import_node_path16.default.sep)) {
6308
- if (ignoredSegments.has(seg)) return true;
6653
+ if (filePath === outDirAbs || filePath.startsWith(outDirAbs + import_node_path17.default.sep)) return true;
6654
+ for (const watchRoot of watchTargets) {
6655
+ if (filePath === watchRoot) return false;
6656
+ const rel = import_node_path17.default.relative(watchRoot, filePath);
6657
+ if (!rel || rel.startsWith("..") || import_node_path17.default.isAbsolute(rel)) continue;
6658
+ for (const seg of rel.split(import_node_path17.default.sep)) {
6659
+ if (ignoredSegments.has(seg)) return true;
6660
+ }
6661
+ return false;
6309
6662
  }
6310
6663
  return false;
6311
6664
  },
6312
6665
  ignoreInitial: true
6313
6666
  });
6667
+ await new Promise((resolve, reject) => {
6668
+ const onReady = () => {
6669
+ watcher.off("error", onError);
6670
+ resolve();
6671
+ };
6672
+ const onError = (err) => {
6673
+ watcher.off("ready", onReady);
6674
+ reject(err);
6675
+ };
6676
+ watcher.once("ready", onReady);
6677
+ watcher.once("error", onError);
6678
+ });
6314
6679
  let server;
6315
6680
  const environmentServices = {};
6316
6681
  let environmentDriversStarted = false;
@@ -6422,16 +6787,25 @@ async function createServer(inlineConfig = {}) {
6422
6787
  });
6423
6788
  };
6424
6789
  watcher.on("change", (file) => {
6790
+ if (file.includes(`${import_node_path17.default.sep}node_modules${import_node_path17.default.sep}`) || file.endsWith(`${import_node_path17.default.sep}node_modules`)) {
6791
+ clearLinkedPackageRootsCache();
6792
+ }
6425
6793
  ssrRunner?.invalidateFile(file);
6426
6794
  queueClientEnvironmentUpdate(file);
6427
6795
  notifyEnvironmentDrivers(file, "change");
6428
6796
  });
6429
6797
  watcher.on("add", (file) => {
6798
+ if (file.includes(`${import_node_path17.default.sep}node_modules${import_node_path17.default.sep}`) || file.endsWith(`${import_node_path17.default.sep}node_modules`)) {
6799
+ clearLinkedPackageRootsCache();
6800
+ }
6430
6801
  ssrRunner?.invalidateFile(file);
6431
6802
  queueClientEnvironmentUpdate(file);
6432
6803
  notifyEnvironmentDrivers(file, "add");
6433
6804
  });
6434
6805
  watcher.on("unlink", (file) => {
6806
+ if (file.includes(`${import_node_path17.default.sep}node_modules${import_node_path17.default.sep}`) || file.endsWith(`${import_node_path17.default.sep}node_modules`)) {
6807
+ clearLinkedPackageRootsCache();
6808
+ }
6435
6809
  ssrRunner?.invalidateFile(file);
6436
6810
  notifyEnvironmentDrivers(file, "unlink");
6437
6811
  });
@@ -6461,7 +6835,7 @@ async function createServer(inlineConfig = {}) {
6461
6835
  const readyIn = Math.ceil(performance.now() - startTime);
6462
6836
  logger.info(
6463
6837
  `
6464
- ${import_picocolors9.default.cyan(import_picocolors9.default.bold("NASTI"))} ${import_picocolors9.default.cyan(`v${"2.4.3"}`)} ${import_picocolors9.default.dim("ready in")} ${import_picocolors9.default.bold(readyIn)} ${import_picocolors9.default.dim("ms")}
6838
+ ${import_picocolors9.default.cyan(import_picocolors9.default.bold("NASTI"))} ${import_picocolors9.default.cyan(`v${"2.5.0"}`)} ${import_picocolors9.default.dim("ready in")} ${import_picocolors9.default.bold(readyIn)} ${import_picocolors9.default.dim("ms")}
6465
6839
  `
6466
6840
  );
6467
6841
  printServerUrls(
@@ -6558,7 +6932,7 @@ async function createServer(inlineConfig = {}) {
6558
6932
  throw error;
6559
6933
  }
6560
6934
  app.use(transformMiddleware(transformContexts.get("client")));
6561
- const publicDir = import_node_path16.default.resolve(config.root, "public");
6935
+ const publicDir = import_node_path17.default.resolve(config.root, "public");
6562
6936
  app.use((0, import_sirv.default)(publicDir, { dev: true, etag: true }));
6563
6937
  app.use((0, import_sirv.default)(config.root, { dev: true, etag: true }));
6564
6938
  const postMiddlewares = [];
@@ -6584,12 +6958,12 @@ function getNetworkAddress() {
6584
6958
  }
6585
6959
  return "localhost";
6586
6960
  }
6587
- var import_node_http, import_node_path16, import_node_os, import_connect, import_sirv, import_chokidar, import_picocolors9;
6961
+ var import_node_http, import_node_path17, import_node_os, import_connect, import_sirv, import_chokidar, import_picocolors9;
6588
6962
  var init_server = __esm({
6589
6963
  "src/server/index.ts"() {
6590
6964
  "use strict";
6591
6965
  import_node_http = __toESM(require("http"), 1);
6592
- import_node_path16 = __toESM(require("path"), 1);
6966
+ import_node_path17 = __toESM(require("path"), 1);
6593
6967
  import_node_os = __toESM(require("os"), 1);
6594
6968
  import_connect = __toESM(require("connect"), 1);
6595
6969
  import_sirv = __toESM(require("sirv"), 1);
@@ -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
 
@@ -6631,6 +7006,7 @@ __export(src_exports, {
6631
7006
  printServerUrls: () => printServerUrls,
6632
7007
  resolveConfig: () => resolveConfig,
6633
7008
  resolveEnvironmentPlugins: () => resolveEnvironmentPlugins,
7009
+ rsc: () => rsc,
6634
7010
  ssrDefineOverrides: () => ssrDefineOverrides,
6635
7011
  startElectronDev: () => startElectronDev
6636
7012
  });
@@ -6641,6 +7017,7 @@ init_build();
6641
7017
  // src/build/electron.ts
6642
7018
  var import_node_path11 = __toESM(require("path"), 1);
6643
7019
  var import_node_fs8 = __toESM(require("fs"), 1);
7020
+ var import_node_module5 = require("module");
6644
7021
  var import_rolldown2 = require("rolldown");
6645
7022
  var import_picocolors5 = __toESM(require("picocolors"), 1);
6646
7023
  init_config();
@@ -6686,7 +7063,7 @@ async function buildElectron(inlineConfig = {}) {
6686
7063
  const config = await resolveConfig({ ...inlineConfig, target: "electron" }, "build");
6687
7064
  const startTime = performance.now();
6688
7065
  assertElectronVersion(config);
6689
- console.log(import_picocolors5.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors5.default.dim(` v${"2.4.3"}`));
7066
+ console.log(import_picocolors5.default.cyan("\n\u26A1 nasti build (electron)") + import_picocolors5.default.dim(` v${"2.5.0"}`));
6690
7067
  console.log(import_picocolors5.default.dim(` root: ${config.root}`));
6691
7068
  console.log(import_picocolors5.default.dim(` mode: ${config.mode}`));
6692
7069
  console.log(import_picocolors5.default.dim(` target: electron (\u2265 ${config.electron.minVersion})`));
@@ -6752,14 +7129,21 @@ async function bundleNode(config, entry, opts) {
6752
7129
  };
6753
7130
  const oxcTransformPlugin = {
6754
7131
  name: "nasti:oxc-transform",
6755
- transform(code, id) {
6756
- if (!shouldTransform(id)) return null;
6757
- const result = transformCode(id, code, {
7132
+ async transform(code, id) {
7133
+ const result = config.framework === "react" ? await transformReactCode(id, code, {
7134
+ react: config.react,
7135
+ consumer: "server",
7136
+ development: config.mode === "development",
7137
+ sourcemap: !!config.build.sourcemap,
7138
+ target: config.electron.nodeTarget,
7139
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
7140
+ }) : shouldTransform(id) ? transformCode(id, code, {
6758
7141
  sourcemap: !!config.build.sourcemap,
6759
7142
  jsxRuntime: "automatic",
6760
- jsxImportSource: config.framework === "vue" ? "vue" : "react",
7143
+ jsxImportSource: "vue",
6761
7144
  target: config.electron.nodeTarget
6762
- });
7145
+ }) : null;
7146
+ if (!result) return null;
6763
7147
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
6764
7148
  }
6765
7149
  };
@@ -6830,13 +7214,21 @@ function assertElectronVersion(config) {
6830
7214
  }
6831
7215
  function detectInstalledElectron(root) {
6832
7216
  try {
6833
- const pkgPath = import_node_path11.default.resolve(root, "node_modules/electron/package.json");
6834
- if (!import_node_fs8.default.existsSync(pkgPath)) return null;
7217
+ const require2 = (0, import_node_module5.createRequire)(import_node_path11.default.resolve(root, "package.json"));
7218
+ const pkgPath = require2.resolve("electron/package.json");
6835
7219
  const pkg = JSON.parse(import_node_fs8.default.readFileSync(pkgPath, "utf-8"));
6836
7220
  const major = parseInt(String(pkg.version).split(".")[0], 10);
6837
7221
  return Number.isFinite(major) ? major : null;
6838
7222
  } catch {
6839
- return null;
7223
+ try {
7224
+ const pkgPath = import_node_path11.default.resolve(root, "node_modules/electron/package.json");
7225
+ if (!import_node_fs8.default.existsSync(pkgPath)) return null;
7226
+ const pkg = JSON.parse(import_node_fs8.default.readFileSync(pkgPath, "utf-8"));
7227
+ const major = parseInt(String(pkg.version).split(".")[0], 10);
7228
+ return Number.isFinite(major) ? major : null;
7229
+ } catch {
7230
+ return null;
7231
+ }
6840
7232
  }
6841
7233
  }
6842
7234
 
@@ -6844,9 +7236,9 @@ function detectInstalledElectron(root) {
6844
7236
  init_server();
6845
7237
 
6846
7238
  // src/server/electron-dev.ts
6847
- var import_node_path17 = __toESM(require("path"), 1);
6848
- var import_node_fs12 = __toESM(require("fs"), 1);
6849
- var import_node_module7 = require("module");
7239
+ var import_node_path18 = __toESM(require("path"), 1);
7240
+ var import_node_fs13 = __toESM(require("fs"), 1);
7241
+ var import_node_module8 = require("module");
6850
7242
  var import_node_child_process = require("child_process");
6851
7243
  var import_chokidar2 = __toESM(require("chokidar"), 1);
6852
7244
  var import_picocolors10 = __toESM(require("picocolors"), 1);
@@ -6859,7 +7251,7 @@ async function startElectronDev(inlineConfig = {}) {
6859
7251
  const { noSpawn, ...rest } = inlineConfig;
6860
7252
  const config = await resolveConfig({ ...rest, target: "electron" }, "serve");
6861
7253
  warnElectronVersion(config);
6862
- console.log(import_picocolors10.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors10.default.dim(` v${"2.4.3"}`));
7254
+ console.log(import_picocolors10.default.cyan("\n\u26A1 nasti electron dev") + import_picocolors10.default.dim(` v${"2.5.0"}`));
6863
7255
  const { createServer: createServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
6864
7256
  const server = await createServer2({
6865
7257
  ...rest,
@@ -6869,11 +7261,11 @@ async function startElectronDev(inlineConfig = {}) {
6869
7261
  await server.listen();
6870
7262
  const devUrl = `http://localhost:${server.config.server.port}` + electronRendererDevPath(config.electron.renderer);
6871
7263
  console.log(import_picocolors10.default.dim(` renderer: ${devUrl}`));
6872
- const stageDir = import_node_path17.default.resolve(config.root, ".nasti");
6873
- import_node_fs12.default.mkdirSync(stageDir, { recursive: true });
6874
- const mainEntry = import_node_path17.default.resolve(config.root, config.electron.main);
7264
+ const stageDir = import_node_path18.default.resolve(config.root, ".nasti");
7265
+ import_node_fs13.default.mkdirSync(stageDir, { recursive: true });
7266
+ const mainEntry = import_node_path18.default.resolve(config.root, config.electron.main);
6875
7267
  const preloadEntries = normalizePreload(config.electron.preload, config.root);
6876
- const builtMainFile = import_node_path17.default.join(stageDir, "main" + extFor(config.electron.mainFormat));
7268
+ const builtMainFile = import_node_path18.default.join(stageDir, "main" + extFor(config.electron.mainFormat));
6877
7269
  const builtPreloadFiles = [];
6878
7270
  const compileAll = async () => {
6879
7271
  await compileNode(config, mainEntry, {
@@ -6883,9 +7275,9 @@ async function startElectronDev(inlineConfig = {}) {
6883
7275
  });
6884
7276
  builtPreloadFiles.length = 0;
6885
7277
  for (const entry of preloadEntries) {
6886
- if (!import_node_fs12.default.existsSync(entry)) continue;
6887
- const base = import_node_path17.default.basename(entry).replace(/\.[^.]+$/, "");
6888
- const out = import_node_path17.default.join(stageDir, base + extFor(config.electron.preloadFormat));
7278
+ if (!import_node_fs13.default.existsSync(entry)) continue;
7279
+ const base = import_node_path18.default.basename(entry).replace(/\.[^.]+$/, "");
7280
+ const out = import_node_path18.default.join(stageDir, base + extFor(config.electron.preloadFormat));
6889
7281
  await compileNode(config, entry, {
6890
7282
  outFile: out,
6891
7283
  format: config.electron.preloadFormat,
@@ -6924,7 +7316,7 @@ async function startElectronDev(inlineConfig = {}) {
6924
7316
  };
6925
7317
  spawnElectron();
6926
7318
  if (config.electron.autoRestart) {
6927
- const watchTargets = [mainEntry, ...preloadEntries].filter(import_node_fs12.default.existsSync);
7319
+ const watchTargets = [mainEntry, ...preloadEntries].filter(import_node_fs13.default.existsSync);
6928
7320
  const watcher = import_chokidar2.default.watch(watchTargets, { ignoreInitial: true });
6929
7321
  let restarting = null;
6930
7322
  let pending = false;
@@ -6984,14 +7376,21 @@ async function compileNode(config, entry, opts) {
6984
7376
  };
6985
7377
  const oxcTransformPlugin = {
6986
7378
  name: "nasti:oxc-transform",
6987
- transform(code, id) {
6988
- if (!shouldTransform(id)) return null;
6989
- const result = transformCode(id, code, {
7379
+ async transform(code, id) {
7380
+ const result = config.framework === "react" ? await transformReactCode(id, code, {
7381
+ react: config.react,
7382
+ consumer: "server",
7383
+ development: true,
7384
+ sourcemap: true,
7385
+ target: config.electron.nodeTarget,
7386
+ onWarning: (message) => config.logger.warn(`[nasti:react] ${message}`)
7387
+ }) : shouldTransform(id) ? transformCode(id, code, {
6990
7388
  sourcemap: true,
6991
7389
  jsxRuntime: "automatic",
6992
- jsxImportSource: config.framework === "vue" ? "vue" : "react",
7390
+ jsxImportSource: "vue",
6993
7391
  target: config.electron.nodeTarget
6994
- });
7392
+ }) : null;
7393
+ if (!result) return null;
6995
7394
  return { code: result.code, map: result.map ? JSON.parse(result.map) : void 0 };
6996
7395
  }
6997
7396
  };
@@ -7004,7 +7403,7 @@ async function compileNode(config, entry, opts) {
7004
7403
  platform: "node",
7005
7404
  plugins: [oxcTransformPlugin, electronPlugin(config), resolvePlugin(config)]
7006
7405
  });
7007
- import_node_fs12.default.mkdirSync(import_node_path17.default.dirname(opts.outFile), { recursive: true });
7406
+ import_node_fs13.default.mkdirSync(import_node_path18.default.dirname(opts.outFile), { recursive: true });
7008
7407
  await bundle2.write({
7009
7408
  file: opts.outFile,
7010
7409
  format: opts.format === "cjs" ? "cjs" : "esm",
@@ -7017,18 +7416,18 @@ async function compileNode(config, entry, opts) {
7017
7416
  await bundle2.close();
7018
7417
  }
7019
7418
  function electronRendererDevPath(renderer) {
7020
- const normalized = renderer.split(import_node_path17.default.sep).join("/").replace(/^\.?\//, "");
7419
+ const normalized = renderer.split(import_node_path18.default.sep).join("/").replace(/^\.?\//, "");
7021
7420
  return normalized === "index.html" ? "/" : `/${normalized}`;
7022
7421
  }
7023
7422
  function resolveElectronBinary(config) {
7024
- if (config.electron.electronPath && import_node_fs12.default.existsSync(config.electron.electronPath)) {
7423
+ if (config.electron.electronPath && import_node_fs13.default.existsSync(config.electron.electronPath)) {
7025
7424
  return config.electron.electronPath;
7026
7425
  }
7027
7426
  try {
7028
- const require2 = (0, import_node_module7.createRequire)(import_node_path17.default.resolve(config.root, "package.json"));
7427
+ const require2 = (0, import_node_module8.createRequire)(import_node_path18.default.resolve(config.root, "package.json"));
7029
7428
  const pathFile = require2.resolve("electron");
7030
7429
  const electronModule = require2(pathFile);
7031
- if (typeof electronModule === "string" && import_node_fs12.default.existsSync(electronModule)) {
7430
+ if (typeof electronModule === "string" && import_node_fs13.default.existsSync(electronModule)) {
7032
7431
  return electronModule;
7033
7432
  }
7034
7433
  } catch {
@@ -7055,10 +7454,10 @@ function warnElectronVersion(config) {
7055
7454
  }
7056
7455
 
7057
7456
  // src/plugins/monaco-editor.ts
7058
- var import_node_path18 = __toESM(require("path"), 1);
7059
- var import_node_fs13 = __toESM(require("fs"), 1);
7457
+ var import_node_path19 = __toESM(require("path"), 1);
7458
+ var import_node_fs14 = __toESM(require("fs"), 1);
7060
7459
  var import_node_crypto4 = __toESM(require("crypto"), 1);
7061
- var import_node_module8 = require("module");
7460
+ var import_node_module9 = require("module");
7062
7461
  var DEFAULT_WORKERS = {
7063
7462
  editorWorkerService: "monaco-editor/esm/vs/editor/editor.worker",
7064
7463
  css: "monaco-editor/esm/vs/language/css/css.worker",
@@ -7077,9 +7476,9 @@ function normalizePublicPath(p) {
7077
7476
  }
7078
7477
  function readMonacoVersion(root) {
7079
7478
  try {
7080
- const require2 = (0, import_node_module8.createRequire)(import_node_path18.default.resolve(root, "package.json"));
7479
+ const require2 = (0, import_node_module9.createRequire)(import_node_path19.default.resolve(root, "package.json"));
7081
7480
  const pkgJsonPath = require2.resolve("monaco-editor/package.json", { paths: [root] });
7082
- const pkg = JSON.parse(import_node_fs13.default.readFileSync(pkgJsonPath, "utf-8"));
7481
+ const pkg = JSON.parse(import_node_fs14.default.readFileSync(pkgJsonPath, "utf-8"));
7083
7482
  return typeof pkg.version === "string" ? pkg.version : "unknown";
7084
7483
  } catch {
7085
7484
  return "unknown";
@@ -7099,20 +7498,20 @@ function monacoEditorPlugin(options = {}) {
7099
7498
  let cacheDir = "";
7100
7499
  const building = /* @__PURE__ */ new Map();
7101
7500
  async function buildWorker(worker) {
7102
- const cacheFile = import_node_path18.default.join(cacheDir, `${worker.label}.worker.js`);
7103
- if (import_node_fs13.default.existsSync(cacheFile)) return cacheFile;
7501
+ const cacheFile = import_node_path19.default.join(cacheDir, `${worker.label}.worker.js`);
7502
+ if (import_node_fs14.default.existsSync(cacheFile)) return cacheFile;
7104
7503
  const existing = building.get(worker.label);
7105
7504
  if (existing) return existing;
7106
7505
  const task = (async () => {
7107
7506
  const { rolldown: rolldown4 } = await import("rolldown");
7108
- const require2 = (0, import_node_module8.createRequire)(import_node_path18.default.resolve(resolvedConfig.root, "package.json"));
7507
+ const require2 = (0, import_node_module9.createRequire)(import_node_path19.default.resolve(resolvedConfig.root, "package.json"));
7109
7508
  let entry;
7110
7509
  try {
7111
7510
  entry = require2.resolve(worker.entry, { paths: [resolvedConfig.root] });
7112
7511
  } catch {
7113
7512
  entry = require2.resolve(worker.entry + ".js", { paths: [resolvedConfig.root] });
7114
7513
  }
7115
- import_node_fs13.default.mkdirSync(cacheDir, { recursive: true });
7514
+ import_node_fs14.default.mkdirSync(cacheDir, { recursive: true });
7116
7515
  const bundle2 = await rolldown4({
7117
7516
  input: entry,
7118
7517
  platform: "browser"
@@ -7172,16 +7571,23 @@ function monacoEditorPlugin(options = {}) {
7172
7571
  resolvedConfig = config;
7173
7572
  const version = readMonacoVersion(config.root);
7174
7573
  const key = import_node_crypto4.default.createHash("sha1").update(version + "|" + publicPath).digest("hex").slice(0, 8);
7175
- cacheDir = import_node_path18.default.resolve(config.root, "node_modules/.nasti/monaco", key);
7574
+ cacheDir = import_node_path19.default.resolve(config.root, "node_modules/.nasti/monaco", key);
7176
7575
  },
7177
7576
  async configureServer(server) {
7178
7577
  const shouldBuild = !isCDN(publicPath) || forceBuildCDN;
7179
7578
  const watcher = server.watcher;
7180
- const monacoDir = import_node_path18.default.resolve(resolvedConfig.root, "node_modules/monaco-editor");
7579
+ const monacoLogical = import_node_path19.default.resolve(resolvedConfig.root, "node_modules/monaco-editor");
7580
+ const monacoPaths = /* @__PURE__ */ new Set([monacoLogical]);
7181
7581
  try {
7182
- watcher?.unwatch?.(monacoDir);
7582
+ monacoPaths.add(import_node_fs14.default.realpathSync(monacoLogical));
7183
7583
  } catch {
7184
7584
  }
7585
+ for (const monacoDir of monacoPaths) {
7586
+ try {
7587
+ watcher?.unwatch?.(monacoDir);
7588
+ } catch {
7589
+ }
7590
+ }
7185
7591
  if (!shouldBuild) return;
7186
7592
  void Promise.all(
7187
7593
  workers.map(
@@ -7207,7 +7613,7 @@ function monacoEditorPlugin(options = {}) {
7207
7613
  const file = await buildWorker(worker);
7208
7614
  res.setHeader("Content-Type", "application/javascript; charset=utf-8");
7209
7615
  res.setHeader("Cache-Control", "public, max-age=604800, immutable");
7210
- import_node_fs13.default.createReadStream(file).pipe(res);
7616
+ import_node_fs14.default.createReadStream(file).pipe(res);
7211
7617
  } catch (e) {
7212
7618
  res.statusCode = 500;
7213
7619
  res.end(`Monaco worker build failed: ${e.message}`);
@@ -7242,16 +7648,16 @@ self.monaco = monaco;`,
7242
7648
  resolvedConfig.root,
7243
7649
  resolvedConfig.build.outDir,
7244
7650
  resolvedConfig.base
7245
- ) : isCDN(publicPath) ? import_node_path18.default.resolve(resolvedConfig.root, resolvedConfig.build.outDir, "monaco") : import_node_path18.default.resolve(
7651
+ ) : isCDN(publicPath) ? import_node_path19.default.resolve(resolvedConfig.root, resolvedConfig.build.outDir, "monaco") : import_node_path19.default.resolve(
7246
7652
  resolvedConfig.root,
7247
7653
  resolvedConfig.build.outDir,
7248
7654
  publicPath.replace(/^\//, "")
7249
7655
  );
7250
- import_node_fs13.default.mkdirSync(outDir, { recursive: true });
7656
+ import_node_fs14.default.mkdirSync(outDir, { recursive: true });
7251
7657
  for (const worker of workers) {
7252
7658
  try {
7253
7659
  const cacheFile = await buildWorker(worker);
7254
- import_node_fs13.default.copyFileSync(cacheFile, import_node_path18.default.join(outDir, `${worker.label}.worker.js`));
7660
+ import_node_fs14.default.copyFileSync(cacheFile, import_node_path19.default.join(outDir, `${worker.label}.worker.js`));
7255
7661
  } catch (e) {
7256
7662
  throw new Error(
7257
7663
  `[nasti:monaco-editor] worker build failed for "${worker.label}": ${e.message}
@@ -7263,6 +7669,345 @@ ${e.stack || ""}`
7263
7669
  };
7264
7670
  }
7265
7671
 
7672
+ // src/plugins/rsc.ts
7673
+ var import_node_fs15 = __toESM(require("fs"), 1);
7674
+ var import_node_path20 = __toESM(require("path"), 1);
7675
+ var import_oxc_parser = require("oxc-parser");
7676
+ init_transformer();
7677
+ var SERVER_RUNTIME_ID = "virtual:nasti-rsc/server-runtime";
7678
+ var CLIENT_RUNTIME_ID = "virtual:nasti-rsc/client-runtime";
7679
+ var RESOLVED_SERVER_RUNTIME_ID = `\0${SERVER_RUNTIME_ID}`;
7680
+ var RESOLVED_CLIENT_RUNTIME_ID = `\0${CLIENT_RUNTIME_ID}`;
7681
+ function rsc(options = {}) {
7682
+ const names = {
7683
+ client: options.environment?.client ?? "client",
7684
+ ssr: options.environment?.ssr ?? "ssr",
7685
+ rsc: options.environment?.rsc ?? "rsc"
7686
+ };
7687
+ const clientReferences = /* @__PURE__ */ new Map();
7688
+ const serverReferences = /* @__PURE__ */ new Map();
7689
+ let resolvedConfig;
7690
+ return {
7691
+ name: "nasti:rsc",
7692
+ enforce: "post",
7693
+ config(config, env) {
7694
+ const root = import_node_path20.default.resolve(config.root ?? ".");
7695
+ const include = options.include ?? config.react?.include ?? /\.[tj]sx?$/;
7696
+ const exclude = options.exclude ?? config.react?.exclude ?? /node_modules/;
7697
+ const discoveredClients = env.command === "build" ? discoverDirectiveModules(root, options.scanDirectories, include, exclude) : [];
7698
+ for (const item of discoveredClients) {
7699
+ if (item.module.useClient) {
7700
+ clientReferences.set(
7701
+ item.id,
7702
+ new Set(item.module.exports.map((entry) => entry.exported))
7703
+ );
7704
+ }
7705
+ if (item.module.useServer) {
7706
+ serverReferences.set(
7707
+ item.id,
7708
+ new Set(item.module.exports.map((entry) => entry.exported))
7709
+ );
7710
+ }
7711
+ }
7712
+ const environments = { ...config.environments ?? {} };
7713
+ if (names.client !== "client") {
7714
+ environments.client = {
7715
+ ...environments.client ?? {},
7716
+ buildEnabled: false
7717
+ };
7718
+ }
7719
+ const client = { ...environments[names.client] ?? {} };
7720
+ const clientSeeds = collectClientSeeds(root, config, client, options.entries?.client);
7721
+ const generatedClientEntries = discoveredClients.filter((item) => item.module.useClient).map((item) => item.id);
7722
+ client.consumer = "client";
7723
+ client.entry = uniqueEntries([...clientSeeds, ...generatedClientEntries]);
7724
+ environments[names.client] = client;
7725
+ const rscEnvironment = { ...environments[names.rsc] ?? {} };
7726
+ rscEnvironment.consumer = "server";
7727
+ const rscEntries = normalizeEntries(options.entries?.rsc);
7728
+ if (rscEntries.length > 0) rscEnvironment.entry = rscEntries;
7729
+ environments[names.rsc] = rscEnvironment;
7730
+ const ssrEntries = normalizeEntries(options.entries?.ssr);
7731
+ if (ssrEntries.length > 0 || environments[names.ssr]) {
7732
+ environments[names.ssr] = {
7733
+ ...environments[names.ssr] ?? {},
7734
+ consumer: "server",
7735
+ ...ssrEntries.length > 0 ? { entry: ssrEntries } : {}
7736
+ };
7737
+ }
7738
+ return { environments };
7739
+ },
7740
+ configEnvironment(name, environment) {
7741
+ if (name !== names.rsc) return;
7742
+ const conditions = environment.resolve?.conditions ?? ["node", "import", "module", "default"];
7743
+ return {
7744
+ consumer: "server",
7745
+ resolve: {
7746
+ ...environment.resolve,
7747
+ conditions: ["react-server", ...conditions.filter((item) => item !== "react-server")]
7748
+ }
7749
+ };
7750
+ },
7751
+ configResolved(config) {
7752
+ if (config.framework !== "react") {
7753
+ throw new Error('[nasti:rsc] the RSC generator requires framework: "react"');
7754
+ }
7755
+ resolvedConfig = config;
7756
+ },
7757
+ resolveId(source) {
7758
+ if (source === SERVER_RUNTIME_ID) return RESOLVED_SERVER_RUNTIME_ID;
7759
+ if (source === CLIENT_RUNTIME_ID) return RESOLVED_CLIENT_RUNTIME_ID;
7760
+ return null;
7761
+ },
7762
+ load(id) {
7763
+ if (id === RESOLVED_SERVER_RUNTIME_ID) return createServerRuntimeModule();
7764
+ if (id === RESOLVED_CLIENT_RUNTIME_ID) {
7765
+ const browser = this.environment?.name === names.client;
7766
+ return createClientRuntimeModule(browser);
7767
+ }
7768
+ return null;
7769
+ },
7770
+ transform(code, id) {
7771
+ if (!resolvedConfig || !isSourceModule(id, resolvedConfig, options)) return null;
7772
+ const cleanId = cleanModuleId(id);
7773
+ const module2 = scanModule(cleanId, code);
7774
+ if (!module2) return null;
7775
+ if (module2.useClient && module2.useServer) {
7776
+ throw new Error(`[nasti:rsc] ${displayId(resolvedConfig.root, cleanId)} cannot contain both "use client" and "use server"`);
7777
+ }
7778
+ const moduleId = referenceModuleId(resolvedConfig.root, cleanId);
7779
+ if (module2.useClient) {
7780
+ clientReferences.set(cleanId, new Set(module2.exports.map((entry) => entry.exported)));
7781
+ if (this.environment?.name === names.rsc) {
7782
+ return {
7783
+ code: createClientReferenceProxy(moduleId, module2.exports),
7784
+ map: { mappings: "" }
7785
+ };
7786
+ }
7787
+ }
7788
+ if (module2.useServer) {
7789
+ serverReferences.set(cleanId, new Set(module2.exports.map((entry) => entry.exported)));
7790
+ if (this.environment?.name === names.rsc) {
7791
+ return {
7792
+ code: registerServerReferences(code, moduleId, module2.exports, cleanId),
7793
+ map: { mappings: "" }
7794
+ };
7795
+ }
7796
+ if (this.environment?.consumer === "client" || this.environment?.name === names.client || this.environment?.name === names.ssr) {
7797
+ return {
7798
+ code: createServerReferenceProxy(moduleId, module2.exports),
7799
+ map: { mappings: "" }
7800
+ };
7801
+ }
7802
+ }
7803
+ return null;
7804
+ },
7805
+ afterBuildApp(results, _api, context) {
7806
+ if (options.manifestFile === false) return;
7807
+ const manifest = createManifest(
7808
+ names,
7809
+ resolvedConfig?.root ?? "",
7810
+ results,
7811
+ clientReferences,
7812
+ serverReferences
7813
+ );
7814
+ const output = {
7815
+ type: "asset",
7816
+ fileName: options.manifestFile ?? "rsc-manifest.json",
7817
+ source: JSON.stringify(manifest, null, 2) + "\n"
7818
+ };
7819
+ context.emitFile(output);
7820
+ }
7821
+ };
7822
+ }
7823
+ function scanModule(filename, code) {
7824
+ if (!code.includes("use client") && !code.includes("use server")) return null;
7825
+ const parsed = (0, import_oxc_parser.parseSync)(filename, code);
7826
+ if (parsed.errors.length > 0) return null;
7827
+ const directives = new Set(
7828
+ parsed.program.body.filter((node) => node.type === "ExpressionStatement" && typeof node.directive === "string").map((node) => node.directive)
7829
+ );
7830
+ const useClient = directives.has("use client");
7831
+ const useServer = directives.has("use server");
7832
+ if (!useClient && !useServer) return null;
7833
+ const exports2 = [];
7834
+ for (const statement of parsed.module.staticExports) {
7835
+ for (const entry of statement.entries) {
7836
+ if (entry.isType) continue;
7837
+ const exported = entry.exportName.kind === "Default" ? "default" : entry.exportName.name;
7838
+ if (!exported) {
7839
+ throw new Error(
7840
+ `[nasti:rsc] ${filename} uses export * inside an RSC directive module; replace it with explicit named exports so reference identities are stable`
7841
+ );
7842
+ }
7843
+ exports2.push({
7844
+ exported,
7845
+ local: entry.localName.kind === "Name" ? entry.localName.name ?? void 0 : void 0,
7846
+ reexported: entry.moduleRequest !== null
7847
+ });
7848
+ }
7849
+ }
7850
+ return { useClient, useServer, exports: dedupeExports(exports2) };
7851
+ }
7852
+ function createClientReferenceProxy(moduleId, exports2) {
7853
+ const lines = [
7854
+ `import { registerClientReference as __nasti_register_client__ } from ${JSON.stringify(SERVER_RUNTIME_ID)};`
7855
+ ];
7856
+ exports2.forEach((entry, index2) => {
7857
+ const local = `__nasti_client_reference_${index2}__`;
7858
+ const message = `Cannot call client export ${moduleId}#${entry.exported} from the RSC server graph.`;
7859
+ lines.push(
7860
+ `const ${local} = __nasti_register_client__(function () { throw new Error(${JSON.stringify(message)}); }, ${JSON.stringify(moduleId)}, ${JSON.stringify(entry.exported)});`,
7861
+ exportLocal(local, entry.exported)
7862
+ );
7863
+ });
7864
+ return lines.join("\n") + "\n";
7865
+ }
7866
+ function registerServerReferences(code, moduleId, exports2, filename) {
7867
+ const registrations = [];
7868
+ for (const entry of exports2) {
7869
+ if (entry.reexported || !entry.local) {
7870
+ throw new Error(
7871
+ `[nasti:rsc] ${filename} must use named local bindings for "use server" exports; ${entry.exported} cannot be registered safely`
7872
+ );
7873
+ }
7874
+ registrations.push(
7875
+ `__nasti_register_server__(${entry.local}, ${JSON.stringify(moduleId)}, ${JSON.stringify(entry.exported)});`
7876
+ );
7877
+ }
7878
+ return [
7879
+ code,
7880
+ `import { registerServerReference as __nasti_register_server__ } from ${JSON.stringify(SERVER_RUNTIME_ID)};`,
7881
+ ...registrations,
7882
+ ""
7883
+ ].join("\n");
7884
+ }
7885
+ function createServerReferenceProxy(moduleId, exports2) {
7886
+ const lines = [
7887
+ `import { createServerReference as __nasti_create_server__ } from ${JSON.stringify(CLIENT_RUNTIME_ID)};`
7888
+ ];
7889
+ exports2.forEach((entry, index2) => {
7890
+ const local = `__nasti_server_reference_${index2}__`;
7891
+ lines.push(
7892
+ `const ${local} = __nasti_create_server__(${JSON.stringify(moduleId)}, ${JSON.stringify(entry.exported)});`,
7893
+ exportLocal(local, entry.exported)
7894
+ );
7895
+ });
7896
+ return lines.join("\n") + "\n";
7897
+ }
7898
+ function exportLocal(local, exported) {
7899
+ if (exported === "default") return `export default ${local};`;
7900
+ const name = /^[A-Za-z_$][\w$]*$/.test(exported) ? exported : JSON.stringify(exported);
7901
+ return `export { ${local} as ${name} };`;
7902
+ }
7903
+ function createServerRuntimeModule() {
7904
+ return [
7905
+ `export { registerClientReference, registerServerReference } from "react-server-dom-webpack/server.edge";`,
7906
+ ""
7907
+ ].join("\n");
7908
+ }
7909
+ function createClientRuntimeModule(browser) {
7910
+ const source = browser ? "react-server-dom-webpack/client.browser" : "react-server-dom-webpack/client.edge";
7911
+ return `
7912
+ import { createServerReference as __createServerReference } from ${JSON.stringify(source)};
7913
+ const __callServer = (id, args) => {
7914
+ const handler = globalThis[Symbol.for("nasti.rsc.callServer")];
7915
+ if (typeof handler !== "function") {
7916
+ throw new Error("No RSC callServer handler is installed. Set globalThis[Symbol.for('nasti.rsc.callServer')].");
7917
+ }
7918
+ return handler(id, args);
7919
+ };
7920
+ export function createServerReference(moduleId, name) {
7921
+ return __createServerReference(moduleId + "#" + name, __callServer, undefined, undefined, name);
7922
+ }
7923
+ `.trimStart();
7924
+ }
7925
+ function createManifest(names, root, results, clients, servers) {
7926
+ return {
7927
+ version: 1,
7928
+ environments: names,
7929
+ clientReferences: manifestReferences(root, results[names.client], clients),
7930
+ serverReferences: manifestReferences(root, results[names.rsc], servers)
7931
+ };
7932
+ }
7933
+ function manifestReferences(root, result, references) {
7934
+ const output = {};
7935
+ for (const [id, names] of [...references].sort(([a], [b]) => a.localeCompare(b))) {
7936
+ const chunks = Object.values(result?.chunks ?? {}).filter((chunk) => chunk.moduleIds.some((moduleId) => cleanModuleId(moduleId) === id)).map((chunk) => chunk.fileName).sort();
7937
+ for (const name of [...names].sort()) {
7938
+ const moduleId = referenceModuleId(root, id);
7939
+ output[`${moduleId}#${name}`] = { id: moduleId, name, chunks };
7940
+ }
7941
+ }
7942
+ return output;
7943
+ }
7944
+ function discoverDirectiveModules(root, scanDirectories, include, exclude) {
7945
+ const requested = scanDirectories ?? ["app", "src"];
7946
+ const roots = requested.map((directory) => import_node_path20.default.resolve(root, directory)).filter((directory) => import_node_fs15.default.existsSync(directory));
7947
+ if (roots.length === 0) roots.push(root);
7948
+ const output = [];
7949
+ for (const directory of roots) walk(directory);
7950
+ return output;
7951
+ function walk(directory) {
7952
+ for (const entry of import_node_fs15.default.readdirSync(directory, { withFileTypes: true })) {
7953
+ if (entry.name === "node_modules" || entry.name === ".git" || entry.name === ".nasti") continue;
7954
+ const id = import_node_path20.default.join(directory, entry.name);
7955
+ if (entry.isDirectory()) {
7956
+ walk(id);
7957
+ continue;
7958
+ }
7959
+ if (!entry.isFile() || !matchesReactFilter(id, include, exclude)) continue;
7960
+ const module2 = scanModule(id, import_node_fs15.default.readFileSync(id, "utf-8"));
7961
+ if (module2) output.push({ id, module: module2 });
7962
+ }
7963
+ }
7964
+ }
7965
+ function collectClientSeeds(root, config, client, configured) {
7966
+ const explicit = [
7967
+ ...normalizeEntries(client.entry),
7968
+ ...normalizeEntries(configured)
7969
+ ];
7970
+ if (explicit.length > 0) return explicit;
7971
+ const htmlFile = import_node_path20.default.resolve(root, client.html ?? "index.html");
7972
+ if (import_node_fs15.default.existsSync(htmlFile)) {
7973
+ const html = import_node_fs15.default.readFileSync(htmlFile, "utf-8");
7974
+ const htmlDir = import_node_path20.default.dirname(htmlFile);
7975
+ const entries = [...html.matchAll(/<script[^>]+src=["']([^"']+)["'][^>]*>/gi)].map((match) => match[1]?.split(/[?#]/, 1)[0]).filter((entry) => !!entry && !entry.startsWith("http")).map((entry) => entry.startsWith("/") ? import_node_path20.default.resolve(root, entry.slice(1)) : import_node_path20.default.resolve(htmlDir, entry));
7976
+ if (entries.length > 0) return entries;
7977
+ }
7978
+ for (const entry of ["src/main.ts", "src/main.tsx", "src/main.js", "src/index.ts", "src/index.tsx", "src/index.js"]) {
7979
+ if (import_node_fs15.default.existsSync(import_node_path20.default.resolve(root, entry))) return [entry];
7980
+ }
7981
+ return [];
7982
+ }
7983
+ function normalizeEntries(entries) {
7984
+ return entries == null ? [] : Array.isArray(entries) ? entries : [entries];
7985
+ }
7986
+ function uniqueEntries(entries) {
7987
+ return [...new Set(entries)];
7988
+ }
7989
+ function isSourceModule(id, config, options) {
7990
+ const cleanId = cleanModuleId(id);
7991
+ if (cleanId.startsWith("\0")) return false;
7992
+ const include = options.include ?? config.react.include;
7993
+ const exclude = options.exclude ?? config.react.exclude;
7994
+ return matchesReactFilter(cleanId, include, exclude);
7995
+ }
7996
+ function cleanModuleId(id) {
7997
+ return id.split(/[?#]/, 1)[0];
7998
+ }
7999
+ function referenceModuleId(root, id) {
8000
+ if (!root || !import_node_path20.default.isAbsolute(id)) return id.replaceAll(import_node_path20.default.sep, "/");
8001
+ const relative = import_node_path20.default.relative(root, id).replaceAll(import_node_path20.default.sep, "/");
8002
+ return relative.startsWith("../") ? id.replaceAll(import_node_path20.default.sep, "/") : `/${relative}`;
8003
+ }
8004
+ function displayId(root, id) {
8005
+ return referenceModuleId(root, id);
8006
+ }
8007
+ function dedupeExports(exports2) {
8008
+ return [...new Map(exports2.map((entry) => [entry.exported, entry])).values()];
8009
+ }
8010
+
7266
8011
  // src/index.ts
7267
8012
  init_environment();
7268
8013
  init_hot_channel();
@@ -7291,6 +8036,7 @@ init_env();
7291
8036
  printServerUrls,
7292
8037
  resolveConfig,
7293
8038
  resolveEnvironmentPlugins,
8039
+ rsc,
7294
8040
  ssrDefineOverrides,
7295
8041
  startElectronDev
7296
8042
  });