@openclaw/slack 2026.11.3 → 2026.11.5-beta.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.
Files changed (220) hide show
  1. package/dist/.setup/{account-inspect-CmkKiSb9.mjs → account-inspect-BLVha-ov.mjs} +11 -8
  2. package/dist/.setup/{accounts-msihSF3-.mjs → accounts-CGJScKtk.mjs} +10 -1
  3. package/dist/.setup/{action-runtime-ChRfnnBu.mjs → action-runtime-D01wBhx5.mjs} +38 -45
  4. package/dist/.setup/action-runtime.runtime-VQGaR6g8.mjs +1 -0
  5. package/dist/.setup/{actions-By7tvpvv.mjs → actions-D5S6D_BU.mjs} +89 -76
  6. package/dist/.setup/{approval-handler.runtime-D8ArtDQt.mjs → approval-handler.runtime-Buw5jh2Y.mjs} +26 -30
  7. package/dist/.setup/{approval-message-updates-DT7XBPbV.mjs → approval-message-updates-pmXcve5E.mjs} +1 -1
  8. package/dist/.setup/{channel-DLFiMJm2.mjs → channel-C_R98Nbv.mjs} +569 -339
  9. package/dist/.setup/{channel-type-BEFP2ORi.mjs → channel-type-B5P3w9eA.mjs} +4 -8
  10. package/dist/.setup/{channel.setup-CzFw73mU.mjs → channel.setup-Lq2OxKkF.mjs} +13 -13
  11. package/dist/.setup/{config-schema-DNnh6bWU.mjs → config-schema-BWAaa5au.mjs} +3 -7
  12. package/dist/.setup/cursor-pages-CATAzbTT.mjs +313 -0
  13. package/dist/.setup/{directory-config-Cjj0N8R0.mjs → directory-config-D-hf9KGQ.mjs} +3 -3
  14. package/dist/.setup/{directory-live-BIKD-5B_.mjs → directory-live-onKAFI1E.mjs} +4 -4
  15. package/dist/.setup/{doctor-contract-Cd4-VzIM.mjs → doctor-contract-9-QJRCXk.mjs} +37 -45
  16. package/dist/.setup/{message-tool-api-BS5ekEA_.mjs → message-tool-api-LGIgVXJf.mjs} +4 -3
  17. package/dist/.setup/{monitor-CV6Z6FKP.mjs → monitor-Cm1TuqxN.mjs} +3424 -3703
  18. package/dist/.setup/{outbound-adapter-9dbnYtL1.mjs → outbound-adapter-C-95EWl2.mjs} +30 -36
  19. package/dist/.setup/paths-B1u59oLK.mjs +8 -0
  20. package/dist/.setup/{pipeline.runtime-DLIQf1Bo.mjs → pipeline.runtime-DGnV6akc.mjs} +416 -534
  21. package/dist/.setup/{policy-yhn48xf5.mjs → policy-DxhGRvc2.mjs} +1 -2
  22. package/dist/.setup/{session-status-Dv8wNBEt.mjs → probe-DANukR3O.mjs} +1206 -839
  23. package/dist/.setup/question-delivery-CWC7sRhH.mjs +39 -0
  24. package/dist/.setup/{relay-source-CxDcrn16.mjs → relay-source-DoyOlTbK.mjs} +5 -3
  25. package/dist/.setup/{replies-MRkrg3rC.mjs → replies-BcmUKord.mjs} +34 -19
  26. package/dist/.setup/{reply-blocks-Ca-raz2z.mjs → reply-blocks-BzsXUUUL.mjs} +201 -206
  27. package/dist/.setup/{resolve-channels-DRRhElwz.mjs → resolve-channels-XDPgnesf.mjs} +4 -7
  28. package/dist/.setup/{resolve-users-Cz8e17ky.mjs → resolve-users-aDAv24U2.mjs} +8 -16
  29. package/dist/.setup/runtime-setter-api-Cx_PV-xu.mjs +2 -0
  30. package/dist/.setup/{scopes-DfQVi8Jw.mjs → scopes-BocHwImV.mjs} +2 -1
  31. package/dist/.setup/secret-contract-api-BlLz88mj.mjs +2 -0
  32. package/dist/.setup/{secret-contract-vVRMoE1D.mjs → secret-contract-uiQtoNlu.mjs} +2 -2
  33. package/dist/.setup/{send-results-eeOu_HYm.mjs → send-results-BGxlroJ-.mjs} +3 -4
  34. package/dist/.setup/{send-C-8wY0lK.mjs → send-yK6_-px6.mjs} +297 -334
  35. package/dist/.setup/setup-plugin-api-Cfz58xoh.mjs +2 -0
  36. package/dist/.setup/{setup-surface--n8VsDvV.mjs → setup-surface-C0KRtyqa.mjs} +5 -6
  37. package/dist/.setup/{slash-dispatch.runtime-D3Wq45ER.mjs → slash-dispatch.runtime-CyVC3bYx.mjs} +2 -2
  38. package/dist/.setup/{target-parsing-FFE26kOV.mjs → target-parsing-Bx2UZniD.mjs} +1 -2
  39. package/dist/.setup/{targets-C6LZQL1Q.mjs → targets-D-ASeWHy.mjs} +1 -1
  40. package/dist/.source-module-urls/c5ffd0957b234c7c12090e7de4eca2482ef339b8561e078da55b734211b0ba58.json +1 -0
  41. package/dist/account-inspect-api.js +1 -1
  42. package/dist/api.js +16 -17
  43. package/dist/channel-config-api.js +1 -2
  44. package/dist/channel-plugin-api.js +1 -2
  45. package/dist/directory-contract-api.js +1 -2
  46. package/dist/doctor-contract-api.js +1 -2
  47. package/dist/index.js +0 -6
  48. package/dist/message-tool-api.js +1 -2
  49. package/dist/runtime-api.js +10 -12
  50. package/dist/runtime-setter-api.js +1 -2
  51. package/dist/secret-contract-api.js +1 -2
  52. package/dist/security-contract-api.js +1 -2
  53. package/dist/setup-entry.js +3 -3
  54. package/dist/setup-plugin-api.js +1 -2
  55. package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
  56. package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
  57. package/node_modules/@slack/bolt/node_modules/@types/node/util.d.ts +6 -3
  58. package/node_modules/@slack/bolt/node_modules/content-disposition/README.md +105 -35
  59. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.d.ts +72 -0
  60. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.js +388 -0
  61. package/node_modules/@slack/bolt/node_modules/content-disposition/dist/index.js.map +1 -0
  62. package/node_modules/@slack/bolt/node_modules/content-disposition/package.json +31 -19
  63. package/node_modules/@slack/bolt/node_modules/content-type/README.md +34 -57
  64. package/node_modules/@slack/bolt/node_modules/content-type/package.json +35 -25
  65. package/node_modules/@slack/bolt/node_modules/express/Readme.md +15 -9
  66. package/node_modules/@slack/bolt/node_modules/express/lib/application.js +2 -2
  67. package/node_modules/@slack/bolt/node_modules/express/lib/request.js +32 -19
  68. package/node_modules/@slack/bolt/node_modules/express/lib/response.js +27 -30
  69. package/node_modules/@slack/bolt/node_modules/express/package.json +10 -10
  70. package/node_modules/@slack/bolt/node_modules/qs/.github/THREAT_MODEL.md +4 -2
  71. package/node_modules/@slack/bolt/node_modules/qs/CHANGELOG.md +38 -14
  72. package/node_modules/@slack/bolt/node_modules/qs/README.md +31 -3
  73. package/node_modules/@slack/bolt/node_modules/qs/dist/qs.js +20 -20
  74. package/node_modules/@slack/bolt/node_modules/qs/lib/parse.js +94 -4
  75. package/node_modules/@slack/bolt/node_modules/qs/lib/stringify.js +4 -4
  76. package/node_modules/@slack/bolt/node_modules/qs/lib/utils.js +130 -6
  77. package/node_modules/@slack/bolt/node_modules/qs/package.json +4 -4
  78. package/node_modules/@slack/bolt/node_modules/qs/test/parse.js +174 -0
  79. package/node_modules/@slack/bolt/node_modules/qs/test/stringify.js +263 -33
  80. package/node_modules/@slack/bolt/node_modules/qs/test/utils.js +184 -0
  81. package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
  82. package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
  83. package/node_modules/@slack/web-api/node_modules/@types/node/util.d.ts +6 -3
  84. package/node_modules/typebox/build/format/duration.d.mts +2 -2
  85. package/node_modules/typebox/build/format/duration.mjs +2 -2
  86. package/node_modules/typebox/build/format/idn_email.d.mts +1 -0
  87. package/node_modules/typebox/build/format/idn_email.mjs +1 -0
  88. package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -1
  89. package/node_modules/typebox/build/format/idn_hostname.mjs +1 -1
  90. package/node_modules/typebox/build/format/ipv4.d.mts +2 -2
  91. package/node_modules/typebox/build/format/ipv4.mjs +2 -2
  92. package/node_modules/typebox/build/format/ipv6.d.mts +1 -1
  93. package/node_modules/typebox/build/format/ipv6.mjs +1 -1
  94. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  95. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  96. package/node_modules/typebox/build/schema/build.mjs +1 -0
  97. package/node_modules/typebox/build/schema/engine/_unique.d.mts +4 -2
  98. package/node_modules/typebox/build/schema/engine/_unique.mjs +7 -3
  99. package/node_modules/typebox/build/schema/engine/additionalItems.mjs +3 -3
  100. package/node_modules/typebox/build/schema/engine/additionalProperties.d.mts +0 -3
  101. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +15 -17
  102. package/node_modules/typebox/build/schema/engine/contains.mjs +3 -3
  103. package/node_modules/typebox/build/schema/engine/index.d.mts +1 -0
  104. package/node_modules/typebox/build/schema/engine/index.mjs +1 -0
  105. package/node_modules/typebox/build/schema/engine/items.mjs +7 -4
  106. package/node_modules/typebox/build/schema/engine/maxContains.mjs +2 -2
  107. package/node_modules/typebox/build/schema/engine/minContains.mjs +3 -3
  108. package/node_modules/typebox/build/schema/engine/oneOf.mjs +2 -2
  109. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +2 -2
  110. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -2
  111. package/node_modules/typebox/build/schema/engine/unevaluatedItems.mjs +2 -2
  112. package/node_modules/typebox/build/schema/engine/unevaluatedProperties.mjs +2 -2
  113. package/node_modules/typebox/build/system/hashing/hash.mjs +63 -34
  114. package/node_modules/typebox/build/system/locale/en_US.mjs +2 -1
  115. package/node_modules/typebox/build/system/memory/assign.d.mts +2 -8
  116. package/node_modules/typebox/build/system/memory/assign.mjs +13 -6
  117. package/node_modules/typebox/build/system/memory/clone.d.mts +4 -5
  118. package/node_modules/typebox/build/system/memory/clone.mjs +8 -96
  119. package/node_modules/typebox/build/system/memory/create.d.mts +1 -5
  120. package/node_modules/typebox/build/system/memory/create.mjs +18 -13
  121. package/node_modules/typebox/build/system/memory/deep.d.mts +2 -0
  122. package/node_modules/typebox/build/system/memory/deep.mjs +108 -0
  123. package/node_modules/typebox/build/system/memory/discard.d.mts +1 -1
  124. package/node_modules/typebox/build/system/memory/discard.mjs +9 -8
  125. package/node_modules/typebox/build/system/memory/finalize.d.mts +4 -0
  126. package/node_modules/typebox/build/system/memory/finalize.mjs +30 -0
  127. package/node_modules/typebox/build/system/memory/keys.d.mts +2 -0
  128. package/node_modules/typebox/build/system/memory/keys.mjs +8 -0
  129. package/node_modules/typebox/build/system/memory/update.d.mts +1 -4
  130. package/node_modules/typebox/build/system/memory/update.mjs +43 -16
  131. package/node_modules/typebox/build/type/engine/call/index.d.mts +1 -0
  132. package/node_modules/typebox/build/type/engine/call/index.mjs +1 -0
  133. package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +2 -24
  134. package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +2 -29
  135. package/node_modules/typebox/build/type/engine/evaluate/index.d.mts +1 -0
  136. package/node_modules/typebox/build/type/engine/evaluate/index.mjs +1 -0
  137. package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +5 -1
  138. package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +6 -1
  139. package/node_modules/typebox/build/type/engine/evaluate/property.d.mts +30 -0
  140. package/node_modules/typebox/build/type/engine/evaluate/property.mjs +29 -0
  141. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.d.mts +1 -3
  142. package/node_modules/typebox/build/type/engine/immutable/instantiate_add.mjs +1 -4
  143. package/node_modules/typebox/build/type/engine/object/from_intersect.d.mts +2 -2
  144. package/node_modules/typebox/build/type/engine/object/from_intersect.mjs +2 -2
  145. package/node_modules/typebox/build/type/engine/object/from_union.d.mts +2 -2
  146. package/node_modules/typebox/build/type/engine/object/from_union.mjs +2 -2
  147. package/node_modules/typebox/build/type/engine/optional/instantiate_add.d.mts +1 -3
  148. package/node_modules/typebox/build/type/engine/optional/instantiate_add.mjs +1 -4
  149. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.d.mts +1 -3
  150. package/node_modules/typebox/build/type/engine/readonly/instantiate_add.mjs +1 -4
  151. package/node_modules/typebox/build/type/engine/this/index.d.mts +1 -0
  152. package/node_modules/typebox/build/type/engine/this/index.mjs +1 -0
  153. package/node_modules/typebox/build/value/clone/clone.d.mts +4 -3
  154. package/node_modules/typebox/build/value/clone/clone.mjs +5 -7
  155. package/node_modules/typebox/build/value/repair/from_cyclic.d.mts +2 -0
  156. package/node_modules/typebox/build/value/repair/from_cyclic.mjs +6 -0
  157. package/node_modules/typebox/build/value/shared/union_priority_sort.mjs +25 -14
  158. package/node_modules/typebox/package.json +1 -1
  159. package/node_modules/typebox/readme.md +1 -1
  160. package/node_modules/undici/docs/docs/api/Interceptors.md +15 -2
  161. package/node_modules/undici/lib/dispatcher/client-h2.js +78 -3
  162. package/node_modules/undici/lib/dispatcher/pool-base.js +20 -3
  163. package/node_modules/undici/package.json +3 -3
  164. package/node_modules/undici/types/api.d.ts +1 -1
  165. package/node_modules/undici/types/utility.d.ts +4 -4
  166. package/node_modules/zod/package.json +1 -1
  167. package/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
  168. package/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
  169. package/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
  170. package/node_modules/zod/src/v4/core/compile.ts +9 -0
  171. package/node_modules/zod/src/v4/core/schemas.ts +35 -1
  172. package/node_modules/zod/src/v4/core/util.ts +13 -0
  173. package/node_modules/zod/src/v4/core/versions.ts +1 -1
  174. package/node_modules/zod/v4/core/compile.cjs +8 -0
  175. package/node_modules/zod/v4/core/compile.js +8 -0
  176. package/node_modules/zod/v4/core/schemas.cjs +30 -0
  177. package/node_modules/zod/v4/core/schemas.d.cts +3 -1
  178. package/node_modules/zod/v4/core/schemas.d.ts +3 -1
  179. package/node_modules/zod/v4/core/schemas.js +30 -0
  180. package/node_modules/zod/v4/core/util.cjs +15 -0
  181. package/node_modules/zod/v4/core/util.d.cts +2 -0
  182. package/node_modules/zod/v4/core/util.d.ts +2 -0
  183. package/node_modules/zod/v4/core/util.js +14 -0
  184. package/node_modules/zod/v4/core/versions.cjs +1 -1
  185. package/node_modules/zod/v4/core/versions.js +1 -1
  186. package/openclaw.plugin.json +6 -30
  187. package/package.json +7 -7
  188. package/dist/.setup/action-runtime.runtime-vLxx_7s2.mjs +0 -2
  189. package/dist/.setup/http-C9sM-FXe.mjs +0 -2
  190. package/dist/.setup/plugin-routes-D4qozHVn.mjs +0 -22
  191. package/dist/.setup/probe-IiHogLQN.mjs +0 -694
  192. package/dist/.setup/registry-DizWcnNp.mjs +0 -36
  193. package/dist/.setup/runtime-setter-api-CMFvhrAr.mjs +0 -3
  194. package/dist/.setup/secret-contract-api-DK9gZldc.mjs +0 -3
  195. package/dist/.setup/setup-plugin-api-BGD1TYnK.mjs +0 -3
  196. package/dist/.setup/shared-BhJHIZs1.mjs +0 -259
  197. package/dist/http-routes-api.js +0 -2
  198. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/LICENSE +0 -22
  199. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/README.md +0 -71
  200. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/package.json +0 -52
  201. package/node_modules/@slack/bolt/node_modules/content-disposition/index.js +0 -536
  202. package/node_modules/@slack/bolt/node_modules/content-type/HISTORY.md +0 -29
  203. package/node_modules/@slack/bolt/node_modules/content-type/index.js +0 -225
  204. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/LICENSE +0 -22
  205. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/README.md +0 -71
  206. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +0 -46
  207. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js +0 -176
  208. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/dist/index.js.map +0 -1
  209. package/node_modules/@slack/bolt/node_modules/negotiator/node_modules/content-type/package.json +0 -52
  210. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/LICENSE +0 -22
  211. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/README.md +0 -71
  212. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.d.ts +0 -46
  213. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js +0 -176
  214. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js.map +0 -1
  215. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/package.json +0 -52
  216. package/node_modules/typebox/build/system/memory/freeze.d.mts +0 -4
  217. package/node_modules/typebox/build/system/memory/freeze.mjs +0 -6
  218. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.d.ts +0 -0
  219. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.js +0 -0
  220. /package/node_modules/@slack/bolt/node_modules/{body-parser/node_modules/content-type → content-type}/dist/index.js.map +0 -0
