@pulse-compute/provider-fastly 1.0.0-beta.7 → 1.0.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -7,9 +7,9 @@
7
7
  > **Supported entry points:** `@pulse-compute/provider-fastly`, `@pulse-compute/provider-fastly/contract`, `@pulse-compute/provider-fastly/toolchain`, `@pulse-compute/provider-fastly/config-schema`, `@pulse-compute/provider-fastly/runtime/canonical-api-runtime`, `@pulse-compute/provider-fastly/build/canonical-target`, `@pulse-compute/provider-fastly/testing/fastly-cli`<br>
8
8
  > **Stability:** The listed entry points are supported for the Beta; all other exported subpaths are implementation-only.<br>
9
9
  > **npm:** [`@pulse-compute/provider-fastly`](https://www.npmjs.com/package/@pulse-compute/provider-fastly)<br>
10
- > **Canonical documentation:** [Package guide](https://pulsecompute.io/v1.0.0-beta.7/packages/provider-fastly/)
10
+ > **Canonical documentation:** [Package guide](https://pulsecompute.io/v1.0.0-beta.8/packages/provider-fastly/)
11
11
  >
12
- > This release-status block is generated from the synchronized `Pulse 1.0.0-beta.7` package policy.
12
+ > This release-status block is generated from the synchronized `Pulse 1.0.0-beta.8` package policy.
13
13
  <!-- pulse-package-status:end -->
14
14
 
15
15
  Fastly provider configuration, canonical capability lowering, local conformance execution, Compute target generation, and explicit external-tool boundaries.
@@ -49,7 +49,7 @@ trusted wall-clock authority. It does not fall back to Node execution.
49
49
 
50
50
  ## Documentation
51
51
 
52
- - [Fastly package guide](https://pulsecompute.io/v1.0.0-beta.7/packages/provider-fastly/)
53
- - [Project configuration](https://pulsecompute.io/v1.0.0-beta.7/reference/project-config/#fastly-provider-options)
54
- - [Fastly capabilities guide](https://pulsecompute.io/v1.0.0-beta.7/guides/fastly-capabilities/)
55
- - [Environment variables](https://pulsecompute.io/v1.0.0-beta.7/reference/environment/#pulse-fastly-bin)
52
+ - [Fastly package guide](https://pulsecompute.io/v1.0.0-beta.8/packages/provider-fastly/)
53
+ - [Project configuration](https://pulsecompute.io/v1.0.0-beta.8/reference/project-config/#fastly-provider-options)
54
+ - [Fastly capabilities guide](https://pulsecompute.io/v1.0.0-beta.8/guides/fastly-capabilities/)
55
+ - [Environment variables](https://pulsecompute.io/v1.0.0-beta.8/reference/environment/#pulse-fastly-bin)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pulse-compute/provider-fastly",
3
- "version": "1.0.0-beta.7",
3
+ "version": "1.0.0-beta.8",
4
4
  "license": "Apache-2.0",
5
5
  "engines": {
6
6
  "node": "^22.14.0 || ^24.0.0"
@@ -59,15 +59,15 @@
59
59
  }
60
60
  },
61
61
  "dependencies": {
62
- "@pulse-compute/crypto": "1.0.0-beta.7",
63
- "@pulse-compute/jwt": "1.0.0-beta.7",
64
- "@pulse-compute/runtime": "1.0.0-beta.7",
65
- "@pulse-compute/s3": "1.0.0-beta.7",
66
- "@pulse-compute/wasm-build-support": "1.0.0-beta.7",
67
- "@pulse-compute/wasm-contracts": "1.0.0-beta.7",
68
- "@pulse-compute/wasm-guest-link": "1.0.0-beta.7",
69
- "@pulse-compute/wasm-host-runtime": "1.0.0-beta.7",
70
- "@pulse-compute/wasm-runtime-core-as": "1.0.0-beta.7",
62
+ "@pulse-compute/crypto": "1.0.0-beta.8",
63
+ "@pulse-compute/jwt": "1.0.0-beta.8",
64
+ "@pulse-compute/runtime": "1.0.0-beta.8",
65
+ "@pulse-compute/s3": "1.0.0-beta.8",
66
+ "@pulse-compute/wasm-build-support": "1.0.0-beta.8",
67
+ "@pulse-compute/wasm-contracts": "1.0.0-beta.8",
68
+ "@pulse-compute/wasm-guest-link": "1.0.0-beta.8",
69
+ "@pulse-compute/wasm-host-runtime": "1.0.0-beta.8",
70
+ "@pulse-compute/wasm-runtime-core-as": "1.0.0-beta.8",
71
71
  "esbuild": "0.28.1"
72
72
  },
73
73
  "types": "./dist/index.d.ts",
@@ -87,7 +87,7 @@
87
87
  "url": "git+https://github.com/pulse-compute/pulse.git",
88
88
  "directory": "packages/provider-fastly"
89
89
  },
90
- "homepage": "https://pulsecompute.io/v1.0.0-beta.7/packages/provider-fastly/",
90
+ "homepage": "https://pulsecompute.io/v1.0.0-beta.8/packages/provider-fastly/",
91
91
  "bugs": {
92
92
  "url": "https://github.com/pulse-compute/pulse/issues"
93
93
  },
@@ -244,6 +244,7 @@ function inspectFastlyCanonicalTarget(options = {}) {
244
244
  || (options.native && options.native.guestUnits),
245
245
  nativeOptimization: options.nativeOptimization
246
246
  || (options.experimentalNativeSize === true ? 'experimental-native-size' : undefined),
247
+ elideJsonCacheArena: options.elideJsonCacheArena,
247
248
  emitWat: options.emitWat,
248
249
  timeoutMs: options.compileTimeoutMs
249
250
  });
@@ -320,6 +321,7 @@ function writeFastlyCanonicalTarget(options = {}) {
320
321
  || (options.native && options.native.guestUnits),
321
322
  nativeOptimization: options.nativeOptimization
322
323
  || (options.experimentalNativeSize === true ? 'experimental-native-size' : undefined),
324
+ elideJsonCacheArena: options.elideJsonCacheArena,
323
325
  emitWat: options.emitWat,
324
326
  compileTimeoutMs: options.compileTimeoutMs
325
327
  });
@@ -496,6 +496,7 @@ function compileFastlyEntitiesNative(sourceArtifact, options = {}) {
496
496
  '--path', path.join(compilerFallback, 'node_modules'),
497
497
  '--path', path.dirname(jsonAsRoot)
498
498
  ];
499
+ require('@pulse-compute/wasm-build-support/native-optimization').appendJsonCacheArenaArgs(args, options.elideJsonCacheArena, true);
499
500
  const startedAt = Date.now();
500
501
  const result = spawnSync(asc.executable, args, {
501
502
  cwd: staging,
@@ -546,6 +547,7 @@ function compileFastlyEntitiesNative(sourceArtifact, options = {}) {
546
547
  package: 'assemblyscript',
547
548
  version: JSON.parse(fs.readFileSync(path.join(asc.packageRoot, 'package.json'), 'utf8')).version,
548
549
  jsonAs: jsonAsManifest.version,
550
+ elideDisabledCacheArena: options.elideJsonCacheArena === true,
549
551
  durationMs: Date.now() - startedAt
550
552
  }),
551
553
  policy: generated.policy
@@ -80,12 +80,16 @@ function __kv_number(value: f64): string {
80
80
  // Count the portable serialized value budget, including this boundary case.
81
81
  return text.endsWith('.0') ? text.substring(0, text.length - 2) : text;
82
82
  }
83
- // Return the same quoted form registered for redaction so validation and writes
84
- // do not allocate and scan a second representation of each string or key.
85
- function __kv_private(text: string): string {
86
- __pulse_fastly_remember_secret(text);
83
+ // Object field names are complete quoted tokens, not substring secrets: a field
84
+ // named "id" must not corrupt "considered", "invalidAcks", or numeric metrics.
85
+ // Values, lookup keys and generations retain raw and JSON-escaped protection.
86
+ function __kv_private(text: string, field: bool = false): string {
87
87
  const encoded = __pulse_fastly_quote(text);
88
- __pulse_fastly_remember_secret(encoded.substring(1, encoded.length - 1));
88
+ if (field) __pulse_fastly_remember_secret(encoded, true);
89
+ else {
90
+ __pulse_fastly_remember_secret(text);
91
+ __pulse_fastly_remember_secret(encoded.substring(1, encoded.length - 1));
92
+ }
89
93
  return encoded;
90
94
  }
91
95
  class __KvEncoder {
@@ -107,7 +111,7 @@ class __KvEncoder {
107
111
  const object = value.kind == PULSE_VALUE_OBJECT; this.add(object ? '{' : '[');
108
112
  for (let i = 0; i < value.values.length && !this.reason.length; i++) {
109
113
  if (i) this.add(',');
110
- if (object) this.add(__kv_private(value.keys[i]) + ':');
114
+ if (object) this.add(__kv_private(value.keys[i], true) + ':');
111
115
  this.visit(value.values[i], depth + 1);
112
116
  }
113
117
  this.add(object ? '}' : ']');
@@ -4,8 +4,13 @@ function enabled(plan) {
4
4
  return (plan.routing?.entries || []).some(entry => entry.kind === 'error');
5
5
  }
6
6
 
7
+ // Fetch-only applications also drain failed groups before their terminal response.
8
+ function settlementEnabled(plan) {
9
+ return enabled(plan) || (!plan.packages?.application && (plan.effects || []).some(effect => effect.kind === 'fetch'));
10
+ }
11
+
7
12
  // Capture provider diagnostics before clearing them. A failed continuation is
8
- // drained once; only its application data error can enter the next Router lane.
13
+ // drained once; only an admitted application error can enter the next Router lane.
9
14
  function runtimeSource(plan) {
10
15
  const jwt = ['TOKEN_REQUIRED', 'BEARER_INVALID', 'MALFORMED', 'LIMIT_EXCEEDED',
11
16
  'ALGORITHM_NOT_ALLOWED', 'KEY_INVALID', 'SIGNATURE_INVALID', 'CLOCK_INVALID',
@@ -14,6 +19,7 @@ function runtimeSource(plan) {
14
19
  let __pulse_application_schema: i32 = 0
15
20
  let __pulse_application_failed_schema: i32 = 0
16
21
  function __pulse_application_code(): string {
22
+ if (__pulse_fastly_last_error == PULSE_ERROR_TRANSPORT && __pulse_fetch_failed()) return __pulse_fastly_error_stage == 271 ? "PULSE_FETCH_TIMEOUT" : "PULSE_FETCH_NETWORK"
17
23
  if (__pulse_fastly_last_error == PULSE_ERROR_REQUEST_BODY)
18
24
  return __pulse_fastly_error_stage == 21 ? "PULSE_BODY_TOO_LARGE" : "PULSE_REQUEST_BODY_INVALID_UTF8"
19
25
  if (__pulse_fastly_jwt_error > 0) {
@@ -40,7 +46,7 @@ function __pulse_application_clear(): void {
40
46
  __pulse_fastly_last_error = 0; __pulse_fastly_error_stage = 0; __pulse_fastly_error_effect = -1
41
47
  __pulse_fastly_jwt_error = 0; __pulse_application_failed_schema = 0
42
48
  }
43
- ${(plan?.effects || []).length > 0 ? settlementSource() : ''}
49
+ ${(plan?.effects || []).length > 0 ? settlementSource(plan) : ''}
44
50
  function host_router_error_take(): i32 {
45
51
  if (__pulse_fastly_last_error == 0) return 0
46
52
  const code = __pulse_application_code()
@@ -52,7 +58,7 @@ function host_router_error_take(): i32 {
52
58
  const error = host_value_object()
53
59
  host_value_object_set(error, __pulse_fastly_string_value("code"), __pulse_fastly_string_value(code))
54
60
  host_value_object_set(error, __pulse_fastly_string_value("name"), __pulse_fastly_string_value("PulseApplicationError"))
55
- host_value_object_set(error, __pulse_fastly_string_value("message"), __pulse_fastly_string_value("Pulse application data validation failed."))
61
+ host_value_object_set(error, __pulse_fastly_string_value("message"), __pulse_fastly_string_value(code == "PULSE_FETCH_TIMEOUT" ? "Fetch header deadline exceeded." : code == "PULSE_FETCH_NETWORK" ? "Fetch transport failed." : "Pulse application data validation failed."))
56
62
  return error
57
63
  }
58
64
  `;
@@ -61,7 +67,7 @@ function host_router_error_take(): i32 {
61
67
  // The caller retains the static pending-slot guards. The shared body owns one
62
68
  // site's resolution and authenticated settlement; diagnostics carry the saved
63
69
  // failure between calls without allocating an accumulator or merging slot state.
64
- function settlementSource() {
70
+ function settlementSource(plan) {
65
71
  return `
66
72
  // Returns 0 for recoverable/no failure, 1 for fatal, -1 for rejected settlement.
67
73
  function __pulse_application_settle_effect(index: i32, fatal: bool): i32 {
@@ -78,7 +84,7 @@ function __pulse_application_settle_effect(index: i32, fatal: bool): i32 {
78
84
  if (result <= 0 && __pulse_fastly_last_error == 0) __pulse_fastly_fail(PULSE_ERROR_STATE, 101, index)
79
85
  } else if (failure == 0) __pulse_fastly_fail(PULSE_ERROR_STATE, 101, index)
80
86
  if (__pulse_fastly_last_error != 0) {
81
- const terminal = __pulse_application_code().length == 0
87
+ const terminal = ${enabled(plan) ? '__pulse_application_code().length == 0' : 'true'}
82
88
  if (failure == 0 || (!fatal && terminal)) {
83
89
  failure = __pulse_fastly_last_error; stage = __pulse_fastly_error_stage; effect = __pulse_fastly_error_effect
84
90
  jwt = __pulse_fastly_jwt_error; schema = __pulse_application_failed_schema; fatal = terminal
@@ -99,13 +105,13 @@ function __pulse_application_settle_effect(index: i32, fatal: bool): i32 {
99
105
  // Preserve the fatal-return boundary consumed by request-budget instrumentation.
100
106
  function driverLoop(plan) {
101
107
  return ` while (runStatus == 1) {
102
- let fatal = __pulse_fastly_last_error != 0 && __pulse_application_code().length == 0
108
+ let fatal = __pulse_fastly_last_error != 0${enabled(plan) ? ' && __pulse_application_code().length == 0' : ''}
103
109
  ${(plan.effects || []).map((_, index) => ` if (__pulse_effect_pending_${index} != 0) {
104
110
  const settled = __pulse_application_settle_effect(${index}, fatal)
105
111
  if (settled < 0) return
106
112
  fatal = settled != 0
107
113
  }`).join('\n')}
108
- if (fatal) return
114
+ ${enabled(plan) ? 'if (fatal) return' : 'if (fatal) { __pulse_fastly_jwt_send_error(); return }'}
109
115
  runStatus = pulse_resume()
110
116
  }`;
111
117
  }
@@ -137,4 +143,4 @@ function instrument(source) {
137
143
  return source;
138
144
  }
139
145
 
140
- module.exports = Object.freeze({ enabled, runtimeSource, driverLoop, instrument });
146
+ module.exports = Object.freeze({ enabled, settlementEnabled, runtimeSource, driverLoop, instrument });
@@ -0,0 +1,161 @@
1
+ // Per-invocation, per-admission header deadlines. A reused effect site gets a new
2
+ // clock sample; waiting on an earlier group member cannot replenish this budget.
3
+ @external('fastly_async_io', 'select')
4
+ declare function __pulse_fetch_select(handles: usize, count: i32, timeout: i32, done: usize): i32
5
+ @external('fastly_http_req', 'pending_req_poll_v2')
6
+ declare function __pulse_fetch_poll(handle: i32, detail: usize, done: usize, response: usize, body: usize): i32
7
+ @external('fastly_http_resp', 'close')
8
+ declare function __pulse_fetch_close_response(handle: i32): i32
9
+ const __pulse_fetch_timeout = new StaticArray<f64>(PULSE_FASTLY_EFFECT_COUNT)
10
+ const __pulse_fetch_started = new StaticArray<i64>(PULSE_FASTLY_EFFECT_COUNT)
11
+ const __pulse_fetch_completed = new StaticArray<bool>(PULSE_FASTLY_EFFECT_COUNT)
12
+ // Zero = headers, positive = Fastly status, -1 = timeout, -2 = protocol/clock.
13
+ const __pulse_fetch_outcome = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
14
+ const __pulse_fetch_retired = new Array<i32>()
15
+ let __pulse_fetch_last_clock: i64 = -1
16
+ let __pulse_fetch_retired_total: i32 = 0
17
+ export function pulse_fastly_fetch_retired(): i32 { return __pulse_fetch_retired_total }
18
+ export function pulse_fastly_fetch_unreaped(): i32 { return __pulse_fetch_retired.length }
19
+ function __pulse_fetch_clock(index: i32): i64 {
20
+ const out = new StaticArray<i64>(1)
21
+ if (wasi_snapshot_preview1_clock_time_get(1, 1, changetype<usize>(out)) != 0
22
+ || out[0] < 0 || out[0] < __pulse_fetch_last_clock) {
23
+ __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 272, index); return -1
24
+ }
25
+ __pulse_fetch_last_clock = out[0]; return out[0]
26
+ }
27
+ function __pulse_fetch_begin_deadline(index: i32, init: __PulseFastlyValue): void {
28
+ __pulse_fetch_timeout[index] = 0; __pulse_fetch_completed[index] = false; __pulse_fetch_outcome[index] = 0
29
+ const field = __pulse_fastly_find(init, 'timeoutMs')
30
+ if (field < 0) return
31
+ const value = __pulse_fastly_value(unchecked(init.values[field]))
32
+ if (value.kind == PULSE_VALUE_UNDEFINED) return
33
+ const ms = value.number
34
+ if (value.kind != PULSE_VALUE_NUMBER || ms <= 0 || ms > 9007199254740991 || Math.floor(ms) != ms) {
35
+ __pulse_fastly_fail(PULSE_ERROR_VALUE, 270, index); return
36
+ }
37
+ __pulse_fetch_timeout[index] = ms
38
+ __pulse_fetch_started[index] = __pulse_fetch_clock(index)
39
+ }
40
+ function __pulse_fetch_remaining(index: i32, now: i64): f64 {
41
+ if (__pulse_fetch_timeout[index] == 0) return 2147483647.0
42
+ // Subtract elapsed nanoseconds before converting. Do not overflow by adding
43
+ // a safe-integer millisecond option to an i64 nanosecond clock.
44
+ return __pulse_fetch_timeout[index] - f64(now - __pulse_fetch_started[index]) / 1000000.0
45
+ }
46
+ function __pulse_fetch_before_send(index: i32): bool {
47
+ if (__pulse_fastly_effect_kind(index) != 1 || __pulse_fetch_timeout[index] == 0) return true
48
+ const now = __pulse_fetch_clock(index)
49
+ if (now < 0) return false
50
+ if (__pulse_fetch_remaining(index, now) > 0) return true
51
+ __pulse_fastly_fail(PULSE_ERROR_TRANSPORT, 271, index); return false
52
+ }
53
+ function __pulse_fetch_active(index: i32): bool {
54
+ return __pulse_fastly_effect_kind(index) == 1 && __pulse_fastly_pending_mode[index] == PULSE_FASTLY_PENDING_ASYNC
55
+ }
56
+ function __pulse_fetch_has_deadlines(): bool {
57
+ for (let i = 0; i < PULSE_FASTLY_EFFECT_COUNT; i++)
58
+ if (__pulse_fetch_active(i) && __pulse_fetch_timeout[i] > 0) return true
59
+ return false
60
+ }
61
+ function __pulse_fetch_complete(index: i32, outcome: i32, result: i32 = 0): void {
62
+ __pulse_fastly_pending_mode[index] = PULSE_FASTLY_PENDING_READY
63
+ __pulse_fastly_pending[index] = 0; __pulse_fastly_ready[index] = result
64
+ __pulse_fetch_completed[index] = true; __pulse_fetch_outcome[index] = outcome
65
+ }
66
+ function __pulse_fetch_retire(index: i32, outcome: i32): void {
67
+ // The Fastly ABI has no pending-request cancellation hostcall. Retain explicit
68
+ // ownership until invocation cleanup; never wait, retry, or claim rollback.
69
+ __pulse_fetch_retired.push(__pulse_fastly_pending[index]); __pulse_fetch_retired_total++
70
+ __pulse_fetch_complete(index, outcome)
71
+ }
72
+ function __pulse_fetch_retire_all(): void {
73
+ for (let i = 0; i < PULSE_FASTLY_EFFECT_COUNT; i++) if (__pulse_fetch_active(i)) __pulse_fetch_retire(i, -2)
74
+ }
75
+ function __pulse_fetch_reap(): void {
76
+ const detail = new StaticArray<i32>(4), done = new StaticArray<i32>(1)
77
+ const response = new StaticArray<i32>(1), body = new StaticArray<i32>(1)
78
+ for (let i = __pulse_fetch_retired.length - 1; i >= 0; i--) {
79
+ done[0] = 0
80
+ const status = __pulse_fetch_poll(__pulse_fetch_retired[i], changetype<usize>(detail), changetype<usize>(done), changetype<usize>(response), changetype<usize>(body))
81
+ if (status == 0 && done[0] == 0) continue
82
+ if (status == 0 && done[0] == 1) { __pulse_fetch_close_response(response[0]); __pulse_fetch_close_body(body[0]) }
83
+ __pulse_fetch_retired[i] = __pulse_fetch_retired[__pulse_fetch_retired.length - 1]; __pulse_fetch_retired.pop()
84
+ }
85
+ // Unready handles remain platform-owned until host teardown. No guest task
86
+ // survives _start and no response/body is exposed for an expired operation.
87
+ }
88
+ // Request-budget instrumentation replaces these hooks when maxDurationMs exists.
89
+ function __pulse_fetch_request_check(index: i32): bool { return true }
90
+ function __pulse_fetch_request_remaining(): i32 { return 2147483647 }
91
+ function __pulse_fetch_take(index: i32): i32 {
92
+ const outcome = __pulse_fetch_outcome[index], result = __pulse_fastly_ready[index]
93
+ __pulse_fetch_completed[index] = false; __pulse_fastly_pending_mode[index] = PULSE_FASTLY_PENDING_NONE
94
+ __pulse_fastly_ready[index] = 0
95
+ if (outcome == -1) __pulse_fastly_fail(PULSE_ERROR_TRANSPORT, 271, index)
96
+ else if (outcome == -2) __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 272, index)
97
+ else if (outcome != 0) __pulse_fetch_fail(outcome, 81, index)
98
+ return outcome == 0 ? result : 0
99
+ }
100
+ function __pulse_fetch_wait(index: i32): i32 {
101
+ const handles = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT), selected = new StaticArray<i32>(1)
102
+ const detail = new StaticArray<i32>(4), done = new StaticArray<i32>(1)
103
+ const response = new StaticArray<i32>(1), body = new StaticArray<i32>(1)
104
+ while (!__pulse_fetch_completed[index]) {
105
+ if (!__pulse_fetch_request_check(index)) { __pulse_fetch_retire_all(); return 0 }
106
+ let now = __pulse_fetch_clock(index)
107
+ if (now < 0) { __pulse_fetch_retire_all(); return 0 }
108
+ let count = 0, remaining = 2147483647.0
109
+ // Observe all dispatched fetches, not just the first static slot. Otherwise
110
+ // a slow earlier sibling could turn timely later headers into a false timeout.
111
+ for (let i = 0; i < PULSE_FASTLY_EFFECT_COUNT; i++) {
112
+ if (!__pulse_fetch_active(i)) continue
113
+ if (__pulse_fetch_remaining(i, now) <= 0) { __pulse_fetch_retire(i, -1); continue }
114
+ done[0] = 0
115
+ const status = __pulse_fetch_poll(__pulse_fastly_pending[i], changetype<usize>(detail), changetype<usize>(done), changetype<usize>(response), changetype<usize>(body))
116
+ now = __pulse_fetch_clock(i)
117
+ if (status != 0) {
118
+ __pulse_fetch_complete(i, now < 0 ? -2 : __pulse_fetch_remaining(i, now) <= 0 ? -1 : status)
119
+ if (now < 0) { __pulse_fetch_retire_all(); return 0 }
120
+ continue
121
+ }
122
+ if (done[0] != 0 && done[0] != 1) {
123
+ __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 272, i); __pulse_fetch_retire_all(); return 0
124
+ }
125
+ if (now < 0 || __pulse_fetch_remaining(i, now) <= 0) {
126
+ if (done[0] == 1) {
127
+ __pulse_fetch_close_response(response[0]); __pulse_fetch_close_body(body[0]); __pulse_fetch_complete(i, now < 0 ? -2 : -1)
128
+ } else __pulse_fetch_retire(i, now < 0 ? -2 : -1)
129
+ if (now < 0) { __pulse_fetch_retire_all(); return 0 }
130
+ continue
131
+ }
132
+ if (done[0] == 1) {
133
+ const value = new __PulseFastlyValue(); value.kind = PULSE_VALUE_FETCH
134
+ value.responseHandle = response[0]; value.bodyHandle = body[0]
135
+ __pulse_fetch_complete(i, 0, __pulse_fastly_put(value)); continue
136
+ }
137
+ }
138
+ if (__pulse_fetch_completed[index]) break
139
+ if (!__pulse_fetch_request_check(index)) { __pulse_fetch_retire_all(); return 0 }
140
+ now = __pulse_fetch_clock(index)
141
+ if (now < 0) { __pulse_fetch_retire_all(); return 0 }
142
+ for (let i = 0; i < PULSE_FASTLY_EFFECT_COUNT; i++) {
143
+ if (!__pulse_fetch_active(i)) continue
144
+ const budget = __pulse_fetch_remaining(i, now)
145
+ if (budget <= 0) { __pulse_fetch_retire(i, -1); continue }
146
+ handles[count++] = __pulse_fastly_pending[i]; remaining = Math.min(remaining, budget)
147
+ }
148
+ if (__pulse_fetch_completed[index]) break
149
+ remaining = Math.min(remaining, f64(__pulse_fetch_request_remaining()))
150
+ if (count == 0 || remaining <= 0) {
151
+ __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 272, index); __pulse_fetch_retire_all(); return 0
152
+ }
153
+ selected[0] = -2
154
+ const status = __pulse_fetch_select(changetype<usize>(handles), count, i32(Math.ceil(remaining)), changetype<usize>(selected))
155
+ const after = __pulse_fetch_clock(index)
156
+ if (status != 0 || selected[0] < -1 || selected[0] >= count || after < 0 || (selected[0] == -1 && after <= now)) {
157
+ __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 272, index); __pulse_fetch_retire_all(); return 0
158
+ }
159
+ }
160
+ return __pulse_fetch_take(index)
161
+ }
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+ const fs = require('node:fs');
3
+ const path = require('node:path');
4
+ function enabled(plan) { return (plan.effects || []).some(effect => effect.kind === 'fetch'); }
5
+ function runtimeSource(plan) {
6
+ if (!enabled(plan)) return `function __pulse_fetch_has_deadlines(): bool { return false }
7
+ function __pulse_fetch_request_check(index: i32): bool { return true }
8
+ function __pulse_fetch_request_remaining(): i32 { return 2147483647 }`;
9
+ return fs.readFileSync(path.join(__dirname,'native-fetch-deadlines.as.ts'),'utf8');
10
+ }
11
+ function instrument(input, plan) {
12
+ if (!enabled(plan)) return input;
13
+ let source = input;
14
+ const replace = (before,after) => {
15
+ if (!source.includes(before)) throw new Error('Fastly fetch deadline boundary drift: ' + before.slice(0,80));
16
+ source = source.replace(before,after);
17
+ };
18
+ replace('const init = initIndex >= 0 ? __pulse_fastly_value(unchecked(payload.values[initIndex])) : new __PulseFastlyValue(); let method',
19
+ 'const init = initIndex >= 0 ? __pulse_fastly_value(unchecked(payload.values[initIndex])) : new __PulseFastlyValue(); __pulse_fetch_begin_deadline(effectIndex, init); if (__pulse_fastly_last_error != 0) return; let method');
20
+ replace('const backendBytes = __pulse_fastly_utf8(backend); const pendingOut',
21
+ 'if (!__pulse_fetch_before_send(effectIndex)) { __pulse_fetch_close_request(requestHandle); __pulse_fetch_close_body(bodyHandle); return; } const backendBytes = __pulse_fastly_utf8(backend); const pendingOut');
22
+ replace('function __pulse_fastly_wait_fetch(effectIndex: i32): i32 {',
23
+ 'function __pulse_fastly_wait_fetch(effectIndex: i32): i32 { if (__pulse_fastly_effect_kind(effectIndex) == 1 && (__pulse_fetch_completed[effectIndex] || __pulse_fetch_has_deadlines())) return __pulse_fetch_wait(effectIndex);');
24
+ replace('function __pulse_invocation_close(): void {', 'function __pulse_invocation_close(): void { __pulse_fetch_reap();');
25
+ return source;
26
+ }
27
+ module.exports = {runtimeSource,instrument};
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ function runtimeSource() {
4
+ return `
5
+ @external("fastly_http_req", "close")
6
+ declare function __pulse_fetch_close_request(handle: i32): i32
7
+ @external("fastly_http_body", "close")
8
+ declare function __pulse_fetch_close_body(handle: i32): i32
9
+ function __pulse_fetch_fail(status: i32, stage: i32, effect: i32): void {
10
+ // Fastly ERROR and HTTP parse/user/incomplete/size/status errors represent
11
+ // failed exchanges. Invalid arguments, handles and unsupported ABI stay fatal.
12
+ const network = __pulse_fastly_effect_kind(effect) != 1 || status == 1 || status == 7 || status == 8 || status == 9 || status == 11 || status == 12;
13
+ __pulse_fastly_fail(network ? PULSE_ERROR_TRANSPORT : PULSE_ERROR_HOSTCALL, stage, effect);
14
+ }
15
+ function __pulse_fetch_failed(): bool {
16
+ return (__pulse_fastly_last_error == PULSE_ERROR_TRANSPORT || __pulse_fastly_last_error == PULSE_ERROR_HOSTCALL || __pulse_fastly_last_error == PULSE_ERROR_VALUE)
17
+ && (__pulse_fastly_error_stage == 77 || __pulse_fastly_error_stage == 81 || (__pulse_fastly_error_stage >= 270 && __pulse_fastly_error_stage <= 272))
18
+ && __pulse_fastly_effect_kind(__pulse_fastly_error_effect) == 1;
19
+ }
20
+ function __pulse_fetch_send_error(): bool {
21
+ if (!__pulse_fetch_failed()) return false;
22
+ const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE;
23
+ const network = __pulse_fastly_last_error == PULSE_ERROR_TRANSPORT;
24
+ output.status = __pulse_fastly_error_stage == 270 ? 400 : __pulse_fastly_error_stage == 271 ? 504 : network ? 502 : 500;
25
+ output.text = __pulse_fastly_error_stage == 270 ? "Invalid fetch timeoutMs" : __pulse_fastly_error_stage == 271 ? "Gateway Timeout" : network ? "Bad Gateway" : "Internal Server Error";
26
+ output.headers.push(new __PulseFastlyHeader("content-type", "text/plain; charset=utf-8"));
27
+ __pulse_fastly_send_result(__pulse_fastly_put(output));
28
+ return true;
29
+ }
30
+ `;
31
+ }
32
+ function instrument(source) {
33
+ // Keep the fatal marker for the deadline owner, which runs after this pass.
34
+ source = source.replace('if (fatal) return',
35
+ 'if (fatal && __pulse_fetch_failed()) { __pulse_fastly_jwt_send_error(); return; }\n if (fatal) return');
36
+ const marker = 'function __pulse_fastly_jwt_send_error(): void {';
37
+ if (!source.includes(marker)) throw new Error('Fastly fetch error boundary drift.');
38
+ return source.replace(marker, marker + ' if (__pulse_fetch_send_error()) return;');
39
+ }
40
+ module.exports = {runtimeSource, instrument};
@@ -0,0 +1,54 @@
1
+ 'use strict';
2
+
3
+ function runtimeSource() {
4
+ return `
5
+ @external("fastly_http_resp", "header_values_get")
6
+ declare function __pulse_response_header_values(handle: i32, name: usize, length: i32, buffer: usize, size: i32, cursor: i32, end: usize, written: usize): i32
7
+ function __pulse_header_lookup_failed(): bool {
8
+ return __pulse_fastly_last_error == PULSE_ERROR_HOSTCALL && (__pulse_fastly_error_stage == 22 || __pulse_fastly_error_stage == 23);
9
+ }
10
+ function __pulse_header_lookup(handle: i32, name: string, response: bool): string | null {
11
+ const key = __pulse_fastly_utf8(name), buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES);
12
+ const end = new StaticArray<i64>(1), written = new StaticArray<i32>(1);
13
+ written[0] = -1;
14
+ // The single-value getter reports INVALID_ARGUMENT for absence on Viceroy.
15
+ // The list ABI distinguishes no values (zero bytes) from an empty value (NUL).
16
+ const status = response
17
+ ? __pulse_response_header_values(handle, changetype<usize>(key), key.byteLength, buffer.dataStart, buffer.length, 0, changetype<usize>(end), changetype<usize>(written))
18
+ : __pulse_request_header_values(handle, changetype<usize>(key), key.byteLength, buffer.dataStart, buffer.length, 0, changetype<usize>(end), changetype<usize>(written));
19
+ const count = written[0], next = end[0];
20
+ if (status == FASTLY_STATUS_OK && count == 0 && (next == -1 || next == 0)) return null;
21
+ if (status != FASTLY_STATUS_OK || count <= 0 || count > buffer.length
22
+ || (next != -1 && (next <= 0 || next > 4294967295)) || buffer[count - 1] != 0) {
23
+ __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, response ? 23 : 22, -1); return null;
24
+ }
25
+ // Pulse's singular accessor returns the first value, including an empty one.
26
+ for (let i = 0; i < count; i++) {
27
+ if (buffer[i] == 0) return String.UTF8.decodeUnsafe(buffer.dataStart, i, false);
28
+ }
29
+ __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, response ? 23 : 22, -1); return null;
30
+ }
31
+ function __pulse_header_send_error(): bool {
32
+ if (!__pulse_header_lookup_failed()) return false;
33
+ const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE;
34
+ output.status = 500; output.text = "Internal Server Error";
35
+ output.headers.push(new __PulseFastlyHeader("content-type", "text/plain; charset=utf-8"));
36
+ // Keep the original hostcall stage available to diagnostics.
37
+ __pulse_fastly_send_result(__pulse_fastly_put(output));
38
+ return true;
39
+ }
40
+ `;
41
+ }
42
+ function instrument(source) {
43
+ source = source.replace(/function (host_\w+)\(([^)]*)\): (i32|void) \{/g,
44
+ (declaration, name, _args, result) => name === 'host_router_error_take' ? declaration
45
+ : `${declaration} if (__pulse_header_lookup_failed()) return${result === 'void' ? '' : ' 0'};`);
46
+ // Header reads performed while settling an effect have a separate fatal exit.
47
+ // Retain its marker so request-budget instrumentation still owns timeout priority.
48
+ source = source.replace('if (fatal) return',
49
+ 'if (fatal && __pulse_header_lookup_failed()) { __pulse_fastly_jwt_send_error(); return; }\n if (fatal) return');
50
+ const marker = 'function __pulse_fastly_jwt_send_error(): void {';
51
+ if (!source.includes(marker)) throw new Error('Fastly header-lookup error boundary drift.');
52
+ return source.replace(marker, marker + ' if (__pulse_header_send_error()) return;');
53
+ }
54
+ module.exports = {runtimeSource, instrument};
@@ -880,6 +880,7 @@ function compileFastlyNativeHttpEffectsPlan(plan, options = {}) {
880
880
  '--path', jsonAs.dependencyRoot
881
881
  );
882
882
  }
883
+ require('@pulse-compute/wasm-build-support/native-optimization').appendJsonCacheArenaArgs(args, options.elideJsonCacheArena, schemaCodecsActive);
883
884
  const startedAt = Date.now();
884
885
  const result = spawnSync(asc.executable, args, {
885
886
  cwd: stagingDir,
@@ -910,7 +911,7 @@ function compileFastlyNativeHttpEffectsPlan(plan, options = {}) {
910
911
  compilerVersion: FASTLY_NATIVE_HTTP_EFFECTS_COMPILER_VERSION,
911
912
  assemblyScript: Object.freeze({ package: 'assemblyscript', version: require(path.join(asc.packageRoot, 'package.json')).version }),
912
913
  jsonAs: jsonAs
913
- ? Object.freeze({ package: 'json-as', version: jsonAs.version, transform: true, strict: true, mode: 'NAIVE', fastPath: false })
914
+ ? Object.freeze({ package: 'json-as', version: jsonAs.version, transform: true, strict: true, mode: 'NAIVE', fastPath: false, elideDisabledCacheArena: options.elideJsonCacheArena === true })
914
915
  : undefined,
915
916
  wasm: Object.freeze({ bytes: inspection.bytes, sha256: inspection.sha256, magic: inspection.magic }),
916
917
  wat: Object.freeze({ bytes: Buffer.byteLength(wat), sha256: sha256(wat) }),
@@ -126,6 +126,7 @@ const FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORTS = Object.freeze([
126
126
  Object.freeze(['fastly_http_resp', 'new']),
127
127
  Object.freeze(['fastly_http_resp', 'header_append']),
128
128
  Object.freeze(['fastly_http_resp', 'header_value_get']),
129
+ Object.freeze(['fastly_http_resp', 'header_values_get']),
129
130
  Object.freeze(['fastly_http_resp', 'status_get']),
130
131
  Object.freeze(['fastly_http_resp', 'status_set']),
131
132
  Object.freeze(['fastly_http_resp', 'send_downstream']),
@@ -988,6 +989,7 @@ function requiredImportsForPlan(plan, bindings) {
988
989
  'fastly_http_req:header_insert', 'fastly_http_req:send_async', 'fastly_http_req:pending_req_wait'
989
990
  ]) keys.add(key);
990
991
  }
992
+ if (kinds.has('fetch')) for (const key of ['wasi_snapshot_preview1:clock_time_get', 'fastly_async_io:select', 'fastly_http_req:pending_req_poll_v2', 'fastly_http_resp:close', 'fastly_http_body:close']) keys.add(key);
991
993
  if (planRequiresFetchBodyRead(plan)) keys.add('fastly_http_body:read');
992
994
  if (kinds.has('config.get')) for (const key of ['fastly_config_store:open', 'fastly_config_store:get']) keys.add(key);
993
995
  const gripAuthenticationRequired = kinds.has('grip.broadcast')
@@ -1651,6 +1653,7 @@ const PULSE_FASTLY_PENDING_READY: i32 = 2
1651
1653
  @lazy const __pulse_fastly_ready = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
1652
1654
  @lazy const __pulse_fastly_grip_channels = new Array<string>()
1653
1655
  @lazy const __pulse_fastly_redactions = new Array<string>()
1656
+ @lazy const __pulse_fastly_field_redactions = new Array<string>()
1654
1657
  let __pulse_fastly_request_handle: i32 = 0
1655
1658
  let __pulse_fastly_request_body_handle: i32 = 0
1656
1659
  let __pulse_fastly_request_method: string = ""
@@ -1695,9 +1698,31 @@ function __pulse_fastly_string_value(value: string): i32 {
1695
1698
  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 }
1696
1699
  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() }
1697
1700
  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) }
1698
- 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 }
1701
+ function __pulse_fastly_remember_secret(value: string, field: bool = false): string { if (value.length == 0) return value; const values = field ? __pulse_fastly_field_redactions : __pulse_fastly_redactions; for (let i = 0; i < values.length; i += 1) if (unchecked(values[i]) == value) return value; values.push(value); return value }
1699
1702
  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) } }
1700
- 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 }
1703
+ // Walk complete JSON string tokens, including escaped quotes. Substring matching
1704
+ // a quoted field would still corrupt an unrelated token such as "prefix\\\"id".
1705
+ function __pulse_fastly_redact_fields(input: string): string {
1706
+ if (__pulse_fastly_field_redactions.length == 0) return input;
1707
+ let output = "", start = 0, cursor = 0;
1708
+ while (cursor < input.length) {
1709
+ if (input.charCodeAt(cursor) != 34) { cursor += 1; continue; }
1710
+ const begin = cursor++;
1711
+ while (cursor < input.length) {
1712
+ const code = input.charCodeAt(cursor++);
1713
+ if (code == 92 && cursor < input.length) cursor += 1;
1714
+ else if (code == 34) break;
1715
+ }
1716
+ const token = input.substring(begin, cursor);
1717
+ for (let i = 0; i < __pulse_fastly_field_redactions.length; i += 1) {
1718
+ if (token != unchecked(__pulse_fastly_field_redactions[i])) continue;
1719
+ output += input.substring(start, begin) + __pulse_fastly_quote("<redacted>");
1720
+ start = cursor; break;
1721
+ }
1722
+ }
1723
+ return output + input.substring(start);
1724
+ }
1725
+ function __pulse_fastly_redact(input: string): string { let output = __pulse_fastly_redact_fields(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 }
1701
1726
  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)) }
1702
1727
  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 }
1703
1728
  function __pulse_fastly_hex(value: i32): string { return String.fromCharCode(value < 10 ? 48 + value : 87 + value) }
@@ -1768,8 +1793,8 @@ function __pulse_fastly_read_body(handle: i32, effectIndex: i32, requestText: bo
1768
1793
  if (requestText && !__pulse_request_utf8_valid(bytes)) { __pulse_fastly_fail(PULSE_ERROR_REQUEST_BODY, 24, effectIndex); return "" }
1769
1794
  return __pulse_fastly_decode(bytes, total);
1770
1795
  }
1771
- 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)) }
1772
- 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)) }
1796
+ function __pulse_fastly_request_header_text(name: string): string { const value = __pulse_header_lookup(__pulse_fastly_request_handle, name, false); return value === null ? "" : value }
1797
+ function __pulse_fastly_fetch_header_text(responseHandle: i32, name: string): string { const value = __pulse_header_lookup(responseHandle, name, true); return value === null ? "" : value }
1773
1798
  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 }
