@lpdjs/firestore-repo-service 2.4.3 → 2.5.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/servers/hono/codegen/path-utils.ts","../../../src/servers/hono/codegen/scanner.ts","../../../src/servers/hono/codegen/generator.ts","../../../src/servers/hono/cli.ts"],"names":["DEFAULT_DERIVE","derivePath","relativeDir","options","skip","s","p","kebab","toImportSpecifier","fromDir","toFile","ext","fromParts","splitAbs","toParts","common","up","down","stripped","finalLast","part","i","DEFAULT_SCANNER","scanRoutes","rootAbs","found","walk","a","b","root","dir","opts","out","entries","readdirSync","name","abs","join","st","statSync","relPath","relative","sep","relDir","DEFAULT_GENERATOR_BANNER","generateRoutesManifest","routes","outDir","dirname","mkdirSync","banner","now","importLines","entryLines","derivedPaths","r","importPath","url","body","writeFileSync","parseArgs","argv","command","rest","flags","arg","key","next","printHelp","asList","v","asString","makePrompter","input","_q","def","_c","rl","createInterface","output","question","defaultValue","hint","choices","answer","runGen","resolve","existsSync","casing","derive","exclude","routesFile","scanned","result","source","runNew","skipPrompts","prompter","routeName","domain","method","api","useCaseFolder","withUseCase","withTest","force","dirAbs","useCaseFile","testFile","className","useCaseSrc","inputZodSnippet","handlerBody","useCaseImport","routesSrc","inferApisImportPath","written","skipped","writeIfPossible","file","content","testSrc","f","runInit","apisFile","apisRaw","apis","basePathFlag","apisAbs","generatedDir","generatedFile","apisSrc","tag","basePath","stubSrc","apisImportPath","relativeImport","routesImportPath","exportsLine","rel","routeDirAbs","candidates","searchRoots","c","full","main","err"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * URL path inference from filesystem layout.\n *\n * Convention: every `routes.ts` file under the configured root contributes\n * one route. The URL path is derived from its directory chain, optionally\n * skipping segments such as `useCases` so that\n *\n * domains/activities/useCases/createOrUpdateCustom/routes.ts\n *\n * becomes\n *\n * /activities/createOrUpdateCustom\n */\n\nexport interface PathDeriveOptions {\n /** Segments to drop from the derived path (case-insensitive). */\n skipSegments: string[];\n /**\n * Casing convention applied to each remaining segment.\n * - `\"preserve\"` — keep the directory name as-is (default),\n * - `\"kebab\"` — convert camelCase / PascalCase to kebab-case.\n */\n casing: \"preserve\" | \"kebab\";\n}\n\nexport const DEFAULT_DERIVE: PathDeriveOptions = {\n skipSegments: [\"useCases\", \"useCase\", \"use-cases\", \"use-case\"],\n casing: \"preserve\",\n};\n\n/**\n * @param relativeDir POSIX-style directory path of the routes file relative\n * to the codegen root (no leading slash, no `routes.ts`).\n */\nexport function derivePath(\n relativeDir: string,\n options: PathDeriveOptions = DEFAULT_DERIVE,\n): string {\n const skip = new Set(options.skipSegments.map((s) => s.toLowerCase()));\n const parts = relativeDir\n .split(\"/\")\n .filter(Boolean)\n .filter((p) => !skip.has(p.toLowerCase()))\n .map((p) => (options.casing === \"kebab\" ? kebab(p) : p));\n return \"/\" + parts.join(\"/\");\n}\n\nfunction kebab(s: string): string {\n return s\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/[\\s_]+/g, \"-\")\n .toLowerCase();\n}\n\n/**\n * Convert an absolute filesystem path to a POSIX-style import specifier\n * relative to a directory (the generated file's directory). Always uses\n * forward slashes and prefixes with `./` or `../` as needed.\n */\nexport function toImportSpecifier(\n fromDir: string,\n toFile: string,\n ext: string,\n): string {\n // Both paths are absolute POSIX (the CLI normalises them).\n const fromParts = splitAbs(fromDir);\n const toParts = splitAbs(toFile);\n let common = 0;\n while (\n common < fromParts.length &&\n common < toParts.length &&\n fromParts[common] === toParts[common]\n ) {\n common++;\n }\n const up = fromParts.length - common;\n const down = toParts.slice(common);\n const last = down[down.length - 1] ?? \"\";\n const stripped = last.replace(/\\.[mc]?[tj]sx?$/i, \"\");\n const finalLast = ext === \"\" ? stripped : `${stripped}${ext}`;\n down[down.length - 1] = finalLast;\n const prefix = up === 0 ? \"./\" : \"../\".repeat(up);\n return prefix + down.join(\"/\");\n}\n\nfunction splitAbs(p: string): string[] {\n const norm = p.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n return norm.split(\"/\").filter((part, i) => !(i === 0 && part === \"\"));\n}\n","/**\n * Filesystem scanner — walks the configured root and yields every route file.\n * Synchronous and dependency-free (no `fast-glob` etc.) for a tiny CLI footprint.\n */\n\nimport { readdirSync, statSync } from \"node:fs\";\nimport { join, relative, sep } from \"node:path\";\n\nexport interface ScannerOptions {\n /** Filename to look for (default: `routes.ts`). */\n routesFile: string;\n /** Glob-like exclude segments (matched against any path part). */\n excludeSegments: string[];\n}\n\nexport const DEFAULT_SCANNER: ScannerOptions = {\n routesFile: \"routes.ts\",\n excludeSegments: [\n \"node_modules\",\n \"__generated__\",\n \"tests\",\n \"__tests__\",\n \".turbo\",\n \"dist\",\n \"build\",\n \".next\",\n ],\n};\n\nexport interface ScannedRoute {\n /** Absolute path to the routes file. */\n absPath: string;\n /** Path relative to the scan root (POSIX style). */\n relPath: string;\n /** Directory portion of `relPath` (what {@link derivePath} consumes). */\n relDir: string;\n}\n\nexport function scanRoutes(\n rootAbs: string,\n options: ScannerOptions = DEFAULT_SCANNER,\n): ScannedRoute[] {\n const found: ScannedRoute[] = [];\n walk(rootAbs, rootAbs, options, found);\n // Stable, deterministic order — important for reproducible builds.\n found.sort((a, b) => a.relPath.localeCompare(b.relPath));\n return found;\n}\n\nfunction walk(\n root: string,\n dir: string,\n opts: ScannerOptions,\n out: ScannedRoute[],\n): void {\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return;\n }\n for (const name of entries) {\n if (opts.excludeSegments.includes(name)) continue;\n const abs = join(dir, name);\n let st;\n try {\n st = statSync(abs);\n } catch {\n continue;\n }\n if (st.isDirectory()) {\n walk(root, abs, opts, out);\n } else if (st.isFile() && name === opts.routesFile) {\n const relPath = relative(root, abs).split(sep).join(\"/\");\n const relDir = relPath.replace(/\\/?[^/]+$/, \"\");\n out.push({ absPath: abs, relPath, relDir });\n }\n }\n}\n","/**\n * Generator — emits `__generated__/routes.ts` from a list of {@link ScannedRoute}s.\n *\n * The generated module statically imports every `routes.ts` so that bundlers\n * (esbuild/tsup) can tree-shake unused dependencies and Cloud Functions get\n * the smallest possible cold-start footprint.\n */\n\nimport { dirname, join } from \"node:path\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\n\nimport {\n derivePath,\n toImportSpecifier,\n type PathDeriveOptions,\n} from \"./path-utils\";\nimport type { ScannedRoute } from \"./scanner\";\n\nexport interface GeneratorOptions {\n /** Absolute path of the file to write (e.g. `…/__generated__/routes.ts`). */\n outFile: string;\n /** Path-derivation options (skipSegments, casing). */\n derive: PathDeriveOptions;\n /**\n * Import extension used in the generated file:\n * - `\".js\"` (default) — required for ESM Node.js with `\"type\": \"module\"`,\n * - `\"\"` — bundler-friendly (Vite, no extension),\n * - `\".ts\"` — for TS-ESM runners (`tsx`, `bun`).\n */\n importExtension: string;\n /** Friendly banner placed at the top of the generated file. */\n banner?: string;\n /** Generation timestamp included in the banner. Default: `new Date()`. */\n now?: Date;\n}\n\nexport const DEFAULT_GENERATOR_BANNER =\n \"/**\\n\" +\n \" * AUTO-GENERATED by `@lpdjs/firestore-repo-service` Hono codegen.\\n\" +\n \" * Do not edit by hand — re-run `hono:gen` after adding / removing route files.\\n\" +\n \" */\\n\";\n\nexport interface GenerationResult {\n /** Absolute path of the file written. */\n outFile: string;\n /** Number of routes captured in the manifest. */\n routeCount: number;\n /** Human-readable summary of the derived URLs. */\n derivedPaths: { source: string; url: string }[];\n}\n\nexport function generateRoutesManifest(\n routes: ScannedRoute[],\n opts: GeneratorOptions,\n): GenerationResult {\n const outDir = dirname(opts.outFile);\n mkdirSync(outDir, { recursive: true });\n\n const banner = opts.banner ?? DEFAULT_GENERATOR_BANNER;\n const now = (opts.now ?? new Date()).toISOString();\n const ext = opts.importExtension;\n\n const importLines: string[] = [];\n const entryLines: string[] = [];\n const derivedPaths: GenerationResult[\"derivedPaths\"] = [];\n\n routes.forEach((r, i) => {\n const importPath = toImportSpecifier(outDir, r.absPath, ext);\n const url = derivePath(r.relDir, opts.derive);\n importLines.push(\n `import mod${i} from ${JSON.stringify(importPath)};`,\n );\n entryLines.push(` { __derivedPath: ${JSON.stringify(url)}, mod: mod${i} },`);\n derivedPaths.push({ source: r.relPath, url });\n });\n\n const body =\n `${banner}` +\n `// Generated at ${now} — ${routes.length} route file${routes.length === 1 ? \"\" : \"s\"}.\\n` +\n `\\n` +\n `import type { AnyRouteDef, RouteModuleDefault } from \"@lpdjs/firestore-repo-service/servers/hono\";\\n` +\n `\\n` +\n importLines.join(\"\\n\") +\n (importLines.length ? \"\\n\\n\" : \"\\n\") +\n `const __defs: { __derivedPath: string; mod: RouteModuleDefault }[] = [\\n` +\n entryLines.join(\"\\n\") +\n (entryLines.length ? \"\\n\" : \"\") +\n `];\\n\\n` +\n `export const routes: AnyRouteDef[] = __defs.flatMap(({ __derivedPath, mod }) => {\\n` +\n ` const list = Array.isArray(mod) ? mod : [mod];\\n` +\n ` return list.map((route) => ({ ...route, path: route.path ?? __derivedPath }));\\n` +\n `});\\n`;\n\n writeFileSync(opts.outFile, body, \"utf8\");\n return {\n outFile: opts.outFile,\n routeCount: routes.length,\n derivedPaths,\n };\n}\n\n/** Convenience helper used by the CLI — combines scan + generate in one call. */\nexport function generateFromRoot(\n rootAbs: string,\n outFileRel: string,\n derive: PathDeriveOptions,\n importExtension: string,\n scan: (root: string) => ScannedRoute[],\n): GenerationResult {\n const routes = scan(rootAbs);\n const outFile = join(rootAbs, outFileRel);\n return generateRoutesManifest(routes, {\n outFile,\n derive,\n importExtension,\n });\n}\n","#!/usr/bin/env node\n/**\n * `frs-hono` CLI — codegen + scaffolder for the file-based Hono server.\n *\n * Usage:\n * frs-hono init # interactive project bootstrap\n * frs-hono gen --root src/domains\n * frs-hono new createPost --domain posts --method post\n *\n * Designed to be a **prebuild step** (e.g. wired into `npm run build`).\n * Outputs a manifest with static imports — no runtime filesystem scanning.\n */\n\nimport { resolve, relative, dirname } from \"node:path\";\nimport { existsSync, mkdirSync, writeFileSync } from \"node:fs\";\nimport { createInterface } from \"node:readline/promises\";\nimport { stdin as input, stdout as output } from \"node:process\";\n\nimport { DEFAULT_DERIVE, type PathDeriveOptions } from \"./codegen/path-utils\";\nimport {\n DEFAULT_SCANNER,\n scanRoutes,\n type ScannerOptions,\n} from \"./codegen/scanner\";\nimport { generateRoutesManifest } from \"./codegen/generator\";\n\ninterface ParsedArgs {\n command: string;\n flags: Record<string, string | boolean>;\n}\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const [command, ...rest] = argv;\n const flags: Record<string, string | boolean> = {};\n for (let i = 0; i < rest.length; i++) {\n const arg = rest[i]!;\n if (!arg.startsWith(\"--\")) continue;\n const key = arg.slice(2);\n const next = rest[i + 1];\n if (next && !next.startsWith(\"--\")) {\n flags[key] = next;\n i++;\n } else {\n flags[key] = true;\n }\n }\n return { command: command ?? \"help\", flags };\n}\n\nfunction printHelp(): void {\n // eslint-disable-next-line no-console\n console.log(`frs-hono — Hono file-based codegen\n\nUsage:\n frs-hono init [flags]\n frs-hono gen [flags]\n frs-hono new <name> [flags]\n frs-hono help\n\nFlags (init):\n --root <dir> Domain root to create (default: src/domains)\n --apis-file <path> Path to the apis.ts file to create (default: src/apis.ts)\n --apis <list> Comma-separated API tags to register (default: v1)\n --base-path <prefix> basePath shared by all APIs (default: derived from tag)\n --force Overwrite existing files\n --yes Skip prompts, use defaults / flag values\n\nFlags (gen):\n --root <dir> Domain root to scan (required, e.g. src/domains)\n --out <file> Output file relative to --root\n (default: __generated__/routes.ts)\n --routes-file <name> Filename to look for (default: routes.ts)\n --skip <list> Comma-separated path segments to drop from URLs\n (default: useCases,useCase,use-cases,use-case)\n --casing <preserve|kebab>\n Casing applied to remaining segments (default: preserve)\n --ext <.js|.ts|''> Import extension in the generated file\n (default: .js — required for ESM Node.js)\n --exclude <list> Comma-separated directories to skip\n (default: node_modules,__generated__,tests,__tests__,dist,build)\n --silent Do not print the generated route table\n\nFlags (new <name>):\n --root <dir> Domain root (default: src/domains)\n --domain <name> Domain name (e.g. posts) — prompted if missing\n --method <verb> HTTP method (default: post) — prompted if missing\n --api <tag> API tag (default: v1) — prompted if missing\n --usecase-folder <name>\n Parent folder under <domain>. Default: useCases\n --with-usecase Also scaffold a sibling useCase.ts file (default: true)\n --with-test Also scaffold a sibling useCase.test.ts (Vitest, default: true)\n --apis-import <path> Import path for the registry (default: auto-detect\n ../../../../apis.js — adjust if your layout differs)\n --force Overwrite if files already exist\n --yes Skip prompts, use defaults / flag values\n\nExamples:\n frs-hono init\n frs-hono new createPost --domain posts --method post\n frs-hono new listPosts --domain posts --method get --api v1\n`);\n}\n\nfunction asList(v: string | boolean | undefined): string[] | undefined {\n if (typeof v !== \"string\") return undefined;\n return v\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\nfunction asString(v: string | boolean | undefined): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Interactive prompts\n// ---------------------------------------------------------------------------\n\ninterface Prompter {\n ask(question: string, defaultValue?: string): Promise<string>;\n askChoice(\n question: string,\n choices: readonly string[],\n defaultValue?: string,\n ): Promise<string>;\n askBool(question: string, defaultValue: boolean): Promise<boolean>;\n close(): void;\n}\n\nfunction makePrompter(skip: boolean): Prompter {\n if (skip || !input.isTTY) {\n // Non-interactive: always return the default.\n return {\n ask: async (_q, def) => def ?? \"\",\n askChoice: async (_q, _c, def) => def ?? \"\",\n askBool: async (_q, def) => def,\n close: () => undefined,\n };\n }\n const rl = createInterface({ input, output });\n return {\n async ask(question, defaultValue) {\n const hint = defaultValue ? ` (${defaultValue})` : \"\";\n const answer = (await rl.question(`? ${question}${hint} › `)).trim();\n return answer || defaultValue || \"\";\n },\n async askChoice(question, choices, defaultValue) {\n const hint = ` [${choices.join(\"/\")}${defaultValue ? `, default: ${defaultValue}` : \"\"}]`;\n while (true) {\n const answer = (await rl.question(`? ${question}${hint} › `))\n .trim()\n .toLowerCase();\n if (!answer && defaultValue) return defaultValue;\n if (choices.includes(answer)) return answer;\n // eslint-disable-next-line no-console\n console.log(` invalid choice — pick one of: ${choices.join(\", \")}`);\n }\n },\n async askBool(question, defaultValue) {\n const hint = ` (${defaultValue ? \"Y/n\" : \"y/N\"})`;\n const answer = (await rl.question(`? ${question}${hint} › `))\n .trim()\n .toLowerCase();\n if (!answer) return defaultValue;\n return answer === \"y\" || answer === \"yes\" || answer === \"true\";\n },\n close: () => rl.close(),\n };\n}\n\nasync function runGen(flags: ParsedArgs[\"flags\"]): Promise<void> {\n const root = asString(flags.root);\n if (!root) {\n // eslint-disable-next-line no-console\n console.error(\"[frs-hono] --root is required\");\n process.exit(2);\n }\n const rootAbs = resolve(process.cwd(), root);\n if (!existsSync(rootAbs)) {\n // eslint-disable-next-line no-console\n console.error(`[frs-hono] root not found: ${rootAbs}`);\n process.exit(2);\n }\n\n const out = asString(flags.out) ?? \"__generated__/routes.ts\";\n\n const skip = asList(flags.skip) ?? DEFAULT_DERIVE.skipSegments;\n const casing =\n asString(flags.casing) === \"kebab\" ? \"kebab\" : DEFAULT_DERIVE.casing;\n const derive: PathDeriveOptions = { skipSegments: skip, casing };\n\n const ext = asString(flags.ext) ?? \".js\";\n const exclude = asList(flags.exclude) ?? DEFAULT_SCANNER.excludeSegments;\n const routesFile = asString(flags[\"routes-file\"]) ?? DEFAULT_SCANNER.routesFile;\n const scannerOpts: ScannerOptions = { routesFile, excludeSegments: exclude };\n\n const scanned = scanRoutes(rootAbs, scannerOpts);\n if (scanned.length === 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `[frs-hono] no \"${routesFile}\" files found under ${rootAbs} — generated an empty manifest.`,\n );\n }\n\n const result = generateRoutesManifest(scanned, {\n outFile: resolve(rootAbs, out),\n derive,\n importExtension: ext,\n });\n\n if (!flags.silent) {\n // eslint-disable-next-line no-console\n console.log(\n `[frs-hono] wrote ${result.outFile} (${result.routeCount} route${\n result.routeCount === 1 ? \"\" : \"s\"\n })`,\n );\n for (const { source, url } of result.derivedPaths) {\n // eslint-disable-next-line no-console\n console.log(` ${url.padEnd(48)} ← ${source}`);\n }\n }\n}\n\nasync function runNew(\n name: string | undefined,\n flags: ParsedArgs[\"flags\"],\n): Promise<void> {\n const skipPrompts = flags.yes === true;\n const prompter = makePrompter(skipPrompts);\n try {\n let routeName = name && !name.startsWith(\"--\") ? name : undefined;\n if (!routeName) {\n routeName = (\n await prompter.ask(\"Route name (e.g. createPost)\")\n ).trim();\n if (!routeName) {\n // eslint-disable-next-line no-console\n console.error(\"[frs-hono] route name is required\");\n process.exit(2);\n }\n }\n\n let domain = asString(flags.domain);\n if (!domain) {\n domain = (await prompter.ask(\"Domain name (e.g. posts)\")).trim();\n if (!domain) {\n // eslint-disable-next-line no-console\n console.error(\"[frs-hono] --domain is required\");\n process.exit(2);\n }\n }\n\n const root = asString(flags.root) ?? \"src/domains\";\n let method = asString(flags.method)?.toLowerCase();\n if (!method) {\n method = await prompter.askChoice(\n \"HTTP method\",\n [\"get\", \"post\", \"put\", \"patch\", \"delete\"],\n \"post\",\n );\n }\n if (![\"get\", \"post\", \"put\", \"patch\", \"delete\"].includes(method)) {\n // eslint-disable-next-line no-console\n console.error(`[frs-hono] invalid --method: ${method}`);\n process.exit(2);\n }\n\n let api = asString(flags.api);\n if (!api) {\n api = (await prompter.ask(\"API tag\", \"v1\")).trim() || \"v1\";\n }\n\n const useCaseFolder = asString(flags[\"usecase-folder\"]) ?? \"useCases\";\n const withUseCase =\n flags[\"with-usecase\"] === undefined\n ? skipPrompts\n ? true\n : await prompter.askBool(\"Scaffold useCase.ts?\", true)\n : flags[\"with-usecase\"] !== false;\n const withTest =\n flags[\"with-test\"] === undefined\n ? skipPrompts || !withUseCase\n ? withUseCase\n : await prompter.askBool(\"Scaffold useCase.test.ts (Vitest)?\", true)\n : flags[\"with-test\"] !== false;\n const force = flags.force === true;\n\n const rootAbs = resolve(process.cwd(), root);\n const dirAbs = resolve(rootAbs, domain, useCaseFolder, routeName);\n const routesFile = resolve(dirAbs, \"routes.ts\");\n const useCaseFile = resolve(dirAbs, \"useCase.ts\");\n const testFile = resolve(dirAbs, \"useCase.test.ts\");\n\n mkdirSync(dirAbs, { recursive: true });\n\n const className = `${routeName.charAt(0).toUpperCase()}${routeName.slice(1)}UseCase`;\n\n const useCaseSrc = `/**\n * ${className} — pure business logic, no HTTP awareness.\n * Reusable across multiple routes / cron jobs / triggers.\n */\n\nexport interface ${className}Input {\n // TODO: define the input shape\n example: string;\n}\n\nexport interface ${className}Output {\n // TODO: define the output shape\n id: string;\n}\n\nexport class ${className} {\n // TODO: inject repositories / services via the constructor.\n // constructor(private readonly repo: SomeRepository) {}\n\n async execute(input: ${className}Input): Promise<${className}Output> {\n // TODO: implement\n return { id: input.example };\n }\n}\n`;\n\n const inputZodSnippet =\n method === \"get\"\n ? `z.object({\\n // GET → lu depuis les query params\\n example: z.string(),\\n })`\n : `z.object({\\n // ${method.toUpperCase()} → lu depuis le body JSON\\n example: z.string(),\\n })`;\n\n const handlerBody = withUseCase\n ? ` const useCase = new ${className}();\\n const data = await useCase.execute(input);\\n return data;`\n : ` // TODO: business logic\\n return { id: input.example };`;\n\n const useCaseImport = withUseCase\n ? `import { ${className} } from \"./useCase.js\";\\n`\n : \"\";\n\n const apisImport =\n asString(flags[\"apis-import\"]) ??\n inferApisImportPath(rootAbs, dirAbs);\n\n const routesSrc = `import { z } from \"zod\";\nimport { defineRoute } from \"${apisImport}\";\n${useCaseImport}\nexport default defineRoute({\n api: \"${api}\",\n method: \"${method}\",\n\n input: ${inputZodSnippet},\n\n output: z.object({\n id: z.string(),\n }),\n\n summary: \"TODO: ${routeName}\",\n tags: [\"${domain}\"],\n\n handler: async ({ input }) => {\n${handlerBody}\n },\n});\n`;\n\n const written: string[] = [];\n const skipped: string[] = [];\n\n const writeIfPossible = (file: string, content: string) => {\n if (existsSync(file) && !force) {\n skipped.push(file);\n return;\n }\n writeFileSync(file, content, \"utf8\");\n written.push(file);\n };\n\n writeIfPossible(routesFile, routesSrc);\n if (withUseCase) writeIfPossible(useCaseFile, useCaseSrc);\n if (withUseCase && withTest) {\n const testSrc = `import { describe, it, expect } from \"vitest\";\nimport { ${className} } from \"./useCase.js\";\n\ndescribe(\"${className}\", () => {\n it(\"returns a response shaped like the output schema\", async () => {\n const useCase = new ${className}();\n const result = await useCase.execute({ example: \"hello\" });\n expect(result).toMatchObject({ id: expect.any(String) });\n });\n\n // TODO: add error-path tests, repository mocks, etc.\n});\n`;\n writeIfPossible(testFile, testSrc);\n }\n\n // eslint-disable-next-line no-console\n for (const f of written) console.log(`[frs-hono] wrote ${f}`);\n for (const f of skipped)\n // eslint-disable-next-line no-console\n console.log(`[frs-hono] skipped ${f} (use --force to overwrite)`);\n // eslint-disable-next-line no-console\n console.log(\n `\\n[frs-hono] reminder: run \"frs-hono gen --root ${root}\" to refresh the manifest.`,\n );\n } finally {\n prompter.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// `init` — bootstrap a fresh project layout\n// ---------------------------------------------------------------------------\n\nasync function runInit(flags: ParsedArgs[\"flags\"]): Promise<void> {\n const skipPrompts = flags.yes === true;\n const prompter = makePrompter(skipPrompts);\n try {\n const force = flags.force === true;\n\n let root = asString(flags.root);\n if (!root) {\n root = (await prompter.ask(\"Domain root\", \"src/domains\")).trim() || \"src/domains\";\n }\n\n let apisFile = asString(flags[\"apis-file\"]);\n if (!apisFile) {\n apisFile = (await prompter.ask(\"apis.ts location\", \"src/apis.ts\")).trim() || \"src/apis.ts\";\n }\n\n let apisRaw = asString(flags.apis);\n if (!apisRaw) {\n apisRaw = (await prompter.ask(\"API tags (comma-separated)\", \"v1\")).trim() || \"v1\";\n }\n const apis = apisRaw\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n if (apis.length === 0) {\n // eslint-disable-next-line no-console\n console.error(\"[frs-hono] at least one API tag is required\");\n process.exit(2);\n }\n\n const basePathFlag = asString(flags[\"base-path\"]);\n\n const rootAbs = resolve(process.cwd(), root);\n const apisAbs = resolve(process.cwd(), apisFile);\n const generatedDir = resolve(rootAbs, \"__generated__\");\n const generatedFile = resolve(generatedDir, \"routes.ts\");\n\n const written: string[] = [];\n const skipped: string[] = [];\n const writeIfPossible = (file: string, content: string) => {\n mkdirSync(dirname(file), { recursive: true });\n if (existsSync(file) && !force) {\n skipped.push(file);\n return;\n }\n writeFileSync(file, content, \"utf8\");\n written.push(file);\n };\n\n // 1) apis.ts ----------------------------------------------------------\n const apisBody = apis\n .map((tag) => {\n const basePath = basePathFlag ?? `/${tag}`;\n return ` ${tag}: {\n basePath: \"${basePath}\",\n openapi: {\n info: { title: \"${tag.toUpperCase()} API\", version: \"1.0.0\", description: \"\" },\n },\n verbose: process.env[\"NODE_ENV\"] !== \"production\",\n },`;\n })\n .join(\"\\n\");\n\n const apisSrc = `import { createApiRegistry } from \"@lpdjs/firestore-repo-service/servers/hono\";\n\n/**\n * Single source of truth for every API exposed by this project.\n * Add per-API middlewares, interceptors, OpenAPI metadata here.\n */\nexport const apis = createApiRegistry({\n${apisBody}\n});\n\n/** Typed helper used inside every route file. */\nexport const defineRoute = apis.defineRoute;\n`;\n\n writeIfPossible(apisAbs, apisSrc);\n\n // 2) Empty generated manifest stub -----------------------------------\n const stubSrc = `// AUTO-GENERATED by frs-hono — do not edit.\n// Run \\`frs-hono gen --root ${root}\\` to refresh.\n\nimport type { AnyRouteDef } from \"@lpdjs/firestore-repo-service/servers/hono\";\n\nexport const routes: AnyRouteDef[] = [];\n`;\n writeIfPossible(generatedFile, stubSrc);\n\n // 3) index.ts snippet hint -------------------------------------------\n const apisImportPath = relativeImport(dirname(apisAbs), apisAbs);\n const routesImportPath = relativeImport(dirname(apisAbs), generatedFile);\n const exportsLine = apis.length === 1\n ? `export const { ${apis[0]} } = apis.toFunctions(routes, onRequest, {`\n : `export const { ${apis.join(\", \")} } = apis.toFunctions(routes, onRequest, {`;\n\n // eslint-disable-next-line no-console\n for (const f of written) console.log(`[frs-hono] wrote ${f}`);\n for (const f of skipped)\n // eslint-disable-next-line no-console\n console.log(`[frs-hono] skipped ${f} (use --force to overwrite)`);\n\n // eslint-disable-next-line no-console\n console.log(`\nNext steps:\n\n1. Wire the registry in your Functions entrypoint (e.g. src/index.ts):\n\n import { onRequest } from \"firebase-functions/v2/https\";\n import { apis } from \"${apisImportPath}\";\n import { routes } from \"${routesImportPath}\";\n\n ${exportsLine}\n defaults: { region: \"us-central1\", invoker: \"public\" },\n });\n\n2. Scaffold a first route:\n\n frs-hono new createPost --domain posts --method post --api ${apis[0]}\n\n3. Refresh the manifest before each build:\n\n frs-hono gen --root ${root}\n`);\n } finally {\n prompter.close();\n }\n}\n\nfunction relativeImport(fromDir: string, toFile: string): string {\n let rel = relative(fromDir, toFile).replace(/\\\\/g, \"/\");\n rel = rel.replace(/\\.ts$/, \".js\");\n if (!rel.startsWith(\".\")) rel = `./${rel}`;\n return rel;\n}\n\n/**\n * Try to find the user's `apis.ts` (or similar) file and return a relative\n * import path from the new route file. Falls back to a sensible placeholder.\n */\nfunction inferApisImportPath(rootAbs: string, routeDirAbs: string): string {\n const candidates = [\"apis.ts\", \"apis.js\", \"api.ts\", \"api.js\"];\n // Search upwards from rootAbs's parent (typical layout: src/apis.ts + src/domains/…)\n const searchRoots = [\n rootAbs,\n dirname(rootAbs),\n dirname(dirname(rootAbs)),\n ];\n for (const dir of searchRoots) {\n for (const c of candidates) {\n const full = resolve(dir, c);\n if (existsSync(full)) {\n let rel = relative(routeDirAbs, full).replace(/\\\\/g, \"/\");\n rel = rel.replace(/\\.ts$/, \".js\").replace(/\\.js$/, \".js\");\n if (!rel.startsWith(\".\")) rel = `./${rel}`;\n return rel;\n }\n }\n }\n return \"../../../../apis.js\";\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n const { command, flags } = parseArgs(argv);\n switch (command) {\n case \"init\":\n await runInit(flags);\n return;\n case \"gen\":\n await runGen(flags);\n return;\n case \"new\":\n // First positional after `new` is the route name.\n await runNew(argv[1], flags);\n return;\n case \"help\":\n case \"--help\":\n case \"-h\":\n printHelp();\n return;\n default:\n // eslint-disable-next-line no-console\n console.error(`[frs-hono] unknown command: ${command}\\n`);\n printHelp();\n process.exit(2);\n }\n}\n\nmain().catch((err) => {\n // eslint-disable-next-line no-console\n console.error(err);\n process.exit(1);\n});\n"]}
1
+ {"version":3,"sources":["../../../src/servers/hono/codegen/path-utils.ts","../../../src/servers/hono/codegen/generator.ts","../../../src/servers/hono/codegen/scanner.ts","../../../src/servers/hono/cli.ts"],"names":["DEFAULT_DERIVE","derivePath","relativeDir","options","skip","s","p","kebab","toImportSpecifier","fromDir","toFile","ext","fromParts","splitAbs","toParts","common","up","down","stripped","finalLast","part","i","DEFAULT_GENERATOR_BANNER","generateRoutesManifest","routes","opts","outDir","dirname","mkdirSync","banner","now","importLines","entryLines","derivedPaths","r","importPath","url","body","writeFileSync","DEFAULT_SCANNER","scanRoutes","rootAbs","found","walk","a","b","root","dir","out","entries","readdirSync","name","abs","join","st","statSync","relPath","relative","sep","relDir","parseArgs","argv","command","rest","flags","arg","key","next","printHelp","asList","v","asString","makePrompter","input","_q","def","_c","rl","createInterface","output","question","defaultValue","hint","choices","answer","runGen","resolve","existsSync","casing","derive","exclude","routesFile","scanned","result","source","runNew","skipPrompts","prompter","routeName","domain","method","api","useCaseFolder","withUseCase","withTest","force","dirAbs","useCaseFile","testFile","className","useCaseSrc","inputZodSnippet","handlerBody","useCaseImport","routesSrc","inferApisImportPath","written","skipped","writeIfPossible","file","content","testSrc","f","runInit","apisFile","servicesFile","defaultServices","apisRaw","apis","basePathFlag","apisAbs","servicesAbs","generatedDir","generatedFile","apisBody","tag","basePath","apisSrc","relativeImport","stubSrc","apisImportPath","routesImportPath","exportsLine","rel","runAdd","what","servicesDir","fileAbs","serviceSrc","current","readFileSync","importLine","factoryLine","lines","lastImportIdx","joined","callMatch","openBraceIdx","updated","routeDirAbs","candidates","searchRoots","c","full","main","err"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * URL path inference from filesystem layout.\n *\n * Convention: every `routes.ts` file under the configured root contributes\n * one route. The URL path is derived from its directory chain, optionally\n * skipping segments such as `useCases` so that\n *\n * domains/activities/useCases/createOrUpdateCustom/routes.ts\n *\n * becomes\n *\n * /activities/createOrUpdateCustom\n */\n\nexport interface PathDeriveOptions {\n /** Segments to drop from the derived path (case-insensitive). */\n skipSegments: string[];\n /**\n * Casing convention applied to each remaining segment.\n * - `\"preserve\"` — keep the directory name as-is (default),\n * - `\"kebab\"` — convert camelCase / PascalCase to kebab-case.\n */\n casing: \"preserve\" | \"kebab\";\n}\n\nexport const DEFAULT_DERIVE: PathDeriveOptions = {\n skipSegments: [\"useCases\", \"useCase\", \"use-cases\", \"use-case\"],\n casing: \"preserve\",\n};\n\n/**\n * @param relativeDir POSIX-style directory path of the routes file relative\n * to the codegen root (no leading slash, no `routes.ts`).\n */\nexport function derivePath(\n relativeDir: string,\n options: PathDeriveOptions = DEFAULT_DERIVE,\n): string {\n const skip = new Set(options.skipSegments.map((s) => s.toLowerCase()));\n const parts = relativeDir\n .split(\"/\")\n .filter(Boolean)\n .filter((p) => !skip.has(p.toLowerCase()))\n .map((p) => (options.casing === \"kebab\" ? kebab(p) : p));\n return \"/\" + parts.join(\"/\");\n}\n\nfunction kebab(s: string): string {\n return s\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .replace(/[\\s_]+/g, \"-\")\n .toLowerCase();\n}\n\n/**\n * Convert an absolute filesystem path to a POSIX-style import specifier\n * relative to a directory (the generated file's directory). Always uses\n * forward slashes and prefixes with `./` or `../` as needed.\n */\nexport function toImportSpecifier(\n fromDir: string,\n toFile: string,\n ext: string,\n): string {\n // Both paths are absolute POSIX (the CLI normalises them).\n const fromParts = splitAbs(fromDir);\n const toParts = splitAbs(toFile);\n let common = 0;\n while (\n common < fromParts.length &&\n common < toParts.length &&\n fromParts[common] === toParts[common]\n ) {\n common++;\n }\n const up = fromParts.length - common;\n const down = toParts.slice(common);\n const last = down[down.length - 1] ?? \"\";\n const stripped = last.replace(/\\.[mc]?[tj]sx?$/i, \"\");\n const finalLast = ext === \"\" ? stripped : `${stripped}${ext}`;\n down[down.length - 1] = finalLast;\n const prefix = up === 0 ? \"./\" : \"../\".repeat(up);\n return prefix + down.join(\"/\");\n}\n\nfunction splitAbs(p: string): string[] {\n const norm = p.replace(/\\\\/g, \"/\").replace(/\\/+$/, \"\");\n return norm.split(\"/\").filter((part, i) => !(i === 0 && part === \"\"));\n}\n","/**\n * Generator — emits `__generated__/routes.ts` from a list of {@link ScannedRoute}s.\n *\n * The generated module statically imports every `routes.ts` so that bundlers\n * (esbuild/tsup) can tree-shake unused dependencies and Cloud Functions get\n * the smallest possible cold-start footprint.\n */\n\nimport { dirname, join } from \"node:path\";\nimport { mkdirSync, writeFileSync } from \"node:fs\";\n\nimport {\n derivePath,\n toImportSpecifier,\n type PathDeriveOptions,\n} from \"./path-utils\";\nimport type { ScannedRoute } from \"./scanner\";\n\nexport interface GeneratorOptions {\n /** Absolute path of the file to write (e.g. `…/__generated__/routes.ts`). */\n outFile: string;\n /** Path-derivation options (skipSegments, casing). */\n derive: PathDeriveOptions;\n /**\n * Import extension used in the generated file:\n * - `\".js\"` (default) — required for ESM Node.js with `\"type\": \"module\"`,\n * - `\"\"` — bundler-friendly (Vite, no extension),\n * - `\".ts\"` — for TS-ESM runners (`tsx`, `bun`).\n */\n importExtension: string;\n /** Friendly banner placed at the top of the generated file. */\n banner?: string;\n /** Generation timestamp included in the banner. Default: `new Date()`. */\n now?: Date;\n}\n\nexport const DEFAULT_GENERATOR_BANNER =\n \"/**\\n\" +\n \" * AUTO-GENERATED by `@lpdjs/firestore-repo-service` Hono codegen.\\n\" +\n \" * Do not edit by hand — re-run `hono:gen` after adding / removing route files.\\n\" +\n \" */\\n\";\n\nexport interface GenerationResult {\n /** Absolute path of the file written. */\n outFile: string;\n /** Number of routes captured in the manifest. */\n routeCount: number;\n /** Human-readable summary of the derived URLs. */\n derivedPaths: { source: string; url: string }[];\n}\n\nexport function generateRoutesManifest(\n routes: ScannedRoute[],\n opts: GeneratorOptions,\n): GenerationResult {\n const outDir = dirname(opts.outFile);\n mkdirSync(outDir, { recursive: true });\n\n const banner = opts.banner ?? DEFAULT_GENERATOR_BANNER;\n const now = (opts.now ?? new Date()).toISOString();\n const ext = opts.importExtension;\n\n const importLines: string[] = [];\n const entryLines: string[] = [];\n const derivedPaths: GenerationResult[\"derivedPaths\"] = [];\n\n routes.forEach((r, i) => {\n const importPath = toImportSpecifier(outDir, r.absPath, ext);\n const url = derivePath(r.relDir, opts.derive);\n importLines.push(\n `import mod${i} from ${JSON.stringify(importPath)};`,\n );\n entryLines.push(` { __derivedPath: ${JSON.stringify(url)}, mod: mod${i} },`);\n derivedPaths.push({ source: r.relPath, url });\n });\n\n const body =\n `${banner}` +\n `// Generated at ${now} — ${routes.length} route file${routes.length === 1 ? \"\" : \"s\"}.\\n` +\n `\\n` +\n `import type { AnyRouteDef, RouteModuleDefault } from \"@lpdjs/firestore-repo-service/servers/hono\";\\n` +\n `\\n` +\n importLines.join(\"\\n\") +\n (importLines.length ? \"\\n\\n\" : \"\\n\") +\n `const __defs: { __derivedPath: string; mod: RouteModuleDefault }[] = [\\n` +\n entryLines.join(\"\\n\") +\n (entryLines.length ? \"\\n\" : \"\") +\n `];\\n\\n` +\n `export const routes: AnyRouteDef[] = __defs.flatMap(({ __derivedPath, mod }) => {\\n` +\n ` const list = Array.isArray(mod) ? mod : [mod];\\n` +\n ` return list.map((route) => ({ ...route, path: route.path ?? __derivedPath }));\\n` +\n `});\\n`;\n\n writeFileSync(opts.outFile, body, \"utf8\");\n return {\n outFile: opts.outFile,\n routeCount: routes.length,\n derivedPaths,\n };\n}\n\n/** Convenience helper used by the CLI — combines scan + generate in one call. */\nexport function generateFromRoot(\n rootAbs: string,\n outFileRel: string,\n derive: PathDeriveOptions,\n importExtension: string,\n scan: (root: string) => ScannedRoute[],\n): GenerationResult {\n const routes = scan(rootAbs);\n const outFile = join(rootAbs, outFileRel);\n return generateRoutesManifest(routes, {\n outFile,\n derive,\n importExtension,\n });\n}\n","/**\n * Filesystem scanner — walks the configured root and yields every route file.\n * Synchronous and dependency-free (no `fast-glob` etc.) for a tiny CLI footprint.\n */\n\nimport { readdirSync, statSync } from \"node:fs\";\nimport { join, relative, sep } from \"node:path\";\n\nexport interface ScannerOptions {\n /** Filename to look for (default: `routes.ts`). */\n routesFile: string;\n /** Glob-like exclude segments (matched against any path part). */\n excludeSegments: string[];\n}\n\nexport const DEFAULT_SCANNER: ScannerOptions = {\n routesFile: \"routes.ts\",\n excludeSegments: [\n \"node_modules\",\n \"__generated__\",\n \"tests\",\n \"__tests__\",\n \".turbo\",\n \"dist\",\n \"build\",\n \".next\",\n ],\n};\n\nexport interface ScannedRoute {\n /** Absolute path to the routes file. */\n absPath: string;\n /** Path relative to the scan root (POSIX style). */\n relPath: string;\n /** Directory portion of `relPath` (what {@link derivePath} consumes). */\n relDir: string;\n}\n\nexport function scanRoutes(\n rootAbs: string,\n options: ScannerOptions = DEFAULT_SCANNER,\n): ScannedRoute[] {\n const found: ScannedRoute[] = [];\n walk(rootAbs, rootAbs, options, found);\n // Stable, deterministic order — important for reproducible builds.\n found.sort((a, b) => a.relPath.localeCompare(b.relPath));\n return found;\n}\n\nfunction walk(\n root: string,\n dir: string,\n opts: ScannerOptions,\n out: ScannedRoute[],\n): void {\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return;\n }\n for (const name of entries) {\n if (opts.excludeSegments.includes(name)) continue;\n const abs = join(dir, name);\n let st;\n try {\n st = statSync(abs);\n } catch {\n continue;\n }\n if (st.isDirectory()) {\n walk(root, abs, opts, out);\n } else if (st.isFile() && name === opts.routesFile) {\n const relPath = relative(root, abs).split(sep).join(\"/\");\n const relDir = relPath.replace(/\\/?[^/]+$/, \"\");\n out.push({ absPath: abs, relPath, relDir });\n }\n }\n}\n","#!/usr/bin/env node\n/**\n * `frs` CLI — codegen + scaffolder for the file-based Hono server.\n *\n * Usage:\n * frs init # interactive project bootstrap\n * frs gen --root src/domains\n * frs new createPost --domain posts --method post\n *\n * Designed to be a **prebuild step** (e.g. wired into `npm run build`).\n * Outputs a manifest with static imports — no runtime filesystem scanning.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, relative, resolve } from \"node:path\";\nimport { stdin as input, stdout as output } from \"node:process\";\nimport { createInterface } from \"node:readline/promises\";\n\nimport { generateRoutesManifest } from \"./codegen/generator\";\nimport { DEFAULT_DERIVE, type PathDeriveOptions } from \"./codegen/path-utils\";\nimport {\n DEFAULT_SCANNER,\n scanRoutes,\n type ScannerOptions,\n} from \"./codegen/scanner\";\n\ninterface ParsedArgs {\n command: string;\n flags: Record<string, string | boolean>;\n}\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const [command, ...rest] = argv;\n const flags: Record<string, string | boolean> = {};\n for (let i = 0; i < rest.length; i++) {\n const arg = rest[i]!;\n if (!arg.startsWith(\"--\")) continue;\n const key = arg.slice(2);\n const next = rest[i + 1];\n if (next && !next.startsWith(\"--\")) {\n flags[key] = next;\n i++;\n } else {\n flags[key] = true;\n }\n }\n return { command: command ?? \"help\", flags };\n}\n\nfunction printHelp(): void {\n // eslint-disable-next-line no-console\n console.log(`frs — Hono file-based codegen\n\nUsage:\n frs init [flags]\n frs gen [flags]\n frs new <name> [flags]\n frs add service <name> [flags]\n frs help\n\nFlags (init):\n --root <dir> Domain root to create (default: src/domains)\n --apis-file <path> Path to the apis.ts file to create (default: src/apis.ts)\n --services-file <path>\n Path to the services.ts file to create\n (default: src/services.ts)\n --apis <list> Comma-separated API tags to register (default: v1)\n --base-path <prefix> basePath shared by all APIs (default: derived from tag)\n --force Overwrite existing files\n --yes Skip prompts, use defaults / flag values\n\nFlags (gen):\n --root <dir> Domain root to scan (required, e.g. src/domains)\n --out <file> Output file relative to --root\n (default: __generated__/routes.ts)\n --routes-file <name> Filename to look for (default: routes.ts)\n --skip <list> Comma-separated path segments to drop from URLs\n (default: useCases,useCase,use-cases,use-case)\n --casing <preserve|kebab>\n Casing applied to remaining segments (default: preserve)\n --ext <.js|.ts|''> Import extension in the generated file\n (default: .js — required for ESM Node.js)\n --exclude <list> Comma-separated directories to skip\n (default: node_modules,__generated__,tests,__tests__,dist,build)\n --silent Do not print the generated route table\n\nFlags (new <name>):\n --root <dir> Domain root (default: src/domains)\n --domain <name> Domain name (e.g. posts) — prompted if missing\n --method <verb> HTTP method (default: post) — prompted if missing\n --api <tag> API tag (default: v1) — prompted if missing\n --usecase-folder <name>\n Parent folder under <domain>. Default: useCases\n --with-usecase Also scaffold a sibling useCase.ts file (default: true)\n --with-test Also scaffold a sibling useCase.test.ts (Vitest, default: true)\n --apis-import <path> Import path for the registry (default: auto-detect\n ../../../../apis.js — adjust if your layout differs)\n --force Overwrite if files already exist\n --yes Skip prompts, use defaults / flag values\n\nFlags (add service <name>):\n --services-file <path>\n Path to the services.ts file (default: src/services.ts)\n --services-dir <dir> Directory hosting individual service files\n (default: <dir-of-services-file>/services)\n --force Overwrite existing files\n\nExamples:\n frs init\n frs new createPost --domain posts --method post\n frs new listPosts --domain posts --method get --api v1\n frs add service postRepo\n`);\n}\n\nfunction asList(v: string | boolean | undefined): string[] | undefined {\n if (typeof v !== \"string\") return undefined;\n return v\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\nfunction asString(v: string | boolean | undefined): string | undefined {\n return typeof v === \"string\" ? v : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Interactive prompts\n// ---------------------------------------------------------------------------\n\ninterface Prompter {\n ask(question: string, defaultValue?: string): Promise<string>;\n askChoice(\n question: string,\n choices: readonly string[],\n defaultValue?: string,\n ): Promise<string>;\n askBool(question: string, defaultValue: boolean): Promise<boolean>;\n close(): void;\n}\n\nfunction makePrompter(skip: boolean): Prompter {\n if (skip || !input.isTTY) {\n // Non-interactive: always return the default.\n return {\n ask: async (_q, def) => def ?? \"\",\n askChoice: async (_q, _c, def) => def ?? \"\",\n askBool: async (_q, def) => def,\n close: () => undefined,\n };\n }\n const rl = createInterface({ input, output });\n return {\n async ask(question, defaultValue) {\n const hint = defaultValue ? ` (${defaultValue})` : \"\";\n const answer = (await rl.question(`? ${question}${hint} › `)).trim();\n return answer || defaultValue || \"\";\n },\n async askChoice(question, choices, defaultValue) {\n const hint = ` [${choices.join(\"/\")}${defaultValue ? `, default: ${defaultValue}` : \"\"}]`;\n while (true) {\n const answer = (await rl.question(`? ${question}${hint} › `))\n .trim()\n .toLowerCase();\n if (!answer && defaultValue) return defaultValue;\n if (choices.includes(answer)) return answer;\n // eslint-disable-next-line no-console\n console.log(` invalid choice — pick one of: ${choices.join(\", \")}`);\n }\n },\n async askBool(question, defaultValue) {\n const hint = ` (${defaultValue ? \"Y/n\" : \"y/N\"})`;\n const answer = (await rl.question(`? ${question}${hint} › `))\n .trim()\n .toLowerCase();\n if (!answer) return defaultValue;\n return answer === \"y\" || answer === \"yes\" || answer === \"true\";\n },\n close: () => rl.close(),\n };\n}\n\nasync function runGen(flags: ParsedArgs[\"flags\"]): Promise<void> {\n const root = asString(flags.root);\n if (!root) {\n // eslint-disable-next-line no-console\n console.error(\"[frs] --root is required\");\n process.exit(2);\n }\n const rootAbs = resolve(process.cwd(), root);\n if (!existsSync(rootAbs)) {\n // eslint-disable-next-line no-console\n console.error(`[frs] root not found: ${rootAbs}`);\n process.exit(2);\n }\n\n const out = asString(flags.out) ?? \"__generated__/routes.ts\";\n\n const skip = asList(flags.skip) ?? DEFAULT_DERIVE.skipSegments;\n const casing =\n asString(flags.casing) === \"kebab\" ? \"kebab\" : DEFAULT_DERIVE.casing;\n const derive: PathDeriveOptions = { skipSegments: skip, casing };\n\n const ext = asString(flags.ext) ?? \".js\";\n const exclude = asList(flags.exclude) ?? DEFAULT_SCANNER.excludeSegments;\n const routesFile = asString(flags[\"routes-file\"]) ?? DEFAULT_SCANNER.routesFile;\n const scannerOpts: ScannerOptions = { routesFile, excludeSegments: exclude };\n\n const scanned = scanRoutes(rootAbs, scannerOpts);\n if (scanned.length === 0) {\n // eslint-disable-next-line no-console\n console.warn(\n `[frs] no \"${routesFile}\" files found under ${rootAbs} — generated an empty manifest.`,\n );\n }\n\n const result = generateRoutesManifest(scanned, {\n outFile: resolve(rootAbs, out),\n derive,\n importExtension: ext,\n });\n\n if (!flags.silent) {\n // eslint-disable-next-line no-console\n console.log(\n `[frs] wrote ${result.outFile} (${result.routeCount} route${\n result.routeCount === 1 ? \"\" : \"s\"\n })`,\n );\n for (const { source, url } of result.derivedPaths) {\n // eslint-disable-next-line no-console\n console.log(` ${url.padEnd(48)} ← ${source}`);\n }\n }\n}\n\nasync function runNew(\n name: string | undefined,\n flags: ParsedArgs[\"flags\"],\n): Promise<void> {\n const skipPrompts = flags.yes === true;\n const prompter = makePrompter(skipPrompts);\n try {\n let routeName = name && !name.startsWith(\"--\") ? name : undefined;\n if (!routeName) {\n routeName = (\n await prompter.ask(\"Route name (e.g. createPost)\")\n ).trim();\n if (!routeName) {\n // eslint-disable-next-line no-console\n console.error(\"[frs] route name is required\");\n process.exit(2);\n }\n }\n\n let domain = asString(flags.domain);\n if (!domain) {\n domain = (await prompter.ask(\"Domain name (e.g. posts)\")).trim();\n if (!domain) {\n // eslint-disable-next-line no-console\n console.error(\"[frs] --domain is required\");\n process.exit(2);\n }\n }\n\n const root = asString(flags.root) ?? \"src/domains\";\n let method = asString(flags.method)?.toLowerCase();\n if (!method) {\n method = await prompter.askChoice(\n \"HTTP method\",\n [\"get\", \"post\", \"put\", \"patch\", \"delete\"],\n \"post\",\n );\n }\n if (![\"get\", \"post\", \"put\", \"patch\", \"delete\"].includes(method)) {\n // eslint-disable-next-line no-console\n console.error(`[frs] invalid --method: ${method}`);\n process.exit(2);\n }\n\n let api = asString(flags.api);\n if (!api) {\n api = (await prompter.ask(\"API tag\", \"v1\")).trim() || \"v1\";\n }\n\n const useCaseFolder = asString(flags[\"usecase-folder\"]) ?? \"useCases\";\n const withUseCase =\n flags[\"with-usecase\"] === undefined\n ? skipPrompts\n ? true\n : await prompter.askBool(\"Scaffold useCase.ts?\", true)\n : flags[\"with-usecase\"] !== false;\n const withTest =\n flags[\"with-test\"] === undefined\n ? skipPrompts || !withUseCase\n ? withUseCase\n : await prompter.askBool(\"Scaffold useCase.test.ts (Vitest)?\", true)\n : flags[\"with-test\"] !== false;\n const force = flags.force === true;\n\n const rootAbs = resolve(process.cwd(), root);\n const dirAbs = resolve(rootAbs, domain, useCaseFolder, routeName);\n const routesFile = resolve(dirAbs, \"routes.ts\");\n const useCaseFile = resolve(dirAbs, \"useCase.ts\");\n const testFile = resolve(dirAbs, \"useCase.test.ts\");\n\n mkdirSync(dirAbs, { recursive: true });\n\n const className = `${routeName.charAt(0).toUpperCase()}${routeName.slice(1)}UseCase`;\n\n const useCaseSrc = `/**\n * ${className} — pure business logic, no HTTP awareness.\n * Reusable across multiple routes / cron jobs / triggers.\n */\n\nexport interface ${className}Input {\n // TODO: define the input shape\n example: string;\n}\n\nexport interface ${className}Output {\n // TODO: define the output shape\n id: string;\n}\n\nexport class ${className} {\n // TODO: inject repositories / services via the constructor.\n // constructor(private readonly repo: SomeRepository) {}\n\n async execute(input: ${className}Input): Promise<${className}Output> {\n // TODO: implement\n return { id: input.example };\n }\n}\n`;\n\n const inputZodSnippet =\n method === \"get\"\n ? `z.object({\\n // GET → lu depuis les query params\\n example: z.string(),\\n })`\n : `z.object({\\n // ${method.toUpperCase()} → lu depuis le body JSON\\n example: z.string(),\\n })`;\n\n const handlerBody = withUseCase\n ? ` const useCase = new ${className}();\\n const data = await useCase.execute(input);\\n return data;`\n : ` // TODO: business logic\\n return { id: input.example };`;\n\n const useCaseImport = withUseCase\n ? `import { ${className} } from \"./useCase.js\";\\n`\n : \"\";\n\n const apisImport =\n asString(flags[\"apis-import\"]) ??\n inferApisImportPath(rootAbs, dirAbs);\n\n const routesSrc = `import { z } from \"zod\";\nimport { defineRoute } from \"${apisImport}\";\n${useCaseImport}\nexport default defineRoute({\n api: \"${api}\",\n method: \"${method}\",\n\n input: ${inputZodSnippet},\n\n output: z.object({\n id: z.string(),\n }),\n\n summary: \"TODO: ${routeName}\",\n tags: [\"${domain}\"],\n\n handler: async ({ input }) => {\n${handlerBody}\n },\n});\n`;\n\n const written: string[] = [];\n const skipped: string[] = [];\n\n const writeIfPossible = (file: string, content: string) => {\n if (existsSync(file) && !force) {\n skipped.push(file);\n return;\n }\n writeFileSync(file, content, \"utf8\");\n written.push(file);\n };\n\n writeIfPossible(routesFile, routesSrc);\n if (withUseCase) writeIfPossible(useCaseFile, useCaseSrc);\n if (withUseCase && withTest) {\n const testSrc = `import { describe, it, expect } from \"vitest\";\nimport { ${className} } from \"./useCase.js\";\n\ndescribe(\"${className}\", () => {\n it(\"returns a response shaped like the output schema\", async () => {\n const useCase = new ${className}();\n const result = await useCase.execute({ example: \"hello\" });\n expect(result).toMatchObject({ id: expect.any(String) });\n });\n\n // TODO: add error-path tests, repository mocks, etc.\n});\n`;\n writeIfPossible(testFile, testSrc);\n }\n\n // eslint-disable-next-line no-console\n for (const f of written) console.log(`[frs] wrote ${f}`);\n for (const f of skipped)\n // eslint-disable-next-line no-console\n console.log(`[frs] skipped ${f} (use --force to overwrite)`);\n // eslint-disable-next-line no-console\n console.log(\n `\\n[frs] reminder: run \"frs gen --root ${root}\" to refresh the manifest.`,\n );\n } finally {\n prompter.close();\n }\n}\n\n// ---------------------------------------------------------------------------\n// `init` — bootstrap a fresh project layout\n// ---------------------------------------------------------------------------\n\nasync function runInit(flags: ParsedArgs[\"flags\"]): Promise<void> {\n const skipPrompts = flags.yes === true;\n const prompter = makePrompter(skipPrompts);\n try {\n const force = flags.force === true;\n\n let root = asString(flags.root);\n if (!root) {\n root = (await prompter.ask(\"Domain root\", \"src/domains\")).trim() || \"src/domains\";\n }\n\n let apisFile = asString(flags[\"apis-file\"]);\n if (!apisFile) {\n apisFile = (await prompter.ask(\"apis.ts location\", \"src/apis.ts\")).trim() || \"src/apis.ts\";\n }\n\n let servicesFile = asString(flags[\"services-file\"]);\n if (!servicesFile) {\n const defaultServices = apisFile.replace(/apis\\.ts$/, \"services.ts\") || \"src/services.ts\";\n servicesFile =\n (await prompter.ask(\"services.ts location\", defaultServices)).trim() ||\n defaultServices;\n }\n\n let apisRaw = asString(flags.apis);\n if (!apisRaw) {\n apisRaw = (await prompter.ask(\"API tags (comma-separated)\", \"v1\")).trim() || \"v1\";\n }\n const apis = apisRaw\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n if (apis.length === 0) {\n // eslint-disable-next-line no-console\n console.error(\"[frs] at least one API tag is required\");\n process.exit(2);\n }\n\n const basePathFlag = asString(flags[\"base-path\"]);\n\n const rootAbs = resolve(process.cwd(), root);\n const apisAbs = resolve(process.cwd(), apisFile);\n const servicesAbs = resolve(process.cwd(), servicesFile);\n const generatedDir = resolve(rootAbs, \"__generated__\");\n const generatedFile = resolve(generatedDir, \"routes.ts\");\n\n const written: string[] = [];\n const skipped: string[] = [];\n const writeIfPossible = (file: string, content: string) => {\n mkdirSync(dirname(file), { recursive: true });\n if (existsSync(file) && !force) {\n skipped.push(file);\n return;\n }\n writeFileSync(file, content, \"utf8\");\n written.push(file);\n };\n\n // 1) apis.ts ----------------------------------------------------------\n const apisBody = apis\n .map((tag) => {\n const basePath = basePathFlag ?? `/${tag}`;\n return ` ${tag}: {\n basePath: \"${basePath}\",\n openapi: {\n info: { title: \"${tag.toUpperCase()} API\", version: \"1.0.0\", description: \"\" },\n },\n verbose: process.env[\"NODE_ENV\"] !== \"production\",\n },`;\n })\n .join(\"\\n\");\n\n const apisSrc = `import { createApiRegistry } from \"@lpdjs/firestore-repo-service/servers/hono\";\nimport { services } from \"${relativeImport(dirname(apisAbs), servicesAbs)}\";\n\n/**\n * Single source of truth for every API exposed by this project.\n * Add per-API middlewares, interceptors, OpenAPI metadata here.\n *\n * The shared \\`services\\` container is injected into every HonoServer the\n * registry builds — handlers / interceptors receive it via \\`{ services }\\`\n * and the built-in \\`services.ctx.c\\` resolves to the current request.\n */\nexport const apis = createApiRegistry(\n {\n${apisBody}\n },\n { services },\n);\n\n/** Typed helper used inside every route file. */\nexport const defineRoute = apis.defineRoute;\n`;\n\n writeIfPossible(apisAbs, apisSrc);\n\n // 1.b services.ts ----------------------------------------------------\n const servicesSrc = `import { createServices } from \"@lpdjs/firestore-repo-service/servers/hono\";\n\n/**\n * Global DI container — declare every singleton (repositories, SDK\n * clients, loggers, useCases) here. Each factory is invoked once on first\n * access and the instance is cached for the process lifetime.\n *\n * Factories receive a typed proxy of every other service plus the\n * built-in \\`ctx\\` (current request \\`Context\\` via AsyncLocalStorage).\n * Destructure what you need — TypeScript will infer everything.\n *\n * @example\n * \\`\\`\\`ts\n * postRepo: () => new PostRepo(),\n * createPostUseCase: ({ ctx, postRepo }) =>\n * new CreatePostUseCase(ctx, postRepo),\n * \\`\\`\\`\n */\nexport const services = createServices({\n // TODO: declare your services here.\n // Example:\n // db: () => getFirestore(),\n // postRepo: ({ db }) => new PostRepo(db),\n});\n\n/** Convenience type — \\`function fn(svc: Services) { ... }\\`. */\nexport type Services = typeof services;\n`;\n\n writeIfPossible(servicesAbs, servicesSrc);\n\n // 2) Empty generated manifest stub -----------------------------------\n const stubSrc = `// AUTO-GENERATED by frs — do not edit.\n// Run \\`frs gen --root ${root}\\` to refresh.\n\nimport type { AnyRouteDef } from \"@lpdjs/firestore-repo-service/servers/hono\";\n\nexport const routes: AnyRouteDef[] = [];\n`;\n writeIfPossible(generatedFile, stubSrc);\n\n // 3) index.ts snippet hint -------------------------------------------\n const apisImportPath = relativeImport(dirname(apisAbs), apisAbs);\n const routesImportPath = relativeImport(dirname(apisAbs), generatedFile);\n const exportsLine = apis.length === 1\n ? `export const { ${apis[0]} } = apis.toFunctions(routes, onRequest, {`\n : `export const { ${apis.join(\", \")} } = apis.toFunctions(routes, onRequest, {`;\n\n // eslint-disable-next-line no-console\n for (const f of written) console.log(`[frs] wrote ${f}`);\n for (const f of skipped)\n // eslint-disable-next-line no-console\n console.log(`[frs] skipped ${f} (use --force to overwrite)`);\n\n // eslint-disable-next-line no-console\n console.log(`\nNext steps:\n\n1. Wire the registry in your Functions entrypoint (e.g. src/index.ts):\n\n import { onRequest } from \"firebase-functions/v2/https\";\n import { apis } from \"${apisImportPath}\";\n import { routes } from \"${routesImportPath}\";\n\n ${exportsLine}\n defaults: { region: \"us-central1\", invoker: \"public\" },\n });\n\n2. Scaffold a first route:\n\n frs new createPost --domain posts --method post --api ${apis[0]}\n\n3. Refresh the manifest before each build:\n\n frs gen --root ${root}\n`);\n } finally {\n prompter.close();\n }\n}\n\nfunction relativeImport(fromDir: string, toFile: string): string {\n let rel = relative(fromDir, toFile).replace(/\\\\/g, \"/\");\n rel = rel.replace(/\\.ts$/, \".js\");\n if (!rel.startsWith(\".\")) rel = `./${rel}`;\n return rel;\n}\n\n// ---------------------------------------------------------------------------\n// `add service <name>` — scaffold a new service file and register it\n// ---------------------------------------------------------------------------\n\nasync function runAdd(\n what: string | undefined,\n name: string | undefined,\n flags: ParsedArgs[\"flags\"],\n): Promise<void> {\n if (what !== \"service\") {\n // eslint-disable-next-line no-console\n console.error(\n `[frs] unknown \"add\" target: ${what ?? \"(missing)\"} — supported: service`,\n );\n process.exit(2);\n }\n if (!name) {\n // eslint-disable-next-line no-console\n console.error(\"[frs] service name is required: frs add service <name>\");\n process.exit(2);\n }\n\n const force = flags.force === true;\n const servicesFile = asString(flags[\"services-file\"]) ?? \"src/services.ts\";\n const servicesAbs = resolve(process.cwd(), servicesFile);\n const servicesDir =\n asString(flags[\"services-dir\"]) ??\n resolve(dirname(servicesAbs), \"services\");\n const dirAbs = resolve(process.cwd(), servicesDir);\n\n if (!existsSync(servicesAbs)) {\n // eslint-disable-next-line no-console\n console.error(\n `[frs] services file not found: ${servicesAbs}\\n` +\n ` Run \\`frs init\\` first or pass --services-file <path>.`,\n );\n process.exit(2);\n }\n\n mkdirSync(dirAbs, { recursive: true });\n\n const className = `${name.charAt(0).toUpperCase()}${name.slice(1)}Service`;\n const fileAbs = resolve(dirAbs, `${name}.ts`);\n\n const serviceSrc = `/**\n * ${className} — generated by \\`frs add service ${name}\\`.\n *\n * Singleton instantiated lazily on first access. Async resources (DB\n * connections, SDK clients) should be lazy-loaded inside the class:\n *\n * @example\n * \\`\\`\\`ts\n * private _client: SomeClient | undefined;\n * get client(): SomeClient {\n * return (this._client ??= new SomeClient({...}));\n * }\n * \\`\\`\\`\n */\nexport class ${className} {\n // TODO: add fields, methods, dependencies.\n hello(): string {\n return \"hello from ${name}\";\n }\n}\n`;\n\n if (existsSync(fileAbs) && !force) {\n // eslint-disable-next-line no-console\n console.log(`[frs] skipped ${fileAbs} (use --force to overwrite)`);\n } else {\n writeFileSync(fileAbs, serviceSrc, \"utf8\");\n // eslint-disable-next-line no-console\n console.log(`[frs] wrote ${fileAbs}`);\n }\n\n // Register in services.ts ------------------------------------------------\n const current = readFileSync(servicesAbs, \"utf8\");\n const importPath = relativeImport(dirname(servicesAbs), fileAbs);\n const importLine = `import { ${className} } from \"${importPath}\";`;\n const factoryLine = ` ${name}: () => new ${className}(),`;\n\n if (current.includes(importLine)) {\n // eslint-disable-next-line no-console\n console.log(`[frs] services.ts already registers \"${name}\" — skipping.`);\n return;\n }\n\n // Insert import after the last existing top-level import (or at the top).\n const lines = current.split(\"\\n\");\n let lastImportIdx = -1;\n for (let i = 0; i < lines.length; i++) {\n if (/^import\\s/.test(lines[i]!)) lastImportIdx = i;\n }\n if (lastImportIdx >= 0) {\n lines.splice(lastImportIdx + 1, 0, importLine);\n } else {\n lines.unshift(importLine);\n }\n\n // Insert factory line inside `createServices({ ... })`.\n const joined = lines.join(\"\\n\");\n const callMatch = joined.match(/createServices\\s*\\(\\s*\\{/);\n if (!callMatch) {\n // eslint-disable-next-line no-console\n console.error(\n `[frs] could not find \\`createServices({\\` in ${servicesAbs} — ` +\n `register \"${name}\" manually.`,\n );\n return;\n }\n const openBraceIdx = callMatch.index! + callMatch[0].length;\n const updated =\n joined.slice(0, openBraceIdx) +\n \"\\n\" +\n factoryLine +\n joined.slice(openBraceIdx);\n\n writeFileSync(servicesAbs, updated, \"utf8\");\n // eslint-disable-next-line no-console\n console.log(`[frs] updated ${servicesAbs} (+ ${name})`);\n}\n\n/**\n * Try to find the user's `apis.ts` (or similar) file and return a relative\n * import path from the new route file. Falls back to a sensible placeholder.\n */\nfunction inferApisImportPath(rootAbs: string, routeDirAbs: string): string {\n const candidates = [\"apis.ts\", \"apis.js\", \"api.ts\", \"api.js\"];\n // Search upwards from rootAbs's parent (typical layout: src/apis.ts + src/domains/…)\n const searchRoots = [\n rootAbs,\n dirname(rootAbs),\n dirname(dirname(rootAbs)),\n ];\n for (const dir of searchRoots) {\n for (const c of candidates) {\n const full = resolve(dir, c);\n if (existsSync(full)) {\n let rel = relative(routeDirAbs, full).replace(/\\\\/g, \"/\");\n rel = rel.replace(/\\.ts$/, \".js\").replace(/\\.js$/, \".js\");\n if (!rel.startsWith(\".\")) rel = `./${rel}`;\n return rel;\n }\n }\n }\n return \"../../../../apis.js\";\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n const { command, flags } = parseArgs(argv);\n switch (command) {\n case \"init\":\n await runInit(flags);\n return;\n case \"gen\":\n await runGen(flags);\n return;\n case \"new\":\n // First positional after `new` is the route name.\n await runNew(argv[1], flags);\n return;\n case \"add\":\n // `frs add service <name>` — argv[1] = target, argv[2] = name.\n await runAdd(argv[1], argv[2], flags);\n return;\n case \"help\":\n case \"--help\":\n case \"-h\":\n printHelp();\n return;\n default:\n // eslint-disable-next-line no-console\n console.error(`[frs] unknown command: ${command}\\n`);\n printHelp();\n process.exit(2);\n }\n}\n\nmain().catch((err) => {\n // eslint-disable-next-line no-console\n console.error(err);\n process.exit(1);\n});\n"]}
@@ -1,4 +1,4 @@
1
- 'use strict';var hono=require('hono'),nodeServer=require('@hono/node-server'),zodToOpenapi=require('@asteasolutions/zod-to-openapi'),zod=require('zod'),fs=require('fs'),path=require('path');var m=class extends Error{constructor(n,o){super("Request validation failed");this.zodError=n;this.source=o;this.statusCode=400;this.name="ValidationError";}};zodToOpenapi.extendZodWithOpenApi(zod.z);var S="Successful response";function j(t){return t==="get"?"query":"json"}function v(t,e,n){let o=new zodToOpenapi.OpenAPIRegistry;if(n.securitySchemes)for(let[s,a]of Object.entries(n.securitySchemes))o.registerComponent("securitySchemes",s,a);for(let s of t){let a=s.method,u=s.source??j(a),p=z(e,s.path??"/"),c=s.status??200,d=$(a,u,s.input),l=w(u,s.input,"query"),f=w(u,s.input,"param"),g=Z(a,p);o.registerPath({method:a,path:q(p),operationId:g,summary:s.summary,description:s.description,tags:s.tags,deprecated:s.deprecated,security:s.security,request:{...l?{query:l}:{},...f?{params:f}:{},...d?{body:d}:{}},responses:s.output?{[c]:{description:S,content:{"application/json":{schema:s.output}}}}:{[c]:{description:S}}});}return new zodToOpenapi.OpenApiGeneratorV31(o.definitions).generateDocument({openapi:"3.1.0",info:n.info,servers:n.servers,security:n.security})}function $(t,e,n){return !n||t==="get"?null:e==="json"?{content:{"application/json":{schema:n}}}:e==="form"?{content:{"application/x-www-form-urlencoded":{schema:n}}}:null}function w(t,e,n){if(e&&(n==="query"&&t==="query"||n==="param"&&t==="param"))return e}function q(t){return t.replace(/:([A-Za-z0-9_]+)/g,"{$1}")}function z(t,e){let n=t.endsWith("/")?t.slice(0,-1):t,o=e.startsWith("/")?e:`/${e}`,r=`${n}${o}`;return r===""?"/":r}function Z(t,e){let n=e.replace(/[{}]/g,"").replace(/\/+/g,"_").replace(/[^A-Za-z0-9_]/g,"").replace(/^_+|_+$/g,"");return `${t}_${n||"root"}`}function E(t,e){let n=t.replace(/"/g,"&quot;");return `<!doctype html>
1
+ 'use strict';var hono=require('hono'),nodeServer=require('@hono/node-server'),zodToOpenapi=require('@asteasolutions/zod-to-openapi'),zod=require('zod'),async_hooks=require('async_hooks'),fs=require('fs'),path=require('path');var g=class extends Error{constructor(n,o){super("Request validation failed");this.zodError=n;this.source=o;this.statusCode=400;this.name="ValidationError";}};zodToOpenapi.extendZodWithOpenApi(zod.z);var D="Successful response";function N(t){return t==="get"?"query":"json"}function w(t,e,n){let o=new zodToOpenapi.OpenAPIRegistry;if(n.securitySchemes)for(let[i,a]of Object.entries(n.securitySchemes))o.registerComponent("securitySchemes",i,a);for(let i of t){let a=i.method,p=i.source??N(a),c=U(e,i.path??"/"),f=i.status??200,u=L(a,p,i.input),l=b(p,i.input,"query"),d=b(p,i.input,"param"),y=K(a,c);o.registerPath({method:a,path:G(c),operationId:y,summary:i.summary,description:i.description,tags:i.tags,deprecated:i.deprecated,security:i.security,request:{...l?{query:l}:{},...d?{params:d}:{},...u?{body:u}:{}},responses:i.output?{[f]:{description:D,content:{"application/json":{schema:i.output}}}}:{[f]:{description:D}}});}return new zodToOpenapi.OpenApiGeneratorV31(o.definitions).generateDocument({openapi:"3.1.0",info:n.info,servers:n.servers,security:n.security})}function L(t,e,n){return !n||t==="get"?null:e==="json"?{content:{"application/json":{schema:n}}}:e==="form"?{content:{"application/x-www-form-urlencoded":{schema:n}}}:null}function b(t,e,n){if(e&&(n==="query"&&t==="query"||n==="param"&&t==="param"))return e}function G(t){return t.replace(/:([A-Za-z0-9_]+)/g,"{$1}")}function U(t,e){let n=t.endsWith("/")?t.slice(0,-1):t,o=e.startsWith("/")?e:`/${e}`,r=`${n}${o}`;return r===""?"/":r}function K(t,e){let n=e.replace(/[{}]/g,"").replace(/\/+/g,"_").replace(/[^A-Za-z0-9_]/g,"").replace(/^_+|_+$/g,"");return `${t}_${n||"root"}`}function E(t,e){let n=t.replace(/"/g,"&quot;");return `<!doctype html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8" />
@@ -9,12 +9,12 @@
9
9
  <script id="api-reference" data-url="${n}"></script>
10
10
  <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
11
11
  </body>
12
- </html>`}var y=class{constructor(e){this.cachedSpec=null;this.options=e,this.app=new hono.Hono,this.mountedRoutes=L(e.routes,e.api);let n=[...e.middlewares??[],...e.globalMiddlewares??[]];for(let o of n)this.app.use("*",o);this.mountRoutes(),this.mountOpenApi(),e.notFound&&this.app.notFound(e.notFound),e.onError&&this.app.onError(e.onError);}get hono(){return this.app}get nodeHandler(){return nodeServer.getRequestListener(this.app.fetch,{overrideGlobalObjects:false})}toFunction(e,n){let o=this.nodeHandler;return n?e(n,o):e(o)}buildOpenApiSpec(){if(this.cachedSpec)return this.cachedSpec;if(!this.options.openapi)throw new Error("[HonoServer] openapi config not set");return this.cachedSpec=v(this.mountedRoutes,this.options.basePath??"",this.options.openapi),this.cachedSpec}mountRoutes(){let e=this.options.basePath??"",n=this.options.validateOutput??false,o=this.options.verbose??false;for(let r of this.mountedRoutes){if(!r.path)throw new Error(`[HonoServer] route "${r.method.toUpperCase()} (no path)" \u2014 missing \`path\`. Run the codegen so the path is derived from the file location, or set it explicitly.`);let i=A(e,r.path),s=r.middlewares??[],a=r.source??(r.method==="get"?"query":"json"),u=B(r,a,n,this.options.interceptor),p=r.method.toUpperCase();this.app.on(p,[i],...s,u),o&&console.log(`[HonoServer] ${r.method.toUpperCase().padEnd(6)} ${i}`);}}mountOpenApi(){let e=this.options.openapi;if(!e)return;let n=e.path??"/openapi.json",o=e.docsPath===void 0?"/docs":e.docsPath,r=A(this.options.basePath??"",n),i=o===false?null:A(this.options.basePath??"",o);if(this.app.get(r,s=>s.json(this.buildOpenApiSpec())),i){let s=U(i,r);this.app.get(i,a=>a.html(E(s,e.info.title)));}}};function L(t,e){return e?t.filter(n=>Array.isArray(n.api)?n.api.includes(e):n.api===e):t.slice()}function A(t,e){let n=t.endsWith("/")?t.slice(0,-1):t,o=e.startsWith("/")?e:`/${e}`,r=`${n}${o}`;return r===""?"/":r}function U(t,e){let n=t.split("/").filter(Boolean),o=e.split("/").filter(Boolean);n.pop();let r=0;for(;r<n.length&&r<o.length&&n[r]===o[r];)r++;let i=n.length-r;return [...Array(i).fill(".."),...o.slice(r)].join("/")||"./"}function B(t,e,n,o){let r=t.input,i=t.output,s=t.status??200;return async a=>{let u=async()=>{let c;if(r){let l;try{l=await W(a,e,t.method);}catch(g){throw new h(g instanceof Error?g.message:String(g))}let f=r.safeParse(l);if(!f.success)throw new m(f.error,e);c=f.data;}let d=await t.handler({input:c,c:a});if(n&&i&&!(d instanceof Response)){let l=i.safeParse(d);if(!l.success)throw new R(l.error);return l.data}return d},p;if(o)p=await o({next:u,route:t,c:a});else try{p=await u();}catch(c){let d=V(a,c);if(d)return d;throw c}return p instanceof Response?p:a.json(p,s)}}var h=class extends Error{constructor(n){super(n);this.statusCode=400;this.name="BadRequestError";}},R=class extends Error{constructor(n){super("Output validation failed");this.zodError=n;this.statusCode=500;this.name="OutputValidationError";}};function V(t,e){return e instanceof m?t.json({success:false,error:"Validation failed",issues:x(e.zodError)},400):e instanceof h?t.json({success:false,error:"Bad Request",message:e.message},400):e instanceof R?t.json({success:false,error:"Output validation failed",issues:x(e.zodError)},500):null}async function W(t,e,n){switch(e){case "json":{if(n==="get")return t.req.query();let o=await t.req.text();if(!o)return {};try{return JSON.parse(o)}catch(r){throw new Error(`Invalid JSON body: ${r instanceof Error?r.message:String(r)}`)}}case "query":return t.req.query();case "form":return await t.req.parseBody();case "param":return t.req.param();default:return {}}}function x(t){return t.issues.map(e=>({path:e.path.join("."),code:e.code,message:e.message}))}function J(t){return {configs:t,defineRoute(e){return e},serverFor(e,n){let o=t[e];if(!o)throw new Error(`[ApiRegistry] unknown api "${e}". Registered: ${Object.keys(t).join(", ")}`);return new y({...o,api:e,routes:n})},toFunctions(e,n,o){let r={};for(let i of Object.keys(t)){let s={...o?.defaults??{},...o?.per?.[i]??{}},a=new y({...t[i],api:i,routes:e});r[i]=Object.keys(s).length?a.toFunction(n,s):a.toFunction(n);}return r}}}var D={skipSegments:["useCases","useCase","use-cases","use-case"],casing:"preserve"};function P(t,e=D){let n=new Set(e.skipSegments.map(r=>r.toLowerCase()));return "/"+t.split("/").filter(Boolean).filter(r=>!n.has(r.toLowerCase())).map(r=>e.casing==="kebab"?K(r):r).join("/")}function K(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase()}function T(t,e,n){let o=O(t),r=O(e),i=0;for(;i<o.length&&i<r.length&&o[i]===r[i];)i++;let s=o.length-i,a=r.slice(i),p=(a[a.length-1]??"").replace(/\.[mc]?[tj]sx?$/i,""),c=n===""?p:`${p}${n}`;return a[a.length-1]=c,(s===0?"./":"../".repeat(s))+a.join("/")}function O(t){return t.replace(/\\/g,"/").replace(/\/+$/,"").split("/").filter((n,o)=>!(o===0&&n===""))}var b={routesFile:"routes.ts",excludeSegments:["node_modules","__generated__","tests","__tests__",".turbo","dist","build",".next"]};function ne(t,e=b){let n=[];return k(t,t,e,n),n.sort((o,r)=>o.relPath.localeCompare(r.relPath)),n}function k(t,e,n,o){let r;try{r=fs.readdirSync(e);}catch{return}for(let i of r){if(n.excludeSegments.includes(i))continue;let s=path.join(e,i),a;try{a=fs.statSync(s);}catch{continue}if(a.isDirectory())k(t,s,n,o);else if(a.isFile()&&i===n.routesFile){let u=path.relative(t,s).split(path.sep).join("/"),p=u.replace(/\/?[^/]+$/,"");o.push({absPath:s,relPath:u,relDir:p});}}}var M="/**\n * AUTO-GENERATED by `@lpdjs/firestore-repo-service` Hono codegen.\n * Do not edit by hand \u2014 re-run `hono:gen` after adding / removing route files.\n */\n";function I(t,e){let n=path.dirname(e.outFile);fs.mkdirSync(n,{recursive:true});let o=e.banner??M,r=(e.now??new Date).toISOString(),i=e.importExtension,s=[],a=[],u=[];t.forEach((c,d)=>{let l=T(n,c.absPath,i),f=P(c.relDir,e.derive);s.push(`import mod${d} from ${JSON.stringify(l)};`),a.push(` { __derivedPath: ${JSON.stringify(f)}, mod: mod${d} },`),u.push({source:c.relPath,url:f});});let p=`${o}// Generated at ${r} \u2014 ${t.length} route file${t.length===1?"":"s"}.
12
+ </html>`}var v=new async_hooks.AsyncLocalStorage,V=Object.freeze({get c(){let t=v.getStore();if(!t)throw new Error("[services] requestContext.c was accessed outside of a request. Wrap non-HTTP code paths (cron, triggers, scripts, tests) in `withRequestContext({ c }, () => ...)` to supply a Hono Context.");return t.c},get maybeC(){return v.getStore()?.c}});function T(){return async(t,e)=>{await v.run({c:t},async()=>{await e();});}}function W(t,e){return v.run({c:t.c},async()=>e())}var h="ctx";function J(t){let e=new Map,n=[],o=new Proxy({},{get(r,s){if(typeof s!="string"||s==="$types")return;if(s===h)return V;if(e.has(s))return e.get(s);let i=t[s];if(typeof i!="function")throw new Error(`[services] unknown service "${s}". Registered: ${[h,...Object.keys(t)].join(", ")}`);if(n.includes(s))throw new Error(`[services] circular dependency detected: ${[...n,s].join(" \u2192 ")}`);n.push(s);try{let a=i(o);return e.set(s,a),a}finally{n.pop();}},has(r,s){return typeof s!="string"?false:s===h||s in t},ownKeys(){return [h,...Object.keys(t)]},getOwnPropertyDescriptor(r,s){if(typeof s=="string"&&(s===h||s in t))return {enumerable:true,configurable:true}}});return o}var X=Object.freeze({$types:void 0}),m=class{constructor(e){this.cachedSpec=null;this.options=e,this.app=new hono.Hono,this.mountedRoutes=ee(e.routes,e.api),e.services&&this.app.use("*",T());let n=[...e.middlewares??[],...e.globalMiddlewares??[]];for(let o of n)this.app.use("*",o);this.mountRoutes(),this.mountOpenApi(),e.notFound&&this.app.notFound(e.notFound),e.onError&&this.app.onError(e.onError);}get hono(){return this.app}get nodeHandler(){return nodeServer.getRequestListener(this.app.fetch,{overrideGlobalObjects:false})}toFunction(e,n){let o=this.nodeHandler;return n?e(n,o):e(o)}buildOpenApiSpec(){if(this.cachedSpec)return this.cachedSpec;if(!this.options.openapi)throw new Error("[HonoServer] openapi config not set");return this.cachedSpec=w(this.mountedRoutes,this.options.basePath??"",this.options.openapi),this.cachedSpec}mountRoutes(){let e=this.options.basePath??"",n=this.options.validateOutput??false,o=this.options.verbose??false;for(let r of this.mountedRoutes){if(!r.path)throw new Error(`[HonoServer] route "${r.method.toUpperCase()} (no path)" \u2014 missing \`path\`. Run the codegen so the path is derived from the file location, or set it explicitly.`);let s=O(e,r.path),i=r.middlewares??[],a=r.source??(r.method==="get"?"query":"json"),p=ne(r,a,n,this.options.interceptor,this.options.services),c=r.method.toUpperCase();this.app.on(c,[s],...i,p),o&&console.log(`[HonoServer] ${r.method.toUpperCase().padEnd(6)} ${s}`);}}mountOpenApi(){let e=this.options.openapi;if(!e)return;let n=e.path??"/openapi.json",o=e.docsPath===void 0?"/docs":e.docsPath,r=O(this.options.basePath??"",n),s=o===false?null:O(this.options.basePath??"",o);if(this.app.get(r,i=>i.json(this.buildOpenApiSpec())),s){let i=te(s,r);this.app.get(s,a=>a.html(E(i,e.info.title)));}}};function ee(t,e){return e?t.filter(n=>Array.isArray(n.api)?n.api.includes(e):n.api===e):t.slice()}function O(t,e){let n=t.endsWith("/")?t.slice(0,-1):t,o=e.startsWith("/")?e:`/${e}`,r=`${n}${o}`;return r===""?"/":r}function te(t,e){let n=t.split("/").filter(Boolean),o=e.split("/").filter(Boolean);n.pop();let r=0;for(;r<n.length&&r<o.length&&n[r]===o[r];)r++;let s=n.length-r;return [...Array(s).fill(".."),...o.slice(r)].join("/")||"./"}function ne(t,e,n,o,r){let s=t.input,i=t.output,a=t.status??200,p=r??X;return async c=>{let f=async()=>{let l;if(s){let y;try{y=await oe(c,e,t.method);}catch(A){throw new R(A instanceof Error?A.message:String(A))}let x=s.safeParse(y);if(!x.success)throw new g(x.error,e);l=x.data;}let d=await t.handler({input:l,c,services:p});if(n&&i&&!(d instanceof Response)){let y=i.safeParse(d);if(!y.success)throw new S(y.error);return y.data}return d},u;if(o)u=await o({next:f,route:t,c,services:p});else try{u=await f();}catch(l){let d=re(c,l);if(d)return d;throw l}return u instanceof Response?u:c.json(u,a)}}var R=class extends Error{constructor(n){super(n);this.statusCode=400;this.name="BadRequestError";}},S=class extends Error{constructor(n){super("Output validation failed");this.zodError=n;this.statusCode=500;this.name="OutputValidationError";}};function re(t,e){return e instanceof g?t.json({success:false,error:"Validation failed",issues:F(e.zodError)},400):e instanceof R?t.json({success:false,error:"Bad Request",message:e.message},400):e instanceof S?t.json({success:false,error:"Output validation failed",issues:F(e.zodError)},500):null}async function oe(t,e,n){switch(e){case "json":{if(n==="get")return t.req.query();let o=await t.req.text();if(!o)return {};try{return JSON.parse(o)}catch(r){throw new Error(`Invalid JSON body: ${r instanceof Error?r.message:String(r)}`)}}case "query":return t.req.query();case "form":return await t.req.parseBody();case "param":return t.req.param();default:return {}}}function F(t){return t.issues.map(e=>({path:e.path.join("."),code:e.code,message:e.message}))}function se(t,e){let n=e?.services;return {configs:t,defineRoute(o){return o},serverFor(o,r){let s=t[o];if(!s)throw new Error(`[ApiRegistry] unknown api "${o}". Registered: ${Object.keys(t).join(", ")}`);return new m({...s,api:o,routes:r,services:n})},toFunctions(o,r,s){let i={};for(let a of Object.keys(t)){let p={...s?.defaults??{},...s?.per?.[a]??{}},c=new m({...t[a],api:a,routes:o,services:n});i[a]=Object.keys(p).length?c.toFunction(r,p):c.toFunction(r);}return i}}}var k={skipSegments:["useCases","useCase","use-cases","use-case"],casing:"preserve"};function P(t,e=k){let n=new Set(e.skipSegments.map(r=>r.toLowerCase()));return "/"+t.split("/").filter(Boolean).filter(r=>!n.has(r.toLowerCase())).map(r=>e.casing==="kebab"?ie(r):r).join("/")}function ie(t){return t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase()}function C(t,e,n){let o=M(t),r=M(e),s=0;for(;s<o.length&&s<r.length&&o[s]===r[s];)s++;let i=o.length-s,a=r.slice(s),c=(a[a.length-1]??"").replace(/\.[mc]?[tj]sx?$/i,""),f=n===""?c:`${c}${n}`;return a[a.length-1]=f,(i===0?"./":"../".repeat(i))+a.join("/")}function M(t){return t.replace(/\\/g,"/").replace(/\/+$/,"").split("/").filter((n,o)=>!(o===0&&n===""))}var H={routesFile:"routes.ts",excludeSegments:["node_modules","__generated__","tests","__tests__",".turbo","dist","build",".next"]};function fe(t,e=H){let n=[];return q(t,t,e,n),n.sort((o,r)=>o.relPath.localeCompare(r.relPath)),n}function q(t,e,n,o){let r;try{r=fs.readdirSync(e);}catch{return}for(let s of r){if(n.excludeSegments.includes(s))continue;let i=path.join(e,s),a;try{a=fs.statSync(i);}catch{continue}if(a.isDirectory())q(t,i,n,o);else if(a.isFile()&&s===n.routesFile){let p=path.relative(t,i).split(path.sep).join("/"),c=p.replace(/\/?[^/]+$/,"");o.push({absPath:i,relPath:p,relDir:c});}}}var _="/**\n * AUTO-GENERATED by `@lpdjs/firestore-repo-service` Hono codegen.\n * Do not edit by hand \u2014 re-run `hono:gen` after adding / removing route files.\n */\n";function I(t,e){let n=path.dirname(e.outFile);fs.mkdirSync(n,{recursive:true});let o=e.banner??_,r=(e.now??new Date).toISOString(),s=e.importExtension,i=[],a=[],p=[];t.forEach((f,u)=>{let l=C(n,f.absPath,s),d=P(f.relDir,e.derive);i.push(`import mod${u} from ${JSON.stringify(l)};`),a.push(` { __derivedPath: ${JSON.stringify(d)}, mod: mod${u} },`),p.push({source:f.relPath,url:d});});let c=`${o}// Generated at ${r} \u2014 ${t.length} route file${t.length===1?"":"s"}.
13
13
 
14
14
  import type { AnyRouteDef, RouteModuleDefault } from "@lpdjs/firestore-repo-service/servers/hono";
15
15
 
16
- `+s.join(`
17
- `)+(s.length?`
16
+ `+i.join(`
17
+ `)+(i.length?`
18
18
 
19
19
  `:`
20
20
  `)+`const __defs: { __derivedPath: string; mod: RouteModuleDefault }[] = [
@@ -26,5 +26,5 @@ export const routes: AnyRouteDef[] = __defs.flatMap(({ __derivedPath, mod }) =>
26
26
  const list = Array.isArray(mod) ? mod : [mod];
27
27
  return list.map((route) => ({ ...route, path: route.path ?? __derivedPath }));
28
28
  });
29
- `;return fs.writeFileSync(e.outFile,p,"utf8"),{outFile:e.outFile,routeCount:t.length,derivedPaths:u}}function ae(t,e,n,o,r){let i=r(t),s=path.join(t,e);return I(i,{outFile:s,derive:n,importExtension:o})}exports.DEFAULT_DERIVE=D;exports.DEFAULT_GENERATOR_BANNER=M;exports.DEFAULT_SCANNER=b;exports.HonoServer=y;exports.ValidationError=m;exports.buildOpenApiDocument=v;exports.createApiRegistry=J;exports.derivePath=P;exports.generateFromRoot=ae;exports.generateRoutesManifest=I;exports.renderDocsHtml=E;exports.scanRoutes=ne;exports.toImportSpecifier=T;//# sourceMappingURL=index.cjs.map
29
+ `;return fs.writeFileSync(e.outFile,c,"utf8"),{outFile:e.outFile,routeCount:t.length,derivedPaths:p}}function he(t,e,n,o,r){let s=r(t),i=path.join(t,e);return I(s,{outFile:i,derive:n,importExtension:o})}exports.DEFAULT_DERIVE=k;exports.DEFAULT_GENERATOR_BANNER=_;exports.DEFAULT_SCANNER=H;exports.HonoServer=m;exports.ValidationError=g;exports.buildOpenApiDocument=w;exports.createApiRegistry=se;exports.createRequestContextMiddleware=T;exports.createServices=J;exports.derivePath=P;exports.generateFromRoot=he;exports.generateRoutesManifest=I;exports.renderDocsHtml=E;exports.scanRoutes=fe;exports.toImportSpecifier=C;exports.withRequestContext=W;//# sourceMappingURL=index.cjs.map
30
30
  //# sourceMappingURL=index.cjs.map