@lark-project/openclaw-lark-project 2026.3.131

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 (368) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/README.zh.md +80 -0
  4. package/dist/index.js +172 -0
  5. package/dist/index.js.map +7 -0
  6. package/dist/skills/feishu-bitable/SKILL.md +248 -0
  7. package/dist/skills/feishu-bitable/references/examples.md +813 -0
  8. package/dist/skills/feishu-bitable/references/field-properties.md +763 -0
  9. package/dist/skills/feishu-bitable/references/record-values.md +911 -0
  10. package/dist/skills/feishu-calendar/SKILL.md +244 -0
  11. package/dist/skills/feishu-channel-rules/SKILL.md +18 -0
  12. package/dist/skills/feishu-channel-rules/references/markdown-syntax.md +138 -0
  13. package/dist/skills/feishu-create-doc/SKILL.md +719 -0
  14. package/dist/skills/feishu-fetch-doc/SKILL.md +93 -0
  15. package/dist/skills/feishu-im-read/SKILL.md +163 -0
  16. package/dist/skills/feishu-project/SKILL.md +122 -0
  17. package/dist/skills/feishu-task/SKILL.md +293 -0
  18. package/dist/skills/feishu-troubleshoot/SKILL.md +70 -0
  19. package/dist/skills/feishu-update-doc/SKILL.md +285 -0
  20. package/dist/src/card/builder.js +293 -0
  21. package/dist/src/card/builder.js.map +7 -0
  22. package/dist/src/card/cardkit.js +126 -0
  23. package/dist/src/card/cardkit.js.map +7 -0
  24. package/dist/src/card/flush-controller.js +107 -0
  25. package/dist/src/card/flush-controller.js.map +7 -0
  26. package/dist/src/card/markdown-style.js +57 -0
  27. package/dist/src/card/markdown-style.js.map +7 -0
  28. package/dist/src/card/reply-dispatcher-types.js +39 -0
  29. package/dist/src/card/reply-dispatcher-types.js.map +7 -0
  30. package/dist/src/card/reply-dispatcher.js +245 -0
  31. package/dist/src/card/reply-dispatcher.js.map +7 -0
  32. package/dist/src/card/reply-mode.js +29 -0
  33. package/dist/src/card/reply-mode.js.map +7 -0
  34. package/dist/src/card/streaming-card-controller.js +653 -0
  35. package/dist/src/card/streaming-card-controller.js.map +7 -0
  36. package/dist/src/card/unavailable-guard.js +76 -0
  37. package/dist/src/card/unavailable-guard.js.map +7 -0
  38. package/dist/src/channel/abort-detect.js +79 -0
  39. package/dist/src/channel/abort-detect.js.map +7 -0
  40. package/dist/src/channel/chat-queue.js +50 -0
  41. package/dist/src/channel/chat-queue.js.map +7 -0
  42. package/dist/src/channel/config-adapter.js +89 -0
  43. package/dist/src/channel/config-adapter.js.map +7 -0
  44. package/dist/src/channel/directory.js +133 -0
  45. package/dist/src/channel/directory.js.map +7 -0
  46. package/dist/src/channel/event-handlers.js +175 -0
  47. package/dist/src/channel/event-handlers.js.map +7 -0
  48. package/dist/src/channel/monitor.js +108 -0
  49. package/dist/src/channel/monitor.js.map +7 -0
  50. package/dist/src/channel/onboarding-config.js +76 -0
  51. package/dist/src/channel/onboarding-config.js.map +7 -0
  52. package/dist/src/channel/onboarding-migrate.js +55 -0
  53. package/dist/src/channel/onboarding-migrate.js.map +7 -0
  54. package/dist/src/channel/onboarding.js +285 -0
  55. package/dist/src/channel/onboarding.js.map +7 -0
  56. package/dist/src/channel/plugin.js +260 -0
  57. package/dist/src/channel/plugin.js.map +7 -0
  58. package/dist/src/channel/probe.js +14 -0
  59. package/dist/src/channel/probe.js.map +7 -0
  60. package/dist/src/channel/types.js +1 -0
  61. package/dist/src/channel/types.js.map +7 -0
  62. package/dist/src/commands/auth.js +73 -0
  63. package/dist/src/commands/auth.js.map +7 -0
  64. package/dist/src/commands/diagnose.js +658 -0
  65. package/dist/src/commands/diagnose.js.map +7 -0
  66. package/dist/src/commands/doctor.js +327 -0
  67. package/dist/src/commands/doctor.js.map +7 -0
  68. package/dist/src/commands/index.js +124 -0
  69. package/dist/src/commands/index.js.map +7 -0
  70. package/dist/src/core/accounts.js +129 -0
  71. package/dist/src/core/accounts.js.map +7 -0
  72. package/dist/src/core/agent-config.js +60 -0
  73. package/dist/src/core/agent-config.js.map +7 -0
  74. package/dist/src/core/api-error.js +55 -0
  75. package/dist/src/core/api-error.js.map +7 -0
  76. package/dist/src/core/app-owner-fallback.js +17 -0
  77. package/dist/src/core/app-owner-fallback.js.map +7 -0
  78. package/dist/src/core/app-scope-checker.js +95 -0
  79. package/dist/src/core/app-scope-checker.js.map +7 -0
  80. package/dist/src/core/auth-errors.js +120 -0
  81. package/dist/src/core/auth-errors.js.map +7 -0
  82. package/dist/src/core/chat-info-cache.js +102 -0
  83. package/dist/src/core/chat-info-cache.js.map +7 -0
  84. package/dist/src/core/config-schema.js +150 -0
  85. package/dist/src/core/config-schema.js.map +7 -0
  86. package/dist/src/core/device-flow.js +174 -0
  87. package/dist/src/core/device-flow.js.map +7 -0
  88. package/dist/src/core/feishu-fetch.js +12 -0
  89. package/dist/src/core/feishu-fetch.js.map +7 -0
  90. package/dist/src/core/footer-config.js +16 -0
  91. package/dist/src/core/footer-config.js.map +7 -0
  92. package/dist/src/core/lark-client.js +322 -0
  93. package/dist/src/core/lark-client.js.map +7 -0
  94. package/dist/src/core/lark-logger.js +92 -0
  95. package/dist/src/core/lark-logger.js.map +7 -0
  96. package/dist/src/core/lark-ticket.js +18 -0
  97. package/dist/src/core/lark-ticket.js.map +7 -0
  98. package/dist/src/core/message-unavailable.js +119 -0
  99. package/dist/src/core/message-unavailable.js.map +7 -0
  100. package/dist/src/core/owner-policy.js +25 -0
  101. package/dist/src/core/owner-policy.js.map +7 -0
  102. package/dist/src/core/permission-url.js +37 -0
  103. package/dist/src/core/permission-url.js.map +7 -0
  104. package/dist/src/core/project-auth.js +177 -0
  105. package/dist/src/core/project-auth.js.map +7 -0
  106. package/dist/src/core/project-oauth-flow.js +124 -0
  107. package/dist/src/core/project-oauth-flow.js.map +7 -0
  108. package/dist/src/core/project-token-store.js +172 -0
  109. package/dist/src/core/project-token-store.js.map +7 -0
  110. package/dist/src/core/raw-request.js +45 -0
  111. package/dist/src/core/raw-request.js.map +7 -0
  112. package/dist/src/core/scope-manager.js +62 -0
  113. package/dist/src/core/scope-manager.js.map +7 -0
  114. package/dist/src/core/security-check.js +118 -0
  115. package/dist/src/core/security-check.js.map +7 -0
  116. package/dist/src/core/shutdown-hooks.js +37 -0
  117. package/dist/src/core/shutdown-hooks.js.map +7 -0
  118. package/dist/src/core/targets.js +55 -0
  119. package/dist/src/core/targets.js.map +7 -0
  120. package/dist/src/core/token-store.js +215 -0
  121. package/dist/src/core/token-store.js.map +7 -0
  122. package/dist/src/core/tool-client.js +335 -0
  123. package/dist/src/core/tool-client.js.map +7 -0
  124. package/dist/src/core/tool-scopes.js +207 -0
  125. package/dist/src/core/tool-scopes.js.map +7 -0
  126. package/dist/src/core/tools-config.js +57 -0
  127. package/dist/src/core/tools-config.js.map +7 -0
  128. package/dist/src/core/types.js +1 -0
  129. package/dist/src/core/types.js.map +7 -0
  130. package/dist/src/core/uat-client.js +124 -0
  131. package/dist/src/core/uat-client.js.map +7 -0
  132. package/dist/src/core/version.js +27 -0
  133. package/dist/src/core/version.js.map +7 -0
  134. package/dist/src/messaging/converters/audio.js +19 -0
  135. package/dist/src/messaging/converters/audio.js.map +7 -0
  136. package/dist/src/messaging/converters/calendar.js +46 -0
  137. package/dist/src/messaging/converters/calendar.js.map +7 -0
  138. package/dist/src/messaging/converters/content-converter.js +61 -0
  139. package/dist/src/messaging/converters/content-converter.js.map +7 -0
  140. package/dist/src/messaging/converters/file.js +18 -0
  141. package/dist/src/messaging/converters/file.js.map +7 -0
  142. package/dist/src/messaging/converters/folder.js +18 -0
  143. package/dist/src/messaging/converters/folder.js.map +7 -0
  144. package/dist/src/messaging/converters/hongbao.js +14 -0
  145. package/dist/src/messaging/converters/hongbao.js.map +7 -0
  146. package/dist/src/messaging/converters/image.js +16 -0
  147. package/dist/src/messaging/converters/image.js.map +7 -0
  148. package/dist/src/messaging/converters/index.js +48 -0
  149. package/dist/src/messaging/converters/index.js.map +7 -0
  150. package/dist/src/messaging/converters/interactive/card-converter.js +1040 -0
  151. package/dist/src/messaging/converters/interactive/card-converter.js.map +7 -0
  152. package/dist/src/messaging/converters/interactive/card-utils.js +36 -0
  153. package/dist/src/messaging/converters/interactive/card-utils.js.map +7 -0
  154. package/dist/src/messaging/converters/interactive/index.js +19 -0
  155. package/dist/src/messaging/converters/interactive/index.js.map +7 -0
  156. package/dist/src/messaging/converters/interactive/legacy.js +53 -0
  157. package/dist/src/messaging/converters/interactive/legacy.js.map +7 -0
  158. package/dist/src/messaging/converters/interactive/types.js +23 -0
  159. package/dist/src/messaging/converters/interactive/types.js.map +7 -0
  160. package/dist/src/messaging/converters/location.js +17 -0
  161. package/dist/src/messaging/converters/location.js.map +7 -0
  162. package/dist/src/messaging/converters/merge-forward.js +143 -0
  163. package/dist/src/messaging/converters/merge-forward.js.map +7 -0
  164. package/dist/src/messaging/converters/post.js +113 -0
  165. package/dist/src/messaging/converters/post.js.map +7 -0
  166. package/dist/src/messaging/converters/share.js +22 -0
  167. package/dist/src/messaging/converters/share.js.map +7 -0
  168. package/dist/src/messaging/converters/sticker.js +16 -0
  169. package/dist/src/messaging/converters/sticker.js.map +7 -0
  170. package/dist/src/messaging/converters/system.js +25 -0
  171. package/dist/src/messaging/converters/system.js.map +7 -0
  172. package/dist/src/messaging/converters/text.js +12 -0
  173. package/dist/src/messaging/converters/text.js.map +7 -0
  174. package/dist/src/messaging/converters/todo.js +37 -0
  175. package/dist/src/messaging/converters/todo.js.map +7 -0
  176. package/dist/src/messaging/converters/types.js +1 -0
  177. package/dist/src/messaging/converters/types.js.map +7 -0
  178. package/dist/src/messaging/converters/unknown.js +13 -0
  179. package/dist/src/messaging/converters/unknown.js.map +7 -0
  180. package/dist/src/messaging/converters/utils.js +35 -0
  181. package/dist/src/messaging/converters/utils.js.map +7 -0
  182. package/dist/src/messaging/converters/video-chat.js +21 -0
  183. package/dist/src/messaging/converters/video-chat.js.map +7 -0
  184. package/dist/src/messaging/converters/video.js +30 -0
  185. package/dist/src/messaging/converters/video.js.map +7 -0
  186. package/dist/src/messaging/converters/vote.js +24 -0
  187. package/dist/src/messaging/converters/vote.js.map +7 -0
  188. package/dist/src/messaging/inbound/dedup.js +82 -0
  189. package/dist/src/messaging/inbound/dedup.js.map +7 -0
  190. package/dist/src/messaging/inbound/dispatch-builders.js +98 -0
  191. package/dist/src/messaging/inbound/dispatch-builders.js.map +7 -0
  192. package/dist/src/messaging/inbound/dispatch-commands.js +94 -0
  193. package/dist/src/messaging/inbound/dispatch-commands.js.map +7 -0
  194. package/dist/src/messaging/inbound/dispatch-context.js +96 -0
  195. package/dist/src/messaging/inbound/dispatch-context.js.map +7 -0
  196. package/dist/src/messaging/inbound/dispatch.js +150 -0
  197. package/dist/src/messaging/inbound/dispatch.js.map +7 -0
  198. package/dist/src/messaging/inbound/enrich.js +137 -0
  199. package/dist/src/messaging/inbound/enrich.js.map +7 -0
  200. package/dist/src/messaging/inbound/gate-effects.js +28 -0
  201. package/dist/src/messaging/inbound/gate-effects.js.map +7 -0
  202. package/dist/src/messaging/inbound/gate.js +163 -0
  203. package/dist/src/messaging/inbound/gate.js.map +7 -0
  204. package/dist/src/messaging/inbound/handler.js +132 -0
  205. package/dist/src/messaging/inbound/handler.js.map +7 -0
  206. package/dist/src/messaging/inbound/media-resolver.js +70 -0
  207. package/dist/src/messaging/inbound/media-resolver.js.map +7 -0
  208. package/dist/src/messaging/inbound/mention.js +50 -0
  209. package/dist/src/messaging/inbound/mention.js.map +7 -0
  210. package/dist/src/messaging/inbound/parse-io.js +41 -0
  211. package/dist/src/messaging/inbound/parse-io.js.map +7 -0
  212. package/dist/src/messaging/inbound/parse.js +79 -0
  213. package/dist/src/messaging/inbound/parse.js.map +7 -0
  214. package/dist/src/messaging/inbound/permission.js +30 -0
  215. package/dist/src/messaging/inbound/permission.js.map +7 -0
  216. package/dist/src/messaging/inbound/policy.js +83 -0
  217. package/dist/src/messaging/inbound/policy.js.map +7 -0
  218. package/dist/src/messaging/inbound/reaction-handler.js +162 -0
  219. package/dist/src/messaging/inbound/reaction-handler.js.map +7 -0
  220. package/dist/src/messaging/inbound/user-name-cache.js +172 -0
  221. package/dist/src/messaging/inbound/user-name-cache.js.map +7 -0
  222. package/dist/src/messaging/outbound/actions.js +239 -0
  223. package/dist/src/messaging/outbound/actions.js.map +7 -0
  224. package/dist/src/messaging/outbound/chat-manage.js +74 -0
  225. package/dist/src/messaging/outbound/chat-manage.js.map +7 -0
  226. package/dist/src/messaging/outbound/deliver.js +162 -0
  227. package/dist/src/messaging/outbound/deliver.js.map +7 -0
  228. package/dist/src/messaging/outbound/fetch.js +7 -0
  229. package/dist/src/messaging/outbound/fetch.js.map +7 -0
  230. package/dist/src/messaging/outbound/forward.js +31 -0
  231. package/dist/src/messaging/outbound/forward.js.map +7 -0
  232. package/dist/src/messaging/outbound/media-url-utils.js +101 -0
  233. package/dist/src/messaging/outbound/media-url-utils.js.map +7 -0
  234. package/dist/src/messaging/outbound/media.js +463 -0
  235. package/dist/src/messaging/outbound/media.js.map +7 -0
  236. package/dist/src/messaging/outbound/outbound.js +95 -0
  237. package/dist/src/messaging/outbound/outbound.js.map +7 -0
  238. package/dist/src/messaging/outbound/reactions.js +312 -0
  239. package/dist/src/messaging/outbound/reactions.js.map +7 -0
  240. package/dist/src/messaging/outbound/send.js +194 -0
  241. package/dist/src/messaging/outbound/send.js.map +7 -0
  242. package/dist/src/messaging/outbound/typing.js +77 -0
  243. package/dist/src/messaging/outbound/typing.js.map +7 -0
  244. package/dist/src/messaging/shared/message-lookup.js +84 -0
  245. package/dist/src/messaging/shared/message-lookup.js.map +7 -0
  246. package/dist/src/messaging/types.js +1 -0
  247. package/dist/src/messaging/types.js.map +7 -0
  248. package/dist/src/tools/auto-auth.js +714 -0
  249. package/dist/src/tools/auto-auth.js.map +7 -0
  250. package/dist/src/tools/helpers.js +133 -0
  251. package/dist/src/tools/helpers.js.map +7 -0
  252. package/dist/src/tools/mcp/doc/create.js +35 -0
  253. package/dist/src/tools/mcp/doc/create.js.map +7 -0
  254. package/dist/src/tools/mcp/doc/fetch.js +33 -0
  255. package/dist/src/tools/mcp/doc/fetch.js.map +7 -0
  256. package/dist/src/tools/mcp/doc/index.js +32 -0
  257. package/dist/src/tools/mcp/doc/index.js.map +7 -0
  258. package/dist/src/tools/mcp/doc/update.js +61 -0
  259. package/dist/src/tools/mcp/doc/update.js.map +7 -0
  260. package/dist/src/tools/mcp/project/endpoint.js +25 -0
  261. package/dist/src/tools/mcp/project/endpoint.js.map +7 -0
  262. package/dist/src/tools/mcp/project/index.js +27 -0
  263. package/dist/src/tools/mcp/project/index.js.map +7 -0
  264. package/dist/src/tools/mcp/project/tools.js +579 -0
  265. package/dist/src/tools/mcp/project/tools.js.map +7 -0
  266. package/dist/src/tools/mcp/shared.js +170 -0
  267. package/dist/src/tools/mcp/shared.js.map +7 -0
  268. package/dist/src/tools/oapi/bitable/app-table-field.js +244 -0
  269. package/dist/src/tools/oapi/bitable/app-table-field.js.map +7 -0
  270. package/dist/src/tools/oapi/bitable/app-table-record.js +501 -0
  271. package/dist/src/tools/oapi/bitable/app-table-record.js.map +7 -0
  272. package/dist/src/tools/oapi/bitable/app-table-view.js +226 -0
  273. package/dist/src/tools/oapi/bitable/app-table-view.js.map +7 -0
  274. package/dist/src/tools/oapi/bitable/app-table.js +278 -0
  275. package/dist/src/tools/oapi/bitable/app-table.js.map +7 -0
  276. package/dist/src/tools/oapi/bitable/app.js +200 -0
  277. package/dist/src/tools/oapi/bitable/app.js.map +7 -0
  278. package/dist/src/tools/oapi/bitable/index.js +13 -0
  279. package/dist/src/tools/oapi/bitable/index.js.map +7 -0
  280. package/dist/src/tools/oapi/calendar/calendar.js +131 -0
  281. package/dist/src/tools/oapi/calendar/calendar.js.map +7 -0
  282. package/dist/src/tools/oapi/calendar/event-attendee.js +301 -0
  283. package/dist/src/tools/oapi/calendar/event-attendee.js.map +7 -0
  284. package/dist/src/tools/oapi/calendar/event.js +834 -0
  285. package/dist/src/tools/oapi/calendar/event.js.map +7 -0
  286. package/dist/src/tools/oapi/calendar/freebusy.js +111 -0
  287. package/dist/src/tools/oapi/calendar/freebusy.js.map +7 -0
  288. package/dist/src/tools/oapi/calendar/index.js +11 -0
  289. package/dist/src/tools/oapi/calendar/index.js.map +7 -0
  290. package/dist/src/tools/oapi/chat/chat.js +132 -0
  291. package/dist/src/tools/oapi/chat/chat.js.map +7 -0
  292. package/dist/src/tools/oapi/chat/index.js +11 -0
  293. package/dist/src/tools/oapi/chat/index.js.map +7 -0
  294. package/dist/src/tools/oapi/chat/members.js +83 -0
  295. package/dist/src/tools/oapi/chat/members.js.map +7 -0
  296. package/dist/src/tools/oapi/common/get-user.js +95 -0
  297. package/dist/src/tools/oapi/common/get-user.js.map +7 -0
  298. package/dist/src/tools/oapi/common/index.js +7 -0
  299. package/dist/src/tools/oapi/common/index.js.map +7 -0
  300. package/dist/src/tools/oapi/common/search-user.js +67 -0
  301. package/dist/src/tools/oapi/common/search-user.js.map +7 -0
  302. package/dist/src/tools/oapi/drive/doc-comments.js +310 -0
  303. package/dist/src/tools/oapi/drive/doc-comments.js.map +7 -0
  304. package/dist/src/tools/oapi/drive/doc-media.js +314 -0
  305. package/dist/src/tools/oapi/drive/doc-media.js.map +7 -0
  306. package/dist/src/tools/oapi/drive/file.js +548 -0
  307. package/dist/src/tools/oapi/drive/file.js.map +7 -0
  308. package/dist/src/tools/oapi/drive/index.js +29 -0
  309. package/dist/src/tools/oapi/drive/index.js.map +7 -0
  310. package/dist/src/tools/oapi/helpers.js +199 -0
  311. package/dist/src/tools/oapi/helpers.js.map +7 -0
  312. package/dist/src/tools/oapi/im/format-messages.js +128 -0
  313. package/dist/src/tools/oapi/im/format-messages.js.map +7 -0
  314. package/dist/src/tools/oapi/im/index.js +15 -0
  315. package/dist/src/tools/oapi/im/index.js.map +7 -0
  316. package/dist/src/tools/oapi/im/message-read.js +404 -0
  317. package/dist/src/tools/oapi/im/message-read.js.map +7 -0
  318. package/dist/src/tools/oapi/im/message.js +179 -0
  319. package/dist/src/tools/oapi/im/message.js.map +7 -0
  320. package/dist/src/tools/oapi/im/resource.js +126 -0
  321. package/dist/src/tools/oapi/im/resource.js.map +7 -0
  322. package/dist/src/tools/oapi/im/time-utils.js +169 -0
  323. package/dist/src/tools/oapi/im/time-utils.js.map +7 -0
  324. package/dist/src/tools/oapi/im/user-name-uat.js +103 -0
  325. package/dist/src/tools/oapi/im/user-name-uat.js.map +7 -0
  326. package/dist/src/tools/oapi/index.js +56 -0
  327. package/dist/src/tools/oapi/index.js.map +7 -0
  328. package/dist/src/tools/oapi/sdk-types.js +1 -0
  329. package/dist/src/tools/oapi/sdk-types.js.map +7 -0
  330. package/dist/src/tools/oapi/search/doc-search.js +215 -0
  331. package/dist/src/tools/oapi/search/doc-search.js.map +7 -0
  332. package/dist/src/tools/oapi/search/index.js +25 -0
  333. package/dist/src/tools/oapi/search/index.js.map +7 -0
  334. package/dist/src/tools/oapi/sheets/index.js +25 -0
  335. package/dist/src/tools/oapi/sheets/index.js.map +7 -0
  336. package/dist/src/tools/oapi/sheets/sheet.js +652 -0
  337. package/dist/src/tools/oapi/sheets/sheet.js.map +7 -0
  338. package/dist/src/tools/oapi/task/comment.js +151 -0
  339. package/dist/src/tools/oapi/task/comment.js.map +7 -0
  340. package/dist/src/tools/oapi/task/index.js +11 -0
  341. package/dist/src/tools/oapi/task/index.js.map +7 -0
  342. package/dist/src/tools/oapi/task/subtask.js +175 -0
  343. package/dist/src/tools/oapi/task/subtask.js.map +7 -0
  344. package/dist/src/tools/oapi/task/task.js +405 -0
  345. package/dist/src/tools/oapi/task/task.js.map +7 -0
  346. package/dist/src/tools/oapi/task/tasklist.js +366 -0
  347. package/dist/src/tools/oapi/task/tasklist.js.map +7 -0
  348. package/dist/src/tools/oapi/wiki/index.js +27 -0
  349. package/dist/src/tools/oapi/wiki/index.js.map +7 -0
  350. package/dist/src/tools/oapi/wiki/space-node.js +311 -0
  351. package/dist/src/tools/oapi/wiki/space-node.js.map +7 -0
  352. package/dist/src/tools/oapi/wiki/space.js +148 -0
  353. package/dist/src/tools/oapi/wiki/space.js.map +7 -0
  354. package/dist/src/tools/oauth-batch-auth.js +125 -0
  355. package/dist/src/tools/oauth-batch-auth.js.map +7 -0
  356. package/dist/src/tools/oauth-cards.js +269 -0
  357. package/dist/src/tools/oauth-cards.js.map +7 -0
  358. package/dist/src/tools/oauth.js +538 -0
  359. package/dist/src/tools/oauth.js.map +7 -0
  360. package/dist/src/tools/onboarding-auth.js +101 -0
  361. package/dist/src/tools/onboarding-auth.js.map +7 -0
  362. package/dist/src/tools/project-oauth.js +305 -0
  363. package/dist/src/tools/project-oauth.js.map +7 -0
  364. package/dist/src/tools/tat/im/index.js +9 -0
  365. package/dist/src/tools/tat/im/index.js.map +7 -0
  366. package/dist/src/tools/tat/im/resource.js +123 -0
  367. package/dist/src/tools/tat/im/resource.js.map +7 -0
  368. package/package.json +64 -0