1774
1799
 
1775
1800
  function __pulse_fastly_scalar(kind: i32, boolean: i32, slot: i32): i32 {
@@ -1819,7 +1844,7 @@ function host_router_match(path: i32, pattern: i32): i32 { return host_value_boo
1819
1844
  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) }
1820
1845
  function host_request_path(): i32 { return __pulse_fastly_string_value(__pulse_fastly_request_path) }
1821
1846
  function host_request_headers(): i32 { return __pulse_request_headers_read() }
1822
- 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) }
1847
+ function host_request_header(name: i32): i32 { const value = __pulse_header_lookup(__pulse_fastly_request_handle, __pulse_fastly_string(name), false); return value === null ? host_value_undefined() : __pulse_fastly_string_value(value) }
1823
1848
  function host_request_text(): i32 { if (__pulse_request_body_failure != 0) { __pulse_fastly_fail(PULSE_ERROR_REQUEST_BODY, __pulse_request_body_failure, -1); return 0 } if (__pulse_fastly_request_body_loaded == 0) { __pulse_fastly_request_body = __pulse_fastly_read_body(__pulse_fastly_request_body_handle, -1, true); __pulse_fastly_request_body_loaded = 1; if (__pulse_fastly_last_error == PULSE_ERROR_REQUEST_BODY) __pulse_request_body_failure = __pulse_fastly_error_stage } if (__pulse_fastly_last_error != 0) return 0; return __pulse_fastly_string_value(__pulse_fastly_request_body) }
