@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
@@ -0,0 +1,161 @@
1
+ import type { KeyedCatalog, MessageKey } from "@/i18n/catalog";
2
+ import type { SettingsIssueCode } from "@/settings/settings-validation-error";
3
+
4
+ /**
5
+ * Catalog key of each validation issue. Typed over every {@link SettingsIssueCode}
6
+ * so adding a code without its wording fails to compile.
7
+ *
8
+ * Placeholders: `min` / `minLength` / `minItems` take `{min}`, `max` /
9
+ * `maxLength` / `maxItems` take `{max}`; the others take none.
10
+ */
11
+ export const SETTINGS_ISSUE_MESSAGES = {
12
+ required: "core.settings.issue.required",
13
+ type: "core.settings.issue.type",
14
+ min: "core.settings.issue.min",
15
+ max: "core.settings.issue.max",
16
+ minLength: "core.settings.issue.min-length",
17
+ maxLength: "core.settings.issue.max-length",
18
+ minItems: "core.settings.issue.min-items",
19
+ maxItems: "core.settings.issue.max-items",
20
+ duplicate: "core.settings.issue.duplicate",
21
+ channelType: "core.settings.issue.channel-type",
22
+ notFound: "core.settings.issue.not-found",
23
+ unknownChoice: "core.settings.issue.unknown-choice",
24
+ unknownField: "core.settings.issue.unknown-field",
25
+ } as const satisfies Readonly<Record<SettingsIssueCode, string>>;
26
+
27
+ /** Catalog keys for the settings feature's own wording outside validation. */
28
+ export const SETTINGS_MESSAGES = {
29
+ /** Shown instead of a secret's value, which no surface ever reads back. */
30
+ secretSet: "core.settings.secret.set",
31
+ secretNotSet: "core.settings.secret.not-set",
32
+ /** Shown for a stored channel, role or member the guild no longer has. */
33
+ valueUnavailable: "core.settings.value.unavailable",
34
+ /** Shown for a setting that holds no value. */
35
+ valueNotSet: "core.settings.value.not-set",
36
+ /** Shown for a toggles setting with none of its toggles on. */
37
+ valueNone: "core.settings.value.none",
38
+ /** The two options a yes/no setting is picked from. */
39
+ booleanTrue: "core.settings.boolean.true",
40
+ booleanFalse: "core.settings.boolean.false",
41
+ /** Reply when a module disabled on the guild is used there. */
42
+ moduleDisabled: "core.settings.module.disabled",
43
+ /** Reply when a module still lacks a required setting. */
44
+ moduleNotConfigured: "core.settings.module.not-configured",
45
+ /** The missing settings, listed only to members who can fix them. */
46
+ moduleNotConfiguredMissing: "core.settings.module.not-configured-missing",
47
+ } as const;
48
+
49
+ /** Catalog keys of the kernel's own settings declaration (`kernelSettings`). */
50
+ export const KERNEL_SETTINGS_MESSAGES = {
51
+ title: "core.settings.kernel.title",
52
+ description: "core.settings.kernel.description",
53
+ modules: "core.settings.kernel.modules",
54
+ modulesDescription: "core.settings.kernel.modules-description",
55
+ locale: "core.settings.kernel.locale",
56
+ localeDescription: "core.settings.kernel.locale-description",
57
+ localeEn: "core.settings.kernel.locale-en",
58
+ localeFr: "core.settings.kernel.locale-fr",
59
+ } as const;
60
+
61
+ /**
62
+ * The settings feature's strings, registered by the composition root alongside
63
+ * the core catalog.
64
+ */
65
+ export const SETTINGS_CATALOG: KeyedCatalog<
66
+ | MessageKey<typeof SETTINGS_ISSUE_MESSAGES>
67
+ | MessageKey<typeof SETTINGS_MESSAGES>
68
+ | MessageKey<typeof KERNEL_SETTINGS_MESSAGES>
69
+ > = {
70
+ [SETTINGS_ISSUE_MESSAGES.required]: {
71
+ en: "This setting is required.",
72
+ fr: "Ce paramètre est obligatoire.",
73
+ },
74
+ [SETTINGS_ISSUE_MESSAGES.type]: {
75
+ en: "This value is not of the expected kind.",
76
+ fr: "Cette valeur n'est pas du type attendu.",
77
+ },
78
+ [SETTINGS_ISSUE_MESSAGES.min]: {
79
+ en: "Must be at least {min}.",
80
+ fr: "Doit être au moins {min}.",
81
+ },
82
+ [SETTINGS_ISSUE_MESSAGES.max]: {
83
+ en: "Must be at most {max}.",
84
+ fr: "Doit être au plus {max}.",
85
+ },
86
+ [SETTINGS_ISSUE_MESSAGES.minLength]: {
87
+ en: "Must be at least {min} characters long.",
88
+ fr: "Doit contenir au moins {min} caractères.",
89
+ },
90
+ [SETTINGS_ISSUE_MESSAGES.maxLength]: {
91
+ en: "Must be at most {max} characters long.",
92
+ fr: "Doit contenir au plus {max} caractères.",
93
+ },
94
+ [SETTINGS_ISSUE_MESSAGES.minItems]: {
95
+ en: "Pick at least {min} items.",
96
+ fr: "Choisissez au moins {min} éléments.",
97
+ },
98
+ [SETTINGS_ISSUE_MESSAGES.maxItems]: {
99
+ en: "Pick at most {max} items.",
100
+ fr: "Choisissez au plus {max} éléments.",
101
+ },
102
+ [SETTINGS_ISSUE_MESSAGES.duplicate]: {
103
+ en: "The same value is listed more than once.",
104
+ fr: "La même valeur apparaît plusieurs fois.",
105
+ },
106
+ [SETTINGS_ISSUE_MESSAGES.channelType]: {
107
+ en: "This type of channel is not allowed here.",
108
+ fr: "Ce type de salon n'est pas autorisé ici.",
109
+ },
110
+ [SETTINGS_ISSUE_MESSAGES.notFound]: {
111
+ en: "This no longer exists on this server.",
112
+ fr: "Cet élément n'existe plus sur ce serveur.",
113
+ },
114
+ [SETTINGS_ISSUE_MESSAGES.unknownChoice]: {
115
+ en: "This value is not one of the allowed choices.",
116
+ fr: "Cette valeur ne fait pas partie des choix autorisés.",
117
+ },
118
+ [SETTINGS_ISSUE_MESSAGES.unknownField]: {
119
+ en: "This setting does not exist.",
120
+ fr: "Ce paramètre n'existe pas.",
121
+ },
122
+ [SETTINGS_MESSAGES.secretSet]: { en: "Set", fr: "Défini" },
123
+ [SETTINGS_MESSAGES.secretNotSet]: { en: "Not set", fr: "Non défini" },
124
+ [SETTINGS_MESSAGES.valueUnavailable]: {
125
+ en: "A saved value is unavailable: it no longer exists on this server.",
126
+ fr: "Une valeur enregistrée est indisponible : elle n'existe plus sur ce serveur.",
127
+ },
128
+ [SETTINGS_MESSAGES.valueNotSet]: { en: "Not set", fr: "Non défini" },
129
+ [SETTINGS_MESSAGES.valueNone]: { en: "None", fr: "Aucun" },
130
+ [SETTINGS_MESSAGES.booleanTrue]: { en: "Yes", fr: "Oui" },
131
+ [SETTINGS_MESSAGES.booleanFalse]: { en: "No", fr: "Non" },
132
+ [SETTINGS_MESSAGES.moduleDisabled]: {
133
+ en: "This feature is disabled on this server.",
134
+ fr: "Cette fonctionnalité est désactivée sur ce serveur.",
135
+ },
136
+ [SETTINGS_MESSAGES.moduleNotConfigured]: {
137
+ en: "This feature is not configured on this server yet: an administrator must set it up first.",
138
+ fr: "Cette fonctionnalité n'est pas encore configurée sur ce serveur : un administrateur doit d'abord la configurer.",
139
+ },
140
+ [SETTINGS_MESSAGES.moduleNotConfiguredMissing]: {
141
+ en: "Missing settings: {fields}.",
142
+ fr: "Paramètres manquants : {fields}.",
143
+ },
144
+ [KERNEL_SETTINGS_MESSAGES.title]: { en: "Server", fr: "Serveur" },
145
+ [KERNEL_SETTINGS_MESSAGES.description]: {
146
+ en: "Features enabled on this server and the bot's language.",
147
+ fr: "Fonctionnalités activées sur ce serveur et langue du bot.",
148
+ },
149
+ [KERNEL_SETTINGS_MESSAGES.modules]: { en: "Features", fr: "Fonctionnalités" },
150
+ [KERNEL_SETTINGS_MESSAGES.modulesDescription]: {
151
+ en: "Turn a feature off to stop its commands, buttons and events on this server.",
152
+ fr: "Désactivez une fonctionnalité pour arrêter ses commandes, boutons et événements sur ce serveur.",
153
+ },
154
+ [KERNEL_SETTINGS_MESSAGES.locale]: { en: "Language", fr: "Langue" },
155
+ [KERNEL_SETTINGS_MESSAGES.localeDescription]: {
156
+ en: "The bot's language on this server, when a member's own language is not supported.",
157
+ fr: "La langue du bot sur ce serveur, lorsque la langue d'un membre n'est pas prise en charge.",
158
+ },
159
+ [KERNEL_SETTINGS_MESSAGES.localeEn]: { en: "English", fr: "Anglais" },
160
+ [KERNEL_SETTINGS_MESSAGES.localeFr]: { en: "French", fr: "Français" },
161
+ };
@@ -0,0 +1,58 @@
1
+ import { decodeStored } from "@/settings/decode-stored";
2
+ import type { SettingsDeclaration } from "@/settings/define-settings";
3
+ import { isPlainObject } from "@/settings/is-plain-object";
4
+ import type { StoredSettings } from "@/settings/ports/settings-store";
5
+
6
+ /**
7
+ * Outcome of {@link migrateStored}. Either way, `values` are the valid declared
8
+ * fields a guild reads; only an `ok` outcome may be written back (FR-018).
9
+ */
10
+ export type MigrationOutcome =
11
+ | { readonly ok: true; readonly values: Readonly<Record<string, unknown>> }
12
+ | {
13
+ readonly ok: false;
14
+ readonly values: Readonly<Record<string, unknown>>;
15
+ /** The declared fields whose migrated value fails validation. */
16
+ readonly invalidKeys: readonly string[];
17
+ /** What the migration threw, or why its result was refused. */
18
+ readonly error?: unknown;
19
+ };
20
+
21
+ /**
22
+ * Reshape values stored under an older declaration version with the
23
+ * declaration's `migrate`, then validate the result through the same checks
24
+ * as any stored value. Pure: it reads and writes nothing, and hands `migrate` a
25
+ * copy, so the stored record is never touched.
26
+ *
27
+ * - `migrate` throws, is missing, or returns anything but a plain object: not
28
+ * `ok`, and `values` are the stored values that still validate as they are.
29
+ * - Some migrated field fails validation: not `ok`, and `values` are the
30
+ * migrated fields that validate.
31
+ * - Otherwise `ok`, with every migrated declared field; undeclared keys the
32
+ * migration returns are dropped.
33
+ *
34
+ * @param declaration - the module's current declaration.
35
+ * @param stored - a record whose `version` is below `declaration.version`.
36
+ */
37
+ export function migrateStored(
38
+ declaration: SettingsDeclaration,
39
+ stored: Pick<StoredSettings, "version" | "values">,
40
+ ): MigrationOutcome {
41
+ let migrated: unknown;
42
+ try {
43
+ if (declaration.migrate === undefined) {
44
+ throw new Error(`module "${declaration.id}" declares no migration`);
45
+ }
46
+ migrated = declaration.migrate(stored.version, structuredClone(stored.values));
47
+ } catch (error) {
48
+ return { ok: false, error, ...decodeStored(declaration, stored.values) };
49
+ }
50
+ if (!isPlainObject(migrated)) {
51
+ const error = new Error(`the migration of module "${declaration.id}" returned no plain object`);
52
+ return { ok: false, error, ...decodeStored(declaration, stored.values) };
53
+ }
54
+ const decoded = decodeStored(declaration, migrated);
55
+ return decoded.invalidKeys.length === 0
56
+ ? { ok: true, values: decoded.values }
57
+ : { ok: false, ...decoded };
58
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Vendor-free channel category a channel field can be restricted to. Each
3
+ * member maps one to one to a guild channel type of Discord's `ChannelType`.
4
+ */
5
+ export type ChannelKind =
6
+ /** `ChannelType.GuildText` */
7
+ | "text"
8
+ /** `ChannelType.GuildVoice` */
9
+ | "voice"
10
+ /** `ChannelType.GuildCategory` */
11
+ | "category"
12
+ /** `ChannelType.GuildAnnouncement` */
13
+ | "announcement"
14
+ /** `ChannelType.AnnouncementThread` */
15
+ | "announcementThread"
16
+ /** `ChannelType.PublicThread` */
17
+ | "publicThread"
18
+ /** `ChannelType.PrivateThread` */
19
+ | "privateThread"
20
+ /** `ChannelType.GuildStageVoice` */
21
+ | "stage"
22
+ /** `ChannelType.GuildDirectory` */
23
+ | "directory"
24
+ /** `ChannelType.GuildForum` */
25
+ | "forum"
26
+ /** `ChannelType.GuildMedia` */
27
+ | "media";
28
+
29
+ /**
30
+ * Read-only view of a guild's channels, roles and members. Settings logic uses
31
+ * it to check that a referenced entity exists and to suggest candidates,
32
+ * without depending on discord.js.
33
+ */
34
+ export interface GuildDirectory {
35
+ channel(
36
+ guildId: string,
37
+ id: string,
38
+ ): Promise<{ id: string; name: string; kind: ChannelKind } | null>;
39
+ role(guildId: string, id: string): Promise<{ id: string; name: string } | null>;
40
+ member(guildId: string, id: string): Promise<{ id: string; name: string } | null>;
41
+ searchChannels(
42
+ guildId: string,
43
+ query: string,
44
+ kinds?: readonly ChannelKind[],
45
+ ): Promise<readonly { id: string; name: string; kind: ChannelKind }[]>;
46
+ searchRoles(guildId: string, query: string): Promise<readonly { id: string; name: string }[]>;
47
+ searchMembers(guildId: string, query: string): Promise<readonly { id: string; name: string }[]>;
48
+ }
@@ -0,0 +1,20 @@
1
+ /** Emitted after a module's settings changed for a guild. */
2
+ export interface SettingsChangedEvent {
3
+ readonly guildId: string;
4
+ readonly moduleId: string;
5
+ readonly changedKeys: readonly string[];
6
+ /** Revision of the record after the change. */
7
+ readonly revision: number;
8
+ /** Snowflake of the user who made the change. */
9
+ readonly changedBy?: string;
10
+ }
11
+
12
+ /**
13
+ * Broadcasts settings changes, e.g. so read caches can invalidate. The default
14
+ * implementation is in-process; distributed delivery is a separate adapter.
15
+ */
16
+ export interface SettingsChangedNotifier {
17
+ notify(event: SettingsChangedEvent): void;
18
+ /** Register `listener`; the returned function unsubscribes it. */
19
+ subscribe(listener: (event: SettingsChangedEvent) => void): () => void;
20
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The record a {@link SettingsStore} persists, one per `(guildId, moduleId)`.
3
+ * Every field is JSON-serialisable, so an adapter may store the record as one
4
+ * document, one row with a JSON column, or one hash; it must give back an equal
5
+ * record (`updatedBy` absent stays absent).
6
+ */
7
+ export interface StoredSettings {
8
+ readonly guildId: string;
9
+ /** Equals the declaration id of the module that owns these values. */
10
+ readonly moduleId: string;
11
+ /** Declaration version the values were written under. */
12
+ readonly version: number;
13
+ /**
14
+ * Starts at 1 on first write; +1 on each write. Used for optimistic
15
+ * concurrency. The caller computes it; the store persists it as given.
16
+ */
17
+ readonly revision: number;
18
+ /**
19
+ * Only declared, valid fields; unset fields are absent. Every value is plain
20
+ * JSON (string, finite number, boolean, `null`, arrays and objects of those),
21
+ * so `JSON.stringify` then `JSON.parse` gives back an equal object.
22
+ */
23
+ readonly values: Readonly<Record<string, unknown>>;
24
+ /** ISO-8601 timestamp from the `Clock` port. */
25
+ readonly updatedAt: string;
26
+ /** Snowflake of the user who made the change. */
27
+ readonly updatedBy?: string;
28
+ }
29
+
30
+ /**
31
+ * Persistence port for module settings: the kernel's only view of a database.
32
+ * An adapter over any engine (a JSON file, SQLite, Postgres, MongoDB, Redis)
33
+ * implements it in the bot or in an opt-in package, never in the kernel, and
34
+ * proves it with `runSettingsStoreContract` from
35
+ * `@azurioh/discord-kernel/settings/testing`.
36
+ *
37
+ * Guarantees every implementation must honour:
38
+ *
39
+ * - **Isolation.** A record is keyed by `(guildId, moduleId)`; reading, writing
40
+ * or deleting one key never touches another.
41
+ * - **Atomic compare-and-set.** `write` checks the stored revision and replaces
42
+ * the record in one atomic step of the engine, so that of several writers
43
+ * holding the same `expectedRevision` (Discord shards, an HTTP API) exactly
44
+ * one wins and the others get `ConflictError`.
45
+ * - **Independent copies.** The store never keeps a reference to the record it
46
+ * was given nor hands out one it keeps: callers may mutate what they pass in
47
+ * or get back without changing what is stored.
48
+ * - **Errors are real.** Only a revision mismatch is a `ConflictError`; any
49
+ * other failure (connection lost, corrupt data) is thrown as it is.
50
+ */
51
+ export interface SettingsStore {
52
+ /**
53
+ * The record of one module in one guild.
54
+ *
55
+ * @returns a copy of the stored record, or `null` when none was written yet
56
+ * (or it was deleted).
57
+ */
58
+ read(guildId: string, moduleId: string): Promise<StoredSettings | null>;
59
+ /**
60
+ * Persist `record` as a whole, replacing any stored one, if and only if the
61
+ * stored revision is `expectedRevision`.
62
+ *
63
+ * @param opts.expectedRevision - the revision the caller read; `null` means
64
+ * no record may exist yet (a create).
65
+ * @throws ConflictError when the stored revision (or `null` for no record)
66
+ * differs from `expectedRevision`. The stored record is then left unchanged.
67
+ */
68
+ write(record: StoredSettings, opts: { expectedRevision: number | null }): Promise<void>;
69
+ /**
70
+ * Remove the record of one module in one guild, whatever its revision.
71
+ * Idempotent: deleting a missing record succeeds and does nothing.
72
+ */
73
+ delete(guildId: string, moduleId: string): Promise<void>;
74
+ }
@@ -0,0 +1,137 @@
1
+ import type { TranslationRegistry } from "@/i18n/catalog";
2
+ import type { SettingsDeclaration } from "@/settings/define-settings";
3
+ import {
4
+ type AnyField,
5
+ type FieldChoice,
6
+ type FieldSpec,
7
+ type Suggestions,
8
+ unhandledFieldKind,
9
+ } from "@/settings/fields/field";
10
+ import { SettingsDeclarationError } from "@/settings/settings-declaration-error";
11
+ import {
12
+ type KernelSettings,
13
+ kernelSettings,
14
+ type ModuleEnablement,
15
+ } from "@/settings/system/kernel-settings";
16
+
17
+ /** Every settings declaration of the bot, checked at boot. */
18
+ export interface SettingsRegistry {
19
+ /** The kernel's own declaration first, then the modules' in registration order. */
20
+ readonly declarations: readonly SettingsDeclaration[];
21
+ /** The kernel's own declaration (id `kernel`), built from the registered modules. */
22
+ readonly kernel: KernelSettings;
23
+ get(id: string): SettingsDeclaration | undefined;
24
+ }
25
+
26
+ /**
27
+ * Collect the modules' settings declarations at boot, after the kernel's own
28
+ * declaration ({@link kernelSettings}), which is always included.
29
+ *
30
+ * @param input.declarations - every module's declaration.
31
+ * @param input.translations - must already contain the modules' catalogs and
32
+ * `SETTINGS_CATALOG`, which holds the kernel declaration's texts.
33
+ * @param input.modules - the registered modules (a `BotModule` fits), whose
34
+ * names and `defaultEnabled` build the kernel's module toggles. None by default.
35
+ * @returns the registry of declarations, by id.
36
+ * @throws SettingsDeclarationError when two declarations share an id (FR-005)
37
+ * or a declaration references a catalog key without an English source (FR-028),
38
+ * or two modules share a name.
39
+ */
40
+ export function createSettingsRegistry(input: {
41
+ declarations: readonly SettingsDeclaration[];
42
+ translations: TranslationRegistry;
43
+ modules?: readonly ModuleEnablement[];
44
+ }): SettingsRegistry {
45
+ const kernel = kernelSettings(input.modules ?? []);
46
+ const byId = new Map<string, SettingsDeclaration>();
47
+ for (const declaration of [kernel, ...input.declarations]) {
48
+ if (byId.has(declaration.id)) {
49
+ throw new SettingsDeclarationError(declaration.id, "is declared more than once");
50
+ }
51
+ checkKeys({ declaration, translations: input.translations });
52
+ byId.set(declaration.id, declaration);
53
+ }
54
+ return {
55
+ declarations: [...byId.values()],
56
+ kernel,
57
+ get: (id) => byId.get(id),
58
+ };
59
+ }
60
+
61
+ function checkKeys(params: {
62
+ declaration: SettingsDeclaration;
63
+ translations: TranslationRegistry;
64
+ }): void {
65
+ const { declaration, translations } = params;
66
+ for (const key of catalogKeys(declaration)) {
67
+ if (!translations.has(key)) {
68
+ throw new SettingsDeclarationError(
69
+ declaration.id,
70
+ `catalog key "${key}" has no English source`,
71
+ );
72
+ }
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Every catalog key a declaration references: labels, groups, fields, choices
78
+ * and toggle key labels.
79
+ */
80
+ function* catalogKeys(declaration: SettingsDeclaration): Generator<string> {
81
+ yield* defined([declaration.labels.title, declaration.labels.description]);
82
+ for (const group of Object.values(declaration.groups ?? {})) {
83
+ yield* defined([group.label, group.description]);
84
+ }
85
+ for (const declared of Object.values(declaration.fields)) {
86
+ yield* fieldKeys(declared);
87
+ }
88
+ }
89
+
90
+ function* fieldKeys(declared: AnyField): Generator<string> {
91
+ yield* defined([declared.label, declared.description, declared.placeholder, declared.unit]);
92
+ yield* specKeys(declared.spec);
93
+ }
94
+
95
+ function* specKeys(spec: FieldSpec): Generator<string> {
96
+ switch (spec.kind) {
97
+ case "enum":
98
+ yield* spec.choices.map(choiceLabel);
99
+ return;
100
+ case "integer":
101
+ case "text":
102
+ yield* suggestionKeys(spec.suggest);
103
+ return;
104
+ case "list":
105
+ yield* fieldKeys(spec.item);
106
+ return;
107
+ case "toggles":
108
+ yield* defined(Object.values(spec.keyLabels ?? {}));
109
+ return;
110
+ case "channel":
111
+ case "role":
112
+ case "user":
113
+ case "color":
114
+ case "duration":
115
+ case "number":
116
+ case "boolean":
117
+ case "secret":
118
+ return;
119
+ default:
120
+ unhandledFieldKind(spec);
121
+ }
122
+ }
123
+
124
+ function suggestionKeys(suggest: Suggestions<unknown> | undefined): string[] {
125
+ if (suggest === undefined || !("choices" in suggest)) {
126
+ return [];
127
+ }
128
+ return suggest.choices.map(choiceLabel);
129
+ }
130
+
131
+ function choiceLabel(choice: FieldChoice<unknown>): string {
132
+ return choice.label;
133
+ }
134
+
135
+ function defined(keys: readonly (string | undefined)[]): string[] {
136
+ return keys.filter((key) => key !== undefined);
137
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * A module's settings declaration breaks a rule that can be checked without a
3
+ * guild: a default failing its own field, a secret with a default, too many
4
+ * choices, a duplicate id, a catalog key with no English source… Raised by
5
+ * `defineSettings` and `createSettingsRegistry` at boot, so a broken
6
+ * declaration never reaches a server.
7
+ */
8
+ export class SettingsDeclarationError extends Error {
9
+ constructor(
10
+ readonly declarationId: string,
11
+ readonly reason: string,
12
+ ) {
13
+ super(`Settings declaration "${declarationId}": ${reason}`);
14
+ this.name = "SettingsDeclarationError";
15
+ }
16
+ }