@pulse-compute/cli 1.0.0-beta.1 → 1.0.0-beta.3

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 (76) hide show
  1. package/API.md +37 -4
  2. package/CHANGELOG.md +30 -0
  3. package/README.md +4 -3
  4. package/cli-spec.json +1 -1
  5. package/docs/README.md +1 -1
  6. package/docs/architecture/current-contracts.md +108 -7
  7. package/docs/concepts/compilation-and-lowering.md +1 -1
  8. package/docs/concepts/contracts-and-providers.md +2 -2
  9. package/docs/concepts/effects-and-continuations.md +57 -0
  10. package/docs/concepts/package-owned-lowering.md +1 -1
  11. package/docs/concepts/targets-and-hosts.md +10 -2
  12. package/docs/contributing/adding-core-provider.md +1 -1
  13. package/docs/contributing/adding-first-party-lowerer.md +1 -1
  14. package/docs/contributing/package-lowerer-contract.md +2 -2
  15. package/docs/guides/migrating-from-express.md +3 -3
  16. package/docs/guides/routing.md +19 -1
  17. package/docs/maintainers/documentation-deployment.md +4 -4
  18. package/docs/maintainers/documentation-versioning.md +1 -1
  19. package/docs/maintainers/maintainer-charter.md +17 -1
  20. package/docs/maintainers/maintenance-policy.json +34 -3
  21. package/docs/maintainers/maintenance-policy.md +3 -3
  22. package/docs/maintainers/npm-publishing.md +34 -6
  23. package/docs/maintainers/plugin-readiness.json +1 -1
  24. package/docs/maintainers/plugin-readiness.md +1 -1
  25. package/docs/maintainers/release-acceptance.md +51 -8
  26. package/docs/maintainers/release-manifest.md +23 -22
  27. package/docs/maintainers/scope-policy.md +13 -1
  28. package/docs/maintainers/testing.md +47 -1
  29. package/docs/packages/README.md +25 -24
  30. package/docs/packages/assets.md +1 -1
  31. package/docs/packages/crypto.md +8 -1
  32. package/docs/packages/entities.md +1 -1
  33. package/docs/packages/grip.md +1 -1
  34. package/docs/packages/implementation-packages.md +10 -1
  35. package/docs/packages/jwt.md +1 -1
  36. package/docs/packages/provider-fastly.md +29 -3
  37. package/docs/packages/pulse.md +1 -1
  38. package/docs/packages/runtime.md +10 -1
  39. package/docs/packages/s3.md +101 -0
  40. package/docs/preview-scope.md +2 -2
  41. package/docs/reference/cli-spec.json +1 -1
  42. package/docs/reference/cli.md +1 -1
  43. package/docs/reference/compatibility-matrix.md +2 -2
  44. package/docs/reference/diagnostics.md +5 -5
  45. package/docs/reference/documentation-versions.json +19 -3
  46. package/docs/reference/handler-authoring.md +1 -1
  47. package/docs/reference/project-config.md +33 -5
  48. package/docs/reference/project-config.schema.json +70 -7
  49. package/docs/reference/release-manifest.json +37 -23
  50. package/documentation-site.json +8 -1
  51. package/documentation-versions.json +19 -3
  52. package/examples/01-hello-json/README.md +1 -1
  53. package/examples/01-hello-json/package.json +2 -2
  54. package/examples/02-request-schema/README.md +1 -1
  55. package/examples/02-request-schema/package.json +2 -2
  56. package/examples/03-fetch-composition/README.md +1 -1
  57. package/examples/03-fetch-composition/package.json +2 -2
  58. package/examples/05-fastly-capabilities/README.md +2 -2
  59. package/examples/05-fastly-capabilities/package.json +4 -4
  60. package/examples/07-opaque-proxy/README.md +2 -2
  61. package/examples/07-opaque-proxy/package.json +3 -3
  62. package/examples/09-router-lowering/README.md +1 -1
  63. package/examples/09-router-lowering/package.json +3 -3
  64. package/examples/10-entities-tools/package.json +3 -3
  65. package/examples/11-events/README.md +1 -1
  66. package/examples/11-events/package.json +2 -2
  67. package/examples/12-mcp-proxy/README.md +1 -1
  68. package/examples/12-mcp-proxy/package.json +2 -2
  69. package/examples/13-jwt-es256/README.md +1 -1
  70. package/examples/13-jwt-es256/package.json +3 -3
  71. package/package.json +7 -7
  72. package/project-config.schema.json +70 -7
  73. package/release-manifest.json +37 -23
  74. package/src/documentation.js +1 -1
  75. package/src/project-config-schema.js +3 -3
  76. package/src/project-execution.js +64 -30
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": "pulse.project-config-schema-bundle.v1",
3
- "releaseVersion": "1.0.0-beta.1",
3
+ "releaseVersion": "1.0.0-beta.3",
4
4
  "project": {
5
5
  "schemaVersion": "pulse.project-config-schema.v1",
6
6
  "discovery": [
@@ -23,7 +23,7 @@
23
23
  {
24
24
  "id": "crypto",
25
25
  "title": "Cryptographic requirements",
26
- "description": "Declare exact algorithms for the global or selected profile and resolve one target realization without fallback. This surface is part of the synchronized 1.0.0-beta.1 package set."
26
+ "description": "Declare exact algorithms for the global or selected profile and resolve one target realization without fallback. This surface is part of the synchronized 1.0.0-beta.3 package set."
27
27
  },
28
28
  {
29
29
  "id": "schemas",
@@ -35,6 +35,11 @@
35
35
  "title": "Local development",
36
36
  "description": "Configure the foreground local server and local-only provider inputs."
37
37
  },
38
+ {
39
+ "description": "Provider-owned Node profile configuration.",
40
+ "id": "node",
41
+ "title": "Node provider options"
42
+ },
38
43
  {
39
44
  "description": "Options passed to fastly(...) from @pulse-compute/provider-fastly.",
40
45
  "id": "fastly",
@@ -111,7 +116,7 @@
111
116
  {
112
117
  "required": false,
113
118
  "default": "implicit no-crypto declaration",
114
- "allowed": "`HS256`, `ES256`; exact pins `runtime-builtin`, `guest-source:pulse-hmac-as`, and `guest-linked:pulse-es256-rustcrypto-p256`",
119
+ "allowed": "`HS256`, `ES256`, `SHA-256`, `HMAC-SHA256`; exact pins `runtime-builtin`, `guest-source:pulse-hmac-as`, and `guest-linked:pulse-es256-rustcrypto-p256`",
115
120
  "precedence": "Used only when the selected profile omits `crypto`.",
116
121
  "security": "Keys and verification bytes are not configuration values. Target selection is deterministic and never probes or falls back.",
117
122
  "diagnostics": [
@@ -122,14 +127,14 @@
122
127
  ],
123
128
  "section": "crypto",
124
129
  "path": "pulse.crypto",
125
- "type": "readonly ('HS256' | 'ES256')[] | { readonly HS256?: { readonly realization?: PulseCryptoRealization }; readonly ES256?: { readonly realization?: PulseCryptoRealization } }",
130
+ "type": "readonly PulseCryptoAlgorithm[] | Readonly<Partial<Record<PulseCryptoAlgorithm, { readonly realization?: PulseCryptoRealization }>>>",
126
131
  "scope": "global crypto requirement default",
127
132
  "description": "Declares the complete global algorithm set. Array entries are canonical algorithm names; object entries may pin one exact known realization."
128
133
  },
129
134
  {
130
135
  "required": false,
131
136
  "default": "inherit `pulse.crypto` when absent",
132
- "allowed": "`[]` and `{}` explicitly select no crypto; otherwise `HS256` and/or `ES256`",
137
+ "allowed": "`[]` and `{}` explicitly select no crypto; otherwise `HS256`, `ES256`, `SHA-256`, `HMAC-SHA256`",
133
138
  "precedence": "Selected-profile declaration replaces `pulse.crypto`; absence inherits it.",
134
139
  "security": "Every declared algorithm must resolve for the selected target before lowering. A failed exact realization cannot select another backend.",
135
140
  "diagnostics": [
@@ -139,7 +144,7 @@
139
144
  ],
140
145
  "section": "crypto",
141
146
  "path": "<profile>.crypto",
142
- "type": "readonly ('HS256' | 'ES256')[] | { readonly HS256?: { readonly realization?: PulseCryptoRealization }; readonly ES256?: { readonly realization?: PulseCryptoRealization } }",
147
+ "type": "readonly PulseCryptoAlgorithm[] | Readonly<Partial<Record<PulseCryptoAlgorithm, { readonly realization?: PulseCryptoRealization }>>>",
143
148
  "scope": "selected profile",
144
149
  "description": "Replaces the complete global crypto declaration for the selected profile. Arrays and objects never merge with `pulse.crypto`."
145
150
  },
@@ -330,6 +335,32 @@
330
335
  "scope": "local fetch capability",
331
336
  "description": "Deterministic fetch fixtures resolved before optional live network fetch."
332
337
  },
338
+ {
339
+ "required": false,
340
+ "default": "`{}`",
341
+ "allowed": "—",
342
+ "precedence": "Configuration value.",
343
+ "security": "Only named credential references are configuration. Runtime keys cannot override authority.",
344
+ "diagnostics": [],
345
+ "description": "Maps literal logical names to fixed HTTPS endpoint, bucket, region, accessKeyIdSecret, secretAccessKeySecret, optional sessionTokenSecret, maxTextBytes (1–32768, default 32768) and timeoutMs (1–30000, default 10000).",
346
+ "path": "node.bindings.s3",
347
+ "scope": "Node Native and JavaScript S3",
348
+ "section": "node",
349
+ "type": "Readonly<Record<string, S3Binding>>"
350
+ },
351
+ {
352
+ "required": false,
353
+ "default": "`{}`",
354
+ "allowed": "—",
355
+ "precedence": "Configuration value.",
356
+ "security": "Credentials resolve through the configured Secret Store at execution. Dynamic backend authority and guest endpoint overrides are forbidden.",
357
+ "diagnostics": [],
358
+ "description": "Maps logical names to fixed HTTPS endpoint, bucket, region, named static backend, accessKeyIdSecret, secretAccessKeySecret, optional sessionTokenSecret, maxTextBytes (1–32768, default 32768) and timeoutMs (1–30000, default 10000).",
359
+ "path": "fastly.bindings.s3",
360
+ "scope": "Fastly Native S3",
361
+ "section": "fastly",
362
+ "type": "Readonly<Record<string, S3Binding & { backend: string }>>"
363
+ },
333
364
  {
334
365
  "required": false,
335
366
  "default": "`pulse_config`",
@@ -729,7 +760,9 @@
729
760
  "items": {
730
761
  "enum": [
731
762
  "HS256",
732
- "ES256"
763
+ "ES256",
764
+ "SHA-256",
765
+ "HMAC-SHA256"
733
766
  ]
734
767
  }
735
768
  },
@@ -762,6 +795,32 @@
762
795
  ]
763
796
  }
