@pulse-compute/provider-fastly 1.0.0-beta.1 → 1.0.0-beta.11

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 (83) hide show
  1. package/README.md +7 -6
  2. package/dist/config-schema.json +30 -0
  3. package/dist/index.d.ts +16 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +8 -0
  6. package/dist/index.js.map +1 -1
  7. package/package.json +11 -10
  8. package/src/build/canonical-target.js +41 -2
  9. package/src/build/digest-native.js +25 -0
  10. package/src/build/effect-invocations.js +51 -0
  11. package/src/build/embedded-assets.as.ts +32 -0
  12. package/src/build/entities-native.js +6 -11
  13. package/src/build/host-extensions.js +254 -0
  14. package/src/build/kv-native.as.ts +331 -0
  15. package/src/build/kv-native.js +27 -0
  16. package/src/build/lifecycle.js +50 -0
  17. package/src/build/native-application-errors.js +159 -0
  18. package/src/build/native-binary-resources.js +30 -0
  19. package/src/build/native-body-forwarding.as.ts +325 -0
  20. package/src/build/native-body-forwarding.js +73 -0
  21. package/src/build/native-dynamic-backends.as.ts +115 -0
  22. package/src/build/native-dynamic-backends.js +52 -0
  23. package/src/build/native-fetch-accounting.as.ts +133 -0
  24. package/src/build/native-fetch-accounting.js +84 -0
  25. package/src/build/native-fetch-bounds.js +47 -0
  26. package/src/build/native-fetch-cohorts.as.ts +126 -0
  27. package/src/build/native-fetch-cohorts.js +65 -0
  28. package/src/build/native-fetch-deadlines.as.ts +169 -0
  29. package/src/build/native-fetch-deadlines.js +36 -0
  30. package/src/build/native-fetch-errors.js +38 -0
  31. package/src/build/native-fetch-headers.js +52 -0
  32. package/src/build/native-fetch-outcomes.js +87 -0
  33. package/src/build/native-fetch-timing.as.ts +74 -0
  34. package/src/build/native-fetch-timing.js +50 -0
  35. package/src/build/native-forwarding-accounting.as.ts +153 -0
  36. package/src/build/native-forwarding-accounting.js +47 -0
  37. package/src/build/native-handle-ownership.js +127 -0
  38. package/src/build/native-header-lookup.js +50 -0
  39. package/src/build/native-http-effects.js +164 -35
  40. package/src/build/native-platform-capabilities.js +815 -220
  41. package/src/build/native-request-body.js +45 -0
  42. package/src/build/native-request-headers.js +93 -0
  43. package/src/build/native-send-error-detail.as.ts +12 -0
  44. package/src/build/native-stdio.js +45 -0
  45. package/src/build/native-string-values.js +143 -0
  46. package/src/build/native-transport-details.as.ts +84 -0
  47. package/src/build/native-value-budget.js +90 -0
  48. package/src/build/package-native-application.js +114 -0
  49. package/src/build/request-budget-source.js +58 -0
  50. package/src/build/request-budget.js +46 -0
  51. package/src/build/response-authority.js +56 -0
  52. package/src/build/s3-body.as.ts +97 -0
  53. package/src/build/s3-native.as.ts +228 -0
  54. package/src/build/s3-native.js +30 -0
  55. package/src/build/schema-admission.js +83 -0
  56. package/src/build/schema-nested-json.js +93 -0
  57. package/src/build/schema-scalar-record.js +41 -0
  58. package/src/build/time-native.js +49 -0
  59. package/src/build/wasm-budget.js +28 -0
  60. package/src/config-api.js +6 -0
  61. package/src/config-schema.json +30 -0
  62. package/src/index.ts +25 -0
  63. package/src/javascript/fetch-adapter.js +3 -0
  64. package/src/javascript/jwt-verifier.js +14 -4
  65. package/src/javascript/logging.js +11 -2
  66. package/src/javascript/package-effects.js +5 -2
  67. package/src/javascript/runtime-host.js +8 -3
  68. package/src/javascript/source-package.js +4 -2
  69. package/src/javascript/target-support-policy.js +20 -3
  70. package/src/javascript/target.js +17 -1
  71. package/src/javascript/test-runtime.js +1 -0
  72. package/src/provider-contract.js +23 -6
  73. package/src/runtime/canonical-api-runtime.js +6 -0
  74. package/src/testing/conditional-kv-host.js +155 -0
  75. package/src/testing/native-dynamic-backends-host.js +39 -0
  76. package/src/testing/native-http-effects-host.js +18 -1
  77. package/src/testing/native-platform-capabilities-host.js +359 -24
  78. package/src/toolchain/body-forwarding.js +25 -0
  79. package/src/toolchain/config.js +16 -0
  80. package/src/toolchain/index.js +49 -5
  81. package/src/toolchain/logging.js +18 -0
  82. package/src/toolchain/native-execution.js +83 -0
  83. package/src/toolchain/s3.js +26 -0
@@ -1,6 +1,14 @@
1
1
  'use strict';
2
2
 
3
+ const { fetchHeadersSource } = require('./native-fetch-headers.js');
4
+
5
+ const dynamicBackends = require('./native-dynamic-backends.js');
6
+
7
+ const { scalarRecordProjectionLines } = require('./schema-scalar-record.js');
8
+ const { hasJsonAdmission, tracksJsonDuplicates, schemaParserDepth, nestedJsonProjectionLines, schemaJsonAdmissionSource, schemaFetchJsonSource } = require('./schema-nested-json.js');
9
+
3
10
  const crypto = require('node:crypto');
11
+ const { nativeStringAssembly, nativeStringFields, nativeStringConcat, nativeStringTrim, nativeStringIndex, needsNativeValueFailureGuard } = require('./native-string-values.js');
4
12
  const fs = require('node:fs');
5
13
  const os = require('node:os');
6
14
  const path = require('node:path');
