@agora-sdk/secure-chat-core 0.6.5 → 0.8.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 (89) hide show
  1. package/dist/cjs/content/builders.d.ts +40 -0
  2. package/dist/cjs/content/builders.js +85 -0
  3. package/dist/cjs/content/builders.js.map +1 -0
  4. package/dist/cjs/content/cbor.d.ts +48 -0
  5. package/dist/cjs/content/cbor.js +298 -0
  6. package/dist/cjs/content/cbor.js.map +1 -0
  7. package/dist/cjs/content/frame.d.ts +24 -0
  8. package/dist/cjs/content/frame.js +39 -0
  9. package/dist/cjs/content/frame.js.map +1 -0
  10. package/dist/cjs/content/mimi-content.d.ts +194 -0
  11. package/dist/cjs/content/mimi-content.js +289 -0
  12. package/dist/cjs/content/mimi-content.js.map +1 -0
  13. package/dist/cjs/context/secure-chat-context.d.ts +19 -3
  14. package/dist/cjs/context/secure-chat-context.js +53 -13
  15. package/dist/cjs/context/secure-chat-context.js.map +1 -1
  16. package/dist/cjs/hooks/message-fold.d.ts +91 -0
  17. package/dist/cjs/hooks/message-fold.js +218 -0
  18. package/dist/cjs/hooks/message-fold.js.map +1 -0
  19. package/dist/cjs/hooks/useSecureConversations.js +11 -0
  20. package/dist/cjs/hooks/useSecureConversations.js.map +1 -1
  21. package/dist/cjs/hooks/useSecureDevice.js +15 -1
  22. package/dist/cjs/hooks/useSecureDevice.js.map +1 -1
  23. package/dist/cjs/hooks/useSecureHandshakes.js +36 -2
  24. package/dist/cjs/hooks/useSecureHandshakes.js.map +1 -1
  25. package/dist/cjs/hooks/useSecureMessages.d.ts +30 -18
  26. package/dist/cjs/hooks/useSecureMessages.js +197 -130
  27. package/dist/cjs/hooks/useSecureMessages.js.map +1 -1
  28. package/dist/cjs/index.d.ts +8 -0
  29. package/dist/cjs/index.js +30 -1
  30. package/dist/cjs/index.js.map +1 -1
  31. package/dist/cjs/persistence/repository.d.ts +24 -0
  32. package/dist/cjs/persistence/repository.js +35 -0
  33. package/dist/cjs/persistence/repository.js.map +1 -1
  34. package/dist/cjs/persistence/store.js +11 -0
  35. package/dist/cjs/persistence/store.js.map +1 -1
  36. package/dist/cjs/transport/rest.d.ts +2 -2
  37. package/dist/cjs/transport/rest.js +2 -2
  38. package/dist/cjs/transport/rest.js.map +1 -1
  39. package/dist/cjs/transport/socket.d.ts +1 -1
  40. package/dist/cjs/transport/socket.js +17 -1
  41. package/dist/cjs/transport/socket.js.map +1 -1
  42. package/dist/cjs/version.d.ts +13 -0
  43. package/dist/cjs/version.js +19 -0
  44. package/dist/cjs/version.js.map +1 -0
  45. package/dist/esm/content/builders.d.ts +40 -0
  46. package/dist/esm/content/builders.js +77 -0
  47. package/dist/esm/content/builders.js.map +1 -0
  48. package/dist/esm/content/cbor.d.ts +48 -0
  49. package/dist/esm/content/cbor.js +292 -0
  50. package/dist/esm/content/cbor.js.map +1 -0
  51. package/dist/esm/content/frame.d.ts +24 -0
  52. package/dist/esm/content/frame.js +34 -0
  53. package/dist/esm/content/frame.js.map +1 -0
  54. package/dist/esm/content/mimi-content.d.ts +194 -0
  55. package/dist/esm/content/mimi-content.js +283 -0
  56. package/dist/esm/content/mimi-content.js.map +1 -0
  57. package/dist/esm/context/secure-chat-context.d.ts +19 -3
  58. package/dist/esm/context/secure-chat-context.js +53 -13
  59. package/dist/esm/context/secure-chat-context.js.map +1 -1
  60. package/dist/esm/hooks/message-fold.d.ts +91 -0
  61. package/dist/esm/hooks/message-fold.js +214 -0
  62. package/dist/esm/hooks/message-fold.js.map +1 -0
  63. package/dist/esm/hooks/useSecureConversations.js +11 -0
  64. package/dist/esm/hooks/useSecureConversations.js.map +1 -1
  65. package/dist/esm/hooks/useSecureDevice.js +15 -1
  66. package/dist/esm/hooks/useSecureDevice.js.map +1 -1
  67. package/dist/esm/hooks/useSecureHandshakes.js +36 -2
  68. package/dist/esm/hooks/useSecureHandshakes.js.map +1 -1
  69. package/dist/esm/hooks/useSecureMessages.d.ts +30 -18
  70. package/dist/esm/hooks/useSecureMessages.js +199 -132
  71. package/dist/esm/hooks/useSecureMessages.js.map +1 -1
  72. package/dist/esm/index.d.ts +8 -0
  73. package/dist/esm/index.js +8 -0
  74. package/dist/esm/index.js.map +1 -1
  75. package/dist/esm/persistence/repository.d.ts +24 -0
  76. package/dist/esm/persistence/repository.js +35 -0
  77. package/dist/esm/persistence/repository.js.map +1 -1
  78. package/dist/esm/persistence/store.js +11 -0
  79. package/dist/esm/persistence/store.js.map +1 -1
  80. package/dist/esm/transport/rest.d.ts +2 -2
  81. package/dist/esm/transport/rest.js +2 -2
  82. package/dist/esm/transport/rest.js.map +1 -1
  83. package/dist/esm/transport/socket.d.ts +1 -1
  84. package/dist/esm/transport/socket.js +17 -1
  85. package/dist/esm/transport/socket.js.map +1 -1
  86. package/dist/esm/version.d.ts +13 -0
  87. package/dist/esm/version.js +16 -0
  88. package/dist/esm/version.js.map +1 -0
  89. package/package.json +3 -3
