1.0.0-beta.9 · exact release
Entities tools facade
Source fda16de1b352 · Published v1.0.0-beta.9
This experimental example declares two schema-bound operations with
@pulse-compute/entities, exposes them through the first-party JSON-RPC
adapter, and projects their emitted static catalog into a dependency-free tools
facade. The facade invokes the governed request boundary; it does not call
application handlers directly.
The application contributes:
system.status, which accepts no input and completes withnull;customer.lookup, which validates named input and output and performs one governedctx.fetcheffect.
JavaScript workflow
Section titled “JavaScript workflow”Install the example's declared dependencies, then run its local CLI scripts.
The default profile is node-javascript:
npm installThe acceptance below uses freshly packed candidate packages. It does not mean
these fixes are available in the already published 1.0.0-beta.9 packages.
Use the matching reviewed package release when it is published; maintainers can
run the candidate acceptance gate described below before publication.
npm run doctornpm run inspectnpm testnpm run devnpm run buildpulse doctor checks the selected JavaScript target and reports Native
eligibility separately.
pulse inspect reports the static entity catalog, declared schemas, handler
effects, and target evidence. pulse test invokes both operations through the
Node JavaScript request boundary. The lookup fixture supplies plain text because
its handler consumes ctx.fetch(...).text(); a value fixture would encode a
JSON string, including quotes.
pulse test --json{"status":"passed","provider":"node","target":"javascript","summary":{"total":2,"passed":2,"failed":0}}During pulse dev, send a JSON-RPC system.status request to check the live
boundary. The harness's lookup fixture applies only to pulse test;
customer.lookup needs a configured development fetch fixture or backend.
This example disables development network fetches by default. Stop the dev
server before continuing to pulse build.
The JavaScript build emits the source package, catalog, and inspection artifacts.
Node Native workflow
Section titled “Node Native workflow”Select the existing node-native profile to compile and execute the package-owned
dispatcher through the ordinary CLI:
pulse doctor --profile node-nativepulse inspect --profile node-nativepulse test --profile node-nativepulse dev --profile node-nativepulse build --profile node-nativeThe build emits dist-node-native/canonical-native.wasm and its Native plan,
catalog, and inspection artifacts. Tests and development execute this generated
guest through the canonical Node host. The guest selects the operation, validates
its schemas, suspends for governed effects, and frames the response. Test JSON
records the plan hash and executed Wasm hash. Native never falls back to
JavaScript.
Maintainers can also run the package-owned orchestration proof from this source checkout:
node ../../wasm/scripts/run-wasm-tests.cjs --task entities-orchestration-demo --no-reportThat proof consumes the catalog through the tools facade and compiles/inspects the package-owned Native artifact. It supplements the ordinary JavaScript workflow above; ordinary Node Native execution has its own lifecycle gate.
Fastly profiles
Section titled “Fastly profiles”The example also declares fastly-javascript and fastly-native. Both bind the
directory origin to the explicit directory_backend backend, with dynamic
backends disabled. Select either profile for the same installed lifecycle:
npm run doctor -- --profile fastly-nativenpm run inspect -- --profile fastly-nativenpm test -- --profile fastly-nativenpm run dev -- --profile fastly-nativenpm run build -- --profile fastly-nativenpm run inspect -- --artifact dist-fastly-native/pulse-build.jsonStop the foreground dev server before building. Its system.status request is:
curl -H 'content-type: application/json' --data '{"jsonrpc":"2.0","method":"system.status","id":"smoke"}' http://127.0.0.1:8787/Use the URL printed by dev if the configured port differs. Native builds emit
dist-fastly-native/bin/main.wasm; JavaScript builds emit their source package
and provider bundle under dist-fastly-javascript. Fastly test and dev use
the provider's local fixture runtime. They do not constitute Viceroy replay or
live deployment. Bind the real directory backend separately before deployment.
Clean installed acceptance
Section titled “Clean installed acceptance”From a source checkout with the pinned workspace dependencies restored:
node wasm/scripts/run-wasm-tests.cjs --task cli-entities-installed-workflowThe gate packs the candidate through the release packer, copies this example
outside the checkout, and installs only its declared dependency graph. A local
read-only registry serves the exact Pulse candidates; third-party dependencies
come from npm, with lifecycle scripts disabled. No workspace links or private
package entry points are injected. It checks package bytes before and after
execution, and prints the retained structured report path under wasm/.test-results/.
| Profile | Measured installed acceptance | Execution boundary |
|---|---|---|
node-javascript | doctor, inspect, test, dev request/shutdown, build, artifact inspection | Package JavaScript runtime |
node-native | Same lifecycle; tested and built Wasm hashes match | Canonical Node host |
fastly-javascript | Same lifecycle and emitted source package | Local provider fixture runtime |
fastly-native | Same lifecycle; tested and built Wasm hashes match | Local provider fixture ABI |
This gate is required by the release profile and can be selected directly. It supplements the fast non-main workflow without adding package installation to every fast PR run. External Viceroy evidence and live deployment remain separate.
Wasm size
Section titled “Wasm size”The default node-javascript profile emits no application Wasm artifact.
Select node-native to emit an application guest. --experimental-native-size
is meaningful only on that Native profile; the default JavaScript build has
no application guest to optimize.
Entity application
Section titled “Entity application”import { EntityRouter, jsonRpc } from '@pulse-compute/entities'import { lookupCustomer, systemStatus } from './handlers.js'
const rpc = new EntityRouter({ adapter: jsonRpc({ namedParamsOnly: true, acceptEmptyObjectForNoInput: true }),})
rpc.on('system.status', { input: null, output: null, metadata: { title: 'Check system status', description: 'Checks that the governed entity request boundary is available.', mcp: { readOnlyHint: true }, },}, systemStatus)
rpc.on('customer.lookup', { input: 'tools.CustomerLookupInput', output: 'tools.CustomerLookupOutput', metadata: { title: 'Look up customer', description: 'Looks up one customer through the configured directory backend.', mcp: { readOnlyHint: true }, },}, lookupCustomer)
export default async function handler(ctx: unknown) { return rpc.handle(ctx as never)}Project config
Section titled “Project config”import { defineConfig } from '@pulse-compute/pulse'
export default defineConfig((_scope) => ({ pulse: { entry: 'src/index.ts', schema: 'src/schemas.ts', tests: 'tests/pulse.harness.ts', defaultProfile: 'node-javascript', strict: true, }, 'node-javascript': { host: 'node', target: 'javascript', outDir: 'dist-node-javascript', dev: { networkFetch: false }, }, 'node-native': { host: 'node', target: 'native', outDir: 'dist-node-native', dev: { networkFetch: false }, }, 'fastly-javascript': { host: 'fastly', target: 'javascript', outDir: 'dist-fastly-javascript', dev: { networkFetch: false }, fastly: { bindings: { backends: { 'https://directory.example.test': 'directory_backend' }, dynamicBackends: false, }, }, }, 'fastly-native': { host: 'fastly', target: 'native', outDir: 'dist-fastly-native', dev: { networkFetch: false }, fastly: { bindings: { backends: { 'https://directory.example.test': 'directory_backend' }, dynamicBackends: false, }, }, },}))Test harness
Section titled “Test harness”export default { cases: [ { name: 'system-status', request: { method: 'POST', path: '/', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', method: 'system.status', id: 'status-doc' }), }, expect: { status: 200, json: { jsonrpc: '2.0', result: null, id: 'status-doc' }, }, }, { name: 'customer-lookup', request: { method: 'POST', path: '/', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', method: 'customer.lookup', params: { email: 'ada@example.test' }, id: 'lookup-doc', }), }, fetches: { 'https://directory.example.test/customers/ada@example.test': { text: 'Ada Lovelace' }, }, expect: { status: 200, json: { jsonrpc: '2.0', result: { email: 'ada@example.test', displayName: 'Ada Lovelace' }, id: 'lookup-doc', }, }, },] }Facade boundary
Section titled “Facade boundary”tools-facade.cjs is an orchestration example, not a complete MCP server. It
does not add listeners, SSE, sessions, tasks, resources, prompts, sampling,
authorization, transport negotiation, or protocol lifecycle state to Pulse
runtime core. A future MCP or tools facade remains an adapter outside the
entity engine, just as a future Worker/event adapter would bind a different
request or event protocol without changing entity handler semantics.