@agora-sdk/secure-chat-core 0.1.0 → 0.3.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 (64) hide show
  1. package/dist/cjs/context/secure-chat-context.d.ts +34 -18
  2. package/dist/cjs/context/secure-chat-context.js +78 -23
  3. package/dist/cjs/context/secure-chat-context.js.map +1 -1
  4. package/dist/cjs/contract/index.js +2 -2
  5. package/dist/cjs/contract/index.js.map +1 -1
  6. package/dist/cjs/hooks/useSecureConversations.d.ts +1 -1
  7. package/dist/cjs/hooks/useSecureConversations.js +9 -7
  8. package/dist/cjs/hooks/useSecureConversations.js.map +1 -1
  9. package/dist/cjs/hooks/useSecureDevice.d.ts +14 -13
  10. package/dist/cjs/hooks/useSecureDevice.js +58 -25
  11. package/dist/cjs/hooks/useSecureDevice.js.map +1 -1
  12. package/dist/cjs/hooks/useSecureHandshakes.d.ts +64 -0
  13. package/dist/cjs/hooks/useSecureHandshakes.js +215 -0
  14. package/dist/cjs/hooks/useSecureHandshakes.js.map +1 -0
  15. package/dist/cjs/hooks/useSecureMessages.d.ts +10 -11
  16. package/dist/cjs/hooks/useSecureMessages.js +99 -21
  17. package/dist/cjs/hooks/useSecureMessages.js.map +1 -1
  18. package/dist/cjs/index.d.ts +20 -14
  19. package/dist/cjs/index.js +25 -19
  20. package/dist/cjs/index.js.map +1 -1
  21. package/dist/cjs/package.json +1 -0
  22. package/dist/cjs/persistence/memory-store.d.ts +9 -0
  23. package/dist/cjs/persistence/memory-store.js +27 -0
  24. package/dist/cjs/persistence/memory-store.js.map +1 -0
  25. package/dist/cjs/persistence/repository.d.ts +36 -0
  26. package/dist/cjs/persistence/repository.js +72 -0
  27. package/dist/cjs/persistence/repository.js.map +1 -0
  28. package/dist/cjs/persistence/store.d.ts +11 -0
  29. package/dist/cjs/persistence/store.js +8 -0
  30. package/dist/cjs/persistence/store.js.map +1 -0
  31. package/dist/cjs/transport/rest.d.ts +1 -1
  32. package/dist/cjs/transport/socket.d.ts +1 -1
  33. package/dist/esm/context/secure-chat-context.d.ts +34 -18
  34. package/dist/esm/context/secure-chat-context.js +77 -22
  35. package/dist/esm/context/secure-chat-context.js.map +1 -1
  36. package/dist/esm/contract/index.js +2 -2
  37. package/dist/esm/contract/index.js.map +1 -1
  38. package/dist/esm/hooks/useSecureConversations.d.ts +1 -1
  39. package/dist/esm/hooks/useSecureConversations.js +6 -4
  40. package/dist/esm/hooks/useSecureConversations.js.map +1 -1
  41. package/dist/esm/hooks/useSecureDevice.d.ts +14 -13
  42. package/dist/esm/hooks/useSecureDevice.js +55 -22
  43. package/dist/esm/hooks/useSecureDevice.js.map +1 -1
  44. package/dist/esm/hooks/useSecureHandshakes.d.ts +64 -0
  45. package/dist/esm/hooks/useSecureHandshakes.js +212 -0
  46. package/dist/esm/hooks/useSecureHandshakes.js.map +1 -0
  47. package/dist/esm/hooks/useSecureMessages.d.ts +10 -11
  48. package/dist/esm/hooks/useSecureMessages.js +96 -18
  49. package/dist/esm/hooks/useSecureMessages.js.map +1 -1
  50. package/dist/esm/index.d.ts +20 -14
  51. package/dist/esm/index.js +10 -7
  52. package/dist/esm/index.js.map +1 -1
  53. package/dist/esm/persistence/memory-store.d.ts +9 -0
  54. package/dist/esm/persistence/memory-store.js +23 -0
  55. package/dist/esm/persistence/memory-store.js.map +1 -0
  56. package/dist/esm/persistence/repository.d.ts +36 -0
  57. package/dist/esm/persistence/repository.js +68 -0
  58. package/dist/esm/persistence/repository.js.map +1 -0
  59. package/dist/esm/persistence/store.d.ts +11 -0
  60. package/dist/esm/persistence/store.js +7 -0
  61. package/dist/esm/persistence/store.js.map +1 -0
  62. package/dist/esm/transport/rest.d.ts +1 -1
  63. package/dist/esm/transport/socket.d.ts +1 -1
  64. package/package.json +3 -3
package/dist/cjs/index.js CHANGED
@@ -5,27 +5,33 @@
5
5
  // injection of a `SecureChatCrypto`. Platform packages (@agora-sdk/secure-chat-react-js, etc.)
6
6
  // re-export this and add the concrete crypto + persistence.
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.bytesToUtf8 = exports.utf8ToBytes = exports.fromBase64 = exports.toBase64 = exports.SecureChatSocketClient = exports.SecureChatRestClient = exports.useSecureMessages = exports.useSecureConversations = exports.useSecureDevice = exports.useSecureChat = exports.SecureChatProvider = void 0;
8
+ exports.bytesToUtf8 = exports.utf8ToBytes = exports.fromBase64 = exports.toBase64 = exports.SecureChatRepository = exports.MemoryStore = exports.SecureChatSocketClient = exports.SecureChatRestClient = exports.useSecureHandshakes = exports.useSecureMessages = exports.useSecureConversations = exports.useSecureDevice = exports.useSecureChat = exports.SecureChatProvider = void 0;
9
9
  // ── context / provider ──────────────────────────────────────────────────────
