@xmtp/node-sdk 5.5.0 → 6.0.0-dev.3f65d25

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.js CHANGED
@@ -1,5 +1,6 @@
1
- import { generateInboxId as generateInboxId$1, getInboxIdForIdentifier as getInboxIdForIdentifier$1, contentTypeIntent, contentTypeActions, contentTypeWalletSendCalls, contentTypeLeaveRequest, contentTypeReadReceipt, contentTypeGroupUpdated, contentTypeTransactionReference, contentTypeMultiRemoteAttachment, contentTypeRemoteAttachment, contentTypeAttachment, contentTypeReaction, contentTypeReply, contentTypeMarkdown, contentTypeText, createClient as createClient$1, revokeInstallationsSignatureRequest, applySignatureRequest, inboxStateFromInboxIds, verifySignedWithPublicKey, isAddressAuthorized, isInstallationAuthorized } from '@xmtp/node-bindings';
2
- export { ActionStyle, ConsentEntityType, ConsentState, ContentType, ConversationType, DeliveryStatus, GroupMembershipState, GroupMessageKind, GroupPermissionsOptions, IdentifierKind, ListConversationsOrderBy, LogLevel, MessageSortBy, MetadataField, PermissionLevel, PermissionPolicy, PermissionUpdateType, ReactionAction, ReactionSchema, SortDirection, contentTypeActions, contentTypeAttachment, contentTypeGroupUpdated, contentTypeIntent, contentTypeLeaveRequest, contentTypeMarkdown, contentTypeMultiRemoteAttachment, contentTypeReaction, contentTypeReadReceipt, contentTypeRemoteAttachment, contentTypeReply, contentTypeText, contentTypeTransactionReference, contentTypeWalletSendCalls, decryptAttachment, encodeActions, encodeAttachment, encodeIntent, encodeMarkdown, encodeMultiRemoteAttachment, encodeReaction, encodeReadReceipt, encodeRemoteAttachment, encodeText, encodeTransactionReference, encodeWalletSendCalls, encryptAttachment } from '@xmtp/node-bindings';
1
+ import { BackendBuilder, generateInboxId as generateInboxId$1, getInboxIdByIdentity, contentTypeIntent, contentTypeActions, contentTypeWalletSendCalls, contentTypeLeaveRequest, contentTypeReadReceipt, contentTypeGroupUpdated, contentTypeTransactionReference, contentTypeMultiRemoteAttachment, contentTypeRemoteAttachment, contentTypeAttachment, contentTypeReaction, contentTypeReply, contentTypeMarkdown, contentTypeText, createClientWithBackend, revokeInstallationsSignatureRequest, applySignatureRequest, fetchInboxStatesByInboxIds, verifySignedWithPublicKey, isAddressAuthorized, isInstallationAuthorized, Backend } from '@xmtp/node-bindings';
2
+ export { ActionStyle, BackupElementSelectionOption, ConsentEntityType, ConsentState, ContentType, ConversationType, DeliveryStatus, GroupMembershipState, GroupMessageKind, GroupPermissionsOptions, IdentifierKind, ListConversationsOrderBy, LogLevel, MessageSortBy, MetadataField, PermissionLevel, PermissionPolicy, PermissionUpdateType, ReactionAction, ReactionSchema, SortDirection, WorkerKind, contentTypeActions, contentTypeAttachment, contentTypeGroupUpdated, contentTypeIntent, contentTypeLeaveRequest, contentTypeMarkdown, contentTypeMultiRemoteAttachment, contentTypeReaction, contentTypeReadReceipt, contentTypeRemoteAttachment, contentTypeReply, contentTypeText, contentTypeTransactionReference, contentTypeWalletSendCalls, decryptAttachment, encodeActions, encodeAttachment, encodeIntent, encodeMarkdown, encodeMultiRemoteAttachment, encodeReaction, encodeReadReceipt, encodeRemoteAttachment, encodeText, encodeTransactionReference, encodeWalletSendCalls, encryptAttachment, flushTelemetry, initLogging } from '@xmtp/node-bindings';
3
+ import { randomBytes } from 'node:crypto';
3
4
  import { contentTypeToString } from '@xmtp/content-type-primitives';
4
5
  import { isPromise } from 'node:util/types';
5
6
  import { join } from 'node:path';
@@ -8,6 +9,7 @@ import process from 'node:process';
8
9
  /**
9
10
  * Pre-configured URLs for the XMTP network based on the environment
10
11
  *
12
+ * @deprecated Use `createBackend()` instead.
11
13
  * @constant
12
14
  * @property {string} local - The local URL for the XMTP network
13
15
  * @property {string} dev - The development URL for the XMTP network
@@ -30,6 +32,43 @@ const HistorySyncUrls = {
30
32
  local: "http://localhost:5558",
31
33
  dev: "https://message-history.dev.ephemera.network",
32
34
  production: "https://message-history.production.ephemera.network",
35
+ "testnet-staging": "https://message-history.dev.ephemera.network",
36
+ "testnet-dev": "https://message-history.dev.ephemera.network",
37
+ testnet: "https://message-history.dev.ephemera.network",
38
+ mainnet: "https://message-history.production.ephemera.network",
39
+ };
40
+
41
+ const envMap = {
42
+ local: "Local" /* BindingsEnv.Local */,
43
+ dev: "Dev" /* BindingsEnv.Dev */,
44
+ production: "Production" /* BindingsEnv.Production */,
45
+ "testnet-staging": "TestnetStaging" /* BindingsEnv.TestnetStaging */,
46
+ "testnet-dev": "TestnetDev" /* BindingsEnv.TestnetDev */,
47
+ testnet: "Testnet" /* BindingsEnv.Testnet */,
48
+ mainnet: "Mainnet" /* BindingsEnv.Mainnet */,
49
+ };
50
+ const reverseEnvMap = {
51
+ ["Local" /* BindingsEnv.Local */]: "local",
52
+ ["Dev" /* BindingsEnv.Dev */]: "dev",
53
+ ["Production" /* BindingsEnv.Production */]: "production",
54
+ ["TestnetStaging" /* BindingsEnv.TestnetStaging */]: "testnet-staging",
55
+ ["TestnetDev" /* BindingsEnv.TestnetDev */]: "testnet-dev",
56
+ ["Testnet" /* BindingsEnv.Testnet */]: "testnet",
57
+ ["Mainnet" /* BindingsEnv.Mainnet */]: "mainnet",
58
+ };
59
+ const envToString = (env) => {
60
+ return reverseEnvMap[env];
61
+ };
62
+ const createBackend = async (options) => {
63
+ const env = options?.env ?? "dev";
64
+ const builder = new BackendBuilder(envMap[env]);
65
+ if (options?.apiUrl)
66
+ builder.setApiUrl(options.apiUrl);
67
+ if (options?.gatewayHost)
68
+ builder.setGatewayHost(options.gatewayHost);
69
+ if (options?.appVersion)
70
+ builder.setAppVersion(options.appVersion);
71
+ return builder.build();
33
72
  };
