@pulse-compute/provider-fastly 0.0.0 → 1.0.0-beta.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.
Files changed (63) hide show
  1. package/README.md +52 -1
  2. package/dist/config-schema.json +73 -0
  3. package/dist/index.d.ts +61 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +59 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +87 -5
  8. package/src/build/canonical-target.js +436 -0
  9. package/src/build/entities-native.js +564 -0
  10. package/src/build/fixed-memory-runtime.as.ts +148 -0
  11. package/src/build/native-http-effects.js +871 -0
  12. package/src/build/native-http-shell.js +703 -0
  13. package/src/build/native-platform-capabilities.js +2109 -0
  14. package/src/compiler/assets-package-out-parity-proof.js +338 -0
  15. package/src/compiler/assets-provider-proof.js +499 -0
  16. package/src/compiler/config-provider-resolution.js +573 -0
  17. package/src/compiler/fastly-adapter.js +564 -0
  18. package/src/compiler/fastly-command-entry.js +390 -0
  19. package/src/compiler/fastly-config-secret-serve.js +323 -0
  20. package/src/compiler/fastly-hostcall-binding.js +598 -0
  21. package/src/compiler/fastly-readiness.js +477 -0
  22. package/src/compiler/index.js +40 -0
  23. package/src/compiler/lifecycle-parity-contract.js +70 -0
  24. package/src/compiler/lifecycle-parity-proof.js +260 -0
  25. package/src/compiler/route-handler-effect-proof.js +255 -0
  26. package/src/compiler/runtime-provider-kv.js +237 -0
  27. package/src/compiler/runtime-provider-shape.js +109 -0
  28. package/src/config-api.js +63 -0
  29. package/src/config-schema.d.ts +13 -0
  30. package/src/config-schema.js +27 -0
  31. package/src/config-schema.json +73 -0
  32. package/src/index.js +3 -0
  33. package/src/index.ts +118 -0
  34. package/src/javascript/assets-adapter.js +122 -0
  35. package/src/javascript/bindings-adapter.js +237 -0
  36. package/src/javascript/errors.js +26 -0
  37. package/src/javascript/fetch-adapter.js +93 -0
  38. package/src/javascript/grip-broadcast.js +261 -0
  39. package/src/javascript/jwt-verifier.js +137 -0
  40. package/src/javascript/lifecycle.js +55 -0
  41. package/src/javascript/local-loader.js +138 -0
  42. package/src/javascript/logging.js +26 -0
  43. package/src/javascript/package-effects.js +68 -0
  44. package/src/javascript/runtime-host.js +108 -0
  45. package/src/javascript/sha256.js +128 -0
  46. package/src/javascript/source-package.js +776 -0
  47. package/src/javascript/support.js +142 -0
  48. package/src/javascript/target-support-policy.js +260 -0
  49. package/src/javascript/target.js +73 -0
  50. package/src/javascript/test-runtime.js +407 -0
  51. package/src/provider-contract.js +72 -0
  52. package/src/runtime/assets-provider.js +464 -0
  53. package/src/runtime/canonical-api-runtime.js +597 -0
  54. package/src/runtime/index.js +28 -0
  55. package/src/runtime/provider-primitives-contract.js +272 -0
  56. package/src/runtime/provider-primitives.js +82 -0
  57. package/src/runtime/route-handler-effects.js +507 -0
  58. package/src/testing/fastly-cli.js +538 -0
  59. package/src/testing/native-http-effects-host.js +390 -0
  60. package/src/testing/native-http-shell-host.js +190 -0
  61. package/src/testing/native-platform-capabilities-host.js +599 -0
  62. package/src/toolchain/config.js +128 -0
  63. package/src/toolchain/index.js +343 -0
