@procedures/client 0.7.0 → 0.8.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.
Files changed (104) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/README.md +20 -3
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/adapters/http/server/transport.d.ts +6 -0
  5. package/dist/adapters/http/server/transport.d.ts.map +1 -1
  6. package/dist/adapters/http/server/transport.js +10 -1
  7. package/dist/adapters/http/server/transport.js.map +1 -1
  8. package/dist/adapters/websocket/client/transport.d.ts +7 -3
  9. package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
  10. package/dist/adapters/websocket/client/transport.js +9 -3
  11. package/dist/adapters/websocket/client/transport.js.map +1 -1
  12. package/dist/adapters/websocket/server/transport.d.ts +10 -0
  13. package/dist/adapters/websocket/server/transport.d.ts.map +1 -1
  14. package/dist/adapters/websocket/server/transport.js +22 -2
  15. package/dist/adapters/websocket/server/transport.js.map +1 -1
  16. package/dist/browser.d.ts +4 -4
  17. package/dist/browser.d.ts.map +1 -1
  18. package/dist/browser.js +1 -1
  19. package/dist/browser.js.map +1 -1
  20. package/dist/client/errors/registry.d.ts.map +1 -1
  21. package/dist/client/errors/registry.js +1 -0
  22. package/dist/client/errors/registry.js.map +1 -1
  23. package/dist/client/middleware/retry.d.ts +4 -0
  24. package/dist/client/middleware/retry.d.ts.map +1 -1
  25. package/dist/client/middleware/retry.js +86 -78
  26. package/dist/client/middleware/retry.js.map +1 -1
  27. package/dist/events/bus.d.ts +32 -14
  28. package/dist/events/bus.d.ts.map +1 -1
  29. package/dist/events/bus.js +119 -65
  30. package/dist/events/bus.js.map +1 -1
  31. package/dist/events/index.d.ts +3 -2
  32. package/dist/events/index.d.ts.map +1 -1
  33. package/dist/events/index.js.map +1 -1
  34. package/dist/events/publisher.d.ts.map +1 -1
  35. package/dist/events/publisher.js +20 -6
  36. package/dist/events/publisher.js.map +1 -1
  37. package/dist/events/remote.d.ts +80 -18
  38. package/dist/events/remote.d.ts.map +1 -1
  39. package/dist/events/remote.js +448 -58
  40. package/dist/events/remote.js.map +1 -1
  41. package/dist/events/types.d.ts +13 -2
  42. package/dist/events/types.d.ts.map +1 -1
  43. package/dist/procedures/caller.d.ts +33 -0
  44. package/dist/procedures/caller.d.ts.map +1 -0
  45. package/dist/procedures/caller.js +27 -0
  46. package/dist/procedures/caller.js.map +1 -0
  47. package/dist/procedures/collection/index.d.ts +2 -2
  48. package/dist/procedures/collection/index.d.ts.map +1 -1
  49. package/dist/procedures/collection/index.js +1 -1
  50. package/dist/procedures/collection/index.js.map +1 -1
  51. package/dist/procedures/collection/procedures.d.ts.map +1 -1
  52. package/dist/procedures/collection/procedures.js +21 -1
  53. package/dist/procedures/collection/procedures.js.map +1 -1
  54. package/dist/procedures/collection/schemas.d.ts +9 -0
  55. package/dist/procedures/collection/schemas.d.ts.map +1 -1
  56. package/dist/procedures/collection/schemas.js +28 -0
  57. package/dist/procedures/collection/schemas.js.map +1 -1
  58. package/dist/procedures/collection/storage.d.ts +6 -0
  59. package/dist/procedures/collection/storage.d.ts.map +1 -1
  60. package/dist/procedures/index.d.ts +3 -1
  61. package/dist/procedures/index.d.ts.map +1 -1
  62. package/dist/procedures/index.js +2 -0
  63. package/dist/procedures/index.js.map +1 -1
  64. package/dist/procedures/invoke.d.ts.map +1 -1
  65. package/dist/procedures/invoke.js +3 -0
  66. package/dist/procedures/invoke.js.map +1 -1
  67. package/dist/procedures/types.d.ts +50 -0
  68. package/dist/procedures/types.d.ts.map +1 -1
  69. package/dist/procedures/types.js.map +1 -1
  70. package/dist/protocol.d.ts +1 -1
  71. package/dist/protocol.d.ts.map +1 -1
  72. package/dist/protocol.js +1 -0
  73. package/dist/protocol.js.map +1 -1
  74. package/dist/server/procedure-server.d.ts +37 -3
  75. package/dist/server/procedure-server.d.ts.map +1 -1
  76. package/dist/server/procedure-server.js +86 -4
  77. package/dist/server/procedure-server.js.map +1 -1
  78. package/dist/timers.d.ts +5 -0
  79. package/dist/timers.d.ts.map +1 -1
  80. package/dist/timers.js +3 -1
  81. package/dist/timers.js.map +1 -1
  82. package/package.json +1 -1
  83. package/src/adapters/http/server/transport.ts +11 -1
  84. package/src/adapters/websocket/client/transport.ts +9 -3
  85. package/src/adapters/websocket/server/transport.ts +23 -2
  86. package/src/browser.ts +6 -0
  87. package/src/client/errors/registry.ts +1 -0
  88. package/src/client/middleware/retry.ts +89 -78
  89. package/src/events/bus.ts +141 -73
  90. package/src/events/index.ts +3 -0
  91. package/src/events/publisher.ts +23 -6
  92. package/src/events/remote.ts +575 -73
  93. package/src/events/types.ts +15 -2
  94. package/src/procedures/caller.ts +45 -0
  95. package/src/procedures/collection/index.ts +3 -0
  96. package/src/procedures/collection/procedures.ts +22 -0
  97. package/src/procedures/collection/schemas.ts +37 -0
  98. package/src/procedures/collection/storage.ts +6 -0
  99. package/src/procedures/index.ts +4 -0
  100. package/src/procedures/invoke.ts +2 -0
  101. package/src/procedures/types.ts +53 -0
  102. package/src/protocol.ts +3 -1
  103. package/src/server/procedure-server.ts +103 -6
  104. package/src/timers.ts +8 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,54 @@
