@lpdjs/firestore-repo-service 2.6.6 → 2.6.8

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,4 +1,4 @@
1
- import { d as CrudRepoRegistry, O as OpenAPISpecOptions } from './types-CeyFvYXO.js';
1
+ import { d as CrudRepoRegistry, O as OpenAPISpecOptions } from './types-n7q6N_Zw.js';
2
2
 
3
3
  /**
4
4
  * OpenAPI 3.1 specification generator for the CRUD server.
@@ -1,4 +1,4 @@
1
- import { d as CrudRepoRegistry, O as OpenAPISpecOptions } from './types-KYdNUffK.cjs';
1
+ import { d as CrudRepoRegistry, O as OpenAPISpecOptions } from './types-B7KFW9S9.cjs';
2
2
 
3
3
  /**
4
4
  * OpenAPI 3.1 specification generator for the CRUD server.
@@ -1,8 +1,8 @@
1
1
  import 'zod';
2
2
  import 'firebase-functions/v2/https';
3
- import '../../types-KYdNUffK.cjs';
3
+ import '../../types-B7KFW9S9.cjs';
4
4
  export { h as Middleware, M as MiniRouter, R as RouteHandler } from '../../firebase-auth-BTclYg-c.cjs';
5
- export { a as AdminRepoConfig, b as AdminRepoEntry, A as AdminServerOptions, B as BasicAuthConfig, c as RepoRegistry, d as createAdminServer } from '../../index-BuxFmMV8.cjs';
5
+ export { a as AdminRepoConfig, b as AdminRepoEntry, A as AdminServerOptions, B as BasicAuthConfig, c as RepoRegistry, d as createAdminServer } from '../../index-BOYhux7q.cjs';
6
6
  import '../../read-CTWZjxyh.cjs';
7
7
  import 'firebase-admin/firestore';
8
8
  import 'firebase-functions/v2/firestore';
@@ -1,8 +1,8 @@
1
1
  import 'zod';
2
2
  import 'firebase-functions/v2/https';
3
- import '../../types-CeyFvYXO.js';
3
+ import '../../types-n7q6N_Zw.js';
4
4
  export { h as Middleware, M as MiniRouter, R as RouteHandler } from '../../firebase-auth-BTclYg-c.js';
5
- export { a as AdminRepoConfig, b as AdminRepoEntry, A as AdminServerOptions, B as BasicAuthConfig, c as RepoRegistry, d as createAdminServer } from '../../index-BM1mgnpJ.js';
5
+ export { a as AdminRepoConfig, b as AdminRepoEntry, A as AdminServerOptions, B as BasicAuthConfig, c as RepoRegistry, d as createAdminServer } from '../../index-BRjxlxWa.js';
6
6
  import '../../read-CTWZjxyh.js';
7
7
  import 'firebase-admin/firestore';
8
8
  import 'firebase-functions/v2/firestore';
@@ -1,8 +1,8 @@
1
1
  import { HttpsOptions } from 'firebase-functions/v2/https';
2
- import { C as ConfiguredRepository, a as CrudServerOptions } from '../../types-KYdNUffK.cjs';
3
- export { A as ApiResponse, B as BasicAuthConfig, b as CrudRepoConfig, c as CrudRepoEntry, d as CrudRepoRegistry, F as FieldRole, L as ListResponseData, M as Middleware, O as OpenAPISpecOptions, Q as QueryRequestBody, R as RepoFieldPath, e as RepoRelationKeys, U as UserFieldPath } from '../../types-KYdNUffK.cjs';
4
- import { O as OpenAPIDocument } from '../../openapi-DpMtzJGo.cjs';
5
- export { g as generateOpenAPISpec } from '../../openapi-DpMtzJGo.cjs';
2
+ import { C as ConfiguredRepository, a as CrudServerOptions } from '../../types-B7KFW9S9.cjs';
3
+ export { A as ApiResponse, B as BasicAuthConfig, b as CrudRepoConfig, c as CrudRepoEntry, d as CrudRepoRegistry, F as FieldRole, L as ListResponseData, M as Middleware, O as OpenAPISpecOptions, Q as QueryRequestBody, R as RepoFieldPath, e as RepoRelationKeys, U as UserFieldPath } from '../../types-B7KFW9S9.cjs';
4
+ import { O as OpenAPIDocument } from '../../openapi-Cci3oqin.cjs';
5
+ export { g as generateOpenAPISpec } from '../../openapi-Cci3oqin.cjs';
6
6
  import '../../firebase-auth-BTclYg-c.cjs';
7
7
  import 'zod';
8
8
  import '../../read-CTWZjxyh.cjs';
@@ -1,8 +1,8 @@
1
1
  import { HttpsOptions } from 'firebase-functions/v2/https';
2
- import { C as ConfiguredRepository, a as CrudServerOptions } from '../../types-CeyFvYXO.js';
3
- export { A as ApiResponse, B as BasicAuthConfig, b as CrudRepoConfig, c as CrudRepoEntry, d as CrudRepoRegistry, F as FieldRole, L as ListResponseData, M as Middleware, O as OpenAPISpecOptions, Q as QueryRequestBody, R as RepoFieldPath, e as RepoRelationKeys, U as UserFieldPath } from '../../types-CeyFvYXO.js';
4
- import { O as OpenAPIDocument } from '../../openapi-ChZojCEO.js';
5
- export { g as generateOpenAPISpec } from '../../openapi-ChZojCEO.js';
2
+ import { C as ConfiguredRepository, a as CrudServerOptions } from '../../types-n7q6N_Zw.js';
3
+ export { A as ApiResponse, B as BasicAuthConfig, b as CrudRepoConfig, c as CrudRepoEntry, d as CrudRepoRegistry, F as FieldRole, L as ListResponseData, M as Middleware, O as OpenAPISpecOptions, Q as QueryRequestBody, R as RepoFieldPath, e as RepoRelationKeys, U as UserFieldPath } from '../../types-n7q6N_Zw.js';
4
+ import { O as OpenAPIDocument } from '../../openapi-BnVlzg59.js';
5
+ export { g as generateOpenAPISpec } from '../../openapi-BnVlzg59.js';
6
6
  import '../../firebase-auth-BTclYg-c.js';
7
7
  import 'zod';
8
8
  import '../../read-CTWZjxyh.js';
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- 'use strict';var fs=require('fs'),path=require('path'),process$1=require('process'),promises=require('readline/promises');var O={skipSegments:["useCases","useCase","use-cases","use-case"],casing:"preserve"};function M(e,t=O){let s=new Set(t.skipSegments.map(o=>o.toLowerCase()));return "/"+e.split("/").filter(Boolean).filter(o=>!s.has(o.toLowerCase())).map(o=>t.casing==="kebab"?se(o):o).join("/")}function se(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase()}function H(e,t,s){let r=B(e),o=B(t),n=0;for(;n<r.length&&n<o.length&&r[n]===o[n];)n++;let c=r.length-n,i=o.slice(n),d=(i[i.length-1]??"").replace(/\.[mc]?[tj]sx?$/i,""),f=s===""?d:`${d}${s}`;return i[i.length-1]=f,(c===0?"./":"../".repeat(c))+i.join("/")}function B(e){return e.replace(/\\/g,"/").replace(/\/+$/,"").split("/").filter((s,r)=>!(r===0&&s===""))}var ne="/**\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 W(e,t){let s=path.dirname(t.outFile);fs.mkdirSync(s,{recursive:true});let r=t.banner??ne,o=(t.now??new Date).toISOString(),n=t.importExtension,c=[],i=[],a=[];e.forEach((f,u)=>{let x=H(s,f.absPath,n),v=M(f.relDir,t.derive);c.push(`import mod${u} from ${JSON.stringify(x)};`),i.push(` { __derivedPath: ${JSON.stringify(v)}, mod: mod${u} },`),a.push({source:f.relPath,url:v});});let d=`${r}// Generated at ${o} \u2014 ${e.length} route file${e.length===1?"":"s"}.
2
+ 'use strict';var fs=require('fs'),path=require('path'),process$1=require('process'),promises=require('readline/promises');var O={skipSegments:["useCases","useCase","use-cases","use-case"],casing:"preserve"};function M(e,t=O){let s=new Set(t.skipSegments.map(o=>o.toLowerCase()));return "/"+e.split("/").filter(Boolean).filter(o=>!s.has(o.toLowerCase())).map(o=>t.casing==="kebab"?re(o):o).join("/")}function re(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/[\s_]+/g,"-").toLowerCase()}function H(e,t,s){let r=B(e),o=B(t),n=0;for(;n<r.length&&n<o.length&&r[n]===o[n];)n++;let c=r.length-n,i=o.slice(n),d=(i[i.length-1]??"").replace(/\.[mc]?[tj]sx?$/i,""),f=s===""?d:`${d}${s}`;return i[i.length-1]=f,(c===0?"./":"../".repeat(c))+i.join("/")}function B(e){return e.replace(/\\/g,"/").replace(/\/+$/,"").split("/").filter((s,r)=>!(r===0&&s===""))}var ce="/**\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 W(e,t){let s=path.dirname(t.outFile);fs.mkdirSync(s,{recursive:true});let r=t.banner??ce,o=(t.now??new Date).toISOString(),n=t.importExtension,c=[],i=[],a=[];e.forEach((f,u)=>{let b=H(s,f.absPath,n),v=M(f.relDir,t.derive);c.push(`import mod${u} from ${JSON.stringify(b)};`),i.push(` { __derivedPath: ${JSON.stringify(v)}, mod: mod${u} },`),a.push({source:f.relPath,url:v});});let d=`${r}// Generated at ${o} \u2014 ${e.length} route file${e.length===1?"":"s"}.
3
3
 
4
4
  import type { AnyRouteDef, RouteModuleDefault } from "@lpdjs/firestore-repo-service/servers/hono";
5
5
 
@@ -16,8 +16,8 @@ export const routes: AnyRouteDef[] = __defs.flatMap(({ __derivedPath, mod }) =>
16
16
  const list = Array.isArray(mod) ? mod : [mod];
17
17
  return list.map((route) => ({ ...route, path: route.path ?? __derivedPath }));
18
18
  });
19
- `;return fs.writeFileSync(t.outFile,d,"utf8"),{outFile:t.outFile,routeCount:e.length,derivedPaths:a}}var I={routesFile:"routes.ts",excludeSegments:["node_modules","__generated__","tests","__tests__",".turbo","dist","build",".next"]};function J(e,t=I){let s=[];return K(e,e,t,s),s.sort((r,o)=>r.relPath.localeCompare(o.relPath)),s}function K(e,t,s,r){let o;try{o=fs.readdirSync(t);}catch{return}for(let n of o){if(s.excludeSegments.includes(n))continue;let c=path.join(t,n),i;try{i=fs.statSync(c);}catch{continue}if(i.isDirectory())K(e,c,s,r);else if(i.isFile()&&n===s.routesFile){let a=path.relative(e,c).split(path.sep).join("/"),d=a.replace(/\/?[^/]+$/,"");r.push({absPath:c,relPath:a,relDir:d});}}}var X=".frsrc.json";function T(e=process.cwd()){let t=path.resolve(e,X);if(!fs.existsSync(t))return {};try{return JSON.parse(fs.readFileSync(t,"utf8"))}catch{return {}}}function me(e,t=process.cwd()){let s=path.resolve(t,X),o={...T(t),...e};return fs.writeFileSync(s,`${JSON.stringify(o,null,2)}
20
- `,"utf8"),s}function ge(e){let[t,...s]=e,r={};for(let o=0;o<s.length;o++){let n=s[o];if(!n.startsWith("--"))continue;let c=n.slice(2),i=s[o+1];i&&!i.startsWith("--")?(r[c]=i,o++):r[c]=true;}return {command:t??"help",flags:r}}function Y(){console.log(`frs \u2014 Hono file-based codegen
19
+ `;return fs.writeFileSync(t.outFile,d,"utf8"),{outFile:t.outFile,routeCount:e.length,derivedPaths:a}}var I={routesFile:"routes.ts",excludeSegments:["node_modules","__generated__","tests","__tests__",".turbo","dist","build",".next"]};function J(e,t=I){let s=[];return K(e,e,t,s),s.sort((r,o)=>r.relPath.localeCompare(o.relPath)),s}function K(e,t,s,r){let o;try{o=fs.readdirSync(t);}catch{return}for(let n of o){if(s.excludeSegments.includes(n))continue;let c=path.join(t,n),i;try{i=fs.statSync(c);}catch{continue}if(i.isDirectory())K(e,c,s,r);else if(i.isFile()&&n===s.routesFile){let a=path.relative(e,c).split(path.sep).join("/"),d=a.replace(/\/?[^/]+$/,"");r.push({absPath:c,relPath:a,relDir:d});}}}var X=".frsrc.json";function T(e=process.cwd()){let t=path.resolve(e,X);if(!fs.existsSync(t))return {};try{return JSON.parse(fs.readFileSync(t,"utf8"))}catch{return {}}}function ge(e,t=process.cwd()){let s=path.resolve(t,X),o={...T(t),...e};return fs.writeFileSync(s,`${JSON.stringify(o,null,2)}
20
+ `,"utf8"),s}function he(e){let[t,...s]=e,r={};for(let o=0;o<s.length;o++){let n=s[o];if(!n.startsWith("--"))continue;let c=n.slice(2),i=s[o+1];i&&!i.startsWith("--")?(r[c]=i,o++):r[c]=true;}return {command:t??"help",flags:r}}function Y(){console.log(`frs \u2014 Hono file-based codegen
21
21
 
22
22
  Usage:
23
23
  frs init [flags]
@@ -62,8 +62,10 @@ Flags (new <name>):
62
62
  --usecase-folder <name>
63
63
  Parent folder under <domain>.
64
64
  Default: .frsrc.json "useCaseFolder" or useCases
65
- --with-usecase Also scaffold a sibling useCase.ts file (default: true)
66
- --with-test Also scaffold a sibling useCase.test.ts (Vitest, default: true)
65
+ --with-usecase Also scaffold a sibling <domain>.<name>.useCase.ts file
66
+ (default: true)
67
+ --with-test Also scaffold a sibling <domain>.<name>.useCase.test.ts
68
+ (Vitest, default: true)
67
69
  --apis-import <path> Import path for the registry (default: auto-detect
68
70
  ../../../../apis.js \u2014 adjust if your layout differs)
69
71
  --force Overwrite if files already exist
@@ -81,8 +83,8 @@ Examples:
81
83
  frs new createPost --domain posts --method post
82
84
  frs new listPosts --domain posts --method get --api v1
83
85
  frs add service postRepo
84
- `);}function Z(e){if(typeof e=="string")return e.split(",").map(t=>t.trim()).filter(Boolean)}function m(e){return typeof e=="string"?e:void 0}function ee(e){if(e||!process$1.stdin.isTTY)return {ask:async(s,r)=>r??"",askChoice:async(s,r,o)=>o??"",askBool:async(s,r)=>r,close:()=>{}};let t=promises.createInterface({input:process$1.stdin,output:process$1.stdout});return {async ask(s,r){let o=r?` (${r})`:"";return (await t.question(`? ${s}${o} \u203A `)).trim()||r||""},async askChoice(s,r,o){let n=` [${r.join("/")}${o?`, default: ${o}`:""}]`;for(;;){let c=(await t.question(`? ${s}${n} \u203A `)).trim().toLowerCase();if(!c&&o)return o;if(r.includes(c))return c;console.log(` invalid choice \u2014 pick one of: ${r.join(", ")}`);}},async askBool(s,r){let o=` (${r?"Y/n":"y/N"})`,n=(await t.question(`? ${s}${o} \u203A `)).trim().toLowerCase();return n?n==="y"||n==="yes"||n==="true":r},close:()=>t.close()}}async function he(e){let t=T(),s=m(e.root)??t.root;s||(console.error("[frs] --root is required (or run `frs init` to write it to .frsrc.json)"),process.exit(2));let r=path.resolve(process.cwd(),s);fs.existsSync(r)||(console.error(`[frs] root not found: ${r}`),process.exit(2));let o=m(e.out)??t.out??"__generated__/routes.ts",n=Z(e.skip)??O.skipSegments,c=m(e.casing)==="kebab"?"kebab":O.casing,i={skipSegments:n,casing:c},a=m(e.ext)??".js",d=Z(e.exclude)??I.excludeSegments,f=m(e["routes-file"])??I.routesFile,x=J(r,{routesFile:f,excludeSegments:d});x.length===0&&console.warn(`[frs] no "${f}" files found under ${r} \u2014 generated an empty manifest.`);let v=W(x,{outFile:path.resolve(r,o),derive:i,importExtension:a});if(!e.silent){console.log(`[frs] wrote ${v.outFile} (${v.routeCount} route${v.routeCount===1?"":"s"})`);for(let{source:S,url:g}of v.derivedPaths)console.log(` ${g.padEnd(48)} \u2190 ${S}`);}}async function ve(e,t){let s=t.yes===true,r=ee(s),o=T();try{let n=e&&!e.startsWith("--")?e:void 0;n||(n=(await r.ask("Route name (e.g. createPost)")).trim(),n||(console.error("[frs] route name is required"),process.exit(2)));let c=m(t.domain);c||(c=(await r.ask("Domain name (e.g. posts)")).trim(),c||(console.error("[frs] --domain is required"),process.exit(2)));let i=m(t.root)??o.root??"src/domains",a=m(t.method)?.toLowerCase();a||(a=await r.askChoice("HTTP method",["get","post","put","patch","delete"],"post")),["get","post","put","patch","delete"].includes(a)||(console.error(`[frs] invalid --method: ${a}`),process.exit(2));let d=m(t.api);if(!d){let $=o.apis?.[0]??"v1";d=(await r.ask("API tag",$)).trim()||$;}let f=m(t["usecase-folder"])??o.useCaseFolder??"useCases",u=t["with-usecase"]===void 0?s?!0:await r.askBool("Scaffold useCase.ts?",!0):t["with-usecase"]!==!1,x=t["with-test"]===void 0?s||!u?u:await r.askBool("Scaffold useCase.test.ts (Vitest)?",!0):t["with-test"]!==!1,v=t.force===!0,S=path.resolve(process.cwd(),i),g=path.resolve(S,c,f,n),D=path.resolve(g,"routes.ts"),b=path.resolve(g,"useCase.ts"),k=path.resolve(g,"useCase.test.ts");fs.mkdirSync(g,{recursive:!0});let y=`${n.charAt(0).toUpperCase()}${n.slice(1)}UseCase`,P="@lpdjs/firestore-repo-service/servers/hono",F=xe(S,g),_=a==="get"?"// GET \u2192 lu depuis les query params":`// ${a.toUpperCase()} \u2192 lu depuis le body JSON`,h=`/**
85
- * ${y} \u2014 pure business logic, no HTTP awareness.
86
+ `);}function Z(e){if(typeof e=="string")return e.split(",").map(t=>t.trim()).filter(Boolean)}function m(e){return typeof e=="string"?e:void 0}function ee(e){if(e||!process$1.stdin.isTTY)return {ask:async(s,r)=>r??"",askChoice:async(s,r,o)=>o??"",askBool:async(s,r)=>r,close:()=>{}};let t=promises.createInterface({input:process$1.stdin,output:process$1.stdout});return {async ask(s,r){let o=r?` (${r})`:"";return (await t.question(`? ${s}${o} \u203A `)).trim()||r||""},async askChoice(s,r,o){let n=` [${r.join("/")}${o?`, default: ${o}`:""}]`;for(;;){let c=(await t.question(`? ${s}${n} \u203A `)).trim().toLowerCase();if(!c&&o)return o;if(r.includes(c))return c;console.log(` invalid choice \u2014 pick one of: ${r.join(", ")}`);}},async askBool(s,r){let o=` (${r?"Y/n":"y/N"})`,n=(await t.question(`? ${s}${o} \u203A `)).trim().toLowerCase();return n?n==="y"||n==="yes"||n==="true":r},close:()=>t.close()}}async function ve(e){let t=T(),s=m(e.root)??t.root;s||(console.error("[frs] --root is required (or run `frs init` to write it to .frsrc.json)"),process.exit(2));let r=path.resolve(process.cwd(),s);fs.existsSync(r)||(console.error(`[frs] root not found: ${r}`),process.exit(2));let o=m(e.out)??t.out??"__generated__/routes.ts",n=Z(e.skip)??O.skipSegments,c=m(e.casing)==="kebab"?"kebab":O.casing,i={skipSegments:n,casing:c},a=m(e.ext)??".js",d=Z(e.exclude)??I.excludeSegments,f=m(e["routes-file"])??I.routesFile,b=J(r,{routesFile:f,excludeSegments:d});b.length===0&&console.warn(`[frs] no "${f}" files found under ${r} \u2014 generated an empty manifest.`);let v=W(b,{outFile:path.resolve(r,o),derive:i,importExtension:a});if(!e.silent){console.log(`[frs] wrote ${v.outFile} (${v.routeCount} route${v.routeCount===1?"":"s"})`);for(let{source:S,url:g}of v.derivedPaths)console.log(` ${g.padEnd(48)} \u2190 ${S}`);}}async function ye(e,t){let s=t.yes===true,r=ee(s),o=T();try{let n=e&&!e.startsWith("--")?e:void 0;n||(n=(await r.ask("Route name (e.g. createPost)")).trim(),n||(console.error("[frs] route name is required"),process.exit(2)));let c=m(t.domain);c||(c=(await r.ask("Domain name (e.g. posts)")).trim(),c||(console.error("[frs] --domain is required"),process.exit(2)));let i=m(t.root)??o.root??"src/domains",a=m(t.method)?.toLowerCase();a||(a=await r.askChoice("HTTP method",["get","post","put","patch","delete"],"post")),["get","post","put","patch","delete"].includes(a)||(console.error(`[frs] invalid --method: ${a}`),process.exit(2));let d=m(t.api);if(!d){let $=o.apis?.[0]??"v1";d=(await r.ask("API tag",$)).trim()||$;}let f=m(t["usecase-folder"])??o.useCaseFolder??"useCases",u=t["with-usecase"]===void 0?s?!0:await r.askBool("Scaffold useCase.ts?",!0):t["with-usecase"]!==!1,b=t["with-test"]===void 0?s||!u?u:await r.askBool("Scaffold useCase.test.ts (Vitest)?",!0):t["with-test"]!==!1,v=t.force===!0,S=path.resolve(process.cwd(),i),g=path.resolve(S,c,f,n),D=path.resolve(g,"routes.ts"),y=`${c}.${n}.useCase`,k=path.resolve(g,`${y}.ts`),F=path.resolve(g,`${y}.test.ts`);fs.mkdirSync(g,{recursive:!0});let w=`${n.charAt(0).toUpperCase()}${n.slice(1)}UseCase`,P="@lpdjs/firestore-repo-service/servers/hono",_=be(S,g),h=a==="get"?"// GET \u2192 lu depuis les query params":`// ${a.toUpperCase()} \u2192 lu depuis le body JSON`,C=`/**
87
+ * ${w} \u2014 pure business logic, no HTTP awareness.
86
88
  *
87
89
  * Owns its Zod \`input\` / \`output\` schemas (declared as \`static\` members, the
88
90
  * single source of truth shared with \`routes.ts\`) and runs the logic in
@@ -92,10 +94,10 @@ Examples:
92
94
 
93
95
  import { z } from "zod";
94
96
  import { UseCase } from "${P}";
95
- import type { Services } from "${F}";
97
+ import type { Services } from "${_}";
96
98
 
97
99
  const input = z.object({
98
- ${_}
100
+ ${h}
99
101
  example: z.string(),
100
102
  });
101
103
 
@@ -103,7 +105,7 @@ const output = z.object({
103
105
  id: z.string(),
104
106
  });
105
107
 
106
- export class ${y} extends UseCase<typeof input, typeof output, Services> {
108
+ export class ${w} extends UseCase<typeof input, typeof output, Services> {
107
109
  static readonly input = input;
108
110
  static readonly output = output;
109
111
 
@@ -114,22 +116,22 @@ export class ${y} extends UseCase<typeof input, typeof output, Services> {
114
116
  return { id: payload.example };
115
117
  }
116
118
  }
117
- `,C=a==="get"?`
118
- source: "query",`:"",N=u?`import { ${y} } from "./useCase.js";
119
- `:"",p=m(t["apis-import"])??we(S,g),j=u?`import { defineRoutes } from "${P}";
120
- import { useCaseRoute } from "${p}";
121
- ${N}
119
+ `,N=a==="get"?`
120
+ source: "query",`:"",l=u?`import { ${w} } from "./${y}.js";
121
+ `:"",j=m(t["apis-import"])??xe(S,g),te=u?`import { defineRoutes } from "${P}";
122
+ import { useCaseRoute } from "${j}";
123
+ ${l}
122
124
  export default defineRoutes([
123
- useCaseRoute(${y}, {
125
+ useCaseRoute(${w}, {
124
126
  api: "${d}",
125
- method: "${a}",${C}
127
+ method: "${a}",${N}
126
128
  summary: "TODO: ${n}",
127
129
  tags: ["${c}"],
128
130
  }),
129
131
  ]);
130
132
  `:`import { z } from "zod";
131
133
  import { defineRoutes } from "${P}";
132
- import { defineRoute } from "${p}";
134
+ import { defineRoute } from "${j}";
133
135
 
134
136
  export default defineRoutes([
135
137
  defineRoute({
@@ -137,7 +139,7 @@ export default defineRoutes([
137
139
  method: "${a}",
138
140
 
139
141
  input: z.object({
140
- ${_}
142
+ ${h}
141
143
  example: z.string(),
142
144
  }),
143
145
 
@@ -154,32 +156,32 @@ export default defineRoutes([
154
156
  },
155
157
  }),
156
158
  ]);
157
- `,z=[],G=[],q=($,te)=>{if(fs.existsSync($)&&!v){G.push($);return}fs.writeFileSync($,te,"utf8"),z.push($);};if(q(D,j),u&&q(b,h),u&&x){let $=`import { describe, it, expect } from "vitest";
158
- import type { Services } from "${F}";
159
- import { ${y} } from "./useCase.js";
159
+ `,z=[],G=[],q=($,se)=>{if(fs.existsSync($)&&!v){G.push($);return}fs.writeFileSync($,se,"utf8"),z.push($);};if(q(D,te),u&&q(k,C),u&&b){let $=`import { describe, it, expect } from "vitest";
160
+ import type { Services } from "${_}";
161
+ import { ${w} } from "./${y}.js";
160
162
 
161
- describe("${y}", () => {
163
+ describe("${w}", () => {
162
164
  it("returns a response shaped like the output schema", async () => {
163
165
  // TODO: replace with real mocks for the services the useCase consumes.
164
166
  const services = {} as unknown as Services;
165
167
 
166
- const useCase = new ${y}(services);
168
+ const useCase = new ${w}(services);
167
169
  const result = await useCase.execute({ example: "hello" });
168
170
  expect(result).toMatchObject({ id: expect.any(String) });
169
171
  });
170
172
 
171
173
  // TODO: add error-path tests, repository mocks, etc.
172
174
  });
173
- `;q(k,$);}for(let $ of z)console.log(`[frs] wrote ${$}`);for(let $ of G)console.log(`[frs] skipped ${$} (use --force to overwrite)`);console.log(`
174
- [frs] reminder: run "frs gen --root ${i}" to refresh the manifest.`);}finally{r.close();}}async function ye(e){let t=e.yes===true,s=ee(t);try{let r=e.force===!0,o=m(e.root);o||(o=(await s.ask("Domain root","src/domains")).trim()||"src/domains");let n=m(e["apis-file"]);n||(n=(await s.ask("apis.ts location","src/apis.ts")).trim()||"src/apis.ts");let c=m(e["services-file"]);if(!c){let p=n.replace(/apis\.ts$/,"services.ts")||"src/services.ts";c=(await s.ask("services.ts location",p)).trim()||p;}let i=m(e.apis);i||(i=(await s.ask("API tags (comma-separated)","v1")).trim()||"v1");let a=i.split(",").map(p=>p.trim()).filter(Boolean);a.length===0&&(console.error("[frs] at least one API tag is required"),process.exit(2));let d=m(e["base-path"]),f=path.resolve(process.cwd(),o),u=path.resolve(process.cwd(),n),x=path.resolve(process.cwd(),c),v=path.resolve(f,"__generated__"),S=path.resolve(v,"routes.ts"),g=[],D=[],b=(p,j)=>{if(fs.mkdirSync(path.dirname(p),{recursive:!0}),fs.existsSync(p)&&!r){D.push(p);return}fs.writeFileSync(p,j,"utf8"),g.push(p);},k=a.map(p=>{let j=d??`/${p}`;return ` ${p}: {
175
+ `;q(F,$);}for(let $ of z)console.log(`[frs] wrote ${$}`);for(let $ of G)console.log(`[frs] skipped ${$} (use --force to overwrite)`);console.log(`
176
+ [frs] reminder: run "frs gen --root ${i}" to refresh the manifest.`);}finally{r.close();}}async function $e(e){let t=e.yes===true,s=ee(t);try{let r=e.force===!0,o=m(e.root);o||(o=(await s.ask("Domain root","src/domains")).trim()||"src/domains");let n=m(e["apis-file"]);n||(n=(await s.ask("apis.ts location","src/apis.ts")).trim()||"src/apis.ts");let c=m(e["services-file"]);if(!c){let l=n.replace(/apis\.ts$/,"services.ts")||"src/services.ts";c=(await s.ask("services.ts location",l)).trim()||l;}let i=m(e.apis);i||(i=(await s.ask("API tags (comma-separated)","v1")).trim()||"v1");let a=i.split(",").map(l=>l.trim()).filter(Boolean);a.length===0&&(console.error("[frs] at least one API tag is required"),process.exit(2));let d=m(e["base-path"]),f=path.resolve(process.cwd(),o),u=path.resolve(process.cwd(),n),b=path.resolve(process.cwd(),c),v=path.resolve(f,"__generated__"),S=path.resolve(v,"routes.ts"),g=[],D=[],y=(l,j)=>{if(fs.mkdirSync(path.dirname(l),{recursive:!0}),fs.existsSync(l)&&!r){D.push(l);return}fs.writeFileSync(l,j,"utf8"),g.push(l);},k=a.map(l=>{let j=d??`/${l}`;return ` ${l}: {
175
177
  basePath: "${j}",
176
178
  openapi: {
177
- info: { title: "${p.toUpperCase()} API", version: "1.0.0", description: "" },
179
+ info: { title: "${l.toUpperCase()} API", version: "1.0.0", description: "" },
178
180
  },
179
181
  verbose: process.env["NODE_ENV"] !== "production",
180
182
  },`}).join(`
181
- `),y=`import { createApiRegistry } from "@lpdjs/firestore-repo-service/servers/hono";
182
- import { services } from "${E(path.dirname(u),x)}";
183
+ `),F=`import { createApiRegistry } from "@lpdjs/firestore-repo-service/servers/hono";
184
+ import { services } from "${E(path.dirname(u),b)}";
183
185
 
184
186
  /**
185
187
  * Single source of truth for every API exposed by this project.
@@ -199,7 +201,7 @@ ${k}
199
201
  /** Typed helpers used inside every route file. */
