4.1.0-beta.6 changelog
Published
Entries marked Breaking change a working bot; the migration guide says what to do about them. Every release of the line is in the changelog.
Minor Changes
#228
8e1b936Thanks @l7aromeo! -@MeoCord({ messages: { mention: 'only' } })starts every message command in a server with a mention of the bot and nothing else, neither a prefix nor the message as plain text, while a direct message starts as usual, after the prefix or as it is;@MessageHandler(pattern, { mention: 'only' })does the same for one command beside the app's prefix. Discord sends a message's text without the privileged MessageContent intent when the message mentions the bot, and in direct messages, so such commands, and commands withscope: 'dm', no longer need it: MeoCord's startup warning about MessageContent names only a@MessageHandler()listener and commands a prefix or plain text starts in a server, and says what still arrives without it. A mention-only bot can run without the intent, and without applying for it once verified. In a test,resolveRoute(App, { content, dm: true })reads a message as a direct message.#252
2d0575fThanks @l7aromeo! - MeoCord's own texts for users go through the app's translator: a message command's usage and each thing wrong with it, the built-in!helpand the labels ofHandlerRegistry.messageHelp, cooldown and cooldown store refusals, "Command not found!", the generic error, and the default presenter's "Working on it…" and "Oops!". Add ameocordgroup to any catalog given to@MeoCord({ i18n }), all of it or part, such asmeocord: { usage: { heading: 'Cara pakai: {usage}' } }; a text a locale leaves out stays in English, line by line. Answers to an interaction are in the user's language, replies to a message in the server's preferred language, or the default locale's in a DM. MeoCord's English stands as the English catalog, so an English-speaking user or server gets it even under a default locale in another language, unless the app's ownen-USoren-GBcatalog words the text. The keys and their English are in the newMeoCordMessagestype frommeocord/interface, and a key MeoCord lacks, or a{param}its English text lacks, fails to compile. Withouti18n, every text is the English one it is today.translateError(error, t, target)frommeocord/commonreturns the text the fallback answers an error with, in the language of an interaction, a message or a locale, for an exception filter that answers MeoCord's errors its own way.- A message param type takes
labelKey, a message key of the app's catalog, for a label in each server's language.@MeoCordrefuses one withouti18n, or one the default catalog has no message for. expectCompleteCatalog(t, { meocord: true })requires every locale that is not English to translate each of MeoCord's texts. Without the option it reports only ameocordkey MeoCord lacks.
See Localisation.
#251
b4a9e58Thanks @l7aromeo! - Message commands have a built-in help command, off unless asked for:@MeoCord({ messages: { prefix: '!', help: true } })answers!helpwith the commands the caller can use where they asked, one line each with its handler'sdescription, and!help <command>with one command's usage, params, aliases and where it works.help: { command, aliases }names other words. The list leaves out a handler with a guard on its method or controller, since it runs no guards, and one whose newhidden: trueoption asks to be left out; named, either is shown.!helpfor words with no handler of their own lists their subcommands, and an unknown name or nothing to list gets a line saying so. It answers only after a prefix or mention, and an app's ownhelphandler always runs instead, with a warning at startup. WithreplyEmojithe reply begins with the theme'semojis.info.The reply follows the app's translations,
meocord.help.*in its catalog with@MeoCord({ i18n }), in the server's language, and is English otherwise; see MeoCord's own texts. A presenter's new optionalmessageHelp(help, message)method writes it instead, fromMessageHelp, what the built-in found.HandlerRegistry.messageHelp(message, query?)gives the same model to a help command of the app's own, with help on or off, andMessageHandlerEntry.hiddensays whether a handler asked to be left out.hiddenalso leaves a subcommand out of the usage listing a message naming only a parent gets.#246
6c46b07Thanks @l7aromeo! - A message that names only a command's leading words, such as!configwhenconfig set …andconfig get …exist, or an unknown subcommand, such as!config reset, gets the usage of each subcommand in reply, under aUsage:heading, one line per handler by its own pattern, where it got no reply. A handler whose pattern matches the message still runs, so aconfigorconfig {key}handler takes it as before. A subcommand with a guard, on its method or its controller, inherited ones included, is left out of the listing on purpose, since the listing runs no guards and must not name what a caller may be refused; it still answers its own usage when named, and a parent with nothing left to list gets no reply. App-wide guards do not filter the listing, as they do not filter a usage reply. The reply is aMessageUsageError, answered through the app's global filters and then the fallback, like any usage reply.#231
8395b05Thanks @l7aromeo! - A button's, select menu's or modal's customId pattern can type a param,{name:type}, withint,number,boolor words to choose from such as{order:asc|desc}, read by the parsers message commands use. The handler receives the value, such as a number for@Command('counter/{count:int}', CommandType.BUTTON), and its params are checked against the pattern when the code compiles;route(pattern).build()takes values of those types. A segment that is not a value of its type matches no route. Such a pattern used to be read as literal text, so it silently never matched; a type a customId cannot hold, such as{target:member}, now stops the bot where it is declared. Beside a text param in the same place, a typed one is tried first, and of two types the narrower (words to choose from, thenbool,int,number), whatever order they are declared in; and patterns whose typed segments take no value in common are different routes. For a route with a typed param,resolveRouteaddsvalues, the params as the handler receives them, besideparams, which stays their text; every other result is as it was. Frommeocord/common,RouteValues<Pattern>now gives each typed param the value of its type, such asnumberfor{count:int}, and an untyped param takes anyRouteValue, a string, number or bigint, as before;RouteParams<Pattern>names each param without its type.#239
a5868f4Thanks @l7aromeo! - A context menu handler can declare the kind of interaction its builder registers:UserContextMenuCommandInteractionfor a builder that callssetType(ApplicationCommandType.User), orMessageContextMenuCommandInteractionforMessage. It had to take the union of both, since declaring one failed to compile with "Unable to resolve signature of method decorator". The union still works. A builder's kind is a value TypeScript cannot read, so the bot checks it as it starts: a handler that declares the other kind stops it, naming both.meocord g co context-menu <name>generates a user context menu command with its handler typed to match, and--messagegenerates a message one. The context menu controller in a new project is typed the same way.
Patch Changes
#229
551c0ebThanks @l7aromeo! - A user context menu command and a message context menu command with the same name, which Discord allows, each reach their own@Commandhandler. The first handler declared under the name took both, so a message command could run the user command's handler.TestingModule.invokerefuses the other kind's interaction the same way, naming both kinds.#243
68638abThanks @l7aromeo! -meocord start --devexits 1 when the bot cannot log in, asmeocord start --proddoes, instead of watching on with the bot offline: a missing or refused token, refused intents, or Discord being unreachable is not something a code change fixes. It says so in one line, after the reason the bot gave. After any other exit, such as an error at startup or a crash once online, it keeps watching and saysThe application exited with code N; waiting for changes., then starts the bot again on the next rebuild. Withsharding, the shard manager ends the session the same way.#249
4af6d70Thanks @l7aromeo! - The package's homepage is https://meocord.dev, the documentation site, where npm links it, and a new application's README links MeoCord there.#240
b462777Thanks @l7aromeo! -module.invoke()checks an interaction's customId against every handler of the testing module, ranked as dispatch ranks them, as it already did for a message. A customId dispatch gives to another handler, such ascard/summarybesidecard/{id}, rejects naming the handler that runs, where it ran the named handler anyway. A handler declared under two patterns gets the params of the one dispatch picks, typed values included. A testing module whose controllers would stop the bot, such as two whose patterns match the same customIds, now makesinvokethrow the same startup error with a customId, asdispatchalready did; give each such controller its own module.#244
eef71c7Thanks @l7aromeo! - The editor documentation of the application, the config file and the remaining public helpers says what each is for, with examples that compile, and links the guide:MeoCordFactory,MeoCordApplication,@MeoCord,HandlerRegistryand its entry types,ShardContext,MeoCordConfig,ShardingConfig,CommandRegistrationConfig,RsbuildConfig, the providers andcreateToken/factoryProvider,Logger,OnReady/OnShutdown,CommandType,DeepPartial/DeepReadonlyand themeocord/eslintconfig.MetadataKeyis marked internal: it holds MeoCord's own reflect keys and is not part of the documented API.#226
5c14933Thanks @l7aromeo! - The JSDoc of every decorator inmeocord/decorator, and ofCooldownOptions,DeferOptionsandCommandBuilderOptions, is rewritten for the hover in your editor: a one-line summary, when to use it and what to use instead, how it works, where it runs in a call, and an example that compiles against the published types. The options of@Guard,@Interceptor,@Observer,@Validate,@Cooldownand@Deferare documented on each option, with its default.#236
01d92f6Thanks @l7aromeo! - The guide links in the JSDoc of the decorators and the pipeline types point to the 4.1 documentation, the version you installed, and to its pages as they are named: slash commands, buttons, selects and modals, and how a call runs.#241
51282feThanks @l7aromeo! - The editor documentation ofMessageCommandOptions,MessageHandlerOptions,route,Route,RouteParams,RouteValueandRouteValuessays what each is for, with an example that compiles, and links the guide.#234
4c9c1dcThanks @l7aromeo! - The editor hover for@MessageHandler,@ReactionHandler,ReactionHandlerAction,CommandNotFoundError,MessageUsageErrorand the message param types (ParamsOf,ParamRefsOf,EntityRef,MessageParamType,MessageParamTypes,CheckedParams,MessageScope,MessagePrefix,ReactionHandlerOptions,ReactionHandlerSettings,MessageUsageIssue,MessageParams) now says in a sentence what each is, when to use it and what to use instead, with an example that compiles against the published types.#230
1004d7bThanks @l7aromeo! - The JSDoc of the types and helpers a guard, interceptor, filter, pipe or observer works with is rewritten for the hover in your editor:ExecutionContext,GuardDeniedError,ValidationError,createMetadata,SetMetadata,applyDecorators,StageParams,Piped, the stage interfaces, the observer types, the Standard Schema types and the command builder types. Each has a one-line summary and when to use it, and each example compiles against the published types.#232
fcd3457Thanks @l7aromeo! - The JSDoc ofrespond, the theme API (useTheme,bindTheme,UseTheme,ThemeCache,Themeand the theme types), the errors a user is shown (UserError,CooldownError,CooldownStoreError), the presenter types, the translator and the cooldown stores now follows the JSDoc standard, for the hover in your editor and the API reference. Every example among them compiles against the published types: those that read aninteraction, a database or an app they did not declare are now complete, andMemoryCooldownStore,Theme,cooldownMessageandcooldownStoreMessagegain one.#235
ee38bcbThanks @l7aromeo! - The JSDoc ofmeocord/testing's mocks follows the standard in CONTRIBUTING.md:createMockInteraction,createMock,createMockUser,createMockClient,createMockGuild,createMockChannel,createMockMessage,createChatInputOptions,createModalFields,createDiscordError,createMockTheme,withTheme,createMockFn,isMockFunction,clearAllMocksandresetAllMocks, with the types they take and return. Each has a one-line summary, when to use it, and an example that compiles against the published package, and declares everything it uses.MockInstance's methods describe themselves on hover.#233
5f42ad2Thanks @l7aromeo! - The JSDoc ofmeocord/testing's module and inspection helpers follows the standard in CONTRIBUTING.md:MeoCordTestingModule,TestingModuleBuilder,TestingModuleand their options and results,getResponse,inspectHandler,createExecutionContext,resolveRoute,findRouteConflicts,expectCompleteCatalogandtestCooldownStore. Each has a one-line summary, when to use it, and an example that compiles against the published package, and every option documents itself, so the hover in your editor and the API reference say the same thing.#247
b31f281Thanks @l7aromeo! -bun run lintin an application prints nothing when the code is clean.meocord/eslintgives its import resolver the application's three tsconfigs, so each file resolves aliases through the tsconfig that includes it, and the resolver printedMultiple projects found, consider using a single tsconfig with references…on every run. It now sets the resolver'snoWarnOnMultipleProjects, since several projects are the intended setup. Existing applications get it by updating meocord; nothing in them changes.#238
dba5defThanks @l7aromeo! - A message command's usage reply reads right for every param type: a word of the wrong type is now"lots" is not a valid whole number, so an app's own type labelled with a noun such asemojireadsis not a valid emoji, where it readis not a emoji. Aboolparam is named ayes or no answer. A role deleted while a command's guards ran is named<@&id> is not a role in this server, and a value of an app's own type whoseEntityRefresolves to nothingis not a valid <label>, where both readis not a value of its type. AMessageParamType'slabelis the bare noun, such ashex colour, as its example now shows. A test that matches the old wording, such asis not a whole number, needs the new one.#250
873aeabThanks @l7aromeo! -MessageParamType's documentation link in your editor opens the message params page, which covers typed params and your own param types, rather than the message commands page.#225
c862b1fThanks @l7aromeo! - Importingmeocord/commonno longer computes the Redis script hash until aRedisCooldownStoreuses it. Each script's SHA1 is worked out the first time a store givenevalsharuns it, then kept, so an app that never uses Redis hashes nothing, and one withoutevalshanever needs the hash.#237
69ec4e8Thanks @l7aromeo! -getResponse(interaction).sentcounts only calls Discord accepted. A reply, update, edit or follow-up that Discord refused, such as a reply rejected with 10062 once the three seconds passed, used to count as sent, so a test of what the member sees after an expired interaction could pass while the member saw nothing. The refused call stays incalls, in the order it was made, and carries what it rejected with aserror, the new optional field ofResponseCall: every callrespond()makes, deferrals and modals included, is marked this way.