@taserjs/plugin 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -14,6 +14,8 @@ export interface HostServerInfo {
14
14
  path: string;
15
15
  }
16
16
  export declare function detectHostServer(serverDir: string, cwd?: string, explicitEntry?: string): HostServerInfo | null;
17
+ export declare function isFullStackPluginName(name: string): boolean;
18
+ export declare function detectFullStack(viteConfig: any, excludeNitro?: boolean): boolean;
17
19
  export declare function normalizeImportPath(pathStr: string): string;
18
20
  export declare function isSubPath(child: string, parent: string): boolean;
19
21
  export declare function isOutputDir(filePath: string, outputDir: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;qBAgBa;qBACA;iBAEI;EACf;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;;wBAYc,iBACd,mBACA,cACA,yBACC;wBAwFa,oBAAoB;wBAQpB,UAAU,eAAe;wBAKzB,YAAY,kBAAkB;wBA0B9B,cACd,QAAQ,qBACR,aACA,UAAU,qBACT;wBAKa,wBACd,kBACA,2BACG,UAAU,YAAY,QAAQ,YAAY;wBAY/B,kBAAkB,UAAU,kBAAkB;wBAa9C,sBACd,wBACA,wBACA;EACG;EAAiB;;wBAgBN,cACd,uBACA,6BACA,aAAa,uBACb;qBA0CW,gCAAW,iBAAA;qBAkQX,SAAK,UACL,0CAAkB,qCAAA,wCAAA,iBAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;qBAgBa;qBACA;iBAEI;EACf;EACA;EACA;EACA;EACA;;iBAGe;EACf;EACA;;wBAYc,iBACd,mBACA,cACA,yBACC;wBA4Ca,sBAAsB;wBAatB,gBAAgB,iBAAiB;wBAoCjC,oBAAoB;wBAQpB,UAAU,eAAe;wBAKzB,YAAY,kBAAkB;wBA0B9B,cACd,QAAQ,qBACR,aACA,UAAU,qBACT;wBAKa,wBACd,kBACA,2BACG,UAAU,YAAY,QAAQ,YAAY;wBAY/B,kBAAkB,UAAU,kBAAkB;wBAa9C,sBACd,wBACA,wBACA;EACG;EAAiB;;wBAgBN,cACd,uBACA,6BACA,aAAa,uBACb;qBAwCW,gCAAW,iBAAA;qBAkQX,SAAK,UACL,0CAAkB,qCAAA,wCAAA,iBAAA"}
package/dist/index.js CHANGED
@@ -49,7 +49,10 @@ const FULLSTACK_PLUGIN_PATTERNS = [
49
49
  "react-router",
50
50
  "remix",
51
51
  "astro",
52
- "sveltekit"
52
+ "sveltekit",
53
+ "nuxt",
54
+ "solid-start",
55
+ "analog"
53
56
  ];
54
57
  function isFullStackPluginName(name) {
55
58
  const lower = name.toLowerCase();
@@ -57,14 +60,16 @@ function isFullStackPluginName(name) {
57
60
  if (lower.includes("tanstack") && lower.includes("start")) return true;
58
61
  return false;
59
62
  }
60
- function detectFullStack(viteConfig) {
63
+ function detectFullStack(viteConfig, excludeNitro = false) {
61
64
  if (!viteConfig) return false;
62
- if (viteConfig.nitro) return true;
65
+ if (!excludeNitro && viteConfig.nitro) return true;
63
66
  const plugins = viteConfig.plugins;
64
67
  if (!plugins) return false;
65
68
  return (Array.isArray(plugins) ? plugins.flat(Infinity) : [plugins]).some((p) => {
66
69
  const name = p?.name;
67
- return typeof name === "string" && isFullStackPluginName(name);
70
+ if (typeof name !== "string") return false;
71
+ if (excludeNitro && name.toLowerCase().includes("nitro")) return false;
72
+ return isFullStackPluginName(name);
68
73
  });
69
74
  }
70
75
  function isRunnableEnvironment(environment) {
@@ -124,7 +129,7 @@ function mountHostFallback(app, hostMod, type) {
124
129
  function buildHostFallbackCode(hostImportPath, type, appVarName = "app") {
125
130
  const isNode = type === "node";
126
131
  return {
127
- imports: `${isNode ? "import { toFetchHandler } from \"srvx/node\";\n" : ""}import hostServerEntry from "${hostImportPath}";`,
132
+ imports: `${isNode ? "import { toFetchHandler } from \"@taserjs/runtime/serve/node\";\n" : ""}import hostServerEntry from "${hostImportPath}";`,
128
133
  setup: isNode ? `const rawHost = hostServerEntry?.default ?? hostServerEntry;
129
134
  const nodeHandler = typeof rawHost === "function" ? rawHost : (rawHost?.routing ?? rawHost);
130
135
  const hostFetch = typeof nodeHandler === "function" ? toFetchHandler(nodeHandler) : null;
@@ -143,9 +148,8 @@ function emitServeShim(serveShimPath, routesGenImportPath, hostServer, ext = ".j
143
148
  else if (hostImportPath.endsWith(".js") && ext === "") hostImportPath = hostImportPath.slice(0, -3);
144
149
  const fallbackCode = buildHostFallbackCode(hostImportPath, hostServer.type, "app");
145
150
  code = `// @ts-nocheck
146
- import { FastResponse } from "srvx";
151
+ import { FastResponse, serve } from "@taserjs/runtime/serve";
147
152
  globalThis.Response = FastResponse;
148
- import { serve } from "srvx/node";
149
153
  ${fallbackCode.imports}
150
154
  import { app } from "${normalizedRoutesPath}";
151
155
 
@@ -155,9 +159,8 @@ export { app };
155
159
  serve(app);
156
160
  `;
157
161
  } else code = `// @ts-nocheck
158
- import { FastResponse } from "srvx";
162
+ import { FastResponse, serve } from "@taserjs/runtime/serve";
159
163
  globalThis.Response = FastResponse;
160
- import { serve } from "srvx/node";
161
164
  import { app } from "${normalizedRoutesPath}";
162
165
 
163
166
  serve(app);
@@ -264,12 +267,7 @@ const taserPlugin = createUnplugin((options = {}, meta) => {
264
267
  return { build: {
265
268
  ssr: serveShimPath,
266
269
  rollupOptions: {
267
- external: [
268
- "srvx",
269
- "srvx/node",
270
- "@taserjs/runtime",
271
- "hono"
272
- ],
270
+ external: ["@taserjs/runtime", /^@taserjs\/runtime\/.*/],
273
271
  output: { entryFileNames: "serve.mjs" }
274
272
  }
275
273
  } };
@@ -332,6 +330,6 @@ const taserPlugin = createUnplugin((options = {}, meta) => {
332
330
  });
333
331
  const taser = Object.assign((options) => taserPlugin.raw(options, {}), taserPlugin);
334
332
  //#endregion
335
- export { DEFAULT_OUTPUT_IGNORE_PATTERN, DEFAULT_WATCH_DEBOUNCE_MS, buildHostFallbackCode, taserPlugin as default, taserPlugin, detectHostServer, emitServeShim, getHostServer, isOutputDir, isSubPath, mountHostFallback, normalizeImportPath, resolveHostFetchHandler, taser };
333
+ export { DEFAULT_OUTPUT_IGNORE_PATTERN, DEFAULT_WATCH_DEBOUNCE_MS, buildHostFallbackCode, taserPlugin as default, taserPlugin, detectFullStack, detectHostServer, emitServeShim, getHostServer, isFullStackPluginName, isOutputDir, isSubPath, mountHostFallback, normalizeImportPath, resolveHostFetchHandler, taser };
336
334
 
337
335
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, normalize, relative, resolve } from \"pathe\";\nimport {\n generateManifest,\n loadConfig,\n resolveAppFile,\n resolveImportExtension,\n resolveOutputDir,\n resolveRoutesDir,\n resolveServerDir,\n scanRoutes,\n type ResolvedTaserConfig,\n} from \"@taserjs/cli\";\nimport { toFetchHandler, toNodeHandler } from \"srvx/node\";\nimport { createUnplugin } from \"unplugin\";\n\nexport const DEFAULT_WATCH_DEBOUNCE_MS = 50;\nexport const DEFAULT_OUTPUT_IGNORE_PATTERN = \"**/.taserjs/**\";\n\nexport interface TaserPluginOptions {\n server?: boolean | undefined;\n serverEntry?: string | undefined;\n cwd?: string | undefined;\n config?: string | undefined;\n standalone?: boolean | undefined;\n}\n\nexport interface HostServerInfo {\n type: \"node\" | \"fetch\";\n path: string;\n}\n\nconst NODE_SERVER_CANDIDATES = [\n \"server.node.ts\",\n \"server.node.js\",\n \"server.node.mjs\",\n \"server.node.cjs\",\n];\n\nconst FETCH_SERVER_CANDIDATES = [\"server.ts\", \"server.js\", \"server.mjs\", \"server.cjs\"];\n\nexport function detectHostServer(\n serverDir: string,\n cwd?: string,\n explicitEntry?: string,\n): HostServerInfo | null {\n if (explicitEntry) {\n const resolvedPath = isAbsolute(explicitEntry)\n ? explicitEntry\n : resolve(cwd ?? process.cwd(), explicitEntry);\n if (existsSync(resolvedPath)) {\n const isNode = resolvedPath.includes(\".node.\") || resolvedPath.endsWith(\".node\");\n return {\n type: isNode ? \"node\" : \"fetch\",\n path: resolvedPath,\n };\n }\n }\n\n for (const candidate of NODE_SERVER_CANDIDATES) {\n const candidatePath = join(serverDir, candidate);\n if (existsSync(candidatePath)) {\n return { type: \"node\", path: candidatePath };\n }\n }\n\n for (const candidate of FETCH_SERVER_CANDIDATES) {\n const candidatePath = join(serverDir, candidate);\n if (existsSync(candidatePath)) {\n return { type: \"fetch\", path: candidatePath };\n }\n }\n\n return null;\n}\n\nconst FULLSTACK_PLUGIN_PATTERNS = [\n \"nitro\",\n \"tanstack-start\",\n \"tanstack:router\",\n \"react-router\",\n \"remix\",\n \"astro\",\n \"sveltekit\",\n];\n\nfunction isFullStackPluginName(name: string): boolean {\n const lower = name.toLowerCase();\n for (const pattern of FULLSTACK_PLUGIN_PATTERNS) {\n if (lower.includes(pattern)) {\n return true;\n }\n }\n if (lower.includes(\"tanstack\") && lower.includes(\"start\")) {\n return true;\n }\n return false;\n}\n\nfunction detectFullStack(viteConfig: any): boolean {\n if (!viteConfig) return false;\n if (viteConfig.nitro) return true;\n const plugins = viteConfig.plugins;\n if (!plugins) return false;\n const flat = Array.isArray(plugins) ? plugins.flat(Infinity) : [plugins];\n return flat.some((p: any) => {\n const name = p?.name;\n return typeof name === \"string\" && isFullStackPluginName(name);\n });\n}\n\nfunction isRunnableEnvironment(environment: any): boolean {\n if (!environment) return true;\n try {\n if (environment.constructor?.name === \"FetchableDevEnvironment\") {\n return false;\n }\n if (environment.constructor?.name === \"RunnableDevEnvironment\") {\n return true;\n }\n if (typeof (environment as any).dispatchFetch === \"function\" && !(environment as any).runner) {\n return false;\n }\n if ((environment as any).runner) {\n return true;\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(`[taserjs] Warning checking Vite environment runnability: ${message}`);\n }\n return true;\n}\n\nexport function normalizeImportPath(pathStr: string): string {\n let normalized = normalize(pathStr);\n if (!isAbsolute(normalized) && !normalized.startsWith(\"./\") && !normalized.startsWith(\"../\")) {\n normalized = `./${normalized}`;\n }\n return normalized;\n}\n\nexport function isSubPath(child: string, parent: string): boolean {\n const rel = relative(parent, child);\n return !rel.startsWith(\"../\") && rel !== \"..\" && !isAbsolute(rel);\n}\n\nexport function isOutputDir(filePath: string, outputDir: string): boolean {\n const normalizedFile = resolve(filePath);\n const normalizedOutput = resolve(outputDir);\n return (\n normalizedFile === normalizedOutput ||\n isSubPath(normalizedFile, normalizedOutput) ||\n filePath.includes(\".taserjs\")\n );\n}\n\nfunction mergeWatchIgnored(current: unknown, ...patterns: string[]): Array<string | RegExp> {\n const existing: Array<string | RegExp> = Array.isArray(current)\n ? [...current]\n : current\n ? [current as string | RegExp]\n : [];\n\n for (const pattern of patterns) {\n if (!existing.includes(pattern)) {\n existing.push(pattern);\n }\n }\n\n return existing;\n}\n\nexport function getHostServer(\n config: ResolvedTaserConfig,\n cwd: string,\n options?: TaserPluginOptions,\n): HostServerInfo | null {\n const serverDir = resolveServerDir(config, cwd);\n return detectHostServer(serverDir, cwd, options?.serverEntry);\n}\n\nexport function resolveHostFetchHandler(\n hostMod: unknown,\n type: \"node\" | \"fetch\",\n): ((fetchReq: Request) => Promise<Response> | Response) | null {\n const rawHost = (hostMod as Record<string, any>)?.default ?? hostMod;\n if (type === \"node\") {\n const nodeHandler = typeof rawHost === \"function\" ? rawHost : (rawHost?.routing ?? rawHost);\n return typeof nodeHandler === \"function\" ? toFetchHandler(nodeHandler) : null;\n }\n if (typeof (rawHost as any)?.fetch === \"function\") {\n return (fetchReq: Request) => (rawHost as any).fetch(fetchReq);\n }\n return typeof rawHost === \"function\" ? (rawHost as any) : null;\n}\n\nexport function mountHostFallback(app: any, hostMod: unknown, type: \"node\" | \"fetch\"): boolean {\n if (!app || typeof app.all !== \"function\" || app._hasHostFallback) {\n return false;\n }\n const hostFetch = resolveHostFetchHandler(hostMod, type);\n if (hostFetch) {\n app.all(\"*\", (c: any) => hostFetch(c.req.raw));\n app._hasHostFallback = true;\n return true;\n }\n return false;\n}\n\nexport function buildHostFallbackCode(\n hostImportPath: string,\n type: \"node\" | \"fetch\",\n appVarName: string = \"app\",\n): { imports: string; setup: string } {\n const isNode = type === \"node\";\n const imports = `${isNode ? 'import { toFetchHandler } from \"srvx/node\";\\n' : \"\"}import hostServerEntry from \"${hostImportPath}\";`;\n\n const setup = isNode\n ? `const rawHost = hostServerEntry?.default ?? hostServerEntry;\nconst nodeHandler = typeof rawHost === \"function\" ? rawHost : (rawHost?.routing ?? rawHost);\nconst hostFetch = typeof nodeHandler === \"function\" ? toFetchHandler(nodeHandler) : null;\nif (hostFetch) ${appVarName}.all(\"*\", (c) => hostFetch(c.req.raw));`\n : `const rawHost = hostServerEntry?.default ?? hostServerEntry;\nconst hostFetch = typeof rawHost?.fetch === \"function\" ? (r) => rawHost.fetch(r) : typeof rawHost === \"function\" ? rawHost : null;\nif (hostFetch) ${appVarName}.all(\"*\", (c) => hostFetch(c.req.raw));`;\n\n return { imports, setup };\n}\n\nexport function emitServeShim(\n serveShimPath: string,\n routesGenImportPath: string,\n hostServer?: HostServerInfo | null,\n ext: string = \".js\",\n): void {\n const normalizedRoutesPath = normalizeImportPath(routesGenImportPath);\n const outputDir = resolve(serveShimPath, \"..\");\n\n let code: string;\n if (hostServer) {\n let hostImportPath = normalizeImportPath(relative(outputDir, hostServer.path));\n if (hostImportPath.endsWith(\".ts\")) {\n hostImportPath = hostImportPath.slice(0, -3) + ext;\n } else if (hostImportPath.endsWith(\".js\") && ext === \"\") {\n hostImportPath = hostImportPath.slice(0, -3);\n }\n\n const fallbackCode = buildHostFallbackCode(hostImportPath, hostServer.type, \"app\");\n code = `// @ts-nocheck\nimport { FastResponse } from \"srvx\";\nglobalThis.Response = FastResponse;\nimport { serve } from \"srvx/node\";\n${fallbackCode.imports}\nimport { app } from \"${normalizedRoutesPath}\";\n\n${fallbackCode.setup}\n\nexport { app };\nserve(app);\n`;\n } else {\n code = `// @ts-nocheck\nimport { FastResponse } from \"srvx\";\nglobalThis.Response = FastResponse;\nimport { serve } from \"srvx/node\";\nimport { app } from \"${normalizedRoutesPath}\";\n\nserve(app);\n`;\n }\n\n mkdirSync(resolve(serveShimPath, \"..\"), { recursive: true });\n writeFileSync(serveShimPath, code, \"utf-8\");\n}\n\nexport const taserPlugin = createUnplugin((options: TaserPluginOptions | undefined = {}, meta) => {\n let cwd = options.cwd ? resolve(options.cwd) : process.cwd();\n let cachedConfig: ResolvedTaserConfig | null = null;\n let detectedFullStack: boolean | null = null;\n\n async function getConfig(): Promise<ResolvedTaserConfig> {\n if (!cachedConfig) {\n cachedConfig = await loadConfig(cwd, options.config);\n }\n return cachedConfig;\n }\n\n async function resolveIsServerMode(viteConfig?: any): Promise<boolean> {\n if (options.server !== undefined) {\n return options.server;\n }\n const config = await getConfig();\n if (config.server !== undefined) {\n return config.server;\n }\n if (detectedFullStack !== null) {\n return !detectedFullStack;\n }\n if (viteConfig && detectFullStack(viteConfig)) {\n detectedFullStack = true;\n return false;\n }\n return true;\n }\n\n async function executeGeneration(isDev = false): Promise<void> {\n try {\n const config = await getConfig();\n const routesDir = resolveRoutesDir(config, cwd);\n const scanResult = scanRoutes({\n routesDir,\n cwd,\n scaffold: isDev,\n formatting: config.formatting,\n });\n\n generateManifest(scanResult, config, cwd);\n } catch (err: unknown) {\n if (isDev) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`[taserjs] Route generation warning: ${message}`);\n } else {\n throw err;\n }\n }\n }\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n function triggerDebouncedGeneration(): void {\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n debounceTimer = setTimeout(() => {\n executeGeneration(true).catch(() => {});\n }, DEFAULT_WATCH_DEBOUNCE_MS);\n }\n\n let cachedDevHandler: ((req: any, res: any) => any) | null = null;\n const VITE_INTERNAL_PREFIXES = [\"/@\", \"/__vite\", \"/__open-in-editor\", \"/@fs/\", \"/@id/\"];\n const VITE_QUERY_PATTERN = /[?&](?:import|raw|url|worker)\\b/;\n\n function shouldSkipDevRequest(url: string): boolean {\n for (let i = 0; i < VITE_INTERNAL_PREFIXES.length; i++) {\n if (url.startsWith(VITE_INTERNAL_PREFIXES[i]!)) {\n return true;\n }\n }\n if (url.startsWith(\"/node_modules/\")) {\n return true;\n }\n return VITE_QUERY_PATTERN.test(url);\n }\n\n return {\n name: \"taserjs:plugin\",\n\n async buildStart() {\n const isDev = meta.framework === \"vite\";\n await executeGeneration(isDev);\n\n const isServerMode = await resolveIsServerMode();\n if (isServerMode) {\n const config = await getConfig();\n const outputDir = resolveOutputDir(config, cwd);\n const hostServer = getHostServer(config, cwd, options);\n const serveShimPath = join(outputDir, \"serve.ts\");\n const ext = resolveImportExtension(config.extension);\n emitServeShim(serveShimPath, `./routes.gen${ext}`, hostServer, ext);\n }\n },\n\n async watchChange(id, _change) {\n cachedDevHandler = null;\n const config = await getConfig();\n const outputDir = resolveOutputDir(config, cwd);\n if (isOutputDir(id, outputDir)) {\n return;\n }\n\n const routesDir = resolveRoutesDir(config, cwd);\n const serverDir = resolveServerDir(config, cwd);\n const appFile = resolveAppFile(config, cwd);\n\n if (id === appFile || isSubPath(id, routesDir) || isSubPath(id, serverDir)) {\n await executeGeneration(true);\n }\n },\n\n vite: {\n async config(config, env) {\n if (!options.cwd && config.root) {\n cwd = resolve(config.root);\n cachedConfig = null;\n }\n config.server = config.server || {};\n config.server.watch = config.server.watch || {};\n config.server.watch.ignored = mergeWatchIgnored(\n config.server.watch.ignored,\n DEFAULT_OUTPUT_IGNORE_PATTERN,\n );\n\n const isFullStack = detectFullStack(config);\n detectedFullStack = isFullStack;\n\n const isServerMode = await resolveIsServerMode(config);\n\n if (isServerMode && env?.command === \"build\") {\n const taserConfig = await getConfig();\n const outputDir = resolveOutputDir(taserConfig, cwd);\n const hostServer = getHostServer(taserConfig, cwd, options);\n const serveShimPath = join(outputDir, \"serve.ts\");\n const ext = resolveImportExtension(taserConfig.extension);\n emitServeShim(serveShimPath, `./routes.gen${ext}`, hostServer, ext);\n\n return {\n build: {\n ssr: serveShimPath,\n rollupOptions: {\n external: [\"srvx\", \"srvx/node\", \"@taserjs/runtime\", \"hono\"],\n output: {\n entryFileNames: \"serve.mjs\",\n },\n },\n },\n };\n }\n },\n\n configResolved(resolvedConfig) {\n if (detectFullStack(resolvedConfig)) {\n detectedFullStack = true;\n } else if (detectedFullStack === null) {\n detectedFullStack = false;\n }\n },\n\n async configureServer(server) {\n const handleFileChange = async (file: string) => {\n cachedDevHandler = null;\n const config = await getConfig();\n const outputDir = resolveOutputDir(config, cwd);\n if (isOutputDir(file, outputDir)) {\n return;\n }\n\n const routesDir = resolveRoutesDir(config, cwd);\n const serverDir = resolveServerDir(config, cwd);\n const appFile = resolveAppFile(config, cwd);\n\n if (file === appFile || isSubPath(file, routesDir) || isSubPath(file, serverDir)) {\n triggerDebouncedGeneration();\n }\n };\n\n server.watcher.on(\"add\", handleFileChange);\n server.watcher.on(\"unlink\", handleFileChange);\n server.watcher.on(\"change\", handleFileChange);\n server.watcher.on(\"unlinkDir\", handleFileChange);\n\n const isServerMode = await resolveIsServerMode(server.config);\n if (!isServerMode) {\n return;\n }\n\n server.middlewares.use(async (req: any, res: any, next: any) => {\n const url = req.url;\n if (!url || shouldSkipDevRequest(url)) {\n return next();\n }\n\n const ssrEnv = (server as any).environments?.ssr;\n if ((server as any).environments && ssrEnv && !isRunnableEnvironment(ssrEnv)) {\n return next();\n }\n\n try {\n if (!cachedDevHandler) {\n const taserConfig = await getConfig();\n const outputDir = resolveOutputDir(taserConfig, cwd);\n const routesGenPath = join(outputDir, \"routes.gen.ts\");\n\n if (!existsSync(routesGenPath)) {\n await executeGeneration(true);\n }\n\n const mod = (await server.ssrLoadModule(routesGenPath)) as Record<string, any>;\n const app = mod.app ?? mod.default;\n\n if (!app || typeof app.fetch !== \"function\") {\n return next();\n }\n\n const hostServer = getHostServer(taserConfig, cwd, options);\n\n if (hostServer) {\n const hostMod = await server.ssrLoadModule(hostServer.path);\n mountHostFallback(app, hostMod, hostServer.type);\n }\n\n cachedDevHandler = toNodeHandler((fetchReq: Request) => app.fetch(fetchReq));\n }\n\n if (cachedDevHandler) {\n await cachedDevHandler(req, res);\n } else {\n next();\n }\n } catch (error) {\n server.ssrFixStacktrace(error as Error);\n next(error);\n }\n });\n },\n },\n\n webpack(compiler) {\n compiler.options.watchOptions = compiler.options.watchOptions || {};\n compiler.options.watchOptions.ignored = mergeWatchIgnored(\n compiler.options.watchOptions.ignored,\n DEFAULT_OUTPUT_IGNORE_PATTERN,\n );\n },\n\n rspack(compiler) {\n compiler.options.watchOptions = compiler.options.watchOptions || {};\n compiler.options.watchOptions.ignored = mergeWatchIgnored(\n compiler.options.watchOptions.ignored,\n DEFAULT_OUTPUT_IGNORE_PATTERN,\n );\n },\n };\n});\n\nexport const taser = Object.assign(\n (options?: TaserPluginOptions) => taserPlugin.raw(options, {} as any),\n taserPlugin,\n);\nexport default taserPlugin;\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, normalize, relative, resolve } from \"pathe\";\nimport {\n generateManifest,\n loadConfig,\n resolveAppFile,\n resolveImportExtension,\n resolveOutputDir,\n resolveRoutesDir,\n resolveServerDir,\n scanRoutes,\n type ResolvedTaserConfig,\n} from \"@taserjs/cli\";\nimport { toFetchHandler, toNodeHandler } from \"srvx/node\";\nimport { createUnplugin } from \"unplugin\";\n\nexport const DEFAULT_WATCH_DEBOUNCE_MS = 50;\nexport const DEFAULT_OUTPUT_IGNORE_PATTERN = \"**/.taserjs/**\";\n\nexport interface TaserPluginOptions {\n server?: boolean | undefined;\n serverEntry?: string | undefined;\n cwd?: string | undefined;\n config?: string | undefined;\n standalone?: boolean | undefined;\n}\n\nexport interface HostServerInfo {\n type: \"node\" | \"fetch\";\n path: string;\n}\n\nconst NODE_SERVER_CANDIDATES = [\n \"server.node.ts\",\n \"server.node.js\",\n \"server.node.mjs\",\n \"server.node.cjs\",\n];\n\nconst FETCH_SERVER_CANDIDATES = [\"server.ts\", \"server.js\", \"server.mjs\", \"server.cjs\"];\n\nexport function detectHostServer(\n serverDir: string,\n cwd?: string,\n explicitEntry?: string,\n): HostServerInfo | null {\n if (explicitEntry) {\n const resolvedPath = isAbsolute(explicitEntry)\n ? explicitEntry\n : resolve(cwd ?? process.cwd(), explicitEntry);\n if (existsSync(resolvedPath)) {\n const isNode = resolvedPath.includes(\".node.\") || resolvedPath.endsWith(\".node\");\n return {\n type: isNode ? \"node\" : \"fetch\",\n path: resolvedPath,\n };\n }\n }\n\n for (const candidate of NODE_SERVER_CANDIDATES) {\n const candidatePath = join(serverDir, candidate);\n if (existsSync(candidatePath)) {\n return { type: \"node\", path: candidatePath };\n }\n }\n\n for (const candidate of FETCH_SERVER_CANDIDATES) {\n const candidatePath = join(serverDir, candidate);\n if (existsSync(candidatePath)) {\n return { type: \"fetch\", path: candidatePath };\n }\n }\n\n return null;\n}\n\nconst FULLSTACK_PLUGIN_PATTERNS = [\n \"nitro\",\n \"tanstack-start\",\n \"tanstack:router\",\n \"react-router\",\n \"remix\",\n \"astro\",\n \"sveltekit\",\n \"nuxt\",\n \"solid-start\",\n \"analog\",\n];\n\nexport function isFullStackPluginName(name: string): boolean {\n const lower = name.toLowerCase();\n for (const pattern of FULLSTACK_PLUGIN_PATTERNS) {\n if (lower.includes(pattern)) {\n return true;\n }\n }\n if (lower.includes(\"tanstack\") && lower.includes(\"start\")) {\n return true;\n }\n return false;\n}\n\nexport function detectFullStack(viteConfig: any, excludeNitro = false): boolean {\n if (!viteConfig) return false;\n if (!excludeNitro && viteConfig.nitro) return true;\n const plugins = viteConfig.plugins;\n if (!plugins) return false;\n const flat = Array.isArray(plugins) ? plugins.flat(Infinity) : [plugins];\n return flat.some((p: any) => {\n const name = p?.name;\n if (typeof name !== \"string\") return false;\n if (excludeNitro && name.toLowerCase().includes(\"nitro\")) return false;\n return isFullStackPluginName(name);\n });\n}\n\nfunction isRunnableEnvironment(environment: any): boolean {\n if (!environment) return true;\n try {\n if (environment.constructor?.name === \"FetchableDevEnvironment\") {\n return false;\n }\n if (environment.constructor?.name === \"RunnableDevEnvironment\") {\n return true;\n }\n if (typeof (environment as any).dispatchFetch === \"function\" && !(environment as any).runner) {\n return false;\n }\n if ((environment as any).runner) {\n return true;\n }\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(`[taserjs] Warning checking Vite environment runnability: ${message}`);\n }\n return true;\n}\n\nexport function normalizeImportPath(pathStr: string): string {\n let normalized = normalize(pathStr);\n if (!isAbsolute(normalized) && !normalized.startsWith(\"./\") && !normalized.startsWith(\"../\")) {\n normalized = `./${normalized}`;\n }\n return normalized;\n}\n\nexport function isSubPath(child: string, parent: string): boolean {\n const rel = relative(parent, child);\n return !rel.startsWith(\"../\") && rel !== \"..\" && !isAbsolute(rel);\n}\n\nexport function isOutputDir(filePath: string, outputDir: string): boolean {\n const normalizedFile = resolve(filePath);\n const normalizedOutput = resolve(outputDir);\n return (\n normalizedFile === normalizedOutput ||\n isSubPath(normalizedFile, normalizedOutput) ||\n filePath.includes(\".taserjs\")\n );\n}\n\nfunction mergeWatchIgnored(current: unknown, ...patterns: string[]): Array<string | RegExp> {\n const existing: Array<string | RegExp> = Array.isArray(current)\n ? [...current]\n : current\n ? [current as string | RegExp]\n : [];\n\n for (const pattern of patterns) {\n if (!existing.includes(pattern)) {\n existing.push(pattern);\n }\n }\n\n return existing;\n}\n\nexport function getHostServer(\n config: ResolvedTaserConfig,\n cwd: string,\n options?: TaserPluginOptions,\n): HostServerInfo | null {\n const serverDir = resolveServerDir(config, cwd);\n return detectHostServer(serverDir, cwd, options?.serverEntry);\n}\n\nexport function resolveHostFetchHandler(\n hostMod: unknown,\n type: \"node\" | \"fetch\",\n): ((fetchReq: Request) => Promise<Response> | Response) | null {\n const rawHost = (hostMod as Record<string, any>)?.default ?? hostMod;\n if (type === \"node\") {\n const nodeHandler = typeof rawHost === \"function\" ? rawHost : (rawHost?.routing ?? rawHost);\n return typeof nodeHandler === \"function\" ? toFetchHandler(nodeHandler) : null;\n }\n if (typeof (rawHost as any)?.fetch === \"function\") {\n return (fetchReq: Request) => (rawHost as any).fetch(fetchReq);\n }\n return typeof rawHost === \"function\" ? (rawHost as any) : null;\n}\n\nexport function mountHostFallback(app: any, hostMod: unknown, type: \"node\" | \"fetch\"): boolean {\n if (!app || typeof app.all !== \"function\" || app._hasHostFallback) {\n return false;\n }\n const hostFetch = resolveHostFetchHandler(hostMod, type);\n if (hostFetch) {\n app.all(\"*\", (c: any) => hostFetch(c.req.raw));\n app._hasHostFallback = true;\n return true;\n }\n return false;\n}\n\nexport function buildHostFallbackCode(\n hostImportPath: string,\n type: \"node\" | \"fetch\",\n appVarName: string = \"app\",\n): { imports: string; setup: string } {\n const isNode = type === \"node\";\n const imports = `${isNode ? 'import { toFetchHandler } from \"@taserjs/runtime/serve/node\";\\n' : \"\"}import hostServerEntry from \"${hostImportPath}\";`;\n\n const setup = isNode\n ? `const rawHost = hostServerEntry?.default ?? hostServerEntry;\nconst nodeHandler = typeof rawHost === \"function\" ? rawHost : (rawHost?.routing ?? rawHost);\nconst hostFetch = typeof nodeHandler === \"function\" ? toFetchHandler(nodeHandler) : null;\nif (hostFetch) ${appVarName}.all(\"*\", (c) => hostFetch(c.req.raw));`\n : `const rawHost = hostServerEntry?.default ?? hostServerEntry;\nconst hostFetch = typeof rawHost?.fetch === \"function\" ? (r) => rawHost.fetch(r) : typeof rawHost === \"function\" ? rawHost : null;\nif (hostFetch) ${appVarName}.all(\"*\", (c) => hostFetch(c.req.raw));`;\n\n return { imports, setup };\n}\n\nexport function emitServeShim(\n serveShimPath: string,\n routesGenImportPath: string,\n hostServer?: HostServerInfo | null,\n ext: string = \".js\",\n): void {\n const normalizedRoutesPath = normalizeImportPath(routesGenImportPath);\n const outputDir = resolve(serveShimPath, \"..\");\n\n let code: string;\n if (hostServer) {\n let hostImportPath = normalizeImportPath(relative(outputDir, hostServer.path));\n if (hostImportPath.endsWith(\".ts\")) {\n hostImportPath = hostImportPath.slice(0, -3) + ext;\n } else if (hostImportPath.endsWith(\".js\") && ext === \"\") {\n hostImportPath = hostImportPath.slice(0, -3);\n }\n\n const fallbackCode = buildHostFallbackCode(hostImportPath, hostServer.type, \"app\");\n code = `// @ts-nocheck\nimport { FastResponse, serve } from \"@taserjs/runtime/serve\";\nglobalThis.Response = FastResponse;\n${fallbackCode.imports}\nimport { app } from \"${normalizedRoutesPath}\";\n\n${fallbackCode.setup}\n\nexport { app };\nserve(app);\n`;\n } else {\n code = `// @ts-nocheck\nimport { FastResponse, serve } from \"@taserjs/runtime/serve\";\nglobalThis.Response = FastResponse;\nimport { app } from \"${normalizedRoutesPath}\";\n\nserve(app);\n`;\n }\n\n mkdirSync(resolve(serveShimPath, \"..\"), { recursive: true });\n writeFileSync(serveShimPath, code, \"utf-8\");\n}\n\nexport const taserPlugin = createUnplugin((options: TaserPluginOptions | undefined = {}, meta) => {\n let cwd = options.cwd ? resolve(options.cwd) : process.cwd();\n let cachedConfig: ResolvedTaserConfig | null = null;\n let detectedFullStack: boolean | null = null;\n\n async function getConfig(): Promise<ResolvedTaserConfig> {\n if (!cachedConfig) {\n cachedConfig = await loadConfig(cwd, options.config);\n }\n return cachedConfig;\n }\n\n async function resolveIsServerMode(viteConfig?: any): Promise<boolean> {\n if (options.server !== undefined) {\n return options.server;\n }\n const config = await getConfig();\n if (config.server !== undefined) {\n return config.server;\n }\n if (detectedFullStack !== null) {\n return !detectedFullStack;\n }\n if (viteConfig && detectFullStack(viteConfig)) {\n detectedFullStack = true;\n return false;\n }\n return true;\n }\n\n async function executeGeneration(isDev = false): Promise<void> {\n try {\n const config = await getConfig();\n const routesDir = resolveRoutesDir(config, cwd);\n const scanResult = scanRoutes({\n routesDir,\n cwd,\n scaffold: isDev,\n formatting: config.formatting,\n });\n\n generateManifest(scanResult, config, cwd);\n } catch (err: unknown) {\n if (isDev) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(`[taserjs] Route generation warning: ${message}`);\n } else {\n throw err;\n }\n }\n }\n\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n function triggerDebouncedGeneration(): void {\n if (debounceTimer) {\n clearTimeout(debounceTimer);\n }\n debounceTimer = setTimeout(() => {\n executeGeneration(true).catch(() => {});\n }, DEFAULT_WATCH_DEBOUNCE_MS);\n }\n\n let cachedDevHandler: ((req: any, res: any) => any) | null = null;\n const VITE_INTERNAL_PREFIXES = [\"/@\", \"/__vite\", \"/__open-in-editor\", \"/@fs/\", \"/@id/\"];\n const VITE_QUERY_PATTERN = /[?&](?:import|raw|url|worker)\\b/;\n\n function shouldSkipDevRequest(url: string): boolean {\n for (let i = 0; i < VITE_INTERNAL_PREFIXES.length; i++) {\n if (url.startsWith(VITE_INTERNAL_PREFIXES[i]!)) {\n return true;\n }\n }\n if (url.startsWith(\"/node_modules/\")) {\n return true;\n }\n return VITE_QUERY_PATTERN.test(url);\n }\n\n return {\n name: \"taserjs:plugin\",\n\n async buildStart() {\n const isDev = meta.framework === \"vite\";\n await executeGeneration(isDev);\n\n const isServerMode = await resolveIsServerMode();\n if (isServerMode) {\n const config = await getConfig();\n const outputDir = resolveOutputDir(config, cwd);\n const hostServer = getHostServer(config, cwd, options);\n const serveShimPath = join(outputDir, \"serve.ts\");\n const ext = resolveImportExtension(config.extension);\n emitServeShim(serveShimPath, `./routes.gen${ext}`, hostServer, ext);\n }\n },\n\n async watchChange(id, _change) {\n cachedDevHandler = null;\n const config = await getConfig();\n const outputDir = resolveOutputDir(config, cwd);\n if (isOutputDir(id, outputDir)) {\n return;\n }\n\n const routesDir = resolveRoutesDir(config, cwd);\n const serverDir = resolveServerDir(config, cwd);\n const appFile = resolveAppFile(config, cwd);\n\n if (id === appFile || isSubPath(id, routesDir) || isSubPath(id, serverDir)) {\n await executeGeneration(true);\n }\n },\n\n vite: {\n async config(config, env) {\n if (!options.cwd && config.root) {\n cwd = resolve(config.root);\n cachedConfig = null;\n }\n config.server = config.server || {};\n config.server.watch = config.server.watch || {};\n config.server.watch.ignored = mergeWatchIgnored(\n config.server.watch.ignored,\n DEFAULT_OUTPUT_IGNORE_PATTERN,\n );\n\n const isFullStack = detectFullStack(config);\n detectedFullStack = isFullStack;\n\n const isServerMode = await resolveIsServerMode(config);\n\n if (isServerMode && env?.command === \"build\") {\n const taserConfig = await getConfig();\n const outputDir = resolveOutputDir(taserConfig, cwd);\n const hostServer = getHostServer(taserConfig, cwd, options);\n const serveShimPath = join(outputDir, \"serve.ts\");\n const ext = resolveImportExtension(taserConfig.extension);\n emitServeShim(serveShimPath, `./routes.gen${ext}`, hostServer, ext);\n\n return {\n build: {\n ssr: serveShimPath,\n rollupOptions: {\n external: [\"@taserjs/runtime\", /^@taserjs\\/runtime\\/.*/],\n output: {\n entryFileNames: \"serve.mjs\",\n },\n },\n },\n };\n }\n },\n\n configResolved(resolvedConfig) {\n if (detectFullStack(resolvedConfig)) {\n detectedFullStack = true;\n } else if (detectedFullStack === null) {\n detectedFullStack = false;\n }\n },\n\n async configureServer(server) {\n const handleFileChange = async (file: string) => {\n cachedDevHandler = null;\n const config = await getConfig();\n const outputDir = resolveOutputDir(config, cwd);\n if (isOutputDir(file, outputDir)) {\n return;\n }\n\n const routesDir = resolveRoutesDir(config, cwd);\n const serverDir = resolveServerDir(config, cwd);\n const appFile = resolveAppFile(config, cwd);\n\n if (file === appFile || isSubPath(file, routesDir) || isSubPath(file, serverDir)) {\n triggerDebouncedGeneration();\n }\n };\n\n server.watcher.on(\"add\", handleFileChange);\n server.watcher.on(\"unlink\", handleFileChange);\n server.watcher.on(\"change\", handleFileChange);\n server.watcher.on(\"unlinkDir\", handleFileChange);\n\n const isServerMode = await resolveIsServerMode(server.config);\n if (!isServerMode) {\n return;\n }\n\n server.middlewares.use(async (req: any, res: any, next: any) => {\n const url = req.url;\n if (!url || shouldSkipDevRequest(url)) {\n return next();\n }\n\n const ssrEnv = (server as any).environments?.ssr;\n if ((server as any).environments && ssrEnv && !isRunnableEnvironment(ssrEnv)) {\n return next();\n }\n\n try {\n if (!cachedDevHandler) {\n const taserConfig = await getConfig();\n const outputDir = resolveOutputDir(taserConfig, cwd);\n const routesGenPath = join(outputDir, \"routes.gen.ts\");\n\n if (!existsSync(routesGenPath)) {\n await executeGeneration(true);\n }\n\n const mod = (await server.ssrLoadModule(routesGenPath)) as Record<string, any>;\n const app = mod.app ?? mod.default;\n\n if (!app || typeof app.fetch !== \"function\") {\n return next();\n }\n\n const hostServer = getHostServer(taserConfig, cwd, options);\n\n if (hostServer) {\n const hostMod = await server.ssrLoadModule(hostServer.path);\n mountHostFallback(app, hostMod, hostServer.type);\n }\n\n cachedDevHandler = toNodeHandler((fetchReq: Request) => app.fetch(fetchReq));\n }\n\n if (cachedDevHandler) {\n await cachedDevHandler(req, res);\n } else {\n next();\n }\n } catch (error) {\n server.ssrFixStacktrace(error as Error);\n next(error);\n }\n });\n },\n },\n\n webpack(compiler) {\n compiler.options.watchOptions = compiler.options.watchOptions || {};\n compiler.options.watchOptions.ignored = mergeWatchIgnored(\n compiler.options.watchOptions.ignored,\n DEFAULT_OUTPUT_IGNORE_PATTERN,\n );\n },\n\n rspack(compiler) {\n compiler.options.watchOptions = compiler.options.watchOptions || {};\n compiler.options.watchOptions.ignored = mergeWatchIgnored(\n compiler.options.watchOptions.ignored,\n DEFAULT_OUTPUT_IGNORE_PATTERN,\n );\n },\n };\n});\n\nexport const taser = Object.assign(\n (options?: TaserPluginOptions) => taserPlugin.raw(options, {} as any),\n taserPlugin,\n);\nexport default taserPlugin;\n"],"mappings":"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"}
package/dist/nitro.d.ts CHANGED
@@ -3,7 +3,7 @@ import { HostServerInfo, TaserPluginOptions } from "./index.js";
3
3
  export declare function buildNitroRoutingVirtualSource(): string;
4
4
  export declare function buildNitroStandaloneAppSource(routesGenPath: string, hostServer?: HostServerInfo | null): string;
5
5
  export declare function buildNitroMiddlewareHandlerSource(routesGenPath: string, hostServer?: HostServerInfo | null): string;
6
- export declare function setupTaserNitro(nitro: any, options?: TaserPluginOptions): void;
6
+ export declare function setupTaserNitro(nitro: any, options?: TaserPluginOptions): Promise<void> | void;
7
7
  export declare function applyTaserNitro(nitro: any, options: TaserPluginOptions): Promise<void>;
8
8
  /**
9
9
  * Taser Nitro module.
@@ -1 +1 @@
1
- {"version":3,"file":"nitro.d.ts","names":[],"sources":["../src/nitro.ts"],"mappings":";;wBAqBgB;wBASA,8BACd,uBACA,aAAa;wBAmCC,kCACd,uBACA,aAAa;wBAoBC,gBAAgB,YAAY,UAAS;wBAY/B,gBAAgB,YAAY,SAAS,qBAAqB;;;;;;;wBA6EhE,MAAM,UAAS"}
1
+ {"version":3,"file":"nitro.d.ts","names":[],"sources":["../src/nitro.ts"],"mappings":";;wBAqBgB;wBASA,8BACd,uBACA,aAAa;wBAmCC,kCACd,uBACA,aAAa;wBAmBC,gBACd,YACA,UAAS,qBACR;wBAUmB,gBAAgB,YAAY,SAAS,qBAAqB;;;;;;;wBAsFhE,MAAM,UAAS"}
package/dist/nitro.js CHANGED
@@ -17,7 +17,7 @@ function buildNitroStandaloneAppSource(routesGenPath, hostServer) {
17
17
  const fallback = hostServer ? buildHostFallbackCode(normalizeImportPath(hostServer.path), hostServer.type, "taserApp") : null;
18
18
  return `// @ts-nocheck
19
19
  import { app as taserApp } from "${normalizedPath}";
20
- import { FastResponse } from "srvx";
20
+ import { FastResponse } from "@taserjs/runtime/serve";
21
21
  ${fallback ? fallback.imports : ""}
22
22
 
23
23
  globalThis.Response = FastResponse;
@@ -47,23 +47,20 @@ function buildNitroMiddlewareHandlerSource(routesGenPath, hostServer) {
47
47
  const fallback = hostServer ? buildHostFallbackCode(normalizeImportPath(hostServer.path), hostServer.type, "taserApp") : null;
48
48
  return `// @ts-nocheck
49
49
  import { app as taserApp } from "${normalizedPath}";
50
- import { toWebRequest } from "h3";
51
50
  ${fallback ? fallback.imports : ""}
52
51
 
53
52
  ${fallback ? fallback.setup : ""}
54
53
 
55
- export default defineEventHandler((event) => {
56
- return taserApp.fetch(toWebRequest(event));
57
- });
54
+ export default (event) => {
55
+ return taserApp.fetch(event.req);
56
+ };
58
57
  `;
59
58
  }
60
59
  function setupTaserNitro(nitro, options = {}) {
61
60
  const state = nitro.options;
62
61
  if (state._taserHookRegistered) return;
63
62
  state._taserHookRegistered = true;
64
- nitro.hooks.hookOnce("build:before", async () => {
65
- await applyTaserNitro(nitro, options);
66
- });
63
+ return applyTaserNitro(nitro, options);
67
64
  }
68
65
  async function applyTaserNitro(nitro, options) {
69
66
  const cwd = resolve(nitro.options.rootDir || options.cwd || process.cwd());
@@ -85,18 +82,21 @@ async function applyTaserNitro(nitro, options) {
85
82
  };
86
83
  executeGeneration();
87
84
  nitro.options.virtual = nitro.options.virtual || {};
88
- if (options.standalone === true) {
85
+ const isStandalone = options.standalone !== false;
86
+ const VIRTUAL_NITRO_HANDLER_ID = "#taserjs/virtual/nitro-handler";
87
+ nitro.options.virtual[VIRTUAL_NITRO_HANDLER_ID] = () => {
88
+ const currentHost = getHostServer(config, cwd, options);
89
+ return buildNitroMiddlewareHandlerSource(routesGenPath, currentHost);
90
+ };
91
+ if (isStandalone) {
89
92
  nitro.options.virtual["#nitro/virtual/app"] = () => {
90
93
  const currentHost = getHostServer(config, cwd, options);
91
94
  return buildNitroStandaloneAppSource(routesGenPath, currentHost);
92
95
  };
93
96
  nitro.options.virtual["#nitro/virtual/routing"] = () => buildNitroRoutingVirtualSource();
97
+ nitro.options.routes = nitro.options.routes || {};
98
+ nitro.options.routes["/**"] = VIRTUAL_NITRO_HANDLER_ID;
94
99
  } else {
95
- const VIRTUAL_NITRO_HANDLER_ID = "#taserjs/virtual/nitro-handler";
96
- nitro.options.virtual[VIRTUAL_NITRO_HANDLER_ID] = () => {
97
- const currentHost = getHostServer(config, cwd, options);
98
- return buildNitroMiddlewareHandlerSource(routesGenPath, currentHost);
99
- };
100
100
  nitro.options.handlers = nitro.options.handlers || [];
101
101
  nitro.options.handlers.unshift({
102
102
  route: "/**",
@@ -104,6 +104,7 @@ async function applyTaserNitro(nitro, options) {
104
104
  handler: VIRTUAL_NITRO_HANDLER_ID
105
105
  });
106
106
  }
107
+ if (nitro.routing?.sync) nitro.routing.sync();
107
108
  let watcher;
108
109
  if (nitro.options.dev && existsSync(routesDir)) {
109
110
  const watchDirs = [routesDir];
package/dist/nitro.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"nitro.js","names":[],"sources":["../src/nitro.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { resolve } from \"pathe\";\nimport {\n generateManifest,\n loadConfig,\n resolveOutputDir,\n resolveRoutesDir,\n resolveServerDir,\n scanRoutes,\n type ResolvedTaserConfig,\n} from \"@taserjs/cli\";\nimport { watch, type FSWatcher } from \"chokidar\";\nimport {\n buildHostFallbackCode,\n getHostServer,\n normalizeImportPath,\n taserPlugin,\n type HostServerInfo,\n type TaserPluginOptions,\n} from \"./index.js\";\n\nexport function buildNitroRoutingVirtualSource(): string {\n return [\n \"export const findRouteRules = () => ({});\",\n \"export const findRoute = () => undefined;\",\n \"export const globalMiddleware = [];\",\n \"export const findRoutedMiddleware = () => [];\",\n ].join(\"\\n\");\n}\n\nexport function buildNitroStandaloneAppSource(\n routesGenPath: string,\n hostServer?: HostServerInfo | null,\n): string {\n const normalizedPath = normalizeImportPath(routesGenPath);\n const fallback = hostServer\n ? buildHostFallbackCode(normalizeImportPath(hostServer.path), hostServer.type, \"taserApp\")\n : null;\n\n return `// @ts-nocheck\nimport { app as taserApp } from \"${normalizedPath}\";\nimport { FastResponse } from \"srvx\";\n${fallback ? fallback.imports : \"\"}\n\nglobalThis.Response = FastResponse;\n\n${fallback ? fallback.setup : \"\"}\n\nexport const handler = (req, ...args) => taserApp.fetch(req, ...args);\n\nexport function createNitroApp() {\n return {\n fetch: handler,\n captureError: (error) => console.error(error),\n hooks: undefined,\n };\n}\n\nexport function initNitroPlugins(app) {\n return app;\n}\n\nexport const app = taserApp;\nexport default app;\n`;\n}\n\nexport function buildNitroMiddlewareHandlerSource(\n routesGenPath: string,\n hostServer?: HostServerInfo | null,\n): string {\n const normalizedPath = normalizeImportPath(routesGenPath);\n const fallback = hostServer\n ? buildHostFallbackCode(normalizeImportPath(hostServer.path), hostServer.type, \"taserApp\")\n : null;\n\n return `// @ts-nocheck\nimport { app as taserApp } from \"${normalizedPath}\";\nimport { toWebRequest } from \"h3\";\n${fallback ? fallback.imports : \"\"}\n\n${fallback ? fallback.setup : \"\"}\n\nexport default defineEventHandler((event) => {\n return taserApp.fetch(toWebRequest(event));\n});\n`;\n}\n\nexport function setupTaserNitro(nitro: any, options: TaserPluginOptions = {}): void {\n const state = nitro.options as unknown as Record<string, unknown>;\n if (state._taserHookRegistered) {\n return;\n }\n state._taserHookRegistered = true;\n\n nitro.hooks.hookOnce(\"build:before\", async () => {\n await applyTaserNitro(nitro, options);\n });\n}\n\nexport async function applyTaserNitro(nitro: any, options: TaserPluginOptions): Promise<void> {\n const cwd = resolve(nitro.options.rootDir || options.cwd || process.cwd());\n const config: ResolvedTaserConfig = await loadConfig(cwd, options.config);\n const routesDir = resolveRoutesDir(config, cwd);\n const serverDir = resolveServerDir(config, cwd);\n const outputDir = resolveOutputDir(config, cwd);\n const routesGenPath = resolve(outputDir, \"routes.gen.ts\");\n\n const executeGeneration = (scaffold = Boolean(nitro.options.dev)) => {\n if (existsSync(routesDir)) {\n const scanResult = scanRoutes({\n routesDir,\n cwd,\n scaffold,\n formatting: config.formatting,\n });\n generateManifest(scanResult, config, cwd);\n }\n };\n\n executeGeneration();\n\n nitro.options.virtual = nitro.options.virtual || {};\n const isStandalone = options.standalone === true;\n\n if (isStandalone) {\n nitro.options.virtual[\"#nitro/virtual/app\"] = () => {\n const currentHost = getHostServer(config, cwd, options);\n return buildNitroStandaloneAppSource(routesGenPath, currentHost);\n };\n nitro.options.virtual[\"#nitro/virtual/routing\"] = () => buildNitroRoutingVirtualSource();\n } else {\n const VIRTUAL_NITRO_HANDLER_ID = \"#taserjs/virtual/nitro-handler\";\n nitro.options.virtual[VIRTUAL_NITRO_HANDLER_ID] = () => {\n const currentHost = getHostServer(config, cwd, options);\n return buildNitroMiddlewareHandlerSource(routesGenPath, currentHost);\n };\n\n nitro.options.handlers = nitro.options.handlers || [];\n nitro.options.handlers.unshift({\n route: \"/**\",\n lazy: false,\n handler: VIRTUAL_NITRO_HANDLER_ID,\n });\n }\n\n let watcher: FSWatcher | undefined;\n if (nitro.options.dev && existsSync(routesDir)) {\n const watchDirs = [routesDir];\n if (existsSync(serverDir) && !watchDirs.includes(serverDir)) {\n watchDirs.push(serverDir);\n }\n watcher = watch(watchDirs, {\n ignoreInitial: true,\n ignored: [/(^|[/\\\\])\\../, /(^|[/\\\\])-/, /node_modules/, /\\.taserjs/],\n });\n\n let timer: NodeJS.Timeout | null = null;\n watcher.on(\"all\", () => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n executeGeneration();\n }, 50);\n });\n }\n\n nitro.hooks.hook(\"close\", async () => {\n await watcher?.close();\n });\n}\n\n/**\n * Taser Nitro module.\n *\n * Can be used as a Nitro module (`modules: [taser()]`) in `nitro.config.ts`,\n * or chained as a rollup plugin.\n */\nexport function taser(options: TaserPluginOptions = {}) {\n const rollupPlugin = taserPlugin.rollup(options);\n return {\n ...rollupPlugin,\n name: \"taserjs:plugin\",\n __taserOptions: options,\n setup: (nitro: any) => setupTaserNitro(nitro, options),\n };\n}\n\nexport default taser;\n"],"mappings":"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"}
1
+ {"version":3,"file":"nitro.js","names":[],"sources":["../src/nitro.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { resolve } from \"pathe\";\nimport {\n generateManifest,\n loadConfig,\n resolveOutputDir,\n resolveRoutesDir,\n resolveServerDir,\n scanRoutes,\n type ResolvedTaserConfig,\n} from \"@taserjs/cli\";\nimport { watch, type FSWatcher } from \"chokidar\";\nimport {\n buildHostFallbackCode,\n getHostServer,\n normalizeImportPath,\n taserPlugin,\n type HostServerInfo,\n type TaserPluginOptions,\n} from \"./index.js\";\n\nexport function buildNitroRoutingVirtualSource(): string {\n return [\n \"export const findRouteRules = () => ({});\",\n \"export const findRoute = () => undefined;\",\n \"export const globalMiddleware = [];\",\n \"export const findRoutedMiddleware = () => [];\",\n ].join(\"\\n\");\n}\n\nexport function buildNitroStandaloneAppSource(\n routesGenPath: string,\n hostServer?: HostServerInfo | null,\n): string {\n const normalizedPath = normalizeImportPath(routesGenPath);\n const fallback = hostServer\n ? buildHostFallbackCode(normalizeImportPath(hostServer.path), hostServer.type, \"taserApp\")\n : null;\n\n return `// @ts-nocheck\nimport { app as taserApp } from \"${normalizedPath}\";\nimport { FastResponse } from \"@taserjs/runtime/serve\";\n${fallback ? fallback.imports : \"\"}\n\nglobalThis.Response = FastResponse;\n\n${fallback ? fallback.setup : \"\"}\n\nexport const handler = (req, ...args) => taserApp.fetch(req, ...args);\n\nexport function createNitroApp() {\n return {\n fetch: handler,\n captureError: (error) => console.error(error),\n hooks: undefined,\n };\n}\n\nexport function initNitroPlugins(app) {\n return app;\n}\n\nexport const app = taserApp;\nexport default app;\n`;\n}\n\nexport function buildNitroMiddlewareHandlerSource(\n routesGenPath: string,\n hostServer?: HostServerInfo | null,\n): string {\n const normalizedPath = normalizeImportPath(routesGenPath);\n const fallback = hostServer\n ? buildHostFallbackCode(normalizeImportPath(hostServer.path), hostServer.type, \"taserApp\")\n : null;\n\n return `// @ts-nocheck\nimport { app as taserApp } from \"${normalizedPath}\";\n${fallback ? fallback.imports : \"\"}\n\n${fallback ? fallback.setup : \"\"}\n\nexport default (event) => {\n return taserApp.fetch(event.req);\n};\n`;\n}\n\nexport function setupTaserNitro(\n nitro: any,\n options: TaserPluginOptions = {},\n): Promise<void> | void {\n const state = nitro.options as unknown as Record<string, unknown>;\n if (state._taserHookRegistered) {\n return;\n }\n state._taserHookRegistered = true;\n\n return applyTaserNitro(nitro, options);\n}\n\nexport async function applyTaserNitro(nitro: any, options: TaserPluginOptions): Promise<void> {\n const cwd = resolve(nitro.options.rootDir || options.cwd || process.cwd());\n const config: ResolvedTaserConfig = await loadConfig(cwd, options.config);\n const routesDir = resolveRoutesDir(config, cwd);\n const serverDir = resolveServerDir(config, cwd);\n const outputDir = resolveOutputDir(config, cwd);\n const routesGenPath = resolve(outputDir, \"routes.gen.ts\");\n\n const executeGeneration = (scaffold = Boolean(nitro.options.dev)) => {\n if (existsSync(routesDir)) {\n const scanResult = scanRoutes({\n routesDir,\n cwd,\n scaffold,\n formatting: config.formatting,\n });\n generateManifest(scanResult, config, cwd);\n }\n };\n\n executeGeneration();\n\n nitro.options.virtual = nitro.options.virtual || {};\n const isStandalone = options.standalone !== false;\n\n const VIRTUAL_NITRO_HANDLER_ID = \"#taserjs/virtual/nitro-handler\";\n\n // Register the virtual middleware/handler used in both standalone and module modes\n nitro.options.virtual[VIRTUAL_NITRO_HANDLER_ID] = () => {\n const currentHost = getHostServer(config, cwd, options);\n return buildNitroMiddlewareHandlerSource(routesGenPath, currentHost);\n };\n\n if (isStandalone) {\n nitro.options.virtual[\"#nitro/virtual/app\"] = () => {\n const currentHost = getHostServer(config, cwd, options);\n return buildNitroStandaloneAppSource(routesGenPath, currentHost);\n };\n nitro.options.virtual[\"#nitro/virtual/routing\"] = () => buildNitroRoutingVirtualSource();\n\n nitro.options.routes = nitro.options.routes || {};\n nitro.options.routes[\"/**\"] = VIRTUAL_NITRO_HANDLER_ID;\n } else {\n nitro.options.handlers = nitro.options.handlers || [];\n nitro.options.handlers.unshift({\n route: \"/**\",\n lazy: false,\n handler: VIRTUAL_NITRO_HANDLER_ID,\n });\n }\n\n if (nitro.routing?.sync) {\n nitro.routing.sync();\n }\n\n let watcher: FSWatcher | undefined;\n if (nitro.options.dev && existsSync(routesDir)) {\n const watchDirs = [routesDir];\n if (existsSync(serverDir) && !watchDirs.includes(serverDir)) {\n watchDirs.push(serverDir);\n }\n watcher = watch(watchDirs, {\n ignoreInitial: true,\n ignored: [/(^|[/\\\\])\\../, /(^|[/\\\\])-/, /node_modules/, /\\.taserjs/],\n });\n\n let timer: NodeJS.Timeout | null = null;\n watcher.on(\"all\", () => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n executeGeneration();\n }, 50);\n });\n }\n\n nitro.hooks.hook(\"close\", async () => {\n await watcher?.close();\n });\n}\n\n/**\n * Taser Nitro module.\n *\n * Can be used as a Nitro module (`modules: [taser()]`) in `nitro.config.ts`,\n * or chained as a rollup plugin.\n */\nexport function taser(options: TaserPluginOptions = {}) {\n const rollupPlugin = taserPlugin.rollup(options);\n return {\n ...rollupPlugin,\n name: \"taserjs:plugin\",\n __taserOptions: options,\n setup: (nitro: any) => setupTaserNitro(nitro, options),\n };\n}\n\nexport default taser;\n"],"mappings":"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"}
package/dist/vite.d.ts CHANGED
@@ -1,7 +1,11 @@
1
- import { HostServerInfo, TaserPluginOptions, detectHostServer, emitServeShim, mountHostFallback, resolveHostFetchHandler } from "./index.js";
1
+ import taserPlugin, { HostServerInfo, TaserPluginOptions, detectFullStack, detectHostServer, emitServeShim, mountHostFallback, resolveHostFetchHandler } from "./index.js";
2
2
  //#region src/vite.d.ts
3
- export declare const taser: (options?: TaserPluginOptions | undefined) => import("unplugin").VitePlugin<any> | import("unplugin").VitePlugin<any>[];
4
- declare const _default: (options?: TaserPluginOptions | undefined) => import("unplugin").VitePlugin<any> | import("unplugin").VitePlugin<any>[];
3
+ export type VitePluginReturn = ReturnType<typeof taserPlugin.vite> & {
4
+ nitro?: {
5
+ setup: (nitro: any) => Promise<void> | void;
6
+ };
7
+ };
8
+ export declare const taser: (options?: TaserPluginOptions) => VitePluginReturn;
5
9
  //#endregion
6
- export { type HostServerInfo, type TaserPluginOptions, _default as default, detectHostServer, emitServeShim, mountHostFallback, resolveHostFetchHandler };
10
+ export { type HostServerInfo, type TaserPluginOptions, taser as default, detectFullStack, detectHostServer, emitServeShim, mountHostFallback, resolveHostFetchHandler };
7
11
  //# sourceMappingURL=vite.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vite.d.ts","names":[],"sources":["../src/vite.ts"],"mappings":";;qBAUa,QAAK,UAAA,sDAAA,qCAAA"}
1
+ {"version":3,"file":"vite.d.ts","names":[],"sources":["../src/vite.ts"],"mappings":";;YAYY,mBAAmB,kBAAkB,YAAY;EAC3D;IACE,QAAQ,eAAe;;;qBAId,QAAQ,UAAU,uBAAuB"}
package/dist/vite.js CHANGED
@@ -1,8 +1,39 @@
1
- import taserPlugin, { detectHostServer, emitServeShim, mountHostFallback, resolveHostFetchHandler } from "./index.js";
1
+ import taserPlugin, { detectFullStack, detectHostServer, emitServeShim, mountHostFallback, resolveHostFetchHandler } from "./index.js";
2
+ import { setupTaserNitro } from "./nitro.js";
2
3
  //#region src/vite.ts
3
- const taser = taserPlugin.vite;
4
- var vite_default = taserPlugin.vite;
4
+ const taser = (options) => {
5
+ let isFrameworkEnvironment = false;
6
+ const rawPlugin = taserPlugin.vite(options);
7
+ const plugin = Array.isArray(rawPlugin) ? rawPlugin[0] : rawPlugin;
8
+ const checkFramework = (cfg) => {
9
+ if (detectFullStack(cfg, true)) isFrameworkEnvironment = true;
10
+ };
11
+ const originalConfig = plugin.config;
12
+ plugin.config = async function(config, env) {
13
+ checkFramework(config);
14
+ if (typeof originalConfig === "function") return originalConfig.call(this, config, env);
15
+ };
16
+ const originalConfigResolved = plugin.configResolved;
17
+ plugin.configResolved = async function(resolvedConfig) {
18
+ checkFramework(resolvedConfig);
19
+ if (typeof originalConfigResolved === "function") return originalConfigResolved.call(this, resolvedConfig);
20
+ };
21
+ const nitroModule = { setup: (nitro) => {
22
+ if (!isFrameworkEnvironment) {
23
+ checkFramework(nitro.options?._viteConfig);
24
+ checkFramework({ plugins: nitro.options?.modules });
25
+ }
26
+ const standalone = options?.standalone !== void 0 ? options.standalone : !isFrameworkEnvironment;
27
+ return setupTaserNitro(nitro, {
28
+ ...options,
29
+ standalone
30
+ });
31
+ } };
32
+ plugin.nitro = nitroModule;
33
+ if (Array.isArray(rawPlugin)) rawPlugin.nitro = nitroModule;
34
+ return rawPlugin;
35
+ };
5
36
  //#endregion
6
- export { vite_default as default, detectHostServer, emitServeShim, mountHostFallback, resolveHostFetchHandler, taser };
37
+ export { taser as default, taser, detectFullStack, detectHostServer, emitServeShim, mountHostFallback, resolveHostFetchHandler };
7
38
 
8
39
  //# sourceMappingURL=vite.js.map
package/dist/vite.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vite.js","names":[],"sources":["../src/vite.ts"],"sourcesContent":["import {\n detectHostServer,\n emitServeShim,\n mountHostFallback,\n resolveHostFetchHandler,\n taserPlugin,\n type HostServerInfo,\n type TaserPluginOptions,\n} from \"./index.js\";\n\nexport const taser = taserPlugin.vite;\nexport default taserPlugin.vite;\nexport {\n detectHostServer,\n emitServeShim,\n mountHostFallback,\n resolveHostFetchHandler,\n type HostServerInfo,\n type TaserPluginOptions,\n};\n"],"mappings":";;AAUA,MAAa,QAAQ,YAAY;AACjC,IAAA,eAAe,YAAY"}
1
+ {"version":3,"file":"vite.js","names":[],"sources":["../src/vite.ts"],"sourcesContent":["import {\n detectFullStack,\n detectHostServer,\n emitServeShim,\n mountHostFallback,\n resolveHostFetchHandler,\n taserPlugin,\n type HostServerInfo,\n type TaserPluginOptions,\n} from \"./index.js\";\nimport { setupTaserNitro } from \"./nitro.js\";\n\nexport type VitePluginReturn = ReturnType<typeof taserPlugin.vite> & {\n nitro?: {\n setup: (nitro: any) => Promise<void> | void;\n };\n};\n\nexport const taser: (options?: TaserPluginOptions) => VitePluginReturn = (\n options?: TaserPluginOptions,\n) => {\n let isFrameworkEnvironment = false;\n const rawPlugin = taserPlugin.vite(options);\n const plugin = (Array.isArray(rawPlugin) ? rawPlugin[0] : rawPlugin) as any;\n\n const checkFramework = (cfg?: any) => {\n if (detectFullStack(cfg, true)) {\n isFrameworkEnvironment = true;\n }\n };\n\n const originalConfig = plugin.config;\n plugin.config = async function (this: any, config: any, env: any) {\n checkFramework(config);\n if (typeof originalConfig === \"function\") {\n return originalConfig.call(this, config, env);\n }\n };\n\n const originalConfigResolved = plugin.configResolved;\n plugin.configResolved = async function (this: any, resolvedConfig: any) {\n checkFramework(resolvedConfig);\n if (typeof originalConfigResolved === \"function\") {\n return originalConfigResolved.call(this, resolvedConfig);\n }\n };\n\n const nitroModule = {\n setup: (nitro: any) => {\n if (!isFrameworkEnvironment) {\n checkFramework(nitro.options?._viteConfig);\n checkFramework({ plugins: nitro.options?.modules });\n }\n const standalone =\n options?.standalone !== undefined ? options.standalone : !isFrameworkEnvironment;\n\n return setupTaserNitro(nitro, {\n ...options,\n standalone,\n });\n },\n };\n\n plugin.nitro = nitroModule;\n if (Array.isArray(rawPlugin)) {\n (rawPlugin as any).nitro = nitroModule;\n }\n\n return rawPlugin as VitePluginReturn;\n};\n\nexport default taser;\nexport {\n detectFullStack,\n detectHostServer,\n emitServeShim,\n mountHostFallback,\n resolveHostFetchHandler,\n type HostServerInfo,\n type TaserPluginOptions,\n};\n"],"mappings":";;;AAkBA,MAAa,SACX,YACG;CACH,IAAI,yBAAyB;CAC7B,MAAM,YAAY,YAAY,KAAK,OAAO;CAC1C,MAAM,SAAU,MAAM,QAAQ,SAAS,IAAI,UAAU,KAAK;CAE1D,MAAM,kBAAkB,QAAc;EACpC,IAAI,gBAAgB,KAAK,IAAI,GAC3B,yBAAyB;CAE7B;CAEA,MAAM,iBAAiB,OAAO;CAC9B,OAAO,SAAS,eAA2B,QAAa,KAAU;EAChE,eAAe,MAAM;EACrB,IAAI,OAAO,mBAAmB,YAC5B,OAAO,eAAe,KAAK,MAAM,QAAQ,GAAG;CAEhD;CAEA,MAAM,yBAAyB,OAAO;CACtC,OAAO,iBAAiB,eAA2B,gBAAqB;EACtE,eAAe,cAAc;EAC7B,IAAI,OAAO,2BAA2B,YACpC,OAAO,uBAAuB,KAAK,MAAM,cAAc;CAE3D;CAEA,MAAM,cAAc,EAClB,QAAQ,UAAe;EACrB,IAAI,CAAC,wBAAwB;GAC3B,eAAe,MAAM,SAAS,WAAW;GACzC,eAAe,EAAE,SAAS,MAAM,SAAS,QAAQ,CAAC;EACpD;EACA,MAAM,aACJ,SAAS,eAAe,KAAA,IAAY,QAAQ,aAAa,CAAC;EAE5D,OAAO,gBAAgB,OAAO;GAC5B,GAAG;GACH;EACF,CAAC;CACH,EACF;CAEA,OAAO,QAAQ;CACf,IAAI,MAAM,QAAQ,SAAS,GACzB,UAAmB,QAAQ;CAG7B,OAAO;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taserjs/plugin",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Universal bundler plugin for Taser.js",
5
5
  "keywords": [
6
6
  "bundler",
@@ -131,7 +131,7 @@
131
131
  "pathe": "^2.0.3",
132
132
  "srvx": "^1.0.4",
133
133
  "unplugin": "^2.3.11",
134
- "@taserjs/cli": "^0.2.0"
134
+ "@taserjs/cli": "^0.2.1"
135
135
  },
136
136
  "devDependencies": {
137
137
  "publint": "^0.3.22",
@@ -140,7 +140,7 @@
140
140
  "typescript": "^5.9.3",
141
141
  "vite": "^8.2.2",
142
142
  "vitest": "^4.1.10",
143
- "create-taserjs": "0.2.0"
143
+ "create-taserjs": "0.2.1"
144
144
  },
145
145
  "engines": {
146
146
  "node": ">=20.19"
package/src/index.ts CHANGED
@@ -82,9 +82,12 @@ const FULLSTACK_PLUGIN_PATTERNS = [
82
82
  "remix",
83
83
  "astro",
84
84
  "sveltekit",
85
+ "nuxt",
86
+ "solid-start",
87
+ "analog",
85
88
  ];
86
89
 
87
- function isFullStackPluginName(name: string): boolean {
90
+ export function isFullStackPluginName(name: string): boolean {
88
91
  const lower = name.toLowerCase();
89
92
  for (const pattern of FULLSTACK_PLUGIN_PATTERNS) {
90
93
  if (lower.includes(pattern)) {
@@ -97,15 +100,17 @@ function isFullStackPluginName(name: string): boolean {
97
100
  return false;
98
101
  }
99
102
 
100
- function detectFullStack(viteConfig: any): boolean {
103
+ export function detectFullStack(viteConfig: any, excludeNitro = false): boolean {
101
104
  if (!viteConfig) return false;
102
- if (viteConfig.nitro) return true;
105
+ if (!excludeNitro && viteConfig.nitro) return true;
103
106
  const plugins = viteConfig.plugins;
104
107
  if (!plugins) return false;
105
108
  const flat = Array.isArray(plugins) ? plugins.flat(Infinity) : [plugins];
106
109
  return flat.some((p: any) => {
107
110
  const name = p?.name;
108
- return typeof name === "string" && isFullStackPluginName(name);
111
+ if (typeof name !== "string") return false;
112
+ if (excludeNitro && name.toLowerCase().includes("nitro")) return false;
113
+ return isFullStackPluginName(name);
109
114
  });
110
115
  }
111
116
 
@@ -213,7 +218,7 @@ export function buildHostFallbackCode(
213
218
  appVarName: string = "app",
214
219
  ): { imports: string; setup: string } {
215
220
  const isNode = type === "node";
216
- const imports = `${isNode ? 'import { toFetchHandler } from "srvx/node";\n' : ""}import hostServerEntry from "${hostImportPath}";`;
221
+ const imports = `${isNode ? 'import { toFetchHandler } from "@taserjs/runtime/serve/node";\n' : ""}import hostServerEntry from "${hostImportPath}";`;
217
222
 
218
223
  const setup = isNode
219
224
  ? `const rawHost = hostServerEntry?.default ?? hostServerEntry;
@@ -247,9 +252,8 @@ export function emitServeShim(
247
252
 
248
253
  const fallbackCode = buildHostFallbackCode(hostImportPath, hostServer.type, "app");
249
254
  code = `// @ts-nocheck
250
- import { FastResponse } from "srvx";
255
+ import { FastResponse, serve } from "@taserjs/runtime/serve";
251
256
  globalThis.Response = FastResponse;
252
- import { serve } from "srvx/node";
253
257
  ${fallbackCode.imports}
254
258
  import { app } from "${normalizedRoutesPath}";
255
259
 
@@ -260,9 +264,8 @@ serve(app);
260
264
  `;
261
265
  } else {
262
266
  code = `// @ts-nocheck
263
- import { FastResponse } from "srvx";
267
+ import { FastResponse, serve } from "@taserjs/runtime/serve";
264
268
  globalThis.Response = FastResponse;
265
- import { serve } from "srvx/node";
266
269
  import { app } from "${normalizedRoutesPath}";
267
270
 
268
271
  serve(app);
@@ -416,7 +419,7 @@ export const taserPlugin = createUnplugin((options: TaserPluginOptions | undefin
416
419
  build: {
417
420
  ssr: serveShimPath,
418
421
  rollupOptions: {
419
- external: ["srvx", "srvx/node", "@taserjs/runtime", "hono"],
422
+ external: ["@taserjs/runtime", /^@taserjs\/runtime\/.*/],
420
423
  output: {
421
424
  entryFileNames: "serve.mjs",
422
425
  },
package/src/nitro.ts CHANGED
@@ -39,7 +39,7 @@ export function buildNitroStandaloneAppSource(
39
39
 
40
40
  return `// @ts-nocheck
41
41
  import { app as taserApp } from "${normalizedPath}";
42
- import { FastResponse } from "srvx";
42
+ import { FastResponse } from "@taserjs/runtime/serve";
43
43
  ${fallback ? fallback.imports : ""}
44
44
 
45
45
  globalThis.Response = FastResponse;
@@ -76,27 +76,27 @@ export function buildNitroMiddlewareHandlerSource(
76
76
 
77
77
  return `// @ts-nocheck
78
78
  import { app as taserApp } from "${normalizedPath}";
79
- import { toWebRequest } from "h3";
80
79
  ${fallback ? fallback.imports : ""}
81
80
 
82
81
  ${fallback ? fallback.setup : ""}
83
82
 
84
- export default defineEventHandler((event) => {
85
- return taserApp.fetch(toWebRequest(event));
86
- });
83
+ export default (event) => {
84
+ return taserApp.fetch(event.req);
85
+ };
87
86
  `;
88
87
  }
89
88
 
90
- export function setupTaserNitro(nitro: any, options: TaserPluginOptions = {}): void {
89
+ export function setupTaserNitro(
90
+ nitro: any,
91
+ options: TaserPluginOptions = {},
92
+ ): Promise<void> | void {
91
93
  const state = nitro.options as unknown as Record<string, unknown>;
92
94
  if (state._taserHookRegistered) {
93
95
  return;
94
96
  }
95
97
  state._taserHookRegistered = true;
96
98
 
97
- nitro.hooks.hookOnce("build:before", async () => {
98
- await applyTaserNitro(nitro, options);
99
- });
99
+ return applyTaserNitro(nitro, options);
100
100
  }
101
101
 
102
102
  export async function applyTaserNitro(nitro: any, options: TaserPluginOptions): Promise<void> {
@@ -122,7 +122,15 @@ export async function applyTaserNitro(nitro: any, options: TaserPluginOptions):
122
122
  executeGeneration();
123
123
 
124
124
  nitro.options.virtual = nitro.options.virtual || {};
125
- const isStandalone = options.standalone === true;
125
+ const isStandalone = options.standalone !== false;
126
+
127
+ const VIRTUAL_NITRO_HANDLER_ID = "#taserjs/virtual/nitro-handler";
128
+
129
+ // Register the virtual middleware/handler used in both standalone and module modes
130
+ nitro.options.virtual[VIRTUAL_NITRO_HANDLER_ID] = () => {
131
+ const currentHost = getHostServer(config, cwd, options);
132
+ return buildNitroMiddlewareHandlerSource(routesGenPath, currentHost);
133
+ };
126
134
 
127
135
  if (isStandalone) {
128
136
  nitro.options.virtual["#nitro/virtual/app"] = () => {
@@ -130,13 +138,10 @@ export async function applyTaserNitro(nitro: any, options: TaserPluginOptions):
130
138
  return buildNitroStandaloneAppSource(routesGenPath, currentHost);
131
139
  };
132
140
  nitro.options.virtual["#nitro/virtual/routing"] = () => buildNitroRoutingVirtualSource();
133
- } else {
134
- const VIRTUAL_NITRO_HANDLER_ID = "#taserjs/virtual/nitro-handler";
135
- nitro.options.virtual[VIRTUAL_NITRO_HANDLER_ID] = () => {
136
- const currentHost = getHostServer(config, cwd, options);
137
- return buildNitroMiddlewareHandlerSource(routesGenPath, currentHost);
138
- };
139
141
 
142
+ nitro.options.routes = nitro.options.routes || {};
143
+ nitro.options.routes["/**"] = VIRTUAL_NITRO_HANDLER_ID;
144
+ } else {
140
145
  nitro.options.handlers = nitro.options.handlers || [];
141
146
  nitro.options.handlers.unshift({
142
147
  route: "/**",
@@ -145,6 +150,10 @@ export async function applyTaserNitro(nitro: any, options: TaserPluginOptions):
145
150
  });
146
151
  }
147
152
 
153
+ if (nitro.routing?.sync) {
154
+ nitro.routing.sync();
155
+ }
156
+
148
157
  let watcher: FSWatcher | undefined;
149
158
  if (nitro.options.dev && existsSync(routesDir)) {
150
159
  const watchDirs = [routesDir];
package/src/vite.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ detectFullStack,
2
3
  detectHostServer,
3
4
  emitServeShim,
4
5
  mountHostFallback,
@@ -7,10 +8,70 @@ import {
7
8
  type HostServerInfo,
8
9
  type TaserPluginOptions,
9
10
  } from "./index.js";
11
+ import { setupTaserNitro } from "./nitro.js";
10
12
 
11
- export const taser = taserPlugin.vite;
12
- export default taserPlugin.vite;
13
+ export type VitePluginReturn = ReturnType<typeof taserPlugin.vite> & {
14
+ nitro?: {
15
+ setup: (nitro: any) => Promise<void> | void;
16
+ };
17
+ };
18
+
19
+ export const taser: (options?: TaserPluginOptions) => VitePluginReturn = (
20
+ options?: TaserPluginOptions,
21
+ ) => {
22
+ let isFrameworkEnvironment = false;
23
+ const rawPlugin = taserPlugin.vite(options);
24
+ const plugin = (Array.isArray(rawPlugin) ? rawPlugin[0] : rawPlugin) as any;
25
+
26
+ const checkFramework = (cfg?: any) => {
27
+ if (detectFullStack(cfg, true)) {
28
+ isFrameworkEnvironment = true;
29
+ }
30
+ };
31
+
32
+ const originalConfig = plugin.config;
33
+ plugin.config = async function (this: any, config: any, env: any) {
34
+ checkFramework(config);
35
+ if (typeof originalConfig === "function") {
36
+ return originalConfig.call(this, config, env);
37
+ }
38
+ };
39
+
40
+ const originalConfigResolved = plugin.configResolved;
41
+ plugin.configResolved = async function (this: any, resolvedConfig: any) {
42
+ checkFramework(resolvedConfig);
43
+ if (typeof originalConfigResolved === "function") {
44
+ return originalConfigResolved.call(this, resolvedConfig);
45
+ }
46
+ };
47
+
48
+ const nitroModule = {
49
+ setup: (nitro: any) => {
50
+ if (!isFrameworkEnvironment) {
51
+ checkFramework(nitro.options?._viteConfig);
52
+ checkFramework({ plugins: nitro.options?.modules });
53
+ }
54
+ const standalone =
55
+ options?.standalone !== undefined ? options.standalone : !isFrameworkEnvironment;
56
+
57
+ return setupTaserNitro(nitro, {
58
+ ...options,
59
+ standalone,
60
+ });
61
+ },
62
+ };
63
+
64
+ plugin.nitro = nitroModule;
65
+ if (Array.isArray(rawPlugin)) {
66
+ (rawPlugin as any).nitro = nitroModule;
67
+ }
68
+
69
+ return rawPlugin as VitePluginReturn;
70
+ };
71
+
72
+ export default taser;
13
73
  export {
74
+ detectFullStack,
14
75
  detectHostServer,
15
76
  emitServeShim,
16
77
  mountHostFallback,