@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
|
@@ -0,0 +1,315 @@
|
|
|
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
|
+
# Add a provider toolchain
|
|
9
|
+
|
|
10
|
+
> **Current boundary:** Provider selection is explicit, not discovered. A bare
|
|
11
|
+
> host ID such as `node`, `fastly`, or `esp32` resolves to
|
|
12
|
+
> `@pulse-compute/provider-<id>`, `none` remains internal, and a scoped package
|
|
13
|
+
> name is loaded exactly from the project. The selected package must export the
|
|
14
|
+
> versioned `./toolchain` contract.
|
|
15
|
+
> No dependency scanning, package-keyword registration, or target fallback
|
|
16
|
+
> occurs.
|
|
17
|
+
|
|
18
|
+
A core provider realizes canonical compiler operations without changing the application handler API. It normally owns a capability descriptor, a local conformance runtime, binding normalization, and—when deployable—a target builder and toolchain boundary.
|
|
19
|
+
|
|
20
|
+
This is separate from package-root lowering. A provider implements canonical
|
|
21
|
+
capabilities and target realization; a Pulse-aware package may contribute a
|
|
22
|
+
bounded first-party package effect. See [Pulse-aware package
|
|
23
|
+
authoring](./pulse-aware-packages.md) before choosing either boundary.
|
|
24
|
+
|
|
25
|
+
## Provider invariants
|
|
26
|
+
|
|
27
|
+
Every provider must preserve:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"providerSpecificUserland": false,
|
|
32
|
+
"providerSdkUserland": false,
|
|
33
|
+
"capabilityDiscoveryFromUserland": false
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Canonical source imports `@pulse-compute/runtime` and supported package facades. Provider SDK objects, request types, storage clients, and deployment resources do not enter handler scope.
|
|
38
|
+
|
|
39
|
+
## Integration map
|
|
40
|
+
|
|
41
|
+
| Concern | Current owner/location |
|
|
42
|
+
|---|---|
|
|
43
|
+
| Capability vocabulary and provider plan | `wasm/packages/contracts/src/provider/canonical-provider.js` |
|
|
44
|
+
| Node descriptor/runtime | `packages/provider-node/src/runtime/canonical-api-runtime.js` |
|
|
45
|
+
| Fastly descriptor | `packages/provider-fastly/src/provider-contract.js` |
|
|
46
|
+
| Fastly local runtime | `packages/provider-fastly/src/runtime/canonical-api-runtime.js` |
|
|
47
|
+
| Fastly target writer/toolchain | `packages/provider-fastly/src/build/` |
|
|
48
|
+
| Deterministic package bootstrap | `wasm/packages/compiler/src/provider-toolchain.js` |
|
|
49
|
+
| Versioned bootstrap contract | `wasm/packages/contracts/src/provider/toolchain.js` |
|
|
50
|
+
| Provider driver and config normalization | Provider-owned `./toolchain` export |
|
|
51
|
+
| Command execution | `wasm/packages/cli/src/project-execution.js` |
|
|
52
|
+
| Public config reference | Provider-owned reference contribution, aggregated by `wasm/packages/cli/src/project-config-schema.js` |
|
|
53
|
+
| Package policy | `release/pulse-release-manifest.json` |
|
|
54
|
+
|
|
55
|
+
## 1. Define provider identity and scope
|
|
56
|
+
|
|
57
|
+
Choose:
|
|
58
|
+
|
|
59
|
+
- stable provider ID;
|
|
60
|
+
- package owner and version;
|
|
61
|
+
- runtime identity;
|
|
62
|
+
- build target identity;
|
|
63
|
+
- whether it supports local execution;
|
|
64
|
+
- whether it emits a deployable target;
|
|
65
|
+
- its exact canonical capabilities;
|
|
66
|
+
- required resource bindings;
|
|
67
|
+
- toolchain and external CLI dependencies.
|
|
68
|
+
|
|
69
|
+
Do not claim a capability because a provider SDK happens to contain something similar. The provider must implement the canonical semantics and failure behavior.
|
|
70
|
+
|
|
71
|
+
## 2. Build a canonical provider descriptor
|
|
72
|
+
|
|
73
|
+
Descriptors are normalized by the shared provider contract. A conceptual descriptor looks like:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
const EXAMPLE_PROVIDER_DESCRIPTOR = createProviderDescriptor({
|
|
77
|
+
id: 'example',
|
|
78
|
+
providerVersion: '1.0.0-beta.2',
|
|
79
|
+
package: '@pulse-compute/provider-example',
|
|
80
|
+
runtime: 'pulse.canonical-example-runtime.v1',
|
|
81
|
+
buildTarget: 'example-edge',
|
|
82
|
+
deployable: true,
|
|
83
|
+
localExecution: true,
|
|
84
|
+
capabilities: [
|
|
85
|
+
'request.method',
|
|
86
|
+
'request.path',
|
|
87
|
+
'response.json',
|
|
88
|
+
'response.text',
|
|
89
|
+
'fetch',
|
|
90
|
+
],
|
|
91
|
+
lowering: {
|
|
92
|
+
'request.method': 'example.request.method',
|
|
93
|
+
'request.path': 'example.request.path',
|
|
94
|
+
'response.json': 'example.response.json',
|
|
95
|
+
'response.text': 'example.response.text',
|
|
96
|
+
fetch: 'example.fetch.dispatch',
|
|
97
|
+
},
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The shared contract verifies that every declared capability has a lowering and that every compiled requirement is supported.
|
|
102
|
+
|
|
103
|
+
When a package-owned operation requires an additional result capability—such as opaque pass-through—the descriptor must implement both the operation and result capability.
|
|
104
|
+
|
|
105
|
+
## 3. Normalize bindings separately from source
|
|
106
|
+
|
|
107
|
+
Canonical effects refer to logical resources: an origin URL, KV namespace, config store, secret store, or package resource. Provider configuration maps those to deployment bindings.
|
|
108
|
+
|
|
109
|
+
A binding normalizer should:
|
|
110
|
+
|
|
111
|
+
- accept only documented project fields;
|
|
112
|
+
- produce deterministic normalized values;
|
|
113
|
+
- reject duplicate, invalid, or missing mappings;
|
|
114
|
+
- keep raw secret values out of the plan;
|
|
115
|
+
- make dynamic-resource behavior explicit;
|
|
116
|
+
- distinguish local fixture values from deployment resource names.
|
|
117
|
+
|
|
118
|
+
Do not discover bindings by scanning provider-specific imports in handler source.
|
|
119
|
+
|
|
120
|
+
## 4. Implement the local conformance runtime
|
|
121
|
+
|
|
122
|
+
The local runtime executes canonical programs for `pulse test` and `pulse dev`. It should use shared host-runtime primitives where possible and implement each descriptor capability with normalized results.
|
|
123
|
+
|
|
124
|
+
Required behavior includes:
|
|
125
|
+
|
|
126
|
+
- bounded request-body access;
|
|
127
|
+
- deterministic response construction;
|
|
128
|
+
- effect dispatch and continuation resumption;
|
|
129
|
+
- timeout and failure normalization;
|
|
130
|
+
- config/secret/KV fixture isolation;
|
|
131
|
+
- structured versus opaque body rules;
|
|
132
|
+
- request completion and cleanup;
|
|
133
|
+
- secret redaction.
|
|
134
|
+
|
|
135
|
+
Local behavior should match canonical semantics, not emulate every incidental detail of a provider SDK.
|
|
136
|
+
|
|
137
|
+
## 5. Implement target generation when deployable
|
|
138
|
+
|
|
139
|
+
A deployable provider needs a target writer that consumes:
|
|
140
|
+
|
|
141
|
+
- the canonical program;
|
|
142
|
+
- provider lowering plan;
|
|
143
|
+
- normalized bindings;
|
|
144
|
+
- schema bundle and package effects;
|
|
145
|
+
- project metadata;
|
|
146
|
+
- output-safety options.
|
|
147
|
+
|
|
148
|
+
It should emit a deterministic source package and validate the final artifact. For Wasm targets, verify at least the expected file, magic/version bytes, and compiler result metadata.
|
|
149
|
+
|
|
150
|
+
Keep external toolchain discovery in a narrow adapter. Return stable diagnostics for unavailable binaries, version mismatch, timeout, compile failure, or invalid output.
|
|
151
|
+
|
|
152
|
+
## 6. Export the formal toolchain
|
|
153
|
+
|
|
154
|
+
The provider package exports `./toolchain`. Its module declares package
|
|
155
|
+
identity and creates the provider-owned driver:
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
module.exports = defineProviderToolchain({
|
|
159
|
+
version: 'pulse.provider-toolchain.v1',
|
|
160
|
+
id: 'example',
|
|
161
|
+
packageName: '@example/pulse-provider',
|
|
162
|
+
packageVersion: require('../package.json').version,
|
|
163
|
+
createDriver() {
|
|
164
|
+
return defineProviderDriver({
|
|
165
|
+
version: 'pulse.provider-driver.v1',
|
|
166
|
+
id: 'example',
|
|
167
|
+
descriptor: EXAMPLE_PROVIDER_DESCRIPTOR,
|
|
168
|
+
executable: true,
|
|
169
|
+
localExecution: true,
|
|
170
|
+
deployable: true,
|
|
171
|
+
normalizeConfig,
|
|
172
|
+
projectConfigDocument,
|
|
173
|
+
initTemplate,
|
|
174
|
+
targets,
|
|
175
|
+
execute: executeCanonicalProgram,
|
|
176
|
+
createLoweringPlan,
|
|
177
|
+
writeTarget,
|
|
178
|
+
})
|
|
179
|
+
},
|
|
180
|
+
})
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`createDriver()` receives no compiler service or caller option bag. Use the
|
|
184
|
+
shared provider contract helpers for the exact planning input, target
|
|
185
|
+
invocation, Native artifact, JavaScript package result, and provider target
|
|
186
|
+
result shapes. A supported Native descriptor must include a valid
|
|
187
|
+
`finalWasmPolicy`, and every command advertised by a target must have the
|
|
188
|
+
required callable surface on the driver.
|
|
189
|
+
|
|
190
|
+
`createLoweringPlan` consumes the versioned provider-plan projection rather
|
|
191
|
+
than compiler metadata. `writeTarget` and `inspectRealization` consume the
|
|
192
|
+
versioned target invocation rather than `{ compiled, metadata, plan, native,
|
|
193
|
+
...options }`. Return normalized versioned data; do not return a compiler
|
|
194
|
+
object, provider implementation, mutable manifest, or unaudited Wasm bytes.
|
|
195
|
+
|
|
196
|
+
Keep concrete implementation, configuration normalization, reference fields,
|
|
197
|
+
and target policy in the provider package. A project selects either a bare host
|
|
198
|
+
ID or an exact scoped package name as its profile `host`; Pulse resolves only
|
|
199
|
+
that package's `./toolchain` export. Adding a first-party bare host to the
|
|
200
|
+
built-in support catalog still requires an architecture-reviewed release
|
|
201
|
+
dependency, documentation, and acceptance change. A project-owned scoped
|
|
202
|
+
provider does not.
|
|
203
|
+
|
|
204
|
+
The selected toolchain executes as trusted build code in the Pulse process.
|
|
205
|
+
Do not run Pulse commands against an untrusted project or dependency tree.
|
|
206
|
+
|
|
207
|
+
## 7. Extend project configuration
|
|
208
|
+
|
|
209
|
+
Update the public TypeScript types, config loader, normalization, and CLI override behavior. Decide whether the provider is selected by a string or a typed helper object.
|
|
210
|
+
|
|
211
|
+
Document every field in the machine-readable project configuration catalog. The release gate compares that catalog with exported TypeScript interfaces, including optionality, so a field cannot be added only in code or only in prose.
|
|
212
|
+
|
|
213
|
+
Cover:
|
|
214
|
+
|
|
215
|
+
- defaults;
|
|
216
|
+
- allowed values;
|
|
217
|
+
- command-line precedence;
|
|
218
|
+
- local versus deployment meaning;
|
|
219
|
+
- secret and path safety;
|
|
220
|
+
- related diagnostics.
|
|
221
|
+
|
|
222
|
+
## 8. Extend CLI behavior and help
|
|
223
|
+
|
|
224
|
+
For each command, decide and test:
|
|
225
|
+
|
|
226
|
+
| Command | Provider question |
|
|
227
|
+
|---|---|
|
|
228
|
+
| `doctor` | What dependencies, bindings, and external tools are checked? |
|
|
229
|
+
| `inspect` | What provider plan and readiness detail is emitted? |
|
|
230
|
+
| `test` | Is local execution supported? |
|
|
231
|
+
| `dev` | Can it serve locally and watch safely? |
|
|
232
|
+
| `build` | What files are emitted, cleaned, and validated? |
|
|
233
|
+
|
|
234
|
+
Update the declarative command specification when provider choices or option behavior change. Installed help and the generated CLI reference must remain in parity.
|
|
235
|
+
|
|
236
|
+
## 9. Add public diagnostics
|
|
237
|
+
|
|
238
|
+
Provider failures reaching the supported workflow need stable `PULSE_*` codes in the public diagnostic catalog. Typical classes include:
|
|
239
|
+
|
|
240
|
+
- unsupported provider or command;
|
|
241
|
+
- missing capability;
|
|
242
|
+
- invalid binding map;
|
|
243
|
+
- missing deployment resource mapping;
|
|
244
|
+
- unavailable compiler or external CLI;
|
|
245
|
+
- version mismatch;
|
|
246
|
+
- target compile/serve timeout;
|
|
247
|
+
- target compile/serve failure.
|
|
248
|
+
|
|
249
|
+
Each public code needs summary, remediation, exit class, optional development HTTP mapping, and a generated exact-version documentation anchor.
|
|
250
|
+
|
|
251
|
+
Internal proof diagnostics may remain `PULSEWASM_*`, but they must not leak as undocumented public links.
|
|
252
|
+
|
|
253
|
+
## 10. Publish and classify the package
|
|
254
|
+
|
|
255
|
+
When the provider is a published package:
|
|
256
|
+
|
|
257
|
+
- add it to the synchronized release manifest and version set;
|
|
258
|
+
- declare the support tier, audience, direct-install guidance, supported entry points, and stability in `release/pulse-release-manifest.json`;
|
|
259
|
+
- ensure repository/homepage/bugs metadata is generated;
|
|
260
|
+
- add a concise package README and a canonical package guide;
|
|
261
|
+
- add required files to `package.json.files`;
|
|
262
|
+
- verify packed relative and exact-version links;
|
|
263
|
+
- test from packed tarballs without workspace links.
|
|
264
|
+
|
|
265
|
+
An exported subpath is not automatically supported. List only entry points that carry an intentional compatibility promise.
|
|
266
|
+
|
|
267
|
+
## 11. Test equivalence and isolation
|
|
268
|
+
|
|
269
|
+
A provider is not complete after one successful request. Cover:
|
|
270
|
+
|
|
271
|
+
```text
|
|
272
|
+
request metadata and headers
|
|
273
|
+
JSON/text/custom responses
|
|
274
|
+
schema decode and encode
|
|
275
|
+
single, grouped, and dependent fetch
|
|
276
|
+
fetch timeout/network failure
|
|
277
|
+
config and secret reads
|
|
278
|
+
KV get/put
|
|
279
|
+
opaque pass-through
|
|
280
|
+
supported package-owned effects
|
|
281
|
+
missing capability and binding failures
|
|
282
|
+
continuation expiry/double-resume protection
|
|
283
|
+
secret redaction
|
|
284
|
+
local dev request behavior
|
|
285
|
+
build output and output-path safety
|
|
286
|
+
packed-package installation
|
|
287
|
+
external target execution where available
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Compare provider plans and observable canonical results with the Node conformance path where the capabilities overlap. Provider-specific target details may differ; application-visible semantics should not.
|
|
291
|
+
|
|
292
|
+
## 12. Release checklist
|
|
293
|
+
|
|
294
|
+
Before adding the provider to the public matrix:
|
|
295
|
+
|
|
296
|
+
- The descriptor lists only implemented capabilities.
|
|
297
|
+
- Every capability has local behavior and, when claimed, target behavior.
|
|
298
|
+
- All required bindings fail early and clearly.
|
|
299
|
+
- The driver is wired into all relevant commands.
|
|
300
|
+
- Config types, normalization, generated reference, and examples agree.
|
|
301
|
+
- Public diagnostics have resolvable anchors.
|
|
302
|
+
- Handler source remains provider-neutral.
|
|
303
|
+
- Packed-package and clean-machine tests pass.
|
|
304
|
+
- External reality checks are separated from deterministic conformance tests.
|
|
305
|
+
- The docs do not imply a public plugin API.
|
|
306
|
+
|
|
307
|
+
## Related documentation
|
|
308
|
+
|
|
309
|
+
- [Pulse-aware package authoring](./pulse-aware-packages.md)
|
|
310
|
+
- [Contracts and providers](../concepts/contracts-and-providers.md)
|
|
311
|
+
- [Fastly package guide](../packages/provider-fastly.md)
|
|
312
|
+
- [Project configuration](../reference/project-config.md)
|
|
313
|
+
- [Diagnostics](../reference/diagnostics.md)
|
|
314
|
+
- [Release acceptance](../maintainers/release-acceptance.md)
|
|
315
|
+
- [Package support policy](../packages/README.md)
|
|
@@ -0,0 +1,327 @@
|
|
|
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
|
+
# Add a first-party package-owned lowerer
|
|
9
|
+
|
|
10
|
+
Start with [Pulse-aware package authoring](./pulse-aware-packages.md) to decide
|
|
11
|
+
whether the package needs Native lowering at all. Ordinary target-compatible
|
|
12
|
+
JavaScript packages do not require a compiler builder.
|
|
13
|
+
|
|
14
|
+
> **Scope and trust boundary:** Pulse `1.0.0-beta.2` executes package-owned compiler builders only when their manifest declares `compiler.trust: 'first-party'` and the package is part of the synchronized release set. This is a core-repository contributor workflow, **not an external plugin** interface or a supported third-party plugin API. An external package cannot self-register arbitrary compiler code.
|
|
15
|
+
|
|
16
|
+
A package-owned lowerer lets one release package define a narrow TypeScript facade and keep its domain-specific static validation outside compiler core. GRIP is the clearest current example; assets is the second implementation proving that the generic loader is not GRIP-specific.
|
|
17
|
+
|
|
18
|
+
## What belongs where
|
|
19
|
+
|
|
20
|
+
| Concern | Owner |
|
|
21
|
+
|---|---|
|
|
22
|
+
| Ergonomic lowerable TypeScript symbols | Feature package root, such as `packages/grip/src/index.ts` |
|
|
23
|
+
| Package identity and facade-to-sidecar declaration | Feature package manifest |
|
|
24
|
+
| Domain payload versions and diagnostic vocabulary | Shared contracts package |
|
|
25
|
+
| AST validation and canonical effect construction | Feature package compiler builder |
|
|
26
|
+
| Manifest discovery and trusted builder loading | `@pulse-compute/wasm-library-kit` |
|
|
27
|
+
| Whole-project orchestration and merge with canonical effects | `@pulse-compute/wasm-compiler` |
|
|
28
|
+
| Capability realization | Node/Fastly provider packages |
|
|
29
|
+
| Product workflow, diagnostics, docs, release validation | `@pulse-compute/cli` and root release scripts |
|
|
30
|
+
|
|
31
|
+
The central compiler may invoke and combine package plans, but it must not absorb package-specific symbol names, payload rules, or provider behavior.
|
|
32
|
+
|
|
33
|
+
## End-to-end data flow
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
application import
|
|
37
|
+
→ package facade symbol
|
|
38
|
+
→ package manifest discovery
|
|
39
|
+
→ first-party compiler builder
|
|
40
|
+
→ package contract validation
|
|
41
|
+
→ canonical package effect
|
|
42
|
+
→ shared provider plan
|
|
43
|
+
→ Node/Fastly realization
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 1. Choose stable identity
|
|
47
|
+
|
|
48
|
+
Define before implementation:
|
|
49
|
+
|
|
50
|
+
- a contract ID, such as `pulse.grip`;
|
|
51
|
+
- an npm package owner;
|
|
52
|
+
- one canonical package-root import;
|
|
53
|
+
- a small static symbol set;
|
|
54
|
+
- canonical effect kinds and result classes;
|
|
55
|
+
- the providers that can realize each operation;
|
|
56
|
+
- unsupported or reserved forms and their diagnostics.
|
|
57
|
+
|
|
58
|
+
Identity must have one owner. Do not duplicate contract IDs, package names, or facade symbol lists in compiler core.
|
|
59
|
+
|
|
60
|
+
For a new package named `@pulse-compute/example`, a typical layout is:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
packages/example/
|
|
64
|
+
src/index.ts
|
|
65
|
+
pulsewasm.manifest.cjs
|
|
66
|
+
pulsewasm.compiler.cjs
|
|
67
|
+
as/index.as.ts
|
|
68
|
+
package.json
|
|
69
|
+
README.md
|
|
70
|
+
test/
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## 2. Create a real package-root API
|
|
74
|
+
|
|
75
|
+
The package root must be the application import for both JavaScript execution
|
|
76
|
+
and supported Native lowering. JavaScript targets execute the real package
|
|
77
|
+
implementation. The compiler recognizes a deliberately narrower set of
|
|
78
|
+
package-root calls for Native targets and reports unsupported forms as
|
|
79
|
+
eligibility diagnostics.
|
|
80
|
+
|
|
81
|
+
Design rules:
|
|
82
|
+
|
|
83
|
+
- keep the public lowerable symbol set narrow;
|
|
84
|
+
- prefer literal or statically bounded arguments;
|
|
85
|
+
- use the package root as `lowerableSubpath` and `facade.import`;
|
|
86
|
+
- do not import a provider SDK;
|
|
87
|
+
- route request-bound work through the explicit Pulse context;
|
|
88
|
+
- keep pure framing or result-adoption helpers free of ambient authority;
|
|
89
|
+
- keep compatibility subpaths, when they already exist, out of new authoring
|
|
90
|
+
guidance.
|
|
91
|
+
|
|
92
|
+
Export the package root from `package.json` and include its built
|
|
93
|
+
JavaScript/types in the packed files.
|
|
94
|
+
|
|
95
|
+
## 3. Declare the package manifest
|
|
96
|
+
|
|
97
|
+
The package root advertises the manifest in `package.json`:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"pulsewasm": {
|
|
102
|
+
"manifest": "./pulsewasm.manifest.cjs"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The manifest uses `pulsewasm.lowerable-library-manifest.v2` and must include:
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
const pulseWasmManifest = Object.freeze({
|
|
111
|
+
version: 'pulsewasm.lowerable-library-manifest.v2',
|
|
112
|
+
kind: 'pulsewasm.lowerable-library-manifest',
|
|
113
|
+
contractId: 'pulse.example',
|
|
114
|
+
npmPackage: '@pulse-compute/example',
|
|
115
|
+
lowerableSubpath: '@pulse-compute/example',
|
|
116
|
+
facade: Object.freeze({
|
|
117
|
+
namespace: 'example',
|
|
118
|
+
import: '@pulse-compute/example',
|
|
119
|
+
symbols: Object.freeze(['emit']),
|
|
120
|
+
}),
|
|
121
|
+
compiler: Object.freeze({
|
|
122
|
+
version: 'pulsewasm.lowerable-compiler-builder.v1',
|
|
123
|
+
entry: './pulsewasm.compiler.cjs',
|
|
124
|
+
export: 'buildExampleLoweringPlan',
|
|
125
|
+
artifact: 'example-lowering-plan.json',
|
|
126
|
+
builderOwner: '@pulse-compute/example',
|
|
127
|
+
trust: 'first-party',
|
|
128
|
+
}),
|
|
129
|
+
modes: Object.freeze({
|
|
130
|
+
typescript: Object.freeze({ entry: './dist/index.js' }),
|
|
131
|
+
jsEngine: Object.freeze({ entry: './dist/index.js' }),
|
|
132
|
+
wasm: Object.freeze({
|
|
133
|
+
mode: 'wasm-sidecar',
|
|
134
|
+
sidecar: './as/index.as.ts',
|
|
135
|
+
lowerings: Object.freeze([
|
|
136
|
+
Object.freeze({
|
|
137
|
+
tsSymbol: 'example.emit',
|
|
138
|
+
asSymbol: 'pulse_example_emit',
|
|
139
|
+
callShape: 'literal-topic-message',
|
|
140
|
+
hostCapabilities: Object.freeze(['example']),
|
|
141
|
+
}),
|
|
142
|
+
]),
|
|
143
|
+
hostCapabilities: Object.freeze(['example']),
|
|
144
|
+
}),
|
|
145
|
+
}),
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
module.exports = pulseWasmManifest
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The manifest validator requires the facade, TypeScript/JS entries, sidecar, lowering list, builder protocol, entry, export, owner, and trust declaration. `compiler.builderOwner` must match `npmPackage`.
|
|
152
|
+
|
|
153
|
+
Do not weaken the `first-party` check to make a local experiment load. A public plugin mechanism would require separate trust, discovery, sandboxing, version negotiation, and compatibility design.
|
|
154
|
+
|
|
155
|
+
## 4. Define contract-owned schemas and diagnostics
|
|
156
|
+
|
|
157
|
+
Add the operation and plan vocabulary under `wasm/packages/contracts/src/<feature>/`. Contracts should define:
|
|
158
|
+
|
|
159
|
+
- contract and artifact version constants;
|
|
160
|
+
- valid operation names and capabilities;
|
|
161
|
+
- payload and result shapes;
|
|
162
|
+
- static status vocabulary;
|
|
163
|
+
- internal compiler diagnostics for invalid facade forms;
|
|
164
|
+
- normalization helpers used by builder and providers.
|
|
165
|
+
|
|
166
|
+
Contracts must not contain package discovery, AST traversal, provider execution, or application runtime code.
|
|
167
|
+
|
|
168
|
+
Export the new contract through the contracts package’s declared subpaths and verify package exports.
|
|
169
|
+
|
|
170
|
+
## 5. Implement the package compiler builder
|
|
171
|
+
|
|
172
|
+
The manifest export, such as `buildExampleLoweringPlan`, receives the source, discovered manifest, library contracts, TypeScript parser, and builder ownership metadata from the generic loader.
|
|
173
|
+
|
|
174
|
+
The builder should:
|
|
175
|
+
|
|
176
|
+
1. collect only imports from its exact `lowerableSubpath`;
|
|
177
|
+
2. classify namespace, default, and named imports intentionally;
|
|
178
|
+
3. match supported call placements;
|
|
179
|
+
4. validate literals and object options with contract-owned rules;
|
|
180
|
+
5. emit source-located diagnostics for unsupported forms;
|
|
181
|
+
6. construct canonical package effects;
|
|
182
|
+
7. return a versioned package plan and summary;
|
|
183
|
+
8. avoid provider-specific lowering names or runtime calls.
|
|
184
|
+
|
|
185
|
+
A canonical package effect needs enough information for the shared provider contract:
|
|
186
|
+
|
|
187
|
+
```js
|
|
188
|
+
{
|
|
189
|
+
version: 'pulse.canonical-package-effect.v1',
|
|
190
|
+
contractId: 'pulse.example',
|
|
191
|
+
package: '@pulse-compute/example',
|
|
192
|
+
import: '@pulse-compute/example',
|
|
193
|
+
kind: 'example.emit',
|
|
194
|
+
providerKind: 'example',
|
|
195
|
+
operation: 'emit',
|
|
196
|
+
capability: 'example.emit',
|
|
197
|
+
result: 'ack',
|
|
198
|
+
resource: { kind: 'literal', value: 'updates' },
|
|
199
|
+
payload: { topic: 'updates', message: 'ready' },
|
|
200
|
+
loc: { file: 'src/index.ts', line: 4, column: 3 },
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Keep domain rules in the builder. The generic loader is intentionally free of strings such as `grip.hold` or `assets.lookup`.
|
|
205
|
+
|
|
206
|
+
## 6. Add the sidecar contract when compiled Wasm needs one
|
|
207
|
+
|
|
208
|
+
The manifest’s sidecar source exports stable symbols and delegates to stable host imports. It is an ABI boundary, not the place to reimplement the package compiler.
|
|
209
|
+
|
|
210
|
+
For each manifest lowering:
|
|
211
|
+
|
|
212
|
+
- export the declared `asSymbol`;
|
|
213
|
+
- keep arguments/results deterministic and versioned;
|
|
214
|
+
- map to named host capabilities;
|
|
215
|
+
- add compile/link tests;
|
|
216
|
+
- prove packed-package discovery, not only monorepo source resolution.
|
|
217
|
+
|
|
218
|
+
A sidecar can be a readiness/ABI surface even when provider execution is implemented elsewhere. Document that status explicitly.
|
|
219
|
+
|
|
220
|
+
## 7. Verify generic discovery
|
|
221
|
+
|
|
222
|
+
The reachable module graph selects participating package contracts and tracks
|
|
223
|
+
package-root symbols through supported imports and re-exports. The compiler
|
|
224
|
+
then recognizes operations in each reachable project module. The generic
|
|
225
|
+
library kit resolves the selected first-party manifest from the synchronized
|
|
226
|
+
workspace or exact installed package and invokes its declared builder.
|
|
227
|
+
|
|
228
|
+
This is not entry-source substring discovery. An installed dependency is not
|
|
229
|
+
participating merely because it has a manifest, and a package cannot
|
|
230
|
+
self-register compiler code. The detailed owner and pipeline map lives in the
|
|
231
|
+
[package lowerer contract reference](./package-lowerer-contract.md).
|
|
232
|
+
|
|
233
|
+
Add tests proving:
|
|
234
|
+
|
|
235
|
+
- the manifest validates;
|
|
236
|
+
- the package exports its lowerable facade, manifest, and compiler-builder subpaths as intended;
|
|
237
|
+
- `package.json.files` includes the manifest, builder, sidecar, and built facade;
|
|
238
|
+
- discovery works from an isolated `node_modules`-style packed package;
|
|
239
|
+
- a reachable import or supported project re-export selects the package contract;
|
|
240
|
+
- an installed but unreachable lowerable package is not selected;
|
|
241
|
+
- the generic loader resolves the manifest-declared builder export;
|
|
242
|
+
- compiler core does not hard-code the new package import or symbol names.
|
|
243
|
+
|
|
244
|
+
Do not rely only on workspace symlinks.
|
|
245
|
+
|
|
246
|
+
## 8. Add provider realization
|
|
247
|
+
|
|
248
|
+
A package effect is not usable until each advertised provider maps its capabilities. For every supported provider:
|
|
249
|
+
|
|
250
|
+
- add capabilities to its descriptor;
|
|
251
|
+
- add stable lowering names;
|
|
252
|
+
- normalize required bindings;
|
|
253
|
+
- implement local conformance behavior;
|
|
254
|
+
- implement target/build behavior where applicable;
|
|
255
|
+
- fail with a public diagnostic when required bindings are absent;
|
|
256
|
+
- preserve `providerSpecificUserland: false` and `providerSdkUserland: false`.
|
|
257
|
+
|
|
258
|
+
A provider that cannot implement the capability should reject it during provider-plan creation, not at an arbitrary later request branch.
|
|
259
|
+
|
|
260
|
+
## 9. Add public diagnostics and documentation
|
|
261
|
+
|
|
262
|
+
Internal `PULSEWASM_*` builder diagnostics are useful for proof lanes but are not automatically public CLI codes. Any failure that can reach application authors through the supported workflow needs an entry in the public diagnostic catalog with title, summary, remediation, exit class, HTTP mapping where applicable, and a generated anchor.
|
|
263
|
+
|
|
264
|
+
Update:
|
|
265
|
+
|
|
266
|
+
- the feature package README;
|
|
267
|
+
- [Package support policy](../packages/README.md) when the package is published or its supported entries change;
|
|
268
|
+
- a package guide under `docs/packages/`;
|
|
269
|
+
- concept or tutorial pages that introduce the capability;
|
|
270
|
+
- project configuration reference when new bindings are public;
|
|
271
|
+
- the environment reference only for genuine process-level inputs.
|
|
272
|
+
|
|
273
|
+
Public examples must use canonical handlers and the normal `pulse` workflow.
|
|
274
|
+
|
|
275
|
+
## 10. Required verification
|
|
276
|
+
|
|
277
|
+
At minimum, cover:
|
|
278
|
+
|
|
279
|
+
```text
|
|
280
|
+
positive static lowering
|
|
281
|
+
negative dynamic/literal validation
|
|
282
|
+
manifest schema validation
|
|
283
|
+
builder owner/trust validation
|
|
284
|
+
normal-JavaScript facade failure
|
|
285
|
+
canonical effect shape
|
|
286
|
+
provider capability plan
|
|
287
|
+
Node local conformance when supported
|
|
288
|
+
Fastly local and compiled target behavior when supported
|
|
289
|
+
packed package discovery
|
|
290
|
+
package export and tarball contents
|
|
291
|
+
documentation links and source-bound snippets
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Run the repository’s focused tests first, then the release gates:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
pnpm docs:check
|
|
298
|
+
pnpm wasm:test:unit
|
|
299
|
+
pnpm wasm:test:native
|
|
300
|
+
pnpm wasm:test:providers
|
|
301
|
+
npm run release:seal
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Exact script names may evolve; the authoritative profiles are described in [Testing](../maintainers/testing.md).
|
|
305
|
+
|
|
306
|
+
## Review checklist
|
|
307
|
+
|
|
308
|
+
A lowerer is ready for the synchronized release only when all answers are yes:
|
|
309
|
+
|
|
310
|
+
- Does the feature package own its facade, manifest, and builder?
|
|
311
|
+
- Does a shared contract own payload/version semantics?
|
|
312
|
+
- Is the builder explicitly first-party and owner-matched?
|
|
313
|
+
- Does compiler core remain free of feature-specific AST rules?
|
|
314
|
+
- Are all advertised providers capable and bound?
|
|
315
|
+
- Does ordinary JavaScript execution use the real package implementation?
|
|
316
|
+
- Does packed dependency discovery work without workspace paths?
|
|
317
|
+
- Are public failures catalogued and documented?
|
|
318
|
+
- Is the Beta boundary narrower than or equal to what tests prove?
|
|
319
|
+
|
|
320
|
+
## Related documentation
|
|
321
|
+
|
|
322
|
+
- [Pulse-aware package authoring](./pulse-aware-packages.md)
|
|
323
|
+
- [Compilation and lowering](../concepts/compilation-and-lowering.md)
|
|
324
|
+
- [Contracts and providers](../concepts/contracts-and-providers.md)
|
|
325
|
+
- [GRIP package guide](../packages/grip.md)
|
|
326
|
+
- [Assets package guide](../packages/assets.md)
|
|
327
|
+
- [Implementation packages](../packages/implementation-packages.md)
|