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
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('reflect-metadata');
4
- var providers = require('../_shared/providers-ChvMqnLd.cjs');
5
- var controller_decorator = require('../_shared/controller.decorator-CRn9kWob.cjs');
4
+ var providers = require('../_shared/providers-B4MOFBrW.cjs');
5
+ var controller_decorator = require('../_shared/controller.decorator-U2NBWcoU.cjs');
6
6
  var inversify = require('inversify');
7
7
  require('node:async_hooks');
8
8
  require('../enum/index.cjs');
@@ -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
  }
@@ -447,14 +447,14 @@ require('chalk');
447
447
  controller_decorator.refuseOnMethod('@Catch', target, propertyKey);
448
448
  providers.makeInjectable(target);
449
449
  errorTypes.forEach((type, index)=>{
450
- if (controller_decorator.isConstructor(type)) return;
450
+ if (controller_decorator.isConstructible(type)) return;
451
451
  const entry = ORDINALS[index] ? `${ORDINALS[index]} entry` : `entry ${index + 1}`;
452
- 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),');
453
453
  });
454
454
  Reflect.defineMetadata(controller_decorator.META.catchTypes, errorTypes, target);
455
455
  });
456
456
  }
457
- const logger = new controller_decorator.Logger('Catch');
457
+ const logger$1 = new controller_decorator.Logger('Catch');
458
458
  const ORDINALS = [
459
459
  'first',
460
460
  'second',
@@ -555,6 +555,35 @@ const ORDINALS = [
555
555
  if (type.labelKey !== undefined) assertLabelKey(appName, name, type.labelKey, i18n);
556
556
  }
557
557
  }
558
+ /**
559
+ * Refuses an option that takes a class given anything else, such as an object or an arrow function, where the app is
560
+ * declared: the startup checks read each class's prototype, and would otherwise fail on it without naming the option.
561
+ */ function assertClassOptions(appName, { presenter, cooldownStore, controllers, services }) {
562
+ for (const [name, value, implementing] of [
563
+ [
564
+ 'presenter',
565
+ presenter,
566
+ 'ResponsePresenter'
567
+ ],
568
+ [
569
+ 'cooldownStore',
570
+ cooldownStore,
571
+ 'CooldownStore'
572
+ ]
573
+ ]){
574
+ if (value !== undefined && !controller_decorator.isConstructor(value)) {
575
+ throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ ${name} }) takes a class implementing ${implementing}, not ${controller_decorator.describeValue(value)}.`));
576
+ }
577
+ }
578
+ for (const controller of controllers ?? []){
579
+ if (!controller_decorator.isConstructor(controller)) throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ controllers }) takes classes, not ${controller_decorator.describeValue(controller)}.`));
580
+ }
581
+ // A string or symbol is a token, which a provider has to provide; that is checked as the app is created
582
+ for (const service of services ?? []){
583
+ if (controller_decorator.isConstructor(service) || typeof service === 'string' || typeof service === 'symbol') continue;
584
+ throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ services }) takes classes, or tokens that providers provide, not ${controller_decorator.describeValue(service)}.`));
585
+ }
586
+ }
558
587
  /** Refuses a type's `labelKey` that no message of the app's default catalog has, as it would be shown as the key. */ function assertLabelKey(appName, name, labelKey, i18n) {
559
588
  const where = `${appName}: @MeoCord({ messages: { types } }): "${name}" has labelKey`;
560
589
  if (typeof labelKey !== 'string') throw controller_decorator.refuse(new TypeError(`${where} ${String(labelKey)}; it takes a message key, such as 'types.${name}'.`));
@@ -599,6 +628,7 @@ const ORDINALS = [
599
628
  */ function MeoCord(options) {
600
629
  return controller_decorator.declaring((target, propertyKey)=>{
601
630
  if (controller_decorator.deprecatedOnMethod('@MeoCord', target, propertyKey)) return;
631
+ assertClassOptions(target.name, options);
602
632
  providers.assertStageEntries('@MeoCord({ guards })', 'guard', target.name, options.guards ?? []);
603
633
  providers.assertStageEntries('@MeoCord({ interceptors })', 'interceptor', target.name, options.interceptors ?? []);
604
634
  providers.assertStageEntries('@MeoCord({ filters })', 'filter', target.name, options.filters ?? []);
@@ -799,6 +829,7 @@ function Cooldown(options) {
799
829
  // Checked where it applies, so the refusal names the handler or controller
800
830
  const problem = cooldownProblem(seconds, uses, per, by);
801
831
  if (problem) throw controller_decorator.refuse(new Error(`${controller_decorator.decoratedName(target, propertyKey)}: ${problem}`));
832
+ for (const warning of cooldownWarnings(options))logger.warn(`${controller_decorator.decoratedName(target, propertyKey)}: ${warning}`);
802
833
  // Decorators apply bottom-up; prepending keeps them in the order they read.
803
834
  if (propertyKey === undefined) {
804
835
  const existing = Reflect.getOwnMetadata(controller_decorator.META.classCooldowns, target) ?? [];
@@ -819,6 +850,20 @@ function Cooldown(options) {
819
850
  * The longest window, in seconds: half the furthest time a `Date` holds, 8.64e15 ms, so the moment a wait ends, now
820
851
  * plus the window, is a real date for a refusal's `retryAt` and the time it shows.
821
852
  */ const MAX_SECONDS = 4320000000000;
853
+ const logger = new controller_decorator.Logger('Cooldown');
854
+ /**
855
+ * What a cooldown's options get wrong that the types refuse, yet still counts: a `bypass` that is not a function, which
856
+ * fails every call, and a `seconds` that is not a number, read as one. A falsy `bypass` means none.
857
+ */ function cooldownWarnings({ seconds, bypass }) {
858
+ const warnings = [];
859
+ if (bypass && typeof bypass !== 'function') {
860
+ 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.');
861
+ }
862
+ if (typeof seconds !== 'number') {
863
+ 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.`);
864
+ }
865
+ return warnings;
866
+ }
822
867
  /** Why a cooldown's options cannot be counted, or undefined when they can. */ function cooldownProblem(seconds, uses, per, by) {
823
868
  if (!(seconds >= 0.001 && seconds <= MAX_SECONDS)) return `@Cooldown needs a number of seconds from 0.001 to ${MAX_SECONDS}, not ${seconds}.`;
824
869
  if (!Number.isInteger(uses) || uses < 1) return `@Cooldown needs a whole number of uses of at least 1, not ${uses}.`;