200
202
  export const defineRoute = apis.defineRoute;
201
203
  export const useCaseRoute = apis.useCaseRoute;
202
- `;b(u,y),b(x,`import { createServices } from "@lpdjs/firestore-repo-service/servers/hono";
204
+ `;y(u,F),y(b,`import { createServices } from "@lpdjs/firestore-repo-service/servers/hono";
203
205
 
204
206
  /**
205
207
  * Global DI container \u2014 declare every singleton (repositories, SDK
@@ -232,13 +234,13 @@ export const services = createServices({
232
234
 
233
235
  /** Convenience type \u2014 \`function fn(svc: Services) { ... }\`. */
234
236
  export type Services = typeof services;
235
- `);let F=`// AUTO-GENERATED by frs \u2014 do not edit.
237
+ `);let P=`// AUTO-GENERATED by frs \u2014 do not edit.
236
238
  // Run \`frs gen --root ${o}\` to refresh.
237
239
 
238
240
  import type { AnyRouteDef } from "@lpdjs/firestore-repo-service/servers/hono";
239
241
 
240
242
  export const routes: AnyRouteDef[] = [];
241
- `;b(S,F);let _=me({root:o,apisFile:n,servicesFile:c,apis:a});g.push(_);let h=E(path.dirname(u),u),C=E(path.dirname(u),S),N=a.length===1?`export const { ${a[0]} } = apis.toFunctions(routes, onRequest, {`:`export const { ${a.join(", ")} } = apis.toFunctions(routes, onRequest, {`;for(let p of g)console.log(`[frs] wrote ${p}`);for(let p of D)console.log(`[frs] skipped ${p} (use --force to overwrite)`);console.log(`
243
+ `;y(S,P);let _=ge({root:o,apisFile:n,servicesFile:c,apis:a});g.push(_);let h=E(path.dirname(u),u),C=E(path.dirname(u),S),N=a.length===1?`export const { ${a[0]} } = apis.toFunctions(routes, onRequest, {`:`export const { ${a.join(", ")} } = apis.toFunctions(routes, onRequest, {`;for(let l of g)console.log(`[frs] wrote ${l}`);for(let l of D)console.log(`[frs] skipped ${l} (use --force to overwrite)`);console.log(`
242
244
  Next steps:
243
245
 
244
246
  1. Wire the registry in your Functions entrypoint (e.g. src/index.ts):
@@ -258,10 +260,10 @@ Next steps:
258
260
  3. Refresh the manifest before each build:
259
261
 
260
262
  frs gen --root ${o}
261
- `);}finally{s.close();}}function E(e,t){let s=path.relative(e,t).replace(/\\/g,"/");return s=s.replace(/\.ts$/,".js"),s.startsWith(".")||(s=`./${s}`),s}async function $e(e,t,s){e!=="service"&&(console.error(`[frs] unknown "add" target: ${e??"(missing)"} \u2014 supported: service`),process.exit(2)),t||(console.error("[frs] service name is required: frs add service <name>"),process.exit(2));let r=s.force===true,o=T(),c=[m(s["services-file"]),o.servicesFile,"src/services.ts","services.ts"].filter(h=>typeof h=="string"&&h.length>0),i;for(let h of c){let C=path.resolve(process.cwd(),h);if(fs.existsSync(C)){i=C;break}}if(!i){let h=c.map(C=>path.resolve(process.cwd(),C)).join(`
263
+ `);}finally{s.close();}}function E(e,t){let s=path.relative(e,t).replace(/\\/g,"/");return s=s.replace(/\.ts$/,".js"),s.startsWith(".")||(s=`./${s}`),s}async function we(e,t,s){e!=="service"&&(console.error(`[frs] unknown "add" target: ${e??"(missing)"} \u2014 supported: service`),process.exit(2)),t||(console.error("[frs] service name is required: frs add service <name>"),process.exit(2));let r=s.force===true,o=T(),c=[m(s["services-file"]),o.servicesFile,"src/services.ts","services.ts"].filter(h=>typeof h=="string"&&h.length>0),i;for(let h of c){let C=path.resolve(process.cwd(),h);if(fs.existsSync(C)){i=C;break}}if(!i){let h=c.map(C=>path.resolve(process.cwd(),C)).join(`
262
264
  `);console.error(`[frs] services file not found. Tried:
263
265
  ${h}
264
- Run \`frs init\` first or pass --services-file <path>.`),process.exit(2);}let a=m(s["services-dir"])??o.servicesDir??path.resolve(path.dirname(i),"services"),d=path.resolve(process.cwd(),a);fs.mkdirSync(d,{recursive:true});let f=`${t.charAt(0).toUpperCase()}${t.slice(1)}Service`,u=path.resolve(d,`${t}.ts`),x=`import type { RequestContext } from "@lpdjs/firestore-repo-service/servers/hono";
266
+ Run \`frs init\` first or pass --services-file <path>.`),process.exit(2);}let a=m(s["services-dir"])??o.servicesDir??path.resolve(path.dirname(i),"services"),d=path.resolve(process.cwd(),a);fs.mkdirSync(d,{recursive:true});let f=`${t.charAt(0).toUpperCase()}${t.slice(1)}Service`,u=path.resolve(d,`${t}.ts`),b=`import type { RequestContext } from "@lpdjs/firestore-repo-service/servers/hono";
265
267
 
266
268
  /**
267
269
  * ${f} \u2014 generated by \`frs add service ${t}\`.
@@ -290,9 +292,9 @@ export class ${f} {
290
292
  return \`hello from ${t} \u2014 user=\${this.ctx.maybeC?.get("user")?.id ?? "anonymous"}\`;
291
293
  }
292
294
  }
293
- `;fs.existsSync(u)&&!r?console.log(`[frs] skipped ${u} (use --force to overwrite)`):(fs.writeFileSync(u,x,"utf8"),console.log(`[frs] wrote ${u}`));let v=fs.readFileSync(i,"utf8"),S=E(path.dirname(i),u),g=`import { ${f} } from "${S}";`,D=` ${t}: ({ ctx }) => new ${f}(ctx),`;if(v.includes(g)){console.log(`[frs] services.ts already registers "${t}" \u2014 skipping.`);return}let b=v.split(`
294
- `),k=-1;for(let h=0;h<b.length;h++)/^import\s/.test(b[h])&&(k=h);k>=0?b.splice(k+1,0,g):b.unshift(g);let y=b.join(`
295
- `),P=y.match(/createServices\s*\(\s*\{/);if(!P){console.error(`[frs] could not find \`createServices({\` in ${i} \u2014 register "${t}" manually.`);return}let F=P.index+P[0].length,_=y.slice(0,F)+`
296
- `+D+y.slice(F);fs.writeFileSync(i,_,"utf8"),console.log(`[frs] updated ${i} (+ ${t})`);}function we(e,t){let s=["apis.ts","apis.js","api.ts","api.js"],r=[e,path.dirname(e),path.dirname(path.dirname(e))];for(let o of r)for(let n of s){let c=path.resolve(o,n);if(fs.existsSync(c)){let i=path.relative(t,c).replace(/\\/g,"/");return i=i.replace(/\.ts$/,".js").replace(/\.js$/,".js"),i.startsWith(".")||(i=`./${i}`),i}}return "../../../../apis.js"}function xe(e,t){let s=["services.ts","services.js"],r=[e,path.dirname(e),path.dirname(path.dirname(e))];for(let o of r)for(let n of s){let c=path.resolve(o,n);if(fs.existsSync(c)){let i=path.relative(t,c).replace(/\\/g,"/");return i=i.replace(/\.ts$/,".js"),i.startsWith(".")||(i=`./${i}`),i}}return "../../../../services.js"}async function be(){let e=process.argv.slice(2),{command:t,flags:s}=ge(e);switch(t){case "init":await ye(s);return;case "gen":await he(s);return;case "new":await ve(e[1],s);return;case "add":await $e(e[1],e[2],s);return;case "help":case "--help":case "-h":Y();return;default:console.error(`[frs] unknown command: ${t}
297
- `),Y(),process.exit(2);}}be().catch(e=>{console.error(e),process.exit(1);});//# sourceMappingURL=cli.cjs.map
295
+ `;fs.existsSync(u)&&!r?console.log(`[frs] skipped ${u} (use --force to overwrite)`):(fs.writeFileSync(u,b,"utf8"),console.log(`[frs] wrote ${u}`));let v=fs.readFileSync(i,"utf8"),S=E(path.dirname(i),u),g=`import { ${f} } from "${S}";`,D=` ${t}: ({ ctx }) => new ${f}(ctx),`;if(v.includes(g)){console.log(`[frs] services.ts already registers "${t}" \u2014 skipping.`);return}let y=v.split(`
296
+ `),k=-1;for(let h=0;h<y.length;h++)/^import\s/.test(y[h])&&(k=h);k>=0?y.splice(k+1,0,g):y.unshift(g);let F=y.join(`
297
+ `),w=F.match(/createServices\s*\(\s*\{/);if(!w){console.error(`[frs] could not find \`createServices({\` in ${i} \u2014 register "${t}" manually.`);return}let P=w.index+w[0].length,_=F.slice(0,P)+`
298
+ `+D+F.slice(P);fs.writeFileSync(i,_,"utf8"),console.log(`[frs] updated ${i} (+ ${t})`);}function xe(e,t){let s=["apis.ts","apis.js","api.ts","api.js"],r=[e,path.dirname(e),path.dirname(path.dirname(e))];for(let o of r)for(let n of s){let c=path.resolve(o,n);if(fs.existsSync(c)){let i=path.relative(t,c).replace(/\\/g,"/");return i=i.replace(/\.ts$/,".js").replace(/\.js$/,".js"),i.startsWith(".")||(i=`./${i}`),i}}return "../../../../apis.js"}function be(e,t){let s=["services.ts","services.js"],r=[e,path.dirname(e),path.dirname(path.dirname(e))];for(let o of r)for(let n of s){let c=path.resolve(o,n);if(fs.existsSync(c)){let i=path.relative(t,c).replace(/\\/g,"/");return i=i.replace(/\.ts$/,".js"),i.startsWith(".")||(i=`./${i}`),i}}return "../../../../services.js"}async function Se(){let e=process.argv.slice(2),{command:t,flags:s}=he(e);switch(t){case "init":await $e(s);return;case "gen":await ve(s);return;case "new":await ye(e[1],s);return;case "add":await we(e[1],e[2],s);return;case "help":case "--help":case "-h":Y();return;default:console.error(`[frs] unknown command: ${t}
299
+ `),Y(),process.exit(2);}}Se().catch(e=>{console.error(e),process.exit(1);});//# sourceMappingURL=cli.cjs.map
298
300
  //# sourceMappingURL=cli.cjs.map