@@ -1,16 +1,16 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.mjs";
2
- import { d as resolveSlackOperationToken, s as resolveSlackAccount } from "./accounts-msihSF3-.mjs";
3
- import { a as parseSlackTarget, t as canonicalizeSlackApiTargetId } from "./target-parsing-FFE26kOV.mjs";
4
- import { A as SLACK_MESSAGE_TEXT_HARD_LIMIT, D as buildSlackCompleteBlocksFallbackText, F as truncateSlackTextByUtf8Bytes, K as resolveSlackQuestionActionIds, L as SLACK_QUESTION_FINALIZATION_BLOCKS, M as SLACK_TEXT_LIMIT, O as renderSlackBlockFallbackText, P as truncateSlackText, T as stripSlackNativeDataBlocks, X as chunkSlackMrkdwnText, Z as markdownToSlackMrkdwnChunks, b as hasSlackNativeDataBlock, gt as validateSlackBlocksArray, j as SLACK_MESSAGE_TEXT_RECOMMENDED_LIMIT, k as SLACK_EDIT_TEXT_MAX_BYTES, m as assertSlackDetachedTargetAllowed, v as buildSlackNativeDataAccessibilityText, w as renderSlackNativeDataPlainTextBlock, x as isSlackInvalidBlocksError, y as createSlackNativeDataBaseTextConsumer } from "./session-status-Dv8wNBEt.mjs";
5
- import { _ as getSlackWriteClient, b as writeLruMapEntry, d as createSlackReadClient, h as createSlackWriteClient, o as formatSlackError, p as createSlackTokenCacheKey, s as getSlackWebApiErrorData } from "./probe-IiHogLQN.mjs";
2
+ import { f as resolveSlackOperationToken, s as resolveSlackAccount } from "./accounts-CGJScKtk.mjs";
3
+ import { a as parseSlackTarget, t as canonicalizeSlackApiTargetId } from "./target-parsing-Bx2UZniD.mjs";
4
+ import { Ct as markdownToSlackMrkdwnChunks, D as createSlackNativeDataBaseTextConsumer, E as buildSlackNativeDataAccessibilityText, F as truncateSlackText, I as truncateSlackTextByUtf8Bytes, J as resolveSlackQuestionActionIds, M as renderSlackNativeDataPlainTextBlock, N as stripSlackNativeDataBlocks, O as hasSlackNativeDataBlock, R as SLACK_QUESTION_FINALIZATION_BLOCKS, S as assertSlackDetachedTargetAllowed, St as chunkSlackMrkdwnText, at as buildSlackCompleteBlocksFallbackText, bt as SLACK_MESSAGE_TEXT_RECOMMENDED_LIMIT, h as getSlackWebApiErrorData, k as isSlackInvalidBlocksError, m as formatSlackError, ot as renderSlackBlockFallbackText, rt as validateSlackBlocksArray, vt as SLACK_EDIT_TEXT_MAX_BYTES, xt as SLACK_TEXT_LIMIT, yt as SLACK_MESSAGE_TEXT_HARD_LIMIT } from "./probe-DANukR3O.mjs";
6
5
  import { r as resolveSlackThreadTsValue, t as normalizeSlackThreadTsCandidate } from "./thread-ts-Cvt7WD6B.mjs";
