meocord 4.1.2 → 4.2.1

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 (140) hide show
  1. package/CHANGELOG.md +362 -0
  2. package/THIRD_PARTY_NOTICES.md +14 -13
  3. package/dist/cjs/_shared/{controller.decorator-BywwkU9O.cjs → controller.decorator-XKMlcUZz.cjs} +669 -185
  4. package/dist/cjs/_shared/{providers-BMMLp2SN.cjs → providers-BZgJyfZS.cjs} +218 -75
  5. package/dist/cjs/_shared/{sharded-cooldown-store-B65iaiAy.cjs → sharded-cooldown-store-CsJJyCZd.cjs} +10 -7
  6. package/dist/cjs/_shared/{startup-roots-lFc69AxC.cjs → startup-roots-CgfPQrNl.cjs} +374 -132
  7. package/dist/cjs/_shared/{translate-error-BnM8FbSH.cjs → translate-error-BUAR1WYG.cjs} +21 -7
  8. package/dist/cjs/common/index.cjs +4 -4
  9. package/dist/cjs/core/index.cjs +365 -310
  10. package/dist/cjs/decorator/index.cjs +85 -61
  11. package/dist/cjs/testing/index.cjs +2236 -496
  12. package/dist/cli.json +1 -1
  13. package/dist/esm/bin/app-template/README.md.template +3 -1
  14. package/dist/esm/bin/app-template/src/controllers/button/sample.button.controller.spec.ts.template +8 -4
  15. package/dist/esm/bin/app-template/src/controllers/button/sample.button.controller.ts.template +2 -2
  16. package/dist/esm/bin/app-template/src/guards/owner.guard.spec.ts.template +8 -4
  17. package/dist/esm/bin/app-template/src/guards/owner.guard.ts.template +1 -1
  18. package/dist/esm/bin/app-template/vitest.config.ts.template +1 -1
  19. package/dist/esm/bin/app-template/vitest.setup.ts.template +7 -3
  20. package/dist/esm/bin/generator.js +4 -5
  21. package/dist/esm/bin/helper/filter-generator.helper.js +4 -5
  22. package/dist/esm/bin/helper/guard-generator.helper.js +4 -5
  23. package/dist/esm/bin/helper/interceptor-generator.helper.js +4 -5
  24. package/dist/esm/bin/helper/observer-generator.helper.js +4 -5
  25. package/dist/esm/bin/helper/pipe-generator.helper.js +4 -5
  26. package/dist/esm/bin/helper/service-generator.helper.js +4 -5
  27. package/dist/esm/bin/meocord.js +84 -25
  28. package/dist/esm/build/load-config.pre-entry.js +17 -4
  29. package/dist/esm/build/rsbuild-config.js +16 -12
  30. package/dist/esm/build/typed-externals.js +36 -0
  31. package/dist/esm/common/cooldown-store.js +10 -2
  32. package/dist/esm/common/decorator.js +6 -6
  33. package/dist/esm/common/deprecation.js +2 -2
  34. package/dist/esm/common/errors.js +27 -2
  35. package/dist/esm/common/execution-context.js +1 -1
  36. package/dist/esm/common/meocord-text.js +11 -8
  37. package/dist/esm/common/metadata.js +1 -1
  38. package/dist/esm/common/response/call-order.js +9 -4
  39. package/dist/esm/common/response/presenter.js +33 -6
  40. package/dist/esm/common/response/response-state.js +84 -10
  41. package/dist/esm/common/route.js +21 -5
  42. package/dist/esm/common/sharded-cooldown-store.js +1 -1
  43. package/dist/esm/common/translate-error.js +1 -1
  44. package/dist/esm/common/translator.js +37 -6
  45. package/dist/esm/core/command-conflicts.js +34 -34
  46. package/dist/esm/core/command-registration.js +93 -24
  47. package/dist/esm/core/command-routes.js +2 -2
  48. package/dist/esm/core/component-routes.js +74 -31
  49. package/dist/esm/core/cooldown-runner.js +29 -8
  50. package/dist/esm/core/dispatcher.js +51 -7
  51. package/dist/esm/core/fallback.js +20 -11
  52. package/dist/esm/core/filter-runner.js +2 -2
  53. package/dist/esm/core/guard-runner.js +16 -3
  54. package/dist/esm/core/handler-input.js +4 -3
  55. package/dist/esm/core/handler-pipeline.js +27 -14
  56. package/dist/esm/core/handler-registry.js +1 -1
  57. package/dist/esm/core/interceptor-runner.js +2 -2
  58. package/dist/esm/core/lifecycle-hooks.js +134 -47
  59. package/dist/esm/core/meocord-factory.js +241 -179
  60. package/dist/esm/core/meocord.app.js +116 -75
  61. package/dist/esm/core/message-routes.js +4 -3
  62. package/dist/esm/core/observer-runner.js +4 -3
  63. package/dist/esm/core/providers.js +45 -23
  64. package/dist/esm/core/route-specificity.js +4 -4
  65. package/dist/esm/core/running-calls.js +43 -0
  66. package/dist/esm/core/scalar-types.js +15 -3
  67. package/dist/esm/core/shard-context.js +6 -7
  68. package/dist/esm/core/shard-manager.js +16 -10
  69. package/dist/esm/core/startup-roots.js +23 -4
  70. package/dist/esm/core/theme-resolvers.js +4 -1
  71. package/dist/esm/core/theme-runtime.js +2 -2
  72. package/dist/esm/core/theme-scope.js +3 -1
  73. package/dist/esm/core/theme-validation.js +17 -10
  74. package/dist/esm/decorator/app.decorator.js +12 -7
  75. package/dist/esm/decorator/command-builder.decorator.js +4 -4
  76. package/dist/esm/decorator/controller-class.decorator.js +9 -4
  77. package/dist/esm/decorator/controller.decorator.js +162 -83
  78. package/dist/esm/decorator/cooldown.decorator.js +20 -3
  79. package/dist/esm/decorator/defer.decorator.js +4 -4
  80. package/dist/esm/decorator/event.decorator.js +5 -5
  81. package/dist/esm/decorator/filter.decorator.js +7 -7
  82. package/dist/esm/decorator/guard.decorator.js +11 -10
  83. package/dist/esm/decorator/inject.decorator.js +4 -4
  84. package/dist/esm/decorator/interceptor.decorator.js +7 -7
  85. package/dist/esm/decorator/observer.decorator.js +4 -4
  86. package/dist/esm/decorator/service.decorator.js +4 -4
  87. package/dist/esm/decorator/theme.decorator.js +3 -3
  88. package/dist/esm/decorator/validation.decorator.js +10 -10
  89. package/dist/esm/package.json.js +1 -1
  90. package/dist/esm/testing/catalog.js +27 -11
  91. package/dist/esm/testing/cooldown-store-suite.js +85 -15
  92. package/dist/esm/testing/discord-defaults.js +249 -21
  93. package/dist/esm/testing/index.js +4 -2
  94. package/dist/esm/testing/inspect-handler.js +20 -3
  95. package/dist/esm/testing/meocord-testing-module.js +352 -205
  96. package/dist/esm/testing/mock-fn.js +173 -22
  97. package/dist/esm/testing/mock-interaction.js +1214 -209
  98. package/dist/esm/testing/response.js +1 -1
  99. package/dist/esm/testing/routing.js +39 -14
  100. package/dist/esm/testing/snowflake.js +9 -2
  101. package/dist/esm/testing/startup-errors.js +26 -0
  102. package/dist/esm/testing/strict-mocks.js +65 -0
  103. package/dist/esm/testing/theme.js +1 -1
  104. package/dist/esm/util/bundle-entry.util.js +2 -1
  105. package/dist/esm/util/common.util.js +47 -19
  106. package/dist/esm/util/dev-runner.util.js +8 -8
  107. package/dist/esm/util/generator-cli.util.js +4 -5
  108. package/dist/esm/util/interaction.util.js +3 -3
  109. package/dist/esm/util/meocord-config-loader.util.js +10 -2
  110. package/dist/esm/util/meocord-config-validation.util.js +4 -5
  111. package/dist/esm/util/meocord-source-config.util.js +65 -20
  112. package/dist/esm/util/metadata-keys.js +1 -0
  113. package/dist/esm/util/method-wrapper.util.js +16 -0
  114. package/dist/esm/util/platform.util.js +10 -10
  115. package/dist/esm/util/refusal.util.js +148 -8
  116. package/dist/esm/util/shard-process.util.js +4 -1
  117. package/dist/esm/util/sharding-mode.util.js +5 -7
  118. package/dist/esm/util/shared-state.util.js +21 -0
  119. package/dist/esm/util/tsconfig-paths.util.js +29 -0
  120. package/dist/esm/util/tsconfig.util.js +10 -10
  121. package/dist/esm/util/value.util.js +12 -1
  122. package/dist/types/common/index.d.cts +8 -8
  123. package/dist/types/common/index.d.ts +8 -8
  124. package/dist/types/core/index.d.cts +10 -7
  125. package/dist/types/core/index.d.ts +10 -7
  126. package/dist/types/decorator/index.d.cts +31 -29
  127. package/dist/types/decorator/index.d.ts +31 -29
  128. package/dist/types/{index-D7n0FBMm.d.ts → index-DKJclIi-.d.ts} +107 -36
  129. package/dist/types/{index-DEP0NYrU.d.cts → index-Dlf0ZZtS.d.cts} +107 -36
  130. package/dist/types/interface/index.d.cts +1 -1
  131. package/dist/types/interface/index.d.ts +1 -1
  132. package/dist/types/{route-C-aMI7Sl.d.cts → route-Bh1U13yy.d.cts} +8 -4
  133. package/dist/types/{route-C-aMI7Sl.d.ts → route-Bh1U13yy.d.ts} +8 -4
  134. package/dist/types/testing/index.d.cts +406 -70
  135. package/dist/types/testing/index.d.ts +406 -70
  136. package/dist/types/{theme-resolvers-COHdX5g6.d.cts → theme-resolvers-CyEz9pnv.d.cts} +1 -1
  137. package/dist/types/{theme-resolvers-DedxyscT.d.ts → theme-resolvers-DA204O-q.d.ts} +1 -1
  138. package/dist/types/{translator-J6tIUfdp.d.ts → translator-Bg7hwxDF.d.cts} +21 -8
  139. package/dist/types/{translator-B4mc1lzJ.d.cts → translator-CeP4bCzp.d.ts} +21 -8
  140. package/package.json +4 -3
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('reflect-metadata');
4
- var providers = require('../_shared/providers-BMMLp2SN.cjs');
5
- var controller_decorator = require('../_shared/controller.decorator-BywwkU9O.cjs');
4
+ var providers = require('../_shared/providers-BZgJyfZS.cjs');
5
+ var controller_decorator = require('../_shared/controller.decorator-XKMlcUZz.cjs');
6
6
  var inversify = require('inversify');
