@pulse-compute/runtime 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/README.md +126 -2
- package/docs/API.md +572 -0
- package/docs/guides/routing.md +202 -0
- package/docs/preview-scope.md +142 -0
- package/package.json +38 -5
- package/src/host.d.ts +420 -0
- package/src/host.js +115 -0
- package/src/index.d.ts +215 -0
- package/src/index.js +11 -0
- package/src/internal/bindings.js +281 -0
- package/src/internal/body.js +254 -0
- package/src/internal/conditional-kv.js +199 -0
- package/src/internal/context.js +275 -0
- package/src/internal/effect-adapter.js +877 -0
- package/src/internal/errors.js +27 -0
- package/src/internal/event-emission.js +182 -0
- package/src/internal/event-execution.js +496 -0
- package/src/internal/fetch.js +221 -0
- package/src/internal/index.js +24 -0
- package/src/internal/logging.js +65 -0
- package/src/internal/package-runtime.js +604 -0
- package/src/internal/path.js +130 -0
- package/src/internal/redaction.js +231 -0
- package/src/internal/response.js +415 -0
- package/src/internal/router.js +487 -0
- package/src/internal/schema.js +340 -0
- package/src/package.d.ts +127 -0
- package/src/package.js +19 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Static Router authoring
|
|
2
|
+
|
|
3
|
+
Use `Router` when an application has several method/path entry points or needs compile-time middleware. It is a static authoring marker from `@pulse-compute/runtime`, not a JavaScript runtime dispatcher. The shared async/static restrictions are defined in [Managed handler TypeScript and JavaScript](https://pulsecompute.io/v1.0.0-beta.2/reference/handler-authoring/); target claims live in the [compatibility matrix](https://pulsecompute.io/v1.0.0-beta.2/reference/compatibility-matrix/).
|
|
4
|
+
|
|
5
|
+
<!-- pulse-doc-source: examples/09-router-lowering/src/index.ts -->
|
|
6
|
+
```ts
|
|
7
|
+
import { Router } from '@pulse-compute/runtime'
|
|
8
|
+
|
|
9
|
+
interface User {
|
|
10
|
+
id: number
|
|
11
|
+
name: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const users = new Router()
|
|
15
|
+
const api = new Router()
|
|
16
|
+
const app = new Router()
|
|
17
|
+
|
|
18
|
+
app.use(async (ctx, next) => {
|
|
19
|
+
if (ctx.req.header('x-pulse-deny') === '1') {
|
|
20
|
+
return ctx.json(
|
|
21
|
+
{ error: 'denied by middleware' },
|
|
22
|
+
{ status: 401 },
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
return next()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
api.use(async (ctx, next) => {
|
|
29
|
+
if (ctx.req.header('x-api-state') === 'closed') {
|
|
30
|
+
return ctx.text('api closed', { status: 503 })
|
|
31
|
+
}
|
|
32
|
+
return next()
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
users.get('/:id', async (ctx) => {
|
|
36
|
+
const id = ctx.param('id')
|
|
37
|
+
const user = await ctx
|
|
38
|
+
.fetch('https://users.example.test/users/' + id)
|
|
39
|
+
.json<User>()
|
|
40
|
+
return ctx.json({ route: 'user', id, user })
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
api.get('/health', async (ctx, next) => {
|
|
44
|
+
if (ctx.req.header('x-health-handler') === 'fallback') {
|
|
45
|
+
return next()
|
|
46
|
+
}
|
|
47
|
+
return ctx.json({ ok: true, handler: 'primary' })
|
|
48
|
+
})
|
|
49
|
+
api.get('/health', async (ctx) => ctx.json({ ok: true, handler: 'fallback' }))
|
|
50
|
+
api.head('/health', async (ctx) => ctx.text('', {
|
|
51
|
+
status: 204,
|
|
52
|
+
headers: [['x-pulse-route', 'health']],
|
|
53
|
+
}))
|
|
54
|
+
api.post('/users', async (ctx) => ctx.json(
|
|
55
|
+
{ route: 'create', method: ctx.req.method },
|
|
56
|
+
{ status: 201 },
|
|
57
|
+
))
|
|
58
|
+
api.get('/files/*', async (ctx) => ctx.text(ctx.req.path))
|
|
59
|
+
api.get('/failure', async (ctx, next) => next('documented-failure'))
|
|
60
|
+
|
|
61
|
+
api.mount('/users', users)
|
|
62
|
+
app.mount('/api', api)
|
|
63
|
+
|
|
64
|
+
app.error(async (error, ctx, next) => {
|
|
65
|
+
if (error === 'documented-failure') {
|
|
66
|
+
return ctx.json({ error: 'handled' }, { status: 418 })
|
|
67
|
+
}
|
|
68
|
+
return next(error)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
export default app
|
|
72
|
+
```
|
|
73
|
+
<!-- /pulse-doc-source -->
|
|
74
|
+
|
|
75
|
+
## Supported v2 surface
|
|
76
|
+
|
|
77
|
+
- `new Router()` with a default-exported root router;
|
|
78
|
+
- `use(handler)` and `use(path, handler)` middleware;
|
|
79
|
+
- `get`, `head`, `post`, `put`, `patch`, and `delete` registrations;
|
|
80
|
+
- exact paths, named `:parameters`, and a trailing `*` wildcard;
|
|
81
|
+
- static acyclic `mount` composition;
|
|
82
|
+
- named or inline async-shaped route handlers using `(ctx)` or `(ctx, next)`;
|
|
83
|
+
- async-shaped middleware using `(ctx, next)`;
|
|
84
|
+
- async-shaped error middleware using `(error, ctx, next)`;
|
|
85
|
+
- `ctx.param('name')` for a parameter declared by the matched route;
|
|
86
|
+
- first-match order, explicit route fallthrough, and compiler-owned 404/500 exhaustion.
|
|
87
|
+
|
|
88
|
+
Every Router handler uses the normal canonical context. Fetches, schemas, config, secrets, KV, opaque responses, and trusted package effects lower into the same native execution plan as single-handler authoring.
|
|
89
|
+
|
|
90
|
+
`Pulse` inherits the same route registration methods. Each registration matches
|
|
91
|
+
its exact HTTP method; a method mismatch advances the route cursor and normal
|
|
92
|
+
exhaustion remains `404`. There is no automatic `OPTIONS` or `405` response.
|
|
93
|
+
Ingress route methods do not widen the separate outbound `ctx.fetch` contract.
|
|
94
|
+
|
|
95
|
+
The `catalog-router-parity` conformance task exercises the original Catalog
|
|
96
|
+
consumer probe and all 14 of its PUT/PATCH/DELETE operations with their existing
|
|
97
|
+
methods and paths. Its shared cases check mounted parameters, request text,
|
|
98
|
+
middleware state, exact method misses, registration order, terminal fallthrough,
|
|
99
|
+
404 exhaustion and handled errors on Node/Fastly JavaScript and Native. Native
|
|
100
|
+
lanes execute compiled Wasm; Fastly evidence uses local provider emulation and
|
|
101
|
+
the target ABI mock host, not a deployed service. The fixtures establish routing
|
|
102
|
+
acceptance only; they do not implement Catalog persistence or authorization.
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
node wasm/scripts/run-wasm-tests.cjs --task catalog-router-parity --no-report
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## `next()` is a terminal transfer
|
|
109
|
+
|
|
110
|
+
`next()` is not an onion-style callback. It is a compiler-visible control transfer:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
app.use(async (ctx, next) => {
|
|
114
|
+
if (!authorized(ctx)) return ctx.text('unauthorized', { status: 401 })
|
|
115
|
+
return next()
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
After `return next()`, the current handler is finished permanently. The Router cursor advances to the next applicable middleware or route. The handler never resumes and `next()` has no downstream response value.
|
|
120
|
+
|
|
121
|
+
These forms are rejected:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
next()
|
|
125
|
+
return ctx.text('too late')
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
const response = next()
|
|
130
|
+
return response
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Use `return next(error)` to enter the error lane:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
app.get('/account', async (ctx, next) => {
|
|
137
|
+
if (!ctx.req.header('x-account')) return next('missing-account')
|
|
138
|
+
return ctx.text('ok')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
app.error(async (error, ctx, next) => {
|
|
142
|
+
if (error === 'missing-account') return ctx.text('account required', { status: 400 })
|
|
143
|
+
return next(error)
|
|
144
|
+
})
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
If the normal lane is exhausted, Pulse returns `404 Not Found`. If the error lane is exhausted, Pulse returns `500 Internal Server Error`.
|
|
148
|
+
|
|
149
|
+
## Middleware scope and effects
|
|
150
|
+
|
|
151
|
+
A path-scoped `use('/api', handler)` applies only to that subtree. Middleware declared on a mounted child Router is naturally limited to the mounted subtree.
|
|
152
|
+
|
|
153
|
+
Middleware may request normal canonical effects before transferring control:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
app.use(async (ctx, next) => {
|
|
157
|
+
const access = await ctx.fetch('https://auth.example.test/check').json<{ allowed: boolean }>()
|
|
158
|
+
if (!access.allowed) return ctx.text('denied', { status: 403 })
|
|
159
|
+
return next()
|
|
160
|
+
})
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Pulse owns suspension and resumption for the effect. `pulse inspect` attributes the effect and continuation to the middleware entry and then resumes the same flat Router execution graph.
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
Use `ctx.parallel({ ... })` inside any managed route or middleware when named
|
|
167
|
+
operations must begin together on both JavaScript and Native targets. Its fixed
|
|
168
|
+
object-literal property order owns effect identity and result reconstruction, and
|
|
169
|
+
the group settles completely before Router execution continues. Separate awaits
|
|
170
|
+
retain ordinary sequential JavaScript behavior; Native may additionally group
|
|
171
|
+
adjacent eligible effects as an optimization.
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
## Deliberately outside v2
|
|
175
|
+
|
|
176
|
+
Canonical Router v2 does not support onion-style post-`next()` work, assigning or awaiting `next()`, user-authored `throw` as Router transfer, post-response hooks, realtime lifecycle registrations, channels, timeout scopes, `ctx.resolve`, or `ctx.resolved`.
|
|
177
|
+
|
|
178
|
+
Observability and explicit post-response work should use dedicated future contracts such as trace or defer effects rather than hidden middleware unwinding.
|
|
179
|
+
|
|
180
|
+
## Inspect the lowering
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
pulse inspect examples/09-router-lowering --json
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Look at:
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
compiler.authoring.kind
|
|
190
|
+
compiler.routing.entries
|
|
191
|
+
compiler.routing.semantics
|
|
192
|
+
compiler.effects[*].routerEntryStableId
|
|
193
|
+
compiler.continuations[*].routerEntryStableId
|
|
194
|
+
compiler.native.planHash
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
The same project can then be compiled or built normally:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
pulse compile examples/09-router-lowering
|
|
201
|
+
pulse build examples/09-router-lowering
|
|
202
|
+
```
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Beta scope
|
|
2
|
+
|
|
3
|
+
Pulse `1.0.0-beta.2` is a Beta of one provider-neutral application contract
|
|
4
|
+
with explicit Native and JavaScript execution targets. The intended 1.0
|
|
5
|
+
surface is present, but deliberate corrections may still occur before the
|
|
6
|
+
stable `1.0.0` release.
|
|
7
|
+
|
|
8
|
+
The Beta is intentionally strict: Pulse builds the target selected by the
|
|
9
|
+
active `.pulse/config.ts` profile, and unsupported source stops at the exact
|
|
10
|
+
lowering boundary with a stable diagnostic. Pulse never silently switches
|
|
11
|
+
targets.
|
|
12
|
+
|
|
13
|
+
## Supported application behavior
|
|
14
|
+
|
|
15
|
+
- Async-shaped provider-neutral TypeScript handlers; trusted Pulse awaits lower
|
|
16
|
+
into explicit effects and continuations without a Promise runtime.
|
|
17
|
+
- Static Router v2 with terminal middleware, route fallthrough, error
|
|
18
|
+
middleware, GET/HEAD/POST/PUT/PATCH/DELETE routes, exact paths, named parameters, trailing
|
|
19
|
+
wildcards, and acyclic mounts.
|
|
20
|
+
- Basic branching and structured object, array, and scalar manipulation.
|
|
21
|
+
- Request method, URL, path, headers, text, and JSON access.
|
|
22
|
+
- Bounded, memoized structured body decoding.
|
|
23
|
+
- Explicit TypeScript JSON schema declarations and literal schema IDs.
|
|
24
|
+
- GET, HEAD, and POST fetch effects.
|
|
25
|
+
- Independent Native effect grouping, dependent continuation chains, and
|
|
26
|
+
explicit cross-target `ctx.parallel({ ... })` keyed groups.
|
|
27
|
+
- HTTP status and headers as ordinary response data.
|
|
28
|
+
- JSON, text, custom, and direct pass-through responses.
|
|
29
|
+
- Exact-name config and secret reads.
|
|
30
|
+
- Named KV `get` and `put`.
|
|
31
|
+
- Opaque host-owned binary and stream pass-through.
|
|
32
|
+
- Stateless package-root GRIP request classification, response subscription and
|
|
33
|
+
handoff framing, and configured request-bound broadcast.
|
|
34
|
+
- Synchronous string logging through `ctx.log.error`, `warn`, `info`, and
|
|
35
|
+
`debug`, with flat profile reporting thresholds and provider-owned output.
|
|
36
|
+
- Root-only static `Pulse.on` declarations, immutable schema-validated event
|
|
37
|
+
contexts, and one-way `ctx.emit` acceptance through the bounded Node
|
|
38
|
+
JavaScript/Native reference adapter.
|
|
39
|
+
- Provider-neutral portable Wasm and configured Native Node or Fastly builds.
|
|
40
|
+
- Direct JavaScript execution and deterministic source packaging for Node and
|
|
41
|
+
Fastly.
|
|
42
|
+
|
|
43
|
+
## Execution contract
|
|
44
|
+
|
|
45
|
+
The Beta has two target classes and four explicitly selected
|
|
46
|
+
execution modes over one application model:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
source
|
|
50
|
+
├─ Node / Native → canonical analysis → Pulse-owned Wasm → Node realization
|
|
51
|
+
├─ Node / JavaScript → graph-backed loader → live packages → Node lifecycle
|
|
52
|
+
├─ Fastly / Native → canonical analysis → direct-host-ABI bin/main.wasm
|
|
53
|
+
└─ Fastly / JavaScript → deterministic source package → Fastly JS runtime candidate
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Native source that crosses the supported lowering boundary fails visibly with a
|
|
57
|
+
stable diagnostic. JavaScript core Router execution, request/response lifecycle,
|
|
58
|
+
eligibility inspection, effects, package realizations, source packaging, schema
|
|
59
|
+
enforcement, target integrity, and bounded GRIP realization are implemented.
|
|
60
|
+
Native/JavaScript conformance covers Router context, body handling, fetch
|
|
61
|
+
projections, configuration, secrets, KV, schema codecs, GRIP framing, logging,
|
|
62
|
+
and target identity. All declared Node and Fastly full-target-support gates are
|
|
63
|
+
satisfied for the implemented four-mode contract.
|
|
64
|
+
|
|
65
|
+
Fastly JavaScript candidate evidence compiles the deterministic source package
|
|
66
|
+
with the exact pinned downstream toolchain and records a structurally deployable
|
|
67
|
+
runtime artifact. The final release candidate must additionally pass the
|
|
68
|
+
mandatory external Fastly CLI-managed reality lane. Neither result authorizes a
|
|
69
|
+
service deployment or activation.
|
|
70
|
+
|
|
71
|
+
There is no automatic fallback. An operator must select the target through
|
|
72
|
+
project configuration or an explicitly permitted CLI target selection. A
|
|
73
|
+
successful provider-neutral compile does not silently change a
|
|
74
|
+
JavaScript-selected project into a Native one.
|
|
75
|
+
|
|
76
|
+
## Deliberately unsupported
|
|
77
|
+
|
|
78
|
+
- Automatic fallback from Native lowering to JavaScript execution.
|
|
79
|
+
- Declaring general target availability without satisfying every declared
|
|
80
|
+
full-target-support gate.
|
|
81
|
+
- Arbitrary Promise construction, arbitrary library awaits under Native
|
|
82
|
+
selection, JSPI, or Asyncify semantics. Managed `async` wrappers and trusted
|
|
83
|
+
Pulse awaits are supported notation, not a Promise runtime.
|
|
84
|
+
- Ambient `fetch`, environment variables, filesystem, process, sockets, or
|
|
85
|
+
timers.
|
|
86
|
+
- Provider SDK objects or `ctx.fastly` / `ctx.cloudflare` namespaces.
|
|
87
|
+
- Capability enumeration or runtime provider introspection.
|
|
88
|
+
- Automatic discovery of arbitrary TypeScript types.
|
|
89
|
+
- Dynamic schema IDs.
|
|
90
|
+
- Arbitrary binary body inspection or mutation.
|
|
91
|
+
- Userland chunk iteration, transform streams, or manual backpressure.
|
|
92
|
+
- Background tasks and work that outlives the request.
|
|
93
|
+
- Raw TCP or UDP sockets.
|
|
94
|
+
- Dynamic GRIP channel, framing-option, or message shapes under Native
|
|
95
|
+
selection.
|
|
96
|
+
- Onion-style post-`next()` middleware, assigning or awaiting `next()`, Router
|
|
97
|
+
`throw` transfer, realtime hooks, channels, timeout scopes, `ctx.resolve`, or
|
|
98
|
+
`ctx.resolved`.
|
|
99
|
+
- Third-party provider or lowerer self-registration.
|
|
100
|
+
- A public event listener, production event transport, delivery/retry
|
|
101
|
+
guarantee, automatic loopback or reentrancy, generic bus, `ctx.call`, or
|
|
102
|
+
request/reply event routing.
|
|
103
|
+
- Fastly, browser, or ESP32 event ingress/emit realization. Fastly fails closed
|
|
104
|
+
with exact eligibility diagnostics; browser and ESP32 remain unclaimed.
|
|
105
|
+
|
|
106
|
+
## Compatibility authority
|
|
107
|
+
|
|
108
|
+
The single source-form, provider-binding, artifact, and deployment-boundary
|
|
109
|
+
table is [Provider and target compatibility](https://pulsecompute.io/v1.0.0-beta.2/reference/compatibility-matrix/).
|
|
110
|
+
It uses one public target order—Node JavaScript, Fastly JavaScript, Node Native,
|
|
111
|
+
and Fastly Native—and links every row to a focused proof or canonical contract.
|
|
112
|
+
|
|
113
|
+
The exact portable language subset and the JavaScript-only Native eligibility
|
|
114
|
+
boundaries are defined in
|
|
115
|
+
[Managed handler TypeScript and JavaScript](https://pulsecompute.io/v1.0.0-beta.2/reference/handler-authoring/).
|
|
116
|
+
|
|
117
|
+
## Body model
|
|
118
|
+
|
|
119
|
+
If a body is inspected as text or JSON, Pulse treats it as a bounded immutable
|
|
120
|
+
value. If a body is passed through as binary or a stream, it remains an opaque
|
|
121
|
+
host-owned capability handle.
|
|
122
|
+
|
|
123
|
+
```text
|
|
124
|
+
inspect it → bounded structured value
|
|
125
|
+
pass it through → opaque handle
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Compatibility and release signals
|
|
129
|
+
|
|
130
|
+
- Documented behavior is intentional and evidence-backed.
|
|
131
|
+
- Unsupported behavior fails explicitly.
|
|
132
|
+
- No execution target silently falls back.
|
|
133
|
+
- Public surfaces may still change deliberately before stable `1.0.0`.
|
|
134
|
+
- Implementation and historical subpaths do not gain accidental compatibility
|
|
135
|
+
guarantees.
|
|
136
|
+
- Package names, release artifacts, and published versions are immutable once
|
|
137
|
+
released.
|
|
138
|
+
|
|
139
|
+
The intended npm dist-tag for the Beta is `beta`. It becomes
|
|
140
|
+
active only through the atomic documentation-release transaction and an
|
|
141
|
+
explicitly authorized publication. The workflow never assigns `latest`
|
|
142
|
+
implicitly.
|
package/package.json
CHANGED
|
@@ -1,15 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pulse-compute/runtime",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Inert namespace bootstrap for Pulse.",
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
5
4
|
"license": "Apache-2.0",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": "^22.14.0 || ^24.0.0"
|
|
7
|
+
},
|
|
8
|
+
"description": "Portable Pulse authoring and execution contract for handlers, contexts, and static routers.",
|
|
9
|
+
"type": "commonjs",
|
|
10
|
+
"main": "./src/index.js",
|
|
11
|
+
"types": "./src/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./src/index.d.ts",
|
|
15
|
+
"require": "./src/index.js",
|
|
16
|
+
"default": "./src/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./host": {
|
|
19
|
+
"types": "./src/host.d.ts",
|
|
20
|
+
"require": "./src/host.js",
|
|
21
|
+
"default": "./src/host.js"
|
|
22
|
+
},
|
|
23
|
+
"./package": {
|
|
24
|
+
"types": "./src/package.d.ts",
|
|
25
|
+
"require": "./src/package.js",
|
|
26
|
+
"default": "./src/package.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
6
29
|
"files": [
|
|
30
|
+
"src",
|
|
7
31
|
"README.md",
|
|
32
|
+
"docs",
|
|
8
33
|
"LICENSE",
|
|
9
34
|
"NOTICE"
|
|
10
35
|
],
|
|
11
36
|
"publishConfig": {
|
|
12
|
-
"access": "public"
|
|
13
|
-
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/pulse-compute/pulse.git",
|
|
42
|
+
"directory": "packages/runtime"
|
|
43
|
+
},
|
|
44
|
+
"homepage": "https://pulsecompute.io/v1.0.0-beta.2/packages/runtime/",
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/pulse-compute/pulse/issues"
|
|
14
47
|
}
|
|
15
|
-
}
|
|
48
|
+
}
|