@@ -46,7 +54,7 @@ const FASTLY_NATIVE_HTTP_EFFECTS_IMPORTS = Object.freeze([
46
54
  Object.freeze(['fastly_http_req', 'new']),
47
55
  Object.freeze(['fastly_http_req', 'method_set']),
48
56
  Object.freeze(['fastly_http_req', 'uri_set']),
49
- Object.freeze(['fastly_http_req', 'header_insert']),
57
+ Object.freeze(['fastly_http_req', 'header_append']),
50
58
  Object.freeze(['fastly_http_req', 'send_async']),
51
59
  Object.freeze(['fastly_http_req', 'pending_req_wait']),
52
60
  Object.freeze(['fastly_http_resp', 'new']),
@@ -72,6 +80,7 @@ const FASTLY_NATIVE_HTTP_EFFECTS_REQUIRED_IMPORTS = Object.freeze([
72
80
  ]);
73
81
 
74
82
  const FASTLY_NATIVE_HTTP_EFFECTS_ALLOWED_IMPORTS = new Set([
83
+ 'fastly_http_req:register_dynamic_backend',
75
84
  ...FASTLY_NATIVE_HTTP_EFFECTS_IMPORTS.map(([moduleName, name]) => `${moduleName}:${name}`)
76
85
  ]);
77
86
 
@@ -120,6 +129,9 @@ function validatePlanBoundary(plan) {
120
129
  if (packageEffects.length > 0) {
121
130
  fail('Pass97 does not realize package-owned Fastly effects; config, secret, KV, and GRIP are introduced in Pass98.', 'PULSE_FASTLY_NATIVE_HTTP_PLATFORM_EFFECTS_DEFERRED', { effects: packageEffects.map((entry) => entry.id) });
122
131
  }
132
+ if (plan.effects?.some(effect => effect.fetchErrors || effect.fetchTiming)) {
133
+ fail('Collected fetch outcomes require the canonical platform realization.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECT_KIND_UNSUPPORTED');
134
+ }
123
135
  const unsupported = (plan.effects || []).filter((effect) => effect.kind !== 'fetch');
124
136
  if (unsupported.length > 0) {
125
137
  fail('Pass97 realizes only outbound HTTP fetch effects.', 'PULSE_FASTLY_NATIVE_HTTP_EFFECT_KIND_UNSUPPORTED', { effects: unsupported.map((entry) => ({ id: entry.id, kind: entry.kind })) });
@@ -150,8 +162,9 @@ function literalOriginFromExpression(expression) {
150
162
  }
151
163
 
152
164
  function resolveBackendBindings(plan, options = {}) {
153
- const byEffect = options.effectBackends || {};
154
- const byOrigin = options.backends || {};
165
+ const source = options.bindings || options;
166
+ const byEffect = source.effectBackends || {};
167
+ const byOrigin = source.backends || {};
155
168
  const bindings = [];
156
169
  for (const [index, effect] of (plan.effects || []).entries()) {
157
170
  const urlInput = (effect.inputs || []).find((entry) => entry.name === 'url');
@@ -161,7 +174,7 @@ function resolveBackendBindings(plan, options = {}) {
161
174
  const backend = byEffect[effect.id]
162
175
  || (origin && byOrigin[origin])
163
176
  || (effect.resource && effect.resource.value && byOrigin[effect.resource.value]);
164
- if (typeof backend !== 'string' || backend.trim() === '') {
177
+ if ((typeof backend !== 'string' || backend.trim() === '') && source.dynamicBackends !== true) {
165
178
  fail(`Fastly native effect ${effect.id} has no static backend binding.`, 'PULSE_FASTLY_NATIVE_HTTP_BACKEND_MISSING', {
166
179
  effectId: effect.id,
167
180
  effectIndex: index,
@@ -169,7 +182,7 @@ function resolveBackendBindings(plan, options = {}) {
169
182
  hint: `Provide options.effectBackends[${JSON.stringify(effect.id)}] or options.backends[${JSON.stringify(origin || '<origin>')}].`
170
183
  });
171
184
  }
172
- bindings.push(Object.freeze({ index, effectId: effect.id, origin: origin || null, backend: backend.trim() }));
185
+ bindings.push(Object.freeze({ index, effectId: effect.id, origin: origin || null, backend: typeof backend === 'string' ? backend.trim() : '', ...(typeof backend !== 'string' || !backend.trim() ? { dynamic: true } : {}) }));
173
186
  }
174
187
  return Object.freeze(bindings);
175
188
  }
@@ -198,30 +211,43 @@ function generateSchemaRuntime(plan) {
198
211
  const fields = node.kind === 'object'
199
212
  ? node.fields.map((field) => Object.freeze({ field, apply: emitNode(schemaIndex, field.value) }))
200
213
  : [];
201
- const body = [`function ${functionName}(valueHandle: i32): i32 {`, ' const input = __pulse_fastly_value(valueHandle)'];
214
+ const body = [`function ${functionName}(valueHandle: i32, checkDuplicates: bool): i32 {`, ' const input = __pulse_fastly_value(valueHandle)'];
202
215
  if (node.kind === 'nullable') {
203
216
  body.push(' if (input.kind == PULSE_VALUE_NULL) return valueHandle');
204
- body.push(` return ${child}(valueHandle)`);
217
+ body.push(` return ${child}(valueHandle, checkDuplicates)`);
205
218
  } else if (node.kind === 'array') {
206
219
  body.push(' if (input.kind != PULSE_VALUE_ARRAY) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 52, -1); return 0 }');
207
220
  body.push(' const output = host_value_array()');
208
221
  body.push(' for (let index = 0; index < input.values.length; index += 1) {');
209
- body.push(` const item = ${child}(unchecked(input.values[index]))`);
222
+ body.push(` const item = ${child}(unchecked(input.values[index]), checkDuplicates)`);
210
223
  body.push(' if (item <= 0) return 0');
211
224
  body.push(' host_value_array_push(output, item)');
212
225
  body.push(' }');
213
226
  body.push(' return output');
227
+ } else if (node.kind === 'json-value' || node.kind === 'json-object') {
228
+ body.push(...nestedJsonProjectionLines(node));
229
+ } else if (node.kind === 'scalar-record') {
230
+ body.push(...scalarRecordProjectionLines(node));
214
231
  } else if (node.kind === 'object') {
215
232
  body.push(' if (input.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 50, -1); return 0 }');
233
+ if (node.additionalProperties) body.push(' if (checkDuplicates && input.duplicateJsonKeys) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 57, -1); return 0 }');
216
234
  body.push(' const output = host_value_object()');
217
235
  fields.forEach(({ field, apply }, fieldIndex) => {
218
236
  body.push(` const key_${currentIndex}_${fieldIndex} = __pulse_fastly_string_value(${quote(field.name)})`);
237
+ if (!field.required) body.push(` if (__pulse_fastly_find(input, ${quote(field.name)}) >= 0) {`);
219
238
  body.push(` const field_${currentIndex}_${fieldIndex} = host_value_property(valueHandle, key_${currentIndex}_${fieldIndex})`);
220
239
  body.push(` if (__pulse_fastly_value(field_${currentIndex}_${fieldIndex}).kind == PULSE_VALUE_UNDEFINED) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 51, -1); return 0 }`);
221
- body.push(` const projected_${currentIndex}_${fieldIndex} = ${apply}(field_${currentIndex}_${fieldIndex})`);
240
+ body.push(` const projected_${currentIndex}_${fieldIndex} = ${apply}(field_${currentIndex}_${fieldIndex}, checkDuplicates)`);
222
241
  body.push(` if (projected_${currentIndex}_${fieldIndex} <= 0) return 0`);
223
242
  body.push(` host_value_object_set(output, key_${currentIndex}_${fieldIndex}, projected_${currentIndex}_${fieldIndex})`);
243
+ if (!field.required) body.push(' }');
224
244
  });
245
+ if (node.additionalProperties) {
246
+ body.push(' for (let index = 0; index < input.keys.length; index++) {', ' const key = unchecked(input.keys[index])');
247
+ if (node.fields.length) body.push(` if (${node.fields.map(field => `key == ${quote(field.name)}`).join(' || ')}) continue`);
248
+ body.push(' const item = __pulse_fastly_copy_json(unchecked(input.values[index]), checkDuplicates)',
249
+ ' if (item <= 0) return 0', ' host_value_object_set(output, __pulse_fastly_string_value(key), item)', ' }');
250
+ }
225
251
  body.push(' return output');
226
252
  } else if (node.kind === 'string') {
227
253
  body.push(' if (input.kind != PULSE_VALUE_STRING) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 52, -1); return 0 }');
@@ -255,17 +281,22 @@ function generateSchemaRuntime(plan) {
255
281
  `const __PULSE_SCHEMA_MAX_BYTES: i32 = ${Number(registry.maxBytes || FASTLY_NATIVE_HTTP_EFFECTS_BUFFER_BYTES)}`,
256
282
  `const __PULSE_SCHEMA_REQUIRE_JSON: bool = ${registry.contentTypePolicy === 'require-json' ? 'true' : 'false'}`,
257
283
  '',
284
+ schemaJsonAdmissionSource(plan),
285
+ fetchHeadersSource(),
286
+ schemaFetchJsonSource(),
258
287
  ...nodeLines,
259
288
  'function __pulse_fastly_schema_apply(schemaId: string, valueHandle: i32, encode: bool): i32 {',
260
289
  ' if (schemaId.length == 0) return valueHandle'
261
290
  ];
262
291
  for (const [schemaIndex, schema] of schemas.entries()) {
263
292
  lines.push(`${schemaIndex === 0 ? ' if' : ' else if'} (schemaId == ${quote(schema.id)}) {`);
264
- lines.push(` const projected = ${roots[schemaIndex]}(valueHandle)`);
293
+ if (schema.jsonLimits) lines.push(` if (__pulse_fastly_admit_bounded_value(valueHandle, __pulse_schema_json_limits_${schemaIndex}()).failure != 0) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 57, -1); return 0 }`);
294
+ lines.push(` const projected = ${roots[schemaIndex]}(valueHandle, !encode)`);
265
295
  lines.push(' if (projected <= 0) return 0');
266
296
  lines.push(' const input = __pulse_fastly_json(projected, 0)');
267
297
  lines.push(` const normalized = encode ? __pulse_schema_encode_${schemaIndex}(input) : __pulse_schema_decode_${schemaIndex}(input)`);
268
- lines.push(' return __pulse_fastly_parse_json(normalized)');
298
+ if (schema.jsonLimits) lines.push(' const output = __pulse_fastly_parse_json(normalized)', ' if (output > 0) __pulse_fastly_deep_freeze(output)', ' return output');
299
+ else lines.push(' return __pulse_fastly_parse_json(normalized)');
269
300
  lines.push(' }');
270
301
  }
271
302
  lines.push(' __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 55, -1)');
@@ -316,7 +347,7 @@ function fastlyRuntimeSource(plan, bindings) {
316
347
  @external("fastly_http_req", "new") declare function fastly_http_req_new(handleOut: usize): i32
317
348
  @external("fastly_http_req", "method_set") declare function fastly_http_req_method_set(handle: i32, method: usize, methodLength: i32): i32
318
349
  @external("fastly_http_req", "uri_set") declare function fastly_http_req_uri_set(handle: i32, uri: usize, uriLength: i32): i32
319
- @external("fastly_http_req", "header_insert") declare function fastly_http_req_header_insert(handle: i32, name: usize, nameLength: i32, value: usize, valueLength: i32): i32
350
+ @external("fastly_http_req", "header_append") declare function fastly_http_req_header_append(handle: i32, name: usize, nameLength: i32, value: usize, valueLength: i32): i32
320
351
  @external("fastly_http_req", "send_async") declare function fastly_http_req_send_async(handle: i32, body: i32, backend: usize, backendLength: i32, pendingOut: usize): i32
321
352
  @external("fastly_http_req", "pending_req_wait") declare function fastly_http_req_pending_req_wait(handle: i32, responseOut: usize, bodyOut: usize): i32
322
353
  @external("fastly_http_resp", "new") declare function fastly_http_resp_new(handleOut: usize): i32
@@ -354,17 +385,34 @@ const PULSE_ERROR_TRANSPORT: i32 = 1006
354
385
  const PULSE_ERROR_STATE: i32 = 1007
355
386
 
356
387
  class __PulseFastlyValue {
388
+ ${tracksJsonDuplicates(plan) ? 'duplicateJsonKeys: bool = false' : ''}
389
+ immutable: bool = false
357
390
  kind: i32 = PULSE_VALUE_UNDEFINED
358
391
  boolean: i32 = 0
359
392
  number: f64 = 0.0
360
- text: string = ""
361
- keys: Array<string> = new Array<string>()
362
- values: Array<i32> = new Array<i32>()
393
+ ${nativeStringFields}
394
+ // Scalar handles do not need collection backing stores.
395
+ private keysStorage: Array<string> | null = null
396
+ get keys(): Array<string> {
397
+ if (this.keysStorage === null) this.keysStorage = new Array<string>()
398
+ return this.keysStorage!
399
+ }
400
+ // Scalar handles do not need collection backing stores.
401
+ private valuesStorage: Array<i32> | null = null
402
+ get values(): Array<i32> {
403
+ if (this.valuesStorage === null) this.valuesStorage = new Array<i32>()
404
+ return this.valuesStorage!
405
+ }
363
406
  responseHandle: i32 = 0
364
407
  bodyHandle: i32 = 0
365
408
  bodyLoaded: i32 = 0
366
409
  status: i32 = 200
367
- headers: Array<__PulseFastlyHeader> = new Array<__PulseFastlyHeader>()
410
+ // Scalar handles do not need collection backing stores.
411
+ private headersStorage: Array<__PulseFastlyHeader> | null = null
412
+ get headers(): Array<__PulseFastlyHeader> {
413
+ if (this.headersStorage === null) this.headersStorage = new Array<__PulseFastlyHeader>()
414
+ return this.headersStorage!
415
+ }
368
416
  }
369
417
  class __PulseFastlyHeader {
370
418
  constructor(public name: string, public value: string) {}
@@ -377,7 +425,7 @@ class __PulseJsonParser {
377
425
  skip(): void { while (this.index < this.source.length) { const c = this.source.charCodeAt(this.index); if (c != 32 && c != 9 && c != 10 && c != 13) return; this.index += 1 } }
378
426
  parse(): i32 { this.skip(); const value = this.value(0); this.skip(); if (this.index != this.source.length) this.failed = true; return this.failed ? 0 : value }
379
427
  value(depth: i32): i32 {
380
- this.skip(); if (this.index >= this.source.length || depth > 64) { this.failed = true; return 0 }
428
+ this.skip(); if (this.index >= this.source.length || depth > ${schemaParserDepth(plan)}) { this.failed = true; return 0 }
381
429
  const c = this.source.charCodeAt(this.index)
382
430
  if (c == 34) return __pulse_fastly_string_value(this.string())
383
431
  if (c == 123) return this.object(depth + 1)
@@ -469,6 +517,7 @@ class __PulseJsonParser {
469
517
  this.skip(); if (this.index >= this.source.length || this.source.charCodeAt(this.index) != 34) { this.failed = true; break }
470
518
  const key = this.string(); this.skip()
471
519
  if (this.index >= this.source.length || this.source.charCodeAt(this.index) != 58) { this.failed = true; break }
520
+ ${tracksJsonDuplicates(plan) ? 'if (__pulse_fastly_find(__pulse_fastly_value(output), key) >= 0) __pulse_fastly_value(output).duplicateJsonKeys = true' : ''}
472
521
  this.index += 1; host_value_object_set(output, __pulse_fastly_string_value(key), this.value(depth)); this.skip()
473
522
  if (this.index >= this.source.length) { this.failed = true; break }
474
523
  const c = this.source.charCodeAt(this.index); this.index += 1
@@ -480,6 +529,10 @@ class __PulseJsonParser {
480
529
  }
481
530
 
482
531
  const __pulse_fastly_values = new Array<__PulseFastlyValue>()
532
+ // Shared schema admission uses storage-independent lookups. This retained
533
+ // HTTP emitter keeps its existing dense table and lifetime policy.
534
+ function __pulse_fastly_has_value(handle: i32): bool { return handle > 0 && handle <= __pulse_fastly_values.length }
535
+ function __pulse_fastly_value_count(): i32 { return __pulse_fastly_values.length }
483
536
  const __pulse_fastly_pending = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
484
537
  const __pulse_fastly_pending_active = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
485
538
  const __pulse_fastly_payloads = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
@@ -507,9 +560,37 @@ function __pulse_fastly_number_string(value: f64): string { if (value >= -900719
507
560
  function __pulse_fastly_string(handle: i32): string { const value = __pulse_fastly_value(handle); if (value.kind == PULSE_VALUE_STRING) return value.text; if (value.kind == PULSE_VALUE_NUMBER) return __pulse_fastly_number_string(value.number); if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean != 0 ? "true" : "false"; if (value.kind == PULSE_VALUE_NULL) return "null"; if (value.kind == PULSE_VALUE_UNDEFINED) return "undefined"; return __pulse_fastly_json(handle, 0) }
508
561
  function __pulse_fastly_number(handle: i32): f64 { const value = __pulse_fastly_value(handle); if (value.kind == PULSE_VALUE_NUMBER) return value.number; if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean != 0 ? 1.0 : 0.0; if (value.kind == PULSE_VALUE_STRING) return F64.parseFloat(value.text); return 0.0 }
509
562
  function __pulse_fastly_hex(value: i32): string { return String.fromCharCode(value < 10 ? 48 + value : 87 + value) }
510
- function __pulse_fastly_quote(value: string): string { let out = "\""; for (let i = 0; i < value.length; i += 1) { const c = value.charCodeAt(i); if (c == 34) out += "\\\""; else if (c == 92) out += "\\\\"; else if (c == 8) out += "\\b"; else if (c == 9) out += "\\t"; else if (c == 10) out += "\\n"; else if (c == 12) out += "\\f"; else if (c == 13) out += "\\r"; else if (c < 32) out += "\\u00" + __pulse_fastly_hex((c >> 4) & 15) + __pulse_fastly_hex(c & 15); else out += String.fromCharCode(c) } return out + "\"" }
563
+ function __pulse_fastly_is_unpaired(value: string, i: i32): bool {
564
+ const c = value.charCodeAt(i);
565
+ if (c >= 0xd800 && c <= 0xdbff) return i + 1 >= value.length || value.charCodeAt(i + 1) < 0xdc00 || value.charCodeAt(i + 1) > 0xdfff;
566
+ if (c >= 0xdc00 && c <= 0xdfff) return i == 0 || value.charCodeAt(i - 1) < 0xd800 || value.charCodeAt(i - 1) > 0xdbff;
567
+ return false;
568
+ }
569
+ function __pulse_fastly_quote(value: string): string {
570
+ // Count once and write UTF-16 units once. Repeated concatenation can allocate
571
+ // gigabytes for a valid bounded string when every byte needs JSON escaping.
572
+ let size = 2;
573
+ for (let i = 0; i < value.length; i++) {
574
+ const c = value.charCodeAt(i);
575
+ size += c == 34 || c == 92 || c == 8 || c == 9 || c == 10 || c == 12 || c == 13 ? 2 : (c < 32 || __pulse_fastly_is_unpaired(value, i)) ? 6 : 1;
576
+ }
577
+ const out = new Uint16Array(size); let cursor = 0; out[cursor++] = 34;
578
+ for (let i = 0; i < value.length; i++) {
579
+ const c = value.charCodeAt(i);
580
+ if (c == 34 || c == 92) { out[cursor++] = 92; out[cursor++] = u16(c); }
581
+ else if (c == 8 || c == 9 || c == 10 || c == 12 || c == 13) {
582
+ out[cursor++] = 92; out[cursor++] = c == 8 ? 98 : c == 9 ? 116 : c == 10 ? 110 : c == 12 ? 102 : 114;
583
+ } else if (c < 32 || __pulse_fastly_is_unpaired(value, i)) {
584
+ out[cursor++] = 92; out[cursor++] = 117;
585
+ out[cursor++] = u16('0123456789abcdef'.charCodeAt((c >> 12) & 15)); out[cursor++] = u16('0123456789abcdef'.charCodeAt((c >> 8) & 15));
586
+ out[cursor++] = u16('0123456789abcdef'.charCodeAt((c >> 4) & 15)); out[cursor++] = u16('0123456789abcdef'.charCodeAt(c & 15));
587
+ } else out[cursor++] = u16(c);
588
+ }
589
+ out[cursor] = 34;
590
+ return String.UTF16.decodeUnsafe(out.dataStart, out.byteLength);
591
+ }
511
592
  function __pulse_fastly_json(handle: i32, depth: i32): string {
512
- if (depth > 64) { __pulse_fastly_fail(PULSE_ERROR_JSON, 2, -1); return "null" }
593
+ if (depth > ${schemaParserDepth(plan)}) { __pulse_fastly_fail(PULSE_ERROR_JSON, 2, -1); return "null" }
513
594
  const value = __pulse_fastly_value(handle)
514
595
  if (value.kind == PULSE_VALUE_UNDEFINED || value.kind == PULSE_VALUE_NULL) return "null"
515
596
  if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean != 0 ? "true" : "false"
@@ -519,6 +600,11 @@ function __pulse_fastly_json(handle: i32, depth: i32): string {
519
600
  if (value.kind == PULSE_VALUE_OBJECT) { let out = "{"; for (let i = 0; i < value.keys.length; i += 1) { if (i > 0) out += ","; out += __pulse_fastly_quote(unchecked(value.keys[i])) + ":" + __pulse_fastly_json(unchecked(value.values[i]), depth + 1) } return out + "}" }
520
601
  return "null"
521
602
  }
603
+ ${nativeStringAssembly}
604
+ ${nativeStringConcat}
605
+ ${nativeStringTrim}
606
+ ${nativeStringIndex}
607
+ function __pulse_fastly_deep_freeze(handle: i32): void { const value = __pulse_fastly_value(handle); if (value.immutable) return; value.immutable = true; if (value.kind == PULSE_VALUE_ARRAY || value.kind == PULSE_VALUE_OBJECT) for (let index = 0; index < value.values.length; index += 1) __pulse_fastly_deep_freeze(unchecked(value.values[index])) }
522
608
  function __pulse_fastly_parse_json(text: string): i32 { const parser = new __PulseJsonParser(text); const value = parser.parse(); if (parser.failed || value <= 0) { __pulse_fastly_fail(PULSE_ERROR_JSON, 3, -1); return 0 } return value }
523
609
  function __pulse_fastly_path(uri: string): string { let start = 0; const scheme = uri.indexOf("://"); if (scheme >= 0) { const slash = uri.indexOf("/", scheme + 3); start = slash >= 0 ? slash : uri.length } let end = uri.length; const query = uri.indexOf("?", start); if (query >= 0 && query < end) end = query; const fragment = uri.indexOf("#", start); if (fragment >= 0 && fragment < end) end = fragment; return start >= end ? "/" : uri.substring(start, end) }
524
610
  function __pulse_fastly_read_req_string(kind: i32): string { const buffer = new Uint8Array(PULSE_FASTLY_BUFFER_BYTES); const written = __pulse_fastly_out_i32(); const status = kind == 0 ? fastly_http_req_method_get(__pulse_fastly_request_handle, buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(written)) : fastly_http_req_uri_get(__pulse_fastly_request_handle, buffer.dataStart, PULSE_FASTLY_BUFFER_BYTES, changetype<usize>(written)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 10 + kind, -1); return "" } return __pulse_fastly_decode(buffer, __pulse_fastly_out_value(written)) }
@@ -530,21 +616,28 @@ function __pulse_fastly_fetch_body(value: __PulseFastlyValue): string { if (valu
530
616
  function host_value_undefined(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_UNDEFINED; return __pulse_fastly_put(item) }
531
617
  function host_value_null(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_NULL; return __pulse_fastly_put(item) }
532
618
  function host_value_boolean(value: i32): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_BOOLEAN; item.boolean = value != 0 ? 1 : 0; return __pulse_fastly_put(item) }
619
+ ${plan.binaryResources || plan.numericWorkspaces?.length ? require('./native-binary-resources.js').source() : ''}
533
620
  function host_value_number(value: f64): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_NUMBER; item.number = value; return __pulse_fastly_put(item) }
534
621
  function host_value_string(pointer: i32, length: i32): i32 { return __pulse_fastly_string_value(changetype<string>(pointer)) }
622
+ function host_effect_collection_count(handle: i32, max: i32, stateIndex: i32): i32 {
623
+ const input = __pulse_fastly_value(handle)
624
+ if (__pulse_fastly_last_error != 0 || input.kind != PULSE_VALUE_ARRAY || max < 1 || max > 32) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 173, -1); return -1 }
625
+ if (input.values.length > max) { __pulse_fastly_fail(PULSE_ERROR_STATE, 172, -1); return -1 }
626
+ return input.values.length
627
+ }
535
628
  function host_value_array(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_ARRAY; return __pulse_fastly_put(item) }
536
- function host_value_array_push(target: i32, value: i32): void { const item = __pulse_fastly_value(target); if (item.kind != PULSE_VALUE_ARRAY) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 30, -1); return } item.values.push(value) }
629
+ function host_value_array_push(target: i32, value: i32): void { const item = __pulse_fastly_value(target); if (item.kind != PULSE_VALUE_ARRAY || item.immutable) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 30, -1); return } item.values.push(value) }
537
630
  function host_value_array_spread(target: i32, source: i32): void { const from = __pulse_fastly_value(source); if (from.kind != PULSE_VALUE_ARRAY) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 31, -1); return } for (let i = 0; i < from.values.length; i += 1) host_value_array_push(target, unchecked(from.values[i])) }
538
631
  function host_value_object(): i32 { const item = new __PulseFastlyValue(); item.kind = PULSE_VALUE_OBJECT; return __pulse_fastly_put(item) }
539
- function host_value_object_set(target: i32, keyHandle: i32, value: i32): void { const item = __pulse_fastly_value(target); if (item.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 32, -1); return } const key = __pulse_fastly_string(keyHandle); const index = __pulse_fastly_find(item, key); if (index >= 0) unchecked(item.values[index] = value); else { item.keys.push(key); item.values.push(value) } }
632
+ function host_value_object_set(target: i32, keyHandle: i32, value: i32): void { const item = __pulse_fastly_value(target); if (item.kind != PULSE_VALUE_OBJECT || item.immutable) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 32, -1); return } const key = __pulse_fastly_string(keyHandle); const index = __pulse_fastly_find(item, key); if (index >= 0) unchecked(item.values[index] = value); else { item.keys.push(key); item.values.push(value) } }
540
633
  function host_value_object_spread(target: i32, source: i32): void { const from = __pulse_fastly_value(source); if (from.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 33, -1); return } for (let i = 0; i < from.keys.length; i += 1) host_value_object_set(target, __pulse_fastly_string_value(unchecked(from.keys[i])), unchecked(from.values[i])) }
541
- function host_value_property(target: i32, keyHandle: i32): i32 { const item = __pulse_fastly_value(target); const key = __pulse_fastly_string(keyHandle); if (item.kind == PULSE_VALUE_OBJECT) { const index = __pulse_fastly_find(item, key); return index >= 0 ? unchecked(item.values[index]) : host_value_undefined() } if (item.kind == PULSE_VALUE_FETCH && key == "status") { const out = __pulse_fastly_out_i32(); const status = fastly_http_resp_status_get(item.responseHandle, changetype<usize>(out)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 34, -1); return 0 } return host_value_number(__pulse_fastly_out_value(out)) } if ((item.kind == PULSE_VALUE_STRING || item.kind == PULSE_VALUE_ARRAY) && key == "length") return host_value_number(item.kind == PULSE_VALUE_STRING ? item.text.length : item.values.length); return host_value_undefined() }
634
+ function host_value_property(target: i32, keyHandle: i32): i32 { const item = __pulse_fastly_value(target); const key = __pulse_fastly_string(keyHandle); if (item.kind == PULSE_VALUE_OBJECT) { const index = __pulse_fastly_find(item, key); return index >= 0 ? unchecked(item.values[index]) : host_value_undefined() } if (item.kind == PULSE_VALUE_FETCH && key == "status") { const out = __pulse_fastly_out_i32(); const status = fastly_http_resp_status_get(item.responseHandle, changetype<usize>(out)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 34, -1); return 0 } return host_value_number(__pulse_fastly_out_value(out)) } if ((item.kind == PULSE_VALUE_STRING || item.kind == PULSE_VALUE_ARRAY) && key == "length") return host_value_number(item.kind == PULSE_VALUE_STRING ? item.textLength : item.values.length); return host_value_undefined() }
542
635
  function host_value_property_set(target: i32, key: i32, value: i32): i32 { host_value_object_set(target, key, value); return value }
543
- function host_value_element(target: i32, keyHandle: i32): i32 { const item = __pulse_fastly_value(target); if (item.kind == PULSE_VALUE_ARRAY) { const index = i32(__pulse_fastly_number(keyHandle)); return index >= 0 && index < item.values.length ? unchecked(item.values[index]) : host_value_undefined() } return host_value_property(target, keyHandle) }
544
- function host_value_element_set(target: i32, keyHandle: i32, value: i32): i32 { const item = __pulse_fastly_value(target); if (item.kind == PULSE_VALUE_ARRAY) { const index = i32(__pulse_fastly_number(keyHandle)); if (index < 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 35, -1); return 0 } while (item.values.length <= index) item.values.push(host_value_undefined()); unchecked(item.values[index] = value); return value } return host_value_property_set(target, keyHandle, value) }
545
- function host_value_truthy(handle: i32): i32 { const value = __pulse_fastly_value(handle); if (value.kind == PULSE_VALUE_UNDEFINED || value.kind == PULSE_VALUE_NULL) return 0; if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean; if (value.kind == PULSE_VALUE_NUMBER) return value.number != 0.0 && !isNaN(value.number) ? 1 : 0; if (value.kind == PULSE_VALUE_STRING) return value.text.length > 0 ? 1 : 0; return 1 }
636
+ function host_value_element(target: i32, keyHandle: i32): i32 { const item = __pulse_fastly_value(target); if (item.kind == PULSE_VALUE_STRING) return __pulse_fastly_string_index(item, keyHandle); if (item.kind == PULSE_VALUE_ARRAY) { const index = i32(__pulse_fastly_number(keyHandle)); return index >= 0 && index < item.values.length ? unchecked(item.values[index]) : host_value_undefined() } return host_value_property(target, keyHandle) }
637
+ function host_value_element_set(target: i32, keyHandle: i32, value: i32): i32 { const item = __pulse_fastly_value(target); if (item.immutable) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 35, -1); return 0 } if (item.kind == PULSE_VALUE_ARRAY) { const index = i32(__pulse_fastly_number(keyHandle)); if (index < 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 35, -1); return 0 } while (item.values.length <= index) item.values.push(host_value_undefined()); unchecked(item.values[index] = value); return value } return host_value_property_set(target, keyHandle, value) }
638
+ function host_value_truthy(handle: i32): i32 { const value = __pulse_fastly_value(handle); if (value.kind == PULSE_VALUE_UNDEFINED || value.kind == PULSE_VALUE_NULL) return 0; if (value.kind == PULSE_VALUE_BOOLEAN) return value.boolean; if (value.kind == PULSE_VALUE_NUMBER) return value.number != 0.0 && !isNaN(value.number) ? 1 : 0; if (value.kind == PULSE_VALUE_STRING) return value.textLength > 0 ? 1 : 0; return 1 }
546
639
  function host_value_nullish(handle: i32): i32 { const kind = __pulse_fastly_value(handle).kind; return kind == PULSE_VALUE_UNDEFINED || kind == PULSE_VALUE_NULL ? 1 : 0 }
