@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,6 @@
1
+ /** RFC 4648 §5 base64url without padding. `decode` rejects padding, foreign characters and non-canonical trailing bits. */
2
+ export declare const b64u: {
3
+ encode(bytes: Uint8Array): string;
4
+ decode(text: string): Uint8Array;
5
+ };
6
+ export declare function utf8(text: string): Uint8Array;
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ declare const TeamCard: z.ZodObject<{
3
+ v: z.ZodLiteral<"messaging/1">;
4
+ relay: z.ZodString;
5
+ team: z.ZodString;
6
+ name: z.ZodString;
7
+ }, z.core.$strict>;
8
+ export type TeamCard = z.infer<typeof TeamCard>;
9
+ declare const AdmitCard: z.ZodObject<{
10
+ v: z.ZodLiteral<"messaging/1">;
11
+ machine: z.ZodString;
12
+ enc: z.ZodString;
13
+ person: z.ZodString;
14
+ label: z.ZodString;
15
+ }, z.core.$strict>;
16
+ export type AdmitCard = z.infer<typeof AdmitCard>;
17
+ export declare function encodeTeamCard(card: TeamCard): string;
18
+ export declare function decodeTeamCard(text: string): TeamCard;
19
+ export declare function encodeAdmitCard(card: AdmitCard): string;
20
+ export declare function decodeAdmitCard(text: string): AdmitCard;
21
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { z } from "zod";
2
+ import { type ErrorCode, MessagingError } from "./schema/errors.js";
3
+ /** Parses with a schema, throwing a MessagingError that names the failing path but never echoes the value. */
4
+ export declare function parseWith<S extends z.ZodType>(schema: S, value: unknown, what: string, code?: ErrorCode): z.output<S>;
5
+ /**
6
+ * What a public entry point throws for `error`: a MessagingError unchanged; anything else (a RangeError or a
7
+ * TypeError caused by a hostile value) as `invalid_request`. The original is not chained as `cause`,
8
+ * because its message can quote the input.
9
+ */
10
+ export declare function asMessagingError(error: unknown, what: string): MessagingError;
@@ -0,0 +1,132 @@
1
+ import type { Identity } from "./identity.js";
2
+ import { type MachineId, type PersonId, type Ulid } from "./schema/common.js";
3
+ import { type AgentMailLevel, type AskLevel, type ChatLevel, ConsentGrant, type GrantLevels, type GrantSubject } from "./schema/consent.js";
4
+ import type { RealmId } from "./schema/realm.js";
5
+ export interface ConsentGrantArgs {
6
+ realm: RealmId;
7
+ /** The person whose policy this is: the signing device's person. */
8
+ person: PersonId;
9
+ subject: GrantSubject;
10
+ levels: GrantLevels;
11
+ now: number;
12
+ id?: Ulid;
13
+ }
14
+ /** Signs a new grant with `identity`, a device of `args.person`. Throws `invalid_request` for a grant that breaks a rule. */
15
+ export declare function signConsentGrant(identity: Identity, args: ConsentGrantArgs): ConsentGrant;
16
+ /**
17
+ * Checks a grant received from another device: the schema and its rules, the size, the realm, the person when
18
+ * given, and the signature by `by` over the raw value (so members a newer device adds stay covered). Whether `by`
19
+ * is a current device of `person` is the caller's: that changes over time (spec §6.9, "Signers"). Throws only
20
+ * MessagingError: `invalid_request`, `too_large` or `bad_signature`.
21
+ */
22
+ export declare function verifyConsentGrant(raw: unknown, ctx: {
23
+ realm: RealmId;
24
+ person?: PersonId;
25
+ }): ConsentGrant;
26
+ /** The key one grant is stored under: its subject. One grant per subject. */
27
+ export declare function grantSubjectKey(subject: GrantSubject): string;
28
+ /**
29
+ * Of two copies of the grant for one subject, the one that counts (spec §6.9, "Merging"): the newer by `ts`, then
30
+ * by `id`. Copies that tie on both are one grant signed twice: a copy whose signer is current beats one whose
31
+ * signer is not; between two current signers (or two removed ones), the signer that sorts first wins, then the
32
+ * signature. The choice is commutative and idempotent, so devices that see the same copies in any order agree.
33
+ */
34
+ export declare function preferGrant(a: ConsentGrant, b: ConsentGrant, current: (device: MachineId) => boolean): ConsentGrant;
35
+ /** Levels that narrow reach: blocks never lapse (spec §6.9, "Signers"). */
36
+ export declare function restrictingLevels(grant: GrantLevels): GrantLevels;
37
+ /** Levels that widen reach: they lapse with their signer, into the person's review list. */
38
+ export declare function wideningLevels(grant: GrantLevels): GrantLevels;
39
+ /**
40
+ * Re-signs a grant whose signer is no longer current with `identity`, a current device of the same person
41
+ * (spec §6.9, "Signers"). `keep: "all"` (a replacement) keeps every level; `keep: "restricting"` (any other
42
+ * removal) keeps only the restricting ones, and returns undefined when there are none: the grant lapses whole.
43
+ * The copy keeps `id` and `ts`, so it never overrides a newer change, and records `resignedAt`.
44
+ */
45
+ export declare function resignGrant(identity: Identity, grant: ConsentGrant, opts: {
46
+ now: number;
47
+ keep: "all" | "restricting";
48
+ }): ConsentGrant | undefined;
49
+ export declare function levelsOf(grant: GrantLevels): GrantLevels;
50
+ /** How the sending person relates to the receiving person (spec §6.9, "Relations"). A roster realm has only `self` and `org`. */
51
+ export type Relation = "self" | "org" | "contact" | "stranger";
52
+ /** How an item delivered to an agent may run (spec §6.9): the person's own, a trusted sender's, or a guarded peer turn. */
53
+ export type ConsentClass = "self" | "guarded" | "trusted";
54
+ /** The levels that apply to one sender, and where each came from. */
55
+ export interface EffectivePolicy {
56
+ chat: ChatLevel | "request_required";
57
+ agentMail: AgentMailLevel;
58
+ ask: AskLevel;
59
+ /** Set while the person grant trusts the sender. */
60
+ trustedUntil?: number;
61
+ /** Which levels a grant set, rather than the relation's default. */
62
+ granted: {
63
+ chat: boolean;
64
+ agentMail: boolean;
65
+ ask: boolean;
66
+ };
67
+ }
68
+ /**
69
+ * Spec §6.9, "Effective policy": each level is the person grant's when it sets one; otherwise, for `ask` and
70
+ * `agentMail`, the most permissive among the grants of channels the sender is in; otherwise the relation's
71
+ * default. An expired `trustedUntil` reads as absent. The caller passes only grants whose signer is current.
72
+ */
73
+ export declare function effectivePolicy(relation: Exclude<Relation, "self">, person: GrantLevels | undefined, channels: readonly GrantLevels[], now: number): EffectivePolicy;
74
+ /**
75
+ * What arrived, classified by the receiver (spec §6.9, "Enforcement"):
76
+ * - `answer`: a receipt, a task update or cancel, or a message the counterpart binding ties to this person's own
77
+ * traffic (a reply or a follow-up); never gated;
78
+ * - `line`: a DM line or channel post, from the person (`agent: false`) or one of their agents (`agent: true`);
79
+ * - `op`: a channel change;
80
+ * - `ask`: mail or a task request to one of the receiver's agents, with the persons of its delegation chain (the
81
+ * sender's alone for mail);
82
+ * - `request`: a message request (class `request`), a person's first line to a person of another org.
83
+ */
84
+ export type Inbound = {
85
+ kind: "answer";
86
+ } | {
87
+ kind: "line";
88
+ agent: boolean;
89
+ } | {
90
+ kind: "op";
91
+ } | {
92
+ kind: "ask";
93
+ chain: readonly PersonId[];
94
+ } | {
95
+ kind: "request";
96
+ };
97
+ export type ConsentDecision = {
98
+ action: "deliver";
99
+ consent: ConsentClass;
100
+ silent?: true;
101
+ } | {
102
+ action: "hold";
103
+ } | {
104
+ action: "refuse";
105
+ code: "refused" | "request_required";
106
+ };
107
+ export interface DecideArgs {
108
+ /** The receiving person. */
109
+ self: PersonId;
110
+ /** The sending person. */
111
+ sender: PersonId;
112
+ relation: Relation;
113
+ /** The person grant for the sender, when its signer is current. */
114
+ grant?: GrantLevels;
115
+ /** Grants of channels the sender is in, in the receiver's own view, each with a current signer. */
116
+ channels: readonly GrantLevels[];
117
+ inbound: Inbound;
118
+ now: number;
119
+ }
120
+ /**
121
+ * Spec §6.9, "Enforcement": step 10 of the receiver order (§5), before the inbound policy of §8.3.
122
+ * - The person's own traffic is delivered as `self`.
123
+ * - Answers to the person's own traffic are delivered whatever the grants, so a change never strands a task.
124
+ * - A `blocked` chat level refuses every other class from the sender.
125
+ * - A `stranger` reaches the person only through a level a grant opened; otherwise `request_required`.
126
+ * - Lines follow `chat` (person) or `agentMail` (agent); `muted` delivers silently.
127
+ * - Asks follow `ask`: `open` delivers guarded, or trusted while the person grant trusts the sender and every person
128
+ * in the delegation chain is the sender or the receiver; `request` holds; `no` refuses, `request_required` when
129
+ * it is the default of a `contact` or a `stranger`.
130
+ * - A message request from a `stranger` is held for the person to accept; from anyone else it is a DM line.
131
+ */
132
+ export declare function decide(args: DecideArgs): ConsentDecision;
@@ -0,0 +1,34 @@
1
+ import { type Relation } from "./consent.js";
2
+ import type { Identity } from "./identity.js";
3
+ import { type PersonId, type Ulid } from "./schema/common.js";
4
+ import { type CardCan, ContactCard, type GrantLevels } from "./schema/consent.js";
5
+ import type { RealmId } from "./schema/realm.js";
6
+ export interface ContactCardArgs {
7
+ realm: RealmId;
8
+ /** The person the card speaks for: the signing device's person. */
9
+ from: PersonId;
10
+ /** The person it is for. */
11
+ to: PersonId;
12
+ seq: number;
13
+ now: number;
14
+ grantId?: Ulid;
15
+ can: CardCan;
16
+ }
17
+ /** Signs a card with `identity`, a device of `args.from`. Throws `invalid_request` or `too_large`. */
18
+ export declare function signContactCard(identity: Identity, args: ContactCardArgs): ContactCard;
19
+ /**
20
+ * Checks a card received from another person: the schema and its rules, the size, the realm, its two persons, and
21
+ * the signature by `by` over the raw value. Whether `by` is a current device of `from` is the caller's: a card
22
+ * whose signer was removed counts as absent. Throws only MessagingError: `invalid_request`, `too_large` or
23
+ * `bad_signature`.
24
+ */
25
+ export declare function verifyContactCard(raw: unknown, ctx: {
26
+ realm: RealmId;
27
+ from: PersonId;
28
+ to: PersonId;
29
+ }): ContactCard;
30
+ /**
31
+ * What a card says for a sender of `relation` with the person grant `grant` (spec §6.9, "Contact cards"): the
32
+ * person grant over the relation's defaults. Channel grants are not on a card: the sender knows its own channels.
33
+ */
34
+ export declare function cardCan(relation: Exclude<Relation, "self">, grant: GrantLevels | undefined, now: number): CardCan;
@@ -0,0 +1,56 @@
1
+ import type { PersonId, SessionName } from "../schema/common.js";
2
+ import { type AgentContext, type ContextAccess, type ContextKind, type ContextRule, type ConvId, type ConvKind, type Visibility } from "../schema/conversation.js";
3
+ /** The defaults that apply where a person has no rule (decided 2026-11-08). `lookbackDays` absent: the retention. */
4
+ export declare const CONTEXT_DEFAULTS: Readonly<Record<ContextKind, {
5
+ access: ContextAccess;
6
+ lookbackDays?: number;
7
+ }>>;
8
+ /** The facts about a conversation that resolution reads. `persons` are its participant persons at the read. */
9
+ export interface ContextConv {
10
+ cid: ConvId;
11
+ kind: ConvKind;
12
+ visibility?: Visibility;
13
+ persons: readonly PersonId[];
14
+ retainDays: number;
15
+ agentContext: AgentContext;
16
+ }
17
+ /**
18
+ * The scope a conversation falls in for `person`: `own` when its participant persons are `person` alone, else its
19
+ * kind (a channel by its visibility). A `self` conversation has none: no agent mines it.
20
+ */
21
+ export declare function contextKindOf(person: PersonId, conv: Pick<ContextConv, "kind" | "visibility" | "persons">): ContextKind | undefined;
22
+ /**
23
+ * The person's rule for (agent, conversation), most specific first: a `cid` scope over a `kind` scope, then a named
24
+ * agent over `*`. Undefined when no rule matches; the defaults then apply.
25
+ */
26
+ export declare function matchContextRule(rules: readonly ContextRule[], agent: SessionName, cid: ConvId, kind: ContextKind): ContextRule | undefined;
27
+ /** The outcome of a context read: served, held for the person (`ask`), or refused. */
28
+ export type ContextDecision = {
29
+ access: "allow" | "ask";
30
+ lookbackDays: number;
31
+ source: "rule" | "default";
32
+ } | {
33
+ access: "forbidden";
34
+ source: "policy" | "rule" | "self";
35
+ };
36
+ /**
37
+ * The effective rule for agent `agent` of `person` reading `conv` as context (not by its seat):
38
+ * - the conversation's policy `seats` or `none` forbids it, whatever the person's rule says;
39
+ * - else the person's rule, or the default: `off` forbids, `ask` holds, `allow` serves;
40
+ * - the lookback is the smallest of the rule's (or the default's) `lookbackDays`, the conversation's `retainDays`,
41
+ * and the person's local retention for it.
42
+ * Throws `invalid_request` for a rule set that fails `ContextRules`.
43
+ */
44
+ export declare function resolveContext(args: {
45
+ person: PersonId;
46
+ agent: SessionName;
47
+ conv: ContextConv;
48
+ rules: readonly ContextRule[];
49
+ localRetentionDays?: number;
50
+ }): ContextDecision;
51
+ /**
52
+ * What a seated agent reads by its seat (spec §16.8): everything from its seat's `seq` on, unless the policy is
53
+ * `none`, when it reads only the events addressed to it and the threads they are in. The person's rules do not
54
+ * apply to seat reads.
55
+ */
56
+ export declare function seatReads(agentContext: AgentContext): "conversation" | "items";
@@ -0,0 +1,36 @@
1
+ import type { Identity } from "../identity.js";
2
+ import { type Hash } from "../schema/common.js";
3
+ import { type ConvEvent, type ConvEventHeader, type ConvId, type UnsignedConvEvent } from "../schema/conversation.js";
4
+ /** h(0) of `cid`'s log: SHA-256(DOMAIN.convGenesis ‖ JCS(cid)), base64url. */
5
+ export declare function convGenesisHash(cid: ConvId): Hash;
6
+ /** SHA-256(JCS(event)), the raw digest, as the chain links it. Throws `invalid_request` for non-I-JSON. */
7
+ export declare function convEventDigest(event: unknown): Uint8Array;
8
+ /** h(seq) = SHA-256(h(seq − 1) ‖ SHA-256(JCS(event))), over the raw 32-byte digests, base64url. */
9
+ export declare function convEntryHash(prev: Hash, event: unknown): Hash;
10
+ /** `convEntryHash` from the event's digest: what a member checks for an entry whose content has expired. */
11
+ export declare function convLinkHash(prev: Hash, digest: Uint8Array): Hash;
12
+ /** The header of an event: everything but `body` and `sig`. JCS of it is the AAD of a sealed body. */
13
+ export declare function convEventHeader(event: ConvEvent | Omit<ConvEvent, "sig"> | ConvEventHeader): ConvEventHeader;
14
+ /**
15
+ * Checks that `raw` is I-JSON within `LIMITS.jsonDepth` and at most `LIMITS.convEventBytes` (`too_large`), that it
16
+ * matches `ConvEvent`, and that `by.device` is a usable Ed25519 key. Returns a frozen JSON copy of the raw value, so
17
+ * the signature and the hash cover exactly what was received. The signature is not checked.
18
+ */
19
+ export declare function admitConvEvent(raw: unknown): ConvEvent;
20
+ /**
21
+ * Signs an event (spec §16.4): `sig = Ed25519(by.device, DOMAIN.convEvent ‖ JCS(event without sig))`. `by.device`
22
+ * must be `identity`'s machine. Refuses an event that fails the schema (`invalid_request`) or is over
23
+ * `LIMITS.convEventBytes` once signed (`too_large`). Authority is checked when the event is applied.
24
+ */
25
+ export declare function signConvEvent<E extends UnsignedConvEvent>(identity: Identity, unsigned: E): E & {
26
+ sig: string;
27
+ };
28
+ /** True only for a valid signature by `event.by.device` over the event without `sig`. Never throws. */
29
+ export declare function convEventSigned(event: ConvEvent): boolean;
30
+ /**
31
+ * Admits `raw` (`admitConvEvent`) and checks its signature over the raw value (`bad_signature`). Membership and
32
+ * authority are `ConvLog.apply`'s. Throws only MessagingError.
33
+ */
34
+ export declare function verifyConvEvent(raw: unknown): ConvEvent;
35
+ /** Freezes a JSON value and everything in it, iteratively. */
36
+ export declare function deepFreeze<T>(value: T): T;
@@ -0,0 +1,18 @@
1
+ import { PersonId } from "../schema/common.js";
2
+ import { type ConvId, ParticipantId } from "../schema/conversation.js";
3
+ /**
4
+ * The id of the dm between `a` and `b`: `"d_" + base32lower(SHA-256(DOMAIN.dm ‖ JCS([a, b] sorted)))[0..26]`. Both
5
+ * ends derive the same id, so a dm has no create race. `a` may equal `b`: a person's note to themselves.
6
+ */
7
+ export declare function dmConvId(a: ParticipantId, b: ParticipantId): ConvId;
8
+ /** The id of `person`'s own `self` conversation: `"s_" + base32lower(SHA-256(DOMAIN.self ‖ JCS(person)))[0..26]`. */
9
+ export declare function selfConvId(person: PersonId): ConvId;
10
+ /** The person a participant is, or belongs to. */
11
+ export declare function participantPerson(p: ParticipantId): PersonId;
12
+ /** The agent's session name, for an agent participant. */
13
+ export declare function participantAgent(p: ParticipantId): string | undefined;
14
+ /** The participant an event's `by` names: `person`, or `person/agent`. */
15
+ export declare function participantOf(by: {
16
+ person: PersonId;
17
+ agent?: string | undefined;
18
+ }): ParticipantId;
@@ -0,0 +1,16 @@
1
+ import type { MachineId, PersonId } from "../schema/common.js";
2
+ import { type LinkRecord, type MsgBody, type ReaderId } from "../schema/conversation.js";
3
+ /** The links in force: for each link id the record written last (records are in `seq` order), unless revoked. */
4
+ export declare function currentLinks(records: readonly LinkRecord[]): LinkRecord[];
5
+ /**
6
+ * Checks a line's `via` against the author's links, as the author's own devices can (other members cannot see the
7
+ * person's links): only a person writes from a linked channel, never an agent, and only through a link of that
8
+ * channel that the authoring device hosts and that is in force. Throws `forbidden`.
9
+ */
10
+ export declare function checkVia(body: MsgBody, by: {
11
+ person: PersonId;
12
+ device: MachineId;
13
+ agent?: string;
14
+ }, links: readonly LinkRecord[]): void;
15
+ /** The reader id of a link's channel provider, for the audience guard: `ext:<channel>:<link id>`. */
16
+ export declare function linkReader(link: Pick<LinkRecord, "channel" | "id">): ReaderId;
@@ -0,0 +1,142 @@
1
+ import type { AnchorRelation } from "../realm.js";
2
+ import { type Hash, type MachineId, type PersonId } from "../schema/common.js";
3
+ import { type AgentContext, type BridgePolicy, type ConvEvent, type ConvHead, type ConvId, type ConvKind, type ConvLogEntry, type ConvRole, type HistoryPolicy, type MsgKind, type ParticipantId, type Permit, type RekeyCause, type RespondTo, type Visibility } from "../schema/conversation.js";
4
+ import type { RealmId } from "../schema/realm.js";
5
+ /** A participant at one position. */
6
+ export interface ConvParticipant {
7
+ p: ParticipantId;
8
+ person: PersonId;
9
+ /** The agent's session name, for an agent participant. */
10
+ agent?: string;
11
+ role: ConvRole;
12
+ /** `invited` until the person accepts, or until the agent's person seats it. */
13
+ state: "member" | "invited";
14
+ device?: MachineId;
15
+ respondTo?: RespondTo;
16
+ /** The seq at which it became a participant. */
17
+ since: number;
18
+ }
19
+ /** Everything the log decides at one position. Frozen. */
20
+ export interface ConvSnapshot {
21
+ cid: ConvId;
22
+ kind: ConvKind;
23
+ visibility?: Visibility;
24
+ history: HistoryPolicy;
25
+ retainDays: number;
26
+ org?: string;
27
+ post: Permit;
28
+ invite: Permit;
29
+ pins: Permit;
30
+ archived: boolean;
31
+ epoch: number;
32
+ /** The seq and `ts` of the op that started the epoch. */
33
+ epochSince: number;
34
+ epochTs: number;
35
+ /** Causes that need a `rekey` before the next message (spec §16.7). Sorted. */
36
+ rekeyDue: RekeyCause[];
37
+ /** Sorted by `p`. */
38
+ participants: ConvParticipant[];
39
+ /** The effective policy. In a channel the owners' and admins'; in a dm or a group the strictest vote. */
40
+ agentContext: AgentContext;
41
+ /**
42
+ * Who may mirror the conversation to a linked channel (reserved: no daemon acts on it yet). In a channel the
43
+ * owners' and admins'; in a dm or a group the strictest vote, where a person who has not voted counts as `none`.
44
+ */
45
+ bridges: BridgePolicy;
46
+ /** dm and group: each participant person's votes, sorted by person. */
47
+ votes: ConvVote[];
48
+ /** The seq of the entry that last changed any of the above. */
49
+ changed: number;
50
+ }
51
+ /** One participant person's policy votes in a dm or group. */
52
+ export interface ConvVote {
53
+ person: PersonId;
54
+ agentContext?: AgentContext;
55
+ bridges?: BridgePolicy;
56
+ }
57
+ /** What a member knows of one event, by id. */
58
+ export interface ConvMessage {
59
+ id: string;
60
+ seq: number;
61
+ class: ConvEvent["class"];
62
+ author: ParticipantId;
63
+ /** Known when the body was opened. */
64
+ t?: MsgKind;
65
+ deleted: boolean;
66
+ pinned: boolean;
67
+ reactions: {
68
+ key: string;
69
+ by: ParticipantId[];
70
+ }[];
71
+ /** For a task request: its executor. */
72
+ taskTo?: ParticipantId;
73
+ /** For a task request: true. */
74
+ taskRoot?: boolean;
75
+ }
76
+ /** Checks only a live append can make: they depend on the realm now, not on the log. */
77
+ export interface ConvLiveChecks {
78
+ /** Wall-clock time; the event's `ts` must be within `skewMs` (default `LIMITS.clockSkewMs`) of it (`expired`). */
79
+ now?: number;
80
+ skewMs?: number;
81
+ /** True when `device` is a current device of `person` in the realm (`unknown_device` otherwise). */
82
+ isDevice?: (person: PersonId, device: MachineId) => boolean;
83
+ /** The org of `person`, for `join`, and for an add of a person who is not a guest (`forbidden`). */
84
+ orgOf?: (person: PersonId) => string | undefined;
85
+ }
86
+ export interface ConvApplyOptions {
87
+ /** The opened body of a `msg` entry; the message rules run only with it. */
88
+ body?: unknown;
89
+ live?: ConvLiveChecks;
90
+ }
91
+ /** An entry whose content the relay expired: its seq, its prev and the digest SHA-256(JCS(event)). */
92
+ export interface ConvExpiredEntry {
93
+ seq: number;
94
+ prev: Hash;
95
+ digest: Hash;
96
+ }
97
+ /**
98
+ * A verified conversation log. Every method throws only MessagingError. Entries are kept as frozen copies of the
99
+ * received JSON, so hashes cover exactly what was received.
100
+ */
101
+ export declare class ConvLog {
102
+ #private;
103
+ readonly cid: ConvId;
104
+ readonly realm: RealmId;
105
+ private constructor();
106
+ /** An empty log of `cid` in `realm`: its head is {0, h(0)}. */
107
+ static open(cid: ConvId, realm: RealmId): ConvLog;
108
+ /** Replays `entries` (each with the opened body of a `msg`, when the caller has it). Throws the first failure. */
109
+ static fromEntries(cid: ConvId, realm: RealmId, entries: {
110
+ entry: unknown;
111
+ body?: unknown;
112
+ }[]): ConvLog;
113
+ head(): ConvHead;
114
+ /** The last op's seq and hash, or {0, h(0)}: what an author puts in `opHead`. */
115
+ opHead(): ConvHead;
116
+ /** h(seq), for 0 ≤ seq ≤ head. */
117
+ hashAt(seq: number): Hash | undefined;
118
+ entries(): (ConvLogEntry | ConvExpiredEntry)[];
119
+ /** The state at the head; undefined before `create`. */
120
+ state(): ConvSnapshot | undefined;
121
+ /** The state after the entry at `seq`, as a log holding only entries 1..seq has it. */
122
+ at(seq: number): ConvSnapshot | undefined;
123
+ /** What a member knows of the event `id`. */
124
+ message(id: string): ConvMessage | undefined;
125
+ /**
126
+ * Gossip (spec §16.4): `ahead` past the head (fetch up to it first); `consistent` when h(seq) is ours; `diverged`
127
+ * when this log has another hash at that seq, a fork whose evidence is the signed event that named it.
128
+ */
129
+ relate(head: ConvHead): AnchorRelation;
130
+ /**
131
+ * Checks one entry and appends it, in order: I-JSON and size (`invalid_request`, `too_large`); schema, realm and
132
+ * cid (`invalid_request`); the chain, seq = head + 1 and prev = h(head) (`conv_conflict`); the signature
133
+ * (`bad_signature`); the live checks given (`expired`, `unknown_device`); a reused id (`duplicate`); then the
134
+ * authority rules of spec §16.7. Returns the entry's h(seq).
135
+ */
136
+ apply(raw: unknown, options?: ConvApplyOptions): Hash;
137
+ /**
138
+ * Appends an entry whose content the relay expired (spec §16.4, "Retention"), by its digest: the chain stays
139
+ * verifiable and the state does not change. An op is never expired: a later op head that names this seq fails.
140
+ */
141
+ applyExpired(raw: ConvExpiredEntry): Hash;
142
+ }
@@ -0,0 +1,95 @@
1
+ import { z } from "zod";
2
+ import { type MachineId } from "../schema/common.js";
3
+ import { type KeyShare } from "../schema/conversation.js";
4
+ /** One ratchet step: the message key for this index and the chain key for the next. */
5
+ export declare function chainStep(ck: Uint8Array): {
6
+ mk: Uint8Array;
7
+ next: Uint8Array;
8
+ };
9
+ /** A sender chain as a device stores it. */
10
+ export declare const SenderChainState: z.ZodObject<{
11
+ epoch: z.ZodNumber;
12
+ device: z.ZodString;
13
+ start: z.ZodNumber;
14
+ origin: z.ZodString;
15
+ idx: z.ZodNumber;
16
+ ck: z.ZodString;
17
+ startedAt: z.ZodNumber;
18
+ }, z.core.$strict>;
19
+ export type SenderChainState = z.infer<typeof SenderChainState>;
20
+ /** The sending side of one chain. `next()` hands out each message key once. */
21
+ export declare class SenderChain {
22
+ #private;
23
+ readonly epoch: number;
24
+ readonly device: MachineId;
25
+ /** The index this chain starts at. */
26
+ readonly start: number;
27
+ readonly startedAt: number;
28
+ private constructor();
29
+ /** A new chain at `idx` (default 0) of `epoch`, from a fresh random chain key. */
30
+ static start(args: {
31
+ epoch: number;
32
+ device: MachineId;
33
+ idx?: number;
34
+ now: number;
35
+ }): SenderChain;
36
+ /** `start` with a caller-chosen chain key: for test vectors, and for a device restoring its own state. */
37
+ static startWith(args: {
38
+ epoch: number;
39
+ device: MachineId;
40
+ idx?: number;
41
+ now: number;
42
+ }, ck: Uint8Array): SenderChain;
43
+ static restore(raw: unknown): SenderChain;
44
+ export(): SenderChainState;
45
+ /** The index the next message gets. */
46
+ get idx(): number;
47
+ /** The share that lets a receiver open every message of this chain: its chain key at its start. */
48
+ share(): KeyShare;
49
+ /** The key for the next message, and its index. The chain moves past it. */
50
+ next(): {
51
+ idx: number;
52
+ mk: Uint8Array;
53
+ };
54
+ /** True once the chain has sent `LIMITS.chainMessages` messages or is `LIMITS.chainMaxMs` old: rotate before the next. */
55
+ due(now: number): boolean;
56
+ /** A fresh chain in the same epoch, starting at this chain's next index. Share it before sending on it. */
57
+ rotate(now: number): SenderChain;
58
+ /** `rotate` with a caller-chosen chain key, for test vectors. */
59
+ rotateWith(now: number, ck: Uint8Array): SenderChain;
60
+ }
61
+ export declare const ReceiverChainsState: z.ZodObject<{
62
+ chains: z.ZodArray<z.ZodObject<{
63
+ epoch: z.ZodNumber;
64
+ device: z.ZodString;
65
+ start: z.ZodNumber;
66
+ origin: z.ZodString;
67
+ pos: z.ZodNumber;
68
+ ck: z.ZodString;
69
+ skipped: z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodString], null>>;
70
+ }, z.core.$strict>>;
71
+ }, z.core.$strict>;
72
+ export type ReceiverChainsState = z.infer<typeof ReceiverChainsState>;
73
+ /**
74
+ * The receiving side: every chain this device holds for one conversation, by (epoch, sender device). It derives
75
+ * forward only and hands out each message key once; a message that arrives out of order uses a key kept from an
76
+ * earlier derivation, at most `LIMITS.skippedKeys` per sender and epoch. The chain keys at each share's index are
77
+ * kept, so the device can share them with a late joiner (history `shared`).
78
+ */
79
+ export declare class ReceiverChains {
80
+ #private;
81
+ static restore(raw: unknown): ReceiverChains;
82
+ export(): ReceiverChainsState;
83
+ /**
84
+ * Adds a share. The first share at a given (epoch, device, idx) wins: a later one with another key changes
85
+ * nothing, and `add` returns false. Returns true when the share was new.
86
+ */
87
+ add(raw: KeyShare): boolean;
88
+ /** Every share this device holds, from each chain's start: what it shares with a late joiner. */
89
+ shares(): KeyShare[];
90
+ /**
91
+ * The message key for (`epoch`, `device`, `idx`), used once. `not_found` when no share covers it, or its key was
92
+ * already used or dropped; `too_large` when it is more than `LIMITS.skippedKeys` past the chain's position.
93
+ */
94
+ messageKey(epoch: number, device: MachineId, idx: number): Uint8Array;
95
+ }
@@ -0,0 +1,47 @@
1
+ import type { Identity } from "../identity.js";
2
+ import { type EncKey, type MachineId, type PersonId } from "../schema/common.js";
3
+ import { type ConvKeysEvent, ConvMeta, type ConvMsgEvent, type ConvOpEvent, type KeyShare, MsgBody } from "../schema/conversation.js";
4
+ /** A message event before its body: the header its author signs, with `class: "msg"`. */
5
+ export type UnsealedMsg = Omit<ConvMsgEvent, "body" | "sig">;
6
+ /** A keys event before its body. */
7
+ export type UnsealedKeys = Omit<ConvKeysEvent, "body" | "sig">;
8
+ /** A recipient device of a key share: its person, its machine and its X25519 key, as the realm verified them. */
9
+ export interface ShareRecipient {
10
+ person: PersonId;
11
+ device: MachineId;
12
+ enc: EncKey;
13
+ }
14
+ /** Fixed randomness of one sealed share, for test vectors: the ephemeral X25519 private key and the nonce. */
15
+ export interface ShareRandomness {
16
+ ephemeral: Uint8Array;
17
+ nonce: Uint8Array;
18
+ }
19
+ /** Seals `body` under `mk` as the body of `unsealed` and signs the event. Throws only MessagingError. */
20
+ export declare function sealConvMsg(identity: Identity, unsealed: UnsealedMsg, body: MsgBody, mk: Uint8Array): ConvMsgEvent;
21
+ /** `sealConvMsg` with a caller-chosen nonce: for test vectors only (`@messaging/core/testing`). */
22
+ export declare function sealConvMsgWith(identity: Identity, unsealed: UnsealedMsg, body: MsgBody, mk: Uint8Array, nonce: Uint8Array): ConvMsgEvent;
23
+ /**
24
+ * Opens a `msg` event's body with its message key: `bad_signature` when it fails to open, `too_large` over
25
+ * `LIMITS.convPlaintextBytes`, `invalid_request` when the plaintext is not a `MsgBody` (parsed with `parseWire`).
26
+ * The caller has verified the event's signature.
27
+ */
28
+ export declare function openConvMsg(event: ConvMsgEvent, mk: Uint8Array): MsgBody;
29
+ /** `create.sealedMeta`: JCS(meta) sealed under the creator's epoch-0 key 0, with the create event's header as AAD. */
30
+ export declare function sealConvMeta(header: Omit<ConvOpEvent, "body" | "sig">, meta: ConvMeta, mk0: Uint8Array): string;
31
+ /** `sealConvMeta` with a caller-chosen nonce: for test vectors only. */
32
+ export declare function sealConvMetaWith(header: Omit<ConvOpEvent, "body" | "sig">, meta: ConvMeta, mk0: Uint8Array, nonce: Uint8Array): string;
33
+ /** Opens a `create` event's `sealedMeta`. Errors as for `openConvMsg`; `not_found` when it has none. */
34
+ export declare function openConvMeta(event: ConvOpEvent, mk0: Uint8Array): ConvMeta;
35
+ /**
36
+ * Seals `shares` to each recipient device as the body of `unsealed`, and signs the event. One sealed share per
37
+ * device; at most `LIMITS.keySharesPerEvent` devices and `LIMITS.keyShares` chain keys. Throws only MessagingError.
38
+ */
39
+ export declare function sealKeyShares(identity: Identity, unsealed: UnsealedKeys, recipients: ShareRecipient[], shares: KeyShare[]): ConvKeysEvent;
40
+ /** `sealKeyShares` with fixed randomness per recipient, in order: for test vectors only. */
41
+ export declare function sealKeySharesWith(identity: Identity, unsealed: UnsealedKeys, recipients: ShareRecipient[], shares: KeyShare[], randomness: ShareRandomness[]): ConvKeysEvent;
42
+ /**
43
+ * Opens the share sealed to `identity`'s device in a `keys` event: `not_found` when there is none, `bad_signature`
44
+ * when it fails to open, `invalid_request` when the plaintext is not a share payload. The caller has verified the
45
+ * event's signature and applied it to the log.
46
+ */
47
+ export declare function openKeyShares(event: ConvKeysEvent, identity: Identity): KeyShare[];