@pulse-compute/provider-fastly 1.0.0-beta.3 → 1.0.0-beta.5
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/README.md +6 -6
- package/dist/config-schema.json +3 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
- package/src/build/canonical-target.js +5 -0
- package/src/build/digest-native.js +25 -0
- package/src/build/native-application-errors.js +117 -0
- package/src/build/native-http-effects.js +89 -16
- package/src/build/native-platform-capabilities.js +153 -40
- package/src/build/native-request-body.js +44 -0
- package/src/build/native-request-headers.js +93 -0
- package/src/build/native-string-values.js +113 -0
- package/src/build/request-budget.as.ts +49 -0
- package/src/build/request-budget.js +43 -0
- package/src/build/s3-native.as.ts +3 -1
- package/src/build/time-native.js +49 -0
- package/src/config-api.js +1 -0
- package/src/config-schema.json +3 -0
- package/src/index.ts +4 -0
- package/src/javascript/package-effects.js +4 -1
- package/src/javascript/runtime-host.js +5 -2
- package/src/javascript/target-support-policy.js +7 -0
- package/src/javascript/target.js +6 -1
- package/src/provider-contract.js +3 -1
- package/src/runtime/canonical-api-runtime.js +2 -0
- package/src/testing/native-platform-capabilities-host.js +54 -3
- package/src/toolchain/config.js +4 -1
- package/src/toolchain/index.js +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
const applicationErrors = require('./native-application-errors.js');
|
|
2
3
|
|
|
3
4
|
const crypto = require('node:crypto');
|
|
5
|
+
const { nativeStringFields, nativeStringConcat, nativeStringTrim, nativeStringIndex, needsNativeValueFailureGuard } = require('./native-string-values.js');
|
|
4
6
|
const conditionalKv = require('./kv-native.js');
|
|
5
7
|
const fs = require('node:fs');
|
|
6
8
|
const os = require('node:os');
|
|
@@ -102,6 +104,8 @@ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORTS = Object.freeze([
|
|
|
102
104
|
Object.freeze(['fastly_http_req', 'method_get']),
|
|
103
105
|
Object.freeze(['fastly_http_req', 'uri_get']),
|
|
104
106
|
Object.freeze(['fastly_http_req', 'header_value_get']),
|
|
107
|
+
Object.freeze(['fastly_http_req', 'header_names_get']),
|
|
108
|
+
Object.freeze(['fastly_http_req', 'header_values_get']),
|
|
105
109
|
Object.freeze(['fastly_http_req', 'new']),
|
|
106
110
|
Object.freeze(['fastly_http_req', 'method_set']),
|
|
107
111
|
Object.freeze(['fastly_http_req', 'uri_set']),
|
|
@@ -157,7 +161,9 @@ const FASTLY_NATIVE_PLATFORM_EFFECT_KIND = Object.freeze({
|
|
|
157
161
|
's3.putText': 14,
|
|
158
162
|
'kv.getVersioned': 15,
|
|
159
163
|
'kv.insertIfAbsent': 16,
|
|
160
|
-
'kv.compareAndSwap': 17
|
|
164
|
+
'kv.compareAndSwap': 17,
|
|
165
|
+
'time.now': 18,
|
|
166
|
+
'crypto.digestText': 19
|
|
161
167
|
});
|
|
162
168
|
|
|
163
169
|
const FASTLY_NATIVE_PLATFORM_CAPABILITIES_ALLOWED_IMPORTS = new Set([
|
|
@@ -165,6 +171,8 @@ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_ALLOWED_IMPORTS = new Set([
|
|
|
165
171
|
]);
|
|
166
172
|
|
|
167
173
|
const FASTLY_NATIVE_PLATFORM_EFFECT_KINDS = Object.freeze([
|
|
174
|
+
'time.now',
|
|
175
|
+
'crypto.digestText',
|
|
168
176
|
'fetch',
|
|
169
177
|
'config.get',
|
|
170
178
|
'secret.get',
|
|
@@ -183,6 +191,8 @@ const FASTLY_NATIVE_PLATFORM_EFFECT_KINDS = Object.freeze([
|
|
|
183
191
|
]);
|
|
184
192
|
|
|
185
193
|
const FASTLY_NATIVE_PLATFORM_CAPABILITY_KINDS = new Set([
|
|
194
|
+
'time.now',
|
|
195
|
+
'crypto.digestText',
|
|
186
196
|
'config.get',
|
|
187
197
|
'secret.get',
|
|
188
198
|
'kv.get',
|
|
@@ -591,10 +601,12 @@ function validatePlanBoundary(plan, options = {}) {
|
|
|
591
601
|
&& effect.capability === 'jwt.verify';
|
|
592
602
|
const s3 = effect.package === '@pulse-compute/s3' && effect.contractId === 'pulse.s3'
|
|
593
603
|
&& ['head', 'getText', 'putText'].includes(effect.operation) && effect.kind === `s3.${effect.operation}` && effect.capability === effect.kind;
|
|
594
|
-
|
|
604
|
+
const digest = effect.package === '@pulse-compute/crypto' && effect.contractId === 'pulse.crypto'
|
|
605
|
+
&& effect.operation === 'digestText' && effect.kind === 'crypto.digestText' && effect.capability === effect.kind;
|
|
606
|
+
return !grip && !assets && !jwt && !s3 && !digest;
|
|
595
607
|
});
|
|
596
608
|
if (unsupportedPackages.length > 0) {
|
|
597
|
-
fail('Fastly native realization only accepts the trusted first-party Assets, GRIP, and
|
|
609
|
+
fail('Fastly native realization only accepts the trusted first-party Assets, GRIP, JWT, S3, and Crypto digest package contracts.', 'PULSE_FASTLY_NATIVE_PLATFORM_PACKAGE_UNSUPPORTED', {
|
|
598
610
|
effects: unsupportedPackages.map((entry) => ({ id: entry.id, kind: entry.kind, package: entry.package, contractId: entry.contractId }))
|
|
599
611
|
});
|
|
600
612
|
}
|
|
@@ -613,10 +625,12 @@ function validatePlanBoundary(plan, options = {}) {
|
|
|
613
625
|
&& effect.capability === 'jwt.verify';
|
|
614
626
|
const s3 = effect.package === '@pulse-compute/s3' && effect.contractId === 'pulse.s3'
|
|
615
627
|
&& ['head', 'getText', 'putText'].includes(effect.operation) && effect.kind === `s3.${effect.operation}` && effect.capability === effect.kind;
|
|
616
|
-
|
|
628
|
+
const digest = effect.package === '@pulse-compute/crypto' && effect.contractId === 'pulse.crypto'
|
|
629
|
+
&& effect.operation === 'digestText' && effect.kind === 'crypto.digestText' && effect.capability === effect.kind;
|
|
630
|
+
return !grip && !assets && !jwt && !s3 && !digest;
|
|
617
631
|
});
|
|
618
632
|
if (unsupportedDeclarations.length > 0) {
|
|
619
|
-
fail('Fastly native package realization is restricted to the Assets, GRIP, and
|
|
633
|
+
fail('Fastly native package realization is restricted to the Assets, GRIP, JWT, S3, and Crypto digest contracts.', 'PULSE_FASTLY_NATIVE_PLATFORM_PACKAGE_UNSUPPORTED', { effects: unsupportedDeclarations });
|
|
620
634
|
}
|
|
621
635
|
for (const effect of effects.filter((entry) => entry.kind === 'jwt.verify')) {
|
|
622
636
|
const resource = effect.resource;
|
|
@@ -821,6 +835,7 @@ function resolveCapabilityBindings(plan, options = {}) {
|
|
|
821
835
|
}
|
|
822
836
|
|
|
823
837
|
return Object.freeze({
|
|
838
|
+
maxDurationMs: require('@pulse-compute/runtime/host').normalizeRequestDuration(options.maxDurationMs),
|
|
824
839
|
configStore,
|
|
825
840
|
secretStore,
|
|
826
841
|
s3: require('../toolchain/s3.js').resolveFastlyS3(effects.map((effect) => ({ ...effect, payload: { contentType: literalObjectField(inputExpression(effect, 'payload'), 'contentType') || undefined } })), source.s3),
|
|
@@ -872,6 +887,7 @@ function requiredImportsForPlan(plan, bindings) {
|
|
|
872
887
|
'fastly_http_body:new',
|
|
873
888
|
'fastly_http_body:write'
|
|
874
889
|
]);
|
|
890
|
+
if (bindings && bindings.maxDurationMs !== undefined) { keys.add('wasi_snapshot_preview1:clock_time_get'); keys.add('fastly_async_io:select'); }
|
|
875
891
|
const kinds = new Set((plan.effects || []).map((effect) => effect.kind));
|
|
876
892
|
if (kinds.has('fetch') || kinds.has('grip.publish') || kinds.has('grip.broadcast')) {
|
|
877
893
|
for (const key of [
|
|
@@ -892,7 +908,7 @@ function requiredImportsForPlan(plan, bindings) {
|
|
|
892
908
|
for (const key of ['fastly_secret_store:open', 'fastly_secret_store:get', 'fastly_secret_store:plaintext']) keys.add(key);
|
|
893
909
|
}
|
|
894
910
|
for (const kind of conditionalKv.KV_CONDITIONAL_KINDS) if (kinds.has(kind)) for (const key of conditionalKv.kvImports(kind)) keys.add(key);
|
|
895
|
-
if (kinds.has('jwt.verify')) keys.add('wasi_snapshot_preview1:clock_time_get');
|
|
911
|
+
if (kinds.has('jwt.verify') || kinds.has('time.now')) keys.add('wasi_snapshot_preview1:clock_time_get');
|
|
896
912
|
if (kinds.has('kv.get') || kinds.has('kv.put') || kinds.has('assets.lookup')) keys.add('fastly_kv_store:open');
|
|
897
913
|
if (kinds.has('kv.get') || kinds.has('assets.lookup')) for (const key of ['fastly_kv_store:lookup', 'fastly_kv_store:lookup_wait_v2', 'fastly_http_body:read']) keys.add(key);
|
|
898
914
|
if (kinds.has('kv.put')) for (const key of ['fastly_kv_store:insert', 'fastly_kv_store:insert_wait']) keys.add(key);
|
|
@@ -947,11 +963,13 @@ function generateSchemaRuntime(plan) {
|
|
|
947
963
|
body.push(' const output = host_value_object()');
|
|
948
964
|
fields.forEach(({ field, apply }, fieldIndex) => {
|
|
949
965
|
body.push(` const key_${currentIndex}_${fieldIndex} = __pulse_fastly_string_value(${quote(field.name)})`);
|
|
966
|
+
if (!field.required) body.push(` if (__pulse_fastly_find(input, ${quote(field.name)}) >= 0) {`);
|
|
950
967
|
body.push(` const field_${currentIndex}_${fieldIndex} = host_value_property(valueHandle, key_${currentIndex}_${fieldIndex})`);
|
|
951
968
|
body.push(` if (__pulse_fastly_value(field_${currentIndex}_${fieldIndex}).kind == PULSE_VALUE_UNDEFINED) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 51, -1); return 0 }`);
|
|
952
969
|
body.push(` const projected_${currentIndex}_${fieldIndex} = ${apply}(field_${currentIndex}_${fieldIndex})`);
|
|
953
970
|
body.push(` if (projected_${currentIndex}_${fieldIndex} <= 0) return 0`);
|
|
954
971
|
body.push(` host_value_object_set(output, key_${currentIndex}_${fieldIndex}, projected_${currentIndex}_${fieldIndex})`);
|
|
972
|
+
if (!field.required) body.push(' }');
|
|
955
973
|
});
|
|
956
974
|
body.push(' return output');
|
|
957
975
|
} else if (node.kind === 'string') {
|
|
@@ -1075,6 +1093,8 @@ function effectResultSource(plan, bindings) {
|
|
|
1075
1093
|
|
|
1076
1094
|
function effectDispatchSource(plan) {
|
|
1077
1095
|
const handlerByKind = Object.freeze({
|
|
1096
|
+
'time.now': '__pulse_fastly_time_begin',
|
|
1097
|
+
'crypto.digestText': '__pulse_fastly_digest_begin',
|
|
1078
1098
|
fetch: '__pulse_fastly_fetch_begin',
|
|
1079
1099
|
'config.get': '__pulse_fastly_config_begin',
|
|
1080
1100
|
'secret.get': '__pulse_fastly_secret_begin',
|
|
@@ -1094,6 +1114,7 @@ function effectDispatchSource(plan) {
|
|
|
1094
1114
|
const kinds = [...new Set((plan.effects || []).map((effect) => effect.kind))];
|
|
1095
1115
|
const lines = [
|
|
1096
1116
|
'function host_effect_begin(effectIndex: i32, payload: i32): void {',
|
|
1117
|
+
...(needsNativeValueFailureGuard(plan) ? [' if (__pulse_fastly_last_error != PULSE_ERROR_NONE) return'] : []),
|
|
1097
1118
|
' if (effectIndex < 0 || effectIndex >= PULSE_FASTLY_EFFECT_COUNT || unchecked(__pulse_fastly_pending_mode[effectIndex]) != PULSE_FASTLY_PENDING_NONE) { __pulse_fastly_fail(PULSE_ERROR_STATE, 46, effectIndex); return }',
|
|
1098
1119
|
' const payloadValue = __pulse_fastly_value(payload)',
|
|
1099
1120
|
' if (payloadValue.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 47, effectIndex); return }',
|
|
@@ -1262,19 +1283,35 @@ const PULSE_ERROR_SCHEMA: i32 = 1005
|
|
|
1262
1283
|
const PULSE_ERROR_TRANSPORT: i32 = 1006
|
|
1263
1284
|
const PULSE_ERROR_STATE: i32 = 1007
|
|
1264
1285
|
const PULSE_ERROR_JWT: i32 = 1008
|
|
1286
|
+
const PULSE_ERROR_REQUEST_BODY: i32 = 1009
|
|
1265
1287
|
|
|
1266
1288
|
class __PulseFastlyValue {
|
|
1267
1289
|
kind: i32 = PULSE_VALUE_UNDEFINED
|
|
1268
1290
|
boolean: i32 = 0
|
|
1269
1291
|
number: f64 = 0.0
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1292
|
+
${nativeStringFields}
|
|
1293
|
+
// Scalar handles do not need collection backing stores.
|
|
1294
|
+
private keysStorage: Array<string> | null = null
|
|
1295
|
+
get keys(): Array<string> {
|
|
1296
|
+
if (this.keysStorage === null) this.keysStorage = new Array<string>()
|
|
1297
|
+
return this.keysStorage!
|
|
1298
|
+
}
|
|
1299
|
+
// Scalar handles do not need collection backing stores.
|
|
1300
|
+
private valuesStorage: Array<i32> | null = null
|
|
1301
|
+
get values(): Array<i32> {
|
|
1302
|
+
if (this.valuesStorage === null) this.valuesStorage = new Array<i32>()
|
|
1303
|
+
return this.valuesStorage!
|
|
1304
|
+
}
|
|
1273
1305
|
responseHandle: i32 = 0
|
|
1274
1306
|
bodyHandle: i32 = 0
|
|
1275
1307
|
bodyLoaded: i32 = 0
|
|
1276
1308
|
status: i32 = 200
|
|
1277
|
-
|
|
1309
|
+
// Scalar handles do not need collection backing stores.
|
|
1310
|
+
private headersStorage: Array<__PulseFastlyHeader> | null = null
|
|
1311
|
+
get headers(): Array<__PulseFastlyHeader> {
|
|
1312
|
+
if (this.headersStorage === null) this.headersStorage = new Array<__PulseFastlyHeader>()
|
|
1313
|
+
return this.headersStorage!
|
|
1314
|
+
}
|
|
1278
1315
|
immutable: bool = false
|
|
1279
1316
|
}
|
|
1280
1317
|
class __PulseFastlyHeader {
|
|
@@ -1404,6 +1441,12 @@ const PULSE_FASTLY_PENDING_NONE: i32 = 0
|
|
|
1404
1441
|
const PULSE_FASTLY_PENDING_ASYNC: i32 = 1
|
|
1405
1442
|
const PULSE_FASTLY_PENDING_READY: i32 = 2
|
|
1406
1443
|
@lazy const __pulse_fastly_values = new Array<__PulseFastlyValue>()
|
|
1444
|
+
// Primitive handles have value semantics. Bounded caches keep admitted scalar
|
|
1445
|
+
// validation loops from retaining a fresh boxed value for every iteration.
|
|
1446
|
+
@lazy const __pulse_fastly_scalar_handles = new StaticArray<i32>(4)
|
|
1447
|
+
@lazy const __pulse_fastly_integer_handles = new StaticArray<i32>(65536)
|
|
1448
|
+
@lazy const __pulse_fastly_character_handles = new StaticArray<i32>(65537)
|
|
1449
|
+
@lazy const __pulse_fastly_literal_handles = new Map<string, i32>()
|
|
1407
1450
|
@lazy const __pulse_fastly_pending = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
|
|
1408
1451
|
@lazy const __pulse_fastly_pending_mode = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
|
|
1409
1452
|
@lazy const __pulse_fastly_payloads = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
|
|
@@ -1439,8 +1482,18 @@ function __pulse_fastly_utf8(value: string): ArrayBuffer { return String.UTF8.en
|
|
|
1439
1482
|
function __pulse_fastly_decode(buffer: Uint8Array, length: i32): string { return String.UTF8.decodeUnsafe(buffer.dataStart, length, false) }
|
|
1440
1483
|
function __pulse_fastly_put(value: __PulseFastlyValue): i32 { __pulse_fastly_values.push(value); return __pulse_fastly_values.length }
|
|
1441
1484
|
function __pulse_fastly_value(handle: i32): __PulseFastlyValue { if (handle <= 0 || handle > __pulse_fastly_values.length) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 1, -1); return new __PulseFastlyValue() } return unchecked(__pulse_fastly_values[handle - 1]) }
|
|
1485
|
+
${nativeStringConcat}
|
|
1486
|
+
${nativeStringTrim}
|
|
1487
|
+
${nativeStringIndex}
|
|
1442
1488
|
function __pulse_fastly_deep_freeze(handle: i32): void { const value = __pulse_fastly_value(handle); if (value.immutable) return; value.immutable = true; if (value.kind == PULSE_VALUE_ARRAY || value.kind == PULSE_VALUE_OBJECT) for (let index = 0; index < value.values.length; index += 1) __pulse_fastly_deep_freeze(unchecked(value.values[index])) }
|
|
1443
|
-
function __pulse_fastly_string_value(value: string): i32 {
|
|
1489
|
+
function __pulse_fastly_string_value(value: string): i32 {
|
|
1490
|
+
const index = value.length == 0 ? 65536 : value.length == 1 ? value.charCodeAt(0) : -1;
|
|
1491
|
+
if (index >= 0) { const cached = unchecked(__pulse_fastly_character_handles[index]); if (cached != 0) return cached }
|
|
1492
|
+
const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_STRING; item.text = value;
|
|
1493
|
+
const handle = __pulse_fastly_put(item);
|
|
1494
|
+
if (index >= 0) unchecked(__pulse_fastly_character_handles[index] = handle);
|
|
1495
|
+
return handle
|
|
1496
|
+
}
|
|
1444
1497
|
function __pulse_fastly_find(object: __PulseFastlyValue, key: string): i32 { for (let i = 0; i < object.keys.length; i += 1) if (unchecked(object.keys[i]) == key) return i; return -1 }
|
|
1445
1498
|
function __pulse_fastly_number_string(value: f64): string { if (value >= -9007199254740991.0 && value <= 9007199254740991.0 && Math.floor(value) == value) return i64(value).toString(); return value.toString() }
|
|
1446
1499
|
function __pulse_fastly_string(handle: i32): string { const value = __pulse_fastly_value(handle); if (value.kind == PULSE_VALUE_STRING) return value.text; if (value.kind == PULSE_VALUE_NUMBER) return __pulse_fastly_number_string(value.number); if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean != 0 ? "true" : "false"; if (value.kind == PULSE_VALUE_NULL) return "null"; if (value.kind == PULSE_VALUE_UNDEFINED) return "undefined"; return __pulse_fastly_json(handle, 0) }
|
|
@@ -1479,21 +1532,26 @@ function __pulse_fastly_quote(value: string): string {
|
|
|
1479
1532
|
out[cursor] = 34;
|
|
1480
1533
|
return String.UTF16.decodeUnsafe(out.dataStart, out.byteLength);
|
|
1481
1534
|
}
|
|
1482
|
-
function
|
|
1483
|
-
if (depth > ${plan.effects.some(effect => conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind)) ? 128 : 64}) { __pulse_fastly_fail(PULSE_ERROR_JSON, 2, -1);
|
|
1535
|
+
function __pulse_fastly_json_parts(handle: i32, depth: i32, parts: Array<string>): void {
|
|
1536
|
+
if (depth > ${plan.effects.some(effect => conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind)) ? 128 : 64}) { __pulse_fastly_fail(PULSE_ERROR_JSON, 2, -1); parts.push("null"); return }
|
|
1484
1537
|
const value = __pulse_fastly_value(handle)
|
|
1485
|
-
if (value.kind ==
|
|
1486
|
-
if (value.kind ==
|
|
1487
|
-
if (value.kind ==
|
|
1488
|
-
if (value.kind ==
|
|
1489
|
-
if (value.kind ==
|
|
1490
|
-
|
|
1491
|
-
|
|
1538
|
+
if (value.kind == PULSE_VALUE_BOOLEAN) { parts.push(value.boolean != 0 ? "true" : "false"); return }
|
|
1539
|
+
if (value.kind == PULSE_VALUE_NUMBER) { parts.push(__pulse_fastly_number_string(value.number)); return }
|
|
1540
|
+
if (value.kind == PULSE_VALUE_STRING) { parts.push(__pulse_fastly_quote(value.text)); return }
|
|
1541
|
+
if (value.kind == PULSE_VALUE_ARRAY) { parts.push("["); for (let i = 0; i < value.values.length; i += 1) { if (i > 0) parts.push(","); __pulse_fastly_json_parts(unchecked(value.values[i]), depth + 1, parts) } parts.push("]"); return }
|
|
1542
|
+
if (value.kind == PULSE_VALUE_OBJECT) { parts.push("{"); for (let i = 0; i < value.keys.length; i += 1) { if (i > 0) parts.push(","); parts.push(__pulse_fastly_quote(unchecked(value.keys[i]))); parts.push(":"); __pulse_fastly_json_parts(unchecked(value.values[i]), depth + 1, parts) } parts.push("}"); return }
|
|
1543
|
+
parts.push("null")
|
|
1544
|
+
}
|
|
1545
|
+
function __pulse_fastly_json(handle: i32, depth: i32): string {
|
|
1546
|
+
// Join once, avoiding a complete copy of a multi-MiB leaf at every ancestor
|
|
1547
|
+
// and at every following member in the response or effect result.
|
|
1548
|
+
const parts = new Array<string>(); __pulse_fastly_json_parts(handle, depth, parts);
|
|
1549
|
+
return parts.join("")
|
|
1492
1550
|
}
|
|
1493
1551
|
function __pulse_fastly_parse_json(text: string): i32 { const parser = new __PulseJsonParser(text); const value = parser.parse(); if (parser.failed || value <= 0) { __pulse_fastly_fail(PULSE_ERROR_JSON, 3, -1); return 0 } return value }
|
|
1494
1552
|
function __pulse_fastly_path(uri: string): string { let start = 0; const scheme = uri.indexOf("://"); if (scheme >= 0) { const slash = uri.indexOf("/", scheme + 3); start = slash >= 0 ? slash : uri.length } let end = uri.length; const query = uri.indexOf("?", start); if (query >= 0 && query < end) end = query; const fragment = uri.indexOf("#", start); if (fragment >= 0 && fragment < end) end = fragment; return start >= end ? "/" : uri.substring(start, end) }
|
|
1495
1553
|
function __pulse_fastly_read_req_string(kind: i32): string { const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES); const written = __pulse_fastly_out_i32(); const status = kind == 0 ? fastly_http_req_method_get(__pulse_fastly_request_handle, buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(written)) : fastly_http_req_uri_get(__pulse_fastly_request_handle, buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(written)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 10 + kind, -1); return "" } return __pulse_fastly_decode(buffer, __pulse_fastly_out_value(written)) }
|
|
1496
|
-
function __pulse_fastly_read_body(handle: i32, effectIndex: i32): string {
|
|
1554
|
+
function __pulse_fastly_read_body(handle: i32, effectIndex: i32, requestText: bool = false): string {
|
|
1497
1555
|
const chunks = new Array<Uint8Array>(); let total = 0;
|
|
1498
1556
|
while (true) {
|
|
1499
1557
|
const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES), read = __pulse_fastly_out_i32();
|
|
@@ -1503,36 +1561,55 @@ function __pulse_fastly_read_body(handle: i32, effectIndex: i32): string {
|
|
|
1503
1561
|
if (count < 0 || count > buffer.length) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 20, effectIndex); return "" }
|
|
1504
1562
|
if (!count) break;
|
|
1505
1563
|
total += count;
|
|
1506
|
-
if (total > __PULSE_SCHEMA_MAX_BYTES && __PULSE_SCHEMA_MAX_BYTES > 0) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 21, effectIndex); return "" }
|
|
1564
|
+
if (total > __PULSE_SCHEMA_MAX_BYTES && __PULSE_SCHEMA_MAX_BYTES > 0) { __pulse_fastly_fail(requestText ? PULSE_ERROR_REQUEST_BODY : PULSE_ERROR_SCHEMA, 21, effectIndex); return "" }
|
|
1507
1565
|
chunks.push(buffer.subarray(0, count));
|
|
1508
1566
|
}
|
|
1509
1567
|
// UTF-8 scalars may straddle host read chunks. Decode the bounded body once.
|
|
1510
1568
|
const bytes = new Uint8Array(total); let offset = 0;
|
|
1511
1569
|
for (let i = 0; i < chunks.length; i++) { bytes.set(chunks[i], offset); offset += chunks[i].length; }
|
|
1570
|
+
if (requestText && !__pulse_request_utf8_valid(bytes)) { __pulse_fastly_fail(PULSE_ERROR_REQUEST_BODY, 24, effectIndex); return "" }
|
|
1512
1571
|
return __pulse_fastly_decode(bytes, total);
|
|
1513
1572
|
}
|
|
1514
1573
|
function __pulse_fastly_request_header_text(name: string): string { const nameBytes = __pulse_fastly_utf8(name); const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES); const written = __pulse_fastly_out_i32(); const status = fastly_http_req_header_value_get(__pulse_fastly_request_handle, changetype<usize>(nameBytes), nameBytes.byteLength, buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(written)); if (status == FASTLY_STATUS_NONE) return ""; if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 22, -1); return "" } return __pulse_fastly_decode(buffer, __pulse_fastly_out_value(written)) }
|
|
1515
1574
|
function __pulse_fastly_fetch_header_text(responseHandle: i32, name: string): string { const nameBytes = __pulse_fastly_utf8(name); const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES); const written = __pulse_fastly_out_i32(); const status = fastly_http_resp_header_value_get(responseHandle, changetype<usize>(nameBytes), nameBytes.byteLength, buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(written)); if (status == FASTLY_STATUS_NONE) return ""; if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 23, -1); return "" } return __pulse_fastly_decode(buffer, __pulse_fastly_out_value(written)) }
|
|
1516
1575
|
function __pulse_fastly_fetch_body(value: __PulseFastlyValue): string { if (value.bodyLoaded == 0) { value.text = __pulse_fastly_read_body(value.bodyHandle, -1); value.bodyLoaded = 1 } return value.text }
|
|
1517
1576
|
|
|
1518
|
-
function
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1577
|
+
function __pulse_fastly_scalar(kind: i32, boolean: i32, slot: i32): i32 {
|
|
1578
|
+
const cached = unchecked(__pulse_fastly_scalar_handles[slot]); if (cached != 0) return cached;
|
|
1579
|
+
const item = new __PulseFastlyValue(); item.kind = kind; item.boolean = boolean;
|
|
1580
|
+
const handle = __pulse_fastly_put(item); unchecked(__pulse_fastly_scalar_handles[slot] = handle); return handle
|
|
1581
|
+
}
|
|
1582
|
+
function host_value_undefined(): i32 { return __pulse_fastly_scalar(PULSE_VALUE_UNDEFINED, 0, 0) }
|
|
1583
|
+
function host_value_null(): i32 { return __pulse_fastly_scalar(PULSE_VALUE_NULL, 0, 1) }
|
|
1584
|
+
function host_value_boolean(value: i32): i32 { return __pulse_fastly_scalar(PULSE_VALUE_BOOLEAN, value != 0 ? 1 : 0, value != 0 ? 3 : 2) }
|
|
1585
|
+
function host_value_number(value: f64): i32 {
|
|
1586
|
+
// Preserve negative zero, NaN, infinities and nonintegral values exactly.
|
|
1587
|
+
const cacheable = value >= 0 && value < 65536 && Math.floor(value) == value && (value != 0 || 1.0 / value > 0);
|
|
1588
|
+
const index = cacheable ? i32(value) : -1;
|
|
1589
|
+
if (index >= 0) { const cached = unchecked(__pulse_fastly_integer_handles[index]); if (cached != 0) return cached }
|
|
1590
|
+
const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_NUMBER; item.number = value;
|
|
1591
|
+
const handle = __pulse_fastly_put(item); if (index >= 0) unchecked(__pulse_fastly_integer_handles[index] = handle); return handle
|
|
1592
|
+
}
|
|
1593
|
+
function host_value_string(pointer: i32, length: i32): i32 {
|
|
1594
|
+
const text = changetype<string>(pointer);
|
|
1595
|
+
if (text.length > 1 && text.length <= 128 && __pulse_fastly_literal_handles.has(text)) return __pulse_fastly_literal_handles.get(text);
|
|
1596
|
+
const handle = __pulse_fastly_string_value(text);
|
|
1597
|
+
if (text.length > 1 && text.length <= 128 && __pulse_fastly_literal_handles.size < 1024) __pulse_fastly_literal_handles.set(text, handle);
|
|
1598
|
+
return handle
|
|
1599
|
+
}
|
|
1523
1600
|
function host_value_array(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_ARRAY; return __pulse_fastly_put(item) }
|
|
1524
1601
|
function host_value_array_push(target: i32, value: i32): void { const item = __pulse_fastly_value(target); if (item.kind != PULSE_VALUE_ARRAY || item.immutable) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 30, -1); return } item.values.push(value) }
|
|
1525
1602
|
function host_value_array_spread(target: i32, source: i32): void { const from = __pulse_fastly_value(source); if (from.kind != PULSE_VALUE_ARRAY) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 31, -1); return } for (let i = 0; i < from.values.length; i += 1) host_value_array_push(target, unchecked(from.values[i])) }
|
|
1526
1603
|
function host_value_object(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_OBJECT; return __pulse_fastly_put(item) }
|
|
1527
1604
|
function host_value_object_set(target: i32, keyHandle: i32, value: i32): void { const item = __pulse_fastly_value(target); if (item.kind != PULSE_VALUE_OBJECT || item.immutable) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 32, -1); return } const key = __pulse_fastly_string(keyHandle); const index = __pulse_fastly_find(item, key); if (index >= 0) unchecked(item.values[index] = value); else { item.keys.push(key); item.values.push(value) } }
|
|
1528
1605
|
function host_value_object_spread(target: i32, source: i32): void { const from = __pulse_fastly_value(source); if (from.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 33, -1); return } for (let i = 0; i < from.keys.length; i += 1) host_value_object_set(target, __pulse_fastly_string_value(unchecked(from.keys[i])), unchecked(from.values[i])) }
|
|
1529
|
-
function host_value_property(target: i32, keyHandle: i32): i32 { const item = __pulse_fastly_value(target); const key = __pulse_fastly_string(keyHandle); if (item.kind == PULSE_VALUE_OBJECT) { const index = __pulse_fastly_find(item, key); return index >= 0 ? unchecked(item.values[index]) : host_value_undefined() } if (item.kind == PULSE_VALUE_FETCH && key == "status") { const out = __pulse_fastly_out_i32(); const status = fastly_http_resp_status_get(item.responseHandle, changetype<usize>(out)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 34, -1); return 0 } return host_value_number(__pulse_fastly_out_value(out)) } if ((item.kind == PULSE_VALUE_STRING || item.kind == PULSE_VALUE_ARRAY) && key == "length") return host_value_number(item.kind == PULSE_VALUE_STRING ? item.
|
|
1606
|
+
function host_value_property(target: i32, keyHandle: i32): i32 { const item = __pulse_fastly_value(target); const key = __pulse_fastly_string(keyHandle); if (item.kind == PULSE_VALUE_OBJECT) { const index = __pulse_fastly_find(item, key); return index >= 0 ? unchecked(item.values[index]) : host_value_undefined() } if (item.kind == PULSE_VALUE_FETCH && key == "status") { const out = __pulse_fastly_out_i32(); const status = fastly_http_resp_status_get(item.responseHandle, changetype<usize>(out)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 34, -1); return 0 } return host_value_number(__pulse_fastly_out_value(out)) } if ((item.kind == PULSE_VALUE_STRING || item.kind == PULSE_VALUE_ARRAY) && key == "length") return host_value_number(item.kind == PULSE_VALUE_STRING ? item.textLength : item.values.length); return host_value_undefined() }
|
|
1530
1607
|
function host_value_property_set(target: i32, key: i32, value: i32): i32 { host_value_object_set(target, key, value); return value }
|
|
1531
|
-
function host_value_element(target: i32, keyHandle: i32): i32 { const item = __pulse_fastly_value(target); if (item.kind == PULSE_VALUE_ARRAY) { const index = i32(__pulse_fastly_number(keyHandle)); return index >= 0 && index < item.values.length ? unchecked(item.values[index]) : host_value_undefined() } return host_value_property(target, keyHandle) }
|
|
1608
|
+
function host_value_element(target: i32, keyHandle: i32): i32 { const item = __pulse_fastly_value(target); if (item.kind == PULSE_VALUE_STRING) return __pulse_fastly_string_index(item, keyHandle); if (item.kind == PULSE_VALUE_ARRAY) { const index = i32(__pulse_fastly_number(keyHandle)); return index >= 0 && index < item.values.length ? unchecked(item.values[index]) : host_value_undefined() } return host_value_property(target, keyHandle) }
|
|
1532
1609
|
function host_value_element_set(target: i32, keyHandle: i32, value: i32): i32 { const item = __pulse_fastly_value(target); if (item.immutable) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 35, -1); return 0 } if (item.kind == PULSE_VALUE_ARRAY) { const index = i32(__pulse_fastly_number(keyHandle)); if (index < 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 35, -1); return 0 } while (item.values.length <= index) item.values.push(host_value_undefined()); unchecked(item.values[index] = value); return value } return host_value_property_set(target, keyHandle, value) }
|
|
1533
|
-
function host_value_truthy(handle: i32): i32 { const value = __pulse_fastly_value(handle); if (value.kind == PULSE_VALUE_UNDEFINED || value.kind == PULSE_VALUE_NULL) return 0; if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean; if (value.kind == PULSE_VALUE_NUMBER) return value.number != 0.0 && !isNaN(value.number) ? 1 : 0; if (value.kind == PULSE_VALUE_STRING) return value.
|
|
1610
|
+
function host_value_truthy(handle: i32): i32 { const value = __pulse_fastly_value(handle); if (value.kind == PULSE_VALUE_UNDEFINED || value.kind == PULSE_VALUE_NULL) return 0; if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean; if (value.kind == PULSE_VALUE_NUMBER) return value.number != 0.0 && !isNaN(value.number) ? 1 : 0; if (value.kind == PULSE_VALUE_STRING) return value.textLength > 0 ? 1 : 0; return 1 }
|
|
1534
1611
|
function host_value_nullish(handle: i32): i32 { const kind = __pulse_fastly_value(handle).kind; return kind == PULSE_VALUE_UNDEFINED || kind == PULSE_VALUE_NULL ? 1 : 0 }
|
|
1535
|
-
function host_value_binary(operator: i32, leftHandle: i32, rightHandle: i32): i32 { const left = __pulse_fastly_value(leftHandle); const right = __pulse_fastly_value(rightHandle); if (operator == 0 || operator == 2) { let equal = false; if (left.kind == right.kind) { if (left.kind == PULSE_VALUE_UNDEFINED || left.kind == PULSE_VALUE_NULL) equal = true; else if (left.kind == PULSE_VALUE_BOOLEAN) equal = left.boolean == right.boolean; else if (left.kind == PULSE_VALUE_NUMBER) equal = left.number == right.number; else if (left.kind == PULSE_VALUE_STRING) equal = left.text == right.text; else equal = leftHandle == rightHandle } return host_value_boolean(equal ? 1 : 0) } if (operator == 1 || operator == 3) { const result = host_value_binary(operator == 1 ? 0 : 2, leftHandle, rightHandle); return host_value_boolean(host_value_truthy(result) == 0 ? 1 : 0) } if (operator == 8) { if (left.kind == PULSE_VALUE_STRING || right.kind == PULSE_VALUE_STRING) return
|
|
1612
|
+
function host_value_binary(operator: i32, leftHandle: i32, rightHandle: i32): i32 { const left = __pulse_fastly_value(leftHandle); const right = __pulse_fastly_value(rightHandle); if (operator == 0 || operator == 2) { let equal = false; if (left.kind == right.kind) { if (left.kind == PULSE_VALUE_UNDEFINED || left.kind == PULSE_VALUE_NULL) equal = true; else if (left.kind == PULSE_VALUE_BOOLEAN) equal = left.boolean == right.boolean; else if (left.kind == PULSE_VALUE_NUMBER) equal = left.number == right.number; else if (left.kind == PULSE_VALUE_STRING) equal = left.text == right.text; else equal = leftHandle == rightHandle } return host_value_boolean(equal ? 1 : 0) } if (operator == 1 || operator == 3) { const result = host_value_binary(operator == 1 ? 0 : 2, leftHandle, rightHandle); return host_value_boolean(host_value_truthy(result) == 0 ? 1 : 0) } if (operator == 8) { if (left.kind == PULSE_VALUE_STRING || right.kind == PULSE_VALUE_STRING) return __pulse_fastly_concat(leftHandle, rightHandle); return host_value_number(__pulse_fastly_number(leftHandle) + __pulse_fastly_number(rightHandle)) } if (left.kind == PULSE_VALUE_STRING && right.kind == PULSE_VALUE_STRING) { if (operator == 4) return host_value_boolean(left.text < right.text ? 1 : 0); if (operator == 5) return host_value_boolean(left.text <= right.text ? 1 : 0); if (operator == 6) return host_value_boolean(left.text > right.text ? 1 : 0); if (operator == 7) return host_value_boolean(left.text >= right.text ? 1 : 0); } if (operator == 4) return host_value_boolean(__pulse_fastly_number(leftHandle) < __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 5) return host_value_boolean(__pulse_fastly_number(leftHandle) <= __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 6) return host_value_boolean(__pulse_fastly_number(leftHandle) > __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 7) return host_value_boolean(__pulse_fastly_number(leftHandle) >= __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 9) return host_value_number(__pulse_fastly_number(leftHandle) - __pulse_fastly_number(rightHandle)); if (operator == 10) return host_value_number(__pulse_fastly_number(leftHandle) * __pulse_fastly_number(rightHandle)); if (operator == 11) return host_value_number(__pulse_fastly_number(leftHandle) / __pulse_fastly_number(rightHandle)); if (operator == 12) return host_value_number(__pulse_fastly_number(leftHandle) % __pulse_fastly_number(rightHandle)); if (operator == 14) return host_value_truthy(leftHandle) != 0 ? rightHandle : leftHandle; if (operator == 15) return host_value_truthy(leftHandle) != 0 ? leftHandle : rightHandle; if (operator == 16) return host_value_nullish(leftHandle) == 0 ? leftHandle : rightHandle; __pulse_fastly_fail(PULSE_ERROR_UNSUPPORTED, 36, -1); return 0 }
|
|
1536
1613
|
function host_value_unary(operator: i32, handle: i32): i32 { if (operator == 0) return host_value_boolean(host_value_truthy(handle) == 0 ? 1 : 0); if (operator == 1) return host_value_number(__pulse_fastly_number(handle)); if (operator == 2) return host_value_number(-__pulse_fastly_number(handle)); if (operator == 5) return host_value_undefined(); __pulse_fastly_fail(PULSE_ERROR_UNSUPPORTED, 37, -1); return 0 }
|
|
1537
1614
|
|
|
1538
1615
|
function host_request_method(): i32 { return __pulse_fastly_string_value(__pulse_fastly_request_method) }
|
|
@@ -1543,13 +1620,35 @@ function __pulse_router_param_text(path: string, pattern: string, name: string):
|
|
|
1543
1620
|
function host_router_match(path: i32, pattern: i32): i32 { return host_value_boolean(__pulse_router_match_text(__pulse_fastly_string(path), __pulse_fastly_string(pattern)) ? 1 : 0) }
|
|
1544
1621
|
function host_router_param(path: i32, pattern: i32, name: i32): i32 { const value = __pulse_router_param_text(__pulse_fastly_string(path), __pulse_fastly_string(pattern), __pulse_fastly_string(name)); return value === null ? host_value_undefined() : __pulse_fastly_string_value(value) }
|
|
1545
1622
|
function host_request_path(): i32 { return __pulse_fastly_string_value(__pulse_fastly_request_path) }
|
|
1546
|
-
function host_request_headers(): i32 { return
|
|
1623
|
+
function host_request_headers(): i32 { return __pulse_request_headers_read() }
|
|
1547
1624
|
function host_request_header(name: i32): i32 { const value = __pulse_fastly_request_header_text(__pulse_fastly_string(name)); return value.length == 0 ? host_value_undefined() : __pulse_fastly_string_value(value) }
|
|
1548
|
-
function host_request_text(): i32 { if (__pulse_fastly_request_body_loaded == 0) { __pulse_fastly_request_body = __pulse_fastly_read_body(__pulse_fastly_request_body_handle, -1); __pulse_fastly_request_body_loaded = 1 } return __pulse_fastly_string_value(__pulse_fastly_request_body) }
|
|
1625
|
+
function host_request_text(): i32 { if (__pulse_request_body_failure != 0) { __pulse_fastly_fail(PULSE_ERROR_REQUEST_BODY, __pulse_request_body_failure, -1); return 0 } if (__pulse_fastly_request_body_loaded == 0) { __pulse_fastly_request_body = __pulse_fastly_read_body(__pulse_fastly_request_body_handle, -1, true); __pulse_fastly_request_body_loaded = 1; if (__pulse_fastly_last_error == PULSE_ERROR_REQUEST_BODY) __pulse_request_body_failure = __pulse_fastly_error_stage } if (__pulse_fastly_last_error != 0) return 0; return __pulse_fastly_string_value(__pulse_fastly_request_body) }
|
|
1549
1626
|
function host_request_json(schema: i32): i32 { const parsed = __pulse_fastly_parse_json(__pulse_fastly_string(host_request_text())); if (parsed <= 0) return 0; const schemaValue = __pulse_fastly_value(schema); return schemaValue.kind == PULSE_VALUE_STRING ? __pulse_fastly_schema_apply(schemaValue.text, parsed, false) : parsed }
|
|
1550
1627
|
function __pulse_fastly_headers_from_options(options: __PulseFastlyValue, output: __PulseFastlyValue): void { const index = __pulse_fastly_find(options, "headers"); if (index < 0) return; const headers = __pulse_fastly_value(unchecked(options.values[index])); if (headers.kind == PULSE_VALUE_OBJECT) { for (let i = 0; i < headers.keys.length; i += 1) { const name = unchecked(headers.keys[i]); const value = __pulse_fastly_value(unchecked(headers.values[i])); if (value.kind == PULSE_VALUE_ARRAY) { for (let j = 0; j < value.values.length; j += 1) output.headers.push(new __PulseFastlyHeader(name, __pulse_fastly_string(unchecked(value.values[j])))) } else output.headers.push(new __PulseFastlyHeader(name, __pulse_fastly_string(unchecked(headers.values[i])))) } return } if (headers.kind == PULSE_VALUE_ARRAY) { for (let i = 0; i < headers.values.length; i += 1) { const pair = __pulse_fastly_value(unchecked(headers.values[i])); if (pair.kind != PULSE_VALUE_ARRAY || pair.values.length < 2) continue; output.headers.push(new __PulseFastlyHeader(__pulse_fastly_string(unchecked(pair.values[0])), __pulse_fastly_string(unchecked(pair.values[1])))) } } }
|
|
1551
1628
|
function __pulse_fastly_response(value: i32, optionsHandle: i32, json: bool): i32 { const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE; output.status = 200; const options = __pulse_fastly_value(optionsHandle); let bodyValue = value; if (options.kind == PULSE_VALUE_OBJECT) { const statusIndex = __pulse_fastly_find(options, "status"); if (statusIndex >= 0) output.status = i32(__pulse_fastly_number(unchecked(options.values[statusIndex]))); const schemaIndex = __pulse_fastly_find(options, "schema"); if (json && schemaIndex >= 0) { bodyValue = __pulse_fastly_schema_apply(__pulse_fastly_string(unchecked(options.values[schemaIndex])), value, true); if (bodyValue <= 0) return 0 } __pulse_fastly_headers_from_options(options, output) } output.text = json ? __pulse_fastly_json(bodyValue, 0) : __pulse_fastly_string(value); let hasContentType = false; for (let i = 0; i < output.headers.length; i += 1) if (unchecked(output.headers[i]).name.toLowerCase() == "content-type") hasContentType = true; if (!hasContentType) output.headers.push(new __PulseFastlyHeader("content-type", json ? "application/json; charset=utf-8" : "text/plain; charset=utf-8")); return __pulse_fastly_put(output) }
|
|
1552
1629
|
function host_response_json(value: i32, options: i32): i32 { return __pulse_fastly_response(value, options, true) }
|
|
1630
|
+
function host_schema_decode(text: i32, schema: i32): i32 {
|
|
1631
|
+
const id = __pulse_fastly_value(schema)
|
|
1632
|
+
if (id.kind != PULSE_VALUE_STRING || id.text.length == 0) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 55, -1); return 0 }
|
|
1633
|
+
const input = __pulse_fastly_value(text)
|
|
1634
|
+
if (input.kind != PULSE_VALUE_STRING) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 52, -1); return 0 }
|
|
1635
|
+
if (String.UTF8.byteLength(input.text) > __PULSE_SCHEMA_MAX_BYTES) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 21, -1); return 0 }
|
|
1636
|
+
const parsed = __pulse_fastly_parse_json(input.text)
|
|
1637
|
+
if (parsed <= 0) return 0
|
|
1638
|
+
const decoded = __pulse_fastly_schema_apply(id.text, parsed, false)
|
|
1639
|
+
if (decoded <= 0) return 0
|
|
1640
|
+
__pulse_fastly_deep_freeze(decoded)
|
|
1641
|
+
return decoded
|
|
1642
|
+
}
|
|
1643
|
+
function host_schema_encode(value: i32, schema: i32): i32 {
|
|
1644
|
+
const id = __pulse_fastly_value(schema)
|
|
1645
|
+
if (id.kind != PULSE_VALUE_STRING || id.text.length == 0) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 55, -1); return 0 }
|
|
1646
|
+
const projected = __pulse_fastly_schema_apply(id.text, value, true)
|
|
1647
|
+
if (projected <= 0) return 0
|
|
1648
|
+
const text = __pulse_fastly_json(projected, 0)
|
|
1649
|
+
if (String.UTF8.byteLength(text) > __PULSE_SCHEMA_MAX_BYTES) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 21, -1); return 0 }
|
|
1650
|
+
return __pulse_fastly_string_value(text)
|
|
1651
|
+
}
|
|
1553
1652
|
function host_response_text(value: i32, options: i32): i32 { return __pulse_fastly_response(value, options, false) }
|
|
1554
1653
|
function host_response_custom(specHandle: i32): i32 { const spec = __pulse_fastly_value(specHandle); if (spec.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 40, -1); return 0 } const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE; output.status = 200; const statusIndex = __pulse_fastly_find(spec, "status"); if (statusIndex >= 0) output.status = i32(__pulse_fastly_number(unchecked(spec.values[statusIndex]))); const bodyIndex = __pulse_fastly_find(spec, "body"); if (bodyIndex >= 0) output.text = __pulse_fastly_string(unchecked(spec.values[bodyIndex])); __pulse_fastly_headers_from_options(spec, output); return __pulse_fastly_put(output) }
|
|
1555
1654
|
function __pulse_fastly_grip_frame_channels(options: __PulseFastlyValue, output: __PulseFastlyValue): bool { const channelsIndex = __pulse_fastly_find(options, "channels"); const channelIndex = __pulse_fastly_find(options, "channel"); let count = 0; if (channelsIndex >= 0) { const channels = __pulse_fastly_value(unchecked(options.values[channelsIndex])); if (channels.kind != PULSE_VALUE_ARRAY) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 133, -1); return false } for (let i = 0; i < channels.values.length; i += 1) { const channel = __pulse_fastly_string(unchecked(channels.values[i])).trim(); if (channel.length == 0 || channel.indexOf(",") >= 0 || channel.indexOf("\r") >= 0 || channel.indexOf("\n") >= 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 134, -1); return false } output.headers.push(new __PulseFastlyHeader("Grip-Channel", channel)); count += 1 } } else if (channelIndex >= 0) { const channel = __pulse_fastly_string(unchecked(options.values[channelIndex])).trim(); if (channel.length == 0 || channel.indexOf(",") >= 0 || channel.indexOf("\r") >= 0 || channel.indexOf("\n") >= 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 134, -1); return false } output.headers.push(new __PulseFastlyHeader("Grip-Channel", channel)); count = 1 } if (count == 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 135, -1); return false } return true }
|
|
@@ -1641,7 +1740,7 @@ export function ${entryName}(): void {
|
|
|
1641
1740
|
if (__pulse_fastly_last_error != 0) { __pulse_fastly_jwt_send_error(); return }
|
|
1642
1741
|
__pulse_fastly_request_path = __pulse_fastly_path(__pulse_fastly_request_url)
|
|
1643
1742
|
let runStatus = pulse_start()
|
|
1644
|
-
while (runStatus == 1 && __pulse_fastly_last_error == 0) {
|
|
1743
|
+
${applicationErrors.enabled(plan) ? applicationErrors.driverLoop(plan) : ` while (runStatus == 1 && __pulse_fastly_last_error == 0) {
|
|
1645
1744
|
for (let effectIndex = 0; effectIndex < PULSE_FASTLY_EFFECT_COUNT; effectIndex += 1) {
|
|
1646
1745
|
if (unchecked(__pulse_fastly_pending_mode[effectIndex]) == PULSE_FASTLY_PENDING_NONE) continue
|
|
1647
1746
|
const result = __pulse_fastly_resolve_effect(effectIndex)
|
|
@@ -1649,7 +1748,7 @@ export function ${entryName}(): void {
|
|
|
1649
1748
|
if (pulse_set_effect_result(effectIndex, result) != 1) { __pulse_fastly_fail(PULSE_ERROR_STATE, 101, effectIndex); __pulse_fastly_jwt_send_error(); return }
|
|
1650
1749
|
}
|
|
1651
1750
|
runStatus = pulse_resume()
|
|
1652
|
-
}
|
|
1751
|
+
}`}
|
|
1653
1752
|
if (__pulse_fastly_last_error != 0) { __pulse_fastly_jwt_send_error(); return }
|
|
1654
1753
|
if (runStatus != 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 102, -1); __pulse_fastly_jwt_send_error(); return }
|
|
1655
1754
|
const result = pulse_result_handle()
|
|
@@ -1662,6 +1761,7 @@ export function ${entryName}(): void {
|
|
|
1662
1761
|
}
|
|
1663
1762
|
|
|
1664
1763
|
function capabilityImports(effect) {
|
|
1764
|
+
if (effect.kind === 'time.now') return ['wasi_snapshot_preview1.clock_time_get'];
|
|
1665
1765
|
if (effect.kind === 'config.get') return ['fastly_config_store.open', 'fastly_config_store.get'];
|
|
1666
1766
|
if (effect.kind === 'secret.get') return ['fastly_secret_store.open', 'fastly_secret_store.get', 'fastly_secret_store.plaintext'];
|
|
1667
1767
|
if (effect.kind === 'jwt.verify') {
|
|
@@ -1724,7 +1824,7 @@ function generateFastlyNativePlatformCapabilitiesAssemblyScript(plan, options =
|
|
|
1724
1824
|
const portableSource = stripPulseHostImports(portable.source);
|
|
1725
1825
|
const hasJwt = (plan.effects || []).some((effect) => effect.kind === 'jwt.verify');
|
|
1726
1826
|
const jwtSource = hasJwt ? pulseJwtAssemblyScriptSource() : undefined;
|
|
1727
|
-
|
|
1827
|
+
let source = [
|
|
1728
1828
|
'/* Generated by Pulse Pass98 Fastly native platform capability compiler. */',
|
|
1729
1829
|
'export function __pulse_fastly_abort(message: string | null, fileName: string | null = null, line: u32 = 0, column: u32 = 0): void { unreachable() }',
|
|
1730
1830
|
'',
|
|
@@ -1735,11 +1835,20 @@ function generateFastlyNativePlatformCapabilitiesAssemblyScript(plan, options =
|
|
|
1735
1835
|
}),
|
|
1736
1836
|
jwtSource ? jwtSource.source : '',
|
|
1737
1837
|
require('./s3-native.js').s3NativeSource(plan, bindings),
|
|
1838
|
+
require('./time-native.js').timeNativeSource(plan),
|
|
1839
|
+
require('./digest-native.js').digestNativeSource(plan),
|
|
1738
1840
|
conditionalKv.kvNativeSource(plan),
|
|
1841
|
+
require('./native-request-body.js').runtimeSource(),
|
|
1842
|
+
require('./native-request-headers.js').runtimeSource(),
|
|
1843
|
+
applicationErrors.enabled(plan) ? applicationErrors.runtimeSource() : '',
|
|
1739
1844
|
portableSource,
|
|
1740
1845
|
driverSource(plan, { guestLinked: facts.guestUnits.length > 0 }),
|
|
1741
1846
|
''
|
|
1742
1847
|
].join('\n');
|
|
1848
|
+
if (applicationErrors.enabled(plan)) source = applicationErrors.instrument(source);
|
|
1849
|
+
source = require('./native-request-headers.js').instrument(source, applicationErrors.enabled(plan), /\bhost_request_headers\(/.test(portableSource));
|
|
1850
|
+
source = require('./native-request-body.js').instrument(source, applicationErrors.enabled(plan));
|
|
1851
|
+
source = require('./request-budget.js').instrumentRequestBudget(source, bindings.maxDurationMs, plan);
|
|
1743
1852
|
const effectKinds = Object.freeze((plan.effects || []).reduce((output, effect) => {
|
|
1744
1853
|
output[effect.kind] = (output[effect.kind] || 0) + 1;
|
|
1745
1854
|
return output;
|
|
@@ -1799,7 +1908,8 @@ function generateFastlyNativePlatformCapabilitiesAssemblyScript(plan, options =
|
|
|
1799
1908
|
'pulse_fastly_error_stage',
|
|
1800
1909
|
'pulse_fastly_error_effect',
|
|
1801
1910
|
'pulse_plan_hash_ptr',
|
|
1802
|
-
'pulse_plan_hash_length'
|
|
1911
|
+
'pulse_plan_hash_length',
|
|
1912
|
+
...(bindings.maxDurationMs === undefined ? [] : ['pulse_fastly_request_expired'])
|
|
1803
1913
|
]),
|
|
1804
1914
|
policy: Object.freeze({
|
|
1805
1915
|
nativeFastly: true,
|
|
@@ -1807,7 +1917,7 @@ function generateFastlyNativePlatformCapabilitiesAssemblyScript(plan, options =
|
|
|
1807
1917
|
providerNeutralInput: true,
|
|
1808
1918
|
javascriptRuntime: false,
|
|
1809
1919
|
jsComputeRuntime: false,
|
|
1810
|
-
wasi: hasJwt || bindings.s3.length || plan.effects.some(effect => conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind)) ? 'clock_time_get only' : false,
|
|
1920
|
+
wasi: bindings.maxDurationMs !== undefined || hasJwt || bindings.s3.length || plan.effects.some(effect => conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind)) ? 'clock_time_get only' : false,
|
|
1811
1921
|
effects: FASTLY_NATIVE_PLATFORM_EFFECT_KINDS.join(', '),
|
|
1812
1922
|
continuations: true,
|
|
1813
1923
|
groupedEffects: 'existing fetch start-before-wait ordering remains intact',
|
|
@@ -1943,6 +2053,9 @@ function compileFastlyNativePlatformCapabilitiesPlan(plan, options = {}) {
|
|
|
1943
2053
|
'--optimize'
|
|
1944
2054
|
];
|
|
1945
2055
|
const optimization = appendAssemblyScriptOptimizationArgs(args, nativeOptimization);
|
|
2056
|
+
if (!guestLinked && plan.effects.some(effect => effect.kind === 'crypto.digestText' || effect.kind.startsWith('s3.'))) {
|
|
2057
|
+
args.push('--maximumMemory', '4096');
|
|
2058
|
+
}
|
|
1946
2059
|
if (generated.guestUnits.length > 0) {
|
|
1947
2060
|
args.push(
|
|
1948
2061
|
'--disable', 'bulk-memory',
|
|
@@ -1972,7 +2085,7 @@ function compileFastlyNativePlatformCapabilitiesPlan(plan, options = {}) {
|
|
|
1972
2085
|
maxBuffer: 64 * 1024 * 1024,
|
|
1973
2086
|
timeout: Number(options.timeoutMs || 180000),
|
|
1974
2087
|
env: schemaCodecsActive
|
|
1975
|
-
? { ...process.env, JSON_STRICT: 'true', JSON_USE_FAST_PATH: '0' }
|
|
2088
|
+
? { ...process.env, JSON_STRICT: 'true', JSON_USE_FAST_PATH: '0', JSON_MODE: 'NAIVE' }
|
|
1976
2089
|
: process.env
|
|
1977
2090
|
});
|
|
1978
2091
|
const assemblyScriptDurationMs = Date.now() - startedAt;
|
|
@@ -2112,7 +2225,7 @@ function compileFastlyNativePlatformCapabilitiesPlan(plan, options = {}) {
|
|
|
2112
2225
|
compilerVersion: FASTLY_NATIVE_PLATFORM_CAPABILITIES_COMPILER_VERSION,
|
|
2113
2226
|
assemblyScript: Object.freeze({ package: 'assemblyscript', version: require(path.join(asc.packageRoot, 'package.json')).version }),
|
|
2114
2227
|
jsonAs: jsonAs
|
|
2115
|
-
? Object.freeze({ package: 'json-as', version: jsonAs.version, transform: true, strict: true })
|
|
2228
|
+
? Object.freeze({ package: 'json-as', version: jsonAs.version, transform: true, strict: true, mode: 'NAIVE', fastPath: false })
|
|
2116
2229
|
: undefined,
|
|
2117
2230
|
optimization,
|
|
2118
2231
|
wasm: Object.freeze({ bytes: inspection.bytes, sha256: inspection.sha256, magic: inspection.magic }),
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function runtimeSource() {
|
|
4
|
+
return `
|
|
5
|
+
let __pulse_request_body_failure: i32 = 0
|
|
6
|
+
// Validate the bounded, assembled request bytes before any text projection.
|
|
7
|
+
function __pulse_request_utf8_valid(bytes: Uint8Array): bool {
|
|
8
|
+
for (let i = 0; i < bytes.length;) {
|
|
9
|
+
const lead = bytes[i++]; if (lead < 128) continue;
|
|
10
|
+
let count = 0, minimum = 128, maximum = 191;
|
|
11
|
+
if (lead >= 194 && lead <= 223) count = 1;
|
|
12
|
+
else if (lead >= 224 && lead <= 239) { count = 2; if (lead == 224) minimum = 160; if (lead == 237) maximum = 159; }
|
|
13
|
+
else if (lead >= 240 && lead <= 244) { count = 3; if (lead == 240) minimum = 144; if (lead == 244) maximum = 143; }
|
|
14
|
+
else return false;
|
|
15
|
+
if (i + count > bytes.length || i32(bytes[i]) < minimum || i32(bytes[i]) > maximum) return false;
|
|
16
|
+
i++; for (let n = 1; n < count; n++, i++) if (bytes[i] < 128 || bytes[i] > 191) return false;
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
function __pulse_request_send_body_error(): bool {
|
|
21
|
+
if (__pulse_fastly_last_error != PULSE_ERROR_REQUEST_BODY) return false;
|
|
22
|
+
const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE;
|
|
23
|
+
output.status = __pulse_fastly_error_stage == 21 ? 413 : 400;
|
|
24
|
+
output.text = output.status == 413 ? "Payload Too Large" : "Bad Request";
|
|
25
|
+
output.headers.push(new __PulseFastlyHeader("content-type", "text/plain; charset=utf-8"));
|
|
26
|
+
__pulse_fastly_last_error = 0; __pulse_fastly_error_stage = 0; __pulse_fastly_error_effect = -1;
|
|
27
|
+
const status = __pulse_fastly_send_result(__pulse_fastly_put(output));
|
|
28
|
+
if (status != FASTLY_STATUS_OK) __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 104, -1);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function instrument(source, applicationErrors) {
|
|
35
|
+
if (!applicationErrors) source = source.replace(/function (host_\w+)\(([^)]*)\): (i32|void) \{/g,
|
|
36
|
+
(declaration, _name, _args, result) => `${declaration} if (__pulse_fastly_last_error == PULSE_ERROR_REQUEST_BODY) return${result === 'void' ? '' : ' 0'};`);
|
|
37
|
+
// The existing terminal failure path also covers applications without an
|
|
38
|
+
// error handler. Request-budget instrumentation subsequently takes priority.
|
|
39
|
+
const marker = 'function __pulse_fastly_jwt_send_error(): void {';
|
|
40
|
+
if (!source.includes(marker)) throw new Error('Fastly request-body error boundary drift.');
|
|
41
|
+
return source.replace(marker, marker + ' if (__pulse_request_send_body_error()) return;');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = { runtimeSource, instrument };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Fastly's multi-value ABI returns NUL-delimited pages and an i64 next cursor
|
|
4
|
+
// (-1 marks completion). See https://docs.rs/fastly/latest/src/fastly/abi.rs.html
|
|
5
|
+
// Keep this independent of outbound response headers.
|
|
6
|
+
function runtimeSource() {
|
|
7
|
+
return `
|
|
8
|
+
@external("fastly_http_req", "header_names_get")
|
|
9
|
+
declare function __pulse_request_header_names(handle: i32, buffer: usize, size: i32, cursor: i32, end: usize, written: usize): i32
|
|
10
|
+
@external("fastly_http_req", "header_values_get")
|
|
11
|
+
declare function __pulse_request_header_values(handle: i32, name: usize, length: i32, buffer: usize, size: i32, cursor: i32, end: usize, written: usize): i32
|
|
12
|
+
let __pulse_request_headers_snapshot: i32 = 0
|
|
13
|
+
let __pulse_request_headers_failed: bool = false
|
|
14
|
+
let __pulse_request_headers_bytes: i32 = 0
|
|
15
|
+
function __pulse_request_headers_fail(): void {
|
|
16
|
+
__pulse_request_headers_failed = true;
|
|
17
|
+
__pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 24, -1);
|
|
18
|
+
}
|
|
19
|
+
function __pulse_request_header_list(name: string, names: bool): Array<string> {
|
|
20
|
+
const output = new Array<string>();
|
|
21
|
+
const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES);
|
|
22
|
+
const end = new StaticArray<i64>(1), written = new StaticArray<i32>(1);
|
|
23
|
+
const key = __pulse_fastly_utf8(name);
|
|
24
|
+
let cursor: i64 = 0;
|
|
25
|
+
let bytes = 0;
|
|
26
|
+
for (let page = 0; page < 256; page++) {
|
|
27
|
+
end[0] = 0; written[0] = -1;
|
|
28
|
+
const status = names
|
|
29
|
+
? __pulse_request_header_names(__pulse_fastly_request_handle, buffer.dataStart, buffer.length, i32(cursor), changetype<usize>(end), changetype<usize>(written))
|
|
30
|
+
: __pulse_request_header_values(__pulse_fastly_request_handle, changetype<usize>(key), key.byteLength, buffer.dataStart, buffer.length, i32(cursor), changetype<usize>(end), changetype<usize>(written));
|
|
31
|
+
const count = written[0], next = end[0];
|
|
32
|
+
if (status == FASTLY_STATUS_OK && count == 0 && cursor == 0 && next == 0) return output;
|
|
33
|
+
if (status != FASTLY_STATUS_OK || count < 0 || count > buffer.length
|
|
34
|
+
|| (next != -1 && (next <= cursor || next > 4294967295 || count == 0))) {
|
|
35
|
+
__pulse_request_headers_fail(); return output;
|
|
36
|
+
}
|
|
37
|
+
bytes += count;
|
|
38
|
+
if (bytes > PULSE_FASTLY_BUFFER_BYTES) { __pulse_request_headers_fail(); return output; }
|
|
39
|
+
let start = 0;
|
|
40
|
+
for (let i = 0; i < count; i++) {
|
|
41
|
+
if (buffer[i] != 0) continue;
|
|
42
|
+
const size = i - start;
|
|
43
|
+
// Count name bytes once per returned pair, including both terminators.
|
|
44
|
+
if (!names) __pulse_request_headers_bytes += key.byteLength + size + 2;
|
|
45
|
+
if (output.length >= 256 || (names && size == 0) || __pulse_request_headers_bytes > PULSE_FASTLY_BUFFER_BYTES) {
|
|
46
|
+
__pulse_request_headers_fail(); return output;
|
|
47
|
+
}
|
|
48
|
+
output.push(String.UTF8.decodeUnsafe(buffer.dataStart + start, size, false));
|
|
49
|
+
start = i + 1;
|
|
50
|
+
}
|
|
51
|
+
if (start != count) { __pulse_request_headers_fail(); return output; }
|
|
52
|
+
if (next == -1) return output;
|
|
53
|
+
cursor = next;
|
|
54
|
+
}
|
|
55
|
+
__pulse_request_headers_fail(); return output;
|
|
56
|
+
}
|
|
57
|
+
function __pulse_request_headers_read(): i32 {
|
|
58
|
+
if (__pulse_request_headers_failed) { __pulse_request_headers_fail(); return 0; }
|
|
59
|
+
if (__pulse_request_headers_snapshot != 0) return __pulse_request_headers_snapshot;
|
|
60
|
+
const names = __pulse_request_header_list("", true);
|
|
61
|
+
if (__pulse_request_headers_failed) return 0;
|
|
62
|
+
const output = host_value_array();
|
|
63
|
+
let pairs = 0;
|
|
64
|
+
for (let n = 0; n < names.length; n++) {
|
|
65
|
+
const name = names[n].toLowerCase();
|
|
66
|
+
for (let previous = 0; previous < n; previous++) {
|
|
67
|
+
if (names[previous].toLowerCase() == name) { __pulse_request_headers_fail(); return 0; }
|
|
68
|
+
}
|
|
69
|
+
const values = __pulse_request_header_list(name, false);
|
|
70
|
+
if (__pulse_request_headers_failed) return 0;
|
|
71
|
+
if (values.length == 0 || pairs + values.length > 256) { __pulse_request_headers_fail(); return 0; }
|
|
72
|
+
pairs += values.length;
|
|
73
|
+
for (let v = 0; v < values.length; v++) {
|
|
74
|
+
const pair = host_value_array();
|
|
75
|
+
host_value_array_push(pair, __pulse_fastly_string_value(name));
|
|
76
|
+
host_value_array_push(pair, __pulse_fastly_string_value(values[v]));
|
|
77
|
+
host_value_array_push(output, pair);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
__pulse_fastly_deep_freeze(output);
|
|
81
|
+
__pulse_request_headers_snapshot = output;
|
|
82
|
+
return output;
|
|
83
|
+
}
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function instrument(source, applicationErrors, used) {
|
|
88
|
+
if (applicationErrors || !used) return source;
|
|
89
|
+
return source.replace(/function (host_\w+)\(([^)]*)\): (i32|void) \{/g,
|
|
90
|
+
(declaration, _name, _args, result) => `${declaration} if (__pulse_request_headers_failed) return${result === 'void' ? '' : ' 0'};`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = { runtimeSource, instrument };
|