@pulse-compute/provider-fastly 0.0.0 → 1.0.0-beta.2

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 (69) hide show
  1. package/README.md +53 -1
  2. package/dist/config-schema.json +77 -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 +88 -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/kv-native.as.ts +229 -0
  12. package/src/build/kv-native.js +20 -0
  13. package/src/build/native-http-effects.js +871 -0
  14. package/src/build/native-http-shell.js +703 -0
  15. package/src/build/native-platform-capabilities.js +2196 -0
  16. package/src/build/s3-native.as.ts +215 -0
  17. package/src/build/s3-native.js +30 -0
  18. package/src/compiler/assets-package-out-parity-proof.js +338 -0
  19. package/src/compiler/assets-provider-proof.js +499 -0
  20. package/src/compiler/config-provider-resolution.js +573 -0
  21. package/src/compiler/fastly-adapter.js +564 -0
  22. package/src/compiler/fastly-command-entry.js +390 -0
  23. package/src/compiler/fastly-config-secret-serve.js +323 -0
  24. package/src/compiler/fastly-hostcall-binding.js +598 -0
  25. package/src/compiler/fastly-readiness.js +477 -0
  26. package/src/compiler/index.js +40 -0
  27. package/src/compiler/lifecycle-parity-contract.js +70 -0
  28. package/src/compiler/lifecycle-parity-proof.js +260 -0
  29. package/src/compiler/route-handler-effect-proof.js +255 -0
  30. package/src/compiler/runtime-provider-kv.js +237 -0
  31. package/src/compiler/runtime-provider-shape.js +109 -0
  32. package/src/config-api.js +63 -0
  33. package/src/config-schema.d.ts +13 -0
  34. package/src/config-schema.js +27 -0
  35. package/src/config-schema.json +77 -0
  36. package/src/index.js +3 -0
  37. package/src/index.ts +118 -0
  38. package/src/javascript/assets-adapter.js +122 -0
  39. package/src/javascript/bindings-adapter.js +237 -0
  40. package/src/javascript/errors.js +26 -0
  41. package/src/javascript/fetch-adapter.js +93 -0
  42. package/src/javascript/grip-broadcast.js +261 -0
  43. package/src/javascript/jwt-verifier.js +137 -0
  44. package/src/javascript/lifecycle.js +55 -0
  45. package/src/javascript/local-loader.js +138 -0
  46. package/src/javascript/logging.js +26 -0
  47. package/src/javascript/package-effects.js +68 -0
  48. package/src/javascript/runtime-host.js +108 -0
  49. package/src/javascript/sha256.js +128 -0
  50. package/src/javascript/source-package.js +776 -0
  51. package/src/javascript/support.js +142 -0
  52. package/src/javascript/target-support-policy.js +264 -0
  53. package/src/javascript/target.js +73 -0
  54. package/src/javascript/test-runtime.js +407 -0
  55. package/src/provider-contract.js +79 -0
  56. package/src/runtime/assets-provider.js +464 -0
  57. package/src/runtime/canonical-api-runtime.js +601 -0
  58. package/src/runtime/index.js +28 -0
  59. package/src/runtime/provider-primitives-contract.js +272 -0
  60. package/src/runtime/provider-primitives.js +82 -0
  61. package/src/runtime/route-handler-effects.js +507 -0
  62. package/src/testing/conditional-kv-host.js +109 -0
  63. package/src/testing/fastly-cli.js +538 -0
  64. package/src/testing/native-http-effects-host.js +390 -0
  65. package/src/testing/native-http-shell-host.js +190 -0
  66. package/src/testing/native-platform-capabilities-host.js +676 -0
  67. package/src/toolchain/config.js +131 -0
  68. package/src/toolchain/index.js +345 -0
  69. package/src/toolchain/s3.js +26 -0
