heliumts 0.4.3 → 0.4.4

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.
@@ -1,6 +1,14 @@
1
+ /**
2
+ * Represents a server method stub that can be passed to client hooks like useFetch/useCall.
3
+ * This type is compatible with HeliumMethodDef so that methods defined with defineMethod
4
+ * can be passed directly to client hooks with proper type inference.
5
+ *
6
+ * Note: Using method shorthand syntax for `handler` makes it bivariant,
7
+ * allowing HeliumMethodDef (with HeliumContext) to be assignable to MethodStub.
8
+ */
1
9
  export type MethodStub<TArgs = unknown, TResult = unknown> = {
10
+ __kind: "method";
2
11
  __id: string;
3
- __args?: TArgs;
4
- __result?: TResult;
12
+ handler(args: TArgs, ctx: unknown): Promise<TResult> | TResult;
5
13
  };
6
14
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,CAAC,KAAK,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,KAAK,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,CAAC,KAAK,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI;IACzD,MAAM,EAAE,QAAQ,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAClE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"","sourcesContent":["export type MethodStub<TArgs = unknown, TResult = unknown> = {\n __id: string;\n __args?: TArgs;\n __result?: TResult;\n};\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/client/types.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Represents a server method stub that can be passed to client hooks like useFetch/useCall.\n * This type is compatible with HeliumMethodDef so that methods defined with defineMethod\n * can be passed directly to client hooks with proper type inference.\n *\n * Note: Using method shorthand syntax for `handler` makes it bivariant,\n * allowing HeliumMethodDef (with HeliumContext) to be assignable to MethodStub.\n */\nexport type MethodStub<TArgs = unknown, TResult = unknown> = {\n __kind: \"method\";\n __id: string;\n handler(args: TArgs, ctx: unknown): Promise<TResult> | TResult;\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"heliumPlugin.d.ts","sourceRoot":"","sources":["../../src/vite/heliumPlugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAkBnC,MAAM,CAAC,OAAO,UAAU,MAAM,IAAI,MAAM,CAoVvC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAiBrG"}
1
+ {"version":3,"file":"heliumPlugin.d.ts","sourceRoot":"","sources":["../../src/vite/heliumPlugin.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAkBnC,MAAM,CAAC,OAAO,UAAU,MAAM,IAAI,MAAM,CAsYvC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAiBrG"}
@@ -155,7 +155,16 @@ export default function helium() {
155
155
  if (!fs.existsSync(typesDir)) {
156
156
  fs.mkdirSync(typesDir, { recursive: true });
157
157
  }
158
- fs.writeFileSync(dtsPath, dts);
158
+ // Only write if content has changed to avoid unnecessary TypeScript recompilation
159
+ if (fs.existsSync(dtsPath)) {
160
+ const existing = fs.readFileSync(dtsPath, "utf-8");
161
+ if (existing !== dts) {
162
+ fs.writeFileSync(dtsPath, dts);
163
+ }
164
+ }
165
+ else {
166
+ fs.writeFileSync(dtsPath, dts);
167
+ }
159
168
  // Check for route collisions in pages directory
160
169
  checkRouteCollisions(root);
161
170
  },
@@ -183,16 +192,40 @@ export default function helium() {
183
192
  req.url = "/index.html";
184
193
  next();
185
194
  });
186
- const regenerateTypes = () => {
187
- const { methods } = scanServerExports(root);
188
- const dts = generateTypeDefinitions(methods, root);
195
+ /**
196
+ * Write type definitions only if content has changed.
197
+ * This prevents unnecessary TypeScript recompilation.
198
+ */
199
+ const writeTypesIfChanged = (dts) => {
189
200
  const typesDir = path.join(root, "src", "types");
190
201
  const dtsPath = path.join(typesDir, "heliumts-server.d.ts");
191
202
  if (!fs.existsSync(typesDir)) {
192
203
  fs.mkdirSync(typesDir, { recursive: true });
193
204
  }
205
+ // Check if file exists and content is the same
206
+ if (fs.existsSync(dtsPath)) {
207
+ const existing = fs.readFileSync(dtsPath, "utf-8");
208
+ if (existing === dts) {
209
+ return false; // No change needed
210
+ }
211
+ }
194
212
  fs.writeFileSync(dtsPath, dts);
213
+ return true; // File was written
195
214
  };
215
+ const regenerateTypes = () => {
216
+ try {
217
+ const { methods } = scanServerExports(root);
218
+ const dts = generateTypeDefinitions(methods, root);
219
+ return writeTypesIfChanged(dts);
220
+ }
221
+ catch (e) {
222
+ log("error", "Failed to regenerate types", e);
223
+ return false;
224
+ }
225
+ };
226
+ // Debounce timer for file changes
227
+ let debounceTimer = null;
228
+ const DEBOUNCE_DELAY = 100; // ms
196
229
  const handleServerFileChange = async () => {
197
230
  // Regenerate type definitions
198
231
  regenerateTypes();
@@ -247,17 +280,30 @@ export default function helium() {
247
280
  server.watcher.add(configPath);
248
281
  }
249
282
  }
283
+ /**
284
+ * Debounced handler for server file changes.
285
+ * This prevents multiple rapid regenerations during file saves.
286
+ */
287
+ const debouncedHandleServerFileChange = () => {
288
+ if (debounceTimer) {
289
+ clearTimeout(debounceTimer);
290
+ }
291
+ debounceTimer = setTimeout(() => {
292
+ debounceTimer = null;
293
+ handleServerFileChange();
294
+ }, DEBOUNCE_DELAY);
295
+ };
250
296
  server.watcher.on("change", (file) => {
251
297
  const relative = path.relative(root, file);
252
298
  const normalized = normalizeToPosix(relative);
253
299
  // If a server file changed, regenerate everything
254
300
  if (normalized.startsWith(`${serverDir}/`)) {
255
- handleServerFileChange();
301
+ debouncedHandleServerFileChange();
256
302
  }
257
303
  // If config file changed, reload config and regenerate
258
304
  if (configFiles.some((cf) => normalized === cf)) {
259
305
  log("info", `Config file changed: ${normalized}`);
260
- handleServerFileChange();
306
+ debouncedHandleServerFileChange();
261
307
  }
262
308
  });
263
309
  server.watcher.on("add", (file) => {
@@ -265,7 +311,7 @@ export default function helium() {
265
311
  const normalized = normalizeToPosix(relative);
266
312
  // If a server file was added, regenerate everything
267
313
  if (normalized.startsWith(`${serverDir}/`)) {
268
- handleServerFileChange();
314
+ debouncedHandleServerFileChange();
269
315
  }
270
316
  });
271
317
  server.watcher.on("unlink", (file) => {
@@ -273,7 +319,7 @@ export default function helium() {
273
319
  const normalized = normalizeToPosix(relative);
274
320
  // If a server file was removed, regenerate everything
275
321
  if (normalized.startsWith(`${serverDir}/`)) {
276
- handleServerFileChange();
322
+ debouncedHandleServerFileChange();
277
323
  }
278
324
  });
279
325
  // We hook into the server start to attach our RPC server
@@ -1 +1 @@
1
- {"version":3,"file":"heliumPlugin.js","sourceRoot":"","sources":["../../src/vite/heliumPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { Plugin } from \"vite\";\n\nimport { clearConfigCache, getRpcClientConfig, loadConfig } from \"../server/config.js\";\nimport { attachToDevServer } from \"../server/devServer.js\";\nimport { createEnvDefines, injectEnvToProcess, loadEnvFiles } from \"../utils/envLoader.js\";\nimport { log } from \"../utils/logger.js\";\nimport {\n RESOLVED_VIRTUAL_CLIENT_MODULE_ID,\n RESOLVED_VIRTUAL_ENTRY_MODULE_ID,\n RESOLVED_VIRTUAL_SERVER_MANIFEST_ID,\n SERVER_DIR,\n VIRTUAL_CLIENT_MODULE_ID,\n VIRTUAL_ENTRY_MODULE_ID,\n VIRTUAL_SERVER_MANIFEST_ID,\n} from \"./paths.js\";\nimport { checkRouteCollisions, scanServerExports } from \"./scanner.js\";\nimport { generateClientModule, generateEntryModule, generateServerManifest, generateTypeDefinitions } from \"./virtualServerModule.js\";\n\nexport default function helium(): Plugin {\n let root = process.cwd();\n const serverDir = normalizeToPosix(SERVER_DIR);\n\n return {\n name: \"vite-plugin-helium\",\n enforce: \"pre\",\n configResolved(config) {\n root = config.root;\n\n // Load and inject environment variables\n const mode = config.mode || \"development\";\n const envVars = loadEnvFiles({ root, mode });\n injectEnvToProcess(envVars);\n },\n transformIndexHtml: {\n order: \"pre\",\n handler(html, _ctx) {\n // Check if HTML already has a script tag for entry\n if (html.includes(\"src/main.tsx\") || html.includes(\"src/main.ts\")) {\n return html; // User has their own entry, don't modify\n }\n\n // Ensure root div exists\n let modifiedHtml = html;\n if (!modifiedHtml.includes('id=\"root\"')) {\n modifiedHtml = modifiedHtml.replace(\"<body>\", '<body>\\n <div id=\"root\"></div>');\n }\n\n // Generate physical entry file\n const heliumDir = path.join(root, \"node_modules\", \".heliumts\");\n if (!fs.existsSync(heliumDir)) {\n fs.mkdirSync(heliumDir, { recursive: true });\n }\n const entryPath = path.join(heliumDir, \"entry.tsx\");\n fs.writeFileSync(entryPath, generateEntryModule());\n\n // Return with tags to inject the entry (runtime config is fetched by the client)\n return [\n {\n tag: \"script\",\n attrs: {\n type: \"module\",\n src: \"/node_modules/.heliumts/entry.tsx\",\n },\n injectTo: \"body\",\n },\n ];\n },\n },\n async config(config) {\n // Load environment variables before config is finalized\n const mode = config.mode || \"development\";\n const envVars = loadEnvFiles({ root, mode });\n\n // Create defines for client-side env variables\n const envDefines = createEnvDefines(envVars);\n\n // Load helium config to get client-side RPC transport settings\n const heliumConfig = await loadConfig(root);\n const rpcClientConfig = getRpcClientConfig(heliumConfig);\n\n // Provide default index.html if none exists\n return {\n appType: \"spa\",\n optimizeDeps: {\n include: [\"react-dom/client\"],\n // Exclude helium from pre-bundling since it's the framework itself\n // This ensures changes to helium are picked up immediately\n exclude: [\"heliumts\", \"heliumts/client\", \"heliumts/server\", \"heliumts/vite\"],\n },\n // SSR configuration to properly isolate server-only code\n ssr: {\n // Externalize Node.js built-in modules - these should never be bundled\n external: [\"util\", \"zlib\", \"http\", \"https\", \"http2\", \"fs\", \"path\", \"crypto\", \"stream\", \"os\", \"url\", \"net\", \"tls\", \"child_process\", \"worker_threads\"],\n // Don't externalize heliumts - let the plugin handle the client/server split\n noExternal: [\"heliumts\"],\n },\n // Ensure Node.js built-ins are not bundled for client\n build: {\n rollupOptions: {\n external: [\n // Node.js built-in modules should never be in client bundle\n /^node:/,\n \"util\",\n \"zlib\",\n \"http\",\n \"https\",\n \"http2\",\n \"fs\",\n \"path\",\n \"crypto\",\n \"stream\",\n \"os\",\n \"url\",\n \"net\",\n \"tls\",\n \"child_process\",\n \"worker_threads\",\n ],\n },\n },\n define: {\n ...envDefines,\n __HELIUM_RPC_TRANSPORT__: JSON.stringify(rpcClientConfig.transport),\n __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__: JSON.stringify(rpcClientConfig.autoHttpOnMobile),\n },\n };\n },\n resolveId(id, importer) {\n if (id === VIRTUAL_CLIENT_MODULE_ID) {\n if (isServerModule(importer, root, serverDir)) {\n return null;\n }\n return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;\n }\n if (id === VIRTUAL_SERVER_MANIFEST_ID) {\n return RESOLVED_VIRTUAL_SERVER_MANIFEST_ID;\n }\n if (id === VIRTUAL_ENTRY_MODULE_ID) {\n // Add .tsx extension so Vite knows it contains JSX\n return RESOLVED_VIRTUAL_ENTRY_MODULE_ID + \".tsx\";\n }\n // Intercept heliumts/server imports from client code\n if (id === \"heliumts/server\") {\n // If imported from server code, let it resolve normally\n if (isServerModule(importer, root, serverDir)) {\n return null;\n }\n // For client code, redirect to virtual client module\n return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;\n }\n return null;\n },\n load(id) {\n if (id === RESOLVED_VIRTUAL_CLIENT_MODULE_ID) {\n const { methods } = scanServerExports(root);\n return generateClientModule(methods);\n }\n if (id === RESOLVED_VIRTUAL_SERVER_MANIFEST_ID) {\n const { methods, httpHandlers, middleware, workers } = scanServerExports(root);\n return generateServerManifest(methods, httpHandlers, middleware, workers);\n }\n if (id === RESOLVED_VIRTUAL_ENTRY_MODULE_ID + \".tsx\") {\n return generateEntryModule();\n }\n },\n buildStart() {\n const { methods } = scanServerExports(root);\n const dts = generateTypeDefinitions(methods, root);\n const typesDir = path.join(root, \"src\", \"types\");\n const dtsPath = path.join(typesDir, \"heliumts-server.d.ts\");\n\n // Ensure src/types exists\n if (!fs.existsSync(typesDir)) {\n fs.mkdirSync(typesDir, { recursive: true });\n }\n fs.writeFileSync(dtsPath, dts);\n\n // Check for route collisions in pages directory\n checkRouteCollisions(root);\n },\n configureServer(server) {\n // Add middleware to handle HTML fallback for nested routes\n // This ensures that routes like /docs/guides/auth properly serve index.html\n // so the client-side router can handle them\n server.middlewares.use((req, res, next) => {\n const url = req.url || \"\";\n const cleanUrl = url.split(\"?\")[0];\n\n // Skip if:\n // - Has file extension (asset request)\n // - Is an API/special endpoint\n // - Is a dev server endpoint\n if (\n path.extname(cleanUrl) !== \"\" ||\n cleanUrl.startsWith(\"/api\") ||\n cleanUrl.startsWith(\"/webhooks\") ||\n cleanUrl.startsWith(\"/auth\") ||\n cleanUrl.startsWith(\"/@\") ||\n cleanUrl.startsWith(\"/__helium__\")\n ) {\n return next();\n }\n\n // For all other routes (including nested paths like /docs/guides/auth),\n // rewrite to index.html so Vite serves it and the client-side router handles routing\n req.url = \"/index.html\";\n next();\n });\n\n const regenerateTypes = () => {\n const { methods } = scanServerExports(root);\n const dts = generateTypeDefinitions(methods, root);\n const typesDir = path.join(root, \"src\", \"types\");\n const dtsPath = path.join(typesDir, \"heliumts-server.d.ts\");\n\n if (!fs.existsSync(typesDir)) {\n fs.mkdirSync(typesDir, { recursive: true });\n }\n fs.writeFileSync(dtsPath, dts);\n };\n\n const handleServerFileChange = async () => {\n // Regenerate type definitions\n regenerateTypes();\n\n // Invalidate the virtual modules so they get regenerated\n const clientModule = server.environments.client?.moduleGraph.getModuleById(RESOLVED_VIRTUAL_CLIENT_MODULE_ID);\n const serverModule = server.environments.ssr?.moduleGraph.getModuleById(RESOLVED_VIRTUAL_SERVER_MANIFEST_ID);\n\n if (clientModule) {\n server.environments.client?.moduleGraph.invalidateModule(clientModule);\n }\n if (serverModule) {\n server.environments.ssr?.moduleGraph.invalidateModule(serverModule);\n }\n\n // Reload the server manifest and re-register methods\n try {\n // Clear config cache to ensure fresh config is loaded\n clearConfigCache();\n const config = await loadConfig(root);\n const mod = await server.ssrLoadModule(VIRTUAL_SERVER_MANIFEST_ID);\n const registerAll = mod.registerAll;\n const httpHandlers = mod.httpHandlers || [];\n const middlewareHandler = mod.middlewareHandler || null;\n const workers = mod.workers || [];\n\n // Update the dev server registry with new methods and HTTP handlers\n if (server.httpServer) {\n attachToDevServer(\n server.httpServer,\n (registry, httpRouter) => {\n registerAll(registry);\n httpRouter.registerRoutes(httpHandlers);\n if (middlewareHandler) {\n registry.setMiddleware(middlewareHandler);\n httpRouter.setMiddleware(middlewareHandler);\n }\n },\n config,\n workers\n );\n }\n } catch (e) {\n log(\"error\", \"Failed to reload Helium server manifest\", e);\n }\n\n // Trigger HMR for any client code that imports heliumts/server\n server.ws.send({\n type: \"full-reload\",\n path: \"*\",\n });\n };\n\n // Watch server directory for changes\n const serverPath = path.join(root, serverDir);\n server.watcher.add(serverPath);\n\n // Watch config files for changes\n const configFiles = [\"helium.config.ts\", \"helium.config.js\", \"helium.config.mjs\"];\n for (const configFile of configFiles) {\n const configPath = path.join(root, configFile);\n if (fs.existsSync(configPath)) {\n server.watcher.add(configPath);\n }\n }\n\n server.watcher.on(\"change\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file changed, regenerate everything\n if (normalized.startsWith(`${serverDir}/`)) {\n handleServerFileChange();\n }\n\n // If config file changed, reload config and regenerate\n if (configFiles.some((cf) => normalized === cf)) {\n log(\"info\", `Config file changed: ${normalized}`);\n handleServerFileChange();\n }\n });\n\n server.watcher.on(\"add\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file was added, regenerate everything\n if (normalized.startsWith(`${serverDir}/`)) {\n handleServerFileChange();\n }\n });\n\n server.watcher.on(\"unlink\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file was removed, regenerate everything\n if (normalized.startsWith(`${serverDir}/`)) {\n handleServerFileChange();\n }\n });\n\n // We hook into the server start to attach our RPC server\n server.httpServer?.on(\"listening\", async () => {\n try {\n // Load config\n const config = await loadConfig(root);\n\n // Load the manifest using Vite's SSR loader\n // This allows us to load TS files directly and handle dependencies\n const mod = await server.ssrLoadModule(VIRTUAL_SERVER_MANIFEST_ID);\n const registerAll = mod.registerAll;\n const httpHandlers = mod.httpHandlers || [];\n const middlewareHandler = mod.middlewareHandler || null;\n const workers = mod.workers || [];\n\n if (server.httpServer) {\n attachToDevServer(\n server.httpServer,\n (registry, httpRouter) => {\n registerAll(registry);\n httpRouter.registerRoutes(httpHandlers);\n if (middlewareHandler) {\n registry.setMiddleware(middlewareHandler);\n httpRouter.setMiddleware(middlewareHandler);\n }\n },\n config,\n workers\n );\n }\n } catch (e) {\n log(\"error\", \"Failed to attach Helium RPC server\", e);\n }\n });\n },\n };\n}\n\n/**\n * Convert file path to POSIX format\n * @internal Exported for testing\n */\nexport function normalizeToPosix(filePath: string): string {\n return filePath.split(path.sep).join(\"/\");\n}\n\n/**\n * Check if an importer is a server module\n * @internal Exported for testing\n */\nexport function isServerModule(importer: string | undefined, root: string, serverDir: string): boolean {\n if (!importer || importer.startsWith(\"\\0\")) {\n return false;\n }\n\n const [importerPath] = importer.split(\"?\");\n if (!importerPath) {\n return false;\n }\n\n const relative = path.relative(root, importerPath);\n if (!relative || relative.startsWith(\"..\")) {\n return false;\n }\n\n const normalized = normalizeToPosix(relative);\n return normalized === serverDir || normalized.startsWith(`${serverDir}/`);\n}\n"]}
1
+ {"version":3,"file":"heliumPlugin.js","sourceRoot":"","sources":["../../src/vite/heliumPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\nimport type { Plugin } from \"vite\";\n\nimport { clearConfigCache, getRpcClientConfig, loadConfig } from \"../server/config.js\";\nimport { attachToDevServer } from \"../server/devServer.js\";\nimport { createEnvDefines, injectEnvToProcess, loadEnvFiles } from \"../utils/envLoader.js\";\nimport { log } from \"../utils/logger.js\";\nimport {\n RESOLVED_VIRTUAL_CLIENT_MODULE_ID,\n RESOLVED_VIRTUAL_ENTRY_MODULE_ID,\n RESOLVED_VIRTUAL_SERVER_MANIFEST_ID,\n SERVER_DIR,\n VIRTUAL_CLIENT_MODULE_ID,\n VIRTUAL_ENTRY_MODULE_ID,\n VIRTUAL_SERVER_MANIFEST_ID,\n} from \"./paths.js\";\nimport { checkRouteCollisions, scanServerExports } from \"./scanner.js\";\nimport { generateClientModule, generateEntryModule, generateServerManifest, generateTypeDefinitions } from \"./virtualServerModule.js\";\n\nexport default function helium(): Plugin {\n let root = process.cwd();\n const serverDir = normalizeToPosix(SERVER_DIR);\n\n return {\n name: \"vite-plugin-helium\",\n enforce: \"pre\",\n configResolved(config) {\n root = config.root;\n\n // Load and inject environment variables\n const mode = config.mode || \"development\";\n const envVars = loadEnvFiles({ root, mode });\n injectEnvToProcess(envVars);\n },\n transformIndexHtml: {\n order: \"pre\",\n handler(html, _ctx) {\n // Check if HTML already has a script tag for entry\n if (html.includes(\"src/main.tsx\") || html.includes(\"src/main.ts\")) {\n return html; // User has their own entry, don't modify\n }\n\n // Ensure root div exists\n let modifiedHtml = html;\n if (!modifiedHtml.includes('id=\"root\"')) {\n modifiedHtml = modifiedHtml.replace(\"<body>\", '<body>\\n <div id=\"root\"></div>');\n }\n\n // Generate physical entry file\n const heliumDir = path.join(root, \"node_modules\", \".heliumts\");\n if (!fs.existsSync(heliumDir)) {\n fs.mkdirSync(heliumDir, { recursive: true });\n }\n const entryPath = path.join(heliumDir, \"entry.tsx\");\n fs.writeFileSync(entryPath, generateEntryModule());\n\n // Return with tags to inject the entry (runtime config is fetched by the client)\n return [\n {\n tag: \"script\",\n attrs: {\n type: \"module\",\n src: \"/node_modules/.heliumts/entry.tsx\",\n },\n injectTo: \"body\",\n },\n ];\n },\n },\n async config(config) {\n // Load environment variables before config is finalized\n const mode = config.mode || \"development\";\n const envVars = loadEnvFiles({ root, mode });\n\n // Create defines for client-side env variables\n const envDefines = createEnvDefines(envVars);\n\n // Load helium config to get client-side RPC transport settings\n const heliumConfig = await loadConfig(root);\n const rpcClientConfig = getRpcClientConfig(heliumConfig);\n\n // Provide default index.html if none exists\n return {\n appType: \"spa\",\n optimizeDeps: {\n include: [\"react-dom/client\"],\n // Exclude helium from pre-bundling since it's the framework itself\n // This ensures changes to helium are picked up immediately\n exclude: [\"heliumts\", \"heliumts/client\", \"heliumts/server\", \"heliumts/vite\"],\n },\n // SSR configuration to properly isolate server-only code\n ssr: {\n // Externalize Node.js built-in modules - these should never be bundled\n external: [\"util\", \"zlib\", \"http\", \"https\", \"http2\", \"fs\", \"path\", \"crypto\", \"stream\", \"os\", \"url\", \"net\", \"tls\", \"child_process\", \"worker_threads\"],\n // Don't externalize heliumts - let the plugin handle the client/server split\n noExternal: [\"heliumts\"],\n },\n // Ensure Node.js built-ins are not bundled for client\n build: {\n rollupOptions: {\n external: [\n // Node.js built-in modules should never be in client bundle\n /^node:/,\n \"util\",\n \"zlib\",\n \"http\",\n \"https\",\n \"http2\",\n \"fs\",\n \"path\",\n \"crypto\",\n \"stream\",\n \"os\",\n \"url\",\n \"net\",\n \"tls\",\n \"child_process\",\n \"worker_threads\",\n ],\n },\n },\n define: {\n ...envDefines,\n __HELIUM_RPC_TRANSPORT__: JSON.stringify(rpcClientConfig.transport),\n __HELIUM_RPC_AUTO_HTTP_ON_MOBILE__: JSON.stringify(rpcClientConfig.autoHttpOnMobile),\n },\n };\n },\n resolveId(id, importer) {\n if (id === VIRTUAL_CLIENT_MODULE_ID) {\n if (isServerModule(importer, root, serverDir)) {\n return null;\n }\n return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;\n }\n if (id === VIRTUAL_SERVER_MANIFEST_ID) {\n return RESOLVED_VIRTUAL_SERVER_MANIFEST_ID;\n }\n if (id === VIRTUAL_ENTRY_MODULE_ID) {\n // Add .tsx extension so Vite knows it contains JSX\n return RESOLVED_VIRTUAL_ENTRY_MODULE_ID + \".tsx\";\n }\n // Intercept heliumts/server imports from client code\n if (id === \"heliumts/server\") {\n // If imported from server code, let it resolve normally\n if (isServerModule(importer, root, serverDir)) {\n return null;\n }\n // For client code, redirect to virtual client module\n return RESOLVED_VIRTUAL_CLIENT_MODULE_ID;\n }\n return null;\n },\n load(id) {\n if (id === RESOLVED_VIRTUAL_CLIENT_MODULE_ID) {\n const { methods } = scanServerExports(root);\n return generateClientModule(methods);\n }\n if (id === RESOLVED_VIRTUAL_SERVER_MANIFEST_ID) {\n const { methods, httpHandlers, middleware, workers } = scanServerExports(root);\n return generateServerManifest(methods, httpHandlers, middleware, workers);\n }\n if (id === RESOLVED_VIRTUAL_ENTRY_MODULE_ID + \".tsx\") {\n return generateEntryModule();\n }\n },\n buildStart() {\n const { methods } = scanServerExports(root);\n const dts = generateTypeDefinitions(methods, root);\n const typesDir = path.join(root, \"src\", \"types\");\n const dtsPath = path.join(typesDir, \"heliumts-server.d.ts\");\n\n // Ensure src/types exists\n if (!fs.existsSync(typesDir)) {\n fs.mkdirSync(typesDir, { recursive: true });\n }\n\n // Only write if content has changed to avoid unnecessary TypeScript recompilation\n if (fs.existsSync(dtsPath)) {\n const existing = fs.readFileSync(dtsPath, \"utf-8\");\n if (existing !== dts) {\n fs.writeFileSync(dtsPath, dts);\n }\n } else {\n fs.writeFileSync(dtsPath, dts);\n }\n\n // Check for route collisions in pages directory\n checkRouteCollisions(root);\n },\n configureServer(server) {\n // Add middleware to handle HTML fallback for nested routes\n // This ensures that routes like /docs/guides/auth properly serve index.html\n // so the client-side router can handle them\n server.middlewares.use((req, res, next) => {\n const url = req.url || \"\";\n const cleanUrl = url.split(\"?\")[0];\n\n // Skip if:\n // - Has file extension (asset request)\n // - Is an API/special endpoint\n // - Is a dev server endpoint\n if (\n path.extname(cleanUrl) !== \"\" ||\n cleanUrl.startsWith(\"/api\") ||\n cleanUrl.startsWith(\"/webhooks\") ||\n cleanUrl.startsWith(\"/auth\") ||\n cleanUrl.startsWith(\"/@\") ||\n cleanUrl.startsWith(\"/__helium__\")\n ) {\n return next();\n }\n\n // For all other routes (including nested paths like /docs/guides/auth),\n // rewrite to index.html so Vite serves it and the client-side router handles routing\n req.url = \"/index.html\";\n next();\n });\n\n /**\n * Write type definitions only if content has changed.\n * This prevents unnecessary TypeScript recompilation.\n */\n const writeTypesIfChanged = (dts: string): boolean => {\n const typesDir = path.join(root, \"src\", \"types\");\n const dtsPath = path.join(typesDir, \"heliumts-server.d.ts\");\n\n if (!fs.existsSync(typesDir)) {\n fs.mkdirSync(typesDir, { recursive: true });\n }\n\n // Check if file exists and content is the same\n if (fs.existsSync(dtsPath)) {\n const existing = fs.readFileSync(dtsPath, \"utf-8\");\n if (existing === dts) {\n return false; // No change needed\n }\n }\n\n fs.writeFileSync(dtsPath, dts);\n return true; // File was written\n };\n\n const regenerateTypes = (): boolean => {\n try {\n const { methods } = scanServerExports(root);\n const dts = generateTypeDefinitions(methods, root);\n return writeTypesIfChanged(dts);\n } catch (e) {\n log(\"error\", \"Failed to regenerate types\", e);\n return false;\n }\n };\n\n // Debounce timer for file changes\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n const DEBOUNCE_DELAY = 100; // ms\n\n const handleServerFileChange = async () => {\n // Regenerate type definitions\n regenerateTypes();\n\n // Invalidate the virtual modules so they get regenerated\n const clientModule = server.environments.client?.moduleGraph.getModuleById(RESOLVED_VIRTUAL_CLIENT_MODULE_ID);\n const serverModule = server.environments.ssr?.moduleGraph.getModuleById(RESOLVED_VIRTUAL_SERVER_MANIFEST_ID);\n\n if (clientModule) {\n server.environments.client?.moduleGraph.invalidateModule(clientModule);\n }\n if (serverModule) {\n server.environments.ssr?.moduleGraph.invalidateModule(serverModule);\n }\n\n // Reload the server manifest and re-register methods\n try {\n // Clear config cache to ensure fresh config is loaded\n clearConfigCache();\n const config = await loadConfig(root);\n const mod = await server.ssrLoadModule(VIRTUAL_SERVER_MANIFEST_ID);\n const registerAll = mod.registerAll;\n const httpHandlers = mod.httpHandlers || [];\n const middlewareHandler = mod.middlewareHandler || null;\n const workers = mod.workers || [];\n\n // Update the dev server registry with new methods and HTTP handlers\n if (server.httpServer) {\n attachToDevServer(\n server.httpServer,\n (registry, httpRouter) => {\n registerAll(registry);\n httpRouter.registerRoutes(httpHandlers);\n if (middlewareHandler) {\n registry.setMiddleware(middlewareHandler);\n httpRouter.setMiddleware(middlewareHandler);\n }\n },\n config,\n workers\n );\n }\n } catch (e) {\n log(\"error\", \"Failed to reload Helium server manifest\", e);\n }\n\n // Trigger HMR for any client code that imports heliumts/server\n server.ws.send({\n type: \"full-reload\",\n path: \"*\",\n });\n };\n\n // Watch server directory for changes\n const serverPath = path.join(root, serverDir);\n server.watcher.add(serverPath);\n\n // Watch config files for changes\n const configFiles = [\"helium.config.ts\", \"helium.config.js\", \"helium.config.mjs\"];\n for (const configFile of configFiles) {\n const configPath = path.join(root, configFile);\n if (fs.existsSync(configPath)) {\n server.watcher.add(configPath);\n }\n }\n\n /**\n * Debounced handler for server file changes.\n * This prevents multiple rapid regenerations during file saves.\n */\n const debouncedHandleServerFileChange = () => {\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n handleServerFileChange();\n }, DEBOUNCE_DELAY);\n };\n\n server.watcher.on(\"change\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file changed, regenerate everything\n if (normalized.startsWith(`${serverDir}/`)) {\n debouncedHandleServerFileChange();\n }\n\n // If config file changed, reload config and regenerate\n if (configFiles.some((cf) => normalized === cf)) {\n log(\"info\", `Config file changed: ${normalized}`);\n debouncedHandleServerFileChange();\n }\n });\n\n server.watcher.on(\"add\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file was added, regenerate everything\n if (normalized.startsWith(`${serverDir}/`)) {\n debouncedHandleServerFileChange();\n }\n });\n\n server.watcher.on(\"unlink\", (file) => {\n const relative = path.relative(root, file);\n const normalized = normalizeToPosix(relative);\n\n // If a server file was removed, regenerate everything\n if (normalized.startsWith(`${serverDir}/`)) {\n debouncedHandleServerFileChange();\n }\n });\n\n // We hook into the server start to attach our RPC server\n server.httpServer?.on(\"listening\", async () => {\n try {\n // Load config\n const config = await loadConfig(root);\n\n // Load the manifest using Vite's SSR loader\n // This allows us to load TS files directly and handle dependencies\n const mod = await server.ssrLoadModule(VIRTUAL_SERVER_MANIFEST_ID);\n const registerAll = mod.registerAll;\n const httpHandlers = mod.httpHandlers || [];\n const middlewareHandler = mod.middlewareHandler || null;\n const workers = mod.workers || [];\n\n if (server.httpServer) {\n attachToDevServer(\n server.httpServer,\n (registry, httpRouter) => {\n registerAll(registry);\n httpRouter.registerRoutes(httpHandlers);\n if (middlewareHandler) {\n registry.setMiddleware(middlewareHandler);\n httpRouter.setMiddleware(middlewareHandler);\n }\n },\n config,\n workers\n );\n }\n } catch (e) {\n log(\"error\", \"Failed to attach Helium RPC server\", e);\n }\n });\n },\n };\n}\n\n/**\n * Convert file path to POSIX format\n * @internal Exported for testing\n */\nexport function normalizeToPosix(filePath: string): string {\n return filePath.split(path.sep).join(\"/\");\n}\n\n/**\n * Check if an importer is a server module\n * @internal Exported for testing\n */\nexport function isServerModule(importer: string | undefined, root: string, serverDir: string): boolean {\n if (!importer || importer.startsWith(\"\\0\")) {\n return false;\n }\n\n const [importerPath] = importer.split(\"?\");\n if (!importerPath) {\n return false;\n }\n\n const relative = path.relative(root, importerPath);\n if (!relative || relative.startsWith(\"..\")) {\n return false;\n }\n\n const normalized = normalizeToPosix(relative);\n return normalized === serverDir || normalized.startsWith(`${serverDir}/`);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/vite/scanner.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,OAAO,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAG9D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CA4E7D;AA4BD,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,cAAc,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAsDlG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAyB1D"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/vite/scanner.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,OAAO,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAG9D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CA8F7D;AA4BD,MAAM,WAAW,cAAc;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,cAAc,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAsDlG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAyB1D"}
@@ -16,15 +16,36 @@ export function scanServerExports(root) {
16
16
  const workers = [];
17
17
  let middleware;
18
18
  function walk(dir) {
19
- const files = fs.readdirSync(dir);
19
+ let files;
20
+ try {
21
+ files = fs.readdirSync(dir);
22
+ }
23
+ catch {
24
+ // Directory might have been deleted during scan
25
+ return;
26
+ }
20
27
  for (const file of files) {
21
28
  const fullPath = path.join(dir, file);
22
- const stat = fs.statSync(fullPath);
29
+ let stat;
30
+ try {
31
+ stat = fs.statSync(fullPath);
32
+ }
33
+ catch {
34
+ // File might have been deleted during scan
35
+ continue;
36
+ }
23
37
  if (stat.isDirectory()) {
24
38
  walk(fullPath);
25
39
  }
26
40
  else if (file.endsWith(".ts")) {
27
- const content = fs.readFileSync(fullPath, "utf-8");
41
+ let content;
42
+ try {
43
+ content = fs.readFileSync(fullPath, "utf-8");
44
+ }
45
+ catch {
46
+ // File might be being written to or deleted
47
+ continue;
48
+ }
28
49
  // Check for _middleware.ts file
29
50
  if (file === "_middleware.ts") {
30
51
  // Support both 'middleware' and 'defineMiddleware' (backwards compatibility)
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/vite/scanner.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\n\nimport { log } from \"../utils/logger.js\";\nimport { SERVER_DIR } from \"./paths.js\";\n\nexport interface MethodExport {\n name: string;\n filePath: string;\n}\n\nexport interface HTTPHandlerExport {\n name: string;\n filePath: string;\n}\n\nexport interface MiddlewareExport {\n name: string;\n filePath: string;\n}\n\nexport interface WorkerExport {\n name: string;\n filePath: string;\n}\n\nexport interface ServerExports {\n methods: MethodExport[];\n httpHandlers: HTTPHandlerExport[];\n middleware?: MiddlewareExport;\n workers: WorkerExport[];\n}\n\nexport function scanServerMethods(root: string): MethodExport[] {\n const exports = scanServerExports(root);\n return exports.methods;\n}\n\nexport function scanServerExports(root: string): ServerExports {\n const serverDir = path.resolve(root, SERVER_DIR);\n if (!fs.existsSync(serverDir)) {\n return { methods: [], httpHandlers: [], workers: [] };\n }\n\n const methods: MethodExport[] = [];\n const httpHandlers: HTTPHandlerExport[] = [];\n const workers: WorkerExport[] = [];\n let middleware: MiddlewareExport | undefined;\n\n function walk(dir: string) {\n const files = fs.readdirSync(dir);\n for (const file of files) {\n const fullPath = path.join(dir, file);\n const stat = fs.statSync(fullPath);\n\n if (stat.isDirectory()) {\n walk(fullPath);\n } else if (file.endsWith(\".ts\")) {\n const content = fs.readFileSync(fullPath, \"utf-8\");\n\n // Check for _middleware.ts file\n if (file === \"_middleware.ts\") {\n // Support both 'middleware' and 'defineMiddleware' (backwards compatibility)\n const middlewareRegex = /export\\s+(const|default)\\s+(\\w+)\\s*=\\s*(middleware|defineMiddleware)/;\n const match = middlewareRegex.exec(content);\n if (match) {\n middleware = {\n name: match[2],\n filePath: fullPath,\n };\n }\n // Also support default export\n const defaultRegex = /export\\s+default\\s+(middleware|defineMiddleware)/;\n if (defaultRegex.test(content)) {\n middleware = {\n name: \"default\",\n filePath: fullPath,\n };\n }\n }\n\n // Find: export const methodName = defineMethod(...)\n const methodRegex = /export\\s+const\\s+(\\w+)\\s*=\\s*defineMethod/g;\n let match;\n while ((match = methodRegex.exec(content)) !== null) {\n methods.push({\n name: match[1],\n filePath: fullPath,\n });\n }\n\n // Find: export const handlerName = defineHTTPRequest(...)\n const httpRegex = /export\\s+const\\s+(\\w+)\\s*=\\s*defineHTTPRequest/g;\n while ((match = httpRegex.exec(content)) !== null) {\n httpHandlers.push({\n name: match[1],\n filePath: fullPath,\n });\n }\n\n // Find: export const workerName = defineWorker(...)\n const workerRegex = /export\\s+const\\s+(\\w+)\\s*=\\s*defineWorker/g;\n while ((match = workerRegex.exec(content)) !== null) {\n workers.push({\n name: match[1],\n filePath: fullPath,\n });\n }\n }\n }\n }\n\n walk(serverDir);\n return { methods, httpHandlers, middleware, workers };\n}\n\n/**\n * Convert a file path to a route pattern (same logic as client-side router)\n */\nfunction pathFromFile(file: string, root: string): string {\n // Remove root/src/pages prefix and file extension\n const pagesDir = path.join(root, \"src\", \"pages\");\n const withoutPrefix = file.replace(pagesDir, \"\").replace(/\\.(tsx|jsx|ts|js)$/, \"\");\n\n // Handle special files\n if (withoutPrefix === \"/404\") {\n return \"__404__\";\n }\n\n // Remove route groups (folders in parentheses)\n let pattern = withoutPrefix.replace(/\\/\\([^)]+\\)/g, \"\");\n\n // Convert /index to /\n pattern = pattern.replace(/\\/index$/, \"\") || \"/\";\n // Convert [...param] to *param (catch-all)\n pattern = pattern.replace(/\\[\\.\\.\\.(.+?)\\]/g, \"*$1\");\n // Convert [param] to :param (single dynamic segment)\n pattern = pattern.replace(/\\[(.+?)\\]/g, \":$1\");\n\n return pattern;\n}\n\nexport interface RouteCollision {\n pattern: string;\n files: string[];\n}\n\n/**\n * Scan pages directory and detect route collisions\n */\nexport function scanPageRoutes(root: string): { collisions: RouteCollision[]; totalRoutes: number } {\n const pagesDir = path.join(root, \"src\", \"pages\");\n\n if (!fs.existsSync(pagesDir)) {\n return { collisions: [], totalRoutes: 0 };\n }\n\n const routePatternMap = new Map<string, string>();\n const collisions: RouteCollision[] = [];\n\n function walkPages(dir: string) {\n const items = fs.readdirSync(dir);\n\n for (const item of items) {\n const fullPath = path.join(dir, item);\n const stat = fs.statSync(fullPath);\n\n if (stat.isDirectory()) {\n walkPages(fullPath);\n } else if (/\\.(tsx|jsx|ts|js)$/.test(item)) {\n // Skip layout files\n if (item.includes(\"_layout.\")) {\n continue;\n }\n\n const pathPattern = pathFromFile(fullPath, root);\n\n // Skip special pages\n if (pathPattern === \"__404__\") {\n continue;\n }\n\n // Check for collision\n const existingFile = routePatternMap.get(pathPattern);\n if (existingFile) {\n // Check if this collision was already recorded\n const existingCollision = collisions.find((c) => c.pattern === pathPattern);\n if (existingCollision) {\n existingCollision.files.push(fullPath);\n } else {\n collisions.push({\n pattern: pathPattern,\n files: [existingFile, fullPath],\n });\n }\n } else {\n routePatternMap.set(pathPattern, fullPath);\n }\n }\n }\n }\n\n walkPages(pagesDir);\n return { collisions, totalRoutes: routePatternMap.size };\n}\n\n/**\n * Check for route collisions and log warnings\n */\nexport function checkRouteCollisions(root: string): boolean {\n const { collisions, totalRoutes } = scanPageRoutes(root);\n\n if (collisions.length === 0) {\n return false;\n }\n\n log(\"warn\", \"⚠️ Route collisions detected! Multiple files resolve to the same URL path:\");\n log(\"warn\", \"\");\n\n for (const collision of collisions) {\n log(\"error\", ` Route pattern: \"${collision.pattern}\"`);\n for (const file of collision.files) {\n const relative = path.relative(root, file);\n log(\"error\", ` - ${relative}`);\n }\n log(\"error\", ` ⚠️ Only the first file will be accessible.`);\n log(\"warn\", \"\");\n }\n\n log(\"warn\", `Found ${collisions.length} collision(s) across ${totalRoutes} unique routes.`);\n log(\"warn\", \"Consider using different file names or organizing files in subdirectories.\");\n log(\"warn\", \"\");\n\n return true;\n}\n"]}
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/vite/scanner.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\n\nimport { log } from \"../utils/logger.js\";\nimport { SERVER_DIR } from \"./paths.js\";\n\nexport interface MethodExport {\n name: string;\n filePath: string;\n}\n\nexport interface HTTPHandlerExport {\n name: string;\n filePath: string;\n}\n\nexport interface MiddlewareExport {\n name: string;\n filePath: string;\n}\n\nexport interface WorkerExport {\n name: string;\n filePath: string;\n}\n\nexport interface ServerExports {\n methods: MethodExport[];\n httpHandlers: HTTPHandlerExport[];\n middleware?: MiddlewareExport;\n workers: WorkerExport[];\n}\n\nexport function scanServerMethods(root: string): MethodExport[] {\n const exports = scanServerExports(root);\n return exports.methods;\n}\n\nexport function scanServerExports(root: string): ServerExports {\n const serverDir = path.resolve(root, SERVER_DIR);\n if (!fs.existsSync(serverDir)) {\n return { methods: [], httpHandlers: [], workers: [] };\n }\n\n const methods: MethodExport[] = [];\n const httpHandlers: HTTPHandlerExport[] = [];\n const workers: WorkerExport[] = [];\n let middleware: MiddlewareExport | undefined;\n\n function walk(dir: string) {\n let files: string[];\n try {\n files = fs.readdirSync(dir);\n } catch {\n // Directory might have been deleted during scan\n return;\n }\n for (const file of files) {\n const fullPath = path.join(dir, file);\n let stat: fs.Stats;\n try {\n stat = fs.statSync(fullPath);\n } catch {\n // File might have been deleted during scan\n continue;\n }\n\n if (stat.isDirectory()) {\n walk(fullPath);\n } else if (file.endsWith(\".ts\")) {\n let content: string;\n try {\n content = fs.readFileSync(fullPath, \"utf-8\");\n } catch {\n // File might be being written to or deleted\n continue;\n }\n\n // Check for _middleware.ts file\n if (file === \"_middleware.ts\") {\n // Support both 'middleware' and 'defineMiddleware' (backwards compatibility)\n const middlewareRegex = /export\\s+(const|default)\\s+(\\w+)\\s*=\\s*(middleware|defineMiddleware)/;\n const match = middlewareRegex.exec(content);\n if (match) {\n middleware = {\n name: match[2],\n filePath: fullPath,\n };\n }\n // Also support default export\n const defaultRegex = /export\\s+default\\s+(middleware|defineMiddleware)/;\n if (defaultRegex.test(content)) {\n middleware = {\n name: \"default\",\n filePath: fullPath,\n };\n }\n }\n\n // Find: export const methodName = defineMethod(...)\n const methodRegex = /export\\s+const\\s+(\\w+)\\s*=\\s*defineMethod/g;\n let match;\n while ((match = methodRegex.exec(content)) !== null) {\n methods.push({\n name: match[1],\n filePath: fullPath,\n });\n }\n\n // Find: export const handlerName = defineHTTPRequest(...)\n const httpRegex = /export\\s+const\\s+(\\w+)\\s*=\\s*defineHTTPRequest/g;\n while ((match = httpRegex.exec(content)) !== null) {\n httpHandlers.push({\n name: match[1],\n filePath: fullPath,\n });\n }\n\n // Find: export const workerName = defineWorker(...)\n const workerRegex = /export\\s+const\\s+(\\w+)\\s*=\\s*defineWorker/g;\n while ((match = workerRegex.exec(content)) !== null) {\n workers.push({\n name: match[1],\n filePath: fullPath,\n });\n }\n }\n }\n }\n\n walk(serverDir);\n return { methods, httpHandlers, middleware, workers };\n}\n\n/**\n * Convert a file path to a route pattern (same logic as client-side router)\n */\nfunction pathFromFile(file: string, root: string): string {\n // Remove root/src/pages prefix and file extension\n const pagesDir = path.join(root, \"src\", \"pages\");\n const withoutPrefix = file.replace(pagesDir, \"\").replace(/\\.(tsx|jsx|ts|js)$/, \"\");\n\n // Handle special files\n if (withoutPrefix === \"/404\") {\n return \"__404__\";\n }\n\n // Remove route groups (folders in parentheses)\n let pattern = withoutPrefix.replace(/\\/\\([^)]+\\)/g, \"\");\n\n // Convert /index to /\n pattern = pattern.replace(/\\/index$/, \"\") || \"/\";\n // Convert [...param] to *param (catch-all)\n pattern = pattern.replace(/\\[\\.\\.\\.(.+?)\\]/g, \"*$1\");\n // Convert [param] to :param (single dynamic segment)\n pattern = pattern.replace(/\\[(.+?)\\]/g, \":$1\");\n\n return pattern;\n}\n\nexport interface RouteCollision {\n pattern: string;\n files: string[];\n}\n\n/**\n * Scan pages directory and detect route collisions\n */\nexport function scanPageRoutes(root: string): { collisions: RouteCollision[]; totalRoutes: number } {\n const pagesDir = path.join(root, \"src\", \"pages\");\n\n if (!fs.existsSync(pagesDir)) {\n return { collisions: [], totalRoutes: 0 };\n }\n\n const routePatternMap = new Map<string, string>();\n const collisions: RouteCollision[] = [];\n\n function walkPages(dir: string) {\n const items = fs.readdirSync(dir);\n\n for (const item of items) {\n const fullPath = path.join(dir, item);\n const stat = fs.statSync(fullPath);\n\n if (stat.isDirectory()) {\n walkPages(fullPath);\n } else if (/\\.(tsx|jsx|ts|js)$/.test(item)) {\n // Skip layout files\n if (item.includes(\"_layout.\")) {\n continue;\n }\n\n const pathPattern = pathFromFile(fullPath, root);\n\n // Skip special pages\n if (pathPattern === \"__404__\") {\n continue;\n }\n\n // Check for collision\n const existingFile = routePatternMap.get(pathPattern);\n if (existingFile) {\n // Check if this collision was already recorded\n const existingCollision = collisions.find((c) => c.pattern === pathPattern);\n if (existingCollision) {\n existingCollision.files.push(fullPath);\n } else {\n collisions.push({\n pattern: pathPattern,\n files: [existingFile, fullPath],\n });\n }\n } else {\n routePatternMap.set(pathPattern, fullPath);\n }\n }\n }\n }\n\n walkPages(pagesDir);\n return { collisions, totalRoutes: routePatternMap.size };\n}\n\n/**\n * Check for route collisions and log warnings\n */\nexport function checkRouteCollisions(root: string): boolean {\n const { collisions, totalRoutes } = scanPageRoutes(root);\n\n if (collisions.length === 0) {\n return false;\n }\n\n log(\"warn\", \"⚠️ Route collisions detected! Multiple files resolve to the same URL path:\");\n log(\"warn\", \"\");\n\n for (const collision of collisions) {\n log(\"error\", ` Route pattern: \"${collision.pattern}\"`);\n for (const file of collision.files) {\n const relative = path.relative(root, file);\n log(\"error\", ` - ${relative}`);\n }\n log(\"error\", ` ⚠️ Only the first file will be accessible.`);\n log(\"warn\", \"\");\n }\n\n log(\"warn\", `Found ${collisions.length} collision(s) across ${totalRoutes} unique routes.`);\n log(\"warn\", \"Consider using different file names or organizing files in subdirectories.\");\n log(\"warn\", \"\");\n\n return true;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"virtualServerModule.d.ts","sourceRoot":"","sources":["../../src/vite/virtualServerModule.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE/F,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,YAAY,EAAE,iBAAiB,EAAE,EAAE,UAAU,CAAC,EAAE,gBAAgB,EAAE,OAAO,GAAE,YAAY,EAAO,GAAG,MAAM,CAgCtK;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAIpE;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAqDrF;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAkB5C"}
1
+ {"version":3,"file":"virtualServerModule.d.ts","sourceRoot":"","sources":["../../src/vite/virtualServerModule.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE/F,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,YAAY,EAAE,iBAAiB,EAAE,EAAE,UAAU,CAAC,EAAE,gBAAgB,EAAE,OAAO,GAAE,YAAY,EAAO,GAAG,MAAM,CAgCtK;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAIpE;AAgBD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAyDrF;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAkB5C"}
@@ -32,11 +32,28 @@ export function generateClientModule(methods) {
32
32
  const exports = methods.map((m) => `export const ${m.name} = { __id: '${m.name}' };`).join("\n");
33
33
  return exports;
34
34
  }
35
+ /**
36
+ * Generate a deterministic hash from a string.
37
+ * This ensures stable type definitions across regenerations.
38
+ */
39
+ function simpleHash(str) {
40
+ let hash = 0;
41
+ for (let i = 0; i < str.length; i++) {
42
+ const char = str.charCodeAt(i);
43
+ hash = (hash << 5) - hash + char;
44
+ hash = hash & hash; // Convert to 32bit integer
45
+ }
46
+ return Math.abs(hash).toString(36).substring(0, 6);
47
+ }
35
48
  export function generateTypeDefinitions(methods, root) {
36
- const methodsWithSuffix = methods.map((m, i) => ({
37
- ...m,
38
- alias: `${m.name}_${i}${Math.random().toString(36).substring(2, 8)}`,
39
- }));
49
+ const methodsWithSuffix = methods.map((m, i) => {
50
+ // Use deterministic hash based on file path and method name
51
+ const hashInput = `${m.filePath}:${m.name}:${i}`;
52
+ return {
53
+ ...m,
54
+ alias: `${m.name}_${simpleHash(hashInput)}`,
55
+ };
56
+ });
40
57
  const imports = methodsWithSuffix
41
58
  .map((m) => {
42
59
  let relPath = path.relative(path.join(root, "src"), m.filePath);
@@ -1 +1 @@
1
- {"version":3,"file":"virtualServerModule.js","sourceRoot":"","sources":["../../src/vite/virtualServerModule.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"path\";\n\nimport { HTTPHandlerExport, MethodExport, MiddlewareExport, WorkerExport } from \"./scanner.js\";\n\nexport function generateServerManifest(methods: MethodExport[], httpHandlers: HTTPHandlerExport[], middleware?: MiddlewareExport, workers: WorkerExport[] = []): string {\n const methodImports = methods.map((m, i) => `import { ${m.name} as method_${i} } from '${m.filePath}';`).join(\"\\n\");\n const httpImports = httpHandlers.map((h, i) => `import { ${h.name} as http_${i} } from '${h.filePath}';`).join(\"\\n\");\n const workerImports = workers.map((w, i) => `import { ${w.name} as worker_${i} } from '${w.filePath}';`).join(\"\\n\");\n const middlewareImport = middleware ? `import ${middleware.name === \"default\" ? \"middleware\" : `{ ${middleware.name} as middleware }`} from '${middleware.filePath}';` : \"\";\n\n const methodRegistrations = methods.map((m, i) => ` registry.register('${m.name}', method_${i});`).join(\"\\n\");\n\n const httpExports = httpHandlers.map((h, i) => ` { name: '${h.name}', handler: http_${i} },`).join(\"\\n\");\n\n const workerExports = workers.map((w, i) => ` { name: '${w.name}', worker: worker_${i} },`).join(\"\\n\");\n\n return `\n${methodImports}\n${httpImports}\n${workerImports}\n${middlewareImport}\n\nexport function registerAll(registry) {\n${methodRegistrations}\n}\n\nexport const httpHandlers = [\n${httpExports}\n];\n\nexport const workers = [\n${workerExports}\n];\n\nexport const middlewareHandler = ${middleware ? \"middleware\" : \"null\"};\n`;\n}\n\nexport function generateClientModule(methods: MethodExport[]): string {\n const exports = methods.map((m) => `export const ${m.name} = { __id: '${m.name}' };`).join(\"\\n\");\n\n return exports;\n}\n\nexport function generateTypeDefinitions(methods: MethodExport[], root: string): string {\n const methodsWithSuffix = methods.map((m, i) => ({\n ...m,\n alias: `${m.name}_${i}${Math.random().toString(36).substring(2, 8)}`,\n }));\n\n const imports = methodsWithSuffix\n .map((m) => {\n let relPath = path.relative(path.join(root, \"src\"), m.filePath);\n if (!relPath.startsWith(\".\")) {\n relPath = \"../\" + relPath;\n }\n relPath = relPath.replace(/\\.ts$/, \"\");\n return `import type { ${m.name} as ${m.alias} } from '${relPath}';`;\n })\n .join(\"\\n\");\n\n const methodExports = methodsWithSuffix\n .map((m) => {\n return ` export const ${m.name}: import('heliumts/client').MethodStub<\n Parameters<typeof ${m.alias}['handler']>[0],\n Awaited<ReturnType<typeof ${m.alias}['handler']>>\n >;`;\n })\n .join(\"\\n\");\n\n // If there are no methods, we don't need to generate any augmentation\n // This prevents shadowing the actual heliumts/server exports\n if (methods.length === 0) {\n return `/* eslint-disable */\n/**\n* Auto generated file - DO NOT EDIT!\n* # Helium Server Type Definitions\n* \n* This file is empty because no methods have been defined yet.\n* Once you create a method using defineMethod(), type stubs will be generated here.\n**/\nexport {};\n`;\n }\n\n return `/* eslint-disable */\n/**\n* Auto generated file - DO NOT EDIT!\n* # Helium Server Type Definitions \n**/\n${imports}\n\ndeclare module 'heliumts/server' {\n // Method stubs for client-side type inference\n${methodExports}\n}\n`;\n}\n\nexport function generateEntryModule(): string {\n return `\nimport React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { AppRouter } from 'heliumts/client';\nimport App from '/src/App';\n\nconst rootEl = document.getElementById('root');\nif (!rootEl) {\n throw new Error('Root element not found. Helium requires a <div id=\\\"root\\\"></div> in your HTML.');\n}\n\ncreateRoot(rootEl).render(\n <React.StrictMode>\n <AppRouter AppShell={App} />\n </React.StrictMode>\n);\n`;\n}\n"]}
1
+ {"version":3,"file":"virtualServerModule.js","sourceRoot":"","sources":["../../src/vite/virtualServerModule.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"path\";\n\nimport { HTTPHandlerExport, MethodExport, MiddlewareExport, WorkerExport } from \"./scanner.js\";\n\nexport function generateServerManifest(methods: MethodExport[], httpHandlers: HTTPHandlerExport[], middleware?: MiddlewareExport, workers: WorkerExport[] = []): string {\n const methodImports = methods.map((m, i) => `import { ${m.name} as method_${i} } from '${m.filePath}';`).join(\"\\n\");\n const httpImports = httpHandlers.map((h, i) => `import { ${h.name} as http_${i} } from '${h.filePath}';`).join(\"\\n\");\n const workerImports = workers.map((w, i) => `import { ${w.name} as worker_${i} } from '${w.filePath}';`).join(\"\\n\");\n const middlewareImport = middleware ? `import ${middleware.name === \"default\" ? \"middleware\" : `{ ${middleware.name} as middleware }`} from '${middleware.filePath}';` : \"\";\n\n const methodRegistrations = methods.map((m, i) => ` registry.register('${m.name}', method_${i});`).join(\"\\n\");\n\n const httpExports = httpHandlers.map((h, i) => ` { name: '${h.name}', handler: http_${i} },`).join(\"\\n\");\n\n const workerExports = workers.map((w, i) => ` { name: '${w.name}', worker: worker_${i} },`).join(\"\\n\");\n\n return `\n${methodImports}\n${httpImports}\n${workerImports}\n${middlewareImport}\n\nexport function registerAll(registry) {\n${methodRegistrations}\n}\n\nexport const httpHandlers = [\n${httpExports}\n];\n\nexport const workers = [\n${workerExports}\n];\n\nexport const middlewareHandler = ${middleware ? \"middleware\" : \"null\"};\n`;\n}\n\nexport function generateClientModule(methods: MethodExport[]): string {\n const exports = methods.map((m) => `export const ${m.name} = { __id: '${m.name}' };`).join(\"\\n\");\n\n return exports;\n}\n\n/**\n * Generate a deterministic hash from a string.\n * This ensures stable type definitions across regenerations.\n */\nfunction simpleHash(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash; // Convert to 32bit integer\n }\n return Math.abs(hash).toString(36).substring(0, 6);\n}\n\nexport function generateTypeDefinitions(methods: MethodExport[], root: string): string {\n const methodsWithSuffix = methods.map((m, i) => {\n // Use deterministic hash based on file path and method name\n const hashInput = `${m.filePath}:${m.name}:${i}`;\n return {\n ...m,\n alias: `${m.name}_${simpleHash(hashInput)}`,\n };\n });\n\n const imports = methodsWithSuffix\n .map((m) => {\n let relPath = path.relative(path.join(root, \"src\"), m.filePath);\n if (!relPath.startsWith(\".\")) {\n relPath = \"../\" + relPath;\n }\n relPath = relPath.replace(/\\.ts$/, \"\");\n return `import type { ${m.name} as ${m.alias} } from '${relPath}';`;\n })\n .join(\"\\n\");\n\n const methodExports = methodsWithSuffix\n .map((m) => {\n return ` export const ${m.name}: import('heliumts/client').MethodStub<\n Parameters<typeof ${m.alias}['handler']>[0],\n Awaited<ReturnType<typeof ${m.alias}['handler']>>\n >;`;\n })\n .join(\"\\n\");\n\n // If there are no methods, we don't need to generate any augmentation\n // This prevents shadowing the actual heliumts/server exports\n if (methods.length === 0) {\n return `/* eslint-disable */\n/**\n* Auto generated file - DO NOT EDIT!\n* # Helium Server Type Definitions\n* \n* This file is empty because no methods have been defined yet.\n* Once you create a method using defineMethod(), type stubs will be generated here.\n**/\nexport {};\n`;\n }\n\n return `/* eslint-disable */\n/**\n* Auto generated file - DO NOT EDIT!\n* # Helium Server Type Definitions \n**/\n${imports}\n\ndeclare module 'heliumts/server' {\n // Method stubs for client-side type inference\n${methodExports}\n}\n`;\n}\n\nexport function generateEntryModule(): string {\n return `\nimport React from 'react';\nimport { createRoot } from 'react-dom/client';\nimport { AppRouter } from 'heliumts/client';\nimport App from '/src/App';\n\nconst rootEl = document.getElementById('root');\nif (!rootEl) {\n throw new Error('Root element not found. Helium requires a <div id=\\\"root\\\"></div> in your HTML.');\n}\n\ncreateRoot(rootEl).render(\n <React.StrictMode>\n <AppRouter AppShell={App} />\n </React.StrictMode>\n);\n`;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "heliumts",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "A lightweight full-stack React framework with file-based routing, RPC, and SSG support",
5
5
  "keywords": [
6
6
  "react",