@richie-rpc/server 1.1.0 → 1.2.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.
@@ -155,9 +155,17 @@ function createErrorResponse(error) {
155
155
  class Router {
156
156
  contract;
157
157
  handlers;
158
- constructor(contract, handlers) {
158
+ basePath;
159
+ constructor(contract, handlers, options) {
159
160
  this.contract = contract;
160
161
  this.handlers = handlers;
162
+ const bp = options?.basePath || "";
163
+ if (bp) {
164
+ this.basePath = bp.startsWith("/") ? bp : `/${bp}`;
165
+ this.basePath = this.basePath.endsWith("/") ? this.basePath.slice(0, -1) : this.basePath;
166
+ } else {
167
+ this.basePath = "";
168
+ }
161
169
  }
162
170
  findEndpoint(method, path) {
163
171
  for (const [name, endpoint] of Object.entries(this.contract)) {
@@ -174,7 +182,10 @@ class Router {
174
182
  try {
175
183
  const url = new URL(request.url);
176
184
  const method = request.method;
177
- const path = url.pathname;
185
+ let path = url.pathname;
186
+ if (this.basePath && path.startsWith(this.basePath)) {
187
+ path = path.slice(this.basePath.length) || "/";
188
+ }
178
189
  const match = this.findEndpoint(method, path);
179
190
  if (!match) {
180
191
  throw new RouteNotFoundError(path, method);
@@ -192,9 +203,9 @@ class Router {
192
203
  return (request) => this.handle(request);
193
204
  }
194
205
  }
195
- function createRouter(contract, handlers) {
196
- return new Router(contract, handlers);
206
+ function createRouter(contract, handlers, options) {
207
+ return new Router(contract, handlers, options);
197
208
  }
198
209
  })
199
210
 
200
- //# debugId=161D525670FA0BC964756E2164756E21
211
+ //# debugId=40B7D7B6952E66ED64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../index.ts"],
4
4
  "sourcesContent": [
5
- "import type {\n Contract,\n EndpointDefinition,\n ExtractBody,\n ExtractHeaders,\n ExtractParams,\n ExtractQuery,\n} from '@richie-rpc/core';\nimport { matchPath, parseQuery, Status } from '@richie-rpc/core';\nimport type { z } from 'zod';\n\n// Re-export Status for convenience\nexport { Status };\n\n// Handler input types\nexport type HandlerInput<T extends EndpointDefinition> = {\n params: ExtractParams<T>;\n query: ExtractQuery<T>;\n headers: ExtractHeaders<T>;\n body: ExtractBody<T>;\n request: Request;\n};\n\n// Handler response type\nexport type HandlerResponse<T extends EndpointDefinition> = {\n [Status in keyof T['responses']]: {\n status: Status;\n body: T['responses'][Status] extends z.ZodTypeAny ? z.infer<T['responses'][Status]> : never;\n headers?: Record<string, string>;\n };\n}[keyof T['responses']];\n\n// Handler function type\nexport type Handler<T extends EndpointDefinition> = (\n input: HandlerInput<T>,\n) => Promise<HandlerResponse<T>> | HandlerResponse<T>;\n\n// Contract handlers mapping\nexport type ContractHandlers<T extends Contract> = {\n [K in keyof T]: Handler<T[K]>;\n};\n\n// Error classes\nexport class ValidationError extends Error {\n constructor(\n public field: string,\n public issues: z.ZodIssue[],\n message?: string,\n ) {\n super(message || `Validation failed for ${field}`);\n this.name = 'ValidationError';\n }\n}\n\nexport class RouteNotFoundError extends Error {\n constructor(\n public path: string,\n public method: string,\n ) {\n super(`Route not found: ${method} ${path}`);\n this.name = 'RouteNotFoundError';\n }\n}\n\n/**\n * Parse and validate request data\n */\nasync function parseRequest<T extends EndpointDefinition>(\n request: Request,\n endpoint: T,\n pathParams: Record<string, string>,\n): Promise<HandlerInput<T>> {\n const url = new URL(request.url);\n\n // Parse path params\n let params: any = pathParams;\n if (endpoint.params) {\n const result = endpoint.params.safeParse(pathParams);\n if (!result.success) {\n throw new ValidationError('params', result.error.issues);\n }\n params = result.data;\n }\n\n // Parse query params\n let query: any = {};\n if (endpoint.query) {\n const queryData = parseQuery(url.searchParams);\n const result = endpoint.query.safeParse(queryData);\n if (!result.success) {\n throw new ValidationError('query', result.error.issues);\n }\n query = result.data;\n }\n\n // Parse headers\n let headers: any = {};\n if (endpoint.headers) {\n const headersObj: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n headersObj[key] = value;\n });\n const result = endpoint.headers.safeParse(headersObj);\n if (!result.success) {\n throw new ValidationError('headers', result.error.issues);\n }\n headers = result.data;\n }\n\n // Parse body\n let body: any;\n if (endpoint.body) {\n const contentType = request.headers.get('content-type') || '';\n let bodyData: any;\n\n if (contentType.includes('application/json')) {\n bodyData = await request.json();\n } else if (contentType.includes('application/x-www-form-urlencoded')) {\n const formData = await request.formData();\n bodyData = Object.fromEntries(formData.entries());\n } else if (contentType.includes('multipart/form-data')) {\n const formData = await request.formData();\n bodyData = Object.fromEntries(formData.entries());\n } else {\n bodyData = await request.text();\n }\n\n const result = endpoint.body.safeParse(bodyData);\n if (!result.success) {\n throw new ValidationError('body', result.error.issues);\n }\n body = result.data;\n }\n\n return { params, query, headers, body, request } as HandlerInput<T>;\n}\n\n/**\n * Validate and create response\n */\nfunction createResponse<T extends EndpointDefinition>(\n endpoint: T,\n handlerResponse: HandlerResponse<T>,\n): Response {\n const { status, body, headers: customHeaders } = handlerResponse;\n\n // Validate response body\n const responseSchema = endpoint.responses[status as keyof typeof endpoint.responses];\n if (responseSchema) {\n const result = responseSchema.safeParse(body);\n if (!result.success) {\n throw new ValidationError(`response[${String(status)}]`, result.error.issues);\n }\n }\n\n // Create response headers\n const responseHeaders = new Headers(customHeaders);\n\n // Handle 204 No Content - must have no body\n if (status === 204) {\n return new Response(null, {\n status: 204,\n headers: responseHeaders,\n });\n }\n\n // For all other responses, return JSON\n if (!responseHeaders.has('content-type')) {\n responseHeaders.set('content-type', 'application/json');\n }\n\n return new Response(JSON.stringify(body), {\n status: status as number,\n headers: responseHeaders,\n });\n}\n\n/**\n * Create error response\n */\nfunction createErrorResponse(error: unknown): Response {\n if (error instanceof ValidationError) {\n return Response.json(\n {\n error: 'Validation Error',\n field: error.field,\n issues: error.issues,\n },\n { status: 400 },\n );\n }\n\n if (error instanceof RouteNotFoundError) {\n return Response.json({ error: 'Not Found', message: error.message }, { status: 404 });\n }\n\n console.error('Internal server error:', error);\n return Response.json({ error: 'Internal Server Error' }, { status: 500 });\n}\n\n/**\n * Router class that manages contract endpoints\n */\nexport class Router<T extends Contract> {\n constructor(\n private contract: T,\n private handlers: ContractHandlers<T>,\n ) {}\n\n /**\n * Find matching endpoint for a request\n */\n private findEndpoint(\n method: string,\n path: string,\n ): { name: keyof T; endpoint: EndpointDefinition; params: Record<string, string> } | null {\n for (const [name, endpoint] of Object.entries(this.contract)) {\n if (endpoint.method === method) {\n const params = matchPath(endpoint.path, path);\n if (params !== null) {\n return { name, endpoint, params };\n }\n }\n }\n return null;\n }\n\n /**\n * Handle a request\n */\n async handle(request: Request): Promise<Response> {\n try {\n const url = new URL(request.url);\n const method = request.method;\n const path = url.pathname;\n\n const match = this.findEndpoint(method, path);\n if (!match) {\n throw new RouteNotFoundError(path, method);\n }\n\n const { name, endpoint, params } = match;\n const handler = this.handlers[name];\n\n // Parse and validate request\n const input = await parseRequest(request, endpoint, params);\n\n // Call handler\n const handlerResponse = await handler(input as any);\n\n // Create and validate response\n return createResponse(endpoint as T[keyof T], handlerResponse);\n } catch (error) {\n return createErrorResponse(error);\n }\n }\n\n /**\n * Get fetch handler compatible with Bun.serve\n */\n get fetch() {\n return (request: Request) => this.handle(request);\n }\n}\n\n/**\n * Create a router from a contract and handlers\n */\nexport function createRouter<T extends Contract>(\n contract: T,\n handlers: ContractHandlers<T>,\n): Router<T> {\n return new Router(contract, handlers);\n}\n"
5
+ "import type {\n Contract,\n EndpointDefinition,\n ExtractBody,\n ExtractHeaders,\n ExtractParams,\n ExtractQuery,\n} from '@richie-rpc/core';\nimport { matchPath, parseQuery, Status } from '@richie-rpc/core';\nimport type { z } from 'zod';\n\n// Re-export Status for convenience\nexport { Status };\n\n// Handler input types\nexport type HandlerInput<T extends EndpointDefinition> = {\n params: ExtractParams<T>;\n query: ExtractQuery<T>;\n headers: ExtractHeaders<T>;\n body: ExtractBody<T>;\n request: Request;\n};\n\n// Handler response type\nexport type HandlerResponse<T extends EndpointDefinition> = {\n [Status in keyof T['responses']]: {\n status: Status;\n body: T['responses'][Status] extends z.ZodTypeAny ? z.infer<T['responses'][Status]> : never;\n headers?: Record<string, string>;\n };\n}[keyof T['responses']];\n\n// Handler function type\nexport type Handler<T extends EndpointDefinition> = (\n input: HandlerInput<T>,\n) => Promise<HandlerResponse<T>> | HandlerResponse<T>;\n\n// Contract handlers mapping\nexport type ContractHandlers<T extends Contract> = {\n [K in keyof T]: Handler<T[K]>;\n};\n\n// Error classes\nexport class ValidationError extends Error {\n constructor(\n public field: string,\n public issues: z.ZodIssue[],\n message?: string,\n ) {\n super(message || `Validation failed for ${field}`);\n this.name = 'ValidationError';\n }\n}\n\nexport class RouteNotFoundError extends Error {\n constructor(\n public path: string,\n public method: string,\n ) {\n super(`Route not found: ${method} ${path}`);\n this.name = 'RouteNotFoundError';\n }\n}\n\n/**\n * Parse and validate request data\n */\nasync function parseRequest<T extends EndpointDefinition>(\n request: Request,\n endpoint: T,\n pathParams: Record<string, string>,\n): Promise<HandlerInput<T>> {\n const url = new URL(request.url);\n\n // Parse path params\n let params: any = pathParams;\n if (endpoint.params) {\n const result = endpoint.params.safeParse(pathParams);\n if (!result.success) {\n throw new ValidationError('params', result.error.issues);\n }\n params = result.data;\n }\n\n // Parse query params\n let query: any = {};\n if (endpoint.query) {\n const queryData = parseQuery(url.searchParams);\n const result = endpoint.query.safeParse(queryData);\n if (!result.success) {\n throw new ValidationError('query', result.error.issues);\n }\n query = result.data;\n }\n\n // Parse headers\n let headers: any = {};\n if (endpoint.headers) {\n const headersObj: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n headersObj[key] = value;\n });\n const result = endpoint.headers.safeParse(headersObj);\n if (!result.success) {\n throw new ValidationError('headers', result.error.issues);\n }\n headers = result.data;\n }\n\n // Parse body\n let body: any;\n if (endpoint.body) {\n const contentType = request.headers.get('content-type') || '';\n let bodyData: any;\n\n if (contentType.includes('application/json')) {\n bodyData = await request.json();\n } else if (contentType.includes('application/x-www-form-urlencoded')) {\n const formData = await request.formData();\n bodyData = Object.fromEntries(formData.entries());\n } else if (contentType.includes('multipart/form-data')) {\n const formData = await request.formData();\n bodyData = Object.fromEntries(formData.entries());\n } else {\n bodyData = await request.text();\n }\n\n const result = endpoint.body.safeParse(bodyData);\n if (!result.success) {\n throw new ValidationError('body', result.error.issues);\n }\n body = result.data;\n }\n\n return { params, query, headers, body, request } as HandlerInput<T>;\n}\n\n/**\n * Validate and create response\n */\nfunction createResponse<T extends EndpointDefinition>(\n endpoint: T,\n handlerResponse: HandlerResponse<T>,\n): Response {\n const { status, body, headers: customHeaders } = handlerResponse;\n\n // Validate response body\n const responseSchema = endpoint.responses[status as keyof typeof endpoint.responses];\n if (responseSchema) {\n const result = responseSchema.safeParse(body);\n if (!result.success) {\n throw new ValidationError(`response[${String(status)}]`, result.error.issues);\n }\n }\n\n // Create response headers\n const responseHeaders = new Headers(customHeaders);\n\n // Handle 204 No Content - must have no body\n if (status === 204) {\n return new Response(null, {\n status: 204,\n headers: responseHeaders,\n });\n }\n\n // For all other responses, return JSON\n if (!responseHeaders.has('content-type')) {\n responseHeaders.set('content-type', 'application/json');\n }\n\n return new Response(JSON.stringify(body), {\n status: status as number,\n headers: responseHeaders,\n });\n}\n\n/**\n * Create error response\n */\nfunction createErrorResponse(error: unknown): Response {\n if (error instanceof ValidationError) {\n return Response.json(\n {\n error: 'Validation Error',\n field: error.field,\n issues: error.issues,\n },\n { status: 400 },\n );\n }\n\n if (error instanceof RouteNotFoundError) {\n return Response.json({ error: 'Not Found', message: error.message }, { status: 404 });\n }\n\n console.error('Internal server error:', error);\n return Response.json({ error: 'Internal Server Error' }, { status: 500 });\n}\n\n/**\n * Router configuration options\n */\nexport interface RouterOptions {\n basePath?: string;\n}\n\n/**\n * Router class that manages contract endpoints\n */\nexport class Router<T extends Contract> {\n private basePath: string;\n\n constructor(\n private contract: T,\n private handlers: ContractHandlers<T>,\n options?: RouterOptions,\n ) {\n // Normalize basePath: ensure it starts with / and doesn't end with /\n const bp = options?.basePath || '';\n if (bp) {\n this.basePath = bp.startsWith('/') ? bp : `/${bp}`;\n this.basePath = this.basePath.endsWith('/') ? this.basePath.slice(0, -1) : this.basePath;\n } else {\n this.basePath = '';\n }\n }\n\n /**\n * Find matching endpoint for a request\n */\n private findEndpoint(\n method: string,\n path: string,\n ): { name: keyof T; endpoint: EndpointDefinition; params: Record<string, string> } | null {\n for (const [name, endpoint] of Object.entries(this.contract)) {\n if (endpoint.method === method) {\n const params = matchPath(endpoint.path, path);\n if (params !== null) {\n return { name, endpoint, params };\n }\n }\n }\n return null;\n }\n\n /**\n * Handle a request\n */\n async handle(request: Request): Promise<Response> {\n try {\n const url = new URL(request.url);\n const method = request.method;\n let path = url.pathname;\n\n // Strip basePath if configured\n if (this.basePath && path.startsWith(this.basePath)) {\n path = path.slice(this.basePath.length) || '/';\n }\n\n const match = this.findEndpoint(method, path);\n if (!match) {\n throw new RouteNotFoundError(path, method);\n }\n\n const { name, endpoint, params } = match;\n const handler = this.handlers[name];\n\n // Parse and validate request\n const input = await parseRequest(request, endpoint, params);\n\n // Call handler\n const handlerResponse = await handler(input as any);\n\n // Create and validate response\n return createResponse(endpoint as T[keyof T], handlerResponse);\n } catch (error) {\n return createErrorResponse(error);\n }\n }\n\n /**\n * Get fetch handler compatible with Bun.serve\n */\n get fetch() {\n return (request: Request) => this.handle(request);\n }\n}\n\n/**\n * Create a router from a contract and handlers\n */\nexport function createRouter<T extends Contract>(\n contract: T,\n handlers: ContractHandlers<T>,\n options?: RouterOptions,\n): Router<T> {\n return new Router(contract, handlers, options);\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQ8C,IAA9C;AAmCO,MAAM,wBAAwB,MAAM;AAAA,EAEhC;AAAA,EACA;AAAA,EAFT,WAAW,CACF,OACA,QACP,SACA;AAAA,IACA,MAAM,WAAW,yBAAyB,OAAO;AAAA,IAJ1C;AAAA,IACA;AAAA,IAIP,KAAK,OAAO;AAAA;AAEhB;AAAA;AAEO,MAAM,2BAA2B,MAAM;AAAA,EAEnC;AAAA,EACA;AAAA,EAFT,WAAW,CACF,MACA,QACP;AAAA,IACA,MAAM,oBAAoB,UAAU,MAAM;AAAA,IAHnC;AAAA,IACA;AAAA,IAGP,KAAK,OAAO;AAAA;AAEhB;AAKA,eAAe,YAA0C,CACvD,SACA,UACA,YAC0B;AAAA,EAC1B,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAAA,EAG/B,IAAI,SAAc;AAAA,EAClB,IAAI,SAAS,QAAQ;AAAA,IACnB,MAAM,SAAS,SAAS,OAAO,UAAU,UAAU;AAAA,IACnD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,gBAAgB,UAAU,OAAO,MAAM,MAAM;AAAA,IACzD;AAAA,IACA,SAAS,OAAO;AAAA,EAClB;AAAA,EAGA,IAAI,QAAa,CAAC;AAAA,EAClB,IAAI,SAAS,OAAO;AAAA,IAClB,MAAM,YAAY,uBAAW,IAAI,YAAY;AAAA,IAC7C,MAAM,SAAS,SAAS,MAAM,UAAU,SAAS;AAAA,IACjD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,gBAAgB,SAAS,OAAO,MAAM,MAAM;AAAA,IACxD;AAAA,IACA,QAAQ,OAAO;AAAA,EACjB;AAAA,EAGA,IAAI,UAAe,CAAC;AAAA,EACpB,IAAI,SAAS,SAAS;AAAA,IACpB,MAAM,aAAqC,CAAC;AAAA,IAC5C,QAAQ,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AAAA,MACtC,WAAW,OAAO;AAAA,KACnB;AAAA,IACD,MAAM,SAAS,SAAS,QAAQ,UAAU,UAAU;AAAA,IACpD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,gBAAgB,WAAW,OAAO,MAAM,MAAM;AAAA,IAC1D;AAAA,IACA,UAAU,OAAO;AAAA,EACnB;AAAA,EAGA,IAAI;AAAA,EACJ,IAAI,SAAS,MAAM;AAAA,IACjB,MAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc,KAAK;AAAA,IAC3D,IAAI;AAAA,IAEJ,IAAI,YAAY,SAAS,kBAAkB,GAAG;AAAA,MAC5C,WAAW,MAAM,QAAQ,KAAK;AAAA,IAChC,EAAO,SAAI,YAAY,SAAS,mCAAmC,GAAG;AAAA,MACpE,MAAM,WAAW,MAAM,QAAQ,SAAS;AAAA,MACxC,WAAW,OAAO,YAAY,SAAS,QAAQ,CAAC;AAAA,IAClD,EAAO,SAAI,YAAY,SAAS,qBAAqB,GAAG;AAAA,MACtD,MAAM,WAAW,MAAM,QAAQ,SAAS;AAAA,MACxC,WAAW,OAAO,YAAY,SAAS,QAAQ,CAAC;AAAA,IAClD,EAAO;AAAA,MACL,WAAW,MAAM,QAAQ,KAAK;AAAA;AAAA,IAGhC,MAAM,SAAS,SAAS,KAAK,UAAU,QAAQ;AAAA,IAC/C,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,gBAAgB,QAAQ,OAAO,MAAM,MAAM;AAAA,IACvD;AAAA,IACA,OAAO,OAAO;AAAA,EAChB;AAAA,EAEA,OAAO,EAAE,QAAQ,OAAO,SAAS,MAAM,QAAQ;AAAA;AAMjD,SAAS,cAA4C,CACnD,UACA,iBACU;AAAA,EACV,QAAQ,QAAQ,MAAM,SAAS,kBAAkB;AAAA,EAGjD,MAAM,iBAAiB,SAAS,UAAU;AAAA,EAC1C,IAAI,gBAAgB;AAAA,IAClB,MAAM,SAAS,eAAe,UAAU,IAAI;AAAA,IAC5C,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,gBAAgB,YAAY,OAAO,MAAM,MAAM,OAAO,MAAM,MAAM;AAAA,IAC9E;AAAA,EACF;AAAA,EAGA,MAAM,kBAAkB,IAAI,QAAQ,aAAa;AAAA,EAGjD,IAAI,WAAW,KAAK;AAAA,IAClB,OAAO,IAAI,SAAS,MAAM;AAAA,MACxB,QAAQ;AAAA,MACR,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAGA,IAAI,CAAC,gBAAgB,IAAI,cAAc,GAAG;AAAA,IACxC,gBAAgB,IAAI,gBAAgB,kBAAkB;AAAA,EACxD;AAAA,EAEA,OAAO,IAAI,SAAS,KAAK,UAAU,IAAI,GAAG;AAAA,IACxC;AAAA,IACA,SAAS;AAAA,EACX,CAAC;AAAA;AAMH,SAAS,mBAAmB,CAAC,OAA0B;AAAA,EACrD,IAAI,iBAAiB,iBAAiB;AAAA,IACpC,OAAO,SAAS,KACd;AAAA,MACE,OAAO;AAAA,MACP,OAAO,MAAM;AAAA,MACb,QAAQ,MAAM;AAAA,IAChB,GACA,EAAE,QAAQ,IAAI,CAChB;AAAA,EACF;AAAA,EAEA,IAAI,iBAAiB,oBAAoB;AAAA,IACvC,OAAO,SAAS,KAAK,EAAE,OAAO,aAAa,SAAS,MAAM,QAAQ,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACtF;AAAA,EAEA,QAAQ,MAAM,0BAA0B,KAAK;AAAA,EAC7C,OAAO,SAAS,KAAK,EAAE,OAAO,wBAAwB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA;AAAA;AAMnE,MAAM,OAA2B;AAAA,EAE5B;AAAA,EACA;AAAA,EAFV,WAAW,CACD,UACA,UACR;AAAA,IAFQ;AAAA,IACA;AAAA;AAAA,EAMF,YAAY,CAClB,QACA,MACwF;AAAA,IACxF,YAAY,MAAM,aAAa,OAAO,QAAQ,KAAK,QAAQ,GAAG;AAAA,MAC5D,IAAI,SAAS,WAAW,QAAQ;AAAA,QAC9B,MAAM,SAAS,sBAAU,SAAS,MAAM,IAAI;AAAA,QAC5C,IAAI,WAAW,MAAM;AAAA,UACnB,OAAO,EAAE,MAAM,UAAU,OAAO;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,OAMH,OAAM,CAAC,SAAqC;AAAA,IAChD,IAAI;AAAA,MACF,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAAA,MAC/B,MAAM,SAAS,QAAQ;AAAA,MACvB,MAAM,OAAO,IAAI;AAAA,MAEjB,MAAM,QAAQ,KAAK,aAAa,QAAQ,IAAI;AAAA,MAC5C,IAAI,CAAC,OAAO;AAAA,QACV,MAAM,IAAI,mBAAmB,MAAM,MAAM;AAAA,MAC3C;AAAA,MAEA,QAAQ,MAAM,UAAU,WAAW;AAAA,MACnC,MAAM,UAAU,KAAK,SAAS;AAAA,MAG9B,MAAM,QAAQ,MAAM,aAAa,SAAS,UAAU,MAAM;AAAA,MAG1D,MAAM,kBAAkB,MAAM,QAAQ,KAAY;AAAA,MAGlD,OAAO,eAAe,UAAwB,eAAe;AAAA,MAC7D,OAAO,OAAO;AAAA,MACd,OAAO,oBAAoB,KAAK;AAAA;AAAA;AAAA,MAOhC,KAAK,GAAG;AAAA,IACV,OAAO,CAAC,YAAqB,KAAK,OAAO,OAAO;AAAA;AAEpD;AAKO,SAAS,YAAgC,CAC9C,UACA,UACW;AAAA,EACX,OAAO,IAAI,OAAO,UAAU,QAAQ;AAAA;",
8
- "debugId": "161D525670FA0BC964756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "40B7D7B6952E66ED64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@richie-rpc/server",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "type": "commonjs"
5
5
  }
@@ -118,9 +118,17 @@ function createErrorResponse(error) {
118
118
  class Router {
119
119
  contract;
120
120
  handlers;
121
- constructor(contract, handlers) {
121
+ basePath;
122
+ constructor(contract, handlers, options) {
122
123
  this.contract = contract;
123
124
  this.handlers = handlers;
125
+ const bp = options?.basePath || "";
126
+ if (bp) {
127
+ this.basePath = bp.startsWith("/") ? bp : `/${bp}`;
128
+ this.basePath = this.basePath.endsWith("/") ? this.basePath.slice(0, -1) : this.basePath;
129
+ } else {
130
+ this.basePath = "";
131
+ }
124
132
  }
125
133
  findEndpoint(method, path) {
126
134
  for (const [name, endpoint] of Object.entries(this.contract)) {
@@ -137,7 +145,10 @@ class Router {
137
145
  try {
138
146
  const url = new URL(request.url);
139
147
  const method = request.method;
140
- const path = url.pathname;
148
+ let path = url.pathname;
149
+ if (this.basePath && path.startsWith(this.basePath)) {
150
+ path = path.slice(this.basePath.length) || "/";
151
+ }
141
152
  const match = this.findEndpoint(method, path);
142
153
  if (!match) {
143
154
  throw new RouteNotFoundError(path, method);
@@ -155,8 +166,8 @@ class Router {
155
166
  return (request) => this.handle(request);
156
167
  }
157
168
  }
158
- function createRouter(contract, handlers) {
159
- return new Router(contract, handlers);
169
+ function createRouter(contract, handlers, options) {
170
+ return new Router(contract, handlers, options);
160
171
  }
161
172
  export {
162
173
  createRouter,
@@ -166,4 +177,4 @@ export {
166
177
  RouteNotFoundError
167
178
  };
168
179
 
169
- //# debugId=137645904680723464756E2164756E21
180
+ //# debugId=F3FA981C312BCBC564756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../index.ts"],
4
4
  "sourcesContent": [
5
- "import type {\n Contract,\n EndpointDefinition,\n ExtractBody,\n ExtractHeaders,\n ExtractParams,\n ExtractQuery,\n} from '@richie-rpc/core';\nimport { matchPath, parseQuery, Status } from '@richie-rpc/core';\nimport type { z } from 'zod';\n\n// Re-export Status for convenience\nexport { Status };\n\n// Handler input types\nexport type HandlerInput<T extends EndpointDefinition> = {\n params: ExtractParams<T>;\n query: ExtractQuery<T>;\n headers: ExtractHeaders<T>;\n body: ExtractBody<T>;\n request: Request;\n};\n\n// Handler response type\nexport type HandlerResponse<T extends EndpointDefinition> = {\n [Status in keyof T['responses']]: {\n status: Status;\n body: T['responses'][Status] extends z.ZodTypeAny ? z.infer<T['responses'][Status]> : never;\n headers?: Record<string, string>;\n };\n}[keyof T['responses']];\n\n// Handler function type\nexport type Handler<T extends EndpointDefinition> = (\n input: HandlerInput<T>,\n) => Promise<HandlerResponse<T>> | HandlerResponse<T>;\n\n// Contract handlers mapping\nexport type ContractHandlers<T extends Contract> = {\n [K in keyof T]: Handler<T[K]>;\n};\n\n// Error classes\nexport class ValidationError extends Error {\n constructor(\n public field: string,\n public issues: z.ZodIssue[],\n message?: string,\n ) {\n super(message || `Validation failed for ${field}`);\n this.name = 'ValidationError';\n }\n}\n\nexport class RouteNotFoundError extends Error {\n constructor(\n public path: string,\n public method: string,\n ) {\n super(`Route not found: ${method} ${path}`);\n this.name = 'RouteNotFoundError';\n }\n}\n\n/**\n * Parse and validate request data\n */\nasync function parseRequest<T extends EndpointDefinition>(\n request: Request,\n endpoint: T,\n pathParams: Record<string, string>,\n): Promise<HandlerInput<T>> {\n const url = new URL(request.url);\n\n // Parse path params\n let params: any = pathParams;\n if (endpoint.params) {\n const result = endpoint.params.safeParse(pathParams);\n if (!result.success) {\n throw new ValidationError('params', result.error.issues);\n }\n params = result.data;\n }\n\n // Parse query params\n let query: any = {};\n if (endpoint.query) {\n const queryData = parseQuery(url.searchParams);\n const result = endpoint.query.safeParse(queryData);\n if (!result.success) {\n throw new ValidationError('query', result.error.issues);\n }\n query = result.data;\n }\n\n // Parse headers\n let headers: any = {};\n if (endpoint.headers) {\n const headersObj: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n headersObj[key] = value;\n });\n const result = endpoint.headers.safeParse(headersObj);\n if (!result.success) {\n throw new ValidationError('headers', result.error.issues);\n }\n headers = result.data;\n }\n\n // Parse body\n let body: any;\n if (endpoint.body) {\n const contentType = request.headers.get('content-type') || '';\n let bodyData: any;\n\n if (contentType.includes('application/json')) {\n bodyData = await request.json();\n } else if (contentType.includes('application/x-www-form-urlencoded')) {\n const formData = await request.formData();\n bodyData = Object.fromEntries(formData.entries());\n } else if (contentType.includes('multipart/form-data')) {\n const formData = await request.formData();\n bodyData = Object.fromEntries(formData.entries());\n } else {\n bodyData = await request.text();\n }\n\n const result = endpoint.body.safeParse(bodyData);\n if (!result.success) {\n throw new ValidationError('body', result.error.issues);\n }\n body = result.data;\n }\n\n return { params, query, headers, body, request } as HandlerInput<T>;\n}\n\n/**\n * Validate and create response\n */\nfunction createResponse<T extends EndpointDefinition>(\n endpoint: T,\n handlerResponse: HandlerResponse<T>,\n): Response {\n const { status, body, headers: customHeaders } = handlerResponse;\n\n // Validate response body\n const responseSchema = endpoint.responses[status as keyof typeof endpoint.responses];\n if (responseSchema) {\n const result = responseSchema.safeParse(body);\n if (!result.success) {\n throw new ValidationError(`response[${String(status)}]`, result.error.issues);\n }\n }\n\n // Create response headers\n const responseHeaders = new Headers(customHeaders);\n\n // Handle 204 No Content - must have no body\n if (status === 204) {\n return new Response(null, {\n status: 204,\n headers: responseHeaders,\n });\n }\n\n // For all other responses, return JSON\n if (!responseHeaders.has('content-type')) {\n responseHeaders.set('content-type', 'application/json');\n }\n\n return new Response(JSON.stringify(body), {\n status: status as number,\n headers: responseHeaders,\n });\n}\n\n/**\n * Create error response\n */\nfunction createErrorResponse(error: unknown): Response {\n if (error instanceof ValidationError) {\n return Response.json(\n {\n error: 'Validation Error',\n field: error.field,\n issues: error.issues,\n },\n { status: 400 },\n );\n }\n\n if (error instanceof RouteNotFoundError) {\n return Response.json({ error: 'Not Found', message: error.message }, { status: 404 });\n }\n\n console.error('Internal server error:', error);\n return Response.json({ error: 'Internal Server Error' }, { status: 500 });\n}\n\n/**\n * Router class that manages contract endpoints\n */\nexport class Router<T extends Contract> {\n constructor(\n private contract: T,\n private handlers: ContractHandlers<T>,\n ) {}\n\n /**\n * Find matching endpoint for a request\n */\n private findEndpoint(\n method: string,\n path: string,\n ): { name: keyof T; endpoint: EndpointDefinition; params: Record<string, string> } | null {\n for (const [name, endpoint] of Object.entries(this.contract)) {\n if (endpoint.method === method) {\n const params = matchPath(endpoint.path, path);\n if (params !== null) {\n return { name, endpoint, params };\n }\n }\n }\n return null;\n }\n\n /**\n * Handle a request\n */\n async handle(request: Request): Promise<Response> {\n try {\n const url = new URL(request.url);\n const method = request.method;\n const path = url.pathname;\n\n const match = this.findEndpoint(method, path);\n if (!match) {\n throw new RouteNotFoundError(path, method);\n }\n\n const { name, endpoint, params } = match;\n const handler = this.handlers[name];\n\n // Parse and validate request\n const input = await parseRequest(request, endpoint, params);\n\n // Call handler\n const handlerResponse = await handler(input as any);\n\n // Create and validate response\n return createResponse(endpoint as T[keyof T], handlerResponse);\n } catch (error) {\n return createErrorResponse(error);\n }\n }\n\n /**\n * Get fetch handler compatible with Bun.serve\n */\n get fetch() {\n return (request: Request) => this.handle(request);\n }\n}\n\n/**\n * Create a router from a contract and handlers\n */\nexport function createRouter<T extends Contract>(\n contract: T,\n handlers: ContractHandlers<T>,\n): Router<T> {\n return new Router(contract, handlers);\n}\n"
5
+ "import type {\n Contract,\n EndpointDefinition,\n ExtractBody,\n ExtractHeaders,\n ExtractParams,\n ExtractQuery,\n} from '@richie-rpc/core';\nimport { matchPath, parseQuery, Status } from '@richie-rpc/core';\nimport type { z } from 'zod';\n\n// Re-export Status for convenience\nexport { Status };\n\n// Handler input types\nexport type HandlerInput<T extends EndpointDefinition> = {\n params: ExtractParams<T>;\n query: ExtractQuery<T>;\n headers: ExtractHeaders<T>;\n body: ExtractBody<T>;\n request: Request;\n};\n\n// Handler response type\nexport type HandlerResponse<T extends EndpointDefinition> = {\n [Status in keyof T['responses']]: {\n status: Status;\n body: T['responses'][Status] extends z.ZodTypeAny ? z.infer<T['responses'][Status]> : never;\n headers?: Record<string, string>;\n };\n}[keyof T['responses']];\n\n// Handler function type\nexport type Handler<T extends EndpointDefinition> = (\n input: HandlerInput<T>,\n) => Promise<HandlerResponse<T>> | HandlerResponse<T>;\n\n// Contract handlers mapping\nexport type ContractHandlers<T extends Contract> = {\n [K in keyof T]: Handler<T[K]>;\n};\n\n// Error classes\nexport class ValidationError extends Error {\n constructor(\n public field: string,\n public issues: z.ZodIssue[],\n message?: string,\n ) {\n super(message || `Validation failed for ${field}`);\n this.name = 'ValidationError';\n }\n}\n\nexport class RouteNotFoundError extends Error {\n constructor(\n public path: string,\n public method: string,\n ) {\n super(`Route not found: ${method} ${path}`);\n this.name = 'RouteNotFoundError';\n }\n}\n\n/**\n * Parse and validate request data\n */\nasync function parseRequest<T extends EndpointDefinition>(\n request: Request,\n endpoint: T,\n pathParams: Record<string, string>,\n): Promise<HandlerInput<T>> {\n const url = new URL(request.url);\n\n // Parse path params\n let params: any = pathParams;\n if (endpoint.params) {\n const result = endpoint.params.safeParse(pathParams);\n if (!result.success) {\n throw new ValidationError('params', result.error.issues);\n }\n params = result.data;\n }\n\n // Parse query params\n let query: any = {};\n if (endpoint.query) {\n const queryData = parseQuery(url.searchParams);\n const result = endpoint.query.safeParse(queryData);\n if (!result.success) {\n throw new ValidationError('query', result.error.issues);\n }\n query = result.data;\n }\n\n // Parse headers\n let headers: any = {};\n if (endpoint.headers) {\n const headersObj: Record<string, string> = {};\n request.headers.forEach((value, key) => {\n headersObj[key] = value;\n });\n const result = endpoint.headers.safeParse(headersObj);\n if (!result.success) {\n throw new ValidationError('headers', result.error.issues);\n }\n headers = result.data;\n }\n\n // Parse body\n let body: any;\n if (endpoint.body) {\n const contentType = request.headers.get('content-type') || '';\n let bodyData: any;\n\n if (contentType.includes('application/json')) {\n bodyData = await request.json();\n } else if (contentType.includes('application/x-www-form-urlencoded')) {\n const formData = await request.formData();\n bodyData = Object.fromEntries(formData.entries());\n } else if (contentType.includes('multipart/form-data')) {\n const formData = await request.formData();\n bodyData = Object.fromEntries(formData.entries());\n } else {\n bodyData = await request.text();\n }\n\n const result = endpoint.body.safeParse(bodyData);\n if (!result.success) {\n throw new ValidationError('body', result.error.issues);\n }\n body = result.data;\n }\n\n return { params, query, headers, body, request } as HandlerInput<T>;\n}\n\n/**\n * Validate and create response\n */\nfunction createResponse<T extends EndpointDefinition>(\n endpoint: T,\n handlerResponse: HandlerResponse<T>,\n): Response {\n const { status, body, headers: customHeaders } = handlerResponse;\n\n // Validate response body\n const responseSchema = endpoint.responses[status as keyof typeof endpoint.responses];\n if (responseSchema) {\n const result = responseSchema.safeParse(body);\n if (!result.success) {\n throw new ValidationError(`response[${String(status)}]`, result.error.issues);\n }\n }\n\n // Create response headers\n const responseHeaders = new Headers(customHeaders);\n\n // Handle 204 No Content - must have no body\n if (status === 204) {\n return new Response(null, {\n status: 204,\n headers: responseHeaders,\n });\n }\n\n // For all other responses, return JSON\n if (!responseHeaders.has('content-type')) {\n responseHeaders.set('content-type', 'application/json');\n }\n\n return new Response(JSON.stringify(body), {\n status: status as number,\n headers: responseHeaders,\n });\n}\n\n/**\n * Create error response\n */\nfunction createErrorResponse(error: unknown): Response {\n if (error instanceof ValidationError) {\n return Response.json(\n {\n error: 'Validation Error',\n field: error.field,\n issues: error.issues,\n },\n { status: 400 },\n );\n }\n\n if (error instanceof RouteNotFoundError) {\n return Response.json({ error: 'Not Found', message: error.message }, { status: 404 });\n }\n\n console.error('Internal server error:', error);\n return Response.json({ error: 'Internal Server Error' }, { status: 500 });\n}\n\n/**\n * Router configuration options\n */\nexport interface RouterOptions {\n basePath?: string;\n}\n\n/**\n * Router class that manages contract endpoints\n */\nexport class Router<T extends Contract> {\n private basePath: string;\n\n constructor(\n private contract: T,\n private handlers: ContractHandlers<T>,\n options?: RouterOptions,\n ) {\n // Normalize basePath: ensure it starts with / and doesn't end with /\n const bp = options?.basePath || '';\n if (bp) {\n this.basePath = bp.startsWith('/') ? bp : `/${bp}`;\n this.basePath = this.basePath.endsWith('/') ? this.basePath.slice(0, -1) : this.basePath;\n } else {\n this.basePath = '';\n }\n }\n\n /**\n * Find matching endpoint for a request\n */\n private findEndpoint(\n method: string,\n path: string,\n ): { name: keyof T; endpoint: EndpointDefinition; params: Record<string, string> } | null {\n for (const [name, endpoint] of Object.entries(this.contract)) {\n if (endpoint.method === method) {\n const params = matchPath(endpoint.path, path);\n if (params !== null) {\n return { name, endpoint, params };\n }\n }\n }\n return null;\n }\n\n /**\n * Handle a request\n */\n async handle(request: Request): Promise<Response> {\n try {\n const url = new URL(request.url);\n const method = request.method;\n let path = url.pathname;\n\n // Strip basePath if configured\n if (this.basePath && path.startsWith(this.basePath)) {\n path = path.slice(this.basePath.length) || '/';\n }\n\n const match = this.findEndpoint(method, path);\n if (!match) {\n throw new RouteNotFoundError(path, method);\n }\n\n const { name, endpoint, params } = match;\n const handler = this.handlers[name];\n\n // Parse and validate request\n const input = await parseRequest(request, endpoint, params);\n\n // Call handler\n const handlerResponse = await handler(input as any);\n\n // Create and validate response\n return createResponse(endpoint as T[keyof T], handlerResponse);\n } catch (error) {\n return createErrorResponse(error);\n }\n }\n\n /**\n * Get fetch handler compatible with Bun.serve\n */\n get fetch() {\n return (request: Request) => this.handle(request);\n }\n}\n\n/**\n * Create a router from a contract and handlers\n */\nexport function createRouter<T extends Contract>(\n contract: T,\n handlers: ContractHandlers<T>,\n options?: RouterOptions,\n): Router<T> {\n return new Router(contract, handlers, options);\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "137645904680723464756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "F3FA981C312BCBC564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@richie-rpc/server",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "type": "module"
5
5
  }
@@ -30,13 +30,20 @@ export declare class RouteNotFoundError extends Error {
30
30
  method: string;
31
31
  constructor(path: string, method: string);
32
32
  }
33
+ /**
34
+ * Router configuration options
35
+ */
36
+ export interface RouterOptions {
37
+ basePath?: string;
38
+ }
33
39
  /**
34
40
  * Router class that manages contract endpoints
35
41
  */
36
42
  export declare class Router<T extends Contract> {
37
43
  private contract;
38
44
  private handlers;
39
- constructor(contract: T, handlers: ContractHandlers<T>);
45
+ private basePath;
46
+ constructor(contract: T, handlers: ContractHandlers<T>, options?: RouterOptions);
40
47
  /**
41
48
  * Find matching endpoint for a request
42
49
  */
@@ -53,4 +60,4 @@ export declare class Router<T extends Contract> {
53
60
  /**
54
61
  * Create a router from a contract and handlers
55
62
  */
56
- export declare function createRouter<T extends Contract>(contract: T, handlers: ContractHandlers<T>): Router<T>;
63
+ export declare function createRouter<T extends Contract>(contract: T, handlers: ContractHandlers<T>, options?: RouterOptions): Router<T>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@richie-rpc/server",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "main": "./dist/cjs/index.cjs",
5
5
  "exports": {
6
6
  ".": {
@@ -10,7 +10,7 @@
10
10
  }
11
11
  },
12
12
  "peerDependencies": {
13
- "@richie-rpc/core": "^1.1.0",
13
+ "@richie-rpc/core": "^1.2.0",
14
14
  "typescript": "^5",
15
15
  "zod": "^4.1.12"
16
16
  },