1
1
  # @procedures/client
2
2
 
3
+ ## 0.8.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 4b09a03: `debounceChannel()` and `throttleChannel()` take a `Duration`, as every other time of the client does since 0.3.0. A plain number of milliseconds throws a `TypeError`. A new option `clock` gives the clock of their timers, for example a fake clock in a test. MINOR: a breaking change of a signature (the API is before 1.0.0).
8
+
9
+ Migration: `debounceChannel(bus, "in", "out", 300)` becomes `debounceChannel(bus, "in", "out", ms(300))`.
10
+ - 698e24d: Three gaps of the remote events (`documentation/EVENTS.md`) are closed. The option `backoff` of a subscription changes, so this release is breaking for a caller that gives it.
11
+
12
+ - **Shared subscriptions.** The subscribers of the same topics with the same options on one transport share one call: one `request` on the wire, with a count of its subscribers. Only the last unsubscribe sends the `cancel`. Before, each `subscribeRemote()`, `remoteEvents()` or `transport.subscribe()` made its own call. Each subscriber keeps its own id, its own `ready` and its own queue of at most 1024 events. A late subscriber gets no replay: its `ready` resolves at once, and its `seq` starts at 1. An error or an end of the shared call goes to each subscriber. `WebSocketServerTransport` shares the subscriptions of one connection.
13
+ - **The end at `clear()`.** `clear()` and `clearAll()` of the bus of the publisher end each subscription of a cleared topic. The subscriber first gets the events of the queue, then the error `TOPIC_CLEARED` (new protocol code, HTTP 410, not retryable) through `onError`, `ready` or the iterator. Before, the listeners went, and the subscriber saw no end. The new option `onClear` of `EventBus.on(channel, handler, { onClear })` (type `EventListenOptions`) gives the same notice to a local handler.
14
+ - **The limit of the resubscribe.** The new option `maxAttempts` (default 10) is the number of resubscribe tries without a confirmation. When the tries run out, the subscription ends with a `SubscriptionError` that has the code of the last failure. Before, a subscription over HTTP resubscribed forever. The WebSocket transport uses `reconnect.maxAttempts` (default `Infinity`), so its behavior stays. The new option `clock` is the clock of the backoff, for a fake clock in a test. `SubscriptionHooks` has the new fields `maxAttempts` and `clock`.
15
+
16
+ Migration: the option `backoff` is an object of durations (type `ResubscribeBackoff`), with the names of the `reconnect` options of `WebSocketTransport`: `initialDelay` (default `ms(250)`), `maxDelay` (default `seconds(30)`), `backoffMultiplier` (default 2) and `jitter` (default 1). Before, it was a function of milliseconds. A function or a plain number throws a `TypeError` at the call. For the old behavior over HTTP, give `maxAttempts: Infinity`.
17
+
18
+ ```ts
19
+ // Before
20
+ subscribeRemote(transport, "orders.created", handler, { backoff: (attempt) => Math.min(30_000, 500 * 2 ** (attempt - 1)) });
21
+ // Now
22
+ subscribeRemote(transport, "orders.created", handler, { backoff: { initialDelay: ms(500), maxDelay: seconds(30), jitter: 0 }, maxAttempts: Infinity });
23
+ ```
24
+ - d25805a: `ProcedureServer.useStorage` with `close` waits for the calls on the old storage before it closes it. Before, it closed the old storage at once, and a call that started on it could fail as closed.
25
+
26
+ MINOR: the call of `useStorage` with `close` can now take up to 30 seconds to resolve. That is a change of behaviour that a caller can see. Give `grace: ms(0)` for the old behaviour.
27
+
28
+ - The new calls use the new storage at once. The server waits only for the calls that took the old storage. A stream holds its storage until its end.
29
+ - The new option `grace` of `UseStorageOptions` is the longest wait, a `Duration`. A plain number throws a `TypeError`. The default is 30 seconds, `TIMER_DEFAULTS.server.storageGraceMs`. 0 closes at once.
30
+ - When the time ends, the server closes the old storage. A call that still uses it then fails with the error of a closed storage.
31
+ - The new option `clock` of `ProcedureServerOptions` is the clock of this wait. A test gives a fake clock.
32
+
33
+ ### Patch Changes
34
+
35
+ - 4b09a03: New `callerOf(...modules)` in the root and the browser entry. It gives a function that runs the procedures of the modules and gives one value. It makes the registry of the modules at the first call and does not use the global registry. An app wrote the three steps itself before: `createRegistry`, `invokePath` and `outputValue`. PATCH: a new export (the API is before 1.0.0).
36
+ - aa6e3aa: `ApiStorage` has `getIds()`. A full pull through it does not read each entry for the ids.
37
+
38
+ - The collections have the procedure `collections.<name>.ids`. It gives the ids in the order of the entries, without the values. Its effects read the collection and write nothing. A storage without `getIds()` gives the ids of its entries.
39
+ - The `CollectionStorage` of the core has the optional method `getIds()`, as the `CollectionStorage` of `@procedures/collections` has.
40
+ - `ApiStorage.getIds()` uses the procedure `ids`. An older server without it answers `NOT_FOUND`. Then the storage reads the ids from the entries, and it does not ask for `ids` again.
41
+ - `ApiStorageOptions.operations` takes `ids`, the name of the operation. The default is `ids`.
42
+ - 4b09a03: `bus.once()` rejects with an `AbortError` when `clear()` or `clearAll()` removes its channel. Before, its promise never settled.
43
+ - 600c497: A server on port 0 tells its real port.
44
+
45
+ - New `HttpServerTransport.port()` returns the port that the server listens on. With the option `port` 0, the system gives a free port, and the function returns that port.
46
+ - `peer.getEndpoints()` gives the real port of each HTTP and WebSocket endpoint. Before, a peer on port 0 gave the address `:0`.
47
+ - The tests of the body and the stop of the peer listen on port 0. Before, a helper found a free port and closed it before the peer took it, so one CI run failed with `EADDRINUSE`.
48
+ - 7c2e7f7: The `onAfterRetry` hook of `createRetryMiddleware` hears of a failure when the reader stops at the error item. A `Client` with `throwOnError` (the default) stops there. Before, the hook ran after the yield of that item, so it ran only for a success. Now it runs when the call ends: after the last item, or when the reader stops. A thrown error and an abort still do not call it. PATCH: a bug fix.
49
+ - 90ea741: A procedure can declare its rules under a root of the files in `metadata.fsRoot` (the new type `FsRootRules`): the inputs that name a path, or the reason that a root cannot confine it. A handler gets `ctx.caller`, the procedure whose handler made the nested call. The framework sets it from the invocation, so an input cannot change it (roadmap R33).
50
+ - c4cfa34: `ProcedureServer.useStorage` with `close` keeps an old storage open while another collection still uses it. The server closes it when the last collection leaves it. Before, the close broke the calls of the other collection.
51
+
3
52
  ## 0.7.0