34
73
 
35
74
  class InboxReassignError extends Error {
@@ -72,10 +111,8 @@ class StreamInvalidRetryAttemptsError extends Error {
72
111
  const generateInboxId = (identifier, nonce) => {
73
112
  return generateInboxId$1(identifier, nonce);
74
113
  };
75
- const getInboxIdForIdentifier = async (identifier, env = "dev", gatewayHost) => {
76
- const host = ApiUrls[env];
77
- const isSecure = host.startsWith("https");
78
- return getInboxIdForIdentifier$1(host, gatewayHost, isSecure, identifier);
114
+ const getInboxIdForIdentifier = async (backend, identifier) => {
115
+ return getInboxIdByIdentity(backend, identifier);
79
116
  };
80
117
 
81
118
  function isHexString(value) {
@@ -709,7 +746,7 @@ class Conversation {
709
746
  * @returns The HMAC keys for this conversation
710
747
  */
711
748
  hmacKeys() {
712
- return this.#conversation.getHmacKeys();
749
+ return this.#conversation.hmacKeys();
713
750
  }
714
751
  /**
715
752
  * Gets the metadata for this conversation
@@ -785,8 +822,10 @@ class Conversation {
785
822
  * @param sendOptions - Options for sending the message
786
823
  * @param sendOptions.shouldPush - Indicates whether this message should be
787
824
  * included in push notifications
788
- * @param sendOptions.isOptimistic - Indicates whether this message should be
825
+ * @param sendOptions.optimistic - Indicates whether this message should be
789
826
  * sent optimistically and published later via `publishMessages`
827
+ * @param sendOptions.idempotencyKey - Optional idempotency key; re-sending
828
+ * identical content with the same key produces the same deduplicated message id
790
829
  * @returns Promise that resolves with the message ID after it has been sent
791
830
  */
792
831
  async send(encodedContent, sendOptions) {
@@ -799,121 +838,120 @@ class Conversation {
799
838
  * Sends a text message
800
839
  *
801
840
  * @param text - The text to send
802
- * @param isOptimistic - Whether to send the message optimistically
841
+ * @param opts - Send options (optimistic delivery, idempotency key)
803
842
  * @returns Promise that resolves with the message ID after it has been sent
804
843
  */
805
- async sendText(text, isOptimistic) {
806
- return this.#conversation.sendText(text, isOptimistic);
844
+ async sendText(text, opts) {
845
+ return this.#conversation.sendText(text, opts);
807
846
  }
808
847
  /**
809
848
  * Sends a markdown message
810
849
  *
811
850
  * @param markdown - The markdown to send
812
- * @param isOptimistic - Whether to send the message optimistically
851
+ * @param opts - Send options (optimistic delivery, idempotency key)
813
852
  * @returns Promise that resolves with the message ID after it has been sent
814
853
  */
815
- async sendMarkdown(markdown, isOptimistic) {
816
- return this.#conversation.sendMarkdown(markdown, isOptimistic);
854
+ async sendMarkdown(markdown, opts) {
855
+ return this.#conversation.sendMarkdown(markdown, opts);
817
856
  }
818
857
  /**
819
858
  * Sends a reaction message
820
859
  *
821
860
  * @param reaction - The reaction to send
822
- * @param isOptimistic - Whether to send the message optimistically
861
+ * @param opts - Send options (optimistic delivery, idempotency key)
823
862
  * @returns Promise that resolves with the message ID after it has been sent
824
863
  */
825
- async sendReaction(reaction, isOptimistic) {
826
- return this.#conversation.sendReaction(reaction, isOptimistic);
864
+ async sendReaction(reaction, opts) {
865
+ return this.#conversation.sendReaction(reaction, opts);
827
866
  }
828
867
  /**
829
868
  * Sends a read receipt message
830
869
  *
831
- * @param readReceipt - The read receipt to send
832
- * @param isOptimistic - Whether to send the message optimistically
870
+ * @param opts - Send options (optimistic delivery, idempotency key)
833
871
  * @returns Promise that resolves with the message ID after it has been sent
834
872
  */
835
- async sendReadReceipt(isOptimistic) {
836
- return this.#conversation.sendReadReceipt(isOptimistic);
873
+ async sendReadReceipt(opts) {
874
+ return this.#conversation.sendReadReceipt(opts);
837
875
  }
838
876
  /**
839
877
  * Sends a reply message
840
878
  *
841
879
  * @param reply - The reply to send
842
- * @param isOptimistic - Whether to send the message optimistically
880
+ * @param opts - Send options (optimistic delivery, idempotency key)
843
881
  * @returns Promise that resolves with the message ID after it has been sent
844
882
  */
845
- async sendReply(reply, isOptimistic) {
846
- return this.#conversation.sendReply(reply, isOptimistic);
883
+ async sendReply(reply, opts) {
884
+ return this.#conversation.sendReply(reply, opts);
847
885
  }
848
886
  /**
849
887
  * Sends a transaction reference message
850
888
  *
851
889
  * @param transactionReference - The transaction reference to send
852
- * @param isOptimistic - Whether to send the message optimistically
890
+ * @param opts - Send options (optimistic delivery, idempotency key)
853
891
  * @returns Promise that resolves with the message ID after it has been sent
854
892
  */
855
- async sendTransactionReference(transactionReference, isOptimistic) {
856
- return this.#conversation.sendTransactionReference(transactionReference, isOptimistic);
893
+ async sendTransactionReference(transactionReference, opts) {
894
+ return this.#conversation.sendTransactionReference(transactionReference, opts);
857
895
  }
858
896
  /**
859
897
  * Sends a wallet send calls message
860
898
  *
861
899
  * @param walletSendCalls - The wallet send calls to send
862
- * @param isOptimistic - Whether to send the message optimistically
900
+ * @param opts - Send options (optimistic delivery, idempotency key)
863
901
  * @returns Promise that resolves with the message ID after it has been sent
864
902
  */
865
- async sendWalletSendCalls(walletSendCalls, isOptimistic) {
866
- return this.#conversation.sendWalletSendCalls(walletSendCalls, isOptimistic);
903
+ async sendWalletSendCalls(walletSendCalls, opts) {
904
+ return this.#conversation.sendWalletSendCalls(walletSendCalls, opts);
867
905
  }
868
906
  /**
869
907
  * Sends a actions message
870
908
  *
871
909
  * @param actions - The actions to send
872
- * @param isOptimistic - Whether to send the message optimistically
910
+ * @param opts - Send options (optimistic delivery, idempotency key)
873
911
  * @returns Promise that resolves with the message ID after it has been sent
874
912
  */
875
- async sendActions(actions, isOptimistic) {
876
- return this.#conversation.sendActions(actions, isOptimistic);
913
+ async sendActions(actions, opts) {
914
+ return this.#conversation.sendActions(actions, opts);
877
915
  }
878
916
  /**
879
917
  * Sends a intent message
880
918
  *
881
919
  * @param intent - The intent to send
882
- * @param isOptimistic - Whether to send the message optimistically
920
+ * @param opts - Send options (optimistic delivery, idempotency key)
883
921
  * @returns Promise that resolves with the message ID after it has been sent
884
922
  */
885
- async sendIntent(intent, isOptimistic) {
886
- return this.#conversation.sendIntent(intent, isOptimistic);
923
+ async sendIntent(intent, opts) {
924
+ return this.#conversation.sendIntent(intent, opts);
887
925
  }
888
926
  /**
889
927
  * Sends an attachment message
890
928
  *
891
929
  * @param attachment - The attachment to send
892
- * @param isOptimistic - Whether to send the message optimistically
930
+ * @param opts - Send options (optimistic delivery, idempotency key)
893
931
  * @returns Promise that resolves with the message ID after it has been sent
894
932
  */
895
- async sendAttachment(attachment, isOptimistic) {
896
- return this.#conversation.sendAttachment(attachment, isOptimistic);
933
+ async sendAttachment(attachment, opts) {
934
+ return this.#conversation.sendAttachment(attachment, opts);
897
935
  }
898
936
  /**
899
937
  * Sends a multi remote attachment message
900
938
  *
901
939
  * @param multiRemoteAttachment - The multi remote attachment to send
902
- * @param isOptimistic - Whether to send the message optimistically
940
+ * @param opts - Send options (optimistic delivery, idempotency key)
903
941
  * @returns Promise that resolves with the message ID after it has been sent
904
942
  */
905
- async sendMultiRemoteAttachment(multiRemoteAttachment, isOptimistic) {
906
- return this.#conversation.sendMultiRemoteAttachment(multiRemoteAttachment, isOptimistic);
943
+ async sendMultiRemoteAttachment(multiRemoteAttachment, opts) {
944
+ return this.#conversation.sendMultiRemoteAttachment(multiRemoteAttachment, opts);
907
945
  }
908
946
  /**
909
947
  * Sends a remote attachment message
910
948
  *
911
949
  * @param remoteAttachment - The remote attachment to send
912
- * @param isOptimistic - Whether to send the message optimistically
950
+ * @param opts - Send options (optimistic delivery, idempotency key)
913
951
  * @returns Promise that resolves with the message ID after it has been sent
914
952
  */
915
- async sendRemoteAttachment(remoteAttachment, isOptimistic) {
916
- return this.#conversation.sendRemoteAttachment(remoteAttachment, isOptimistic);
953
+ async sendRemoteAttachment(remoteAttachment, opts) {
954
+ return this.#conversation.sendRemoteAttachment(remoteAttachment, opts);
917
955
  }
918
956
  /**
919
957
  * Lists messages in this conversation
@@ -922,7 +960,7 @@ class Conversation {
922
960
  * @returns Promise that resolves with an array of decoded messages
923
961
  */
924
962
  async messages(options) {
925
- const messages = await this.#conversation.findEnrichedMessages(options);
963
+ const messages = await this.#conversation.listEnrichedMessages(options);
926
964
  return messages.map((message) => new DecodedMessage(this.#codecRegistry, message));
927
965
  }
928
966
  /**
@@ -1016,7 +1054,7 @@ class Conversation {
1016
1054
  * (nanoseconds since epoch)
1017
1055
  */
1018
1056
  async lastReadTimes() {
1019
- return this.#conversation.getLastReadTimes();
1057
+ return this.#conversation.lastReadTimes();
1020
1058
  }
1021
1059
  }
1022
1060
 
@@ -1051,7 +1089,7 @@ class Dm extends Conversation {
1051
1089
  return this.#conversation.dmPeerInboxId();
1052
1090
  }
1053
1091
  async duplicateDms() {
1054
- const duplicateDms = await this.#conversation.findDuplicateDms();
1092
+ const duplicateDms = await this.#conversation.duplicateDms();
1055
1093
  return duplicateDms.map((dm) => new Dm(this.#client, this.#codecRegistry, dm));
1056
1094
  }
1057
1095
  }
@@ -1154,13 +1192,13 @@ class Group extends Conversation {
1154
1192
  * The list of admins of the group
1155
1193
  */
1156
1194
  listAdmins() {
1157
- return this.#conversation.adminList();
1195
+ return this.#conversation.listAdmins();
1158
1196
  }
1159
1197
  /**
1160
1198
  * The list of super admins of the group
1161
1199
  */
1162
1200
  listSuperAdmins() {
1163
- return this.#conversation.superAdminList();
1201
+ return this.#conversation.listSuperAdmins();
1164
1202
  }
1165
1203
  /**
1166
1204
  * Checks if an inbox is an admin of the group
@@ -1186,7 +1224,7 @@ class Group extends Conversation {
1186
1224
  * @param identifiers Array of member identifiers to add
1187
1225
  */
1188
1226
  async addMembersByIdentifiers(identifiers) {
1189
- return this.#conversation.addMembers(identifiers);
1227
+ return this.#conversation.addMembersByIdentity(identifiers);
1190
1228
  }
1191
1229
  /**
1192
1230
  * Adds members to the group using inbox IDs
@@ -1194,7 +1232,7 @@ class Group extends Conversation {
1194
1232
  * @param inboxIds Array of inbox IDs to add
1195
1233
  */
1196
1234
  async addMembers(inboxIds) {
1197
- return this.#conversation.addMembersByInboxId(inboxIds);
1235
+ return this.#conversation.addMembers(inboxIds);
1198
1236
  }
1199
1237
  /**
1200
1238
  * Removes members from the group using identifiers
@@ -1202,7 +1240,7 @@ class Group extends Conversation {
1202
1240
  * @param identifiers Array of member identifiers to remove
1203
1241
  */
1204
1242
  async removeMembersByIdentifiers(identifiers) {
1205
- return this.#conversation.removeMembers(identifiers);
1243
+ return this.#conversation.removeMembersByIdentity(identifiers);
1206
1244
  }
1207
1245
  /**
1208
1246
  * Removes members from the group using inbox IDs
@@ -1210,7 +1248,7 @@ class Group extends Conversation {
1210
1248
  * @param inboxIds Array of inbox IDs to remove
1211
1249
  */
1212
1250
  async removeMembers(inboxIds) {
1213
- return this.#conversation.removeMembersByInboxId(inboxIds);
1251
+ return this.#conversation.removeMembers(inboxIds);
1214
1252
  }
1215
1253
  /**
1216
1254
  * Promotes a group member to admin status
@@ -1294,8 +1332,8 @@ class Conversations {
1294
1332
  */
1295
1333
  async getConversationById(id) {
1296
1334
  try {
1297
- // findGroupById will throw if group is not found
1298
- const group = this.#conversations.findGroupById(id);
1335
+ // getConversationById will throw if group is not found
1336
+ const group = this.#conversations.getConversationById(id);
1299
1337
  const metadata = await group.groupMetadata();
1300
1338
  switch (metadata.conversationType()) {
1301
1339
  case 1 /* ConversationType.Group */:
@@ -1319,8 +1357,8 @@ class Conversations {
1319
1357
  */
1320
1358
  getDmByInboxId(inboxId) {
1321
1359
  try {
1322
- // findDmByTargetInboxId will throw if group is not found
1323
- const group = this.#conversations.findDmByTargetInboxId(inboxId);
1360
+ // getDmByInboxId will throw if group is not found
1361
+ const group = this.#conversations.getDmByInboxId(inboxId);
1324
1362
  return new Dm(this.#client, this.#codecRegistry, group);
1325
1363
  }
1326
1364
  catch {
@@ -1350,8 +1388,8 @@ class Conversations {
1350
1388
  */
1351
1389
  getMessageById(id) {
1352
1390
  try {
1353
- // findEnrichedMessageById will throw if message is not found
1354
- const message = this.#conversations.findEnrichedMessageById(id);
1391
+ // getEnrichedMessageById will throw if message is not found
1392
+ const message = this.#conversations.getEnrichedMessageById(id);
1355
1393
  return new DecodedMessage(this.#codecRegistry, message);
1356
1394
  }
1357
1395
  catch {
@@ -1378,7 +1416,7 @@ class Conversations {
1378
1416
  * @see https://docs.xmtp.org/chat-apps/core-messaging/create-conversations#create-a-new-group-chat
1379
1417
  */
1380
1418
  async createGroupWithIdentifiers(identifiers, options) {
1381
- const group = await this.#conversations.createGroup(identifiers, options);
1419
+ const group = await this.#conversations.createGroupByIdentity(identifiers, options);
1382
1420
  const conversation = new Group(this.#client, this.#codecRegistry, group);
1383
1421
  return conversation;
1384
1422
  }
@@ -1391,7 +1429,7 @@ class Conversations {
1391
1429
  * @see https://docs.xmtp.org/chat-apps/core-messaging/create-conversations#create-a-new-group-chat
1392
1430
  */
1393
1431
  async createGroup(inboxIds, options) {
1394
- const group = await this.#conversations.createGroupByInboxId(inboxIds, options);
1432
+ const group = await this.#conversations.createGroup(inboxIds, options);
1395
1433
  const conversation = new Group(this.#client, this.#codecRegistry, group);
1396
1434
  return conversation;
1397
1435
  }
@@ -1404,7 +1442,7 @@ class Conversations {
1404
1442
  * @see https://docs.xmtp.org/agents/build-agents/create-conversations#by-ethereum-address-1
1405
1443
  */
1406
1444
  async createDmWithIdentifier(identifier, options) {
1407
- const group = await this.#conversations.createDm(identifier, options);
1445
+ const group = await this.#conversations.createDmByIdentity(identifier, options);
1408
1446
  const conversation = new Dm(this.#client, this.#codecRegistry, group);
1409
1447
  return conversation;
1410
1448
  }
@@ -1417,7 +1455,7 @@ class Conversations {
1417
1455
  * @see https://docs.xmtp.org/agents/build-agents/create-conversations#by-inbox-id-1
1418
1456
  */
1419
1457
  async createDm(inboxId, options) {
1420
- const group = await this.#conversations.createDmByInboxId(inboxId, options);
1458
+ const group = await this.#conversations.createDm(inboxId, options);
1421
1459
  const conversation = new Dm(this.#client, this.#codecRegistry, group);
1422
1460
  return conversation;
1423
1461
  }
@@ -1496,7 +1534,7 @@ class Conversations {
1496
1534
  * @see https://docs.xmtp.org/chat-apps/list-stream-sync/sync-and-syncall#sync-all-new-welcomes-conversations-messages-and-preferences
1497
1535
  */
1498
1536
  async syncAll(consentStates) {
1499
- return this.#conversations.syncAllConversations(consentStates);
1537
+ return this.#conversations.syncAll(consentStates);
1500
1538
  }
1501
1539
  /**
1502
1540
  * Creates a stream for new conversations
@@ -1664,7 +1702,7 @@ class Conversations {
1664
1702
  * @see https://docs.xmtp.org/chat-apps/push-notifs/push-notifs#get-hmac-keys-for-a-conversation
1665
1703
  */
1666
1704
  hmacKeys() {
1667
- return this.#conversations.getHmacKeys();
1705
+ return this.#conversations.hmacKeys();
1668
1706
  }
1669
1707
  }
1670
1708
 
@@ -1711,7 +1749,7 @@ class Preferences {
1711
1749
  this.#conversations = conversations;
1712
1750
  }
1713
1751
  sync() {
1714
- return this.#client.syncPreferences();
1752
+ return this.#conversations.syncPreferences();
1715
1753
  }
1716
1754
  /**
1717
1755
  * Retrieves the current inbox state of this client from the local database
@@ -1737,7 +1775,7 @@ class Preferences {
1737
1775
  * @returns Promise that resolves with the inbox states for the inbox IDs
1738
1776
  */
1739
1777
  async getInboxStates(inboxIds) {
1740
- return this.#client.addressesFromInboxId(false, inboxIds);
1778
+ return this.#client.fetchInboxStatesByInboxIds(inboxIds, false);
1741
1779
  }
1742
1780
  /**
1743
1781
  * Retrieves the latest inbox states for specified inbox IDs from the network
@@ -1746,7 +1784,7 @@ class Preferences {
1746
1784
  * @returns Promise that resolves with the inbox states for the inbox IDs
1747
1785
  */
1748
1786
  async fetchInboxStates(inboxIds) {
1749
- return this.#client.addressesFromInboxId(true, inboxIds);
1787
+ return this.#client.fetchInboxStatesByInboxIds(inboxIds, true);
1750
1788
  }
1751
1789
  /**
1752
1790
  * Updates consent states for multiple records
@@ -1799,13 +1837,36 @@ class Preferences {
1799
1837
  }
1800
1838
  }
1801
1839
 
1840
+ const networkOptionKeys = [
1841
+ "env",
1842
+ "apiUrl",
1843
+ "gatewayHost",
1844
+ "appVersion",
1845
+ ];
1846
+ const hasBackend = (options) => {
1847
+ return "backend" in options;
1848
+ };
1849
+ const resolveBackend$1 = async (options) => {
1850
+ if (!options) {
1851
+ return createBackend();
1852
+ }
1853
+ if (hasBackend(options)) {
1854
+ // Validate that no NetworkOptions fields are also set
1855
+ const conflicting = networkOptionKeys.filter((key) => key in options && options[key] != null);
1856
+ if (conflicting.length > 0) {
1857
+ throw new Error(`Cannot specify both 'backend' and network options (${conflicting.join(", ")}). ` +
1858
+ `Use either a pre-built Backend or network options, not both.`);
1859
+ }
1860
+ return options.backend;
1861
+ }
1862
+ // No backend provided — build one from NetworkOptions
1863
+ return createBackend(options);
1864
+ };
1802
1865
  const createClient = async (identifier, options) => {
1803
- const env = options?.env || "dev";
1804
- const host = options?.apiUrl || ApiUrls[env];
1805
- const gatewayHost = options?.gatewayHost || undefined;
1806
- const isSecure = host.startsWith("https");
1807
- const inboxId = (await getInboxIdForIdentifier(identifier, env, gatewayHost)) ||
1866
+ const backend = await resolveBackend$1(options);
1867
+ const inboxId = (await getInboxIdForIdentifier(backend, identifier)) ||
1808
1868
  generateInboxId(identifier, options?.nonce);
1869
+ const env = envToString(backend.env);
1809
1870
  let dbPath;
1810
1871
  if (options?.dbPath === undefined) {
1811
1872
  // Default: auto-generated path
@@ -1822,19 +1883,50 @@ const createClient = async (identifier, options) => {
1822
1883
  const logOptions = {
1823
1884
  structured: options?.structuredLogging ?? false,
1824
1885
  level: options?.loggingLevel ?? "Off" /* LogLevel.Off */,
1886
+ stdoutLevel: options?.stdoutLoggingLevel,
1887
+ otelEndpoint: options?.otelEndpoint,
1888
+ resourceAttributes: options?.resourceAttributes,
1825
1889
  };
1826
- const historySyncUrl = options?.historySyncUrl === undefined
1827
- ? HistorySyncUrls[env]
1828
- : options.historySyncUrl;
1829
1890
  const deviceSyncWorkerMode = options?.disableDeviceSync
1830
1891
  ? "Disabled" /* SyncWorkerMode.Disabled */
1831
1892
  : "Enabled" /* SyncWorkerMode.Enabled */;
1832
1893
  const dbEncryptionKey = isHexString(options?.dbEncryptionKey)
1833
1894
  ? Buffer.from(options.dbEncryptionKey.replace(/^0x/, ""), "hex")
1834
1895
  : options?.dbEncryptionKey;
1835
- return createClient$1(host, gatewayHost, isSecure, dbPath, inboxId, identifier, dbEncryptionKey, historySyncUrl, deviceSyncWorkerMode, logOptions, undefined, options?.appVersion);
1896
+ const client = await createClientWithBackend(backend, {
1897
+ dbPath: dbPath ?? undefined,
1898
+ encryptionKey: dbEncryptionKey,
1899
+ maxDbPoolSize: options?.maxDbPoolSize,
1900
+ minDbPoolSize: options?.minDbPoolSize,
1901
+ useSingleConnection: options?.useSingleConnection,
1902
+ }, inboxId, identifier, deviceSyncWorkerMode, options?.workerConfig, logOptions, undefined, // allowOffline
1903
+ options?.nonce);
1904
+ return { client, env };
1836
1905
  };
1837
1906
 
1907
+ /**
1908
+ * Resolves a `Backend` instance from either a `Backend` or an `XmtpEnv` string.
1909
+ *
1910
+ * @param envOrBackend - A `Backend` instance, or an `XmtpEnv` string
1911
+ * @param gatewayHost - Optional gateway host (only used when `envOrBackend` is an `XmtpEnv`)
1912
+ * @returns A `Backend` instance
1913
+ */
1914
+ const resolveBackend = async (envOrBackend, gatewayHost) => {
1915
+ if (envOrBackend instanceof Backend) {
1916
+ return envOrBackend;
1917
+ }
1918
+ return createBackend({ env: envOrBackend, gatewayHost });
1919
+ };
1920
+ const createEphemeralIdentifier = () => ({
1921
+ identifier: `0x${randomBytes(20).toString("hex")}`,
1922
+ identifierKind: 0 /* IdentifierKind.Ethereum */,
1923
+ });
1924
+ const toInboxUpdatesCountMap = (value) => {
1925
+ if (value instanceof Map) {
1926
+ return value;
1927
+ }
1928
+ return new Map(Object.entries(value));
1929
+ };
1838
1930
  /**
1839
1931
  * Client for interacting with the XMTP network
1840
1932
  */
@@ -1843,6 +1935,7 @@ class Client {
1843
1935
  #codecRegistry;
1844
1936
  #conversations;
1845
1937
  #debugInformation;
1938
+ #env;
1846
1939
  #preferences;
1847
1940
  #signer;
1848
1941
  #identifier;
@@ -1872,7 +1965,9 @@ class Client {
1872
1965
  return;
1873
1966
  }
1874
1967
  this.#identifier = identifier;
1875
- this.#client = await createClient(identifier, this.#options);
1968
+ const { client, env } = await createClient(identifier, this.#options);
1969
+ this.#client = client;
1970
+ this.#env = env;
1876
1971
  const conversations = this.#client.conversations();
1877
1972
  this.#conversations = new Conversations(this, this.#codecRegistry, conversations);
1878
1973
  this.#debugInformation = new DebugInformation(this.#client);
@@ -1925,6 +2020,17 @@ class Client {
1925
2020
  get appVersion() {
1926
2021
  return this.#client?.appVersion();
1927
2022
  }
2023
+ /**
2024
+ * Gets the XMTP environment the client is connected to
2025
+ *
2026
+ * @throws {ClientNotInitializedError} if the client is not initialized
2027
+ */
2028
+ get env() {
2029
+ if (!this.#env) {
2030
+ throw new ClientNotInitializedError();
2031
+ }
2032
+ return this.#env;
2033
+ }
1928
2034
  /**
1929
2035
  * Gets the client options
1930
2036
  */
@@ -2014,6 +2120,24 @@ class Client {
2014
2120
  }
2015
2121
  return this.#preferences;
2016
2122
  }
2123
+ /**
2124
+ * Cleanly shuts down the client: cancels in-flight workers and detached
2125
+ * streams, then releases the database connection.
2126
+ *
2127
+ * This is idempotent — calling it more than once resolves without error.
2128
+ * Await this before deleting the database file or dropping the client
2129
+ * reference to avoid log noise from background tasks running against a
2130
+ * closed database.
2131
+ *
2132
+ * @throws {ClientNotInitializedError} if the client is not initialized
2133
+ * @returns Promise that resolves when the client has shut down
2134
+ */
2135
+ async close() {
2136
+ if (!this.#client) {
2137
+ throw new ClientNotInitializedError();
2138
+ }
2139
+ return this.#client.close();
2140
+ }
2017
2141
  /**
2018
2142
  * Adds a signature to a signature request using the client's signer (or the
2019
2143
  * provided signer)
@@ -2206,7 +2330,7 @@ class Client {
2206
2330
  return;
2207
2331
  }
2208
2332
  await this.unsafe_addSignature(signatureRequest);
2209
- await this.#client?.registerIdentity(signatureRequest);
2333
+ await this.#client?.registerIdentity(signatureRequest, this.#options?.waitForRegistrationVisible);
2210
2334
  }
2211
2335
  /**
2212
2336
  * Adds a new account to the client inbox
@@ -2282,18 +2406,10 @@ class Client {
2282
2406
  await this.unsafe_addSignature(signatureRequest);
2283
2407
  await this.unsafe_applySignatureRequest(signatureRequest);
2284
2408
  }
2285
- /**
2286
- * Revokes specific installations of the client's inbox without a client
2287
- *
2288
- * @param env - The environment to use
2289
- * @param signer - The signer to use
2290
- * @param inboxId - The inbox ID to revoke installations for
2291
- * @param installationIds - The installation IDs to revoke
2292
- */
2293
- static async revokeInstallations(signer, inboxId, installationIds, env, gatewayHost) {
2294
- const host = ApiUrls[env ?? "dev"];
2409
+ static async revokeInstallations(signer, inboxId, installationIds, envOrBackend, gatewayHost) {
2410
+ const backend = await resolveBackend(envOrBackend, gatewayHost);
2295
2411
  const identifier = await signer.getIdentifier();
2296
- const signatureRequest = await revokeInstallationsSignatureRequest(host, gatewayHost, identifier, inboxId, installationIds);
2412
+ const signatureRequest = await revokeInstallationsSignatureRequest(backend, identifier, inboxId, installationIds);
2297
2413
  const signatureText = await signatureRequest.signatureText();
2298
2414
  const signature = await signer.signMessage(signatureText);
2299
2415
  switch (signer.type) {
@@ -2304,7 +2420,7 @@ class Client {
2304
2420
  await signatureRequest.addEcdsaSignature(signature);
2305
2421
  break;
2306
2422
  }
2307
- await applySignatureRequest(host, gatewayHost, signatureRequest);
2423
+ await applySignatureRequest(backend, signatureRequest);
2308
2424
  }
2309
2425
  /**
2310
2426
  * Changes the recovery identifier for the client's inbox
@@ -2334,6 +2450,32 @@ class Client {
2334
2450
  const canMessage = await this.#client.canMessage(identifiers);
2335
2451
  return new Map(Object.entries(canMessage));
2336
2452
  }
2453
+ /**
2454
+ * Fetches the latest inbox updates count for the specified inbox IDs
2455
+ *
2456
+ * @param inboxIds - The inbox IDs to check
2457
+ * @returns Map of inbox IDs to their updates count
2458
+ * @throws {ClientNotInitializedError} if the client is not initialized
2459
+ */
2460
+ async fetchLatestInboxUpdatesCount(inboxIds) {
2461
+ if (!this.#client) {
2462
+ throw new ClientNotInitializedError();
2463
+ }
2464
+ const result = await this.#client.fetchInboxUpdatesCount(inboxIds, true);
2465
+ return toInboxUpdatesCountMap(result);
2466
+ }
2467
+ /**
2468
+ * Fetches the latest inbox updates count for the client's inbox
2469
+ *
2470
+ * @returns The latest inbox updates count
2471
+ * @throws {ClientNotInitializedError} if the client is not initialized
2472
+ */
2473
+ async fetchOwnInboxUpdatesCount() {
2474
+ if (!this.#client) {
2475
+ throw new ClientNotInitializedError();
2476
+ }
2477
+ return this.#client.fetchOwnInboxUpdatesCount(true);
2478
+ }
2337
2479
  /**
2338
2480
  * Fetches the key package statuses from the network for the specified
2339
2481
  * installation IDs
@@ -2346,7 +2488,7 @@ class Client {
2346
2488
  if (!this.#client) {
2347
2489
  throw new ClientNotInitializedError();
2348
2490
  }
2349
- return this.#client.getKeyPackageStatusesForInstallationIds(installationIds);
2491
+ return this.#client.fetchKeyPackageStatusesByInstallationIds(installationIds);
2350
2492
  }
2351
2493
  /**
2352
2494
  * Fetches the inbox ID for a given identifier from the local database
@@ -2360,7 +2502,7 @@ class Client {
2360
2502
  if (!this.#client) {
2361
2503
  throw new ClientNotInitializedError();
2362
2504
  }
2363
- return this.#client.findInboxIdByIdentifier(identifier);
2505
+ return this.#client.getInboxIdByIdentity(identifier);
2364
2506
  }
2365
2507
  /**
2366
2508
  * Signs a message with the installation key
@@ -2395,29 +2537,31 @@ class Client {
2395
2537
  return false;
2396
2538
  }
2397
2539
  }
2398
- /**
2399
- * Fetches the inbox states for the specified inbox IDs from the network
2400
- * without a client
2401
- *
2402
- * @param env - The environment to use
2403
- * @param inboxIds - The inbox IDs to get the state for
2404
- * @returns The inbox states for the specified inbox IDs
2405
- */
2406
- static async fetchInboxStates(inboxIds, env, gatewayHost) {
2407
- const host = ApiUrls[env ?? "dev"];
2408
- return inboxStateFromInboxIds(host, gatewayHost, inboxIds);
2540
+ static async fetchInboxStates(inboxIds, envOrBackend, gatewayHost) {
2541
+ const backend = await resolveBackend(envOrBackend, gatewayHost);
2542
+ return fetchInboxStatesByInboxIds(backend, inboxIds);
2543
+ }
2544
+ static async fetchLatestInboxUpdatesCount(inboxIds, envOrBackend, gatewayHost) {
2545
+ const backend = await resolveBackend(envOrBackend, gatewayHost);
2546
+ // The node-bindings Client is a napi-rs class with no explicit close/free
2547
+ // method. Release is non-deterministic: once this reference goes out of
2548
+ // scope, JS GC will eventually invoke the Rust Drop impl and reclaim the
2549
+ // underlying resources. If this becomes a bottleneck, switch to an
2550
+ // explicit disposal API if/when the bindings expose one.
2551
+ const { client } = await createClient(createEphemeralIdentifier(), {
2552
+ backend,
2553
+ dbPath: null,
2554
+ disableDeviceSync: true,
2555
+ });
2556
+ const result = await client.fetchInboxUpdatesCount(inboxIds, true);
2557
+ return toInboxUpdatesCountMap(result);
2409
2558
  }
2410
- /**
2411
- * Checks if the specified identifiers can be messaged
2412
- *
2413
- * @param identifiers - The identifiers to check
2414
- * @param env - Optional XMTP environment
2415
- * @returns Map of identifiers to whether they can be messaged
2416
- */
2417
- static async canMessage(identifiers, env) {
2559
+ /* eslint-enable @typescript-eslint/unified-signatures */
2560
+ static async canMessage(identifiers, envOrBackend) {
2561
+ const backend = await resolveBackend(envOrBackend);
2418
2562
  const canMessageMap = new Map();
2419
2563
  for (const identifier of identifiers) {
2420
- const inboxId = await getInboxIdForIdentifier(identifier, env);
2564
+ const inboxId = await getInboxIdForIdentifier(backend, identifier);
2421
2565
  canMessageMap.set(identifier.identifier.toLowerCase(), inboxId !== null);
2422
2566
  }
2423
2567
  return canMessageMap;
@@ -2439,42 +2583,150 @@ class Client {
2439
2583
  return false;
2440
2584
  }
2441
2585
  }
2586
+ static async isAddressAuthorized(inboxId, address, envOrBackend, gatewayHost) {
2587
+ const backend = await resolveBackend(envOrBackend, gatewayHost);
2588
+ return await isAddressAuthorized(backend, inboxId, address);
2589
+ }
2590
+ static async isInstallationAuthorized(inboxId, installation, envOrBackend, gatewayHost) {
2591
+ const backend = await resolveBackend(envOrBackend, gatewayHost);
2592
+ return await isInstallationAuthorized(backend, inboxId, installation);
2593
+ }
2442
2594
  /**
2443
- * Checks if an address is authorized for an inbox
2444
- *
2445
- * @param inboxId - The inbox ID to check
2446
- * @param address - The address to check
2447
- * @param options - Optional network options
2448
- * @returns Whether the address is authorized
2595
+ * Get the default archive options (consent and messages)
2449
2596
  */
2450
- static async isAddressAuthorized(inboxId, address, env, gatewayHost) {
2451
- const host = ApiUrls[env ?? "dev"];
2452
- return await isAddressAuthorized(host, gatewayHost, inboxId, address);
2597
+ #getDefaultArchiveOptions() {
2598
+ return {
2599
+ elements: [
2600
+ "Consent" /* BackupElementSelectionOption.Consent */,
2601
+ "Messages" /* BackupElementSelectionOption.Messages */,
2602
+ ],
2603
+ excludeDisappearingMessages: false,
2604
+ };
2453
2605
  }
2454
2606
  /**
2455
- * Checks if an installation is authorized for an inbox
2456
- *
2457
- * @param inboxId - The inbox ID to check
2458
- * @param installation - The installation to check
2459
- * @param options - Optional network options
2460
- * @returns Whether the installation is authorized
2607
+ * Get the default server URL based on the environment
2461
2608
  */
2462
- static async isInstallationAuthorized(inboxId, installation, env, gatewayHost) {
2463
- const host = ApiUrls[env ?? "dev"];
2464
- return await isInstallationAuthorized(host, gatewayHost, inboxId, installation);
2609
+ #getDefaultServerUrl() {
2610
+ const env = this.env;
2611
+ return HistorySyncUrls[env];
2465
2612
  }
2466
2613
  /**
2467
2614
  * Send a sync request to other devices on the network
2468
2615
  *
2616
+ * @param options - Archive options specifying what to sync (defaults to consent and messages)
2617
+ * @param serverUrl - The server URL for the sync request (defaults to environment-specific URL)
2469
2618
  * @returns Promise that resolves when the sync request is sent
2470
2619
  */
2471
- async sendSyncRequest() {
2620
+ async sendSyncRequest(options, serverUrl) {
2621
+ if (!this.#client) {
2622
+ throw new ClientNotInitializedError();
2623
+ }
2624
+ const resolvedOptions = options ?? this.#getDefaultArchiveOptions();
2625
+ const resolvedServerUrl = serverUrl ?? this.#getDefaultServerUrl();
2626
+ return this.#client
2627
+ .deviceSync()
2628
+ .sendSyncRequest(resolvedOptions, resolvedServerUrl);
2629
+ }
2630
+ /**
2631
+ * Send a sync archive to the sync group
2632
+ *
2633
+ * @param pin - The pin used for reference when importing
2634
+ * @param options - Archive options specifying what to sync (defaults to consent and messages)
2635
+ * @param serverUrl - The server URL for the sync archive (defaults to environment-specific URL)
2636
+ * @returns Promise that resolves when the sync archive is sent
2637
+ */
2638
+ async sendSyncArchive(pin, options, serverUrl) {
2639
+ if (!this.#client) {
2640
+ throw new ClientNotInitializedError();
2641
+ }
2642
+ const resolvedOptions = options ?? this.#getDefaultArchiveOptions();
2643
+ const resolvedServerUrl = serverUrl ?? this.#getDefaultServerUrl();
2644
+ return this.#client
2645
+ .deviceSync()
2646
+ .sendSyncArchive(resolvedOptions, resolvedServerUrl, pin);
2647
+ }
2648
+ /**
2649
+ * Process a sync archive that matches the pin given
2650
+ *
2651
+ * @param archivePin - Optional pin to match. If not provided, processes the last archive sent
2652
+ * @returns Promise that resolves when the archive is processed
2653
+ */
2654
+ async processSyncArchive(archivePin) {
2655
+ if (!this.#client) {
2656
+ throw new ClientNotInitializedError();
2657
+ }
2658
+ return this.#client.deviceSync().processSyncArchive(archivePin);
2659
+ }
2660
+ /**
2661
+ * List the archives available for import in the sync group
2662
+ *
2663
+ * You may need to manually sync the sync group before calling
2664
+ * this function to see recently uploaded archives.
2665
+ *
2666
+ * @param daysCutoff - Number of days to look back for archives
2667
+ * @returns Array of available archive information
2668
+ */
2669
+ listAvailableArchives(daysCutoff) {
2670
+ if (!this.#client) {
2671
+ throw new ClientNotInitializedError();
2672
+ }
2673
+ return this.#client.deviceSync().listAvailableArchives(daysCutoff);
2674
+ }
2675
+ /**
2676
+ * Archive application elements to file for later restoration
2677
+ *
2678
+ * @param path - The file path to save the archive
2679
+ * @param key - Encryption key for the archive
2680
+ * @param opts - Archive options specifying what to include (defaults to consent and messages)
2681
+ * @returns Promise that resolves when the archive is created
2682
+ */
2683
+ async createArchive(path, key, opts) {
2684
+ if (!this.#client) {
2685
+ throw new ClientNotInitializedError();
2686
+ }
2687
+ const resolvedOpts = opts ?? this.#getDefaultArchiveOptions();
2688
+ return this.#client.deviceSync().createArchive(path, resolvedOpts, key);
2689
+ }
2690
+ /**
2691
+ * Import a previous archive from a file
2692
+ *
2693
+ * @param path - The file path to the archive
2694
+ * @param key - Encryption key for the archive
2695
+ * @returns Promise that resolves when the archive is imported
2696
+ */
2697
+ async importArchive(path, key) {
2698
+ if (!this.#client) {
2699
+ throw new ClientNotInitializedError();
2700
+ }
2701
+ return this.#client.deviceSync().importArchive(path, key);
2702
+ }
2703
+ /**
2704
+ * Load the metadata for an archive to see what it contains
2705
+ *
2706
+ * Reads only the metadata without loading the entire file, so this function is quick.
2707
+ *
2708
+ * @param path - The file path to the archive
2709
+ * @param key - Encryption key for the archive
2710
+ * @returns Promise that resolves with the archive metadata
2711
+ */
2712
+ async archiveMetadata(path, key) {
2713
+ if (!this.#client) {
2714
+ throw new ClientNotInitializedError();
2715
+ }
2716
+ return this.#client.deviceSync().archiveMetadata(path, key);
2717
+ }
2718
+ /**
2719
+ * Manually sync all device sync groups
2720
+ *
2721
+ * @returns Promise that resolves with a summary of the sync operation
2722
+ */
2723
+ async syncAllDeviceSyncGroups() {
2472
2724
  if (!this.#client) {
2473
2725
  throw new ClientNotInitializedError();
2474
2726
  }
2475
- return this.#client.sendSyncRequest();
2727
+ return this.#client.deviceSync().syncAllDeviceSyncGroups();
2476
2728
  }
2477
2729
  }
2478
2730
 
2479
- export { AccountAlreadyAssociatedError, ApiUrls, Client, ClientNotInitializedError, Conversation, Conversations, DecodedMessage, Dm, Group, HistorySyncUrls, InboxReassignError, MissingContentTypeError, SignerUnavailableError, StreamFailedError, StreamInvalidRetryAttemptsError, generateInboxId, getInboxIdForIdentifier, isActions, isAttachment, isGroupUpdated, isHexString, isIntent, isLeaveRequest, isMarkdown, isMultiRemoteAttachment, isReaction, isReadReceipt, isRemoteAttachment, isReply, isText, isTextReply, isTransactionReference, isWalletSendCalls, validHex };
2731
+ export { AccountAlreadyAssociatedError, ApiUrls, Client, ClientNotInitializedError, Conversation, Conversations, DecodedMessage, Dm, Group, HistorySyncUrls, InboxReassignError, MissingContentTypeError, SignerUnavailableError, StreamFailedError, StreamInvalidRetryAttemptsError, createBackend, envToString, generateInboxId, getInboxIdForIdentifier, isActions, isAttachment, isGroupUpdated, isHexString, isIntent, isLeaveRequest, isMarkdown, isMultiRemoteAttachment, isReaction, isReadReceipt, isRemoteAttachment, isReply, isText, isTextReply, isTransactionReference, isWalletSendCalls, validHex };
2480
2732
  //# sourceMappingURL=index.js.map