7
7
  require('node:async_hooks');
8
8
  require('../enum/index.cjs');
@@ -46,12 +46,12 @@ require('chalk');
46
46
  * @group Decorators
47
47
  * @category App
48
48
  * @see {@link Inject}
49
- * @see {@link https://meocord.dev/docs/4.1/services | Services}
49
+ * @see {@link https://meocord.dev/docs/4.2/services | Services}
50
50
  */ function Service() {
51
- return function(target, propertyKey) {
51
+ return controller_decorator.declaring(function(target, propertyKey) {
52
52
  if (controller_decorator.deprecatedOnMethod('@Service', target, propertyKey)) return;
53
53
  providers.makeInjectable(target);
54
- };
54
+ });
55
55
  }
56
56
 
57
57
  /**
@@ -81,9 +81,9 @@ require('chalk');
81
81
  * @group Decorators
82
82
  * @category Handlers
83
83
  * @see {@link Command}
84
- * @see {@link https://meocord.dev/docs/4.1/slash-commands | Slash commands}
84
+ * @see {@link https://meocord.dev/docs/4.2/slash-commands | Slash commands}
85
85
  */ function CommandBuilder(commandType, options = {}) {
86
- return function(target, propertyKey) {
86
+ return controller_decorator.declaring(function(target, propertyKey) {
87
87
  if (controller_decorator.deprecatedOnMethod('@CommandBuilder', target, propertyKey)) return;
88
88
  providers.makeInjectable(target);
89
89
  // Define the command type metadata for the target class
@@ -91,7 +91,7 @@ require('chalk');
91
91
  if (options.guilds) Reflect.defineMetadata(controller_decorator.META.builderGuilds, [
92
92
  ...options.guilds
93
93
  ], target);
94
- };
94
+ });
95
95
  }
96
96
 
97
97
  /**
@@ -123,10 +123,10 @@ require('chalk');
123
123
  * which has already run the guards, passes through every wrapper.
124
124
  */ function applyGuards(descriptor, prototype, propertyKey) {
125
125
  const originalMethod = descriptor.value;
126
- descriptor.value = async function(...args) {
126
+ descriptor.value = controller_decorator.wrapsMethod(async function(...args) {
127
127
  if (providers.consumeDispatchMark(args[0], this, propertyKey)) return originalMethod.apply(this, args);
128
128
  return providers.runDirectCall(this, propertyKey, args, ()=>originalMethod.apply(this, args));
129
- };
129
+ }, originalMethod);
130
130
  const wrappers = Reflect.getOwnMetadata(controller_decorator.META.guardWrappers, prototype, propertyKey) ?? 0;
131
131
  Reflect.defineMetadata(controller_decorator.META.guardWrappers, wrappers + 1, prototype, propertyKey);
132
132
  }
@@ -208,14 +208,14 @@ require('chalk');
208
208
  * @see {@link UseGuard}
209
209
  * @see {@link GuardDeniedError}
210
210
  * @see {@link ExecutionContext}
211
- * @see {@link https://meocord.dev/docs/4.1/guards | Guards}
211
+ * @see {@link https://meocord.dev/docs/4.2/guards | Guards}
212
212
  */ function Guard(options = {}) {
213
- return function(target, propertyKey) {
213
+ return controller_decorator.declaring(function(target, propertyKey) {
214
214
  if (controller_decorator.deprecatedOnMethod('@Guard', target, propertyKey)) return;
215
215
  providers.makeInjectable(target);
216
216
  providers.defineStageTypes(target, options.types, 'Guard');
217
217
  Reflect.defineMetadata(controller_decorator.META.guardClass, true, target);
218
- };
218
+ });
219
219
  }
220
220
  /**
221
221
  * Runs guards before a handler, or before every handler of a controller.
@@ -246,10 +246,10 @@ require('chalk');
246
246
  * @see {@link Guard}
247
247
  * @see {@link GuardDeniedError}
248
248
  * @see {@link ExecutionContext}
249
- * @see {@link https://meocord.dev/docs/4.1/guards | Guards}
249
+ * @see {@link https://meocord.dev/docs/4.2/guards | Guards}
250
250
  */ function UseGuard(...entries) {
251
251
  const guards = entries;
252
- return function(target, propertyKey, descriptor) {
252
+ return controller_decorator.declaring(function(target, propertyKey, descriptor) {
253
253
  const where = propertyKey === undefined ? String(target?.name) : `${target.constructor.name}.${String(propertyKey)}`;
254
254
  providers.assertStageEntries('@UseGuard', 'guard', where, guards);
255
255
  if (descriptor && propertyKey) {
@@ -274,7 +274,7 @@ require('chalk');
274
274
  }
275
275
  }
276
276
  }
277
- };
277
+ });
278
278
  }
279
279
 
280
280
  /**
@@ -309,14 +309,18 @@ require('chalk');
309
309
  * @category Controllers
310
310
  * @see {@link Command}
311
311
  * @see {@link ControllerOptions}
312
- * @see {@link https://meocord.dev/docs/4.1/how-a-call-runs | How a call runs}
312
+ * @see {@link https://meocord.dev/docs/4.2/how-a-call-runs | How a call runs}
313
313
  */ function Controller(options = {}) {
314
- return function(target, propertyKey) {
314
+ return controller_decorator.declaring(function(target, propertyKey) {
315
315
  if (controller_decorator.deprecatedOnMethod('@Controller', target, propertyKey)) return;
316
316
  providers.makeInjectable(target);
317
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
+ }
318
322
  guardOwnHandlersWithBaseGuards(target);
319
- };
323
+ });
320
324
  }
321
325
 
322
326
  /**
@@ -351,13 +355,13 @@ require('chalk');
351
355
  * @group Decorators
352
356
  * @category Pipeline stages
353
357
  * @see {@link UseInterceptor}
354
- * @see {@link https://meocord.dev/docs/4.1/interceptors | Interceptors}
358
+ * @see {@link https://meocord.dev/docs/4.2/interceptors | Interceptors}
355
359
  */ function Interceptor(options = {}) {
356
- return function(target, propertyKey) {
360
+ return controller_decorator.declaring(function(target, propertyKey) {
357
361
  controller_decorator.refuseOnMethod('@Interceptor', target, propertyKey);
358
362
  providers.makeInjectable(target);
359
363
  providers.defineStageTypes(target, options.types, 'Interceptor');
360
- };
364
+ });
361
365
  }
362
366
  /**
363
367
  * Runs interceptors around a handler, or around every handler of a controller.
@@ -388,9 +392,9 @@ require('chalk');
388
392
  * @group Decorators
389
393
  * @category Pipeline stages
390
394
  * @see {@link Interceptor}
391
- * @see {@link https://meocord.dev/docs/4.1/interceptors | Interceptors}
395
+ * @see {@link https://meocord.dev/docs/4.2/interceptors | Interceptors}
392
396
  */ function UseInterceptor(...interceptors) {
393
- return function(target, propertyKey) {
397
+ return controller_decorator.declaring(function(target, propertyKey) {
394
398
  const where = propertyKey === undefined ? target.name : `${target.constructor.name}.${String(propertyKey)}`;
395
399
  providers.assertStageEntries('@UseInterceptor', 'interceptor', where, interceptors);
396
400
  // Decorators apply bottom-up, so a higher decorator's interceptors go first, as with @UseGuard.
@@ -407,7 +411,7 @@ require('chalk');
407
411
  ...existing
408
412
  ], target, propertyKey);
409
413
  }
410
- };
414
+ });
411
415
  }
