@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,195 @@
1
+ import type { ActionRowBuilder, AnySelectMenuInteraction, Attachment, ChatInputCommandInteraction, ContainerBuilder, EmbedBuilder, InteractionUpdateOptions, MessageActionRowComponentBuilder, MessageMentionOptions } from "discord.js";
2
+ import type { Button } from "../../../discord/interaction/button";
3
+ import type { Card } from "../../../discord/ui/card";
4
+ import { type MessageFile } from "../../../discord/ui/message-attachments";
5
+ import type { Logger } from "../../../logger";
6
+ /** How long an interactive message stays live without a click. */
7
+ export declare const COLLECTOR_IDLE_MS: number;
8
+ /**
9
+ * What every layout a message can render shares: the files it carries and who
10
+ * it may notify.
11
+ */
12
+ interface InteractiveMessagePayloadBase {
13
+ /**
14
+ * The files this message carries, as its **whole** set — an embed or a
15
+ * card's `thumbnail`/`gallery` refers to one by name, as
16
+ * `attachment://<name>`.
17
+ *
18
+ * Leaving the key out means "leave the message's attachments alone", which
19
+ * is what a view carrying no file of its own must do: stating an empty set
20
+ * would strip whatever the message was sent with. A view that does own its
21
+ * files states them on every render, empty included, since that is what
22
+ * makes removing one show up.
23
+ */
24
+ files?: MessageFile[];
25
+ /**
26
+ * Who this message may notify.
27
+ *
28
+ * Stated by a view that renders text it does not own — user-authored content
29
+ * carrying mentions — so looking at a preview never pings the people it
30
+ * names. Left out means Discord's own default, which is what a view building
31
+ * every string itself wants.
32
+ */
33
+ allowedMentions?: MessageMentionOptions;
34
+ }
35
+ /**
36
+ * The message payload shape shared by the initial reply and every update.
37
+ *
38
+ * A discriminated union rather than one shape with an optional `card`:
39
+ * Discord's `IS_COMPONENTS_V2` flag is **irreversible** (once a message carries
40
+ * it, an edit can never clear it) and a message carrying it may hold **no**
41
+ * embed at all — so "embeds" and "card" are not two options on the same
42
+ * message, they are two kinds of message, and mixing their fields must fail to
43
+ * compile rather than build a payload Discord would refuse.
44
+ *
45
+ * `layout` defaults to `"embeds"` — it is optional on that branch alone — so
46
+ * every payload a view already returns (`{ embeds, components }`, no `layout`
47
+ * key at all) keeps satisfying this type unchanged: nothing that predates the
48
+ * card layout has to name the one it was always using.
49
+ */
50
+ export type InteractiveMessagePayload<S = never> = (InteractiveMessagePayloadBase & {
51
+ layout?: "embeds";
52
+ embeds: EmbedBuilder[];
53
+ components: ActionRowBuilder<MessageActionRowComponentBuilder>[];
54
+ }) | (InteractiveMessagePayloadBase & {
55
+ layout: "card";
56
+ card: Card<S>;
57
+ /**
58
+ * Rows shown beside the card rather than inside it — a screen's own
59
+ * controls (reset, back, done). A Components V2 message accepts several
60
+ * top-level components: the `Container` `card` compiles to is one, and
61
+ * each of these is an `ActionRow` next to it. Omitted, or empty, for a
62
+ * payload with no screen-level controls to show right now (a closed
63
+ * screen).
64
+ */
65
+ controls?: ActionRowBuilder<MessageActionRowComponentBuilder>[];
66
+ /**
67
+ * Never present on this branch — declared anyway so that
68
+ * `InteractiveMessagePayload<S>["components"]`, used elsewhere purely to
69
+ * name the action-row array type, keeps resolving instead of erroring on
70
+ * a key one arm of the union does not have.
71
+ */
72
+ components?: never;
73
+ });
74
+ /**
75
+ * The payload as discord.js takes it on an edit, given what the message already
76
+ * carries: a file already up there under a wanted name is kept rather than
77
+ * uploaded a second time, so an unrelated re-render neither drops nor re-sends
78
+ * it.
79
+ *
80
+ * A payload stating no files touches neither field, leaving the message's own
81
+ * attachments alone.
82
+ *
83
+ * `state` is only read for a `"card"` payload — it is what `Card.apply` needs
84
+ * to render the container — and is otherwise unused. No caller building an
85
+ * `"embeds"` payload has ever had to pass it, and still does not: it is the
86
+ * third, optional parameter existing two-argument calls already omit.
87
+ */
88
+ export declare function toMessageEditOptions<S>(payload: InteractiveMessagePayload<S>, existing: readonly Attachment[], state?: S): InteractionUpdateOptions;
89
+ /**
90
+ * The single mutable cell shared by the view and the collector. Kept explicit
91
+ * rather than captured as a closure variable so the two always read the same
92
+ * reference.
93
+ */
94
+ export interface StateStore<S> {
95
+ read(): S;
96
+ write(next: S): void;
97
+ }
98
+ /** Hold a state the collector can advance in place. */
99
+ export declare function createStateStore<S>(initial: S): StateStore<S>;
100
+ /**
101
+ * What {@link InteractiveView.disabledControls} hands back: enough of a payload
102
+ * to neutralise the message's controls in place, in whichever layout the view
103
+ * renders.
104
+ *
105
+ * Not `Pick<InteractiveMessagePayload<S>, "components">` alone — on the card
106
+ * branch that type is `{ components?: never }`, since a card carries `render`'s
107
+ * controls beside its one container rather than inside it, as top-level
108
+ * `components` of its own kind. The second arm is what lets a card screen hand
109
+ * back its neutralised container *and* its neutralised outer row together —
110
+ * `Card.apply(state, true)` for the former, the same `createActionRow(...,
111
+ * { disableAll: true })` `render` already builds the row with for the latter —
112
+ * see {@link import("../../../discord/ui/card").Card}.
113
+ */
114
+ export type DisabledInteractiveMessageComponents<S> = Pick<InteractiveMessagePayload<S>, "components"> | {
115
+ readonly components: readonly (ContainerBuilder | ActionRowBuilder<MessageActionRowComponentBuilder>)[];
116
+ };
117
+ /**
118
+ * Turns a state into a message payload. Everything sent to Discord goes through
119
+ * here, so the collector never builds a payload of its own and the initial
120
+ * render can never drift from the updates.
121
+ */
122
+ export interface InteractiveView<S> {
123
+ render(state: S): InteractiveMessagePayload<S>;
124
+ disabledControls(state: S): DisabledInteractiveMessageComponents<S>;
125
+ }
126
+ /**
127
+ * What a pick hands to its handler: the triggering interaction, the values
128
+ * Discord sent back already unwrapped, and the same `state`/`update` pairing a
129
+ * button's {@link ComponentContext} carries.
130
+ */
131
+ export interface SelectComponentContext<S> {
132
+ readonly interaction: AnySelectMenuInteraction;
133
+ readonly values: readonly string[];
134
+ readonly state: S;
135
+ update(next: S): Promise<void>;
136
+ }
137
+ /**
138
+ * A select menu's behaviour inside an interactive message: the custom id the
139
+ * collector routes on, and what a pick does with the current state.
140
+ *
141
+ * Only the behaviour, unlike {@link Button} which also renders itself: a
142
+ * compiled select menu's rendering does not vary with the state, so it stays
143
+ * where the rest of the message is built — in the view.
144
+ */
145
+ export interface InteractiveSelect<S> {
146
+ readonly id: string;
147
+ onSelect(ctx: SelectComponentContext<S>): Promise<void> | void;
148
+ }
149
+ export interface InteractiveMessageCollectorDeps<S> {
150
+ interaction: ChatInputCommandInteraction;
151
+ response: Awaited<ReturnType<ChatInputCommandInteraction["editReply"]>>;
152
+ buttons: Button<S>[];
153
+ /** Omitted by a message whose controls are all buttons. */
154
+ selects?: InteractiveSelect<S>[];
155
+ view: InteractiveView<S>;
156
+ store: StateStore<S>;
157
+ ownerId: string;
158
+ idleMs: number;
159
+ /**
160
+ * Run once the message stops reacting, whichever way it ended — an explicit
161
+ * {@link InteractiveMessageHandle.stop} or the idle deadline.
162
+ *
163
+ * This is where work that must not repeat at every click belongs: a settings
164
+ * screen pushing its result to whatever it configures, so what it configures
165
+ * never shows the half-finished states an administrator passed through. A
166
+ * failure is logged, never thrown — the message has already ended.
167
+ */
168
+ onEnd?: () => Promise<void> | void;
169
+ logger: Logger;
170
+ }
171
+ /**
172
+ * Attach the interaction/idle wiring to an already-sent message: it owns the
173
+ * collector, routes each interaction by custom ID to the button's `onClick` or
174
+ * the select menu's `onSelect`, scopes every interaction to the owner, and
175
+ * centralises error handling. Mirrors command `dispatch`.
176
+ *
177
+ * Generic over the state so the same mechanism serves anything whose controls
178
+ * react for a bounded lifetime — pagination, a settings screen, a confirmation.
179
+ * Persistent components that must survive a restart belong to the
180
+ * {@link import("../../../discord/components/component-router").ComponentRouter}
181
+ * instead: this state lives in memory and dies on idle.
182
+ */
183
+ export interface InteractiveMessageHandle {
184
+ /**
185
+ * End the message's interactive life **without** neutralising its controls.
186
+ *
187
+ * For callers that have already rendered a final state — a confirmed
188
+ * deletion, say — where the usual "disable on end" edit would target a
189
+ * message, or a channel, that no longer exists. `onEnd` still runs.
190
+ */
191
+ stop(): void;
192
+ }
193
+ export declare function mountInteractiveMessageCollector<S>(deps: InteractiveMessageCollectorDeps<S>): InteractiveMessageHandle;
194
+ export {};
195
+ //# sourceMappingURL=interactive-message-collector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-message-collector.d.ts","sourceRoot":"","sources":["../../../../src/discord/components/interactive-message/interactive-message-collector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.COLLECTOR_IDLE_MS = void 0;
4
+ exports.toMessageEditOptions = toMessageEditOptions;
5
+ exports.createStateStore = createStateStore;
6
+ exports.mountInteractiveMessageCollector = mountInteractiveMessageCollector;
7
+ const message_attachments_1 = require("../../../discord/ui/message-attachments");
8
+ const errors_1 = require("../../../errors");
9
+ /** How long an interactive message stays live without a click. */
10
+ exports.COLLECTOR_IDLE_MS = 5 * 60 * 1000;
11
+ /**
12
+ * The payload as discord.js takes it on an edit, given what the message already
13
+ * carries: a file already up there under a wanted name is kept rather than
14
+ * uploaded a second time, so an unrelated re-render neither drops nor re-sends
15
+ * it.
16
+ *
17
+ * A payload stating no files touches neither field, leaving the message's own
18
+ * attachments alone.
19
+ *
20
+ * `state` is only read for a `"card"` payload — it is what `Card.apply` needs
21
+ * to render the container — and is otherwise unused. No caller building an
22
+ * `"embeds"` payload has ever had to pass it, and still does not: it is the
23
+ * third, optional parameter existing two-argument calls already omit.
24
+ */
25
+ function toMessageEditOptions(payload, existing, state) {
26
+ const { files, allowedMentions } = payload;
27
+ const mentions = allowedMentions === undefined ? {} : { allowedMentions };
28
+ const attachments = files === undefined ? {} : (0, message_attachments_1.planMessageAttachments)(existing, files);
29
+ if (payload.layout === "card") {
30
+ if (state === undefined) {
31
+ // Only reachable once a caller actually builds a `"card"` payload
32
+ // without threading the state its `Card` needs — a programming error
33
+ // in that caller, not something a member's click can trigger.
34
+ throw new Error('toMessageEditOptions: a "card" layout payload needs the state its Card was ' +
35
+ "declared over to call Card.apply, and none was given.");
36
+ }
37
+ return {
38
+ components: [payload.card.apply(state, false), ...(payload.controls ?? [])],
39
+ ...mentions,
40
+ ...attachments,
41
+ };
42
+ }
43
+ const { embeds, components } = payload;
44
+ return { embeds, components, ...mentions, ...attachments };
45
+ }
46
+ /** Hold a state the collector can advance in place. */
47
+ function createStateStore(initial) {
48
+ let state = initial;
49
+ return {
50
+ read: () => state,
51
+ write: (next) => {
52
+ state = next;
53
+ },
54
+ };
55
+ }
56
+ function mountInteractiveMessageCollector(deps) {
57
+ const { interaction, response, buttons, view, store, ownerId, idleMs, logger } = deps;
58
+ const selects = deps.selects ?? [];
59
+ function renderOnto(collected, next) {
60
+ return toMessageEditOptions(view.render(next), [...collected.message.attachments.values()], next);
61
+ }
62
+ function createClickContext(clicked) {
63
+ return {
64
+ interaction: clicked,
65
+ state: store.read(),
66
+ update: async (next) => {
67
+ store.write(next);
68
+ await clicked.update(renderOnto(clicked, next));
69
+ },
70
+ };
71
+ }
72
+ function createPickContext(picked) {
73
+ return {
74
+ interaction: picked,
75
+ values: picked.values,
76
+ state: store.read(),
77
+ update: async (next) => {
78
+ store.write(next);
79
+ await picked.update(renderOnto(picked, next));
80
+ },
81
+ };
82
+ }
83
+ async function route(collected) {
84
+ if (collected.isButton()) {
85
+ const target = buttons.find((entry) => entry.id === collected.customId);
86
+ await target?.onClick?.(createClickContext(collected));
87
+ return;
88
+ }
89
+ if (collected.isAnySelectMenu()) {
90
+ const target = selects.find((entry) => entry.id === collected.customId);
91
+ await target?.onSelect(createPickContext(collected));
92
+ }
93
+ }
94
+ async function handleCollected(collected) {
95
+ try {
96
+ await route(collected);
97
+ }
98
+ catch (error) {
99
+ // At `error`, and with everything the throw carried: whatever lands here
100
+ // left the click unanswered — Discord tells the administrator the
101
+ // interaction failed — so it is a defect to be found, not a hiccup. The
102
+ // custom id says which control it was, since the state that produced it
103
+ // is gone by the time anybody reads this.
104
+ logger.error({ err: (0, errors_1.describeError)(error), customId: collected.customId }, "Failed to update interactive message");
105
+ }
106
+ }
107
+ function disableOnEnd() {
108
+ // The message outlives the collector, so leave the controls visibly inert
109
+ // instead of letting clicks fail silently.
110
+ interaction.editReply(view.disabledControls(store.read())).catch((error) => {
111
+ logger.warn({ err: (0, errors_1.describeError)(error) }, "Failed to disable interactive message controls");
112
+ });
113
+ }
114
+ /**
115
+ * A caller that stops the message itself has already rendered the final state,
116
+ * so the disabling edit would be at best redundant and at worst aimed at
117
+ * something that is gone. `onEnd` still runs: it answers "the message is over",
118
+ * not "the message timed out".
119
+ */
120
+ let stoppedByCaller = false;
121
+ async function handleEnd() {
122
+ if (!stoppedByCaller) {
123
+ disableOnEnd();
124
+ }
125
+ try {
126
+ await deps.onEnd?.();
127
+ }
128
+ catch (error) {
129
+ logger.warn({ err: (0, errors_1.describeError)(error) }, "Failed to close interactive message");
130
+ }
131
+ }
132
+ // No `componentType`: the collector takes every message component the view
133
+ // renders — buttons and select menus alike — and `route` sorts them out.
134
+ const collector = response.createMessageComponentCollector({
135
+ // `idle` rearms on every collected interaction, so each click grants a
136
+ // fresh window rather than counting down from the first render.
137
+ idle: idleMs,
138
+ filter: (collected) => collected.user.id === ownerId,
139
+ });
140
+ collector.on("collect", handleCollected);
141
+ // One `end` listener for both ways out, so nothing an ending owes — inert
142
+ // controls, `onEnd` — depends on which one happened.
143
+ collector.on("end", handleEnd);
144
+ return {
145
+ stop() {
146
+ stoppedByCaller = true;
147
+ collector.stop();
148
+ },
149
+ };
150
+ }
151
+ //# sourceMappingURL=interactive-message-collector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive-message-collector.js","sourceRoot":"","sources":["../../../../src/discord/components/interactive-message/interactive-message-collector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { type ChatInputCommandInteraction } from "discord.js";
2
+ import { type InteractiveMessageHandle, type InteractiveSelect, type InteractiveView, type StateStore } from "../../../discord/components/interactive-message/interactive-message-collector";
3
+ import type { Button } from "../../../discord/interaction/button";
4
+ import type { Logger } from "../../../logger";
5
+ export interface InteractiveMessageOptions<S> {
6
+ initialState: S;
7
+ buttons: Button<S>[];
8
+ /** Omitted by a message whose controls are all buttons. */
9
+ selects?: InteractiveSelect<S>[];
10
+ view: InteractiveView<S>;
11
+ ownerId: string;
12
+ /** Run once the message stops reacting, whichever way it ended. */
13
+ onEnd?: () => Promise<void> | void;
14
+ logger: Logger;
15
+ idleMs?: number;
16
+ }
17
+ /**
18
+ * Send an interactive message and keep its controls live for a bounded time:
19
+ * renders the initial state, then hands the message to the collector.
20
+ *
21
+ * Callers that have already sent their message — or that decide case by case
22
+ * whether it is worth collecting at all — use
23
+ * {@link mountInteractiveMessageCollector} directly.
24
+ *
25
+ * Call it on an already-deferred interaction.
26
+ */
27
+ export declare function mountInteractiveMessage<S>(interaction: ChatInputCommandInteraction, options: InteractiveMessageOptions<S>): Promise<InteractiveMessageHandle & {
28
+ readonly store: StateStore<S>;
29
+ }>;
30
+ //# sourceMappingURL=mount-interactive-message.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-interactive-message.d.ts","sourceRoot":"","sources":["../../../../src/discord/components/interactive-message/mount-interactive-message.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,2BAA2B,EAAgB,MAAM,YAAY,CAAC;AAC5E,OAAO,EAGN,KAAK,wBAAwB,EAC7B,KAAK,iBAAiB,EACtB,KAAK,eAAe,EAEpB,KAAK,UAAU,EAEf,MAAM,wEAAwE,CAAC;AAChF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,WAAW,yBAAyB,CAAC,CAAC;IAC3C,YAAY,EAAE,CAAC,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACrB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC;IACjC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;GASG;AACH,wBAAsB,uBAAuB,CAAC,CAAC,EAC9C,WAAW,EAAE,2BAA2B,EACxC,OAAO,EAAE,yBAAyB,CAAC,CAAC,CAAC,GACnC,OAAO,CAAC,wBAAwB,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAA;CAAE,CAAC,CA8BvE"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mountInteractiveMessage = mountInteractiveMessage;
4
+ const discord_js_1 = require("discord.js");
5
+ const interactive_message_collector_1 = require("../../../discord/components/interactive-message/interactive-message-collector");
6
+ /**
7
+ * Send an interactive message and keep its controls live for a bounded time:
8
+ * renders the initial state, then hands the message to the collector.
9
+ *
10
+ * Callers that have already sent their message — or that decide case by case
11
+ * whether it is worth collecting at all — use
12
+ * {@link mountInteractiveMessageCollector} directly.
13
+ *
14
+ * Call it on an already-deferred interaction.
15
+ */
16
+ async function mountInteractiveMessage(interaction, options) {
17
+ const store = (0, interactive_message_collector_1.createStateStore)(options.initialState);
18
+ const initial = options.view.render(store.read());
19
+ // A deferred reply carries no attachment yet, so every file the first render
20
+ // states is uploaded — there is nothing up there that could be kept instead.
21
+ const editOptions = (0, interactive_message_collector_1.toMessageEditOptions)(initial, [], store.read());
22
+ const response = await interaction.editReply(
23
+ // `IS_COMPONENTS_V2` is set on the *first* send only, never again: Discord
24
+ // treats it as irreversible on a message — an edit can never clear it —
25
+ // so posing it here and only here is what keeps a later re-render from
26
+ // trying to flip a flag Discord would refuse to change.
27
+ initial.layout === "card"
28
+ ? { ...editOptions, flags: discord_js_1.MessageFlags.IsComponentsV2 }
29
+ : editOptions);
30
+ const handle = (0, interactive_message_collector_1.mountInteractiveMessageCollector)({
31
+ interaction,
32
+ response,
33
+ buttons: options.buttons,
34
+ selects: options.selects,
35
+ view: options.view,
36
+ store,
37
+ ownerId: options.ownerId,
38
+ ...(options.onEnd === undefined ? {} : { onEnd: options.onEnd }),
39
+ idleMs: options.idleMs ?? interactive_message_collector_1.COLLECTOR_IDLE_MS,
40
+ logger: options.logger,
41
+ });
42
+ return { ...handle, store };
43
+ }
44
+ //# sourceMappingURL=mount-interactive-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-interactive-message.js","sourceRoot":"","sources":["../../../../src/discord/components/interactive-message/mount-interactive-message.ts"],"names":[],"mappings":";;AAqCA,0DAiCC;AAtED,2CAA4E;AAC5E,0HASgF;AAiBhF;;;;;;;;;GASG;AACI,KAAK,UAAU,uBAAuB,CAC5C,WAAwC,EACxC,OAAqC;IAErC,MAAM,KAAK,GAAG,IAAA,gDAAgB,EAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAClD,6EAA6E;IAC7E,6EAA6E;IAC7E,MAAM,WAAW,GAAG,IAAA,oDAAoB,EAAC,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,SAAS;IAC3C,2EAA2E;IAC3E,wEAAwE;IACxE,uEAAuE;IACvE,wDAAwD;IACxD,OAAO,CAAC,MAAM,KAAK,MAAM;QACxB,CAAC,CAAC,EAAE,GAAG,WAAW,EAAE,KAAK,EAAE,yBAAY,CAAC,cAAc,EAAE;QACxD,CAAC,CAAC,WAAW,CACd,CAAC;IAEF,MAAM,MAAM,GAAG,IAAA,gEAAgC,EAAC;QAC/C,WAAW;QACX,QAAQ;QACR,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,KAAK;QACL,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;QAChE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,iDAAiB;QAC3C,MAAM,EAAE,OAAO,CAAC,MAAM;KACtB,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { mountPaginator, type PaginatorOptions, } from "../../../discord/components/paginator/mount-paginator";
2
+ export { clampPage, createPageState, isFirstPage, isLastPage, nextPage, type PageState, pageCount, previousPage, selectPageItems, } from "../../../discord/components/paginator/page-state";
3
+ export type { PaginatorLabels } from "../../../discord/components/paginator/paginator-buttons";
4
+ export type { PaginatorRender } from "../../../discord/components/paginator/paginator-view";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/discord/components/paginator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,cAAc,EACd,KAAK,gBAAgB,GACrB,MAAM,gDAAgD,CAAC;AACxD,OAAO,EACN,SAAS,EACT,eAAe,EACf,WAAW,EACX,UAAU,EACV,QAAQ,EACR,KAAK,SAAS,EACd,SAAS,EACT,YAAY,EACZ,eAAe,GACf,MAAM,2CAA2C,CAAC;AACnD,YAAY,EAAE,eAAe,EAAE,MAAM,kDAAkD,CAAC;AACxF,YAAY,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selectPageItems = exports.previousPage = exports.pageCount = exports.nextPage = exports.isLastPage = exports.isFirstPage = exports.createPageState = exports.clampPage = exports.mountPaginator = void 0;
4
+ var mount_paginator_1 = require("../../../discord/components/paginator/mount-paginator");
5
+ Object.defineProperty(exports, "mountPaginator", { enumerable: true, get: function () { return mount_paginator_1.mountPaginator; } });
6
+ var page_state_1 = require("../../../discord/components/paginator/page-state");
7
+ Object.defineProperty(exports, "clampPage", { enumerable: true, get: function () { return page_state_1.clampPage; } });
8
+ Object.defineProperty(exports, "createPageState", { enumerable: true, get: function () { return page_state_1.createPageState; } });
9
+ Object.defineProperty(exports, "isFirstPage", { enumerable: true, get: function () { return page_state_1.isFirstPage; } });
10
+ Object.defineProperty(exports, "isLastPage", { enumerable: true, get: function () { return page_state_1.isLastPage; } });
11
+ Object.defineProperty(exports, "nextPage", { enumerable: true, get: function () { return page_state_1.nextPage; } });
12
+ Object.defineProperty(exports, "pageCount", { enumerable: true, get: function () { return page_state_1.pageCount; } });
13
+ Object.defineProperty(exports, "previousPage", { enumerable: true, get: function () { return page_state_1.previousPage; } });
14
+ Object.defineProperty(exports, "selectPageItems", { enumerable: true, get: function () { return page_state_1.selectPageItems; } });
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/discord/components/paginator/index.ts"],"names":[],"mappings":";;;AAAA,kFAGwD;AAFvD,iHAAA,cAAc,OAAA;AAGf,wEAUmD;AATlD,uGAAA,SAAS,OAAA;AACT,6GAAA,eAAe,OAAA;AACf,yGAAA,WAAW,OAAA;AACX,wGAAA,UAAU,OAAA;AACV,sGAAA,QAAQ,OAAA;AAER,uGAAA,SAAS,OAAA;AACT,0GAAA,YAAY,OAAA;AACZ,6GAAA,eAAe,OAAA"}
@@ -0,0 +1,25 @@
1
+ import type { ChatInputCommandInteraction } from "discord.js";
2
+ import { type PaginatorLabels } from "../../../discord/components/paginator/paginator-buttons";
3
+ import { type PaginatorRender } from "../../../discord/components/paginator/paginator-view";
4
+ import type { Logger } from "../../../logger";
5
+ export interface PaginatorOptions<T> {
6
+ items: T[];
7
+ pageSize: number;
8
+ ownerId: string;
9
+ logger: Logger;
10
+ initialPage?: number;
11
+ idleMs?: number;
12
+ labels?: Partial<PaginatorLabels>;
13
+ render: PaginatorRender<T>;
14
+ }
15
+ /**
16
+ * A composed component: an embed plus previous/next buttons plus a collector.
17
+ * The collector itself is the generic
18
+ * {@link import("../../../discord/components/interactive-message").mountInteractiveMessageCollector} —
19
+ * this module only contributes what is specific to pagination: the page state,
20
+ * the navigation buttons and the page view.
21
+ *
22
+ * Call it on an already-deferred interaction.
23
+ */
24
+ export declare function mountPaginator<T>(interaction: ChatInputCommandInteraction, options: PaginatorOptions<T>): Promise<void>;
25
+ //# sourceMappingURL=mount-paginator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-paginator.d.ts","sourceRoot":"","sources":["../../../../src/discord/components/paginator/mount-paginator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAQ9D,OAAO,EAEN,KAAK,eAAe,EAEpB,MAAM,kDAAkD,CAAC;AAC1D,OAAO,EAEN,KAAK,eAAe,EACpB,MAAM,+CAA+C,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAClC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAClC,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACrC,WAAW,EAAE,2BAA2B,EACxC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mountPaginator = mountPaginator;
4
+ const interactive_message_1 = require("../../../discord/components/interactive-message");
5
+ const page_state_1 = require("../../../discord/components/paginator/page-state");
6
+ const paginator_buttons_1 = require("../../../discord/components/paginator/paginator-buttons");
7
+ const paginator_view_1 = require("../../../discord/components/paginator/paginator-view");
8
+ /**
9
+ * A composed component: an embed plus previous/next buttons plus a collector.
10
+ * The collector itself is the generic
11
+ * {@link import("../../../discord/components/interactive-message").mountInteractiveMessageCollector} —
12
+ * this module only contributes what is specific to pagination: the page state,
13
+ * the navigation buttons and the page view.
14
+ *
15
+ * Call it on an already-deferred interaction.
16
+ */
17
+ async function mountPaginator(interaction, options) {
18
+ const { items, pageSize, ownerId, render, logger } = options;
19
+ const count = (0, page_state_1.pageCount)(items.length, pageSize);
20
+ const store = (0, interactive_message_1.createStateStore)((0, page_state_1.createPageState)(options.initialPage ?? 1, count));
21
+ const buttons = (0, paginator_buttons_1.createPaginatorButtons)(count, (0, paginator_buttons_1.resolveLabels)(options.labels));
22
+ const view = (0, paginator_view_1.createPaginatorView)({ items, pageSize, count, render, buttons });
23
+ const response = await interaction.editReply((0, interactive_message_1.toMessageEditOptions)(view.render(store.read()), []));
24
+ // A single page has nothing to navigate to, so it needs no collector at all —
25
+ // a pagination-specific rule, which is why it lives here and not in the
26
+ // generic mechanism.
27
+ if (count <= 1) {
28
+ return;
29
+ }
30
+ (0, interactive_message_1.mountInteractiveMessageCollector)({
31
+ interaction,
32
+ response,
33
+ buttons,
34
+ view,
35
+ store,
36
+ ownerId,
37
+ idleMs: options.idleMs ?? interactive_message_1.COLLECTOR_IDLE_MS,
38
+ logger,
39
+ });
40
+ }
41
+ //# sourceMappingURL=mount-paginator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mount-paginator.js","sourceRoot":"","sources":["../../../../src/discord/components/paginator/mount-paginator.ts"],"names":[],"mappings":";;AAuCA,wCA6BC;AAnED,kFAKkD;AAClD,0EAAuF;AACvF,wFAI0D;AAC1D,kFAGuD;AAcvD;;;;;;;;GAQG;AACI,KAAK,UAAU,cAAc,CACnC,WAAwC,EACxC,OAA4B;IAE5B,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAC7D,MAAM,KAAK,GAAG,IAAA,sBAAS,EAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,IAAA,sCAAgB,EAAC,IAAA,4BAAe,EAAC,OAAO,CAAC,WAAW,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACjF,MAAM,OAAO,GAAG,IAAA,0CAAsB,EAAC,KAAK,EAAE,IAAA,iCAAa,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7E,MAAM,IAAI,GAAG,IAAA,oCAAmB,EAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAE9E,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,IAAA,0CAAoB,EAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IAElG,8EAA8E;IAC9E,wEAAwE;IACxE,qBAAqB;IACrB,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;QAChB,OAAO;IACR,CAAC;IAED,IAAA,sDAAgC,EAAC;QAChC,WAAW;QACX,QAAQ;QACR,OAAO;QACP,IAAI;QACJ,KAAK;QACL,OAAO;QACP,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,uCAAiB;QAC3C,MAAM;KACN,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ /** What the paginator remembers between two clicks: the page being displayed (1-based). */
2
+ export interface PageState {
3
+ page: number;
4
+ }
5
+ /** Total number of pages for a collection, never below 1. */
6
+ export declare function pageCount(total: number, pageSize: number): number;
7
+ /** Clamp a page number into the valid `[1, count]` range. */
8
+ export declare function clampPage(page: number, count: number): number;
9
+ /** Opening state, clamped so a caller-supplied out-of-range page stays valid. */
10
+ export declare function createPageState(page: number, count: number): PageState;
11
+ /** Transition one page back; a no-op on the first page. */
12
+ export declare function previousPage(state: PageState, count: number): PageState;
13
+ /** Transition one page forward; a no-op on the last page. */
14
+ export declare function nextPage(state: PageState, count: number): PageState;
15
+ /** Whether the "previous" affordance has nothing left to go back to. */
16
+ export declare function isFirstPage(state: PageState): boolean;
17
+ /** Whether the "next" affordance has nothing left to go forward to. */
18
+ export declare function isLastPage(state: PageState, count: number): boolean;
19
+ /** Slice of the collection visible on the current page. */
20
+ export declare function selectPageItems<T>(items: T[], state: PageState, pageSize: number): T[];
21
+ //# sourceMappingURL=page-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-state.d.ts","sourceRoot":"","sources":["../../../../src/discord/components/paginator/page-state.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,6DAA6D;AAC7D,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,iFAAiF;AACjF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAEtE;AAED,2DAA2D;AAC3D,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAEvE;AAED,6DAA6D;AAC7D,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,CAEnE;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAErD;AAED,uEAAuE;AACvE,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,2DAA2D;AAC3D,wBAAgB,eAAe,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,EAAE,CAGtF"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pageCount = pageCount;
4
+ exports.clampPage = clampPage;
5
+ exports.createPageState = createPageState;
6
+ exports.previousPage = previousPage;
7
+ exports.nextPage = nextPage;
8
+ exports.isFirstPage = isFirstPage;
9
+ exports.isLastPage = isLastPage;
10
+ exports.selectPageItems = selectPageItems;
11
+ /** Total number of pages for a collection, never below 1. */
12
+ function pageCount(total, pageSize) {
13
+ return Math.max(1, Math.ceil(total / pageSize));
14
+ }
15
+ /** Clamp a page number into the valid `[1, count]` range. */
16
+ function clampPage(page, count) {
17
+ return Math.min(Math.max(page, 1), count);
18
+ }
19
+ /** Opening state, clamped so a caller-supplied out-of-range page stays valid. */
20
+ function createPageState(page, count) {
21
+ return { page: clampPage(page, count) };
22
+ }
23
+ /** Transition one page back; a no-op on the first page. */
24
+ function previousPage(state, count) {
25
+ return { page: clampPage(state.page - 1, count) };
26
+ }
27
+ /** Transition one page forward; a no-op on the last page. */
28
+ function nextPage(state, count) {
29
+ return { page: clampPage(state.page + 1, count) };
30
+ }
31
+ /** Whether the "previous" affordance has nothing left to go back to. */
32
+ function isFirstPage(state) {
33
+ return state.page <= 1;
34
+ }
35
+ /** Whether the "next" affordance has nothing left to go forward to. */
36
+ function isLastPage(state, count) {
37
+ return state.page >= count;
38
+ }
39
+ /** Slice of the collection visible on the current page. */
40
+ function selectPageItems(items, state, pageSize) {
41
+ const start = (state.page - 1) * pageSize;
42
+ return items.slice(start, start + pageSize);
43
+ }
44
+ //# sourceMappingURL=page-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page-state.js","sourceRoot":"","sources":["../../../../src/discord/components/paginator/page-state.ts"],"names":[],"mappings":";;AAMA,8BAEC;AAGD,8BAEC;AAGD,0CAEC;AAGD,oCAEC;AAGD,4BAEC;AAGD,kCAEC;AAGD,gCAEC;AAGD,0CAGC;AAvCD,6DAA6D;AAC7D,SAAgB,SAAS,CAAC,KAAa,EAAE,QAAgB;IACxD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,6DAA6D;AAC7D,SAAgB,SAAS,CAAC,IAAY,EAAE,KAAa;IACpD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAC3C,CAAC;AAED,iFAAiF;AACjF,SAAgB,eAAe,CAAC,IAAY,EAAE,KAAa;IAC1D,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;AACzC,CAAC;AAED,2DAA2D;AAC3D,SAAgB,YAAY,CAAC,KAAgB,EAAE,KAAa;IAC3D,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;AACnD,CAAC;AAED,6DAA6D;AAC7D,SAAgB,QAAQ,CAAC,KAAgB,EAAE,KAAa;IACvD,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;AACnD,CAAC;AAED,wEAAwE;AACxE,SAAgB,WAAW,CAAC,KAAgB;IAC3C,OAAO,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,uEAAuE;AACvE,SAAgB,UAAU,CAAC,KAAgB,EAAE,KAAa;IACzD,OAAO,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC;AAC5B,CAAC;AAED,2DAA2D;AAC3D,SAAgB,eAAe,CAAI,KAAU,EAAE,KAAgB,EAAE,QAAgB;IAChF,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;IAC1C,OAAO,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,CAAC,CAAC;AAC7C,CAAC"}