@@ -0,0 +1,871 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const fs = require('node:fs');
5
+ const os = require('node:os');
6
+ const path = require('node:path');
7
+ const { spawnSync } = require('node:child_process');
8
+ const { CANONICAL_NATIVE_PLAN_VERSION } = require('@pulse-compute/wasm-contracts/handler/canonical-native-plan');
9
+
10
+ function loadBuildSupport() {
11
+ try { return require('@pulse-compute/wasm-build-support/assemblyscript-compile'); }
12
+ catch (error) {
13
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) {
14
+ return require('../../../../wasm/packages/build-support/src/assemblyscript-compile.js');
15
+ }
16
+ throw error;
17
+ }
18
+ }
19
+
20
+ function loadNativeGenerator() {
21
+ try { return require('@pulse-compute/wasm-runtime-core-as/compiler/canonical-native'); }
22
+ catch (error) {
23
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) {
24
+ return require('../../../../wasm/packages/runtime-core-as/src/compiler/canonical-native.js');
25
+ }
26
+ throw error;
27
+ }
28
+ }
29
+
30
+ const { resolveAsc } = loadBuildSupport();
31
+ const { generateCanonicalNativeAssemblyScript } = loadNativeGenerator();
32
+
33
+ const FASTLY_NATIVE_HTTP_EFFECTS_VERSION = 'pulse.fastly-native-http-effects.v1';
34
+ const FASTLY_NATIVE_HTTP_EFFECTS_GENERATOR_VERSION = 'pulse.fastly-native-http-effects-generator.v1';
35
+ const FASTLY_NATIVE_HTTP_EFFECTS_COMPILER_VERSION = 'pulse.fastly-native-http-effects-compiler.v1';
36
+ const FASTLY_NATIVE_HTTP_EFFECTS_ABI_VERSION = 1;
37
+ const FASTLY_NATIVE_HTTP_EFFECTS_MAX_WASM_BYTES = 1024 * 1024;
38
+ const FASTLY_NATIVE_HTTP_EFFECTS_BUFFER_BYTES = 65536;
39
+
40
+ const FASTLY_NATIVE_HTTP_EFFECTS_IMPORTS = Object.freeze([
41
+ Object.freeze(['fastly_abi', 'init']),
42
+ Object.freeze(['fastly_http_req', 'body_downstream_get']),
43
+ Object.freeze(['fastly_http_req', 'method_get']),
44
+ Object.freeze(['fastly_http_req', 'uri_get']),
45
+ Object.freeze(['fastly_http_req', 'header_value_get']),
46
+ Object.freeze(['fastly_http_req', 'new']),
47
+ Object.freeze(['fastly_http_req', 'method_set']),
48
+ Object.freeze(['fastly_http_req', 'uri_set']),
49
+ Object.freeze(['fastly_http_req', 'header_insert']),
50
+ Object.freeze(['fastly_http_req', 'send_async']),
51
+ Object.freeze(['fastly_http_req', 'pending_req_wait']),
52
+ Object.freeze(['fastly_http_resp', 'new']),
53
+ Object.freeze(['fastly_http_resp', 'header_append']),
54
+ Object.freeze(['fastly_http_resp', 'header_value_get']),
55
+ Object.freeze(['fastly_http_resp', 'status_get']),
56
+ Object.freeze(['fastly_http_resp', 'status_set']),
57
+ Object.freeze(['fastly_http_resp', 'send_downstream']),
58
+ Object.freeze(['fastly_http_body', 'new']),
59
+ Object.freeze(['fastly_http_body', 'read']),
60
+ Object.freeze(['fastly_http_body', 'write'])
61
+ ]);
62
+
63
+ const FASTLY_NATIVE_HTTP_EFFECTS_REQUIRED_IMPORTS = Object.freeze([
64
+ Object.freeze(['fastly_abi', 'init']),
65
+ Object.freeze(['fastly_http_req', 'body_downstream_get']),
66
+ Object.freeze(['fastly_http_req', 'new']),
67
+ Object.freeze(['fastly_http_req', 'send_async']),
68
+ Object.freeze(['fastly_http_req', 'pending_req_wait']),
69
+ Object.freeze(['fastly_http_resp', 'send_downstream']),
70
+ Object.freeze(['fastly_http_body', 'new']),
71
+ Object.freeze(['fastly_http_body', 'write'])
72
+ ]);
73
+
74
+ const FASTLY_NATIVE_HTTP_EFFECTS_ALLOWED_IMPORTS = new Set([
75
+ ...FASTLY_NATIVE_HTTP_EFFECTS_IMPORTS.map(([moduleName, name]) => `${moduleName}:${name}`)
76
+ ]);
77
+
78
+ class FastlyNativeHttpEffectsError extends Error {
79
+ constructor(message, code = 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_FAILED', detail = {}) {
80
+ super(message);
81
+ this.name = 'FastlyNativeHttpEffectsError';
82
+ this.code = code;
83
+ this.detail = Object.freeze({ ...detail });
84
+ }
85
+ }
86
+
87
+ function sha256(value) {
88
+ return crypto.createHash('sha256').update(value).digest('hex');
89
+ }
90
+
91
+ function stableObject(value) {
92
+ if (Array.isArray(value)) return value.map(stableObject);
93
+ if (!value || typeof value !== 'object') return value;
94
+ const output = {};
95
+ for (const key of Object.keys(value).sort()) if (value[key] !== undefined) output[key] = stableObject(value[key]);
96
+ return output;
97
+ }
98
+
99
+ function stableStringify(value, space = 0) {
100
+ return JSON.stringify(stableObject(value), null, space);
101
+ }
102
+
103
+ function quote(value) {
104
+ return JSON.stringify(String(value));
105
+ }
106
+
107
+ function fail(message, code, detail = {}) {
108
+ throw new FastlyNativeHttpEffectsError(message, code, detail);
109
+ }
110
+
111
+ function validatePlanBoundary(plan) {
112
+ if (!plan || typeof plan !== 'object') throw new TypeError('Fastly native HTTP effects realization requires a canonical native plan.');
113
+ if (plan.version !== CANONICAL_NATIVE_PLAN_VERSION) {
114
+ fail(`Fastly native HTTP effects realization requires ${CANONICAL_NATIVE_PLAN_VERSION}.`, 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_PLAN_VERSION_UNSUPPORTED', { version: plan.version });
115
+ }
116
+ if (!plan.ownership || plan.ownership.providerNeutral !== true || plan.ownership.javascriptRuntime !== false) {
117
+ fail('Fastly native HTTP effects realization requires a provider-neutral plan without JavaScript runtime ownership.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_PLAN_OWNERSHIP_INVALID', { ownership: plan.ownership });
118
+ }
119
+ const packageEffects = ((plan.packages && plan.packages.effects) || []);
120
+ if (packageEffects.length > 0) {
121
+ fail('Pass97 does not realize package-owned Fastly effects; config, secret, KV, and GRIP are introduced in Pass98.', 'PULSE_FASTLY_NATIVE_HTTP_PLATFORM_EFFECTS_DEFERRED', { effects: packageEffects.map((entry) => entry.id) });
122
+ }
123
+ const unsupported = (plan.effects || []).filter((effect) => effect.kind !== 'fetch');
124
+ if (unsupported.length > 0) {
125
+ fail('Pass97 realizes only outbound HTTP fetch effects.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECT_KIND_UNSUPPORTED', { effects: unsupported.map((entry) => ({ id: entry.id, kind: entry.kind })) });
126
+ }
127
+ if ((plan.effects || []).length === 0) {
128
+ fail('Pass97 requires at least one outbound HTTP effect.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECT_REQUIRED');
129
+ }
130
+ if (!plan.entry || !Array.isArray(plan.entry.body)) {
131
+ fail('Fastly native HTTP effects realization requires a canonical handler entry body.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_ENTRY_INVALID');
132
+ }
133
+ return plan;
134
+ }
135
+
136
+ function literalOriginFromExpression(expression) {
137
+ if (!expression || typeof expression !== 'object') return undefined;
138
+ if (expression.kind === 'literal' && typeof expression.value === 'string') {
139
+ try { return new URL(expression.value).origin; }
140
+ catch (_) { return undefined; }
141
+ }
142
+ if (expression.kind === 'template') {
143
+ const first = (expression.parts || [])[0];
144
+ if (first && first.kind === 'text') {
145
+ try { return new URL(first.value).origin; }
146
+ catch (_) { return undefined; }
147
+ }
148
+ }
149
+ return undefined;
150
+ }
151
+
152
+ function resolveBackendBindings(plan, options = {}) {
153
+ const byEffect = options.effectBackends || {};
154
+ const byOrigin = options.backends || {};
155
+ const bindings = [];
156
+ for (const [index, effect] of (plan.effects || []).entries()) {
157
+ const urlInput = (effect.inputs || []).find((entry) => entry.name === 'url');
158
+ const origin = effect.resource && effect.resource.origin
159
+ ? String(effect.resource.origin)
160
+ : literalOriginFromExpression(urlInput && urlInput.value);
161
+ const backend = byEffect[effect.id]
162
+ || (origin && byOrigin[origin])
163
+ || (effect.resource && effect.resource.value && byOrigin[effect.resource.value]);
164
+ if (typeof backend !== 'string' || backend.trim() === '') {
165
+ fail(`Fastly native effect ${effect.id} has no static backend binding.`, 'PULSE_FASTLY_NATIVE_HTTP_BACKEND_MISSING', {
166
+ effectId: effect.id,
167
+ effectIndex: index,
168
+ origin,
169
+ hint: `Provide options.effectBackends[${JSON.stringify(effect.id)}] or options.backends[${JSON.stringify(origin || '<origin>')}].`
170
+ });
171
+ }
172
+ bindings.push(Object.freeze({ index, effectId: effect.id, origin: origin || null, backend: backend.trim() }));
173
+ }
174
+ return Object.freeze(bindings);
175
+ }
176
+
177
+ function stripPulseHostImports(source) {
178
+ return String(source)
179
+ .split('\n')
180
+ .filter((line) => !line.startsWith('@external("pulse_host",'))
181
+ .join('\n');
182
+ }
183
+
184
+ function generateSchemaRuntime(plan) {
185
+ const registry = plan.schemas && plan.schemas.registry ? plan.schemas.registry : { schemas: [], maxBytes: FASTLY_NATIVE_HTTP_EFFECTS_BUFFER_BYTES, contentTypePolicy: 'accept-json-or-missing' };
186
+ const schemas = registry.schemas || [];
187
+ const nodeLines = [];
188
+ let nodeIndex = 0;
189
+
190
+ function emitNode(schemaIndex, node) {
191
+ const currentIndex = nodeIndex++;
192
+ const functionName = `__pulse_fastly_schema_${schemaIndex}_${currentIndex}`;
193
+ const child = node.kind === 'nullable'
194
+ ? emitNode(schemaIndex, node.value)
195
+ : node.kind === 'array'
196
+ ? emitNode(schemaIndex, node.element)
197
+ : undefined;
198
+ const fields = node.kind === 'object'
199
+ ? node.fields.map((field) => Object.freeze({ field, apply: emitNode(schemaIndex, field.value) }))
200
+ : [];
201
+ const body = [`function ${functionName}(valueHandle: i32): i32 {`, ' const input = __pulse_fastly_value(valueHandle)'];
202
+ if (node.kind === 'nullable') {
203
+ body.push(' if (input.kind == PULSE_VALUE_NULL) return valueHandle');
204
+ body.push(` return ${child}(valueHandle)`);
205
+ } else if (node.kind === 'array') {
206
+ body.push(' if (input.kind != PULSE_VALUE_ARRAY) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 52, -1); return 0 }');
207
+ body.push(' const output = host_value_array()');
208
+ body.push(' for (let index = 0; index < input.values.length; index += 1) {');
209
+ body.push(` const item = ${child}(unchecked(input.values[index]))`);
210
+ body.push(' if (item <= 0) return 0');
211
+ body.push(' host_value_array_push(output, item)');
212
+ body.push(' }');
213
+ body.push(' return output');
214
+ } else if (node.kind === 'object') {
215
+ body.push(' if (input.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 50, -1); return 0 }');
216
+ body.push(' const output = host_value_object()');
217
+ fields.forEach(({ field, apply }, fieldIndex) => {
218
+ body.push(` const key_${currentIndex}_${fieldIndex} = __pulse_fastly_string_value(${quote(field.name)})`);
219
+ body.push(` const field_${currentIndex}_${fieldIndex} = host_value_property(valueHandle, key_${currentIndex}_${fieldIndex})`);
220
+ body.push(` if (__pulse_fastly_value(field_${currentIndex}_${fieldIndex}).kind == PULSE_VALUE_UNDEFINED) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 51, -1); return 0 }`);
221
+ body.push(` const projected_${currentIndex}_${fieldIndex} = ${apply}(field_${currentIndex}_${fieldIndex})`);
222
+ body.push(` if (projected_${currentIndex}_${fieldIndex} <= 0) return 0`);
223
+ body.push(` host_value_object_set(output, key_${currentIndex}_${fieldIndex}, projected_${currentIndex}_${fieldIndex})`);
224
+ });
225
+ body.push(' return output');
226
+ } else if (node.kind === 'string') {
227
+ body.push(' if (input.kind != PULSE_VALUE_STRING) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 52, -1); return 0 }');
228
+ body.push(' return valueHandle');
229
+ } else if (node.kind === 'boolean') {
230
+ body.push(' if (input.kind != PULSE_VALUE_BOOLEAN) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 52, -1); return 0 }');
231
+ body.push(' return valueHandle');
232
+ } else if (node.kind === 'i32') {
233
+ body.push(' if (input.kind != PULSE_VALUE_NUMBER || !isFinite(input.number) || input.number < -2147483648.0 || input.number > 2147483647.0 || Math.floor(input.number) != input.number) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 53, -1); return 0 }');
234
+ body.push(' return valueHandle');
235
+ } else if (node.kind === 'u32') {
236
+ body.push(' if (input.kind != PULSE_VALUE_NUMBER || !isFinite(input.number) || input.number < 0.0 || input.number > 4294967295.0 || Math.floor(input.number) != input.number) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 53, -1); return 0 }');
237
+ body.push(' return valueHandle');
238
+ } else if (node.kind === 'f64') {
239
+ body.push(' if (input.kind != PULSE_VALUE_NUMBER || !isFinite(input.number)) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 53, -1); return 0 }');
240
+ body.push(' return valueHandle');
241
+ } else if (node.kind === 'string-enum') {
242
+ const allowed = node.values.map((value) => `input.text == ${quote(value)}`).join(' || ') || 'false';
243
+ body.push(` if (input.kind != PULSE_VALUE_STRING || !(${allowed})) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 54, -1); return 0 }`);
244
+ body.push(' return valueHandle');
245
+ } else {
246
+ throw new TypeError(`Unsupported Fastly native schema node ${String(node.kind)}.`);
247
+ }
248
+ body.push('}', '');
249
+ nodeLines.push(...body);
250
+ return functionName;
251
+ }
252
+
253
+ const roots = schemas.map((schema, schemaIndex) => emitNode(schemaIndex, schema.root));
254
+ const lines = [
255
+ `const __PULSE_SCHEMA_MAX_BYTES: i32 = ${Number(registry.maxBytes || FASTLY_NATIVE_HTTP_EFFECTS_BUFFER_BYTES)}`,
256
+ `const __PULSE_SCHEMA_REQUIRE_JSON: bool = ${registry.contentTypePolicy === 'require-json' ? 'true' : 'false'}`,
257
+ '',
258
+ ...nodeLines,
259
+ 'function __pulse_fastly_schema_apply(schemaId: string, valueHandle: i32, encode: bool): i32 {',
260
+ ' if (schemaId.length == 0) return valueHandle'
261
+ ];
262
+ for (const [schemaIndex, schema] of schemas.entries()) {
263
+ lines.push(`${schemaIndex === 0 ? ' if' : ' else if'} (schemaId == ${quote(schema.id)}) {`);
264
+ lines.push(` const projected = ${roots[schemaIndex]}(valueHandle)`);
265
+ lines.push(' if (projected <= 0) return 0');
266
+ lines.push(' const input = __pulse_fastly_json(projected, 0)');
267
+ lines.push(` const normalized = encode ? __pulse_schema_encode_${schemaIndex}(input) : __pulse_schema_decode_${schemaIndex}(input)`);
268
+ lines.push(' return __pulse_fastly_parse_json(normalized)');
269
+ lines.push(' }');
270
+ }
271
+ lines.push(' __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 55, -1)');
272
+ lines.push(' return 0');
273
+ lines.push('}');
274
+ lines.push('');
275
+ return lines.join('\n');
276
+ }
277
+
278
+ function effectResultSource(plan, bindings) {
279
+ const lines = ['function __pulse_fastly_backend(effectIndex: i32): string {', ' switch (effectIndex) {'];
280
+ for (const binding of bindings) lines.push(` case ${binding.index}: return ${quote(binding.backend)}`);
281
+ lines.push(' default: return ""', ' }', '}', '');
282
+ lines.push('function __pulse_fastly_resolve_effect(effectIndex: i32): i32 {');
283
+ lines.push(' const response = __pulse_fastly_wait_fetch(effectIndex)');
284
+ lines.push(' if (response <= 0) return 0');
285
+ lines.push(' switch (effectIndex) {');
286
+ for (const [index, effect] of (plan.effects || []).entries()) {
287
+ const result = effect.result || {};
288
+ const decoder = result.decoder;
289
+ lines.push(` case ${index}: {`);
290
+ if (result.valueKind === 'json' || (decoder && decoder.kind === 'json' && result.valueKind !== 'fetch-response')) {
291
+ const args = (decoder && decoder.arguments) || [];
292
+ const schemaId = args.length === 1 && args[0].kind === 'literal' && typeof args[0].value === 'string' ? args[0].value : '';
293
+ lines.push(` return host_fetch_json(response, ${schemaId ? `__pulse_fastly_string_value(${quote(schemaId)})` : 'host_value_undefined()'})`);
294
+ } else if (result.valueKind === 'text' || (decoder && decoder.kind === 'text')) {
295
+ lines.push(' return host_fetch_text(response)');
296
+ } else {
297
+ lines.push(' return response');
298
+ }
299
+ lines.push(' }');
300
+ }
301
+ lines.push(' default: __pulse_fastly_fail(PULSE_ERROR_STATE, 61, effectIndex); return 0');
302
+ lines.push(' }');
303
+ lines.push('}');
304
+ lines.push('');
305
+ return lines.join('\n');
306
+ }
307
+
308
+ function fastlyRuntimeSource(plan, bindings) {
309
+ const effectCount = (plan.effects || []).length;
310
+ return String.raw`
311
+ @external("fastly_abi", "init") declare function fastly_abi_init(version: i64): i32
312
+ @external("fastly_http_req", "body_downstream_get") declare function fastly_http_req_body_downstream_get(requestOut: usize, bodyOut: usize): i32
313
+ @external("fastly_http_req", "method_get") declare function fastly_http_req_method_get(handle: i32, buffer: usize, bufferLength: i32, writtenOut: usize): i32
314
+ @external("fastly_http_req", "uri_get") declare function fastly_http_req_uri_get(handle: i32, buffer: usize, bufferLength: i32, writtenOut: usize): i32
315
+ @external("fastly_http_req", "header_value_get") declare function fastly_http_req_header_value_get(handle: i32, name: usize, nameLength: i32, value: usize, valueLength: i32, writtenOut: usize): i32
316
+ @external("fastly_http_req", "new") declare function fastly_http_req_new(handleOut: usize): i32
317
+ @external("fastly_http_req", "method_set") declare function fastly_http_req_method_set(handle: i32, method: usize, methodLength: i32): i32
318
+ @external("fastly_http_req", "uri_set") declare function fastly_http_req_uri_set(handle: i32, uri: usize, uriLength: i32): i32
319
+ @external("fastly_http_req", "header_insert") declare function fastly_http_req_header_insert(handle: i32, name: usize, nameLength: i32, value: usize, valueLength: i32): i32
320
+ @external("fastly_http_req", "send_async") declare function fastly_http_req_send_async(handle: i32, body: i32, backend: usize, backendLength: i32, pendingOut: usize): i32
321
+ @external("fastly_http_req", "pending_req_wait") declare function fastly_http_req_pending_req_wait(handle: i32, responseOut: usize, bodyOut: usize): i32
322
+ @external("fastly_http_resp", "new") declare function fastly_http_resp_new(handleOut: usize): i32
323
+ @external("fastly_http_resp", "header_append") declare function fastly_http_resp_header_append(handle: i32, name: usize, nameLength: i32, value: usize, valueLength: i32): i32
324
+ @external("fastly_http_resp", "header_value_get") declare function fastly_http_resp_header_value_get(handle: i32, name: usize, nameLength: i32, value: usize, valueLength: i32, writtenOut: usize): i32
325
+ @external("fastly_http_resp", "status_get") declare function fastly_http_resp_status_get(handle: i32, statusOut: usize): i32
326
+ @external("fastly_http_resp", "status_set") declare function fastly_http_resp_status_set(handle: i32, status: i32): i32
327
+ @external("fastly_http_resp", "send_downstream") declare function fastly_http_resp_send_downstream(handle: i32, body: i32, streaming: i32): i32
328
+ @external("fastly_http_body", "new") declare function fastly_http_body_new(handleOut: usize): i32
329
+ @external("fastly_http_body", "read") declare function fastly_http_body_read(handle: i32, buffer: usize, bufferLength: i32, readOut: usize): i32
330
+ @external("fastly_http_body", "write") declare function fastly_http_body_write(handle: i32, buffer: usize, bufferLength: i32, end: i32, writtenOut: usize): i32
331
+
332
+ const PULSE_FASTLY_EFFECTS_ABI_VERSION: i64 = ${FASTLY_NATIVE_HTTP_EFFECTS_ABI_VERSION}
333
+ const PULSE_FASTLY_BUFFER_BYTES: i32 = ${FASTLY_NATIVE_HTTP_EFFECTS_BUFFER_BYTES}
334
+ const PULSE_FASTLY_EFFECT_COUNT: i32 = ${effectCount}
335
+ const FASTLY_STATUS_OK: i32 = 0
336
+ const FASTLY_STATUS_BUFLEN: i32 = 4
337
+ const FASTLY_STATUS_NONE: i32 = 10
338
+ const PULSE_VALUE_UNDEFINED: i32 = 0
339
+ const PULSE_VALUE_NULL: i32 = 1
340
+ const PULSE_VALUE_BOOLEAN: i32 = 2
341
+ const PULSE_VALUE_NUMBER: i32 = 3
342
+ const PULSE_VALUE_STRING: i32 = 4
343
+ const PULSE_VALUE_ARRAY: i32 = 5
344
+ const PULSE_VALUE_OBJECT: i32 = 6
345
+ const PULSE_VALUE_FETCH: i32 = 7
346
+ const PULSE_VALUE_RESPONSE: i32 = 8
347
+ const PULSE_ERROR_NONE: i32 = 0
348
+ const PULSE_ERROR_VALUE: i32 = 1001
349
+ const PULSE_ERROR_UNSUPPORTED: i32 = 1002
350
+ const PULSE_ERROR_HOSTCALL: i32 = 1003
351
+ const PULSE_ERROR_JSON: i32 = 1004
352
+ const PULSE_ERROR_SCHEMA: i32 = 1005
353
+ const PULSE_ERROR_TRANSPORT: i32 = 1006
354
+ const PULSE_ERROR_STATE: i32 = 1007
355
+
356
+ class __PulseFastlyValue {
357
+ kind: i32 = PULSE_VALUE_UNDEFINED
358
+ boolean: i32 = 0
359
+ number: f64 = 0.0
360
+ text: string = ""
361
+ keys: Array<string> = new Array<string>()
362
+ values: Array<i32> = new Array<i32>()
363
+ responseHandle: i32 = 0
364
+ bodyHandle: i32 = 0
365
+ bodyLoaded: i32 = 0
366
+ status: i32 = 200
367
+ headers: Array<__PulseFastlyHeader> = new Array<__PulseFastlyHeader>()
368
+ }
369
+ class __PulseFastlyHeader {
370
+ constructor(public name: string, public value: string) {}
371
+ }
372
+ class __PulseJsonParser {
373
+ source: string
374
+ index: i32 = 0
375
+ failed: bool = false
376
+ constructor(source: string) { this.source = source }
377
+ skip(): void { while (this.index < this.source.length) { const c = this.source.charCodeAt(this.index); if (c != 32 && c != 9 && c != 10 && c != 13) return; this.index += 1 } }
378
+ parse(): i32 { this.skip(); const value = this.value(0); this.skip(); if (this.index != this.source.length) this.failed = true; return this.failed ? 0 : value }
379
+ value(depth: i32): i32 {
380
+ this.skip(); if (this.index >= this.source.length || depth > 64) { this.failed = true; return 0 }
381
+ const c = this.source.charCodeAt(this.index)
382
+ if (c == 34) return __pulse_fastly_string_value(this.string())
383
+ if (c == 123) return this.object(depth + 1)
384
+ if (c == 91) return this.array(depth + 1)
385
+ if (this.source.substr(this.index, 4) == "true") { this.index += 4; return host_value_boolean(1) }
386
+ if (this.source.substr(this.index, 5) == "false") { this.index += 5; return host_value_boolean(0) }
387
+ if (this.source.substr(this.index, 4) == "null") { this.index += 4; return host_value_null() }
388
+ if (c == 45 || (c >= 48 && c <= 57)) return this.numberValue()
389
+ this.failed = true; return 0
390
+ }
391
+ string(): string {
392
+ let output = ""; this.index += 1
393
+ while (this.index < this.source.length) {
394
+ let c = this.source.charCodeAt(this.index); this.index += 1
395
+ if (c == 34) return output
396
+ if (c == 92) {
397
+ if (this.index >= this.source.length) { this.failed = true; return "" }
398
+ c = this.source.charCodeAt(this.index); this.index += 1
399
+ if (c == 34 || c == 92 || c == 47) output += String.fromCharCode(c)
400
+ else if (c == 98) output += String.fromCharCode(8)
401
+ else if (c == 102) output += String.fromCharCode(12)
402
+ else if (c == 110) output += "\n"
403
+ else if (c == 114) output += "\r"
404
+ else if (c == 116) output += "\t"
405
+ else if (c == 117) {
406
+ if (this.index + 4 > this.source.length) { this.failed = true; return "" }
407
+ let code = 0
408
+ for (let digitIndex = 0; digitIndex < 4; digitIndex += 1) {
409
+ const digitCode = this.source.charCodeAt(this.index + digitIndex)
410
+ let digit = -1
411
+ if (digitCode >= 48 && digitCode <= 57) digit = digitCode - 48
412
+ else if (digitCode >= 65 && digitCode <= 70) digit = digitCode - 55
413
+ else if (digitCode >= 97 && digitCode <= 102) digit = digitCode - 87
414
+ if (digit < 0) { this.failed = true; return "" }
415
+ code = (code << 4) | digit
416
+ }
417
+ this.index += 4; output += String.fromCharCode(code)
418
+ } else { this.failed = true; return "" }
419
+ } else if (c < 32) { this.failed = true; return "" }
420
+ else output += String.fromCharCode(c)
421
+ }
422
+ this.failed = true; return ""
423
+ }
424
+ numberValue(): i32 {
425
+ const start = this.index
426
+ if (this.source.charCodeAt(this.index) == 45) { this.index += 1; if (this.index >= this.source.length) { this.failed = true; return 0 } }
427
+ let c = this.source.charCodeAt(this.index)
428
+ if (c == 48) {
429
+ this.index += 1
430
+ if (this.index < this.source.length) { c = this.source.charCodeAt(this.index); if (c >= 48 && c <= 57) { this.failed = true; return 0 } }
431
+ } else if (c >= 49 && c <= 57) {
432
+ this.index += 1
433
+ while (this.index < this.source.length) { c = this.source.charCodeAt(this.index); if (c < 48 || c > 57) break; this.index += 1 }
434
+ } else { this.failed = true; return 0 }
435
+ if (this.index < this.source.length && this.source.charCodeAt(this.index) == 46) {
436
+ this.index += 1
437
+ if (this.index >= this.source.length) { this.failed = true; return 0 }
438
+ c = this.source.charCodeAt(this.index); if (c < 48 || c > 57) { this.failed = true; return 0 }
439
+ while (this.index < this.source.length) { c = this.source.charCodeAt(this.index); if (c < 48 || c > 57) break; this.index += 1 }
440
+ }
441
+ if (this.index < this.source.length) {
442
+ c = this.source.charCodeAt(this.index)
443
+ if (c == 69 || c == 101) {
444
+ this.index += 1
445
+ if (this.index < this.source.length) { c = this.source.charCodeAt(this.index); if (c == 43 || c == 45) this.index += 1 }
446
+ if (this.index >= this.source.length) { this.failed = true; return 0 }
447
+ c = this.source.charCodeAt(this.index); if (c < 48 || c > 57) { this.failed = true; return 0 }
448
+ while (this.index < this.source.length) { c = this.source.charCodeAt(this.index); if (c < 48 || c > 57) break; this.index += 1 }
449
+ }
450
+ }
451
+ return host_value_number(F64.parseFloat(this.source.substring(start, this.index)))
452
+ }
453
+ array(depth: i32): i32 {
454
+ const output = host_value_array(); this.index += 1; this.skip()
455
+ if (this.index < this.source.length && this.source.charCodeAt(this.index) == 93) { this.index += 1; return output }
456
+ while (!this.failed) {
457
+ host_value_array_push(output, this.value(depth)); this.skip()
458
+ if (this.index >= this.source.length) { this.failed = true; break }
459
+ const c = this.source.charCodeAt(this.index); this.index += 1
460
+ if (c == 93) break
461
+ if (c != 44) { this.failed = true; break }
462
+ }
463
+ return output
464
+ }
465
+ object(depth: i32): i32 {
466
+ const output = host_value_object(); this.index += 1; this.skip()
467
+ if (this.index < this.source.length && this.source.charCodeAt(this.index) == 125) { this.index += 1; return output }
468
+ while (!this.failed) {
469
+ this.skip(); if (this.index >= this.source.length || this.source.charCodeAt(this.index) != 34) { this.failed = true; break }
470
+ const key = this.string(); this.skip()
471
+ if (this.index >= this.source.length || this.source.charCodeAt(this.index) != 58) { this.failed = true; break }
472
+ this.index += 1; host_value_object_set(output, __pulse_fastly_string_value(key), this.value(depth)); this.skip()
473
+ if (this.index >= this.source.length) { this.failed = true; break }
474
+ const c = this.source.charCodeAt(this.index); this.index += 1
475
+ if (c == 125) break
476
+ if (c != 44) { this.failed = true; break }
477
+ }
478
+ return output
479
+ }
480
+ }
481
+
482
+ const __pulse_fastly_values = new Array<__PulseFastlyValue>()
483
+ const __pulse_fastly_pending = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
484
+ const __pulse_fastly_pending_active = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
485
+ const __pulse_fastly_payloads = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
486
+ let __pulse_fastly_request_handle: i32 = 0
487
+ let __pulse_fastly_request_body_handle: i32 = 0
488
+ let __pulse_fastly_request_method: string = ""
489
+ let __pulse_fastly_request_url: string = ""
490
+ let __pulse_fastly_request_path: string = ""
491
+ let __pulse_fastly_request_body: string = ""
492
+ let __pulse_fastly_request_body_loaded: i32 = 0
493
+ let __pulse_fastly_last_error: i32 = 0
494
+ let __pulse_fastly_error_stage: i32 = 0
495
+ let __pulse_fastly_error_effect: i32 = -1
496
+
497
+ function __pulse_fastly_fail(code: i32, stage: i32, effectIndex: i32): void { if (__pulse_fastly_last_error == 0) { __pulse_fastly_last_error = code; __pulse_fastly_error_stage = stage; __pulse_fastly_error_effect = effectIndex } }
498
+ function __pulse_fastly_out_i32(): StaticArray<i32> { return new StaticArray<i32>(1) }
499
+ function __pulse_fastly_out_value(out: StaticArray<i32>): i32 { return load<i32>(changetype<usize>(out)) }
500
+ function __pulse_fastly_utf8(value: string): ArrayBuffer { return String.UTF8.encode(value, false) }
501
+ function __pulse_fastly_decode(buffer: Uint8Array, length: i32): string { return String.UTF8.decodeUnsafe(buffer.dataStart, length, false) }
502
+ function __pulse_fastly_put(value: __PulseFastlyValue): i32 { __pulse_fastly_values.push(value); return __pulse_fastly_values.length }
503
+ 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]) }
504
+ function __pulse_fastly_string_value(value: string): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_STRING; item.text = value; return __pulse_fastly_put(item) }
505
+ 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 }
506
+ 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() }
507
+ 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) }
508
+ function __pulse_fastly_number(handle: i32): f64 { const value = __pulse_fastly_value(handle); if (value.kind == PULSE_VALUE_NUMBER) return value.number; if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean != 0 ? 1.0 : 0.0; if (value.kind == PULSE_VALUE_STRING) return F64.parseFloat(value.text); return 0.0 }
509
+ function __pulse_fastly_hex(value: i32): string { return String.fromCharCode(value < 10 ? 48 + value : 87 + value) }
510
+ function __pulse_fastly_quote(value: string): string { let out = "\""; for (let i = 0; i < value.length; i += 1) { const c = value.charCodeAt(i); if (c == 34) out += "\\\""; else if (c == 92) out += "\\\\"; else if (c == 8) out += "\\b"; else if (c == 9) out += "\\t"; else if (c == 10) out += "\\n"; else if (c == 12) out += "\\f"; else if (c == 13) out += "\\r"; else if (c < 32) out += "\\u00" + __pulse_fastly_hex((c >> 4) & 15) + __pulse_fastly_hex(c & 15); else out += String.fromCharCode(c) } return out + "\"" }
511
+ function __pulse_fastly_json(handle: i32, depth: i32): string {
512
+ if (depth > 64) { __pulse_fastly_fail(PULSE_ERROR_JSON, 2, -1); return "null" }
513
+ const value = __pulse_fastly_value(handle)
514
+ if (value.kind == PULSE_VALUE_UNDEFINED || value.kind == PULSE_VALUE_NULL) return "null"
515
+ if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean != 0 ? "true" : "false"
516
+ if (value.kind == PULSE_VALUE_NUMBER) return __pulse_fastly_number_string(value.number)
517
+ if (value.kind == PULSE_VALUE_STRING) return __pulse_fastly_quote(value.text)
518
+ if (value.kind == PULSE_VALUE_ARRAY) { let out = "["; for (let i = 0; i < value.values.length; i += 1) { if (i > 0) out += ","; out += __pulse_fastly_json(unchecked(value.values[i]), depth + 1) } return out + "]" }
519
+ if (value.kind == PULSE_VALUE_OBJECT) { let out = "{"; for (let i = 0; i < value.keys.length; i += 1) { if (i > 0) out += ","; out += __pulse_fastly_quote(unchecked(value.keys[i])) + ":" + __pulse_fastly_json(unchecked(value.values[i]), depth + 1) } return out + "}" }
520
+ return "null"
521
+ }
522
+ 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 }
523
+ 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) }
524
+ 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)) }
525
+ function __pulse_fastly_read_body(handle: i32, effectIndex: i32): string { let out = ""; let total = 0; while (true) { const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES); const read = __pulse_fastly_out_i32(); const status = fastly_http_body_read(handle, buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(read)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 20, effectIndex); return "" } const count = __pulse_fastly_out_value(read); if (count <= 0) return out; total += count; if (total > __PULSE_SCHEMA_MAX_BYTES && __PULSE_SCHEMA_MAX_BYTES > 0) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 21, effectIndex); return "" } out += __pulse_fastly_decode(buffer, count) } }
526
+ 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)) }
527
+ 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)) }
528
+ 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 }
529
+
530
+ function host_value_undefined(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_UNDEFINED; return __pulse_fastly_put(item) }
531
+ function host_value_null(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_NULL; return __pulse_fastly_put(item) }
532
+ function host_value_boolean(value: i32): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_BOOLEAN; item.boolean = value != 0 ? 1 : 0; return __pulse_fastly_put(item) }
533
+ function host_value_number(value: f64): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_NUMBER; item.number = value; return __pulse_fastly_put(item) }
534
+ function host_value_string(pointer: i32, length: i32): i32 { return __pulse_fastly_string_value(changetype<string>(pointer)) }
535
+ function host_value_array(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_ARRAY; return __pulse_fastly_put(item) }
536
+ function host_value_array_push(target: i32, value: i32): void { const item = __pulse_fastly_value(target); if (item.kind != PULSE_VALUE_ARRAY) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 30, -1); return } item.values.push(value) }
537
+ 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])) }
538
+ function host_value_object(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_OBJECT; return __pulse_fastly_put(item) }
539
+ function host_value_object_set(target: i32, keyHandle: i32, value: i32): void { const item = __pulse_fastly_value(target); if (item.kind != PULSE_VALUE_OBJECT) { __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) } }
540
+ 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])) }
541
+ 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.text.length : item.values.length); return host_value_undefined() }
542
+ function host_value_property_set(target: i32, key: i32, value: i32): i32 { host_value_object_set(target, key, value); return value }
543
+ 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) }
544
+ function host_value_element_set(target: i32, keyHandle: i32, value: i32): i32 { const item = __pulse_fastly_value(target); 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) }
545
+ 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.text.length > 0 ? 1 : 0; return 1 }
546
+ 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 }
547
+ 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_string_value(__pulse_fastly_string(leftHandle) + __pulse_fastly_string(rightHandle)); return host_value_number(__pulse_fastly_number(leftHandle) + __pulse_fastly_number(rightHandle)) } 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 == 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 }
548
+ 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 }
549
+
550
+ function host_request_method(): i32 { return __pulse_fastly_string_value(__pulse_fastly_request_method) }
551
+ function host_request_url(): i32 { return __pulse_fastly_string_value(__pulse_fastly_request_url) }
552
+ function __pulse_router_segments(value: string): Array<string> { let start = 0; let end = value.length; while (start < end && value.charCodeAt(start) == 47) start += 1; while (end > start && value.charCodeAt(end - 1) == 47) end -= 1; if (start >= end) return new Array<string>(); return value.substring(start, end).split("/") }
553
+ function __pulse_router_match_text(path: string, pattern: string): bool { const actual = __pulse_router_segments(path); const expected = __pulse_router_segments(pattern); const wildcard = expected.length > 0 && unchecked(expected[expected.length - 1]) == "*"; if ((!wildcard && actual.length != expected.length) || (wildcard && actual.length < expected.length - 1)) return false; const limit = wildcard ? expected.length - 1 : expected.length; for (let i = 0; i < limit; i += 1) { const part = unchecked(expected[i]); if (part.length > 0 && part.charCodeAt(0) == 58) { if (unchecked(actual[i]).length == 0) return false } else if (unchecked(actual[i]) != part) return false } return true }
554
+ function __pulse_router_param_text(path: string, pattern: string, name: string): string | null { const actual = __pulse_router_segments(path); const expected = __pulse_router_segments(pattern); const target = ":" + name; for (let i = 0; i < expected.length; i += 1) if (unchecked(expected[i]) == target) return unchecked(actual[i]); return null }
555
+ 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) }
556
+ 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) }
557
+ function host_request_path(): i32 { return __pulse_fastly_string_value(__pulse_fastly_request_path) }
558
+ function host_request_headers(): i32 { return host_value_object() }
559
+ 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) }
560
+ 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) }
561
+ 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 }
562
+ 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])))) } } }
563
+ 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) }
564
+ function host_response_json(value: i32, options: i32): i32 { return __pulse_fastly_response(value, options, true) }
565
+ function host_response_text(value: i32, options: i32): i32 { return __pulse_fastly_response(value, options, false) }
566
+ 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) }
567
+ 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 }
568
+ function __pulse_fastly_grip_frame(options: __PulseFastlyValue, output: __PulseFastlyValue): bool { for (let i = output.headers.length - 1; i >= 0; i -= 1) { const name = unchecked(output.headers[i]).name.toLowerCase(); if (name == "grip-hold" || name == "grip-channel" || name == "grip-timeout") output.headers.splice(i, 1) } const modeIndex = __pulse_fastly_find(options, "mode"); const mode = modeIndex < 0 ? "stream" : __pulse_fastly_string(unchecked(options.values[modeIndex])); if (mode != "stream" && mode != "response") { __pulse_fastly_fail(PULSE_ERROR_VALUE, 136, -1); return false } output.headers.push(new __PulseFastlyHeader("Grip-Hold", mode)); if (!__pulse_fastly_grip_frame_channels(options, output)) return false; const timeoutIndex = __pulse_fastly_find(options, "timeoutMs"); if (timeoutIndex >= 0) { const timeout = __pulse_fastly_number(unchecked(options.values[timeoutIndex])); if (timeout < 0.0 || Math.floor(timeout) != timeout) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 137, -1); return false } output.headers.push(new __PulseFastlyHeader("Grip-Timeout", i64(timeout).toString())) } return true }
569
+ function host_grip_is_websocket(): i32 { const contentType = __pulse_fastly_request_header_text("content-type").toLowerCase(); const accept = __pulse_fastly_request_header_text("accept").toLowerCase(); const upgrade = __pulse_fastly_request_header_text("upgrade").toLowerCase(); const connection = __pulse_fastly_request_header_text("connection").toLowerCase(); let connectionUpgrade = false; const tokens = connection.split(","); for (let i = 0; i < tokens.length; i += 1) if (unchecked(tokens[i]).trim() == "upgrade") connectionUpgrade = true; return host_value_boolean(contentType.indexOf("application/websocket-events") >= 0 || accept.indexOf("application/websocket-events") >= 0 || (upgrade == "websocket" && connectionUpgrade) ? 1 : 0) }
570
+ function host_grip_subscribe(responseHandle: i32, optionsHandle: i32): i32 { const output = __pulse_fastly_value(responseHandle); const options = __pulse_fastly_value(optionsHandle); if (output.kind != PULSE_VALUE_RESPONSE || options.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 138, -1); return 0 } return __pulse_fastly_grip_frame(options, output) ? responseHandle : 0 }
571
+ function host_grip_handoff(optionsHandle: i32): i32 { const options = __pulse_fastly_value(optionsHandle); if (options.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 139, -1); return 0 } const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE; output.status = 200; const statusIndex = __pulse_fastly_find(options, "status"); if (statusIndex >= 0) output.status = i32(__pulse_fastly_number(unchecked(options.values[statusIndex]))); const bodyIndex = __pulse_fastly_find(options, "body"); if (bodyIndex >= 0) output.text = __pulse_fastly_string(unchecked(options.values[bodyIndex])); __pulse_fastly_headers_from_options(options, output); 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", "application/websocket-events")); return __pulse_fastly_grip_frame(options, output) ? __pulse_fastly_put(output) : 0 }
572
+ function host_kv_namespace(name: i32): i32 { __pulse_fastly_fail(PULSE_ERROR_UNSUPPORTED, 41, -1); return 0 }
573
+ function host_fetch_text(responseHandle: i32): i32 { const response = __pulse_fastly_value(responseHandle); if (response.kind != PULSE_VALUE_FETCH) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 42, -1); return 0 } return __pulse_fastly_string_value(__pulse_fastly_fetch_body(response)) }
574
+ function host_fetch_json(responseHandle: i32, schemaHandle: i32): i32 { const response = __pulse_fastly_value(responseHandle); if (response.kind != PULSE_VALUE_FETCH) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 43, -1); return 0 } if (__PULSE_SCHEMA_REQUIRE_JSON) { const contentType = __pulse_fastly_fetch_header_text(response.responseHandle, "content-type"); if (contentType.length == 0 || contentType.toLowerCase().indexOf("json") < 0) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 44, -1); return 0 } } const parsed = __pulse_fastly_parse_json(__pulse_fastly_fetch_body(response)); if (parsed <= 0) return 0; const schema = __pulse_fastly_value(schemaHandle); return schema.kind == PULSE_VALUE_STRING ? __pulse_fastly_schema_apply(schema.text, parsed, false) : parsed }
575
+ function host_fetch_header(responseHandle: i32, nameHandle: i32): i32 { const response = __pulse_fastly_value(responseHandle); if (response.kind != PULSE_VALUE_FETCH) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 45, -1); return 0 } const value = __pulse_fastly_fetch_header_text(response.responseHandle, __pulse_fastly_string(nameHandle)); return value.length == 0 ? host_value_undefined() : __pulse_fastly_string_value(value) }
576
+ function host_effect_begin(effectIndex: i32, payload: i32): void { if (effectIndex < 0 || effectIndex >= PULSE_FASTLY_EFFECT_COUNT || unchecked(__pulse_fastly_pending_active[effectIndex]) != 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 46, effectIndex); return } const payloadValue = __pulse_fastly_value(payload); if (payloadValue.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 47, effectIndex); return } const urlIndex = __pulse_fastly_find(payloadValue, "url"); if (urlIndex < 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 48, effectIndex); return } const url = __pulse_fastly_string(unchecked(payloadValue.values[urlIndex])); const initIndex = __pulse_fastly_find(payloadValue, "init"); const init = initIndex >= 0 ? __pulse_fastly_value(unchecked(payloadValue.values[initIndex])) : new __PulseFastlyValue(); let method = "GET"; let body = ""; let headers = new __PulseFastlyValue(); headers.kind = PULSE_VALUE_OBJECT; if (init.kind == PULSE_VALUE_OBJECT) { const methodIndex = __pulse_fastly_find(init, "method"); if (methodIndex >= 0) method = __pulse_fastly_string(unchecked(init.values[methodIndex])).toUpperCase(); const headersIndex = __pulse_fastly_find(init, "headers"); if (headersIndex >= 0) headers = __pulse_fastly_value(unchecked(init.values[headersIndex])); const bodyIndex = __pulse_fastly_find(init, "body"); if (bodyIndex >= 0) { const bodyValue = unchecked(init.values[bodyIndex]); const bodyObject = __pulse_fastly_value(bodyValue); body = bodyObject.kind == PULSE_VALUE_STRING ? bodyObject.text : __pulse_fastly_json(bodyValue, 0) } }
577
+ const requestOut = __pulse_fastly_out_i32(); let status = fastly_http_req_new(changetype<usize>(requestOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 70, effectIndex); return } const requestHandle = __pulse_fastly_out_value(requestOut)
578
+ const bodyOut = __pulse_fastly_out_i32(); status = fastly_http_body_new(changetype<usize>(bodyOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 71, effectIndex); return } const bodyHandle = __pulse_fastly_out_value(bodyOut)
579
+ const methodBytes = __pulse_fastly_utf8(method); status = fastly_http_req_method_set(requestHandle, changetype<usize>(methodBytes), methodBytes.byteLength); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 72, effectIndex); return }
580
+ const urlBytes = __pulse_fastly_utf8(url); status = fastly_http_req_uri_set(requestHandle, changetype<usize>(urlBytes), urlBytes.byteLength); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 73, effectIndex); return }
581
+ if (headers.kind == PULSE_VALUE_OBJECT) { for (let i = 0; i < headers.keys.length; i += 1) { const nameBytes = __pulse_fastly_utf8(unchecked(headers.keys[i])); const valueBytes = __pulse_fastly_utf8(__pulse_fastly_string(unchecked(headers.values[i]))); status = fastly_http_req_header_insert(requestHandle, changetype<usize>(nameBytes), nameBytes.byteLength, changetype<usize>(valueBytes), valueBytes.byteLength); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 74, effectIndex); return } } }
582
+ if (body.length > 0) { status = __pulse_fastly_write_body(bodyHandle, body); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 75, effectIndex); return } }
583
+ const backend = __pulse_fastly_backend(effectIndex); if (backend.length == 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 76, effectIndex); return } const backendBytes = __pulse_fastly_utf8(backend); const pendingOut = __pulse_fastly_out_i32(); status = fastly_http_req_send_async(requestHandle, bodyHandle, changetype<usize>(backendBytes), backendBytes.byteLength, changetype<usize>(pendingOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_TRANSPORT, 77, effectIndex); return } unchecked(__pulse_fastly_pending[effectIndex] = __pulse_fastly_out_value(pendingOut)); unchecked(__pulse_fastly_pending_active[effectIndex] = 1); unchecked(__pulse_fastly_payloads[effectIndex] = payload)
584
+ }
585
+ function __pulse_fastly_wait_fetch(effectIndex: i32): i32 { if (unchecked(__pulse_fastly_pending_active[effectIndex]) == 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 80, effectIndex); return 0 } const pending = unchecked(__pulse_fastly_pending[effectIndex]); const responseOut = __pulse_fastly_out_i32(); const bodyOut = __pulse_fastly_out_i32(); const status = fastly_http_req_pending_req_wait(pending, changetype<usize>(responseOut), changetype<usize>(bodyOut)); unchecked(__pulse_fastly_pending_active[effectIndex] = 0); unchecked(__pulse_fastly_pending[effectIndex] = 0); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_TRANSPORT, 81, effectIndex); return 0 } const value = new __PulseFastlyValue(); value.kind = PULSE_VALUE_FETCH; value.responseHandle = __pulse_fastly_out_value(responseOut); value.bodyHandle = __pulse_fastly_out_value(bodyOut); return __pulse_fastly_put(value) }
586
+ function __pulse_fastly_write_body(bodyHandle: i32, value: string): i32 { const bytes = __pulse_fastly_utf8(value); let offset = 0; while (offset < bytes.byteLength) { const written = __pulse_fastly_out_i32(); const status = fastly_http_body_write(bodyHandle, changetype<usize>(bytes) + offset, bytes.byteLength - offset, 0, changetype<usize>(written)); if (status != FASTLY_STATUS_OK) return status; const count = __pulse_fastly_out_value(written); if (count <= 0) return 1; offset += count } return FASTLY_STATUS_OK }
587
+ function __pulse_fastly_send_result(handle: i32): i32 { const value = __pulse_fastly_value(handle); if (value.kind == PULSE_VALUE_FETCH) return fastly_http_resp_send_downstream(value.responseHandle, value.bodyHandle, 0); if (value.kind != PULSE_VALUE_RESPONSE) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 90, -1); return PULSE_ERROR_VALUE } const responseOut = __pulse_fastly_out_i32(); let status = fastly_http_resp_new(changetype<usize>(responseOut)); if (status != FASTLY_STATUS_OK) return status; const responseHandle = __pulse_fastly_out_value(responseOut); const bodyOut = __pulse_fastly_out_i32(); status = fastly_http_body_new(changetype<usize>(bodyOut)); if (status != FASTLY_STATUS_OK) return status; const bodyHandle = __pulse_fastly_out_value(bodyOut); status = fastly_http_resp_status_set(responseHandle, value.status); if (status != FASTLY_STATUS_OK) return status; for (let i = 0; i < value.headers.length; i += 1) { const header = unchecked(value.headers[i]); const nameBytes = __pulse_fastly_utf8(header.name); const valueBytes = __pulse_fastly_utf8(header.value); status = fastly_http_resp_header_append(responseHandle, changetype<usize>(nameBytes), nameBytes.byteLength, changetype<usize>(valueBytes), valueBytes.byteLength); if (status != FASTLY_STATUS_OK) return status } status = __pulse_fastly_write_body(bodyHandle, value.text); if (status != FASTLY_STATUS_OK) return status; return fastly_http_resp_send_downstream(responseHandle, bodyHandle, 0) }
588
+
589
+ ${generateSchemaRuntime(plan)}
590
+ ${effectResultSource(plan, bindings)}
591
+ `;
592
+ }
593
+
594
+ function driverSource(plan) {
595
+ return String.raw`
596
+ export function pulse_fastly_last_error(): i32 { return __pulse_fastly_last_error }
597
+ export function pulse_fastly_error_stage(): i32 { return __pulse_fastly_error_stage }
598
+ export function pulse_fastly_error_effect(): i32 { return __pulse_fastly_error_effect }
599
+ export function _start(): void {
600
+ __pulse_fastly_last_error = fastly_abi_init(PULSE_FASTLY_EFFECTS_ABI_VERSION)
601
+ if (__pulse_fastly_last_error != FASTLY_STATUS_OK) return
602
+ const handles = new StaticArray<i32>(2)
603
+ const downstreamStatus = fastly_http_req_body_downstream_get(changetype<usize>(handles), changetype<usize>(handles) + 4)
604
+ if (downstreamStatus != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 100, -1); return }
605
+ __pulse_fastly_request_handle = load<i32>(changetype<usize>(handles))
606
+ __pulse_fastly_request_body_handle = load<i32>(changetype<usize>(handles) + 4)
607
+ __pulse_fastly_request_method = __pulse_fastly_read_req_string(0)
608
+ if (__pulse_fastly_last_error != 0) return
609
+ __pulse_fastly_request_url = __pulse_fastly_read_req_string(1)
610
+ if (__pulse_fastly_last_error != 0) return
611
+ __pulse_fastly_request_path = __pulse_fastly_path(__pulse_fastly_request_url)
612
+ let runStatus = pulse_start()
613
+ while (runStatus == 1 && __pulse_fastly_last_error == 0) {
614
+ for (let effectIndex = 0; effectIndex < PULSE_FASTLY_EFFECT_COUNT; effectIndex += 1) {
615
+ if (unchecked(__pulse_fastly_pending_active[effectIndex]) == 0) continue
616
+ const result = __pulse_fastly_resolve_effect(effectIndex)
617
+ if (result <= 0 || __pulse_fastly_last_error != 0) return
618
+ if (pulse_set_effect_result(effectIndex, result) != 1) { __pulse_fastly_fail(PULSE_ERROR_STATE, 101, effectIndex); return }
619
+ }
620
+ runStatus = pulse_resume()
621
+ }
622
+ if (runStatus != 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 102, -1); return }
623
+ const result = pulse_result_handle()
624
+ if (result <= 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 103, -1); return }
625
+ const sendStatus = __pulse_fastly_send_result(result)
626
+ if (sendStatus != FASTLY_STATUS_OK) __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 104, -1)
627
+ }
628
+ `;
629
+ }
630
+
631
+ function generateFastlyNativeHttpEffectsAssemblyScript(plan, options = {}) {
632
+ validatePlanBoundary(plan);
633
+ const bindings = resolveBackendBindings(plan, options);
634
+ const portable = generateCanonicalNativeAssemblyScript(plan, options);
635
+ const portableSource = stripPulseHostImports(portable.source);
636
+ const source = [
637
+ '/* Generated by Pulse Pass97 Fastly native HTTP effects compiler. */',
638
+ 'export function __pulse_fastly_abort(message: string | null, fileName: string | null, line: u32, column: u32): void { unreachable() }',
639
+ '',
640
+ fastlyRuntimeSource(plan, bindings),
641
+ portableSource,
642
+ driverSource(plan),
643
+ ''
644
+ ].join('\n');
645
+ const manifest = Object.freeze({
646
+ version: FASTLY_NATIVE_HTTP_EFFECTS_VERSION,
647
+ generatorVersion: FASTLY_NATIVE_HTTP_EFFECTS_GENERATOR_VERSION,
648
+ abiVersion: FASTLY_NATIVE_HTTP_EFFECTS_ABI_VERSION,
649
+ planVersion: plan.version,
650
+ planHash: plan.planHash,
651
+ sourceHash: sha256(source),
652
+ portableGeneratorVersion: portable.version,
653
+ portableSourceHash: portable.sourceHash,
654
+ schemaCodecs: portable.manifest.schemaCodecs,
655
+ effectCount: (plan.effects || []).length,
656
+ continuationCount: (plan.continuations || []).length,
657
+ groupedContinuationCount: (plan.continuations || []).filter((entry) => (entry.effectIds || []).length > 1).length,
658
+ backends: bindings,
659
+ allowedImports: FASTLY_NATIVE_HTTP_EFFECTS_IMPORTS,
660
+ requiredExports: Object.freeze([
661
+ '_start',
662
+ 'pulse_fastly_last_error',
663
+ 'pulse_fastly_error_stage',
664
+ 'pulse_fastly_error_effect',
665
+ 'pulse_plan_hash_ptr',
666
+ 'pulse_plan_hash_length'
667
+ ]),
668
+ policy: Object.freeze({
669
+ nativeFastly: true,
670
+ provider: 'fastly',
671
+ providerNeutralInput: true,
672
+ javascriptRuntime: false,
673
+ jsComputeRuntime: false,
674
+ wasi: false,
675
+ effects: 'fetch-only',
676
+ continuations: true,
677
+ groupedEffects: 'all send_async calls begin before pending_req_wait',
678
+ schemas: 'fetch JSON decode and structured response encode',
679
+ opaqueResponse: 'origin response/body handles pass through without guest body materialization',
680
+ transportErrors: 'nonzero Fastly pending_req_wait status fails execution; HTTP status remains response data',
681
+ platformCapabilities: false
682
+ })
683
+ });
684
+ return Object.freeze({
685
+ version: FASTLY_NATIVE_HTTP_EFFECTS_GENERATOR_VERSION,
686
+ source,
687
+ sourceHash: manifest.sourceHash,
688
+ manifest,
689
+ bindings,
690
+ portable
691
+ });
692
+ }
693
+
694
+ function inspectFastlyNativeHttpEffectsWasm(input) {
695
+ const bytes = Buffer.isBuffer(input) ? input : fs.readFileSync(path.resolve(input));
696
+ if (!WebAssembly.validate(bytes)) fail('Generated Fastly native HTTP effects module is not valid WebAssembly.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_WASM_INVALID');
697
+ const module = new WebAssembly.Module(bytes);
698
+ const imports = WebAssembly.Module.imports(module).map((entry) => Object.freeze({ module: entry.module, name: entry.name, kind: entry.kind }));
699
+ const exports = WebAssembly.Module.exports(module).map((entry) => Object.freeze({ name: entry.name, kind: entry.kind }));
700
+ const unexpected = imports.filter((entry) => !FASTLY_NATIVE_HTTP_EFFECTS_ALLOWED_IMPORTS.has(`${entry.module}:${entry.name}`));
701
+ if (unexpected.length > 0) fail('Generated Fastly native HTTP effects module imports functions outside the Pass97 ABI.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_IMPORT_UNSUPPORTED', { unexpected, imports });
702
+ const forbidden = imports.filter((entry) => /pulse_host|wasi|js[_-]?compute/i.test(`${entry.module}:${entry.name}`));
703
+ if (forbidden.length > 0) fail('Generated Fastly native HTTP effects module imports a forbidden runtime.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_RUNTIME_FORBIDDEN', { forbidden });
704
+ const imported = new Set(imports.map((entry) => `${entry.module}:${entry.name}`));
705
+ const missingImports = FASTLY_NATIVE_HTTP_EFFECTS_REQUIRED_IMPORTS.map(([moduleName, name]) => `${moduleName}:${name}`).filter((key) => !imported.has(key));
706
+ if (missingImports.length > 0) fail('Generated Fastly native HTTP effects module is missing required host imports.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_IMPORT_MISSING', { missingImports, imports });
707
+ const exportNames = new Set(exports.map((entry) => entry.name));
708
+ const requiredExports = ['_start', 'memory', 'pulse_fastly_last_error', 'pulse_fastly_error_stage', 'pulse_fastly_error_effect', 'pulse_start', 'pulse_resume', 'pulse_set_effect_result', 'pulse_result_handle'];
709
+ const missingExports = requiredExports.filter((name) => !exportNames.has(name));
710
+ if (missingExports.length > 0) fail('Generated Fastly native HTTP effects module is missing required exports.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_EXPORT_MISSING', { missingExports, exports });
711
+ if (bytes.length > FASTLY_NATIVE_HTTP_EFFECTS_MAX_WASM_BYTES) fail('Generated Fastly native HTTP effects module exceeds the Pass97 size ceiling.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_WASM_TOO_LARGE', { bytes: bytes.length, maxBytes: FASTLY_NATIVE_HTTP_EFFECTS_MAX_WASM_BYTES });
712
+ return Object.freeze({
713
+ valid: true,
714
+ bytes: bytes.length,
715
+ sha256: sha256(bytes),
716
+ magic: bytes.subarray(0, 8).toString('hex'),
717
+ imports: Object.freeze(imports),
718
+ exports: Object.freeze(exports),
719
+ importModules: Object.freeze([...new Set(imports.map((entry) => entry.module))].sort())
720
+ });
721
+ }
722
+
723
+ function compileFastlyNativeHttpEffectsPlan(plan, options = {}) {
724
+ const generated = generateFastlyNativeHttpEffectsAssemblyScript(plan, options);
725
+ const cwd = path.resolve(options.cwd || process.cwd());
726
+ const compilerFallback = path.resolve(__dirname, '..', '..', '..', '..', 'wasm', 'packages', 'compiler');
727
+ const asc = resolveAsc(cwd) || resolveAsc(compilerFallback);
728
+ if (!asc) fail('AssemblyScript compiler dependency was not found for Fastly native HTTP effects realization.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_ASC_MISSING', { cwd, compilerFallback });
729
+ const schemaCodecsActive = generated.manifest.schemaCodecs && generated.manifest.schemaCodecs.active === true;
730
+ let jsonAs;
731
+ if (schemaCodecsActive) {
732
+ let transform;
733
+ try {
734
+ transform = require.resolve('json-as', { paths: [compilerFallback, cwd] });
735
+ } catch (error) {
736
+ fail(
737
+ 'The lockfile-pinned json-as transform was not found for Fastly Native HTTP effects schema codec compilation.',
738
+ 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_JSON_AS_MISSING',
739
+ { cwd, package: 'json-as', version: '1.5.0', cause: error && error.message }
740
+ );
741
+ }
742
+ const packageRoot = path.resolve(transform, '..', '..', '..');
743
+ const dependencyRoot = path.dirname(packageRoot);
744
+ const packageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
745
+ if (packageJson.version !== '1.5.0') {
746
+ fail(
747
+ 'Fastly Native HTTP effects schema codec compilation requires json-as 1.5.0 exactly.',
748
+ 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_JSON_AS_VERSION_INVALID',
749
+ { expected: '1.5.0', actual: packageJson.version, packageRoot }
750
+ );
751
+ }
752
+ jsonAs = Object.freeze({ transform, dependencyRoot, version: packageJson.version });
753
+ }
754
+ const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pulse-fastly-native-effects-'));
755
+ const requestedOutDir = options.outDir ? path.resolve(options.outDir) : undefined;
756
+ const outputDir = requestedOutDir || stagingDir;
757
+ fs.mkdirSync(outputDir, { recursive: true });
758
+ const sourceFile = path.join(stagingDir, 'fastly-native-http-effects.as.ts');
759
+ const wasmFile = path.join(outputDir, options.wasmFile || 'fastly-native-http-effects.wasm');
760
+ const watFile = path.join(outputDir, options.watFile || 'fastly-native-http-effects.wat');
761
+ try {
762
+ fs.writeFileSync(sourceFile, generated.source, 'utf8');
763
+ const args = [
764
+ asc.script,
765
+ path.basename(sourceFile),
766
+ '--outFile', wasmFile,
767
+ '--textFile', watFile,
768
+ '--runtime', schemaCodecsActive ? 'incremental' : 'stub',
769
+ '--noAssert',
770
+ '--optimize',
771
+ '--use', 'abort=fastly-native-http-effects.as/__pulse_fastly_abort'
772
+ ];
773
+ if (schemaCodecsActive) {
774
+ args.push(
775
+ '--exportRuntime',
776
+ '--transform', jsonAs.transform,
777
+ '--path', path.join(compilerFallback, 'node_modules'),
778
+ '--path', jsonAs.dependencyRoot
779
+ );
780
+ }
781
+ const startedAt = Date.now();
782
+ const result = spawnSync(asc.executable, args, {
783
+ cwd: stagingDir,
784
+ encoding: 'utf8',
785
+ maxBuffer: 64 * 1024 * 1024,
786
+ timeout: Number(options.timeoutMs || 180000),
787
+ env: schemaCodecsActive
788
+ ? { ...process.env, JSON_STRICT: 'true', JSON_USE_FAST_PATH: '0' }
789
+ : process.env
790
+ });
791
+ const durationMs = Date.now() - startedAt;
792
+ if (result.error || result.status !== 0 || !fs.existsSync(wasmFile)) {
793
+ fail('AssemblyScript failed to compile the Fastly native HTTP effects module.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECTS_ASC_FAILED', {
794
+ status: result.status,
795
+ signal: result.signal,
796
+ error: result.error && result.error.message,
797
+ stdout: String(result.stdout || '').slice(-24000),
798
+ stderr: String(result.stderr || '').slice(-24000),
799
+ source: generated.source,
800
+ durationMs
801
+ });
802
+ }
803
+ const wasm = fs.readFileSync(wasmFile);
804
+ const wat = fs.existsSync(watFile) ? fs.readFileSync(watFile, 'utf8') : '';
805
+ const inspection = inspectFastlyNativeHttpEffectsWasm(wasm);
806
+ const manifest = Object.freeze({
807
+ ...generated.manifest,
808
+ compilerVersion: FASTLY_NATIVE_HTTP_EFFECTS_COMPILER_VERSION,
809
+ assemblyScript: Object.freeze({ package: 'assemblyscript', version: require(path.join(asc.packageRoot, 'package.json')).version }),
810
+ jsonAs: jsonAs
811
+ ? Object.freeze({ package: 'json-as', version: jsonAs.version, transform: true, strict: true })
812
+ : undefined,
813
+ wasm: Object.freeze({ bytes: inspection.bytes, sha256: inspection.sha256, magic: inspection.magic }),
814
+ wat: Object.freeze({ bytes: Buffer.byteLength(wat), sha256: sha256(wat) }),
815
+ importModules: inspection.importModules,
816
+ imports: inspection.imports,
817
+ exports: inspection.exports
818
+ });
819
+ return Object.freeze({
820
+ version: FASTLY_NATIVE_HTTP_EFFECTS_VERSION,
821
+ compilerVersion: FASTLY_NATIVE_HTTP_EFFECTS_COMPILER_VERSION,
822
+ plan,
823
+ generated,
824
+ source: generated.source,
825
+ sourceHash: generated.sourceHash,
826
+ wasm,
827
+ wat,
828
+ inspection,
829
+ manifest,
830
+ durationMs,
831
+ output: requestedOutDir ? Object.freeze({ outDir: outputDir, wasmFile, watFile }) : undefined
832
+ });
833
+ } finally {
834
+ fs.rmSync(stagingDir, { recursive: true, force: true });
835
+ }
836
+ }
837
+
838
+ function writeFastlyNativeHttpEffectsModule(compiled, outDir, options = {}) {
839
+ if (!compiled || !Buffer.isBuffer(compiled.wasm) || !compiled.manifest || !compiled.plan) throw new TypeError('writeFastlyNativeHttpEffectsModule requires a compiled Pass97 module.');
840
+ const target = path.resolve(outDir);
841
+ fs.mkdirSync(target, { recursive: true });
842
+ const sourceFile = path.join(target, options.sourceFile || 'fastly-native-http-effects.as.ts');
843
+ const wasmFile = path.join(target, options.wasmFile || 'fastly-native-http-effects.wasm');
844
+ const watFile = path.join(target, options.watFile || 'fastly-native-http-effects.wat');
845
+ const planFile = path.join(target, options.planFile || 'canonical-native-plan.json');
846
+ const manifestFile = path.join(target, options.manifestFile || 'fastly-native-http-effects-manifest.json');
847
+ fs.writeFileSync(sourceFile, compiled.source, 'utf8');
848
+ fs.writeFileSync(wasmFile, compiled.wasm);
849
+ fs.writeFileSync(watFile, compiled.wat, 'utf8');
850
+ fs.writeFileSync(planFile, `${stableStringify(compiled.plan, 2)}\n`, 'utf8');
851
+ fs.writeFileSync(manifestFile, `${stableStringify(compiled.manifest, 2)}\n`, 'utf8');
852
+ return Object.freeze({ target, sourceFile, wasmFile, watFile, planFile, manifestFile, manifest: compiled.manifest });
853
+ }
854
+
855
+ module.exports = Object.freeze({
856
+ FASTLY_NATIVE_HTTP_EFFECTS_VERSION,
857
+ FASTLY_NATIVE_HTTP_EFFECTS_GENERATOR_VERSION,
858
+ FASTLY_NATIVE_HTTP_EFFECTS_COMPILER_VERSION,
859
+ FASTLY_NATIVE_HTTP_EFFECTS_ABI_VERSION,
860
+ FASTLY_NATIVE_HTTP_EFFECTS_BUFFER_BYTES,
861
+ FASTLY_NATIVE_HTTP_EFFECTS_MAX_WASM_BYTES,
862
+ FASTLY_NATIVE_HTTP_EFFECTS_IMPORTS,
863
+ FASTLY_NATIVE_HTTP_EFFECTS_REQUIRED_IMPORTS,
864
+ FastlyNativeHttpEffectsError,
865
+ resolveBackendBindings,
866
+ generateFastlyNativeHttpEffectsAssemblyScript,
867
+ compileFastlyNativeHttpEffectsPlan,
868
+ inspectFastlyNativeHttpEffectsWasm,
869
+ writeFastlyNativeHttpEffectsModule,
870
+ stableStringify
871
+ });