@gjermundgaraba/effect-actions 0.19.0 → 0.21.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 (326) hide show
  1. package/README.md +19 -41
  2. package/dist/Action.d.mts +140 -48
  3. package/dist/Action.mjs +88 -44
  4. package/dist/ActionCli.d.mts +70 -35
  5. package/dist/ActionCli.mjs +53 -34
  6. package/dist/ActionHttp.d.mts +70 -38
  7. package/dist/ActionHttp.mjs +76 -25
  8. package/dist/ActionMcp.d.mts +56 -24
  9. package/dist/ActionMcp.mjs +104 -61
  10. package/dist/ActionRpc.d.mts +222 -57
  11. package/dist/ActionRpc.mjs +301 -49
  12. package/dist/ActionToolkit.d.mts +22 -7
  13. package/dist/ActionToolkit.mjs +37 -14
  14. package/dist/Authentication.d.mts +42 -12
  15. package/dist/Authentication.mjs +38 -32
  16. package/dist/Event.d.mts +370 -0
  17. package/dist/Event.mjs +103 -0
  18. package/dist/Testing.d.mts +1 -3
  19. package/dist/Testing.mjs +2 -3
  20. package/dist/Webhook.d.mts +146 -0
  21. package/dist/Webhook.mjs +72 -0
  22. package/dist/authentication/provider.d.mts +35 -12
  23. package/dist/authentication/provider.mjs +2 -3
  24. package/dist/authentication/refusal.mjs +3 -4
  25. package/dist/cli/commands.d.mts +9 -7
  26. package/dist/cli/commands.mjs +85 -35
  27. package/dist/contract/ast.mjs +5 -3
  28. package/dist/contract/authorizer.d.mts +8 -0
  29. package/dist/contract/authorizer.mjs +20 -0
  30. package/dist/contract/call.d.mts +9 -8
  31. package/dist/contract/call.mjs +49 -8
  32. package/dist/contract/callback.d.mts +7 -0
  33. package/dist/contract/callback.mjs +27 -0
  34. package/dist/contract/caller.d.mts +12 -3
  35. package/dist/contract/caller.mjs +23 -5
  36. package/dist/contract/canonical.mjs +10 -0
  37. package/dist/contract/codec.d.mts +9 -0
  38. package/dist/contract/codec.mjs +9 -0
  39. package/dist/contract/codes.mjs +81 -0
  40. package/dist/contract/declared.d.mts +0 -2
  41. package/dist/contract/declared.mjs +26 -11
  42. package/dist/contract/digest.mjs +6 -0
  43. package/dist/contract/errors.d.mts +9 -5
  44. package/dist/contract/errors.mjs +2 -3
  45. package/dist/contract/feed.d.mts +127 -0
  46. package/dist/contract/feed.mjs +249 -0
  47. package/dist/contract/hints.mjs +1 -2
  48. package/dist/contract/hub.d.mts +94 -0
  49. package/dist/contract/hub.mjs +133 -0
  50. package/dist/contract/idempotency.d.mts +47 -0
  51. package/dist/contract/idempotency.mjs +99 -0
  52. package/dist/contract/implementation.d.mts +73 -51
  53. package/dist/contract/implementation.mjs +94 -60
  54. package/dist/contract/input-check.d.mts +15 -0
  55. package/dist/contract/input-check.mjs +16 -0
  56. package/dist/contract/lease.mjs +28 -0
  57. package/dist/contract/listed.d.mts +4 -0
  58. package/dist/contract/listed.mjs +22 -0
  59. package/dist/contract/log.d.mts +41 -0
  60. package/dist/contract/log.mjs +144 -0
  61. package/dist/contract/media.d.mts +1 -3
  62. package/dist/contract/media.mjs +1 -2
  63. package/dist/contract/names.mjs +15 -6
  64. package/dist/contract/occurrence.d.mts +29 -0
  65. package/dist/contract/occurrence.mjs +45 -0
  66. package/dist/contract/pages.d.mts +13 -0
  67. package/dist/contract/pages.mjs +39 -0
  68. package/dist/contract/progress.d.mts +26 -0
  69. package/dist/contract/progress.mjs +72 -0
  70. package/dist/contract/push.d.mts +20 -0
  71. package/dist/contract/push.mjs +96 -0
  72. package/dist/contract/receiving.d.mts +29 -0
  73. package/dist/contract/receiving.mjs +42 -0
  74. package/dist/contract/recent.mjs +12 -0
  75. package/dist/contract/reported.mjs +16 -0
  76. package/dist/contract/serving.mjs +63 -0
  77. package/dist/contract/status.mjs +15 -7
  78. package/dist/contract/stream.d.mts +34 -0
  79. package/dist/contract/stream.mjs +31 -0
  80. package/dist/contract/subscribe.d.mts +45 -0
  81. package/dist/contract/subscribe.mjs +50 -0
  82. package/dist/contract/transient.mjs +28 -0
  83. package/dist/contract/watch.d.mts +18 -0
  84. package/dist/contract/watch.mjs +105 -0
  85. package/dist/contract/webhooks.d.mts +42 -0
  86. package/dist/contract/webhooks.mjs +53 -0
  87. package/dist/http/client.d.mts +37 -14
  88. package/dist/http/client.mjs +52 -14
  89. package/dist/http/events.d.mts +56 -0
  90. package/dist/http/events.mjs +102 -0
  91. package/dist/http/placed.d.mts +36 -0
  92. package/dist/http/placed.mjs +71 -0
  93. package/dist/http/schema-errors.mjs +2 -3
  94. package/dist/http/streamed.d.mts +21 -0
  95. package/dist/http/streamed.mjs +94 -0
  96. package/dist/http/watch.mjs +50 -0
  97. package/dist/mcp/bridge.mjs +283 -0
  98. package/dist/mcp/client.d.mts +30 -99
  99. package/dist/mcp/client.mjs +60 -134
  100. package/dist/mcp/events.mjs +142 -0
  101. package/dist/mcp/progress.mjs +34 -0
  102. package/dist/mcp/protocol.mjs +40 -15
  103. package/dist/mcp/reply.d.mts +79 -0
  104. package/dist/mcp/reply.mjs +99 -0
  105. package/dist/mcp/request.d.mts +40 -0
  106. package/dist/mcp/request.mjs +51 -0
  107. package/dist/mcp/watch.mjs +115 -0
  108. package/dist/rpc/watch.mjs +39 -0
  109. package/dist/stdio/console.mjs +14 -7
  110. package/dist/testing/memory.d.mts +1 -3
  111. package/dist/testing/memory.mjs +4 -5
  112. package/dist/webhook/address.mjs +47 -0
  113. package/dist/webhook/attempt.mjs +65 -0
  114. package/dist/webhook/receiver.mjs +67 -0
  115. package/dist/webhook/signing.mjs +28 -0
  116. package/dist/webhook/stored.mjs +57 -0
  117. package/dist/webhook/subscriptions.mjs +342 -0
  118. package/docs/Action-failures.md +2 -2
  119. package/docs/Action-streams.md +115 -0
  120. package/docs/Action.md +58 -124
  121. package/docs/ActionCli-failures.md +1 -2
  122. package/docs/ActionCli.md +83 -88
  123. package/docs/ActionHttp-failures.md +3 -3
  124. package/docs/ActionHttp.md +90 -70
  125. package/docs/ActionMcp-failures.md +2 -1
  126. package/docs/ActionMcp.md +120 -92
  127. package/docs/ActionRpc-events.md +126 -0
  128. package/docs/ActionRpc-failures.md +1 -2
  129. package/docs/ActionRpc.md +108 -79
  130. package/docs/ActionToolkit-failures.md +1 -2
  131. package/docs/ActionToolkit.md +33 -90
  132. package/docs/Authentication-advanced.md +57 -61
  133. package/docs/Authentication-failures.md +5 -4
  134. package/docs/Authentication.md +23 -58
  135. package/docs/Event-failures.md +15 -0
  136. package/docs/Event.md +281 -0
  137. package/docs/README.md +51 -82
  138. package/docs/Testing-failures.md +1 -5
  139. package/docs/Testing.md +126 -86
  140. package/docs/Webhook-failures.md +8 -0
  141. package/docs/Webhook.md +319 -0
  142. package/docs/setup-failures.md +2 -3
  143. package/docs/setup.md +32 -53
  144. package/examples/README.md +12 -37
  145. package/examples/assistant/README.md +21 -26
  146. package/examples/assistant/src/agent.ts +66 -24
  147. package/examples/assistant/src/cli.ts +7 -4
  148. package/examples/assistant/src/commands.ts +9 -4
  149. package/examples/assistant/src/identity/Identity.ts +5 -4
  150. package/examples/assistant/src/identity/authorize.ts +13 -5
  151. package/examples/assistant/src/identity/handlers.ts +3 -2
  152. package/examples/assistant/src/identity/permissions.ts +9 -3
  153. package/examples/assistant/src/platform/tasks-file.ts +15 -11
  154. package/examples/assistant/src/scripted.ts +7 -4
  155. package/examples/assistant/src/tasks/Tasks.ts +20 -6
  156. package/examples/assistant/src/tasks/handlers.ts +9 -5
  157. package/examples/assistant/src/tasks/store.ts +38 -11
  158. package/examples/assistant/src/toolkit.ts +11 -7
  159. package/examples/assistant/test/commands.test.ts +53 -27
  160. package/examples/assistant/test/identity/identity.test.ts +27 -11
  161. package/examples/assistant/test/platform/tasks-file.test.ts +39 -23
  162. package/examples/assistant/test/tasks/tasks.test.ts +62 -34
  163. package/examples/assistant/test/toolkit.test.ts +104 -75
  164. package/examples/build-events/README.md +83 -0
  165. package/examples/build-events/src/Api.ts +27 -0
  166. package/examples/build-events/src/Rpc.ts +26 -0
  167. package/examples/build-events/src/builds/Builds.ts +108 -0
  168. package/examples/build-events/src/builds/events.ts +54 -0
  169. package/examples/build-events/src/builds/handlers.ts +58 -0
  170. package/examples/build-events/src/builds/log.ts +30 -0
  171. package/examples/build-events/src/builds/status.ts +28 -0
  172. package/examples/build-events/src/builds/store.ts +130 -0
  173. package/examples/build-events/src/cli.ts +18 -0
  174. package/examples/build-events/src/commands.ts +32 -0
  175. package/examples/build-events/src/deploys/Deploys.ts +44 -0
  176. package/examples/build-events/src/deploys/approvers.ts +55 -0
  177. package/examples/build-events/src/deploys/events.ts +32 -0
  178. package/examples/build-events/src/deploys/handlers.ts +38 -0
  179. package/examples/build-events/src/identity/Identity.ts +29 -0
  180. package/examples/build-events/src/identity/members.ts +7 -0
  181. package/examples/build-events/src/identity/verifier.ts +22 -0
  182. package/examples/build-events/src/notifier/Notices.ts +26 -0
  183. package/examples/build-events/src/notifier/routes.ts +71 -0
  184. package/examples/build-events/src/notifier.ts +48 -0
  185. package/examples/build-events/src/routes.ts +71 -0
  186. package/examples/build-events/src/server.ts +62 -0
  187. package/examples/build-events/test/builds/events.test.ts +68 -0
  188. package/examples/build-events/test/builds/log.test.ts +71 -0
  189. package/examples/build-events/test/builds/progress.test.ts +57 -0
  190. package/examples/build-events/test/builds/status.test.ts +42 -0
  191. package/examples/build-events/test/commands.test.ts +103 -0
  192. package/examples/build-events/test/deploys/events.test.ts +52 -0
  193. package/examples/build-events/test/http.test.ts +95 -0
  194. package/examples/build-events/test/notifier.test.ts +80 -0
  195. package/examples/build-events/test/routes.test.ts +96 -0
  196. package/examples/build-events/test/rpc.test.ts +84 -0
  197. package/examples/build-events/test/support/as.ts +8 -0
  198. package/examples/build-events/test/support/memory.ts +43 -0
  199. package/examples/build-events/test/webhooks.test.ts +143 -0
  200. package/examples/kitchen-sink/README.md +178 -166
  201. package/examples/kitchen-sink/src/Actions.ts +11 -3
  202. package/examples/kitchen-sink/src/Api.ts +12 -6
  203. package/examples/kitchen-sink/src/Rpc.ts +7 -5
  204. package/examples/kitchen-sink/src/admin/Admin.ts +21 -10
  205. package/examples/kitchen-sink/src/admin/authenticate.ts +8 -4
  206. package/examples/kitchen-sink/src/admin/authorize.ts +13 -5
  207. package/examples/kitchen-sink/src/admin/grants.ts +5 -3
  208. package/examples/kitchen-sink/src/admin/handlers.ts +9 -5
  209. package/examples/kitchen-sink/src/agent.ts +14 -6
  210. package/examples/kitchen-sink/src/assistant/Assistant.ts +21 -15
  211. package/examples/kitchen-sink/src/assistant/conversations.ts +14 -9
  212. package/examples/kitchen-sink/src/assistant/demo-model.ts +2 -2
  213. package/examples/kitchen-sink/src/assistant/handlers.ts +42 -22
  214. package/examples/kitchen-sink/src/attachments/Attachments.ts +6 -6
  215. package/examples/kitchen-sink/src/attachments/download.ts +7 -6
  216. package/examples/kitchen-sink/src/attachments/handlers.ts +9 -4
  217. package/examples/kitchen-sink/src/attachments/store.ts +25 -18
  218. package/examples/kitchen-sink/src/browser.ts +10 -4
  219. package/examples/kitchen-sink/src/cli.ts +28 -12
  220. package/examples/kitchen-sink/src/config.ts +1 -1
  221. package/examples/kitchen-sink/src/identity/Identity.ts +24 -10
  222. package/examples/kitchen-sink/src/identity/authenticate.ts +19 -11
  223. package/examples/kitchen-sink/src/identity/authorize.ts +14 -4
  224. package/examples/kitchen-sink/src/identity/directory.ts +16 -7
  225. package/examples/kitchen-sink/src/identity/handlers.ts +1 -0
  226. package/examples/kitchen-sink/src/identity/members.ts +7 -2
  227. package/examples/kitchen-sink/src/identity/quota.ts +23 -20
  228. package/examples/kitchen-sink/src/issues/Issues.ts +91 -15
  229. package/examples/kitchen-sink/src/issues/assistant.ts +4 -2
  230. package/examples/kitchen-sink/src/issues/events.ts +46 -0
  231. package/examples/kitchen-sink/src/issues/export.ts +35 -0
  232. package/examples/kitchen-sink/src/issues/guide.ts +4 -3
  233. package/examples/kitchen-sink/src/issues/handlers.ts +20 -7
  234. package/examples/kitchen-sink/src/issues/store.ts +156 -67
  235. package/examples/kitchen-sink/src/issues/write-limit.ts +44 -18
  236. package/examples/kitchen-sink/src/memory.ts +11 -2
  237. package/examples/kitchen-sink/src/ops.ts +10 -5
  238. package/examples/kitchen-sink/src/request-policy.ts +25 -9
  239. package/examples/kitchen-sink/src/routes.ts +67 -27
  240. package/examples/kitchen-sink/src/sdk.ts +22 -12
  241. package/examples/kitchen-sink/src/seed.ts +15 -9
  242. package/examples/kitchen-sink/src/server.ts +24 -10
  243. package/examples/kitchen-sink/src/stdio.ts +9 -3
  244. package/examples/kitchen-sink/src/workspaces/Workspaces.ts +10 -7
  245. package/examples/kitchen-sink/src/workspaces/handlers.ts +3 -2
  246. package/examples/kitchen-sink/src/workspaces/registry.ts +16 -10
  247. package/examples/kitchen-sink/src/workspaces/tenant.ts +12 -5
  248. package/examples/kitchen-sink/test/admin/admin.test.ts +38 -23
  249. package/examples/kitchen-sink/test/assistant/assistant.test.ts +471 -299
  250. package/examples/kitchen-sink/test/attachments/attachments.test.ts +135 -94
  251. package/examples/kitchen-sink/test/identity/identity.test.ts +110 -82
  252. package/examples/kitchen-sink/test/identity/session.test.ts +65 -43
  253. package/examples/kitchen-sink/test/issues/assistant.test.ts +50 -31
  254. package/examples/kitchen-sink/test/issues/events.test.ts +273 -0
  255. package/examples/kitchen-sink/test/issues/export.test.ts +120 -0
  256. package/examples/kitchen-sink/test/issues/issues.test.ts +105 -75
  257. package/examples/kitchen-sink/test/request-policy.test.ts +130 -33
  258. package/examples/kitchen-sink/test/routes.test.ts +102 -57
  259. package/examples/kitchen-sink/test/support/as.ts +9 -0
  260. package/examples/kitchen-sink/test/support/scripted.ts +6 -5
  261. package/examples/kitchen-sink/test/support/services.ts +17 -0
  262. package/examples/live-rpc/README.md +33 -35
  263. package/examples/live-rpc/src/Rpc.ts +9 -5
  264. package/examples/live-rpc/src/browser.ts +39 -11
  265. package/examples/live-rpc/src/chat/Chat.ts +30 -16
  266. package/examples/live-rpc/src/chat/authorize.ts +2 -1
  267. package/examples/live-rpc/src/chat/events.ts +74 -0
  268. package/examples/live-rpc/src/chat/handlers.ts +13 -5
  269. package/examples/live-rpc/src/chat/room.ts +9 -5
  270. package/examples/live-rpc/src/chat/store.ts +51 -14
  271. package/examples/live-rpc/src/client.ts +22 -5
  272. package/examples/live-rpc/src/identity/Identity.ts +3 -3
  273. package/examples/live-rpc/src/identity/verifier.ts +8 -4
  274. package/examples/live-rpc/src/page.ts +58 -12
  275. package/examples/live-rpc/src/routes.ts +14 -10
  276. package/examples/live-rpc/src/server.ts +15 -5
  277. package/examples/live-rpc/test/browser.test.ts +127 -50
  278. package/examples/live-rpc/test/chat/chat.test.ts +215 -23
  279. package/examples/live-rpc/test/routes.test.ts +130 -46
  280. package/examples/live-rpc/test/server.test.ts +94 -33
  281. package/examples/mcp-tools/README.md +24 -38
  282. package/examples/mcp-tools/src/platform/fake-farm.ts +63 -24
  283. package/examples/mcp-tools/src/platform/print-farm.ts +59 -29
  284. package/examples/mcp-tools/src/printers/Printers.ts +18 -7
  285. package/examples/mcp-tools/src/printers/farm.ts +15 -5
  286. package/examples/mcp-tools/src/printers/handlers.ts +12 -6
  287. package/examples/mcp-tools/src/routes.ts +8 -6
  288. package/examples/mcp-tools/src/server.ts +12 -5
  289. package/examples/mcp-tools/src/stdio.ts +3 -2
  290. package/examples/mcp-tools/test/printers/printers.test.ts +132 -89
  291. package/examples/mcp-tools/test/routes.test.ts +140 -81
  292. package/examples/notes-service/README.md +30 -45
  293. package/examples/notes-service/src/Api.ts +1 -0
  294. package/examples/notes-service/src/browser.ts +15 -14
  295. package/examples/notes-service/src/cli.ts +8 -3
  296. package/examples/notes-service/src/commands.ts +46 -20
  297. package/examples/notes-service/src/identity/Identity.ts +2 -2
  298. package/examples/notes-service/src/identity/authorize.ts +6 -2
  299. package/examples/notes-service/src/identity/handlers.ts +3 -2
  300. package/examples/notes-service/src/identity/users.ts +2 -1
  301. package/examples/notes-service/src/identity/verifier.ts +12 -6
  302. package/examples/notes-service/src/notes/Notes.ts +46 -22
  303. package/examples/notes-service/src/notes/handlers.ts +18 -9
  304. package/examples/notes-service/src/notes/store.ts +70 -43
  305. package/examples/notes-service/src/routes.ts +7 -5
  306. package/examples/notes-service/src/server.ts +12 -5
  307. package/examples/notes-service/src/status/Status.ts +1 -1
  308. package/examples/notes-service/src/status/handlers.ts +5 -3
  309. package/examples/notes-service/src/stdio.ts +7 -3
  310. package/examples/notes-service/src/worker.ts +6 -3
  311. package/examples/notes-service/test/commands.test.ts +164 -91
  312. package/examples/notes-service/test/notes/as.ts +3 -1
  313. package/examples/notes-service/test/notes/idempotency.test.ts +97 -67
  314. package/examples/notes-service/test/notes/in-process.test.ts +26 -15
  315. package/examples/notes-service/test/notes/notes.test.ts +49 -31
  316. package/examples/notes-service/test/routes.test.ts +106 -71
  317. package/examples/notes-service/test/worker.test.ts +21 -13
  318. package/examples/quickstart/README.md +2 -6
  319. package/examples/quickstart/src/Api.ts +1 -0
  320. package/examples/quickstart/src/client.ts +6 -3
  321. package/examples/quickstart/src/greeting/Greeting.ts +1 -1
  322. package/examples/quickstart/src/greeting/handlers.ts +5 -2
  323. package/examples/quickstart/src/routes.ts +3 -2
  324. package/examples/quickstart/src/server.ts +6 -2
  325. package/examples/quickstart/test/routes.test.ts +3 -2
  326. package/package.json +19 -17
