@joe-broadhead/messaging 0.0.0-stage → 0.7.1

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 (273) hide show
  1. package/CHANGELOG.md +220 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +12 -0
  4. package/README.md +36 -2
  5. package/dist/bin/messaging-mcp.js +26524 -0
  6. package/dist/bin/messaging-relay.js +19768 -0
  7. package/dist/bin/messaging.js +15465 -0
  8. package/dist/bin/messagingd.js +29449 -0
  9. package/dist/lib/core-testing.js +1 -0
  10. package/dist/lib/core.js +1 -0
  11. package/dist/lib/ipc-testing.js +1 -0
  12. package/dist/lib/ipc.js +1 -0
  13. package/dist/lib/modules/core/address.js +42 -0
  14. package/dist/lib/modules/core/agent/operations.js +595 -0
  15. package/dist/lib/modules/core/agent/present.js +244 -0
  16. package/dist/lib/modules/core/agent/text.js +79 -0
  17. package/dist/lib/modules/core/agent-tools.js +477 -0
  18. package/dist/lib/modules/core/b64u.js +20 -0
  19. package/dist/lib/modules/core/cards.js +55 -0
  20. package/dist/lib/modules/core/check.js +20 -0
  21. package/dist/lib/modules/core/consent.js +199 -0
  22. package/dist/lib/modules/core/contact-card.js +74 -0
  23. package/dist/lib/modules/core/conversation/context.js +80 -0
  24. package/dist/lib/modules/core/conversation/event.js +100 -0
  25. package/dist/lib/modules/core/conversation/ids.js +38 -0
  26. package/dist/lib/modules/core/conversation/link.js +35 -0
  27. package/dist/lib/modules/core/conversation/log.js +766 -0
  28. package/dist/lib/modules/core/conversation/ratchet.js +243 -0
  29. package/dist/lib/modules/core/conversation/seal.js +198 -0
  30. package/dist/lib/modules/core/delegation.js +174 -0
  31. package/dist/lib/modules/core/directory/device-log.js +258 -0
  32. package/dist/lib/modules/core/directory/epoch.js +103 -0
  33. package/dist/lib/modules/core/directory/handle.js +29 -0
  34. package/dist/lib/modules/core/directory/jelly-device.js +204 -0
  35. package/dist/lib/modules/core/directory/jelly-issuer.js +12 -0
  36. package/dist/lib/modules/core/directory/jelly-token.js +305 -0
  37. package/dist/lib/modules/core/directory/keys-statement.js +43 -0
  38. package/dist/lib/modules/core/directory/link.js +81 -0
  39. package/dist/lib/modules/core/directory/merkle-log.js +250 -0
  40. package/dist/lib/modules/core/directory/person-view.js +197 -0
  41. package/dist/lib/modules/core/directory/person.js +40 -0
  42. package/dist/lib/modules/core/directory/realm.js +59 -0
  43. package/dist/lib/modules/core/directory/smt.js +266 -0
  44. package/dist/lib/modules/core/envelope.js +320 -0
  45. package/dist/lib/modules/core/hash.js +5 -0
  46. package/dist/lib/modules/core/head.js +27 -0
  47. package/dist/lib/modules/core/identity.js +71 -0
  48. package/dist/lib/modules/core/index.js +53 -0
  49. package/dist/lib/modules/core/jcs.js +96 -0
  50. package/dist/lib/modules/core/jelly-host-double.js +35 -0
  51. package/dist/lib/modules/core/jelly-host.js +211 -0
  52. package/dist/lib/modules/core/keys.js +79 -0
  53. package/dist/lib/modules/core/peer-text.js +563 -0
  54. package/dist/lib/modules/core/realm.js +1 -0
  55. package/dist/lib/modules/core/roster.js +454 -0
  56. package/dist/lib/modules/core/schema/a2a.js +85 -0
  57. package/dist/lib/modules/core/schema/common.js +310 -0
  58. package/dist/lib/modules/core/schema/consent.js +120 -0
  59. package/dist/lib/modules/core/schema/conversation.js +292 -0
  60. package/dist/lib/modules/core/schema/delegation.js +58 -0
  61. package/dist/lib/modules/core/schema/directory-frames.js +270 -0
  62. package/dist/lib/modules/core/schema/directory.js +169 -0
  63. package/dist/lib/modules/core/schema/envelope.js +211 -0
  64. package/dist/lib/modules/core/schema/errors.js +104 -0
  65. package/dist/lib/modules/core/schema/index.js +16 -0
  66. package/dist/lib/modules/core/schema/ipc/consent.js +181 -0
  67. package/dist/lib/modules/core/schema/ipc/device.js +276 -0
  68. package/dist/lib/modules/core/schema/ipc/jelly.js +189 -0
  69. package/dist/lib/modules/core/schema/ipc/shapes.js +185 -0
  70. package/dist/lib/modules/core/schema/ipc/surfaces.js +223 -0
  71. package/dist/lib/modules/core/schema/ipc.js +451 -0
  72. package/dist/lib/modules/core/schema/jelly.js +122 -0
  73. package/dist/lib/modules/core/schema/realm.js +27 -0
  74. package/dist/lib/modules/core/schema/relay.js +112 -0
  75. package/dist/lib/modules/core/schema/roster.js +126 -0
  76. package/dist/lib/modules/core/sign.js +43 -0
  77. package/dist/lib/modules/core/task.js +37 -0
  78. package/dist/lib/modules/core/testing.js +21 -0
  79. package/dist/lib/modules/core/ulid.js +36 -0
  80. package/dist/lib/modules/core/version.js +6 -0
  81. package/dist/lib/modules/core/wire.js +255 -0
  82. package/dist/lib/modules/ipc/client.js +289 -0
  83. package/dist/lib/modules/ipc/framing.js +33 -0
  84. package/dist/lib/modules/ipc/index.js +6 -0
  85. package/dist/lib/modules/ipc/paths.js +102 -0
  86. package/dist/lib/modules/ipc/pipes.js +65 -0
  87. package/dist/lib/modules/ipc/rpc.js +8 -0
  88. package/dist/lib/modules/ipc/server.js +317 -0
  89. package/dist/lib/modules/ipc/testing.js +145 -0
  90. package/dist/lib/modules/ipc/trust.js +166 -0
  91. package/dist/lib/modules/ipc/windows-acl.js +275 -0
  92. package/dist/lib/modules/vendor/zod/index.js +7 -0
  93. package/dist/lib/modules/vendor/zod/v4/classic/checks.js +1 -0
  94. package/dist/lib/modules/vendor/zod/v4/classic/coerce.js +17 -0
  95. package/dist/lib/modules/vendor/zod/v4/classic/compat.js +31 -0
  96. package/dist/lib/modules/vendor/zod/v4/classic/deep-partial.js +13 -0
  97. package/dist/lib/modules/vendor/zod/v4/classic/errors.js +57 -0
  98. package/dist/lib/modules/vendor/zod/v4/classic/external.js +17 -0
  99. package/dist/lib/modules/vendor/zod/v4/classic/from-json-schema.js +881 -0
  100. package/dist/lib/modules/vendor/zod/v4/classic/in-out.js +36 -0
  101. package/dist/lib/modules/vendor/zod/v4/classic/iso.js +15 -0
  102. package/dist/lib/modules/vendor/zod/v4/classic/parse.js +16 -0
  103. package/dist/lib/modules/vendor/zod/v4/classic/schemas.js +1535 -0
  104. package/dist/lib/modules/vendor/zod/v4/core/api.js +1107 -0
  105. package/dist/lib/modules/vendor/zod/v4/core/checks.js +516 -0
  106. package/dist/lib/modules/vendor/zod/v4/core/compile.js +1866 -0
  107. package/dist/lib/modules/vendor/zod/v4/core/core.js +141 -0
  108. package/dist/lib/modules/vendor/zod/v4/core/doc.js +38 -0
  109. package/dist/lib/modules/vendor/zod/v4/core/errors.js +267 -0
  110. package/dist/lib/modules/vendor/zod/v4/core/index.js +19 -0
  111. package/dist/lib/modules/vendor/zod/v4/core/json-schema-generator.js +99 -0
  112. package/dist/lib/modules/vendor/zod/v4/core/json-schema-processors.js +843 -0
  113. package/dist/lib/modules/vendor/zod/v4/core/json-schema.js +1 -0
  114. package/dist/lib/modules/vendor/zod/v4/core/memoizer.js +311 -0
  115. package/dist/lib/modules/vendor/zod/v4/core/parse.js +175 -0
  116. package/dist/lib/modules/vendor/zod/v4/core/regexes.js +156 -0
  117. package/dist/lib/modules/vendor/zod/v4/core/registries.js +51 -0
  118. package/dist/lib/modules/vendor/zod/v4/core/schemas.js +2636 -0
  119. package/dist/lib/modules/vendor/zod/v4/core/to-json-schema.js +651 -0
  120. package/dist/lib/modules/vendor/zod/v4/core/util.js +873 -0
  121. package/dist/lib/modules/vendor/zod/v4/core/versions.js +5 -0
  122. package/dist/lib/modules/vendor/zod/v4/core/visit.js +169 -0
  123. package/dist/lib/modules/vendor/zod/v4/locales/ar.js +111 -0
  124. package/dist/lib/modules/vendor/zod/v4/locales/az.js +110 -0
  125. package/dist/lib/modules/vendor/zod/v4/locales/be.js +168 -0
  126. package/dist/lib/modules/vendor/zod/v4/locales/bg.js +125 -0
  127. package/dist/lib/modules/vendor/zod/v4/locales/bn.js +113 -0
  128. package/dist/lib/modules/vendor/zod/v4/locales/ca.js +112 -0
  129. package/dist/lib/modules/vendor/zod/v4/locales/ckb.js +133 -0
  130. package/dist/lib/modules/vendor/zod/v4/locales/cs.js +116 -0
  131. package/dist/lib/modules/vendor/zod/v4/locales/da.js +120 -0
  132. package/dist/lib/modules/vendor/zod/v4/locales/de.js +113 -0
  133. package/dist/lib/modules/vendor/zod/v4/locales/el.js +112 -0
  134. package/dist/lib/modules/vendor/zod/v4/locales/en.js +125 -0
  135. package/dist/lib/modules/vendor/zod/v4/locales/eo.js +114 -0
  136. package/dist/lib/modules/vendor/zod/v4/locales/es.js +136 -0
  137. package/dist/lib/modules/vendor/zod/v4/locales/fa.js +119 -0
  138. package/dist/lib/modules/vendor/zod/v4/locales/fi.js +117 -0
  139. package/dist/lib/modules/vendor/zod/v4/locales/fr-CA.js +112 -0
  140. package/dist/lib/modules/vendor/zod/v4/locales/fr.js +129 -0
  141. package/dist/lib/modules/vendor/zod/v4/locales/gu.js +113 -0
  142. package/dist/lib/modules/vendor/zod/v4/locales/he.js +221 -0
  143. package/dist/lib/modules/vendor/zod/v4/locales/hi.js +111 -0
  144. package/dist/lib/modules/vendor/zod/v4/locales/hr.js +126 -0
  145. package/dist/lib/modules/vendor/zod/v4/locales/hu.js +113 -0
  146. package/dist/lib/modules/vendor/zod/v4/locales/hy.js +158 -0
  147. package/dist/lib/modules/vendor/zod/v4/locales/id.js +111 -0
  148. package/dist/lib/modules/vendor/zod/v4/locales/index.js +63 -0
  149. package/dist/lib/modules/vendor/zod/v4/locales/is.js +114 -0
  150. package/dist/lib/modules/vendor/zod/v4/locales/it.js +113 -0
  151. package/dist/lib/modules/vendor/zod/v4/locales/ja.js +112 -0
  152. package/dist/lib/modules/vendor/zod/v4/locales/ka.js +117 -0
  153. package/dist/lib/modules/vendor/zod/v4/locales/kh.js +5 -0
  154. package/dist/lib/modules/vendor/zod/v4/locales/km.js +115 -0
  155. package/dist/lib/modules/vendor/zod/v4/locales/kn.js +116 -0
  156. package/dist/lib/modules/vendor/zod/v4/locales/ko.js +116 -0
  157. package/dist/lib/modules/vendor/zod/v4/locales/lt.js +207 -0
  158. package/dist/lib/modules/vendor/zod/v4/locales/mk.js +114 -0
  159. package/dist/lib/modules/vendor/zod/v4/locales/ms.js +112 -0
  160. package/dist/lib/modules/vendor/zod/v4/locales/ne.js +111 -0
  161. package/dist/lib/modules/vendor/zod/v4/locales/nl.js +115 -0
  162. package/dist/lib/modules/vendor/zod/v4/locales/nn.js +113 -0
  163. package/dist/lib/modules/vendor/zod/v4/locales/no.js +113 -0
  164. package/dist/lib/modules/vendor/zod/v4/locales/ota.js +114 -0
  165. package/dist/lib/modules/vendor/zod/v4/locales/pl.js +114 -0
  166. package/dist/lib/modules/vendor/zod/v4/locales/ps.js +119 -0
  167. package/dist/lib/modules/vendor/zod/v4/locales/pt-BR.js +143 -0
  168. package/dist/lib/modules/vendor/zod/v4/locales/pt.js +142 -0
  169. package/dist/lib/modules/vendor/zod/v4/locales/ro.js +122 -0
  170. package/dist/lib/modules/vendor/zod/v4/locales/ru.js +168 -0
  171. package/dist/lib/modules/vendor/zod/v4/locales/sk.js +116 -0
  172. package/dist/lib/modules/vendor/zod/v4/locales/sl.js +114 -0
  173. package/dist/lib/modules/vendor/zod/v4/locales/sv.js +115 -0
  174. package/dist/lib/modules/vendor/zod/v4/locales/ta.js +115 -0
  175. package/dist/lib/modules/vendor/zod/v4/locales/tg.js +117 -0
  176. package/dist/lib/modules/vendor/zod/v4/locales/th.js +115 -0
  177. package/dist/lib/modules/vendor/zod/v4/locales/tk.js +107 -0
  178. package/dist/lib/modules/vendor/zod/v4/locales/tr.js +110 -0
  179. package/dist/lib/modules/vendor/zod/v4/locales/ua.js +5 -0
  180. package/dist/lib/modules/vendor/zod/v4/locales/uk.js +113 -0
  181. package/dist/lib/modules/vendor/zod/v4/locales/ur.js +115 -0
  182. package/dist/lib/modules/vendor/zod/v4/locales/uz.js +113 -0
  183. package/dist/lib/modules/vendor/zod/v4/locales/vi.js +113 -0
  184. package/dist/lib/modules/vendor/zod/v4/locales/yo.js +112 -0
  185. package/dist/lib/modules/vendor/zod/v4/locales/zh-CN.js +114 -0
  186. package/dist/lib/modules/vendor/zod/v4/locales/zh-TW.js +112 -0
  187. package/dist/lib/testing-jelly-id.js +1219 -0
  188. package/dist/lib/zod.js +1 -0
  189. package/dist/spec/messaging-v1.md +3744 -0
  190. package/dist/third-party-notices.md +239 -0
  191. package/dist/third-party.json +88 -0
  192. package/dist/types/core/address.d.ts +16 -0
  193. package/dist/types/core/agent/operations.d.ts +129 -0
  194. package/dist/types/core/agent/present.d.ts +57 -0
  195. package/dist/types/core/agent/text.d.ts +62 -0
  196. package/dist/types/core/agent-tools.d.ts +966 -0
  197. package/dist/types/core/b64u.d.ts +6 -0
  198. package/dist/types/core/cards.d.ts +21 -0
  199. package/dist/types/core/check.d.ts +10 -0
  200. package/dist/types/core/consent.d.ts +132 -0
  201. package/dist/types/core/contact-card.d.ts +34 -0
  202. package/dist/types/core/conversation/context.d.ts +56 -0
  203. package/dist/types/core/conversation/event.d.ts +36 -0
  204. package/dist/types/core/conversation/ids.d.ts +18 -0
  205. package/dist/types/core/conversation/link.d.ts +16 -0
  206. package/dist/types/core/conversation/log.d.ts +142 -0
  207. package/dist/types/core/conversation/ratchet.d.ts +95 -0
  208. package/dist/types/core/conversation/seal.d.ts +47 -0
  209. package/dist/types/core/delegation.d.ts +71 -0
  210. package/dist/types/core/directory/device-log.d.ts +119 -0
  211. package/dist/types/core/directory/epoch.d.ts +53 -0
  212. package/dist/types/core/directory/handle.d.ts +11 -0
  213. package/dist/types/core/directory/jelly-device.d.ts +88 -0
  214. package/dist/types/core/directory/jelly-issuer.d.ts +8 -0
  215. package/dist/types/core/directory/jelly-token.d.ts +116 -0
  216. package/dist/types/core/directory/keys-statement.d.ts +22 -0
  217. package/dist/types/core/directory/link.d.ts +36 -0
  218. package/dist/types/core/directory/merkle-log.d.ts +40 -0
  219. package/dist/types/core/directory/person-view.d.ts +90 -0
  220. package/dist/types/core/directory/person.d.ts +8 -0
  221. package/dist/types/core/directory/realm.d.ts +23 -0
  222. package/dist/types/core/directory/smt.d.ts +52 -0
  223. package/dist/types/core/envelope.d.ts +68 -0
  224. package/dist/types/core/hash.d.ts +2 -0
  225. package/dist/types/core/head.d.ts +34 -0
  226. package/dist/types/core/identity.d.ts +35 -0
  227. package/dist/types/core/index.d.ts +45 -0
  228. package/dist/types/core/jcs.d.ts +12 -0
  229. package/dist/types/core/jelly-host-double.d.ts +21 -0
  230. package/dist/types/core/jelly-host.d.ts +86 -0
  231. package/dist/types/core/keys.d.ts +16 -0
  232. package/dist/types/core/peer-text.d.ts +87 -0
  233. package/dist/types/core/realm.d.ts +36 -0
  234. package/dist/types/core/roster.d.ts +146 -0
  235. package/dist/types/core/schema/a2a.d.ts +251 -0
  236. package/dist/types/core/schema/common.d.ts +328 -0
  237. package/dist/types/core/schema/consent.d.ts +140 -0
  238. package/dist/types/core/schema/conversation.d.ts +1657 -0
  239. package/dist/types/core/schema/delegation.d.ts +58 -0
  240. package/dist/types/core/schema/directory-frames.d.ts +1301 -0
  241. package/dist/types/core/schema/directory.d.ts +375 -0
  242. package/dist/types/core/schema/envelope.d.ts +756 -0
  243. package/dist/types/core/schema/errors.d.ts +142 -0
  244. package/dist/types/core/schema/index.d.ts +16 -0
  245. package/dist/types/core/schema/ipc/consent.d.ts +555 -0
  246. package/dist/types/core/schema/ipc/device.d.ts +735 -0
  247. package/dist/types/core/schema/ipc/jelly.d.ts +501 -0
  248. package/dist/types/core/schema/ipc/shapes.d.ts +414 -0
  249. package/dist/types/core/schema/ipc/surfaces.d.ts +680 -0
  250. package/dist/types/core/schema/ipc.d.ts +3146 -0
  251. package/dist/types/core/schema/jelly.d.ts +160 -0
  252. package/dist/types/core/schema/realm.d.ts +38 -0
  253. package/dist/types/core/schema/relay.d.ts +1134 -0
  254. package/dist/types/core/schema/roster.d.ts +347 -0
  255. package/dist/types/core/sign.d.ts +13 -0
  256. package/dist/types/core/task.d.ts +6 -0
  257. package/dist/types/core/testing.d.ts +19 -0
  258. package/dist/types/core/ulid.d.ts +5 -0
  259. package/dist/types/core/version.d.ts +6 -0
  260. package/dist/types/core/wire.d.ts +14 -0
  261. package/dist/types/ipc/client.d.ts +85 -0
  262. package/dist/types/ipc/framing.d.ts +12 -0
  263. package/dist/types/ipc/index.d.ts +6 -0
  264. package/dist/types/ipc/paths.d.ts +39 -0
  265. package/dist/types/ipc/pipes.d.ts +16 -0
  266. package/dist/types/ipc/rpc.d.ts +13 -0
  267. package/dist/types/ipc/server.d.ts +94 -0
  268. package/dist/types/ipc/testing.d.ts +89 -0
  269. package/dist/types/ipc/trust.d.ts +49 -0
  270. package/dist/types/ipc/windows-acl.d.ts +56 -0
  271. package/dist/types/testing/jelly-id.d.ts +518 -0
  272. package/dist/types/zod.d.ts +1 -0
  273. package/package.json +77 -4