@@ -0,0 +1,113 @@
1
+ import { resolveMentions } from "./content-converter";
2
+ import { safeParse } from "./utils";
3
+ const LOCALE_PRIORITY = ["zh_cn", "en_us", "ja_jp"];
4
+ function unwrapLocale(parsed) {
5
+ if ("title" in parsed || "content" in parsed) {
6
+ return parsed;
7
+ }
8
+ for (const locale of LOCALE_PRIORITY) {
9
+ const localeData = parsed[locale];
10
+ if (localeData != null && typeof localeData === "object") {
11
+ return localeData;
12
+ }
13
+ }
14
+ const firstKey = Object.keys(parsed)[0];
15
+ if (firstKey) {
16
+ const firstValue = parsed[firstKey];
17
+ if (firstValue != null && typeof firstValue === "object") {
18
+ return firstValue;
19
+ }
20
+ }
21
+ return void 0;
22
+ }
23
+ const convertPost = (raw, ctx) => {
24
+ const rawParsed = safeParse(raw);
25
+ if (rawParsed == null || typeof rawParsed !== "object") {
26
+ return { content: "[rich text message]", resources: [] };
27
+ }
28
+ const parsed = unwrapLocale(rawParsed);
29
+ if (!parsed) {
30
+ return { content: "[rich text message]", resources: [] };
31
+ }
32
+ const resources = [];
33
+ const lines = [];
34
+ if (parsed.title) {
35
+ lines.push(`**${parsed.title}**`, "");
36
+ }
37
+ const contentBlocks = parsed.content ?? [];
38
+ for (const paragraph of contentBlocks) {
39
+ if (!Array.isArray(paragraph)) continue;
40
+ let line = "";
41
+ for (const el of paragraph) {
42
+ line += renderElement(el, ctx, resources);
43
+ }
44
+ lines.push(line);
45
+ }
46
+ let content = lines.join("\n").trim() || "[rich text message]";
47
+ content = resolveMentions(content, ctx);
48
+ return { content, resources };
49
+ };
50
+ function renderElement(el, ctx, resources) {
51
+ switch (el.tag) {
52
+ case "text": {
53
+ let text = el.text ?? "";
54
+ text = applyStyle(text, el.style);
55
+ return text;
56
+ }
57
+ case "a": {
58
+ const text = el.text ?? el.href ?? "";
59
+ return el.href ? `[${text}](${el.href})` : text;
60
+ }
61
+ case "at": {
62
+ const userId = el.user_id ?? "";
63
+ if (userId === "all") return "@all";
64
+ const name = el.user_name ?? userId;
65
+ const info = ctx.mentionsByOpenId.get(userId);
66
+ if (info) {
67
+ return info.key;
68
+ }
69
+ return `@${name}`;
70
+ }
71
+ case "img": {
72
+ if (el.image_key) {
73
+ resources.push({ type: "image", fileKey: el.image_key });
74
+ return `![image](${el.image_key})`;
75
+ }
76
+ return "";
77
+ }
78
+ case "media": {
79
+ if (el.file_key) {
80
+ resources.push({ type: "file", fileKey: el.file_key });
81
+ return `<file key="${el.file_key}"/>`;
82
+ }
83
+ return "";
84
+ }
85
+ case "code_block": {
86
+ const lang = el.language ?? "";
87
+ const code = el.text ?? "";
88
+ return `
89
+ \`\`\`${lang}
90
+ ${code}
91
+ \`\`\`
92
+ `;
93
+ }
94
+ case "hr":
95
+ return "\n---\n";
96
+ default:
97
+ return el.text ?? "";
98
+ }
99
+ }
100
+ function applyStyle(text, style) {
101
+ if (!style || style.length === 0) return text;
102
+ let result = text;
103
+ if (style.includes("bold")) result = `**${result}**`;
104
+ if (style.includes("italic")) result = `*${result}*`;
105
+ if (style.includes("underline")) result = `<u>${result}</u>`;
106
+ if (style.includes("lineThrough")) result = `~~${result}~~`;
107
+ if (style.includes("codeInline")) result = `\`${result}\``;
108
+ return result;
109
+ }
110
+ export {
111
+ convertPost
112
+ };
113
+ //# sourceMappingURL=post.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/post.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Converter for \"post\" (rich text) message type.\n *\n * Preserves structure as Markdown: links as `[text](href)`,\n * images as `![image](key)`, code blocks, and mention resolution.\n */\n\nimport type { ResourceDescriptor } from '../types';\nimport type { ContentConverterFn, ConvertContext, PostElement } from './types';\nimport { resolveMentions } from './content-converter';\nimport { safeParse } from './utils';\n\n/** Preferred locale order for multi-language post unwrapping. */\nconst LOCALE_PRIORITY = ['zh_cn', 'en_us', 'ja_jp'] as const;\n\ninterface PostBody {\n title?: string;\n content?: PostElement[][];\n}\n\n/**\n * Unwrap a parsed post object that may be locale-wrapped.\n *\n * Feishu post messages come in two shapes:\n * - Flat: `{ title, content }`\n * - Locale: `{ zh_cn: { title, content }, en_us: { title, content } }`\n */\nfunction unwrapLocale(parsed: Record<string, unknown>): PostBody | undefined {\n if ('title' in parsed || 'content' in parsed) {\n return parsed as unknown as PostBody;\n }\n\n for (const locale of LOCALE_PRIORITY) {\n const localeData = parsed[locale];\n if (localeData != null && typeof localeData === 'object') {\n return localeData as PostBody;\n }\n }\n\n const firstKey = Object.keys(parsed)[0];\n if (firstKey) {\n const firstValue = parsed[firstKey];\n if (firstValue != null && typeof firstValue === 'object') {\n return firstValue as PostBody;\n }\n }\n\n return undefined;\n}\n\nexport const convertPost: ContentConverterFn = (raw, ctx) => {\n const rawParsed = safeParse(raw);\n if (rawParsed == null || typeof rawParsed !== 'object') {\n return { content: '[rich text message]', resources: [] };\n }\n\n const parsed = unwrapLocale(rawParsed as Record<string, unknown>);\n if (!parsed) {\n return { content: '[rich text message]', resources: [] };\n }\n\n const resources: ResourceDescriptor[] = [];\n const lines: string[] = [];\n\n // Title\n if (parsed.title) {\n lines.push(`**${parsed.title}**`, '');\n }\n\n const contentBlocks = parsed.content ?? [];\n\n for (const paragraph of contentBlocks) {\n if (!Array.isArray(paragraph)) continue;\n\n let line = '';\n for (const el of paragraph) {\n line += renderElement(el, ctx, resources);\n }\n lines.push(line);\n }\n\n let content = lines.join('\\n').trim() || '[rich text message]';\n content = resolveMentions(content, ctx);\n\n return { content, resources };\n};\n\nfunction renderElement(el: PostElement, ctx: ConvertContext, resources: ResourceDescriptor[]): string {\n switch (el.tag) {\n case 'text': {\n let text = el.text ?? '';\n text = applyStyle(text, el.style);\n return text;\n }\n case 'a': {\n const text = el.text ?? el.href ?? '';\n return el.href ? `[${text}](${el.href})` : text;\n }\n case 'at': {\n // At-mention in post \u2014 use placeholder key if available via context,\n // otherwise fall back to @user_name.\n const userId = el.user_id ?? '';\n if (userId === 'all') return '@all';\n const name = el.user_name ?? userId;\n // O(1) lookup via reverse map\n const info = ctx.mentionsByOpenId.get(userId);\n if (info) {\n // Let resolveMentions handle it \u2014 return the placeholder key\n return info.key;\n }\n return `@${name}`;\n }\n case 'img': {\n if (el.image_key) {\n resources.push({ type: 'image', fileKey: el.image_key });\n return `![image](${el.image_key})`;\n }\n return '';\n }\n case 'media': {\n if (el.file_key) {\n resources.push({ type: 'file', fileKey: el.file_key });\n return `<file key=\"${el.file_key}\"/>`;\n }\n return '';\n }\n case 'code_block': {\n const lang = el.language ?? '';\n const code = el.text ?? '';\n return `\\n\\`\\`\\`${lang}\\n${code}\\n\\`\\`\\`\\n`;\n }\n case 'hr':\n return '\\n---\\n';\n default:\n return el.text ?? '';\n }\n}\n\nfunction applyStyle(text: string, style?: string[]): string {\n if (!style || style.length === 0) return text;\n let result = text;\n if (style.includes('bold')) result = `**${result}**`;\n if (style.includes('italic')) result = `*${result}*`;\n if (style.includes('underline')) result = `<u>${result}</u>`;\n if (style.includes('lineThrough')) result = `~~${result}~~`;\n if (style.includes('codeInline')) result = `\\`${result}\\``;\n return result;\n}\n"],
5
+ "mappings": "AAYA,SAAS,uBAAuB;AAChC,SAAS,iBAAiB;AAG1B,MAAM,kBAAkB,CAAC,SAAS,SAAS,OAAO;AAclD,SAAS,aAAa,QAAuD;AAC3E,MAAI,WAAW,UAAU,aAAa,QAAQ;AAC5C,WAAO;AAAA,EACT;AAEA,aAAW,UAAU,iBAAiB;AACpC,UAAM,aAAa,OAAO,MAAM;AAChC,QAAI,cAAc,QAAQ,OAAO,eAAe,UAAU;AACxD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,WAAW,OAAO,KAAK,MAAM,EAAE,CAAC;AACtC,MAAI,UAAU;AACZ,UAAM,aAAa,OAAO,QAAQ;AAClC,QAAI,cAAc,QAAQ,OAAO,eAAe,UAAU;AACxD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAEO,MAAM,cAAkC,CAAC,KAAK,QAAQ;AAC3D,QAAM,YAAY,UAAU,GAAG;AAC/B,MAAI,aAAa,QAAQ,OAAO,cAAc,UAAU;AACtD,WAAO,EAAE,SAAS,uBAAuB,WAAW,CAAC,EAAE;AAAA,EACzD;AAEA,QAAM,SAAS,aAAa,SAAoC;AAChE,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,SAAS,uBAAuB,WAAW,CAAC,EAAE;AAAA,EACzD;AAEA,QAAM,YAAkC,CAAC;AACzC,QAAM,QAAkB,CAAC;AAGzB,MAAI,OAAO,OAAO;AAChB,UAAM,KAAK,KAAK,OAAO,KAAK,MAAM,EAAE;AAAA,EACtC;AAEA,QAAM,gBAAgB,OAAO,WAAW,CAAC;AAEzC,aAAW,aAAa,eAAe;AACrC,QAAI,CAAC,MAAM,QAAQ,SAAS,EAAG;AAE/B,QAAI,OAAO;AACX,eAAW,MAAM,WAAW;AAC1B,cAAQ,cAAc,IAAI,KAAK,SAAS;AAAA,IAC1C;AACA,UAAM,KAAK,IAAI;AAAA,EACjB;AAEA,MAAI,UAAU,MAAM,KAAK,IAAI,EAAE,KAAK,KAAK;AACzC,YAAU,gBAAgB,SAAS,GAAG;AAEtC,SAAO,EAAE,SAAS,UAAU;AAC9B;AAEA,SAAS,cAAc,IAAiB,KAAqB,WAAyC;AACpG,UAAQ,GAAG,KAAK;AAAA,IACd,KAAK,QAAQ;AACX,UAAI,OAAO,GAAG,QAAQ;AACtB,aAAO,WAAW,MAAM,GAAG,KAAK;AAChC,aAAO;AAAA,IACT;AAAA,IACA,KAAK,KAAK;AACR,YAAM,OAAO,GAAG,QAAQ,GAAG,QAAQ;AACnC,aAAO,GAAG,OAAO,IAAI,IAAI,KAAK,GAAG,IAAI,MAAM;AAAA,IAC7C;AAAA,IACA,KAAK,MAAM;AAGT,YAAM,SAAS,GAAG,WAAW;AAC7B,UAAI,WAAW,MAAO,QAAO;AAC7B,YAAM,OAAO,GAAG,aAAa;AAE7B,YAAM,OAAO,IAAI,iBAAiB,IAAI,MAAM;AAC5C,UAAI,MAAM;AAER,eAAO,KAAK;AAAA,MACd;AACA,aAAO,IAAI,IAAI;AAAA,IACjB;AAAA,IACA,KAAK,OAAO;AACV,UAAI,GAAG,WAAW;AAChB,kBAAU,KAAK,EAAE,MAAM,SAAS,SAAS,GAAG,UAAU,CAAC;AACvD,eAAO,YAAY,GAAG,SAAS;AAAA,MACjC;AACA,aAAO;AAAA,IACT;AAAA,IACA,KAAK,SAAS;AACZ,UAAI,GAAG,UAAU;AACf,kBAAU,KAAK,EAAE,MAAM,QAAQ,SAAS,GAAG,SAAS,CAAC;AACrD,eAAO,cAAc,GAAG,QAAQ;AAAA,MAClC;AACA,aAAO;AAAA,IACT;AAAA,IACA,KAAK,cAAc;AACjB,YAAM,OAAO,GAAG,YAAY;AAC5B,YAAM,OAAO,GAAG,QAAQ;AACxB,aAAO;AAAA,QAAW,IAAI;AAAA,EAAK,IAAI;AAAA;AAAA;AAAA,IACjC;AAAA,IACA,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO,GAAG,QAAQ;AAAA,EACtB;AACF;AAEA,SAAS,WAAW,MAAc,OAA0B;AAC1D,MAAI,CAAC,SAAS,MAAM,WAAW,EAAG,QAAO;AACzC,MAAI,SAAS;AACb,MAAI,MAAM,SAAS,MAAM,EAAG,UAAS,KAAK,MAAM;AAChD,MAAI,MAAM,SAAS,QAAQ,EAAG,UAAS,IAAI,MAAM;AACjD,MAAI,MAAM,SAAS,WAAW,EAAG,UAAS,MAAM,MAAM;AACtD,MAAI,MAAM,SAAS,aAAa,EAAG,UAAS,KAAK,MAAM;AACvD,MAAI,MAAM,SAAS,YAAY,EAAG,UAAS,KAAK,MAAM;AACtD,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,22 @@
1
+ import { safeParse } from "./utils";
2
+ const convertShareChat = (raw) => {
3
+ const parsed = safeParse(raw);
4
+ const chatId = parsed?.chat_id ?? "";
5
+ return {
6
+ content: `<group_card id="${chatId}"/>`,
7
+ resources: []
8
+ };
9
+ };
10
+ const convertShareUser = (raw) => {
11
+ const parsed = safeParse(raw);
12
+ const userId = parsed?.user_id ?? "";
13
+ return {
14
+ content: `<contact_card id="${userId}"/>`,
15
+ resources: []
16
+ };
17
+ };
18
+ export {
19
+ convertShareChat,
20
+ convertShareUser
21
+ };
22
+ //# sourceMappingURL=share.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/share.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Converter for \"share_chat\" and \"share_user\" message types.\n */\n\nimport type { ContentConverterFn } from './types';\nimport { safeParse } from './utils';\n\nexport const convertShareChat: ContentConverterFn = (raw) => {\n const parsed = safeParse(raw) as { chat_id?: string } | undefined;\n const chatId = parsed?.chat_id ?? '';\n\n return {\n content: `<group_card id=\"${chatId}\"/>`,\n resources: [],\n };\n};\n\nexport const convertShareUser: ContentConverterFn = (raw) => {\n const parsed = safeParse(raw) as { user_id?: string } | undefined;\n const userId = parsed?.user_id ?? '';\n\n return {\n content: `<contact_card id=\"${userId}\"/>`,\n resources: [],\n };\n};\n"],
5
+ "mappings": "AAQA,SAAS,iBAAiB;AAEnB,MAAM,mBAAuC,CAAC,QAAQ;AAC3D,QAAM,SAAS,UAAU,GAAG;AAC5B,QAAM,SAAS,QAAQ,WAAW;AAElC,SAAO;AAAA,IACL,SAAS,mBAAmB,MAAM;AAAA,IAClC,WAAW,CAAC;AAAA,EACd;AACF;AAEO,MAAM,mBAAuC,CAAC,QAAQ;AAC3D,QAAM,SAAS,UAAU,GAAG;AAC5B,QAAM,SAAS,QAAQ,WAAW;AAElC,SAAO;AAAA,IACL,SAAS,qBAAqB,MAAM;AAAA,IACpC,WAAW,CAAC;AAAA,EACd;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import { safeParse } from "./utils";
2
+ const convertSticker = (raw) => {
3
+ const parsed = safeParse(raw);
4
+ const fileKey = parsed?.file_key;
5
+ if (!fileKey) {
6
+ return { content: "[sticker]", resources: [] };
7
+ }
8
+ return {
9
+ content: `<sticker key="${fileKey}"/>`,
10
+ resources: [{ type: "sticker", fileKey }]
11
+ };
12
+ };
13
+ export {
14
+ convertSticker
15
+ };
16
+ //# sourceMappingURL=sticker.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/sticker.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Converter for \"sticker\" message type.\n */\n\nimport type { ContentConverterFn } from './types';\nimport { safeParse } from './utils';\n\nexport const convertSticker: ContentConverterFn = (raw) => {\n const parsed = safeParse(raw) as { file_key?: string } | undefined;\n const fileKey = parsed?.file_key;\n\n if (!fileKey) {\n return { content: '[sticker]', resources: [] };\n }\n\n return {\n content: `<sticker key=\"${fileKey}\"/>`,\n resources: [{ type: 'sticker', fileKey }],\n };\n};\n"],
5
+ "mappings": "AAQA,SAAS,iBAAiB;AAEnB,MAAM,iBAAqC,CAAC,QAAQ;AACzD,QAAM,SAAS,UAAU,GAAG;AAC5B,QAAM,UAAU,QAAQ;AAExB,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,SAAS,aAAa,WAAW,CAAC,EAAE;AAAA,EAC/C;AAEA,SAAO;AAAA,IACL,SAAS,iBAAiB,OAAO;AAAA,IACjC,WAAW,CAAC,EAAE,MAAM,WAAW,QAAQ,CAAC;AAAA,EAC1C;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,25 @@
1
+ import { safeParse } from "./utils";
2
+ const convertSystem = (raw) => {
3
+ const parsed = safeParse(raw);
4
+ if (!parsed?.template) {
5
+ return { content: "[system message]", resources: [] };
6
+ }
7
+ let content = parsed.template;
8
+ const replacements = {
9
+ "{from_user}": parsed.from_user?.length ? parsed.from_user.filter(Boolean).join(", ") : void 0,
10
+ "{to_chatters}": parsed.to_chatters?.length ? parsed.to_chatters.filter(Boolean).join(", ") : void 0,
11
+ "{divider_text}": parsed.divider_text?.text
12
+ };
13
+ for (const [placeholder, value] of Object.entries(replacements)) {
14
+ if (value != null) {
15
+ content = content.replaceAll(placeholder, value);
16
+ } else {
17
+ content = content.replaceAll(placeholder, "");
18
+ }
19
+ }
20
+ return { content: content.trim(), resources: [] };
21
+ };
22
+ export {
23
+ convertSystem
24
+ };
25
+ //# sourceMappingURL=system.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/system.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Converter for \"system\" message type.\n *\n * System messages use a template string with placeholders like\n * `{from_user}`, `{to_chatters}`, `{divider_text}` that are replaced\n * with actual values from the message body.\n */\n\nimport type { ContentConverterFn } from './types';\nimport { safeParse } from './utils';\n\nexport const convertSystem: ContentConverterFn = (raw) => {\n const parsed = safeParse(raw) as\n | {\n template?: string;\n from_user?: string[];\n to_chatters?: string[];\n divider_text?: { text?: string };\n }\n | undefined;\n\n if (!parsed?.template) {\n return { content: '[system message]', resources: [] };\n }\n\n let content = parsed.template;\n\n const replacements: Record<string, string | undefined> = {\n '{from_user}': parsed.from_user?.length ? parsed.from_user.filter(Boolean).join(', ') : undefined,\n '{to_chatters}': parsed.to_chatters?.length ? parsed.to_chatters.filter(Boolean).join(', ') : undefined,\n '{divider_text}': parsed.divider_text?.text,\n };\n\n for (const [placeholder, value] of Object.entries(replacements)) {\n if (value != null) {\n content = content.replaceAll(placeholder, value);\n } else {\n content = content.replaceAll(placeholder, '');\n }\n }\n\n return { content: content.trim(), resources: [] };\n};\n"],
5
+ "mappings": "AAYA,SAAS,iBAAiB;AAEnB,MAAM,gBAAoC,CAAC,QAAQ;AACxD,QAAM,SAAS,UAAU,GAAG;AAS5B,MAAI,CAAC,QAAQ,UAAU;AACrB,WAAO,EAAE,SAAS,oBAAoB,WAAW,CAAC,EAAE;AAAA,EACtD;AAEA,MAAI,UAAU,OAAO;AAErB,QAAM,eAAmD;AAAA,IACvD,eAAe,OAAO,WAAW,SAAS,OAAO,UAAU,OAAO,OAAO,EAAE,KAAK,IAAI,IAAI;AAAA,IACxF,iBAAiB,OAAO,aAAa,SAAS,OAAO,YAAY,OAAO,OAAO,EAAE,KAAK,IAAI,IAAI;AAAA,IAC9F,kBAAkB,OAAO,cAAc;AAAA,EACzC;AAEA,aAAW,CAAC,aAAa,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AAC/D,QAAI,SAAS,MAAM;AACjB,gBAAU,QAAQ,WAAW,aAAa,KAAK;AAAA,IACjD,OAAO;AACL,gBAAU,QAAQ,WAAW,aAAa,EAAE;AAAA,IAC9C;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,QAAQ,KAAK,GAAG,WAAW,CAAC,EAAE;AAClD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,12 @@
1
+ import { resolveMentions } from "./content-converter";
2
+ import { safeParse } from "./utils";
3
+ const convertText = (raw, ctx) => {
4
+ const parsed = safeParse(raw);
5
+ const text = parsed?.text ?? raw;
6
+ const content = resolveMentions(text, ctx);
7
+ return { content, resources: [] };
8
+ };
9
+ export {
10
+ convertText
11
+ };
12
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/text.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Converter for \"text\" message type.\n */\n\nimport type { ContentConverterFn } from './types';\nimport { resolveMentions } from './content-converter';\nimport { safeParse } from './utils';\n\nexport const convertText: ContentConverterFn = (raw, ctx) => {\n const parsed = safeParse(raw) as { text?: string } | undefined;\n const text = parsed?.text ?? raw;\n const content = resolveMentions(text, ctx);\n return { content, resources: [] };\n};\n"],
5
+ "mappings": "AAQA,SAAS,uBAAuB;AAChC,SAAS,iBAAiB;AAEnB,MAAM,cAAkC,CAAC,KAAK,QAAQ;AAC3D,QAAM,SAAS,UAAU,GAAG;AAC5B,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,UAAU,gBAAgB,MAAM,GAAG;AACzC,SAAO,EAAE,SAAS,WAAW,CAAC,EAAE;AAClC;",
6
+ "names": []
7
+ }
@@ -0,0 +1,37 @@
1
+ import { safeParse, millisToDatetime } from "./utils";
2
+ function extractPlainText(content) {
3
+ const lines = [];
4
+ for (const paragraph of content) {
5
+ if (!Array.isArray(paragraph)) continue;
6
+ let line = "";
7
+ for (const el of paragraph) {
8
+ if (el.text) line += el.text;
9
+ }
10
+ lines.push(line);
11
+ }
12
+ return lines.join("\n").trim();
13
+ }
14
+ const convertTodo = (raw) => {
15
+ const parsed = safeParse(raw);
16
+ const parts = [];
17
+ const title = parsed?.summary?.title ?? "";
18
+ const body = parsed?.summary?.content ? extractPlainText(parsed.summary.content) : "";
19
+ const fullTitle = [title, body].filter(Boolean).join("\n");
20
+ if (fullTitle) {
21
+ parts.push(fullTitle);
22
+ }
23
+ if (parsed?.due_time) {
24
+ parts.push(`Due: ${millisToDatetime(parsed.due_time)}`);
25
+ }
26
+ const inner = parts.join("\n") || "[todo]";
27
+ return {
28
+ content: `<todo>
29
+ ${inner}
30
+ </todo>`,
31
+ resources: []
32
+ };
33
+ };
34
+ export {
35
+ convertTodo
36
+ };
37
+ //# sourceMappingURL=todo.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/todo.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Converter for \"todo\" message type.\n */\n\nimport type { ContentConverterFn, PostElement } from './types';\nimport { safeParse, millisToDatetime } from './utils';\n\n/** Extract plain text from post-style content blocks. */\nfunction extractPlainText(content: PostElement[][]): string {\n const lines: string[] = [];\n for (const paragraph of content) {\n if (!Array.isArray(paragraph)) continue;\n let line = '';\n for (const el of paragraph) {\n if (el.text) line += el.text;\n }\n lines.push(line);\n }\n return lines.join('\\n').trim();\n}\n\nexport const convertTodo: ContentConverterFn = (raw) => {\n const parsed = safeParse(raw) as\n | {\n task_id?: string;\n summary?: {\n title?: string;\n content?: PostElement[][];\n };\n due_time?: string;\n }\n | undefined;\n\n const parts: string[] = [];\n\n // Build title from summary.title and summary.content\n const title = parsed?.summary?.title ?? '';\n const body = parsed?.summary?.content ? extractPlainText(parsed.summary.content) : '';\n\n const fullTitle = [title, body].filter(Boolean).join('\\n');\n if (fullTitle) {\n parts.push(fullTitle);\n }\n\n if (parsed?.due_time) {\n parts.push(`Due: ${millisToDatetime(parsed.due_time)}`);\n }\n\n const inner = parts.join('\\n') || '[todo]';\n\n return {\n content: `<todo>\\n${inner}\\n</todo>`,\n resources: [],\n };\n};\n"],
5
+ "mappings": "AAQA,SAAS,WAAW,wBAAwB;AAG5C,SAAS,iBAAiB,SAAkC;AAC1D,QAAM,QAAkB,CAAC;AACzB,aAAW,aAAa,SAAS;AAC/B,QAAI,CAAC,MAAM,QAAQ,SAAS,EAAG;AAC/B,QAAI,OAAO;AACX,eAAW,MAAM,WAAW;AAC1B,UAAI,GAAG,KAAM,SAAQ,GAAG;AAAA,IAC1B;AACA,UAAM,KAAK,IAAI;AAAA,EACjB;AACA,SAAO,MAAM,KAAK,IAAI,EAAE,KAAK;AAC/B;AAEO,MAAM,cAAkC,CAAC,QAAQ;AACtD,QAAM,SAAS,UAAU,GAAG;AAW5B,QAAM,QAAkB,CAAC;AAGzB,QAAM,QAAQ,QAAQ,SAAS,SAAS;AACxC,QAAM,OAAO,QAAQ,SAAS,UAAU,iBAAiB,OAAO,QAAQ,OAAO,IAAI;AAEnF,QAAM,YAAY,CAAC,OAAO,IAAI,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AACzD,MAAI,WAAW;AACb,UAAM,KAAK,SAAS;AAAA,EACtB;AAEA,MAAI,QAAQ,UAAU;AACpB,UAAM,KAAK,QAAQ,iBAAiB,OAAO,QAAQ,CAAC,EAAE;AAAA,EACxD;AAEA,QAAM,QAAQ,MAAM,KAAK,IAAI,KAAK;AAElC,SAAO;AAAA,IACL,SAAS;AAAA,EAAW,KAAK;AAAA;AAAA,IACzB,WAAW,CAAC;AAAA,EACd;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -0,0 +1,13 @@
1
+ import { safeParse } from "./utils";
2
+ const convertUnknown = (raw) => {
3
+ const parsed = safeParse(raw);
4
+ if (parsed != null && typeof parsed === "object" && "text" in parsed) {
5
+ const text = parsed.text;
6
+ if (typeof text === "string") return { content: text, resources: [] };
7
+ }
8
+ return { content: "[unsupported message]", resources: [] };
9
+ };
10
+ export {
11
+ convertUnknown
12
+ };
13
+ //# sourceMappingURL=unknown.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/unknown.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Fallback converter for unsupported message types.\n */\n\nimport type { ContentConverterFn } from './types';\nimport { safeParse } from './utils';\n\nexport const convertUnknown: ContentConverterFn = (raw) => {\n const parsed = safeParse(raw);\n if (parsed != null && typeof parsed === 'object' && 'text' in parsed) {\n const text = (parsed as Record<string, unknown>).text;\n if (typeof text === 'string') return { content: text, resources: [] };\n }\n return { content: '[unsupported message]', resources: [] };\n};\n"],
5
+ "mappings": "AAQA,SAAS,iBAAiB;AAEnB,MAAM,iBAAqC,CAAC,QAAQ;AACzD,QAAM,SAAS,UAAU,GAAG;AAC5B,MAAI,UAAU,QAAQ,OAAO,WAAW,YAAY,UAAU,QAAQ;AACpE,UAAM,OAAQ,OAAmC;AACjD,QAAI,OAAO,SAAS,SAAU,QAAO,EAAE,SAAS,MAAM,WAAW,CAAC,EAAE;AAAA,EACtE;AACA,SAAO,EAAE,SAAS,yBAAyB,WAAW,CAAC,EAAE;AAC3D;",
6
+ "names": []
7
+ }
@@ -0,0 +1,35 @@
1
+ function escapeRegExp(str) {
2
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3
+ }
4
+ function safeParse(raw) {
5
+ try {
6
+ return JSON.parse(raw);
7
+ } catch {
8
+ return void 0;
9
+ }
10
+ }
11
+ function formatDuration(ms) {
12
+ const seconds = ms / 1e3;
13
+ if (seconds < 1) return `${ms}ms`;
14
+ if (Number.isInteger(seconds)) return `${seconds}s`;
15
+ return `${seconds.toFixed(1)}s`;
16
+ }
17
+ function millisToDatetime(ms) {
18
+ const num = Number(ms);
19
+ if (!Number.isFinite(num)) return String(ms);
20
+ const utc8Offset = 8 * 60 * 60 * 1e3;
21
+ const d = new Date(num + utc8Offset);
22
+ const year = d.getUTCFullYear();
23
+ const month = String(d.getUTCMonth() + 1).padStart(2, "0");
24
+ const day = String(d.getUTCDate()).padStart(2, "0");
25
+ const hour = String(d.getUTCHours()).padStart(2, "0");
26
+ const minute = String(d.getUTCMinutes()).padStart(2, "0");
27
+ return `${year}-${month}-${day} ${hour}:${minute}`;
28
+ }
29
+ export {
30
+ escapeRegExp,
31
+ formatDuration,
32
+ millisToDatetime,
33
+ safeParse
34
+ };
35
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/utils.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Shared utilities for content converters.\n */\n\n/** Escape a string for safe use inside a RegExp. */\nexport function escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Safely parse a JSON string, returning undefined on failure.\n */\nexport function safeParse(raw: string): unknown | undefined {\n try {\n return JSON.parse(raw);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Format a duration in milliseconds to a human-readable string.\n *\n * Examples: 1500 \u2192 \"1.5s\", 65000 \u2192 \"65s\"\n */\nexport function formatDuration(ms: number): string {\n const seconds = ms / 1000;\n if (seconds < 1) return `${ms}ms`;\n if (Number.isInteger(seconds)) return `${seconds}s`;\n return `${seconds.toFixed(1)}s`;\n}\n\n/**\n * Convert a millisecond timestamp to \"YYYY-MM-DD HH:mm\" in UTC+8 (Beijing time).\n */\nexport function millisToDatetime(ms: string | number): string {\n const num = Number(ms);\n if (!Number.isFinite(num)) return String(ms);\n\n // UTC+8 offset in milliseconds\n const utc8Offset = 8 * 60 * 60 * 1000;\n const d = new Date(num + utc8Offset);\n\n const year = d.getUTCFullYear();\n const month = String(d.getUTCMonth() + 1).padStart(2, '0');\n const day = String(d.getUTCDate()).padStart(2, '0');\n const hour = String(d.getUTCHours()).padStart(2, '0');\n const minute = String(d.getUTCMinutes()).padStart(2, '0');\n\n return `${year}-${month}-${day} ${hour}:${minute}`;\n}\n"],
5
+ "mappings": "AAQO,SAAS,aAAa,KAAqB;AAChD,SAAO,IAAI,QAAQ,uBAAuB,MAAM;AAClD;AAKO,SAAS,UAAU,KAAkC;AAC1D,MAAI;AACF,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOO,SAAS,eAAe,IAAoB;AACjD,QAAM,UAAU,KAAK;AACrB,MAAI,UAAU,EAAG,QAAO,GAAG,EAAE;AAC7B,MAAI,OAAO,UAAU,OAAO,EAAG,QAAO,GAAG,OAAO;AAChD,SAAO,GAAG,QAAQ,QAAQ,CAAC,CAAC;AAC9B;AAKO,SAAS,iBAAiB,IAA6B;AAC5D,QAAM,MAAM,OAAO,EAAE;AACrB,MAAI,CAAC,OAAO,SAAS,GAAG,EAAG,QAAO,OAAO,EAAE;AAG3C,QAAM,aAAa,IAAI,KAAK,KAAK;AACjC,QAAM,IAAI,IAAI,KAAK,MAAM,UAAU;AAEnC,QAAM,OAAO,EAAE,eAAe;AAC9B,QAAM,QAAQ,OAAO,EAAE,YAAY,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AACzD,QAAM,MAAM,OAAO,EAAE,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AAClD,QAAM,OAAO,OAAO,EAAE,YAAY,CAAC,EAAE,SAAS,GAAG,GAAG;AACpD,QAAM,SAAS,OAAO,EAAE,cAAc,CAAC,EAAE,SAAS,GAAG,GAAG;AAExD,SAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,IAAI,IAAI,IAAI,MAAM;AAClD;",
6
+ "names": []
7
+ }
@@ -0,0 +1,21 @@
1
+ import { safeParse, millisToDatetime } from "./utils";
2
+ const convertVideoChat = (raw) => {
3
+ const parsed = safeParse(raw);
4
+ const topic = parsed?.topic ?? "";
5
+ const parts = [];
6
+ if (topic) {
7
+ parts.push(`\u{1F4F9} ${topic}`);
8
+ }
9
+ if (parsed?.start_time) {
10
+ parts.push(`\u{1F559} ${millisToDatetime(parsed.start_time)}`);
11
+ }
12
+ const inner = parts.join("\n") || "[video chat]";
13
+ return {
14
+ content: `<meeting>${inner}</meeting>`,
15
+ resources: []
16
+ };
17
+ };
18
+ export {
19
+ convertVideoChat
20
+ };
21
+ //# sourceMappingURL=video-chat.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/video-chat.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Converter for \"video_chat\" message type.\n */\n\nimport type { ContentConverterFn } from './types';\nimport { safeParse, millisToDatetime } from './utils';\n\nexport const convertVideoChat: ContentConverterFn = (raw) => {\n const parsed = safeParse(raw) as\n | {\n topic?: string;\n start_time?: string;\n }\n | undefined;\n\n const topic = parsed?.topic ?? '';\n const parts: string[] = [];\n\n if (topic) {\n parts.push(`\uD83D\uDCF9 ${topic}`);\n }\n\n if (parsed?.start_time) {\n parts.push(`\uD83D\uDD59 ${millisToDatetime(parsed.start_time)}`);\n }\n\n const inner = parts.join('\\n') || '[video chat]';\n\n return {\n content: `<meeting>${inner}</meeting>`,\n resources: [],\n };\n};\n"],
5
+ "mappings": "AAQA,SAAS,WAAW,wBAAwB;AAErC,MAAM,mBAAuC,CAAC,QAAQ;AAC3D,QAAM,SAAS,UAAU,GAAG;AAO5B,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,QAAkB,CAAC;AAEzB,MAAI,OAAO;AACT,UAAM,KAAK,aAAM,KAAK,EAAE;AAAA,EAC1B;AAEA,MAAI,QAAQ,YAAY;AACtB,UAAM,KAAK,aAAM,iBAAiB,OAAO,UAAU,CAAC,EAAE;AAAA,EACxD;AAEA,QAAM,QAAQ,MAAM,KAAK,IAAI,KAAK;AAElC,SAAO;AAAA,IACL,SAAS,YAAY,KAAK;AAAA,IAC1B,WAAW,CAAC;AAAA,EACd;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,30 @@
1
+ import { safeParse } from "./utils";
2
+ import { formatDuration } from "./utils";
3
+ const convertVideo = (raw) => {
4
+ const parsed = safeParse(raw);
5
+ const fileKey = parsed?.file_key;
6
+ if (!fileKey) {
7
+ return { content: "[video]", resources: [] };
8
+ }
9
+ const fileName = parsed?.file_name ?? "";
10
+ const duration = parsed?.duration;
11
+ const coverKey = parsed?.image_key;
12
+ const nameAttr = fileName ? ` name="${fileName}"` : "";
13
+ const durationAttr = duration != null ? ` duration="${formatDuration(duration)}"` : "";
14
+ return {
15
+ content: `<video key="${fileKey}"${nameAttr}${durationAttr}/>`,
16
+ resources: [
17
+ {
18
+ type: "video",
19
+ fileKey,
20
+ fileName: fileName || void 0,
21
+ duration: duration ?? void 0,
22
+ coverImageKey: coverKey ?? void 0
23
+ }
24
+ ]
25
+ };
26
+ };
27
+ export {
28
+ convertVideo
29
+ };
30
+ //# sourceMappingURL=video.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/video.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Converter for \"video\" and \"media\" message types.\n */\n\nimport type { ContentConverterFn } from './types';\nimport { safeParse } from './utils';\nimport { formatDuration } from './utils';\n\nexport const convertVideo: ContentConverterFn = (raw) => {\n const parsed = safeParse(raw) as\n | {\n file_key?: string;\n file_name?: string;\n duration?: number;\n image_key?: string;\n }\n | undefined;\n\n const fileKey = parsed?.file_key;\n if (!fileKey) {\n return { content: '[video]', resources: [] };\n }\n\n const fileName = parsed?.file_name ?? '';\n const duration = parsed?.duration;\n const coverKey = parsed?.image_key;\n\n const nameAttr = fileName ? ` name=\"${fileName}\"` : '';\n const durationAttr = duration != null ? ` duration=\"${formatDuration(duration)}\"` : '';\n\n return {\n content: `<video key=\"${fileKey}\"${nameAttr}${durationAttr}/>`,\n resources: [\n {\n type: 'video',\n fileKey,\n fileName: fileName || undefined,\n duration: duration ?? undefined,\n coverImageKey: coverKey ?? undefined,\n },\n ],\n };\n};\n"],
5
+ "mappings": "AAQA,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAExB,MAAM,eAAmC,CAAC,QAAQ;AACvD,QAAM,SAAS,UAAU,GAAG;AAS5B,QAAM,UAAU,QAAQ;AACxB,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,SAAS,WAAW,WAAW,CAAC,EAAE;AAAA,EAC7C;AAEA,QAAM,WAAW,QAAQ,aAAa;AACtC,QAAM,WAAW,QAAQ;AACzB,QAAM,WAAW,QAAQ;AAEzB,QAAM,WAAW,WAAW,UAAU,QAAQ,MAAM;AACpD,QAAM,eAAe,YAAY,OAAO,cAAc,eAAe,QAAQ,CAAC,MAAM;AAEpF,SAAO;AAAA,IACL,SAAS,eAAe,OAAO,IAAI,QAAQ,GAAG,YAAY;AAAA,IAC1D,WAAW;AAAA,MACT;AAAA,QACE,MAAM;AAAA,QACN;AAAA,QACA,UAAU,YAAY;AAAA,QACtB,UAAU,YAAY;AAAA,QACtB,eAAe,YAAY;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,24 @@
1
+ import { safeParse } from "./utils";
2
+ const convertVote = (raw) => {
3
+ const parsed = safeParse(raw);
4
+ const topic = parsed?.topic ?? "";
5
+ const options = parsed?.options ?? [];
6
+ const parts = [];
7
+ if (topic) {
8
+ parts.push(topic);
9
+ }
10
+ for (const opt of options) {
11
+ parts.push(`\u2022 ${opt}`);
12
+ }
13
+ const inner = parts.join("\n") || "[vote]";
14
+ return {
15
+ content: `<vote>
16
+ ${inner}
17
+ </vote>`,
18
+ resources: []
19
+ };
20
+ };
21
+ export {
22
+ convertVote
23
+ };
24
+ //# sourceMappingURL=vote.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/converters/vote.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * Converter for \"vote\" message type.\n */\n\nimport type { ContentConverterFn } from './types';\nimport { safeParse } from './utils';\n\nexport const convertVote: ContentConverterFn = (raw) => {\n const parsed = safeParse(raw) as\n | {\n topic?: string;\n options?: string[];\n }\n | undefined;\n\n const topic = parsed?.topic ?? '';\n const options = parsed?.options ?? [];\n\n const parts: string[] = [];\n\n if (topic) {\n parts.push(topic);\n }\n\n for (const opt of options) {\n parts.push(`\u2022 ${opt}`);\n }\n\n const inner = parts.join('\\n') || '[vote]';\n\n return {\n content: `<vote>\\n${inner}\\n</vote>`,\n resources: [],\n };\n};\n"],
5
+ "mappings": "AAQA,SAAS,iBAAiB;AAEnB,MAAM,cAAkC,CAAC,QAAQ;AACtD,QAAM,SAAS,UAAU,GAAG;AAO5B,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,UAAU,QAAQ,WAAW,CAAC;AAEpC,QAAM,QAAkB,CAAC;AAEzB,MAAI,OAAO;AACT,UAAM,KAAK,KAAK;AAAA,EAClB;AAEA,aAAW,OAAO,SAAS;AACzB,UAAM,KAAK,UAAK,GAAG,EAAE;AAAA,EACvB;AAEA,QAAM,QAAQ,MAAM,KAAK,IAAI,KAAK;AAElC,SAAO;AAAA,IACL,SAAS;AAAA,EAAW,KAAK;AAAA;AAAA,IACzB,WAAW,CAAC;AAAA,EACd;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,82 @@
1
+ const DEFAULT_TTL_MS = 12 * 60 * 60 * 1e3;
2
+ const DEFAULT_MAX_ENTRIES = 5e3;
3
+ const SWEEP_INTERVAL_MS = 5 * 60 * 1e3;
4
+ const DEFAULT_EXPIRY_MS = 30 * 60 * 1e3;
5
+ function isMessageExpired(createTimeStr, expiryMs = DEFAULT_EXPIRY_MS) {
6
+ if (!createTimeStr) return false;
7
+ const createTime = parseInt(createTimeStr, 10);
8
+ if (Number.isNaN(createTime)) return false;
9
+ return Date.now() - createTime > expiryMs;
10
+ }
11
+ class MessageDedup {
12
+ store = /* @__PURE__ */ new Map();
13
+ ttlMs;
14
+ maxEntries;
15
+ sweepTimer;
16
+ constructor(opts = {}) {
17
+ this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
18
+ this.maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;
19
+ this.sweepTimer = setInterval(() => this.sweep(), SWEEP_INTERVAL_MS);
20
+ this.sweepTimer.unref();
21
+ }
22
+ /**
23
+ * Try to record a message ID.
24
+ *
25
+ * @param id Unique message identifier (e.g. Feishu `message_id`).
26
+ * @param scope Optional scope prefix (e.g. accountId) to namespace IDs.
27
+ * @returns `true` if the message is **new**; `false` if it is a duplicate.
28
+ */
29
+ tryRecord(id, scope) {
30
+ const key = scope ? `${scope}:${id}` : id;
31
+ const now = Date.now();
32
+ const existing = this.store.get(key);
33
+ if (existing !== void 0) {
34
+ if (now - existing < this.ttlMs) {
35
+ return false;
36
+ }
37
+ this.store.delete(key);
38
+ }
39
+ if (this.store.size >= this.maxEntries) {
40
+ const oldest = this.store.keys().next().value;
41
+ if (oldest !== void 0) {
42
+ this.store.delete(oldest);
43
+ }
44
+ }
45
+ this.store.set(key, now);
46
+ return true;
47
+ }
48
+ /** Current number of tracked entries (for diagnostics). */
49
+ get size() {
50
+ return this.store.size;
51
+ }
52
+ /** Remove all entries and stop the periodic sweep. */
53
+ clear() {
54
+ clearInterval(this.sweepTimer);
55
+ this.store.clear();
56
+ }
57
+ /** Stop the periodic sweep timer and clear all tracked entries. */
58
+ dispose() {
59
+ clearInterval(this.sweepTimer);
60
+ this.store.clear();
61
+ }
62
+ // ---------------------------------------------------------------------------
63
+ // Internal
64
+ // ---------------------------------------------------------------------------
65
+ /**
66
+ * Sweep expired entries from the front of the map.
67
+ * Because entries are in insertion order (FIFO), we can stop as soon as
68
+ * we hit one that hasn't expired yet.
69
+ */
70
+ sweep() {
71
+ const now = Date.now();
72
+ for (const [key, ts] of this.store) {
73
+ if (now - ts < this.ttlMs) break;
74
+ this.store.delete(key);
75
+ }
76
+ }
77
+ }
78
+ export {
79
+ MessageDedup,
80
+ isMessageExpired
81
+ };
82
+ //# sourceMappingURL=dedup.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/messaging/inbound/dedup.ts"],
4
+ "sourcesContent": ["/**\n * Copyright (c) 2026 ByteDance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n *\n * FIFO-based message deduplication.\n *\n * Feishu WebSocket connections may redeliver messages on reconnect.\n * This module tracks recently-seen message IDs and filters duplicates.\n *\n * Design choices:\n * - FIFO eviction (not LRU) \u2014 message IDs are write-once/check-once,\n * no hot/cold access pattern. FIFO naturally expires the oldest entry\n * first, which matches the dedup semantics.\n * - ES2015 `Map` preserves insertion order, giving us FIFO for free.\n * - Periodic sweep leverages FIFO ordering: iterate from oldest and\n * `break` at the first non-expired entry \u2192 O(expired), not O(n).\n */\n\nexport interface MessageDedupOpts {\n /** Time-to-live for each entry in milliseconds (default: 5 min). */\n ttlMs?: number;\n /** Maximum number of tracked entries (default: 10 000). */\n maxEntries?: number;\n}\n\nconst DEFAULT_TTL_MS = 12 * 60 * 60 * 1000; // 12 hours\nconst DEFAULT_MAX_ENTRIES = 5_000;\nconst SWEEP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes\n\n// ---------------------------------------------------------------------------\n// Message expiry check\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_EXPIRY_MS = 30 * 60 * 1000; // 30 minutes\n\n/**\n * Check whether a message is too old to process.\n *\n * Feishu message `create_time` is a millisecond Unix timestamp encoded\n * as a string. When a WebSocket reconnects after a long outage, stale\n * messages may be redelivered \u2014 this function lets callers discard them\n * before entering the full handling pipeline.\n */\nexport function isMessageExpired(createTimeStr: string | undefined, expiryMs: number = DEFAULT_EXPIRY_MS): boolean {\n if (!createTimeStr) return false;\n const createTime = parseInt(createTimeStr, 10);\n if (Number.isNaN(createTime)) return false;\n return Date.now() - createTime > expiryMs;\n}\n\n// ---------------------------------------------------------------------------\n// Message deduplication\n// ---------------------------------------------------------------------------\n\nexport class MessageDedup {\n private readonly store = new Map<string, number>();\n private readonly ttlMs: number;\n private readonly maxEntries: number;\n private readonly sweepTimer: ReturnType<typeof setInterval>;\n\n constructor(opts: MessageDedupOpts = {}) {\n this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;\n this.maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;\n\n // Periodic sweep \u2014 relies on FIFO ordering so we can break early.\n this.sweepTimer = setInterval(() => this.sweep(), SWEEP_INTERVAL_MS);\n this.sweepTimer.unref();\n }\n\n /**\n * Try to record a message ID.\n *\n * @param id Unique message identifier (e.g. Feishu `message_id`).\n * @param scope Optional scope prefix (e.g. accountId) to namespace IDs.\n * @returns `true` if the message is **new**; `false` if it is a duplicate.\n */\n tryRecord(id: string, scope?: string): boolean {\n const key = scope ? `${scope}:${id}` : id;\n const now = Date.now();\n\n const existing = this.store.get(key);\n if (existing !== undefined) {\n // Entry exists \u2014 check TTL.\n if (now - existing < this.ttlMs) {\n // Still within TTL \u2192 duplicate.\n return false;\n }\n // Expired \u2014 remove so we can re-insert at the tail (refresh position).\n this.store.delete(key);\n }\n\n // Enforce capacity via FIFO: drop the oldest entry.\n if (this.store.size >= this.maxEntries) {\n const oldest = this.store.keys().next().value;\n if (oldest !== undefined) {\n this.store.delete(oldest);\n }\n }\n\n this.store.set(key, now);\n return true;\n }\n\n /** Current number of tracked entries (for diagnostics). */\n get size(): number {\n return this.store.size;\n }\n\n /** Remove all entries and stop the periodic sweep. */\n clear(): void {\n clearInterval(this.sweepTimer);\n this.store.clear();\n }\n\n /** Stop the periodic sweep timer and clear all tracked entries. */\n dispose(): void {\n clearInterval(this.sweepTimer);\n this.store.clear();\n }\n\n // ---------------------------------------------------------------------------\n // Internal\n // ---------------------------------------------------------------------------\n\n /**\n * Sweep expired entries from the front of the map.\n * Because entries are in insertion order (FIFO), we can stop as soon as\n * we hit one that hasn't expired yet.\n */\n private sweep(): void {\n const now = Date.now();\n for (const [key, ts] of this.store) {\n if (now - ts < this.ttlMs) break;\n this.store.delete(key);\n }\n }\n}\n"],
5
+ "mappings": "AAyBA,MAAM,iBAAiB,KAAK,KAAK,KAAK;AACtC,MAAM,sBAAsB;AAC5B,MAAM,oBAAoB,IAAI,KAAK;AAMnC,MAAM,oBAAoB,KAAK,KAAK;AAU7B,SAAS,iBAAiB,eAAmC,WAAmB,mBAA4B;AACjH,MAAI,CAAC,cAAe,QAAO;AAC3B,QAAM,aAAa,SAAS,eAAe,EAAE;AAC7C,MAAI,OAAO,MAAM,UAAU,EAAG,QAAO;AACrC,SAAO,KAAK,IAAI,IAAI,aAAa;AACnC;AAMO,MAAM,aAAa;AAAA,EACP,QAAQ,oBAAI,IAAoB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,OAAyB,CAAC,GAAG;AACvC,SAAK,QAAQ,KAAK,SAAS;AAC3B,SAAK,aAAa,KAAK,cAAc;AAGrC,SAAK,aAAa,YAAY,MAAM,KAAK,MAAM,GAAG,iBAAiB;AACnE,SAAK,WAAW,MAAM;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,UAAU,IAAY,OAAyB;AAC7C,UAAM,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE,KAAK;AACvC,UAAM,MAAM,KAAK,IAAI;AAErB,UAAM,WAAW,KAAK,MAAM,IAAI,GAAG;AACnC,QAAI,aAAa,QAAW;AAE1B,UAAI,MAAM,WAAW,KAAK,OAAO;AAE/B,eAAO;AAAA,MACT;AAEA,WAAK,MAAM,OAAO,GAAG;AAAA,IACvB;AAGA,QAAI,KAAK,MAAM,QAAQ,KAAK,YAAY;AACtC,YAAM,SAAS,KAAK,MAAM,KAAK,EAAE,KAAK,EAAE;AACxC,UAAI,WAAW,QAAW;AACxB,aAAK,MAAM,OAAO,MAAM;AAAA,MAC1B;AAAA,IACF;AAEA,SAAK,MAAM,IAAI,KAAK,GAAG;AACvB,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,IAAI,OAAe;AACjB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA,EAGA,QAAc;AACZ,kBAAc,KAAK,UAAU;AAC7B,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA,EAGA,UAAgB;AACd,kBAAc,KAAK,UAAU;AAC7B,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,QAAc;AACpB,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO;AAClC,UAAI,MAAM,KAAK,KAAK,MAAO;AAC3B,WAAK,MAAM,OAAO,GAAG;AAAA,IACvB;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }