@xmtp/browser-sdk 1.1.4 → 2.0.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.
- package/dist/index.d.ts +774 -27
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/workers/client.js +1 -1
- package/dist/workers/client.js.map +1 -1
- package/dist/workers/utils.js +1 -1
- package/dist/workers/utils.js.map +1 -1
- package/package.json +8 -8
- package/src/Client.ts +351 -72
- package/src/Conversation.ts +104 -13
- package/src/Conversations.ts +130 -0
- package/src/DecodedMessage.ts +20 -12
- package/src/Dm.ts +17 -1
- package/src/Group.ts +124 -9
- package/src/Preferences.ts +54 -0
- package/src/Utils.ts +21 -4
- package/src/UtilsWorkerClass.ts +7 -0
- package/src/WorkerClient.ts +18 -2
- package/src/WorkerConversation.ts +5 -0
- package/src/constants.ts +16 -0
- package/src/index.ts +0 -1
- package/src/types/clientEvents.ts +26 -2
- package/src/types/options.ts +5 -1
- package/src/types/utilsEvents.ts +8 -2
- package/src/utils/conversions.ts +21 -0
- package/src/utils/createClient.ts +4 -3
- package/src/utils/errors.ts +86 -0
- package/src/workers/client.ts +40 -8
- package/src/workers/utils.ts +12 -2
package/src/Client.ts
CHANGED
|
@@ -16,30 +16,46 @@ import { ClientWorkerClass } from "@/ClientWorkerClass";
|
|
|
16
16
|
import { Conversations } from "@/Conversations";
|
|
17
17
|
import { Preferences } from "@/Preferences";
|
|
18
18
|
import type { ClientOptions, XmtpEnv } from "@/types";
|
|
19
|
+
import { Utils } from "@/Utils";
|
|
19
20
|
import {
|
|
20
21
|
fromSafeEncodedContent,
|
|
21
22
|
toSafeEncodedContent,
|
|
22
23
|
type SafeMessage,
|
|
23
24
|
} from "@/utils/conversions";
|
|
25
|
+
import {
|
|
26
|
+
AccountAlreadyAssociatedError,
|
|
27
|
+
CodecNotFoundError,
|
|
28
|
+
GenerateSignatureError,
|
|
29
|
+
InboxReassignError,
|
|
30
|
+
InvalidGroupMembershipChangeError,
|
|
31
|
+
SignerUnavailableError,
|
|
32
|
+
} from "@/utils/errors";
|
|
24
33
|
import { type Signer } from "@/utils/signer";
|
|
25
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Client for interacting with the XMTP network
|
|
37
|
+
*/
|
|
26
38
|
export class Client extends ClientWorkerClass {
|
|
27
39
|
#codecs: Map<string, ContentCodec>;
|
|
28
40
|
#conversations: Conversations;
|
|
29
|
-
#
|
|
41
|
+
#identifier?: Identifier;
|
|
30
42
|
#inboxId: string | undefined;
|
|
31
43
|
#installationId: string | undefined;
|
|
32
44
|
#installationIdBytes: Uint8Array | undefined;
|
|
33
45
|
#isReady = false;
|
|
34
46
|
#preferences: Preferences;
|
|
35
|
-
#signer
|
|
36
|
-
options?: ClientOptions;
|
|
47
|
+
#signer?: Signer;
|
|
48
|
+
#options?: ClientOptions;
|
|
37
49
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new XMTP client instance
|
|
52
|
+
*
|
|
53
|
+
* This class is not intended to be initialized directly.
|
|
54
|
+
* Use `Client.create` or `Client.build` instead.
|
|
55
|
+
*
|
|
56
|
+
* @param options - Optional configuration for the client
|
|
57
|
+
*/
|
|
58
|
+
constructor(options?: ClientOptions) {
|
|
43
59
|
const worker = new Worker(new URL("./workers/client", import.meta.url), {
|
|
44
60
|
type: "module",
|
|
45
61
|
});
|
|
@@ -47,9 +63,7 @@ export class Client extends ClientWorkerClass {
|
|
|
47
63
|
worker,
|
|
48
64
|
options?.loggingLevel !== undefined && options.loggingLevel !== "off",
|
|
49
65
|
);
|
|
50
|
-
this
|
|
51
|
-
this.#encryptionKey = encryptionKey;
|
|
52
|
-
this.#signer = signer;
|
|
66
|
+
this.#options = options;
|
|
53
67
|
this.#conversations = new Conversations(this);
|
|
54
68
|
this.#preferences = new Preferences(this);
|
|
55
69
|
const codecs = [
|
|
@@ -62,26 +76,38 @@ export class Client extends ClientWorkerClass {
|
|
|
62
76
|
);
|
|
63
77
|
}
|
|
64
78
|
|
|
65
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Initializes the client with the provided identifier
|
|
81
|
+
*
|
|
82
|
+
* This is not meant to be called directly.
|
|
83
|
+
* Use `Client.create` or `Client.build` instead.
|
|
84
|
+
*
|
|
85
|
+
* @param identifier - The identifier to initialize the client with
|
|
86
|
+
*/
|
|
87
|
+
async init(identifier: Identifier) {
|
|
66
88
|
const result = await this.sendMessage("init", {
|
|
67
|
-
identifier
|
|
68
|
-
|
|
69
|
-
options: this.options,
|
|
89
|
+
identifier,
|
|
90
|
+
options: this.#options,
|
|
70
91
|
});
|
|
92
|
+
this.#identifier = identifier;
|
|
71
93
|
this.#inboxId = result.inboxId;
|
|
72
94
|
this.#installationId = result.installationId;
|
|
73
95
|
this.#installationIdBytes = result.installationIdBytes;
|
|
74
96
|
this.#isReady = true;
|
|
75
97
|
}
|
|
76
98
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Creates a new client instance with a signer
|
|
101
|
+
*
|
|
102
|
+
* @param signer - The signer to use for authentication
|
|
103
|
+
* @param options - Optional configuration for the client
|
|
104
|
+
* @returns A new client instance
|
|
105
|
+
*/
|
|
106
|
+
static async create(signer: Signer, options?: ClientOptions) {
|
|
107
|
+
const client = new Client(options);
|
|
108
|
+
client.#signer = signer;
|
|
83
109
|
|
|
84
|
-
await client.init();
|
|
110
|
+
await client.init(await signer.getIdentifier());
|
|
85
111
|
|
|
86
112
|
if (!options?.disableAutoRegister) {
|
|
87
113
|
await client.register();
|
|
@@ -90,63 +116,115 @@ export class Client extends ClientWorkerClass {
|
|
|
90
116
|
return client;
|
|
91
117
|
}
|
|
92
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Creates a new client instance with an identifier
|
|
121
|
+
*
|
|
122
|
+
* Clients created with this method must already be registered.
|
|
123
|
+
* Any methods called that require a signer will throw an error.
|
|
124
|
+
*
|
|
125
|
+
* @param identifier - The identifier to use
|
|
126
|
+
* @param options - Optional configuration for the client
|
|
127
|
+
* @returns A new client instance
|
|
128
|
+
*/
|
|
129
|
+
static async build(identifier: Identifier, options?: ClientOptions) {
|
|
130
|
+
const client = new Client({
|
|
131
|
+
...options,
|
|
132
|
+
disableAutoRegister: true,
|
|
133
|
+
});
|
|
134
|
+
await client.init(identifier);
|
|
135
|
+
return client;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Gets the client options
|
|
140
|
+
*/
|
|
141
|
+
get options() {
|
|
142
|
+
return this.#options;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Gets whether the client has been initialized
|
|
147
|
+
*/
|
|
93
148
|
get isReady() {
|
|
94
149
|
return this.#isReady;
|
|
95
150
|
}
|
|
96
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Gets the inbox ID associated with this client
|
|
154
|
+
*/
|
|
97
155
|
get inboxId() {
|
|
98
156
|
return this.#inboxId;
|
|
99
157
|
}
|
|
100
158
|
|
|
101
|
-
|
|
102
|
-
|
|
159
|
+
/**
|
|
160
|
+
* Gets the account identifier for this client
|
|
161
|
+
*/
|
|
162
|
+
get accountIdentifier() {
|
|
163
|
+
return this.#identifier;
|
|
103
164
|
}
|
|
104
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Gets the installation ID for this client
|
|
168
|
+
*/
|
|
105
169
|
get installationId() {
|
|
106
170
|
return this.#installationId;
|
|
107
171
|
}
|
|
108
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Gets the installation ID bytes for this client
|
|
175
|
+
*/
|
|
109
176
|
get installationIdBytes() {
|
|
110
177
|
return this.#installationIdBytes;
|
|
111
178
|
}
|
|
112
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Gets the conversations manager for this client
|
|
182
|
+
*/
|
|
113
183
|
get conversations() {
|
|
114
184
|
return this.#conversations;
|
|
115
185
|
}
|
|
116
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Gets the preferences manager for this client
|
|
189
|
+
*/
|
|
117
190
|
get preferences() {
|
|
118
191
|
return this.#preferences;
|
|
119
192
|
}
|
|
120
193
|
|
|
121
194
|
/**
|
|
195
|
+
* Creates signature text for creating a new inbox
|
|
196
|
+
*
|
|
122
197
|
* WARNING: This function should be used with caution. It is only provided
|
|
123
198
|
* for use in special cases where the provided workflows do not meet the
|
|
124
199
|
* requirements of an application.
|
|
125
200
|
*
|
|
126
|
-
* It is highly recommended to use the `register`
|
|
201
|
+
* It is highly recommended to use the `register` method instead.
|
|
202
|
+
*
|
|
203
|
+
* @returns The signature text
|
|
127
204
|
*/
|
|
128
205
|
async unsafe_createInboxSignatureText() {
|
|
129
206
|
return this.sendMessage("createInboxSignatureText", undefined);
|
|
130
207
|
}
|
|
131
208
|
|
|
132
209
|
/**
|
|
210
|
+
* Creates signature text for adding a new account to the client's inbox
|
|
211
|
+
*
|
|
133
212
|
* WARNING: This function should be used with caution. It is only provided
|
|
134
213
|
* for use in special cases where the provided workflows do not meet the
|
|
135
214
|
* requirements of an application.
|
|
136
215
|
*
|
|
137
|
-
* It is highly recommended to use the `unsafe_addAccount`
|
|
216
|
+
* It is highly recommended to use the `unsafe_addAccount` method instead.
|
|
138
217
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
218
|
+
* @param newIdentifier - The identifier of the new account
|
|
219
|
+
* @param allowInboxReassign - Whether to allow inbox reassignment
|
|
220
|
+
* @returns The signature text
|
|
141
221
|
*/
|
|
142
222
|
async unsafe_addAccountSignatureText(
|
|
143
223
|
newIdentifier: Identifier,
|
|
144
224
|
allowInboxReassign: boolean = false,
|
|
145
225
|
) {
|
|
146
226
|
if (!allowInboxReassign) {
|
|
147
|
-
throw new
|
|
148
|
-
"Unable to create add account signature text, `allowInboxReassign` must be true",
|
|
149
|
-
);
|
|
227
|
+
throw new InboxReassignError();
|
|
150
228
|
}
|
|
151
229
|
|
|
152
230
|
return this.sendMessage("addAccountSignatureText", {
|
|
@@ -155,11 +233,16 @@ export class Client extends ClientWorkerClass {
|
|
|
155
233
|
}
|
|
156
234
|
|
|
157
235
|
/**
|
|
236
|
+
* Creates signature text for removing an account from the client's inbox
|
|
237
|
+
*
|
|
158
238
|
* WARNING: This function should be used with caution. It is only provided
|
|
159
239
|
* for use in special cases where the provided workflows do not meet the
|
|
160
240
|
* requirements of an application.
|
|
161
241
|
*
|
|
162
|
-
* It is highly recommended to use the `removeAccount`
|
|
242
|
+
* It is highly recommended to use the `removeAccount` method instead.
|
|
243
|
+
*
|
|
244
|
+
* @param identifier - The identifier of the account to remove
|
|
245
|
+
* @returns The signature text
|
|
163
246
|
*/
|
|
164
247
|
async unsafe_removeAccountSignatureText(identifier: Identifier) {
|
|
165
248
|
return this.sendMessage("removeAccountSignatureText", {
|
|
@@ -168,12 +251,16 @@ export class Client extends ClientWorkerClass {
|
|
|
168
251
|
}
|
|
169
252
|
|
|
170
253
|
/**
|
|
254
|
+
* Creates signature text for revoking all other installations of the
|
|
255
|
+
* client's inbox
|
|
256
|
+
*
|
|
171
257
|
* WARNING: This function should be used with caution. It is only provided
|
|
172
258
|
* for use in special cases where the provided workflows do not meet the
|
|
173
259
|
* requirements of an application.
|
|
174
260
|
*
|
|
175
|
-
* It is highly recommended to use the `revokeAllOtherInstallations`
|
|
176
|
-
*
|
|
261
|
+
* It is highly recommended to use the `revokeAllOtherInstallations` method instead.
|
|
262
|
+
*
|
|
263
|
+
* @returns The signature text
|
|
177
264
|
*/
|
|
178
265
|
async unsafe_revokeAllOtherInstallationsSignatureText() {
|
|
179
266
|
return this.sendMessage(
|
|
@@ -183,11 +270,17 @@ export class Client extends ClientWorkerClass {
|
|
|
183
270
|
}
|
|
184
271
|
|
|
185
272
|
/**
|
|
273
|
+
* Creates signature text for revoking specific installations of the
|
|
274
|
+
* client's inbox
|
|
275
|
+
*
|
|
186
276
|
* WARNING: This function should be used with caution. It is only provided
|
|
187
277
|
* for use in special cases where the provided workflows do not meet the
|
|
188
278
|
* requirements of an application.
|
|
189
279
|
*
|
|
190
|
-
* It is highly recommended to use the `revokeInstallations`
|
|
280
|
+
* It is highly recommended to use the `revokeInstallations` method instead.
|
|
281
|
+
*
|
|
282
|
+
* @param installationIds - The installation IDs to revoke
|
|
283
|
+
* @returns The signature text
|
|
191
284
|
*/
|
|
192
285
|
async unsafe_revokeInstallationsSignatureText(installationIds: Uint8Array[]) {
|
|
193
286
|
return this.sendMessage("revokeInstallationsSignatureText", {
|
|
@@ -196,13 +289,39 @@ export class Client extends ClientWorkerClass {
|
|
|
196
289
|
}
|
|
197
290
|
|
|
198
291
|
/**
|
|
292
|
+
* Creates signature text for changing the recovery identifier for this
|
|
293
|
+
* client's inbox
|
|
294
|
+
*
|
|
199
295
|
* WARNING: This function should be used with caution. It is only provided
|
|
200
296
|
* for use in special cases where the provided workflows do not meet the
|
|
201
297
|
* requirements of an application.
|
|
202
298
|
*
|
|
203
|
-
* It is highly recommended to use the `
|
|
299
|
+
* It is highly recommended to use the `changeRecoveryIdentifier` method instead.
|
|
300
|
+
*
|
|
301
|
+
* @param identifier - The new recovery identifier
|
|
302
|
+
* @returns The signature text
|
|
303
|
+
*/
|
|
304
|
+
async unsafe_changeRecoveryIdentifierSignatureText(identifier: Identifier) {
|
|
305
|
+
return this.sendMessage("changeRecoveryIdentifierSignatureText", {
|
|
306
|
+
identifier,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Adds a signature for a specific request type
|
|
312
|
+
*
|
|
313
|
+
* WARNING: This function should be used with caution. It is only provided
|
|
314
|
+
* for use in special cases where the provided workflows do not meet the
|
|
315
|
+
* requirements of an application.
|
|
316
|
+
*
|
|
317
|
+
* It is highly recommended to use the `register`, `unsafe_addAccount`,
|
|
204
318
|
* `removeAccount`, `revokeAllOtherInstallations`, or `revokeInstallations`
|
|
205
|
-
*
|
|
319
|
+
* methods instead.
|
|
320
|
+
*
|
|
321
|
+
* @param signatureType - The type of signature request
|
|
322
|
+
* @param signatureText - The text to sign
|
|
323
|
+
* @param signer - The signer to use
|
|
324
|
+
* @warning This is an unsafe operation and should be used with caution
|
|
206
325
|
*/
|
|
207
326
|
async unsafe_addSignature(
|
|
208
327
|
signatureType: SignatureRequestType,
|
|
@@ -230,19 +349,32 @@ export class Client extends ClientWorkerClass {
|
|
|
230
349
|
}
|
|
231
350
|
|
|
232
351
|
/**
|
|
352
|
+
* Applies all pending signatures
|
|
353
|
+
*
|
|
233
354
|
* WARNING: This function should be used with caution. It is only provided
|
|
234
355
|
* for use in special cases where the provided workflows do not meet the
|
|
235
356
|
* requirements of an application.
|
|
236
357
|
*
|
|
237
|
-
* It is highly recommended to use the `register`, `
|
|
358
|
+
* It is highly recommended to use the `register`, `unsafe_addAccount`,
|
|
238
359
|
* `removeAccount`, `revokeAllOtherInstallations`, or `revokeInstallations`
|
|
239
|
-
*
|
|
360
|
+
* methods instead.
|
|
240
361
|
*/
|
|
241
362
|
async unsafe_applySignatures() {
|
|
242
363
|
return this.sendMessage("applySignatures", undefined);
|
|
243
364
|
}
|
|
244
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Registers the client with the XMTP network
|
|
368
|
+
*
|
|
369
|
+
* Requires a signer, use `Client.create` to create a client with a signer.
|
|
370
|
+
*
|
|
371
|
+
* @throws {SignerUnavailableError} if no signer is available
|
|
372
|
+
*/
|
|
245
373
|
async register() {
|
|
374
|
+
if (!this.#signer) {
|
|
375
|
+
throw new SignerUnavailableError();
|
|
376
|
+
}
|
|
377
|
+
|
|
246
378
|
const signatureText = await this.unsafe_createInboxSignatureText();
|
|
247
379
|
|
|
248
380
|
// if the signature text is not available, the client is already registered
|
|
@@ -260,12 +392,22 @@ export class Client extends ClientWorkerClass {
|
|
|
260
392
|
}
|
|
261
393
|
|
|
262
394
|
/**
|
|
395
|
+
* Adds a new account to the client inbox
|
|
396
|
+
*
|
|
263
397
|
* WARNING: This function should be used with caution. Adding a wallet already
|
|
264
|
-
* associated with an
|
|
398
|
+
* associated with an inbox ID will cause the wallet to lose access to
|
|
265
399
|
* that inbox.
|
|
266
400
|
*
|
|
267
401
|
* The `allowInboxReassign` parameter must be true to reassign an inbox
|
|
268
402
|
* already associated with a different account.
|
|
403
|
+
*
|
|
404
|
+
* Requires a signer, use `Client.create` to create a client with a signer.
|
|
405
|
+
*
|
|
406
|
+
* @param newAccountSigner - The signer for the new account
|
|
407
|
+
* @param allowInboxReassign - Whether to allow inbox reassignment
|
|
408
|
+
* @throws {AccountAlreadyAssociatedError} if the account is already associated with an inbox ID
|
|
409
|
+
* @throws {GenerateSignatureError} if the signature cannot be generated
|
|
410
|
+
* @throws {SignerUnavailableError} if no signer is available
|
|
269
411
|
*/
|
|
270
412
|
async unsafe_addAccount(
|
|
271
413
|
newAccountSigner: Signer,
|
|
@@ -277,9 +419,7 @@ export class Client extends ClientWorkerClass {
|
|
|
277
419
|
);
|
|
278
420
|
|
|
279
421
|
if (existingInboxId && !allowInboxReassign) {
|
|
280
|
-
throw new
|
|
281
|
-
`Signer address already associated with inbox ${existingInboxId}`,
|
|
282
|
-
);
|
|
422
|
+
throw new AccountAlreadyAssociatedError(existingInboxId);
|
|
283
423
|
}
|
|
284
424
|
|
|
285
425
|
const signatureText = await this.unsafe_addAccountSignatureText(
|
|
@@ -288,7 +428,7 @@ export class Client extends ClientWorkerClass {
|
|
|
288
428
|
);
|
|
289
429
|
|
|
290
430
|
if (!signatureText) {
|
|
291
|
-
throw new
|
|
431
|
+
throw new GenerateSignatureError(SignatureRequestType.AddWallet);
|
|
292
432
|
}
|
|
293
433
|
|
|
294
434
|
await this.unsafe_addSignature(
|
|
@@ -300,12 +440,25 @@ export class Client extends ClientWorkerClass {
|
|
|
300
440
|
await this.unsafe_applySignatures();
|
|
301
441
|
}
|
|
302
442
|
|
|
443
|
+
/**
|
|
444
|
+
* Removes an account from the client's inbox
|
|
445
|
+
*
|
|
446
|
+
* Requires a signer, use `Client.create` to create a client with a signer.
|
|
447
|
+
*
|
|
448
|
+
* @param accountIdentifier - The identifier of the account to remove
|
|
449
|
+
* @throws {GenerateSignatureError} if the signature cannot be generated
|
|
450
|
+
* @throws {SignerUnavailableError} if no signer is available
|
|
451
|
+
*/
|
|
303
452
|
async removeAccount(accountIdentifier: Identifier) {
|
|
453
|
+
if (!this.#signer) {
|
|
454
|
+
throw new SignerUnavailableError();
|
|
455
|
+
}
|
|
456
|
+
|
|
304
457
|
const signatureText =
|
|
305
458
|
await this.unsafe_removeAccountSignatureText(accountIdentifier);
|
|
306
459
|
|
|
307
460
|
if (!signatureText) {
|
|
308
|
-
throw new
|
|
461
|
+
throw new GenerateSignatureError(SignatureRequestType.RevokeWallet);
|
|
309
462
|
}
|
|
310
463
|
|
|
311
464
|
await this.unsafe_addSignature(
|
|
@@ -317,13 +470,25 @@ export class Client extends ClientWorkerClass {
|
|
|
317
470
|
await this.unsafe_applySignatures();
|
|
318
471
|
}
|
|
319
472
|
|
|
473
|
+
/**
|
|
474
|
+
* Revokes all other installations of the client's inbox
|
|
475
|
+
*
|
|
476
|
+
* Requires a signer, use `Client.create` to create a client with a signer.
|
|
477
|
+
*
|
|
478
|
+
* @throws {GenerateSignatureError} if the signature cannot be generated
|
|
479
|
+
* @throws {SignerUnavailableError} if no signer is available
|
|
480
|
+
*/
|
|
320
481
|
async revokeAllOtherInstallations() {
|
|
482
|
+
if (!this.#signer) {
|
|
483
|
+
throw new SignerUnavailableError();
|
|
484
|
+
}
|
|
485
|
+
|
|
321
486
|
const signatureText =
|
|
322
487
|
await this.unsafe_revokeAllOtherInstallationsSignatureText();
|
|
323
488
|
|
|
324
489
|
if (!signatureText) {
|
|
325
|
-
throw new
|
|
326
|
-
|
|
490
|
+
throw new GenerateSignatureError(
|
|
491
|
+
SignatureRequestType.RevokeInstallations,
|
|
327
492
|
);
|
|
328
493
|
}
|
|
329
494
|
|
|
@@ -336,12 +501,27 @@ export class Client extends ClientWorkerClass {
|
|
|
336
501
|
await this.unsafe_applySignatures();
|
|
337
502
|
}
|
|
338
503
|
|
|
504
|
+
/**
|
|
505
|
+
* Revokes specific installations of the client's inbox
|
|
506
|
+
*
|
|
507
|
+
* Requires a signer, use `Client.create` to create a client with a signer.
|
|
508
|
+
*
|
|
509
|
+
* @param installationIds - The installation IDs to revoke
|
|
510
|
+
* @throws {GenerateSignatureError} if the signature cannot be generated
|
|
511
|
+
* @throws {SignerUnavailableError} if no signer is available
|
|
512
|
+
*/
|
|
339
513
|
async revokeInstallations(installationIds: Uint8Array[]) {
|
|
514
|
+
if (!this.#signer) {
|
|
515
|
+
throw new SignerUnavailableError();
|
|
516
|
+
}
|
|
517
|
+
|
|
340
518
|
const signatureText =
|
|
341
519
|
await this.unsafe_revokeInstallationsSignatureText(installationIds);
|
|
342
520
|
|
|
343
521
|
if (!signatureText) {
|
|
344
|
-
throw new
|
|
522
|
+
throw new GenerateSignatureError(
|
|
523
|
+
SignatureRequestType.RevokeInstallations,
|
|
524
|
+
);
|
|
345
525
|
}
|
|
346
526
|
|
|
347
527
|
await this.unsafe_addSignature(
|
|
@@ -353,48 +533,107 @@ export class Client extends ClientWorkerClass {
|
|
|
353
533
|
await this.unsafe_applySignatures();
|
|
354
534
|
}
|
|
355
535
|
|
|
536
|
+
/**
|
|
537
|
+
* Changes the recovery identifier for the client's inbox
|
|
538
|
+
*
|
|
539
|
+
* Requires a signer, use `Client.create` to create a client with a signer.
|
|
540
|
+
*
|
|
541
|
+
* @param identifier - The new recovery identifier
|
|
542
|
+
* @throws {GenerateSignatureError} if the signature cannot be generated
|
|
543
|
+
* @throws {SignerUnavailableError} if no signer is available
|
|
544
|
+
*/
|
|
545
|
+
async changeRecoveryIdentifier(identifier: Identifier) {
|
|
546
|
+
if (!this.#signer) {
|
|
547
|
+
throw new SignerUnavailableError();
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const signatureText =
|
|
551
|
+
await this.unsafe_changeRecoveryIdentifierSignatureText(identifier);
|
|
552
|
+
|
|
553
|
+
if (!signatureText) {
|
|
554
|
+
throw new GenerateSignatureError(
|
|
555
|
+
SignatureRequestType.ChangeRecoveryIdentifier,
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
await this.unsafe_addSignature(
|
|
560
|
+
SignatureRequestType.ChangeRecoveryIdentifier,
|
|
561
|
+
signatureText,
|
|
562
|
+
this.#signer,
|
|
563
|
+
);
|
|
564
|
+
|
|
565
|
+
await this.unsafe_applySignatures();
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Checks if the client is registered with the XMTP network
|
|
570
|
+
*
|
|
571
|
+
* @returns Whether the client is registered
|
|
572
|
+
*/
|
|
356
573
|
async isRegistered() {
|
|
357
574
|
return this.sendMessage("isRegistered", undefined);
|
|
358
575
|
}
|
|
359
576
|
|
|
577
|
+
/**
|
|
578
|
+
* Checks if the client can message the specified identifiers
|
|
579
|
+
*
|
|
580
|
+
* @param identifiers - The identifiers to check
|
|
581
|
+
* @returns Whether the client can message the identifiers
|
|
582
|
+
*/
|
|
360
583
|
async canMessage(identifiers: Identifier[]) {
|
|
361
584
|
return this.sendMessage("canMessage", { identifiers });
|
|
362
585
|
}
|
|
363
586
|
|
|
587
|
+
/**
|
|
588
|
+
* Checks if the specified identifiers can be messaged
|
|
589
|
+
*
|
|
590
|
+
* @param identifiers - The identifiers to check
|
|
591
|
+
* @param env - Optional XMTP environment
|
|
592
|
+
* @returns Map of identifiers to whether they can be messaged
|
|
593
|
+
*/
|
|
364
594
|
static async canMessage(identifiers: Identifier[], env?: XmtpEnv) {
|
|
365
|
-
const
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const client = await Client.create(
|
|
374
|
-
signer,
|
|
375
|
-
window.crypto.getRandomValues(new Uint8Array(32)),
|
|
376
|
-
{
|
|
377
|
-
disableAutoRegister: true,
|
|
378
|
-
env,
|
|
379
|
-
},
|
|
380
|
-
);
|
|
381
|
-
return client.canMessage(identifiers);
|
|
595
|
+
const canMessageMap = new Map<string, boolean>();
|
|
596
|
+
const utils = new Utils();
|
|
597
|
+
for (const identifier of identifiers) {
|
|
598
|
+
const inboxId = await utils.getInboxIdForIdentifier(identifier, env);
|
|
599
|
+
canMessageMap.set(identifier.identifier, inboxId !== undefined);
|
|
600
|
+
}
|
|
601
|
+
utils.close();
|
|
602
|
+
return canMessageMap;
|
|
382
603
|
}
|
|
383
604
|
|
|
605
|
+
/**
|
|
606
|
+
* Finds the inbox ID for a given identifier
|
|
607
|
+
*
|
|
608
|
+
* @param identifier - The identifier to look up
|
|
609
|
+
* @returns The inbox ID, if found
|
|
610
|
+
*/
|
|
384
611
|
async findInboxIdByIdentifier(identifier: Identifier) {
|
|
385
612
|
return this.sendMessage("findInboxIdByIdentifier", { identifier });
|
|
386
613
|
}
|
|
387
614
|
|
|
615
|
+
/**
|
|
616
|
+
* Gets the codec for a given content type
|
|
617
|
+
*
|
|
618
|
+
* @param contentType - The content type to get the codec for
|
|
619
|
+
* @returns The codec, if found
|
|
620
|
+
*/
|
|
388
621
|
codecFor(contentType: ContentTypeId) {
|
|
389
622
|
return this.#codecs.get(contentType.toString());
|
|
390
623
|
}
|
|
391
624
|
|
|
625
|
+
/**
|
|
626
|
+
* Encodes content for a given content type
|
|
627
|
+
*
|
|
628
|
+
* @param content - The content to encode
|
|
629
|
+
* @param contentType - The content type to encode for
|
|
630
|
+
* @returns The encoded content
|
|
631
|
+
* @throws {CodecNotFoundError} if no codec is found for the content type
|
|
632
|
+
*/
|
|
392
633
|
encodeContent(content: any, contentType: ContentTypeId) {
|
|
393
634
|
const codec = this.codecFor(contentType);
|
|
394
635
|
if (!codec) {
|
|
395
|
-
throw new
|
|
396
|
-
`Codec not found for "${contentType.toString()}" content type`,
|
|
397
|
-
);
|
|
636
|
+
throw new CodecNotFoundError(contentType);
|
|
398
637
|
}
|
|
399
638
|
const encoded = codec.encode(content, this);
|
|
400
639
|
const fallback = codec.fallback(content);
|
|
@@ -404,12 +643,19 @@ export class Client extends ClientWorkerClass {
|
|
|
404
643
|
return toSafeEncodedContent(encoded);
|
|
405
644
|
}
|
|
406
645
|
|
|
646
|
+
/**
|
|
647
|
+
* Decodes a message for a given content type
|
|
648
|
+
*
|
|
649
|
+
* @param message - The message to decode
|
|
650
|
+
* @param contentType - The content type to decode for
|
|
651
|
+
* @returns The decoded content
|
|
652
|
+
* @throws {CodecNotFoundError} if no codec is found for the content type
|
|
653
|
+
* @throws {InvalidGroupMembershipChangeError} if the message is an invalid group membership change
|
|
654
|
+
*/
|
|
407
655
|
decodeContent(message: SafeMessage, contentType: ContentTypeId) {
|
|
408
656
|
const codec = this.codecFor(contentType);
|
|
409
657
|
if (!codec) {
|
|
410
|
-
throw new
|
|
411
|
-
`Codec not found for "${contentType.toString()}" content type`,
|
|
412
|
-
);
|
|
658
|
+
throw new CodecNotFoundError(contentType);
|
|
413
659
|
}
|
|
414
660
|
|
|
415
661
|
// throw an error if there's an invalid group membership change message
|
|
@@ -417,7 +663,7 @@ export class Client extends ClientWorkerClass {
|
|
|
417
663
|
contentType.sameAs(ContentTypeGroupUpdated) &&
|
|
418
664
|
message.kind !== GroupMessageKind.MembershipChange
|
|
419
665
|
) {
|
|
420
|
-
throw new
|
|
666
|
+
throw new InvalidGroupMembershipChangeError(message.id);
|
|
421
667
|
}
|
|
422
668
|
|
|
423
669
|
const encodedContent = fromSafeEncodedContent(message.content);
|
|
@@ -425,10 +671,23 @@ export class Client extends ClientWorkerClass {
|
|
|
425
671
|
return codec.decode(encodedContent, this);
|
|
426
672
|
}
|
|
427
673
|
|
|
674
|
+
/**
|
|
675
|
+
* Signs a message with the installation key
|
|
676
|
+
*
|
|
677
|
+
* @param signatureText - The text to sign
|
|
678
|
+
* @returns The signature
|
|
679
|
+
*/
|
|
428
680
|
signWithInstallationKey(signatureText: string) {
|
|
429
681
|
return this.sendMessage("signWithInstallationKey", { signatureText });
|
|
430
682
|
}
|
|
431
683
|
|
|
684
|
+
/**
|
|
685
|
+
* Verifies a signature was made with the installation key
|
|
686
|
+
*
|
|
687
|
+
* @param signatureText - The text that was signed
|
|
688
|
+
* @param signatureBytes - The signature bytes to verify
|
|
689
|
+
* @returns Whether the signature is valid
|
|
690
|
+
*/
|
|
432
691
|
verifySignedWithInstallationKey(
|
|
433
692
|
signatureText: string,
|
|
434
693
|
signatureBytes: Uint8Array,
|
|
@@ -439,6 +698,14 @@ export class Client extends ClientWorkerClass {
|
|
|
439
698
|
});
|
|
440
699
|
}
|
|
441
700
|
|
|
701
|
+
/**
|
|
702
|
+
* Verifies a signature was made with a public key
|
|
703
|
+
*
|
|
704
|
+
* @param signatureText - The text that was signed
|
|
705
|
+
* @param signatureBytes - The signature bytes to verify
|
|
706
|
+
* @param publicKey - The public key to verify against
|
|
707
|
+
* @returns Whether the signature is valid
|
|
708
|
+
*/
|
|
442
709
|
verifySignedWithPublicKey(
|
|
443
710
|
signatureText: string,
|
|
444
711
|
signatureBytes: Uint8Array,
|
|
@@ -450,4 +717,16 @@ export class Client extends ClientWorkerClass {
|
|
|
450
717
|
publicKey,
|
|
451
718
|
});
|
|
452
719
|
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Gets the key package statuses for the specified installation IDs
|
|
723
|
+
*
|
|
724
|
+
* @param installationIds - The installation IDs to check
|
|
725
|
+
* @returns The key package statuses
|
|
726
|
+
*/
|
|
727
|
+
async getKeyPackageStatusesForInstallationIds(installationIds: string[]) {
|
|
728
|
+
return this.sendMessage("getKeyPackageStatusesForInstallationIds", {
|
|
729
|
+
installationIds,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
453
732
|
}
|