412
416
 
413
417
  /**
@@ -437,20 +441,20 @@ require('chalk');
437
441
  * @group Decorators
438
442
  * @category Pipeline stages
439
443
  * @see {@link UseFilter}
440
- * @see {@link https://meocord.dev/docs/4.1/exception-filters | Exception filters}
444
+ * @see {@link https://meocord.dev/docs/4.2/exception-filters | Exception filters}
441
445
  */ function Catch(...errorTypes) {
442
- return function(target, propertyKey) {
446
+ return controller_decorator.declaring(function(target, propertyKey) {
443
447
  controller_decorator.refuseOnMethod('@Catch', target, propertyKey);
444
448
  providers.makeInjectable(target);
445
449
  errorTypes.forEach((type, index)=>{
446
450
  if (controller_decorator.isConstructor(type)) return;
447
451
  const entry = ORDINALS[index] ? `${ORDINALS[index]} entry` : `entry ${index + 1}`;
448
- controller_decorator.warnDeprecatedBehaviour(logger, `${target.name}: @Catch's ${entry}, ${controller_decorator.describeValue(type)}, which matches no error,`, 'is refused', 'an error class, such as @Catch(CooldownError),');
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),');
449
453
  });
450
454
  Reflect.defineMetadata(controller_decorator.META.catchTypes, errorTypes, target);
451
- };
455
+ });
452
456
  }
