@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,290 @@
1
+ import type { ChannelType } from "discord.js";
2
+ import type { TextFieldStyleName } from "@/discord/interaction/modal";
3
+ import type { TranslationParams } from "@/i18n";
4
+
5
+ /**
6
+ * How a field is entered.
7
+ *
8
+ * `image` is the only typed one that differs: it offers a file upload beside the
9
+ * address box, because an administrator should not have to host a picture
10
+ * somewhere before the bot will show it.
11
+ *
12
+ * `role`, `category`, `user`, `channel` and `choice` are picked rather than
13
+ * typed — see {@link SettingsEditorPickerField}.
14
+ */
15
+ export type SettingsEditorFieldKind =
16
+ | "text"
17
+ | "image"
18
+ | "level"
19
+ | "role"
20
+ | "category"
21
+ | "user"
22
+ | "channel"
23
+ | "choice";
24
+
25
+ /**
26
+ * What every menu entry states, whatever picking it does.
27
+ *
28
+ * `hintKey` is required rather than optional on purpose: an entry the reader
29
+ * cannot tell apart from its neighbours is the very problem these screens exist
30
+ * to solve, so a declaration without one does not typecheck.
31
+ */
32
+ interface SettingsEditorEntry<F extends string> {
33
+ readonly key: F;
34
+ readonly labelKey: string;
35
+ /** Shown under the label in the menu — what this field controls, in one line. */
36
+ readonly hintKey: string;
37
+ /**
38
+ * The emoji a card layout's own button wears for this entry, in place of the
39
+ * generic one `mount-settings-editor.ts` would otherwise pick from the
40
+ * entry's own kind — a pencil for something edited, an arrow for a level
41
+ * descended into. Declared only where the generic would lie: an entry that
42
+ * opens a modal to *create* something reads wrong under a pencil, the icon
43
+ * for changing what already exists. Left undeclared, which is most entries,
44
+ * the generic stands exactly as it did before this existed.
45
+ */
46
+ readonly icon?: string;
47
+ }
48
+
49
+ /**
50
+ * An entry that goes somewhere rather than editing anything: picking it descends
51
+ * into `levelKey`, and the return control comes back.
52
+ *
53
+ * It declares no modal geometry because it opens no modal — which the union
54
+ * below enforces rather than leaving to a comment.
55
+ */
56
+ export interface SettingsEditorLevelField<F extends string> extends SettingsEditorEntry<F> {
57
+ readonly kind: "level";
58
+ readonly levelKey: string;
59
+ }
60
+
61
+ /**
62
+ * One editable field of a customisable embed: what it is called, what editing it
63
+ * looks like, and what it is allowed to hold.
64
+ *
65
+ * Pure data, deliberately: both screens declare their fields as a constant list,
66
+ * which is what lets the menu, the modal and the notices be built from one
67
+ * declaration instead of three that have to agree.
68
+ */
69
+ export interface SettingsEditorValueField<F extends string> extends SettingsEditorEntry<F> {
70
+ readonly kind: "text" | "image";
71
+ readonly style: TextFieldStyleName;
72
+ /**
73
+ * Stops an over-long value at the client instead of rejecting it after the
74
+ * round trip. The domain parsers still enforce the real limit: this one is
75
+ * capped by what a modal input can carry at all.
76
+ */
77
+ readonly maxLength: number;
78
+ /**
79
+ * Replaces the generic "leave empty to clear" helper under the box, for a
80
+ * field whose empty case means something of its own.
81
+ */
82
+ readonly helperKey?: string;
83
+ /**
84
+ * The upload cap the helper text states, in MiB. Declared by the screen
85
+ * because the limit is the caller's own — the editor neither enforces it nor
86
+ * knows what is being stored.
87
+ */
88
+ readonly uploadMaxMib?: number;
89
+ /** Greyed-out example inside the box — the welcome message's token list. */
90
+ readonly placeholderKey?: string;
91
+ readonly placeholderParams?: TranslationParams;
92
+ }
93
+
94
+ /** What every picked entry states, whichever list it is picked from. */
95
+ interface SettingsEditorPickerEntry<F extends string> extends SettingsEditorEntry<F> {
96
+ /** How many may be picked at once. One unless the screen says otherwise. */
97
+ readonly maxValues?: number;
98
+ /** Zero lets the picker clear the setting; one makes it mandatory. */
99
+ readonly minValues?: number;
100
+ /** Shown inside the picker before anything is chosen. */
101
+ readonly pickerPlaceholderKey?: string;
102
+ }
103
+
104
+ /**
105
+ * An entry picked from a list Discord populates itself — a role, a member, or a
106
+ * category channel.
107
+ *
108
+ * `category` is the shorthand for the one channel shape a screen keeps asking
109
+ * for; anything else states its own types through
110
+ * {@link SettingsEditorChannelField}.
111
+ */
112
+ export interface SettingsEditorEntityField<F extends string> extends SettingsEditorPickerEntry<F> {
113
+ readonly kind: "role" | "category" | "user";
114
+ }
115
+
116
+ /** An entry picked from the guild's channels, narrowed to the types it names. */
117
+ export interface SettingsEditorChannelField<F extends string> extends SettingsEditorPickerEntry<F> {
118
+ readonly kind: "channel";
119
+ /**
120
+ * Required rather than optional: a channel picker offering every kind in the
121
+ * guild for a setting that only accepts one of them invites a choice the write
122
+ * then refuses.
123
+ */
124
+ readonly channelTypes: readonly ChannelType[];
125
+ }
126
+
127
+ /** One option of a {@link SettingsEditorChoiceField}. */
128
+ export interface SettingsEditorChoice {
129
+ /** What is stored — never shown, so it is not translated. */
130
+ readonly value: string;
131
+ readonly labelKey: string;
132
+ /** Shown under the label, as a menu entry's hint is. Optional: a two-way toggle rarely needs one. */
133
+ readonly descriptionKey?: string;
134
+ }
135
+
136
+ /**
137
+ * An entry picked from a list the screen itself declares — a visibility mode, a
138
+ * weekday.
139
+ *
140
+ * The command layer expresses these as `createStringOption().choices(...)`, and
141
+ * a setting that had a closed set of values when it was a command still has one
142
+ * once it moves behind a screen. Typing the value back into a modal would turn a
143
+ * guaranteed-valid pick into a spelling test whose only feedback is a refusal.
144
+ */
145
+ export interface SettingsEditorChoiceField<F extends string> extends SettingsEditorPickerEntry<F> {
146
+ readonly kind: "choice";
147
+ readonly choices: readonly SettingsEditorChoice[];
148
+ }
149
+
150
+ /**
151
+ * An entry whose value is picked rather than typed.
152
+ *
153
+ * A modal carries text inputs only and cannot be changed once open, so a role, a
154
+ * member, a channel or one of a closed set of values has to be chosen from a
155
+ * component. Declaring the kind rather than wiring each picker by hand keeps the
156
+ * one-declaration property: a field cannot appear in the menu with no way to
157
+ * edit it.
158
+ *
159
+ * It states no modal geometry, for the same reason a level does not.
160
+ */
161
+ export type SettingsEditorPickerField<F extends string> =
162
+ | SettingsEditorEntityField<F>
163
+ | SettingsEditorChannelField<F>
164
+ | SettingsEditorChoiceField<F>;
165
+
166
+ /**
167
+ * An entry that asks for several settings at once, in a single modal — a
168
+ * tournament's announcement message, colour, image and footer, which read as
169
+ * one decision rather than four.
170
+ *
171
+ * Its member fields are declared *inside* the group rather than as menu
172
+ * entries of their own: that is what keeps the repository's "one declaration"
173
+ * property — each member still owns the single `key` `currentValue` and the
174
+ * write are named by, it is only the menu that no longer lists it separately.
175
+ *
176
+ * A level that reduces to a single group is not a level: per the rule this
177
+ * repository already states for `COMMS_AREA_FIELDS` ("a domain that carries a
178
+ * single setting *is* that setting, not a level"), a group replaces the level
179
+ * outright rather than being offered as its lone entry.
180
+ */
181
+ export interface SettingsEditorGroupField<F extends string> extends SettingsEditorEntry<F> {
182
+ readonly kind: "group";
183
+ /** The settings this modal asks for, in the order it poses them. */
184
+ readonly fields: readonly (SettingsEditorValueField<F> | SettingsEditorPickerField<F>)[];
185
+ }
186
+
187
+ /**
188
+ * A menu entry: either something to edit, or somewhere to go.
189
+ *
190
+ * Kept as one union so a level and a field are declared side by side in the same
191
+ * list, in the order the menu offers them — the screen's shape is one constant,
192
+ * not a field list plus a navigation table that could disagree about ordering.
193
+ */
194
+ export type SettingsEditorField<F extends string> =
195
+ | SettingsEditorValueField<F>
196
+ | SettingsEditorPickerField<F>
197
+ | SettingsEditorLevelField<F>
198
+ | SettingsEditorGroupField<F>;
199
+
200
+ /** Whether this entry is typed — a text box or an image upload — rather than picked. */
201
+ export function isValueField<F extends string>(
202
+ field: SettingsEditorField<F>,
203
+ ): field is SettingsEditorValueField<F> {
204
+ return field.kind === "text" || field.kind === "image";
205
+ }
206
+
207
+ /**
208
+ * Whether this entry is picked from a list rather than typed.
209
+ *
210
+ * Both shapes open a modal; this only decides which geometry it opens with — a
211
+ * role/user/channel select or a string select, prefilled from the current
212
+ * selection, in place of a text input.
213
+ */
214
+ export function isPickerField<F extends string>(
215
+ field: SettingsEditorField<F>,
216
+ ): field is SettingsEditorPickerField<F> {
217
+ return (
218
+ field.kind === "role" ||
219
+ field.kind === "category" ||
220
+ field.kind === "user" ||
221
+ field.kind === "channel" ||
222
+ field.kind === "choice"
223
+ );
224
+ }
225
+
226
+ /** Whether this entry opens a modal asking for several settings at once. */
227
+ export function isGroupField<F extends string>(
228
+ field: SettingsEditorField<F>,
229
+ ): field is SettingsEditorGroupField<F> {
230
+ return field.kind === "group";
231
+ }
232
+
233
+ /** The stored value of one field, as the modal editing it opens on. */
234
+ export interface SettingsEditorFieldValue {
235
+ /** Prefills the text input; `null` when there is nothing to type back. */
236
+ readonly text: string | null;
237
+ /**
238
+ * Whether the field currently holds an upload. Discord cannot prefill a file
239
+ * input, so the modal says so in words instead of opening on a blank that
240
+ * reads like nothing being set.
241
+ */
242
+ readonly uploaded: boolean;
243
+ /** The identifiers a picker field currently carries. Empty for a field that is not picked. */
244
+ readonly picked: readonly string[];
245
+ }
246
+
247
+ /** A text override, as the modal editing it opens on. */
248
+ export function textFieldValue(value: string | null): SettingsEditorFieldValue {
249
+ return { text: value, uploaded: false, picked: [] };
250
+ }
251
+
252
+ /** A picker override, as the modal editing it opens on — prefilled from what it already holds. */
253
+ export function pickedFieldValue(ids: readonly string[]): SettingsEditorFieldValue {
254
+ return { text: null, uploaded: false, picked: ids };
255
+ }
256
+
257
+ /** Discord's own cap on a modal text input, whatever the embed itself would take. */
258
+ export const MAX_MODAL_INPUT_LENGTH = 4000;
259
+
260
+ /**
261
+ * Discord's own cap on a modal's top-level components: "between 1 and 5
262
+ * (inclusive) components that make up the modal" (Discord's interaction
263
+ * callback data reference). A group's member fields count against it one for
264
+ * one — each becomes a `Label` — and so does the legend a group's modal may
265
+ * carry, via a `TextDisplay`.
266
+ */
267
+ export const MAX_MODAL_COMPONENTS = 5;
268
+
269
+ /** Whether a value picked from the menu is one of the fields a screen declared. */
270
+ export function isEditorField<F extends string>(
271
+ fields: readonly SettingsEditorField<F>[],
272
+ value: string,
273
+ ): value is F {
274
+ return fields.some((field) => field.key === value);
275
+ }
276
+
277
+ /** The declaration of one field, by key. */
278
+ export function editorField<F extends string>(
279
+ fields: readonly SettingsEditorField<F>[],
280
+ key: F,
281
+ ): SettingsEditorField<F> {
282
+ const found = fields.find((field) => field.key === key);
283
+ if (found === undefined) {
284
+ // Unreachable: a key only ever reaches here after `isEditorField` matched
285
+ // it against this very list. Kept because nothing in the types ties the two
286
+ // calls together.
287
+ throw new Error(`No editable field declared under "${key}"`);
288
+ }
289
+ return found;
290
+ }