@@ -1,22 +1,58 @@
1
- // useSecureMessages — load, decrypt, send, and live-receive messages in a secure conversation.
1
+ // useSecureMessages — load, decrypt, send, and live-receive MIMI-content messages in a secure conversation.
2
2
  //
3
- // Self-sufficient once a store is wired: the MLS GroupHandle is auto-resolved from persistence via
4
- // resolveGroup, and senderDeviceId is read from the persisted device. Both stay overridable through
5
- // options for advanced use. Without a resolvable handle, ciphertext is still listed/received
6
- // (plaintext: null) and sending is disabled.
7
- import { useCallback, useEffect, useRef, useState } from "react";
3
+ // Content is the IETF MimiContent format (CBOR) inside a [kind][payload] routing frame inside the
4
+ // size-bucket padding frame all ABOVE the unchanged SecureChatCrypto seam (which still exchanges
5
+ // Uint8Array). The hook owns message-list STATE (dedup, ordering, decrypt-once, write-through) keyed by
6
+ // server messageId; a MessageFold collapses reaction/edit/delete/un-react messages onto their target by
7
+ // MIMI content-hash. The durable source of truth stays REST; realtime is a notification optimization.
8
+ import { useCallback, useEffect, useMemo, useReducer, useRef, useState } from "react";
8
9
  import { SecureChatDecryptError, } from "@agora-sdk/secure-chat-crypto";
9
- import { toBase64, fromBase64, utf8ToBytes, bytesToUtf8 } from "../util/base64.js";
10
+ import { toBase64, fromBase64 } from "../util/base64.js";
10
11
  import { padPlaintext, unpadPlaintext } from "../util/padding.js";
11
12
  import { createDebugLogger } from "../util/debug.js";
12
13
  import { useSecureChat } from "../context/secure-chat-context.js";
14
+ import { frameContent, unframe, ContentKind } from "../content/frame.js";
15
+ import { encodeMimiContent, decodeMimiContent, contentHash, } from "../content/mimi-content.js";
16
+ import { buildPost, buildReply, buildEdit, buildDelete, buildReaction, buildUnreact, } from "../content/builders.js";
17
+ import { MessageFold, } from "./message-fold.js";
13
18
  const log = createDebugLogger("messages");
