@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
|
@@ -18410,13 +18410,11 @@ import { WASI } from "node:wasi";
|
|
|
18410
18410
|
var textEncoder = new TextEncoder();
|
|
18411
18411
|
var textDecoder = new TextDecoder();
|
|
18412
18412
|
var MemoryManager = class {
|
|
18413
|
-
|
|
18414
|
-
|
|
18415
|
-
|
|
18416
|
-
|
|
18417
|
-
|
|
18418
|
-
this.isInitializing = false;
|
|
18419
|
-
}
|
|
18413
|
+
memory = null;
|
|
18414
|
+
instance = null;
|
|
18415
|
+
hostAllocOffset = 0;
|
|
18416
|
+
logCallback = null;
|
|
18417
|
+
isInitializing = false;
|
|
18420
18418
|
setMemory(memory) {
|
|
18421
18419
|
this.memory = memory;
|
|
18422
18420
|
}
|
|
@@ -18579,7 +18577,7 @@ var MemoryManager = class {
|
|
|
18579
18577
|
|
|
18580
18578
|
// server/runner/HeaderManager.ts
|
|
18581
18579
|
var textEncoder2 = new TextEncoder();
|
|
18582
|
-
var HeaderManager = class {
|
|
18580
|
+
var HeaderManager = class _HeaderManager {
|
|
18583
18581
|
// Read a header value as a single string. For multi-valued headers (string[]) returns the first.
|
|
18584
18582
|
// Use when callers know the header is conventionally single-valued (content-type, host, location, etc.)
|
|
18585
18583
|
// and need to satisfy APIs that take a string.
|
|
@@ -18602,7 +18600,7 @@ var HeaderManager = class {
|
|
|
18602
18600
|
return flat;
|
|
18603
18601
|
}
|
|
18604
18602
|
static normalize(headers) {
|
|
18605
|
-
const normalized =
|
|
18603
|
+
const normalized = /* @__PURE__ */ Object.create(null);
|
|
18606
18604
|
for (const [key, value] of Object.entries(headers)) {
|
|
18607
18605
|
const k = key.toLowerCase();
|
|
18608
18606
|
if (Array.isArray(value)) {
|
|
@@ -18613,6 +18611,30 @@ var HeaderManager = class {
|
|
|
18613
18611
|
}
|
|
18614
18612
|
return normalized;
|
|
18615
18613
|
}
|
|
18614
|
+
// Append-merge two header records: for keys present in both, values are
|
|
18615
|
+
// concatenated into a string[] rather than the right-hand side overwriting
|
|
18616
|
+
// the left. Keys are lowercased on the way in (consistent with `normalize`).
|
|
18617
|
+
//
|
|
18618
|
+
// Used by the runner to combine request-phase response-header state with
|
|
18619
|
+
// the origin's response headers, mirroring how Envoy serves
|
|
18620
|
+
// `add_http_response_header` calls issued during onRequestHeaders /
|
|
18621
|
+
// onRequestBody against the actual upstream response — both values survive
|
|
18622
|
+
// as a multi-value list (preserving the proxy-wasm cross-phase pattern).
|
|
18623
|
+
static appendMerge(left, right) {
|
|
18624
|
+
const result = _HeaderManager.normalize(left);
|
|
18625
|
+
for (const [key, value] of Object.entries(right)) {
|
|
18626
|
+
const k = key.toLowerCase();
|
|
18627
|
+
const incoming = Array.isArray(value) ? value.map(String) : [String(value)];
|
|
18628
|
+
if (Object.hasOwn(result, k)) {
|
|
18629
|
+
const existing = result[k];
|
|
18630
|
+
const existingArr = Array.isArray(existing) ? existing : [existing];
|
|
18631
|
+
result[k] = [...existingArr, ...incoming];
|
|
18632
|
+
} else {
|
|
18633
|
+
result[k] = incoming.length === 1 ? incoming[0] : incoming;
|
|
18634
|
+
}
|
|
18635
|
+
}
|
|
18636
|
+
return result;
|
|
18637
|
+
}
|
|
18616
18638
|
static serialize(headers) {
|
|
18617
18639
|
const pairs = Object.entries(headers);
|
|
18618
18640
|
const numPairs = pairs.length;
|
|
@@ -18791,20 +18813,18 @@ var HeaderManager = class {
|
|
|
18791
18813
|
|
|
18792
18814
|
// server/runner/PropertyResolver.ts
|
|
18793
18815
|
var PropertyResolver = class {
|
|
18794
|
-
|
|
18795
|
-
|
|
18796
|
-
|
|
18797
|
-
|
|
18798
|
-
|
|
18799
|
-
|
|
18800
|
-
|
|
18801
|
-
|
|
18802
|
-
|
|
18803
|
-
|
|
18804
|
-
|
|
18805
|
-
|
|
18806
|
-
this.responseStatusText = "OK";
|
|
18807
|
-
}
|
|
18816
|
+
properties = {};
|
|
18817
|
+
requestHeaders = {};
|
|
18818
|
+
requestMethod = "GET";
|
|
18819
|
+
requestPath = "/";
|
|
18820
|
+
requestScheme = "https";
|
|
18821
|
+
requestUrl = "";
|
|
18822
|
+
requestHost = "";
|
|
18823
|
+
requestQuery = "";
|
|
18824
|
+
requestExtension = "";
|
|
18825
|
+
responseHeaders = {};
|
|
18826
|
+
responseStatus = 200;
|
|
18827
|
+
responseStatusText = "OK";
|
|
18808
18828
|
setProperties(properties) {
|
|
18809
18829
|
this.properties = properties;
|
|
18810
18830
|
}
|
|
@@ -18996,6 +19016,7 @@ var PropertyResolver = class {
|
|
|
18996
19016
|
|
|
18997
19017
|
// server/fastedge-host/SecretStore.ts
|
|
18998
19018
|
var SecretStore = class {
|
|
19019
|
+
secrets;
|
|
18999
19020
|
constructor(initialSecrets) {
|
|
19000
19021
|
this.secrets = /* @__PURE__ */ new Map();
|
|
19001
19022
|
if (initialSecrets) {
|
|
@@ -19078,6 +19099,7 @@ var SecretStore = class {
|
|
|
19078
19099
|
|
|
19079
19100
|
// server/fastedge-host/Dictionary.ts
|
|
19080
19101
|
var Dictionary = class {
|
|
19102
|
+
data;
|
|
19081
19103
|
constructor(initialData) {
|
|
19082
19104
|
this.data = /* @__PURE__ */ new Map();
|
|
19083
19105
|
if (initialData) {
|
|
@@ -19245,26 +19267,33 @@ function createFastEdgeHostFunctions(memory, secretStore, dictionary, logDebug)
|
|
|
19245
19267
|
// server/runner/HostFunctions.ts
|
|
19246
19268
|
var textEncoder3 = new TextEncoder();
|
|
19247
19269
|
var HostFunctions = class {
|
|
19270
|
+
memory;
|
|
19271
|
+
propertyResolver;
|
|
19272
|
+
propertyAccessControl;
|
|
19273
|
+
getCurrentHook;
|
|
19274
|
+
logs = [];
|
|
19275
|
+
requestHeaders = [];
|
|
19276
|
+
responseHeaders = [];
|
|
19277
|
+
requestBody = "";
|
|
19278
|
+
responseBody = "";
|
|
19279
|
+
vmConfig = "";
|
|
19280
|
+
pluginConfig = "";
|
|
19281
|
+
currentContextId = 1;
|
|
19282
|
+
lastHostCall = null;
|
|
19283
|
+
debug = false;
|
|
19284
|
+
currentLogLevel = 0 /* Trace */;
|
|
19285
|
+
// Default to show all logs
|
|
19286
|
+
// http_call state
|
|
19287
|
+
nextTokenId = 0;
|
|
19288
|
+
pendingHttpCall = null;
|
|
19289
|
+
httpCallResponse = null;
|
|
19290
|
+
streamClosed = false;
|
|
19291
|
+
// Local response state (from proxy_send_local_response / send_http_response)
|
|
19292
|
+
localResponse = null;
|
|
19293
|
+
// FastEdge extensions
|
|
19294
|
+
secretStore;
|
|
19295
|
+
dictionary;
|
|
19248
19296
|
constructor(memory, propertyResolver, propertyAccessControl, getCurrentHook, debug = false, secretStore, dictionary) {
|
|
19249
|
-
this.logs = [];
|
|
19250
|
-
this.requestHeaders = [];
|
|
19251
|
-
this.responseHeaders = [];
|
|
19252
|
-
this.requestBody = "";
|
|
19253
|
-
this.responseBody = "";
|
|
19254
|
-
this.vmConfig = "";
|
|
19255
|
-
this.pluginConfig = "";
|
|
19256
|
-
this.currentContextId = 1;
|
|
19257
|
-
this.lastHostCall = null;
|
|
19258
|
-
this.debug = false;
|
|
19259
|
-
this.currentLogLevel = 0 /* Trace */;
|
|
19260
|
-
// Default to show all logs
|
|
19261
|
-
// http_call state
|
|
19262
|
-
this.nextTokenId = 0;
|
|
19263
|
-
this.pendingHttpCall = null;
|
|
19264
|
-
this.httpCallResponse = null;
|
|
19265
|
-
this.streamClosed = false;
|
|
19266
|
-
// Local response state (from proxy_send_local_response / send_http_response)
|
|
19267
|
-
this.localResponse = null;
|
|
19268
19297
|
this.memory = memory;
|
|
19269
19298
|
this.propertyResolver = propertyResolver;
|
|
19270
19299
|
this.propertyAccessControl = propertyAccessControl;
|
|
@@ -19995,6 +20024,8 @@ var BUILT_IN_PROPERTIES = [
|
|
|
19995
20024
|
}
|
|
19996
20025
|
];
|
|
19997
20026
|
var PropertyAccessControl = class {
|
|
20027
|
+
builtInProperties;
|
|
20028
|
+
customProperties;
|
|
19998
20029
|
constructor() {
|
|
19999
20030
|
this.builtInProperties = /* @__PURE__ */ new Map();
|
|
20000
20031
|
this.customProperties = /* @__PURE__ */ new Map();
|
|
@@ -20212,21 +20243,28 @@ var textEncoder4 = new TextEncoder();
|
|
|
20212
20243
|
var BUILTIN_URL = "http://fastedge-builtin.debug";
|
|
20213
20244
|
var BUILTIN_SHORTHAND = "built-in";
|
|
20214
20245
|
var ProxyWasmRunner = class {
|
|
20246
|
+
module = null;
|
|
20247
|
+
// Compiled module (reused)
|
|
20248
|
+
instance = null;
|
|
20249
|
+
// Current instance (transient per hook)
|
|
20250
|
+
memory;
|
|
20251
|
+
propertyResolver;
|
|
20252
|
+
propertyAccessControl;
|
|
20253
|
+
currentHook = null;
|
|
20254
|
+
hostFunctions;
|
|
20255
|
+
logs = [];
|
|
20256
|
+
rootContextId = 1;
|
|
20257
|
+
nextContextId = 2;
|
|
20258
|
+
currentContextId = 1;
|
|
20259
|
+
isInitializing = false;
|
|
20260
|
+
debug = process.env.PROXY_RUNNER_DEBUG === "1";
|
|
20261
|
+
stateManager = null;
|
|
20262
|
+
secretStore;
|
|
20263
|
+
dictionary;
|
|
20264
|
+
dotenvEnabled = true;
|
|
20265
|
+
// Default to enabled
|
|
20266
|
+
dotenvPath = ".";
|
|
20215
20267
|
constructor(fastEdgeConfig, dotenvEnabled = true) {
|
|
20216
|
-
this.module = null;
|
|
20217
|
-
// Compiled module (reused)
|
|
20218
|
-
this.instance = null;
|
|
20219
|
-
this.currentHook = null;
|
|
20220
|
-
this.logs = [];
|
|
20221
|
-
this.rootContextId = 1;
|
|
20222
|
-
this.nextContextId = 2;
|
|
20223
|
-
this.currentContextId = 1;
|
|
20224
|
-
this.isInitializing = false;
|
|
20225
|
-
this.debug = process.env.PROXY_RUNNER_DEBUG === "1";
|
|
20226
|
-
this.stateManager = null;
|
|
20227
|
-
this.dotenvEnabled = true;
|
|
20228
|
-
// Default to enabled
|
|
20229
|
-
this.dotenvPath = ".";
|
|
20230
20268
|
this.memory = new MemoryManager();
|
|
20231
20269
|
this.propertyResolver = new PropertyResolver();
|
|
20232
20270
|
this.propertyAccessControl = new PropertyAccessControl();
|
|
@@ -20579,6 +20617,14 @@ var ProxyWasmRunner = class {
|
|
|
20579
20617
|
`Fetch completed: ${responseStatus} ${responseStatusText}`
|
|
20580
20618
|
);
|
|
20581
20619
|
}
|
|
20620
|
+
const requestPhaseResponseHeaders = {
|
|
20621
|
+
...results.onRequestHeaders.output.response.headers ?? {},
|
|
20622
|
+
...results.onRequestBody.output.response.headers ?? {}
|
|
20623
|
+
};
|
|
20624
|
+
const mergedResponseHeaders = HeaderManager.appendMerge(
|
|
20625
|
+
requestPhaseResponseHeaders,
|
|
20626
|
+
responseHeaders
|
|
20627
|
+
);
|
|
20582
20628
|
const responseCall = {
|
|
20583
20629
|
...call,
|
|
20584
20630
|
request: {
|
|
@@ -20587,7 +20633,7 @@ var ProxyWasmRunner = class {
|
|
|
20587
20633
|
body: modifiedRequestBody
|
|
20588
20634
|
},
|
|
20589
20635
|
response: {
|
|
20590
|
-
headers:
|
|
20636
|
+
headers: mergedResponseHeaders,
|
|
20591
20637
|
body: responseBody,
|
|
20592
20638
|
status: responseStatus,
|
|
20593
20639
|
statusText: responseStatusText
|
|
@@ -20609,6 +20655,25 @@ var ProxyWasmRunner = class {
|
|
|
20609
20655
|
"system"
|
|
20610
20656
|
);
|
|
20611
20657
|
}
|
|
20658
|
+
if (results.onResponseHeaders.returnCode === 1 && this.hostFunctions.hasLocalResponse()) {
|
|
20659
|
+
const local = this.hostFunctions.getLocalResponse();
|
|
20660
|
+
const headers = results.onResponseHeaders.output.response.headers;
|
|
20661
|
+
this.hostFunctions.resetLocalResponse();
|
|
20662
|
+
const contentType2 = HeaderManager.firstValue(headers["content-type"]) || "text/plain";
|
|
20663
|
+
const { body, isBase64: isBase642 } = encodeLocalResponseBody(local.body, contentType2);
|
|
20664
|
+
return {
|
|
20665
|
+
hookResults: results,
|
|
20666
|
+
finalResponse: {
|
|
20667
|
+
status: local.statusCode,
|
|
20668
|
+
statusText: local.statusText,
|
|
20669
|
+
headers,
|
|
20670
|
+
body,
|
|
20671
|
+
contentType: contentType2,
|
|
20672
|
+
isBase64: isBase642
|
|
20673
|
+
},
|
|
20674
|
+
calculatedProperties: this.propertyResolver.getCalculatedProperties()
|
|
20675
|
+
};
|
|
20676
|
+
}
|
|
20612
20677
|
const headersAfterResponseHeaders = results.onResponseHeaders.output.response.headers;
|
|
20613
20678
|
const propertiesAfterResponseHeaders = results.onResponseHeaders.properties;
|
|
20614
20679
|
this.logDebug(
|
|
@@ -20633,6 +20698,25 @@ var ProxyWasmRunner = class {
|
|
|
20633
20698
|
"system"
|
|
20634
20699
|
);
|
|
20635
20700
|
}
|
|
20701
|
+
if (results.onResponseBody.returnCode === 1 && this.hostFunctions.hasLocalResponse()) {
|
|
20702
|
+
const local = this.hostFunctions.getLocalResponse();
|
|
20703
|
+
const headers = results.onResponseBody.output.response.headers;
|
|
20704
|
+
this.hostFunctions.resetLocalResponse();
|
|
20705
|
+
const contentType2 = HeaderManager.firstValue(headers["content-type"]) || "text/plain";
|
|
20706
|
+
const { body, isBase64: isBase642 } = encodeLocalResponseBody(local.body, contentType2);
|
|
20707
|
+
return {
|
|
20708
|
+
hookResults: results,
|
|
20709
|
+
finalResponse: {
|
|
20710
|
+
status: local.statusCode,
|
|
20711
|
+
statusText: local.statusText,
|
|
20712
|
+
headers,
|
|
20713
|
+
body,
|
|
20714
|
+
contentType: contentType2,
|
|
20715
|
+
isBase64: isBase642
|
|
20716
|
+
},
|
|
20717
|
+
calculatedProperties: this.propertyResolver.getCalculatedProperties()
|
|
20718
|
+
};
|
|
20719
|
+
}
|
|
20636
20720
|
const finalHeaders = results.onResponseBody.output.response.headers;
|
|
20637
20721
|
const finalBody = results.onResponseBody.output.response.body;
|
|
20638
20722
|
this.logDebug(`Final response body length: ${finalBody.length}`);
|
|
@@ -21109,7 +21193,7 @@ var ProxyWasmRunner = class {
|
|
|
21109
21193
|
/**
|
|
21110
21194
|
* Not supported for Proxy-WASM (HTTP WASM only)
|
|
21111
21195
|
*/
|
|
21112
|
-
async execute(
|
|
21196
|
+
async execute(_request) {
|
|
21113
21197
|
throw new Error(
|
|
21114
21198
|
"execute() is not supported for Proxy-WASM. Use callHook() or callFullFlow() instead."
|
|
21115
21199
|
);
|
|
@@ -21273,21 +21357,22 @@ async function isLegacySyncWasm(bufferOrPath) {
|
|
|
21273
21357
|
|
|
21274
21358
|
// server/runner/HttpWasmRunner.ts
|
|
21275
21359
|
var HttpWasmRunner = class {
|
|
21360
|
+
process = null;
|
|
21361
|
+
port = null;
|
|
21362
|
+
cliPath = null;
|
|
21363
|
+
tempWasmPath = null;
|
|
21364
|
+
currentWasmPath = null;
|
|
21365
|
+
// resolved path used when spawning
|
|
21366
|
+
logs = [];
|
|
21367
|
+
stateManager = null;
|
|
21368
|
+
portManager;
|
|
21369
|
+
dotenvEnabled = true;
|
|
21370
|
+
dotenvPath = null;
|
|
21371
|
+
/** Pinned ports bypass PortManager allocation and must not be released back to it. */
|
|
21372
|
+
isPinnedPort = false;
|
|
21373
|
+
/** @deprecated Legacy sync support — remove when #[fastedge::http] is retired */
|
|
21374
|
+
isLegacySync = false;
|
|
21276
21375
|
constructor(portManager, dotenvEnabled = true) {
|
|
21277
|
-
this.process = null;
|
|
21278
|
-
this.port = null;
|
|
21279
|
-
this.cliPath = null;
|
|
21280
|
-
this.tempWasmPath = null;
|
|
21281
|
-
this.currentWasmPath = null;
|
|
21282
|
-
// resolved path used when spawning
|
|
21283
|
-
this.logs = [];
|
|
21284
|
-
this.stateManager = null;
|
|
21285
|
-
this.dotenvEnabled = true;
|
|
21286
|
-
this.dotenvPath = null;
|
|
21287
|
-
/** Pinned ports bypass PortManager allocation and must not be released back to it. */
|
|
21288
|
-
this.isPinnedPort = false;
|
|
21289
|
-
/** @deprecated Legacy sync support — remove when #[fastedge::http] is retired */
|
|
21290
|
-
this.isLegacySync = false;
|
|
21291
21376
|
this.portManager = portManager;
|
|
21292
21377
|
this.dotenvEnabled = dotenvEnabled;
|
|
21293
21378
|
}
|
|
@@ -21687,12 +21772,10 @@ function parseFetchHeaders(headers) {
|
|
|
21687
21772
|
// server/runner/PortManager.ts
|
|
21688
21773
|
import { createServer } from "net";
|
|
21689
21774
|
var PortManager = class {
|
|
21690
|
-
|
|
21691
|
-
|
|
21692
|
-
|
|
21693
|
-
|
|
21694
|
-
this.lastAllocatedPort = this.minPort - 1;
|
|
21695
|
-
}
|
|
21775
|
+
minPort = 8100;
|
|
21776
|
+
maxPort = 8199;
|
|
21777
|
+
allocatedPorts = /* @__PURE__ */ new Set();
|
|
21778
|
+
lastAllocatedPort = this.minPort - 1;
|
|
21696
21779
|
/**
|
|
21697
21780
|
* Check whether a port is actually free at the OS level.
|
|
21698
21781
|
* This is necessary when multiple server processes run simultaneously —
|