@mateosuarezdev/brpc 1.0.49 → 1.0.52

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/index.js.map CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["..\\src\\procedure.ts", "..\\src\\router\\router.ts", "..\\src\\errors\\BRPCError.ts", "..\\src\\router\\RouteMatcher.ts", "..\\..\\..\\node_modules\\.bun\\@mateosuarezdev+headers-builder@1.0.5\\node_modules\\@mateosuarezdev\\headers-builder\\dist\\index.js", "..\\src\\stream\\media.ts", "..\\src\\context.ts", "..\\src\\schemas.ts", "..\\src\\middlewares\\pathblocker\\index.ts", "..\\src\\middlewares\\ratelimiter\\index.ts"],
3
+ "sources": ["..\\src\\procedure.ts", "..\\src\\router\\router.ts", "..\\src\\errors\\BRPCError.ts", "..\\src\\router\\RouteMatcher.ts", "..\\..\\..\\node_modules\\@mateosuarezdev\\headers-builder\\dist\\index.js", "..\\src\\stream\\media.ts", "..\\src\\context.ts", "..\\src\\schemas.ts", "..\\src\\middlewares\\pathblocker\\index.ts", "..\\src\\middlewares\\ratelimiter\\index.ts", "..\\src\\middlewares\\createMiddleware.ts"],
4
4
  "sourcesContent": [
5
- "import { z } from \"zod\";\r\nimport type {\r\n BaseContext,\r\n Handler,\r\n InferInput,\r\n Procedure,\r\n StreamableResponse,\r\n} from \"./types\";\r\nimport type { BunFile } from \"bun\";\r\n\r\nclass ProcedureBuilder<C extends BaseContext> {\r\n private middlewares: ((ctx: C) => Promise<void>)[] = [];\r\n\r\n constructor(middlewares: ((ctx: C) => Promise<void>)[] = []) {\r\n this.middlewares = middlewares;\r\n }\r\n\r\n use(middleware: (ctx: C) => Promise<void>) {\r\n return new ProcedureBuilder<C>([...this.middlewares, middleware]);\r\n }\r\n\r\n input<I extends z.ZodType>(schema: I) {\r\n return new InputProcedureBuilder<C, I>(this.middlewares, schema);\r\n }\r\n\r\n query<O>(\r\n handler: Handler<C, {}, O>\r\n ): Procedure<C, z.ZodObject<{}>, O, \"query\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"query\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n mutation<O>(\r\n handler: Handler<C, {}, O>\r\n ): Procedure<C, z.ZodObject<{}>, O, \"mutation\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"mutation\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n formMutation<O>(\r\n handler: Handler<C, {}, O>\r\n ): Procedure<C, z.ZodObject<{}>, O, \"formMutation\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"formMutation\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n //TODO\r\n // formMutation\r\n // streamMutation\r\n // streamQuery? Is even possible?\r\n\r\n subscription<O>(\r\n handler: Handler<C, {}, O>\r\n ): Procedure<C, z.ZodObject<{}>, O, \"subscription\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"subscription\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n file(\r\n handler: Handler<C, {}, BunFile | Response>\r\n ): Procedure<C, z.ZodObject<{}>, BunFile | Response, \"file\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as BunFile | Response,\r\n _ctx: null as unknown as C,\r\n _type: \"file\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n // NEW: Video streaming file handler using existing Handler type\r\n fileStream(\r\n handler: Handler<C, {}, Blob | string>\r\n ): Procedure<\r\n C,\r\n z.ZodObject<{}>,\r\n StreamableResponse | Blob | string,\r\n \"fileStream\"\r\n > {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as StreamableResponse | Blob | string,\r\n _ctx: null as unknown as C,\r\n _type: \"fileStream\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n html(\r\n handler: Handler<C, {}, string>\r\n ): Procedure<C, z.ZodObject<{}>, string, \"html\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as string,\r\n _ctx: null as unknown as C,\r\n _type: \"html\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n}\r\n\r\nclass InputProcedureBuilder<C extends BaseContext, I extends z.ZodType> {\r\n constructor(\r\n private middlewares: ((ctx: C) => Promise<void>)[],\r\n private inputSchema: I,\r\n private timeoutMs?: number\r\n ) {}\r\n\r\n /**\r\n * Set a custom timeout for this procedure (in milliseconds).\r\n * Overrides the default router timeout.\r\n */\r\n timeout(ms: number) {\r\n return new InputProcedureBuilder<C, I>(\r\n this.middlewares,\r\n this.inputSchema,\r\n ms\r\n );\r\n }\r\n\r\n query<O>(handler: Handler<C, InferInput<I>, O>): Procedure<C, I, O, \"query\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"query\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n mutation<O>(\r\n handler: Handler<C, InferInput<I>, O>\r\n ): Procedure<C, I, O, \"mutation\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"mutation\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n formMutation<O>(\r\n handler: Handler<C, InferInput<I>, O>\r\n ): Procedure<C, I, O, \"formMutation\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"formMutation\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n subscription<O>(\r\n handler: Handler<C, InferInput<I>, O>\r\n ): Procedure<C, I, O, \"subscription\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"subscription\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n file(\r\n handler: Handler<C, InferInput<I>, BunFile | Response>\r\n ): Procedure<C, I, BunFile | Response, \"file\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as BunFile | Response,\r\n _ctx: null as unknown as C,\r\n _type: \"file\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n // NEW: Video streaming file handler using existing Handler type\r\n fileStream(\r\n handler: Handler<C, InferInput<I>, StreamableResponse | Blob | string>\r\n ): Procedure<C, I, StreamableResponse | Blob | string, \"fileStream\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as StreamableResponse | Blob | string,\r\n _ctx: null as unknown as C,\r\n _type: \"fileStream\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n html(\r\n handler: Handler<C, {}, string>\r\n ): Procedure<C, z.ZodObject<{}>, string, \"html\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as string,\r\n _ctx: null as unknown as C,\r\n _type: \"html\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n}\r\n\r\nexport function createProcedure<C extends BaseContext>() {\r\n return new ProcedureBuilder<C>();\r\n}\r\n",
6
- "import type { BunFile, Server, ServerWebSocket, BunRequest } from \"bun\";\r\nimport type {\r\n BaseContext,\r\n InferInput,\r\n Procedure,\r\n ProcedureType,\r\n RouterConfig,\r\n Routes,\r\n} from \"../types\";\r\nimport { ZodError, z } from \"zod\";\r\nimport { BRPCError } from \"../errors/BRPCError\";\r\nimport { type RouteMatch, RouteMatcher } from \"./RouteMatcher\";\r\nimport { buildHeaders, getCorsOrigin } from \"@mateosuarezdev/headers-builder\";\r\nimport {\r\n streamMediaInternal,\r\n type StreamableMediaResponse,\r\n} from \"../stream/media\";\r\n\r\ninterface WebSocketData {\r\n ctx: any;\r\n topics: Set<string>;\r\n lastActivity: number;\r\n}\r\n\r\n//====================\r\n// #region Class\r\n//====================\r\nexport class Router<C extends BaseContext> {\r\n private routes: Routes;\r\n private routeMatcher: RouteMatcher;\r\n private contextCreator: (req: Request) => Promise<C>;\r\n private prefix: string;\r\n private globalMiddlewares: ((ctx: C) => Promise<void>)[];\r\n private server: Server | null = null;\r\n private wsConfig: RouterConfig<C>[\"websocket\"];\r\n private integrations: RouterConfig<C>[\"integrations\"];\r\n private development = process.env.NODE_ENV !== \"production\";\r\n private debug = false;\r\n private allowedOrigins = [];\r\n private onError?: (\r\n error: Error,\r\n { req, route }: { req: Request; route: string },\r\n ) => void;\r\n\r\n // Connection management fields...\r\n private activeConnections: Set<ServerWebSocket<WebSocketData>> = new Set();\r\n private readonly maxConnections: number = parseInt(\r\n process.env.MAX_WS_CONNECTIONS ?? \"1000\",\r\n );\r\n private readonly connectionTimeout: number = parseInt(\r\n process.env.WS_TIMEOUT ?? \"30000\",\r\n );\r\n private readonly maxRequestSize: number = parseInt(\r\n process.env.MAX_REQUEST_SIZE ?? \"10485760\",\r\n );\r\n private readonly requestTimeout: number = parseInt(\r\n process.env.REQUEST_TIMEOUT ?? \"30000\",\r\n );\r\n\r\n constructor(config: RouterConfig<C>) {\r\n this.contextCreator = config.context;\r\n this.prefix = config.prefix ?? \"\";\r\n this.routes = config.routes;\r\n this.globalMiddlewares = config.globalMiddlewares ?? [];\r\n this.wsConfig = config.websocket ?? {};\r\n this.integrations = config.integrations;\r\n this.debug = !!config.debug && process.env.NODE_ENV === \"development\";\r\n this.onError = config.onError;\r\n\r\n // Initialize the route matcher\r\n this.routeMatcher = new RouteMatcher(config.routes, {\r\n enableCaching: !this.development, // Disable cache in dev for hot reloading\r\n maxCacheSize: parseInt(process.env.ROUTE_CACHE_SIZE ?? \"1000\"),\r\n debug: this.debug,\r\n });\r\n\r\n // Start periodic cleanup\r\n if (!this.development) {\r\n setInterval(() => this.cleanupStaleConnections(), 60000);\r\n }\r\n\r\n if (this.debug) {\r\n console.log(\"Router initialized with route matcher\");\r\n console.log(\"Route cache stats:\", this.routeMatcher.getCacheStats());\r\n }\r\n }\r\n\r\n /**\r\n * Simplified route finding using RouteMatcher\r\n */\r\n private findRoute(pathParts: string[]): RouteMatch | null {\r\n return this.routeMatcher.match(pathParts);\r\n }\r\n\r\n /**\r\n * Parses and validates the request input\r\n */\r\n private async parseInput(\r\n req: Request,\r\n schema: z.ZodType,\r\n routeType: ProcedureType,\r\n ): Promise<any> {\r\n let input: any = {};\r\n const url = new URL(req.url);\r\n const queryParams = Object.fromEntries(url.searchParams);\r\n const method = req.method;\r\n\r\n // Check request size for POST requests\r\n if (method === \"POST\") {\r\n const contentLength = parseInt(req.headers.get(\"content-length\") || \"0\");\r\n if (contentLength > this.maxRequestSize) {\r\n throw new Error(\"Request payload too large\");\r\n }\r\n }\r\n\r\n // Handle different procedure types and HTTP methods\r\n if (\r\n method === \"GET\" &&\r\n [\"query\", \"streamQuery\", \"file\", \"fileStream\", \"html\"].includes(routeType)\r\n ) {\r\n input = queryParams;\r\n } else if (\r\n method === \"POST\" &&\r\n [\"mutation\", \"formMutation\", \"streamMutation\"].includes(routeType)\r\n ) {\r\n const contentType = req.headers.get(\"content-type\");\r\n if (contentType?.includes(\"application/json\")) {\r\n input = await req.json();\r\n } else if (contentType?.includes(\"multipart/form-data\")) {\r\n const formData = await req.formData();\r\n //todo investigate about this deprecation\r\n //@ts-ignore\r\n input = await this.parseFormData(formData);\r\n } else {\r\n throw new Error(\"Unsupported content type\");\r\n }\r\n } else {\r\n throw new Error(\r\n `Unsupported request method ${method} for procedure type ${routeType}`,\r\n );\r\n }\r\n\r\n return schema.parse(input);\r\n }\r\n\r\n /**\r\n * Helper method to parse form data\r\n */\r\n private async parseFormData(\r\n formData: FormData,\r\n ): Promise<Record<string, any>> {\r\n const result: Record<string, any> = {};\r\n const fileGroups: Record<string, any[]> = {};\r\n\r\n formData.forEach(async (value, key) => {\r\n if (value instanceof File) {\r\n // Initialize array for this file key if it doesn't exist\r\n if (!fileGroups[key]) {\r\n fileGroups[key] = [];\r\n }\r\n fileGroups[key].push(value);\r\n } else if (typeof value === \"string\") {\r\n // Try to parse JSON strings\r\n try {\r\n result[key] = JSON.parse(value);\r\n } catch {\r\n // If not JSON, keep as string\r\n result[key] = value;\r\n }\r\n }\r\n });\r\n\r\n // Process file groups - ALWAYS return as array\r\n for (const [key, files] of Object.entries(fileGroups)) {\r\n result[key] = files; // ✅ Always an array, even if single file\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * handleError\r\n * @description global error handling for\r\n * each incoming request\r\n */\r\n private handleError(error: any, req: Request): Response {\r\n // Fire error logging with the REAL error (before any mapping)\r\n if (this.onError) {\r\n try {\r\n this.onError(error, { req, route: req.url });\r\n } catch (logError) {\r\n console.error(\"Error logger failed:\", logError);\r\n }\r\n }\r\n\r\n // Handle Zod validation errors\r\n if (\r\n error?.errors &&\r\n Array.isArray(error.errors) &&\r\n error.name === \"ZodError\"\r\n ) {\r\n return new Response(\r\n JSON.stringify({\r\n error: {\r\n name: \"ValidationError\",\r\n code: \"BAD_REQUEST\",\r\n clientCode: \"VALIDATION_ERROR\",\r\n message: \"Input validation failed\",\r\n data: {\r\n validationErrors: error.errors.map((err: any) => ({\r\n path: err.path.join(\".\"),\r\n message: err.message,\r\n code: err.code,\r\n received: err.received,\r\n })),\r\n },\r\n httpStatus: 400,\r\n },\r\n }),\r\n {\r\n status: 400,\r\n headers: buildHeaders()\r\n .contentType(\"json\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n },\r\n );\r\n }\r\n\r\n // Handle BRPCError\r\n if (error instanceof BRPCError) {\r\n return new Response(JSON.stringify({ error: error.toJSON() }), {\r\n status: error.httpStatus,\r\n headers: buildHeaders()\r\n .contentType(\"json\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n // Handle generic Error instances with special messages (backward compatibility)\r\n if (error instanceof Error) {\r\n const status =\r\n error.message === \"Not Found\"\r\n ? 404\r\n : error.message === \"Unauthorized\"\r\n ? 401\r\n : error.message === \"Forbidden\"\r\n ? 403\r\n : error.message === \"Request payload too large\"\r\n ? 413\r\n : error.message === \"Request timeout\"\r\n ? 504 // Use 504 Gateway Timeout instead of 408 to prevent browser auto-retry\r\n : 500;\r\n\r\n const errorCode =\r\n status === 404\r\n ? \"NOT_FOUND\"\r\n : status === 401\r\n ? \"UNAUTHORIZED\"\r\n : status === 403\r\n ? \"FORBIDDEN\"\r\n : status === 413\r\n ? \"PAYLOAD_TOO_LARGE\"\r\n : status === 504\r\n ? \"GATEWAY_TIMEOUT\"\r\n : \"INTERNAL_SERVER_ERROR\";\r\n\r\n // ✅ Safe message for client (never expose internal errors)\r\n const clientMessage =\r\n status < 500\r\n ? error.message // 4xx errors are safe (client's fault)\r\n : \"Internal Server Error\"; // 5xx errors hide details\r\n\r\n return new Response(\r\n JSON.stringify({\r\n error: {\r\n code: errorCode,\r\n message: clientMessage,\r\n },\r\n }),\r\n {\r\n status,\r\n headers: buildHeaders()\r\n .contentType(\"json\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n },\r\n );\r\n }\r\n\r\n // Fallback for unknown errors\r\n return new Response(\r\n JSON.stringify({\r\n error: {\r\n code: \"INTERNAL_SERVER_ERROR\",\r\n message: \"Internal Server Error\", // Generic safe message\r\n },\r\n }),\r\n {\r\n status: 500,\r\n headers: buildHeaders()\r\n .contentType(\"json\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n },\r\n );\r\n }\r\n\r\n /**\r\n * handles the default cache control headers for file routes\r\n */\r\n private handleFileCacheControl(contentType: string) {\r\n let cacheControl: string;\r\n if (contentType?.includes(\"text/html\")) {\r\n cacheControl = \"public, max-age=0, must-revalidate\";\r\n } else if (\r\n contentType?.includes(\"text/css\") ||\r\n contentType?.includes(\"text/javascript\") ||\r\n contentType?.includes(\"application/javascript\")\r\n ) {\r\n cacheControl = \"public, max-age=31536000, immutable\";\r\n } else {\r\n cacheControl = \"public, max-age=86400, stale-while-revalidate=604800\";\r\n }\r\n return cacheControl;\r\n }\r\n\r\n /**\r\n * Handles the behavior of each request\r\n */\r\n private async handleRequest(\r\n req: Request,\r\n server?: Server,\r\n ): Promise<Response> {\r\n try {\r\n // Handle OPTIONS preflight requests without timeout\r\n if (req.method === \"OPTIONS\") {\r\n return new Response(null, {\r\n status: 204,\r\n headers: buildHeaders()\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n const url = new URL(req.url);\r\n let path = url.pathname;\r\n path = path.startsWith(this.prefix)\r\n ? path.slice(this.prefix.length)\r\n : path;\r\n path = path.startsWith(\"/\") ? path : \"/\" + path;\r\n\r\n // Handle WebSocket upgrade without timeout\r\n if (path === \"/ws\" && server) {\r\n if (this.debug) {\r\n console.log(\"🔌 WebSocket upgrade requested\");\r\n }\r\n return this.handleWebSocketUpgrade(req, server);\r\n }\r\n\r\n // Handle root path specially, not returning two parts [\"\",\"\"]\r\n const pathParts = path === \"/\" ? [] : path.split(\"/\").filter(Boolean);\r\n\r\n // Use the optimized route matcher\r\n const routeResult = this.findRoute(pathParts);\r\n\r\n if (!routeResult) {\r\n return new Response(\"Not Found\", {\r\n status: 404,\r\n headers: buildHeaders()\r\n .contentType(\"text\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n const { route } = routeResult;\r\n\r\n // Determine timeout: use procedure-specific timeout or fall back to default\r\n const timeout = route._timeout ?? this.requestTimeout;\r\n\r\n const timeoutPromise = new Promise<Response>((_, reject) => {\r\n setTimeout(() => reject(new Error(\"Request timeout\")), timeout);\r\n });\r\n\r\n return await Promise.race([\r\n this._handleRequest(req, server, routeResult),\r\n timeoutPromise,\r\n ]);\r\n } catch (error) {\r\n return this.handleError(error, req);\r\n }\r\n }\r\n\r\n private async _handleRequest(\r\n req: Request,\r\n server?: Server,\r\n routeResult?: RouteMatch | null,\r\n ): Promise<Response> {\r\n try {\r\n // routeResult is now passed in from handleRequest\r\n if (!routeResult) {\r\n return new Response(\"Not Found\", {\r\n status: 404,\r\n headers: buildHeaders()\r\n .contentType(\"text\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n const { params, route } = routeResult;\r\n\r\n if (!route.handler) {\r\n return new Response(\"Handler not implemented\", {\r\n status: 501,\r\n headers: buildHeaders()\r\n .contentType(\"text\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n // Simple headers storage\r\n const customHeaders: Headers = new Headers();\r\n\r\n // Create context with all the properties from BaseContext\r\n const ctx = await this.contextCreator(req);\r\n Object.assign(ctx, {\r\n params,\r\n publishToProcedure: async <\r\n P extends Procedure<any, any, any, \"subscription\">,\r\n >(\r\n procedure: P,\r\n input: InferInput<P[\"_input\"]>,\r\n params: Record<string, string>,\r\n ) => {\r\n await this.publishToProcedure(procedure, input, ctx, params);\r\n },\r\n headers: customHeaders,\r\n });\r\n\r\n // Run global middlewares\r\n for (const middleware of this.globalMiddlewares) {\r\n await middleware(ctx);\r\n }\r\n\r\n // Run procedure-specific middlewares\r\n for (const middleware of route.middlewares) {\r\n await middleware(ctx);\r\n }\r\n\r\n // Parse input based on procedure type\r\n const input = await this.parseInput(req, route._input, route._type);\r\n const result = await route.handler({ ctx, input });\r\n\r\n const corsHeaders = buildHeaders()\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build();\r\n\r\n Object.keys(corsHeaders).forEach((key) => {\r\n customHeaders.set(key, corsHeaders[key]);\r\n });\r\n\r\n // Handle different response types based on procedure type\r\n return await this.handleProcedureResponse(\r\n route._type,\r\n result,\r\n customHeaders,\r\n );\r\n } catch (error) {\r\n return this.handleError(error, req);\r\n }\r\n }\r\n\r\n /**\r\n * @description Entry point for testing router behavior without starting a server.\r\n * This method processes a request through the full routing pipeline including\r\n * middlewares, validation, and handlers.\r\n *\r\n * @example\r\n * ```typescript\r\n * const request = new Request(\"http://localhost/api/users\", {\r\n * method: \"POST\",\r\n * body: JSON.stringify({ name: \"John\" })\r\n * });\r\n * const response = await router.testRequest(request);\r\n * expect(response.status).toBe(200);\r\n * ```\r\n */\r\n public async testRequest(req: Request): Promise<Response> {\r\n return this.handleRequest(req);\r\n }\r\n\r\n /**\r\n * Handle responses based on procedure type\r\n */\r\n private async handleProcedureResponse(\r\n procedureType: ProcedureType,\r\n result: any,\r\n customHeaders: Headers,\r\n // corsHeaders: Record<string, string>,\r\n ): Promise<Response> {\r\n switch (procedureType) {\r\n case \"file\":\r\n if (result instanceof Response) {\r\n return result;\r\n }\r\n const contentType = (result as BunFile).type;\r\n customHeaders.append(\"Content-Type\", contentType);\r\n customHeaders.append(\r\n \"Cache-Control\",\r\n this.development\r\n ? \"public, max-age=0, must-revalidate\"\r\n : this.handleFileCacheControl(contentType),\r\n );\r\n return new Response(result, {\r\n headers: customHeaders,\r\n });\r\n\r\n case \"fileStream\":\r\n if (\r\n typeof result === \"object\" &&\r\n result !== null &&\r\n \"type\" in result &&\r\n result.type === \"stream\"\r\n ) {\r\n const mediaStreamResult = result as StreamableMediaResponse;\r\n return await streamMediaInternal(\r\n result.file,\r\n result.request,\r\n this.allowedOrigins,\r\n mediaStreamResult.options,\r\n );\r\n }\r\n // Fallback to regular file response\r\n const streamContentType = (result as Blob).type;\r\n customHeaders.append(\"Content-Type\", streamContentType);\r\n customHeaders.append(\r\n \"Cache-Control\",\r\n this.development\r\n ? \"public, max-age=0, must-revalidate\"\r\n : this.handleFileCacheControl(streamContentType),\r\n );\r\n return new Response(result, {\r\n headers: customHeaders,\r\n });\r\n\r\n case \"html\":\r\n // Handle HTML rendering\r\n if (typeof result === \"string\") {\r\n customHeaders.append(\"Content-Type\", \"text/html\");\r\n return new Response(result, {\r\n headers: customHeaders,\r\n });\r\n }\r\n break;\r\n\r\n case \"query\":\r\n case \"mutation\":\r\n case \"formMutation\":\r\n case \"streamQuery\":\r\n case \"streamMutation\":\r\n case \"subscription\":\r\n default:\r\n // Standard JSON response\r\n customHeaders.append(\"Content-Type\", \"application/json\");\r\n return new Response(JSON.stringify({ data: result }), {\r\n headers: customHeaders,\r\n });\r\n }\r\n\r\n // Fallback\r\n customHeaders.append(\"Content-Type\", \"application/json\");\r\n return new Response(JSON.stringify({ data: result }), {\r\n headers: customHeaders,\r\n });\r\n }\r\n\r\n //====================\r\n // #region Websockets\r\n //====================\r\n private cleanupStaleConnections() {\r\n const now = Date.now();\r\n for (const ws of this.activeConnections) {\r\n if (now - ws.data.lastActivity > this.connectionTimeout) {\r\n ws.close();\r\n this.activeConnections.delete(ws);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * handleWebSocketUpgrade\r\n * @description upgrades the incoming request to\r\n * a websocket connection\r\n */\r\n private async handleWebSocketUpgrade(\r\n req: Request,\r\n server: Server,\r\n ): Promise<Response> {\r\n if (this.activeConnections.size >= this.maxConnections) {\r\n return new Response(\"Too many connections\", { status: 503 });\r\n }\r\n\r\n const ctx = await this.contextCreator(req);\r\n for (const middleware of this.globalMiddlewares) {\r\n await middleware(ctx);\r\n }\r\n\r\n const success = server.upgrade<WebSocketData>(req, {\r\n data: {\r\n ctx,\r\n topics: new Set<string>(),\r\n lastActivity: Date.now(),\r\n },\r\n });\r\n\r\n if (success) {\r\n return new Response(null, { status: 101 }); // Switching Protocols\r\n }\r\n\r\n return new Response(\"WebSocket upgrade failed\", { status: 500 });\r\n }\r\n\r\n /**\r\n * Handles WebSocket authentication\r\n */\r\n private async handleAuthenticate(\r\n ws: ServerWebSocket<WebSocketData>,\r\n token: string,\r\n _ctx: C,\r\n ) {\r\n try {\r\n // Extract token from \"Bearer xxx\" format if needed\r\n const finalToken = token.startsWith(\"Bearer \")\r\n ? token.substring(7)\r\n : token;\r\n\r\n // Store the token in the WebSocket context\r\n ws.data.ctx.authToken = finalToken;\r\n\r\n // Additionally, we can verify the token and update the session\r\n // For example, with Supabase:\r\n // const { data, error } = await supabase.auth.getUser(finalToken);\r\n // if (error) throw new Error(error.message);\r\n // ws.data.ctx.session = { user: data.user };\r\n\r\n // Send success response\r\n ws.send(\r\n JSON.stringify({\r\n type: \"auth_success\",\r\n message: \"Authentication successful\",\r\n }),\r\n );\r\n\r\n if (this.debug) {\r\n console.log(\"[BRPC]\", \"WebSocket authenticated successfully\");\r\n }\r\n } catch (error) {\r\n ws.send(\r\n JSON.stringify({\r\n type: \"auth_error\",\r\n error:\r\n error instanceof Error ? error.message : \"Authentication failed\",\r\n }),\r\n );\r\n\r\n if (this.debug) {\r\n console.error(\"WebSocket authentication error:\", error);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * handles the ws client topic subscription\r\n */\r\n private async handleSubscribe(\r\n ws: ServerWebSocket<WebSocketData>,\r\n topic: string,\r\n _ctx: C,\r\n ) {\r\n // Find route first to validate subscription\r\n const routeResult = this.findRoute(topic.split(\"/\").filter(Boolean));\r\n\r\n if (!routeResult || routeResult.route._type !== \"subscription\") {\r\n throw new Error(\"Invalid subscription route\");\r\n }\r\n\r\n ws.subscribe(topic);\r\n ws.data.topics.add(topic);\r\n }\r\n\r\n /**\r\n * handles the ws client topic unsubscription\r\n */\r\n private async handleUnsubscribe(\r\n ws: ServerWebSocket<WebSocketData>,\r\n topic: string,\r\n _ctx: C,\r\n ) {\r\n const routeResult = this.findRoute(topic.split(\"/\").filter(Boolean));\r\n\r\n if (!routeResult || routeResult.route._type !== \"subscription\") {\r\n throw new Error(\"Invalid subscription route\");\r\n }\r\n\r\n ws.unsubscribe(topic);\r\n ws.data.topics.delete(topic);\r\n }\r\n\r\n /**\r\n * handles the message publication of a certain ws client\r\n */\r\n private async handlePublish(\r\n _ws: ServerWebSocket<WebSocketData>,\r\n topic: string,\r\n message: any,\r\n ctx: C,\r\n ) {\r\n const routeResult = this.findRoute(topic.split(\"/\").filter(Boolean));\r\n\r\n if (!routeResult) {\r\n throw new Error(\"Subscription not found\");\r\n }\r\n\r\n const { params, route } = routeResult;\r\n\r\n if (route._type !== \"subscription\" || !route.handler) {\r\n throw new Error(\"Invalid subscription route\");\r\n }\r\n\r\n Object.assign(ctx, { params });\r\n\r\n // Only validate if the procedure has defined input\r\n const validatedMessage = route._input.fields\r\n ? route._input.parse(message)\r\n : message;\r\n\r\n const publishMessage = await route.handler({\r\n ctx,\r\n input: validatedMessage,\r\n });\r\n\r\n const converted = {\r\n topic: topic,\r\n data: publishMessage,\r\n type: \"publish\",\r\n };\r\n\r\n if (this.debug) {\r\n console.log(`Server will publish to ${topic}`, converted);\r\n }\r\n\r\n // this.server!.publish(topic, JSON.stringify(publishMessage));\r\n this.server!.publish(topic, JSON.stringify(converted));\r\n }\r\n\r\n private async publishToProcedure<\r\n P extends Procedure<any, any, any, \"subscription\">,\r\n >(\r\n procedure: P,\r\n input: InferInput<P[\"_input\"]>,\r\n ctx: C,\r\n params: Record<string, string>,\r\n ) {\r\n if (procedure._type !== \"subscription\" || !procedure.handler) {\r\n throw new Error(\"Can only publish to subscription procedures\");\r\n }\r\n\r\n const routePath = this.findRoutePath(this.routes, procedure);\r\n\r\n if (!routePath) {\r\n throw new Error(\"Subscription route not found\");\r\n }\r\n\r\n // Replace params in the path\r\n const finalPath = routePath\r\n .split(\"/\")\r\n .map((part) => {\r\n if (part.startsWith(\":\")) {\r\n const paramName = part.slice(1);\r\n const paramValue = params[paramName];\r\n if (!paramValue) {\r\n throw new Error(`Missing parameter: ${paramName}`);\r\n }\r\n return paramValue;\r\n }\r\n return part;\r\n })\r\n .join(\"/\");\r\n\r\n const result = await procedure.handler({\r\n ctx: { ...ctx, params },\r\n input,\r\n });\r\n\r\n const converted = { topic: finalPath, data: result, type: \"publish\" };\r\n\r\n if (this.debug) {\r\n console.log(`Server will publish to ${finalPath}`, converted);\r\n }\r\n\r\n // this.server?.publish(finalPath, JSON.stringify(result));\r\n this.server?.publish(finalPath, JSON.stringify(converted));\r\n return result;\r\n }\r\n\r\n async publish<P extends Procedure<any, any, any, \"subscription\">>(\r\n procedure: P,\r\n input: InferInput<P[\"_input\"]>,\r\n params?: Record<string, string>,\r\n ) {\r\n if (procedure._type !== \"subscription\" || !procedure.handler) {\r\n throw new Error(\"Can only publish to subscription procedures\");\r\n }\r\n\r\n const routePath = this.findRoutePath(this.routes, procedure);\r\n\r\n if (!routePath) {\r\n throw new Error(\"Subscription route not found\");\r\n }\r\n\r\n // Replace params in the path\r\n const finalPath = routePath\r\n .split(\"/\")\r\n .map((part) => {\r\n if (part.startsWith(\":\")) {\r\n const paramName = part.slice(1);\r\n const paramValue = params ? params[paramName] : null;\r\n if (!paramValue) {\r\n throw new Error(`Missing parameter: ${paramName}`);\r\n }\r\n return paramValue;\r\n }\r\n return part;\r\n })\r\n .join(\"/\");\r\n\r\n const result = await procedure.handler({\r\n ctx: { params },\r\n input,\r\n });\r\n\r\n const converted = { topic: finalPath, data: result, type: \"publish\" };\r\n\r\n if (this.debug) {\r\n console.log(`Server will publish to ${finalPath}`, converted);\r\n }\r\n\r\n // this.server?.publish(finalPath, JSON.stringify(result));\r\n this.server?.publish(finalPath, JSON.stringify(converted));\r\n return result;\r\n }\r\n\r\n /**\r\n * publish\r\n * @description publish a message to a topic from\r\n * the server itself\r\n */\r\n // private publish(topic: string, message: string | Uint8Array) {\r\n // if (this.server) {\r\n // this.server.publish(topic, message);\r\n // } else {\r\n // //?debug\r\n // //console.warn(\"Server not initialized. Cannot publish message.\");\r\n // }\r\n // }\r\n public freePublish<T>(topic: string, message: T) {\r\n const converted = { topic: topic, data: message, type: \"publish\" };\r\n this.server?.publish(topic, JSON.stringify(converted));\r\n }\r\n //====================\r\n // #endregion\r\n //====================\r\n\r\n //====================\r\n // #region Helpers\r\n //====================\r\n /**\r\n * findRoutePath\r\n * @description finds the full path to a procedure in the routes tree\r\n */\r\n private findRoutePath(\r\n routes: Routes,\r\n targetProcedure: Procedure<any, any, any, any>,\r\n prefix: string = \"\",\r\n ): string | null {\r\n for (const [key, value] of Object.entries(routes)) {\r\n const currentPath = prefix ? `${prefix}/${key}` : key;\r\n\r\n if (value === targetProcedure) {\r\n return currentPath;\r\n }\r\n\r\n if (value && typeof value === \"object\" && !(\"_type\" in value)) {\r\n const found = this.findRoutePath(\r\n value as Routes,\r\n targetProcedure,\r\n currentPath,\r\n );\r\n if (found) return found;\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n private getIntegrationRoutes() {\r\n if (!this.integrations) return undefined;\r\n\r\n let routes: any = {}; // Initialize the routes object\r\n\r\n if (this.integrations.betterAuth) {\r\n const handler = this.integrations.betterAuth.handler;\r\n if (!handler) {\r\n throw new Error(\"Please provide a handler for betterAuth integration\");\r\n }\r\n routes[\"/api/auth/*\"] = async (req: BunRequest<\"auth\">) => {\r\n return await handler(req);\r\n };\r\n }\r\n\r\n if (this.integrations.rawRoutes) {\r\n Object.keys(this.integrations.rawRoutes).forEach((val) => {\r\n routes[val] = this.integrations!.rawRoutes![val];\r\n });\r\n }\r\n\r\n return Object.keys(routes).length > 0 ? routes : undefined;\r\n }\r\n\r\n /**\r\n * New utility methods for route management\r\n */\r\n public getRouteStats() {\r\n return {\r\n cache: this.routeMatcher.getCacheStats(),\r\n suggestions: this.routeMatcher.getOptimizationSuggestions(),\r\n };\r\n }\r\n\r\n public clearRouteCache() {\r\n this.routeMatcher.clearCache();\r\n if (this.debug) {\r\n console.log(\"[ROUTEMATCHER] Route cache cleared\");\r\n }\r\n }\r\n\r\n public benchmarkRoutes(\r\n testPaths: string[] = [\"/users/123\", \"/posts/456/comments\"],\r\n iterations = 1000,\r\n ) {\r\n if (this.debug) {\r\n const results = this.routeMatcher.benchmark(testPaths, iterations);\r\n console.log(\"[ROUTEMATCHER]\", \"Route matching benchmark:\", results);\r\n return results;\r\n }\r\n }\r\n\r\n /**\r\n * Hot reload support for development\r\n */\r\n public updateRoutes(newRoutes: Routes) {\r\n if (this.development) {\r\n this.routes = newRoutes;\r\n this.routeMatcher = new RouteMatcher(newRoutes, {\r\n enableCaching: false, // No caching in dev\r\n debug: this.debug,\r\n });\r\n console.log(\"[HMR]\", \"Server Routes updated\");\r\n } else {\r\n console.warn(\"Route updates are only allowed in development mode\");\r\n }\r\n }\r\n //====================\r\n // #endregion\r\n //====================\r\n\r\n //====================\r\n // #region Server\r\n //====================\r\n /**\r\n * Listen\r\n * @description starts up the Bun http server\r\n */\r\n listen(port: number, callback?: () => void) {\r\n this.server = Bun.serve({\r\n port,\r\n routes: this.getIntegrationRoutes(),\r\n fetch: (req, server) => this.handleRequest(req, server),\r\n websocket: {\r\n open: (ws: ServerWebSocket<WebSocketData>) => {\r\n this.activeConnections.add(ws);\r\n if (this.wsConfig?.onOpen) {\r\n this.wsConfig.onOpen(ws, ws.data.ctx);\r\n }\r\n\r\n if (this.debug) {\r\n console.log(\"[BRPC]\", \"WebSocket connection opened\", {\r\n connections: this.activeConnections.size,\r\n });\r\n }\r\n },\r\n message: async (ws: ServerWebSocket<WebSocketData>, message: any) => {\r\n try {\r\n ws.data.lastActivity = Date.now();\r\n const { type, topic, token, data } = JSON.parse(message as string);\r\n // console.log(type, token);\r\n const ctx = ws.data.ctx;\r\n\r\n if (this.debug) {\r\n console.log(\"[BRPC]\", \"WebSocket message received:\", {\r\n type,\r\n topic,\r\n });\r\n }\r\n\r\n switch (type) {\r\n case \"authenticate\":\r\n await this.handleAuthenticate(ws, token, ctx);\r\n break;\r\n case \"subscribe\":\r\n await this.handleSubscribe(ws, topic, ctx);\r\n break;\r\n case \"unsubscribe\":\r\n await this.handleUnsubscribe(ws, topic, ctx);\r\n break;\r\n case \"publish\":\r\n await this.handlePublish(ws, topic, data, ctx);\r\n break;\r\n default:\r\n ws.send(JSON.stringify({ error: \"Unknown message type\" }));\r\n if (this.debug) {\r\n console.error(\"Unknown WebSocket message type:\", type);\r\n }\r\n }\r\n } catch (error) {\r\n if (this.debug) {\r\n console.error(\"[BRPC]\", \"WebSocket message error:\", error);\r\n }\r\n\r\n if (error instanceof ZodError) {\r\n ws.send(JSON.stringify({ error: \"Invalid message format\" }));\r\n } else if (error instanceof Error) {\r\n ws.send(JSON.stringify({ error: error.message }));\r\n }\r\n }\r\n },\r\n close: (\r\n ws: ServerWebSocket<WebSocketData>,\r\n code: number,\r\n reason: string,\r\n ) => {\r\n this.activeConnections.delete(ws);\r\n ws.data.topics.forEach((topic) => {\r\n ws.unsubscribe(topic);\r\n });\r\n\r\n if (this.debug) {\r\n console.log(\"[BRPC]\", \"WebSocket connection closed\", {\r\n code,\r\n reason,\r\n remainingConnections: this.activeConnections.size,\r\n });\r\n }\r\n\r\n if (this.wsConfig?.onClose) {\r\n this.wsConfig.onClose(ws, code, reason, ws.data.ctx);\r\n }\r\n },\r\n },\r\n });\r\n\r\n if (callback) callback();\r\n }\r\n //====================\r\n // #endregion\r\n //====================\r\n}\r\n//====================\r\n// #endregion Class\r\n//====================\r\n\r\n//====================\r\n// #region Exports\r\n//====================\r\n/**\r\n * createRouter\r\n * @description helper function to create a\r\n * Router instance\r\n */\r\nexport function createRouter<C extends BaseContext>(config: RouterConfig<C>) {\r\n return new Router(config);\r\n}\r\n\r\nexport type CreateRouter = ReturnType<typeof createRouter>;\r\n//====================\r\n// #endregion\r\n//====================\r\n",
5
+ "import { z } from \"zod\";\r\nimport type {\r\n BaseContext,\r\n Handler,\r\n InferInput,\r\n Procedure,\r\n StreamableResponse,\r\n} from \"./types\";\r\nimport type { BunFile } from \"bun\";\r\n\r\nclass ProcedureBuilder<C extends BaseContext> {\r\n private middlewares: ((ctx: any) => Promise<Record<string, any> | void>)[] = [];\r\n\r\n constructor(middlewares: ((ctx: any) => Promise<Record<string, any> | void>)[] = []) {\r\n this.middlewares = middlewares;\r\n }\r\n\r\n use<M extends (ctx: C) => Promise<Record<string, any> | void>>(\r\n middleware: M\r\n ): ProcedureBuilder<\r\n Awaited<ReturnType<M>> extends Record<string, any>\r\n ? C & Awaited<ReturnType<M>>\r\n : C\r\n > {\r\n return new ProcedureBuilder<any>([...this.middlewares, middleware]);\r\n }\r\n\r\n input<I extends z.ZodType>(schema: I) {\r\n return new InputProcedureBuilder<C, I>(this.middlewares, schema);\r\n }\r\n\r\n query<O>(\r\n handler: Handler<C, {}, O>\r\n ): Procedure<C, z.ZodObject<{}>, O, \"query\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"query\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n mutation<O>(\r\n handler: Handler<C, {}, O>\r\n ): Procedure<C, z.ZodObject<{}>, O, \"mutation\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"mutation\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n formMutation<O>(\r\n handler: Handler<C, {}, O>\r\n ): Procedure<C, z.ZodObject<{}>, O, \"formMutation\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"formMutation\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n //TODO\r\n // formMutation\r\n // streamMutation\r\n // streamQuery? Is even possible?\r\n\r\n subscription<O>(\r\n handler: Handler<C, {}, O>\r\n ): Procedure<C, z.ZodObject<{}>, O, \"subscription\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"subscription\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n file(\r\n handler: Handler<C, {}, BunFile | Response>\r\n ): Procedure<C, z.ZodObject<{}>, BunFile | Response, \"file\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as BunFile | Response,\r\n _ctx: null as unknown as C,\r\n _type: \"file\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n // NEW: Video streaming file handler using existing Handler type\r\n fileStream(\r\n handler: Handler<C, {}, Blob | string>\r\n ): Procedure<\r\n C,\r\n z.ZodObject<{}>,\r\n StreamableResponse | Blob | string,\r\n \"fileStream\"\r\n > {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as StreamableResponse | Blob | string,\r\n _ctx: null as unknown as C,\r\n _type: \"fileStream\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n html(\r\n handler: Handler<C, {}, string>\r\n ): Procedure<C, z.ZodObject<{}>, string, \"html\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as string,\r\n _ctx: null as unknown as C,\r\n _type: \"html\",\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n}\r\n\r\nclass InputProcedureBuilder<C extends BaseContext, I extends z.ZodType> {\r\n constructor(\r\n private middlewares: ((ctx: any) => Promise<Record<string, any> | void>)[],\r\n private inputSchema: I,\r\n private timeoutMs?: number\r\n ) {}\r\n\r\n /**\r\n * Set a custom timeout for this procedure (in milliseconds).\r\n * Overrides the default router timeout.\r\n */\r\n timeout(ms: number) {\r\n return new InputProcedureBuilder<C, I>(\r\n this.middlewares,\r\n this.inputSchema,\r\n ms\r\n );\r\n }\r\n\r\n query<O>(handler: Handler<C, InferInput<I>, O>): Procedure<C, I, O, \"query\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"query\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n mutation<O>(\r\n handler: Handler<C, InferInput<I>, O>\r\n ): Procedure<C, I, O, \"mutation\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"mutation\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n formMutation<O>(\r\n handler: Handler<C, InferInput<I>, O>\r\n ): Procedure<C, I, O, \"formMutation\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"formMutation\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n subscription<O>(\r\n handler: Handler<C, InferInput<I>, O>\r\n ): Procedure<C, I, O, \"subscription\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as O,\r\n _ctx: null as unknown as C,\r\n _type: \"subscription\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n file(\r\n handler: Handler<C, InferInput<I>, BunFile | Response>\r\n ): Procedure<C, I, BunFile | Response, \"file\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as BunFile | Response,\r\n _ctx: null as unknown as C,\r\n _type: \"file\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n // NEW: Video streaming file handler using existing Handler type\r\n fileStream(\r\n handler: Handler<C, InferInput<I>, StreamableResponse | Blob | string>\r\n ): Procedure<C, I, StreamableResponse | Blob | string, \"fileStream\"> {\r\n return {\r\n _input: this.inputSchema,\r\n _output: null as unknown as StreamableResponse | Blob | string,\r\n _ctx: null as unknown as C,\r\n _type: \"fileStream\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n\r\n html(\r\n handler: Handler<C, {}, string>\r\n ): Procedure<C, z.ZodObject<{}>, string, \"html\"> {\r\n return {\r\n _input: z.object({}),\r\n _output: null as unknown as string,\r\n _ctx: null as unknown as C,\r\n _type: \"html\",\r\n _timeout: this.timeoutMs,\r\n handler,\r\n middlewares: this.middlewares,\r\n };\r\n }\r\n}\r\n\r\nexport function createProcedure<C extends BaseContext>(\r\n _context: (req: Request) => Promise<C>\r\n): ProcedureBuilder<C>;\r\nexport function createProcedure<C extends BaseContext>(): ProcedureBuilder<C>;\r\nexport function createProcedure<C extends BaseContext>(_context?: any): ProcedureBuilder<C> {\r\n return new ProcedureBuilder<C>();\r\n}\r\n",
6
+ "import type { BunFile, Server, ServerWebSocket, BunRequest } from \"bun\";\r\nimport type {\r\n BaseContext,\r\n InferInput,\r\n Procedure,\r\n ProcedureType,\r\n RouterConfig,\r\n Routes,\r\n} from \"../types\";\r\nimport { ZodError, z } from \"zod\";\r\nimport { BRPCError } from \"../errors/BRPCError\";\r\nimport { type RouteMatch, RouteMatcher } from \"./RouteMatcher\";\r\nimport { buildHeaders, getCorsOrigin } from \"@mateosuarezdev/headers-builder\";\r\nimport {\r\n streamMediaInternal,\r\n type StreamableMediaResponse,\r\n} from \"../stream/media\";\r\n\r\ninterface WebSocketData {\r\n ctx: any;\r\n topics: Set<string>;\r\n lastActivity: number;\r\n}\r\n\r\n//====================\r\n// #region Class\r\n//====================\r\nexport class Router<C extends BaseContext> {\r\n private routes: Routes;\r\n private routeMatcher: RouteMatcher;\r\n private contextCreator: (req: Request) => Promise<C>;\r\n private prefix: string;\r\n private globalMiddlewares: ((ctx: C) => Promise<Record<string, any> | void>)[];\r\n private server: Server | null = null;\r\n private wsConfig: RouterConfig<C>[\"websocket\"];\r\n private integrations: RouterConfig<C>[\"integrations\"];\r\n private development = process.env.NODE_ENV !== \"production\";\r\n private debug = false;\r\n private allowedOrigins = [];\r\n private onError?: (\r\n error: Error,\r\n { req, route }: { req: Request; route: string },\r\n ) => void;\r\n\r\n // Connection management fields...\r\n private activeConnections: Set<ServerWebSocket<WebSocketData>> = new Set();\r\n private readonly maxConnections: number = parseInt(\r\n process.env.MAX_WS_CONNECTIONS ?? \"1000\",\r\n );\r\n private readonly connectionTimeout: number = parseInt(\r\n process.env.WS_TIMEOUT ?? \"30000\",\r\n );\r\n private readonly maxRequestSize: number = parseInt(\r\n process.env.MAX_REQUEST_SIZE ?? \"10485760\",\r\n );\r\n private readonly requestTimeout: number = parseInt(\r\n process.env.REQUEST_TIMEOUT ?? \"30000\",\r\n );\r\n\r\n constructor(config: RouterConfig<C>) {\r\n this.contextCreator = config.context;\r\n this.prefix = config.prefix ?? \"\";\r\n this.routes = config.routes;\r\n this.globalMiddlewares = config.globalMiddlewares ?? [];\r\n this.wsConfig = config.websocket ?? {};\r\n this.integrations = config.integrations;\r\n this.debug = !!config.debug && process.env.NODE_ENV === \"development\";\r\n this.onError = config.onError;\r\n\r\n // Initialize the route matcher\r\n this.routeMatcher = new RouteMatcher(config.routes, {\r\n enableCaching: !this.development, // Disable cache in dev for hot reloading\r\n maxCacheSize: parseInt(process.env.ROUTE_CACHE_SIZE ?? \"1000\"),\r\n debug: this.debug,\r\n });\r\n\r\n // Start periodic cleanup\r\n if (!this.development) {\r\n setInterval(() => this.cleanupStaleConnections(), 60000);\r\n }\r\n\r\n if (this.debug) {\r\n console.log(\"Router initialized with route matcher\");\r\n console.log(\"Route cache stats:\", this.routeMatcher.getCacheStats());\r\n }\r\n }\r\n\r\n /**\r\n * Simplified route finding using RouteMatcher\r\n */\r\n private findRoute(pathParts: string[]): RouteMatch | null {\r\n return this.routeMatcher.match(pathParts);\r\n }\r\n\r\n /**\r\n * Parses and validates the request input\r\n */\r\n private async parseInput(\r\n req: Request,\r\n schema: z.ZodType,\r\n routeType: ProcedureType,\r\n ): Promise<any> {\r\n let input: any = {};\r\n const url = new URL(req.url);\r\n const queryParams = Object.fromEntries(url.searchParams);\r\n const method = req.method;\r\n\r\n // Check request size for POST requests\r\n if (method === \"POST\") {\r\n const contentLength = parseInt(req.headers.get(\"content-length\") || \"0\");\r\n if (contentLength > this.maxRequestSize) {\r\n throw new Error(\"Request payload too large\");\r\n }\r\n }\r\n\r\n // Handle different procedure types and HTTP methods\r\n if (\r\n method === \"GET\" &&\r\n [\"query\", \"streamQuery\", \"file\", \"fileStream\", \"html\"].includes(routeType)\r\n ) {\r\n input = queryParams;\r\n } else if (\r\n method === \"POST\" &&\r\n [\"mutation\", \"formMutation\", \"streamMutation\"].includes(routeType)\r\n ) {\r\n const contentType = req.headers.get(\"content-type\");\r\n if (contentType?.includes(\"application/json\")) {\r\n input = await req.json();\r\n } else if (contentType?.includes(\"multipart/form-data\")) {\r\n const formData = await req.formData();\r\n //todo investigate about this deprecation\r\n //@ts-ignore\r\n input = await this.parseFormData(formData);\r\n } else {\r\n throw new Error(\"Unsupported content type\");\r\n }\r\n } else {\r\n throw new Error(\r\n `Unsupported request method ${method} for procedure type ${routeType}`,\r\n );\r\n }\r\n\r\n return schema.parse(input);\r\n }\r\n\r\n /**\r\n * Helper method to parse form data\r\n */\r\n private async parseFormData(\r\n formData: FormData,\r\n ): Promise<Record<string, any>> {\r\n const result: Record<string, any> = {};\r\n const fileGroups: Record<string, any[]> = {};\r\n\r\n formData.forEach(async (value, key) => {\r\n if (value instanceof File) {\r\n // Initialize array for this file key if it doesn't exist\r\n if (!fileGroups[key]) {\r\n fileGroups[key] = [];\r\n }\r\n fileGroups[key].push(value);\r\n } else if (typeof value === \"string\") {\r\n // Try to parse JSON strings\r\n try {\r\n result[key] = JSON.parse(value);\r\n } catch {\r\n // If not JSON, keep as string\r\n result[key] = value;\r\n }\r\n }\r\n });\r\n\r\n // Process file groups - ALWAYS return as array\r\n for (const [key, files] of Object.entries(fileGroups)) {\r\n result[key] = files; // ✅ Always an array, even if single file\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * handleError\r\n * @description global error handling for\r\n * each incoming request\r\n */\r\n private handleError(error: any, req: Request): Response {\r\n // Fire error logging with the REAL error (before any mapping)\r\n if (this.onError) {\r\n try {\r\n this.onError(error, { req, route: req.url });\r\n } catch (logError) {\r\n console.error(\"Error logger failed:\", logError);\r\n }\r\n }\r\n\r\n // Handle Zod validation errors\r\n if (\r\n error?.errors &&\r\n Array.isArray(error.errors) &&\r\n error.name === \"ZodError\"\r\n ) {\r\n return new Response(\r\n JSON.stringify({\r\n error: {\r\n name: \"ValidationError\",\r\n code: \"BAD_REQUEST\",\r\n clientCode: \"VALIDATION_ERROR\",\r\n message: \"Input validation failed\",\r\n data: {\r\n validationErrors: error.errors.map((err: any) => ({\r\n path: err.path.join(\".\"),\r\n message: err.message,\r\n code: err.code,\r\n received: err.received,\r\n })),\r\n },\r\n httpStatus: 400,\r\n },\r\n }),\r\n {\r\n status: 400,\r\n headers: buildHeaders()\r\n .contentType(\"json\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n },\r\n );\r\n }\r\n\r\n // Handle BRPCError\r\n if (error instanceof BRPCError) {\r\n return new Response(JSON.stringify({ error: error.toJSON() }), {\r\n status: error.httpStatus,\r\n headers: buildHeaders()\r\n .contentType(\"json\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n // Handle generic Error instances with special messages (backward compatibility)\r\n if (error instanceof Error) {\r\n const status =\r\n error.message === \"Not Found\"\r\n ? 404\r\n : error.message === \"Unauthorized\"\r\n ? 401\r\n : error.message === \"Forbidden\"\r\n ? 403\r\n : error.message === \"Request payload too large\"\r\n ? 413\r\n : error.message === \"Request timeout\"\r\n ? 504 // Use 504 Gateway Timeout instead of 408 to prevent browser auto-retry\r\n : 500;\r\n\r\n const errorCode =\r\n status === 404\r\n ? \"NOT_FOUND\"\r\n : status === 401\r\n ? \"UNAUTHORIZED\"\r\n : status === 403\r\n ? \"FORBIDDEN\"\r\n : status === 413\r\n ? \"PAYLOAD_TOO_LARGE\"\r\n : status === 504\r\n ? \"GATEWAY_TIMEOUT\"\r\n : \"INTERNAL_SERVER_ERROR\";\r\n\r\n // ✅ Safe message for client (never expose internal errors)\r\n const clientMessage =\r\n status < 500\r\n ? error.message // 4xx errors are safe (client's fault)\r\n : \"Internal Server Error\"; // 5xx errors hide details\r\n\r\n return new Response(\r\n JSON.stringify({\r\n error: {\r\n code: errorCode,\r\n message: clientMessage,\r\n },\r\n }),\r\n {\r\n status,\r\n headers: buildHeaders()\r\n .contentType(\"json\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n },\r\n );\r\n }\r\n\r\n // Fallback for unknown errors\r\n return new Response(\r\n JSON.stringify({\r\n error: {\r\n code: \"INTERNAL_SERVER_ERROR\",\r\n message: \"Internal Server Error\", // Generic safe message\r\n },\r\n }),\r\n {\r\n status: 500,\r\n headers: buildHeaders()\r\n .contentType(\"json\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n },\r\n );\r\n }\r\n\r\n /**\r\n * handles the default cache control headers for file routes\r\n */\r\n private handleFileCacheControl(contentType: string) {\r\n let cacheControl: string;\r\n if (contentType?.includes(\"text/html\")) {\r\n cacheControl = \"public, max-age=0, must-revalidate\";\r\n } else if (\r\n contentType?.includes(\"text/css\") ||\r\n contentType?.includes(\"text/javascript\") ||\r\n contentType?.includes(\"application/javascript\")\r\n ) {\r\n cacheControl = \"public, max-age=31536000, immutable\";\r\n } else {\r\n cacheControl = \"public, max-age=86400, stale-while-revalidate=604800\";\r\n }\r\n return cacheControl;\r\n }\r\n\r\n /**\r\n * Handles the behavior of each request\r\n */\r\n private async handleRequest(\r\n req: Request,\r\n server?: Server,\r\n ): Promise<Response> {\r\n try {\r\n // Handle OPTIONS preflight requests without timeout\r\n if (req.method === \"OPTIONS\") {\r\n return new Response(null, {\r\n status: 204,\r\n headers: buildHeaders()\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n const url = new URL(req.url);\r\n let path = url.pathname;\r\n path = path.startsWith(this.prefix)\r\n ? path.slice(this.prefix.length)\r\n : path;\r\n path = path.startsWith(\"/\") ? path : \"/\" + path;\r\n\r\n // Handle WebSocket upgrade without timeout\r\n if (path === \"/ws\" && server) {\r\n if (this.debug) {\r\n console.log(\"🔌 WebSocket upgrade requested\");\r\n }\r\n return this.handleWebSocketUpgrade(req, server);\r\n }\r\n\r\n // Handle root path specially, not returning two parts [\"\",\"\"]\r\n const pathParts = path === \"/\" ? [] : path.split(\"/\").filter(Boolean);\r\n\r\n // Use the optimized route matcher\r\n const routeResult = this.findRoute(pathParts);\r\n\r\n if (!routeResult) {\r\n return new Response(\"Not Found\", {\r\n status: 404,\r\n headers: buildHeaders()\r\n .contentType(\"text\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n const { route } = routeResult;\r\n\r\n // Determine timeout: use procedure-specific timeout or fall back to default\r\n const timeout = route._timeout ?? this.requestTimeout;\r\n\r\n const timeoutPromise = new Promise<Response>((_, reject) => {\r\n setTimeout(() => reject(new Error(\"Request timeout\")), timeout);\r\n });\r\n\r\n return await Promise.race([\r\n this._handleRequest(req, server, routeResult),\r\n timeoutPromise,\r\n ]);\r\n } catch (error) {\r\n return this.handleError(error, req);\r\n }\r\n }\r\n\r\n private async _handleRequest(\r\n req: Request,\r\n server?: Server,\r\n routeResult?: RouteMatch | null,\r\n ): Promise<Response> {\r\n try {\r\n // routeResult is now passed in from handleRequest\r\n if (!routeResult) {\r\n return new Response(\"Not Found\", {\r\n status: 404,\r\n headers: buildHeaders()\r\n .contentType(\"text\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n const { params, route } = routeResult;\r\n\r\n if (!route.handler) {\r\n return new Response(\"Handler not implemented\", {\r\n status: 501,\r\n headers: buildHeaders()\r\n .contentType(\"text\")\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n // Simple headers storage\r\n const customHeaders: Headers = new Headers();\r\n\r\n // Create context with all the properties from BaseContext\r\n const ctx = await this.contextCreator(req);\r\n Object.assign(ctx, {\r\n req,\r\n params,\r\n publishToProcedure: async <\r\n P extends Procedure<any, any, any, \"subscription\">,\r\n >(\r\n procedure: P,\r\n input: InferInput<P[\"_input\"]>,\r\n params: Record<string, string>,\r\n ) => {\r\n await this.publishToProcedure(procedure, input, ctx, params);\r\n },\r\n headers: customHeaders,\r\n });\r\n\r\n // Run global middlewares\r\n for (const middleware of this.globalMiddlewares) {\r\n const ext = await middleware(ctx);\r\n if (ext !== null && ext !== undefined && typeof ext === \"object\") {\r\n Object.assign(ctx, ext);\r\n }\r\n }\r\n\r\n // Run procedure-specific middlewares\r\n for (const middleware of route.middlewares) {\r\n const ext = await middleware(ctx);\r\n if (ext !== null && ext !== undefined && typeof ext === \"object\") {\r\n Object.assign(ctx, ext);\r\n }\r\n }\r\n\r\n // Parse input based on procedure type\r\n const input = await this.parseInput(req, route._input, route._type);\r\n const result = await route.handler({ ctx, input });\r\n\r\n const corsHeaders = buildHeaders()\r\n .cors({ origin: getCorsOrigin(req, this.allowedOrigins) })\r\n .build();\r\n\r\n Object.keys(corsHeaders).forEach((key) => {\r\n customHeaders.set(key, corsHeaders[key]);\r\n });\r\n\r\n // Handle different response types based on procedure type\r\n return await this.handleProcedureResponse(\r\n route._type,\r\n result,\r\n customHeaders,\r\n );\r\n } catch (error) {\r\n return this.handleError(error, req);\r\n }\r\n }\r\n\r\n /**\r\n * @description Entry point for testing router behavior without starting a server.\r\n * This method processes a request through the full routing pipeline including\r\n * middlewares, validation, and handlers.\r\n *\r\n * @example\r\n * ```typescript\r\n * const request = new Request(\"http://localhost/api/users\", {\r\n * method: \"POST\",\r\n * body: JSON.stringify({ name: \"John\" })\r\n * });\r\n * const response = await router.testRequest(request);\r\n * expect(response.status).toBe(200);\r\n * ```\r\n */\r\n public async testRequest(req: Request): Promise<Response> {\r\n return this.handleRequest(req);\r\n }\r\n\r\n /**\r\n * Handle responses based on procedure type\r\n */\r\n private async handleProcedureResponse(\r\n procedureType: ProcedureType,\r\n result: any,\r\n customHeaders: Headers,\r\n // corsHeaders: Record<string, string>,\r\n ): Promise<Response> {\r\n switch (procedureType) {\r\n case \"file\":\r\n if (result instanceof Response) {\r\n return result;\r\n }\r\n const contentType = (result as BunFile).type;\r\n customHeaders.append(\"Content-Type\", contentType);\r\n customHeaders.append(\r\n \"Cache-Control\",\r\n this.development\r\n ? \"public, max-age=0, must-revalidate\"\r\n : this.handleFileCacheControl(contentType),\r\n );\r\n return new Response(result, {\r\n headers: customHeaders,\r\n });\r\n\r\n case \"fileStream\":\r\n if (\r\n typeof result === \"object\" &&\r\n result !== null &&\r\n \"type\" in result &&\r\n result.type === \"stream\"\r\n ) {\r\n const mediaStreamResult = result as StreamableMediaResponse;\r\n return await streamMediaInternal(\r\n result.file,\r\n result.request,\r\n this.allowedOrigins,\r\n mediaStreamResult.options,\r\n );\r\n }\r\n // Fallback to regular file response\r\n const streamContentType = (result as Blob).type;\r\n customHeaders.append(\"Content-Type\", streamContentType);\r\n customHeaders.append(\r\n \"Cache-Control\",\r\n this.development\r\n ? \"public, max-age=0, must-revalidate\"\r\n : this.handleFileCacheControl(streamContentType),\r\n );\r\n return new Response(result, {\r\n headers: customHeaders,\r\n });\r\n\r\n case \"html\":\r\n // Handle HTML rendering\r\n if (typeof result === \"string\") {\r\n customHeaders.append(\"Content-Type\", \"text/html\");\r\n return new Response(result, {\r\n headers: customHeaders,\r\n });\r\n }\r\n break;\r\n\r\n case \"query\":\r\n case \"mutation\":\r\n case \"formMutation\":\r\n case \"streamQuery\":\r\n case \"streamMutation\":\r\n case \"subscription\":\r\n default:\r\n // Standard JSON response\r\n customHeaders.append(\"Content-Type\", \"application/json\");\r\n return new Response(JSON.stringify({ data: result }), {\r\n headers: customHeaders,\r\n });\r\n }\r\n\r\n // Fallback\r\n customHeaders.append(\"Content-Type\", \"application/json\");\r\n return new Response(JSON.stringify({ data: result }), {\r\n headers: customHeaders,\r\n });\r\n }\r\n\r\n //====================\r\n // #region Websockets\r\n //====================\r\n private cleanupStaleConnections() {\r\n const now = Date.now();\r\n for (const ws of this.activeConnections) {\r\n if (now - ws.data.lastActivity > this.connectionTimeout) {\r\n ws.close();\r\n this.activeConnections.delete(ws);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * handleWebSocketUpgrade\r\n * @description upgrades the incoming request to\r\n * a websocket connection\r\n */\r\n private async handleWebSocketUpgrade(\r\n req: Request,\r\n server: Server,\r\n ): Promise<Response> {\r\n if (this.activeConnections.size >= this.maxConnections) {\r\n return new Response(\"Too many connections\", { status: 503 });\r\n }\r\n\r\n const ctx = await this.contextCreator(req);\r\n Object.assign(ctx, { req });\r\n for (const middleware of this.globalMiddlewares) {\r\n const ext = await middleware(ctx);\r\n if (ext !== null && ext !== undefined && typeof ext === \"object\") {\r\n Object.assign(ctx, ext);\r\n }\r\n }\r\n\r\n const success = server.upgrade<WebSocketData>(req, {\r\n data: {\r\n ctx,\r\n topics: new Set<string>(),\r\n lastActivity: Date.now(),\r\n },\r\n });\r\n\r\n if (success) {\r\n return new Response(null, { status: 101 }); // Switching Protocols\r\n }\r\n\r\n return new Response(\"WebSocket upgrade failed\", { status: 500 });\r\n }\r\n\r\n /**\r\n * Handles WebSocket authentication\r\n */\r\n private async handleAuthenticate(\r\n ws: ServerWebSocket<WebSocketData>,\r\n token: string,\r\n _ctx: C,\r\n ) {\r\n try {\r\n // Extract token from \"Bearer xxx\" format if needed\r\n const finalToken = token.startsWith(\"Bearer \")\r\n ? token.substring(7)\r\n : token;\r\n\r\n // Store the token in the WebSocket context\r\n ws.data.ctx.authToken = finalToken;\r\n\r\n // Additionally, we can verify the token and update the session\r\n // For example, with Supabase:\r\n // const { data, error } = await supabase.auth.getUser(finalToken);\r\n // if (error) throw new Error(error.message);\r\n // ws.data.ctx.session = { user: data.user };\r\n\r\n // Send success response\r\n ws.send(\r\n JSON.stringify({\r\n type: \"auth_success\",\r\n message: \"Authentication successful\",\r\n }),\r\n );\r\n\r\n if (this.debug) {\r\n console.log(\"[BRPC]\", \"WebSocket authenticated successfully\");\r\n }\r\n } catch (error) {\r\n ws.send(\r\n JSON.stringify({\r\n type: \"auth_error\",\r\n error:\r\n error instanceof Error ? error.message : \"Authentication failed\",\r\n }),\r\n );\r\n\r\n if (this.debug) {\r\n console.error(\"WebSocket authentication error:\", error);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * handles the ws client topic subscription\r\n */\r\n private async handleSubscribe(\r\n ws: ServerWebSocket<WebSocketData>,\r\n topic: string,\r\n _ctx: C,\r\n ) {\r\n // Find route first to validate subscription\r\n const routeResult = this.findRoute(topic.split(\"/\").filter(Boolean));\r\n\r\n if (!routeResult || routeResult.route._type !== \"subscription\") {\r\n throw new Error(\"Invalid subscription route\");\r\n }\r\n\r\n ws.subscribe(topic);\r\n ws.data.topics.add(topic);\r\n }\r\n\r\n /**\r\n * handles the ws client topic unsubscription\r\n */\r\n private async handleUnsubscribe(\r\n ws: ServerWebSocket<WebSocketData>,\r\n topic: string,\r\n _ctx: C,\r\n ) {\r\n const routeResult = this.findRoute(topic.split(\"/\").filter(Boolean));\r\n\r\n if (!routeResult || routeResult.route._type !== \"subscription\") {\r\n throw new Error(\"Invalid subscription route\");\r\n }\r\n\r\n ws.unsubscribe(topic);\r\n ws.data.topics.delete(topic);\r\n }\r\n\r\n /**\r\n * handles the message publication of a certain ws client\r\n */\r\n private async handlePublish(\r\n _ws: ServerWebSocket<WebSocketData>,\r\n topic: string,\r\n message: any,\r\n ctx: C,\r\n ) {\r\n const routeResult = this.findRoute(topic.split(\"/\").filter(Boolean));\r\n\r\n if (!routeResult) {\r\n throw new Error(\"Subscription not found\");\r\n }\r\n\r\n const { params, route } = routeResult;\r\n\r\n if (route._type !== \"subscription\" || !route.handler) {\r\n throw new Error(\"Invalid subscription route\");\r\n }\r\n\r\n Object.assign(ctx, { params });\r\n\r\n // Only validate if the procedure has defined input\r\n const validatedMessage = route._input.fields\r\n ? route._input.parse(message)\r\n : message;\r\n\r\n const publishMessage = await route.handler({\r\n ctx,\r\n input: validatedMessage,\r\n });\r\n\r\n const converted = {\r\n topic: topic,\r\n data: publishMessage,\r\n type: \"publish\",\r\n };\r\n\r\n if (this.debug) {\r\n console.log(`Server will publish to ${topic}`, converted);\r\n }\r\n\r\n // this.server!.publish(topic, JSON.stringify(publishMessage));\r\n this.server!.publish(topic, JSON.stringify(converted));\r\n }\r\n\r\n private async publishToProcedure<\r\n P extends Procedure<any, any, any, \"subscription\">,\r\n >(\r\n procedure: P,\r\n input: InferInput<P[\"_input\"]>,\r\n ctx: C,\r\n params: Record<string, string>,\r\n ) {\r\n if (procedure._type !== \"subscription\" || !procedure.handler) {\r\n throw new Error(\"Can only publish to subscription procedures\");\r\n }\r\n\r\n const routePath = this.findRoutePath(this.routes, procedure);\r\n\r\n if (!routePath) {\r\n throw new Error(\"Subscription route not found\");\r\n }\r\n\r\n // Replace params in the path\r\n const finalPath = routePath\r\n .split(\"/\")\r\n .map((part) => {\r\n if (part.startsWith(\":\")) {\r\n const paramName = part.slice(1);\r\n const paramValue = params[paramName];\r\n if (!paramValue) {\r\n throw new Error(`Missing parameter: ${paramName}`);\r\n }\r\n return paramValue;\r\n }\r\n return part;\r\n })\r\n .join(\"/\");\r\n\r\n const result = await procedure.handler({\r\n ctx: { ...ctx, params },\r\n input,\r\n });\r\n\r\n const converted = { topic: finalPath, data: result, type: \"publish\" };\r\n\r\n if (this.debug) {\r\n console.log(`Server will publish to ${finalPath}`, converted);\r\n }\r\n\r\n // this.server?.publish(finalPath, JSON.stringify(result));\r\n this.server?.publish(finalPath, JSON.stringify(converted));\r\n return result;\r\n }\r\n\r\n async publish<P extends Procedure<any, any, any, \"subscription\">>(\r\n procedure: P,\r\n input: InferInput<P[\"_input\"]>,\r\n params?: Record<string, string>,\r\n ) {\r\n if (procedure._type !== \"subscription\" || !procedure.handler) {\r\n throw new Error(\"Can only publish to subscription procedures\");\r\n }\r\n\r\n const routePath = this.findRoutePath(this.routes, procedure);\r\n\r\n if (!routePath) {\r\n throw new Error(\"Subscription route not found\");\r\n }\r\n\r\n // Replace params in the path\r\n const finalPath = routePath\r\n .split(\"/\")\r\n .map((part) => {\r\n if (part.startsWith(\":\")) {\r\n const paramName = part.slice(1);\r\n const paramValue = params ? params[paramName] : null;\r\n if (!paramValue) {\r\n throw new Error(`Missing parameter: ${paramName}`);\r\n }\r\n return paramValue;\r\n }\r\n return part;\r\n })\r\n .join(\"/\");\r\n\r\n const result = await procedure.handler({\r\n ctx: { params },\r\n input,\r\n });\r\n\r\n const converted = { topic: finalPath, data: result, type: \"publish\" };\r\n\r\n if (this.debug) {\r\n console.log(`Server will publish to ${finalPath}`, converted);\r\n }\r\n\r\n // this.server?.publish(finalPath, JSON.stringify(result));\r\n this.server?.publish(finalPath, JSON.stringify(converted));\r\n return result;\r\n }\r\n\r\n /**\r\n * publish\r\n * @description publish a message to a topic from\r\n * the server itself\r\n */\r\n // private publish(topic: string, message: string | Uint8Array) {\r\n // if (this.server) {\r\n // this.server.publish(topic, message);\r\n // } else {\r\n // //?debug\r\n // //console.warn(\"Server not initialized. Cannot publish message.\");\r\n // }\r\n // }\r\n public freePublish<T>(topic: string, message: T) {\r\n const converted = { topic: topic, data: message, type: \"publish\" };\r\n this.server?.publish(topic, JSON.stringify(converted));\r\n }\r\n //====================\r\n // #endregion\r\n //====================\r\n\r\n //====================\r\n // #region Helpers\r\n //====================\r\n /**\r\n * findRoutePath\r\n * @description finds the full path to a procedure in the routes tree\r\n */\r\n private findRoutePath(\r\n routes: Routes,\r\n targetProcedure: Procedure<any, any, any, any>,\r\n prefix: string = \"\",\r\n ): string | null {\r\n for (const [key, value] of Object.entries(routes)) {\r\n const currentPath = prefix ? `${prefix}/${key}` : key;\r\n\r\n if (value === targetProcedure) {\r\n return currentPath;\r\n }\r\n\r\n if (value && typeof value === \"object\" && !(\"_type\" in value)) {\r\n const found = this.findRoutePath(\r\n value as Routes,\r\n targetProcedure,\r\n currentPath,\r\n );\r\n if (found) return found;\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n private getIntegrationRoutes() {\r\n if (!this.integrations) return undefined;\r\n\r\n let routes: any = {}; // Initialize the routes object\r\n\r\n if (this.integrations.betterAuth) {\r\n const handler = this.integrations.betterAuth.handler;\r\n if (!handler) {\r\n throw new Error(\"Please provide a handler for betterAuth integration\");\r\n }\r\n routes[\"/api/auth/*\"] = async (req: BunRequest<\"auth\">) => {\r\n return await handler(req);\r\n };\r\n }\r\n\r\n if (this.integrations.rawRoutes) {\r\n Object.keys(this.integrations.rawRoutes).forEach((val) => {\r\n routes[val] = this.integrations!.rawRoutes![val];\r\n });\r\n }\r\n\r\n return Object.keys(routes).length > 0 ? routes : undefined;\r\n }\r\n\r\n /**\r\n * New utility methods for route management\r\n */\r\n public getRouteStats() {\r\n return {\r\n cache: this.routeMatcher.getCacheStats(),\r\n suggestions: this.routeMatcher.getOptimizationSuggestions(),\r\n };\r\n }\r\n\r\n public clearRouteCache() {\r\n this.routeMatcher.clearCache();\r\n if (this.debug) {\r\n console.log(\"[ROUTEMATCHER] Route cache cleared\");\r\n }\r\n }\r\n\r\n public benchmarkRoutes(\r\n testPaths: string[] = [\"/users/123\", \"/posts/456/comments\"],\r\n iterations = 1000,\r\n ) {\r\n if (this.debug) {\r\n const results = this.routeMatcher.benchmark(testPaths, iterations);\r\n console.log(\"[ROUTEMATCHER]\", \"Route matching benchmark:\", results);\r\n return results;\r\n }\r\n }\r\n\r\n /**\r\n * Hot reload support for development\r\n */\r\n public updateRoutes(newRoutes: Routes) {\r\n if (this.development) {\r\n this.routes = newRoutes;\r\n this.routeMatcher = new RouteMatcher(newRoutes, {\r\n enableCaching: false, // No caching in dev\r\n debug: this.debug,\r\n });\r\n console.log(\"[HMR]\", \"Server Routes updated\");\r\n } else {\r\n console.warn(\"Route updates are only allowed in development mode\");\r\n }\r\n }\r\n //====================\r\n // #endregion\r\n //====================\r\n\r\n //====================\r\n // #region Server\r\n //====================\r\n /**\r\n * Listen\r\n * @description starts up the Bun http server\r\n */\r\n listen(port: number, callback?: () => void) {\r\n this.server = Bun.serve({\r\n port,\r\n routes: this.getIntegrationRoutes(),\r\n fetch: (req, server) => this.handleRequest(req, server),\r\n websocket: {\r\n open: (ws: ServerWebSocket<WebSocketData>) => {\r\n this.activeConnections.add(ws);\r\n if (this.wsConfig?.onOpen) {\r\n this.wsConfig.onOpen(ws, ws.data.ctx);\r\n }\r\n\r\n if (this.debug) {\r\n console.log(\"[BRPC]\", \"WebSocket connection opened\", {\r\n connections: this.activeConnections.size,\r\n });\r\n }\r\n },\r\n message: async (ws: ServerWebSocket<WebSocketData>, message: any) => {\r\n try {\r\n ws.data.lastActivity = Date.now();\r\n const { type, topic, token, data } = JSON.parse(message as string);\r\n // console.log(type, token);\r\n const ctx = ws.data.ctx;\r\n\r\n if (this.debug) {\r\n console.log(\"[BRPC]\", \"WebSocket message received:\", {\r\n type,\r\n topic,\r\n });\r\n }\r\n\r\n switch (type) {\r\n case \"authenticate\":\r\n await this.handleAuthenticate(ws, token, ctx);\r\n break;\r\n case \"subscribe\":\r\n await this.handleSubscribe(ws, topic, ctx);\r\n break;\r\n case \"unsubscribe\":\r\n await this.handleUnsubscribe(ws, topic, ctx);\r\n break;\r\n case \"publish\":\r\n await this.handlePublish(ws, topic, data, ctx);\r\n break;\r\n default:\r\n ws.send(JSON.stringify({ error: \"Unknown message type\" }));\r\n if (this.debug) {\r\n console.error(\"Unknown WebSocket message type:\", type);\r\n }\r\n }\r\n } catch (error) {\r\n if (this.debug) {\r\n console.error(\"[BRPC]\", \"WebSocket message error:\", error);\r\n }\r\n\r\n if (error instanceof ZodError) {\r\n ws.send(JSON.stringify({ error: \"Invalid message format\" }));\r\n } else if (error instanceof Error) {\r\n ws.send(JSON.stringify({ error: error.message }));\r\n }\r\n }\r\n },\r\n close: (\r\n ws: ServerWebSocket<WebSocketData>,\r\n code: number,\r\n reason: string,\r\n ) => {\r\n this.activeConnections.delete(ws);\r\n ws.data.topics.forEach((topic) => {\r\n ws.unsubscribe(topic);\r\n });\r\n\r\n if (this.debug) {\r\n console.log(\"[BRPC]\", \"WebSocket connection closed\", {\r\n code,\r\n reason,\r\n remainingConnections: this.activeConnections.size,\r\n });\r\n }\r\n\r\n if (this.wsConfig?.onClose) {\r\n this.wsConfig.onClose(ws, code, reason, ws.data.ctx);\r\n }\r\n },\r\n },\r\n });\r\n\r\n if (callback) callback();\r\n }\r\n //====================\r\n // #endregion\r\n //====================\r\n}\r\n//====================\r\n// #endregion Class\r\n//====================\r\n\r\n//====================\r\n// #region Exports\r\n//====================\r\n/**\r\n * createRouter\r\n * @description helper function to create a\r\n * Router instance\r\n */\r\nexport function createRouter<C extends BaseContext>(config: RouterConfig<C>) {\r\n return new Router(config);\r\n}\r\n\r\nexport type CreateRouter = ReturnType<typeof createRouter>;\r\n//====================\r\n// #endregion\r\n//====================\r\n",
7
7
  "export type BRPCErrorCode =\r\n | \"BAD_REQUEST\"\r\n | \"UNAUTHORIZED\"\r\n | \"FORBIDDEN\"\r\n | \"NOT_FOUND\"\r\n | \"METHOD_NOT_SUPPORTED\"\r\n | \"TIMEOUT\"\r\n | \"CONFLICT\"\r\n | \"PRECONDITION_FAILED\"\r\n | \"PAYLOAD_TOO_LARGE\"\r\n | \"UNPROCESSABLE_CONTENT\"\r\n | \"TOO_MANY_REQUESTS\"\r\n | \"CLIENT_CLOSED_REQUEST\"\r\n | \"INTERNAL_SERVER_ERROR\"\r\n | \"NOT_IMPLEMENTED\"\r\n | \"BAD_GATEWAY\"\r\n | \"SERVICE_UNAVAILABLE\"\r\n | \"GATEWAY_TIMEOUT\";\r\n\r\nexport interface BRPCErrorOptions {\r\n code: BRPCErrorCode;\r\n message: string;\r\n clientCode?: string; // Custom code for client-side detection\r\n cause?: Error;\r\n data?: Record<string, any>;\r\n}\r\n\r\nexport class BRPCError extends Error {\r\n public readonly code: BRPCErrorCode;\r\n public readonly clientCode?: string;\r\n public readonly httpStatus: number;\r\n public readonly data?: Record<string, any>;\r\n public readonly cause?: Error;\r\n\r\n private static readonly STATUS_MAP: Record<BRPCErrorCode, number> = {\r\n BAD_REQUEST: 400,\r\n UNAUTHORIZED: 401,\r\n FORBIDDEN: 403,\r\n NOT_FOUND: 404,\r\n METHOD_NOT_SUPPORTED: 405,\r\n TIMEOUT: 408,\r\n CONFLICT: 409,\r\n PRECONDITION_FAILED: 412,\r\n PAYLOAD_TOO_LARGE: 413,\r\n UNPROCESSABLE_CONTENT: 422,\r\n TOO_MANY_REQUESTS: 429,\r\n CLIENT_CLOSED_REQUEST: 499,\r\n INTERNAL_SERVER_ERROR: 500,\r\n NOT_IMPLEMENTED: 501,\r\n BAD_GATEWAY: 502,\r\n SERVICE_UNAVAILABLE: 503,\r\n GATEWAY_TIMEOUT: 504,\r\n };\r\n\r\n constructor(options: BRPCErrorOptions) {\r\n super(options.message);\r\n\r\n this.name = \"BRPCError\";\r\n this.code = options.code;\r\n this.clientCode = options.clientCode;\r\n this.httpStatus = BRPCError.STATUS_MAP[options.code];\r\n this.data = options.data;\r\n this.cause = options.cause;\r\n\r\n // Maintains proper stack trace for where our error was thrown (only available on V8)\r\n if (Error.captureStackTrace) {\r\n Error.captureStackTrace(this, BRPCError);\r\n }\r\n }\r\n\r\n /**\r\n * Create a serializable object for sending to frontend\r\n */\r\n toJSON() {\r\n return {\r\n name: this.name,\r\n code: this.code,\r\n clientCode: this.clientCode,\r\n message: this.message,\r\n data: this.data,\r\n httpStatus: this.httpStatus,\r\n };\r\n }\r\n\r\n /**\r\n * Static factory methods for common errors\r\n */\r\n static badRequest(\r\n message: string,\r\n clientCode?: string,\r\n data?: Record<string, any>\r\n ) {\r\n return new BRPCError({ code: \"BAD_REQUEST\", message, clientCode, data });\r\n }\r\n\r\n static unauthorized(\r\n message: string = \"Unauthorized\",\r\n clientCode?: string,\r\n data?: Record<string, any>\r\n ) {\r\n return new BRPCError({ code: \"UNAUTHORIZED\", message, clientCode, data });\r\n }\r\n\r\n static forbidden(\r\n message: string = \"Forbidden\",\r\n clientCode?: string,\r\n data?: Record<string, any>\r\n ) {\r\n return new BRPCError({ code: \"FORBIDDEN\", message, clientCode, data });\r\n }\r\n\r\n static notFound(\r\n message: string = \"Not Found\",\r\n clientCode?: string,\r\n data?: Record<string, any>\r\n ) {\r\n return new BRPCError({ code: \"NOT_FOUND\", message, clientCode, data });\r\n }\r\n\r\n static preconditionFailed(\r\n message: string = \"Precondition failed\",\r\n clientCode?: string,\r\n data?: Record<string, any>\r\n ) {\r\n return new BRPCError({ code: \"NOT_FOUND\", message, clientCode, data });\r\n }\r\n\r\n static conflict(\r\n message: string,\r\n clientCode?: string,\r\n data?: Record<string, any>\r\n ) {\r\n return new BRPCError({ code: \"CONFLICT\", message, clientCode, data });\r\n }\r\n\r\n static unprocessableContent(\r\n message: string,\r\n clientCode?: string,\r\n data?: Record<string, any>\r\n ) {\r\n return new BRPCError({\r\n code: \"UNPROCESSABLE_CONTENT\",\r\n message,\r\n clientCode,\r\n data,\r\n });\r\n }\r\n\r\n static tooManyRequests(\r\n message: string = \"Too many requests\",\r\n clientCode?: string,\r\n data?: Record<string, any>\r\n ) {\r\n return new BRPCError({\r\n code: \"TOO_MANY_REQUESTS\",\r\n message,\r\n clientCode,\r\n data,\r\n });\r\n }\r\n\r\n static internalServerError(\r\n message: string = \"Internal Server Error\",\r\n clientCode?: string,\r\n data?: Record<string, any>\r\n ) {\r\n return new BRPCError({\r\n code: \"INTERNAL_SERVER_ERROR\",\r\n message,\r\n clientCode,\r\n data,\r\n });\r\n }\r\n\r\n static timeout(\r\n message: string = \"Request timeout\",\r\n clientCode?: string,\r\n data?: Record<string, any>\r\n ) {\r\n return new BRPCError({ code: \"TIMEOUT\", message, clientCode, data });\r\n }\r\n}\r\n",
8
- "// Optimized route finding for BRPC\r\n\r\nimport type { Routes, Procedure, ProcedureType } from \"../types\";\r\n\r\ninterface RouteMatch {\r\n params: Record<string, string>;\r\n route: Procedure<any, any, any, any>;\r\n}\r\n\r\ninterface CompiledRoute {\r\n handler: Procedure<any, any, any, any>;\r\n paramNames: string[];\r\n hasWildcard: boolean;\r\n wildcardIndex?: number;\r\n}\r\n\r\ninterface RouteNode {\r\n // Static routes (exact match) - O(1) lookup with Map\r\n static: Map<string, RouteNode>;\r\n // Parameter route (single dynamic segment)\r\n param?: { name: string; node: RouteNode };\r\n // Wildcard route (catches everything)\r\n wildcard?: CompiledRoute;\r\n // Handler if this node is a terminal route\r\n handler?: CompiledRoute;\r\n // Index handler\r\n index?: CompiledRoute;\r\n}\r\n\r\ninterface RouteMatcherOptions {\r\n enableCaching?: boolean;\r\n maxCacheSize?: number;\r\n debug?: boolean;\r\n}\r\n\r\ninterface RouteStats {\r\n totalRoutes: number;\r\n staticRoutes: number;\r\n paramRoutes: number;\r\n wildcardRoutes: number;\r\n indexRoutes: number;\r\n maxDepth: number;\r\n procedureTypes: Record<ProcedureType, number>;\r\n}\r\n\r\nexport class RouteMatcher {\r\n private routeTree: RouteNode;\r\n private routeCache: Map<string, RouteMatch | null>;\r\n private readonly options: Required<RouteMatcherOptions>;\r\n private routeStats: RouteStats;\r\n\r\n constructor(routes: Routes, options: RouteMatcherOptions = {}) {\r\n this.options = {\r\n enableCaching: true,\r\n maxCacheSize: 1000,\r\n debug: false,\r\n ...options,\r\n };\r\n\r\n this.routeCache = new Map();\r\n this.routeStats = this.analyzeRoutes(routes);\r\n this.routeTree = this.compileRoutes(routes);\r\n\r\n if (this.options.debug) {\r\n console.log(\"[ROUTEMATCHER]\", \"initialized with stats:\", this.routeStats);\r\n }\r\n }\r\n\r\n /**\r\n * Main route matching method\r\n */\r\n public match(pathParts: string[]): RouteMatch | null {\r\n if (this.options.enableCaching) {\r\n return this.matchWithCache(pathParts);\r\n }\r\n return this.matchDirect(pathParts);\r\n }\r\n\r\n /**\r\n * Route matching with caching\r\n */\r\n private matchWithCache(pathParts: string[]): RouteMatch | null {\r\n const cacheKey = pathParts.join(\"/\");\r\n\r\n // Check cache first\r\n if (this.routeCache.has(cacheKey)) {\r\n const cached = this.routeCache.get(cacheKey)!;\r\n if (this.options.debug && cached) {\r\n console.log(\"[ROUTEMATCHER]\", `🎯 Cache hit for route: /${cacheKey}`);\r\n }\r\n return cached;\r\n }\r\n\r\n // Find route\r\n const result = this.matchDirect(pathParts);\r\n\r\n // Cache the result (including null results to avoid repeated failed lookups)\r\n this.cacheResult(cacheKey, result);\r\n\r\n if (this.options.debug) {\r\n console.log(\r\n \"[ROUTEMATCHER]\",\r\n `💾 Cached route: /${cacheKey} -> ${result ? \"found\" : \"not found\"}`\r\n );\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Direct route matching without caching\r\n */\r\n private matchDirect(pathParts: string[]): RouteMatch | null {\r\n const startTime = this.options.debug ? performance.now() : 0;\r\n\r\n const result = this.traverseTree(this.routeTree, pathParts, 0, {});\r\n\r\n if (this.options.debug) {\r\n const duration = performance.now() - startTime;\r\n const routeType = result?.route._type || \"none\";\r\n console.log(\r\n \"[ROUTEMATCHER]\",\r\n `⚡ Route match: /${pathParts.join(\r\n \"/\"\r\n )} (${routeType}) took ${duration.toFixed(3)}ms`\r\n );\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Traverse the compiled route tree\r\n */\r\n private traverseTree(\r\n node: RouteNode,\r\n pathParts: string[],\r\n index: number,\r\n params: Record<string, string>\r\n ): RouteMatch | null {\r\n // If we've consumed all path parts\r\n if (index >= pathParts.length) {\r\n // Try handler first, then index\r\n if (node.handler) {\r\n return { params, route: node.handler.handler };\r\n }\r\n if (node.index) {\r\n return { params, route: node.index.handler };\r\n }\r\n return null;\r\n }\r\n\r\n const segment = pathParts[index];\r\n const decodedSegment = decodeURIComponent(segment);\r\n\r\n // 1. Try static route first (O(1) lookup with Map)\r\n const staticChild = node.static.get(decodedSegment);\r\n if (staticChild) {\r\n const result = this.traverseTree(\r\n staticChild,\r\n pathParts,\r\n index + 1,\r\n params\r\n );\r\n if (result) return result;\r\n }\r\n\r\n // 2. Try parameter route\r\n if (node.param) {\r\n const newParams = { ...params, [node.param.name]: decodedSegment };\r\n const result = this.traverseTree(\r\n node.param.node,\r\n pathParts,\r\n index + 1,\r\n newParams\r\n );\r\n if (result) return result;\r\n }\r\n\r\n // 3. Try wildcard route (catches all remaining segments)\r\n if (node.wildcard) {\r\n const wildcardPath = pathParts.slice(index).join(\"/\");\r\n return {\r\n params: { ...params, wildcardPath },\r\n route: node.wildcard.handler,\r\n };\r\n }\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * Compile the routes object into an optimized tree structure\r\n */\r\n private compileRoutes(routes: Routes, paramNames: string[] = []): RouteNode {\r\n const node: RouteNode = {\r\n static: new Map(),\r\n };\r\n\r\n for (const [key, value] of Object.entries(routes)) {\r\n if (key === \"index\" && this.isProcedure(value)) {\r\n // Index route\r\n node.index = {\r\n handler: value,\r\n paramNames: [...paramNames],\r\n hasWildcard: false,\r\n };\r\n continue;\r\n }\r\n\r\n if (key === \"*\") {\r\n // Wildcard route\r\n if (this.isProcedure(value)) {\r\n node.wildcard = {\r\n handler: value,\r\n paramNames: [...paramNames, \"wildcardPath\"],\r\n hasWildcard: true,\r\n wildcardIndex: paramNames.length,\r\n };\r\n }\r\n continue;\r\n }\r\n\r\n if (this.isProcedure(value)) {\r\n // Terminal route with handler\r\n const compiledRoute: CompiledRoute = {\r\n handler: value,\r\n paramNames: [...paramNames],\r\n hasWildcard: false,\r\n };\r\n\r\n if (key.startsWith(\":\")) {\r\n // Parameter route\r\n const paramName = key.slice(1);\r\n const terminalNode: RouteNode = {\r\n static: new Map(),\r\n handler: compiledRoute,\r\n };\r\n node.param = { name: paramName, node: terminalNode };\r\n } else {\r\n // Static route\r\n const terminalNode: RouteNode = {\r\n static: new Map(),\r\n handler: compiledRoute,\r\n };\r\n node.static.set(key, terminalNode);\r\n }\r\n } else if (typeof value === \"object\" && value !== null) {\r\n // Nested routes\r\n if (key.startsWith(\":\")) {\r\n // Parameter segment with nested routes\r\n const paramName = key.slice(1);\r\n const childNode = this.compileRoutes(value as Routes, [\r\n ...paramNames,\r\n paramName,\r\n ]);\r\n node.param = { name: paramName, node: childNode };\r\n } else {\r\n // Static segment with nested routes\r\n const childNode = this.compileRoutes(value as Routes, paramNames);\r\n node.static.set(key, childNode);\r\n }\r\n }\r\n }\r\n\r\n return node;\r\n }\r\n\r\n /**\r\n * Type guard to check if value is a Procedure\r\n */\r\n private isProcedure(value: any): value is Procedure<any, any, any, any> {\r\n return (\r\n value &&\r\n typeof value === \"object\" &&\r\n \"_type\" in value &&\r\n \"_input\" in value\r\n );\r\n }\r\n\r\n /**\r\n * Cache management with LRU behavior\r\n */\r\n private cacheResult(key: string, result: RouteMatch | null): void {\r\n // Implement LRU: remove oldest entry if cache is full\r\n if (this.routeCache.size >= this.options.maxCacheSize) {\r\n const firstKey = this.routeCache.keys().next().value;\r\n if (firstKey !== undefined) {\r\n this.routeCache.delete(firstKey);\r\n\r\n if (this.options.debug) {\r\n console.log(`🗑️ Evicted oldest cache entry: ${firstKey}`);\r\n }\r\n }\r\n }\r\n\r\n this.routeCache.set(key, result);\r\n }\r\n\r\n /**\r\n * Analyze route structure for optimization insights and debugging\r\n */\r\n private analyzeRoutes(routes: Routes): RouteStats {\r\n const stats: RouteStats = {\r\n totalRoutes: 0,\r\n staticRoutes: 0,\r\n paramRoutes: 0,\r\n wildcardRoutes: 0,\r\n indexRoutes: 0,\r\n maxDepth: 0,\r\n procedureTypes: {\r\n query: 0,\r\n mutation: 0,\r\n subscription: 0,\r\n file: 0,\r\n fileStream: 0,\r\n streamQuery: 0,\r\n streamMutation: 0,\r\n formMutation: 0,\r\n html: 0,\r\n },\r\n };\r\n\r\n const traverse = (obj: any, depth = 0): void => {\r\n stats.maxDepth = Math.max(stats.maxDepth, depth);\r\n\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (this.isProcedure(value)) {\r\n stats.totalRoutes++;\r\n\r\n // Count procedure types\r\n if (value._type in stats.procedureTypes) {\r\n stats.procedureTypes[value._type as ProcedureType]++;\r\n }\r\n\r\n // Count route patterns\r\n if (key === \"index\") {\r\n stats.indexRoutes++;\r\n } else if (key.startsWith(\":\")) {\r\n stats.paramRoutes++;\r\n } else if (key === \"*\") {\r\n stats.wildcardRoutes++;\r\n } else {\r\n stats.staticRoutes++;\r\n }\r\n } else if (typeof value === \"object\" && value !== null) {\r\n traverse(value, depth + 1);\r\n }\r\n }\r\n };\r\n\r\n traverse(routes);\r\n return stats;\r\n }\r\n\r\n /**\r\n * Utility methods\r\n */\r\n public clearCache(): void {\r\n this.routeCache.clear();\r\n if (this.options.debug) {\r\n console.log(\"[ROUTEMATCHER]\", \"🧹 Route cache cleared\");\r\n }\r\n }\r\n\r\n public getCacheStats(): {\r\n size: number;\r\n maxSize: number;\r\n hitRatio?: number;\r\n routeStats: RouteStats;\r\n } {\r\n return {\r\n size: this.routeCache.size,\r\n maxSize: this.options.maxCacheSize,\r\n routeStats: this.routeStats,\r\n };\r\n }\r\n\r\n /**\r\n * Get suggestions for route optimization\r\n */\r\n public getOptimizationSuggestions(): string[] {\r\n const suggestions: string[] = [];\r\n const { routeStats } = this;\r\n\r\n if (routeStats.paramRoutes > routeStats.staticRoutes * 2) {\r\n suggestions.push(\r\n \"🚀 Consider grouping routes to reduce parameter route overhead\"\r\n );\r\n }\r\n\r\n if (routeStats.maxDepth > 6) {\r\n suggestions.push(\r\n \"📊 Deep route nesting detected - consider flattening some routes\"\r\n );\r\n }\r\n\r\n if (routeStats.totalRoutes > 200) {\r\n suggestions.push(\r\n \"⚡ Large route table - consider route splitting or lazy loading\"\r\n );\r\n }\r\n\r\n if (!this.options.enableCaching && routeStats.totalRoutes > 50) {\r\n suggestions.push(\r\n \"💾 Enable caching for better performance with many routes\"\r\n );\r\n }\r\n\r\n if (routeStats.procedureTypes.file > 20) {\r\n suggestions.push(\r\n \"📁 Many file routes detected - consider static file serving\"\r\n );\r\n }\r\n\r\n if (routeStats.procedureTypes.subscription > 10) {\r\n suggestions.push(\r\n \"🔄 Many subscription routes - ensure WebSocket optimization\"\r\n );\r\n }\r\n\r\n return suggestions;\r\n }\r\n\r\n /**\r\n * Find all routes matching a pattern (useful for debugging)\r\n */\r\n public findRoutesByPattern(_pattern: string): string[] {\r\n const matchingRoutes: string[] = [];\r\n // const regex = new RegExp(pattern);\r\n\r\n // This would require storing all route paths during compilation\r\n // For now, return empty array - can be implemented if needed\r\n return matchingRoutes;\r\n }\r\n\r\n /**\r\n * Get route information for debugging\r\n */\r\n public getRouteInfo(path: string): {\r\n found: boolean;\r\n route?: Procedure<any, any, any, any>;\r\n params?: Record<string, string>;\r\n cached: boolean;\r\n matchTime?: number;\r\n } {\r\n const pathParts = path.split(\"/\").filter(Boolean);\r\n const cacheKey = pathParts.join(\"/\");\r\n const cached = this.routeCache.has(cacheKey);\r\n\r\n const startTime = performance.now();\r\n const result = this.matchDirect(pathParts);\r\n const matchTime = performance.now() - startTime;\r\n\r\n return {\r\n found: !!result,\r\n route: result?.route,\r\n params: result?.params,\r\n cached,\r\n matchTime,\r\n };\r\n }\r\n\r\n /**\r\n * Benchmark route matching performance\r\n */\r\n public benchmark(\r\n testPaths: string[],\r\n iterations = 1000\r\n ): {\r\n averageTime: number;\r\n totalTime: number;\r\n routesPerSecond: number;\r\n cacheHitRatio?: number;\r\n } {\r\n const pathSegments = testPaths.map((path) =>\r\n path.split(\"/\").filter(Boolean)\r\n );\r\n\r\n // Clear cache for accurate benchmarking\r\n const originalCache = new Map(this.routeCache);\r\n this.routeCache.clear();\r\n\r\n const startTime = performance.now();\r\n\r\n for (let i = 0; i < iterations; i++) {\r\n for (const segments of pathSegments) {\r\n this.matchDirect(segments); // Use direct matching for pure performance\r\n }\r\n }\r\n\r\n const endTime = performance.now();\r\n const totalTime = endTime - startTime;\r\n const totalMatches = iterations * testPaths.length;\r\n const averageTime = totalTime / totalMatches;\r\n const routesPerSecond = (totalMatches / totalTime) * 1000;\r\n\r\n // Restore cache\r\n this.routeCache = originalCache;\r\n\r\n return {\r\n averageTime,\r\n totalTime,\r\n routesPerSecond,\r\n };\r\n }\r\n\r\n /**\r\n * Warm up the cache with common routes\r\n */\r\n public warmupCache(commonPaths: string[]): void {\r\n if (!this.options.enableCaching) return;\r\n\r\n const startTime = performance.now();\r\n let warmedRoutes = 0;\r\n\r\n for (const path of commonPaths) {\r\n const pathParts = path.split(\"/\").filter(Boolean);\r\n const result = this.matchDirect(pathParts);\r\n if (result) {\r\n this.cacheResult(pathParts.join(\"/\"), result);\r\n warmedRoutes++;\r\n }\r\n }\r\n\r\n const endTime = performance.now();\r\n\r\n if (this.options.debug) {\r\n console.log(\r\n \"[ROUTEMATCHER]\",\r\n `🔥 Cache warmed up: ${warmedRoutes} routes in ${(\r\n endTime - startTime\r\n ).toFixed(2)}ms`\r\n );\r\n }\r\n }\r\n}\r\n\r\n// Export types for use in Router\r\nexport type { RouteMatch, RouteMatcherOptions, RouteStats };\r\n",
8
+ "// TODO\r\n\r\n// Add regex pattern support\r\n// Benefits:\r\n\r\n// Validation at routing level - invalid formats don't even reach your handler\r\n// Cleaner code - no need to validate ID format in every handler\r\n// Better error messages - 404 vs validation error\r\n\r\n// Example:\r\n// {\r\n// \"users\": {\r\n// \":id(\\\\d+)\": { ... }, // only matches numeric IDs: /users/123 ✅, /users/abc ❌\r\n// \":slug([a-z-]+)\": { ... }, // only matches slugs: /users/my-post ✅, /users/My_Post ❌\r\n// \":uuid([0-9a-f]{8}-...)\": { ... }, // only UUIDs\r\n// },\r\n// \"posts\": {\r\n// \":year(\\\\d{4})\": {\r\n// \":month(\\\\d{2})\": {\r\n// \":day(\\\\d{2})\": { ... } // /posts/2024/01/30 ✅, /posts/24/1/3 ❌\r\n// }\r\n// }\r\n// },\r\n// \"files\": {\r\n// \"*.(jpg|png|gif)\": { ... }, // only image files\r\n// }\r\n// }\r\n\r\nimport type { Routes, Procedure, ProcedureType } from \"../types\";\r\n\r\ninterface RouteMatch {\r\n params: Record<string, string>;\r\n route: Procedure<any, any, any, any>;\r\n}\r\n\r\ninterface CompiledRoute {\r\n handler: Procedure<any, any, any, any>;\r\n paramNames: string[];\r\n hasWildcard: boolean;\r\n wildcardIndex?: number;\r\n}\r\n\r\ninterface RouteNode {\r\n // Static routes (exact match) - O(1) lookup with Map\r\n static: Map<string, RouteNode>;\r\n // Parameter route (single dynamic segment)\r\n param?: { name: string; node: RouteNode };\r\n // Wildcard route (catches everything)\r\n wildcard?: CompiledRoute;\r\n // Handler if this node is a terminal route\r\n handler?: CompiledRoute;\r\n // Index handler\r\n index?: CompiledRoute;\r\n}\r\n\r\ninterface RouteMatcherOptions {\r\n enableCaching?: boolean;\r\n maxCacheSize?: number;\r\n debug?: boolean;\r\n}\r\n\r\ninterface RouteStats {\r\n totalRoutes: number;\r\n staticRoutes: number;\r\n paramRoutes: number;\r\n wildcardRoutes: number;\r\n indexRoutes: number;\r\n maxDepth: number;\r\n procedureTypes: Record<ProcedureType, number>;\r\n}\r\n\r\n/**\r\n * Optimized route matcher for the BRPC Framework\r\n */\r\nexport class RouteMatcher {\r\n private routeTree: RouteNode;\r\n private routeCache: Map<string, RouteMatch | null>;\r\n private readonly options: Required<RouteMatcherOptions>;\r\n private routeStats: RouteStats;\r\n\r\n constructor(routes: Routes, options: RouteMatcherOptions = {}) {\r\n this.options = {\r\n enableCaching: true,\r\n maxCacheSize: 1000,\r\n debug: false,\r\n ...options,\r\n };\r\n\r\n this.routeCache = new Map();\r\n this.routeStats = this.analyzeRoutes(routes);\r\n this.routeTree = this.compileRoutes(routes);\r\n\r\n if (this.options.debug) {\r\n console.log(\"[ROUTEMATCHER]\", \"initialized with stats:\", this.routeStats);\r\n }\r\n }\r\n\r\n /**\r\n * Main route matching method\r\n */\r\n public match(pathParts: string[]): RouteMatch | null {\r\n if (this.options.enableCaching) {\r\n return this.matchWithCache(pathParts);\r\n }\r\n return this.matchDirect(pathParts);\r\n }\r\n\r\n /**\r\n * Route matching with caching\r\n */\r\n private matchWithCache(pathParts: string[]): RouteMatch | null {\r\n const cacheKey = pathParts.join(\"/\");\r\n\r\n // Check cache first\r\n if (this.routeCache.has(cacheKey)) {\r\n const cached = this.routeCache.get(cacheKey)!;\r\n if (this.options.debug && cached) {\r\n console.log(\"[ROUTEMATCHER]\", `🎯 Cache hit for route: /${cacheKey}`);\r\n }\r\n return cached;\r\n }\r\n\r\n // Find route\r\n const result = this.matchDirect(pathParts);\r\n\r\n // Cache the result (including null results to avoid repeated failed lookups)\r\n this.cacheResult(cacheKey, result);\r\n\r\n if (this.options.debug) {\r\n console.log(\r\n \"[ROUTEMATCHER]\",\r\n `💾 Cached route: /${cacheKey} -> ${result ? \"found\" : \"not found\"}`,\r\n );\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Direct route matching without caching\r\n */\r\n private matchDirect(pathParts: string[]): RouteMatch | null {\r\n const startTime = this.options.debug ? performance.now() : 0;\r\n\r\n const result = this.traverseTree(this.routeTree, pathParts, 0, {});\r\n\r\n if (this.options.debug) {\r\n const duration = performance.now() - startTime;\r\n const routeType = result?.route._type || \"none\";\r\n console.log(\r\n \"[ROUTEMATCHER]\",\r\n `⚡ Route match: /${pathParts.join(\r\n \"/\",\r\n )} (${routeType}) took ${duration.toFixed(3)}ms`,\r\n );\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Traverse the compiled route tree\r\n */\r\n private traverseTree(\r\n node: RouteNode,\r\n pathParts: string[],\r\n index: number,\r\n params: Record<string, string>,\r\n ): RouteMatch | null {\r\n // If we've consumed all path parts\r\n if (index >= pathParts.length) {\r\n // Try handler first, then index\r\n if (node.handler) {\r\n return { params, route: node.handler.handler };\r\n }\r\n if (node.index) {\r\n return { params, route: node.index.handler };\r\n }\r\n // Then only match wildcard at root if pathParts\r\n // is empty (root path) and there's no index handler defined\r\n //! This was the last change I made trying to fix\r\n //! Wildacrd not matching root (/) when index wasn't defined\r\n if (node.wildcard && pathParts.length === 0) {\r\n return {\r\n params: { ...params, wildcardPath: \"\" },\r\n route: node.wildcard.handler,\r\n };\r\n }\r\n return null;\r\n }\r\n\r\n const segment = pathParts[index];\r\n const decodedSegment = decodeURIComponent(segment);\r\n\r\n // 1. Try static route first (O(1) lookup with Map)\r\n const staticChild = node.static.get(decodedSegment);\r\n if (staticChild) {\r\n const result = this.traverseTree(\r\n staticChild,\r\n pathParts,\r\n index + 1,\r\n params,\r\n );\r\n if (result) return result;\r\n }\r\n\r\n // 2. Try parameter route\r\n if (node.param) {\r\n const newParams = { ...params, [node.param.name]: decodedSegment };\r\n const result = this.traverseTree(\r\n node.param.node,\r\n pathParts,\r\n index + 1,\r\n newParams,\r\n );\r\n if (result) return result;\r\n }\r\n\r\n // 3. Try wildcard route (catches all remaining segments including unmatched routes)\r\n if (node.wildcard) {\r\n const wildcardPath = pathParts.slice(index).join(\"/\");\r\n return {\r\n params: { ...params, wildcardPath },\r\n route: node.wildcard.handler,\r\n };\r\n }\r\n\r\n return null;\r\n }\r\n\r\n /**\r\n * Compile the routes object into an optimized tree structure\r\n */\r\n private compileRoutes(routes: Routes, paramNames: string[] = []): RouteNode {\r\n const node: RouteNode = {\r\n static: new Map(),\r\n };\r\n\r\n for (const [key, value] of Object.entries(routes)) {\r\n if (key === \"index\" && this.isProcedure(value)) {\r\n // Index route\r\n node.index = {\r\n handler: value,\r\n paramNames: [...paramNames],\r\n hasWildcard: false,\r\n };\r\n continue;\r\n }\r\n\r\n if (key === \"*\") {\r\n // Wildcard route\r\n if (this.isProcedure(value)) {\r\n node.wildcard = {\r\n handler: value,\r\n paramNames: [...paramNames, \"wildcardPath\"],\r\n hasWildcard: true,\r\n wildcardIndex: paramNames.length,\r\n };\r\n }\r\n continue;\r\n }\r\n\r\n if (this.isProcedure(value)) {\r\n // Terminal route with handler\r\n const compiledRoute: CompiledRoute = {\r\n handler: value,\r\n paramNames: [...paramNames],\r\n hasWildcard: false,\r\n };\r\n\r\n if (key.startsWith(\":\")) {\r\n // Parameter route\r\n const paramName = key.slice(1);\r\n const terminalNode: RouteNode = {\r\n static: new Map(),\r\n handler: compiledRoute,\r\n };\r\n node.param = { name: paramName, node: terminalNode };\r\n } else {\r\n // Static route\r\n const terminalNode: RouteNode = {\r\n static: new Map(),\r\n handler: compiledRoute,\r\n };\r\n node.static.set(key, terminalNode);\r\n }\r\n } else if (typeof value === \"object\" && value !== null) {\r\n // Nested routes\r\n if (key.startsWith(\":\")) {\r\n // Parameter segment with nested routes\r\n const paramName = key.slice(1);\r\n const childNode = this.compileRoutes(value as Routes, [\r\n ...paramNames,\r\n paramName,\r\n ]);\r\n node.param = { name: paramName, node: childNode };\r\n } else {\r\n // Static segment with nested routes\r\n const childNode = this.compileRoutes(value as Routes, paramNames);\r\n node.static.set(key, childNode);\r\n }\r\n }\r\n }\r\n\r\n return node;\r\n }\r\n\r\n /**\r\n * Type guard to check if value is a Procedure\r\n */\r\n private isProcedure(value: any): value is Procedure<any, any, any, any> {\r\n return (\r\n value &&\r\n typeof value === \"object\" &&\r\n \"_type\" in value &&\r\n \"_input\" in value\r\n );\r\n }\r\n\r\n /**\r\n * Cache management with LRU behavior\r\n */\r\n private cacheResult(key: string, result: RouteMatch | null): void {\r\n // Implement LRU: remove oldest entry if cache is full\r\n if (this.routeCache.size >= this.options.maxCacheSize) {\r\n const firstKey = this.routeCache.keys().next().value;\r\n if (firstKey !== undefined) {\r\n this.routeCache.delete(firstKey);\r\n\r\n if (this.options.debug) {\r\n console.log(`🗑️ Evicted oldest cache entry: ${firstKey}`);\r\n }\r\n }\r\n }\r\n\r\n this.routeCache.set(key, result);\r\n }\r\n\r\n /**\r\n * Analyze route structure for optimization insights and debugging\r\n */\r\n private analyzeRoutes(routes: Routes): RouteStats {\r\n const stats: RouteStats = {\r\n totalRoutes: 0,\r\n staticRoutes: 0,\r\n paramRoutes: 0,\r\n wildcardRoutes: 0,\r\n indexRoutes: 0,\r\n maxDepth: 0,\r\n procedureTypes: {\r\n query: 0,\r\n mutation: 0,\r\n subscription: 0,\r\n file: 0,\r\n fileStream: 0,\r\n streamQuery: 0,\r\n streamMutation: 0,\r\n formMutation: 0,\r\n html: 0,\r\n },\r\n };\r\n\r\n const traverse = (obj: any, depth = 0): void => {\r\n stats.maxDepth = Math.max(stats.maxDepth, depth);\r\n\r\n for (const [key, value] of Object.entries(obj)) {\r\n if (this.isProcedure(value)) {\r\n stats.totalRoutes++;\r\n\r\n // Count procedure types\r\n if (value._type in stats.procedureTypes) {\r\n stats.procedureTypes[value._type as ProcedureType]++;\r\n }\r\n\r\n // Count route patterns\r\n if (key === \"index\") {\r\n stats.indexRoutes++;\r\n } else if (key.startsWith(\":\")) {\r\n stats.paramRoutes++;\r\n } else if (key === \"*\") {\r\n stats.wildcardRoutes++;\r\n } else {\r\n stats.staticRoutes++;\r\n }\r\n } else if (typeof value === \"object\" && value !== null) {\r\n traverse(value, depth + 1);\r\n }\r\n }\r\n };\r\n\r\n traverse(routes);\r\n return stats;\r\n }\r\n\r\n /**\r\n * Utility methods\r\n */\r\n public clearCache(): void {\r\n this.routeCache.clear();\r\n if (this.options.debug) {\r\n console.log(\"[ROUTEMATCHER]\", \"🧹 Route cache cleared\");\r\n }\r\n }\r\n\r\n public getCacheStats(): {\r\n size: number;\r\n maxSize: number;\r\n hitRatio?: number;\r\n routeStats: RouteStats;\r\n } {\r\n return {\r\n size: this.routeCache.size,\r\n maxSize: this.options.maxCacheSize,\r\n routeStats: this.routeStats,\r\n };\r\n }\r\n\r\n /**\r\n * Get suggestions for route optimization\r\n */\r\n public getOptimizationSuggestions(): string[] {\r\n const suggestions: string[] = [];\r\n const { routeStats } = this;\r\n\r\n if (routeStats.paramRoutes > routeStats.staticRoutes * 2) {\r\n suggestions.push(\r\n \"🚀 Consider grouping routes to reduce parameter route overhead\",\r\n );\r\n }\r\n\r\n if (routeStats.maxDepth > 6) {\r\n suggestions.push(\r\n \"📊 Deep route nesting detected - consider flattening some routes\",\r\n );\r\n }\r\n\r\n if (routeStats.totalRoutes > 200) {\r\n suggestions.push(\r\n \"⚡ Large route table - consider route splitting or lazy loading\",\r\n );\r\n }\r\n\r\n if (!this.options.enableCaching && routeStats.totalRoutes > 50) {\r\n suggestions.push(\r\n \"💾 Enable caching for better performance with many routes\",\r\n );\r\n }\r\n\r\n if (routeStats.procedureTypes.file > 20) {\r\n suggestions.push(\r\n \"📁 Many file routes detected - consider static file serving\",\r\n );\r\n }\r\n\r\n if (routeStats.procedureTypes.subscription > 10) {\r\n suggestions.push(\r\n \"🔄 Many subscription routes - ensure WebSocket optimization\",\r\n );\r\n }\r\n\r\n return suggestions;\r\n }\r\n\r\n /**\r\n * Find all routes matching a pattern (useful for debugging)\r\n */\r\n public findRoutesByPattern(_pattern: string): string[] {\r\n const matchingRoutes: string[] = [];\r\n // const regex = new RegExp(pattern);\r\n\r\n // This would require storing all route paths during compilation\r\n // For now, return empty array - can be implemented if needed\r\n return matchingRoutes;\r\n }\r\n\r\n /**\r\n * Get route information for debugging\r\n */\r\n public getRouteInfo(path: string): {\r\n found: boolean;\r\n route?: Procedure<any, any, any, any>;\r\n params?: Record<string, string>;\r\n cached: boolean;\r\n matchTime?: number;\r\n } {\r\n const pathParts = path.split(\"/\").filter(Boolean);\r\n const cacheKey = pathParts.join(\"/\");\r\n const cached = this.routeCache.has(cacheKey);\r\n\r\n const startTime = performance.now();\r\n const result = this.matchDirect(pathParts);\r\n const matchTime = performance.now() - startTime;\r\n\r\n return {\r\n found: !!result,\r\n route: result?.route,\r\n params: result?.params,\r\n cached,\r\n matchTime,\r\n };\r\n }\r\n\r\n /**\r\n * Benchmark route matching performance\r\n */\r\n public benchmark(\r\n testPaths: string[],\r\n iterations = 1000,\r\n ): {\r\n averageTime: number;\r\n totalTime: number;\r\n routesPerSecond: number;\r\n cacheHitRatio?: number;\r\n } {\r\n const pathSegments = testPaths.map((path) =>\r\n path.split(\"/\").filter(Boolean),\r\n );\r\n\r\n // Clear cache for accurate benchmarking\r\n const originalCache = new Map(this.routeCache);\r\n this.routeCache.clear();\r\n\r\n const startTime = performance.now();\r\n\r\n for (let i = 0; i < iterations; i++) {\r\n for (const segments of pathSegments) {\r\n this.matchDirect(segments); // Use direct matching for pure performance\r\n }\r\n }\r\n\r\n const endTime = performance.now();\r\n const totalTime = endTime - startTime;\r\n const totalMatches = iterations * testPaths.length;\r\n const averageTime = totalTime / totalMatches;\r\n const routesPerSecond = (totalMatches / totalTime) * 1000;\r\n\r\n // Restore cache\r\n this.routeCache = originalCache;\r\n\r\n return {\r\n averageTime,\r\n totalTime,\r\n routesPerSecond,\r\n };\r\n }\r\n\r\n /**\r\n * Warm up the cache with common routes\r\n */\r\n public warmupCache(commonPaths: string[]): void {\r\n if (!this.options.enableCaching) return;\r\n\r\n const startTime = performance.now();\r\n let warmedRoutes = 0;\r\n\r\n for (const path of commonPaths) {\r\n const pathParts = path.split(\"/\").filter(Boolean);\r\n const result = this.matchDirect(pathParts);\r\n if (result) {\r\n this.cacheResult(pathParts.join(\"/\"), result);\r\n warmedRoutes++;\r\n }\r\n }\r\n\r\n const endTime = performance.now();\r\n\r\n if (this.options.debug) {\r\n console.log(\r\n \"[ROUTEMATCHER]\",\r\n `🔥 Cache warmed up: ${warmedRoutes} routes in ${(\r\n endTime - startTime\r\n ).toFixed(2)}ms`,\r\n );\r\n }\r\n }\r\n}\r\n\r\n// Export types for use in Router\r\nexport type { RouteMatch, RouteMatcherOptions, RouteStats };\r\n",
9
9
  "// @bun\nvar L=import.meta.require;var W={NO_CACHE:{cacheControl:\"no-cache, no-store, must-revalidate\",expires:new Date(0).toUTCString()},ONE_YEAR:{cacheControl:\"public, max-age=31536000\",expires:new Date(Date.now()+31536000000).toUTCString()},IMMUTABLE:{cacheControl:\"public, max-age=31536000, immutable\",expires:new Date(Date.now()+31536000000).toUTCString()},ONE_MONTH:{cacheControl:\"public, max-age=2592000\"},ONE_WEEK:{cacheControl:\"public, max-age=604800\"},ONE_DAY:{cacheControl:\"public, max-age=86400, must-revalidate\"},ONE_HOUR:{cacheControl:\"public, max-age=3600, must-revalidate\"},FIVE_MINUTES:{cacheControl:\"public, max-age=300\"},API:{cacheControl:\"public, max-age=300, s-maxage=3600\"},STYLESHEET:{cacheControl:\"public, max-age=2592000, must-revalidate\"},JAVASCRIPT:{cacheControl:\"public, max-age=2592000, must-revalidate\"},HASHED_ASSET:{cacheControl:\"public, max-age=31536000, immutable\",expires:new Date(Date.now()+31536000000).toUTCString()},FONT:{cacheControl:\"public, max-age=31536000\",expires:new Date(Date.now()+31536000000).toUTCString()},IMAGE:{cacheControl:\"public, max-age=2592000\"},FAVICON:{cacheControl:\"public, max-age=31536000\",expires:new Date(Date.now()+31536000000).toUTCString()},HTML_PAGE:{cacheControl:\"public, max-age=3600, must-revalidate\"},API_RESPONSE:{cacheControl:\"public, max-age=300, s-maxage=900\"},FEED:{cacheControl:\"public, max-age=3600\"},SITEMAP:{cacheControl:\"public, max-age=86400\"},MANIFEST:{cacheControl:\"public, max-age=86400, must-revalidate\"},SERVICE_WORKER:{cacheControl:\"no-cache, no-store, must-revalidate\",expires:new Date(0).toUTCString()},MEDIA_STREAM:{cacheControl:\"no-cache, no-store\"},DOCUMENT:{cacheControl:\"public, max-age=86400\"},ARCHIVE:{cacheControl:\"public, max-age=604800\"}};function J(k){return W[k]}var Y={html:\"text/html; charset=utf-8\",css:\"text/css\",javascript:\"application/javascript\",json:\"application/json\",xml:\"application/xml\",text:\"text/plain; charset=utf-8\",csv:\"text/csv\",markdown:\"text/markdown; charset=utf-8\",png:\"image/png\",jpeg:\"image/jpeg\",gif:\"image/gif\",svg:\"image/svg+xml\",webp:\"image/webp\",icon:\"image/x-icon\",bmp:\"image/bmp\",woff:\"font/woff\",woff2:\"font/woff2\",truetype:\"font/ttf\",\"embedded-opentype\":\"application/vnd.ms-fontobject\",opentype:\"font/otf\",mp4:\"video/mp4\",webm:\"video/webm\",ogg:\"video/ogg\",mpeg:\"audio/mpeg\",wav:\"audio/wav\",flac:\"audio/flac\",pdf:\"application/pdf\",doc:\"application/msword\",docx:\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",zip:\"application/zip\",tar:\"application/x-tar\",gzip:\"application/gzip\",\"7z\":\"application/x-7z-compressed\",js:\"application/javascript\",txt:\"text/plain; charset=utf-8\",jpg:\"image/jpeg\",ico:\"image/x-icon\",ttf:\"font/ttf\",eot:\"application/vnd.ms-fontobject\",otf:\"font/otf\",mp3:\"audio/mpeg\",gz:\"application/gzip\"};function V(k){return Y[k]||\"application/octet-stream\"}function Z(k){if(typeof Bun!==\"undefined\"&&Bun.hash)return Bun.hash(k).toString(16);try{let z=L(\"crypto\"),K;if(typeof k===\"string\")K=Buffer.from(k);else if(k instanceof ArrayBuffer)K=Buffer.from(new Uint8Array(k));else K=Buffer.from(k);return z.createHash(\"md5\").update(K).digest(\"hex\")}catch{let z=typeof k===\"string\"?new TextEncoder().encode(k):k instanceof ArrayBuffer?new Uint8Array(k):k,K=0;for(let U=0;U<z.length;U++)K=(K<<5)-K+z[U],K=K&K;return Math.abs(K).toString(16).padStart(16,\"0\")}}function B(k,z,K){let U=k.headers.get(\"Origin\"),D=!0;if((K?.allowAll??!0)&&U)return U;if(z.length===0)return U||\"*\";if(!U)return z[0];if(z.includes(U))return U;return z[0]}class ${headers={};contentType(k){return this.headers[\"Content-Type\"]=V(k),this}filePath(k){let z=k.split(\".\").pop()?.toLowerCase()||\"\";return this.headers[\"Content-Type\"]=V(z),this}mimeType(k){return this.headers[\"Content-Type\"]=k,this}cache(k){let{cacheControl:z,expires:K}=J(k);if(this.headers[\"Cache-Control\"]=z,K)this.headers.Expires=K;return this}eTag(k){if(!k)return this;let z;if(typeof k===\"string\"&&k.startsWith('\"'))z=k;else z=`\"${Z(k)}\"`;return this.headers.ETag=z,this}lastModified(k){return this.headers[\"Last-Modified\"]=k.toUTCString(),this}contentLength(k){return this.headers[\"Content-Length\"]=k.toString(),this}redirect(k,z=!1){return this.headers.Location=k,this.headers[\"X-Redirect-Type\"]=z?\"permanent\":\"temporary\",this}cors({origin:k=\"*\",methods:z=[\"GET\",\"POST\",\"PUT\",\"DELETE\",\"OPTIONS\"],headers:K=[\"Content-Type\",\"Authorization\"],maxAge:U=86400,credentials:D}={}){let X=D??k!==\"*\";if(X&&k===\"*\")throw new Error('CORS: Cannot use credentials with wildcard origin \"*\". Specify an exact origin or set credentials to false.');if(this.headers[\"Access-Control-Allow-Origin\"]=k,this.headers[\"Access-Control-Allow-Methods\"]=z.join(\", \"),this.headers[\"Access-Control-Allow-Headers\"]=K.join(\", \"),X)this.headers[\"Access-Control-Allow-Credentials\"]=\"true\";return this.headers[\"Access-Control-Max-Age\"]=U.toString(),this}security(k){let z={hsts:!0,noSniff:!0,frameOptions:\"SAMEORIGIN\",xssProtection:!0,...k};if(z.csp)this.headers[\"Content-Security-Policy\"]=z.csp;if(z.hsts){let K=typeof z.hsts===\"number\"?z.hsts:31536000;this.headers[\"Strict-Transport-Security\"]=`max-age=${K}; includeSubDomains`}if(z.noSniff)this.headers[\"X-Content-Type-Options\"]=\"nosniff\";if(z.frameOptions)this.headers[\"X-Frame-Options\"]=z.frameOptions;if(z.xssProtection)this.headers[\"X-XSS-Protection\"]=\"1; mode=block\";return this}custom(k,z){return this.headers[k]=z,this}customHeaders(k){return Object.assign(this.headers,k),this}vary(...k){let z=this.headers.Vary,K=z?`${z}, ${k.join(\", \")}`:k.join(\", \");return this.headers.Vary=K,this}compress(k){if(k)this.headers[\"Content-Encoding\"]=k;return this}build(k){let z={...this.headers};if(k&&!z[\"Content-Length\"]){let K=typeof k===\"string\"?new TextEncoder().encode(k).length:k.byteLength;z[\"Content-Length\"]=K.toString()}return z}buildHeaders(k){return new Headers(this.build(k))}}function Q(){return new $}function F(k,z){let K=Q().contentType(k);if(z)K.cache(z);return K.build()}var G={css:(k)=>Q().contentType(\"css\").cache(\"STYLESHEET\").eTag(k),javascript:(k)=>Q().contentType(\"javascript\").cache(\"JAVASCRIPT\").eTag(k),hashedAsset:(k,z)=>Q().filePath(k).cache(\"HASHED_ASSET\").eTag(z),font:(k)=>Q().filePath(k).cache(\"FONT\").cors({origin:\"*\"}),image:(k)=>Q().filePath(k).cache(\"IMAGE\"),favicon:()=>Q().contentType(\"icon\").cache(\"FAVICON\"),api:()=>Q().contentType(\"json\").cache(\"API_RESPONSE\").cors(),expensiveApi:(k)=>Q().contentType(\"json\").cache(\"API_RESPONSE\").cors().eTag(k),realtime:()=>Q().contentType(\"json\").cache(\"NO_CACHE\").cors(),html:()=>Q().contentType(\"html\").cache(\"HTML_PAGE\").security(),expensiveHtml:(k)=>Q().contentType(\"html\").cache(\"HTML_PAGE\").security().eTag(k),manifest:(k)=>Q().contentType(\"json\").cache(\"MANIFEST\").eTag(k),serviceWorker:()=>Q().contentType(\"javascript\").cache(\"SERVICE_WORKER\"),sitemap:(k)=>Q().contentType(\"xml\").cache(\"SITEMAP\").eTag(k),feed:(k,z=\"rss\")=>Q().contentType(\"xml\").cache(\"FEED\").eTag(k).mimeType(z===\"rss\"?\"application/rss+xml\":\"application/atom+xml\"),video:(k)=>Q().filePath(k).cache(\"MEDIA_STREAM\").custom(\"Accept-Ranges\",\"bytes\"),audio:(k)=>Q().filePath(k).cache(\"MEDIA_STREAM\").custom(\"Accept-Ranges\",\"bytes\"),pdf:(k)=>Q().contentType(\"pdf\").cache(\"DOCUMENT\").custom(\"Content-Disposition\",\"inline\").eTag(k),download:(k,z,K)=>Q().filePath(z).cache(\"ARCHIVE\").custom(\"Content-Disposition\",`attachment; filename=\"${k}\"`).eTag(K),secure:()=>Q().security({csp:\"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'\",hsts:31536000}).custom(\"X-Powered-By\",\"Bun\"),permanentRedirect:(k)=>Q().redirect(k,!0),temporaryRedirect:(k)=>Q().redirect(k,!1)};export{F as quickHeaders,Z as hashContent,V as getMimeType,B as getCorsOrigin,G as commonHeaders,Q as buildHeaders};\n\n//# debugId=4EE16D0787D156E064756E2164756E21\n",
10
10
  "import type { BunFile } from \"bun\";\r\nimport { buildHeaders, getCorsOrigin } from \"@mateosuarezdev/headers-builder\"; // Adjust import path as needed\r\n\r\ninterface StreamMediaOptions {\r\n maxChunkSize?: number; // Default: 2MB\r\n cacheMaxAge?: number; // Default: 3600 (1 hour)\r\n acceptedExtensions?: string[]; // Optional whitelist\r\n}\r\n\r\n/**\r\n * Metadata for deferred media streaming\r\n * Used with router's streamFile procedure\r\n */\r\nexport interface StreamableMediaResponse {\r\n type: \"stream\";\r\n file: BunFile;\r\n request: Request;\r\n options?: StreamMediaOptions;\r\n}\r\n\r\n/**\r\n * Handle media streaming with automatic Range request support\r\n * Supports video, audio, and other streamable media formats\r\n * @internal - Used by router to process StreamableMediaResponse\r\n */\r\nexport async function streamMediaInternal(\r\n file: BunFile,\r\n request: Request,\r\n allowedOrigins: string[],\r\n options: StreamMediaOptions = {}\r\n): Promise<Response> {\r\n const {\r\n maxChunkSize = 2 * 1024 * 1024,\r\n cacheMaxAge = 3600,\r\n acceptedExtensions,\r\n } = options;\r\n\r\n // Check if file exists\r\n const fileExists = await file.exists();\r\n if (!fileExists) {\r\n return new Response(\"Media file not found\", {\r\n status: 404,\r\n headers: buildHeaders()\r\n .contentType(\"text\")\r\n .cors({ origin: getCorsOrigin(request, allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n // Validate file extension if acceptedExtensions provided\r\n if (acceptedExtensions && acceptedExtensions.length > 0) {\r\n const ext = file.name?.toLowerCase().split(\".\").pop();\r\n if (!ext || !acceptedExtensions.includes(ext)) {\r\n return new Response(\"File type not supported\", {\r\n status: 415, // Unsupported Media Type\r\n headers: buildHeaders()\r\n .contentType(\"text\")\r\n .cors({ origin: getCorsOrigin(request, allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n }\r\n\r\n const fileSize = file.size;\r\n const range = request.headers.get(\"Range\");\r\n\r\n // No range request - send full file\r\n if (!range) {\r\n return new Response(file, {\r\n headers: buildHeaders()\r\n .filePath(file.name || \"media\")\r\n .custom(\"Accept-Ranges\", \"bytes\")\r\n .custom(\"Cache-Control\", `public, max-age=${cacheMaxAge}`)\r\n .cors({ origin: getCorsOrigin(request, allowedOrigins) })\r\n .build(),\r\n });\r\n }\r\n\r\n // Parse range header\r\n const rangeMatch = range.match(/bytes=(\\d*)-(\\d*)/);\r\n if (!rangeMatch) {\r\n return new Response(\"Invalid Range header\", {\r\n status: 416,\r\n headers: buildHeaders()\r\n .contentType(\"text\")\r\n .cors({ origin: getCorsOrigin(request, allowedOrigins) })\r\n .custom(\"Content-Range\", `bytes */${fileSize}`)\r\n .build(),\r\n });\r\n }\r\n\r\n // Calculate start and end positions\r\n const start = rangeMatch[1] ? parseInt(rangeMatch[1]) : 0;\r\n const requestedEnd = rangeMatch[2] ? parseInt(rangeMatch[2]) : fileSize - 1;\r\n\r\n // Apply maxChunkSize limit\r\n const end = Math.min(requestedEnd, start + maxChunkSize - 1, fileSize - 1);\r\n\r\n // Validate range\r\n if (start >= fileSize || end >= fileSize || start > end) {\r\n return new Response(\"Range not satisfiable\", {\r\n status: 416,\r\n headers: buildHeaders()\r\n .contentType(\"text\")\r\n .cors({ origin: getCorsOrigin(request, allowedOrigins) })\r\n .custom(\"Content-Range\", `bytes */${fileSize}`)\r\n .build(),\r\n });\r\n }\r\n\r\n // Bun automatically sets Content-Range and Content-Length for slices\r\n return new Response(file.slice(start, end + 1), {\r\n status: 206,\r\n headers: buildHeaders()\r\n .filePath(file.name || \"media\")\r\n .custom(\"Accept-Ranges\", \"bytes\")\r\n .custom(\"Cache-Control\", `public, max-age=${cacheMaxAge}`)\r\n .cors({ origin: getCorsOrigin(request, allowedOrigins) })\r\n .build(),\r\n });\r\n}\r\n\r\n/**\r\n * Helper function to create a streamable media response\r\n * Returns metadata that the router will process with streamMediaInternal()\r\n *\r\n * @example\r\n * ```typescript\r\n * // Stream any media\r\n * return streamMedia(file, ctx.request);\r\n *\r\n * // Stream with validation\r\n * return streamMedia(file, ctx.request, {\r\n * acceptedExtensions: [\"mp4\", \"webm\", \"mov\"],\r\n * maxChunkSize: 5 * 1024 * 1024,\r\n * });\r\n * ```\r\n */\r\nexport function streamMedia(\r\n file: BunFile,\r\n request: Request,\r\n options?: StreamMediaOptions\r\n): StreamableMediaResponse {\r\n return {\r\n type: \"stream\",\r\n file,\r\n request,\r\n options,\r\n };\r\n}\r\n\r\n//? I don't need to bundle them, users can create their owns\r\n// but just in case or if I want to add to docs\r\n// /**\r\n// * Common media extension presets\r\n// */\r\n// export const MEDIA_EXTENSIONS = {\r\n// video: [\"mp4\", \"webm\", \"mov\", \"avi\", \"mkv\", \"ogg\", \"ogv\"],\r\n// audio: [\"mp3\", \"wav\", \"ogg\", \"m4a\", \"flac\", \"aac\", \"opus\"],\r\n// all: [\r\n// \"mp4\",\r\n// \"webm\",\r\n// \"mov\",\r\n// \"avi\",\r\n// \"mkv\",\r\n// \"ogg\",\r\n// \"ogv\",\r\n// \"mp3\",\r\n// \"wav\",\r\n// \"m4a\",\r\n// \"flac\",\r\n// \"aac\",\r\n// \"opus\",\r\n// ],\r\n// } as const;\r\n",
11
- "import type { BaseContext } from \"./types\";\r\n\r\nexport function createContext<C extends BaseContext>(\r\n contextCreator: (req: Request) => Promise<C>\r\n) {\r\n return contextCreator;\r\n}\r\n",
11
+ "import type { BaseContext } from \"./types\";\r\n\r\nexport function createContext<TCustom extends Record<string, any>>(\r\n contextCreator: (req: Request) => Promise<TCustom>\r\n): (req: Request) => Promise<BaseContext & TCustom>;\r\nexport function createContext(\r\n contextCreator: (req: Request) => Promise<void>\r\n): (req: Request) => Promise<BaseContext>;\r\nexport function createContext(contextCreator: any): any {\r\n return contextCreator;\r\n}\r\n",
12
12
  "import { z } from \"zod\";\r\n\r\n// Common MIME type groups\r\nconst MIME_TYPES = {\r\n image: [\r\n \"image/jpeg\",\r\n \"image/png\",\r\n \"image/gif\",\r\n \"image/webp\",\r\n \"image/svg+xml\",\r\n ],\r\n video: [\"video/mp4\", \"video/webm\", \"video/ogg\"],\r\n audio: [\"audio/mpeg\", \"audio/ogg\", \"audio/wav\"],\r\n document: [\r\n \"application/pdf\",\r\n \"application/msword\",\r\n \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\r\n \"application/vnd.ms-excel\",\r\n \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\r\n ],\r\n} as const;\r\n\r\ntype MimeTypeGroup = keyof typeof MIME_TYPES;\r\ntype MimeTypeValues<T extends MimeTypeGroup> = (typeof MIME_TYPES)[T][number];\r\n\r\n// Type for accepting either specific types or wildcard per group\r\ntype MimeTypeConfig = {\r\n [K in MimeTypeGroup]?: \"*\" | MimeTypeValues<K>[];\r\n};\r\n\r\n/** Options for creating a file validation schema */\r\ntype FileSchemaOptions = {\r\n /** Accepted MIME types configuration. Use \"*\" for all types in a category or specify an array of types\r\n * @example\r\n * {\r\n * image: \"*\", // All image types\r\n * audio: [\"audio/mpeg\"], // Only MP3s\r\n * document: [\"application/pdf\", \"application/msword\"] // PDFs and DOCs\r\n * }\r\n */\r\n acceptedTypes?: MimeTypeConfig;\r\n /** Maximum file size in megabytes */\r\n maxSize?: number;\r\n /** Minimum file size in megabytes */\r\n minSize?: number;\r\n /** Whether the file field is required */\r\n // required?: boolean;\r\n /** Custom error messages */\r\n messages?: {\r\n /** Custom message for type validation failure */\r\n type?: string;\r\n /** Custom message for maximum size validation failure */\r\n maxSize?: string;\r\n /** Custom message for minimum size validation failure */\r\n minSize?: string;\r\n /** Custom message for required field validation failure */\r\n required?: string;\r\n };\r\n};\r\n\r\nconst convertToBytes = (\r\n size: number,\r\n unit: \"MB\" | \"KB\" | \"B\" = \"MB\"\r\n): number => {\r\n switch (unit) {\r\n case \"MB\":\r\n return size * 1024 * 1024;\r\n case \"KB\":\r\n return size * 1024;\r\n case \"B\":\r\n return size;\r\n }\r\n};\r\n\r\n/**\r\n * Creates a Zod schema for file validation with support for MIME types and size constraints\r\n * you can extend it as any other zod schema after calling it\r\n * @param {Object} options - The configuration options for the file schema\r\n * @returns Zod schema for file validation\r\n */\r\nexport const createFileSchema = ({\r\n acceptedTypes,\r\n maxSize = Infinity,\r\n minSize,\r\n // required = true,\r\n messages = {},\r\n}: FileSchemaOptions = {}) => {\r\n // Convert MB to bytes\r\n const maxBytes = maxSize ? convertToBytes(maxSize) : Infinity;\r\n const minBytes = minSize ? convertToBytes(minSize) : 0;\r\n\r\n // Process accepted types\r\n const validMimeTypes = acceptedTypes\r\n ? Object.entries(acceptedTypes).flatMap(([category, types]) => {\r\n const cat = category as MimeTypeGroup;\r\n\r\n // Handle wildcard\r\n if (types === \"*\") {\r\n return MIME_TYPES[cat];\r\n }\r\n\r\n // Handle array of specific types\r\n if (Array.isArray(types)) {\r\n return types;\r\n }\r\n\r\n return [];\r\n })\r\n : undefined;\r\n\r\n // Base schema\r\n let schema = z.instanceof(File, {\r\n message: messages.required ?? \"File is required\",\r\n });\r\n\r\n // Add size refinement\r\n schema = schema\r\n .refine(\r\n (file) => file.size <= maxBytes,\r\n messages.maxSize ?? `File size must be less than ${maxSize}MB`\r\n )\r\n .refine(\r\n (file) => file.size >= minBytes,\r\n messages.minSize ?? `File size must be at least ${minSize}MB`\r\n );\r\n\r\n // Add type refinement if acceptedTypes is provided\r\n if (validMimeTypes?.length) {\r\n schema = schema.refine(\r\n (file) =>\r\n validMimeTypes.includes(file.type as MimeTypeValues<MimeTypeGroup>),\r\n messages.type ?? `File must be of type: ${validMimeTypes.join(\", \")}`\r\n );\r\n }\r\n\r\n return schema;\r\n};\r\n",
13
13
  "import type { BaseContext } from \"../..\";\r\n\r\n// blockPaths.ts\r\nexport type PathBlockerConfig = {\r\n paths: string[]; // Array of paths/patterns to block\r\n};\r\n\r\nexport const createPathBlocker = (config: PathBlockerConfig) => {\r\n const patterns = config.paths.map((path) => new RegExp(path));\r\n const message = \"Not Found\";\r\n\r\n return async <C extends BaseContext>(ctx: C): Promise<void> => {\r\n const url = new URL(ctx.req.url);\r\n const path = url.pathname;\r\n\r\n // Check if the path matches any blocked pattern\r\n if (patterns.some((pattern) => pattern.test(path))) {\r\n throw new Error(message);\r\n }\r\n };\r\n};\r\n",
14
- "import type { BaseContext } from \"../../types\";\r\n\r\nexport interface RateLimitConfig {\r\n windowMs: number;\r\n maxRequests: number;\r\n maxEntries?: number;\r\n cleanupIntervalMs?: number;\r\n message?: string;\r\n statusCode?: number;\r\n headerPrefix?: string;\r\n}\r\n\r\ninterface RequestWindow {\r\n count: number;\r\n startTime: number;\r\n lastAccessed: number;\r\n}\r\n\r\ninterface RateLimitResult {\r\n isLimited: boolean;\r\n remaining: number;\r\n resetTime: number;\r\n}\r\n\r\nclass RateLimiter {\r\n private requests: Map<string, RequestWindow> = new Map();\r\n private lastCleanupTime: number = Date.now();\r\n private readonly alertThreshold: number;\r\n private config: Required<RateLimitConfig>;\r\n\r\n constructor(config: RateLimitConfig) {\r\n this.config = {\r\n windowMs: config.windowMs,\r\n maxRequests: config.maxRequests,\r\n maxEntries: config.maxEntries ?? 10000,\r\n cleanupIntervalMs: config.cleanupIntervalMs ?? 60000,\r\n message: config.message ?? \"Too Many Requests\",\r\n statusCode: config.statusCode ?? 429,\r\n headerPrefix: config.headerPrefix ?? \"X-RateLimit\",\r\n };\r\n this.alertThreshold = this.config.maxEntries * 0.8;\r\n\r\n // Start periodic cleanup\r\n if (process.env.NODE_ENV !== \"development\") {\r\n setInterval(() => this.cleanup(), this.config.cleanupIntervalMs);\r\n }\r\n }\r\n\r\n private cleanup(): number {\r\n const now = Date.now();\r\n let deletedCount = 0;\r\n\r\n for (const [ip, window] of this.requests.entries()) {\r\n const windowExpired = now - window.startTime > this.config.windowMs;\r\n const inactive = now - window.lastAccessed > this.config.windowMs * 2;\r\n\r\n if (windowExpired || inactive) {\r\n this.requests.delete(ip);\r\n deletedCount++;\r\n }\r\n }\r\n\r\n this.lastCleanupTime = now;\r\n return deletedCount;\r\n }\r\n\r\n private handleMaxEntries(ip: string): boolean {\r\n const currentSize = this.requests.size;\r\n\r\n // Regular cleanup if interval passed\r\n if (Date.now() - this.lastCleanupTime > this.config.cleanupIntervalMs) {\r\n this.cleanup();\r\n }\r\n\r\n // Alert if nearing capacity\r\n if (currentSize >= this.alertThreshold) {\r\n console.warn(\r\n `Rate limiter at ${Math.round(\r\n (currentSize / this.config.maxEntries) * 100,\r\n )}% capacity`,\r\n );\r\n }\r\n\r\n // If IP is already tracked, allow it\r\n if (this.requests.has(ip)) {\r\n return true;\r\n }\r\n\r\n // Reject if at max capacity\r\n return currentSize < this.config.maxEntries;\r\n }\r\n\r\n check(ip: string): RateLimitResult {\r\n // Check system capacity first\r\n if (!this.handleMaxEntries(ip)) {\r\n return {\r\n isLimited: true,\r\n remaining: 0,\r\n resetTime: Date.now() + this.config.windowMs,\r\n };\r\n }\r\n\r\n const now = Date.now();\r\n const window = this.requests.get(ip);\r\n\r\n // Create new window if none exists or current one expired\r\n if (!window || now - window.startTime >= this.config.windowMs) {\r\n this.requests.set(ip, {\r\n count: 1,\r\n startTime: now,\r\n lastAccessed: now,\r\n });\r\n\r\n return {\r\n isLimited: false,\r\n remaining: this.config.maxRequests - 1,\r\n resetTime: now + this.config.windowMs,\r\n };\r\n }\r\n\r\n // Update existing window\r\n window.lastAccessed = now;\r\n const isLimited = window.count >= this.config.maxRequests;\r\n\r\n if (!isLimited) {\r\n window.count++;\r\n }\r\n\r\n return {\r\n isLimited,\r\n remaining: Math.max(0, this.config.maxRequests - window.count),\r\n resetTime: window.startTime + this.config.windowMs,\r\n };\r\n }\r\n\r\n getConfig() {\r\n return this.config;\r\n }\r\n}\r\n\r\n// Middleware factory\r\nexport const createRateLimiter = (config: RateLimitConfig) => {\r\n const limiter = new RateLimiter(config);\r\n\r\n return async <C extends BaseContext>(ctx: C): Promise<void> => {\r\n // Skip rate limiting for video range requests\r\n if (ctx.req.headers.get(\"range\")) {\r\n return; // Don't apply rate limiting to video chunks\r\n }\r\n\r\n const ip =\r\n ctx.req.headers.get(\"x-forwarded-for\")?.split(\",\")[0] || // Get first IP if multiple\r\n ctx.req.headers.get(\"x-real-ip\") ||\r\n \"unknown\";\r\n\r\n const { isLimited, remaining, resetTime } = limiter.check(ip);\r\n\r\n const { headerPrefix } = limiter.getConfig();\r\n ctx.headers.set(`${headerPrefix}-Remaining`, remaining.toString());\r\n ctx.headers.set(`${headerPrefix}-Reset`, resetTime.toString());\r\n\r\n if (isLimited) {\r\n ctx.headers.set(`${headerPrefix}-Exceeded`, \"true\");\r\n throw new Error(limiter.getConfig().message);\r\n }\r\n };\r\n};\r\n\r\n//example usage with more options\r\n// const rateLimiter = createRateLimiter({\r\n// windowMs: 60 * 1000, // 1 minute\r\n// maxRequests: 100, // 100 requests per minute\r\n// maxEntries: 10000, // Maximum number of IPs to track\r\n// cleanupIntervalMs: 30000, // Cleanup every 30 seconds\r\n// message: 'Rate limit exceeded. Please try again later.',\r\n// headerPrefix: 'X-RateLimit'\r\n// });\r\n\r\n// const router = createRouter({\r\n// context: createContext,\r\n// routes: appRoutes,\r\n// globalMiddlewares: [rateLimiter],\r\n// // ... other config\r\n// });\r\n"
14
+ "import type { BaseContext } from \"../../types\";\r\n\r\nexport interface RateLimitConfig {\r\n windowMs: number;\r\n maxRequests: number;\r\n maxEntries?: number;\r\n cleanupIntervalMs?: number;\r\n message?: string;\r\n statusCode?: number;\r\n headerPrefix?: string;\r\n}\r\n\r\ninterface RequestWindow {\r\n count: number;\r\n startTime: number;\r\n lastAccessed: number;\r\n}\r\n\r\ninterface RateLimitResult {\r\n isLimited: boolean;\r\n remaining: number;\r\n resetTime: number;\r\n}\r\n\r\nclass RateLimiter {\r\n private requests: Map<string, RequestWindow> = new Map();\r\n private lastCleanupTime: number = Date.now();\r\n private readonly alertThreshold: number;\r\n private config: Required<RateLimitConfig>;\r\n\r\n constructor(config: RateLimitConfig) {\r\n this.config = {\r\n windowMs: config.windowMs,\r\n maxRequests: config.maxRequests,\r\n maxEntries: config.maxEntries ?? 10000,\r\n cleanupIntervalMs: config.cleanupIntervalMs ?? 60000,\r\n message: config.message ?? \"Too Many Requests\",\r\n statusCode: config.statusCode ?? 429,\r\n headerPrefix: config.headerPrefix ?? \"X-RateLimit\",\r\n };\r\n this.alertThreshold = this.config.maxEntries * 0.8;\r\n\r\n // Start periodic cleanup\r\n if (process.env.NODE_ENV !== \"development\") {\r\n setInterval(() => this.cleanup(), this.config.cleanupIntervalMs);\r\n }\r\n }\r\n\r\n private cleanup(): number {\r\n const now = Date.now();\r\n let deletedCount = 0;\r\n\r\n for (const [ip, window] of this.requests.entries()) {\r\n const windowExpired = now - window.startTime > this.config.windowMs;\r\n const inactive = now - window.lastAccessed > this.config.windowMs * 2;\r\n\r\n if (windowExpired || inactive) {\r\n this.requests.delete(ip);\r\n deletedCount++;\r\n }\r\n }\r\n\r\n this.lastCleanupTime = now;\r\n return deletedCount;\r\n }\r\n\r\n private handleMaxEntries(ip: string): boolean {\r\n const currentSize = this.requests.size;\r\n\r\n // Regular cleanup if interval passed\r\n if (Date.now() - this.lastCleanupTime > this.config.cleanupIntervalMs) {\r\n this.cleanup();\r\n }\r\n\r\n // Alert if nearing capacity\r\n if (currentSize >= this.alertThreshold) {\r\n console.warn(\r\n `Rate limiter at ${Math.round(\r\n (currentSize / this.config.maxEntries) * 100,\r\n )}% capacity`,\r\n );\r\n }\r\n\r\n // If IP is already tracked, allow it\r\n if (this.requests.has(ip)) {\r\n return true;\r\n }\r\n\r\n // Reject if at max capacity\r\n return currentSize < this.config.maxEntries;\r\n }\r\n\r\n check(ip: string): RateLimitResult {\r\n // Check system capacity first\r\n if (!this.handleMaxEntries(ip)) {\r\n return {\r\n isLimited: true,\r\n remaining: 0,\r\n resetTime: Date.now() + this.config.windowMs,\r\n };\r\n }\r\n\r\n const now = Date.now();\r\n const window = this.requests.get(ip);\r\n\r\n // Create new window if none exists or current one expired\r\n if (!window || now - window.startTime >= this.config.windowMs) {\r\n this.requests.set(ip, {\r\n count: 1,\r\n startTime: now,\r\n lastAccessed: now,\r\n });\r\n\r\n return {\r\n isLimited: false,\r\n remaining: this.config.maxRequests - 1,\r\n resetTime: now + this.config.windowMs,\r\n };\r\n }\r\n\r\n // Update existing window\r\n window.lastAccessed = now;\r\n const isLimited = window.count >= this.config.maxRequests;\r\n\r\n if (!isLimited) {\r\n window.count++;\r\n }\r\n\r\n return {\r\n isLimited,\r\n remaining: Math.max(0, this.config.maxRequests - window.count),\r\n resetTime: window.startTime + this.config.windowMs,\r\n };\r\n }\r\n\r\n getConfig() {\r\n return this.config;\r\n }\r\n}\r\n\r\n// Middleware factory\r\nexport const createRateLimiter = (config: RateLimitConfig) => {\r\n const limiter = new RateLimiter(config);\r\n\r\n return async <C extends BaseContext>(ctx: C): Promise<void> => {\r\n // Skip rate limiting for video range requests\r\n if (ctx.req.headers.get(\"range\")) {\r\n return; // Don't apply rate limiting to video chunks\r\n }\r\n\r\n const ip =\r\n ctx.req.headers.get(\"x-forwarded-for\")?.split(\",\")[0] || // Get first IP if multiple\r\n ctx.req.headers.get(\"x-real-ip\") ||\r\n \"unknown\";\r\n\r\n const { isLimited, remaining, resetTime } = limiter.check(ip);\r\n\r\n const { headerPrefix } = limiter.getConfig();\r\n ctx.headers.set(`${headerPrefix}-Remaining`, remaining.toString());\r\n ctx.headers.set(`${headerPrefix}-Reset`, resetTime.toString());\r\n\r\n if (isLimited) {\r\n ctx.headers.set(`${headerPrefix}-Exceeded`, \"true\");\r\n throw new Error(limiter.getConfig().message);\r\n }\r\n };\r\n};\r\n\r\n//example usage with more options\r\n// const rateLimiter = createRateLimiter({\r\n// windowMs: 60 * 1000, // 1 minute\r\n// maxRequests: 100, // 100 requests per minute\r\n// maxEntries: 10000, // Maximum number of IPs to track\r\n// cleanupIntervalMs: 30000, // Cleanup every 30 seconds\r\n// message: 'Rate limit exceeded. Please try again later.',\r\n// headerPrefix: 'X-RateLimit'\r\n// });\r\n\r\n// const router = createRouter({\r\n// context: createContext,\r\n// routes: appRoutes,\r\n// globalMiddlewares: [rateLimiter],\r\n// // ... other config\r\n// });\r\n",
15
+ "import type { BaseContext } from \"../types\";\r\n\r\n/**\r\n * Helper to define a reusable, typed middleware outside of a procedure chain.\r\n *\r\n * @example\r\n * ```ts\r\n * // Infer context type from your context creator\r\n * const authMiddleware = createMiddleware(context, async (ctx) => {\r\n * const session = await getSession(ctx.req);\r\n * if (!session) throw new BRPCError({ code: \"UNAUTHORIZED\" });\r\n * return { session };\r\n * });\r\n *\r\n * // Or with an explicit generic (no context reference needed)\r\n * const authMiddleware = createMiddleware<MyContext>(async (ctx) => {\r\n * return { session: await getSession(ctx.req) };\r\n * });\r\n *\r\n * createProcedure(context)\r\n * .use(authMiddleware) // ctx.session is typed in the handler ✅\r\n * .query(async ({ ctx }) => ctx.session.user);\r\n * ```\r\n */\r\nexport function createMiddleware<C extends BaseContext, TReturn extends Record<string, any> | void = void>(\r\n _context: (req: Request) => Promise<C>,\r\n fn: (ctx: C) => Promise<TReturn>\r\n): (ctx: C) => Promise<TReturn>;\r\nexport function createMiddleware<C extends BaseContext, TReturn extends Record<string, any> | void = void>(\r\n fn: (ctx: C) => Promise<TReturn>\r\n): (ctx: C) => Promise<TReturn>;\r\nexport function createMiddleware<C extends BaseContext, TReturn extends Record<string, any> | void = void>(\r\n contextOrFn: ((req: Request) => Promise<C>) | ((ctx: C) => Promise<TReturn>),\r\n fn?: (ctx: C) => Promise<TReturn>\r\n): (ctx: C) => Promise<TReturn> {\r\n return fn ?? (contextOrFn as (ctx: C) => Promise<TReturn>);\r\n}\r\n"
15
16
  ],
