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.
- package/CHANGELOG.md +362 -0
- package/THIRD_PARTY_NOTICES.md +14 -13
- package/dist/cjs/_shared/{controller.decorator-BywwkU9O.cjs → controller.decorator-XKMlcUZz.cjs} +669 -185
- package/dist/cjs/_shared/{providers-BMMLp2SN.cjs → providers-BZgJyfZS.cjs} +218 -75
- package/dist/cjs/_shared/{sharded-cooldown-store-B65iaiAy.cjs → sharded-cooldown-store-CsJJyCZd.cjs} +10 -7
- package/dist/cjs/_shared/{startup-roots-lFc69AxC.cjs → startup-roots-CgfPQrNl.cjs} +374 -132
- package/dist/cjs/_shared/{translate-error-BnM8FbSH.cjs → translate-error-BUAR1WYG.cjs} +21 -7
- package/dist/cjs/common/index.cjs +4 -4
- package/dist/cjs/core/index.cjs +365 -310
- package/dist/cjs/decorator/index.cjs +85 -61
- package/dist/cjs/testing/index.cjs +2236 -496
- package/dist/cli.json +1 -1
- package/dist/esm/bin/app-template/README.md.template +3 -1
- package/dist/esm/bin/app-template/src/controllers/button/sample.button.controller.spec.ts.template +8 -4
- package/dist/esm/bin/app-template/src/controllers/button/sample.button.controller.ts.template +2 -2
- package/dist/esm/bin/app-template/src/guards/owner.guard.spec.ts.template +8 -4
- package/dist/esm/bin/app-template/src/guards/owner.guard.ts.template +1 -1
- package/dist/esm/bin/app-template/vitest.config.ts.template +1 -1
- package/dist/esm/bin/app-template/vitest.setup.ts.template +7 -3
- package/dist/esm/bin/generator.js +4 -5
- package/dist/esm/bin/helper/filter-generator.helper.js +4 -5
- package/dist/esm/bin/helper/guard-generator.helper.js +4 -5
- package/dist/esm/bin/helper/interceptor-generator.helper.js +4 -5
- package/dist/esm/bin/helper/observer-generator.helper.js +4 -5
- package/dist/esm/bin/helper/pipe-generator.helper.js +4 -5
- package/dist/esm/bin/helper/service-generator.helper.js +4 -5
- package/dist/esm/bin/meocord.js +84 -25
- package/dist/esm/build/load-config.pre-entry.js +17 -4
- package/dist/esm/build/rsbuild-config.js +16 -12
- package/dist/esm/build/typed-externals.js +36 -0
- package/dist/esm/common/cooldown-store.js +10 -2
- package/dist/esm/common/decorator.js +6 -6
- package/dist/esm/common/deprecation.js +2 -2
- package/dist/esm/common/errors.js +27 -2
- package/dist/esm/common/execution-context.js +1 -1
- package/dist/esm/common/meocord-text.js +11 -8
- package/dist/esm/common/metadata.js +1 -1
- package/dist/esm/common/response/call-order.js +9 -4
- package/dist/esm/common/response/presenter.js +33 -6
- package/dist/esm/common/response/response-state.js +84 -10
- package/dist/esm/common/route.js +21 -5
- package/dist/esm/common/sharded-cooldown-store.js +1 -1
- package/dist/esm/common/translate-error.js +1 -1
- package/dist/esm/common/translator.js +37 -6
- package/dist/esm/core/command-conflicts.js +34 -34
- package/dist/esm/core/command-registration.js +93 -24
- package/dist/esm/core/command-routes.js +2 -2
- package/dist/esm/core/component-routes.js +74 -31
- package/dist/esm/core/cooldown-runner.js +29 -8
- package/dist/esm/core/dispatcher.js +51 -7
- package/dist/esm/core/fallback.js +20 -11
- package/dist/esm/core/filter-runner.js +2 -2
- package/dist/esm/core/guard-runner.js +16 -3
- package/dist/esm/core/handler-input.js +4 -3
- package/dist/esm/core/handler-pipeline.js +27 -14
- package/dist/esm/core/handler-registry.js +1 -1
- package/dist/esm/core/interceptor-runner.js +2 -2
- package/dist/esm/core/lifecycle-hooks.js +134 -47
- package/dist/esm/core/meocord-factory.js +241 -179
- package/dist/esm/core/meocord.app.js +116 -75
- package/dist/esm/core/message-routes.js +4 -3
- package/dist/esm/core/observer-runner.js +4 -3
- package/dist/esm/core/providers.js +45 -23
- package/dist/esm/core/route-specificity.js +4 -4
- package/dist/esm/core/running-calls.js +43 -0
- package/dist/esm/core/scalar-types.js +15 -3
- package/dist/esm/core/shard-context.js +6 -7
- package/dist/esm/core/shard-manager.js +16 -10
- package/dist/esm/core/startup-roots.js +23 -4
- package/dist/esm/core/theme-resolvers.js +4 -1
- package/dist/esm/core/theme-runtime.js +2 -2
- package/dist/esm/core/theme-scope.js +3 -1
- package/dist/esm/core/theme-validation.js +17 -10
- package/dist/esm/decorator/app.decorator.js +12 -7
- package/dist/esm/decorator/command-builder.decorator.js +4 -4
- package/dist/esm/decorator/controller-class.decorator.js +9 -4
- package/dist/esm/decorator/controller.decorator.js +162 -83
- package/dist/esm/decorator/cooldown.decorator.js +20 -3
- package/dist/esm/decorator/defer.decorator.js +4 -4
- package/dist/esm/decorator/event.decorator.js +5 -5
- package/dist/esm/decorator/filter.decorator.js +7 -7
- package/dist/esm/decorator/guard.decorator.js +11 -10
- package/dist/esm/decorator/inject.decorator.js +4 -4
- package/dist/esm/decorator/interceptor.decorator.js +7 -7
- package/dist/esm/decorator/observer.decorator.js +4 -4
- package/dist/esm/decorator/service.decorator.js +4 -4
- package/dist/esm/decorator/theme.decorator.js +3 -3
- package/dist/esm/decorator/validation.decorator.js +10 -10
- package/dist/esm/package.json.js +1 -1
- package/dist/esm/testing/catalog.js +27 -11
- package/dist/esm/testing/cooldown-store-suite.js +85 -15
- package/dist/esm/testing/discord-defaults.js +249 -21
- package/dist/esm/testing/index.js +4 -2
- package/dist/esm/testing/inspect-handler.js +20 -3
- package/dist/esm/testing/meocord-testing-module.js +352 -205
- package/dist/esm/testing/mock-fn.js +173 -22
- package/dist/esm/testing/mock-interaction.js +1214 -209
- package/dist/esm/testing/response.js +1 -1
- package/dist/esm/testing/routing.js +39 -14
- package/dist/esm/testing/snowflake.js +9 -2
- package/dist/esm/testing/startup-errors.js +26 -0
- package/dist/esm/testing/strict-mocks.js +65 -0
- package/dist/esm/testing/theme.js +1 -1
- package/dist/esm/util/bundle-entry.util.js +2 -1
- package/dist/esm/util/common.util.js +47 -19
- package/dist/esm/util/dev-runner.util.js +8 -8
- package/dist/esm/util/generator-cli.util.js +4 -5
- package/dist/esm/util/interaction.util.js +3 -3
- package/dist/esm/util/meocord-config-loader.util.js +10 -2
- package/dist/esm/util/meocord-config-validation.util.js +4 -5
- package/dist/esm/util/meocord-source-config.util.js +65 -20
- package/dist/esm/util/metadata-keys.js +1 -0
- package/dist/esm/util/method-wrapper.util.js +16 -0
- package/dist/esm/util/platform.util.js +10 -10
- package/dist/esm/util/refusal.util.js +148 -8
- package/dist/esm/util/shard-process.util.js +4 -1
- package/dist/esm/util/sharding-mode.util.js +5 -7
- package/dist/esm/util/shared-state.util.js +21 -0
- package/dist/esm/util/tsconfig-paths.util.js +29 -0
- package/dist/esm/util/tsconfig.util.js +10 -10
- package/dist/esm/util/value.util.js +12 -1
- package/dist/types/common/index.d.cts +8 -8
- package/dist/types/common/index.d.ts +8 -8
- package/dist/types/core/index.d.cts +10 -7
- package/dist/types/core/index.d.ts +10 -7
- package/dist/types/decorator/index.d.cts +31 -29
- package/dist/types/decorator/index.d.ts +31 -29
- package/dist/types/{index-D7n0FBMm.d.ts → index-DKJclIi-.d.ts} +107 -36
- package/dist/types/{index-DEP0NYrU.d.cts → index-Dlf0ZZtS.d.cts} +107 -36
- package/dist/types/interface/index.d.cts +1 -1
- package/dist/types/interface/index.d.ts +1 -1
- package/dist/types/{route-C-aMI7Sl.d.cts → route-Bh1U13yy.d.cts} +8 -4
- package/dist/types/{route-C-aMI7Sl.d.ts → route-Bh1U13yy.d.ts} +8 -4
- package/dist/types/testing/index.d.cts +406 -70
- package/dist/types/testing/index.d.ts +406 -70
- package/dist/types/{theme-resolvers-COHdX5g6.d.cts → theme-resolvers-CyEz9pnv.d.cts} +1 -1
- package/dist/types/{theme-resolvers-DedxyscT.d.ts → theme-resolvers-DA204O-q.d.ts} +1 -1
- package/dist/types/{translator-J6tIUfdp.d.ts → translator-Bg7hwxDF.d.cts} +21 -8
- package/dist/types/{translator-B4mc1lzJ.d.cts → translator-CeP4bCzp.d.ts} +21 -8
- 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-
|
|
5
|
-
var controller_decorator = require('../_shared/controller.decorator-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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;
|