@@ -0,0 +1,310 @@
1
+ import { z } from "../../vendor/zod/index.js";
2
+ /** Protocol identifier carried in every envelope and roster entry. A breaking change gets a new value. */
3
+ export const PROTOCOL = "messaging/1";
4
+ /** Relay WebSocket sub-protocol identifier. */
5
+ export const RELAY_PROTOCOL = "messaging-relay/1";
6
+ /**
7
+ * Domain-separation prefixes. Every signature covers `prefix + JCS(value)` as UTF-8,
8
+ * so a signature made for one purpose can never verify for another.
9
+ */
10
+ export const DOMAIN = {
11
+ envelope: "messaging/1/envelope\n",
12
+ roster: "messaging/1/roster\n",
13
+ relayAuth: "messaging/1/relay-auth\n",
14
+ /** An invite redeem proof, signed with the invite seed over JCS({team, inviteId, member}). */
15
+ invite: "messaging/1/invite\n",
16
+ /** A pre-auth `join` proof, signed with the invite seed over JCS({relay, team, inviteId, nonce}). */
17
+ inviteJoin: "messaging/1/invite-join\n",
18
+ /** A delegation grant, signed by the delegating machine over JCS(grant without sig). */
19
+ delegation: "messaging/1/delegation\n",
20
+ /** A consent grant (spec §6.9), signed by a device of its person over JCS(grant without sig). */
21
+ grant: "messaging/1/grant\n",
22
+ /** A contact card (spec §6.9, "Contact cards"), signed by a device of the person it speaks for over JCS(card without sig). */
23
+ card: "messaging/1/card\n",
24
+ /** HKDF `info` for sealing envelope bodies. */
25
+ seal: "messaging/1/seal",
26
+ /** Hosted realms (spec §15.1): the prefix of the hash that turns a Jelly account into a `PersonId`. */
27
+ person: "messaging/1/person\n",
28
+ /** Hosted realms (spec §15.5): an erased person's map value is the SHA-256 of this text. */
29
+ tombstone: "messaging/1/tombstone",
30
+ /**
31
+ * Hosted realms (spec §7, "Directory frames"): a device's proof, before `hello`, that it holds its key on this
32
+ * connection, signed over JCS(`dirReadPayload`), so it may read its own person's log.
33
+ */
34
+ dirRead: "messaging/1/dir-read\n",
35
+ /** Hosted realms (spec §15.3): a device-log entry, signed by `by` over JCS(entry without sig). */
36
+ deviceLog: "messaging/1/device-log\n",
37
+ /** Hosted realms (spec §15.4): a keys statement, signed by its device over JCS(statement without sig). */
38
+ deviceKeys: "messaging/1/device-keys\n",
39
+ /** Hosted realms (spec §15.3): a link request, signed by the new device over JCS(request without sig). */
40
+ deviceLink: "messaging/1/device-link\n",
41
+ /** Hosted realms (spec §15.6): a signed tree head, signed by the directory's epoch key over JCS(head without sig). */
42
+ epoch: "messaging/1/epoch\n",
43
+ /** Hosted realms (spec §15.6): an epoch-key rotation, signed by the old key and by the new over JCS(rotation without sigs). */
44
+ dirKey: "messaging/1/dir-key\n",
45
+ /** Conversations (spec §16.4): a conversation event, signed by `by.device` over JCS(event without sig). */
46
+ convEvent: "messaging/1/conv-event\n",
47
+ /** Conversations (spec §16.4): the prefix of a conversation log's genesis hash h(0), over JCS(cid). */
48
+ convGenesis: "messaging/1/conv-genesis\n",
49
+ /** Conversations (spec §16.1): the prefix of the hash that derives a dm's id, over JCS of its two sorted participants. */
50
+ dm: "messaging/1/dm\n",
51
+ /** Conversations (spec §16.1): the prefix of the hash that derives a person's `self` conversation id, over JCS(person). */
52
+ self: "messaging/1/self\n",
53
+ /** Conversations (spec §16.5): HKDF `info` for a sender chain's message key. */
54
+ convMsg: "messaging/1/conv-msg",
55
+ /** Conversations (spec §16.5): HKDF `info` for a sender chain's next chain key. */
56
+ convChain: "messaging/1/conv-chain",
57
+ };
58
+ /** A2A extension and binding URIs owned by Messaging. */
59
+ export const URI = {
60
+ binding: "urn:messaging:binding:relay:v1",
61
+ provenance: "urn:messaging:ext:provenance:v1",
62
+ presence: "urn:messaging:ext:presence:v1",
63
+ };
64
+ export const Base64Url = z.string().regex(/^[A-Za-z0-9_-]*$/, "base64url without padding");
65
+ /** Any 32-byte value in base64url, e.g. a raw public key. */
66
+ export const Key32 = z.string().regex(/^[A-Za-z0-9_-]{43}$/, "32 bytes, base64url without padding");
67
+ /** A machine's identity: its Ed25519 public key (32 bytes, base64url). */
68
+ export const MachineId = Key32.describe("Ed25519 public key of a machine, base64url");
69
+ /** A machine's X25519 public key used to seal envelope bodies addressed to it. */
70
+ export const EncKey = Key32.describe("X25519 public key, base64url");
71
+ /** SHA-256 digest, base64url. */
72
+ export const Hash = Key32.describe("SHA-256 digest, base64url");
73
+ /** A team id is the hash of its JCS-canonical genesis entry. */
74
+ export const TeamId = Key32.describe("Team id: SHA-256 of the canonical genesis entry, base64url");
75
+ /** Crockford base32 ULID, 26 chars. */
76
+ export const Ulid = z.string().regex(/^[0-7][0-9A-HJKMNP-TV-Z]{25}$/, "ULID");
77
+ export const PersonName = z.string().regex(/^[a-z][a-z0-9-]{0,31}$/, "lowercase person name");
78
+ /** A hosted realm's person (spec §15.1): `p_` and 26 lower-case base32 characters, derived from a Jelly account. */
79
+ export const HostedPersonId = z.string().regex(/^p_[a-z2-7]{26}$/, "hosted person id");
80
+ /** A person in either realm: a roster person name, or a hosted `p_…` id. The two forms cannot collide. */
81
+ export const PersonId = z.union([PersonName, HostedPersonId]);
82
+ /** A channel's name (spec §6.8). Unique among the channels one machine holds, not across the team. */
83
+ export const ChannelName = z.string().regex(/^[a-z][a-z0-9-]{0,31}$/, "lowercase channel name");
84
+ /** A chat room (spec §6.8): `dm:<person>` for a direct human message, `channel:<name>` for a channel. */
85
+ export const RoomRef = z.string().regex(/^(?:dm:(?:[a-z][a-z0-9-]{0,31}|p_[a-z2-7]{26})|channel:[a-z][a-z0-9-]{0,31})$/, "dm:<person> or channel:<name>");
86
+ export const SessionName = z.string().regex(/^[a-z0-9][a-z0-9._-]{0,63}$/, "lowercase session name");
87
+ export const MachineLabel = z.string().regex(/^[a-z0-9][a-z0-9-]{0,31}$/, "lowercase machine label");
88
+ export const TeamName = z.string().min(1).max(64);
89
+ /** Client kind, e.g. "opencode", "claude-code", "cli". */
90
+ export const AgentKind = z.string().regex(/^[a-z0-9][a-z0-9._-]{0,63}$/, "lowercase agent kind");
91
+ /**
92
+ * The agent kind of the human `messaging` command line (spec §8.2, §8.3): never kept or expired on
93
+ * disconnect, refused as a task executor, and the only sender of group addresses.
94
+ */
95
+ export const CLI_AGENT = "cli";
96
+ /** Milliseconds since the Unix epoch. */
97
+ export const Millis = z.number().int().nonnegative();
98
+ /**
99
+ * Address grammar (parsed by `parseAddress`); `person` is a `PersonId` (a roster person name or a hosted `p_…`):
100
+ * person/session one session (must be unambiguous across the person's machines)
101
+ * person/session@label one session on a named machine
102
+ * There are no group addresses (spec §3).
103
+ */
104
+ export const Address = z.string().min(1).max(200);
105
+ /**
106
+ * A resolved, fully qualified single-session address: `person/session@label`, where `person` is a `PersonId` (a
107
+ * roster person name, or a hosted `p_…` id). Every daemon-produced address uses it.
108
+ */
109
+ export const SessionAddress = z
110
+ .string()
111
+ .regex(/^(?:[a-z][a-z0-9-]{0,31}|p_[a-z2-7]{26})\/[a-z0-9][a-z0-9._-]{0,63}@[a-z0-9][a-z0-9-]{0,31}$/, "person/session@label");
112
+ export const MemberRole = z.enum(["admin", "member"]);
113
+ export const SessionState = z.enum(["idle", "busy"]);
114
+ /** push: the client may wake an idle session for inbound mail. pull: the agent reads its inbox. */
115
+ export const DeliveryTier = z.enum(["push", "pull"]);
116
+ /** Sender-side view of one envelope's progress. Stages only move forward, except to rejected/expired. */
117
+ export const DeliveryStage = z.enum([
118
+ "accepted", // stored in the local outbox
119
+ "relayed", // the relay stored or forwarded it
120
+ "delivered", // recipient daemon stored it (signed receipt)
121
+ "held", // recipient daemon holds it for its person to answer (signed receipt, spec §6.9)
122
+ "handed_to_agent", // recipient client put it in front of the agent (signed receipt)
123
+ "read", // recipient agent read the full body (signed receipt)
124
+ "replied", // a message with replyTo = this id arrived
125
+ "rejected", // refused by policy, unknown session, etc. (code says why)
126
+ "expired", // TTL passed before delivery
127
+ ]);
128
+ export const LIMITS = {
129
+ /** Max bytes for one relay WebSocket frame. */
130
+ frameBytes: 1_048_576,
131
+ /** Max bytes for one IPC NDJSON line. */
132
+ ipcLineBytes: 2_097_152,
133
+ /** Max UTF-8 bytes of a decrypted envelope body (JCS). */
134
+ plaintextBytes: 262_144,
135
+ /** Max characters in a single text part. */
136
+ textPartChars: 65_536,
137
+ /** Max parts in one message. */
138
+ partsPerMessage: 16,
139
+ /** Default and max envelope TTL, and the max invite lifetime (`expires − ts`). */
140
+ ttlMs: 7 * 24 * 60 * 60 * 1000,
141
+ /** Max nesting of arrays and objects in any JSON value Messaging parses, signs or hashes; the outermost container is depth 1. */
142
+ jsonDepth: 32,
143
+ /** Accepted clock skew for `ts` in the future. */
144
+ clockSkewMs: 5 * 60 * 1000,
145
+ /** Inbound envelopes accepted per sending machine per minute (daemon policy). */
146
+ inboundPerMachinePerMinute: 60,
147
+ /** Agent-to-agent loop guard per (sender session, recipient session) pair. */
148
+ loopGuard: { max: 12, windowMs: 10 * 60 * 1000 },
149
+ /** Max sessions advertised in one presence payload. */
150
+ presenceSessions: 200,
151
+ /**
152
+ * Max UTF-8 bytes of a presence body (JCS). It bounds what each member adds to every welcome's replay
153
+ * and every fan-out, and still holds `presenceSessions` sessions once their optional fields are dropped.
154
+ */
155
+ presenceBytes: 65_536,
156
+ /** Max preview characters in an inbox item. */
157
+ previewChars: 200,
158
+ /** Max UTF-8 bytes of one relay frame before `hello`; a larger one closes the connection. */
159
+ preAuthFrameBytes: 32_768,
160
+ /** Max UTF-8 bytes of an envelope header: JCS of the envelope without `body` (relay nacks `too_large`). */
161
+ headerBytes: 4096,
162
+ /** Max unexpired envelopes the relay queues from one sender machine to one recipient machine (`rate_limited`). */
163
+ queuePerSender: 1000,
164
+ /** Relay budget per machine for every frame after `hello`: a token bucket of this many frames, refilled per minute. */
165
+ relayFramesPerMinute: 600,
166
+ /** Relay budget per machine for every frame after `hello`: a token bucket of this many UTF-8 bytes, refilled per minute. */
167
+ relayBytesPerMinute: 32 * 1_048_576,
168
+ /** Relay limit on presence frames per machine: a token bucket of `presenceBurst`, refilled one per `presenceIntervalMs`. */
169
+ presenceIntervalMs: 2000,
170
+ /** See `presenceIntervalMs`. */
171
+ presenceBurst: 3,
172
+ /** Max entries in one `join` or `roster.sync` reply page. */
173
+ rosterPageEntries: 256,
174
+ /** Max UTF-8 bytes of one roster entry (JCS). */
175
+ rosterEntryBytes: 16_384,
176
+ /** Max grants in a delegation chain (spec §6.7): R → X → Y → Z → W. */
177
+ delegationDepth: 4,
178
+ /** Max scope labels in one delegation grant. */
179
+ delegationScopes: 8,
180
+ /** Max UTF-8 bytes of a whole delegation chain (JCS). */
181
+ delegationBytes: 8192,
182
+ /** Max persons in a channel, its creator included (spec §6.8). */
183
+ channelPersons: 32,
184
+ /** Max UTF-16 code units of one chat line's text (spec §6.8). */
185
+ chatChars: 8000,
186
+ /** Max follow-ups a requester's task record lists (spec §6.3, the newest). */
187
+ taskFollowUps: 20,
188
+ /** Max current devices of one hosted person (spec §15.3); also bounds `dir.erase` (§7, "Directory frames"). */
189
+ devicesPerPerson: 10,
190
+ /** A directory makes a new epoch at most this often while changes wait (spec §15.10). */
191
+ epochMinMs: 5000,
192
+ /** ...and one at least this often without changes, so a fresh STH always exists. */
193
+ epochHeartbeatMs: 10 * 60 * 1000,
194
+ /** How often a directory reads Jelly ID's account-deletion feed (spec §15.10). */
195
+ deletionPollMs: 6 * 60 * 60 * 1000,
196
+ /** After a gap in that feed of over 90 days, the directory erases persons idle for this many days, once. */
197
+ dormantDays: 180,
198
+ /** Distinct persons one person may send message requests to per day, at a directory relay. */
199
+ requestsPerDay: 20,
200
+ /** Max UTF-16 code units of a message request's text (spec §6.9, "Message requests"): the whole of what a stranger may say first. */
201
+ requestChars: 500,
202
+ /** Envelopes per day from one person to another who never sent to them (an unsolicited pair). */
203
+ unsolicitedPerPairPerDay: 20,
204
+ /** Distinct persons one person may send to unsolicited per day. */
205
+ unsolicitedTargetsPerDay: 50,
206
+ /** Max persons in one `dir.lookup`. */
207
+ dirLookupPersons: 64,
208
+ /** Max persons one `dir.resolve` or `dir.search` answers. */
209
+ dirSearchResults: 25,
210
+ /** Max persons one device watches with `dir.watch`, and with `presence.watch`. */
211
+ watchPersons: 500,
212
+ /** Max age of a link request when its device is approved, and of an approval after it (spec §15.3). */
213
+ linkTtlMs: 10 * 60 * 1000,
214
+ /**
215
+ * A directory realm's freshness bounds (spec §15.9): a person's devices are sealed to only when verified at an STH
216
+ * fetched at most `dirFreshFirstMs` ago for a first message or right after a change push, and at most `dirFreshMs`
217
+ * ago otherwise.
218
+ */
219
+ dirFreshFirstMs: 10 * 60 * 1000,
220
+ dirFreshMs: 24 * 60 * 60 * 1000,
221
+ /** How often, at least, a device verifies its own person's log and keys at the directory (spec §15.9). */
222
+ selfMonitorMs: 60 * 60 * 1000,
223
+ /** A Jelly-vouched device attests again at its first chance after this long (spec §15.9). */
224
+ attestAfterMs: 30 * 24 * 60 * 60 * 1000,
225
+ /** Max UTF-8 bytes of one device-log entry (JCS), a Jelly token included (spec §15.3). */
226
+ logEntryBytes: 16_384,
227
+ /** Max UTF-8 bytes of one keys statement (JCS) (spec §15.4). */
228
+ keysStatementBytes: 1024,
229
+ /** Trust a grant gives when the person names no end (spec §6.9). */
230
+ trustDefaultMs: 30 * 24 * 60 * 60 * 1000,
231
+ /** Max `trustedUntil − ts` of a grant (spec §6.9). */
232
+ trustMaxMs: 90 * 24 * 60 * 60 * 1000,
233
+ /** Max UTF-8 bytes of one grant (JCS). */
234
+ grantBytes: 2048,
235
+ /** Max UTF-8 bytes of one contact card (JCS) (spec §6.9, "Contact cards"). */
236
+ cardBytes: 2048,
237
+ /** Max grants one person's device holds (spec §6.9): one per subject. */
238
+ grantsPerPerson: 5000,
239
+ /** Max requests a device holds from one sending person for its person to answer (spec §6.9). */
240
+ heldPerSender: 20,
241
+ /** Max requests a device holds in all (spec §6.9). */
242
+ heldTotal: 200,
243
+ /** Max lines one person's agents send to another person in an hour, summed over the agents (spec §6.9, "Pacing"). */
244
+ a2hPerHour: 30,
245
+ /** Max lines one person's agents send to another person in a day, summed over the agents (spec §6.9, "Pacing"). */
246
+ a2hPerDay: 100,
247
+ /** Conversations (spec §16): max participants (persons and agents) of a channel. */
248
+ convParticipants: 1000,
249
+ /** Max participants (persons and agents) of a group. A group has at least 3. */
250
+ groupParticipants: 50,
251
+ /** Max participants one `add` or `remove` op names. */
252
+ convOpParticipants: 100,
253
+ /** Max UTF-8 bytes of one conversation event (JCS), signature and body included. */
254
+ convEventBytes: 262_144,
255
+ /** Max UTF-8 bytes of one message body's plaintext (JCS) before it is sealed. */
256
+ convPlaintextBytes: 65_536,
257
+ /** Max UTF-16 code units of one conversation line's text. */
258
+ lineChars: 40_000,
259
+ /** Max mentions in one line or edit. */
260
+ mentions: 50,
261
+ /** Max attachments in one line. */
262
+ files: 10,
263
+ /** Max delegation grants one line carries for the agents it mentions (spec §16.3). */
264
+ agentMentions: 5,
265
+ /** Max bytes of one attached file, encrypted. */
266
+ blobBytes: 26_214_400,
267
+ /** Max distinct reaction keys on one event. */
268
+ reactionsPerEvent: 50,
269
+ /** Max pinned events in one conversation. */
270
+ pins: 100,
271
+ /** Retention of a conversation that sets none, in days. */
272
+ retainDaysDefault: 90,
273
+ /** Max `retainDays` of a conversation, and max lookback of a context rule. */
274
+ retainDaysMax: 365,
275
+ /** Max message keys a receiver keeps for one sender chain to open messages that arrive out of order. */
276
+ skippedKeys: 1000,
277
+ /** A sender starts a new chain after this many messages on one chain... */
278
+ chainMessages: 500,
279
+ /** ...or this long after it started the chain, whichever comes first. */
280
+ chainMaxMs: 7 * 24 * 60 * 60 * 1000,
281
+ /** An epoch older than this may be ended by a `rekey` with cause `schedule`. */
282
+ rekeyScheduleMs: 30 * 24 * 60 * 60 * 1000,
283
+ /** Max chain keys in one sealed key share, and in one `keys` sync of the `self` conversation. */
284
+ keyShares: 512,
285
+ /** Max recipient devices one `keys` event seals to; a larger share is split over several events. */
286
+ keySharesPerEvent: 500,
287
+ /** Max agents one event's `wake` hint names. */
288
+ wakeHints: 5,
289
+ /** Max context rules a person holds (spec §16.8). */
290
+ contextRules: 500,
291
+ };
292
+ const LOOPBACK_HOST = /^(?:localhost|127(?:\.\d{1,3}){3}|\[::1\])$/;
293
+ /**
294
+ * True for a relay URL a client may connect to: `wss://`, or `ws://` to a loopback host (`localhost`,
295
+ * 127.0.0.0/8 or `[::1]`, after WHATWG URL parsing). Anything else, including text that is not a URL, is false.
296
+ */
297
+ export function isAllowedRelayUrl(url) {
298
+ let parsed;
299
+ try {
300
+ parsed = new URL(url);
301
+ }
302
+ catch {
303
+ return false;
304
+ }
305
+ if (parsed.protocol === "wss:")
306
+ return true;
307
+ return parsed.protocol === "ws:" && LOOPBACK_HOST.test(parsed.hostname);
308
+ }
309
+ /** A relay connect URL that passes `isAllowedRelayUrl`. */
310
+ export const RelayUrl = z.string().url().refine(isAllowedRelayUrl, { message: "relay must be wss://, or ws:// to a loopback host" });
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Consent (spec §6.9): a person's grants, the policy they hold for one sender person or one channel. One of the
3
+ * person's devices signs each grant; only the person's own devices hold it, and their daemons enforce it on
4
+ * receipt. Agents never sign or change a grant: every method that does is human tier (§8.2).
5
+ */
6
+ import { z } from "../../vendor/zod/index.js";
7
+ import { Base64Url, LIMITS, MachineId, Millis, PersonId, PROTOCOL, Ulid } from "./common.js";
8
+ import { RealmId } from "./realm.js";
9
+ /** H2H lines from the subject: `muted` delivers with no notification and no unread mark; `blocked` refuses every class from them. */
10
+ export const ChatLevel = z.enum(["open", "muted", "blocked"]);
11
+ /** Lines from the subject's agents to the person (A2H). */
12
+ export const AgentMailLevel = z.enum(["open", "blocked"]);
13
+ /** Mail and tasks from the subject or their agents to the person's agents: `request` holds each one for the person to answer. */
14
+ export const AskLevel = z.enum(["open", "request", "no"]);
15
+ /** Whom a grant is about: one person, or every member of one channel (by its id). */
16
+ export const GrantSubject = z.union([z.strictObject({ person: PersonId }), z.strictObject({ channel: Ulid })]);
17
+ /**
18
+ * A grant, signed by `by`, a device of `person`: `sig = Ed25519(by, "messaging/1/grant\n" || JCS(grant without sig))`.
19
+ * Every level is optional: an absent level is the default for the relation (spec §6.9, "Effective policy"), and a
20
+ * grant with none is a clear. `trustedUntil` needs `ask: "open"` and is at most `ts + LIMITS.trustMaxMs`. A channel
21
+ * grant sets only `ask` and `agentMail`. A grant about the person themself sets only `discoverable`.
22
+ * `resignedAt` marks a grant re-signed by another device of the person (spec §6.9, "Signers"); it keeps `id` and
23
+ * `ts`.
24
+ */
25
+ export const ConsentGrant = z
26
+ .object({
27
+ v: z.literal(PROTOCOL),
28
+ realm: RealmId,
29
+ id: Ulid,
30
+ person: PersonId,
31
+ by: MachineId,
32
+ ts: Millis,
33
+ subject: GrantSubject,
34
+ chat: ChatLevel.optional(),
35
+ agentMail: AgentMailLevel.optional(),
36
+ ask: AskLevel.optional(),
37
+ trustedUntil: Millis.optional(),
38
+ discoverable: z.boolean().optional(),
39
+ resignedAt: Millis.optional(),
40
+ sig: Base64Url,
41
+ })
42
+ .superRefine((grant, ctx) => {
43
+ const problem = grantProblem(grant);
44
+ if (problem)
45
+ ctx.addIssue({ code: "custom", message: problem });
46
+ });
47
+ /** Most grants one `self` sync envelope carries (spec §6.9, "Sync"): a snapshot goes in as many envelopes as it needs. */
48
+ export const GRANTS_PER_SYNC = 100;
49
+ /**
50
+ * The one data part of a `self` sync envelope (spec §6.9, "Sync"): grants as signed, kept raw so that members a
51
+ * newer device adds stay covered by their signatures. The receiver verifies each one.
52
+ */
53
+ export const GrantSync = z.strictObject({ grants: z.array(z.record(z.string(), z.unknown())).min(1).max(GRANTS_PER_SYNC) });
54
+ /** The rules of a grant that its schema alone cannot say. */
55
+ export function grantProblem(grant) {
56
+ const own = "person" in grant.subject && grant.subject.person === grant.person;
57
+ if ("channel" in grant.subject && (grant.chat !== undefined || grant.trustedUntil !== undefined || grant.discoverable !== undefined)) {
58
+ return "a channel grant sets only ask and agentMail";
59
+ }
60
+ if (own && (grant.chat !== undefined || grant.agentMail !== undefined || grant.ask !== undefined || grant.trustedUntil !== undefined)) {
61
+ return "a grant about its own person sets only discoverable";
62
+ }
63
+ if (!own && grant.discoverable !== undefined)
64
+ return "discoverable is set only on a grant about its own person";
65
+ if (grant.trustedUntil !== undefined) {
66
+ if (grant.ask !== "open")
67
+ return "trustedUntil needs ask open";
68
+ if (grant.trustedUntil > grant.ts + LIMITS.trustMaxMs)
69
+ return "trustedUntil is past ts + LIMITS.trustMaxMs";
70
+ }
71
+ if (grant.resignedAt !== undefined && grant.resignedAt < grant.ts)
72
+ return "resignedAt is before ts";
73
+ return undefined;
74
+ }
75
+ /**
76
+ * What a person's card tells another person they may send (spec §6.9, "Contact cards"): DM lines (`chat`), lines from
77
+ * their agents (`agentMail`), and asks to the person's agents (`ask`, with `trustedUntil` while they are trusted).
78
+ */
79
+ export const CardCan = z.strictObject({
80
+ chat: z.boolean(),
81
+ agentMail: z.boolean(),
82
+ ask: AskLevel,
83
+ trustedUntil: Millis.optional(),
84
+ });
85
+ /**
86
+ * A contact card: `from`'s word to `to` about what `to` may send them, signed by `by`, a device of `from`:
87
+ * `sig = Ed25519(by, "messaging/1/card\n" || JCS(card without sig))`. `seq` rises with every card `from` sends `to`;
88
+ * the receiver keeps the highest. `grantId` names the grant it reflects. A card is advice: `from`'s own daemon
89
+ * enforces the grants, which may be newer.
90
+ */
91
+ export const ContactCard = z
92
+ .object({
93
+ v: z.literal(PROTOCOL),
94
+ realm: RealmId,
95
+ from: PersonId,
96
+ to: PersonId,
97
+ by: MachineId,
98
+ seq: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
99
+ ts: Millis,
100
+ grantId: Ulid.optional(),
101
+ can: CardCan,
102
+ sig: Base64Url,
103
+ })
104
+ .superRefine((card, ctx) => {
105
+ const problem = cardProblem(card);
106
+ if (problem)
107
+ ctx.addIssue({ code: "custom", message: problem });
108
+ });
109
+ /** The rules of a card that its schema alone cannot say. */
110
+ export function cardProblem(card) {
111
+ if (card.from === card.to)
112
+ return "a card is about another person";
113
+ if (card.can.trustedUntil !== undefined && card.can.ask !== "open")
114
+ return "trustedUntil needs ask open";
115
+ return undefined;
116
+ }
117
+ /** The one data part of a `card` message (spec §5, "Meaning"): the card as signed, kept raw; the receiver verifies it. */
118
+ export const CardData = z.strictObject({ card: z.record(z.string(), z.unknown()) });
119
+ /** The one data part of a card request (`what: "get"`). */
120
+ export const CardGetData = z.strictObject({ get: z.literal(true) });