@pulse-compute/cli 0.0.0 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/API.md +572 -0
  2. package/CHANGELOG.md +71 -0
  3. package/README.md +71 -1
  4. package/bin/pulse.js +15 -0
  5. package/bin/pulsewasm-extract.js +22 -0
  6. package/cli-spec.json +575 -0
  7. package/completions/_pulse +106 -0
  8. package/completions/pulse.bash +31 -0
  9. package/completions/pulse.fish +76 -0
  10. package/docs/README.md +77 -0
  11. package/docs/architecture/current-contracts.md +470 -0
  12. package/docs/architecture/overview.md +93 -0
  13. package/docs/architecture/vision.md +515 -0
  14. package/docs/concepts/bodies.md +186 -0
  15. package/docs/concepts/compilation-and-lowering.md +496 -0
  16. package/docs/concepts/contracts-and-providers.md +158 -0
  17. package/docs/concepts/effects-and-continuations.md +300 -0
  18. package/docs/concepts/entities-and-adapters.md +71 -0
  19. package/docs/concepts/package-owned-lowering.md +175 -0
  20. package/docs/concepts/targets-and-hosts.md +70 -0
  21. package/docs/contributing/README.md +38 -0
  22. package/docs/contributing/adding-core-provider.md +315 -0
  23. package/docs/contributing/adding-first-party-lowerer.md +327 -0
  24. package/docs/contributing/entities-lowering.md +91 -0
  25. package/docs/contributing/package-lowerer-contract.md +383 -0
  26. package/docs/contributing/pulse-aware-packages.md +149 -0
  27. package/docs/examples.md +112 -0
  28. package/docs/fixtures/inspect-fetch-composition.selected.json +181 -0
  29. package/docs/getting-started.md +128 -0
  30. package/docs/guides/compatibility-imports.md +60 -0
  31. package/docs/guides/deploying-fastly.md +188 -0
  32. package/docs/guides/deploying-node.md +143 -0
  33. package/docs/guides/events.md +233 -0
  34. package/docs/guides/fastly-capabilities.md +153 -0
  35. package/docs/guides/fetching-and-composition.md +101 -0
  36. package/docs/guides/grip.md +94 -0
  37. package/docs/guides/json-schemas.md +233 -0
  38. package/docs/guides/migrating-from-express.md +192 -0
  39. package/docs/guides/project-lifecycle.md +143 -0
  40. package/docs/guides/routing.md +202 -0
  41. package/docs/guides/troubleshooting.md +47 -0
  42. package/docs/maintainers/README.md +60 -0
  43. package/docs/maintainers/codex-maintainer.md +71 -0
  44. package/docs/maintainers/documentation-deployment.md +147 -0
  45. package/docs/maintainers/documentation-system.md +58 -0
  46. package/docs/maintainers/documentation-versioning.md +65 -0
  47. package/docs/maintainers/maintainer-charter.md +100 -0
  48. package/docs/maintainers/maintenance-policy.json +809 -0
  49. package/docs/maintainers/maintenance-policy.md +124 -0
  50. package/docs/maintainers/npm-publishing.md +154 -0
  51. package/docs/maintainers/plugin-readiness.json +19 -0
  52. package/docs/maintainers/plugin-readiness.md +31 -0
  53. package/docs/maintainers/public-site.md +158 -0
  54. package/docs/maintainers/release-acceptance.md +293 -0
  55. package/docs/maintainers/release-manifest.md +89 -0
  56. package/docs/maintainers/repository-setup.md +145 -0
  57. package/docs/maintainers/scope-policy.md +105 -0
  58. package/docs/maintainers/support-and-triage.md +74 -0
  59. package/docs/maintainers/testing.md +334 -0
  60. package/docs/packages/README.md +60 -0
  61. package/docs/packages/assets.md +85 -0
  62. package/docs/packages/cli.md +190 -0
  63. package/docs/packages/crypto.md +78 -0
  64. package/docs/packages/entities.md +129 -0
  65. package/docs/packages/grip.md +82 -0
  66. package/docs/packages/implementation-packages.md +122 -0
  67. package/docs/packages/jwt.md +55 -0
  68. package/docs/packages/provider-fastly.md +243 -0
  69. package/docs/packages/pulse.md +159 -0
  70. package/docs/packages/runtime.md +265 -0
  71. package/docs/packages/s3.md +101 -0
  72. package/docs/preview-scope.md +142 -0
  73. package/docs/reference/README.md +33 -0
  74. package/docs/reference/cli-spec.json +575 -0
  75. package/docs/reference/cli.md +457 -0
  76. package/docs/reference/compatibility-matrix.md +169 -0
  77. package/docs/reference/diagnostics.md +1872 -0
  78. package/docs/reference/documentation-versions.json +22 -0
  79. package/docs/reference/environment.md +347 -0
  80. package/docs/reference/handler-authoring.md +264 -0
  81. package/docs/reference/project-config.md +582 -0
  82. package/docs/reference/project-config.schema.json +981 -0
  83. package/docs/reference/release-manifest.json +441 -0
  84. package/docs/reference/shell-completion.md +23 -0
  85. package/documentation-site.json +668 -0
  86. package/documentation-versions.json +22 -0
  87. package/examples/01-hello-json/.pulse/.gitignore +3 -0
  88. package/examples/01-hello-json/.pulse/config.ts +16 -0
  89. package/examples/01-hello-json/README.md +119 -0
  90. package/examples/01-hello-json/package.json +20 -0
  91. package/examples/01-hello-json/src/index.ts +9 -0
  92. package/examples/01-hello-json/tests/pulse.harness.ts +22 -0
  93. package/examples/01-hello-json/tsconfig.json +14 -0
  94. package/examples/02-request-schema/.pulse/.gitignore +3 -0
  95. package/examples/02-request-schema/.pulse/config.ts +17 -0
  96. package/examples/02-request-schema/README.md +145 -0
  97. package/examples/02-request-schema/package.json +20 -0
  98. package/examples/02-request-schema/src/index.ts +18 -0
  99. package/examples/02-request-schema/src/schemas.ts +20 -0
  100. package/examples/02-request-schema/tests/pulse.harness.ts +37 -0
  101. package/examples/02-request-schema/tsconfig.json +14 -0
  102. package/examples/03-fetch-composition/.pulse/.gitignore +3 -0
  103. package/examples/03-fetch-composition/.pulse/config.ts +31 -0
  104. package/examples/03-fetch-composition/README.md +210 -0
  105. package/examples/03-fetch-composition/package.json +20 -0
  106. package/examples/03-fetch-composition/src/index.ts +60 -0
  107. package/examples/03-fetch-composition/tests/pulse.harness.ts +47 -0
  108. package/examples/03-fetch-composition/tsconfig.json +14 -0
  109. package/examples/05-fastly-capabilities/.pulse/.gitignore +3 -0
  110. package/examples/05-fastly-capabilities/.pulse/config.ts +57 -0
  111. package/examples/05-fastly-capabilities/README.md +257 -0
  112. package/examples/05-fastly-capabilities/package.json +22 -0
  113. package/examples/05-fastly-capabilities/src/index.ts +55 -0
  114. package/examples/05-fastly-capabilities/tests/pulse.harness.ts +66 -0
  115. package/examples/05-fastly-capabilities/tsconfig.json +14 -0
  116. package/examples/07-opaque-proxy/.pulse/.gitignore +3 -0
  117. package/examples/07-opaque-proxy/.pulse/config.ts +38 -0
  118. package/examples/07-opaque-proxy/README.md +150 -0
  119. package/examples/07-opaque-proxy/package.json +21 -0
  120. package/examples/07-opaque-proxy/src/index.ts +9 -0
  121. package/examples/07-opaque-proxy/tests/pulse.harness.ts +25 -0
  122. package/examples/07-opaque-proxy/tsconfig.json +14 -0
  123. package/examples/09-router-lowering/.pulse/.gitignore +3 -0
  124. package/examples/09-router-lowering/.pulse/config.ts +22 -0
  125. package/examples/09-router-lowering/README.md +287 -0
  126. package/examples/09-router-lowering/package.json +22 -0
  127. package/examples/09-router-lowering/src/index.ts +65 -0
  128. package/examples/09-router-lowering/tests/pulse.harness.ts +91 -0
  129. package/examples/09-router-lowering/tsconfig.json +14 -0
  130. package/examples/10-entities-tools/.pulse/.gitignore +4 -0
  131. package/examples/10-entities-tools/.pulse/config.ts +23 -0
  132. package/examples/10-entities-tools/README.md +165 -0
  133. package/examples/10-entities-tools/package.json +21 -0
  134. package/examples/10-entities-tools/src/handlers.ts +15 -0
  135. package/examples/10-entities-tools/src/index.ts +31 -0
  136. package/examples/10-entities-tools/src/schemas.ts +18 -0
  137. package/examples/10-entities-tools/tests/pulse.harness.ts +40 -0
  138. package/examples/10-entities-tools/tools-facade.cjs +158 -0
  139. package/examples/10-entities-tools/tsconfig.json +14 -0
  140. package/examples/11-events/.pulse/.gitignore +4 -0
  141. package/examples/11-events/.pulse/config.ts +24 -0
  142. package/examples/11-events/README.md +194 -0
  143. package/examples/11-events/package.json +20 -0
  144. package/examples/11-events/src/index.ts +27 -0
  145. package/examples/11-events/src/schemas.ts +19 -0
  146. package/examples/11-events/tests/pulse.harness.ts +34 -0
  147. package/examples/11-events/tsconfig.json +15 -0
  148. package/examples/12-mcp-proxy/.pulse/.gitignore +3 -0
  149. package/examples/12-mcp-proxy/.pulse/config.ts +25 -0
  150. package/examples/12-mcp-proxy/README.md +149 -0
  151. package/examples/12-mcp-proxy/package.json +20 -0
  152. package/examples/12-mcp-proxy/src/index.ts +17 -0
  153. package/examples/12-mcp-proxy/tests/pulse.harness.ts +29 -0
  154. package/examples/12-mcp-proxy/tsconfig.json +14 -0
  155. package/examples/13-jwt-es256/.pulse/config.ts +19 -0
  156. package/examples/13-jwt-es256/README.md +195 -0
  157. package/examples/13-jwt-es256/package.json +21 -0
  158. package/examples/13-jwt-es256/src/index.ts +21 -0
  159. package/examples/13-jwt-es256/tests/pulse.harness.ts +54 -0
  160. package/examples/13-jwt-es256/tsconfig.json +14 -0
  161. package/examples/README.md +36 -0
  162. package/package.json +66 -6
  163. package/project-config.schema.json +981 -0
  164. package/release-manifest.json +441 -0
  165. package/src/command-spec.js +279 -0
  166. package/src/completion.js +113 -0
  167. package/src/diagnostics.js +350 -0
  168. package/src/documentation.js +45 -0
  169. package/src/index.d.ts +133 -0
  170. package/src/index.js +15 -0
  171. package/src/internal/command-executor.d.ts +29 -0
  172. package/src/internal/command-executor.js +143 -0
  173. package/src/internal/command-plan.d.ts +9 -0
  174. package/src/internal/command-plan.js +73 -0
  175. package/src/internal/command-reporter.d.ts +15 -0
  176. package/src/internal/command-reporter.js +133 -0
  177. package/src/internal/command-request.d.ts +35 -0
  178. package/src/internal/command-request.js +154 -0
  179. package/src/internal/node-http.js +54 -0
  180. package/src/internal/project-context.d.ts +66 -0
  181. package/src/internal/project-context.js +175 -0
  182. package/src/project-config-reference.js +4 -0
  183. package/src/project-config-schema.d.ts +23 -0
  184. package/src/project-config-schema.js +271 -0
  185. package/src/project-config.js +724 -0
  186. package/src/project-execution.js +2946 -0
  187. package/src/provider-drivers.js +3 -0
  188. package/src/target-support.js +3 -0
  189. package/src/typescript-module-loader.js +269 -0
  190. package/src/workflow.js +78 -0
  191. package/src/workspace.js +82 -0