4
53
 
5
54
  ### Minor Changes
package/README.md CHANGED
@@ -179,6 +179,18 @@ const getUserProcedure = defineProcedure({
179
179
  registerProcedures([getUserProcedure]);
180
180
  ```
181
181
 
182
+ ### Procedures of a package in the same process
183
+
184
+ `callerOf(...modules)` gives a function that runs the procedures of the modules. It makes the registry of the modules at the first call, and it does not use the global registry. Each call gives one value: the output, or the last item of a stream.
185
+
186
+ ```typescript
187
+ import { callerOf } from "@procedures/client";
188
+ import { ghModule } from "@procedures/gh";
189
+
190
+ const gh = callerOf(ghModule);
191
+ const runs = await gh<RunList>(["gh", "run", "list"], { repo: "owner/name" });
192
+ ```
193
+
182
194
  ## API Reference
183
195
 
184
196
  ### Client
@@ -289,7 +301,7 @@ await toClient.call({ service: "ui", operation: "notify" }, { text: "Build done"
289
301
  // function gives the unsubscribe. After a drop, the transport resubscribes on the new connection.
290
302
  const unsubscribe = transport.subscribe("orders.created", (order, event) => console.log(event.seq, order), {
291
303
  onSubscribed: (topics) => console.log("subscribed", topics),
292
- onError: (error) => console.error(error.code), // TOPIC_NOT_FOUND, FORBIDDEN, NOT_FOUND
304
+ onError: (error) => console.error(error.code), // TOPIC_NOT_FOUND, FORBIDDEN, NOT_FOUND, TOPIC_CLEARED
293
305
  });
294
306
  await unsubscribe.ready;
295
307
  unsubscribe();
@@ -531,7 +543,10 @@ const server = new ProcedureServer({
531
543
  server.publish("orders.created", { order: 1 }) // the same as bus.emit()
532
544
 
533
545
  // The subscriber, over each transport
534
- const unsubscribe = subscribeRemote(transport, "orders.created", (order, event) => console.log(order, event.seq))
546
+ const unsubscribe = subscribeRemote(transport, "orders.created", (order, event) => console.log(order, event.seq), {
547
+ maxAttempts: 10, // the resubscribe tries without a confirmation (default 10; WebSocket: reconnect.maxAttempts)
548
+ backoff: { initialDelay: ms(250), maxDelay: seconds(30), backoffMultiplier: 2, jitter: 1 }, // Durations: a plain number throws a TypeError
549
+ })
535
550
  for await (const event of remoteEvents(transport, ["orders.created"], { signal })) console.log(event.data)
536
551
 
537
552
  // The server subscribes to the bus of a client: the client serves it with `serve`
@@ -541,7 +556,9 @@ wsServer.subscribe(connectionId, "ui.clicked", (click) => console.log(click))
541
556
 
542
557
  - 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
558
  - 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.
559
+ - `ProcedureServer.stop()` ends each subscription with `UNAVAILABLE`, and the subscriber resubscribes later, at most `maxAttempts` times without a confirmation.
560
+ - `clear()` or `clearAll()` of the bus ends each subscription of a cleared topic with `TOPIC_CLEARED`. The subscriber does not resubscribe. `bus.on(channel, handler, { onClear })` gives the same notice to a local handler.
561
+ - The subscribers of the same topics with the same options on one transport share one call. The last unsubscribe sends the cancel. A late subscriber gets no replay: its `ready` resolves at once, and its `seq` starts at 1.
545
562
  - `events.subscribe` is not in a registry: it is not an MCP tool.
546
563
 
547
564
  ### Server