@@ -0,0 +1,2196 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const conditionalKv = require('./kv-native.js');
5
+ const fs = require('node:fs');
6
+ const os = require('node:os');
7
+ const path = require('node:path');
8
+ const { spawnSync } = require('node:child_process');
9
+ const { CANONICAL_NATIVE_PLAN_VERSION } = require('@pulse-compute/wasm-contracts/handler/canonical-native-plan');
10
+ const {
11
+ GUEST_UNIT_CONTRIBUTION_FIELDS,
12
+ normalizeCanonicalGuestUnitContribution
13
+ } = require('@pulse-compute/wasm-contracts/package/package-contract');
14
+ const {
15
+ EXPERIMENTAL_NATIVE_SIZE_OPTIMIZATION,
16
+ appendAssemblyScriptOptimizationArgs
17
+ } = require('@pulse-compute/wasm-build-support/native-optimization');
18
+
19
+ function loadBuildSupport() {
20
+ try { return require('@pulse-compute/wasm-build-support/assemblyscript-compile'); }
21
+ catch (error) {
22
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) {
23
+ return require('../../../../wasm/packages/build-support/src/assemblyscript-compile.js');
24
+ }
25
+ throw error;
26
+ }
27
+ }
28
+
29
+ function loadNativeGenerator() {
30
+ try { return require('@pulse-compute/wasm-runtime-core-as/compiler/canonical-native'); }
31
+ catch (error) {
32
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) {
33
+ return require('../../../../wasm/packages/runtime-core-as/src/compiler/canonical-native.js');
34
+ }
35
+ throw error;
36
+ }
37
+ }
38
+
39
+ function loadJwtNativeSource() {
40
+ try { return require('@pulse-compute/jwt/pulsewasm-native'); }
41
+ catch (error) {
42
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) {
43
+ return require('../../../jwt/pulsewasm.native.cjs');
44
+ }
45
+ throw error;
46
+ }
47
+ }
48
+
49
+ function loadGuestUnitStage() {
50
+ try { return require('@pulse-compute/wasm-guest-link/stage'); }
51
+ catch (error) {
52
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) {
53
+ return require('../../../../wasm/packages/wasm-guest-link/src/stage.js');
54
+ }
55
+ throw error;
56
+ }
57
+ }
58
+
59
+ function loadGuestMemoryContract() {
60
+ try { return require('@pulse-compute/wasm-guest-link'); }
61
+ catch (error) {
62
+ if (error && error.code === 'MODULE_NOT_FOUND') {
63
+ return require('../../../../wasm/packages/wasm-guest-link/src/index.js');
64
+ }
65
+ throw error;
66
+ }
67
+ }
68
+
69
+ function loadGuestToolchain() {
70
+ try { return require('@pulse-compute/wasm-guest-link/toolchain'); }
71
+ catch (error) {
72
+ if (error && ['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(error.code)) {
73
+ return require('../../../../wasm/packages/wasm-guest-link/src/toolchain.js');
74
+ }
75
+ throw error;
76
+ }
77
+ }
78
+
79
+ const { resolveAsc } = loadBuildSupport();
80
+ const { generateCanonicalNativeAssemblyScript } = loadNativeGenerator();
81
+ const { pulseJwtAssemblyScriptSource } = loadJwtNativeSource();
82
+ const {
83
+ GUEST_LINK_STAGE_INVOCATION_VERSION,
84
+ realizeGuestLinkStage
85
+ } = loadGuestUnitStage();
86
+ const { memoryAbiV2, es256FrameV2 } = loadGuestMemoryContract();
87
+ const { runTool: runGuestTool, binaryenIdentity } = loadGuestToolchain();
88
+
89
+ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_VERSION = 'pulse.fastly-native-platform-capabilities.v1';
90
+ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_GENERATOR_VERSION = 'pulse.fastly-native-platform-capabilities-generator.v1';
91
+ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_COMPILER_VERSION = 'pulse.fastly-native-platform-capabilities-compiler.v1';
92
+ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_ABI_VERSION = 1;
93
+ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_MAX_WASM_BYTES = 1024 * 1024;
94
+ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_BUFFER_BYTES = 65536;
95
+ const FASTLY_NATIVE_SIZE_OPTIMIZATION = EXPERIMENTAL_NATIVE_SIZE_OPTIMIZATION;
96
+
97
+ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORTS = Object.freeze([
98
+ ...conditionalKv.KV_IMPORTS.map((key) => Object.freeze(key.split(':'))),
99
+ ...require('./s3-native.js').S3_IMPORTS.map((key) => Object.freeze(key.split(':'))),
100
+ Object.freeze(['fastly_abi', 'init']),
101
+ Object.freeze(['fastly_http_req', 'body_downstream_get']),
102
+ Object.freeze(['fastly_http_req', 'method_get']),
103
+ Object.freeze(['fastly_http_req', 'uri_get']),
104
+ Object.freeze(['fastly_http_req', 'header_value_get']),
105
+ Object.freeze(['fastly_http_req', 'new']),
106
+ Object.freeze(['fastly_http_req', 'method_set']),
107
+ Object.freeze(['fastly_http_req', 'uri_set']),
108
+ Object.freeze(['fastly_http_req', 'header_insert']),
109
+ Object.freeze(['fastly_http_req', 'send_async']),
110
+ Object.freeze(['fastly_http_req', 'pending_req_wait']),
111
+ Object.freeze(['fastly_http_resp', 'new']),
112
+ Object.freeze(['fastly_http_resp', 'header_append']),
113
+ Object.freeze(['fastly_http_resp', 'header_value_get']),
114
+ Object.freeze(['fastly_http_resp', 'status_get']),
115
+ Object.freeze(['fastly_http_resp', 'status_set']),
116
+ Object.freeze(['fastly_http_resp', 'send_downstream']),
117
+ Object.freeze(['fastly_http_body', 'new']),
118
+ Object.freeze(['fastly_http_body', 'read']),
119
+ Object.freeze(['fastly_http_body', 'write']),
120
+ Object.freeze(['fastly_config_store', 'open']),
121
+ Object.freeze(['fastly_config_store', 'get']),
122
+ Object.freeze(['fastly_secret_store', 'open']),
123
+ Object.freeze(['fastly_secret_store', 'get']),
124
+ Object.freeze(['fastly_secret_store', 'plaintext']),
125
+ Object.freeze(['fastly_kv_store', 'open']),
126
+ Object.freeze(['fastly_kv_store', 'lookup']),
127
+ Object.freeze(['fastly_kv_store', 'lookup_wait_v2']),
128
+ Object.freeze(['fastly_kv_store', 'insert']),
129
+ Object.freeze(['fastly_kv_store', 'insert_wait']),
130
+ Object.freeze(['fastly_log', 'endpoint_get']),
131
+ Object.freeze(['fastly_log', 'write']),
132
+ Object.freeze(['wasi_snapshot_preview1', 'clock_time_get'])
133
+ ].filter(([module, name], index, entries) => entries.findIndex((item) => item[0] === module && item[1] === name) === index));
134
+
135
+ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_REQUIRED_IMPORTS = Object.freeze([
136
+ Object.freeze(['fastly_abi', 'init']),
137
+ Object.freeze(['fastly_http_req', 'body_downstream_get']),
138
+ Object.freeze(['fastly_http_resp', 'send_downstream']),
139
+ Object.freeze(['fastly_http_body', 'new']),
140
+ Object.freeze(['fastly_http_body', 'write'])
141
+ ]);
142
+
143
+ const FASTLY_NATIVE_PLATFORM_EFFECT_KIND = Object.freeze({
144
+ fetch: 1,
145
+ 'config.get': 2,
146
+ 'secret.get': 3,
147
+ 'kv.get': 4,
148
+ 'kv.put': 5,
149
+ 'grip.channel': 6,
150
+ 'grip.hold': 7,
151
+ 'grip.publish': 8,
152
+ 'grip.broadcast': 9,
153
+ 'assets.lookup': 10,
154
+ 'jwt.verify': 11,
155
+ 's3.head': 12,
156
+ 's3.getText': 13,
157
+ 's3.putText': 14,
158
+ 'kv.getVersioned': 15,
159
+ 'kv.insertIfAbsent': 16,
160
+ 'kv.compareAndSwap': 17
161
+ });
162
+
163
+ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_ALLOWED_IMPORTS = new Set([
164
+ ...FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORTS.map(([moduleName, name]) => `${moduleName}:${name}`)
165
+ ]);
166
+
167
+ const FASTLY_NATIVE_PLATFORM_EFFECT_KINDS = Object.freeze([
168
+ 'fetch',
169
+ 'config.get',
170
+ 'secret.get',
171
+ 'kv.get',
172
+ 'kv.put',
173
+ ...conditionalKv.KV_CONDITIONAL_KINDS,
174
+ 'grip.channel',
175
+ 'grip.hold',
176
+ 'grip.publish',
177
+ 'grip.broadcast',
178
+ 'assets.lookup',
179
+ 'jwt.verify',
180
+ 's3.head',
181
+ 's3.getText',
182
+ 's3.putText'
183
+ ]);
184
+
185
+ const FASTLY_NATIVE_PLATFORM_CAPABILITY_KINDS = new Set([
186
+ 'config.get',
187
+ 'secret.get',
188
+ 'kv.get',
189
+ 'kv.put',
190
+ ...conditionalKv.KV_CONDITIONAL_KINDS,
191
+ 'assets.lookup',
192
+ 'grip.channel',
193
+ 'grip.hold',
194
+ 'grip.publish',
195
+ 'grip.broadcast',
196
+ 'jwt.verify',
197
+ 's3.head',
198
+ 's3.getText',
199
+ 's3.putText'
200
+ ]);
201
+
202
+ class FastlyNativePlatformCapabilitiesError extends Error {
203
+ constructor(message, code = 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_FAILED', detail = {}) {
204
+ super(message);
205
+ this.name = 'FastlyNativePlatformCapabilitiesError';
206
+ this.code = code;
207
+ this.detail = Object.freeze({ ...detail });
208
+ }
209
+ }
210
+
211
+ function sha256(value) {
212
+ return crypto.createHash('sha256').update(value).digest('hex');
213
+ }
214
+
215
+ function stableObject(value) {
216
+ if (Array.isArray(value)) return value.map(stableObject);
217
+ if (!value || typeof value !== 'object') return value;
218
+ const output = {};
219
+ for (const key of Object.keys(value).sort()) if (value[key] !== undefined) output[key] = stableObject(value[key]);
220
+ return output;
221
+ }
222
+
223
+ function stableStringify(value, space = 0) {
224
+ return JSON.stringify(stableObject(value), null, space);
225
+ }
226
+
227
+ function canonicalGuestContribution(selection) {
228
+ return normalizeCanonicalGuestUnitContribution(Object.fromEntries(
229
+ GUEST_UNIT_CONTRIBUTION_FIELDS.map((field) => [field, selection && selection[field]])
230
+ ));
231
+ }
232
+
233
+ function guestLinkOptimizationPosture(value) {
234
+ return value
235
+ && (
236
+ value === true
237
+ || value === 'experimental-native-size'
238
+ || (typeof value === 'object' && value.mode === 'experimental-native-size')
239
+ )
240
+ ? 'native-size'
241
+ : 'native-default';
242
+ }
243
+
244
+ function quote(value) {
245
+ return JSON.stringify(String(value));
246
+ }
247
+
248
+ function fail(message, code, detail = {}) {
249
+ throw new FastlyNativePlatformCapabilitiesError(message, code, detail);
250
+ }
251
+
252
+ function packageFacts(_plan, options = {}) {
253
+ const realizationArtifacts = options.realizationArtifacts || [];
254
+ const guestUnits = options.guestUnits || [];
255
+ return Object.freeze({
256
+ realizationArtifacts: Object.freeze([...realizationArtifacts]),
257
+ guestUnits: Object.freeze([...guestUnits])
258
+ });
259
+ }
260
+
261
+ function selectedJwtCrypto(plan) {
262
+ const hasJwt = (plan.effects || []).some((effect) => effect.kind === 'jwt.verify');
263
+ if (!hasJwt) return undefined;
264
+ const algorithms = plan.crypto && Array.isArray(plan.crypto.algorithms)
265
+ ? plan.crypto.algorithms.filter((entry) => ['HS256', 'ES256'].includes(entry.algorithm))
266
+ : [];
267
+ if (algorithms.length !== 1) {
268
+ fail(
269
+ 'Fastly Native JWT requires one exact crypto realization.',
270
+ 'PULSE_FASTLY_NATIVE_JWT_CRYPTO_REALIZATION_INVALID',
271
+ { algorithms, automaticFallback: false }
272
+ );
273
+ }
274
+ const selected = algorithms[0];
275
+ const hs256 = selected.algorithm === 'HS256'
276
+ && selected.realization === 'guest-source:pulse-hmac-as'
277
+ && selected.implementation === 'pulse-hmac-as.v1'
278
+ && selected.kind === 'guest-source'
279
+ && selected.targetImplemented === true;
280
+ const es256 = selected.algorithm === 'ES256'
281
+ && selected.realization === 'guest-linked:pulse-es256-rustcrypto-p256'
282
+ && selected.implementation === 'rustcrypto.p256-0.13.2.ecdsa-0.16.9.sha2-0.10.9.v1'
283
+ && selected.kind === 'guest-linked'
284
+ && selected.targetImplemented === true;
285
+ if ((!hs256 && !es256) || selected.automaticFallback !== false) {
286
+ fail(
287
+ 'Fastly Native JWT selected an unavailable or non-exact crypto realization.',
288
+ 'PULSE_FASTLY_NATIVE_JWT_CRYPTO_REALIZATION_INVALID',
289
+ { selected, automaticFallback: false }
290
+ );
291
+ }
292
+ return Object.freeze({
293
+ algorithm: selected.algorithm,
294
+ realization: selected.realization,
295
+ implementation: selected.implementation,
296
+ kind: selected.kind,
297
+ guestUnitRequired: es256,
298
+ automaticFallback: false
299
+ });
300
+ }
301
+
302
+ function decodeP256Coordinate(value, artifactId, field) {
303
+ if (typeof value !== 'string' || !/^[A-Za-z0-9_-]+$/.test(value)) {
304
+ fail(
305
+ 'Fastly Native ES256 key artifacts require canonical base64url coordinates.',
306
+ 'PULSE_FASTLY_NATIVE_JWT_KEY_ARTIFACT_INVALID',
307
+ { artifactId, field }
308
+ );
309
+ }
310
+ const bytes = Buffer.from(value, 'base64url');
311
+ if (bytes.length !== 32 || bytes.toString('base64url') !== value) {
312
+ fail(
313
+ 'Fastly Native ES256 key artifacts require exactly 32-byte coordinates.',
314
+ 'PULSE_FASTLY_NATIVE_JWT_KEY_ARTIFACT_INVALID',
315
+ { artifactId, field, bytes: bytes.length }
316
+ );
317
+ }
318
+ return bytes;
319
+ }
320
+
321
+ function normalizedEs256Jwk(value, artifactId) {
322
+ if (
323
+ !value
324
+ || typeof value !== 'object'
325
+ || Array.isArray(value)
326
+ || value.kty !== 'EC'
327
+ || value.crv !== 'P-256'
328
+ || (value.alg !== undefined && value.alg !== 'ES256')
329
+ || (value.use !== undefined && value.use !== 'sig')
330
+ || (
331
+ value.key_ops !== undefined
332
+ && (
333
+ !Array.isArray(value.key_ops)
334
+ || value.key_ops.length !== 1
335
+ || value.key_ops[0] !== 'verify'
336
+ )
337
+ )
338
+ || ['d', 'p', 'q', 'dp', 'dq', 'qi', 'oth', 'x5c', 'x5u', 'x5t', 'x5t#S256']
339
+ .some((name) => Object.prototype.hasOwnProperty.call(value, name))
340
+ ) {
341
+ fail(
342
+ 'Fastly Native ES256 key artifacts contain an invalid public JWK.',
343
+ 'PULSE_FASTLY_NATIVE_JWT_KEY_ARTIFACT_INVALID',
344
+ { artifactId }
345
+ );
346
+ }
347
+ const x = decodeP256Coordinate(value.x, artifactId, 'x');
348
+ const y = decodeP256Coordinate(value.y, artifactId, 'y');
349
+ return Object.freeze({
350
+ kid: value.kid === undefined ? undefined : String(value.kid),
351
+ bytes: Buffer.concat([x, y])
352
+ });
353
+ }
354
+
355
+ function resolveEs256KeyArtifacts(plan, facts) {
356
+ const artifacts = new Map(facts.realizationArtifacts.map((artifact) => [
357
+ String(artifact && artifact.id || ''),
358
+ artifact
359
+ ]));
360
+ const records = [];
361
+ for (const [effectIndex, effect] of (plan.effects || []).entries()) {
362
+ if (effect.kind !== 'jwt.verify' || !['jwk', 'jwks'].includes(effect.resource.keyType)) {
363
+ continue;
364
+ }
365
+ const artifactId = effect.resource.keyArtifactId;
366
+ const artifact = artifacts.get(artifactId);
367
+ if (
368
+ !artifact
369
+ || artifact.version !== 'pulse.jwt-es256-key-artifact.v1'
370
+ || artifact.contractId !== 'pulse.jwt'
371
+ || artifact.package !== '@pulse-compute/jwt'
372
+ || artifact.kind !== 'jwt-es256-static-public-key'
373
+ || artifact.mediaType !== 'application/vnd.pulse.jwt-es256-key+json'
374
+ || artifact.id !== artifactId
375
+ || artifact.materialHash !== sha256(stableStringify(artifact.data))
376
+ || !artifact.data
377
+ || artifact.data.type !== effect.resource.keyType
378
+ ) {
379
+ fail(
380
+ 'Fastly Native ES256 requires the exact private package key artifact selected by lowering.',
381
+ 'PULSE_FASTLY_NATIVE_JWT_KEY_ARTIFACT_INVALID',
382
+ { effectId: effect.id, artifactId, automaticFallback: false }
383
+ );
384
+ }
385
+ const keys = artifact.data.type === 'jwk'
386
+ ? [artifact.data.key]
387
+ : artifact.data.keys;
388
+ if (
389
+ !Array.isArray(keys)
390
+ || keys.length === 0
391
+ || keys.length > 16
392
+ ) {
393
+ fail(
394
+ 'Fastly Native ES256 key artifacts require one bounded static JWK set.',
395
+ 'PULSE_FASTLY_NATIVE_JWT_KEY_ARTIFACT_INVALID',
396
+ { effectId: effect.id, artifactId, keyCount: keys && keys.length }
397
+ );
398
+ }
399
+ const normalized = keys.map((key) => normalizedEs256Jwk(key, artifactId));
400
+ const kids = normalized.map((key) => key.kid).filter((kid) => kid !== undefined);
401
+ if (new Set(kids).size !== kids.length) {
402
+ fail(
403
+ 'Fastly Native ES256 key artifacts reject duplicate kid values.',
404
+ 'PULSE_FASTLY_NATIVE_JWT_KEY_ARTIFACT_INVALID',
405
+ { effectId: effect.id, artifactId }
406
+ );
407
+ }
408
+ records.push(Object.freeze({
409
+ effectIndex,
410
+ effectId: effect.id,
411
+ artifactId,
412
+ type: artifact.data.type,
413
+ materialHash: artifact.materialHash,
414
+ keys: Object.freeze(normalized)
415
+ }));
416
+ }
417
+ return Object.freeze(records);
418
+ }
419
+
420
+ function byteAssignments(name, bytes) {
421
+ return [
422
+ `function ${name}(): Uint8Array {`,
423
+ ` const output = new Uint8Array(${bytes.length})`,
424
+ ...[...bytes].map((value, index) => ` unchecked(output[${index}] = ${value})`),
425
+ ' return output',
426
+ '}'
427
+ ].join('\n');
428
+ }
429
+
430
+ function es256KeyArtifactSource(records) {
431
+ if (records.length === 0) {
432
+ return 'function __pulse_fastly_jwt_resolve_es256_key(effectIndex: i32, kid: string | null): Uint8Array | null { void effectIndex; void kid; return null }';
433
+ }
434
+ const lines = [];
435
+ for (const record of records) {
436
+ for (const [keyIndex, key] of record.keys.entries()) {
437
+ lines.push(byteAssignments(
438
+ `__pulse_fastly_es256_key_${record.effectIndex}_${keyIndex}`,
439
+ key.bytes
440
+ ));
441
+ }
442
+ }
443
+ lines.push(
444
+ 'function __pulse_fastly_jwt_resolve_es256_key(effectIndex: i32, kid: string | null): Uint8Array | null {',
445
+ ' switch (effectIndex) {'
446
+ );
447
+ for (const record of records) {
448
+ lines.push(` case ${record.effectIndex}: {`);
449
+ if (record.type === 'jwk') {
450
+ const key = record.keys[0];
451
+ if (key.kid !== undefined) {
452
+ lines.push(` if (kid !== null && kid != ${quote(key.kid)}) return null`);
453
+ }
454
+ lines.push(` return __pulse_fastly_es256_key_${record.effectIndex}_0()`);
455
+ } else {
456
+ lines.push(' if (kid !== null) {');
457
+ for (const [keyIndex, key] of record.keys.entries()) {
458
+ if (key.kid !== undefined) {
459
+ lines.push(` if (kid == ${quote(key.kid)}) return __pulse_fastly_es256_key_${record.effectIndex}_${keyIndex}()`);
460
+ }
461
+ }
462
+ lines.push(' return null', ' }');
463
+ if (record.keys.length === 1) {
464
+ lines.push(` return __pulse_fastly_es256_key_${record.effectIndex}_0()`);
465
+ } else {
466
+ lines.push(' return null');
467
+ }
468
+ }
469
+ lines.push(' }');
470
+ }
471
+ lines.push(' default: return null', ' }', '}');
472
+ return lines.join('\n');
473
+ }
474
+
475
+ function jwtCryptoCompositionSource(selected) {
476
+ if (!selected) {
477
+ return [
478
+ 'function __pulse_fastly_jwt_capture_signing_input(input: Uint8Array): void { void input }',
479
+ 'function __pulse_fastly_jwt_crypto_verify(algorithm: string, key: Uint8Array, data: Uint8Array, signature: Uint8Array): i32 { void algorithm; void key; void data; void signature; return -3 }'
480
+ ].join('\n');
481
+ }
482
+ if (selected.algorithm === 'HS256') {
483
+ return String.raw`
484
+ function __pulse_fastly_jwt_capture_signing_input(input: Uint8Array): void {
485
+ const digest = new Uint8Array(32)
486
+ if (pulse_crypto_sha256_digest(input.dataStart, input.byteLength, digest.dataStart, digest.byteLength) == 1) {
487
+ __pulse_fastly_jwt_record_signing_input(input.byteLength, __pulse_jwt_hex(digest))
488
+ }
489
+ for (let index: i32 = 0; index < digest.byteLength; index += 1) unchecked(digest[index] = 0)
490
+ }
491
+ function __pulse_fastly_jwt_crypto_verify(algorithm: string, key: Uint8Array, data: Uint8Array, signature: Uint8Array): i32 {
492
+ if (algorithm != "HS256") return -2
493
+ return pulse_crypto_hs256_verify(
494
+ key.dataStart,
495
+ key.byteLength,
496
+ data.dataStart,
497
+ data.byteLength,
498
+ signature.dataStart,
499
+ signature.byteLength,
500
+ )
501
+ }`;
502
+ }
503
+ return String.raw`
504
+ const __PULSE_FASTLY_ES256_FRAME_POINTER: i32 = ${memoryAbiV2.layout.invocationFrame.start}
505
+ const __PULSE_FASTLY_ES256_FRAME_CAPACITY: i32 = ${es256FrameV2.capacityBytes}
506
+ function __pulse_fastly_es256_clear_frame(): void {
507
+ for (let index: i32 = 0; index < __PULSE_FASTLY_ES256_FRAME_CAPACITY; index += 1) {
508
+ store<u8>(__PULSE_FASTLY_ES256_FRAME_POINTER + index, 0)
509
+ }
510
+ }
511
+ function __pulse_fastly_jwt_capture_signing_input(input: Uint8Array): void {
512
+ __pulse_fastly_jwt_record_signing_input(input.byteLength, "")
513
+ }
514
+ function __pulse_fastly_jwt_crypto_verify(algorithm: string, key: Uint8Array, data: Uint8Array, signature: Uint8Array): i32 {
515
+ if (algorithm != "ES256" || key.byteLength != 64 || signature.byteLength != 64 || data.byteLength > ${es256FrameV2.signingInputBytesMaximum}) return -2
516
+ __pulse_fastly_es256_clear_frame()
517
+ const totalLength = (192 + data.byteLength + 15) & ~15
518
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 0, ${es256FrameV2.magic})
519
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 4, ${es256FrameV2.version})
520
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 8, ${es256FrameV2.headerBytes})
521
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 12, totalLength)
522
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 16, 1)
523
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 20, 0)
524
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 24, 192)
525
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 28, data.byteLength)
526
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 32, 64)
527
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 36, 64)
528
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 40, 128)
529
+ store<u32>(__PULSE_FASTLY_ES256_FRAME_POINTER + 44, 64)
530
+ for (let index: i32 = 0; index < key.byteLength; index += 1) store<u8>(__PULSE_FASTLY_ES256_FRAME_POINTER + 64 + index, unchecked(key[index]))
531
+ for (let index: i32 = 0; index < signature.byteLength; index += 1) store<u8>(__PULSE_FASTLY_ES256_FRAME_POINTER + 128 + index, unchecked(signature[index]))
532
+ for (let index: i32 = 0; index < data.byteLength; index += 1) store<u8>(__PULSE_FASTLY_ES256_FRAME_POINTER + 192 + index, unchecked(data[index]))
533
+ const status = __pulse_crypto_es256_link_anchor(
534
+ __PULSE_FASTLY_ES256_FRAME_POINTER,
535
+ __PULSE_FASTLY_ES256_FRAME_CAPACITY,
536
+ )
537
+ __pulse_fastly_es256_clear_frame()
538
+ return status
539
+ }`;
540
+ }
541
+
542
+ function fastlyGuestLinkedStartWrapperWat() {
543
+ return `(module
544
+ (import "pulse_fastly_primary" "__pulse_initialize" (func $initialize))
545
+ (import "pulse_fastly_primary" "pulse_fastly_handle" (func $handle))
546
+ (global $initialized (mut i32) (i32.const 0))
547
+ (func (export "_start")
548
+ (if (i32.eqz (global.get $initialized))
549
+ (then
550
+ (call $initialize)
551
+ (global.set $initialized (i32.const 1))
552
+ )
553
+ )
554
+ (call $handle)
555
+ )
556
+ )
557
+ `;
558
+ }
559
+
560
+ function validatePlanBoundary(plan, options = {}) {
561
+ if (!plan || typeof plan !== 'object') throw new TypeError('Fastly native platform capability realization requires a canonical native plan.');
562
+ if (plan.version !== CANONICAL_NATIVE_PLAN_VERSION) {
563
+ fail(`Fastly native platform capability realization requires ${CANONICAL_NATIVE_PLAN_VERSION}.`, 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_PLAN_VERSION_UNSUPPORTED', { version: plan.version });
564
+ }
565
+ if (!plan.ownership || plan.ownership.providerNeutral !== true || plan.ownership.javascriptRuntime !== false) {
566
+ fail('Fastly native platform capability realization requires a provider-neutral plan without JavaScript runtime ownership.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_PLAN_OWNERSHIP_INVALID', { ownership: plan.ownership });
567
+ }
568
+ const effects = plan.effects || [];
569
+ const unsupported = effects.filter((effect) => !FASTLY_NATIVE_PLATFORM_EFFECT_KINDS.includes(effect.kind));
570
+ if (unsupported.length > 0) {
571
+ fail('Fastly native realization supports fetch, config, secret, KV, Assets, JWT, and the first-party GRIP capability contract.', 'PULSE_FASTLY_NATIVE_PLATFORM_EFFECT_KIND_UNSUPPORTED', {
572
+ effects: unsupported.map((entry) => ({ id: entry.id, kind: entry.kind, package: entry.package, contractId: entry.contractId }))
573
+ });
574
+ }
575
+ const platformEffects = effects.filter((effect) => FASTLY_NATIVE_PLATFORM_CAPABILITY_KINDS.has(effect.kind));
576
+ if (platformEffects.length === 0 && options.requirePlatformCapability !== false) {
577
+ fail('Pass98 requires at least one Fastly platform capability effect.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITY_REQUIRED');
578
+ }
579
+ const packageEffects = effects.filter((effect) => effect.package || effect.contractId);
580
+ const unsupportedPackages = packageEffects.filter((effect) => {
581
+ const grip = effect.package === '@pulse-compute/grip'
582
+ && effect.contractId === 'pulse.grip'
583
+ && String(effect.kind).startsWith('grip.');
584
+ const assets = effect.package === '@pulse-compute/assets'
585
+ && effect.contractId === 'pulse.assets'
586
+ && effect.kind === 'assets.lookup';
587
+ const jwt = effect.package === '@pulse-compute/jwt'
588
+ && effect.contractId === 'pulse.jwt'
589
+ && effect.kind === 'jwt.verify'
590
+ && effect.operation === 'verify'
591
+ && effect.capability === 'jwt.verify';
592
+ const s3 = effect.package === '@pulse-compute/s3' && effect.contractId === 'pulse.s3'
593
+ && ['head', 'getText', 'putText'].includes(effect.operation) && effect.kind === `s3.${effect.operation}` && effect.capability === effect.kind;
594
+ return !grip && !assets && !jwt && !s3;
595
+ });
596
+ if (unsupportedPackages.length > 0) {
597
+ fail('Fastly native realization only accepts the trusted first-party Assets, GRIP, and JWT package contracts.', 'PULSE_FASTLY_NATIVE_PLATFORM_PACKAGE_UNSUPPORTED', {
598
+ effects: unsupportedPackages.map((entry) => ({ id: entry.id, kind: entry.kind, package: entry.package, contractId: entry.contractId }))
599
+ });
600
+ }
601
+ const declaredPackageEffects = ((plan.packages && plan.packages.effects) || []);
602
+ const unsupportedDeclarations = declaredPackageEffects.filter((effect) => {
603
+ const grip = effect.package === '@pulse-compute/grip'
604
+ && effect.contractId === 'pulse.grip'
605
+ && String(effect.kind).startsWith('grip.');
606
+ const assets = effect.package === '@pulse-compute/assets'
607
+ && effect.contractId === 'pulse.assets'
608
+ && effect.kind === 'assets.lookup';
609
+ const jwt = effect.package === '@pulse-compute/jwt'
610
+ && effect.contractId === 'pulse.jwt'
611
+ && effect.kind === 'jwt.verify'
612
+ && effect.operation === 'verify'
613
+ && effect.capability === 'jwt.verify';
614
+ const s3 = effect.package === '@pulse-compute/s3' && effect.contractId === 'pulse.s3'
615
+ && ['head', 'getText', 'putText'].includes(effect.operation) && effect.kind === `s3.${effect.operation}` && effect.capability === effect.kind;
616
+ return !grip && !assets && !jwt && !s3;
617
+ });
618
+ if (unsupportedDeclarations.length > 0) {
619
+ fail('Fastly native package realization is restricted to the Assets, GRIP, and JWT contracts.', 'PULSE_FASTLY_NATIVE_PLATFORM_PACKAGE_UNSUPPORTED', { effects: unsupportedDeclarations });
620
+ }
621
+ for (const effect of effects.filter((entry) => entry.kind === 'jwt.verify')) {
622
+ const resource = effect.resource;
623
+ const knownShape = resource
624
+ && !Object.keys(resource)
625
+ .some((name) => !['keyType', 'keyArtifactId', 'secretBinding'].includes(name));
626
+ const namedSecret = knownShape
627
+ && resource.keyType === 'secret'
628
+ && resource.keyArtifactId === null
629
+ && typeof resource.secretBinding === 'string'
630
+ && resource.secretBinding.length > 0;
631
+ const staticPublicKey = knownShape
632
+ && ['jwk', 'jwks'].includes(resource.keyType)
633
+ && typeof resource.keyArtifactId === 'string'
634
+ && resource.keyArtifactId.length > 0
635
+ && resource.secretBinding === null;
636
+ if (!namedSecret && !staticPublicKey) {
637
+ fail('Fastly Native JWT requires one exact named-secret or bounded static public-key descriptor.', 'PULSE_FASTLY_NATIVE_JWT_KEY_DESCRIPTOR_INVALID', {
638
+ effectId: effect.id,
639
+ resource,
640
+ automaticFallback: false
641
+ });
642
+ }
643
+ }
644
+ if (!plan.entry || !Array.isArray(plan.entry.body)) {
645
+ fail('Fastly native platform capability realization requires a canonical handler entry body.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_ENTRY_INVALID');
646
+ }
647
+ return plan;
648
+ }
649
+
650
+ function literalOriginFromExpression(expression) {
651
+ if (!expression || typeof expression !== 'object') return undefined;
652
+ if (expression.kind === 'literal' && typeof expression.value === 'string') {
653
+ try { return new URL(expression.value).origin; }
654
+ catch (_) { return undefined; }
655
+ }
656
+ if (expression.kind === 'template') {
657
+ const first = (expression.parts || [])[0];
658
+ if (first && first.kind === 'text') {
659
+ try { return new URL(first.value).origin; }
660
+ catch (_) { return undefined; }
661
+ }
662
+ }
663
+ return undefined;
664
+ }
665
+
666
+ function stringBinding(value, label, code, detail = {}) {
667
+ const normalized = value === undefined || value === null ? '' : String(value).trim();
668
+ if (!normalized) fail(`${label} is required for Pass98 native Fastly realization.`, code, detail);
669
+ return normalized;
670
+ }
671
+
672
+ function inputExpression(effect, name) {
673
+ const found = (effect.inputs || []).find((entry) => entry.name === name);
674
+ return found && found.value;
675
+ }
676
+
677
+ function literalString(expression) {
678
+ return expression && expression.kind === 'literal' && typeof expression.value === 'string'
679
+ ? expression.value
680
+ : undefined;
681
+ }
682
+
683
+ function literalObjectField(expression, name) {
684
+ if (!expression || expression.kind !== 'object' || !Array.isArray(expression.entries)) return undefined;
685
+ const entry = expression.entries.find((item) => item
686
+ && item.kind === 'property'
687
+ && item.key
688
+ && item.key.kind === 'literal'
689
+ && item.key.value === name);
690
+ return entry && literalString(entry.value);
691
+ }
692
+
693
+ function resolveCapabilityBindings(plan, options = {}) {
694
+ const source = options.bindings && typeof options.bindings === 'object' ? options.bindings : options;
695
+ const byEffect = source.effectBackends || options.effectBackends || {};
696
+ const byOrigin = source.backends || options.backends || {};
697
+ const kvMap = source.kv || options.kv || {};
698
+ const gripInput = source.grip || options.grip || {};
699
+ const effects = plan.effects || [];
700
+ const hasConfig = effects.some((effect) => effect.kind === 'config.get');
701
+ const hasSecret = effects.some((effect) => (
702
+ effect.kind === 'secret.get' || ['s3.head', 's3.getText', 's3.putText'].includes(effect.kind)
703
+ || (effect.kind === 'jwt.verify' && effect.resource && effect.resource.keyType === 'secret')
704
+ ));
705
+ const hasGripHold = effects.some((effect) => effect.kind === 'grip.hold');
706
+ const hasGripBroadcast = effects.some((effect) => effect.kind === 'grip.broadcast');
707
+ const hasGripPublish = effects.some((effect) => effect.kind === 'grip.publish') || hasGripBroadcast;
708
+ const gripAuthentication = gripInput.authentication && typeof gripInput.authentication === 'object'
709
+ ? gripInput.authentication
710
+ : undefined;
711
+ const gripSecretRef = gripAuthentication && String(gripAuthentication.secretRef || '').trim();
712
+ if (gripAuthentication && String(gripAuthentication.scheme || 'bearer').toLowerCase() !== 'bearer') {
713
+ fail('Fastly GRIP broadcast supports only bearer authentication.', 'PULSE_FASTLY_NATIVE_GRIP_AUTH_SCHEME_UNSUPPORTED');
714
+ }
715
+ if (gripAuthentication && !gripSecretRef) {
716
+ fail('Fastly GRIP bearer authentication requires a named secret reference.', 'PULSE_FASTLY_NATIVE_GRIP_SECRET_REFERENCE_MISSING');
717
+ }
718
+ const configStore = hasConfig
719
+ ? stringBinding(source.configStore, 'Fastly configStore binding', 'PULSE_FASTLY_NATIVE_CONFIG_STORE_MISSING')
720
+ : '';
721
+ const secretStore = hasSecret || gripSecretRef
722
+ ? stringBinding(source.secretStore, 'Fastly secretStore binding', 'PULSE_FASTLY_NATIVE_SECRET_STORE_MISSING')
723
+ : '';
724
+
725
+ const kv = [];
726
+ for (const [index, effect] of effects.entries()) {
727
+ if (effect.kind !== 'kv.get' && effect.kind !== 'kv.put' && !conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind) && effect.kind !== 'assets.lookup') continue;
728
+ const packagePayload = inputExpression(effect, 'payload');
729
+ const logical = effect.resource && effect.resource.kind === 'literal'
730
+ && effect.kind !== 'assets.lookup'
731
+ ? String(effect.resource.value)
732
+ : literalString(inputExpression(effect, 'store')) || literalObjectField(packagePayload, 'store');
733
+ if (!logical) {
734
+ fail(`KV-backed effect ${effect.id} requires a static logical namespace.`, 'PULSE_FASTLY_NATIVE_KV_NAMESPACE_DYNAMIC', {
735
+ effectId: effect.id,
736
+ resource: effect.resource
737
+ });
738
+ }
739
+ if (conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind) && Buffer.byteLength(logical, 'utf8') > conditionalKv.KV_CONDITIONAL_LIMITS.namespaceBytes) fail('Conditional KV namespace exceeds its portable bound.', 'PULSE_FASTLY_NATIVE_KV_NAMESPACE_DYNAMIC');
740
+ const physical = stringBinding(
741
+ kvMap[logical],
742
+ `Fastly KV binding for ${logical}`,
743
+ 'PULSE_FASTLY_NATIVE_KV_STORE_MISSING',
744
+ { logical, effectId: effect.id }
745
+ );
746
+ kv.push(Object.freeze({ index, effectId: effect.id, kind: effect.kind, logical, physical }));
747
+ }
748
+
749
+ if (hasGripHold && gripInput.directHold === false) {
750
+ fail(
751
+ 'Pass98 realizes direct GRIP hold headers only; Fanout handoff remains outside this atomic pass.',
752
+ 'PULSE_FASTLY_NATIVE_GRIP_FANOUT_DEFERRED'
753
+ );
754
+ }
755
+
756
+ const backends = [];
757
+ const fetch = [];
758
+ const gripPublish = [];
759
+ let publishUrl = '';
760
+ let publishBackend = '';
761
+ if (hasGripPublish) {
762
+ publishUrl = stringBinding(
763
+ hasGripBroadcast ? gripInput.publishEndpoint : (gripInput.publishUrl || gripInput.publishEndpoint),
764
+ hasGripBroadcast ? 'Fastly GRIP publishEndpoint binding' : 'Fastly GRIP publishUrl binding',
765
+ 'PULSE_FASTLY_NATIVE_GRIP_PUBLISH_URL_MISSING'
766
+ );
767
+ let derivedBackend;
768
+ try { derivedBackend = byOrigin[new URL(publishUrl).origin]; }
769
+ catch (_) { /* stringBinding below reports a stable binding diagnostic */ }
770
+ publishBackend = stringBinding(
771
+ gripInput.publishBackend || derivedBackend,
772
+ 'Fastly GRIP publish backend binding',
773
+ 'PULSE_FASTLY_NATIVE_GRIP_PUBLISH_BACKEND_MISSING'
774
+ );
775
+ }
776
+
777
+ for (const [index, effect] of effects.entries()) {
778
+ if (effect.kind !== 'fetch' && effect.kind !== 'grip.publish' && effect.kind !== 'grip.broadcast') continue;
779
+ let origin = null;
780
+ let url = null;
781
+ let backend;
782
+ if (effect.kind === 'grip.publish' || effect.kind === 'grip.broadcast') {
783
+ url = publishUrl;
784
+ try { origin = new URL(url).origin; }
785
+ catch (_) { origin = null; }
786
+ backend = publishBackend;
787
+ } else {
788
+ const urlInput = inputExpression(effect, 'url');
789
+ origin = effect.resource && effect.resource.origin
790
+ ? String(effect.resource.origin)
791
+ : literalOriginFromExpression(urlInput) || null;
792
+ backend = byEffect[effect.id]
793
+ || (origin && byOrigin[origin])
794
+ || (effect.resource && effect.resource.value && byOrigin[effect.resource.value]);
795
+ if ((typeof backend !== 'string' || backend.trim() === '') && !origin) {
796
+ const configured = [...new Set(Object.values(byOrigin).filter((value) => typeof value === 'string' && value.trim()).map((value) => value.trim()))];
797
+ if (configured.length === 1) backend = configured[0];
798
+ }
799
+ if (typeof backend !== 'string' || backend.trim() === '') {
800
+ fail(`Fastly native effect ${effect.id} has no static backend binding.`, 'PULSE_FASTLY_BACKEND_REQUIRED', {
801
+ effectId: effect.id,
802
+ effectIndex: index,
803
+ origin,
804
+ hint: `Provide bindings.backends[${JSON.stringify(origin || '<origin>')}] or an explicit effect backend.`
805
+ });
806
+ }
807
+ backend = backend.trim();
808
+ }
809
+ const binding = Object.freeze({
810
+ index,
811
+ effectId: effect.id,
812
+ kind: effect.kind,
813
+ origin,
814
+ url,
815
+ backend,
816
+ ...(effect.kind === 'grip.broadcast' && gripSecretRef ? { authSecretRef: gripSecretRef } : {})
817
+ });
818
+ backends.push(binding);
819
+ if (effect.kind === 'fetch') fetch.push(binding);
820
+ else gripPublish.push(binding);
821
+ }
822
+
823
+ return Object.freeze({
824
+ configStore,
825
+ secretStore,
826
+ s3: require('../toolchain/s3.js').resolveFastlyS3(effects.map((effect) => ({ ...effect, payload: { contentType: literalObjectField(inputExpression(effect, 'payload'), 'contentType') || undefined } })), source.s3),
827
+ kv: Object.freeze(kv),
828
+ fetch: Object.freeze(fetch),
829
+ backends: Object.freeze(backends),
830
+ grip: Object.freeze({
831
+ directHold: gripInput.directHold !== false,
832
+ authentication: gripSecretRef ? Object.freeze({ scheme: 'bearer', secretRef: gripSecretRef }) : undefined,
833
+ publish: Object.freeze(gripPublish)
834
+ })
835
+ });
836
+ }
837
+
838
+ function planRequiresFetchBodyRead(plan) {
839
+ for (const effect of plan.effects || []) {
840
+ if (effect.kind !== 'fetch') continue;
841
+ const result = effect.result || {};
842
+ const decoder = effect.decoder || result.decoder;
843
+ const decoderKind = typeof decoder === 'string' ? decoder : decoder && decoder.kind;
844
+ if (result.valueKind === 'json' || result.valueKind === 'text' || decoderKind === 'json' || decoderKind === 'text') return true;
845
+ }
846
+
847
+ const seen = new Set();
848
+ function visit(value) {
849
+ if (!value || typeof value !== 'object') return false;
850
+ if (seen.has(value)) return false;
851
+ seen.add(value);
852
+ if (
853
+ value.kind === 'method-call' &&
854
+ (value.method === 'json' || value.method === 'text') &&
855
+ value.receiver && value.receiver.valueKind === 'fetch-response'
856
+ ) return true;
857
+ if (Array.isArray(value)) return value.some(visit);
858
+ return Object.values(value).some(visit);
859
+ }
860
+ return visit(plan.entry);
861
+ }
862
+
863
+ function requiredImportsForPlan(plan, bindings) {
864
+ const keys = new Set([
865
+ 'fastly_abi:init',
866
+ 'fastly_http_req:body_downstream_get',
867
+ 'fastly_http_req:method_get',
868
+ 'fastly_http_req:uri_get',
869
+ 'fastly_http_resp:new',
870
+ 'fastly_http_resp:status_set',
871
+ 'fastly_http_resp:send_downstream',
872
+ 'fastly_http_body:new',
873
+ 'fastly_http_body:write'
874
+ ]);
875
+ const kinds = new Set((plan.effects || []).map((effect) => effect.kind));
876
+ if (kinds.has('fetch') || kinds.has('grip.publish') || kinds.has('grip.broadcast')) {
877
+ for (const key of [
878
+ 'fastly_http_req:new', 'fastly_http_req:method_set', 'fastly_http_req:uri_set',
879
+ 'fastly_http_req:header_insert', 'fastly_http_req:send_async', 'fastly_http_req:pending_req_wait'
880
+ ]) keys.add(key);
881
+ }
882
+ if (planRequiresFetchBodyRead(plan)) keys.add('fastly_http_body:read');
883
+ if (kinds.has('config.get')) for (const key of ['fastly_config_store:open', 'fastly_config_store:get']) keys.add(key);
884
+ const gripAuthenticationRequired = kinds.has('grip.broadcast')
885
+ && (!bindings || Boolean(bindings.grip && bindings.grip.authentication));
886
+ const jwtSecretRequired = (plan.effects || []).some((effect) => (
887
+ effect.kind === 'jwt.verify'
888
+ && effect.resource
889
+ && effect.resource.keyType === 'secret'
890
+ ));
891
+ if (kinds.has('secret.get') || jwtSecretRequired || gripAuthenticationRequired) {
892
+ for (const key of ['fastly_secret_store:open', 'fastly_secret_store:get', 'fastly_secret_store:plaintext']) keys.add(key);
893
+ }
894
+ 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');
896
+ if (kinds.has('kv.get') || kinds.has('kv.put') || kinds.has('assets.lookup')) keys.add('fastly_kv_store:open');
897
+ 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
+ if (kinds.has('kv.put')) for (const key of ['fastly_kv_store:insert', 'fastly_kv_store:insert_wait']) keys.add(key);
899
+ if (kinds.has('grip.hold')) keys.add('fastly_http_resp:header_append');
900
+ if (plan.logging && plan.logging.enabledStatements > 0) {
901
+ keys.add('fastly_log:endpoint_get');
902
+ keys.add('fastly_log:write');
903
+ }
904
+ if (kinds.has('s3.head') || kinds.has('s3.getText') || kinds.has('s3.putText')) for (const key of require('./s3-native.js').S3_IMPORTS) keys.add(key);
905
+ return Object.freeze([...keys].sort());
906
+ }
907
+
908
+ function stripPulseHostImports(source) {
909
+ return String(source)
910
+ .split('\n')
911
+ .filter((line) => !line.startsWith('@external("pulse_host",'))
912
+ .join('\n');
913
+ }
914
+
915
+ function generateSchemaRuntime(plan) {
916
+ const registry = plan.schemas && plan.schemas.registry ? plan.schemas.registry : { schemas: [], maxBytes: FASTLY_NATIVE_PLATFORM_CAPABILITIES_BUFFER_BYTES, contentTypePolicy: 'accept-json-or-missing' };
917
+ const schemas = registry.schemas || [];
918
+ const nodeLines = [];
919
+ let nodeIndex = 0;
920
+
921
+ function emitNode(schemaIndex, node) {
922
+ const currentIndex = nodeIndex++;
923
+ const functionName = `__pulse_fastly_schema_${schemaIndex}_${currentIndex}`;
924
+ const child = node.kind === 'nullable'
925
+ ? emitNode(schemaIndex, node.value)
926
+ : node.kind === 'array'
927
+ ? emitNode(schemaIndex, node.element)
928
+ : undefined;
929
+ const fields = node.kind === 'object'
930
+ ? node.fields.map((field) => Object.freeze({ field, apply: emitNode(schemaIndex, field.value) }))
931
+ : [];
932
+ const body = [`function ${functionName}(valueHandle: i32): i32 {`, ' const input = __pulse_fastly_value(valueHandle)'];
933
+ if (node.kind === 'nullable') {
934
+ body.push(' if (input.kind == PULSE_VALUE_NULL) return valueHandle');
935
+ body.push(` return ${child}(valueHandle)`);
936
+ } else if (node.kind === 'array') {
937
+ body.push(' if (input.kind != PULSE_VALUE_ARRAY) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 52, -1); return 0 }');
938
+ body.push(' const output = host_value_array()');
939
+ body.push(' for (let index = 0; index < input.values.length; index += 1) {');
940
+ body.push(` const item = ${child}(unchecked(input.values[index]))`);
941
+ body.push(' if (item <= 0) return 0');
942
+ body.push(' host_value_array_push(output, item)');
943
+ body.push(' }');
944
+ body.push(' return output');
945
+ } else if (node.kind === 'object') {
946
+ body.push(' if (input.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 50, -1); return 0 }');
947
+ body.push(' const output = host_value_object()');
948
+ fields.forEach(({ field, apply }, fieldIndex) => {
949
+ body.push(` const key_${currentIndex}_${fieldIndex} = __pulse_fastly_string_value(${quote(field.name)})`);
950
+ body.push(` const field_${currentIndex}_${fieldIndex} = host_value_property(valueHandle, key_${currentIndex}_${fieldIndex})`);
951
+ body.push(` if (__pulse_fastly_value(field_${currentIndex}_${fieldIndex}).kind == PULSE_VALUE_UNDEFINED) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 51, -1); return 0 }`);
952
+ body.push(` const projected_${currentIndex}_${fieldIndex} = ${apply}(field_${currentIndex}_${fieldIndex})`);
953
+ body.push(` if (projected_${currentIndex}_${fieldIndex} <= 0) return 0`);
954
+ body.push(` host_value_object_set(output, key_${currentIndex}_${fieldIndex}, projected_${currentIndex}_${fieldIndex})`);
955
+ });
956
+ body.push(' return output');
957
+ } else if (node.kind === 'string') {
958
+ body.push(' if (input.kind != PULSE_VALUE_STRING) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 52, -1); return 0 }');
959
+ body.push(' return valueHandle');
960
+ } else if (node.kind === 'boolean') {
961
+ body.push(' if (input.kind != PULSE_VALUE_BOOLEAN) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 52, -1); return 0 }');
962
+ body.push(' return valueHandle');
963
+ } else if (node.kind === 'i32') {
964
+ 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 }');
965
+ body.push(' return valueHandle');
966
+ } else if (node.kind === 'u32') {
967
+ 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 }');
968
+ body.push(' return valueHandle');
969
+ } else if (node.kind === 'f64') {
970
+ body.push(' if (input.kind != PULSE_VALUE_NUMBER || !isFinite(input.number)) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 53, -1); return 0 }');
971
+ body.push(' return valueHandle');
972
+ } else if (node.kind === 'string-enum') {
973
+ const allowed = node.values.map((value) => `input.text == ${quote(value)}`).join(' || ') || 'false';
974
+ body.push(` if (input.kind != PULSE_VALUE_STRING || !(${allowed})) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 54, -1); return 0 }`);
975
+ body.push(' return valueHandle');
976
+ } else {
977
+ throw new TypeError(`Unsupported Fastly native schema node ${String(node.kind)}.`);
978
+ }
979
+ body.push('}', '');
980
+ nodeLines.push(...body);
981
+ return functionName;
982
+ }
983
+
984
+ const roots = schemas.map((schema, schemaIndex) => emitNode(schemaIndex, schema.root));
985
+ const lines = [
986
+ `const __PULSE_SCHEMA_MAX_BYTES: i32 = ${Number(registry.maxBytes || FASTLY_NATIVE_PLATFORM_CAPABILITIES_BUFFER_BYTES)}`,
987
+ `const __PULSE_SCHEMA_REQUIRE_JSON: bool = ${registry.contentTypePolicy === 'require-json' ? 'true' : 'false'}`,
988
+ '',
989
+ ...nodeLines,
990
+ 'function __pulse_fastly_schema_apply(schemaId: string, valueHandle: i32, encode: bool): i32 {',
991
+ ' if (schemaId.length == 0) return valueHandle'
992
+ ];
993
+ for (const [schemaIndex, schema] of schemas.entries()) {
994
+ lines.push(`${schemaIndex === 0 ? ' if' : ' else if'} (schemaId == ${quote(schema.id)}) {`);
995
+ lines.push(` const projected = ${roots[schemaIndex]}(valueHandle)`);
996
+ lines.push(' if (projected <= 0) return 0');
997
+ lines.push(' const input = __pulse_fastly_json(projected, 0)');
998
+ lines.push(` const normalized = encode ? __pulse_schema_encode_${schemaIndex}(input) : __pulse_schema_decode_${schemaIndex}(input)`);
999
+ lines.push(' return __pulse_fastly_parse_json(normalized)');
1000
+ lines.push(' }');
1001
+ }
1002
+ lines.push(' __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 55, -1)');
1003
+ lines.push(' return 0');
1004
+ lines.push('}');
1005
+ lines.push('');
1006
+ return lines.join('\n');
1007
+ }
1008
+
1009
+ function effectResultSource(plan, bindings) {
1010
+ const lines = ['function __pulse_fastly_effect_kind(effectIndex: i32): i32 {', ' switch (effectIndex) {'];
1011
+ for (const [index, effect] of (plan.effects || []).entries()) lines.push(` case ${index}: return ${FASTLY_NATIVE_PLATFORM_EFFECT_KIND[effect.kind]}`);
1012
+ lines.push(' default: return 0', ' }', '}', '');
1013
+
1014
+ lines.push('function __pulse_fastly_backend(effectIndex: i32): string {', ' switch (effectIndex) {');
1015
+ for (const binding of bindings.backends) lines.push(` case ${binding.index}: return ${quote(binding.backend)}`);
1016
+ lines.push(' default: return ""', ' }', '}', '');
1017
+
1018
+ lines.push(`function __pulse_fastly_config_store(effectIndex: i32): string { return ${quote(bindings.configStore)} }`, '');
1019
+ lines.push(`function __pulse_fastly_secret_store(effectIndex: i32): string { return ${quote(bindings.secretStore)} }`, '');
1020
+ lines.push('function __pulse_fastly_jwt_secret_binding(effectIndex: i32): string {', ' switch (effectIndex) {');
1021
+ for (const [index, effect] of (plan.effects || []).entries()) {
1022
+ if (effect.kind === 'jwt.verify' && effect.resource.keyType === 'secret') {
1023
+ lines.push(` case ${index}: return ${quote(effect.resource.secretBinding)}`);
1024
+ }
1025
+ }
1026
+ lines.push(' default: return ""', ' }', '}', '');
1027
+ lines.push('function __pulse_fastly_kv_store(effectIndex: i32): string {', ' switch (effectIndex) {');
1028
+ for (const binding of bindings.kv) lines.push(` case ${binding.index}: return ${quote(binding.physical)}`);
1029
+ lines.push(' default: return ""', ' }', '}', '');
1030
+ lines.push('function __pulse_fastly_grip_publish_url(effectIndex: i32): string {', ' switch (effectIndex) {');
1031
+ for (const binding of bindings.grip.publish) lines.push(` case ${binding.index}: return ${quote(binding.url)}`);
1032
+ lines.push(' default: return ""', ' }', '}', '');
1033
+ lines.push('function __pulse_fastly_grip_auth_ref(effectIndex: i32): string {', ' switch (effectIndex) {');
1034
+ for (const binding of bindings.grip.publish) lines.push(` case ${binding.index}: return ${quote(binding.authSecretRef || '')}`);
1035
+ lines.push(' default: return ""', ' }', '}', '');
1036
+
1037
+ lines.push('function __pulse_fastly_resolve_effect(effectIndex: i32): i32 {');
1038
+ lines.push(' switch (effectIndex) {');
1039
+ for (const [index, effect] of (plan.effects || []).entries()) {
1040
+ const result = effect.result || {};
1041
+ const decoder = result.decoder;
1042
+ const waiter = conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind) ? '__pulse_fastly_kv_conditional_wait' : ['s3.head', 's3.getText', 's3.putText'].includes(effect.kind) ? '__pulse_fastly_s3_wait' : effect.kind === 'fetch'
1043
+ ? '__pulse_fastly_wait_fetch'
1044
+ : effect.kind === 'grip.publish'
1045
+ ? '__pulse_fastly_wait_grip_publish'
1046
+ : effect.kind === 'grip.broadcast'
1047
+ ? '__pulse_fastly_wait_grip_broadcast'
1048
+ : effect.kind === 'assets.lookup'
1049
+ ? '__pulse_fastly_wait_assets'
1050
+ : effect.kind === 'kv.get'
1051
+ ? '__pulse_fastly_wait_kv_get'
1052
+ : effect.kind === 'kv.put'
1053
+ ? '__pulse_fastly_wait_kv_put'
1054
+ : '__pulse_fastly_wait_ready';
1055
+ lines.push(` case ${index}: {`);
1056
+ lines.push(` const response = ${waiter}(effectIndex)`);
1057
+ lines.push(' if (response <= 0) return 0');
1058
+ if (effect.kind === 'fetch' && (result.valueKind === 'json' || (decoder && decoder.kind === 'json' && result.valueKind !== 'fetch-response'))) {
1059
+ const args = (decoder && decoder.arguments) || [];
1060
+ const schemaId = args.length === 1 && args[0].kind === 'literal' && typeof args[0].value === 'string' ? args[0].value : '';
1061
+ lines.push(` return host_fetch_json(response, ${schemaId ? `__pulse_fastly_string_value(${quote(schemaId)})` : 'host_value_undefined()'})`);
1062
+ } else if (effect.kind === 'fetch' && (result.valueKind === 'text' || (decoder && decoder.kind === 'text'))) {
1063
+ lines.push(' return host_fetch_text(response)');
1064
+ } else {
1065
+ lines.push(' return response');
1066
+ }
1067
+ lines.push(' }');
1068
+ }
1069
+ lines.push(' default: __pulse_fastly_fail(PULSE_ERROR_STATE, 61, effectIndex); return 0');
1070
+ lines.push(' }');
1071
+ lines.push('}');
1072
+ lines.push('');
1073
+ return lines.join('\n');
1074
+ }
1075
+
1076
+ function effectDispatchSource(plan) {
1077
+ const handlerByKind = Object.freeze({
1078
+ fetch: '__pulse_fastly_fetch_begin',
1079
+ 'config.get': '__pulse_fastly_config_begin',
1080
+ 'secret.get': '__pulse_fastly_secret_begin',
1081
+ 'jwt.verify': '__pulse_fastly_jwt_begin',
1082
+ 's3.head': '__pulse_fastly_s3_begin',
1083
+ 's3.getText': '__pulse_fastly_s3_begin',
1084
+ 's3.putText': '__pulse_fastly_s3_begin',
1085
+ 'kv.get': '__pulse_fastly_kv_get_begin',
1086
+ 'kv.put': '__pulse_fastly_kv_put_begin',
1087
+ ...Object.fromEntries(conditionalKv.KV_CONDITIONAL_KINDS.map(kind => [kind, '__pulse_fastly_kv_conditional_begin'])),
1088
+ 'assets.lookup': '__pulse_fastly_assets_begin',
1089
+ 'grip.channel': '__pulse_fastly_grip_channel_begin',
1090
+ 'grip.hold': '__pulse_fastly_grip_hold_begin',
1091
+ 'grip.publish': '__pulse_fastly_grip_publish_begin',
1092
+ 'grip.broadcast': '__pulse_fastly_grip_publish_begin'
1093
+ });
1094
+ const kinds = [...new Set((plan.effects || []).map((effect) => effect.kind))];
1095
+ const lines = [
1096
+ 'function host_effect_begin(effectIndex: i32, payload: i32): void {',
1097
+ ' 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
+ ' const payloadValue = __pulse_fastly_value(payload)',
1099
+ ' if (payloadValue.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 47, effectIndex); return }',
1100
+ ' unchecked(__pulse_fastly_payloads[effectIndex] = payload)',
1101
+ ' const kind = __pulse_fastly_effect_kind(effectIndex)'
1102
+ ];
1103
+ const handlers = kinds
1104
+ .map((kind) => Object.freeze({ kind, handler: handlerByKind[kind] }))
1105
+ .filter((entry) => entry.handler);
1106
+ handlers.forEach((entry, index) => {
1107
+ lines.push(` ${index === 0 ? 'if' : 'else if'} (kind == ${FASTLY_NATIVE_PLATFORM_EFFECT_KIND[entry.kind]}) ${entry.handler}(effectIndex, payloadValue)`);
1108
+ });
1109
+ lines.push(handlers.length === 0
1110
+ ? ' __pulse_fastly_fail(PULSE_ERROR_UNSUPPORTED, 123, effectIndex)'
1111
+ : ' else __pulse_fastly_fail(PULSE_ERROR_UNSUPPORTED, 123, effectIndex)');
1112
+ lines.push('}');
1113
+ return lines.join('\n');
1114
+ }
1115
+
1116
+ function fastlyRuntimeSource(plan, bindings, options = {}) {
1117
+ const effectCount = (plan.effects || []).length;
1118
+ const jwtCrypto = options.jwtCrypto || selectedJwtCrypto(plan);
1119
+ const es256KeyRecords = options.es256KeyRecords || Object.freeze([]);
1120
+ const jwtReality = options.jwtReality && options.jwtReality.enabled === true
1121
+ ? options.jwtReality
1122
+ : undefined;
1123
+ const jwtCaseSource = jwtReality
1124
+ ? '__pulse_fastly_request_header_text("x-pulse-e2-case")'
1125
+ : '""';
1126
+ const jwtWrongSecretBinding = jwtReality && String(jwtReality.wrongSecretBinding || '').trim();
1127
+ const jwtShortSecretBinding = jwtReality && String(jwtReality.shortSecretBinding || '').trim();
1128
+ const jwtClockOverride = jwtReality && Number.isFinite(Number(jwtReality.clockUnixSeconds))
1129
+ ? `${Number(jwtReality.clockUnixSeconds)}.0`
1130
+ : '';
1131
+ const jwtBindingOverrides = [
1132
+ jwtWrongSecretBinding ? `if (caseId == "wrong-key") return ${quote(jwtWrongSecretBinding)};` : '',
1133
+ jwtShortSecretBinding ? `if (caseId == "undersized-secret") return ${quote(jwtShortSecretBinding)};` : ''
1134
+ ].filter(Boolean).join('; ');
1135
+ const jwtEvidenceSource = jwtReality
1136
+ ? String.raw`
1137
+ function __pulse_fastly_jwt_error_name(): string {
1138
+ if (__pulse_fastly_jwt_error == 0) return ""
1139
+ if (__pulse_fastly_jwt_error == 1) return "PULSE_JWT_TOKEN_REQUIRED"
1140
+ if (__pulse_fastly_jwt_error == 2) return "PULSE_JWT_BEARER_INVALID"
1141
+ if (__pulse_fastly_jwt_error == 3) return "PULSE_JWT_MALFORMED"
1142
+ if (__pulse_fastly_jwt_error == 4) return "PULSE_JWT_LIMIT_EXCEEDED"
1143
+ if (__pulse_fastly_jwt_error == 5) return "PULSE_JWT_ALGORITHM_NOT_ALLOWED"
1144
+ if (__pulse_fastly_jwt_error == 6) return "PULSE_JWT_KEY_INVALID"
1145
+ if (__pulse_fastly_jwt_error == 7) return "PULSE_JWT_SIGNATURE_INVALID"
1146
+ if (__pulse_fastly_jwt_error == 8) return "PULSE_JWT_CLOCK_INVALID"
1147
+ if (__pulse_fastly_jwt_error == 9) return "PULSE_JWT_CLAIMS_INVALID"
1148
+ if (__pulse_fastly_jwt_error == 10) return "PULSE_JWT_CLAIMS_SCHEMA_INVALID"
1149
+ if (__pulse_fastly_jwt_error == 11) return "PULSE_JWT_OPERATION_FAILED"
1150
+ return "PULSE_RUNTIME_FAILED"
1151
+ }
1152
+ function __pulse_fastly_jwt_evidence_headers(output: __PulseFastlyValue): void {
1153
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-status", __pulse_fastly_jwt_error == 0 ? "success" : "error"))
1154
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-code", __pulse_fastly_jwt_error_name()))
1155
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-category", __pulse_fastly_jwt_error == 11 ? "crypto-realization" : ""))
1156
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-case", __pulse_fastly_jwt_case_id()))
1157
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-secret-calls", __pulse_fastly_jwt_secret_calls.toString()))
1158
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-crypto-calls", __pulse_fastly_jwt_crypto_calls.toString()))
1159
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-clock-calls", __pulse_fastly_jwt_clock_calls.toString()))
1160
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-schema-calls", __pulse_fastly_jwt_schema_calls.toString()))
1161
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-claims-parsed", __pulse_fastly_jwt_claims_parsed.toString()))
1162
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-verified", __pulse_fastly_jwt_verified.toString()))
1163
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-order", __pulse_fastly_jwt_event_order))
1164
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-signing-bytes", __pulse_fastly_jwt_signing_input_bytes.toString()))
1165
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-signing-sha256", __pulse_fastly_jwt_signing_input_sha256))
1166
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-realization", ${quote(jwtCrypto && jwtCrypto.realization || "")}))
1167
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-implementation", ${quote(jwtCrypto && jwtCrypto.implementation || "")}))
1168
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-fallback", "false"))
1169
+ output.headers.push(new __PulseFastlyHeader("x-pulse-e2-realization-attempts", __pulse_fastly_jwt_crypto_calls.toString()))
1170
+ }
1171
+ function __pulse_fastly_jwt_attach_evidence(handle: i32): void {
1172
+ const value = __pulse_fastly_value(handle)
1173
+ if (value.kind == PULSE_VALUE_RESPONSE) __pulse_fastly_jwt_evidence_headers(value)
1174
+ }
1175
+ function __pulse_fastly_jwt_send_error(): void {
1176
+ const output = new __PulseFastlyValue()
1177
+ output.kind = PULSE_VALUE_RESPONSE
1178
+ output.status = 400
1179
+ output.text = ""
1180
+ output.headers.push(new __PulseFastlyHeader("content-type", "text/plain; charset=utf-8"))
1181
+ __pulse_fastly_jwt_evidence_headers(output)
1182
+ __pulse_fastly_send_result(__pulse_fastly_put(output))
1183
+ }
1184
+ `
1185
+ : String.raw`
1186
+ function __pulse_fastly_jwt_attach_evidence(handle: i32): void { void handle }
1187
+ function __pulse_fastly_jwt_send_error(): void {}
1188
+ `;
1189
+ const gripAuthentication = bindings.grip && bindings.grip.authentication;
1190
+ const gripSecretSource = gripAuthentication
1191
+ ? 'function __pulse_fastly_grip_secret(effectIndex: i32, name: string): string { const store = __pulse_fastly_open_secret_store(effectIndex); if (__pulse_fastly_last_error != 0) return ""; const keyBytes = __pulse_fastly_utf8(name); const secretOut = __pulse_fastly_out_i32(); let status = fastly_secret_store_get(store, changetype<usize>(keyBytes), keyBytes.byteLength, changetype<usize>(secretOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 140, effectIndex); return "" } const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES); const written = __pulse_fastly_out_i32(); status = fastly_secret_store_plaintext(__pulse_fastly_out_value(secretOut), buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(written)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 141, effectIndex); return "" } return __pulse_fastly_remember_secret(__pulse_fastly_decode(buffer, __pulse_fastly_out_value(written))) }'
1192
+ : '';
1193
+ const gripAuthorizationSource = gripAuthentication
1194
+ ? `const secret = __pulse_fastly_grip_secret(effectIndex, ${quote(gripAuthentication.secretRef)}); if (__pulse_fastly_last_error != 0) return; headers.keys.push("authorization"); headers.values.push(__pulse_fastly_string_value("Bearer " + secret));`
1195
+ : '';
1196
+ return String.raw`
1197
+ @external("fastly_abi", "init") declare function fastly_abi_init(version: i64): i32
1198
+ @external("fastly_http_req", "body_downstream_get") declare function fastly_http_req_body_downstream_get(requestOut: usize, bodyOut: usize): i32
1199
+ @external("fastly_http_req", "method_get") declare function fastly_http_req_method_get(handle: i32, buffer: usize, bufferLength: i32, writtenOut: usize): i32
1200
+ @external("fastly_http_req", "uri_get") declare function fastly_http_req_uri_get(handle: i32, buffer: usize, bufferLength: i32, writtenOut: usize): i32
1201
+ @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
1202
+ @external("fastly_http_req", "new") declare function fastly_http_req_new(handleOut: usize): i32
1203
+ @external("fastly_http_req", "method_set") declare function fastly_http_req_method_set(handle: i32, method: usize, methodLength: i32): i32
1204
+ @external("fastly_http_req", "uri_set") declare function fastly_http_req_uri_set(handle: i32, uri: usize, uriLength: i32): i32
1205
+ @external("fastly_http_req", "header_insert") declare function fastly_http_req_header_insert(handle: i32, name: usize, nameLength: i32, value: usize, valueLength: i32): i32
1206
+ @external("fastly_http_req", "send_async") declare function fastly_http_req_send_async(handle: i32, body: i32, backend: usize, backendLength: i32, pendingOut: usize): i32
1207
+ @external("fastly_http_req", "pending_req_wait") declare function fastly_http_req_pending_req_wait(handle: i32, responseOut: usize, bodyOut: usize): i32
1208
+ @external("fastly_http_resp", "new") declare function fastly_http_resp_new(handleOut: usize): i32
1209
+ @external("fastly_http_resp", "header_append") declare function fastly_http_resp_header_append(handle: i32, name: usize, nameLength: i32, value: usize, valueLength: i32): i32
1210
+ @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
1211
+ @external("fastly_http_resp", "status_get") declare function fastly_http_resp_status_get(handle: i32, statusOut: usize): i32
1212
+ @external("fastly_http_resp", "status_set") declare function fastly_http_resp_status_set(handle: i32, status: i32): i32
1213
+ @external("fastly_http_resp", "send_downstream") declare function fastly_http_resp_send_downstream(handle: i32, body: i32, streaming: i32): i32
1214
+ @external("fastly_http_body", "new") declare function fastly_http_body_new(handleOut: usize): i32
1215
+ @external("fastly_http_body", "read") declare function fastly_http_body_read(handle: i32, buffer: usize, bufferLength: i32, readOut: usize): i32
1216
+ @external("fastly_http_body", "write") declare function fastly_http_body_write(handle: i32, buffer: usize, bufferLength: i32, end: i32, writtenOut: usize): i32
1217
+ @external("fastly_config_store", "open") declare function fastly_config_store_open(name: usize, nameLength: i32, handleOut: usize): i32
1218
+ @external("fastly_config_store", "get") declare function fastly_config_store_get(handle: i32, key: usize, keyLength: i32, value: usize, valueLength: i32, writtenOut: usize): i32
1219
+ @external("fastly_secret_store", "open") declare function fastly_secret_store_open(name: usize, nameLength: i32, handleOut: usize): i32
1220
+ @external("fastly_secret_store", "get") declare function fastly_secret_store_get(handle: i32, key: usize, keyLength: i32, secretOut: usize): i32
1221
+ @external("fastly_secret_store", "plaintext") declare function fastly_secret_store_plaintext(secret: i32, value: usize, valueLength: i32, writtenOut: usize): i32
1222
+ @external("fastly_kv_store", "open") declare function fastly_kv_store_open(name: usize, nameLength: i32, handleOut: usize): i32
1223
+ @external("fastly_kv_store", "lookup") declare function fastly_kv_store_lookup(store: i32, key: usize, keyLength: i32, configMask: i32, config: usize, lookupOut: usize): i32
1224
+ @external("fastly_kv_store", "lookup_wait_v2") declare function fastly_kv_store_lookup_wait_v2(handle: i32, bodyOut: usize, metadata: usize, metadataLength: i32, writtenOut: usize, generationOut: usize, kvErrorOut: usize): i32
1225
+ @external("fastly_kv_store", "insert") declare function fastly_kv_store_insert(store: i32, key: usize, keyLength: i32, body: i32, configMask: i32, config: usize, insertOut: usize): i32
1226
+ @external("fastly_kv_store", "insert_wait") declare function fastly_kv_store_insert_wait(handle: i32, kvErrorOut: usize): i32
1227
+ @external("fastly_log", "endpoint_get") declare function fastly_log_endpoint_get(name: usize, nameLength: i32, handleOut: usize): i32
1228
+ @external("fastly_log", "write") declare function fastly_log_write(handle: i32, message: usize, messageLength: i32, writtenOut: usize): i32
1229
+ @external("wasi_snapshot_preview1", "clock_time_get") declare function wasi_snapshot_preview1_clock_time_get(clockId: i32, precision: i64, timeOut: usize): i32
1230
+
1231
+ const PULSE_FASTLY_EFFECTS_ABI_VERSION: i64 = ${FASTLY_NATIVE_PLATFORM_CAPABILITIES_ABI_VERSION}
1232
+ const PULSE_FASTLY_BUFFER_BYTES: i32 = ${FASTLY_NATIVE_PLATFORM_CAPABILITIES_BUFFER_BYTES}
1233
+ const PULSE_FASTLY_EFFECT_COUNT: i32 = ${effectCount}
1234
+ const PULSE_EFFECT_FETCH: i32 = 1
1235
+ const PULSE_EFFECT_CONFIG_GET: i32 = 2
1236
+ const PULSE_EFFECT_SECRET_GET: i32 = 3
1237
+ const PULSE_EFFECT_KV_GET: i32 = 4
1238
+ const PULSE_EFFECT_KV_PUT: i32 = 5
1239
+ const PULSE_EFFECT_GRIP_CHANNEL: i32 = 6
1240
+ const PULSE_EFFECT_GRIP_HOLD: i32 = 7
1241
+ const PULSE_EFFECT_GRIP_PUBLISH: i32 = 8
1242
+ const PULSE_EFFECT_ASSETS_LOOKUP: i32 = 10
1243
+ const PULSE_EFFECT_JWT_VERIFY: i32 = 11
1244
+ const FASTLY_STATUS_OK: i32 = 0
1245
+ const FASTLY_STATUS_BUFLEN: i32 = 4
1246
+ const FASTLY_STATUS_NONE: i32 = 10
1247
+ const PULSE_VALUE_UNDEFINED: i32 = 0
1248
+ const PULSE_VALUE_NULL: i32 = 1
1249
+ const PULSE_VALUE_BOOLEAN: i32 = 2
1250
+ const PULSE_VALUE_NUMBER: i32 = 3
1251
+ const PULSE_VALUE_STRING: i32 = 4
1252
+ const PULSE_VALUE_ARRAY: i32 = 5
1253
+ const PULSE_VALUE_OBJECT: i32 = 6
1254
+ const PULSE_VALUE_FETCH: i32 = 7
1255
+ const PULSE_VALUE_RESPONSE: i32 = 8
1256
+ const PULSE_ERROR_NONE: i32 = 0
1257
+ const PULSE_ERROR_VALUE: i32 = 1001
1258
+ const PULSE_ERROR_UNSUPPORTED: i32 = 1002
1259
+ const PULSE_ERROR_HOSTCALL: i32 = 1003
1260
+ const PULSE_ERROR_JSON: i32 = 1004
1261
+ const PULSE_ERROR_SCHEMA: i32 = 1005
1262
+ const PULSE_ERROR_TRANSPORT: i32 = 1006
1263
+ const PULSE_ERROR_STATE: i32 = 1007
1264
+ const PULSE_ERROR_JWT: i32 = 1008
1265
+
1266
+ class __PulseFastlyValue {
1267
+ kind: i32 = PULSE_VALUE_UNDEFINED
1268
+ boolean: i32 = 0
1269
+ number: f64 = 0.0
1270
+ text: string = ""
1271
+ keys: Array<string> = new Array<string>()
1272
+ values: Array<i32> = new Array<i32>()
1273
+ responseHandle: i32 = 0
1274
+ bodyHandle: i32 = 0
1275
+ bodyLoaded: i32 = 0
1276
+ status: i32 = 200
1277
+ headers: Array<__PulseFastlyHeader> = new Array<__PulseFastlyHeader>()
1278
+ immutable: bool = false
1279
+ }
1280
+ class __PulseFastlyHeader {
1281
+ constructor(public name: string, public value: string) {}
1282
+ }
1283
+ class __PulseJsonParser {
1284
+ source: string
1285
+ index: i32 = 0
1286
+ failed: bool = false
1287
+ tooLarge: bool = false
1288
+ entries: i32 = 0
1289
+ constructor(source: string, public conditionalKv: bool = false) { this.source = source }
1290
+ 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 } }
1291
+ 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 }
1292
+ value(depth: i32): i32 {
1293
+ this.skip(); if (this.conditionalKv && (depth > ${conditionalKv.KV_CONDITIONAL_LIMITS.depth + 1} || ++this.entries > ${conditionalKv.KV_CONDITIONAL_LIMITS.entries + 2})) { this.failed = true; this.tooLarge = true; return 0 }
1294
+ if (this.index >= this.source.length || (!this.conditionalKv && depth > ${plan.effects.some(effect => conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind)) ? 128 : 64})) { this.failed = true; return 0 }
1295
+ const c = this.source.charCodeAt(this.index)
1296
+ if (c == 34) return __pulse_fastly_string_value(this.string())
1297
+ if (c == 123) return this.object(depth + 1)
1298
+ if (c == 91) return this.array(depth + 1)
1299
+ if (this.source.substr(this.index, 4) == "true") { this.index += 4; return host_value_boolean(1) }
1300
+ if (this.source.substr(this.index, 5) == "false") { this.index += 5; return host_value_boolean(0) }
1301
+ if (this.source.substr(this.index, 4) == "null") { this.index += 4; return host_value_null() }
1302
+ if (c == 45 || (c >= 48 && c <= 57)) return this.numberValue()
1303
+ this.failed = true; return 0
1304
+ }
1305
+ string(): string {
1306
+ // Find a bounded span, then decode each UTF-16 unit once. Concatenating one
1307
+ // character at a time exhausts stub/fixed memory on a valid maximum KV value.
1308
+ const start = this.index + 1; let end = start;
1309
+ while (end < this.source.length) {
1310
+ const c = this.source.charCodeAt(end);
1311
+ if (c == 34) break;
1312
+ if (c == 92) end += 1;
1313
+ end += 1;
1314
+ }
1315
+ if (end >= this.source.length) { this.failed = true; return "" }
1316
+ const output = new Uint16Array(end - start); let count = 0; this.index = start;
1317
+ while (this.index < end) {
1318
+ let c = this.source.charCodeAt(this.index++);
1319
+ if (c == 92) {
1320
+ if (this.index >= end) { this.failed = true; return "" }
1321
+ c = this.source.charCodeAt(this.index++);
1322
+ if (c == 34 || c == 92 || c == 47) {}
1323
+ else if (c == 98) c = 8;
1324
+ else if (c == 102) c = 12;
1325
+ else if (c == 110) c = 10;
1326
+ else if (c == 114) c = 13;
1327
+ else if (c == 116) c = 9;
1328
+ else if (c == 117) {
1329
+ if (this.index + 4 > end) { this.failed = true; return "" }
1330
+ c = 0;
1331
+ for (let i = 0; i < 4; i++) {
1332
+ const d = this.source.charCodeAt(this.index++);
1333
+ const digit = d >= 48 && d <= 57 ? d - 48 : d >= 65 && d <= 70 ? d - 55 : d >= 97 && d <= 102 ? d - 87 : -1;
1334
+ if (digit < 0) { this.failed = true; return "" }
1335
+ c = (c << 4) | digit;
1336
+ }
1337
+ } else { this.failed = true; return "" }
1338
+ } else if (c < 32) { this.failed = true; return "" }
1339
+ output[count++] = u16(c);
1340
+ }
1341
+ this.index = end + 1;
1342
+ return String.UTF16.decodeUnsafe(output.dataStart, count * 2);
1343
+ }
1344
+ numberValue(): i32 {
1345
+ const start = this.index
1346
+ if (this.source.charCodeAt(this.index) == 45) { this.index += 1; if (this.index >= this.source.length) { this.failed = true; return 0 } }
1347
+ let c = this.source.charCodeAt(this.index)
1348
+ if (c == 48) {
1349
+ this.index += 1
1350
+ if (this.index < this.source.length) { c = this.source.charCodeAt(this.index); if (c >= 48 && c <= 57) { this.failed = true; return 0 } }
1351
+ } else if (c >= 49 && c <= 57) {
1352
+ this.index += 1
1353
+ while (this.index < this.source.length) { c = this.source.charCodeAt(this.index); if (c < 48 || c > 57) break; this.index += 1 }
1354
+ } else { this.failed = true; return 0 }
1355
+ if (this.index < this.source.length && this.source.charCodeAt(this.index) == 46) {
1356
+ this.index += 1
1357
+ if (this.index >= this.source.length) { this.failed = true; return 0 }
1358
+ c = this.source.charCodeAt(this.index); if (c < 48 || c > 57) { this.failed = true; return 0 }
1359
+ while (this.index < this.source.length) { c = this.source.charCodeAt(this.index); if (c < 48 || c > 57) break; this.index += 1 }
1360
+ }
1361
+ if (this.index < this.source.length) {
1362
+ c = this.source.charCodeAt(this.index)
1363
+ if (c == 69 || c == 101) {
1364
+ this.index += 1
1365
+ if (this.index < this.source.length) { c = this.source.charCodeAt(this.index); if (c == 43 || c == 45) this.index += 1 }
1366
+ if (this.index >= this.source.length) { this.failed = true; return 0 }
1367
+ c = this.source.charCodeAt(this.index); if (c < 48 || c > 57) { this.failed = true; return 0 }
1368
+ while (this.index < this.source.length) { c = this.source.charCodeAt(this.index); if (c < 48 || c > 57) break; this.index += 1 }
1369
+ }
1370
+ }
1371
+ return host_value_number(F64.parseFloat(this.source.substring(start, this.index)))
1372
+ }
1373
+ array(depth: i32): i32 {
1374
+ const output = host_value_array(); this.index += 1; this.skip()
1375
+ if (this.index < this.source.length && this.source.charCodeAt(this.index) == 93) { this.index += 1; return output }
1376
+ while (!this.failed) {
1377
+ host_value_array_push(output, this.value(depth)); this.skip()
1378
+ if (this.index >= this.source.length) { this.failed = true; break }
1379
+ const c = this.source.charCodeAt(this.index); this.index += 1
1380
+ if (c == 93) break
1381
+ if (c != 44) { this.failed = true; break }
1382
+ }
1383
+ return output
1384
+ }
1385
+ object(depth: i32): i32 {
1386
+ const output = host_value_object(); this.index += 1; this.skip()
1387
+ if (this.index < this.source.length && this.source.charCodeAt(this.index) == 125) { this.index += 1; return output }
1388
+ while (!this.failed) {
1389
+ this.skip(); if (this.index >= this.source.length || this.source.charCodeAt(this.index) != 34) { this.failed = true; break }
1390
+ const key = this.string(); this.skip()
1391
+ if (this.conditionalKv && __pulse_fastly_find(__pulse_fastly_value(output), key) >= 0) { this.failed = true; break }
1392
+ if (this.index >= this.source.length || this.source.charCodeAt(this.index) != 58) { this.failed = true; break }
1393
+ this.index += 1; host_value_object_set(output, __pulse_fastly_string_value(key), this.value(depth)); this.skip()
1394
+ if (this.index >= this.source.length) { this.failed = true; break }
1395
+ const c = this.source.charCodeAt(this.index); this.index += 1
1396
+ if (c == 125) break
1397
+ if (c != 44) { this.failed = true; break }
1398
+ }
1399
+ return output
1400
+ }
1401
+ }
1402
+
1403
+ const PULSE_FASTLY_PENDING_NONE: i32 = 0
1404
+ const PULSE_FASTLY_PENDING_ASYNC: i32 = 1
1405
+ const PULSE_FASTLY_PENDING_READY: i32 = 2
1406
+ @lazy const __pulse_fastly_values = new Array<__PulseFastlyValue>()
1407
+ @lazy const __pulse_fastly_pending = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
1408
+ @lazy const __pulse_fastly_pending_mode = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
1409
+ @lazy const __pulse_fastly_payloads = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
1410
+ @lazy const __pulse_fastly_ready = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
1411
+ @lazy const __pulse_fastly_grip_channels = new Array<string>()
1412
+ @lazy const __pulse_fastly_redactions = new Array<string>()
1413
+ let __pulse_fastly_request_handle: i32 = 0
1414
+ let __pulse_fastly_request_body_handle: i32 = 0
1415
+ let __pulse_fastly_request_method: string = ""
1416
+ let __pulse_fastly_request_url: string = ""
1417
+ let __pulse_fastly_request_path: string = ""
1418
+ let __pulse_fastly_request_body: string = ""
1419
+ let __pulse_fastly_request_body_loaded: i32 = 0
1420
+ let __pulse_fastly_last_error: i32 = 0
1421
+ let __pulse_fastly_error_stage: i32 = 0
1422
+ let __pulse_fastly_error_effect: i32 = -1
1423
+ let __pulse_fastly_log_handle: i32 = -1
1424
+ let __pulse_fastly_jwt_error: i32 = 0
1425
+ let __pulse_fastly_jwt_secret_calls: i32 = 0
1426
+ let __pulse_fastly_jwt_crypto_calls: i32 = 0
1427
+ let __pulse_fastly_jwt_clock_calls: i32 = 0
1428
+ let __pulse_fastly_jwt_schema_calls: i32 = 0
1429
+ let __pulse_fastly_jwt_claims_parsed: i32 = 0
1430
+ let __pulse_fastly_jwt_verified: i32 = 0
1431
+ let __pulse_fastly_jwt_signing_input_bytes: i32 = 0
1432
+ let __pulse_fastly_jwt_signing_input_sha256: string = ""
1433
+ let __pulse_fastly_jwt_event_order: string = ""
1434
+
1435
+ 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 } }
1436
+ function __pulse_fastly_out_i32(): StaticArray<i32> { return new StaticArray<i32>(1) }
1437
+ function __pulse_fastly_out_value(out: StaticArray<i32>): i32 { return load<i32>(changetype<usize>(out)) }
1438
+ function __pulse_fastly_utf8(value: string): ArrayBuffer { return String.UTF8.encode(value, false) }
1439
+ function __pulse_fastly_decode(buffer: Uint8Array, length: i32): string { return String.UTF8.decodeUnsafe(buffer.dataStart, length, false) }
1440
+ function __pulse_fastly_put(value: __PulseFastlyValue): i32 { __pulse_fastly_values.push(value); return __pulse_fastly_values.length }
1441
+ 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]) }
1442
+ 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 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_STRING; item.text = value; return __pulse_fastly_put(item) }
1444
+ 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
+ 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
+ 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) }
1447
+ function __pulse_fastly_remember_secret(value: string): string { if (value.length == 0) return value; for (let i = 0; i < __pulse_fastly_redactions.length; i += 1) if (unchecked(__pulse_fastly_redactions[i]) == value) return value; __pulse_fastly_redactions.push(value); return value }
1448
+ function __pulse_fastly_replace_secret(input: string, secret: string): string { if (secret.length == 0) return input; let source = input; let output = ""; while (true) { const index = source.indexOf(secret); if (index < 0) return output + source; output += source.substring(0, index) + "<redacted>"; source = source.substring(index + secret.length) } }
1449
+ function __pulse_fastly_redact(input: string): string { let output = input; for (let i = 0; i < __pulse_fastly_redactions.length; i += 1) output = __pulse_fastly_replace_secret(output, unchecked(__pulse_fastly_redactions[i])); return output }
1450
+ function host_log(level: i32, messageHandle: i32): void { let endpoint = __pulse_fastly_log_handle; if (endpoint == -2) return; if (endpoint == -1) { const name = __pulse_fastly_utf8("stdout"); const out = __pulse_fastly_out_i32(); if (fastly_log_endpoint_get(changetype<usize>(name), name.byteLength, changetype<usize>(out)) != FASTLY_STATUS_OK) { __pulse_fastly_log_handle = -2; return } endpoint = __pulse_fastly_out_value(out); __pulse_fastly_log_handle = endpoint } let label = "unknown"; if (level == 1) label = "error"; else if (level == 2) label = "warn"; else if (level == 3) label = "info"; else if (level == 4) label = "debug"; const bytes = __pulse_fastly_utf8("[pulse:" + label + "] " + __pulse_fastly_redact(__pulse_fastly_string(messageHandle)) + "\n"); const written = __pulse_fastly_out_i32(); fastly_log_write(endpoint, changetype<usize>(bytes), bytes.byteLength, changetype<usize>(written)) }
1451
+ 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 }
1452
+ function __pulse_fastly_hex(value: i32): string { return String.fromCharCode(value < 10 ? 48 + value : 87 + value) }
1453
+ function __pulse_fastly_is_unpaired(value: string, i: i32): bool {
1454
+ const c = value.charCodeAt(i);
1455
+ if (c >= 0xd800 && c <= 0xdbff) return i + 1 >= value.length || value.charCodeAt(i + 1) < 0xdc00 || value.charCodeAt(i + 1) > 0xdfff;
1456
+ if (c >= 0xdc00 && c <= 0xdfff) return i == 0 || value.charCodeAt(i - 1) < 0xd800 || value.charCodeAt(i - 1) > 0xdbff;
1457
+ return false;
1458
+ }
1459
+ function __pulse_fastly_quote(value: string): string {
1460
+ // Count once and write UTF-16 units once. Repeated concatenation can allocate
1461
+ // gigabytes for a valid bounded string when every byte needs JSON escaping.
1462
+ let size = 2;
1463
+ for (let i = 0; i < value.length; i++) {
1464
+ const c = value.charCodeAt(i);
1465
+ size += c == 34 || c == 92 || c == 8 || c == 9 || c == 10 || c == 12 || c == 13 ? 2 : (c < 32 || __pulse_fastly_is_unpaired(value, i)) ? 6 : 1;
1466
+ }
1467
+ const out = new Uint16Array(size); let cursor = 0; out[cursor++] = 34;
1468
+ for (let i = 0; i < value.length; i++) {
1469
+ const c = value.charCodeAt(i);
1470
+ if (c == 34 || c == 92) { out[cursor++] = 92; out[cursor++] = u16(c); }
1471
+ else if (c == 8 || c == 9 || c == 10 || c == 12 || c == 13) {
1472
+ out[cursor++] = 92; out[cursor++] = c == 8 ? 98 : c == 9 ? 116 : c == 10 ? 110 : c == 12 ? 102 : 114;
1473
+ } else if (c < 32 || __pulse_fastly_is_unpaired(value, i)) {
1474
+ out[cursor++] = 92; out[cursor++] = 117;
1475
+ out[cursor++] = u16('0123456789abcdef'.charCodeAt((c >> 12) & 15)); out[cursor++] = u16('0123456789abcdef'.charCodeAt((c >> 8) & 15));
1476
+ out[cursor++] = u16('0123456789abcdef'.charCodeAt((c >> 4) & 15)); out[cursor++] = u16('0123456789abcdef'.charCodeAt(c & 15));
1477
+ } else out[cursor++] = u16(c);
1478
+ }
1479
+ out[cursor] = 34;
1480
+ return String.UTF16.decodeUnsafe(out.dataStart, out.byteLength);
1481
+ }
1482
+ function __pulse_fastly_json(handle: i32, depth: i32): string {
1483
+ if (depth > ${plan.effects.some(effect => conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind)) ? 128 : 64}) { __pulse_fastly_fail(PULSE_ERROR_JSON, 2, -1); return "null" }
1484
+ const value = __pulse_fastly_value(handle)
1485
+ if (value.kind == PULSE_VALUE_UNDEFINED || value.kind == PULSE_VALUE_NULL) return "null"
1486
+ if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean != 0 ? "true" : "false"
1487
+ if (value.kind == PULSE_VALUE_NUMBER) return __pulse_fastly_number_string(value.number)
1488
+ if (value.kind == PULSE_VALUE_STRING) return __pulse_fastly_quote(value.text)
1489
+ 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 + "]" }
1490
+ 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 + "}" }
1491
+ return "null"
1492
+ }
1493
+ 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
+ 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
+ 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 {
1497
+ const chunks = new Array<Uint8Array>(); let total = 0;
1498
+ while (true) {
1499
+ const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES), read = __pulse_fastly_out_i32();
1500
+ const status = fastly_http_body_read(handle, buffer.dataStart, buffer.length, changetype<usize>(read));
1501
+ if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 20, effectIndex); return "" }
1502
+ const count = __pulse_fastly_out_value(read);
1503
+ if (count < 0 || count > buffer.length) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 20, effectIndex); return "" }
1504
+ if (!count) break;
1505
+ total += count;
1506
+ if (total > __PULSE_SCHEMA_MAX_BYTES && __PULSE_SCHEMA_MAX_BYTES > 0) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 21, effectIndex); return "" }
1507
+ chunks.push(buffer.subarray(0, count));
1508
+ }
1509
+ // UTF-8 scalars may straddle host read chunks. Decode the bounded body once.
1510
+ const bytes = new Uint8Array(total); let offset = 0;
1511
+ for (let i = 0; i < chunks.length; i++) { bytes.set(chunks[i], offset); offset += chunks[i].length; }
1512
+ return __pulse_fastly_decode(bytes, total);
1513
+ }
1514
+ 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
+ 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
+ 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
+
1518
+ function host_value_undefined(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_UNDEFINED; return __pulse_fastly_put(item) }
1519
+ function host_value_null(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_NULL; return __pulse_fastly_put(item) }
1520
+ 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) }
1521
+ function host_value_number(value: f64): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_NUMBER; item.number = value; return __pulse_fastly_put(item) }
1522
+ function host_value_string(pointer: i32, length: i32): i32 { return __pulse_fastly_string_value(changetype<string>(pointer)) }
1523
+ function host_value_array(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_ARRAY; return __pulse_fastly_put(item) }
1524
+ 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
+ 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
+ function host_value_object(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_OBJECT; return __pulse_fastly_put(item) }
1527
+ 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
+ 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.text.length : item.values.length); return host_value_undefined() }
1530
+ 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) }
1532
+ 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.text.length > 0 ? 1 : 0; return 1 }
1534
+ 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 __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 }
1536
+ 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
+
1538
+ function host_request_method(): i32 { return __pulse_fastly_string_value(__pulse_fastly_request_method) }
1539
+ function host_request_url(): i32 { return __pulse_fastly_string_value(__pulse_fastly_request_url) }
1540
+ 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("/") }
1541
+ 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 }
1542
+ 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 }
1543
+ 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
+ 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
+ function host_request_path(): i32 { return __pulse_fastly_string_value(__pulse_fastly_request_path) }
1546
+ function host_request_headers(): i32 { return host_value_object() }
1547
+ 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) }
1549
+ 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
+ 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
+ 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
+ function host_response_json(value: i32, options: i32): i32 { return __pulse_fastly_response(value, options, true) }
1553
+ function host_response_text(value: i32, options: i32): i32 { return __pulse_fastly_response(value, options, false) }
1554
+ 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
+ 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 }
1556
+ 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 }
1557
+ 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) }
1558
+ 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 }
1559
+ 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 }
1560
+ function host_kv_namespace(name: i32): i32 { return name }
1561
+ 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)) }
1562
+ 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 }
1563
+ 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) }
1564
+ function __pulse_fastly_payload_field(payload: __PulseFastlyValue, name: string): i32 { const index = __pulse_fastly_find(payload, name); return index < 0 ? host_value_undefined() : unchecked(payload.values[index]) }
1565
+ function __pulse_fastly_ready_effect(effectIndex: i32, handle: i32): void { unchecked(__pulse_fastly_ready[effectIndex] = handle); unchecked(__pulse_fastly_pending_mode[effectIndex] = PULSE_FASTLY_PENDING_READY) }
1566
+ function __pulse_fastly_open_config_store(effectIndex: i32): i32 { const nameBytes = __pulse_fastly_utf8(__pulse_fastly_config_store(effectIndex)); const out = __pulse_fastly_out_i32(); const status = fastly_config_store_open(changetype<usize>(nameBytes), nameBytes.byteLength, changetype<usize>(out)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 110, effectIndex); return 0 } return __pulse_fastly_out_value(out) }
1567
+ function __pulse_fastly_open_secret_store(effectIndex: i32): i32 { const nameBytes = __pulse_fastly_utf8(__pulse_fastly_secret_store(effectIndex)); const out = __pulse_fastly_out_i32(); const status = fastly_secret_store_open(changetype<usize>(nameBytes), nameBytes.byteLength, changetype<usize>(out)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 111, effectIndex); return 0 } return __pulse_fastly_out_value(out) }
1568
+ function __pulse_fastly_open_kv_store(effectIndex: i32): i32 { const nameBytes = __pulse_fastly_utf8(__pulse_fastly_kv_store(effectIndex)); const out = __pulse_fastly_out_i32(); const status = fastly_kv_store_open(changetype<usize>(nameBytes), nameBytes.byteLength, changetype<usize>(out)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 112, effectIndex); return 0 } return __pulse_fastly_out_value(out) }
1569
+ function __pulse_fastly_config_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const name = __pulse_fastly_string(__pulse_fastly_payload_field(payload, "name")); const store = __pulse_fastly_open_config_store(effectIndex); if (__pulse_fastly_last_error != 0) return; const keyBytes = __pulse_fastly_utf8(name); const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES); const written = __pulse_fastly_out_i32(); const status = fastly_config_store_get(store, changetype<usize>(keyBytes), keyBytes.byteLength, buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(written)); if (status == FASTLY_STATUS_NONE) { __pulse_fastly_ready_effect(effectIndex, host_value_undefined()); return } if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 113, effectIndex); return } __pulse_fastly_ready_effect(effectIndex, __pulse_fastly_string_value(__pulse_fastly_decode(buffer, __pulse_fastly_out_value(written)))) }
1570
+ function __pulse_fastly_secret_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const name = __pulse_fastly_string(__pulse_fastly_payload_field(payload, "name")); const store = __pulse_fastly_open_secret_store(effectIndex); if (__pulse_fastly_last_error != 0) return; const keyBytes = __pulse_fastly_utf8(name); const secretOut = __pulse_fastly_out_i32(); let status = fastly_secret_store_get(store, changetype<usize>(keyBytes), keyBytes.byteLength, changetype<usize>(secretOut)); if (status == FASTLY_STATUS_NONE) { __pulse_fastly_ready_effect(effectIndex, host_value_undefined()); return } if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 114, effectIndex); return } const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES); const written = __pulse_fastly_out_i32(); status = fastly_secret_store_plaintext(__pulse_fastly_out_value(secretOut), buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(written)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 115, effectIndex); return } const secret = __pulse_fastly_remember_secret(__pulse_fastly_decode(buffer, __pulse_fastly_out_value(written))); __pulse_fastly_ready_effect(effectIndex, __pulse_fastly_string_value(secret)) }
1571
+ function __pulse_fastly_jwt_case_id(): string { return ${jwtCaseSource} }
1572
+ function __pulse_fastly_jwt_fail_code(effectIndex: i32, code: i32, stage: i32): i32 { if (__pulse_fastly_jwt_error == 0) __pulse_fastly_jwt_error = code; __pulse_fastly_fail(PULSE_ERROR_JWT, stage, effectIndex); return 0 }
1573
+ function __pulse_fastly_jwt_key_descriptor_valid(effectIndex: i32): bool { return __pulse_fastly_jwt_case_id() != "malformed-secret-descriptor" }
1574
+ function __pulse_fastly_jwt_effect_secret_binding(effectIndex: i32): string { const caseId = __pulse_fastly_jwt_case_id(); ${jwtBindingOverrides} return __pulse_fastly_jwt_secret_binding(effectIndex) }
1575
+ function __pulse_fastly_jwt_resolve_secret(effectIndex: i32): Uint8Array { __pulse_fastly_jwt_secret_calls += 1; __pulse_fastly_jwt_event_order += "S"; const store = __pulse_fastly_open_secret_store(effectIndex); if (__pulse_fastly_last_error != 0) return new Uint8Array(0); const name = __pulse_fastly_jwt_effect_secret_binding(effectIndex); const keyBytes = __pulse_fastly_utf8(name); const secretOut = __pulse_fastly_out_i32(); let status = fastly_secret_store_get(store, changetype<usize>(keyBytes), keyBytes.byteLength, changetype<usize>(secretOut)); if (status == FASTLY_STATUS_NONE) return new Uint8Array(0); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 224, effectIndex); return new Uint8Array(0) } const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES); const written = __pulse_fastly_out_i32(); status = fastly_secret_store_plaintext(__pulse_fastly_out_value(secretOut), buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(written)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 225, effectIndex); return new Uint8Array(0) } const length = __pulse_fastly_out_value(written); const output = new Uint8Array(length); for (let index = 0; index < length; index += 1) unchecked(output[index] = buffer[index]); __pulse_fastly_remember_secret(__pulse_fastly_decode(buffer, length)); for (let index = 0; index < length; index += 1) unchecked(buffer[index] = 0); return output }
1576
+ function __pulse_fastly_jwt_force_crypto_failure(effectIndex: i32): bool { const caseId = __pulse_fastly_jwt_case_id(); return caseId == "runtime-realization-failure" || caseId == "realization-failure-distinct" || caseId == "no-fallback" }
1577
+ function __pulse_fastly_jwt_record_crypto_attempt(): void { __pulse_fastly_jwt_crypto_calls += 1; __pulse_fastly_jwt_event_order += "A" }
1578
+ function __pulse_fastly_jwt_record_claims_parsed(): void { __pulse_fastly_jwt_claims_parsed = 1; __pulse_fastly_jwt_event_order += "P" }
1579
+ function __pulse_fastly_jwt_record_verified(): void { __pulse_fastly_jwt_verified = 1; __pulse_fastly_jwt_event_order += "V" }
1580
+ function __pulse_fastly_jwt_record_signing_input(bytes: i32, digest: string): void { __pulse_fastly_jwt_signing_input_bytes = bytes; __pulse_fastly_jwt_signing_input_sha256 = digest }
1581
+ function __pulse_fastly_jwt_capture_clock(effectIndex: i32): f64 { __pulse_fastly_jwt_clock_calls += 1; __pulse_fastly_jwt_event_order += "C"; const out = new StaticArray<i64>(1); const status = wasi_snapshot_preview1_clock_time_get(0, 1, changetype<usize>(out)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 226, effectIndex); return NaN } ${jwtClockOverride ? `return ${jwtClockOverride}` : 'return f64(load<i64>(changetype<usize>(out))) / 1000000000.0'} }
1582
+ function __pulse_fastly_jwt_validate_schema(effectIndex: i32, schemaId: string, claimsHandle: i32): i32 { __pulse_fastly_jwt_schema_calls += 1; __pulse_fastly_jwt_event_order += "H"; if (__pulse_fastly_jwt_case_id() == "claims-schema-failure-after-registered-claims") return 0; return __pulse_fastly_schema_apply(schemaId, claimsHandle, false) }
1583
+ function __pulse_fastly_jwt_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const result = pulse_jwt_fastly_verify(effectIndex, unchecked(__pulse_fastly_payloads[effectIndex])); if (result > 0 && __pulse_fastly_last_error == 0) __pulse_fastly_ready_effect(effectIndex, result) }
1584
+ function __pulse_fastly_start_request(effectIndex: i32, url: string, method: string, headers: __PulseFastlyValue, body: string, backend: string): void { 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); 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); 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 } 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 } 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 } } } 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 } } 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_mode[effectIndex] = PULSE_FASTLY_PENDING_ASYNC) }
1585
+ function __pulse_fastly_fetch_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const urlIndex = __pulse_fastly_find(payload, "url"); if (urlIndex < 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 48, effectIndex); return } const url = __pulse_fastly_string(unchecked(payload.values[urlIndex])); const initIndex = __pulse_fastly_find(payload, "init"); const init = initIndex >= 0 ? __pulse_fastly_value(unchecked(payload.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"); const jsonIndex = __pulse_fastly_find(init, "json"); 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) } else if (jsonIndex >= 0) { body = __pulse_fastly_json(unchecked(init.values[jsonIndex]), 0); let hasContentType = false; for (let i = 0; i < headers.keys.length; i += 1) if (unchecked(headers.keys[i]).toLowerCase() == "content-type") hasContentType = true; if (!hasContentType) { headers.keys.push("content-type"); headers.values.push(__pulse_fastly_string_value("application/json; charset=utf-8")) } } } __pulse_fastly_start_request(effectIndex, url, method, headers, body, __pulse_fastly_backend(effectIndex)) }
1586
+ function __pulse_fastly_kv_get_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const store = __pulse_fastly_open_kv_store(effectIndex); if (__pulse_fastly_last_error != 0) return; const key = __pulse_fastly_string(__pulse_fastly_payload_field(payload, "key")); const keyBytes = __pulse_fastly_utf8(key); const lookupOut = __pulse_fastly_out_i32(); const config = new StaticArray<i32>(1); const status = fastly_kv_store_lookup(store, changetype<usize>(keyBytes), keyBytes.byteLength, 0, changetype<usize>(config), changetype<usize>(lookupOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 116, effectIndex); return } unchecked(__pulse_fastly_pending[effectIndex] = __pulse_fastly_out_value(lookupOut)); unchecked(__pulse_fastly_pending_mode[effectIndex] = PULSE_FASTLY_PENDING_ASYNC) }
1587
+ function __pulse_fastly_assets_payload(payload: __PulseFastlyValue): __PulseFastlyValue { const value = __pulse_fastly_value(__pulse_fastly_payload_field(payload, "payload")); if (value.kind != PULSE_VALUE_OBJECT) __pulse_fastly_fail(PULSE_ERROR_VALUE, 146, -1); return value }
1588
+ function __pulse_fastly_assets_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const value = __pulse_fastly_assets_payload(payload); if (__pulse_fastly_last_error != 0) return; const store = __pulse_fastly_open_kv_store(effectIndex); if (__pulse_fastly_last_error != 0) return; const key = __pulse_fastly_string(__pulse_fastly_payload_field(value, "key")); const keyBytes = __pulse_fastly_utf8(key); const lookupOut = __pulse_fastly_out_i32(); const config = new StaticArray<i32>(1); const status = fastly_kv_store_lookup(store, changetype<usize>(keyBytes), keyBytes.byteLength, 0, changetype<usize>(config), changetype<usize>(lookupOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 147, effectIndex); return } unchecked(__pulse_fastly_pending[effectIndex] = __pulse_fastly_out_value(lookupOut)); unchecked(__pulse_fastly_pending_mode[effectIndex] = PULSE_FASTLY_PENDING_ASYNC) }
1589
+ function __pulse_fastly_kv_put_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const store = __pulse_fastly_open_kv_store(effectIndex); if (__pulse_fastly_last_error != 0) return; const key = __pulse_fastly_string(__pulse_fastly_payload_field(payload, "key")); const value = __pulse_fastly_payload_field(payload, "value"); const bodyOut = __pulse_fastly_out_i32(); let status = fastly_http_body_new(changetype<usize>(bodyOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 117, effectIndex); return } const body = __pulse_fastly_out_value(bodyOut); status = __pulse_fastly_write_body(body, "{\"__pulseKv\":1,\"value\":" + __pulse_fastly_json(value, 0) + "}"); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 118, effectIndex); return } const keyBytes = __pulse_fastly_utf8(key); const insertOut = __pulse_fastly_out_i32(); const config = new StaticArray<i64>(4); status = fastly_kv_store_insert(store, changetype<usize>(keyBytes), keyBytes.byteLength, body, 0, changetype<usize>(config), changetype<usize>(insertOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 119, effectIndex); return } unchecked(__pulse_fastly_pending[effectIndex] = __pulse_fastly_out_value(insertOut)); unchecked(__pulse_fastly_pending_mode[effectIndex] = PULSE_FASTLY_PENDING_ASYNC) }
1590
+ function __pulse_fastly_grip_add_channel(channel: string): void { if (channel.length == 0) return; for (let i = 0; i < __pulse_fastly_grip_channels.length; i += 1) if (unchecked(__pulse_fastly_grip_channels[i]) == channel) return; __pulse_fastly_grip_channels.push(channel) }
1591
+ function __pulse_fastly_grip_payload(payload: __PulseFastlyValue): __PulseFastlyValue { return __pulse_fastly_value(__pulse_fastly_payload_field(payload, "payload")) }
1592
+ function __pulse_fastly_grip_channel_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const value = __pulse_fastly_grip_payload(payload); if (value.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 120, effectIndex); return } const channel = __pulse_fastly_string(__pulse_fastly_payload_field(value, "channel")); const prefixHandle = __pulse_fastly_payload_field(value, "prefix"); const prefixValue = __pulse_fastly_value(prefixHandle); const prefix = prefixValue.kind == PULSE_VALUE_UNDEFINED ? "" : __pulse_fastly_string(prefixHandle); __pulse_fastly_grip_add_channel(prefix + channel); __pulse_fastly_ready_effect(effectIndex, host_value_boolean(1)) }
1593
+ function __pulse_fastly_grip_hold_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const value = __pulse_fastly_grip_payload(payload); if (value.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 121, effectIndex); return } const modeHandle = __pulse_fastly_payload_field(value, "mode"); const modeValue = __pulse_fastly_value(modeHandle); const mode = modeValue.kind == PULSE_VALUE_UNDEFINED ? "stream" : __pulse_fastly_string(modeHandle); const explicitHandle = __pulse_fastly_payload_field(value, "channels"); const explicit = __pulse_fastly_value(explicitHandle); if (explicit.kind == PULSE_VALUE_ARRAY) for (let i = 0; i < explicit.values.length; i += 1) __pulse_fastly_grip_add_channel(__pulse_fastly_string(unchecked(explicit.values[i]))); const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE; output.status = 200; output.headers.push(new __PulseFastlyHeader("content-type", "application/octet-stream")); output.headers.push(new __PulseFastlyHeader("grip-hold", mode)); for (let i = 0; i < __pulse_fastly_grip_channels.length; i += 1) output.headers.push(new __PulseFastlyHeader("grip-channel", unchecked(__pulse_fastly_grip_channels[i]))); const timeoutHandle = __pulse_fastly_payload_field(value, "timeoutMs"); if (__pulse_fastly_value(timeoutHandle).kind != PULSE_VALUE_UNDEFINED) output.headers.push(new __PulseFastlyHeader("grip-timeout", i32(Math.max(0.0, __pulse_fastly_number(timeoutHandle))).toString())); __pulse_fastly_ready_effect(effectIndex, __pulse_fastly_put(output)) }
1594
+ ${gripSecretSource}
1595
+ function __pulse_fastly_grip_publish_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const valueHandle = __pulse_fastly_payload_field(payload, "payload"); const value = __pulse_fastly_value(valueHandle); if (value.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 122, effectIndex); return } const headers = new __PulseFastlyValue(); headers.kind = PULSE_VALUE_OBJECT; headers.keys.push("content-type"); headers.values.push(__pulse_fastly_string_value("application/json; charset=utf-8")); headers.keys.push("accept"); headers.values.push(__pulse_fastly_string_value("application/json")); ${gripAuthorizationSource} const body = __pulse_fastly_json(valueHandle, 0); if (String.UTF8.encode(body, false).byteLength > PULSE_FASTLY_BUFFER_BYTES) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 145, effectIndex); return } __pulse_fastly_start_request(effectIndex, __pulse_fastly_grip_publish_url(effectIndex), "POST", headers, body, __pulse_fastly_backend(effectIndex)) }
1596
+ ${effectDispatchSource(plan)}
1597
+ function __pulse_fastly_wait_fetch(effectIndex: i32): i32 { if (unchecked(__pulse_fastly_pending_mode[effectIndex]) != PULSE_FASTLY_PENDING_ASYNC) { __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_mode[effectIndex] = PULSE_FASTLY_PENDING_NONE); 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) }
1598
+ function __pulse_fastly_wait_grip_publish(effectIndex: i32): i32 { const responseHandle = __pulse_fastly_wait_fetch(effectIndex); if (responseHandle <= 0) return 0; const response = __pulse_fastly_value(responseHandle); if (response.kind != PULSE_VALUE_FETCH) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 129, effectIndex); return 0 } const statusOut = __pulse_fastly_out_i32(); const statusCall = fastly_http_resp_status_get(response.responseHandle, changetype<usize>(statusOut)); if (statusCall != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 130, effectIndex); return 0 } const originStatus = __pulse_fastly_out_value(statusOut); if (originStatus < 200 || originStatus > 299) { __pulse_fastly_fail(PULSE_ERROR_TRANSPORT, 131, effectIndex); return 0 } const outer = __pulse_fastly_value(unchecked(__pulse_fastly_payloads[effectIndex])); const publicationHandle = __pulse_fastly_payload_field(outer, "payload"); const publication = __pulse_fastly_value(publicationHandle); if (publication.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 132, effectIndex); return 0 } const receipt = host_value_object(); host_value_object_set(receipt, __pulse_fastly_string_value("published"), host_value_boolean(1)); for (let i = 0; i < publication.keys.length; i += 1) host_value_object_set(receipt, __pulse_fastly_string_value(unchecked(publication.keys[i])), unchecked(publication.values[i])); const options = host_value_object(); host_value_object_set(options, __pulse_fastly_string_value("status"), host_value_number(202.0)); return host_response_json(receipt, options) }
1599
+ function __pulse_fastly_wait_grip_broadcast(effectIndex: i32): i32 { const responseHandle = __pulse_fastly_wait_fetch(effectIndex); if (responseHandle <= 0) return 0; const response = __pulse_fastly_value(responseHandle); if (response.kind != PULSE_VALUE_FETCH) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 142, effectIndex); return 0 } const statusOut = __pulse_fastly_out_i32(); const statusCall = fastly_http_resp_status_get(response.responseHandle, changetype<usize>(statusOut)); if (statusCall != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 143, effectIndex); return 0 } const originStatus = __pulse_fastly_out_value(statusOut); if (originStatus < 200 || originStatus > 299) { __pulse_fastly_fail(PULSE_ERROR_TRANSPORT, 144, effectIndex); return 0 } const receipt = host_value_object(); host_value_object_set(receipt, __pulse_fastly_string_value("accepted"), host_value_boolean(1)); host_value_object_set(receipt, __pulse_fastly_string_value("status"), host_value_number(f64(originStatus))); return receipt }
1600
+ function __pulse_fastly_wait_ready(effectIndex: i32): i32 { if (unchecked(__pulse_fastly_pending_mode[effectIndex]) != PULSE_FASTLY_PENDING_READY) { __pulse_fastly_fail(PULSE_ERROR_STATE, 124, effectIndex); return 0 } const value = unchecked(__pulse_fastly_ready[effectIndex]); unchecked(__pulse_fastly_pending_mode[effectIndex] = PULSE_FASTLY_PENDING_NONE); unchecked(__pulse_fastly_pending[effectIndex] = 0); unchecked(__pulse_fastly_ready[effectIndex] = 0); return value }
1601
+ function __pulse_fastly_wait_kv_get(effectIndex: i32): i32 { if (unchecked(__pulse_fastly_pending_mode[effectIndex]) == PULSE_FASTLY_PENDING_READY) return __pulse_fastly_wait_ready(effectIndex); if (unchecked(__pulse_fastly_pending_mode[effectIndex]) != PULSE_FASTLY_PENDING_ASYNC) { __pulse_fastly_fail(PULSE_ERROR_STATE, 125, effectIndex); return 0 } const pending = unchecked(__pulse_fastly_pending[effectIndex]); const bodyOut = __pulse_fastly_out_i32(); const metadata = new Uint8Array(1); const written = __pulse_fastly_out_i32(); const generation = new StaticArray<i64>(1); const kvError = __pulse_fastly_out_i32(); const status = fastly_kv_store_lookup_wait_v2(pending, changetype<usize>(bodyOut), metadata.dataStart, 0, changetype<usize>(written), changetype<usize>(generation), changetype<usize>(kvError)); unchecked(__pulse_fastly_pending_mode[effectIndex] = PULSE_FASTLY_PENDING_NONE); unchecked(__pulse_fastly_pending[effectIndex] = 0); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 125, effectIndex); return 0 } const errorCode = __pulse_fastly_out_value(kvError); if (errorCode == 3) return host_value_undefined(); if (errorCode != 1) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 128, effectIndex); return 0 } const text = __pulse_fastly_read_body(__pulse_fastly_out_value(bodyOut), effectIndex); if (__pulse_fastly_last_error != 0) return 0; const parser = new __PulseJsonParser(text); const parsed = parser.parse(); if (parser.failed || parsed <= 0) return __pulse_fastly_string_value(text); const object = __pulse_fastly_value(parsed); if (object.kind == PULSE_VALUE_OBJECT) { const marker = __pulse_fastly_find(object, "__pulseKv"); const value = __pulse_fastly_find(object, "value"); if (marker >= 0 && value >= 0 && __pulse_fastly_number(unchecked(object.values[marker])) == 1.0) return unchecked(object.values[value]) } return parsed }
1602
+ function __pulse_fastly_asset_content_type(key: string): string { const dot = key.lastIndexOf("."); const extension = dot < 0 ? "" : key.substring(dot + 1).toLowerCase(); if (extension == "css") return "text/css; charset=utf-8"; if (extension == "html") return "text/html; charset=utf-8"; if (extension == "js" || extension == "mjs") return "text/javascript; charset=utf-8"; if (extension == "json") return "application/json; charset=utf-8"; if (extension == "svg") return "image/svg+xml"; if (extension == "txt") return "text/plain; charset=utf-8"; if (extension == "webp") return "image/webp"; if (extension == "png") return "image/png"; if (extension == "jpg" || extension == "jpeg") return "image/jpeg"; if (extension == "gif") return "image/gif"; if (extension == "ico") return "image/x-icon"; return "application/octet-stream" }
1603
+ function __pulse_fastly_asset_text(text: string): string { const parser = new __PulseJsonParser(text); const parsed = parser.parse(); if (parser.failed || parsed <= 0) return text; const object = __pulse_fastly_value(parsed); if (object.kind != PULSE_VALUE_OBJECT) return text; const marker = __pulse_fastly_find(object, "__pulseKv"); const value = __pulse_fastly_find(object, "value"); if (marker < 0 || value < 0 || __pulse_fastly_number(unchecked(object.values[marker])) != 1.0) return text; return __pulse_fastly_string(unchecked(object.values[value])) }
1604
+ function __pulse_fastly_wait_assets(effectIndex: i32): i32 { if (unchecked(__pulse_fastly_pending_mode[effectIndex]) != PULSE_FASTLY_PENDING_ASYNC) { __pulse_fastly_fail(PULSE_ERROR_STATE, 148, effectIndex); return 0 } const pending = unchecked(__pulse_fastly_pending[effectIndex]); const bodyOut = __pulse_fastly_out_i32(); const metadata = new Uint8Array(1); const written = __pulse_fastly_out_i32(); const generation = new StaticArray<i64>(1); const kvError = __pulse_fastly_out_i32(); const status = fastly_kv_store_lookup_wait_v2(pending, changetype<usize>(bodyOut), metadata.dataStart, 0, changetype<usize>(written), changetype<usize>(generation), changetype<usize>(kvError)); unchecked(__pulse_fastly_pending_mode[effectIndex] = PULSE_FASTLY_PENDING_NONE); unchecked(__pulse_fastly_pending[effectIndex] = 0); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 149, effectIndex); return 0 } const outer = __pulse_fastly_value(unchecked(__pulse_fastly_payloads[effectIndex])); const payload = __pulse_fastly_assets_payload(outer); if (__pulse_fastly_last_error != 0) return 0; const key = __pulse_fastly_string(__pulse_fastly_payload_field(payload, "key")); const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE; const errorCode = __pulse_fastly_out_value(kvError); output.status = errorCode == 3 ? 404 : 200; if (errorCode != 1 && errorCode != 3) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 150, effectIndex); return 0 } const headersHandle = __pulse_fastly_payload_field(payload, "headers"); const headers = __pulse_fastly_value(headersHandle); let hasContentType = false; if (headers.kind == PULSE_VALUE_OBJECT) { for (let i = 0; i < headers.keys.length; i += 1) { const name = unchecked(headers.keys[i]); if (name.toLowerCase() == "content-type") hasContentType = true; output.headers.push(new __PulseFastlyHeader(name, __pulse_fastly_string(unchecked(headers.values[i])))) } } if (!hasContentType) output.headers.push(new __PulseFastlyHeader("content-type", output.status == 200 ? __pulse_fastly_asset_content_type(key) : "text/plain; charset=utf-8")); const cacheHandle = __pulse_fastly_payload_field(payload, "cacheControl"); if (__pulse_fastly_value(cacheHandle).kind != PULSE_VALUE_UNDEFINED) output.headers.push(new __PulseFastlyHeader("cache-control", __pulse_fastly_string(cacheHandle))); const methodHandle = __pulse_fastly_payload_field(payload, "method"); const method = __pulse_fastly_value(methodHandle).kind == PULSE_VALUE_UNDEFINED ? "GET" : __pulse_fastly_string(methodHandle).toUpperCase(); if (output.status == 200 && method != "HEAD") { const text = __pulse_fastly_read_body(__pulse_fastly_out_value(bodyOut), effectIndex); if (__pulse_fastly_last_error != 0) return 0; output.text = __pulse_fastly_asset_text(text) } return __pulse_fastly_put(output) }
1605
+ function __pulse_fastly_wait_kv_put(effectIndex: i32): i32 { if (unchecked(__pulse_fastly_pending_mode[effectIndex]) != PULSE_FASTLY_PENDING_ASYNC) { __pulse_fastly_fail(PULSE_ERROR_STATE, 126, effectIndex); return 0 } const pending = unchecked(__pulse_fastly_pending[effectIndex]); const kvError = __pulse_fastly_out_i32(); const status = fastly_kv_store_insert_wait(pending, changetype<usize>(kvError)); unchecked(__pulse_fastly_pending_mode[effectIndex] = PULSE_FASTLY_PENDING_NONE); unchecked(__pulse_fastly_pending[effectIndex] = 0); if (status != FASTLY_STATUS_OK || __pulse_fastly_out_value(kvError) != 1) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 127, effectIndex); return 0 } return host_value_boolean(1) }
1606
+ 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 }
1607
+ 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) }
1608
+
1609
+ ${jwtEvidenceSource}
1610
+ ${es256KeyArtifactSource(es256KeyRecords)}
1611
+ ${jwtCryptoCompositionSource(jwtCrypto)}
1612
+ ${generateSchemaRuntime(plan)}
1613
+ ${effectResultSource(plan, bindings)}
1614
+ `;
1615
+ }
1616
+
1617
+ function driverSource(plan, options = {}) {
1618
+ const entryName = options.guestLinked === true
1619
+ ? 'pulse_fastly_handle'
1620
+ : '_start';
1621
+ return String.raw`
1622
+ export function pulse_fastly_last_error(): i32 { return __pulse_fastly_last_error }
1623
+ export function pulse_fastly_error_stage(): i32 { return __pulse_fastly_error_stage }
1624
+ export function pulse_fastly_error_effect(): i32 { return __pulse_fastly_error_effect }
1625
+ export function pulse_fastly_jwt_error(): i32 { return __pulse_fastly_jwt_error }
1626
+ export function pulse_fastly_jwt_secret_calls(): i32 { return __pulse_fastly_jwt_secret_calls }
1627
+ export function pulse_fastly_jwt_crypto_calls(): i32 { return __pulse_fastly_jwt_crypto_calls }
1628
+ export function pulse_fastly_jwt_clock_calls(): i32 { return __pulse_fastly_jwt_clock_calls }
1629
+ export function pulse_fastly_jwt_schema_calls(): i32 { return __pulse_fastly_jwt_schema_calls }
1630
+ export function ${entryName}(): void {
1631
+ __pulse_fastly_last_error = fastly_abi_init(PULSE_FASTLY_EFFECTS_ABI_VERSION)
1632
+ if (__pulse_fastly_last_error != FASTLY_STATUS_OK) { __pulse_fastly_jwt_send_error(); return }
1633
+ const handles = new StaticArray<i32>(2)
1634
+ const downstreamStatus = fastly_http_req_body_downstream_get(changetype<usize>(handles), changetype<usize>(handles) + 4)
1635
+ if (downstreamStatus != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 100, -1); __pulse_fastly_jwt_send_error(); return }
1636
+ __pulse_fastly_request_handle = load<i32>(changetype<usize>(handles))
1637
+ __pulse_fastly_request_body_handle = load<i32>(changetype<usize>(handles) + 4)
1638
+ __pulse_fastly_request_method = __pulse_fastly_read_req_string(0)
1639
+ if (__pulse_fastly_last_error != 0) { __pulse_fastly_jwt_send_error(); return }
1640
+ __pulse_fastly_request_url = __pulse_fastly_read_req_string(1)
1641
+ if (__pulse_fastly_last_error != 0) { __pulse_fastly_jwt_send_error(); return }
1642
+ __pulse_fastly_request_path = __pulse_fastly_path(__pulse_fastly_request_url)
1643
+ let runStatus = pulse_start()
1644
+ while (runStatus == 1 && __pulse_fastly_last_error == 0) {
1645
+ for (let effectIndex = 0; effectIndex < PULSE_FASTLY_EFFECT_COUNT; effectIndex += 1) {
1646
+ if (unchecked(__pulse_fastly_pending_mode[effectIndex]) == PULSE_FASTLY_PENDING_NONE) continue
1647
+ const result = __pulse_fastly_resolve_effect(effectIndex)
1648
+ if (result <= 0 || __pulse_fastly_last_error != 0) { __pulse_fastly_jwt_send_error(); return }
1649
+ if (pulse_set_effect_result(effectIndex, result) != 1) { __pulse_fastly_fail(PULSE_ERROR_STATE, 101, effectIndex); __pulse_fastly_jwt_send_error(); return }
1650
+ }
1651
+ runStatus = pulse_resume()
1652
+ }
1653
+ if (__pulse_fastly_last_error != 0) { __pulse_fastly_jwt_send_error(); return }
1654
+ if (runStatus != 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 102, -1); __pulse_fastly_jwt_send_error(); return }
1655
+ const result = pulse_result_handle()
1656
+ if (result <= 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 103, -1); __pulse_fastly_jwt_send_error(); return }
1657
+ __pulse_fastly_jwt_attach_evidence(result)
1658
+ const sendStatus = __pulse_fastly_send_result(result)
1659
+ if (sendStatus != FASTLY_STATUS_OK) __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 104, -1)
1660
+ }
1661
+ `;
1662
+ }
1663
+
1664
+ function capabilityImports(effect) {
1665
+ if (effect.kind === 'config.get') return ['fastly_config_store.open', 'fastly_config_store.get'];
1666
+ if (effect.kind === 'secret.get') return ['fastly_secret_store.open', 'fastly_secret_store.get', 'fastly_secret_store.plaintext'];
1667
+ if (effect.kind === 'jwt.verify') {
1668
+ return [
1669
+ ...(effect.resource && effect.resource.keyType === 'secret'
1670
+ ? [
1671
+ 'fastly_secret_store.open',
1672
+ 'fastly_secret_store.get',
1673
+ 'fastly_secret_store.plaintext'
1674
+ ]
1675
+ : []),
1676
+ 'wasi_snapshot_preview1.clock_time_get'
1677
+ ];
1678
+ }
1679
+ if (conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind)) return conditionalKv.kvImports(effect.kind).map(key => key.replace(':', '.'));
1680
+ if (effect.kind === 'kv.get') return ['fastly_kv_store.open', 'fastly_kv_store.lookup', 'fastly_kv_store.lookup_wait_v2', 'fastly_http_body.read'];
1681
+ if (effect.kind === 'kv.put') return ['fastly_kv_store.open', 'fastly_kv_store.insert', 'fastly_kv_store.insert_wait', 'fastly_http_body.new', 'fastly_http_body.write'];
1682
+ if (effect.kind === 'assets.lookup') return ['fastly_kv_store.open', 'fastly_kv_store.lookup', 'fastly_kv_store.lookup_wait_v2', 'fastly_http_body.read'];
1683
+ if (effect.kind === 'fetch' || effect.kind === 'grip.publish' || effect.kind === 'grip.broadcast') {
1684
+ return [
1685
+ 'fastly_http_req.new',
1686
+ 'fastly_http_req.send_async',
1687
+ 'fastly_http_req.pending_req_wait',
1688
+ ...(effect.kind === 'grip.broadcast' ? ['fastly_secret_store.open', 'fastly_secret_store.get', 'fastly_secret_store.plaintext'] : [])
1689
+ ];
1690
+ }
1691
+ if (effect.kind === 'grip.hold') return ['fastly_http_resp.new', 'fastly_http_resp.header_append', 'fastly_http_resp.send_downstream'];
1692
+ return [];
1693
+ }
1694
+
1695
+ function generateFastlyNativePlatformCapabilitiesAssemblyScript(plan, options = {}) {
1696
+ validatePlanBoundary(plan, options);
1697
+ const facts = packageFacts(plan, options);
1698
+ const jwtCrypto = selectedJwtCrypto(plan);
1699
+ const es256KeyRecords = jwtCrypto && jwtCrypto.algorithm === 'ES256'
1700
+ ? resolveEs256KeyArtifacts(plan, facts)
1701
+ : Object.freeze([]);
1702
+ if (jwtCrypto && jwtCrypto.guestUnitRequired && facts.guestUnits.length !== 1) {
1703
+ fail(
1704
+ 'Fastly Native ES256 requires exactly one synchronized linked guest unit.',
1705
+ 'PULSE_FASTLY_NATIVE_JWT_CRYPTO_REALIZATION_INVALID',
1706
+ {
1707
+ selected: facts.guestUnits.map((entry) => entry.id),
1708
+ automaticFallback: false
1709
+ }
1710
+ );
1711
+ }
1712
+ if (jwtCrypto && !jwtCrypto.guestUnitRequired && facts.guestUnits.length !== 0) {
1713
+ fail(
1714
+ 'Fastly Native JWT received an unselected guest unit.',
1715
+ 'PULSE_FASTLY_NATIVE_JWT_CRYPTO_REALIZATION_INVALID',
1716
+ {
1717
+ selected: facts.guestUnits.map((entry) => entry.id),
1718
+ automaticFallback: false
1719
+ }
1720
+ );
1721
+ }
1722
+ const bindings = resolveCapabilityBindings(plan, options);
1723
+ const portable = generateCanonicalNativeAssemblyScript(plan, options);
1724
+ const portableSource = stripPulseHostImports(portable.source);
1725
+ const hasJwt = (plan.effects || []).some((effect) => effect.kind === 'jwt.verify');
1726
+ const jwtSource = hasJwt ? pulseJwtAssemblyScriptSource() : undefined;
1727
+ const source = [
1728
+ '/* Generated by Pulse Pass98 Fastly native platform capability compiler. */',
1729
+ 'export function __pulse_fastly_abort(message: string | null, fileName: string | null = null, line: u32 = 0, column: u32 = 0): void { unreachable() }',
1730
+ '',
1731
+ fastlyRuntimeSource(plan, bindings, {
1732
+ ...options,
1733
+ jwtCrypto,
1734
+ es256KeyRecords
1735
+ }),
1736
+ jwtSource ? jwtSource.source : '',
1737
+ require('./s3-native.js').s3NativeSource(plan, bindings),
1738
+ conditionalKv.kvNativeSource(plan),
1739
+ portableSource,
1740
+ driverSource(plan, { guestLinked: facts.guestUnits.length > 0 }),
1741
+ ''
1742
+ ].join('\n');
1743
+ const effectKinds = Object.freeze((plan.effects || []).reduce((output, effect) => {
1744
+ output[effect.kind] = (output[effect.kind] || 0) + 1;
1745
+ return output;
1746
+ }, {}));
1747
+ const capabilityDiagnostics = Object.freeze((plan.effects || []).map((effect, index) => Object.freeze({
1748
+ index,
1749
+ id: effect.id,
1750
+ kind: effect.kind,
1751
+ capability: effect.capability,
1752
+ package: effect.package,
1753
+ contractId: effect.contractId,
1754
+ imports: Object.freeze(capabilityImports(effect))
1755
+ })));
1756
+ const manifest = Object.freeze({
1757
+ version: FASTLY_NATIVE_PLATFORM_CAPABILITIES_VERSION,
1758
+ generatorVersion: FASTLY_NATIVE_PLATFORM_CAPABILITIES_GENERATOR_VERSION,
1759
+ abiVersion: FASTLY_NATIVE_PLATFORM_CAPABILITIES_ABI_VERSION,
1760
+ planVersion: plan.version,
1761
+ planHash: plan.planHash,
1762
+ sourceHash: sha256(source),
1763
+ portableGeneratorVersion: portable.version,
1764
+ portableSourceHash: portable.sourceHash,
1765
+ schemaCodecs: portable.manifest.schemaCodecs,
1766
+ crypto: portable.manifest.crypto,
1767
+ jwt: jwtSource
1768
+ ? Object.freeze({
1769
+ status: jwtCrypto && jwtCrypto.algorithm === 'ES256'
1770
+ ? 'implemented-g4'
1771
+ : 'implemented-e2',
1772
+ package: jwtSource.owner,
1773
+ packageVersion: jwtSource.packageVersion,
1774
+ sourceId: jwtSource.id,
1775
+ sourceFile: jwtSource.sourceFile,
1776
+ sourceBytes: jwtSource.sourceBytes,
1777
+ sourceSha256: jwtSource.sourceSha256,
1778
+ sourceIncluded: true,
1779
+ semanticOwnership: jwtSource.semanticOwnership,
1780
+ providerAuthorities: jwtSource.providerAuthorities,
1781
+ cryptoRealization: jwtCrypto.realization,
1782
+ cryptoImplementation: jwtCrypto.implementation,
1783
+ keyArtifactCount: es256KeyRecords.length,
1784
+ automaticFallback: false
1785
+ })
1786
+ : Object.freeze({ status: 'inactive' }),
1787
+ effectCount: (plan.effects || []).length,
1788
+ effectKinds,
1789
+ continuationCount: (plan.continuations || []).length,
1790
+ groupedContinuationCount: (plan.continuations || []).filter((entry) => (entry.effectIds || []).length > 1).length,
1791
+ bindings,
1792
+ backends: bindings.backends,
1793
+ capabilityDiagnostics,
1794
+ allowedImports: FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORTS,
1795
+ requiredImports: requiredImportsForPlan(plan, bindings),
1796
+ requiredExports: Object.freeze([
1797
+ '_start',
1798
+ 'pulse_fastly_last_error',
1799
+ 'pulse_fastly_error_stage',
1800
+ 'pulse_fastly_error_effect',
1801
+ 'pulse_plan_hash_ptr',
1802
+ 'pulse_plan_hash_length'
1803
+ ]),
1804
+ policy: Object.freeze({
1805
+ nativeFastly: true,
1806
+ provider: 'fastly',
1807
+ providerNeutralInput: true,
1808
+ javascriptRuntime: false,
1809
+ jsComputeRuntime: false,
1810
+ wasi: hasJwt || bindings.s3.length || plan.effects.some(effect => conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind)) ? 'clock_time_get only' : false,
1811
+ effects: FASTLY_NATIVE_PLATFORM_EFFECT_KINDS.join(', '),
1812
+ continuations: true,
1813
+ groupedEffects: 'existing fetch start-before-wait ordering remains intact',
1814
+ config: 'Fastly Config Store open/get with undefined for missing values',
1815
+ secrets: 'Fastly Secret Store open/get/plaintext; proof traces redact plaintext values',
1816
+ jwt: hasJwt
1817
+ ? `package-owned compact-JWS and registered-claim semantics composed with ${jwtCrypto.realization}; provider-owned request, clock, schema, and transport`
1818
+ : 'inactive',
1819
+ kv: 'Fastly KV Store async lookup/insert; conditional operations preserve u64 generations, bounded readiness, strict Pulse envelopes and uncertain dispatch',
1820
+ assets: 'Fastly KV Store lookup with provider-owned content type, cache headers, and GET/HEAD body ownership',
1821
+ grip: 'canonical stateless framing plus bound, secret-referenced broadcast HTTP realization and stable acknowledgement',
1822
+ logging: 'best-effort redacted writes to the provider-owned stdout logging endpoint',
1823
+ schemas: 'fetch JSON decode and structured response encode',
1824
+ opaqueResponse: 'origin fetch response/body handles and direct GRIP hold responses pass through without JavaScript runtime ownership',
1825
+ transportErrors: 'host status failures remain distinct from HTTP response status',
1826
+ platformCapabilities: (plan.effects || []).some((effect) => FASTLY_NATIVE_PLATFORM_CAPABILITY_KINDS.has(effect.kind)),
1827
+ canonicalBuildLifecycle: options.canonicalBuild === true,
1828
+ realFastlyExecution: false
1829
+ }),
1830
+ harness: options.jwtReality && options.jwtReality.enabled === true
1831
+ ? Object.freeze({
1832
+ id: 'pulse.jwt-native-reality.e2',
1833
+ classifiedAsTargetBehavior: false,
1834
+ clockOverride: Number(options.jwtReality.clockUnixSeconds),
1835
+ caseHeader: 'x-pulse-e2-case'
1836
+ })
1837
+ : undefined
1838
+ });
1839
+ return Object.freeze({
1840
+ version: FASTLY_NATIVE_PLATFORM_CAPABILITIES_GENERATOR_VERSION,
1841
+ source,
1842
+ sourceHash: manifest.sourceHash,
1843
+ manifest,
1844
+ bindings,
1845
+ portable,
1846
+ realizationArtifacts: facts.realizationArtifacts,
1847
+ guestUnits: facts.guestUnits,
1848
+ jwtCrypto,
1849
+ es256KeyRecords
1850
+ });
1851
+ }
1852
+
1853
+ function inspectFastlyNativePlatformCapabilitiesWasm(input) {
1854
+ const bytes = Buffer.isBuffer(input) ? input : fs.readFileSync(path.resolve(input));
1855
+ if (!WebAssembly.validate(bytes)) fail('Generated Fastly native platform capabilities module is not valid WebAssembly.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_WASM_INVALID');
1856
+ const module = new WebAssembly.Module(bytes);
1857
+ const imports = WebAssembly.Module.imports(module).map((entry) => Object.freeze({ module: entry.module, name: entry.name, kind: entry.kind }));
1858
+ const exports = WebAssembly.Module.exports(module).map((entry) => Object.freeze({ name: entry.name, kind: entry.kind }));
1859
+ const unexpected = imports.filter((entry) => !FASTLY_NATIVE_PLATFORM_CAPABILITIES_ALLOWED_IMPORTS.has(`${entry.module}:${entry.name}`));
1860
+ if (unexpected.length > 0) fail('Generated Fastly native platform capabilities module imports functions outside the Pass98 ABI.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORT_UNSUPPORTED', { unexpected, imports });
1861
+ const forbidden = imports.filter((entry) => /pulse_host|js[_-]?compute/i.test(`${entry.module}:${entry.name}`));
1862
+ if (forbidden.length > 0) fail('Generated Fastly native platform capabilities module imports a forbidden runtime.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_RUNTIME_FORBIDDEN', { forbidden });
1863
+ const imported = new Set(imports.map((entry) => `${entry.module}:${entry.name}`));
1864
+ const missingImports = FASTLY_NATIVE_PLATFORM_CAPABILITIES_REQUIRED_IMPORTS.map(([moduleName, name]) => `${moduleName}:${name}`).filter((key) => !imported.has(key));
1865
+ if (missingImports.length > 0) fail('Generated Fastly native platform capabilities module is missing required host imports.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORT_MISSING', { missingImports, imports });
1866
+ const exportNames = new Set(exports.map((entry) => entry.name));
1867
+ 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'];
1868
+ const missingExports = requiredExports.filter((name) => !exportNames.has(name));
1869
+ if (missingExports.length > 0) fail('Generated Fastly native platform capabilities module is missing required exports.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_EXPORT_MISSING', { missingExports, exports });
1870
+ if (bytes.length > FASTLY_NATIVE_PLATFORM_CAPABILITIES_MAX_WASM_BYTES) fail('Generated Fastly native platform capabilities module exceeds the Pass98 size ceiling.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_WASM_TOO_LARGE', { bytes: bytes.length, maxBytes: FASTLY_NATIVE_PLATFORM_CAPABILITIES_MAX_WASM_BYTES });
1871
+ return Object.freeze({
1872
+ valid: true,
1873
+ bytes: bytes.length,
1874
+ sha256: sha256(bytes),
1875
+ magic: bytes.subarray(0, 8).toString('hex'),
1876
+ imports: Object.freeze(imports),
1877
+ exports: Object.freeze(exports),
1878
+ importModules: Object.freeze([...new Set(imports.map((entry) => entry.module))].sort())
1879
+ });
1880
+ }
1881
+
1882
+ function compileFastlyNativePlatformCapabilitiesPlan(plan, options = {}) {
1883
+ const generated = generateFastlyNativePlatformCapabilitiesAssemblyScript(plan, options);
1884
+ const cwd = path.resolve(options.cwd || process.cwd());
1885
+ const compilerFallback = path.resolve(__dirname, '..', '..', '..', '..', 'wasm', 'packages', 'compiler');
1886
+ const asc = resolveAsc(cwd) || resolveAsc(compilerFallback);
1887
+ if (!asc) fail('AssemblyScript compiler dependency was not found for Fastly native platform capabilities realization.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_ASC_MISSING', { cwd, compilerFallback });
1888
+ const schemaCodecsActive = generated.manifest.schemaCodecs && generated.manifest.schemaCodecs.active === true;
1889
+ const nativeOptimization = options.nativeOptimization
1890
+ || (options.experimentalNativeSize === true ? FASTLY_NATIVE_SIZE_OPTIMIZATION : undefined);
1891
+ let jsonAs;
1892
+ if (schemaCodecsActive) {
1893
+ let transform;
1894
+ try {
1895
+ transform = require.resolve('json-as', { paths: [compilerFallback, cwd] });
1896
+ } catch (error) {
1897
+ fail(
1898
+ 'The lockfile-pinned json-as transform was not found for Fastly Native schema codec compilation.',
1899
+ 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_JSON_AS_MISSING',
1900
+ { cwd, package: 'json-as', version: '1.5.0', cause: error && error.message }
1901
+ );
1902
+ }
1903
+ const packageRoot = path.resolve(transform, '..', '..', '..');
1904
+ const dependencyRoot = path.dirname(packageRoot);
1905
+ const packageJson = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
1906
+ if (packageJson.version !== '1.5.0') {
1907
+ fail(
1908
+ 'Fastly Native schema codec compilation requires json-as 1.5.0 exactly.',
1909
+ 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_JSON_AS_VERSION_INVALID',
1910
+ { expected: '1.5.0', actual: packageJson.version, packageRoot }
1911
+ );
1912
+ }
1913
+ jsonAs = Object.freeze({ transform, dependencyRoot, version: packageJson.version });
1914
+ }
1915
+ const stagingDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pulse-fastly-native-platform-'));
1916
+ const requestedOutDir = options.outDir ? path.resolve(options.outDir) : undefined;
1917
+ const outputDir = requestedOutDir || stagingDir;
1918
+ fs.mkdirSync(outputDir, { recursive: true });
1919
+ const sourceFile = path.join(stagingDir, 'fastly-native-platform-capabilities.as.ts');
1920
+ const wasmFile = path.join(outputDir, options.wasmFile || 'fastly-native-platform-capabilities.wasm');
1921
+ const watFile = path.join(outputDir, options.watFile || 'fastly-native-platform-capabilities.wat');
1922
+ const guestLinked = generated.guestUnits.length > 0;
1923
+ // asc resolves custom runtimes like module names and appends ".ts".
1924
+ const fixedMemoryRuntimeModule = path.join(__dirname, 'fixed-memory-runtime.as');
1925
+ const fixedMemoryRuntimeFile = `${fixedMemoryRuntimeModule}.ts`;
1926
+ const assemblyScriptWasmFile = guestLinked
1927
+ ? path.join(stagingDir, 'fastly-native-platform-capabilities.primary.wasm')
1928
+ : wasmFile;
1929
+ const assemblyScriptWatFile = guestLinked
1930
+ ? path.join(stagingDir, 'fastly-native-platform-capabilities.primary.wat')
1931
+ : watFile;
1932
+ try {
1933
+ fs.writeFileSync(sourceFile, generated.source, 'utf8');
1934
+ const args = [
1935
+ asc.script,
1936
+ path.basename(sourceFile),
1937
+ '--outFile', assemblyScriptWasmFile,
1938
+ '--textFile', assemblyScriptWatFile,
1939
+ '--runtime', guestLinked
1940
+ ? fixedMemoryRuntimeModule
1941
+ : (schemaCodecsActive ? 'incremental' : 'stub'),
1942
+ '--noAssert',
1943
+ '--optimize'
1944
+ ];
1945
+ const optimization = appendAssemblyScriptOptimizationArgs(args, nativeOptimization);
1946
+ if (generated.guestUnits.length > 0) {
1947
+ args.push(
1948
+ '--disable', 'bulk-memory',
1949
+ '--disable', 'nontrapping-f2i',
1950
+ '--disable', 'sign-extension',
1951
+ '--importMemory',
1952
+ '--noExportMemory',
1953
+ '--initialMemory', String(memoryAbiV2.minimumPages),
1954
+ '--maximumMemory', String(memoryAbiV2.maximumPages),
1955
+ '--memoryBase', String(memoryAbiV2.layout.primaryStatic.start),
1956
+ '--exportStart', '__pulse_initialize'
1957
+ );
1958
+ }
1959
+ args.push('--use', 'abort=fastly-native-platform-capabilities.as/__pulse_fastly_abort');
1960
+ if (schemaCodecsActive) {
1961
+ args.push(
1962
+ '--exportRuntime',
1963
+ '--transform', jsonAs.transform,
1964
+ '--path', path.join(compilerFallback, 'node_modules'),
1965
+ '--path', jsonAs.dependencyRoot
1966
+ );
1967
+ }
1968
+ const startedAt = Date.now();
1969
+ const result = spawnSync(asc.executable, args, {
1970
+ cwd: stagingDir,
1971
+ encoding: 'utf8',
1972
+ maxBuffer: 64 * 1024 * 1024,
1973
+ timeout: Number(options.timeoutMs || 180000),
1974
+ env: schemaCodecsActive
1975
+ ? { ...process.env, JSON_STRICT: 'true', JSON_USE_FAST_PATH: '0' }
1976
+ : process.env
1977
+ });
1978
+ const assemblyScriptDurationMs = Date.now() - startedAt;
1979
+ if (result.error || result.status !== 0 || !fs.existsSync(assemblyScriptWasmFile)) {
1980
+ fail('AssemblyScript failed to compile the Fastly native platform capabilities module.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_ASC_FAILED', {
1981
+ status: result.status,
1982
+ signal: result.signal,
1983
+ error: result.error && result.error.message,
1984
+ stdout: String(result.stdout || '').slice(-24000),
1985
+ stderr: String(result.stderr || '').slice(-24000),
1986
+ source: generated.source,
1987
+ durationMs: assemblyScriptDurationMs
1988
+ });
1989
+ }
1990
+ let startWrapper;
1991
+ if (guestLinked) {
1992
+ const wrapperWatFile = path.join(stagingDir, 'fastly-native-start-wrapper.wat');
1993
+ const wrapperWasmFile = path.join(stagingDir, 'fastly-native-start-wrapper.wasm');
1994
+ fs.writeFileSync(wrapperWatFile, fastlyGuestLinkedStartWrapperWat(), 'utf8');
1995
+ const wrapperStartedAt = Date.now();
1996
+ const assembled = runGuestTool(
1997
+ 'wasm-as',
1998
+ [wrapperWatFile, '--mvp-features', '-o', wrapperWasmFile],
1999
+ {
2000
+ cwd: stagingDir,
2001
+ timeoutMs: Number(options.timeoutMs || 180000),
2002
+ failureMessage: 'Fastly Native start wrapper assembly failed.'
2003
+ }
2004
+ );
2005
+ const merged = runGuestTool(
2006
+ 'wasm-merge',
2007
+ [
2008
+ assemblyScriptWasmFile,
2009
+ 'pulse_fastly_primary',
2010
+ wrapperWasmFile,
2011
+ 'pulse_fastly_entry',
2012
+ '--mvp-features',
2013
+ '-o',
2014
+ wasmFile
2015
+ ],
2016
+ {
2017
+ cwd: stagingDir,
2018
+ timeoutMs: Number(options.timeoutMs || 180000),
2019
+ failureMessage: 'Fastly Native start wrapper composition failed.'
2020
+ }
2021
+ );
2022
+ runGuestTool(
2023
+ 'wasm-dis',
2024
+ [wasmFile, '--mvp-features', '-o', watFile],
2025
+ {
2026
+ cwd: stagingDir,
2027
+ timeoutMs: Number(options.timeoutMs || 180000),
2028
+ failureMessage: 'Fastly Native start wrapper text emission failed.'
2029
+ }
2030
+ );
2031
+ startWrapper = Object.freeze({
2032
+ status: 'composed',
2033
+ initialization: 'exported-start-called-once-per-instance-before-handler',
2034
+ implicitStartSection: false,
2035
+ binaryen: binaryenIdentity(),
2036
+ wasmAs: assembled.tool,
2037
+ wasmMerge: merged.tool,
2038
+ fixedMemoryRuntime: Object.freeze({
2039
+ file: 'src/build/fixed-memory-runtime.as.ts',
2040
+ bytes: fs.statSync(fixedMemoryRuntimeFile).size,
2041
+ sha256: sha256(fs.readFileSync(fixedMemoryRuntimeFile)),
2042
+ primaryHeapStart: memoryAbiV2.layout.unallocated.start,
2043
+ primaryHeapEndExclusive: memoryAbiV2.layout.unallocated.endExclusive,
2044
+ invocationFrameExcluded: true,
2045
+ memoryGrow: false,
2046
+ bulkMemory: false
2047
+ }),
2048
+ durationMs: Date.now() - wrapperStartedAt
2049
+ });
2050
+ }
2051
+ const primaryWasm = fs.readFileSync(wasmFile);
2052
+ const primaryWat = fs.existsSync(watFile) ? fs.readFileSync(watFile, 'utf8') : '';
2053
+ const primaryArtifact = Object.freeze({
2054
+ bytes: primaryWasm.length,
2055
+ sha256: sha256(primaryWasm)
2056
+ });
2057
+ let realization = Object.freeze({
2058
+ plan,
2059
+ generated,
2060
+ source: generated.source,
2061
+ sourceHash: generated.sourceHash,
2062
+ realizationArtifacts: generated.realizationArtifacts,
2063
+ guestUnits: generated.guestUnits,
2064
+ wasm: primaryWasm,
2065
+ wat: primaryWat,
2066
+ durationMs: assemblyScriptDurationMs
2067
+ });
2068
+ if (generated.guestUnits.length > 0) {
2069
+ const stageResult = realizeGuestLinkStage({
2070
+ version: GUEST_LINK_STAGE_INVOCATION_VERSION,
2071
+ primaryWasm: realization.wasm,
2072
+ guestUnits: generated.guestUnits.map((selection) => Object.freeze({
2073
+ contribution: canonicalGuestContribution(selection),
2074
+ packageRoot: selection.packageRoot
2075
+ })),
2076
+ projectRoot: path.resolve(options.projectRoot || cwd),
2077
+ profile: String(options.profile || 'fastly-native'),
2078
+ finalWasmPolicy: options.targetDescriptor && options.targetDescriptor.finalWasmPolicy,
2079
+ synchronizedPackages: options.synchronizedPackages,
2080
+ optimizationPosture: guestLinkOptimizationPosture(nativeOptimization)
2081
+ });
2082
+ realization = Object.freeze({
2083
+ ...realization,
2084
+ wasm: stageResult.wasm,
2085
+ wat: stageResult.wat,
2086
+ guestUnits: stageResult.guestUnits,
2087
+ guestLink: Object.freeze({
2088
+ version: stageResult.version,
2089
+ plan: stageResult.plan,
2090
+ report: stageResult.report,
2091
+ audit: stageResult.audit,
2092
+ materialization: stageResult.materialization,
2093
+ finalArtifact: stageResult.finalArtifact,
2094
+ providerPackaging: stageResult.providerPackaging,
2095
+ fallback: stageResult.fallback
2096
+ })
2097
+ });
2098
+ }
2099
+ const wasm = realization.wasm;
2100
+ const wat = realization.wat;
2101
+ if (requestedOutDir && generated.guestUnits.length > 0) {
2102
+ fs.writeFileSync(wasmFile, wasm);
2103
+ fs.writeFileSync(watFile, wat, 'utf8');
2104
+ }
2105
+ const inspection = inspectFastlyNativePlatformCapabilitiesWasm(wasm);
2106
+ const imported = new Set(inspection.imports.map((entry) => `${entry.module}:${entry.name}`));
2107
+ const requiredImports = requiredImportsForPlan(plan, generated.bindings);
2108
+ const missingRequiredImports = requiredImports.filter((key) => !imported.has(key));
2109
+ if (missingRequiredImports.length > 0) fail('Generated Fastly native platform capabilities module is missing plan-required host imports.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORT_MISSING', { missingRequiredImports, imports: inspection.imports, requiredImports });
2110
+ const manifest = Object.freeze({
2111
+ ...generated.manifest,
2112
+ compilerVersion: FASTLY_NATIVE_PLATFORM_CAPABILITIES_COMPILER_VERSION,
2113
+ assemblyScript: Object.freeze({ package: 'assemblyscript', version: require(path.join(asc.packageRoot, 'package.json')).version }),
2114
+ jsonAs: jsonAs
2115
+ ? Object.freeze({ package: 'json-as', version: jsonAs.version, transform: true, strict: true })
2116
+ : undefined,
2117
+ optimization,
2118
+ wasm: Object.freeze({ bytes: inspection.bytes, sha256: inspection.sha256, magic: inspection.magic }),
2119
+ wat: Object.freeze({ bytes: Buffer.byteLength(wat), sha256: sha256(wat) }),
2120
+ importModules: inspection.importModules,
2121
+ imports: inspection.imports,
2122
+ requiredImports,
2123
+ exports: inspection.exports,
2124
+ primaryArtifact,
2125
+ startWrapper,
2126
+ ...(realization.guestLink ? {
2127
+ guestUnitPlan: realization.guestLink.plan,
2128
+ guestLinkReport: realization.guestLink.report,
2129
+ finalWasmAudit: realization.guestLink.audit,
2130
+ providerPackaging: realization.guestLink.providerPackaging
2131
+ } : {})
2132
+ });
2133
+ const durationMs = Date.now() - startedAt;
2134
+ return Object.freeze({
2135
+ version: FASTLY_NATIVE_PLATFORM_CAPABILITIES_VERSION,
2136
+ compilerVersion: FASTLY_NATIVE_PLATFORM_CAPABILITIES_COMPILER_VERSION,
2137
+ plan,
2138
+ generated,
2139
+ source: generated.source,
2140
+ sourceHash: generated.sourceHash,
2141
+ realizationArtifacts: generated.realizationArtifacts,
2142
+ guestUnits: realization.guestUnits,
2143
+ guestLink: realization.guestLink,
2144
+ wasm,
2145
+ wat,
2146
+ inspection,
2147
+ manifest,
2148
+ durationMs,
2149
+ assemblyScriptDurationMs,
2150
+ primaryArtifact,
2151
+ startWrapper,
2152
+ output: requestedOutDir ? Object.freeze({ outDir: outputDir, wasmFile, watFile }) : undefined
2153
+ });
2154
+ } finally {
2155
+ fs.rmSync(stagingDir, { recursive: true, force: true });
2156
+ }
2157
+ }
2158
+
2159
+ function writeFastlyNativePlatformCapabilitiesModule(compiled, outDir, options = {}) {
2160
+ if (!compiled || !Buffer.isBuffer(compiled.wasm) || !compiled.manifest || !compiled.plan) throw new TypeError('writeFastlyNativePlatformCapabilitiesModule requires a compiled Pass98 module.');
2161
+ const target = path.resolve(outDir);
2162
+ fs.mkdirSync(target, { recursive: true });
2163
+ const sourceFile = path.join(target, options.sourceFile || 'fastly-native-platform-capabilities.as.ts');
2164
+ const wasmFile = path.join(target, options.wasmFile || 'fastly-native-platform-capabilities.wasm');
2165
+ const watFile = path.join(target, options.watFile || 'fastly-native-platform-capabilities.wat');
2166
+ const planFile = path.join(target, options.planFile || 'canonical-native-plan.json');
2167
+ const manifestFile = path.join(target, options.manifestFile || 'fastly-native-platform-capabilities-manifest.json');
2168
+ fs.writeFileSync(sourceFile, compiled.source, 'utf8');
2169
+ fs.writeFileSync(wasmFile, compiled.wasm);
2170
+ fs.writeFileSync(watFile, compiled.wat, 'utf8');
2171
+ fs.writeFileSync(planFile, `${stableStringify(compiled.plan, 2)}\n`, 'utf8');
2172
+ fs.writeFileSync(manifestFile, `${stableStringify(compiled.manifest, 2)}\n`, 'utf8');
2173
+ return Object.freeze({ target, sourceFile, wasmFile, watFile, planFile, manifestFile, manifest: compiled.manifest });
2174
+ }
2175
+
2176
+ module.exports = Object.freeze({
2177
+ FASTLY_NATIVE_PLATFORM_CAPABILITIES_VERSION,
2178
+ FASTLY_NATIVE_PLATFORM_CAPABILITIES_GENERATOR_VERSION,
2179
+ FASTLY_NATIVE_PLATFORM_CAPABILITIES_COMPILER_VERSION,
2180
+ FASTLY_NATIVE_PLATFORM_CAPABILITIES_ABI_VERSION,
2181
+ FASTLY_NATIVE_PLATFORM_CAPABILITIES_BUFFER_BYTES,
2182
+ FASTLY_NATIVE_PLATFORM_CAPABILITIES_MAX_WASM_BYTES,
2183
+ FASTLY_NATIVE_SIZE_OPTIMIZATION,
2184
+ FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORTS,
2185
+ FASTLY_NATIVE_PLATFORM_CAPABILITIES_REQUIRED_IMPORTS,
2186
+ FASTLY_NATIVE_PLATFORM_EFFECT_KIND,
2187
+ FastlyNativePlatformCapabilitiesError,
2188
+ resolveCapabilityBindings,
2189
+ planRequiresFetchBodyRead,
2190
+ requiredImportsForPlan,
2191
+ generateFastlyNativePlatformCapabilitiesAssemblyScript,
2192
+ compileFastlyNativePlatformCapabilitiesPlan,
2193
+ inspectFastlyNativePlatformCapabilitiesWasm,
2194
+ writeFastlyNativePlatformCapabilitiesModule,
2195
+ stableStringify
2196
+ });