@gakr-gakr/discord 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. package/account-inspect-api.ts +6 -0
  2. package/action-runtime-api.ts +1 -0
  3. package/api.ts +130 -0
  4. package/autobot.plugin.json +15 -0
  5. package/channel-config-api.ts +1 -0
  6. package/channel-plugin-api.ts +3 -0
  7. package/config-api.ts +4 -0
  8. package/configured-state.ts +6 -0
  9. package/contract-api.ts +21 -0
  10. package/directory-contract-api.ts +4 -0
  11. package/doctor-contract-api.ts +1 -0
  12. package/index.ts +24 -0
  13. package/package.json +79 -0
  14. package/runtime-api.actions.ts +15 -0
  15. package/runtime-api.lookup.ts +22 -0
  16. package/runtime-api.monitor.ts +50 -0
  17. package/runtime-api.send.ts +79 -0
  18. package/runtime-api.threads.ts +31 -0
  19. package/runtime-api.ts +181 -0
  20. package/runtime-setter-api.ts +3 -0
  21. package/secret-contract-api.ts +4 -0
  22. package/security-audit-contract-api.ts +1 -0
  23. package/security-contract-api.ts +4 -0
  24. package/session-key-api.ts +1 -0
  25. package/setup-entry.ts +9 -0
  26. package/setup-plugin-api.ts +3 -0
  27. package/src/account-inspect.ts +131 -0
  28. package/src/accounts.ts +205 -0
  29. package/src/actions/handle-action.guild-admin.ts +421 -0
  30. package/src/actions/handle-action.ts +402 -0
  31. package/src/actions/runtime.guild.ts +446 -0
  32. package/src/actions/runtime.messaging.messages.ts +226 -0
  33. package/src/actions/runtime.messaging.reactions.ts +67 -0
  34. package/src/actions/runtime.messaging.runtime.ts +73 -0
  35. package/src/actions/runtime.messaging.send.ts +336 -0
  36. package/src/actions/runtime.messaging.shared.ts +97 -0
  37. package/src/actions/runtime.messaging.ts +37 -0
  38. package/src/actions/runtime.moderation-shared.ts +48 -0
  39. package/src/actions/runtime.moderation.ts +116 -0
  40. package/src/actions/runtime.presence.ts +117 -0
  41. package/src/actions/runtime.shared.ts +86 -0
  42. package/src/actions/runtime.ts +87 -0
  43. package/src/api.ts +219 -0
  44. package/src/approval-handler.runtime.ts +636 -0
  45. package/src/approval-native.ts +219 -0
  46. package/src/approval-runtime.ts +14 -0
  47. package/src/approval-shared.ts +56 -0
  48. package/src/audit-core.ts +178 -0
  49. package/src/audit.ts +32 -0
  50. package/src/channel-actions.runtime.ts +1 -0
  51. package/src/channel-actions.ts +254 -0
  52. package/src/channel-api.ts +29 -0
  53. package/src/channel.conversation.ts +159 -0
  54. package/src/channel.loaders.ts +50 -0
  55. package/src/channel.runtime.ts +1 -0
  56. package/src/channel.setup.ts +12 -0
  57. package/src/channel.ts +728 -0
  58. package/src/chunk.ts +321 -0
  59. package/src/client.ts +143 -0
  60. package/src/component-custom-id.ts +72 -0
  61. package/src/components-registry.ts +356 -0
  62. package/src/components.builders.ts +410 -0
  63. package/src/components.modal.ts +124 -0
  64. package/src/components.parse.ts +407 -0
  65. package/src/components.ts +54 -0
  66. package/src/components.types.ts +187 -0
  67. package/src/config-schema.ts +6 -0
  68. package/src/config-ui-hints.ts +354 -0
  69. package/src/conversation-identity.ts +58 -0
  70. package/src/delivery-retry.ts +56 -0
  71. package/src/directory-cache.ts +116 -0
  72. package/src/directory-config.ts +58 -0
  73. package/src/directory-live.ts +135 -0
  74. package/src/doctor-contract.ts +477 -0
  75. package/src/doctor-shared.ts +5 -0
  76. package/src/doctor.ts +340 -0
  77. package/src/draft-chunking.ts +43 -0
  78. package/src/draft-stream.ts +162 -0
  79. package/src/error-body.ts +38 -0
  80. package/src/exec-approvals.ts +110 -0
  81. package/src/gateway-logging.ts +67 -0
  82. package/src/group-policy.ts +113 -0
  83. package/src/guilds.ts +29 -0
  84. package/src/inbound-event-delivery.ts +135 -0
  85. package/src/interactive-dispatch.ts +104 -0
  86. package/src/internal/api.commands.ts +51 -0
  87. package/src/internal/api.guild.ts +164 -0
  88. package/src/internal/api.interactions.ts +53 -0
  89. package/src/internal/api.messages.ts +113 -0
  90. package/src/internal/api.reactions.ts +38 -0
  91. package/src/internal/api.ts +61 -0
  92. package/src/internal/api.users.ts +19 -0
  93. package/src/internal/api.webhooks.ts +13 -0
  94. package/src/internal/client.ts +310 -0
  95. package/src/internal/command-deploy.ts +352 -0
  96. package/src/internal/commands.ts +188 -0
  97. package/src/internal/components.base.ts +65 -0
  98. package/src/internal/components.message.ts +279 -0
  99. package/src/internal/components.modal.ts +95 -0
  100. package/src/internal/components.ts +31 -0
  101. package/src/internal/discord.ts +11 -0
  102. package/src/internal/embeds.ts +35 -0
  103. package/src/internal/entity-cache.ts +98 -0
  104. package/src/internal/event-queue.ts +185 -0
  105. package/src/internal/gateway-close-codes.ts +25 -0
  106. package/src/internal/gateway-dispatch.ts +96 -0
  107. package/src/internal/gateway-identify-limiter.ts +26 -0
  108. package/src/internal/gateway-lifecycle.ts +75 -0
  109. package/src/internal/gateway-rate-limit.ts +104 -0
  110. package/src/internal/gateway.ts +479 -0
  111. package/src/internal/interaction-dispatch.ts +162 -0
  112. package/src/internal/interaction-options.ts +98 -0
  113. package/src/internal/interaction-response.ts +53 -0
  114. package/src/internal/interactions.ts +378 -0
  115. package/src/internal/listeners.ts +91 -0
  116. package/src/internal/modal-fields.ts +95 -0
  117. package/src/internal/payload.ts +69 -0
  118. package/src/internal/rest-body.ts +115 -0
  119. package/src/internal/rest-errors.ts +88 -0
  120. package/src/internal/rest-routes.ts +50 -0
  121. package/src/internal/rest-scheduler.ts +557 -0
  122. package/src/internal/rest.ts +322 -0
  123. package/src/internal/schemas.ts +36 -0
  124. package/src/internal/structures.ts +280 -0
  125. package/src/internal/test-builders.test-support.ts +167 -0
  126. package/src/internal/voice.ts +49 -0
  127. package/src/media-detection.ts +28 -0
  128. package/src/mentions.ts +147 -0
  129. package/src/monitor/ack-reactions.ts +70 -0
  130. package/src/monitor/agent-components-auth.ts +7 -0
  131. package/src/monitor/agent-components-context.ts +154 -0
  132. package/src/monitor/agent-components-data.ts +224 -0
  133. package/src/monitor/agent-components-dm-auth.ts +177 -0
  134. package/src/monitor/agent-components-guild-auth.ts +322 -0
  135. package/src/monitor/agent-components-helpers.runtime.ts +3 -0
  136. package/src/monitor/agent-components-helpers.ts +34 -0
  137. package/src/monitor/agent-components-reply.ts +10 -0
  138. package/src/monitor/agent-components.deps.runtime.ts +2 -0
  139. package/src/monitor/agent-components.dispatch.ts +359 -0
  140. package/src/monitor/agent-components.handlers.ts +303 -0
  141. package/src/monitor/agent-components.modal.ts +160 -0
  142. package/src/monitor/agent-components.plugin-interactive.ts +187 -0
  143. package/src/monitor/agent-components.runtime.ts +14 -0
  144. package/src/monitor/agent-components.system-controls.ts +215 -0
  145. package/src/monitor/agent-components.ts +70 -0
  146. package/src/monitor/agent-components.types.ts +58 -0
  147. package/src/monitor/agent-components.wildcard-controls.ts +171 -0
  148. package/src/monitor/allow-list.ts +631 -0
  149. package/src/monitor/auto-presence.ts +356 -0
  150. package/src/monitor/channel-access.ts +102 -0
  151. package/src/monitor/commands.ts +9 -0
  152. package/src/monitor/dm-command-auth.ts +259 -0
  153. package/src/monitor/dm-command-decision.ts +49 -0
  154. package/src/monitor/exec-approvals.ts +161 -0
  155. package/src/monitor/format.ts +45 -0
  156. package/src/monitor/gateway-handle.ts +34 -0
  157. package/src/monitor/gateway-metadata.ts +298 -0
  158. package/src/monitor/gateway-plugin.ts +302 -0
  159. package/src/monitor/gateway-registry.ts +37 -0
  160. package/src/monitor/gateway-supervisor.ts +206 -0
  161. package/src/monitor/inbound-context.ts +95 -0
  162. package/src/monitor/inbound-dedupe.ts +79 -0
  163. package/src/monitor/inbound-job.ts +118 -0
  164. package/src/monitor/listeners.queue.ts +91 -0
  165. package/src/monitor/listeners.reactions.ts +594 -0
  166. package/src/monitor/listeners.ts +150 -0
  167. package/src/monitor/message-channel-info.ts +96 -0
  168. package/src/monitor/message-forwarded.ts +114 -0
  169. package/src/monitor/message-handler.batch-gate.ts +19 -0
  170. package/src/monitor/message-handler.context.ts +492 -0
  171. package/src/monitor/message-handler.dm-preflight.ts +119 -0
  172. package/src/monitor/message-handler.draft-preview.ts +436 -0
  173. package/src/monitor/message-handler.hydration.ts +198 -0
  174. package/src/monitor/message-handler.module-test-helpers.ts +31 -0
  175. package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
  176. package/src/monitor/message-handler.preflight-channel-context.ts +58 -0
  177. package/src/monitor/message-handler.preflight-context.ts +54 -0
  178. package/src/monitor/message-handler.preflight-helpers.ts +164 -0
  179. package/src/monitor/message-handler.preflight-history.ts +23 -0
  180. package/src/monitor/message-handler.preflight-logging.ts +36 -0
  181. package/src/monitor/message-handler.preflight-pluralkit.ts +28 -0
  182. package/src/monitor/message-handler.preflight-runtime.ts +28 -0
  183. package/src/monitor/message-handler.preflight-thread.ts +49 -0
  184. package/src/monitor/message-handler.preflight.ts +822 -0
  185. package/src/monitor/message-handler.preflight.types.ts +115 -0
  186. package/src/monitor/message-handler.process.ts +1033 -0
  187. package/src/monitor/message-handler.routing-preflight.ts +112 -0
  188. package/src/monitor/message-handler.ts +309 -0
  189. package/src/monitor/message-media.ts +536 -0
  190. package/src/monitor/message-run-queue.ts +101 -0
  191. package/src/monitor/message-text.ts +171 -0
  192. package/src/monitor/message-utils.ts +34 -0
  193. package/src/monitor/model-picker-preferences.ts +184 -0
  194. package/src/monitor/model-picker.state.ts +364 -0
  195. package/src/monitor/model-picker.test-utils.ts +26 -0
  196. package/src/monitor/model-picker.ts +38 -0
  197. package/src/monitor/model-picker.view.ts +722 -0
  198. package/src/monitor/native-command-agent-reply.ts +125 -0
  199. package/src/monitor/native-command-arg-ui.ts +233 -0
  200. package/src/monitor/native-command-auth.ts +309 -0
  201. package/src/monitor/native-command-bypass.ts +13 -0
  202. package/src/monitor/native-command-context.ts +109 -0
  203. package/src/monitor/native-command-dispatch.ts +35 -0
  204. package/src/monitor/native-command-model-picker-apply.ts +209 -0
  205. package/src/monitor/native-command-model-picker-interaction.ts +516 -0
  206. package/src/monitor/native-command-model-picker-ui.ts +357 -0
  207. package/src/monitor/native-command-reply.ts +185 -0
  208. package/src/monitor/native-command-route.ts +91 -0
  209. package/src/monitor/native-command-status.ts +76 -0
  210. package/src/monitor/native-command-ui.ts +26 -0
  211. package/src/monitor/native-command-ui.types.ts +20 -0
  212. package/src/monitor/native-command.args.ts +45 -0
  213. package/src/monitor/native-command.options.ts +153 -0
  214. package/src/monitor/native-command.runtime.ts +51 -0
  215. package/src/monitor/native-command.ts +747 -0
  216. package/src/monitor/native-command.types.ts +9 -0
  217. package/src/monitor/native-interaction-channel-context.ts +50 -0
  218. package/src/monitor/preflight-audio.runtime.ts +9 -0
  219. package/src/monitor/preflight-audio.ts +130 -0
  220. package/src/monitor/presence-cache.ts +61 -0
  221. package/src/monitor/presence.ts +50 -0
  222. package/src/monitor/provider-session.runtime.ts +12 -0
  223. package/src/monitor/provider.acp.ts +89 -0
  224. package/src/monitor/provider.allowlist.ts +398 -0
  225. package/src/monitor/provider.cleanup.ts +41 -0
  226. package/src/monitor/provider.commands.ts +129 -0
  227. package/src/monitor/provider.config-log.ts +45 -0
  228. package/src/monitor/provider.deploy-errors.ts +362 -0
  229. package/src/monitor/provider.deploy.ts +221 -0
  230. package/src/monitor/provider.interactions.ts +160 -0
  231. package/src/monitor/provider.lifecycle.ts +562 -0
  232. package/src/monitor/provider.runtime.ts +1 -0
  233. package/src/monitor/provider.startup-log.ts +32 -0
  234. package/src/monitor/provider.startup.ts +323 -0
  235. package/src/monitor/provider.ts +688 -0
  236. package/src/monitor/reply-context.ts +64 -0
  237. package/src/monitor/reply-delivery.ts +216 -0
  238. package/src/monitor/reply-safety.ts +96 -0
  239. package/src/monitor/rest-fetch.ts +97 -0
  240. package/src/monitor/route-resolution.ts +140 -0
  241. package/src/monitor/sender-identity.ts +81 -0
  242. package/src/monitor/startup-status.ts +10 -0
  243. package/src/monitor/status.ts +22 -0
  244. package/src/monitor/system-events.ts +55 -0
  245. package/src/monitor/thread-bindings.config.ts +35 -0
  246. package/src/monitor/thread-bindings.discord-api.ts +310 -0
  247. package/src/monitor/thread-bindings.lifecycle.ts +354 -0
  248. package/src/monitor/thread-bindings.manager.ts +554 -0
  249. package/src/monitor/thread-bindings.messages.ts +6 -0
  250. package/src/monitor/thread-bindings.persona.ts +25 -0
  251. package/src/monitor/thread-bindings.session-adapter.ts +229 -0
  252. package/src/monitor/thread-bindings.session-shared.ts +59 -0
  253. package/src/monitor/thread-bindings.session-updates.ts +35 -0
  254. package/src/monitor/thread-bindings.state.ts +540 -0
  255. package/src/monitor/thread-bindings.ts +48 -0
  256. package/src/monitor/thread-bindings.types.ts +83 -0
  257. package/src/monitor/thread-channel-context.ts +112 -0
  258. package/src/monitor/thread-session-close.ts +63 -0
  259. package/src/monitor/thread-title.ts +181 -0
  260. package/src/monitor/threading.auto-thread.ts +287 -0
  261. package/src/monitor/threading.cache.ts +45 -0
  262. package/src/monitor/threading.starter.ts +288 -0
  263. package/src/monitor/threading.ts +20 -0
  264. package/src/monitor/threading.types.ts +102 -0
  265. package/src/monitor/timeouts.ts +84 -0
  266. package/src/monitor/typing.ts +17 -0
  267. package/src/monitor.gateway.ts +75 -0
  268. package/src/monitor.ts +28 -0
  269. package/src/network-config.ts +79 -0
  270. package/src/normalize.ts +86 -0
  271. package/src/outbound-adapter.ts +327 -0
  272. package/src/outbound-approval.ts +29 -0
  273. package/src/outbound-components.ts +86 -0
  274. package/src/outbound-payload.ts +208 -0
  275. package/src/outbound-send-context.ts +92 -0
  276. package/src/outbound-session-route.ts +72 -0
  277. package/src/pluralkit.ts +58 -0
  278. package/src/preview-streaming.ts +18 -0
  279. package/src/probe.runtime.ts +1 -0
  280. package/src/probe.ts +237 -0
  281. package/src/proxy-fetch.ts +92 -0
  282. package/src/proxy-request-client.ts +21 -0
  283. package/src/recipient-resolution.ts +39 -0
  284. package/src/resolve-allowlist-common.ts +39 -0
  285. package/src/resolve-channels.ts +369 -0
  286. package/src/resolve-users.ts +184 -0
  287. package/src/retry.ts +98 -0
  288. package/src/runtime-api.ts +64 -0
  289. package/src/runtime-config.ts +16 -0
  290. package/src/runtime.ts +23 -0
  291. package/src/secret-config-contract.ts +140 -0
  292. package/src/security-audit.runtime.ts +1 -0
  293. package/src/security-audit.ts +208 -0
  294. package/src/security-contract.ts +47 -0
  295. package/src/security-doctor.ts +20 -0
  296. package/src/security.ts +60 -0
  297. package/src/send-target-parsing.ts +14 -0
  298. package/src/send.channels.ts +139 -0
  299. package/src/send.components.ts +391 -0
  300. package/src/send.emojis-stickers.ts +57 -0
  301. package/src/send.guild.ts +170 -0
  302. package/src/send.message-request.ts +112 -0
  303. package/src/send.messages.ts +229 -0
  304. package/src/send.outbound.ts +459 -0
  305. package/src/send.permissions.ts +283 -0
  306. package/src/send.reactions.ts +155 -0
  307. package/src/send.receipt.ts +69 -0
  308. package/src/send.shared.ts +469 -0
  309. package/src/send.ts +82 -0
  310. package/src/send.types.ts +191 -0
  311. package/src/send.typing.ts +9 -0
  312. package/src/send.voice.ts +140 -0
  313. package/src/send.webhook.ts +137 -0
  314. package/src/session-contract.ts +3 -0
  315. package/src/session-key-normalization.ts +47 -0
  316. package/src/setup-account-state.ts +144 -0
  317. package/src/setup-adapter.ts +14 -0
  318. package/src/setup-core.ts +215 -0
  319. package/src/setup-runtime-helpers.ts +10 -0
  320. package/src/setup-surface.ts +132 -0
  321. package/src/shared-interactive.ts +167 -0
  322. package/src/shared.ts +197 -0
  323. package/src/status-issues.ts +201 -0
  324. package/src/subagent-hooks.ts +232 -0
  325. package/src/target-parsing.ts +70 -0
  326. package/src/target-resolver.ts +129 -0
  327. package/src/targets.ts +12 -0
  328. package/src/token.ts +107 -0
  329. package/src/ui-colors.ts +27 -0
  330. package/src/ui.ts +20 -0
  331. package/src/voice/access.ts +126 -0
  332. package/src/voice/audio.ts +249 -0
  333. package/src/voice/capture-state.ts +120 -0
  334. package/src/voice/command.ts +284 -0
  335. package/src/voice/config.ts +8 -0
  336. package/src/voice/ingress.ts +164 -0
  337. package/src/voice/manager.runtime.ts +14 -0
  338. package/src/voice/manager.ts +1155 -0
  339. package/src/voice/prompt.ts +22 -0
  340. package/src/voice/realtime.ts +1370 -0
  341. package/src/voice/receive-recovery.ts +159 -0
  342. package/src/voice/sanitize.ts +29 -0
  343. package/src/voice/sdk-runtime.ts +14 -0
  344. package/src/voice/segment.ts +160 -0
  345. package/src/voice/session.ts +81 -0
  346. package/src/voice/speaker-context.ts +127 -0
  347. package/src/voice/tts.ts +151 -0
  348. package/src/voice-message.ts +474 -0
  349. package/subagent-hooks-api.ts +27 -0
  350. package/test-api.ts +4 -0
  351. package/thread-binding-api.ts +1 -0
  352. package/timeouts.ts +6 -0
  353. package/tsconfig.json +16 -0
