stream-chat 10.0.0-rc.3 → 10.0.0-rc.4

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.
@@ -230,7 +230,7 @@ __export(index_exports, {
230
230
  module.exports = __toCommonJS(index_exports);
231
231
 
232
232
  // src/client.ts
233
- var import_axios5 = __toESM(require("axios"));
233
+ var import_axios4 = __toESM(require("axios"));
234
234
 
235
235
  // src/constants.ts
236
236
  var DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE = 25;
@@ -363,9 +363,6 @@ var chatCodes = {
363
363
  function isOwnUser(user) {
364
364
  return user?.total_unread_count !== void 0;
365
365
  }
366
- function isBlobWebAPI(uri) {
367
- return typeof window !== "undefined" && "Blob" in window && uri instanceof Blob;
368
- }
369
366
  function isOwnUserBaseProperty(property) {
370
367
  const ownUserBaseProperties = {
371
368
  channel_mutes: true,
@@ -389,21 +386,6 @@ var channelHasReadEvents = (channel) => {
389
386
  };
390
387
  var channelTracksReadLocally = (channel) => !channelHasReadEvents(channel) && !!channel?.getClient().options.isLocalUnreadCountEnabled;
391
388
  var userHasReadReceipts = (client) => client.user?.privacy_settings?.read_receipts?.enabled ?? true;
392
- function addFileToFormData(uri, name, contentType) {
393
- const data = new FormData();
394
- if (isBlobWebAPI(uri)) {
395
- if (name) data.append("file", uri, name);
396
- else data.append("file", uri);
397
- } else {
398
- data.append("file", {
399
- uri,
400
- name: name || uri.split("/").reverse()[0],
401
- contentType: contentType || void 0,
402
- type: contentType || void 0
403
- });
404
- }
405
- return data;
406
- }
407
389
  function retryInterval(numberOfFailures) {
408
390
  const max = Math.min(500 + numberOfFailures * 2e3, 25e3);
409
391
  const min = Math.min(Math.max(250, (numberOfFailures - 1) * 2e3), 25e3);
@@ -459,17 +441,6 @@ function convertErrorToJson(err) {
459
441
  }
460
442
  return jsonObj;
461
443
  }
462
- function isOnline() {
463
- const nav = typeof navigator !== "undefined" ? navigator : typeof window !== "undefined" && window.navigator ? window.navigator : void 0;
464
- if (!nav) {
465
- logger.withExtraTags("isOnline").warn("Could not access window.navigator; assuming the browser is online.");
466
- return true;
467
- }
468
- if (typeof nav.onLine !== "boolean") {
469
- return true;
470
- }
471
- return nav.onLine;
472
- }
473
444
  function addConnectionEventListeners(cb) {
474
445
  if (typeof window !== "undefined" && window.addEventListener) {
475
446
  window.addEventListener("offline", cb);
@@ -1332,19 +1303,6 @@ function isEphemeral(error) {
1332
1303
  if (!error.response) return true;
1333
1304
  return isErrorRetryable(error);
1334
1305
  }
1335
- function isConnectionIDError(error) {
1336
- return error.code === 46;
1337
- }
1338
- function isWSFailure(err) {
1339
- if (typeof err.isWSFailure === "boolean") {
1340
- return err.isWSFailure;
1341
- }
1342
- try {
1343
- return JSON.parse(err.message).isWSFailure;
1344
- } catch (_) {
1345
- return false;
1346
- }
1347
- }
1348
1306
 
1349
1307
  // src/entityStore/applyReactionLocally.ts
1350
1308
  var applyReactionLocally = (client, {
@@ -2469,25 +2427,27 @@ var _AttachmentManager = class _AttachmentManager {
2469
2427
  const percent = progressEvent.lengthComputable && progressEvent.total ? Math.round(progressEvent.loaded * 100 / progressEvent.total) : void 0;
2470
2428
  options.onProgress?.(percent);
2471
2429
  } : void 0;
2472
- const axiosUploadConfig = progressHandler || options?.abortSignal ? {
2430
+ const requestOptions = {
2473
2431
  ...progressHandler ? { onUploadProgress: progressHandler } : {},
2474
2432
  ...options?.abortSignal ? { signal: options.abortSignal } : {}
2475
- } : void 0;
2476
- if (isFileReference(fileLike)) {
2477
- return this.channel[isImageFile(fileLike) ? "sendImage" : "sendFile"](
2478
- fileLike.uri,
2479
- fileLike.name,
2480
- fileLike.type,
2481
- void 0,
2482
- axiosUploadConfig
2483
- );
2484
- }
2485
- const file = isFile(fileLike) ? fileLike : createFileFromBlobs({
2433
+ };
2434
+ const file = isFileReference(fileLike) || isFile(fileLike) ? fileLike : createFileFromBlobs({
2486
2435
  blobsArray: [fileLike],
2487
2436
  fileName: generateFileName(fileLike.type),
2488
2437
  mimeType: fileLike.type
2489
2438
  });
2490
- const { duration: _duration, ...result } = await this.channel[isImageFile(fileLike) ? "sendImage" : "sendFile"](file, void 0, void 0, void 0, axiosUploadConfig);
2439
+ const {
2440
+ duration: _duration,
2441
+ // per-request artifact - `doUploadRequest`'s result is public API
2442
+ metadata: _metadata,
2443
+ ...result
2444
+ } = await this.channel[isImageFile(fileLike) ? "uploadImage" : "uploadFile"](
2445
+ { file },
2446
+ requestOptions
2447
+ );
2448
+ if (!result.file) {
2449
+ throw new Error("The upload succeeded but the response carried no file URL");
2450
+ }
2491
2451
  return result;
2492
2452
  };
2493
2453
  /**
@@ -12865,6 +12825,34 @@ var MessageReceiptsTracker = class extends WithSubscriptions {
12865
12825
  }
12866
12826
  };
12867
12827
 
12828
+ // src/upload-utils.ts
12829
+ var isWebFile = (value) => typeof Blob !== "undefined" && value instanceof Blob;
12830
+ var isFileReferenceBase = (value) => !!value && typeof value === "object" && typeof value.uri === "string";
12831
+ var normalizeUploadFile = (file) => typeof file === "string" ? { uri: file } : file;
12832
+ function appendToFormData(data, key, value) {
12833
+ if (value === void 0 || value === null) return;
12834
+ if (isWebFile(value)) {
12835
+ const name = value.name;
12836
+ if (name) data.append(key, value, name);
12837
+ else data.append(key, value);
12838
+ } else if (isFileReferenceBase(value)) {
12839
+ data.append(key, {
12840
+ uri: value.uri,
12841
+ name: value.name || value.uri.split("/").reverse()[0],
12842
+ type: value.type || void 0
12843
+ });
12844
+ } else if (typeof value === "object") {
12845
+ data.append(key, JSON.stringify(value));
12846
+ } else {
12847
+ data.append(key, String(value));
12848
+ }
12849
+ }
12850
+ function toFormData(body) {
12851
+ const data = new FormData();
12852
+ for (const [key, value] of Object.entries(body)) appendToFormData(data, key, value);
12853
+ return data;
12854
+ }
12855
+
12868
12856
  // src/gen/chat/ChannelApi.ts
12869
12857
  var ChannelApi = class {
12870
12858
  constructor(chatApi, type, id) {
@@ -13142,6 +13130,12 @@ var Channel = class extends ChannelApi {
13142
13130
  /** Re-entrancy guard for {@link Channel.reload} (mirrors Thread.reload's isLoading guard). */
13143
13131
  this._reloading = false;
13144
13132
  this.configState = new StateStore({});
13133
+ /**
13134
+ * Alias for {@link uploadChannelFile}, mirroring `client.uploadFile`.
13135
+ */
13136
+ this.uploadFile = (...args) => this.uploadChannelFile(...args);
13137
+ /** Alias for {@link uploadChannelImage}, mirroring `client.uploadImage`. */
13138
+ this.uploadImage = (...args) => this.uploadChannelImage(...args);
13145
13139
  /**
13146
13140
  * Creates a new channel.
13147
13141
  *
@@ -13408,43 +13402,29 @@ var Channel = class extends ChannelApi {
13408
13402
  }
13409
13403
  }
13410
13404
  /**
13411
- * Upload a file to this channel’s file endpoint (multipart). Forwards to the client’s `sendFile` implementation.
13405
+ * Upload a file to this channel's file endpoint (multipart).
13412
13406
  *
13413
- * @param uri - File source: URL string, `File`, `Buffer`, or readable stream (Node).
13414
- * @param name - File name sent in the multipart body (optional).
13415
- * @param contentType - MIME type; required for React Native URI uploads (optional).
13416
- * @param user - User payload appended to the form as JSON (optional).
13417
- * @param axiosRequestConfig - Axios per-request config, merged after upload defaults, e.g. `onUploadProgress`, `signal` from `AbortController` (optional).
13407
+ * @param request - Upload payload. `request.file` is the file to upload.
13408
+ * @param requestOptions - Per-request options, e.g. `onUploadProgress` or an abort `signal` (optional).
13418
13409
  * @returns A promise resolving to `{ file: string, ... }` with the CDN URL.
13419
13410
  */
13420
- sendFile(uri, name, contentType, user, axiosRequestConfig) {
13421
- return this.getClient().api.sendFile(
13422
- `${this._channelURL()}/file`,
13423
- uri,
13424
- name,
13425
- contentType,
13426
- user,
13427
- axiosRequestConfig
13411
+ async uploadChannelFile(request, requestOptions) {
13412
+ return await super.uploadChannelFile(
13413
+ { ...request, file: normalizeUploadFile(request?.file) },
13414
+ requestOptions
13428
13415
  );
13429
13416
  }
13430
13417
  /**
13431
- * Upload an image to this channel's image endpoint (multipart). Uses the same transport as `sendFile`.
13418
+ * Upload an image to this channel's image endpoint (multipart).
13432
13419
  *
13433
- * @param uri - Image source: URL string, `File`, or readable stream (Node). For `Buffer` uploads, use `sendFile` toward the channel file endpoint instead.
13434
- * @param name - File name sent in the multipart body (optional).
13435
- * @param contentType - MIME type; required for React Native URI uploads (optional).
13436
- * @param user - User payload appended to the form as JSON (optional).
13437
- * @param axiosRequestConfig - Axios per-request config, merged after upload defaults, e.g. `onUploadProgress`, `signal` (optional).
13420
+ * @param request - Upload payload. `request.file` is the image to upload.
13421
+ * @param requestOptions - Per-request options, e.g. `onUploadProgress` or an abort `signal` (optional).
13438
13422
  * @returns A promise resolving to `{ file: string, ... }` with the CDN URL.
13439
13423
  */
13440
- sendImage(uri, name, contentType, user, axiosRequestConfig) {
13441
- return this.getClient().api.sendFile(
13442
- `${this._channelURL()}/image`,
13443
- uri,
13444
- name,
13445
- contentType,
13446
- user,
13447
- axiosRequestConfig
13424
+ async uploadChannelImage(request, requestOptions) {
13425
+ return await super.uploadChannelImage(
13426
+ { ...request, file: normalizeUploadFile(request?.file) },
13427
+ requestOptions
13448
13428
  );
13449
13429
  }
13450
13430
  deleteFile(url, requestOptions) {
@@ -15271,7 +15251,6 @@ function buildWsBaseInsight(connection) {
15271
15251
  token: client.tokenManager.token,
15272
15252
  user_id: client.userId,
15273
15253
  user_details: client._user,
15274
- device: client.options.device,
15275
15254
  client_id: connection.connectionID,
15276
15255
  ws_details: connection.ws,
15277
15256
  ws_consecutive_failures: client.insightMetrics.wsConsecutiveFailures,
@@ -17295,6 +17274,7 @@ var decodeWSEvent = (data) => {
17295
17274
 
17296
17275
  // src/connection.ts
17297
17276
  var logger5 = chatLoggerSystem.getLogger("connection");
17277
+ var decodeConnectionEvent = (data) => data.type === "connection.ok" ? decoders.HealthCheckEvent(data) : decodeWSEvent(data);
17298
17278
  var isCloseEvent = (res) => res.code !== void 0;
17299
17279
  var isErrorEvent = (res) => res.error !== void 0;
17300
17280
  var WSCloseError = class extends Error {
@@ -17311,16 +17291,11 @@ var StableWSConnection = class {
17311
17291
  * @returns url string
17312
17292
  */
17313
17293
  this._buildUrl = () => {
17314
- const qs = this.client._buildWSPayload(this.requestID);
17315
- const token = this.client.tokenManager.getToken();
17316
- const wsUrlParams = this.client.options.wsUrlParams;
17317
- const params = new URLSearchParams(wsUrlParams);
17318
- params.set("json", qs);
17294
+ const params = new URLSearchParams(this.client.options.wsUrlParams);
17319
17295
  params.set("api_key", this.client.key);
17320
- params.set("authorization", `${token}`);
17321
17296
  params.set("stream-auth-type", this.client.getAuthType());
17322
17297
  params.set("X-Stream-Client", this.client.getUserAgent());
17323
- return `${this.client.wsBaseURL}/connect?${params.toString()}`;
17298
+ return `${this.client.wsBaseURL}/api/v2/connect?${params.toString()}`;
17324
17299
  };
17325
17300
  /**
17326
17301
  * Called when the browser connects or disconnects from the internet.
@@ -17338,11 +17313,20 @@ var StableWSConnection = class {
17338
17313
  }
17339
17314
  }
17340
17315
  };
17341
- this.onopen = (wsId) => {
17316
+ this.onopen = (wsId, authMessage) => {
17342
17317
  if (this.wsID !== wsId) return;
17343
17318
  logger5.withExtraTags("onopen").debug("WebSocket onopen callback fired.", {
17344
17319
  wsID: wsId
17345
17320
  });
17321
+ const { ws } = this;
17322
+ if (!ws || ws.readyState !== ws.OPEN) return;
17323
+ try {
17324
+ ws.send(authMessage);
17325
+ } catch (error) {
17326
+ logger5.withExtraTags("onopen").error("Failed to send the WebSocket auth message.", { error });
17327
+ this.rejectPromise?.(this._errorFromWSEvent(error));
17328
+ this._destroyCurrentWSConnection();
17329
+ }
17346
17330
  };
17347
17331
  this.onmessage = (wsId, event) => {
17348
17332
  if (this.wsID !== wsId) return;
@@ -17352,7 +17336,7 @@ var StableWSConnection = class {
17352
17336
  });
17353
17337
  if (typeof event.data !== "string") return;
17354
17338
  const data = JSON.parse(event.data);
17355
- const decodedData = decodeWSEvent(data);
17339
+ const decodedData = decodeConnectionEvent(data);
17356
17340
  if (!this.isResolved) {
17357
17341
  this.isResolved = true;
17358
17342
  if (data.error) {
@@ -17363,7 +17347,7 @@ var StableWSConnection = class {
17363
17347
  this._setHealth(true);
17364
17348
  }
17365
17349
  this.lastEvent = /* @__PURE__ */ new Date();
17366
- if (data.type === "health.check") {
17350
+ if (data.type === "health.check" || data.type === "connection.ok") {
17367
17351
  this.scheduleNextPing();
17368
17352
  }
17369
17353
  this.client.dispatchEvent(decodedData);
@@ -17429,7 +17413,7 @@ var StableWSConnection = class {
17429
17413
  * @param isWSFailure - Whether the underlying cause is a WebSocket failure (optional, defaults to `true`).
17430
17414
  * @returns A normalized error describing the WS failure.
17431
17415
  */
17432
- this._errorFromWSEvent = (event, isWSFailure2 = true) => {
17416
+ this._errorFromWSEvent = (event, isWSFailure = true) => {
17433
17417
  let code;
17434
17418
  let statusCode;
17435
17419
  let message;
@@ -17449,7 +17433,7 @@ var StableWSConnection = class {
17449
17433
  );
17450
17434
  error.code = code;
17451
17435
  error.StatusCode = statusCode;
17452
- error.isWSFailure = isWSFailure2;
17436
+ error.isWSFailure = isWSFailure;
17453
17437
  return error;
17454
17438
  };
17455
17439
  /**
@@ -17642,8 +17626,7 @@ var StableWSConnection = class {
17642
17626
  * @returns A promise that resolves once the first health check message is received.
17643
17627
  */
17644
17628
  async _connect() {
17645
- if (this.isConnecting || this.isDisconnected && this.client.options.enableWSFallback)
17646
- return;
17629
+ if (this.isConnecting || this.isDisconnected) return;
17647
17630
  this.isConnecting = true;
17648
17631
  this.requestID = randomId();
17649
17632
  this.client.insightMetrics.connectionStartTimestamp = (/* @__PURE__ */ new Date()).getTime();
@@ -17661,13 +17644,14 @@ var StableWSConnection = class {
17661
17644
  }
17662
17645
  this._setupConnectionPromise();
17663
17646
  const wsURL = this._buildUrl();
17647
+ const authMessage = this.client._buildWSAuthMessage();
17664
17648
  logger5.withExtraTags("_connect").info(`Connecting to ${wsURL}.`, {
17665
17649
  wsURL,
17666
17650
  requestID: this.requestID
17667
17651
  });
17668
17652
  const WS = this.client.options.WebSocketImpl ?? WebSocket;
17669
17653
  this.ws = new WS(wsURL);
17670
- this.ws.onopen = this.onopen.bind(this, this.wsID);
17654
+ this.ws.onopen = this.onopen.bind(this, this.wsID, authMessage);
17671
17655
  this.ws.onclose = this.onclose.bind(this, this.wsID);
17672
17656
  this.ws.onerror = this.onerror.bind(this, this.wsID);
17673
17657
  this.ws.onmessage = this.onmessage.bind(this, this.wsID);
@@ -17721,7 +17705,7 @@ var StableWSConnection = class {
17721
17705
  logger5.withExtraTags("_reconnect").debug("Aborting reconnect: already connecting or healthy (check 2).");
17722
17706
  return;
17723
17707
  }
17724
- if (this.isDisconnected && this.client.options.enableWSFallback) {
17708
+ if (this.isDisconnected) {
17725
17709
  logger5.withExtraTags("_reconnect").debug("Aborting reconnect: disconnect() was called.");
17726
17710
  return;
17727
17711
  }
@@ -17912,6 +17896,7 @@ var TokenManager = class {
17912
17896
  * Initializes the token manager.
17913
17897
  */
17914
17898
  constructor() {
17899
+ this._isAnonymous = false;
17915
17900
  /**
17916
17901
  * Sets the static string token or token provider. A token provider should return a token string
17917
17902
  * or a promise that resolves to a token string.
@@ -17922,6 +17907,7 @@ var TokenManager = class {
17922
17907
  this.setTokenOrProvider = async (tokenOrProvider, user) => {
17923
17908
  this.validateToken(tokenOrProvider, user);
17924
17909
  this.user = user;
17910
+ this._isAnonymous = !!user.anon;
17925
17911
  if (isFunction(tokenOrProvider)) {
17926
17912
  this.tokenProvider = tokenOrProvider;
17927
17913
  this.type = "provider";
@@ -17937,6 +17923,7 @@ var TokenManager = class {
17937
17923
  * Useful for client disconnection or switching user.
17938
17924
  */
17939
17925
  this.reset = () => {
17926
+ this._isAnonymous = false;
17940
17927
  this.token = void 0;
17941
17928
  this.tokenProvider = void 0;
17942
17929
  this.type = "static";
@@ -17988,8 +17975,8 @@ var TokenManager = class {
17988
17975
  if (this.token) {
17989
17976
  return this.token;
17990
17977
  }
17991
- if (this.user && this.user.anon && !this.token) {
17992
- return this.token;
17978
+ if (this._isAnonymous) {
17979
+ return "";
17993
17980
  }
17994
17981
  throw new Error(
17995
17982
  `Both secret and user tokens are not set. Either client.connectUser wasn't called or client.disconnect was called`
@@ -17999,153 +17986,13 @@ var TokenManager = class {
17999
17986
  this.loadTokenPromise = null;
18000
17987
  this.type = "static";
18001
17988
  }
18002
- };
18003
-
18004
- // src/connection_fallback.ts
18005
- var import_axios3 = __toESM(require("axios"));
18006
- var logger8 = chatLoggerSystem.getLogger("connection-fallback");
18007
- var WSConnectionFallback = class {
18008
- constructor({ client }) {
18009
- /** @private */
18010
- this._onlineStatusChanged = (event) => {
18011
- logger8.withExtraTags("_onlineStatusChanged").info(`Network status changed to ${event.type}.`);
18012
- if (event.type === "offline") {
18013
- this._setState("CLOSED" /* Closed */);
18014
- this.cancelToken?.cancel("disconnect() is called");
18015
- this.cancelToken = void 0;
18016
- return;
18017
- }
18018
- if (event.type === "online" && this.state === "CLOSED" /* Closed */) {
18019
- this.connect(true);
18020
- }
18021
- };
18022
- /** @private */
18023
- this._req = async (params, config, retry) => {
18024
- if (!this.cancelToken && !params.close) {
18025
- this.cancelToken = import_axios3.default.CancelToken.source();
18026
- }
18027
- try {
18028
- const res = await this.client.api.doAxiosRequest(
18029
- "get",
18030
- this.client.baseURL.replace(":3030", ":8900") + "/longpoll",
18031
- // replace port if present for testing with local API
18032
- void 0,
18033
- { ...config, cancelToken: this.cancelToken?.token, params }
18034
- );
18035
- this.consecutiveFailures = 0;
18036
- return res;
18037
- } catch (error) {
18038
- this.consecutiveFailures += 1;
18039
- if (retry && isErrorRetryable(error)) {
18040
- logger8.withExtraTags("_req").debug("Encountered a retryable error. Retrying the request.");
18041
- await sleep(retryInterval(this.consecutiveFailures));
18042
- return this._req(params, config, retry);
18043
- }
18044
- throw error;
18045
- }
18046
- };
18047
- /** @private */
18048
- this._poll = async () => {
18049
- while (this.state === "CONNECTED" /* Connected */) {
18050
- try {
18051
- const data = await this._req({}, { timeout: 3e4 }, true);
18052
- if (data.events?.length) {
18053
- for (let i = 0; i < data.events.length; i++) {
18054
- this.client.dispatchEvent(data.events[i]);
18055
- }
18056
- }
18057
- } catch (error) {
18058
- if (import_axios3.default.isCancel(error)) {
18059
- logger8.withExtraTags("_poll").debug("Axios canceled the request.");
18060
- return;
18061
- }
18062
- if (isConnectionIDError(error)) {
18063
- logger8.withExtraTags("_poll").warn("Received a connection ID error. Reconnecting without an ID.");
18064
- this._setState("DISCONNECTED" /* Disconnected */);
18065
- this.connect(true);
18066
- return;
18067
- }
18068
- if (isAPIError(error) && !isErrorRetryable(error)) {
18069
- this._setState("CLOSED" /* Closed */);
18070
- return;
18071
- }
18072
- await sleep(retryInterval(this.consecutiveFailures));
18073
- }
18074
- }
18075
- };
18076
- /**
18077
- * connect try to open a longpoll request
18078
- *
18079
- * @param reconnect - should be false for first call and true for subsequent calls to keep the connection alive and call recoverState
18080
- */
18081
- this.connect = async (reconnect = false) => {
18082
- if (this.state === "CONNECTING" /* Connecting */) {
18083
- logger8.withExtraTags("connect").warn("A connection attempt is already in progress.", { reconnect });
18084
- return;
18085
- }
18086
- if (this.state === "CONNECTED" /* Connected */) {
18087
- logger8.withExtraTags("connect").warn("Already connected and polling.", { reconnect });
18088
- return;
18089
- }
18090
- this._setState("CONNECTING" /* Connecting */);
18091
- this.connectionID = void 0;
18092
- try {
18093
- const { event } = await this._req(
18094
- { json: this.client._buildWSPayload() },
18095
- { timeout: 8e3 },
18096
- // 8s
18097
- reconnect
18098
- );
18099
- this._setState("CONNECTED" /* Connected */);
18100
- this.connectionID = event.connection_id;
18101
- this.client.dispatchEvent(event);
18102
- this._poll();
18103
- if (reconnect) {
18104
- this.client.recoverState();
18105
- }
18106
- return event;
18107
- } catch (err) {
18108
- this._setState("CLOSED" /* Closed */);
18109
- throw err;
18110
- }
18111
- };
18112
- /**
18113
- * isHealthy checks if there is a connectionID and connection is in Connected state
18114
- */
18115
- this.isHealthy = () => !!this.connectionID && this.state === "CONNECTED" /* Connected */;
18116
- this.disconnect = async (timeout = 2e3) => {
18117
- removeConnectionEventListeners(this._onlineStatusChanged);
18118
- this._setState("DISCONNECTED" /* Disconnected */);
18119
- this.cancelToken?.cancel("disconnect() is called");
18120
- this.cancelToken = void 0;
18121
- const connection_id = this.connectionID;
18122
- this.connectionID = void 0;
18123
- try {
18124
- await this._req({ close: true, connection_id }, { timeout }, false);
18125
- logger8.withExtraTags("disconnect").info("Closed the connection ID.");
18126
- } catch (err) {
18127
- logger8.withExtraTags("disconnect").error("Disconnect failed.", { error: err });
18128
- }
18129
- };
18130
- this.client = client;
18131
- this.state = "INIT" /* Init */;
18132
- this.consecutiveFailures = 0;
18133
- addConnectionEventListeners(this._onlineStatusChanged);
18134
- }
18135
- _setState(state) {
18136
- logger8.withExtraTags("_setState").debug(`Transitioning to state: ${state}.`);
18137
- if (this.state === "CONNECTING" /* Connecting */ && state === "CONNECTED" /* Connected */) {
18138
- this.client.dispatchEvent({ type: "connection.changed", online: true });
18139
- }
18140
- if (state === "CLOSED" /* Closed */ || state === "DISCONNECTED" /* Disconnected */) {
18141
- this.client.dispatchEvent({ type: "connection.changed", online: false });
18142
- }
18143
- this.state = state;
17989
+ get isAnonymous() {
17990
+ return this._isAnonymous;
18144
17991
  }
18145
17992
  };
18146
17993
 
18147
17994
  // src/api-client.ts
18148
- var import_axios4 = require("axios");
17995
+ var import_axios3 = require("axios");
18149
17996
 
18150
17997
  // src/utils/retryable.ts
18151
17998
  var _RetryError = class _RetryError extends Error {
@@ -18193,20 +18040,30 @@ var runWithRetry = (f, {
18193
18040
  };
18194
18041
 
18195
18042
  // src/api-client.ts
18196
- var logger9 = chatLoggerSystem.getLogger("api-client");
18043
+ var logger8 = chatLoggerSystem.getLogger("api-client");
18044
+ var MULTIPART_CONTENT_TYPE = "multipart/form-data";
18045
+ var UPLOAD_REQUEST_DEFAULTS = {
18046
+ timeout: 0,
18047
+ maxContentLength: Infinity,
18048
+ maxBodyLength: Infinity
18049
+ };
18197
18050
  var ApiClient = class {
18198
18051
  constructor(client) {
18199
18052
  if (client) this.client = client;
18200
18053
  }
18201
18054
  _getToken() {
18202
- if (this.client.getAuthType() === "anonymous") return;
18203
18055
  return this.client.tokenManager.getToken();
18204
18056
  }
18205
18057
  sendRequest(method, url, pathParams, queryParams, body, requestContentType, options) {
18206
18058
  const resolvedUrl = this.resolveUrl(url, pathParams);
18207
- return this._doRequest(method, resolvedUrl, body, {
18059
+ const isMultipart = requestContentType === MULTIPART_CONTENT_TYPE;
18060
+ const requestBody = isMultipart && body && typeof body === "object" ? toFormData(body) : body;
18061
+ return this._doRequest(method, resolvedUrl, requestBody, {
18208
18062
  params: queryParams,
18209
18063
  headers: { "Content-Type": requestContentType },
18064
+ ...isMultipart ? UPLOAD_REQUEST_DEFAULTS : {},
18065
+ // Keep this last so a caller-supplied signal wins - and keep it returning only the keys
18066
+ // it owns, so it can never clobber the upload defaults above.
18210
18067
  ...toAxiosRequestConfig(options)
18211
18068
  });
18212
18069
  }
@@ -18228,16 +18085,6 @@ var ApiClient = class {
18228
18085
  delete(url, params) {
18229
18086
  return this._doRequest("delete", url, null, { params }).then((r) => r.body);
18230
18087
  }
18231
- sendFile(url, uri, name, contentType, user, axiosRequestConfig) {
18232
- const data = addFileToFormData(uri, name, contentType || "multipart/form-data");
18233
- if (user != null) data.append("user", JSON.stringify(user));
18234
- return this._doRequest("post", url, data, {
18235
- timeout: 0,
18236
- maxContentLength: Infinity,
18237
- maxBodyLength: Infinity,
18238
- ...axiosRequestConfig
18239
- }).then((response) => response.body);
18240
- }
18241
18088
  // --- private ---
18242
18089
  resolveUrl(url, pathParams) {
18243
18090
  let resolved = url;
@@ -18256,13 +18103,11 @@ var ApiClient = class {
18256
18103
  return {
18257
18104
  ...additonalConfig,
18258
18105
  headers: {
18106
+ ...this.client.options.axiosRequestConfig?.headers,
18107
+ ...additonalConfig.headers,
18259
18108
  Authorization: token,
18260
18109
  "stream-auth-type": this.client.getAuthType(),
18261
18110
  "x-stream-client": this.client.getUserAgent(),
18262
- ...additonalConfig.headers,
18263
- // TODO: figure out whether this is needed, setting these at a later time (client.options.axiosRequestConfig = {...}) should probably be a setter
18264
- // that updates existing axios instance options instead
18265
- ...this.client.options.axiosRequestConfig?.headers,
18266
18111
  "x-client-request-id": additonalConfig.headers?.["x-client-request-id"] || randomId()
18267
18112
  },
18268
18113
  params: {
@@ -18314,7 +18159,7 @@ var ApiClient = class {
18314
18159
  requestResponse = await this.client.axiosInstance.request(config);
18315
18160
  } catch (error) {
18316
18161
  if (isTokenExpiredError(error)) {
18317
- logger9.withExtraTags("_doRequest").debug(
18162
+ logger8.withExtraTags("_doRequest").debug(
18318
18163
  `The token expired on a ${type.toUpperCase()} request. Reloading the token before retrying.`,
18319
18164
  { url, config }
18320
18165
  );
@@ -18328,7 +18173,7 @@ var ApiClient = class {
18328
18173
  delayBetweenRetries: (attemptNumber) => retryInterval(attemptNumber + 1),
18329
18174
  retryAttempts: 10,
18330
18175
  isRetryable: (error) => {
18331
- if (!(error instanceof import_axios4.AxiosError)) return false;
18176
+ if (!(error instanceof import_axios3.AxiosError)) return false;
18332
18177
  if (error.status === 429 || isTokenExpiredError(error)) return true;
18333
18178
  return false;
18334
18179
  }
@@ -18353,12 +18198,16 @@ var ApiClient = class {
18353
18198
  };
18354
18199
  var isUsableAbortSignal = (signal) => typeof signal?.addEventListener === "function";
18355
18200
  var toAxiosRequestConfig = ({
18356
- signal
18201
+ signal,
18202
+ onUploadProgress
18357
18203
  } = {}) => ({
18358
- signal: isUsableAbortSignal(signal) ? signal : void 0
18204
+ signal: isUsableAbortSignal(signal) ? signal : void 0,
18205
+ // Same reasoning as `isUsableAbortSignal`: an options object revived from a persisted
18206
+ // offline-db task payload has lost its functions.
18207
+ onUploadProgress: typeof onUploadProgress === "function" ? onUploadProgress : void 0
18359
18208
  });
18360
18209
  var errorIsApiError = (error) => {
18361
- if (!(error instanceof import_axios4.AxiosError)) return false;
18210
+ if (!(error instanceof import_axios3.AxiosError)) return false;
18362
18211
  return typeof error.response?.data?.code === "number";
18363
18212
  };
18364
18213
  var isTokenExpiredError = (error) => errorIsApiError(error) && error.response?.data.code === chatCodes.TOKEN_EXPIRED;
@@ -18930,7 +18779,7 @@ var Moderation = class extends ModerationApi {
18930
18779
  };
18931
18780
 
18932
18781
  // src/thread_manager.ts
18933
- var eventIsHealthCheck = (event) => Object.hasOwn(event, "me");
18782
+ var eventCarriesOwnUser = (event) => Object.hasOwn(event, "me");
18934
18783
  var DEFAULT_CONNECTION_RECOVERY_THROTTLE_DURATION = 1e3;
18935
18784
  var MAX_QUERY_THREADS_LIMIT = 25;
18936
18785
  var THREAD_MANAGER_INITIAL_STATE = {
@@ -18948,7 +18797,7 @@ var THREAD_MANAGER_INITIAL_STATE = {
18948
18797
  },
18949
18798
  ready: false
18950
18799
  };
18951
- var logger10 = chatLoggerSystem.getLogger("thread-manager");
18800
+ var logger9 = chatLoggerSystem.getLogger("thread-manager");
18952
18801
  var ThreadManager = class extends WithSubscriptions {
18953
18802
  // cache used in combination with threadsById
18954
18803
  // used for threads which are not stored in the list
@@ -18978,13 +18827,14 @@ var ThreadManager = class extends WithSubscriptions {
18978
18827
  this.state.partialNext({ unreadThreadCount });
18979
18828
  const unsubscribeFunctions = [
18980
18829
  "health.check",
18830
+ "connection.ok",
18981
18831
  "notification.mark_read",
18982
18832
  "notification.mark_unread",
18983
18833
  "notification.thread_message_new",
18984
18834
  "notification.channel_deleted"
18985
18835
  ].map(
18986
18836
  (eventType) => this.client.on(eventType, (event) => {
18987
- const { unread_threads: unreadThreadCount2 } = eventIsHealthCheck(event) && event.me || event;
18837
+ const { unread_threads: unreadThreadCount2 } = eventCarriesOwnUser(event) && event.me || event;
18988
18838
  if (typeof unreadThreadCount2 === "number") {
18989
18839
  this.state.partialNext({ unreadThreadCount: unreadThreadCount2 });
18990
18840
  }
@@ -19100,7 +18950,7 @@ var ThreadManager = class extends WithSubscriptions {
19100
18950
  ready: true
19101
18951
  }));
19102
18952
  } catch (error) {
19103
- logger10.withExtraTags("reload").error("Failed to reload the thread list.", { error });
18953
+ logger9.withExtraTags("reload").error("Failed to reload the thread list.", { error });
19104
18954
  this.state.next((current) => ({
19105
18955
  ...current,
19106
18956
  pagination: {
@@ -19136,7 +18986,7 @@ var ThreadManager = class extends WithSubscriptions {
19136
18986
  }
19137
18987
  }));
19138
18988
  } catch (error) {
19139
- logger10.withExtraTags("loadNextPage").error("Failed to load the next page of threads.", { error });
18989
+ logger9.withExtraTags("loadNextPage").error("Failed to load the next page of threads.", { error });
19140
18990
  this.state.next((current) => ({
19141
18991
  ...current,
19142
18992
  pagination: {
@@ -22861,7 +22711,7 @@ var ChatApi = class {
22861
22711
  function isString(value) {
22862
22712
  return typeof value === "string" || value instanceof String;
22863
22713
  }
22864
- var logger11 = chatLoggerSystem.getLogger("client");
22714
+ var logger10 = chatLoggerSystem.getLogger("client");
22865
22715
  var offlineDbLogger3 = chatLoggerSystem.getLogger("offline-db");
22866
22716
  var StreamChat = class _StreamChat extends ChatApi {
22867
22717
  /**
@@ -22893,7 +22743,7 @@ var StreamChat = class _StreamChat extends ChatApi {
22893
22743
  */
22894
22744
  this.preventThreadCleanup = false;
22895
22745
  this.instanceConfigurationService = new InstanceConfigurationService();
22896
- this._getConnectionID = () => this.wsConnection?.connectionID || this.wsFallback?.connectionID;
22746
+ this._getConnectionID = () => this.wsConnection?.connectionID;
22897
22747
  this._hasConnectionID = () => Boolean(this._getConnectionID());
22898
22748
  this.setMessageComposerSetupFunction = (setupFunction) => {
22899
22749
  this.instanceConfigurationService.setSetupFunctions({
@@ -22915,7 +22765,7 @@ var StreamChat = class _StreamChat extends ChatApi {
22915
22765
  throw new Error('The "id" field on the user is missing');
22916
22766
  }
22917
22767
  if (this.userId === user.id && this.setUserPromise) {
22918
- logger11.withExtraTags("connectUser").warn(
22768
+ logger10.withExtraTags("connectUser").warn(
22919
22769
  "Detected consecutive calls to connectUser. Ideally, this function should only be called once."
22920
22770
  );
22921
22771
  return this.setUserPromise;
@@ -22926,7 +22776,7 @@ var StreamChat = class _StreamChat extends ChatApi {
22926
22776
  );
22927
22777
  }
22928
22778
  if (this.node && !this.options.allowServerSideConnect) {
22929
- logger11.withExtraTags("connectUser").warn(
22779
+ logger10.withExtraTags("connectUser").warn(
22930
22780
  'Do not use connectUser server-side. connectUser impacts MAU and concurrent connection usage, and therefore your bill. If you have a valid use case, set "allowServerSideConnect: true" in the client options to disable this warning.'
22931
22781
  );
22932
22782
  }
@@ -22977,10 +22827,7 @@ var StreamChat = class _StreamChat extends ChatApi {
22977
22827
  clearInterval(this.cleaningIntervalRef);
22978
22828
  this.cleaningIntervalRef = void 0;
22979
22829
  }
22980
- await Promise.all([
22981
- this.wsConnection?.disconnect(timeout),
22982
- this.wsFallback?.disconnect(timeout)
22983
- ]);
22830
+ await this.wsConnection?.disconnect(timeout);
22984
22831
  this.offlineDb?.executeQuerySafely(
22985
22832
  async (db) => {
22986
22833
  if (this.userId) {
@@ -23006,11 +22853,11 @@ var StreamChat = class _StreamChat extends ChatApi {
23006
22853
  );
23007
22854
  }
23008
22855
  if (this.wsConnection?.isConnecting && this.wsPromise) {
23009
- logger11.withExtraTags("openConnection").debug("A connection attempt is already in progress.");
22856
+ logger10.withExtraTags("openConnection").debug("A connection attempt is already in progress.");
23010
22857
  return this.wsPromise;
23011
22858
  }
23012
- if ((this.wsConnection?.isHealthy || this.wsFallback?.isHealthy()) && this._hasConnectionID()) {
23013
- logger11.withExtraTags("openConnection").debug("openConnection was called twice; a healthy connection already exists.");
22859
+ if (this.wsConnection?.isHealthy && this._hasConnectionID()) {
22860
+ logger10.withExtraTags("openConnection").debug("openConnection was called twice; a healthy connection already exists.");
23014
22861
  return;
23015
22862
  }
23016
22863
  this.clientId = `${this.userId}--${randomId()}`;
@@ -23026,7 +22873,7 @@ var StreamChat = class _StreamChat extends ChatApi {
23026
22873
  * @returns The close-connection promise.
23027
22874
  */
23028
22875
  this.disconnectUser = (timeout) => {
23029
- logger11.withExtraTags("disconnectUser").info("Disconnecting the client.");
22876
+ logger10.withExtraTags("disconnectUser").info("Disconnecting the client.");
23030
22877
  delete this.user;
23031
22878
  delete this._user;
23032
22879
  const closePromise = this.closeConnection(timeout);
@@ -23043,7 +22890,7 @@ var StreamChat = class _StreamChat extends ChatApi {
23043
22890
  closePromise.finally(() => {
23044
22891
  this.tokenManager.reset();
23045
22892
  }).catch(
23046
- (err) => logger11.withExtraTags("disconnectUser").error("The close promise rejected during disconnect.", { error: err })
22893
+ (err) => logger10.withExtraTags("disconnectUser").error("The close promise rejected during disconnect.", { error: err })
23047
22894
  );
23048
22895
  return closePromise;
23049
22896
  };
@@ -23061,7 +22908,7 @@ var StreamChat = class _StreamChat extends ChatApi {
23061
22908
  */
23062
22909
  this.connectAnonymousUser = () => {
23063
22910
  if (this.node && !this.options.allowServerSideConnect) {
23064
- logger11.withExtraTags("connectAnonymousUser").warn(
22911
+ logger10.withExtraTags("connectAnonymousUser").warn(
23065
22912
  'Do not use connectUser server-side. connectUser impacts MAU and concurrent connection usage, and therefore your bill. If you have a valid use case, set "allowServerSideConnect: true" in the client options to disable this warning.'
23066
22913
  );
23067
22914
  }
@@ -23216,10 +23063,10 @@ var StreamChat = class _StreamChat extends ChatApi {
23216
23063
  );
23217
23064
  };
23218
23065
  this.recoverState = async () => {
23219
- logger11.withExtraTags("recoverState").info(`Starting state recovery with connection ID ${this._getConnectionID()}.`);
23066
+ logger10.withExtraTags("recoverState").info(`Starting state recovery with connection ID ${this._getConnectionID()}.`);
23220
23067
  const cids = Object.keys(this.activeChannels);
23221
23068
  if (cids.length && this.recoverStateOnReconnect) {
23222
- logger11.withExtraTags("recoverState").info(`Starting the query for ${cids.length} channel(s).`);
23069
+ logger10.withExtraTags("recoverState").info(`Starting the query for ${cids.length} channel(s).`);
23223
23070
  await this.queryChannelsAndHydrate({
23224
23071
  filter_conditions: {
23225
23072
  cid: { $in: cids }
@@ -23227,7 +23074,7 @@ var StreamChat = class _StreamChat extends ChatApi {
23227
23074
  limit: 30,
23228
23075
  sort: [{ field: "last_message_at", direction: -1 }]
23229
23076
  });
23230
- logger11.withExtraTags("recoverState").info("Finished querying channels.");
23077
+ logger10.withExtraTags("recoverState").info("Finished querying channels.");
23231
23078
  this.dispatchEvent({
23232
23079
  type: "connection.recovered"
23233
23080
  });
@@ -23325,7 +23172,7 @@ var StreamChat = class _StreamChat extends ChatApi {
23325
23172
  return this.userAgent;
23326
23173
  }
23327
23174
  if (!this.cachedUserAgent) {
23328
- const version = "10.0.0-rc.3";
23175
+ const version = "10.0.0-rc.4";
23329
23176
  const { name: sdkName, version: sdkVersion } = this.sdkIdentifier ?? {};
23330
23177
  const { name: appName, version: appVersion } = this.appIdentifier ?? {};
23331
23178
  const { os, model: deviceModel } = this.deviceIdentifier ?? {};
@@ -23347,18 +23194,23 @@ var StreamChat = class _StreamChat extends ChatApi {
23347
23194
  };
23348
23195
  this._cacheEnabled = () => !this.options.disableCache;
23349
23196
  /**
23350
- * Encodes the WS URL payload.
23197
+ * Encodes the WebSocket auth message, sent as the first frame once the socket opens.
23198
+ *
23199
+ * `products` is not optional in practice: without `'chat'` the server treats the
23200
+ * connection as video-only, which drops every chat event and unread count.
23351
23201
  *
23352
23202
  * @private
23353
23203
  *
23354
- * @param client_request_id - The client request ID (optional).
23355
- * @returns The JSON-encoded payload string.
23204
+ * @returns The JSON-encoded auth message.
23356
23205
  */
23357
- this._buildWSPayload = (client_request_id) => JSON.stringify({
23358
- user_id: this.userId,
23206
+ this._buildWSAuthMessage = () => JSON.stringify({
23207
+ // The server requires a non-empty token even for anonymous connections, but
23208
+ // skips JWT parsing for any string that is not shaped like one. Anonymous users
23209
+ // have no token, so send a placeholder the server accepts and ignores.
23210
+ token: this.tokenManager.getToken() || "anonymous",
23211
+ // `connect()` rejects before reaching this when `_user` is unset.
23359
23212
  user_details: this._user,
23360
- device: this.options.device,
23361
- client_request_id
23213
+ products: ["chat"]
23362
23214
  });
23363
23215
  this.apiClient.client = this;
23364
23216
  this.key = key;
@@ -23385,7 +23237,7 @@ var StreamChat = class _StreamChat extends ChatApi {
23385
23237
  wsUrlParams: new URLSearchParams({}),
23386
23238
  ...options
23387
23239
  };
23388
- this.axiosInstance = import_axios5.default.create({
23240
+ this.axiosInstance = import_axios4.default.create({
23389
23241
  timeout: 3e3,
23390
23242
  withCredentials: false,
23391
23243
  ...this.options.axiosRequestConfig,
@@ -23408,7 +23260,6 @@ var StreamChat = class _StreamChat extends ChatApi {
23408
23260
  this.persistUserOnConnectionFailure = this.options?.persistUserOnConnectionFailure;
23409
23261
  this.tokenManager = new TokenManager();
23410
23262
  this.insightMetrics = new InsightMetrics();
23411
- this.defaultWSTimeoutWithFallback = 6 * 1e3;
23412
23263
  this.defaultWSTimeout = 15 * 1e3;
23413
23264
  this.recoverStateOnReconnect = this.options.recoverStateOnReconnect;
23414
23265
  this.messageStore = new EntityStore({
@@ -23422,7 +23273,7 @@ var StreamChat = class _StreamChat extends ChatApi {
23422
23273
  this.messageComposerCache = new FixedSizeQueueCache(64);
23423
23274
  }
23424
23275
  get anonymous() {
23425
- return this.user?.anon ?? false;
23276
+ return this.tokenManager.isAnonymous;
23426
23277
  }
23427
23278
  get userId() {
23428
23279
  return this.user?.id;
@@ -23537,6 +23388,26 @@ var StreamChat = class _StreamChat extends ChatApi {
23537
23388
  async getAppSettings(requestOptions) {
23538
23389
  return await (this.appSettingsPromise = this.getApp(requestOptions));
23539
23390
  }
23391
+ /**
23392
+ * Creates a guest user and returns its access token.
23393
+ *
23394
+ * @param args - The guest creation request, plus optional per-request options.
23395
+ * @returns The created guest user and its access token.
23396
+ */
23397
+ async createGuest(...args) {
23398
+ if (this.tokenManager.token || this.tokenManager.tokenProvider) {
23399
+ return await super.createGuest(...args);
23400
+ }
23401
+ await this.tokenManager.setTokenOrProvider("", {
23402
+ id: this.userId ?? "!anon",
23403
+ anon: true
23404
+ });
23405
+ try {
23406
+ return await super.createGuest(...args);
23407
+ } finally {
23408
+ this.tokenManager.reset();
23409
+ }
23410
+ }
23540
23411
  /**
23541
23412
  * Sets up a temporary guest user.
23542
23413
  *
@@ -23560,14 +23431,14 @@ var StreamChat = class _StreamChat extends ChatApi {
23560
23431
  const key = callbackOrNothing ? callbackOrString : "all";
23561
23432
  const callback = callbackOrNothing ? callbackOrNothing : callbackOrString;
23562
23433
  const set = this.listeners.get(key) ?? /* @__PURE__ */ new Set();
23563
- logger11.withExtraTags("on").debug(`Attaching a listener for the "${key}" event.`);
23434
+ logger10.withExtraTags("on").debug(`Attaching a listener for the "${key}" event.`);
23564
23435
  set.add(callback);
23565
23436
  if (!this.listeners.has(key)) {
23566
23437
  this.listeners.set(key, set);
23567
23438
  }
23568
23439
  return {
23569
23440
  unsubscribe: () => {
23570
- logger11.withExtraTags("on").debug(`Removing the listener for the "${key}" event.`);
23441
+ logger10.withExtraTags("on").debug(`Removing the listener for the "${key}" event.`);
23571
23442
  set.delete(callback);
23572
23443
  if (!set.size) {
23573
23444
  this.listeners.delete(key);
@@ -23578,7 +23449,7 @@ var StreamChat = class _StreamChat extends ChatApi {
23578
23449
  off(callbackOrString, callbackOrNothing) {
23579
23450
  const key = callbackOrNothing ? callbackOrString : "all";
23580
23451
  const callback = callbackOrNothing ? callbackOrNothing : callbackOrString;
23581
- logger11.withExtraTags("off").debug(`Removing the listener for the "${key}" event.`);
23452
+ logger10.withExtraTags("off").debug(`Removing the listener for the "${key}" event.`);
23582
23453
  const set = this.listeners.get(key);
23583
23454
  set?.delete(callback);
23584
23455
  if (!set?.size) {
@@ -23588,14 +23459,14 @@ var StreamChat = class _StreamChat extends ChatApi {
23588
23459
  _handleClientEvent(event) {
23589
23460
  const client = this;
23590
23461
  const postListenerCallbacks = [];
23591
- logger11.withExtraTags("_handleClientEvent").debug(`Received an event of type "${event.type}".`, { event });
23462
+ logger10.withExtraTags("_handleClientEvent").debug(`Received an event of type "${event.type}".`, { event });
23592
23463
  if (event.type === "user.presence.changed" || event.type === "user.updated" || event.type === "user.deleted") {
23593
23464
  this._handleUserEvent(event);
23594
23465
  }
23595
23466
  if (event.type === "user.messages.deleted" && !event.cid && event.user) {
23596
23467
  this._deleteUserMessageReference(event.user, event.hard_delete, event.created_at);
23597
23468
  }
23598
- if (event.type === "health.check" && event.me) {
23469
+ if ((event.type === "health.check" || event.type === "connection.ok") && event.me) {
23599
23470
  client.user = event.me;
23600
23471
  client.state.updateUser(event.me);
23601
23472
  client.mutedChannels = event.me.channel_mutes;
@@ -23684,26 +23555,7 @@ var StreamChat = class _StreamChat extends ChatApi {
23684
23555
  client: this
23685
23556
  });
23686
23557
  }
23687
- try {
23688
- if (this.wsFallback) {
23689
- return await this.wsFallback.connect();
23690
- }
23691
- return await this.wsConnection.connect(
23692
- this.options.enableWSFallback ? this.defaultWSTimeoutWithFallback : this.defaultWSTimeout
23693
- );
23694
- } catch (error) {
23695
- if (this.options.enableWSFallback && isWSFailure(error) && isOnline()) {
23696
- logger11.withExtraTags("connect").warn("The WebSocket connection failed; falling back to long-polling.");
23697
- this.dispatchEvent({ type: "transport.changed", mode: "longpoll" });
23698
- this.wsConnection._destroyCurrentWSConnection();
23699
- this.wsConnection.disconnect().then();
23700
- this.wsFallback = new WSConnectionFallback({
23701
- client: this
23702
- });
23703
- return await this.wsFallback.connect();
23704
- }
23705
- throw error;
23706
- }
23558
+ return await this.wsConnection.connect(this.defaultWSTimeout);
23707
23559
  }
23708
23560
  /**
23709
23561
  * Checks connectivity with the server for warmup purposes.
@@ -23924,19 +23776,6 @@ var StreamChat = class _StreamChat extends ChatApi {
23924
23776
  await this.wsPromise;
23925
23777
  return await super.search(request, requestOptions);
23926
23778
  }
23927
- /**
23928
- * Sets the device info for the current client. It will be sent via the WS connection automatically.
23929
- *
23930
- * @param device - The device object.
23931
- * @param device.id - Device ID.
23932
- * @param device.push_provider - The push provider.
23933
- */
23934
- setLocalDevice(device) {
23935
- if (this.wsConnection?.isConnecting && this.wsPromise || (this.wsConnection?.isHealthy || this.wsFallback?.isHealthy()) && this._hasConnectionID()) {
23936
- throw new Error("Device cannot be set before opening a WebSocket connection");
23937
- }
23938
- this.options.device = device;
23939
- }
23940
23779
  _addChannelConfig({ cid, config }) {
23941
23780
  if (this._cacheEnabled()) {
23942
23781
  this.configs = {
@@ -24468,43 +24307,29 @@ var StreamChat = class _StreamChat extends ChatApi {
24468
24307
  );
24469
24308
  }
24470
24309
  /**
24471
- * Uploads a file to the configured storage (defaults to Stream CDN).
24310
+ * Uploads a file to the Stream CDN
24472
24311
  *
24473
- * @param uri - The file to upload.
24474
- * @param name - The name of the file (optional).
24475
- * @param contentType - MIME type; required for React Native URI uploads (optional).
24476
- * @param user - User information (optional).
24477
- * @param axiosRequestConfig - Axios config, e.g. `onUploadProgress` for progress tracking (optional).
24312
+ * @param request - Upload payload. `request.file` is the file to upload.
24313
+ * @param requestOptions - Per-request options, e.g. `onUploadProgress` or an abort `signal` (optional).
24478
24314
  * @returns Response containing the file URL.
24479
24315
  */
24480
- uploadFile_(uri, name, contentType, user, axiosRequestConfig) {
24481
- return this.api.sendFile(
24482
- `${this.baseURL}/uploads/file`,
24483
- uri,
24484
- name,
24485
- contentType,
24486
- user,
24487
- axiosRequestConfig
24316
+ async uploadFile(request, requestOptions) {
24317
+ return await super.uploadFile(
24318
+ { ...request, file: normalizeUploadFile(request?.file) },
24319
+ requestOptions
24488
24320
  );
24489
24321
  }
24490
24322
  /**
24491
- * Uploads an image to the configured storage (defaults to Stream CDN).
24323
+ * Uploads an image to Stream CDN
24492
24324
  *
24493
- * @param uri - The image to upload.
24494
- * @param name - The name of the image (optional).
24495
- * @param contentType - MIME type; required for React Native URI uploads (optional).
24496
- * @param user - User information (optional).
24497
- * @param axiosRequestConfig - Axios config, e.g. `onUploadProgress` for progress tracking (optional).
24325
+ * @param request - Upload payload. `request.file` is the image to upload.
24326
+ * @param requestOptions - Per-request options, e.g. `onUploadProgress` or an abort `signal` (optional).
24498
24327
  * @returns Response containing the image URL.
24499
24328
  */
24500
- uploadImage_(uri, name, contentType, user, axiosRequestConfig) {
24501
- return this.api.sendFile(
24502
- `${this.baseURL}/uploads/image`,
24503
- uri,
24504
- name,
24505
- contentType,
24506
- user,
24507
- axiosRequestConfig
24329
+ async uploadImage(request, requestOptions) {
24330
+ return await super.uploadImage(
24331
+ { ...request, file: normalizeUploadFile(request?.file) },
24332
+ requestOptions
24508
24333
  );
24509
24334
  }
24510
24335
  /**
@@ -24611,8 +24436,8 @@ var OfflineError = class extends Error {
24611
24436
  };
24612
24437
 
24613
24438
  // src/offline-support/offline_sync_manager.ts
24614
- var import_axios6 = require("axios");
24615
- var logger12 = chatLoggerSystem.getLogger("offline-db");
24439
+ var import_axios5 = require("axios");
24440
+ var logger11 = chatLoggerSystem.getLogger("offline-db");
24616
24441
  var OfflineDBSyncManager = class {
24617
24442
  constructor({
24618
24443
  client,
@@ -24650,7 +24475,7 @@ var OfflineDBSyncManager = class {
24650
24475
  }
24651
24476
  );
24652
24477
  } catch (error) {
24653
- logger12.withExtraTags("init").error("Failed to initialize the offline DB sync manager.", { error });
24478
+ logger11.withExtraTags("init").error("Failed to initialize the offline DB sync manager.", { error });
24654
24479
  }
24655
24480
  };
24656
24481
  /**
@@ -24740,7 +24565,7 @@ var OfflineDBSyncManager = class {
24740
24565
  const { syncMaxEventCount } = this;
24741
24566
  const exceedsLimit = typeof syncMaxEventCount === "number" && syncMaxEventCount > 0 && result.events.length > syncMaxEventCount;
24742
24567
  if (exceedsLimit) {
24743
- logger12.withExtraTags("sync").warn(
24568
+ logger11.withExtraTags("sync").warn(
24744
24569
  `Skipping sync event replay: received ${result.events.length} events, which exceeds the configured limit of ${syncMaxEventCount}. Visible channels are refreshed on reconnect instead.`
24745
24570
  );
24746
24571
  } else {
@@ -24760,8 +24585,8 @@ var OfflineDBSyncManager = class {
24760
24585
  lastSyncedAt: (/* @__PURE__ */ new Date()).toString()
24761
24586
  });
24762
24587
  } catch (e) {
24763
- logger12.withExtraTags("syncAndExecutePendingTasks").error("An error occurred while syncing the database.", { error: e });
24764
- if ((0, import_axios6.isAxiosError)(e) && e.code === "ECONNABORTED") {
24588
+ logger11.withExtraTags("syncAndExecutePendingTasks").error("An error occurred while syncing the database.", { error: e });
24589
+ if ((0, import_axios5.isAxiosError)(e) && e.code === "ECONNABORTED") {
24765
24590
  return;
24766
24591
  }
24767
24592
  const error = e;
@@ -24800,7 +24625,7 @@ var OfflineDBSyncManager = class {
24800
24625
  };
24801
24626
 
24802
24627
  // src/offline-support/offline_support_api.ts
24803
- var logger13 = chatLoggerSystem.getLogger("offline-db");
24628
+ var logger12 = chatLoggerSystem.getLogger("offline-db");
24804
24629
  var AbstractOfflineDB = class {
24805
24630
  constructor({
24806
24631
  client,
@@ -24825,7 +24650,7 @@ var AbstractOfflineDB = class {
24825
24650
  }
24826
24651
  } catch (error) {
24827
24652
  this.state.partialNext({ initialized: false, userId: void 0 });
24828
- logger13.withExtraTags("init").error("Failed to initialize the offline database.", { error });
24653
+ logger12.withExtraTags("init").error("Failed to initialize the offline database.", { error });
24829
24654
  }
24830
24655
  };
24831
24656
  /**
@@ -24901,14 +24726,14 @@ var AbstractOfflineDB = class {
24901
24726
  }
24902
24727
  return newQueries;
24903
24728
  } else {
24904
- logger13.withExtraTags("queriesWithChannelGuard").warn(
24729
+ logger12.withExtraTags("queriesWithChannelGuard").warn(
24905
24730
  `Could not create channel queries on a "${type}" event for an initialized channel that is not in the database. Skipping the event.`,
24906
24731
  { event }
24907
24732
  );
24908
24733
  return [];
24909
24734
  }
24910
24735
  } else {
24911
- logger13.withExtraTags("queriesWithChannelGuard").warn(
24736
+ logger12.withExtraTags("queriesWithChannelGuard").warn(
24912
24737
  `Received a "${type}" event for a non-initialized channel that is not in the database. Skipping the event.`,
24913
24738
  { event }
24914
24739
  );