@spfn/core 0.1.0-alpha.88 → 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 (97) hide show
  1. package/README.md +298 -466
  2. package/dist/boss-DI1r4kTS.d.ts +244 -0
  3. package/dist/cache/index.d.ts +13 -33
  4. package/dist/cache/index.js +14 -703
  5. package/dist/cache/index.js.map +1 -1
  6. package/dist/codegen/index.d.ts +214 -17
  7. package/dist/codegen/index.js +231 -1420
  8. package/dist/codegen/index.js.map +1 -1
  9. package/dist/config/index.d.ts +1227 -0
  10. package/dist/config/index.js +273 -0
  11. package/dist/config/index.js.map +1 -0
  12. package/dist/db/index.d.ts +741 -59
  13. package/dist/db/index.js +1063 -1226
  14. package/dist/db/index.js.map +1 -1
  15. package/dist/env/index.d.ts +658 -308
  16. package/dist/env/index.js +503 -928
  17. package/dist/env/index.js.map +1 -1
  18. package/dist/env/loader.d.ts +87 -0
  19. package/dist/env/loader.js +70 -0
  20. package/dist/env/loader.js.map +1 -0
  21. package/dist/errors/index.d.ts +417 -29
  22. package/dist/errors/index.js +359 -98
  23. package/dist/errors/index.js.map +1 -1
  24. package/dist/event/index.d.ts +41 -0
  25. package/dist/event/index.js +131 -0
  26. package/dist/event/index.js.map +1 -0
  27. package/dist/event/sse/client.d.ts +82 -0
  28. package/dist/event/sse/client.js +115 -0
  29. package/dist/event/sse/client.js.map +1 -0
  30. package/dist/event/sse/index.d.ts +40 -0
  31. package/dist/event/sse/index.js +92 -0
  32. package/dist/event/sse/index.js.map +1 -0
  33. package/dist/job/index.d.ts +218 -0
  34. package/dist/job/index.js +410 -0
  35. package/dist/job/index.js.map +1 -0
  36. package/dist/logger/index.d.ts +20 -79
  37. package/dist/logger/index.js +82 -387
  38. package/dist/logger/index.js.map +1 -1
  39. package/dist/middleware/index.d.ts +102 -20
  40. package/dist/middleware/index.js +51 -705
  41. package/dist/middleware/index.js.map +1 -1
  42. package/dist/nextjs/index.d.ts +120 -0
  43. package/dist/nextjs/index.js +448 -0
  44. package/dist/nextjs/index.js.map +1 -0
  45. package/dist/{client/nextjs/index.d.ts → nextjs/server.d.ts} +335 -262
  46. package/dist/nextjs/server.js +637 -0
  47. package/dist/nextjs/server.js.map +1 -0
  48. package/dist/route/index.d.ts +879 -25
  49. package/dist/route/index.js +697 -1271
  50. package/dist/route/index.js.map +1 -1
  51. package/dist/route/types.d.ts +9 -0
  52. package/dist/route/types.js +3 -0
  53. package/dist/route/types.js.map +1 -0
  54. package/dist/router-Di7ENoah.d.ts +151 -0
  55. package/dist/server/index.d.ts +345 -64
  56. package/dist/server/index.js +1174 -3233
  57. package/dist/server/index.js.map +1 -1
  58. package/dist/types-B-e_f2dQ.d.ts +121 -0
  59. package/dist/types-BGl4QL1w.d.ts +77 -0
  60. package/dist/types-BOPTApC2.d.ts +245 -0
  61. package/docs/cache.md +133 -0
  62. package/docs/codegen.md +74 -0
  63. package/docs/database.md +346 -0
  64. package/docs/entity.md +539 -0
  65. package/docs/env.md +477 -0
  66. package/docs/errors.md +319 -0
  67. package/docs/event.md +116 -0
  68. package/docs/file-upload.md +717 -0
  69. package/docs/job.md +131 -0
  70. package/docs/logger.md +108 -0
  71. package/docs/middleware.md +337 -0
  72. package/docs/nextjs.md +241 -0
  73. package/docs/repository.md +496 -0
  74. package/docs/route.md +497 -0
  75. package/docs/server.md +307 -0
  76. package/package.json +68 -48
  77. package/dist/auto-loader-JFaZ9gON.d.ts +0 -80
  78. package/dist/client/index.d.ts +0 -358
  79. package/dist/client/index.js +0 -357
  80. package/dist/client/index.js.map +0 -1
  81. package/dist/client/nextjs/index.js +0 -371
  82. package/dist/client/nextjs/index.js.map +0 -1
  83. package/dist/codegen/generators/index.d.ts +0 -19
  84. package/dist/codegen/generators/index.js +0 -1404
  85. package/dist/codegen/generators/index.js.map +0 -1
  86. package/dist/database-errors-BNNmLTJE.d.ts +0 -86
  87. package/dist/events/index.d.ts +0 -183
  88. package/dist/events/index.js +0 -77
  89. package/dist/events/index.js.map +0 -1
  90. package/dist/index-DHiAqhKv.d.ts +0 -101
  91. package/dist/index.d.ts +0 -8
  92. package/dist/index.js +0 -3674
  93. package/dist/index.js.map +0 -1
  94. package/dist/types/index.d.ts +0 -121
  95. package/dist/types/index.js +0 -38
  96. package/dist/types/index.js.map +0 -1
  97. package/dist/types-BXibIEyj.d.ts +0 -60