547
- function host_value_binary(operator: i32, leftHandle: i32, rightHandle: i32): i32 { const left = __pulse_fastly_value(leftHandle); const right = __pulse_fastly_value(rightHandle); if (operator == 0 || operator == 2) { let equal = false; if (left.kind == right.kind) { if (left.kind == PULSE_VALUE_UNDEFINED || left.kind == PULSE_VALUE_NULL) equal = true; else if (left.kind == PULSE_VALUE_BOOLEAN) equal = left.boolean == right.boolean; else if (left.kind == PULSE_VALUE_NUMBER) equal = left.number == right.number; else if (left.kind == PULSE_VALUE_STRING) equal = left.text == right.text; else equal = leftHandle == rightHandle } return host_value_boolean(equal ? 1 : 0) } if (operator == 1 || operator == 3) { const result = host_value_binary(operator == 1 ? 0 : 2, leftHandle, rightHandle); return host_value_boolean(host_value_truthy(result) == 0 ? 1 : 0) } if (operator == 8) { if (left.kind == PULSE_VALUE_STRING || right.kind == PULSE_VALUE_STRING) return __pulse_fastly_string_value(__pulse_fastly_string(leftHandle) + __pulse_fastly_string(rightHandle)); return host_value_number(__pulse_fastly_number(leftHandle) + __pulse_fastly_number(rightHandle)) } if (operator == 4) return host_value_boolean(__pulse_fastly_number(leftHandle) < __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 5) return host_value_boolean(__pulse_fastly_number(leftHandle) <= __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 6) return host_value_boolean(__pulse_fastly_number(leftHandle) > __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 7) return host_value_boolean(__pulse_fastly_number(leftHandle) >= __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 9) return host_value_number(__pulse_fastly_number(leftHandle) - __pulse_fastly_number(rightHandle)); if (operator == 10) return host_value_number(__pulse_fastly_number(leftHandle) * __pulse_fastly_number(rightHandle)); if (operator == 11) return host_value_number(__pulse_fastly_number(leftHandle) / __pulse_fastly_number(rightHandle)); if (operator == 14) return host_value_truthy(leftHandle) != 0 ? rightHandle : leftHandle; if (operator == 15) return host_value_truthy(leftHandle) != 0 ? leftHandle : rightHandle; if (operator == 16) return host_value_nullish(leftHandle) == 0 ? leftHandle : rightHandle; __pulse_fastly_fail(PULSE_ERROR_UNSUPPORTED, 36, -1); return 0 }
640
+ function host_value_binary(operator: i32, leftHandle: i32, rightHandle: i32): i32 { const left = __pulse_fastly_value(leftHandle); const right = __pulse_fastly_value(rightHandle); if (operator == 0 || operator == 2) { let equal = false; if (left.kind == right.kind) { if (left.kind == PULSE_VALUE_UNDEFINED || left.kind == PULSE_VALUE_NULL) equal = true; else if (left.kind == PULSE_VALUE_BOOLEAN) equal = left.boolean == right.boolean; else if (left.kind == PULSE_VALUE_NUMBER) equal = left.number == right.number; else if (left.kind == PULSE_VALUE_STRING) equal = left.text == right.text; else equal = leftHandle == rightHandle } return host_value_boolean(equal ? 1 : 0) } if (operator == 1 || operator == 3) { const result = host_value_binary(operator == 1 ? 0 : 2, leftHandle, rightHandle); return host_value_boolean(host_value_truthy(result) == 0 ? 1 : 0) } if (operator == 8) { if (left.kind == PULSE_VALUE_STRING || right.kind == PULSE_VALUE_STRING) return __pulse_fastly_concat(leftHandle, rightHandle); return host_value_number(__pulse_fastly_number(leftHandle) + __pulse_fastly_number(rightHandle)) } if (left.kind == PULSE_VALUE_STRING && right.kind == PULSE_VALUE_STRING) { if (operator == 4) return host_value_boolean(left.text < right.text ? 1 : 0); if (operator == 5) return host_value_boolean(left.text <= right.text ? 1 : 0); if (operator == 6) return host_value_boolean(left.text > right.text ? 1 : 0); if (operator == 7) return host_value_boolean(left.text >= right.text ? 1 : 0); } if (operator == 4) return host_value_boolean(__pulse_fastly_number(leftHandle) < __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 5) return host_value_boolean(__pulse_fastly_number(leftHandle) <= __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 6) return host_value_boolean(__pulse_fastly_number(leftHandle) > __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 7) return host_value_boolean(__pulse_fastly_number(leftHandle) >= __pulse_fastly_number(rightHandle) ? 1 : 0); if (operator == 9) return host_value_number(__pulse_fastly_number(leftHandle) - __pulse_fastly_number(rightHandle)); if (operator == 10) return host_value_number(__pulse_fastly_number(leftHandle) * __pulse_fastly_number(rightHandle)); if (operator == 11) return host_value_number(__pulse_fastly_number(leftHandle) / __pulse_fastly_number(rightHandle)); if (operator == 12) return host_value_number(__pulse_fastly_number(leftHandle) % __pulse_fastly_number(rightHandle)); if (operator == 14) return host_value_truthy(leftHandle) != 0 ? rightHandle : leftHandle; if (operator == 15) return host_value_truthy(leftHandle) != 0 ? leftHandle : rightHandle; if (operator == 16) return host_value_nullish(leftHandle) == 0 ? leftHandle : rightHandle; __pulse_fastly_fail(PULSE_ERROR_UNSUPPORTED, 36, -1); return 0 }
548
641
  function host_value_unary(operator: i32, handle: i32): i32 { if (operator == 0) return host_value_boolean(host_value_truthy(handle) == 0 ? 1 : 0); if (operator == 1) return host_value_number(__pulse_fastly_number(handle)); if (operator == 2) return host_value_number(-__pulse_fastly_number(handle)); if (operator == 5) return host_value_undefined(); __pulse_fastly_fail(PULSE_ERROR_UNSUPPORTED, 37, -1); return 0 }