@@ -0,0 +1,133 @@
1
+ import { makeLog, makeLogStore, memoryStorage } from "./log.mjs";
2
+ import { Context, Effect, Layer, Queue, Stream } from "effect";
3
+ // src/contract/hub.ts
4
+ /** Revisions kept in memory, starting again, in a new epoch, with each call. */
5
+ const memoryRevisions = () => {
6
+ const counts = /* @__PURE__ */ new Map();
7
+ return {
8
+ epoch: globalThis.crypto.randomUUID(),
9
+ get: (name) => Effect.sync(() => counts.get(name) ?? 0),
10
+ bump: (names) => Effect.sync(() => {
11
+ for (const name of names) counts.set(name, (counts.get(name) ?? 0) + 1);
12
+ })
13
+ };
14
+ };
15
+ const everyKey = (event) => event.name;
16
+ const noKey = (event) => `${event.name}\u0000`;
17
+ const ofKey = (event, key) => `${event.name}\u0000=${key}`;
18
+ /**
19
+ * Where an event's occurrences are announced as they happen: `notify` wakes the subscribers of a
20
+ * check source to read now, and `publish` appends an occurrence to a log source, both reaching
21
+ * the subscribers of one `key` or every one. Domain code yields it as it yields a store, and an
22
+ * entrypoint provides one implementation: `Event.layerMemory`, kept in a process's memory.
23
+ * Every surface serving events and `Action.client` watching them need it.
24
+ *
25
+ * **Gotchas**
26
+ *
27
+ * - The handlers announcing and the surfaces serving must share one, as they share a store: built separately, as a test building its handlers under a `provide` of their own does, each has its own, and an announcement reaches no subscriber of the other.
28
+ * - An event no implementation attached here has no subscribers here: `publish` does nothing for it, and `notify` only moves its revision, so a current source attached later answers the change.
29
+ * - `notify` of a log source and `publish` to a check source die naming the other: a check source reads your store, so write there and notify; a log source keeps what you publish.
30
+ * - Implementations attach only to one `layerMemory` or `makeEvents` made: built over another, such as `Events.of` in a test, they die, naming both.
31
+ */
32
+ var Events = class extends Context.Service()("effect-actions/Event/Events") {};
33
+ const attached = /* @__PURE__ */ new WeakMap();
34
+ /** How sources attach to `events`, the `Events` `makeEvents` made; one made otherwise dies. */
35
+ const attachmentsOf = (events) => Effect.suspend(() => {
36
+ const attachments = attached.get(events);
37
+ return attachments === void 0 ? Effect.die(/* @__PURE__ */ new Error("This Event.Events serves no event implementation: provide Event.layerMemory, or one Event.makeEvents builds")) : Effect.succeed(attachments);
38
+ });
39
+ /** Whether an announcement to `target` reaches a subscriber of `key`: either absent means every one. */
40
+ const reaches = (target, key) => target === void 0 || key === void 0 || target === key;
41
+ const holding = (set, value) => Effect.acquireRelease(Effect.sync(() => {
42
+ set.add(value);
43
+ return value;
44
+ }), () => Effect.sync(() => set.delete(value)));
45
+ /**
46
+ * An `Events` for as long as the scope lasts, over the log storage `log` makes: what a host keeping
47
+ * logs elsewhere, such as a Durable Object's storage, provides as `Events`, its subscribers' wakes
48
+ * in memory and its logs where `log` keeps them.
49
+ *
50
+ * **Gotchas**
51
+ *
52
+ * - Make it once per host, around the handlers that announce and the surfaces that serve, as `layerMemory` is built.
53
+ * - A log's storage is made once per event for the life of the scope, its position read on every append and read: a storage emptied behind its back, as `storage.deleteAll` empties one, starts a new epoch, and a cursor from before reads a gap.
54
+ */
55
+ const makeEvents = (options) => Effect.gen(function* () {
56
+ const polls = options.polls ?? true;
57
+ const emits = options.emits ?? true;
58
+ const revisions = options.revisions ?? memoryRevisions();
59
+ const scope = yield* Effect.scope;
60
+ const checks = /* @__PURE__ */ new Map();
61
+ const logs = /* @__PURE__ */ new Map();
62
+ const checkOf = (event) => {
63
+ const found = checks.get(event) ?? {
64
+ attached: /* @__PURE__ */ new Set(),
65
+ waiters: /* @__PURE__ */ new Set()
66
+ };
67
+ checks.set(event, found);
68
+ return found;
69
+ };
70
+ const isCheck = (event) => (checks.get(event)?.attached.size ?? 0) > 0;
71
+ const feed = (kept) => Effect.suspend(() => {
72
+ const [next] = kept.feeding ? [] : kept.waiting;
73
+ if (next === void 0) return Effect.void;
74
+ kept.waiting.delete(next);
75
+ kept.feeding = true;
76
+ const fed = Effect.andThen(kept.log.feed(Stream.map(next.emit, ({ key, ...value }) => ({
77
+ value,
78
+ key
79
+ }))), Effect.suspend(() => {
80
+ kept.feeding = false;
81
+ return feed(kept);
82
+ }));
83
+ return Effect.asVoid(Effect.forkIn(fed, scope));
84
+ });
85
+ const fedBy = (kept, emit) => Effect.tap(holding(kept.waiting, { emit }), () => feed(kept));
86
+ const events = Events.of({
87
+ notify: (event, notifyOptions) => Effect.suspend(() => {
88
+ if (!isCheck(event) && logs.has(event)) return Effect.die(/* @__PURE__ */ new Error(`Event "${event.name}" has a log source, which keeps what is published: give each occurrence to publish (Event.Events.publish(event, { data }))`));
89
+ const key = notifyOptions?.key;
90
+ return Effect.andThen(checks.get(event)?.current === false ? Effect.void : revisions.bump([everyKey(event), key === void 0 ? noKey(event) : ofKey(event, key)]), Effect.sync(() => {
91
+ for (const waiter of checkOf(event).waiters) if (reaches(key, waiter.key)) Queue.offerUnsafe(waiter.woken, void 0);
92
+ }));
93
+ }),
94
+ publish: (event, emitted, publishOptions) => Effect.suspend(() => {
95
+ const kept = logs.get(event);
96
+ if (kept !== void 0) return kept.log.append(emitted, publishOptions?.key);
97
+ return isCheck(event) ? Effect.die(/* @__PURE__ */ new Error(`Event "${event.name}" has a check source, which reads your store: write the occurrence there, then wake its subscribers (Event.Events.notify(event))`)) : Effect.void;
98
+ })
99
+ });
100
+ attached.set(events, {
101
+ check: (event, current) => Effect.map(holding(Object.assign(checkOf(event), { current }).attached, {}), () => ({
102
+ polls,
103
+ wakes: (key) => Effect.flatMap(Queue.sliding(1), (woken) => Effect.as(holding(checkOf(event).waiters, {
104
+ key,
105
+ woken
106
+ }), Queue.take(woken))),
107
+ revision: (key) => key === void 0 ? Effect.map(revisions.get(everyKey(event)), (count) => `${revisions.epoch}:${count}`) : Effect.map(Effect.all([revisions.get(noKey(event)), revisions.get(ofKey(event, key))]), ([unkeyed, keyed]) => `${revisions.epoch}:${unkeyed + keyed}:${key}`)
108
+ })),
109
+ log: (event, bounds, emit) => Effect.suspend(() => {
110
+ if (emit !== void 0 && !emits) return Effect.die(/* @__PURE__ */ new Error(`Event "${event.name}" has a log source fed by emit, which this Event.Events does not consume, as its host does not last between requests (publish each occurrence with Event.Events.publish as the host receives it, such as in a call or a route)`));
111
+ const kept = logs.get(event) ?? {
112
+ log: makeLog(makeLogStore(options.log(event), bounds)),
113
+ waiting: /* @__PURE__ */ new Set(),
114
+ feeding: false
115
+ };
116
+ logs.set(event, kept);
117
+ return Effect.as(emit === void 0 ? Effect.void : fedBy(kept, emit), kept.log);
118
+ })
119
+ });
120
+ return events;
121
+ });
122
+ /**
123
+ * An `Events` kept in the memory of the process that builds it: for a server holding its
124
+ * subscribers' connections itself, such as Node's, and for tests.
125
+ *
126
+ * **Gotchas**
127
+ *
128
+ * - Build it once, around the handlers that announce and the surfaces that serve, as a store is: each build is its own.
129
+ * - A log lives as long as this build, through rebuilds of the implementations attached to it: a restart forgets it, and a subscriber resuming from one of its cursors receives a gap.
130
+ * - Several builds of one log source share its log, and its `emit` feeds it from one build at a time, so nothing is appended twice.
131
+ */
132
+ const layerMemory = Layer.effect(Events)(makeEvents({ log: () => memoryStorage() }));
133
+ export { Events, attachmentsOf, layerMemory, makeEvents, reaches };
@@ -0,0 +1,47 @@
1
+ import "./implementation.mjs";
2
+ import "../Action.mjs";
3
+ import { Context, Effect, Layer, Schema } from "effect";
4
+ declare const Kept: Schema.Struct<{
5
+ readonly input: Schema.String;
6
+ readonly outcome: Schema.String;
7
+ readonly at: Schema.Finite;
8
+ }>;
9
+ type Kept = typeof Kept.Type;
10
+ declare const Idempotency_base: Context.ServiceClass<Idempotency, "effect-actions/Action/Idempotency", {
11
+ /** What was kept under `id`, or `undefined`; one kept longer than 24 hours may be either. */
12
+ readonly get: (id: string) => Effect.Effect<Kept | undefined>;
13
+ /** Keeps `kept` under `id`, replacing what was. */
14
+ readonly set: (id: string, kept: Kept) => Effect.Effect<void>;
15
+ }>;
16
+ /**
17
+ * Where the answers of calls given an idempotency key are kept, by the action's name and a
18
+ * SHA-256 digest in hex of the key and its caller's principal, `<action>/<digest>`, for 24 hours
19
+ * at least: what an implementation of an action naming `idempotencyKey` requires at startup.
20
+ * `layerIdempotency` keeps them in memory; a Durable Object's `make` and `handlers` provide one
21
+ * over its storage; another store, shared by several servers, implements `get` and `set`, keeping
22
+ * `Idempotency.Kept` at least `Idempotency.keptFor` milliseconds.
23
+ *
24
+ * **Gotchas**
25
+ *
26
+ * - Provide one per server, around the surfaces: an implementation built in another layer graph keeps its own.
27
+ * - A server waits for a repeat's first call itself, in memory: two servers sharing a store run a call each, the later answer kept.
28
+ */
29
+ export declare class Idempotency extends Idempotency_base {
30
+ /**
31
+ * What is kept of a call answered under its key: the digest of its input, its outcome as JSON,
32
+ * and when it was kept, in milliseconds since the epoch.
33
+ */
34
+ static readonly Kept: Schema.Struct<{
35
+ readonly input: Schema.String;
36
+ readonly outcome: Schema.String;
37
+ readonly at: Schema.Finite;
38
+ }>;
39
+ /** How long, in milliseconds, a kept answer is kept at least: 24 hours. */
40
+ static readonly keptFor: number;
41
+ }
42
+ /**
43
+ * `Idempotency` in the server's memory, each answer kept 24 hours after it was kept: lost when
44
+ * the server stops, and kept apart from every other server's.
45
+ */
46
+ export declare const layerIdempotency: Layer.Layer<Idempotency>;
47
+ export {};
@@ -0,0 +1,99 @@
1
+ import { CallerKeyed, principalOf } from "./caller.mjs";
2
+ import { InvalidInput } from "./errors.mjs";
3
+ import { declaredStatus, isTransientStatus } from "./status.mjs";
4
+ import { projectedErrors } from "./declared.mjs";
5
+ import { answered } from "./implementation.mjs";
6
+ import { canonicalInput } from "./canonical.mjs";
7
+ import { sha256Hex } from "./digest.mjs";
8
+ import { Cause, Clock, Context, Deferred, Effect, Exit, Layer, Option, Predicate, Schema } from "effect";
9
+ // src/contract/idempotency.ts
10
+ const Kept = Schema.Struct({
11
+ input: Schema.String,
12
+ outcome: Schema.String,
13
+ at: Schema.Finite
14
+ });
15
+ const keptFor = 864e5;
16
+ /**
17
+ * Where the answers of calls given an idempotency key are kept, by the action's name and a
18
+ * SHA-256 digest in hex of the key and its caller's principal, `<action>/<digest>`, for 24 hours
19
+ * at least: what an implementation of an action naming `idempotencyKey` requires at startup.
20
+ * `layerIdempotency` keeps them in memory; a Durable Object's `make` and `handlers` provide one
21
+ * over its storage; another store, shared by several servers, implements `get` and `set`, keeping
22
+ * `Idempotency.Kept` at least `Idempotency.keptFor` milliseconds.
23
+ *
24
+ * **Gotchas**
25
+ *
26
+ * - Provide one per server, around the surfaces: an implementation built in another layer graph keeps its own.
27
+ * - A server waits for a repeat's first call itself, in memory: two servers sharing a store run a call each, the later answer kept.
28
+ */
29
+ var Idempotency = class extends Context.Service()("effect-actions/Action/Idempotency") {
30
+ /**
31
+ * What is kept of a call answered under its key: the digest of its input, its outcome as JSON,
32
+ * and when it was kept, in milliseconds since the epoch.
33
+ */
34
+ static Kept = Kept;
35
+ /** How long, in milliseconds, a kept answer is kept at least: 24 hours. */
36
+ static keptFor = keptFor;
37
+ };
38
+ /**
39
+ * `Idempotency` in the server's memory, each answer kept 24 hours after it was kept: lost when
40
+ * the server stops, and kept apart from every other server's.
41
+ */
42
+ const layerIdempotency = Layer.sync(Idempotency)(() => {
43
+ const held = /* @__PURE__ */ new Map();
44
+ return Idempotency.of({
45
+ get: (id) => Effect.sync(() => held.get(id)),
46
+ set: (id, kept) => Effect.sync(() => {
47
+ held.delete(id);
48
+ held.set(id, kept);
49
+ for (const [oldest, { at }] of held) {
50
+ if (at > kept.at - keptFor) break;
51
+ held.delete(oldest);
52
+ }
53
+ })
54
+ });
55
+ });
56
+ /**
57
+ * `handle`, answering a call given `action`'s idempotency key as the first call with it and the
58
+ * same input was answered: from `store`, or, while that call runs, once it has.
59
+ */
60
+ const keyed = (action, store, handle) => {
61
+ const field = action.idempotencyKey;
62
+ if (field === void 0) return handle;
63
+ const Outcome = Schema.fromJsonString(Schema.toCodecJson(Schema.Exit(action.success, Schema.Union(projectedErrors(action)), Schema.Never)));
64
+ const encodeOutcome = Schema.encodeUnknownEffect(Outcome);
65
+ const decodeOutcome = Schema.decodeUnknownOption(Outcome);
66
+ const isTransientFailure = Schema.is(Schema.Union(projectedErrors(action).filter((error) => isTransientStatus(declaredStatus(error)))));
67
+ const running = /* @__PURE__ */ new Map();
68
+ const run = (id, key, digest, answer) => Effect.gen(function* () {
69
+ const first = running.get(id);
70
+ if (first !== void 0) {
71
+ yield* Deferred.await(first).pipe(Effect.withSpan("Idempotency.wait", { attributes: { "action.name": action.name } }));
72
+ return yield* run(id, key, digest, answer);
73
+ }
74
+ const claim = Deferred.makeUnsafe();
75
+ running.set(id, claim);
76
+ const release = Effect.andThen(Effect.sync(() => running.delete(id)), Deferred.succeed(claim, void 0));
77
+ return yield* Effect.gen(function* () {
78
+ const kept = yield* store.get(id);
79
+ if (kept !== void 0 && kept.input !== digest) return yield* new InvalidInput({ message: `The idempotency key ${key} of ${action.name} was given with another input (send a new key for another call)` });
80
+ const replayed = kept === void 0 ? Option.none() : decodeOutcome(kept.outcome);
81
+ if (Option.isSome(replayed)) return yield* replayed.value;
82
+ const exit = yield* Effect.exit(answer);
83
+ const json = Exit.isSuccess(exit) || exit.cause.reasons.every((reason) => Cause.isFailReason(reason) && !isTransientFailure(reason.error)) ? yield* Effect.option(encodeOutcome(exit)) : Option.none();
84
+ if (Option.isSome(json)) yield* store.set(id, {
85
+ input: digest,
86
+ outcome: json.value,
87
+ at: yield* Clock.currentTimeMillis
88
+ });
89
+ return yield* exit;
90
+ }).pipe(Effect.ensuring(release));
91
+ });
92
+ return (input, reporting) => {
93
+ const key = Predicate.hasProperty(input, field) ? input[field] : void 0;
94
+ if (!Predicate.isString(key)) return handle(input, reporting);
95
+ const answer = Effect.suspend(() => answered(handle(input, reporting)));
96
+ return Effect.flatMap(Effect.all([Effect.service(CallerKeyed).pipe(Effect.flatMap((named) => principalOf(action, named)), Effect.flatMap((principal) => sha256Hex(JSON.stringify([principal ?? null, key])))), Effect.flatMap(canonicalInput(action.input, input), sha256Hex)]), ([id, digest]) => run(`${action.name}/${id}`, key, digest, answer));
97
+ };
98
+ };
99
+ export { Idempotency, keyed, layerIdempotency };
@@ -1,28 +1,41 @@
1
- import { Anyone } from "./caller.mjs";
1
+ import { Anyone, Keyed } from "./caller.mjs";
2
2
  import { Refusal } from "./errors.mjs";
