@spfn/core 0.2.0-beta.1 → 0.2.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +262 -1092
  2. package/dist/{boss-D-fGtVgM.d.ts → boss-DI1r4kTS.d.ts} +68 -11
  3. package/dist/codegen/index.d.ts +55 -8
  4. package/dist/codegen/index.js +159 -5
  5. package/dist/codegen/index.js.map +1 -1
  6. package/dist/config/index.d.ts +36 -0
  7. package/dist/config/index.js +15 -6
  8. package/dist/config/index.js.map +1 -1
  9. package/dist/db/index.d.ts +13 -0
  10. package/dist/db/index.js +40 -6
  11. package/dist/db/index.js.map +1 -1
  12. package/dist/env/index.d.ts +82 -3
  13. package/dist/env/index.js +81 -14
  14. package/dist/env/index.js.map +1 -1
  15. package/dist/env/loader.d.ts +87 -0
  16. package/dist/env/loader.js +70 -0
  17. package/dist/env/loader.js.map +1 -0
  18. package/dist/event/index.d.ts +3 -70
  19. package/dist/event/index.js +10 -1
  20. package/dist/event/index.js.map +1 -1
  21. package/dist/event/sse/client.d.ts +82 -0
  22. package/dist/event/sse/client.js +115 -0
  23. package/dist/event/sse/client.js.map +1 -0
  24. package/dist/event/sse/index.d.ts +40 -0
  25. package/dist/event/sse/index.js +92 -0
  26. package/dist/event/sse/index.js.map +1 -0
  27. package/dist/job/index.d.ts +54 -8
  28. package/dist/job/index.js +61 -12
  29. package/dist/job/index.js.map +1 -1
  30. package/dist/middleware/index.d.ts +102 -11
  31. package/dist/middleware/index.js +2 -2
  32. package/dist/middleware/index.js.map +1 -1
  33. package/dist/nextjs/index.d.ts +2 -2
  34. package/dist/nextjs/index.js +36 -4
  35. package/dist/nextjs/index.js.map +1 -1
  36. package/dist/nextjs/server.d.ts +62 -15
  37. package/dist/nextjs/server.js +102 -33
  38. package/dist/nextjs/server.js.map +1 -1
  39. package/dist/route/index.d.ts +227 -15
  40. package/dist/route/index.js +307 -31
  41. package/dist/route/index.js.map +1 -1
  42. package/dist/route/types.d.ts +2 -31
  43. package/dist/router-Di7ENoah.d.ts +151 -0
  44. package/dist/server/index.d.ts +153 -6
  45. package/dist/server/index.js +216 -14
  46. package/dist/server/index.js.map +1 -1
  47. package/dist/types-B-e_f2dQ.d.ts +121 -0
  48. package/dist/{types-DRG2XMTR.d.ts → types-BOPTApC2.d.ts} +91 -3
  49. package/docs/cache.md +133 -0
  50. package/docs/codegen.md +74 -0
  51. package/docs/database.md +346 -0
  52. package/docs/entity.md +539 -0
  53. package/docs/env.md +477 -0
  54. package/docs/errors.md +319 -0
  55. package/docs/event.md +116 -0
  56. package/docs/file-upload.md +717 -0
  57. package/docs/job.md +131 -0
  58. package/docs/logger.md +108 -0
  59. package/docs/middleware.md +337 -0
  60. package/docs/nextjs.md +241 -0
  61. package/docs/repository.md +496 -0
  62. package/docs/route.md +497 -0
  63. package/docs/server.md +307 -0
  64. package/package.json +18 -3
@@ -1,7 +1,7 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
- import { Router } from '@spfn/core/route';
2
+ import { Router, HttpMethod } from '@spfn/core/route';
3
3
  import { InterceptorRule as InterceptorRule$1 } from '@spfn/core/nextjs/server';
4
- import { S as SetCookie } from '../types-DRG2XMTR.js';
4
+ import { f as SetCookie } from '../types-BOPTApC2.js';
5
5
  import '@sinclair/typebox';
6
6
  import '@spfn/core/errors';
7
7
 
