@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.
- package/API.md +572 -0
- package/CHANGELOG.md +71 -0
- package/README.md +71 -1
- package/bin/pulse.js +15 -0
- package/bin/pulsewasm-extract.js +22 -0
- package/cli-spec.json +575 -0
- package/completions/_pulse +106 -0
- package/completions/pulse.bash +31 -0
- package/completions/pulse.fish +76 -0
- package/docs/README.md +77 -0
- package/docs/architecture/current-contracts.md +470 -0
- package/docs/architecture/overview.md +93 -0
- package/docs/architecture/vision.md +515 -0
- package/docs/concepts/bodies.md +186 -0
- package/docs/concepts/compilation-and-lowering.md +496 -0
- package/docs/concepts/contracts-and-providers.md +158 -0
- package/docs/concepts/effects-and-continuations.md +300 -0
- package/docs/concepts/entities-and-adapters.md +71 -0
- package/docs/concepts/package-owned-lowering.md +175 -0
- package/docs/concepts/targets-and-hosts.md +70 -0
- package/docs/contributing/README.md +38 -0
- package/docs/contributing/adding-core-provider.md +315 -0
- package/docs/contributing/adding-first-party-lowerer.md +327 -0
- package/docs/contributing/entities-lowering.md +91 -0
- package/docs/contributing/package-lowerer-contract.md +383 -0
- package/docs/contributing/pulse-aware-packages.md +149 -0
- package/docs/examples.md +112 -0
- package/docs/fixtures/inspect-fetch-composition.selected.json +181 -0
- package/docs/getting-started.md +128 -0
- package/docs/guides/compatibility-imports.md +60 -0
- package/docs/guides/deploying-fastly.md +188 -0
- package/docs/guides/deploying-node.md +143 -0
- package/docs/guides/events.md +233 -0
- package/docs/guides/fastly-capabilities.md +153 -0
- package/docs/guides/fetching-and-composition.md +101 -0
- package/docs/guides/grip.md +94 -0
- package/docs/guides/json-schemas.md +233 -0
- package/docs/guides/migrating-from-express.md +192 -0
- package/docs/guides/project-lifecycle.md +143 -0
- package/docs/guides/routing.md +202 -0
- package/docs/guides/troubleshooting.md +47 -0
- package/docs/maintainers/README.md +60 -0
- package/docs/maintainers/codex-maintainer.md +71 -0
- package/docs/maintainers/documentation-deployment.md +147 -0
- package/docs/maintainers/documentation-system.md +58 -0
- package/docs/maintainers/documentation-versioning.md +65 -0
- package/docs/maintainers/maintainer-charter.md +100 -0
- package/docs/maintainers/maintenance-policy.json +809 -0
- package/docs/maintainers/maintenance-policy.md +124 -0
- package/docs/maintainers/npm-publishing.md +154 -0
- package/docs/maintainers/plugin-readiness.json +19 -0
- package/docs/maintainers/plugin-readiness.md +31 -0
- package/docs/maintainers/public-site.md +158 -0
- package/docs/maintainers/release-acceptance.md +293 -0
- package/docs/maintainers/release-manifest.md +89 -0
- package/docs/maintainers/repository-setup.md +145 -0
- package/docs/maintainers/scope-policy.md +105 -0
- package/docs/maintainers/support-and-triage.md +74 -0
- package/docs/maintainers/testing.md +334 -0
- package/docs/packages/README.md +60 -0
- package/docs/packages/assets.md +85 -0
- package/docs/packages/cli.md +190 -0
- package/docs/packages/crypto.md +78 -0
- package/docs/packages/entities.md +129 -0
- package/docs/packages/grip.md +82 -0
- package/docs/packages/implementation-packages.md +122 -0
- package/docs/packages/jwt.md +55 -0
- package/docs/packages/provider-fastly.md +243 -0
- package/docs/packages/pulse.md +159 -0
- package/docs/packages/runtime.md +265 -0
- package/docs/packages/s3.md +101 -0
- package/docs/preview-scope.md +142 -0
- package/docs/reference/README.md +33 -0
- package/docs/reference/cli-spec.json +575 -0
- package/docs/reference/cli.md +457 -0
- package/docs/reference/compatibility-matrix.md +169 -0
- package/docs/reference/diagnostics.md +1872 -0
- package/docs/reference/documentation-versions.json +22 -0
- package/docs/reference/environment.md +347 -0
- package/docs/reference/handler-authoring.md +264 -0
- package/docs/reference/project-config.md +582 -0
- package/docs/reference/project-config.schema.json +981 -0
- package/docs/reference/release-manifest.json +441 -0
- package/docs/reference/shell-completion.md +23 -0
- package/documentation-site.json +668 -0
- package/documentation-versions.json +22 -0
- package/examples/01-hello-json/.pulse/.gitignore +3 -0
- package/examples/01-hello-json/.pulse/config.ts +16 -0
- package/examples/01-hello-json/README.md +119 -0
- package/examples/01-hello-json/package.json +20 -0
- package/examples/01-hello-json/src/index.ts +9 -0
- package/examples/01-hello-json/tests/pulse.harness.ts +22 -0
- package/examples/01-hello-json/tsconfig.json +14 -0
- package/examples/02-request-schema/.pulse/.gitignore +3 -0
- package/examples/02-request-schema/.pulse/config.ts +17 -0
- package/examples/02-request-schema/README.md +145 -0
- package/examples/02-request-schema/package.json +20 -0
- package/examples/02-request-schema/src/index.ts +18 -0
- package/examples/02-request-schema/src/schemas.ts +20 -0
- package/examples/02-request-schema/tests/pulse.harness.ts +37 -0
- package/examples/02-request-schema/tsconfig.json +14 -0
- package/examples/03-fetch-composition/.pulse/.gitignore +3 -0
- package/examples/03-fetch-composition/.pulse/config.ts +31 -0
- package/examples/03-fetch-composition/README.md +210 -0
- package/examples/03-fetch-composition/package.json +20 -0
- package/examples/03-fetch-composition/src/index.ts +60 -0
- package/examples/03-fetch-composition/tests/pulse.harness.ts +47 -0
- package/examples/03-fetch-composition/tsconfig.json +14 -0
- package/examples/05-fastly-capabilities/.pulse/.gitignore +3 -0
- package/examples/05-fastly-capabilities/.pulse/config.ts +57 -0
- package/examples/05-fastly-capabilities/README.md +257 -0
- package/examples/05-fastly-capabilities/package.json +22 -0
- package/examples/05-fastly-capabilities/src/index.ts +55 -0
- package/examples/05-fastly-capabilities/tests/pulse.harness.ts +66 -0
- package/examples/05-fastly-capabilities/tsconfig.json +14 -0
- package/examples/07-opaque-proxy/.pulse/.gitignore +3 -0
- package/examples/07-opaque-proxy/.pulse/config.ts +38 -0
- package/examples/07-opaque-proxy/README.md +150 -0
- package/examples/07-opaque-proxy/package.json +21 -0
- package/examples/07-opaque-proxy/src/index.ts +9 -0
- package/examples/07-opaque-proxy/tests/pulse.harness.ts +25 -0
- package/examples/07-opaque-proxy/tsconfig.json +14 -0
- package/examples/09-router-lowering/.pulse/.gitignore +3 -0
- package/examples/09-router-lowering/.pulse/config.ts +22 -0
- package/examples/09-router-lowering/README.md +287 -0
- package/examples/09-router-lowering/package.json +22 -0
- package/examples/09-router-lowering/src/index.ts +65 -0
- package/examples/09-router-lowering/tests/pulse.harness.ts +91 -0
- package/examples/09-router-lowering/tsconfig.json +14 -0
- package/examples/10-entities-tools/.pulse/.gitignore +4 -0
- package/examples/10-entities-tools/.pulse/config.ts +23 -0
- package/examples/10-entities-tools/README.md +165 -0
- package/examples/10-entities-tools/package.json +21 -0
- package/examples/10-entities-tools/src/handlers.ts +15 -0
- package/examples/10-entities-tools/src/index.ts +31 -0
- package/examples/10-entities-tools/src/schemas.ts +18 -0
- package/examples/10-entities-tools/tests/pulse.harness.ts +40 -0
- package/examples/10-entities-tools/tools-facade.cjs +158 -0
- package/examples/10-entities-tools/tsconfig.json +14 -0
- package/examples/11-events/.pulse/.gitignore +4 -0
- package/examples/11-events/.pulse/config.ts +24 -0
- package/examples/11-events/README.md +194 -0
- package/examples/11-events/package.json +20 -0
- package/examples/11-events/src/index.ts +27 -0
- package/examples/11-events/src/schemas.ts +19 -0
- package/examples/11-events/tests/pulse.harness.ts +34 -0
- package/examples/11-events/tsconfig.json +15 -0
- package/examples/12-mcp-proxy/.pulse/.gitignore +3 -0
- package/examples/12-mcp-proxy/.pulse/config.ts +25 -0
- package/examples/12-mcp-proxy/README.md +149 -0
- package/examples/12-mcp-proxy/package.json +20 -0
- package/examples/12-mcp-proxy/src/index.ts +17 -0
- package/examples/12-mcp-proxy/tests/pulse.harness.ts +29 -0
- package/examples/12-mcp-proxy/tsconfig.json +14 -0
- package/examples/13-jwt-es256/.pulse/config.ts +19 -0
- package/examples/13-jwt-es256/README.md +195 -0
- package/examples/13-jwt-es256/package.json +21 -0
- package/examples/13-jwt-es256/src/index.ts +21 -0
- package/examples/13-jwt-es256/tests/pulse.harness.ts +54 -0
- package/examples/13-jwt-es256/tsconfig.json +14 -0
- package/examples/README.md +36 -0
- package/package.json +66 -6
- package/project-config.schema.json +981 -0
- package/release-manifest.json +441 -0
- package/src/command-spec.js +279 -0
- package/src/completion.js +113 -0
- package/src/diagnostics.js +350 -0
- package/src/documentation.js +45 -0
- package/src/index.d.ts +133 -0
- package/src/index.js +15 -0
- package/src/internal/command-executor.d.ts +29 -0
- package/src/internal/command-executor.js +143 -0
- package/src/internal/command-plan.d.ts +9 -0
- package/src/internal/command-plan.js +73 -0
- package/src/internal/command-reporter.d.ts +15 -0
- package/src/internal/command-reporter.js +133 -0
- package/src/internal/command-request.d.ts +35 -0
- package/src/internal/command-request.js +154 -0
- package/src/internal/node-http.js +54 -0
- package/src/internal/project-context.d.ts +66 -0
- package/src/internal/project-context.js +175 -0
- package/src/project-config-reference.js +4 -0
- package/src/project-config-schema.d.ts +23 -0
- package/src/project-config-schema.js +271 -0
- package/src/project-config.js +724 -0
- package/src/project-execution.js +2946 -0
- package/src/provider-drivers.js +3 -0
- package/src/target-support.js +3 -0
- package/src/typescript-module-loader.js +269 -0
- package/src/workflow.js +78 -0
- package/src/workspace.js +82 -0
package/API.md
ADDED
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
# Pulse runtime contract
|
|
2
|
+
|
|
3
|
+
For source eligibility, use [Managed handler TypeScript and
|
|
4
|
+
JavaScript](./docs/reference/handler-authoring.md). For provider and target
|
|
5
|
+
differences, use the [compatibility
|
|
6
|
+
matrix](./docs/reference/compatibility-matrix.md). For CLI and runtime failures,
|
|
7
|
+
use the stable codes in the [diagnostics
|
|
8
|
+
reference](./docs/reference/diagnostics.md).
|
|
9
|
+
|
|
10
|
+
This document describes the provider-neutral TypeScript application contract compiled by Pulse. Low-level authoring types and the static `Router` come from `@pulse-compute/runtime`. The public `@pulse-compute/pulse` package owns the conventional `Pulse` application root, deferred project configuration, and schema declarations, while `@pulse-compute/cli` owns workspace orchestration.
|
|
11
|
+
|
|
12
|
+
`@pulse-compute/runtime` is the low-level portable application surface and
|
|
13
|
+
`@pulse-compute/pulse` is the conventional project surface. Both belong to the
|
|
14
|
+
14-package public release catalog. Native and JavaScript execution remain
|
|
15
|
+
explicitly selected targets over the same canonical runtime contract.
|
|
16
|
+
|
|
17
|
+
## Context at a glance
|
|
18
|
+
|
|
19
|
+
`ctx` is the complete application authority. There is no ambient request,
|
|
20
|
+
process, provider SDK, or global network surface behind it.
|
|
21
|
+
|
|
22
|
+
| Surface | Available in | Purpose |
|
|
23
|
+
|---|---|---|
|
|
24
|
+
| [`ctx.req`](#ctxreq) | HTTP handlers and middleware | Method, URL, path, ordered headers, and bounded body reads. |
|
|
25
|
+
| [`ctx.req.header(name)`](#request-metadata-and-headers) | HTTP handlers and middleware | Case-insensitive first-value header lookup. |
|
|
26
|
+
| [`ctx.param(name)`](#ctxparam) | Matched route handlers | Named parameters from the static route pattern. |
|
|
27
|
+
| [`ctx.state`](#ctxstate) | HTTP and event handlers | Invocation-local string state shared across one execution. |
|
|
28
|
+
| [`ctx.fetch`](#ctxfetch) | HTTP and event handlers | Explicit outbound HTTP effect and structured or opaque response ownership. |
|
|
29
|
+
| [`ctx.parallel`](#ctxparallel) | HTTP and event handlers | Statically keyed concurrent Pulse effects. |
|
|
30
|
+
| [`ctx.emit`](#ctxemit) | HTTP and event handlers | One-way, schema-bound event acceptance effect. |
|
|
31
|
+
| [`ctx.log`](#ctxlog) | HTTP and event handlers | Synchronous thresholded logging. |
|
|
32
|
+
| [`ctx.config`, `ctx.secret`](#config-and-secrets) | HTTP and event handlers | Explicit configured binding reads. |
|
|
33
|
+
| [`ctx.kv(name)`](#kv) | HTTP and event handlers | Bound reads, writes, and conditional KV effects (Node reference). |
|
|
34
|
+
| [`ctx.json`, `ctx.text`, `ctx.response`](#response-builders) | HTTP handlers and middleware | Synchronous response construction. |
|
|
35
|
+
| `ctx.event` | Event handlers only | Exact event type and immutable validated payload. |
|
|
36
|
+
|
|
37
|
+
## Handler
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import type { Handler, PulseContext } from '@pulse-compute/runtime'
|
|
41
|
+
|
|
42
|
+
const handler: Handler = async (ctx: PulseContext) => ctx.json({ ok: true })
|
|
43
|
+
export default handler
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Every managed handler is async-shaped:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
type Handler = (ctx: PulseContext) => Promise<PulseResult | PulseFetchResponse>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
For native targets the compiler erases the async wrapper. Awaited Pulse effects lower into the existing explicit effect and continuation state machine; no Promise runtime or Asyncify transform is linked. Awaiting a proven synchronous `ctx` expression is redundant and may warn, while arbitrary non-Pulse awaits mark the native eligibility boundary. The canonical [handler authoring reference](./docs/reference/handler-authoring.md) defines the static language subset; the [compatibility matrix](./docs/reference/compatibility-matrix.md) owns the tested four-mode claims.
|
|
53
|
+
|
|
54
|
+
## Static `Router`
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import { Router } from '@pulse-compute/runtime'
|
|
58
|
+
|
|
59
|
+
const api = new Router()
|
|
60
|
+
const app = new Router()
|
|
61
|
+
|
|
62
|
+
api.use(async (ctx, next) => {
|
|
63
|
+
if (ctx.req.header('authorization') === undefined) {
|
|
64
|
+
return ctx.text('Unauthorized', { status: 401 })
|
|
65
|
+
}
|
|
66
|
+
return next()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
api.get('/health', async (ctx) => ctx.json({ ok: true }))
|
|
70
|
+
api.get('/users/:id', async (ctx, next) => {
|
|
71
|
+
if (ctx.param('id') === '0') return next()
|
|
72
|
+
return ctx.json({ id: ctx.param('id') })
|
|
73
|
+
})
|
|
74
|
+
api.get('/users/:id', async (ctx) => ctx.json({ fallback: ctx.param('id') }))
|
|
75
|
+
|
|
76
|
+
api.error(async (error, ctx, next) => {
|
|
77
|
+
const routedError = error as { code?: string }
|
|
78
|
+
if (routedError.code === 'NOT_FOUND') return ctx.text('Missing', { status: 404 })
|
|
79
|
+
return next(error)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
app.mount('/api', api)
|
|
83
|
+
export default app
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`Router` is a compile-time marker. Canonical v2 supports `get`, `head`, `post`, `put`, `patch`, `delete`, exact paths, named parameters, a trailing wildcard, static mounts, global/path-scoped/mounted middleware, route fallthrough, and error middleware. `Pulse` inherits these registrations. `ctx.param(name)` returns the matched named parameter inside route handlers.
|
|
87
|
+
|
|
88
|
+
`next()` is a terminal control transfer. `return next()` advances the normal Router cursor and permanently ends the current handler scope. `return next(error)` enters or advances the error lane. There is no onion-style downstream return or post-`next()` resume. Normal and error exhaustion produce compiler-owned 404 and 500 responses respectively.
|
|
89
|
+
|
|
90
|
+
The flattened execution graph, route table, and entry-owned effects/continuations are reported by `pulse inspect`. See the [routing guide](./docs/guides/routing.md).
|
|
91
|
+
|
|
92
|
+
## Static event handlers
|
|
93
|
+
|
|
94
|
+
`Pulse.on` declares an exact event entry beside, not inside, Router topology:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import { Pulse } from '@pulse-compute/pulse'
|
|
98
|
+
|
|
99
|
+
const app = new Pulse({ auto: true })
|
|
100
|
+
|
|
101
|
+
app.on('device.reading', { schema: 'events.DeviceReading' }, async (ctx) => {
|
|
102
|
+
const mode = await ctx.config.get('MODE')
|
|
103
|
+
ctx.state.set('mode', mode)
|
|
104
|
+
void ctx.event.payload
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
app.on('system.tick', { schema: null }, async (ctx) => {
|
|
108
|
+
void ctx.event.type
|
|
109
|
+
})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The type and schema are literal compiler inputs, every type has one owner, and
|
|
113
|
+
non-null schemas resolve through the project registry. `ctx.event.type` is the
|
|
114
|
+
exact registered type; `ctx.event.payload` is an immutable schema-validated
|
|
115
|
+
value, or `null` for a no-payload registration. Event handlers share state,
|
|
116
|
+
logging, fetch, config, secret, KV, and keyed-parallel authority, but expose no
|
|
117
|
+
request, route, response, middleware, or Router-transfer surface and complete
|
|
118
|
+
with `void`.
|
|
119
|
+
|
|
120
|
+
Eligible handlers lower into plane-neutral application entries and execute
|
|
121
|
+
through the conditional provider-neutral `pulse.native-event-abi.v1`
|
|
122
|
+
extension. Event-only and mixed HTTP/event artifacts are supported, while
|
|
123
|
+
HTTP-only Native output remains byte-identical and has no event ABI. This does
|
|
124
|
+
not by itself activate a provider transport. The Node provider now has an
|
|
125
|
+
invocation-scoped bounded FIFO reference ingress/acceptance adapter for direct
|
|
126
|
+
JavaScript and Native parity evidence; it is not a public event bus or a
|
|
127
|
+
deployment listener.
|
|
128
|
+
|
|
129
|
+
Conventional project harnesses can exercise this reference boundary with an
|
|
130
|
+
explicit `kind: 'event'` case, a canonical input frame, and an ordered exact
|
|
131
|
+
`expect.emitted` frame list. Node JavaScript and Node Native support that test
|
|
132
|
+
workflow. `pulse inspect` and `pulse doctor` report the event catalog,
|
|
133
|
+
registrations, schemas, outbound callsites, host requirements, and selected
|
|
134
|
+
target support; eligible build and compile output includes `event-catalog.json`
|
|
135
|
+
and `event-inspection.json`. Compile-only `none` reports inspection-only
|
|
136
|
+
eligibility. Fastly targets fail closed because no event ingress/emit adapter is
|
|
137
|
+
claimed. There is no public event injection command, no event-aware development
|
|
138
|
+
listener, no HTTP/GRIP translation, and no automatic target fallback.
|
|
139
|
+
|
|
140
|
+
The [static events guide](./docs/guides/events.md) owns the complete frame,
|
|
141
|
+
queue, target-eligibility, diagnostic, and Native-extension contract. The
|
|
142
|
+
source-bound [event example](./examples/11-events/) runs the same mixed project
|
|
143
|
+
on Node JavaScript and Node Native.
|
|
144
|
+
|
|
145
|
+
## `ctx.req`
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
interface PulseRequest {
|
|
149
|
+
readonly method: string
|
|
150
|
+
readonly url: string
|
|
151
|
+
readonly path: string
|
|
152
|
+
readonly headers: readonly [string, string][]
|
|
153
|
+
header(name: string): string | undefined
|
|
154
|
+
text(): PulseEffect<string>
|
|
155
|
+
json<T = unknown>(schemaId?: string): PulseEffect<T>
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Structured request bodies are bounded runtime-owned snapshots. Repeated `text()` and `json()` reads are memoized immutable transforms.
|
|
160
|
+
|
|
161
|
+
### Request metadata and headers
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
const requestId = ctx.req.header('x-request-id')
|
|
165
|
+
const authorization = ctx.req.header('Authorization')
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`header(name)` compares names case-insensitively, returns the first matching
|
|
169
|
+
value, and returns `undefined` when the header is absent. Use
|
|
170
|
+
`ctx.req.headers` when order or repeated fields matter: it is an immutable,
|
|
171
|
+
ordered array of `[name, value]` pairs and preserves repeated pairs. Pulse does
|
|
172
|
+
not expose an ambient `Request` or mutable `Headers` object to application
|
|
173
|
+
code.
|
|
174
|
+
|
|
175
|
+
`method` is normalized to uppercase, `url` is the complete request URL, and
|
|
176
|
+
`path` is its pathname.
|
|
177
|
+
|
|
178
|
+
When a schema ID is supplied, it must be a literal declared by the selected `.pulse/config.ts` profile:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
const input = await ctx.req.json<Input>('app.Input')
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## `ctx.param`
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
app.get('/users/:id', async (ctx) => {
|
|
188
|
+
const id = ctx.param('id')
|
|
189
|
+
return id === undefined
|
|
190
|
+
? ctx.text('missing route parameter', { status: 500 })
|
|
191
|
+
: ctx.json({ id })
|
|
192
|
+
})
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`ctx.param(name)` is synchronous and is available only to a matched route
|
|
196
|
+
handler. It returns the decoded value owned by the static route match or
|
|
197
|
+
`undefined` when the named parameter is not present. Middleware and event
|
|
198
|
+
handlers do not receive route-parameter authority.
|
|
199
|
+
|
|
200
|
+
## `ctx.state`
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
ctx.state.set('request-id', 'r1')
|
|
204
|
+
const requestId = ctx.state.get('request-id') // string | undefined
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
State is a synchronous, invocation-local string map. One HTTP execution shares
|
|
208
|
+
it across forward middleware, mounted Routers, error recovery, and effect
|
|
209
|
+
continuation resume. An event handler retains its state across continuation
|
|
210
|
+
resume. State is isolated between requests and event invocations; it is not
|
|
211
|
+
durable storage and does not cross an invocation boundary.
|
|
212
|
+
|
|
213
|
+
## `ctx.fetch`
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
interface PulseFetchInit {
|
|
217
|
+
readonly method?: 'GET' | 'HEAD' | 'POST'
|
|
218
|
+
readonly headers?: Readonly<Record<string, string>> | readonly [string, string][]
|
|
219
|
+
readonly body?: string
|
|
220
|
+
readonly json?: unknown
|
|
221
|
+
readonly timeoutMs?: number
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
ctx.fetch(url: string, init?: PulseFetchInit): PulseFetchOperation
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
HTTP status is response data. Network and timeout failures are runtime failures.
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
const user = await ctx.fetch('https://api.example.test/user').json<User>('app.User')
|
|
231
|
+
return ctx.json({ found: true, user })
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Consecutive independent fetches may lower into a deterministic effect group. Results are presented in declaration order, not host completion order.
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
## `ctx.parallel`
|
|
238
|
+
|
|
239
|
+
Use `ctx.parallel({ ... })` to make concurrent Pulse effects an explicit,
|
|
240
|
+
key-preserving cross-target contract:
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
const { user, permissions } = await ctx.parallel({
|
|
244
|
+
user: ctx.fetch('https://api.example.test/user').json<User>(),
|
|
245
|
+
permissions: ctx.fetch('https://api.example.test/permissions').json<Permissions>(),
|
|
246
|
+
})
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Its TypeScript result preserves every input key and the independently inferred
|
|
250
|
+
result type of that effect. The initial portable form accepts exactly one nonempty
|
|
251
|
+
inline object literal with fixed identifier or string-literal keys and directly
|
|
252
|
+
recognizable Pulse effects as values. Array-index keys, `__proto__`, arrays,
|
|
253
|
+
spreads, computed keys, shorthand properties, methods, accessors, dynamic records,
|
|
254
|
+
arbitrary promises, reused effect roots, and nested parallel groups are rejected.
|
|
255
|
+
|
|
256
|
+
Source property order defines effect registration, deterministic identity, result
|
|
257
|
+
reconstruction, trace order, and primary-failure ownership. Operations may finish
|
|
258
|
+
in any order, but all settle before the continuation proceeds. When multiple
|
|
259
|
+
members fail, the first failure in property order is primary and bounded keyed
|
|
260
|
+
failure evidence identifies the others.
|
|
261
|
+
|
|
262
|
+
The JavaScript runtime executes every member through one execution-owned shared
|
|
263
|
+
effect adapter. Native lowering erases the call into one canonical effect group
|
|
264
|
+
and reconstructs an ordinary keyed object after one continuation. Separate awaits
|
|
265
|
+
remain sequential in direct JavaScript execution; the Native compiler may still
|
|
266
|
+
implicitly group adjacent eligible effects as a performance optimization.
|
|
267
|
+
|
|
268
|
+
## `ctx.emit`
|
|
269
|
+
|
|
270
|
+
HTTP and event handlers share a one-way outbound event effect:
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
await ctx.emit('device.led.set', {
|
|
274
|
+
schema: 'events.DeviceLedSet',
|
|
275
|
+
payload: { enabled: true },
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
await ctx.emit('system.tick', { schema: null })
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The event type and schema are literal compiler inputs. A non-null schema must
|
|
282
|
+
resolve through the project registry and requires `payload`; `schema: null`
|
|
283
|
+
forbids it. JavaScript and Native runtimes validate and detach the same
|
|
284
|
+
canonical frame before passing it to the execution-owned adapter. Public effect
|
|
285
|
+
evidence redacts the payload.
|
|
286
|
+
|
|
287
|
+
The effect is valid as a fresh member of an awaited `ctx.parallel` group and
|
|
288
|
+
resolves to `undefined` after bounded host acceptance. It does not return a
|
|
289
|
+
delivery receipt, correlation ID, or handler result, and it never invokes a
|
|
290
|
+
matching local event handler. Native lowering uses the ordinary canonical
|
|
291
|
+
effect/continuation protocol and adds no JavaScript or Asyncify imports. The
|
|
292
|
+
invocation-scoped Node reference adapter provides bounded host acceptance and
|
|
293
|
+
exact-frame evidence in JavaScript and Native modes; it provides no delivery,
|
|
294
|
+
retry, persistence, public event bus, or automatic loopback. Other provider
|
|
295
|
+
realizations remain unclaimed.
|
|
296
|
+
|
|
297
|
+
There is no `ctx.call`, `app.call`, generic call effect, request/reply bus, or
|
|
298
|
+
reserved compiler/runtime opcode for reflexive routing. `ctx.emit` cannot
|
|
299
|
+
observe or invoke a local handler. A future call mechanism requires a separate
|
|
300
|
+
host and lifecycle contract.
|
|
301
|
+
|
|
302
|
+
## `ctx.log`
|
|
303
|
+
|
|
304
|
+
Logging is synchronous, string-only, and provider-neutral:
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
ctx.log.error('failed to publish event')
|
|
308
|
+
ctx.log.warn('retrying origin request')
|
|
309
|
+
ctx.log.info('user created')
|
|
310
|
+
ctx.log.debug('decoded request body')
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
The fixed levels are `error = 1`, `warn = 2`, `info = 3`, and `debug = 4`.
|
|
314
|
+
`off = 0` is configuration-only. A statement emits when its level is less than
|
|
315
|
+
or equal to the selected profile’s resolved `reporting` level; the default is
|
|
316
|
+
`info`.
|
|
317
|
+
|
|
318
|
+
`ctx.log` is not an effect, continuation, or asynchronous operation. Native
|
|
319
|
+
lowering erases statements disabled by the resolved build threshold. JavaScript
|
|
320
|
+
targets filter at runtime, so a disabled JavaScript call may still evaluate its
|
|
321
|
+
message expression; application-significant side effects do not belong in log
|
|
322
|
+
expressions. Provider formatting and destination are intentionally outside the
|
|
323
|
+
portable contract.
|
|
324
|
+
|
|
325
|
+
Logging failures do not fail the request. Known request secrets pass through the
|
|
326
|
+
same redaction boundary before provider emission and evidence capture. The
|
|
327
|
+
initial contract accepts only strings; structured logging and dynamic level
|
|
328
|
+
registration are not supported.
|
|
329
|
+
|
|
330
|
+
## Fetch responses
|
|
331
|
+
|
|
332
|
+
Structured responses expose:
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
response.status
|
|
336
|
+
response.ok
|
|
337
|
+
response.headers
|
|
338
|
+
response.header(name)
|
|
339
|
+
response.text()
|
|
340
|
+
response.json<T>(schemaId?)
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
`response.header(name)` uses the same case-insensitive, first-value lookup as
|
|
344
|
+
`ctx.req.header(name)`. `response.headers` retains immutable ordered pairs when
|
|
345
|
+
repeated response fields must be observed. HTTP status is always response data;
|
|
346
|
+
only transport and timeout failures reject the fetch effect.
|
|
347
|
+
|
|
348
|
+
Opaque responses preserve a host-owned body handle and may be returned directly:
|
|
349
|
+
|
|
350
|
+
<!-- pulse-doc-source: examples/07-opaque-proxy/src/index.ts -->
|
|
351
|
+
```ts
|
|
352
|
+
import { Pulse } from '@pulse-compute/pulse'
|
|
353
|
+
|
|
354
|
+
const app = new Pulse({ auto: true })
|
|
355
|
+
|
|
356
|
+
app.get('/archive', async (ctx) => {
|
|
357
|
+
return ctx.fetch('https://assets.example.com/archive.bin')
|
|
358
|
+
})
|
|
359
|
+
|
|
360
|
+
export default app
|
|
361
|
+
```
|
|
362
|
+
<!-- /pulse-doc-source -->
|
|
363
|
+
|
|
364
|
+
Opaque bodies cannot be decoded, copied into Wasm, mutated, iterated, or transformed in user scope.
|
|
365
|
+
|
|
366
|
+
## Response builders
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
ctx.json(value, options?)
|
|
370
|
+
ctx.text(value, options?)
|
|
371
|
+
ctx.response({ status?, headers?, body? })
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
JSON responses may use an explicit output schema:
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
return ctx.json(output, {
|
|
378
|
+
status: 201,
|
|
379
|
+
headers: { 'x-schema': 'app.Output' },
|
|
380
|
+
schema: 'app.Output',
|
|
381
|
+
})
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## Config and secrets
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
ctx.config.get(name: string): PulseEffect<string | undefined>
|
|
388
|
+
ctx.secret.get(name: string): PulseEffect<string | undefined>
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Reads use exact, provider-injected names. Missing values resolve to `undefined`; Pulse does not enumerate bindings, consult inherited properties, or fall back to `process.env`. Names and returned strings are UTF-8 byte-bounded.
|
|
392
|
+
|
|
393
|
+
Resolved secret values are registered with the execution-owned redaction boundary. Pulse removes known secret substrings and sensitive fields from its own observations, traces, diagnostics, and managed errors. This is not taint tracking: application responses are never silently rewritten, and ordinary config values are not automatically treated as secrets.
|
|
394
|
+
|
|
395
|
+
## KV
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
const sessions = ctx.kv<Session>('sessions')
|
|
399
|
+
const value = await sessions.get('current')
|
|
400
|
+
if (value !== undefined) await sessions.put('last', value)
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
The existing `get` and `put` operations remain available. Store names and keys are
|
|
404
|
+
provider-neutral logical bindings. Values are bounded, detached, deeply frozen
|
|
405
|
+
JSON-compatible trees; accessors, symbols, sparse arrays, repeated references,
|
|
406
|
+
cycles, class instances, nonfinite numbers, and nested `undefined` are rejected.
|
|
407
|
+
`put` resolves to an explicit boolean acknowledgement. Durability, consistency,
|
|
408
|
+
and cross-request lifetime remain provider capabilities rather than properties
|
|
409
|
+
of the common API.
|
|
410
|
+
|
|
411
|
+
The Node reference on JavaScript and Native, and the Fastly Native adapter,
|
|
412
|
+
realize these operations through direct await or keyed `ctx.parallel`:
|
|
413
|
+
|
|
414
|
+
| Method | Result |
|
|
415
|
+
| --- | --- |
|
|
416
|
+
| `getVersioned(key)` | `found` with one observed `value` and opaque `generation`, `not-found`, or `failed` with a reason. |
|
|
417
|
+
| `insertIfAbsent(key, value)` | Atomically creates an absent key. |
|
|
418
|
+
| `compareAndSwap(key, generation, value)` | Atomically replaces the value only when its current generation matches. |
|
|
419
|
+
|
|
420
|
+
Conditional writes return `stored`, `conflict`, `not-stored` with a reason, or
|
|
421
|
+
`unknown` with a reason. `unknown` may have committed; Pulse never automatically
|
|
422
|
+
retries or rebases. A write acknowledgement carries no new generation. An absent
|
|
423
|
+
CAS conflicts. A read may be stale, but its value and token describe the same
|
|
424
|
+
observation. Tokens are bounded opaque strings, never JavaScript numbers or
|
|
425
|
+
application revision counters.
|
|
426
|
+
|
|
427
|
+
Namespaces must be literal bindings; keys, generations, and candidates are runtime
|
|
428
|
+
data. Candidates are snapshotted at admission. Keys are exact Unicode scalar
|
|
429
|
+
strings of 1–1,024 UTF-8 bytes without C0/C1 controls; tokens are 1–256 visible
|
|
430
|
+
ASCII bytes. Values retain the 65,536-byte JSON, depth-64 and 10,000-entry bounds.
|
|
431
|
+
The host owns the ten-second operation deadline, shortened by a request deadline.
|
|
432
|
+
Timeouts before dispatch are `not-stored`; unconfirmed writes after dispatch are
|
|
433
|
+
`unknown`. Request cancellation follows the existing managed lifecycle and
|
|
434
|
+
never implies rollback.
|
|
435
|
+
|
|
436
|
+
The Node realization is an explicit in-memory reference instance, not a durable
|
|
437
|
+
storage guarantee. Fastly Native uses lossless 64-bit generation metadata and
|
|
438
|
+
conditional host operations with bounded readiness and body acquisition. Deployed
|
|
439
|
+
cross-location acceptance remains a separate gate. The Fastly JavaScript SDK is
|
|
440
|
+
incomplete capability mapping and does not define or block
|
|
441
|
+
Pulse's contract. Conditional wire values use the strict
|
|
442
|
+
`{"__pulseKv":1,"value":...}` envelope; legacy raw JSON requires explicit migration.
|
|
443
|
+
|
|
444
|
+
## Explicit JSON schemas
|
|
445
|
+
|
|
446
|
+
<!-- pulse-doc-source: examples/02-request-schema/.pulse/config.ts -->
|
|
447
|
+
```ts
|
|
448
|
+
import { defineConfig } from '@pulse-compute/pulse'
|
|
449
|
+
|
|
450
|
+
export default defineConfig((_scope) => ({
|
|
451
|
+
pulse: {
|
|
452
|
+
entry: 'src/index.ts',
|
|
453
|
+
schema: 'src/schemas.ts',
|
|
454
|
+
tests: 'tests/pulse.harness.ts',
|
|
455
|
+
defaultProfile: 'local',
|
|
456
|
+
strict: true,
|
|
457
|
+
},
|
|
458
|
+
local: {
|
|
459
|
+
host: 'node',
|
|
460
|
+
target: 'native',
|
|
461
|
+
outDir: 'dist',
|
|
462
|
+
schemas: { contentTypePolicy: 'require-json', maxBytes: 1024 },
|
|
463
|
+
},
|
|
464
|
+
}))
|
|
465
|
+
```
|
|
466
|
+
<!-- /pulse-doc-source -->
|
|
467
|
+
|
|
468
|
+
Pulse compiles declared TypeScript interfaces and type aliases into a registry and direct codecs. It does not discover arbitrary types automatically.
|
|
469
|
+
|
|
470
|
+
## GRIP
|
|
471
|
+
|
|
472
|
+
The canonical GRIP application surface is the package root:
|
|
473
|
+
|
|
474
|
+
```ts
|
|
475
|
+
import { grip } from '@pulse-compute/grip'
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
Pure request classification and response framing use `grip.isWebSocket`,
|
|
479
|
+
`grip.subscribe`, and `grip.handoff`. Configured outbound work is the
|
|
480
|
+
request-bound `await grip.broadcast(ctx, message)` effect. Supported Native
|
|
481
|
+
forms lower into canonical package operations; JavaScript targets execute the
|
|
482
|
+
real package implementation.
|
|
483
|
+
|
|
484
|
+
Older `/pulsewasm` imports are compatibility-only and are isolated in the
|
|
485
|
+
[migration guide](./docs/guides/compatibility-imports.md). See the
|
|
486
|
+
[GRIP package guide](./docs/packages/grip.md) for the complete current surface.
|
|
487
|
+
|
|
488
|
+
## Entities API
|
|
489
|
+
|
|
490
|
+
`@pulse-compute/entities` is part of the synchronized `1.0.0-beta.2` package
|
|
491
|
+
set. The application surface has two runtime values:
|
|
492
|
+
|
|
493
|
+
```ts
|
|
494
|
+
import { EntityRouter, jsonRpc } from '@pulse-compute/entities'
|
|
495
|
+
|
|
496
|
+
const rpc = new EntityRouter({ adapter: jsonRpc({ namedParamsOnly: true }) })
|
|
497
|
+
|
|
498
|
+
rpc.on('customer.lookup', {
|
|
499
|
+
input: 'tools.CustomerLookupInput',
|
|
500
|
+
output: 'tools.CustomerLookupOutput',
|
|
501
|
+
}, lookupCustomer)
|
|
502
|
+
|
|
503
|
+
export default function handler(ctx: unknown) {
|
|
504
|
+
return rpc.handle(ctx as never)
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
```ts
|
|
509
|
+
interface EntityRouterOptions {
|
|
510
|
+
readonly adapter: JsonRpcAdapter
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
interface EntityDeclaration {
|
|
514
|
+
readonly input: string | null
|
|
515
|
+
readonly output: string | null
|
|
516
|
+
readonly metadata?: StaticEntityMetadata
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
type EntityHandler<Input, Output> = (
|
|
520
|
+
ctx: PulseContext,
|
|
521
|
+
input: DeepReadonly<Input>,
|
|
522
|
+
) => Output | Promise<Output>
|
|
523
|
+
|
|
524
|
+
class EntityRouter {
|
|
525
|
+
constructor(options: EntityRouterOptions)
|
|
526
|
+
on<Input, Output>(
|
|
527
|
+
discriminator: string,
|
|
528
|
+
declaration: EntityDeclaration,
|
|
529
|
+
handler: EntityHandler<Input, Output>,
|
|
530
|
+
): this
|
|
531
|
+
handle(ctx: PulseContext): Promise<Response>
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
interface JsonRpcOptions {
|
|
535
|
+
readonly namedParamsOnly?: true
|
|
536
|
+
readonly acceptEmptyObjectForNoInput?: boolean
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function jsonRpc(options?: JsonRpcOptions): JsonRpcAdapter
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
`StaticJsonPrimitive`, `StaticJsonValue`, `StaticJsonObject`,
|
|
543
|
+
`StaticEntityMetadata`, `EntitySchemaId`, `DeepReadonly`,
|
|
544
|
+
`EntityHandlerResult`, `EntityAdapter`, and `JsonRpcAdapter` are also exported
|
|
545
|
+
as types. The package exposes no public runtime registry, schema codecs, raw
|
|
546
|
+
JSON access, provider objects, or third-party adapter registration.
|
|
547
|
+
|
|
548
|
+
Registrations and the terminal binding must use the supported static form. The
|
|
549
|
+
first-party JSON-RPC adapter accepts bounded JSON-RPC 2.0 request objects and
|
|
550
|
+
named params, validates declared schemas, uses stable error framing, and
|
|
551
|
+
acknowledges notifications with HTTP `204`. See the [package
|
|
552
|
+
guide](./docs/packages/entities.md), [entity/adapter
|
|
553
|
+
model](./docs/concepts/entities-and-adapters.md), and [executable
|
|
554
|
+
example](./examples/10-entities-tools/).
|
|
555
|
+
|
|
556
|
+
## Project workflow
|
|
557
|
+
|
|
558
|
+
```text
|
|
559
|
+
pulse init
|
|
560
|
+
pulse doctor
|
|
561
|
+
pulse test
|
|
562
|
+
pulse dev
|
|
563
|
+
pulse build
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
These normal lifecycle commands resolve the same authoritative workspace,
|
|
567
|
+
selected profile, handler entry, schema declarations, provider bindings, and
|
|
568
|
+
output directory through `.pulse/config.ts`. `pulse inspect` is optional
|
|
569
|
+
observability, and `pulse compile` is the advanced provider-neutral Native
|
|
570
|
+
artifact command; neither is required before `pulse build`. See the [project
|
|
571
|
+
lifecycle guide](./docs/guides/project-lifecycle.md) and [CLI
|
|
572
|
+
reference](./docs/reference/cli.md).
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Pulse follows semantic versioning for public releases. The repository begins its public history with the `1.0.0-beta.1` prerelease.
|
|
4
|
+
|
|
5
|
+
## 1.0.0-beta.2 — Beta (2026-09-13)
|
|
6
|
+
|
|
7
|
+
This candidate synchronizes the 19-package release catalog and prepares the
|
|
8
|
+
next npm `beta` release:
|
|
9
|
+
|
|
10
|
+
- adds bounded S3-compatible object storage in `@pulse-compute/s3`, backed by
|
|
11
|
+
the Crypto hashing and signing primitives; the Assets contract stays intact;
|
|
12
|
+
- adds conditional KV operations and opaque generation tokens, with explicit
|
|
13
|
+
conflict handling and no non-atomic emulation;
|
|
14
|
+
- propagates explicit JavaScript targets through project analysis, retaining
|
|
15
|
+
resolved static third-party imports and ordinary awaited calls while
|
|
16
|
+
checking Native eligibility independently;
|
|
17
|
+
- clarifies maintainer ownership, target boundaries, evidence requirements,
|
|
18
|
+
and human release authority;
|
|
19
|
+
- links public and internal package listings to npm and preserves the exact
|
|
20
|
+
published beta.1 documentation snapshot alongside the beta.2 documentation.
|
|
21
|
+
|
|
22
|
+
Conditional KV acceptance remains gated separately from the aggregate seal:
|
|
23
|
+
Viceroy 0.21.0 creates a missing key for an existing-generation CAS, contrary to
|
|
24
|
+
the required conflict behavior, and deployed Pulse cross-location acceptance
|
|
25
|
+
is still pending. The standalone live Fastly probe confirms missing-key
|
|
26
|
+
rejection but does not satisfy those Pulse acceptance gates. See
|
|
27
|
+
[`wasm/test/kv/K4.md`](https://github.com/pulse-compute/pulse/blob/16444cc5e116498e1fdf5f1e4815b4b8c3c74349/wasm/test/kv/K4.md) for the evidence and release boundary.
|
|
28
|
+
|
|
29
|
+
## 1.0.0-beta.1 — Beta (2026-08-01)
|
|
30
|
+
|
|
31
|
+
The first public Beta establishes a native-first Pulse application contract
|
|
32
|
+
and completes the synchronized release candidate:
|
|
33
|
+
|
|
34
|
+
- promotes `@pulse-compute/pulse` into the synchronized public package set and
|
|
35
|
+
removes its duplicate Fastly-conditioned bootstrap so provider-specific
|
|
36
|
+
startup remains owned by `@pulse-compute/provider-fastly`.
|
|
37
|
+
- adds `--experimental-native-size` to provider-neutral compile and Native
|
|
38
|
+
provider builds. The Native compiler owns the experimental size profile and
|
|
39
|
+
the default remains unchanged.
|
|
40
|
+
- moves the fixed provider composition behind a neutral CLI facade. Concrete
|
|
41
|
+
host operations and target policy are now composed from provider-owned
|
|
42
|
+
modules, while Node remains the reference/smoke substrate.
|
|
43
|
+
- adds synchronous string logging through `ctx.log.error`, `warn`, `info`, and
|
|
44
|
+
`debug`, including profile thresholds, Native pruning, a compact host ABI,
|
|
45
|
+
provider-owned output, redaction, and four-mode conformance.
|
|
46
|
+
- completes direct Fastly JavaScript execution, provider capabilities, package
|
|
47
|
+
effects, local tooling, deterministic source/deployment packaging, and
|
|
48
|
+
downstream runtime compilation.
|
|
49
|
+
- seals full-target-support availability for Node and Fastly JavaScript without
|
|
50
|
+
automatic fallback.
|
|
51
|
+
- adds revision-bound release reports, sixteen-shard evidence aggregation,
|
|
52
|
+
offline Fastly Native/JavaScript candidates, and exact binary-patch replay.
|
|
53
|
+
- adds the bounded Crypto, JWT, and Entities packages to the synchronized
|
|
54
|
+
18-package release catalog;
|
|
55
|
+
- synchronizes the Apache-2.0 package metadata, Beta documentation,
|
|
56
|
+
exact `v1.0.0-beta.1` routes, and npm `beta` policy without assigning `latest`;
|
|
57
|
+
- performs no deployment or publication; those operations remain separately
|
|
58
|
+
authorized release actions.
|
|
59
|
+
|
|
60
|
+
- `@pulse-compute/runtime` as the canonical application surface;
|
|
61
|
+
- static Router authoring with parameters, mounts, terminal middleware, fallthrough, and error lanes;
|
|
62
|
+
- whole-project analysis with explicit effects and continuations;
|
|
63
|
+
- schema-backed request, fetch, and response handling;
|
|
64
|
+
- provider-neutral portable Wasm and direct native Fastly realization;
|
|
65
|
+
- Node development, inspection, testing, and provider conformance;
|
|
66
|
+
- package-owned GRIP and asset lowering;
|
|
67
|
+
- generated, versioned documentation and guarded release candidates;
|
|
68
|
+
- explicit runtime-target support gates with no automatic fallback.
|
|
69
|
+
|
|
70
|
+
The Beta deliberately rejects unsupported Native source instead of
|
|
71
|
+
silently changing execution targets.
|