@procedures/client 0.15.0 → 0.16.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 (85) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/adapters/http/server/handler.d.ts.map +1 -1
  4. package/dist/adapters/http/server/handler.js +5 -3
  5. package/dist/adapters/http/server/handler.js.map +1 -1
  6. package/dist/browser.d.ts +3 -2
  7. package/dist/browser.d.ts.map +1 -1
  8. package/dist/browser.js +1 -1
  9. package/dist/browser.js.map +1 -1
  10. package/dist/client/errors/registry.d.ts.map +1 -1
  11. package/dist/client/errors/registry.js +12 -0
  12. package/dist/client/errors/registry.js.map +1 -1
  13. package/dist/client/middleware/rate-limit.d.ts +17 -0
  14. package/dist/client/middleware/rate-limit.d.ts.map +1 -1
  15. package/dist/client/middleware/rate-limit.js +94 -39
  16. package/dist/client/middleware/rate-limit.js.map +1 -1
  17. package/dist/events/index.d.ts +1 -0
  18. package/dist/events/index.d.ts.map +1 -1
  19. package/dist/events/index.js.map +1 -1
  20. package/dist/events/publisher.d.ts +50 -5
  21. package/dist/events/publisher.d.ts.map +1 -1
  22. package/dist/events/publisher.js +99 -10
  23. package/dist/events/publisher.js.map +1 -1
  24. package/dist/events/recheck.d.ts +84 -0
  25. package/dist/events/recheck.d.ts.map +1 -0
  26. package/dist/events/recheck.js +135 -0
  27. package/dist/events/recheck.js.map +1 -0
  28. package/dist/procedures/collection/changes.d.ts +9 -8
  29. package/dist/procedures/collection/changes.d.ts.map +1 -1
  30. package/dist/procedures/collection/changes.js +11 -11
  31. package/dist/procedures/collection/changes.js.map +1 -1
  32. package/dist/procedures/collection/index.d.ts +1 -0
  33. package/dist/procedures/collection/index.d.ts.map +1 -1
  34. package/dist/procedures/collection/index.js +2 -0
  35. package/dist/procedures/collection/index.js.map +1 -1
  36. package/dist/procedures/collection/partition.d.ts +4 -23
  37. package/dist/procedures/collection/partition.d.ts.map +1 -1
  38. package/dist/procedures/collection/partition.js +2 -28
  39. package/dist/procedures/collection/partition.js.map +1 -1
  40. package/dist/procedures/collection/topic.d.ts +86 -0
  41. package/dist/procedures/collection/topic.d.ts.map +1 -0
  42. package/dist/procedures/collection/topic.js +94 -0
  43. package/dist/procedures/collection/topic.js.map +1 -0
  44. package/dist/procedures/index.d.ts +1 -1
  45. package/dist/procedures/index.d.ts.map +1 -1
  46. package/dist/procedures/index.js +1 -1
  47. package/dist/procedures/index.js.map +1 -1
  48. package/dist/protocol.d.ts +1 -1
  49. package/dist/protocol.d.ts.map +1 -1
  50. package/dist/protocol.js +1 -0
  51. package/dist/protocol.js.map +1 -1
  52. package/dist/server/host-policy.d.ts +17 -0
  53. package/dist/server/host-policy.d.ts.map +1 -1
  54. package/dist/server/host-policy.js +7 -0
  55. package/dist/server/host-policy.js.map +1 -1
  56. package/dist/server/limits.d.ts +122 -0
  57. package/dist/server/limits.d.ts.map +1 -0
  58. package/dist/server/limits.js +153 -0
  59. package/dist/server/limits.js.map +1 -0
  60. package/dist/server/procedure-server.d.ts +35 -3
  61. package/dist/server/procedure-server.d.ts.map +1 -1
  62. package/dist/server/procedure-server.js +42 -8
  63. package/dist/server/procedure-server.js.map +1 -1
  64. package/dist/server/request-auth.d.ts +5 -1
  65. package/dist/server/request-auth.d.ts.map +1 -1
  66. package/dist/server/request-auth.js +19 -2
  67. package/dist/server/request-auth.js.map +1 -1
  68. package/package.json +3 -3
  69. package/src/adapters/http/server/handler.ts +5 -3
  70. package/src/browser.ts +5 -0
  71. package/src/client/errors/registry.ts +13 -0
  72. package/src/client/middleware/rate-limit.ts +116 -41
  73. package/src/events/index.ts +1 -0
  74. package/src/events/publisher.ts +121 -12
  75. package/src/events/recheck.ts +182 -0
  76. package/src/procedures/collection/changes.ts +12 -11
  77. package/src/procedures/collection/index.ts +2 -0
  78. package/src/procedures/collection/partition.ts +5 -27
  79. package/src/procedures/collection/topic.ts +115 -0
  80. package/src/procedures/index.ts +1 -0
  81. package/src/protocol.ts +3 -1
  82. package/src/server/host-policy.ts +22 -0
  83. package/src/server/limits.ts +254 -0
  84. package/src/server/procedure-server.ts +59 -9
  85. package/src/server/request-auth.ts +19 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,96 @@