549
642
 
550
643
  function host_request_method(): i32 { return __pulse_fastly_string_value(__pulse_fastly_request_method) }
@@ -558,10 +651,32 @@ function host_request_path(): i32 { return __pulse_fastly_string_value(__pulse_f
558
651
  function host_request_headers(): i32 { return host_value_object() }
559
652
  function host_request_header(name: i32): i32 { const value = __pulse_fastly_request_header_text(__pulse_fastly_string(name)); return value.length == 0 ? host_value_undefined() : __pulse_fastly_string_value(value) }
560
653
  function host_request_text(): i32 { if (__pulse_fastly_request_body_loaded == 0) { __pulse_fastly_request_body = __pulse_fastly_read_body(__pulse_fastly_request_body_handle, -1); __pulse_fastly_request_body_loaded = 1 } return __pulse_fastly_string_value(__pulse_fastly_request_body) }
561
- function host_request_json(schema: i32): i32 { const parsed = __pulse_fastly_parse_json(__pulse_fastly_string(host_request_text())); if (parsed <= 0) return 0; const schemaValue = __pulse_fastly_value(schema); return schemaValue.kind == PULSE_VALUE_STRING ? __pulse_fastly_schema_apply(schemaValue.text, parsed, false) : parsed }
654
+ 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 }
562
655
  function __pulse_fastly_headers_from_options(options: __PulseFastlyValue, output: __PulseFastlyValue): void { const index = __pulse_fastly_find(options, "headers"); if (index < 0) return; const headers = __pulse_fastly_value(unchecked(options.values[index])); if (headers.kind == PULSE_VALUE_OBJECT) { for (let i = 0; i < headers.keys.length; i += 1) { const name = unchecked(headers.keys[i]); const value = __pulse_fastly_value(unchecked(headers.values[i])); if (value.kind == PULSE_VALUE_ARRAY) { for (let j = 0; j < value.values.length; j += 1) output.headers.push(new __PulseFastlyHeader(name, __pulse_fastly_string(unchecked(value.values[j])))) } else output.headers.push(new __PulseFastlyHeader(name, __pulse_fastly_string(unchecked(headers.values[i])))) } return } if (headers.kind == PULSE_VALUE_ARRAY) { for (let i = 0; i < headers.values.length; i += 1) { const pair = __pulse_fastly_value(unchecked(headers.values[i])); if (pair.kind != PULSE_VALUE_ARRAY || pair.values.length < 2) continue; output.headers.push(new __PulseFastlyHeader(__pulse_fastly_string(unchecked(pair.values[0])), __pulse_fastly_string(unchecked(pair.values[1])))) } } }
563
656
  function __pulse_fastly_response(value: i32, optionsHandle: i32, json: bool): i32 { const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE; output.status = 200; const options = __pulse_fastly_value(optionsHandle); let bodyValue = value; if (options.kind == PULSE_VALUE_OBJECT) { const statusIndex = __pulse_fastly_find(options, "status"); if (statusIndex >= 0) output.status = i32(__pulse_fastly_number(unchecked(options.values[statusIndex]))); const schemaIndex = __pulse_fastly_find(options, "schema"); if (json && schemaIndex >= 0) { bodyValue = __pulse_fastly_schema_apply(__pulse_fastly_string(unchecked(options.values[schemaIndex])), value, true); if (bodyValue <= 0) return 0 } __pulse_fastly_headers_from_options(options, output) } output.text = json ? __pulse_fastly_json(bodyValue, 0) : __pulse_fastly_string(value); let hasContentType = false; for (let i = 0; i < output.headers.length; i += 1) if (unchecked(output.headers[i]).name.toLowerCase() == "content-type") hasContentType = true; if (!hasContentType) output.headers.push(new __PulseFastlyHeader("content-type", json ? "application/json; charset=utf-8" : "text/plain; charset=utf-8")); return __pulse_fastly_put(output) }
564
657
  function host_response_json(value: i32, options: i32): i32 { return __pulse_fastly_response(value, options, true) }
658
+ function host_schema_decode(text: i32, schema: i32): i32 {
659
+ const id = __pulse_fastly_value(schema)
660
+ if (id.kind != PULSE_VALUE_STRING || id.text.length == 0) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 55, -1); return 0 }
661
+ const input = __pulse_fastly_value(text)
662
+ if (input.kind != PULSE_VALUE_STRING) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 52, -1); return 0 }
663
+ if (String.UTF8.byteLength(input.text) > __PULSE_SCHEMA_MAX_BYTES) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 21, -1); return 0 }
664
+ const parsed = ${hasJsonAdmission(plan) ? '__pulse_fastly_schema_parse_json(input.text, schema)' : '__pulse_fastly_parse_json(input.text)'}
665
+ if (parsed <= 0) return 0
666
+ const decoded = __pulse_fastly_schema_apply(id.text, parsed, false)
667
+ if (decoded <= 0) return 0
668
+ __pulse_fastly_deep_freeze(decoded)
669
+ return decoded
670
+ }
671
+ function host_schema_encode(value: i32, schema: i32): i32 {
672
+ const id = __pulse_fastly_value(schema)
673
+ if (id.kind != PULSE_VALUE_STRING || id.text.length == 0) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 55, -1); return 0 }
674
+ const projected = __pulse_fastly_schema_apply(id.text, value, true)
675
+ if (projected <= 0) return 0
676
+ const text = __pulse_fastly_json(projected, 0)
677
+ if (String.UTF8.byteLength(text) > __PULSE_SCHEMA_MAX_BYTES) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 21, -1); return 0 }
678
+ return __pulse_fastly_string_value(text)
679
+ }
565
680
  function host_response_text(value: i32, options: i32): i32 { return __pulse_fastly_response(value, options, false) }