@@ -0,0 +1,300 @@
1
+ # Effects and continuations
2
+
3
+ A Pulse handler is written as async-shaped TypeScript. Host operations such as fetch, KV, secrets, and GRIP are awaited in source, but Native targets do not link a JavaScript Promise runtime. The compiler erases the managed async wrapper and trusted Pulse awaits into **effects** and the code that follows into **continuations**. JavaScript targets execute the same source through the live runtime and provider-owned effect adapter.
4
+
5
+ Application authors do not create or resume continuation objects. They write canonical TypeScript; the compiler and provider runtime own the lifecycle.
6
+
7
+ ## Effect
8
+
9
+ An effect is an explicit request for host authority. Each effect has an identity, capability, operation, resource, source position, and result shape. Common examples include:
10
+
11
+ - dispatching an outbound fetch;
12
+ - reading config or a secret;
13
+ - getting or putting a KV value;
14
+ - accepting one outbound event through `ctx.emit`;
15
+ - declaring a GRIP channel;
16
+ - holding or publishing through GRIP.
17
+
18
+ Pure value construction, branching, property reads, and arithmetic are not effects.
19
+
20
+ ## Continuation
21
+
22
+ A continuation identifies the compiled work that can proceed after one effect—or one effect group—settles. It carries no application-accessible provider object. The runtime resumes it with a normalized result or failure.
23
+
24
+ ```text
25
+ compiled values
26
+
27
+ ├── effect request ──► provider/runtime
28
+ │ │
29
+ └── continuation ◄────────┘ normalized result or failure
30
+ ```
31
+
32
+ A continuation is single-use and time-bounded. Expired or duplicate resume attempts fail with stable diagnostics such as [`PULSE_CONTINUATION_EXPIRED`](../reference/diagnostics.md#pulse-continuation-expired) and [`PULSE_CONTINUATION_DOUBLE_RESUME`](../reference/diagnostics.md#pulse-continuation-double-resume).
33
+
34
+ ## Independent effects form a group
35
+
36
+ The multi-fetch example declares three independent fetch values before consuming any of them:
37
+
38
+ <!-- pulse-doc-source: examples/03-fetch-composition/src/index.ts -->
39
+ ```ts
40
+ import { Pulse } from '@pulse-compute/pulse'
41
+
42
+ interface User {
43
+ id: number
44
+ name: string
45
+ }
46
+
47
+ interface Stats {
48
+ score: number
49
+ }
50
+
51
+ interface Flags {
52
+ enabled: boolean
53
+ }
54
+
55
+ const app = new Pulse({ auto: true })
56
+
57
+ // One structured origin.
58
+ app.get('/user', async (ctx) => {
59
+ const user = await ctx
60
+ .fetch('https://users.example.test/users/123')
61
+ .json<User>()
62
+ return ctx.json({ found: true, user })
63
+ })
64
+
65
+ // Multiple origins with explicit sequential awaits.
66
+ app.get('/user-summary', async (ctx) => {
67
+ const user = await ctx
68
+ .fetch('https://users.example.test/users/123')
69
+ .json<User>()
70
+ const stats = await ctx
71
+ .fetch('https://stats.example.test/users/123')
72
+ .json<Stats>()
73
+ const flags = await ctx
74
+ .fetch('https://flags.example.test/users/123')
75
+ .json<Flags>()
76
+ return ctx.json({
77
+ id: user.id,
78
+ name: user.name,
79
+ score: stats.score,
80
+ enabled: flags.enabled,
81
+ })
82
+ })
83
+
84
+ // Multiple origins with explicit portable concurrency.
85
+ app.get('/user-summary-parallel', async (ctx) => {
86
+ const { user, stats, flags } = await ctx.parallel({
87
+ user: ctx.fetch('https://users.example.test/users/123').json<User>(),
88
+ stats: ctx.fetch('https://stats.example.test/users/123').json<Stats>(),
89
+ flags: ctx.fetch('https://flags.example.test/users/123').json<Flags>(),
90
+ })
91
+ return ctx.json({
92
+ id: user.id,
93
+ name: user.name,
94
+ score: stats.score,
95
+ enabled: flags.enabled,
96
+ })
97
+ })
98
+
99
+ export default app
100
+ ```
101
+ <!-- /pulse-doc-source -->
102
+
103
+ ```bash
104
+ pulse inspect examples/03-fetch-composition --json
105
+ ```
106
+
107
+ The compiler can issue those fetches as one effect group because none depends on another result. The continuation becomes eligible only after the group settles.
108
+
109
+ Grouping provides concurrency without linking a general Promise runtime into Native artifacts. Source declaration order remains deterministic for identities and result binding, but providers may perform independent operations concurrently.
110
+
111
+
112
+ ## Explicit portable groups with `ctx.parallel`
113
+
114
+ Native Pulse may discover independent adjacent effects and place them in one group
115
+ for performance. Direct JavaScript execution does not rewrite ordinary `await`
116
+ semantics, so separate awaits remain sequential there. Use `ctx.parallel({ ... })`
117
+ when concurrency is required application behavior across targets:
118
+
119
+ ```ts
120
+ const { profile, flags } = await ctx.parallel({
121
+ profile: ctx.fetch(profileUrl).json<Profile>(),
122
+ flags: ctx.fetch(flagsUrl).json<Flags>(),
123
+ })
124
+ ```
125
+
126
+ The first contract accepts a nonempty inline object literal with fixed,
127
+ non-index string keys and Pulse effect expressions as values. Property order owns
128
+ dispatch identity, trace order, deterministic primary-failure selection, and keyed
129
+ result reconstruction. Providers may complete members in any order, but every
130
+ member settles before the continuation resumes.
131
+
132
+ On JavaScript, all members execute through one execution-owned shared effect adapter.
133
+ On Native, lowering erases `ctx.parallel`, emits the member operations into one
134
+ canonical effect group, and reconstructs the ordinary keyed result object after
135
+ one continuation. Arrays, spreads, computed keys, dynamic records, arbitrary
136
+ promises, reused roots, and nested groups are outside the initial portable shape.
137
+
138
+ ## One-way outbound events
139
+
140
+ HTTP and event handlers share the direct JavaScript `ctx.emit` effect:
141
+
142
+ ```ts
143
+ await ctx.emit('device.led.set', {
144
+ schema: 'events.DeviceLedSet',
145
+ payload: { enabled: true },
146
+ })
147
+
148
+ await ctx.emit('system.tick', { schema: null })
149
+ ```
150
+
151
+ The event type and schema are static compiler inputs. A non-null schema requires
152
+ `payload`; `schema: null` forbids it. The runtime schema-validates and detaches
153
+ the canonical frame before dispatch, and the effect resolves only when the
154
+ configured host adapter accepts that frame. It returns `undefined`: there is no
155
+ delivery receipt, correlation ID, handler result, retry guarantee, or local
156
+ loopback.
157
+
158
+ `ctx.emit` may be awaited directly or used as a fresh member of an awaited
159
+ `ctx.parallel` group. It consumes the same execution effect budget, cancellation,
160
+ redaction, and disposal boundary as fetch, config, secret, and KV effects. The
161
+ JavaScript dispatch uses the execution-owned effect adapter. Native lowering
162
+ emits the same canonical `event.emit` descriptor, suspends on the ordinary
163
+ continuation protocol, and resumes after host acceptance; it adds no JavaScript,
164
+ Promise, or Asyncify runtime. The Node provider has a bounded, invocation-scoped
165
+ FIFO reference adapter for direct JavaScript/Native ingress and exact accepted
166
+ frame evidence. Its outbound ledger never loops back into ingress, and its
167
+ success still promises no delivery, persistence, retry, receipt, or public
168
+ event-bus behavior. No other provider realization or automatic fallback is
169
+ claimed.
170
+
171
+ One-way acceptance is also the recursion boundary. Pulse exposes no
172
+ `ctx.call`, generic request/reply effect, automatic local dispatch, or reserved
173
+ call opcode. A future reflexive mechanism cannot be inferred from `ctx.emit`;
174
+ it requires a separately specified host and lifecycle. See [Static events and
175
+ outbound emission](../guides/events.md).
176
+
177
+ ## Dependencies split continuation stages
178
+
179
+ When later control flow or a later host operation depends on an earlier result, the compiler creates another continuation stage. For example, inspecting a first response and choosing a second URL is dependent work; it cannot be moved into the first independent group.
180
+
181
+ The rule is semantic rather than stylistic:
182
+
183
+ - independent operations may share one group;
184
+ - operations that need prior values start in a later continuation;
185
+ - pure computation between effects stays in the continuation that owns it;
186
+ - returning a final response completes the request lifecycle.
187
+
188
+ Use `pulse inspect --json` to see the actual grouping rather than inferring it from line spacing.
189
+
190
+ ## Failure behavior
191
+
192
+ An effect failure is normalized into a stable public error. Examples include:
193
+
194
+ - [`PULSE_FETCH_TIMEOUT`](../reference/diagnostics.md#pulse-fetch-timeout);
195
+ - [`PULSE_FETCH_NETWORK`](../reference/diagnostics.md#pulse-fetch-network);
196
+ - [`PULSE_PROVIDER_CAPABILITY_UNSUPPORTED`](../reference/diagnostics.md#pulse-provider-capability-unsupported);
197
+ - [`PULSE_FASTLY_BACKEND_REQUIRED`](../reference/diagnostics.md#pulse-fastly-backend-required).
198
+
199
+ For an independent group, the runtime settles the group and reports the normalized failures through the owning continuation boundary. Userland does not receive partially live provider handles or background tasks that can outlive the request.
200
+
201
+ ## Timeouts have two scopes
202
+
203
+ A fetch can have an operation timeout through `PulseFetchInit.timeoutMs`. The request runtime also owns a continuation lifetime configured by the execution environment or test case. These are different controls:
204
+
205
+ - the operation timeout bounds one host operation;
206
+ - the continuation TTL bounds how long compiled execution may remain suspended before resumption is rejected.
207
+
208
+ Project tests can set `continuationTtlMs` in a case inside the dedicated `tests/pulse.harness.ts` module for deterministic failure coverage.
209
+
210
+ ## Managed async, not arbitrary async
211
+
212
+ Write managed handlers with `async` and await trusted Pulse effects. On Native targets, the compiler erases that notation into effects and continuations. On JavaScript targets, the live runtime executes the same async-shaped handler normally.
213
+
214
+ Arbitrary Promise construction, ambient asynchronous APIs, and unrecognized library awaits remain outside Native eligibility. They must not be mistaken for Pulse effects or silently trigger target fallback.
215
+
216
+ This design keeps:
217
+
218
+ - effects visible to the compiler;
219
+ - provider capability checks complete before execution;
220
+ - failures and timeouts normalized;
221
+ - request completion bounded;
222
+ - Node and Fastly behavior comparable.
223
+
224
+ ## Inspect and test the lifecycle
225
+
226
+ A useful workflow is:
227
+
228
+ ```bash
229
+ pulse inspect ./my-app --json
230
+ pulse test ./my-app --json
231
+ ```
232
+
233
+ `inspect` proves compilation, effects, grouping, continuations, and provider lowering without executing application test cases. `test` executes configured cases through the selected provider’s local conformance runtime.
234
+
235
+ ## Related documentation
236
+
237
+ - [Managed handler TypeScript and JavaScript](../reference/handler-authoring.md)
238
+ - [Provider and target compatibility](../reference/compatibility-matrix.md)
239
+ - [Compilation and lowering](./compilation-and-lowering.md)
240
+ - [Structured and opaque bodies](./bodies.md)
241
+ - [Fetching and composing data](../guides/fetching-and-composition.md)
242
+ - [Project configuration](../reference/project-config.md)
243
+ - [Troubleshooting](../guides/troubleshooting.md)
244
+
245
+ ## Conditional KV
246
+
247
+ `ctx.kv<T>('name')` exposes `getVersioned(key)`, `insertIfAbsent(key, value)`, and
248
+ `compareAndSwap(key, generation, value)` as direct awaited or keyed parallel
249
+ effects. The Node reference implements the contract for JavaScript and compiled
250
+ Native control flow. Fastly Native implements it through direct KV hostcalls;
251
+ Fastly JavaScript conditional KV remains explicitly incomplete.
252
+
253
+ The condition and mutation are atomic at one key's authority. A versioned read
254
+ returns a value and an opaque generation from the same observation, which may be
255
+ stale. Generations are strings, not numbers, hashes or application versions.
256
+ Create conflicts when present; CAS conflicts when absent or when its token is
257
+ stale. Equal-byte replacement is still a write and changes its generation.
258
+ Existing unconditional `get` and `put` remain available.
259
+
260
+ A write returns `stored`, `conflict`, `not-stored` with a bounded reason, or
261
+ `unknown` with a bounded reason. Unknown may have committed. A complete explicit
262
+ provider rejection establishes no write; an exception from a send primitive
263
+ does not. Pulse does not retry, reread-and-rebase, or invent a generation from a
264
+ write acknowledgement. A subsequent missing or stale read cannot resolve an
265
+ ambiguous write by itself.
266
+
267
+ Admission detaches and freezes the candidate before provider preparation. The
268
+ host's monotonic ten-second deadline starts at admission and is shortened by an
269
+ owning request deadline. Preparation may resolve bindings and stage data but
270
+ cannot send. Entry into the returned provider primitive marks dispatch even if
271
+ it throws synchronously. Timeout before that boundary is `not-stored`; timeout
272
+ or transport loss after it is `unknown`. Cancellation suppresses delivery to an
273
+ inactive execution and records whether dispatch occurred; it promises no rollback.
274
+
275
+ Exact keys are bounded Unicode scalar strings; generations are bounded visible
276
+ ASCII strings. Values retain the portable KV JSON limits. Conditional storage
277
+ uses a strict UTF-8 JSON envelope with exactly `__pulseKv: 1` and `value`, rejecting
278
+ duplicate members, invalid values, and oversized bodies. The wrapper is not
279
+ recursively unwrapped. Legacy raw JSON requires explicit migration. Keys, tokens,
280
+ and values are omitted or redacted from runtime evidence and managed errors;
281
+ application responses are not silently rewritten.
282
+
283
+ Node reference instances retain nonreused generation identities for their own
284
+ lifetime. Host code can explicitly reuse one reference across requests and target
285
+ runners; independent instances isolate their state. Deterministic identities,
286
+ clocks, and failure hooks belong to host evidence, not handler authority. This
287
+ local model does not establish durability, global visibility, cross-key
288
+ transactions, or a portable physical-delete/recreate guarantee. Fastly SDK
289
+ limitations cannot redefine this contract or gate other targets.
290
+
291
+ Fastly Native preserves all 64 generation bits in an opaque string. ADD and
292
+ generation-conditioned overwrite remain distinct operations, including an explicit
293
+ condition for zero bits. The adapter stages the complete envelope before dispatch,
294
+ uses monotonic deadlines and readiness selection before pending waits and body
295
+ reads, and closes acquired bodies. It accepts up to 65,560 wire bytes, including
296
+ wrapper overhead. Provider key restrictions return `invalid-key` without changing
297
+ the key. Pending KV operations have no cancellation hostcall; an expired operation
298
+ is abandoned to invocation teardown and may still commit. Host termination never
299
+ resumes an inactive handler. Local Wasm evidence is separate from K4's deployed
300
+ cross-location acceptance.
@@ -0,0 +1,71 @@
1
+ # Entity engine, adapters, and facades
2
+
3
+ Pulse Entities separates governed operation semantics from the protocol that
4
+ selects an operation and from any facade that presents those operations to an
5
+ external ecosystem.
6
+
7
+ ## The four layers
8
+
9
+ | Layer | Owns | Does not own |
10
+ |---|---|---|
11
+ | Entity engine | Static operation names, schema declarations, handler identity, governed execution, deterministic catalog | HTTP/JSON-RPC syntax, MCP lifecycle, provider SDKs |
12
+ | JSON-RPC adapter | Bounded envelope parsing, request/notification selection, named params, stable JSON-RPC result/error framing | Handler semantics, schema registry authority, direct provider access |
13
+ | Tools or MCP facade | Catalog projection, external tool naming/annotations, transport-facing invocation policy | Direct handler calls, runtime registry mutation, hidden Pulse authority |
14
+ | Worker/event adapter (future) | A separately specified event/request binding and response/acknowledgement mapping | Changes to entity declarations or handler effect authority |
15
+
16
+ The entity engine is therefore not a server. `EntityRouter` records a static
17
+ registry and binds it to one governed request. `jsonRpc()` is the only current
18
+ adapter. A facade may read the emitted `entities-catalog.json` and construct a
19
+ request for that adapter, but it cannot enumerate live handler functions or
20
+ call them outside a Pulse request context.
21
+
22
+ ## Why the catalog is protocol-neutral
23
+
24
+ The catalog contains operation names, schema IDs, static metadata, and target
25
+ eligibility. It excludes handlers, raw requests, request IDs, provider objects,
26
+ secrets, and runtime values. That makes it suitable for build-time discovery
27
+ without making discovery a new ambient runtime authority.
28
+
29
+ The inspection artifact is richer and maintainer-facing: it adds redacted
30
+ handler-effect summaries and measured target evidence. Neither artifact is a
31
+ mutable service registry.
32
+
33
+ ## Authority flow
34
+
35
+ 1. Project configuration owns declared schemas and provider selection.
36
+ 2. The trusted first-party lowerer extracts entity declarations without
37
+ evaluating application code.
38
+ 3. The selected adapter owns bounded protocol decoding and operation selection.
39
+ 4. The selected schema codecs decode only the chosen input and encode only the
40
+ chosen output.
41
+ 5. The handler receives the normal request-owned `PulseContext`; every fetch,
42
+ config, secret, KV, log, or package effect remains governed by that context.
43
+ 6. The adapter frames completion. A facade sees only the framed boundary.
44
+
45
+ No layer may silently choose another target. Native ineligibility fails closed;
46
+ it never authorizes JavaScript fallback.
47
+
48
+ ## MCP/tools boundary
49
+
50
+ The [Entities tools example](../../examples/10-entities-tools/) demonstrates a
51
+ small facade that projects static metadata and invokes JSON-RPC. It is
52
+ intentionally not a complete MCP implementation. Pulse runtime core does not
53
+ gain SSE, sessions, tasks, resources, prompts, sampling, authorization,
54
+ transport negotiation, or MCP lifecycle state from this candidate.
55
+
56
+ A complete MCP server could be built outside the entity engine if it preserves
57
+ these rules: static discovery comes from an emitted catalog, invocation crosses
58
+ a governed adapter boundary, external protocol state stays outside runtime
59
+ core, and MCP behavior never becomes a source of provider or schema authority.
60
+
61
+ ## Future adapters
62
+
63
+ A Worker, queue, scheduled-event, or other event adapter would be a new
64
+ first-party adapter contract. It would define bounded selection and completion
65
+ for that event shape while retaining the same static declaration, schema,
66
+ handler, effect, catalog, and no-fallback rules. The current package does not
67
+ open third-party adapter registration or claim those adapters exist.
68
+
69
+ See the [Entities package guide](../packages/entities.md) for current behavior
70
+ and [Entities lowering](../contributing/entities-lowering.md) for the trusted
71
+ maintainer boundary.
@@ -0,0 +1,175 @@
1
+ # Package-owned lowering
2
+
3
+ Package-owned lowering lets a synchronized Pulse package extend the canonical compiler with narrow, statically recognized operations while keeping domain rules out of compiler core.
4
+
5
+ The synchronized `1.0.0-beta.2` release uses this pattern for Assets, GRIP,
6
+ JWT, and Entities.
7
+ It is a **trusted first-party synchronization mechanism**, not a public
8
+ registry that executes arbitrary npm compiler plugins.
9
+
10
+ ## One package API, two execution paths
11
+
12
+ Application code imports the normal package root:
13
+
14
+ ```ts
15
+ import { assets } from '@pulse-compute/assets'
16
+ import { grip } from '@pulse-compute/grip'
17
+ import { jwt } from '@pulse-compute/jwt'
18
+ ```
19
+
20
+ On the JavaScript target, the actual package TypeScript/JavaScript implementation executes. On Native targets, the compiler recognizes supported package-root symbols and lowers them into canonical package effects. Lowering restrictions remain eligibility and diagnostic rules; they do not require target-specific application source.
21
+
22
+ Older `/pulsewasm` imports are compatibility-only and are isolated in the
23
+ [migration guide](../guides/compatibility-imports.md).
24
+
25
+ ## Why the package owns the lowerer
26
+
27
+ A domain package knows details that compiler core should not:
28
+
29
+ - which root symbols are effects or pure result adapters;
30
+ - which argument shapes are statically representable;
31
+ - which payload versions and diagnostics belong to the domain;
32
+ - which sidecar symbols compiled Wasm requires;
33
+ - which capabilities a provider must implement;
34
+ - which JavaScript behavior is broader than the lowerable Native subset.
35
+
36
+ ## Package anatomy
37
+
38
+ A lowerable package normally ships:
39
+
40
+ ```text
41
+ package.json application exports and discovery pointers
42
+ pulse.package.json product, target, ownership, and conformance metadata
43
+ src/ actual JavaScript implementation and portable API
44
+ pulsewasm.manifest.cjs trusted lowerer and compatibility declaration
45
+ pulsewasm.compiler.cjs package-specific validation and effect construction
46
+ as/index.as.ts optional compiled-Wasm sidecar ABI
47
+ README.md current product and compatibility boundary
48
+ ```
49
+
50
+ `pulse.package.json` is static metadata. It cannot register or execute compiler code. `pulsewasm.manifest.cjs` identifies the trusted first-party compiler builder. Product metadata and executable compiler authority remain separate.
51
+
52
+ ## Discovery and trust
53
+
54
+ The canonical project compiler:
55
+
56
+ 1. builds the reachable module graph;
57
+ 2. attributes package imports from that graph rather than source substrings;
58
+ 3. loads synchronized package product contracts;
59
+ 4. selects a trusted package compiler only for a reachable supported Native operation;
60
+ 5. invokes it through the exact immutable shared builder envelope;
61
+ 6. normalizes its artifact and contributions before compiler orchestration;
62
+ 7. combines canonical package effects with core effects and continuations;
63
+ 8. validates the complete provider capability envelope.
64
+
65
+ A package manifest must declare first-party trust and ownership matching the
66
+ package. Dynamic third-party compiler registration is not part of the Beta
67
+ contract.
68
+
69
+ Caller option bags do not cross this boundary. In particular, provider target
70
+ descriptors, drivers, runtime objects, raw CLI configuration, compiler caches,
71
+ resolved secrets, and arbitrary compiler services are not builder inputs.
72
+ Package builders emit canonical requirements; later compiler/provider
73
+ eligibility checks decide whether the selected target can satisfy them.
74
+
75
+ ## Request-bound package effects
76
+
77
+ A package effect is created through an explicit `PulseContext`:
78
+
79
+ ```ts
80
+ await grip.broadcast(ctx, {
81
+ channel: 'events:demo',
82
+ data: { type: 'message', value: 'hello' },
83
+ })
84
+ ```
85
+
86
+ The shared package bridge returns the same request-owned effect value used by core operations. It therefore supports:
87
+
88
+ - direct `await`;
89
+ - keyed `ctx.parallel({ ... })`;
90
+ - request cancellation and completion containment;
91
+ - deterministic grouped failure selection;
92
+ - known-secret redaction;
93
+ - generic provider dispatch.
94
+
95
+ The bridge has a fixed first-party identity catalog. It does not use ambient current-request state, `AsyncLocalStorage`, or mutable global registration.
96
+
97
+ ## Pure package operations
98
+
99
+ Not every package function is an effect. Pure request classification and response decoration should remain ordinary JavaScript:
100
+
101
+ ```ts
102
+ if (grip.isWebSocket(ctx.req)) {
103
+ return grip.handoff({ channel: 'events:demo' })
104
+ }
105
+
106
+ return grip.subscribe(new Response(null), {
107
+ channel: 'events:demo',
108
+ mode: 'stream',
109
+ })
110
+ ```
111
+
112
+ Similarly, `assets.respond()` is a pure result adapter. Native lowering may erase that helper around an `assets.lookup()` result without turning response decoration into another provider effect.
113
+
114
+ ## Static call shapes
115
+
116
+ Native package lowering intentionally accepts less than arbitrary TypeScript. A package may require:
117
+
118
+ - a known package-root import and symbol;
119
+ - supported direct-await, variable, return, or `ctx.parallel()` placement;
120
+ - fixed object-literal options;
121
+ - statically representable resources or operation selectors;
122
+ - no escaping internal handles;
123
+ - no provider SDK values.
124
+
125
+ Unsupported shapes make the Native project ineligible with a source-located diagnostic. The same package may still support broader direct JavaScript behavior when the selected JavaScript target and provider contract allow it.
126
+
127
+ ## Provider completion
128
+
129
+ A package is not complete merely because its compiler emits an effect. Every provider advertised for that operation must:
130
+
131
+ - declare the capability;
132
+ - map it to a stable operation;
133
+ - validate required bindings;
134
+ - execute it in local conformance;
135
+ - realize it in deployable output when claimed;
136
+ - preserve structured or opaque result ownership.
137
+
138
+ Assets demonstrates package-root JavaScript execution plus Native package lowering and opaque response ownership. GRIP provides stateless JavaScript framing, bounded broadcast provider realization, and Native/root conformance.
139
+
140
+ JWT demonstrates a package-owned verification effect whose Native lowering
141
+ composes package-owned JWT logic with crypto-owned realizations. HS256 Native
142
+ compiles the crypto guest source into the primary module; ES256 Native
143
+ contributes one exact prebuilt guest unit through the guest-link boundary.
144
+ JavaScript uses the same package contract with the selected runtime builtin for
145
+ HS256 and ES256. Provider eligibility begins only after the package emits its
146
+ provider-neutral capability and crypto requirements.
147
+
148
+ A package-selected prebuilt guest is a separate canonical contribution, not a
149
+ filesystem or compiler object. It carries only its version, stable ID,
150
+ package-relative manifest, exact owner/package version, and
151
+ `package-prebuilt` origin. The compiler resolves the synchronized package root
152
+ as a separate selection fact. Guest-link then receives that exact contribution
153
+ through its own invocation contract; `packageRoot`, target descriptors,
154
+ compiler realizations, and option bags are never fields of the contribution.
155
+
156
+ ## Release expectations
157
+
158
+ A supported package-owned lowerer needs:
159
+
160
+ - product and trusted-manifest validation;
161
+ - positive and negative static lowering tests;
162
+ - JavaScript runtime tests for the real package implementation;
163
+ - direct-await and keyed-parallel package-effect tests;
164
+ - provider capability and binding tests;
165
+ - packed-package discovery and clean installation;
166
+ - documentation distinguishing canonical roots from compatibility subpaths;
167
+ - explicit evidence classifying every unsupported shape.
168
+
169
+ See [Pulse-aware package
170
+ authoring](../contributing/pulse-aware-packages.md), [Add a first-party
171
+ package-owned lowerer](../contributing/adding-first-party-lowerer.md), [Managed
172
+ handler TypeScript and JavaScript](../reference/handler-authoring.md),
173
+ [Provider and target compatibility](../reference/compatibility-matrix.md),
174
+ [Contracts and providers](./contracts-and-providers.md), and [Compilation and
175
+ lowering](./compilation-and-lowering.md).
@@ -0,0 +1,70 @@
1
+ # Targets and host work
2
+
3
+ Pulse is centered on one application contract. A host is the explicit
4
+ realization layer for that contract, not an object application code imports or
5
+ branches on. The release distinguishes current execution proof from forward
6
+ host work so architectural direction does not become an accidental support
7
+ claim.
8
+
9
+ An explicit JavaScript profile can retain resolved static package imports and
10
+ project-relative helpers, including awaited calls into ordinary JavaScript
11
+ dependencies. Pulse checks the canonical application surface and packages its
12
+ original source graph. Native eligibility is reported separately and does not
13
+ block JavaScript execution. Unsupported dynamic module boundaries and missing
14
+ `await` on Pulse effects still fail validation. `pulse compile` continues to
15
+ require Native-compatible source; use `pulse build` for a JavaScript package.
16
+
17
+ ## Current Beta targets
18
+
19
+ `1.0.0-beta.2` exercises four explicit modes through one conformance corpus:
20
+
21
+ | Host | Target | Current release status | Build shape |
22
+ |---|---|---|---|
23
+ | Node | Native | Beta candidate | Provider-neutral application Wasm with the Node host runtime. |
24
+ | Node | JavaScript | Beta candidate | Explicit Node JavaScript source package. |
25
+ | Fastly | Native | Beta candidate | Provider-neutral application Wasm plus deployable `bin/main.wasm`. |
26
+ | Fastly | JavaScript | Beta candidate | Explicit Fastly JavaScript package. |
27
+
28
+ Target selection is part of the active project profile. Pulse does not switch
29
+ targets automatically when source crosses a Native boundary. The
30
+ [compatibility matrix](../reference/compatibility-matrix.md) owns exact
31
+ capability differences, and [Beta scope](../preview-scope.md) owns the release
32
+ claim.
33
+
34
+ The `none` selector is compile-only: it can inspect and emit canonical Native
35
+ artifacts without claiming an executable host.
36
+
37
+ ## Forward boundary witnesses
38
+
39
+ Forward hosts are useful because they pressure the contract in different ways.
40
+ They remain outside the Beta execution matrix until they have their own
41
+ adapter, lifecycle, conformance evidence, and package claim.
42
+
43
+ ### ESP32
44
+
45
+ The [ESP32 reference host](https://github.com/pulsecompute/pulse-esp32-host)
46
+ tests whether the event/effect/continuation model remains useful without a
47
+ JavaScript fallback, abundant memory, or an HTTP-centered lifecycle. It is a
48
+ boundary witness, not a `1.0.0-beta.2` provider or compatibility promise. The
49
+ [architecture vision](../architecture/vision.md#esp32-as-a-boundary-witness)
50
+ describes the intended host-owned interrupt queue and non-reentrant Wasm entry.
51
+
52
+ ### Browser event conformance
53
+
54
+ The browser is a forward event-conformance target: a future browser host should
55
+ accept the same canonical event frames, keep HTTP and event entries separate,
56
+ preserve invocation-local state, and report outbound frame acceptance through
57
+ the same bounded contract. Pulse does not currently claim a browser runtime,
58
+ provider package, listener, delivery service, or event transport.
59
+
60
+ This is deliberately narrower than saying “Pulse runs in the browser.” The
61
+ [events guide](../guides/events.md) defines the current Node reference boundary
62
+ and the evidence a new host must supply.
63
+
64
+ ## Where provider details belong
65
+
66
+ Application docs lead with `ctx`, Router, schemas, and capabilities. Provider
67
+ details belong in project profiles, deployment guides, compatibility tables,
68
+ and package pages where build or runtime behavior actually differs. That keeps
69
+ the common surface readable while leaving each host’s authority and limits
70
+ explicit.
@@ -0,0 +1,38 @@
1
+ <!-- pulse-doc-meta:start
2
+ owner: docs-platform
3
+ status: active
4
+ last-reviewed: 2026-07-25
5
+ review-by: 2027-01-25
6
+ pulse-doc-meta:end -->
7
+
8
+ # Contributing documentation
9
+
10
+ These pages describe changes to the synchronized Pulse repository. They are not application-author extension APIs.
11
+
12
+ ## Choose the extension boundary
13
+
14
+ - [Pulse-aware package authoring](./pulse-aware-packages.md) — ordinary JavaScript packages, bounded package-root Native lowering, trusted builders, and the separate scoped-provider boundary.
15
+
16
+ ## Package-owned lowering
17
+
18
+ - [Package lowerer contract reference](./package-lowerer-contract.md) — manifest fields, builder protocol, effect shape, trust rules, and release invariants.
19
+ - [Add a first-party package-owned lowerer](./adding-first-party-lowerer.md) — end-to-end implementation tutorial using the GRIP/assets pattern.
20
+ - [Entities lowering maintainer reference](./entities-lowering.md) — static extraction, schema authority, Native realization, catalog, and seal invariants for the Entities package.
21
+
22
+ ## Providers
23
+
24
+ - [Add a provider toolchain](./adding-core-provider.md) — descriptor, bindings, runtime, target, namespace bootstrap, diagnostics, docs, and tests.
25
+
26
+ ## Repository context
27
+
28
+ - [Package support policy](../packages/README.md)
29
+ - [Architecture overview](../architecture/overview.md)
30
+ - [Current architecture contracts](../architecture/current-contracts.md)
31
+ - [Reference overview](../reference/README.md)
32
+
33
+ The current release executes only trusted first-party lowerer builders. Built-in
34
+ provider shorthand is release-owned, while an exact scoped project provider may
35
+ export the versioned `./toolchain` contract without self-registration or
36
+ dependency scanning. Changes that widen either executable trust boundary
37
+ require an explicit security and compatibility design, not only another
38
+ manifest or package export.