19
+ const REJECT_MALFORMED = { status: "rejected", rejectedReason: "malformed" };
20
+ /** Decode a content-frame to a typed outcome. Pure; fails closed on any framing/schema error. */
21
+ function decodeFrame(frameBytes, model, senderDeviceId) {
22
+ let unf;
23
+ try {
24
+ unf = unframe(frameBytes);
25
+ }
26
+ catch {
27
+ return REJECT_MALFORMED;
28
+ }
29
+ // kind 1 = IUC control (reserved; out of scope here): authenticate + hide, never render, never error.
30
+ if (unf.kind === ContentKind.IucControl)
31
+ return { status: "ok", control: true };
32
+ if (unf.kind !== ContentKind.Mimi)
33
+ return REJECT_MALFORMED;
34
+ let mimi;
35
+ try {
36
+ mimi = decodeMimiContent(unf.payload);
37
+ }
38
+ catch {
39
+ return REJECT_MALFORMED;
40
+ }
41
+ return {
42
+ status: "ok",
43
+ control: false,
44
+ decoded: {
45
+ messageId: model.id,
46
+ createdAt: model.createdAt,
47
+ senderDeviceId,
48
+ contentHash: contentHash(mimi),
49
+ mimi,
50
+ },
51
+ };
52
+ }
53
+ const cmpStr = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
14
54
  /**
15
- * Load, decrypt, send, and live-receive messages in one secure conversation.
16
- *
17
- * Auto-resolves the MLS group handle (via `resolveGroup`) and the sender device id (from the
18
- * persisted device) unless overridden in `options`. Joins the conversation socket room for live
19
- * `secure:message` events.
55
+ * Load, decrypt, send, and live-receive MIMI-content messages in one secure conversation.
20
56
  *
21
57
  * @param conversationId - The conversation to read and send within.
22
58
  * @param options - {@link UseSecureMessagesOptions}.
@@ -24,40 +60,38 @@ const log = createDebugLogger("messages");
24
60
  *
25
61
  * @example
26
62
  * ```tsx
27
- * const { messages, sendMessage } = useSecureMessages(conversationId);
63
+ * const { messages, sendMessage, react } = useSecureMessages(conversationId);
28
64
  * await sendMessage("hello 💜");
65
+ * await react(messages[0].contentHash!, "👍");
29
66
  * ```
30
67
  */
