@chat-adapter/slack 4.13.0 → 4.13.2

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/dist/index.js CHANGED
@@ -80,8 +80,11 @@ function convertChildToBlocks(child) {
80
80
  return [];
81
81
  }
82
82
  }
83
+ function markdownToMrkdwn(text) {
84
+ return text.replace(/\*\*(.+?)\*\*/g, "*$1*");
85
+ }
83
86
  function convertTextToBlock(element) {
84
- const text = convertEmoji(element.content);
87
+ const text = markdownToMrkdwn(convertEmoji(element.content));
85
88
  let formattedText = text;
86
89
  if (element.style === "bold") {
87
90
  formattedText = `*${text}*`;
@@ -238,8 +241,8 @@ function convertFieldsToBlock(element) {
238
241
  for (const field of element.children) {
239
242
  fields.push({
240
243
  type: "mrkdwn",
241
- text: `*${convertEmoji(field.label)}*
242
- ${convertEmoji(field.value)}`
244
+ text: `*${markdownToMrkdwn(convertEmoji(field.label))}*
245
+ ${markdownToMrkdwn(convertEmoji(field.value))}`
243
246
  });
244
247
  }
245
248
  return {
@@ -260,6 +263,7 @@ import crypto from "crypto";
260
263
  var ALGORITHM = "aes-256-gcm";
261
264
  var IV_LENGTH = 12;
262
265
  var AUTH_TAG_LENGTH = 16;
266
+ var HEX_KEY_PATTERN = /^[0-9a-fA-F]{64}$/;
263
267
  function encryptToken(plaintext, key) {
264
268
  const iv = crypto.randomBytes(IV_LENGTH);
265
269
  const cipher = crypto.createCipheriv(ALGORITHM, key, iv, {
@@ -290,13 +294,15 @@ function decryptToken(encrypted, key) {
290
294
  ]).toString("utf8");
291
295
  }
292
296
  function isEncryptedTokenData(value) {
293
- if (!value || typeof value !== "object") return false;
297
+ if (!value || typeof value !== "object") {
298
+ return false;
299
+ }
294
300
  const obj = value;
295
301
  return typeof obj.iv === "string" && typeof obj.data === "string" && typeof obj.tag === "string";
296
302
  }
297
303
  function decodeKey(rawKey) {
298
304
  const trimmed = rawKey.trim();
299
- const isHex = /^[0-9a-fA-F]{64}$/.test(trimmed);
305
+ const isHex = HEX_KEY_PATTERN.test(trimmed);
300
306
  const key = Buffer.from(trimmed, isHex ? "hex" : "base64");
301
307
  if (key.length !== 32) {
302
308
  throw new Error(
@@ -434,11 +440,15 @@ ${node.value}
434
440
 
435
441
  // src/modals.ts
436
442
  function encodeModalMetadata(meta) {
437
- if (!meta.contextId && !meta.privateMetadata) return void 0;
443
+ if (!(meta.contextId || meta.privateMetadata)) {
444
+ return void 0;
445
+ }
438
446
  return JSON.stringify({ c: meta.contextId, m: meta.privateMetadata });
439
447
  }
440
448
  function decodeModalMetadata(raw) {
441
- if (!raw) return {};
449
+ if (!raw) {
450
+ return {};
451
+ }
442
452
  try {
443
453
  const parsed = JSON.parse(raw);
444
454
  if (typeof parsed === "object" && parsed !== null && ("c" in parsed || "m" in parsed)) {
@@ -475,6 +485,10 @@ function modalChildToBlock(child) {
475
485
  return convertTextToBlock(child);
476
486
  case "fields":
477
487
  return convertFieldsToBlock(child);
488
+ default:
489
+ throw new Error(
490
+ `Unknown modal child type: ${child.type}`
491
+ );
478
492
  }
479
493
  }
480
494
  function textInputToBlock(input) {
@@ -592,7 +606,9 @@ var SlackAdapter = class _SlackAdapter {
592
606
  /** Bot user ID (e.g., U_BOT_123) used for mention detection */
593
607
  get botUserId() {
594
608
  const ctx = this.requestContext.getStore();
595
- if (ctx?.botUserId) return ctx.botUserId;
609
+ if (ctx?.botUserId) {
610
+ return ctx.botUserId;
611
+ }
596
612
  return this._botUserId || void 0;
597
613
  }
598
614
  constructor(config) {
@@ -614,8 +630,12 @@ var SlackAdapter = class _SlackAdapter {
614
630
  */
615
631
  getToken() {
616
632
  const ctx = this.requestContext.getStore();
617
- if (ctx?.token) return ctx.token;
618
- if (this.defaultBotToken) return this.defaultBotToken;
633
+ if (ctx?.token) {
634
+ return ctx.token;
635
+ }
636
+ if (this.defaultBotToken) {
637
+ return this.defaultBotToken;
638
+ }
619
639
  throw new ChatError(
620
640
  "No bot token available. In multi-workspace mode, ensure the webhook is being processed.",
621
641
  "MISSING_BOT_TOKEN"
@@ -693,7 +713,9 @@ var SlackAdapter = class _SlackAdapter {
693
713
  const state = this.chat.getState();
694
714
  const key = this.installationKey(teamId);
695
715
  const stored = await state.get(key);
696
- if (!stored) return null;
716
+ if (!stored) {
717
+ return null;
718
+ }
697
719
  if (this.encryptionKey && isEncryptedTokenData(stored.botToken)) {
698
720
  return {
699
721
  ...stored,
@@ -711,7 +733,7 @@ var SlackAdapter = class _SlackAdapter {
711
733
  * exchanges it for tokens, and saves the installation.
712
734
  */
713
735
  async handleOAuthCallback(request) {
714
- if (!this.clientId || !this.clientSecret) {
736
+ if (!(this.clientId && this.clientSecret)) {
715
737
  throw new ChatError(
716
738
  "clientId and clientSecret are required for OAuth. Pass them in createSlackAdapter().",
717
739
  "MISSING_OAUTH_CONFIG"
@@ -732,7 +754,7 @@ var SlackAdapter = class _SlackAdapter {
732
754
  code,
733
755
  redirect_uri: redirectUri
734
756
  });
735
- if (!result.ok || !result.access_token || !result.team?.id) {
757
+ if (!(result.ok && result.access_token && result.team?.id)) {
736
758
  throw new ChatError(
737
759
  `Slack OAuth failed: ${result.error || "missing access_token or team.id"}`,
738
760
  "OAUTH_FAILED"
@@ -800,7 +822,9 @@ var SlackAdapter = class _SlackAdapter {
800
822
  try {
801
823
  const params = new URLSearchParams(body);
802
824
  const payloadStr = params.get("payload");
803
- if (!payloadStr) return null;
825
+ if (!payloadStr) {
826
+ return null;
827
+ }
804
828
  const payload = JSON.parse(payloadStr);
805
829
  return payload.team?.id || payload.team_id || null;
806
830
  } catch {
@@ -891,9 +915,7 @@ var SlackAdapter = class _SlackAdapter {
891
915
  return new Response("Invalid JSON", { status: 400 });
892
916
  }
893
917
  if (payload.type === "url_verification" && payload.challenge) {
894
- return new Response(JSON.stringify({ challenge: payload.challenge }), {
895
- headers: { "Content-Type": "application/json" }
896
- });
918
+ return Response.json({ challenge: payload.challenge });
897
919
  }
898
920
  if (!this.defaultBotToken && payload.type === "event_callback") {
899
921
  const teamId = payload.team_id;
@@ -918,7 +940,7 @@ var SlackAdapter = class _SlackAdapter {
918
940
  const event = payload.event;
919
941
  if (event.type === "message" || event.type === "app_mention") {
920
942
  const slackEvent = event;
921
- if (!slackEvent.team && !slackEvent.team_id && payload.team_id) {
943
+ if (!(slackEvent.team || slackEvent.team_id) && payload.team_id) {
922
944
  slackEvent.team_id = payload.team_id;
923
945
  }
924
946
  this.handleMessageEvent(slackEvent, options);
@@ -1020,7 +1042,7 @@ var SlackAdapter = class _SlackAdapter {
1020
1042
  const messageTs = payload.message?.ts || payload.container?.message_ts;
1021
1043
  const threadTs = payload.message?.thread_ts || payload.container?.thread_ts || messageTs;
1022
1044
  const isViewAction = payload.container?.type === "view";
1023
- if (!isViewAction && !channel) {
1045
+ if (!(isViewAction || channel)) {
1024
1046
  this.logger.warn("Missing channel in block_actions", { channel });
1025
1047
  return;
1026
1048
  }
@@ -1173,11 +1195,11 @@ var SlackAdapter = class _SlackAdapter {
1173
1195
  return modal;
1174
1196
  }
1175
1197
  verifySignature(body, timestamp, signature) {
1176
- if (!timestamp || !signature) {
1198
+ if (!(timestamp && signature)) {
1177
1199
  return false;
1178
1200
  }
1179
1201
  const now = Math.floor(Date.now() / 1e3);
1180
- if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
1202
+ if (Math.abs(now - Number.parseInt(timestamp, 10)) > 300) {
1181
1203
  return false;
1182
1204
  }
1183
1205
  const sigBasestring = `v0:${timestamp}:${body}`;
@@ -1206,7 +1228,7 @@ var SlackAdapter = class _SlackAdapter {
1206
1228
  });
1207
1229
  return;
1208
1230
  }
1209
- if (!event.channel || !event.ts) {
1231
+ if (!(event.channel && event.ts)) {
1210
1232
  this.logger.debug("Ignoring event without channel or ts", {
1211
1233
  channel: event.channel,
1212
1234
  ts: event.ts
@@ -1440,11 +1462,15 @@ var SlackAdapter = class _SlackAdapter {
1440
1462
  userIds.add(match[1]);
1441
1463
  match = mentionPattern.exec(text);
1442
1464
  }
1443
- if (userIds.size === 0) return text;
1465
+ if (userIds.size === 0) {
1466
+ return text;
1467
+ }
1444
1468
  if (skipSelfMention && this._botUserId) {
1445
1469
  userIds.delete(this._botUserId);
1446
1470
  }
1447
- if (userIds.size === 0) return text;
1471
+ if (userIds.size === 0) {
1472
+ return text;
1473
+ }
1448
1474
  const lookups = await Promise.all(
1449
1475
  [...userIds].map(async (uid) => {
1450
1476
  const info = await this.lookupUser(uid);
@@ -1483,9 +1509,9 @@ var SlackAdapter = class _SlackAdapter {
1483
1509
  isMe
1484
1510
  },
1485
1511
  metadata: {
1486
- dateSent: new Date(parseFloat(event.ts || "0") * 1e3),
1512
+ dateSent: new Date(Number.parseFloat(event.ts || "0") * 1e3),
1487
1513
  edited: !!event.edited,
1488
- editedAt: event.edited ? new Date(parseFloat(event.edited.ts) * 1e3) : void 0
1514
+ editedAt: event.edited ? new Date(Number.parseFloat(event.edited.ts) * 1e3) : void 0
1489
1515
  },
1490
1516
  attachments: (event.files || []).map(
1491
1517
  (file) => this.createAttachment(file)
@@ -1540,7 +1566,7 @@ var SlackAdapter = class _SlackAdapter {
1540
1566
  await this.uploadFiles(files, channel, threadTs || void 0);
1541
1567
  const hasText = typeof message === "string" || typeof message === "object" && message !== null && ("raw" in message || "markdown" in message || "ast" in message);
1542
1568
  const card2 = extractCard(message);
1543
- if (!hasText && !card2) {
1569
+ if (!(hasText || card2)) {
1544
1570
  return {
1545
1571
  id: `file-${Date.now()}`,
1546
1572
  threadId,
@@ -1918,7 +1944,7 @@ var SlackAdapter = class _SlackAdapter {
1918
1944
  * Requires `recipientUserId` and `recipientTeamId` in options.
1919
1945
  */
1920
1946
  async stream(threadId, textStream, options) {
1921
- if (!options?.recipientUserId || !options?.recipientTeamId) {
1947
+ if (!(options?.recipientUserId && options?.recipientTeamId)) {
1922
1948
  throw new ChatError(
1923
1949
  "Slack streaming requires recipientUserId and recipientTeamId in options",
1924
1950
  "MISSING_STREAM_OPTIONS"
@@ -1990,7 +2016,7 @@ var SlackAdapter = class _SlackAdapter {
1990
2016
  const limit = options.limit || 100;
1991
2017
  try {
1992
2018
  if (direction === "forward") {
1993
- return this.fetchMessagesForward(
2019
+ return await this.fetchMessagesForward(
1994
2020
  channel,
1995
2021
  threadTs,
1996
2022
  threadId,
@@ -1998,7 +2024,7 @@ var SlackAdapter = class _SlackAdapter {
1998
2024
  options.cursor
1999
2025
  );
2000
2026
  }
2001
- return this.fetchMessagesBackward(
2027
+ return await this.fetchMessagesBackward(
2002
2028
  channel,
2003
2029
  threadTs,
2004
2030
  threadId,
@@ -2138,7 +2164,9 @@ var SlackAdapter = class _SlackAdapter {
2138
2164
  );
2139
2165
  const messages = result.messages || [];
2140
2166
  const target = messages.find((msg) => msg.ts === messageId);
2141
- if (!target) return null;
2167
+ if (!target) {
2168
+ return null;
2169
+ }
2142
2170
  return this.parseSlackMessage(target, threadId);
2143
2171
  } catch (error) {
2144
2172
  this.handleSlackError(error);
@@ -2200,9 +2228,9 @@ var SlackAdapter = class _SlackAdapter {
2200
2228
  isMe
2201
2229
  },
2202
2230
  metadata: {
2203
- dateSent: new Date(parseFloat(event.ts || "0") * 1e3),
2231
+ dateSent: new Date(Number.parseFloat(event.ts || "0") * 1e3),
2204
2232
  edited: !!event.edited,
2205
- editedAt: event.edited ? new Date(parseFloat(event.edited.ts) * 1e3) : void 0
2233
+ editedAt: event.edited ? new Date(Number.parseFloat(event.edited.ts) * 1e3) : void 0
2206
2234
  },
2207
2235
  attachments: (event.files || []).map(
2208
2236
  (file) => this.createAttachment(file)
@@ -2276,7 +2304,7 @@ var SlackAdapter = class _SlackAdapter {
2276
2304
  );
2277
2305
  let nextCursor;
2278
2306
  if (result.has_more && slackMessages.length > 0) {
2279
- const newest = slackMessages[slackMessages.length - 1];
2307
+ const newest = slackMessages.at(-1);
2280
2308
  if (newest?.ts) {
2281
2309
  nextCursor = newest.ts;
2282
2310
  }
@@ -2399,7 +2427,7 @@ var SlackAdapter = class _SlackAdapter {
2399
2427
  return {
2400
2428
  id: channelId,
2401
2429
  name: info?.name ? `#${info.name}` : void 0,
2402
- isDM: info?.is_im || info?.is_mpim || false,
2430
+ isDM: Boolean(info?.is_im || info?.is_mpim),
2403
2431
  memberCount: info?.num_members,
2404
2432
  metadata: {
2405
2433
  purpose: info?.purpose?.value,
@@ -2422,7 +2450,7 @@ var SlackAdapter = class _SlackAdapter {
2422
2450
  );
2423
2451
  }
2424
2452
  const syntheticThreadId = `slack:${channel}:`;
2425
- return this.postMessage(syntheticThreadId, message);
2453
+ return await this.postMessage(syntheticThreadId, message);
2426
2454
  }
2427
2455
  renderFormatted(content) {
2428
2456
  return this.formatConverter.fromAst(content);
@@ -2453,10 +2481,8 @@ var SlackAdapter = class _SlackAdapter {
2453
2481
  }
2454
2482
  handleSlackError(error) {
2455
2483
  const slackError = error;
2456
- if (slackError.code === "slack_webapi_platform_error") {
2457
- if (slackError.data?.error === "ratelimited") {
2458
- throw new AdapterRateLimitError("slack");
2459
- }
2484
+ if (slackError.code === "slack_webapi_platform_error" && slackError.data?.error === "ratelimited") {
2485
+ throw new AdapterRateLimitError("slack");
2460
2486
  }
2461
2487
  throw error;
2462
2488
  }
@@ -2473,9 +2499,13 @@ var SlackAdapter = class _SlackAdapter {
2473
2499
  * Returns null if the messageId is not an ephemeral encoding.
2474
2500
  */
2475
2501
  decodeEphemeralMessageId(messageId) {
2476
- if (!messageId.startsWith("ephemeral:")) return null;
2502
+ if (!messageId.startsWith("ephemeral:")) {
2503
+ return null;
2504
+ }
2477
2505
  const parts = messageId.split(":");
2478
- if (parts.length < 3) return null;
2506
+ if (parts.length < 3) {
2507
+ return null;
2508
+ }
2479
2509
  const messageTs = parts[1];
2480
2510
  const encodedData = parts.slice(2).join(":");
2481
2511
  try {