@gcoredev/fastedge-test 0.2.0 → 0.2.1
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/fastedge-cli/METADATA.json +1 -1
- package/dist/fastedge-cli/fastedge-run-darwin-arm64 +0 -0
- package/dist/fastedge-cli/fastedge-run-linux-x64 +0 -0
- package/dist/fastedge-cli/fastedge-run.exe +0 -0
- package/dist/lib/index.cjs +162 -78
- package/dist/lib/index.js +162 -78
- package/dist/lib/runner/HeaderManager.d.ts +1 -0
- package/dist/lib/runner/ProxyWasmRunner.d.ts +1 -1
- package/dist/lib/test-framework/index.cjs +161 -78
- package/dist/lib/test-framework/index.js +161 -78
- package/dist/server.js +25 -25
- package/docs/API.md +4 -4
- package/docs/DEBUGGER.md +1 -0
- package/docs/RUNNER.md +32 -32
- package/docs/TEST_CONFIG.md +19 -19
- package/docs/TEST_FRAMEWORK.md +21 -23
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"fastedge_run_version": "v0.
|
|
1
|
+
{"fastedge_run_version": "v0.16.5"}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/lib/index.cjs
CHANGED
|
@@ -49,13 +49,11 @@ var import_node_wasi = require("node:wasi");
|
|
|
49
49
|
var textEncoder = new TextEncoder();
|
|
50
50
|
var textDecoder = new TextDecoder();
|
|
51
51
|
var MemoryManager = class {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
this.isInitializing = false;
|
|
58
|
-
}
|
|
52
|
+
memory = null;
|
|
53
|
+
instance = null;
|
|
54
|
+
hostAllocOffset = 0;
|
|
55
|
+
logCallback = null;
|
|
56
|
+
isInitializing = false;
|
|
59
57
|
setMemory(memory) {
|
|
60
58
|
this.memory = memory;
|
|
61
59
|
}
|
|
@@ -218,7 +216,7 @@ var MemoryManager = class {
|
|
|
218
216
|
|
|
219
217
|
// server/runner/HeaderManager.ts
|
|
220
218
|
var textEncoder2 = new TextEncoder();
|
|
221
|
-
var HeaderManager = class {
|
|
219
|
+
var HeaderManager = class _HeaderManager {
|
|
222
220
|
// Read a header value as a single string. For multi-valued headers (string[]) returns the first.
|
|
223
221
|
// Use when callers know the header is conventionally single-valued (content-type, host, location, etc.)
|
|
224
222
|
// and need to satisfy APIs that take a string.
|
|
@@ -241,7 +239,7 @@ var HeaderManager = class {
|
|
|
241
239
|
return flat;
|
|
242
240
|
}
|
|
243
241
|
static normalize(headers) {
|
|
244
|
-
const normalized =
|
|
242
|
+
const normalized = /* @__PURE__ */ Object.create(null);
|
|
245
243
|
for (const [key, value] of Object.entries(headers)) {
|
|
246
244
|
const k = key.toLowerCase();
|
|
247
245
|
if (Array.isArray(value)) {
|
|
@@ -252,6 +250,30 @@ var HeaderManager = class {
|
|
|
252
250
|
}
|
|
253
251
|
return normalized;
|
|
254
252
|
}
|
|
253
|
+
// Append-merge two header records: for keys present in both, values are
|
|
254
|
+
// concatenated into a string[] rather than the right-hand side overwriting
|
|
255
|
+
// the left. Keys are lowercased on the way in (consistent with `normalize`).
|
|
256
|
+
//
|
|
257
|
+
// Used by the runner to combine request-phase response-header state with
|
|
258
|
+
// the origin's response headers, mirroring how Envoy serves
|
|
259
|
+
// `add_http_response_header` calls issued during onRequestHeaders /
|
|
260
|
+
// onRequestBody against the actual upstream response — both values survive
|
|
261
|
+
// as a multi-value list (preserving the proxy-wasm cross-phase pattern).
|
|
262
|
+
static appendMerge(left, right) {
|
|
263
|
+
const result = _HeaderManager.normalize(left);
|
|
264
|
+
for (const [key, value] of Object.entries(right)) {
|
|
265
|
+
const k = key.toLowerCase();
|
|
266
|
+
const incoming = Array.isArray(value) ? value.map(String) : [String(value)];
|
|
267
|
+
if (Object.hasOwn(result, k)) {
|
|
268
|
+
const existing = result[k];
|
|
269
|
+
const existingArr = Array.isArray(existing) ? existing : [existing];
|
|
270
|
+
result[k] = [...existingArr, ...incoming];
|
|
271
|
+
} else {
|
|
272
|
+
result[k] = incoming.length === 1 ? incoming[0] : incoming;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return result;
|
|
276
|
+
}
|
|
255
277
|
static serialize(headers) {
|
|
256
278
|
const pairs = Object.entries(headers);
|
|
257
279
|
const numPairs = pairs.length;
|
|
@@ -430,20 +452,18 @@ var HeaderManager = class {
|
|
|
430
452
|
|
|
431
453
|
// server/runner/PropertyResolver.ts
|
|
432
454
|
var PropertyResolver = class {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
this.responseStatusText = "OK";
|
|
446
|
-
}
|
|
455
|
+
properties = {};
|
|
456
|
+
requestHeaders = {};
|
|
457
|
+
requestMethod = "GET";
|
|
458
|
+
requestPath = "/";
|
|
459
|
+
requestScheme = "https";
|
|
460
|
+
requestUrl = "";
|
|
461
|
+
requestHost = "";
|
|
462
|
+
requestQuery = "";
|
|
463
|
+
requestExtension = "";
|
|
464
|
+
responseHeaders = {};
|
|
465
|
+
responseStatus = 200;
|
|
466
|
+
responseStatusText = "OK";
|
|
447
467
|
setProperties(properties) {
|
|
448
468
|
this.properties = properties;
|
|
449
469
|
}
|
|
@@ -635,6 +655,7 @@ var PropertyResolver = class {
|
|
|
635
655
|
|
|
636
656
|
// server/fastedge-host/SecretStore.ts
|
|
637
657
|
var SecretStore = class {
|
|
658
|
+
secrets;
|
|
638
659
|
constructor(initialSecrets) {
|
|
639
660
|
this.secrets = /* @__PURE__ */ new Map();
|
|
640
661
|
if (initialSecrets) {
|
|
@@ -717,6 +738,7 @@ var SecretStore = class {
|
|
|
717
738
|
|
|
718
739
|
// server/fastedge-host/Dictionary.ts
|
|
719
740
|
var Dictionary = class {
|
|
741
|
+
data;
|
|
720
742
|
constructor(initialData) {
|
|
721
743
|
this.data = /* @__PURE__ */ new Map();
|
|
722
744
|
if (initialData) {
|
|
@@ -884,26 +906,33 @@ function createFastEdgeHostFunctions(memory, secretStore, dictionary, logDebug)
|
|
|
884
906
|
// server/runner/HostFunctions.ts
|
|
885
907
|
var textEncoder3 = new TextEncoder();
|
|
886
908
|
var HostFunctions = class {
|
|
909
|
+
memory;
|
|
910
|
+
propertyResolver;
|
|
911
|
+
propertyAccessControl;
|
|
912
|
+
getCurrentHook;
|
|
913
|
+
logs = [];
|
|
914
|
+
requestHeaders = [];
|
|
915
|
+
responseHeaders = [];
|
|
916
|
+
requestBody = "";
|
|
917
|
+
responseBody = "";
|
|
918
|
+
vmConfig = "";
|
|
919
|
+
pluginConfig = "";
|
|
920
|
+
currentContextId = 1;
|
|
921
|
+
lastHostCall = null;
|
|
922
|
+
debug = false;
|
|
923
|
+
currentLogLevel = 0 /* Trace */;
|
|
924
|
+
// Default to show all logs
|
|
925
|
+
// http_call state
|
|
926
|
+
nextTokenId = 0;
|
|
927
|
+
pendingHttpCall = null;
|
|
928
|
+
httpCallResponse = null;
|
|
929
|
+
streamClosed = false;
|
|
930
|
+
// Local response state (from proxy_send_local_response / send_http_response)
|
|
931
|
+
localResponse = null;
|
|
932
|
+
// FastEdge extensions
|
|
933
|
+
secretStore;
|
|
934
|
+
dictionary;
|
|
887
935
|
constructor(memory, propertyResolver, propertyAccessControl, getCurrentHook, debug = false, secretStore, dictionary) {
|
|
888
|
-
this.logs = [];
|
|
889
|
-
this.requestHeaders = [];
|
|
890
|
-
this.responseHeaders = [];
|
|
891
|
-
this.requestBody = "";
|
|
892
|
-
this.responseBody = "";
|
|
893
|
-
this.vmConfig = "";
|
|
894
|
-
this.pluginConfig = "";
|
|
895
|
-
this.currentContextId = 1;
|
|
896
|
-
this.lastHostCall = null;
|
|
897
|
-
this.debug = false;
|
|
898
|
-
this.currentLogLevel = 0 /* Trace */;
|
|
899
|
-
// Default to show all logs
|
|
900
|
-
// http_call state
|
|
901
|
-
this.nextTokenId = 0;
|
|
902
|
-
this.pendingHttpCall = null;
|
|
903
|
-
this.httpCallResponse = null;
|
|
904
|
-
this.streamClosed = false;
|
|
905
|
-
// Local response state (from proxy_send_local_response / send_http_response)
|
|
906
|
-
this.localResponse = null;
|
|
907
936
|
this.memory = memory;
|
|
908
937
|
this.propertyResolver = propertyResolver;
|
|
909
938
|
this.propertyAccessControl = propertyAccessControl;
|
|
@@ -1634,6 +1663,8 @@ var BUILT_IN_PROPERTIES = [
|
|
|
1634
1663
|
}
|
|
1635
1664
|
];
|
|
1636
1665
|
var PropertyAccessControl = class {
|
|
1666
|
+
builtInProperties;
|
|
1667
|
+
customProperties;
|
|
1637
1668
|
constructor() {
|
|
1638
1669
|
this.builtInProperties = /* @__PURE__ */ new Map();
|
|
1639
1670
|
this.customProperties = /* @__PURE__ */ new Map();
|
|
@@ -1851,21 +1882,28 @@ var textEncoder4 = new TextEncoder();
|
|
|
1851
1882
|
var BUILTIN_URL = "http://fastedge-builtin.debug";
|
|
1852
1883
|
var BUILTIN_SHORTHAND = "built-in";
|
|
1853
1884
|
var ProxyWasmRunner = class {
|
|
1885
|
+
module = null;
|
|
1886
|
+
// Compiled module (reused)
|
|
1887
|
+
instance = null;
|
|
1888
|
+
// Current instance (transient per hook)
|
|
1889
|
+
memory;
|
|
1890
|
+
propertyResolver;
|
|
1891
|
+
propertyAccessControl;
|
|
1892
|
+
currentHook = null;
|
|
1893
|
+
hostFunctions;
|
|
1894
|
+
logs = [];
|
|
1895
|
+
rootContextId = 1;
|
|
1896
|
+
nextContextId = 2;
|
|
1897
|
+
currentContextId = 1;
|
|
1898
|
+
isInitializing = false;
|
|
1899
|
+
debug = process.env.PROXY_RUNNER_DEBUG === "1";
|
|
1900
|
+
stateManager = null;
|
|
1901
|
+
secretStore;
|
|
1902
|
+
dictionary;
|
|
1903
|
+
dotenvEnabled = true;
|
|
1904
|
+
// Default to enabled
|
|
1905
|
+
dotenvPath = ".";
|
|
1854
1906
|
constructor(fastEdgeConfig, dotenvEnabled = true) {
|
|
1855
|
-
this.module = null;
|
|
1856
|
-
// Compiled module (reused)
|
|
1857
|
-
this.instance = null;
|
|
1858
|
-
this.currentHook = null;
|
|
1859
|
-
this.logs = [];
|
|
1860
|
-
this.rootContextId = 1;
|
|
1861
|
-
this.nextContextId = 2;
|
|
1862
|
-
this.currentContextId = 1;
|
|
1863
|
-
this.isInitializing = false;
|
|
1864
|
-
this.debug = process.env.PROXY_RUNNER_DEBUG === "1";
|
|
1865
|
-
this.stateManager = null;
|
|
1866
|
-
this.dotenvEnabled = true;
|
|
1867
|
-
// Default to enabled
|
|
1868
|
-
this.dotenvPath = ".";
|
|
1869
1907
|
this.memory = new MemoryManager();
|
|
1870
1908
|
this.propertyResolver = new PropertyResolver();
|
|
1871
1909
|
this.propertyAccessControl = new PropertyAccessControl();
|
|
@@ -2218,6 +2256,14 @@ var ProxyWasmRunner = class {
|
|
|
2218
2256
|
`Fetch completed: ${responseStatus} ${responseStatusText}`
|
|
2219
2257
|
);
|
|
2220
2258
|
}
|
|
2259
|
+
const requestPhaseResponseHeaders = {
|
|
2260
|
+
...results.onRequestHeaders.output.response.headers ?? {},
|
|
2261
|
+
...results.onRequestBody.output.response.headers ?? {}
|
|
2262
|
+
};
|
|
2263
|
+
const mergedResponseHeaders = HeaderManager.appendMerge(
|
|
2264
|
+
requestPhaseResponseHeaders,
|
|
2265
|
+
responseHeaders
|
|
2266
|
+
);
|
|
2221
2267
|
const responseCall = {
|
|
2222
2268
|
...call,
|
|
2223
2269
|
request: {
|
|
@@ -2226,7 +2272,7 @@ var ProxyWasmRunner = class {
|
|
|
2226
2272
|
body: modifiedRequestBody
|
|
2227
2273
|
},
|
|
2228
2274
|
response: {
|
|
2229
|
-
headers:
|
|
2275
|
+
headers: mergedResponseHeaders,
|
|
2230
2276
|
body: responseBody,
|
|
2231
2277
|
status: responseStatus,
|
|
2232
2278
|
statusText: responseStatusText
|
|
@@ -2248,6 +2294,25 @@ var ProxyWasmRunner = class {
|
|
|
2248
2294
|
"system"
|
|
2249
2295
|
);
|
|
2250
2296
|
}
|
|
2297
|
+
if (results.onResponseHeaders.returnCode === 1 && this.hostFunctions.hasLocalResponse()) {
|
|
2298
|
+
const local = this.hostFunctions.getLocalResponse();
|
|
2299
|
+
const headers = results.onResponseHeaders.output.response.headers;
|
|
2300
|
+
this.hostFunctions.resetLocalResponse();
|
|
2301
|
+
const contentType2 = HeaderManager.firstValue(headers["content-type"]) || "text/plain";
|
|
2302
|
+
const { body, isBase64: isBase642 } = encodeLocalResponseBody(local.body, contentType2);
|
|
2303
|
+
return {
|
|
2304
|
+
hookResults: results,
|
|
2305
|
+
finalResponse: {
|
|
2306
|
+
status: local.statusCode,
|
|
2307
|
+
statusText: local.statusText,
|
|
2308
|
+
headers,
|
|
2309
|
+
body,
|
|
2310
|
+
contentType: contentType2,
|
|
2311
|
+
isBase64: isBase642
|
|
2312
|
+
},
|
|
2313
|
+
calculatedProperties: this.propertyResolver.getCalculatedProperties()
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2251
2316
|
const headersAfterResponseHeaders = results.onResponseHeaders.output.response.headers;
|
|
2252
2317
|
const propertiesAfterResponseHeaders = results.onResponseHeaders.properties;
|
|
2253
2318
|
this.logDebug(
|
|
@@ -2272,6 +2337,25 @@ var ProxyWasmRunner = class {
|
|
|
2272
2337
|
"system"
|
|
2273
2338
|
);
|
|
2274
2339
|
}
|
|
2340
|
+
if (results.onResponseBody.returnCode === 1 && this.hostFunctions.hasLocalResponse()) {
|
|
2341
|
+
const local = this.hostFunctions.getLocalResponse();
|
|
2342
|
+
const headers = results.onResponseBody.output.response.headers;
|
|
2343
|
+
this.hostFunctions.resetLocalResponse();
|
|
2344
|
+
const contentType2 = HeaderManager.firstValue(headers["content-type"]) || "text/plain";
|
|
2345
|
+
const { body, isBase64: isBase642 } = encodeLocalResponseBody(local.body, contentType2);
|
|
2346
|
+
return {
|
|
2347
|
+
hookResults: results,
|
|
2348
|
+
finalResponse: {
|
|
2349
|
+
status: local.statusCode,
|
|
2350
|
+
statusText: local.statusText,
|
|
2351
|
+
headers,
|
|
2352
|
+
body,
|
|
2353
|
+
contentType: contentType2,
|
|
2354
|
+
isBase64: isBase642
|
|
2355
|
+
},
|
|
2356
|
+
calculatedProperties: this.propertyResolver.getCalculatedProperties()
|
|
2357
|
+
};
|
|
2358
|
+
}
|
|
2275
2359
|
const finalHeaders = results.onResponseBody.output.response.headers;
|
|
2276
2360
|
const finalBody = results.onResponseBody.output.response.body;
|
|
2277
2361
|
this.logDebug(`Final response body length: ${finalBody.length}`);
|
|
@@ -2748,7 +2832,7 @@ var ProxyWasmRunner = class {
|
|
|
2748
2832
|
/**
|
|
2749
2833
|
* Not supported for Proxy-WASM (HTTP WASM only)
|
|
2750
2834
|
*/
|
|
2751
|
-
async execute(
|
|
2835
|
+
async execute(_request) {
|
|
2752
2836
|
throw new Error(
|
|
2753
2837
|
"execute() is not supported for Proxy-WASM. Use callHook() or callFullFlow() instead."
|
|
2754
2838
|
);
|
|
@@ -2912,21 +2996,22 @@ async function isLegacySyncWasm(bufferOrPath) {
|
|
|
2912
2996
|
|
|
2913
2997
|
// server/runner/HttpWasmRunner.ts
|
|
2914
2998
|
var HttpWasmRunner = class {
|
|
2999
|
+
process = null;
|
|
3000
|
+
port = null;
|
|
3001
|
+
cliPath = null;
|
|
3002
|
+
tempWasmPath = null;
|
|
3003
|
+
currentWasmPath = null;
|
|
3004
|
+
// resolved path used when spawning
|
|
3005
|
+
logs = [];
|
|
3006
|
+
stateManager = null;
|
|
3007
|
+
portManager;
|
|
3008
|
+
dotenvEnabled = true;
|
|
3009
|
+
dotenvPath = null;
|
|
3010
|
+
/** Pinned ports bypass PortManager allocation and must not be released back to it. */
|
|
3011
|
+
isPinnedPort = false;
|
|
3012
|
+
/** @deprecated Legacy sync support — remove when #[fastedge::http] is retired */
|
|
3013
|
+
isLegacySync = false;
|
|
2915
3014
|
constructor(portManager, dotenvEnabled = true) {
|
|
2916
|
-
this.process = null;
|
|
2917
|
-
this.port = null;
|
|
2918
|
-
this.cliPath = null;
|
|
2919
|
-
this.tempWasmPath = null;
|
|
2920
|
-
this.currentWasmPath = null;
|
|
2921
|
-
// resolved path used when spawning
|
|
2922
|
-
this.logs = [];
|
|
2923
|
-
this.stateManager = null;
|
|
2924
|
-
this.dotenvEnabled = true;
|
|
2925
|
-
this.dotenvPath = null;
|
|
2926
|
-
/** Pinned ports bypass PortManager allocation and must not be released back to it. */
|
|
2927
|
-
this.isPinnedPort = false;
|
|
2928
|
-
/** @deprecated Legacy sync support — remove when #[fastedge::http] is retired */
|
|
2929
|
-
this.isLegacySync = false;
|
|
2930
3015
|
this.portManager = portManager;
|
|
2931
3016
|
this.dotenvEnabled = dotenvEnabled;
|
|
2932
3017
|
}
|
|
@@ -3326,12 +3411,10 @@ function parseFetchHeaders(headers) {
|
|
|
3326
3411
|
// server/runner/PortManager.ts
|
|
3327
3412
|
var import_net = require("net");
|
|
3328
3413
|
var PortManager = class {
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
this.lastAllocatedPort = this.minPort - 1;
|
|
3334
|
-
}
|
|
3414
|
+
minPort = 8100;
|
|
3415
|
+
maxPort = 8199;
|
|
3416
|
+
allocatedPorts = /* @__PURE__ */ new Set();
|
|
3417
|
+
lastAllocatedPort = this.minPort - 1;
|
|
3335
3418
|
/**
|
|
3336
3419
|
* Check whether a port is actually free at the OS level.
|
|
3337
3420
|
* This is necessary when multiple server processes run simultaneously —
|
|
@@ -3391,6 +3474,7 @@ var PortManager = class {
|
|
|
3391
3474
|
|
|
3392
3475
|
// server/runner/WasmRunnerFactory.ts
|
|
3393
3476
|
var WasmRunnerFactory = class {
|
|
3477
|
+
portManager;
|
|
3394
3478
|
constructor() {
|
|
3395
3479
|
this.portManager = new PortManager();
|
|
3396
3480
|
}
|