rpc4next-cli 0.3.2 → 0.4.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.
Files changed (3) hide show
  1. package/README.md +28 -1
  2. package/dist/index.js +10 -7
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,6 +8,18 @@ Inspired by Hono RPC and Pathpida, **rpc4next** automatically generates a type-s
8
8
 
9
9
  ---
10
10
 
11
+ ## Development Notes
12
+
13
+ This repository is a monorepo.
14
+
15
+ - `packages/rpc4next` contains the runtime client/server helpers.
16
+ - `packages/rpc4next-cli` contains the Next.js scanner and type generator.
17
+ - `integration/next-app` is the real end-to-end fixture app used to verify generated artifacts, runtime behavior, and browser usage together.
18
+
19
+ When a change affects scanner behavior, generated path structure output, params generation, or integration fixture routes, regenerate the integration artifacts and review those diffs as part of the change.
20
+
21
+ ---
22
+
11
23
  ## ✨ Features
12
24
 
13
25
  - ✅ ルート、パラメータ、クエリパラメータ、 リクエストボディ、レスポンスの型安全なクライアント生成
@@ -68,6 +80,21 @@ npx rpc4next <baseDir> <outputPath>
68
80
 
69
81
  `rpc4next` command is provided by the `rpc4next-cli` package.
70
82
 
83
+ ```json
84
+ {
85
+ "baseDir": "app",
86
+ "outputPath": "src/generated/rpc.ts",
87
+ "paramsFile": "params.ts"
88
+ }
89
+ ```
90
+
91
+ `rpc4next.config.json` を実行ディレクトリに置くと、固定値を CLI 引数に繰り返し書かずに済みます。
92
+
93
+ ```bash
94
+ npx rpc4next
95
+ npx rpc4next --watch
96
+ ```
97
+
71
98
  - `<baseDir>`: Next.js の Appルータが配置されたベースディレクトリ
72
99
  - `<outputPath>`: 生成された型定義ファイルの出力先
73
100
 
