stream-chat 4.4.3-dev.0 → 4.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +844 -0
- package/dist/browser.es.js +705 -682
- package/dist/browser.es.js.map +1 -1
- package/dist/browser.full-bundle.min.js +1 -1
- package/dist/browser.full-bundle.min.js.map +1 -1
- package/dist/browser.js +705 -681
- package/dist/browser.js.map +1 -1
- package/dist/index.es.js +705 -682
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +705 -681
- package/dist/index.js.map +1 -1
- package/dist/types/client.d.ts +7 -10
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/connection.d.ts +4 -4
- package/dist/types/connection.d.ts.map +1 -1
- package/dist/types/insights.d.ts +13 -6
- package/dist/types/insights.d.ts.map +1 -1
- package/dist/types/types.d.ts +1 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/utils.d.ts +1 -1
- package/dist/types/utils.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/client.ts +34 -38
- package/src/connection.ts +15 -13
- package/src/insights.ts +33 -19
- package/src/types.ts +2 -0
- package/src/utils.ts +10 -5
package/src/client.ts
CHANGED
|
@@ -118,7 +118,7 @@ import {
|
|
|
118
118
|
DeleteChannelsResponse,
|
|
119
119
|
TaskResponse,
|
|
120
120
|
} from './types';
|
|
121
|
-
import {
|
|
121
|
+
import { InsightMetrics, postInsights } from './insights';
|
|
122
122
|
|
|
123
123
|
function isString(x: unknown): x is string {
|
|
124
124
|
return typeof x === 'string' || x instanceof String;
|
|
@@ -269,7 +269,7 @@ export class StreamChat<
|
|
|
269
269
|
|
|
270
270
|
this.axiosInstance = axios.create(this.options);
|
|
271
271
|
|
|
272
|
-
this.setBaseURL(this.options.baseURL || 'https://chat
|
|
272
|
+
this.setBaseURL(this.options.baseURL || 'https://chat.stream-io-api.com');
|
|
273
273
|
|
|
274
274
|
if (typeof process !== 'undefined' && process.env.STREAM_LOCAL_TEST_RUN) {
|
|
275
275
|
this.setBaseURL('http://localhost:3030');
|
|
@@ -1140,6 +1140,7 @@ export class StreamChat<
|
|
|
1140
1140
|
this.consecutiveFailures = 0;
|
|
1141
1141
|
return this.handleResponse(response);
|
|
1142
1142
|
} catch (e) {
|
|
1143
|
+
e.client_request_id = requestConfig.headers?.['x-client-request-id'];
|
|
1143
1144
|
this._logApiError(type, url, e);
|
|
1144
1145
|
this.consecutiveFailures += 1;
|
|
1145
1146
|
if (e.response) {
|
|
@@ -1619,10 +1620,14 @@ export class StreamChat<
|
|
|
1619
1620
|
throw Error('clientID is not set');
|
|
1620
1621
|
}
|
|
1621
1622
|
|
|
1622
|
-
|
|
1623
|
+
if (!this.wsConnection && (this.options.warmUp || this.options.enableInsights)) {
|
|
1624
|
+
this._sayHi();
|
|
1625
|
+
}
|
|
1623
1626
|
|
|
1627
|
+
// The StableWSConnection handles all the reconnection logic.
|
|
1624
1628
|
this.wsConnection = new StableWSConnection<ChannelType, CommandType, UserType>({
|
|
1625
1629
|
wsBaseURL: client.wsBaseURL,
|
|
1630
|
+
enableInsights: this.options.enableInsights,
|
|
1626
1631
|
clientID: client.clientID,
|
|
1627
1632
|
userID: client.userID,
|
|
1628
1633
|
tokenManager: client.tokenManager,
|
|
@@ -1635,24 +1640,29 @@ export class StreamChat<
|
|
|
1635
1640
|
eventCallback: this.dispatchEvent as (event: ConnectionChangeEvent) => void,
|
|
1636
1641
|
logger: this.logger,
|
|
1637
1642
|
device: this.options.device,
|
|
1638
|
-
postInsights: this.options.enableInsights ? this.postInsights : undefined,
|
|
1639
1643
|
insightMetrics: this.insightMetrics,
|
|
1640
1644
|
});
|
|
1641
1645
|
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
warmUpPromise = this.doAxiosRequest('options', this.baseURL + '/connect');
|
|
1645
|
-
}
|
|
1646
|
-
const handshake = await this.wsConnection.connect();
|
|
1647
|
-
try {
|
|
1648
|
-
await warmUpPromise;
|
|
1649
|
-
} catch (e) {
|
|
1650
|
-
this.logger('error', 'Warmup request failed', {
|
|
1651
|
-
error: e,
|
|
1652
|
-
});
|
|
1653
|
-
}
|
|
1646
|
+
return await this.wsConnection.connect();
|
|
1647
|
+
}
|
|
1654
1648
|
|
|
1655
|
-
|
|
1649
|
+
/**
|
|
1650
|
+
* Check the connectivity with server for warmup purpose.
|
|
1651
|
+
*
|
|
1652
|
+
* @private
|
|
1653
|
+
*/
|
|
1654
|
+
_sayHi() {
|
|
1655
|
+
const client_request_id = randomId();
|
|
1656
|
+
const opts = { headers: { 'x-client-request-id': client_request_id } };
|
|
1657
|
+
this.doAxiosRequest('get', this.baseURL + '/hi', null, opts).catch((e) => {
|
|
1658
|
+
if (this.options.enableInsights) {
|
|
1659
|
+
postInsights('http_hi_failed', {
|
|
1660
|
+
api_key: this.key,
|
|
1661
|
+
err: e,
|
|
1662
|
+
client_request_id,
|
|
1663
|
+
});
|
|
1664
|
+
}
|
|
1665
|
+
});
|
|
1656
1666
|
}
|
|
1657
1667
|
|
|
1658
1668
|
/**
|
|
@@ -2912,6 +2922,13 @@ export class StreamChat<
|
|
|
2912
2922
|
) {
|
|
2913
2923
|
const token = this._getToken();
|
|
2914
2924
|
|
|
2925
|
+
if (!options.headers?.['x-client-request-id']) {
|
|
2926
|
+
options.headers = {
|
|
2927
|
+
...options.headers,
|
|
2928
|
+
'x-client-request-id': randomId(),
|
|
2929
|
+
};
|
|
2930
|
+
}
|
|
2931
|
+
|
|
2915
2932
|
return {
|
|
2916
2933
|
params: {
|
|
2917
2934
|
user_id: this.userID,
|
|
@@ -3349,27 +3366,6 @@ export class StreamChat<
|
|
|
3349
3366
|
);
|
|
3350
3367
|
}
|
|
3351
3368
|
|
|
3352
|
-
postInsights = async (insightType: InsightTypes, insights: Record<string, unknown>) => {
|
|
3353
|
-
const maxAttempts = 3;
|
|
3354
|
-
for (let i = 0; i < maxAttempts; i++) {
|
|
3355
|
-
try {
|
|
3356
|
-
await this.axiosInstance.post(
|
|
3357
|
-
`https://insights.stream-io-api.com/insights/${insightType}`,
|
|
3358
|
-
insights,
|
|
3359
|
-
);
|
|
3360
|
-
} catch (e) {
|
|
3361
|
-
this.logger('warn', `failed to send insights event ${insightType}`, {
|
|
3362
|
-
tags: ['insights', 'connection'],
|
|
3363
|
-
error: e,
|
|
3364
|
-
insights,
|
|
3365
|
-
});
|
|
3366
|
-
await sleep((i + 1) * 3000);
|
|
3367
|
-
continue;
|
|
3368
|
-
}
|
|
3369
|
-
break;
|
|
3370
|
-
}
|
|
3371
|
-
};
|
|
3372
|
-
|
|
3373
3369
|
/**
|
|
3374
3370
|
* deleteUsers - Batch Delete Users
|
|
3375
3371
|
*
|
package/src/connection.ts
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
buildWsFatalInsight,
|
|
6
6
|
buildWsSuccessAfterFailureInsight,
|
|
7
7
|
InsightMetrics,
|
|
8
|
-
|
|
8
|
+
postInsights,
|
|
9
9
|
} from './insights';
|
|
10
10
|
import {
|
|
11
11
|
BaseDeviceFields,
|
|
@@ -48,7 +48,7 @@ type Constructor<
|
|
|
48
48
|
userID: string;
|
|
49
49
|
wsBaseURL: string;
|
|
50
50
|
device?: BaseDeviceFields;
|
|
51
|
-
|
|
51
|
+
enableInsights?: boolean;
|
|
52
52
|
};
|
|
53
53
|
|
|
54
54
|
/**
|
|
@@ -110,7 +110,7 @@ export class StableWSConnection<
|
|
|
110
110
|
totalFailures: number;
|
|
111
111
|
ws?: WebSocket;
|
|
112
112
|
wsID: number;
|
|
113
|
-
|
|
113
|
+
enableInsights?: boolean;
|
|
114
114
|
insightMetrics: InsightMetrics;
|
|
115
115
|
constructor({
|
|
116
116
|
apiKey,
|
|
@@ -126,7 +126,7 @@ export class StableWSConnection<
|
|
|
126
126
|
userID,
|
|
127
127
|
wsBaseURL,
|
|
128
128
|
device,
|
|
129
|
-
|
|
129
|
+
enableInsights,
|
|
130
130
|
insightMetrics,
|
|
131
131
|
}: Constructor<ChannelType, CommandType, UserType>) {
|
|
132
132
|
this.wsBaseURL = wsBaseURL;
|
|
@@ -161,7 +161,7 @@ export class StableWSConnection<
|
|
|
161
161
|
this.pingInterval = 25 * 1000;
|
|
162
162
|
this.connectionCheckTimeout = this.pingInterval + 10 * 1000;
|
|
163
163
|
this._listenForConnectionChanges();
|
|
164
|
-
this.
|
|
164
|
+
this.enableInsights = enableInsights;
|
|
165
165
|
this.insightMetrics = insightMetrics;
|
|
166
166
|
}
|
|
167
167
|
|
|
@@ -270,7 +270,7 @@ export class StableWSConnection<
|
|
|
270
270
|
user_token: this.tokenManager.getToken(),
|
|
271
271
|
server_determines_connection_id: true,
|
|
272
272
|
device: this.device,
|
|
273
|
-
|
|
273
|
+
client_request_id: reqID,
|
|
274
274
|
};
|
|
275
275
|
const qs = encodeURIComponent(JSON.stringify(params));
|
|
276
276
|
const token = this.tokenManager.getToken();
|
|
@@ -388,10 +388,10 @@ export class StableWSConnection<
|
|
|
388
388
|
|
|
389
389
|
if (response) {
|
|
390
390
|
this.connectionID = response.connection_id;
|
|
391
|
-
if (this.insightMetrics.wsConsecutiveFailures > 0 && this.
|
|
392
|
-
|
|
391
|
+
if (this.insightMetrics.wsConsecutiveFailures > 0 && this.enableInsights) {
|
|
392
|
+
postInsights(
|
|
393
393
|
'ws_success_after_failure',
|
|
394
|
-
buildWsSuccessAfterFailureInsight(this),
|
|
394
|
+
buildWsSuccessAfterFailureInsight((this as unknown) as StableWSConnection),
|
|
395
395
|
);
|
|
396
396
|
this.insightMetrics.wsConsecutiveFailures = 0;
|
|
397
397
|
}
|
|
@@ -400,13 +400,15 @@ export class StableWSConnection<
|
|
|
400
400
|
} catch (err) {
|
|
401
401
|
this.isConnecting = false;
|
|
402
402
|
|
|
403
|
-
if (this.
|
|
403
|
+
if (this.enableInsights) {
|
|
404
404
|
this.insightMetrics.wsConsecutiveFailures++;
|
|
405
405
|
this.insightMetrics.wsTotalFailures++;
|
|
406
406
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
407
|
+
const insights = buildWsFatalInsight(
|
|
408
|
+
(this as unknown) as StableWSConnection,
|
|
409
|
+
convertErrorToJson(err as Error),
|
|
410
|
+
);
|
|
411
|
+
postInsights?.('ws_fatal', insights);
|
|
410
412
|
}
|
|
411
413
|
throw err;
|
|
412
414
|
}
|
package/src/insights.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
1
2
|
import { StableWSConnection } from './connection';
|
|
2
|
-
import {
|
|
3
|
-
import { randomId } from './utils';
|
|
3
|
+
import { randomId, sleep } from './utils';
|
|
4
4
|
|
|
5
|
-
export type InsightTypes = 'ws_fatal' | 'ws_success_after_failure';
|
|
5
|
+
export type InsightTypes = 'ws_fatal' | 'ws_success_after_failure' | 'http_hi_failed';
|
|
6
6
|
export class InsightMetrics {
|
|
7
7
|
connectionStartTimestamp: number | null;
|
|
8
8
|
wsConsecutiveFailures: number;
|
|
@@ -17,12 +17,34 @@ export class InsightMetrics {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
/**
|
|
21
|
+
* postInsights is not supposed to be used by end users directly within chat application, and thus is kept isolated
|
|
22
|
+
* from all the client/connection code/logic.
|
|
23
|
+
*
|
|
24
|
+
* @param insightType
|
|
25
|
+
* @param insights
|
|
26
|
+
*/
|
|
27
|
+
export const postInsights = async (
|
|
28
|
+
insightType: InsightTypes,
|
|
29
|
+
insights: Record<string, unknown>,
|
|
30
|
+
) => {
|
|
31
|
+
const maxAttempts = 3;
|
|
32
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
33
|
+
try {
|
|
34
|
+
await axios.post(
|
|
35
|
+
`https://chat-insights.getstream.io/insights/${insightType}`,
|
|
36
|
+
insights,
|
|
37
|
+
);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
await sleep((i + 1) * 3000);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export function buildWsFatalInsight(
|
|
47
|
+
connection: StableWSConnection,
|
|
26
48
|
event: Record<string, unknown>,
|
|
27
49
|
) {
|
|
28
50
|
return {
|
|
@@ -31,11 +53,7 @@ export function buildWsFatalInsight<
|
|
|
31
53
|
};
|
|
32
54
|
}
|
|
33
55
|
|
|
34
|
-
function buildWsBaseInsight
|
|
35
|
-
ChannelType extends UnknownType = UnknownType,
|
|
36
|
-
CommandType extends string = LiteralStringForUnion,
|
|
37
|
-
UserType extends UnknownType = UnknownType
|
|
38
|
-
>(connection: StableWSConnection<ChannelType, CommandType, UserType>) {
|
|
56
|
+
function buildWsBaseInsight(connection: StableWSConnection) {
|
|
39
57
|
return {
|
|
40
58
|
ready_state: connection.ws?.readyState,
|
|
41
59
|
url: connection._buildUrl(connection.requestID),
|
|
@@ -58,10 +76,6 @@ function buildWsBaseInsight<
|
|
|
58
76
|
};
|
|
59
77
|
}
|
|
60
78
|
|
|
61
|
-
export function buildWsSuccessAfterFailureInsight
|
|
62
|
-
ChannelType extends UnknownType = UnknownType,
|
|
63
|
-
CommandType extends string = LiteralStringForUnion,
|
|
64
|
-
UserType extends UnknownType = UnknownType
|
|
65
|
-
>(connection: StableWSConnection<ChannelType, CommandType, UserType>) {
|
|
79
|
+
export function buildWsSuccessAfterFailureInsight(connection: StableWSConnection) {
|
|
66
80
|
return buildWsBaseInsight(connection);
|
|
67
81
|
}
|
package/src/types.ts
CHANGED
|
@@ -2163,11 +2163,13 @@ export type DeleteType = 'soft' | 'hard';
|
|
|
2163
2163
|
implies that all related objects (messages, flags, etc) will be hard-deleted as well.
|
|
2164
2164
|
`conversations` soft|hard will delete any 1to1 channels that the user was a member of.
|
|
2165
2165
|
`messages` soft-hard will delete any messages that the user has sent.
|
|
2166
|
+
`new_channel_owner_id` any channels owned by the hard-deleted user will be transferred to this user ID
|
|
2166
2167
|
*/
|
|
2167
2168
|
export type DeleteUserOptions = {
|
|
2168
2169
|
user: DeleteType;
|
|
2169
2170
|
conversations?: DeleteType;
|
|
2170
2171
|
messages?: DeleteType;
|
|
2172
|
+
new_channel_owner_id?: string;
|
|
2171
2173
|
};
|
|
2172
2174
|
|
|
2173
2175
|
export type SegmentData = {
|
package/src/utils.ts
CHANGED
|
@@ -199,15 +199,20 @@ function getRandomBytes(length: number): Uint8Array {
|
|
|
199
199
|
return bytes;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
export function convertErrorToJson(err:
|
|
202
|
+
export function convertErrorToJson(err: Error) {
|
|
203
203
|
const jsonObj = {} as Record<string, unknown>;
|
|
204
204
|
|
|
205
205
|
if (!err) return jsonObj;
|
|
206
206
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
207
|
+
try {
|
|
208
|
+
Object.getOwnPropertyNames(err).forEach((key) => {
|
|
209
|
+
jsonObj[key] = Object.getOwnPropertyDescriptor(err, key);
|
|
210
|
+
});
|
|
211
|
+
} catch (_) {
|
|
212
|
+
return {
|
|
213
|
+
error: 'failed to serialize the error',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
211
216
|
|
|
212
217
|
return jsonObj;
|
|
213
218
|
}
|