@azurioh/discord-kernel 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 (373) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/dist/authz/authorizer.d.ts +45 -0
  4. package/dist/authz/authorizer.d.ts.map +1 -0
  5. package/dist/authz/authorizer.js +31 -0
  6. package/dist/authz/authorizer.js.map +1 -0
  7. package/dist/authz/require-level-guard.d.ts +23 -0
  8. package/dist/authz/require-level-guard.d.ts.map +1 -0
  9. package/dist/authz/require-level-guard.js +37 -0
  10. package/dist/authz/require-level-guard.js.map +1 -0
  11. package/dist/clock.d.ts +13 -0
  12. package/dist/clock.d.ts.map +1 -0
  13. package/dist/clock.js +13 -0
  14. package/dist/clock.js.map +1 -0
  15. package/dist/concurrency/keyed-queue.d.ts +18 -0
  16. package/dist/concurrency/keyed-queue.d.ts.map +1 -0
  17. package/dist/concurrency/keyed-queue.js +37 -0
  18. package/dist/concurrency/keyed-queue.js.map +1 -0
  19. package/dist/concurrency/run-with-concurrency.d.ts +15 -0
  20. package/dist/concurrency/run-with-concurrency.d.ts.map +1 -0
  21. package/dist/concurrency/run-with-concurrency.js +40 -0
  22. package/dist/concurrency/run-with-concurrency.js.map +1 -0
  23. package/dist/config/env.d.ts +17 -0
  24. package/dist/config/env.d.ts.map +1 -0
  25. package/dist/config/env.js +49 -0
  26. package/dist/config/env.js.map +1 -0
  27. package/dist/config/errors.d.ts +14 -0
  28. package/dist/config/errors.d.ts.map +1 -0
  29. package/dist/config/errors.js +25 -0
  30. package/dist/config/errors.js.map +1 -0
  31. package/dist/datetime.d.ts +34 -0
  32. package/dist/datetime.d.ts.map +1 -0
  33. package/dist/datetime.js +188 -0
  34. package/dist/datetime.js.map +1 -0
  35. package/dist/discord/api-errors.d.ts +20 -0
  36. package/dist/discord/api-errors.d.ts.map +1 -0
  37. package/dist/discord/api-errors.js +90 -0
  38. package/dist/discord/api-errors.js.map +1 -0
  39. package/dist/discord/channel-exporter.d.ts +42 -0
  40. package/dist/discord/channel-exporter.d.ts.map +1 -0
  41. package/dist/discord/channel-exporter.js +3 -0
  42. package/dist/discord/channel-exporter.js.map +1 -0
  43. package/dist/discord/command/autocomplete-dispatcher.d.ts +26 -0
  44. package/dist/discord/command/autocomplete-dispatcher.d.ts.map +1 -0
  45. package/dist/discord/command/autocomplete-dispatcher.js +41 -0
  46. package/dist/discord/command/autocomplete-dispatcher.js.map +1 -0
  47. package/dist/discord/command/autocomplete.d.ts +18 -0
  48. package/dist/discord/command/autocomplete.d.ts.map +1 -0
  49. package/dist/discord/command/autocomplete.js +65 -0
  50. package/dist/discord/command/autocomplete.js.map +1 -0
  51. package/dist/discord/command/context.d.ts +33 -0
  52. package/dist/discord/command/context.d.ts.map +1 -0
  53. package/dist/discord/command/context.js +48 -0
  54. package/dist/discord/command/context.js.map +1 -0
  55. package/dist/discord/command/cooldown-guard.d.ts +25 -0
  56. package/dist/discord/command/cooldown-guard.d.ts.map +1 -0
  57. package/dist/discord/command/cooldown-guard.js +60 -0
  58. package/dist/discord/command/cooldown-guard.js.map +1 -0
  59. package/dist/discord/command/create-command.d.ts +100 -0
  60. package/dist/discord/command/create-command.d.ts.map +1 -0
  61. package/dist/discord/command/create-command.js +245 -0
  62. package/dist/discord/command/create-command.js.map +1 -0
  63. package/dist/discord/command/create-context-menu-command.d.ts +51 -0
  64. package/dist/discord/command/create-context-menu-command.d.ts.map +1 -0
  65. package/dist/discord/command/create-context-menu-command.js +128 -0
  66. package/dist/discord/command/create-context-menu-command.js.map +1 -0
  67. package/dist/discord/command/errors.d.ts +19 -0
  68. package/dist/discord/command/errors.d.ts.map +1 -0
  69. package/dist/discord/command/errors.js +27 -0
  70. package/dist/discord/command/errors.js.map +1 -0
  71. package/dist/discord/command/guard.d.ts +30 -0
  72. package/dist/discord/command/guard.d.ts.map +1 -0
  73. package/dist/discord/command/guard.js +34 -0
  74. package/dist/discord/command/guard.js.map +1 -0
  75. package/dist/discord/command/localization.d.ts +9 -0
  76. package/dist/discord/command/localization.d.ts.map +1 -0
  77. package/dist/discord/command/localization.js +13 -0
  78. package/dist/discord/command/localization.js.map +1 -0
  79. package/dist/discord/command/options.d.ts +113 -0
  80. package/dist/discord/command/options.d.ts.map +1 -0
  81. package/dist/discord/command/options.js +509 -0
  82. package/dist/discord/command/options.js.map +1 -0
  83. package/dist/discord/command/permission-guard.d.ts +21 -0
  84. package/dist/discord/command/permission-guard.d.ts.map +1 -0
  85. package/dist/discord/command/permission-guard.js +69 -0
  86. package/dist/discord/command/permission-guard.js.map +1 -0
  87. package/dist/discord/command/router.d.ts +48 -0
  88. package/dist/discord/command/router.d.ts.map +1 -0
  89. package/dist/discord/command/router.js +118 -0
  90. package/dist/discord/command/router.js.map +1 -0
  91. package/dist/discord/command/types.d.ts +51 -0
  92. package/dist/discord/command/types.d.ts.map +1 -0
  93. package/dist/discord/command/types.js +3 -0
  94. package/dist/discord/command/types.js.map +1 -0
  95. package/dist/discord/components/component-router.d.ts +116 -0
  96. package/dist/discord/components/component-router.d.ts.map +1 -0
  97. package/dist/discord/components/component-router.js +123 -0
  98. package/dist/discord/components/component-router.js.map +1 -0
  99. package/dist/discord/components/interactive-message/index.d.ts +3 -0
  100. package/dist/discord/components/interactive-message/index.d.ts.map +1 -0
  101. package/dist/discord/components/interactive-message/index.js +11 -0
  102. package/dist/discord/components/interactive-message/index.js.map +1 -0
  103. package/dist/discord/components/interactive-message/interactive-message-collector.d.ts +195 -0
  104. package/dist/discord/components/interactive-message/interactive-message-collector.d.ts.map +1 -0
  105. package/dist/discord/components/interactive-message/interactive-message-collector.js +151 -0
  106. package/dist/discord/components/interactive-message/interactive-message-collector.js.map +1 -0
  107. package/dist/discord/components/interactive-message/mount-interactive-message.d.ts +30 -0
  108. package/dist/discord/components/interactive-message/mount-interactive-message.d.ts.map +1 -0
  109. package/dist/discord/components/interactive-message/mount-interactive-message.js +44 -0
  110. package/dist/discord/components/interactive-message/mount-interactive-message.js.map +1 -0
  111. package/dist/discord/components/paginator/index.d.ts +5 -0
  112. package/dist/discord/components/paginator/index.d.ts.map +1 -0
  113. package/dist/discord/components/paginator/index.js +15 -0
  114. package/dist/discord/components/paginator/index.js.map +1 -0
  115. package/dist/discord/components/paginator/mount-paginator.d.ts +25 -0
  116. package/dist/discord/components/paginator/mount-paginator.d.ts.map +1 -0
  117. package/dist/discord/components/paginator/mount-paginator.js +41 -0
  118. package/dist/discord/components/paginator/mount-paginator.js.map +1 -0
  119. package/dist/discord/components/paginator/page-state.d.ts +21 -0
  120. package/dist/discord/components/paginator/page-state.d.ts.map +1 -0
  121. package/dist/discord/components/paginator/page-state.js +44 -0
  122. package/dist/discord/components/paginator/page-state.js.map +1 -0
  123. package/dist/discord/components/paginator/paginator-buttons.d.ts +17 -0
  124. package/dist/discord/components/paginator/paginator-buttons.d.ts.map +1 -0
  125. package/dist/discord/components/paginator/paginator-buttons.js +45 -0
  126. package/dist/discord/components/paginator/paginator-buttons.js.map +1 -0
  127. package/dist/discord/components/paginator/paginator-view.d.ts +26 -0
  128. package/dist/discord/components/paginator/paginator-view.d.ts.map +1 -0
  129. package/dist/discord/components/paginator/paginator-view.js +28 -0
  130. package/dist/discord/components/paginator/paginator-view.js.map +1 -0
  131. package/dist/discord/components/persistent-paginator.d.ts +47 -0
  132. package/dist/discord/components/persistent-paginator.d.ts.map +1 -0
  133. package/dist/discord/components/persistent-paginator.js +137 -0
  134. package/dist/discord/components/persistent-paginator.js.map +1 -0
  135. package/dist/discord/components/settings-editor/index.d.ts +7 -0
  136. package/dist/discord/components/settings-editor/index.d.ts.map +1 -0
  137. package/dist/discord/components/settings-editor/index.js +22 -0
  138. package/dist/discord/components/settings-editor/index.js.map +1 -0
  139. package/dist/discord/components/settings-editor/mount-settings-editor.d.ts +140 -0
  140. package/dist/discord/components/settings-editor/mount-settings-editor.d.ts.map +1 -0
  141. package/dist/discord/components/settings-editor/mount-settings-editor.js +344 -0
  142. package/dist/discord/components/settings-editor/mount-settings-editor.js.map +1 -0
  143. package/dist/discord/components/settings-editor/navigation.d.ts +49 -0
  144. package/dist/discord/components/settings-editor/navigation.d.ts.map +1 -0
  145. package/dist/discord/components/settings-editor/navigation.js +39 -0
  146. package/dist/discord/components/settings-editor/navigation.js.map +1 -0
  147. package/dist/discord/components/settings-editor/settings-editor-card.view.d.ts +56 -0
  148. package/dist/discord/components/settings-editor/settings-editor-card.view.d.ts.map +1 -0
  149. package/dist/discord/components/settings-editor/settings-editor-card.view.js +284 -0
  150. package/dist/discord/components/settings-editor/settings-editor-card.view.js.map +1 -0
  151. package/dist/discord/components/settings-editor/settings-editor-field-modal.d.ts +69 -0
  152. package/dist/discord/components/settings-editor/settings-editor-field-modal.d.ts.map +1 -0
  153. package/dist/discord/components/settings-editor/settings-editor-field-modal.js +353 -0
  154. package/dist/discord/components/settings-editor/settings-editor-field-modal.js.map +1 -0
  155. package/dist/discord/components/settings-editor/settings-editor-fields.d.ts +216 -0
  156. package/dist/discord/components/settings-editor/settings-editor-fields.d.ts.map +1 -0
  157. package/dist/discord/components/settings-editor/settings-editor-fields.js +66 -0
  158. package/dist/discord/components/settings-editor/settings-editor-fields.js.map +1 -0
  159. package/dist/discord/components/settings-editor/settings-editor.view.d.ts +303 -0
  160. package/dist/discord/components/settings-editor/settings-editor.view.d.ts.map +1 -0
  161. package/dist/discord/components/settings-editor/settings-editor.view.js +316 -0
  162. package/dist/discord/components/settings-editor/settings-editor.view.js.map +1 -0
  163. package/dist/discord/events/create-event.d.ts +5 -0
  164. package/dist/discord/events/create-event.d.ts.map +1 -0
  165. package/dist/discord/events/create-event.js +8 -0
  166. package/dist/discord/events/create-event.js.map +1 -0
  167. package/dist/discord/events/event-router.d.ts +16 -0
  168. package/dist/discord/events/event-router.d.ts.map +1 -0
  169. package/dist/discord/events/event-router.js +51 -0
  170. package/dist/discord/events/event-router.js.map +1 -0
  171. package/dist/discord/events/types.d.ts +16 -0
  172. package/dist/discord/events/types.d.ts.map +1 -0
  173. package/dist/discord/events/types.js +3 -0
  174. package/dist/discord/events/types.js.map +1 -0
  175. package/dist/discord/i18n.d.ts +58 -0
  176. package/dist/discord/i18n.d.ts.map +1 -0
  177. package/dist/discord/i18n.js +173 -0
  178. package/dist/discord/i18n.js.map +1 -0
  179. package/dist/discord/interaction/button.d.ts +39 -0
  180. package/dist/discord/interaction/button.d.ts.map +1 -0
  181. package/dist/discord/interaction/button.js +36 -0
  182. package/dist/discord/interaction/button.js.map +1 -0
  183. package/dist/discord/interaction/interaction-router.d.ts +21 -0
  184. package/dist/discord/interaction/interaction-router.d.ts.map +1 -0
  185. package/dist/discord/interaction/interaction-router.js +24 -0
  186. package/dist/discord/interaction/interaction-router.js.map +1 -0
  187. package/dist/discord/interaction/modal.d.ts +171 -0
  188. package/dist/discord/interaction/modal.d.ts.map +1 -0
  189. package/dist/discord/interaction/modal.js +264 -0
  190. package/dist/discord/interaction/modal.js.map +1 -0
  191. package/dist/discord/interaction/select-menu.d.ts +104 -0
  192. package/dist/discord/interaction/select-menu.d.ts.map +1 -0
  193. package/dist/discord/interaction/select-menu.js +126 -0
  194. package/dist/discord/interaction/select-menu.js.map +1 -0
  195. package/dist/discord/permissions.d.ts +32 -0
  196. package/dist/discord/permissions.d.ts.map +1 -0
  197. package/dist/discord/permissions.js +40 -0
  198. package/dist/discord/permissions.js.map +1 -0
  199. package/dist/discord/placeholder-registry-errors.d.ts +10 -0
  200. package/dist/discord/placeholder-registry-errors.d.ts.map +1 -0
  201. package/dist/discord/placeholder-registry-errors.js +18 -0
  202. package/dist/discord/placeholder-registry-errors.js.map +1 -0
  203. package/dist/discord/placeholder-registry.d.ts +53 -0
  204. package/dist/discord/placeholder-registry.d.ts.map +1 -0
  205. package/dist/discord/placeholder-registry.js +52 -0
  206. package/dist/discord/placeholder-registry.js.map +1 -0
  207. package/dist/discord/presenter.d.ts +26 -0
  208. package/dist/discord/presenter.d.ts.map +1 -0
  209. package/dist/discord/presenter.js +3 -0
  210. package/dist/discord/presenter.js.map +1 -0
  211. package/dist/discord/ui/card.d.ts +114 -0
  212. package/dist/discord/ui/card.d.ts.map +1 -0
  213. package/dist/discord/ui/card.js +162 -0
  214. package/dist/discord/ui/card.js.map +1 -0
  215. package/dist/discord/ui/color-input-errors.d.ts +12 -0
  216. package/dist/discord/ui/color-input-errors.d.ts.map +1 -0
  217. package/dist/discord/ui/color-input-errors.js +21 -0
  218. package/dist/discord/ui/color-input-errors.js.map +1 -0
  219. package/dist/discord/ui/color-input.d.ts +37 -0
  220. package/dist/discord/ui/color-input.d.ts.map +1 -0
  221. package/dist/discord/ui/color-input.js +166 -0
  222. package/dist/discord/ui/color-input.js.map +1 -0
  223. package/dist/discord/ui/colors.d.ts +44 -0
  224. package/dist/discord/ui/colors.d.ts.map +1 -0
  225. package/dist/discord/ui/colors.js +45 -0
  226. package/dist/discord/ui/colors.js.map +1 -0
  227. package/dist/discord/ui/embed.d.ts +16 -0
  228. package/dist/discord/ui/embed.d.ts.map +1 -0
  229. package/dist/discord/ui/embed.js +53 -0
  230. package/dist/discord/ui/embed.js.map +1 -0
  231. package/dist/discord/ui/message-attachments.d.ts +40 -0
  232. package/dist/discord/ui/message-attachments.d.ts.map +1 -0
  233. package/dist/discord/ui/message-attachments.js +27 -0
  234. package/dist/discord/ui/message-attachments.js.map +1 -0
  235. package/dist/errors/business-error.d.ts +41 -0
  236. package/dist/errors/business-error.d.ts.map +1 -0
  237. package/dist/errors/business-error.js +39 -0
  238. package/dist/errors/business-error.js.map +1 -0
  239. package/dist/errors/describe-error.d.ts +29 -0
  240. package/dist/errors/describe-error.d.ts.map +1 -0
  241. package/dist/errors/describe-error.js +49 -0
  242. package/dist/errors/describe-error.js.map +1 -0
  243. package/dist/errors/incident-ref.d.ts +7 -0
  244. package/dist/errors/incident-ref.d.ts.map +1 -0
  245. package/dist/errors/incident-ref.js +13 -0
  246. package/dist/errors/incident-ref.js.map +1 -0
  247. package/dist/errors/index.d.ts +4 -0
  248. package/dist/errors/index.d.ts.map +1 -0
  249. package/dist/errors/index.js +15 -0
  250. package/dist/errors/index.js.map +1 -0
  251. package/dist/i18n/business-message.d.ts +14 -0
  252. package/dist/i18n/business-message.d.ts.map +1 -0
  253. package/dist/i18n/business-message.js +19 -0
  254. package/dist/i18n/business-message.js.map +1 -0
  255. package/dist/i18n/catalog.d.ts +27 -0
  256. package/dist/i18n/catalog.d.ts.map +1 -0
  257. package/dist/i18n/catalog.js +25 -0
  258. package/dist/i18n/catalog.js.map +1 -0
  259. package/dist/i18n/errors.d.ts +10 -0
  260. package/dist/i18n/errors.d.ts.map +1 -0
  261. package/dist/i18n/errors.js +18 -0
  262. package/dist/i18n/errors.js.map +1 -0
  263. package/dist/i18n/index.d.ts +6 -0
  264. package/dist/i18n/index.d.ts.map +1 -0
  265. package/dist/i18n/index.js +16 -0
  266. package/dist/i18n/index.js.map +1 -0
  267. package/dist/i18n/locale.d.ts +22 -0
  268. package/dist/i18n/locale.d.ts.map +1 -0
  269. package/dist/i18n/locale.js +40 -0
  270. package/dist/i18n/locale.js.map +1 -0
  271. package/dist/i18n/translator.d.ts +35 -0
  272. package/dist/i18n/translator.d.ts.map +1 -0
  273. package/dist/i18n/translator.js +40 -0
  274. package/dist/i18n/translator.js.map +1 -0
  275. package/dist/logger.d.ts +28 -0
  276. package/dist/logger.d.ts.map +1 -0
  277. package/dist/logger.js +3 -0
  278. package/dist/logger.js.map +1 -0
  279. package/dist/module/module.d.ts +42 -0
  280. package/dist/module/module.d.ts.map +1 -0
  281. package/dist/module/module.js +3 -0
  282. package/dist/module/module.js.map +1 -0
  283. package/dist/persistence/database.d.ts +24 -0
  284. package/dist/persistence/database.d.ts.map +1 -0
  285. package/dist/persistence/database.js +3 -0
  286. package/dist/persistence/database.js.map +1 -0
  287. package/dist/resilience/retry.d.ts +36 -0
  288. package/dist/resilience/retry.d.ts.map +1 -0
  289. package/dist/resilience/retry.js +78 -0
  290. package/dist/resilience/retry.js.map +1 -0
  291. package/dist/scheduler/errors.d.ts +25 -0
  292. package/dist/scheduler/errors.d.ts.map +1 -0
  293. package/dist/scheduler/errors.js +45 -0
  294. package/dist/scheduler/errors.js.map +1 -0
  295. package/dist/scheduler/scheduler.d.ts +68 -0
  296. package/dist/scheduler/scheduler.d.ts.map +1 -0
  297. package/dist/scheduler/scheduler.js +162 -0
  298. package/dist/scheduler/scheduler.js.map +1 -0
  299. package/package.json +89 -0
  300. package/src/authz/authorizer.ts +76 -0
  301. package/src/authz/require-level-guard.ts +42 -0
  302. package/src/clock.ts +18 -0
  303. package/src/concurrency/keyed-queue.ts +50 -0
  304. package/src/concurrency/run-with-concurrency.ts +44 -0
  305. package/src/config/env.ts +58 -0
  306. package/src/config/errors.ts +21 -0
  307. package/src/datetime.ts +221 -0
  308. package/src/discord/api-errors.ts +91 -0
  309. package/src/discord/channel-exporter.ts +48 -0
  310. package/src/discord/command/autocomplete-dispatcher.ts +54 -0
  311. package/src/discord/command/autocomplete.ts +76 -0
  312. package/src/discord/command/context.ts +85 -0
  313. package/src/discord/command/cooldown-guard.ts +81 -0
  314. package/src/discord/command/create-command.ts +431 -0
  315. package/src/discord/command/create-context-menu-command.ts +227 -0
  316. package/src/discord/command/errors.ts +22 -0
  317. package/src/discord/command/guard.ts +54 -0
  318. package/src/discord/command/localization.ts +11 -0
  319. package/src/discord/command/options.ts +847 -0
  320. package/src/discord/command/permission-guard.ts +74 -0
  321. package/src/discord/command/router.ts +142 -0
  322. package/src/discord/command/types.ts +52 -0
  323. package/src/discord/components/component-router.ts +213 -0
  324. package/src/discord/components/interactive-message/index.ts +18 -0
  325. package/src/discord/components/interactive-message/interactive-message-collector.ts +374 -0
  326. package/src/discord/components/interactive-message/mount-interactive-message.ts +71 -0
  327. package/src/discord/components/paginator/index.ts +17 -0
  328. package/src/discord/components/paginator/mount-paginator.ts +69 -0
  329. package/src/discord/components/paginator/page-state.ts +45 -0
  330. package/src/discord/components/paginator/paginator-buttons.ts +60 -0
  331. package/src/discord/components/paginator/paginator-view.ts +61 -0
  332. package/src/discord/components/persistent-paginator.ts +197 -0
  333. package/src/discord/components/settings-editor/index.ts +41 -0
  334. package/src/discord/components/settings-editor/mount-settings-editor.ts +646 -0
  335. package/src/discord/components/settings-editor/navigation.ts +67 -0
  336. package/src/discord/components/settings-editor/settings-editor-card.view.ts +344 -0
  337. package/src/discord/components/settings-editor/settings-editor-field-modal.ts +538 -0
  338. package/src/discord/components/settings-editor/settings-editor-fields.ts +290 -0
  339. package/src/discord/components/settings-editor/settings-editor.view.ts +654 -0
  340. package/src/discord/events/create-event.ts +7 -0
  341. package/src/discord/events/event-router.ts +53 -0
  342. package/src/discord/events/types.ts +17 -0
  343. package/src/discord/i18n.ts +173 -0
  344. package/src/discord/interaction/button.ts +75 -0
  345. package/src/discord/interaction/interaction-router.ts +28 -0
  346. package/src/discord/interaction/modal.ts +505 -0
  347. package/src/discord/interaction/select-menu.ts +246 -0
  348. package/src/discord/permissions.ts +57 -0
  349. package/src/discord/placeholder-registry-errors.ts +11 -0
  350. package/src/discord/placeholder-registry.ts +77 -0
  351. package/src/discord/presenter.ts +26 -0
  352. package/src/discord/ui/card.ts +303 -0
  353. package/src/discord/ui/color-input-errors.ts +17 -0
  354. package/src/discord/ui/color-input.ts +179 -0
  355. package/src/discord/ui/colors.ts +58 -0
  356. package/src/discord/ui/embed.ts +64 -0
  357. package/src/discord/ui/message-attachments.ts +57 -0
  358. package/src/errors/business-error.ts +49 -0
  359. package/src/errors/describe-error.ts +73 -0
  360. package/src/errors/incident-ref.ts +10 -0
  361. package/src/errors/index.ts +12 -0
  362. package/src/i18n/business-message.ts +23 -0
  363. package/src/i18n/catalog.ts +41 -0
  364. package/src/i18n/errors.ts +11 -0
  365. package/src/i18n/index.ts +11 -0
  366. package/src/i18n/locale.ts +41 -0
  367. package/src/i18n/translator.ts +78 -0
  368. package/src/logger.ts +28 -0
  369. package/src/module/module.ts +42 -0
  370. package/src/persistence/database.ts +23 -0
  371. package/src/resilience/retry.ts +102 -0
  372. package/src/scheduler/errors.ts +40 -0
  373. package/src/scheduler/scheduler.ts +248 -0
