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 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,6 +186,8 @@ __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,
@@ -193,6 +203,7 @@ __export(index_exports, {
193
203
  getRawCommandName: () => getRawCommandName,
194
204
  getTokenizedSuggestionDisplayName: () => getTokenizedSuggestionDisplayName,
195
205
  getTriggerCharWithToken: () => getTriggerCharWithToken,
206
+ gunzipPayload: () => gunzipPayload,
196
207
  insertItemWithTrigger: () => insertItemWithTrigger,
197
208
  isAudioAttachment: () => isAudioAttachment,
198
209
  isBlobButNotFile: () => isBlobButNotFile,
@@ -223,6 +234,9 @@ __export(index_exports, {
223
234
  logChatPromiseExecution: () => logChatPromiseExecution,
224
235
  mapPollStateToResponse: () => mapPollStateToResponse,
225
236
  notifyCommandDisabled: () => notifyCommandDisabled,
237
+ parseEvent: () => parseEvent,
238
+ parseSns: () => parseSns,
239
+ parseSqs: () => parseSqs,
226
240
  pollCompositionStateProcessors: () => pollCompositionStateProcessors,
227
241
  pollStateChangeValidators: () => pollStateChangeValidators,
228
242
  postInsights: () => postInsights,
@@ -232,7 +246,9 @@ __export(index_exports, {
232
246
  replaceWordWithEntity: () => replaceWordWithEntity,
233
247
  stripCommandFromText: () => stripCommandFromText,
234
248
  textIsEmpty: () => textIsEmpty,
235
- timeLeftMs: () => timeLeftMs
249
+ timeLeftMs: () => timeLeftMs,
250
+ verifyAndParseWebhook: () => verifyAndParseWebhook,
251
+ verifySignature: () => verifySignature
236
252
  });
237
253
  module.exports = __toCommonJS(index_exports);
238
254
 
@@ -844,7 +860,7 @@ var deleteUserMessages = ({
844
860
  if (message.user?.id === user.id) {
845
861
  messages[i] = message.type === "deleted" ? message : toDeletedMessage({ message, hardDelete, deletedAt });
846
862
  }
847
- if (message.quoted_message?.user?.id === user.id) {
863
+ if (messages[i].quoted_message && message.quoted_message?.user?.id === user.id) {
848
864
  messages[i].quoted_message = message.quoted_message.type === "deleted" ? message.quoted_message : toDeletedMessage({
849
865
  message: messages[i].quoted_message,
850
866
  hardDelete,
@@ -7444,6 +7460,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
7444
7460
  const draft = event.draft;
7445
7461
  if (!draft || (draft.parent_id ?? null) !== (this.threadId ?? null) || draft.channel_cid !== this.channel.cid)
7446
7462
  return;
7463
+ if (this.editedMessage) return;
7447
7464
  this.initState({ composition: draft });
7448
7465
  }).unsubscribe;
7449
7466
  this.subscribeDraftDeleted = () => this.client.on("draft.deleted", (event) => {
@@ -7451,6 +7468,7 @@ var _MessageComposer = class _MessageComposer extends WithSubscriptions {
7451
7468
  if (!draft || (draft.parent_id ?? null) !== (this.threadId ?? null) || draft.channel_cid !== this.channel.cid) {
7452
7469
  return;
7453
7470
  }
7471
+ if (this.editedMessage) return;
7454
7472
  this.logDraftUpdateTimestamp();
7455
7473
  if (this.compositionIsEmpty) {
7456
7474
  return;
@@ -9494,7 +9512,7 @@ var Channel = class {
9494
9512
  if (Array.isArray(this.data?.own_capabilities) && !this.data?.own_capabilities.includes("read-events")) {
9495
9513
  return false;
9496
9514
  }
9497
- if (this.muteStatus().muted) return false;
9515
+ if (this.getClient()._muteStatus(this.cid).muted) return false;
9498
9516
  return true;
9499
9517
  }
9500
9518
  /**
@@ -11005,6 +11023,7 @@ var UploadManager = class {
11005
11023
  // src/signing.ts
11006
11024
  var import_jsonwebtoken = __toESM(require_jsonwebtoken());
11007
11025
  var import_crypto = __toESM(require_crypto());
11026
+ var import_zlib = __toESM(require_zlib());
11008
11027
  function JWTUserToken(apiSecret, userId, extraData = {}, jwtOptions = {}) {
11009
11028
  if (typeof userId !== "string") {
11010
11029
  throw new TypeError("userId should be a string");
@@ -11056,7 +11075,7 @@ function DevToken(userId) {
11056
11075
  // hardcoded signature
11057
11076
  ].join(".");
11058
11077
  }
11059
- function CheckSignature(body, secret, signature) {
11078
+ function verifySignature(body, signature, secret) {
11060
11079
  const key = Buffer.from(secret, "utf8");
11061
11080
  const hash = import_crypto.default.createHmac("sha256", key).update(body).digest("hex");
11062
11081
  try {
@@ -11065,6 +11084,86 @@ function CheckSignature(body, secret, signature) {
11065
11084
  return false;
11066
11085
  }
11067
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
+ }
11068
11167
 
11069
11168
  // src/token_manager.ts
11070
11169
  var TokenManager = class {
@@ -15668,7 +15767,7 @@ var StreamChat = class _StreamChat {
15668
15767
  if (this.userAgent) {
15669
15768
  return this.userAgent;
15670
15769
  }
15671
- const version = "9.43.2";
15770
+ const version = "9.44.0";
15672
15771
  const clientBundle = "browser-cjs";
15673
15772
  let userAgentString = "";
15674
15773
  if (this.sdkIdentifier) {
@@ -15761,7 +15860,50 @@ var StreamChat = class _StreamChat {
15761
15860
  * @returns {boolean}
15762
15861
  */
15763
15862
  verifyWebhook(requestBody, xSignature) {
15764
- 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);
15765
15907
  }
15766
15908
  /** getPermission - gets the definition for a permission
15767
15909
  *