@gcoredev/fastedge-test 0.1.7 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/frontend/assets/{index-BCXfEMSq.js → index-CiqeJ9rz.js} +24 -24
- package/dist/frontend/index.html +1 -1
- package/dist/lib/index.cjs +130 -62
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +130 -62
- package/dist/lib/runner/HeaderManager.d.ts +6 -4
- package/dist/lib/runner/HostFunctions.d.ts +5 -5
- package/dist/lib/runner/HttpWasmRunner.d.ts +13 -4
- package/dist/lib/runner/IStateManager.d.ts +7 -7
- package/dist/lib/runner/IWasmRunner.d.ts +17 -9
- package/dist/lib/runner/PropertyResolver.d.ts +3 -3
- package/dist/lib/runner/ProxyWasmRunner.d.ts +5 -2
- package/dist/lib/runner/standalone.d.ts +1 -1
- package/dist/lib/runner/types.d.ts +17 -8
- package/dist/lib/schemas/api.d.ts +0 -8
- package/dist/lib/schemas/config.d.ts +0 -13
- package/dist/lib/schemas/index.d.ts +2 -2
- package/dist/lib/test-framework/assertions.d.ts +18 -4
- package/dist/lib/test-framework/index.cjs +18593 -111
- package/dist/lib/test-framework/index.d.ts +2 -0
- package/dist/lib/test-framework/index.js +18610 -100
- package/dist/lib/test-framework/mock-origins.d.ts +56 -0
- package/dist/lib/test-framework/types.d.ts +1 -5
- package/dist/server.js +33 -33
- package/docs/API.md +19 -49
- package/docs/DEBUGGER.md +6 -7
- package/docs/INDEX.md +4 -1
- package/docs/RUNNER.md +96 -81
- package/docs/TEST_CONFIG.md +9 -22
- package/docs/TEST_FRAMEWORK.md +206 -31
- package/docs/WEBSOCKET.md +25 -21
- package/docs/quickstart.md +1 -13
- package/package.json +4 -1
- package/schemas/api-config.schema.json +0 -24
- package/schemas/api-send.schema.json +0 -20
- package/schemas/fastedge-config.test.schema.json +0 -24
- package/schemas/full-flow-result.schema.json +17 -7
- package/schemas/hook-call.schema.json +16 -6
- package/schemas/hook-result.schema.json +16 -6
- package/schemas/http-response.schema.json +227 -5
package/dist/frontend/index.html
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Proxy Runner</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-CiqeJ9rz.js"></script>
|
|
8
8
|
<link rel="stylesheet" crossorigin href="/assets/index-DdlINQc_.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
package/dist/lib/index.cjs
CHANGED
|
@@ -219,10 +219,36 @@ var MemoryManager = class {
|
|
|
219
219
|
// server/runner/HeaderManager.ts
|
|
220
220
|
var textEncoder2 = new TextEncoder();
|
|
221
221
|
var HeaderManager = class {
|
|
222
|
+
// Read a header value as a single string. For multi-valued headers (string[]) returns the first.
|
|
223
|
+
// Use when callers know the header is conventionally single-valued (content-type, host, location, etc.)
|
|
224
|
+
// and need to satisfy APIs that take a string.
|
|
225
|
+
static firstValue(v) {
|
|
226
|
+
return Array.isArray(v) ? v[0] : v;
|
|
227
|
+
}
|
|
228
|
+
// Flatten a HeaderRecord to a HeaderMap (single string per key) for consumers
|
|
229
|
+
// that can't handle multi-valued headers (e.g. fetch's HeadersInit).
|
|
230
|
+
// Multi-valued entries are joined with ", " — caller must be sure this is acceptable
|
|
231
|
+
// (NOT valid for Set-Cookie; route those through a separate channel).
|
|
232
|
+
static flattenToMap(headers) {
|
|
233
|
+
const flat = {};
|
|
234
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
235
|
+
if (Array.isArray(v)) {
|
|
236
|
+
flat[k] = v.join(", ");
|
|
237
|
+
} else if (v !== void 0) {
|
|
238
|
+
flat[k] = String(v);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return flat;
|
|
242
|
+
}
|
|
222
243
|
static normalize(headers) {
|
|
223
244
|
const normalized = {};
|
|
224
245
|
for (const [key, value] of Object.entries(headers)) {
|
|
225
|
-
|
|
246
|
+
const k = key.toLowerCase();
|
|
247
|
+
if (Array.isArray(value)) {
|
|
248
|
+
normalized[k] = value.map(String);
|
|
249
|
+
} else {
|
|
250
|
+
normalized[k] = String(value);
|
|
251
|
+
}
|
|
226
252
|
}
|
|
227
253
|
return normalized;
|
|
228
254
|
}
|
|
@@ -301,13 +327,31 @@ var HeaderManager = class {
|
|
|
301
327
|
}
|
|
302
328
|
// --- Tuple-based methods for multi-valued header support ---
|
|
303
329
|
static recordToTuples(headers) {
|
|
304
|
-
|
|
330
|
+
const tuples = [];
|
|
331
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
332
|
+
const key = k.toLowerCase();
|
|
333
|
+
if (Array.isArray(v)) {
|
|
334
|
+
for (const val of v) tuples.push([key, String(val)]);
|
|
335
|
+
} else if (v !== void 0) {
|
|
336
|
+
tuples.push([key, String(v)]);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return tuples;
|
|
305
340
|
}
|
|
341
|
+
// Lossless projection of tuples to a Record: single-valued keys are string,
|
|
342
|
+
// multi-valued keys are string[] — matching Node's IncomingHttpHeaders shape.
|
|
343
|
+
// Set-Cookie and other legitimately-repeatable headers are preserved across duplicates.
|
|
306
344
|
static tuplesToRecord(tuples) {
|
|
307
345
|
const record = {};
|
|
308
346
|
for (const [key, value] of tuples) {
|
|
309
347
|
const existing = record[key];
|
|
310
|
-
|
|
348
|
+
if (existing === void 0) {
|
|
349
|
+
record[key] = value;
|
|
350
|
+
} else if (Array.isArray(existing)) {
|
|
351
|
+
existing.push(value);
|
|
352
|
+
} else {
|
|
353
|
+
record[key] = [existing, value];
|
|
354
|
+
}
|
|
311
355
|
}
|
|
312
356
|
return record;
|
|
313
357
|
}
|
|
@@ -453,10 +497,11 @@ var PropertyResolver = class {
|
|
|
453
497
|
const url = new URL(targetUrl);
|
|
454
498
|
this.requestUrl = targetUrl;
|
|
455
499
|
this.requestHost = url.hostname + (url.port ? `:${url.port}` : "");
|
|
456
|
-
this.requestPath = url.pathname || "/";
|
|
500
|
+
this.requestPath = (url.pathname || "/") + url.search;
|
|
457
501
|
this.requestQuery = url.search.startsWith("?") ? url.search.substring(1) : url.search;
|
|
458
502
|
this.requestScheme = url.protocol.replace(":", "");
|
|
459
|
-
const
|
|
503
|
+
const pathOnly = url.pathname || "/";
|
|
504
|
+
const pathParts = pathOnly.split("/");
|
|
460
505
|
const lastPart = pathParts[pathParts.length - 1];
|
|
461
506
|
const dotIndex = lastPart.lastIndexOf(".");
|
|
462
507
|
if (dotIndex > 0 && dotIndex < lastPart.length - 1) {
|
|
@@ -526,28 +571,28 @@ var PropertyResolver = class {
|
|
|
526
571
|
if (path2 === "request.url")
|
|
527
572
|
return this.requestUrl || `${this.requestScheme}://${this.requestHost}${this.requestPath}`;
|
|
528
573
|
if (path2 === "request.host")
|
|
529
|
-
return this.requestHost || this.requestHeaders["host"] || "localhost";
|
|
574
|
+
return this.requestHost || HeaderManager.firstValue(this.requestHeaders["host"]) || "localhost";
|
|
530
575
|
if (path2 === "request.scheme") return this.requestScheme;
|
|
531
576
|
if (path2 === "request.protocol") return this.requestScheme;
|
|
532
577
|
if (path2 === "request.query") return this.requestQuery;
|
|
533
578
|
if (path2 === "request.extension") return this.requestExtension;
|
|
534
579
|
if (path2 === "request.content_type") {
|
|
535
|
-
return this.requestHeaders["content-type"] || "";
|
|
580
|
+
return HeaderManager.firstValue(this.requestHeaders["content-type"]) || "";
|
|
536
581
|
}
|
|
537
582
|
if (path2.startsWith("request.headers.")) {
|
|
538
583
|
const headerName = path2.substring("request.headers.".length).toLowerCase();
|
|
539
|
-
return this.requestHeaders[headerName] || "";
|
|
584
|
+
return HeaderManager.firstValue(this.requestHeaders[headerName]) || "";
|
|
540
585
|
}
|
|
541
586
|
if (path2 === "response.code") return this.responseStatus;
|
|
542
587
|
if (path2 === "response.status") return this.responseStatus;
|
|
543
588
|
if (path2 === "response.status_code") return this.responseStatus;
|
|
544
589
|
if (path2 === "response.code_details") return this.responseStatusText;
|
|
545
590
|
if (path2 === "response.content_type") {
|
|
546
|
-
return this.responseHeaders["content-type"] || "";
|
|
591
|
+
return HeaderManager.firstValue(this.responseHeaders["content-type"]) || "";
|
|
547
592
|
}
|
|
548
593
|
if (path2.startsWith("response.headers.")) {
|
|
549
594
|
const headerName = path2.substring("response.headers.".length).toLowerCase();
|
|
550
|
-
return this.responseHeaders[headerName] || "";
|
|
595
|
+
return HeaderManager.firstValue(this.responseHeaders[headerName]) || "";
|
|
551
596
|
}
|
|
552
597
|
return void 0;
|
|
553
598
|
}
|
|
@@ -902,7 +947,8 @@ var HostFunctions = class {
|
|
|
902
947
|
return call;
|
|
903
948
|
}
|
|
904
949
|
setHttpCallResponse(tokenId, headers, body) {
|
|
905
|
-
|
|
950
|
+
const tuples = Array.isArray(headers) ? headers : HeaderManager.recordToTuples(headers);
|
|
951
|
+
this.httpCallResponse = { tokenId, headers: tuples, body };
|
|
906
952
|
}
|
|
907
953
|
clearHttpCallResponse() {
|
|
908
954
|
this.httpCallResponse = null;
|
|
@@ -1332,7 +1378,7 @@ var HostFunctions = class {
|
|
|
1332
1378
|
return this.responseHeaders;
|
|
1333
1379
|
}
|
|
1334
1380
|
if (mapType === 6 /* HttpCallResponseHeaders */ || mapType === 7 /* HttpCallResponseTrailers */) {
|
|
1335
|
-
return
|
|
1381
|
+
return this.httpCallResponse?.headers ?? [];
|
|
1336
1382
|
}
|
|
1337
1383
|
return this.requestHeaders;
|
|
1338
1384
|
}
|
|
@@ -1992,7 +2038,7 @@ var ProxyWasmRunner = class {
|
|
|
1992
2038
|
const local = this.hostFunctions.getLocalResponse();
|
|
1993
2039
|
const responseHeaders2 = results.onRequestHeaders.output.response.headers;
|
|
1994
2040
|
this.hostFunctions.resetLocalResponse();
|
|
1995
|
-
const contentType2 = responseHeaders2["content-type"] || "text/plain";
|
|
2041
|
+
const contentType2 = HeaderManager.firstValue(responseHeaders2["content-type"]) || "text/plain";
|
|
1996
2042
|
const { body, isBase64: isBase642 } = encodeLocalResponseBody(local.body, contentType2);
|
|
1997
2043
|
return {
|
|
1998
2044
|
hookResults: results,
|
|
@@ -2035,7 +2081,7 @@ var ProxyWasmRunner = class {
|
|
|
2035
2081
|
const local = this.hostFunctions.getLocalResponse();
|
|
2036
2082
|
const responseHeaders2 = results.onRequestBody.output.response.headers;
|
|
2037
2083
|
this.hostFunctions.resetLocalResponse();
|
|
2038
|
-
const contentType2 = responseHeaders2["content-type"] || "text/plain";
|
|
2084
|
+
const contentType2 = HeaderManager.firstValue(responseHeaders2["content-type"]) || "text/plain";
|
|
2039
2085
|
const { body, isBase64: isBase642 } = encodeLocalResponseBody(local.body, contentType2);
|
|
2040
2086
|
return {
|
|
2041
2087
|
hookResults: results,
|
|
@@ -2066,7 +2112,7 @@ var ProxyWasmRunner = class {
|
|
|
2066
2112
|
try {
|
|
2067
2113
|
if (isBuiltIn) {
|
|
2068
2114
|
this.logDebug("Using built-in responder");
|
|
2069
|
-
const rawStatus = (modifiedRequestHeaders["x-debugger-status"] || "").trim();
|
|
2115
|
+
const rawStatus = (HeaderManager.firstValue(modifiedRequestHeaders["x-debugger-status"]) || "").trim();
|
|
2070
2116
|
if (rawStatus === "") {
|
|
2071
2117
|
responseStatus = 200;
|
|
2072
2118
|
} else {
|
|
@@ -2077,7 +2123,7 @@ var ProxyWasmRunner = class {
|
|
|
2077
2123
|
}
|
|
2078
2124
|
}
|
|
2079
2125
|
responseStatusText = responseStatus === 200 ? "OK" : String(responseStatus);
|
|
2080
|
-
const responseContentMode = modifiedRequestHeaders["x-debugger-content"] || "";
|
|
2126
|
+
const responseContentMode = HeaderManager.firstValue(modifiedRequestHeaders["x-debugger-content"]) || "";
|
|
2081
2127
|
delete modifiedRequestHeaders["x-debugger-status"];
|
|
2082
2128
|
delete modifiedRequestHeaders["x-debugger-content"];
|
|
2083
2129
|
if (responseContentMode === "status-only") {
|
|
@@ -2085,14 +2131,14 @@ var ProxyWasmRunner = class {
|
|
|
2085
2131
|
contentType = "text/plain";
|
|
2086
2132
|
} else if (responseContentMode === "body-only") {
|
|
2087
2133
|
responseBody = modifiedRequestBody || "";
|
|
2088
|
-
contentType = modifiedRequestHeaders["content-type"] || "text/plain";
|
|
2134
|
+
contentType = HeaderManager.firstValue(modifiedRequestHeaders["content-type"]) || "text/plain";
|
|
2089
2135
|
} else {
|
|
2090
2136
|
contentType = "application/json";
|
|
2091
2137
|
responseBody = JSON.stringify({
|
|
2092
2138
|
method: requestMethod,
|
|
2093
2139
|
reqHeaders: modifiedRequestHeaders,
|
|
2094
2140
|
reqBody: modifiedRequestBody || "",
|
|
2095
|
-
requestUrl: BUILTIN_URL
|
|
2141
|
+
requestUrl: propertiesAfterRequestBody["request.url"] || BUILTIN_URL
|
|
2096
2142
|
});
|
|
2097
2143
|
}
|
|
2098
2144
|
responseHeaders = {
|
|
@@ -2103,27 +2149,30 @@ var ProxyWasmRunner = class {
|
|
|
2103
2149
|
`Built-in responder: ${responseStatus} ${responseStatusText}, mode=${responseContentMode || "full"}`
|
|
2104
2150
|
);
|
|
2105
2151
|
} else {
|
|
2106
|
-
const
|
|
2107
|
-
const
|
|
2108
|
-
const modifiedPath = propertiesAfterRequestBody["request.path"] || "/";
|
|
2109
|
-
const modifiedQuery = propertiesAfterRequestBody["request.query"] || "";
|
|
2110
|
-
const actualTargetUrl = `${modifiedScheme}://${modifiedHost}${modifiedPath}${modifiedQuery ? "?" + modifiedQuery : ""}`;
|
|
2152
|
+
const actualTargetUrl = propertiesAfterRequestBody["request.url"] || targetUrl;
|
|
2153
|
+
const actualScheme = new URL(actualTargetUrl).protocol.replace(":", "");
|
|
2111
2154
|
this.logDebug(`Original URL: ${targetUrl}`);
|
|
2112
|
-
this.logDebug(`
|
|
2155
|
+
this.logDebug(`Effective URL: ${actualTargetUrl}`);
|
|
2113
2156
|
this.logDebug(`Fetching ${requestMethod} ${actualTargetUrl}`);
|
|
2114
|
-
const fetchHeaders =
|
|
2115
|
-
|
|
2116
|
-
|
|
2157
|
+
const fetchHeaders = HeaderManager.flattenToMap(
|
|
2158
|
+
modifiedRequestHeaders
|
|
2159
|
+
);
|
|
2160
|
+
for (const key of Object.keys(fetchHeaders)) {
|
|
2161
|
+
if (key.startsWith(":")) {
|
|
2162
|
+
delete fetchHeaders[key];
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2117
2165
|
const hostHeader = Object.entries(modifiedRequestHeaders).find(
|
|
2118
2166
|
([key]) => key.toLowerCase() === "host"
|
|
2119
2167
|
);
|
|
2120
2168
|
if (hostHeader) {
|
|
2121
|
-
|
|
2122
|
-
|
|
2169
|
+
const hostValue = HeaderManager.firstValue(hostHeader[1]) ?? "";
|
|
2170
|
+
fetchHeaders["x-forwarded-host"] = hostValue;
|
|
2171
|
+
this.logDebug(`Adding x-forwarded-host: ${hostValue}`);
|
|
2123
2172
|
}
|
|
2124
|
-
fetchHeaders["x-forwarded-proto"] =
|
|
2125
|
-
this.logDebug(`Adding x-forwarded-proto: ${
|
|
2126
|
-
fetchHeaders["x-forwarded-port"] =
|
|
2173
|
+
fetchHeaders["x-forwarded-proto"] = actualScheme;
|
|
2174
|
+
this.logDebug(`Adding x-forwarded-proto: ${actualScheme}`);
|
|
2175
|
+
fetchHeaders["x-forwarded-port"] = actualScheme === "https" ? "443" : "80";
|
|
2127
2176
|
this.logDebug(
|
|
2128
2177
|
`Adding x-forwarded-port: ${fetchHeaders["x-forwarded-port"]}`
|
|
2129
2178
|
);
|
|
@@ -2143,8 +2192,14 @@ var ProxyWasmRunner = class {
|
|
|
2143
2192
|
const response = await fetch(actualTargetUrl, fetchOptions);
|
|
2144
2193
|
responseHeaders = {};
|
|
2145
2194
|
response.headers.forEach((value, key) => {
|
|
2146
|
-
|
|
2195
|
+
if (key.toLowerCase() !== "set-cookie") {
|
|
2196
|
+
responseHeaders[key] = value;
|
|
2197
|
+
}
|
|
2147
2198
|
});
|
|
2199
|
+
const setCookies = response.headers.getSetCookie();
|
|
2200
|
+
if (setCookies.length > 0) {
|
|
2201
|
+
responseHeaders["set-cookie"] = setCookies;
|
|
2202
|
+
}
|
|
2148
2203
|
contentType = response.headers.get("content-type") || "text/plain";
|
|
2149
2204
|
responseStatus = response.status;
|
|
2150
2205
|
responseStatusText = response.statusText;
|
|
@@ -2221,7 +2276,7 @@ var ProxyWasmRunner = class {
|
|
|
2221
2276
|
const finalBody = results.onResponseBody.output.response.body;
|
|
2222
2277
|
this.logDebug(`Final response body length: ${finalBody.length}`);
|
|
2223
2278
|
const calculatedProperties = this.propertyResolver.getCalculatedProperties();
|
|
2224
|
-
const finalContentType = finalHeaders["content-type"] || contentType;
|
|
2279
|
+
const finalContentType = HeaderManager.firstValue(finalHeaders["content-type"]) || contentType;
|
|
2225
2280
|
return {
|
|
2226
2281
|
hookResults: results,
|
|
2227
2282
|
finalResponse: {
|
|
@@ -2314,13 +2369,13 @@ var ProxyWasmRunner = class {
|
|
|
2314
2369
|
this.hostFunctions.setLogLevel(0);
|
|
2315
2370
|
const requestHeaders = HeaderManager.normalize(call.request.headers ?? {});
|
|
2316
2371
|
const responseHeaders = HeaderManager.normalize(
|
|
2317
|
-
call.response
|
|
2372
|
+
call.response?.headers ?? {}
|
|
2318
2373
|
);
|
|
2319
2374
|
const requestBody = call.request.body ?? "";
|
|
2320
|
-
const responseBody = call.response
|
|
2375
|
+
const responseBody = call.response?.body ?? "";
|
|
2321
2376
|
const requestMethod = call.request.method ?? "GET";
|
|
2322
|
-
const responseStatus = call.response
|
|
2323
|
-
const responseStatusText = call.response
|
|
2377
|
+
const responseStatus = call.response?.status ?? 200;
|
|
2378
|
+
const responseStatusText = call.response?.statusText ?? "OK";
|
|
2324
2379
|
this.propertyResolver.setProperties({ ...call.properties ?? {} });
|
|
2325
2380
|
this.propertyResolver.setRequestMetadata(
|
|
2326
2381
|
requestHeaders,
|
|
@@ -2407,7 +2462,7 @@ var ProxyWasmRunner = class {
|
|
|
2407
2462
|
for (const [k, v] of Object.entries(pending.headers)) {
|
|
2408
2463
|
if (!k.startsWith(":")) fetchHeaders[k] = v;
|
|
2409
2464
|
}
|
|
2410
|
-
let responseHeaders2 =
|
|
2465
|
+
let responseHeaders2 = [];
|
|
2411
2466
|
let responseBody2 = new Uint8Array(0);
|
|
2412
2467
|
try {
|
|
2413
2468
|
const resp = await fetch(url, {
|
|
@@ -2417,20 +2472,23 @@ var ProxyWasmRunner = class {
|
|
|
2417
2472
|
signal: AbortSignal.timeout(pending.timeoutMs)
|
|
2418
2473
|
});
|
|
2419
2474
|
resp.headers.forEach((v, k) => {
|
|
2420
|
-
responseHeaders2[k
|
|
2475
|
+
if (k.toLowerCase() !== "set-cookie") responseHeaders2.push([k, v]);
|
|
2421
2476
|
});
|
|
2477
|
+
for (const cookie of resp.headers.getSetCookie()) {
|
|
2478
|
+
responseHeaders2.push(["set-cookie", cookie]);
|
|
2479
|
+
}
|
|
2422
2480
|
responseBody2 = new Uint8Array(await resp.arrayBuffer());
|
|
2423
2481
|
this.logDebug(
|
|
2424
|
-
`http_call response: ${resp.status} ${resp.statusText} numHeaders=${
|
|
2482
|
+
`http_call response: ${resp.status} ${resp.statusText} numHeaders=${responseHeaders2.length} bodySize=${responseBody2.byteLength}`
|
|
2425
2483
|
);
|
|
2426
2484
|
} catch (err) {
|
|
2427
2485
|
const errMsg = `http_call failed for ${url}: ${String(err)}`;
|
|
2428
2486
|
this.logDebug(errMsg);
|
|
2429
2487
|
this.logs.push({ level: 3, message: `[host] ${errMsg}` });
|
|
2430
|
-
responseHeaders2 =
|
|
2488
|
+
responseHeaders2 = [];
|
|
2431
2489
|
responseBody2 = new Uint8Array(0);
|
|
2432
2490
|
}
|
|
2433
|
-
const numHeaders =
|
|
2491
|
+
const numHeaders = responseHeaders2.length;
|
|
2434
2492
|
const bodySize = responseBody2.byteLength;
|
|
2435
2493
|
this.hostFunctions.setHttpCallResponse(pending.tokenId, responseHeaders2, responseBody2);
|
|
2436
2494
|
this.hostFunctions.resetStreamClosed();
|
|
@@ -2532,11 +2590,18 @@ var ProxyWasmRunner = class {
|
|
|
2532
2590
|
this.isInitializing = false;
|
|
2533
2591
|
}
|
|
2534
2592
|
buildHookInvocation(hook, requestHeaders, responseHeaders, requestBody, responseBody) {
|
|
2593
|
+
const countEntries = (h) => {
|
|
2594
|
+
let n = 0;
|
|
2595
|
+
for (const v of Object.values(h)) {
|
|
2596
|
+
n += Array.isArray(v) ? v.length : 1;
|
|
2597
|
+
}
|
|
2598
|
+
return n;
|
|
2599
|
+
};
|
|
2535
2600
|
switch (hook) {
|
|
2536
2601
|
case "onRequestHeaders":
|
|
2537
2602
|
return {
|
|
2538
2603
|
exportName: "proxy_on_request_headers",
|
|
2539
|
-
args: [this.currentContextId,
|
|
2604
|
+
args: [this.currentContextId, countEntries(requestHeaders), 0]
|
|
2540
2605
|
};
|
|
2541
2606
|
case "onRequestBody":
|
|
2542
2607
|
return {
|
|
@@ -2546,7 +2611,7 @@ var ProxyWasmRunner = class {
|
|
|
2546
2611
|
case "onResponseHeaders":
|
|
2547
2612
|
return {
|
|
2548
2613
|
exportName: "proxy_on_response_headers",
|
|
2549
|
-
args: [this.currentContextId,
|
|
2614
|
+
args: [this.currentContextId, countEntries(responseHeaders), 0]
|
|
2550
2615
|
};
|
|
2551
2616
|
case "onResponseBody":
|
|
2552
2617
|
return {
|
|
@@ -2661,9 +2726,12 @@ var ProxyWasmRunner = class {
|
|
|
2661
2726
|
console.warn(entry.message);
|
|
2662
2727
|
}
|
|
2663
2728
|
/**
|
|
2664
|
-
* Interface-compliant callFullFlow method
|
|
2729
|
+
* Interface-compliant callFullFlow method.
|
|
2730
|
+
*
|
|
2731
|
+
* The upstream response is generated at runtime by a real HTTP fetch
|
|
2732
|
+
* against `url` or by the built-in responder when `url === "built-in"`.
|
|
2665
2733
|
*/
|
|
2666
|
-
async callFullFlow(url, method, headers, body,
|
|
2734
|
+
async callFullFlow(url, method, headers, body, properties, enforceProductionPropertyRules) {
|
|
2667
2735
|
const call = {
|
|
2668
2736
|
hook: "",
|
|
2669
2737
|
// Not used in fullFlow
|
|
@@ -2672,12 +2740,6 @@ var ProxyWasmRunner = class {
|
|
|
2672
2740
|
body,
|
|
2673
2741
|
method
|
|
2674
2742
|
},
|
|
2675
|
-
response: {
|
|
2676
|
-
headers: responseHeaders,
|
|
2677
|
-
body: responseBody,
|
|
2678
|
-
status: responseStatus,
|
|
2679
|
-
statusText: responseStatusText
|
|
2680
|
-
},
|
|
2681
2743
|
properties,
|
|
2682
2744
|
enforceProductionPropertyRules
|
|
2683
2745
|
};
|
|
@@ -2991,7 +3053,7 @@ var HttpWasmRunner = class {
|
|
|
2991
3053
|
/**
|
|
2992
3054
|
* Not supported for HTTP WASM (proxy-wasm only)
|
|
2993
3055
|
*/
|
|
2994
|
-
async callFullFlow(_url, _method, _headers, _body,
|
|
3056
|
+
async callFullFlow(_url, _method, _headers, _body, _properties, _enforceProductionPropertyRules) {
|
|
2995
3057
|
throw new Error(
|
|
2996
3058
|
"callFullFlow() is not supported for HTTP WASM. Use execute() instead."
|
|
2997
3059
|
);
|
|
@@ -3243,17 +3305,23 @@ ${recentLogs || "(no logs)"}`
|
|
|
3243
3305
|
];
|
|
3244
3306
|
return binaryTypes.some((type) => contentType.toLowerCase().includes(type));
|
|
3245
3307
|
}
|
|
3246
|
-
/**
|
|
3247
|
-
* Parse headers from fetch Headers object
|
|
3248
|
-
*/
|
|
3249
3308
|
parseHeaders(headers) {
|
|
3250
|
-
|
|
3251
|
-
headers.forEach((value, key) => {
|
|
3252
|
-
result[key] = value;
|
|
3253
|
-
});
|
|
3254
|
-
return result;
|
|
3309
|
+
return parseFetchHeaders(headers);
|
|
3255
3310
|
}
|
|
3256
3311
|
};
|
|
3312
|
+
function parseFetchHeaders(headers) {
|
|
3313
|
+
const result = {};
|
|
3314
|
+
headers.forEach((value, key) => {
|
|
3315
|
+
if (key.toLowerCase() !== "set-cookie") {
|
|
3316
|
+
result[key] = value;
|
|
3317
|
+
}
|
|
3318
|
+
});
|
|
3319
|
+
const setCookies = headers.getSetCookie();
|
|
3320
|
+
if (setCookies.length > 0) {
|
|
3321
|
+
result["set-cookie"] = setCookies;
|
|
3322
|
+
}
|
|
3323
|
+
return result;
|
|
3324
|
+
}
|
|
3257
3325
|
|
|
3258
3326
|
// server/runner/PortManager.ts
|
|
3259
3327
|
var import_net = require("net");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./runner/index.js";
|