meocord 4.2.2 → 4.2.3

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 (136) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/dist/cjs/_shared/{controller.decorator-U2NBWcoU.cjs → controller.decorator-hp5xdJU4.cjs} +512 -183
  3. package/dist/cjs/_shared/{startup-roots-lA5xkBFq.cjs → event-sources-DzqTODXg.cjs} +265 -80
  4. package/dist/cjs/_shared/{providers-B4MOFBrW.cjs → providers-BBvbnmLP.cjs} +780 -281
  5. package/dist/cjs/_shared/{sharded-cooldown-store-HTUb3Ii_.cjs → sharded-cooldown-store-B62g5O88.cjs} +11 -9
  6. package/dist/cjs/_shared/{translate-error-CbBHUu5P.cjs → translate-error-wsgfsUET.cjs} +1 -1
  7. package/dist/cjs/common/index.cjs +4 -104
  8. package/dist/cjs/core/index.cjs +432 -181
  9. package/dist/cjs/decorator/index.cjs +85 -120
  10. package/dist/cjs/testing/index.cjs +1664 -784
  11. package/dist/cli.json +1 -1
  12. package/dist/esm/bin/app-template/package.json.template +9 -9
  13. package/dist/esm/bin/app-template/src/main.ts.template +3 -2
  14. package/dist/esm/bin/generator.js +6 -4
  15. package/dist/esm/bin/helper/filter-generator.helper.js +6 -4
  16. package/dist/esm/bin/helper/guard-generator.helper.js +6 -4
  17. package/dist/esm/bin/helper/interceptor-generator.helper.js +6 -4
  18. package/dist/esm/bin/helper/observer-generator.helper.js +6 -4
  19. package/dist/esm/bin/helper/pipe-generator.helper.js +6 -4
  20. package/dist/esm/bin/helper/service-generator.helper.js +6 -4
  21. package/dist/esm/bin/meocord.js +106 -48
  22. package/dist/esm/build/native-addons.js +75 -19
  23. package/dist/esm/build/rsbuild-config.js +11 -3
  24. package/dist/esm/build/typed-externals.js +15 -2
  25. package/dist/esm/common/cooldown-store.js +38 -14
  26. package/dist/esm/common/deprecation.js +4 -1
  27. package/dist/esm/common/execution-context.js +3 -1
  28. package/dist/esm/common/explained-error.js +7 -3
  29. package/dist/esm/common/log-level.js +13 -9
  30. package/dist/esm/common/logger.js +4 -2
  31. package/dist/esm/common/meocord-text.js +11 -6
  32. package/dist/esm/common/redis-cooldown-store.js +3 -7
  33. package/dist/esm/common/response/flags.js +17 -1
  34. package/dist/esm/common/response/install-context.js +27 -16
  35. package/dist/esm/common/response/presenter.js +7 -3
  36. package/dist/esm/common/response/response-state.js +27 -5
  37. package/dist/esm/common/sharded-cooldown-store.js +11 -9
  38. package/dist/esm/common/theme.js +3 -1
  39. package/dist/esm/common/translator.js +17 -8
  40. package/dist/esm/core/autocomplete-routes.js +26 -0
  41. package/dist/esm/core/command-conflicts.js +15 -7
  42. package/dist/esm/core/command-registration.js +15 -1
  43. package/dist/esm/core/cooldown-runner.js +7 -9
  44. package/dist/esm/core/defer.js +2 -5
  45. package/dist/esm/core/dispatcher.js +83 -58
  46. package/dist/esm/core/event-requirements.js +67 -19
  47. package/dist/esm/core/event-sources.js +100 -0
  48. package/dist/esm/core/fallback.js +3 -1
  49. package/dist/esm/core/filter-runner.js +4 -4
  50. package/dist/esm/core/guard-runner.js +173 -52
  51. package/dist/esm/core/handler-input.js +24 -3
  52. package/dist/esm/core/handler-pipeline.js +44 -28
  53. package/dist/esm/core/handler-registry.js +51 -21
  54. package/dist/esm/core/input-runner.js +7 -8
  55. package/dist/esm/core/interceptor-runner.js +4 -5
  56. package/dist/esm/core/lifecycle-hooks.js +3 -8
  57. package/dist/esm/core/lifecycle-order.js +1 -15
  58. package/dist/esm/core/meocord-classes.js +14 -1
  59. package/dist/esm/core/meocord-factory.js +80 -53
  60. package/dist/esm/core/meocord.app.js +174 -89
  61. package/dist/esm/core/message-help.js +5 -9
  62. package/dist/esm/core/message-params.js +126 -46
  63. package/dist/esm/core/message-routes.js +225 -45
  64. package/dist/esm/core/message-words.js +30 -2
  65. package/dist/esm/core/observer-runner.js +2 -1
  66. package/dist/esm/core/process-state.js +19 -0
  67. package/dist/esm/core/providers.js +28 -3
  68. package/dist/esm/core/scalar-types.js +57 -16
  69. package/dist/esm/core/shard-context.js +11 -10
  70. package/dist/esm/core/shard-exit.js +3 -3
  71. package/dist/esm/core/shard-manager.js +16 -6
  72. package/dist/esm/core/startup-roots.js +28 -8
  73. package/dist/esm/core/theme-resolvers.js +26 -11
  74. package/dist/esm/core/theme-runtime.js +23 -13
  75. package/dist/esm/core/theme-scope.js +27 -29
  76. package/dist/esm/core/theme-validation.js +1 -1
  77. package/dist/esm/decorator/app.decorator.js +6 -1
  78. package/dist/esm/decorator/command-builder.decorator.js +14 -0
  79. package/dist/esm/decorator/controller-class.decorator.js +1 -1
  80. package/dist/esm/decorator/controller.decorator.js +48 -19
  81. package/dist/esm/decorator/defer.decorator.js +2 -2
  82. package/dist/esm/decorator/event.decorator.js +4 -5
  83. package/dist/esm/decorator/filter.decorator.js +2 -2
  84. package/dist/esm/decorator/guard.decorator.js +4 -61
  85. package/dist/esm/decorator/inject.decorator.js +4 -1
  86. package/dist/esm/decorator/interceptor.decorator.js +2 -2
  87. package/dist/esm/decorator/theme.decorator.js +4 -3
  88. package/dist/esm/decorator/validation.decorator.js +5 -5
  89. package/dist/esm/package.json.js +1 -1
  90. package/dist/esm/testing/catalog.js +29 -13
  91. package/dist/esm/testing/cooldown-store-suite.js +3 -3
  92. package/dist/esm/testing/discord-defaults.js +449 -355
  93. package/dist/esm/testing/inspect-handler.js +91 -10
  94. package/dist/esm/testing/meocord-testing-module.js +195 -77
  95. package/dist/esm/testing/mock-fn.js +8 -2
  96. package/dist/esm/testing/mock-interaction.js +639 -113
  97. package/dist/esm/testing/response-log.js +8 -0
  98. package/dist/esm/testing/response.js +7 -5
  99. package/dist/esm/testing/routing.js +48 -6
  100. package/dist/esm/testing/strict-mocks.js +1 -0
  101. package/dist/esm/testing/theme.js +3 -2
  102. package/dist/esm/util/common.util.js +30 -9
  103. package/dist/esm/util/generator-cli.util.js +6 -4
  104. package/dist/esm/util/inherited-env.util.js +72 -13
  105. package/dist/esm/util/json.util.js +10 -3
  106. package/dist/esm/util/meocord-cli.util.js +3 -2
  107. package/dist/esm/util/meocord-config-loader.util.js +14 -1
  108. package/dist/esm/util/meocord-config-validation.util.js +13 -3
  109. package/dist/esm/util/meocord-source-config.util.js +13 -3
  110. package/dist/esm/util/platform.util.js +3 -2
  111. package/dist/esm/util/refusal.util.js +29 -11
  112. package/dist/esm/util/registration-mode.util.js +14 -1
  113. package/dist/esm/util/timer-limit.util.js +4 -1
  114. package/dist/esm/util/tsconfig-paths.util.js +38 -7
  115. package/dist/esm/util/tsconfig.util.js +16 -58
  116. package/dist/esm/util/user-text.util.js +8 -4
  117. package/dist/esm/util/value.util.js +15 -4
  118. package/dist/types/common/index.d.cts +13 -9
  119. package/dist/types/common/index.d.ts +13 -9
  120. package/dist/types/core/index.d.cts +21 -11
  121. package/dist/types/core/index.d.ts +21 -11
  122. package/dist/types/decorator/index.d.cts +63 -63
  123. package/dist/types/decorator/index.d.ts +63 -63
  124. package/dist/types/{index-DKJclIi-.d.ts → index-Brkd6QGL.d.ts} +81 -35
  125. package/dist/types/{index-Dlf0ZZtS.d.cts → index-CqXImwF_.d.cts} +81 -35
  126. package/dist/types/interface/index.d.cts +1 -1
  127. package/dist/types/interface/index.d.ts +1 -1
  128. package/dist/types/{route-Bh1U13yy.d.ts → route-IQrK-MN2.d.cts} +11 -3
  129. package/dist/types/{route-Bh1U13yy.d.cts → route-bI-okq7g.d.ts} +11 -3
  130. package/dist/types/testing/index.d.cts +137 -54
  131. package/dist/types/testing/index.d.ts +137 -54
  132. package/dist/types/{theme-resolvers-CyEz9pnv.d.cts → theme-resolvers-AtgeaYqF.d.cts} +1 -1
  133. package/dist/types/{theme-resolvers-DA204O-q.d.ts → theme-resolvers-BgqysV8d.d.ts} +1 -1
  134. package/dist/types/{translator-Bg7hwxDF.d.cts → translator-D8aydlCE.d.ts} +12 -11
  135. package/dist/types/{translator-CeP4bCzp.d.ts → translator-iJhDlgwL.d.cts} +12 -11
  136. package/package.json +5 -2
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('reflect-metadata');
4
- var providers = require('../_shared/providers-B4MOFBrW.cjs');
5
- var controller_decorator = require('../_shared/controller.decorator-U2NBWcoU.cjs');
4
+ var providers = require('../_shared/providers-BBvbnmLP.cjs');
5
+ var controller_decorator = require('../_shared/controller.decorator-hp5xdJU4.cjs');
6
6
  var inversify = require('inversify');