@@ -330,7 +357,7 @@ async function callUserApi() {
330
357
  aqua i
331
358
  ```
332
359
 
333
- - `aqua.yaml` を更新したら、チェックサムを更新してください
360
+ - `aqua/aqua.yaml` を更新したら、チェックサムを更新してください
334
361
 
335
362
  ```bash
336
363
  aqua update-checksum
package/dist/index.js CHANGED
@@ -1,26 +1,29 @@
1
1
  #!/usr/bin/env node
2
- import Jt from"node:path";import{parseArgs as Zt}from"node:util";import _t from"node:path";var R=["page.tsx","route.ts"];import M from"node:path";var st=(t,e)=>{let r=S(M.relative(M.dirname(t),e)).replace(/\.tsx?$/,"");return r.startsWith("../")||(r=`./${r}`),r},S=t=>t.replace(/\\/g,"/"),x=t=>M.relative(process.cwd(),t);import J from"node:fs";import Vt from"node:path";var ot=["Query"];var H="Endpoint",k="QueryKey",G="ParamsKey",it=[H,G,k],at="rpc4next/client";import dt from"node:fs";import A from"node:path";import{CATCH_ALL_PREFIX as kt,DYNAMIC_PREFIX as Gt,OPTIONAL_CATCH_ALL_PREFIX as Kt}from"rpc4next-shared";import K from"node:path";var y=new Map,N=new Map,ct=(t,e)=>{let r=K.resolve(e);[...t.keys()].forEach(s=>{let n=K.resolve(s);(n===r||r.startsWith(n+K.sep))&&t.delete(s)})},pt=t=>{ct(y,t)},mt=t=>{ct(N,t)};import jt from"node:fs";import{HTTP_METHODS_EXCLUDE_OPTIONS as Ut}from"rpc4next-shared";import Yt from"node:crypto";var ut=(t,e)=>{let r=Yt.createHash("md5").update(`${t}::${e}`).digest("hex").slice(0,16);return`${e}_${r}`};var v=(t,e)=>!t||!e?"":`Record<${t}, ${e}>`,L=t=>t.length===0||t.some(({name:e,type:r})=>!e||!r)?"":`{ ${t.map(({name:e,type:r})=>`"${e}": ${r}`).join(`${";"} `)}${t.length>1?";":""} }`,D=(t,e,r)=>!t||!e?"":r?`import type { ${t} as ${r} } from "${e}"${";"}`:`import type { ${t} } from "${e}"${";"}`;var ft=(t,e,r,s)=>{let n=st(t,e),i=ut(n,r);return{importName:i,importPath:n,importStatement:D(r,n,i),type:s(r,i),exportName:r}},Mt=t=>ot.find(e=>new RegExp(`export (interface ${e} ?{|type ${e} ?=)`).test(t)),Ht=(t,e)=>new RegExp(`export (async )?(function ${e} ?\\(|const ${e} ?=|\\{[^}]*\\b${e}\\b[^}]*\\} ?=|const \\{[^}]*\\b${e}\\b[^}]*\\} ?=|\\{[^}]*\\b${e}\\b[^}]*\\} from)`).test(t),ht=(t,e)=>{let r=jt.readFileSync(e,"utf8"),s=Mt(r),n=s?ft(t,e,s,(o,c)=>v(k,c)):void 0,i=Ut.filter(o=>Ht(r,o)).map(o=>ft(t,e,o,(c,a)=>L([{name:`$${c.toLowerCase()}`,type:`typeof ${a}`}])));return{...n?{query:n}:{},routes:i}};var gt=new Set(R),Xt=t=>t.startsWith("(.)")||t.startsWith("(..)")||t.startsWith("(...)"),Qt=t=>{try{return decodeURIComponent(t)}catch{return t}},X=t=>{let e=t.startsWith("(")&&t.endsWith(")"),r=t.startsWith("@"),s=t.startsWith("[[...")&&t.endsWith("]]"),n=t.startsWith("[...")&&t.endsWith("]"),i=t.startsWith("[")&&t.endsWith("]"),o=t.startsWith("_"),c=Xt(t),a=Qt(t);return{isCatchAll:n,isDynamic:i,isGroup:e,isIntercept:c,isOptionalCatchAll:s,isParallel:r,isPrivate:o,staticKeyName:a}},Et=t=>{let e=y.get(t);if(e!==void 0)return e;let r=A.basename(t),s=X(r);if(r==="node_modules"||s.isPrivate||s.isIntercept)return y.set(t,!1),!1;let n=dt.readdirSync(t,{withFileTypes:!0});for(let i of n){let{name:o}=i,c=A.join(t,o),a=X(o);if(!(o==="node_modules"||a.isPrivate||a.isIntercept)){if(i.isFile()&&gt.has(o))return y.set(t,!0),!0;if(i.isDirectory()&&Et(c))return y.set(t,!0),!0}}return y.set(t,!1),!1},qt=(t,{isDynamic:e,isCatchAll:r,isOptionalCatchAll:s})=>{let n=t;return e&&(n=n.replace(/^\[+|\]+$/g,"")),(r||s)&&(n=n.replace(/^\.{3}/,"")),{paramName:n,keyName:`${s?Kt:r?kt:e?Gt:""}${n}`}},q=(t,e,r="",s=[])=>{let n=N.get(e);if(n!==void 0)return n;let i=r,o=r+" ",c=[],a=[],p=[],m=[],h=[...s],tt=dt.readdirSync(e,{withFileTypes:!0}).filter(E=>{if(E.isDirectory()){let T=A.join(e,E.name);return Et(T)}return gt.has(E.name)}).sort();for(let E of tt){let T=S(A.join(e,E.name));if(E.isDirectory()){let $=E.name,{isGroup:C,isParallel:d,isOptionalCatchAll:u,isCatchAll:l,isDynamic:f,isPrivate:j,isIntercept:vt,staticKeyName:Lt}=X($);if(j||vt)continue;let{paramName:Dt,keyName:wt}=qt($,{isDynamic:f,isCatchAll:l,isOptionalCatchAll:u}),Ot=f||l||u?[...h,{paramName:Dt,routeType:{isDynamic:f,isCatchAll:l,isOptionalCatchAll:u,isGroup:C,isParallel:d}}]:h,rt=C||d,{pathStructure:U,imports:Ft,paramsTypes:Wt}=q(t,T,rt?i:o,Ot);if(a.push(...Ft),m.push(...Wt),rt){let b=U.match(/^\s*\{([\s\S]*)\}\s*$/),nt=U.trim();if(b)c.push(`${o}${b[1].trim()}`);else if(nt)p.push(nt);else throw new Error(`Invalid empty child path structure in grouped/parallel route: ${T}`)}else{let b=f||l||u?wt:Lt;c.push(`${o}"${b}": ${U}`)}}else{let{query:$,routes:C}=ht(t,T);if($){let{importStatement:d,importPath:u,type:l}=$;a.push({statement:d,path:u}),p.push(l)}if(C.forEach(d=>{let{importStatement:u,importPath:l,type:f}=d;a.push({statement:u,path:l}),p.push(f)}),p.push(H),h.length>0){let d=h.map(({paramName:l,routeType:f})=>{let j=f.isCatchAll?"string[]":f.isOptionalCatchAll?"string[] | undefined":"string";return{name:l,type:j}}),u=L(d);m.push({paramsType:u,dirPath:A.dirname(T)}),p.push(v(G,u))}}}let W=p.join(" & "),Y=c.length>0?`{${`
3
- `}${c.join(`,${`
2
+ import ce from"node:path";import{parseArgs as pe}from"node:util";import bt from"node:path";var D=["page.tsx","route.ts"];import G from"node:path";var it=(t,e)=>{let r=P(G.relative(G.dirname(t),e)).replace(/\.tsx?$/,"");return r.startsWith("../")||(r=`./${r}`),r},P=t=>t.replace(/\\/g,"/"),x=t=>G.relative(process.cwd(),t);import tt from"node:fs";import oe from"node:path";var at=["Query"];var k="Endpoint",K="QueryKey",X="ParamsKey",ct=[k,X,K],pt="rpc4next/client";import yt from"node:fs";import _ from"node:path";import{CATCH_ALL_PREFIX as Vt,DYNAMIC_PREFIX as zt,OPTIONAL_CATCH_ALL_PREFIX as Jt}from"rpc4next-shared";import Q from"node:path";var S=new Map,F=new Map,mt=(t,e)=>{let r=Q.resolve(e);[...t.keys()].forEach(n=>{let o=Q.resolve(n);(o===r||r.startsWith(o+Q.sep))&&t.delete(n)})},ut=t=>{mt(S,t)},lt=t=>{mt(F,t)};import Xt from"node:fs";import{HTTP_METHODS_EXCLUDE_OPTIONS as Qt}from"rpc4next-shared";import Kt from"node:crypto";var ft=(t,e)=>{let r=Kt.createHash("md5").update(`${t}::${e}`).digest("hex").slice(0,16);return`${e}_${r}`};var v=(t,e)=>!t||!e?"":`Record<${t}, ${e}>`,L=t=>t.length===0||t.some(({name:e,type:r})=>!e||!r)?"":`{ ${t.map(({name:e,type:r})=>`"${e}": ${r}`).join(`${";"} `)}${t.length>1?";":""} }`,O=(t,e,r)=>!t||!e?"":r?`import type { ${t} as ${r} } from "${e}"${";"}`:`import type { ${t} } from "${e}"${";"}`;var gt=(t,e,r,n)=>{let o=it(t,e),i=ft(o,r);return{importName:i,importPath:o,importStatement:O(r,o,i),type:n(r,i),exportName:r}},qt=t=>at.find(e=>new RegExp(`export (interface ${e} ?{|type ${e} ?=)`).test(t)),Bt=(t,e)=>new RegExp(`export (async )?(function ${e} ?\\(|const ${e} ?=|\\{[^}]*\\b${e}\\b[^}]*\\} ?=|const \\{[^}]*\\b${e}\\b[^}]*\\} ?=|\\{[^}]*\\b${e}\\b[^}]*\\} from)`).test(t),dt=(t,e)=>{let r=Xt.readFileSync(e,"utf8"),n=qt(r),o=n?gt(t,e,n,(s,a)=>v(K,a)):void 0,i=Qt.filter(s=>Bt(r,s)).map(s=>gt(t,e,s,(a,c)=>L([{name:`$${a.toLowerCase()}`,type:`typeof ${c}`}])));return{...o?{query:o}:{},routes:i}};var Et=new Set(D),Tt=["(..)(..)","(...)","(..)","(.)"],Zt=t=>Tt.some(e=>t.startsWith(e)),te=t=>{let e=t;for(;;){let r=Tt.find(n=>e.startsWith(n));if(!r)return e;e=e.slice(r.length)}},ee=t=>{try{let e=decodeURIComponent(t);return e.startsWith("_")?t:e}catch{return t}},q=t=>{let e=Zt(t),r=e?te(t):t,n=!e&&r.startsWith("(")&&r.endsWith(")"),o=!e&&r.startsWith("@"),i=r.startsWith("[[...")&&r.endsWith("]]"),s=!i&&r.startsWith("[...")&&r.endsWith("]"),a=r.startsWith("[")&&r.endsWith("]"),c=!e&&r.startsWith("_"),p=ee(r);return{isCatchAll:s,isDynamic:a,isGroup:n,isIntercept:e,isOptionalCatchAll:i,isParallel:o,isPrivate:c,segmentName:r,staticKeyName:p}},St=t=>{let e=S.get(t);if(e!==void 0)return e;let r=_.basename(t),n=q(r);if(r==="node_modules"||n.isPrivate)return S.set(t,!1),!1;let o=yt.readdirSync(t,{withFileTypes:!0});for(let i of o){let{name:s}=i,a=_.join(t,s),c=q(s);if(!(s==="node_modules"||c.isPrivate)){if(i.isFile()&&Et.has(s))return S.set(t,!0),!0;if(i.isDirectory()&&St(a))return S.set(t,!0),!0}}return S.set(t,!1),!1},re=(t,{isDynamic:e,isCatchAll:r,isOptionalCatchAll:n})=>{let o=t;return e&&(o=o.replace(/^\[+|\]+$/g,"")),(r||n)&&(o=o.replace(/^\.{3}/,"")),{paramName:o,keyName:`${n?Jt:r?Vt:e?zt:""}${o}`}},V=(t,e,r="",n=[])=>{let o=F.get(e);if(o!==void 0)return o;let i=r,s=r+" ",a=[],c=[],p=[],m=[],u=[...n],y=yt.readdirSync(e,{withFileTypes:!0}).filter(h=>{if(h.isDirectory()){let E=_.join(e,h.name);return St(E)}return Et.has(h.name)}).sort((h,E)=>h.name.localeCompare(E.name));for(let h of y){let E=P(_.join(e,h.name));if(h.isDirectory()){let b=h.name,{isGroup:R,isParallel:g,isOptionalCatchAll:l,isCatchAll:f,isDynamic:d,isPrivate:H,isIntercept:Ot,segmentName:jt,staticKeyName:Wt}=q(b);if(H)continue;let{paramName:Yt,keyName:Mt}=re(jt,{isDynamic:d,isCatchAll:f,isOptionalCatchAll:l}),Ut=d||f||l?[...u,{paramName:Yt,routeType:{isDynamic:d,isCatchAll:f,isOptionalCatchAll:l,isGroup:R,isParallel:g}}]:u,ot=R,Ht=Ot||g,{pathStructure:C,imports:Gt,paramsTypes:kt}=V(t,E,ot||g?i:s,Ut);if(m.push(...kt),Ht)continue;if(c.push(...Gt),ot){let w=C.match(/^\s*\{([\s\S]*)\}\s*$/),st=C.trim();if(!C)continue;if(w)a.push(`${s}${w[1].trim()}`);else if(st)p.push(st);else throw new Error(`Invalid empty child path structure in grouped/parallel route: ${E}`)}else{if(!C.trim())continue;let w=d||f||l?Mt:Wt;a.push(`${s}"${w}": ${C}`)}}else{let{query:b,routes:R}=dt(t,E);if(b){let{importStatement:g,importPath:l,type:f}=b;c.push({statement:g,path:l}),p.push(f)}if(R.forEach(g=>{let{importStatement:l,importPath:f,type:d}=g;c.push({statement:l,path:f}),p.push(d)}),p.push(k),u.length>0){let g=u.map(({paramName:f,routeType:d})=>{let H=d.isCatchAll?"string[]":d.isOptionalCatchAll?"string[] | undefined":"string";return{name:f,type:H}}),l=L(g);m.push({paramsType:l,dirPath:_.dirname(E)}),p.push(v(X,l))}}}let M=p.join(" & "),U=a.length>0?`{${`
3
+ `}${a.join(`,${`
4
4
  `}`)}${`
5
- `}${i}}`:"",et={pathStructure:W&&Y?`${W} & ${Y}`:W||Y,imports:a,paramsTypes:m};return N.set(e,et),et};var yt=(t,e)=>{let{pathStructure:r,imports:s,paramsTypes:n}=q(t,e),i=`export type PathStructure = ${r}${";"}`,o=s.length?`${s.sort((m,h)=>m.path.localeCompare(h.path,void 0,{numeric:!0})).map(m=>m.statement).join(`
6
- `)}`:"",c=it.filter(m=>r.includes(m)),a=D(c.join(" ,"),at),p=n.map(({paramsType:m,dirPath:h})=>({paramsType:`export type Params = ${m}${";"}`,dirPath:h}));return{pathStructure:`${a}${`
7
- `}${o}${`
5
+ `}${i}}`:"",nt={pathStructure:M&&U?`${M} & ${U}`:M||U,imports:c,paramsTypes:m};return F.set(e,nt),nt};var Pt=(t,e)=>{let{pathStructure:r,imports:n,paramsTypes:o}=V(t,e),i=`export type PathStructure = ${r}${";"}`,s=n.length?`${n.sort((m,u)=>m.path.localeCompare(u.path,void 0,{numeric:!0})).map(m=>m.statement).join(`
6
+ `)}`:"",a=ct.filter(m=>r.includes(m)),c=O(a.join(" ,"),pt),p=o.map(({paramsType:m,dirPath:u})=>({paramsType:`export type Params = ${m}${";"}`,dirPath:u}));return{pathStructure:`${c}${`
7
+ `}${s}${`
8
8
  `}${`
9
- `}${i}`,paramsTypes:p}};var Bt=()=>!!process.stdout?.isTTY;var B=t=>e=>Bt()?`\x1B[${t}m${e}\x1B[0m`:e,Tt=B(36),St=B(32),V=B(31);var _=(t,e,r="\u2192",s=24)=>`${t.padEnd(s)} ${r} ${e}`,z=(t=0)=>" ".repeat(t),xt=()=>({info:(t,e={})=>{let{indentLevel:r=0,event:s}=e,n=s?`${Tt(`[${s}]`)} `:"";console.log(`${z(r)}${n}${t}`)},success:(t,e={})=>{let{indentLevel:r=0}=e;console.log(`${z(r)}${St("\u2713")} ${t}`)},error:(t,e={})=>{let{indentLevel:r=0}=e;console.error(`${z(r)}${V("\u2717")} ${V(t)}`)}});var Pt=(t,e)=>J.existsSync(t)&&J.readFileSync(t,"utf8")===e?!1:(J.writeFileSync(t,e),!0),$t=({baseDir:t,outputPath:e,paramsFileName:r,logger:s})=>{s.info("Generating types...",{event:"generate"});let{pathStructure:n,paramsTypes:i}=yt(e,t);if(Pt(e,n)?s.success(_("Path structure type",x(e),"\u2192",20),{indentLevel:1}):s.info(_("Unchanged path type",x(e),"\u2192",20),{indentLevel:1}),r){let o=!1;i.forEach(({paramsType:c,dirPath:a})=>{let p=Vt.join(a,r),m=Pt(p,c);o=o||m}),o?s.success(_("Params types",r,"\u2192",20),{indentLevel:1}):s.info(_("Unchanged params",r,"\u2192",20),{indentLevel:1})}};import zt from"chokidar";var It=(t,e)=>{let r=null,s=!1,n=null,i=async(...o)=>{s=!0;try{await t(...o)}finally{if(s=!1,n){let c=n;n=null,i(...c)}}};return(...o)=>{r&&clearTimeout(r),r=setTimeout(()=>{if(s){n=o;return}i(...o)},e)}};var At=(t,e,r)=>{r.info(`${x(t)}`,{event:"watch"});let s=a=>R.some(p=>a.endsWith(p)),n=new Set,i=It(async()=>{let a=Array.from(n);n.clear();for(let p of a)pt(p),mt(p);await e()},300),o=zt.watch(t,{ignoreInitial:!0,ignored:(a,p)=>!!p?.isFile()&&!s(a)});o.on("ready",()=>{i(),o.on("all",(a,p)=>{if(s(p)){let m=x(p);r.info(m,{event:a}),n.add(p),i()}})}),o.on("error",a=>{a instanceof Error?r.error(`Watcher error: ${a.message}`):r.error(`Unknown watcher error: ${String(a)}`)});let c=()=>{o.close().then(()=>{r.info("Watcher closed.",{event:"watch"})}).catch(a=>{r.error(`Failed to close watcher: ${a.message}`)})};process.on("SIGINT",c),process.on("SIGTERM",c)};var Ct=(t,e,r,s)=>{try{return $t({baseDir:t,outputPath:e,paramsFileName:r,logger:s}),0}catch(n){return n instanceof Error?s.error(`Failed to generate: ${n.message}`):s.error(`Unknown error occurred during generate: ${String(n)}`),1}},Rt=(t,e,r,s)=>{let n=S(_t.resolve(t)),i=S(_t.resolve(e)),o=typeof r.paramsFile=="string"?r.paramsFile:null;return r.paramsFile!==void 0&&!o?(s.error("Error: --params-file requires a filename."),1):r.watch?(At(n,()=>{Ct(n,i,o,s)},s),0):Ct(n,i,o,s)};function te(t){if(t.length===0)return[];if(t[0].startsWith("-"))return t;let e=Jt.basename(t[0]).toLowerCase();return new Set(["node","node.exe","bun","bun.exe","deno","deno.exe"]).has(e)&&t.length>=2?t.slice(2):t}function Z(t){let e=`
9
+ `}${i}`,paramsTypes:p}};var ne=()=>!!process.stdout?.isTTY;var z=t=>e=>ne()?`\x1B[${t}m${e}\x1B[0m`:e,xt=z(36),$t=z(32),J=z(31);var A=(t,e,r="\u2192",n=24)=>`${t.padEnd(n)} ${r} ${e}`,Z=(t=0)=>" ".repeat(t),Ct=()=>({info:(t,e={})=>{let{indentLevel:r=0,event:n}=e,o=n?`${xt(`[${n}]`)} `:"";console.log(`${Z(r)}${o}${t}`)},success:(t,e={})=>{let{indentLevel:r=0}=e;console.log(`${Z(r)}${$t("\u2713")} ${t}`)},error:(t,e={})=>{let{indentLevel:r=0}=e;console.error(`${Z(r)}${J("\u2717")} ${J(t)}`)}});var It=(t,e)=>tt.existsSync(t)&&tt.readFileSync(t,"utf8")===e?!1:(tt.writeFileSync(t,e),!0),_t=({baseDir:t,outputPath:e,paramsFileName:r,logger:n})=>{n.info("Generating types...",{event:"generate"});let{pathStructure:o,paramsTypes:i}=Pt(e,t);if(It(e,o)?n.success(A("Path structure type",x(e),"\u2192",20),{indentLevel:1}):n.info(A("Unchanged path type",x(e),"\u2192",20),{indentLevel:1}),r){let s=!1;i.forEach(({paramsType:a,dirPath:c})=>{let p=oe.join(c,r),m=It(p,a);s=s||m}),s?n.success(A("Params types",r,"\u2192",20),{indentLevel:1}):n.info(A("Unchanged params",r,"\u2192",20),{indentLevel:1})}};import se from"chokidar";var At=(t,e)=>{let r=null,n=!1,o=null,i=async(...s)=>{n=!0;try{await t(...s)}finally{if(n=!1,o){let a=o;o=null,i(...a)}}};return(...s)=>{r&&clearTimeout(r),r=setTimeout(()=>{if(n){o=s;return}i(...s)},e)}};var Nt=(t,e,r)=>{r.info(`${x(t)}`,{event:"watch"});let n=c=>D.some(p=>c.endsWith(p)),o=new Set,i=At(async()=>{let c=Array.from(o);o.clear();for(let p of c)ut(p),lt(p);await e()},300),s=se.watch(t,{ignoreInitial:!0,ignored:(c,p)=>!!p?.isFile()&&!n(c)});s.on("ready",()=>{i(),s.on("all",(c,p)=>{if(n(p)){let m=x(p);r.info(m,{event:c}),o.add(p),i()}})}),s.on("error",c=>{c instanceof Error?r.error(`Watcher error: ${c.message}`):r.error(`Unknown watcher error: ${String(c)}`)});let a=()=>{s.close().then(()=>{r.info("Watcher closed.",{event:"watch"})}).catch(c=>{r.error(`Failed to close watcher: ${c.message}`)})};process.on("SIGINT",a),process.on("SIGTERM",a)};var Rt=(t,e,r,n)=>{try{return _t({baseDir:t,outputPath:e,paramsFileName:r,logger:n}),0}catch(o){return o instanceof Error?n.error(`Failed to generate: ${o.message}`):n.error(`Unknown error occurred during generate: ${String(o)}`),1}},Dt=(t,e,r,n)=>{let o=P(bt.resolve(t)),i=P(bt.resolve(e)),s=typeof r.paramsFile=="string"?r.paramsFile:null;return r.paramsFile!==void 0&&!s?(n.error("Error: --params-file requires a filename."),1):r.watch?(Nt(o,()=>{Rt(o,i,s,n)},n),0):Rt(o,i,s,n)};import Ft from"node:fs";import ie from"node:path";var N="rpc4next.config.json",et=t=>typeof t=="string"&&t.length>0,ae=(t=process.cwd())=>ie.join(t,N),vt=(t=process.cwd())=>{let e=ae(t);if(!Ft.existsSync(e))return{};let r=JSON.parse(Ft.readFileSync(e,"utf8"));if(!r||Array.isArray(r))throw new Error(`${N} must contain a JSON object.`);let n={};if("baseDir"in r){if(!et(r.baseDir))throw new Error(`${N} field "baseDir" must be a string.`);n.baseDir=r.baseDir}if("outputPath"in r){if(!et(r.outputPath))throw new Error(`${N} field "outputPath" must be a string.`);n.outputPath=r.outputPath}if("paramsFile"in r){if(!et(r.paramsFile))throw new Error(`${N} field "paramsFile" must be a string.`);n.paramsFile=r.paramsFile}return n};function me(t){if(t.length===0)return[];if(t[0].startsWith("-"))return t;let e=ce.basename(t[0]).toLowerCase();return new Set(["node","node.exe","bun","bun.exe","deno","deno.exe"]).has(e)&&t.length>=2?t.slice(2):t}function rt(t){let e=`
10
10
  Generate RPC client type definitions based on the Next.js path structure.
11
11
 
12
12
  Usage:
13
13
  rpc4next <baseDir> <outputPath> [options]
14
+ rpc4next [options]
14
15
 
15
16
  Arguments:
16
17
  baseDir Base directory containing Next.js paths for type generation
17
18
  outputPath Output path for the generated type definitions
19
+ Both can be omitted when rpc4next.config.json provides them
18
20
 
19
21
  Options:
20
22
  -w, --watch Watch mode: regenerate on file changes
21
23
  -p, --params-file [filename] Generate params types file (optional filename)
24
+ Config file: rpc4next.config.json in the current directory
22
25
  -h, --help Show help
23
- `.trim();t.info(e)}function ee(t,e){let r=[],s;for(let n=0;n<t.length;n++){let i=t[n],o=!1;for(let c of e)if(i.startsWith(`${c}=`)){s=i.slice(`${c}=`.length)||!0,o=!0;break}if(!o){if(e.includes(i)){let c=t[n+1];typeof c=="string"&&!c.startsWith("-")?(s=c,n++):s=!0;continue}r.push(i)}}return{args:r,value:s}}var Nt=(t,e=xt())=>{try{let r=te(t),{args:s,value:n}=ee(r,["-p","--params-file"]),{values:i,positionals:o}=Zt({args:s,options:{watch:{type:"boolean",short:"w"},help:{type:"boolean",short:"h"}},allowPositionals:!0,strict:!0});i.help&&(Z(e),process.exit(0));let c=o[0],a=o[1];(!c||!a)&&(e.error("Missing required arguments: <baseDir> <outputPath>"),Z(e),process.exit(1));let p={watch:!!i.watch,...n!==void 0?{paramsFile:n}:{}};(async()=>{try{let m=await Rt(c,a,p,e);p.watch||process.exit(m)}catch(m){e.error(`Unexpected error occurred:${m instanceof Error?m.message:String(m)}`),process.exit(1)}})()}catch(r){e.error(r instanceof Error?r.message:`Invalid arguments: ${String(r)}`),Z(e),process.exit(1)}};Nt(process.argv);
26
+ `.trim();t.info(e)}function ue(t,e){let r=[],n;for(let o=0;o<t.length;o++){let i=t[o],s=!1;for(let a of e)if(i.startsWith(`${a}=`)){n=i.slice(`${a}=`.length)||!0,s=!0;break}if(!s){if(e.includes(i)){let a=t[o+1];typeof a=="string"&&!a.startsWith("-")?(n=a,o++):n=!0;continue}r.push(i)}}return{args:r,value:n}}var Lt=(t,e=Ct())=>{try{let r=me(t),{args:n,value:o}=ue(r,["-p","--params-file"]),{values:i,positionals:s}=pe({args:n,options:{watch:{type:"boolean",short:"w"},help:{type:"boolean",short:"h"}},allowPositionals:!0,strict:!0});i.help&&(rt(e),process.exit(0));let a=vt(),c=s[0]??a.baseDir,p=s[1]??a.outputPath,m=o!==void 0?o:a.paramsFile;(!c||!p)&&(e.error("Missing required arguments: <baseDir> <outputPath>"),rt(e),process.exit(1));let u={watch:!!i.watch,...m!==void 0?{paramsFile:m}:{}};(async()=>{try{let y=await Dt(c,p,u,e);u.watch||process.exit(y)}catch(y){e.error(`Unexpected error occurred:${y instanceof Error?y.message:String(y)}`),process.exit(1)}})()}catch(r){e.error(r instanceof Error?r.message:`Invalid arguments: ${String(r)}`),rt(e),process.exit(1)}};Lt(process.argv);
24
27
  /*!
25
28
  * Inspired by pathpida (https://github.com/aspida/pathpida),
26
29
  * especially the design and UX of its CLI.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rpc4next-cli",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "description": "Command line interface for rpc4next. Generates RPC client type definitions from Next.js routes.",
5
5
  "homepage": "https://github.com/watanabe-1/rpc4next#readme",
6
6
  "repository": {