@azurioh/discord-kernel 0.1.0 → 1.0.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 (529) hide show
  1. package/README.md +318 -1
  2. package/dist/authz/require-level-guard.d.ts +1 -1
  3. package/dist/authz/require-level-guard.d.ts.map +1 -1
  4. package/dist/color.d.ts +42 -0
  5. package/dist/color.d.ts.map +1 -0
  6. package/dist/color.js +130 -0
  7. package/dist/color.js.map +1 -0
  8. package/dist/discord/command/all-required.d.ts +8 -0
  9. package/dist/discord/command/all-required.d.ts.map +1 -0
  10. package/dist/discord/command/all-required.js +12 -0
  11. package/dist/discord/command/all-required.js.map +1 -0
  12. package/dist/discord/command/autocomplete-dispatcher.d.ts.map +1 -1
  13. package/dist/discord/command/autocomplete-dispatcher.js +2 -1
  14. package/dist/discord/command/autocomplete-dispatcher.js.map +1 -1
  15. package/dist/discord/command/autocomplete-limits.d.ts +3 -0
  16. package/dist/discord/command/autocomplete-limits.d.ts.map +1 -0
  17. package/dist/discord/command/autocomplete-limits.js +6 -0
  18. package/dist/discord/command/autocomplete-limits.js.map +1 -0
  19. package/dist/discord/command/autocomplete.d.ts +6 -1
  20. package/dist/discord/command/autocomplete.d.ts.map +1 -1
  21. package/dist/discord/command/autocomplete.js +6 -6
  22. package/dist/discord/command/autocomplete.js.map +1 -1
  23. package/dist/discord/command/command-responders.d.ts +26 -0
  24. package/dist/discord/command/command-responders.d.ts.map +1 -0
  25. package/dist/discord/command/command-responders.js +16 -0
  26. package/dist/discord/command/command-responders.js.map +1 -0
  27. package/dist/discord/command/context.d.ts +8 -17
  28. package/dist/discord/command/context.d.ts.map +1 -1
  29. package/dist/discord/command/context.js +8 -37
  30. package/dist/discord/command/context.js.map +1 -1
  31. package/dist/discord/command/cooldown-guard.d.ts +1 -1
  32. package/dist/discord/command/cooldown-guard.d.ts.map +1 -1
  33. package/dist/discord/command/create-command.d.ts +1 -8
  34. package/dist/discord/command/create-command.d.ts.map +1 -1
  35. package/dist/discord/command/create-command.js +17 -65
  36. package/dist/discord/command/create-command.js.map +1 -1
  37. package/dist/discord/command/create-context-menu-command.d.ts +3 -9
  38. package/dist/discord/command/create-context-menu-command.d.ts.map +1 -1
  39. package/dist/discord/command/create-context-menu-command.js +14 -65
  40. package/dist/discord/command/create-context-menu-command.js.map +1 -1
  41. package/dist/discord/command/errors.d.ts +1 -1
  42. package/dist/discord/command/errors.d.ts.map +1 -1
  43. package/dist/discord/command/errors.js +2 -2
  44. package/dist/discord/command/errors.js.map +1 -1
  45. package/dist/discord/command/guard.d.ts +15 -8
  46. package/dist/discord/command/guard.d.ts.map +1 -1
  47. package/dist/discord/command/guard.js +4 -4
  48. package/dist/discord/command/guard.js.map +1 -1
  49. package/dist/discord/command/options.d.ts +1 -10
  50. package/dist/discord/command/options.d.ts.map +1 -1
  51. package/dist/discord/command/options.js +127 -320
  52. package/dist/discord/command/options.js.map +1 -1
  53. package/dist/discord/command/passes-guard.d.ts +14 -0
  54. package/dist/discord/command/passes-guard.d.ts.map +1 -0
  55. package/dist/discord/command/passes-guard.js +27 -0
  56. package/dist/discord/command/passes-guard.js.map +1 -0
  57. package/dist/discord/command/permission-guard.d.ts +1 -1
  58. package/dist/discord/command/permission-guard.d.ts.map +1 -1
  59. package/dist/discord/command/render-command-failure.d.ts +23 -0
  60. package/dist/discord/command/render-command-failure.d.ts.map +1 -0
  61. package/dist/discord/command/render-command-failure.js +40 -0
  62. package/dist/discord/command/render-command-failure.js.map +1 -0
  63. package/dist/discord/command/route-key.d.ts +8 -0
  64. package/dist/discord/command/route-key.d.ts.map +1 -0
  65. package/dist/discord/command/route-key.js +13 -0
  66. package/dist/discord/command/route-key.js.map +1 -0
  67. package/dist/discord/command/router.d.ts +32 -7
  68. package/dist/discord/command/router.d.ts.map +1 -1
  69. package/dist/discord/command/router.js +48 -10
  70. package/dist/discord/command/router.js.map +1 -1
  71. package/dist/discord/command/send-embed.d.ts +14 -0
  72. package/dist/discord/command/send-embed.d.ts.map +1 -0
  73. package/dist/discord/command/send-embed.js +37 -0
  74. package/dist/discord/command/send-embed.js.map +1 -0
  75. package/dist/discord/command/types.d.ts +7 -1
  76. package/dist/discord/command/types.d.ts.map +1 -1
  77. package/dist/discord/components/component-access.d.ts +12 -0
  78. package/dist/discord/components/component-access.d.ts.map +1 -0
  79. package/dist/discord/components/component-access.js +21 -0
  80. package/dist/discord/components/component-access.js.map +1 -0
  81. package/dist/discord/components/component-router.d.ts +37 -15
  82. package/dist/discord/components/component-router.d.ts.map +1 -1
  83. package/dist/discord/components/component-router.js +44 -32
  84. package/dist/discord/components/component-router.js.map +1 -1
  85. package/dist/discord/components/interactive-message/index.d.ts +3 -1
  86. package/dist/discord/components/interactive-message/index.d.ts.map +1 -1
  87. package/dist/discord/components/interactive-message/index.js +5 -3
  88. package/dist/discord/components/interactive-message/index.js.map +1 -1
  89. package/dist/discord/components/interactive-message/interactive-message-collector.d.ts +3 -28
  90. package/dist/discord/components/interactive-message/interactive-message-collector.d.ts.map +1 -1
  91. package/dist/discord/components/interactive-message/interactive-message-collector.js +6 -53
  92. package/dist/discord/components/interactive-message/interactive-message-collector.js.map +1 -1
  93. package/dist/discord/components/interactive-message/message-edit-options.d.ts +18 -0
  94. package/dist/discord/components/interactive-message/message-edit-options.d.ts.map +1 -0
  95. package/dist/discord/components/interactive-message/message-edit-options.js +40 -0
  96. package/dist/discord/components/interactive-message/message-edit-options.js.map +1 -0
  97. package/dist/discord/components/interactive-message/mount-interactive-message.d.ts +2 -1
  98. package/dist/discord/components/interactive-message/mount-interactive-message.d.ts.map +1 -1
  99. package/dist/discord/components/interactive-message/mount-interactive-message.js +4 -2
  100. package/dist/discord/components/interactive-message/mount-interactive-message.js.map +1 -1
  101. package/dist/discord/components/interactive-message/state-store.d.ts +12 -0
  102. package/dist/discord/components/interactive-message/state-store.d.ts.map +1 -0
  103. package/dist/discord/components/interactive-message/state-store.js +14 -0
  104. package/dist/discord/components/interactive-message/state-store.js.map +1 -0
  105. package/dist/discord/components/paginator/mount-paginator.js +7 -5
  106. package/dist/discord/components/paginator/mount-paginator.js.map +1 -1
  107. package/dist/discord/components/paginator/paginator-view.d.ts +1 -1
  108. package/dist/discord/components/paginator/paginator-view.d.ts.map +1 -1
  109. package/dist/discord/components/persistent-paginator.d.ts +1 -1
  110. package/dist/discord/components/persistent-paginator.d.ts.map +1 -1
  111. package/dist/discord/components/persistent-paginator.js +6 -6
  112. package/dist/discord/components/persistent-paginator.js.map +1 -1
  113. package/dist/discord/components/settings-editor/from-declaration-controls.d.ts +67 -0
  114. package/dist/discord/components/settings-editor/from-declaration-controls.d.ts.map +1 -0
  115. package/dist/discord/components/settings-editor/from-declaration-controls.js +245 -0
  116. package/dist/discord/components/settings-editor/from-declaration-controls.js.map +1 -0
  117. package/dist/discord/components/settings-editor/from-declaration-display.d.ts +23 -0
  118. package/dist/discord/components/settings-editor/from-declaration-display.d.ts.map +1 -0
  119. package/dist/discord/components/settings-editor/from-declaration-display.js +114 -0
  120. package/dist/discord/components/settings-editor/from-declaration-display.js.map +1 -0
  121. package/dist/discord/components/settings-editor/from-declaration-layout.d.ts +33 -0
  122. package/dist/discord/components/settings-editor/from-declaration-layout.d.ts.map +1 -0
  123. package/dist/discord/components/settings-editor/from-declaration-layout.js +178 -0
  124. package/dist/discord/components/settings-editor/from-declaration-layout.js.map +1 -0
  125. package/dist/discord/components/settings-editor/from-declaration-search.d.ts +27 -0
  126. package/dist/discord/components/settings-editor/from-declaration-search.d.ts.map +1 -0
  127. package/dist/discord/components/settings-editor/from-declaration-search.js +58 -0
  128. package/dist/discord/components/settings-editor/from-declaration-search.js.map +1 -0
  129. package/dist/discord/components/settings-editor/from-declaration-stored.d.ts +21 -0
  130. package/dist/discord/components/settings-editor/from-declaration-stored.d.ts.map +1 -0
  131. package/dist/discord/components/settings-editor/from-declaration-stored.js +37 -0
  132. package/dist/discord/components/settings-editor/from-declaration-stored.js.map +1 -0
  133. package/dist/discord/components/settings-editor/from-declaration-subject.d.ts +32 -0
  134. package/dist/discord/components/settings-editor/from-declaration-subject.d.ts.map +1 -0
  135. package/dist/discord/components/settings-editor/from-declaration-subject.js +65 -0
  136. package/dist/discord/components/settings-editor/from-declaration-subject.js.map +1 -0
  137. package/dist/discord/components/settings-editor/from-declaration-values.d.ts +57 -0
  138. package/dist/discord/components/settings-editor/from-declaration-values.d.ts.map +1 -0
  139. package/dist/discord/components/settings-editor/from-declaration-values.js +187 -0
  140. package/dist/discord/components/settings-editor/from-declaration-values.js.map +1 -0
  141. package/dist/discord/components/settings-editor/from-declaration.d.ts +39 -0
  142. package/dist/discord/components/settings-editor/from-declaration.d.ts.map +1 -0
  143. package/dist/discord/components/settings-editor/from-declaration.js +132 -0
  144. package/dist/discord/components/settings-editor/from-declaration.js.map +1 -0
  145. package/dist/discord/components/settings-editor/index.d.ts +3 -1
  146. package/dist/discord/components/settings-editor/index.d.ts.map +1 -1
  147. package/dist/discord/components/settings-editor/index.js +6 -3
  148. package/dist/discord/components/settings-editor/index.js.map +1 -1
  149. package/dist/discord/components/settings-editor/mount-settings-editor.d.ts +16 -2
  150. package/dist/discord/components/settings-editor/mount-settings-editor.d.ts.map +1 -1
  151. package/dist/discord/components/settings-editor/mount-settings-editor.js +14 -10
  152. package/dist/discord/components/settings-editor/mount-settings-editor.js.map +1 -1
  153. package/dist/discord/components/settings-editor/navigation.d.ts +20 -0
  154. package/dist/discord/components/settings-editor/navigation.d.ts.map +1 -1
  155. package/dist/discord/components/settings-editor/navigation.js +22 -0
  156. package/dist/discord/components/settings-editor/navigation.js.map +1 -1
  157. package/dist/discord/components/settings-editor/settings-editor-card.view.d.ts +4 -3
  158. package/dist/discord/components/settings-editor/settings-editor-card.view.d.ts.map +1 -1
  159. package/dist/discord/components/settings-editor/settings-editor-card.view.js +60 -34
  160. package/dist/discord/components/settings-editor/settings-editor-card.view.js.map +1 -1
  161. package/dist/discord/components/settings-editor/settings-editor-field-modal.d.ts +2 -1
  162. package/dist/discord/components/settings-editor/settings-editor-field-modal.d.ts.map +1 -1
  163. package/dist/discord/components/settings-editor/settings-editor-field-modal.js +48 -72
  164. package/dist/discord/components/settings-editor/settings-editor-field-modal.js.map +1 -1
  165. package/dist/discord/components/settings-editor/settings-editor-field-values.d.ts +6 -0
  166. package/dist/discord/components/settings-editor/settings-editor-field-values.d.ts.map +1 -0
  167. package/dist/discord/components/settings-editor/settings-editor-field-values.js +13 -0
  168. package/dist/discord/components/settings-editor/settings-editor-field-values.js.map +1 -0
  169. package/dist/discord/components/settings-editor/settings-editor-fields.d.ts +6 -5
  170. package/dist/discord/components/settings-editor/settings-editor-fields.d.ts.map +1 -1
  171. package/dist/discord/components/settings-editor/settings-editor-fields.js +0 -10
  172. package/dist/discord/components/settings-editor/settings-editor-fields.js.map +1 -1
  173. package/dist/discord/components/settings-editor/settings-editor.view.d.ts +3 -2
  174. package/dist/discord/components/settings-editor/settings-editor.view.d.ts.map +1 -1
  175. package/dist/discord/components/settings-editor/settings-editor.view.js +4 -21
  176. package/dist/discord/components/settings-editor/settings-editor.view.js.map +1 -1
  177. package/dist/discord/events/event-guild-id.d.ts +10 -0
  178. package/dist/discord/events/event-guild-id.d.ts.map +1 -0
  179. package/dist/discord/events/event-guild-id.js +37 -0
  180. package/dist/discord/events/event-guild-id.js.map +1 -0
  181. package/dist/discord/events/event-router.d.ts +17 -3
  182. package/dist/discord/events/event-router.d.ts.map +1 -1
  183. package/dist/discord/events/event-router.js +33 -9
  184. package/dist/discord/events/event-router.js.map +1 -1
  185. package/dist/discord/i18n.d.ts +17 -2
  186. package/dist/discord/i18n.d.ts.map +1 -1
  187. package/dist/discord/i18n.js +43 -6
  188. package/dist/discord/i18n.js.map +1 -1
  189. package/dist/discord/interaction/interaction-locale.d.ts +14 -0
  190. package/dist/discord/interaction/interaction-locale.d.ts.map +1 -0
  191. package/dist/discord/interaction/interaction-locale.js +12 -0
  192. package/dist/discord/interaction/interaction-locale.js.map +1 -0
  193. package/dist/discord/interaction/locale-resolver.d.ts +27 -0
  194. package/dist/discord/interaction/locale-resolver.d.ts.map +1 -0
  195. package/dist/discord/interaction/locale-resolver.js +3 -0
  196. package/dist/discord/interaction/locale-resolver.js.map +1 -0
  197. package/dist/discord/interaction/modal.d.ts.map +1 -1
  198. package/dist/discord/interaction/modal.js +5 -40
  199. package/dist/discord/interaction/modal.js.map +1 -1
  200. package/dist/discord/interaction/reply-locale.d.ts +18 -0
  201. package/dist/discord/interaction/reply-locale.d.ts.map +1 -0
  202. package/dist/discord/interaction/reply-locale.js +25 -0
  203. package/dist/discord/interaction/reply-locale.js.map +1 -0
  204. package/dist/discord/interaction/select-bounds.d.ts +19 -0
  205. package/dist/discord/interaction/select-bounds.d.ts.map +1 -0
  206. package/dist/discord/interaction/select-bounds.js +17 -0
  207. package/dist/discord/interaction/select-bounds.js.map +1 -0
  208. package/dist/discord/interaction/select-menu.d.ts.map +1 -1
  209. package/dist/discord/interaction/select-menu.js +2 -9
  210. package/dist/discord/interaction/select-menu.js.map +1 -1
  211. package/dist/discord/placeholder-registry.d.ts +1 -1
  212. package/dist/discord/placeholder-registry.d.ts.map +1 -1
  213. package/dist/discord/presenter.d.ts +1 -1
  214. package/dist/discord/presenter.d.ts.map +1 -1
  215. package/dist/discord/settings/discord-guild-directory.d.ts +28 -0
  216. package/dist/discord/settings/discord-guild-directory.d.ts.map +1 -0
  217. package/dist/discord/settings/discord-guild-directory.js +171 -0
  218. package/dist/discord/settings/discord-guild-directory.js.map +1 -0
  219. package/dist/discord/settings/guild-locale-resolver.d.ts +25 -0
  220. package/dist/discord/settings/guild-locale-resolver.d.ts.map +1 -0
  221. package/dist/discord/settings/guild-locale-resolver.js +33 -0
  222. package/dist/discord/settings/guild-locale-resolver.js.map +1 -0
  223. package/dist/discord/settings/is-module-disabled.d.ts +16 -0
  224. package/dist/discord/settings/is-module-disabled.d.ts.map +1 -0
  225. package/dist/discord/settings/is-module-disabled.js +20 -0
  226. package/dist/discord/settings/is-module-disabled.js.map +1 -0
  227. package/dist/discord/settings/module-disabled-embed.d.ts +13 -0
  228. package/dist/discord/settings/module-disabled-embed.d.ts.map +1 -0
  229. package/dist/discord/settings/module-disabled-embed.js +16 -0
  230. package/dist/discord/settings/module-disabled-embed.js.map +1 -0
  231. package/dist/discord/settings/require-configured.d.ts +26 -0
  232. package/dist/discord/settings/require-configured.d.ts.map +1 -0
  233. package/dist/discord/settings/require-configured.js +62 -0
  234. package/dist/discord/settings/require-configured.js.map +1 -0
  235. package/dist/discord/ui/color-aliases.d.ts +31 -0
  236. package/dist/discord/ui/color-aliases.d.ts.map +1 -0
  237. package/dist/discord/ui/color-aliases.js +66 -0
  238. package/dist/discord/ui/color-aliases.js.map +1 -0
  239. package/dist/discord/ui/color-input.d.ts +5 -32
  240. package/dist/discord/ui/color-input.d.ts.map +1 -1
  241. package/dist/discord/ui/color-input.js +8 -157
  242. package/dist/discord/ui/color-input.js.map +1 -1
  243. package/dist/discord/ui/colors.d.ts +0 -2
  244. package/dist/discord/ui/colors.d.ts.map +1 -1
  245. package/dist/discord/ui/colors.js +4 -5
  246. package/dist/discord/ui/colors.js.map +1 -1
  247. package/dist/discord/ui/embed.d.ts.map +1 -1
  248. package/dist/discord/ui/embed.js +3 -8
  249. package/dist/discord/ui/embed.js.map +1 -1
  250. package/dist/discord/ui/truncate-text.d.ts +11 -0
  251. package/dist/discord/ui/truncate-text.d.ts.map +1 -0
  252. package/dist/discord/ui/truncate-text.js +19 -0
  253. package/dist/discord/ui/truncate-text.js.map +1 -0
  254. package/dist/errors/error-message.d.ts +9 -0
  255. package/dist/errors/error-message.d.ts.map +1 -0
  256. package/dist/errors/error-message.js +14 -0
  257. package/dist/errors/error-message.js.map +1 -0
  258. package/dist/i18n/business-message.d.ts +1 -1
  259. package/dist/i18n/business-message.d.ts.map +1 -1
  260. package/dist/i18n/catalog.d.ts +9 -0
  261. package/dist/i18n/catalog.d.ts.map +1 -1
  262. package/dist/i18n/catalog.js +4 -0
  263. package/dist/i18n/catalog.js.map +1 -1
  264. package/dist/i18n/locale.d.ts +2 -0
  265. package/dist/i18n/locale.d.ts.map +1 -1
  266. package/dist/i18n/locale.js +3 -1
  267. package/dist/i18n/locale.js.map +1 -1
  268. package/dist/i18n/translator.d.ts +2 -0
  269. package/dist/i18n/translator.d.ts.map +1 -1
  270. package/dist/i18n/translator.js.map +1 -1
  271. package/dist/module/module.d.ts +15 -1
  272. package/dist/module/module.d.ts.map +1 -1
  273. package/dist/resilience/retry.js +2 -2
  274. package/dist/resilience/retry.js.map +1 -1
  275. package/dist/scheduler/scheduler.d.ts.map +1 -1
  276. package/dist/scheduler/scheduler.js +2 -4
  277. package/dist/scheduler/scheduler.js.map +1 -1
  278. package/dist/settings/cache.d.ts +29 -0
  279. package/dist/settings/cache.d.ts.map +1 -0
  280. package/dist/settings/cache.js +47 -0
  281. package/dist/settings/cache.js.map +1 -0
  282. package/dist/settings/choice.d.ts +10 -0
  283. package/dist/settings/choice.d.ts.map +1 -0
  284. package/dist/settings/choice.js +3 -0
  285. package/dist/settings/choice.js.map +1 -0
  286. package/dist/settings/decode-stored.d.ts +20 -0
  287. package/dist/settings/decode-stored.d.ts.map +1 -0
  288. package/dist/settings/decode-stored.js +35 -0
  289. package/dist/settings/decode-stored.js.map +1 -0
  290. package/dist/settings/define-settings.d.ts +52 -0
  291. package/dist/settings/define-settings.d.ts.map +1 -0
  292. package/dist/settings/define-settings.js +141 -0
  293. package/dist/settings/define-settings.js.map +1 -0
  294. package/dist/settings/describe-field.d.ts +19 -0
  295. package/dist/settings/describe-field.d.ts.map +1 -0
  296. package/dist/settings/describe-field.js +131 -0
  297. package/dist/settings/describe-field.js.map +1 -0
  298. package/dist/settings/describe.d.ts +27 -0
  299. package/dist/settings/describe.d.ts.map +1 -0
  300. package/dist/settings/describe.js +62 -0
  301. package/dist/settings/describe.js.map +1 -0
  302. package/dist/settings/duration.d.ts +16 -0
  303. package/dist/settings/duration.d.ts.map +1 -0
  304. package/dist/settings/duration.js +56 -0
  305. package/dist/settings/duration.js.map +1 -0
  306. package/dist/settings/field-order.d.ts +37 -0
  307. package/dist/settings/field-order.d.ts.map +1 -0
  308. package/dist/settings/field-order.js +100 -0
  309. package/dist/settings/field-order.js.map +1 -0
  310. package/dist/settings/field-search.d.ts +10 -0
  311. package/dist/settings/field-search.d.ts.map +1 -0
  312. package/dist/settings/field-search.js +18 -0
  313. package/dist/settings/field-search.js.map +1 -0
  314. package/dist/settings/fields/builders.d.ts +41 -0
  315. package/dist/settings/fields/builders.d.ts.map +1 -0
  316. package/dist/settings/fields/builders.js +83 -0
  317. package/dist/settings/fields/builders.js.map +1 -0
  318. package/dist/settings/fields/field.d.ts +199 -0
  319. package/dist/settings/fields/field.d.ts.map +1 -0
  320. package/dist/settings/fields/field.js +33 -0
  321. package/dist/settings/fields/field.js.map +1 -0
  322. package/dist/settings/fields/zod-schema.d.ts +67 -0
  323. package/dist/settings/fields/zod-schema.d.ts.map +1 -0
  324. package/dist/settings/fields/zod-schema.js +281 -0
  325. package/dist/settings/fields/zod-schema.js.map +1 -0
  326. package/dist/settings/in-memory/in-memory-guild-directory.d.ts +24 -0
  327. package/dist/settings/in-memory/in-memory-guild-directory.d.ts.map +1 -0
  328. package/dist/settings/in-memory/in-memory-guild-directory.js +42 -0
  329. package/dist/settings/in-memory/in-memory-guild-directory.js.map +1 -0
  330. package/dist/settings/in-memory/in-memory-settings-store.d.ts +8 -0
  331. package/dist/settings/in-memory/in-memory-settings-store.d.ts.map +1 -0
  332. package/dist/settings/in-memory/in-memory-settings-store.js +43 -0
  333. package/dist/settings/in-memory/in-memory-settings-store.js.map +1 -0
  334. package/dist/settings/in-memory/in-process-notifier.d.ts +9 -0
  335. package/dist/settings/in-memory/in-process-notifier.d.ts.map +1 -0
  336. package/dist/settings/in-memory/in-process-notifier.js +32 -0
  337. package/dist/settings/in-memory/in-process-notifier.js.map +1 -0
  338. package/dist/settings/index.d.ts +22 -0
  339. package/dist/settings/index.d.ts.map +1 -0
  340. package/dist/settings/index.js +31 -0
  341. package/dist/settings/index.js.map +1 -0
  342. package/dist/settings/is-plain-object.d.ts +6 -0
  343. package/dist/settings/is-plain-object.d.ts.map +1 -0
  344. package/dist/settings/is-plain-object.js +15 -0
  345. package/dist/settings/is-plain-object.js.map +1 -0
  346. package/dist/settings/messages.d.ts +61 -0
  347. package/dist/settings/messages.d.ts.map +1 -0
  348. package/dist/settings/messages.js +155 -0
  349. package/dist/settings/messages.js.map +1 -0
  350. package/dist/settings/migrate.d.ts +35 -0
  351. package/dist/settings/migrate.d.ts.map +1 -0
  352. package/dist/settings/migrate.js +42 -0
  353. package/dist/settings/migrate.js.map +1 -0
  354. package/dist/settings/ports/guild-directory.d.ts +61 -0
  355. package/dist/settings/ports/guild-directory.d.ts.map +1 -0
  356. package/dist/settings/ports/guild-directory.js +3 -0
  357. package/dist/settings/ports/guild-directory.js.map +1 -0
  358. package/dist/settings/ports/settings-changed-notifier.d.ts +20 -0
  359. package/dist/settings/ports/settings-changed-notifier.d.ts.map +1 -0
  360. package/dist/settings/ports/settings-changed-notifier.js +3 -0
  361. package/dist/settings/ports/settings-changed-notifier.js.map +1 -0
  362. package/dist/settings/ports/settings-store.d.ts +76 -0
  363. package/dist/settings/ports/settings-store.d.ts.map +1 -0
  364. package/dist/settings/ports/settings-store.js +3 -0
  365. package/dist/settings/ports/settings-store.js.map +1 -0
  366. package/dist/settings/registry.d.ts +31 -0
  367. package/dist/settings/registry.d.ts.map +1 -0
  368. package/dist/settings/registry.js +102 -0
  369. package/dist/settings/registry.js.map +1 -0
  370. package/dist/settings/settings-declaration-error.d.ts +13 -0
  371. package/dist/settings/settings-declaration-error.d.ts.map +1 -0
  372. package/dist/settings/settings-declaration-error.js +22 -0
  373. package/dist/settings/settings-declaration-error.js.map +1 -0
  374. package/dist/settings/settings-service.d.ts +148 -0
  375. package/dist/settings/settings-service.d.ts.map +1 -0
  376. package/dist/settings/settings-service.js +279 -0
  377. package/dist/settings/settings-service.js.map +1 -0
  378. package/dist/settings/settings-validation-error.d.ts +23 -0
  379. package/dist/settings/settings-validation-error.d.ts.map +1 -0
  380. package/dist/settings/settings-validation-error.js +17 -0
  381. package/dist/settings/settings-validation-error.js.map +1 -0
  382. package/dist/settings/status.d.ts +16 -0
  383. package/dist/settings/status.d.ts.map +1 -0
  384. package/dist/settings/status.js +18 -0
  385. package/dist/settings/status.js.map +1 -0
  386. package/dist/settings/suggest.d.ts +77 -0
  387. package/dist/settings/suggest.d.ts.map +1 -0
  388. package/dist/settings/suggest.js +192 -0
  389. package/dist/settings/suggest.js.map +1 -0
  390. package/dist/settings/system/kernel-settings.d.ts +43 -0
  391. package/dist/settings/system/kernel-settings.d.ts.map +1 -0
  392. package/dist/settings/system/kernel-settings.js +53 -0
  393. package/dist/settings/system/kernel-settings.js.map +1 -0
  394. package/dist/settings/system/module-gate.d.ts +31 -0
  395. package/dist/settings/system/module-gate.d.ts.map +1 -0
  396. package/dist/settings/system/module-gate.js +34 -0
  397. package/dist/settings/system/module-gate.js.map +1 -0
  398. package/dist/settings/testing/index.d.ts +2 -0
  399. package/dist/settings/testing/index.d.ts.map +1 -0
  400. package/dist/settings/testing/index.js +6 -0
  401. package/dist/settings/testing/index.js.map +1 -0
  402. package/dist/settings/testing/settings-store-contract.d.ts +29 -0
  403. package/dist/settings/testing/settings-store-contract.d.ts.map +1 -0
  404. package/dist/settings/testing/settings-store-contract.js +192 -0
  405. package/dist/settings/testing/settings-store-contract.js.map +1 -0
  406. package/dist/settings/timed-search.d.ts +26 -0
  407. package/dist/settings/timed-search.d.ts.map +1 -0
  408. package/dist/settings/timed-search.js +48 -0
  409. package/dist/settings/timed-search.js.map +1 -0
  410. package/dist/settings/types.d.ts +37 -0
  411. package/dist/settings/types.d.ts.map +1 -0
  412. package/dist/settings/types.js +3 -0
  413. package/dist/settings/types.js.map +1 -0
  414. package/dist/settings/validate.d.ts +55 -0
  415. package/dist/settings/validate.d.ts.map +1 -0
  416. package/dist/settings/validate.js +196 -0
  417. package/dist/settings/validate.js.map +1 -0
  418. package/package.json +463 -88
  419. package/src/authz/require-level-guard.ts +1 -1
  420. package/src/color.ts +134 -0
  421. package/src/discord/command/all-required.ts +12 -0
  422. package/src/discord/command/autocomplete-dispatcher.ts +2 -1
  423. package/src/discord/command/autocomplete-limits.ts +2 -0
  424. package/src/discord/command/autocomplete.ts +8 -7
  425. package/src/discord/command/command-responders.ts +39 -0
  426. package/src/discord/command/context.ts +14 -54
  427. package/src/discord/command/cooldown-guard.ts +1 -1
  428. package/src/discord/command/create-command.ts +19 -94
  429. package/src/discord/command/create-context-menu-command.ts +19 -97
  430. package/src/discord/command/errors.ts +1 -1
  431. package/src/discord/command/guard.ts +24 -12
  432. package/src/discord/command/options.ts +202 -412
  433. package/src/discord/command/passes-guard.ts +37 -0
  434. package/src/discord/command/permission-guard.ts +1 -1
  435. package/src/discord/command/render-command-failure.ts +71 -0
  436. package/src/discord/command/route-key.ts +9 -0
  437. package/src/discord/command/router.ts +73 -12
  438. package/src/discord/command/send-embed.ts +42 -0
  439. package/src/discord/command/types.ts +7 -1
  440. package/src/discord/components/component-access.ts +20 -0
  441. package/src/discord/components/component-router.ts +73 -36
  442. package/src/discord/components/interactive-message/index.ts +5 -3
  443. package/src/discord/components/interactive-message/interactive-message-collector.ts +4 -68
  444. package/src/discord/components/interactive-message/message-edit-options.ts +47 -0
  445. package/src/discord/components/interactive-message/mount-interactive-message.ts +5 -3
  446. package/src/discord/components/interactive-message/state-store.ts +20 -0
  447. package/src/discord/components/paginator/mount-paginator.ts +3 -3
  448. package/src/discord/components/paginator/paginator-view.ts +1 -1
  449. package/src/discord/components/persistent-paginator.ts +8 -9
  450. package/src/discord/components/settings-editor/from-declaration-controls.ts +371 -0
  451. package/src/discord/components/settings-editor/from-declaration-display.ts +155 -0
  452. package/src/discord/components/settings-editor/from-declaration-layout.ts +247 -0
  453. package/src/discord/components/settings-editor/from-declaration-search.ts +77 -0
  454. package/src/discord/components/settings-editor/from-declaration-stored.ts +39 -0
  455. package/src/discord/components/settings-editor/from-declaration-subject.ts +110 -0
  456. package/src/discord/components/settings-editor/from-declaration-values.ts +240 -0
  457. package/src/discord/components/settings-editor/from-declaration.ts +218 -0
  458. package/src/discord/components/settings-editor/index.ts +5 -2
  459. package/src/discord/components/settings-editor/mount-settings-editor.ts +28 -10
  460. package/src/discord/components/settings-editor/navigation.ts +41 -0
  461. package/src/discord/components/settings-editor/settings-editor-card.view.ts +79 -36
  462. package/src/discord/components/settings-editor/settings-editor-field-modal.ts +76 -68
  463. package/src/discord/components/settings-editor/settings-editor-field-values.ts +11 -0
  464. package/src/discord/components/settings-editor/settings-editor-fields.ts +6 -11
  465. package/src/discord/components/settings-editor/settings-editor.view.ts +11 -24
  466. package/src/discord/events/event-guild-id.ts +35 -0
  467. package/src/discord/events/event-router.ts +46 -13
  468. package/src/discord/i18n.ts +47 -8
  469. package/src/discord/interaction/interaction-locale.ts +19 -0
  470. package/src/discord/interaction/locale-resolver.ts +28 -0
  471. package/src/discord/interaction/modal.ts +5 -40
  472. package/src/discord/interaction/reply-locale.ts +35 -0
  473. package/src/discord/interaction/select-bounds.ts +33 -0
  474. package/src/discord/interaction/select-menu.ts +2 -9
  475. package/src/discord/placeholder-registry.ts +1 -1
  476. package/src/discord/presenter.ts +1 -1
  477. package/src/discord/settings/discord-guild-directory.ts +214 -0
  478. package/src/discord/settings/guild-locale-resolver.ts +38 -0
  479. package/src/discord/settings/is-module-disabled.ts +22 -0
  480. package/src/discord/settings/module-disabled-embed.ts +19 -0
  481. package/src/discord/settings/require-configured.ts +68 -0
  482. package/src/discord/ui/color-aliases.ts +70 -0
  483. package/src/discord/ui/color-input.ts +8 -173
  484. package/src/discord/ui/colors.ts +2 -3
  485. package/src/discord/ui/embed.ts +3 -9
  486. package/src/discord/ui/truncate-text.ts +15 -0
  487. package/src/errors/error-message.ts +10 -0
  488. package/src/i18n/business-message.ts +1 -1
  489. package/src/i18n/catalog.ts +14 -0
  490. package/src/i18n/locale.ts +3 -0
  491. package/src/i18n/translator.ts +3 -0
  492. package/src/module/module.ts +15 -1
  493. package/src/resilience/retry.ts +1 -1
  494. package/src/scheduler/scheduler.ts +2 -5
  495. package/src/settings/cache.ts +70 -0
  496. package/src/settings/choice.ts +9 -0
  497. package/src/settings/decode-stored.ts +40 -0
  498. package/src/settings/define-settings.ts +214 -0
  499. package/src/settings/describe-field.ts +155 -0
  500. package/src/settings/describe.ts +90 -0
  501. package/src/settings/duration.ts +54 -0
  502. package/src/settings/field-order.ts +128 -0
  503. package/src/settings/field-search.ts +16 -0
  504. package/src/settings/fields/builders.ts +161 -0
  505. package/src/settings/fields/field.ts +205 -0
  506. package/src/settings/fields/zod-schema.ts +300 -0
  507. package/src/settings/in-memory/in-memory-guild-directory.ts +69 -0
  508. package/src/settings/in-memory/in-memory-settings-store.ts +46 -0
  509. package/src/settings/in-memory/in-process-notifier.ts +40 -0
  510. package/src/settings/index.ts +72 -0
  511. package/src/settings/is-plain-object.ts +11 -0
  512. package/src/settings/messages.ts +161 -0
  513. package/src/settings/migrate.ts +58 -0
  514. package/src/settings/ports/guild-directory.ts +48 -0
  515. package/src/settings/ports/settings-changed-notifier.ts +20 -0
  516. package/src/settings/ports/settings-store.ts +74 -0
  517. package/src/settings/registry.ts +137 -0
  518. package/src/settings/settings-declaration-error.ts +16 -0
  519. package/src/settings/settings-service.ts +535 -0
  520. package/src/settings/settings-validation-error.ts +41 -0
  521. package/src/settings/status.ts +25 -0
  522. package/src/settings/suggest.ts +267 -0
  523. package/src/settings/system/kernel-settings.ts +74 -0
  524. package/src/settings/system/module-gate.ts +49 -0
  525. package/src/settings/testing/index.ts +7 -0
  526. package/src/settings/testing/settings-store-contract.ts +278 -0
  527. package/src/settings/timed-search.ts +56 -0
  528. package/src/settings/types.ts +42 -0
  529. package/src/settings/validate.ts +298 -0