6
+ import { c as createSlackWriteClient, d as getOrCreateWeakOwnerMap, i as createSlackReadClient, m as writeLruMapEntry, o as createSlackTokenCacheKey, u as getSlackWriteClient } from "./cursor-pages-CATAzbTT.mjs";
7
7
  import { t as getOptionalSlackRuntime } from "./runtime-JSVZSWAj.mjs";
8
- import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
9
8
  import { asOptionalObjectRecord, asOptionalRecord, isRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
9
+ import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
10
10
  import { createMessageReceiptFromOutboundResults } from "openclaw/plugin-sdk/channel-outbound";
11
11
  import { logVerbose, sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
12
12
  import { chunkTextForOutbound } from "openclaw/plugin-sdk/text-chunking";
13
- import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
13
+ import { resolveGlobalSingleton } from "openclaw/plugin-sdk/global-singleton";
14
14
  import { resolveTextChunksWithFallback } from "openclaw/plugin-sdk/reply-payload";
15
15
  import { createHash, createHmac } from "node:crypto";
16
16
  import { withTrustedEnvProxyGuardedFetchMode } from "openclaw/plugin-sdk/fetch-runtime";
@@ -112,63 +112,9 @@ function buildSlackMessageIdentityPayload(identity) {
112
112
  ...identity?.iconUrl ? { icon_url: identity.iconUrl } : identity?.iconEmoji ? { icon_emoji: identity.iconEmoji } : {}
113
113
  };
114
114
  }
115
- function classifySlackCustomIdentityError(err) {
116
- const data = getSlackWebApiErrorData(err);
117
- const code = normalizeLowercaseStringOrEmpty(data?.error);
118
- if (code === "invalid_arguments" || code === "invalid_arg_name") return "argument";
119
- if (code !== "missing_scope") return;
120
- if (normalizeLowercaseStringOrEmpty(data?.needed).includes("chat:write.customize")) return "scope";
121
- return [...normalizeTrimmedStringList(data?.response_metadata?.scopes), ...normalizeTrimmedStringList(data?.response_metadata?.acceptedScopes)].map((scope) => normalizeLowercaseStringOrEmpty(scope)).includes("chat:write.customize") ? "scope" : void 0;
122
- }
123
115
  function hasSlackMessageIdentity(identity) {
124
116
  return Boolean(identity?.username || identity?.iconUrl || identity?.iconEmoji);
125
117
  }
126
- /** Post with the requested identity, degrading only on Slack identity-specific errors. */
127
- async function postSlackMessageWithIdentityFallback(params) {
128
- const { basePayload, identity, post } = params;
129
- try {
130
- if (!identity) return await post(basePayload);
131
- return await post({
132
- ...basePayload,
133
- ...buildSlackMessageIdentityPayload(identity)
134
- }, identity);
135
- } catch (err) {
136
- if (!identity || !hasSlackMessageIdentity(identity)) throw err;
137
- const rejection = classifySlackCustomIdentityError(err);
138
- if (!rejection) throw err;
139
- if (rejection === "argument" && identity.username && (identity.iconUrl || identity.iconEmoji)) {
140
- logVerbose("slack send: custom icon rejected, retrying with username only");
141
- try {
142
- return await post({
143
- ...basePayload,
144
- username: identity.username
145
- }, { username: identity.username });
146
- } catch (retryError) {
147
- if (!classifySlackCustomIdentityError(retryError)) throw retryError;
148
- }
149
- }
150
- logVerbose("slack send: custom identity rejected, retrying without custom identity");
151
- return post(basePayload);
152
- }
153
- }
154
- //#endregion
155
- //#region extensions/slack/src/post-message-payload.ts
156
- function buildSlackPostMessagePayload(params) {
157
- const threadPayload = params.replyBroadcast && params.threadTs ? {
158
- thread_ts: params.threadTs,
159
- reply_broadcast: true
160
- } : params.threadTs ? { thread_ts: params.threadTs } : {};
161
- return {
162
- channel: params.channelId,
163
- text: params.text,
164
- ...params.blocks?.length ? { blocks: params.blocks } : {},
165
- ...params.metadata ? { metadata: params.metadata } : {},
166
- ...typeof params.mrkdwn === "boolean" ? { mrkdwn: params.mrkdwn } : {},
167
- ...threadPayload,
168
- unfurl_links: params.unfurl?.unfurlLinks ?? false,
169
- ...typeof params.unfurl?.unfurlMedia === "boolean" ? { unfurl_media: params.unfurl.unfurlMedia } : {}
170
- };
171
- }
172
118
  //#endregion
173
119
  //#region extensions/slack/src/client-delivery.ts
174
120
  const SLACK_COMMERCIAL_API_HOSTNAME = "slack.com";
@@ -291,18 +237,61 @@ function requireSlackPostMessageTimestamp(response) {
291
237
  if (!timestamp) throw new Error("Slack chat.postMessage returned no message timestamp");
292
238
  return timestamp;
293
239
  }
240
+ function classifySlackCustomIdentityError(err) {
241
+ const data = getSlackWebApiErrorData(err);
242
+ const code = normalizeLowercaseStringOrEmpty(data?.error);
243
+ if (code === "invalid_arguments" || code === "invalid_arg_name") return "argument";
244
+ if (code !== "missing_scope") return;
245
+ if (normalizeLowercaseStringOrEmpty(data?.needed).includes("chat:write.customize")) return "scope";
246
+ return [...normalizeTrimmedStringList(data?.response_metadata?.scopes), ...normalizeTrimmedStringList(data?.response_metadata?.acceptedScopes)].map((scope) => normalizeLowercaseStringOrEmpty(scope)).includes("chat:write.customize") ? "scope" : void 0;
247
+ }
294
248
  async function postSlackMessageBestEffort(params) {
295
- const basePayload = buildSlackPostMessagePayload(params);
249
+ const threadPayload = params.replyBroadcast && params.threadTs ? {
250
+ thread_ts: params.threadTs,
251
+ reply_broadcast: true
252
+ } : params.threadTs ? { thread_ts: params.threadTs } : {};
253
+ const basePayload = {
254
+ channel: params.channelId,
255
+ text: params.text,
256
+ ...params.blocks?.length ? { blocks: params.blocks } : {},
257
+ ...params.metadata ? { metadata: params.metadata } : {},
258
+ ...params.mrkdwn !== void 0 ? { mrkdwn: params.mrkdwn } : {},
259
+ ...threadPayload,
260
+ unfurl_links: params.unfurl?.unfurlLinks ?? false,
261
+ ...params.unfurl?.unfurlMedia !== void 0 ? { unfurl_media: params.unfurl.unfurlMedia } : {}
262
+ };
296
263
  const postChatMessage = params.client.chat.postMessage.bind(params.client.chat);
297
264
  const post = async (payload, identity) => ({
298
265
  response: await withSlackDnsRequestRetry("chat.postMessage", () => postChatMessage(payload)).catch(rethrowSlackPermanentOutboundApiRejection),
299
266
  identity
300
267
  });
301
- const posted = await postSlackMessageWithIdentityFallback({
302
- basePayload,
303
- identity: params.identity,
304
- post
305
- });
268
+ const identity = params.identity;
269
+ const posted = await (async () => {
270
+ try {
271
+ if (!identity) return await post(basePayload);
272
+ return await post({
273
+ ...basePayload,
274
+ ...buildSlackMessageIdentityPayload(identity)
275
+ }, identity);
276
+ } catch (err) {
277
+ if (!identity || !hasSlackMessageIdentity(identity)) throw err;
278
+ const rejection = classifySlackCustomIdentityError(err);
279
+ if (!rejection) throw err;
280
+ if (rejection === "argument" && identity.username && (identity.iconUrl || identity.iconEmoji)) {
281
+ logVerbose("slack send: custom icon rejected, retrying with username only");
282
+ try {
283
+ return await post({
284
+ ...basePayload,
285
+ username: identity.username
286
+ }, { username: identity.username });
287
+ } catch (retryError) {
288
+ if (!classifySlackCustomIdentityError(retryError)) throw retryError;
289
+ }
290
+ }
291
+ logVerbose("slack send: custom identity rejected, retrying without custom identity");
292
+ return post(basePayload);
293
+ }
294
+ })();
306
295
  const timestamp = requireSlackPostMessageTimestamp(posted.response);
307
296
  return {
308
297
  ...posted,
@@ -463,18 +452,11 @@ const slackDmChannelCaches = /* @__PURE__ */ new WeakMap();
463
452
  function createSlackDmCacheKey(params) {
464
453
  return `${params.accountId ?? "default"}:${createSlackTokenCacheKey(params.token)}:${params.recipientId}`;
465
454
  }
466
- function getSlackDmChannelCache(client) {
467
- const existing = slackDmChannelCaches.get(client);
468
- if (existing) return existing;
469
- const cache = /* @__PURE__ */ new Map();
470
- slackDmChannelCaches.set(client, cache);
471
- return cache;
472
- }
473
455
  function readCachedSlackDmChannelId(params) {
474
- return getSlackDmChannelCache(params.cacheOwner).get(createSlackDmCacheKey(params));
456
+ return slackDmChannelCaches.get(params.cacheOwner)?.get(createSlackDmCacheKey(params));
475
457
  }
476
458
  function cacheSlackDmChannelId(params, channelId) {
477
- const cache = getSlackDmChannelCache(params.cacheOwner);
459
+ const cache = getOrCreateWeakOwnerMap(slackDmChannelCaches, params.cacheOwner);
478
460
  const key = createSlackDmCacheKey(params);
479
461
  writeLruMapEntry(cache, key, channelId, SLACK_DM_CHANNEL_CACHE_MAX);
480
462
  }
@@ -542,17 +524,23 @@ function resolvePostedMessageThreadTs(response) {
542
524
  }
543
525
  async function updateMessageSlack(params) {
544
526
  const cfg = requireRuntimeConfig(params.cfg, "Slack update");
545
- const account = resolveSlackAccount({
546
- cfg,
547
- accountId: params.accountId
548
- });
549
- assertSlackDetachedTargetAllowed(account.accountId, params.teamId);
550
- const token = resolveToken({
551
- accountId: account.accountId,
552
- fallbackToken: account.botToken,
553
- fallbackSource: account.botTokenSource
527
+ const { client } = resolveSlackDelivery({
528
+ account: resolveSlackAccount({
529
+ cfg,
530
+ accountId: params.accountId
531
+ }),
532
+ eventScope: params.eventScope,
533
+ opts: {
534
+ cfg,
535
+ token: params.token
536
+ },
537
+ recipient: {
538
+ kind: "channel",
539
+ id: params.channelId,
540
+ teamId: params.teamId
541
+ }
554
542
  });
555
- await getSlackWriteClient(token, { teamId: params.teamId }).chat.update({
543
+ await client.chat.update({
556
544
  channel: params.channelId,
557
545
  ts: params.messageTs,
558
546
  text: truncateSlackTextByUtf8Bytes(params.text, SLACK_EDIT_TEXT_MAX_BYTES),
@@ -629,19 +617,20 @@ function parseEnterpriseEventRecipient(raw) {
629
617
  function resolveSlackDelivery(params) {
630
618
  if (params.eventScope) {
631
619
  if (!params.eventScope.writeClient) throw new Error("missing_enterprise_slack_write_client");
632
- return Object.freeze({
620
+ return {
633
621
  client: params.eventScope.writeClient,
634
622
  credential: SLACK_ENTERPRISE_LISTENER_QUEUE_CREDENTIAL,
635
623
  identity: normalizeSlackSendIdentity(params.opts.identity),
636
624
  recipient: params.recipient,
637
625
  teamId: params.eventScope.teamId,
638
626
  unfurl: { unfurlMedia: params.account.config.unfurlMedia },
639
- upload: Object.freeze({
627
+ upload: {
640
628
  client: params.eventScope.client,
641
629
  auditContext: "slack-enterprise-immediate-upload"
642
- })
643
- });
630
+ }
631
+ };
644
632
  }
633
+ assertSlackDetachedTargetAllowed(params.account.accountId, params.recipient.teamId);
645
634
  const credential = resolveToken({
646
635
  explicit: params.opts.token,
647
636
  accountId: params.account.accountId,
@@ -650,7 +639,7 @@ function resolveSlackDelivery(params) {
650
639
  });
651
640
  const cachedClient = params.recipient.teamId ? getSlackWriteClient(credential, { teamId: params.recipient.teamId }) : params.opts.client ?? getSlackWriteClient(credential);
652
641
  const client = params.opts.assertDirectAdapterHandoff ? createSlackWriteClient(credential, { teamId: params.recipient.teamId }, params.opts.assertDirectAdapterHandoff) : cachedClient;
653
- return Object.freeze({
642
+ return {
654
643
  client,
655
644
  ...client !== cachedClient ? { dmCacheOwner: cachedClient } : {},
656
645
  credential,
@@ -661,7 +650,7 @@ function resolveSlackDelivery(params) {
661
650
  unfurlLinks: params.account.config.unfurlLinks,
662
651
  unfurlMedia: params.account.config.unfurlMedia
663
652
  }
664
- });
653
+ };
665
654
  }
666
655
  async function resolveChannelId(client, recipient, params) {
667
656
  if (recipient.kind !== "user") return recipient.id;
@@ -678,20 +667,6 @@ async function resolveChannelId(client, recipient, params) {
678
667
  cacheSlackDmChannelId(cacheParams, channelId);
679
668
  return channelId;
680
669
  }
681
- function resolveSlackTextChunks(params) {
682
- const text = params.text;
683
- const chunkLimit = params.chunkLimit;
684
- if (params.preservePlainText) return text ? chunkTextForOutbound(text, chunkLimit, { preserveWhitespace: true }) : [];
685
- if (params.textIsSlackMrkdwn) return resolveTextChunksWithFallback(text, chunkSlackMrkdwnText(text, chunkLimit));
686
- const tableMode = resolveMarkdownTableMode({
687
- cfg: params.cfg,
688
- channel: "slack",
689
- ...params.accountId ? { accountId: params.accountId } : {}
690
- });
691
- const chunkMode = resolveChunkMode(params.cfg, "slack", params.accountId);
692
- const chunks = (chunkMode === "newline" ? chunkMarkdownTextWithMode(text, chunkLimit, chunkMode) : [text]).flatMap((markdown) => markdownToSlackMrkdwnChunks(markdown, chunkLimit, { tableMode }));
693
- return resolveTextChunksWithFallback(text, chunks);
694
- }
695
670
  async function resolveSlackDmChannelId(params) {
696
671
  return await resolveChannelId(params.client, {
697
672
  kind: "user",
@@ -762,37 +737,8 @@ const SLACK_RECONCILIATION_EVIDENCE_RANK = {
762
737
  conflict: 2,
763
738
  complete: 3
764
739
  };
765
- function findSlackConversationDeliveryParts(params) {
766
- const matches = [];
767
- for (const message of params.messages) {
768
- const marker = asOptionalRecord(asOptionalRecord(message.metadata)?.event_payload);
769
- if (!marker || marker[SLACK_DELIVERY_METADATA_KEY] !== params.deliveryId) continue;
770
- const partIndex = marker[SLACK_DELIVERY_METADATA_PART_INDEX_KEY];
771
- const partCount = marker[SLACK_DELIVERY_METADATA_PART_COUNT_KEY];
772
- if (typeof partIndex !== "number" || !Number.isInteger(partIndex) || typeof partCount !== "number" || !Number.isInteger(partCount) || partIndex < 0 || partCount <= 0 || partIndex >= partCount) continue;
773
- const expectedSignature = createSlackDeliveryMetadataSignature({
774
- queueId: params.queueId,
775
- channelId: params.channelId,
776
- threadTs: params.threadTs,
777
- partIndex,
778
- partCount
779
- });
780
- const actualSignature = marker[SLACK_DELIVERY_METADATA_SIGNATURE_KEY];
781
- if (typeof actualSignature !== "string" || !safeEqualSecret(actualSignature, expectedSignature)) continue;
782
- const messageId = typeof message.ts === "string" ? normalizeSlackThreadTsCandidate(message.ts) : void 0;
783
- if (!messageId) continue;
784
- const threadTs = typeof message.thread_ts === "string" ? normalizeSlackThreadTsCandidate(message.thread_ts) : void 0;
785
- matches.push({
786
- messageId,
787
- partIndex,
788
- partCount,
789
- ...threadTs ? { threadTs } : {}
790
- });
791
- }
792
- return matches;
793
- }
794
740
  async function scanSlackConversationForDelivery(params) {
795
- const threadTs = params.threadTs;
741
+ const lookupThreadTs = params.threadTs;
796
742
  let cursor;
797
743
  let expectedPartCount;
798
744
  const deliveryParts = /* @__PURE__ */ new Map();
@@ -805,17 +751,36 @@ async function scanSlackConversationForDelivery(params) {
805
751
  limit: SLACK_RECONCILE_LIMIT,
806
752
  ...cursor ? { cursor } : {}
807
753
  };
808
- const response = threadTs ? await withSlackDnsRequestRetry("conversations.replies", () => params.client.conversations.replies({
754
+ const response = lookupThreadTs ? await withSlackDnsRequestRetry("conversations.replies", () => params.client.conversations.replies({
809
755
  ...query,
810
- ts: threadTs
756
+ ts: lookupThreadTs
811
757
  })) : await withSlackDnsRequestRetry("conversations.history", () => params.client.conversations.history(query));
812
- const matches = findSlackConversationDeliveryParts({
813
- messages: asSlackConversationMessages(response),
814
- queueId: params.queueId,
815
- deliveryId: params.deliveryId,
816
- channelId: params.channelId,
817
- ...threadTs ? { threadTs } : {}
818
- });
758
+ const matches = [];
759
+ for (const message of asSlackConversationMessages(response)) {
760
+ const marker = asOptionalRecord(asOptionalRecord(message.metadata)?.event_payload);
761
+ if (!marker || marker[SLACK_DELIVERY_METADATA_KEY] !== params.deliveryId) continue;
762
+ const partIndex = marker[SLACK_DELIVERY_METADATA_PART_INDEX_KEY];
763
+ const partCount = marker[SLACK_DELIVERY_METADATA_PART_COUNT_KEY];
764
+ if (typeof partIndex !== "number" || !Number.isInteger(partIndex) || typeof partCount !== "number" || !Number.isInteger(partCount) || partIndex < 0 || partCount <= 0 || partIndex >= partCount) continue;
765
+ const expectedSignature = createSlackDeliveryMetadataSignature({
766
+ queueId: params.queueId,
767
+ channelId: params.channelId,
768
+ threadTs: lookupThreadTs,
769
+ partIndex,
770
+ partCount
771
+ });
772
+ const actualSignature = marker[SLACK_DELIVERY_METADATA_SIGNATURE_KEY];
773
+ if (typeof actualSignature !== "string" || !safeEqualSecret(actualSignature, expectedSignature)) continue;
774
+ const messageId = typeof message.ts === "string" ? normalizeSlackThreadTsCandidate(message.ts) : void 0;
775
+ if (!messageId) continue;
776
+ const threadTs = typeof message.thread_ts === "string" ? normalizeSlackThreadTsCandidate(message.thread_ts) : void 0;
777
+ matches.push({
778
+ messageId,
779
+ partIndex,
780
+ partCount,
781
+ ...threadTs ? { threadTs } : {}
782
+ });
783
+ }
819
784
  for (const match of matches) {
820
785
  expectedPartCount ??= match.partCount;
821
786
  const existing = deliveryParts.get(match.partIndex);
@@ -921,209 +886,207 @@ async function reconcileSlackUnknownSend(ctx) {
921
886
  return unresolvedSlackDelivery(readSlackRequestErrorMessage(enrichSlackWebApiError(err)), ctx.retryCount < 3);
922
887
  }
923
888
  }
924
- async function sendMessageSlack(to, message, opts) {
889
+ async function sendMessageSlack(to, message, options) {
925
890
  const normalizedMessage = normalizeOptionalString(message) ?? "";
926
- const trimmedMessage = opts.textIsSlackPlainText && normalizedMessage ? message : normalizedMessage;
927
- const cfg = requireRuntimeConfig(opts.cfg, "Slack send");
891
+ const trimmedMessage = options.textIsSlackPlainText && normalizedMessage ? message : normalizedMessage;
892
+ const cfg = requireRuntimeConfig(options.cfg, "Slack send");
928
893
  const account = resolveSlackAccount({
929
894
  cfg,
930
- accountId: opts.accountId
895
+ accountId: options.accountId
931
896
  });
932
- const eventScope = opts.eventScope;
897
+ const eventScope = options.eventScope;
933
898
  if (eventScope && (!/^T[A-Z0-9]+$/i.test(eventScope.teamId) || !eventScope.client)) throw new Error("invalid_enterprise_slack_listener_scope");
934
- const recipient = eventScope ? parseEnterpriseEventRecipient(to) : parseRecipient(to);
935
- if (!eventScope) assertSlackDetachedTargetAllowed(account.accountId, recipient.teamId);
936
- const blocks = opts.blocks == null ? void 0 : validateSlackBlocksArray(opts.blocks);
937
- if (!normalizedMessage && !opts.mediaUrl && !blocks) throw new Error("Slack send requires text, blocks, or media");
938
- const queuedOpts = Object.freeze({ ...opts });
899
+ const parsedRecipient = eventScope ? parseEnterpriseEventRecipient(to) : parseRecipient(to);
900
+ const blocks = options.blocks == null ? void 0 : validateSlackBlocksArray(options.blocks);
901
+ if (!normalizedMessage && !options.mediaUrl && !blocks) throw new Error("Slack send requires text, blocks, or media");
902
+ const opts = { ...options };
939
903
  const delivery = resolveSlackDelivery({
940
904
  account,
941
905
  eventScope,
942
- opts: queuedOpts,
943
- recipient
906
+ opts,
907
+ recipient: parsedRecipient
944
908
  });
945
909
  const workspaceScope = delivery.teamId ? `:${delivery.teamId}` : "";
946
- const queueKey = `${account.accountId}:${createSlackTokenCacheKey(delivery.credential)}${workspaceScope}:${delivery.recipient.kind}:${delivery.recipient.id}:${opts.threadTs ?? ""}`;
947
- const result = await slackSendQueue.enqueue(queueKey, () => sendMessageSlackQueued({
948
- trimmedMessage,
949
- opts: queuedOpts,
950
- cfg,
951
- account,
952
- blocks,
953
- delivery
954
- }).catch((err) => {
955
- throw enrichSlackWebApiError(err);
956
- }));
957
- const threadTs = result.threadTs ?? normalizeSlackThreadTsCandidate(queuedOpts.threadTs);
958
- if (threadTs && result.channelId && account.accountId) recordSlackThreadParticipation(account.accountId, result.channelId, threadTs, { teamId: delivery.teamId });
959
- return result;
960
- }
961
- async function sendMessageSlackQueued(params) {
962
- const { opts, cfg, account, blocks, trimmedMessage, delivery } = params;
963
- const { client, identity, recipient, unfurl } = delivery;
964
- if (opts.replyBroadcast && opts.mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
965
- const directUserPostChannelId = !opts.deliveryQueueId && recipient.kind === "user" && !opts.mediaUrl && !opts.threadTs ? recipient.id : void 0;
966
- const channelId = directUserPostChannelId ? directUserPostChannelId : await resolveChannelId(client, recipient, {
967
- accountId: account.accountId,
968
- token: delivery.credential,
969
- ...delivery.dmCacheOwner ? { dmCacheOwner: delivery.dmCacheOwner } : {}
970
- });
971
- const deliveredResults = [];
972
- const reportDelivery = async (result, deliveredBlocks) => {
973
- const slackQuestionActionIds = resolveSlackQuestionActionIds(deliveredBlocks);
974
- const deliveryResult = slackQuestionActionIds.length ? {
975
- ...result,
976
- meta: {
977
- ...result.meta,
978
- slackQuestionActionIds,
979
- [SLACK_QUESTION_FINALIZATION_BLOCKS]: deliveredBlocks.filter((block) => block.type !== "actions")
980
- }
981
- } : result;
982
- deliveredResults.push(deliveryResult);
983
- await opts.onDeliveryResult?.(deliveryResult);
984
- return deliveryResult;
985
- };
986
- let didDispatch = false;
987
- const dispatchOnce = async () => {
988
- if (didDispatch) return;
989
- didDispatch = true;
990
- await opts.onPlatformSendDispatch?.();
991
- };
992
- const explicitNativeDataFallbackBase = Object.hasOwn(opts, "nativeDataFallbackBaseText") ? opts.nativeDataFallbackBaseText?.trim() ?? "" : void 0;
993
- const authoredTextPlacement = opts.authoredTextPlacement ?? "outside-blocks";
994
- const nativeDataFallbackBase = blocks && authoredTextPlacement === "outside-blocks" ? explicitNativeDataFallbackBase ?? trimmedMessage : "";
995
- const hasNativeData = Boolean(blocks && hasSlackNativeDataBlock(blocks));
996
- const textChunkLimit = Math.min(opts.textLimit ?? resolveTextChunkLimit(cfg, "slack", account.accountId, { fallbackLimit: 8e3 }), SLACK_TEXT_LIMIT);
997
- const usesOrderedBlockAccessibility = Boolean(blocks && (hasNativeData || opts.authoredTextPlacement !== void 0));
998
- const orderedBlockDeliveryPlan = blocks && usesOrderedBlockAccessibility ? buildSlackNativeDataDeliveryPlan({
999
- baseText: nativeDataFallbackBase,
1000
- blocks,
1001
- textLimit: textChunkLimit
1002
- }) : void 0;
1003
- const completeBlockFallbackText = blocks ? buildSlackCompleteBlocksFallbackText(blocks) : "";
1004
- const rawBlockAccessibilityText = trimmedMessage ? [trimmedMessage, ...completeBlockFallbackText.includes(trimmedMessage) ? [] : [completeBlockFallbackText]].join("\n\n") : completeBlockFallbackText;
1005
- const blockAccessibilityText = blocks ? orderedBlockDeliveryPlan?.accessibilityText ?? rawBlockAccessibilityText : void 0;
1006
- let pendingBlockFallback = orderedBlockDeliveryPlan?.skipOriginalBlocks ? orderedBlockDeliveryPlan : void 0;
1007
- let lastMessageId = "";
1008
- let deliveredChannelId = channelId;
1009
- let canonicalDeliveredThreadTs;
1010
- let sendIdentity = identity;
1011
- const postPart = async (part) => {
1012
- const posted = await postSlackMessageBestEffort({
1013
- client,
1014
- channelId,
1015
- threadTs: opts.threadTs,
1016
- identity: sendIdentity,
1017
- unfurl,
1018
- ...part
1019
- });
1020
- const { response } = posted;
1021
- sendIdentity = posted.identity;
1022
- lastMessageId = response.ts;
1023
- deliveredChannelId = (typeof response.channel === "string" ? normalizeOptionalString(response.channel) : null) ?? deliveredChannelId;
1024
- const responseThreadTs = resolvePostedMessageThreadTs(response);
1025
- canonicalDeliveredThreadTs ??= responseThreadTs;
1026
- return await reportDelivery(createSlackSendResult(response.ts, deliveredChannelId, part.blocks ? "card" : "text", responseThreadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs)), part.blocks);
1027
- };
1028
- if (blocks && opts.mediaUrl) throw new Error("Slack send does not support blocks with mediaUrl");
1029
- if (blocks) {
1030
- if (pendingBlockFallback) logVerbose("slack send: native data accessibility exceeds hard limit, using text fallback");
1031
- else {
1032
- const accessibilityText = usesOrderedBlockAccessibility ? blockAccessibilityText ?? "Slack could not render this Block Kit message." : truncateSlackText(blockAccessibilityText ?? "", SLACK_TEXT_LIMIT);
1033
- const initialBlockMetadata = withSlackDeliveryMetadata(opts.metadata, {
1034
- queueId: opts.deliveryQueueId,
1035
- channelId,
1036
- threadTs: opts.threadTs,
1037
- partIndex: 0,
1038
- partCount: 1
910
+ const queueKey = `${account.accountId}:${createSlackTokenCacheKey(delivery.credential)}${workspaceScope}:${delivery.recipient.kind}:${delivery.recipient.id}:${options.threadTs ?? ""}`;
911
+ const sent = await slackSendQueue.enqueue(queueKey, async () => {
912
+ try {
913
+ const { client, identity, recipient, unfurl } = delivery;
914
+ if (opts.replyBroadcast && opts.mediaUrl) throw new Error("Slack replyBroadcast is only supported for text or block thread replies.");
915
+ const directUserPostChannelId = !opts.deliveryQueueId && recipient.kind === "user" && !opts.mediaUrl && !opts.threadTs ? recipient.id : void 0;
916
+ const channelId = directUserPostChannelId ? directUserPostChannelId : await resolveChannelId(client, recipient, {
917
+ accountId: account.accountId,
918
+ token: delivery.credential,
919
+ ...delivery.dmCacheOwner ? { dmCacheOwner: delivery.dmCacheOwner } : {}
1039
920
  });
1040
- await dispatchOnce();
1041
- try {
1042
- return await postPart({
1043
- text: accessibilityText,
1044
- replyBroadcast: opts.replyBroadcast,
1045
- blocks,
1046
- metadata: initialBlockMetadata,
1047
- ...usesOrderedBlockAccessibility ? { mrkdwn: false } : {}
921
+ const deliveredResults = [];
922
+ const reportDelivery = async (result, deliveredBlocks) => {
923
+ const slackQuestionActionIds = resolveSlackQuestionActionIds(deliveredBlocks);
924
+ const deliveryResult = slackQuestionActionIds.length ? {
925
+ ...result,
926
+ meta: {
927
+ ...result.meta,
928
+ slackQuestionActionIds,
929
+ [SLACK_QUESTION_FINALIZATION_BLOCKS]: deliveredBlocks
930
+ }
931
+ } : result;
932
+ deliveredResults.push(deliveryResult);
933
+ await opts.onDeliveryResult?.(deliveryResult);
934
+ return deliveryResult;
935
+ };
936
+ let didDispatch = false;
937
+ const dispatchOnce = async () => {
938
+ if (didDispatch) return;
939
+ didDispatch = true;
940
+ await opts.onPlatformSendDispatch?.();
941
+ };
942
+ const explicitNativeDataFallbackBase = Object.hasOwn(opts, "nativeDataFallbackBaseText") ? opts.nativeDataFallbackBaseText?.trim() ?? "" : void 0;
943
+ const authoredTextPlacement = opts.authoredTextPlacement ?? "outside-blocks";
944
+ const nativeDataFallbackBase = blocks && authoredTextPlacement === "outside-blocks" ? explicitNativeDataFallbackBase ?? trimmedMessage : "";
945
+ const hasNativeData = Boolean(blocks && hasSlackNativeDataBlock(blocks));
946
+ const textChunkLimit = Math.min(opts.textLimit ?? resolveTextChunkLimit(cfg, "slack", account.accountId, { fallbackLimit: 8e3 }), SLACK_TEXT_LIMIT);
947
+ const usesOrderedBlockAccessibility = Boolean(blocks && (hasNativeData || opts.authoredTextPlacement !== void 0));
948
+ const orderedBlockDeliveryPlan = blocks && usesOrderedBlockAccessibility ? buildSlackNativeDataDeliveryPlan({
949
+ baseText: nativeDataFallbackBase,
950
+ blocks,
951
+ textLimit: textChunkLimit
952
+ }) : void 0;
953
+ let pendingBlockFallback = orderedBlockDeliveryPlan?.skipOriginalBlocks ? orderedBlockDeliveryPlan : void 0;
954
+ let lastMessageId = "";
955
+ let deliveredChannelId = channelId;
956
+ let canonicalDeliveredThreadTs;
957
+ let sendIdentity = identity;
958
+ const postPart = async (part) => {
959
+ const posted = await postSlackMessageBestEffort({
960
+ client,
961
+ channelId,
962
+ threadTs: opts.threadTs,
963
+ identity: sendIdentity,
964
+ unfurl,
965
+ ...part
966
+ });
967
+ const { response } = posted;
968
+ sendIdentity = posted.identity;
969
+ lastMessageId = response.ts;
970
+ deliveredChannelId = (typeof response.channel === "string" ? normalizeOptionalString(response.channel) : null) ?? deliveredChannelId;
971
+ const responseThreadTs = resolvePostedMessageThreadTs(response);
972
+ canonicalDeliveredThreadTs ??= responseThreadTs;
973
+ return await reportDelivery(createSlackSendResult(response.ts, deliveredChannelId, part.blocks ? "card" : "text", responseThreadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs)), part.blocks);
974
+ };
975
+ if (blocks && opts.mediaUrl) throw new Error("Slack send does not support blocks with mediaUrl");
976
+ if (blocks) {
977
+ if (pendingBlockFallback) logVerbose("slack send: native data accessibility exceeds hard limit, using text fallback");
978
+ else {
979
+ let accessibilityText = orderedBlockDeliveryPlan?.accessibilityText;
980
+ if (accessibilityText === void 0) {
981
+ const fallback = buildSlackCompleteBlocksFallbackText(blocks);
982
+ accessibilityText = truncateSlackText(trimmedMessage ? [trimmedMessage, ...fallback.includes(trimmedMessage) ? [] : [fallback]].join("\n\n") : fallback, SLACK_TEXT_LIMIT);
983
+ }
984
+ const initialBlockMetadata = withSlackDeliveryMetadata(opts.metadata, {
985
+ queueId: opts.deliveryQueueId,
986
+ channelId,
987
+ threadTs: opts.threadTs,
988
+ partIndex: 0,
989
+ partCount: 1
990
+ });
991
+ await dispatchOnce();
992
+ try {
993
+ return await postPart({
994
+ text: accessibilityText,
995
+ replyBroadcast: opts.replyBroadcast,
996
+ blocks,
997
+ metadata: initialBlockMetadata,
998
+ ...usesOrderedBlockAccessibility ? { mrkdwn: false } : {}
999
+ });
1000
+ } catch (error) {
1001
+ if (!hasNativeData || !isSlackInvalidBlocksError(error)) throw error;
1002
+ logVerbose("slack send: native data rejected, delivering complete text fallback");
1003
+ pendingBlockFallback = orderedBlockDeliveryPlan;
1004
+ }
1005
+ }
1006
+ }
1007
+ let messages;
1008
+ if (pendingBlockFallback) messages = pendingBlockFallback.fallbackMessages;
1009
+ else {
1010
+ let resolvedChunks;
1011
+ if (opts.textIsSlackPlainText) resolvedChunks = trimmedMessage ? chunkTextForOutbound(trimmedMessage, textChunkLimit, { preserveWhitespace: true }) : [];
1012
+ else if (opts.textIsSlackMrkdwn) resolvedChunks = resolveTextChunksWithFallback(trimmedMessage, chunkSlackMrkdwnText(trimmedMessage, textChunkLimit));
1013
+ else {
1014
+ const tableMode = resolveMarkdownTableMode({
1015
+ cfg,
1016
+ channel: "slack",
1017
+ ...account.accountId ? { accountId: account.accountId } : {}
1018
+ });
1019
+ const chunkMode = resolveChunkMode(cfg, "slack", account.accountId);
1020
+ const chunks = (chunkMode === "newline" ? chunkMarkdownTextWithMode(trimmedMessage, textChunkLimit, chunkMode) : [trimmedMessage]).flatMap((markdown) => markdownToSlackMrkdwnChunks(markdown, textChunkLimit, { tableMode }));
1021
+ resolvedChunks = resolveTextChunksWithFallback(trimmedMessage, chunks);
1022
+ }
1023
+ const mediaMaxBytes = opts.mediaMaxBytes ?? (typeof account.config.mediaMaxMb === "number" ? account.config.mediaMaxMb * 1024 * 1024 : void 0);
1024
+ let chunksToPost;
1025
+ if (opts.mediaUrl) {
1026
+ const [firstChunk, ...rest] = resolvedChunks;
1027
+ lastMessageId = await uploadSlackFile({
1028
+ client: delivery.upload?.client ?? client,
1029
+ completionClient: client,
1030
+ channelId,
1031
+ mediaUrl: opts.mediaUrl,
1032
+ mediaAccess: opts.mediaAccess,
1033
+ uploadFileName: opts.uploadFileName,
1034
+ uploadTitle: opts.uploadTitle,
1035
+ mediaLocalRoots: opts.mediaLocalRoots,
1036
+ mediaReadFile: opts.mediaReadFile,
1037
+ caption: firstChunk,
1038
+ threadTs: opts.threadTs,
1039
+ maxBytes: mediaMaxBytes,
1040
+ ...opts.forceDocument ? { optimizeImages: false } : {},
1041
+ onPlatformSendDispatch: dispatchOnce,
1042
+ assertDirectAdapterHandoff: opts.assertDirectAdapterHandoff,
1043
+ ...delivery.upload ? { auditContext: delivery.upload.auditContext } : {}
1044
+ });
1045
+ await reportDelivery(createSlackSendResult(lastMessageId, channelId, "media", normalizeSlackThreadTsCandidate(opts.threadTs)));
1046
+ chunksToPost = rest;
1047
+ } else chunksToPost = resolvedChunks.length ? resolvedChunks : [""];
1048
+ messages = chunksToPost.map((text) => opts.textIsSlackPlainText ? {
1049
+ text,
1050
+ mrkdwn: false
1051
+ } : { text });
1052
+ }
1053
+ let questionDelivery;
1054
+ for (const [partIndex, part] of messages.entries()) {
1055
+ const carriesPrimaryMessageOptions = partIndex === 0 && !opts.mediaUrl;
1056
+ const baseMetadata = carriesPrimaryMessageOptions ? opts.metadata : void 0;
1057
+ const metadata = opts.mediaUrl ? baseMetadata : withSlackDeliveryMetadata(baseMetadata, {
1058
+ queueId: opts.deliveryQueueId,
1059
+ channelId,
1060
+ threadTs: opts.threadTs,
1061
+ partIndex,
1062
+ partCount: messages.length
1048
1063
  });
1049
- } catch (error) {
1050
- if (!hasNativeData || !isSlackInvalidBlocksError(error)) throw error;
1051
- logVerbose("slack send: native data rejected, delivering complete text fallback");
1052
- pendingBlockFallback = orderedBlockDeliveryPlan;
1064
+ if (partIndex === 0 && !opts.mediaUrl) await dispatchOnce();
1065
+ const partDelivery = await postPart({
1066
+ ...part,
1067
+ replyBroadcast: carriesPrimaryMessageOptions ? opts.replyBroadcast : void 0,
1068
+ metadata
1069
+ });
1070
+ if (pendingBlockFallback && partDelivery.meta?.slackQuestionActionIds.length) questionDelivery = partDelivery;
1053
1071
  }
1072
+ const deliveredThreadTs = canonicalDeliveredThreadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs);
1073
+ return {
1074
+ messageId: lastMessageId,
1075
+ channelId: deliveredChannelId,
1076
+ threadTs: deliveredThreadTs,
1077
+ ...questionDelivery?.meta ? { meta: {
1078
+ ...questionDelivery.meta,
1079
+ slackQuestionMessageId: questionDelivery.messageId
1080
+ } } : {},
1081
+ receipt: createSlackSendReceiptFromResults(deliveredResults, deliveredThreadTs)
1082
+ };
1083
+ } catch (err) {
1084
+ throw enrichSlackWebApiError(err);
1054
1085
  }
1055
- }
1056
- let messages;
1057
- if (pendingBlockFallback) messages = pendingBlockFallback.fallbackMessages;
1058
- else {
1059
- const resolvedChunks = resolveSlackTextChunks({
1060
- cfg,
1061
- accountId: account.accountId,
1062
- text: trimmedMessage,
1063
- chunkLimit: textChunkLimit,
1064
- ...opts.textIsSlackMrkdwn ? { textIsSlackMrkdwn: true } : {},
1065
- ...opts.textIsSlackPlainText ? { preservePlainText: true } : {}
1066
- });
1067
- const mediaMaxBytes = opts.mediaMaxBytes ?? (typeof account.config.mediaMaxMb === "number" ? account.config.mediaMaxMb * 1024 * 1024 : void 0);
1068
- let chunksToPost;
1069
- if (opts.mediaUrl) {
1070
- const [firstChunk, ...rest] = resolvedChunks;
1071
- lastMessageId = await uploadSlackFile({
1072
- client: delivery.upload?.client ?? client,
1073
- completionClient: client,
1074
- channelId,
1075
- mediaUrl: opts.mediaUrl,
1076
- mediaAccess: opts.mediaAccess,
1077
- uploadFileName: opts.uploadFileName,
1078
- uploadTitle: opts.uploadTitle,
1079
- mediaLocalRoots: opts.mediaLocalRoots,
1080
- mediaReadFile: opts.mediaReadFile,
1081
- caption: firstChunk,
1082
- threadTs: opts.threadTs,
1083
- maxBytes: mediaMaxBytes,
1084
- ...opts.forceDocument ? { optimizeImages: false } : {},
1085
- onPlatformSendDispatch: dispatchOnce,
1086
- assertDirectAdapterHandoff: opts.assertDirectAdapterHandoff,
1087
- ...delivery.upload ? { auditContext: delivery.upload.auditContext } : {}
1088
- });
1089
- await reportDelivery(createSlackSendResult(lastMessageId, channelId, "media", normalizeSlackThreadTsCandidate(opts.threadTs)));
1090
- chunksToPost = rest;
1091
- } else chunksToPost = resolvedChunks.length ? resolvedChunks : [""];
1092
- messages = chunksToPost.map((text) => opts.textIsSlackPlainText ? {
1093
- text,
1094
- mrkdwn: false
1095
- } : { text });
1096
- }
1097
- let questionDelivery;
1098
- for (const [partIndex, part] of messages.entries()) {
1099
- const carriesPrimaryMessageOptions = partIndex === 0 && !opts.mediaUrl;
1100
- const baseMetadata = carriesPrimaryMessageOptions ? opts.metadata : void 0;
1101
- const metadata = opts.mediaUrl ? baseMetadata : withSlackDeliveryMetadata(baseMetadata, {
1102
- queueId: opts.deliveryQueueId,
1103
- channelId,
1104
- threadTs: opts.threadTs,
1105
- partIndex,
1106
- partCount: messages.length
1107
- });
1108
- if (partIndex === 0 && !opts.mediaUrl) await dispatchOnce();
1109
- const partDelivery = await postPart({
1110
- ...part,
1111
- replyBroadcast: carriesPrimaryMessageOptions ? opts.replyBroadcast : void 0,
1112
- metadata
1113
- });
1114
- if (pendingBlockFallback && partDelivery.meta?.slackQuestionActionIds.length) questionDelivery = partDelivery;
1115
- }
1116
- const deliveredThreadTs = canonicalDeliveredThreadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs);
1117
- return {
1118
- messageId: lastMessageId,
1119
- channelId: deliveredChannelId,
1120
- threadTs: deliveredThreadTs,
1121
- ...questionDelivery?.meta ? { meta: {
1122
- ...questionDelivery.meta,
1123
- slackQuestionMessageId: questionDelivery.messageId
1124
- } } : {},
1125
- receipt: createSlackSendReceiptFromResults(deliveredResults, deliveredThreadTs)
1126
- };
1086
+ });
1087
+ const threadTs = sent.threadTs ?? normalizeSlackThreadTsCandidate(opts.threadTs);
1088
+ if (threadTs && sent.channelId && account.accountId) recordSlackThreadParticipation(account.accountId, sent.channelId, threadTs, { teamId: delivery.teamId });
1089
+ return sent;
1127
1090
  }
1128
1091
  //#endregion
1129
- export { clearSlackThreadParticipationCache as a, hasSlackThreadParticipationWithPersistence as c, requireSlackPostMessageTimestamp as d, buildSlackMessageIdentityPayload as f, chunkSlackTextAtHardLimit as h, clearSlackThreadFailureNotice as i, recordSlackThreadFailureNotice as l, buildSlackNativeDataDeliveryPlan as m, send_exports as n, hasSlackThreadFailureNotice as o, hasSlackMessageIdentity as p, setSlackDefaultSendIdentity as r, hasSlackThreadParticipation as s, sendMessageSlack as t, recordSlackThreadParticipation as u };
1092
+ export { clearSlackThreadFailureNotice as a, hasSlackThreadParticipation as c, recordSlackThreadParticipation as d, requireSlackPostMessageTimestamp as f, chunkSlackTextAtHardLimit as g, buildSlackNativeDataDeliveryPlan as h, updateMessageSlack as i, hasSlackThreadParticipationWithPersistence as l, hasSlackMessageIdentity as m, send_exports as n, clearSlackThreadParticipationCache as o, buildSlackMessageIdentityPayload as p, setSlackDefaultSendIdentity as r, hasSlackThreadFailureNotice as s, sendMessageSlack as t, recordSlackThreadFailureNotice as u };