566
681
  function host_response_custom(specHandle: i32): i32 { const spec = __pulse_fastly_value(specHandle); if (spec.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 40, -1); return 0 } const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE; output.status = 200; const statusIndex = __pulse_fastly_find(spec, "status"); if (statusIndex >= 0) output.status = i32(__pulse_fastly_number(unchecked(spec.values[statusIndex]))); const bodyIndex = __pulse_fastly_find(spec, "body"); if (bodyIndex >= 0) output.text = __pulse_fastly_string(unchecked(spec.values[bodyIndex])); __pulse_fastly_headers_from_options(spec, output); return __pulse_fastly_put(output) }
567
682
  function __pulse_fastly_grip_frame_channels(options: __PulseFastlyValue, output: __PulseFastlyValue): bool { const channelsIndex = __pulse_fastly_find(options, "channels"); const channelIndex = __pulse_fastly_find(options, "channel"); let count = 0; if (channelsIndex >= 0) { const channels = __pulse_fastly_value(unchecked(options.values[channelsIndex])); if (channels.kind != PULSE_VALUE_ARRAY) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 133, -1); return false } for (let i = 0; i < channels.values.length; i += 1) { const channel = __pulse_fastly_string(unchecked(channels.values[i])).trim(); if (channel.length == 0 || channel.indexOf(",") >= 0 || channel.indexOf("\r") >= 0 || channel.indexOf("\n") >= 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 134, -1); return false } output.headers.push(new __PulseFastlyHeader("Grip-Channel", channel)); count += 1 } } else if (channelIndex >= 0) { const channel = __pulse_fastly_string(unchecked(options.values[channelIndex])).trim(); if (channel.length == 0 || channel.indexOf(",") >= 0 || channel.indexOf("\r") >= 0 || channel.indexOf("\n") >= 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 134, -1); return false } output.headers.push(new __PulseFastlyHeader("Grip-Channel", channel)); count = 1 } if (count == 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 135, -1); return false } return true }