1824
1849
  function host_request_json(schema: i32): i32 { const parsed = ${hasJsonAdmission(plan) ? '__pulse_fastly_schema_parse_json(__pulse_fastly_string(host_request_text()), schema)' : '__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 }
1825
1850
  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])))) } } }
@@ -1858,7 +1883,7 @@ function host_grip_handoff(optionsHandle: i32): i32 { const options = __pulse_fa
1858
1883
  function host_kv_namespace(name: i32): i32 { return name }
1859
1884
  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)) }
1860
1885
  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 = ${hasJsonAdmission(plan) ? '__pulse_fastly_schema_parse_json(__pulse_fastly_fetch_body(response), schemaHandle)' : '__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 }
1861
- 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) }
1886
+ 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_header_lookup(response.responseHandle, __pulse_fastly_string(nameHandle), true); return value === null ? host_value_undefined() : __pulse_fastly_string_value(value) }
1862
1887
  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]) }
1863
1888
  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) }
1864
1889
  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) }
@@ -1880,7 +1905,7 @@ function __pulse_fastly_jwt_capture_clock(effectIndex: i32): f64 { __pulse_fastl
1880
1905
  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) }
1881
1906
  function __pulse_fastly_jwt_sign_begin(effectIndex: i32, payload: __PulseFastlyValue): void { const result = pulse_jwt_fastly_sign(effectIndex, unchecked(__pulse_fastly_payloads[effectIndex])); if (result > 0 && __pulse_fastly_last_error == 0) __pulse_fastly_ready_effect(effectIndex, result) }
