{"version":3,"file":"index.mjs","names":[],"sources":["../src/core-plugin.ts","../src/virtual-modules.ts","../src/dev-server.ts","../src/warm.ts","../src/module-discovery.ts","../src/hmr-plugin.ts","../src/devtools-flag-plugin.ts","../src/babel-strip-devtools.ts","../src/devtools-strip-plugin.ts","../src/typegen-plugin.ts","../src/env-watch-plugin.ts","../src/index.ts"],"sourcesContent":["/**\n * Core Vite plugin for KickJS — configures the Vite server for backend\n * framework use: custom app type, SSR environment, and Node.js target.\n *\n * This plugin runs first in the array and sets up the environment that\n * the other sub-plugins (dev-server, virtual-modules, hmr) depend on.\n *\n * @module @forinda/kickjs-vite/core-plugin\n */\n\nimport type { Plugin } from 'vite'\nimport type { PluginContext } from './types'\n\n/**\n * Creates the core configuration plugin.\n *\n * Responsibilities:\n * - Sets `appType: 'custom'` so Vite doesn't serve index.html\n * - Configures the SSR environment for Node.js backend code\n * - Prevents Vite from clearing the terminal (KickJS logs route tables on startup)\n * - Externalizes Node.js built-ins and framework packages from the bundle\n *\n * @param ctx - Shared plugin context (entry file, root directory)\n * @returns Vite plugin\n */\nexport function kickjsCorePlugin(ctx: PluginContext): Plugin {\n  return {\n    name: 'kickjs:core',\n\n    /**\n     * Vite config hook — runs before config is resolved.\n     * Sets the foundational configuration for a backend Node.js framework.\n     */\n    config(userConfig, _env) {\n      // Respect explicit server.port from user's vite.config.ts.\n      // Only inject .env PORT when the user hasn't set one.\n      const explicitPort = userConfig.server?.port\n      const envPort = process.env.PORT ? parseInt(process.env.PORT, 10) : undefined\n      const port = explicitPort ?? envPort ?? 3000\n\n      return {\n        server: {\n          port,\n        },\n\n        // 'custom' tells Vite this is not a SPA or MPA — we handle all requests\n        appType: 'custom' as const,\n\n        // Don't clear the terminal — KickJS logs route tables on startup\n        clearScreen: false,\n\n        // SSR environment configuration for backend code\n        environments: {\n          ssr: {\n            // Warm up the entry file for faster first request\n            dev: {\n              warmup: [ctx.entry],\n            },\n          },\n        },\n\n        // Disable dep optimization discovery — KickJS is SSR-only, not a client app\n        optimizeDeps: {\n          noDiscovery: true,\n        },\n\n        // SSR-specific settings\n        ssr: {\n          // Externalize Node.js built-ins and framework packages\n          // These should NOT be bundled by Vite — they run natively in Node\n          external: ['@forinda/kickjs', 'express', 'reflect-metadata'],\n        },\n      }\n    },\n  }\n}\n","/**\n * Virtual module plugin for KickJS — generates the `virtual:kickjs/app`\n * module that bridges Vite and the KickJS application.\n *\n * Virtual modules are Vite's mechanism for generating code at build/serve\n * time that doesn't exist on disk. When the dev server calls\n * `ssrLoadModule('virtual:kickjs/app')`, this plugin generates the code\n * that imports and re-exports the user's application entry.\n *\n * In the future, this will also support auto-discovery of `@Module` classes\n * (Step 4 in v3/plan.md) and container manifest generation.\n *\n * @see https://vite.dev/guide/api-plugin.html#virtual-modules-convention\n *\n * @module @forinda/kickjs-vite/virtual-modules\n */\n\nimport { normalizePath, type Plugin } from 'vite'\nimport type { PluginContext } from './types'\n\n/** Prefix for resolved virtual module IDs (Vite convention) */\nconst VIRTUAL_PREFIX = '\\0'\n\n/** Virtual module ID for the KickJS application entry */\nconst VIRTUAL_APP = 'virtual:kickjs/app'\n\n/** Resolved virtual module ID (with \\0 prefix to mark as virtual) */\nconst RESOLVED_APP = `${VIRTUAL_PREFIX}${VIRTUAL_APP}`\n\n/**\n * Creates the virtual modules plugin.\n *\n * Currently provides one virtual module:\n * - `virtual:kickjs/app` — re-exports the user's application entry\n *\n * The dev server plugin imports this on every request via `ssrLoadModule()`.\n * When any source file changes, Vite invalidates the module graph and the\n * next import returns fresh code — this is how server-side HMR works.\n *\n * Future virtual modules (planned for Steps 4-5):\n * - `virtual:kickjs/modules` — auto-discovered `@Module` classes\n * - `virtual:kickjs/manifest` — container metadata for DevTools\n *\n * @param ctx - Shared plugin context (entry file, root directory)\n * @returns Vite plugin\n */\nexport function kickjsVirtualModulesPlugin(ctx: PluginContext): Plugin {\n  return {\n    name: 'kickjs:virtual-modules',\n\n    /**\n     * Resolve virtual module IDs.\n     * Tells Vite that `virtual:kickjs/app` is a valid module ID\n     * and maps it to our internal resolved ID.\n     */\n    resolveId(id: string) {\n      if (id === VIRTUAL_APP) {\n        return RESOLVED_APP\n      }\n    },\n\n    /**\n     * Load virtual module content.\n     * Generates the code for `virtual:kickjs/app` that imports the user's\n     * entry file and re-exports the Express app.\n     *\n     * The generated code:\n     * 1. Imports the user's entry file (which calls `bootstrap()`)\n     * 2. Re-exports everything from it (including the `app` export)\n     *\n     * The dev server plugin then does:\n     *   `const { app } = await ssrLoadModule('virtual:kickjs/app')`\n     * and uses `app.handle(req, res, next)` to route requests through Express.\n     */\n    load(id: string) {\n      if (id !== RESOLVED_APP) return\n\n      // Generate code that imports and re-exports the user's entry\n      // The entry file should: export const app = bootstrap({ modules: [...] })\n      const normalizedEntry = normalizePath(ctx.entry)\n      return [\n        `// Auto-generated by @forinda/kickjs-vite`,\n        `// Imports the user's application entry and re-exports the Express app.`,\n        `// Vite's module graph tracks this — file changes trigger re-evaluation.`,\n        `export * from '${normalizedEntry}'`,\n      ].join('\\n')\n    },\n  }\n}\n\nexport { VIRTUAL_APP, RESOLVED_APP }\n","/**\n * Dev server plugin for KickJS — mounts the Express application on Vite's\n * HTTP server using the `configureServer` hook.\n *\n * ## Architecture\n *\n * In development, Vite owns the HTTP port and creates the `http.Server`.\n * This plugin:\n *\n * 1. **Stores `viteServer.httpServer` on `globalThis`** so KickJS adapters\n *    (WsAdapter, Socket.IO, GraphQL subscriptions) can attach to the real\n *    server via `server.on('upgrade', ...)`. This is the key to supporting\n *    any library that needs the raw `http.Server`.\n *\n * 2. **Registers a post-middleware** that loads the KickJS app through\n *    Vite's SSR transform pipeline on every request. When source files\n *    change, Vite invalidates the module graph and the next request\n *    gets fresh code — no process restart needed.\n *\n * 3. **Stores the Vite server reference** on `globalThis` so SSR\n *    renderers can use `createViteRuntime()`.\n *\n * ## Why NOT middlewareMode\n *\n * The initial KickJS Vite plugin attempt used `middlewareMode: true`, which\n * makes `viteServer.httpServer = null`. This broke WsAdapter and any library\n * needing `server.on('upgrade', ...)`. By letting Vite create the server,\n * `httpServer` is the real `http.Server` — adapters attach to it seamlessly.\n *\n * ## Request Flow\n *\n * ```\n * HTTP Request → Vite static middleware (HMR, assets)\n *   → If Vite handles it → done\n *   → If not → KickJS post-middleware\n *     → ssrLoadModule('virtual:kickjs/app') → fresh Express app\n *     → Express handles request (routes, middleware, controllers)\n * ```\n *\n * @see v3/architecture.md Section 2.6 for the httpServer piping design\n * @see bench-mark/react-router-analysis.md for the pattern origin\n *\n * @module @forinda/kickjs-vite/dev-server\n */\n\nimport type { Plugin, ViteDevServer } from 'vite'\nimport type { PluginContext } from './types'\nimport { VIRTUAL_APP } from './virtual-modules'\n\n/**\n * Declare the globalThis properties used for cross-module communication.\n * These persist across Vite's `ssrLoadModule()` re-evaluations.\n *\n * `__kickjs_httpServer` uses the same `HttpServer` type that Vite uses\n * internally (union of http.Server | https.Server | Http2SecureServer).\n * KickJS adapters receive it as `http.Server` via AdapterContext — the\n * cast is safe because Express only works with HTTP/1.1 servers.\n */\ndeclare global {\n  // eslint-disable-next-line no-var\n  var __kickjs_httpServer: any\n  // eslint-disable-next-line no-var\n  var __kickjs_viteServer: ViteDevServer | null\n}\n\n/**\n * Creates the dev server plugin.\n *\n * This is the critical integration point between Vite and KickJS:\n * - Pipes `viteServer.httpServer` to adapters via `globalThis`\n * - Loads fresh Express app on every request via `ssrLoadModule()`\n * - Fixes stack traces for SSR errors with `ssrFixStacktrace()`\n *\n * @param ctx - Shared plugin context (entry file, root directory)\n * @returns Vite plugin\n */\nexport function kickjsDevServerPlugin(_ctx: PluginContext): Plugin {\n  return {\n    name: 'kickjs:dev-server',\n\n    /**\n     * Configure the Vite dev server.\n     *\n     * The `configureServer` hook runs after Vite creates the HTTP server.\n     * We use it to:\n     * 1. Store the httpServer on globalThis (for WsAdapter, Socket.IO, etc.)\n     * 2. Store the Vite server reference (for SSR rendering)\n     * 3. Return a post-middleware that loads the KickJS app on each request\n     *\n     * Returning a function from `configureServer` registers it as a\n     * **post-middleware** — it runs AFTER Vite's own middleware (static\n     * files, HMR client, etc.), so Vite-handled requests never hit Express.\n     */\n    configureServer(viteServer: ViteDevServer) {\n      // ━━━ Store the REAL http.Server on globalThis ━━━\n      // This is the key to supporting Socket.IO, WsAdapter, GraphQL WS,\n      // and any library that needs `server.on('upgrade', ...)`.\n      //\n      // Application.start() detects this and skips creating its own server:\n      //   if (globalThis.__kickjs_httpServer) → reuse Vite's server\n      //   else → create own http.Server (production mode)\n      //\n      // Adapters receive the server in afterStart({ server }) — same API\n      // in both dev and prod. Zero adapter code changes needed.\n      globalThis.__kickjs_httpServer = viteServer.httpServer ?? null\n      globalThis.__kickjs_viteServer = viteServer\n\n      // ━━━ Eagerly bootstrap the app once the server is listening ━━━\n      // The post-middleware below only evaluates the entry on the FIRST\n      // request (lazy SSR). That means `bootstrap()`, adapter\n      // `afterStart`, and the app's startup logs don't run until someone\n      // hits the URL — the app looks \"not started\" until then. Warm the\n      // module once the HTTP server is listening so startup behaves like\n      // `node`/`tsx` (logs + adapters + the in-dev shutdown hook ready\n      // immediately). Errors surface with a fixed stacktrace.\n      const warm = () => {\n        viteServer.ssrLoadModule(VIRTUAL_APP).catch((err: unknown) => {\n          if (err instanceof Error) viteServer.ssrFixStacktrace(err)\n          viteServer.config.logger.error(\n            `[kickjs] failed to bootstrap app on startup: ${\n              err instanceof Error ? err.message : String(err)\n            }`,\n          )\n        })\n      }\n      const httpServer = viteServer.httpServer\n      if (httpServer) {\n        if (httpServer.listening) warm()\n        else httpServer.once('listening', warm)\n      }\n\n      // Return post-middleware — runs after Vite's static/HMR middleware\n      return () => {\n        viteServer.middlewares.use(async (req, res, next) => {\n          try {\n            // Load the KickJS app through Vite's SSR transform pipeline.\n            // On first request: evaluates the entry file and all imports.\n            // On subsequent requests: returns cached modules (or re-evaluates\n            // if source files changed since last request).\n            //\n            // This is the same pattern React Router and TanStack Start use.\n            const mod = await viteServer.ssrLoadModule(VIRTUAL_APP)\n\n            // The entry file exports: export const app = bootstrap({ modules })\n            // `app` is the configured Express instance (not yet listening).\n            const expressApp = mod.app\n\n            if (!expressApp?.handle) {\n              // Entry file doesn't export an Express app — fall through to Vite's 404\n              return next()\n            }\n\n            // Let Express handle the request.\n            // If Express doesn't match any route, it calls next() and\n            // Vite's default 404 handler takes over.\n            expressApp.handle(req, res, (err?: any) => {\n              if (err) {\n                // Fix stack traces to point to original source (not compiled)\n                if (err instanceof Error) {\n                  viteServer.ssrFixStacktrace(err)\n                }\n                return next(err)\n              }\n              next()\n            })\n          } catch (err) {\n            // SSR load/evaluation error (syntax error, missing import, etc.)\n            if (err instanceof Error) {\n              viteServer.ssrFixStacktrace(err)\n            }\n            next(err)\n          }\n        })\n      }\n    },\n  }\n}\n","/**\n * Eager app re-warm after an invalidation.\n *\n * The dev server evaluates `virtual:kickjs/app` lazily — after a save\n * invalidates it, re-evaluation waits for the NEXT HTTP request. A\n * broken file (syntax error, failed import, boot throw) was therefore\n * silent until something hit the server, even though startup surfaced\n * the same class of error eagerly. Re-warming right after invalidation\n * pushes transform/bootstrap errors into the dev console the moment\n * the save lands.\n *\n * Errors are logged (with fixed stacktraces) but never thrown — the\n * dev loop must survive a mid-edit broken state; the next successful\n * save heals it.\n */\nimport type { ViteDevServer } from 'vite'\n\nimport { VIRTUAL_APP } from './virtual-modules'\n\nexport function rewarmApp(server: ViteDevServer, reason: string): void {\n  server.ssrLoadModule(VIRTUAL_APP).catch((err: unknown) => {\n    if (err instanceof Error) server.ssrFixStacktrace(err)\n    server.config.logger.error(\n      `[kickjs] app failed to reload after ${reason}: ${\n        err instanceof Error ? err.message : String(err)\n      }`,\n      { timestamp: true },\n    )\n  })\n}\n","/**\n * Module discovery plugin for KickJS — automatically detects `@Module` classes\n * by scanning source files during Vite's `transform()` hook.\n *\n * ## How It Works\n *\n * 1. Vite calls `transform(code, id)` for every file it processes\n * 2. This plugin checks if the file matches `*.module.ts` (or `.js`)\n * 3. If the file contains a class exported with `@Module` or extends `AppModule`,\n *    it extracts the class name and records the file path\n * 4. The virtual module `virtual:kickjs/app` is invalidated so the next request\n *    picks up the newly discovered module\n *\n * ## Why This Matters\n *\n * Without auto-discovery, users must manually maintain a barrel file\n * (`src/modules/index.ts`) that imports and re-exports all modules.\n * When `kick g module` creates a new module, it has to edit this barrel.\n * With auto-discovery, modules are detected automatically — no barrel needed.\n *\n * ## Interaction with HMR\n *\n * When a module file is added, renamed, or deleted:\n * - `handleHotUpdate()` detects the change\n * - The virtual module is invalidated\n * - The next `ssrLoadModule()` call regenerates the virtual module\n *   with the updated module list\n *\n * @module @forinda/kickjs-vite/module-discovery\n */\n\nimport type { Plugin, ViteDevServer } from 'vite'\nimport type { PluginContext } from './types'\nimport { RESOLVED_APP } from './virtual-modules'\nimport { rewarmApp } from './warm'\n\n/** Regex to detect exported module classes in source files */\nconst MODULE_CLASS_REGEX =\n  /export\\s+(?:default\\s+)?class\\s+(\\w+(?:Module))\\s*(?:extends|implements|{)/\n\n/** File extensions to scan for modules */\nconst MODULE_FILE_PATTERN = /\\.module\\.[tj]sx?$/\n\n/**\n * Discovered module entry — maps a file path to its exported class name.\n *\n * @example\n * ```\n * {\n *   filePath: '/src/modules/users/user.module.ts',\n *   className: 'UserModule'\n * }\n * ```\n */\nexport interface DiscoveredModule {\n  /** Absolute file path */\n  filePath: string\n  /** Exported class name (e.g., 'UserModule') */\n  className: string\n}\n\n/**\n * Creates the module auto-discovery plugin.\n *\n * Scans `*.module.ts` files during Vite's transform phase to build a\n * registry of `@Module` classes. The registry is used by the virtual\n * modules plugin to generate auto-imports.\n *\n * @param ctx - Shared plugin context\n * @returns Vite plugin\n */\nexport function kickjsModuleDiscoveryPlugin(ctx: PluginContext): Plugin {\n  /**\n   * Registry of discovered modules.\n   * Keyed by absolute file path to handle renames and deletions.\n   * Stored on the plugin context so the virtual modules plugin can read it.\n   */\n  const discovered = new Map<string, DiscoveredModule>()\n  let server: ViteDevServer | null = null\n\n  // Expose discovered modules on the context for virtual-modules plugin\n  ;(ctx as any).discoveredModules = discovered\n\n  return {\n    name: 'kickjs:module-discovery',\n\n    configureServer(viteServer) {\n      server = viteServer\n\n      // Watch for new/deleted files in the modules directory\n      viteServer.watcher.on('add', (filePath) => {\n        if (MODULE_FILE_PATTERN.test(filePath)) {\n          // File added — it will be processed in transform() when first imported.\n          // Invalidate virtual module so it picks up the new file on next request.\n          invalidateVirtualApp(viteServer)\n        }\n      })\n\n      viteServer.watcher.on('unlink', (filePath) => {\n        if (discovered.has(filePath)) {\n          discovered.delete(filePath)\n          invalidateVirtualApp(viteServer)\n        }\n      })\n    },\n\n    /**\n     * Transform hook — called for every file Vite processes.\n     *\n     * We don't actually transform the code (return null), but we use this\n     * hook to observe which files contain module classes. This is cheaper\n     * than AST parsing — a regex match on the source is sufficient because\n     * module files follow a consistent naming pattern (`*.module.ts`).\n     */\n    transform(code: string, id: string) {\n      // Only scan files matching the module pattern\n      if (!MODULE_FILE_PATTERN.test(id)) return null\n      // Skip node_modules\n      if (id.includes('node_modules')) return null\n\n      const match = code.match(MODULE_CLASS_REGEX)\n      if (match) {\n        const className = match[1]\n        const wasNew = !discovered.has(id)\n        discovered.set(id, { filePath: id, className })\n\n        if (wasNew && server) {\n          // New module discovered — invalidate virtual module\n          invalidateVirtualApp(server)\n        }\n      } else if (discovered.has(id)) {\n        // File no longer exports a module class (user removed it)\n        discovered.delete(id)\n        if (server) {\n          invalidateVirtualApp(server)\n        }\n      }\n\n      // Return null — we don't transform the code, just observe it\n      return null\n    },\n\n    /**\n     * HMR hook — called when a file changes.\n     *\n     * If a module file changes, we re-scan it and invalidate the virtual\n     * module so the next request picks up the changes.\n     */\n    handleHotUpdate({ file, server: viteServer }) {\n      if (!MODULE_FILE_PATTERN.test(file)) return\n\n      // The file will be re-processed in transform() on next import.\n      // Invalidate the virtual module so it regenerates with fresh imports.\n      invalidateVirtualApp(viteServer)\n    },\n  }\n}\n\n/**\n * Invalidate the virtual:kickjs/app module in Vite's module graph.\n * This forces the next `ssrLoadModule()` call to re-evaluate the\n * virtual module, picking up any new/removed modules.\n */\nfunction invalidateVirtualApp(server: ViteDevServer): void {\n  const mod = server.moduleGraph.getModuleById(RESOLVED_APP)\n  if (mod) {\n    server.moduleGraph.invalidateModule(mod)\n  }\n  // Re-warm immediately so a broken module file surfaces its error on\n  // save instead of on the next HTTP request (see warm.ts).\n  rewarmApp(server, 'module discovery change')\n}\n\n/**\n * Get the current list of discovered modules.\n * Used by the virtual modules plugin to generate auto-imports.\n */\nexport function getDiscoveredModules(ctx: PluginContext): DiscoveredModule[] {\n  const map = (ctx as any).discoveredModules as Map<string, DiscoveredModule> | undefined\n  return map ? [...map.values()] : []\n}\n","/**\n * HMR plugin for KickJS — selective container invalidation when source\n * files change, with debounced batching for bulk operations.\n *\n * ## How It Works\n *\n * 1. During `transform()`, the plugin scans for decorator patterns\n *    (`@Service`, `@Controller`, etc.) and maps file paths to DI token names\n * 2. When a file changes (`handleHotUpdate()`), the plugin:\n *    - Looks up which DI tokens are defined in that file\n *    - Calls `container.invalidate(token)` for each (which walks the dep graph)\n *    - Invalidates the virtual module so `ssrLoadModule()` returns fresh code\n *    - Sends a custom HMR event (`kickjs:hmr`) so DevTools/Swagger can react\n * 3. Changes are **debounced** (150ms) so `kick g module` creating 10+ files\n *    emits ONE invalidation batch, not 10 separate events\n *\n * ## Interaction with Reactive Container\n *\n * `container.invalidate(token)` (from Step 3) does:\n * - Clears the cached instance for that token\n * - Walks the dependency graph to find dependents\n * - Invalidates all dependents recursively\n * - Emits batched `onChange()` events to all subscribers (Swagger, DevTools, etc.)\n *\n * ## Detection Strategy\n *\n * Uses regex patterns (not AST) for speed. This is the same approach\n * TanStack Start uses (`KindDetectionPatterns` in their compiler).\n * It's fast because:\n * - Only runs on files that actually contain decorator patterns\n * - No Babel/SWC parsing needed\n * - False positives are harmless (extra invalidation is safe)\n *\n * @see bench-mark/tanstack-router-analysis.md — Detection pattern origin\n * @see v3/plan.md Step 5 — Design rationale\n *\n * @module @forinda/kickjs-vite/hmr-plugin\n */\n\nimport type { Plugin, ViteDevServer } from 'vite'\nimport type { HmrOptions, PluginContext } from './types'\nimport { RESOLVED_APP } from './virtual-modules'\nimport { rewarmApp } from './warm'\n\n/**\n * Test whether a watcher event refers to a file we should react to.\n *\n * Vite's chokidar fires for everything under the project root. We only\n * want code that the running Express app could realistically depend on:\n *\n *  - **Source extensions only.** `.ts`, `.tsx`, `.js`, `.jsx`, `.mts`,\n *    `.cts`, `.mjs`, `.cjs`. JSON / lockfiles / images / typegen\n *    declaration files are noise.\n *  - **Skip `.d.ts` declaration files.** They're regenerated by typegen\n *    on every save and would create an invalidation loop with the\n *    typegen watcher in `kick dev`.\n *  - **Skip well-known noise directories.** `node_modules`, `dist`, the\n *    `.kickjs` typegen output, `.git`, `coverage`, OS swap files.\n *\n * Errs on the inclusive side: a file that is genuinely unused but still\n * lives under `src/` causes a cheap virtual-app invalidation, no worse\n * than `kick dev`'s typegen sweep already does on the same event.\n */\nfunction isProjectSource(file: string): boolean {\n  if (!/\\.(?:ts|tsx|js|jsx|mts|cts|mjs|cjs)$/.test(file)) return false\n  if (file.endsWith('.d.ts') || file.endsWith('.d.mts') || file.endsWith('.d.cts')) return false\n  if (\n    file.includes('/node_modules/') ||\n    file.includes('/.kickjs/') ||\n    file.includes('/dist/') ||\n    file.includes('/.git/') ||\n    file.includes('/coverage/')\n  ) {\n    return false\n  }\n  return true\n}\n\n/** Strip directory components for a friendlier dev-console label. */\nfunction basename(file: string): string {\n  const i = file.lastIndexOf('/')\n  return i === -1 ? file : file.slice(i + 1)\n}\n\n/**\n * Regex patterns that detect KickJS decorator usage in source files.\n * Matches `@Service()`, `@Controller()`, `@Repository()`, etc.\n * followed by an exported class declaration.\n *\n * Pattern: decorator → optional whitespace → export? class ClassName\n */\nconst DECORATOR_CLASS_REGEX =\n  /@(?:Service|Controller|Repository|Injectable|Component)\\s*\\([^)]*\\)\\s*\\n?\\s*(?:export\\s+)?class\\s+(\\w+)/g\n\n/**\n * Regex patterns that detect the v4 factory-style declarations:\n * `defineAdapter`, `definePlugin`, `defineContextDecorator`. These\n * produce values rather than decorated classes, so the class regex\n * above misses them and changes to plugin/adapter/contributor files\n * silently bypass kickjs HMR.\n *\n * Pattern: `export const Name = defineAdapter|definePlugin|defineContextDecorator(`\n * — captures the constant's name so it can be surfaced in the dev\n * console alongside the rest of the invalidation batch.\n */\nconst FACTORY_DECL_REGEX =\n  /(?:export\\s+)?const\\s+(\\w+)\\s*(?::[^=]+)?=\\s*(defineAdapter|definePlugin|defineContextDecorator)\\s*[<(]/g\n\n/** Substrings that bail out the transform scanner before regex work. */\nconst FACTORY_KEYWORDS = ['defineAdapter', 'definePlugin', 'defineContextDecorator'] as const\nconst DECORATOR_KEYWORDS = [\n  '@Service',\n  '@Controller',\n  '@Repository',\n  '@Injectable',\n  '@Component',\n] as const\n\n/** Debounce time for batching multiple file changes into one invalidation */\nconst DEBOUNCE_MS = 150\n\n/**\n * Creates the HMR selective invalidation plugin.\n *\n * Tracks which DI tokens are defined in which files, then selectively\n * invalidates only the affected tokens (and their dependents) when\n * those files change. Much faster than a full Container.reset().\n *\n * @param ctx - Shared plugin context\n * @returns Vite plugin\n */\nexport function kickjsHmrPlugin(ctx: PluginContext, hmrOptions: HmrOptions = {}): Plugin {\n  /**\n   * Maps file paths to the DI token names defined in them.\n   * Built up during transform(), read during handleHotUpdate().\n   *\n   * @example\n   * ```\n   * '/src/modules/users/user.service.ts' → ['UserService']\n   * '/src/modules/users/user.controller.ts' → ['UserController']\n   * ```\n   */\n  const fileTokenMap = new Map<string, string[]>()\n\n  /** Pending tokens to invalidate (accumulated during debounce window) */\n  let pendingTokens = new Set<string>()\n  let debounceTimer: ReturnType<typeof setTimeout> | null = null\n\n  return {\n    name: 'kickjs:hmr',\n\n    /**\n     * Transform hook — scans source files for decorator patterns.\n     *\n     * Doesn't modify the code (returns null), just records which\n     * DI tokens are defined in each file. This mapping is used by\n     * `handleHotUpdate()` to determine what to invalidate.\n     */\n    transform(code: string, id: string) {\n      // Skip non-TypeScript/JavaScript files and node_modules\n      if (!/\\.[tj]sx?$/.test(id)) return null\n      if (id.includes('node_modules')) return null\n\n      const hasDecorator = DECORATOR_KEYWORDS.some((kw) => code.includes(kw))\n      const hasFactory = FACTORY_KEYWORDS.some((kw) => code.includes(kw))\n\n      // Quick bail-out: nothing kickjs-relevant in the file\n      if (!hasDecorator && !hasFactory) {\n        if (fileTokenMap.has(id)) fileTokenMap.delete(id)\n        return null\n      }\n\n      const tokens: string[] = []\n\n      if (hasDecorator) {\n        for (const m of code.matchAll(DECORATOR_CLASS_REGEX)) {\n          tokens.push(m[1])\n        }\n      }\n\n      if (hasFactory) {\n        // Tag each entry with the factory kind so the HMR log line\n        // distinguishes a controller-class invalidation from an adapter\n        // / plugin / contributor reload — the second kind never maps\n        // back to a DI token, but it still needs the virtual app\n        // re-evaluated so bootstrap re-imports the new value.\n        for (const m of code.matchAll(FACTORY_DECL_REGEX)) {\n          tokens.push(`${m[1]} (${m[2]})`)\n        }\n      }\n\n      if (tokens.length > 0) {\n        fileTokenMap.set(id, tokens)\n      } else if (fileTokenMap.has(id)) {\n        fileTokenMap.delete(id)\n      }\n\n      return null\n    },\n\n    /**\n     * HMR hook — called when a file changes in dev mode.\n     *\n     * If the changed file contains KickJS decorated classes:\n     * 1. Accumulate the affected tokens in the debounce buffer\n     * 2. After 150ms of quiet, flush: invalidate all tokens at once\n     * 3. Invalidate the virtual module for fresh `ssrLoadModule()` response\n     * 4. Send ONE `kickjs:hmr` event to the client (DevTools, Swagger UI)\n     *\n     * The 150ms debounce is critical for `kick g module` which creates\n     * 10+ files in rapid succession. Without debouncing, each file would\n     * trigger a separate invalidation cycle.\n     *\n     * Returns an empty array to tell Vite we handled the update\n     * (prevents Vite's default full-page reload for these files).\n     */\n    handleHotUpdate({ file, server }) {\n      // Reject anything outside the project's source surface — chokidar\n      // also fires for `.kickjs/` typegen output, `dist/`, and editor\n      // swap files that have nothing to do with the running app.\n      if (!isProjectSource(file)) return\n\n      const tokens = fileTokenMap.get(file)\n\n      // Files with kickjs decorators / factories: accumulate their token\n      // names so the dev console can name what changed. Files without a\n      // tracked token (plain helpers, pure utilities, side-effect modules\n      // like `hello.ts`) still trigger an invalidation — just labelled\n      // by the file's basename so the user sees something happened.\n      if (tokens && tokens.length > 0) {\n        for (const t of tokens) pendingTokens.add(t)\n      } else {\n        pendingTokens.add(basename(file))\n      }\n\n      // Debounce: flush after 150ms of quiet\n      if (debounceTimer) clearTimeout(debounceTimer)\n      debounceTimer = setTimeout(() => {\n        flushInvalidation(server, pendingTokens, hmrOptions)\n        pendingTokens = new Set()\n      }, DEBOUNCE_MS)\n\n      // Tell Vite we handled it — don't do default full-page reload.\n      // `flushInvalidation` always invalidates the virtual app module,\n      // so the next ssrLoadModule re-imports the changed file via the\n      // dev-server's middleware shim.\n      return []\n    },\n  }\n}\n\n/**\n * Shape of the reactive-container handle the KickJS runtime publishes on\n * `globalThis` for dev-mode HMR. Optional all the way down — the container\n * only exists after the app has bootstrapped at least once, and older\n * runtime versions may not expose `invalidate`.\n */\ninterface KickHmrGlobal {\n  __kickjs_container?: {\n    invalidate?: (token: string) => void\n  }\n}\n\n/**\n * Flush accumulated token invalidations.\n *\n * Called after the debounce window closes. Performs:\n * 1. Container invalidation (clears instances + walks dependency graph)\n * 2. Virtual module invalidation (forces ssrLoadModule to re-evaluate)\n * 3. HMR event broadcast (notifies DevTools, Swagger UI, etc.)\n *\n * @param server - Vite dev server\n * @param tokens - Set of DI token names to invalidate\n */\nfunction flushInvalidation(\n  server: ViteDevServer,\n  tokens: Set<string>,\n  hmrOptions: HmrOptions,\n): void {\n  const batch = [...tokens]\n  if (batch.length === 0) return\n  const timestamp = Date.now()\n\n  // 1. Invalidate tokens in the reactive container (if available)\n  //    container.invalidate() walks the dependency graph and notifies subscribers\n  const container = (globalThis as typeof globalThis & KickHmrGlobal).__kickjs_container\n  if (container && typeof container.invalidate === 'function') {\n    for (const token of batch) {\n      container.invalidate(token)\n    }\n  }\n\n  // 2. Invalidate the virtual module so next ssrLoadModule() re-evaluates\n  const vmod = server.moduleGraph.getModuleById(RESOLVED_APP)\n  if (vmod) {\n    server.moduleGraph.invalidateModule(vmod)\n  }\n  // 2b. Re-warm immediately — without this, re-evaluation waits for the\n  //     next HTTP request, so a broken save (syntax error, boot throw)\n  //     stays SILENT until something hits the server. Mirrors the eager\n  //     startup warm in dev-server.ts.\n  rewarmApp(server, `HMR invalidation (${batch.length} token${batch.length === 1 ? '' : 's'})`)\n\n  // 3. Send ONE custom HMR event with the full batch\n  //    DevTools dashboard, Swagger UI, and other dev tools can listen:\n  //      import.meta.hot?.on('kickjs:hmr', (data) => { ... })\n  server.hot.send({\n    type: 'custom',\n    event: 'kickjs:hmr',\n    data: { tokens: batch, timestamp },\n  })\n\n  // 4. Dev-console log — three modes, in priority order:\n  //    a. `silent: true` → no log\n  //    b. `onInvalidation` provided → custom function controls the line\n  //       (returning a string emits one console.log, void/undefined =\n  //       suppresses, useful when piping to a structured logger or\n  //       overlay)\n  //    c. neither set → default `HMR invalidated N tokens: …` line\n  if (hmrOptions.silent) return\n\n  if (hmrOptions.onInvalidation) {\n    const out = hmrOptions.onInvalidation({ tokens: batch, timestamp })\n    if (typeof out === 'string') console.log(out)\n    return\n  }\n\n  const names = batch.join(', ')\n  const label = batch.length === 1 ? '1 token' : `${batch.length} tokens`\n  console.log(`  ${green('HMR')} invalidated ${label}: ${names}`)\n}\n\n/** ANSI green for terminal output */\nfunction green(text: string): string {\n  return `\\x1b[32m${text}\\x1b[0m`\n}\n","// `devtoolsFlagPlugin()` — exposes `__KICKJS_DEVTOOLS__` as a build-time\n// constant adopters guard their devtools imports behind. Vite/Rollup's\n// existing dead-code-elimination strips the gated branch from production\n// bundles entirely (including any dynamic `import('@forinda/kickjs-devtools')`\n// inside the gate), giving \"devtools-in-dev, zero overhead in prod\"\n// without a babel pass.\n//\n// Adopter usage:\n//\n//   const adapters = [/* prod adapters… */]\n//   if (__KICKJS_DEVTOOLS__) {\n//     const { DevToolsAdapter } = await import('@forinda/kickjs-devtools')\n//     adapters.push(DevToolsAdapter({ basePath: '/_debug' }))\n//   }\n//\n//   bootstrap({ adapters, modules: [...] })\n//\n// Resolution order for the flag's value:\n//   1. explicit `enabled` option on the plugin → wins\n//   2. `KICKJS_DEVTOOLS=0|1` env var → operator-side override\n//   3. Vite `command` — `'serve'` (dev) → true, `'build'` → false.\n//      `command` is cleaner than NODE_ENV: Vite passes it explicitly\n//      to plugins regardless of how the user set their environment.\n//\n// The plugin returns a Vite `config` hook that adds the literal under\n// `define`. Vite's `define` is a verbatim-substitution map; stringifying\n// with JSON.stringify keeps the value a true / false token (no quotes\n// would break the parser).\n\nimport type { ConfigEnv, Plugin } from 'vite'\n\nexport interface DevtoolsFlagOptions {\n  /**\n   * Force the flag value. When set, environment-based detection is\n   * bypassed entirely. Useful for explicit feature gates per build\n   * profile.\n   *\n   * @default `vite command === 'serve'` (true in dev, false in build)\n   */\n  enabled?: boolean\n  /**\n   * Override the global name. Default `__KICKJS_DEVTOOLS__`.\n   * Useful for adopters who want a project-specific flag name to\n   * avoid colliding with another tooling's own globals.\n   */\n  flagName?: string\n}\n\n/**\n * Resolve the build-time devtools flag. Exposed for unit tests +\n * adopters who want to compute the same answer the plugin would.\n */\nexport function resolveDevtoolsFlag(opts: DevtoolsFlagOptions = {}, env?: ConfigEnv): boolean {\n  if (typeof opts.enabled === 'boolean') return opts.enabled\n  const envOverride = process.env.KICKJS_DEVTOOLS\n  if (envOverride === '1' || envOverride === 'true') return true\n  if (envOverride === '0' || envOverride === 'false') return false\n  // env may be undefined when callers compute the flag outside a\n  // Vite plugin invocation (tests). Fall back to NODE_ENV as a last\n  // resort so the resolver still gives a sensible answer.\n  if (env) return env.command === 'serve'\n  return process.env.NODE_ENV !== 'production'\n}\n\nexport function devtoolsFlagPlugin(opts: DevtoolsFlagOptions = {}): Plugin {\n  const flagName = opts.flagName ?? '__KICKJS_DEVTOOLS__'\n  return {\n    name: 'kickjs:devtools-flag',\n    config(_userConfig, env) {\n      const enabled = resolveDevtoolsFlag(opts, env)\n      return {\n        define: {\n          [flagName]: JSON.stringify(enabled),\n        },\n      }\n    },\n  }\n}\n","/**\n * Babel-based devtools stripper for production builds.\n *\n * Built around a single rule: anything sourced from\n * `@forinda/kickjs-devtools-kit` (or any of its sub-paths) is dev-\n * only and must not ship in the prod bundle. The transform walks\n * each module and removes:\n *\n *  1. `import ... from '@forinda/kickjs-devtools-kit'` declarations\n *     (named, default, namespace, side-effect — all forms).\n *  2. Top-level `ExpressionStatement`s whose call/expression root is\n *     a binding imported from devtools-kit\n *     (e.g., `defineDevtoolsRenderTab({...})`).\n *  3. Side-effect imports whose path ends in `/devtools-events`\n *     (with any extension) — type-augmentation modules shipped by\n *     adapter packages. Already side-effect-only, safe to drop in\n *     prod.\n *\n * The transform is intentionally conservative. It will not:\n *\n *  - Remove identifier *references* outside of the rules above. If\n *    your code calls `defineDevtoolsRenderTab(...)` inside a regular\n *    function body (i.e. not a top-level `ExpressionStatement`),\n *    the reference stays. After we drop the import the build will\n *    fail loud — that is the signal to gate the call behind\n *    `__KICKJS_DEVTOOLS__` (see `devtools-flag-plugin.ts`).\n *  - Touch files that don't import from devtools-kit at all.\n *  - Touch files in `node_modules` (Vite's plugin chain handles\n *    that already, but the transform short-circuits on a quick\n *    string check too).\n *\n * The dev path is unchanged: this transform only runs when Vite's\n * `command === 'build'`. In dev, devtools-kit imports stay live.\n *\n * Spec: docs/db/m3-plan.md §M3.C.\n */\n\n// Namespace import, not a default import: Babel 8 ships as native ESM and\n// `@babel/core` exposes only named exports — `import babel from '@babel/core'`\n// fails at load with \"does not provide an export named 'default'\".\nimport * as babel from '@babel/core'\n\nconst DEVTOOLS_KIT_RE = /^@forinda\\/kickjs-devtools-kit(\\/.*)?$/\nconst DEVTOOLS_EVENTS_RE = /(^|\\/)devtools-events(\\.[a-z]+)?$/\n\nexport interface StripDevtoolsOptions {\n  /**\n   * When `false`, skips files that don't import devtools-kit. The\n   * default short-circuit is a substring check on the source text;\n   * disable it only for tests where you want the visitor to run\n   * unconditionally.\n   *\n   * @default true\n   */\n  fastReject?: boolean\n}\n\nexport interface StripResult {\n  /** Transformed source. Returns the original `code` when nothing was stripped. */\n  code: string\n  /** `true` if the visitor removed at least one node. */\n  changed: boolean\n}\n\n/**\n * Strip devtools-kit imports and their dependent top-level calls\n * from a single TypeScript module. Pure — no I/O, no Vite, no\n * filesystem.\n */\nexport function stripDevtoolsCode(\n  source: string,\n  filename: string,\n  opts: StripDevtoolsOptions = {},\n): StripResult {\n  if (opts.fastReject !== false) {\n    if (!source.includes('@forinda/kickjs-devtools-kit') && !source.includes('devtools-events')) {\n      return { code: source, changed: false }\n    }\n  }\n\n  let changed = false\n\n  // Add the `jsx` plugin only for files that may contain JSX —\n  // `.tsx` / `.jsx`. Mixing `jsx` + `typescript` on a `.ts` file\n  // breaks the angle-bracket type-assertion syntax (`<T>x`); kept\n  // off by default. `.tsx` files would otherwise fail to parse on\n  // any embedded JSX.\n  const isJsx = /\\.(?:tsx|jsx)$/i.test(filename)\n  const parserPlugins: string[] = ['typescript', 'decorators-legacy', 'classProperties']\n  if (isJsx) parserPlugins.push('jsx')\n\n  const result = babel.transformSync(source, {\n    filename,\n    babelrc: false,\n    configFile: false,\n    sourceType: 'module',\n    parserOpts: {\n      plugins: parserPlugins as never,\n    },\n    generatorOpts: {\n      retainLines: true,\n    },\n    plugins: [\n      function devtoolsStripPlugin(): babel.PluginObject {\n        return {\n          name: 'kickjs-strip-devtools',\n          visitor: {\n            Program(path) {\n              const devtoolsBindings = new Set<string>()\n\n              // Pass 1 — drop devtools-kit imports + collect bound names.\n              for (const stmt of path.get('body')) {\n                if (!stmt.isImportDeclaration()) continue\n                const src = stmt.node.source.value\n                if (!DEVTOOLS_KIT_RE.test(src) && !DEVTOOLS_EVENTS_RE.test(src)) continue\n\n                for (const spec of stmt.node.specifiers) {\n                  if (spec.local?.name) devtoolsBindings.add(spec.local.name)\n                }\n                stmt.remove()\n                changed = true\n              }\n\n              if (devtoolsBindings.size === 0) return\n\n              // Pass 2 — drop top-level expression statements rooted\n              // in a stripped binding.\n              for (const stmt of path.get('body')) {\n                if (!stmt.isExpressionStatement()) continue\n                const root = rootIdentifier(stmt.node.expression)\n                if (root && devtoolsBindings.has(root)) {\n                  stmt.remove()\n                  changed = true\n                }\n              }\n            },\n          },\n        }\n      },\n    ],\n  })\n\n  // Return the original source verbatim when nothing was stripped —\n  // Babel's generator otherwise normalises whitespace + adds\n  // semicolons, which would invalidate Vite's cache for files that\n  // shouldn't have changed at all.\n  if (!result || result.code == null || !changed) {\n    return { code: source, changed: false }\n  }\n  return { code: result.code, changed: true }\n}\n\n/**\n * Walk a call/member expression tree to its root identifier. Returns\n * `null` for expressions we don't recognize (literals, sequence\n * expressions, etc.) — the caller skips those rather than guessing.\n */\nfunction rootIdentifier(expr: babel.types.Expression): string | null {\n  let node: babel.types.Node = expr\n  while (true) {\n    if (node.type === 'Identifier') return node.name\n    if (node.type === 'CallExpression') {\n      node = node.callee\n      continue\n    }\n    if (node.type === 'MemberExpression') {\n      node = node.object\n      continue\n    }\n    if (node.type === 'TSAsExpression' || node.type === 'TSNonNullExpression') {\n      node = node.expression\n      continue\n    }\n    return null\n  }\n}\n","/**\n * Vite plugin wrapping `stripDevtoolsCode` for production builds.\n *\n * Runs only when Vite's `command === 'build'`. In dev the plugin is\n * a no-op so the devtools UI keeps working under `kick dev`.\n *\n * Pairs with `devtoolsFlagPlugin()` — that one constant-folds\n * `if (__KICKJS_DEVTOOLS__)` branches via Vite's existing DCE; this\n * one strips top-level devtools-kit imports + their `defineDevtoolsRenderTab(...)` /\n * `defineDevtoolsTab(...)` call sites without requiring adopters to\n * wrap them in the flag.\n *\n * Spec: docs/db/m3-plan.md §M3.C.\n */\n\nimport type { Plugin } from 'vite'\nimport { stripDevtoolsCode } from './babel-strip-devtools'\n\nexport interface DevtoolsStripOptions {\n  /**\n   * Force enable / disable. Default: enabled when `command === 'build'`.\n   * Adopters running a debug-prod build (`kick build` with the flag\n   * forced on) can pass `false` to keep devtools-kit code in the\n   * bundle.\n   */\n  enabled?: boolean\n  /**\n   * Glob-like include pattern. Default: any `.ts` / `.tsx` /\n   * `.mts` / `.cts` file under the project root. The transform is\n   * a no-op on files that don't import devtools-kit, so this is\n   * normally fine to leave at the default.\n   */\n  include?: RegExp\n}\n\nconst DEFAULT_INCLUDE = /\\.(?:m|c)?[jt]sx?$/\n\n/**\n * Strips devtools-kit imports + their top-level call sites from\n * production bundles. See `babel-strip-devtools.ts` for the exact\n * rule set.\n */\nexport function devtoolsStripPlugin(opts: DevtoolsStripOptions = {}): Plugin {\n  let active = false\n  const include = opts.include ?? DEFAULT_INCLUDE\n\n  return {\n    name: 'kickjs:devtools-strip',\n    enforce: 'pre',\n    apply: 'build',\n    config(_userConfig, env) {\n      active = opts.enabled ?? env.command === 'build'\n    },\n    transform(code, id) {\n      if (!active) return null\n      if (id.includes('node_modules')) return null\n      if (!include.test(id)) return null\n      const result = stripDevtoolsCode(code, id)\n      if (!result.changed) return null\n      return { code: result.code, map: null }\n    },\n  }\n}\n","/**\n * kickjs:typegen — typegen-on-save for plain `vite` boots.\n *\n * `kick dev` owns the typegen watcher when it boots Vite (it claims\n * ownership on `globalThis` before `createServer`). But adopters who\n * run bare `vite` (the pre-fix scaffold default, or any Vite-embedding\n * tool) historically got working HMR with silently frozen\n * `.kickjs/types` — new routes lost their typing until a manual\n * `kick typegen`.\n *\n * This plugin closes that gap: when nothing has claimed ownership, it\n * dynamically loads the PROJECT's `@forinda/kickjs-cli` (optional peer\n * — resolved from the project root, never bundled) and wires the same\n * `createTypegenDevWatcher` engine `kick dev` uses, plus one startup\n * catch-up pass. No CLI installed → quiet no-op with a one-line notice.\n */\nimport { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { pathToFileURL } from 'node:url'\n\nimport type { Plugin, ViteDevServer } from 'vite'\n\n/** Mirror of the CLI's TYPEGEN_OWNER_KEY — string-duplicated so this\n * module never needs the CLI at import time. */\nconst OWNER_KEY = '__kickjs_typegen_owner'\n\n/** Structural slice of the CLI surface this plugin consumes. */\nexport interface TypegenCliModule {\n  loadKickConfig(cwd: string): Promise<unknown>\n  createTypegenDevWatcher(opts: {\n    cwd: string\n    config: unknown\n    emitWarning: (message: string) => void\n  }): {\n    handleWatchEvent(event: 'add' | 'change' | 'unlink' | 'unlinkDir', file: string): void\n    runOnce(): void\n    assetSrcRoots: readonly string[]\n    dispose(): void\n  }\n}\n\n/**\n * Resolve `@forinda/kickjs-cli` from the PROJECT root (not from this\n * package — under pnpm's strict layout the vite plugin can't see the\n * CLI through its own node_modules). Walks `node_modules` upward and\n * reads the manifest directly with fs: the CLI is ESM-only (no\n * `require` condition in its exports map), so `createRequire().resolve`\n * throws ERR_PACKAGE_PATH_NOT_EXPORTED and can't be used here.\n * Returns null when not installed or too old to export the watcher\n * engine.\n */\nfunction resolveCliEntry(root: string): string | null {\n  let dir = root\n  for (;;) {\n    const pkgDir = join(dir, 'node_modules', '@forinda', 'kickjs-cli')\n    const manifestPath = join(pkgDir, 'package.json')\n    if (existsSync(manifestPath)) {\n      try {\n        const pkg = JSON.parse(readFileSync(manifestPath, 'utf8')) as {\n          exports?: Record<string, unknown>\n          module?: string\n          main?: string\n        }\n        const dot = pkg.exports?.['.'] as string | Record<string, unknown> | undefined\n        const fromExports =\n          typeof dot === 'string'\n            ? dot\n            : typeof dot?.import === 'string'\n              ? dot.import\n              : typeof (dot?.import as Record<string, unknown> | undefined)?.default === 'string'\n                ? ((dot!.import as Record<string, unknown>).default as string)\n                : typeof dot?.default === 'string'\n                  ? (dot.default as string)\n                  : undefined\n        const entryRel = fromExports ?? pkg.module ?? pkg.main\n        if (typeof entryRel === 'string') return join(pkgDir, entryRel)\n      } catch {\n        // Unreadable manifest — keep walking up.\n      }\n    }\n    const parent = dirname(dir)\n    if (parent === dir) return null\n    dir = parent\n  }\n}\n\nasync function loadCliFromProject(root: string): Promise<TypegenCliModule | null> {\n  try {\n    const entry = resolveCliEntry(root)\n    if (!entry || !existsSync(entry)) return null\n    const mod = (await import(pathToFileURL(entry).href)) as Partial<TypegenCliModule>\n    if (\n      typeof mod.createTypegenDevWatcher === 'function' &&\n      typeof mod.loadKickConfig === 'function'\n    ) {\n      return mod as TypegenCliModule\n    }\n    return null\n  } catch {\n    return null\n  }\n}\n\nexport interface TypegenPluginOptions {\n  /** Test seam — defaults to project-root resolution of the real CLI. */\n  loadCli?: (root: string) => Promise<TypegenCliModule | null>\n}\n\nexport function kickjsTypegenPlugin(opts: TypegenPluginOptions = {}): Plugin {\n  const loadCli = opts.loadCli ?? loadCliFromProject\n  return {\n    name: 'kickjs:typegen',\n    apply: 'serve',\n\n    async configureServer(server: ViteDevServer) {\n      // `kick dev` boots Vite in-process and runs its own watcher —\n      // stand down so the pipeline never double-runs.\n      if ((globalThis as Record<string, unknown>)[OWNER_KEY]) return\n\n      const root = server.config.root\n      const cli = await loadCli(root)\n      if (!cli) {\n        server.config.logger.info(\n          '[kickjs] typegen-on-save disabled — @forinda/kickjs-cli not resolvable from the ' +\n            'project (install it, or run `kick dev`).',\n        )\n        return\n      }\n\n      const config = await cli.loadKickConfig(root).catch(() => null)\n      const watcher = cli.createTypegenDevWatcher({\n        cwd: root,\n        config,\n        emitWarning: (message) => {\n          server.config.logger.warn(message)\n          server.hot.send({\n            type: 'custom',\n            event: 'kickjs:typegen-error',\n            data: { message, timestamp: Date.now() },\n          })\n        },\n      })\n\n      // Startup catch-up — bare `vite` has no pre-server typegen pass\n      // (kick dev runs one before createServer), so types may be stale\n      // from edits made while no dev server was running.\n      watcher.runOnce()\n\n      server.watcher.on('add', (f: string) => watcher.handleWatchEvent('add', f))\n      server.watcher.on('change', (f: string) => watcher.handleWatchEvent('change', f))\n      server.watcher.on('unlink', (f: string) => watcher.handleWatchEvent('unlink', f))\n      server.watcher.on('unlinkDir', (d: string) => watcher.handleWatchEvent('unlinkDir', d))\n      if (watcher.assetSrcRoots.length > 0) {\n        server.watcher.add([...watcher.assetSrcRoots])\n      }\n      if (server.httpServer) {\n        server.httpServer.once('close', () => watcher.dispose())\n      } else {\n        // Middleware mode — no httpServer; tie disposal to the chokidar\n        // watcher's own close so the debounce timer can't leak.\n        server.watcher.once('close', () => watcher.dispose())\n      }\n    },\n  }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { reloadEnv } from '@forinda/kickjs'\nimport type { Plugin } from 'vite'\n\n/**\n * Vite plugin that watches `.env` files and triggers a full reload\n * when they change. This ensures the dev server picks up environment\n * variable changes without a manual restart.\n *\n * Lives in `@forinda/kickjs-vite` so all Vite-only concerns are in one\n * place.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { envWatchPlugin } from '@forinda/kickjs-vite'\n *\n * export default defineConfig({\n *   plugins: [swc.vite(), envWatchPlugin()],\n * })\n * ```\n */\nexport function envWatchPlugin(): Plugin {\n  const envFiles = ['.env', '.env.local', '.env.development', '.env.production', '.env.test']\n\n  return {\n    name: 'kickjs-env-watch',\n\n    configureServer(server) {\n      const root = server.config.root\n\n      for (const file of envFiles) {\n        const filePath = path.resolve(root, file)\n        if (fs.existsSync(filePath)) {\n          server.watcher.add(filePath)\n        }\n      }\n\n      server.watcher.on('change', (changedPath) => {\n        const basename = path.basename(changedPath)\n        if (envFiles.includes(basename)) {\n          server.config.logger.info(`  .env changed (${basename}), triggering reload...`, {\n            timestamp: true,\n          })\n\n          // Re-read the .env file into process.env *before* invalidating\n          // modules. Without this, the next SSR evaluation parses the\n          // (stale) cached env snapshot — Zod throws on the missing key\n          // and the user has to hard-restart the dev server.\n          try {\n            reloadEnv()\n          } catch (err: any) {\n            server.config.logger.warn(\n              `  env reload failed: ${err?.message ?? err} — restart may be required`,\n              { timestamp: true },\n            )\n          }\n\n          // Invalidate all modules to trigger full HMR rebuild\n          const mods = server.moduleGraph.getModulesByFile(path.resolve(root, 'src/index.ts'))\n          if (mods) {\n            for (const mod of mods) {\n              server.moduleGraph.invalidateModule(mod)\n            }\n          }\n\n          server.ws.send({ type: 'full-reload' })\n        }\n      })\n    },\n  }\n}\n","/**\n * @forinda/kickjs-vite — Vite plugin for the KickJS framework.\n *\n * Provides first-class Vite integration for KickJS backend applications:\n * - **Dev server**: Mounts Express on Vite's HTTP server (single port)\n * - **HMR**: Fresh server code on every request via `ssrLoadModule()`\n * - **httpServer piping**: Real `http.Server` available to all adapters\n * - **Virtual modules**: Auto-generated application entry\n *\n * ## Quick Start\n *\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite'\n * import { kickjsVitePlugin } from '@forinda/kickjs-vite'\n * import swc from 'unplugin-swc'\n *\n * export default defineConfig({\n *   plugins: [\n *     swc.vite({ tsconfigFile: 'tsconfig.json' }),\n *     kickjsVitePlugin({ entry: 'src/index.ts' }),\n *   ],\n * })\n * ```\n *\n * ```ts\n * // src/index.ts\n * import { bootstrap } from '@forinda/kickjs'\n * import { UserModule } from './modules/users/user.module'\n *\n * // Export the Express app — Vite serves it in dev, you start it in prod\n * export const app = bootstrap({\n *   modules: [UserModule],\n *   middleware: [express.json()],\n * })\n *\n * // Production: start the server directly\n * if (process.env.NODE_ENV === 'production') {\n *   app.start()\n * }\n * ```\n *\n * ## Architecture\n *\n * The plugin returns an array of focused sub-plugins (React Router pattern):\n *\n * | Plugin | Responsibility |\n * |--------|---------------|\n * | `kickjs:core` | Vite config: appType, SSR environment, externals |\n * | `kickjs:module-discovery` | Auto-discover `@Module` classes via `transform()` |\n * | `kickjs:hmr` | Selective container invalidation via `handleHotUpdate()` |\n * | `kickjs:virtual-modules` | `virtual:kickjs/app` resolution and generation |\n * | `kickjs:dev-server` | `configureServer()` — mounts Express, pipes httpServer |\n *\n * ## httpServer Piping\n *\n * Vite creates the `http.Server` — this plugin stores it on\n * `globalThis.__kickjs_httpServer`. KickJS adapters (WsAdapter, Socket.IO,\n * GraphQL subscriptions) attach to this server via the standard\n * `afterStart({ server })` hook. Zero adapter code changes needed.\n *\n * @see v3/architecture.md — Full architecture documentation\n * @see v3/plan.md — Implementation plan and rationale\n * @see bench-mark/react-router-analysis.md — Pattern origin\n *\n * @module @forinda/kickjs-vite\n */\n\nimport { resolve } from 'node:path'\nimport type { Plugin } from 'vite'\nimport type { KickJSPluginOptions, PluginContext } from './types'\nimport { kickjsCorePlugin } from './core-plugin'\nimport { kickjsVirtualModulesPlugin } from './virtual-modules'\nimport { kickjsDevServerPlugin } from './dev-server'\nimport { kickjsModuleDiscoveryPlugin } from './module-discovery'\nimport { kickjsHmrPlugin } from './hmr-plugin'\nimport { devtoolsFlagPlugin } from './devtools-flag-plugin'\nimport { devtoolsStripPlugin } from './devtools-strip-plugin'\nimport { kickjsTypegenPlugin } from './typegen-plugin'\n\n/**\n * Create the KickJS Vite plugin array.\n *\n * Returns an array of focused sub-plugins that together provide full\n * Vite integration for KickJS backend applications. Each sub-plugin\n * has a single responsibility and runs at the appropriate Vite lifecycle stage.\n *\n * @param options - Plugin configuration\n * @param options.entry - Path to app entry file (default: 'src/index.ts')\n * @returns Array of Vite plugins\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite'\n * import { kickjsVitePlugin } from '@forinda/kickjs-vite'\n * import swc from 'unplugin-swc'\n *\n * export default defineConfig({\n *   plugins: [\n *     swc.vite({ tsconfigFile: 'tsconfig.json' }),\n *     kickjsVitePlugin(),\n *   ],\n * })\n * ```\n */\nexport function kickjsVitePlugin(options: KickJSPluginOptions = {}): Plugin[] {\n  const entry = options.entry ?? 'src/index.ts'\n\n  // Create shared context — resolved lazily in config hook since we\n  // don't have the root directory until Vite resolves its config.\n  const ctx: PluginContext = {\n    entry,\n    root: process.cwd(),\n  }\n\n  // Resolve root and entry as early as possible so sub-plugin config() hooks\n  // (e.g., warmup) see the correct absolute entry path.\n  const rootResolver: Plugin = {\n    name: 'kickjs:root-resolver',\n    config(config) {\n      const root = config.root ?? process.cwd()\n      ctx.root = root\n      ctx.entry = resolve(root, entry)\n    },\n  }\n\n  const plugins: Plugin[] = [\n    rootResolver,\n    kickjsCorePlugin(ctx),\n    kickjsModuleDiscoveryPlugin(ctx),\n    kickjsHmrPlugin(ctx, options.hmr),\n    kickjsVirtualModulesPlugin(ctx),\n    kickjsDevServerPlugin(ctx),\n    // Typegen-on-save for bare `vite` boots — no-op under `kick dev`\n    // (which claims ownership) or when @forinda/kickjs-cli is absent.\n    kickjsTypegenPlugin(),\n  ]\n  // Register the devtools flag plugin by default. Adopters who don't\n  // gate their devtools imports get a harmless no-op; adopters who do\n  // get tree-shaking for free. Pass `devtools: false` to skip.\n  if (options.devtools !== false) {\n    plugins.push(devtoolsFlagPlugin(options.devtools ?? {}))\n    // Babel-based strip — runs only on `vite build`, removes\n    // devtools-kit imports + their top-level call sites without\n    // requiring adopters to gate them behind the flag. See\n    // `babel-strip-devtools.ts` for the rule set.\n    plugins.push(devtoolsStripPlugin())\n  }\n  return plugins\n}\n\n// Re-export types for consumers\nexport type {\n  KickJSPluginOptions,\n  PluginContext,\n  HmrOptions,\n  HmrInvalidationContext,\n  DevtoolsOptions,\n} from './types'\n\n// Standalone plugins users can compose alongside `kickjsVitePlugin()`\nexport { envWatchPlugin } from './env-watch-plugin'\nexport {\n  kickjsTypegenPlugin,\n  type TypegenPluginOptions,\n  type TypegenCliModule,\n} from './typegen-plugin'\nexport {\n  devtoolsFlagPlugin,\n  resolveDevtoolsFlag,\n  type DevtoolsFlagOptions,\n} from './devtools-flag-plugin'\nexport { devtoolsStripPlugin, type DevtoolsStripOptions } from './devtools-strip-plugin'\nexport {\n  stripDevtoolsCode,\n  type StripDevtoolsOptions,\n  type StripResult,\n} from './babel-strip-devtools'\n"],"mappings":"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"}