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.
- package/dist/cjs/index.browser.js +202 -377
- package/dist/cjs/index.browser.js.map +4 -4
- package/dist/cjs/index.node.js +202 -377
- package/dist/cjs/index.node.js.map +4 -4
- package/dist/esm/index.mjs +197 -372
- package/dist/esm/index.mjs.map +4 -4
- package/dist/types/api-client.d.ts +1 -2
- package/dist/types/channel.d.ts +20 -17
- package/dist/types/client.d.ts +34 -46
- package/dist/types/connection.d.ts +4 -10
- package/dist/types/errors.d.ts +0 -1
- package/dist/types/insights.d.ts +0 -2
- package/dist/types/logger.d.ts +1 -1
- package/dist/types/messageComposer/attachmentManager.d.ts +3 -9
- package/dist/types/messageComposer/types.d.ts +2 -3
- package/dist/types/token_manager.d.ts +3 -1
- package/dist/types/types.d.ts +35 -9
- package/dist/types/upload-utils.d.ts +20 -0
- package/dist/types/utils.d.ts +0 -1
- package/package.json +1 -1
- package/src/api-client.ts +39 -35
- package/src/channel.ts +32 -39
- package/src/client.ts +73 -119
- package/src/connection.ts +52 -22
- package/src/errors.ts +0 -4
- package/src/insights.ts +0 -1
- package/src/logger.ts +0 -1
- package/src/messageComposer/attachmentManager.ts +33 -29
- package/src/messageComposer/types.ts +14 -14
- package/src/thread_manager.ts +5 -2
- package/src/token_manager.ts +9 -2
- package/src/types.ts +39 -6
- package/src/upload-utils.ts +53 -0
- package/src/utils.ts +0 -27
- package/dist/types/connection_fallback.d.ts +0 -42
- package/src/connection_fallback.ts +0 -215
|
@@ -230,7 +230,7 @@ __export(index_exports, {
|
|
|
230
230
|
module.exports = __toCommonJS(index_exports);
|
|
231
231
|
|
|
232
232
|
// src/client.ts
|
|
233
|
-
var
|
|
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
|
|
2430
|
+
const requestOptions = {
|
|
2473
2431
|
...progressHandler ? { onUploadProgress: progressHandler } : {},
|
|
2474
2432
|
...options?.abortSignal ? { signal: options.abortSignal } : {}
|
|
2475
|
-
}
|
|
2476
|
-
|
|
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 {
|
|
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
|
|
13405
|
+
* Upload a file to this channel's file endpoint (multipart).
|
|
13412
13406
|
*
|
|
13413
|
-
* @param
|
|
13414
|
-
* @param
|
|
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
|
-
|
|
13421
|
-
return
|
|
13422
|
-
|
|
13423
|
-
|
|
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).
|
|
13418
|
+
* Upload an image to this channel's image endpoint (multipart).
|
|
13432
13419
|
*
|
|
13433
|
-
* @param
|
|
13434
|
-
* @param
|
|
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
|
-
|
|
13441
|
-
return
|
|
13442
|
-
|
|
13443
|
-
|
|
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
|
|
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 =
|
|
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,
|
|
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 =
|
|
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
|
|
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
|
|
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.
|
|
17992
|
-
return
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 } =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
22856
|
+
logger10.withExtraTags("openConnection").debug("A connection attempt is already in progress.");
|
|
23010
22857
|
return this.wsPromise;
|
|
23011
22858
|
}
|
|
23012
|
-
if (
|
|
23013
|
-
|
|
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
|
-
|
|
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) =>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
-
* @
|
|
23355
|
-
* @returns The JSON-encoded payload string.
|
|
23204
|
+
* @returns The JSON-encoded auth message.
|
|
23356
23205
|
*/
|
|
23357
|
-
this.
|
|
23358
|
-
|
|
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
|
-
|
|
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 =
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
24310
|
+
* Uploads a file to the Stream CDN
|
|
24472
24311
|
*
|
|
24473
|
-
* @param
|
|
24474
|
-
* @param
|
|
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
|
-
|
|
24481
|
-
return
|
|
24482
|
-
|
|
24483
|
-
|
|
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
|
|
24323
|
+
* Uploads an image to Stream CDN
|
|
24492
24324
|
*
|
|
24493
|
-
* @param
|
|
24494
|
-
* @param
|
|
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
|
-
|
|
24501
|
-
return
|
|
24502
|
-
|
|
24503
|
-
|
|
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
|
|
24615
|
-
var
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
24764
|
-
if ((0,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
);
|