1882
1907
  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) }
1883
- 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) }
1908
+ 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_fetch_close_request(requestHandle); __pulse_fetch_close_body(bodyHandle); __pulse_fetch_fail(status, 77, effectIndex); return } unchecked(__pulse_fastly_pending[effectIndex] = __pulse_fastly_out_value(pendingOut)); unchecked(__pulse_fastly_pending_mode[effectIndex] = PULSE_FASTLY_PENDING_ASYNC) }
1884
1909
  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_fetch_json_body(init, unchecked(init.values[jsonIndex])); if (__pulse_fastly_last_error != 0) return; headers = __pulse_fastly_fetch_json_headers(headers) } } __pulse_fastly_start_request(effectIndex, url, method, headers, body, __pulse_fastly_backend(effectIndex)) }
1885
1910
  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) }
1886
1911
  ${assetBeginSource}
@@ -1892,7 +1917,7 @@ function __pulse_fastly_grip_hold_begin(effectIndex: i32, payload: __PulseFastly
1892
1917
  ${gripSecretSource}
1893
1918
  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)) }
1894
1919
  ${effectDispatchSource(plan)}
1895
- 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) }
1920
+ 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_fetch_fail(status, 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) }
1896
1921
  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) }
1897
1922
  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 }
1898
1923
  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 }