@@ -0,0 +1,150 @@
1
+ import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
2
+ import { danger } from "autobot/plugin-sdk/runtime-env";
3
+ import {
4
+ type Client,
5
+ InteractionCreateListener,
6
+ MessageCreateListener,
7
+ PresenceUpdateListener,
8
+ ThreadUpdateListener,
9
+ } from "../internal/discord.js";
10
+ import { discordEventQueueLog, runDiscordListenerWithSlowLog } from "./listeners.queue.js";
11
+ export { DiscordReactionListener, DiscordReactionRemoveListener } from "./listeners.reactions.js";
12
+ import { setPresence } from "./presence-cache.js";
13
+ import { isThreadArchived } from "./thread-bindings.discord-api.js";
14
+ import { closeDiscordThreadSessions } from "./thread-session-close.js";
15
+
16
+ type Logger = ReturnType<typeof import("autobot/plugin-sdk/runtime-env").createSubsystemLogger>;
17
+
18
+ export type DiscordMessageEvent = Parameters<MessageCreateListener["handle"]>[0];
19
+ export type DiscordInteractionEvent = Parameters<InteractionCreateListener["handle"]>[0];
20
+
21
+ export type DiscordMessageHandler = (
22
+ data: DiscordMessageEvent,
23
+ client: Client,
24
+ options?: { abortSignal?: AbortSignal },
25
+ ) => Promise<void>;
26
+
27
+ export function registerDiscordListener(listeners: Array<object>, listener: object) {
28
+ if (listeners.some((existing) => existing.constructor === listener.constructor)) {
29
+ return false;
30
+ }
31
+ listeners.push(listener);
32
+ return true;
33
+ }
34
+
35
+ export class DiscordMessageListener extends MessageCreateListener {
36
+ constructor(
37
+ private handler: DiscordMessageHandler,
38
+ private logger?: Logger,
39
+ private onEvent?: () => void,
40
+ ) {
41
+ super();
42
+ }
43
+
44
+ async handle(data: DiscordMessageEvent, client: Client) {
45
+ this.onEvent?.();
46
+ // Fire-and-forget: hand off to the handler without blocking gateway dispatch.
47
+ // Per-session ordering is owned by the message run queue.
48
+ void Promise.resolve()
49
+ .then(() => this.handler(data, client))
50
+ .catch((err) => {
51
+ const logger = this.logger ?? discordEventQueueLog;
52
+ logger.error(danger(`discord handler failed: ${String(err)}`));
53
+ });
54
+ }
55
+ }
56
+
57
+ export class DiscordInteractionListener extends InteractionCreateListener {
58
+ constructor(
59
+ private logger?: Logger,
60
+ private onEvent?: () => void,
61
+ ) {
62
+ super();
63
+ }
64
+
65
+ async handle(data: DiscordInteractionEvent, client: Client) {
66
+ this.onEvent?.();
67
+ // Hand off immediately so slash/component handling can wait on session locks
68
+ // or compaction without blocking later gateway events.
69
+ void Promise.resolve()
70
+ .then(() => client.handleInteraction(data as Parameters<Client["handleInteraction"]>[0], {}))
71
+ .catch((err) => {
72
+ const logger = this.logger ?? discordEventQueueLog;
73
+ logger.error(danger(`discord interaction handler failed: ${String(err)}`));
74
+ });
75
+ }
76
+ }
77
+
78
+ type PresenceUpdateEvent = Parameters<PresenceUpdateListener["handle"]>[0];
79
+
80
+ export class DiscordPresenceListener extends PresenceUpdateListener {
81
+ private logger?: Logger;
82
+ private accountId?: string;
83
+
84
+ constructor(params: { logger?: Logger; accountId?: string }) {
85
+ super();
86
+ this.logger = params.logger;
87
+ this.accountId = params.accountId;
88
+ }
89
+
90
+ async handle(data: PresenceUpdateEvent) {
91
+ try {
92
+ const userId =
93
+ "user" in data && data.user && typeof data.user === "object" && "id" in data.user
94
+ ? data.user.id
95
+ : undefined;
96
+ if (!userId) {
97
+ return;
98
+ }
99
+ setPresence(this.accountId, userId, data);
100
+ } catch (err) {
101
+ const logger = this.logger ?? discordEventQueueLog;
102
+ logger.error(danger(`discord presence handler failed: ${String(err)}`));
103
+ }
104
+ }
105
+ }
106
+
107
+ type ThreadUpdateEvent = Parameters<ThreadUpdateListener["handle"]>[0];
108
+
109
+ export class DiscordThreadUpdateListener extends ThreadUpdateListener {
110
+ constructor(
111
+ private cfg: AutoBotConfig,
112
+ private accountId: string,
113
+ private logger?: Logger,
114
+ ) {
115
+ super();
116
+ }
117
+
118
+ async handle(data: ThreadUpdateEvent) {
119
+ await runDiscordListenerWithSlowLog({
120
+ logger: this.logger,
121
+ listener: this.constructor.name,
122
+ event: this.type,
123
+ run: async () => {
124
+ // Discord only fires THREAD_UPDATE when a field actually changes, so
125
+ // `thread_metadata.archived === true` in this payload means the thread
126
+ // just transitioned to the archived state.
127
+ if (!isThreadArchived(data)) {
128
+ return;
129
+ }
130
+ const threadId = "id" in data && typeof data.id === "string" ? data.id : undefined;
131
+ if (!threadId) {
132
+ return;
133
+ }
134
+ const logger = this.logger ?? discordEventQueueLog;
135
+ const count = await closeDiscordThreadSessions({
136
+ cfg: this.cfg,
137
+ accountId: this.accountId,
138
+ threadId,
139
+ });
140
+ if (count > 0) {
141
+ logger.info("Discord thread archived — reset sessions", { threadId, count });
142
+ }
143
+ },
144
+ onError: (err) => {
145
+ const logger = this.logger ?? discordEventQueueLog;
146
+ logger.error(danger(`discord thread-update handler failed: ${String(err)}`));
147
+ },
148
+ });
149
+ }
150
+ }
@@ -0,0 +1,96 @@
1
+ import { logVerbose } from "autobot/plugin-sdk/runtime-env";
2
+ import { normalizeOptionalStringifiedId } from "autobot/plugin-sdk/string-coerce-runtime";
3
+ import type { ChannelType, Message } from "../internal/discord.js";
4
+ import { resolveDiscordChannelInfoSafe } from "./channel-access.js";
5
+
6
+ export type DiscordChannelInfo = {
7
+ type: ChannelType;
8
+ name?: string;
9
+ topic?: string;
10
+ parentId?: string;
11
+ ownerId?: string;
12
+ };
13
+ export type DiscordChannelInfoClient = {
14
+ fetchChannel(channelId: string): Promise<unknown>;
15
+ };
16
+
17
+ type DiscordMessageWithChannelId = Message & {
18
+ channel_id?: unknown;
19
+ rawData?: { channel_id?: unknown };
20
+ };
21
+
22
+ const DISCORD_CHANNEL_INFO_CACHE_TTL_MS = 5 * 60 * 1000;
23
+ const DISCORD_CHANNEL_INFO_NEGATIVE_CACHE_TTL_MS = 30 * 1000;
24
+ const DISCORD_CHANNEL_INFO_CACHE = new Map<
25
+ string,
26
+ { value: DiscordChannelInfo | null; expiresAt: number }
27
+ >();
28
+
29
+ export function resetDiscordChannelInfoCacheForTest() {
30
+ DISCORD_CHANNEL_INFO_CACHE.clear();
31
+ }
32
+
33
+ function normalizeDiscordChannelId(value: unknown): string {
34
+ return normalizeOptionalStringifiedId(value) ?? "";
35
+ }
36
+
37
+ export function resolveDiscordMessageChannelId(params: {
38
+ message: Message;
39
+ eventChannelId?: string | number | null;
40
+ }): string {
41
+ const message = params.message as DiscordMessageWithChannelId;
42
+ return (
43
+ normalizeDiscordChannelId(message.channelId) ||
44
+ normalizeDiscordChannelId(message.channel_id) ||
45
+ normalizeDiscordChannelId(message.rawData?.channel_id) ||
46
+ normalizeDiscordChannelId(params.eventChannelId)
47
+ );
48
+ }
49
+
50
+ export async function resolveDiscordChannelInfo(
51
+ client: DiscordChannelInfoClient,
52
+ channelId: string,
53
+ ): Promise<DiscordChannelInfo | null> {
54
+ const cached = DISCORD_CHANNEL_INFO_CACHE.get(channelId);
55
+ if (cached) {
56
+ if (cached.expiresAt > Date.now()) {
57
+ return cached.value;
58
+ }
59
+ DISCORD_CHANNEL_INFO_CACHE.delete(channelId);
60
+ }
61
+ try {
62
+ const channel = await client.fetchChannel(channelId);
63
+ if (!channel) {
64
+ DISCORD_CHANNEL_INFO_CACHE.set(channelId, {
65
+ value: null,
66
+ expiresAt: Date.now() + DISCORD_CHANNEL_INFO_NEGATIVE_CACHE_TTL_MS,
67
+ });
68
+ return null;
69
+ }
70
+ const channelInfo = resolveDiscordChannelInfoSafe(channel);
71
+ const rawChannel = channel as { type?: ChannelType };
72
+ const type = (channelInfo.type as ChannelType | undefined) ?? rawChannel.type;
73
+ if (type === undefined) {
74
+ return null;
75
+ }
76
+ const payload: DiscordChannelInfo = {
77
+ type,
78
+ name: channelInfo.name,
79
+ topic: channelInfo.topic,
80
+ parentId: channelInfo.parentId,
81
+ ownerId: channelInfo.ownerId,
82
+ };
83
+ DISCORD_CHANNEL_INFO_CACHE.set(channelId, {
84
+ value: payload,
85
+ expiresAt: Date.now() + DISCORD_CHANNEL_INFO_CACHE_TTL_MS,
86
+ });
87
+ return payload;
88
+ } catch (err) {
89
+ logVerbose(`discord: failed to fetch channel ${channelId}: ${String(err)}`);
90
+ DISCORD_CHANNEL_INFO_CACHE.set(channelId, {
91
+ value: null,
92
+ expiresAt: Date.now() + DISCORD_CHANNEL_INFO_NEGATIVE_CACHE_TTL_MS,
93
+ });
94
+ return null;
95
+ }
96
+ }
@@ -0,0 +1,114 @@
1
+ import type { APIAttachment, APIStickerItem } from "discord-api-types/v10";
2
+ import { normalizeOptionalString } from "autobot/plugin-sdk/string-coerce-runtime";
3
+ import type { Message } from "../internal/discord.js";
4
+
5
+ export type DiscordSnapshotAuthor = {
6
+ id?: string | null;
7
+ username?: string | null;
8
+ discriminator?: string | null;
9
+ global_name?: string | null;
10
+ name?: string | null;
11
+ };
12
+
13
+ export type DiscordSnapshotMessage = {
14
+ content?: string | null;
15
+ components?: unknown;
16
+ embeds?: Array<{ description?: string | null; title?: string | null }> | null;
17
+ attachments?: APIAttachment[] | null;
18
+ stickers?: APIStickerItem[] | null;
19
+ sticker_items?: APIStickerItem[] | null;
20
+ author?: DiscordSnapshotAuthor | null;
21
+ };
22
+
23
+ export type DiscordMessageSnapshot = {
24
+ message?: DiscordSnapshotMessage | null;
25
+ };
26
+
27
+ const FORWARD_MESSAGE_REFERENCE_TYPE = 1;
28
+
29
+ export function normalizeDiscordStickerItems(value: unknown): APIStickerItem[] {
30
+ if (!Array.isArray(value)) {
31
+ return [];
32
+ }
33
+ return value.filter(
34
+ (entry): entry is APIStickerItem =>
35
+ Boolean(entry) &&
36
+ typeof entry === "object" &&
37
+ typeof (entry as { id?: unknown }).id === "string" &&
38
+ typeof (entry as { name?: unknown }).name === "string",
39
+ );
40
+ }
41
+
42
+ export function resolveDiscordMessageStickers(message: Message): APIStickerItem[] {
43
+ const stickers = (message as { stickers?: unknown }).stickers;
44
+ const normalized = normalizeDiscordStickerItems(stickers);
45
+ if (normalized.length > 0) {
46
+ return normalized;
47
+ }
48
+ const rawData = (message as { rawData?: { sticker_items?: unknown; stickers?: unknown } })
49
+ .rawData;
50
+ return normalizeDiscordStickerItems(rawData?.sticker_items ?? rawData?.stickers);
51
+ }
52
+
53
+ export function resolveDiscordSnapshotStickers(snapshot: DiscordSnapshotMessage): APIStickerItem[] {
54
+ return normalizeDiscordStickerItems(snapshot.stickers ?? snapshot.sticker_items);
55
+ }
56
+
57
+ export function hasDiscordMessageStickers(message: Message): boolean {
58
+ return resolveDiscordMessageStickers(message).length > 0;
59
+ }
60
+
61
+ export function resolveDiscordMessageSnapshots(message: Message): DiscordMessageSnapshot[] {
62
+ const rawData = (message as { rawData?: { message_snapshots?: unknown } }).rawData;
63
+ return normalizeDiscordMessageSnapshots(
64
+ rawData?.message_snapshots ??
65
+ (message as { message_snapshots?: unknown }).message_snapshots ??
66
+ (message as { messageSnapshots?: unknown }).messageSnapshots,
67
+ );
68
+ }
69
+
70
+ export function normalizeDiscordMessageSnapshots(snapshots: unknown): DiscordMessageSnapshot[] {
71
+ if (!Array.isArray(snapshots)) {
72
+ return [];
73
+ }
74
+ return snapshots.filter(
75
+ (entry): entry is DiscordMessageSnapshot => Boolean(entry) && typeof entry === "object",
76
+ );
77
+ }
78
+
79
+ export function resolveDiscordReferencedForwardMessage(message: Message): Message | null {
80
+ const referenceType = message.messageReference?.type;
81
+ return Number(referenceType) === FORWARD_MESSAGE_REFERENCE_TYPE
82
+ ? message.referencedMessage
83
+ : null;
84
+ }
85
+
86
+ export function resolveDiscordReferencedReplyMessage(message: Message): Message | null {
87
+ const referenceType = message.messageReference?.type;
88
+ return Number(referenceType) === FORWARD_MESSAGE_REFERENCE_TYPE
89
+ ? null
90
+ : (message.referencedMessage ?? null);
91
+ }
92
+
93
+ export function formatDiscordSnapshotAuthor(
94
+ author: DiscordSnapshotAuthor | null | undefined,
95
+ ): string | undefined {
96
+ if (!author) {
97
+ return undefined;
98
+ }
99
+ const globalName = normalizeOptionalString(author.global_name) ?? undefined;
100
+ const username = normalizeOptionalString(author.username) ?? undefined;
101
+ const name = normalizeOptionalString(author.name) ?? undefined;
102
+ const discriminator = normalizeOptionalString(author.discriminator) ?? undefined;
103
+ const base = globalName || username || name;
104
+ if (username && discriminator && discriminator !== "0") {
105
+ return `@${username}#${discriminator}`;
106
+ }
107
+ if (base) {
108
+ return `@${base}`;
109
+ }
110
+ if (author.id) {
111
+ return `@${author.id}`;
112
+ }
113
+ return undefined;
114
+ }
@@ -0,0 +1,19 @@
1
+ import type { ReplyToMode } from "autobot/plugin-sdk/config-contracts";
2
+ import type { ReplyThreadingPolicy } from "autobot/plugin-sdk/reply-reference";
3
+ import { resolveBatchedReplyThreadingPolicy } from "autobot/plugin-sdk/reply-reference";
4
+
5
+ type ReplyThreadingContext = {
6
+ ReplyThreading?: ReplyThreadingPolicy;
7
+ };
8
+
9
+ export function applyImplicitReplyBatchGate(
10
+ ctx: object,
11
+ replyToMode: ReplyToMode,
12
+ isBatched: boolean,
13
+ ) {
14
+ const replyThreading = resolveBatchedReplyThreadingPolicy(replyToMode, isBatched);
15
+ if (!replyThreading) {
16
+ return;
17
+ }
18
+ (ctx as ReplyThreadingContext).ReplyThreading = replyThreading;
19
+ }