31
68
  export function useSecureMessages(conversationId, options = {}) {
32
- const { rest, crypto, socket, repo, resolveGroup, getGroupVersion, subscribeGroupChange, padding } = useSecureChat();
33
- const [messages, setMessages] = useState([]);
69
+ const { rest, crypto, socket, repo, resolveGroup, persistGroupState, getGroupVersion, subscribeGroupChange, padding, } = useSecureChat();
34
70
  const [before, setBefore] = useState(undefined);
35
71
  const [hasMore, setHasMore] = useState(true);
36
72
  const [loading, setLoading] = useState(false);
37
73
  const [error, setError] = useState(null);
38
74
  const [group, setGroup] = useState(options.group ?? null);
39
75
  const [senderDeviceId, setSenderDeviceId] = useState(options.senderDeviceId);
40
- // Bumps when THIS conversation's group handle advances (a join or a processed Commit, driven by
41
- // useSecureHandshakes calling rememberGroup). Feeds the group-resolve effect's deps so we re-resolve
42
- // the now-current handle and flush buffered (plaintext:null) rows.
43
76
  const [groupVersion, setGroupVersion] = useState(0);
44
- // Latest messages, read by the "decrypt history once the group resolves" effect below without
45
- // making `messages` one of its deps (which would loop).
46
- const messagesRef = useRef(messages);
47
- messagesRef.current = messages;
48
- // Subscribe to provider group-change signals; only a change to OUR conversation's version updates
49
- // state (React bails on an unchanged primitive), so unrelated conversations don't re-resolve us.
77
+ // Rendered state lives in refs (the fold mutates target rows in place); `bump` forces a re-derive.
78
+ const byIdRef = useRef(new Map());
79
+ const foldRef = useRef(new MessageFold());
80
+ // Decrypt-once cache by id: MLS application keys are single-use, so the one decrypt that succeeds is
81
+ // the only one that ever will. Survives StrictMode double-invokes and multi-effect decrypts.
82
+ const okCache = useRef(new Map());
83
+ const [version, bump] = useReducer((x) => x + 1, 0);
84
+ const groupRef = useRef(group);
85
+ groupRef.current = group;
50
86
  useEffect(() => {
51
87
  return subscribeGroupChange(() => setGroupVersion(getGroupVersion(conversationId)));
52
88
  }, [subscribeGroupChange, getGroupVersion, conversationId]);
53
- // Resolve the group handle: explicit override, else persisted state.
89
+ // Resolve the group handle: explicit override, else persisted state. (Same as before.)
54
90
  useEffect(() => {
55
91
  if (options.group) {
56
92
  setGroup(options.group);
57
93
  return;
58
94
  }
59
- // Clear any stale handle from the previous conversation before re-resolving, so live messages
60
- // for the new conversation never decrypt against the old group during the async window.
61
95
  setGroup(null);
62
96
  let alive = true;
63
97
  resolveGroup(conversationId)
@@ -72,9 +106,8 @@ export function useSecureMessages(conversationId, options = {}) {
72
106
  return () => {
73
107
  alive = false;
74
108
  };
75
- // `groupVersion` re-runs this when a Commit/join advances the handle → flushes buffered rows.
76
109
  }, [options.group, conversationId, resolveGroup, groupVersion]);
77
- // Resolve the sender device id: explicit override, else persisted device row.
110
+ // Resolve the sender device id: explicit override, else persisted device row. (Same as before.)
78
111
  useEffect(() => {
79
112
  if (options.senderDeviceId) {
80
113
  setSenderDeviceId(options.senderDeviceId);
@@ -95,86 +128,127 @@ export function useSecureMessages(conversationId, options = {}) {
95
128
  alive = false;
96
129
  };
97
130
  }, [options.senderDeviceId, repo]);
131
+ // Decrypt one message to a typed outcome. Two short-circuits BEFORE the single-use ratchet: the
132
+ // in-memory okCache and the durable content-frame store. A store/cache hit re-decodes locally and
133
+ // NEVER touches the ratchet (re-decrypting a consumed key throws "Desired gen in the past").
98
134
  const decrypt = useCallback(async (model) => {
99
- // No handle yet (still resolving) → retryable once it arrives.
100
- if (!group) {
101
- log.trace("decrypt deferred — no group handle yet", { messageId: model.id, epoch: model.epoch });
102
- return { model, plaintext: null, status: "pending" };
135
+ const cached = okCache.current.get(model.id);
136
+ if (cached)
137
+ return cached;
138
+ const storedFrame = await repo.loadMessageContent(conversationId, model.id);
139
+ if (storedFrame !== null) {
140
+ // The frame was already authenticated when first decrypted (and write-through only happens on an
141
+ // `ok` decrypt). The server-reported senderDeviceId is just a render label here; coalesce its
142
+ // possible null to "" so the fold's DecodedContentMessage stays a plain string.
143
+ const outcome = decodeFrame(storedFrame, model, model.senderDeviceId ?? "");
144
+ if (outcome.status === "ok")
145
+ okCache.current.set(model.id, outcome);
146
+ return outcome;
103
147
  }
148
+ const grp = groupRef.current;
149
+ if (!grp)
150
+ return { status: "pending" };
104
151
  let plaintext;
152
+ let sender;
105
153
  try {
106
- ({ plaintext } = await crypto.decryptMessage(group, fromBase64(model.ciphertext)));
154
+ ({ plaintext, senderDeviceId: sender } = await crypto.decryptMessage(grp, fromBase64(model.ciphertext)));
107
155
  }
108
156
  catch (err) {
109
- // Classify, don't conflate. A message from an epoch we HAVEN'T reached yet is legitimately
110
- // buffered (a future Commit will advance us, then this re-decrypts). Anything else that fails
111
- // at an epoch we HAVE reached is a terminal rejection — the MLS core refused it (replay,
112
- // over-window gap, bad auth, malformed, too-old epoch). Fail closed: never show it as text and
113
- // never silently retry it forever (the old behavior masked replays/forgeries as "pending").
114
- if (BigInt(model.epoch) > group.epoch) {
115
- log.debug("decrypt buffered — message epoch ahead of ours", {
116
- messageId: model.id,
117
- messageEpoch: model.epoch,
118
- groupEpoch: group.epoch.toString(),
119
- });
120
- return { model, plaintext: null, status: "pending" };
121
- }
157
+ if (BigInt(model.epoch) > grp.epoch)
158
+ return { status: "pending" }; // epoch ahead buffer
122
159
  const rejectedReason = err instanceof SecureChatDecryptError ? err.reason : "unknown";
123
- log.debug("decrypt rejected (fail closed)", {
124
- messageId: model.id,
125
- messageEpoch: model.epoch,
126
- groupEpoch: group.epoch.toString(),
127
- rejectedReason,
128
- });
129
- return { model, plaintext: null, status: "rejected", rejectedReason };
160
+ return { status: "rejected", rejectedReason };
130
161
  }
131
- // Decrypt + MLS authentication succeeded, so the bytes are from a real group member. Strip the
132
- // size-bucket padding frame (see util/padding). A bad frame here is NOT a decrypt failure — it's a
133
- // framing/version mismatch from an authenticated sender — so fail closed as "malformed" rather
134
- // than rendering raw padded bytes as text.
162
+ let frameBytes;
135
163
  try {
136
- return { model, plaintext: bytesToUtf8(unpadPlaintext(plaintext)), status: "ok" };
164
+ frameBytes = unpadPlaintext(plaintext); // authenticated sender, bad padding ⇒ malformed (fail closed)
137
165
  }
138
166
  catch {
139
- return { model, plaintext: null, status: "rejected", rejectedReason: "malformed" };
167
+ return REJECT_MALFORMED;
168
+ }
169
+ const outcome = decodeFrame(frameBytes, model, sender);
170
+ if (outcome.status === "ok") {
171
+ okCache.current.set(model.id, outcome);
172
+ // Write-through the raw content-frame bytes (re-decoded + re-folded on reload), then persist the
173
+ // advanced RECEIVE ratchet (decrypt moved the generation in memory; a reload must not rewind it).
174
+ await repo.saveMessageContent(conversationId, model.id, frameBytes);
175
+ await persistGroupState(conversationId, grp);
176
+ }
177
+ return outcome;
178
+ }, [crypto, repo, conversationId, persistGroupState]);
179
+ // Fold one outcome into rendered state. `ok` is terminal (never downgraded — forward secrecy).
180
+ const ingest = useCallback((model, outcome) => {
181
+ const entries = byIdRef.current;
182
+ const prev = entries.get(model.id);
183
+ if (prev?.status === "ok")
184
+ return;
185
+ if (outcome.status === "ok") {
186
+ if (outcome.control) {
187
+ entries.set(model.id, { model, status: "ok", renderable: false });
188
+ }
189
+ else {
190
+ const { renderable } = foldRef.current.apply(outcome.decoded);
191
+ entries.set(model.id, { model, status: "ok", renderable, decoded: outcome.decoded });
192
+ }
193
+ }
194
+ else if (outcome.status === "pending") {
195
+ if (!prev)
196
+ entries.set(model.id, { model, status: "pending", renderable: false });
197
+ }
198
+ else {
199
+ if (!prev || prev.status === "pending")
200
+ entries.set(model.id, { model, status: "rejected", renderable: false, rejectedReason: outcome.rejectedReason });
201
+ }
202
+ bump();
203
+ }, []);
204
+ // Derive the rendered list: only renderable (post/reply) rows + non-ok rows, newest-first. Mutation
205
+ // and control rows are folded/hidden. Recomputed on every `bump` (fold mutates rows in place).
206
+ const messages = useMemo(() => {
207
+ const rows = [];
208
+ for (const e of byIdRef.current.values()) {
209
+ if (e.status === "ok") {
210
+ if (!e.renderable)
211
+ continue;
212
+ rows.push({
213
+ model: e.model,
214
+ content: foldRef.current.getContent(e.model.id),
215
+ mimi: e.decoded?.mimi ?? null,
216
+ contentHash: e.decoded?.contentHash ?? null,
217
+ status: "ok",
218
+ });
219
+ }
220
+ else {
221
+ rows.push({ model: e.model, content: null, mimi: null, contentHash: null, status: e.status, rejectedReason: e.rejectedReason });
222
+ }
140
223
  }
141
- }, [crypto, group]);
224
+ rows.sort((a, b) => cmpStr(b.model.createdAt, a.model.createdAt) || cmpStr(b.model.id, a.model.id));
225
+ return rows;
226
+ // eslint-disable-next-line react-hooks/exhaustive-deps
227
+ }, [version]);
142
228
  const load = useCallback(async (reset) => {
143
229
  setLoading(true);
144
230
  setError(null);
145
231
  try {
146
- const page = await rest.listMessages(conversationId, {
147
- before: reset ? undefined : before,
148
- limit: 40,
149
- });
150
- const decrypted = await Promise.all(page.messages.map(decrypt));
232
+ const page = await rest.listMessages(conversationId, { before: reset ? undefined : before, limit: 40 });
233
+ if (reset) {
234
+ byIdRef.current.clear();
235
+ foldRef.current.reset();
236
+ }
151
237
  const oldest = page.messages[page.messages.length - 1];
152
238
  setBefore(oldest ? oldest.createdAt : before);
153
239
  setHasMore(page.hasMore);
154
- // Server returns created_at DESC; keep newest-first in state.
155
- setMessages((prev) => (reset ? decrypted : [...prev, ...decrypted]));
156
- log.debug("loaded message page", {
157
- conversationId,
158
- reset,
159
- before: reset ? undefined : before,
160
- count: decrypted.length,
161
- hasMore: page.hasMore,
162
- ok: decrypted.filter((m) => m.status === "ok").length,
163
- pending: decrypted.filter((m) => m.status === "pending").length,
164
- rejected: decrypted.filter((m) => m.status === "rejected").length,
165
- });
240
+ for (const model of page.messages)
241
+ ingest(model, await decrypt(model));
242
+ bump();
243
+ log.debug("loaded message page", { conversationId, reset, count: page.messages.length, hasMore: page.hasMore });
166
244
  }
167
245
  catch (err) {
168
- log.debug("load message page failed", {
169
- conversationId,
170
- error: err instanceof Error ? err.message : String(err),
171
- });
172
246
  setError(err);
173
247
  }
174
248
  finally {
175
249
  setLoading(false);
176
250
  }
177
- }, [rest, conversationId, before, decrypt]);
251
+ }, [rest, conversationId, before, decrypt, ingest]);
178
252
  const refresh = useCallback(async () => {
179
253
  setBefore(undefined);
180
254
  await load(true);
@@ -184,82 +258,75 @@ export function useSecureMessages(conversationId, options = {}) {
184
258
  return;
185
259
  await load(false);
186
260
  }, [hasMore, loading, load]);
187
- const sendMessage = useCallback(async (text) => {
188
- // Assumes the crypto identity is already hydrated (mount `useSecureDevice` under the same
189
- // provider): the crypto layer tags the sender from the restored device identity, so after a
190
- // reload the first send must wait for useSecureDevice's importDeviceState to complete.
261
+ // Shared send: encode frame → pad → encrypt → persist ratchet → POST → persist content → optimistic.
262
+ const sendContent = useCallback(async (mimi) => {
191
263
  if (!group)
192
264
  throw new Error("Cannot send: no MLS group handle for this conversation.");
193
265
  if (!senderDeviceId)
194
266
  throw new Error("Cannot send: senderDeviceId is required.");
195
- // Pad the plaintext to a size bucket BEFORE encryption so the ciphertext length leaks less
196
- // (the receiver strips the frame in `decrypt`). See util/padding for the framing.
197
- const { ciphertext, epoch } = await crypto.encryptMessage(group, padPlaintext(utf8ToBytes(text), padding));
267
+ const frame = frameContent(ContentKind.Mimi, encodeMimiContent(mimi));
268
+ const { ciphertext, epoch } = await crypto.encryptMessage(group, padPlaintext(frame, padding));
269
+ // Persist the advanced SEND ratchet BEFORE the network send (it moved regardless of success).
270
+ await persistGroupState(conversationId, group);
198
271
  const sent = await rest.sendMessage(conversationId, {
199
272
  ciphertext: toBase64(ciphertext),
200
273
  epoch: epoch.toString(),
201
274
  senderDeviceId,
202
275
  });
203
- log.debug("sent message", {
204
- conversationId,
205
- messageId: sent.id,
206
- epoch: epoch.toString(),
207
- senderDeviceId,
208
- });
209
- // Optimistic: we know our own plaintext without a round-trip through decrypt. Dedup by id while
210
- // prepending: the server echoes this same row back over `secure:message`, and a sender can't
211
- // decrypt their own MLS message, so that echo decrypts as `rejected`. If the echo wins the race
212
- // against this HTTP response it's already in `prev` — drop it and keep this authoritative `ok`
213
- // copy, so the list never holds two rows with the same id (React duplicate-key) and the user
214
- // never sees their own message as `rejected`. (The live-receive path dedups the other ordering.)
215
- setMessages((prev) => [
216
- { model: sent, plaintext: text, status: "ok" },
217
- ...prev.filter((p) => p.model.id !== sent.id),
218
- ]);
219
- }, [crypto, rest, conversationId, group, senderDeviceId, padding]);
276
+ await repo.saveMessageContent(conversationId, sent.id, frame);
277
+ // Optimistic: we can't decrypt our own MLS message, so seed the decoded content directly and cache
278
+ // it so the server echo short-circuits (no rejected flicker).
279
+ const decoded = {
280
+ messageId: sent.id, createdAt: sent.createdAt, senderDeviceId, contentHash: contentHash(mimi), mimi,
281
+ };
282
+ const outcome = { status: "ok", control: false, decoded };
283
+ okCache.current.set(sent.id, outcome);
284
+ ingest(sent, outcome);
285
+ log.debug("sent content", { conversationId, messageId: sent.id, epoch: epoch.toString() });
286
+ }, [crypto, rest, repo, conversationId, group, senderDeviceId, padding, persistGroupState, ingest]);
287
+ const sendMessage = useCallback((text) => sendContent(buildPost(text)), [sendContent]);
288
+ const reply = useCallback((t, text) => sendContent(buildReply(text, t)), [sendContent]);
289
+ const react = useCallback((t, token) => sendContent(buildReaction(t, token)), [sendContent]);
290
+ const editMessage = useCallback((t, text) => sendContent(buildEdit(t, text)), [sendContent]);
291
+ const deleteMessage = useCallback((t) => sendContent(buildDelete(t)), [sendContent]);
292
+ const unreact = useCallback((reactionHash) => sendContent(buildUnreact(reactionHash)), [sendContent]);
220
293
  useEffect(() => {
221
294
  refresh();
222
295
  // eslint-disable-next-line react-hooks/exhaustive-deps
223
296
  }, [conversationId]);
224
- // Re-decrypt buffered rows when the group handle advances. On reload the first page loads while
225
- // resolveGroup is still in flight (those rows come back `pending`); a Commit/join also advances the
226
- // epoch, letting previously-ahead rows decrypt. Retry ONLY `pending` rows — never `rejected` ones, so
227
- // a replay/forgery the core already refused isn't retried on every epoch bump. `ok` rows are kept.
297
+ // Retry buffered (pending) rows when the group handle advances.
228
298
  useEffect(() => {
229
299
  if (!group)
230
300
  return;
231
- if (!messagesRef.current.some((m) => m.status === "pending"))
301
+ const pendingModels = [...byIdRef.current.values()].filter((e) => e.status === "pending").map((e) => e.model);
302
+ if (pendingModels.length === 0)
232
303
  return;
233
304
  let alive = true;
234
- Promise.all(messagesRef.current.map((m) => (m.status === "pending" ? decrypt(m.model) : Promise.resolve(m)))).then((next) => {
235
- if (alive)
236
- setMessages(next);
237
- });
305
+ (async () => {
306
+ for (const m of pendingModels) {
307
+ const outcome = await decrypt(m);
308
+ if (!alive)
309
+ return;
310
+ ingest(m, outcome);
311
+ }
312
+ })();
238
313
  return () => {
239
314
  alive = false;
240
315
  };
241
- }, [group, decrypt]);
242
- // Live receive: join the conversation room and decrypt inbound ciphertext.
316
+ }, [group, decrypt, ingest]);
317
+ // Live receive: join the conversation room and decrypt+ingest inbound ciphertext.
243
318
  useEffect(() => {
244
319
  socket.joinConversation(conversationId);
245
320
  const off = socket.on("secure:message", (model) => {
246
321
  if (model.conversationId !== conversationId)
247
322
  return;
248
- decrypt(model).then((m) => setMessages((prev) => {
249
- if (prev.some((p) => p.model.id === m.model.id)) {
250
- log.trace("live message deduped", { messageId: m.model.id });
251
- return prev;
252
- }
253
- log.debug("live message received", {
254
- conversationId,
255
- messageId: m.model.id,
256
- status: m.status,
257
- });
258
- return [m, ...prev];
259
- }));
323
+ decrypt(model).then((outcome) => ingest(model, outcome));
260
324
  });
261
325
  return off;
262
- }, [socket, conversationId, decrypt]);
263
- return { messages, loading, hasMore, error, loadMore, refresh, sendMessage };
326
+ }, [socket, conversationId, decrypt, ingest]);
327
+ return {
328
+ messages, loading, hasMore, error, loadMore, refresh,
329
+ sendMessage, reply, react, editMessage, deleteMessage, unreact,
330
+ };
264
331
  }