@@ -115,7 +115,16 @@ interface TypedProxyConfig {
115
115
  * Next.js API Route handler that resolves routeName to method/path
116
116
  * and forwards requests to SPFN backend.
117
117
  *
118
- * @example
118
+ * @example Using routeMap (recommended - no server code loaded)
119
+ * ```typescript
120
+ * // app/api/rpc/[routeName]/route.ts
121
+ * import { routeMap } from '@/generated/route-map';
122
+ * import { createRpcProxy } from '@spfn/core/nextjs/proxy';
123
+ *
124
+ * export const { GET, POST } = createRpcProxy({ routeMap });
125
+ * ```
126
+ *
127
+ * @example Using router (legacy - loads full server code)
119
128
  * ```typescript
120
129
  * // app/api/rpc/[routeName]/route.ts
121
130
  * import { appRouter } from '@/server/router';
@@ -125,29 +134,66 @@ interface TypedProxyConfig {
125
134
  * ```
126
135
  */
127
136
 
128
- interface RpcProxyConfig<TRouter extends Router<any>> extends Omit<TypedProxyConfig, 'onRequest' | 'onResponse'> {
137
+ /**
138
+ * Route info from generated route map
139
+ */
140
+ interface RouteMapEntry {
141
+ method: HttpMethod;
142
+ path: string;
143
+ }
144
+ /**
145
+ * Generated route map type
146
+ */
147
+ type RouteMap = Record<string, RouteMapEntry>;
148
+ /**
149
+ * Base config for RPC proxy
150
+ */
151
+ interface RpcProxyBaseConfig extends Omit<TypedProxyConfig, 'onRequest' | 'onResponse'> {
152
+ }
153
+ /**
154
+ * Config using routeMap (recommended)
155
+ *
156
+ * Uses generated route map file - no server code loaded in Next.js process.
157
+ */
158
+ interface RpcProxyRouteMapConfig extends RpcProxyBaseConfig {
159
+ /**
160
+ * Generated route map containing routeName → {method, path} mappings
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * import { routeMap } from '@/generated/route-map';
165
+ *
166
+ * export const { GET, POST } = createRpcProxy({ routeMap });
167
+ * ```
168
+ */
169
+ routeMap: RouteMap;
170
+ router?: never;
171
+ }
172
+ /**
173
+ * Config using router (legacy)
174
+ *
175
+ * @deprecated Use routeMap instead to avoid loading server code in Next.js process
176
+ */
177
+ interface RpcProxyRouterConfig<TRouter extends Router<any>> extends RpcProxyBaseConfig {
129
178
  /**
130
179
  * The router containing all route definitions
131
180
  *
132
- * Package routes registered via `.packages()` are automatically recognized.
181
+ * @deprecated Use routeMap instead - router imports all server code
133
182
  *
134
183
  * @example
135
184
  * ```typescript
136
- * // router.ts
137
- * export const appRouter = defineRouter({
138
- * getRoot,
139
- * getHealth,
140
- * })
141
- * .packages([authRouter, cmsAppRouter]);
142
- *
143
- * // api/rpc/[routeName]/route.ts
144
185
  * export const { GET, POST } = createRpcProxy({
145
186
  * router: appRouter,
146
187
  * });
147
188
  * ```
148
189
  */
149
190
  router: TRouter;
191
+ routeMap?: never;
150
192
  }
193
+ /**
194
+ * Combined config type
195
+ */
196
+ type RpcProxyConfig<TRouter extends Router<any> = Router<any>> = RpcProxyRouteMapConfig | RpcProxyRouterConfig<TRouter>;
151
197
  /**
152
198
  * Create RPC proxy handler for Next.js API Route
153
199
  *
@@ -155,7 +201,7 @@ interface RpcProxyConfig<TRouter extends Router<any>> extends Omit<TypedProxyCon
155
201
  * - GET /api/rpc/{routeName}?input={...}
156
202
  * - POST /api/rpc/{routeName} with body
157
203
  *
158
- * Resolves routeName to actual HTTP method and path from the router,
204
+ * Resolves routeName to actual HTTP method and path from the router or routeMap,
159
205
  * then forwards to SPFN backend.
160
206
  */
161
207
  declare function createRpcProxy<TRouter extends Router<any>>(config: RpcProxyConfig<TRouter>): {
@@ -280,6 +326,7 @@ interface ResponseInterceptorContext {
280
326
  * Response data (mutable)
281
327
  */
282
328
  response: {
329
+ ok: boolean;
283
330
  status: number;
284
331
  statusText: string;
285
332
  headers: Headers;
@@ -580,4 +627,4 @@ declare const interceptorRegistry: InterceptorRegistry;
580
627
  */
581
628
  declare function registerInterceptors(packageName: string, interceptors: InterceptorRule[]): void;
582
629
 
583
- export { type InterceptorRule, type ProxyConfig, type ProxyRequestInterceptor, type ProxyResponseInterceptor, type RequestInterceptor, type RequestInterceptorContext, type RequestInterceptorResult, type ResponseInterceptor, type ResponseInterceptorContext, type ResponseInterceptorResult, type RpcProxyConfig, type TypedProxyConfig, createRpcProxy, executeRequestInterceptors, executeResponseInterceptors, filterMatchingInterceptors, interceptorRegistry, matchMethod, matchPath, registerInterceptors };
630
+ export { type InterceptorRule, type ProxyConfig, type RequestInterceptor, type RequestInterceptorContext, type ResponseInterceptor, type ResponseInterceptorContext, type RpcProxyConfig, createRpcProxy, executeRequestInterceptors, executeResponseInterceptors, filterMatchingInterceptors, interceptorRegistry, matchMethod, matchPath, registerInterceptors };
@@ -27,6 +27,9 @@ function buildQueryString(query) {
27
27
  return `?${searchParams.toString()}`;
28
28
  }
29
29
  async function parseResponseBody(response) {
30
+ if (response.status === 204) {
31
+ return null;
32
+ }
30
33
  const contentType = response.headers.get("content-type");
31
34
  if (contentType?.includes("application/json")) {
32
35
  const text = await response.text();
@@ -311,6 +314,7 @@ function buildResponseContext(path, method, requestHeaders, requestBody, respons
311
314
  body: requestBody
312
315
  },
313
316
  response: {
317
+ ok: response.ok,
314
318
  status: response.status,
315
319
  statusText: response.statusText,
316
320
  headers: response.headers,
@@ -352,7 +356,6 @@ function getRouteByPath(router, routePath) {
352
356
  }
353
357
  function createRpcProxy(config) {
354
358
  const {
355
- router,
356
359
  apiUrl = env.SPFN_API_URL || "http://localhost:8790",
357
360
  debug = env.NODE_ENV === "development",
358
361
  timeout = 3e4,
@@ -361,7 +364,37 @@ function createRpcProxy(config) {
361
364
  autoDiscoverInterceptors = true,
362
365
  disableAutoInterceptors
363
366
  } = config;
364
- const packageRouters = router._packageRouters || [];
367
+ const useRouteMap = "routeMap" in config && config.routeMap !== void 0;
368
+ const routeMap = useRouteMap ? config.routeMap : null;
369
+ const router = !useRouteMap && "router" in config ? config.router : null;
370
+ const packageRouters = router?._packageRouters || [];
371
+ function resolveRoute(routeName) {
372
+ if (routeMap) {
373
+ const entry = routeMap[routeName];
374
+ if (entry) {
375
+ return { method: entry.method, path: entry.path };
376
+ }
377
+ return null;
378
+ }
379
+ if (router) {
380
+ let routeDef = getRouteByPath(router, routeName);
381
+ if (!routeDef && packageRouters.length > 0) {
382
+ for (const pkgRouter of packageRouters) {
383
+ routeDef = getRouteByPath(pkgRouter, routeName);
384
+ if (routeDef) {
385
+ if (debug) {
386
+ rpcLogger.debug(`Route "${routeName}" found in package router`);
387
+ }
388
+ break;
389
+ }
390
+ }
391
+ }
392
+ if (routeDef && routeDef.method && routeDef.path) {
393
+ return { method: routeDef.method, path: routeDef.path };
394
+ }
395
+ }
396
+ return null;
397
+ }
365
398
  async function handleRpc(request, context) {
366
399
  const startTime = Date.now();
367
400
  const params = await context.params;
@@ -374,6 +407,7 @@ function createRpcProxy(config) {
374
407
  );
375
408
  }
376
409
  let input = {};
410
+ let rawFormData = null;
377
411
  if (request.method === "GET") {
378
412
  const inputParam = request.nextUrl.searchParams.get("input");
379
413
  if (inputParam) {
@@ -387,45 +421,63 @@ function createRpcProxy(config) {
387
421
  }
388
422
  }
389
423
  } else {
390
- try {
391
- input = await request.json();
392
- } catch {
393
- return NextResponse.json(
394
- buildErrorResponse("Bad Request", "Invalid JSON body", debug),
395
- { status: 400 }
396
- );
397
- }
398
- }
399
- let routeDef = getRouteByPath(router, routeName);
400
- if (!routeDef && packageRouters.length > 0) {
401
- for (const pkgRouter of packageRouters) {
402
- routeDef = getRouteByPath(pkgRouter, routeName);
403
- if (routeDef) {
404
- if (debug) {
405
- rpcLogger.debug(`Route "${routeName}" found in package router`);
424
+ const contentType = request.headers.get("content-type") || "";
425
+ if (contentType.includes("multipart/form-data")) {
426
+ try {
427
+ rawFormData = await request.formData();
428
+ const metadataStr = rawFormData.get("__metadata");
429
+ if (metadataStr && typeof metadataStr === "string") {
430
+ const metadata = JSON.parse(metadataStr);
431
+ input.params = metadata.params;
432
+ input.query = metadata.query;
433
+ input.headers = metadata.headers;
434
+ input.cookies = metadata.cookies;
406
435
  }
407
- break;
436
+ input.formData = {};
437
+ rawFormData.forEach((value, key) => {
438
+ if (key === "__metadata") return;
439
+ const existing = input.formData[key];
440
+ if (existing !== void 0) {
441
+ if (Array.isArray(existing)) {
442
+ existing.push(value);
443
+ } else {
444
+ input.formData[key] = [existing, value];
445
+ }
446
+ } else {
447
+ input.formData[key] = value;
448
+ }
449
+ });
450
+ } catch (error) {
451
+ return NextResponse.json(
452
+ buildErrorResponse("Bad Request", "Invalid form data", debug),
453
+ { status: 400 }
454
+ );
455
+ }
456
+ } else {
457
+ try {
458
+ input = await request.json();
459
+ } catch {
460
+ return NextResponse.json(
461
+ buildErrorResponse("Bad Request", "Invalid JSON body", debug),
462
+ { status: 400 }
463
+ );
408
464
  }
409
465
  }
410
466
  }
411
- if (!routeDef) {
467
+ const routeInfo = resolveRoute(routeName);
468
+ if (!routeInfo) {
412
469
  rpcLogger.warn(`Route not found: ${routeName}`);
413
470
  return NextResponse.json(
414
- buildErrorResponse("Not Found", `Route "${routeName}" not found in router`, debug),
471
+ buildErrorResponse("Not Found", `Route "${routeName}" not found`, debug),
415
472
  { status: 404 }
416
473
  );
417
474
  }
418
- const { method: targetMethod, path: targetPath } = routeDef;
419
- if (!targetMethod || !targetPath) {
420
- rpcLogger.warn(`Route "${routeName}" is missing method or path`);
421
- return NextResponse.json(
422
- buildErrorResponse("Internal Error", `Route "${routeName}" is misconfigured`, debug),
423
- { status: 500 }
424
- );
425
- }
475
+ const { method: targetMethod, path: targetPath } = routeInfo;
426
476
  const inputParams = input.params || {};
427
477
  const inputQuery = input.query || {};
428
478
  const inputBody = input.body;
479
+ const inputFormData = input.formData;
480
+ const hasFormData = rawFormData !== null && inputFormData && Object.keys(inputFormData).length > 0;
429
481
  const resolvedPath = buildUrlWithParams(targetPath, inputParams);
430
482
  const queryString = buildQueryString(inputQuery);
431
483
  const targetUrl = `${apiUrl}${resolvedPath}${queryString}`;
@@ -435,16 +487,30 @@ function createRpcProxy(config) {
435
487
  targetMethod,
436
488
  targetPath: resolvedPath,
437
489
  targetUrl,
438
- hasBody: !!inputBody
490
+ hasBody: !!inputBody,
491
+ hasFormData
439
492
  });
440
493
  }
441
494
  const headers = buildProxyHeaders(request.headers, defaultHeaders);
495
+ if (hasFormData) {
496
+ headers.delete("content-type");
497
+ }
442
498
  const fetchOptions = {
443
499
  method: targetMethod,
444
500
  headers
445
501
  };
446
- if (["POST", "PUT", "PATCH"].includes(targetMethod) && inputBody) {
447
- fetchOptions.body = JSON.stringify(inputBody);
502
+ if (["POST", "PUT", "PATCH"].includes(targetMethod)) {
503
+ if (hasFormData && rawFormData) {
504
+ const forwardFormData = new FormData();
505
+ rawFormData.forEach((value, key) => {
506
+ if (key !== "__metadata") {
507
+ forwardFormData.append(key, value);
508
+ }
509
+ });
510
+ fetchOptions.body = forwardFormData;
511
+ } else if (inputBody) {
512
+ fetchOptions.body = JSON.stringify(inputBody);
513
+ }
448
514
  }
449
515
  const allInterceptors = collectInterceptors(autoDiscoverInterceptors, disableAutoInterceptors, interceptors, interceptorRegistry);
450
516
  const matchingInterceptors = filterMatchingInterceptors(allInterceptors, resolvedPath, targetMethod);
@@ -504,7 +570,10 @@ function createRpcProxy(config) {
504
570
  duration: `${duration}ms`
505
571
  });
506
572
  }
507
- const nextResponse = NextResponse.json(body, {
573
+ const nextResponse = responseCtx.response.status === 204 ? new NextResponse(null, {
574
+ status: 204,
575
+ statusText: responseCtx.response.statusText
576
+ }) : NextResponse.json(body, {
508
577
  status: responseCtx.response.status,
509
578
  statusText: responseCtx.response.statusText
510
579
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/nextjs/shared.ts","../../src/nextjs/proxy/interceptors/helpers.ts","../../src/nextjs/proxy/interceptors/registry.ts","../../src/nextjs/proxy/helpers.ts","../../src/nextjs/proxy/rpc.ts"],"names":["headersToForward"],"mappings":"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","file":"server.js","sourcesContent":["/**\n * Shared utilities for Next.js client and proxy modules\n *\n * Contains common functions used by both client and proxy to avoid code duplication.\n */\n\n/**\n * Build URL with path parameters replaced\n *\n * @example\n * buildUrlWithParams('/users/:id/posts/:postId', { id: '123', postId: '456' })\n * // Returns: '/users/123/posts/456'\n */\nexport function buildUrlWithParams(path: string, params: Record<string, any>): string\n{\n let url = path;\n for (const [key, value] of Object.entries(params))\n {\n url = url.replace(`:${key}`, encodeURIComponent(String(value)));\n }\n\n return url;\n}\n\n/**\n * Build query string from object\n *\n * @example\n * buildQueryString({ page: '1', limit: '10', tags: ['foo', 'bar'] })\n * // Returns: '?page=1&limit=10&tags=foo&tags=bar'\n */\nexport function buildQueryString(query: Record<string, any>): string\n{\n if (Object.keys(query).length === 0)\n {\n return '';\n }\n\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(query))\n {\n if (Array.isArray(value))\n {\n value.forEach((v) => searchParams.append(key, String(v)));\n }\n else\n {\n searchParams.append(key, String(value));\n }\n }\n\n return `?${searchParams.toString()}`;\n}\n\n/**\n * Build Cookie header string from cookies object\n *\n * @example\n * buildCookieHeader({ session: 'abc123', theme: 'dark' })\n * // Returns: 'session=abc123; theme=dark'\n */\nexport function buildCookieHeader(cookies: Record<string, string>): string\n{\n return Object.entries(cookies)\n .map(([key, value]) => `${key}=${value}`)\n .join('; ');\n}\n\n/**\n * Parse response body based on content type\n */\nexport async function parseResponseBody(response: Response): Promise<any>\n{\n const contentType = response.headers.get('content-type');\n\n if (contentType?.includes('application/json'))\n {\n const text = await response.text();\n return text ? JSON.parse(text) : null;\n }\n else\n {\n return await response.text();\n }\n}","/**\n * SPFN Next.js Proxy Interceptor Execution Engine\n */\n\nimport type {\n InterceptorRule,\n RequestInterceptor,\n ResponseInterceptor,\n RequestInterceptorContext,\n ResponseInterceptorContext,\n} from './types';\n\n/**\n * Check if path matches pattern\n *\n * Supports:\n * - Wildcards: '/_auth/*' matches '/_auth/login'\n * - Path params: '/users/:id' matches '/users/123'\n * - RegExp: /^\\/_auth\\/.+$/ matches '/_auth/login'\n * - Exact match: '/_auth/login' matches '/_auth/login'\n * - All: '*' matches any path\n *\n * @param path - Request path to test\n * @param pattern - Pattern to match against\n * @returns True if path matches pattern\n */\nexport function matchPath(path: string, pattern: string | RegExp): boolean\n{\n // Match all\n if (pattern === '*')\n {\n return true;\n }\n\n // RegExp pattern\n if (pattern instanceof RegExp)\n {\n return pattern.test(path);\n }\n\n // String pattern\n // Convert wildcard pattern to RegExp\n // '/_auth/*' -> /^\\/_auth\\/.*/\n // '/users/:id' -> /^\\/users\\/[^/]+$/\n const regexPattern = pattern\n .replace(/\\*/g, '.*')\n .replace(/:[^/]+/g, '[^/]+')\n .replace(/\\//g, '\\\\/');\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(path);\n}\n\n/**\n * Check if method matches pattern\n *\n * @param method - Request method (e.g., 'POST')\n * @param pattern - Method pattern (e.g., 'POST' or ['POST', 'PUT'])\n * @returns True if method matches pattern\n */\nexport function matchMethod(\n method: string,\n pattern?: string | string[]\n): boolean\n{\n // No method filter = match all\n if (!pattern)\n {\n return true;\n }\n\n // Single method\n if (typeof pattern === 'string')\n {\n return method.toUpperCase() === pattern.toUpperCase();\n }\n\n // Multiple methods\n return pattern.some((m) => m.toUpperCase() === method.toUpperCase());\n}\n\n/**\n * Filter interceptors that match the request\n *\n * @param rules - All interceptor rules\n * @param path - Request path\n * @param method - Request method\n * @returns Matched interceptors\n */\nexport function filterMatchingInterceptors(\n rules: InterceptorRule[],\n path: string,\n method: string\n): InterceptorRule[]\n{\n return rules.filter((rule) => {\n return matchPath(path, rule.pathPattern) && matchMethod(method, rule.method);\n });\n}\n\n/**\n * Execute request interceptors in chain\n *\n * Interceptors are executed in order:\n * 1. First registered interceptor\n * 2. Second registered interceptor\n * 3. ... and so on\n *\n * Each interceptor must call next() to continue the chain.\n * If next() is not called, the chain stops and remaining interceptors are skipped.\n *\n * @param context - Request interceptor context\n * @param interceptors - Interceptors to execute\n */\nexport async function executeRequestInterceptors(\n context: RequestInterceptorContext,\n interceptors: RequestInterceptor[]\n): Promise<void>\n{\n let index = 0;\n\n const next = async (): Promise<void> => {\n if (index >= interceptors.length)\n {\n return;\n }\n\n const interceptor = interceptors[index];\n index++;\n\n await interceptor(context, next);\n };\n\n await next();\n}\n\n/**\n * Execute response interceptors in chain\n *\n * Interceptors are executed in order:\n * 1. First registered interceptor\n * 2. Second registered interceptor\n * 3. ... and so on\n *\n * Each interceptor must call next() to continue the chain.\n * If next() is not called, the chain stops and remaining interceptors are skipped.\n *\n * @param context - Response interceptor context\n * @param interceptors - Interceptors to execute\n */\nexport async function executeResponseInterceptors(\n context: ResponseInterceptorContext,\n interceptors: ResponseInterceptor[]\n): Promise<void>\n{\n let index = 0;\n\n const next = async (): Promise<void> => {\n if (index >= interceptors.length)\n {\n return;\n }\n\n const interceptor = interceptors[index];\n index++;\n\n await interceptor(context, next);\n };\n\n await next();\n}","/**\n * Global Interceptor Registry\n *\n * Allows packages to automatically register their interceptors\n * for Next.js proxy without manual configuration.\n *\n * Uses globalThis for persistence across module reloads (HMR).\n */\nimport type { InterceptorRule } from './types';\n\n// ============================================================================\n// Global Type Declarations\n// ============================================================================\n\n/**\n * Extend globalThis with interceptor registry\n *\n * Using globalThis allows the registry to persist across module reloads (HMR).\n * preventing duplicate registrations during development with HMR.\n */\ndeclare global\n{\n var __SPFN_INTERCEPTOR_REGISTRY__: InterceptorRegistry | undefined;\n}\n\n/**\n * Global interceptor registry\n *\n * Packages register their interceptors on import,\n * and proxy automatically discovers and applies them.\n */\nexport class InterceptorRegistry\n{\n private interceptors = new Map<string, InterceptorRule[]>();\n\n /**\n * Register interceptors for a package\n *\n * @param packageName - Unique package identifier (e.g., 'auth', 'storage')\n * @param interceptors - Array of interceptor rules\n *\n * @example\n * ```typescript\n * registerInterceptors('auth', [\n * {\n * pathPattern: '/_auth/*',\n * request: async (ctx, next) => { ... }\n * }\n * ]);\n * ```\n */\n register(packageName: string, interceptors: InterceptorRule[]): void\n {\n if (!this.interceptors.has(packageName))\n {\n this.interceptors.set(packageName, interceptors);\n }\n }\n\n /**\n * Get all registered interceptors\n *\n * @param exclude - Package names to exclude\n * @returns Flat array of all interceptor rules\n */\n getAll(exclude: string[] = []): InterceptorRule[]\n {\n const all: InterceptorRule[] = [];\n\n for (const [packageName, interceptors] of this.interceptors.entries())\n {\n if (!exclude.includes(packageName))\n {\n all.push(...interceptors);\n }\n }\n\n return all;\n }\n\n /**\n * Get interceptors for specific package\n *\n * @param packageName - Package identifier\n * @returns Interceptor rules or undefined\n */\n get(packageName: string): InterceptorRule[] | undefined\n {\n return this.interceptors.get(packageName);\n }\n\n /**\n * Get list of registered package names\n */\n getPackageNames(): string[]\n {\n return Array.from(this.interceptors.keys());\n }\n\n /**\n * Check if package has registered interceptors\n */\n has(packageName: string): boolean\n {\n return this.interceptors.has(packageName);\n }\n\n /**\n * Unregister interceptors for a package\n *\n * @param packageName - Package identifier\n */\n unregister(packageName: string): void\n {\n this.interceptors.delete(packageName);\n }\n\n /**\n * Clear all registered interceptors\n *\n * Useful for testing\n */\n clear(): void\n {\n this.interceptors.clear();\n }\n\n /**\n * Get total count of registered interceptors\n */\n count(): number\n {\n let total = 0;\n for (const interceptors of this.interceptors.values())\n {\n total += interceptors.length;\n }\n return total;\n }\n}\n\n/**\n * Global singleton registry instance\n *\n * Uses globalThis to persist across module reloads (HMR).\n * This prevents duplicate registrations during development.\n */\nexport const interceptorRegistry = (() =>\n{\n if (!globalThis.__SPFN_INTERCEPTOR_REGISTRY__)\n {\n globalThis.__SPFN_INTERCEPTOR_REGISTRY__ = new InterceptorRegistry();\n }\n\n return globalThis.__SPFN_INTERCEPTOR_REGISTRY__;\n})();\n\n/**\n * Register interceptors for a package\n *\n * This should be called during package initialization (on import).\n * The interceptors will be automatically applied by the Next.js proxy.\n *\n * @param packageName - Unique package identifier (e.g., 'auth', 'storage')\n * @param interceptors - Array of interceptor rules\n *\n * @example\n * ```typescript\n * // packages/auth/src/adapters/nextjs/interceptors/index.ts\n * import { registerInterceptors } from '@spfn/core/nextjs';\n *\n * const authInterceptors = [\n * {\n * pathPattern: '/_auth/*',\n * request: async (ctx, next) => {\n * // Add JWT token\n * ctx.headers['Authorization'] = 'Bearer token';\n * await next();\n * }\n * }\n * ];\n *\n * // Auto-register on import\n * registerInterceptors('auth', authInterceptors);\n * ```\n */\nexport function registerInterceptors(\n packageName: string,\n interceptors: InterceptorRule[]\n): void\n{\n interceptorRegistry.register(packageName, interceptors);\n}","/**\n * Helper functions for proxy handler\n * Separates utility logic from main proxy handler for better maintainability\n */\nimport { NextRequest } from 'next/server';\nimport type { CookieOptions, SetCookie } from \"../client\";\nimport type { InterceptorRule, RequestInterceptorContext, ResponseInterceptorContext } from './interceptors/types';\nimport type { InterceptorRegistry } from './interceptors/registry';\n\n// Re-export from shared\nexport { parseResponseBody } from '../shared';\n\n/**\n * Build request headers for proxying\n * Forwards important headers from source and adds default headers\n *\n * @param sourceHeaders - Source headers (can be Headers object or Record)\n * @param defaultHeaders - Default headers to add\n */\nexport function buildProxyHeaders(\n sourceHeaders: Headers | Record<string, string>,\n defaultHeaders: Record<string, string>\n): Headers\n{\n const headers = new Headers();\n\n // Forward important headers from source\n const headersToForward = [\n 'content-type',\n 'authorization',\n 'cookie',\n 'user-agent',\n 'accept',\n 'accept-language',\n ];\n\n for (const header of headersToForward)\n {\n const value = sourceHeaders instanceof Headers\n ? sourceHeaders.get(header)\n : sourceHeaders[header];\n\n if (value)\n {\n headers.set(header, value);\n }\n }\n\n // Add default headers\n for (const [key, value] of Object.entries(defaultHeaders))\n {\n headers.set(key, value);\n }\n\n return headers;\n}\n\n/**\n * Parse cookies from Cookie header string\n *\n * @param cookieHeader - Cookie header string (e.g., \"session=abc; theme=dark\")\n * @returns Map of cookie name-value pairs\n */\nexport function parseCookies(cookieHeader: string | null | undefined): Map<string, string>\n{\n const cookiesMap = new Map<string, string>();\n\n if (!cookieHeader)\n {\n return cookiesMap;\n }\n\n const cookiePairs = cookieHeader.split(';').map(c => c.trim());\n for (const pair of cookiePairs)\n {\n const [name, ...valueParts] = pair.split('=');\n if (name && valueParts.length > 0)\n {\n const value = valueParts.join('='); // Handle = in cookie value\n cookiesMap.set(name.trim(), value.trim());\n }\n }\n\n return cookiesMap;\n}\n\n/**\n * Parse cookies from NextRequest (Next.js specific helper)\n * Combines cookies from both NextRequest.cookies and Cookie header\n */\nexport function parseCookiesFromNextRequest(request: NextRequest): Map<string, string>\n{\n const cookiesMap = new Map<string, string>();\n\n // Add cookies from NextRequest (browser cookies)\n for (const cookie of request.cookies.getAll())\n {\n cookiesMap.set(cookie.name, cookie.value);\n }\n\n // Add cookies from Cookie header (server-side forwarded cookies)\n const cookieHeader = request.headers.get('cookie');\n if (cookieHeader)\n {\n const parsed = parseCookies(cookieHeader);\n for (const [name, value] of parsed.entries())\n {\n cookiesMap.set(name, value);\n }\n }\n\n return cookiesMap;\n}\n\n// Mapping of option names to Set-Cookie attribute formats\nconst optionMappings: Array<{\n key: keyof CookieOptions;\n format: (value: any) => string | null;\n}> = [\n { key: 'httpOnly', format: (v) => v ? 'HttpOnly' : null },\n { key: 'secure', format: (v) => v ? 'Secure' : null },\n { key: 'sameSite', format: (v) => v ? `SameSite=${v}` : null },\n { key: 'maxAge', format: (v) => v !== undefined ? `Max-Age=${v}` : null },\n { key: 'path', format: (v) => v ? `Path=${v}` : null },\n { key: 'domain', format: (v) => v ? `Domain=${v}` : null },\n];\n\n/**\n * Build Set-Cookie header string from cookie options\n */\nexport function buildSetCookieHeader(cookie: SetCookie): string\n{\n const parts = [`${cookie.name}=${cookie.value}`];\n const options = cookie.options || {};\n\n for (const { key, format } of optionMappings)\n {\n const value = options[key];\n if (value !== undefined && value !== false)\n {\n const formatted = format(value);\n if (formatted)\n {\n parts.push(formatted);\n }\n }\n }\n\n return parts.join('; ');\n}\n\n/**\n * Build error response JSON\n */\nexport function buildErrorResponse(\n errorType: string,\n message: string,\n debug: boolean,\n error?: Error\n): any\n{\n return {\n error: errorType,\n message,\n ...(debug && error?.stack && { stack: error.stack }),\n };\n}\n\nconst headersToForward = [\n 'content-type',\n 'cache-control',\n 'set-cookie',\n 'etag',\n 'last-modified',\n];\n\n/**\n * Forward response headers back to client\n */\nexport function forwardResponseHeaders(\n sourceHeaders: Headers,\n targetHeaders: Headers\n): void\n{\n for (const header of headersToForward)\n {\n const value = sourceHeaders.get(header);\n if (value)\n {\n targetHeaders.set(header, value);\n }\n }\n}\n\n/**\n * Collect all interceptors (auto-discovered + config)\n */\nexport function collectInterceptors(\n autoDiscoverInterceptors: boolean,\n disableAutoInterceptors: string[] | undefined,\n configInterceptors: InterceptorRule[] | undefined,\n registry: InterceptorRegistry\n): InterceptorRule[]\n{\n const allInterceptors: InterceptorRule[] = [];\n\n // Auto-discover from registry\n if (autoDiscoverInterceptors)\n {\n const registeredInterceptors = registry.getAll(disableAutoInterceptors || []);\n allInterceptors.push(...registeredInterceptors);\n }\n\n // Add config interceptors\n if (configInterceptors)\n {\n allInterceptors.push(...configInterceptors);\n }\n\n return allInterceptors;\n}\n\n/**\n * Build RequestInterceptorContext\n */\nexport function buildRequestContext(\n path: string,\n method: string,\n headers: Headers,\n body: any,\n searchParams: URLSearchParams,\n cookiesMap: Map<string, string>,\n request: NextRequest\n): RequestInterceptorContext\n{\n return {\n path: `/${path}`,\n method,\n headers: Object.fromEntries(headers.entries()),\n body,\n query: Object.fromEntries(searchParams.entries()),\n cookies: cookiesMap,\n request,\n metadata: {},\n };\n}\n\n/**\n * Build ResponseInterceptorContext\n */\nexport function buildResponseContext(\n path: string,\n method: string,\n requestHeaders: Headers,\n requestBody: any,\n response: Response,\n responseBody: any,\n requestMetadata: Record<string, any>\n): ResponseInterceptorContext\n{\n return {\n path: `/${path}`,\n method,\n request: {\n headers: Object.fromEntries(requestHeaders.entries()),\n body: requestBody,\n },\n response: {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n body: responseBody,\n },\n setCookies: [],\n metadata: requestMetadata,\n };\n}","/**\n * RPC-Style Proxy for define-route System\n *\n * Next.js API Route handler that resolves routeName to method/path\n * and forwards requests to SPFN backend.\n *\n * @example\n * ```typescript\n * // app/api/rpc/[routeName]/route.ts\n * import { appRouter } from '@/server/router';\n * import { createRpcProxy } from '@spfn/core/nextjs/proxy';\n *\n * export const { GET, POST } = createRpcProxy({ router: appRouter });\n * ```\n */\nimport { NextRequest, NextResponse } from 'next/server';\n\nimport { env } from '@spfn/core/config';\nimport { logger } from '@spfn/core/logger';\nimport type { Router, RouteDef } from '@spfn/core/route';\n\nimport { buildUrlWithParams, buildQueryString } from '../shared';\nimport { interceptorRegistry } from './interceptors';\nimport { executeRequestInterceptors, executeResponseInterceptors, filterMatchingInterceptors } from './interceptors';\nimport {\n buildProxyHeaders,\n parseCookiesFromNextRequest,\n buildSetCookieHeader,\n buildErrorResponse,\n forwardResponseHeaders,\n parseResponseBody,\n collectInterceptors,\n buildRequestContext,\n buildResponseContext,\n} from './helpers';\nimport type { TypedProxyConfig } from \"./types\";\n\nconst rpcLogger = logger.child('@spfn/core:rpc-proxy');\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface RpcProxyConfig<TRouter extends Router<any>> extends Omit<TypedProxyConfig, 'onRequest' | 'onResponse'>\n{\n /**\n * The router containing all route definitions\n *\n * Package routes registered via `.packages()` are automatically recognized.\n *\n * @example\n * ```typescript\n * // router.ts\n * export const appRouter = defineRouter({\n * getRoot,\n * getHealth,\n * })\n * .packages([authRouter, cmsAppRouter]);\n *\n * // api/rpc/[routeName]/route.ts\n * export const { GET, POST } = createRpcProxy({\n * router: appRouter,\n * });\n * ```\n */\n router: TRouter;\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Type guard to check if value is a RouteDef\n */\nfunction isRouteDef(value: unknown): value is RouteDef<any>\n{\n return value !== null &&\n typeof value === 'object' &&\n 'handler' in value &&\n 'method' in value &&\n 'path' in value;\n}\n\n/**\n * Type guard to check if value is a Router\n */\nfunction isRouter(value: unknown): value is Router<any>\n{\n return value !== null &&\n typeof value === 'object' &&\n 'routes' in value &&\n '_routes' in value;\n}\n\n/**\n * Get route definition from router by dotted path\n *\n * @example\n * getRouteByPath(router, 'users.getUser') → RouteDef\n * getRouteByPath(router, 'getUser') → RouteDef\n */\nfunction getRouteByPath(router: Router<any>, routePath: string): RouteDef<any> | null\n{\n const parts = routePath.split('.');\n let current: any = router.routes;\n\n for (const part of parts)\n {\n if (!current || typeof current !== 'object')\n {\n return null;\n }\n\n const next = current[part];\n\n if (isRouter(next))\n {\n current = next.routes;\n }\n else if (isRouteDef(next))\n {\n return next;\n }\n else\n {\n current = next;\n }\n }\n\n if (isRouteDef(current))\n {\n return current;\n }\n\n return null;\n}\n\n// ============================================================================\n// RPC Proxy Handler\n// ============================================================================\n\n/**\n * Create RPC proxy handler for Next.js API Route\n *\n * Handles requests in the format:\n * - GET /api/rpc/{routeName}?input={...}\n * - POST /api/rpc/{routeName} with body\n *\n * Resolves routeName to actual HTTP method and path from the router,\n * then forwards to SPFN backend.\n */\nexport function createRpcProxy<TRouter extends Router<any>>(config: RpcProxyConfig<TRouter>)\n{\n const {\n router,\n apiUrl = env.SPFN_API_URL || 'http://localhost:8790',\n debug = env.NODE_ENV === 'development',\n timeout = 30000,\n headers: defaultHeaders = {},\n interceptors,\n autoDiscoverInterceptors = true,\n disableAutoInterceptors,\n } = config;\n\n // Get package routers (registered via .packages())\n const packageRouters = router._packageRouters || [];\n\n /**\n * Handle RPC request\n */\n async function handleRpc(\n request: NextRequest,\n context: { params: Promise<{ routeName?: string }> }\n ): Promise<NextResponse>\n {\n const startTime = Date.now();\n const params = await context.params;\n\n try\n {\n const routeName = params.routeName;\n\n if (!routeName)\n {\n return NextResponse.json(\n buildErrorResponse('Bad Request', 'Missing routeName parameter', debug),\n { status: 400 }\n );\n }\n\n // Parse input from query string (GET) or body (POST)\n let input: {\n params?: Record<string, any>;\n query?: Record<string, any>;\n body?: Record<string, any>;\n } = {};\n\n if (request.method === 'GET')\n {\n const inputParam = request.nextUrl.searchParams.get('input');\n if (inputParam)\n {\n try\n {\n input = JSON.parse(decodeURIComponent(inputParam));\n }\n catch\n {\n return NextResponse.json(\n buildErrorResponse('Bad Request', 'Invalid input parameter', debug),\n { status: 400 }\n );\n }\n }\n }\n else\n {\n // POST - parse body\n try\n {\n input = await request.json();\n }\n catch\n {\n return NextResponse.json(\n buildErrorResponse('Bad Request', 'Invalid JSON body', debug),\n { status: 400 }\n );\n }\n }\n\n // Get route definition from router (try main router first, then package routers)\n let routeDef = getRouteByPath(router, routeName);\n\n // If not found in main router, search in package routers\n if (!routeDef && packageRouters.length > 0)\n {\n for (const pkgRouter of packageRouters)\n {\n routeDef = getRouteByPath(pkgRouter, routeName);\n if (routeDef)\n {\n if (debug)\n {\n rpcLogger.debug(`Route \"${routeName}\" found in package router`);\n }\n break;\n }\n }\n }\n\n if (!routeDef)\n {\n rpcLogger.warn(`Route not found: ${routeName}`);\n return NextResponse.json(\n buildErrorResponse('Not Found', `Route \"${routeName}\" not found in router`, debug),\n { status: 404 }\n );\n }\n\n const { method: targetMethod, path: targetPath } = routeDef;\n\n if (!targetMethod || !targetPath)\n {\n rpcLogger.warn(`Route \"${routeName}\" is missing method or path`);\n return NextResponse.json(\n buildErrorResponse('Internal Error', `Route \"${routeName}\" is misconfigured`, debug),\n { status: 500 }\n );\n }\n\n // Build target URL with params and query\n const inputParams = input.params || {};\n const inputQuery = input.query || {};\n const inputBody = input.body;\n\n const resolvedPath = buildUrlWithParams(targetPath, inputParams);\n const queryString = buildQueryString(inputQuery);\n const targetUrl = `${apiUrl}${resolvedPath}${queryString}`;\n\n if (debug)\n {\n rpcLogger.debug('→ RPC request', {\n routeName,\n targetMethod,\n targetPath: resolvedPath,\n targetUrl,\n hasBody: !!inputBody,\n });\n }\n\n // Build headers\n const headers = buildProxyHeaders(request.headers, defaultHeaders);\n\n // Build fetch options\n const fetchOptions: RequestInit = {\n method: targetMethod,\n headers,\n };\n\n // Add body for POST/PUT/PATCH\n if (['POST', 'PUT', 'PATCH'].includes(targetMethod) && inputBody)\n {\n fetchOptions.body = JSON.stringify(inputBody);\n }\n\n // ============================================================\n // Advanced Interceptors - BEFORE FETCH\n // ============================================================\n\n // Collect and filter interceptors\n const allInterceptors = collectInterceptors(autoDiscoverInterceptors, disableAutoInterceptors, interceptors, interceptorRegistry);\n const matchingInterceptors = filterMatchingInterceptors(allInterceptors, resolvedPath, targetMethod);\n\n if (debug && matchingInterceptors.length > 0)\n {\n rpcLogger.debug(`🎯 Found ${matchingInterceptors.length} matching interceptors for ${targetMethod} ${resolvedPath}`);\n }\n\n // Create RequestInterceptorContext\n const cookiesMap = parseCookiesFromNextRequest(request);\n const requestCtx = buildRequestContext(\n resolvedPath.slice(1), // Remove leading slash\n targetMethod,\n headers,\n inputBody,\n new URLSearchParams(queryString.slice(1)), // Remove leading ?\n cookiesMap,\n request\n );\n\n // Execute request interceptors\n const requestInterceptorsToRun = matchingInterceptors.map(r => r.request).filter((i): i is NonNullable<typeof i> => !!i);\n if (requestInterceptorsToRun.length > 0)\n {\n await executeRequestInterceptors(requestCtx, requestInterceptorsToRun);\n\n // Apply modified headers\n for (const [key, value] of Object.entries(requestCtx.headers))\n {\n headers.set(key, value);\n }\n\n // Apply modified body\n if (requestCtx.body)\n {\n fetchOptions.body = JSON.stringify(requestCtx.body);\n }\n }\n\n // Execute fetch with timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try\n {\n const response = await fetch(targetUrl, {\n ...fetchOptions,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n let body = await parseResponseBody(response);\n\n // ============================================================\n // Advanced Interceptors - AFTER FETCH\n // ============================================================\n\n // Create ResponseInterceptorContext\n const responseCtx = buildResponseContext(\n resolvedPath.slice(1),\n targetMethod,\n headers,\n inputBody,\n response,\n body,\n requestCtx.metadata\n );\n\n // Execute response interceptors\n const responseInterceptorsToRun = matchingInterceptors.map(r => r.response).filter((i): i is NonNullable<typeof i> => !!i);\n if (responseInterceptorsToRun.length > 0)\n {\n await executeResponseInterceptors(responseCtx, responseInterceptorsToRun);\n body = responseCtx.response.body;\n }\n\n const duration = Date.now() - startTime;\n\n if (debug)\n {\n rpcLogger.debug('← RPC response', {\n routeName,\n status: responseCtx.response.status,\n duration: `${duration}ms`,\n });\n }\n\n // Build Next.js response\n const nextResponse = NextResponse.json(body, {\n status: responseCtx.response.status,\n statusText: responseCtx.response.statusText,\n });\n\n // Forward response headers\n forwardResponseHeaders(response.headers, nextResponse.headers);\n\n // Apply setCookies from interceptors\n for (const cookie of responseCtx.setCookies)\n {\n const setCookieHeader = buildSetCookieHeader(cookie);\n nextResponse.headers.append('Set-Cookie', setCookieHeader);\n\n if (debug)\n {\n rpcLogger.debug('🍪 Set-Cookie header added', {\n name: cookie.name,\n });\n }\n }\n\n return nextResponse;\n }\n catch (error)\n {\n clearTimeout(timeoutId);\n\n // Handle timeout\n if (error instanceof Error && error.name === 'AbortError')\n {\n rpcLogger.error('Request timeout', {\n routeName,\n targetUrl,\n timeout,\n });\n\n return NextResponse.json(\n buildErrorResponse('Gateway Timeout', `Request timed out after ${timeout}ms`, debug, error),\n { status: 504 }\n );\n }\n\n // Handle other fetch errors\n const fetchErr = error as Error;\n rpcLogger.error('Fetch error', {\n routeName,\n targetUrl,\n error: fetchErr.message,\n });\n\n return NextResponse.json(\n buildErrorResponse('Bad Gateway', fetchErr.message || 'Failed to connect to backend', debug, fetchErr),\n { status: 502 }\n );\n }\n }\n catch (error)\n {\n const duration = Date.now() - startTime;\n const err = error as Error;\n\n rpcLogger.error('RPC proxy error', {\n error: err.message,\n stack: err.stack,\n duration: `${duration}ms`,\n });\n\n return NextResponse.json(\n buildErrorResponse('Internal Server Error', err.message || 'Unknown error', debug, err),\n { status: 500 }\n );\n }\n }\n\n // Return route handlers\n return {\n GET: (req: NextRequest, context: { params: Promise<{ routeName?: string }> }) =>\n handleRpc(req, context),\n POST: (req: NextRequest, context: { params: Promise<{ routeName?: string }> }) =>\n handleRpc(req, context),\n };\n}"]}
1
+ {"version":3,"sources":["../../src/nextjs/shared.ts","../../src/nextjs/proxy/interceptors/helpers.ts","../../src/nextjs/proxy/interceptors/registry.ts","../../src/nextjs/proxy/helpers.ts","../../src/nextjs/proxy/rpc.ts"],"names":["headersToForward"],"mappings":"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","file":"server.js","sourcesContent":["/**\n * Shared utilities for Next.js client and proxy modules\n *\n * Contains common functions used by both client and proxy to avoid code duplication.\n */\n\n/**\n * Build URL with path parameters replaced\n *\n * @example\n * buildUrlWithParams('/users/:id/posts/:postId', { id: '123', postId: '456' })\n * // Returns: '/users/123/posts/456'\n */\nexport function buildUrlWithParams(path: string, params: Record<string, any>): string\n{\n let url = path;\n for (const [key, value] of Object.entries(params))\n {\n url = url.replace(`:${key}`, encodeURIComponent(String(value)));\n }\n\n return url;\n}\n\n/**\n * Build query string from object\n *\n * @example\n * buildQueryString({ page: '1', limit: '10', tags: ['foo', 'bar'] })\n * // Returns: '?page=1&limit=10&tags=foo&tags=bar'\n */\nexport function buildQueryString(query: Record<string, any>): string\n{\n if (Object.keys(query).length === 0)\n {\n return '';\n }\n\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(query))\n {\n if (Array.isArray(value))\n {\n value.forEach((v) => searchParams.append(key, String(v)));\n }\n else\n {\n searchParams.append(key, String(value));\n }\n }\n\n return `?${searchParams.toString()}`;\n}\n\n/**\n * Build Cookie header string from cookies object\n *\n * @example\n * buildCookieHeader({ session: 'abc123', theme: 'dark' })\n * // Returns: 'session=abc123; theme=dark'\n */\nexport function buildCookieHeader(cookies: Record<string, string>): string\n{\n return Object.entries(cookies)\n .map(([key, value]) => `${key}=${value}`)\n .join('; ');\n}\n\n/**\n * Parse response body based on content type\n *\n * Handles:\n * - 204 No Content: returns null (no body expected)\n * - application/json: parses JSON body\n * - Other content types: returns raw text\n */\nexport async function parseResponseBody(response: Response): Promise<any>\n{\n // 204 No Content has no body\n if (response.status === 204)\n {\n return null;\n }\n\n const contentType = response.headers.get('content-type');\n\n if (contentType?.includes('application/json'))\n {\n const text = await response.text();\n return text ? JSON.parse(text) : null;\n }\n else\n {\n return await response.text();\n }\n}","/**\n * SPFN Next.js Proxy Interceptor Execution Engine\n */\n\nimport type {\n InterceptorRule,\n RequestInterceptor,\n ResponseInterceptor,\n RequestInterceptorContext,\n ResponseInterceptorContext,\n} from './types';\n\n/**\n * Check if path matches pattern\n *\n * Supports:\n * - Wildcards: '/_auth/*' matches '/_auth/login'\n * - Path params: '/users/:id' matches '/users/123'\n * - RegExp: /^\\/_auth\\/.+$/ matches '/_auth/login'\n * - Exact match: '/_auth/login' matches '/_auth/login'\n * - All: '*' matches any path\n *\n * @param path - Request path to test\n * @param pattern - Pattern to match against\n * @returns True if path matches pattern\n */\nexport function matchPath(path: string, pattern: string | RegExp): boolean\n{\n // Match all\n if (pattern === '*')\n {\n return true;\n }\n\n // RegExp pattern\n if (pattern instanceof RegExp)\n {\n return pattern.test(path);\n }\n\n // String pattern\n // Convert wildcard pattern to RegExp\n // '/_auth/*' -> /^\\/_auth\\/.*/\n // '/users/:id' -> /^\\/users\\/[^/]+$/\n const regexPattern = pattern\n .replace(/\\*/g, '.*')\n .replace(/:[^/]+/g, '[^/]+')\n .replace(/\\//g, '\\\\/');\n\n const regex = new RegExp(`^${regexPattern}$`);\n return regex.test(path);\n}\n\n/**\n * Check if method matches pattern\n *\n * @param method - Request method (e.g., 'POST')\n * @param pattern - Method pattern (e.g., 'POST' or ['POST', 'PUT'])\n * @returns True if method matches pattern\n */\nexport function matchMethod(\n method: string,\n pattern?: string | string[]\n): boolean\n{\n // No method filter = match all\n if (!pattern)\n {\n return true;\n }\n\n // Single method\n if (typeof pattern === 'string')\n {\n return method.toUpperCase() === pattern.toUpperCase();\n }\n\n // Multiple methods\n return pattern.some((m) => m.toUpperCase() === method.toUpperCase());\n}\n\n/**\n * Filter interceptors that match the request\n *\n * @param rules - All interceptor rules\n * @param path - Request path\n * @param method - Request method\n * @returns Matched interceptors\n */\nexport function filterMatchingInterceptors(\n rules: InterceptorRule[],\n path: string,\n method: string\n): InterceptorRule[]\n{\n return rules.filter((rule) => {\n return matchPath(path, rule.pathPattern) && matchMethod(method, rule.method);\n });\n}\n\n/**\n * Execute request interceptors in chain\n *\n * Interceptors are executed in order:\n * 1. First registered interceptor\n * 2. Second registered interceptor\n * 3. ... and so on\n *\n * Each interceptor must call next() to continue the chain.\n * If next() is not called, the chain stops and remaining interceptors are skipped.\n *\n * @param context - Request interceptor context\n * @param interceptors - Interceptors to execute\n */\nexport async function executeRequestInterceptors(\n context: RequestInterceptorContext,\n interceptors: RequestInterceptor[]\n): Promise<void>\n{\n let index = 0;\n\n const next = async (): Promise<void> => {\n if (index >= interceptors.length)\n {\n return;\n }\n\n const interceptor = interceptors[index];\n index++;\n\n await interceptor(context, next);\n };\n\n await next();\n}\n\n/**\n * Execute response interceptors in chain\n *\n * Interceptors are executed in order:\n * 1. First registered interceptor\n * 2. Second registered interceptor\n * 3. ... and so on\n *\n * Each interceptor must call next() to continue the chain.\n * If next() is not called, the chain stops and remaining interceptors are skipped.\n *\n * @param context - Response interceptor context\n * @param interceptors - Interceptors to execute\n */\nexport async function executeResponseInterceptors(\n context: ResponseInterceptorContext,\n interceptors: ResponseInterceptor[]\n): Promise<void>\n{\n let index = 0;\n\n const next = async (): Promise<void> => {\n if (index >= interceptors.length)\n {\n return;\n }\n\n const interceptor = interceptors[index];\n index++;\n\n await interceptor(context, next);\n };\n\n await next();\n}","/**\n * Global Interceptor Registry\n *\n * Allows packages to automatically register their interceptors\n * for Next.js proxy without manual configuration.\n *\n * Uses globalThis for persistence across module reloads (HMR).\n */\nimport type { InterceptorRule } from './types';\n\n// ============================================================================\n// Global Type Declarations\n// ============================================================================\n\n/**\n * Extend globalThis with interceptor registry\n *\n * Using globalThis allows the registry to persist across module reloads (HMR).\n * preventing duplicate registrations during development with HMR.\n */\ndeclare global\n{\n var __SPFN_INTERCEPTOR_REGISTRY__: InterceptorRegistry | undefined;\n}\n\n/**\n * Global interceptor registry\n *\n * Packages register their interceptors on import,\n * and proxy automatically discovers and applies them.\n */\nexport class InterceptorRegistry\n{\n private interceptors = new Map<string, InterceptorRule[]>();\n\n /**\n * Register interceptors for a package\n *\n * @param packageName - Unique package identifier (e.g., 'auth', 'storage')\n * @param interceptors - Array of interceptor rules\n *\n * @example\n * ```typescript\n * registerInterceptors('auth', [\n * {\n * pathPattern: '/_auth/*',\n * request: async (ctx, next) => { ... }\n * }\n * ]);\n * ```\n */\n register(packageName: string, interceptors: InterceptorRule[]): void\n {\n if (!this.interceptors.has(packageName))\n {\n this.interceptors.set(packageName, interceptors);\n }\n }\n\n /**\n * Get all registered interceptors\n *\n * @param exclude - Package names to exclude\n * @returns Flat array of all interceptor rules\n */\n getAll(exclude: string[] = []): InterceptorRule[]\n {\n const all: InterceptorRule[] = [];\n\n for (const [packageName, interceptors] of this.interceptors.entries())\n {\n if (!exclude.includes(packageName))\n {\n all.push(...interceptors);\n }\n }\n\n return all;\n }\n\n /**\n * Get interceptors for specific package\n *\n * @param packageName - Package identifier\n * @returns Interceptor rules or undefined\n */\n get(packageName: string): InterceptorRule[] | undefined\n {\n return this.interceptors.get(packageName);\n }\n\n /**\n * Get list of registered package names\n */\n getPackageNames(): string[]\n {\n return Array.from(this.interceptors.keys());\n }\n\n /**\n * Check if package has registered interceptors\n */\n has(packageName: string): boolean\n {\n return this.interceptors.has(packageName);\n }\n\n /**\n * Unregister interceptors for a package\n *\n * @param packageName - Package identifier\n */\n unregister(packageName: string): void\n {\n this.interceptors.delete(packageName);\n }\n\n /**\n * Clear all registered interceptors\n *\n * Useful for testing\n */\n clear(): void\n {\n this.interceptors.clear();\n }\n\n /**\n * Get total count of registered interceptors\n */\n count(): number\n {\n let total = 0;\n for (const interceptors of this.interceptors.values())\n {\n total += interceptors.length;\n }\n return total;\n }\n}\n\n/**\n * Global singleton registry instance\n *\n * Uses globalThis to persist across module reloads (HMR).\n * This prevents duplicate registrations during development.\n */\nexport const interceptorRegistry = (() =>\n{\n if (!globalThis.__SPFN_INTERCEPTOR_REGISTRY__)\n {\n globalThis.__SPFN_INTERCEPTOR_REGISTRY__ = new InterceptorRegistry();\n }\n\n return globalThis.__SPFN_INTERCEPTOR_REGISTRY__;\n})();\n\n/**\n * Register interceptors for a package\n *\n * This should be called during package initialization (on import).\n * The interceptors will be automatically applied by the Next.js proxy.\n *\n * @param packageName - Unique package identifier (e.g., 'auth', 'storage')\n * @param interceptors - Array of interceptor rules\n *\n * @example\n * ```typescript\n * // packages/auth/src/adapters/nextjs/interceptors/index.ts\n * import { registerInterceptors } from '@spfn/core/nextjs';\n *\n * const authInterceptors = [\n * {\n * pathPattern: '/_auth/*',\n * request: async (ctx, next) => {\n * // Add JWT token\n * ctx.headers['Authorization'] = 'Bearer token';\n * await next();\n * }\n * }\n * ];\n *\n * // Auto-register on import\n * registerInterceptors('auth', authInterceptors);\n * ```\n */\nexport function registerInterceptors(\n packageName: string,\n interceptors: InterceptorRule[]\n): void\n{\n interceptorRegistry.register(packageName, interceptors);\n}","/**\n * Helper functions for proxy handler\n * Separates utility logic from main proxy handler for better maintainability\n */\nimport { NextRequest } from 'next/server';\nimport type { CookieOptions, SetCookie } from \"../client\";\nimport type { InterceptorRule, RequestInterceptorContext, ResponseInterceptorContext } from './interceptors/types';\nimport type { InterceptorRegistry } from './interceptors';\n\n// Re-export from shared\nexport { parseResponseBody } from '../shared';\n\n/**\n * Build request headers for proxying\n * Forwards important headers from source and adds default headers\n *\n * @param sourceHeaders - Source headers (can be Headers object or Record)\n * @param defaultHeaders - Default headers to add\n */\nexport function buildProxyHeaders(\n sourceHeaders: Headers | Record<string, string>,\n defaultHeaders: Record<string, string>\n): Headers\n{\n const headers = new Headers();\n\n // Forward important headers from source\n const headersToForward = [\n 'content-type',\n 'authorization',\n 'cookie',\n 'user-agent',\n 'accept',\n 'accept-language',\n ];\n\n for (const header of headersToForward)\n {\n const value = sourceHeaders instanceof Headers\n ? sourceHeaders.get(header)\n : sourceHeaders[header];\n\n if (value)\n {\n headers.set(header, value);\n }\n }\n\n // Add default headers\n for (const [key, value] of Object.entries(defaultHeaders))\n {\n headers.set(key, value);\n }\n\n return headers;\n}\n\n/**\n * Parse cookies from Cookie header string\n *\n * @param cookieHeader - Cookie header string (e.g., \"session=abc; theme=dark\")\n * @returns Map of cookie name-value pairs\n */\nexport function parseCookies(cookieHeader: string | null | undefined): Map<string, string>\n{\n const cookiesMap = new Map<string, string>();\n\n if (!cookieHeader)\n {\n return cookiesMap;\n }\n\n const cookiePairs = cookieHeader.split(';').map(c => c.trim());\n for (const pair of cookiePairs)\n {\n const [name, ...valueParts] = pair.split('=');\n if (name && valueParts.length > 0)\n {\n const value = valueParts.join('='); // Handle = in cookie value\n cookiesMap.set(name.trim(), value.trim());\n }\n }\n\n return cookiesMap;\n}\n\n/**\n * Parse cookies from NextRequest (Next.js specific helper)\n * Combines cookies from both NextRequest.cookies and Cookie header\n */\nexport function parseCookiesFromNextRequest(request: NextRequest): Map<string, string>\n{\n const cookiesMap = new Map<string, string>();\n\n // Add cookies from NextRequest (browser cookies)\n for (const cookie of request.cookies.getAll())\n {\n cookiesMap.set(cookie.name, cookie.value);\n }\n\n // Add cookies from Cookie header (server-side forwarded cookies)\n const cookieHeader = request.headers.get('cookie');\n if (cookieHeader)\n {\n const parsed = parseCookies(cookieHeader);\n for (const [name, value] of parsed.entries())\n {\n cookiesMap.set(name, value);\n }\n }\n\n return cookiesMap;\n}\n\n// Mapping of option names to Set-Cookie attribute formats\nconst optionMappings: Array<{\n key: keyof CookieOptions;\n format: (value: any) => string | null;\n}> = [\n { key: 'httpOnly', format: (v) => v ? 'HttpOnly' : null },\n { key: 'secure', format: (v) => v ? 'Secure' : null },\n { key: 'sameSite', format: (v) => v ? `SameSite=${v}` : null },\n { key: 'maxAge', format: (v) => v !== undefined ? `Max-Age=${v}` : null },\n { key: 'path', format: (v) => v ? `Path=${v}` : null },\n { key: 'domain', format: (v) => v ? `Domain=${v}` : null },\n];\n\n/**\n * Build Set-Cookie header string from cookie options\n */\nexport function buildSetCookieHeader(cookie: SetCookie): string\n{\n const parts = [`${cookie.name}=${cookie.value}`];\n const options = cookie.options || {};\n\n for (const { key, format } of optionMappings)\n {\n const value = options[key];\n if (value !== undefined && value !== false)\n {\n const formatted = format(value);\n if (formatted)\n {\n parts.push(formatted);\n }\n }\n }\n\n return parts.join('; ');\n}\n\n/**\n * Build error response JSON\n */\nexport function buildErrorResponse(\n errorType: string,\n message: string,\n debug: boolean,\n error?: Error\n): any\n{\n return {\n error: errorType,\n message,\n ...(debug && error?.stack && { stack: error.stack }),\n };\n}\n\nconst headersToForward = [\n 'content-type',\n 'cache-control',\n 'set-cookie',\n 'etag',\n 'last-modified',\n];\n\n/**\n * Forward response headers back to client\n */\nexport function forwardResponseHeaders(\n sourceHeaders: Headers,\n targetHeaders: Headers\n): void\n{\n for (const header of headersToForward)\n {\n const value = sourceHeaders.get(header);\n if (value)\n {\n targetHeaders.set(header, value);\n }\n }\n}\n\n/**\n * Collect all interceptors (auto-discovered + config)\n */\nexport function collectInterceptors(\n autoDiscoverInterceptors: boolean,\n disableAutoInterceptors: string[] | undefined,\n configInterceptors: InterceptorRule[] | undefined,\n registry: InterceptorRegistry\n): InterceptorRule[]\n{\n const allInterceptors: InterceptorRule[] = [];\n\n // Auto-discover from registry\n if (autoDiscoverInterceptors)\n {\n const registeredInterceptors = registry.getAll(disableAutoInterceptors || []);\n allInterceptors.push(...registeredInterceptors);\n }\n\n // Add config interceptors\n if (configInterceptors)\n {\n allInterceptors.push(...configInterceptors);\n }\n\n return allInterceptors;\n}\n\n/**\n * Build RequestInterceptorContext\n */\nexport function buildRequestContext(\n path: string,\n method: string,\n headers: Headers,\n body: any,\n searchParams: URLSearchParams,\n cookiesMap: Map<string, string>,\n request: NextRequest\n): RequestInterceptorContext\n{\n return {\n path: `/${path}`,\n method,\n headers: Object.fromEntries(headers.entries()),\n body,\n query: Object.fromEntries(searchParams.entries()),\n cookies: cookiesMap,\n request,\n metadata: {},\n };\n}\n\n/**\n * Build ResponseInterceptorContext\n */\nexport function buildResponseContext(\n path: string,\n method: string,\n requestHeaders: Headers,\n requestBody: any,\n response: Response,\n responseBody: any,\n requestMetadata: Record<string, any>\n): ResponseInterceptorContext\n{\n return {\n path: `/${path}`,\n method,\n request: {\n headers: Object.fromEntries(requestHeaders.entries()),\n body: requestBody,\n },\n response: {\n ok: response.ok,\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n body: responseBody,\n },\n setCookies: [],\n metadata: requestMetadata,\n };\n}","/**\n * RPC-Style Proxy for define-route System\n *\n * Next.js API Route handler that resolves routeName to method/path\n * and forwards requests to SPFN backend.\n *\n * @example Using routeMap (recommended - no server code loaded)\n * ```typescript\n * // app/api/rpc/[routeName]/route.ts\n * import { routeMap } from '@/generated/route-map';\n * import { createRpcProxy } from '@spfn/core/nextjs/proxy';\n *\n * export const { GET, POST } = createRpcProxy({ routeMap });\n * ```\n *\n * @example Using router (legacy - loads full server code)\n * ```typescript\n * // app/api/rpc/[routeName]/route.ts\n * import { appRouter } from '@/server/router';\n * import { createRpcProxy } from '@spfn/core/nextjs/proxy';\n *\n * export const { GET, POST } = createRpcProxy({ router: appRouter });\n * ```\n */\nimport { NextRequest, NextResponse } from 'next/server';\n\nimport { env } from '@spfn/core/config';\nimport { logger } from '@spfn/core/logger';\nimport type { Router, RouteDef, HttpMethod } from '@spfn/core/route';\n\nimport { buildUrlWithParams, buildQueryString } from '../shared';\nimport { interceptorRegistry } from './interceptors';\nimport { executeRequestInterceptors, executeResponseInterceptors, filterMatchingInterceptors } from './interceptors';\nimport {\n buildProxyHeaders,\n parseCookiesFromNextRequest,\n buildSetCookieHeader,\n buildErrorResponse,\n forwardResponseHeaders,\n parseResponseBody,\n collectInterceptors,\n buildRequestContext,\n buildResponseContext,\n} from './helpers';\nimport type { TypedProxyConfig } from \"./types\";\n\nconst rpcLogger = logger.child('@spfn/core:rpc-proxy');\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Route info from generated route map\n */\nexport interface RouteMapEntry\n{\n method: HttpMethod;\n path: string;\n}\n\n/**\n * Generated route map type\n */\nexport type RouteMap = Record<string, RouteMapEntry>;\n\n/**\n * Base config for RPC proxy\n */\ninterface RpcProxyBaseConfig extends Omit<TypedProxyConfig, 'onRequest' | 'onResponse'> {}\n\n/**\n * Config using routeMap (recommended)\n *\n * Uses generated route map file - no server code loaded in Next.js process.\n */\nexport interface RpcProxyRouteMapConfig extends RpcProxyBaseConfig\n{\n /**\n * Generated route map containing routeName → {method, path} mappings\n *\n * @example\n * ```typescript\n * import { routeMap } from '@/generated/route-map';\n *\n * export const { GET, POST } = createRpcProxy({ routeMap });\n * ```\n */\n routeMap: RouteMap;\n router?: never;\n}\n\n/**\n * Config using router (legacy)\n *\n * @deprecated Use routeMap instead to avoid loading server code in Next.js process\n */\nexport interface RpcProxyRouterConfig<TRouter extends Router<any>> extends RpcProxyBaseConfig\n{\n /**\n * The router containing all route definitions\n *\n * @deprecated Use routeMap instead - router imports all server code\n *\n * @example\n * ```typescript\n * export const { GET, POST } = createRpcProxy({\n * router: appRouter,\n * });\n * ```\n */\n router: TRouter;\n routeMap?: never;\n}\n\n/**\n * Combined config type\n */\nexport type RpcProxyConfig<TRouter extends Router<any> = Router<any>> =\n | RpcProxyRouteMapConfig\n | RpcProxyRouterConfig<TRouter>;\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/**\n * Type guard to check if value is a RouteDef\n */\nfunction isRouteDef(value: unknown): value is RouteDef<any>\n{\n return value !== null &&\n typeof value === 'object' &&\n 'handler' in value &&\n 'method' in value &&\n 'path' in value;\n}\n\n/**\n * Type guard to check if value is a Router\n */\nfunction isRouter(value: unknown): value is Router<any>\n{\n return value !== null &&\n typeof value === 'object' &&\n 'routes' in value &&\n '_routes' in value;\n}\n\n/**\n * Get route definition from router by dotted path\n *\n * @example\n * getRouteByPath(router, 'users.getUser') → RouteDef\n * getRouteByPath(router, 'getUser') → RouteDef\n */\nfunction getRouteByPath(router: Router<any>, routePath: string): RouteDef<any> | null\n{\n const parts = routePath.split('.');\n let current: any = router.routes;\n\n for (const part of parts)\n {\n if (!current || typeof current !== 'object')\n {\n return null;\n }\n\n const next = current[part];\n\n if (isRouter(next))\n {\n current = next.routes;\n }\n else if (isRouteDef(next))\n {\n return next;\n }\n else\n {\n current = next;\n }\n }\n\n if (isRouteDef(current))\n {\n return current;\n }\n\n return null;\n}\n\n// ============================================================================\n// RPC Proxy Handler\n// ============================================================================\n\n/**\n * Create RPC proxy handler for Next.js API Route\n *\n * Handles requests in the format:\n * - GET /api/rpc/{routeName}?input={...}\n * - POST /api/rpc/{routeName} with body\n *\n * Resolves routeName to actual HTTP method and path from the router or routeMap,\n * then forwards to SPFN backend.\n */\nexport function createRpcProxy<TRouter extends Router<any>>(config: RpcProxyConfig<TRouter>)\n{\n const {\n apiUrl = env.SPFN_API_URL || 'http://localhost:8790',\n debug = env.NODE_ENV === 'development',\n timeout = 30000,\n headers: defaultHeaders = {},\n interceptors,\n autoDiscoverInterceptors = true,\n disableAutoInterceptors,\n } = config;\n\n // Determine if using routeMap or router\n const useRouteMap = 'routeMap' in config && config.routeMap !== undefined;\n const routeMap = useRouteMap ? config.routeMap : null;\n const router = !useRouteMap && 'router' in config ? config.router : null;\n\n // Get package routers (only when using router mode)\n const packageRouters = router?._packageRouters || [];\n\n /**\n * Resolve route info from routeMap or router\n */\n function resolveRoute(routeName: string): { method: string; path: string } | null\n {\n // Try routeMap first (recommended)\n if (routeMap)\n {\n const entry = routeMap[routeName];\n if (entry)\n {\n return { method: entry.method, path: entry.path };\n }\n return null;\n }\n\n // Fall back to router (legacy)\n if (router)\n {\n let routeDef = getRouteByPath(router, routeName);\n\n // If not found in main router, search in package routers\n if (!routeDef && packageRouters.length > 0)\n {\n for (const pkgRouter of packageRouters)\n {\n routeDef = getRouteByPath(pkgRouter, routeName);\n if (routeDef)\n {\n if (debug)\n {\n rpcLogger.debug(`Route \"${routeName}\" found in package router`);\n }\n break;\n }\n }\n }\n\n if (routeDef && routeDef.method && routeDef.path)\n {\n return { method: routeDef.method, path: routeDef.path };\n }\n }\n\n return null;\n }\n\n /**\n * Handle RPC request\n */\n async function handleRpc(\n request: NextRequest,\n context: { params: Promise<{ routeName?: string }> }\n ): Promise<NextResponse>\n {\n const startTime = Date.now();\n const params = await context.params;\n\n try\n {\n const routeName = params.routeName;\n\n if (!routeName)\n {\n return NextResponse.json(\n buildErrorResponse('Bad Request', 'Missing routeName parameter', debug),\n { status: 400 }\n );\n }\n\n // Parse input from query string (GET) or body (POST)\n let input: {\n params?: Record<string, any>;\n query?: Record<string, any>;\n body?: Record<string, any>;\n formData?: Record<string, any>;\n headers?: Record<string, any>;\n cookies?: Record<string, any>;\n } = {};\n let rawFormData: FormData | null = null;\n\n if (request.method === 'GET')\n {\n const inputParam = request.nextUrl.searchParams.get('input');\n if (inputParam)\n {\n try\n {\n input = JSON.parse(decodeURIComponent(inputParam));\n }\n catch\n {\n return NextResponse.json(\n buildErrorResponse('Bad Request', 'Invalid input parameter', debug),\n { status: 400 }\n );\n }\n }\n }\n else\n {\n // POST - check Content-Type for formData vs JSON\n const contentType = request.headers.get('content-type') || '';\n\n if (contentType.includes('multipart/form-data'))\n {\n // Parse multipart/form-data\n try\n {\n rawFormData = await request.formData();\n\n // Extract __metadata if present (contains params, query, etc.)\n const metadataStr = rawFormData.get('__metadata');\n if (metadataStr && typeof metadataStr === 'string')\n {\n const metadata = JSON.parse(metadataStr);\n input.params = metadata.params;\n input.query = metadata.query;\n input.headers = metadata.headers;\n input.cookies = metadata.cookies;\n }\n\n // Collect formData fields (excluding __metadata)\n input.formData = {};\n rawFormData.forEach((value, key) =>\n {\n if (key === '__metadata') return;\n\n const existing = input.formData![key];\n if (existing !== undefined)\n {\n // Multiple values with same key\n if (Array.isArray(existing))\n {\n existing.push(value);\n }\n else\n {\n input.formData![key] = [existing, value];\n }\n }\n else\n {\n input.formData![key] = value;\n }\n });\n }\n catch (error)\n {\n return NextResponse.json(\n buildErrorResponse('Bad Request', 'Invalid form data', debug),\n { status: 400 }\n );\n }\n }\n else\n {\n // Parse JSON body\n try\n {\n input = await request.json();\n }\n catch\n {\n return NextResponse.json(\n buildErrorResponse('Bad Request', 'Invalid JSON body', debug),\n { status: 400 }\n );\n }\n }\n }\n\n // Resolve route info from routeMap or router\n const routeInfo = resolveRoute(routeName);\n\n if (!routeInfo)\n {\n rpcLogger.warn(`Route not found: ${routeName}`);\n return NextResponse.json(\n buildErrorResponse('Not Found', `Route \"${routeName}\" not found`, debug),\n { status: 404 }\n );\n }\n\n const { method: targetMethod, path: targetPath } = routeInfo;\n\n // Build target URL with params and query\n const inputParams = input.params || {};\n const inputQuery = input.query || {};\n const inputBody = input.body;\n const inputFormData = input.formData;\n const hasFormData = rawFormData !== null && inputFormData && Object.keys(inputFormData).length > 0;\n\n const resolvedPath = buildUrlWithParams(targetPath, inputParams);\n const queryString = buildQueryString(inputQuery);\n const targetUrl = `${apiUrl}${resolvedPath}${queryString}`;\n\n if (debug)\n {\n rpcLogger.debug('→ RPC request', {\n routeName,\n targetMethod,\n targetPath: resolvedPath,\n targetUrl,\n hasBody: !!inputBody,\n hasFormData,\n });\n }\n\n // Build headers\n const headers = buildProxyHeaders(request.headers, defaultHeaders);\n\n // Remove Content-Type for formData (let fetch set it with boundary)\n if (hasFormData)\n {\n headers.delete('content-type');\n }\n\n // Build fetch options\n const fetchOptions: RequestInit = {\n method: targetMethod,\n headers,\n };\n\n // Add body for POST/PUT/PATCH\n if (['POST', 'PUT', 'PATCH'].includes(targetMethod))\n {\n if (hasFormData && rawFormData)\n {\n // Forward formData to backend (rebuild without __metadata)\n const forwardFormData = new FormData();\n rawFormData.forEach((value, key) =>\n {\n if (key !== '__metadata')\n {\n forwardFormData.append(key, value);\n }\n });\n fetchOptions.body = forwardFormData;\n }\n else if (inputBody)\n {\n fetchOptions.body = JSON.stringify(inputBody);\n }\n }\n\n // ============================================================\n // Advanced Interceptors - BEFORE FETCH\n // ============================================================\n\n // Collect and filter interceptors\n const allInterceptors = collectInterceptors(autoDiscoverInterceptors, disableAutoInterceptors, interceptors, interceptorRegistry);\n const matchingInterceptors = filterMatchingInterceptors(allInterceptors, resolvedPath, targetMethod);\n\n if (debug && matchingInterceptors.length > 0)\n {\n rpcLogger.debug(`🎯 Found ${matchingInterceptors.length} matching interceptors for ${targetMethod} ${resolvedPath}`);\n }\n\n // Create RequestInterceptorContext\n const cookiesMap = parseCookiesFromNextRequest(request);\n const requestCtx = buildRequestContext(\n resolvedPath.slice(1), // Remove leading slash\n targetMethod,\n headers,\n inputBody,\n new URLSearchParams(queryString.slice(1)), // Remove leading ?\n cookiesMap,\n request\n );\n\n // Execute request interceptors\n const requestInterceptorsToRun = matchingInterceptors.map(r => r.request).filter((i): i is NonNullable<typeof i> => !!i);\n if (requestInterceptorsToRun.length > 0)\n {\n await executeRequestInterceptors(requestCtx, requestInterceptorsToRun);\n\n // Apply modified headers\n for (const [key, value] of Object.entries(requestCtx.headers))\n {\n headers.set(key, value);\n }\n\n // Apply modified body\n if (requestCtx.body)\n {\n fetchOptions.body = JSON.stringify(requestCtx.body);\n }\n }\n\n // Execute fetch with timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeout);\n\n try\n {\n const response = await fetch(targetUrl, {\n ...fetchOptions,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n let body = await parseResponseBody(response);\n\n // ============================================================\n // Advanced Interceptors - AFTER FETCH\n // ============================================================\n\n // Create ResponseInterceptorContext\n const responseCtx = buildResponseContext(\n resolvedPath.slice(1),\n targetMethod,\n headers,\n inputBody,\n response,\n body,\n requestCtx.metadata\n );\n\n // Execute response interceptors\n const responseInterceptorsToRun = matchingInterceptors.map(r => r.response).filter((i): i is NonNullable<typeof i> => !!i);\n if (responseInterceptorsToRun.length > 0)\n {\n await executeResponseInterceptors(responseCtx, responseInterceptorsToRun);\n body = responseCtx.response.body;\n }\n\n const duration = Date.now() - startTime;\n\n if (debug)\n {\n rpcLogger.debug('← RPC response', {\n routeName,\n status: responseCtx.response.status,\n duration: `${duration}ms`,\n });\n }\n\n // Build Next.js response\n // 204 No Content should use NextResponse directly, not NextResponse.json()\n const nextResponse = responseCtx.response.status === 204\n ? new NextResponse(null, {\n status: 204,\n statusText: responseCtx.response.statusText,\n })\n : NextResponse.json(body, {\n status: responseCtx.response.status,\n statusText: responseCtx.response.statusText,\n });\n\n // Forward response headers\n forwardResponseHeaders(response.headers, nextResponse.headers);\n\n // Apply setCookies from interceptors\n for (const cookie of responseCtx.setCookies)\n {\n const setCookieHeader = buildSetCookieHeader(cookie);\n nextResponse.headers.append('Set-Cookie', setCookieHeader);\n\n if (debug)\n {\n rpcLogger.debug('🍪 Set-Cookie header added', {\n name: cookie.name,\n });\n }\n }\n\n return nextResponse;\n }\n catch (error)\n {\n clearTimeout(timeoutId);\n\n // Handle timeout\n if (error instanceof Error && error.name === 'AbortError')\n {\n rpcLogger.error('Request timeout', {\n routeName,\n targetUrl,\n timeout,\n });\n\n return NextResponse.json(\n buildErrorResponse('Gateway Timeout', `Request timed out after ${timeout}ms`, debug, error),\n { status: 504 }\n );\n }\n\n // Handle other fetch errors\n const fetchErr = error as Error;\n rpcLogger.error('Fetch error', {\n routeName,\n targetUrl,\n error: fetchErr.message,\n });\n\n return NextResponse.json(\n buildErrorResponse('Bad Gateway', fetchErr.message || 'Failed to connect to backend', debug, fetchErr),\n { status: 502 }\n );\n }\n }\n catch (error)\n {\n const duration = Date.now() - startTime;\n const err = error as Error;\n\n rpcLogger.error('RPC proxy error', {\n error: err.message,\n stack: err.stack,\n duration: `${duration}ms`,\n });\n\n return NextResponse.json(\n buildErrorResponse('Internal Server Error', err.message || 'Unknown error', debug, err),\n { status: 500 }\n );\n }\n }\n\n // Return route handlers\n return {\n GET: (req: NextRequest, context: { params: Promise<{ routeName?: string }> }) =>\n handleRpc(req, context),\n POST: (req: NextRequest, context: { params: Promise<{ routeName?: string }> }) =>\n handleRpc(req, context),\n };\n}"]}