@spfn/core 0.2.0-beta.6 → 0.2.0-beta.64
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +181 -1281
- package/dist/authz/index.d.ts +34 -0
- package/dist/authz/index.js +415 -0
- package/dist/authz/index.js.map +1 -0
- package/dist/{boss-DI1r4kTS.d.ts → boss-gXhgctn6.d.ts} +40 -0
- package/dist/cache/index.js +42 -30
- package/dist/cache/index.js.map +1 -1
- package/dist/codegen/index.d.ts +55 -8
- package/dist/codegen/index.js +183 -7
- package/dist/codegen/index.js.map +1 -1
- package/dist/config/index.d.ts +585 -6
- package/dist/config/index.js +116 -5
- package/dist/config/index.js.map +1 -1
- package/dist/db/index.d.ts +270 -4
- package/dist/db/index.js +404 -60
- package/dist/db/index.js.map +1 -1
- package/dist/define-middleware-DuXD8Hvu.d.ts +167 -0
- package/dist/env/index.d.ts +26 -2
- package/dist/env/index.js +15 -5
- package/dist/env/index.js.map +1 -1
- package/dist/env/loader.d.ts +26 -19
- package/dist/env/loader.js +32 -25
- package/dist/env/loader.js.map +1 -1
- package/dist/errors/index.d.ts +10 -0
- package/dist/errors/index.js +20 -2
- package/dist/errors/index.js.map +1 -1
- package/dist/event/index.d.ts +33 -3
- package/dist/event/index.js +24 -3
- package/dist/event/index.js.map +1 -1
- package/dist/event/sse/client.d.ts +42 -3
- package/dist/event/sse/client.js +128 -45
- package/dist/event/sse/client.js.map +1 -1
- package/dist/event/sse/index.d.ts +12 -5
- package/dist/event/sse/index.js +271 -32
- package/dist/event/sse/index.js.map +1 -1
- package/dist/event/ws/client.d.ts +59 -0
- package/dist/event/ws/client.js +273 -0
- package/dist/event/ws/client.js.map +1 -0
- package/dist/event/ws/index.d.ts +94 -0
- package/dist/event/ws/index.js +272 -0
- package/dist/event/ws/index.js.map +1 -0
- package/dist/job/index.d.ts +2 -2
- package/dist/job/index.js +155 -42
- package/dist/job/index.js.map +1 -1
- package/dist/logger/index.d.ts +5 -0
- package/dist/logger/index.js +14 -0
- package/dist/logger/index.js.map +1 -1
- package/dist/middleware/index.d.ts +243 -2
- package/dist/middleware/index.js +1323 -13
- package/dist/middleware/index.js.map +1 -1
- package/dist/nextjs/index.d.ts +2 -2
- package/dist/nextjs/index.js +77 -31
- package/dist/nextjs/index.js.map +1 -1
- package/dist/nextjs/server.d.ts +53 -23
- package/dist/nextjs/server.js +197 -66
- package/dist/nextjs/server.js.map +1 -1
- package/dist/route/index.d.ts +138 -146
- package/dist/route/index.js +238 -22
- package/dist/route/index.js.map +1 -1
- package/dist/security/index.d.ts +83 -0
- package/dist/security/index.js +173 -0
- package/dist/security/index.js.map +1 -0
- package/dist/server/index.d.ts +450 -17
- package/dist/server/index.js +1756 -277
- package/dist/server/index.js.map +1 -1
- package/dist/{router-Di7ENoah.d.ts → token-manager-jKD_EsSE.d.ts} +121 -1
- package/dist/{types-D_N_U-Py.d.ts → types-7Mhoxnnt.d.ts} +21 -1
- package/dist/types-BFB72jbM.d.ts +282 -0
- package/dist/types-DVjf37yO.d.ts +205 -0
- package/docs/file-upload.md +717 -0
- package/package.json +235 -208
- package/dist/types-B-e_f2dQ.d.ts +0 -121
package/dist/nextjs/server.js
CHANGED
|
@@ -1,8 +1,77 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server';
|
|
2
2
|
import { env } from '@spfn/core/config';
|
|
3
3
|
import { logger } from '@spfn/core/logger';
|
|
4
|
+
import { randomBytes, createHmac, createHash } from 'crypto';
|
|
4
5
|
|
|
5
6
|
// src/nextjs/proxy/rpc.ts
|
|
7
|
+
var PROXY_SIGNATURE_HEADER = "x-spfn-proxy-signature";
|
|
8
|
+
var PROXY_TIMESTAMP_HEADER = "x-spfn-proxy-timestamp";
|
|
9
|
+
var PROXY_NONCE_HEADER = "x-spfn-proxy-nonce";
|
|
10
|
+
var PROXY_KEY_ID_HEADER = "x-spfn-proxy-key-id";
|
|
11
|
+
var PROXY_CLIENT_IP_HEADER = "x-spfn-proxy-client-ip";
|
|
12
|
+
var DEFAULT_KEY_ID = "default";
|
|
13
|
+
function parseProxyKey(raw) {
|
|
14
|
+
const idx = raw.indexOf(":");
|
|
15
|
+
if (idx === -1) {
|
|
16
|
+
return { keyId: DEFAULT_KEY_ID, secret: raw };
|
|
17
|
+
}
|
|
18
|
+
return { keyId: raw.slice(0, idx) || DEFAULT_KEY_ID, secret: raw.slice(idx + 1) };
|
|
19
|
+
}
|
|
20
|
+
function parseProxyKeySet(raws) {
|
|
21
|
+
const keys = [];
|
|
22
|
+
const seen = /* @__PURE__ */ new Set();
|
|
23
|
+
for (const raw of raws) {
|
|
24
|
+
if (!raw) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
for (const part of raw.split(",")) {
|
|
28
|
+
const trimmed = part.trim();
|
|
29
|
+
if (!trimmed) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const key = parseProxyKey(trimmed);
|
|
33
|
+
if (!key.secret || seen.has(key.keyId)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
seen.add(key.keyId);
|
|
37
|
+
keys.push(key);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return keys;
|
|
41
|
+
}
|
|
42
|
+
function buildCanonicalString(parts) {
|
|
43
|
+
return [parts.method.toUpperCase(), parts.path, parts.query, parts.timestamp, parts.nonce, parts.bodyHash].join("\n");
|
|
44
|
+
}
|
|
45
|
+
function hashBody(body) {
|
|
46
|
+
if (!body || body.length === 0) {
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
return typeof body === "string" ? createHash("sha256").update(body, "utf8").digest("hex") : createHash("sha256").update(body).digest("hex");
|
|
50
|
+
}
|
|
51
|
+
function computeSignature(secret, parts) {
|
|
52
|
+
return createHmac("sha256", secret).update(buildCanonicalString(parts)).digest("hex");
|
|
53
|
+
}
|
|
54
|
+
function generateNonce() {
|
|
55
|
+
return randomBytes(16).toString("hex");
|
|
56
|
+
}
|
|
57
|
+
function signProxyRequest(input) {
|
|
58
|
+
const timestamp = input.timestamp ?? String(Date.now());
|
|
59
|
+
const nonce = input.nonce ?? generateNonce();
|
|
60
|
+
const signature = computeSignature(input.key.secret, {
|
|
61
|
+
method: input.method,
|
|
62
|
+
path: input.path,
|
|
63
|
+
query: input.query ?? "",
|
|
64
|
+
timestamp,
|
|
65
|
+
nonce,
|
|
66
|
+
bodyHash: hashBody(input.body)
|
|
67
|
+
});
|
|
68
|
+
return {
|
|
69
|
+
[PROXY_SIGNATURE_HEADER]: signature,
|
|
70
|
+
[PROXY_TIMESTAMP_HEADER]: timestamp,
|
|
71
|
+
[PROXY_NONCE_HEADER]: nonce,
|
|
72
|
+
[PROXY_KEY_ID_HEADER]: input.key.keyId
|
|
73
|
+
};
|
|
74
|
+
}
|
|
6
75
|
|
|
7
76
|
// src/nextjs/shared.ts
|
|
8
77
|
function buildUrlWithParams(path, params) {
|
|
@@ -27,6 +96,9 @@ function buildQueryString(query) {
|
|
|
27
96
|
return `?${searchParams.toString()}`;
|
|
28
97
|
}
|
|
29
98
|
async function parseResponseBody(response) {
|
|
99
|
+
if (response.status === 204) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
30
102
|
const contentType = response.headers.get("content-type");
|
|
31
103
|
if (contentType?.includes("application/json")) {
|
|
32
104
|
const text = await response.text();
|
|
@@ -185,6 +257,17 @@ function registerInterceptors(packageName, interceptors) {
|
|
|
185
257
|
}
|
|
186
258
|
|
|
187
259
|
// src/nextjs/proxy/helpers.ts
|
|
260
|
+
function clientIpFromForwardedChain(xff, trustedHops) {
|
|
261
|
+
if (!xff) return void 0;
|
|
262
|
+
const parts = xff.split(",").map((s) => s.trim()).filter(Boolean);
|
|
263
|
+
if (parts.length === 0) return void 0;
|
|
264
|
+
const idx = parts.length - Math.max(1, trustedHops);
|
|
265
|
+
return parts[idx] ?? parts[0];
|
|
266
|
+
}
|
|
267
|
+
function trustedProxyHops() {
|
|
268
|
+
const raw = Number.parseInt(process.env.TRUSTED_PROXY_HOPS ?? "", 10);
|
|
269
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 1;
|
|
270
|
+
}
|
|
188
271
|
function buildProxyHeaders(sourceHeaders, defaultHeaders) {
|
|
189
272
|
const headers = new Headers();
|
|
190
273
|
const headersToForward2 = [
|
|
@@ -193,7 +276,10 @@ function buildProxyHeaders(sourceHeaders, defaultHeaders) {
|
|
|
193
276
|
"cookie",
|
|
194
277
|
"user-agent",
|
|
195
278
|
"accept",
|
|
196
|
-
"accept-language"
|
|
279
|
+
"accept-language",
|
|
280
|
+
// Forwarded so the backend proxy-guard can enforce its origin allowlist on
|
|
281
|
+
// the real browser Origin; without this allowedOrigins would be a no-op.
|
|
282
|
+
"origin"
|
|
197
283
|
];
|
|
198
284
|
for (const header of headersToForward2) {
|
|
199
285
|
const value = sourceHeaders instanceof Headers ? sourceHeaders.get(header) : sourceHeaders[header];
|
|
@@ -201,6 +287,11 @@ function buildProxyHeaders(sourceHeaders, defaultHeaders) {
|
|
|
201
287
|
headers.set(header, value);
|
|
202
288
|
}
|
|
203
289
|
}
|
|
290
|
+
const xff = sourceHeaders instanceof Headers ? sourceHeaders.get("x-forwarded-for") : sourceHeaders["x-forwarded-for"];
|
|
291
|
+
const clientIp = clientIpFromForwardedChain(xff, trustedProxyHops());
|
|
292
|
+
if (clientIp) {
|
|
293
|
+
headers.set(PROXY_CLIENT_IP_HEADER, clientIp);
|
|
294
|
+
}
|
|
204
295
|
for (const [key, value] of Object.entries(defaultHeaders)) {
|
|
205
296
|
headers.set(key, value);
|
|
206
297
|
}
|
|
@@ -302,7 +393,7 @@ function buildRequestContext(path, method, headers, body, searchParams, cookiesM
|
|
|
302
393
|
metadata: {}
|
|
303
394
|
};
|
|
304
395
|
}
|
|
305
|
-
function buildResponseContext(path, method, requestHeaders, requestBody, response, responseBody, requestMetadata) {
|
|
396
|
+
function buildResponseContext(path, method, requestHeaders, requestBody, response, responseBody, requestMetadata, cookies) {
|
|
306
397
|
return {
|
|
307
398
|
path: `/${path}`,
|
|
308
399
|
method,
|
|
@@ -317,6 +408,7 @@ function buildResponseContext(path, method, requestHeaders, requestBody, respons
|
|
|
317
408
|
headers: response.headers,
|
|
318
409
|
body: responseBody
|
|
319
410
|
},
|
|
411
|
+
cookies,
|
|
320
412
|
setCookies: [],
|
|
321
413
|
metadata: requestMetadata
|
|
322
414
|
};
|
|
@@ -324,45 +416,37 @@ function buildResponseContext(path, method, requestHeaders, requestBody, respons
|
|
|
324
416
|
|
|
325
417
|
// src/nextjs/proxy/rpc.ts
|
|
326
418
|
var rpcLogger = logger.child("@spfn/core:rpc-proxy");
|
|
327
|
-
function isRouteDef(value) {
|
|
328
|
-
return value !== null && typeof value === "object" && "handler" in value && "method" in value && "path" in value;
|
|
329
|
-
}
|
|
330
|
-
function isRouter(value) {
|
|
331
|
-
return value !== null && typeof value === "object" && "routes" in value && "_routes" in value;
|
|
332
|
-
}
|
|
333
|
-
function getRouteByPath(router, routePath) {
|
|
334
|
-
const parts = routePath.split(".");
|
|
335
|
-
let current = router.routes;
|
|
336
|
-
for (const part of parts) {
|
|
337
|
-
if (!current || typeof current !== "object") {
|
|
338
|
-
return null;
|
|
339
|
-
}
|
|
340
|
-
const next = current[part];
|
|
341
|
-
if (isRouter(next)) {
|
|
342
|
-
current = next.routes;
|
|
343
|
-
} else if (isRouteDef(next)) {
|
|
344
|
-
return next;
|
|
345
|
-
} else {
|
|
346
|
-
current = next;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
if (isRouteDef(current)) {
|
|
350
|
-
return current;
|
|
351
|
-
}
|
|
352
|
-
return null;
|
|
353
|
-
}
|
|
354
419
|
function createRpcProxy(config) {
|
|
355
420
|
const {
|
|
356
|
-
router,
|
|
357
421
|
apiUrl = env.SPFN_API_URL || "http://localhost:8790",
|
|
358
422
|
debug = env.NODE_ENV === "development",
|
|
359
|
-
timeout =
|
|
423
|
+
timeout = env.RPC_PROXY_TIMEOUT,
|
|
360
424
|
headers: defaultHeaders = {},
|
|
361
425
|
interceptors,
|
|
362
426
|
autoDiscoverInterceptors = true,
|
|
363
|
-
disableAutoInterceptors
|
|
427
|
+
disableAutoInterceptors,
|
|
428
|
+
proxySecret = env.SPFN_PROXY_SECRET,
|
|
429
|
+
routeMap
|
|
364
430
|
} = config;
|
|
365
|
-
const
|
|
431
|
+
const proxyKey = proxySecret ? parseProxyKeySet([proxySecret])[0] ?? null : null;
|
|
432
|
+
if (proxyKey) {
|
|
433
|
+
try {
|
|
434
|
+
const basePath = new URL(apiUrl).pathname;
|
|
435
|
+
if (basePath !== "/" && basePath !== "") {
|
|
436
|
+
rpcLogger.warn(
|
|
437
|
+
`SPFN_API_URL has a base path ("${basePath}"). proxy-guard signs route-relative paths, so the backend must receive paths WITHOUT this prefix (e.g. ingress strip) or strict mode will reject all signed requests with 403.`
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
} catch {
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function resolveRoute(routeName) {
|
|
444
|
+
const entry = routeMap[routeName];
|
|
445
|
+
if (entry) {
|
|
446
|
+
return { method: entry.method, path: entry.path };
|
|
447
|
+
}
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
366
450
|
async function handleRpc(request, context) {
|
|
367
451
|
const startTime = Date.now();
|
|
368
452
|
const params = await context.params;
|
|
@@ -375,6 +459,7 @@ function createRpcProxy(config) {
|
|
|
375
459
|
);
|
|
376
460
|
}
|
|
377
461
|
let input = {};
|
|
462
|
+
let rawFormData = null;
|
|
378
463
|
if (request.method === "GET") {
|
|
379
464
|
const inputParam = request.nextUrl.searchParams.get("input");
|
|
380
465
|
if (inputParam) {
|
|
@@ -388,45 +473,63 @@ function createRpcProxy(config) {
|
|
|
388
473
|
}
|
|
389
474
|
}
|
|
390
475
|
} else {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
for (const pkgRouter of packageRouters) {
|
|
403
|
-
routeDef = getRouteByPath(pkgRouter, routeName);
|
|
404
|
-
if (routeDef) {
|
|
405
|
-
if (debug) {
|
|
406
|
-
rpcLogger.debug(`Route "${routeName}" found in package router`);
|
|
476
|
+
const contentType = request.headers.get("content-type") || "";
|
|
477
|
+
if (contentType.includes("multipart/form-data")) {
|
|
478
|
+
try {
|
|
479
|
+
rawFormData = await request.formData();
|
|
480
|
+
const metadataStr = rawFormData.get("__metadata");
|
|
481
|
+
if (metadataStr && typeof metadataStr === "string") {
|
|
482
|
+
const metadata = JSON.parse(metadataStr);
|
|
483
|
+
input.params = metadata.params;
|
|
484
|
+
input.query = metadata.query;
|
|
485
|
+
input.headers = metadata.headers;
|
|
486
|
+
input.cookies = metadata.cookies;
|
|
407
487
|
}
|
|
408
|
-
|
|
488
|
+
input.formData = {};
|
|
489
|
+
rawFormData.forEach((value, key) => {
|
|
490
|
+
if (key === "__metadata") return;
|
|
491
|
+
const existing = input.formData[key];
|
|
492
|
+
if (existing !== void 0) {
|
|
493
|
+
if (Array.isArray(existing)) {
|
|
494
|
+
existing.push(value);
|
|
495
|
+
} else {
|
|
496
|
+
input.formData[key] = [existing, value];
|
|
497
|
+
}
|
|
498
|
+
} else {
|
|
499
|
+
input.formData[key] = value;
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
} catch (error) {
|
|
503
|
+
return NextResponse.json(
|
|
504
|
+
buildErrorResponse("Bad Request", "Invalid form data", debug),
|
|
505
|
+
{ status: 400 }
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
} else {
|
|
509
|
+
try {
|
|
510
|
+
input = await request.json();
|
|
511
|
+
} catch {
|
|
512
|
+
return NextResponse.json(
|
|
513
|
+
buildErrorResponse("Bad Request", "Invalid JSON body", debug),
|
|
514
|
+
{ status: 400 }
|
|
515
|
+
);
|
|
409
516
|
}
|
|
410
517
|
}
|
|
411
518
|
}
|
|
412
|
-
|
|
519
|
+
const routeInfo = resolveRoute(routeName);
|
|
520
|
+
if (!routeInfo) {
|
|
413
521
|
rpcLogger.warn(`Route not found: ${routeName}`);
|
|
414
522
|
return NextResponse.json(
|
|
415
|
-
buildErrorResponse("Not Found", `Route "${routeName}" not found
|
|
523
|
+
buildErrorResponse("Not Found", `Route "${routeName}" not found`, debug),
|
|
416
524
|
{ status: 404 }
|
|
417
525
|
);
|
|
418
526
|
}
|
|
419
|
-
const { method: targetMethod, path: targetPath } =
|
|
420
|
-
if (!targetMethod || !targetPath) {
|
|
421
|
-
rpcLogger.warn(`Route "${routeName}" is missing method or path`);
|
|
422
|
-
return NextResponse.json(
|
|
423
|
-
buildErrorResponse("Internal Error", `Route "${routeName}" is misconfigured`, debug),
|
|
424
|
-
{ status: 500 }
|
|
425
|
-
);
|
|
426
|
-
}
|
|
527
|
+
const { method: targetMethod, path: targetPath } = routeInfo;
|
|
427
528
|
const inputParams = input.params || {};
|
|
428
529
|
const inputQuery = input.query || {};
|
|
429
530
|
const inputBody = input.body;
|
|
531
|
+
const inputFormData = input.formData;
|
|
532
|
+
const hasFormData = rawFormData !== null && inputFormData && Object.keys(inputFormData).length > 0;
|
|
430
533
|
const resolvedPath = buildUrlWithParams(targetPath, inputParams);
|
|
431
534
|
const queryString = buildQueryString(inputQuery);
|
|
432
535
|
const targetUrl = `${apiUrl}${resolvedPath}${queryString}`;
|
|
@@ -436,21 +539,35 @@ function createRpcProxy(config) {
|
|
|
436
539
|
targetMethod,
|
|
437
540
|
targetPath: resolvedPath,
|
|
438
541
|
targetUrl,
|
|
439
|
-
hasBody: !!inputBody
|
|
542
|
+
hasBody: !!inputBody,
|
|
543
|
+
hasFormData
|
|
440
544
|
});
|
|
441
545
|
}
|
|
442
546
|
const headers = buildProxyHeaders(request.headers, defaultHeaders);
|
|
547
|
+
if (hasFormData) {
|
|
548
|
+
headers.delete("content-type");
|
|
549
|
+
}
|
|
443
550
|
const fetchOptions = {
|
|
444
551
|
method: targetMethod,
|
|
445
552
|
headers
|
|
446
553
|
};
|
|
447
|
-
if (["POST", "PUT", "PATCH"].includes(targetMethod)
|
|
448
|
-
|
|
554
|
+
if (["POST", "PUT", "PATCH"].includes(targetMethod)) {
|
|
555
|
+
if (hasFormData && rawFormData) {
|
|
556
|
+
const forwardFormData = new FormData();
|
|
557
|
+
rawFormData.forEach((value, key) => {
|
|
558
|
+
if (key !== "__metadata") {
|
|
559
|
+
forwardFormData.append(key, value);
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
fetchOptions.body = forwardFormData;
|
|
563
|
+
} else if (inputBody) {
|
|
564
|
+
fetchOptions.body = JSON.stringify(inputBody);
|
|
565
|
+
}
|
|
449
566
|
}
|
|
450
567
|
const allInterceptors = collectInterceptors(autoDiscoverInterceptors, disableAutoInterceptors, interceptors, interceptorRegistry);
|
|
451
568
|
const matchingInterceptors = filterMatchingInterceptors(allInterceptors, resolvedPath, targetMethod);
|
|
452
569
|
if (debug && matchingInterceptors.length > 0) {
|
|
453
|
-
rpcLogger.debug(
|
|
570
|
+
rpcLogger.debug(`Found ${matchingInterceptors.length} matching interceptors for ${targetMethod} ${resolvedPath}`);
|
|
454
571
|
}
|
|
455
572
|
const cookiesMap = parseCookiesFromNextRequest(request);
|
|
456
573
|
const requestCtx = buildRequestContext(
|
|
@@ -474,6 +591,19 @@ function createRpcProxy(config) {
|
|
|
474
591
|
fetchOptions.body = JSON.stringify(requestCtx.body);
|
|
475
592
|
}
|
|
476
593
|
}
|
|
594
|
+
if (proxyKey) {
|
|
595
|
+
const signedBody = typeof fetchOptions.body === "string" ? fetchOptions.body : void 0;
|
|
596
|
+
const signatureHeaders = signProxyRequest({
|
|
597
|
+
key: proxyKey,
|
|
598
|
+
method: targetMethod,
|
|
599
|
+
path: resolvedPath,
|
|
600
|
+
query: queryString,
|
|
601
|
+
body: signedBody
|
|
602
|
+
});
|
|
603
|
+
for (const [headerName, value] of Object.entries(signatureHeaders)) {
|
|
604
|
+
headers.set(headerName, value);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
477
607
|
const controller = new AbortController();
|
|
478
608
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
479
609
|
try {
|
|
@@ -490,7 +620,8 @@ function createRpcProxy(config) {
|
|
|
490
620
|
inputBody,
|
|
491
621
|
response,
|
|
492
622
|
body,
|
|
493
|
-
requestCtx.metadata
|
|
623
|
+
requestCtx.metadata,
|
|
624
|
+
requestCtx.cookies
|
|
494
625
|
);
|
|
495
626
|
const responseInterceptorsToRun = matchingInterceptors.map((r) => r.response).filter((i) => !!i);
|
|
496
627
|
if (responseInterceptorsToRun.length > 0) {
|
|
@@ -517,7 +648,7 @@ function createRpcProxy(config) {
|
|
|
517
648
|
const setCookieHeader = buildSetCookieHeader(cookie);
|
|
518
649
|
nextResponse.headers.append("Set-Cookie", setCookieHeader);
|
|
519
650
|
if (debug) {
|
|
520
|
-
rpcLogger.debug("
|
|
651
|
+
rpcLogger.debug("Set-Cookie header added", {
|
|
521
652
|
name: cookie.name
|
|
522
653
|
});
|
|
523
654
|
}
|