@@ -0,0 +1,637 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { env } from '@spfn/core/config';
3
+ import { logger } from '@spfn/core/logger';
4
+
5
+ // src/nextjs/proxy/rpc.ts
6
+
7
+ // src/nextjs/shared.ts
8
+ function buildUrlWithParams(path, params) {
9
+ let url = path;
10
+ for (const [key, value] of Object.entries(params)) {
11
+ url = url.replace(`:${key}`, encodeURIComponent(String(value)));
12
+ }
13
+ return url;
14
+ }
15
+ function buildQueryString(query) {
16
+ if (Object.keys(query).length === 0) {
17
+ return "";
18
+ }
19
+ const searchParams = new URLSearchParams();
20
+ for (const [key, value] of Object.entries(query)) {
21
+ if (Array.isArray(value)) {
22
+ value.forEach((v) => searchParams.append(key, String(v)));
23
+ } else {
24
+ searchParams.append(key, String(value));
25
+ }
26
+ }
27
+ return `?${searchParams.toString()}`;
28
+ }
29
+ async function parseResponseBody(response) {
30
+ if (response.status === 204) {
31
+ return null;
32
+ }
33
+ const contentType = response.headers.get("content-type");
34
+ if (contentType?.includes("application/json")) {
35
+ const text = await response.text();
36
+ return text ? JSON.parse(text) : null;
37
+ } else {
38
+ return await response.text();
39
+ }
40
+ }
41
+
42
+ // src/nextjs/proxy/interceptors/helpers.ts
43
+ function matchPath(path, pattern) {
44
+ if (pattern === "*") {
45
+ return true;
46
+ }
47
+ if (pattern instanceof RegExp) {
48
+ return pattern.test(path);
49
+ }
50
+ const regexPattern = pattern.replace(/\*/g, ".*").replace(/:[^/]+/g, "[^/]+").replace(/\//g, "\\/");
51
+ const regex = new RegExp(`^${regexPattern}$`);
52
+ return regex.test(path);
53
+ }
54
+ function matchMethod(method, pattern) {
55
+ if (!pattern) {
56
+ return true;
57
+ }
58
+ if (typeof pattern === "string") {
59
+ return method.toUpperCase() === pattern.toUpperCase();
60
+ }
61
+ return pattern.some((m) => m.toUpperCase() === method.toUpperCase());
62
+ }
63
+ function filterMatchingInterceptors(rules, path, method) {
64
+ return rules.filter((rule) => {
65
+ return matchPath(path, rule.pathPattern) && matchMethod(method, rule.method);
66
+ });
67
+ }
68
+ async function executeRequestInterceptors(context, interceptors) {
69
+ let index = 0;
70
+ const next = async () => {
71
+ if (index >= interceptors.length) {
72
+ return;
73
+ }
74
+ const interceptor = interceptors[index];
75
+ index++;
76
+ await interceptor(context, next);
77
+ };
78
+ await next();
79
+ }
80
+ async function executeResponseInterceptors(context, interceptors) {
81
+ let index = 0;
82
+ const next = async () => {
83
+ if (index >= interceptors.length) {
84
+ return;
85
+ }
86
+ const interceptor = interceptors[index];
87
+ index++;
88
+ await interceptor(context, next);
89
+ };
90
+ await next();
91
+ }
92
+
93
+ // src/nextjs/proxy/interceptors/registry.ts
94
+ var InterceptorRegistry = class {
95
+ interceptors = /* @__PURE__ */ new Map();
96
+ /**
97
+ * Register interceptors for a package
98
+ *
99
+ * @param packageName - Unique package identifier (e.g., 'auth', 'storage')
100
+ * @param interceptors - Array of interceptor rules
101
+ *
102
+ * @example
103
+ * ```typescript
104
+ * registerInterceptors('auth', [
105
+ * {
106
+ * pathPattern: '/_auth/*',
107
+ * request: async (ctx, next) => { ... }
108
+ * }
109
+ * ]);
110
+ * ```
111
+ */
112
+ register(packageName, interceptors) {
113
+ if (!this.interceptors.has(packageName)) {
114
+ this.interceptors.set(packageName, interceptors);
115
+ }
116
+ }
117
+ /**
118
+ * Get all registered interceptors
119
+ *
120
+ * @param exclude - Package names to exclude
121
+ * @returns Flat array of all interceptor rules
122
+ */
123
+ getAll(exclude = []) {
124
+ const all = [];
125
+ for (const [packageName, interceptors] of this.interceptors.entries()) {
126
+ if (!exclude.includes(packageName)) {
127
+ all.push(...interceptors);
128
+ }
129
+ }
130
+ return all;
131
+ }
132
+ /**
133
+ * Get interceptors for specific package
134
+ *
135
+ * @param packageName - Package identifier
136
+ * @returns Interceptor rules or undefined
137
+ */
138
+ get(packageName) {
139
+ return this.interceptors.get(packageName);
140
+ }
141
+ /**
142
+ * Get list of registered package names
143
+ */
144
+ getPackageNames() {
145
+ return Array.from(this.interceptors.keys());
146
+ }
147
+ /**
148
+ * Check if package has registered interceptors
149
+ */
150
+ has(packageName) {
151
+ return this.interceptors.has(packageName);
152
+ }
153
+ /**
154
+ * Unregister interceptors for a package
155
+ *
156
+ * @param packageName - Package identifier
157
+ */
158
+ unregister(packageName) {
159
+ this.interceptors.delete(packageName);
160
+ }
161
+ /**
162
+ * Clear all registered interceptors
163
+ *
164
+ * Useful for testing
165
+ */
166
+ clear() {
167
+ this.interceptors.clear();
168
+ }
169
+ /**
170
+ * Get total count of registered interceptors
171
+ */
172
+ count() {
173
+ let total = 0;
174
+ for (const interceptors of this.interceptors.values()) {
175
+ total += interceptors.length;
176
+ }
177
+ return total;
178
+ }
179
+ };
180
+ var interceptorRegistry = (() => {
181
+ if (!globalThis.__SPFN_INTERCEPTOR_REGISTRY__) {
182
+ globalThis.__SPFN_INTERCEPTOR_REGISTRY__ = new InterceptorRegistry();
183
+ }
184
+ return globalThis.__SPFN_INTERCEPTOR_REGISTRY__;
185
+ })();
186
+ function registerInterceptors(packageName, interceptors) {
187
+ interceptorRegistry.register(packageName, interceptors);
188
+ }
189
+
190
+ // src/nextjs/proxy/helpers.ts
191
+ function buildProxyHeaders(sourceHeaders, defaultHeaders) {
192
+ const headers = new Headers();
193
+ const headersToForward2 = [
194
+ "content-type",
195
+ "authorization",
196
+ "cookie",
197
+ "user-agent",
198
+ "accept",
199
+ "accept-language"
200
+ ];
201
+ for (const header of headersToForward2) {
202
+ const value = sourceHeaders instanceof Headers ? sourceHeaders.get(header) : sourceHeaders[header];
203
+ if (value) {
204
+ headers.set(header, value);
205
+ }
206
+ }
207
+ for (const [key, value] of Object.entries(defaultHeaders)) {
208
+ headers.set(key, value);
209
+ }
210
+ return headers;
211
+ }
212
+ function parseCookies(cookieHeader) {
213
+ const cookiesMap = /* @__PURE__ */ new Map();
214
+ if (!cookieHeader) {
215
+ return cookiesMap;
216
+ }
217
+ const cookiePairs = cookieHeader.split(";").map((c) => c.trim());
218
+ for (const pair of cookiePairs) {
219
+ const [name, ...valueParts] = pair.split("=");
220
+ if (name && valueParts.length > 0) {
221
+ const value = valueParts.join("=");
222
+ cookiesMap.set(name.trim(), value.trim());
223
+ }
224
+ }
225
+ return cookiesMap;
226
+ }
227
+ function parseCookiesFromNextRequest(request) {
228
+ const cookiesMap = /* @__PURE__ */ new Map();
229
+ for (const cookie of request.cookies.getAll()) {
230
+ cookiesMap.set(cookie.name, cookie.value);
231
+ }
232
+ const cookieHeader = request.headers.get("cookie");
233
+ if (cookieHeader) {
234
+ const parsed = parseCookies(cookieHeader);
235
+ for (const [name, value] of parsed.entries()) {
236
+ cookiesMap.set(name, value);
237
+ }
238
+ }
239
+ return cookiesMap;
240
+ }
241
+ var optionMappings = [
242
+ { key: "httpOnly", format: (v) => v ? "HttpOnly" : null },
243
+ { key: "secure", format: (v) => v ? "Secure" : null },
244
+ { key: "sameSite", format: (v) => v ? `SameSite=${v}` : null },
245
+ { key: "maxAge", format: (v) => v !== void 0 ? `Max-Age=${v}` : null },
246
+ { key: "path", format: (v) => v ? `Path=${v}` : null },
247
+ { key: "domain", format: (v) => v ? `Domain=${v}` : null }
248
+ ];
249
+ function buildSetCookieHeader(cookie) {
250
+ const parts = [`${cookie.name}=${cookie.value}`];
251
+ const options = cookie.options || {};
252
+ for (const { key, format } of optionMappings) {
253
+ const value = options[key];
254
+ if (value !== void 0 && value !== false) {
255
+ const formatted = format(value);
256
+ if (formatted) {
257
+ parts.push(formatted);
258
+ }
259
+ }
260
+ }
261
+ return parts.join("; ");
262
+ }
263
+ function buildErrorResponse(errorType, message, debug, error) {
264
+ return {
265
+ error: errorType,
266
+ message,
267
+ ...debug && error?.stack && { stack: error.stack }
268
+ };
269
+ }
270
+ var headersToForward = [
271
+ "content-type",
272
+ "cache-control",
273
+ "set-cookie",
274
+ "etag",
275
+ "last-modified"
276
+ ];
277
+ function forwardResponseHeaders(sourceHeaders, targetHeaders) {
278
+ for (const header of headersToForward) {
279
+ const value = sourceHeaders.get(header);
280
+ if (value) {
281
+ targetHeaders.set(header, value);
282
+ }
283
+ }
284
+ }
285
+ function collectInterceptors(autoDiscoverInterceptors, disableAutoInterceptors, configInterceptors, registry) {
286
+ const allInterceptors = [];
287
+ if (autoDiscoverInterceptors) {
288
+ const registeredInterceptors = registry.getAll(disableAutoInterceptors || []);
289
+ allInterceptors.push(...registeredInterceptors);
290
+ }
291
+ if (configInterceptors) {
292
+ allInterceptors.push(...configInterceptors);
293
+ }
294
+ return allInterceptors;
295
+ }
296
+ function buildRequestContext(path, method, headers, body, searchParams, cookiesMap, request) {
297
+ return {
298
+ path: `/${path}`,
299
+ method,
300
+ headers: Object.fromEntries(headers.entries()),
301
+ body,
302
+ query: Object.fromEntries(searchParams.entries()),
303
+ cookies: cookiesMap,
304
+ request,
305
+ metadata: {}
306
+ };
307
+ }
308
+ function buildResponseContext(path, method, requestHeaders, requestBody, response, responseBody, requestMetadata) {
309
+ return {
310
+ path: `/${path}`,
311
+ method,
312
+ request: {
313
+ headers: Object.fromEntries(requestHeaders.entries()),
314
+ body: requestBody
315
+ },
316
+ response: {
317
+ ok: response.ok,
318
+ status: response.status,
319
+ statusText: response.statusText,
320
+ headers: response.headers,
321
+ body: responseBody
322
+ },
323
+ setCookies: [],
324
+ metadata: requestMetadata
325
+ };
326
+ }
327
+
328
+ // src/nextjs/proxy/rpc.ts
329
+ var rpcLogger = logger.child("@spfn/core:rpc-proxy");
330
+ function isRouteDef(value) {
331
+ return value !== null && typeof value === "object" && "handler" in value && "method" in value && "path" in value;
332
+ }
333
+ function isRouter(value) {
334
+ return value !== null && typeof value === "object" && "routes" in value && "_routes" in value;
335
+ }
336
+ function getRouteByPath(router, routePath) {
337
+ const parts = routePath.split(".");
338
+ let current = router.routes;
339
+ for (const part of parts) {
340
+ if (!current || typeof current !== "object") {
341
+ return null;
342
+ }
343
+ const next = current[part];
344
+ if (isRouter(next)) {
345
+ current = next.routes;
346
+ } else if (isRouteDef(next)) {
347
+ return next;
348
+ } else {
349
+ current = next;
350
+ }
351
+ }
352
+ if (isRouteDef(current)) {
353
+ return current;
354
+ }
355
+ return null;
356
+ }
357
+ function createRpcProxy(config) {
358
+ const {
359
+ apiUrl = env.SPFN_API_URL || "http://localhost:8790",
360
+ debug = env.NODE_ENV === "development",
361
+ timeout = 3e4,
362
+ headers: defaultHeaders = {},
363
+ interceptors,
364
+ autoDiscoverInterceptors = true,
365
+ disableAutoInterceptors
366
+ } = config;
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
+ }
398
+ async function handleRpc(request, context) {
399
+ const startTime = Date.now();
400
+ const params = await context.params;
401
+ try {
402
+ const routeName = params.routeName;
403
+ if (!routeName) {
404
+ return NextResponse.json(
405
+ buildErrorResponse("Bad Request", "Missing routeName parameter", debug),
406
+ { status: 400 }
407
+ );
408
+ }
409
+ let input = {};
410
+ let rawFormData = null;
411
+ if (request.method === "GET") {
412
+ const inputParam = request.nextUrl.searchParams.get("input");
413
+ if (inputParam) {
414
+ try {
415
+ input = JSON.parse(decodeURIComponent(inputParam));
416
+ } catch {
417
+ return NextResponse.json(
418
+ buildErrorResponse("Bad Request", "Invalid input parameter", debug),
419
+ { status: 400 }
420
+ );
421
+ }
422
+ }
423
+ } else {
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;
435
+ }
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
+ );
464
+ }
465
+ }
466
+ }
467
+ const routeInfo = resolveRoute(routeName);
468
+ if (!routeInfo) {
469
+ rpcLogger.warn(`Route not found: ${routeName}`);
470
+ return NextResponse.json(
471
+ buildErrorResponse("Not Found", `Route "${routeName}" not found`, debug),
472
+ { status: 404 }
473
+ );
474
+ }
475
+ const { method: targetMethod, path: targetPath } = routeInfo;
476
+ const inputParams = input.params || {};
477
+ const inputQuery = input.query || {};
478
+ const inputBody = input.body;
479
+ const inputFormData = input.formData;
480
+ const hasFormData = rawFormData !== null && inputFormData && Object.keys(inputFormData).length > 0;
481
+ const resolvedPath = buildUrlWithParams(targetPath, inputParams);
482
+ const queryString = buildQueryString(inputQuery);
483
+ const targetUrl = `${apiUrl}${resolvedPath}${queryString}`;
484
+ if (debug) {
485
+ rpcLogger.debug("\u2192 RPC request", {
486
+ routeName,
487
+ targetMethod,
488
+ targetPath: resolvedPath,
489
+ targetUrl,
490
+ hasBody: !!inputBody,
491
+ hasFormData
492
+ });
493
+ }
494
+ const headers = buildProxyHeaders(request.headers, defaultHeaders);
495
+ if (hasFormData) {
496
+ headers.delete("content-type");
497
+ }
498
+ const fetchOptions = {
499
+ method: targetMethod,
500
+ headers
501
+ };
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
+ }
514
+ }
515
+ const allInterceptors = collectInterceptors(autoDiscoverInterceptors, disableAutoInterceptors, interceptors, interceptorRegistry);
516
+ const matchingInterceptors = filterMatchingInterceptors(allInterceptors, resolvedPath, targetMethod);
517
+ if (debug && matchingInterceptors.length > 0) {
518
+ rpcLogger.debug(`\u{1F3AF} Found ${matchingInterceptors.length} matching interceptors for ${targetMethod} ${resolvedPath}`);
519
+ }
520
+ const cookiesMap = parseCookiesFromNextRequest(request);
521
+ const requestCtx = buildRequestContext(
522
+ resolvedPath.slice(1),
523
+ // Remove leading slash
524
+ targetMethod,
525
+ headers,
526
+ inputBody,
527
+ new URLSearchParams(queryString.slice(1)),
528
+ // Remove leading ?
529
+ cookiesMap,
530
+ request
531
+ );
532
+ const requestInterceptorsToRun = matchingInterceptors.map((r) => r.request).filter((i) => !!i);
533
+ if (requestInterceptorsToRun.length > 0) {
534
+ await executeRequestInterceptors(requestCtx, requestInterceptorsToRun);
535
+ for (const [key, value] of Object.entries(requestCtx.headers)) {
536
+ headers.set(key, value);
537
+ }
538
+ if (requestCtx.body) {
539
+ fetchOptions.body = JSON.stringify(requestCtx.body);
540
+ }
541
+ }
542
+ const controller = new AbortController();
543
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
544
+ try {
545
+ const response = await fetch(targetUrl, {
546
+ ...fetchOptions,
547
+ signal: controller.signal
548
+ });
549
+ clearTimeout(timeoutId);
550
+ let body = await parseResponseBody(response);
551
+ const responseCtx = buildResponseContext(
552
+ resolvedPath.slice(1),
553
+ targetMethod,
554
+ headers,
555
+ inputBody,
556
+ response,
557
+ body,
558
+ requestCtx.metadata
559
+ );
560
+ const responseInterceptorsToRun = matchingInterceptors.map((r) => r.response).filter((i) => !!i);
561
+ if (responseInterceptorsToRun.length > 0) {
562
+ await executeResponseInterceptors(responseCtx, responseInterceptorsToRun);
563
+ body = responseCtx.response.body;
564
+ }
565
+ const duration = Date.now() - startTime;
566
+ if (debug) {
567
+ rpcLogger.debug("\u2190 RPC response", {
568
+ routeName,
569
+ status: responseCtx.response.status,
570
+ duration: `${duration}ms`
571
+ });
572
+ }
573
+ const nextResponse = responseCtx.response.status === 204 ? new NextResponse(null, {
574
+ status: 204,
575
+ statusText: responseCtx.response.statusText
576
+ }) : NextResponse.json(body, {
577
+ status: responseCtx.response.status,
578
+ statusText: responseCtx.response.statusText
579
+ });
580
+ forwardResponseHeaders(response.headers, nextResponse.headers);
581
+ for (const cookie of responseCtx.setCookies) {
582
+ const setCookieHeader = buildSetCookieHeader(cookie);
583
+ nextResponse.headers.append("Set-Cookie", setCookieHeader);
584
+ if (debug) {
585
+ rpcLogger.debug("\u{1F36A} Set-Cookie header added", {
586
+ name: cookie.name
587
+ });
588
+ }
589
+ }
590
+ return nextResponse;
591
+ } catch (error) {
592
+ clearTimeout(timeoutId);
593
+ if (error instanceof Error && error.name === "AbortError") {
594
+ rpcLogger.error("Request timeout", {
595
+ routeName,
596
+ targetUrl,
597
+ timeout
598
+ });
599
+ return NextResponse.json(
600
+ buildErrorResponse("Gateway Timeout", `Request timed out after ${timeout}ms`, debug, error),
601
+ { status: 504 }
602
+ );
603
+ }
604
+ const fetchErr = error;
605
+ rpcLogger.error("Fetch error", {
606
+ routeName,
607
+ targetUrl,
608
+ error: fetchErr.message
609
+ });
610
+ return NextResponse.json(
611
+ buildErrorResponse("Bad Gateway", fetchErr.message || "Failed to connect to backend", debug, fetchErr),
612
+ { status: 502 }
613
+ );
614
+ }
615
+ } catch (error) {
616
+ const duration = Date.now() - startTime;
617
+ const err = error;
618
+ rpcLogger.error("RPC proxy error", {
619
+ error: err.message,
620
+ stack: err.stack,
621
+ duration: `${duration}ms`
622
+ });
623
+ return NextResponse.json(
624
+ buildErrorResponse("Internal Server Error", err.message || "Unknown error", debug, err),
625
+ { status: 500 }
626
+ );
627
+ }
628
+ }
629
+ return {
630
+ GET: (req, context) => handleRpc(req, context),
631
+ POST: (req, context) => handleRpc(req, context)
632
+ };
633
+ }
634
+
635
+ export { createRpcProxy, executeRequestInterceptors, executeResponseInterceptors, filterMatchingInterceptors, interceptorRegistry, matchMethod, matchPath, registerInterceptors };
636
+ //# sourceMappingURL=server.js.map
637
+ //# sourceMappingURL=server.js.map