16
- "mappings": "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",
17
- "debugId": "EBF1C3C33DEA530E64756E2164756E21",
17
+ "mappings": "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",
18
+ "debugId": "A0ABAC27AD65C3FD64756E2164756E21",
18
19
  "names": []
19
20
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ import type { BaseContext } from "../types";
2
+ /**
3
+ * Helper to define a reusable, typed middleware outside of a procedure chain.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * // Infer context type from your context creator
8
+ * const authMiddleware = createMiddleware(context, async (ctx) => {
9
+ * const session = await getSession(ctx.req);
10
+ * if (!session) throw new BRPCError({ code: "UNAUTHORIZED" });
11
+ * return { session };
12
+ * });
13
+ *
14
+ * // Or with an explicit generic (no context reference needed)
15
+ * const authMiddleware = createMiddleware<MyContext>(async (ctx) => {
16
+ * return { session: await getSession(ctx.req) };
17
+ * });
18
+ *
19
+ * createProcedure(context)
20
+ * .use(authMiddleware) // ctx.session is typed in the handler ✅
21
+ * .query(async ({ ctx }) => ctx.session.user);
22
+ * ```
23
+ */
24
+ export declare function createMiddleware<C extends BaseContext, TReturn extends Record<string, any> | void = void>(_context: (req: Request) => Promise<C>, fn: (ctx: C) => Promise<TReturn>): (ctx: C) => Promise<TReturn>;
25
+ export declare function createMiddleware<C extends BaseContext, TReturn extends Record<string, any> | void = void>(fn: (ctx: C) => Promise<TReturn>): (ctx: C) => Promise<TReturn>;