453
- const logger = new controller_decorator.Logger('Catch');
457
+ const logger$1 = new controller_decorator.Logger('Catch');
454
458
  const ORDINALS = [
455
459
  'first',
456
460
  'second',
@@ -488,9 +492,9 @@ const ORDINALS = [
488
492
  * @group Decorators
489
493
  * @category Pipeline stages
490
494
  * @see {@link Catch}
491
- * @see {@link https://meocord.dev/docs/4.1/exception-filters | Exception filters}
495
+ * @see {@link https://meocord.dev/docs/4.2/exception-filters | Exception filters}
492
496
  */ function UseFilter(...filters) {
493
- return function(target, propertyKey) {
497
+ return controller_decorator.declaring(function(target, propertyKey) {
494
498
  const where = propertyKey === undefined ? target.name : `${target.constructor.name}.${String(propertyKey)}`;
495
499
  providers.assertStageEntries('@UseFilter', 'filter', where, filters);
496
500
  // Decorators apply bottom-up, so a higher decorator's filters are tried first.
@@ -507,7 +511,7 @@ const ORDINALS = [
507
511
  ...existing
508
512
  ], target, propertyKey);
509
513
  }
510
- };
514
+ });
511
515
  }
512
516
 
513
517
  /** Refuses a `messages` option of the wrong type where the app is declared, rather than at the first message. */ function assertMessageOptions(appName, messages, i18n) {
@@ -517,14 +521,19 @@ const ORDINALS = [
517
521
  if (prefix !== undefined && !isText(prefix) && typeof prefix !== 'function' && !(Array.isArray(prefix) && prefix.every(isText))) {
518
522
  throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ messages: { prefix } }) takes a string, a list of strings, or a function of the message returning them.`));
519
523
  }
520
- for (const [name, value] of Object.entries({
524
+ const flags = {
521
525
  caseSensitive,
522
526
  replyEmoji: messages.replyEmoji,
523
527
  dmOnError: messages.dmOnError,
524
- dmOnCooldown: messages.dmOnCooldown
525
- })){
528
+ dmOnCooldown: messages.dmOnCooldown,
529
+ slowHandlerWarning: messages.slowHandlerWarning
530
+ };
531
+ for (const [name, value] of Object.entries(flags)){
526
532
  if (value !== undefined && typeof value !== 'boolean') throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ messages: { ${name} } }) takes true or false.`));
527
533
  }