265
332
  //# sourceMappingURL=useSecureMessages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSecureMessages.js","sourceRoot":"","sources":["../../../src/hooks/useSecureMessages.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useSecureMessages.js","sourceRoot":"","sources":["../../../src/hooks/useSecureMessages.tsx"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ export { VERSION } from "./version.js";
1
2
  export { SecureChatProvider, useSecureChat } from "./context/secure-chat-context.js";
2
3
  export type { SecureChatProviderProps, SecureChatContextValue, } from "./context/secure-chat-context.js";
3
4
  export { useSecureDevice } from "./hooks/useSecureDevice.js";
@@ -30,5 +31,12 @@ export { padPlaintext, unpadPlaintext, nextBucket } from "./util/padding.js";
30
31
  export type { PaddingPolicy } from "./util/padding.js";
31
32
  export { computeSafetyNumber } from "./util/safety-number.js";
32
33
  export type { SafetyNumber } from "./util/safety-number.js";
34
+ export { encodeMimiContent, decodeMimiContent, contentHash, Cardinality, Disposition, HashAlg, PartSemantics, MIMI_LIMITS, } from "./content/mimi-content.js";
35
+ export type { MimiContent, Part, NullPart, SinglePart, ExternalPart, MultiPart, Expiration, } from "./content/mimi-content.js";
36
+ export { buildPost, buildReply, buildEdit, buildDelete, buildReaction, buildUnreact, } from "./content/builders.js";
37
+ export { frameContent, unframe, ContentKind } from "./content/frame.js";
38
+ export type { RenderedContent } from "./hooks/message-fold.js";
39
+ export { encode as encodeCbor, decode as decodeCbor, CborTag } from "./content/cbor.js";
40
+ export type { CborValue, CborMap, CborLimits } from "./content/cbor.js";
33
41
  export { setSecureChatDebug, isSecureChatDebugEnabled } from "./util/debug.js";
