@absolutejs/absolute 0.13.11 → 0.15.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.
Files changed (82) hide show
  1. package/.claude/settings.local.json +7 -1
  2. package/CLAUDE.md +65 -56
  3. package/LICENSE +80 -24
  4. package/README.md +163 -163
  5. package/THIRD_PARTY_NOTICES.md +61 -0
  6. package/dist/cli/index.js +24 -8
  7. package/dist/index.js +3013 -480
  8. package/dist/index.js.map +56 -26
  9. package/dist/{build → src/build}/compileSvelte.d.ts +2 -1
  10. package/dist/src/build/compileVue.d.ts +33 -0
  11. package/dist/src/build/generateReactIndexes.d.ts +1 -0
  12. package/dist/src/build/htmlScriptHMRPlugin.d.ts +13 -0
  13. package/dist/src/build/wrapHTMLScript.d.ts +24 -0
  14. package/dist/src/core/build.d.ts +2 -0
  15. package/dist/src/core/devBuild.d.ts +6 -0
  16. package/dist/{core → src/core}/index.d.ts +2 -1
  17. package/dist/src/core/lookup.d.ts +3 -0
  18. package/dist/{core → src/core}/pageHandlers.d.ts +4 -4
  19. package/dist/src/dev/assetStore.d.ts +12 -0
  20. package/dist/src/dev/buildHMRClient.d.ts +1 -0
  21. package/dist/src/dev/clientManager.d.ts +26 -0
  22. package/dist/src/dev/configResolver.d.ts +13 -0
  23. package/dist/src/dev/dependencyGraph.d.ts +13 -0
  24. package/dist/src/dev/fileHashTracker.d.ts +2 -0
  25. package/dist/src/dev/fileWatcher.d.ts +3 -0
  26. package/dist/src/dev/moduleMapper.d.ts +21 -0
  27. package/dist/src/dev/moduleVersionTracker.d.ts +7 -0
  28. package/dist/src/dev/pathUtils.d.ts +5 -0
  29. package/dist/src/dev/reactComponentClassifier.d.ts +2 -0
  30. package/dist/src/dev/rebuildTrigger.d.ts +10 -0
  31. package/dist/src/dev/simpleHTMLHMR.d.ts +4 -0
  32. package/dist/src/dev/simpleHTMXHMR.d.ts +4 -0
  33. package/dist/src/dev/simpleSvelteHMR.d.ts +1 -0
  34. package/dist/src/dev/simpleVueHMR.d.ts +1 -0
  35. package/dist/src/dev/webSocket.d.ts +9 -0
  36. package/dist/{index.d.ts → src/index.d.ts} +1 -0
  37. package/dist/src/plugins/hmr.d.ts +62 -0
  38. package/dist/{plugins → src/plugins}/index.d.ts +2 -1
  39. package/dist/{plugins → src/plugins}/networking.d.ts +3 -0
  40. package/dist/{svelte → src/svelte}/renderToReadableStream.d.ts +3 -1
  41. package/dist/src/utils/getRegisterClientScript.d.ts +10 -0
  42. package/dist/{utils → src/utils}/index.d.ts +2 -0
  43. package/dist/src/utils/logger.d.ts +45 -0
  44. package/dist/src/utils/networking.d.ts +2 -0
  45. package/dist/src/utils/normalizePath.d.ts +9 -0
  46. package/dist/src/utils/registerClientScript.d.ts +51 -0
  47. package/dist/{types.d.ts → types/build.d.ts} +7 -0
  48. package/dist/types/client.d.ts +104 -0
  49. package/dist/types/index.d.ts +4 -0
  50. package/dist/types/messages.d.ts +138 -0
  51. package/dist/types/websocket.d.ts +6 -0
  52. package/eslint.config.mjs +238 -234
  53. package/package.json +17 -12
  54. package/tsconfig.build.json +20 -20
  55. package/types/build.ts +46 -0
  56. package/types/client.ts +109 -0
  57. package/types/index.ts +4 -0
  58. package/types/messages.ts +205 -0
  59. package/types/websocket.ts +12 -0
  60. package/types/window-globals.ts +53 -0
  61. package/dist/build/compileVue.d.ts +0 -5
  62. package/dist/build/generateReactIndexes.d.ts +0 -1
  63. package/dist/core/build.d.ts +0 -2
  64. package/dist/core/lookup.d.ts +0 -1
  65. package/dist/utils/networking.d.ts +0 -1
  66. /package/dist/{build → src/build}/generateManifest.d.ts +0 -0
  67. /package/dist/{build → src/build}/outputLogs.d.ts +0 -0
  68. /package/dist/{build → src/build}/scanEntryPoints.d.ts +0 -0
  69. /package/dist/{build → src/build}/updateAssetPaths.d.ts +0 -0
  70. /package/dist/{cli → src/cli}/index.d.ts +0 -0
  71. /package/dist/{constants.d.ts → src/constants.d.ts} +0 -0
  72. /package/dist/{plugins → src/plugins}/pageRouter.d.ts +0 -0
  73. /package/dist/{svelte → src/svelte}/renderToPipeableStream.d.ts +0 -0
  74. /package/dist/{svelte → src/svelte}/renderToString.d.ts +0 -0
  75. /package/dist/{utils → src/utils}/cleanup.d.ts +0 -0
  76. /package/dist/{utils → src/utils}/commonAncestor.d.ts +0 -0
  77. /package/dist/{utils → src/utils}/escapeScriptContent.d.ts +0 -0
  78. /package/dist/{utils → src/utils}/generateHeadElement.d.ts +0 -0
  79. /package/dist/{utils → src/utils}/getDurationString.d.ts +0 -0
  80. /package/dist/{utils → src/utils}/getEnv.d.ts +0 -0
  81. /package/dist/{utils → src/utils}/stringModifiers.d.ts +0 -0
  82. /package/dist/{utils → src/utils}/validateSafePath.d.ts +0 -0
package/dist/index.js CHANGED
@@ -1,143 +1,47 @@
1
1
  // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
13
+ var __require = import.meta.require;
14
+
2
15
  // src/constants.ts
3
- var UNFOUND_INDEX = -1;
4
- var SECONDS_IN_A_MINUTE = 60;
5
- var MILLISECONDS_IN_A_SECOND = 1000;
6
- var MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
7
- var MINUTES_IN_AN_HOUR = 60;
8
- var HOURS_IN_DAY = 24;
9
- var MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
10
- var TIME_PRECISION = 2;
11
- var TWO_THIRDS = 2 / 3;
12
- var DEFAULT_PORT = 3000;
13
- var DEFAULT_CHUNK_SIZE = 16384;
14
- var BUN_BUILD_WARNING_SUPPRESSION = "wildcard sideEffects are not supported yet";
15
- // src/core/build.ts
16
- import { copyFileSync, cpSync, mkdirSync } from "fs";
17
- import { rm as rm3 } from "fs/promises";
18
- import { basename as basename4, join as join5 } from "path";
19
- import { cwd, env as env2, exit } from "process";
20
- var {$, build: bunBuild, Glob: Glob3 } = globalThis.Bun;
16
+ var UNFOUND_INDEX = -1, SECONDS_IN_A_MINUTE = 60, MILLISECONDS_IN_A_SECOND = 1000, MILLISECONDS_IN_A_MINUTE, MINUTES_IN_AN_HOUR = 60, HOURS_IN_DAY = 24, MILLISECONDS_IN_A_DAY, TIME_PRECISION = 2, TWO_THIRDS, DEFAULT_PORT = 3000, DEFAULT_CHUNK_SIZE = 16384, BUN_BUILD_WARNING_SUPPRESSION = "wildcard sideEffects are not supported yet";
17
+ var init_constants = __esm(() => {
18
+ MILLISECONDS_IN_A_MINUTE = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE;
19
+ MILLISECONDS_IN_A_DAY = MILLISECONDS_IN_A_SECOND * SECONDS_IN_A_MINUTE * MINUTES_IN_AN_HOUR * HOURS_IN_DAY;
20
+ TWO_THIRDS = 2 / 3;
21
+ });
21
22
 
