@quilibrium/quorum-shared 2.1.0-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 (51) hide show
  1. package/dist/index.d.mts +2414 -0
  2. package/dist/index.d.ts +2414 -0
  3. package/dist/index.js +2788 -0
  4. package/dist/index.mjs +2678 -0
  5. package/package.json +49 -0
  6. package/src/api/client.ts +86 -0
  7. package/src/api/endpoints.ts +87 -0
  8. package/src/api/errors.ts +179 -0
  9. package/src/api/index.ts +35 -0
  10. package/src/crypto/encryption-state.ts +249 -0
  11. package/src/crypto/index.ts +55 -0
  12. package/src/crypto/types.ts +307 -0
  13. package/src/crypto/wasm-provider.ts +298 -0
  14. package/src/hooks/index.ts +31 -0
  15. package/src/hooks/keys.ts +62 -0
  16. package/src/hooks/mutations/index.ts +15 -0
  17. package/src/hooks/mutations/useDeleteMessage.ts +67 -0
  18. package/src/hooks/mutations/useEditMessage.ts +87 -0
  19. package/src/hooks/mutations/useReaction.ts +163 -0
  20. package/src/hooks/mutations/useSendMessage.ts +131 -0
  21. package/src/hooks/useChannels.ts +49 -0
  22. package/src/hooks/useMessages.ts +77 -0
  23. package/src/hooks/useSpaces.ts +60 -0
  24. package/src/index.ts +32 -0
  25. package/src/signing/index.ts +10 -0
  26. package/src/signing/types.ts +83 -0
  27. package/src/signing/wasm-provider.ts +75 -0
  28. package/src/storage/adapter.ts +118 -0
  29. package/src/storage/index.ts +9 -0
  30. package/src/sync/index.ts +83 -0
  31. package/src/sync/service.test.ts +822 -0
  32. package/src/sync/service.ts +947 -0
  33. package/src/sync/types.ts +267 -0
  34. package/src/sync/utils.ts +588 -0
  35. package/src/transport/browser-websocket.ts +299 -0
  36. package/src/transport/index.ts +34 -0
  37. package/src/transport/rn-websocket.ts +321 -0
  38. package/src/transport/types.ts +56 -0
  39. package/src/transport/websocket.ts +212 -0
  40. package/src/types/bookmark.ts +29 -0
  41. package/src/types/conversation.ts +25 -0
  42. package/src/types/index.ts +57 -0
  43. package/src/types/message.ts +178 -0
  44. package/src/types/space.ts +75 -0
  45. package/src/types/user.ts +72 -0
  46. package/src/utils/encoding.ts +106 -0
  47. package/src/utils/formatting.ts +139 -0
  48. package/src/utils/index.ts +9 -0
  49. package/src/utils/logger.ts +141 -0
  50. package/src/utils/mentions.ts +135 -0
  51. package/src/utils/validation.ts +84 -0
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Crypto module exports
3
+ */
4
+
5
+ export type {
6
+ // Key types
7
+ Ed448Keypair,
8
+ X448Keypair,
9
+ Keypair,
10
+ // Message types
11
+ MessageCiphertext,
12
+ P2PChannelEnvelope,
13
+ // X3DH
14
+ SenderX3DHParams,
15
+ ReceiverX3DHParams,
16
+ // Double ratchet
17
+ NewDoubleRatchetParams,
18
+ DoubleRatchetStateAndMessage,
19
+ DoubleRatchetStateAndEnvelope,
20
+ // Triple ratchet
21
+ PeerInfo,
22
+ NewTripleRatchetParams,
23
+ TripleRatchetStateAndMetadata,
24
+ TripleRatchetStateAndMessage,
25
+ TripleRatchetStateAndEnvelope,
26
+ // Initialization envelope
27
+ InitializationEnvelope,
28
+ // Inbox encryption
29
+ InboxMessageEncryptRequest,
30
+ InboxMessageDecryptRequest,
31
+ // Provider interface
32
+ CryptoProvider,
33
+ } from './types';
34
+
35
+ // Encryption state types and storage interface
36
+ export type {
37
+ // Device and recipient types
38
+ DeviceKeys,
39
+ RecipientInfo,
40
+ EncryptedEnvelope,
41
+ // Storage types
42
+ KeyValueStorageProvider,
43
+ SendingInbox,
44
+ ReceivingInbox,
45
+ EncryptionState,
46
+ InboxMapping,
47
+ LatestState,
48
+ ConversationInboxKeypair,
49
+ EncryptionStateStorageInterface,
50
+ } from './encryption-state';
51
+ export { ENCRYPTION_STORAGE_KEYS } from './encryption-state';
52
+
53
+ // WASM implementation (for desktop/web)
54
+ export { WasmCryptoProvider } from './wasm-provider';
55
+ export type { ChannelWasmModule } from './wasm-provider';
@@ -0,0 +1,307 @@
1
+ /**
2
+ * Crypto types and CryptoProvider interface
3
+ *
4
+ * Platform-agnostic cryptographic operations for E2E encryption.
5
+ * Implementations:
6
+ * - WASM (desktop/web): Uses channel-wasm bindings
7
+ * - Native (iOS/Android): Uses uniffi-generated bindings
8
+ */
9
+
10
+ // ============ Key Types ============
11
+
12
+ export interface Ed448Keypair {
13
+ type: 'ed448';
14
+ public_key: number[];
15
+ private_key: number[];
16
+ }
17
+
18
+ export interface X448Keypair {
19
+ type: 'x448';
20
+ public_key: number[];
21
+ private_key: number[];
22
+ }
23
+
24
+ export type Keypair = Ed448Keypair | X448Keypair;
25
+
26
+ // ============ Message Ciphertext ============
27
+
28
+ export interface MessageCiphertext {
29
+ ciphertext: string;
30
+ initialization_vector: string;
31
+ associated_data?: string;
32
+ }
33
+
34
+ export interface P2PChannelEnvelope {
35
+ protocol_identifier: number;
36
+ message_header: MessageCiphertext;
37
+ message_body: MessageCiphertext;
38
+ }
39
+
40
+ // ============ X3DH Key Agreement ============
41
+
42
+ export interface SenderX3DHParams {
43
+ sending_identity_private_key: number[];
44
+ sending_ephemeral_private_key: number[];
45
+ receiving_identity_key: number[];
46
+ receiving_signed_pre_key: number[];
47
+ session_key_length: number;
48
+ }
49
+
50
+ export interface ReceiverX3DHParams {
51
+ sending_identity_private_key: number[];
52
+ sending_signed_private_key: number[];
53
+ receiving_identity_key: number[];
54
+ receiving_ephemeral_key: number[];
55
+ session_key_length: number;
56
+ }
57
+
58
+ // ============ Double Ratchet ============
59
+
60
+ export interface NewDoubleRatchetParams {
61
+ session_key: number[];
62
+ sending_header_key: number[];
63
+ next_receiving_header_key: number[];
64
+ is_sender: boolean;
65
+ sending_ephemeral_private_key: number[];
66
+ receiving_ephemeral_key: number[];
67
+ }
68
+
69
+ export interface DoubleRatchetStateAndMessage {
70
+ ratchet_state: string;
71
+ message: number[];
72
+ }
73
+
74
+ export interface DoubleRatchetStateAndEnvelope {
75
+ ratchet_state: string;
76
+ envelope: string;
77
+ }
78
+
79
+ // ============ Triple Ratchet ============
80
+
81
+ export interface PeerInfo {
82
+ public_key: number[];
83
+ identity_public_key: number[];
84
+ signed_pre_public_key: number[];
85
+ }
86
+
87
+ export interface NewTripleRatchetParams {
88
+ peers: number[][];
89
+ peer_key: number[];
90
+ identity_key: number[];
91
+ signed_pre_key: number[];
92
+ threshold: number;
93
+ async_dkg_ratchet: boolean;
94
+ }
95
+
96
+ export interface TripleRatchetStateAndMetadata {
97
+ ratchet_state: string;
98
+ metadata: Record<string, string>;
99
+ }
100
+
101
+ export interface TripleRatchetStateAndMessage {
102
+ ratchet_state: string;
103
+ message: number[];
104
+ }
105
+
106
+ export interface TripleRatchetStateAndEnvelope {
107
+ ratchet_state: string;
108
+ envelope: string;
109
+ }
110
+
111
+ // ============ Initialization Envelope ============
112
+
113
+ /**
114
+ * InitializationEnvelope - Contains sender info for first message in a session
115
+ *
116
+ * This is the format BEFORE sealing. The ephemeral_public_key is NOT included here -
117
+ * it goes at the TOP LEVEL of the SealedMessage, and the SAME ephemeral key is used for both:
118
+ * 1. Sealing the envelope (inbox encryption)
119
+ * 2. X3DH session establishment
120
+ *
121
+ * After unsealing, the ephemeral_public_key is added back to create UnsealedEnvelope
122
+ * (see transport/websocket.ts)
123
+ */
124
+ export interface InitializationEnvelope {
125
+ /** Sender's user address */
126
+ user_address: string;
127
+ /** Sender's display name */
128
+ display_name?: string;
129
+ /** Sender's icon URL */
130
+ user_icon?: string;
131
+ /** Inbox address for sending replies */
132
+ return_inbox_address: string;
133
+ /** X448 encryption key for the return inbox (hex) */
134
+ return_inbox_encryption_key: string;
135
+ /** Ed448 public key for the return inbox (hex) */
136
+ return_inbox_public_key: string;
137
+ /** Ed448 private key for the return inbox (hex) - shared so recipient can sign replies */
138
+ return_inbox_private_key: string;
139
+ /** Sender's identity public key for X3DH (hex) */
140
+ identity_public_key: string;
141
+ /** Session/conversation tag (typically the return inbox address) */
142
+ tag: string;
143
+ /** The Double Ratchet encrypted message envelope */
144
+ message: string;
145
+ /** Message type (e.g., 'direct') */
146
+ type: string;
147
+ }
148
+
149
+ // ============ Inbox Message Encryption ============
150
+
151
+ export interface InboxMessageEncryptRequest {
152
+ inbox_public_key: number[];
153
+ ephemeral_private_key: number[];
154
+ plaintext: number[];
155
+ }
156
+
157
+ export interface InboxMessageDecryptRequest {
158
+ inbox_private_key: number[];
159
+ ephemeral_public_key: number[];
160
+ ciphertext: MessageCiphertext;
161
+ }
162
+
163
+ // ============ CryptoProvider Interface ============
164
+
165
+ /**
166
+ * CryptoProvider - Platform-agnostic interface for cryptographic operations
167
+ *
168
+ * This interface abstracts the underlying crypto implementation,
169
+ * allowing the same code to work with WASM (desktop) or native modules (mobile).
170
+ *
171
+ * All methods are async to support both synchronous WASM and async native bridges.
172
+ * State is serialized as JSON strings for cross-platform compatibility.
173
+ */
174
+ export interface CryptoProvider {
175
+ // ============ Key Generation ============
176
+
177
+ /**
178
+ * Generate an X448 keypair for encryption
179
+ */
180
+ generateX448(): Promise<X448Keypair>;
181
+
182
+ /**
183
+ * Generate an Ed448 keypair for signing
184
+ */
185
+ generateEd448(): Promise<Ed448Keypair>;
186
+
187
+ /**
188
+ * Derive public key from X448 private key
189
+ * @param privateKey Base64-encoded private key
190
+ * @returns Base64-encoded public key
191
+ */
192
+ getPublicKeyX448(privateKey: string): Promise<string>;
193
+
194
+ /**
195
+ * Derive public key from Ed448 private key
196
+ * @param privateKey Base64-encoded private key
197
+ * @returns Base64-encoded public key
198
+ */
199
+ getPublicKeyEd448(privateKey: string): Promise<string>;
200
+
201
+ // ============ X3DH Key Agreement ============
202
+
203
+ /**
204
+ * Perform sender-side X3DH key agreement
205
+ * @returns Base64-encoded session key (96 bytes: 32 session + 32 sending header + 32 receiving header)
206
+ */
207
+ senderX3DH(params: SenderX3DHParams): Promise<string>;
208
+
209
+ /**
210
+ * Perform receiver-side X3DH key agreement
211
+ * @returns Base64-encoded session key (96 bytes)
212
+ */
213
+ receiverX3DH(params: ReceiverX3DHParams): Promise<string>;
214
+
215
+ // ============ Double Ratchet ============
216
+
217
+ /**
218
+ * Initialize a new double ratchet session
219
+ * @returns JSON-serialized ratchet state
220
+ */
221
+ newDoubleRatchet(params: NewDoubleRatchetParams): Promise<string>;
222
+
223
+ /**
224
+ * Encrypt a message using double ratchet
225
+ * @returns Updated state and encrypted envelope
226
+ */
227
+ doubleRatchetEncrypt(
228
+ stateAndMessage: DoubleRatchetStateAndMessage
229
+ ): Promise<DoubleRatchetStateAndEnvelope>;
230
+
231
+ /**
232
+ * Decrypt a message using double ratchet
233
+ * @returns Updated state and decrypted message
234
+ */
235
+ doubleRatchetDecrypt(
236
+ stateAndEnvelope: DoubleRatchetStateAndEnvelope
237
+ ): Promise<DoubleRatchetStateAndMessage>;
238
+
239
+ // ============ Triple Ratchet ============
240
+
241
+ /**
242
+ * Initialize a new triple ratchet session for group messaging
243
+ * @returns Initial state and DKG metadata
244
+ */
245
+ newTripleRatchet(params: NewTripleRatchetParams): Promise<TripleRatchetStateAndMetadata>;
246
+
247
+ /**
248
+ * Triple ratchet DKG round 1 - Generate polynomial fragments
249
+ */
250
+ tripleRatchetInitRound1(
251
+ state: TripleRatchetStateAndMetadata
252
+ ): Promise<TripleRatchetStateAndMetadata>;
253
+
254
+ /**
255
+ * Triple ratchet DKG round 2 - Receive fragments, compute ZK commitment
256
+ */
257
+ tripleRatchetInitRound2(
258
+ state: TripleRatchetStateAndMetadata
259
+ ): Promise<TripleRatchetStateAndMetadata>;
260
+
261
+ /**
262
+ * Triple ratchet DKG round 3 - Receive commitments, compute ZK reveal
263
+ */
264
+ tripleRatchetInitRound3(
265
+ state: TripleRatchetStateAndMetadata
266
+ ): Promise<TripleRatchetStateAndMetadata>;
267
+
268
+ /**
269
+ * Triple ratchet DKG round 4 - Verify proofs, reconstruct group key
270
+ */
271
+ tripleRatchetInitRound4(
272
+ state: TripleRatchetStateAndMetadata
273
+ ): Promise<TripleRatchetStateAndMetadata>;
274
+
275
+ /**
276
+ * Encrypt a message for the group using triple ratchet
277
+ */
278
+ tripleRatchetEncrypt(
279
+ stateAndMessage: TripleRatchetStateAndMessage
280
+ ): Promise<TripleRatchetStateAndEnvelope>;
281
+
282
+ /**
283
+ * Decrypt a group message using triple ratchet
284
+ */
285
+ tripleRatchetDecrypt(
286
+ stateAndEnvelope: TripleRatchetStateAndEnvelope
287
+ ): Promise<TripleRatchetStateAndMessage>;
288
+
289
+ /**
290
+ * Handle group membership changes
291
+ */
292
+ tripleRatchetResize(state: TripleRatchetStateAndMetadata): Promise<TripleRatchetStateAndMetadata>;
293
+
294
+ // ============ Inbox Message Encryption ============
295
+
296
+ /**
297
+ * Encrypt a message for an inbox (sealed sender / ECIES-style)
298
+ * @returns Base64-encoded sealed message
299
+ */
300
+ encryptInboxMessage(request: InboxMessageEncryptRequest): Promise<string>;
301
+
302
+ /**
303
+ * Decrypt a sealed inbox message
304
+ * @returns Decrypted plaintext as byte array
305
+ */
306
+ decryptInboxMessage(request: InboxMessageDecryptRequest): Promise<number[]>;
307
+ }
@@ -0,0 +1,298 @@
1
+ /**
2
+ * WASM CryptoProvider implementation
3
+ *
4
+ * Wraps the channel-wasm WASM module to implement the CryptoProvider interface.
5
+ * Used by desktop/web applications.
6
+ *
7
+ * Note: This file imports from the WASM module dynamically to avoid bundling
8
+ * issues in environments that don't support WASM.
9
+ */
10
+
11
+ import type {
12
+ CryptoProvider,
13
+ Ed448Keypair,
14
+ X448Keypair,
15
+ SenderX3DHParams,
16
+ ReceiverX3DHParams,
17
+ NewDoubleRatchetParams,
18
+ DoubleRatchetStateAndMessage,
19
+ DoubleRatchetStateAndEnvelope,
20
+ NewTripleRatchetParams,
21
+ TripleRatchetStateAndMetadata,
22
+ TripleRatchetStateAndMessage,
23
+ TripleRatchetStateAndEnvelope,
24
+ InboxMessageEncryptRequest,
25
+ InboxMessageDecryptRequest,
26
+ } from './types';
27
+
28
+ /**
29
+ * Interface for the WASM module functions
30
+ * This matches the exports from channel-wasm
31
+ */
32
+ export interface ChannelWasmModule {
33
+ js_generate_x448(): string;
34
+ js_generate_ed448(): string;
35
+ js_get_pubkey_x448(key: string): string;
36
+ js_get_pubkey_ed448(key: string): string;
37
+ js_sign_ed448(key: string, message: string): string;
38
+ js_verify_ed448(publicKey: string, message: string, signature: string): string;
39
+ js_sender_x3dh(input: string): string;
40
+ js_receiver_x3dh(input: string): string;
41
+ js_new_double_ratchet(params: string): string;
42
+ js_double_ratchet_encrypt(params: string): string;
43
+ js_double_ratchet_decrypt(params: string): string;
44
+ js_new_triple_ratchet(params: string): string;
45
+ js_triple_ratchet_init_round_1(params: string): string;
46
+ js_triple_ratchet_init_round_2(params: string): string;
47
+ js_triple_ratchet_init_round_3(params: string): string;
48
+ js_triple_ratchet_init_round_4(params: string): string;
49
+ js_triple_ratchet_encrypt(params: string): string;
50
+ js_triple_ratchet_decrypt(params: string): string;
51
+ js_triple_ratchet_resize(params: string): string;
52
+ js_encrypt_inbox_message(input: string): string;
53
+ js_decrypt_inbox_message(input: string): string;
54
+ }
55
+
56
+ /**
57
+ * Parse WASM result and check for errors
58
+ * WASM functions return error strings on failure
59
+ */
60
+ function parseWasmResult<T>(result: string): T {
61
+ // Check for common error patterns
62
+ if (
63
+ result.startsWith('invalid') ||
64
+ result.startsWith('error') ||
65
+ result.includes('failed') ||
66
+ result.includes('Error')
67
+ ) {
68
+ throw new Error(result);
69
+ }
70
+
71
+ try {
72
+ return JSON.parse(result) as T;
73
+ } catch {
74
+ // If it's not JSON, it might be a quoted string or error
75
+ if (result.startsWith('"') && result.endsWith('"')) {
76
+ // Remove quotes from string results
77
+ return result.slice(1, -1) as unknown as T;
78
+ }
79
+ throw new Error(`Failed to parse WASM result: ${result}`);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * WasmCryptoProvider - Implements CryptoProvider using channel-wasm
85
+ */
86
+ export class WasmCryptoProvider implements CryptoProvider {
87
+ private wasm: ChannelWasmModule;
88
+
89
+ constructor(wasmModule: ChannelWasmModule) {
90
+ this.wasm = wasmModule;
91
+ }
92
+
93
+ // ============ Key Generation ============
94
+
95
+ async generateX448(): Promise<X448Keypair> {
96
+ const result = this.wasm.js_generate_x448();
97
+ const keypair = parseWasmResult<{ public_key: number[]; private_key: number[] }>(result);
98
+ return {
99
+ type: 'x448',
100
+ public_key: keypair.public_key,
101
+ private_key: keypair.private_key,
102
+ };
103
+ }
104
+
105
+ async generateEd448(): Promise<Ed448Keypair> {
106
+ const result = this.wasm.js_generate_ed448();
107
+ const keypair = parseWasmResult<{ public_key: number[]; private_key: number[] }>(result);
108
+ return {
109
+ type: 'ed448',
110
+ public_key: keypair.public_key,
111
+ private_key: keypair.private_key,
112
+ };
113
+ }
114
+
115
+ async getPublicKeyX448(privateKey: string): Promise<string> {
116
+ const result = this.wasm.js_get_pubkey_x448(privateKey);
117
+ return parseWasmResult<string>(result);
118
+ }
119
+
120
+ async getPublicKeyEd448(privateKey: string): Promise<string> {
121
+ const result = this.wasm.js_get_pubkey_ed448(privateKey);
122
+ return parseWasmResult<string>(result);
123
+ }
124
+
125
+ // ============ X3DH Key Agreement ============
126
+
127
+ async senderX3DH(params: SenderX3DHParams): Promise<string> {
128
+ const input = JSON.stringify({
129
+ sending_identity_private_key: params.sending_identity_private_key,
130
+ sending_ephemeral_private_key: params.sending_ephemeral_private_key,
131
+ receiving_identity_key: params.receiving_identity_key,
132
+ receiving_signed_pre_key: params.receiving_signed_pre_key,
133
+ session_key_length: params.session_key_length,
134
+ });
135
+ const result = this.wasm.js_sender_x3dh(input);
136
+ if (result.startsWith('invalid') || result.includes('error')) {
137
+ throw new Error(result);
138
+ }
139
+ return result;
140
+ }
141
+
142
+ async receiverX3DH(params: ReceiverX3DHParams): Promise<string> {
143
+ const input = JSON.stringify({
144
+ sending_identity_private_key: params.sending_identity_private_key,
145
+ sending_signed_private_key: params.sending_signed_private_key,
146
+ receiving_identity_key: params.receiving_identity_key,
147
+ receiving_ephemeral_key: params.receiving_ephemeral_key,
148
+ session_key_length: params.session_key_length,
149
+ });
150
+ const result = this.wasm.js_receiver_x3dh(input);
151
+ if (result.startsWith('invalid') || result.includes('error')) {
152
+ throw new Error(result);
153
+ }
154
+ return result;
155
+ }
156
+
157
+ // ============ Double Ratchet ============
158
+
159
+ async newDoubleRatchet(params: NewDoubleRatchetParams): Promise<string> {
160
+ const input = JSON.stringify({
161
+ session_key: params.session_key,
162
+ sending_header_key: params.sending_header_key,
163
+ next_receiving_header_key: params.next_receiving_header_key,
164
+ is_sender: params.is_sender,
165
+ sending_ephemeral_private_key: params.sending_ephemeral_private_key,
166
+ receiving_ephemeral_key: params.receiving_ephemeral_key,
167
+ });
168
+ const result = this.wasm.js_new_double_ratchet(input);
169
+ if (result.startsWith('invalid') || result.includes('error')) {
170
+ throw new Error(result);
171
+ }
172
+ return result;
173
+ }
174
+
175
+ async doubleRatchetEncrypt(
176
+ stateAndMessage: DoubleRatchetStateAndMessage
177
+ ): Promise<DoubleRatchetStateAndEnvelope> {
178
+ const input = JSON.stringify({
179
+ ratchet_state: stateAndMessage.ratchet_state,
180
+ message: stateAndMessage.message,
181
+ });
182
+ const result = this.wasm.js_double_ratchet_encrypt(input);
183
+ return parseWasmResult<DoubleRatchetStateAndEnvelope>(result);
184
+ }
185
+
186
+ async doubleRatchetDecrypt(
187
+ stateAndEnvelope: DoubleRatchetStateAndEnvelope
188
+ ): Promise<DoubleRatchetStateAndMessage> {
189
+ const input = JSON.stringify({
190
+ ratchet_state: stateAndEnvelope.ratchet_state,
191
+ envelope: stateAndEnvelope.envelope,
192
+ });
193
+ const result = this.wasm.js_double_ratchet_decrypt(input);
194
+ return parseWasmResult<DoubleRatchetStateAndMessage>(result);
195
+ }
196
+
197
+ // ============ Triple Ratchet ============
198
+
199
+ async newTripleRatchet(params: NewTripleRatchetParams): Promise<TripleRatchetStateAndMetadata> {
200
+ const input = JSON.stringify({
201
+ peers: params.peers,
202
+ peer_key: params.peer_key,
203
+ identity_key: params.identity_key,
204
+ signed_pre_key: params.signed_pre_key,
205
+ threshold: params.threshold,
206
+ async_dkg_ratchet: params.async_dkg_ratchet,
207
+ });
208
+ const result = this.wasm.js_new_triple_ratchet(input);
209
+ return parseWasmResult<TripleRatchetStateAndMetadata>(result);
210
+ }
211
+
212
+ async tripleRatchetInitRound1(
213
+ state: TripleRatchetStateAndMetadata
214
+ ): Promise<TripleRatchetStateAndMetadata> {
215
+ const input = JSON.stringify(state);
216
+ const result = this.wasm.js_triple_ratchet_init_round_1(input);
217
+ return parseWasmResult<TripleRatchetStateAndMetadata>(result);
218
+ }
219
+
220
+ async tripleRatchetInitRound2(
221
+ state: TripleRatchetStateAndMetadata
222
+ ): Promise<TripleRatchetStateAndMetadata> {
223
+ const input = JSON.stringify(state);
224
+ const result = this.wasm.js_triple_ratchet_init_round_2(input);
225
+ return parseWasmResult<TripleRatchetStateAndMetadata>(result);
226
+ }
227
+
228
+ async tripleRatchetInitRound3(
229
+ state: TripleRatchetStateAndMetadata
230
+ ): Promise<TripleRatchetStateAndMetadata> {
231
+ const input = JSON.stringify(state);
232
+ const result = this.wasm.js_triple_ratchet_init_round_3(input);
233
+ return parseWasmResult<TripleRatchetStateAndMetadata>(result);
234
+ }
235
+
236
+ async tripleRatchetInitRound4(
237
+ state: TripleRatchetStateAndMetadata
238
+ ): Promise<TripleRatchetStateAndMetadata> {
239
+ const input = JSON.stringify(state);
240
+ const result = this.wasm.js_triple_ratchet_init_round_4(input);
241
+ return parseWasmResult<TripleRatchetStateAndMetadata>(result);
242
+ }
243
+
244
+ async tripleRatchetEncrypt(
245
+ stateAndMessage: TripleRatchetStateAndMessage
246
+ ): Promise<TripleRatchetStateAndEnvelope> {
247
+ const input = JSON.stringify({
248
+ ratchet_state: stateAndMessage.ratchet_state,
249
+ message: stateAndMessage.message,
250
+ });
251
+ const result = this.wasm.js_triple_ratchet_encrypt(input);
252
+ return parseWasmResult<TripleRatchetStateAndEnvelope>(result);
253
+ }
254
+
255
+ async tripleRatchetDecrypt(
256
+ stateAndEnvelope: TripleRatchetStateAndEnvelope
257
+ ): Promise<TripleRatchetStateAndMessage> {
258
+ const input = JSON.stringify({
259
+ ratchet_state: stateAndEnvelope.ratchet_state,
260
+ envelope: stateAndEnvelope.envelope,
261
+ });
262
+ const result = this.wasm.js_triple_ratchet_decrypt(input);
263
+ return parseWasmResult<TripleRatchetStateAndMessage>(result);
264
+ }
265
+
266
+ async tripleRatchetResize(
267
+ state: TripleRatchetStateAndMetadata
268
+ ): Promise<TripleRatchetStateAndMetadata> {
269
+ const input = JSON.stringify(state);
270
+ const result = this.wasm.js_triple_ratchet_resize(input);
271
+ return parseWasmResult<TripleRatchetStateAndMetadata>(result);
272
+ }
273
+
274
+ // ============ Inbox Message Encryption ============
275
+
276
+ async encryptInboxMessage(request: InboxMessageEncryptRequest): Promise<string> {
277
+ const input = JSON.stringify({
278
+ inbox_public_key: request.inbox_public_key,
279
+ ephemeral_private_key: request.ephemeral_private_key,
280
+ plaintext: request.plaintext,
281
+ });
282
+ const result = this.wasm.js_encrypt_inbox_message(input);
283
+ if (result.startsWith('invalid') || result.includes('error')) {
284
+ throw new Error(result);
285
+ }
286
+ return result;
287
+ }
288
+
289
+ async decryptInboxMessage(request: InboxMessageDecryptRequest): Promise<number[]> {
290
+ const input = JSON.stringify({
291
+ inbox_private_key: request.inbox_private_key,
292
+ ephemeral_public_key: request.ephemeral_public_key,
293
+ ciphertext: request.ciphertext,
294
+ });
295
+ const result = this.wasm.js_decrypt_inbox_message(input);
296
+ return parseWasmResult<number[]>(result);
297
+ }
298
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Shared React Query hooks
3
+ */
4
+
5
+ // Query keys
6
+ export { queryKeys } from './keys';
7
+ export type {
8
+ SpacesKey,
9
+ SpaceDetailKey,
10
+ ChannelsKey,
11
+ MessagesInfiniteKey,
12
+ } from './keys';
13
+
14
+ // Space hooks
15
+ export { useSpaces, useSpace, useSpaceMembers } from './useSpaces';
16
+ export type { UseSpacesOptions, UseSpaceOptions } from './useSpaces';
17
+
18
+ // Channel hooks
19
+ export { useChannels, flattenChannels, findChannel } from './useChannels';
20
+ export type { UseChannelsOptions } from './useChannels';
21
+
22
+ // Message hooks
23
+ export {
24
+ useMessages,
25
+ flattenMessages,
26
+ useInvalidateMessages,
27
+ } from './useMessages';
28
+ export type { UseMessagesOptions } from './useMessages';
29
+
30
+ // Mutations (to be added)
31
+ export * from './mutations';