@moltzap/client 2026.414.0 → 2026.425.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 (216) hide show
  1. package/dist/channel-core.d.ts +28 -15
  2. package/dist/channel-core.d.ts.map +1 -1
  3. package/dist/channel-core.js +113 -74
  4. package/dist/channel-core.js.map +1 -1
  5. package/dist/channel-core.test.js +126 -34
  6. package/dist/channel-core.test.js.map +1 -1
  7. package/dist/cli/__tests__/cli-multi-agent.int.test.d.ts +2 -0
  8. package/dist/cli/__tests__/cli-multi-agent.int.test.d.ts.map +1 -0
  9. package/dist/cli/__tests__/cli-multi-agent.int.test.js +26 -0
  10. package/dist/cli/__tests__/cli-multi-agent.int.test.js.map +1 -0
  11. package/dist/cli/commands/agents.d.ts +13 -2
  12. package/dist/cli/commands/agents.d.ts.map +1 -1
  13. package/dist/cli/commands/agents.js +30 -18
  14. package/dist/cli/commands/agents.js.map +1 -1
  15. package/dist/cli/commands/apps.d.ts +96 -0
  16. package/dist/cli/commands/apps.d.ts.map +1 -0
  17. package/dist/cli/commands/apps.js +193 -0
  18. package/dist/cli/commands/apps.js.map +1 -0
  19. package/dist/cli/commands/apps.test.d.ts +2 -0
  20. package/dist/cli/commands/apps.test.d.ts.map +1 -0
  21. package/dist/cli/commands/apps.test.js +220 -0
  22. package/dist/cli/commands/apps.test.js.map +1 -0
  23. package/dist/cli/commands/contacts.d.ts +18 -2
  24. package/dist/cli/commands/contacts.d.ts.map +1 -1
  25. package/dist/cli/commands/contacts.js +44 -52
  26. package/dist/cli/commands/contacts.js.map +1 -1
  27. package/dist/cli/commands/conversations-v2.test.d.ts +2 -0
  28. package/dist/cli/commands/conversations-v2.test.d.ts.map +1 -0
  29. package/dist/cli/commands/conversations-v2.test.js +92 -0
  30. package/dist/cli/commands/conversations-v2.test.js.map +1 -0
  31. package/dist/cli/commands/conversations.d.ts +73 -3
  32. package/dist/cli/commands/conversations.d.ts.map +1 -1
  33. package/dist/cli/commands/conversations.js +157 -108
  34. package/dist/cli/commands/conversations.js.map +1 -1
  35. package/dist/cli/commands/invite.d.ts +6 -2
  36. package/dist/cli/commands/invite.d.ts.map +1 -1
  37. package/dist/cli/commands/invite.js +8 -6
  38. package/dist/cli/commands/invite.js.map +1 -1
  39. package/dist/cli/commands/messages.d.ts +48 -0
  40. package/dist/cli/commands/messages.d.ts.map +1 -0
  41. package/dist/cli/commands/messages.js +68 -0
  42. package/dist/cli/commands/messages.js.map +1 -0
  43. package/dist/cli/commands/messages.test.d.ts +2 -0
  44. package/dist/cli/commands/messages.test.d.ts.map +1 -0
  45. package/dist/cli/commands/messages.test.js +73 -0
  46. package/dist/cli/commands/messages.test.js.map +1 -0
  47. package/dist/cli/commands/permissions.d.ts +66 -0
  48. package/dist/cli/commands/permissions.d.ts.map +1 -0
  49. package/dist/cli/commands/permissions.js +101 -0
  50. package/dist/cli/commands/permissions.js.map +1 -0
  51. package/dist/cli/commands/permissions.test.d.ts +2 -0
  52. package/dist/cli/commands/permissions.test.d.ts.map +1 -0
  53. package/dist/cli/commands/permissions.test.js +126 -0
  54. package/dist/cli/commands/permissions.test.js.map +1 -0
  55. package/dist/cli/commands/ping.d.ts +6 -2
  56. package/dist/cli/commands/ping.d.ts.map +1 -1
  57. package/dist/cli/commands/ping.js +21 -20
  58. package/dist/cli/commands/ping.js.map +1 -1
  59. package/dist/cli/commands/presence.d.ts +10 -2
  60. package/dist/cli/commands/presence.d.ts.map +1 -1
  61. package/dist/cli/commands/presence.js +27 -15
  62. package/dist/cli/commands/presence.js.map +1 -1
  63. package/dist/cli/commands/register.d.ts +24 -2
  64. package/dist/cli/commands/register.d.ts.map +1 -1
  65. package/dist/cli/commands/register.js +123 -47
  66. package/dist/cli/commands/register.js.map +1 -1
  67. package/dist/cli/commands/register.test.js +45 -27
  68. package/dist/cli/commands/register.test.js.map +1 -1
  69. package/dist/cli/commands/send.d.ts +43 -2
  70. package/dist/cli/commands/send.d.ts.map +1 -1
  71. package/dist/cli/commands/send.js +55 -13
  72. package/dist/cli/commands/send.js.map +1 -1
  73. package/dist/cli/commands/send.test.js +20 -19
  74. package/dist/cli/commands/send.test.js.map +1 -1
  75. package/dist/cli/commands/status.d.ts +6 -2
  76. package/dist/cli/commands/status.d.ts.map +1 -1
  77. package/dist/cli/commands/status.js +16 -10
  78. package/dist/cli/commands/status.js.map +1 -1
  79. package/dist/cli/commands/whoami.d.ts +7 -2
  80. package/dist/cli/commands/whoami.d.ts.map +1 -1
  81. package/dist/cli/commands/whoami.js +13 -7
  82. package/dist/cli/commands/whoami.js.map +1 -1
  83. package/dist/cli/config.d.ts +24 -8
  84. package/dist/cli/config.d.ts.map +1 -1
  85. package/dist/cli/config.js +65 -39
  86. package/dist/cli/config.js.map +1 -1
  87. package/dist/cli/config.test.js +12 -10
  88. package/dist/cli/config.test.js.map +1 -1
  89. package/dist/cli/http-client.d.ts +6 -2
  90. package/dist/cli/http-client.d.ts.map +1 -1
  91. package/dist/cli/http-client.js +25 -24
  92. package/dist/cli/http-client.js.map +1 -1
  93. package/dist/cli/index.d.ts +16 -1
  94. package/dist/cli/index.d.ts.map +1 -1
  95. package/dist/cli/index.js +160 -27
  96. package/dist/cli/index.js.map +1 -1
  97. package/dist/cli/profile.d.ts +134 -0
  98. package/dist/cli/profile.d.ts.map +1 -0
  99. package/dist/cli/profile.js +217 -0
  100. package/dist/cli/profile.js.map +1 -0
  101. package/dist/cli/profile.test.d.ts +2 -0
  102. package/dist/cli/profile.test.d.ts.map +1 -0
  103. package/dist/cli/profile.test.js +263 -0
  104. package/dist/cli/profile.test.js.map +1 -0
  105. package/dist/cli/runtime.d.ts +34 -0
  106. package/dist/cli/runtime.d.ts.map +1 -0
  107. package/dist/cli/runtime.js +94 -0
  108. package/dist/cli/runtime.js.map +1 -0
  109. package/dist/cli/socket-client.d.ts +15 -12
  110. package/dist/cli/socket-client.d.ts.map +1 -1
  111. package/dist/cli/socket-client.js +72 -75
  112. package/dist/cli/socket-client.js.map +1 -1
  113. package/dist/cli/transport.d.ts +181 -0
  114. package/dist/cli/transport.d.ts.map +1 -0
  115. package/dist/cli/transport.js +324 -0
  116. package/dist/cli/transport.js.map +1 -0
  117. package/dist/cli/transport.test.d.ts +2 -0
  118. package/dist/cli/transport.test.d.ts.map +1 -0
  119. package/dist/cli/transport.test.js +197 -0
  120. package/dist/cli/transport.test.js.map +1 -0
  121. package/dist/index.d.ts +6 -2
  122. package/dist/index.d.ts.map +1 -1
  123. package/dist/index.js +1 -0
  124. package/dist/index.js.map +1 -1
  125. package/dist/runtime/close-info.d.ts +94 -0
  126. package/dist/runtime/close-info.d.ts.map +1 -0
  127. package/dist/runtime/close-info.js +109 -0
  128. package/dist/runtime/close-info.js.map +1 -0
  129. package/dist/runtime/close-info.test.d.ts +2 -0
  130. package/dist/runtime/close-info.test.d.ts.map +1 -0
  131. package/dist/runtime/close-info.test.js +102 -0
  132. package/dist/runtime/close-info.test.js.map +1 -0
  133. package/dist/runtime/errors.d.ts +47 -0
  134. package/dist/runtime/errors.d.ts.map +1 -0
  135. package/dist/runtime/errors.js +20 -0
  136. package/dist/runtime/errors.js.map +1 -0
  137. package/dist/runtime/errors.test.d.ts +2 -0
  138. package/dist/runtime/errors.test.d.ts.map +1 -0
  139. package/dist/runtime/errors.test.js +66 -0
  140. package/dist/runtime/errors.test.js.map +1 -0
  141. package/dist/runtime/frame.d.ts +25 -0
  142. package/dist/runtime/frame.d.ts.map +1 -0
  143. package/dist/runtime/frame.js +106 -0
  144. package/dist/runtime/frame.js.map +1 -0
  145. package/dist/runtime/frame.test.d.ts +2 -0
  146. package/dist/runtime/frame.test.d.ts.map +1 -0
  147. package/dist/runtime/frame.test.js +32 -0
  148. package/dist/runtime/frame.test.js.map +1 -0
  149. package/dist/runtime/index.d.ts +3 -0
  150. package/dist/runtime/index.d.ts.map +1 -0
  151. package/dist/runtime/index.js +3 -0
  152. package/dist/runtime/index.js.map +1 -0
  153. package/dist/runtime/refs.d.ts +10 -0
  154. package/dist/runtime/refs.d.ts.map +1 -0
  155. package/dist/runtime/refs.js +10 -0
  156. package/dist/runtime/refs.js.map +1 -0
  157. package/dist/runtime/runtime.test.d.ts +2 -0
  158. package/dist/runtime/runtime.test.d.ts.map +1 -0
  159. package/dist/runtime/runtime.test.js +29 -0
  160. package/dist/runtime/runtime.test.js.map +1 -0
  161. package/dist/runtime/subscribers.d.ts +157 -0
  162. package/dist/runtime/subscribers.d.ts.map +1 -0
  163. package/dist/runtime/subscribers.js +131 -0
  164. package/dist/runtime/subscribers.js.map +1 -0
  165. package/dist/runtime/subscribers.test.d.ts +2 -0
  166. package/dist/runtime/subscribers.test.d.ts.map +1 -0
  167. package/dist/runtime/subscribers.test.js +155 -0
  168. package/dist/runtime/subscribers.test.js.map +1 -0
  169. package/dist/service.d.ts +68 -17
  170. package/dist/service.d.ts.map +1 -1
  171. package/dist/service.js +461 -307
  172. package/dist/service.js.map +1 -1
  173. package/dist/service.test.js +266 -77
  174. package/dist/service.test.js.map +1 -1
  175. package/dist/test/index.d.ts +33 -0
  176. package/dist/test/index.d.ts.map +1 -0
  177. package/dist/test/index.js +44 -0
  178. package/dist/test/index.js.map +1 -0
  179. package/dist/test-utils/channel-service-fixture.d.ts +2 -1
  180. package/dist/test-utils/channel-service-fixture.d.ts.map +1 -1
  181. package/dist/test-utils/channel-service-fixture.js +31 -11
  182. package/dist/test-utils/channel-service-fixture.js.map +1 -1
  183. package/dist/test-utils/conformance-adapter.d.ts +50 -0
  184. package/dist/test-utils/conformance-adapter.d.ts.map +1 -0
  185. package/dist/test-utils/conformance-adapter.js +206 -0
  186. package/dist/test-utils/conformance-adapter.js.map +1 -0
  187. package/dist/test-utils/fake-service.d.ts +85 -0
  188. package/dist/test-utils/fake-service.d.ts.map +1 -0
  189. package/dist/test-utils/fake-service.js +103 -0
  190. package/dist/test-utils/fake-service.js.map +1 -0
  191. package/dist/test-utils/index.d.ts +2 -0
  192. package/dist/test-utils/index.d.ts.map +1 -1
  193. package/dist/test-utils/index.js +3 -2
  194. package/dist/test-utils/index.js.map +1 -1
  195. package/dist/ws-client.d.ts +157 -18
  196. package/dist/ws-client.d.ts.map +1 -1
  197. package/dist/ws-client.js +432 -94
  198. package/dist/ws-client.js.map +1 -1
  199. package/dist/ws-client.test.d.ts +2 -0
  200. package/dist/ws-client.test.d.ts.map +1 -0
  201. package/dist/ws-client.test.js +672 -0
  202. package/dist/ws-client.test.js.map +1 -0
  203. package/package.json +23 -14
  204. package/LICENSE +0 -21
  205. package/dist/__tests__/service.integration.test.d.ts +0 -2
  206. package/dist/__tests__/service.integration.test.d.ts.map +0 -1
  207. package/dist/__tests__/service.integration.test.js +0 -1087
  208. package/dist/__tests__/service.integration.test.js.map +0 -1
  209. package/dist/cli/commands/delete.d.ts +0 -3
  210. package/dist/cli/commands/delete.d.ts.map +0 -1
  211. package/dist/cli/commands/delete.js +0 -10
  212. package/dist/cli/commands/delete.js.map +0 -1
  213. package/dist/cli/commands/react.d.ts +0 -3
  214. package/dist/cli/commands/react.d.ts.map +0 -1
  215. package/dist/cli/commands/react.js +0 -18
  216. package/dist/cli/commands/react.js.map +0 -1