22
- // src/build/compileSvelte.ts
23
- import { mkdir, stat } from "fs/promises";
24
- import {
25
- dirname,
26
- join,
27
- basename,
28
- extname,
29
- resolve,
30
- relative,
31
- sep
32
- } from "path";
33
- import { env } from "process";
34
- var {write, file, Transpiler } = globalThis.Bun;
35
- import { compile, compileModule, preprocess } from "svelte/compiler";
36
- var transpiler = new Transpiler({ loader: "ts", target: "browser" });
37
- var exists = async (path) => {
38
- try {
39
- await stat(path);
40
- return true;
41
- } catch {
42
- return false;
43
- }
44
- };
45
- var resolveSvelte = async (spec, from) => {
46
- const basePath = resolve(dirname(from), spec);
47
- const explicit = /\.(svelte|svelte\.(?:ts|js))$/.test(basePath);
48
- if (!explicit) {
49
- const extensions = [".svelte", ".svelte.ts", ".svelte.js"];
50
- const paths = extensions.map((ext) => `${basePath}${ext}`);
51
- const checks = await Promise.all(paths.map(exists));
52
- const match = paths.find((_, index) => checks[index]);
53
- return match ?? null;
23
+ // src/utils/stringModifiers.ts
24
+ var exports_stringModifiers = {};
25
+ __export(exports_stringModifiers, {
26
+ toPascal: () => toPascal,
27
+ toKebab: () => toKebab
28
+ });
29
+ var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-9\-_]+/g, "").replace(/[-_]{2,}/g, "-"), toPascal = (str) => {
30
+ if (!str.includes("-") && !str.includes("_")) {
31
+ return str.charAt(0).toUpperCase() + str.slice(1);
54
32
  }
55
- if (await exists(basePath))
56
- return basePath;
57
- if (!basePath.endsWith(".svelte"))
58
- return null;
59
- const tsPath = `${basePath}.ts`;
60
- if (await exists(tsPath))
61
- return tsPath;
62
- const jsPath = `${basePath}.js`;
63
- if (await exists(jsPath))
64
- return jsPath;
65
- return null;
66
- };
67
- var compileSvelte = async (entryPoints, svelteRoot, cache = new Map) => {
68
- const compiledRoot = join(svelteRoot, "compiled");
69
- const clientDir = join(compiledRoot, "client");
70
- const indexDir = join(compiledRoot, "indexes");
71
- const pagesDir = join(compiledRoot, "pages");
72
- await Promise.all([clientDir, indexDir, pagesDir].map((dir) => mkdir(dir, { recursive: true })));
73
- const dev = env.NODE_ENV === "development";
74
- const build = async (src) => {
75
- const memoized = cache.get(src);
76
- if (memoized)
77
- return memoized;
78
- const raw = await file(src).text();
79
- const isModule = src.endsWith(".svelte.ts") || src.endsWith(".svelte.js");
80
- const preprocessed = isModule ? raw : (await preprocess(raw, {})).code;
81
- const transpiled = src.endsWith(".ts") || src.endsWith(".svelte.ts") ? transpiler.transformSync(preprocessed) : preprocessed;
82
- const relDir = dirname(relative(svelteRoot, src)).replace(/\\/g, "/");
83
- const baseName = basename(src).replace(/\.svelte(\.(ts|js))?$/, "");
84
- const importPaths = Array.from(transpiled.matchAll(/from\s+['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((path) => path !== undefined);
85
- const resolvedImports = await Promise.all(importPaths.map((importPath) => resolveSvelte(importPath, src)));
86
- const childSources = resolvedImports.filter((path) => path !== null);
87
- await Promise.all(childSources.map((child) => build(child)));
88
- const generate = (mode) => (isModule ? compileModule(transpiled, { dev, filename: src }).js.code : compile(transpiled, {
89
- css: "injected",
90
- dev,
91
- filename: src,
92
- generate: mode
93
- }).js.code).replace(/\.svelte(?:\.(?:ts|js))?(['"])/g, ".js$1");
94
- const ssrPath = join(pagesDir, relDir, `${baseName}.js`);
95
- const clientPath = join(clientDir, relDir, `${baseName}.js`);
96
- await Promise.all([
97
- mkdir(dirname(ssrPath), { recursive: true }),
98
- mkdir(dirname(clientPath), { recursive: true })
99
- ]);
100
- if (isModule) {
101
- const bundle = generate("client");
102
- await Promise.all([
103
- write(ssrPath, bundle),
104
- write(clientPath, bundle)
105
- ]);
106
- } else {
107
- const serverBundle = generate("server");
108
- const clientBundle = generate("client");
109
- await Promise.all([
110
- write(ssrPath, serverBundle),
111
- write(clientPath, clientBundle)
112
- ]);
113
- }
114
- const built = { client: clientPath, ssr: ssrPath };
115
- cache.set(src, built);
116
- return built;
117
- };
118
- const roots = await Promise.all(entryPoints.map(build));
119
- await Promise.all(roots.map(async ({ client }) => {
120
- const relClientDir = dirname(relative(clientDir, client));
121
- const name = basename(client, extname(client));
122
- const indexPath = join(indexDir, relClientDir, `${name}.js`);
123
- const importRaw = relative(dirname(indexPath), client).split(sep).join("/");
124
- const importPath = importRaw.startsWith(".") || importRaw.startsWith("/") ? importRaw : `./${importRaw}`;
125
- const bootstrap = `import C from "${importPath}";
126
- import { hydrate } from "svelte";
127
- hydrate(C,{target:document.body,props:window.__INITIAL_PROPS__??{}});`;
128
- await mkdir(dirname(indexPath), { recursive: true });
129
- return write(indexPath, bootstrap);
130
- }));
131
- return {
132
- svelteClientPaths: roots.map(({ client }) => {
133
- const rel = dirname(relative(clientDir, client));
134
- return join(indexDir, rel, basename(client));
135
- }),
136
- svelteServerPaths: roots.map(({ ssr }) => ssr)
137
- };
138
- };
33
+ return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
34
+ }, toKebab = (str) => normalizeSlug(str).replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
139
35
 
140
36
  // src/build/compileVue.ts
37
+ var exports_compileVue = {};
38
+ __export(exports_compileVue, {
39
+ vueHmrMetadata: () => vueHmrMetadata,
40
+ generateVueHmrId: () => generateVueHmrId,
41
+ detectVueChangeType: () => detectVueChangeType,
42
+ compileVue: () => compileVue,
43
+ clearVueHmrCaches: () => clearVueHmrCaches
44
+ });
141
45
  import { mkdir as mkdir2 } from "fs/promises";
142
46
  import { basename as basename2, dirname as dirname2, join as join2, relative as relative2, resolve as resolve2 } from "path";
143
47
  import {
@@ -147,29 +51,51 @@ import {
147
51
  compileStyle
148
52
  } from "@vue/compiler-sfc";
149
53
  var {file: file2, write: write2, Transpiler: Transpiler2 } = globalThis.Bun;
150
-
151
- // src/utils/stringModifiers.ts
152
- var normalizeSlug = (str) => str.trim().replace(/\s+/g, "-").replace(/[^A-Za-z0-9\-_]+/g, "").replace(/[-_]{2,}/g, "-");
153
- var toPascal = (str) => {
154
- if (!str.includes("-") && !str.includes("_")) {
155
- return str.charAt(0).toUpperCase() + str.slice(1);
54
+ var hmrClientPath2, transpiler2, scriptCache, scriptSetupCache, templateCache, styleCache, vueHmrMetadata, detectVueChangeType = (filePath, descriptor) => {
55
+ const prevScript = scriptCache.get(filePath);
56
+ const prevScriptSetup = scriptSetupCache.get(filePath);
57
+ const prevTemplate = templateCache.get(filePath);
58
+ const prevStyle = styleCache.get(filePath);
59
+ const currentScript = descriptor.script?.content ?? "";
60
+ const currentScriptSetup = descriptor.scriptSetup?.content ?? "";
61
+ const currentTemplate = descriptor.template?.content ?? "";
62
+ const currentStyle = descriptor.styles.map((s) => `${s.scoped ? "scoped:" : ""}${s.content}`).join("|||");
63
+ scriptCache.set(filePath, currentScript);
64
+ scriptSetupCache.set(filePath, currentScriptSetup);
65
+ templateCache.set(filePath, currentTemplate);
66
+ styleCache.set(filePath, currentStyle);
67
+ if (prevScript === undefined && prevScriptSetup === undefined) {
68
+ return "full";
156
69
  }
157
- return normalizeSlug(str).split(/[-_]/).filter(Boolean).map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1).toLowerCase()).join("");
158
- };
159
- var toKebab = (str) => normalizeSlug(str).replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
160
-
161
- // src/build/compileVue.ts
162
- var transpiler2 = new Transpiler2({ loader: "ts", target: "browser" });
163
- var extractImports = (sourceCode) => Array.from(sourceCode.matchAll(/import\s+[\s\S]+?['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((importPath) => importPath !== undefined);
164
- var toJs = (filePath) => {
70
+ const scriptChanged = prevScript !== currentScript;
71
+ const scriptSetupChanged = prevScriptSetup !== currentScriptSetup;
72
+ const templateChanged = prevTemplate !== currentTemplate;
73
+ const styleChanged = prevStyle !== currentStyle;
74
+ if (scriptChanged || scriptSetupChanged) {
75
+ return "script";
76
+ }
77
+ if (styleChanged && !templateChanged) {
78
+ return "style-only";
79
+ }
80
+ if (templateChanged) {
81
+ return "template-only";
82
+ }
83
+ return "full";
84
+ }, generateVueHmrId = (sourceFilePath, vueRootDir) => {
85
+ return relative2(vueRootDir, sourceFilePath).replace(/\\/g, "/").replace(/\.vue$/, "");
86
+ }, clearVueHmrCaches = () => {
87
+ scriptCache.clear();
88
+ scriptSetupCache.clear();
89
+ templateCache.clear();
90
+ styleCache.clear();
91
+ vueHmrMetadata.clear();
92
+ }, extractImports = (sourceCode) => Array.from(sourceCode.matchAll(/import\s+[\s\S]+?['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((importPath) => importPath !== undefined), toJs = (filePath) => {
165
93
  if (filePath.endsWith(".vue"))
166
94
  return filePath.replace(/\.vue$/, ".js");
167
95
  if (filePath.endsWith(".ts"))
168
96
  return filePath.replace(/\.ts$/, ".js");
169
97
  return `${filePath}.js`;
170
- };
171
- var stripExports = (code) => code.replace(/export\s+default/, "const script =").replace(/^export\s+/gm, "");
172
- var mergeVueImports = (code) => {
98
+ }, stripExports = (code) => code.replace(/export\s+default/, "const script =").replace(/^export\s+/gm, ""), mergeVueImports = (code) => {
173
99
  const lines = code.split(`
174
100
  `);
175
101
  const specifierSet = new Set;
@@ -186,8 +112,7 @@ var mergeVueImports = (code) => {
186
112
  ].join(`
187
113
  `) : nonVueLines.join(`
188
114
  `);
189
- };
190
- var compileVueFile = async (sourceFilePath, outputDirs, cacheMap, isEntryPoint, vueRootDir) => {
115
+ }, compileVueFile = async (sourceFilePath, outputDirs, cacheMap, isEntryPoint, vueRootDir) => {
191
116
  const cachedResult = cacheMap.get(sourceFilePath);
192
117
  if (cachedResult)
193
118
  return cachedResult;
@@ -197,6 +122,9 @@ var compileVueFile = async (sourceFilePath, outputDirs, cacheMap, isEntryPoint,
197
122
  const componentId = toKebab(fileBaseName);
198
123
  const sourceContent = await file2(sourceFilePath).text();
199
124
  const { descriptor } = parse(sourceContent, { filename: sourceFilePath });
125
+ const hmrId = generateVueHmrId(sourceFilePath, vueRootDir);
126
+ const changeType = detectVueChangeType(sourceFilePath, descriptor);
127
+ vueHmrMetadata.set(sourceFilePath, { hmrId, changeType });
200
128
  const scriptSource = descriptor.scriptSetup?.content ?? descriptor.script?.content ?? "";
201
129
  const importPaths = extractImports(scriptSource);
202
130
  const childComponentPaths = importPaths.filter((path) => path.startsWith(".") && path.endsWith(".vue"));
@@ -239,15 +167,31 @@ var compileVueFile = async (sourceFilePath, outputDirs, cacheMap, isEntryPoint,
239
167
  `));
240
168
  cssOutputPaths = [cssOutputFile];
241
169
  }
242
- const assembleModule = (renderCode, renderFnName) => mergeVueImports([
243
- transpiledScript,
244
- renderCode,
245
- `script.${renderFnName} = ${renderFnName};`,
246
- "export default script;"
247
- ].join(`
170
+ const assembleModule = (renderCode, renderFnName, includeHmr) => {
171
+ const hasScoped = descriptor.styles.some((styleBlock) => styleBlock.scoped);
172
+ const scopeIdCode = hasScoped ? `script.__scopeId = "data-v-${componentId}";` : "";
173
+ const hmrCode = includeHmr ? `
174
+ // Vue Native HMR Registration
175
+ script.__hmrId = ${JSON.stringify(hmrId)};
176
+ if (typeof __VUE_HMR_RUNTIME__ !== 'undefined') {
177
+ __VUE_HMR_RUNTIME__.createRecord(script.__hmrId, script);
178
+ if (typeof window !== 'undefined') {
179
+ window.__VUE_HMR_COMPONENTS__ = window.__VUE_HMR_COMPONENTS__ || {};
180
+ window.__VUE_HMR_COMPONENTS__[script.__hmrId] = script;
181
+ }
182
+ }` : "";
183
+ return mergeVueImports([
184
+ transpiledScript,
185
+ renderCode,
186
+ `script.${renderFnName} = ${renderFnName};`,
187
+ scopeIdCode,
188
+ hmrCode,
189
+ "export default script;"
190
+ ].join(`
248
191
  `));
249
- const clientCode = assembleModule(generateRenderFunction(false), "render");
250
- const serverCode = assembleModule(generateRenderFunction(true), "ssrRender");
192
+ };
193
+ const clientCode = assembleModule(generateRenderFunction(false), "render", true);
194
+ const serverCode = assembleModule(generateRenderFunction(true), "ssrRender", false);
251
195
  const clientOutputPath = join2(outputDirs.client, `${relativeWithoutExtension}.js`);
252
196
  const serverOutputPath = join2(outputDirs.server, `${relativeWithoutExtension}.js`);
253
197
  await mkdir2(dirname2(clientOutputPath), { recursive: true });
@@ -262,12 +206,12 @@ var compileVueFile = async (sourceFilePath, outputDirs, cacheMap, isEntryPoint,
262
206
  tsHelperPaths: [
263
207
  ...helperModulePaths.map((helper) => resolve2(dirname2(sourceFilePath), helper.endsWith(".ts") ? helper : `${helper}.ts`)),
264
208
  ...childBuildResults.flatMap((child) => child.tsHelperPaths)
265
- ]
209
+ ],
210
+ hmrId
266
211
  };
267
212
  cacheMap.set(sourceFilePath, result);
268
213
  return result;
269
- };
270
- var compileVue = async (entryPoints, vueRootDir) => {
214
+ }, compileVue = async (entryPoints, vueRootDir, isDev = false) => {
271
215
  const compiledOutputRoot = join2(vueRootDir, "compiled");
272
216
  const clientOutputDir = join2(compiledOutputRoot, "client");
273
217
  const indexOutputDir = join2(compiledOutputRoot, "indexes");
@@ -292,14 +236,92 @@ var compileVue = async (entryPoints, vueRootDir) => {
292
236
  const indexOutputFile = join2(indexOutputDir, `${entryBaseName}.js`);
293
237
  const clientOutputFile = join2(clientOutputDir, relative2(vueRootDir, entryPath).replace(/\\/g, "/").replace(/\.vue$/, ".js"));
294
238
  await mkdir2(dirname2(indexOutputFile), { recursive: true });
239
+ const vueHmrImports = isDev ? [
240
+ `window.__HMR_FRAMEWORK__ = "vue";`,
241
+ `import "${hmrClientPath2}";`
242
+ ] : [];
295
243
  await write2(indexOutputFile, [
244
+ ...vueHmrImports,
296
245
  `import Comp from "${relative2(dirname2(indexOutputFile), clientOutputFile).replace(/\\/g, "/")}";`,
297
246
  'import { createSSRApp } from "vue";',
298
- "const props = window.__INITIAL_PROPS__ ?? {};",
299
- 'createSSRApp(Comp, props).mount("#root");'
247
+ "",
248
+ "// HMR State Preservation: Check for preserved state from HMR",
249
+ 'let preservedState = (typeof window !== "undefined" && window.__HMR_PRESERVED_STATE__) ? window.__HMR_PRESERVED_STATE__ : {};',
250
+ "",
251
+ "// Fallback: check sessionStorage if window state is empty",
252
+ 'if (typeof window !== "undefined" && Object.keys(preservedState).length === 0) {',
253
+ " try {",
254
+ ' const stored = sessionStorage.getItem("__VUE_HMR_STATE__");',
255
+ " if (stored) {",
256
+ " preservedState = JSON.parse(stored);",
257
+ ' sessionStorage.removeItem("__VUE_HMR_STATE__");',
258
+ " }",
259
+ " } catch (e) {}",
260
+ "}",
261
+ "",
262
+ "const mergedProps = { ...(window.__INITIAL_PROPS__ ?? {}), ...preservedState };",
263
+ "",
264
+ "// Use createSSRApp for proper hydration of server-rendered content",
265
+ "const app = createSSRApp(Comp, mergedProps);",
266
+ 'app.mount("#root");',
267
+ "",
268
+ "// Store app instance for HMR - used for manual component updates",
269
+ 'if (typeof window !== "undefined") {',
270
+ " window.__VUE_APP__ = app;",
271
+ "}",
272
+ "",
273
+ "// Post-mount: Apply preserved state to reactive refs in component tree",
274
+ "// This restores state that lives in refs (like count) rather than props",
275
+ 'if (typeof window !== "undefined" && Object.keys(preservedState).length > 0) {',
276
+ " requestAnimationFrame(function() {",
277
+ " if (window.__VUE_APP__ && window.__VUE_APP__._instance) {",
278
+ " applyPreservedState(window.__VUE_APP__._instance, preservedState);",
279
+ " }",
280
+ " });",
281
+ "}",
282
+ "",
283
+ "function applyPreservedState(instance, state) {",
284
+ " // Apply to root component setupState",
285
+ " if (instance.setupState) {",
286
+ " Object.keys(state).forEach(function(key) {",
287
+ " const ref = instance.setupState[key];",
288
+ ' if (ref && typeof ref === "object" && "value" in ref) {',
289
+ " ref.value = state[key];",
290
+ " }",
291
+ " });",
292
+ " }",
293
+ " // Also apply to child components",
294
+ " if (instance.subTree) {",
295
+ " walkAndApply(instance.subTree, state);",
296
+ " }",
297
+ "}",
298
+ "",
299
+ "function walkAndApply(vnode, state) {",
300
+ " if (!vnode) return;",
301
+ " if (vnode.component && vnode.component.setupState) {",
302
+ " Object.keys(state).forEach(function(key) {",
303
+ " const ref = vnode.component.setupState[key];",
304
+ ' if (ref && typeof ref === "object" && "value" in ref) {',
305
+ " ref.value = state[key];",
306
+ " }",
307
+ " });",
308
+ " }",
309
+ " if (vnode.children && Array.isArray(vnode.children)) {",
310
+ " vnode.children.forEach(function(child) { walkAndApply(child, state); });",
311
+ " }",
312
+ " if (vnode.component && vnode.component.subTree) {",
313
+ " walkAndApply(vnode.component.subTree, state);",
314
+ " }",
315
+ "}",
316
+ "",
317
+ "// Clear preserved state after applying",
318
+ 'if (typeof window !== "undefined") {',
319
+ " window.__HMR_PRESERVED_STATE__ = undefined;",
320
+ "}"
300
321
  ].join(`
301
322
  `));
302
323
  return {
324
+ clientPath: clientOutputFile,
303
325
  cssPaths: result.cssPaths,
304
326
  indexPath: indexOutputFile,
305
327
  serverPath: result.serverPath
@@ -317,97 +339,901 @@ var compileVue = async (entryPoints, vueRootDir) => {
317
339
  await write2(outServerPath, transpiledCode);
318
340
  }));
319
341
  return {
342
+ vueClientPaths: compiledPages.map((result) => result.clientPath),
320
343
  vueCssPaths: compiledPages.flatMap((result) => result.cssPaths),
321
344
  vueIndexPaths: compiledPages.map((result) => result.indexPath),
322
- vueServerPaths: compiledPages.map((result) => result.serverPath)
345
+ vueServerPaths: compiledPages.map((result) => result.serverPath),
346
+ hmrMetadata: new Map(vueHmrMetadata)
323
347
  };
324
348
  };
349
+ var init_compileVue = __esm(() => {
350
+ hmrClientPath2 = resolve2(import.meta.dir, "../dev/client/hmrClient.ts").replace(/\\/g, "/");
351
+ transpiler2 = new Transpiler2({ loader: "ts", target: "browser" });
352
+ scriptCache = new Map;
353
+ scriptSetupCache = new Map;
354
+ templateCache = new Map;
355
+ styleCache = new Map;
356
+ vueHmrMetadata = new Map;
357
+ });
325
358
 
326
- // src/build/generateManifest.ts
327
- import { extname as extname2 } from "path";
328
- var generateManifest = (outputs, buildPath) => outputs.reduce((manifest, artifact) => {
329
- let relative3 = artifact.path.startsWith(buildPath) ? artifact.path.slice(buildPath.length) : artifact.path;
330
- relative3 = relative3.replace(/\\/g, "/").replace(/^\/+/, "");
331
- const segments = relative3.split("/");
332
- const fileWithHash = segments.pop();
333
- if (!fileWithHash)
334
- return manifest;
335
- const [baseName] = fileWithHash.split(`.${artifact.hash}.`);
336
- if (!baseName)
337
- return manifest;
338
- const pascalName = toPascal(baseName);
339
- const ext = extname2(fileWithHash);
340
- if (ext === ".css") {
341
- manifest[`${pascalName}CSS`] = `/${relative3}`;
342
- return manifest;
343
- }
344
- const idx = segments.findIndex((seg) => seg === "indexes" || seg === "pages");
345
- const folder = idx > UNFOUND_INDEX ? segments[idx] : segments[0];
346
- if (folder === "indexes") {
347
- manifest[`${pascalName}Index`] = `/${relative3}`;
348
- } else if (folder === "pages") {
349
- manifest[pascalName] = artifact.path;
350
- } else {
351
- manifest[pascalName] = `/${relative3}`;
352
- }
353
- return manifest;
354
- }, {});
355
-
356
- // src/build/generateReactIndexes.ts
357
- import { mkdir as mkdir3, rm, writeFile } from "fs/promises";
358
- import { basename as basename3, join as join3 } from "path";
359
- var {Glob } = globalThis.Bun;
360
- var generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory) => {
361
- await rm(reactIndexesDirectory, { force: true, recursive: true });
362
- await mkdir3(reactIndexesDirectory);
363
- const pagesGlob = new Glob("*.*");
364
- const files = [];
365
- for await (const file3 of pagesGlob.scan({ cwd: reactPagesDirectory })) {
366
- files.push(file3);
359
+ // src/dev/simpleHTMLHMR.ts
360
+ var exports_simpleHTMLHMR = {};
361
+ __export(exports_simpleHTMLHMR, {
362
+ handleHTMLUpdate: () => handleHTMLUpdate
363
+ });
364
+ import { readFileSync as readFileSync4, existsSync as existsSync3 } from "fs";
365
+ import { resolve as resolve13 } from "path";
366
+ var handleHTMLUpdate = async (htmlFilePath) => {
367
+ try {
368
+ const resolvedPath = resolve13(htmlFilePath);
369
+ if (!existsSync3(resolvedPath)) {
370
+ return null;
371
+ }
372
+ const htmlContent = readFileSync4(resolvedPath, "utf-8");
373
+ const headMatch = htmlContent.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
374
+ const bodyMatch = htmlContent.match(/<body[^>]*>([\s\S]*)<\/body>/i);
375
+ if (bodyMatch && bodyMatch[1]) {
376
+ const bodyContent = bodyMatch[1].trim();
377
+ const headContent = headMatch && headMatch[1] ? headMatch[1].trim() : null;
378
+ return {
379
+ body: bodyContent,
380
+ head: headContent
381
+ };
382
+ }
383
+ return htmlContent;
384
+ } catch {
385
+ return null;
367
386
  }
368
- const promises = files.map(async (file3) => {
369
- const fileName = basename3(file3);
370
- const [componentName] = fileName.split(".");
371
- const content = [
372
- `import { hydrateRoot } from 'react-dom/client';`,
373
- `import type { ComponentType } from 'react'`,
374
- `import { ${componentName} } from '../pages/${componentName}';
375
- `,
376
- `type PropsOf<C> = C extends ComponentType<infer P> ? P : never;
377
- `,
378
- `declare global {`,
379
- ` interface Window {`,
380
- ` __INITIAL_PROPS__: PropsOf<typeof ${componentName}>`,
381
- ` }`,
382
- `}
383
- `,
384
- `hydrateRoot(document, <${componentName} {...window.__INITIAL_PROPS__} />);`
385
- ].join(`
386
- `);
387
- return writeFile(join3(reactIndexesDirectory, `${componentName}.tsx`), content);
388
- });
389
- await Promise.all(promises);
390
387
  };
388
+ var init_simpleHTMLHMR = () => {};
391
389
 
392
- // src/build/outputLogs.ts
393
- var outputLogs = (logs) => {
394
- for (const log of logs) {
395
- if (log.message.includes(BUN_BUILD_WARNING_SUPPRESSION))
396
- continue;
397
- if (log.level === "error")
398
- console.error(log);
399
- else if (log.level === "warning")
400
- console.warn(log);
401
- else
402
- console.info(log);
390
+ // src/utils/escapeScriptContent.ts
391
+ var ESCAPE_LOOKUP, ESCAPE_REGEX, escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
392
+ const escaped = ESCAPE_LOOKUP[char];
393
+ return escaped !== undefined ? escaped : char;
394
+ });
395
+ var init_escapeScriptContent = __esm(() => {
396
+ ESCAPE_LOOKUP = {
397
+ "\u2028": "\\u2028",
398
+ "\u2029": "\\u2029",
399
+ "&": "\\u0026",
400
+ "<": "\\u003C",
401
+ ">": "\\u003E"
402
+ };
403
+ ESCAPE_REGEX = /[&><\u2028\u2029]/g;
404
+ });
405
+
406
+ // src/svelte/renderToReadableStream.ts
407
+ import { render } from "svelte/server";
408
+ var renderToReadableStream = async (component, props, {
409
+ bootstrapScriptContent,
410
+ bootstrapScripts = [],
411
+ bootstrapModules = [],
412
+ nonce,
413
+ onError = console.error,
414
+ progressiveChunkSize = DEFAULT_CHUNK_SIZE,
415
+ signal,
416
+ headContent,
417
+ bodyContent
418
+ } = {}) => {
419
+ try {
420
+ const { head, body } = typeof props === "undefined" ? render(component) : render(component, { props });
421
+ const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
422
+ const scripts = (bootstrapScriptContent ? `<script${nonceAttr}>${escapeScriptContent(bootstrapScriptContent)}</script>` : "") + bootstrapScripts.map((src) => `<script${nonceAttr} src="${src}"></script>`).join("") + bootstrapModules.map((src) => `<script${nonceAttr} type="module" src="${src}"></script>`).join("");
423
+ const encoder = new TextEncoder;
424
+ const full = encoder.encode(`<!DOCTYPE html><html lang="en"><head>${head}${headContent ?? ""}</head><body>${body}${scripts}${bodyContent ?? ""}</body></html>`);
425
+ let offset = 0;
426
+ return new ReadableStream({
427
+ type: "bytes",
428
+ cancel(reason) {
429
+ onError?.(reason);
430
+ },
431
+ pull(controller) {
432
+ if (signal?.aborted) {
433
+ controller.close();
434
+ return;
435
+ }
436
+ if (offset >= full.length) {
437
+ controller.close();
438
+ return;
439
+ }
440
+ const end = Math.min(offset + progressiveChunkSize, full.length);
441
+ controller.enqueue(full.subarray(offset, end));
442
+ offset = end;
443
+ }
444
+ });
445
+ } catch (error) {
446
+ onError?.(error);
447
+ throw error;
403
448
  }
404
449
  };
450
+ var init_renderToReadableStream = __esm(() => {
451
+ init_constants();
452
+ init_escapeScriptContent();
453
+ });
405
454
 
406
- // src/build/scanEntryPoints.ts
407
- var {Glob: Glob2 } = globalThis.Bun;
408
- var scanEntryPoints = async (dir, pattern) => {
409
- const entryPaths = [];
410
- const glob = new Glob2(pattern);
455
+ // src/core/pageHandlers.ts
456
+ var exports_pageHandlers = {};
457
+ __export(exports_pageHandlers, {
458
+ handleVuePageRequest: () => handleVuePageRequest,
459
+ handleSveltePageRequest: () => handleSveltePageRequest,
460
+ handleReactPageRequest: () => handleReactPageRequest,
461
+ handlePageRequest: () => handlePageRequest,
462
+ handleHTMXPageRequest: () => handleHTMXPageRequest,
463
+ handleHTMLPageRequest: () => handleHTMLPageRequest
464
+ });
465
+ var {file: file3 } = globalThis.Bun;
466
+ import { createElement } from "react";
467
+ import { renderToReadableStream as renderReactToReadableStream } from "react-dom/server";
468
+ import { createSSRApp, h } from "vue";
469
+ import { renderToWebStream as renderVueToWebStream } from "vue/server-renderer";
470
+ var handleReactPageRequest = async (PageComponent, index, ...props) => {
471
+ const [maybeProps] = props;
472
+ const element = maybeProps !== undefined ? createElement(PageComponent, maybeProps) : createElement(PageComponent);
473
+ const stream = await renderReactToReadableStream(element, {
474
+ bootstrapModules: [index],
475
+ bootstrapScriptContent: maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)}` : undefined
476
+ });
477
+ return new Response(stream, {
478
+ headers: { "Content-Type": "text/html" }
479
+ });
480
+ }, handleSveltePageRequest = async (_PageComponent, pagePath, indexPath, props) => {
481
+ const { default: ImportedPageComponent } = await import(pagePath);
482
+ const stream = await renderToReadableStream(ImportedPageComponent, props, {
483
+ bootstrapModules: indexPath ? [indexPath] : [],
484
+ bootstrapScriptContent: `window.__INITIAL_PROPS__=${JSON.stringify(props)}`
485
+ });
486
+ return new Response(stream, {
487
+ headers: { "Content-Type": "text/html" }
488
+ });
489
+ }, handleVuePageRequest = async (_PageComponent, pagePath, indexPath, headTag = "<head></head>", ...props) => {
490
+ const [maybeProps] = props;
491
+ const { default: ImportedPageComponent } = await import(pagePath);
492
+ const app = createSSRApp({
493
+ render: () => h(ImportedPageComponent, maybeProps ?? null)
494
+ });
495
+ const bodyStream = renderVueToWebStream(app);
496
+ const head = `<!DOCTYPE html><html>${headTag}<body><div id="root">`;
497
+ const tail = `</div><script>window.__INITIAL_PROPS__=${JSON.stringify(maybeProps ?? {})}</script><script type="module" src="${indexPath}"></script></body></html>`;
498
+ const stream = new ReadableStream({
499
+ start(controller) {
500
+ controller.enqueue(head);
501
+ const reader = bodyStream.getReader();
502
+ const pumpLoop = () => {
503
+ reader.read().then(({ done, value }) => done ? (controller.enqueue(tail), controller.close()) : (controller.enqueue(value), pumpLoop())).catch((err) => controller.error(err));
504
+ };
505
+ pumpLoop();
506
+ }
507
+ });
508
+ return new Response(stream, {
509
+ headers: { "Content-Type": "text/html" }
510
+ });
511
+ }, handleHTMLPageRequest = (pagePath) => file3(pagePath), handleHTMXPageRequest = (pagePath) => file3(pagePath), handlePageRequest = (PageComponent, ...props) => {
512
+ console.log("handlePageRequest coming soon.", PageComponent, props);
513
+ };
514
+ var init_pageHandlers = __esm(() => {
515
+ init_renderToReadableStream();
516
+ });
517
+
518
+ // src/utils/generateHeadElement.ts
519
+ var exports_generateHeadElement = {};
520
+ __export(exports_generateHeadElement, {
521
+ generateHeadElement: () => generateHeadElement
522
+ });
523
+ var generateHeadElement = ({
524
+ cssPath,
525
+ title = "AbsoluteJS",
526
+ description = "A page created using AbsoluteJS",
527
+ font,
528
+ icon = "/assets/ico/favicon.ico"
529
+ } = {}) => `<head>
530
+ <meta charset="UTF-8">
531
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
532
+ <title>${title}</title>
533
+ <meta name="description" content="${description}">
534
+ <link rel="icon" href="${icon}" type="image/x-icon">
535
+ ${font ? `<link rel="preconnect" href="https://fonts.googleapis.com">
536
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
537
+ <link href="https://fonts.googleapis.com/css2?family=${font}:wght@100..900&display=swap" rel="stylesheet">` : ""}
538
+ ${cssPath ? `<link rel="stylesheet" href="${cssPath}" type="text/css">` : ""}
539
+ </head>`;
540
+
541
+ // src/dev/simpleVueHMR.ts
542
+ var exports_simpleVueHMR = {};
543
+ __export(exports_simpleVueHMR, {
544
+ handleVueUpdate: () => handleVueUpdate
545
+ });
546
+ import { basename as basename6, join as join7, resolve as resolve14 } from "path";
547
+ var handleVueUpdate = async (vueFilePath, manifest, buildDir) => {
548
+ try {
549
+ const resolvedPath = resolve14(vueFilePath);
550
+ const fileName = basename6(resolvedPath);
551
+ const baseName = fileName.replace(/\.vue$/, "");
552
+ const pascalName = toPascal(baseName);
553
+ const componentKey = pascalName;
554
+ const indexKey = `${pascalName}Index`;
555
+ const cssKey = `${pascalName}CSS`;
556
+ const serverPath = manifest[componentKey];
557
+ if (!serverPath) {
558
+ console.warn("[Vue HMR] Server path not found in manifest for:", componentKey);
559
+ console.warn("[Vue HMR] Available manifest keys:", Object.keys(manifest).join(", "));
560
+ return null;
561
+ }
562
+ const absoluteServerPath = resolve14(serverPath) === serverPath || serverPath.startsWith("/") || /^[A-Za-z]:[\\/]/.test(serverPath) ? serverPath : join7(buildDir || process.cwd(), serverPath.replace(/^\//, ""));
563
+ const cacheBuster = `?t=${Date.now()}`;
564
+ const serverModule = await import(`${absoluteServerPath}${cacheBuster}`);
565
+ if (!serverModule || !serverModule.default) {
566
+ console.warn("[Vue HMR] Module has no default export:", absoluteServerPath);
567
+ return null;
568
+ }
569
+ const indexPath = manifest[indexKey];
570
+ if (!indexPath) {
571
+ console.warn("[Vue HMR] Index path not found in manifest for:", indexKey);
572
+ return null;
573
+ }
574
+ const { handleVuePageRequest: handleVuePageRequest2 } = await Promise.resolve().then(() => (init_pageHandlers(), exports_pageHandlers));
575
+ const { generateHeadElement: generateHeadElement2 } = await Promise.resolve().then(() => exports_generateHeadElement);
576
+ const response = await handleVuePageRequest2(serverModule.default, serverPath, indexPath, generateHeadElement2({
577
+ cssPath: manifest[cssKey] || "",
578
+ title: "AbsoluteJS + Vue"
579
+ }), { initialCount: 0 });
580
+ const html = await response.text();
581
+ const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
582
+ if (bodyMatch && bodyMatch[1]) {
583
+ const bodyContent = bodyMatch[1].trim();
584
+ return bodyContent;
585
+ }
586
+ return html;
587
+ } catch (err) {
588
+ console.error("[Vue HMR] Error in handleVueUpdate:", err);
589
+ return null;
590
+ }
591
+ };
592
+ var init_simpleVueHMR = () => {};
593
+
594
+ // src/dev/simpleSvelteHMR.ts
595
+ var exports_simpleSvelteHMR = {};
596
+ __export(exports_simpleSvelteHMR, {
597
+ handleSvelteUpdate: () => handleSvelteUpdate
598
+ });
599
+ import { basename as basename7, join as join8, resolve as resolve15 } from "path";
600
+ var handleSvelteUpdate = async (svelteFilePath, manifest, buildDir) => {
601
+ try {
602
+ const resolvedPath = resolve15(svelteFilePath);
603
+ const fileName = basename7(resolvedPath);
604
+ const baseName = fileName.replace(/\.svelte$/, "");
605
+ const pascalName = toPascal(baseName);
606
+ const componentKey = pascalName;
607
+ const indexKey = `${pascalName}Index`;
608
+ const cssKey = `${pascalName}CSS`;
609
+ const serverPath = manifest[componentKey];
610
+ if (!serverPath) {
611
+ console.warn("[Svelte HMR] Server path not found in manifest for:", componentKey);
612
+ console.warn("[Svelte HMR] Available manifest keys:", Object.keys(manifest).join(", "));
613
+ return null;
614
+ }
615
+ const absoluteServerPath = resolve15(serverPath) === serverPath || serverPath.startsWith("/") || /^[A-Za-z]:[\\/]/.test(serverPath) ? serverPath : join8(buildDir || process.cwd(), serverPath.replace(/^\//, ""));
616
+ const cacheBuster = `?t=${Date.now()}`;
617
+ const serverModule = await import(`${absoluteServerPath}${cacheBuster}`);
618
+ if (!serverModule || !serverModule.default) {
619
+ console.warn("[Svelte HMR] Module has no default export:", absoluteServerPath);
620
+ return null;
621
+ }
622
+ const indexPath = manifest[indexKey];
623
+ if (!indexPath) {
624
+ console.warn("[Svelte HMR] Index path not found in manifest for:", indexKey);
625
+ return null;
626
+ }
627
+ const { handleSveltePageRequest: handleSveltePageRequest2 } = await Promise.resolve().then(() => (init_pageHandlers(), exports_pageHandlers));
628
+ const response = await handleSveltePageRequest2(serverModule.default, serverPath, indexPath, {
629
+ cssPath: manifest[cssKey] || "",
630
+ initialCount: 0
631
+ });
632
+ const html = await response.text();
633
+ const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
634
+ if (bodyMatch && bodyMatch[1]) {
635
+ const bodyContent = bodyMatch[1].trim();
636
+ return bodyContent;
637
+ }
638
+ return html;
639
+ } catch (err) {
640
+ console.error("[Svelte HMR] Error in handleSvelteUpdate:", err);
641
+ return null;
642
+ }
643
+ };
644
+ var init_simpleSvelteHMR = () => {};
645
+
646
+ // src/dev/simpleHTMXHMR.ts
647
+ var exports_simpleHTMXHMR = {};
648
+ __export(exports_simpleHTMXHMR, {
649
+ handleHTMXUpdate: () => handleHTMXUpdate
650
+ });
651
+ import { readFileSync as readFileSync5, existsSync as existsSync4 } from "fs";
652
+ import { resolve as resolve16 } from "path";
653
+ var handleHTMXUpdate = async (htmxFilePath) => {
654
+ try {
655
+ const resolvedPath = resolve16(htmxFilePath);
656
+ if (!existsSync4(resolvedPath)) {
657
+ return null;
658
+ }
659
+ const htmlContent = readFileSync5(resolvedPath, "utf-8");
660
+ const headMatch = htmlContent.match(/<head[^>]*>([\s\S]*?)<\/head>/i);
661
+ const bodyMatch = htmlContent.match(/<body[^>]*>([\s\S]*)<\/body>/i);
662
+ if (bodyMatch && bodyMatch[1]) {
663
+ const bodyContent = bodyMatch[1].trim();
664
+ const headContent = headMatch && headMatch[1] ? headMatch[1].trim() : null;
665
+ return {
666
+ body: bodyContent,
667
+ head: headContent
668
+ };
669
+ }
670
+ return htmlContent;
671
+ } catch {
672
+ return null;
673
+ }
674
+ };
675
+ var init_simpleHTMXHMR = () => {};
676
+ // types/client.ts
677
+ var hmrState = {
678
+ isConnected: false,
679
+ isFirstHMRUpdate: true,
680
+ isHMRUpdating: false,
681
+ pingInterval: null,
682
+ reconnectTimeout: null
683
+ };
684
+ // types/messages.ts
685
+ var isValidHMRClientMessage = (data) => {
686
+ if (!data || typeof data !== "object") {
687
+ return false;
688
+ }
689
+ const message = data;
690
+ if (!("type" in message) || typeof message.type !== "string") {
691
+ return false;
692
+ }
693
+ switch (message.type) {
694
+ case "ping":
695
+ return true;
696
+ case "ready":
697
+ return true;
698
+ case "request-rebuild":
699
+ return true;
700
+ case "hydration-error":
701
+ return true;
702
+ default:
703
+ return false;
704
+ }
705
+ };
706
+ // types/websocket.ts
707
+ var WS_READY_STATE_OPEN = 1;
708
+ // src/index.ts
709
+ init_constants();
710
+
711
+ // src/core/build.ts
712
+ import {
713
+ copyFileSync,
714
+ cpSync,
715
+ mkdirSync,
716
+ readFileSync,
717
+ writeFileSync
718
+ } from "fs";
719
+ import { rm as rm3 } from "fs/promises";
720
+ import { basename as basename4, join as join5, resolve as resolve6 } from "path";
721
+ import { cwd, env as env2, exit } from "process";
722
+ var {$, build: bunBuild2, Glob: Glob3 } = globalThis.Bun;
723
+
724
+ // src/build/compileSvelte.ts
725
+ import { mkdir, stat } from "fs/promises";
726
+ import {
727
+ dirname,
728
+ join,
729
+ basename,
730
+ extname,
731
+ resolve,
732
+ relative,
733
+ sep
734
+ } from "path";
735
+ import { env } from "process";
736
+ var {write, file, Transpiler } = globalThis.Bun;
737
+ import { compile, compileModule, preprocess } from "svelte/compiler";
738
+ var hmrClientPath = resolve(import.meta.dir, "../dev/client/hmrClient.ts").replace(/\\/g, "/");
739
+ var transpiler = new Transpiler({ loader: "ts", target: "browser" });
740
+ var exists = async (path) => {
741
+ try {
742
+ await stat(path);
743
+ return true;
744
+ } catch {
745
+ return false;
746
+ }
747
+ };
748
+ var resolveSvelte = async (spec, from) => {
749
+ const basePath = resolve(dirname(from), spec);
750
+ const explicit = /\.(svelte|svelte\.(?:ts|js))$/.test(basePath);
751
+ if (!explicit) {
752
+ const extensions = [".svelte", ".svelte.ts", ".svelte.js"];
753
+ const paths = extensions.map((ext) => `${basePath}${ext}`);
754
+ const checks = await Promise.all(paths.map(exists));
755
+ const match = paths.find((_, index) => checks[index]);
756
+ return match ?? null;
757
+ }
758
+ if (await exists(basePath))
759
+ return basePath;
760
+ if (!basePath.endsWith(".svelte"))
761
+ return null;
762
+ const tsPath = `${basePath}.ts`;
763
+ if (await exists(tsPath))
764
+ return tsPath;
765
+ const jsPath = `${basePath}.js`;
766
+ if (await exists(jsPath))
767
+ return jsPath;
768
+ return null;
769
+ };
770
+ var compileSvelte = async (entryPoints, svelteRoot, cache = new Map, isDev = false) => {
771
+ const compiledRoot = join(svelteRoot, "compiled");
772
+ const clientDir = join(compiledRoot, "client");
773
+ const indexDir = join(compiledRoot, "indexes");
774
+ const pagesDir = join(compiledRoot, "pages");
775
+ await Promise.all([clientDir, indexDir, pagesDir].map((dir) => mkdir(dir, { recursive: true })));
776
+ const dev = env.NODE_ENV !== "production";
777
+ const build2 = async (src) => {
778
+ const memoized = cache.get(src);
779
+ if (memoized)
780
+ return memoized;
781
+ const raw = await file(src).text();
782
+ const isModule = src.endsWith(".svelte.ts") || src.endsWith(".svelte.js");
783
+ const preprocessed = isModule ? raw : (await preprocess(raw, {})).code;
784
+ const transpiled = src.endsWith(".ts") || src.endsWith(".svelte.ts") ? transpiler.transformSync(preprocessed) : preprocessed;
785
+ const relDir = dirname(relative(svelteRoot, src)).replace(/\\/g, "/");
786
+ const baseName = basename(src).replace(/\.svelte(\.(ts|js))?$/, "");
787
+ const importPaths = Array.from(transpiled.matchAll(/from\s+['"]([^'"]+)['"]/g)).map((match) => match[1]).filter((path) => path !== undefined);
788
+ const resolvedImports = await Promise.all(importPaths.map((importPath) => resolveSvelte(importPath, src)));
789
+ const childSources = resolvedImports.filter((path) => path !== null);
790
+ await Promise.all(childSources.map((child) => build2(child)));
791
+ const generate = (mode) => (isModule ? compileModule(transpiled, { dev, filename: src }).js.code : compile(transpiled, {
792
+ css: "injected",
793
+ dev,
794
+ filename: src,
795
+ generate: mode
796
+ }).js.code).replace(/\.svelte(?:\.(?:ts|js))?(['"])/g, ".js$1");
797
+ const ssrPath = join(pagesDir, relDir, `${baseName}.js`);
798
+ const clientPath = join(clientDir, relDir, `${baseName}.js`);
799
+ await Promise.all([
800
+ mkdir(dirname(ssrPath), { recursive: true }),
801
+ mkdir(dirname(clientPath), { recursive: true })
802
+ ]);
803
+ if (isModule) {
804
+ const bundle = generate("client");
805
+ await Promise.all([
806
+ write(ssrPath, bundle),
807
+ write(clientPath, bundle)
808
+ ]);
809
+ } else {
810
+ const serverBundle = generate("server");
811
+ const clientBundle = generate("client");
812
+ await Promise.all([
813
+ write(ssrPath, serverBundle),
814
+ write(clientPath, clientBundle)
815
+ ]);
816
+ }
817
+ const built = { client: clientPath, ssr: ssrPath };
818
+ cache.set(src, built);
819
+ return built;
820
+ };
821
+ const roots = await Promise.all(entryPoints.map(build2));
822
+ await Promise.all(roots.map(async ({ client: client2 }) => {
823
+ const relClientDir = dirname(relative(clientDir, client2));
824
+ const name = basename(client2, extname(client2));
825
+ const indexPath = join(indexDir, relClientDir, `${name}.js`);
826
+ const importRaw = relative(dirname(indexPath), client2).split(sep).join("/");
827
+ const importPath = importRaw.startsWith(".") || importRaw.startsWith("/") ? importRaw : `./${importRaw}`;
828
+ const hmrImports = isDev ? `window.__HMR_FRAMEWORK__ = "svelte";
829
+ import "${hmrClientPath}";
830
+ ` : "";
831
+ const bootstrap = `${hmrImports}import Component from "${importPath}";
832
+ import { hydrate, mount, unmount } from "svelte";
833
+
834
+ var initialProps = (typeof window !== "undefined" && window.__INITIAL_PROPS__) ? window.__INITIAL_PROPS__ : {};
835
+ var isHMR = typeof window !== "undefined" && window.__SVELTE_COMPONENT__ !== undefined;
836
+ var component;
837
+
838
+ if (isHMR) {
839
+ var headLinks = document.querySelectorAll('link[rel="stylesheet"]');
840
+ var preservedLinks = [];
841
+ headLinks.forEach(function(link) {
842
+ var clone = link.cloneNode(true);
843
+ clone.setAttribute("data-hmr-preserve", "true");
844
+ document.head.appendChild(clone);
845
+ preservedLinks.push(clone);
846
+ });
847
+ if (typeof window.__SVELTE_UNMOUNT__ === "function") {
848
+ try { window.__SVELTE_UNMOUNT__(); } catch (err) { console.warn("[HMR] unmount error:", err); }
849
+ }
850
+ var preservedState = window.__HMR_PRESERVED_STATE__;
851
+ if (!preservedState) {
852
+ try {
853
+ var stored = sessionStorage.getItem("__SVELTE_HMR_STATE__");
854
+ if (stored) preservedState = JSON.parse(stored);
855
+ } catch (err) { /* ignore */ }
856
+ }
857
+ var mergedProps = preservedState ? Object.assign({}, initialProps, preservedState) : initialProps;
858
+ component = mount(Component, { target: document.body, props: mergedProps });
859
+ requestAnimationFrame(function() {
860
+ preservedLinks.forEach(function(link) { link.remove(); });
861
+ });
862
+ window.__HMR_PRESERVED_STATE__ = undefined;
863
+ } else {
864
+ component = hydrate(Component, { target: document.body, props: initialProps });
865
+ }
866
+
867
+ if (typeof window !== "undefined") {
868
+ window.__SVELTE_COMPONENT__ = component;
869
+ window.__SVELTE_UNMOUNT__ = function() { unmount(component); };
870
+ }`;
871
+ await mkdir(dirname(indexPath), { recursive: true });
872
+ return write(indexPath, bootstrap);
873
+ }));
874
+ return {
875
+ svelteIndexPaths: roots.map(({ client: client2 }) => {
876
+ const rel = dirname(relative(clientDir, client2));
877
+ return join(indexDir, rel, basename(client2));
878
+ }),
879
+ svelteClientPaths: roots.map(({ client: client2 }) => client2),
880
+ svelteServerPaths: roots.map(({ ssr }) => ssr)
881
+ };
882
+ };
883
+
884
+ // src/core/build.ts
885
+ init_compileVue();
886
+
887
+ // src/build/generateManifest.ts
888
+ init_constants();
889
+ import { extname as extname2 } from "path";
890
+
891
+ // src/utils/normalizePath.ts
892
+ var normalizePath = (path) => path.replace(/\\/g, "/");
893
+
894
+ // src/build/generateManifest.ts
895
+ var generateManifest = (outputs, buildPath) => outputs.reduce((manifest, artifact) => {
896
+ const normalizedArtifactPath = normalizePath(artifact.path);
897
+ const normalizedBuildPath = normalizePath(buildPath);
898
+ let relative3 = normalizedArtifactPath.startsWith(normalizedBuildPath) ? normalizedArtifactPath.slice(normalizedBuildPath.length) : normalizedArtifactPath;
899
+ relative3 = relative3.replace(/^\/+/, "");
900
+ const segments = relative3.split("/");
901
+ const fileWithHash = segments.pop();
902
+ if (!fileWithHash)
903
+ return manifest;
904
+ const [baseName] = fileWithHash.split(`.${artifact.hash}.`);
905
+ if (!baseName)
906
+ return manifest;
907
+ const pascalName = toPascal(baseName);
908
+ const ext = extname2(fileWithHash);
909
+ if (ext === ".css") {
910
+ manifest[`${pascalName}CSS`] = `/${relative3}`;
911
+ return manifest;
912
+ }
913
+ const idx = segments.findIndex((seg) => seg === "indexes" || seg === "pages" || seg === "client");
914
+ const folder = idx > UNFOUND_INDEX ? segments[idx] : segments[0];
915
+ const isReact = segments.some((seg) => seg === "react");
916
+ const isVue = segments.some((seg) => seg === "vue");
917
+ const isSvelte = segments.some((seg) => seg === "svelte");
918
+ const isClientComponent = segments.includes("client");
919
+ if (folder === "indexes") {
920
+ manifest[`${pascalName}Index`] = `/${relative3}`;
921
+ } else if (isClientComponent) {
922
+ manifest[`${pascalName}Client`] = `/${relative3}`;
923
+ } else if (folder === "pages") {
924
+ if (isReact) {
925
+ manifest[`${pascalName}Page`] = `/${relative3}`;
926
+ } else if (isVue || isSvelte) {
927
+ manifest[pascalName] = `/${relative3}`;
928
+ } else {
929
+ manifest[`${pascalName}Page`] = `/${relative3}`;
930
+ }
931
+ } else {
932
+ manifest[pascalName] = `/${relative3}`;
933
+ }
934
+ return manifest;
935
+ }, {});
936
+
937
+ // src/build/generateReactIndexes.ts
938
+ import { mkdir as mkdir3, rm, writeFile } from "fs/promises";
939
+ import { basename as basename3, join as join3, resolve as resolve3 } from "path";
940
+ var {Glob } = globalThis.Bun;
941
+ var hmrClientPath3 = resolve3(import.meta.dir, "../dev/client/hmrClient.ts").replace(/\\/g, "/");
942
+ var refreshSetupPath = resolve3(import.meta.dir, "../dev/client/reactRefreshSetup.ts").replace(/\\/g, "/");
943
+ var generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory, isDev = false) => {
944
+ await rm(reactIndexesDirectory, { force: true, recursive: true });
945
+ await mkdir3(reactIndexesDirectory);
946
+ const pagesGlob = new Glob("*.*");
947
+ const files = [];
948
+ for await (const file3 of pagesGlob.scan({ cwd: reactPagesDirectory })) {
949
+ files.push(file3);
950
+ }
951
+ const promises = files.map(async (file3) => {
952
+ const fileName = basename3(file3);
953
+ const [componentName] = fileName.split(".");
954
+ const hmrPreamble = isDev ? [
955
+ `window.__HMR_FRAMEWORK__ = "react";`,
956
+ `window.__REACT_COMPONENT_KEY__ = "${componentName}Index";`,
957
+ `import '${refreshSetupPath}';`,
958
+ `import '${hmrClientPath3}';
959
+ `
960
+ ] : [];
961
+ const content = [
962
+ ...hmrPreamble,
963
+ `import { hydrateRoot, createRoot } from 'react-dom/client';`,
964
+ `import { createElement } from 'react';`,
965
+ `import type { ComponentType } from 'react'`,
966
+ `import { ${componentName} } from '../pages/${componentName}';
967
+ `,
968
+ `type PropsOf<C> = C extends ComponentType<infer P> ? P : never;
969
+ `,
970
+ `declare global {`,
971
+ ` interface Window {`,
972
+ ` __INITIAL_PROPS__?: PropsOf<typeof ${componentName}>`,
973
+ ` __REACT_ROOT__?: ReturnType<typeof hydrateRoot | typeof createRoot>`,
974
+ ` __HMR_CLIENT_ONLY_MODE__?: boolean`,
975
+ ` }`,
976
+ `}
977
+ `,
978
+ `// Hydration with error handling and fallback`,
979
+ `const isDev = ${isDev};`,
980
+ `const componentPath = '../pages/${componentName}';
981
+ `,
982
+ `function isHydrationError(error) {`,
983
+ ` if (!error) return false;`,
984
+ ` const errorMessage = error instanceof Error ? error.message : String(error);`,
985
+ ` const errorString = String(error);`,
986
+ ` const fullMessage = errorMessage + ' ' + errorString;`,
987
+ ` const hydrationKeywords = ['hydration', 'Hydration', 'mismatch', 'Mismatch', 'did not match', 'server rendered HTML', 'server HTML', 'client HTML', 'Hydration failed'];`,
988
+ ` const isHydration = hydrationKeywords.some(keyword => fullMessage.includes(keyword));`,
989
+ ` `,
990
+ ` // Ignore whitespace-only mismatches in <head> - these are harmless formatting differences`,
991
+ ` // The error often shows: + <link...> vs - {"\\n "} which is just formatting`,
992
+ ` if (isHydration) {`,
993
+ ` // Check if this is a head/link/stylesheet related mismatch`,
994
+ ` const isHeadRelated = fullMessage.includes('<head') || fullMessage.includes('</head>') || fullMessage.includes('head>') || fullMessage.includes('<link') || fullMessage.includes('link>') || fullMessage.includes('stylesheet') || fullMessage.includes('fonts.googleapis') || fullMessage.includes('rel="stylesheet"');`,
995
+ ` `,
996
+ ` // Check if the mismatch involves only whitespace/newlines`,
997
+ ` // Pattern: looks for {"\\n"} or {"\\n "} or similar whitespace-only content`,
998
+ ` // Also check for patterns like: - {"\\n "} or + <link...>`,
999
+ ` const hasWhitespacePattern = /\\{\\s*["']\\\\n[^"']*["']\\s*\\}/.test(fullMessage) || /\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage) || /-\\s*\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage);`,
1000
+ ` const isWhitespaceOnly = /^[\\s\\n\\r]*$/.test(errorString) || /^[\\s\\n\\r]*$/.test(errorMessage);`,
1001
+ ` const hasNewlinePattern = fullMessage.includes('\\\\n') || fullMessage.includes('\\\\r') || fullMessage.includes('\\n') || fullMessage.includes('\\r');`,
1002
+ ` `,
1003
+ ` // If it's head-related and involves whitespace/newlines, ignore it`,
1004
+ ` if (isHeadRelated && (hasWhitespacePattern || isWhitespaceOnly || hasNewlinePattern)) {`,
1005
+ ` return false; // Don't treat whitespace-only head mismatches as errors`,
1006
+ ` }`,
1007
+ ` }`,
1008
+ ` return isHydration;`,
1009
+ `}
1010
+ `,
1011
+ `function logHydrationError(error, componentName) {`,
1012
+ ` if (!isDev) return;`,
1013
+ ` if (window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN) {`,
1014
+ ` try {`,
1015
+ ` window.__HMR_WS__.send(JSON.stringify({`,
1016
+ ` type: 'hydration-error',`,
1017
+ ` data: {`,
1018
+ ` componentName: '${componentName}',`,
1019
+ ` componentPath: componentPath,`,
1020
+ ` error: error instanceof Error ? error.message : String(error),`,
1021
+ ` timestamp: Date.now()`,
1022
+ ` }`,
1023
+ ` }));`,
1024
+ ` } catch (err) {}`,
1025
+ ` }`,
1026
+ `}
1027
+ `,
1028
+ `// Track if we've already switched to client-only mode`,
1029
+ `let hasSwitchedToClientOnly = false;`,
1030
+ `let hydrationErrorDetected = false;
1031
+ `,
1032
+ `function handleHydrationFallback(error) {`,
1033
+ ` if (hasSwitchedToClientOnly) return; // Already handled`,
1034
+ ` hasSwitchedToClientOnly = true;`,
1035
+ ` hydrationErrorDetected = true;
1036
+ `,
1037
+ ` logHydrationError(error, '${componentName}');
1038
+ `,
1039
+ ` // Fallback: client-only render (no hydration)`,
1040
+ ` try {`,
1041
+ ` // Unmount existing root if it exists`,
1042
+ ` if (window.__REACT_ROOT__ && typeof window.__REACT_ROOT__.unmount === 'function') {`,
1043
+ ` try {`,
1044
+ ` window.__REACT_ROOT__.unmount();`,
1045
+ ` } catch (e) {`,
1046
+ ` // Ignore unmount errors`,
1047
+ ` }`,
1048
+ ` }
1049
+ `,
1050
+ ` // Render into the same root container when falling back to client-only`,
1051
+ ` const root = createRoot(container);`,
1052
+ ` root.render(createElement(${componentName}, mergedProps));`,
1053
+ ` window.__REACT_ROOT__ = root;`,
1054
+ ` window.__HMR_CLIENT_ONLY_MODE__ = true;`,
1055
+ ` } catch (fallbackError) {`,
1056
+ ` window.location.reload();`,
1057
+ ` }`,
1058
+ `}
1059
+ `,
1060
+ `// HMR State Preservation: Check for preserved state and merge with initial props`,
1061
+ `// This allows state to be preserved across HMR updates without modifying component files`,
1062
+ `let preservedState = (typeof window !== 'undefined' && window.__HMR_PRESERVED_STATE__) ? window.__HMR_PRESERVED_STATE__ : {};
1063
+ `,
1064
+ `// Also check sessionStorage for state that survived a page reload (for React HMR)`,
1065
+ `if (typeof window !== 'undefined' && typeof sessionStorage !== 'undefined') {`,
1066
+ ` const hmrStateJson = sessionStorage.getItem('__REACT_HMR_STATE__');`,
1067
+ ` if (hmrStateJson) {`,
1068
+ ` try {`,
1069
+ ` const hmrState = JSON.parse(hmrStateJson);`,
1070
+ ` preservedState = { ...preservedState, ...hmrState };`,
1071
+ ` sessionStorage.removeItem('__REACT_HMR_STATE__');`,
1072
+ ` } catch (e) {}`,
1073
+ ` }`,
1074
+ `}
1075
+ `,
1076
+ `const mergedProps = { ...(window.__INITIAL_PROPS__ || {}), ...preservedState };`,
1077
+ `// Clear preserved state after using it (so it doesn't persist across multiple updates)`,
1078
+ `if (typeof window !== 'undefined') {`,
1079
+ ` window.__HMR_PRESERVED_STATE__ = undefined;`,
1080
+ `}
1081
+ `,
1082
+ `// Attempt hydration with error handling`,
1083
+ `// Use document (not document.body) when the page renders <html><head><body>`,
1084
+ `// to avoid "In HTML, <html> cannot be a child of <body>" hydration error`,
1085
+ `const container = typeof document !== 'undefined' ? document : null;`,
1086
+ `if (!container) {`,
1087
+ ` throw new Error('React root container not found: document is null');`,
1088
+ `}
1089
+ `,
1090
+ `// Guard: only hydrate on first load. During HMR re-imports, skip hydration`,
1091
+ `// so React Fast Refresh can swap components in-place and preserve state.`,
1092
+ `if (!window.__REACT_ROOT__) {`,
1093
+ ` let root;`,
1094
+ ` try {`,
1095
+ ` // Use onRecoverableError to catch hydration errors (React 19)`,
1096
+ ` root = hydrateRoot(`,
1097
+ ` container,`,
1098
+ ` createElement(${componentName}, mergedProps),`,
1099
+ ` {`,
1100
+ ` onRecoverableError: (error) => {`,
1101
+ ` // Check if this is a hydration error (isHydrationError filters out whitespace-only head mismatches)`,
1102
+ ` if (isDev && isHydrationError(error)) {`,
1103
+ ` // Real hydration error - handle it`,
1104
+ ` handleHydrationFallback(error);`,
1105
+ ` } else {`,
1106
+ ` // Not a hydration error, or it's a whitespace-only mismatch that was filtered out`,
1107
+ ` // Check if it's a whitespace-only head mismatch using the same logic as isHydrationError`,
1108
+ ` const errorMessage = error instanceof Error ? error.message : String(error);`,
1109
+ ` const errorString = String(error);`,
1110
+ ` const fullMessage = errorMessage + ' ' + errorString;`,
1111
+ ` const hydrationKeywords = ['hydration', 'Hydration', 'mismatch', 'Mismatch', 'did not match', 'server rendered HTML', 'server HTML', 'client HTML', 'Hydration failed'];`,
1112
+ ` const isHydration = hydrationKeywords.some(keyword => fullMessage.includes(keyword));`,
1113
+ ` if (isHydration) {`,
1114
+ ` // Check if this is a head/link/stylesheet related mismatch`,
1115
+ ` const isHeadRelated = fullMessage.includes('<head') || fullMessage.includes('</head>') || fullMessage.includes('head>') || fullMessage.includes('<link') || fullMessage.includes('link>') || fullMessage.includes('stylesheet') || fullMessage.includes('fonts.googleapis') || fullMessage.includes('rel="stylesheet"');`,
1116
+ ` // Check if the mismatch involves only whitespace/newlines`,
1117
+ ` const hasWhitespacePattern = /\\{\\s*["']\\\\n[^"']*["']\\s*\\}/.test(fullMessage) || /\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage) || /-\\s*\\{\\s*["'][\\\\n\\\\r\\\\s]+["']\\s*\\}/.test(fullMessage);`,
1118
+ ` const isWhitespaceOnly = /^[\\s\\n\\r]*$/.test(errorString) || /^[\\s\\n\\r]*$/.test(errorMessage);`,
1119
+ ` const hasNewlinePattern = fullMessage.includes('\\\\n') || fullMessage.includes('\\\\r') || fullMessage.includes('\\n') || fullMessage.includes('\\r');`,
1120
+ ` // If it's head-related and involves whitespace/newlines, silently ignore it`,
1121
+ ` if (isHeadRelated && (hasWhitespacePattern || isWhitespaceOnly || hasNewlinePattern)) {`,
1122
+ ` // Already logged by isHydrationError, just return silently`,
1123
+ ` return;`,
1124
+ ` }`,
1125
+ ` }`,
1126
+ ` // Log other recoverable errors`,
1127
+ ` console.error('React recoverable error:', error);`,
1128
+ ` }`,
1129
+ ` }`,
1130
+ ` }`,
1131
+ ` );`,
1132
+ ` window.__REACT_ROOT__ = root;`,
1133
+ ` } catch (error) {`,
1134
+ ` // Catch synchronous errors (shouldn't happen with hydrateRoot, but safety net)`,
1135
+ ` if (isDev && isHydrationError(error)) {`,
1136
+ ` handleHydrationFallback(error);`,
1137
+ ` } else {`,
1138
+ ` throw error;`,
1139
+ ` }`,
1140
+ ` }
1141
+ `,
1142
+ ` // Also listen for hydration errors via console.error (React logs them there)`,
1143
+ ` if (isDev) {`,
1144
+ ` const originalError = console.error;`,
1145
+ ` console.error = function(...args) {`,
1146
+ ` const errorMessage = args.map(arg => {`,
1147
+ ` if (arg instanceof Error) return arg.message;`,
1148
+ ` return String(arg);`,
1149
+ ` }).join(' ');`,
1150
+ ` `,
1151
+ ` // Check if this is a hydration error`,
1152
+ ` if (isHydrationError({ message: errorMessage }) && !hydrationErrorDetected) {`,
1153
+ ` hydrationErrorDetected = true;`,
1154
+ ` // Create a synthetic error for fallback`,
1155
+ ` const syntheticError = new Error(errorMessage);`,
1156
+ ` // Use setTimeout to ensure this happens after React's error handling`,
1157
+ ` setTimeout(() => {`,
1158
+ ` handleHydrationFallback(syntheticError);`,
1159
+ ` }, 0);`,
1160
+ ` }`,
1161
+ ` `,
1162
+ ` // Call original console.error`,
1163
+ ` originalError.apply(console, args);`,
1164
+ ` };`,
1165
+ ` }`,
1166
+ `}`
1167
+ ].join(`
1168
+ `);
1169
+ return writeFile(join3(reactIndexesDirectory, `${componentName}.tsx`), content);
1170
+ });
1171
+ await Promise.all(promises);
1172
+ if (isDev) {
1173
+ await writeFile(join3(reactIndexesDirectory, "_refresh.tsx"), `import 'react';
1174
+ import 'react-dom/client';
1175
+ `);
1176
+ }
1177
+ };
1178
+
1179
+ // src/build/wrapHTMLScript.ts
1180
+ var wrapHTMLScriptWithHMR = (code, scriptId) => {
1181
+ const escapedId = JSON.stringify(scriptId);
1182
+ return `${code}
1183
+
1184
+ // HMR acceptance - allows this script to be hot-reloaded
1185
+ if (typeof import.meta !== "undefined" && import.meta.hot) {
1186
+ import.meta.hot.accept();
1187
+ console.log('[HMR] Script ready:', ${escapedId});
1188
+ }
1189
+ `;
1190
+ };
1191
+
1192
+ // src/build/htmlScriptHMRPlugin.ts
1193
+ var createHTMLScriptHMRPlugin = (htmlDir, htmxDir) => {
1194
+ return {
1195
+ name: "html-script-hmr",
1196
+ setup(build2) {
1197
+ build2.onLoad({ filter: /\.(ts|js|tsx|jsx)$/ }, async (args) => {
1198
+ const normalizedPath = args.path.replace(/\\/g, "/");
1199
+ const isHtmlScript = htmlDir && normalizedPath.includes(htmlDir.replace(/\\/g, "/")) && normalizedPath.includes("/scripts/");
1200
+ const isHtmxScript = htmxDir && normalizedPath.includes(htmxDir.replace(/\\/g, "/")) && normalizedPath.includes("/scripts/");
1201
+ if (!isHtmlScript && !isHtmxScript) {
1202
+ return;
1203
+ }
1204
+ const text = await Bun.file(args.path).text();
1205
+ const wrapped = wrapHTMLScriptWithHMR(text, normalizedPath);
1206
+ const ext = args.path.split(".").pop() || "ts";
1207
+ const loader = ext;
1208
+ return {
1209
+ contents: wrapped,
1210
+ loader
1211
+ };
1212
+ });
1213
+ }
1214
+ };
1215
+ };
1216
+
1217
+ // src/build/outputLogs.ts
1218
+ init_constants();
1219
+ var outputLogs = (logs) => {
1220
+ for (const log of logs) {
1221
+ if (log.message.includes(BUN_BUILD_WARNING_SUPPRESSION))
1222
+ continue;
1223
+ if (log.level === "error")
1224
+ console.error(log);
1225
+ else if (log.level === "warning")
1226
+ console.warn(log);
1227
+ else
1228
+ console.info(log);
1229
+ }
1230
+ };
1231
+
1232
+ // src/build/scanEntryPoints.ts
1233
+ var {Glob: Glob2 } = globalThis.Bun;
1234
+ var scanEntryPoints = async (dir, pattern) => {
1235
+ const entryPaths = [];
1236
+ const glob = new Glob2(pattern);
411
1237
  for await (const file3 of glob.scan({ absolute: true, cwd: dir })) {
412
1238
  entryPaths.push(file3);
413
1239
  }
@@ -433,6 +1259,13 @@ var updateAssetPaths = async (manifest, directory) => {
433
1259
  }
434
1260
  const newPath = manifest[key];
435
1261
  if (newPath) {
1262
+ if (ext === ".js" || ext === ".ts") {
1263
+ const hasTypeModule = /type\s*=\s*["']module["']/i.test(match);
1264
+ if (!hasTypeModule) {
1265
+ const newSuffix = suffix.replace(/>$/, ' type="module">');
1266
+ return `${prefix}${newPath}${newSuffix}`;
1267
+ }
1268
+ }
436
1269
  return `${prefix}${newPath}${suffix}`;
437
1270
  }
438
1271
  console.error(`error: no manifest entry for ${ext.slice(1)} "${name}" referenced in ${filePath}`);
@@ -443,6 +1276,24 @@ var updateAssetPaths = async (manifest, directory) => {
443
1276
  await Promise.all(tasks);
444
1277
  };
445
1278
 
1279
+ // src/dev/buildHMRClient.ts
1280
+ var {build: bunBuild } = globalThis.Bun;
1281
+ import { resolve as resolve4 } from "path";
1282
+ var buildHMRClient = async () => {
1283
+ const entryPoint = resolve4(import.meta.dir, "client/hmrClient.ts");
1284
+ const result = await bunBuild({
1285
+ entrypoints: [entryPoint],
1286
+ format: "iife",
1287
+ minify: false,
1288
+ target: "browser"
1289
+ });
1290
+ if (!result.success) {
1291
+ console.error("Failed to build HMR client:", result.logs);
1292
+ return "// HMR client build failed";
1293
+ }
1294
+ return await result.outputs[0].text();
1295
+ };
1296
+
446
1297
  // src/utils/cleanup.ts
447
1298
  import { rm as rm2 } from "fs/promises";
448
1299
  import { join as join4 } from "path";
@@ -462,19 +1313,19 @@ var cleanup = async ({
462
1313
  };
463
1314
 
464
1315
  // src/utils/commonAncestor.ts
465
- import { sep as sep2 } from "path";
466
1316
  var commonAncestor = (paths, fallback) => {
467
1317
  if (paths.length === 0)
468
1318
  return fallback;
469
- const segmentsList = paths.map((p) => p.split(sep2));
1319
+ const segmentsList = paths.map((p) => normalizePath(p).split("/"));
470
1320
  const [first] = segmentsList;
471
1321
  if (!first)
472
1322
  return fallback;
473
1323
  const commonSegments = first.filter((segment, index) => segmentsList.every((pathSegs) => pathSegs[index] === segment));
474
- return commonSegments.length ? commonSegments.join(sep2) : fallback;
1324
+ return commonSegments.length ? commonSegments.join("/") : fallback;
475
1325
  };
476
1326
 
477
1327
  // src/utils/getDurationString.ts
1328
+ init_constants();
478
1329
  var getDurationString = (duration) => {
479
1330
  let durationString;
480
1331
  if (duration < MILLISECONDS_IN_A_SECOND) {
@@ -487,27 +1338,127 @@ var getDurationString = (duration) => {
487
1338
  return durationString;
488
1339
  };
489
1340
 
1341
+ // src/utils/logger.ts
1342
+ var colors = {
1343
+ reset: "\x1B[0m",
1344
+ bold: "\x1B[1m",
1345
+ dim: "\x1B[2m",
1346
+ cyan: "\x1B[36m",
1347
+ green: "\x1B[32m",
1348
+ yellow: "\x1B[33m",
1349
+ red: "\x1B[31m",
1350
+ blue: "\x1B[34m",
1351
+ magenta: "\x1B[35m",
1352
+ white: "\x1B[37m"
1353
+ };
1354
+ var frameworkColors = {
1355
+ react: colors.blue,
1356
+ vue: colors.green,
1357
+ svelte: colors.yellow,
1358
+ angular: colors.magenta,
1359
+ html: colors.white,
1360
+ htmx: colors.white,
1361
+ css: colors.cyan,
1362
+ assets: colors.dim
1363
+ };
1364
+ var formatTimestamp = () => {
1365
+ const now = new Date;
1366
+ let hours = now.getHours();
1367
+ const minutes = now.getMinutes().toString().padStart(2, "0");
1368
+ const seconds = now.getSeconds().toString().padStart(2, "0");
1369
+ const ampm = hours >= 12 ? "PM" : "AM";
1370
+ hours = hours % 12 || 12;
1371
+ return `${hours}:${minutes}:${seconds} ${ampm}`;
1372
+ };
1373
+ var formatPath = (filePath) => {
1374
+ const cwd = process.cwd();
1375
+ let relative3 = filePath.startsWith(cwd) ? filePath.slice(cwd.length + 1) : filePath;
1376
+ relative3 = relative3.replace(/\\/g, "/");
1377
+ if (!relative3.startsWith("/")) {
1378
+ relative3 = "/" + relative3;
1379
+ }
1380
+ return relative3;
1381
+ };
1382
+ var getFrameworkColor = (framework) => {
1383
+ return frameworkColors[framework] || colors.white;
1384
+ };
1385
+ var log = (action, options) => {
1386
+ const timestamp = `${colors.dim}${formatTimestamp()}${colors.reset}`;
1387
+ const tag = `${colors.cyan}[hmr]${colors.reset}`;
1388
+ let message = action;
1389
+ if (options?.path) {
1390
+ const pathColor = options.framework ? getFrameworkColor(options.framework) : colors.white;
1391
+ message += ` ${pathColor}${formatPath(options.path)}${colors.reset}`;
1392
+ }
1393
+ if (options?.duration !== undefined) {
1394
+ message += ` ${colors.dim}(${options.duration}ms)${colors.reset}`;
1395
+ }
1396
+ console.log(`${timestamp} ${tag} ${message}`);
1397
+ };
1398
+ var logError = (message, error) => {
1399
+ const timestamp = `${colors.dim}${formatTimestamp()}${colors.reset}`;
1400
+ const tag = `${colors.red}[hmr]${colors.reset}`;
1401
+ const errorMsg = error instanceof Error ? error.message : error;
1402
+ const fullMessage = `${colors.red}error${colors.reset} ${message}${errorMsg ? `: ${errorMsg}` : ""}`;
1403
+ console.error(`${timestamp} ${tag} ${fullMessage}`);
1404
+ };
1405
+ var logWarn = (message) => {
1406
+ const timestamp = `${colors.dim}${formatTimestamp()}${colors.reset}`;
1407
+ const tag = `${colors.yellow}[hmr]${colors.reset}`;
1408
+ console.warn(`${timestamp} ${tag} ${colors.yellow}warning${colors.reset} ${message}`);
1409
+ };
1410
+ var logger = {
1411
+ hmrUpdate(path, framework) {
1412
+ log("hmr update", { path, framework });
1413
+ },
1414
+ pageReload(path, framework) {
1415
+ log("page reload", { path, framework });
1416
+ },
1417
+ cssUpdate(path, framework) {
1418
+ log("css update", { path, framework: framework ?? "css" });
1419
+ },
1420
+ scriptUpdate(path, framework) {
1421
+ log("script update", { path, framework });
1422
+ },
1423
+ rebuilt(duration) {
1424
+ const timestamp = `${colors.dim}${formatTimestamp()}${colors.reset}`;
1425
+ const tag = `${colors.cyan}[hmr]${colors.reset}`;
1426
+ const message = `${colors.green}rebuilt${colors.reset} ${colors.dim}(${duration}ms)${colors.reset}`;
1427
+ console.log(`${timestamp} ${tag} ${message}`);
1428
+ },
1429
+ error(message, error) {
1430
+ logError(message, error);
1431
+ },
1432
+ warn(message) {
1433
+ logWarn(message);
1434
+ },
1435
+ info(message) {
1436
+ log(message);
1437
+ }
1438
+ };
490
1439
  // src/utils/validateSafePath.ts
491
- import { resolve as resolve3, relative as relative3, sep as sep3 } from "path";
1440
+ import { resolve as resolve5, relative as relative3 } from "path";
492
1441
  var validateSafePath = (targetPath, baseDirectory) => {
493
- const absoluteBase = resolve3(baseDirectory);
494
- const absoluteTarget = resolve3(baseDirectory, targetPath);
495
- if (relative3(absoluteBase, absoluteTarget).startsWith(`..${sep3}`)) {
1442
+ const absoluteBase = resolve5(baseDirectory);
1443
+ const absoluteTarget = resolve5(baseDirectory, targetPath);
1444
+ const relativePath = normalizePath(relative3(absoluteBase, absoluteTarget));
1445
+ if (relativePath.startsWith("../") || relativePath === "..") {
496
1446
  throw new Error(`Unsafe path: ${targetPath}`);
497
1447
  }
498
1448
  return absoluteTarget;
499
1449
  };
500
1450
 
501
1451
  // src/core/build.ts
502
- var isDev = env2.NODE_ENV === "development";
1452
+ var isDev = env2.NODE_ENV !== "production";
503
1453
  var vueFeatureFlags = {
504
1454
  __VUE_OPTIONS_API__: "true",
505
1455
  __VUE_PROD_DEVTOOLS__: isDev ? "true" : "false",
506
1456
  __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: isDev ? "true" : "false"
507
1457
  };
508
- var build = async ({
1458
+ var build2 = async ({
509
1459
  buildDirectory = "build",
510
- assetsDirectory = "assets",
1460
+ assetsDirectory,
1461
+ publicDirectory,
511
1462
  reactDirectory,
512
1463
  htmlDirectory,
513
1464
  htmxDirectory,
@@ -515,10 +1466,17 @@ var build = async ({
515
1466
  svelteDirectory,
516
1467
  vueDirectory,
517
1468
  tailwind,
518
- options
1469
+ options,
1470
+ incrementalFiles
519
1471
  }) => {
520
1472
  const buildStart = performance.now();
521
1473
  const projectRoot = cwd();
1474
+ const isIncremental = incrementalFiles && incrementalFiles.length > 0;
1475
+ const normalizedIncrementalFiles = incrementalFiles?.map(normalizePath);
1476
+ if (isIncremental) {
1477
+ console.log(`\u26A1 Incremental build: ${incrementalFiles.length} file(s) to rebuild`);
1478
+ }
1479
+ const throwOnError = options?.throwOnError === true;
522
1480
  const buildPath = validateSafePath(buildDirectory, projectRoot);
523
1481
  const assetsPath = assetsDirectory && validateSafePath(assetsDirectory, projectRoot);
524
1482
  const reactDir = reactDirectory && validateSafePath(reactDirectory, projectRoot);
@@ -544,6 +1502,14 @@ var build = async ({
544
1502
  angularDir
545
1503
  ].filter(Boolean);
546
1504
  const isSingle = frontends.length === 1;
1505
+ const clientRoots = [
1506
+ reactDir,
1507
+ svelteDir,
1508
+ htmlDir,
1509
+ vueDir,
1510
+ angularDir
1511
+ ].filter((dir) => Boolean(dir));
1512
+ const clientRoot = isSingle ? clientRoots[0] ?? projectRoot : commonAncestor(clientRoots, projectRoot);
547
1513
  let serverOutDir;
548
1514
  if (svelteDir)
549
1515
  serverOutDir = join5(buildPath, basename4(svelteDir), "pages");
@@ -554,34 +1520,83 @@ var build = async ({
554
1520
  serverRoot = sveltePagesPath;
555
1521
  else if (vuePagesPath)
556
1522
  serverRoot = vuePagesPath;
557
- await rm3(buildPath, { force: true, recursive: true });
558
- mkdirSync(buildPath);
559
- if (reactIndexesPath && reactPagesPath)
560
- await generateReactIndexFiles(reactPagesPath, reactIndexesPath);
561
- if (assetsPath)
1523
+ const publicPath = publicDirectory && validateSafePath(publicDirectory, projectRoot);
1524
+ if (!isIncremental) {
1525
+ await rm3(buildPath, { force: true, recursive: true });
1526
+ }
1527
+ mkdirSync(buildPath, { recursive: true });
1528
+ if (publicPath)
1529
+ cpSync(publicPath, buildPath, { force: true, recursive: true });
1530
+ const filterToIncrementalEntries = (entryPoints, mapToSource) => {
1531
+ if (!isIncremental || !incrementalFiles)
1532
+ return entryPoints;
1533
+ const normalizedIncremental = new Set(incrementalFiles.map((f) => resolve6(f)));
1534
+ const matchingEntries = [];
1535
+ for (const entry of entryPoints) {
1536
+ const sourceFile = mapToSource(entry);
1537
+ if (sourceFile && normalizedIncremental.has(resolve6(sourceFile))) {
1538
+ matchingEntries.push(entry);
1539
+ }
1540
+ }
1541
+ return matchingEntries;
1542
+ };
1543
+ if (reactIndexesPath && reactPagesPath) {
1544
+ await generateReactIndexFiles(reactPagesPath, reactIndexesPath, isDev);
1545
+ }
1546
+ if (assetsPath && (!isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/assets/")))) {
562
1547
  cpSync(assetsPath, join5(buildPath, "assets"), {
563
1548
  force: true,
564
1549
  recursive: true
565
1550
  });
566
- if (tailwind)
1551
+ }
1552
+ if (tailwind && (!isIncremental || normalizedIncrementalFiles?.some((f) => f.endsWith(".css")))) {
567
1553
  await $`bunx @tailwindcss/cli -i ${tailwind.input} -o ${join5(buildPath, tailwind.output)}`;
568
- const reactEntries = reactIndexesPath ? await scanEntryPoints(reactIndexesPath, "*.tsx") : [];
569
- const htmlEntries = htmlScriptsPath ? await scanEntryPoints(htmlScriptsPath, "*.{js,ts}") : [];
570
- const svelteEntries = sveltePagesPath ? await scanEntryPoints(sveltePagesPath, "*.svelte") : [];
571
- const vueEntries = vuePagesPath ? await scanEntryPoints(vuePagesPath, "*.vue") : [];
572
- const angularEntries = angularPagesPath ? await scanEntryPoints(angularPagesPath, "*.ts") : [];
573
- const htmlCssEntries = htmlDir ? await scanEntryPoints(join5(htmlDir, "styles"), "*.css") : [];
574
- const htmxCssEntries = htmxDir ? await scanEntryPoints(join5(htmxDir, "styles"), "*.css") : [];
575
- const reactCssEntries = reactDir ? await scanEntryPoints(join5(reactDir, "styles"), "*.css") : [];
576
- const svelteCssEntries = svelteDir ? await scanEntryPoints(join5(svelteDir, "styles"), "*.css") : [];
577
- const { svelteServerPaths, svelteClientPaths } = svelteDir ? await compileSvelte(svelteEntries, svelteDir) : { svelteClientPaths: [], svelteServerPaths: [] };
578
- const { vueServerPaths, vueIndexPaths, vueCssPaths } = vueDir ? await compileVue(vueEntries, vueDir) : { vueCssPaths: [], vueIndexPaths: [], vueServerPaths: [] };
1554
+ }
1555
+ const allReactEntries = reactIndexesPath ? await scanEntryPoints(reactIndexesPath, "*.tsx") : [];
1556
+ const allHtmlEntries = htmlScriptsPath ? await scanEntryPoints(htmlScriptsPath, "*.{js,ts}") : [];
1557
+ const allSvelteEntries = sveltePagesPath ? await scanEntryPoints(sveltePagesPath, "*.svelte") : [];
1558
+ const allVueEntries = vuePagesPath ? await scanEntryPoints(vuePagesPath, "*.vue") : [];
1559
+ const allAngularEntries = angularPagesPath ? await scanEntryPoints(angularPagesPath, "*.ts") : [];
1560
+ const allHtmlCssEntries = htmlDir ? await scanEntryPoints(join5(htmlDir, "styles"), "*.css") : [];
1561
+ const allHtmxCssEntries = htmxDir ? await scanEntryPoints(join5(htmxDir, "styles"), "*.css") : [];
1562
+ const allReactCssEntries = reactDir ? await scanEntryPoints(join5(reactDir, "styles"), "*.css") : [];
1563
+ const allSvelteCssEntries = svelteDir ? await scanEntryPoints(join5(svelteDir, "styles"), "*.css") : [];
1564
+ const shouldIncludeHtmlAssets = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/html/") && (f.endsWith(".html") || f.endsWith(".css")));
1565
+ const shouldIncludeHtmxAssets = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/htmx/") && (f.endsWith(".html") || f.endsWith(".css")));
1566
+ const reactEntries = isIncremental && reactIndexesPath && reactPagesPath ? filterToIncrementalEntries(allReactEntries, (entry) => {
1567
+ if (entry.startsWith(resolve6(reactIndexesPath))) {
1568
+ const pageName = basename4(entry, ".tsx");
1569
+ return join5(reactPagesPath, `${pageName}.tsx`);
1570
+ }
1571
+ return null;
1572
+ }) : allReactEntries;
1573
+ const htmlEntries = isIncremental && htmlScriptsPath && !shouldIncludeHtmlAssets ? filterToIncrementalEntries(allHtmlEntries, (entry) => entry) : allHtmlEntries;
1574
+ const svelteEntries = isIncremental ? filterToIncrementalEntries(allSvelteEntries, (entry) => entry) : allSvelteEntries;
1575
+ const vueEntries = isIncremental ? filterToIncrementalEntries(allVueEntries, (entry) => entry) : allVueEntries;
1576
+ const angularEntries = isIncremental ? filterToIncrementalEntries(allAngularEntries, (entry) => entry) : allAngularEntries;
1577
+ const htmlCssEntries = isIncremental && !shouldIncludeHtmlAssets ? filterToIncrementalEntries(allHtmlCssEntries, (entry) => entry) : allHtmlCssEntries;
1578
+ const htmxCssEntries = isIncremental && !shouldIncludeHtmxAssets ? filterToIncrementalEntries(allHtmxCssEntries, (entry) => entry) : allHtmxCssEntries;
1579
+ const reactCssEntries = isIncremental ? filterToIncrementalEntries(allReactCssEntries, (entry) => entry) : allReactCssEntries;
1580
+ const svelteCssEntries = isIncremental ? filterToIncrementalEntries(allSvelteCssEntries, (entry) => entry) : allSvelteCssEntries;
1581
+ const { svelteServerPaths, svelteIndexPaths, svelteClientPaths } = svelteDir ? await compileSvelte(svelteEntries, svelteDir, new Map, isDev) : {
1582
+ svelteClientPaths: [],
1583
+ svelteIndexPaths: [],
1584
+ svelteServerPaths: []
1585
+ };
1586
+ const { vueServerPaths, vueIndexPaths, vueClientPaths, vueCssPaths } = vueDir ? await compileVue(vueEntries, vueDir, isDev) : {
1587
+ vueClientPaths: [],
1588
+ vueCssPaths: [],
1589
+ vueIndexPaths: [],
1590
+ vueServerPaths: []
1591
+ };
579
1592
  const serverEntryPoints = [...svelteServerPaths, ...vueServerPaths];
580
- const clientEntryPoints = [
581
- ...reactEntries,
1593
+ const reactClientEntryPoints = [...reactEntries];
1594
+ const nonReactClientEntryPoints = [
1595
+ ...svelteIndexPaths,
582
1596
  ...svelteClientPaths,
583
1597
  ...htmlEntries,
584
- ...vueIndexPaths
1598
+ ...vueIndexPaths,
1599
+ ...vueClientPaths
585
1600
  ];
586
1601
  const cssEntryPoints = [
587
1602
  ...vueCssPaths,
@@ -590,244 +1605,1697 @@ var build = async ({
590
1605
  ...htmlCssEntries,
591
1606
  ...htmxCssEntries
592
1607
  ];
593
- if (serverEntryPoints.length === 0 && clientEntryPoints.length === 0 && htmxDir === undefined) {
594
- console.warn("No entry points found, manifest will be empty.");
1608
+ if (serverEntryPoints.length === 0 && reactClientEntryPoints.length === 0 && nonReactClientEntryPoints.length === 0 && htmxDir === undefined && htmlDir === undefined) {
1609
+ logger.warn("No entry points found, manifest will be empty");
595
1610
  return {};
596
1611
  }
597
1612
  let serverLogs = [];
598
1613
  let serverOutputs = [];
599
1614
  if (serverEntryPoints.length > 0) {
600
- const { logs, outputs } = await bunBuild({
1615
+ const result = await bunBuild2({
601
1616
  entrypoints: serverEntryPoints,
602
1617
  format: "esm",
603
1618
  naming: `[dir]/[name].[hash].[ext]`,
604
1619
  outdir: serverOutDir,
605
1620
  root: serverRoot,
606
- target: "bun"
607
- }).catch((err) => {
608
- console.error("Server build failed:", err);
609
- exit(1);
1621
+ target: "bun",
1622
+ throw: false
610
1623
  });
611
- serverLogs = logs;
612
- serverOutputs = outputs;
613
- }
614
- let clientLogs = [];
615
- let clientOutputs = [];
616
- if (clientEntryPoints.length > 0) {
617
- const roots = [
618
- reactDir,
619
- svelteDir,
620
- htmlDir,
621
- vueDir,
622
- angularDir
623
- ].filter((dir) => Boolean(dir));
624
- const clientRoot = isSingle ? roots[0] ?? projectRoot : commonAncestor(roots, projectRoot);
625
- const { logs, outputs } = await bunBuild({
626
- define: vueDirectory ? vueFeatureFlags : undefined,
627
- entrypoints: clientEntryPoints,
1624
+ serverLogs = result.logs;
1625
+ serverOutputs = result.outputs;
1626
+ if (!result.success && result.logs.length > 0) {
1627
+ const errLog = result.logs.find((l) => l.level === "error") ?? result.logs[0];
1628
+ const err = new Error(typeof errLog.message === "string" ? errLog.message : String(errLog.message));
1629
+ err.logs = result.logs;
1630
+ logger.error("Server build failed", err);
1631
+ if (throwOnError)
1632
+ throw err;
1633
+ exit(1);
1634
+ }
1635
+ }
1636
+ let reactClientLogs = [];
1637
+ let reactClientOutputs = [];
1638
+ if (isDev && reactIndexesPath && reactClientEntryPoints.length > 0) {
1639
+ const refreshEntry = join5(reactIndexesPath, "_refresh.tsx");
1640
+ if (!reactClientEntryPoints.includes(refreshEntry)) {
1641
+ reactClientEntryPoints.push(refreshEntry);
1642
+ }
1643
+ }
1644
+ if (reactClientEntryPoints.length > 0) {
1645
+ const reactBuildConfig = {
1646
+ entrypoints: reactClientEntryPoints,
628
1647
  format: "esm",
629
- minify: true,
1648
+ minify: !isDev,
630
1649
  naming: `[dir]/[name].[hash].[ext]`,
631
1650
  outdir: buildPath,
632
1651
  root: clientRoot,
633
- target: "browser"
634
- }).catch((err) => {
635
- console.error("Client build failed:", err);
1652
+ splitting: true,
1653
+ target: "browser",
1654
+ throw: false
1655
+ };
1656
+ if (isDev) {
1657
+ reactBuildConfig.reactFastRefresh = true;
1658
+ }
1659
+ const reactClientResult = await bunBuild2(reactBuildConfig);
1660
+ reactClientLogs = reactClientResult.logs;
1661
+ reactClientOutputs = reactClientResult.outputs;
1662
+ if (!reactClientResult.success && reactClientResult.logs.length > 0) {
1663
+ const errLog = reactClientResult.logs.find((l) => l.level === "error") ?? reactClientResult.logs[0];
1664
+ const err = new Error(typeof errLog.message === "string" ? errLog.message : String(errLog.message));
1665
+ err.logs = reactClientResult.logs;
1666
+ logger.error("React client build failed", err);
1667
+ if (throwOnError)
1668
+ throw err;
636
1669
  exit(1);
1670
+ }
1671
+ }
1672
+ let nonReactClientLogs = [];
1673
+ let nonReactClientOutputs = [];
1674
+ if (nonReactClientEntryPoints.length > 0) {
1675
+ const htmlScriptPlugin = isDev ? createHTMLScriptHMRPlugin(htmlDir, htmxDir) : undefined;
1676
+ const nonReactClientResult = await bunBuild2({
1677
+ define: vueDirectory ? vueFeatureFlags : undefined,
1678
+ entrypoints: nonReactClientEntryPoints,
1679
+ format: "esm",
1680
+ minify: !isDev,
1681
+ naming: `[dir]/[name].[hash].[ext]`,
1682
+ outdir: buildPath,
1683
+ plugins: htmlScriptPlugin ? [htmlScriptPlugin] : undefined,
1684
+ root: clientRoot,
1685
+ target: "browser",
1686
+ splitting: !isDev,
1687
+ throw: false
637
1688
  });
638
- clientLogs = logs;
639
- clientOutputs = outputs;
1689
+ nonReactClientLogs = nonReactClientResult.logs;
1690
+ nonReactClientOutputs = nonReactClientResult.outputs;
1691
+ if (!nonReactClientResult.success && nonReactClientResult.logs.length > 0) {
1692
+ const errLog = nonReactClientResult.logs.find((l) => l.level === "error") ?? nonReactClientResult.logs[0];
1693
+ const err = new Error(typeof errLog.message === "string" ? errLog.message : String(errLog.message));
1694
+ err.logs = nonReactClientResult.logs;
1695
+ logger.error("Non-React client build failed", err);
1696
+ if (throwOnError)
1697
+ throw err;
1698
+ exit(1);
1699
+ }
640
1700
  }
641
1701
  let cssLogs = [];
642
1702
  let cssOutputs = [];
643
1703
  if (cssEntryPoints.length > 0) {
644
- const { logs, outputs } = await bunBuild({
1704
+ const cssResult = await bunBuild2({
645
1705
  entrypoints: cssEntryPoints,
646
1706
  naming: `[name].[hash].[ext]`,
647
- outdir: join5(buildPath, basename4(assetsPath), "css"),
648
- target: "browser"
649
- }).catch((err) => {
650
- console.error("CSS build failed:", err);
1707
+ outdir: join5(buildPath, assetsPath ? basename4(assetsPath) : "assets", "css"),
1708
+ target: "browser",
1709
+ throw: false
1710
+ });
1711
+ cssLogs = cssResult.logs;
1712
+ cssOutputs = cssResult.outputs;
1713
+ if (!cssResult.success && cssResult.logs.length > 0) {
1714
+ const errLog = cssResult.logs.find((l) => l.level === "error") ?? cssResult.logs[0];
1715
+ const err = new Error(typeof errLog.message === "string" ? errLog.message : String(errLog.message));
1716
+ err.logs = cssResult.logs;
1717
+ logger.error("CSS build failed", err);
1718
+ if (throwOnError)
1719
+ throw err;
651
1720
  exit(1);
1721
+ }
1722
+ }
1723
+ const allLogs = [
1724
+ ...serverLogs,
1725
+ ...reactClientLogs,
1726
+ ...nonReactClientLogs,
1727
+ ...cssLogs
1728
+ ];
1729
+ outputLogs(allLogs);
1730
+ const manifest = generateManifest([
1731
+ ...serverOutputs,
1732
+ ...reactClientOutputs,
1733
+ ...nonReactClientOutputs,
1734
+ ...cssOutputs
1735
+ ], buildPath);
1736
+ for (const artifact of serverOutputs) {
1737
+ const fileWithHash = basename4(artifact.path);
1738
+ const [baseName] = fileWithHash.split(`.${artifact.hash}.`);
1739
+ if (!baseName)
1740
+ continue;
1741
+ manifest[toPascal(baseName)] = artifact.path;
1742
+ }
1743
+ const htmlOrHtmlCssChanged = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/html/") && (f.endsWith(".html") || f.endsWith(".css")));
1744
+ const htmxOrHtmxCssChanged = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/htmx/") && (f.endsWith(".html") || f.endsWith(".css")));
1745
+ const shouldCopyHtml = htmlOrHtmlCssChanged;
1746
+ const shouldCopyHtmx = htmxOrHtmxCssChanged;
1747
+ const shouldUpdateHtmlAssetPaths = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/html/") && (f.endsWith(".html") || f.endsWith(".css")));
1748
+ const shouldUpdateHtmxAssetPaths = !isIncremental || normalizedIncrementalFiles?.some((f) => f.includes("/htmx/") && (f.endsWith(".html") || f.endsWith(".css")));
1749
+ const hmrClientBundle = isDev && (htmlDir || htmxDir) ? await buildHMRClient() : null;
1750
+ const injectHMRIntoHTMLFile = (filePath, framework) => {
1751
+ if (!hmrClientBundle)
1752
+ return;
1753
+ let html = readFileSync(filePath, "utf-8");
1754
+ if (html.includes("data-hmr-client"))
1755
+ return;
1756
+ const tag = `<script>window.__HMR_FRAMEWORK__="${framework}";</script>` + `<script data-hmr-client>${hmrClientBundle}</script>`;
1757
+ const bodyClose = /<\/body\s*>/i.exec(html);
1758
+ html = bodyClose ? html.slice(0, bodyClose.index) + tag + html.slice(bodyClose.index) : html + tag;
1759
+ writeFileSync(filePath, html);
1760
+ };
1761
+ if (htmlDir && htmlPagesPath) {
1762
+ const outputHtmlPages = isSingle ? join5(buildPath, "pages") : join5(buildPath, basename4(htmlDir), "pages");
1763
+ if (shouldCopyHtml) {
1764
+ mkdirSync(outputHtmlPages, { recursive: true });
1765
+ cpSync(htmlPagesPath, outputHtmlPages, {
1766
+ force: true,
1767
+ recursive: true
1768
+ });
1769
+ }
1770
+ if (shouldUpdateHtmlAssetPaths) {
1771
+ await updateAssetPaths(manifest, outputHtmlPages);
1772
+ }
1773
+ const htmlPageFiles = await scanEntryPoints(outputHtmlPages, "*.html");
1774
+ for (const htmlFile of htmlPageFiles) {
1775
+ if (isDev)
1776
+ injectHMRIntoHTMLFile(htmlFile, "html");
1777
+ const fileName = basename4(htmlFile, ".html");
1778
+ manifest[fileName] = htmlFile;
1779
+ }
1780
+ }
1781
+ if (htmxDir && htmxPagesPath) {
1782
+ const outputHtmxPages = isSingle ? join5(buildPath, "pages") : join5(buildPath, basename4(htmxDir), "pages");
1783
+ if (shouldCopyHtmx) {
1784
+ mkdirSync(outputHtmxPages, { recursive: true });
1785
+ cpSync(htmxPagesPath, outputHtmxPages, {
1786
+ force: true,
1787
+ recursive: true
1788
+ });
1789
+ }
1790
+ if (shouldCopyHtmx) {
1791
+ const htmxDestDir = isSingle ? buildPath : join5(buildPath, basename4(htmxDir));
1792
+ mkdirSync(htmxDestDir, { recursive: true });
1793
+ const glob = new Glob3("htmx*.min.js");
1794
+ for (const relPath of glob.scanSync({ cwd: htmxDir })) {
1795
+ const src = join5(htmxDir, relPath);
1796
+ const dest = join5(htmxDestDir, "htmx.min.js");
1797
+ copyFileSync(src, dest);
1798
+ break;
1799
+ }
1800
+ }
1801
+ if (shouldUpdateHtmxAssetPaths) {
1802
+ await updateAssetPaths(manifest, outputHtmxPages);
1803
+ }
1804
+ const htmxPageFiles = await scanEntryPoints(outputHtmxPages, "*.html");
1805
+ for (const htmxFile of htmxPageFiles) {
1806
+ if (isDev)
1807
+ injectHMRIntoHTMLFile(htmxFile, "htmx");
1808
+ const fileName = basename4(htmxFile, ".html");
1809
+ manifest[fileName] = htmxFile;
1810
+ }
1811
+ }
1812
+ if (!options?.preserveIntermediateFiles)
1813
+ await cleanup({
1814
+ reactIndexesPath,
1815
+ svelteDir,
1816
+ vueDir
1817
+ });
1818
+ console.log(`Build completed in ${getDurationString(performance.now() - buildStart)}`);
1819
+ return manifest;
1820
+ };
1821
+ // src/core/devBuild.ts
1822
+ import { statSync } from "fs";
1823
+ import { resolve as resolve18 } from "path";
1824
+
1825
+ // src/dev/dependencyGraph.ts
1826
+ import { readFileSync as readFileSync2, readdirSync, existsSync } from "fs";
1827
+ import { resolve as resolve7 } from "path";
1828
+ var createDependencyGraph = () => ({
1829
+ dependencies: new Map,
1830
+ dependents: new Map
1831
+ });
1832
+ var extractDependencies = (filePath) => {
1833
+ try {
1834
+ if (!existsSync(filePath)) {
1835
+ return [];
1836
+ }
1837
+ const content = readFileSync2(filePath, "utf-8");
1838
+ const dependencies = [];
1839
+ const lowerPath = filePath.toLowerCase();
1840
+ const isHtml = lowerPath.endsWith(".html") || lowerPath.endsWith(".htm");
1841
+ if (isHtml) {
1842
+ const linkRegex = /<link\s+[^>]*rel=["']stylesheet["'][^>]*href=["']([^"']+)["'][^>]*>/gi;
1843
+ let matchLink;
1844
+ while ((matchLink = linkRegex.exec(content)) !== null) {
1845
+ const href = matchLink[1];
1846
+ if (!href)
1847
+ continue;
1848
+ const resolvedHref = resolveImportPath(href, filePath);
1849
+ if (resolvedHref) {
1850
+ dependencies.push(resolvedHref);
1851
+ }
1852
+ }
1853
+ return dependencies;
1854
+ }
1855
+ const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
1856
+ const importWithoutFromRegex = /import\s+['"]([^'"]+)['"]/g;
1857
+ const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
1858
+ const dynamicImportRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
1859
+ let match;
1860
+ while ((match = importRegex.exec(content)) !== null) {
1861
+ if (match[1]) {
1862
+ const resolved = resolveImportPath(match[1], filePath);
1863
+ if (resolved)
1864
+ dependencies.push(resolved);
1865
+ }
1866
+ }
1867
+ while ((match = importWithoutFromRegex.exec(content)) !== null) {
1868
+ if (match[1]) {
1869
+ const resolved = resolveImportPath(match[1], filePath);
1870
+ if (resolved)
1871
+ dependencies.push(resolved);
1872
+ }
1873
+ }
1874
+ while ((match = requireRegex.exec(content)) !== null) {
1875
+ if (match[1]) {
1876
+ const resolved = resolveImportPath(match[1], filePath);
1877
+ if (resolved)
1878
+ dependencies.push(resolved);
1879
+ }
1880
+ }
1881
+ while ((match = dynamicImportRegex.exec(content)) !== null) {
1882
+ if (match[1]) {
1883
+ const resolved = resolveImportPath(match[1], filePath);
1884
+ if (resolved)
1885
+ dependencies.push(resolved);
1886
+ }
1887
+ }
1888
+ return dependencies;
1889
+ } catch {
1890
+ return [];
1891
+ }
1892
+ };
1893
+ var resolveImportPath = (importPath, fromFile) => {
1894
+ if (!importPath.startsWith(".") && !importPath.startsWith("/")) {
1895
+ return null;
1896
+ }
1897
+ const fromDir = resolve7(fromFile, "..");
1898
+ const resolved = resolve7(fromDir, importPath);
1899
+ const normalized = resolve7(resolved);
1900
+ const extensions = [
1901
+ ".ts",
1902
+ ".tsx",
1903
+ ".js",
1904
+ ".jsx",
1905
+ ".vue",
1906
+ ".svelte",
1907
+ ".css",
1908
+ ".html"
1909
+ ];
1910
+ for (const ext of extensions) {
1911
+ const withExt = normalized + ext;
1912
+ try {
1913
+ readFileSync2(withExt);
1914
+ return normalized + ext;
1915
+ } catch {}
1916
+ }
1917
+ try {
1918
+ readFileSync2(normalized);
1919
+ return normalized;
1920
+ } catch {
1921
+ return null;
1922
+ }
1923
+ };
1924
+ var addFileToGraph = (graph, filePath) => {
1925
+ const normalizedPath = resolve7(filePath);
1926
+ if (!existsSync(normalizedPath)) {
1927
+ return;
1928
+ }
1929
+ const dependencies = extractDependencies(normalizedPath);
1930
+ const existingDeps = graph.dependencies.get(normalizedPath);
1931
+ if (existingDeps) {
1932
+ for (const dep of existingDeps) {
1933
+ const dependents = graph.dependents.get(dep);
1934
+ if (dependents) {
1935
+ dependents.delete(normalizedPath);
1936
+ }
1937
+ }
1938
+ }
1939
+ const newDeps = new Set(dependencies);
1940
+ graph.dependencies.set(normalizedPath, newDeps);
1941
+ for (const dep of dependencies) {
1942
+ if (!graph.dependents.has(dep)) {
1943
+ graph.dependents.set(dep, new Set);
1944
+ }
1945
+ graph.dependents.get(dep).add(normalizedPath);
1946
+ }
1947
+ };
1948
+ var getAffectedFiles = (graph, changedFile) => {
1949
+ const normalizedPath = resolve7(changedFile);
1950
+ const affected = new Set;
1951
+ const toProcess = [normalizedPath];
1952
+ while (toProcess.length > 0) {
1953
+ const current = toProcess.pop();
1954
+ if (affected.has(current)) {
1955
+ continue;
1956
+ }
1957
+ affected.add(current);
1958
+ const dependents = graph.dependents.get(current);
1959
+ if (dependents) {
1960
+ for (const dependent of dependents) {
1961
+ toProcess.push(dependent);
1962
+ }
1963
+ }
1964
+ }
1965
+ return Array.from(affected);
1966
+ };
1967
+ var removeFileFromGraph = (graph, filePath) => {
1968
+ const normalizedPath = resolve7(filePath);
1969
+ const deps = graph.dependencies.get(normalizedPath);
1970
+ if (deps) {
1971
+ for (const dep of deps) {
1972
+ const dependents2 = graph.dependents.get(dep);
1973
+ if (dependents2) {
1974
+ dependents2.delete(normalizedPath);
1975
+ }
1976
+ }
1977
+ graph.dependencies.delete(normalizedPath);
1978
+ }
1979
+ const dependents = graph.dependents.get(normalizedPath);
1980
+ if (dependents) {
1981
+ for (const dependent of dependents) {
1982
+ const depList = graph.dependencies.get(dependent);
1983
+ if (depList) {
1984
+ depList.delete(normalizedPath);
1985
+ }
1986
+ }
1987
+ graph.dependents.delete(normalizedPath);
1988
+ }
1989
+ };
1990
+ var buildInitialDependencyGraph = (graph, directories) => {
1991
+ const processedFiles = new Set;
1992
+ const scanDirectory = (dir) => {
1993
+ const normalizedDir = resolve7(dir);
1994
+ try {
1995
+ const entries = readdirSync(normalizedDir, { withFileTypes: true });
1996
+ for (const entry of entries) {
1997
+ const fullPath = resolve7(normalizedDir, entry.name);
1998
+ if (fullPath.includes("/node_modules/") || fullPath.includes("/.git/") || fullPath.includes("/build/") || fullPath.includes("/compiled/") || fullPath.includes("/indexes/") || entry.name.startsWith(".")) {
1999
+ continue;
2000
+ }
2001
+ if (entry.isDirectory()) {
2002
+ scanDirectory(fullPath);
2003
+ } else if (entry.isFile()) {
2004
+ const ext = entry.name.split(".").pop()?.toLowerCase();
2005
+ if ([
2006
+ "ts",
2007
+ "tsx",
2008
+ "js",
2009
+ "jsx",
2010
+ "vue",
2011
+ "svelte",
2012
+ "html",
2013
+ "htm"
2014
+ ].includes(ext || "")) {
2015
+ if (!processedFiles.has(fullPath)) {
2016
+ addFileToGraph(graph, fullPath);
2017
+ processedFiles.add(fullPath);
2018
+ }
2019
+ }
2020
+ }
2021
+ }
2022
+ } catch {}
2023
+ };
2024
+ for (const dir of directories) {
2025
+ const resolvedDir = resolve7(dir);
2026
+ if (existsSync(resolvedDir)) {
2027
+ scanDirectory(resolvedDir);
2028
+ }
2029
+ }
2030
+ };
2031
+
2032
+ // src/dev/moduleVersionTracker.ts
2033
+ var globalVersionCounter = 0;
2034
+ var getNextVersion = () => ++globalVersionCounter;
2035
+ var createModuleVersionTracker = () => new Map;
2036
+ var incrementModuleVersion = (versions, modulePath) => {
2037
+ const newVersion = getNextVersion();
2038
+ versions.set(modulePath, newVersion);
2039
+ return newVersion;
2040
+ };
2041
+ var incrementModuleVersions = (versions, modulePaths) => {
2042
+ const updated = new Map;
2043
+ for (const path of modulePaths) {
2044
+ const version = incrementModuleVersion(versions, path);
2045
+ updated.set(path, version);
2046
+ }
2047
+ return updated;
2048
+ };
2049
+ var serializeModuleVersions = (versions) => {
2050
+ const serialized = {};
2051
+ for (const [path, version] of versions.entries()) {
2052
+ serialized[path] = version;
2053
+ }
2054
+ return serialized;
2055
+ };
2056
+
2057
+ // src/dev/configResolver.ts
2058
+ import { resolve as resolve8 } from "path";
2059
+ var resolveBuildPaths = (config) => {
2060
+ const cwd2 = process.cwd();
2061
+ const normalize = (path) => path.replace(/\\/g, "/");
2062
+ const withDefault = (value, fallback) => normalize(resolve8(cwd2, value ?? fallback));
2063
+ const optional = (value) => value ? normalize(resolve8(cwd2, value)) : undefined;
2064
+ return {
2065
+ buildDir: withDefault(config.buildDirectory, "build"),
2066
+ assetsDir: optional(config.assetsDirectory),
2067
+ reactDir: optional(config.reactDirectory),
2068
+ svelteDir: optional(config.svelteDirectory),
2069
+ vueDir: optional(config.vueDirectory),
2070
+ angularDir: optional(config.angularDirectory),
2071
+ htmlDir: optional(config.htmlDirectory),
2072
+ htmxDir: optional(config.htmxDirectory)
2073
+ };
2074
+ };
2075
+
2076
+ // src/dev/clientManager.ts
2077
+ var createHMRState = (config) => ({
2078
+ connectedClients: new Set,
2079
+ debounceTimeout: null,
2080
+ dependencyGraph: createDependencyGraph(),
2081
+ fileChangeQueue: new Map,
2082
+ fileHashes: new Map,
2083
+ isRebuilding: false,
2084
+ moduleVersions: createModuleVersionTracker(),
2085
+ rebuildQueue: new Set,
2086
+ rebuildTimeout: null,
2087
+ sourceFileVersions: new Map,
2088
+ watchers: [],
2089
+ config,
2090
+ resolvedPaths: resolveBuildPaths(config),
2091
+ vueChangeTypes: new Map,
2092
+ assetStore: new Map
2093
+ });
2094
+ var incrementSourceFileVersion = (state, filePath) => {
2095
+ const currentVersion = state.sourceFileVersions.get(filePath) || 0;
2096
+ const newVersion = currentVersion + 1;
2097
+ state.sourceFileVersions.set(filePath, newVersion);
2098
+ return newVersion;
2099
+ };
2100
+ var incrementSourceFileVersions = (state, filePaths) => {
2101
+ for (const filePath of filePaths) {
2102
+ incrementSourceFileVersion(state, filePath);
2103
+ }
2104
+ };
2105
+
2106
+ // src/dev/fileWatcher.ts
2107
+ import { watch } from "fs";
2108
+ import { existsSync as existsSync2 } from "fs";
2109
+ import { join as join6, resolve as resolve9 } from "path";
2110
+
2111
+ // src/dev/pathUtils.ts
2112
+ var getWatchPaths = (config, resolved) => {
2113
+ const paths = [];
2114
+ const push = (base, sub) => {
2115
+ if (!base)
2116
+ return;
2117
+ const normalizedBase = normalizePath(base);
2118
+ paths.push(sub ? `${normalizedBase}/${sub}` : normalizedBase);
2119
+ };
2120
+ const cfg = resolved ?? {
2121
+ reactDir: config.reactDirectory,
2122
+ svelteDir: config.svelteDirectory,
2123
+ vueDir: config.vueDirectory,
2124
+ angularDir: config.angularDirectory,
2125
+ htmlDir: config.htmlDirectory,
2126
+ htmxDir: config.htmxDirectory,
2127
+ assetsDir: config.assetsDirectory
2128
+ };
2129
+ push(cfg.reactDir, "components");
2130
+ push(cfg.reactDir, "pages");
2131
+ push(cfg.reactDir, "styles");
2132
+ push(cfg.svelteDir, "components");
2133
+ push(cfg.svelteDir, "pages");
2134
+ push(cfg.svelteDir, "composables");
2135
+ push(cfg.svelteDir, "styles");
2136
+ push(cfg.vueDir, "components");
2137
+ push(cfg.vueDir, "pages");
2138
+ push(cfg.vueDir, "composables");
2139
+ push(cfg.vueDir, "styles");
2140
+ push(cfg.angularDir, "components");
2141
+ push(cfg.angularDir, "pages");
2142
+ push(cfg.angularDir, "styles");
2143
+ push(cfg.htmlDir, "pages");
2144
+ push(cfg.htmlDir, "scripts");
2145
+ push(cfg.htmlDir, "styles");
2146
+ push(cfg.htmxDir, "pages");
2147
+ push(cfg.htmxDir, "styles");
2148
+ push(cfg.assetsDir);
2149
+ return paths;
2150
+ };
2151
+ var shouldIgnorePath = (path) => {
2152
+ const normalizedPath = path.replace(/\\/g, "/");
2153
+ return normalizedPath.includes("/build/") || normalizedPath.includes("/compiled/") || normalizedPath.includes("/indexes/") || normalizedPath.includes("/node_modules/") || normalizedPath.includes("/.git/") || normalizedPath.endsWith(".log") || normalizedPath.endsWith(".tmp") || normalizedPath.startsWith(".") || normalizedPath === "compiled" || normalizedPath.endsWith("/compiled") || normalizedPath.endsWith("/compiled/");
2154
+ };
2155
+ var detectFramework = (filePath, resolved) => {
2156
+ if (shouldIgnorePath(filePath)) {
2157
+ return "ignored";
2158
+ }
2159
+ const normalized = filePath.replace(/\\/g, "/");
2160
+ const startsWithDir = (dir) => dir ? normalized.startsWith(dir.replace(/\\/g, "/")) : false;
2161
+ if (resolved) {
2162
+ if (startsWithDir(resolved.htmxDir))
2163
+ return "htmx";
2164
+ if (startsWithDir(resolved.reactDir))
2165
+ return "react";
2166
+ if (startsWithDir(resolved.svelteDir))
2167
+ return "svelte";
2168
+ if (startsWithDir(resolved.vueDir))
2169
+ return "vue";
2170
+ if (startsWithDir(resolved.angularDir))
2171
+ return "angular";
2172
+ if (startsWithDir(resolved.htmlDir))
2173
+ return "html";
2174
+ if (startsWithDir(resolved.assetsDir))
2175
+ return "assets";
2176
+ } else {
2177
+ if (normalized.includes("/htmx/"))
2178
+ return "htmx";
2179
+ if (normalized.includes("/react/"))
2180
+ return "react";
2181
+ if (normalized.includes("/svelte/"))
2182
+ return "svelte";
2183
+ if (normalized.includes("/vue/"))
2184
+ return "vue";
2185
+ if (normalized.includes("/angular/"))
2186
+ return "angular";
2187
+ if (normalized.includes("/html/"))
2188
+ return "html";
2189
+ }
2190
+ if (normalized.endsWith(".tsx") || normalized.endsWith(".jsx"))
2191
+ return "react";
2192
+ if (normalized.endsWith(".svelte"))
2193
+ return "svelte";
2194
+ if (normalized.endsWith(".vue"))
2195
+ return "vue";
2196
+ if (normalized.endsWith(".html"))
2197
+ return "html";
2198
+ if (normalized.endsWith(".ts") && normalized.includes("angular"))
2199
+ return "angular";
2200
+ if (normalized.includes("/assets/"))
2201
+ return "assets";
2202
+ if (normalized.endsWith(".css")) {
2203
+ if (normalized.includes("/vue/") || normalized.includes("/vue-"))
2204
+ return "vue";
2205
+ if (normalized.includes("/svelte/") || normalized.includes("/svelte-"))
2206
+ return "svelte";
2207
+ if (normalized.includes("/react/") || normalized.includes("/react-"))
2208
+ return "react";
2209
+ if (normalized.includes("/angular/") || normalized.includes("/angular-"))
2210
+ return "angular";
2211
+ if (normalized.includes("/html/") || normalized.includes("/html-"))
2212
+ return "html";
2213
+ if (normalized.includes("/htmx/") || normalized.includes("/htmx-"))
2214
+ return "htmx";
2215
+ return "assets";
2216
+ }
2217
+ return "unknown";
2218
+ };
2219
+
2220
+ // src/dev/fileWatcher.ts
2221
+ var startFileWatching = (state, config, onFileChange) => {
2222
+ const watchPaths = getWatchPaths(config, state.resolvedPaths);
2223
+ for (const path of watchPaths) {
2224
+ const absolutePath = resolve9(path).replace(/\\/g, "/");
2225
+ if (!existsSync2(absolutePath)) {
2226
+ continue;
2227
+ }
2228
+ const watcher = watch(absolutePath, { recursive: true }, (event, filename) => {
2229
+ if (!filename)
2230
+ return;
2231
+ if (filename === "compiled" || filename === "build" || filename === "indexes" || filename.includes("/compiled") || filename.includes("/build") || filename.includes("/indexes") || filename.endsWith("/")) {
2232
+ return;
2233
+ }
2234
+ const fullPath = join6(absolutePath, filename).replace(/\\/g, "/");
2235
+ if (shouldIgnorePath(fullPath)) {
2236
+ return;
2237
+ }
2238
+ if (event === "rename" && !existsSync2(fullPath)) {
2239
+ try {
2240
+ removeFileFromGraph(state.dependencyGraph, fullPath);
2241
+ } catch {}
2242
+ onFileChange(fullPath);
2243
+ return;
2244
+ }
2245
+ if (existsSync2(fullPath)) {
2246
+ onFileChange(fullPath);
2247
+ try {
2248
+ addFileToGraph(state.dependencyGraph, fullPath);
2249
+ } catch {}
2250
+ }
652
2251
  });
653
- cssLogs = logs;
654
- cssOutputs = outputs;
2252
+ state.watchers.push(watcher);
2253
+ }
2254
+ };
2255
+
2256
+ // src/dev/assetStore.ts
2257
+ import { resolve as resolve10 } from "path";
2258
+ import { readdir, unlink } from "fs/promises";
2259
+ var mimeTypes = {
2260
+ ".css": "text/css",
2261
+ ".html": "text/html",
2262
+ ".js": "application/javascript",
2263
+ ".mjs": "application/javascript",
2264
+ ".json": "application/json",
2265
+ ".svg": "image/svg+xml",
2266
+ ".woff": "font/woff",
2267
+ ".woff2": "font/woff2"
2268
+ };
2269
+ var getMimeType = (filePath) => {
2270
+ const ext = filePath.slice(filePath.lastIndexOf("."));
2271
+ return mimeTypes[ext] ?? "application/octet-stream";
2272
+ };
2273
+ var HASHED_FILE_RE = /\.[a-z0-9]{8}\.(js|css|mjs)$/;
2274
+ var stripHash = (webPath) => webPath.replace(/\.[a-z0-9]{8}(\.(js|css|mjs))$/, "$1");
2275
+ var populateAssetStore = async (store, manifest, buildDir) => {
2276
+ const loadPromises = [];
2277
+ const newIdentities = new Map;
2278
+ for (const webPath of Object.values(manifest)) {
2279
+ if (!webPath.startsWith("/"))
2280
+ continue;
2281
+ newIdentities.set(stripHash(webPath), webPath);
2282
+ }
2283
+ for (const existingPath of store.keys()) {
2284
+ const identity = stripHash(existingPath);
2285
+ const replacement = newIdentities.get(identity);
2286
+ if (replacement && replacement !== existingPath) {
2287
+ store.delete(existingPath);
2288
+ }
2289
+ }
2290
+ for (const webPath of newIdentities.values()) {
2291
+ loadPromises.push(Bun.file(resolve10(buildDir, webPath.slice(1))).bytes().then((bytes) => {
2292
+ store.set(webPath, bytes);
2293
+ }).catch(() => {}));
2294
+ }
2295
+ try {
2296
+ const scanDir = async (dir, prefix) => {
2297
+ const entries = await readdir(dir, { withFileTypes: true });
2298
+ const subTasks = [];
2299
+ for (const entry of entries) {
2300
+ if (entry.isDirectory()) {
2301
+ subTasks.push(scanDir(resolve10(dir, entry.name), `${prefix}${entry.name}/`));
2302
+ } else if (entry.name.startsWith("chunk-")) {
2303
+ const webPath = `/${prefix}${entry.name}`;
2304
+ if (!store.has(webPath)) {
2305
+ subTasks.push(Bun.file(resolve10(dir, entry.name)).bytes().then((bytes) => {
2306
+ store.set(webPath, bytes);
2307
+ }).catch(() => {}));
2308
+ }
2309
+ }
2310
+ }
2311
+ await Promise.all(subTasks);
2312
+ };
2313
+ await scanDir(buildDir, "");
2314
+ } catch {}
2315
+ await Promise.all(loadPromises);
2316
+ };
2317
+ var cleanStaleAssets = async (store, manifest, buildDir) => {
2318
+ const liveByIdentity = new Map;
2319
+ for (const webPath of store.keys()) {
2320
+ const diskPath = resolve10(buildDir, webPath.slice(1));
2321
+ liveByIdentity.set(stripHash(diskPath), diskPath);
2322
+ }
2323
+ const absBuildDir = resolve10(buildDir);
2324
+ for (const val of Object.values(manifest)) {
2325
+ if (!HASHED_FILE_RE.test(val))
2326
+ continue;
2327
+ if (val.startsWith(absBuildDir)) {
2328
+ liveByIdentity.set(stripHash(val), val);
2329
+ }
2330
+ }
2331
+ try {
2332
+ const walkAndClean = async (dir) => {
2333
+ const entries = await readdir(dir, { withFileTypes: true });
2334
+ const tasks = [];
2335
+ for (const entry of entries) {
2336
+ const fullPath = resolve10(dir, entry.name);
2337
+ if (entry.isDirectory()) {
2338
+ tasks.push(walkAndClean(fullPath));
2339
+ } else if (HASHED_FILE_RE.test(entry.name)) {
2340
+ const identity = stripHash(fullPath);
2341
+ const livePath = liveByIdentity.get(identity);
2342
+ if (livePath && livePath !== fullPath) {
2343
+ tasks.push(unlink(fullPath).catch(() => {}));
2344
+ }
2345
+ }
2346
+ }
2347
+ await Promise.all(tasks);
2348
+ };
2349
+ await walkAndClean(buildDir);
2350
+ } catch {}
2351
+ };
2352
+ var lookupAsset = (store, path) => store.get(path);
2353
+
2354
+ // src/dev/rebuildTrigger.ts
2355
+ import { existsSync as existsSync5 } from "fs";
2356
+ import { basename as basename8, resolve as resolve17 } from "path";
2357
+
2358
+ // src/dev/fileHashTracker.ts
2359
+ import { createHash } from "crypto";
2360
+ import { readFileSync as readFileSync3 } from "fs";
2361
+ var computeFileHash = (filePath) => {
2362
+ try {
2363
+ const fileContent = readFileSync3(filePath);
2364
+ const hash = createHash("sha256");
2365
+ hash.update(fileContent);
2366
+ return hash.digest("hex");
2367
+ } catch {
2368
+ return Date.now().toString();
2369
+ }
2370
+ };
2371
+ var hasFileChanged = (filePath, currentHash, previousHashes) => {
2372
+ const normalizedPath = normalizePath(filePath);
2373
+ const previousHash = previousHashes.get(normalizedPath);
2374
+ if (!previousHash) {
2375
+ return true;
2376
+ }
2377
+ return previousHash !== currentHash;
2378
+ };
2379
+
2380
+ // src/dev/moduleMapper.ts
2381
+ import { basename as basename5, resolve as resolve12 } from "path";
2382
+
2383
+ // src/dev/reactComponentClassifier.ts
2384
+ import { resolve as resolve11 } from "path";
2385
+ var classifyComponent = (filePath) => {
2386
+ const normalizedPath = resolve11(filePath);
2387
+ if (normalizedPath.includes("/react/pages/")) {
2388
+ return "server";
2389
+ }
2390
+ if (normalizedPath.includes("/react/components/") || normalizedPath.includes("/react/composables/")) {
2391
+ return "client";
2392
+ }
2393
+ return "client";
2394
+ };
2395
+
2396
+ // src/dev/moduleMapper.ts
2397
+ var mapSourceFileToManifestKeys = (sourceFile, framework, resolvedPaths) => {
2398
+ const normalizedFile = resolve12(sourceFile);
2399
+ const fileName = basename5(normalizedFile);
2400
+ const baseName = fileName.replace(/\.(tsx?|jsx?|vue|svelte|css|html)$/, "");
2401
+ const pascalName = toPascal(baseName);
2402
+ const keys = [];
2403
+ const inSubdir = (dir, sub) => {
2404
+ if (!dir)
2405
+ return false;
2406
+ const prefix = `${dir.replace(/\\/g, "/")}/${sub}/`;
2407
+ return normalizedFile.startsWith(prefix);
2408
+ };
2409
+ switch (framework) {
2410
+ case "react":
2411
+ if (inSubdir(resolvedPaths?.reactDir, "pages") || normalizedFile.includes("/react/pages/")) {
2412
+ keys.push(`${pascalName}Index`);
2413
+ keys.push(`${pascalName}CSS`);
2414
+ }
2415
+ break;
2416
+ case "svelte":
2417
+ if (inSubdir(resolvedPaths?.svelteDir, "pages") || normalizedFile.includes("/svelte/pages/")) {
2418
+ keys.push(pascalName);
2419
+ keys.push(`${pascalName}Index`);
2420
+ keys.push(`${pascalName}CSS`);
2421
+ }
2422
+ break;
2423
+ case "vue":
2424
+ if (inSubdir(resolvedPaths?.vueDir, "pages") || normalizedFile.includes("/vue/pages/")) {
2425
+ keys.push(pascalName);
2426
+ keys.push(`${pascalName}Index`);
2427
+ keys.push(`${pascalName}CSS`);
2428
+ }
2429
+ break;
2430
+ case "angular":
2431
+ if (inSubdir(resolvedPaths?.angularDir, "pages") || normalizedFile.includes("/angular/pages/")) {
2432
+ keys.push(pascalName);
2433
+ keys.push(`${pascalName}Index`);
2434
+ }
2435
+ break;
2436
+ case "html":
2437
+ case "htmx":
2438
+ break;
2439
+ case "assets":
2440
+ if (normalizedFile.endsWith(".css")) {
2441
+ keys.push(`${pascalName}CSS`);
2442
+ }
2443
+ break;
655
2444
  }
656
- const allLogs = [...serverLogs, ...clientLogs, ...cssLogs];
657
- outputLogs(allLogs);
658
- const manifest = generateManifest([...serverOutputs, ...clientOutputs, ...cssOutputs], buildPath);
659
- if (htmlDir && htmlPagesPath) {
660
- const outputHtmlPages = isSingle ? join5(buildPath, "pages") : join5(buildPath, basename4(htmlDir), "pages");
661
- mkdirSync(outputHtmlPages, { recursive: true });
662
- cpSync(htmlPagesPath, outputHtmlPages, {
663
- force: true,
664
- recursive: true
665
- });
666
- await updateAssetPaths(manifest, outputHtmlPages);
2445
+ return keys;
2446
+ };
2447
+ var createModuleUpdates = (changedFiles, framework, manifest, resolvedPaths) => {
2448
+ const updates = [];
2449
+ const processedFiles = new Set;
2450
+ for (const sourceFile of changedFiles) {
2451
+ const normalizedFile = resolve12(sourceFile);
2452
+ const normalizedPath = normalizedFile.replace(/\\/g, "/");
2453
+ if (processedFiles.has(normalizedFile))
2454
+ continue;
2455
+ processedFiles.add(normalizedFile);
2456
+ const moduleKeys = mapSourceFileToManifestKeys(normalizedFile, framework, resolvedPaths);
2457
+ const isReactPage = resolvedPaths?.reactDir ? normalizedPath.startsWith(`${resolvedPaths.reactDir.replace(/\\/g, "/")}/pages/`) : normalizedPath.includes("/react/pages/");
2458
+ if (framework === "react" && !isReactPage) {
2459
+ continue;
2460
+ }
2461
+ const modulePaths = {};
2462
+ for (const key of moduleKeys) {
2463
+ if (manifest[key]) {
2464
+ modulePaths[key] = manifest[key];
2465
+ }
2466
+ }
2467
+ if (Object.keys(modulePaths).length > 0) {
2468
+ const componentType = framework === "react" ? classifyComponent(normalizedFile) : undefined;
2469
+ updates.push({
2470
+ componentType,
2471
+ framework,
2472
+ moduleKeys: Object.keys(modulePaths),
2473
+ modulePaths,
2474
+ sourceFile: normalizedFile
2475
+ });
2476
+ }
667
2477
  }
668
- if (htmxDir && htmxPagesPath) {
669
- const outputHtmxPages = isSingle ? join5(buildPath, "pages") : join5(buildPath, basename4(htmxDir), "pages");
670
- mkdirSync(outputHtmxPages, { recursive: true });
671
- cpSync(htmxPagesPath, outputHtmxPages, {
672
- force: true,
673
- recursive: true
674
- });
675
- const htmxDestDir = isSingle ? buildPath : join5(buildPath, basename4(htmxDir));
676
- mkdirSync(htmxDestDir, { recursive: true });
677
- const glob = new Glob3("htmx*.min.js");
678
- for (const relativePath of glob.scanSync({ cwd: htmxDir })) {
679
- const src = join5(htmxDir, relativePath);
680
- const dest = join5(htmxDestDir, "htmx.min.js");
681
- copyFileSync(src, dest);
682
- break;
2478
+ return updates;
2479
+ };
2480
+ var groupModuleUpdatesByFramework = (updates) => {
2481
+ const grouped = new Map;
2482
+ for (const update of updates) {
2483
+ if (!grouped.has(update.framework)) {
2484
+ grouped.set(update.framework, []);
683
2485
  }
684
- await updateAssetPaths(manifest, outputHtmxPages);
2486
+ grouped.get(update.framework).push(update);
685
2487
  }
686
- if (!options?.preserveIntermediateFiles)
687
- await cleanup({
688
- reactIndexesPath,
689
- svelteDir,
690
- vueDir
691
- });
692
- console.log(`Build completed in ${getDurationString(performance.now() - buildStart)}`);
693
- return manifest;
2488
+ return grouped;
694
2489
  };
695
- // src/core/pageHandlers.ts
696
- var {file: file3 } = globalThis.Bun;
697
- import { createElement } from "react";
698
- import { renderToReadableStream as renderReactToReadableStream } from "react-dom/server";
699
- import { createSSRApp, h } from "vue";
700
- import { renderToWebStream as renderVueToWebStream } from "vue/server-renderer";
701
-
702
- // src/svelte/renderToReadableStream.ts
703
- import { render } from "svelte/server";
704
2490
 
705
- // src/utils/escapeScriptContent.ts
706
- var ESCAPE_LOOKUP = {
707
- "\u2028": "\\u2028",
708
- "\u2029": "\\u2029",
709
- "&": "\\u0026",
710
- "<": "\\u003C",
711
- ">": "\\u003E"
712
- };
713
- var ESCAPE_REGEX = /[&><\u2028\u2029]/g;
714
- var escapeScriptContent = (content) => content.replace(ESCAPE_REGEX, (char) => {
715
- const escaped = ESCAPE_LOOKUP[char];
716
- return escaped !== undefined ? escaped : char;
717
- });
2491
+ // src/dev/webSocket.ts
2492
+ var handleClientConnect = (state, client2, manifest) => {
2493
+ state.connectedClients.add(client2);
2494
+ const serverVersions = serializeModuleVersions(state.moduleVersions);
2495
+ client2.send(JSON.stringify({
2496
+ data: {
2497
+ manifest,
2498
+ serverVersions
2499
+ },
2500
+ timestamp: Date.now(),
2501
+ type: "manifest"
2502
+ }));
2503
+ client2.send(JSON.stringify({
2504
+ message: "HMR client connected successfully",
2505
+ timestamp: Date.now(),
2506
+ type: "connected"
2507
+ }));
2508
+ };
2509
+ var handleClientDisconnect = (state, client2) => {
2510
+ state.connectedClients.delete(client2);
2511
+ };
2512
+ var handleHMRMessage = (state, client2, message) => {
2513
+ try {
2514
+ let parsedData;
2515
+ if (typeof message === "string") {
2516
+ parsedData = JSON.parse(message);
2517
+ } else if (message instanceof Buffer) {
2518
+ parsedData = JSON.parse(message.toString());
2519
+ } else if (message instanceof ArrayBuffer) {
2520
+ parsedData = JSON.parse(new TextDecoder().decode(new Uint8Array(message)));
2521
+ } else if (ArrayBuffer.isView(message)) {
2522
+ parsedData = JSON.parse(new TextDecoder().decode(message));
2523
+ } else if (typeof message === "object" && message !== null) {
2524
+ parsedData = message;
2525
+ } else {
2526
+ return;
2527
+ }
2528
+ if (!isValidHMRClientMessage(parsedData)) {
2529
+ return;
2530
+ }
2531
+ const data = parsedData;
2532
+ switch (data.type) {
2533
+ case "ping":
2534
+ client2.send(JSON.stringify({
2535
+ timestamp: Date.now(),
2536
+ type: "pong"
2537
+ }));
2538
+ break;
2539
+ case "request-rebuild":
2540
+ break;
2541
+ case "ready":
2542
+ break;
2543
+ case "hydration-error":
2544
+ break;
2545
+ }
2546
+ } catch {}
2547
+ };
2548
+ var broadcastToClients = (state, message) => {
2549
+ const messageStr = JSON.stringify({
2550
+ ...message,
2551
+ timestamp: Date.now()
2552
+ });
2553
+ let sentCount = 0;
2554
+ const clientsToRemove = [];
2555
+ for (const client2 of state.connectedClients) {
2556
+ if (client2.readyState === WS_READY_STATE_OPEN) {
2557
+ try {
2558
+ client2.send(messageStr);
2559
+ sentCount++;
2560
+ } catch {
2561
+ clientsToRemove.push(client2);
2562
+ }
2563
+ } else {
2564
+ clientsToRemove.push(client2);
2565
+ }
2566
+ }
2567
+ for (const client2 of clientsToRemove) {
2568
+ state.connectedClients.delete(client2);
2569
+ }
2570
+ };
718
2571
 
719
- // src/svelte/renderToReadableStream.ts
720
- var renderToReadableStream = async (component, props, {
721
- bootstrapScriptContent,
722
- bootstrapScripts = [],
723
- bootstrapModules = [],
724
- nonce,
725
- onError = console.error,
726
- progressiveChunkSize = DEFAULT_CHUNK_SIZE,
727
- signal
728
- } = {}) => {
2572
+ // src/dev/rebuildTrigger.ts
2573
+ var parseErrorLocationFromMessage = (msg) => {
2574
+ const pathLineCol = msg.match(/^([^\s:]+):(\d+)(?::(\d+))?/);
2575
+ if (pathLineCol) {
2576
+ const [, file4, lineStr, colStr] = pathLineCol;
2577
+ return {
2578
+ file: file4,
2579
+ line: lineStr ? parseInt(lineStr, 10) : undefined,
2580
+ column: colStr ? parseInt(colStr, 10) : undefined
2581
+ };
2582
+ }
2583
+ const atMatch = msg.match(/(?:at|in)\s+([^(:\s]+)(?:\s*\([^)]*line\s*(\d+)[^)]*col(?:umn)?\s*(\d+)[^)]*\)|:(\d+):(\d+)?)/i);
2584
+ if (atMatch) {
2585
+ const [, file4, line1, col1, line2, col2] = atMatch;
2586
+ return {
2587
+ file: file4?.trim(),
2588
+ line: line1 ? parseInt(line1, 10) : line2 ? parseInt(line2, 10) : undefined,
2589
+ column: col1 ? parseInt(col1, 10) : col2 ? parseInt(col2, 10) : undefined
2590
+ };
2591
+ }
2592
+ const parenMatch = msg.match(/([^\s(]+)\s*\([^)]*line\s*(\d+)[^)]*col(?:umn)?\s*(\d+)/i);
2593
+ if (parenMatch) {
2594
+ const [, file4, lineStr, colStr] = parenMatch;
2595
+ return {
2596
+ file: file4 ?? undefined,
2597
+ line: lineStr ? parseInt(lineStr, 10) : undefined,
2598
+ column: colStr ? parseInt(colStr, 10) : undefined
2599
+ };
2600
+ }
2601
+ return {};
2602
+ };
2603
+ var extractBuildErrorDetails = (error, affectedFrameworks, resolvedPaths) => {
2604
+ let logs = error?.logs;
2605
+ if (!logs && error instanceof AggregateError && error.errors?.length) {
2606
+ logs = error.errors;
2607
+ }
2608
+ if (logs && Array.isArray(logs) && logs.length > 0) {
2609
+ const errLog = logs.find((l) => l.level === "error") ?? logs[0];
2610
+ const pos = errLog?.position;
2611
+ const file4 = pos && "file" in pos ? pos.file : undefined;
2612
+ const line = pos && "line" in pos ? pos.line : undefined;
2613
+ const column = pos && "column" in pos ? pos.column : undefined;
2614
+ const lineText = pos && "lineText" in pos ? pos.lineText : undefined;
2615
+ const framework = file4 && resolvedPaths ? detectFramework(file4, resolvedPaths) : affectedFrameworks[0] ?? "unknown";
2616
+ return {
2617
+ file: file4,
2618
+ line,
2619
+ column,
2620
+ lineText,
2621
+ framework: framework !== "ignored" ? framework : affectedFrameworks[0]
2622
+ };
2623
+ }
2624
+ const msg = error instanceof Error ? error.message : String(error);
2625
+ const parsed = parseErrorLocationFromMessage(msg);
2626
+ let fw = affectedFrameworks[0];
2627
+ if (parsed.file && resolvedPaths) {
2628
+ const detected = detectFramework(parsed.file, resolvedPaths);
2629
+ fw = detected !== "ignored" ? detected : affectedFrameworks[0];
2630
+ }
2631
+ return { ...parsed, framework: fw };
2632
+ };
2633
+ var queueFileChange = (state, filePath, config, onRebuildComplete) => {
2634
+ const framework = detectFramework(filePath, state.resolvedPaths);
2635
+ if (framework === "ignored") {
2636
+ return;
2637
+ }
2638
+ const currentHash = computeFileHash(filePath);
2639
+ if (!hasFileChanged(filePath, currentHash, state.fileHashes)) {
2640
+ return;
2641
+ }
2642
+ if (!state.fileChangeQueue.has(framework)) {
2643
+ state.fileChangeQueue.set(framework, []);
2644
+ }
2645
+ const queue = state.fileChangeQueue.get(framework);
2646
+ if (!queue.includes(filePath)) {
2647
+ queue.push(filePath);
2648
+ }
2649
+ if (state.isRebuilding) {
2650
+ return;
2651
+ }
2652
+ if (state.rebuildTimeout) {
2653
+ clearTimeout(state.rebuildTimeout);
2654
+ }
2655
+ const DEBOUNCE_MS = config.options?.hmr?.debounceMs ?? 500;
2656
+ state.rebuildTimeout = setTimeout(() => {
2657
+ const filesToProcess = new Map;
2658
+ const uniqueFilesByFramework = new Map;
2659
+ for (const [fwKey, filePaths] of state.fileChangeQueue) {
2660
+ uniqueFilesByFramework.set(fwKey, new Set(filePaths));
2661
+ }
2662
+ for (const [fwKey, filePathSet] of uniqueFilesByFramework) {
2663
+ const validFiles = [];
2664
+ const processedFiles = new Set;
2665
+ for (const filePathInSet of filePathSet) {
2666
+ if (!existsSync5(filePathInSet)) {
2667
+ state.fileHashes.delete(filePathInSet);
2668
+ try {
2669
+ const affectedFiles = getAffectedFiles(state.dependencyGraph, filePathInSet);
2670
+ const deletedPathResolved = resolve17(filePathInSet);
2671
+ for (const affectedFile of affectedFiles) {
2672
+ if (affectedFile !== deletedPathResolved && !processedFiles.has(affectedFile) && existsSync5(affectedFile)) {
2673
+ validFiles.push(affectedFile);
2674
+ processedFiles.add(affectedFile);
2675
+ }
2676
+ }
2677
+ } catch {}
2678
+ continue;
2679
+ }
2680
+ const fileHash = computeFileHash(filePathInSet);
2681
+ const storedHash = state.fileHashes.get(filePathInSet);
2682
+ if (!storedHash || storedHash !== fileHash) {
2683
+ const normalizedFilePath = resolve17(filePathInSet);
2684
+ if (!processedFiles.has(normalizedFilePath)) {
2685
+ validFiles.push(normalizedFilePath);
2686
+ processedFiles.add(normalizedFilePath);
2687
+ }
2688
+ state.fileHashes.set(normalizedFilePath, fileHash);
2689
+ incrementSourceFileVersions(state, [normalizedFilePath]);
2690
+ try {
2691
+ const dependents = state.dependencyGraph.dependents.get(normalizedFilePath);
2692
+ if (dependents && dependents.size > 0) {
2693
+ const dependentFiles = Array.from(dependents).filter((f) => existsSync5(f));
2694
+ if (dependentFiles.length > 0) {
2695
+ incrementSourceFileVersions(state, dependentFiles);
2696
+ }
2697
+ }
2698
+ } catch {}
2699
+ try {
2700
+ const affectedFiles = getAffectedFiles(state.dependencyGraph, normalizedFilePath);
2701
+ for (const affectedFile of affectedFiles) {
2702
+ if (!processedFiles.has(affectedFile) && affectedFile !== normalizedFilePath && existsSync5(affectedFile)) {
2703
+ validFiles.push(affectedFile);
2704
+ processedFiles.add(affectedFile);
2705
+ }
2706
+ }
2707
+ } catch {
2708
+ if (!processedFiles.has(normalizedFilePath)) {
2709
+ validFiles.push(normalizedFilePath);
2710
+ processedFiles.add(normalizedFilePath);
2711
+ }
2712
+ }
2713
+ }
2714
+ }
2715
+ if (validFiles.length > 0) {
2716
+ const firstFile = validFiles[0];
2717
+ if (firstFile) {
2718
+ const detectedFramework = detectFramework(firstFile, state.resolvedPaths);
2719
+ filesToProcess.set(detectedFramework, validFiles);
2720
+ }
2721
+ }
2722
+ }
2723
+ state.fileChangeQueue.clear();
2724
+ if (filesToProcess.size === 0) {
2725
+ return;
2726
+ }
2727
+ const affectedFrameworks = Array.from(filesToProcess.keys());
2728
+ for (const frameworkKey of affectedFrameworks) {
2729
+ state.rebuildQueue.add(frameworkKey);
2730
+ }
2731
+ const filesToRebuild = [];
2732
+ for (const [, filePaths] of filesToProcess) {
2733
+ filesToRebuild.push(...filePaths);
2734
+ }
2735
+ triggerRebuild(state, config, onRebuildComplete, filesToRebuild);
2736
+ }, DEBOUNCE_MS);
2737
+ };
2738
+ var triggerRebuild = async (state, config, onRebuildComplete, filesToRebuild) => {
2739
+ if (state.isRebuilding) {
2740
+ return null;
2741
+ }
2742
+ state.isRebuilding = true;
2743
+ const affectedFrameworks = Array.from(state.rebuildQueue);
2744
+ state.rebuildQueue.clear();
2745
+ const startTime = Date.now();
2746
+ broadcastToClients(state, {
2747
+ data: { affectedFrameworks },
2748
+ message: "Rebuild started...",
2749
+ type: "rebuild-start"
2750
+ });
729
2751
  try {
730
- const { head, body } = typeof props === "undefined" ? render(component) : render(component, { props });
731
- const nonceAttr = nonce ? ` nonce="${nonce}"` : "";
732
- const scripts = (bootstrapScriptContent ? `<script${nonceAttr}>${escapeScriptContent(bootstrapScriptContent)}</script>` : "") + bootstrapScripts.map((src) => `<script${nonceAttr} src="${src}"></script>`).join("") + bootstrapModules.map((src) => `<script${nonceAttr} type="module" src="${src}"></script>`).join("");
733
- const encoder = new TextEncoder;
734
- const full = encoder.encode(`<!DOCTYPE html><html lang="en"><head>${head}</head><body>${body}${scripts}</body></html>`);
735
- let offset = 0;
736
- return new ReadableStream({
737
- type: "bytes",
738
- cancel(reason) {
739
- onError?.(reason);
2752
+ const manifest = await build2({
2753
+ ...config,
2754
+ incrementalFiles: filesToRebuild && filesToRebuild.length > 0 ? filesToRebuild : undefined,
2755
+ options: {
2756
+ ...config.options,
2757
+ preserveIntermediateFiles: true,
2758
+ throwOnError: true
2759
+ }
2760
+ });
2761
+ if (!manifest) {
2762
+ throw new Error("Build failed - no manifest generated");
2763
+ }
2764
+ const duration = Date.now() - startTime;
2765
+ logger.rebuilt(duration);
2766
+ broadcastToClients(state, {
2767
+ data: {
2768
+ affectedFrameworks,
2769
+ manifest
740
2770
  },
741
- pull(controller) {
742
- if (signal?.aborted) {
743
- controller.close();
744
- return;
2771
+ message: "Rebuild completed successfully",
2772
+ type: "rebuild-complete"
2773
+ });
2774
+ if (filesToRebuild && filesToRebuild.length > 0) {
2775
+ const allModuleUpdates = [];
2776
+ for (const framework of affectedFrameworks) {
2777
+ const frameworkFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === framework);
2778
+ if (frameworkFiles.length > 0) {
2779
+ const moduleUpdates = createModuleUpdates(frameworkFiles, framework, manifest, state.resolvedPaths);
2780
+ if (moduleUpdates.length > 0) {
2781
+ allModuleUpdates.push(...moduleUpdates);
2782
+ }
745
2783
  }
746
- if (offset >= full.length) {
747
- controller.close();
748
- return;
2784
+ }
2785
+ if (affectedFrameworks.includes("react") && filesToRebuild && state.resolvedPaths.reactDir) {
2786
+ const reactFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "react");
2787
+ if (reactFiles.length > 0) {
2788
+ const reactPageFiles = reactFiles.filter((file4) => {
2789
+ const normalized = file4.replace(/\\/g, "/");
2790
+ return normalized.includes("/pages/");
2791
+ });
2792
+ const sourceFiles = reactPageFiles.length > 0 ? reactPageFiles : reactFiles;
2793
+ const primarySource = sourceFiles[0];
2794
+ try {
2795
+ const hasComponentChanges = reactFiles.some((file4) => file4.endsWith(".tsx") || file4.endsWith(".ts") || file4.endsWith(".jsx"));
2796
+ const hasCSSChanges = reactFiles.some((file4) => file4.endsWith(".css"));
2797
+ if (hasCSSChanges && !hasComponentChanges) {
2798
+ logger.cssUpdate(primarySource ?? reactFiles[0] ?? "", "react");
2799
+ } else {
2800
+ logger.hmrUpdate(primarySource ?? reactFiles[0] ?? "", "react");
2801
+ }
2802
+ broadcastToClients(state, {
2803
+ data: {
2804
+ framework: "react",
2805
+ manifest,
2806
+ sourceFiles,
2807
+ primarySource,
2808
+ hasComponentChanges,
2809
+ hasCSSChanges
2810
+ },
2811
+ type: "react-update"
2812
+ });
2813
+ } catch {}
749
2814
  }
750
- const end = Math.min(offset + progressiveChunkSize, full.length);
751
- controller.enqueue(full.subarray(offset, end));
752
- offset = end;
753
2815
  }
754
- });
2816
+ if (affectedFrameworks.includes("html") && filesToRebuild && state.resolvedPaths.htmlDir) {
2817
+ const htmlFrameworkFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "html");
2818
+ if (htmlFrameworkFiles.length > 0) {
2819
+ const scriptFiles = htmlFrameworkFiles.filter((f) => (f.endsWith(".ts") || f.endsWith(".js") || f.endsWith(".tsx") || f.endsWith(".jsx")) && f.replace(/\\/g, "/").includes("/scripts/"));
2820
+ const htmlPageFiles = htmlFrameworkFiles.filter((f) => f.endsWith(".html"));
2821
+ if (scriptFiles.length > 0 && htmlPageFiles.length === 0) {
2822
+ for (const scriptFile of scriptFiles) {
2823
+ const { basename: basename9 } = await import("path");
2824
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
2825
+ const scriptBaseName = basename9(scriptFile).replace(/\.(ts|js|tsx|jsx)$/, "");
2826
+ const pascalName = toPascal2(scriptBaseName);
2827
+ const manifestKey = pascalName;
2828
+ const scriptPath = manifest[manifestKey] || null;
2829
+ if (scriptPath) {
2830
+ logger.scriptUpdate(scriptFile, "html");
2831
+ broadcastToClients(state, {
2832
+ data: {
2833
+ framework: "html",
2834
+ scriptPath,
2835
+ sourceFile: scriptFile,
2836
+ manifest
2837
+ },
2838
+ type: "script-update"
2839
+ });
2840
+ } else {
2841
+ logger.warn(`Script not found in manifest: ${manifestKey}`);
2842
+ }
2843
+ }
2844
+ }
2845
+ }
2846
+ }
2847
+ if (affectedFrameworks.includes("html") && filesToRebuild && state.resolvedPaths.htmlDir) {
2848
+ const htmlFrameworkFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "html");
2849
+ if (htmlFrameworkFiles.length > 0) {
2850
+ const htmlPageFiles = htmlFrameworkFiles.filter((f) => f.endsWith(".html"));
2851
+ const pagesToUpdate = htmlPageFiles;
2852
+ const isSingle = !config.reactDirectory && !config.svelteDirectory && !config.vueDirectory && !config.htmxDirectory;
2853
+ const outputHtmlPages = isSingle ? resolve17(state.resolvedPaths.buildDir, "pages") : resolve17(state.resolvedPaths.buildDir, basename8(config.htmlDirectory ?? "html"), "pages");
2854
+ for (const pageFile of pagesToUpdate) {
2855
+ const htmlPageName = basename8(pageFile);
2856
+ const builtHtmlPagePath = resolve17(outputHtmlPages, htmlPageName);
2857
+ try {
2858
+ const { handleHTMLUpdate: handleHTMLUpdate2 } = await Promise.resolve().then(() => (init_simpleHTMLHMR(), exports_simpleHTMLHMR));
2859
+ const newHTML = await handleHTMLUpdate2(builtHtmlPagePath);
2860
+ if (newHTML) {
2861
+ logger.hmrUpdate(pageFile, "html");
2862
+ broadcastToClients(state, {
2863
+ data: {
2864
+ framework: "html",
2865
+ html: newHTML,
2866
+ sourceFile: builtHtmlPagePath
2867
+ },
2868
+ type: "html-update"
2869
+ });
2870
+ }
2871
+ } catch {}
2872
+ }
2873
+ }
2874
+ }
2875
+ if (affectedFrameworks.includes("vue") && filesToRebuild && config.vueDirectory) {
2876
+ const vueFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "vue");
2877
+ if (vueFiles.length > 0) {
2878
+ const vueComponentFiles = vueFiles.filter((f) => f.endsWith(".vue"));
2879
+ const vueCssFiles = vueFiles.filter((f) => f.endsWith(".css"));
2880
+ const isCssOnlyChange = vueComponentFiles.length === 0 && vueCssFiles.length > 0;
2881
+ const vuePageFiles = vueFiles.filter((f) => f.replace(/\\/g, "/").includes("/pages/"));
2882
+ const pagesToUpdate = vuePageFiles.length > 0 ? vuePageFiles : vueComponentFiles;
2883
+ if (isCssOnlyChange && vueCssFiles.length > 0) {
2884
+ const { basename: basename9 } = await import("path");
2885
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
2886
+ const cssFile = vueCssFiles[0];
2887
+ if (cssFile) {
2888
+ const cssBaseName = basename9(cssFile, ".css");
2889
+ const cssPascalName = toPascal2(cssBaseName);
2890
+ const cssKey = `${cssPascalName}CSS`;
2891
+ const cssUrl = manifest[cssKey] || null;
2892
+ logger.cssUpdate(cssFile, "vue");
2893
+ broadcastToClients(state, {
2894
+ data: {
2895
+ framework: "vue",
2896
+ updateType: "css-only",
2897
+ cssUrl,
2898
+ cssBaseName,
2899
+ manifest,
2900
+ sourceFile: cssFile
2901
+ },
2902
+ type: "vue-update"
2903
+ });
2904
+ }
2905
+ }
2906
+ for (const vuePagePath of pagesToUpdate) {
2907
+ try {
2908
+ const { basename: basename9, relative: relative5 } = await import("path");
2909
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
2910
+ const fileName = basename9(vuePagePath);
2911
+ const baseName = fileName.replace(/\.vue$/, "");
2912
+ const pascalName = toPascal2(baseName);
2913
+ const vueRoot = config.vueDirectory;
2914
+ const hmrId = vueRoot ? relative5(vueRoot, vuePagePath).replace(/\\/g, "/").replace(/\.vue$/, "") : baseName;
2915
+ const cssKey = `${pascalName}CSS`;
2916
+ const cssUrl = manifest[cssKey] || null;
2917
+ const { vueHmrMetadata: vueHmrMetadata2 } = await Promise.resolve().then(() => (init_compileVue(), exports_compileVue));
2918
+ const hmrMeta = vueHmrMetadata2.get(resolve17(vuePagePath));
2919
+ const changeType = hmrMeta?.changeType ?? "full";
2920
+ if (changeType === "style-only") {
2921
+ logger.cssUpdate(vuePagePath, "vue");
2922
+ broadcastToClients(state, {
2923
+ data: {
2924
+ framework: "vue",
2925
+ updateType: "css-only",
2926
+ changeType: "style-only",
2927
+ cssUrl,
2928
+ cssBaseName: baseName,
2929
+ hmrId,
2930
+ manifest,
2931
+ sourceFile: vuePagePath
2932
+ },
2933
+ type: "vue-update"
2934
+ });
2935
+ continue;
2936
+ }
2937
+ const { handleVueUpdate: handleVueUpdate2 } = await Promise.resolve().then(() => (init_simpleVueHMR(), exports_simpleVueHMR));
2938
+ const newHTML = await handleVueUpdate2(vuePagePath, manifest, state.resolvedPaths.buildDir);
2939
+ const componentPath = manifest[`${pascalName}Client`] || null;
2940
+ logger.hmrUpdate(vuePagePath, "vue");
2941
+ broadcastToClients(state, {
2942
+ data: {
2943
+ framework: "vue",
2944
+ html: newHTML,
2945
+ hmrId,
2946
+ changeType,
2947
+ componentPath,
2948
+ cssUrl,
2949
+ updateType: "full",
2950
+ manifest,
2951
+ sourceFile: vuePagePath
2952
+ },
2953
+ type: "vue-update"
2954
+ });
2955
+ } catch {}
2956
+ }
2957
+ }
2958
+ }
2959
+ if (affectedFrameworks.includes("svelte") && filesToRebuild && config.svelteDirectory) {
2960
+ const svelteFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "svelte");
2961
+ if (svelteFiles.length > 0) {
2962
+ const svelteComponentFiles = svelteFiles.filter((f) => f.endsWith(".svelte"));
2963
+ const svelteCssFiles = svelteFiles.filter((f) => f.endsWith(".css"));
2964
+ const isCssOnlyChange = svelteComponentFiles.length === 0 && svelteCssFiles.length > 0;
2965
+ const sveltePageFiles = svelteFiles.filter((f) => f.replace(/\\/g, "/").includes("/pages/"));
2966
+ const pagesToUpdate = sveltePageFiles.length > 0 ? sveltePageFiles : svelteComponentFiles;
2967
+ if (isCssOnlyChange && svelteCssFiles.length > 0) {
2968
+ const { basename: basename9 } = await import("path");
2969
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
2970
+ const cssFile = svelteCssFiles[0];
2971
+ if (cssFile) {
2972
+ const cssBaseName = basename9(cssFile, ".css");
2973
+ const cssPascalName = toPascal2(cssBaseName);
2974
+ const cssKey = `${cssPascalName}CSS`;
2975
+ const cssUrl = manifest[cssKey] || null;
2976
+ logger.cssUpdate(cssFile, "svelte");
2977
+ broadcastToClients(state, {
2978
+ data: {
2979
+ framework: "svelte",
2980
+ updateType: "css-only",
2981
+ cssUrl,
2982
+ cssBaseName,
2983
+ manifest,
2984
+ sourceFile: cssFile
2985
+ },
2986
+ type: "svelte-update"
2987
+ });
2988
+ }
2989
+ }
2990
+ for (const sveltePagePath of pagesToUpdate) {
2991
+ try {
2992
+ const { handleSvelteUpdate: handleSvelteUpdate2 } = await Promise.resolve().then(() => (init_simpleSvelteHMR(), exports_simpleSvelteHMR));
2993
+ const newHTML = await handleSvelteUpdate2(sveltePagePath, manifest, state.resolvedPaths.buildDir);
2994
+ const { basename: basename9 } = await import("path");
2995
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
2996
+ const fileName = basename9(sveltePagePath);
2997
+ const baseName = fileName.replace(/\.svelte$/, "");
2998
+ const pascalName = toPascal2(baseName);
2999
+ const cssKey = `${pascalName}CSS`;
3000
+ const cssUrl = manifest[cssKey] || null;
3001
+ logger.hmrUpdate(sveltePagePath, "svelte");
3002
+ broadcastToClients(state, {
3003
+ data: {
3004
+ framework: "svelte",
3005
+ html: newHTML,
3006
+ cssUrl,
3007
+ cssBaseName: baseName,
3008
+ updateType: "full",
3009
+ manifest,
3010
+ sourceFile: sveltePagePath
3011
+ },
3012
+ type: "svelte-update"
3013
+ });
3014
+ } catch {}
3015
+ }
3016
+ }
3017
+ }
3018
+ if (affectedFrameworks.includes("htmx") && filesToRebuild && state.resolvedPaths.htmxDir) {
3019
+ const htmxFrameworkFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "htmx");
3020
+ if (htmxFrameworkFiles.length > 0) {
3021
+ const htmxScriptFiles = htmxFrameworkFiles.filter((f) => (f.endsWith(".ts") || f.endsWith(".js") || f.endsWith(".tsx") || f.endsWith(".jsx")) && f.replace(/\\/g, "/").includes("/scripts/"));
3022
+ const htmxHtmlFiles = htmxFrameworkFiles.filter((f) => f.endsWith(".html"));
3023
+ if (htmxScriptFiles.length > 0 && htmxHtmlFiles.length === 0) {
3024
+ for (const scriptFile of htmxScriptFiles) {
3025
+ const { basename: basename9 } = await import("path");
3026
+ const { toPascal: toPascal2 } = await Promise.resolve().then(() => exports_stringModifiers);
3027
+ const scriptBaseName = basename9(scriptFile).replace(/\.(ts|js|tsx|jsx)$/, "");
3028
+ const pascalName = toPascal2(scriptBaseName);
3029
+ const manifestKey = pascalName;
3030
+ const scriptPath = manifest[manifestKey] || null;
3031
+ if (scriptPath) {
3032
+ logger.scriptUpdate(scriptFile, "htmx");
3033
+ broadcastToClients(state, {
3034
+ data: {
3035
+ framework: "htmx",
3036
+ scriptPath,
3037
+ sourceFile: scriptFile,
3038
+ manifest
3039
+ },
3040
+ type: "script-update"
3041
+ });
3042
+ }
3043
+ }
3044
+ }
3045
+ }
3046
+ }
3047
+ if (affectedFrameworks.includes("htmx") && filesToRebuild && state.resolvedPaths.htmxDir) {
3048
+ const htmxFrameworkFiles = filesToRebuild.filter((file4) => detectFramework(file4, state.resolvedPaths) === "htmx");
3049
+ if (htmxFrameworkFiles.length > 0) {
3050
+ const htmxPageFiles = htmxFrameworkFiles.filter((f) => f.endsWith(".html"));
3051
+ const isSingle = !config.reactDirectory && !config.svelteDirectory && !config.vueDirectory && !config.htmlDirectory;
3052
+ const outputHtmxPages = isSingle ? resolve17(state.resolvedPaths.buildDir, "pages") : resolve17(state.resolvedPaths.buildDir, basename8(config.htmxDirectory ?? "htmx"), "pages");
3053
+ for (const htmxPageFile of htmxPageFiles) {
3054
+ const htmxPageName = basename8(htmxPageFile);
3055
+ const builtHtmxPagePath = resolve17(outputHtmxPages, htmxPageName);
3056
+ try {
3057
+ const { handleHTMXUpdate: handleHTMXUpdate2 } = await Promise.resolve().then(() => (init_simpleHTMXHMR(), exports_simpleHTMXHMR));
3058
+ const newHTML = await handleHTMXUpdate2(builtHtmxPagePath);
3059
+ if (newHTML) {
3060
+ logger.hmrUpdate(htmxPageFile, "htmx");
3061
+ broadcastToClients(state, {
3062
+ data: {
3063
+ framework: "htmx",
3064
+ html: newHTML,
3065
+ sourceFile: builtHtmxPagePath
3066
+ },
3067
+ type: "htmx-update"
3068
+ });
3069
+ }
3070
+ } catch {}
3071
+ }
3072
+ }
3073
+ }
3074
+ const updatedModulePaths = [];
3075
+ for (const update of allModuleUpdates) {
3076
+ updatedModulePaths.push(update.sourceFile);
3077
+ for (const modulePath of Object.values(update.modulePaths)) {
3078
+ updatedModulePaths.push(modulePath);
3079
+ }
3080
+ }
3081
+ if (updatedModulePaths.length > 0) {
3082
+ incrementModuleVersions(state.moduleVersions, updatedModulePaths);
3083
+ }
3084
+ if (allModuleUpdates.length > 0) {
3085
+ const updatesByFramework = groupModuleUpdatesByFramework(allModuleUpdates);
3086
+ const serverVersions = serializeModuleVersions(state.moduleVersions);
3087
+ for (const [framework, updates] of updatesByFramework) {
3088
+ const moduleVersions = {};
3089
+ for (const update of updates) {
3090
+ const sourceVersion = state.moduleVersions.get(update.sourceFile);
3091
+ if (sourceVersion !== undefined) {
3092
+ moduleVersions[update.sourceFile] = sourceVersion;
3093
+ }
3094
+ for (const [, path] of Object.entries(update.modulePaths)) {
3095
+ const pathVersion = state.moduleVersions.get(path);
3096
+ if (pathVersion !== undefined) {
3097
+ moduleVersions[path] = pathVersion;
3098
+ }
3099
+ }
3100
+ }
3101
+ broadcastToClients(state, {
3102
+ data: {
3103
+ framework,
3104
+ manifest,
3105
+ modules: updates.map((update) => ({
3106
+ componentType: update.componentType,
3107
+ moduleKeys: update.moduleKeys,
3108
+ modulePaths: update.modulePaths,
3109
+ sourceFile: update.sourceFile,
3110
+ version: state.moduleVersions.get(update.sourceFile)
3111
+ })),
3112
+ moduleVersions,
3113
+ serverVersions
3114
+ },
3115
+ message: `${framework} modules updated`,
3116
+ type: "module-update"
3117
+ });
3118
+ }
3119
+ }
3120
+ }
3121
+ for (const framework of affectedFrameworks) {
3122
+ broadcastToClients(state, {
3123
+ data: {
3124
+ framework,
3125
+ manifest
3126
+ },
3127
+ message: `${framework} framework updated`,
3128
+ type: "framework-update"
3129
+ });
3130
+ }
3131
+ onRebuildComplete({ manifest, hmrState: state });
3132
+ await populateAssetStore(state.assetStore, manifest, state.resolvedPaths.buildDir);
3133
+ await cleanStaleAssets(state.assetStore, manifest, state.resolvedPaths.buildDir);
3134
+ return manifest;
755
3135
  } catch (error) {
756
- onError?.(error);
757
- throw error;
3136
+ const errorData = extractBuildErrorDetails(error, affectedFrameworks, state.resolvedPaths);
3137
+ broadcastToClients(state, {
3138
+ data: {
3139
+ affectedFrameworks,
3140
+ error: error instanceof Error ? error.message : String(error),
3141
+ ...errorData
3142
+ },
3143
+ message: "Rebuild failed",
3144
+ type: "rebuild-error"
3145
+ });
3146
+ return null;
3147
+ } finally {
3148
+ state.isRebuilding = false;
3149
+ if (state.fileChangeQueue.size > 0) {
3150
+ const pending = Array.from(state.fileChangeQueue.keys());
3151
+ const queuedFiles = [];
3152
+ for (const [, filePaths] of state.fileChangeQueue) {
3153
+ queuedFiles.push(...filePaths);
3154
+ }
3155
+ state.fileChangeQueue.clear();
3156
+ for (const f of pending)
3157
+ state.rebuildQueue.add(f);
3158
+ if (state.rebuildTimeout)
3159
+ clearTimeout(state.rebuildTimeout);
3160
+ state.rebuildTimeout = setTimeout(() => {
3161
+ triggerRebuild(state, config, onRebuildComplete, queuedFiles.length > 0 ? queuedFiles : undefined);
3162
+ }, 50);
3163
+ }
758
3164
  }
759
3165
  };
760
3166
 
761
- // src/core/pageHandlers.ts
762
- var handleReactPageRequest = async (pageComponent, index, ...props) => {
763
- const [maybeProps] = props;
764
- const element = maybeProps !== undefined ? createElement(pageComponent, maybeProps) : createElement(pageComponent);
765
- const stream = await renderReactToReadableStream(element, {
766
- bootstrapModules: [index],
767
- bootstrapScriptContent: maybeProps ? `window.__INITIAL_PROPS__=${JSON.stringify(maybeProps)}` : undefined
768
- });
769
- return new Response(stream, {
770
- headers: { "Content-Type": "text/html" }
771
- });
772
- };
773
- var handleSveltePageRequest = async (_PageComponent, pagePath, indexPath, props) => {
774
- const { default: ImportedPageComponent } = await import(pagePath);
775
- const stream = await renderToReadableStream(ImportedPageComponent, props, {
776
- bootstrapModules: indexPath ? [indexPath] : [],
777
- bootstrapScriptContent: `window.__INITIAL_PROPS__=${JSON.stringify(props)}`
778
- });
779
- return new Response(stream, {
780
- headers: { "Content-Type": "text/html" }
781
- });
782
- };
783
- var handleVuePageRequest = async (_PageComponent, pagePath, indexPath, headTag = "<head></head>", ...props) => {
784
- const [maybeProps] = props;
785
- const { default: ImportedPageComponent } = await import(pagePath);
786
- const app = createSSRApp({
787
- render: () => h(ImportedPageComponent, maybeProps ?? {})
788
- });
789
- const bodyStream = renderVueToWebStream(app);
790
- const head = `<!DOCTYPE html><html>${headTag}<body><div id="root">`;
791
- const tail = `</div><script>window.__INITIAL_PROPS__=${JSON.stringify(maybeProps ?? {})}</script><script type="module" src="${indexPath}"></script></body></html>`;
792
- const stream = new ReadableStream({
793
- start(controller) {
794
- controller.enqueue(head);
795
- const reader = bodyStream.getReader();
796
- const pumpLoop = () => {
797
- reader.read().then(({ done, value }) => done ? (controller.enqueue(tail), controller.close()) : (controller.enqueue(value), pumpLoop())).catch((err) => controller.error(err));
798
- };
799
- pumpLoop();
3167
+ // src/core/devBuild.ts
3168
+ var devBuild = async (config) => {
3169
+ const cached = globalThis.__hmrDevResult;
3170
+ if (cached) {
3171
+ const serverMtime = statSync(resolve18(Bun.main)).mtimeMs;
3172
+ const lastMtime = globalThis.__hmrServerMtime;
3173
+ globalThis.__hmrServerMtime = serverMtime;
3174
+ if (serverMtime !== lastMtime) {
3175
+ console.log("\x1B[36m[hmr] Server module reloaded\x1B[0m");
3176
+ } else {
3177
+ globalThis.__hmrSkipServerRestart = true;
3178
+ console.log("\x1B[36m[hmr] Hot module update detected\x1B[0m");
3179
+ }
3180
+ return cached;
3181
+ }
3182
+ const state = createHMRState(config);
3183
+ const watchPaths = getWatchPaths(config, state.resolvedPaths);
3184
+ buildInitialDependencyGraph(state.dependencyGraph, watchPaths);
3185
+ console.log("\uD83D\uDD28 Building AbsoluteJS with HMR...");
3186
+ const manifest = await build2({
3187
+ ...config,
3188
+ options: {
3189
+ ...config.options,
3190
+ preserveIntermediateFiles: true
800
3191
  }
801
3192
  });
802
- return new Response(stream, {
803
- headers: { "Content-Type": "text/html" }
3193
+ if (!manifest || Object.keys(manifest).length === 0) {
3194
+ console.log("\u26A0\uFE0F Manifest is empty - this is OK for HTML/HTMX-only projects");
3195
+ }
3196
+ await populateAssetStore(state.assetStore, manifest ?? {}, state.resolvedPaths.buildDir);
3197
+ await cleanStaleAssets(state.assetStore, manifest ?? {}, state.resolvedPaths.buildDir);
3198
+ console.log("\u2705 Build completed successfully");
3199
+ startFileWatching(state, config, (filePath) => {
3200
+ queueFileChange(state, filePath, config, (newBuildResult) => {
3201
+ Object.assign(manifest, newBuildResult.manifest);
3202
+ });
804
3203
  });
805
- };
806
- var handleHTMLPageRequest = (html) => file3(html);
807
- var handleHTMXPageRequest = (htmx) => file3(htmx);
808
- var handlePageRequest = (PageComponent, ...props) => {
809
- console.log("handlePageRequest coming soon.", PageComponent, props);
3204
+ console.log("\uD83D\uDC40 File watching: Active");
3205
+ console.log("\uD83D\uDD25 HMR: Ready");
3206
+ const result = {
3207
+ hmrState: state,
3208
+ manifest
3209
+ };
3210
+ globalThis.__hmrServerStartup = Date.now().toString();
3211
+ globalThis.__hmrDevResult = result;
3212
+ globalThis.__hmrServerMtime = statSync(resolve18(Bun.main)).mtimeMs;
3213
+ return result;
810
3214
  };
811
3215
  // src/core/lookup.ts
812
- var asset = (manifest, name) => {
813
- const assetPath = manifest[name];
3216
+ var isWrapped = (source) => ("manifest" in source) && typeof source.manifest === "object" && !Array.isArray(source.manifest);
3217
+ var asset = (source, name) => {
3218
+ const assetPath = isWrapped(source) ? source.manifest[name] : source[name];
814
3219
  if (assetPath === undefined) {
815
3220
  throw new Error(`Asset "${name}" not found in manifest.`);
816
3221
  }
817
3222
  return assetPath;
818
3223
  };
3224
+
3225
+ // src/core/index.ts
3226
+ init_pageHandlers();
3227
+ // src/plugins/pageRouter.ts
3228
+ var pageRouterPlugin = () => {
3229
+ console.log("Page Router Plugin Not Implemented Yet");
3230
+ };
3231
+ // src/plugins/hmr.ts
3232
+ var STORE_KEY = "__elysiaStore";
3233
+ var restoreStore = (app) => {
3234
+ const saved = globalThis[STORE_KEY];
3235
+ if (saved) {
3236
+ const store = app.store;
3237
+ for (const key of Object.keys(saved)) {
3238
+ store[key] = saved[key];
3239
+ }
3240
+ }
3241
+ globalThis[STORE_KEY] = app.store;
3242
+ };
3243
+ var hmr = (hmrState2, manifest) => {
3244
+ return (app) => {
3245
+ restoreStore(app);
3246
+ return app.onBeforeHandle(({ request }) => {
3247
+ const rawUrl = request.url;
3248
+ const qIdx = rawUrl.indexOf("?");
3249
+ const pathEnd = qIdx === -1 ? rawUrl.length : qIdx;
3250
+ const pathStart = rawUrl.indexOf("/", rawUrl.indexOf("//") + 2);
3251
+ const pathname = rawUrl.slice(pathStart, pathEnd);
3252
+ const bytes = lookupAsset(hmrState2.assetStore, pathname);
3253
+ if (bytes) {
3254
+ return new Response(new Uint8Array(bytes).buffer, {
3255
+ headers: {
3256
+ "Cache-Control": "public, max-age=31536000, immutable",
3257
+ "Content-Type": getMimeType(pathname)
3258
+ }
3259
+ });
3260
+ }
3261
+ }).ws("/hmr", {
3262
+ close: (ws) => handleClientDisconnect(hmrState2, ws),
3263
+ message: (ws, msg) => handleHMRMessage(hmrState2, ws, msg),
3264
+ open: (ws) => handleClientConnect(hmrState2, ws, manifest)
3265
+ }).get("/hmr-status", () => ({
3266
+ connectedClients: hmrState2.connectedClients.size,
3267
+ isRebuilding: hmrState2.isRebuilding,
3268
+ manifestKeys: Object.keys(manifest),
3269
+ rebuildQueue: Array.from(hmrState2.rebuildQueue),
3270
+ timestamp: Date.now()
3271
+ }));
3272
+ };
3273
+ };
819
3274
  // src/plugins/networking.ts
3275
+ init_constants();
820
3276
  import { argv } from "process";
821
3277
  var {env: env3 } = globalThis.Bun;
822
3278
 
823
3279
  // src/utils/networking.ts
824
3280
  import os from "os";
825
- var getLocalIPAddress = () => {
3281
+ var getAllNetworkIPs = () => {
826
3282
  const interfaces = os.networkInterfaces();
827
3283
  const addresses = Object.values(interfaces).flat().filter((iface) => iface !== undefined);
828
- const ipAddress = addresses.find((iface) => iface.family === "IPv4" && !iface.internal);
829
- if (ipAddress)
830
- return ipAddress.address;
3284
+ const ipv4Addresses = [];
3285
+ for (const addr of addresses) {
3286
+ if (addr.internal)
3287
+ continue;
3288
+ if (addr.family === "IPv4") {
3289
+ ipv4Addresses.push(addr.address);
3290
+ }
3291
+ }
3292
+ return ipv4Addresses;
3293
+ };
3294
+ var getLocalIPAddress = () => {
3295
+ const allIPs = getAllNetworkIPs();
3296
+ if (allIPs.length > 0 && allIPs[0]) {
3297
+ return allIPs[0];
3298
+ }
831
3299
  console.warn("No IP address found, falling back to localhost");
832
3300
  return "localhost";
833
3301
  };
@@ -853,28 +3321,6 @@ var networking = (app) => app.listen({
853
3321
  console.log(`Server started on http://${host}:${port}`);
854
3322
  }
855
3323
  });
856
- // src/plugins/pageRouter.ts
857
- var pageRouterPlugin = () => {
858
- console.log("Page Router Plugin Not Implemented Yet");
859
- };
860
- // src/utils/generateHeadElement.ts
861
- var generateHeadElement = ({
862
- cssPath,
863
- title = "AbsoluteJS",
864
- description = "A page created using AbsoluteJS",
865
- font,
866
- icon = "/assets/ico/favicon.ico"
867
- } = {}) => `<head>
868
- <meta charset="UTF-8">
869
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
870
- <title>${title}</title>
871
- <meta name="description" content="${description}">
872
- <link rel="icon" href="${icon}" type="image/x-icon">
873
- ${font ? `<link rel="preconnect" href="https://fonts.googleapis.com">
874
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
875
- <link href="https://fonts.googleapis.com/css2?family=${font}:wght@100..900&display=swap" rel="stylesheet">` : ""}
876
- ${cssPath ? `<link rel="stylesheet" href="${cssPath}" type="text/css">` : ""}
877
- </head>`;
878
3324
  // src/utils/getEnv.ts
879
3325
  var {env: env4 } = globalThis.Bun;
880
3326
  var getEnv = (key) => {
@@ -884,21 +3330,108 @@ var getEnv = (key) => {
884
3330
  }
885
3331
  return environmentVariable;
886
3332
  };
3333
+ // src/utils/registerClientScript.ts
3334
+ var scriptRegistry = new Map;
3335
+ var requestCounter = 0;
3336
+ var getRequestId = () => `req_${Date.now()}_${++requestCounter}`;
3337
+ var registerClientScript = (script, requestId) => {
3338
+ const id = requestId || globalThis.__absolutejs_requestId || getRequestId();
3339
+ if (!scriptRegistry.has(id)) {
3340
+ scriptRegistry.set(id, new Set);
3341
+ }
3342
+ scriptRegistry.get(id).add(script);
3343
+ return id;
3344
+ };
3345
+ if (typeof globalThis !== "undefined") {
3346
+ globalThis.registerClientScript = registerClientScript;
3347
+ }
3348
+ var getAndClearClientScripts = (requestId) => {
3349
+ const scripts = scriptRegistry.get(requestId);
3350
+ if (!scripts) {
3351
+ return [];
3352
+ }
3353
+ const scriptArray = Array.from(scripts);
3354
+ scriptRegistry.delete(requestId);
3355
+ return scriptArray;
3356
+ };
3357
+ var generateClientScriptCode = (scripts) => {
3358
+ if (scripts.length === 0) {
3359
+ return "";
3360
+ }
3361
+ const scriptCode = scripts.map((script, index) => {
3362
+ const funcString = script.toString();
3363
+ const bodyMatch = funcString.match(/\{([\s\S]*)\}/);
3364
+ if (!bodyMatch || !bodyMatch[1]) {
3365
+ return "";
3366
+ }
3367
+ const body = bodyMatch[1].trim();
3368
+ return `
3369
+ (function() {
3370
+ function executeScript_${index}() {
3371
+ ${body}
3372
+ }
3373
+
3374
+ // Try executing immediately if DOM is ready
3375
+ if (document.readyState === 'complete' || document.readyState === 'interactive') {
3376
+ executeScript_${index}();
3377
+ } else {
3378
+ document.addEventListener('DOMContentLoaded', executeScript_${index});
3379
+ }
3380
+
3381
+ // Also try with delays to ensure element is available after hydration
3382
+ setTimeout(executeScript_${index}, 100);
3383
+ setTimeout(executeScript_${index}, 300);
3384
+ setTimeout(executeScript_${index}, 500);
3385
+ setTimeout(executeScript_${index}, 1000);
3386
+
3387
+ // Fallback on window load
3388
+ window.addEventListener('load', executeScript_${index});
3389
+ })();`;
3390
+ }).join(`
3391
+ `);
3392
+ return `<script>
3393
+ (function() {
3394
+ ${scriptCode}
3395
+ })();
3396
+ </script>`;
3397
+ };
3398
+ var clearAllClientScripts = () => {
3399
+ scriptRegistry.clear();
3400
+ };
3401
+ // src/utils/getRegisterClientScript.ts
3402
+ var getRegisterClientScript = () => {
3403
+ const globalRegister = globalThis.registerClientScript;
3404
+ if (globalRegister && typeof globalRegister === "function") {
3405
+ return globalRegister;
3406
+ }
3407
+ return null;
3408
+ };
887
3409
  export {
888
3410
  updateAssetPaths,
3411
+ registerClientScript,
889
3412
  pageRouterPlugin,
890
3413
  networking,
3414
+ isValidHMRClientMessage,
3415
+ hmrState,
3416
+ hmr,
891
3417
  handleVuePageRequest,
892
3418
  handleSveltePageRequest,
893
3419
  handleReactPageRequest,
894
3420
  handlePageRequest,
895
3421
  handleHTMXPageRequest,
896
3422
  handleHTMLPageRequest,
3423
+ getRegisterClientScript,
897
3424
  getLocalIPAddress,
898
3425
  getEnv,
3426
+ getAndClearClientScripts,
3427
+ getAllNetworkIPs,
899
3428
  generateHeadElement,
900
- build,
3429
+ generateClientScriptCode,
3430
+ devBuild,
3431
+ clearAllClientScripts,
3432
+ build2 as build,
901
3433
  asset,
3434
+ WS_READY_STATE_OPEN,
902
3435
  UNFOUND_INDEX,
903
3436
  TWO_THIRDS,
904
3437
  TIME_PRECISION,
@@ -913,5 +3446,5 @@ export {
913
3446
  BUN_BUILD_WARNING_SUPPRESSION
914
3447
  };
915
3448
 
916
- //# debugId=E4E62E702FF838A264756E2164756E21
3449
+ //# debugId=FE1A3F856A389BB564756E2164756E21
917
3450
  //# sourceMappingURL=index.js.map