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 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) and [User Token](./docs/userToken.md) or visit our [documentation](https://getstream.io/chat/docs/) for more examples.
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.muteStatus().muted) return false;
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 CheckSignature(body, secret, signature) {
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: normalizeQuerySort(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.43.1";
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 && CheckSignature(requestBody, this.secret, xSignature);
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
  *