meocord 4.2.0 → 4.2.2

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 (103) hide show
  1. package/CHANGELOG.md +322 -0
  2. package/THIRD_PARTY_NOTICES.md +14 -13
  3. package/dist/cjs/_shared/{controller.decorator-CRn9kWob.cjs → controller.decorator-U2NBWcoU.cjs} +416 -108
  4. package/dist/cjs/_shared/{providers-ChvMqnLd.cjs → providers-B4MOFBrW.cjs} +202 -50
  5. package/dist/cjs/_shared/{sharded-cooldown-store-BdAUTdYs.cjs → sharded-cooldown-store-HTUb3Ii_.cjs} +10 -7
  6. package/dist/cjs/_shared/{startup-roots-CQo8mSP8.cjs → startup-roots-lA5xkBFq.cjs} +228 -71
  7. package/dist/cjs/_shared/{translate-error-DhDVbT5M.cjs → translate-error-CbBHUu5P.cjs} +10 -5
  8. package/dist/cjs/common/index.cjs +3 -3
  9. package/dist/cjs/core/index.cjs +188 -169
  10. package/dist/cjs/decorator/index.cjs +52 -7
  11. package/dist/cjs/testing/index.cjs +1854 -311
  12. package/dist/cli.json +1 -1
  13. package/dist/esm/bin/generator.js +4 -5
  14. package/dist/esm/bin/helper/filter-generator.helper.js +4 -5
  15. package/dist/esm/bin/helper/guard-generator.helper.js +4 -5
  16. package/dist/esm/bin/helper/interceptor-generator.helper.js +4 -5
  17. package/dist/esm/bin/helper/observer-generator.helper.js +4 -5
  18. package/dist/esm/bin/helper/pipe-generator.helper.js +4 -5
  19. package/dist/esm/bin/helper/service-generator.helper.js +4 -5
  20. package/dist/esm/bin/meocord.js +84 -25
  21. package/dist/esm/build/load-config.pre-entry.js +13 -3
  22. package/dist/esm/build/rsbuild-config.js +16 -12
  23. package/dist/esm/build/typed-externals.js +36 -0
  24. package/dist/esm/common/cooldown-store.js +10 -2
  25. package/dist/esm/common/errors.js +25 -0
  26. package/dist/esm/common/meocord-text.js +11 -8
  27. package/dist/esm/common/response/call-order.js +9 -4
  28. package/dist/esm/common/response/presenter.js +33 -6
  29. package/dist/esm/common/response/response-state.js +89 -15
  30. package/dist/esm/common/route.js +11 -4
  31. package/dist/esm/common/sharded-cooldown-store.js +1 -1
  32. package/dist/esm/common/translator.js +52 -11
  33. package/dist/esm/core/command-registration.js +93 -24
  34. package/dist/esm/core/command-routes.js +2 -2
  35. package/dist/esm/core/cooldown-runner.js +29 -8
  36. package/dist/esm/core/dispatcher.js +9 -8
  37. package/dist/esm/core/fallback.js +20 -11
  38. package/dist/esm/core/filter-runner.js +2 -2
  39. package/dist/esm/core/guard-runner.js +16 -3
  40. package/dist/esm/core/handler-input.js +4 -3
  41. package/dist/esm/core/handler-pipeline.js +10 -4
  42. package/dist/esm/core/lifecycle-hooks.js +134 -47
  43. package/dist/esm/core/meocord-factory.js +59 -34
  44. package/dist/esm/core/meocord.app.js +116 -75
  45. package/dist/esm/core/message-help.js +32 -6
  46. package/dist/esm/core/observer-runner.js +2 -1
  47. package/dist/esm/core/providers.js +19 -4
  48. package/dist/esm/core/running-calls.js +43 -0
  49. package/dist/esm/core/shard-context.js +5 -6
  50. package/dist/esm/core/shard-manager.js +16 -10
  51. package/dist/esm/core/stage-scope.js +2 -1
  52. package/dist/esm/core/startup-roots.js +21 -1
  53. package/dist/esm/core/theme-resolvers.js +4 -1
  54. package/dist/esm/core/theme-scope.js +7 -2
  55. package/dist/esm/core/theme-validation.js +17 -10
  56. package/dist/esm/decorator/app.decorator.js +31 -0
  57. package/dist/esm/decorator/controller.decorator.js +56 -20
  58. package/dist/esm/decorator/cooldown.decorator.js +17 -0
  59. package/dist/esm/decorator/filter.decorator.js +2 -2
  60. package/dist/esm/decorator/guard.decorator.js +3 -2
  61. package/dist/esm/package.json.js +1 -1
  62. package/dist/esm/testing/catalog.js +20 -13
  63. package/dist/esm/testing/cooldown-store-suite.js +67 -5
  64. package/dist/esm/testing/discord-defaults.js +225 -30
  65. package/dist/esm/testing/meocord-testing-module.js +158 -44
  66. package/dist/esm/testing/mock-fn.js +107 -26
  67. package/dist/esm/testing/mock-interaction.js +1250 -182
  68. package/dist/esm/testing/snowflake.js +9 -2
  69. package/dist/esm/testing/strict-mocks.js +40 -17
  70. package/dist/esm/util/common.util.js +47 -19
  71. package/dist/esm/util/dev-runner.util.js +8 -8
  72. package/dist/esm/util/generator-cli.util.js +4 -5
  73. package/dist/esm/util/interaction.util.js +2 -2
  74. package/dist/esm/util/meocord-config-loader.util.js +10 -2
  75. package/dist/esm/util/meocord-config-validation.util.js +3 -5
  76. package/dist/esm/util/meocord-source-config.util.js +65 -20
  77. package/dist/esm/util/method-wrapper.util.js +16 -0
  78. package/dist/esm/util/platform.util.js +10 -10
  79. package/dist/esm/util/shard-process.util.js +4 -1
  80. package/dist/esm/util/sharding-mode.util.js +5 -7
  81. package/dist/esm/util/shared-state.util.js +21 -0
  82. package/dist/esm/util/tsconfig-paths.util.js +29 -0
  83. package/dist/esm/util/tsconfig.util.js +10 -10
  84. package/dist/esm/util/value.util.js +30 -2
  85. package/dist/types/common/index.d.cts +10 -7
  86. package/dist/types/common/index.d.ts +10 -7
  87. package/dist/types/core/index.d.cts +3 -2
  88. package/dist/types/core/index.d.ts +3 -2
  89. package/dist/types/decorator/index.d.cts +1 -0
  90. package/dist/types/decorator/index.d.ts +1 -0
  91. package/dist/types/{index-CdXsFgjE.d.ts → index-DKJclIi-.d.ts} +45 -21
  92. package/dist/types/{index-nn5p7OoX.d.cts → index-Dlf0ZZtS.d.cts} +45 -21
  93. package/dist/types/interface/index.d.cts +1 -1
  94. package/dist/types/interface/index.d.ts +1 -1
  95. package/dist/types/{route-BZgFoNeB.d.cts → route-Bh1U13yy.d.cts} +3 -2
  96. package/dist/types/{route-BZgFoNeB.d.ts → route-Bh1U13yy.d.ts} +3 -2
  97. package/dist/types/testing/index.d.cts +198 -62
  98. package/dist/types/testing/index.d.ts +198 -62
  99. package/dist/types/{theme-resolvers-UKr3-6Ys.d.cts → theme-resolvers-CyEz9pnv.d.cts} +1 -1
  100. package/dist/types/{theme-resolvers-BcOJVzR9.d.ts → theme-resolvers-DA204O-q.d.ts} +1 -1
  101. package/dist/types/{translator-DHMkkCpg.d.cts → translator-Bg7hwxDF.d.cts} +21 -8
  102. package/dist/types/{translator-BViWKtLJ.d.ts → translator-CeP4bCzp.d.ts} +21 -8
  103. package/package.json +2 -2