34
42
  export type { SecureChatDebugLevel, SecureChatDebugLogger } from "./util/debug.js";
package/dist/esm/index.js CHANGED
@@ -3,6 +3,8 @@
3
3
  // Transport (REST + /secure socket) + provider/hooks, with MLS crypto supplied by dependency
4
4
  // injection of a `SecureChatCrypto`. Platform packages (@agora-sdk/secure-chat-react-js, etc.)
5
5
  // re-export this and add the concrete crypto + persistence.
6
+ // ── version (generated from package.json; see scripts/write-version.mjs) ──────
7
+ export { VERSION } from "./version.js";
6
8
  // ── context / provider ──────────────────────────────────────────────────────
7
9
  export { SecureChatProvider, useSecureChat } from "./context/secure-chat-context.js";
8
10
  // ── hooks ────────────────────────────────────────────────────────────────────
@@ -24,6 +26,12 @@ export { SecureChatRepository } from "./persistence/repository.js";
24
26
  export { toBase64, fromBase64, utf8ToBytes, bytesToUtf8 } from "./util/base64.js";
25
27
  export { padPlaintext, unpadPlaintext, nextBucket } from "./util/padding.js";
26
28
  export { computeSafetyNumber } from "./util/safety-number.js";
29
+ // ── MIMI content (CBOR message content + routing frame + fold) ─────────────────
30
+ export { encodeMimiContent, decodeMimiContent, contentHash, Cardinality, Disposition, HashAlg, PartSemantics, MIMI_LIMITS, } from "./content/mimi-content.js";
31
+ export { buildPost, buildReply, buildEdit, buildDelete, buildReaction, buildUnreact, } from "./content/builders.js";
32
+ export { frameContent, unframe, ContentKind } from "./content/frame.js";
33
+ // Low-level CBOR codec (advanced; the IUC control channel reuses it under kind 1).
34
+ export { encode as encodeCbor, decode as decodeCbor, CborTag } from "./content/cbor.js";
27
35
  // ── dev logging (off by default; see util/debug) ──────────────────────────────