@@ -571,14 +686,23 @@ function host_grip_subscribe(responseHandle: i32, optionsHandle: i32): i32 { con
571
686
  function host_grip_handoff(optionsHandle: i32): i32 { const options = __pulse_fastly_value(optionsHandle); if (options.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 139, -1); return 0 } const output = new __PulseFastlyValue(); output.kind = PULSE_VALUE_RESPONSE; output.status = 200; const statusIndex = __pulse_fastly_find(options, "status"); if (statusIndex >= 0) output.status = i32(__pulse_fastly_number(unchecked(options.values[statusIndex]))); const bodyIndex = __pulse_fastly_find(options, "body"); if (bodyIndex >= 0) output.text = __pulse_fastly_string(unchecked(options.values[bodyIndex])); __pulse_fastly_headers_from_options(options, output); let hasContentType = false; for (let i = 0; i < output.headers.length; i += 1) if (unchecked(output.headers[i]).name.toLowerCase() == "content-type") hasContentType = true; if (!hasContentType) output.headers.push(new __PulseFastlyHeader("Content-Type", "application/websocket-events")); return __pulse_fastly_grip_frame(options, output) ? __pulse_fastly_put(output) : 0 }
572
687
  function host_kv_namespace(name: i32): i32 { __pulse_fastly_fail(PULSE_ERROR_UNSUPPORTED, 41, -1); return 0 }