@@ -0,0 +1,32 @@
1
+ import { Effect } from "effect";
2
+ import { describe, expect, it } from "vitest";
3
+ import { decodeFrames } from "./frame.js";
4
+ describe("decodeFrames", () => {
5
+ it("decodes padded chunks that contain both an event and a response", async () => {
6
+ const raw = JSON.stringify({
7
+ jsonrpc: "2.0",
8
+ type: "event",
9
+ event: "messages/received",
10
+ data: { message: { id: "m-1", conversationId: "c-1" } },
11
+ }) +
12
+ "\u0000\n" +
13
+ JSON.stringify({
14
+ jsonrpc: "2.0",
15
+ type: "response",
16
+ id: "rpc-7",
17
+ result: { ok: true },
18
+ });
19
+ const decoded = await Effect.runPromise(decodeFrames(raw));
20
+ expect(decoded).toHaveLength(2);
21
+ expect(decoded[0]).toMatchObject({
22
+ _tag: "Event",
23
+ frame: { event: "messages/received" },
24
+ });
25
+ expect(decoded[1]).toMatchObject({
26
+ _tag: "Response",
27
+ id: "rpc-7",
28
+ result: { ok: true },
29
+ });
30
+ });
31
+ });
32
+ //# sourceMappingURL=frame.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame.test.js","sourceRoot":"","sources":["../../src/runtime/frame.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,iEAAiE,EAAE,KAAK,IAAI,EAAE;QAC/E,MAAM,GAAG,GACP,IAAI,CAAC,SAAS,CAAC;YACb,OAAO,EAAE,KAAK;YACd,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,mBAAmB;YAC1B,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE;SACxD,CAAC;YACF,UAAU;YACV,IAAI,CAAC,SAAS,CAAC;gBACb,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,UAAU;gBAChB,EAAE,EAAE,OAAO;gBACX,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE;aACrB,CAAC,CAAC;QAEL,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QAE3D,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;YAC/B,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE;SACtC,CAAC,CAAC;QACH,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;YAC/B,IAAI,EAAE,UAAU;YAChB,EAAE,EAAE,OAAO;YACX,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE;SACrB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { AgentNotFoundError, NotConnectedError, RpcTimeoutError, RpcServerError, MalformedFrameError, } from "./errors.js";
2
+ export { snapshot, getOr } from "./refs.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,mBAAmB,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { AgentNotFoundError, NotConnectedError, RpcTimeoutError, RpcServerError, MalformedFrameError, } from "./errors.js";
2
+ export { snapshot, getOr } from "./refs.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,mBAAmB,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { HashMap, Ref } from "effect";
2
+ /**
3
+ * Read a `Ref` synchronously outside an Effect scope. Only safe for `Ref`s
4
+ * that never fiber-park (the stock `Ref.Ref<A>` never does). Use from
5
+ * object methods or sync code paths that hold a `Ref` set up at construction.
6
+ */
7
+ export declare const snapshot: <A>(ref: Ref.Ref<A>) => A;
8
+ /** Lookup `key` in `m`, falling back to `dflt()` if absent. Lazy default. */
9
+ export declare const getOr: <K, V>(m: HashMap.HashMap<K, V>, key: K, dflt: () => V) => V;
10
+ //# sourceMappingURL=refs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../../src/runtime/refs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,OAAO,EAAU,GAAG,EAAE,MAAM,QAAQ,CAAC;AAEtD;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAG,CAAiC,CAAC;AAEhF,6EAA6E;AAC7E,eAAO,MAAM,KAAK,GAAI,CAAC,EAAE,CAAC,EACxB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,EACxB,KAAK,CAAC,EACN,MAAM,MAAM,CAAC,KACZ,CAAgD,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { Effect, HashMap, Option, Ref } from "effect";
2
+ /**
3
+ * Read a `Ref` synchronously outside an Effect scope. Only safe for `Ref`s
4
+ * that never fiber-park (the stock `Ref.Ref<A>` never does). Use from
5
+ * object methods or sync code paths that hold a `Ref` set up at construction.
6
+ */
7
+ export const snapshot = (ref) => Effect.runSync(Ref.get(ref));
8
+ /** Lookup `key` in `m`, falling back to `dflt()` if absent. Lazy default. */
9
+ export const getOr = (m, key, dflt) => Option.getOrElse(HashMap.get(m, key), dflt);
10
+ //# sourceMappingURL=refs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refs.js","sourceRoot":"","sources":["../../src/runtime/refs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAEtD;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAI,GAAe,EAAK,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAEhF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,CAAwB,EACxB,GAAM,EACN,IAAa,EACV,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=runtime.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.test.d.ts","sourceRoot":"","sources":["../../src/runtime/runtime.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,29 @@
1
+ import { it } from "@effect/vitest";
2
+ import { Effect, Exit } from "effect";
3
+ import { expect } from "vitest";
4
+ import { NotConnectedError, RpcServerError, RpcTimeoutError, } from "./errors.js";
5
+ it.effect("tagged errors discriminate by _tag", () => Effect.gen(function* () {
6
+ const exit = yield* Effect.exit(Effect.fail(new RpcTimeoutError({ method: "messages/send", timeoutMs: 30_000 })));
7
+ if (Exit.isFailure(exit) && exit.cause._tag === "Fail") {
8
+ const err = exit.cause.error;
9
+ expect(err._tag).toBe("RpcTimeoutError");
10
+ expect(err.method).toBe("messages/send");
11
+ }
12
+ else {
13
+ throw new Error("expected failure");
14
+ }
15
+ }));
16
+ it.effect("RpcServerError preserves wire fields", () => Effect.gen(function* () {
17
+ const err = new RpcServerError({
18
+ code: -32002,
19
+ message: "Not found",
20
+ });
21
+ expect(err.code).toBe(-32002);
22
+ expect(err.message).toBe("Not found");
23
+ expect(err.data).toBeUndefined();
24
+ }));
25
+ it.effect("NotConnectedError compiles and carries message", () => Effect.gen(function* () {
26
+ const err = new NotConnectedError({ message: "socket closed" });
27
+ expect(err.message).toBe("socket closed");
28
+ }));
29
+ //# sourceMappingURL=runtime.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.test.js","sourceRoot":"","sources":["../../src/runtime/runtime.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,cAAc,EACd,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,EAAE,CAAC,MAAM,CAAC,oCAAoC,EAAE,GAAG,EAAE,CACnD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAC7B,MAAM,CAAC,IAAI,CACT,IAAI,eAAe,CAAC,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CACpE,CACF,CAAC;IACF,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACvD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACtC,CAAC;AACH,CAAC,CAAC,CACH,CAAC;AAEF,EAAE,CAAC,MAAM,CAAC,sCAAsC,EAAE,GAAG,EAAE,CACrD,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,GAAG,GAAG,IAAI,cAAc,CAAC;QAC7B,IAAI,EAAE,CAAC,KAAK;QACZ,OAAO,EAAE,WAAW;KACrB,CAAC,CAAC;IACH,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC;IAC9B,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;AACnC,CAAC,CAAC,CACH,CAAC;AAEF,EAAE,CAAC,MAAM,CAAC,gDAAgD,EAAE,GAAG,EAAE,CAC/D,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAClB,MAAM,GAAG,GAAG,IAAI,iBAAiB,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;IAChE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;AAC5C,CAAC,CAAC,CACH,CAAC"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Per-subscription event registry for `MoltZapWsClient`.
3
+ *
4
+ * Responsibility: own the list of live `subscribe()` handles and fan each
5
+ * inbound `EventFrame` out to every subscription whose filter matches.
6
+ * Implements spec #222 §5.3 (C4 + the `RealClientEventSubscriber.subscribe`
7
+ * filter stub). Lives as an internal collaborator of `MoltZapWsClient`;
8
+ * the public types (`SubscriptionFilter`, `EventSubscription`,
9
+ * `SubscriptionId`) re-export from the package barrel.
10
+ *
11
+ * Dispatch ordering (Invariant 6 — events delivered in arrival order):
12
+ * 1. Inbound frames are handed to the registry in arrival order.
13
+ * 2. Within a single frame, subscriptions are notified in registration
14
+ * order.
15
+ * 3. There is no separate legacy `onEvent` fanout — spec #222 OQ-4 is
16
+ * resolved by DELETING `MoltZapWsClientOptions.onEvent`. Callers
17
+ * that want "every event" register `subscribe({}, handler)` after
18
+ * construction and before `connect()`.
19
+ *
20
+ * Unsubscribe semantics (OQ-3 A): `unsubscribe` takes effect on the next
21
+ * frame. The registry snapshots its live-subscription list at the start
22
+ * of each `dispatch` call; in-flight dispatch of frame N is not
23
+ * interrupted by an unsubscribe during frame N. Frame N+1 observes the
24
+ * unsubscribed state.
25
+ *
26
+ * Error channel: handlers are invoked inside a defect-catcher; a throw is
27
+ * logged via the client's injected `WsClientLogger` and swallowed
28
+ * (matching the prior `onEvent` contract at `ws-client.ts:650-655`
29
+ * pre-deletion). The registry itself has no typed error surface —
30
+ * `register`, `dispatch`, and `closeAll` are `Effect<T, never>`.
31
+ */
32
+ import { Effect } from "effect";
33
+ import type { EventFrame } from "@moltzap/protocol";
34
+ /** Branded identifier for a subscription handle. Minted by `register`. */
35
+ export type SubscriptionId = string & {
36
+ readonly __brand: "SubscriptionId";
37
+ };
38
+ /**
39
+ * Filter grammar for `subscribe`. An event is delivered to a subscription
40
+ * iff it matches **every** field that is set on the filter. Unset fields
41
+ * are wildcards; the empty filter `{}` matches every event.
42
+ *
43
+ * OQ-2 resolution (A): exactly these three fields, no free-form
44
+ * predicate, no schema-derived matcher. Matches the existing
45
+ * `RealClientEventFilter` contract at
46
+ * `packages/protocol/src/testing/conformance/client/runner.ts:104-116`
47
+ * one-for-one.
48
+ *
49
+ * - `emissionTag` — exact match against the canonical payload key
50
+ * `frame.data.__emissionTag`. (The adapter reads the same key at
51
+ * `packages/client/src/test-utils/conformance-adapter.ts:77-79`;
52
+ * `emitTaggedEventDefault` writes it at `runner.ts:343-357`. The
53
+ * `__emissionId` string in the `runner.ts:108` doc comment is a
54
+ * known doc-bug — architect files a follow-up issue against
55
+ * protocol to correct the comment; it is not the canonical name.)
56
+ * - `conversationId` — exact match against `frame.data.conversationId`
57
+ * when set on the event payload.
58
+ * - `eventNamePrefix` — `frame.event.startsWith(prefix)`.
59
+ */
60
+ export interface SubscriptionFilter {
61
+ readonly emissionTag?: string;
62
+ readonly conversationId?: string;
63
+ readonly eventNamePrefix?: string;
64
+ }
65
+ /**
66
+ * Handle returned by `register` / `MoltZapWsClient.subscribe`. Caller
67
+ * holds the handle for its subscription's lifetime and runs
68
+ * `unsubscribe` to stop delivery.
69
+ *
70
+ * `unsubscribe` is `Effect<void, never>`: it is idempotent and total.
71
+ * Calling `unsubscribe` a second time, or after `closeAll`, is a no-op.
72
+ */
73
+ export interface EventSubscription {
74
+ readonly id: SubscriptionId;
75
+ readonly unsubscribe: Effect.Effect<void, never>;
76
+ }
77
+ /**
78
+ * Per-subscription handler signature. Runs inside the registry's
79
+ * dispatch fiber. Must not throw — throws are caught by the registry,
80
+ * logged via the injected logger, and swallowed.
81
+ *
82
+ * Returning an `Effect` (not a plain `void`) lets handlers compose with
83
+ * Effect-native downstream code without an extra runSync shim. The
84
+ * registry awaits each handler's effect before moving to the next
85
+ * subscription for this frame — fairness over throughput, so a slow
86
+ * handler on subscription A does not reorder frames seen by
87
+ * subscription B across frames.
88
+ */
89
+ export type SubscriberHandler = (frame: EventFrame) => Effect.Effect<void, never>;
90
+ /**
91
+ * Subscriber registry. One instance per `MoltZapWsClient`, created at
92
+ * construction time and owned by the client. Not exported from the
93
+ * package barrel — consumers reach the registry only through
94
+ * `MoltZapWsClient.subscribe`.
95
+ */
96
+ export interface SubscriberRegistry {
97
+ /**
98
+ * Add a subscription. Returns the handle immediately; delivery starts
99
+ * with the next frame passed to `dispatch`. Does not await any
100
+ * connection state — subscribe is legal pre-connect (spec §5.3 +
101
+ * Assumption 1 deletion: post-delete of `onEvent`, subscribe is the
102
+ * only pre-connect event hook).
103
+ */
104
+ readonly register: (filter: SubscriptionFilter, handler: SubscriberHandler) => Effect.Effect<EventSubscription, never>;
105
+ /**
106
+ * Fan an inbound event out to every matching subscription. Called by
107
+ * `MoltZapWsClient.handleIncoming` at the existing event-dispatch
108
+ * point (`ws-client.ts:649-685`). Implementation snapshots the
109
+ * live-subscription list at the start of dispatch so
110
+ * unsubscribe-during-dispatch observes next-frame semantics (OQ-3 A).
111
+ *
112
+ * Dispatch order: registration order, iterated sequentially; slow
113
+ * handlers block later subscriptions for this frame but never
114
+ * reorder frame N relative to frame N+1.
115
+ */
116
+ readonly dispatch: (frame: EventFrame) => Effect.Effect<void, never>;
117
+ /**
118
+ * Drop every live subscription. Called from `MoltZapWsClient.close`
119
+ * so handlers stop firing once the client is torn down. Idempotent.
120
+ */
121
+ readonly closeAll: Effect.Effect<void, never>;
122
+ }
123
+ /**
124
+ * Construct an empty registry. Called once from the `MoltZapWsClient`
125
+ * constructor. Takes a logger so registry-internal error logs reach the
126
+ * same sink as the rest of the client.
127
+ *
128
+ * Implementation notes:
129
+ * - Live subscriptions are stored in a `Ref<ReadonlyArray<…>>` keyed
130
+ * by registration order. Append-on-register, filter-on-unsubscribe
131
+ * keeps the dispatch path O(N) with N = live subscription count.
132
+ * Bigger structures aren't justified at the expected sub count
133
+ * (≤ ~10 per fixture).
134
+ * - `dispatch` snapshots the array at start (OQ-3 A). An
135
+ * `unsubscribe` mid-dispatch mutates the Ref but the in-flight
136
+ * iteration walks the snapshot.
137
+ * - Handler exceptions are caught with `Effect.catchAllDefect` after
138
+ * the handler Effect. Sync `throw` from a `(frame) => …` body
139
+ * surfaces as a defect; we log + swallow to match the pre-deletion
140
+ * `onEvent` contract.
141
+ */
142
+ export declare function makeSubscriberRegistry(logger: {
143
+ readonly warn: (...args: ReadonlyArray<unknown>) => void;
144
+ }): Effect.Effect<SubscriberRegistry, never>;
145
+ /**
146
+ * Pure filter-match predicate. Exposed for unit testing so executable
147
+ * client-side divergence proofs can force known-bad subscription
148
+ * behavior without bypassing the production dispatch path.
149
+ *
150
+ * Returns `true` iff `frame` matches every set field on `filter`:
151
+ * - `filter.emissionTag === frame.data.__emissionTag` (strict ===)
152
+ * - `filter.conversationId === frame.data.conversationId` (strict ===)
153
+ * - `frame.event.startsWith(filter.eventNamePrefix)`
154
+ * Unset filter fields are wildcards.
155
+ */
156
+ export declare function matchesFilter(filter: SubscriptionFilter, frame: EventFrame): boolean;
157
+ //# sourceMappingURL=subscribers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribers.d.ts","sourceRoot":"","sources":["../../src/runtime/subscribers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,MAAM,EAAO,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEpD,0EAA0E;AAC1E,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;CAClD;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAC9B,KAAK,EAAE,UAAU,KACd,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,CACjB,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,iBAAiB,KACvB,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;IAE7C;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAErE;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;CAC/C;AAQD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CAC1D,GAAG,MAAM,CAAC,MAAM,CAAC,kBAAkB,EAAE,KAAK,CAAC,CA8C3C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,UAAU,GAChB,OAAO,CA8BT"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Per-subscription event registry for `MoltZapWsClient`.
3
+ *
4
+ * Responsibility: own the list of live `subscribe()` handles and fan each
5
+ * inbound `EventFrame` out to every subscription whose filter matches.
6
+ * Implements spec #222 §5.3 (C4 + the `RealClientEventSubscriber.subscribe`
7
+ * filter stub). Lives as an internal collaborator of `MoltZapWsClient`;
8
+ * the public types (`SubscriptionFilter`, `EventSubscription`,
9
+ * `SubscriptionId`) re-export from the package barrel.
10
+ *
11
+ * Dispatch ordering (Invariant 6 — events delivered in arrival order):
12
+ * 1. Inbound frames are handed to the registry in arrival order.
13
+ * 2. Within a single frame, subscriptions are notified in registration
14
+ * order.
15
+ * 3. There is no separate legacy `onEvent` fanout — spec #222 OQ-4 is
16
+ * resolved by DELETING `MoltZapWsClientOptions.onEvent`. Callers
17
+ * that want "every event" register `subscribe({}, handler)` after
18
+ * construction and before `connect()`.
19
+ *
20
+ * Unsubscribe semantics (OQ-3 A): `unsubscribe` takes effect on the next
21
+ * frame. The registry snapshots its live-subscription list at the start
22
+ * of each `dispatch` call; in-flight dispatch of frame N is not
23
+ * interrupted by an unsubscribe during frame N. Frame N+1 observes the
24
+ * unsubscribed state.
25
+ *
26
+ * Error channel: handlers are invoked inside a defect-catcher; a throw is
27
+ * logged via the client's injected `WsClientLogger` and swallowed
28
+ * (matching the prior `onEvent` contract at `ws-client.ts:650-655`
29
+ * pre-deletion). The registry itself has no typed error surface —
30
+ * `register`, `dispatch`, and `closeAll` are `Effect<T, never>`.
31
+ */
32
+ import { Effect, Ref } from "effect";
33
+ /**
34
+ * Construct an empty registry. Called once from the `MoltZapWsClient`
35
+ * constructor. Takes a logger so registry-internal error logs reach the
36
+ * same sink as the rest of the client.
37
+ *
38
+ * Implementation notes:
39
+ * - Live subscriptions are stored in a `Ref<ReadonlyArray<…>>` keyed
40
+ * by registration order. Append-on-register, filter-on-unsubscribe
41
+ * keeps the dispatch path O(N) with N = live subscription count.
42
+ * Bigger structures aren't justified at the expected sub count
43
+ * (≤ ~10 per fixture).
44
+ * - `dispatch` snapshots the array at start (OQ-3 A). An
45
+ * `unsubscribe` mid-dispatch mutates the Ref but the in-flight
46
+ * iteration walks the snapshot.
47
+ * - Handler exceptions are caught with `Effect.catchAllDefect` after
48
+ * the handler Effect. Sync `throw` from a `(frame) => …` body
49
+ * surfaces as a defect; we log + swallow to match the pre-deletion
50
+ * `onEvent` contract.
51
+ */
52
+ export function makeSubscriberRegistry(logger) {
53
+ return Effect.gen(function* () {
54
+ const subsRef = yield* Ref.make([]);
55
+ const counterRef = yield* Ref.make(0);
56
+ const register = (filter, handler) => Effect.gen(function* () {
57
+ const n = yield* Ref.updateAndGet(counterRef, (c) => c + 1);
58
+ const id = `sub-${n}`;
59
+ const live = { id, filter, handler };
60
+ yield* Ref.update(subsRef, (xs) => [...xs, live]);
61
+ const unsubscribe = Ref.update(subsRef, (xs) => xs.filter((s) => s.id !== id));
62
+ return { id, unsubscribe };
63
+ });
64
+ const dispatch = (frame) => Effect.gen(function* () {
65
+ // Snapshot at dispatch-start: OQ-3 A. Unsubscribes during this
66
+ // frame mutate `subsRef` but our iteration walks `snapshot`.
67
+ const snapshot = yield* Ref.get(subsRef);
68
+ // Short-circuit the common pre-subscribe path (every inbound
69
+ // frame before any `subscribe()` call) so hot-path dispatch
70
+ // avoids even the `for…of` allocation.
71
+ if (snapshot.length === 0)
72
+ return;
73
+ for (const sub of snapshot) {
74
+ if (!matchesFilter(sub.filter, frame))
75
+ continue;
76
+ // Handlers must not throw; we catch defects defensively so
77
+ // one buggy subscriber can't kill the dispatch loop or break
78
+ // the reader fiber.
79
+ yield* Effect.suspend(() => sub.handler(frame)).pipe(Effect.catchAllDefect((err) => Effect.sync(() => {
80
+ logger.warn("subscriber handler threw", err);
81
+ })));
82
+ }
83
+ });
84
+ const closeAll = Ref.set(subsRef, []);
85
+ return { register, dispatch, closeAll };
86
+ });
87
+ }
88
+ /**
89
+ * Pure filter-match predicate. Exposed for unit testing so executable
90
+ * client-side divergence proofs can force known-bad subscription
91
+ * behavior without bypassing the production dispatch path.
92
+ *
93
+ * Returns `true` iff `frame` matches every set field on `filter`:
94
+ * - `filter.emissionTag === frame.data.__emissionTag` (strict ===)
95
+ * - `filter.conversationId === frame.data.conversationId` (strict ===)
96
+ * - `frame.event.startsWith(filter.eventNamePrefix)`
97
+ * Unset filter fields are wildcards.
98
+ */
99
+ export function matchesFilter(filter, frame) {
100
+ if (filter.eventNamePrefix !== undefined) {
101
+ if (!frame.event.startsWith(filter.eventNamePrefix))
102
+ return false;
103
+ }
104
+ // `frame.data` is `unknown` per the EventFrame schema; narrow it to
105
+ // a record before reading the two payload-keyed fields. Anything
106
+ // else (string, number, array) cannot satisfy a payload-key filter.
107
+ // The cast is annotated below: the EventFrame schema declares `data:
108
+ // unknown`, and the OQ-2 A filter grammar intentionally treats
109
+ // payloads as untyped maps so arbitrary publisher payloads can be
110
+ // filtered without a per-event schema tax. The `typeof === "object"`
111
+ // guard is the runtime boundary; the read sites
112
+ // (`data?.["__emissionTag"]`, `data?.["conversationId"]`) defend
113
+ // against missing or wrong-typed values via `=== filter.<field>`.
114
+ const data = typeof frame.data === "object" &&
115
+ frame.data !== null &&
116
+ !Array.isArray(frame.data)
117
+ ? frame.data // #ignore-sloppy-code[record-cast]: EventFrame schema declares `data: unknown`; OQ-2 A filter treats payloads as untyped maps; the typeof guard above is the runtime boundary
118
+ : null;
119
+ if (filter.emissionTag !== undefined) {
120
+ const tag = data?.["__emissionTag"];
121
+ if (tag !== filter.emissionTag)
122
+ return false;
123
+ }
124
+ if (filter.conversationId !== undefined) {
125
+ const cid = data?.["conversationId"];
126
+ if (cid !== filter.conversationId)
127
+ return false;
128
+ }
129
+ return true;
130
+ }
131
+ //# sourceMappingURL=subscribers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribers.js","sourceRoot":"","sources":["../../src/runtime/subscribers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=subscribers.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribers.test.d.ts","sourceRoot":"","sources":["../../src/runtime/subscribers.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Unit tests for the per-subscription event registry.
3
+ *
4
+ * Spec #222 §5.3 (C4 + the `RealClientEventSubscriber.subscribe` filter
5
+ * stub) requires:
6
+ * - Every set filter field narrows delivery (AND semantics).
7
+ * - Subscriptions fire in registration order.
8
+ * - Unsubscribe-during-dispatch is next-frame effective (OQ-3 A
9
+ * snapshot semantics).
10
+ * - Handler exceptions are caught + logged, not propagated.
11
+ *
12
+ * Each scenario gets a dedicated test so a mutation that bypasses the
13
+ * filter (e.g. force `matchesFilter` to always return `true`) trips the
14
+ * filter-narrows tests but leaves order tests passing — the tests
15
+ * discriminate.
16
+ */
17
+ import { describe, expect, it, vi } from "vitest";
18
+ import { Effect, Ref } from "effect";
19
+ import { makeSubscriberRegistry, matchesFilter } from "./subscribers.js";
20
+ const eventFrame = (event, data) => ({
21
+ jsonrpc: "2.0",
22
+ type: "event",
23
+ event,
24
+ data,
25
+ });
26
+ const noopLogger = { warn: vi.fn() };
27
+ describe("matchesFilter", () => {
28
+ it("empty filter matches every frame", () => {
29
+ expect(matchesFilter({}, eventFrame("any", { x: 1 }))).toBe(true);
30
+ });
31
+ it("emissionTag matches on `__emissionTag` key", () => {
32
+ const frame = eventFrame("e", { __emissionTag: "tag-1" });
33
+ expect(matchesFilter({ emissionTag: "tag-1" }, frame)).toBe(true);
34
+ expect(matchesFilter({ emissionTag: "tag-other" }, frame)).toBe(false);
35
+ });
36
+ it("conversationId matches on `conversationId` key", () => {
37
+ const frame = eventFrame("e", { conversationId: "c-1" });
38
+ expect(matchesFilter({ conversationId: "c-1" }, frame)).toBe(true);
39
+ expect(matchesFilter({ conversationId: "c-2" }, frame)).toBe(false);
40
+ });
41
+ it("eventNamePrefix uses startsWith", () => {
42
+ const frame = eventFrame("messages/received", {});
43
+ expect(matchesFilter({ eventNamePrefix: "messages/" }, frame)).toBe(true);
44
+ expect(matchesFilter({ eventNamePrefix: "presence/" }, frame)).toBe(false);
45
+ });
46
+ it("AND semantics: all set fields must match", () => {
47
+ const frame = eventFrame("messages/received", {
48
+ __emissionTag: "tag-1",
49
+ conversationId: "c-1",
50
+ });
51
+ expect(matchesFilter({ emissionTag: "tag-1", conversationId: "c-1", eventNamePrefix: "m" }, frame)).toBe(true);
52
+ // conversationId mismatch → reject even when other fields match.
53
+ expect(matchesFilter({ emissionTag: "tag-1", conversationId: "c-other" }, frame)).toBe(false);
54
+ });
55
+ it("non-record `data` cannot satisfy payload-key filters", () => {
56
+ const stringData = eventFrame("e", "string-payload");
57
+ expect(matchesFilter({ emissionTag: "x" }, stringData)).toBe(false);
58
+ expect(matchesFilter({ conversationId: "x" }, stringData)).toBe(false);
59
+ // …but an event-name-prefix filter still applies.
60
+ expect(matchesFilter({ eventNamePrefix: "e" }, stringData)).toBe(true);
61
+ });
62
+ });
63
+ describe("SubscriberRegistry", () => {
64
+ it("dispatches in registration order", async () => {
65
+ const registry = await Effect.runPromise(makeSubscriberRegistry(noopLogger));
66
+ const order = [];
67
+ await Effect.runPromise(registry.register({}, () => Effect.sync(() => void order.push("a"))));
68
+ await Effect.runPromise(registry.register({}, () => Effect.sync(() => void order.push("b"))));
69
+ await Effect.runPromise(registry.dispatch(eventFrame("e", {})));
70
+ expect(order).toEqual(["a", "b"]);
71
+ });
72
+ it("unsubscribe stops delivery for the next frame (OQ-3 A snapshot)", async () => {
73
+ const registry = await Effect.runPromise(makeSubscriberRegistry(noopLogger));
74
+ const aCalls = [];
75
+ const bCalls = [];
76
+ let frameIdx = 0;
77
+ let unsubA = null;
78
+ const handleA = await Effect.runPromise(registry.register({}, () => Effect.gen(function* () {
79
+ aCalls.push(frameIdx);
80
+ // During the FIRST frame's dispatch, a unsubscribes itself.
81
+ // OQ-3 A: b should still see frame 0 (snapshot taken at
82
+ // dispatch start), but a should NOT see frame 1.
83
+ if (frameIdx === 0 && unsubA !== null) {
84
+ yield* unsubA;
85
+ }
86
+ })));
87
+ unsubA = handleA.unsubscribe;
88
+ await Effect.runPromise(registry.register({}, () => Effect.sync(() => void bCalls.push(frameIdx))));
89
+ frameIdx = 0;
90
+ await Effect.runPromise(registry.dispatch(eventFrame("e", {})));
91
+ frameIdx = 1;
92
+ await Effect.runPromise(registry.dispatch(eventFrame("e", {})));
93
+ expect(aCalls).toEqual([0]); // a saw frame 0, not frame 1.
94
+ expect(bCalls).toEqual([0, 1]); // b saw both — snapshot at start of frame 0 still included a; b is unaffected by a's unsub.
95
+ });
96
+ it("filters narrow delivery", async () => {
97
+ const registry = await Effect.runPromise(makeSubscriberRegistry(noopLogger));
98
+ const seenByConv1 = [];
99
+ const seenByConv2 = [];
100
+ await Effect.runPromise(registry.register({ conversationId: "c-1" }, (frame) => Effect.sync(() => void seenByConv1.push(frame))));
101
+ await Effect.runPromise(registry.register({ conversationId: "c-2" }, (frame) => Effect.sync(() => void seenByConv2.push(frame))));
102
+ await Effect.runPromise(registry.dispatch(eventFrame("e", { conversationId: "c-1" })));
103
+ await Effect.runPromise(registry.dispatch(eventFrame("e", { conversationId: "c-2" })));
104
+ expect(seenByConv1).toHaveLength(1);
105
+ expect(seenByConv2).toHaveLength(1);
106
+ expect(seenByConv1[0].data.conversationId).toBe("c-1");
107
+ expect(seenByConv2[0].data.conversationId).toBe("c-2");
108
+ });
109
+ it("handler exceptions are caught + logged via the injected logger", async () => {
110
+ const warn = vi.fn();
111
+ const registry = await Effect.runPromise(makeSubscriberRegistry({ warn }));
112
+ const otherCalls = [];
113
+ await Effect.runPromise(registry.register({}, () => Effect.sync(() => {
114
+ throw new Error("subscriber blew up");
115
+ })));
116
+ await Effect.runPromise(registry.register({}, () => Effect.sync(() => void otherCalls.push(1))));
117
+ await Effect.runPromise(registry.dispatch(eventFrame("e", {})));
118
+ expect(warn).toHaveBeenCalledTimes(1);
119
+ expect(otherCalls).toEqual([1]); // other subscribers still fire.
120
+ });
121
+ it("construction-time throw from handler is caught + logged (not escaped)", async () => {
122
+ const warn = vi.fn();
123
+ const registry = await Effect.runPromise(makeSubscriberRegistry({ warn }));
124
+ const otherCalls = [];
125
+ await Effect.runPromise(registry.register({}, (_frame) => {
126
+ throw new Error("construction-time throw");
127
+ }));
128
+ await Effect.runPromise(registry.register({}, () => Effect.sync(() => void otherCalls.push(1))));
129
+ await Effect.runPromise(registry.dispatch(eventFrame("e", {})));
130
+ expect(warn).toHaveBeenCalledTimes(1);
131
+ expect(otherCalls).toEqual([1]); // subsequent subscribers still fire.
132
+ });
133
+ it("closeAll drops every subscription", async () => {
134
+ const registry = await Effect.runPromise(makeSubscriberRegistry(noopLogger));
135
+ const calls = [];
136
+ await Effect.runPromise(registry.register({}, () => Effect.sync(() => void calls.push(1))));
137
+ await Effect.runPromise(registry.closeAll);
138
+ await Effect.runPromise(registry.dispatch(eventFrame("e", {})));
139
+ expect(calls).toEqual([]);
140
+ });
141
+ it("Ref-make composition works: register inside an Effect.gen", async () => {
142
+ // Smoke test that the Effect surface composes; the registry never
143
+ // resolves with `never` failure tag, so this can't catch
144
+ // typechecker drift, but it does pin behaviour.
145
+ const result = await Effect.runPromise(Effect.gen(function* () {
146
+ const registry = yield* makeSubscriberRegistry(noopLogger);
147
+ const counter = yield* Ref.make(0);
148
+ yield* registry.register({}, () => Ref.update(counter, (n) => n + 1));
149
+ yield* registry.dispatch(eventFrame("e", {}));
150
+ return yield* Ref.get(counter);
151
+ }));
152
+ expect(result).toBe(1);
153
+ });
154
+ });
155
+ //# sourceMappingURL=subscribers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscribers.test.js","sourceRoot":"","sources":["../../src/runtime/subscribers.test.ts"],"names":[],"mappings":"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"}