28
36
  export { setSecureChatDebug, isSecureChatDebugEnabled } from "./util/debug.js";
29
37
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,EAAE;AACF,6FAA6F;AAC7F,+FAA+F;AAC/F,4DAA4D;AAE5D,+EAA+E;AAC/E,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAMrF,gFAAgF;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAMjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAKrE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAGzE,iFAAiF;AACjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAG7E,gFAAgF;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAoB/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAOvE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGnE,gFAAgF;AAChF,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAG9D,iFAAiF;AACjF,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,EAAE;AACF,6FAA6F;AAC7F,+FAA+F;AAC/F,4DAA4D;AAE5D,iFAAiF;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,+EAA+E;AAC/E,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAMrF,gFAAgF;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAE3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAMjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAKrE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AAGzE,iFAAiF;AACjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAG7E,gFAAgF;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAoB/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAOvE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAGnE,gFAAgF;AAChF,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAG9D,kFAAkF;AAClF,OAAO,EACL,iBAAiB,EAAE,iBAAiB,EAAE,WAAW,EACjD,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,GAC9D,MAAM,2BAA2B,CAAC;AAInC,OAAO,EACL,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,GAC3E,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAExE,mFAAmF;AACnF,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,IAAI,UAAU,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGxF,iFAAiF;AACjF,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -27,6 +27,30 @@ export declare class SecureChatRepository {
27
27
  deleteGroupState(conversationId: string): Promise<void>;
28
28
  /** List the conversation ids that have persisted group state. */
29
29
  listGroupConversationIds(): Promise<string[]>;
30
+ /**
31
+ * Persist the decrypted content-frame bytes of a message (local-only, decrypt-once history).
32
+ *
33
+ * Stores the `[kind][payload]` frame exactly as decrypted (raw bytes — NOT text): MLS application
34
+ * keys are single-use (forward secrecy), so a message decrypts exactly once; this stored copy is what
35
+ * the hook re-decodes + re-folds on every later reload. The blind server never receives this; it lives
36
+ * only in the platform store (web: IndexedDB; tests: MemoryStore).
37
+ *
38
+ * @param conversationId - The conversation the message belongs to.
39
+ * @param messageId - The globally-unique server message id.
40
+ * @param content - The decrypted content-frame bytes (`[kind][payload]`, post-unpadding).
41
+ */
42
+ saveMessageContent(conversationId: string, messageId: string, content: Uint8Array): Promise<void>;
43
+ /**
44
+ * Load a message's previously-decrypted content-frame bytes, or `null` if never stored.
45
+ *
46
+ * A non-null result lets the decrypt path short-circuit BEFORE touching the MLS ratchet — re-decrypting
47
+ * would throw `"Desired gen in the past"` (the key is gone after first use).
48
+ *
49
+ * @param conversationId - The conversation the message belongs to.
50
+ * @param messageId - The globally-unique server message id.
51
+ * @returns The stored content-frame bytes, or `null` on a miss.
52
+ */
53
+ loadMessageContent(conversationId: string, messageId: string): Promise<Uint8Array | null>;
30
54
  /** Load this device row's persisted handshake delivery cursor (`seq`), or `null`. */
31
55
  loadHandshakeCursor(deviceRowId: string): Promise<string | null>;
32
56
  /** Persist this device row's handshake delivery cursor (`seq`). */