@@ -0,0 +1,48 @@
1
+ import { type Interaction } from "discord.js";
2
+ import type { ContextMenuCommand, SlashCommand } from "../../discord/command/types";
3
+ import type { InteractionDispatcher } from "../../discord/interaction/interaction-router";
4
+ import type { Presenter } from "../../discord/presenter";
5
+ import type { Translator } from "../../i18n";
6
+ import type { Logger } from "../../logger";
7
+ export interface CommandRouterDeps {
8
+ presenter: Presenter;
9
+ logger: Logger;
10
+ translator: Translator;
11
+ }
12
+ /**
13
+ * Owns the registered slash commands and dispatches chat-input interactions to
14
+ * them, injecting the shared {@link CommandRuntime}. Also registers the command
15
+ * definitions with Discord's API. It does not attach its own listener — it is an
16
+ * {@link InteractionDispatcher} driven by the shared {@link InteractionRouter}.
17
+ */
18
+ export declare class CommandRouter implements InteractionDispatcher {
19
+ private readonly deps;
20
+ private readonly commands;
21
+ private readonly contextMenuCommands;
22
+ private readonly runtime;
23
+ constructor(deps: CommandRouterDeps);
24
+ /** Register a command (last registration of a name wins). */
25
+ register(command: SlashCommand): this;
26
+ /** Register many commands at once. */
27
+ registerAll(commands: Iterable<SlashCommand>): this;
28
+ /**
29
+ * Register a context-menu entry. Kept in its own map because Discord treats a
30
+ * slash command and a context-menu entry as distinct application command
31
+ * types, and therefore lets them share a name.
32
+ */
33
+ registerContextMenu(command: ContextMenuCommand): this;
34
+ registerAllContextMenus(commands: Iterable<ContextMenuCommand>): this;
35
+ /** Look up a registered slash command, for dispatchers that share this registry. */
36
+ get(name: string): SlashCommand | undefined;
37
+ /** Claim and dispatch chat-input and context-menu commands; ignore everything else. */
38
+ handle(interaction: Interaction): Promise<boolean>;
39
+ /**
40
+ * Push every registered command to its declared scope: commands with
41
+ * `guildIds` go to those guild(s) (instant availability), the rest are
42
+ * deployed globally (available on every server, slower to propagate). The
43
+ * global scope is always synced — even when empty — so stale global commands
44
+ * are pruned. Returns the number of commands deployed.
45
+ */
46
+ deployCommands(token: string, clientId: string): Promise<number>;
47
+ }
48
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../src/discord/command/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAgB,MAAM,YAAY,CAAC;AAC5D,OAAO,KAAK,EAEX,kBAAkB,EAElB,YAAY,EACZ,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;CACvB;AAED;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,qBAAqB;IAK9C,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAC5D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAyC;IAC7E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;gBAEZ,IAAI,EAAE,iBAAiB;IAQpD,6DAA6D;IAC7D,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAKrC,sCAAsC;IACtC,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,IAAI;IAOnD;;;;OAIG;IACH,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAKtD,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GAAG,IAAI;IAOrE,oFAAoF;IACpF,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI3C,uFAAuF;IACjF,MAAM,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAsBxD;;;;;;OAMG;IACG,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAsCtE"}
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CommandRouter = void 0;
4
+ const discord_js_1 = require("discord.js");
5
+ /**
6
+ * Owns the registered slash commands and dispatches chat-input interactions to
7
+ * them, injecting the shared {@link CommandRuntime}. Also registers the command
8
+ * definitions with Discord's API. It does not attach its own listener — it is an
9
+ * {@link InteractionDispatcher} driven by the shared {@link InteractionRouter}.
10
+ */
11
+ class CommandRouter {
12
+ deps;
13
+ commands = new Map();
14
+ contextMenuCommands = new Map();
15
+ runtime;
16
+ constructor(deps) {
17
+ this.deps = deps;
18
+ this.runtime = {
19
+ presenter: deps.presenter,
20
+ logger: deps.logger,
21
+ translator: deps.translator,
22
+ };
23
+ }
24
+ /** Register a command (last registration of a name wins). */
25
+ register(command) {
26
+ this.commands.set(command.data.name, command);
27
+ return this;
28
+ }
29
+ /** Register many commands at once. */
30
+ registerAll(commands) {
31
+ for (const command of commands) {
32
+ this.register(command);
33
+ }
34
+ return this;
35
+ }
36
+ /**
37
+ * Register a context-menu entry. Kept in its own map because Discord treats a
38
+ * slash command and a context-menu entry as distinct application command
39
+ * types, and therefore lets them share a name.
40
+ */
41
+ registerContextMenu(command) {
42
+ this.contextMenuCommands.set(command.data.name, command);
43
+ return this;
44
+ }
45
+ registerAllContextMenus(commands) {
46
+ for (const command of commands) {
47
+ this.registerContextMenu(command);
48
+ }
49
+ return this;
50
+ }
51
+ /** Look up a registered slash command, for dispatchers that share this registry. */
52
+ get(name) {
53
+ return this.commands.get(name);
54
+ }
55
+ /** Claim and dispatch chat-input and context-menu commands; ignore everything else. */
56
+ async handle(interaction) {
57
+ if (interaction.isChatInputCommand()) {
58
+ const command = this.commands.get(interaction.commandName);
59
+ if (!command) {
60
+ return false;
61
+ }
62
+ await command.dispatch(interaction, this.runtime);
63
+ return true;
64
+ }
65
+ if (interaction.isContextMenuCommand()) {
66
+ const command = this.contextMenuCommands.get(interaction.commandName);
67
+ if (!command) {
68
+ return false;
69
+ }
70
+ await command.dispatch(interaction, this.runtime);
71
+ return true;
72
+ }
73
+ return false;
74
+ }
75
+ /**
76
+ * Push every registered command to its declared scope: commands with
77
+ * `guildIds` go to those guild(s) (instant availability), the rest are
78
+ * deployed globally (available on every server, slower to propagate). The
79
+ * global scope is always synced — even when empty — so stale global commands
80
+ * are pruned. Returns the number of commands deployed.
81
+ */
82
+ async deployCommands(token, clientId) {
83
+ const rest = new discord_js_1.REST({ version: "10" }).setToken(token);
84
+ const global = [];
85
+ const byGuild = new Map();
86
+ let deployed = 0;
87
+ const all = [
88
+ ...this.commands.values(),
89
+ ...this.contextMenuCommands.values(),
90
+ ];
91
+ for (const command of all) {
92
+ const body = command.data.toJSON ? command.data.toJSON() : null;
93
+ if (body === null) {
94
+ continue;
95
+ }
96
+ deployed += 1;
97
+ if (command.guildIds && command.guildIds.length > 0) {
98
+ for (const guildId of command.guildIds) {
99
+ const bucket = byGuild.get(guildId) ?? [];
100
+ bucket.push(body);
101
+ byGuild.set(guildId, bucket);
102
+ }
103
+ }
104
+ else {
105
+ global.push(body);
106
+ }
107
+ }
108
+ await rest.put(discord_js_1.Routes.applicationCommands(clientId), { body: global });
109
+ this.deps.logger.info({ count: global.length }, "Global slash commands deployed");
110
+ for (const [guildId, body] of byGuild) {
111
+ await rest.put(discord_js_1.Routes.applicationGuildCommands(clientId, guildId), { body });
112
+ this.deps.logger.info({ guildId, count: body.length }, "Guild slash commands deployed");
113
+ }
114
+ return deployed;
115
+ }
116
+ }
117
+ exports.CommandRouter = CommandRouter;
118
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../../src/discord/command/router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import type { AutocompleteInteraction, ChatInputCommandInteraction, ContextMenuCommandInteraction } from "discord.js";
2
+ import type { Presenter } from "../../discord/presenter";
3
+ import type { Translator } from "../../i18n";
4
+ import type { Logger } from "../../logger";
5
+ /**
6
+ * Per-request dependencies injected into the command pipeline by the router.
7
+ * Passing these at dispatch time (rather than importing singletons) keeps the
8
+ * framework free of global state and trivially testable.
9
+ */
10
+ export interface CommandRuntime {
11
+ readonly presenter: Presenter;
12
+ readonly logger: Logger;
13
+ readonly translator: Translator;
14
+ }
15
+ /**
16
+ * The framework's slash-command contract. `data` is a discord.js builder (or
17
+ * anything with `.toJSON()`); `dispatch` routes an interaction using the
18
+ * supplied runtime. `guildIds` restricts deployment to specific guild(s); when
19
+ * omitted the command is deployed globally (available on every server).
20
+ */
21
+ export interface SlashCommand {
22
+ readonly data: {
23
+ name: string;
24
+ toJSON?: () => unknown;
25
+ };
26
+ readonly guildIds?: readonly string[];
27
+ dispatch(interaction: ChatInputCommandInteraction, runtime: CommandRuntime): Promise<void>;
28
+ /**
29
+ * Answer an autocomplete request for one of this command's options. Present
30
+ * only when at least one option declares a resolver, so the dispatcher can
31
+ * skip commands that never autocomplete.
32
+ */
33
+ autocomplete?(interaction: AutocompleteInteraction): Promise<void>;
34
+ }
35
+ /**
36
+ * A context-menu (a.k.a. application) command: the entry a user gets by
37
+ * right-clicking a member or a message. It shares deployment and permissions
38
+ * with a slash command, but carries no name to type and no options — only the
39
+ * target the user clicked.
40
+ */
41
+ export interface ContextMenuCommand {
42
+ readonly data: {
43
+ name: string;
44
+ toJSON?: () => unknown;
45
+ };
46
+ readonly guildIds?: readonly string[];
47
+ dispatch(interaction: ContextMenuCommandInteraction, runtime: CommandRuntime): Promise<void>;
48
+ }
49
+ /** Anything the command router can register and deploy to Discord. */
50
+ export type DeployableCommand = SlashCommand | ContextMenuCommand;
51
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/discord/command/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,uBAAuB,EACvB,2BAA2B,EAC3B,6BAA6B,EAC7B,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CAChC;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC;IACxD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,2BAA2B,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3F;;;;OAIG;IACH,YAAY,CAAC,CAAC,WAAW,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnE;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,OAAO,CAAA;KAAE,CAAC;IACxD,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,6BAA6B,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7F;AAED,sEAAsE;AACtE,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,kBAAkB,CAAC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/discord/command/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,116 @@
1
+ import { type AnySelectMenuInteraction, type ButtonInteraction, type Interaction, type ModalSubmitInteraction } from "discord.js";
2
+ import type { InteractionDispatcher } from "../../discord/interaction/interaction-router";
3
+ import { type PermissionBit } from "../../discord/permissions";
4
+ import type { Presenter } from "../../discord/presenter";
5
+ import { type Translator } from "../../i18n";
6
+ import type { Logger } from "../../logger";
7
+ /**
8
+ * Interactions a {@link ComponentHandler} can be routed: message components
9
+ * (buttons, any select menu) and modal submissions.
10
+ */
11
+ export type RoutableInteraction = ButtonInteraction | AnySelectMenuInteraction | ModalSubmitInteraction;
12
+ /** Per-dispatch dependencies, injected by the router (mirrors `CommandRuntime`). */
13
+ export interface ComponentRuntime {
14
+ readonly presenter: Presenter;
15
+ readonly logger: Logger;
16
+ readonly translator: Translator;
17
+ }
18
+ /**
19
+ * Who may act on a component.
20
+ *
21
+ * A command declares its audience through `defaultMemberPermissions` + a
22
+ * `Guard`, and `Guard` is typed on `CommandInteraction` — deliberately, so a
23
+ * guard cannot be attached to a button. That leaves a component with no
24
+ * framework-level place to state who may click it, and the only thing standing
25
+ * between a member and a destructive button is whether whoever wrote the
26
+ * handler remembered to check. Every existing handler does; nothing makes the
27
+ * next one.
28
+ *
29
+ * So the answer is required by the type. There is no default and no optional
30
+ * field: a handler that says nothing does not compile, and "anyone may click
31
+ * this" has to be written down and justified rather than reached by omission.
32
+ */
33
+ export type ComponentAuthorization =
34
+ /** Any member may click. `because` is why that is safe, not decoration. */
35
+ {
36
+ readonly kind: "anyone";
37
+ readonly because: string;
38
+ }
39
+ /** The router denies unless the member holds every listed permission. */
40
+ | {
41
+ readonly kind: "permissions";
42
+ readonly required: readonly PermissionBit[];
43
+ }
44
+ /**
45
+ * The handler decides for itself, because the answer depends on state the
46
+ * router cannot see — whether this member opened *this* ticket, say.
47
+ */
48
+ | {
49
+ readonly kind: "handler";
50
+ readonly because: string;
51
+ };
52
+ /** Any member may click; `because` records why that is acceptable. */
53
+ export declare function openToAnyone(because: string): ComponentAuthorization;
54
+ /** The router denies the click unless the member holds every permission. */
55
+ export declare function requiresPermissions(...required: readonly PermissionBit[]): ComponentAuthorization;
56
+ /**
57
+ * The decision needs per-resource state, so the handler makes it. `because`
58
+ * names the rule it applies, so a reviewer can go and check that it does.
59
+ */
60
+ export declare function checkedByHandler(because: string): ComponentAuthorization;
61
+ /**
62
+ * A persistent component handler, routed by `customId`. It claims an interaction
63
+ * whose customId equals `customId` or starts with `${customId}:`, so dynamic
64
+ * state can be appended after a colon (e.g. handler `role` claims `role:add:123`).
65
+ *
66
+ * Best practice — handler (this) vs collector ({@link import("../../discord/components/paginator").mountPaginator}):
67
+ * use a **handler** for *persistent* components that must keep working forever and
68
+ * survive a restart (role pickers, ticket/verify buttons); the bot has no
69
+ * in-memory closure after a restart, so encode state in the customId (or refetch
70
+ * it). Use a **collector** for *transient*, single-message, owner-scoped flows
71
+ * with a lifetime (pagination, a confirm dialog) — its state lives in memory and
72
+ * dies on idle.
73
+ */
74
+ export interface ComponentHandler {
75
+ readonly customId: string;
76
+ /** Who may act on this component. Required: see {@link ComponentAuthorization}. */
77
+ readonly authorize: ComponentAuthorization;
78
+ handle(interaction: RoutableInteraction, runtime: ComponentRuntime): Promise<void> | void;
79
+ }
80
+ /** Declare a {@link ComponentHandler}. Identity helper kept for a consistent DSL. */
81
+ export declare function createComponentHandler(handler: ComponentHandler): ComponentHandler;
82
+ export interface ComponentRouterDeps {
83
+ presenter: Presenter;
84
+ logger: Logger;
85
+ translator: Translator;
86
+ }
87
+ /**
88
+ * Routes persistent component/modal interactions to registered handlers by
89
+ * `customId`, injecting the shared {@link ComponentRuntime}. It does not attach
90
+ * its own listener — it is an {@link InteractionDispatcher} driven by the shared
91
+ * {@link import("../../discord/interaction/interaction-router").InteractionRouter},
92
+ * so commands and components share a single `interactionCreate` listener.
93
+ */
94
+ export declare class ComponentRouter implements InteractionDispatcher {
95
+ private readonly deps;
96
+ private readonly handlers;
97
+ private readonly runtime;
98
+ constructor(deps: ComponentRouterDeps);
99
+ register(handler: ComponentHandler): this;
100
+ registerAll(handlers: Iterable<ComponentHandler>): this;
101
+ private match;
102
+ /** Claim and route component/modal interactions by `customId`; ignore the rest. */
103
+ handle(interaction: Interaction): Promise<boolean>;
104
+ /**
105
+ * Enforce the handler's declared audience. Only `permissions` is enforceable
106
+ * here — the other two kinds are statements about a decision made elsewhere,
107
+ * and their value is that the handler had to state one.
108
+ *
109
+ * `memberPermissions` is `null` outside a guild; that is a denial, since an
110
+ * unknown permission set must never be read as a granted one — the same rule
111
+ * `createPermissionGuard` follows for commands.
112
+ */
113
+ private passesAuthorization;
114
+ private localeOf;
115
+ }
116
+ //# sourceMappingURL=component-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-router.d.ts","sourceRoot":"","sources":["../../../src/discord/components/component-router.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAEhB,KAAK,sBAAsB,EAC3B,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,EAAyC,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAClG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAA8B,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAC5B,iBAAiB,GACjB,wBAAwB,GACxB,sBAAsB,CAAC;AAE1B,oFAAoF;AACpF,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CAChC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,sBAAsB;AACjC,2EAA2E;AACzE;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACvD,yEAAyE;GACvE;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAA;CAAE;AAC/E;;;GAGG;GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB,CAEpE;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,GAAG,QAAQ,EAAE,SAAS,aAAa,EAAE,GAAG,sBAAsB,CAEjG;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB,CAExE;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,sBAAsB,CAAC;IAC3C,MAAM,CAAC,WAAW,EAAE,mBAAmB,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC1F;AAED,qFAAqF;AACrF,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,gBAAgB,CAElF;AAED,MAAM,WAAW,mBAAmB;IACnC,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;CACvB;AAMD;;;;;;GAMG;AACH,qBAAa,eAAgB,YAAW,qBAAqB;IAIhD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA0B;IACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;gBAEd,IAAI,EAAE,mBAAmB;IAQtD,QAAQ,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAKzC,WAAW,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,IAAI;IAOvD,OAAO,CAAC,KAAK;IAMb,mFAAmF;IAC7E,MAAM,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IA2BxD;;;;;;;;OAQG;YACW,mBAAmB;IAuBjC,OAAO,CAAC,QAAQ;CAMhB"}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ComponentRouter = void 0;
4
+ exports.openToAnyone = openToAnyone;
5
+ exports.requiresPermissions = requiresPermissions;
6
+ exports.checkedByHandler = checkedByHandler;
7
+ exports.createComponentHandler = createComponentHandler;
8
+ const discord_js_1 = require("discord.js");
9
+ const i18n_1 = require("../../discord/i18n");
10
+ const permissions_1 = require("../../discord/permissions");
11
+ const i18n_2 = require("../../i18n");
12
+ /** Any member may click; `because` records why that is acceptable. */
13
+ function openToAnyone(because) {
14
+ return { kind: "anyone", because };
15
+ }
16
+ /** The router denies the click unless the member holds every permission. */
17
+ function requiresPermissions(...required) {
18
+ return { kind: "permissions", required };
19
+ }
20
+ /**
21
+ * The decision needs per-resource state, so the handler makes it. `because`
22
+ * names the rule it applies, so a reviewer can go and check that it does.
23
+ */
24
+ function checkedByHandler(because) {
25
+ return { kind: "handler", because };
26
+ }
27
+ /** Declare a {@link ComponentHandler}. Identity helper kept for a consistent DSL. */
28
+ function createComponentHandler(handler) {
29
+ return handler;
30
+ }
31
+ function isRoutable(interaction) {
32
+ return interaction.isButton() || interaction.isAnySelectMenu() || interaction.isModalSubmit();
33
+ }
34
+ /**
35
+ * Routes persistent component/modal interactions to registered handlers by
36
+ * `customId`, injecting the shared {@link ComponentRuntime}. It does not attach
37
+ * its own listener — it is an {@link InteractionDispatcher} driven by the shared
38
+ * {@link import("../../discord/interaction/interaction-router").InteractionRouter},
39
+ * so commands and components share a single `interactionCreate` listener.
40
+ */
41
+ class ComponentRouter {
42
+ deps;
43
+ handlers = [];
44
+ runtime;
45
+ constructor(deps) {
46
+ this.deps = deps;
47
+ this.runtime = {
48
+ presenter: deps.presenter,
49
+ logger: deps.logger,
50
+ translator: deps.translator,
51
+ };
52
+ }
53
+ register(handler) {
54
+ this.handlers.push(handler);
55
+ return this;
56
+ }
57
+ registerAll(handlers) {
58
+ for (const handler of handlers) {
59
+ this.register(handler);
60
+ }
61
+ return this;
62
+ }
63
+ match(customId) {
64
+ return this.handlers.find((handler) => customId === handler.customId || customId.startsWith(`${handler.customId}:`));
65
+ }
66
+ /** Claim and route component/modal interactions by `customId`; ignore the rest. */
67
+ async handle(interaction) {
68
+ if (!isRoutable(interaction)) {
69
+ return false;
70
+ }
71
+ const handler = this.match(interaction.customId);
72
+ if (!handler) {
73
+ return false;
74
+ }
75
+ // Before the handler runs, so a declared permission cannot be bypassed by a
76
+ // handler that forgot to check it.
77
+ if (!(await this.passesAuthorization(interaction, handler))) {
78
+ return true;
79
+ }
80
+ try {
81
+ await handler.handle(interaction, this.runtime);
82
+ }
83
+ catch (error) {
84
+ this.deps.logger.error({
85
+ customId: interaction.customId,
86
+ err: error instanceof Error ? error.message : String(error),
87
+ }, "Component handler failed");
88
+ }
89
+ return true;
90
+ }
91
+ /**
92
+ * Enforce the handler's declared audience. Only `permissions` is enforceable
93
+ * here — the other two kinds are statements about a decision made elsewhere,
94
+ * and their value is that the handler had to state one.
95
+ *
96
+ * `memberPermissions` is `null` outside a guild; that is a denial, since an
97
+ * unknown permission set must never be read as a granted one — the same rule
98
+ * `createPermissionGuard` follows for commands.
99
+ */
100
+ async passesAuthorization(interaction, handler) {
101
+ if (handler.authorize.kind !== "permissions") {
102
+ return true;
103
+ }
104
+ const missing = (0, permissions_1.missingPermissions)(interaction.memberPermissions, handler.authorize.required);
105
+ if (missing.length === 0) {
106
+ return true;
107
+ }
108
+ const locale = this.localeOf(interaction);
109
+ const message = this.deps.translator.translate(locale, i18n_1.CORE_MESSAGES.guardPermissionDenied, {
110
+ missing: (0, permissions_1.formatPermissions)(missing),
111
+ });
112
+ await interaction.reply({
113
+ embeds: [this.deps.presenter.denial(message, locale)],
114
+ flags: discord_js_1.MessageFlags.Ephemeral,
115
+ });
116
+ return false;
117
+ }
118
+ localeOf(interaction) {
119
+ return (0, i18n_2.resolveLocale)([interaction.locale, interaction.guildLocale], this.deps.translator.defaultLocale);
120
+ }
121
+ }
122
+ exports.ComponentRouter = ComponentRouter;
123
+ //# sourceMappingURL=component-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-router.js","sourceRoot":"","sources":["../../../src/discord/components/component-router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { COLLECTOR_IDLE_MS, createStateStore, type DisabledInteractiveMessageComponents, type InteractiveMessageCollectorDeps, type InteractiveMessageHandle, type InteractiveMessagePayload, type InteractiveSelect, type InteractiveView, mountInteractiveMessageCollector, type SelectComponentContext, type StateStore, toMessageEditOptions, } from "../../../discord/components/interactive-message/interactive-message-collector";
2
+ export { type InteractiveMessageOptions, mountInteractiveMessage, } from "../../../discord/components/interactive-message/mount-interactive-message";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/discord/components/interactive-message/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,oCAAoC,EACzC,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,gCAAgC,EAChC,KAAK,sBAAsB,EAC3B,KAAK,UAAU,EACf,oBAAoB,GACpB,MAAM,wEAAwE,CAAC;AAChF,OAAO,EACN,KAAK,yBAAyB,EAC9B,uBAAuB,GACvB,MAAM,oEAAoE,CAAC"}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mountInteractiveMessage = exports.toMessageEditOptions = exports.mountInteractiveMessageCollector = exports.createStateStore = exports.COLLECTOR_IDLE_MS = void 0;
4
+ var interactive_message_collector_1 = require("../../../discord/components/interactive-message/interactive-message-collector");
5
+ Object.defineProperty(exports, "COLLECTOR_IDLE_MS", { enumerable: true, get: function () { return interactive_message_collector_1.COLLECTOR_IDLE_MS; } });
6
+ Object.defineProperty(exports, "createStateStore", { enumerable: true, get: function () { return interactive_message_collector_1.createStateStore; } });
7
+ Object.defineProperty(exports, "mountInteractiveMessageCollector", { enumerable: true, get: function () { return interactive_message_collector_1.mountInteractiveMessageCollector; } });
8
+ Object.defineProperty(exports, "toMessageEditOptions", { enumerable: true, get: function () { return interactive_message_collector_1.toMessageEditOptions; } });
9
+ var mount_interactive_message_1 = require("../../../discord/components/interactive-message/mount-interactive-message");
10
+ Object.defineProperty(exports, "mountInteractiveMessage", { enumerable: true, get: function () { return mount_interactive_message_1.mountInteractiveMessage; } });
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/discord/components/interactive-message/index.ts"],"names":[],"mappings":";;;AAAA,wHAagF;AAZ/E,kIAAA,iBAAiB,OAAA;AACjB,iIAAA,gBAAgB,OAAA;AAOhB,iJAAA,gCAAgC,OAAA;AAGhC,qIAAA,oBAAoB,OAAA;AAErB,gHAG4E;AAD3E,oIAAA,uBAAuB,OAAA"}