@procedures/client 0.4.0 → 0.5.0
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/CHANGELOG.md +39 -0
- package/README.md +46 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapters/http/client/transport.d.ts +2 -1
- package/dist/adapters/http/client/transport.d.ts.map +1 -1
- package/dist/adapters/http/client/transport.js +9 -2
- package/dist/adapters/http/client/transport.js.map +1 -1
- package/dist/adapters/http/server/transport.d.ts +3 -1
- package/dist/adapters/http/server/transport.d.ts.map +1 -1
- package/dist/adapters/http/server/transport.js +6 -3
- package/dist/adapters/http/server/transport.js.map +1 -1
- package/dist/adapters/local/client/transport.d.ts +2 -1
- package/dist/adapters/local/client/transport.d.ts.map +1 -1
- package/dist/adapters/local/client/transport.js +8 -2
- package/dist/adapters/local/client/transport.js.map +1 -1
- package/dist/adapters/local/client/types.d.ts +6 -0
- package/dist/adapters/local/client/types.d.ts.map +1 -1
- package/dist/adapters/local/client/types.js.map +1 -1
- package/dist/adapters/sequence.d.ts +36 -0
- package/dist/adapters/sequence.d.ts.map +1 -0
- package/dist/adapters/sequence.js +55 -0
- package/dist/adapters/sequence.js.map +1 -0
- package/dist/adapters/websocket/client/transport.d.ts +39 -1
- package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/client/transport.js +102 -7
- package/dist/adapters/websocket/client/transport.js.map +1 -1
- package/dist/adapters/websocket/client/types.d.ts +12 -3
- package/dist/adapters/websocket/client/types.d.ts.map +1 -1
- package/dist/adapters/websocket/client/types.js.map +1 -1
- package/dist/adapters/websocket/server/transport.d.ts +22 -1
- package/dist/adapters/websocket/server/transport.d.ts.map +1 -1
- package/dist/adapters/websocket/server/transport.js +29 -1
- package/dist/adapters/websocket/server/transport.js.map +1 -1
- package/dist/adapters/websocket/server/types.d.ts +6 -0
- package/dist/adapters/websocket/server/types.d.ts.map +1 -1
- package/dist/adapters/websocket/shared/rpc.d.ts +4 -3
- package/dist/adapters/websocket/shared/rpc.d.ts.map +1 -1
- package/dist/adapters/websocket/shared/rpc.js +18 -9
- package/dist/adapters/websocket/shared/rpc.js.map +1 -1
- package/dist/browser.d.ts +3 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +4 -0
- package/dist/browser.js.map +1 -1
- package/dist/client/errors/registry.d.ts.map +1 -1
- package/dist/client/errors/registry.js +1 -0
- package/dist/client/errors/registry.js.map +1 -1
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js +3 -0
- package/dist/events/index.js.map +1 -1
- package/dist/events/publisher.d.ts +95 -0
- package/dist/events/publisher.d.ts.map +1 -0
- package/dist/events/publisher.js +268 -0
- package/dist/events/publisher.js.map +1 -0
- package/dist/events/remote.d.ts +164 -0
- package/dist/events/remote.d.ts.map +1 -0
- package/dist/events/remote.js +250 -0
- package/dist/events/remote.js.map +1 -0
- package/dist/procedures/collection/index.d.ts +1 -1
- package/dist/procedures/collection/index.d.ts.map +1 -1
- package/dist/procedures/collection/index.js.map +1 -1
- package/dist/procedures/collection/procedures.d.ts.map +1 -1
- package/dist/procedures/collection/procedures.js +6 -1
- package/dist/procedures/collection/procedures.js.map +1 -1
- package/dist/procedures/collection/schemas.d.ts +16 -1
- package/dist/procedures/collection/schemas.d.ts.map +1 -1
- package/dist/procedures/collection/schemas.js +13 -2
- package/dist/procedures/collection/schemas.js.map +1 -1
- package/dist/procedures/collection/storage.d.ts +14 -2
- package/dist/procedures/collection/storage.d.ts.map +1 -1
- package/dist/procedures/invoke.d.ts +4 -2
- package/dist/procedures/invoke.d.ts.map +1 -1
- package/dist/procedures/invoke.js +1 -1
- package/dist/procedures/invoke.js.map +1 -1
- package/dist/protocol.d.ts +1 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +1 -0
- package/dist/protocol.js.map +1 -1
- package/dist/server/host-policy.d.ts +11 -0
- package/dist/server/host-policy.d.ts.map +1 -1
- package/dist/server/host-policy.js +5 -0
- package/dist/server/host-policy.js.map +1 -1
- package/dist/server/procedure-server.d.ts +24 -2
- package/dist/server/procedure-server.d.ts.map +1 -1
- package/dist/server/procedure-server.js +34 -4
- package/dist/server/procedure-server.js.map +1 -1
- package/package.json +3 -3
- package/src/adapters/http/client/transport.ts +9 -2
- package/src/adapters/http/server/transport.ts +6 -3
- package/src/adapters/local/client/transport.ts +8 -2
- package/src/adapters/local/client/types.ts +7 -0
- package/src/adapters/sequence.ts +55 -0
- package/src/adapters/websocket/client/transport.ts +108 -7
- package/src/adapters/websocket/client/types.ts +13 -3
- package/src/adapters/websocket/server/transport.ts +43 -1
- package/src/adapters/websocket/server/types.ts +7 -0
- package/src/adapters/websocket/shared/rpc.ts +19 -9
- package/src/browser.ts +15 -0
- package/src/client/errors/registry.ts +1 -0
- package/src/events/index.ts +16 -0
- package/src/events/publisher.ts +314 -0
- package/src/events/remote.ts +369 -0
- package/src/procedures/collection/index.ts +1 -0
- package/src/procedures/collection/procedures.ts +6 -1
- package/src/procedures/collection/schemas.ts +28 -2
- package/src/procedures/collection/storage.ts +14 -2
- package/src/procedures/invoke.ts +4 -2
- package/src/protocol.ts +3 -1
- package/src/server/host-policy.ts +14 -0
- package/src/server/procedure-server.ts +41 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# @procedures/client
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 09e5566: Remote events (`documentation/EVENTS.md`): a peer subscribes to the topics of the event bus of another peer. A subscription is a streaming call of the procedure `events.subscribe`, so it uses the frames of each call: credit is the backpressure, and a cancel is the unsubscribe. It works over WebSocket in the two directions, HTTP with NDJSON, a message port and the local transport. The protocol stays v1.
|
|
8
|
+
|
|
9
|
+
- `WebSocketTransport.subscribe(topics, handler)` gives the unsubscribe function, with the `ready` promise of the first confirmation. `WebSocketTransport.events(topics)` gives an async iterator. After a drop, the transport resubscribes on the new connection.
|
|
10
|
+
- `subscribeRemote()` and `remoteEvents()` do the same over each transport. After a failure that a retry can repair, they resubscribe with a backoff.
|
|
11
|
+
- `ProcedureServer` has the option `events`: a bus, a topic rule (`topics`), an `allow` function and a `buffer`. The server pins `events.subscribe` outside its registry, so it is not an MCP tool. `ProcedureServer.publish()` emits on the bus. `stop()` ends each subscription with `UNAVAILABLE`.
|
|
12
|
+
- `WebSocketServerTransport.subscribe(connectionId, topics, handler)` and `events(connectionId, topics)` subscribe to the bus of a client. `LocalTransport` takes an `EventPublisher` with its option `events`.
|
|
13
|
+
- The delivery is at most once, in the order of `emit()`. When the queue of a slow subscriber is full, the publisher drops the oldest event, and the next event tells the loss (`dropped`).
|
|
14
|
+
- The new error code `TOPIC_NOT_FOUND` (404) is for a topic outside the topic rule. A topic that `allow` refuses gives `FORBIDDEN` with the reason `topic-not-allowed`.
|
|
15
|
+
- The `onEvent` option of `WebSocketTransport` is now a wrapper: it gets each event of each subscription of the transport. A raw `event` frame still goes to it.
|
|
16
|
+
- The WebSocket client does not warn about a `stream` frame of a call that it cancelled. The WebSocket server ignores a late `stream`, `response` or `error` frame of a call that it stopped. Before, it answered such a frame with an `error` frame.
|
|
17
|
+
- ab77f75: Sequence numbers of the stream frames (`documentation/WIRE-PROTOCOL.md`). Before, a duplicate `stream` frame gave a duplicate item. The change is additive, and the protocol stays v1.
|
|
18
|
+
|
|
19
|
+
- Each `stream` frame has the field `seq`: 1 in the first frame of a call, and one more in each next frame. The end frame has a number too. Each NDJSON line `item` or `done` has the same field.
|
|
20
|
+
- The receiver drops a frame whose `seq` is not above the last one. Thus a duplicate frame or a late frame gives no item.
|
|
21
|
+
- A gap does not end the stream, because the delivery is at most once. The next item has the number of lost frames in the metadata key `stream-gap` (`STREAM_GAP_METADATA_KEY`), and the console gets a warning. The receiver gives back the credit of the lost frames.
|
|
22
|
+
- A frame without `seq` comes from an older peer. The receiver takes it as before.
|
|
23
|
+
- The rules apply to WebSocket in the two directions, the message port and HTTP with NDJSON. The local transport has no frames.
|
|
24
|
+
- `WebSocketMessage` has the optional field `seq`.
|
|
25
|
+
- a47bee6: The hosts serve the remote events (`documentation/EVENTS.md`).
|
|
26
|
+
|
|
27
|
+
- `hostPolicy()` takes the option `events`: the topic rule, with an optional bus, `allow` function and buffer. `procedureServerOptions()` gives it to the `ProcedureServer`, which pins `events.subscribe`. `HostPolicy` has the new field `events`.
|
|
28
|
+
- `procedure-server` and `mark serve` have the option `--events <patterns>`. The option is repeatable, and it takes comma-separated patterns: exact names, prefixes (`orders.*`) or `*`. `parseTopicPatterns()` checks them.
|
|
29
|
+
- `mark --server` has the same option `--events`.
|
|
30
|
+
- These hosts always serve `events.subscribe`. Without `--events`, they serve no topic, and each subscription gets `TOPIC_NOT_FOUND`. The bus is the global bus, which is also the `ctx.bus` of their procedures.
|
|
31
|
+
- The MCP server serves no events, because its transport carries only MCP.
|
|
32
|
+
- `mark --port`, `--host`, `--transport` and `--events` without `--server` are an error now, also before `serve` and `mcp`. Before, `mark --port 4000 serve` ignored `--port`.
|
|
33
|
+
- bc74091: Two changes for the contract of `CollectionStorage`:
|
|
34
|
+
|
|
35
|
+
- The collection procedure `collections.<name>.get` takes the input `found: true`. Then its output is `{ found, value }`, so a stored `null` and a missing id give different outputs in one call. Without `found`, the output is the item, as before.
|
|
36
|
+
- `ProcedureServer.stop()` and `closeStorages()` close each storage one time, also a storage of two collections, and remove the storages from the server. Before, a server that started again used the closed storages.
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- 0f75644: The dependencies go to `@mark1russell7/algebra` `^0.7.0` and `@mark1russell7/service` `^0.4.1`. A host that uses algebra 0.7.0 gets one copy of it. Algebra 0.7.0 only adds to 0.6.0.
|
|
41
|
+
|
|
3
42
|
## 0.4.0
|
|
4
43
|
|
|
5
44
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ The core depends on no other package of the repository. The procedure components
|
|
|
27
27
|
- **Type-Safe Procedures**: Schema-validated procedures with auto-discovery and registry management
|
|
28
28
|
- **Middleware System**: Composable middleware for retry, cache, timeout, circuit breaker, rate limiting, auth, tracing, and validation
|
|
29
29
|
- **Procedure-as-Data**: JSON programs of calls, references and control flow ([PROGRAM-FORMAT.md](../documentation/PROGRAM-FORMAT.md))
|
|
30
|
-
- **Event Bus**: Pub/sub messaging with async iteration support
|
|
30
|
+
- **Event Bus**: Pub/sub messaging with async iteration support. A peer subscribes to the bus of another peer over each transport ([EVENTS.md](../documentation/EVENTS.md))
|
|
31
31
|
- **Error System**: 70+ error codes with rich metadata and recovery suggestions
|
|
32
32
|
|
|
33
33
|
## Installation
|
|
@@ -284,6 +284,17 @@ new WebSocketServerTransport(server, { server: http, heartbeat: { interval: seco
|
|
|
284
284
|
const transport = new WebSocketTransport({ url, serve: new ProcedureServer({ registry: uiRegistry, autoRegister: true }) });
|
|
285
285
|
const toClient = new Client({ transport: wsServer.transportFor(connectionId) }); // or peer.clientFor(id)
|
|
286
286
|
await toClient.call({ service: "ui", operation: "notify" }, { text: "Build done" });
|
|
287
|
+
|
|
288
|
+
// Remote events (documentation/EVENTS.md): subscribe to topics of the bus of the server. The
|
|
289
|
+
// function gives the unsubscribe. After a drop, the transport resubscribes on the new connection.
|
|
290
|
+
const unsubscribe = transport.subscribe("orders.created", (order, event) => console.log(event.seq, order), {
|
|
291
|
+
onSubscribed: (topics) => console.log("subscribed", topics),
|
|
292
|
+
onError: (error) => console.error(error.code), // TOPIC_NOT_FOUND, FORBIDDEN, NOT_FOUND
|
|
293
|
+
});
|
|
294
|
+
await unsubscribe.ready;
|
|
295
|
+
unsubscribe();
|
|
296
|
+
// The same events as an async iterator: a break or the signal unsubscribes
|
|
297
|
+
for await (const event of transport.events(["orders.created", "orders.paid"], { signal })) console.log(event.topic, event.data);
|
|
287
298
|
```
|
|
288
299
|
|
|
289
300
|
#### `LocalTransport`
|
|
@@ -500,6 +511,39 @@ const unsubscribe = bus.on("event", handler)
|
|
|
500
511
|
unsubscribe()
|
|
501
512
|
```
|
|
502
513
|
|
|
514
|
+
#### Remote events
|
|
515
|
+
|
|
516
|
+
A peer subscribes to the topics of the bus of another peer ([EVENTS.md](../documentation/EVENTS.md)). A subscription is a streaming call of the procedure `events.subscribe`, so it works over WebSocket (in the two directions), HTTP with NDJSON, a message port and the local transport.
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
// The publisher: a ProcedureServer with the option events
|
|
520
|
+
const bus = createEventBus()
|
|
521
|
+
const server = new ProcedureServer({
|
|
522
|
+
registry,
|
|
523
|
+
autoRegister: true,
|
|
524
|
+
events: {
|
|
525
|
+
bus, // the procedures of the server get it as ctx.bus
|
|
526
|
+
topics: ["orders.*", "system:*"], // the topic rule: an exact name, a prefix with *, or *
|
|
527
|
+
allow: (topic, call) => !topic.startsWith("system:") || call.capability.clearance === "admin",
|
|
528
|
+
buffer: 1024, // the events that one subscription holds for a slow subscriber
|
|
529
|
+
},
|
|
530
|
+
})
|
|
531
|
+
server.publish("orders.created", { order: 1 }) // the same as bus.emit()
|
|
532
|
+
|
|
533
|
+
// The subscriber, over each transport
|
|
534
|
+
const unsubscribe = subscribeRemote(transport, "orders.created", (order, event) => console.log(order, event.seq))
|
|
535
|
+
for await (const event of remoteEvents(transport, ["orders.created"], { signal })) console.log(event.data)
|
|
536
|
+
|
|
537
|
+
// The server subscribes to the bus of a client: the client serves it with `serve`
|
|
538
|
+
new WebSocketTransport({ url, serve: new ProcedureServer({ events: { bus: clientBus, topics: ["ui.*"] } }) })
|
|
539
|
+
wsServer.subscribe(connectionId, "ui.clicked", (click) => console.log(click))
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
- The delivery is at most once, in the order of `emit()`. `seq` numbers the events of a subscription, and `dropped` tells the events that the publisher dropped for a slow subscriber.
|
|
543
|
+
- A topic outside the topic rule gives `TOPIC_NOT_FOUND`. A topic that `allow` refuses gives `FORBIDDEN` with the reason `topic-not-allowed`. The procedure reads the resource `events`, so the capability of the host applies to it.
|
|
544
|
+
- `ProcedureServer.stop()` ends each subscription with `UNAVAILABLE`, and the subscriber resubscribes later.
|
|
545
|
+
- `events.subscribe` is not in a registry: it is not an MCP tool.
|
|
546
|
+
|
|
503
547
|
### Server
|
|
504
548
|
|
|
505
549
|
```typescript
|
|
@@ -550,6 +594,7 @@ interface ProcedureServerOptions {
|
|
|
550
594
|
registry?: ProcedureRegistry;
|
|
551
595
|
storage?: StorageConfig;
|
|
552
596
|
transports?: ServerTransport[];
|
|
597
|
+
events?: EventPublisherOptions | EventPublisher; // the remote events: refer to "Remote events"
|
|
553
598
|
}
|
|
554
599
|
```
|
|
555
600
|
|