@vex-chat/libvex 6.6.1 → 6.6.3

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/Client.js CHANGED
@@ -5,10 +5,10 @@
5
5
  */
6
6
  import { enterCryptoProfileScope, getCryptoProfile, leaveCryptoProfileScope, setCryptoProfile, xBoxKeyPairAsync, xBoxKeyPairFromSecretAsync, xConcat, xConstants, xDHAsync, xEcdhKeyPairFromEcdsaKeyPairAsync, xEncode, xHMAC, xKDF, XKeyConvert, xMakeNonce, xMnemonic, xRandomBytes, xSecretboxAsync, xSecretboxOpenAsync, xSignAsync, xSignKeyPair, xSignKeyPairAsync, xSignKeyPairFromSecret, xSignKeyPairFromSecretAsync, XUtils, } from "@vex-chat/crypto";
7
7
  import { MailType, MailWSSchema, PermissionSchema, WSMessageSchema, } from "@vex-chat/types";
8
- import axios, { isAxiosError } from "axios";
9
8
  import { EventEmitter } from "eventemitter3";
10
9
  import * as uuid from "uuid";
11
10
  import { z } from "zod/v4";
11
+ import { createFetchHttpClient, isHttpError, } from "./http.js";
12
12
  import { clampLocalMessageRetentionDays, formatVexRetentionEnvelope, stripVexRetentionEnvelope, } from "./retention.js";
13
13
  import { WebSocketAdapter, WebSocketNotOpenError, } from "./transport/websocket.js";
14
14
  import { decodeFipsInitialExtraV1, encodeFipsInitialExtraV1, fipsP256AdFromIdentityPubs, fipsP256PreKeySignPayload, isFipsInitialExtraV1, } from "./utils/fipsMailExtra.js";
@@ -195,10 +195,22 @@ function spireErrorBodyMessage(data, max = 8_000) {
195
195
  return t.length > max ? t.slice(0, max) + "…" : t;
196
196
  }
197
197
  import { msgpack } from "./codec.js";
198
- import { ActionTokenCodec, AuthResponseCodec, ChannelArrayCodec, ChannelCodec, ConnectResponseCodec, decodeAxios, DeviceArrayCodec, DeviceChallengeCodec, DeviceCodec, DeviceRegistrationResultCodec, EmojiArrayCodec, EmojiCodec, FileSQLCodec, InviteArrayCodec, InviteCodec, KeyBundleCodec, OtkCountCodec, PasskeyArrayCodec, PasskeyAuthFinishResponseCodec, PasskeyCodec, PasskeyOptionsCodec, PendingDeviceRequestArrayCodec, PendingDeviceRequestCodec, PermissionArrayCodec, PermissionCodec, RegisterPendingApprovalCodec, RegisterResponseCodec, ServerArrayCodec, ServerChannelBootstrapCodec, ServerCodec, UserArrayCodec, UserCodec, WhoamiCodec, } from "./codecs.js";
198
+ import { ActionTokenCodec, AuthResponseCodec, ChannelArrayCodec, ChannelCodec, ConnectResponseCodec, decodeHttpResponse, DeviceArrayCodec, DeviceChallengeCodec, DeviceCodec, DeviceRegistrationResultCodec, EmojiArrayCodec, EmojiCodec, FileSQLCodec, InviteArrayCodec, InviteCodec, KeyBundleCodec, OtkCountCodec, PasskeyArrayCodec, PasskeyAuthFinishResponseCodec, PasskeyCodec, PasskeyOptionsCodec, PendingDeviceRequestArrayCodec, PendingDeviceRequestCodec, PermissionArrayCodec, PermissionCodec, RegisterPendingApprovalCodec, RegisterResponseCodec, ServerArrayCodec, ServerChannelBootstrapCodec, ServerCodec, UserArrayCodec, UserCodec, WhoamiCodec, } from "./codecs.js";
199
199
  import { sqlSessionToCrypto } from "./utils/sqlSessionToCrypto.js";
200
200
  import { uuidToUint8 } from "./utils/uint8uuid.js";
201
201
  const _protocolMsgRegex = /��\w+:\w+��/g;
