stream-chat 9.43.2 → 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 +148 -6
- package/dist/cjs/index.browser.js.map +3 -3
- package/dist/cjs/index.node.js +153 -7
- package/dist/cjs/index.node.js.map +3 -3
- package/dist/esm/index.mjs +148 -6
- package/dist/esm/index.mjs.map +3 -3
- package/dist/types/client.d.ts +32 -0
- package/dist/types/signing.d.ts +99 -5
- package/package.json +2 -1
- package/src/channel.ts +3 -1
- package/src/client.ts +56 -2
- package/src/messageComposer/messageComposer.ts +2 -0
- package/src/signing.ts +195 -7
- package/src/utils.ts +1 -1
package/dist/cjs/index.node.js
CHANGED
|
@@ -71,6 +71,8 @@ __export(index_exports, {
|
|
|
71
71
|
FilterBuilder: () => FilterBuilder,
|
|
72
72
|
FixedSizeQueueCache: () => FixedSizeQueueCache,
|
|
73
73
|
InsightMetrics: () => InsightMetrics,
|
|
74
|
+
InvalidWebhookError: () => InvalidWebhookError,
|
|
75
|
+
InvalidWebhookErrorMessages: () => InvalidWebhookErrorMessages,
|
|
74
76
|
JWTServerToken: () => JWTServerToken,
|
|
75
77
|
JWTUserToken: () => JWTUserToken,
|
|
76
78
|
LinkPreviewStatus: () => LinkPreviewStatus,
|
|
@@ -157,6 +159,8 @@ __export(index_exports, {
|
|
|
157
159
|
createUploadConfigCheckMiddleware: () => createUploadConfigCheckMiddleware,
|
|
158
160
|
createUploadErrorHandlerMiddleware: () => createUploadErrorHandlerMiddleware,
|
|
159
161
|
decodeBase64: () => decodeBase64,
|
|
162
|
+
decodeSnsPayload: () => decodeSnsPayload,
|
|
163
|
+
decodeSqsPayload: () => decodeSqsPayload,
|
|
160
164
|
defaultPollFieldBlurEventValidators: () => defaultPollFieldBlurEventValidators,
|
|
161
165
|
defaultPollFieldChangeEventValidators: () => defaultPollFieldChangeEventValidators,
|
|
162
166
|
encodeBase64: () => encodeBase64,
|
|
@@ -172,6 +176,7 @@ __export(index_exports, {
|
|
|
172
176
|
getRawCommandName: () => getRawCommandName,
|
|
173
177
|
getTokenizedSuggestionDisplayName: () => getTokenizedSuggestionDisplayName,
|
|
174
178
|
getTriggerCharWithToken: () => getTriggerCharWithToken,
|
|
179
|
+
gunzipPayload: () => gunzipPayload,
|
|
175
180
|
insertItemWithTrigger: () => insertItemWithTrigger,
|
|
176
181
|
isAudioAttachment: () => isAudioAttachment,
|
|
177
182
|
isBlobButNotFile: () => isBlobButNotFile,
|
|
@@ -202,6 +207,9 @@ __export(index_exports, {
|
|
|
202
207
|
logChatPromiseExecution: () => logChatPromiseExecution,
|
|
203
208
|
mapPollStateToResponse: () => mapPollStateToResponse,
|
|
204
209
|
notifyCommandDisabled: () => notifyCommandDisabled,
|
|
210
|
+
parseEvent: () => parseEvent,
|
|
211
|
+
parseSns: () => parseSns,
|
|
212
|
+
parseSqs: () => parseSqs,
|
|
205
213
|
pollCompositionStateProcessors: () => pollCompositionStateProcessors,
|
|
206
214
|
pollStateChangeValidators: () => pollStateChangeValidators,
|
|
207
215
|
postInsights: () => postInsights,
|
|
@@ -211,7 +219,9 @@ __export(index_exports, {
|
|
|
211
219
|
replaceWordWithEntity: () => replaceWordWithEntity,
|
|
212
220
|
stripCommandFromText: () => stripCommandFromText,
|
|
213
221
|
textIsEmpty: () => textIsEmpty,
|
|
214
|
-
timeLeftMs: () => timeLeftMs
|
|
222
|
+
timeLeftMs: () => timeLeftMs,
|
|
223
|
+
verifyAndParseWebhook: () => verifyAndParseWebhook,
|
|
224
|
+
verifySignature: () => verifySignature
|
|
215
225
|
});
|
|
216
226
|
module.exports = __toCommonJS(index_exports);
|
|
217
227
|
|
|
@@ -823,7 +833,7 @@ var deleteUserMessages = ({
|
|
|
823
833
|
if (message.user?.id === user.id) {
|
|
824
834
|
messages[i] = message.type === "deleted" ? message : toDeletedMessage({ message, hardDelete, deletedAt });
|
|
825
835
|
}
|
|
826
|
-
if (message.quoted_message?.user?.id === user.id) {
|
|
836
|
+
if (messages[i].quoted_message && message.quoted_message?.user?.id === user.id) {
|
|
827
837
|
messages[i].quoted_message = message.quoted_message.type === "deleted" ? message.quoted_message : toDeletedMessage({
|
|
828
838
|
message: messages[i].quoted_message,
|
|
829
839
|
hardDelete,
|
|
@@ -7423,6 +7433,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
7423
7433
|
const draft = event.draft;
|
|
7424
7434
|
if (!draft || (draft.parent_id ?? null) !== (this.threadId ?? null) || draft.channel_cid !== this.channel.cid)
|
|
7425
7435
|
return;
|
|
7436
|
+
if (this.editedMessage) return;
|
|
7426
7437
|
this.initState({ composition: draft });
|
|
7427
7438
|
}).unsubscribe;
|
|
7428
7439
|
this.subscribeDraftDeleted = () => this.client.on("draft.deleted", (event) => {
|
|
@@ -7430,6 +7441,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
|
|
|
7430
7441
|
if (!draft || (draft.parent_id ?? null) !== (this.threadId ?? null) || draft.channel_cid !== this.channel.cid) {
|
|
7431
7442
|
return;
|
|
7432
7443
|
}
|
|
7444
|
+
if (this.editedMessage) return;
|
|
7433
7445
|
this.logDraftUpdateTimestamp();
|
|
7434
7446
|
if (this.compositionIsEmpty) {
|
|
7435
7447
|
return;
|
|
@@ -9473,7 +9485,7 @@ var Channel = class {
|
|
|
9473
9485
|
if (Array.isArray(this.data?.own_capabilities) && !this.data?.own_capabilities.includes("read-events")) {
|
|
9474
9486
|
return false;
|
|
9475
9487
|
}
|
|
9476
|
-
if (this.
|
|
9488
|
+
if (this.getClient()._muteStatus(this.cid).muted) return false;
|
|
9477
9489
|
return true;
|
|
9478
9490
|
}
|
|
9479
9491
|
/**
|
|
@@ -10984,6 +10996,7 @@ var UploadManager = class {
|
|
|
10984
10996
|
// src/signing.ts
|
|
10985
10997
|
var import_jsonwebtoken = __toESM(require("jsonwebtoken"));
|
|
10986
10998
|
var import_crypto = __toESM(require("crypto"));
|
|
10999
|
+
var import_zlib = __toESM(require("zlib"));
|
|
10987
11000
|
function JWTUserToken(apiSecret, userId, extraData = {}, jwtOptions = {}) {
|
|
10988
11001
|
if (typeof userId !== "string") {
|
|
10989
11002
|
throw new TypeError("userId should be a string");
|
|
@@ -11035,7 +11048,7 @@ function DevToken(userId) {
|
|
|
11035
11048
|
// hardcoded signature
|
|
11036
11049
|
].join(".");
|
|
11037
11050
|
}
|
|
11038
|
-
function
|
|
11051
|
+
function verifySignature(body, signature, secret) {
|
|
11039
11052
|
const key = Buffer.from(secret, "utf8");
|
|
11040
11053
|
const hash = import_crypto.default.createHmac("sha256", key).update(body).digest("hex");
|
|
11041
11054
|
try {
|
|
@@ -11044,6 +11057,86 @@ function CheckSignature(body, secret, signature) {
|
|
|
11044
11057
|
return false;
|
|
11045
11058
|
}
|
|
11046
11059
|
}
|
|
11060
|
+
function CheckSignature(body, secret, signature) {
|
|
11061
|
+
return verifySignature(body, signature, secret);
|
|
11062
|
+
}
|
|
11063
|
+
var InvalidWebhookErrorMessages = {
|
|
11064
|
+
signatureMismatch: "signature mismatch",
|
|
11065
|
+
invalidBase64: "invalid base64 encoding",
|
|
11066
|
+
gzipFailed: "gzip decompression failed",
|
|
11067
|
+
invalidJson: "invalid JSON payload"
|
|
11068
|
+
};
|
|
11069
|
+
var InvalidWebhookError = class extends Error {
|
|
11070
|
+
constructor(message = InvalidWebhookErrorMessages.signatureMismatch) {
|
|
11071
|
+
super(message);
|
|
11072
|
+
this.name = "InvalidWebhookError";
|
|
11073
|
+
}
|
|
11074
|
+
};
|
|
11075
|
+
function gunzipPayload(rawBody) {
|
|
11076
|
+
const GZIP_MAGIC = Buffer.from([31, 139]);
|
|
11077
|
+
const body = Buffer.isBuffer(rawBody) ? rawBody : Buffer.from(rawBody);
|
|
11078
|
+
if (body.length >= 2 && body.subarray(0, 2).equals(GZIP_MAGIC)) {
|
|
11079
|
+
try {
|
|
11080
|
+
return import_zlib.default.gunzipSync(body);
|
|
11081
|
+
} catch {
|
|
11082
|
+
throw new InvalidWebhookError(InvalidWebhookErrorMessages.gzipFailed);
|
|
11083
|
+
}
|
|
11084
|
+
}
|
|
11085
|
+
return body;
|
|
11086
|
+
}
|
|
11087
|
+
function decodeSqsPayload(body) {
|
|
11088
|
+
if (!/^[A-Za-z0-9+/]*={0,2}$/.test(body) || body.length % 4 !== 0) {
|
|
11089
|
+
throw new InvalidWebhookError(InvalidWebhookErrorMessages.invalidBase64);
|
|
11090
|
+
}
|
|
11091
|
+
const decoded = Buffer.from(body, "base64");
|
|
11092
|
+
if (decoded.toString("base64").length !== body.length) {
|
|
11093
|
+
throw new InvalidWebhookError(InvalidWebhookErrorMessages.invalidBase64);
|
|
11094
|
+
}
|
|
11095
|
+
return gunzipPayload(decoded);
|
|
11096
|
+
}
|
|
11097
|
+
function decodeSnsPayload(notificationBody) {
|
|
11098
|
+
const inner = extractSnsMessage(notificationBody);
|
|
11099
|
+
return decodeSqsPayload(inner ?? notificationBody);
|
|
11100
|
+
}
|
|
11101
|
+
function extractSnsMessage(notificationBody) {
|
|
11102
|
+
const trimmed = notificationBody.replace(/^[\s\uFEFF]+/, "");
|
|
11103
|
+
if (!trimmed.startsWith("{")) {
|
|
11104
|
+
return null;
|
|
11105
|
+
}
|
|
11106
|
+
let parsed;
|
|
11107
|
+
try {
|
|
11108
|
+
parsed = JSON.parse(trimmed);
|
|
11109
|
+
} catch {
|
|
11110
|
+
return null;
|
|
11111
|
+
}
|
|
11112
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed) || typeof parsed.Message !== "string") {
|
|
11113
|
+
return null;
|
|
11114
|
+
}
|
|
11115
|
+
return parsed.Message;
|
|
11116
|
+
}
|
|
11117
|
+
function parseEvent(payload) {
|
|
11118
|
+
const text = Buffer.isBuffer(payload) ? payload.toString("utf8") : payload;
|
|
11119
|
+
try {
|
|
11120
|
+
return JSON.parse(text);
|
|
11121
|
+
} catch {
|
|
11122
|
+
throw new InvalidWebhookError(InvalidWebhookErrorMessages.invalidJson);
|
|
11123
|
+
}
|
|
11124
|
+
}
|
|
11125
|
+
function verifyAndParse(payload, signature, secret) {
|
|
11126
|
+
if (!verifySignature(payload, signature, secret)) {
|
|
11127
|
+
throw new InvalidWebhookError(InvalidWebhookErrorMessages.signatureMismatch);
|
|
11128
|
+
}
|
|
11129
|
+
return parseEvent(payload);
|
|
11130
|
+
}
|
|
11131
|
+
function verifyAndParseWebhook(rawBody, signature, secret) {
|
|
11132
|
+
return verifyAndParse(gunzipPayload(rawBody), signature, secret);
|
|
11133
|
+
}
|
|
11134
|
+
function parseSqs(messageBody) {
|
|
11135
|
+
return parseEvent(decodeSqsPayload(messageBody));
|
|
11136
|
+
}
|
|
11137
|
+
function parseSns(notificationBody) {
|
|
11138
|
+
return parseEvent(decodeSnsPayload(notificationBody));
|
|
11139
|
+
}
|
|
11047
11140
|
|
|
11048
11141
|
// src/token_manager.ts
|
|
11049
11142
|
var TokenManager = class {
|
|
@@ -15647,7 +15740,7 @@ var StreamChat = class _StreamChat {
|
|
|
15647
15740
|
if (this.userAgent) {
|
|
15648
15741
|
return this.userAgent;
|
|
15649
15742
|
}
|
|
15650
|
-
const version = "9.
|
|
15743
|
+
const version = "9.44.0";
|
|
15651
15744
|
const clientBundle = "node-cjs";
|
|
15652
15745
|
let userAgentString = "";
|
|
15653
15746
|
if (this.sdkIdentifier) {
|
|
@@ -15740,7 +15833,50 @@ var StreamChat = class _StreamChat {
|
|
|
15740
15833
|
* @returns {boolean}
|
|
15741
15834
|
*/
|
|
15742
15835
|
verifyWebhook(requestBody, xSignature) {
|
|
15743
|
-
return !!this.secret &&
|
|
15836
|
+
return !!this.secret && verifySignature(requestBody, xSignature, this.secret);
|
|
15837
|
+
}
|
|
15838
|
+
/**
|
|
15839
|
+
* Verify and parse an HTTP webhook event.
|
|
15840
|
+
*
|
|
15841
|
+
* Decompresses `rawBody` when gzipped (detected from the body bytes),
|
|
15842
|
+
* verifies the `X-Signature` header against the app's API secret, and
|
|
15843
|
+
* returns the parsed `Event`. Works whether or not Stream is currently
|
|
15844
|
+
* compressing payloads for this app, and stays correct behind
|
|
15845
|
+
* middleware that auto-decompresses the request.
|
|
15846
|
+
*
|
|
15847
|
+
* @param rawBody Raw HTTP request body bytes Stream signed
|
|
15848
|
+
* @param signature Value of the `X-Signature` header
|
|
15849
|
+
* @throws {InvalidWebhookError} When the signature does not match or
|
|
15850
|
+
* the gzip envelope is malformed.
|
|
15851
|
+
*/
|
|
15852
|
+
verifyAndParseWebhook(rawBody, signature) {
|
|
15853
|
+
if (!this.secret) {
|
|
15854
|
+
throw new InvalidWebhookError(
|
|
15855
|
+
"cannot verify webhook signature without an API secret on the client"
|
|
15856
|
+
);
|
|
15857
|
+
}
|
|
15858
|
+
return verifyAndParseWebhook(rawBody, signature, this.secret);
|
|
15859
|
+
}
|
|
15860
|
+
/**
|
|
15861
|
+
* Parse an SQS firehose event: decodes the message `Body` (base64 +
|
|
15862
|
+
* optional gzip) and returns the parsed `Event`. No HMAC verification
|
|
15863
|
+
* (Stream does not sign SQS bodies).
|
|
15864
|
+
*
|
|
15865
|
+
* @param messageBody SQS message `Body` string
|
|
15866
|
+
* @throws {InvalidWebhookError} When the base64 / gzip envelope is malformed.
|
|
15867
|
+
*/
|
|
15868
|
+
parseSqs(messageBody) {
|
|
15869
|
+
return parseSqs(messageBody);
|
|
15870
|
+
}
|
|
15871
|
+
/**
|
|
15872
|
+
* Parse an SNS-delivered event (unwraps envelope JSON when needed, then
|
|
15873
|
+
* same decode path as SQS). No HMAC verification.
|
|
15874
|
+
*
|
|
15875
|
+
* @param notificationBody Raw SNS POST body or pre-extracted `Message` string
|
|
15876
|
+
* @throws {InvalidWebhookError} When the envelope cannot be decoded.
|
|
15877
|
+
*/
|
|
15878
|
+
parseSns(notificationBody) {
|
|
15879
|
+
return parseSns(notificationBody);
|
|
15744
15880
|
}
|
|
15745
15881
|
/** getPermission - gets the definition for a permission
|
|
15746
15882
|
*
|
|
@@ -18291,6 +18427,8 @@ var FixedSizeQueueCache = class {
|
|
|
18291
18427
|
FilterBuilder,
|
|
18292
18428
|
FixedSizeQueueCache,
|
|
18293
18429
|
InsightMetrics,
|
|
18430
|
+
InvalidWebhookError,
|
|
18431
|
+
InvalidWebhookErrorMessages,
|
|
18294
18432
|
JWTServerToken,
|
|
18295
18433
|
JWTUserToken,
|
|
18296
18434
|
LinkPreviewStatus,
|
|
@@ -18377,6 +18515,8 @@ var FixedSizeQueueCache = class {
|
|
|
18377
18515
|
createUploadConfigCheckMiddleware,
|
|
18378
18516
|
createUploadErrorHandlerMiddleware,
|
|
18379
18517
|
decodeBase64,
|
|
18518
|
+
decodeSnsPayload,
|
|
18519
|
+
decodeSqsPayload,
|
|
18380
18520
|
defaultPollFieldBlurEventValidators,
|
|
18381
18521
|
defaultPollFieldChangeEventValidators,
|
|
18382
18522
|
encodeBase64,
|
|
@@ -18392,6 +18532,7 @@ var FixedSizeQueueCache = class {
|
|
|
18392
18532
|
getRawCommandName,
|
|
18393
18533
|
getTokenizedSuggestionDisplayName,
|
|
18394
18534
|
getTriggerCharWithToken,
|
|
18535
|
+
gunzipPayload,
|
|
18395
18536
|
insertItemWithTrigger,
|
|
18396
18537
|
isAudioAttachment,
|
|
18397
18538
|
isBlobButNotFile,
|
|
@@ -18422,6 +18563,9 @@ var FixedSizeQueueCache = class {
|
|
|
18422
18563
|
logChatPromiseExecution,
|
|
18423
18564
|
mapPollStateToResponse,
|
|
18424
18565
|
notifyCommandDisabled,
|
|
18566
|
+
parseEvent,
|
|
18567
|
+
parseSns,
|
|
18568
|
+
parseSqs,
|
|
18425
18569
|
pollCompositionStateProcessors,
|
|
18426
18570
|
pollStateChangeValidators,
|
|
18427
18571
|
postInsights,
|
|
@@ -18431,6 +18575,8 @@ var FixedSizeQueueCache = class {
|
|
|
18431
18575
|
replaceWordWithEntity,
|
|
18432
18576
|
stripCommandFromText,
|
|
18433
18577
|
textIsEmpty,
|
|
18434
|
-
timeLeftMs
|
|
18578
|
+
timeLeftMs,
|
|
18579
|
+
verifyAndParseWebhook,
|
|
18580
|
+
verifySignature
|
|
18435
18581
|
});
|
|
18436
18582
|
//# sourceMappingURL=index.node.js.map
|