@@ -1949,7 +1974,7 @@ function __pulse_fastly_run_invocation(): void {
1949
1974
  if (__pulse_fastly_last_error != 0) { __pulse_fastly_jwt_send_error(); return }
1950
1975
  __pulse_fastly_request_path = __pulse_fastly_path(__pulse_fastly_request_url)
1951
1976
  let runStatus = pulse_start()
1952
- ${packageApplication.enabled(plan) ? packageApplication.driverLoop() : applicationErrors.enabled(plan) ? applicationErrors.driverLoop(plan) : ` while (runStatus == 1 && __pulse_fastly_last_error == 0) {
1977
+ ${packageApplication.enabled(plan) ? packageApplication.driverLoop() : applicationErrors.settlementEnabled(plan) ? applicationErrors.driverLoop(plan) : ` while (runStatus == 1 && __pulse_fastly_last_error == 0) {
1953
1978
  for (let effectIndex = 0; effectIndex < PULSE_FASTLY_EFFECT_COUNT; effectIndex += 1) {
1954
1979
  if (unchecked(__pulse_fastly_pending_mode[effectIndex]) == PULSE_FASTLY_PENDING_NONE) continue
1955
1980
  const invocation = unchecked(__pulse_invocation_tickets[effectIndex])
@@ -2052,14 +2077,20 @@ function generateFastlyNativePlatformCapabilitiesAssemblyScript(plan, options =
2052
2077
  conditionalKv.kvNativeSource(plan),
2053
2078
  require('./native-request-body.js').runtimeSource(),
2054
2079
  require('./native-request-headers.js').runtimeSource(),
2055
- applicationErrors.enabled(plan) ? applicationErrors.runtimeSource(plan) : '',
2080
+ require('./native-header-lookup.js').runtimeSource(),
2081
+ require('./native-fetch-errors.js').runtimeSource(),
2082
+ require('./native-fetch-deadlines.js').runtimeSource(plan),
2083
+ applicationErrors.settlementEnabled(plan) ? applicationErrors.runtimeSource(plan) : '',
2056
2084
  effectInvocations.runtimeSource({ packageCompletion: packageApplication.enabled(plan) }),
2057
2085
  portableSource,
2058
2086
  driverSource(plan, { guestLinked: facts.guestUnits.length > 0 }),
2059
2087
  ''
2060
2088
  ].join('\n');
2061
- if (applicationErrors.enabled(plan)) source = applicationErrors.instrument(source);
2089
+ if (applicationErrors.settlementEnabled(plan)) source = applicationErrors.instrument(source);
2062
2090
  source = require('./native-request-headers.js').instrument(source, applicationErrors.enabled(plan), /\bhost_request_headers\(/.test(portableSource));
2091
+ source = require('./native-header-lookup.js').instrument(source);
2092
+ source = require('./native-fetch-errors.js').instrument(source);
2093
+ source = require('./native-fetch-deadlines.js').instrument(source, plan);
2063
2094
  source = require('./native-request-body.js').instrument(source, applicationErrors.enabled(plan));
2064
2095
  if (packageApplication.enabled(plan)) source = packageApplication.instrument(source);
2065
2096
  source = effectInvocations.instrument(source);
@@ -2089,6 +2120,7 @@ function generateFastlyNativePlatformCapabilitiesAssemblyScript(plan, options =
2089
2120
  portableSourceHash: portable.sourceHash,
2090
2121
  schemaCodecs: portable.manifest.schemaCodecs,
2091
2122
  handlerBodies: portable.manifest.handlerBodies,
2123
+ ...(portable.manifest.reportOwnership ? { reportOwnership: portable.manifest.reportOwnership } : {}),
2092
2124
  dispatcher: portable.manifest.dispatcher,
2093
2125
  stages: portable.manifest.stages,
2094
2126
  helperBodies: portable.manifest.helperBodies,
@@ -2139,7 +2171,7 @@ function generateFastlyNativePlatformCapabilitiesAssemblyScript(plan, options =
2139
2171
  providerNeutralInput: true,
2140
2172
  javascriptRuntime: false,
2141
2173
  jsComputeRuntime: false,
2142
- wasi: bindings.maxDurationMs !== undefined || hasJwt || hasSign || bindings.s3.length || plan.effects.some(effect => conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind)) ? 'clock_time_get only' : false,
2174
+ wasi: plan.effects.some(effect => effect.kind === 'fetch') || bindings.maxDurationMs !== undefined || hasJwt || hasSign || bindings.s3.length || plan.effects.some(effect => conditionalKv.KV_CONDITIONAL_KINDS.includes(effect.kind)) ? 'clock_time_get only' : false,
2143
2175
  effects: FASTLY_NATIVE_PLATFORM_EFFECT_KINDS.join(', '),
2144
2176
  continuations: true,
2145
2177
  groupedEffects: 'existing fetch start-before-wait ordering remains intact',
@@ -2304,9 +2336,10 @@ function compileFastlyNativePlatformCapabilitiesPlan(plan, options = {}) {
2304
2336
  '--path', jsonAs.dependencyRoot
2305
2337
  );
2306
2338
  }
2339
+ require('@pulse-compute/wasm-build-support/native-optimization').appendJsonCacheArenaArgs(args, options.elideJsonCacheArena, schemaCodecsActive);
2307
2340
  const readReportCapture = options.reportCapture === false ? () => null : prepareReportCapture(args, stagingDir, generated.manifest,
2308
2341
  require(path.join(asc.packageRoot, 'package.json')).version, 'fastly-native-platform-capabilities.as/');
2309
- const startedAt = Date.now();
2342
+ const startedAt = process.hrtime.bigint();
2310
2343
  const result = spawnSync(asc.executable, args, {
2311
2344
  cwd: stagingDir,
2312
2345
  encoding: 'utf8',
@@ -2316,7 +2349,7 @@ function compileFastlyNativePlatformCapabilitiesPlan(plan, options = {}) {
2316
2349
  ? { ...process.env, JSON_STRICT: 'true', JSON_USE_FAST_PATH: '0', JSON_MODE: 'NAIVE' }
2317
2350
  : process.env
2318
2351
  });
2319
- const assemblyScriptDurationMs = Date.now() - startedAt;
2352
+ const assemblyScriptDurationMs = Math.round(Number(process.hrtime.bigint() - startedAt) / 1e6);
2320
2353
  if (result.error || result.status !== 0 || !fs.existsSync(assemblyScriptWasmFile)) {
2321
2354
  fail('AssemblyScript failed to compile the Fastly native platform capabilities module.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_ASC_FAILED', {
2322
2355
  status: result.status,
@@ -2454,7 +2487,7 @@ function compileFastlyNativePlatformCapabilitiesPlan(plan, options = {}) {
2454
2487
  compilerVersion: FASTLY_NATIVE_PLATFORM_CAPABILITIES_COMPILER_VERSION,
2455
2488
  assemblyScript: Object.freeze({ package: 'assemblyscript', version: require(path.join(asc.packageRoot, 'package.json')).version }),
2456
2489
  jsonAs: jsonAs
2457
- ? Object.freeze({ package: 'json-as', version: jsonAs.version, transform: true, strict: true, mode: 'NAIVE', fastPath: false })
2490
+ ? Object.freeze({ package: 'json-as', version: jsonAs.version, transform: true, strict: true, mode: 'NAIVE', fastPath: false, elideDisabledCacheArena: options.elideJsonCacheArena === true })
2458
2491
  : undefined,
2459
2492
  optimization,
2460
2493
  wasm: Object.freeze({ bytes: inspection.bytes, sha256: inspection.sha256, magic: inspection.magic }),
@@ -2474,11 +2507,17 @@ function compileFastlyNativePlatformCapabilitiesPlan(plan, options = {}) {
2474
2507
  providerPackaging: realization.guestLink.providerPackaging
2475
2508
  } : {})
2476
2509
  });
2477
- const durationMs = Date.now() - startedAt;
2510
+ const durationMs = Math.round(Number(process.hrtime.bigint() - startedAt) / 1e6);
2478
2511
  return Object.freeze({
2479
2512
  version: FASTLY_NATIVE_PLATFORM_CAPABILITIES_VERSION,
2480
2513
  compilerVersion: FASTLY_NATIVE_PLATFORM_CAPABILITIES_COMPILER_VERSION,
2481
2514
  reportAttribution: readReportCapture(wasm),
2515
+ buildObservation: require('@pulse-compute/wasm-build-support/native-optimization').observeAssemblyScript(args, {
2516
+ version: require(path.join(asc.packageRoot, 'package.json')).version,
2517
+ assemblyScriptRoot: asc.packageRoot, timeoutMs: Number(options.timeoutMs || 180000),
2518
+ compilerVersion: FASTLY_NATIVE_PLATFORM_CAPABILITIES_COMPILER_VERSION,
2519
+ durationMs: assemblyScriptDurationMs, jsonAsVersion: jsonAs && jsonAs.version
2520
+ }),
2482
2521
  plan,
2483
2522
  generated,
2484
2523
  source: generated.source,
@@ -23,7 +23,7 @@ function instrumentRequestBudget(input, duration, plan) {
23
23
  replace('function __pulse_fastly_resolve_effect(effectIndex: i32): i32 {', `function __pulse_fastly_resolve_effect(effectIndex: i32): i32 {
24
24
  if (!__request_check(effectIndex)) return 0;
25
25
  const kind = __pulse_fastly_effect_kind(effectIndex);
26
- if (unchecked(__pulse_fastly_pending_mode[effectIndex]) == PULSE_FASTLY_PENDING_ASYNC && kind != 12 && kind != 13 && kind != 14 && kind != 21 && ${plan.effects.filter(e=>e.kind.startsWith('kv.')&&['kv.getVersioned','kv.insertIfAbsent','kv.compareAndSwap'].includes(e.kind)).map(e=>'effectIndex != '+plan.effects.indexOf(e)).join(' && ')||'true'}) {
26
+ if (unchecked(__pulse_fastly_pending_mode[effectIndex]) == PULSE_FASTLY_PENDING_ASYNC && !(kind == 1 && __pulse_fetch_has_deadlines()) && kind != 12 && kind != 13 && kind != 14 && kind != 21 && ${plan.effects.filter(e=>e.kind.startsWith('kv.')&&['kv.getVersioned','kv.insertIfAbsent','kv.compareAndSwap'].includes(e.kind)).map(e=>'effectIndex != '+plan.effects.indexOf(e)).join(' && ')||'true'}) {
27
27
  if (!__request_wait(unchecked(__pulse_fastly_pending[effectIndex]), effectIndex)) return 0;
28
28
  }`);
29
29
  replace(' const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES), read = __pulse_fastly_out_i32();', ' if (!__request_wait(handle, effectIndex)) return "";\n const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES), read = __pulse_fastly_out_i32();');
@@ -40,6 +40,8 @@ function instrumentRequestBudget(input, duration, plan) {
40
40
  if (source.includes('__kv_deadline[index] = start +')) replace('__kv_deadline[index] = start + i64(__KV_timeoutMs) * 1000000;', '__kv_deadline[index] = min<i64>(__request_deadline, start + i64(__KV_timeoutMs) * 1000000);');
41
41
  if (source.includes('__s3_deadlines[index] = start +')) replace('__s3_deadlines[index] = start + i64(binding.timeout) * 1000000;', '__s3_deadlines[index] = min<i64>(__request_deadline, start + i64(binding.timeout) * 1000000);');
42
42
  if (source.includes('function __pulse_fastly_write_binary(')) replace('const written = new StaticArray<i32>(1); let offset = 0;\n while (offset < data.length) {', 'const written = new StaticArray<i32>(1); let offset = 0;\n while (offset < data.length) { if (!__request_check()) return 1;');
43
+ replace('function __pulse_fetch_request_check(index: i32): bool { return true }', 'function __pulse_fetch_request_check(index: i32): bool { return __request_check(index) }');
44
+ replace('function __pulse_fetch_request_remaining(): i32 { return 2147483647 }', 'function __pulse_fetch_request_remaining(): i32 { return __request_remaining() }');
43
45
  return source + '\n' + fs.readFileSync(path.join(__dirname,'request-budget.as.ts'),'utf8');
44
46
  }
45
47
  module.exports = {instrumentRequestBudget};
@@ -4,6 +4,7 @@ const fs = require('node:fs');
4
4
  const path = require('node:path');
5
5
 
6
6
  const FASTLY_STATUS_OK = 0;
7
+ const FASTLY_STATUS_INVALID_ARGUMENT = 2;
7
8
  const FASTLY_STATUS_ERROR = 1;
8
9
  const FASTLY_STATUS_BADF = 3;
9
10
  const FASTLY_STATUS_BUFLEN = 4;
@@ -229,7 +230,7 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
229
230
  new Uint8Array(memory().buffer, Number(buffer), output.length).set(output);
230
231
  return FASTLY_STATUS_OK;
231
232
  }
232
- function requestHeaderList(values, buffer, size, cursor, end, written, kind) {
233
+ function requestHeaderList(values, buffer, size, cursor, end, written, kind, lookupKind) {
233
234
  const limit = Math.min(Number(size), options.requestHeaderPageBytes ?? Number(size));
234
235
  let index = Number(cursor), count = 0;
235
236
  if (index < 0 || index > values.length) return FASTLY_STATUS_ERROR;
@@ -245,7 +246,7 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
245
246
  writeU32(written, count);
246
247
  view().setBigInt64(Number(end), index === values.length ? -1n : BigInt(index), true);
247
248
  // Fault injection is host-fixture-only; neither values nor faults enter traces.
248
- const fault = options.requestHeaderFault?.({kind, cursor: Number(cursor)});
249
+ const fault = (lookupKind && options.headerLookupFault?.({kind:lookupKind})) || options.requestHeaderFault?.({kind, cursor: Number(cursor)});
249
250
  if (fault?.written !== undefined) writeU32(written, fault.written);
250
251
  if (fault?.cursor !== undefined) view().setBigInt64(Number(end), BigInt(fault.cursor), true);
251
252
  if (fault?.unterminated && count) new Uint8Array(memory().buffer)[Number(buffer) + count - 1] = 65;
@@ -254,14 +255,17 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
254
255
  const imports = {
255
256
  fastly_async_io: {
256
257
  select(handles, count, timeout, done) {
257
- if (Number(count) !== 1 || Number(timeout) <= 0) return FASTLY_STATUS_ERROR;
258
- const handle = view().getUint32(Number(handles), true);
259
- const item = pending.get(handle) || bodies.get(handle);
260
- if (!item) return FASTLY_STATUS_BADF;
261
- const wait = Math.max(0, Number(item.readyAt || 0) - monotonicMs);
262
- monotonicMs += Math.min(wait, Number(timeout));
263
- writeU32(done, wait >= Number(timeout) ? 0xffffffff : 0);
264
- trace.push({ module: 'fastly_async_io', name: 'select', timeout: Number(timeout), timedOut: wait >= Number(timeout) });
258
+ if (Number(count) < 1 || Number(timeout) <= 0) return FASTLY_STATUS_ERROR;
259
+ const selected = Array.from({length:Number(count)},(_,i) => view().getUint32(Number(handles)+4*i,true));
260
+ const items = selected.map(handle => pending.get(handle) || bodies.get(handle));
261
+ if (items.some(item => !item)) return FASTLY_STATUS_BADF;
262
+ const waits = items.map(item => Math.max(0, Number(item.readyAt || 0) - monotonicMs));
263
+ const wait = Math.min(...waits), timedOut = wait >= Number(timeout);
264
+ const fault = options.asyncSelectFault?.({handles:selected,timeout:Number(timeout),now:monotonicMs});
265
+ monotonicMs += fault?.advanceMs ?? Math.min(wait,Number(timeout));
266
+ writeU32(done, fault?.selected ?? (timedOut ? 0xffffffff : waits.indexOf(wait)));
267
+ trace.push({ module: 'fastly_async_io', name: 'select', handles:selected, timeout:Number(timeout), timedOut, now:monotonicMs });
268
+ if (fault?.status) return fault.status;
265
269
  return FASTLY_STATUS_OK;
266
270
  }
267
271
  },
@@ -325,7 +329,11 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
325
329
  trace.push({ module: 'fastly_log', name: 'write', endpoint, accepted: false });
326
330
  return FASTLY_STATUS_ERROR;
327
331
  }
328
- const message = redactText(readUtf8(messagePointer, messageLength));
332
+ const emitted = readUtf8(messagePointer, messageLength);
333
+ // Test-only assertion seam before proof-trace redaction. Never retain raw
334
+ // guest bytes in the returned evidence, even when the guest regresses.
335
+ if (typeof options.onLogWrite === 'function') options.onLogWrite(emitted);
336
+ const message = redactText(emitted);
329
337
  writeU32(writtenOut, Buffer.byteLength(message));
330
338
  logs.push(Object.freeze({ endpoint, message }));
331
339
  trace.push({ module: 'fastly_log', name: 'write', endpoint, message, accepted: true });
@@ -360,7 +368,8 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
360
368
  const request = requests.get(Number(handle));
361
369
  if (!request) return FASTLY_STATUS_BADF;
362
370
  const name = readUtf8(pointer, length).toLowerCase();
363
- return requestHeaderList(request.headers.filter(([key]) => key.toLowerCase() === name).map(([, value]) => value), buffer, size, cursor, end, written, 'values');
371
+ if (!/^[!#$%&'*+.^_`|~0-9a-z-]+$/.test(name)) return FASTLY_STATUS_INVALID_ARGUMENT;
372
+ return requestHeaderList(request.headers.filter(([key]) => key.toLowerCase() === name).map(([, value]) => value), buffer, size, cursor, end, written, 'values', 'request');
364
373
  },
365
374
  header_value_get(handle, namePointer, nameLength, valuePointer, valueLength, writtenOut) {
366
375
  const request = requests.get(Number(handle));
@@ -368,7 +377,7 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
368
377
  trace.push({ module: 'fastly_http_req', name: 'header_value_get', handle: Number(handle), header: name });
369
378
  if (!request) return FASTLY_STATUS_BADF;
370
379
  const value = headerValue(request.headers, name);
371
- return value === undefined ? FASTLY_STATUS_NONE : writeUtf8(value, valuePointer, valueLength, writtenOut);
380
+ return value === undefined ? FASTLY_STATUS_INVALID_ARGUMENT : writeUtf8(value, valuePointer, valueLength, writtenOut);
372
381
  },
373
382
  new(handleOut) {
374
383
  const handle = alloc('request');
@@ -413,6 +422,7 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
413
422
  close(handle) { return requests.delete(Number(handle)) ? FASTLY_STATUS_OK : FASTLY_STATUS_BADF; },
414
423
  pending_req_poll_v2(handle, detail, done, responseOut, bodyOut) {
415
424
  const item = pending.get(Number(handle)); if (!item) return FASTLY_STATUS_BADF;
425
+ trace.push({module:'fastly_http_req',name:'pending_req_poll_v2',pendingHandle:Number(handle)});
416
426
  if (monotonicMs < item.readyAt) { writeU32(done, 0); return FASTLY_STATUS_OK; }
417
427
  writeU32(done, 1); return imports.fastly_http_req.pending_req_wait(handle, responseOut, bodyOut);
418
428
  },
@@ -430,7 +440,7 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
430
440
  }
431
441
  const pendingHandle = alloc('pending');
432
442
  const capturedBody = bodyBytes(bodyHandle);
433
- pending.set(pendingHandle, { request: { ...request, headers: request.headers.map((entry) => [...entry]), body: capturedBody }, backend, fixture, readyAt: monotonicMs + Number(fixture.delayMs || 0) });
443
+ pending.set(pendingHandle, { request: { ...request, headers: request.headers.map((entry) => [...entry]), body: capturedBody }, backend, fixture, readyAt: fixture.neverHeaders ? Infinity : monotonicMs + Number(fixture.delayMs || 0) });
434
444
  if (typeof options.onOutboundRequest === 'function') options.onOutboundRequest({ ...request, backend, headers: request.headers.map((entry) => [...entry]), body: capturedBody });
435
445
  if (fixture.sendStatus) { pending.delete(pendingHandle); return Number(fixture.sendStatus); }
436
446
  if (request.headers.some(([name, value]) => name.toLowerCase() === 'authorization' && value.startsWith('AWS4-HMAC-SHA256 '))) privateUrls.add(request.url);
@@ -576,13 +586,21 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
576
586
  trace.push({ module: 'fastly_http_resp', name: 'header_append', handle: Number(handle), header: [name, value] });
577
587
  return FASTLY_STATUS_OK;
578
588
  },
589
+ header_values_get(handle, pointer, length, buffer, size, cursor, end, written) {
590
+ trace.push({module:'fastly_http_resp', name:'header_values_get', cursor:Number(cursor)});
591
+ const response = responses.get(Number(handle));
592
+ if (!response) return FASTLY_STATUS_BADF;
593
+ const name = readUtf8(pointer, length).toLowerCase();
594
+ if (!/^[!#$%&'*+.^_`|~0-9a-z-]+$/.test(name)) return FASTLY_STATUS_INVALID_ARGUMENT;
595
+ return requestHeaderList(response.headers.filter(([key]) => key.toLowerCase() === name).map(([, value]) => value), buffer, size, cursor, end, written, 'response-values', 'response');
596
+ },
579
597
  header_value_get(handle, namePointer, nameLength, valuePointer, valueLength, writtenOut) {
580
598
  const response = responses.get(Number(handle));
581
599
  const name = readUtf8(namePointer, nameLength);
582
600
  trace.push({ module: 'fastly_http_resp', name: 'header_value_get', handle: Number(handle), header: name });
583
601
  if (!response) return FASTLY_STATUS_BADF;
584
602
  const value = headerValue(response.headers, name);
585
- return value === undefined ? FASTLY_STATUS_NONE : writeUtf8(value, valuePointer, valueLength, writtenOut);
603
+ return value === undefined ? FASTLY_STATUS_INVALID_ARGUMENT : writeUtf8(value, valuePointer, valueLength, writtenOut);
586
604
  },
587
605
  status_get(handle, statusOut) {
588
606
  const response = responses.get(Number(handle));
@@ -702,7 +720,16 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
702
720
  const handledJwtError = options.allowHandledJwtError === true
703
721
  && lastError === 1008
704
722
  && Boolean(downstream);
705
- if (lastError !== FASTLY_STATUS_OK && !handledJwtError && !(options.allowAbortedResponse === true && downstream?.aborted)) {
723
+ const handledHeaderError = options.allowHandledHeaderError === true
724
+ && lastError === 1003 && (errorStage === 22 || errorStage === 23) && downstream?.status === 500;
725
+ const handledTransportError = options.allowHandledTransportError === true
726
+ && (errorStage === 77 || errorStage === 81)
727
+ && ((lastError === 1006 && downstream?.status === 502) || (lastError === 1003 && downstream?.status === 500));
728
+ const handledDeadlineError = options.allowHandledFetchDeadlineError === true
729
+ && ((lastError === 1006 && errorStage === 271 && downstream?.status === 504)
730
+ || (lastError === 1001 && errorStage === 270 && downstream?.status === 400)
731
+ || (lastError === 1003 && errorStage === 272 && downstream?.status === 500));
732
+ if (lastError !== FASTLY_STATUS_OK && !handledDeadlineError && !handledTransportError && !handledHeaderError && !handledJwtError && !(options.allowAbortedResponse === true && downstream?.aborted)) {
706
733
  throw new FastlyNativePlatformCapabilitiesMockError('Fastly native platform capabilities module reported an execution error.', 'PULSE_FASTLY_NATIVE_PLATFORM_CAPABILITIES_MOCK_EXECUTION_FAILED', { lastError, errorStage, errorEffect, pulseLastError, trace });
707
734
  }
708
735
  if (!downstream) {
@@ -729,6 +756,9 @@ function executeFastlyNativePlatformCapabilities(input, options = {}) {
729
756
  outboundRequests: Object.freeze(outboundRequests),
730
757
  stores: Object.freeze({ config: snapshotStores(configStores), secrets: Object.fromEntries([...secretStores].map(([name, values]) => [name, Object.fromEntries([...values].map(([key]) => [key, '[REDACTED]']))])), kv: snapshotStores(kvStores, true) }),
731
758
  kvEvidence,
759
+ monotonicMs,
760
+ transportResources: Object.freeze({pendingRequests: pending.size,
761
+ outboundRequests: requests.size - Number(requests.has(downstreamRequestHandle))}),
732
762
  instance
733
763
  });
734
764
  }
@@ -285,6 +285,7 @@ function createDriver() {
285
285
  realizationArtifacts: invocation.nativeArtifact.realizationArtifacts,
286
286
  guestUnits: invocation.nativeArtifact.guestUnits,
287
287
  nativeOptimization: invocation.optimization,
288
+ elideJsonCacheArena: invocation.nativeArtifact.manifest.elideJsonCacheArena === true,
288
289
  emitWat: invocation.nativeArtifact.manifest.wat?.emitted === true,
289
290
  compileTimeoutMs: invocation.timeoutMs
290
291
  });
@@ -314,6 +315,7 @@ function createDriver() {
314
315
  realizationArtifacts: invocation.nativeArtifact.realizationArtifacts,
315
316
  guestUnits: invocation.nativeArtifact.guestUnits,
316
317
  nativeOptimization: invocation.optimization,
318
+ elideJsonCacheArena: invocation.nativeArtifact.manifest.elideJsonCacheArena === true,
317
319
  emitWat: invocation.nativeArtifact.manifest.wat?.emitted === true,
318
320
  compileTimeoutMs: invocation.timeoutMs
319
321
  });
@@ -350,7 +352,7 @@ function createDriver() {
350
352
  providerPackage: providerBuild.packageFile,
351
353
  providerSourceEntry: providerBuild.sourceEntryFile
352
354
  }),
353
- build: { ...providerBuild.build, reportAttribution: native.reportAttribution },
355
+ build: { ...providerBuild.build, reportAttribution: native.reportAttribution, buildObservation: native.buildObservation },
354
356
  realization: publicRealization,
355
357
  packaging: audit ? Object.freeze({
356
358
  version: PROVIDER_PACKAGING_AUDIT_VERSION,
@@ -18,6 +18,7 @@ function prepareFastlyNativeExecution(invocation) {
18
18
  realizationArtifacts: invocation.nativeArtifact.realizationArtifacts,
19
19
  guestUnits: invocation.nativeArtifact.guestUnits,
20
20
  nativeOptimization: invocation.optimization,
21
+ elideJsonCacheArena: invocation.nativeArtifact.manifest.elideJsonCacheArena === true,
21
22
  emitWat: invocation.nativeArtifact.manifest.wat?.emitted === true,
22
23
  compileTimeoutMs: invocation.timeoutMs || undefined
23
24
  });