202
+ const NotificationSubscriptionSchema = z.object({
203
+ channel: z.literal("expo"),
204
+ createdAt: z.string(),
205
+ deviceID: z.string(),
206
+ enabled: z.boolean(),
207
+ events: z.array(z.string()),
208
+ platform: z.string().nullable(),
209
+ subscriptionID: z.string(),
210
+ token: z.string(),
211
+ updatedAt: z.string(),
212
+ userID: z.string(),
213
+ });
202
214
  function compareInboxEntries(a, b) {
203
215
  const timeCmp = a[2].localeCompare(b[2]);
204
216
  if (timeCmp !== 0) {
@@ -585,7 +597,7 @@ export class Client {
585
597
  forwarded = new Set();
586
598
  host;
587
599
  http;
588
- /** Cancels in-flight axios work on `close()` so `postAuth`/`getMail` cannot hang forever. */
600
+ /** Cancels in-flight HTTP work on `close()` so `postAuth`/`getMail` cannot hang forever. */
589
601
  httpAbortController = new AbortController();
590
602
  idKeys;
591
603
  isAlive = true;
@@ -593,11 +605,6 @@ export class Client {
593
605
  localRetentionPurgeTimer = null;
594
606
  mailInterval;
595
607
  manuallyClosing = false;
596
- /**
597
- * Node-only: per-client HTTP(S) agents (see `init()` + `storage/node/http-agents`).
598
- * Dropped on `close()` so idle keep-alive sockets do not keep the process alive.
599
- */
600
- nodeHttpAgents;
601
608
  /* Retrieves the userID with the user identifier.
602
609
  user identifier is checked for userID, then signkey,
603
610
  and finally falls back to username. */
@@ -658,7 +665,7 @@ export class Client {
658
665
  this.database.on("error", (_error) => {
659
666
  void this.close(true);
660
667
  });
661
- this.http = axios.create({
668
+ this.http = createFetchHttpClient({
662
669
  responseType: "arraybuffer",
663
670
  signal: this.httpAbortController.signal,
664
671
  });
@@ -830,27 +837,6 @@ export class Client {
830
837
  return undefined;
831
838
  }
832
839
  }
833
- /**
834
- * True when running under Node (has `process.versions`).
835
- * Uses indirect lookup so the bare `process` global never appears in
836
- * source that the platform-guard plugin scans.
837
- */
838
- static isNodeRuntime() {
839
- try {
840
- const g = Object.getOwnPropertyDescriptor(globalThis, "\u0070rocess");
841
- if (!g)
842
- return false;
843
- const proc = typeof g.get === "function" ? g.get() : g.value;
844
- if (typeof proc !== "object" || proc === null) {
845
- return false;
846
- }
847
- return ("versions" in proc &&
848
- typeof proc.versions === "object");
849
- }
850
- catch {
851
- return false;
852
- }
853
- }
854
840
  /**
855
841
  * Closes the client — disconnects the WebSocket, shuts down storage,
856
842
  * and emits `closed` unless `muteEvent` is `true`.
@@ -867,11 +853,6 @@ export class Client {
867
853
  this.httpAbortController.abort();
868
854
  this.socket.close();
869
855
  await this.database.close();
870
- if (this.nodeHttpAgents) {
871
- this.nodeHttpAgents.http.destroy();
872
- this.nodeHttpAgents.https.destroy();
873
- delete this.nodeHttpAgents;
874
- }
875
856
  if (this.pingInterval) {
876
857
  clearInterval(this.pingInterval);
877
858
  }
@@ -909,7 +890,7 @@ export class Client {
909
890
  }
910
891
  const signedAsync = await xSignAsync(Uint8Array.from(uuid.parse(connectToken.key)), this.signKeys.secretKey);
911
892
  const res = await this.http.post(this.getHost() + "/device/" + this.device.deviceID + "/connect", msgpack.encode({ signed: signedAsync }), { headers: { "Content-Type": "application/msgpack" } });
912
- const { deviceToken } = decodeAxios(ConnectResponseCodec, res.data);
893
+ const { deviceToken } = decodeHttpResponse(ConnectResponseCodec, res.data);
913
894
  this.http.defaults.headers.common["X-Device-Token"] = deviceToken;
914
895
  this.autoReconnectEnabled = true;
915
896
  this.initSocket();
@@ -978,14 +959,14 @@ export class Client {
978
959
  }), {
979
960
  headers: { "Content-Type": "application/msgpack" },
980
961
  });
981
- const { token, user } = decodeAxios(AuthResponseCodec, res.data);
962
+ const { token, user } = decodeHttpResponse(AuthResponseCodec, res.data);
982
963
  this.setUser(user);
983
964
  this.token = token;
984
965
  this.http.defaults.headers.common.Authorization = `Bearer ${token}`;
985
966
  return { ok: true };
986
967
  }
987
968
  catch (err) {
988
- if (isAxiosError(err) && err.response) {
969
+ if (isHttpError(err) && err.response) {
989
970
  return {
990
971
  error: spireErrorBodyMessage(err.response.data),
991
972
  ok: false,
@@ -1014,10 +995,10 @@ export class Client {
1014
995
  deviceID: id,
1015
996
  signKey: signKeyHex,
1016
997
  }), { headers: { "Content-Type": "application/msgpack" } });
1017
- const { challenge, challengeID } = decodeAxios(DeviceChallengeCodec, challengeRes.data);
998
+ const { challenge, challengeID } = decodeHttpResponse(DeviceChallengeCodec, challengeRes.data);
1018
999
  const signed = XUtils.encodeHex(await xSignAsync(XUtils.decodeHex(challenge), this.signKeys.secretKey));
1019
1000
  const verifyRes = await this.http.post(this.getHost() + "/auth/device/verify", msgpack.encode({ challengeID, signed }), { headers: { "Content-Type": "application/msgpack" } });
1020
- const { token, user } = decodeAxios(AuthResponseCodec, verifyRes.data);
1001
+ const { token, user } = decodeHttpResponse(AuthResponseCodec, verifyRes.data);
1021
1002
  this.setUser(user);
1022
1003
  this.token = token;
1023
1004
  this.http.defaults.headers.common.Authorization = `Bearer ${token}`;
@@ -1128,7 +1109,7 @@ export class Client {
1128
1109
  let didDecodeRegisterResponse = false;
1129
1110
  let pendingApproval = null;
1130
1111
  try {
1131
- const { device, token, user } = decodeAxios(RegisterResponseCodec, res.data);
1112
+ const { device, token, user } = decodeHttpResponse(RegisterResponseCodec, res.data);
1132
1113
  this.device = device;
1133
1114
  this.setUser(user);
1134
1115
  this.token = token;
@@ -1140,7 +1121,7 @@ export class Client {
1140
1121
  }
1141
1122
  if (!didDecodeRegisterResponse) {
1142
1123
  try {
1143
- pendingApproval = decodeAxios(RegisterPendingApprovalCodec, res.data);
1124
+ pendingApproval = decodeHttpResponse(RegisterPendingApprovalCodec, res.data);
1144
1125
  }
1145
1126
  catch {
1146
1127
  // fall through to legacy decode path
@@ -1158,7 +1139,7 @@ export class Client {
1158
1139
  }),
1159
1140
  ];
1160
1141
  }
1161
- const legacyUser = decodeAxios(UserCodec, res.data);
1142
+ const legacyUser = decodeHttpResponse(UserCodec, res.data);
1162
1143
  this.setUser(legacyUser);
1163
1144
  // Legacy servers require /auth after /register to get a JWT.
1164
1145
  const loginResult = await this.login(resolvedUsername, resolvedPassword);
@@ -1173,7 +1154,7 @@ export class Client {
1173
1154
  return [this.getUser(), null];
1174
1155
  }
1175
1156
  catch (err) {
1176
- if (isAxiosError(err) && err.response) {
1157
+ if (isHttpError(err) && err.response) {
1177
1158
  return [
1178
1159
  null,
1179
1160
  new Error(spireErrorBodyMessage(err.response.data)),
@@ -1213,7 +1194,7 @@ export class Client {
1213
1194
  "/device/" +
1214
1195
  this.getDevice().deviceID +
1215
1196
  "/notifications/subscriptions", input, { responseType: "json" });
1216
- return response.data;
1197
+ return NotificationSubscriptionSchema.parse(response.data);
1217
1198
  }
1218
1199
  /**
1219
1200
  * Triggers an immediate inbox sync by fetching `/mail` once.
@@ -1254,7 +1235,7 @@ export class Client {
1254
1235
  */
1255
1236
  async whoami() {
1256
1237
  const res = await this.http.post(this.getHost() + "/whoami");
1257
- const whoami = decodeAxios(WhoamiCodec, res.data);
1238
+ const whoami = decodeHttpResponse(WhoamiCodec, res.data);
1258
1239
  return whoami;
1259
1240
  }
1260
1241
  async abortPendingDeviceRegistration(args) {
@@ -1299,16 +1280,16 @@ export class Client {
1299
1280
  "/devices/requests/" +
1300
1281
  requestID +
1301
1282
  "/approve", msgpack.encode({ signed }), { headers: { "Content-Type": "application/msgpack" } });
1302
- return decodeAxios(DeviceCodec, response.data);
1283
+ return decodeHttpResponse(DeviceCodec, response.data);
1303
1284
  }
1304
1285
  async beginPasskeyAuthentication(username) {
1305
1286
  const response = await this.http.post(this.getHost() + "/auth/passkey/begin", msgpack.encode({ username }), { headers: { "Content-Type": "application/msgpack" } });
1306
- return decodeAxios(PasskeyOptionsCodec, response.data);
1287
+ return decodeHttpResponse(PasskeyOptionsCodec, response.data);
1307
1288
  }
1308
1289
  async beginPasskeyRegistration(name) {
1309
1290
  const userID = this.getUser().userID;
1310
1291
  const response = await this.http.post(this.getHost() + "/user/" + userID + "/passkeys/register/begin", msgpack.encode({ name }), { headers: { "Content-Type": "application/msgpack" } });
1311
- return decodeAxios(PasskeyOptionsCodec, response.data);
1292
+ return decodeHttpResponse(PasskeyOptionsCodec, response.data);
1312
1293
  }
1313
1294
  censorPreKey(preKey) {
1314
1295
  if (!preKey.index) {
@@ -1324,7 +1305,7 @@ export class Client {
1324
1305
  async createChannel(name, serverID) {
1325
1306
  const body = { name };
1326
1307
  const res = await this.http.post(this.getHost() + "/server/" + serverID + "/channels", msgpack.encode(body), { headers: { "Content-Type": "application/msgpack" } });
1327
- return decodeAxios(ChannelCodec, res.data);
1308
+ return decodeHttpResponse(ChannelCodec, res.data);
1328
1309
  }
1329
1310
  // returns the file details and the encryption key
1330
1311
  async createFile(file) {
@@ -1334,7 +1315,19 @@ export class Client {
1334
1315
  ? xRandomBytes(32)
1335
1316
  : (await xBoxKeyPairAsync()).secretKey;
1336
1317
  const box = await xSecretboxAsync(Uint8Array.from(file), nonce, fileKey);
1337
- if (typeof FormData !== "undefined") {
1318
+ const canUseMultipart = typeof FormData !== "undefined" &&
1319
+ (() => {
1320
+ try {
1321
+ // React Native/Hermes can expose Blob/FormData but
1322
+ // reject ArrayBufferView-backed blobs at runtime.
1323
+ void new Blob([new Uint8Array([1, 2, 3])]);
1324
+ return true;
1325
+ }
1326
+ catch {
1327
+ return false;
1328
+ }
1329
+ })();
1330
+ if (canUseMultipart) {
1338
1331
  const fpayload = new FormData();
1339
1332
  fpayload.set("owner", this.getDevice().deviceID);
1340
1333
  fpayload.set("nonce", XUtils.encodeHex(nonce));
@@ -1355,7 +1348,7 @@ export class Client {
1355
1348
  this.emitter.emit("fileProgress", progress);
1356
1349
  },
1357
1350
  });
1358
- const fcreatedFile = decodeAxios(FileSQLCodec, fres.data);
1351
+ const fcreatedFile = decodeHttpResponse(FileSQLCodec, fres.data);
1359
1352
  return [fcreatedFile, XUtils.encodeHex(fileKey)];
1360
1353
  }
1361
1354
  const payload = {
@@ -1364,7 +1357,7 @@ export class Client {
1364
1357
  owner: this.getDevice().deviceID,
1365
1358
  };
1366
1359
  const res = await this.http.post(this.getHost() + "/file/json", msgpack.encode(payload), { headers: { "Content-Type": "application/msgpack" } });
1367
- const createdFile = decodeAxios(FileSQLCodec, res.data);
1360
+ const createdFile = decodeHttpResponse(FileSQLCodec, res.data);
1368
1361
  return [createdFile, XUtils.encodeHex(fileKey)];
1369
1362
  });
1370
1363
  }
@@ -1374,7 +1367,7 @@ export class Client {
1374
1367
  serverID,
1375
1368
  };
1376
1369
  const res = await this.http.post(this.getHost() + "/server/" + serverID + "/invites", msgpack.encode(payload), { headers: { "Content-Type": "application/msgpack" } });
1377
- return decodeAxios(InviteCodec, res.data);
1370
+ return decodeHttpResponse(InviteCodec, res.data);
1378
1371
  }
1379
1372
  async createPreKey() {
1380
1373
  const preKeyPair = await xBoxKeyPairAsync();
@@ -1388,7 +1381,7 @@ export class Client {
1388
1381
  }
1389
1382
  async createServer(name) {
1390
1383
  const res = await this.http.post(this.getHost() + "/server/" + globalThis.btoa(name));
1391
- return decodeAxios(ServerCodec, res.data);
1384
+ return decodeHttpResponse(ServerCodec, res.data);
1392
1385
  }
1393
1386
  async createSession(device, user, message, group,
1394
1387
  /* this is passed through if the first message is
@@ -1584,7 +1577,7 @@ export class Client {
1584
1577
  await this.http.delete(this.getHost() + "/server/" + serverID);
1585
1578
  }
1586
1579
  deviceListFailureDetail(err) {
1587
- if (!isAxiosError(err)) {
1580
+ if (!isHttpError(err)) {
1588
1581
  return "";
1589
1582
  }
1590
1583
  const st = err.response?.status;
@@ -1607,7 +1600,7 @@ export class Client {
1607
1600
  "/server/" +
1608
1601
  serverID +
1609
1602
  "/permissions");
1610
- return decodeAxios(PermissionArrayCodec, res.data);
1603
+ return decodeHttpResponse(PermissionArrayCodec, res.data);
1611
1604
  }
1612
1605
  async fetchUser(userIdentifier) {
1613
1606
  // Usernames are case-insensitive at the protocol level, so
@@ -1631,19 +1624,19 @@ export class Client {
1631
1624
  }
1632
1625
  try {
1633
1626
  const res = await this.http.get(this.getHost() + "/user/" + cacheKey);
1634
- const userRecord = decodeAxios(UserCodec, res.data);
1627
+ const userRecord = decodeHttpResponse(UserCodec, res.data);
1635
1628
  this.userRecords[cacheKey] = userRecord;
1636
1629
  this.notFoundUsers.delete(cacheKey);
1637
1630
  return [userRecord, null];
1638
1631
  }
1639
1632
  catch (err) {
1640
- if (isAxiosError(err) && err.response?.status === 404) {
1633
+ if (isHttpError(err) && err.response?.status === 404) {
1641
1634
  // Definitive: user doesn't exist — cache and don't retry
1642
1635
  this.notFoundUsers.set(cacheKey, Date.now());
1643
1636
  return [null, err];
1644
1637
  }
1645
1638
  // Transient (5xx, network error) — don't cache, caller can retry
1646
- return [null, isAxiosError(err) ? err : null];
1639
+ return [null, isHttpError(err) ? err : null];
1647
1640
  }
1648
1641
  }
1649
1642
  async fetchUserDeviceListOnce(userID) {
@@ -1651,7 +1644,7 @@ export class Client {
1651
1644
  return [];
1652
1645
  }
1653
1646
  const res = await this.http.get(this.getHost() + "/user/" + userID + "/devices");
1654
- const devices = decodeAxios(DeviceArrayCodec, res.data);
1647
+ const devices = decodeHttpResponse(DeviceArrayCodec, res.data);
1655
1648
  for (const device of devices) {
1656
1649
  this.deviceRecords[device.deviceID] = device;
1657
1650
  }
@@ -1698,7 +1691,7 @@ export class Client {
1698
1691
  */
1699
1692
  async finishPasskeyAuthentication(args) {
1700
1693
  const response = await this.http.post(this.getHost() + "/auth/passkey/finish", msgpack.encode(args), { headers: { "Content-Type": "application/msgpack" } });
1701
- const decoded = decodeAxios(PasskeyAuthFinishResponseCodec, response.data);
1694
+ const decoded = decodeHttpResponse(PasskeyAuthFinishResponseCodec, response.data);
1702
1695
  this.setUser(decoded.user);
1703
1696
  this.token = decoded.token;
1704
1697
  this.http.defaults.headers.common.Authorization = `Bearer ${decoded.token}`;
@@ -1707,7 +1700,7 @@ export class Client {
1707
1700
  async finishPasskeyRegistration(args) {
1708
1701
  const userID = this.getUser().userID;
1709
1702
  const response = await this.http.post(this.getHost() + "/user/" + userID + "/passkeys/register/finish", msgpack.encode(args), { headers: { "Content-Type": "application/msgpack" } });
1710
- return decodeAxios(PasskeyCodec, response.data);
1703
+ return decodeHttpResponse(PasskeyCodec, response.data);
1711
1704
  }
1712
1705
  async forward(message) {
1713
1706
  if (this.isManualCloseInFlight()) {
@@ -1741,7 +1734,7 @@ export class Client {
1741
1734
  async getChannelByID(channelID) {
1742
1735
  try {
1743
1736
  const res = await this.http.get(this.getHost() + "/channel/" + channelID);
1744
- return decodeAxios(ChannelCodec, res.data);
1737
+ return decodeHttpResponse(ChannelCodec, res.data);
1745
1738
  }
1746
1739
  catch (_err) {
1747
1740
  return null;
@@ -1749,7 +1742,7 @@ export class Client {
1749
1742
  }
1750
1743
  async getChannelList(serverID) {
1751
1744
  const res = await this.http.get(this.getHost() + "/server/" + serverID + "/channels");
1752
- return decodeAxios(ChannelArrayCodec, res.data);
1745
+ return decodeHttpResponse(ChannelArrayCodec, res.data);
1753
1746
  }
1754
1747
  getDevice() {
1755
1748
  if (!this.device) {
@@ -1768,7 +1761,7 @@ export class Client {
1768
1761
  }
1769
1762
  try {
1770
1763
  const res = await this.http.get(this.getHost() + "/device/" + deviceID);
1771
- const fetchedDevice = decodeAxios(DeviceCodec, res.data);
1764
+ const fetchedDevice = decodeHttpResponse(DeviceCodec, res.data);
1772
1765
  this.deviceRecords[deviceID] = fetchedDevice;
1773
1766
  await this.database.saveDevice(fetchedDevice);
1774
1767
  return fetchedDevice;
@@ -1785,10 +1778,10 @@ export class Client {
1785
1778
  this.getUser().userID +
1786
1779
  "/devices/requests/" +
1787
1780
  requestID);
1788
- return decodeAxios(PendingDeviceRequestCodec, response.data);
1781
+ return decodeHttpResponse(PendingDeviceRequestCodec, response.data);
1789
1782
  }
1790
1783
  catch (err) {
1791
- if (isAxiosError(err) && err.response?.status === 404) {
1784
+ if (isHttpError(err) && err.response?.status === 404) {
1792
1785
  return null;
1793
1786
  }
1794
1787
  throw err;
@@ -1885,7 +1878,7 @@ export class Client {
1885
1878
  async getMultiUserDeviceList(userIDs) {
1886
1879
  try {
1887
1880
  const res = await this.http.post(this.getHost() + "/deviceList", msgpack.encode(userIDs), { headers: { "Content-Type": "application/msgpack" } });
1888
- const devices = decodeAxios(DeviceArrayCodec, res.data);
1881
+ const devices = decodeHttpResponse(DeviceArrayCodec, res.data);
1889
1882
  for (const device of devices) {
1890
1883
  this.deviceRecords[device.deviceID] = device;
1891
1884
  }
@@ -1900,7 +1893,7 @@ export class Client {
1900
1893
  "/device/" +
1901
1894
  this.getDevice().deviceID +
1902
1895
  "/otk/count");
1903
- return decodeAxios(OtkCountCodec, res.data).count;
1896
+ return decodeHttpResponse(OtkCountCodec, res.data).count;
1904
1897
  }
1905
1898
  /**
1906
1899
  * Gets all permissions for the logged in user.
@@ -1909,12 +1902,12 @@ export class Client {
1909
1902
  */
1910
1903
  async getPermissions() {
1911
1904
  const res = await this.http.get(this.getHost() + "/user/" + this.getUser().userID + "/permissions");
1912
- return decodeAxios(PermissionArrayCodec, res.data);
1905
+ return decodeHttpResponse(PermissionArrayCodec, res.data);
1913
1906
  }
1914
1907
  async getServerByID(serverID) {
1915
1908
  try {
1916
1909
  const res = await this.http.get(this.getHost() + "/server/" + serverID);
1917
- return decodeAxios(ServerCodec, res.data);
1910
+ return decodeHttpResponse(ServerCodec, res.data);
1918
1911
  }
1919
1912
  catch (_err) {
1920
1913
  return null;
@@ -1925,11 +1918,11 @@ export class Client {
1925
1918
  "/user/" +
1926
1919
  this.getUser().userID +
1927
1920
  "/servers/bootstrap");
1928
- return decodeAxios(ServerChannelBootstrapCodec, res.data);
1921
+ return decodeHttpResponse(ServerChannelBootstrapCodec, res.data);
1929
1922
  }
1930
1923
  async getServerList() {
1931
1924
  const res = await this.http.get(this.getHost() + "/user/" + this.getUser().userID + "/servers");
1932
- return decodeAxios(ServerArrayCodec, res.data);
1925
+ return decodeHttpResponse(ServerArrayCodec, res.data);
1933
1926
  }
1934
1927
  async getSessionByPubkey(publicKey) {
1935
1928
  const strPubKey = XUtils.encodeHex(publicKey);
@@ -1950,7 +1943,7 @@ export class Client {
1950
1943
  const res = await this.http.get(this.getHost() + "/token/" + type, {
1951
1944
  responseType: "arraybuffer",
1952
1945
  });
1953
- return decodeAxios(ActionTokenCodec, res.data);
1946
+ return decodeHttpResponse(ActionTokenCodec, res.data);
1954
1947
  }
1955
1948
  catch {
1956
1949
  return null;
@@ -1980,7 +1973,7 @@ export class Client {
1980
1973
  }
1981
1974
  async getUserList(channelID) {
1982
1975
  const res = await this.http.post(this.getHost() + "/userList/" + channelID);
1983
- return decodeAxios(UserArrayCodec, res.data);
1976
+ return decodeHttpResponse(UserArrayCodec, res.data);
1984
1977
  }
1985
1978
  async handleNotify(msg) {
1986
1979
  switch (msg.event) {
@@ -2044,12 +2037,6 @@ export class Client {
2044
2037
  throw new Error("You should only call init() once.");
2045
2038
  }
2046
2039
  this.hasInit = true;
2047
- if (Client.isNodeRuntime()) {
2048
- const { attachNodeAgentsToAxios, createNodeHttpAgents } = await import("./storage/node/http-agents.js");
2049
- const agents = createNodeHttpAgents();
2050
- this.nodeHttpAgents = agents;
2051
- attachNodeAgentsToAxios(this.http, agents);
2052
- }
2053
2040
  await this.populateKeyRing();
2054
2041
  this.emitter.on("message", this.onInternalMessage);
2055
2042
  void this.runLocalRetentionPurge();
@@ -2182,7 +2169,7 @@ export class Client {
2182
2169
  "/user/" +
2183
2170
  this.getUser().userID +
2184
2171
  "/devices/requests");
2185
- return decodeAxios(PendingDeviceRequestArrayCodec, response.data);
2172
+ return decodeHttpResponse(PendingDeviceRequestArrayCodec, response.data);
2186
2173
  }
2187
2174
  /**
2188
2175
  * Lists every device the current account owns.
@@ -2193,12 +2180,12 @@ export class Client {
2193
2180
  async listDevices() {
2194
2181
  const userID = this.getUser().userID;
2195
2182
  const res = await this.http.get(this.getHost() + "/user/" + userID + "/devices");
2196
- return decodeAxios(DeviceArrayCodec, res.data);
2183
+ return decodeHttpResponse(DeviceArrayCodec, res.data);
2197
2184
  }
2198
2185
  async listPasskeys() {
2199
2186
  const userID = this.getUser().userID;
2200
2187
  const response = await this.http.get(this.getHost() + "/user/" + userID + "/passkeys");
2201
- return decodeAxios(PasskeyArrayCodec, response.data);
2188
+ return decodeHttpResponse(PasskeyArrayCodec, response.data);
2202
2189
  }
2203
2190
  async markSessionVerified(sessionID) {
2204
2191
  return this.database.markSessionVerified(sessionID);
@@ -2249,7 +2236,7 @@ export class Client {
2249
2236
  "/passkey/devices/requests/" +
2250
2237
  requestID +
2251
2238
  "/approve");
2252
- return decodeAxios(DeviceCodec, response.data);
2239
+ return decodeHttpResponse(DeviceCodec, response.data);
2253
2240
  }
2254
2241
  async passkeyDeleteDevice(deviceID) {
2255
2242
  const userID = this.getUser().userID;
@@ -2258,7 +2245,7 @@ export class Client {
2258
2245
  async passkeyListDevices() {
2259
2246
  const userID = this.getUser().userID;
2260
2247
  const response = await this.http.get(this.getHost() + "/user/" + userID + "/passkey/devices");
2261
- return decodeAxios(DeviceArrayCodec, response.data);
2248
+ return decodeHttpResponse(DeviceArrayCodec, response.data);
2262
2249
  }
2263
2250
  async passkeyRejectDeviceRequest(requestID) {
2264
2251
  const userID = this.getUser().userID;
@@ -2310,10 +2297,10 @@ export class Client {
2310
2297
  "/user/devices/requests/" +
2311
2298
  args.requestID +
2312
2299
  "/poll", msgpack.encode({ signed }), { headers: { "Content-Type": "application/msgpack" } });
2313
- return decodeAxios(PendingDeviceRequestCodec, response.data);
2300
+ return decodeHttpResponse(PendingDeviceRequestCodec, response.data);
2314
2301
  }
2315
2302
  catch (err) {
2316
- if (isAxiosError(err) && err.response?.status === 404) {
2303
+ if (isHttpError(err) && err.response?.status === 404) {
2317
2304
  return null;
2318
2305
  }
2319
2306
  throw err;
@@ -2930,7 +2917,7 @@ export class Client {
2930
2917
  }
2931
2918
  async redeemInvite(inviteID) {
2932
2919
  const res = await this.http.patch(this.getHost() + "/invite/" + inviteID);
2933
- return decodeAxios(PermissionCodec, res.data);
2920
+ return decodeHttpResponse(PermissionCodec, res.data);
2934
2921
  }
2935
2922
  registerDecryptFailure(mail) {
2936
2923
  const count = (this.decryptFailureCounts.get(mail.mailID) ?? 0) + 1;
@@ -2969,7 +2956,7 @@ export class Client {
2969
2956
  "/user/" +
2970
2957
  userDetails.userID +
2971
2958
  "/devices", msgpack.encode(devMsg), { headers: { "Content-Type": "application/msgpack" } });
2972
- return decodeAxios(DeviceRegistrationResultCodec, res.data);
2959
+ return decodeHttpResponse(DeviceRegistrationResultCodec, res.data);
2973
2960
  }
2974
2961
  async rejectDeviceRequest(requestID) {
2975
2962
  await this.http.post(this.prefixes.HTTP +
@@ -2996,22 +2983,18 @@ export class Client {
2996
2983
  }
2997
2984
  async retrieveEmojiByID(emojiID) {
2998
2985
  const res = await this.http.get(this.getHost() + "/emoji/" + emojiID + "/details");
2999
- if (!res.data) {
3000
- return null;
3001
- }
3002
- return decodeAxios(EmojiCodec, res.data);
2986
+ return decodeHttpResponse(EmojiCodec, res.data);
3003
2987
  }
3004
2988
  async retrieveEmojiList(serverID) {
3005
2989
  const res = await this.http.get(this.getHost() + "/server/" + serverID + "/emoji");
3006
- return decodeAxios(EmojiArrayCodec, res.data);
2990
+ return decodeHttpResponse(EmojiArrayCodec, res.data);
3007
2991
  }
3008
2992
  async retrieveFile(fileID, key) {
3009
2993
  const detailsRes = await this.http.get(this.getHost() + "/file/" + fileID + "/details");
3010
- const details = decodeAxios(FileSQLCodec, detailsRes.data);
2994
+ const details = decodeHttpResponse(FileSQLCodec, detailsRes.data);
3011
2995
  const res = await this.http.get(this.getHost() + "/file/" + fileID, {
3012
2996
  onDownloadProgress: (progressEvent) => {
3013
- const percentCompleted = Math.round((progressEvent.loaded * 100) /
3014
- (progressEvent.total ?? 1));
2997
+ const percentCompleted = Math.round((progressEvent.loaded * 100) / (progressEvent.total ?? 1));
3015
2998
  const { loaded, total = 0 } = progressEvent;
3016
2999
  const progress = {
3017
3000
  direction: "download",
@@ -3035,11 +3018,11 @@ export class Client {
3035
3018
  }
3036
3019
  async retrieveInvites(serverID) {
3037
3020
  const res = await this.http.get(this.getHost() + "/server/" + serverID + "/invites");
3038
- return decodeAxios(InviteArrayCodec, res.data);
3021
+ return decodeHttpResponse(InviteArrayCodec, res.data);
3039
3022
  }
3040
3023
  async retrieveKeyBundle(deviceID) {
3041
3024
  const res = await this.http.post(this.getHost() + "/device/" + deviceID + "/keyBundle");
3042
- return decodeAxios(KeyBundleCodec, res.data);
3025
+ return decodeHttpResponse(KeyBundleCodec, res.data);
3043
3026
  }
3044
3027
  async retrieveOrCreateDevice() {
3045
3028
  let device;
@@ -3048,10 +3031,10 @@ export class Client {
3048
3031
  this.host +
3049
3032
  "/device/" +
3050
3033
  XUtils.encodeHex(this.signKeys.publicKey));
3051
- device = decodeAxios(DeviceCodec, res.data);
3034
+ device = decodeHttpResponse(DeviceCodec, res.data);
3052
3035
  }
3053
3036
  catch (err) {
3054
- if (isAxiosError(err) && err.response?.status === 404) {
3037
+ if (isHttpError(err) && err.response?.status === 404) {
3055
3038
  await this.database.purgeKeyData();
3056
3039
  await this.populateKeyRing();
3057
3040
  const newDevice = await this.registerDevice();
@@ -3634,7 +3617,7 @@ export class Client {
3634
3617
  this.emitter.emit("fileProgress", progress);
3635
3618
  },
3636
3619
  });
3637
- return decodeAxios(EmojiCodec, res.data);
3620
+ return decodeHttpResponse(EmojiCodec, res.data);
3638
3621
  }
3639
3622
  catch (_err) {
3640
3623
  return null;
@@ -3646,7 +3629,7 @@ export class Client {
3646
3629
  };
3647
3630
  try {
3648
3631
  const res = await this.http.post(this.getHost() + "/emoji/" + serverID + "/json", msgpack.encode(payload), { headers: { "Content-Type": "application/msgpack" } });
3649
- return decodeAxios(EmojiCodec, res.data);
3632
+ return decodeHttpResponse(EmojiCodec, res.data);
3650
3633
  }
3651
3634
  catch (_err) {
3652
3635
  return null;