meocord 4.2.1 → 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.
- package/CHANGELOG.md +188 -0
- package/dist/cjs/_shared/{controller.decorator-XKMlcUZz.cjs → controller.decorator-hp5xdJU4.cjs} +550 -189
- package/dist/cjs/_shared/{startup-roots-CgfPQrNl.cjs → event-sources-DzqTODXg.cjs} +274 -88
- package/dist/cjs/_shared/{providers-BZgJyfZS.cjs → providers-BBvbnmLP.cjs} +837 -295
- package/dist/cjs/_shared/{sharded-cooldown-store-CsJJyCZd.cjs → sharded-cooldown-store-B62g5O88.cjs} +11 -9
- package/dist/cjs/_shared/{translate-error-BUAR1WYG.cjs → translate-error-wsgfsUET.cjs} +1 -1
- package/dist/cjs/common/index.cjs +4 -104
- package/dist/cjs/core/index.cjs +435 -182
- package/dist/cjs/decorator/index.cjs +116 -121
- package/dist/cjs/testing/index.cjs +1923 -808
- package/dist/cli.json +1 -1
- package/dist/esm/bin/app-template/package.json.template +9 -9
- package/dist/esm/bin/app-template/src/main.ts.template +3 -2
- package/dist/esm/bin/generator.js +6 -4
- package/dist/esm/bin/helper/filter-generator.helper.js +6 -4
- package/dist/esm/bin/helper/guard-generator.helper.js +6 -4
- package/dist/esm/bin/helper/interceptor-generator.helper.js +6 -4
- package/dist/esm/bin/helper/observer-generator.helper.js +6 -4
- package/dist/esm/bin/helper/pipe-generator.helper.js +6 -4
- package/dist/esm/bin/helper/service-generator.helper.js +6 -4
- package/dist/esm/bin/meocord.js +106 -48
- package/dist/esm/build/native-addons.js +75 -19
- package/dist/esm/build/rsbuild-config.js +11 -3
- package/dist/esm/build/typed-externals.js +15 -2
- package/dist/esm/common/cooldown-store.js +38 -14
- package/dist/esm/common/deprecation.js +4 -1
- package/dist/esm/common/execution-context.js +3 -1
- package/dist/esm/common/explained-error.js +7 -3
- package/dist/esm/common/log-level.js +13 -9
- package/dist/esm/common/logger.js +4 -2
- package/dist/esm/common/meocord-text.js +11 -6
- package/dist/esm/common/redis-cooldown-store.js +3 -7
- package/dist/esm/common/response/flags.js +17 -1
- package/dist/esm/common/response/install-context.js +27 -16
- package/dist/esm/common/response/presenter.js +7 -3
- package/dist/esm/common/response/response-state.js +32 -10
- package/dist/esm/common/sharded-cooldown-store.js +11 -9
- package/dist/esm/common/theme.js +3 -1
- package/dist/esm/common/translator.js +27 -8
- package/dist/esm/core/autocomplete-routes.js +26 -0
- package/dist/esm/core/command-conflicts.js +15 -7
- package/dist/esm/core/command-registration.js +15 -1
- package/dist/esm/core/cooldown-runner.js +7 -9
- package/dist/esm/core/defer.js +2 -5
- package/dist/esm/core/dispatcher.js +92 -66
- package/dist/esm/core/event-requirements.js +67 -19
- package/dist/esm/core/event-sources.js +100 -0
- package/dist/esm/core/fallback.js +3 -1
- package/dist/esm/core/filter-runner.js +6 -6
- package/dist/esm/core/guard-runner.js +173 -52
- package/dist/esm/core/handler-input.js +24 -3
- package/dist/esm/core/handler-pipeline.js +54 -32
- package/dist/esm/core/handler-registry.js +51 -21
- package/dist/esm/core/input-runner.js +7 -8
- package/dist/esm/core/interceptor-runner.js +4 -5
- package/dist/esm/core/lifecycle-hooks.js +3 -8
- package/dist/esm/core/lifecycle-order.js +1 -15
- package/dist/esm/core/meocord-classes.js +14 -1
- package/dist/esm/core/meocord-factory.js +83 -54
- package/dist/esm/core/meocord.app.js +174 -89
- package/dist/esm/core/message-help.js +37 -15
- package/dist/esm/core/message-params.js +126 -46
- package/dist/esm/core/message-routes.js +225 -45
- package/dist/esm/core/message-words.js +30 -2
- package/dist/esm/core/observer-runner.js +4 -2
- package/dist/esm/core/process-state.js +19 -0
- package/dist/esm/core/providers.js +39 -4
- package/dist/esm/core/scalar-types.js +57 -16
- package/dist/esm/core/shard-context.js +11 -10
- package/dist/esm/core/shard-exit.js +3 -3
- package/dist/esm/core/shard-manager.js +16 -6
- package/dist/esm/core/stage-scope.js +2 -1
- package/dist/esm/core/startup-roots.js +28 -8
- package/dist/esm/core/theme-resolvers.js +26 -11
- package/dist/esm/core/theme-runtime.js +23 -13
- package/dist/esm/core/theme-scope.js +31 -30
- package/dist/esm/core/theme-validation.js +1 -1
- package/dist/esm/decorator/app.decorator.js +37 -1
- package/dist/esm/decorator/command-builder.decorator.js +14 -0
- package/dist/esm/decorator/controller-class.decorator.js +1 -1
- package/dist/esm/decorator/controller.decorator.js +48 -19
- package/dist/esm/decorator/defer.decorator.js +2 -2
- package/dist/esm/decorator/event.decorator.js +4 -5
- package/dist/esm/decorator/filter.decorator.js +4 -4
- package/dist/esm/decorator/guard.decorator.js +4 -61
- package/dist/esm/decorator/inject.decorator.js +4 -1
- package/dist/esm/decorator/interceptor.decorator.js +2 -2
- package/dist/esm/decorator/theme.decorator.js +4 -3
- package/dist/esm/decorator/validation.decorator.js +5 -5
- package/dist/esm/package.json.js +1 -1
- package/dist/esm/testing/catalog.js +32 -25
- package/dist/esm/testing/cooldown-store-suite.js +3 -3
- package/dist/esm/testing/discord-defaults.js +449 -335
- package/dist/esm/testing/inspect-handler.js +91 -10
- package/dist/esm/testing/meocord-testing-module.js +217 -91
- package/dist/esm/testing/mock-fn.js +8 -2
- package/dist/esm/testing/mock-interaction.js +864 -124
- package/dist/esm/testing/response-log.js +8 -0
- package/dist/esm/testing/response.js +7 -5
- package/dist/esm/testing/routing.js +48 -6
- package/dist/esm/testing/strict-mocks.js +8 -4
- package/dist/esm/testing/theme.js +3 -2
- package/dist/esm/util/common.util.js +30 -9
- package/dist/esm/util/generator-cli.util.js +6 -4
- package/dist/esm/util/inherited-env.util.js +72 -13
- package/dist/esm/util/json.util.js +10 -3
- package/dist/esm/util/meocord-cli.util.js +3 -2
- package/dist/esm/util/meocord-config-loader.util.js +14 -1
- package/dist/esm/util/meocord-config-validation.util.js +13 -3
- package/dist/esm/util/meocord-source-config.util.js +13 -3
- package/dist/esm/util/platform.util.js +3 -2
- package/dist/esm/util/refusal.util.js +29 -11
- package/dist/esm/util/registration-mode.util.js +14 -1
- package/dist/esm/util/timer-limit.util.js +4 -1
- package/dist/esm/util/tsconfig-paths.util.js +38 -7
- package/dist/esm/util/tsconfig.util.js +16 -58
- package/dist/esm/util/user-text.util.js +8 -4
- package/dist/esm/util/value.util.js +33 -5
- package/dist/types/common/index.d.cts +17 -10
- package/dist/types/common/index.d.ts +17 -10
- package/dist/types/core/index.d.cts +21 -11
- package/dist/types/core/index.d.ts +21 -11
- package/dist/types/decorator/index.d.cts +63 -63
- package/dist/types/decorator/index.d.ts +63 -63
- package/dist/types/{index-DKJclIi-.d.ts → index-Brkd6QGL.d.ts} +81 -35
- package/dist/types/{index-Dlf0ZZtS.d.cts → index-CqXImwF_.d.cts} +81 -35
- package/dist/types/interface/index.d.cts +1 -1
- package/dist/types/interface/index.d.ts +1 -1
- package/dist/types/{route-Bh1U13yy.d.ts → route-IQrK-MN2.d.cts} +11 -3
- package/dist/types/{route-Bh1U13yy.d.cts → route-bI-okq7g.d.ts} +11 -3
- package/dist/types/testing/index.d.cts +158 -61
- package/dist/types/testing/index.d.ts +158 -61
- package/dist/types/{theme-resolvers-CyEz9pnv.d.cts → theme-resolvers-AtgeaYqF.d.cts} +1 -1
- package/dist/types/{theme-resolvers-DA204O-q.d.ts → theme-resolvers-BgqysV8d.d.ts} +1 -1
- package/dist/types/{translator-Bg7hwxDF.d.cts → translator-D8aydlCE.d.ts} +12 -11
- package/dist/types/{translator-CeP4bCzp.d.ts → translator-iJhDlgwL.d.cts} +12 -11
- 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-
|
|
5
|
-
var controller_decorator = require('../_shared/controller.decorator-
|
|
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
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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 =
|
|
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 =
|
|
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) {
|
|
@@ -447,14 +404,14 @@ require('chalk');
|
|
|
447
404
|
controller_decorator.refuseOnMethod('@Catch', target, propertyKey);
|
|
448
405
|
providers.makeInjectable(target);
|
|
449
406
|
errorTypes.forEach((type, index)=>{
|
|
450
|
-
if (controller_decorator.
|
|
407
|
+
if (controller_decorator.isConstructible(type)) return;
|
|
451
408
|
const entry = ORDINALS[index] ? `${ORDINALS[index]} entry` : `entry ${index + 1}`;
|
|
452
|
-
controller_decorator.warnDeprecatedBehaviour(logger$
|
|
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$
|
|
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 =
|
|
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);
|
|
@@ -555,6 +516,35 @@ const ORDINALS = [
|
|
|
555
516
|
if (type.labelKey !== undefined) assertLabelKey(appName, name, type.labelKey, i18n);
|
|
556
517
|
}
|
|
557
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* Refuses an option that takes a class given anything else, such as an object or an arrow function, where the app is
|
|
521
|
+
* declared: the startup checks read each class's prototype, and would otherwise fail on it without naming the option.
|
|
522
|
+
*/ function assertClassOptions(appName, { presenter, cooldownStore, controllers, services }) {
|
|
523
|
+
for (const [name, value, implementing] of [
|
|
524
|
+
[
|
|
525
|
+
'presenter',
|
|
526
|
+
presenter,
|
|
527
|
+
'ResponsePresenter'
|
|
528
|
+
],
|
|
529
|
+
[
|
|
530
|
+
'cooldownStore',
|
|
531
|
+
cooldownStore,
|
|
532
|
+
'CooldownStore'
|
|
533
|
+
]
|
|
534
|
+
]){
|
|
535
|
+
if (value !== undefined && !controller_decorator.isConstructor(value)) {
|
|
536
|
+
throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ ${name} }) takes a class implementing ${implementing}, not ${controller_decorator.describeValue(value)}.`));
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
for (const controller of controllers ?? []){
|
|
540
|
+
if (!controller_decorator.isConstructor(controller)) throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ controllers }) takes classes, not ${controller_decorator.describeValue(controller)}.`));
|
|
541
|
+
}
|
|
542
|
+
// A string or symbol is a token, which a provider has to provide; that is checked as the app is created
|
|
543
|
+
for (const service of services ?? []){
|
|
544
|
+
if (controller_decorator.isConstructor(service) || typeof service === 'string' || typeof service === 'symbol') continue;
|
|
545
|
+
throw controller_decorator.refuse(new TypeError(`${appName}: @MeoCord({ services }) takes classes, or tokens that providers provide, not ${controller_decorator.describeValue(service)}.`));
|
|
546
|
+
}
|
|
547
|
+
}
|
|
558
548
|
/** 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
549
|
const where = `${appName}: @MeoCord({ messages: { types } }): "${name}" has labelKey`;
|
|
560
550
|
if (typeof labelKey !== 'string') throw controller_decorator.refuse(new TypeError(`${where} ${String(labelKey)}; it takes a message key, such as 'types.${name}'.`));
|
|
@@ -599,6 +589,7 @@ const ORDINALS = [
|
|
|
599
589
|
*/ function MeoCord(options) {
|
|
600
590
|
return controller_decorator.declaring((target, propertyKey)=>{
|
|
601
591
|
if (controller_decorator.deprecatedOnMethod('@MeoCord', target, propertyKey)) return;
|
|
592
|
+
assertClassOptions(target.name, options);
|
|
602
593
|
providers.assertStageEntries('@MeoCord({ guards })', 'guard', target.name, options.guards ?? []);
|
|
603
594
|
providers.assertStageEntries('@MeoCord({ interceptors })', 'interceptor', target.name, options.interceptors ?? []);
|
|
604
595
|
providers.assertStageEntries('@MeoCord({ filters })', 'filter', target.name, options.filters ?? []);
|
|
@@ -693,15 +684,15 @@ const ORDINALS = [
|
|
|
693
684
|
controller_decorator.refuseOnClass('@Validate', target, propertyKey);
|
|
694
685
|
// Checked where it applies, so the refusal names the handler
|
|
695
686
|
if (typeof schema?.['~standard']?.validate !== 'function') {
|
|
696
|
-
throw controller_decorator.refuse(new Error(`${target
|
|
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.`));
|
|
697
688
|
}
|
|
698
689
|
if (Reflect.hasOwnMetadata(controller_decorator.META.methodValidation, target, propertyKey)) {
|
|
699
|
-
throw controller_decorator.refuse(new Error(`${target
|
|
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.`));
|
|
700
691
|
}
|
|
701
692
|
const inlinePipes = Object.values(options.pipes ?? {}).flatMap((entries)=>Array.isArray(entries) ? entries : [
|
|
702
693
|
entries
|
|
703
694
|
]);
|
|
704
|
-
providers.assertStageEntries('@Validate', 'pipe',
|
|
695
|
+
providers.assertStageEntries('@Validate', 'pipe', controller_decorator.decoratedName(target, propertyKey), inlinePipes);
|
|
705
696
|
const metadata = {
|
|
706
697
|
schema,
|
|
707
698
|
pipes: options.pipes ?? {}
|
|
@@ -743,7 +734,7 @@ const ORDINALS = [
|
|
|
743
734
|
*/ function UsePipe(key, ...pipes) {
|
|
744
735
|
return controller_decorator.declaring(function(target, propertyKey, _descriptor) {
|
|
745
736
|
controller_decorator.refuseOnClass('@UsePipe', target, propertyKey);
|
|
746
|
-
providers.assertStageEntries('@UsePipe', 'pipe',
|
|
737
|
+
providers.assertStageEntries('@UsePipe', 'pipe', controller_decorator.decoratedName(target, propertyKey), pipes);
|
|
747
738
|
// Decorators apply bottom-up, so a higher @UsePipe's pipes go first, in the order they read.
|
|
748
739
|
const existing = Reflect.getOwnMetadata(controller_decorator.META.methodPipes, target, propertyKey) ?? [];
|
|
749
740
|
Reflect.defineMetadata(controller_decorator.META.methodPipes, [
|
|
@@ -891,7 +882,7 @@ const logger = new controller_decorator.Logger('Cooldown');
|
|
|
891
882
|
controller_decorator.refuseOnClass('@Defer', target, propertyKey);
|
|
892
883
|
const methodName = String(propertyKey);
|
|
893
884
|
const kind = providers.nonInteractionHandler(target, methodName);
|
|
894
|
-
if (kind) throw controller_decorator.refuse(providers.deferMisuseError(target
|
|
885
|
+
if (kind) throw controller_decorator.refuse(providers.deferMisuseError(controller_decorator.ownerName(target), methodName, kind));
|
|
895
886
|
Reflect.defineMetadata(controller_decorator.META.deferOptions, {
|
|
896
887
|
...options
|
|
897
888
|
}, target, methodName);
|
|
@@ -927,6 +918,9 @@ const logger = new controller_decorator.Logger('Cooldown');
|
|
|
927
918
|
return controller_decorator.declaring((target, propertyKey, parameterIndex)=>{
|
|
928
919
|
// A constructor parameter has no property key either, but has an index
|
|
929
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
|
+
}
|
|
930
924
|
decorate(target, propertyKey, parameterIndex);
|
|
931
925
|
});
|
|
932
926
|
}
|
|
@@ -1007,8 +1001,9 @@ const logger = new controller_decorator.Logger('Cooldown');
|
|
|
1007
1001
|
*/ function UseTheme(theme) {
|
|
1008
1002
|
return controller_decorator.declaring(function(target, propertyKey) {
|
|
1009
1003
|
const onClass = propertyKey === undefined;
|
|
1010
|
-
|
|
1011
|
-
const
|
|
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`;
|
|
1012
1007
|
controller_decorator.assertValidTheme(theme, where);
|
|
1013
1008
|
const key = onClass ? controller_decorator.META.classTheme : controller_decorator.META.methodTheme;
|
|
1014
1009
|
const existing = onClass ? Reflect.getOwnMetadata(key, target) : Reflect.getOwnMetadata(key, target, propertyKey);
|