534
+ if (messages.handlers !== undefined && messages.handlers !== 'sequential' && messages.handlers !== 'concurrent') {
535
+ throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ messages: { handlers } }) takes 'sequential' or 'concurrent'.`));
536
+ }
528
537
  if (mention !== undefined && typeof mention !== 'boolean' && mention !== 'only') {
529
538
  throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ messages: { mention } }) takes true, false or 'only'.`));
530
539
  }
@@ -586,9 +595,9 @@ const ORDINALS = [
586
595
  * @see {@link MeoCordOptions}
587
596
  * @see {@link MeoCordFactory}
588
597
  * @see {@link MeoCordConfig}
589
- * @see {@link https://meocord.dev/docs/4.1/configuration | Configuration}
598
+ * @see {@link https://meocord.dev/docs/4.2/configuration | Configuration}
590
599
  */ function MeoCord(options) {
591
- return (target, propertyKey)=>{
600
+ return controller_decorator.declaring((target, propertyKey)=>{
592
601
  if (controller_decorator.deprecatedOnMethod('@MeoCord', target, propertyKey)) return;
593
602
  providers.assertStageEntries('@MeoCord({ guards })', 'guard', target.name, options.guards ?? []);
594
603
  providers.assertStageEntries('@MeoCord({ interceptors })', 'interceptor', target.name, options.interceptors ?? []);
@@ -610,7 +619,7 @@ const ORDINALS = [
610
619
  ...options,
611
620
  theme
612
621
  }, target);
613
- };
622
+ });
614
623
  }
615
624
  /** Refuses theme resolvers and cache options the runtime cannot follow, where the app is declared. */ function assertThemeFor(appName, { themeFor, themeCache, themeForTimeoutMs }) {
616
625
  const problem = themeFor === undefined ? undefined : controller_decorator.themeForProblem(themeFor, `${appName}: @MeoCord({ themeFor })`, 'or a class implementing ThemeResolver.');
@@ -678,9 +687,9 @@ const ORDINALS = [
678
687
  * @category Pipeline stages
679
688
  * @see {@link UsePipe}
680
689
  * @see {@link ValidationError}
681
- * @see {@link https://meocord.dev/docs/4.1/validation | Validation and pipes}
690
+ * @see {@link https://meocord.dev/docs/4.2/validation | Validation and pipes}
682
691
  */ function Validate(schema, options = {}) {
683
- return function(target, propertyKey, _descriptor) {
692
+ return controller_decorator.declaring(function(target, propertyKey, _descriptor) {
684
693
  controller_decorator.refuseOnClass('@Validate', target, propertyKey);
685
694
  // Checked where it applies, so the refusal names the handler
686
695
  if (typeof schema?.['~standard']?.validate !== 'function') {
@@ -698,7 +707,7 @@ const ORDINALS = [
698
707
  pipes: options.pipes ?? {}
699
708
  };
700
709
  Reflect.defineMetadata(controller_decorator.META.methodValidation, metadata, target, propertyKey);
701
- };
710
+ });
702
711
  }
703
712
  /**
704
713
  * Runs pipes on one value of a handler's input, to turn it into what the handler works with.
@@ -730,9 +739,9 @@ const ORDINALS = [
730
739
  * @category Pipeline stages
731
740
  * @see {@link Pipe}
732
741
  * @see {@link Validate}
733
- * @see {@link https://meocord.dev/docs/4.1/validation | Validation and pipes}
742
+ * @see {@link https://meocord.dev/docs/4.2/validation | Validation and pipes}
734
743
  */ function UsePipe(key, ...pipes) {
735
- return function(target, propertyKey, _descriptor) {
744
+ return controller_decorator.declaring(function(target, propertyKey, _descriptor) {
736
745
  controller_decorator.refuseOnClass('@UsePipe', target, propertyKey);
737
746
  providers.assertStageEntries('@UsePipe', 'pipe', `${target.constructor.name}.${propertyKey}`, pipes);
738
747
  // Decorators apply bottom-up, so a higher @UsePipe's pipes go first, in the order they read.
@@ -744,7 +753,7 @@ const ORDINALS = [
744
753
  })),
745
754
  ...existing
746
755
  ], target, propertyKey);
747
- };
756
+ });
748
757
  }
749
758
  /**
750
759
  * Marks a class as a pipe, which turns one input value into what the handler works with.
@@ -770,12 +779,12 @@ const ORDINALS = [
770
779
  * @group Decorators
771
780
  * @category Pipeline stages
772
781
  * @see {@link UsePipe}
773
- * @see {@link https://meocord.dev/docs/4.1/validation | Validation and pipes}
782
+ * @see {@link https://meocord.dev/docs/4.2/validation | Validation and pipes}
774
783
  */ function Pipe() {
775
- return function(target, propertyKey) {
784
+ return controller_decorator.declaring(function(target, propertyKey) {
776
785
  controller_decorator.refuseOnMethod('@Pipe', target, propertyKey);
777
786
  providers.makeInjectable(target);
778
- };
787
+ });
779
788
  }
780
789
 
781
790
  function Cooldown(options) {
@@ -786,10 +795,11 @@ function Cooldown(options) {
786
795
  per,
787
796
  windowMs: Math.round(seconds * 1000)
788
797
  };
789
- return function(target, propertyKey) {
798
+ return controller_decorator.declaring(function(target, propertyKey) {
790
799
  // Checked where it applies, so the refusal names the handler or controller
791
800
  const problem = cooldownProblem(seconds, uses, per, by);
792
801
  if (problem) throw controller_decorator.refuse(new Error(`${controller_decorator.decoratedName(target, propertyKey)}: ${problem}`));
802
+ for (const warning of cooldownWarnings(options))logger.warn(`${controller_decorator.decoratedName(target, propertyKey)}: ${warning}`);
793
803
  // Decorators apply bottom-up; prepending keeps them in the order they read.
794
804
  if (propertyKey === undefined) {
795
805
  const existing = Reflect.getOwnMetadata(controller_decorator.META.classCooldowns, target) ?? [];
@@ -804,12 +814,26 @@ function Cooldown(options) {
804
814
  ...existing
805
815
  ], target, propertyKey);
806
816
  }
807
- };
817
+ });
808
818
  }
809
819
  /**
810
820
  * The longest window, in seconds: half the furthest time a `Date` holds, 8.64e15 ms, so the moment a wait ends, now
811
821
  * plus the window, is a real date for a refusal's `retryAt` and the time it shows.
812
822
  */ const MAX_SECONDS = 4320000000000;
823
+ const logger = new controller_decorator.Logger('Cooldown');
824
+ /**
825
+ * What a cooldown's options get wrong that the types refuse, yet still counts: a `bypass` that is not a function, which
826
+ * fails every call, and a `seconds` that is not a number, read as one. A falsy `bypass` means none.
827
+ */ function cooldownWarnings({ seconds, bypass }) {
828
+ const warnings = [];
829
+ if (bypass && typeof bypass !== 'function') {
830
+ warnings.push(`@Cooldown takes bypass as a function of the call, returning whether the call skips the cooldown, not ${controller_decorator.describeValue(bypass)}; ` + 'every call it counts fails with it. In the next major version (5.0) it is refused.');
831
+ }
832
+ if (typeof seconds !== 'number') {
833
+ warnings.push(`@Cooldown takes seconds as a number, not ${controller_decorator.describeValue(seconds)}, which it counts as a window of ` + `${Math.round(seconds * 1000)} ms. In the next major version (5.0) it is refused.`);
834
+ }
835
+ return warnings;
836
+ }
813
837
  /** Why a cooldown's options cannot be counted, or undefined when they can. */ function cooldownProblem(seconds, uses, per, by) {
814
838
  if (!(seconds >= 0.001 && seconds <= MAX_SECONDS)) return `@Cooldown needs a number of seconds from 0.001 to ${MAX_SECONDS}, not ${seconds}.`;
815
839
  if (!Number.isInteger(uses) || uses < 1) return `@Cooldown needs a whole number of uses of at least 1, not ${uses}.`;
@@ -861,9 +885,9 @@ function Cooldown(options) {
861
885
  * @category Pipeline stages
862
886
  * @see {@link DeferOptions}
863
887
  * @see {@link respond}
864
- * @see {@link https://meocord.dev/docs/4.1/defer | Deferring}
888
+ * @see {@link https://meocord.dev/docs/4.2/defer | Deferring}
865
889
  */ function Defer(options = {}) {
866
- return (target, propertyKey)=>{
890
+ return controller_decorator.declaring((target, propertyKey)=>{
867
891
  controller_decorator.refuseOnClass('@Defer', target, propertyKey);
868
892
  const methodName = String(propertyKey);
869
893
  const kind = providers.nonInteractionHandler(target, methodName);
@@ -871,7 +895,7 @@ function Cooldown(options) {
871
895
  Reflect.defineMetadata(controller_decorator.META.deferOptions, {
872
896
  ...options
873
897
  }, target, methodName);
874
- };
898
+ });
875
899
  }
876
900
 
877
901
  /**
@@ -897,14 +921,14 @@ function Cooldown(options) {
897
921
  * @category Params
898
922
  * @see {@link Service}
899
923
  * @see {@link createToken}
900
- * @see {@link https://meocord.dev/docs/4.1/services | Services}
924
+ * @see {@link https://meocord.dev/docs/4.2/services | Services}
901
925
  */ function Inject(token) {
902
926
  const decorate = inversify.inject(token);
903
- return (target, propertyKey, parameterIndex)=>{
927
+ return controller_decorator.declaring((target, propertyKey, parameterIndex)=>{
904
928
  // A constructor parameter has no property key either, but has an index
905
929
  if (typeof parameterIndex !== 'number') controller_decorator.refuseOnClass('@Inject', target, propertyKey, 'a constructor parameter or a property');
906
930
  decorate(target, propertyKey, parameterIndex);
907
- };
931
+ });
908
932
  }
909
933
 
910
934
  /**
@@ -938,9 +962,9 @@ function Cooldown(options) {
938
962
  * @pipeline observers-settled once the call has settled and been answered, however it ended
939
963
  * @group Decorators
940
964
  * @category Pipeline stages
941
- * @see {@link https://meocord.dev/docs/4.1/observers | Observers}
965
+ * @see {@link https://meocord.dev/docs/4.2/observers | Observers}
942
966
  */ function Observer(options = {}) {
943
- return function(target, propertyKey) {
967
+ return controller_decorator.declaring(function(target, propertyKey) {
944
968
  controller_decorator.refuseOnMethod('@Observer', target, propertyKey);
945
969
  if (typeof target.prototype.onSettled !== 'function') {
946
970
  throw controller_decorator.refuse(new Error(`${target.name}: an @Observer needs an onSettled method, and it has none.`));
@@ -948,7 +972,7 @@ function Cooldown(options) {
948
972
  providers.makeInjectable(target);
949
973
  providers.defineStageTypes(target, options.types, 'Observer');
950
974
  Reflect.defineMetadata(controller_decorator.META.observerClass, true, target);
951
- };
975
+ });
952
976
  }
953
977
 
954
978
  /**
@@ -981,7 +1005,7 @@ function Cooldown(options) {
981
1005
  * @group Decorators
982
1006
  * @category Controllers
983
1007
  */ function UseTheme(theme) {
984
- return function(target, propertyKey) {
1008
+ return controller_decorator.declaring(function(target, propertyKey) {
985
1009
  const onClass = propertyKey === undefined;
986
1010
  const owner = onClass ? target : target.constructor;
987
1011
  const where = `${owner.name}${onClass ? '' : `.${String(propertyKey)}`}: @UseTheme`;
@@ -993,7 +1017,7 @@ function Cooldown(options) {
993
1017
  if (onClass) Reflect.defineMetadata(key, layer, target);
994
1018
  else Reflect.defineMetadata(key, layer, target, propertyKey);
995
1019
  providers.THEMED_CLASSES.add(owner);
996
- };
1020
+ });
997
1021
  }
998
1022
 
999
1023
  exports.On = providers.On;