1
1
  # @procedures/client
2
2
 
3
+ ## 0.16.0
4
+
5
+ ### Minor Changes
6
+
7
+ - deada4b: The name of a collection with partitions can have a dot (roadmap CLI-42). In the topic of a partition, the name encodes `%` and `.`, so the name and the partition of each topic stay apart. This change is a break of the server stack, thus it is its own MINOR (decision D13, decision D22). No earlier release marks it as deprecated, because no export moves. Only the topic form of these names changes.
8
+
9
+ Before, `usePartitions` refused a name with a dot, because the topic `collections.<name>.<partition>` did not show where the name ends.
10
+
11
+ - In the topic of a partition, the name encodes `%` as `%25` and `.` as `%2E`. The first dot after the name thus ends the name. The partition stays as it is, and it can have each character, also `.`, `/` and `%`.
12
+ - `collectionChangeTopic()` makes each topic, and `collectionTopicPartition()` reads it back to the same name and the same partition.
13
+ - Only the canonical form of a topic counts. The parse gives a collection and a partition only when `collectionChangeTopic()` gives the same topic again. Thus `collections.a%2eb.t1` names no collection.
14
+ - `collectionTopicTarget()`, `collectionTopicReads()` and `EventPublisher` use the same parse. `collectionTopicReads(topic, repository)` takes the repository, as the default read check of the publisher does.
15
+ - New `collectionTopicRule(name)`: the topic rule of a collection for the option `topics` of `EventPublisher`. It gives the plain topic and the pattern of the topics of the partitions, for example `["collections.graph.nodes", "collections.graph%2Enodes.*"]`.
16
+ - The topic of a partition of a name without `%` and `.` does not change. The topic of a collection without a partition does not change.
17
+
18
+ The behavior that changes:
19
+
20
+ - A collection with partitions whose name has `%` gets a new topic for each partition. For example, the topic of the partition `t1` of `rate%` changes from `collections.rate%.t1` to `collections.rate%25.t1`.
21
+ - A collection with partitions whose name has `.` is new. Its topics of a partition have the encoded name, for example `collections.graph%2Enodes.acme/space`. A topic or a rule that joins the raw name, for example `collections.graph.nodes.*`, matches none of them.
22
+ - In a deployment with two versions, an old publisher and a new subscriber of such a name do not match. The reverse is also true.
23
+ - `collectionTopicReads()` gives no read for a topic that names no collection, for example `collections.notes.` with an empty partition.
24
+
25
+ Migration steps:
26
+
27
+ - For each collection with partitions whose name has `%` or `.`, upgrade the publishers and the subscribers together.
28
+ - Build each topic rule of a collection with `collectionTopicRule()`. Do not join the parts yourself.
29
+ - The site: no change is necessary. It has no collection with partitions.
30
+ - MiniMongo: no change is necessary. It has no collection with partitions.
31
+ - Graph: no change is necessary. Graph has dotted names of collections, but no dotted name has partitions yet. When a dotted name gets partitions, build the rule of `graph-host.ts` with `collectionTopicRule()`, not `collections.${c}.*`.
32
+ - jarvis: no change is necessary. It has no collection with partitions.
33
+
34
+ ## 0.15.1
35
+
36
+ ### Patch Changes
37
+
38
+ - c78da2d: The procedures server can limit the calls of each principal, tenant or route (server stack CLI-40). This change is additive. Without the new option, nothing changes. Thus it is a PATCH of the client group (decision D13).
39
+
40
+ The new behavior:
41
+
42
+ - `hostPolicy()` and `ProcedureServer` of `@procedures/client` have the new option `limits`. Each limit has a name, a key over the call, the calls that it covers, a limit policy, a store and a bound on its keys.
43
+ - The key is the principal, a claim of the principal (`{ claim: "tenant" }`), the route, a list of these, or a function of the call. A call without a value of its key is outside the limit.
44
+ - The option `covers` takes `{ writes: true }` for only the calls that can change data, `{ routes: [...] }` for some procedures, or a function of the call.
45
+ - Each limit is a keyed limiter of `@mark1russell7/service/limiter` (SYS-28) on the clock of the server. The option `limitStores` gives the stores that the replicas share.
46
+ - The server takes one unit of each limit that covers a call, after the authentication and before the run. This is one step for each face: HTTP, WebSocket, MCP and the calls in the process.
47
+ - A call above a limit gets the new error code `RATE_LIMITED` (retryable). Its metadata has the wait in `retry-after` (milliseconds) and the cause in `reason` (`limit`, `cap` or `store`). The call does not run.
48
+ - HTTP gives 429 with `Retry-After` in whole seconds. WebSocket gives the same code and metadata. MCP gives the code, `reason` and `retryAfterMs` in `_meta`.
49
+ - A circuit breaker does not count `RATE_LIMITED`, because the server is healthy.
50
+ - `createProcedureHost()` of `@procedures/peer` declares each limiter on its service with `svc.limiter()`. Thus `describe()` and `lint()` see it. `host.limiters` gives the limiters, and `ProcedureServer.limiters()` gives them too.
51
+ - The rate limit middleware of the client (`createRateLimitMiddleware`) uses the same keyed limiter. Its bucket, its queue and its statistics do not change. The new option `clock` gives the clock of the bucket and of the queue. The default is `Date.now()` and `setTimeout`, as before.
52
+ - The `Retry-After` header of the HTTP face rounds the wait up to whole seconds with the rule of `@mark1russell7/service`. A wait above a whole second only by an error of floating point does not add a second.
53
+ - The client packages use `@mark1russell7/service` 0.5.3 and `@mark1russell7/algebra` 0.7.2.
54
+
55
+ An example for the writes of each tenant:
56
+
57
+ ```ts
58
+ hostPolicy({
59
+ principalOf,
60
+ limits: [
61
+ {
62
+ name: "graph.writes",
63
+ key: { claim: "tenant" },
64
+ covers: { writes: true },
65
+ policy: { type: "sliding-window", limit: { value: 120, unit: "count" }, window: { value: 1, unit: "min" } },
66
+ store: { kind: "local" },
67
+ evict: { maxKeys: { value: 10000, unit: "count" } },
68
+ },
69
+ ],
70
+ });
71
+ ```
72
+ - d99b2d5: New: an open subscription can get the checks of its admission again (roadmap CLI-44). Before, `EventPublisher` examined the rights of a subscriber only at the start of `events.subscribe`. A subscription of a collection change feed thus continued after the app revoked a right.
73
+
74
+ `rightsChanged(change)` of `EventPublisher` starts a check of each open subscription that the change touches. The change is the id of a principal, a test of the principal, or no value for each subscription. The new option `recheck` of `EventPublisherOptions` has `maxAge`, a check after a time on the clock of the publisher. It also has `rightsChanges`, a source of the changes of the app.
75
+
76
+ The check is the same function as at the start: the topic rule, the reads, `allow` and the partition. While it operates, the events of the subscription wait. A refusal ends the subscription with its error, for example `FORBIDDEN`. The events that waited do not reach the subscriber. The new option `clock` of `EventPublisherOptions` is the clock of `maxAge`, and a `ProcedureServer` gives its own clock. Without a call of `rightsChanged()` and without the option `recheck`, nothing changes.
77
+ - 534e4ea: Fixed: `bearerOf` also reads the scheme of an `Authorization` header in another case (CLI-60). RFC 7235 makes the scheme case-insensitive, with one or more spaces (`1*SP`) before the token. Before, `bearerOf` read only a header that starts with `Bearer ` and one space, so a correct `bearer <token>` got 401.
78
+
79
+ Each header that `bearerOf` read before gives the same token. A correct header in another case passes too, also with more spaces before the token.
80
+
81
+ - A header that starts with `Bearer ` gives the rest of the header, as before.
82
+ - A header with the scheme in another case, for example `bearer` or `BEARER`, gives the token after one or more spaces. Spaces or tabs can come after the token. The token has no whitespace (`token68`).
83
+ - A tab between the scheme and the token is not `1*SP`, so it gives no token.
84
+ - `Basic x`, `Bearer` with no space and an empty header give no token, as before.
85
+ - The token comparison (`tokenMatches`) does not change.
86
+
87
+ Each user of `bearerOf` gets the change. These users are `credentialsOf`, `requestCredentials`, `procedureHandler` and the WebSocket server. The WebSocket admission of `createProcedureHost()`, `guardMcpRequest` and the credentials of the MCP face also get it.
88
+ - 44fdd60: `@types/ws` is a dependency of `@procedures/client`, not a development dependency (CLI-61). The published declarations of the WebSocket transports name the types of `ws`, which is a dependency. Before, a project that checks the declarations of its libraries (`skipLibCheck: false`) and had no `@types/ws` failed to compile. Now each install gets the types with `ws`.
89
+
90
+ The types of `express` stay an optional part, as `express` is an optional peer dependency. A project that checks library declarations and imports the root of the client needs `@types/express` until the next breaking release of the server stack (CLI-6 step 2), which takes the Express types out of the root.
91
+
92
+ PATCH: a dependency of the package changes, and no API changes.
93
+
3
94
  ## 0.15.0
4
95
 
5
96
  ### Minor Changes