@@ -3,6 +3,7 @@ import { existsSync, readFileSync, writeFileSync, mkdtempSync, rmSync, readlinkS
3
3
  import { tmpdir, hostname } from 'os';
4
4
  import { createRequire } from 'module';
5
5
  import { parseJsonc } from './json.util.js';
6
+ import { projectPaths } from './tsconfig-paths.util.js';
6
7
 
7
8
  /**
8
9
  * An `extends` made to work from another directory: a relative path made absolute, and a package
@@ -89,10 +90,11 @@ function isRunning(pid) {
89
90
  }
90
91
  /**
91
92
  * Writes a copy of the project's tsconfig.json for the bundler and returns its path: comments and trailing commas
92
- * removed, paths made absolute (a `paths` target from `baseUrl` when set), `noEmit` dropped. One file per call in this
93
+ * removed, paths made absolute (`paths` as {@link projectPaths} reads them), `noEmit` dropped. One file per call in this
93
94
  * process's directory, removed at exit; the project's file is never written.
94
95
  * @throws When `tsconfig.json` is missing or cannot be parsed.
95
96
  */ function prepareModifiedTsConfig() {
97
+ var _parsedConfig;
96
98
  const tsConfigPath = path.resolve(process.cwd(), 'tsconfig.json');
97
99
  // Ensure tsconfig.json exists
98
100
  if (!existsSync(tsConfigPath)) {
@@ -109,12 +111,15 @@ function isRunning(pid) {
109
111
  // The copy lives in the temp directory, so every path in it is made absolute from the project
110
112
  const cwd = process.cwd();
111
113
  if (parsedConfig?.extends) parsedConfig.extends = resolveExtends(parsedConfig.extends, cwd);
114
+ // `${configDir}` is the project, which the copy's own directory would otherwise stand for
112
115
  for (const key of [
113
116
  'include',
114
117
  'exclude',
115
118
  'files'
116
119
  ]){
117
- if (Array.isArray(parsedConfig?.[key])) parsedConfig[key] = parsedConfig[key].map((p)=>path.resolve(cwd, p));
120
+ if (Array.isArray(parsedConfig?.[key])) {
121
+ parsedConfig[key] = parsedConfig[key].map((p)=>path.resolve(cwd, p.replaceAll('${configDir}', cwd)));
122
+ }
118
123
  }
119
124
  // Process compilerOptions
120
125
  if (parsedConfig?.compilerOptions) {
@@ -133,19 +138,14 @@ function isRunning(pid) {
133
138
  if (Array.isArray(parsedConfig.compilerOptions.typeRoots)) {
134
139
  parsedConfig.compilerOptions.typeRoots = parsedConfig.compilerOptions.typeRoots.map((p)=>path.resolve(cwd, p));
135
140
  }
136
- // A `paths` target is relative to baseUrl when there is one, made absolute above, and else to the project. Only
137
- // this file's own baseUrl counts: one inherited through `extends` isn't applied, so paths are the project's own.
138
- if (parsedConfig.compilerOptions.paths) {
139
- const base = parsedConfig.compilerOptions.baseUrl ?? cwd;
140
- Object.keys(parsedConfig.compilerOptions.paths).forEach((alias)=>{
141
- parsedConfig.compilerOptions.paths[alias] = parsedConfig.compilerOptions.paths[alias].map((p)=>path.resolve(base, p));
142
- });
143
- }
144
141
  // Remove `noEmit` option if it exists
145
142
  if ('noEmit' in parsedConfig.compilerOptions) {
146
143
  delete parsedConfig.compilerOptions.noEmit;
147
144
  }
148
145
  }
146
+ // The paths as tsc reads them, inherited ones included, written absolute so the copy in the temp directory keeps them
147
+ const paths = projectPaths(cwd);
148
+ if (paths) ((_parsedConfig = parsedConfig).compilerOptions ?? (_parsedConfig.compilerOptions = {})).paths = paths;
149
149
  const tempTsConfigPath = path.join(copiesDirectory(), `modified-tsconfig-${++copies}.json`);
150
150
  writeFileSync(tempTsConfigPath, JSON.stringify(parsedConfig, null, 2));
151
151
  return tempTsConfigPath;
@@ -1,6 +1,23 @@
1
1
  import { quoteForLog } from './user-text.util.js';
2
2
 
3
- /** Whether a value is a class, which a stage entry or a `@Catch` type must be: what `new` and `instanceof` take. */ const isConstructor = (value)=>typeof value === 'function';
3
+ /** Whether `new` takes a value, as `instanceof` needs of its right side, such as a `@Catch` type. */ function isConstructible(value) {
4
+ if (typeof value !== 'function') return false;
5
+ try {
6
+ // Fails unless value can be new.target, which only a constructor can; none of value's constructor code runs
7
+ Reflect.construct(String, [], value);
8
+ return true;
9
+ } catch {
10
+ return false;
11
+ }
12
+ }
13
+ /**
14
+ * Whether a value is a class, which a stage entry or an app option must be: constructible, with an object prototype for
15
+ * the metadata MeoCord reads. An arrow function, a method, an async or a generator function is none.
16
+ */ function isConstructor(value) {
17
+ if (!isConstructible(value)) return false;
18
+ const prototype = value.prototype;
19
+ return typeof prototype === 'object' && prototype !== null;
20
+ }
4
21
  /** A value as a refusal or a warning names it: a string quoted, `null` and `undefined` as written, else its kind. */ function describeValue(value) {
5
22
  if (value === null || value === undefined) return String(value);
6
23
  if (typeof value === 'string') return quoteForLog(value);
@@ -8,5 +25,16 @@ import { quoteForLog } from './user-text.util.js';
8
25
  return typeof value === 'object' ? 'an object' : `a ${typeof value}`;
9
26
  }
10
27
  /** A class's name after its article, such as `an AutocompleteInteraction`; a `U` name reads as "you", so takes `a`. */ const withArticle = (name)=>`${/^[AEIO]/i.test(name) ? 'an' : 'a'} ${name}`;
28
+ /**
29
+ * Sets `key` on `target` as an own, enumerable data property: unlike `target[key] = value`, a key named `__proto__`
30
+ * is a key like any other rather than the object's prototype.
31
+ */ function setOwn(target, key, value) {
32
+ Object.defineProperty(target, key, {
33
+ value,
34
+ enumerable: true,
35
+ writable: true,
36
+ configurable: true
37
+ });
38
+ }
11
39
 
12
- export { describeValue, isConstructor, withArticle };
40
+ export { describeValue, isConstructible, isConstructor, setOwn, withArticle };
@@ -1,11 +1,11 @@
1
1
  import { ColorResolvable, Interaction, Message, Locale } from 'discord.js';
2
- import { C as CooldownStore, a as CooldownLimit, b as CooldownVerdict, c as CooldownEntry, d as CooldownBatchVerdict } from '../index-nn5p7OoX.cjs';
2
+ import { C as CooldownStore, a as CooldownLimit, b as CooldownVerdict, c as CooldownEntry, d as CooldownBatchVerdict } from '../index-Dlf0ZZtS.cjs';
3
3
  import { Token, ProviderToken, FactoryProvider, DeepReadonly, MeoCordTheme } from '../interface/index.cjs';
4
- export { e as CommandNotFoundError, f as CooldownError, g as CooldownScope, h as CooldownStoreError, E as ExecutionContext, i as ExecutionContextType, G as GuardDeniedError, I as InstallContext, j as MemoryCooldownStore, k as MessageUsageError, l as MessageUsageIssue, m as MetadataDecorator, R as ResponseCall, n as ResponseEditFlags, o as ResponseEditPayload, p as ResponseErrorOptions, q as ResponseFlags, r as ResponseLockOptions, s as ResponsePayload, t as ResponsePhase, u as ResponseSendOptions, v as ResponseState, U as UserError, w as UserErrorOptions, V as ValidationError, x as ValidationIssue, y as cooldownMessage, z as cooldownStoreMessage, A as createMetadata, B as getInstallContext, H as respond } from '../index-nn5p7OoX.cjs';
5
- export { R as Route, a as RouteParams, b as RouteValue, c as RouteValues, r as route } from '../route-BZgFoNeB.cjs';
6
- import { T as Translator } from '../translator-DHMkkCpg.cjs';
7
- export { C as CatalogDefinition, a as CatalogShape, L as LocaleCatalog, b as LocalizationKey, M as MessageKey, c as MessageParams, P as PluralCategory, d as PluralMessage, S as StringMessageKey, e as Translate, f as TranslatorOptions, g as createTranslator, h as defineCatalog } from '../translator-DHMkkCpg.cjs';
8
- export { T as ThemeCache } from '../theme-resolvers-UKr3-6Ys.cjs';
4
+ export { e as CommandNotFoundError, f as CooldownError, g as CooldownScope, h as CooldownStoreError, E as ExecutionContext, i as ExecutionContextType, G as GuardDeniedError, I as InstallContext, j as MemoryCooldownStore, k as MessageUsageError, l as MessageUsageIssue, m as MetadataDecorator, R as ResponseCall, n as ResponseEditFlags, o as ResponseEditPayload, p as ResponseErrorOptions, q as ResponseFlags, r as ResponseLockOptions, s as ResponsePayload, t as ResponsePhase, u as ResponseSendOptions, v as ResponseState, U as UserError, w as UserErrorOptions, V as ValidationError, x as ValidationIssue, y as cooldownMessage, z as cooldownStoreMessage, A as createMetadata, B as getInstallContext, H as respond } from '../index-Dlf0ZZtS.cjs';
5
+ export { R as Route, a as RouteParams, b as RouteValue, c as RouteValues, r as route } from '../route-Bh1U13yy.cjs';
6
+ import { T as Translator } from '../translator-Bg7hwxDF.cjs';
7
+ export { C as CatalogDefinition, a as CatalogShape, L as LocaleCatalog, b as LocalizationKey, M as MessageKey, c as MessageParams, P as PluralCategory, d as PluralMessage, S as StringMessageKey, e as Translate, f as TranslatorOptions, g as createTranslator, h as defineCatalog } from '../translator-Bg7hwxDF.cjs';
8
+ export { T as ThemeCache } from '../theme-resolvers-CyEz9pnv.cjs';
9
9
  import '@rsbuild/core';
10
10
  import '../controller.enum-DTDn69N9.cjs';
11
11
 
@@ -596,6 +596,9 @@ declare function useTheme(): ResolvedTheme;
596
596
  * Such a listener runs in its emitter's context, so without it a `useTheme()` inside reads the theme outside any call.
597
597
  * Timers and promises the handler starts keep its theme without it.
598
598
  *
599
+ * The theme is the binding call's whole theme, its server's and user's themes included, so every later call, whoever
600
+ * it is for, is answered in the starting member's theme.
601
+ *
599
602
  * @param fn - The function to run in the call's theme; `this` and its arguments are passed through.
600
603
  * @returns A function that runs `fn` in the theme `useTheme()` returns where `bindTheme` is called.
601
604
  *
@@ -605,7 +608,7 @@ declare function useTheme(): ResolvedTheme;
605
608
  * async poll(message: Message) {
606
609
  * const collector = message.createMessageComponentCollector({ componentType: ComponentType.Button, time: 60_000 })
607
610
  * collector.on('collect', bindTheme(async (click: ButtonInteraction) => {
608
- * const { emojis } = useTheme() // the handler's theme, @UseTheme included
611
+ * const { emojis } = useTheme() // the starting member's theme, @UseTheme included
609
612
  * await click.reply(`${emojis.success} Picked`)
610
613
  * }))
611
614
  * }
@@ -1,11 +1,11 @@
1
1
  import { ColorResolvable, Interaction, Message, Locale } from 'discord.js';
2
- import { C as CooldownStore, a as CooldownLimit, b as CooldownVerdict, c as CooldownEntry, d as CooldownBatchVerdict } from '../index-CdXsFgjE.js';
2
+ import { C as CooldownStore, a as CooldownLimit, b as CooldownVerdict, c as CooldownEntry, d as CooldownBatchVerdict } from '../index-DKJclIi-.js';
3
3
  import { Token, ProviderToken, FactoryProvider, DeepReadonly, MeoCordTheme } from '../interface/index.js';
4
- export { e as CommandNotFoundError, f as CooldownError, g as CooldownScope, h as CooldownStoreError, E as ExecutionContext, i as ExecutionContextType, G as GuardDeniedError, I as InstallContext, j as MemoryCooldownStore, k as MessageUsageError, l as MessageUsageIssue, m as MetadataDecorator, R as ResponseCall, n as ResponseEditFlags, o as ResponseEditPayload, p as ResponseErrorOptions, q as ResponseFlags, r as ResponseLockOptions, s as ResponsePayload, t as ResponsePhase, u as ResponseSendOptions, v as ResponseState, U as UserError, w as UserErrorOptions, V as ValidationError, x as ValidationIssue, y as cooldownMessage, z as cooldownStoreMessage, A as createMetadata, B as getInstallContext, H as respond } from '../index-CdXsFgjE.js';
5
- export { R as Route, a as RouteParams, b as RouteValue, c as RouteValues, r as route } from '../route-BZgFoNeB.js';
6
- import { T as Translator } from '../translator-BViWKtLJ.js';
7
- export { C as CatalogDefinition, a as CatalogShape, L as LocaleCatalog, b as LocalizationKey, M as MessageKey, c as MessageParams, P as PluralCategory, d as PluralMessage, S as StringMessageKey, e as Translate, f as TranslatorOptions, g as createTranslator, h as defineCatalog } from '../translator-BViWKtLJ.js';
8
- export { T as ThemeCache } from '../theme-resolvers-BcOJVzR9.js';
4
+ export { e as CommandNotFoundError, f as CooldownError, g as CooldownScope, h as CooldownStoreError, E as ExecutionContext, i as ExecutionContextType, G as GuardDeniedError, I as InstallContext, j as MemoryCooldownStore, k as MessageUsageError, l as MessageUsageIssue, m as MetadataDecorator, R as ResponseCall, n as ResponseEditFlags, o as ResponseEditPayload, p as ResponseErrorOptions, q as ResponseFlags, r as ResponseLockOptions, s as ResponsePayload, t as ResponsePhase, u as ResponseSendOptions, v as ResponseState, U as UserError, w as UserErrorOptions, V as ValidationError, x as ValidationIssue, y as cooldownMessage, z as cooldownStoreMessage, A as createMetadata, B as getInstallContext, H as respond } from '../index-DKJclIi-.js';
5
+ export { R as Route, a as RouteParams, b as RouteValue, c as RouteValues, r as route } from '../route-Bh1U13yy.js';
6
+ import { T as Translator } from '../translator-CeP4bCzp.js';
7
+ export { C as CatalogDefinition, a as CatalogShape, L as LocaleCatalog, b as LocalizationKey, M as MessageKey, c as MessageParams, P as PluralCategory, d as PluralMessage, S as StringMessageKey, e as Translate, f as TranslatorOptions, g as createTranslator, h as defineCatalog } from '../translator-CeP4bCzp.js';
8
+ export { T as ThemeCache } from '../theme-resolvers-DA204O-q.js';
9
9
  import '@rsbuild/core';
10
10
  import '../controller.enum-DTDn69N9.js';
11
11
 
@@ -596,6 +596,9 @@ declare function useTheme(): ResolvedTheme;
596
596
  * Such a listener runs in its emitter's context, so without it a `useTheme()` inside reads the theme outside any call.
597
597
  * Timers and promises the handler starts keep its theme without it.
598
598
  *
599
+ * The theme is the binding call's whole theme, its server's and user's themes included, so every later call, whoever
600
+ * it is for, is answered in the starting member's theme.
601
+ *
599
602
  * @param fn - The function to run in the call's theme; `this` and its arguments are passed through.
600
603
  * @returns A function that runs `fn` in the theme `useTheme()` returns where `bindTheme` is called.
601
604
  *
@@ -605,7 +608,7 @@ declare function useTheme(): ResolvedTheme;
605
608
  * async poll(message: Message) {
606
609
  * const collector = message.createMessageComponentCollector({ componentType: ComponentType.Button, time: 60_000 })
607
610
  * collector.on('collect', bindTheme(async (click: ButtonInteraction) => {
608
- * const { emojis } = useTheme() // the handler's theme, @UseTheme included
611
+ * const { emojis } = useTheme() // the starting member's theme, @UseTheme included
609
612
  * await click.reply(`${emojis.success} Picked`)
610
613
  * }))
611
614
  * }
@@ -1,5 +1,5 @@
1
1
  import { ServiceIdentifier } from 'inversify';
2
- import { J as MeoCordApplication } from '../index-nn5p7OoX.cjs';
2
+ import { J as MeoCordApplication } from '../index-Dlf0ZZtS.cjs';
3
3
  import { MetadataDecorator } from '../common/index.cjs';
4
4
  import { MessageScope, MessageCommandOptions, MessageHelp } from '../interface/index.cjs';
5
5
  import { RESTPostAPIApplicationCommandsJSONBody, ClientEvents, Message, Client } from 'discord.js';
@@ -44,7 +44,8 @@ declare class MeoCordFactory {
44
44
  * @returns The application, which `start()` logs in.
45
45
  * @throws Error when the class has no `@MeoCord`, when the compiled config is missing beside the bundle or fails to
46
46
  * load, naming the file and the reason, with what to do about it, when a provider cannot
47
- * be bound, such as one for a token MeoCord binds itself, when two handlers take one command, or two builder
47
+ * be bound, such as one for a token MeoCord binds itself (a provider for `ThemeCache` or `ExecutionContext` is warned
48
+ * about instead, and refused from the next major version, 5.0), when two handlers take one command, or two builder
48
49
  * classes build one, naming both, and for any other mistake it refuses as the app loads, such as two component
49
50
  * patterns that match the same customIds. Each check reports every error it finds, and the first is thrown,
50
51
  * unchanged. When there are several, each is logged first, with where in the source it comes from; a lone one is
@@ -1,5 +1,5 @@
1
1
  import { ServiceIdentifier } from 'inversify';
2
- import { J as MeoCordApplication } from '../index-CdXsFgjE.js';
2
+ import { J as MeoCordApplication } from '../index-DKJclIi-.js';
3
3
  import { MetadataDecorator } from '../common/index.js';
4
4
  import { MessageScope, MessageCommandOptions, MessageHelp } from '../interface/index.js';
5
5
  import { RESTPostAPIApplicationCommandsJSONBody, ClientEvents, Message, Client } from 'discord.js';
@@ -44,7 +44,8 @@ declare class MeoCordFactory {
44
44
  * @returns The application, which `start()` logs in.
45
45
  * @throws Error when the class has no `@MeoCord`, when the compiled config is missing beside the bundle or fails to
46
46
  * load, naming the file and the reason, with what to do about it, when a provider cannot
47
- * be bound, such as one for a token MeoCord binds itself, when two handlers take one command, or two builder
47
+ * be bound, such as one for a token MeoCord binds itself (a provider for `ThemeCache` or `ExecutionContext` is warned
48
+ * about instead, and refused from the next major version, 5.0), when two handlers take one command, or two builder
48
49
  * classes build one, naming both, and for any other mistake it refuses as the app loads, such as two component
49
50
  * patterns that match the same customIds. Each check reports every error it finds, and the first is thrown,
50
51
  * unchanged. When there are several, each is logged first, with where in the source it comes from; a lone one is
@@ -1045,6 +1045,7 @@ interface CooldownByDecorator<P> {
1045
1045
  * @param options - The limit, whose calls count together, and how to exempt or tell calls apart.
1046
1046
  * @throws Error when `seconds` is not from `0.001` to `4320000000000`, `uses` is not a whole number of at least 1,
1047
1047
  * `per` is not a scope or `by` is not a function, as the decorator applies; `CooldownError` to a call over the limit.
1048
+ * A `bypass` given but not a function, and a `seconds` that is not a number, are warned about as the decorator applies.
1048
1049
  *
1049
1050
  * @example
1050
1051
  * ```ts
@@ -1045,6 +1045,7 @@ interface CooldownByDecorator<P> {
1045
1045
  * @param options - The limit, whose calls count together, and how to exempt or tell calls apart.
1046
1046
  * @throws Error when `seconds` is not from `0.001` to `4320000000000`, `uses` is not a whole number of at least 1,
1047
1047
  * `per` is not a scope or `by` is not a function, as the decorator applies; `CooldownError` to a call over the limit.
1048
+ * A `bypass` given but not a function, and a `seconds` that is not a number, are warned about as the decorator applies.
1048
1049
  *
1049
1050
  * @example
1050
1051
  * ```ts
@@ -1,4 +1,4 @@
1
- import { BaseInteraction, Message, APIEmbed, InteractionReplyOptions, BitFieldResolvable, MessageFlags, InteractionEditReplyOptions, JSONEncodable, APIModalInteractionResponseCallbackData, ModalComponentData, Interaction, ColorResolvable, ButtonStyle, MessageReaction, PartialMessageReaction, ContextMenuCommandType, UserContextMenuCommandInteraction, MessageContextMenuCommandInteraction, ApplicationCommandType, SlashCommandBuilder, SlashCommandOptionsOnlyBuilder, SlashCommandSubcommandsOnlyBuilder, ContextMenuCommandBuilder, RESTPostAPIPrimaryEntryPointApplicationCommandJSONBody, ChatInputCommandInteraction, PrimaryEntryPointCommandInteraction, ButtonInteraction, StringSelectMenuInteraction, UserSelectMenuInteraction, RoleSelectMenuInteraction, MentionableSelectMenuInteraction, ChannelSelectMenuInteraction, ModalSubmitInteraction, APIComponentInContainer, AttachmentBuilder, MessageReplyOptions, GuildMember, User, Role, GuildBasedChannel, PartialUser, Client } from 'discord.js';
1
+ import { BaseInteraction, Message, APIMessageTopLevelComponent, APIEmbed, InteractionReplyOptions, BitFieldResolvable, MessageFlags, InteractionEditReplyOptions, JSONEncodable, APIModalInteractionResponseCallbackData, ModalComponentData, Interaction, ColorResolvable, ButtonStyle, MessageReaction, PartialMessageReaction, ContextMenuCommandType, UserContextMenuCommandInteraction, MessageContextMenuCommandInteraction, ApplicationCommandType, SlashCommandBuilder, SlashCommandOptionsOnlyBuilder, SlashCommandSubcommandsOnlyBuilder, ContextMenuCommandBuilder, RESTPostAPIPrimaryEntryPointApplicationCommandJSONBody, ChatInputCommandInteraction, PrimaryEntryPointCommandInteraction, ButtonInteraction, StringSelectMenuInteraction, UserSelectMenuInteraction, RoleSelectMenuInteraction, MentionableSelectMenuInteraction, ChannelSelectMenuInteraction, ModalSubmitInteraction, APIComponentInContainer, AttachmentBuilder, MessageReplyOptions, GuildMember, User, Role, GuildBasedChannel, PartialUser, Client } from 'discord.js';
2
2
  import { RsbuildConfig as RsbuildConfig$1 } from '@rsbuild/core';
3
3
  import { C as CommandType, R as ReactionHandlerAction } from './controller.enum-DTDn69N9.js';
4
4
 
@@ -329,13 +329,14 @@ interface ResponseState {
329
329
  /** Where the answer stands, re-read from the interaction so answers made around this state count. */
330
330
  readonly state: ResponsePhase;
331
331
  /**
332
- * The message this state last replied with, updated or edited, never a follow-up, or the message a component is on.
333
- * Read-only: edit through the state.
332
+ * The answer's message: the one this state last replied with, updated or edited, or the message a component is on. A
333
+ * follow-up is it only once it is the answer, after replacing a public deferral or after `delete()`; after `delete()`
334
+ * it is `undefined` until something is sent. Read-only: edit through the state.
334
335
  */
335
336
  readonly message: Message | undefined;
336
337
  /** The components and embeds of the message before `@Defer` locked it; `undefined` until then. */
337
338
  readonly original: {
338
- readonly components: readonly unknown[];
339
+ readonly components: readonly APIMessageTopLevelComponent[];
339
340
  readonly embeds: readonly APIEmbed[];
340
341
  } | undefined;
341
342
  /**
@@ -366,6 +367,9 @@ interface ResponseState {
366
367
  * A reply Discord refuses as already acknowledged elsewhere still throws, and the next `send()` edits.
367
368
  * After `modal()` it throws: a modal has no message, and the modal's submit is answered instead.
368
369
  *
370
+ * After a private `followUp()` replaced a public deferral, it edits that follow-up. After `delete()` it sends a
371
+ * follow-up, private when the deleted answer was unless `flags` say otherwise, and that follow-up is the answer.
372
+ *
369
373
  * After `@Defer` locked a message, omitting `components` puts back its components as they were
370
374
  * before the lock, and omitting `embeds` drops the loading view; `components: []` clears them.
371
375
  *
@@ -375,7 +379,8 @@ interface ResponseState {
375
379
  */
376
380
  send(payload: ResponsePayload, options?: ResponseSendOptions): Promise<Message | undefined>;
377
381
  /**
378
- * Edits the answer, routed as `send()` is: an edit once the interaction is answered.
382
+ * Edits the answer, routed as `send()` is: an edit once the interaction is answered, of the follow-up that replaced
383
+ * a public deferral, or, after `delete()`, a follow-up that becomes the answer.
379
384
  *
380
385
  * @param payload - Text, or edit options.
381
386
  * @param options - `fill: false` leaves this edit's embeds and containers uncoloured.
@@ -386,8 +391,9 @@ interface ResponseState {
386
391
  * Sends another message after the answer. Before any answer it is the first reply. While a command's
387
392
  * reply is deferred and nothing is sent yet, Discord turns a follow-up into the deferred reply and
388
393
  * ignores its flags, so it is sent as that edit; a private follow-up on a public deferral deletes the
389
- * deferral first and is sent privately. After `modal()` it is sent as made, and Discord decides whether it
390
- * accepts a follow-up there; the modal's submit is the interaction to answer.
394
+ * deferral first, is sent privately, and is the answer `send()`, `edit()` and `delete()` act on. After `delete()`,
395
+ * it is the answer too. After `modal()` it is sent as made, and Discord decides whether it accepts a follow-up
396
+ * there; the modal's submit is the interaction to answer.
391
397
  *
392
398
  * @param payload - Text, or reply options; `Ephemeral` makes the follow-up private.
393
399
  * @param options - `fill: false` leaves this follow-up's embeds and containers uncoloured.
@@ -395,8 +401,9 @@ interface ResponseState {
395
401
  */
396
402
  followUp(payload: ResponsePayload, options?: ResponseSendOptions): Promise<Message | undefined>;
397
403
  /**
398
- * Deletes the answer: the reply, or for a component deferred without a reply of its own, its message.
399
- * Throws before any answer, and after `modal()`, which leaves no message.
404
+ * Deletes the answer: the reply, the follow-up that replaced a public deferral, or for a component deferred
405
+ * without a reply of its own, its message. `message` is then `undefined` until something is sent. Throws before any
406
+ * answer, after `modal()`, which leaves no message, and again with nothing sent since the last `delete()`.
400
407
  */
401
408
  delete(): Promise<void>;
402
409
  /**
@@ -1243,7 +1250,10 @@ declare class MemoryCooldownStore extends CooldownStore {
1243
1250
  peekMany(entries: readonly CooldownEntry[]): Promise<CooldownBatchVerdict>;
1244
1251
  /** Each entry's call times, trimmed to its window, and whether it allows one more call now. */
1245
1252
  private check;
1246
- /** Drops the keys whose calls have all left their window, once a minute from the store's first call. */
1253
+ /**
1254
+ * Drops the keys whose calls have all left their window, once a minute from a call, until a sweep leaves none: an
1255
+ * idle store then holds no timer, so one nothing references is collected, and its next call starts the sweep again.
1256
+ */
1247
1257
  private startSweeping;
1248
1258
  }
1249
1259
 
@@ -2105,10 +2115,14 @@ interface MeoCordApplication {
2105
2115
  */
2106
2116
  start(): Promise<void>;
2107
2117
  /**
2108
- * Stops the bot: runs the `onShutdown` hooks under the configured `shutdownTimeout` and closes the client, or with
2109
- * process sharding, asks every shard to shut down and waits for it. It ends no process of its own accord, except that
2110
- * called in a shard, it asks the manager to stop every shard, which then shuts that shard's process down too. A stop
2111
- * while the bot starts ends that start, a call after the first waits for it, and a stopped app does not start again.
2118
+ * Stops the bot: stops taking events, waits for the calls under way, runs the `onShutdown` hooks under the configured
2119
+ * `shutdownTimeout` and closes the client, or with process sharding, asks every shard to shut down and waits for it.
2120
+ * It ends no process of its own accord, except that called in a shard, it asks the manager to stop every shard, which
2121
+ * then shuts that shard's process down too. A call that awaits `stop()`, as an owner-only shutdown command does, is
2122
+ * not waited for.
2123
+ *
2124
+ * A stop while the bot starts ends that start: it waits for the providers being made, at most `shutdownTimeout`, and
2125
+ * nothing more is made after it. A call after the first waits for it, and a stopped app does not start again.
2112
2126
  *
2113
2127
  * @returns A promise that resolves once the bot is stopped. It never rejects: a failure to close is logged, and sets
2114
2128
  * `process.exitCode` to 1 unless another code is already set.
@@ -2188,9 +2202,11 @@ interface OnReady {
2188
2202
  * it injects. The whole sequence is limited by `shutdownTimeout` in `meocord.config.ts`; shutdown then goes on
2189
2203
  * whether or not it finished. A hook that throws is logged and the next one still runs.
2190
2204
  *
2191
- * It runs only for a class whose `onReady` has finished, or that has none: a signal that arrives
2192
- * while the ready hooks are running skips the class still starting and those not reached yet, and no
2193
- * further `onReady` starts. An `onReady` that threw counts as finished, so its partial setup is cleaned up.
2205
+ * It runs only for a class whose `onReady` has finished, or that has none. A stop while the ready hooks
2206
+ * are running waits for the `onReady` in progress, within `shutdownTimeout`, then shuts that class down too;
2207
+ * those not reached yet are skipped, and no further `onReady` starts. An `onReady` still running once only the
2208
+ * hooks' share of the timeout is left is named in a warning and skipped. An `onReady` that threw counts as
2209
+ * finished, so its partial setup is cleaned up.
2194
2210
  *
2195
2211
  * @example
2196
2212
  * ```ts
@@ -2355,7 +2371,11 @@ interface MessageResponseContext {
2355
2371
  * @category Presenters
2356
2372
  */
2357
2373
  interface PresentedError {
2358
- /** What the user is told. */
2374
+ /**
2375
+ * What the user is told, fitted to Discord's limit for the answer's `mode`: at most 4096 characters for an embed and
2376
+ * 4000 for a Components V2 Text Display, cut to end in `…`. An empty or whitespace-only message comes as MeoCord's generic error text.
2377
+ * So a presenter that writes it as its view's text renders, whatever the error's message.
2378
+ */
2359
2379
  message: string;
2360
2380
  /** The error being answered, so a presenter can style it by kind. */
2361
2381
  error: unknown;
@@ -3186,9 +3206,13 @@ interface MeoCordConfig {
3186
3206
  */
3187
3207
  startupErrors?: 'first' | 'all';
3188
3208
  /**
3189
- * How long, in milliseconds, shutdown waits for the `onShutdown` hooks before destroying the client
3190
- * anyway: from 0 to 2147478647, the longest a timer keeps less the margin the shard manager waits on top. The limit covers the whole sequence, not each hook,
3191
- * including the calls under way that the cooldown store's shutdown waits for.
3209
+ * How long, in milliseconds, shutdown waits for the calls under way and the `onShutdown` hooks before destroying the
3210
+ * client anyway: from 0 to 2147478647, the longest a timer keeps less the margin the shard manager waits on top. The
3211
+ * limit covers the whole sequence, not each hook.
3212
+ *
3213
+ * The calls are waited for first, but no longer than the timeout less a reserve kept for the hooks: a quarter of it,
3214
+ * at least 1 second and never more than half. A call still running then is named in a warning, and the hooks run in
3215
+ * the time left.
3192
3216
  *
3193
3217
  * @defaultValue `10_000`
3194
3218
  */
@@ -1,4 +1,4 @@
1
- import { BaseInteraction, Message, APIEmbed, InteractionReplyOptions, BitFieldResolvable, MessageFlags, InteractionEditReplyOptions, JSONEncodable, APIModalInteractionResponseCallbackData, ModalComponentData, Interaction, ColorResolvable, ButtonStyle, MessageReaction, PartialMessageReaction, ContextMenuCommandType, UserContextMenuCommandInteraction, MessageContextMenuCommandInteraction, ApplicationCommandType, SlashCommandBuilder, SlashCommandOptionsOnlyBuilder, SlashCommandSubcommandsOnlyBuilder, ContextMenuCommandBuilder, RESTPostAPIPrimaryEntryPointApplicationCommandJSONBody, ChatInputCommandInteraction, PrimaryEntryPointCommandInteraction, ButtonInteraction, StringSelectMenuInteraction, UserSelectMenuInteraction, RoleSelectMenuInteraction, MentionableSelectMenuInteraction, ChannelSelectMenuInteraction, ModalSubmitInteraction, APIComponentInContainer, AttachmentBuilder, MessageReplyOptions, GuildMember, User, Role, GuildBasedChannel, PartialUser, Client } from 'discord.js';
1
+ import { BaseInteraction, Message, APIMessageTopLevelComponent, APIEmbed, InteractionReplyOptions, BitFieldResolvable, MessageFlags, InteractionEditReplyOptions, JSONEncodable, APIModalInteractionResponseCallbackData, ModalComponentData, Interaction, ColorResolvable, ButtonStyle, MessageReaction, PartialMessageReaction, ContextMenuCommandType, UserContextMenuCommandInteraction, MessageContextMenuCommandInteraction, ApplicationCommandType, SlashCommandBuilder, SlashCommandOptionsOnlyBuilder, SlashCommandSubcommandsOnlyBuilder, ContextMenuCommandBuilder, RESTPostAPIPrimaryEntryPointApplicationCommandJSONBody, ChatInputCommandInteraction, PrimaryEntryPointCommandInteraction, ButtonInteraction, StringSelectMenuInteraction, UserSelectMenuInteraction, RoleSelectMenuInteraction, MentionableSelectMenuInteraction, ChannelSelectMenuInteraction, ModalSubmitInteraction, APIComponentInContainer, AttachmentBuilder, MessageReplyOptions, GuildMember, User, Role, GuildBasedChannel, PartialUser, Client } from 'discord.js';
2
2
  import { RsbuildConfig as RsbuildConfig$1 } from '@rsbuild/core';
3
3
  import { C as CommandType, R as ReactionHandlerAction } from './controller.enum-DTDn69N9.cjs';
4
4
 
@@ -329,13 +329,14 @@ interface ResponseState {
329
329
  /** Where the answer stands, re-read from the interaction so answers made around this state count. */
330
330
  readonly state: ResponsePhase;
331
331
  /**
332
- * The message this state last replied with, updated or edited, never a follow-up, or the message a component is on.
333
- * Read-only: edit through the state.
332
+ * The answer's message: the one this state last replied with, updated or edited, or the message a component is on. A
333
+ * follow-up is it only once it is the answer, after replacing a public deferral or after `delete()`; after `delete()`
334
+ * it is `undefined` until something is sent. Read-only: edit through the state.
334
335
  */
335
336
  readonly message: Message | undefined;
336
337
  /** The components and embeds of the message before `@Defer` locked it; `undefined` until then. */
337
338
  readonly original: {
338
- readonly components: readonly unknown[];
339
+ readonly components: readonly APIMessageTopLevelComponent[];
339
340
  readonly embeds: readonly APIEmbed[];
340
341
  } | undefined;
341
342
  /**
@@ -366,6 +367,9 @@ interface ResponseState {
366
367
  * A reply Discord refuses as already acknowledged elsewhere still throws, and the next `send()` edits.
367
368
  * After `modal()` it throws: a modal has no message, and the modal's submit is answered instead.
368
369
  *
370
+ * After a private `followUp()` replaced a public deferral, it edits that follow-up. After `delete()` it sends a
371
+ * follow-up, private when the deleted answer was unless `flags` say otherwise, and that follow-up is the answer.
372
+ *
369
373
  * After `@Defer` locked a message, omitting `components` puts back its components as they were
370
374
  * before the lock, and omitting `embeds` drops the loading view; `components: []` clears them.
371
375
  *
@@ -375,7 +379,8 @@ interface ResponseState {
375
379
  */
376
380
  send(payload: ResponsePayload, options?: ResponseSendOptions): Promise<Message | undefined>;
377
381
  /**
378
- * Edits the answer, routed as `send()` is: an edit once the interaction is answered.
382
+ * Edits the answer, routed as `send()` is: an edit once the interaction is answered, of the follow-up that replaced
383
+ * a public deferral, or, after `delete()`, a follow-up that becomes the answer.
379
384
  *
380
385
  * @param payload - Text, or edit options.
381
386
  * @param options - `fill: false` leaves this edit's embeds and containers uncoloured.
@@ -386,8 +391,9 @@ interface ResponseState {
386
391
  * Sends another message after the answer. Before any answer it is the first reply. While a command's
387
392
  * reply is deferred and nothing is sent yet, Discord turns a follow-up into the deferred reply and
388
393
  * ignores its flags, so it is sent as that edit; a private follow-up on a public deferral deletes the
389
- * deferral first and is sent privately. After `modal()` it is sent as made, and Discord decides whether it
390
- * accepts a follow-up there; the modal's submit is the interaction to answer.
394
+ * deferral first, is sent privately, and is the answer `send()`, `edit()` and `delete()` act on. After `delete()`,
395
+ * it is the answer too. After `modal()` it is sent as made, and Discord decides whether it accepts a follow-up
396
+ * there; the modal's submit is the interaction to answer.
391
397
  *
392
398
  * @param payload - Text, or reply options; `Ephemeral` makes the follow-up private.
393
399
  * @param options - `fill: false` leaves this follow-up's embeds and containers uncoloured.
@@ -395,8 +401,9 @@ interface ResponseState {
395
401
  */
396
402
  followUp(payload: ResponsePayload, options?: ResponseSendOptions): Promise<Message | undefined>;
397
403
  /**
398
- * Deletes the answer: the reply, or for a component deferred without a reply of its own, its message.
399
- * Throws before any answer, and after `modal()`, which leaves no message.
404
+ * Deletes the answer: the reply, the follow-up that replaced a public deferral, or for a component deferred
405
+ * without a reply of its own, its message. `message` is then `undefined` until something is sent. Throws before any
406
+ * answer, after `modal()`, which leaves no message, and again with nothing sent since the last `delete()`.
400
407
  */
401
408
  delete(): Promise<void>;
402
409
  /**
@@ -1243,7 +1250,10 @@ declare class MemoryCooldownStore extends CooldownStore {
1243
1250
  peekMany(entries: readonly CooldownEntry[]): Promise<CooldownBatchVerdict>;
1244
1251
  /** Each entry's call times, trimmed to its window, and whether it allows one more call now. */
1245
1252
  private check;
1246
- /** Drops the keys whose calls have all left their window, once a minute from the store's first call. */
1253
+ /**
1254
+ * Drops the keys whose calls have all left their window, once a minute from a call, until a sweep leaves none: an
1255
+ * idle store then holds no timer, so one nothing references is collected, and its next call starts the sweep again.
1256
+ */
1247
1257
  private startSweeping;
1248
1258
  }
1249
1259
 
@@ -2105,10 +2115,14 @@ interface MeoCordApplication {
2105
2115
  */
2106
2116
  start(): Promise<void>;
2107
2117
  /**
2108
- * Stops the bot: runs the `onShutdown` hooks under the configured `shutdownTimeout` and closes the client, or with
2109
- * process sharding, asks every shard to shut down and waits for it. It ends no process of its own accord, except that
2110
- * called in a shard, it asks the manager to stop every shard, which then shuts that shard's process down too. A stop
2111
- * while the bot starts ends that start, a call after the first waits for it, and a stopped app does not start again.
2118
+ * Stops the bot: stops taking events, waits for the calls under way, runs the `onShutdown` hooks under the configured
2119
+ * `shutdownTimeout` and closes the client, or with process sharding, asks every shard to shut down and waits for it.
2120
+ * It ends no process of its own accord, except that called in a shard, it asks the manager to stop every shard, which
2121
+ * then shuts that shard's process down too. A call that awaits `stop()`, as an owner-only shutdown command does, is
2122
+ * not waited for.
2123
+ *
2124
+ * A stop while the bot starts ends that start: it waits for the providers being made, at most `shutdownTimeout`, and
2125
+ * nothing more is made after it. A call after the first waits for it, and a stopped app does not start again.
2112
2126
  *
2113
2127
  * @returns A promise that resolves once the bot is stopped. It never rejects: a failure to close is logged, and sets
2114
2128
  * `process.exitCode` to 1 unless another code is already set.
@@ -2188,9 +2202,11 @@ interface OnReady {
2188
2202
  * it injects. The whole sequence is limited by `shutdownTimeout` in `meocord.config.ts`; shutdown then goes on
2189
2203
  * whether or not it finished. A hook that throws is logged and the next one still runs.
2190
2204
  *
2191
- * It runs only for a class whose `onReady` has finished, or that has none: a signal that arrives
2192
- * while the ready hooks are running skips the class still starting and those not reached yet, and no
2193
- * further `onReady` starts. An `onReady` that threw counts as finished, so its partial setup is cleaned up.
2205
+ * It runs only for a class whose `onReady` has finished, or that has none. A stop while the ready hooks
2206
+ * are running waits for the `onReady` in progress, within `shutdownTimeout`, then shuts that class down too;
2207
+ * those not reached yet are skipped, and no further `onReady` starts. An `onReady` still running once only the
2208
+ * hooks' share of the timeout is left is named in a warning and skipped. An `onReady` that threw counts as
2209
+ * finished, so its partial setup is cleaned up.
2194
2210
  *
2195
2211
  * @example
2196
2212
  * ```ts
@@ -2355,7 +2371,11 @@ interface MessageResponseContext {
2355
2371
  * @category Presenters
2356
2372
  */
2357
2373
  interface PresentedError {
2358
- /** What the user is told. */
2374
+ /**
2375
+ * What the user is told, fitted to Discord's limit for the answer's `mode`: at most 4096 characters for an embed and
2376
+ * 4000 for a Components V2 Text Display, cut to end in `…`. An empty or whitespace-only message comes as MeoCord's generic error text.
2377
+ * So a presenter that writes it as its view's text renders, whatever the error's message.
2378
+ */
2359
2379
  message: string;
2360
2380
  /** The error being answered, so a presenter can style it by kind. */
2361
2381
  error: unknown;
@@ -3186,9 +3206,13 @@ interface MeoCordConfig {
3186
3206
  */
3187
3207
  startupErrors?: 'first' | 'all';
3188
3208
  /**
3189
- * How long, in milliseconds, shutdown waits for the `onShutdown` hooks before destroying the client
3190
- * anyway: from 0 to 2147478647, the longest a timer keeps less the margin the shard manager waits on top. The limit covers the whole sequence, not each hook,
3191
- * including the calls under way that the cooldown store's shutdown waits for.
3209
+ * How long, in milliseconds, shutdown waits for the calls under way and the `onShutdown` hooks before destroying the
3210
+ * client anyway: from 0 to 2147478647, the longest a timer keeps less the margin the shard manager waits on top. The
3211
+ * limit covers the whole sequence, not each hook.
3212
+ *
3213
+ * The calls are waited for first, but no longer than the timeout less a reserve kept for the hooks: a quarter of it,
3214
+ * at least 1 second and never more than half. A call still running then is named in a warning, and the hooks run in
3215
+ * the time left.
3192
3216
  *
3193
3217
  * @defaultValue `10_000`
3194
3218
  */
@@ -1,4 +1,4 @@
1
1
  import 'discord.js';
2
2
  import '@rsbuild/core';
3
3
  import '../controller.enum-DTDn69N9.cjs';
4
- export { ar as AutocompleteMetadata, O as BuildableCommandType, as as CallHandler, _ as CheckedParams, ao as ClassProvider, at as CommandBuildResult, S as CommandBuilderBase, X as CommandBuilderConstructor, Q as CommandBuilderOptions, Y as CommandInteractionType, au as CommandMetadata, av as CommandRegistrationConfig, a1 as ControllerOptions, ak as CooldownOptions, a9 as CooldownStoreFailure, aw as DeepPartial, D as DeepReadonly, ab as DispatchObserver, ax as DispatchOutcome, ay as DispatchResult, az as EntityRef, a7 as ExceptionFilter, F as FactoryProvider, a4 as GuardInterface, a3 as GuardOptions, aA as GuildThemeTarget, aj as InferSchemaOutput, a6 as InterceptorInterface, a5 as InterceptorOptions, J as MeoCordApplication, aB as MeoCordConfig, aq as MeoCordMessages, M as MeoCordTheme, L as MessageCommandOptions, Z as MessageHandlerOptions, N as MessageHelp, aC as MessageHelpEntry, aD as MessageHelpOptions, aE as MessageHelpParam, aF as MessageParamType, aG as MessageParamTypes, an as MessagePrefix, aH as MessageResponseContext, K as MessageScope, al as ObserverOptions, aI as OnReady, aJ as OnShutdown, W as PIPED_BRAND, aK as ParamRefsOf, aL as ParamsOf, af as PipeInterface, aM as Piped, aN as PresentedError, aO as PrimaryEntryPointCommandData, a8 as Provider, P as ProviderToken, a0 as ReactionEvent, aP as ReactionHandlerOptions, $ as ReactionHandlerSettings, aQ as ReadyInfo, aR as ReservedThemeRole, aS as ResponseContext, aT as ResponseFile, aa as ResponsePresenter, aU as ResponseView, ac as RootTheme, aV as RsbuildConfig, aW as ShardingConfig, a2 as StageParams, ag as StandardSchemaV1, aX as StandardSchemaV1Issue, aY as StandardSchemaV1Props, aZ as StandardSchemaV1Result, a_ as ThemeButtonStyle, a$ as ThemeButtons, b0 as ThemeColors, b1 as ThemeEmojis, am as ThemeOverride, ae as ThemeResolver, ad as ThemeResolvers, T as Token, b2 as UserThemeTarget, ai as ValidateOptions, ah as ValidatePipes, ap as ValueProvider } from '../index-nn5p7OoX.cjs';
4
+ export { ar as AutocompleteMetadata, O as BuildableCommandType, as as CallHandler, _ as CheckedParams, ao as ClassProvider, at as CommandBuildResult, S as CommandBuilderBase, X as CommandBuilderConstructor, Q as CommandBuilderOptions, Y as CommandInteractionType, au as CommandMetadata, av as CommandRegistrationConfig, a1 as ControllerOptions, ak as CooldownOptions, a9 as CooldownStoreFailure, aw as DeepPartial, D as DeepReadonly, ab as DispatchObserver, ax as DispatchOutcome, ay as DispatchResult, az as EntityRef, a7 as ExceptionFilter, F as FactoryProvider, a4 as GuardInterface, a3 as GuardOptions, aA as GuildThemeTarget, aj as InferSchemaOutput, a6 as InterceptorInterface, a5 as InterceptorOptions, J as MeoCordApplication, aB as MeoCordConfig, aq as MeoCordMessages, M as MeoCordTheme, L as MessageCommandOptions, Z as MessageHandlerOptions, N as MessageHelp, aC as MessageHelpEntry, aD as MessageHelpOptions, aE as MessageHelpParam, aF as MessageParamType, aG as MessageParamTypes, an as MessagePrefix, aH as MessageResponseContext, K as MessageScope, al as ObserverOptions, aI as OnReady, aJ as OnShutdown, W as PIPED_BRAND, aK as ParamRefsOf, aL as ParamsOf, af as PipeInterface, aM as Piped, aN as PresentedError, aO as PrimaryEntryPointCommandData, a8 as Provider, P as ProviderToken, a0 as ReactionEvent, aP as ReactionHandlerOptions, $ as ReactionHandlerSettings, aQ as ReadyInfo, aR as ReservedThemeRole, aS as ResponseContext, aT as ResponseFile, aa as ResponsePresenter, aU as ResponseView, ac as RootTheme, aV as RsbuildConfig, aW as ShardingConfig, a2 as StageParams, ag as StandardSchemaV1, aX as StandardSchemaV1Issue, aY as StandardSchemaV1Props, aZ as StandardSchemaV1Result, a_ as ThemeButtonStyle, a$ as ThemeButtons, b0 as ThemeColors, b1 as ThemeEmojis, am as ThemeOverride, ae as ThemeResolver, ad as ThemeResolvers, T as Token, b2 as UserThemeTarget, ai as ValidateOptions, ah as ValidatePipes, ap as ValueProvider } from '../index-Dlf0ZZtS.cjs';
@@ -1,4 +1,4 @@
1
1
  import 'discord.js';
2
2
  import '@rsbuild/core';
3
3
  import '../controller.enum-DTDn69N9.js';
4
- export { ar as AutocompleteMetadata, O as BuildableCommandType, as as CallHandler, _ as CheckedParams, ao as ClassProvider, at as CommandBuildResult, S as CommandBuilderBase, X as CommandBuilderConstructor, Q as CommandBuilderOptions, Y as CommandInteractionType, au as CommandMetadata, av as CommandRegistrationConfig, a1 as ControllerOptions, ak as CooldownOptions, a9 as CooldownStoreFailure, aw as DeepPartial, D as DeepReadonly, ab as DispatchObserver, ax as DispatchOutcome, ay as DispatchResult, az as EntityRef, a7 as ExceptionFilter, F as FactoryProvider, a4 as GuardInterface, a3 as GuardOptions, aA as GuildThemeTarget, aj as InferSchemaOutput, a6 as InterceptorInterface, a5 as InterceptorOptions, J as MeoCordApplication, aB as MeoCordConfig, aq as MeoCordMessages, M as MeoCordTheme, L as MessageCommandOptions, Z as MessageHandlerOptions, N as MessageHelp, aC as MessageHelpEntry, aD as MessageHelpOptions, aE as MessageHelpParam, aF as MessageParamType, aG as MessageParamTypes, an as MessagePrefix, aH as MessageResponseContext, K as MessageScope, al as ObserverOptions, aI as OnReady, aJ as OnShutdown, W as PIPED_BRAND, aK as ParamRefsOf, aL as ParamsOf, af as PipeInterface, aM as Piped, aN as PresentedError, aO as PrimaryEntryPointCommandData, a8 as Provider, P as ProviderToken, a0 as ReactionEvent, aP as ReactionHandlerOptions, $ as ReactionHandlerSettings, aQ as ReadyInfo, aR as ReservedThemeRole, aS as ResponseContext, aT as ResponseFile, aa as ResponsePresenter, aU as ResponseView, ac as RootTheme, aV as RsbuildConfig, aW as ShardingConfig, a2 as StageParams, ag as StandardSchemaV1, aX as StandardSchemaV1Issue, aY as StandardSchemaV1Props, aZ as StandardSchemaV1Result, a_ as ThemeButtonStyle, a$ as ThemeButtons, b0 as ThemeColors, b1 as ThemeEmojis, am as ThemeOverride, ae as ThemeResolver, ad as ThemeResolvers, T as Token, b2 as UserThemeTarget, ai as ValidateOptions, ah as ValidatePipes, ap as ValueProvider } from '../index-CdXsFgjE.js';
4
+ export { ar as AutocompleteMetadata, O as BuildableCommandType, as as CallHandler, _ as CheckedParams, ao as ClassProvider, at as CommandBuildResult, S as CommandBuilderBase, X as CommandBuilderConstructor, Q as CommandBuilderOptions, Y as CommandInteractionType, au as CommandMetadata, av as CommandRegistrationConfig, a1 as ControllerOptions, ak as CooldownOptions, a9 as CooldownStoreFailure, aw as DeepPartial, D as DeepReadonly, ab as DispatchObserver, ax as DispatchOutcome, ay as DispatchResult, az as EntityRef, a7 as ExceptionFilter, F as FactoryProvider, a4 as GuardInterface, a3 as GuardOptions, aA as GuildThemeTarget, aj as InferSchemaOutput, a6 as InterceptorInterface, a5 as InterceptorOptions, J as MeoCordApplication, aB as MeoCordConfig, aq as MeoCordMessages, M as MeoCordTheme, L as MessageCommandOptions, Z as MessageHandlerOptions, N as MessageHelp, aC as MessageHelpEntry, aD as MessageHelpOptions, aE as MessageHelpParam, aF as MessageParamType, aG as MessageParamTypes, an as MessagePrefix, aH as MessageResponseContext, K as MessageScope, al as ObserverOptions, aI as OnReady, aJ as OnShutdown, W as PIPED_BRAND, aK as ParamRefsOf, aL as ParamsOf, af as PipeInterface, aM as Piped, aN as PresentedError, aO as PrimaryEntryPointCommandData, a8 as Provider, P as ProviderToken, a0 as ReactionEvent, aP as ReactionHandlerOptions, $ as ReactionHandlerSettings, aQ as ReadyInfo, aR as ReservedThemeRole, aS as ResponseContext, aT as ResponseFile, aa as ResponsePresenter, aU as ResponseView, ac as RootTheme, aV as RsbuildConfig, aW as ShardingConfig, a2 as StageParams, ag as StandardSchemaV1, aX as StandardSchemaV1Issue, aY as StandardSchemaV1Props, aZ as StandardSchemaV1Result, a_ as ThemeButtonStyle, a$ as ThemeButtons, b0 as ThemeColors, b1 as ThemeEmojis, am as ThemeOverride, ae as ThemeResolver, ad as ThemeResolvers, T as Token, b2 as UserThemeTarget, ai as ValidateOptions, ah as ValidatePipes, ap as ValueProvider } from '../index-DKJclIi-.js';
@@ -58,7 +58,7 @@ interface Route<T extends string = string> {
58
58
  * encoded, and the handler receives the value as it was given.
59
59
  *
60
60
  * @throws TypeError for a missing, empty or unknown value or one not of its param's type, and RangeError for an id
61
- * over 100 characters.
61
+ * that is empty or over 100 characters.
62
62
  */
63
63
  build(...values: [RouteParams<T>] extends [never] ? [] : [values: RouteValues<T>]): string;
64
64
  /** The pattern, so a route reads as its pattern in a template string. */
@@ -76,7 +76,8 @@ interface Route<T extends string = string> {
76
76
  * fails to compile, and a typed param takes a value of its type.
77
77
  *
78
78
  * @param pattern - The customId pattern, where `{name}` captures one `/`-separated segment and `{name:int}` a
79
- * typed one.
79
+ * typed one. A param's name is ASCII letters, digits and _: a brace pair such as `{café}` is literal text, and is
80
+ * warned about.
80
81
  * @returns A route whose `build` takes a value for each param.
81
82
  * @throws Error when the pattern cannot be read, as `@Command` would throw for it.
82
83
  *
@@ -58,7 +58,7 @@ interface Route<T extends string = string> {
58
58
  * encoded, and the handler receives the value as it was given.
59
59
  *
60
60
  * @throws TypeError for a missing, empty or unknown value or one not of its param's type, and RangeError for an id
61
- * over 100 characters.
61
+ * that is empty or over 100 characters.
62
62
  */
63
63
  build(...values: [RouteParams<T>] extends [never] ? [] : [values: RouteValues<T>]): string;
64
64
  /** The pattern, so a route reads as its pattern in a template string. */
@@ -76,7 +76,8 @@ interface Route<T extends string = string> {
76
76
  * fails to compile, and a typed param takes a value of its type.
77
77
  *
78
78
  * @param pattern - The customId pattern, where `{name}` captures one `/`-separated segment and `{name:int}` a
79
- * typed one.
79
+ * typed one. A param's name is ASCII letters, digits and _: a brace pair such as `{café}` is literal text, and is
80
+ * warned about.
80
81
  * @returns A route whose `build` takes a value for each param.
81
82
  * @throws Error when the pattern cannot be read, as `@Command` would throw for it.
82
83
  *