@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,246 @@
1
+ import {
2
+ ActionRowBuilder,
3
+ type AnySelectMenuInteraction,
4
+ ChannelSelectMenuBuilder,
5
+ type ChannelSelectMenuInteraction,
6
+ type ChannelType,
7
+ RoleSelectMenuBuilder,
8
+ type RoleSelectMenuInteraction,
9
+ StringSelectMenuBuilder,
10
+ type StringSelectMenuInteraction,
11
+ UserSelectMenuBuilder,
12
+ type UserSelectMenuInteraction,
13
+ } from "discord.js";
14
+ import type {
15
+ ComponentAuthorization,
16
+ ComponentHandler,
17
+ } from "@/discord/components/component-router";
18
+
19
+ /** The builders this DSL can produce; the union an action row accepts. */
20
+ export type AnySelectMenuBuilder =
21
+ | StringSelectMenuBuilder
22
+ | ChannelSelectMenuBuilder
23
+ | RoleSelectMenuBuilder
24
+ | UserSelectMenuBuilder;
25
+
26
+ /**
27
+ * Context handed to `onSelect`, mirroring
28
+ * {@link import("@/discord/interaction/button").ComponentContext}: the
29
+ * triggering interaction plus the picked values, already unwrapped so a handler
30
+ * does not have to know where discord.js keeps them.
31
+ */
32
+ export interface SelectContext<I extends AnySelectMenuInteraction> {
33
+ readonly interaction: I;
34
+ readonly values: readonly string[];
35
+ }
36
+
37
+ /**
38
+ * Presentation options shared by every select flavour. Split from the handler so
39
+ * the shared `applyBaseOptions` never sees `onSelect`: a callback is
40
+ * contravariant in its interaction type, so a common supertype for the
41
+ * *definitions* cannot exist.
42
+ */
43
+ export interface SelectLayout {
44
+ id: string;
45
+ placeholder?: string;
46
+ minValues?: number;
47
+ maxValues?: number;
48
+ disabled?: boolean;
49
+ }
50
+
51
+ /** A select declaration: its layout plus the behaviour it carries. */
52
+ export interface BaseSelectDef<I extends AnySelectMenuInteraction> extends SelectLayout {
53
+ onSelect?: (ctx: SelectContext<I>) => Promise<void> | void;
54
+ }
55
+
56
+ /**
57
+ * Compiled select menu: renders itself (`apply`) and owns its behaviour
58
+ * (`onSelect`), exactly like a compiled
59
+ * {@link import("@/discord/interaction/button").Button}. It lives in the
60
+ * interaction layer for the same reason — it carries behaviour, it is not a
61
+ * passive widget.
62
+ */
63
+ export interface SelectMenu<B, I extends AnySelectMenuInteraction> {
64
+ readonly id: string;
65
+ readonly onSelect?: (ctx: SelectContext<I>) => Promise<void> | void;
66
+ apply(forceDisabled?: boolean): B;
67
+ }
68
+
69
+ export interface StringSelectOption {
70
+ label: string;
71
+ value: string;
72
+ description?: string;
73
+ emoji?: string;
74
+ default?: boolean;
75
+ }
76
+
77
+ export interface StringSelectDef extends BaseSelectDef<StringSelectMenuInteraction> {
78
+ options: readonly StringSelectOption[];
79
+ }
80
+
81
+ export interface ChannelSelectDef extends BaseSelectDef<ChannelSelectMenuInteraction> {
82
+ /** Restricts what the picker offers, e.g. text channels only. */
83
+ channelTypes?: readonly ChannelType[];
84
+ /**
85
+ * What the picker opens already holding.
86
+ *
87
+ * A picker returns its whole selection, never a delta, so one that opens
88
+ * empty over a setting that already has a value turns "change this" into
89
+ * "type the list again" — and anything the administrator forgets to re-pick
90
+ * is silently dropped.
91
+ */
92
+ defaultChannelIds?: readonly string[];
93
+ }
94
+
95
+ export interface RoleSelectDef extends BaseSelectDef<RoleSelectMenuInteraction> {
96
+ /** What the picker opens already holding. See {@link ChannelSelectDef.defaultChannelIds}. */
97
+ defaultRoleIds?: readonly string[];
98
+ }
99
+
100
+ export interface UserSelectDef extends BaseSelectDef<UserSelectMenuInteraction> {
101
+ /** What the picker opens already holding. See {@link ChannelSelectDef.defaultChannelIds}. */
102
+ defaultUserIds?: readonly string[];
103
+ }
104
+
105
+ /** Apply the options every select flavour shares onto its builder. */
106
+ function applyBaseOptions<B extends AnySelectMenuBuilder>(
107
+ builder: B,
108
+ def: SelectLayout,
109
+ forceDisabled: boolean,
110
+ ): B {
111
+ builder.setCustomId(def.id);
112
+ if (def.placeholder !== undefined) {
113
+ builder.setPlaceholder(def.placeholder);
114
+ }
115
+ if (def.minValues !== undefined) {
116
+ builder.setMinValues(def.minValues);
117
+ }
118
+ if (def.maxValues !== undefined) {
119
+ builder.setMaxValues(def.maxValues);
120
+ }
121
+ builder.setDisabled(forceDisabled || (def.disabled ?? false));
122
+ return builder;
123
+ }
124
+
125
+ /** A menu of caller-defined string values. */
126
+ export function createStringSelect(
127
+ def: StringSelectDef,
128
+ ): SelectMenu<StringSelectMenuBuilder, StringSelectMenuInteraction> {
129
+ return {
130
+ id: def.id,
131
+ onSelect: def.onSelect,
132
+ apply(forceDisabled = false) {
133
+ const builder = applyBaseOptions(new StringSelectMenuBuilder(), def, forceDisabled);
134
+ return builder.addOptions(
135
+ ...def.options.map((option) => ({
136
+ label: option.label,
137
+ value: option.value,
138
+ description: option.description,
139
+ emoji: option.emoji,
140
+ default: option.default,
141
+ })),
142
+ );
143
+ },
144
+ };
145
+ }
146
+
147
+ /** A menu populated by Discord with the guild's channels. */
148
+ export function createChannelSelect(
149
+ def: ChannelSelectDef,
150
+ ): SelectMenu<ChannelSelectMenuBuilder, ChannelSelectMenuInteraction> {
151
+ return {
152
+ id: def.id,
153
+ onSelect: def.onSelect,
154
+ apply(forceDisabled = false) {
155
+ const builder = applyBaseOptions(new ChannelSelectMenuBuilder(), def, forceDisabled);
156
+ if (def.defaultChannelIds !== undefined && def.defaultChannelIds.length > 0) {
157
+ builder.setDefaultChannels(...def.defaultChannelIds);
158
+ }
159
+ if (def.channelTypes !== undefined) {
160
+ builder.setChannelTypes(...def.channelTypes);
161
+ }
162
+ return builder;
163
+ },
164
+ };
165
+ }
166
+
167
+ /** A menu populated by Discord with the guild's roles. */
168
+ export function createRoleSelect(
169
+ def: RoleSelectDef,
170
+ ): SelectMenu<RoleSelectMenuBuilder, RoleSelectMenuInteraction> {
171
+ return {
172
+ id: def.id,
173
+ onSelect: def.onSelect,
174
+ apply(forceDisabled = false) {
175
+ const builder = applyBaseOptions(new RoleSelectMenuBuilder(), def, forceDisabled);
176
+ if (def.defaultRoleIds !== undefined && def.defaultRoleIds.length > 0) {
177
+ builder.setDefaultRoles(...def.defaultRoleIds);
178
+ }
179
+ return builder;
180
+ },
181
+ };
182
+ }
183
+
184
+ /**
185
+ * A menu populated by Discord with the guild's members.
186
+ *
187
+ * A distinct flavour from the mentionable one on purpose: naming a person is not
188
+ * the same act as naming a role, and the calls behind it — adding someone to the
189
+ * recap's ping list, granting a user a level — take a user id, not either.
190
+ */
191
+ export function createUserSelect(
192
+ def: UserSelectDef,
193
+ ): SelectMenu<UserSelectMenuBuilder, UserSelectMenuInteraction> {
194
+ return {
195
+ id: def.id,
196
+ onSelect: def.onSelect,
197
+ apply(forceDisabled = false) {
198
+ const builder = applyBaseOptions(new UserSelectMenuBuilder(), def, forceDisabled);
199
+ if (def.defaultUserIds !== undefined && def.defaultUserIds.length > 0) {
200
+ builder.setDefaultUsers(...def.defaultUserIds);
201
+ }
202
+ return builder;
203
+ },
204
+ };
205
+ }
206
+
207
+ /**
208
+ * Wrap a select menu in its own action row. Unlike buttons, Discord gives a
209
+ * select menu a whole row, so there is nothing to group — hence a distinct
210
+ * helper from `createActionRow`.
211
+ */
212
+ export function createSelectRow<B extends AnySelectMenuBuilder, I extends AnySelectMenuInteraction>(
213
+ menu: SelectMenu<B, I>,
214
+ forceDisabled = false,
215
+ ): ActionRowBuilder<B> {
216
+ return new ActionRowBuilder<B>().addComponents(menu.apply(forceDisabled));
217
+ }
218
+
219
+ /**
220
+ * Bridge a select menu's `onSelect` to the persistent
221
+ * {@link import("@/discord/components/component-router").ComponentRouter}.
222
+ *
223
+ * Without this a declared `onSelect` would never run: the router dispatches to a
224
+ * `ComponentHandler`, and nothing else turns an interaction back into the menu
225
+ * that produced it. Register the result through a module's `components`.
226
+ */
227
+ export function createSelectHandler<
228
+ B extends AnySelectMenuBuilder,
229
+ I extends AnySelectMenuInteraction,
230
+ >(menu: SelectMenu<B, I>, authorize: ComponentAuthorization): ComponentHandler {
231
+ return {
232
+ customId: menu.id,
233
+ // Passed in rather than defaulted: this bridge knows nothing about what
234
+ // the menu does, and a default here would be exactly the silent "anyone
235
+ // may click" the required field exists to prevent.
236
+ authorize,
237
+ async handle(interaction) {
238
+ // The router also routes buttons and modals to a matching customId; a
239
+ // menu only speaks for select interactions.
240
+ if (!interaction.isAnySelectMenu()) {
241
+ return;
242
+ }
243
+ await menu.onSelect?.({ interaction: interaction as I, values: interaction.values });
244
+ },
245
+ };
246
+ }
@@ -0,0 +1,57 @@
1
+ import { PermissionFlagsBits, PermissionsBitField } from "discord.js";
2
+
3
+ /**
4
+ * Permission helpers shared by the command DSL, the guards and any adapter that
5
+ * needs to reason about what the bot (or a member) is allowed to do.
6
+ *
7
+ * Everything is expressed in terms of {@link PermissionBit} rather than raw
8
+ * `bigint`s: the values come from discord.js' `PermissionFlagsBits`, so a typo
9
+ * is a type error instead of a silently wrong bitfield.
10
+ */
11
+
12
+ /**
13
+ * A single Discord permission flag. Deriving the type from the enum-like object
14
+ * means the DSL accepts `PermissionFlagsBits.ManageChannels` and rejects an
15
+ * arbitrary `bigint`.
16
+ */
17
+ export type PermissionBit = (typeof PermissionFlagsBits)[keyof typeof PermissionFlagsBits];
18
+
19
+ /** Combine permission flags into the single bitfield Discord's API expects. */
20
+ export function resolvePermissions(permissions: readonly PermissionBit[]): bigint {
21
+ return PermissionsBitField.resolve([...permissions]);
22
+ }
23
+
24
+ /**
25
+ * Bits in `required` that `held` lacks (empty when everything is granted).
26
+ *
27
+ * `held === null` means the permissions could not be resolved (outside a guild,
28
+ * or an uncached member). It returns *all* of `required`: an absent answer must
29
+ * never be mistaken for a granted one.
30
+ */
31
+ export function missingPermissions(
32
+ held: Readonly<PermissionsBitField> | null,
33
+ required: readonly PermissionBit[],
34
+ ): PermissionBit[] {
35
+ if (held === null) {
36
+ return [...required];
37
+ }
38
+ return required.filter((permission) => !held.has(permission));
39
+ }
40
+
41
+ /**
42
+ * Human-readable names for permission bits, for user-facing messages. Resolved
43
+ * by reverse lookup in `PermissionFlagsBits` so the names track discord.js
44
+ * rather than a hand-maintained table that silently rots.
45
+ */
46
+ export function formatPermissions(permissions: readonly PermissionBit[]): string {
47
+ return permissions.map(permissionName).join(", ");
48
+ }
49
+
50
+ function permissionName(permission: PermissionBit): string {
51
+ for (const [name, bit] of Object.entries(PermissionFlagsBits)) {
52
+ if (bit === permission) {
53
+ return name;
54
+ }
55
+ }
56
+ return String(permission);
57
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Two providers registered the same token. Raised while modules register their
3
+ * placeholders at boot — a wiring mistake that must stop the boot, never a
4
+ * runtime condition a guild's rendered text could trigger.
5
+ */
6
+ export class DuplicatePlaceholderTokenError extends Error {
7
+ constructor(readonly token: string) {
8
+ super(`Placeholder token "${token}" is registered twice`);
9
+ this.name = "DuplicatePlaceholderTokenError";
10
+ }
11
+ }
@@ -0,0 +1,77 @@
1
+ import { DuplicatePlaceholderTokenError } from "@/discord/placeholder-registry-errors";
2
+ import type { Locale } from "@/i18n";
3
+
4
+ /**
5
+ * A token a module offers to text another module's administrator writes,
6
+ * resolved only once that text is actually rendered.
7
+ *
8
+ * `core` sits between the two by design: a module that publishes a token
9
+ * (`tournament`'s `{tournament_template}`) and a module that renders text
10
+ * carrying it (`ticket`'s welcome message) never import each other —
11
+ * `AGENTS.md` forbids it. Both go through {@link PlaceholderRegistry} instead,
12
+ * which `bootstrap` hands to every module factory from the same container-held
13
+ * instance, so neither module ever names the other.
14
+ */
15
+ export interface PlaceholderProvider {
16
+ /** The token, braces included — `{tournament_template}`. */
17
+ readonly token: string;
18
+ /** What it becomes, for one guild, at render time. */
19
+ resolve(guildId: string, locale: Locale): Promise<string>;
20
+ /**
21
+ * Catalog key describing this token in the legend an admin reads while
22
+ * writing the text — owned by the module that offers the token, since it is
23
+ * the only one that knows what the token means.
24
+ */
25
+ readonly legendKey: string;
26
+ }
27
+
28
+ /**
29
+ * Accumulates every {@link PlaceholderProvider} registered at boot and resolves
30
+ * them against a piece of already-rendered text.
31
+ *
32
+ * Consulted at render, never at construction — that is what makes the order
33
+ * `bootstrap/modules.ts` lists modules in irrelevant here: a module registers
34
+ * into this from its own factory, whatever position it holds in that list, and
35
+ * `resolve` only ever reads the registry as it stands by the time some guild's
36
+ * text is actually rendered — well after every module has finished
37
+ * registering, unlike `ChannelExporter` (`bootstrap/channel-exporter.ts`),
38
+ * which has to be built with the enabled module list already known.
39
+ */
40
+ export class PlaceholderRegistry {
41
+ private readonly providers: PlaceholderProvider[] = [];
42
+
43
+ /** @throws DuplicatePlaceholderTokenError — a boot-time wiring mistake. */
44
+ register(provider: PlaceholderProvider): void {
45
+ if (this.providers.some((existing) => existing.token === provider.token)) {
46
+ throw new DuplicatePlaceholderTokenError(provider.token);
47
+ }
48
+ this.providers.push(provider);
49
+ }
50
+
51
+ /** Every registered provider, in registration order — for building a legend. */
52
+ list(): readonly PlaceholderProvider[] {
53
+ return this.providers;
54
+ }
55
+
56
+ /** The token every registered provider answers to. */
57
+ tokens(): readonly string[] {
58
+ return this.providers.map((provider) => provider.token);
59
+ }
60
+
61
+ /**
62
+ * Replace every registered token `text` carries with what it resolves to for
63
+ * `guildId`/`locale`. A provider whose token is absent from `text` is never
64
+ * asked to resolve — the common case, since one guild's text rarely uses
65
+ * every token every module has ever registered.
66
+ */
67
+ async resolve(text: string, guildId: string, locale: Locale): Promise<string> {
68
+ let result = text;
69
+ for (const provider of this.providers) {
70
+ if (result.includes(provider.token)) {
71
+ const value = await provider.resolve(guildId, locale);
72
+ result = result.split(provider.token).join(value);
73
+ }
74
+ }
75
+ return result;
76
+ }
77
+ }
@@ -0,0 +1,26 @@
1
+ import type { EmbedBuilder } from "discord.js";
2
+ import type { Locale } from "@/i18n";
3
+
4
+ /**
5
+ * Port that renders framework-level responses (errors, denials, confirmations)
6
+ * as embeds. The command pipeline depends on this interface, never on a concrete
7
+ * embed module — so a bot can fully restyle/localise feedback by providing its
8
+ * own implementation, with zero changes to the core.
9
+ *
10
+ * Every method receives the locale resolved for the interaction being answered,
11
+ * so titles and fixed copy follow the user's language, not the process's.
12
+ *
13
+ * The default implementation lives in `infrastructure/discord/default-presenter.ts`.
14
+ */
15
+ export interface Presenter {
16
+ /** A successful, affirmative action. */
17
+ confirmation(message: string, locale: Locale): EmbedBuilder;
18
+ /** A benign business problem (bad input, missing resource, conflict). */
19
+ warning(message: string, locale: Locale): EmbedBuilder;
20
+ /** A serious—but expected—business error. */
21
+ error(message: string, locale: Locale): EmbedBuilder;
22
+ /** An authorization denial from a guard. */
23
+ denial(message: string, locale: Locale): EmbedBuilder;
24
+ /** An unexpected failure, carrying a quotable incident reference. */
25
+ systemError(message: string, reference: string, locale: Locale): EmbedBuilder;
26
+ }