@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
|
@@ -18446,13 +18446,11 @@ var import_node_wasi = require("node:wasi");
|
|
|
18446
18446
|
var textEncoder = new TextEncoder();
|
|
18447
18447
|
var textDecoder = new TextDecoder();
|
|
18448
18448
|
var MemoryManager = class {
|
|
18449
|
-
|
|
18450
|
-
|
|
18451
|
-
|
|
18452
|
-
|
|
18453
|
-
|
|
18454
|
-
this.isInitializing = false;
|
|
18455
|
-
}
|
|
18449
|
+
memory = null;
|
|
18450
|
+
instance = null;
|
|
18451
|
+
hostAllocOffset = 0;
|
|
18452
|
+
logCallback = null;
|
|
18453
|
+
isInitializing = false;
|
|
18456
18454
|
setMemory(memory) {
|
|
18457
18455
|
this.memory = memory;
|
|
18458
18456
|
}
|
|
@@ -18615,7 +18613,7 @@ var MemoryManager = class {
|
|
|
18615
18613
|
|
|
18616
18614
|
// server/runner/HeaderManager.ts
|
|
18617
18615
|
var textEncoder2 = new TextEncoder();
|
|
18618
|
-
var HeaderManager = class {
|
|
18616
|
+
var HeaderManager = class _HeaderManager {
|
|
18619
18617
|
// Read a header value as a single string. For multi-valued headers (string[]) returns the first.
|
|
18620
18618
|
// Use when callers know the header is conventionally single-valued (content-type, host, location, etc.)
|
|
18621
18619
|
// and need to satisfy APIs that take a string.
|
|
@@ -18638,7 +18636,7 @@ var HeaderManager = class {
|
|
|
18638
18636
|
return flat;
|
|
18639
18637
|
}
|
|
18640
18638
|
static normalize(headers) {
|
|
18641
|
-
const normalized =
|
|
18639
|
+
const normalized = /* @__PURE__ */ Object.create(null);
|
|
18642
18640
|
for (const [key, value] of Object.entries(headers)) {
|
|
18643
18641
|
const k = key.toLowerCase();
|
|
18644
18642
|
if (Array.isArray(value)) {
|
|
@@ -18649,6 +18647,30 @@ var HeaderManager = class {
|
|
|
18649
18647
|
}
|
|
18650
18648
|
return normalized;
|
|
18651
18649
|
}
|
|
18650
|
+
// Append-merge two header records: for keys present in both, values are
|
|
18651
|
+
// concatenated into a string[] rather than the right-hand side overwriting
|
|
18652
|
+
// the left. Keys are lowercased on the way in (consistent with `normalize`).
|
|
18653
|
+
//
|
|
18654
|
+
// Used by the runner to combine request-phase response-header state with
|
|
18655
|
+
// the origin's response headers, mirroring how Envoy serves
|
|
18656
|
+
// `add_http_response_header` calls issued during onRequestHeaders /
|
|
18657
|
+
// onRequestBody against the actual upstream response — both values survive
|
|
18658
|
+
// as a multi-value list (preserving the proxy-wasm cross-phase pattern).
|
|
18659
|
+
static appendMerge(left, right) {
|
|
18660
|
+
const result = _HeaderManager.normalize(left);
|
|
18661
|
+
for (const [key, value] of Object.entries(right)) {
|
|
18662
|
+
const k = key.toLowerCase();
|
|
18663
|
+
const incoming = Array.isArray(value) ? value.map(String) : [String(value)];
|
|
18664
|
+
if (Object.hasOwn(result, k)) {
|
|
18665
|
+
const existing = result[k];
|
|
18666
|
+
const existingArr = Array.isArray(existing) ? existing : [existing];
|
|
18667
|
+
result[k] = [...existingArr, ...incoming];
|
|
18668
|
+
} else {
|
|
18669
|
+
result[k] = incoming.length === 1 ? incoming[0] : incoming;
|
|
18670
|
+
}
|
|
18671
|
+
}
|
|
18672
|
+
return result;
|
|
18673
|
+
}
|
|
18652
18674
|
static serialize(headers) {
|
|
18653
18675
|
const pairs = Object.entries(headers);
|
|
18654
18676
|
const numPairs = pairs.length;
|
|
@@ -18827,20 +18849,18 @@ var HeaderManager = class {
|
|
|
18827
18849
|
|
|
18828
18850
|
// server/runner/PropertyResolver.ts
|
|
18829
18851
|
var PropertyResolver = class {
|
|
18830
|
-
|
|
18831
|
-
|
|
18832
|
-
|
|
18833
|
-
|
|
18834
|
-
|
|
18835
|
-
|
|
18836
|
-
|
|
18837
|
-
|
|
18838
|
-
|
|
18839
|
-
|
|
18840
|
-
|
|
18841
|
-
|
|
18842
|
-
this.responseStatusText = "OK";
|
|
18843
|
-
}
|
|
18852
|
+
properties = {};
|
|
18853
|
+
requestHeaders = {};
|
|
18854
|
+
requestMethod = "GET";
|
|
18855
|
+
requestPath = "/";
|
|
18856
|
+
requestScheme = "https";
|
|
18857
|
+
requestUrl = "";
|
|
18858
|
+
requestHost = "";
|
|
18859
|
+
requestQuery = "";
|
|
18860
|
+
requestExtension = "";
|
|
18861
|
+
responseHeaders = {};
|
|
18862
|
+
responseStatus = 200;
|
|
18863
|
+
responseStatusText = "OK";
|
|
18844
18864
|
setProperties(properties) {
|
|
18845
18865
|
this.properties = properties;
|
|
18846
18866
|
}
|
|
@@ -19032,6 +19052,7 @@ var PropertyResolver = class {
|
|
|
19032
19052
|
|
|
19033
19053
|
// server/fastedge-host/SecretStore.ts
|
|
19034
19054
|
var SecretStore = class {
|
|
19055
|
+
secrets;
|
|
19035
19056
|
constructor(initialSecrets) {
|
|
19036
19057
|
this.secrets = /* @__PURE__ */ new Map();
|
|
19037
19058
|
if (initialSecrets) {
|
|
@@ -19114,6 +19135,7 @@ var SecretStore = class {
|
|
|
19114
19135
|
|
|
19115
19136
|
// server/fastedge-host/Dictionary.ts
|
|
19116
19137
|
var Dictionary = class {
|
|
19138
|
+
data;
|
|
19117
19139
|
constructor(initialData) {
|
|
19118
19140
|
this.data = /* @__PURE__ */ new Map();
|
|
19119
19141
|
if (initialData) {
|
|
@@ -19281,26 +19303,33 @@ function createFastEdgeHostFunctions(memory, secretStore, dictionary, logDebug)
|
|
|
19281
19303
|
// server/runner/HostFunctions.ts
|
|
19282
19304
|
var textEncoder3 = new TextEncoder();
|
|
19283
19305
|
var HostFunctions = class {
|
|
19306
|
+
memory;
|
|
19307
|
+
propertyResolver;
|
|
19308
|
+
propertyAccessControl;
|
|
19309
|
+
getCurrentHook;
|
|
19310
|
+
logs = [];
|
|
19311
|
+
requestHeaders = [];
|
|
19312
|
+
responseHeaders = [];
|
|
19313
|
+
requestBody = "";
|
|
19314
|
+
responseBody = "";
|
|
19315
|
+
vmConfig = "";
|
|
19316
|
+
pluginConfig = "";
|
|
19317
|
+
currentContextId = 1;
|
|
19318
|
+
lastHostCall = null;
|
|
19319
|
+
debug = false;
|
|
19320
|
+
currentLogLevel = 0 /* Trace */;
|
|
19321
|
+
// Default to show all logs
|
|
19322
|
+
// http_call state
|
|
19323
|
+
nextTokenId = 0;
|
|
19324
|
+
pendingHttpCall = null;
|
|
19325
|
+
httpCallResponse = null;
|
|
19326
|
+
streamClosed = false;
|
|
19327
|
+
// Local response state (from proxy_send_local_response / send_http_response)
|
|
19328
|
+
localResponse = null;
|
|
19329
|
+
// FastEdge extensions
|
|
19330
|
+
secretStore;
|
|
19331
|
+
dictionary;
|
|
19284
19332
|
constructor(memory, propertyResolver, propertyAccessControl, getCurrentHook, debug = false, secretStore, dictionary) {
|
|
19285
|
-
this.logs = [];
|
|
19286
|
-
this.requestHeaders = [];
|
|
19287
|
-
this.responseHeaders = [];
|
|
19288
|
-
this.requestBody = "";
|
|
19289
|
-
this.responseBody = "";
|
|
19290
|
-
this.vmConfig = "";
|
|
19291
|
-
this.pluginConfig = "";
|
|
19292
|
-
this.currentContextId = 1;
|
|
19293
|
-
this.lastHostCall = null;
|
|
19294
|
-
this.debug = false;
|
|
19295
|
-
this.currentLogLevel = 0 /* Trace */;
|
|
19296
|
-
// Default to show all logs
|
|
19297
|
-
// http_call state
|
|
19298
|
-
this.nextTokenId = 0;
|
|
19299
|
-
this.pendingHttpCall = null;
|
|
19300
|
-
this.httpCallResponse = null;
|
|
19301
|
-
this.streamClosed = false;
|
|
19302
|
-
// Local response state (from proxy_send_local_response / send_http_response)
|
|
19303
|
-
this.localResponse = null;
|
|
19304
19333
|
this.memory = memory;
|
|
19305
19334
|
this.propertyResolver = propertyResolver;
|
|
19306
19335
|
this.propertyAccessControl = propertyAccessControl;
|
|
@@ -20031,6 +20060,8 @@ var BUILT_IN_PROPERTIES = [
|
|
|
20031
20060
|
}
|
|
20032
20061
|
];
|
|
20033
20062
|
var PropertyAccessControl = class {
|
|
20063
|
+
builtInProperties;
|
|
20064
|
+
customProperties;
|
|
20034
20065
|
constructor() {
|
|
20035
20066
|
this.builtInProperties = /* @__PURE__ */ new Map();
|
|
20036
20067
|
this.customProperties = /* @__PURE__ */ new Map();
|
|
@@ -20248,21 +20279,28 @@ var textEncoder4 = new TextEncoder();
|
|
|
20248
20279
|
var BUILTIN_URL = "http://fastedge-builtin.debug";
|
|
20249
20280
|
var BUILTIN_SHORTHAND = "built-in";
|
|
20250
20281
|
var ProxyWasmRunner = class {
|
|
20282
|
+
module = null;
|
|
20283
|
+
// Compiled module (reused)
|
|
20284
|
+
instance = null;
|
|
20285
|
+
// Current instance (transient per hook)
|
|
20286
|
+
memory;
|
|
20287
|
+
propertyResolver;
|
|
20288
|
+
propertyAccessControl;
|
|
20289
|
+
currentHook = null;
|
|
20290
|
+
hostFunctions;
|
|
20291
|
+
logs = [];
|
|
20292
|
+
rootContextId = 1;
|
|
20293
|
+
nextContextId = 2;
|
|
20294
|
+
currentContextId = 1;
|
|
20295
|
+
isInitializing = false;
|
|
20296
|
+
debug = process.env.PROXY_RUNNER_DEBUG === "1";
|
|
20297
|
+
stateManager = null;
|
|
20298
|
+
secretStore;
|
|
20299
|
+
dictionary;
|
|
20300
|
+
dotenvEnabled = true;
|
|
20301
|
+
// Default to enabled
|
|
20302
|
+
dotenvPath = ".";
|
|
20251
20303
|
constructor(fastEdgeConfig, dotenvEnabled = true) {
|
|
20252
|
-
this.module = null;
|
|
20253
|
-
// Compiled module (reused)
|
|
20254
|
-
this.instance = null;
|
|
20255
|
-
this.currentHook = null;
|
|
20256
|
-
this.logs = [];
|
|
20257
|
-
this.rootContextId = 1;
|
|
20258
|
-
this.nextContextId = 2;
|
|
20259
|
-
this.currentContextId = 1;
|
|
20260
|
-
this.isInitializing = false;
|
|
20261
|
-
this.debug = process.env.PROXY_RUNNER_DEBUG === "1";
|
|
20262
|
-
this.stateManager = null;
|
|
20263
|
-
this.dotenvEnabled = true;
|
|
20264
|
-
// Default to enabled
|
|
20265
|
-
this.dotenvPath = ".";
|
|
20266
20304
|
this.memory = new MemoryManager();
|
|
20267
20305
|
this.propertyResolver = new PropertyResolver();
|
|
20268
20306
|
this.propertyAccessControl = new PropertyAccessControl();
|
|
@@ -20615,6 +20653,14 @@ var ProxyWasmRunner = class {
|
|
|
20615
20653
|
`Fetch completed: ${responseStatus} ${responseStatusText}`
|
|
20616
20654
|
);
|
|
20617
20655
|
}
|
|
20656
|
+
const requestPhaseResponseHeaders = {
|
|
20657
|
+
...results.onRequestHeaders.output.response.headers ?? {},
|
|
20658
|
+
...results.onRequestBody.output.response.headers ?? {}
|
|
20659
|
+
};
|
|
20660
|
+
const mergedResponseHeaders = HeaderManager.appendMerge(
|
|
20661
|
+
requestPhaseResponseHeaders,
|
|
20662
|
+
responseHeaders
|
|
20663
|
+
);
|
|
20618
20664
|
const responseCall = {
|
|
20619
20665
|
...call,
|
|
20620
20666
|
request: {
|
|
@@ -20623,7 +20669,7 @@ var ProxyWasmRunner = class {
|
|
|
20623
20669
|
body: modifiedRequestBody
|
|
20624
20670
|
},
|
|
20625
20671
|
response: {
|
|
20626
|
-
headers:
|
|
20672
|
+
headers: mergedResponseHeaders,
|
|
20627
20673
|
body: responseBody,
|
|
20628
20674
|
status: responseStatus,
|
|
20629
20675
|
statusText: responseStatusText
|
|
@@ -20645,6 +20691,25 @@ var ProxyWasmRunner = class {
|
|
|
20645
20691
|
"system"
|
|
20646
20692
|
);
|
|
20647
20693
|
}
|
|
20694
|
+
if (results.onResponseHeaders.returnCode === 1 && this.hostFunctions.hasLocalResponse()) {
|
|
20695
|
+
const local = this.hostFunctions.getLocalResponse();
|
|
20696
|
+
const headers = results.onResponseHeaders.output.response.headers;
|
|
20697
|
+
this.hostFunctions.resetLocalResponse();
|
|
20698
|
+
const contentType2 = HeaderManager.firstValue(headers["content-type"]) || "text/plain";
|
|
20699
|
+
const { body, isBase64: isBase642 } = encodeLocalResponseBody(local.body, contentType2);
|
|
20700
|
+
return {
|
|
20701
|
+
hookResults: results,
|
|
20702
|
+
finalResponse: {
|
|
20703
|
+
status: local.statusCode,
|
|
20704
|
+
statusText: local.statusText,
|
|
20705
|
+
headers,
|
|
20706
|
+
body,
|
|
20707
|
+
contentType: contentType2,
|
|
20708
|
+
isBase64: isBase642
|
|
20709
|
+
},
|
|
20710
|
+
calculatedProperties: this.propertyResolver.getCalculatedProperties()
|
|
20711
|
+
};
|
|
20712
|
+
}
|
|
20648
20713
|
const headersAfterResponseHeaders = results.onResponseHeaders.output.response.headers;
|
|
20649
20714
|
const propertiesAfterResponseHeaders = results.onResponseHeaders.properties;
|
|
20650
20715
|
this.logDebug(
|
|
@@ -20669,6 +20734,25 @@ var ProxyWasmRunner = class {
|
|
|
20669
20734
|
"system"
|
|
20670
20735
|
);
|
|
20671
20736
|
}
|
|
20737
|
+
if (results.onResponseBody.returnCode === 1 && this.hostFunctions.hasLocalResponse()) {
|
|
20738
|
+
const local = this.hostFunctions.getLocalResponse();
|
|
20739
|
+
const headers = results.onResponseBody.output.response.headers;
|
|
20740
|
+
this.hostFunctions.resetLocalResponse();
|
|
20741
|
+
const contentType2 = HeaderManager.firstValue(headers["content-type"]) || "text/plain";
|
|
20742
|
+
const { body, isBase64: isBase642 } = encodeLocalResponseBody(local.body, contentType2);
|
|
20743
|
+
return {
|
|
20744
|
+
hookResults: results,
|
|
20745
|
+
finalResponse: {
|
|
20746
|
+
status: local.statusCode,
|
|
20747
|
+
statusText: local.statusText,
|
|
20748
|
+
headers,
|
|
20749
|
+
body,
|
|
20750
|
+
contentType: contentType2,
|
|
20751
|
+
isBase64: isBase642
|
|
20752
|
+
},
|
|
20753
|
+
calculatedProperties: this.propertyResolver.getCalculatedProperties()
|
|
20754
|
+
};
|
|
20755
|
+
}
|
|
20672
20756
|
const finalHeaders = results.onResponseBody.output.response.headers;
|
|
20673
20757
|
const finalBody = results.onResponseBody.output.response.body;
|
|
20674
20758
|
this.logDebug(`Final response body length: ${finalBody.length}`);
|
|
@@ -21145,7 +21229,7 @@ var ProxyWasmRunner = class {
|
|
|
21145
21229
|
/**
|
|
21146
21230
|
* Not supported for Proxy-WASM (HTTP WASM only)
|
|
21147
21231
|
*/
|
|
21148
|
-
async execute(
|
|
21232
|
+
async execute(_request) {
|
|
21149
21233
|
throw new Error(
|
|
21150
21234
|
"execute() is not supported for Proxy-WASM. Use callHook() or callFullFlow() instead."
|
|
21151
21235
|
);
|
|
@@ -21309,21 +21393,22 @@ async function isLegacySyncWasm(bufferOrPath) {
|
|
|
21309
21393
|
|
|
21310
21394
|
// server/runner/HttpWasmRunner.ts
|
|
21311
21395
|
var HttpWasmRunner = class {
|
|
21396
|
+
process = null;
|
|
21397
|
+
port = null;
|
|
21398
|
+
cliPath = null;
|
|
21399
|
+
tempWasmPath = null;
|
|
21400
|
+
currentWasmPath = null;
|
|
21401
|
+
// resolved path used when spawning
|
|
21402
|
+
logs = [];
|
|
21403
|
+
stateManager = null;
|
|
21404
|
+
portManager;
|
|
21405
|
+
dotenvEnabled = true;
|
|
21406
|
+
dotenvPath = null;
|
|
21407
|
+
/** Pinned ports bypass PortManager allocation and must not be released back to it. */
|
|
21408
|
+
isPinnedPort = false;
|
|
21409
|
+
/** @deprecated Legacy sync support — remove when #[fastedge::http] is retired */
|
|
21410
|
+
isLegacySync = false;
|
|
21312
21411
|
constructor(portManager, dotenvEnabled = true) {
|
|
21313
|
-
this.process = null;
|
|
21314
|
-
this.port = null;
|
|
21315
|
-
this.cliPath = null;
|
|
21316
|
-
this.tempWasmPath = null;
|
|
21317
|
-
this.currentWasmPath = null;
|
|
21318
|
-
// resolved path used when spawning
|
|
21319
|
-
this.logs = [];
|
|
21320
|
-
this.stateManager = null;
|
|
21321
|
-
this.dotenvEnabled = true;
|
|
21322
|
-
this.dotenvPath = null;
|
|
21323
|
-
/** Pinned ports bypass PortManager allocation and must not be released back to it. */
|
|
21324
|
-
this.isPinnedPort = false;
|
|
21325
|
-
/** @deprecated Legacy sync support — remove when #[fastedge::http] is retired */
|
|
21326
|
-
this.isLegacySync = false;
|
|
21327
21412
|
this.portManager = portManager;
|
|
21328
21413
|
this.dotenvEnabled = dotenvEnabled;
|
|
21329
21414
|
}
|
|
@@ -21723,12 +21808,10 @@ function parseFetchHeaders(headers) {
|
|
|
21723
21808
|
// server/runner/PortManager.ts
|
|
21724
21809
|
var import_net = require("net");
|
|
21725
21810
|
var PortManager = class {
|
|
21726
|
-
|
|
21727
|
-
|
|
21728
|
-
|
|
21729
|
-
|
|
21730
|
-
this.lastAllocatedPort = this.minPort - 1;
|
|
21731
|
-
}
|
|
21811
|
+
minPort = 8100;
|
|
21812
|
+
maxPort = 8199;
|
|
21813
|
+
allocatedPorts = /* @__PURE__ */ new Set();
|
|
21814
|
+
lastAllocatedPort = this.minPort - 1;
|
|
21732
21815
|
/**
|
|
21733
21816
|
* Check whether a port is actually free at the OS level.
|
|
21734
21817
|
* This is necessary when multiple server processes run simultaneously —
|