stream-chat 9.43.1 → 9.44.0
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/README.md +1 -1
- package/dist/cjs/index.browser.js +156 -7
- package/dist/cjs/index.browser.js.map +3 -3
- package/dist/cjs/index.node.js +166 -8
- package/dist/cjs/index.node.js.map +3 -3
- package/dist/esm/index.mjs +156 -7
- package/dist/esm/index.mjs.map +3 -3
- package/dist/types/client.d.ts +36 -4
- package/dist/types/messageComposer/middleware/textComposer/index.d.ts +1 -0
- package/dist/types/signing.d.ts +99 -5
- package/dist/types/types.d.ts +121 -15
- package/package.json +2 -1
- package/src/channel.ts +3 -1
- package/src/client.ts +78 -11
- package/src/messageComposer/messageComposer.ts +2 -0
- package/src/messageComposer/middleware/textComposer/index.ts +1 -0
- package/src/signing.ts +195 -7
- package/src/types.ts +133 -15
- package/src/utils.ts +1 -1
package/README.md
CHANGED
|
@@ -151,7 +151,7 @@ yarn start
|
|
|
151
151
|
|
|
152
152
|
## 📚 More Code Examples
|
|
153
153
|
|
|
154
|
-
Read up more on [Logging](./docs/logging.md)
|
|
154
|
+
Read up more on [Logging](./docs/logging.md), [User Token](./docs/userToken.md), and [Webhooks](./docs/webhooks.md) (including compressed payloads and SQS / SNS delivery) or visit our [documentation](https://getstream.io/chat/docs/) for more examples.
|
|
155
155
|
|
|
156
156
|
## ✍️ Contributing
|
|
157
157
|
|
|
@@ -48,6 +48,12 @@ var require_crypto = __commonJS({
|
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
// (disabled):zlib
|
|
52
|
+
var require_zlib = __commonJS({
|
|
53
|
+
"(disabled):zlib"() {
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
51
57
|
// src/index.ts
|
|
52
58
|
var index_exports = {};
|
|
53
59
|
__export(index_exports, {
|
|
@@ -92,6 +98,8 @@ __export(index_exports, {
|
|
|
92
98
|
FilterBuilder: () => FilterBuilder,
|
|
93
99
|
FixedSizeQueueCache: () => FixedSizeQueueCache,
|
|
94
100
|
InsightMetrics: () => InsightMetrics,
|
|
101
|
+
InvalidWebhookError: () => InvalidWebhookError,
|
|
102
|
+
InvalidWebhookErrorMessages: () => InvalidWebhookErrorMessages,
|
|
95
103
|
JWTServerToken: () => JWTServerToken,
|
|
96
104
|
JWTUserToken: () => JWTUserToken,
|
|
97
105
|
LinkPreviewStatus: () => LinkPreviewStatus,
|
|
@@ -178,18 +186,24 @@ __export(index_exports, {
|
|
|
178
186
|
createUploadConfigCheckMiddleware: () => createUploadConfigCheckMiddleware,
|
|
179
187
|
createUploadErrorHandlerMiddleware: () => createUploadErrorHandlerMiddleware,
|
|
180
188
|
decodeBase64: () => decodeBase64,
|
|
189
|
+
decodeSnsPayload: () => decodeSnsPayload,
|
|
190
|
+
decodeSqsPayload: () => decodeSqsPayload,
|
|
181
191
|
defaultPollFieldBlurEventValidators: () => defaultPollFieldBlurEventValidators,
|
|
182
192
|
defaultPollFieldChangeEventValidators: () => defaultPollFieldChangeEventValidators,
|
|
183
193
|
encodeBase64: () => encodeBase64,
|
|
184
194
|
ensureIsLocalAttachment: () => ensureIsLocalAttachment,
|
|
195
|
+
escapeCommandRegExp: () => escapeCommandRegExp,
|
|
185
196
|
extractPollData: () => extractPollData,
|
|
186
197
|
extractPollEnrichedData: () => extractPollEnrichedData,
|
|
187
198
|
formatMessage: () => formatMessage,
|
|
188
199
|
generateFileName: () => generateFileName,
|
|
189
200
|
getAttachmentTypeFromMimeType: () => getAttachmentTypeFromMimeType,
|
|
201
|
+
getCompleteCommandInString: () => getCompleteCommandInString,
|
|
190
202
|
getExtensionFromMimeType: () => getExtensionFromMimeType,
|
|
203
|
+
getRawCommandName: () => getRawCommandName,
|
|
191
204
|
getTokenizedSuggestionDisplayName: () => getTokenizedSuggestionDisplayName,
|
|
192
205
|
getTriggerCharWithToken: () => getTriggerCharWithToken,
|
|
206
|
+
gunzipPayload: () => gunzipPayload,
|
|
193
207
|
insertItemWithTrigger: () => insertItemWithTrigger,
|
|
194
208
|
isAudioAttachment: () => isAudioAttachment,
|
|
195
209
|
isBlobButNotFile: () => isBlobButNotFile,
|
|
@@ -219,6 +233,10 @@ __export(index_exports, {
|
|
|
219
233
|
localMessageToNewMessagePayload: () => localMessageToNewMessagePayload,
|
|
220
234
|
logChatPromiseExecution: () => logChatPromiseExecution,
|
|
221
235
|
mapPollStateToResponse: () => mapPollStateToResponse,
|
|
236
|
+
notifyCommandDisabled: () => notifyCommandDisabled,
|
|
237
|
+
parseEvent: () => parseEvent,
|
|
238
|
+
parseSns: () => parseSns,
|
|
239
|
+
parseSqs: () => parseSqs,
|
|
222
240
|
pollCompositionStateProcessors: () => pollCompositionStateProcessors,
|
|
223
241
|
pollStateChangeValidators: () => pollStateChangeValidators,
|
|
224
242
|
postInsights: () => postInsights,
|
|
@@ -226,8 +244,11 @@ __export(index_exports, {
|
|
|
226
244
|
readFileAsArrayBuffer: () => readFileAsArrayBuffer,
|
|
227
245
|
removeDiacritics: () => removeDiacritics,
|
|
228
246
|
replaceWordWithEntity: () => replaceWordWithEntity,
|
|
247
|
+
stripCommandFromText: () => stripCommandFromText,
|
|
229
248
|
textIsEmpty: () => textIsEmpty,
|
|
230
|
-
timeLeftMs: () => timeLeftMs
|
|
249
|
+
timeLeftMs: () => timeLeftMs,
|
|
250
|
+
verifyAndParseWebhook: () => verifyAndParseWebhook,
|
|
251
|
+
verifySignature: () => verifySignature
|
|
231
252
|
});
|
|
232
253
|
module.exports = __toCommonJS(index_exports);
|
|
233
254
|
|
|
@@ -839,7 +860,7 @@ var deleteUserMessages = ({
|
|
|
839
860
|
if (message.user?.id === user.id) {
|
|
840
861
|
messages[i] = message.type === "deleted" ? message : toDeletedMessage({ message, hardDelete, deletedAt });
|
|
841
862
|
}
|
|
842
|
-
if (message.quoted_message?.user?.id === user.id) {
|
|
863
|
+
if (messages[i].quoted_message && message.quoted_message?.user?.id === user.id) {
|
|
843
864
|
messages[i].quoted_message = message.quoted_message.type === "deleted" ? message.quoted_message : toDeletedMessage({
|
|
844
865
|
message: messages[i].quoted_message,
|
|
845
866
|
hardDelete,
|
|
@@ -7439,6 +7460,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
7439
7460
|
const draft = event.draft;
|
|
7440
7461
|
if (!draft || (draft.parent_id ?? null) !== (this.threadId ?? null) || draft.channel_cid !== this.channel.cid)
|
|
7441
7462
|
return;
|
|
7463
|
+
if (this.editedMessage) return;
|
|
7442
7464
|
this.initState({ composition: draft });
|
|
7443
7465
|
}).unsubscribe;
|
|
7444
7466
|
this.subscribeDraftDeleted = () => this.client.on("draft.deleted", (event) => {
|
|
@@ -7446,6 +7468,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
7446
7468
|
if (!draft || (draft.parent_id ?? null) !== (this.threadId ?? null) || draft.channel_cid !== this.channel.cid) {
|
|
7447
7469
|
return;
|
|
7448
7470
|
}
|
|
7471
|
+
if (this.editedMessage) return;
|
|
7449
7472
|
this.logDraftUpdateTimestamp();
|
|
7450
7473
|
if (this.compositionIsEmpty) {
|
|
7451
7474
|
return;
|
|
@@ -9489,7 +9512,7 @@ var Channel = class {
|
|
|
9489
9512
|
if (Array.isArray(this.data?.own_capabilities) && !this.data?.own_capabilities.includes("read-events")) {
|
|
9490
9513
|
return false;
|
|
9491
9514
|
}
|
|
9492
|
-
if (this.
|
|
9515
|
+
if (this.getClient()._muteStatus(this.cid).muted) return false;
|
|
9493
9516
|
return true;
|
|
9494
9517
|
}
|
|
9495
9518
|
/**
|
|
@@ -11000,6 +11023,7 @@ var UploadManager = class {
|
|
|
11000
11023
|
// src/signing.ts
|
|
11001
11024
|
var import_jsonwebtoken = __toESM(require_jsonwebtoken());
|
|
11002
11025
|
var import_crypto = __toESM(require_crypto());
|
|
11026
|
+
var import_zlib = __toESM(require_zlib());
|
|
11003
11027
|
function JWTUserToken(apiSecret, userId, extraData = {}, jwtOptions = {}) {
|
|
11004
11028
|
if (typeof userId !== "string") {
|
|
11005
11029
|
throw new TypeError("userId should be a string");
|
|
@@ -11051,7 +11075,7 @@ function DevToken(userId) {
|
|
|
11051
11075
|
// hardcoded signature
|
|
11052
11076
|
].join(".");
|
|
11053
11077
|
}
|
|
11054
|
-
function
|
|
11078
|
+
function verifySignature(body, signature, secret) {
|
|
11055
11079
|
const key = Buffer.from(secret, "utf8");
|
|
11056
11080
|
const hash = import_crypto.default.createHmac("sha256", key).update(body).digest("hex");
|
|
11057
11081
|
try {
|
|
@@ -11060,6 +11084,86 @@ function CheckSignature(body, secret, signature) {
|
|
|
11060
11084
|
return false;
|
|
11061
11085
|
}
|
|
11062
11086
|
}
|
|
11087
|
+
function CheckSignature(body, secret, signature) {
|
|
11088
|
+
return verifySignature(body, signature, secret);
|
|
11089
|
+
}
|
|
11090
|
+
var InvalidWebhookErrorMessages = {
|
|
11091
|
+
signatureMismatch: "signature mismatch",
|
|
11092
|
+
invalidBase64: "invalid base64 encoding",
|
|
11093
|
+
gzipFailed: "gzip decompression failed",
|
|
11094
|
+
invalidJson: "invalid JSON payload"
|
|
11095
|
+
};
|
|
11096
|
+
var InvalidWebhookError = class extends Error {
|
|
11097
|
+
constructor(message = InvalidWebhookErrorMessages.signatureMismatch) {
|
|
11098
|
+
super(message);
|
|
11099
|
+
this.name = "InvalidWebhookError";
|
|
11100
|
+
}
|
|
11101
|
+
};
|
|
11102
|
+
function gunzipPayload(rawBody) {
|
|
11103
|
+
const GZIP_MAGIC = Buffer.from([31, 139]);
|
|
11104
|
+
const body = Buffer.isBuffer(rawBody) ? rawBody : Buffer.from(rawBody);
|
|
11105
|
+
if (body.length >= 2 && body.subarray(0, 2).equals(GZIP_MAGIC)) {
|
|
11106
|
+
try {
|
|
11107
|
+
return import_zlib.default.gunzipSync(body);
|
|
11108
|
+
} catch {
|
|
11109
|
+
throw new InvalidWebhookError(InvalidWebhookErrorMessages.gzipFailed);
|
|
11110
|
+
}
|
|
11111
|
+
}
|
|
11112
|
+
return body;
|
|
11113
|
+
}
|
|
11114
|
+
function decodeSqsPayload(body) {
|
|
11115
|
+
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(body) || body.length % 4 !== 0) {
|
|
11116
|
+
throw new InvalidWebhookError(InvalidWebhookErrorMessages.invalidBase64);
|
|
11117
|
+
}
|
|
11118
|
+
const decoded = Buffer.from(body, "base64");
|
|
11119
|
+
if (decoded.toString("base64").length !== body.length) {
|
|
11120
|
+
throw new InvalidWebhookError(InvalidWebhookErrorMessages.invalidBase64);
|
|
11121
|
+
}
|
|
11122
|
+
return gunzipPayload(decoded);
|
|
11123
|
+
}
|
|
11124
|
+
function decodeSnsPayload(notificationBody) {
|
|
11125
|
+
const inner = extractSnsMessage(notificationBody);
|
|
11126
|
+
return decodeSqsPayload(inner ?? notificationBody);
|
|
11127
|
+
}
|
|
11128
|
+
function extractSnsMessage(notificationBody) {
|
|
11129
|
+
const trimmed = notificationBody.replace(/^[\s\uFEFF]+/, "");
|
|
11130
|
+
if (!trimmed.startsWith("{")) {
|
|
11131
|
+
return null;
|
|
11132
|
+
}
|
|
11133
|
+
let parsed;
|
|
11134
|
+
try {
|
|
11135
|
+
parsed = JSON.parse(trimmed);
|
|
11136
|
+
} catch {
|
|
11137
|
+
return null;
|
|
11138
|
+
}
|
|
11139
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed) || typeof parsed.Message !== "string") {
|
|
11140
|
+
return null;
|
|
11141
|
+
}
|
|
11142
|
+
return parsed.Message;
|
|
11143
|
+
}
|
|
11144
|
+
function parseEvent(payload) {
|
|
11145
|
+
const text = Buffer.isBuffer(payload) ? payload.toString("utf8") : payload;
|
|
11146
|
+
try {
|
|
11147
|
+
return JSON.parse(text);
|
|
11148
|
+
} catch {
|
|
11149
|
+
throw new InvalidWebhookError(InvalidWebhookErrorMessages.invalidJson);
|
|
11150
|
+
}
|
|
11151
|
+
}
|
|
11152
|
+
function verifyAndParse(payload, signature, secret) {
|
|
11153
|
+
if (!verifySignature(payload, signature, secret)) {
|
|
11154
|
+
throw new InvalidWebhookError(InvalidWebhookErrorMessages.signatureMismatch);
|
|
11155
|
+
}
|
|
11156
|
+
return parseEvent(payload);
|
|
11157
|
+
}
|
|
11158
|
+
function verifyAndParseWebhook(rawBody, signature, secret) {
|
|
11159
|
+
return verifyAndParse(gunzipPayload(rawBody), signature, secret);
|
|
11160
|
+
}
|
|
11161
|
+
function parseSqs(messageBody) {
|
|
11162
|
+
return parseEvent(decodeSqsPayload(messageBody));
|
|
11163
|
+
}
|
|
11164
|
+
function parseSns(notificationBody) {
|
|
11165
|
+
return parseEvent(decodeSnsPayload(notificationBody));
|
|
11166
|
+
}
|
|
11063
11167
|
|
|
11064
11168
|
// src/token_manager.ts
|
|
11065
11169
|
var TokenManager = class {
|
|
@@ -14490,15 +14594,17 @@ var StreamChat = class _StreamChat {
|
|
|
14490
14594
|
defaultOptions.watch = false;
|
|
14491
14595
|
}
|
|
14492
14596
|
const { predefined_filter, filter_values, sort_values, ...restOptions } = options;
|
|
14597
|
+
const normalizedSort = normalizeQuerySort(sort);
|
|
14493
14598
|
const payload = predefined_filter ? {
|
|
14494
14599
|
predefined_filter,
|
|
14495
14600
|
filter_values,
|
|
14496
14601
|
sort_values,
|
|
14602
|
+
sort: normalizedSort,
|
|
14497
14603
|
...defaultOptions,
|
|
14498
14604
|
...restOptions
|
|
14499
14605
|
} : {
|
|
14500
14606
|
filter_conditions: filterConditions,
|
|
14501
|
-
sort:
|
|
14607
|
+
sort: normalizedSort,
|
|
14502
14608
|
...defaultOptions,
|
|
14503
14609
|
...restOptions
|
|
14504
14610
|
};
|
|
@@ -15661,7 +15767,7 @@ var StreamChat = class _StreamChat {
|
|
|
15661
15767
|
if (this.userAgent) {
|
|
15662
15768
|
return this.userAgent;
|
|
15663
15769
|
}
|
|
15664
|
-
const version = "9.
|
|
15770
|
+
const version = "9.44.0";
|
|
15665
15771
|
const clientBundle = "browser-cjs";
|
|
15666
15772
|
let userAgentString = "";
|
|
15667
15773
|
if (this.sdkIdentifier) {
|
|
@@ -15754,7 +15860,50 @@ var StreamChat = class _StreamChat {
|
|
|
15754
15860
|
* @returns {boolean}
|
|
15755
15861
|
*/
|
|
15756
15862
|
verifyWebhook(requestBody, xSignature) {
|
|
15757
|
-
return !!this.secret &&
|
|
15863
|
+
return !!this.secret && verifySignature(requestBody, xSignature, this.secret);
|
|
15864
|
+
}
|
|
15865
|
+
/**
|
|
15866
|
+
* Verify and parse an HTTP webhook event.
|
|
15867
|
+
*
|
|
15868
|
+
* Decompresses `rawBody` when gzipped (detected from the body bytes),
|
|
15869
|
+
* verifies the `X-Signature` header against the app's API secret, and
|
|
15870
|
+
* returns the parsed `Event`. Works whether or not Stream is currently
|
|
15871
|
+
* compressing payloads for this app, and stays correct behind
|
|
15872
|
+
* middleware that auto-decompresses the request.
|
|
15873
|
+
*
|
|
15874
|
+
* @param rawBody Raw HTTP request body bytes Stream signed
|
|
15875
|
+
* @param signature Value of the `X-Signature` header
|
|
15876
|
+
* @throws {InvalidWebhookError} When the signature does not match or
|
|
15877
|
+
* the gzip envelope is malformed.
|
|
15878
|
+
*/
|
|
15879
|
+
verifyAndParseWebhook(rawBody, signature) {
|
|
15880
|
+
if (!this.secret) {
|
|
15881
|
+
throw new InvalidWebhookError(
|
|
15882
|
+
"cannot verify webhook signature without an API secret on the client"
|
|
15883
|
+
);
|
|
15884
|
+
}
|
|
15885
|
+
return verifyAndParseWebhook(rawBody, signature, this.secret);
|
|
15886
|
+
}
|
|
15887
|
+
/**
|
|
15888
|
+
* Parse an SQS firehose event: decodes the message `Body` (base64 +
|
|
15889
|
+
* optional gzip) and returns the parsed `Event`. No HMAC verification
|
|
15890
|
+
* (Stream does not sign SQS bodies).
|
|
15891
|
+
*
|
|
15892
|
+
* @param messageBody SQS message `Body` string
|
|
15893
|
+
* @throws {InvalidWebhookError} When the base64 / gzip envelope is malformed.
|
|
15894
|
+
*/
|
|
15895
|
+
parseSqs(messageBody) {
|
|
15896
|
+
return parseSqs(messageBody);
|
|
15897
|
+
}
|
|
15898
|
+
/**
|
|
15899
|
+
* Parse an SNS-delivered event (unwraps envelope JSON when needed, then
|
|
15900
|
+
* same decode path as SQS). No HMAC verification.
|
|
15901
|
+
*
|
|
15902
|
+
* @param notificationBody Raw SNS POST body or pre-extracted `Message` string
|
|
15903
|
+
* @throws {InvalidWebhookError} When the envelope cannot be decoded.
|
|
15904
|
+
*/
|
|
15905
|
+
parseSns(notificationBody) {
|
|
15906
|
+
return parseSns(notificationBody);
|
|
15758
15907
|
}
|
|
15759
15908
|
/** getPermission - gets the definition for a permission
|
|
15760
15909
|
*
|