package/README.md CHANGED
@@ -51,6 +51,300 @@ import { type Catalog, createTranslator } from "@azurioh/discord-kernel/i18n";
51
51
  - **A palette.** Embeds render in Discord's blurple until you say otherwise, so a
52
52
  bot never starts out wearing someone else's identity.
53
53
 
54
+ ## Module settings
55
+
56
+ A module declares its per-guild settings once. The kernel then validates,
57
+ stores, caches and reads them, and builds the Discord settings screen, the
58
+ autocomplete suggestions and a JSON Schema for other surfaces (a web
59
+ dashboard) from that single declaration. Everything lives behind two entry
60
+ points: `@azurioh/discord-kernel/settings` and, for tests,
61
+ `@azurioh/discord-kernel/settings/testing`.
62
+
63
+ ### Declaring settings
64
+
65
+ Every text is a catalog key (with an English source), never a literal:
66
+
67
+ ```ts
68
+ import { defineSettings, field } from "@azurioh/discord-kernel/settings";
69
+
70
+ export const tickets = defineSettings({
71
+ id: "tickets",
72
+ version: 1,
73
+ labels: { title: "tickets.settings.title" },
74
+ groups: { routing: { label: "tickets.settings.routing" } },
75
+ fields: {
76
+ channel: field.channel({ label: "tickets.channel", types: ["text"], required: true, ui: { group: "routing" } }),
77
+ staffRole: field.role({ label: "tickets.staff-role", ui: { group: "routing" } }),
78
+ maxOpen: field.integer({ label: "tickets.max-open", min: 1, max: 10, default: 3 }),
79
+ cooldown: field.duration({ label: "tickets.cooldown", default: 300 }), // seconds, typed as `5m`
80
+ mode: field.enum({
81
+ label: "tickets.mode",
82
+ choices: [
83
+ { value: "open", label: "tickets.mode.open" },
84
+ { value: "closed", label: "tickets.mode.closed" },
85
+ ],
86
+ default: "open",
87
+ }),
88
+ apiKey: field.secret({ label: "tickets.api-key" }),
89
+ pingRoles: field.list(field.role(), { label: "tickets.ping-roles", maxItems: 5, default: [] }),
90
+ },
91
+ });
92
+ ```
93
+
94
+ Field kinds: `text`, `integer`, `number`, `boolean`, `enum`, `color`,
95
+ `duration`, `channel`, `role`, `user`, `secret`, `list` and `toggles`. Give the
96
+ declarations to a `BotModule` (`settings: [tickets]`), then build the registry
97
+ and the service once, in the composition root:
98
+
99
+ ```ts
100
+ import { createDiscordGuildDirectory } from "@azurioh/discord-kernel/discord/settings/discord-guild-directory";
101
+ import {
102
+ createInProcessNotifier,
103
+ createSettingsRegistry,
104
+ createSettingsService,
105
+ SETTINGS_CATALOG,
106
+ } from "@azurioh/discord-kernel/settings";
107
+
108
+ translations.register(SETTINGS_CATALOG); // with CORE_CATALOG and every module's catalog
109
+ const registry = createSettingsRegistry({
110
+ declarations: modules.flatMap((module) => module.settings ?? []),
111
+ translations, // a key without an English source fails the boot, as does a duplicate id
112
+ modules, // builds the module toggles, see "System settings"
113
+ });
114
+ const settings = createSettingsService({
115
+ registry,
116
+ store, // your SettingsStore adapter, see "Storage adapters"
117
+ guilds: createDiscordGuildDirectory(client),
118
+ notifier: createInProcessNotifier(logger),
119
+ translator,
120
+ clock: systemClock,
121
+ logger,
122
+ });
123
+ ```
124
+
125
+ ### Reading and writing
126
+
127
+ Values are typed from the declaration: a required field or a field with a
128
+ default is never `undefined`, a mistyped key fails to compile.
129
+
130
+ ```ts
131
+ const values = await settings.get(tickets, guildId); // cached; defaults for unset fields
132
+ values.maxOpen; // number
133
+ values.staffRole; // string | undefined
134
+
135
+ const ctx = { guildId, userId, locale }; // who writes, where, in which language
136
+ await settings.validate(tickets, guildId, { maxOpen: 50 }, ctx); // { ok: false, issues: [{ field: "maxOpen", code: "max", ... }] }
137
+ await settings.set(tickets, guildId, { maxOpen: 5, staffRole: null }, ctx); // null unsets a field
138
+ await settings.reset(tickets, guildId, ["maxOpen"], ctx); // or "all"
139
+ const { missing } = await settings.status(tickets, guildId); // required fields left unset
140
+ ```
141
+
142
+ `set` stores nothing unless every submitted field is valid, and throws a
143
+ `SettingsValidationError` listing all the issues. Two writers holding the same
144
+ `expectedRevision` cannot both win: the second gets a `ConflictError`. Every
145
+ write invalidates the cache and emits a `settings.changed` event through the
146
+ notifier. Module logic reads secrets with `get`; surfaces use `getForSurface`,
147
+ where a secret is only `{ isSet }`.
148
+
149
+ ### The Discord settings screen
150
+
151
+ `settingsEditorFromDeclaration` turns a declaration into the options of
152
+ `mountSettingsEditor`: one control per field kind, groups split into modals of
153
+ at most 5 inputs, nested levels so a card never exceeds Discord's component
154
+ budget, and every save sent through `service.set`, so the screen accepts and
155
+ refuses exactly what the service does.
156
+
157
+ ```ts
158
+ import {
159
+ editorComponentIds,
160
+ mountSettingsEditor,
161
+ settingsEditorFromDeclaration,
162
+ } from "@azurioh/discord-kernel/discord/components/settings-editor";
163
+
164
+ const adapted = await settingsEditorFromDeclaration(tickets, settings, {
165
+ guildId,
166
+ userId,
167
+ locale: ctx.locale,
168
+ translator,
169
+ });
170
+ await mountSettingsEditor(ctx.interaction, {
171
+ ...adapted,
172
+ ids: editorComponentIds("tickets-settings"),
173
+ chrome, // your title and colours
174
+ translator,
175
+ locale: ctx.locale,
176
+ clock: systemClock,
177
+ logger,
178
+ });
179
+ ```
180
+
181
+ ### Describing settings for other surfaces
182
+
183
+ `settings.describe(declaration, locale)` returns a JSON Schema (draft 2020-12)
184
+ with every label and description translated (English for an unsupported
185
+ locale), and kernel hints (kind, group, order, secret) under `x-kernel`. A
186
+ secret's value is never in it. A web dashboard renders its form from this and
187
+ writes through the same `set`.
188
+
189
+ ### Suggestions and strict fields
190
+
191
+ A field can offer suggestions, static or searched:
192
+
193
+ ```ts
194
+ timezone: field.text({
195
+ label: "tickets.timezone",
196
+ suggest: { resolve: searchTimezones, label: timezoneLabel, strict: true },
197
+ }),
198
+ ```
199
+
200
+ `settings.suggest(declaration, key, query, { ...ctx, values })` returns at most
201
+ 25 `Choice`s in the command autocomplete's own format, so one search serves
202
+ `/config set` and the settings screen (where a searchable field becomes a
203
+ select). Channel, role and user fields search the guild without any code. A
204
+ search slower than 2.5 s (`SUGGESTION_TIMEOUT_MS`) or failing yields nothing
205
+ and is logged. `settings.label(...)` gives a stored value's readable name. A
206
+ **strict** field accepts only a value its search knows; anything else is an
207
+ `unknownChoice` issue.
208
+
209
+ ### System settings: module toggles and guild language
210
+
211
+ The kernel declares its own settings like any module (`registry.kernel`): which
212
+ modules are enabled on the guild (`defaultEnabled` on a `BotModule`, `true`
213
+ unless said otherwise) and the bot's language there. Pass a `ModuleGate` to the
214
+ routers and each gated handler is skipped on a guild that disabled its module,
215
+ with a translated reply for commands and components:
216
+
217
+ ```ts
218
+ import { createModuleGate } from "@azurioh/discord-kernel/settings";
219
+
220
+ const gate = createModuleGate({ service: settings, registry, logger });
221
+ const commands = new CommandRouter({ presenter, logger, translator, gate, localeResolver });
222
+ const components = new ComponentRouter({ presenter, logger, translator, gate, localeResolver });
223
+ const events = new EventRouter(logger, gate);
224
+ commands.registerAll(module.commands ?? [], module.name); // no name: never gated
225
+ ```
226
+
227
+ Scheduled jobs call `gate.isEnabled(moduleName, guildId)` themselves. The guild
228
+ language reaches every reply through the `LocaleResolver` port, described in
229
+ [Per-guild values](#per-guild-values).
230
+
231
+ ### Blocking a command until its module is configured
232
+
233
+ `requireConfigured(declaration, service)` is a guard for a command or a
234
+ component handler. It denies while a required field is unset, and lets the call
235
+ through as soon as it is set, without a restart. Members with *Manage Server*
236
+ also read which settings are missing.
237
+
238
+ ```ts
239
+ import { requireConfigured } from "@azurioh/discord-kernel/discord/settings/require-configured";
240
+
241
+ createCommand({ name: "ticket", guard: requireConfigured(tickets, settings), handler });
242
+ ```
243
+
244
+ ### Evolving module settings
245
+
246
+ Adding a field needs nothing: guilds configured before read its default.
247
+ Removing one needs nothing either: its stored value is ignored and dropped on
248
+ the next write. To reshape stored values (rename a key, change a unit), raise
249
+ the declaration's `version` and give it a `migrate`:
250
+
251
+ ```ts
252
+ export const warnings = defineSettings({
253
+ id: "warnings",
254
+ version: 2, // was 1: `maxWarnings` became `warnLimit`
255
+ migrate: (fromVersion, raw) => {
256
+ if (fromVersion !== 1) throw new Error(`no migration from version ${fromVersion}`);
257
+ const { maxWarnings, ...rest } = raw as Record<string, unknown>;
258
+ return maxWarnings === undefined ? rest : { ...rest, warnLimit: maxWarnings };
259
+ },
260
+ labels: { title: "warnings.title" },
261
+ fields: { warnLimit: field.integer({ label: "warnings.limit", min: 1, max: 10, default: 3 }) },
262
+ });
263
+ ```
264
+
265
+ Migration is lazy: the first read of a guild's older record runs `migrate`,
266
+ validates the result like any stored value, and writes it back once under the
267
+ new version (a concurrent reader on another shard loses the compare-and-set and
268
+ simply reads the migrated record). `set` and `reset` migrate first too. Rules for
269
+ `migrate`:
270
+
271
+ - **Pure.** It receives a copy of the stored values and returns the new ones;
272
+ no I/O, no clock, no randomness.
273
+ - **Every older version.** A guild may skip releases, so `fromVersion` can be
274
+ any version below the current one. Chain the steps (v1 → v2 → v3) or throw
275
+ for a version you no longer support.
276
+ - **Failures are safe.** When it throws or its result fails validation, nothing
277
+ is written, the error is logged with the guild, module and versions, and the
278
+ guild reads defaults for the fields it cannot read. A record written by a
279
+ newer version (after a rollback) is read but never overwritten.
280
+
281
+ ### Storage adapters
282
+
283
+ Settings persistence is hexagonal: the kernel declares the `SettingsStore` port
284
+ and never imports a database driver. Each database sits behind an adapter your
285
+ bot owns, and the composition root picks one at boot.
286
+
287
+ ```mermaid
288
+ flowchart LR
289
+ service["SettingsService (kernel)"] --> port(["SettingsStore port"])
290
+ port -.implemented by.-> memory["createInMemorySettingsStore (kernel, tests)"]
291
+ port -.implemented by.-> json["JSON file adapter (your bot)"]
292
+ port -.implemented by.-> sql["SQLite / Postgres adapter (your bot)"]
293
+ port -.implemented by.-> other["MongoDB / Redis adapter (your bot)"]
294
+ ```
295
+
296
+ The port has three methods: `read`, `write` and `delete`. It stores one
297
+ `StoredSettings` record per `(guildId, moduleId)`, and every field of a record
298
+ is JSON-serialisable. An adapter must honour these guarantees:
299
+
300
+ | Guarantee | Meaning |
301
+ | --------- | ------- |
302
+ | A missing record reads as `null` | `read` returns `null` until the first write and after a delete |
303
+ | Atomic compare-and-set | `write` lands only if the stored revision equals `expectedRevision` (`null` means no record yet), checked and applied in one atomic step, so of two writers holding the same revision exactly one wins |
304
+ | Conflicts change nothing | A mismatch throws the kernel's `ConflictError` and leaves the stored record as it was. Any other failure is thrown as it is, never as a conflict |
305
+ | Isolation | One `(guildId, moduleId)` never reads, overwrites or deletes another |
306
+ | Idempotent delete | Deleting a missing record succeeds |
307
+ | Independent copies | The store keeps no reference to the record it was given and hands out none it keeps |
308
+ | Faithful round-trip | `read` returns a record equal to the one written (JSON values, `updatedBy` absent stays absent) |
309
+
310
+ #### Writing an adapter for any database
311
+
312
+ The only hard part is the compare-and-set. Use the native primitive that checks
313
+ and writes in one step, never a read followed by a write:
314
+
315
+ - **SQL (Postgres, MySQL, SQLite):** a table keyed `(guild_id, module_id)`. A create
316
+ is `INSERT ... ON CONFLICT DO NOTHING` and an update is
317
+ `UPDATE ... WHERE guild_id = ? AND module_id = ? AND revision = ?`. Zero affected
318
+ rows means `ConflictError`. The sandbox bot's `src/shared/settings/sqlite/` is a
319
+ worked example.
320
+ - **MongoDB:** one document per key with a unique index on `{ guildId, moduleId }`.
321
+ An update is `findOneAndUpdate({ guildId, moduleId, revision: expected }, { $set: record })`,
322
+ where no match means a conflict. A create is `insertOne`, where a duplicate-key error
323
+ (code 11000) means a conflict.
324
+ - **Redis:** one key per record. Either `WATCH key`, `GET`, compare, then
325
+ `MULTI`/`SET`/`EXEC`, where a nil `EXEC` means a conflict, or a Lua script that
326
+ compares the stored revision and sets the key atomically.
327
+
328
+ Then prove the adapter with the contract suite. It is runner-agnostic: pass it
329
+ your runner's `describe`, `it` and `expect`, and a factory that returns an empty store:
330
+
331
+ ```ts
332
+ // tests/postgres-settings-store.test.ts
333
+ import { runSettingsStoreContract } from "@azurioh/discord-kernel/settings/testing";
334
+ import { afterAll, describe, expect, it } from "vitest";
335
+ import { createPostgresSettingsStore } from "../src/postgres-settings-store";
336
+ import { createTestDatabase } from "./support/test-database";
337
+
338
+ const database = await createTestDatabase(); // one fresh schema per run
339
+ afterAll(() => database.drop());
340
+
341
+ runSettingsStoreContract(() => createPostgresSettingsStore(database.freshTable()), { describe, it, expect });
342
+ ```
343
+
344
+ Every guarantee in the table has a case in the suite, including two concurrent
345
+ writers with the same revision. The kernel's own `createInMemorySettingsStore`
346
+ passes the same suite and is the store to use in tests.
347
+
54
348
  ## Making it yours
55
349
 
56
350
  Two things are global by nature — a bot has one look, decided once — and are set
@@ -58,7 +352,7 @@ from the composition root before any module is constructed:
58
352
 
59
353
  ```ts
60
354
  import { configureEmbedColors } from "@azurioh/discord-kernel/discord/ui/colors";
61
- import { registerColorAliases } from "@azurioh/discord-kernel/discord/ui/color-input";
355
+ import { registerColorAliases } from "@azurioh/discord-kernel/discord/ui/color-aliases";
62
356
 
63
357
  configureEmbedColors({ brand: 0xf3c909 });
64
358
  registerColorAliases({ gold: "#f3c909", or: "#f3c909" });
@@ -67,6 +361,29 @@ registerColorAliases({ gold: "#f3c909", or: "#f3c909" });
67
361
  Everything else is injected: your modules are factories receiving a container
68
362
  you define, so nothing in the kernel is reachable as a singleton.
69
363
 
364
+ ## Per-guild values
365
+
366
+ A value the kernel uses when it answers an interaction is read through a
367
+ resolver port, per guild, never from a global. The bot passes a default
368
+ implementation built from its own configuration, and any module can replace it
369
+ with its own. Today that value is the reply language:
370
+
371
+ ```ts
372
+ import { createGuildLocaleResolver } from "@azurioh/discord-kernel/discord/settings/guild-locale-resolver";
373
+
374
+ // Member locale → guild language setting → guild Discord locale → translator default.
375
+ const localeResolver = createGuildLocaleResolver({ service: settings, registry, translator });
376
+ const commands = new CommandRouter({ presenter, logger, translator, localeResolver });
377
+ const components = new ComponentRouter({ presenter, logger, translator, localeResolver });
378
+ ```
379
+
380
+ Any object implementing `LocaleResolver`
381
+ (`@azurioh/discord-kernel/discord/interaction/locale-resolver`) fits:
382
+ `{ resolve({ locale, guildLocale, guildId }) => Promise<Locale> }`. Without one,
383
+ the routers keep the interaction's own locales, so a bot without settings is
384
+ unaffected. A resolver that throws is logged and the interaction's own locales
385
+ are used.
386
+
70
387
  ## Requirements
71
388
 
72
389
  Node 22.12+, discord.js 14.27+, TypeScript 5.9. The published build is
@@ -1,7 +1,7 @@
1
1
  import type { BaseInteraction } from "discord.js";
2
2
  import type { Authorizer, PermissionLevel } from "../authz/authorizer";
3
3
  import type { Guard } from "../discord/command/guard";
4
- import type { LocalizedText } from "../i18n";
4
+ import type { LocalizedText } from "../i18n/translator";
5
5
  /**
6
6
  * Role IDs held by the interacting member, resolved without a network call:
7
7
  * `interaction.member.roles` is either the cached `GuildMemberRoleManager` (a
@@ -1 +1 @@
1
- {"version":3,"file":"require-level-guard.d.ts","sourceRoot":"","sources":["../../src/authz/require-level-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,eAAe,GAAG,MAAM,EAAE,CAOpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,eAAe,EACzB,WAAW,EAAE,aAAa,GACxB,KAAK,CAOP"}
1
+ {"version":3,"file":"require-level-guard.d.ts","sourceRoot":"","sources":["../../src/authz/require-level-guard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAsB,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,eAAe,GAAG,MAAM,EAAE,CAOpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC3B,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,eAAe,EACzB,WAAW,EAAE,aAAa,GACxB,KAAK,CAOP"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Discord's own brand colour. Kept with the base names rather than in the
3
+ * Discord ring so a `blurple` setting means the same colour on every surface,
4
+ * and so embeds fall back to it when a bot declares no palette.
5
+ */
6
+ export declare const DISCORD_BLURPLE = "#5865f2";
7
+ /**
8
+ * Colour names an administrator may type instead of a hex code, French and
9
+ * English side by side.
10
+ *
11
+ * This table is **input vocabulary, not display text**. Nothing in it is ever
12
+ * shown to anyone, and its keys must never be translated at runtime: a catalog
13
+ * lookup resolves against the reply locale, which would make `rouge` stop
14
+ * working the moment an admin's Discord is set to English — the opposite of the
15
+ * point. Both spellings are accepted from everyone, always, which only a flat
16
+ * table can promise.
17
+ *
18
+ * Fixed on purpose: a value stored from one of these names must mean the same
19
+ * colour in every bot. Names a bot adds for its own inputs live with those
20
+ * inputs, not here.
21
+ */
22
+ export declare const BASE_COLOR_NAMES: Readonly<Record<string, string>>;
23
+ /**
24
+ * Accents must not be a trap: `dore` and `doré` are the same request, and an
25
+ * administrator has no way of knowing which one a table happened to spell.
26
+ * Case and surrounding whitespace are folded for the same reason.
27
+ */
28
+ export declare function normalizeColorName(raw: string): string;
29
+ /** Index a name → `#rrggbb` table by {@link normalizeColorName}, so lookups fold case and accents. */
30
+ export declare function indexColorNames(names: Readonly<Record<string, string>>): Map<string, string>;
31
+ /**
32
+ * Normalize a hexadecimal colour code to `#rrggbb`, `null` when the input is
33
+ * not one. Surrounding whitespace is ignored.
34
+ */
35
+ export declare function parseHexColor(raw: string): string | null;
36
+ /**
37
+ * Normalize a colour to `#rrggbb`, from a hexadecimal code or from one of the
38
+ * {@link BASE_COLOR_NAMES}. `null` for anything else: the refusal belongs to
39
+ * whichever caller asked, so this only reports that it could not read the value.
40
+ */
41
+ export declare function parseColor(raw: string): string | null;
42
+ //# sourceMappingURL=color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":"AAcA;;;;GAIG;AACH,eAAO,MAAM,eAAe,YAAY,CAAC;AAiBzC;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkC7D,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMtD;AAED,sGAAsG;AACtG,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAE5F;AAQD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASxD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAErD"}
package/dist/color.js ADDED
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BASE_COLOR_NAMES = exports.DISCORD_BLURPLE = void 0;
4
+ exports.normalizeColorName = normalizeColorName;
5
+ exports.indexColorNames = indexColorNames;
6
+ exports.parseHexColor = parseHexColor;
7
+ exports.parseColor = parseColor;
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
+ * Discord's own brand colour. Kept with the base names rather than in the
23
+ * Discord ring so a `blurple` setting means the same colour on every surface,
24
+ * and so embeds fall back to it when a bot declares no palette.
25
+ */
26
+ exports.DISCORD_BLURPLE = "#5865f2";
27
+ /**
28
+ * Not `#000000`: Discord reads a zero colour as "no colour set" and renders the
29
+ * default grey bar instead, so pure black is the one value an administrator
30
+ * could ask for and never see. One step off zero reads as black.
31
+ */
32
+ const BLACK = "#010101";
33
+ const GREY = "#808080";
34
+ const CYAN = "#00ffff";
35
+ const BROWN = "#a52a2a";
36
+ const SILVER = "#c0c0c0";
37
+ const TURQUOISE = "#40e0d0";
38
+ const MAGENTA = "#ff00ff";
39
+ const NAVY = "#000080";
40
+ /**
41
+ * Colour names an administrator may type instead of a hex code, French and
42
+ * English side by side.
43
+ *
44
+ * This table is **input vocabulary, not display text**. Nothing in it is ever
45
+ * shown to anyone, and its keys must never be translated at runtime: a catalog
46
+ * lookup resolves against the reply locale, which would make `rouge` stop
47
+ * working the moment an admin's Discord is set to English — the opposite of the
48
+ * point. Both spellings are accepted from everyone, always, which only a flat
49
+ * table can promise.
50
+ *
51
+ * Fixed on purpose: a value stored from one of these names must mean the same
52
+ * colour in every bot. Names a bot adds for its own inputs live with those
53
+ * inputs, not here.
54
+ */
55
+ exports.BASE_COLOR_NAMES = {
56
+ red: RED,
57
+ rouge: RED,
58
+ blue: BLUE,
59
+ bleu: BLUE,
60
+ green: GREEN,
61
+ vert: GREEN,
62
+ yellow: YELLOW,
63
+ jaune: YELLOW,
64
+ orange: ORANGE,
65
+ purple: PURPLE,
66
+ // French for purple, not the CSS `violet` (a pale pink): an admin typing it
67
+ // here is asking for the colour the word means in their own language.
68
+ violet: PURPLE,
69
+ pink: PINK,
70
+ rose: PINK,
71
+ white: WHITE,
72
+ blanc: WHITE,
73
+ black: BLACK,
74
+ noir: BLACK,
75
+ grey: GREY,
76
+ gray: GREY,
77
+ gris: GREY,
78
+ cyan: CYAN,
79
+ brown: BROWN,
80
+ marron: BROWN,
81
+ silver: SILVER,
82
+ argent: SILVER,
83
+ argenté: SILVER,
84
+ turquoise: TURQUOISE,
85
+ magenta: MAGENTA,
86
+ navy: NAVY,
87
+ marine: NAVY,
88
+ blurple: exports.DISCORD_BLURPLE,
89
+ };
90
+ /**
91
+ * Accents must not be a trap: `dore` and `doré` are the same request, and an
92
+ * administrator has no way of knowing which one a table happened to spell.
93
+ * Case and surrounding whitespace are folded for the same reason.
94
+ */
95
+ function normalizeColorName(raw) {
96
+ return raw
97
+ .trim()
98
+ .toLowerCase()
99
+ .normalize("NFD")
100
+ .replace(/\p{Diacritic}/gu, "");
101
+ }
102
+ /** Index a name → `#rrggbb` table by {@link normalizeColorName}, so lookups fold case and accents. */
103
+ function indexColorNames(names) {
104
+ return new Map(Object.entries(names).map(([name, hex]) => [normalizeColorName(name), hex]));
105
+ }
106
+ const BASE_COLORS_BY_NORMALIZED_NAME = indexColorNames(exports.BASE_COLOR_NAMES);
107
+ /** `#RGB` and `#RRGGBB`, with or without the leading hash. */
108
+ const HEX_COLOR_PATTERN = /^#?(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
109
+ /**
110
+ * Normalize a hexadecimal colour code to `#rrggbb`, `null` when the input is
111
+ * not one. Surrounding whitespace is ignored.
112
+ */
113
+ function parseHexColor(raw) {
114
+ const value = raw.trim();
115
+ if (!HEX_COLOR_PATTERN.test(value)) {
116
+ return null;
117
+ }
118
+ const digits = value.replace("#", "").toLowerCase();
119
+ const expanded = digits.length === 3 ? [...digits].map((digit) => `${digit}${digit}`).join("") : digits;
120
+ return `#${expanded}`;
121
+ }
122
+ /**
123
+ * Normalize a colour to `#rrggbb`, from a hexadecimal code or from one of the
124
+ * {@link BASE_COLOR_NAMES}. `null` for anything else: the refusal belongs to
125
+ * whichever caller asked, so this only reports that it could not read the value.
126
+ */
127
+ function parseColor(raw) {
128
+ return BASE_COLORS_BY_NORMALIZED_NAME.get(normalizeColorName(raw)) ?? parseHexColor(raw);
129
+ }
130
+ //# sourceMappingURL=color.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.js","sourceRoot":"","sources":["../src/color.ts"],"names":[],"mappings":";;;AA4FA,gDAMC;AAGD,0CAEC;AAYD,sCASC;AAOD,gCAEC;AArID;;;;GAIG;AACH,MAAM,GAAG,GAAG,SAAS,CAAC;AACtB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,KAAK,GAAG,SAAS,CAAC;AACxB,MAAM,MAAM,GAAG,SAAS,CAAC;AACzB,MAAM,MAAM,GAAG,SAAS,CAAC;AACzB,MAAM,MAAM,GAAG,SAAS,CAAC;AACzB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB;;;;GAIG;AACU,QAAA,eAAe,GAAG,SAAS,CAAC;AAEzC;;;;GAIG;AACH,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,KAAK,GAAG,SAAS,CAAC;AACxB,MAAM,MAAM,GAAG,SAAS,CAAC;AACzB,MAAM,SAAS,GAAG,SAAS,CAAC;AAC5B,MAAM,OAAO,GAAG,SAAS,CAAC;AAC1B,MAAM,IAAI,GAAG,SAAS,CAAC;AAEvB;;;;;;;;;;;;;;GAcG;AACU,QAAA,gBAAgB,GAAqC;IACjE,GAAG,EAAE,GAAG;IACR,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,KAAK;IACX,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;IACd,4EAA4E;IAC5E,sEAAsE;IACtE,MAAM,EAAE,MAAM;IACd,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,KAAK,EAAE,KAAK;IACZ,IAAI,EAAE,KAAK;IACX,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,KAAK;IACZ,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,MAAM;IACd,MAAM,EAAE,MAAM;IACd,OAAO,EAAE,MAAM;IACf,SAAS,EAAE,SAAS;IACpB,OAAO,EAAE,OAAO;IAChB,IAAI,EAAE,IAAI;IACV,MAAM,EAAE,IAAI;IACZ,OAAO,EAAE,uBAAe;CACxB,CAAC;AAEF;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,GAAW;IAC7C,OAAO,GAAG;SACR,IAAI,EAAE;SACN,WAAW,EAAE;SACb,SAAS,CAAC,KAAK,CAAC;SAChB,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,sGAAsG;AACtG,SAAgB,eAAe,CAAC,KAAuC;IACtE,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,8BAA8B,GACnC,eAAe,CAAC,wBAAgB,CAAC,CAAC;AAEnC,8DAA8D;AAC9D,MAAM,iBAAiB,GAAG,kCAAkC,CAAC;AAE7D;;;GAGG;AACH,SAAgB,aAAa,CAAC,GAAW;IACxC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACzB,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACpD,MAAM,QAAQ,GACb,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACxF,OAAO,IAAI,QAAQ,EAAE,CAAC;AACvB,CAAC;AAED;;;;GAIG;AACH,SAAgB,UAAU,CAAC,GAAW;IACrC,OAAO,8BAA8B,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;AAC1F,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Option, Options } from "../../discord/command/options";
2
+ type AsRequired<O> = O extends Option<infer V, boolean> ? Option<V, true> : never;
3
+ /** Turn every option in a record into its required variant. */
4
+ export declare function allRequired<O extends Options>(fields: O): {
5
+ [K in keyof O]: AsRequired<O[K]>;
6
+ };
7
+ export {};
8
+ //# sourceMappingURL=all-required.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"all-required.d.ts","sourceRoot":"","sources":["../../../src/discord/command/all-required.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAEjE,KAAK,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;AAElF,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,CAAC,SAAS,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAAE,CAM9F"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.allRequired = allRequired;
4
+ /** Turn every option in a record into its required variant. */
5
+ function allRequired(fields) {
6
+ const out = {};
7
+ for (const [key, option] of Object.entries(fields)) {
8
+ out[key] = option.required();
9
+ }
10
+ return out;
11
+ }
12
+ //# sourceMappingURL=all-required.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"all-required.js","sourceRoot":"","sources":["../../../src/discord/command/all-required.ts"],"names":[],"mappings":";;AAKA,kCAMC;AAPD,+DAA+D;AAC/D,SAAgB,WAAW,CAAoB,MAAS;IACvD,MAAM,GAAG,GAAG,EAA0C,CAAC;IACvD,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACpD,GAAG,CAAC,GAAc,CAAC,GAAG,MAAM,CAAC,QAAQ,EAA4B,CAAC;IACnE,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"autocomplete-dispatcher.d.ts","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC7B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;CAC5C;AAED;;;;GAIG;AACH,qBAAa,sBAAuB,YAAW,qBAAqB;IAElE,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,MAAM;IAGhC,+DAA+D;IACzD,MAAM,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;CA0BxD"}
1
+ {"version":3,"file":"autocomplete-dispatcher.d.ts","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-dispatcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,0CAA0C,CAAC;AAEtF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC7B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;CAC5C;AAED;;;;GAIG;AACH,qBAAa,sBAAuB,YAAW,qBAAqB;IAElE,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,QAAQ,EAAE,aAAa,EACvB,MAAM,EAAE,MAAM;IAGhC,+DAA+D;IACzD,MAAM,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;CA0BxD"}
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AutocompleteDispatcher = void 0;
4
+ const error_message_1 = require("../../errors/error-message");
4
5
  /**
5
6
  * Answers option autocomplete requests. It is an {@link InteractionDispatcher}
6
7
  * aggregated by the shared {@link InteractionRouter}, never a second
@@ -31,7 +32,7 @@ class AutocompleteDispatcher {
31
32
  catch (error) {
32
33
  this.logger.error({
33
34
  command: interaction.commandName,
34
- err: error instanceof Error ? error.message : String(error),
35
+ err: (0, error_message_1.errorMessage)(error),
35
36
  }, "Autocomplete handler failed");
36
37
  }
37
38
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"autocomplete-dispatcher.js","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-dispatcher.ts"],"names":[],"mappings":";;;AAeA;;;;GAIG;AACH,MAAa,sBAAsB;IAEhB;IACA;IAFlB,YACkB,QAAuB,EACvB,MAAc;QADd,aAAQ,GAAR,QAAQ,CAAe;QACvB,WAAM,GAAN,MAAM,CAAQ;IAC7B,CAAC;IAEJ,+DAA+D;IAC/D,KAAK,CAAC,MAAM,CAAC,WAAwB;QACpC,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAC3D,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC;YAC5B,OAAO,KAAK,CAAC;QACd,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,mEAAmE;QACnE,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAChB;gBACC,OAAO,EAAE,WAAW,CAAC,WAAW;gBAChC,GAAG,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC3D,EACD,6BAA6B,CAC7B,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAjCD,wDAiCC"}
1
+ {"version":3,"file":"autocomplete-dispatcher.js","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-dispatcher.ts"],"names":[],"mappings":";;;AAGA,0DAAsD;AAatD;;;;GAIG;AACH,MAAa,sBAAsB;IAEhB;IACA;IAFlB,YACkB,QAAuB,EACvB,MAAc;QADd,aAAQ,GAAR,QAAQ,CAAe;QACvB,WAAM,GAAN,MAAM,CAAQ;IAC7B,CAAC;IAEJ,+DAA+D;IAC/D,KAAK,CAAC,MAAM,CAAC,WAAwB;QACpC,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC;QACd,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAC3D,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC;YAC5B,OAAO,KAAK,CAAC;QACd,CAAC;QAED,wEAAwE;QACxE,yEAAyE;QACzE,mEAAmE;QACnE,IAAI,CAAC;YACJ,MAAM,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAChB;gBACC,OAAO,EAAE,WAAW,CAAC,WAAW;gBAChC,GAAG,EAAE,IAAA,4BAAY,EAAC,KAAK,CAAC;aACxB,EACD,6BAA6B,CAC7B,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAjCD,wDAiCC"}
@@ -0,0 +1,3 @@
1
+ /** Discord refuses an autocomplete response carrying more than this many choices. */
2
+ export declare const MAX_AUTOCOMPLETE_CHOICES = 25;
3
+ //# sourceMappingURL=autocomplete-limits.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autocomplete-limits.d.ts","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-limits.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,KAAK,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_AUTOCOMPLETE_CHOICES = void 0;
4
+ /** Discord refuses an autocomplete response carrying more than this many choices. */
5
+ exports.MAX_AUTOCOMPLETE_CHOICES = 25;
6
+ //# sourceMappingURL=autocomplete-limits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autocomplete-limits.js","sourceRoot":"","sources":["../../../src/discord/command/autocomplete-limits.ts"],"names":[],"mappings":";;;AAAA,qFAAqF;AACxE,QAAA,wBAAwB,GAAG,EAAE,CAAC"}
@@ -1,6 +1,11 @@
1
1
  import type { AutocompleteInteraction } from "discord.js";
2
- import { type CompiledSubcommand } from "../../discord/command/create-command";
2
+ import type { CompiledSubcommand } from "../../discord/command/create-command";
3
3
  import type { Options } from "../../discord/command/options";
4
+ /**
5
+ * Serving option autocomplete. Kept beside the DSL because resolving *which*
6
+ * option is focused needs the same route table `createCommand` builds — the
7
+ * dispatcher only decides that an interaction is an autocomplete request.
8
+ */
4
9
  /**
5
10
  * Answer a focused option's autocomplete request.
6
11
  *
@@ -1 +1 @@
1
- {"version":3,"file":"autocomplete.d.ts","sourceRoot":"","sources":["../../../src/discord/command/autocomplete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,KAAK,kBAAkB,EAAY,MAAM,kCAAkC,CAAC;AACrF,OAAO,KAAK,EAAU,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAWjE;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC3C,WAAW,EAAE,uBAAuB,EACpC,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC,CAsBf;AAWD;;;GAGG;AACH,wBAAgB,mBAAmB,CAClC,WAAW,EAAE,uBAAuB,EACpC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACvC,WAAW,EAAE,OAAO,GAAG,IAAI,GACzB,OAAO,CAUT"}
1
+ {"version":3,"file":"autocomplete.d.ts","sourceRoot":"","sources":["../../../src/discord/command/autocomplete.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAE1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;AAIzD;;;;GAIG;AAEH;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC3C,WAAW,EAAE,uBAAuB,EACpC,OAAO,EAAE,OAAO,GACd,OAAO,CAAC,IAAI,CAAC,CAsBf;AAYD;;;GAGG;AACH,wBAAgB,mBAAmB,CAClC,WAAW,EAAE,uBAAuB,EACpC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACvC,WAAW,EAAE,OAAO,GAAG,IAAI,GACzB,OAAO,CAUT"}