764
797
  }
798
+ },
799
+ "SHA-256": {
800
+ "type": "object",
801
+ "additionalProperties": false,
802
+ "properties": {
803
+ "realization": {
804
+ "enum": [
805
+ "runtime-builtin",
806
+ "guest-source:pulse-hmac-as",
807
+ "guest-linked:pulse-es256-rustcrypto-p256"
808
+ ]
809
+ }
810
+ }
811
+ },
812
+ "HMAC-SHA256": {
813
+ "type": "object",
814
+ "additionalProperties": false,
815
+ "properties": {
816
+ "realization": {
817
+ "enum": [
818
+ "runtime-builtin",
819
+ "guest-source:pulse-hmac-as",
820
+ "guest-linked:pulse-es256-rustcrypto-p256"
821
+ ]
822
+ }
823
+ }
765
824
  }
766
825
  }
767
826
  }
@@ -844,6 +903,10 @@
844
903
  "fastly": {
845
904
  "schemaVersion": "pulse.provider-fastly-config-schema.v1",
846
905
  "fields": {
906
+ "fastly.bindings.s3": {
907
+ "kind": "object",
908
+ "default": {}
909
+ },
847
910
  "fastly.configStore": {
848
911
  "kind": "string",
849
912
  "default": "pulse_config"
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "schemaVersion": "pulse.release-catalog.v1",
3
- "releaseVersion": "1.0.0-beta.1",
3
+ "releaseVersion": "1.0.0-beta.3",
4
4
  "channel": "beta",
5
- "releasedAt": "2026-08-01",
5
+ "releasedAt": "2026-09-14",
6
6
  "license": "Apache-2.0",
7
7
  "display": {
8
8
  "productName": "Pulse",
9
9
  "candidateLabel": "Beta",
10
- "candidateName": "Pulse 1.0.0-beta.1 — Beta",
10
+ "candidateName": "Pulse 1.0.0-beta.3 — Beta",
11
11
  "activationStage": "documentation-release"
12
12
  },
13
13
  "legal": {
@@ -29,7 +29,7 @@
29
29
  "documentation": {
30
30
  "origin": "https://pulsecompute.io",
31
31
  "basePath": "/",
32
- "version": "v1.0.0-beta.1",
32
+ "version": "v1.0.0-beta.3",
33
33
  "latestAlias": "latest",
34
34
  "source": "docs/README.md"
35
35
  },
@@ -97,7 +97,7 @@
97
97
  },
98
98
  "publication": {
99
99
  "registry": "https://registry.npmjs.org",
100
- "distTag": "beta",
100
+ "distTag": "latest",
101
101
  "access": "public",
102
102
  "authentication": "npm-trusted-publishing-oidc",
103
103
  "provenance": "automatic",
@@ -153,7 +153,7 @@
153
153
  {
154
154
  "dir": "packages/runtime",
155
155
  "name": "@pulse-compute/runtime",
156
- "version": "1.0.0-beta.1",
156
+ "version": "1.0.0-beta.3",
157
157
  "documentation": "docs/packages/runtime.md",
158
158
  "role": "public-runtime",
159
159
  "tier": "canonical-application",
@@ -167,7 +167,7 @@
167
167
  {
168
168
  "dir": "packages/pulse",
169
169
  "name": "@pulse-compute/pulse",
170
- "version": "1.0.0-beta.1",
170
+ "version": "1.0.0-beta.3",
171
171
  "documentation": "docs/packages/pulse.md",
172
172
  "role": "public-api",
173
173
  "tier": "canonical-application",
@@ -182,7 +182,7 @@
182
182
  {
183
183
  "dir": "wasm/packages/cli",
184
184
  "name": "@pulse-compute/cli",
185
- "version": "1.0.0-beta.1",
185
+ "version": "1.0.0-beta.3",
186
186
  "documentation": "docs/packages/cli.md",
187
187
  "role": "public-cli",
188
188
  "tier": "canonical-application",
@@ -207,7 +207,7 @@
207
207
  {
208
208
  "dir": "packages/provider-fastly",
209
209
  "name": "@pulse-compute/provider-fastly",
210
- "version": "1.0.0-beta.1",
210
+ "version": "1.0.0-beta.3",
211
211
  "documentation": "docs/packages/provider-fastly.md",
212
212
  "role": "public-provider",
213
213
  "tier": "supported-extension",
@@ -227,7 +227,7 @@
227
227
  {
228
228
  "dir": "packages/grip",
229
229
  "name": "@pulse-compute/grip",
230
- "version": "1.0.0-beta.1",
230
+ "version": "1.0.0-beta.3",
231
231
  "documentation": "docs/packages/grip.md",
232
232
  "role": "public-extension",
233
233
  "tier": "supported-extension",
@@ -241,7 +241,7 @@
241
241
  {
242
242
  "dir": "packages/assets",
243
243
  "name": "@pulse-compute/assets",
244
- "version": "1.0.0-beta.1",
244
+ "version": "1.0.0-beta.3",
245
245
  "documentation": "docs/packages/assets.md",
246
246
  "role": "public-extension",
247
247
  "tier": "supported-extension",
@@ -255,7 +255,7 @@
255
255
  {
256
256
  "dir": "packages/crypto",
257
257
  "name": "@pulse-compute/crypto",
258
- "version": "1.0.0-beta.1",
258
+ "version": "1.0.0-beta.3",
259
259
  "documentation": "docs/packages/crypto.md",
260
260
  "role": "public-extension",
261
261
  "tier": "supported-extension",
@@ -269,7 +269,7 @@
269
269
  {
270
270
  "dir": "packages/jwt",
271
271
  "name": "@pulse-compute/jwt",
272
- "version": "1.0.0-beta.1",
272
+ "version": "1.0.0-beta.3",
273
273
  "documentation": "docs/packages/jwt.md",
274
274
  "role": "public-extension",
275
275
  "tier": "supported-extension",
@@ -283,7 +283,7 @@
283
283
  {
284
284
  "dir": "packages/entities",
285
285
  "name": "@pulse-compute/entities",
286
- "version": "1.0.0-beta.1",
286
+ "version": "1.0.0-beta.3",
287
287
  "documentation": "docs/packages/entities.md",
288
288
  "role": "public-extension",
289
289
  "tier": "supported-extension",
@@ -294,10 +294,24 @@
294
294
  ],
295
295
  "stability": "The package root and first-party JSON-RPC adapter are supported Beta contracts; compiler integration subpaths remain toolchain-only."
296
296
  },
297
+ {
298
+ "dir": "packages/s3",
299
+ "name": "@pulse-compute/s3",
300
+ "version": "1.0.0-beta.3",
301
+ "documentation": "docs/packages/s3.md",
302
+ "role": "public-extension",
303
+ "tier": "supported-extension",
304
+ "audience": "Applications using bounded exact-key object reads and writes through Pulse effects.",
305
+ "directInstall": "Yes, when an application uses S3 object operations.",
306
+ "entryPoints": [
307
+ "@pulse-compute/s3"
308
+ ],
309
+ "stability": "The package root supports head, getText and putText on Node Native, Node JavaScript and Fastly Native. Fastly JavaScript is ineligible. Provider and lowering subpaths are toolchain-only; live origin acceptance is separate."
310
+ },
297
311
  {
298
312
  "dir": "wasm/packages/build-support",
299
313
  "name": "@pulse-compute/wasm-build-support",
300
- "version": "1.0.0-beta.1",
314
+ "version": "1.0.0-beta.3",
301
315
  "documentation": "docs/packages/implementation-packages.md",
302
316
  "role": "implementation",
303
317
  "tier": "implementation",
@@ -311,7 +325,7 @@
311
325
  {
312
326
  "dir": "wasm/packages/compiler",
313
327
  "name": "@pulse-compute/wasm-compiler",
314
- "version": "1.0.0-beta.1",
328
+ "version": "1.0.0-beta.3",
315
329
  "documentation": "docs/packages/implementation-packages.md",
316
330
  "role": "implementation",
317
331
  "tier": "implementation",
@@ -326,7 +340,7 @@
326
340
  {
327
341
  "dir": "wasm/packages/wasm-guest-link",
328
342
  "name": "@pulse-compute/wasm-guest-link",
329
- "version": "1.0.0-beta.1",
343
+ "version": "1.0.0-beta.3",
330
344
  "documentation": "docs/packages/implementation-packages.md",
331
345
  "role": "implementation",
332
346
  "tier": "implementation",
@@ -340,7 +354,7 @@
340
354
  {
341
355
  "dir": "wasm/packages/contracts",
342
356
  "name": "@pulse-compute/wasm-contracts",
343
- "version": "1.0.0-beta.1",
357
+ "version": "1.0.0-beta.3",
344
358
  "documentation": "docs/packages/implementation-packages.md",
345
359
  "role": "implementation",
346
360
  "tier": "implementation",
@@ -354,7 +368,7 @@
354
368
  {
355
369
  "dir": "wasm/packages/host-runtime",
356
370
  "name": "@pulse-compute/wasm-host-runtime",
357
- "version": "1.0.0-beta.1",
371
+ "version": "1.0.0-beta.3",
358
372
  "documentation": "docs/packages/implementation-packages.md",
359
373
  "role": "implementation",
360
374
  "tier": "implementation",
@@ -368,7 +382,7 @@
368
382
  {
369
383
  "dir": "wasm/packages/library-kit",
370
384
  "name": "@pulse-compute/wasm-library-kit",
371
- "version": "1.0.0-beta.1",
385
+ "version": "1.0.0-beta.3",
372
386
  "documentation": "docs/packages/implementation-packages.md",
373
387
  "role": "implementation",
374
388
  "tier": "implementation",
@@ -382,7 +396,7 @@
382
396
  {
383
397
  "dir": "packages/provider-node",
384
398
  "name": "@pulse-compute/provider-node",
385
- "version": "1.0.0-beta.1",
399
+ "version": "1.0.0-beta.3",
386
400
  "documentation": "docs/packages/implementation-packages.md",
387
401
  "role": "implementation",
388
402
  "tier": "implementation",
@@ -397,7 +411,7 @@
397
411
  {
398
412
  "dir": "wasm/packages/runtime-core-as",
399
413
  "name": "@pulse-compute/wasm-runtime-core-as",
400
- "version": "1.0.0-beta.1",
414
+ "version": "1.0.0-beta.3",
401
415
  "documentation": "docs/packages/implementation-packages.md",
402
416
  "role": "implementation",
403
417
  "tier": "implementation",
@@ -411,7 +425,7 @@
411
425
  {
412
426
  "dir": "wasm/packages/schema-json",
413
427
  "name": "@pulse-compute/wasm-schema-json",
414
- "version": "1.0.0-beta.1",
428
+ "version": "1.0.0-beta.3",
415
429
  "documentation": "docs/packages/implementation-packages.md",
416
430
  "role": "implementation",
417
431
  "tier": "implementation",
@@ -3,7 +3,7 @@
3
3
  // Generated from release/pulse-release-manifest.json by wasm/scripts/sync-reference-docs.cjs.
4
4
  const DOCUMENTATION_ORIGIN = "https://pulsecompute.io";
5
5
  const DOCUMENTATION_BASE_PATH = "";
6
- const DOCUMENTATION_VERSION = "v1.0.0-beta.1";
6
+ const DOCUMENTATION_VERSION = "v1.0.0-beta.3";
7
7
  const DOCUMENTATION_LATEST_ALIAS = "latest";
8
8
 
9
9
  function trimSlashes(value) { return String(value || '').replace(/^\/+|\/+$/g, ''); }
@@ -36,7 +36,7 @@ function field(value) {
36
36
 
37
37
  const CONFIG_SECTIONS = Object.freeze([
38
38
  Object.freeze({ id: 'project', title: 'Project and provider selection', description: 'Select the canonical entry, provider, and build output.' }),
39
- Object.freeze({ id: 'crypto', title: 'Cryptographic requirements', description: 'Declare exact algorithms for the global or selected profile and resolve one target realization without fallback. This surface is part of the synchronized 1.0.0-beta.1 package set.' }),
39
+ Object.freeze({ id: 'crypto', title: 'Cryptographic requirements', description: 'Declare exact algorithms for the global or selected profile and resolve one target realization without fallback. This surface is part of the synchronized 1.0.0-beta.3 package set.' }),
40
40
  Object.freeze({ id: 'schemas', title: 'JSON schema policy', description: 'Configure bounded schema-body policy. Conventional projects declare registry identity only through pulse.schema.' }),
41
41
  Object.freeze({ id: 'dev', title: 'Local development', description: 'Configure the foreground local server and local-only provider inputs.' }),
42
42
  ...providerConfigSections
@@ -48,8 +48,8 @@ const CONFIG_FIELDS = Object.freeze([
48
48
  field({ section: 'project', path: 'outDir', type: 'string', default: '`./dist`', scope: 'compile/build', description: 'Project-relative artifact output directory.', precedence: '`--out` overrides this field for the current command.', security: 'Must remain a real child of the project root; absolute, parent-traversal, and symbolic-link traversal outside the project root is rejected.', diagnostics: ['PULSE_BUILD_OUT_UNSAFE'] }),
49
49
  field({ section: 'project', path: 'reporting', type: "'off' | 'error' | 'warn' | 'info' | 'debug'", default: '`info`', allowed: '`off`, `error`, `warn`, `info`, `debug`', scope: 'compile/build/dev/test', description: 'Resolved synchronous logging threshold after the flat profile override is applied.', precedence: 'Selected-profile `reporting`, then `pulse.reporting`, then `info`.', security: 'Known request-owned secret values are redacted before provider emission.', diagnostics: ['PULSE_REPORTING_LEVEL_UNSUPPORTED'] }),
50
50
 
51
- field({ section: 'crypto', path: 'pulse.crypto', type: "readonly ('HS256' | 'ES256')[] | { readonly HS256?: { readonly realization?: PulseCryptoRealization }; readonly ES256?: { readonly realization?: PulseCryptoRealization } }", default: 'implicit no-crypto declaration', allowed: '`HS256`, `ES256`; exact pins `runtime-builtin`, `guest-source:pulse-hmac-as`, and `guest-linked:pulse-es256-rustcrypto-p256`', scope: 'global crypto requirement default', description: 'Declares the complete global algorithm set. Array entries are canonical algorithm names; object entries may pin one exact known realization.', precedence: 'Used only when the selected profile omits `crypto`.', security: 'Keys and verification bytes are not configuration values. Target selection is deterministic and never probes or falls back.', diagnostics: ['PULSE_CRYPTO_CONFIG_SHAPE_INVALID', 'PULSE_CRYPTO_ALGORITHM_DUPLICATE', 'PULSE_CRYPTO_ALGORITHM_UNKNOWN', 'PULSE_CRYPTO_REALIZATION_UNKNOWN'] }),
52
- field({ section: 'crypto', path: '<profile>.crypto', type: "readonly ('HS256' | 'ES256')[] | { readonly HS256?: { readonly realization?: PulseCryptoRealization }; readonly ES256?: { readonly realization?: PulseCryptoRealization } }", default: 'inherit `pulse.crypto` when absent', allowed: '`[]` and `{}` explicitly select no crypto; otherwise `HS256` and/or `ES256`', scope: 'selected profile', description: 'Replaces the complete global crypto declaration for the selected profile. Arrays and objects never merge with `pulse.crypto`.', precedence: 'Selected-profile declaration replaces `pulse.crypto`; absence inherits it.', security: 'Every declared algorithm must resolve for the selected target before lowering. A failed exact realization cannot select another backend.', diagnostics: ['PULSE_CRYPTO_CONFIG_REQUIRED', 'PULSE_CRYPTO_REALIZATION_PIN_INVALID', 'PULSE_CRYPTO_REALIZATION_UNAVAILABLE'] }),
51
+ field({ section: 'crypto', path: 'pulse.crypto', type: "readonly PulseCryptoAlgorithm[] | Readonly<Partial<Record<PulseCryptoAlgorithm, { readonly realization?: PulseCryptoRealization }>>>", default: 'implicit no-crypto declaration', allowed: '`HS256`, `ES256`, `SHA-256`, `HMAC-SHA256`; exact pins `runtime-builtin`, `guest-source:pulse-hmac-as`, and `guest-linked:pulse-es256-rustcrypto-p256`', scope: 'global crypto requirement default', description: 'Declares the complete global algorithm set. Array entries are canonical algorithm names; object entries may pin one exact known realization.', precedence: 'Used only when the selected profile omits `crypto`.', security: 'Keys and verification bytes are not configuration values. Target selection is deterministic and never probes or falls back.', diagnostics: ['PULSE_CRYPTO_CONFIG_SHAPE_INVALID', 'PULSE_CRYPTO_ALGORITHM_DUPLICATE', 'PULSE_CRYPTO_ALGORITHM_UNKNOWN', 'PULSE_CRYPTO_REALIZATION_UNKNOWN'] }),
52
+ field({ section: 'crypto', path: '<profile>.crypto', type: "readonly PulseCryptoAlgorithm[] | Readonly<Partial<Record<PulseCryptoAlgorithm, { readonly realization?: PulseCryptoRealization }>>>", default: 'inherit `pulse.crypto` when absent', allowed: '`[]` and `{}` explicitly select no crypto; otherwise `HS256`, `ES256`, `SHA-256`, `HMAC-SHA256`', scope: 'selected profile', description: 'Replaces the complete global crypto declaration for the selected profile. Arrays and objects never merge with `pulse.crypto`.', precedence: 'Selected-profile declaration replaces `pulse.crypto`; absence inherits it.', security: 'Every declared algorithm must resolve for the selected target before lowering. A failed exact realization cannot select another backend.', diagnostics: ['PULSE_CRYPTO_CONFIG_REQUIRED', 'PULSE_CRYPTO_REALIZATION_PIN_INVALID', 'PULSE_CRYPTO_REALIZATION_UNAVAILABLE'] }),
53
53
 
54
54
  field({ section: 'schemas', path: 'schemas', type: 'PulseSchemaConfig', default: '`{}`', scope: 'compile/dev/test/build', description: 'Sets schema body limits and content-type policy. Schema identities come from the module selected by pulse.schema.', security: 'Structured bodies are bounded before decoding.', diagnostics: ['PULSE_SCHEMA_COMPILE_FAILED'] }),
55
55
  field({ section: 'schemas', path: 'schemas.contentTypePolicy', type: "'accept-json-or-missing' | 'require-json'", default: '`accept-json-or-missing`', allowed: '`accept-json-or-missing`, `require-json`', scope: 'request and fetched-body schema decode', description: 'Controls whether a JSON content type is mandatory.', diagnostics: ['PULSE_SCHEMA_CONTENT_TYPE_POLICY_INVALID', 'PULSE_SCHEMA_DECODE'] }),
@@ -16,14 +16,11 @@ const {
16
16
  } = require('@pulse-compute/wasm-compiler/canonical-project-compiler');
17
17
  const { createCanonicalSchemaCodecs } = require('@pulse-compute/wasm-schema-json/compiler/canonical-schema-codecs');
18
18
  const { buildJavascriptApplicationPlan } = require('@pulse-compute/wasm-compiler/javascript-application-plan');
19
- const { buildCanonicalNativePlan } = require('@pulse-compute/wasm-compiler/canonical-native-plan');
19
+ const { buildCanonicalNativePlan, CanonicalNativePlanError } = require('@pulse-compute/wasm-compiler/canonical-native-plan');
20
20
  const {
21
21
  compileCanonicalNativePlan,
22
22
  writeCanonicalNativeModule
23
23
  } = require('@pulse-compute/wasm-compiler/canonical-native-compiler');
24
- const {
25
- executeCanonicalNativeModule
26
- } = require('@pulse-compute/wasm-host-runtime/runtime/canonical-native-host');
27
24
  const { PulseProjectError, projectJson, relative } = require('./project-config.js');
28
25
  const { describeDiagnostic, decorateDiagnostic, httpStatusForDiagnostic } = require('./diagnostics.js');
29
26
  const {
@@ -293,9 +290,10 @@ function jsonPolicyInspection(project, compiled, nativePlan) {
293
290
 
294
291
  function compileProject(project, options = {}) {
295
292
  const handlerAuthoring = options.handlerAuthoring || HANDLER_AUTHORING_MODES.ASYNC_REQUIRED;
296
- const configuredTarget = project.target || 'native';
293
+ const configuredTarget = options.target || project.target || 'native';
297
294
  const packageTargetDescriptor = getProviderTargetDescriptor(providerDriver(project), configuredTarget);
298
295
  return compileCanonicalProject(project.entryFile, {
296
+ target: configuredTarget,
299
297
  rootDir: project.root,
300
298
  // Package lowerers are discovered from the nearest package-manager workspace.
301
299
  // The Pulse project root remains authoritative for config and paths, but a
@@ -308,7 +306,6 @@ function compileProject(project, options = {}) {
308
306
  handlerAuthoring,
309
307
  requireAsync: handlerAuthoring === HANDLER_AUTHORING_MODES.ASYNC_REQUIRED,
310
308
  requireEffectAwait: false,
311
- nativeEligibilityMode: (project.target || 'native') === 'javascript' ? 'record' : 'enforce',
312
309
  packageTargetDescriptor,
313
310
  packageTarget: configuredTarget,
314
311
  applicationProjectMetadata: Object.freeze({
@@ -322,14 +319,26 @@ function compileProject(project, options = {}) {
322
319
  crypto: project.profilePlan && project.profilePlan.crypto,
323
320
  reporting: project.reporting,
324
321
  reportingLevel: project.reportingLevel,
325
- target: project.target || 'native',
322
+ target: configuredTarget,
326
323
  host: project.provider || null
327
324
  })
328
325
  });
329
326
  }
330
327
 
331
328
  function compileNativeProjectInMemory(project, options = {}) {
332
- const compiled = options.compiled || compileProject(project);
329
+ let compiled;
330
+ try {
331
+ compiled = options.compiled && options.compiled.target !== 'javascript'
332
+ ? options.compiled
333
+ : compileProject(project, { ...options, target: 'native' });
334
+ } catch (error) {
335
+ // Native inspection is independent of a successful JavaScript compilation.
336
+ // Keep its rejection in the Native diagnostic lane used by doctor/inspect.
337
+ if ((project.target || 'native') !== 'javascript' || !Array.isArray(error.diagnostics)) throw error;
338
+ const failure = new CanonicalNativePlanError(error.message, error.diagnostics);
339
+ failure.detail = Object.freeze({ ...error.detail, causeCode: error.code, automaticFallback: false });
340
+ throw failure;
341
+ }
333
342
  const plan = buildCanonicalNativePlan(compiled, { reporting: project.reporting });
334
343
  const native = compileCanonicalNativePlan(plan, {
335
344
  cwd: project.root,
@@ -482,13 +491,23 @@ function providerExecutionOptions(project, values = {}) {
482
491
  return driver.executionOptions ? driver.executionOptions(project.providerConfig, resolved) : resolved;
483
492
  }
484
493
 
485
- function requiresExactNativeCrypto(compiled) {
486
- return Boolean(
487
- compiled
488
- && compiled.cryptoRealizationPlan
489
- && Array.isArray(compiled.cryptoRealizationPlan.algorithms)
490
- && compiled.cryptoRealizationPlan.algorithms.some((entry) => entry.kind === 'guest-linked')
491
- );
494
+ function requiresExactNativeExecution(compiled) {
495
+ const algorithms = compiled.cryptoRealizationPlan && compiled.cryptoRealizationPlan.algorithms || [];
496
+ const operations = compiled.metadata && compiled.metadata.providerOperations || [];
497
+ return algorithms.some((entry) => entry.kind === 'guest-linked' || entry.kind === 'guest-source')
498
+ || operations.some((entry) => ['kv.getVersioned', 'kv.insertIfAbsent', 'kv.compareAndSwap'].includes(entry.capability));
499
+ }
500
+
501
+ function prepareNativeExecution(project, compiled, native) {
502
+ const driver = providerDriver(project);
503
+ if (typeof driver.prepareNativeExecution !== 'function') {
504
+ throw new TypeError(`Provider ${driver.id} cannot execute this Native artifact locally.`);
505
+ }
506
+ const execute = driver.prepareNativeExecution(providerTargetInvocation(
507
+ project, 'execute-native', native.plan, providerLoweringPlan(project, compiled.metadata), { native }
508
+ ));
509
+ if (typeof execute !== 'function') throw new TypeError('Provider Native execution preparation must return a function.');
510
+ return execute;
492
511
  }
493
512
 
494
513
  function providerLoweringPlan(project, metadata) {
@@ -1513,11 +1532,12 @@ async function runProjectTests(project, options = {}) {
1513
1532
  assertImplementedTarget(project, 'test');
1514
1533
  const executeCanonicalProgram = driver.execute;
1515
1534
  if (!compiled) compiled = compileProject(project);
1516
- const exactNativeCrypto = requiresExactNativeCrypto(compiled);
1517
- const program = exactNativeCrypto ? null : loadCanonicalModule(compiled);
1518
- const native = hasEventCase || exactNativeCrypto
1535
+ const exactNativeExecution = requiresExactNativeExecution(compiled);
1536
+ const program = exactNativeExecution ? null : loadCanonicalModule(compiled);
1537
+ const native = hasEventCase || exactNativeExecution
1519
1538
  ? compileNativeProjectInMemory(project, { ...options, compiled }).native
1520
1539
  : null;
1540
+ const executeNative = exactNativeExecution ? prepareNativeExecution(project, compiled, native) : null;
1521
1541
  const cases = [];
1522
1542
  let failed = 0;
1523
1543
  for (const testCase of selected) {
@@ -1555,8 +1575,8 @@ async function runProjectTests(project, options = {}) {
1555
1575
  continuationTtlMs: testCase.continuationTtlMs,
1556
1576
  executionId: `test:${testCase.name}`
1557
1577
  });
1558
- const execution = exactNativeCrypto
1559
- ? await executeCanonicalNativeModule(native, executionOptions)
1578
+ const execution = exactNativeExecution
1579
+ ? await executeNative(executionOptions)
1560
1580
  : await executeCanonicalProgram(program, executionOptions);
1561
1581
  if (testCase.expect.error) throw new assert.AssertionError({ message: `${testCase.name}: expected ${testCase.expect.error.name || 'an error'} but execution completed` });
1562
1582
  assertExpectation(testCase, Object.freeze({
@@ -1569,6 +1589,7 @@ async function runProjectTests(project, options = {}) {
1569
1589
  durationMs: Number(process.hrtime.bigint() - started) / 1e6,
1570
1590
  response: Object.freeze({ status: execution.response.status, bodyClass: execution.response.bodyClass, kind: execution.response.kind }),
1571
1591
  effects: execution.effectCount,
1592
+ ...(execution.evidence ? { executionEvidence: execution.evidence } : {}),
1572
1593
  continuations: execution.continuations.map((entry) => Object.freeze({ id: entry.id, state: entry.state, effectIds: entry.effectIds })),
1573
1594
  resolutionOrder: execution.resolutionOrder
1574
1595
  }));
@@ -1894,7 +1915,11 @@ function doctorProject(project, options = {}) {
1894
1915
  let eventInspection;
1895
1916
  try {
1896
1917
  compiled = compileProject(project);
1897
- check('canonical-compile', (compiled.metadata.warningCount || 0) > 0 ? 'warning' : 'passed', `Canonical source lowered with ${compiled.metadata.effectCount} effect(s), ${compiled.metadata.continuationCount} continuation(s), and ${compiled.metadata.warningCount || 0} warning(s).`, { capabilities: compiled.metadata.capabilities, warnings: compiled.metadata.warnings || [] });
1918
+ check('canonical-compile', (compiled.metadata.warningCount || 0) > 0 ? 'warning' : 'passed',
1919
+ compiled.target === 'javascript'
1920
+ ? `JavaScript source inspected with ${compiled.metadata.effectCount} recognized Pulse effect(s) and ${compiled.metadata.warningCount || 0} warning(s); execution retains the original source graph.`
1921
+ : `Canonical source lowered with ${compiled.metadata.effectCount} effect(s), ${compiled.metadata.continuationCount} continuation(s), and ${compiled.metadata.warningCount || 0} warning(s).`,
1922
+ { capabilities: compiled.metadata.capabilities, warnings: compiled.metadata.warnings || [] });
1898
1923
  eventSupport = selectedEventTargetSupport(project, compiled, selectedTargetDescriptor);
1899
1924
  if (eventSupport) {
1900
1925
  eventInspection = eventInspectionProjection(project, compiled, eventSupport);
@@ -2595,6 +2620,12 @@ async function startJavascriptDevServer(project, options = {}) {
2595
2620
  config: project.dev.config,
2596
2621
  secrets: project.dev.secrets,
2597
2622
  kv: project.dev.kv,
2623
+ bindings: project.providerConfig.bindings,
2624
+ s3FetchImplementation: javascript.createFixtureFetch(
2625
+ project.dev.fetches,
2626
+ project.dev.networkFetch ? globalThis.fetch : undefined,
2627
+ { rawResponse: true }
2628
+ ),
2598
2629
  fetchImplementation: javascript.createFixtureFetch(
2599
2630
  project.dev.fetches,
2600
2631
  project.dev.networkFetch ? globalThis.fetch : undefined
@@ -2664,7 +2695,8 @@ async function startDevServer(project, options = {}) {
2664
2695
  let compiled;
2665
2696
  let program;
2666
2697
  let native;
2667
- let exactNativeCrypto = false;
2698
+ let executeNative;
2699
+ let exactNativeExecution = false;
2668
2700
  let packageArtifacts = Object.freeze([]);
2669
2701
  let compileError;
2670
2702
  let reloadTimer;
@@ -2689,15 +2721,17 @@ async function startDevServer(project, options = {}) {
2689
2721
  function reload(reason) {
2690
2722
  try {
2691
2723
  const nextCompiled = compileProject(project);
2692
- const nextExactNativeCrypto = requiresExactNativeCrypto(nextCompiled);
2693
- const nextProgram = nextExactNativeCrypto ? null : loadCanonicalModule(nextCompiled);
2694
- const nextNative = nextExactNativeCrypto
2724
+ const nextExactNativeExecution = requiresExactNativeExecution(nextCompiled);
2725
+ const nextProgram = nextExactNativeExecution ? null : loadCanonicalModule(nextCompiled);
2726
+ const nextNative = nextExactNativeExecution
2695
2727
  ? compileNativeProjectInMemory(project, { ...options, compiled: nextCompiled }).native
2696
2728
  : null;
2729
+ const nextExecuteNative = nextExactNativeExecution ? prepareNativeExecution(project, nextCompiled, nextNative) : null;
2697
2730
  compiled = nextCompiled;
2698
2731
  program = nextProgram;
2699
2732
  native = nextNative;
2700
- exactNativeCrypto = nextExactNativeCrypto;
2733
+ executeNative = nextExecuteNative;
2734
+ exactNativeExecution = nextExactNativeExecution;
2701
2735
  packageArtifacts = packageRealizationArtifactsForCompiled(nextCompiled);
2702
2736
  compileError = undefined;
2703
2737
  syncWatchFiles(compiled.watchFiles);
@@ -2710,8 +2744,8 @@ async function startDevServer(project, options = {}) {
2710
2744
  watchFiles: Object.freeze(compiled.watchFiles.map((file) => relative(file, project.root)))
2711
2745
  }));
2712
2746
  } catch (error) {
2713
- if (!program) compileError = error;
2714
- events(Object.freeze({ event: 'compile-error', retainedLastGoodProgram: Boolean(program), error: errorSummary(error, project.dev.secrets) }));
2747
+ if (!program && !executeNative) compileError = error;
2748
+ events(Object.freeze({ event: 'compile-error', retainedLastGoodProgram: Boolean(program || executeNative), error: errorSummary(error, project.dev.secrets) }));
2715
2749
  }
2716
2750
  }
2717
2751
  function scheduleReload() {
@@ -2742,8 +2776,8 @@ async function startDevServer(project, options = {}) {
2742
2776
  liveFetch: project.dev.networkFetch,
2743
2777
  executionId: `dev:${++handled}`
2744
2778
  });
2745
- const execution = exactNativeCrypto
2746
- ? await executeCanonicalNativeModule(native, executionOptions)
2779
+ const execution = exactNativeExecution
2780
+ ? await executeNative(executionOptions)
2747
2781
  : await executeCanonicalProgram(program, executionOptions);
2748
2782
  writeNodeHttpResponse(res, execution.response);
2749
2783
  events(Object.freeze({ event: 'request', method: req.method || 'GET', path: url.pathname, status: execution.response.status, effects: execution.effectCount }));