meocord 4.2.2 → 4.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +130 -0
- package/dist/cjs/_shared/{controller.decorator-U2NBWcoU.cjs → controller.decorator-hp5xdJU4.cjs} +512 -183
- package/dist/cjs/_shared/{startup-roots-lA5xkBFq.cjs → event-sources-DzqTODXg.cjs} +265 -80
- package/dist/cjs/_shared/{providers-B4MOFBrW.cjs → providers-BBvbnmLP.cjs} +780 -281
- package/dist/cjs/_shared/{sharded-cooldown-store-HTUb3Ii_.cjs → sharded-cooldown-store-B62g5O88.cjs} +11 -9
- package/dist/cjs/_shared/{translate-error-CbBHUu5P.cjs → translate-error-wsgfsUET.cjs} +1 -1
- package/dist/cjs/common/index.cjs +4 -104
- package/dist/cjs/core/index.cjs +432 -181
- package/dist/cjs/decorator/index.cjs +85 -120
- package/dist/cjs/testing/index.cjs +1664 -784
- 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 +27 -5
- package/dist/esm/common/sharded-cooldown-store.js +11 -9
- package/dist/esm/common/theme.js +3 -1
- package/dist/esm/common/translator.js +17 -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 +83 -58
- 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 +4 -4
- 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 +44 -28
- 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 +80 -53
- package/dist/esm/core/meocord.app.js +174 -89
- package/dist/esm/core/message-help.js +5 -9
- 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 +2 -1
- package/dist/esm/core/process-state.js +19 -0
- package/dist/esm/core/providers.js +28 -3
- 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/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 +27 -29
- package/dist/esm/core/theme-validation.js +1 -1
- package/dist/esm/decorator/app.decorator.js +6 -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 +2 -2
- 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 +29 -13
- package/dist/esm/testing/cooldown-store-suite.js +3 -3
- package/dist/esm/testing/discord-defaults.js +449 -355
- package/dist/esm/testing/inspect-handler.js +91 -10
- package/dist/esm/testing/meocord-testing-module.js +195 -77
- package/dist/esm/testing/mock-fn.js +8 -2
- package/dist/esm/testing/mock-interaction.js +639 -113
- 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 +1 -0
- 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 +15 -4
- package/dist/types/common/index.d.cts +13 -9
- package/dist/types/common/index.d.ts +13 -9
- 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 +137 -54
- package/dist/types/testing/index.d.ts +137 -54
- 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,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var discord_js = require('discord.js');
|
|
4
|
-
var controller_decorator = require('./controller.decorator-
|
|
5
|
-
var providers = require('./providers-
|
|
4
|
+
var controller_decorator = require('./controller.decorator-hp5xdJU4.cjs');
|
|
5
|
+
var providers = require('./providers-BBvbnmLP.cjs');
|
|
6
6
|
var enum_index = require('../enum/index.cjs');
|
|
7
7
|
var node_async_hooks = require('node:async_hooks');
|
|
8
|
-
var translateError = require('./translate-error-
|
|
8
|
+
var translateError = require('./translate-error-wsgfsUET.cjs');
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* How a pattern ranks, one character per segment twice over: `L` for literal text or `P` for a param, then how narrow
|
|
@@ -392,9 +392,9 @@ const quoted = (names)=>names.length < 2 ? names.map((name)=>`"${name}"`).join('
|
|
|
392
392
|
}
|
|
393
393
|
/**
|
|
394
394
|
* Warns about a handler a subclass re-declares on other routes while it still answers the ones it inherits, for
|
|
395
|
-
* `@Command`, `@MessageHandler`, `@ReactionHandler` and `@
|
|
396
|
-
* the inherited routes. Every class a listed controller extends is checked, a base that is not listed
|
|
397
|
-
* the methods the controller still inherits through it.
|
|
395
|
+
* `@Command`, `@MessageHandler`, `@ReactionHandler`, `@Autocomplete`, `@On` and `@Once` alike. The next major version
|
|
396
|
+
* (5.0) drops the inherited routes. Every class a listed controller extends is checked, a base that is not listed
|
|
397
|
+
* included, for the methods the controller still inherits through it.
|
|
398
398
|
*/ function warnInheritedRoutes(controllerClasses) {
|
|
399
399
|
// A set, so a class two listed controllers extend is named once, for the routes either of them still answers
|
|
400
400
|
const problems = new Set();
|
|
@@ -403,11 +403,18 @@ const quoted = (names)=>names.length < 2 ? names.map((name)=>`"${name}"`).join('
|
|
|
403
403
|
// nothing of them from above it, so a class above is not named for them
|
|
404
404
|
const cut = new Set();
|
|
405
405
|
for(let prototype = controllerClass.prototype; prototype && prototype !== Object.prototype; prototype = Object.getPrototypeOf(prototype)){
|
|
406
|
-
const declared = controller_decorator.getDeclaredRoutes(prototype);
|
|
407
406
|
const base = Object.getPrototypeOf(prototype);
|
|
408
|
-
if (
|
|
407
|
+
if (!base) continue;
|
|
408
|
+
const declared = [
|
|
409
|
+
...controller_decorator.getDeclaredRoutes(prototype),
|
|
410
|
+
...controller_decorator.ownEventHandlers(prototype).map(controller_decorator.eventRoute)
|
|
411
|
+
];
|
|
412
|
+
if (declared.length === 0) continue;
|
|
409
413
|
if (Reflect.getOwnMetadata(controller_decorator.META.replacesInheritedRoutes, prototype)) for (const route of declared)cut.add(route.method);
|
|
410
|
-
const inherited =
|
|
414
|
+
const inherited = [
|
|
415
|
+
...controller_decorator.getHandlerRoutes(base),
|
|
416
|
+
...providers.getEventHandlers(base).map(controller_decorator.eventRoute)
|
|
417
|
+
].filter((route)=>!cut.has(route.method));
|
|
411
418
|
for (const method of new Set(declared.map((route)=>route.method))){
|
|
412
419
|
const own = [
|
|
413
420
|
...new Set(declared.filter((route)=>route.method === method).map((route)=>route.label))
|
|
@@ -721,7 +728,8 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
721
728
|
parse: []
|
|
722
729
|
}
|
|
723
730
|
}));
|
|
724
|
-
|
|
731
|
+
// Longer than a timer can wait keeps it, as 0 does; the timer would fire at once
|
|
732
|
+
if (seconds > 0 && providers.timerKeepsSeconds(seconds)) {
|
|
725
733
|
setTimeout(()=>{
|
|
726
734
|
reply.delete().catch((failure)=>controller_decorator.logFailedSend(logger, 'delete a reply to a command', failure));
|
|
727
735
|
}, seconds * 1000).unref?.();
|
|
@@ -919,9 +927,9 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
919
927
|
}
|
|
920
928
|
/**
|
|
921
929
|
* Resolves each unit and runs its `onReady` one at a time, in the units' dependency order. A failure is
|
|
922
|
-
* reported and the next unit still runs.
|
|
923
|
-
* to
|
|
924
|
-
*/ async function runReadyHooks(container, units, client, info,
|
|
930
|
+
* reported and the next unit still runs. `settled` hears of each unit as its `onReady` settles, or once it is found
|
|
931
|
+
* to have none, which is what a shutdown that starts meanwhile reads.
|
|
932
|
+
*/ async function runReadyHooks(container, units, client, info, report, { stopped = ()=>false, slowAfterMs, settled, runOnReady } = {}) {
|
|
925
933
|
const failed = new Set();
|
|
926
934
|
// For each unit, the failed units it depends on, directly or through another dependency
|
|
927
935
|
const failedUpstream = new Map();
|
|
@@ -958,11 +966,7 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
958
966
|
continue;
|
|
959
967
|
}
|
|
960
968
|
firstToken.set(instance, unit.token);
|
|
961
|
-
const entry = lifecycleEntry(unit, instance);
|
|
962
|
-
// Only a unit whose onReady has settled, or that has none, is shut down: a stop mid-ready waits for the one still
|
|
963
|
-
// starting, within its time, and skips those not reached yet
|
|
964
969
|
if (typeof instance.onReady !== 'function') {
|
|
965
|
-
entries.push(entry);
|
|
966
970
|
settled?.(unit);
|
|
967
971
|
continue;
|
|
968
972
|
}
|
|
@@ -979,7 +983,6 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
979
983
|
} finally{
|
|
980
984
|
clearTimeout(slow);
|
|
981
985
|
}
|
|
982
|
-
entries.push(entry);
|
|
983
986
|
settled?.(unit);
|
|
984
987
|
}
|
|
985
988
|
}
|
|
@@ -1093,6 +1096,28 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1093
1096
|
]);
|
|
1094
1097
|
}
|
|
1095
1098
|
|
|
1099
|
+
/**
|
|
1100
|
+
* Every `@Autocomplete` handler of the given controllers, read from their metadata, with the handlers of one option
|
|
1101
|
+
* before those of a whole command, so an option's handler wins over its command's whatever order they are declared in.
|
|
1102
|
+
*/ function buildAutocompleteRoutes(controllers) {
|
|
1103
|
+
const routes = controllers.flatMap((controllerClass)=>controller_decorator.getAutocompleteHandlers(controllerClass.prototype).map((meta)=>({
|
|
1104
|
+
controllerClass,
|
|
1105
|
+
meta
|
|
1106
|
+
})));
|
|
1107
|
+
return routes.sort((a, b)=>Number(Boolean(b.meta.optionName)) - Number(Boolean(a.meta.optionName)));
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* The handler an autocomplete reaches, as dispatch routes it: its full command path, then its command's name, and at
|
|
1111
|
+
* each the first handler whose option is the focused one, or that names none.
|
|
1112
|
+
*/ function matchAutocompleteRoute(routes, interaction) {
|
|
1113
|
+
const focused = controller_decorator.focusedOptionName(interaction);
|
|
1114
|
+
for (const path of controller_decorator.resolveCommandPaths(interaction)){
|
|
1115
|
+
const route = routes.find(({ meta })=>meta.commandPath === path && (meta.optionName === undefined || meta.optionName === focused));
|
|
1116
|
+
if (route) return route;
|
|
1117
|
+
}
|
|
1118
|
+
return undefined;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1096
1121
|
/** The keys a command is routed by, most specific first: a chat command's full path, then its name; none for anything else. */ function commandRouteKeys(interaction) {
|
|
1097
1122
|
if (interaction.isChatInputCommand()) return controller_decorator.resolveCommandPaths(interaction);
|
|
1098
1123
|
if (interaction.isContextMenuCommand() || interaction.isPrimaryEntryPointCommand()) return [
|
|
@@ -1255,6 +1280,26 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1255
1280
|
if (winner) return `command '${keys[0]}' does not reach ${handler}: dispatch runs ${winner.controllerClass.name}.${winner.meta.methodName}.`;
|
|
1256
1281
|
return `command '${keys[0]}' does not match ${handler}'s route ${named.map(({ route })=>`'${route}'`).join(' or ')}.`;
|
|
1257
1282
|
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Why an autocomplete could not reach a handler, for a test calling the handler directly: the handler is checked
|
|
1285
|
+
* against the one dispatch routes the autocomplete to among `controllers`, by its command path and focused option.
|
|
1286
|
+
* `undefined` when it is that one, when the handler has no `@Autocomplete` route, or when the interaction is not an
|
|
1287
|
+
* autocomplete or has no command name.
|
|
1288
|
+
*/ function autocompleteMismatch(controllers, controller, methodName, interaction) {
|
|
1289
|
+
if (!interaction.isAutocomplete() || typeof interaction.commandName !== 'string') return undefined;
|
|
1290
|
+
const own = controller_decorator.getAutocompleteHandlers(controller.prototype).filter((meta)=>meta.methodName === methodName);
|
|
1291
|
+
if (own.length === 0) return undefined;
|
|
1292
|
+
const winner = matchAutocompleteRoute(buildAutocompleteRoutes(controllers), interaction);
|
|
1293
|
+
if (winner?.controllerClass === controller && winner.meta.methodName === methodName) return undefined;
|
|
1294
|
+
const handler = `${controller.name}.${methodName}`;
|
|
1295
|
+
const received = controller_decorator.describeInteraction(interaction);
|
|
1296
|
+
// A mock without a focused option reaches no option's handler, the commonest way to miss one
|
|
1297
|
+
const option = controller_decorator.focusedOptionName(interaction) === undefined ? own.find((meta)=>meta.optionName !== undefined)?.optionName : undefined;
|
|
1298
|
+
const fix = option === undefined ? '' : ` Give the mock the focused option: options: createChatInputOptions({ focused: '${option}' }).`;
|
|
1299
|
+
if (winner) return `${received} does not reach ${handler}: dispatch runs ${winner.controllerClass.name}.${winner.meta.methodName}.${fix}`;
|
|
1300
|
+
const routes = own.map((meta)=>meta.optionName === undefined ? `'${meta.commandPath}'` : `'${meta.commandPath}' option '${meta.optionName}'`);
|
|
1301
|
+
return `${received} does not match ${handler}'s route ${routes.join(' or ')}.${fix}`;
|
|
1302
|
+
}
|
|
1258
1303
|
|
|
1259
1304
|
/**
|
|
1260
1305
|
* How long a component or modal submission no route takes is left to the client's other listeners, such as a
|
|
@@ -1322,13 +1367,19 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1322
1367
|
this.logger.warn(`messages.help is on, but ${route.controllerClass.name}.${route.method} (${JSON.stringify(route.pattern)}) takes "${shown}", ` + `which runs it instead, so the built-in help never answers. Turn help off, or give the handler another word.`);
|
|
1323
1368
|
}
|
|
1324
1369
|
}
|
|
1325
|
-
/**
|
|
1370
|
+
/**
|
|
1371
|
+
* The call for one event, stamped as it is made, so every handler it runs reports one start and a duration that
|
|
1372
|
+
* includes routing and any handler that ran before it; the fallback is told of each error that reaches it when there
|
|
1373
|
+
* is a recorder.
|
|
1374
|
+
*/ callFor(record) {
|
|
1326
1375
|
const fallback = record ? async (error, context)=>{
|
|
1327
1376
|
record.unhandled(error);
|
|
1328
|
-
|
|
1377
|
+
const failure = await this.fallback(error, context);
|
|
1378
|
+
if (failure !== undefined) record.unanswered(error, failure);
|
|
1379
|
+
return failure;
|
|
1329
1380
|
} : this.fallback;
|
|
1330
1381
|
return {
|
|
1331
|
-
startedAt,
|
|
1382
|
+
startedAt: performance.now(),
|
|
1332
1383
|
fallback,
|
|
1333
1384
|
record
|
|
1334
1385
|
};
|
|
@@ -1339,32 +1390,35 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1339
1390
|
}
|
|
1340
1391
|
return this.controllerInstancesCache.get(controllerClass);
|
|
1341
1392
|
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Runs `run` on the controller's instance, resolved as its handler starts. A controller that cannot be made fails
|
|
1395
|
+
* only its own handlers: the error goes to the global filters, then the fallback, and the call goes on without it.
|
|
1396
|
+
*/ async withInstance(controllerClass, args, call, run, unresolved = new Set()) {
|
|
1397
|
+
// A controller that failed to resolve for this event is reported once, however many of its handlers it reaches
|
|
1398
|
+
if (unresolved.has(controllerClass)) return;
|
|
1399
|
+
let instance;
|
|
1400
|
+
try {
|
|
1401
|
+
instance = this.getInstance(controllerClass);
|
|
1402
|
+
} catch (error) {
|
|
1403
|
+
unresolved.add(controllerClass);
|
|
1404
|
+
await providers.handleUnroutedError(this.container, args, error, this.runOptions(call));
|
|
1405
|
+
return;
|
|
1406
|
+
}
|
|
1407
|
+
await run(instance);
|
|
1408
|
+
}
|
|
1342
1409
|
/** The component routes, built on first use; the app calls it as it is created. */ getComponentRoutes() {
|
|
1343
1410
|
return this.componentRoutes ?? (this.componentRoutes = buildComponentRoutes([
|
|
1344
1411
|
...this.controllerClasses
|
|
1345
1412
|
]));
|
|
1346
1413
|
}
|
|
1347
1414
|
getAutocompleteRoutes() {
|
|
1348
|
-
|
|
1349
|
-
const routes = [];
|
|
1350
|
-
for (const controllerClass of this.controllerClasses){
|
|
1351
|
-
for (const meta of controller_decorator.getAutocompleteHandlers(this.getInstance(controllerClass))){
|
|
1352
|
-
routes.push({
|
|
1353
|
-
controllerClass,
|
|
1354
|
-
meta
|
|
1355
|
-
});
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
routes.sort((a, b)=>Number(Boolean(b.meta.optionName)) - Number(Boolean(a.meta.optionName)));
|
|
1359
|
-
this.autocompleteRoutes = routes;
|
|
1360
|
-
return routes;
|
|
1415
|
+
return this.autocompleteRoutes ?? (this.autocompleteRoutes = buildAutocompleteRoutes(this.controllerClasses));
|
|
1361
1416
|
}
|
|
1362
1417
|
/**
|
|
1363
1418
|
* Dispatches an interaction. A failure outside any handler, such as no route matching or resolving
|
|
1364
1419
|
* the controller, goes to the global filters, then the fallback.
|
|
1365
1420
|
*/ async interaction(interaction, record) {
|
|
1366
|
-
|
|
1367
|
-
const call = this.callFor(record, performance.now());
|
|
1421
|
+
const call = this.callFor(record);
|
|
1368
1422
|
try {
|
|
1369
1423
|
await this.dispatchInteraction(interaction, call);
|
|
1370
1424
|
} catch (error) {
|
|
@@ -1390,14 +1444,14 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1390
1444
|
if (matched) {
|
|
1391
1445
|
const { route, params } = matched;
|
|
1392
1446
|
interaction.dynamicParams = params;
|
|
1393
|
-
await this.executeCommand(
|
|
1447
|
+
await this.executeCommand(route.controllerClass, route.meta, interaction, call);
|
|
1394
1448
|
return;
|
|
1395
1449
|
}
|
|
1396
1450
|
}
|
|
1397
1451
|
// The same match a test's invoke checks a handler against, so the two cannot disagree
|
|
1398
1452
|
const command = matchCommandRoute(this.controllerClasses, interaction);
|
|
1399
1453
|
if (command) {
|
|
1400
|
-
await this.executeCommand(
|
|
1454
|
+
await this.executeCommand(command.controllerClass, command.meta, interaction, call);
|
|
1401
1455
|
return;
|
|
1402
1456
|
}
|
|
1403
1457
|
// A component or modal no route takes may be a collector's: with another listener on the client, it has the
|
|
@@ -1420,21 +1474,17 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1420
1474
|
* Answers an autocomplete interaction from the `@Autocomplete` handler that claims it. An unclaimed
|
|
1421
1475
|
* option gets an empty list and a warning, rather than a menu stuck loading until Discord times out.
|
|
1422
1476
|
*/ async handleAutocomplete(interaction, call) {
|
|
1423
|
-
const
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
], call);
|
|
1435
|
-
if (!ran) await closeAutocomplete(interaction, this.logger);
|
|
1436
|
-
return;
|
|
1437
|
-
}
|
|
1477
|
+
const route = matchAutocompleteRoute(this.getAutocompleteRoutes(), interaction);
|
|
1478
|
+
if (route) {
|
|
1479
|
+
const { controllerClass, meta } = route;
|
|
1480
|
+
this.logger.log('[AUTOCOMPLETE]', `[${meta.commandPath}]`, `[${meta.methodName}]`);
|
|
1481
|
+
const params = controller_decorator.resolveOptionParams(interaction);
|
|
1482
|
+
const ran = await this.invokeHandler(this.getInstance(controllerClass), meta.methodName, [
|
|
1483
|
+
interaction,
|
|
1484
|
+
params
|
|
1485
|
+
], call);
|
|
1486
|
+
if (!ran) await closeAutocomplete(interaction, this.logger);
|
|
1487
|
+
return;
|
|
1438
1488
|
}
|
|
1439
1489
|
this.logger.warn(`No handler matched ${controller_decorator.describeInteraction(interaction)}. Declare an @Autocomplete handler for it, ` + `or drop setAutocomplete(true) from the option.`);
|
|
1440
1490
|
await closeAutocomplete(interaction, this.logger);
|
|
@@ -1442,19 +1492,22 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1442
1492
|
interaction
|
|
1443
1493
|
], this.runOptions(call));
|
|
1444
1494
|
}
|
|
1445
|
-
/** Warns, in development, that a modal field or select menu choice is hidden by a customId param of the same name. */ warnCollisions(methodName, names) {
|
|
1495
|
+
/** Warns, in development, that a modal field or select menu choice is hidden by a customId param of the same name. */ warnCollisions(controllerClass, methodName, names) {
|
|
1446
1496
|
if (process.env.NODE_ENV !== 'development') return;
|
|
1497
|
+
let warned = this.warnedCollisions.get(controllerClass);
|
|
1498
|
+
if (!warned) this.warnedCollisions.set(controllerClass, warned = new Set());
|
|
1447
1499
|
for (const name of names){
|
|
1448
1500
|
const key = `${methodName}:${name}`;
|
|
1449
|
-
if (
|
|
1450
|
-
|
|
1451
|
-
this.logger.warn(`"${name}" is both a customId param and a modal field or select menu choice of ${methodName}; the handler receives the customId
|
|
1501
|
+
if (warned.has(key)) continue;
|
|
1502
|
+
warned.add(key);
|
|
1503
|
+
this.logger.warn(`"${name}" is both a customId param and a modal field or select menu choice of ${controllerClass.name}.${methodName}; the handler ` + `receives the customId param. Rename one to receive both.`);
|
|
1452
1504
|
}
|
|
1453
1505
|
}
|
|
1454
1506
|
/**
|
|
1455
1507
|
* Runs a resolved command, shared by both dispatch paths so a pattern-matched
|
|
1456
1508
|
* component and a named slash command behave identically once the route is chosen.
|
|
1457
|
-
*/ async executeCommand(
|
|
1509
|
+
*/ async executeCommand(controllerClass, commandMetadata, interaction, call) {
|
|
1510
|
+
const controllerInstance = this.getInstance(controllerClass);
|
|
1458
1511
|
const { methodName, type } = commandMetadata;
|
|
1459
1512
|
// No interaction-type check here: both callers pick the route with
|
|
1460
1513
|
// `matchesCommandType` before getting this far, and `@Command` re-checks the
|
|
@@ -1462,7 +1515,7 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1462
1515
|
this.logger.log('[INTERACTION]', `[${type}]`, `[${methodName}]`);
|
|
1463
1516
|
const routeParams = interaction.dynamicParams;
|
|
1464
1517
|
const { params, collisions } = handlerInput(interaction, routeParams);
|
|
1465
|
-
this.warnCollisions(methodName, collisions);
|
|
1518
|
+
this.warnCollisions(controllerClass, methodName, collisions);
|
|
1466
1519
|
await this.invokeHandler(controllerInstance, methodName, [
|
|
1467
1520
|
interaction,
|
|
1468
1521
|
params
|
|
@@ -1509,7 +1562,7 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1509
1562
|
* usage through that handler's filters. A bare parent's unguarded subcommands' usage, once the app's guards allow
|
|
1510
1563
|
* it, and a failure to read the prefixes, go through the global filters, then the fallback; the listeners still run.
|
|
1511
1564
|
*/ async message(message, record) {
|
|
1512
|
-
if (message.author.bot || !message.content
|
|
1565
|
+
if (message.author.bot || !providers.hasMessageText(message.content)) return;
|
|
1513
1566
|
const call = this.callFor(record);
|
|
1514
1567
|
let target;
|
|
1515
1568
|
try {
|
|
@@ -1536,24 +1589,29 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1536
1589
|
}
|
|
1537
1590
|
// The matched handler, then every listener, each resolved from the container only as it starts
|
|
1538
1591
|
const runs = [];
|
|
1592
|
+
const unresolved = new Set();
|
|
1539
1593
|
if (target) {
|
|
1540
1594
|
const { route, params, start, given } = target;
|
|
1541
1595
|
noteInvocation(message, `${start}${providers.commandWordsOf(route.tokens).join(' ')}`);
|
|
1542
1596
|
const hooks = providers.messageCommandHooks(route, params, message, start, given, this.messageOptions.types);
|
|
1543
1597
|
runs.push({
|
|
1544
1598
|
name: `${route.controllerClass.name}.${route.method}`,
|
|
1545
|
-
run: (at)=>this.
|
|
1546
|
-
message
|
|
1547
|
-
|
|
1548
|
-
|
|
1599
|
+
run: (at)=>this.withInstance(route.controllerClass, [
|
|
1600
|
+
message
|
|
1601
|
+
], at, (instance)=>this.invokeHandler(instance, route.method, [
|
|
1602
|
+
message,
|
|
1603
|
+
params
|
|
1604
|
+
], at, hooks), unresolved)
|
|
1549
1605
|
});
|
|
1550
1606
|
}
|
|
1551
1607
|
for (const { controllerClass, method } of this.messageListeners){
|
|
1552
1608
|
runs.push({
|
|
1553
1609
|
name: `${controllerClass.name}.${method}`,
|
|
1554
|
-
run: (at)=>this.
|
|
1610
|
+
run: (at)=>this.withInstance(controllerClass, [
|
|
1555
1611
|
message
|
|
1556
|
-
], at)
|
|
1612
|
+
], at, (instance)=>this.invokeHandler(instance, method, [
|
|
1613
|
+
message
|
|
1614
|
+
], at), unresolved)
|
|
1557
1615
|
});
|
|
1558
1616
|
}
|
|
1559
1617
|
if (this.messageOptions.handlers === 'concurrent') await this.runTogether(runs, call);
|
|
@@ -1578,7 +1636,8 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1578
1636
|
...call,
|
|
1579
1637
|
record: {
|
|
1580
1638
|
settled: (...report)=>reports[index].push(report),
|
|
1581
|
-
unhandled: (error)=>record.unhandled(error)
|
|
1639
|
+
unhandled: (error)=>record.unhandled(error),
|
|
1640
|
+
unanswered: (error, failure)=>record.unanswered(error, failure)
|
|
1582
1641
|
}
|
|
1583
1642
|
} : call)));
|
|
1584
1643
|
for (const report of reports.flat())record?.settled(...report);
|
|
@@ -1658,7 +1717,7 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1658
1717
|
const matching = this.controllerClasses.map((controllerClass)=>({
|
|
1659
1718
|
controllerClass,
|
|
1660
1719
|
// Handlers for this emoji first, then those for every emoji
|
|
1661
|
-
handlers: controller_decorator.getReactionHandlers(
|
|
1720
|
+
handlers: controller_decorator.getReactionHandlers(controllerClass.prototype).filter(forEmoji).sort((a, b)=>Number(!a.emoji) - Number(!b.emoji))
|
|
1662
1721
|
})).filter(({ handlers })=>handlers.length > 0);
|
|
1663
1722
|
if (matching.length === 0) return;
|
|
1664
1723
|
// Only asked when a matching handler leaves bots out, since a partial user costs a fetch
|
|
@@ -1682,16 +1741,21 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1682
1741
|
return;
|
|
1683
1742
|
}
|
|
1684
1743
|
for (const { controllerClass, handlers } of runs){
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1744
|
+
await this.withInstance(controllerClass, [
|
|
1745
|
+
reaction,
|
|
1746
|
+
{
|
|
1747
|
+
user,
|
|
1748
|
+
action
|
|
1749
|
+
}
|
|
1750
|
+
], call, async (instance)=>{
|
|
1751
|
+
for (const { method } of handlers)await this.invokeHandler(instance, method, [
|
|
1688
1752
|
reaction,
|
|
1689
1753
|
{
|
|
1690
1754
|
user,
|
|
1691
1755
|
action
|
|
1692
1756
|
}
|
|
1693
1757
|
], call);
|
|
1694
|
-
}
|
|
1758
|
+
});
|
|
1695
1759
|
}
|
|
1696
1760
|
}
|
|
1697
1761
|
/**
|
|
@@ -1710,7 +1774,10 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1710
1774
|
constructor(options){
|
|
1711
1775
|
this.options = options;
|
|
1712
1776
|
this.controllerInstancesCache = new Map();
|
|
1713
|
-
/**
|
|
1777
|
+
/**
|
|
1778
|
+
* Method and name pairs already warned about, by controller class, so a collision warns once per handler, not on
|
|
1779
|
+
* every submit or selection. Keyed by the class itself, so two controllers of one name stay apart.
|
|
1780
|
+
*/ this.warnedCollisions = new WeakMap();
|
|
1714
1781
|
/** The handlers already warned about, so each is named once however often it runs. */ this.warnedUnanswered = new Set();
|
|
1715
1782
|
/** The message handlers already warned about as slow, so each is named once. */ this.warnedSlow = new Set();
|
|
1716
1783
|
this.container = options.container;
|
|
@@ -1725,6 +1792,8 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1725
1792
|
// The app's own help command reads this table too, so it lists the commands dispatch reaches
|
|
1726
1793
|
if (this.container.isBound(providers.HandlerRegistry)) providers.shareMessageRoutes(this.container.get(providers.HandlerRegistry), this.messageRoutes);
|
|
1727
1794
|
this.warnUnreachableHelp();
|
|
1795
|
+
// Here, where the routes are built once, rather than in buildMessageRoutes, which startup runs twice
|
|
1796
|
+
for (const warning of providers.messageRouteWarnings(this.messageRoutes, this.messageOptions))this.logger.warn(warning);
|
|
1728
1797
|
this.messageListeners = this.controllerClasses.flatMap((controllerClass)=>controller_decorator.getMessageHandlers(controllerClass.prototype).filter((handler)=>handler.pattern === undefined).map(({ method })=>({
|
|
1729
1798
|
controllerClass,
|
|
1730
1799
|
method
|
|
@@ -1808,19 +1877,38 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1808
1877
|
seen.add(cls);
|
|
1809
1878
|
return providers.injectedTokens(cls).some((token)=>token === controller_decorator.ExecutionContext || providers.isAppClassToken(token) && !providers$1.has(token) && !seen.has(token) && reachesContext(token, providers$1, seen));
|
|
1810
1879
|
}
|
|
1811
|
-
/**
|
|
1812
|
-
* The classes the app's stages and presenter inject, which they would make only at their first call. Made with the
|
|
1813
|
-
* app's own classes, a service among them gets its lifecycle hooks. One that reaches the call's `ExecutionContext` is
|
|
1814
|
-
* made for each call, so it is left out, and a stage a test replaces is not among the stages, so what it would inject
|
|
1815
|
-
* is not made.
|
|
1816
|
-
*/ function stageDependencies({ decorators }, providers$1, presenter) {
|
|
1880
|
+
/** The app's classes the stages and presenter inject. */ function stageInjected({ decorators }, presenter) {
|
|
1817
1881
|
const stages = [
|
|
1818
1882
|
...decorators
|
|
1819
1883
|
].filter(([, decorator])=>decorator !== '@Controller()').map(([stage])=>stage);
|
|
1820
1884
|
if (typeof presenter === 'function') stages.push(presenter);
|
|
1821
1885
|
return [
|
|
1822
1886
|
...new Set(stages.flatMap((stage)=>providers.injectedTokens(stage)))
|
|
1823
|
-
].filter(providers.isAppClassToken)
|
|
1887
|
+
].filter(providers.isAppClassToken);
|
|
1888
|
+
}
|
|
1889
|
+
/**
|
|
1890
|
+
* The classes the app's stages and presenter inject, which they would make only at their first call. Made with the
|
|
1891
|
+
* app's own classes, a service among them gets its lifecycle hooks. One that reaches the call's `ExecutionContext` is
|
|
1892
|
+
* made for each call, so it is left out, and a stage a test replaces is not among the stages, so what it would inject
|
|
1893
|
+
* is not made.
|
|
1894
|
+
*/ function stageDependencies(startup, providers, presenter) {
|
|
1895
|
+
return stageInjected(startup, presenter).filter((cls)=>!reachesContext(cls, providers));
|
|
1896
|
+
}
|
|
1897
|
+
/**
|
|
1898
|
+
* A warning for each `@On` and `@Once` handler on a class the stages and presenter reach that is made for each call,
|
|
1899
|
+
* as it reaches `ExecutionContext`: no one instance of it receives events.
|
|
1900
|
+
*/ function perCallEventWarnings(startup, providers$1, presenter) {
|
|
1901
|
+
const perCall = new Set();
|
|
1902
|
+
// What a class made for each call injects is made for each call too only if it also reaches the context
|
|
1903
|
+
const visit = (cls)=>{
|
|
1904
|
+
if (perCall.has(cls) || providers$1.has(cls) || !reachesContext(cls, providers$1)) return;
|
|
1905
|
+
perCall.add(cls);
|
|
1906
|
+
providers.injectedTokens(cls).filter(providers.isAppClassToken).forEach(visit);
|
|
1907
|
+
};
|
|
1908
|
+
stageInjected(startup, presenter).forEach(visit);
|
|
1909
|
+
return [
|
|
1910
|
+
...perCall
|
|
1911
|
+
].flatMap((cls)=>providers.getEventHandlers(cls.prototype).map(({ event, method, once })=>`${cls.name}.${method}: @${once ? 'Once' : 'On'}('${event}') is on a class made for each call, as it injects ` + 'ExecutionContext or a class that does, so it receives no events. The next major version (5.0) refuses it; ' + 'move the handler to a service that does not.'));
|
|
1824
1912
|
}
|
|
1825
1913
|
/** How a container checks a guard first met at a call: the guard and what it injects, as the startup checks would. */ function lateGuardCheck(providers$1, translator) {
|
|
1826
1914
|
return (guard)=>assertStartupClasses({
|
|
@@ -1843,6 +1931,100 @@ async function replyToMessage(message, error, logger, withEmoji, answering) {
|
|
|
1843
1931
|
for (const needsOne of classes.filter((cls)=>providers.injectedTokens(cls).includes(controller_decorator.Translator)))controller_decorator.startupError(controller_decorator.missingTranslatorError(needsOne));
|
|
1844
1932
|
}
|
|
1845
1933
|
|
|
1934
|
+
/**
|
|
1935
|
+
* One source for each instance whose lifecycle hooks run, the cooldown store aside, in lifecycle order; read once the
|
|
1936
|
+
* providers are made, as a value's or a factory's class is its instance's. A class `prepared` lacks has its handlers
|
|
1937
|
+
* prepared here, and one a controller's would be refused for is left out, with `warn` naming the refusal.
|
|
1938
|
+
*/ function eventSources(container, providers$1, units, prepared, warn) {
|
|
1939
|
+
// The tokens of each class the container makes, bound as itself or given as a provider's `useClass`, the cooldown
|
|
1940
|
+
// store's included: no event reaches it, nor its instance through a factory
|
|
1941
|
+
const classTokens = new Map();
|
|
1942
|
+
for (const { token } of units){
|
|
1943
|
+
const provider = providers$1.get(token);
|
|
1944
|
+
if (provider && !providers.isClassProvider(provider) || !provider && !providers.isAppClassToken(token)) continue;
|
|
1945
|
+
const cls = provider ? provider.useClass : token;
|
|
1946
|
+
classTokens.set(cls, [
|
|
1947
|
+
...classTokens.get(cls) ?? [],
|
|
1948
|
+
token
|
|
1949
|
+
]);
|
|
1950
|
+
}
|
|
1951
|
+
const names = new Map(prepared.map((cls)=>[
|
|
1952
|
+
cls.name,
|
|
1953
|
+
cls
|
|
1954
|
+
]));
|
|
1955
|
+
const handlers = new Map();
|
|
1956
|
+
const handlersOf = (cls)=>{
|
|
1957
|
+
let found = handlers.get(cls);
|
|
1958
|
+
if (!found) {
|
|
1959
|
+
found = prepared.includes(cls) ? providers.getEventHandlers(cls.prototype) : prepareClass(container, cls, names, warn);
|
|
1960
|
+
handlers.set(cls, found);
|
|
1961
|
+
}
|
|
1962
|
+
return found;
|
|
1963
|
+
};
|
|
1964
|
+
const sources = [];
|
|
1965
|
+
const given = new Set();
|
|
1966
|
+
for (const { token, cooldownStore } of units){
|
|
1967
|
+
// The cooldown store is the app's infrastructure, never one of its classes, so no event reaches it
|
|
1968
|
+
if (cooldownStore) continue;
|
|
1969
|
+
const provider = providers$1.get(token);
|
|
1970
|
+
if (!provider || providers.isClassProvider(provider)) {
|
|
1971
|
+
const cls = provider ? provider.useClass : token;
|
|
1972
|
+
const found = handlersOf(cls);
|
|
1973
|
+
if (found.length > 0) sources.push({
|
|
1974
|
+
cls,
|
|
1975
|
+
handlers: found,
|
|
1976
|
+
resolve: ()=>container.get(token)
|
|
1977
|
+
});
|
|
1978
|
+
continue;
|
|
1979
|
+
}
|
|
1980
|
+
// A value, or a factory's, made by now; one instance under several tokens is one source
|
|
1981
|
+
const instance = container.get(token);
|
|
1982
|
+
if (typeof instance !== 'object' || instance === null || given.has(instance)) continue;
|
|
1983
|
+
given.add(instance);
|
|
1984
|
+
const cls = instance.constructor;
|
|
1985
|
+
if (typeof cls !== 'function') continue;
|
|
1986
|
+
const found = handlersOf(cls);
|
|
1987
|
+
if (found.length === 0) continue;
|
|
1988
|
+
// A factory may return the instance the container made for a class unit, whose own source runs it; only units of
|
|
1989
|
+
// the instance's class are resolved, and each resolves on the event through its own source anyway
|
|
1990
|
+
const tokens = classTokens.get(cls) ?? [];
|
|
1991
|
+
const owned = ()=>tokens.some((token)=>container.get(token) === instance);
|
|
1992
|
+
sources.push({
|
|
1993
|
+
cls,
|
|
1994
|
+
handlers: found,
|
|
1995
|
+
resolve: ()=>owned() ? undefined : instance
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1998
|
+
return sources;
|
|
1999
|
+
}
|
|
2000
|
+
/** The handlers of `cls` that pass a controller's checks, warning of each other one and why it does not run. */ function prepareClass(container, cls, names, warn) {
|
|
2001
|
+
const declared = providers.getEventHandlers(cls.prototype);
|
|
2002
|
+
if (declared.length === 0) return [];
|
|
2003
|
+
const other = names.get(cls.name);
|
|
2004
|
+
if (!other) names.set(cls.name, cls);
|
|
2005
|
+
// @Once tells classes apart by name, so this class's would share another's
|
|
2006
|
+
const sharesName = other !== undefined && other !== cls && declared.some((handler)=>handler.once);
|
|
2007
|
+
if (sharesName) {
|
|
2008
|
+
refused(warn, cls, `${cls.name}: two classes have this name; @Cooldown and @Once tell classes apart by name, so they would share their counts. Rename one of them.`, declared.filter((handler)=>handler.once));
|
|
2009
|
+
}
|
|
2010
|
+
const errors = new Map();
|
|
2011
|
+
return declared.filter((handler)=>{
|
|
2012
|
+
if (sharesName && handler.once) return false;
|
|
2013
|
+
let found = errors.get(handler.method);
|
|
2014
|
+
if (!found) {
|
|
2015
|
+
found = providers.prepareEventHandler(container, cls, handler.method);
|
|
2016
|
+
errors.set(handler.method, found);
|
|
2017
|
+
const onMethod = declared.filter((other)=>other.method === handler.method && !(sharesName && other.once));
|
|
2018
|
+
for (const error of found)refused(warn, cls, error.message, onMethod);
|
|
2019
|
+
}
|
|
2020
|
+
return found.length === 0;
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
function refused(warn, cls, reason, handlers) {
|
|
2024
|
+
const labels = handlers.map(({ event, method, once })=>`@${once ? 'Once' : 'On'}('${event}') in ${cls.name}.${method}`);
|
|
2025
|
+
warn(`${reason} Until the next major version (5.0) refuses it at startup, ${labels.join(', ')} does not run.`);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
1846
2028
|
exports.DEFAULT_SHUTDOWN_TIMEOUT_MS = DEFAULT_SHUTDOWN_TIMEOUT_MS;
|
|
1847
2029
|
exports.Dispatcher = Dispatcher;
|
|
1848
2030
|
exports.ReadyPass = ReadyPass;
|
|
@@ -1850,11 +2032,13 @@ exports.RunningCalls = RunningCalls;
|
|
|
1850
2032
|
exports.SHUTDOWN_MARGIN_MS = SHUTDOWN_MARGIN_MS;
|
|
1851
2033
|
exports.assertDistinctCommands = assertDistinctCommands;
|
|
1852
2034
|
exports.assertStartupClasses = assertStartupClasses;
|
|
2035
|
+
exports.autocompleteMismatch = autocompleteMismatch;
|
|
1853
2036
|
exports.buildComponentRoutes = buildComponentRoutes;
|
|
1854
2037
|
exports.callsSettled = callsSettled;
|
|
1855
2038
|
exports.commandMismatch = commandMismatch;
|
|
1856
2039
|
exports.componentRouteFor = componentRouteFor;
|
|
1857
2040
|
exports.createFallback = createFallback;
|
|
2041
|
+
exports.eventSources = eventSources;
|
|
1858
2042
|
exports.findComponentRouteConflicts = findComponentRouteConflicts;
|
|
1859
2043
|
exports.handlerInput = handlerInput;
|
|
1860
2044
|
exports.lateGuardCheck = lateGuardCheck;
|
|
@@ -1862,6 +2046,7 @@ exports.lifecycleEntry = lifecycleEntry;
|
|
|
1862
2046
|
exports.matchComponentRoute = matchComponentRoute;
|
|
1863
2047
|
exports.messageDecorator = messageDecorator;
|
|
1864
2048
|
exports.ownInteractionListener = ownInteractionListener;
|
|
2049
|
+
exports.perCallEventWarnings = perCallEventWarnings;
|
|
1865
2050
|
exports.reactionDecorator = reactionDecorator;
|
|
1866
2051
|
exports.readCustomId = readCustomId;
|
|
1867
2052
|
exports.replyWithUserError = replyWithUserError;
|