10
- var secure_chat_context_1 = require("./context/secure-chat-context");
11
- Object.defineProperty(exports, "SecureChatProvider", { enumerable: true, get: function () { return secure_chat_context_1.SecureChatProvider; } });
12
- Object.defineProperty(exports, "useSecureChat", { enumerable: true, get: function () { return secure_chat_context_1.useSecureChat; } });
10
+ var secure_chat_context_js_1 = require("./context/secure-chat-context.js");
11
+ Object.defineProperty(exports, "SecureChatProvider", { enumerable: true, get: function () { return secure_chat_context_js_1.SecureChatProvider; } });
12
+ Object.defineProperty(exports, "useSecureChat", { enumerable: true, get: function () { return secure_chat_context_js_1.useSecureChat; } });
13
13
  // ── hooks ────────────────────────────────────────────────────────────────────
14
- var useSecureDevice_1 = require("./hooks/useSecureDevice");
15
- Object.defineProperty(exports, "useSecureDevice", { enumerable: true, get: function () { return useSecureDevice_1.useSecureDevice; } });
16
- var useSecureConversations_1 = require("./hooks/useSecureConversations");
17
- Object.defineProperty(exports, "useSecureConversations", { enumerable: true, get: function () { return useSecureConversations_1.useSecureConversations; } });
18
- var useSecureMessages_1 = require("./hooks/useSecureMessages");
19
- Object.defineProperty(exports, "useSecureMessages", { enumerable: true, get: function () { return useSecureMessages_1.useSecureMessages; } });
14
+ var useSecureDevice_js_1 = require("./hooks/useSecureDevice.js");
15
+ Object.defineProperty(exports, "useSecureDevice", { enumerable: true, get: function () { return useSecureDevice_js_1.useSecureDevice; } });
16
+ var useSecureConversations_js_1 = require("./hooks/useSecureConversations.js");
17
+ Object.defineProperty(exports, "useSecureConversations", { enumerable: true, get: function () { return useSecureConversations_js_1.useSecureConversations; } });
18
+ var useSecureMessages_js_1 = require("./hooks/useSecureMessages.js");
19
+ Object.defineProperty(exports, "useSecureMessages", { enumerable: true, get: function () { return useSecureMessages_js_1.useSecureMessages; } });
20
+ var useSecureHandshakes_js_1 = require("./hooks/useSecureHandshakes.js");
21
+ Object.defineProperty(exports, "useSecureHandshakes", { enumerable: true, get: function () { return useSecureHandshakes_js_1.useSecureHandshakes; } });
20
22
  // ── transport (for advanced / non-React use) ─────────────────────────────────
21
- var rest_1 = require("./transport/rest");
22
- Object.defineProperty(exports, "SecureChatRestClient", { enumerable: true, get: function () { return rest_1.SecureChatRestClient; } });
23
- var socket_1 = require("./transport/socket");
24
- Object.defineProperty(exports, "SecureChatSocketClient", { enumerable: true, get: function () { return socket_1.SecureChatSocketClient; } });
23
+ var rest_js_1 = require("./transport/rest.js");
24
+ Object.defineProperty(exports, "SecureChatRestClient", { enumerable: true, get: function () { return rest_js_1.SecureChatRestClient; } });
25
+ var socket_js_1 = require("./transport/socket.js");
26
+ Object.defineProperty(exports, "SecureChatSocketClient", { enumerable: true, get: function () { return socket_js_1.SecureChatSocketClient; } });
27
+ var memory_store_js_1 = require("./persistence/memory-store.js");
28
+ Object.defineProperty(exports, "MemoryStore", { enumerable: true, get: function () { return memory_store_js_1.MemoryStore; } });
29
+ var repository_js_1 = require("./persistence/repository.js");
30
+ Object.defineProperty(exports, "SecureChatRepository", { enumerable: true, get: function () { return repository_js_1.SecureChatRepository; } });
25
31
  // ── utils ────────────────────────────────────────────────────────────────────
