@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,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_CARD_TEXT_CHARACTERS = exports.MAX_CARD_COMPONENTS = void 0;
4
+ exports.createCard = createCard;
5
+ const discord_js_1 = require("discord.js");
6
+ const button_1 = require("../../discord/interaction/button");
7
+ /** Discord refuses a message carrying more components than this, container included. */
8
+ exports.MAX_CARD_COMPONENTS = 40;
9
+ /** Discord's cap on the characters carried by every `TextDisplay` in a message, summed. */
10
+ exports.MAX_CARD_TEXT_CHARACTERS = 4000;
11
+ /**
12
+ * The text an `entry` block renders, whether it ends up alone in a
13
+ * `TextDisplay` or riding along inside a `Section`.
14
+ *
15
+ * Composed as one `TextDisplay` — the title in bold, then each line on its
16
+ * own row — rather than one `TextDisplay` per line: a `Section` holds at
17
+ * most three text children, so a title plus more than two lines would
18
+ * already be out of room, and a single block reads as one paragraph instead
19
+ * of a list of unrelated fragments.
20
+ */
21
+ function entryContent(block) {
22
+ const lines = block.lines ?? [];
23
+ return lines.length === 0 ? `**${block.title}**` : `**${block.title}**\n${lines.join("\n")}`;
24
+ }
25
+ /** How many characters of the 4000-character `TextDisplay` budget a block spends. */
26
+ function textCharacters(block) {
27
+ if (block.kind === "text") {
28
+ return block.content.length;
29
+ }
30
+ if (block.kind === "entry") {
31
+ return entryContent(block).length;
32
+ }
33
+ return 0;
34
+ }
35
+ /** How many components a block compiles to, container itself excluded. */
36
+ function componentCount(block) {
37
+ switch (block.kind) {
38
+ case "text":
39
+ return 1;
40
+ case "entry":
41
+ // No accessory: one `TextDisplay`. Either accessory: the `Section`
42
+ // itself, its one `TextDisplay` child, and the accessory — three.
43
+ return block.action !== undefined || block.thumbnail !== undefined ? 3 : 1;
44
+ case "controls":
45
+ // The `ActionRow` plus every button it carries.
46
+ return 1 + block.buttons.length;
47
+ case "select":
48
+ // The `ActionRow` plus the menu itself.
49
+ return 2;
50
+ case "separator":
51
+ return 1;
52
+ case "gallery":
53
+ // Discord counts the gallery as one component; its items are data on
54
+ // it, not components of their own, the same way an embed's fields
55
+ // are not counted individually.
56
+ return 1;
57
+ }
58
+ }
59
+ /**
60
+ * Refuse a card Discord would refuse, naming what is over budget and by how
61
+ * much — the pattern `settings-editor.view.ts` (`assertFits`) already uses
62
+ * for a select menu's option cap. Checked once, at `createCard`, rather than
63
+ * at `apply()`: the block list does not vary with state, so failing here
64
+ * names the declaration instead of surfacing as a rejected message at
65
+ * whichever render happens to trip it first.
66
+ */
67
+ function assertFitsBudget(blocks) {
68
+ // +1 for the container itself, which is a component in its own right.
69
+ const totalComponents = 1 + blocks.reduce((sum, block) => sum + componentCount(block), 0);
70
+ const totalCharacters = blocks.reduce((sum, block) => sum + textCharacters(block), 0);
71
+ const problems = [];
72
+ if (totalComponents > exports.MAX_CARD_COMPONENTS) {
73
+ problems.push(`${totalComponents} components (container included), Discord allows ${exports.MAX_CARD_COMPONENTS} — ${totalComponents - exports.MAX_CARD_COMPONENTS} over`);
74
+ }
75
+ if (totalCharacters > exports.MAX_CARD_TEXT_CHARACTERS) {
76
+ problems.push(`${totalCharacters} characters across its text, Discord allows ${exports.MAX_CARD_TEXT_CHARACTERS} — ${totalCharacters - exports.MAX_CARD_TEXT_CHARACTERS} over`);
77
+ }
78
+ if (problems.length > 0) {
79
+ throw new Error(`Card exceeds Discord's budget: ${problems.join("; ")}.`);
80
+ }
81
+ }
82
+ /** Render one `entry` block: a `Section` with an accessory, or a bare `TextDisplay`. */
83
+ function applyEntry(container, block, state, forceDisabled) {
84
+ const text = new discord_js_1.TextDisplayBuilder().setContent(entryContent(block));
85
+ if (block.action !== undefined) {
86
+ container.addSectionComponents(new discord_js_1.SectionBuilder()
87
+ .addTextDisplayComponents(text)
88
+ .setButtonAccessory(block.action.apply(state, forceDisabled)));
89
+ return;
90
+ }
91
+ if (block.thumbnail !== undefined) {
92
+ container.addSectionComponents(new discord_js_1.SectionBuilder()
93
+ .addTextDisplayComponents(text)
94
+ .setThumbnailAccessory(new discord_js_1.ThumbnailBuilder().setURL(block.thumbnail)));
95
+ return;
96
+ }
97
+ container.addTextDisplayComponents(text);
98
+ }
99
+ /** Render one block onto the container being built, for the given state. */
100
+ function applyBlock(container, block, state, forceDisabled) {
101
+ switch (block.kind) {
102
+ case "text":
103
+ container.addTextDisplayComponents(new discord_js_1.TextDisplayBuilder().setContent(block.content));
104
+ return;
105
+ case "entry":
106
+ applyEntry(container, block, state, forceDisabled);
107
+ return;
108
+ case "controls":
109
+ container.addActionRowComponents((0, button_1.createActionRow)([...block.buttons], state, { disableAll: forceDisabled }));
110
+ return;
111
+ case "select":
112
+ container.addActionRowComponents(new discord_js_1.ActionRowBuilder().addComponents(block.menu.apply(forceDisabled)));
113
+ return;
114
+ case "separator": {
115
+ const separator = new discord_js_1.SeparatorBuilder();
116
+ if (block.spacing !== undefined) {
117
+ separator.setSpacing(block.spacing === "large" ? discord_js_1.SeparatorSpacingSize.Large : discord_js_1.SeparatorSpacingSize.Small);
118
+ }
119
+ if (block.divider !== undefined) {
120
+ separator.setDivider(block.divider);
121
+ }
122
+ container.addSeparatorComponents(separator);
123
+ return;
124
+ }
125
+ case "gallery":
126
+ container.addMediaGalleryComponents(new discord_js_1.MediaGalleryBuilder().addItems(...block.images.map((image) => {
127
+ const item = new discord_js_1.MediaGalleryItemBuilder().setURL(image.url);
128
+ if (image.description !== undefined) {
129
+ item.setDescription(image.description);
130
+ }
131
+ if (image.spoiler !== undefined) {
132
+ item.setSpoiler(image.spoiler);
133
+ }
134
+ return item;
135
+ })));
136
+ return;
137
+ }
138
+ }
139
+ /**
140
+ * Declare a card: a definition compiling to a `ContainerBuilder`, the
141
+ * Components V2 analogue of an embed. Follows the same split as
142
+ * `createButton`/`createModal`/`createStringSelect` — data in, a compiled
143
+ * value with an `apply` out — so a caller never touches a V2 builder
144
+ * directly.
145
+ */
146
+ function createCard(def) {
147
+ const blocks = def.blocks.filter((block) => block !== null);
148
+ assertFitsBudget(blocks);
149
+ return {
150
+ apply(state, forceDisabled = false) {
151
+ const container = new discord_js_1.ContainerBuilder();
152
+ if (def.accent !== undefined) {
153
+ container.setAccentColor(def.accent);
154
+ }
155
+ for (const block of blocks) {
156
+ applyBlock(container, block, state, forceDisabled);
157
+ }
158
+ return container;
159
+ },
160
+ };
161
+ }
162
+ //# sourceMappingURL=card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.js","sourceRoot":"","sources":["../../../src/discord/ui/card.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * A bot registered a colour name longer than the field an administrator types
3
+ * it into. Raised while the composition root registers its aliases at boot —
4
+ * the alternative is a name Discord silently truncates, which then never
5
+ * resolves and looks like the parser rejecting a colour it actually knows.
6
+ */
7
+ export declare class ColorAliasTooLongError extends Error {
8
+ readonly alias: string;
9
+ readonly maxLength: number;
10
+ constructor(alias: string, maxLength: number);
11
+ }
12
+ //# sourceMappingURL=color-input-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-input-errors.d.ts","sourceRoot":"","sources":["../../../src/discord/ui/color-input-errors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;IAE/C,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM;gBADjB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM;CAO3B"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ColorAliasTooLongError = void 0;
4
+ /**
5
+ * A bot registered a colour name longer than the field an administrator types
6
+ * it into. Raised while the composition root registers its aliases at boot —
7
+ * the alternative is a name Discord silently truncates, which then never
8
+ * resolves and looks like the parser rejecting a colour it actually knows.
9
+ */
10
+ class ColorAliasTooLongError extends Error {
11
+ alias;
12
+ maxLength;
13
+ constructor(alias, maxLength) {
14
+ super(`Colour alias "${alias}" is ${alias.length} characters, over the ${maxLength} the input field accepts`);
15
+ this.alias = alias;
16
+ this.maxLength = maxLength;
17
+ this.name = "ColorAliasTooLongError";
18
+ }
19
+ }
20
+ exports.ColorAliasTooLongError = ColorAliasTooLongError;
21
+ //# sourceMappingURL=color-input-errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-input-errors.js","sourceRoot":"","sources":["../../../src/discord/ui/color-input-errors.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,MAAa,sBAAuB,SAAQ,KAAK;IAEtC;IACA;IAFV,YACU,KAAa,EACb,SAAiB;QAE1B,KAAK,CACJ,iBAAiB,KAAK,QAAQ,KAAK,CAAC,MAAM,yBAAyB,SAAS,0BAA0B,CACtG,CAAC;QALO,UAAK,GAAL,KAAK,CAAQ;QACb,cAAS,GAAT,SAAS,CAAQ;QAK1B,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACtC,CAAC;CACD;AAVD,wDAUC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Every name a lookup answers to: the kernel's own, plus whatever the bot
3
+ * registered. Exposed for inspection — a screen listing the colours it accepts
4
+ * reads this — never for mutation, which goes through
5
+ * {@link registerColorAliases} so the length check cannot be skipped.
6
+ */
7
+ export declare const COLOR_ALIASES: Readonly<Record<string, string>>;
8
+ /**
9
+ * What a colour input field may hold.
10
+ *
11
+ * Derived from the built-in table rather than written down, so adding a longer
12
+ * name here cannot leave the field silently truncating it at the client — and
13
+ * fixed rather than recomputed on registration, because field definitions read
14
+ * it once at module load, long before a bot registers anything.
15
+ */
16
+ export declare const MAX_COLOR_INPUT_LENGTH: number;
17
+ /**
18
+ * Teach the parser the colours this bot calls by name — its brand gold, its
19
+ * team colours — from the composition root, before any module is constructed.
20
+ *
21
+ * A name over {@link MAX_COLOR_INPUT_LENGTH} is refused rather than accepted:
22
+ * the input field is already sized, so registering a longer name would let an
23
+ * administrator type a colour the client cuts short, which then reads as the
24
+ * parser rejecting a name it actually knows.
25
+ *
26
+ * @throws ColorAliasTooLongError when a name cannot fit the input field.
27
+ */
28
+ export declare function registerColorAliases(aliases: Readonly<Record<string, string>>): void;
29
+ /**
30
+ * Normalize a colour input to `#RRGGBB`, from a hexadecimal code or from one of
31
+ * the names in {@link COLOR_ALIASES} — an administrator picking a colour should
32
+ * not have to look a hex code up. `null` for anything that is neither: the
33
+ * refusal an administrator reads belongs to whichever screen asked, so core
34
+ * reports that it could not read the value and leaves the wording to the caller.
35
+ */
36
+ export declare function parseColorInput(raw: string): string | null;
37
+ //# sourceMappingURL=color-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-input.d.ts","sourceRoot":"","sources":["../../../src/discord/ui/color-input.ts"],"names":[],"mappings":"AAgGA;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAE1D,CAAC;AAcF;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,QAGlC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,CAWpF;AAKD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAa1D"}
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_COLOR_INPUT_LENGTH = exports.COLOR_ALIASES = void 0;
4
+ exports.registerColorAliases = registerColorAliases;
5
+ exports.parseColorInput = parseColorInput;
6
+ const color_input_errors_1 = require("../../discord/ui/color-input-errors");
7
+ const colors_1 = require("../../discord/ui/colors");
8
+ /**
9
+ * The generic web colours, at the value the name carries everywhere else — an
10
+ * administrator typing `orange` gets the orange they would get in CSS, not a
11
+ * shade this module invented.
12
+ */
13
+ const RED = "#ff0000";
14
+ const BLUE = "#0000ff";
15
+ const GREEN = "#008000";
16
+ const YELLOW = "#ffff00";
17
+ const ORANGE = "#ffa500";
18
+ const PURPLE = "#800080";
19
+ const PINK = "#ffc0cb";
20
+ const WHITE = "#ffffff";
21
+ /**
22
+ * Not `#000000`: Discord reads a zero colour as "no colour set" and renders the
23
+ * default grey bar instead, so pure black is the one value an administrator
24
+ * could ask for and never see. One step off zero reads as black.
25
+ */
26
+ const BLACK = "#010101";
27
+ const GREY = "#808080";
28
+ const CYAN = "#00ffff";
29
+ const BROWN = "#a52a2a";
30
+ const SILVER = "#c0c0c0";
31
+ const TURQUOISE = "#40e0d0";
32
+ const MAGENTA = "#ff00ff";
33
+ const NAVY = "#000080";
34
+ /**
35
+ * Colour names an administrator may type instead of a hex code, French and
36
+ * English side by side.
37
+ *
38
+ * This table is **input vocabulary, not display text**. Nothing in it is ever
39
+ * shown to anyone, and its keys must never be translated at runtime: a catalog
40
+ * lookup resolves against the reply locale, which would make `rouge` stop
41
+ * working the moment an admin's Discord is set to English — the opposite of the
42
+ * point. Both spellings are accepted from everyone, always, which only a flat
43
+ * table can promise.
44
+ *
45
+ * These are the names the kernel ships. A bot adds its own — the colour it
46
+ * calls by its brand's name — through {@link registerColorAliases}, which is
47
+ * also why this table is not the one lookups read: {@link COLOR_ALIASES} is.
48
+ */
49
+ const BUILT_IN_COLOR_ALIASES = {
50
+ red: RED,
51
+ rouge: RED,
52
+ blue: BLUE,
53
+ bleu: BLUE,
54
+ green: GREEN,
55
+ vert: GREEN,
56
+ yellow: YELLOW,
57
+ jaune: YELLOW,
58
+ orange: ORANGE,
59
+ purple: PURPLE,
60
+ // French for purple, not the CSS `violet` (a pale pink): an admin typing it
61
+ // here is asking for the colour the word means in their own language.
62
+ violet: PURPLE,
63
+ pink: PINK,
64
+ rose: PINK,
65
+ white: WHITE,
66
+ blanc: WHITE,
67
+ black: BLACK,
68
+ noir: BLACK,
69
+ grey: GREY,
70
+ gray: GREY,
71
+ gris: GREY,
72
+ cyan: CYAN,
73
+ brown: BROWN,
74
+ marron: BROWN,
75
+ silver: SILVER,
76
+ argent: SILVER,
77
+ argenté: SILVER,
78
+ turquoise: TURQUOISE,
79
+ magenta: MAGENTA,
80
+ navy: NAVY,
81
+ marine: NAVY,
82
+ blurple: colors_1.DISCORD_BLURPLE,
83
+ };
84
+ /**
85
+ * Accents must not be a trap: `dore` and `doré` are the same request, and an
86
+ * administrator has no way of knowing which one this file happened to spell.
87
+ * Case and surrounding whitespace are folded for the same reason.
88
+ */
89
+ function normalizeColorName(raw) {
90
+ return raw
91
+ .trim()
92
+ .toLowerCase()
93
+ .normalize("NFD")
94
+ .replace(/\p{Diacritic}/gu, "");
95
+ }
96
+ /**
97
+ * Every name a lookup answers to: the kernel's own, plus whatever the bot
98
+ * registered. Exposed for inspection — a screen listing the colours it accepts
99
+ * reads this — never for mutation, which goes through
100
+ * {@link registerColorAliases} so the length check cannot be skipped.
101
+ */
102
+ exports.COLOR_ALIASES = {
103
+ ...BUILT_IN_COLOR_ALIASES,
104
+ };
105
+ const COLORS_BY_NORMALIZED_NAME = new Map(Object.entries(exports.COLOR_ALIASES).map(([name, hex]) => [normalizeColorName(name), hex]));
106
+ /** The `#rrggbb` a recognised colour name stands for, `null` for anything else. */
107
+ function resolveNamedColor(raw) {
108
+ return COLORS_BY_NORMALIZED_NAME.get(normalizeColorName(raw)) ?? null;
109
+ }
110
+ /** `#RRGGBB` — the longest hexadecimal form the parser accepts. */
111
+ const HEX_INPUT_LENGTH = 7;
112
+ /**
113
+ * What a colour input field may hold.
114
+ *
115
+ * Derived from the built-in table rather than written down, so adding a longer
116
+ * name here cannot leave the field silently truncating it at the client — and
117
+ * fixed rather than recomputed on registration, because field definitions read
118
+ * it once at module load, long before a bot registers anything.
119
+ */
120
+ exports.MAX_COLOR_INPUT_LENGTH = Math.max(HEX_INPUT_LENGTH, ...Object.keys(BUILT_IN_COLOR_ALIASES).map((name) => name.length));
121
+ /**
122
+ * Teach the parser the colours this bot calls by name — its brand gold, its
123
+ * team colours — from the composition root, before any module is constructed.
124
+ *
125
+ * A name over {@link MAX_COLOR_INPUT_LENGTH} is refused rather than accepted:
126
+ * the input field is already sized, so registering a longer name would let an
127
+ * administrator type a colour the client cuts short, which then reads as the
128
+ * parser rejecting a name it actually knows.
129
+ *
130
+ * @throws ColorAliasTooLongError when a name cannot fit the input field.
131
+ */
132
+ function registerColorAliases(aliases) {
133
+ for (const [name, hex] of Object.entries(aliases)) {
134
+ if (name.length > exports.MAX_COLOR_INPUT_LENGTH) {
135
+ throw new color_input_errors_1.ColorAliasTooLongError(name, exports.MAX_COLOR_INPUT_LENGTH);
136
+ }
137
+ // Both views are written: the table is what a screen lists, the map is what
138
+ // a lookup reads, and a name present in one but not the other would be a
139
+ // colour the bot advertises and refuses.
140
+ exports.COLOR_ALIASES[name] = hex;
141
+ COLORS_BY_NORMALIZED_NAME.set(normalizeColorName(name), hex);
142
+ }
143
+ }
144
+ /** Discord accepts `#RGB` and `#RRGGBB`, with or without the leading hash. */
145
+ const HEX_COLOR_PATTERN = /^#?(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
146
+ /**
147
+ * Normalize a colour input to `#RRGGBB`, from a hexadecimal code or from one of
148
+ * the names in {@link COLOR_ALIASES} — an administrator picking a colour should
149
+ * not have to look a hex code up. `null` for anything that is neither: the
150
+ * refusal an administrator reads belongs to whichever screen asked, so core
151
+ * reports that it could not read the value and leaves the wording to the caller.
152
+ */
153
+ function parseColorInput(raw) {
154
+ const value = raw.trim();
155
+ const named = resolveNamedColor(value);
156
+ if (named !== null) {
157
+ return named;
158
+ }
159
+ if (!HEX_COLOR_PATTERN.test(value)) {
160
+ return null;
161
+ }
162
+ const digits = value.replace("#", "").toLowerCase();
163
+ const expanded = digits.length === 3 ? [...digits].map((digit) => `${digit}${digit}`).join("") : digits;
164
+ return `#${expanded}`;
165
+ }
166
+ //# sourceMappingURL=color-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color-input.js","sourceRoot":"","sources":["../../../src/discord/ui/color-input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The five roles an embed colour can play. A bot restyles by supplying its own
3
+ * values for these, never by adding a sixth: a role the kernel does not know is
4
+ * a module's own constant, not a theme entry.
5
+ */
6
+ export interface EmbedColors {
7
+ success: number;
8
+ warning: number;
9
+ danger: number;
10
+ /** The bot's own identity, for embeds that should not read as Discord's. */
11
+ brand: number;
12
+ /** Neutral informational embeds — listings, recaps, previews. */
13
+ neutral: number;
14
+ }
15
+ /** Convert a `#rrggbb` string to the integer discord.js wants for `setColor`. */
16
+ export declare function toDiscordColor(hex: string): number;
17
+ /** Discord's own brand colour, the fallback for a bot that declares no palette. */
18
+ export declare const DISCORD_BLURPLE = "#5865f2";
19
+ /**
20
+ * What every embed renders as until the composition root says otherwise. Kept
21
+ * deliberately unbranded: a kernel that shipped one bot's colours would make
22
+ * every other bot start out wearing them.
23
+ */
24
+ export declare const DEFAULT_EMBED_COLORS: Readonly<EmbedColors>;
25
+ /**
26
+ * The live palette every embed reads, in the kernel and in the modules alike.
27
+ *
28
+ * This is the one piece of module-level state the kernel keeps, and it is a
29
+ * deliberate exception to "DI, no singletons". A colour is read deep inside pure
30
+ * view functions that build an embed from a value object — threading a theme
31
+ * through every one of them would put a parameter nobody reasons about on the
32
+ * whole rendering surface, to express something that is global by nature: a bot
33
+ * has one palette, decided once, for its entire run.
34
+ *
35
+ * Read it, never copy it: destructuring at module load captures the defaults
36
+ * before {@link configureEmbedColors} has run.
37
+ */
38
+ export declare const EMBED_COLORS: EmbedColors;
39
+ /**
40
+ * Replace some or all of the palette. Call it from the composition root, before
41
+ * any module is constructed — after that, an embed may already have rendered.
42
+ */
43
+ export declare function configureEmbedColors(overrides: Partial<EmbedColors>): void;
44
+ //# sourceMappingURL=colors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../../../src/discord/ui/colors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,mFAAmF;AACnF,eAAO,MAAM,eAAe,YAAY,CAAC;AAEzC;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,WAAW,CAMtD,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,EAAE,WAAyC,CAAC;AAErE;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAE1E"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EMBED_COLORS = exports.DEFAULT_EMBED_COLORS = exports.DISCORD_BLURPLE = void 0;
4
+ exports.toDiscordColor = toDiscordColor;
5
+ exports.configureEmbedColors = configureEmbedColors;
6
+ /** Convert a `#rrggbb` string to the integer discord.js wants for `setColor`. */
7
+ function toDiscordColor(hex) {
8
+ return Number.parseInt(hex.slice(1), 16);
9
+ }
10
+ /** Discord's own brand colour, the fallback for a bot that declares no palette. */
11
+ exports.DISCORD_BLURPLE = "#5865f2";
12
+ /**
13
+ * What every embed renders as until the composition root says otherwise. Kept
14
+ * deliberately unbranded: a kernel that shipped one bot's colours would make
15
+ * every other bot start out wearing them.
16
+ */
17
+ exports.DEFAULT_EMBED_COLORS = {
18
+ success: toDiscordColor("#22c55e"),
19
+ warning: toDiscordColor("#e67e22"),
20
+ danger: toDiscordColor("#ef4444"),
21
+ brand: toDiscordColor(exports.DISCORD_BLURPLE),
22
+ neutral: toDiscordColor(exports.DISCORD_BLURPLE),
23
+ };
24
+ /**
25
+ * The live palette every embed reads, in the kernel and in the modules alike.
26
+ *
27
+ * This is the one piece of module-level state the kernel keeps, and it is a
28
+ * deliberate exception to "DI, no singletons". A colour is read deep inside pure
29
+ * view functions that build an embed from a value object — threading a theme
30
+ * through every one of them would put a parameter nobody reasons about on the
31
+ * whole rendering surface, to express something that is global by nature: a bot
32
+ * has one palette, decided once, for its entire run.
33
+ *
34
+ * Read it, never copy it: destructuring at module load captures the defaults
35
+ * before {@link configureEmbedColors} has run.
36
+ */
37
+ exports.EMBED_COLORS = { ...exports.DEFAULT_EMBED_COLORS };
38
+ /**
39
+ * Replace some or all of the palette. Call it from the composition root, before
40
+ * any module is constructed — after that, an embed may already have rendered.
41
+ */
42
+ function configureEmbedColors(overrides) {
43
+ Object.assign(exports.EMBED_COLORS, overrides);
44
+ }
45
+ //# sourceMappingURL=colors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colors.js","sourceRoot":"","sources":["../../../src/discord/ui/colors.ts"],"names":[],"mappings":";;;AAgBA,wCAEC;AAqCD,oDAEC;AA1CD,iFAAiF;AACjF,SAAgB,cAAc,CAAC,GAAW;IACzC,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,mFAAmF;AACtE,QAAA,eAAe,GAAG,SAAS,CAAC;AAEzC;;;;GAIG;AACU,QAAA,oBAAoB,GAA0B;IAC1D,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC;IAClC,OAAO,EAAE,cAAc,CAAC,SAAS,CAAC;IAClC,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC;IACjC,KAAK,EAAE,cAAc,CAAC,uBAAe,CAAC;IACtC,OAAO,EAAE,cAAc,CAAC,uBAAe,CAAC;CACxC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACU,QAAA,YAAY,GAAgB,EAAE,GAAG,4BAAoB,EAAE,CAAC;AAErE;;;GAGG;AACH,SAAgB,oBAAoB,CAAC,SAA+B;IACnE,MAAM,CAAC,MAAM,CAAC,oBAAY,EAAE,SAAS,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { EmbedBuilder } from "discord.js";
2
+ /** A single embed field. */
3
+ export interface EmbedField {
4
+ name: string;
5
+ value: string;
6
+ }
7
+ /**
8
+ * Add fields to an embed while respecting Discord's size limits. Truncates
9
+ * over-long names/values, stops before exceeding the 25-field or 6000-character
10
+ * caps, and appends an overflow footer when some fields were dropped — so the
11
+ * embed can always be sent (no `MAX_EMBED_SIZE_EXCEEDED` rejection).
12
+ */
13
+ export declare function appendBoundedFields(embed: EmbedBuilder, fields: EmbedField[], overflowFooter: (hiddenCount: number) => string): void;
14
+ /** Build a plain titled embed. */
15
+ export declare function buildEmbed(title: string, description: string): EmbedBuilder;
16
+ //# sourceMappingURL=embed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../../../src/discord/ui/embed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAa1C,4BAA4B;AAC5B,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAClC,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,UAAU,EAAE,EACpB,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,GAC7C,IAAI,CAsBN;AASD,kCAAkC;AAClC,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,CAE3E"}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.appendBoundedFields = appendBoundedFields;
4
+ exports.buildEmbed = buildEmbed;
5
+ const discord_js_1 = require("discord.js");
6
+ /** Discord hard limit on the number of fields per embed. */
7
+ const MAX_EMBED_FIELDS = 25;
8
+ /** Discord hard limit on a field name length. */
9
+ const MAX_FIELD_NAME = 256;
10
+ /** Discord hard limit on a field value length. */
11
+ const MAX_FIELD_VALUE = 1024;
12
+ /** Discord hard limit on the total character count of an embed. */
13
+ const MAX_EMBED_TOTAL = 6000;
14
+ /** Headroom kept free for footer/title so the total stays under the limit. */
15
+ const EMBED_TOTAL_SAFETY_MARGIN = 256;
16
+ /**
17
+ * Add fields to an embed while respecting Discord's size limits. Truncates
18
+ * over-long names/values, stops before exceeding the 25-field or 6000-character
19
+ * caps, and appends an overflow footer when some fields were dropped — so the
20
+ * embed can always be sent (no `MAX_EMBED_SIZE_EXCEEDED` rejection).
21
+ */
22
+ function appendBoundedFields(embed, fields, overflowFooter) {
23
+ let usedChars = (embed.data.title?.length ?? 0) + (embed.data.description?.length ?? 0);
24
+ let shown = 0;
25
+ for (const field of fields) {
26
+ if (shown >= MAX_EMBED_FIELDS) {
27
+ break;
28
+ }
29
+ const name = truncate(field.name, MAX_FIELD_NAME);
30
+ const value = truncate(field.value, MAX_FIELD_VALUE);
31
+ if (usedChars + name.length + value.length > MAX_EMBED_TOTAL - EMBED_TOTAL_SAFETY_MARGIN) {
32
+ break;
33
+ }
34
+ embed.addFields({ name, value });
35
+ usedChars += name.length + value.length;
36
+ shown += 1;
37
+ }
38
+ const hidden = fields.length - shown;
39
+ if (hidden > 0) {
40
+ embed.setFooter({ text: overflowFooter(hidden) });
41
+ }
42
+ }
43
+ function truncate(text, max) {
44
+ if (text.length <= max) {
45
+ return text;
46
+ }
47
+ return `${text.slice(0, max - 1)}…`;
48
+ }
49
+ /** Build a plain titled embed. */
50
+ function buildEmbed(title, description) {
51
+ return new discord_js_1.EmbedBuilder().setTitle(title).setDescription(description);
52
+ }
53
+ //# sourceMappingURL=embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.js","sourceRoot":"","sources":["../../../src/discord/ui/embed.ts"],"names":[],"mappings":";;AAyBA,kDA0BC;AAUD,gCAEC;AA/DD,2CAA0C;AAE1C,4DAA4D;AAC5D,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,iDAAiD;AACjD,MAAM,cAAc,GAAG,GAAG,CAAC;AAC3B,kDAAkD;AAClD,MAAM,eAAe,GAAG,IAAI,CAAC;AAC7B,mEAAmE;AACnE,MAAM,eAAe,GAAG,IAAI,CAAC;AAC7B,8EAA8E;AAC9E,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAQtC;;;;;GAKG;AACH,SAAgB,mBAAmB,CAClC,KAAmB,EACnB,MAAoB,EACpB,cAA+C;IAE/C,IAAI,SAAS,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC;IACxF,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,KAAK,IAAI,gBAAgB,EAAE,CAAC;YAC/B,MAAM;QACP,CAAC;QACD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;QACrD,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,eAAe,GAAG,yBAAyB,EAAE,CAAC;YAC1F,MAAM;QACP,CAAC;QACD,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACjC,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QACxC,KAAK,IAAI,CAAC,CAAC;IACZ,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IACrC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAChB,KAAK,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnD,CAAC;AACF,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY,EAAE,GAAW;IAC1C,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;AACrC,CAAC;AAED,kCAAkC;AAClC,SAAgB,UAAU,CAAC,KAAa,EAAE,WAAmB;IAC5D,OAAO,IAAI,yBAAY,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;AACvE,CAAC"}
@@ -0,0 +1,40 @@
1
+ import type { Attachment } from "discord.js";
2
+ /**
3
+ * A file a message carries: the bytes, and the name an embed resolves an
4
+ * `attachment://` reference on.
5
+ *
6
+ * `Uint8Array` rather than `Buffer` so a caller can produce one without
7
+ * reaching for a Node-specific type; the conversion happens here, at the edge
8
+ * that hands it to discord.js.
9
+ */
10
+ export interface MessageFile {
11
+ readonly name: string;
12
+ readonly bytes: Uint8Array;
13
+ }
14
+ /** A file as discord.js takes it on a send or an edit. */
15
+ export interface MessageUpload {
16
+ readonly attachment: Buffer;
17
+ readonly name: string;
18
+ }
19
+ /** What an edit has to state for a message to end up carrying exactly what was asked. */
20
+ export interface PlannedAttachments {
21
+ readonly attachments: Attachment[];
22
+ readonly files: MessageUpload[];
23
+ }
24
+ export declare function toMessageUpload(file: MessageFile): MessageUpload;
25
+ /**
26
+ * Split what a message should carry into what is already up there and what has
27
+ * to be uploaded.
28
+ *
29
+ * Discord reads an edit's `attachments` field as the complete set the message
30
+ * keeps — so `attachments: []` strips whatever it was published with, and
31
+ * re-sending the bytes to hold on to a file would upload the same one again on
32
+ * every unrelated re-render. Existing attachments are matched by name because
33
+ * that is what an embed resolves `attachment://` on, so a file already up there
34
+ * under the wanted name is the very one to keep.
35
+ *
36
+ * A caller carrying no files of its own never reaches this: it states neither
37
+ * field, and Discord leaves the message's own alone.
38
+ */
39
+ export declare function planMessageAttachments(existing: readonly Attachment[], wanted: readonly MessageFile[]): PlannedAttachments;
40
+ //# sourceMappingURL=message-attachments.d.ts.map