rpc4next 0.3.8 → 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/rpc/cli/index.js +1 -1
- package/dist/rpc/client/http-method.js +1 -1
- package/dist/rpc/client/match.js +1 -1
- package/dist/rpc/client/rpc-client.js +1 -1
- package/dist/rpc/client/rpc.js +1 -1
- package/dist/rpc/server/handler.d.ts +4 -0
- package/dist/rpc/server/handler.js +1 -0
- package/dist/rpc/server/route-context.js +1 -0
- package/dist/rpc/server/route-handler-factory.js +1 -1
- package/dist/rpc/server/route-types.d.ts +7 -7
- package/dist/rpc/server/types.d.ts +9 -3
- package/dist/rpc/server/validators/validator.d.ts +12 -0
- package/dist/rpc/server/validators/validator.js +8 -0
- package/dist/rpc/server/validators/zod/index.d.ts +1 -1
- package/dist/rpc/server/validators/zod/index.js +1 -1
- package/dist/rpc/server/validators/zod/zod-validator.d.ts +3 -2
- package/dist/rpc/server/validators/zod/zod-validator.js +1 -1
- package/package.json +4 -3
- package/dist/rpc/server/create-handler.d.ts +0 -3
- package/dist/rpc/server/create-handler.js +0 -1
- package/dist/rpc/server/create-route-context.js +0 -1
- /package/dist/rpc/client/{utils.d.ts → client-utils.d.ts} +0 -0
- /package/dist/rpc/client/{utils.js → client-utils.js} +0 -0
- /package/dist/rpc/server/{create-route-context.d.ts → route-context.d.ts} +0 -0
- /package/dist/rpc/server/{search-params-to-object.d.ts → server-utils.d.ts} +0 -0
- /package/dist/rpc/server/{search-params-to-object.js → server-utils.js} +0 -0
package/dist/rpc/cli/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import{Command as Wt}from"commander";import $t from"path";var R=["page.tsx","route.ts"],w=0,$=1,Y=1,M=20,W="\u2192";import U from"path";var et=(t,r)=>{let e=_(U.relative(U.dirname(t),r)).replace(/\.tsx?$/,"");return e.startsWith("../")||(e="./"+e),e},_=t=>t.replace(/\\/g,"/"),C=t=>U.relative(process.cwd(),t);import Pt from"fs";import Yt from"path";var rt=["Query","OptionalQuery"],O=" ",E=`
|
|
3
|
-
`,S=";",H=";",j="Endpoint",X="QueryKey",K="OptionalQueryKey",Q="ParamsKey",ot=[j,K,Q,X],nt="rpc4next/client";import Tt from"fs";import b from"path";import G from"path";var
|
|
3
|
+
`,S=";",H=";",j="Endpoint",X="QueryKey",K="OptionalQueryKey",Q="ParamsKey",ot=[j,K,Q,X],nt="rpc4next/client";import Tt from"fs";import b from"path";import G from"path";var g=new Map,N=new Map,st=(t,r)=>{let e=G.resolve(r);[...t.keys()].forEach(o=>{let n=G.resolve(o);(n===e||e.startsWith(n+G.sep))&&t.delete(o)})},it=t=>{st(g,t)},at=t=>{st(N,t)};import vt from"fs";import bt from"crypto";var pt=(t,r)=>{let e=bt.createHash("md5").update(`${t}::${r}`).digest("hex").slice(0,16);return`${r}_${e}`};var I=(t,r)=>!t||!r?"":`Record<${t}, ${r}>`,L=t=>t.length===0||t.some(({name:r,type:e})=>!r||!e)?"":`{ ${t.map(({name:r,type:e})=>`"${r}": ${e}`).join(`${H} `)}${t.length>1?H:""} }`,D=(t,r,e)=>!t||!r?"":e?`import type { ${t} as ${e} } from "${r}"${S}`:`import type { ${t} } from "${r}"${S}`;var ct=(t,r,e,o)=>{let n=vt.readFileSync(r,"utf8"),i=e(n);if(!i)return;let s=et(t,r),p=pt(s,i);return{importName:p,importPath:s,importStatement:D(i,s,p),type:o(i,p)}},mt=(t,r)=>ct(t,r,e=>rt.find(o=>new RegExp(`export (interface ${o} ?{|type ${o} ?=)`).test(e)),(e,o)=>e==="Query"?I(X,o):I(K,o)),lt=(t,r,e)=>ct(t,r,o=>[e].find(n=>new RegExp(`export (async )?(function ${n} ?\\(|const ${n} ?=|\\{[^}]*\\b${n}\\b[^}]*\\} ?=|const \\{[^}]*\\b${n}\\b[^}]*\\} ?=|\\{[^}]*\\b${n}\\b[^}]*\\} from)`).test(o)),(o,n)=>L([{name:`$${o.toLowerCase()}`,type:`typeof ${n}`}]));var Ft=["GET","HEAD","OPTIONS","POST","PUT","DELETE","PATCH"],ut="_____",ft="___",Et="_",k=Ft.filter(t=>t!=="OPTIONS"),oe=k.map(t=>`$${t.toLowerCase()}`);var ht=new Set(R),gt=t=>{if(g.has(t))return g.get(t);let r=Tt.readdirSync(t,{withFileTypes:!0});for(let e of r){let{name:o}=e,n=b.join(t,o);if(o==="node_modules"||o.startsWith("_")||o.startsWith("(.)")||o.startsWith("(..)")||o.startsWith("(...)"))return g.set(t,!1),!1;if(e.isFile()&&ht.has(o))return g.set(t,!0),!0;if(e.isDirectory()&>(n))return g.set(t,!0),!0}return g.set(t,!1),!1},wt=(t,{isDynamic:r,isCatchAll:e,isOptionalCatchAll:o})=>{let n=t;return r&&(n=n.replace(/^\[+|\]+$/g,"")),(e||o)&&(n=n.replace(/^\.{3}/,"")),{paramName:n,keyName:`${o?ut:e?ft:r?Et:""}${n}`}},V=(t,r,e="",o=[])=>{if(N.has(r))return N.get(r);let n=e,i=e+O,s=[],p=[],a=[],m=[],c=[...o],x=Tt.readdirSync(r,{withFileTypes:!0}).filter(y=>{if(y.isDirectory()){let P=b.join(r,y.name);return gt(P)}return ht.has(y.name)}).sort();for(let y of x){let P=_(b.join(r,y.name));if(y.isDirectory()){let l=y.name,T=l.startsWith("(")&&l.endsWith(")"),u=l.startsWith("@"),f=l.startsWith("[[...")&&l.endsWith("]]"),h=l.startsWith("[...")&&l.endsWith("]"),d=l.startsWith("[")&&l.endsWith("]"),{paramName:At,keyName:Rt}=wt(l,{isDynamic:d,isCatchAll:h,isOptionalCatchAll:f}),Ot=d||h||f?[...c,{paramName:At,routeType:{isDynamic:d,isCatchAll:h,isOptionalCatchAll:f,isGroup:T,isParallel:u}}]:c,J=T||u,{pathStructure:Z,imports:Lt,paramsTypes:Dt}=V(t,P,J?n:i,Ot);if(p.push(...Lt),m.push(...Dt),J){let tt=Z.match(/^\s*\{([\s\S]*)\}\s*$/);tt&&s.push(`${i}${tt[1].trim()}`)}else s.push(`${i}"${Rt}": ${Z}`)}else{let l=mt(t,P);if(l){let{importStatement:T,importPath:u,type:f}=l;p.push({statement:T,path:u}),a.push(f)}if(k.forEach(T=>{let u=lt(t,P,T);if(u){let{importStatement:f,importPath:h,type:d}=u;p.push({statement:f,path:h}),a.push(d)}}),a.push(j),c.length>0){let T=c.map(({paramName:f,routeType:h})=>{let d=h.isCatchAll?"string[]":h.isOptionalCatchAll?"string[] | undefined":"string";return{name:f,type:d}}),u=L(T);m.push({paramsType:u,dirPath:b.dirname(P)}),a.push(I(Q,u))}}}let A=a.join(" & "),F=s.length>0?`{${E}${s.join(`,${E}`)}${E}${n}}`:"",z={pathStructure:A&&F?`${A} & ${F}`:A||F,imports:p,paramsTypes:m};return N.set(r,z),z};var yt=(t,r)=>{let{pathStructure:e,imports:o,paramsTypes:n}=V(t,r),i=`export type PathStructure = ${e}${S}`,s=o.length?`${o.sort((c,x)=>c.path.localeCompare(x.path,void 0,{numeric:!0})).map(c=>c.statement).join(E)}`:"",p=ot.filter(c=>e.includes(c)),a=D(p.join(" ,"),nt),m=n.map(({paramsType:c,dirPath:x})=>({paramsType:`export type Params = ${c}${S}`,dirPath:x}));return{pathStructure:`${a}${E}${s}${E}${E}${i}`,paramsTypes:m}};import v from"chalk";var q=(t,r,e="\u2192",o=24)=>t.padEnd(o)+` ${e} ${r}`,B=(t=0)=>O.repeat(t),dt=()=>({info:(t,r={})=>{let{indentLevel:e=0,event:o}=r,n=o?`${v.cyan(`[${o}]`)} `:"";console.log(`${B(e)}${n}${t}`)},success:(t,r={})=>{let{indentLevel:e=0}=r;console.log(`${B(e)}${v.green("\u2713")} ${t}`)},error:(t,r={})=>{let{indentLevel:e=0}=r;console.error(`${B(e)}${v.red("\u2717")} ${v.red(t)}`)}});var _t=({baseDir:t,outputPath:r,paramsFileName:e,logger:o})=>{o.info("Generating types...",{event:"generate"});let{pathStructure:n,paramsTypes:i}=yt(r,t);Pt.writeFileSync(r,n),o.success(q("Path structure type",C(r),W,M),{indentLevel:Y}),e&&(i.forEach(({paramsType:s,dirPath:p})=>{let a=Yt.join(p,e);Pt.writeFileSync(a,s)}),o.success(q("Params types",e,W,M),{indentLevel:Y}))};import Mt from"chokidar";var St=(t,r)=>{let e=null,o=!1,n=null,i=async(...s)=>{o=!0;try{await t(...s)}finally{if(o=!1,n){let p=n;n=null,i(...p)}}};return(...s)=>{e&&clearTimeout(e),e=setTimeout(()=>{if(o){n=s;return}i(...s)},r)}};var xt=(t,r,e)=>{e.info(`${C(t)}`,{event:"watch"});let o=a=>R.some(m=>a.endsWith(m)),n=new Set,i=St(()=>{n.forEach(a=>{it(a),at(a)}),n.clear(),r()},300),s=Mt.watch(t,{ignoreInitial:!0,ignored:(a,m)=>!!m?.isFile()&&!o(a)});s.on("ready",()=>{i(),s.on("all",(a,m)=>{if(o(m)){let c=C(m);e.info(c,{event:a}),n.add(m),i()}})}),s.on("error",a=>{a instanceof Error?e.error(`Watcher error: ${a.message}`):e.error(`Unknown watcher error: ${String(a)}`)});let p=()=>{s.close().then(()=>{e.info("Watcher closed.",{event:"watch"})}).catch(a=>{e.error(`Failed to close watcher: ${a.message}`)})};process.on("SIGINT",p),process.on("SIGTERM",p)};var Ct=(t,r,e,o)=>{try{return _t({baseDir:t,outputPath:r,paramsFileName:e,logger:o}),w}catch(n){return n instanceof Error?o.error(`Failed to generate: ${n.message}`):o.error(`Unknown error occurred during generate: ${String(n)}`),$}},Nt=(t,r,e,o)=>{let n=_($t.resolve(t)),i=_($t.resolve(r)),s=typeof e.paramsFile=="string"?e.paramsFile:null;return e.paramsFile!==void 0&&!s?(o.error("Error: --params-file requires a filename."),$):e.watch?(xt(n,()=>{Ct(n,i,s,o)},o),w):Ct(n,i,s,o)};var It=(t,r=dt())=>{let e=new Wt;e.description("Generate RPC client type definitions based on the Next.js path structure.").argument("<baseDir>","Base directory containing Next.js paths for type generation").argument("<outputPath>","Output path for the generated type definitions").option("-w, --watch","Watch mode: regenerate on file changes").option("-p, --params-file [filename]","Generate params types file with specified filename").action(async(o,n,i)=>{try{let s=await Nt(o,n,i,r);i.watch||process.exit(s)}catch(s){r.error(`Unexpected error occurred:${s instanceof Error?s.message:String(s)}`),process.exit($)}}),e.parse(t)};It(process.argv);
|
|
4
4
|
/*!
|
|
5
5
|
* Inspired by pathpida (https://github.com/aspida/pathpida),
|
|
6
6
|
* especially the design and UX of its CLI.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{deepMerge as q}from"./client-utils";import{createUrl as T}from"./url";const l=t=>{const e={};return t?t instanceof Headers?(t.forEach((n,r)=>{e[r.toLowerCase()]=n}),e):Array.isArray(t)?(t.forEach(([n,r])=>{e[n.toLowerCase()]=r}),e):(Object.entries(t).forEach(([n,r])=>{e[n.toLowerCase()]=r}),e):e},F=(t,e,n,r,c)=>async(s,p)=>{let d,a;s?.body?.json&&(a="application/json",d=JSON.stringify(s.body.json));const g=s?.requestHeaders?.headers,f=s?.requestHeaders?.cookies,m=T([...e],n,r)(s?.url),h=t.replace(/^\$/,"").toUpperCase(),H=p?.fetch??c.fetch??fetch,u=c.init??{},y=p?.init??{},O=l(u.headers),C=l(g??y.headers),o={...O,...C};a&&(o["content-type"]=a),f&&(o.cookie=Object.entries(f).map(([j,R])=>`${j}=${R}`).join("; "));const{headers:k,...b}=u,{headers:w,...I}=y,i=q(b,I);return i.method=h,Object.keys(o).length>0&&(i.headers=o),d&&(i.body=d),await H(m.path,i)};export{F as httpMethod};
|
package/dist/rpc/client/match.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{isCatchAllOrOptional as d}from"./client-utils";import{replaceDynamicSegments as u}from"./url";const f=(r,o)=>a=>{const c=`/${r.slice(1).join("/")}`,i=u(c,{optionalCatchAll:"(?:/(.*))?",catchAll:"/([^/]+(?:/[^/]+)*)",dynamic:"/([^/]+)"}),n=new RegExp(`^${i}/?$`).exec(a);return n?o.reduce((l,t,s)=>{const m=t.replace(/^_+/,""),e=n[s+1],p=d(t)?e===void 0||e===""?void 0:e.split("/").filter(Boolean).map(decodeURIComponent):decodeURIComponent(e);return{...l,[m]:p}},{}):null};export{f as matchPath};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{isHttpMethod as n}from"./client-utils";import{httpMethod as p}from"./http-method";import{makeCreateRpc as m}from"./rpc";import{createUrl as c}from"./url";const l=m((t,{paths:r,params:o,dynamicKeys:e,options:i})=>{if(t==="$url")return c([...r],o,e);if(n(t))return p(t,[...r],o,e,i)});export{l as createRpcClient};
|
package/dist/rpc/client/rpc.js
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* Inspired by the design of Hono (https://github.com/honojs/hono)
|
|
3
3
|
* and pathpida (https://github.com/aspida/pathpida)
|
|
4
4
|
* particularly their routing structures and developer experience.
|
|
5
|
-
*/import{isDynamic as f}from"./utils";const s=(n,e,t,c,o)=>new Proxy(u=>{const r=t.at(-1),i=o.at(-1);if(u===void 0)throw new Error(`Missing value for dynamic parameter: ${i}`);if(r&&i&&f(r))return s(n,e,[...t],{...c,[i]:u},o);throw new Error(`${r} is not dynamic`)},{get(u,r){const i=n(r,{paths:t,params:c,dynamicKeys:o,options:e});return i!==void 0?i:f(r)?s(n,e,[...t,r],c,[...o,r]):s(n,e,[...t,r],c,o)}}),l=n=>(e="/",t={})=>s(n,t,[e],{},[]);export{l as makeCreateRpc};
|
|
5
|
+
*/import{isDynamic as f}from"./client-utils";const s=(n,e,t,c,o)=>new Proxy(u=>{const r=t.at(-1),i=o.at(-1);if(u===void 0)throw new Error(`Missing value for dynamic parameter: ${i}`);if(r&&i&&f(r))return s(n,e,[...t],{...c,[i]:u},o);throw new Error(`${r} is not dynamic`)},{get(u,r){const i=n(r,{paths:t,params:c,dynamicKeys:o,options:e});return i!==void 0?i:f(r)?s(n,e,[...t,r],c,[...o,r]):s(n,e,[...t,r],c,o)}}),l=n=>(e="/",t={})=>s(n,t,[e],{},[]);export{l as makeCreateRpc};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ValidationSchema, RouteResponse, Handler } from "./route-types";
|
|
2
|
+
import type { Params, Query } from "./types";
|
|
3
|
+
import type { HttpMethod } from "../lib/types";
|
|
4
|
+
export declare const createHandler: <THttpMethod extends HttpMethod, TParams extends Params, TQuery extends Query, TValidationSchema extends ValidationSchema>() => <TRouteResponse extends RouteResponse>(handler: Handler<THttpMethod, TParams, TQuery, TValidationSchema, TRouteResponse>) => Handler<THttpMethod, TParams, TQuery, TValidationSchema, TRouteResponse>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const t=()=>e=>e;export{t as createHandler};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{NextResponse as a}from"next/server";import{searchParamsToObject as p}from"./server-utils";const d=(s,o)=>{const n={};return{req:Object.assign(s,{query:()=>p(s.nextUrl.searchParams),params:()=>o.params,valid:t=>n[t],addValidatedData:(t,e)=>{n[t]=e}}),body:(t,e)=>new a(t,e),json:(t,e)=>a.json(t,e),text:(t,e)=>new a(t,{...e,headers:{"Content-Type":"text/plain",...e?.headers}}),redirect:(t,e)=>a.redirect(t,e)}};export{d as createRouteContext};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Inspired by Hono (https://github.com/honojs/hono),
|
|
3
3
|
* particularly its routing design and handler interface.
|
|
4
|
-
*/import{createRouteContext as d}from"./
|
|
4
|
+
*/import{createRouteContext as d}from"./route-context";const i=(o,e)=>async(n,s)=>{const a=d(n,s);try{for(const t of o){const r=await t(a);if(r instanceof Response)return r}throw new Error("No handler returned a response")}catch(t){return await e(t,a)}},T=o=>()=>{const e=n=>(...s)=>{const t=i(s,o??((r,p)=>{throw r}));return{[n]:t}};return{get:e("GET"),post:e("POST"),put:e("PUT"),delete:e("DELETE"),patch:e("PATCH"),head:e("HEAD"),options:e("OPTIONS")}};export{T as routeHandlerFactory};
|
|
@@ -19,7 +19,7 @@ export interface ValidationSchema {
|
|
|
19
19
|
input: {};
|
|
20
20
|
output: {};
|
|
21
21
|
}
|
|
22
|
-
export type Handler<TParams = Params, TQuery = Query, TValidationSchema extends ValidationSchema = ValidationSchema, TRouteResponse extends RouteResponse = RouteResponse> = (routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => TRouteResponse;
|
|
22
|
+
export type Handler<_THttpMethod extends HttpMethod, TParams = Params, TQuery = Query, TValidationSchema extends ValidationSchema = ValidationSchema, TRouteResponse extends RouteResponse = RouteResponse> = (routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => TRouteResponse;
|
|
23
23
|
export type ErrorHandler<TRouteResponse extends RequiredRouteResponse, TParams = Params, TQuery = Query, TValidationSchema extends ValidationSchema = ValidationSchema> = (error: unknown, routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => TRouteResponse;
|
|
24
24
|
export type RouteHandlerResponse<TRouteResponse extends RouteResponse, _TValidationSchema extends ValidationSchema> = Promise<Exclude<Awaited<TRouteResponse>, void | undefined>>;
|
|
25
25
|
export type RouteHandler<TParams extends RouteBindings["params"], TRouteResponse extends RouteResponse, TValidationSchema extends ValidationSchema> = (req: NextRequest, segmentData: {
|
|
@@ -31,11 +31,11 @@ export interface MethodRouteDefinition<THttpMethod extends HttpMethod, TBindings
|
|
|
31
31
|
} ? Awaited<TValue> : Params, TQuery extends TBindings["query"] = TBindings extends {
|
|
32
32
|
query: infer TValue;
|
|
33
33
|
} ? TValue : Query> {
|
|
34
|
-
<TV1 extends ValidationSchema = ValidationSchema, TR1 extends RequiredRouteResponse = RequiredRouteResponse>(handler: Handler<TParams, TQuery, TV1, TR1>): HttpMethodMapping<THttpMethod, TParams, TR1 | TOnErrorResponse, TV1>;
|
|
35
|
-
<TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TR1 extends RouteResponse = RouteResponse, TR2 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<TParams, TQuery, TV1, TR1>, handler2: Handler<TParams, TQuery, TV2, TR2>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TOnErrorResponse, TV2>;
|
|
36
|
-
<TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<TParams, TQuery, TV1, TR1>, handler2: Handler<TParams, TQuery, TV2, TR2>, handler3: Handler<TParams, TQuery, TV3, TR3>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TOnErrorResponse, TV3>;
|
|
37
|
-
<TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TV4 extends ValidationSchema = TV1 & TV2 & TV3, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RouteResponse = RouteResponse, TR4 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<TParams, TQuery, TV1, TR1>, handler2: Handler<TParams, TQuery, TV2, TR2>, handler3: Handler<TParams, TQuery, TV3, TR3>, handler4: Handler<TParams, TQuery, TV4, TR4>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TR4 | TOnErrorResponse, TV4>;
|
|
38
|
-
<TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TV4 extends ValidationSchema = TV1 & TV2 & TV3, TV5 extends ValidationSchema = TV1 & TV2 & TV3 & TV4, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RouteResponse = RouteResponse, TR4 extends RouteResponse = RouteResponse, TR5 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<TParams, TQuery, TV1, TR1>, handler2: Handler<TParams, TQuery, TV2, TR2>, handler3: Handler<TParams, TQuery, TV3, TR3>, handler4: Handler<TParams, TQuery, TV4, TR4>, handler5: Handler<TParams, TQuery, TV5, TR5>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TR4 | TR5 | TOnErrorResponse, TV5>;
|
|
39
|
-
<TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TV4 extends ValidationSchema = TV1 & TV2 & TV3, TV5 extends ValidationSchema = TV1 & TV2 & TV3 & TV4, TV6 extends ValidationSchema = TV1 & TV2 & TV3 & TV4 & TV5, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RouteResponse = RouteResponse, TR4 extends RouteResponse = RouteResponse, TR5 extends RouteResponse = RouteResponse, TR6 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<TParams, TQuery, TV1, TR1>, handler2: Handler<TParams, TQuery, TV2, TR2>, handler3: Handler<TParams, TQuery, TV3, TR3>, handler4: Handler<TParams, TQuery, TV4, TR4>, handler5: Handler<TParams, TQuery, TV5, TR5>, handler6: Handler<TParams, TQuery, TV6, TR6>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TR4 | TR5 | TR6 | TOnErrorResponse, TV6>;
|
|
34
|
+
<TV1 extends ValidationSchema = ValidationSchema, TR1 extends RequiredRouteResponse = RequiredRouteResponse>(handler: Handler<THttpMethod, TParams, TQuery, TV1, TR1>): HttpMethodMapping<THttpMethod, TParams, TR1 | TOnErrorResponse, TV1>;
|
|
35
|
+
<TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TR1 extends RouteResponse = RouteResponse, TR2 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<THttpMethod, TParams, TQuery, TV1, TR1>, handler2: Handler<THttpMethod, TParams, TQuery, TV2, TR2>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TOnErrorResponse, TV2>;
|
|
36
|
+
<TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<THttpMethod, TParams, TQuery, TV1, TR1>, handler2: Handler<THttpMethod, TParams, TQuery, TV2, TR2>, handler3: Handler<THttpMethod, TParams, TQuery, TV3, TR3>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TOnErrorResponse, TV3>;
|
|
37
|
+
<TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TV4 extends ValidationSchema = TV1 & TV2 & TV3, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RouteResponse = RouteResponse, TR4 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<THttpMethod, TParams, TQuery, TV1, TR1>, handler2: Handler<THttpMethod, TParams, TQuery, TV2, TR2>, handler3: Handler<THttpMethod, TParams, TQuery, TV3, TR3>, handler4: Handler<THttpMethod, TParams, TQuery, TV4, TR4>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TR4 | TOnErrorResponse, TV4>;
|
|
38
|
+
<TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TV4 extends ValidationSchema = TV1 & TV2 & TV3, TV5 extends ValidationSchema = TV1 & TV2 & TV3 & TV4, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RouteResponse = RouteResponse, TR4 extends RouteResponse = RouteResponse, TR5 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<THttpMethod, TParams, TQuery, TV1, TR1>, handler2: Handler<THttpMethod, TParams, TQuery, TV2, TR2>, handler3: Handler<THttpMethod, TParams, TQuery, TV3, TR3>, handler4: Handler<THttpMethod, TParams, TQuery, TV4, TR4>, handler5: Handler<THttpMethod, TParams, TQuery, TV5, TR5>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TR4 | TR5 | TOnErrorResponse, TV5>;
|
|
39
|
+
<TV1 extends ValidationSchema = ValidationSchema, TV2 extends ValidationSchema = TV1, TV3 extends ValidationSchema = TV1 & TV2, TV4 extends ValidationSchema = TV1 & TV2 & TV3, TV5 extends ValidationSchema = TV1 & TV2 & TV3 & TV4, TV6 extends ValidationSchema = TV1 & TV2 & TV3 & TV4 & TV5, TR1 extends RouteResponse = RouteResponse, TR2 extends RouteResponse = RouteResponse, TR3 extends RouteResponse = RouteResponse, TR4 extends RouteResponse = RouteResponse, TR5 extends RouteResponse = RouteResponse, TR6 extends RequiredRouteResponse = RequiredRouteResponse>(handler1: Handler<THttpMethod, TParams, TQuery, TV1, TR1>, handler2: Handler<THttpMethod, TParams, TQuery, TV2, TR2>, handler3: Handler<THttpMethod, TParams, TQuery, TV3, TR3>, handler4: Handler<THttpMethod, TParams, TQuery, TV4, TR4>, handler5: Handler<THttpMethod, TParams, TQuery, TV5, TR5>, handler6: Handler<THttpMethod, TParams, TQuery, TV6, TR6>): HttpMethodMapping<THttpMethod, TParams, TR1 | TR2 | TR3 | TR4 | TR5 | TR6 | TOnErrorResponse, TV6>;
|
|
40
40
|
}
|
|
41
41
|
export {};
|
|
@@ -2,6 +2,7 @@ import type { ValidationSchema } from "./route-types";
|
|
|
2
2
|
import type { ContentType } from "../lib/content-type-types";
|
|
3
3
|
import type { HttpResponseHeaders } from "../lib/http-response-headers-types";
|
|
4
4
|
import type { HttpStatusCode, RedirectionHttpStatusCode, SuccessfulHttpStatusCode } from "../lib/http-status-code-types";
|
|
5
|
+
import type { HttpMethod } from "../lib/types";
|
|
5
6
|
import type { NextResponse, NextRequest } from "next/server";
|
|
6
7
|
/**
|
|
7
8
|
* Represents the result of an HTTP response status check.
|
|
@@ -99,7 +100,7 @@ export interface RouteContext<TParams = Params, TQuery = Query, TValidationSchem
|
|
|
99
100
|
* @param target - The part of the request to validate.
|
|
100
101
|
* @returns The validation result of the target.
|
|
101
102
|
*/
|
|
102
|
-
valid: <TValidationTarget extends ValidationTarget>(target: TValidationTarget) => ValidationOutputFor<TValidationTarget, TValidationSchema>;
|
|
103
|
+
valid: <TValidationTarget extends ValidationTarget>(target: Extract<TValidationTarget, keyof TValidationSchema["output"]>) => ValidationOutputFor<TValidationTarget, TValidationSchema>;
|
|
103
104
|
/**
|
|
104
105
|
* Stores validated data for a specific part of the request.
|
|
105
106
|
* This data can be retrieved later using `valid(...)`.
|
|
@@ -107,7 +108,7 @@ export interface RouteContext<TParams = Params, TQuery = Query, TValidationSchem
|
|
|
107
108
|
* @param target - The request part to associate the value with.
|
|
108
109
|
* @param value - The validated data.
|
|
109
110
|
*/
|
|
110
|
-
addValidatedData: (target: ValidationTarget, value:
|
|
111
|
+
addValidatedData: (target: ValidationTarget, value: ValidatedData) => void;
|
|
111
112
|
};
|
|
112
113
|
/**
|
|
113
114
|
* Creates a typed response with an optional status.
|
|
@@ -145,7 +146,12 @@ export interface RouteContext<TParams = Params, TQuery = Query, TValidationSchem
|
|
|
145
146
|
*/
|
|
146
147
|
redirect: <TStatus extends RedirectionHttpStatusCode = 302>(url: string, init?: TStatus | TypedResponseInit<TStatus, "">) => TypedNextResponse<undefined, TStatus, "">;
|
|
147
148
|
}
|
|
148
|
-
|
|
149
|
+
declare const __validatedBrand: unique symbol;
|
|
150
|
+
export type ValidatedData = {
|
|
151
|
+
[__validatedBrand]: true;
|
|
152
|
+
};
|
|
153
|
+
type ValidationTargetKey = "params" | "query" | "json" | "headers" | "cookies";
|
|
154
|
+
export type ValidationTarget<THttpMethod extends HttpMethod = HttpMethod> = THttpMethod extends "GET" | "HEAD" ? Exclude<ValidationTargetKey, "json"> : ValidationTargetKey;
|
|
149
155
|
type ValidationFor<TDirection extends keyof ValidationSchema, TTarget extends ValidationTarget, TSchema extends ValidationSchema> = TTarget extends keyof TSchema[TDirection] ? TSchema[TDirection][TTarget] : never;
|
|
150
156
|
export type ValidationInputFor<TTarget extends ValidationTarget, TSchema extends ValidationSchema> = ValidationFor<"input", TTarget, TSchema>;
|
|
151
157
|
type ValidationOutputFor<TTarget extends ValidationTarget, TSchema extends ValidationSchema> = ValidationFor<"output", TTarget, TSchema>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Portions of this code are based on the Hono project (https://github.com/honojs/hono),
|
|
3
|
+
* originally created by Yusuke Wada (https://github.com/yusukebe) and developed with
|
|
4
|
+
* contributions from the Hono community.
|
|
5
|
+
* This code has been adapted and modified for this project.
|
|
6
|
+
* Original copyright belongs to Yusuke Wada and the Hono project contributors.
|
|
7
|
+
* Hono is licensed under the MIT License.
|
|
8
|
+
*/
|
|
9
|
+
import type { HttpMethod } from "../../lib/types";
|
|
10
|
+
import type { ValidationSchema } from "../route-types";
|
|
11
|
+
import type { Params, Query, RouteContext, TypedNextResponse, ValidatedData, ValidationTarget } from "../types";
|
|
12
|
+
export declare const validator: <THttpMethod extends HttpMethod, TValidationTarget extends ValidationTarget<THttpMethod>, TParams extends Params, TQuery extends Query, TValidationSchema extends ValidationSchema>() => <TTypedNextResponse extends TypedNextResponse>(target: TValidationTarget, validateHandler: (value: object, routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => Promise<ValidatedData | TTypedNextResponse>) => import("../route-types").Handler<THttpMethod, TParams, TQuery, TValidationSchema, Promise<TTypedNextResponse | undefined>>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Portions of this code are based on the Hono project (https://github.com/honojs/hono),
|
|
3
|
+
* originally created by Yusuke Wada (https://github.com/yusukebe) and developed with
|
|
4
|
+
* contributions from the Hono community.
|
|
5
|
+
* This code has been adapted and modified for this project.
|
|
6
|
+
* Original copyright belongs to Yusuke Wada and the Hono project contributors.
|
|
7
|
+
* Hono is licensed under the MIT License.
|
|
8
|
+
*/import{createHandler as i}from"../handler";import{getCookiesObject as n,getHeadersObject as s}from"./validator-utils";const T=()=>(e,r)=>i()(async t=>{const o=await(async()=>{if(e==="params")return await t.req.params();if(e==="query")return t.req.query();if(e==="json")return t.req.json();if(e==="headers")return await s();if(e==="cookies")return await n();throw new Error(`Unexpected target: ${e}`)})(),a=await r(o,t);if(a instanceof Response)return a;t.req.addValidatedData(e,a)});export{T as validator};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { zValidator } from "./zod-validator";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{zValidator as a}from"./zod-validator";export{a as zValidator};
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
* Original copyright belongs to Yusuke Wada and the Hono project contributors.
|
|
7
7
|
* Hono is licensed under the MIT License.
|
|
8
8
|
*/
|
|
9
|
+
import type { HttpMethod } from "../../../lib/types";
|
|
9
10
|
import type { ValidationSchema } from "../../route-types";
|
|
10
11
|
import type { RouteContext, Params, Query, TypedNextResponse, ConditionalValidationInput, ValidationTarget } from "../../types";
|
|
11
12
|
import type { z, ZodSchema } from "zod";
|
|
12
|
-
export declare const
|
|
13
|
+
export declare const zValidator: <THttpMethod extends HttpMethod, TValidationTarget extends ValidationTarget<THttpMethod>, TSchema extends ZodSchema<any>, TParams extends ConditionalValidationInput<TValidationTarget, "params", TValidationSchema, Params> & Params, TQuery extends ConditionalValidationInput<TValidationTarget, "query", TValidationSchema, Query> & Query, TInput = z.input<TSchema>, TOutput = z.output<TSchema>, TValidationSchema extends ValidationSchema = {
|
|
13
14
|
input: Record<TValidationTarget, TInput>;
|
|
14
15
|
output: Record<TValidationTarget, TOutput>;
|
|
15
|
-
}, THookReturn extends TypedNextResponse | void = TypedNextResponse<z.SafeParseError<TInput>, 400, "application/json"> | void>(target: TValidationTarget, schema: TSchema, hook?: (result: z.SafeParseReturnType<TInput, TOutput>, routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => THookReturn) => import("../../route-types").Handler<TParams, TQuery, TValidationSchema, Promise<Exclude<THookReturn, void> | undefined>>;
|
|
16
|
+
}, THookReturn extends TypedNextResponse | void = TypedNextResponse<z.SafeParseError<TInput>, 400, "application/json"> | void>(target: TValidationTarget, schema: TSchema, hook?: (result: z.SafeParseReturnType<TInput, TOutput>, routeContext: RouteContext<TParams, TQuery, TValidationSchema>) => THookReturn) => import("../../route-types").Handler<THttpMethod, TParams, TQuery, TValidationSchema, Promise<Exclude<THookReturn, void> | undefined>>;
|
|
@@ -5,4 +5,4 @@
|
|
|
5
5
|
* This code has been adapted and modified for this project.
|
|
6
6
|
* Original copyright belongs to Yusuke Wada and the Hono project contributors.
|
|
7
7
|
* Hono is licensed under the MIT License.
|
|
8
|
-
*/import{
|
|
8
|
+
*/import{validator as s}from"../validator";const T=(n,i,r)=>{const d=r??((t,a)=>{if(!t.success)return a.json(t,{status:400})});return s()(n,async(t,a)=>{const e=await i.safeParseAsync(t),o=d(e,a);if(o instanceof Response)return o;if(!e.success)throw new Error("If you provide a custom hook, you must explicitly return a response when validation fails.");return e.data})};export{T as zValidator};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rpc4next",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Inspired by Hono RPC and Pathpida, rpc4next brings a lightweight and intuitive RPC solution to Next.js, making server-client communication seamless",
|
|
5
5
|
"author": "watanabe-1",
|
|
6
6
|
"license": "MIT",
|
|
@@ -68,7 +68,8 @@
|
|
|
68
68
|
"test:ui": "vitest --ui --coverage.enabled true",
|
|
69
69
|
"test:watch": "vitest --watch",
|
|
70
70
|
"lint": "eslint \"**/*.ts\"",
|
|
71
|
-
"lint:fix": "eslint \"**/*.ts\" --fix"
|
|
71
|
+
"lint:fix": "eslint \"**/*.ts\" --fix",
|
|
72
|
+
"typecheck": "tsc --noEmit"
|
|
72
73
|
},
|
|
73
74
|
"dependencies": {
|
|
74
75
|
"chalk": "^5.4.1",
|
|
@@ -76,7 +77,7 @@
|
|
|
76
77
|
"commander": "^13.1.0"
|
|
77
78
|
},
|
|
78
79
|
"devDependencies": {
|
|
79
|
-
"@types/node": "^22.
|
|
80
|
+
"@types/node": "^22.15.2",
|
|
80
81
|
"@vitest/coverage-v8": "^3.1.2",
|
|
81
82
|
"@vitest/eslint-plugin": "^1.1.43",
|
|
82
83
|
"@vitest/ui": "^3.1.2",
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import type { ValidationSchema, RouteResponse, Handler } from "./route-types";
|
|
2
|
-
import type { Params, Query } from "./types";
|
|
3
|
-
export declare const createHandler: <TParams extends Params, TQuery extends Query, TValidationSchema extends ValidationSchema>() => <TRouteResponse extends RouteResponse>(handler: Handler<TParams, TQuery, TValidationSchema, TRouteResponse>) => Handler<TParams, TQuery, TValidationSchema, TRouteResponse>;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const a=()=>e=>e;export{a as createHandler};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{NextResponse as a}from"next/server";import{searchParamsToObject as p}from"./search-params-to-object";const d=(s,o)=>{const n={};return{req:Object.assign(s,{query:()=>p(s.nextUrl.searchParams),params:()=>o.params,valid:t=>n[t],addValidatedData:(t,e)=>{n[t]=e}}),body:(t,e)=>new a(t,e),json:(t,e)=>a.json(t,e),text:(t,e)=>new a(t,{...e,headers:{"Content-Type":"text/plain",...e?.headers}}),redirect:(t,e)=>a.redirect(t,e)}};export{d as createRouteContext};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|