@pulse-compute/provider-fastly 1.0.0-beta.5 → 1.0.0-beta.6

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 (39) hide show
  1. package/README.md +6 -6
  2. package/dist/config-schema.json +7 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +2 -0
  6. package/dist/index.js.map +1 -1
  7. package/package.json +11 -11
  8. package/src/build/canonical-target.js +10 -2
  9. package/src/build/effect-invocations.js +49 -0
  10. package/src/build/embedded-assets.as.ts +32 -0
  11. package/src/build/kv-native.as.ts +18 -8
  12. package/src/build/native-application-errors.js +49 -26
  13. package/src/build/native-http-effects.js +41 -12
  14. package/src/build/native-platform-capabilities.js +346 -120
  15. package/src/build/native-string-values.js +1 -1
  16. package/src/build/native-value-budget.js +58 -0
  17. package/src/build/package-native-application.js +94 -0
  18. package/src/build/request-budget.js +3 -1
  19. package/src/build/s3-body.as.ts +97 -0
  20. package/src/build/s3-native.as.ts +9 -3
  21. package/src/build/s3-native.js +2 -2
  22. package/src/build/schema-admission.js +83 -0
  23. package/src/build/schema-nested-json.js +93 -0
  24. package/src/build/schema-scalar-record.js +41 -0
  25. package/src/build/wasm-budget.js +28 -0
  26. package/src/config-api.js +2 -0
  27. package/src/config-schema.json +7 -0
  28. package/src/index.ts +5 -0
  29. package/src/javascript/jwt-verifier.js +14 -4
  30. package/src/javascript/package-effects.js +1 -1
  31. package/src/javascript/target-support-policy.js +11 -5
  32. package/src/javascript/target.js +10 -0
  33. package/src/provider-contract.js +4 -2
  34. package/src/testing/native-http-effects-host.js +5 -1
  35. package/src/testing/native-platform-capabilities-host.js +24 -3
  36. package/src/toolchain/config.js +4 -0
  37. package/src/toolchain/index.js +30 -1
  38. package/src/toolchain/native-execution.js +1 -0
  39. package/src/toolchain/s3.js +2 -2
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.5/packages/provider-fastly/)
10
+ > **Canonical documentation:** [Package guide](https://pulsecompute.io/v1.0.0-beta.6/packages/provider-fastly/)
11
11
  >
12
- > This release-status block is generated from the synchronized `Pulse 1.0.0-beta.5` package policy.
12
+ > This release-status block is generated from the synchronized `Pulse 1.0.0-beta.6` 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.5/packages/provider-fastly/)
53
- - [Project configuration](https://pulsecompute.io/v1.0.0-beta.5/reference/project-config/#fastly-provider-options)
54
- - [Fastly capabilities guide](https://pulsecompute.io/v1.0.0-beta.5/guides/fastly-capabilities/)
55
- - [Environment variables](https://pulsecompute.io/v1.0.0-beta.5/reference/environment/#pulse-fastly-bin)
52
+ - [Fastly package guide](https://pulsecompute.io/v1.0.0-beta.6/packages/provider-fastly/)
53
+ - [Project configuration](https://pulsecompute.io/v1.0.0-beta.6/reference/project-config/#fastly-provider-options)
54
+ - [Fastly capabilities guide](https://pulsecompute.io/v1.0.0-beta.6/guides/fastly-capabilities/)
55
+ - [Environment variables](https://pulsecompute.io/v1.0.0-beta.6/reference/environment/#pulse-fastly-bin)
@@ -75,6 +75,13 @@
75
75
  },
76
76
  "fastly.maxDurationMs": {
77
77
  "kind": "optional-number"
78
+ },
79
+ "fastly.build.maxWasmBytes": {
80
+ "kind": "positive-safe-integer",
81
+ "default": 4194304
82
+ },
83
+ "fastly.maxWasmBytes": {
84
+ "kind": "positive-safe-integer"
78
85
  }
79
86
  }
80
87
  }
package/dist/index.d.ts CHANGED
@@ -14,6 +14,8 @@ export interface PulseFastlyLocalOptions {
14
14
  readonly networkFetch?: boolean;
15
15
  }
16
16
  export interface PulseFastlyProviderOptions {
17
+ /** Inclusive final Native Wasm byte budget; default 4 MiB. */
18
+ readonly maxWasmBytes?: number;
17
19
  readonly maxDurationMs?: number;
18
20
  readonly configStore?: string;
19
21
  readonly secretStore?: string;
@@ -49,6 +51,7 @@ export interface PulseFastlyProviderConfig {
49
51
  readonly dynamicBackends: boolean;
50
52
  };
51
53
  readonly build: {
54
+ readonly maxWasmBytes: number;
52
55
  readonly name: string;
53
56
  readonly description: string;
54
57
  readonly authors: readonly string[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.FASTLY_PROVIDER_API_VERSION = void 0;
7
7
  exports.fastly = fastly;
8
+ const { normalizeFastlyMaxWasmBytes } = require('../src/build/wasm-budget.js');
8
9
  const { normalizeRequestDuration } = require('@pulse-compute/runtime/host');
9
10
  const config_schema_json_1 = __importDefault(require("./config-schema.json"));
10
11
  const fastlySchemaFields = config_schema_json_1.default.fields;
@@ -49,6 +50,7 @@ function fastly(options = {}) {
49
50
  dynamicBackends: options.dynamicBackends === undefined ? Boolean(fastlyDefaults['fastly.dynamicBackends']) : options.dynamicBackends === true
50
51
  }),
51
52
  build: Object.freeze({
53
+ maxWasmBytes: normalizeFastlyMaxWasmBytes(options.maxWasmBytes),
52
54
  name: String(options.name ?? fastlyDefaults['fastly.name']),
53
55
  description: String(options.description ?? fastlyDefaults['fastly.description']),
54
56
  authors: Object.freeze((options.authors ?? (Array.isArray(fastlyDefaults['fastly.authors']) ? fastlyDefaults['fastly.authors'] : [])).map(String)),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pulse-compute/provider-fastly",
3
- "version": "1.0.0-beta.5",
3
+ "version": "1.0.0-beta.6",
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.5",
63
- "@pulse-compute/jwt": "1.0.0-beta.5",
64
- "@pulse-compute/runtime": "1.0.0-beta.5",
65
- "@pulse-compute/s3": "1.0.0-beta.5",
66
- "@pulse-compute/wasm-build-support": "1.0.0-beta.5",
67
- "@pulse-compute/wasm-contracts": "1.0.0-beta.5",
68
- "@pulse-compute/wasm-guest-link": "1.0.0-beta.5",
69
- "@pulse-compute/wasm-host-runtime": "1.0.0-beta.5",
70
- "@pulse-compute/wasm-runtime-core-as": "1.0.0-beta.5",
62
+ "@pulse-compute/crypto": "1.0.0-beta.6",
63
+ "@pulse-compute/jwt": "1.0.0-beta.6",
64
+ "@pulse-compute/runtime": "1.0.0-beta.6",
65
+ "@pulse-compute/s3": "1.0.0-beta.6",
66
+ "@pulse-compute/wasm-build-support": "1.0.0-beta.6",
67
+ "@pulse-compute/wasm-contracts": "1.0.0-beta.6",
68
+ "@pulse-compute/wasm-guest-link": "1.0.0-beta.6",
69
+ "@pulse-compute/wasm-host-runtime": "1.0.0-beta.6",
70
+ "@pulse-compute/wasm-runtime-core-as": "1.0.0-beta.6",
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.5/packages/provider-fastly/",
90
+ "homepage": "https://pulsecompute.io/v1.0.0-beta.6/packages/provider-fastly/",
91
91
  "bugs": {
92
92
  "url": "https://github.com/pulse-compute/pulse/issues"
93
93
  },
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const crypto = require('node:crypto');
4
+ const { normalizeFastlyMaxWasmBytes, assertFastlyWasmBudget } = require('./wasm-budget.js');
4
5
  const fs = require('node:fs');
5
6
  const path = require('node:path');
6
7
  const { CANONICAL_NATIVE_PLAN_VERSION } = require('@pulse-compute/wasm-contracts/handler/canonical-native-plan');
@@ -222,6 +223,8 @@ function inspectFastlyCanonicalTarget(options = {}) {
222
223
  }
223
224
  const providerConfig = options.providerConfig || {};
224
225
  const bindings = options.bindings || providerConfig.bindings || {};
226
+ const maxWasmBytes = normalizeFastlyMaxWasmBytes(providerConfig.build?.maxWasmBytes);
227
+ if (isFastlyNativeArtifact(options.native)) assertFastlyWasmBudget(options.native.wasm.length, maxWasmBytes);
225
228
  const native = isFastlyNativeArtifact(options.native)
226
229
  ? assertExactProviderNative(options.native)
227
230
  : compileFastlyNativePlatformCapabilitiesPlan(plan, {
@@ -230,6 +233,7 @@ function inspectFastlyCanonicalTarget(options = {}) {
230
233
  profile: options.profile,
231
234
  bindings,
232
235
  maxDurationMs: providerConfig.maxDurationMs,
236
+ maxWasmBytes,
233
237
  requirePlatformCapability: false,
234
238
  canonicalBuild: true,
235
239
  targetDescriptor: options.targetDescriptor,
@@ -240,6 +244,7 @@ function inspectFastlyCanonicalTarget(options = {}) {
240
244
  || (options.native && options.native.guestUnits),
241
245
  nativeOptimization: options.nativeOptimization
242
246
  || (options.experimentalNativeSize === true ? 'experimental-native-size' : undefined),
247
+ emitWat: options.emitWat,
243
248
  timeoutMs: options.compileTimeoutMs
244
249
  });
245
250
  const duration = require('@pulse-compute/runtime/host').normalizeRequestDuration(providerConfig.maxDurationMs);
@@ -292,6 +297,8 @@ function writeFastlyCanonicalTarget(options = {}) {
292
297
  fs.mkdirSync(binDir, { recursive: true });
293
298
 
294
299
  let native;
300
+ const maxWasmBytes = normalizeFastlyMaxWasmBytes(providerConfig.build?.maxWasmBytes);
301
+ if (isFastlyNativeArtifact(options.native)) assertFastlyWasmBudget(options.native.wasm.length, maxWasmBytes);
295
302
  const auditedNative = isFastlyNativeArtifact(options.native)
296
303
  ? assertExactProviderNative(options.native)
297
304
  : null;
@@ -313,6 +320,7 @@ function writeFastlyCanonicalTarget(options = {}) {
313
320
  || (options.native && options.native.guestUnits),
314
321
  nativeOptimization: options.nativeOptimization
315
322
  || (options.experimentalNativeSize === true ? 'experimental-native-size' : undefined),
323
+ emitWat: options.emitWat,
316
324
  compileTimeoutMs: options.compileTimeoutMs
317
325
  });
318
326
  native = realization.native;
@@ -378,7 +386,7 @@ function writeFastlyCanonicalTarget(options = {}) {
378
386
  }),
379
387
  optimization: native.manifest.optimization,
380
388
  wasm: Object.freeze({ file: 'bin/main.wasm', ...native.manifest.wasm }),
381
- wat: Object.freeze({ file: 'bin/main.wat', ...native.manifest.wat }),
389
+ wat: Object.freeze({ file: written.watFile ? 'bin/main.wat' : null, ...native.manifest.wat }),
382
390
  imports: native.manifest.imports,
383
391
  importModules: native.manifest.importModules,
384
392
  exports: native.manifest.exports,
@@ -407,7 +415,7 @@ function writeFastlyCanonicalTarget(options = {}) {
407
415
  localEntry: 'fastly-entry.cjs',
408
416
  sourceEntry: 'src/main.as.ts',
409
417
  wasm: 'bin/main.wasm',
410
- wat: 'bin/main.wat',
418
+ wat: written.watFile ? 'bin/main.wat' : null,
411
419
  nativePlan: 'fastly-native-plan.json',
412
420
  nativeManifest: 'fastly-native-manifest.json',
413
421
  fastlyToml: 'fastly.toml',
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ const { CANONICAL_EFFECT_INVOCATION_POLICY } = require('@pulse-compute/wasm-contracts/handler/canonical-runtime');
4
+
5
+ function runtimeSource(options = {}) {
6
+ return `
7
+ const PULSE_FASTLY_MAX_EFFECT_INVOCATIONS: i32 = ${CANONICAL_EFFECT_INVOCATION_POLICY.defaultMaxEffects}
8
+ let __pulse_invocation_count: i32 = 0
9
+ let __pulse_invocation_started: bool = false
10
+ let __pulse_invocation_closed: bool = false
11
+ let __pulse_invocation_failure: i32 = 171
12
+ const __pulse_invocation_tickets = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
13
+ function __pulse_invocation_begin(index: i32): bool {
14
+ if (__pulse_invocation_closed || index < 0 || index >= PULSE_FASTLY_EFFECT_COUNT
15
+ || unchecked(__pulse_invocation_tickets[index]) != 0) {
16
+ __pulse_fastly_fail(PULSE_ERROR_STATE, __pulse_invocation_failure, index); return false
17
+ }
18
+ if (__pulse_invocation_count >= PULSE_FASTLY_MAX_EFFECT_INVOCATIONS) {
19
+ __pulse_invocation_closed = true
20
+ __pulse_invocation_failure = 170
21
+ __pulse_fastly_fail(PULSE_ERROR_STATE, 170, index); return false
22
+ }
23
+ unchecked(__pulse_invocation_tickets[index] = ++__pulse_invocation_count)
24
+ return true
25
+ }
26
+ function __pulse_invocation_settle(index: i32, ticket: i32, result: i32): i32 {
27
+ if (__pulse_invocation_closed || index < 0 || index >= PULSE_FASTLY_EFFECT_COUNT
28
+ || ticket <= 0 || unchecked(__pulse_invocation_tickets[index]) != ticket) {
29
+ __pulse_fastly_fail(PULSE_ERROR_STATE, __pulse_invocation_failure, index); return 0
30
+ }
31
+ unchecked(__pulse_invocation_tickets[index] = 0)
32
+ return ${options.packageCompletion ? "result == 0 ? pulse_package_set_effect_failure(index) : pulse_set_effect_result(index, result)" : "pulse_set_effect_result(index, result)"}
33
+ }
34
+ function __pulse_invocation_close(): void {
35
+ __pulse_invocation_closed = true
36
+ for (let i = 0; i < PULSE_FASTLY_EFFECT_COUNT; i += 1) unchecked(__pulse_invocation_tickets[i] = 0)
37
+ }
38
+ `;
39
+ }
40
+
41
+ function instrument(source) {
42
+ const signature = 'function host_effect_begin(effectIndex: i32, payload: i32): void {';
43
+ if (!source.includes(signature)) throw new Error('Fastly invocation admission boundary drift.');
44
+ // Every guest-requested slot gets a ticket, including a group member suppressed
45
+ // by an earlier application error. Its undefined result can then be drained.
46
+ return source.replace(signature, signature + '\n if (!__pulse_invocation_begin(effectIndex)) return;');
47
+ }
48
+
49
+ module.exports = { runtimeSource, instrument, policy: CANONICAL_EFFECT_INVOCATION_POLICY };
@@ -0,0 +1,32 @@
1
+ function __pulse_embedded_request_header(name: string): string | null {
2
+ const values = __pulse_request_header_list(name, false);
3
+ return values.length ? values.join(', ') : null;
4
+ }
5
+ function __pulse_embedded_field(payload: __PulseFastlyValue, name: string): string { return __pulse_fastly_string(__pulse_fastly_payload_field(payload, name)); }
6
+ function __pulse_fastly_embedded_asset(payload: __PulseFastlyValue): i32 {
7
+ // Avoid exposing provider buffers as canonical application values.
8
+ const length = __pulse_fastly_value(__pulse_fastly_payload_field(payload, 'embeddedFound')).boolean != 0 ? i32(__pulse_fastly_number(__pulse_fastly_payload_field(payload, 'embeddedLength'))) : -1;
9
+ const etag = __pulse_embedded_field(payload, 'embeddedEtag'), method = __pulse_embedded_field(payload, 'method');
10
+ const selected = __pulse_embedded_selection(length, method, etag,
11
+ __pulse_embedded_request_header('if-none-match'), __pulse_embedded_request_header('range'), __pulse_embedded_request_header('if-range'));
12
+ if (__pulse_request_headers_failed) return 0;
13
+ const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE; output.status = selected.status;
14
+ if (selected.status != 400 && selected.status != 404) {
15
+ output.headers.push(new __PulseFastlyHeader('content-type', __pulse_embedded_field(payload, 'embeddedType')));
16
+ output.headers.push(new __PulseFastlyHeader('etag', etag)); output.headers.push(new __PulseFastlyHeader('accept-ranges', 'bytes'));
17
+ if (selected.contentRange.length) output.headers.push(new __PulseFastlyHeader('content-range', selected.contentRange));
18
+ if (selected.status == 200 || selected.status == 206) {
19
+ output.headers.push(new __PulseFastlyHeader('content-length', max<i32>(0, selected.end - selected.start + 1).toString()));
20
+ if (method != 'HEAD') output.binaryBody = __pulse_embedded_bytes(__pulse_embedded_field(payload, 'embeddedData'), selected.start, selected.end);
21
+ }
22
+ }
23
+ return __pulse_fastly_put(output);
24
+ }
25
+ function __pulse_fastly_write_binary(handle: i32, data: Uint8Array): i32 {
26
+ const written = new StaticArray<i32>(1); let offset = 0;
27
+ while (offset < data.length) {
28
+ if (fastly_http_body_write(handle, data.dataStart + offset, data.length - offset, 0, changetype<usize>(written)) != 0 || written[0] <= 0 || written[0] > data.length - offset) return 1;
29
+ offset += written[0];
30
+ }
31
+ return 0;
32
+ }
@@ -80,35 +80,40 @@ 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
- function __kv_private(text: string): void {
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 {
84
86
  __pulse_fastly_remember_secret(text);
85
87
  const encoded = __pulse_fastly_quote(text);
86
88
  __pulse_fastly_remember_secret(encoded.substring(1, encoded.length - 1));
89
+ return encoded;
87
90
  }
88
91
  class __KvEncoder {
89
92
  reason: string = ''; entries: i32 = 0; bytes: i32 = 0;
90
- seen: Set<i32> = new Set<i32>(); parts: Array<string> = new Array<string>();
91
- add(text: string): void { this.bytes += String.UTF8.byteLength(text); if (this.bytes > __KV_valueBytes) this.reason = 'too-large'; else this.parts.push(text); }
93
+ seen: Set<i32> = new Set<i32>(); parts: Array<string> | null;
94
+ // Reads need the same validation and redaction walk, but no serialized output.
95
+ constructor(materialize: bool = true) { this.parts = materialize ? new Array<string>() : null; }
96
+ add(text: string): void { this.bytes += String.UTF8.byteLength(text); if (this.bytes > __KV_valueBytes) this.reason = 'too-large'; else if (this.parts !== null) this.parts!.push(text); }
92
97
  visit(handle: i32, depth: i32 = 0): void {
93
98
  if (this.reason.length) return;
94
99
  if (++this.entries > __KV_entries || depth > __KV_depth) { this.reason = 'too-large'; return; }
95
100
  const value = __pulse_fastly_value(handle);
96
101
  if (value.kind == PULSE_VALUE_NULL) this.add('null');
97
102
  else if (value.kind == PULSE_VALUE_BOOLEAN) this.add(value.boolean ? 'true' : 'false');
98
- else if (value.kind == PULSE_VALUE_STRING) { __kv_private(value.text); this.add(__pulse_fastly_quote(value.text)); }
103
+ else if (value.kind == PULSE_VALUE_STRING) this.add(__kv_private(value.text));
99
104
  else if (value.kind == PULSE_VALUE_NUMBER) { if (!isFinite(value.number)) this.reason = 'invalid-value'; else this.add(value.number == 0 ? '0' : __kv_number(value.number)); }
100
105
  else if (value.kind == PULSE_VALUE_ARRAY || value.kind == PULSE_VALUE_OBJECT) {
101
106
  if (this.seen.has(handle)) { this.reason = 'invalid-value'; return; } this.seen.add(handle);
102
107
  const object = value.kind == PULSE_VALUE_OBJECT; this.add(object ? '{' : '[');
103
108
  for (let i = 0; i < value.values.length && !this.reason.length; i++) {
104
109
  if (i) this.add(',');
105
- if (object) { __kv_private(value.keys[i]); this.add(__pulse_fastly_quote(value.keys[i]) + ':'); }
110
+ if (object) this.add(__kv_private(value.keys[i]) + ':');
106
111
  this.visit(value.values[i], depth + 1);
107
112
  }
108
113
  this.add(object ? '}' : ']');
109
114
  } else this.reason = 'invalid-value';
110
115
  }
111
- encode(handle: i32): string { this.visit(handle); return this.reason.length ? '' : this.parts.join(''); }
116
+ encode(handle: i32): string { this.visit(handle); return this.reason.length ? '' : this.parts!.join(''); }
112
117
  }
113
118
  function __pulse_fastly_kv_conditional_begin(index: i32, payload: __PulseFastlyValue): void {
114
119
  __kv_dispatched[index] = false;
@@ -171,8 +176,13 @@ function __kv_utf8(data: Uint8Array, length: i32): bool {
171
176
  }
172
177
  return true;
173
178
  }
179
+ // Each read is synchronous through owned-string decoding and parsing. Parallel
180
+ // effects enter their waits serially; no result or pending hostcall owns this
181
+ // scratch buffer. Only the written prefix is inspected, including after errors.
182
+ @lazy let __kv_read_buffer: Uint8Array | null = null;
174
183
  function __kv_read(index: i32, body: i32, generation: u64): i32 {
175
- const buffer = new Uint8Array(__KV_wireBytes + 1), written = new StaticArray<i32>(1); let count = 0;
184
+ if (__kv_read_buffer === null) __kv_read_buffer = new Uint8Array(__KV_wireBytes + 1);
185
+ const buffer = __kv_read_buffer!, written = new StaticArray<i32>(1); let count = 0;
176
186
  while (true) {
177
187
  const ready = __kv_ready(index, body); if (ready <= 0) return __kv_ready_failure(index, ready);
178
188
  written[0] = 0;
@@ -188,7 +198,7 @@ function __kv_read(index: i32, body: i32, generation: u64): i32 {
188
198
  if (outer.kind != PULSE_VALUE_OBJECT || outer.keys.length != 2 || __pulse_fastly_find(outer, '__pulseKv') < 0 || __pulse_fastly_find(outer, 'value') < 0) return __kv_failure(index, 'protocol');
189
199
  const marker = __pulse_fastly_value(__pulse_fastly_payload_field(outer, '__pulseKv'));
190
200
  if (marker.kind != PULSE_VALUE_NUMBER || marker.number != 1) return __kv_failure(index, 'protocol');
191
- const value = __pulse_fastly_payload_field(outer, 'value'), encoder = new __KvEncoder(); encoder.encode(value);
201
+ const value = __pulse_fastly_payload_field(outer, 'value'), encoder = new __KvEncoder(false); encoder.visit(value);
192
202
  if (encoder.reason.length) return __kv_failure(index, encoder.reason);
193
203
  const remaining = __kv_remaining(index); if (remaining <= 0) return __kv_failure(index, remaining == 0 ? 'timeout' : 'unavailable');
194
204
  const result = __kv_result('found'), token = __kv_token(generation); __kv_private(token);
@@ -6,7 +6,7 @@ function enabled(plan) {
6
6
 
7
7
  // Capture provider diagnostics before clearing them. A failed continuation is
8
8
  // drained once; only its application data error can enter the next Router lane.
9
- function runtimeSource() {
9
+ function runtimeSource(plan) {
10
10
  const jwt = ['TOKEN_REQUIRED', 'BEARER_INVALID', 'MALFORMED', 'LIMIT_EXCEEDED',
11
11
  'ALGORITHM_NOT_ALLOWED', 'KEY_INVALID', 'SIGNATURE_INVALID', 'CLOCK_INVALID',
12
12
  'CLAIMS_INVALID', 'CLAIMS_SCHEMA_INVALID'];
@@ -29,7 +29,10 @@ ${jwt.map((code, i) => ` case ${i + 1}: return "PULSE_JWT_${code}"`).join('
29
29
  if (__pulse_fastly_last_error != PULSE_ERROR_SCHEMA) return ""
30
30
  if (__pulse_fastly_error_stage == 21) return "PULSE_BODY_TOO_LARGE"
31
31
  if (__pulse_fastly_error_stage == 44) return "PULSE_SCHEMA_CONTENT_TYPE"
32
- if (__pulse_fastly_error_stage >= 50 && __pulse_fastly_error_stage <= 54)
32
+ // Stages 56/57 reject ScalarRecord and bounded nested JSON data.
33
+ // Stage 55 remains a fatal schema-ID/configuration error.
34
+ if ((__pulse_fastly_error_stage >= 50 && __pulse_fastly_error_stage <= 54)
35
+ || __pulse_fastly_error_stage == 56 || __pulse_fastly_error_stage == 57)
33
36
  return __pulse_application_failed_schema == 2 ? "PULSE_SCHEMA_ENCODE" : "PULSE_SCHEMA_DECODE"
34
37
  return ""
35
38
  }
@@ -37,6 +40,7 @@ function __pulse_application_clear(): void {
37
40
  __pulse_fastly_last_error = 0; __pulse_fastly_error_stage = 0; __pulse_fastly_error_effect = -1
38
41
  __pulse_fastly_jwt_error = 0; __pulse_application_failed_schema = 0
39
42
  }
43
+ ${(plan?.effects || []).length > 0 ? settlementSource() : ''}
40
44
  function host_router_error_take(): i32 {
41
45
  if (__pulse_fastly_last_error == 0) return 0
42
46
  const code = __pulse_application_code()
@@ -54,34 +58,53 @@ function host_router_error_take(): i32 {
54
58
  `;
55
59
  }
56
60
 
61
+ // The caller retains the static pending-slot guards. The shared body owns one
62
+ // site's resolution and authenticated settlement; diagnostics carry the saved
63
+ // failure between calls without allocating an accumulator or merging slot state.
64
+ function settlementSource() {
65
+ return `
66
+ // Returns 0 for recoverable/no failure, 1 for fatal, -1 for rejected settlement.
67
+ function __pulse_application_settle_effect(index: i32, fatal: bool): i32 {
68
+ let failure = __pulse_fastly_last_error
69
+ let stage = __pulse_fastly_error_stage
70
+ let effect = __pulse_fastly_error_effect
71
+ let jwt = __pulse_fastly_jwt_error
72
+ let schema = __pulse_application_failed_schema
73
+ const invocation = unchecked(__pulse_invocation_tickets[index])
74
+ __pulse_application_clear()
75
+ let result = host_value_undefined()
76
+ if (unchecked(__pulse_fastly_pending_mode[index]) != PULSE_FASTLY_PENDING_NONE) {
77
+ result = __pulse_fastly_resolve_effect(index)
78
+ if (result <= 0 && __pulse_fastly_last_error == 0) __pulse_fastly_fail(PULSE_ERROR_STATE, 101, index)
79
+ } else if (failure == 0) __pulse_fastly_fail(PULSE_ERROR_STATE, 101, index)
80
+ if (__pulse_fastly_last_error != 0) {
81
+ const terminal = __pulse_application_code().length == 0
82
+ if (failure == 0 || (!fatal && terminal)) {
83
+ failure = __pulse_fastly_last_error; stage = __pulse_fastly_error_stage; effect = __pulse_fastly_error_effect
84
+ jwt = __pulse_fastly_jwt_error; schema = __pulse_application_failed_schema; fatal = terminal
85
+ }
86
+ __pulse_application_clear()
87
+ result = host_value_undefined()
88
+ }
89
+ if (__pulse_invocation_settle(index, invocation, result) != 1) {
90
+ __pulse_fastly_fail(PULSE_ERROR_STATE, 101, index); __pulse_fastly_jwt_send_error(); return -1
91
+ }
92
+ __pulse_fastly_last_error = failure; __pulse_fastly_error_stage = stage; __pulse_fastly_error_effect = effect
93
+ __pulse_fastly_jwt_error = jwt; __pulse_application_failed_schema = schema
94
+ return fatal ? 1 : 0
95
+ }
96
+ `;
97
+ }
98
+
99
+ // Preserve the fatal-return boundary consumed by request-budget instrumentation.
57
100
  function driverLoop(plan) {
58
101
  return ` while (runStatus == 1) {
59
- let failure = __pulse_fastly_last_error
60
- let stage = __pulse_fastly_error_stage
61
- let effect = __pulse_fastly_error_effect
62
- let jwt = __pulse_fastly_jwt_error
63
- let schema = __pulse_application_failed_schema
64
- let fatal = failure != 0 && __pulse_application_code().length == 0
102
+ let fatal = __pulse_fastly_last_error != 0 && __pulse_application_code().length == 0
65
103
  ${(plan.effects || []).map((_, index) => ` if (__pulse_effect_pending_${index} != 0) {
66
- __pulse_application_clear()
67
- let result = host_value_undefined()
68
- if (unchecked(__pulse_fastly_pending_mode[${index}]) != PULSE_FASTLY_PENDING_NONE) {
69
- result = __pulse_fastly_resolve_effect(${index})
70
- if (result <= 0 && __pulse_fastly_last_error == 0) __pulse_fastly_fail(PULSE_ERROR_STATE, 101, ${index})
71
- } else if (failure == 0) __pulse_fastly_fail(PULSE_ERROR_STATE, 101, ${index})
72
- if (__pulse_fastly_last_error != 0) {
73
- const terminal = __pulse_application_code().length == 0
74
- if (failure == 0 || (!fatal && terminal)) {
75
- failure = __pulse_fastly_last_error; stage = __pulse_fastly_error_stage; effect = __pulse_fastly_error_effect
76
- jwt = __pulse_fastly_jwt_error; schema = __pulse_application_failed_schema; fatal = terminal
77
- }
78
- __pulse_application_clear()
79
- result = host_value_undefined()
80
- }
81
- if (pulse_set_effect_result(${index}, result) != 1) { __pulse_fastly_fail(PULSE_ERROR_STATE, 101, ${index}); return }
104
+ const settled = __pulse_application_settle_effect(${index}, fatal)
105
+ if (settled < 0) return
106
+ fatal = settled != 0
82
107
  }`).join('\n')}
83
- __pulse_fastly_last_error = failure; __pulse_fastly_error_stage = stage; __pulse_fastly_error_effect = effect
84
- __pulse_fastly_jwt_error = jwt; __pulse_application_failed_schema = schema
85
108
  if (fatal) return
86
109
  runStatus = pulse_resume()
87
110
  }`;