573
688
  function host_fetch_text(responseHandle: i32): i32 { const response = __pulse_fastly_value(responseHandle); if (response.kind != PULSE_VALUE_FETCH) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 42, -1); return 0 } return __pulse_fastly_string_value(__pulse_fastly_fetch_body(response)) }
574
- function host_fetch_json(responseHandle: i32, schemaHandle: i32): i32 { const response = __pulse_fastly_value(responseHandle); if (response.kind != PULSE_VALUE_FETCH) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 43, -1); return 0 } if (__PULSE_SCHEMA_REQUIRE_JSON) { const contentType = __pulse_fastly_fetch_header_text(response.responseHandle, "content-type"); if (contentType.length == 0 || contentType.toLowerCase().indexOf("json") < 0) { __pulse_fastly_fail(PULSE_ERROR_SCHEMA, 44, -1); return 0 } } const parsed = __pulse_fastly_parse_json(__pulse_fastly_fetch_body(response)); if (parsed <= 0) return 0; const schema = __pulse_fastly_value(schemaHandle); return schema.kind == PULSE_VALUE_STRING ? __pulse_fastly_schema_apply(schema.text, parsed, false) : parsed }
689
+ 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 }
575
690
  function host_fetch_header(responseHandle: i32, nameHandle: i32): i32 { const response = __pulse_fastly_value(responseHandle); if (response.kind != PULSE_VALUE_FETCH) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 45, -1); return 0 } const value = __pulse_fastly_fetch_header_text(response.responseHandle, __pulse_fastly_string(nameHandle)); return value.length == 0 ? host_value_undefined() : __pulse_fastly_string_value(value) }
576
- function host_effect_begin(effectIndex: i32, payload: i32): void { if (effectIndex < 0 || effectIndex >= PULSE_FASTLY_EFFECT_COUNT || unchecked(__pulse_fastly_pending_active[effectIndex]) != 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 46, effectIndex); return } const payloadValue = __pulse_fastly_value(payload); if (payloadValue.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 47, effectIndex); return } const urlIndex = __pulse_fastly_find(payloadValue, "url"); if (urlIndex < 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 48, effectIndex); return } const url = __pulse_fastly_string(unchecked(payloadValue.values[urlIndex])); const initIndex = __pulse_fastly_find(payloadValue, "init"); const init = initIndex >= 0 ? __pulse_fastly_value(unchecked(payloadValue.values[initIndex])) : new __PulseFastlyValue(); let method = "GET"; let body = ""; let headers = new __PulseFastlyValue(); headers.kind = PULSE_VALUE_OBJECT; if (init.kind == PULSE_VALUE_OBJECT) { const methodIndex = __pulse_fastly_find(init, "method"); if (methodIndex >= 0) method = __pulse_fastly_string(unchecked(init.values[methodIndex])).toUpperCase(); const headersIndex = __pulse_fastly_find(init, "headers"); if (headersIndex >= 0) headers = __pulse_fastly_value(unchecked(init.values[headersIndex])); const bodyIndex = __pulse_fastly_find(init, "body"); if (bodyIndex >= 0) { const bodyValue = unchecked(init.values[bodyIndex]); const bodyObject = __pulse_fastly_value(bodyValue); body = bodyObject.kind == PULSE_VALUE_STRING ? bodyObject.text : __pulse_fastly_json(bodyValue, 0) } }
691
+ function host_effect_begin(effectIndex: i32, payload: i32): void { ${needsNativeValueFailureGuard(plan) ? 'if (__pulse_fastly_last_error != PULSE_ERROR_NONE) return; ' : ''}if (effectIndex < 0 || effectIndex >= PULSE_FASTLY_EFFECT_COUNT || unchecked(__pulse_fastly_pending_active[effectIndex]) != 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 46, effectIndex); return } const payloadValue = __pulse_fastly_value(payload); if (payloadValue.kind != PULSE_VALUE_OBJECT) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 47, effectIndex); return } const urlIndex = __pulse_fastly_find(payloadValue, "url"); if (urlIndex < 0) { __pulse_fastly_fail(PULSE_ERROR_VALUE, 48, effectIndex); return } const url = __pulse_fastly_string(unchecked(payloadValue.values[urlIndex])); const initIndex = __pulse_fastly_find(payloadValue, "init"); const init = initIndex >= 0 ? __pulse_fastly_value(unchecked(payloadValue.values[initIndex])) : new __PulseFastlyValue(); let method = "GET"; let body = ""; let headers = new __PulseFastlyValue(); headers.kind = PULSE_VALUE_OBJECT; if (init.kind == PULSE_VALUE_OBJECT) { const methodIndex = __pulse_fastly_find(init, "method"); if (methodIndex >= 0) method = __pulse_fastly_string(unchecked(init.values[methodIndex])).toUpperCase(); const headersIndex = __pulse_fastly_find(init, "headers"); if (headersIndex >= 0) headers = __pulse_fastly_value(unchecked(init.values[headersIndex])); headers = __pulse_fastly_fetch_headers(headers, effectIndex); if (__pulse_fastly_last_error != 0) return; const bodyIndex = __pulse_fastly_find(init, "body"); if (bodyIndex >= 0) { const bodyValue = unchecked(init.values[bodyIndex]); const bodyObject = __pulse_fastly_value(bodyValue); body = bodyObject.kind == PULSE_VALUE_STRING ? bodyObject.text : __pulse_fastly_json(bodyValue, 0) }
692
+ else {
693
+ const jsonIndex = __pulse_fastly_find(init, "json")
694
+ if (jsonIndex >= 0) {
695
+ body = __pulse_fastly_fetch_json_body(init, unchecked(init.values[jsonIndex]))
696
+ if (__pulse_fastly_last_error != 0) return
697
+ headers = __pulse_fastly_fetch_json_headers(headers)
698
+ }
699
+ }
700
+ }
577
701
  const requestOut = __pulse_fastly_out_i32(); let status = fastly_http_req_new(changetype<usize>(requestOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 70, effectIndex); return } const requestHandle = __pulse_fastly_out_value(requestOut)
