@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,53 @@
1
+ import type { Client } from "discord.js";
2
+ import type { DiscordEvent, EventListener } from "@/discord/events/types";
3
+ import type { Logger } from "@/logger";
4
+
5
+ /**
6
+ * Wrap a handler so a thrown error is logged instead of escaping to the
7
+ * process-level `error` event: a failing handler must never take the bot down.
8
+ */
9
+ function createEventListener(event: DiscordEvent, logger: Logger): EventListener {
10
+ return async (...args) => {
11
+ try {
12
+ await event.execute(...args);
13
+ } catch (error) {
14
+ logger.error(
15
+ { event: event.name, err: error instanceof Error ? error.message : String(error) },
16
+ "Event handler failed",
17
+ );
18
+ }
19
+ };
20
+ }
21
+
22
+ /**
23
+ * Binds registered {@link DiscordEvent}s to a client. This is the only place in
24
+ * the app that calls `client.on`/`client.once`.
25
+ */
26
+ export class EventRouter {
27
+ private readonly events: DiscordEvent[] = [];
28
+
29
+ constructor(private readonly logger: Logger) {}
30
+
31
+ register(event: DiscordEvent): this {
32
+ this.events.push(event);
33
+ return this;
34
+ }
35
+
36
+ registerAll(events: Iterable<DiscordEvent>): this {
37
+ for (const event of events) {
38
+ this.register(event);
39
+ }
40
+ return this;
41
+ }
42
+
43
+ bind(client: Client): void {
44
+ for (const event of this.events) {
45
+ const listener = createEventListener(event, this.logger);
46
+ if (event.once) {
47
+ client.once(event.name, listener);
48
+ } else {
49
+ client.on(event.name, listener);
50
+ }
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,17 @@
1
+ import type { ClientEvents } from "discord.js";
2
+
3
+ /**
4
+ * A typed Discord gateway event handler. `name` is keyed to discord.js'
5
+ * {@link ClientEvents}, so `args` are inferred per event with no `any`.
6
+ */
7
+ export interface DiscordEvent<K extends keyof ClientEvents = keyof ClientEvents> {
8
+ readonly name: K;
9
+ readonly once?: boolean;
10
+ execute(...args: ClientEvents[K]): Promise<void> | void;
11
+ }
12
+
13
+ /**
14
+ * The listener actually handed to discord.js. It is type-erased over every event
15
+ * name because the router holds heterogeneous events in a single collection.
16
+ */
17
+ export type EventListener = (...args: ClientEvents[keyof ClientEvents]) => Promise<void>;
@@ -0,0 +1,173 @@
1
+ import type { Catalog } from "@/i18n";
2
+
3
+ /** Catalog keys for the framework's own feedback, under the `core.` namespace. */
4
+ export const CORE_MESSAGES = {
5
+ presenterSuccessTitle: "core.presenter.success-title",
6
+ presenterWarningTitle: "core.presenter.warning-title",
7
+ presenterErrorTitle: "core.presenter.error-title",
8
+ presenterDenialTitle: "core.presenter.denial-title",
9
+ presenterIncidentFooter: "core.presenter.incident-footer",
10
+ unknownSubcommand: "core.command.unknown-subcommand",
11
+ genericError: "core.command.generic-error",
12
+ cooldownWait: "core.cooldown.wait",
13
+ guardPermissionDenied: "core.guard.permission-denied",
14
+ guardRoleDenied: "core.guard.role-denied",
15
+ guardGuildOnly: "core.guard.guild-only",
16
+ } as const;
17
+
18
+ /**
19
+ * Catalog keys for the settings editor's own chrome — the wording that is the
20
+ * same whatever is being edited.
21
+ *
22
+ * Deliberately *not* the wording of the settings themselves: a field's label and
23
+ * its one-line hint name something only the calling module knows about, so those
24
+ * stay in that module's catalog and reach the editor as keys.
25
+ */
26
+ export const SETTINGS_EDITOR_MESSAGES = {
27
+ modalTitle: "core.settings-editor.modal-title",
28
+ modalHelper: "core.settings-editor.modal-helper",
29
+ modalUploadLabel: "core.settings-editor.modal-upload-label",
30
+ modalUploadHelper: "core.settings-editor.modal-upload-helper",
31
+ modalImageUrlLabel: "core.settings-editor.modal-image-url-label",
32
+ modalImageHelper: "core.settings-editor.modal-image-helper",
33
+ modalImageHelperUploaded: "core.settings-editor.modal-image-helper-uploaded",
34
+ fieldSaved: "core.settings-editor.field-saved",
35
+ fieldCleared: "core.settings-editor.field-cleared",
36
+ fieldUploaded: "core.settings-editor.field-uploaded",
37
+ resetButton: "core.settings-editor.reset-button",
38
+ resetConfirmTitle: "core.settings-editor.reset-confirm-title",
39
+ resetConfirmDescription: "core.settings-editor.reset-confirm-description",
40
+ resetConfirmButton: "core.settings-editor.reset-confirm-button",
41
+ resetCancelButton: "core.settings-editor.reset-cancel-button",
42
+ resetDone: "core.settings-editor.reset-done",
43
+ resetCancelled: "core.settings-editor.reset-cancelled",
44
+ backButton: "core.settings-editor.back-button",
45
+ /**
46
+ * A card screen's per-entry button: what selecting the entry from the old
47
+ * field menu used to do, now spelled on the button that replaces it. One
48
+ * wording for a field that opens a modal, another for one that descends a
49
+ * level — both generic enough that no card screen has ever needed its own.
50
+ */
51
+ editFieldButton: "core.settings-editor.edit-field-button",
52
+ openLevelButton: "core.settings-editor.open-level-button",
53
+ } as const;
54
+
55
+ /**
56
+ * The framework's own strings: presenter titles, the incident footer, dispatch
57
+ * fallbacks and the default cooldown notice. Registered by the composition root
58
+ * before any module catalog.
59
+ */
60
+ export const CORE_CATALOG: Catalog = {
61
+ [CORE_MESSAGES.presenterSuccessTitle]: { en: "Success", fr: "Succès" },
62
+ [CORE_MESSAGES.presenterWarningTitle]: { en: "Warning", fr: "Avertissement" },
63
+ [CORE_MESSAGES.presenterErrorTitle]: { en: "Error", fr: "Erreur" },
64
+ [CORE_MESSAGES.presenterDenialTitle]: { en: "Access denied", fr: "Accès refusé" },
65
+ [CORE_MESSAGES.presenterIncidentFooter]: {
66
+ en: "Ref: {reference} · contact an admin if this persists",
67
+ fr: "Réf : {reference} · contactez un admin si le problème persiste",
68
+ },
69
+ [CORE_MESSAGES.unknownSubcommand]: {
70
+ en: "Unknown subcommand.",
71
+ fr: "Sous-commande inconnue.",
72
+ },
73
+ [CORE_MESSAGES.genericError]: {
74
+ en: "Something went wrong.",
75
+ fr: "Une erreur est survenue.",
76
+ },
77
+ [CORE_MESSAGES.cooldownWait]: {
78
+ en: "Slow down — try again in {seconds}s.",
79
+ fr: "Doucement — réessayez dans {seconds}s.",
80
+ },
81
+ [CORE_MESSAGES.guardPermissionDenied]: {
82
+ en: "You do not have permission to use this command. Missing: {missing}.",
83
+ fr: "Vous n'avez pas la permission d'utiliser cette commande. Manquant : {missing}.",
84
+ },
85
+ [CORE_MESSAGES.guardRoleDenied]: {
86
+ en: "You do not have the role required to use this command.",
87
+ fr: "Vous n'avez pas le rôle requis pour utiliser cette commande.",
88
+ },
89
+ [CORE_MESSAGES.guardGuildOnly]: {
90
+ en: "This command can only be used in a server.",
91
+ fr: "Cette commande ne peut être utilisée que sur un serveur.",
92
+ },
93
+ [SETTINGS_EDITOR_MESSAGES.modalTitle]: {
94
+ en: "Edit: {field}",
95
+ fr: "Modifier : {field}",
96
+ },
97
+ [SETTINGS_EDITOR_MESSAGES.modalHelper]: {
98
+ en: "Leave empty to clear your customisation and go back to the default.",
99
+ fr: "Laisse vide pour effacer ta personnalisation et revenir à la valeur par défaut.",
100
+ },
101
+ [SETTINGS_EDITOR_MESSAGES.modalUploadLabel]: {
102
+ en: "Upload an image",
103
+ fr: "Envoyer une image",
104
+ },
105
+ [SETTINGS_EDITOR_MESSAGES.modalUploadHelper]: {
106
+ en: "PNG, JPEG, GIF or WebP, up to {max} MiB. An upload wins over the address below.",
107
+ fr: "PNG, JPEG, GIF ou WebP, jusqu'à {max} Mio. Un envoi l'emporte sur l'adresse ci-dessous.",
108
+ },
109
+ [SETTINGS_EDITOR_MESSAGES.modalImageUrlLabel]: {
110
+ en: "…or an image address",
111
+ fr: "…ou une adresse d'image",
112
+ },
113
+ [SETTINGS_EDITOR_MESSAGES.modalImageHelper]: {
114
+ en: "An http(s) address. Leave both empty to restore the default.",
115
+ fr: "Une adresse http(s). Laisse les deux vides pour revenir au défaut.",
116
+ },
117
+ [SETTINGS_EDITOR_MESSAGES.modalImageHelperUploaded]: {
118
+ en: "An image is uploaded; it cannot be shown here. Empty both to restore the default.",
119
+ fr: "Une image est envoyée ; impossible de la réafficher. Vide les deux pour le défaut.",
120
+ },
121
+ [SETTINGS_EDITOR_MESSAGES.fieldSaved]: {
122
+ en: "✅ {field} updated.",
123
+ fr: "✅ {field} mis à jour.",
124
+ },
125
+ [SETTINGS_EDITOR_MESSAGES.fieldCleared]: {
126
+ en: "✅ {field} cleared — the default is used again.",
127
+ fr: "✅ {field} effacé — la valeur par défaut est de nouveau utilisée.",
128
+ },
129
+ [SETTINGS_EDITOR_MESSAGES.fieldUploaded]: {
130
+ en: "✅ {field} updated with your upload.",
131
+ fr: "✅ {field} mis à jour avec ton envoi.",
132
+ },
133
+ [SETTINGS_EDITOR_MESSAGES.resetButton]: {
134
+ en: "Reset everything",
135
+ fr: "Tout réinitialiser",
136
+ },
137
+ [SETTINGS_EDITOR_MESSAGES.resetConfirmTitle]: {
138
+ en: "Reset every field?",
139
+ fr: "Réinitialiser tous les champs ?",
140
+ },
141
+ [SETTINGS_EDITOR_MESSAGES.resetConfirmDescription]: {
142
+ en: "Every field goes back to its default. An uploaded image is not merely unset — its file is deleted for good and cannot be recovered. The preview below is what you are about to lose.",
143
+ fr: "Chaque champ revient à sa valeur par défaut. Une image envoyée n'est pas simplement retirée : le fichier est supprimé définitivement et ne pourra pas être récupéré. L'aperçu ci-dessous est ce que tu es sur le point de perdre.",
144
+ },
145
+ [SETTINGS_EDITOR_MESSAGES.resetConfirmButton]: {
146
+ en: "Reset for good",
147
+ fr: "Réinitialiser définitivement",
148
+ },
149
+ [SETTINGS_EDITOR_MESSAGES.resetCancelButton]: {
150
+ en: "Cancel",
151
+ fr: "Annuler",
152
+ },
153
+ [SETTINGS_EDITOR_MESSAGES.resetDone]: {
154
+ en: "✅ Every field is back to its default.",
155
+ fr: "✅ Tous les champs sont revenus à leur valeur par défaut.",
156
+ },
157
+ [SETTINGS_EDITOR_MESSAGES.resetCancelled]: {
158
+ en: "Nothing was reset. Your customisation is untouched.",
159
+ fr: "Rien n'a été réinitialisé. Ta personnalisation est intacte.",
160
+ },
161
+ [SETTINGS_EDITOR_MESSAGES.backButton]: {
162
+ en: "Back",
163
+ fr: "Retour",
164
+ },
165
+ [SETTINGS_EDITOR_MESSAGES.editFieldButton]: {
166
+ en: "Edit",
167
+ fr: "Modifier",
168
+ },
169
+ [SETTINGS_EDITOR_MESSAGES.openLevelButton]: {
170
+ en: "Open",
171
+ fr: "Ouvrir",
172
+ },
173
+ };
@@ -0,0 +1,75 @@
1
+ import { ActionRowBuilder, ButtonBuilder, type ButtonInteraction, ButtonStyle } from "discord.js";
2
+
3
+ export type ButtonStyleName = "primary" | "secondary" | "success" | "danger";
4
+
5
+ const BUTTON_STYLES: Record<ButtonStyleName, ButtonStyle> = {
6
+ primary: ButtonStyle.Primary,
7
+ secondary: ButtonStyle.Secondary,
8
+ success: ButtonStyle.Success,
9
+ danger: ButtonStyle.Danger,
10
+ };
11
+
12
+ /**
13
+ * Interaction context handed to a button's `onClick`, mirroring the command
14
+ * {@link import("@/discord/command/context").Context}: it exposes the
15
+ * triggering interaction, the current state, and an `update` that re-renders the
16
+ * message with the next state.
17
+ */
18
+ export interface ComponentContext<S> {
19
+ readonly interaction: ButtonInteraction;
20
+ readonly state: S;
21
+ update(next: S): Promise<void>;
22
+ }
23
+
24
+ export interface ButtonDef<S> {
25
+ id: string;
26
+ label?: string;
27
+ emoji?: string;
28
+ style?: ButtonStyleName;
29
+ disabled?: (state: S) => boolean;
30
+ onClick?: (ctx: ComponentContext<S>) => Promise<void> | void;
31
+ }
32
+
33
+ /**
34
+ * Type-erased compiled button: knows how to render itself for a given state
35
+ * (`apply`) and how to react to a click (`onClick`) — the component analogue of
36
+ * a compiled subcommand. A button is *behaviour*, not a passive widget, which is
37
+ * why it lives in the interaction layer rather than a UI/embed module.
38
+ */
39
+ export interface Button<S> {
40
+ readonly id: string;
41
+ readonly onClick?: (ctx: ComponentContext<S>) => Promise<void> | void;
42
+ apply(state: S, forceDisabled?: boolean): ButtonBuilder;
43
+ }
44
+
45
+ /** Declare a button: a definition bundling construction (`apply`) and behaviour (`onClick`). */
46
+ export function createButton<S>(def: ButtonDef<S>): Button<S> {
47
+ const style = BUTTON_STYLES[def.style ?? "secondary"];
48
+ return {
49
+ id: def.id,
50
+ onClick: def.onClick,
51
+ apply(state, forceDisabled = false) {
52
+ const builder = new ButtonBuilder().setCustomId(def.id).setStyle(style);
53
+ if (def.label !== undefined) {
54
+ builder.setLabel(def.label);
55
+ }
56
+ if (def.emoji !== undefined) {
57
+ builder.setEmoji(def.emoji);
58
+ }
59
+ builder.setDisabled(forceDisabled || (def.disabled?.(state) ?? false));
60
+ return builder;
61
+ },
62
+ };
63
+ }
64
+
65
+ /** Group buttons into a single action row, applying each against the current state. */
66
+ export function createActionRow<S>(
67
+ buttons: Button<S>[],
68
+ state: S,
69
+ options: { disableAll?: boolean } = {},
70
+ ): ActionRowBuilder<ButtonBuilder> {
71
+ const disableAll = options.disableAll ?? false;
72
+ return new ActionRowBuilder<ButtonBuilder>().addComponents(
73
+ ...buttons.map((entry) => entry.apply(state, disableAll)),
74
+ );
75
+ }
@@ -0,0 +1,28 @@
1
+ import type { Interaction } from "discord.js";
2
+
3
+ /**
4
+ * Anything that can consume a gateway interaction. `handle` returns `true` when
5
+ * it claimed the interaction, `false` to let the next dispatcher try. This is the
6
+ * seam that lets the whole app share a single `interactionCreate` listener.
7
+ */
8
+ export interface InteractionDispatcher {
9
+ handle(interaction: Interaction): Promise<boolean>;
10
+ }
11
+
12
+ /**
13
+ * Aggregates {@link InteractionDispatcher}s behind one entry point so the app
14
+ * registers a *single* `interactionCreate` listener (wired at the composition
15
+ * root, attached in `bootstrap/lifecycle`). Dispatchers are tried in order and
16
+ * the first to claim the interaction wins — no global state, no singleton.
17
+ */
18
+ export class InteractionRouter {
19
+ constructor(private readonly dispatchers: readonly InteractionDispatcher[]) {}
20
+
21
+ async dispatch(interaction: Interaction): Promise<void> {
22
+ for (const dispatcher of this.dispatchers) {
23
+ if (await dispatcher.handle(interaction)) {
24
+ return;
25
+ }
26
+ }
27
+ }
28
+ }