26
- var base64_1 = require("./util/base64");
27
- Object.defineProperty(exports, "toBase64", { enumerable: true, get: function () { return base64_1.toBase64; } });
28
- Object.defineProperty(exports, "fromBase64", { enumerable: true, get: function () { return base64_1.fromBase64; } });
29
- Object.defineProperty(exports, "utf8ToBytes", { enumerable: true, get: function () { return base64_1.utf8ToBytes; } });
30
- Object.defineProperty(exports, "bytesToUtf8", { enumerable: true, get: function () { return base64_1.bytesToUtf8; } });
32
+ var base64_js_1 = require("./util/base64.js");
33
+ Object.defineProperty(exports, "toBase64", { enumerable: true, get: function () { return base64_js_1.toBase64; } });
34
+ Object.defineProperty(exports, "fromBase64", { enumerable: true, get: function () { return base64_js_1.fromBase64; } });
35
+ Object.defineProperty(exports, "utf8ToBytes", { enumerable: true, get: function () { return base64_js_1.utf8ToBytes; } });
36
+ Object.defineProperty(exports, "bytesToUtf8", { enumerable: true, get: function () { return base64_js_1.bytesToUtf8; } });
31
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,qEAAkF;AAAzE,yHAAA,kBAAkB,OAAA;AAAE,oHAAA,aAAa,OAAA;AAM1C,gFAAgF;AAChF,2DAA0D;AAAjD,kHAAA,eAAe,OAAA;AAExB,yEAAwE;AAA/D,gIAAA,sBAAsB,OAAA;AAE/B,+DAA8D;AAArD,sHAAA,iBAAiB,OAAA;AAO1B,gFAAgF;AAChF,yCAAwD;AAA/C,4GAAA,oBAAoB,OAAA;AAE7B,6CAA4D;AAAnD,gHAAA,sBAAsB,OAAA;AAsB/B,gFAAgF;AAChF,wCAA+E;AAAtE,kGAAA,QAAQ,OAAA;AAAE,oGAAA,UAAU,OAAA;AAAE,qGAAA,WAAW,OAAA;AAAE,qGAAA,WAAW,OAAA"}
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,2EAAqF;AAA5E,4HAAA,kBAAkB,OAAA;AAAE,uHAAA,aAAa,OAAA;AAM1C,gFAAgF;AAChF,iEAA6D;AAApD,qHAAA,eAAe,OAAA;AAExB,+EAA2E;AAAlE,mIAAA,sBAAsB,OAAA;AAE/B,qEAAiE;AAAxD,yHAAA,iBAAiB,OAAA;AAM1B,yEAAqE;AAA5D,6HAAA,mBAAmB,OAAA;AAM5B,gFAAgF;AAChF,+CAA2D;AAAlD,+GAAA,oBAAoB,OAAA;AAE7B,mDAA+D;AAAtD,mHAAA,sBAAsB,OAAA;AAwB/B,iEAA4D;AAAnD,8GAAA,WAAW,OAAA;AACpB,6DAAmE;AAA1D,qHAAA,oBAAoB,OAAA;AAG7B,gFAAgF;AAChF,8CAAkF;AAAzE,qGAAA,QAAQ,OAAA;AAAE,uGAAA,UAAU,OAAA;AAAE,wGAAA,WAAW,OAAA;AAAE,wGAAA,WAAW,OAAA"}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,9 @@
1
+ import type { SecureChatStore } from "./store.js";
2
+ /** A `Map`-backed {@link SecureChatStore}. Non-persistent; the default when no store is injected. */
3
+ export declare class MemoryStore implements SecureChatStore {
4
+ private readonly map;
5
+ get(key: string): Promise<Uint8Array | null>;
6
+ set(key: string, value: Uint8Array): Promise<void>;
7
+ delete(key: string): Promise<void>;
8
+ list(prefix: string): Promise<string[]>;
9
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ // In-memory SecureChatStore — the provider default and the unit-test backing store.
3
+ //
4
+ // Not persistent: state is lost on reload. Platforms inject a durable store (IndexedDB on web) for
5
+ // real persistence; this keeps core usable in tests and SSR without one.
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.MemoryStore = void 0;
8
+ /** A `Map`-backed {@link SecureChatStore}. Non-persistent; the default when no store is injected. */
9
+ class MemoryStore {
10
+ constructor() {
11
+ this.map = new Map();
12
+ }
13
+ async get(key) {
14
+ return this.map.get(key) ?? null;
15
+ }
16
+ async set(key, value) {
17
+ this.map.set(key, value);
18
+ }
19
+ async delete(key) {
20
+ this.map.delete(key);
21
+ }
22
+ async list(prefix) {
23
+ return [...this.map.keys()].filter((k) => k.startsWith(prefix));
24
+ }
25
+ }
26
+ exports.MemoryStore = MemoryStore;
27
+ //# sourceMappingURL=memory-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-store.js","sourceRoot":"","sources":["../../../src/persistence/memory-store.ts"],"names":[],"mappings":";AAAA,oFAAoF;AACpF,EAAE;AACF,mGAAmG;AACnG,yEAAyE;;;AAIzE,qGAAqG;AACrG,MAAa,WAAW;IAAxB;QACmB,QAAG,GAAG,IAAI,GAAG,EAAsB,CAAC;IAiBvD,CAAC;IAfC,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAiB;QACtC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAc;QACvB,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAClE,CAAC;CACF;AAlBD,kCAkBC"}
@@ -0,0 +1,36 @@
1
+ import type { SecureDeviceModel } from "../contract/index.js";
2
+ import type { SecureChatStore } from "./store.js";
3
+ /** The persisted device record: stable id, opaque crypto device-state, and the server row. */
4
+ export interface PersistedDevice {
5
+ /** Stable MLS device id; survives reload. */
6
+ deviceId: string;
7
+ /** Opaque bytes from `crypto.exportDeviceState()`. */
8
+ deviceState: Uint8Array;
9
+ /** The registered server row (rehydrates UI without a refetch), or `null` if not yet registered. */
10
+ device: SecureDeviceModel | null;
11
+ }
12
+ /** Typed persistence for device identity, per-conversation group state, and the handshake cursor. */
13
+ export declare class SecureChatRepository {
14
+ private readonly store;
15
+ constructor(store: SecureChatStore);
16
+ /** Load the persisted device record, or `null` if none saved (first run / evicted). */
17
+ loadDevice(): Promise<PersistedDevice | null>;
18
+ /** Persist (replace) the device record. */
19
+ saveDevice(d: PersistedDevice): Promise<void>;
20
+ /** Remove the persisted device record. */
21
+ clearDevice(): Promise<void>;
22
+ /** Load opaque MLS group state for a conversation, or `null` if none. */
23
+ loadGroupState(conversationId: string): Promise<Uint8Array | null>;
24
+ /** Persist opaque MLS group state for a conversation. */
25
+ saveGroupState(conversationId: string, state: Uint8Array): Promise<void>;
26
+ /** Remove persisted group state for a conversation. */
27
+ deleteGroupState(conversationId: string): Promise<void>;
28
+ /** List the conversation ids that have persisted group state. */
29
+ listGroupConversationIds(): Promise<string[]>;
30
+ /** Load the persisted handshake delivery cursor (`seq`), or `null`. */
31
+ loadHandshakeCursor(): Promise<string | null>;
32
+ /** Persist the handshake delivery cursor (`seq`). */
33
+ saveHandshakeCursor(seq: string): Promise<void>;
34
+ /** Wipe all persisted secure-chat state (sign-out / device revoke). */
35
+ clearAll(): Promise<void>;
36
+ }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ // SecureChatRepository — typed façade over a SecureChatStore.
3
+ //
4
+ // The ONLY place in the SDK that knows the persistence key strings and how each record is
5
+ // serialized. Binary fields are base64-wrapped inside JSON; opaque crypto blobs (group/device
6
+ // state) are stored as-is. Built by SecureChatProvider over the injected store.
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.SecureChatRepository = void 0;
9
+ const base64_js_1 = require("../util/base64.js");
10
+ const DEVICE_KEY = "device";
11
+ const GROUP_PREFIX = "group:";
12
+ const CURSOR_KEY = "handshake:cursor";
13
+ /** Typed persistence for device identity, per-conversation group state, and the handshake cursor. */
14
+ class SecureChatRepository {
15
+ constructor(store) {
16
+ this.store = store;
17
+ }
18
+ /** Load the persisted device record, or `null` if none saved (first run / evicted). */
19
+ async loadDevice() {
20
+ const bytes = await this.store.get(DEVICE_KEY);
21
+ if (!bytes)
22
+ return null;
23
+ const rec = JSON.parse((0, base64_js_1.bytesToUtf8)(bytes));
24
+ return { deviceId: rec.deviceId, deviceState: (0, base64_js_1.fromBase64)(rec.deviceState), device: rec.device };
25
+ }
26
+ /** Persist (replace) the device record. */
27
+ async saveDevice(d) {
28
+ const rec = {
29
+ deviceId: d.deviceId,
30
+ deviceState: (0, base64_js_1.toBase64)(d.deviceState),
31
+ device: d.device,
32
+ };
33
+ await this.store.set(DEVICE_KEY, (0, base64_js_1.utf8ToBytes)(JSON.stringify(rec)));
34
+ }
35
+ /** Remove the persisted device record. */
36
+ async clearDevice() {
37
+ await this.store.delete(DEVICE_KEY);
38
+ }
39
+ /** Load opaque MLS group state for a conversation, or `null` if none. */
40
+ async loadGroupState(conversationId) {
41
+ return this.store.get(GROUP_PREFIX + conversationId);
42
+ }
43
+ /** Persist opaque MLS group state for a conversation. */
44
+ async saveGroupState(conversationId, state) {
45
+ await this.store.set(GROUP_PREFIX + conversationId, state);
46
+ }
47
+ /** Remove persisted group state for a conversation. */
48
+ async deleteGroupState(conversationId) {
49
+ await this.store.delete(GROUP_PREFIX + conversationId);
50
+ }
51
+ /** List the conversation ids that have persisted group state. */
52
+ async listGroupConversationIds() {
53
+ const keys = await this.store.list(GROUP_PREFIX);
54
+ return keys.map((k) => k.slice(GROUP_PREFIX.length));
55
+ }
56
+ /** Load the persisted handshake delivery cursor (`seq`), or `null`. */
57
+ async loadHandshakeCursor() {
58
+ const bytes = await this.store.get(CURSOR_KEY);
59
+ return bytes ? (0, base64_js_1.bytesToUtf8)(bytes) : null;
60
+ }
61
+ /** Persist the handshake delivery cursor (`seq`). */
62
+ async saveHandshakeCursor(seq) {
63
+ await this.store.set(CURSOR_KEY, (0, base64_js_1.utf8ToBytes)(seq));
64
+ }
65
+ /** Wipe all persisted secure-chat state (sign-out / device revoke). */
66
+ async clearAll() {
67
+ const keys = await this.store.list("");
68
+ await Promise.all(keys.map((k) => this.store.delete(k)));
69
+ }
70
+ }
71
+ exports.SecureChatRepository = SecureChatRepository;
72
+ //# sourceMappingURL=repository.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.js","sourceRoot":"","sources":["../../../src/persistence/repository.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /** A platform-agnostic async key→blob store. Implementations: `MemoryStore`, `createIndexedDBStore`. */
2
+ export interface SecureChatStore {
3
+ /** Read the bytes at `key`, or `null` if absent. */
4
+ get(key: string): Promise<Uint8Array | null>;
5
+ /** Write `value` at `key`, overwriting any existing value. */
6
+ set(key: string, value: Uint8Array): Promise<void>;
7
+ /** Remove `key` if present (no-op when absent). */
8
+ delete(key: string): Promise<void>;
9
+ /** Return all keys that start with `prefix` (use `""` for every key). */
10
+ list(prefix: string): Promise<string[]>;
11
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ // The persistence seam — a dumb, async key→blob store.
3
+ //
4
+ // This is ALL a platform must implement: web ships an IndexedDB-backed store, native swaps a
5
+ // keystore later. The SDK owns the key schema and (de)serialization on top of this (see
6
+ // ./repository.ts); the store itself never interprets keys or values. Values are opaque bytes.
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/persistence/store.ts"],"names":[],"mappings":";AAAA,uDAAuD;AACvD,EAAE;AACF,6FAA6F;AAC7F,wFAAwF;AACxF,+FAA+F"}
@@ -1,4 +1,4 @@
1
- import { AddSecureMemberBody, CreateSecureConversationBody, PublishKeyPackagesBody, RegisterDeviceBody, RemoveSecureMemberBody, SecureConversationMemberModel, SecureConversationModel, SecureDeviceModel, SecureHandshakeModel, SecureKeyBackupModel, SecureKeyPackageClaim, SecureMessageModel, SendSecureMessageBody, UploadKeyBackupBody } from "../contract";
1
+ import { AddSecureMemberBody, CreateSecureConversationBody, PublishKeyPackagesBody, RegisterDeviceBody, RemoveSecureMemberBody, SecureConversationMemberModel, SecureConversationModel, SecureDeviceModel, SecureHandshakeModel, SecureKeyBackupModel, SecureKeyPackageClaim, SecureMessageModel, SendSecureMessageBody, UploadKeyBackupBody } from "../contract/index.js";
2
2
  /**
3
3
  * Configuration for {@link SecureChatRestClient}. The base URL and access token are read through
4
4
  * resolver callbacks rather than captured once, so a late-set `baseUrl` or a refreshed token take
@@ -1,5 +1,5 @@
1
1
  import { Socket } from "socket.io-client";
2
- import { SecureHandshakeModel, SecureMessageModel } from "../contract";
2
+ import { SecureHandshakeModel, SecureMessageModel } from "../contract/index.js";
3
3
  /** Server → client events on the `/secure` namespace (§10). */
4
4
  export interface SecureServerEvents {
5
5
  "secure:message": (message: SecureMessageModel) => void;
@@ -1,18 +1,36 @@
1
1
  import React from "react";
2
- import { SecureChatCrypto } from "@agora-sdk/secure-chat-crypto";
3
- import { SecureChatRestClient } from "../transport/rest";
4
- import { SecureChatSocketClient } from "../transport/socket";
2
+ import { SecureChatCrypto, GroupHandle } from "@agora-sdk/secure-chat-crypto";
3
+ import { SecureChatRestClient } from "../transport/rest.js";
4
+ import { SecureChatSocketClient } from "../transport/socket.js";
5
+ import { SecureChatStore } from "../persistence/store.js";
6
+ import { SecureChatRepository } from "../persistence/repository.js";
5
7
  /**
6
- * The value exposed by {@link useSecureChat}: the shared transport clients, the injected crypto,
7
- * and the active project id. The hooks build everything else on top of these.
8
+ * The value exposed by {@link useSecureChat}: shared transport clients, the injected crypto, the
9
+ * persistence repository, the group-handle resolver, and the active project id.
8
10
  */
9
11
  export interface SecureChatContextValue {
10
12
  /** REST client for the blind Delivery Service endpoints. */
11
13
  rest: SecureChatRestClient;
12
14
  /** Realtime client for the `/secure` socket.io namespace. */
13
15
  socket: SecureChatSocketClient;
14
- /** The injected MLS crypto implementation (mock, or platform ts-mls/native). */
16
+ /** The injected MLS crypto implementation. */
15
17
  crypto: SecureChatCrypto;
18
+ /** Typed persistence over the injected store. */
19
+ repo: SecureChatRepository;
20
+ /** Resolve a conversation's MLS group handle (cache → store → importGroupState), or `null`. */
21
+ resolveGroup: (conversationId: string) => Promise<GroupHandle | null>;
22
+ /** Cache + persist a conversation's group handle (after createGroup / processWelcome). */
23
+ rememberGroup: (conversationId: string, handle: GroupHandle) => Promise<void>;
24
+ /**
25
+ * Current change-version for a conversation's group handle. Bumps every time the handle advances
26
+ * (a join or a processed Commit), so consumers can detect "the group moved" without diffing handles.
27
+ */
28
+ getGroupVersion: (conversationId: string) => number;
29
+ /**
30
+ * Subscribe to group-handle changes across all conversations (fired by {@link rememberGroup}).
31
+ * @returns An unsubscribe function.
32
+ */
33
+ subscribeGroupChange: (listener: () => void) => () => void;
16
34
  /** The Agora project id these clients are scoped to. */
17
35
  projectId: string;
18
36
  }
@@ -22,6 +40,8 @@ export interface SecureChatProviderProps {
22
40
  crypto: SecureChatCrypto;
23
41
  /** Agora project id (path-scoped on every endpoint). */
24
42
  projectId: string;
43
+ /** Persistence store. Defaults to a non-persistent in-memory store when omitted. */
44
+ store?: SecureChatStore;
25
45
  /** Current access token. Re-pass on refresh; read lazily per request. */
26
46
  accessToken?: string;
27
47
  /** Override token resolution (takes precedence over `accessToken`). */
@@ -33,28 +53,24 @@ export interface SecureChatProviderProps {
33
53
  children: React.ReactNode;
34
54
  }
35
55
  /**
36
- * Provides the secure-chat transport + crypto to the `useSecure*` hooks. Render it inside a
37
- * `ReplykeProvider`: by default it inherits the API base URL and socket origin from
38
- * `@agora-sdk/core`'s runtime, and disconnects the socket on unmount.
56
+ * Provides secure-chat transport, crypto, and persistence to the `useSecure*` hooks. Render inside a
57
+ * `ReplykeProvider`; disconnects the socket on unmount.
39
58
  *
40
- * @param props - {@link SecureChatProviderProps} — the injected crypto, project id, token, and
41
- * optional base/socket URL overrides.
59
+ * @param props - {@link SecureChatProviderProps}.
42
60
  * @returns A context provider wrapping `children`.
43
61
  *
44
62
  * @example
45
63
  * ```tsx
46
- * <ReplykeProvider projectId={projectId} baseUrl={baseUrl}>
47
- * <SecureChatProvider crypto={crypto} projectId={projectId} accessToken={token}>
48
- * <Chat />
49
- * </SecureChatProvider>
50
- * </ReplykeProvider>
64
+ * <SecureChatProvider crypto={crypto} projectId={projectId} store={createIndexedDBStore()} accessToken={token}>
65
+ * <Chat />
66
+ * </SecureChatProvider>
51
67
  * ```
52
68
  */
53
- export declare function SecureChatProvider({ crypto, projectId, accessToken, getAccessToken, baseUrl, socketUrl, children, }: SecureChatProviderProps): React.JSX.Element;
69
+ export declare function SecureChatProvider({ crypto, projectId, store, accessToken, getAccessToken, baseUrl, socketUrl, children, }: SecureChatProviderProps): React.JSX.Element;
54
70
  /**
55
71
  * Access the nearest {@link SecureChatContextValue}.
56
72
  *
57
- * @returns The shared rest/socket/crypto/projectId for this provider subtree.
73
+ * @returns The shared rest/socket/crypto/repo/resolveGroup/projectId for this provider subtree.
58
74
  * @throws {Error} When called outside a `<SecureChatProvider>`.
59
75
  */
60
76
  export declare function useSecureChat(): SecureChatContextValue;
@@ -1,36 +1,33 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- // SecureChatProvider — wires the transport + crypto for the secure-chat hooks.
2
+ // SecureChatProvider — wires transport + crypto + persistence for the secure-chat hooks.
3
3
  //
4
4
  // Sits INSIDE a ReplykeProvider: by default it resolves the API base URL and socket origin from
5
- // @agora-sdk/core's runtime singletons (getApiBaseUrl / getSocketUrl), so whatever `baseUrl` the
6
- // app set on ReplykeProvider is honored here too. Crypto is injected (a `SecureChatCrypto`), keeping
7
- // core platform- and library-agnostic the web/native packages supply the concrete MLS impl.
8
- import { createContext, useContext, useEffect, useMemo, useRef } from "react";
5
+ // @agora-sdk/core's runtime singletons (getApiBaseUrl / getSocketUrl). Crypto AND the persistence
6
+ // store are injected, keeping core platform- and library-agnostic. The provider builds a typed
7
+ // SecureChatRepository over the store plus a cached resolveGroup/rememberGroup so the hooks become
8
+ // self-sufficient (no need to thread a GroupHandle in by hand).
9
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef } from "react";
9
10
  import { getApiBaseUrl, getSocketUrl } from "@agora-sdk/core";
10
- import { SecureChatRestClient } from "../transport/rest";
11
- import { SecureChatSocketClient } from "../transport/socket";
11
+ import { SecureChatRestClient } from "../transport/rest.js";
12
+ import { SecureChatSocketClient } from "../transport/socket.js";
13
+ import { MemoryStore } from "../persistence/memory-store.js";
14
+ import { SecureChatRepository } from "../persistence/repository.js";
12
15
  const SecureChatContext = createContext(null);
13
16
  /**
14
- * Provides the secure-chat transport + crypto to the `useSecure*` hooks. Render it inside a
15
- * `ReplykeProvider`: by default it inherits the API base URL and socket origin from
16
- * `@agora-sdk/core`'s runtime, and disconnects the socket on unmount.
17
+ * Provides secure-chat transport, crypto, and persistence to the `useSecure*` hooks. Render inside a
18
+ * `ReplykeProvider`; disconnects the socket on unmount.
17
19
  *
18
- * @param props - {@link SecureChatProviderProps} — the injected crypto, project id, token, and
19
- * optional base/socket URL overrides.
20
+ * @param props - {@link SecureChatProviderProps}.
20
21
  * @returns A context provider wrapping `children`.
21
22
  *
22
23
  * @example
23
24
  * ```tsx
24
- * <ReplykeProvider projectId={projectId} baseUrl={baseUrl}>
25
- * <SecureChatProvider crypto={crypto} projectId={projectId} accessToken={token}>
26
- * <Chat />
27
- * </SecureChatProvider>
28
- * </ReplykeProvider>
25
+ * <SecureChatProvider crypto={crypto} projectId={projectId} store={createIndexedDBStore()} accessToken={token}>
26
+ * <Chat />
27
+ * </SecureChatProvider>
29
28
  * ```
30
29
  */
31
- export function SecureChatProvider({ crypto, projectId, accessToken, getAccessToken, baseUrl, socketUrl, children, }) {
32
- // Keep the latest token in a ref so the per-request resolver always returns the current value
33
- // without rebuilding the transport clients on every token change.
30
+ export function SecureChatProvider({ crypto, projectId, store, accessToken, getAccessToken, baseUrl, socketUrl, children, }) {
34
31
  const tokenRef = useRef(accessToken);
35
32
  tokenRef.current = accessToken;
36
33
  const resolveToken = useMemo(() => getAccessToken ?? (() => tokenRef.current), [getAccessToken]);
@@ -44,16 +41,74 @@ export function SecureChatProvider({ crypto, projectId, accessToken, getAccessTo
44
41
  getAccessToken: resolveToken,
45
42
  getSocketUrl: () => socketUrl ?? getSocketUrl(),
46
43
  }), [projectId, resolveToken, socketUrl]);
44
+ const resolvedStore = useMemo(() => store ?? new MemoryStore(), [store]);
45
+ const repo = useMemo(() => new SecureChatRepository(resolvedStore), [resolvedStore]);
46
+ // In-memory GroupHandle cache, keyed by conversationId. Survives re-renders via the ref.
47
+ // NOTE: not cleared on a `store` prop swap — a store change in practice means a new provider
48
+ // instance (fresh cache), not a live prop change on the same mounted provider.
49
+ const groupCache = useRef(new Map());
50
+ // Per-conversation change counter, bumped whenever a group handle advances (a join or a processed
51
+ // Commit). Lets useSecureMessages re-resolve and flush buffered (undecrypted) rows without a
52
+ // re-fetch. Held in a ref + listener set so a bump notifies consumers WITHOUT re-rendering the
53
+ // provider (and thus rebuilding rest/socket/repo).
54
+ const groupVersion = useRef(new Map());
55
+ const groupListeners = useRef(new Set());
56
+ const resolveGroup = useCallback(async (conversationId) => {
57
+ const cached = groupCache.current.get(conversationId);
58
+ if (cached)
59
+ return cached;
60
+ const bytes = await repo.loadGroupState(conversationId);
61
+ if (!bytes)
62
+ return null;
63
+ const handle = await crypto.importGroupState(bytes);
64
+ groupCache.current.set(conversationId, handle);
65
+ return handle;
66
+ }, [repo, crypto]);
67
+ const rememberGroup = useCallback(async (conversationId, handle) => {
68
+ groupCache.current.set(conversationId, handle);
69
+ const bytes = await crypto.exportGroupState(handle);
70
+ await repo.saveGroupState(conversationId, bytes);
71
+ // Signal that this conversation's group advanced, so message hooks re-resolve + flush.
72
+ groupVersion.current.set(conversationId, (groupVersion.current.get(conversationId) ?? 0) + 1);
73
+ groupListeners.current.forEach((l) => l());
74
+ }, [repo, crypto]);
75
+ const getGroupVersion = useCallback((conversationId) => groupVersion.current.get(conversationId) ?? 0, []);
76
+ const subscribeGroupChange = useCallback((listener) => {
77
+ groupListeners.current.add(listener);
78
+ return () => {
79
+ groupListeners.current.delete(listener);
80
+ };
81
+ }, []);
47
82
  useEffect(() => {
48
83
  return () => socket.disconnect();
49
84
  }, [socket]);
50
- const value = useMemo(() => ({ rest, socket, crypto, projectId }), [rest, socket, crypto, projectId]);
85
+ const value = useMemo(() => ({
86
+ rest,
87
+ socket,
88
+ crypto,
89
+ repo,
90
+ resolveGroup,
91
+ rememberGroup,
92
+ getGroupVersion,
93
+ subscribeGroupChange,
94
+ projectId,
95
+ }), [
96
+ rest,
97
+ socket,
98
+ crypto,
99
+ repo,
100
+ resolveGroup,
101
+ rememberGroup,
102
+ getGroupVersion,
103
+ subscribeGroupChange,
104
+ projectId,
105
+ ]);
51
106
  return _jsx(SecureChatContext.Provider, { value: value, children: children });
52
107
  }
53
108
  /**
54
109
  * Access the nearest {@link SecureChatContextValue}.
55
110
  *
56
- * @returns The shared rest/socket/crypto/projectId for this provider subtree.
111
+ * @returns The shared rest/socket/crypto/repo/resolveGroup/projectId for this provider subtree.
57
112
  * @throws {Error} When called outside a `<SecureChatProvider>`.
58
113
  */
59
114
  export function useSecureChat() {
@@ -1 +1 @@
1
- {"version":3,"file":"secure-chat-context.js","sourceRoot":"","sources":["../../../src/context/secure-chat-context.tsx"],"names":[],"mappings":";AAAA,+EAA+E;AAC/E,EAAE;AACF,gGAAgG;AAChG,iGAAiG;AACjG,qGAAqG;AACrG,8FAA8F;AAE9F,OAAc,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAiB7D,MAAM,iBAAiB,GAAG,aAAa,CAAgC,IAAI,CAAC,CAAC;AAmB7E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,MAAM,EACN,SAAS,EACT,WAAW,EACX,cAAc,EACd,OAAO,EACP,SAAS,EACT,QAAQ,GACgB;IACxB,8FAA8F;IAC9F,kEAAkE;IAClE,MAAM,QAAQ,GAAG,MAAM,CAAqB,WAAW,CAAC,CAAC;IACzD,QAAQ,CAAC,OAAO,GAAG,WAAW,CAAC;IAE/B,MAAM,YAAY,GAAG,OAAO,CAC1B,GAAG,EAAE,CAAC,cAAc,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAChD,CAAC,cAAc,CAAC,CACjB,CAAC;IAEF,MAAM,IAAI,GAAG,OAAO,CAClB,GAAG,EAAE,CACH,IAAI,oBAAoB,CAAC;QACvB,SAAS;QACT,cAAc,EAAE,YAAY;QAC5B,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,IAAI,aAAa,EAAE;KAC7C,CAAC,EACJ,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,CAAC,CACnC,CAAC;IAEF,MAAM,MAAM,GAAG,OAAO,CACpB,GAAG,EAAE,CACH,IAAI,sBAAsB,CAAC;QACzB,SAAS;QACT,cAAc,EAAE,YAAY;QAC5B,YAAY,EAAE,GAAG,EAAE,CAAC,SAAS,IAAI,YAAY,EAAE;KAChD,CAAC,EACJ,CAAC,SAAS,EAAE,YAAY,EAAE,SAAS,CAAC,CACrC,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;IACnC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAC3C,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAClC,CAAC;IAEF,OAAO,KAAC,iBAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAA8B,CAAC;AAC3F,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,GAAG,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC1C,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"secure-chat-context.js","sourceRoot":"","sources":["../../../src/context/secure-chat-context.tsx"],"names":[],"mappings":"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"}
@@ -1,11 +1,11 @@
1
- // Secure-chat wire contract — stand-in for @agora/contract (the Apache-2.0 server contract).
1
+ // Secure-chat wire contract — stand-in for @agora-server/contract (the Apache-2.0 server contract).
2
2
  //
3
3
  // Mirrors the response models + request bodies of agora-server's
4
4
  // `packages/contract/src/secure-chat.ts`. That package is the source of truth (zod + TS); the
5
5
  // client only needs the TypeScript shapes, so this copy is types-only.
6
6
  //
7
7
  // ⚠️ Keep this byte-faithful to the server contract. The arrow is SDK → contract: once
8
- // `@agora/contract` is published, DELETE this file and `import type { ... } from "@agora/contract"`.
8
+ // `@agora-server/contract` is published, DELETE this file and `import type { ... } from "@agora-server/contract"`.
9
9
  // Do NOT publish a separate `@agora-sdk/secure-chat-contract` (that would invert the dependency —
10
10
  // see STATUS.md). Do not let this copy drift in the meantime.
11
11
  //
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/contract/index.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,EAAE;AACF,iEAAiE;AACjE,8FAA8F;AAC9F,uEAAuE;AACvE,EAAE;AACF,uFAAuF;AACvF,qGAAqG;AACrG,kGAAkG;AAClG,8DAA8D;AAC9D,EAAE;AACF,gGAAgG;AAChG,0FAA0F"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/contract/index.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,EAAE;AACF,iEAAiE;AACjE,8FAA8F;AAC9F,uEAAuE;AACvE,EAAE;AACF,uFAAuF;AACvF,mHAAmH;AACnH,kGAAkG;AAClG,8DAA8D;AAC9D,EAAE;AACF,gGAAgG;AAChG,0FAA0F"}
@@ -1,4 +1,4 @@
1
- import { SecureConversationModel } from "../contract";
1
+ import { SecureConversationModel } from "../contract/index.js";
2
2
  /** The state and actions returned by {@link useSecureConversations}. */
3
3
  export interface UseSecureConversationsValues {
4
4
  /** The loaded conversations, newest activity first. */
@@ -4,8 +4,8 @@
4
4
  // POST /conversations with the Welcomes targeted to each peer device. The MLS group secrets stay on
5
5
  // the client; the server only stores ciphertext metadata.
6
6
  import { useCallback, useEffect, useState } from "react";
7
- import { toBase64, fromBase64 } from "../util/base64";
8
- import { useSecureChat } from "../context/secure-chat-context";
7
+ import { toBase64, fromBase64 } from "../util/base64.js";
8
+ import { useSecureChat } from "../context/secure-chat-context.js";
9
9
  /**
10
10
  * List the caller's secure conversations and start new direct messages.
11
11
  *
@@ -23,7 +23,7 @@ import { useSecureChat } from "../context/secure-chat-context";
23
23
  * ```
24
24
  */
25
25
  export function useSecureConversations() {
26
- const { rest, crypto, socket } = useSecureChat();
26
+ const { rest, crypto, socket, rememberGroup } = useSecureChat();
27
27
  const [conversations, setConversations] = useState([]);
28
28
  const [cursor, setCursor] = useState(undefined);
29
29
  const [hasMore, setHasMore] = useState(true);
@@ -81,9 +81,11 @@ export function useSecureConversations() {
81
81
  epoch: group.epoch.toString(),
82
82
  })),
83
83
  });
84
+ // Persist + cache the creator's MLS group handle so messages resolve after a reload.
85
+ await rememberGroup(conversation.id, group);
84
86
  setConversations((prev) => [conversation, ...prev.filter((c) => c.id !== conversation.id)]);
85
87
  return conversation;
86
- }, [rest, crypto]);
88
+ }, [rest, crypto, rememberGroup]);
87
89
  useEffect(() => {
88
90
  refresh();
89
91
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -1 +1 @@
1
- {"version":3,"file":"useSecureConversations.js","sourceRoot":"","sources":["../../../src/hooks/useSecureConversations.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useSecureConversations.js","sourceRoot":"","sources":["../../../src/hooks/useSecureConversations.tsx"],"names":[],"mappings":"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"}