578
702
  const bodyOut = __pulse_fastly_out_i32(); status = fastly_http_body_new(changetype<usize>(bodyOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 71, effectIndex); return } const bodyHandle = __pulse_fastly_out_value(bodyOut)
579
703
  const methodBytes = __pulse_fastly_utf8(method); status = fastly_http_req_method_set(requestHandle, changetype<usize>(methodBytes), methodBytes.byteLength); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 72, effectIndex); return }
580
704
  const urlBytes = __pulse_fastly_utf8(url); status = fastly_http_req_uri_set(requestHandle, changetype<usize>(urlBytes), urlBytes.byteLength); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 73, effectIndex); return }
581
- if (headers.kind == PULSE_VALUE_OBJECT) { for (let i = 0; i < headers.keys.length; i += 1) { const nameBytes = __pulse_fastly_utf8(unchecked(headers.keys[i])); const valueBytes = __pulse_fastly_utf8(__pulse_fastly_string(unchecked(headers.values[i]))); status = fastly_http_req_header_insert(requestHandle, changetype<usize>(nameBytes), nameBytes.byteLength, changetype<usize>(valueBytes), valueBytes.byteLength); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 74, effectIndex); return } } }
705
+ 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_append(requestHandle, changetype<usize>(nameBytes), nameBytes.byteLength, changetype<usize>(valueBytes), valueBytes.byteLength); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 74, effectIndex); return } } }
582
706
  if (body.length > 0) { status = __pulse_fastly_write_body(bodyHandle, body); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_HOSTCALL, 75, effectIndex); return } }
583
707
  const backend = __pulse_fastly_backend(effectIndex); if (backend.length == 0) { __pulse_fastly_fail(PULSE_ERROR_STATE, 76, effectIndex); return } const backendBytes = __pulse_fastly_utf8(backend); const pendingOut = __pulse_fastly_out_i32(); status = fastly_http_req_send_async(requestHandle, bodyHandle, changetype<usize>(backendBytes), backendBytes.byteLength, changetype<usize>(pendingOut)); if (status != FASTLY_STATUS_OK) { __pulse_fastly_fail(PULSE_ERROR_TRANSPORT, 77, effectIndex); return } unchecked(__pulse_fastly_pending[effectIndex] = __pulse_fastly_out_value(pendingOut)); unchecked(__pulse_fastly_pending_active[effectIndex] = 1); unchecked(__pulse_fastly_payloads[effectIndex] = payload)
584
708
  }
@@ -633,15 +757,16 @@ function generateFastlyNativeHttpEffectsAssemblyScript(plan, options = {}) {
633
757
  const bindings = resolveBackendBindings(plan, options);
634
758
  const portable = generateCanonicalNativeAssemblyScript(plan, options);
635
759
  const portableSource = stripPulseHostImports(portable.source);
636
- const source = [
760
+ let source = [
637
761
  '/* Generated by Pulse Pass97 Fastly native HTTP effects compiler. */',
638
- 'export function __pulse_fastly_abort(message: string | null, fileName: string | null, line: u32, column: u32): void { unreachable() }',
762
+ 'export function __pulse_fastly_abort(message: string | null, fileName: string | null = null, line: u32 = 0, column: u32 = 0): void { unreachable() }',
639
763
  '',
640
764
  fastlyRuntimeSource(plan, bindings),
641
765
  portableSource,
642
766
  driverSource(plan),
643
767
  ''
644
768
  ].join('\n');
769
+ source = dynamicBackends.instrument(source, bindings, false, (options.bindings || options).backends);
645
770
  const manifest = Object.freeze({
646
771
  version: FASTLY_NATIVE_HTTP_EFFECTS_VERSION,
647
772
  generatorVersion: FASTLY_NATIVE_HTTP_EFFECTS_GENERATOR_VERSION,
@@ -656,7 +781,10 @@ function generateFastlyNativeHttpEffectsAssemblyScript(plan, options = {}) {
656
781
  continuationCount: (plan.continuations || []).length,
657
782
  groupedContinuationCount: (plan.continuations || []).filter((entry) => (entry.effectIds || []).length > 1).length,
658
783
  backends: bindings,
659
- allowedImports: FASTLY_NATIVE_HTTP_EFFECTS_IMPORTS,
784
+ ...(dynamicBackends.active(bindings) ? { dynamicBackends: dynamicBackends.describe((options.bindings || options).backends) } : {}),
785
+ allowedImports: dynamicBackends.active(bindings)
786
+ ? Object.freeze([...FASTLY_NATIVE_HTTP_EFFECTS_IMPORTS, Object.freeze(['fastly_http_req', 'register_dynamic_backend'])])
787
+ : FASTLY_NATIVE_HTTP_EFFECTS_IMPORTS,
660
788
  requiredExports: Object.freeze([
661
789
  '_start',
662
790
  'pulse_fastly_last_error',
@@ -778,6 +906,7 @@ function compileFastlyNativeHttpEffectsPlan(plan, options = {}) {
778
906
  '--path', jsonAs.dependencyRoot
779
907
  );
780
908
  }
909
+ require('@pulse-compute/wasm-build-support/native-optimization').appendJsonCacheArenaArgs(args, options.elideJsonCacheArena, schemaCodecsActive);
781
910
  const startedAt = Date.now();
782
911
  const result = spawnSync(asc.executable, args, {
783
912
  cwd: stagingDir,
@@ -785,7 +914,7 @@ function compileFastlyNativeHttpEffectsPlan(plan, options = {}) {
785
914
  maxBuffer: 64 * 1024 * 1024,
786
915
  timeout: Number(options.timeoutMs || 180000),
787
916
  env: schemaCodecsActive
788
- ? { ...process.env, JSON_STRICT: 'true', JSON_USE_FAST_PATH: '0' }
917
+ ? { ...process.env, JSON_STRICT: 'true', JSON_USE_FAST_PATH: '0', JSON_MODE: 'NAIVE' }
789
918
  : process.env
790
919
  });
791
920
  const durationMs = Date.now() - startedAt;
@@ -808,7 +937,7 @@ function compileFastlyNativeHttpEffectsPlan(plan, options = {}) {
808
937
  compilerVersion: FASTLY_NATIVE_HTTP_EFFECTS_COMPILER_VERSION,
809
938
  assemblyScript: Object.freeze({ package: 'assemblyscript', version: require(path.join(asc.packageRoot, 'package.json')).version }),
810
939
  jsonAs: jsonAs
811
- ? Object.freeze({ package: 'json-as', version: jsonAs.version, transform: true, strict: true })
940
+ ? Object.freeze({ package: 'json-as', version: jsonAs.version, transform: true, strict: true, mode: 'NAIVE', fastPath: false, elideDisabledCacheArena: options.elideJsonCacheArena === true })
812
941
  : undefined,
813
942
  wasm: Object.freeze({ bytes: inspection.bytes, sha256: inspection.sha256, magic: inspection.magic }),
814
943
  wat: Object.freeze({ bytes: Buffer.byteLength(wat), sha256: sha256(wat) }),