3
- import { Any } from "../Action.mjs";
4
- import { Context, Effect, Layer, Scope } from "effect";
5
- //#region src/contract/implementation.d.ts
3
+ import { AnyEventImplementation, EventOf } from "./feed.mjs";
4
+ import { Any } from "../Event.mjs";
5
+ import { Reporting } from "./progress.mjs";
6
+ import { Any as Any$1 } from "../Action.mjs";
7
+ import { Context, Effect, Layer, Scope, Stream } from "effect";
6
8
  /** Decoded values at the dispatch boundary every surface shares. */
7
- export type ErasedValue = Any["input"]["Type"];
9
+ export type ErasedValue = Any$1["input"]["Type"];
8
10
  /**
9
- * A handler, erased. Method extraction makes the argument bivariant: a surface selects the
10
- * action before it invokes a handler, so its decoded input is the matching handler input, and
11
- * handlers are not widened at their public API.
11
+ * A handler as written, erased: its answer, or the stream of an action answering one. Method
12
+ * extraction makes the argument bivariant: a surface selects the action before it invokes a
13
+ * handler, so its decoded input is the matching handler input, and handlers are not widened at
14
+ * their public API.
12
15
  */
13
- export type ErasedHandler<R> = {
14
- handle(input: ErasedValue): Effect.Effect<ErasedValue, ErasedValue, R>;
16
+ export type WrittenHandler<R> = {
17
+ handle(input: ErasedValue, reporting?: Reporting): Effect.Effect<ErasedValue, ErasedValue, R> | Stream.Stream<ErasedValue, ErasedValue, R>;
15
18
  }["handle"];
19
+ /**
20
+ * A handler behind its action's authentication, authorization and declared errors, as a surface
21
+ * calls it. For an action answering a stream it succeeds at once with the call's stream, which
22
+ * `elementsOf` reads, the refusals included. `reporting` is where its progress goes, ignored for
23
+ * an action declaring no `progress`, so a surface may hand one to every call.
24
+ */
25
+ export type ErasedHandler<R> = (input: ErasedValue, reporting?: Reporting) => Effect.Effect<ErasedValue, ErasedValue, R>;
16
26
  /**
17
27
  * Authorization for protected contracts: it refuses, and fails with nothing else. It runs only for
18
28
  * protected actions, after authentication and before the handler.
19
29
  */
20
- export type Authorize<A extends Any, R = never> = (action: A) => Effect.Effect<void, Refusal, R>;
21
- /** An implementation's authorizer, erased. */
22
- export type ErasedAuthorize = (action: Any) => Effect.Effect<void, unknown, unknown>;
23
- /** Each action of an implementation with its handler, as its builder made them. */
24
- export type Bound = ReadonlyArray<readonly [Any, ErasedHandler<unknown>]>;
25
- interface Memoized<S, E, R> {
30
+ export type Authorize<A extends Any$1, R = never> = (action: A) => Effect.Effect<void, Refusal, R>;
31
+ /** An authorization rule over contracts `C`, erased: it refuses, or lets the call run. */
32
+ export type ErasedAuthorize<C = Any$1> = (contract: C) => Effect.Effect<void, unknown, unknown>;
33
+ /** Each action of an implementation with its handler, as `dispatch` makes it. */
34
+ export type Bound = ReadonlyArray<readonly [Any$1, ErasedHandler<unknown>]>;
35
+ /** Each action of an implementation with its handler as written, as its builder made them. */
36
+ export type Written = ReadonlyArray<readonly [Any$1, WrittenHandler<unknown>]>;
37
+ /** A build shared by every layer an implementation reaches, through the one key it is provided under. */
38
+ export interface Memoized<S, E, R> {
26
39
  readonly key: Context.Key<S, S>;
27
40
  readonly layer: Layer.Layer<S, E, R>;
28
41
  }
@@ -35,12 +48,10 @@ interface Memoized<S, E, R> {
35
48
  * its handlers' builder, `RA` what its authorizer reads per request, and `EAX` and `RAX` the
36
49
  * failures and services of the authorizer's builder.
37
50
  */
38
- export declare class Implementation<A extends Any, RequestServices extends {
51
+ export declare class Implementation<A extends Any$1, RequestServices extends {
39
52
  readonly [name: string]: unknown;
40
53
  }, EX, RX, RA = never, EAX = never, RAX = never> {
41
54
  #private;
42
- /** The contracts this implementation answers. */
43
- readonly actions: ReadonlyArray<A>;
44
55
  /** Type-only: each action's handler's request-time requirements. */
45
56
  readonly "~request": RequestServices;
46
57
  /** Type-only: what building its handlers fails with. */
@@ -53,15 +64,15 @@ export declare class Implementation<A extends Any, RequestServices extends {
53
64
  readonly "~authorizeBuildError": EAX;
54
65
  /** Type-only: what building its authorizer needs. */
55
66
  readonly "~authorizeBuildServices": RAX;
56
- constructor(
57
67
  /** The contracts this implementation answers. */
58
- actions: ReadonlyArray<A>,
68
+ readonly actions: readonly A[];
69
+ constructor(actions: readonly A[],
59
70
  /** Builds each action paired with its handler: its own builder, or the one it shares. */
60
- handlers: Memoized<Bound, EX, RX>,
71
+ handlers: Memoized<Written, EX, RX>,
61
72
  /** Builds its authorizer. */
62
73
  authorizer: Memoized<ErasedAuthorize, EAX, RAX>);
63
74
  /** Select contracts while retaining their handlers, authorization and shared builder. */
64
- static share(actions: ReadonlyArray<Any>, app: AnyImplementation): AnyImplementation;
75
+ static share(actions: readonly Any$1[], app: AnyImplementation): AnyImplementation;
65
76
  /**
66
77
  * The key of what runs a call of `app`'s actions: its handlers' memoized layer's, which each
67
78
  * `implement` makes, so it is unique to the implementation. Every selection retains it.
@@ -77,7 +88,7 @@ export declare class Implementation<A extends Any, RequestServices extends {
77
88
  * The actions of `app` with their handlers, behind its authorizer, from the context
78
89
  * `layerOf(app)` provides.
79
90
  */
80
- static boundOf(app: AnyImplementation): Effect.Effect<Bound, never, unknown>;
91
+ static boundOf(app: AnyImplementation, keyed: Keyed | undefined): Effect.Effect<Bound, never, unknown>;
81
92
  /** `app`, if this copy of the module made it; another installed copy's cannot be read. */
82
93
  private static own;
83
94
  }
@@ -88,43 +99,55 @@ export declare class Implementation<A extends Any, RequestServices extends {
88
99
  * admits every implementation, while a value of this type owes `unknown`, which no surface can be
89
100
  * given.
90
101
  */
91
- export type AnyImplementation<A extends Any = Any> = Implementation<A, {
102
+ export type AnyImplementation<A extends Any$1 = Any$1> = Implementation<A, {
92
103
  readonly [name: string]: unknown;
93
104
  }, unknown, unknown, unknown, unknown, unknown>;
94
- /** What a surface serves: one implementation, or a list of them. */
95
- export type Served = AnyImplementation | ReadonlyArray<AnyImplementation>;
105
+ /** What a surface serves: one implementation, of actions or of events, or a list of them. */
106
+ export type Served = AnyImplementation | AnyEventImplementation | ReadonlyArray<AnyImplementation | AnyEventImplementation>;
107
+ /** What a surface serving no events takes: one action implementation, or a list of them. */
108
+ export type ServedActions = AnyImplementation | readonly AnyImplementation[];
96
109
  /** The implementations `S` stands for. */
97
110
  export type Member<S> = S extends ReadonlyArray<infer App> ? App : S;
98
- /** Options that may list actions of `A`, the shape every selecting surface's options share. */
99
- export interface Selection<A extends Any> {
100
- readonly actions?: ReadonlyArray<A> | undefined;
111
+ /**
112
+ * Options that may list actions and event types of `C`, the shape every selecting surface's
113
+ * options share.
114
+ */
115
+ export interface Selection<C extends Any$1 | Any> {
116
+ readonly actions?: readonly C[] | undefined;
101
117
  }
102
118
  /**
103
119
  * The actions options `O` select, of `All`: those its `actions` lists when it always lists
104
- * them, and every one otherwise. Options whose `actions` may be absent, being optional or
105
- * a union with options lacking it, select every action at run time, so they narrow nothing.
120
+ * them, none where it lists event types alone, and every one otherwise. Options whose `actions`
121
+ * may be absent, being optional or a union with options lacking it, select every action at run
122
+ * time, so they narrow nothing.
106
123
  */
107
- export type Selected<O, All extends Any> = O extends {
108
- readonly actions: ReadonlyArray<infer A extends Any>;
109
- } ? A : All;
124
+ export type Selected<O, All extends Any$1> = O extends {
125
+ readonly actions: ReadonlyArray<infer C>;
126
+ } ? Extract<C, Any$1> : All;
127
+ /** The event types options `O` select, of `All`, as `Selected` selects actions. */
128
+ export type SelectedEvents<O, All extends Any> = O extends {
129
+ readonly actions: ReadonlyArray<infer C>;
130
+ } ? Extract<C, Any> : All;
110
131
  /**
111
132
  * The middleware options `O` install, each a member of `L`: its `middleware` when always given,
112
133
  * an array of unknown length when it may be absent, which installs none or all of them, and
113
134
  * none otherwise.
114
135
  */
115
- export type MiddlewareOf<O, L extends ReadonlyArray<unknown>> = O extends {
136
+ export type MiddlewareOf<O, L extends readonly unknown[]> = O extends {
116
137
  readonly middleware: infer M extends L;
117
138
  } ? M : O extends {
118
139
  readonly middleware?: infer M extends L | undefined;
119
140
  } ? "middleware" extends keyof O ? ReadonlyArray<NonNullable<M>[number]> : [] : [];
120
141
  /** The actions options `O` select of the implementations `Apps` stand for. */
121
142
  export type SelectedOf<O, Apps extends Served> = Selected<O, ActionOf<Member<Apps>>>;
143
+ /** The event types options `O` select of the implementations `Apps` stand for. */
144
+ export type SelectedEventsOf<O, Apps extends Served> = SelectedEvents<O, EventOf<Member<Apps>>>;
122
145
  /**
123
- * The actions a client of options `O` offers methods for, of `All`: those `actions` may
146
+ * The actions or event types a client of options `O` offers, of `All`: those `actions` may
124
147
  * list, wherever some member of `O` may list them, as each is present whether the list is
125
148
  * given or not; every one where no member lists any.
126
149
  */
127
- export type Offered<O, All extends Any> = [Listing<O>] extends [never] ? All : Extract<All, Listing<O> extends ReadonlyArray<infer A extends Any> ? A : never>;
150
+ export type Offered<O, All extends Any$1 | Any> = [Listing<O>] extends [never] ? All : Extract<All, Listing<O> extends ReadonlyArray<infer C> ? C : never>;
128
151
  type Listing<O> = O extends unknown ? NonNullable<O["actions" & keyof O]> : never;
129
152
  /**
130
153
  * No key of any member of `O` beyond those of `Keys`, so a misspelled option is refused
@@ -142,7 +165,7 @@ export type OptionalUnless<O, Given> = {} extends O ? [options?: Given] : [optio
142
165
  export type ActionOf<App> = App extends {
143
166
  readonly actions: ReadonlyArray<infer A>;
144
167
  } ? A : never;
145
- type Matches<A extends Any, Listed extends Any> = Listed extends Any ? [A] extends [Listed] ? true : [Listed] extends [A] ? true : never : never;
168
+ type Matches<A extends Any$1, Listed extends Any$1> = Listed extends Any$1 ? [A] extends [Listed] ? true : [Listed] extends [A] ? true : never : never;
146
169
  /**
147
170
  * The actions of `App` a surface given the actions `Listed` may serve, as `select` selects
148
171
  * them by identity: an action whose type either is assignable to, or is assigned by, one
@@ -150,34 +173,34 @@ type Matches<A extends Any, Listed extends Any> = Listed extends Any ? [A] exten
150
173
  * actions, an erased one included, still counts, and another contract of a listed name, which
151
174
  * the surface leaves out beside an action it serves, does not.
152
175
  */
153
- export type Serving<App, Listed extends Any> = ActionOf<App> extends (infer A extends Any) ? A extends unknown ? [A] extends [Listed] ? A : string extends A["name"] ? A : [Extract<A["name"], Listed["name"]>] extends [never] ? never : [Matches<A, Listed>] extends [never] ? never : A : never : never;
176
+ export type Serving<App, Listed extends Any$1> = ActionOf<App> extends (infer A extends Any$1) ? A extends unknown ? [A] extends [Listed] ? A : string extends A["name"] ? A : [Extract<A["name"], Listed["name"]>] extends [never] ? never : [Matches<A, Listed>] extends [never] ? never : A : never : never;
154
177
  /**
155
178
  * What each implementation among `App` owes per request where a surface serving the actions
156
179
  * `Listed` serves it: its authorizer's services, and the handlers' of the actions it serves.
157
180
  */
158
- export type ServedRequest<App, Listed extends Any> = App extends unknown ? RequestOf<App, Serving<App, Listed>> : never;
181
+ export type ServedRequest<App, Listed extends Any$1> = App extends unknown ? RequestOf<App, Serving<App, Listed>> : never;
159
182
  /** The implementations among `App` holding an action of `Listed`: those a surface builds. */
160
- export type Holding<App, Listed extends Any> = App extends unknown ? [Serving<App, Listed>] extends [never] ? never : App : never;
161
- /** The protected members of a contract union. */
162
- export type Protected<A extends Any> = A extends unknown ? A["caller"] extends typeof Anyone ? never : A : never;
183
+ export type Holding<App, Listed extends Any$1> = App extends unknown ? [Serving<App, Listed>] extends [never] ? never : App : never;
184
+ /** The protected members of a contract union, of actions or of events. */
185
+ export type Protected<A extends Pick<Any$1, "caller">> = A extends unknown ? A["caller"] extends typeof Anyone ? never : A : never;
163
186
  type ServiceOf<K> = K extends Context.Key<infer I, unknown> ? I : never;
164
- type AuthenticationOf<A extends Any> = A["caller"] extends typeof Anyone ? never : ServiceOf<A["caller"]>;
187
+ type AuthenticationOf<A extends Any$1> = A["caller"] extends typeof Anyone ? never : ServiceOf<A["caller"]>;
165
188
  /**
166
189
  * Per-request requirements of `App`'s authorization and handler for each `A` it
167
190
  * implements: those of every name `A`'s may be, so a union or an erased name owes each it may
168
191
  * stand for.
169
192
  */
170
- export type RequestOf<App, A extends Any> = App extends {
193
+ export type RequestOf<App, A extends Any$1> = App extends {
171
194
  readonly "~request": infer R;
172
195
  readonly "~authorizeRequest": infer RA;
173
- } ? A extends Any ? [A["name"] & keyof R] extends [never] ? never : R[A["name"] & keyof R] | (A["caller"] extends typeof Anyone ? never : RA) | AuthenticationOf<A> : never : never;
174
- type OwnActions<App> = Extract<ActionOf<App>, Any>;
196
+ } ? A extends Any$1 ? [A["name"] & keyof R] extends [never] ? never : R[A["name"] & keyof R] | (A["caller"] extends typeof Anyone ? never : RA) | AuthenticationOf<A> : never : never;
197
+ type OwnActions<App> = Extract<ActionOf<App>, Any$1>;
175
198
  /**
176
199
  * What a surface serving the actions `Listed` of the implementations `App` fails with at startup:
177
200
  * their builders' and built authorizers' failures, an authorizer's only if a selected protected
178
201
  * action needs it.
179
202
  */
180
- export type BuildError<App, Listed extends Any = OwnActions<App>> = App extends {
203
+ export type BuildError<App, Listed extends Any$1 = OwnActions<App>> = App extends {
181
204
  readonly "~buildError": infer EX;
182
205
  readonly "~authorizeBuildError": infer EAX;
183
206
  } ? EX | ([Protected<Serving<App, Listed>>] extends [never] ? never : EAX) : never;
@@ -185,9 +208,8 @@ export type BuildError<App, Listed extends Any = OwnActions<App>> = App extends
185
208
  * What a surface serving the actions `Listed` of the implementations `App` reads at startup: their
186
209
  * builders' and built authorizers' services.
187
210
  */
188
- export type BuildServices<App, Listed extends Any = OwnActions<App>> = App extends {
211
+ export type BuildServices<App, Listed extends Any$1 = OwnActions<App>> = App extends {
189
212
  readonly "~buildServices": infer RX;
190
213
  readonly "~authorizeBuildServices": infer RAX;
191
214
  } ? RX | ([Protected<Serving<App, Listed>>] extends [never] ? never : RAX) : never;
192
- //#endregion
193
215
  export {};