7
7
  require('node:async_hooks');
8
8
  require('../enum/index.cjs');
@@ -12,14 +12,14 @@ require('fs');
12
12
  require('path');
13
13
  require('cli-table3');
14
14
  require('node:crypto');
15
- require('node:fs');
16
- require('node:url');
17
15
  require('node:util');
18
16
  require('dayjs');
19
17
  require('dayjs/plugin/utc.js');
20
18
  require('dayjs/plugin/timezone.js');
21
19
  require('module');
20
+ require('node:fs');
22
21
  require('chalk');
22
+ require('node:url');
23
23
 
24
24
  /**
25
25
  * Marks a class as a service, which controllers and other services inject by its type.
@@ -54,6 +54,13 @@ require('chalk');
54
54
  });
55
55
  }
56
56
 
57
+ const logger$3 = new controller_decorator.Logger('CommandBuilder');
58
+ /** The nearest base class of `target` that gives `guilds`, which `target` inherits when it gives none. */ function guildsBase(target) {
59
+ for(let base = Object.getPrototypeOf(target); base && base !== Function.prototype; base = Object.getPrototypeOf(base)){
60
+ if (Reflect.hasOwnMetadata(controller_decorator.META.builderGuilds, base)) return base;
61
+ }
62
+ return undefined;
63
+ }
57
64
  /**
58
65
  * Marks a class as a command's builder, which describes the command MeoCord registers with Discord.
59
66
  *
@@ -91,45 +98,61 @@ require('chalk');
91
98
  if (options.guilds) Reflect.defineMetadata(controller_decorator.META.builderGuilds, [
92
99
  ...options.guilds
93
100
  ], target);
101
+ else {
102
+ const base = guildsBase(target);
103
+ if (base) {
104
+ logger$3.warn(`${target.name} gives no guilds and inherits ${base.name}'s; declare guilds on ${target.name} to keep them. ` + 'The next major version (5.0) registers it in the configured scope.');
105
+ }
106
+ }
94
107
  });
95
108
  }
96
109
 
97
110
  /**
98
- * Adds guards to a method's class or method list, then republishes the effective list under
99
- * `META.guards`, in the order they run: the bases' before the class's own, and within one class or method the
100
- * latest decorator first, since it wraps outermost.
101
- */ function recordGuards(key, guards, prototype, methodName) {
102
- const existing = Reflect.getOwnMetadata(key, prototype, methodName) ?? [];
103
- const bases = key === controller_decorator.META.classGuards ? Reflect.getOwnMetadata(controller_decorator.META.baseClassGuards, prototype, methodName) ?? 0 : 0;
104
- Reflect.defineMetadata(key, [
105
- ...existing.slice(0, bases),
106
- ...guards,
107
- ...existing.slice(bases)
108
- ], prototype, methodName);
109
- const [classGuards, inheritedGuards, methodGuards] = [
110
- controller_decorator.META.classGuards,
111
- controller_decorator.META.inheritedGuards,
112
- controller_decorator.META.methodGuards
113
- ].map((list)=>Reflect.getOwnMetadata(list, prototype, methodName) ?? []);
114
- Reflect.defineMetadata(controller_decorator.META.guards, [
115
- ...inheritedGuards,
116
- ...classGuards,
117
- ...methodGuards
118
- ], prototype, methodName);
119
- }
120
- /**
121
- * Wraps a method so a direct call runs its guards first: the wrapper entered first runs the whole
122
- * chain dispatch resolves for the handler, and lets the ones inside it through. A call from dispatch,
123
- * which has already run the guards, passes through every wrapper.
124
- */ function applyGuards(descriptor, prototype, propertyKey) {
125
- const originalMethod = descriptor.value;
126
- descriptor.value = controller_decorator.wrapsMethod(async function(...args) {
127
- if (providers.consumeDispatchMark(args[0], this, propertyKey)) return originalMethod.apply(this, args);
128
- return providers.runDirectCall(this, propertyKey, args, ()=>originalMethod.apply(this, args));
129
- }, originalMethod);
130
- const wrappers = Reflect.getOwnMetadata(controller_decorator.META.guardWrappers, prototype, propertyKey) ?? 0;
131
- Reflect.defineMetadata(controller_decorator.META.guardWrappers, wrappers + 1, prototype, propertyKey);
111
+ * Marks a class as a controller, whose methods handle commands, components, messages, reactions or events.
112
+ *
113
+ * Use it on every class of handlers, and list the class in `@MeoCord({ controllers })`. Logic the handlers
114
+ * share, such as database access, belongs in a service it injects.
115
+ *
116
+ * @remarks
117
+ * A controller's class-level guards and filters apply to every handler it declares or inherits, its interceptors to
118
+ * all but autocomplete, and its cooldowns to its command, component and message handlers; each also applies to the
119
+ * handlers of a class that extends it. A base wraps what extends it: guards and interceptors
120
+ * run the top base's first, then each subclass's, then the method's, and filters are tried the other way, the
121
+ * method's first. `inheritStages: false` keeps the handlers a subclass declares to its own stages.
122
+ *
123
+ * @param options - Whether the handlers it declares take the stages of the classes it extends.
124
+ *
125
+ * @example
126
+ * ```ts
127
+ * @Controller()
128
+ * export class ProfileSlashController {
129
+ * constructor(private readonly profiles: ProfileService) {}
130
+ *
131
+ * @Command('profile', CommandType.SLASH)
132
+ * async profile(interaction: ChatInputCommandInteraction) {
133
+ * await respond(interaction).send({ embeds: [await this.profiles.render(interaction.user.id)] })
134
+ * }
135
+ * }
136
+ * ```
137
+ *
138
+ * @group Decorators
139
+ * @category Controllers
140
+ * @see {@link Command}
141
+ * @see {@link ControllerOptions}
142
+ * @see {@link https://meocord.dev/docs/4.2/how-a-call-runs | How a call runs}
143
+ */ function Controller(options = {}) {
144
+ return controller_decorator.declaring(function(target, propertyKey) {
145
+ if (controller_decorator.deprecatedOnMethod('@Controller', target, propertyKey)) return;
146
+ providers.makeInjectable(target);
147
+ if (options.inheritStages === false) Reflect.defineMetadata(controller_decorator.META.inheritStages, false, target);
148
+ if (options.inheritedRoutes === 'replace') {
149
+ controller_decorator.dropInheritedRoutes(target.prototype);
150
+ Reflect.defineMetadata(controller_decorator.META.replacesInheritedRoutes, true, target.prototype);
151
+ }
152
+ providers.guardOwnHandlersWithBaseGuards(target);
153
+ });
132
154
  }
155
+
133
156
  /**
134
157
  * The class's own descriptor for a handler. An inherited handler gets one that calls the inherited
135
158
  * method, starting from its guard lists and wrapper count, so class guards wrap it like an own method.
@@ -157,26 +180,6 @@ require('chalk');
157
180
  ...inherited
158
181
  };
159
182
  }
160
- /**
161
- * Gives each handler a controller declares itself the class-level guards of the classes it extends,
162
- * as its inherited handlers have: recorded under `META.guards`, and wrapped so a direct call
163
- * runs them when no other guard wraps the handler. `@Controller` calls this.
164
- */ function guardOwnHandlersWithBaseGuards(target) {
165
- const prototype = target.prototype;
166
- for (const methodName of providers.handlerMethods(prototype)){
167
- const descriptor = Object.getOwnPropertyDescriptor(prototype, methodName);
168
- // Inherited handlers have the chain of the class that declares them
169
- if (typeof descriptor?.value !== 'function' || Reflect.getOwnMetadata(controller_decorator.META.inheritedFrom, prototype, methodName)) continue;
170
- // Base first, as dispatch runs them
171
- const guards = providers.classChain(prototype, prototype).slice(1).reverse().flatMap(providers.classLevelGuards);
172
- if (guards.length === 0) continue;
173
- if (!Reflect.getOwnMetadata(controller_decorator.META.guardWrappers, prototype, methodName)) {
174
- applyGuards(descriptor, prototype, methodName);
175
- Object.defineProperty(prototype, methodName, descriptor);
176
- }
177
- recordGuards(controller_decorator.META.inheritedGuards, guards, prototype, methodName);
178
- }
179
- }
180
183
  /**
181
184
  * Marks a class as a guard, which decides whether a handler runs.
182
185
  *
@@ -250,12 +253,12 @@ require('chalk');
250
253
  */ function UseGuard(...entries) {
251
254
  const guards = entries;
252
255
  return controller_decorator.declaring(function(target, propertyKey, descriptor) {
253
- const where = propertyKey === undefined ? String(target?.name) : `${target.constructor.name}.${String(propertyKey)}`;
256
+ const where = controller_decorator.decoratedName(target, propertyKey);
254
257
  providers.assertStageEntries('@UseGuard', 'guard', where, guards);
255
258
  if (descriptor && propertyKey) {
256
259
  // Method Decorator
257
- applyGuards(descriptor, target, String(propertyKey));
258
- recordGuards(controller_decorator.META.methodGuards, guards, target, String(propertyKey));
260
+ providers.applyGuards(descriptor, target, String(propertyKey));
261
+ providers.recordGuards(controller_decorator.META.methodGuards, guards, target, String(propertyKey));
259
262
  } else if (typeof target === 'function' && !propertyKey && !descriptor) {
260
263
  // Class Decorator
261
264
  const prototype = target.prototype;
@@ -268,61 +271,15 @@ require('chalk');
268
271
  for (const methodName of methods){
269
272
  const methodDescriptor = ownHandlerDescriptor(prototype, methodName);
270
273
  if (methodDescriptor) {
271
- applyGuards(methodDescriptor, prototype, methodName);
274
+ providers.applyGuards(methodDescriptor, prototype, methodName);
272
275
  Object.defineProperty(prototype, methodName, methodDescriptor);
273
- recordGuards(controller_decorator.META.classGuards, guards, prototype, methodName);
276
+ providers.recordGuards(controller_decorator.META.classGuards, guards, prototype, methodName);
274
277
  }
275
278
  }
276
279
  }
277
280
  });
278
281
  }
279
282
 
280
- /**
281
- * Marks a class as a controller, whose methods handle commands, components, messages, reactions or events.
282
- *
283
- * Use it on every class of handlers, and list the class in `@MeoCord({ controllers })`. Logic the handlers
284
- * share, such as database access, belongs in a service it injects.
285
- *
286
- * @remarks
287
- * A controller's class-level guards and filters apply to every handler it declares or inherits, its interceptors to
288
- * all but autocomplete, and its cooldowns to its command, component and message handlers; each also applies to the
289
- * handlers of a class that extends it. A base wraps what extends it: guards and interceptors
290
- * run the top base's first, then each subclass's, then the method's, and filters are tried the other way, the
291
- * method's first. `inheritStages: false` keeps the handlers a subclass declares to its own stages.
292
- *
293
- * @param options - Whether the handlers it declares take the stages of the classes it extends.
294
- *
295
- * @example
296
- * ```ts
297
- * @Controller()
298
- * export class ProfileSlashController {
299
- * constructor(private readonly profiles: ProfileService) {}
300
- *
301
- * @Command('profile', CommandType.SLASH)
302
- * async profile(interaction: ChatInputCommandInteraction) {
303
- * await respond(interaction).send({ embeds: [await this.profiles.render(interaction.user.id)] })
304
- * }
305
- * }
306
- * ```
307
- *
308
- * @group Decorators
309
- * @category Controllers
310
- * @see {@link Command}
311
- * @see {@link ControllerOptions}
312
- * @see {@link https://meocord.dev/docs/4.2/how-a-call-runs | How a call runs}
313
- */ function Controller(options = {}) {
314
- return controller_decorator.declaring(function(target, propertyKey) {
315
- if (controller_decorator.deprecatedOnMethod('@Controller', target, propertyKey)) return;
316
- providers.makeInjectable(target);
317
- if (options.inheritStages === false) Reflect.defineMetadata(controller_decorator.META.inheritStages, false, target);
318
- if (options.inheritedRoutes === 'replace') {
319
- controller_decorator.dropInheritedRoutes(target.prototype);
320
- Reflect.defineMetadata(controller_decorator.META.replacesInheritedRoutes, true, target.prototype);
321
- }
322
- guardOwnHandlersWithBaseGuards(target);
323
- });
324
- }
325
-
326
283
  /**
327
284
  * Marks a class as an interceptor, which wraps a handler to act before and after it.
328
285
  *
@@ -395,7 +352,7 @@ require('chalk');
395
352
  * @see {@link https://meocord.dev/docs/4.2/interceptors | Interceptors}
396
353
  */ function UseInterceptor(...interceptors) {
397
354
  return controller_decorator.declaring(function(target, propertyKey) {
398
- const where = propertyKey === undefined ? target.name : `${target.constructor.name}.${String(propertyKey)}`;
355
+ const where = controller_decorator.decoratedName(target, propertyKey);
399
356
  providers.assertStageEntries('@UseInterceptor', 'interceptor', where, interceptors);
400
357
  // Decorators apply bottom-up, so a higher decorator's interceptors go first, as with @UseGuard.
401
358
  if (propertyKey === undefined) {
@@ -449,12 +406,12 @@ require('chalk');
449
406
  errorTypes.forEach((type, index)=>{
450
407
  if (controller_decorator.isConstructible(type)) return;
451
408
  const entry = ORDINALS[index] ? `${ORDINALS[index]} entry` : `entry ${index + 1}`;
452
- controller_decorator.warnDeprecatedBehaviour(logger$1, `${target.name}: @Catch's ${entry}, ${controller_decorator.describeValue(type)}, which matches no error,`, 'is refused', 'an error class, such as @Catch(CooldownError),');
409
+ controller_decorator.warnDeprecatedBehaviour(logger$2, `${target.name}: @Catch's ${entry}, ${controller_decorator.describeValue(type)}, which matches no error,`, 'is refused', 'an error class, such as @Catch(CooldownError),');
453
410
  });
454
411
  Reflect.defineMetadata(controller_decorator.META.catchTypes, errorTypes, target);
455
412
  });
456
413
  }
457
- const logger$1 = new controller_decorator.Logger('Catch');
414
+ const logger$2 = new controller_decorator.Logger('Catch');
458
415
  const ORDINALS = [
459
416
  'first',
460
417
  'second',
@@ -495,7 +452,7 @@ const ORDINALS = [
495
452
  * @see {@link https://meocord.dev/docs/4.2/exception-filters | Exception filters}
496
453
  */ function UseFilter(...filters) {
497
454
  return controller_decorator.declaring(function(target, propertyKey) {
498
- const where = propertyKey === undefined ? target.name : `${target.constructor.name}.${String(propertyKey)}`;
455
+ const where = controller_decorator.decoratedName(target, propertyKey);
499
456
  providers.assertStageEntries('@UseFilter', 'filter', where, filters);
500
457
  // Decorators apply bottom-up, so a higher decorator's filters are tried first.
501
458
  if (propertyKey === undefined) {
@@ -514,6 +471,7 @@ const ORDINALS = [
514
471
  });
515
472
  }
516
473
 
474
+ const logger$1 = new controller_decorator.Logger('MeoCord');
517
475
  /** Refuses a `messages` option of the wrong type where the app is declared, rather than at the first message. */ function assertMessageOptions(appName, messages, i18n) {
518
476
  if (!messages) return;
519
477
  const { prefix, mention, caseSensitive } = messages;
@@ -541,6 +499,9 @@ const ORDINALS = [
541
499
  if (deleteUsageRepliesAfter !== undefined && !(typeof deleteUsageRepliesAfter === 'number' && deleteUsageRepliesAfter >= 0 && Number.isFinite(deleteUsageRepliesAfter))) {
542
500
  throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ messages: { deleteUsageRepliesAfter } }) takes a number of seconds, or 0 to keep usage replies.`));
543
501
  }
502
+ if (deleteUsageRepliesAfter !== undefined && !providers.timerKeepsSeconds(deleteUsageRepliesAfter)) {
503
+ logger$1.warn(`${appName}: @MeoCord({ messages: { deleteUsageRepliesAfter } }) is ${deleteUsageRepliesAfter} seconds, longer than a timer ` + `can wait (${providers.MAX_TIMER_SECONDS}), so usage replies are kept. The next major version (5.0) refuses it.`);
504
+ }
544
505
  const { help } = messages;
545
506
  // One word each, since help is asked for by its first word
546
507
  const isWord = (value)=>typeof value === 'string' && /^\S+$/.test(value);
@@ -723,15 +684,15 @@ const ORDINALS = [
723
684
  controller_decorator.refuseOnClass('@Validate', target, propertyKey);
724
685
  // Checked where it applies, so the refusal names the handler
725
686
  if (typeof schema?.['~standard']?.validate !== 'function') {
726
- throw controller_decorator.refuse(new Error(`${target.constructor.name}.${propertyKey}: @Validate takes a Standard Schema, such as a zod, valibot or arktype schema.`));
687
+ throw controller_decorator.refuse(new Error(`${controller_decorator.decoratedName(target, propertyKey)}: @Validate takes a Standard Schema, such as a zod, valibot or arktype schema.`));
727
688
  }
728
689
  if (Reflect.hasOwnMetadata(controller_decorator.META.methodValidation, target, propertyKey)) {
729
- throw controller_decorator.refuse(new Error(`${target.constructor.name}.${propertyKey}: more than one @Validate; one @Validate per handler: combine the schemas into one.`));
690
+ throw controller_decorator.refuse(new Error(`${controller_decorator.decoratedName(target, propertyKey)}: more than one @Validate; one @Validate per handler: combine the schemas into one.`));
730
691
  }
731
692
  const inlinePipes = Object.values(options.pipes ?? {}).flatMap((entries)=>Array.isArray(entries) ? entries : [
732
693
  entries
733
694
  ]);
734
- providers.assertStageEntries('@Validate', 'pipe', `${target.constructor.name}.${propertyKey}`, inlinePipes);
695
+ providers.assertStageEntries('@Validate', 'pipe', controller_decorator.decoratedName(target, propertyKey), inlinePipes);
735
696
  const metadata = {
736
697
  schema,
737
698
  pipes: options.pipes ?? {}
@@ -773,7 +734,7 @@ const ORDINALS = [
773
734
  */ function UsePipe(key, ...pipes) {
774
735
  return controller_decorator.declaring(function(target, propertyKey, _descriptor) {
775
736
  controller_decorator.refuseOnClass('@UsePipe', target, propertyKey);
776
- providers.assertStageEntries('@UsePipe', 'pipe', `${target.constructor.name}.${propertyKey}`, pipes);
737
+ providers.assertStageEntries('@UsePipe', 'pipe', controller_decorator.decoratedName(target, propertyKey), pipes);
777
738
  // Decorators apply bottom-up, so a higher @UsePipe's pipes go first, in the order they read.
778
739
  const existing = Reflect.getOwnMetadata(controller_decorator.META.methodPipes, target, propertyKey) ?? [];
779
740
  Reflect.defineMetadata(controller_decorator.META.methodPipes, [
@@ -921,7 +882,7 @@ const logger = new controller_decorator.Logger('Cooldown');
921
882
  controller_decorator.refuseOnClass('@Defer', target, propertyKey);
922
883
  const methodName = String(propertyKey);
923
884
  const kind = providers.nonInteractionHandler(target, methodName);
924
- if (kind) throw controller_decorator.refuse(providers.deferMisuseError(target.constructor.name, methodName, kind));
885
+ if (kind) throw controller_decorator.refuse(providers.deferMisuseError(controller_decorator.ownerName(target), methodName, kind));
925
886
  Reflect.defineMetadata(controller_decorator.META.deferOptions, {
926
887
  ...options
927
888
  }, target, methodName);
@@ -957,6 +918,9 @@ const logger = new controller_decorator.Logger('Cooldown');
957
918
  return controller_decorator.declaring((target, propertyKey, parameterIndex)=>{
958
919
  // A constructor parameter has no property key either, but has an index
959
920
  if (typeof parameterIndex !== 'number') controller_decorator.refuseOnClass('@Inject', target, propertyKey, 'a constructor parameter or a property');
921
+ else if (propertyKey !== undefined) {
922
+ throw controller_decorator.refuse(new Error(`${controller_decorator.decoratedName(target, propertyKey)}: @Inject goes on a constructor parameter or a property, not a method parameter.`));
923
+ }
960
924
  decorate(target, propertyKey, parameterIndex);
961
925
  });
962
926
  }
@@ -1037,8 +1001,9 @@ const logger = new controller_decorator.Logger('Cooldown');
1037
1001
  */ function UseTheme(theme) {
1038
1002
  return controller_decorator.declaring(function(target, propertyKey) {
1039
1003
  const onClass = propertyKey === undefined;
1040
- const owner = onClass ? target : target.constructor;
1041
- const where = `${owner.name}${onClass ? '' : `.${String(propertyKey)}`}: @UseTheme`;
1004
+ // The class it themes: the target itself on a class or a static member, else the target's constructor
1005
+ const owner = onClass || typeof target === 'function' ? target : target.constructor;
1006
+ const where = `${controller_decorator.decoratedName(target, propertyKey)}: @UseTheme`;
1042
1007
  controller_decorator.assertValidTheme(theme, where);
1043
1008
  const key = onClass ? controller_decorator.META.classTheme : controller_decorator.META.methodTheme;
1044
1009
  const existing = onClass ? Reflect.getOwnMetadata(key, target) : Reflect.getOwnMetadata(key, target, propertyKey);