@xdevplatform/chat-xdk 0.1.0 → 0.2.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.
- package/LICENSE +21 -0
- package/README.md +27 -23
- package/index.d.ts +372 -78
- package/index.js +208 -47
- package/package.json +6 -2
- package/pkg/chat_xdk_wasm.d.ts +124 -44
- package/pkg/chat_xdk_wasm.js +224 -223
- package/pkg/chat_xdk_wasm_bg.wasm +0 -0
- package/pkg/chat_xdk_wasm_bg.wasm.d.ts +15 -9
- package/pkg/package.json +21 -0
package/index.d.ts
CHANGED
|
@@ -10,6 +10,11 @@ export interface PublicKeys {
|
|
|
10
10
|
identity: string;
|
|
11
11
|
/** Base64-encoded signing public key */
|
|
12
12
|
signing: string;
|
|
13
|
+
/**
|
|
14
|
+
* Always the empty string; reserved. The registered key version set via
|
|
15
|
+
* setKeyVersion is tracked internally and not surfaced here.
|
|
16
|
+
*/
|
|
17
|
+
version: string;
|
|
13
18
|
}
|
|
14
19
|
|
|
15
20
|
/**
|
|
@@ -34,7 +39,8 @@ export interface PublicKeyRegistrationPayload {
|
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
/**
|
|
37
|
-
* Result from
|
|
42
|
+
* Result from encryptMessage, encryptReply, encryptAddReaction, and
|
|
43
|
+
* encryptRemoveReaction.
|
|
38
44
|
*/
|
|
39
45
|
export interface SendPayload {
|
|
40
46
|
/** Base64-encoded Thrift MessageCreateEvent. */
|
|
@@ -52,7 +58,7 @@ export interface SendPayload {
|
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
/**
|
|
55
|
-
*
|
|
61
|
+
* An action signature authenticating a conversation key change or member add.
|
|
56
62
|
*/
|
|
57
63
|
export interface ActionSignature {
|
|
58
64
|
messageId: string;
|
|
@@ -60,19 +66,8 @@ export interface ActionSignature {
|
|
|
60
66
|
signature: string;
|
|
61
67
|
signatureVersion: string;
|
|
62
68
|
publicKeyVersion: string;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* A recipient for encryptConversationKeyForRecipients.
|
|
68
|
-
*/
|
|
69
|
-
export interface RecipientInput {
|
|
70
|
-
/** The recipient's user ID (snowflake string). */
|
|
71
|
-
userId: string;
|
|
72
|
-
/** Base64-encoded identity public key (SEC1 or SPKI). */
|
|
73
|
-
publicKey: string;
|
|
74
|
-
/** Key version string from the X API. */
|
|
75
|
-
keyVersion: string;
|
|
69
|
+
/** Omitted for conversation-key changes; the signed payload embeds the plaintext conversation key. */
|
|
70
|
+
signaturePayload?: string;
|
|
76
71
|
}
|
|
77
72
|
|
|
78
73
|
/**
|
|
@@ -124,8 +119,8 @@ export interface DecryptEventsResult {
|
|
|
124
119
|
messages: DecryptedMessage[];
|
|
125
120
|
/** Extracted conversation keys (for caching). */
|
|
126
121
|
conversationKeys: ConversationKeyResult;
|
|
127
|
-
/** Errors encountered during decryption (index → error message). */
|
|
128
|
-
errors: { [index:
|
|
122
|
+
/** Errors encountered during decryption (event index, as a string key → error message). */
|
|
123
|
+
errors: { [index: string]: string };
|
|
129
124
|
}
|
|
130
125
|
|
|
131
126
|
/**
|
|
@@ -137,7 +132,7 @@ export interface ImageDimensions {
|
|
|
137
132
|
}
|
|
138
133
|
|
|
139
134
|
/**
|
|
140
|
-
* Encrypted key for a single
|
|
135
|
+
* Encrypted conversation key for a single participant.
|
|
141
136
|
*/
|
|
142
137
|
export interface EncryptedKeyForRecipient {
|
|
143
138
|
userId: string;
|
|
@@ -146,7 +141,7 @@ export interface EncryptedKeyForRecipient {
|
|
|
146
141
|
}
|
|
147
142
|
|
|
148
143
|
/**
|
|
149
|
-
* A public key input for
|
|
144
|
+
* A public key input for prepareConversationKeyChange / prepareGroupMembersChange.
|
|
150
145
|
*
|
|
151
146
|
* Represents a single public key version for a user, as returned by the
|
|
152
147
|
* X API `GET /2/dm/encryption/public_keys` endpoint.
|
|
@@ -164,26 +159,209 @@ export interface PublicKeyInput {
|
|
|
164
159
|
}
|
|
165
160
|
|
|
166
161
|
/**
|
|
167
|
-
* Result from
|
|
162
|
+
* Result from prepareConversationKeyChange / prepareGroupMembersChange.
|
|
168
163
|
*
|
|
169
|
-
* Contains everything needed to POST to the X API
|
|
170
|
-
*
|
|
164
|
+
* Contains everything needed to POST the change to the X API: the new key
|
|
165
|
+
* (to keep locally), the per-participant encrypted copies, and the action
|
|
166
|
+
* signature that lets recipients verify the change.
|
|
171
167
|
*/
|
|
172
|
-
export interface
|
|
168
|
+
export interface PreparedConversationChange {
|
|
169
|
+
/** Conversation id the change applies to (derived for a one-to-one, or the id you passed). */
|
|
170
|
+
conversationId: string;
|
|
173
171
|
/** Raw conversation key bytes (32 bytes). Store locally for encrypting messages. */
|
|
174
172
|
conversationKey: Uint8Array;
|
|
175
173
|
/** Timestamp-based version string for this conversation key. */
|
|
176
174
|
conversationKeyVersion: string;
|
|
177
175
|
/** Encrypted keys for each participant, ready to POST to the API. */
|
|
178
176
|
participantKeys: EncryptedKeyForRecipient[];
|
|
177
|
+
/** Action signatures authenticating the change, ready to POST to the API. */
|
|
178
|
+
actionSignatures: ActionSignature[];
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
/**
|
|
182
182
|
* Entity descriptor tuple: [startByteOffset, endByteOffset, entityType].
|
|
183
|
-
* entityType is one of: "url", "mention", "hashtag", "cashtag", "email",
|
|
183
|
+
* entityType is one of: "url", "mention", "hashtag", "cashtag", "email",
|
|
184
|
+
* "address", "phoneNumber" (the snake_case spelling "phone_number" is
|
|
185
|
+
* accepted too). Unrecognized entity types are silently dropped — the
|
|
186
|
+
* message encrypts without that entity and no error is raised.
|
|
184
187
|
*/
|
|
185
188
|
export type EntityTuple = [number, number, string];
|
|
186
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Parameters for encryptMessage.
|
|
192
|
+
*/
|
|
193
|
+
export interface EncryptMessageParams {
|
|
194
|
+
/** ID of the message being sent. */
|
|
195
|
+
messageId: string;
|
|
196
|
+
/** User ID of the sender. */
|
|
197
|
+
senderId: string;
|
|
198
|
+
/** ID of the conversation the message belongs to. */
|
|
199
|
+
conversationId: string;
|
|
200
|
+
/** Raw 32-byte conversation key used to encrypt the message content. */
|
|
201
|
+
conversationKey: Uint8Array;
|
|
202
|
+
/** The plaintext message text. */
|
|
203
|
+
text: string;
|
|
204
|
+
/** Version of the conversation key used for encryption. */
|
|
205
|
+
conversationKeyVersion: string;
|
|
206
|
+
/** Version of the signing key used to sign the message. */
|
|
207
|
+
signingKeyVersion: string;
|
|
208
|
+
/** Optional rich-text entities (URLs, mentions, etc.) to embed. */
|
|
209
|
+
entities?: EntityTuple[] | null;
|
|
210
|
+
/** Optional attachments (posts, URLs, media, etc.) to include in the message. */
|
|
211
|
+
attachments?: AttachmentDescriptor[] | null;
|
|
212
|
+
/** Whether to send a push notification. Omitted defaults to true. */
|
|
213
|
+
shouldNotify?: boolean | null;
|
|
214
|
+
/** Optional TTL in milliseconds for disappearing messages. */
|
|
215
|
+
ttlMsec?: number | null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Parameters for encryptReply.
|
|
220
|
+
*/
|
|
221
|
+
export interface EncryptReplyParams {
|
|
222
|
+
/** ID of the reply message being sent. */
|
|
223
|
+
messageId: string;
|
|
224
|
+
/** User ID of the sender. */
|
|
225
|
+
senderId: string;
|
|
226
|
+
/** ID of the conversation the reply belongs to. */
|
|
227
|
+
conversationId: string;
|
|
228
|
+
/** Raw 32-byte conversation key used to encrypt the message content. */
|
|
229
|
+
conversationKey: Uint8Array;
|
|
230
|
+
/** The plaintext reply text. */
|
|
231
|
+
text: string;
|
|
232
|
+
/** Version of the conversation key used for encryption. */
|
|
233
|
+
conversationKeyVersion: string;
|
|
234
|
+
/** Version of the signing key used to sign the message. */
|
|
235
|
+
signingKeyVersion: string;
|
|
236
|
+
/** The sequenceId of the message being replied to. */
|
|
237
|
+
replyToSequenceId: string;
|
|
238
|
+
/**
|
|
239
|
+
* The sender ID of the message being replied to (for preview).
|
|
240
|
+
* Prefer a string: snowflake user ids exceed the range where JavaScript
|
|
241
|
+
* numbers stay exact. Numbers are accepted only while integral and within
|
|
242
|
+
* `Number.MAX_SAFE_INTEGER`.
|
|
243
|
+
*/
|
|
244
|
+
replyToSenderId?: string | number | null;
|
|
245
|
+
/** The text of the message being replied to (for preview). */
|
|
246
|
+
replyToText?: string | null;
|
|
247
|
+
/** Optional rich-text entities (URLs, mentions, etc.) to embed in the outgoing message. */
|
|
248
|
+
entities?: EntityTuple[] | null;
|
|
249
|
+
/** Optional attachments (posts, URLs, media, etc.) to include in the outgoing message. */
|
|
250
|
+
attachments?: AttachmentDescriptor[] | null;
|
|
251
|
+
/** Optional rich-text entities from the original message (for the reply preview). */
|
|
252
|
+
replyToEntities?: EntityTuple[] | null;
|
|
253
|
+
/** Optional attachments from the original message (for the reply preview). */
|
|
254
|
+
replyToAttachments?: AttachmentDescriptor[] | null;
|
|
255
|
+
/** Whether to send a push notification. Omitted defaults to true. */
|
|
256
|
+
shouldNotify?: boolean | null;
|
|
257
|
+
/** Optional TTL in milliseconds for disappearing messages. */
|
|
258
|
+
ttlMsec?: number | null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Parameters for encryptAddReaction and encryptRemoveReaction.
|
|
263
|
+
*
|
|
264
|
+
* All fields are required; the same params object can be passed to both
|
|
265
|
+
* methods to add and later remove the same reaction.
|
|
266
|
+
*/
|
|
267
|
+
export interface EncryptReactionParams {
|
|
268
|
+
/** ID of the reaction message being sent. */
|
|
269
|
+
messageId: string;
|
|
270
|
+
/** User ID of the sender. */
|
|
271
|
+
senderId: string;
|
|
272
|
+
/** ID of the conversation the reaction belongs to. */
|
|
273
|
+
conversationId: string;
|
|
274
|
+
/** Raw 32-byte conversation key used to encrypt the reaction content. */
|
|
275
|
+
conversationKey: Uint8Array;
|
|
276
|
+
/** The sequenceId of the message being reacted to. */
|
|
277
|
+
targetMessageSequenceId: string;
|
|
278
|
+
/** The reaction emoji. */
|
|
279
|
+
emoji: string;
|
|
280
|
+
/** Version of the conversation key used for encryption. */
|
|
281
|
+
conversationKeyVersion: string;
|
|
282
|
+
/** Version of the signing key used to sign the message. */
|
|
283
|
+
signingKeyVersion: string;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Parameters for prepareConversationKeyChange.
|
|
288
|
+
*/
|
|
289
|
+
export interface ConversationKeyChangeParams {
|
|
290
|
+
/** User ID of the sender signing the change. */
|
|
291
|
+
senderId: string;
|
|
292
|
+
/** Version of the signing key used to sign the change. */
|
|
293
|
+
signingKeyVersion: string;
|
|
294
|
+
/** Identity public keys for every participant the new key is encrypted for. */
|
|
295
|
+
publicKeys: PublicKeyInput[];
|
|
296
|
+
/**
|
|
297
|
+
* Conversation the change applies to. Omit for a one-to-one (the canonical
|
|
298
|
+
* id is derived from the two participants); pass the existing id for a
|
|
299
|
+
* group key rotation.
|
|
300
|
+
*/
|
|
301
|
+
conversationId?: string | null;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Parameters for prepareGroupMembersChange.
|
|
306
|
+
*
|
|
307
|
+
* The current* fields snapshot the group state the change is made against.
|
|
308
|
+
* An unset optional signs the null sentinel, so every binding produces
|
|
309
|
+
* identical signed bytes.
|
|
310
|
+
*/
|
|
311
|
+
export interface GroupMembersChangeParams {
|
|
312
|
+
/** User ID of the sender signing the change. */
|
|
313
|
+
senderId: string;
|
|
314
|
+
/** Version of the signing key used to sign the change. */
|
|
315
|
+
signingKeyVersion: string;
|
|
316
|
+
/** Identity public keys for every participant of the updated roster. */
|
|
317
|
+
publicKeys: PublicKeyInput[];
|
|
318
|
+
/** ID of the group conversation being changed. */
|
|
319
|
+
conversationId: string;
|
|
320
|
+
/** User IDs being added to the group. */
|
|
321
|
+
newMemberIds: string[];
|
|
322
|
+
/** User IDs of the current members. */
|
|
323
|
+
currentMemberIds: string[];
|
|
324
|
+
/** User IDs of the current admins. */
|
|
325
|
+
currentAdminIds: string[];
|
|
326
|
+
/** User IDs of members whose join is still pending. */
|
|
327
|
+
currentPendingMemberIds: string[];
|
|
328
|
+
/** The group's current title, if set. */
|
|
329
|
+
currentTitle?: string | null;
|
|
330
|
+
/** The group's current avatar URL, if set. */
|
|
331
|
+
currentAvatarUrl?: string | null;
|
|
332
|
+
/** The group's current message TTL in milliseconds, if set. */
|
|
333
|
+
currentTtlMsec?: number | null;
|
|
334
|
+
/** The group's current screen-capture-blocking state; omit when unset. */
|
|
335
|
+
currentScreenCaptureBlockingEnabled?: boolean | null;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Parameters for prepareGroupCreate.
|
|
340
|
+
*
|
|
341
|
+
* An unset optional signs the null sentinel, so every binding produces
|
|
342
|
+
* identical signed bytes.
|
|
343
|
+
*/
|
|
344
|
+
export interface GroupCreateParams {
|
|
345
|
+
/** User ID of the sender signing the create. */
|
|
346
|
+
senderId: string;
|
|
347
|
+
/** Version of the signing key used to sign the create. */
|
|
348
|
+
signingKeyVersion: string;
|
|
349
|
+
/** Identity public keys for every participant of the new group. */
|
|
350
|
+
publicKeys: PublicKeyInput[];
|
|
351
|
+
/** ID of the new group conversation (the g-prefixed id minted by the initialize endpoint). */
|
|
352
|
+
conversationId: string;
|
|
353
|
+
/** User IDs of the group's members. */
|
|
354
|
+
memberIds: string[];
|
|
355
|
+
/** User IDs of the group's admins. */
|
|
356
|
+
adminIds: string[];
|
|
357
|
+
/** The group's title, if set. */
|
|
358
|
+
title?: string | null;
|
|
359
|
+
/** The group's avatar URL, if set. */
|
|
360
|
+
avatarUrl?: string | null;
|
|
361
|
+
/** The group's message TTL in milliseconds, if set. */
|
|
362
|
+
ttlMsec?: number | null;
|
|
363
|
+
}
|
|
364
|
+
|
|
187
365
|
// NOTE: AttachmentDescriptor uses snake_case as it's part of the Thrift protocol
|
|
188
366
|
// and matches the wire format used by the X API
|
|
189
367
|
/**
|
|
@@ -221,7 +399,12 @@ export interface Event {
|
|
|
221
399
|
attachments?: AttachmentInfo[];
|
|
222
400
|
/** For message events: media hash keys derived from attachments (if any). */
|
|
223
401
|
mediaHashes?: MediaHashReference[];
|
|
224
|
-
/**
|
|
402
|
+
/**
|
|
403
|
+
* The conversation key version (a snowflake/timestamp string). On message
|
|
404
|
+
* events: the version the message and any attached media were encrypted
|
|
405
|
+
* under — decrypt them with the matching key from the conversationKeys
|
|
406
|
+
* map. On keyChange events: the new key version introduced by the change.
|
|
407
|
+
*/
|
|
225
408
|
keyVersion?: string;
|
|
226
409
|
/** For keyChange events: encrypted conversation keys, one per participant. */
|
|
227
410
|
participantKeys?: ParticipantKey[];
|
|
@@ -231,8 +414,8 @@ export interface Event {
|
|
|
231
414
|
|
|
232
415
|
/**
|
|
233
416
|
* Decrypted message content. Permissive convenience shape: `contentType`
|
|
234
|
-
* discriminates which fields are present.
|
|
235
|
-
*
|
|
417
|
+
* discriminates which fields are present (e.g. `text` on 'text' content,
|
|
418
|
+
* `emoji`/`targetMessageId` on reactions, `newText` on edits).
|
|
236
419
|
*/
|
|
237
420
|
export interface MessageContent {
|
|
238
421
|
/**
|
|
@@ -281,9 +464,8 @@ export interface MediaHashReference {
|
|
|
281
464
|
|
|
282
465
|
/**
|
|
283
466
|
* An attachment on a decrypted message. Permissive convenience shape: the
|
|
284
|
-
* fields are flattened and `attachmentType` discriminates which
|
|
285
|
-
*
|
|
286
|
-
* `./types` entry.
|
|
467
|
+
* per-variant fields are flattened and `attachmentType` discriminates which
|
|
468
|
+
* apply ('media', 'url', 'post', 'unifiedCard', or 'money').
|
|
287
469
|
*/
|
|
288
470
|
export interface AttachmentInfo {
|
|
289
471
|
/** One of: 'media', 'url', 'post', 'unifiedCard', 'money'. */
|
|
@@ -314,7 +496,18 @@ export interface AttachmentInfo {
|
|
|
314
496
|
export interface CreateChatOptions {
|
|
315
497
|
/**
|
|
316
498
|
* Juicebox configuration JSON from the X API.
|
|
317
|
-
* Obtain this from
|
|
499
|
+
* Obtain this from the `juicebox_config` field of
|
|
500
|
+
* GET /2/users/:id/public_keys (your own user, `public_key.fields=juicebox_config`).
|
|
501
|
+
*
|
|
502
|
+
* Accepted shapes match the native bindings and are checked in this
|
|
503
|
+
* order: the `sdk_config` wrapper (its embedded SDK config string is
|
|
504
|
+
* unwrapped for the Juicebox client), the X API `juicebox_config` object
|
|
505
|
+
* (its `key_store_token_map_json` string is used verbatim so realm public
|
|
506
|
+
* keys and server thresholds are preserved), a bare `token_map` array
|
|
507
|
+
* (converted to a realms config with majority recover threshold — no
|
|
508
|
+
* realm public keys, so only suitable for realms that don't require
|
|
509
|
+
* them), or a raw realms config. Realm auth tokens always come from
|
|
510
|
+
* `getAuthToken`, not the config.
|
|
318
511
|
*/
|
|
319
512
|
juiceboxConfig: string;
|
|
320
513
|
|
|
@@ -335,11 +528,52 @@ export interface CreateChatOptions {
|
|
|
335
528
|
getAuthToken: (realmId: string) => Promise<string>;
|
|
336
529
|
|
|
337
530
|
/**
|
|
338
|
-
* Optional number of PIN guesses allowed before lockout.
|
|
531
|
+
* Optional override for the number of PIN guesses allowed before lockout.
|
|
532
|
+
* A non-negative integer wins over the config, including across later
|
|
533
|
+
* `updateConfig()` calls. When omitted, the config's `max_guess_count`
|
|
534
|
+
* applies when it is a non-negative integer (0 included), defaulting to
|
|
535
|
+
* 20 for the `sdk_config` and `key_store_token_map_json` shapes and 5
|
|
536
|
+
* otherwise.
|
|
339
537
|
*/
|
|
340
538
|
maxGuessCount?: number;
|
|
341
539
|
}
|
|
342
540
|
|
|
541
|
+
/**
|
|
542
|
+
* Incremental stream encryptor for large payloads.
|
|
543
|
+
*
|
|
544
|
+
* Feed plaintext with `push`; call `finish` once to emit the final frame.
|
|
545
|
+
* `finish()` consumes and frees the WASM object — do not call `free()` after
|
|
546
|
+
* it (doing so throws). Call `free()` only when abandoning a stream without
|
|
547
|
+
* finishing it.
|
|
548
|
+
*/
|
|
549
|
+
export declare class StreamEncryptor {
|
|
550
|
+
/** Encrypt a plaintext chunk, returning ciphertext available so far. */
|
|
551
|
+
push(plaintext: Uint8Array): Uint8Array;
|
|
552
|
+
/** Emit the final frame; consumes and frees the encryptor. */
|
|
553
|
+
finish(): Uint8Array;
|
|
554
|
+
/** Release the underlying WASM object when abandoning an unfinished stream. */
|
|
555
|
+
free(): void;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Incremental stream decryptor for large payloads.
|
|
560
|
+
*
|
|
561
|
+
* Feed ciphertext with `push`; call `finish` once at end of input. `finish`
|
|
562
|
+
* throws if the stream ended before its final frame (truncation), so do not
|
|
563
|
+
* treat plaintext from `push` as complete until `finish` succeeds.
|
|
564
|
+
* `finish()` consumes and frees the WASM object — do not call `free()` after
|
|
565
|
+
* it (doing so throws). Call `free()` only when abandoning a stream without
|
|
566
|
+
* finishing it.
|
|
567
|
+
*/
|
|
568
|
+
export declare class StreamDecryptor {
|
|
569
|
+
/** Decrypt a ciphertext chunk, returning plaintext available so far. */
|
|
570
|
+
push(ciphertext: Uint8Array): Uint8Array;
|
|
571
|
+
/** Decrypt the final frame; consumes and frees the decryptor. */
|
|
572
|
+
finish(): Uint8Array;
|
|
573
|
+
/** Release the underlying WASM object when abandoning an unfinished stream. */
|
|
574
|
+
free(): void;
|
|
575
|
+
}
|
|
576
|
+
|
|
343
577
|
/**
|
|
344
578
|
* Common interface for all Chat methods (shared by Chat and ChatWithJuicebox).
|
|
345
579
|
*
|
|
@@ -347,12 +581,19 @@ export interface CreateChatOptions {
|
|
|
347
581
|
* `ChatWithJuicebox` (returned by `createChat()`) adds Juicebox lifecycle methods.
|
|
348
582
|
*/
|
|
349
583
|
interface ChatCrypto {
|
|
350
|
-
/**
|
|
584
|
+
/**
|
|
585
|
+
* When enabled — the default — `decryptEvent` throws for any signed event
|
|
586
|
+
* whose signature cannot be verified (invalid, missing, or no matching
|
|
587
|
+
* signing key) instead of returning it with `verified: false`.
|
|
588
|
+
*/
|
|
351
589
|
setRejectUnverified(reject: boolean): void;
|
|
352
590
|
|
|
353
591
|
/** Generate new keypairs and return the registration payload. */
|
|
354
592
|
generateKeypairs(): PublicKeyRegistrationPayload;
|
|
355
593
|
|
|
594
|
+
/** Set the registered public key version (call after unlock()). */
|
|
595
|
+
setKeyVersion(version: string): void;
|
|
596
|
+
|
|
356
597
|
/** Get current public keys. */
|
|
357
598
|
getPublicKeys(): PublicKeys;
|
|
358
599
|
|
|
@@ -371,9 +612,6 @@ interface ChatCrypto {
|
|
|
371
612
|
/** Decrypt an encrypted conversation key (ECIES). */
|
|
372
613
|
decryptConversationKey(encryptedKeyB64: string): Uint8Array;
|
|
373
614
|
|
|
374
|
-
/** Generate a new conversation key. */
|
|
375
|
-
generateConversationKey(): Uint8Array;
|
|
376
|
-
|
|
377
615
|
/** Extract and decrypt conversation keys from raw KeyChange event strings. */
|
|
378
616
|
extractConversationKeys(events: string[]): ConversationKeyResult;
|
|
379
617
|
|
|
@@ -386,12 +624,22 @@ interface ChatCrypto {
|
|
|
386
624
|
* 3. Decrypts the message using the appropriate conversation key
|
|
387
625
|
*
|
|
388
626
|
* @param events - Raw base64-encoded event strings from the webhook
|
|
389
|
-
* @param signingKeys - All known signing keys for all participants (with
|
|
627
|
+
* @param signingKeys - All known signing keys for all participants (with
|
|
628
|
+
* userId). Under the default reject-unverified policy, omitting this makes
|
|
629
|
+
* every signed event land in `errors`; only after
|
|
630
|
+
* `setRejectUnverified(false)` are such events returned with
|
|
631
|
+
* `verified: false`.
|
|
390
632
|
*/
|
|
391
633
|
decryptEvents(events: string[], signingKeys?: SigningKeyEntry[]): DecryptEventsResult;
|
|
392
634
|
|
|
393
|
-
/**
|
|
394
|
-
|
|
635
|
+
/**
|
|
636
|
+
* Decrypt a raw webhook event payload.
|
|
637
|
+
*
|
|
638
|
+
* Under the default reject-unverified policy, omitting `signingKeys` makes
|
|
639
|
+
* every signed event throw; only after `setRejectUnverified(false)` are
|
|
640
|
+
* such events returned with `verified: false`.
|
|
641
|
+
*/
|
|
642
|
+
decryptEvent(eventB64: string, conversationKeys?: ConversationKeyMap | null, signingKeys?: SigningKeyEntry[]): Event;
|
|
395
643
|
|
|
396
644
|
/** Sign data. Returns raw signature bytes (64 bytes). */
|
|
397
645
|
sign(data: Uint8Array): Uint8Array;
|
|
@@ -399,17 +647,20 @@ interface ChatCrypto {
|
|
|
399
647
|
/** Verify a signature. */
|
|
400
648
|
verify(publicKeyB64: string, signature: Uint8Array, data: Uint8Array): boolean;
|
|
401
649
|
|
|
650
|
+
/** Verify that an identity key signed a signing key (key binding). */
|
|
651
|
+
verifyKeyBinding(identityPublicKeyB64: string, signingPublicKeyB64: string, identityPublicKeySignatureB64: string): boolean;
|
|
652
|
+
|
|
402
653
|
/** Encrypt a text message. */
|
|
403
|
-
encryptMessage(
|
|
654
|
+
encryptMessage(params: EncryptMessageParams): SendPayload;
|
|
404
655
|
|
|
405
656
|
/** Encrypt a reply. */
|
|
406
|
-
encryptReply(
|
|
657
|
+
encryptReply(params: EncryptReplyParams): SendPayload;
|
|
407
658
|
|
|
408
659
|
/** Encrypt a reaction-add. */
|
|
409
|
-
encryptAddReaction(
|
|
660
|
+
encryptAddReaction(params: EncryptReactionParams): SendPayload;
|
|
410
661
|
|
|
411
662
|
/** Encrypt a reaction-remove. */
|
|
412
|
-
encryptRemoveReaction(
|
|
663
|
+
encryptRemoveReaction(params: EncryptReactionParams): SendPayload;
|
|
413
664
|
|
|
414
665
|
/** Encrypt a stream (e.g. media). */
|
|
415
666
|
encryptStream(plaintext: Uint8Array, conversationKey: Uint8Array): Uint8Array;
|
|
@@ -417,33 +668,59 @@ interface ChatCrypto {
|
|
|
417
668
|
/** Decrypt a streaming-encrypted payload (e.g. media). */
|
|
418
669
|
decryptStream(encrypted: Uint8Array, conversationKey: Uint8Array): Uint8Array;
|
|
419
670
|
|
|
671
|
+
/** Create an incremental stream encryptor for large payloads. */
|
|
672
|
+
streamEncryptor(conversationKey: Uint8Array): StreamEncryptor;
|
|
673
|
+
|
|
674
|
+
/** Create an incremental stream decryptor for large payloads. */
|
|
675
|
+
streamDecryptor(conversationKey: Uint8Array): StreamDecryptor;
|
|
676
|
+
|
|
420
677
|
/** Encrypt a UTF-8 string and return base64 ciphertext. Use for metadata fields like group names. */
|
|
421
678
|
encrypt(plaintext: string, conversationKey: Uint8Array): string;
|
|
422
679
|
|
|
423
680
|
/** Decrypt a base64-encoded ciphertext and return the UTF-8 plaintext. Use for metadata fields like group names. */
|
|
424
681
|
decrypt(ciphertextB64: string, conversationKey: Uint8Array): string;
|
|
425
682
|
|
|
426
|
-
/** Encrypt a conversation key for one or more recipients. */
|
|
427
|
-
encryptConversationKeyForRecipients(conversationKey: Uint8Array, recipients: RecipientInput[]): EncryptedKeyForRecipient[];
|
|
428
|
-
|
|
429
683
|
/**
|
|
430
|
-
* Prepare conversation
|
|
684
|
+
* Prepare a signed conversation-key change, ready to send to the X API.
|
|
431
685
|
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
686
|
+
* Use this to start a one-to-one or rotate an existing conversation's key
|
|
687
|
+
* (one-to-one or group). Creating a group or adding members requires a
|
|
688
|
+
* paired group signature as well — use prepareGroupCreate or
|
|
689
|
+
* prepareGroupMembersChange for those.
|
|
436
690
|
*
|
|
437
|
-
*
|
|
438
|
-
*
|
|
691
|
+
* Pass the flat array of public keys (self plus recipients) from the X API
|
|
692
|
+
* in params.publicKeys. Omit params.conversationId for a one-to-one (it is
|
|
693
|
+
* derived from the two participants); pass the existing id for a group key
|
|
694
|
+
* rotation.
|
|
695
|
+
*
|
|
696
|
+
* @returns PreparedConversationChange ready to POST to the API
|
|
439
697
|
*/
|
|
440
|
-
|
|
698
|
+
prepareConversationKeyChange(params: ConversationKeyChangeParams): PreparedConversationChange;
|
|
441
699
|
|
|
442
|
-
/**
|
|
443
|
-
|
|
700
|
+
/**
|
|
701
|
+
* Prepare a signed group member-add change, ready to send to the X API.
|
|
702
|
+
*
|
|
703
|
+
* Use this when adding members to an existing group. Creating the group is
|
|
704
|
+
* prepareGroupCreate; a key rotation without a roster change is
|
|
705
|
+
* prepareConversationKeyChange.
|
|
706
|
+
*
|
|
707
|
+
* @returns PreparedConversationChange with two action signatures: the
|
|
708
|
+
* conversation-key change and the member add
|
|
709
|
+
*/
|
|
710
|
+
prepareGroupMembersChange(params: GroupMembersChangeParams): PreparedConversationChange;
|
|
444
711
|
|
|
445
|
-
/**
|
|
446
|
-
|
|
712
|
+
/**
|
|
713
|
+
* Prepare a signed group create, ready to send to the X API.
|
|
714
|
+
*
|
|
715
|
+
* Use this once, when creating a group (conversationId is the g-prefixed id
|
|
716
|
+
* minted by the initialize endpoint). Later key rotations use
|
|
717
|
+
* prepareConversationKeyChange; roster additions use
|
|
718
|
+
* prepareGroupMembersChange.
|
|
719
|
+
*
|
|
720
|
+
* @returns PreparedConversationChange with two action signatures: the
|
|
721
|
+
* conversation-key change and the group create
|
|
722
|
+
*/
|
|
723
|
+
prepareGroupCreate(params: GroupCreateParams): PreparedConversationChange;
|
|
447
724
|
}
|
|
448
725
|
|
|
449
726
|
/** Internal crypto engine wrapped by ChatWithJuicebox. Not part of the public API. */
|
|
@@ -460,25 +737,25 @@ declare class Chat implements ChatCrypto {
|
|
|
460
737
|
hasIdentityKey(): boolean;
|
|
461
738
|
lock(): void;
|
|
462
739
|
decryptConversationKey(encryptedKeyB64: string): Uint8Array;
|
|
463
|
-
generateConversationKey(): Uint8Array;
|
|
464
740
|
extractConversationKeys(events: string[]): ConversationKeyResult;
|
|
465
741
|
decryptEvents(events: string[], signingKeys?: SigningKeyEntry[]): DecryptEventsResult;
|
|
466
|
-
decryptEvent(eventB64: string, conversationKeys
|
|
742
|
+
decryptEvent(eventB64: string, conversationKeys?: ConversationKeyMap | null, signingKeys?: SigningKeyEntry[]): Event;
|
|
467
743
|
sign(data: Uint8Array): Uint8Array;
|
|
468
744
|
verify(publicKeyB64: string, signature: Uint8Array, data: Uint8Array): boolean;
|
|
469
745
|
verifyKeyBinding(identityPublicKeyB64: string, signingPublicKeyB64: string, identityPublicKeySignatureB64: string): boolean;
|
|
470
|
-
encryptMessage(
|
|
471
|
-
encryptReply(
|
|
472
|
-
encryptAddReaction(
|
|
473
|
-
encryptRemoveReaction(
|
|
746
|
+
encryptMessage(params: EncryptMessageParams): SendPayload;
|
|
747
|
+
encryptReply(params: EncryptReplyParams): SendPayload;
|
|
748
|
+
encryptAddReaction(params: EncryptReactionParams): SendPayload;
|
|
749
|
+
encryptRemoveReaction(params: EncryptReactionParams): SendPayload;
|
|
474
750
|
encryptStream(plaintext: Uint8Array, conversationKey: Uint8Array): Uint8Array;
|
|
475
751
|
decryptStream(encrypted: Uint8Array, conversationKey: Uint8Array): Uint8Array;
|
|
752
|
+
streamEncryptor(conversationKey: Uint8Array): StreamEncryptor;
|
|
753
|
+
streamDecryptor(conversationKey: Uint8Array): StreamDecryptor;
|
|
476
754
|
encrypt(plaintext: string, conversationKey: Uint8Array): string;
|
|
477
755
|
decrypt(ciphertextB64: string, conversationKey: Uint8Array): string;
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
signKeyChange(publicKeyVersion: string, messageId: string, senderId: string, conversationId: string, conversationKeyVersion: string, conversationKey: Uint8Array): ActionSignature;
|
|
756
|
+
prepareConversationKeyChange(params: ConversationKeyChangeParams): PreparedConversationChange;
|
|
757
|
+
prepareGroupMembersChange(params: GroupMembersChangeParams): PreparedConversationChange;
|
|
758
|
+
prepareGroupCreate(params: GroupCreateParams): PreparedConversationChange;
|
|
482
759
|
}
|
|
483
760
|
|
|
484
761
|
/**
|
|
@@ -497,6 +774,11 @@ export declare class ChatWithJuicebox implements ChatCrypto {
|
|
|
497
774
|
delete(): Promise<void>;
|
|
498
775
|
/** The new PIN must meet the same strength requirements as setup(). */
|
|
499
776
|
changePin(oldPin: string | Uint8Array, newPin: string | Uint8Array): Promise<void>;
|
|
777
|
+
/**
|
|
778
|
+
* Re-create the Juicebox client from a new config (e.g. refreshed auth
|
|
779
|
+
* tokens) and re-resolve the PIN guess budget from it; an explicit
|
|
780
|
+
* createChat `maxGuessCount` override keeps winning.
|
|
781
|
+
*/
|
|
500
782
|
updateConfig(juiceboxConfig: string): void;
|
|
501
783
|
|
|
502
784
|
setRejectUnverified(reject: boolean): void;
|
|
@@ -509,31 +791,43 @@ export declare class ChatWithJuicebox implements ChatCrypto {
|
|
|
509
791
|
hasIdentityKey(): boolean;
|
|
510
792
|
lock(): void;
|
|
511
793
|
decryptConversationKey(encryptedKeyB64: string): Uint8Array;
|
|
512
|
-
generateConversationKey(): Uint8Array;
|
|
513
794
|
extractConversationKeys(events: string[]): ConversationKeyResult;
|
|
514
795
|
decryptEvents(events: string[], signingKeys?: SigningKeyEntry[]): DecryptEventsResult;
|
|
515
|
-
decryptEvent(eventB64: string, conversationKeys
|
|
796
|
+
decryptEvent(eventB64: string, conversationKeys?: ConversationKeyMap | null, signingKeys?: SigningKeyEntry[]): Event;
|
|
516
797
|
sign(data: Uint8Array): Uint8Array;
|
|
517
798
|
verify(publicKeyB64: string, signature: Uint8Array, data: Uint8Array): boolean;
|
|
518
799
|
verifyKeyBinding(identityPublicKeyB64: string, signingPublicKeyB64: string, identityPublicKeySignatureB64: string): boolean;
|
|
519
|
-
encryptMessage(
|
|
520
|
-
encryptReply(
|
|
521
|
-
encryptAddReaction(
|
|
522
|
-
encryptRemoveReaction(
|
|
800
|
+
encryptMessage(params: EncryptMessageParams): SendPayload;
|
|
801
|
+
encryptReply(params: EncryptReplyParams): SendPayload;
|
|
802
|
+
encryptAddReaction(params: EncryptReactionParams): SendPayload;
|
|
803
|
+
encryptRemoveReaction(params: EncryptReactionParams): SendPayload;
|
|
523
804
|
encryptStream(plaintext: Uint8Array, conversationKey: Uint8Array): Uint8Array;
|
|
524
805
|
decryptStream(encrypted: Uint8Array, conversationKey: Uint8Array): Uint8Array;
|
|
806
|
+
streamEncryptor(conversationKey: Uint8Array): StreamEncryptor;
|
|
807
|
+
streamDecryptor(conversationKey: Uint8Array): StreamDecryptor;
|
|
525
808
|
encrypt(plaintext: string, conversationKey: Uint8Array): string;
|
|
526
809
|
decrypt(ciphertextB64: string, conversationKey: Uint8Array): string;
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
810
|
+
prepareConversationKeyChange(params: ConversationKeyChangeParams): PreparedConversationChange;
|
|
811
|
+
prepareGroupMembersChange(params: GroupMembersChangeParams): PreparedConversationChange;
|
|
812
|
+
prepareGroupCreate(params: GroupCreateParams): PreparedConversationChange;
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Release the WASM-side crypto engine: clears key material (`lock()`) and
|
|
816
|
+
* frees the underlying WASM object. The instance must not be used
|
|
817
|
+
* afterwards. When reusing the instance, `lock()` alone suffices for key
|
|
818
|
+
* hygiene.
|
|
819
|
+
*/
|
|
820
|
+
free(): void;
|
|
531
821
|
}
|
|
532
822
|
|
|
533
823
|
/**
|
|
534
824
|
* Create a Chat instance with integrated Juicebox key storage.
|
|
535
825
|
*
|
|
536
826
|
* Each call creates an independent instance with its own Juicebox client.
|
|
827
|
+
* The Juicebox auth-token callback is a process-wide global that each
|
|
828
|
+
* instance re-arms before its own operations, so sequential use of multiple
|
|
829
|
+
* instances is fine but concurrent Juicebox operations across instances in
|
|
830
|
+
* one process are not supported.
|
|
537
831
|
*/
|
|
538
832
|
export declare function createChat(options: CreateChatOptions): Promise<ChatWithJuicebox>;
|
|
539
833
|
|