meocord 4.1.0 → 4.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # meocord
2
2
 
3
+ ## 4.1.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#454](https://github.com/meocord/meocord/pull/454) [`1f71fe1`](https://github.com/meocord/meocord/commit/1f71fe12b96c339bf3e1f19f714f24ebd8e7e853) Thanks [@l7aromeo](https://github.com/l7aromeo)! - A mock interaction's type guards, such as `isButton()` and `isRepliable()`, and its `inGuild()`, `inCachedGuild()` and `inRawGuild()` keep answering as discord.js does after `resetAllMocks()`. They returned `undefined` after a reset, so a mock made once for several tests, such as in `beforeAll`, failed every type check after the first test in a project that resets between tests, as a generated one does.
8
+
9
+ ## 4.1.1
10
+
11
+ ### Patch Changes
12
+
13
+ - [#424](https://github.com/meocord/meocord/pull/424) [`43b9454`](https://github.com/meocord/meocord/commit/43b945447262405f61cced6660cd1d2be881d4b8) Thanks [@l7aromeo](https://github.com/l7aromeo)! - A mock guild's `members.fetch({ user: ids })` now resolves to a collection of each of those members, found in the cache or made the way `members.fetch(id)` makes one. It resolved to an empty collection, so in a test a message command naming two or more members by ID that the guild hasn't cached refused them all as not members of the server, while one such member resolved. Mentioned members were not affected: they come from the message's mentions.
14
+
15
+ - [#422](https://github.com/meocord/meocord/pull/422) [`22daff2`](https://github.com/meocord/meocord/commit/22daff26ac4a694a8d70eace38a4c038d3cef0ef) Thanks [@l7aromeo](https://github.com/l7aromeo)! - `createMockClient()` is typed as a logged-in client, `DeepMocked<Client<true>>`, as the mock already behaves. Pass it straight to `createMockInteraction`, `createMockChannel`, `createMockUser` or `module.init({ ready: { client } })`: each of these failed to compile without a cast, since an interaction's client is `Client<true>`. `client.user` is no longer nullable, so `client.user!.id` can be `client.user.id`. Remove any `as unknown as Client<true>` cast on the mock.
16
+
17
+ - [#430](https://github.com/meocord/meocord/pull/430) [`1d0c0cf`](https://github.com/meocord/meocord/commit/1d0c0cf7d9755e5d24a0f218809a2f95fe403ccc) Thanks [@l7aromeo](https://github.com/l7aromeo)! - Mocks from `meocord/testing` now compute what discord.js computes from them, where they returned `undefined` or a placeholder object:
18
+
19
+ - **Lookups:** a manager's `resolve()` and `resolveId()` read its cache, so `guild.members.resolve(id)` finds a member given to `createMockGuild`. `guild.members.me` is the bot's member, the cached one or one with @everyone. A guild's roles and channels, and the guilds of a client's messages and interactions, belong where discord.js puts them, and everything in a guild shares its client.
20
+ - **Ranking and permissions:** `role.comparePositionTo()`, `channel.permissionsFor()`, `member.permissionsIn()` and an interaction's `appPermissions` compute from the roles, the channel's `permissionOverwrites` and the bot's member. Being real, they keep working after `resetAllMocks()`.
21
+ - **Messages:** `message.member` reads the guild's member cache, so a test that removes the author's member there gets `null`, as discord.js gives for an author it hasn't cached. A default message now caches its author and the author's member, as Discord's message event does. `message.mentions.has(user)` answers from what the content mentions.
22
+ - **Defaults:** a role is not hoisted, managed or mentionable, with no icon, tags or colours. A member's `joinedTimestamp` is when the mock was made, so `partial` is `false`. A message has no `reference`, `poll` or stickers. `avatarURL()` and `iconURL()` are `null` without an avatar or icon, `displayAvatarURL()` is Discord's default avatar, and a mock client `isReady()`.
23
+ - **User context menus:** `targetUser` is the user with `targetId`, the client's cached one or one made, and `targetMember` that user's member in a server. A `targetId` given later picks its user, and both stay assignable.
24
+
25
+ - [#431](https://github.com/meocord/meocord/pull/431) [`b24a0bc`](https://github.com/meocord/meocord/commit/b24a0bca78b72c602718a5a8f496251484f37bfe) Thanks [@l7aromeo](https://github.com/l7aromeo)! - A mock still reads some values discord.js computes as a truthy placeholder: a message's `editable`, `deletable`, `pinnable`, `crosspostable`, `bulkDeletable`, `hasThread` and `partial`, a member's `manageable`, `kickable`, `bannable` and `moderatable`, a role's `editable`, a channel's `viewable`, `manageable` and `deletable` and its thread and voice counterparts, and `partial` on users, channels and reactions. A test that reads one now gets a warning, once per run, that 5.0 computes it as discord.js does, and how to set it on the mock, such as `message.editable = false`, to test either way. A value the test sets is read without a warning.
26
+
27
+ `message.thread` is the thread the message's channel caches under the message's id, as discord.js reads it. Without one it is still a placeholder thread, with a warning that 5.0 gives `null` there.
28
+
29
+ - [#429](https://github.com/meocord/meocord/pull/429) [`961455d`](https://github.com/meocord/meocord/commit/961455d86534be61c2b22739240fa48d53564dd7) Thanks [@l7aromeo](https://github.com/l7aromeo)! - Mocks from `meocord/testing` now pass to one another, and to the testing module, without a cast:
30
+
31
+ - **A mock reached through a property that may be `null`** keeps its mock API, such as `message.member?.fetch.mockResolvedValue(member)` or `message.guild?.members.fetch`.
32
+ - **An overloaded method's mock** takes what any of its overloads takes or resolves to, such as `guild.members.fetch.mockResolvedValue(member)` and `channel.messages.fetch.mockResolvedValue(message)`, where only the list form compiled before.
33
+ - **`createMockInteraction` given `guild: null`, `member: null` or a DM channel** builds an interaction outside a server, typed so its `guild` and `member` may be `null`.
34
+ - **`createMockMessage`** is typed as discord.js emits a message, so `module.emit('messageCreate', createMockMessage())` compiles.
35
+ - **`createMockChannel(ThreadChannel)`** is typed as a public or private thread, as discord.js types every thread, so it fits an interaction's `channel`, a guild's channels and the `threadCreate` event.
36
+ - **`getResponse(interaction).calls[n].payload`** is typed by the call's `method`: after `call.method === 'reply'`, it is the reply's options. `ResponseCall` itself is unchanged, so code that builds or extends one compiles as before.
37
+
3
38
  ## 4.1.0
4
39
 
5
40
  ### Highlights
package/README.md CHANGED
@@ -15,17 +15,17 @@
15
15
 
16
16
  If you know NestJS, the shape will feel familiar.
17
17
 
18
- **Documentation:** [meocord.dev](https://meocord.dev/docs/4.1) · [Getting started](https://meocord.dev/docs/4.1/getting-started) · [API reference](https://meocord.dev/docs/4.1/api) · [Upgrading to 4.1](https://meocord.dev/docs/4.1/migrating) · [Changelog](https://meocord.dev/docs/4.1/changelog)
18
+ **Documentation:** [meocord.dev](https://meocord.dev/docs/latest) · [Getting started](https://meocord.dev/docs/latest/getting-started) · [API reference](https://meocord.dev/docs/latest/api) · [Upgrading to 4.1](https://meocord.dev/docs/latest/migrating) · [Changelog](https://meocord.dev/docs/latest/changelog)
19
19
 
20
20
  ## Features
21
21
 
22
- - **Controllers for every interaction** — [slash commands](https://meocord.dev/docs/4.1/slash-commands) and their subcommands, autocomplete, [buttons, selects and modals](https://meocord.dev/docs/4.1/components) routed by customId, context menus, message commands and reactions, each a decorated method.
23
- - **Message commands** — [commands typed in chat](https://meocord.dev/docs/4.1/message-commands), from a pattern such as `ban {target:member} {reason...?}`: typed params, flags and lists, a usage reply when a message does not fit, and built-in help.
24
- - **A request pipeline** — [guards](https://meocord.dev/docs/4.1/guards) decide whether a handler runs, interceptors wrap it, validation and pipes check its input, [cooldowns](https://meocord.dev/docs/4.1/cooldowns) limit how often it runs, and exception filters decide what the user is told.
22
+ - **Controllers for every interaction** — [slash commands](https://meocord.dev/docs/latest/slash-commands) and their subcommands, autocomplete, [buttons, selects and modals](https://meocord.dev/docs/latest/components) routed by customId, context menus, message commands and reactions, each a decorated method.
23
+ - **Message commands** — [commands typed in chat](https://meocord.dev/docs/latest/message-commands), from a pattern such as `ban {target:member} {reason...?}`: typed params, flags and lists, a usage reply when a message does not fit, and built-in help.
24
+ - **A request pipeline** — [guards](https://meocord.dev/docs/latest/guards) decide whether a handler runs, interceptors wrap it, validation and pipes check its input, [cooldowns](https://meocord.dev/docs/latest/cooldowns) limit how often it runs, and exception filters decide what the user is told.
25
25
  - **Dependency injection** — services, providers and lifecycle hooks, wired into controllers with no manual instantiation.
26
- - **Answers that fit the interaction** — `respond(interaction)` replies, edits or follows up from whatever state the interaction is in, styled by a presenter and a [theme](https://meocord.dev/docs/4.1/theming).
27
- - **Testing without Discord** — `meocord/testing` runs a handler through its whole pipeline, with [mocks](https://meocord.dev/docs/4.1/mocks) for every interaction type.
28
- - **A CLI** — `meocord create`, `build`, `start`, `register` and `generate`, with Rsbuild builds for development and production, sharding, and [self-contained builds](https://meocord.dev/docs/4.1/self-contained-builds) that deploy without `node_modules`.
26
+ - **Answers that fit the interaction** — `respond(interaction)` replies, edits or follows up from whatever state the interaction is in, styled by a presenter and a [theme](https://meocord.dev/docs/latest/theming).
27
+ - **Testing without Discord** — `meocord/testing` runs a handler through its whole pipeline, with [mocks](https://meocord.dev/docs/latest/mocks) for every interaction type.
28
+ - **A CLI** — `meocord create`, `build`, `start`, `register` and `generate`, with Rsbuild builds for development and production, sharding, and [self-contained builds](https://meocord.dev/docs/latest/self-contained-builds) that deploy without `node_modules`.
29
29
 
30
30
  ## Getting started
31
31
 
@@ -38,7 +38,7 @@ cp .env.example .env # then put your bot token in DISCORD_TOKEN
38
38
  npx meocord start --dev # development, restarting on every change
39
39
  ```
40
40
 
41
- The new project comes with a sample of each controller type, a guard, a presenter, a service and a spec for each. [Getting started](https://meocord.dev/docs/4.1/getting-started) walks through it, and [Your first command](https://meocord.dev/docs/4.1/first-command) adds one.
41
+ The new project comes with a sample of each controller type, a guard, a presenter, a service and a spec for each. [Getting started](https://meocord.dev/docs/latest/getting-started) walks through it, and [Your first command](https://meocord.dev/docs/latest/first-command) adds one.
42
42
 
43
43
  ## Example
44
44
 
@@ -77,18 +77,18 @@ export class GreetController {
77
77
  export default class App {}
78
78
  ```
79
79
 
80
- The command's options arrive as the handler's second argument. [Slash commands](https://meocord.dev/docs/4.1/slash-commands) covers options, subcommands and registration.
80
+ The command's options arrive as the handler's second argument. [Slash commands](https://meocord.dev/docs/latest/slash-commands) covers options, subcommands and registration.
81
81
 
82
82
  ## Documentation
83
83
 
84
- Everything else is on [meocord.dev](https://meocord.dev/docs/4.1), for each version:
84
+ Everything else is on [meocord.dev](https://meocord.dev/docs/latest), for each version:
85
85
 
86
- | To | Read |
87
- | ----------------------------------- | --------------------------------------------------------------- |
88
- | Learn MeoCord from the start | [Getting started](https://meocord.dev/docs/4.1/getting-started) |
89
- | Look up a decorator, type or helper | [API reference](https://meocord.dev/docs/4.1/api) |
90
- | Upgrade from 4.0, or from 3.x | [Upgrading](https://meocord.dev/docs/4.1/migrating) |
91
- | See what changed in each release | [Changelog](https://meocord.dev/docs/4.1/changelog) |
86
+ | To | Read |
87
+ | ----------------------------------- | ------------------------------------------------------------------ |
88
+ | Learn MeoCord from the start | [Getting started](https://meocord.dev/docs/latest/getting-started) |
89
+ | Look up a decorator, type or helper | [API reference](https://meocord.dev/docs/latest/api) |
90
+ | Upgrade from 4.0, or from 3.x | [Upgrading](https://meocord.dev/docs/latest/migrating) |
91
+ | See what changed in each release | [Changelog](https://meocord.dev/docs/latest/changelog) |
92
92
 
93
93
  ## Support
94
94
 
@@ -108,28 +108,28 @@ These sections moved to meocord.dev. Their headings stay here so that links from
108
108
 
109
109
  ### Theming
110
110
 
111
- [Theming](https://meocord.dev/docs/4.1/theming) on meocord.dev.
111
+ [Theming](https://meocord.dev/docs/latest/theming) on meocord.dev.
112
112
 
113
113
  ### Themes per server and per user
114
114
 
115
- [Themes per server and per user](https://meocord.dev/docs/4.1/theming#per-server-and-per-user) on meocord.dev.
115
+ [Themes per server and per user](https://meocord.dev/docs/latest/theming#per-server-and-per-user) on meocord.dev.
116
116
 
117
117
  ### Adding tokens of your own
118
118
 
119
- [Adding tokens of your own](https://meocord.dev/docs/4.1/theming#adding-tokens-of-your-own) on meocord.dev.
119
+ [Adding tokens of your own](https://meocord.dev/docs/latest/theming#adding-tokens-of-your-own) on meocord.dev.
120
120
 
121
121
  ### Where calls are counted
122
122
 
123
- [Where calls are counted](https://meocord.dev/docs/4.1/cooldowns#where-calls-are-counted) on meocord.dev.
123
+ [Where calls are counted](https://meocord.dev/docs/latest/cooldowns#where-calls-are-counted) on meocord.dev.
124
124
 
125
125
  ### Store recipes
126
126
 
127
- [Cooldown stores](https://meocord.dev/docs/4.1/recipes/cooldown-stores) on meocord.dev.
127
+ [Cooldown stores](https://meocord.dev/docs/latest/recipes/cooldown-stores) on meocord.dev.
128
128
 
129
129
  ### Stack traces
130
130
 
131
- [Stack traces](https://meocord.dev/docs/4.1/configuration#stack-traces) on meocord.dev.
131
+ [Stack traces](https://meocord.dev/docs/latest/configuration#stack-traces) on meocord.dev.
132
132
 
133
133
  ### Running tests
134
134
 
135
- [Running tests](https://meocord.dev/docs/4.1/testing#running-tests) on meocord.dev.
135
+ [Running tests](https://meocord.dev/docs/latest/testing#running-tests) on meocord.dev.
@@ -119,7 +119,7 @@ let problem;
119
119
  try {
120
120
  // Called through a variable so a bundler does not try to resolve the path while building the
121
121
  // application; the file is only there once the build is done.
122
- const load = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('_shared/controller.decorator-Ds7dj8uZ.cjs', document.baseURI).href)));
122
+ const load = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('_shared/controller.decorator-BywwkU9O.cjs', document.baseURI).href)));
123
123
  const loaded = load(compiledPath);
124
124
  return loaded.default ?? loaded;
125
125
  } catch (error) {
@@ -346,6 +346,12 @@ const warned = new Set();
346
346
  */ function warnDeprecatedBehaviour(logger, old, outcome, replacement) {
347
347
  warnOnce(logger, `${old} is deprecated; in the next major version (5.0) it ${outcome}. Use ${replacement} instead.`);
348
348
  }
349
+ /**
350
+ * Warns once per run that a mock reads `value` as a placeholder where discord.js computes it, saying what 5.0 gives
351
+ * and how to set it.
352
+ */ function warnPlaceholder(logger, value, outcome, how) {
353
+ warnOnce(logger, `${value} reads a placeholder here; in the next major version (5.0) ${outcome}. ${how}`);
354
+ }
349
355
  function warnOnce(logger, text) {
350
356
  if (warned.has(text)) return;
351
357
  warned.add(text);
@@ -5142,6 +5148,7 @@ exports.useTheme = useTheme;
5142
5148
  exports.userWords = userWords;
5143
5149
  exports.warnDeprecated = warnDeprecated;
5144
5150
  exports.warnDeprecatedBehaviour = warnDeprecatedBehaviour;
5151
+ exports.warnPlaceholder = warnPlaceholder;
5145
5152
  exports.withRelease = withRelease;
5146
5153
  exports.withSendableFiles = withSendableFiles;
5147
5154
  exports.withoutFiles = withoutFiles;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var controller_decorator = require('./controller.decorator-Ds7dj8uZ.cjs');
3
+ var controller_decorator = require('./controller.decorator-BywwkU9O.cjs');
4
4
  require('reflect-metadata');
5
5
  var node_async_hooks = require('node:async_hooks');
6
6
  var inversify = require('inversify');
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var node_crypto = require('node:crypto');
4
- var controller_decorator = require('./controller.decorator-Ds7dj8uZ.cjs');
4
+ var controller_decorator = require('./controller.decorator-BywwkU9O.cjs');
5
5
 
6
6
  /** The `fatal` code of a shard whose app MeoCord refused, which every shard would refuse alike. */ const REFUSED_CODE = 'Refused';
7
7
  /** Whether an IPC message is one of MeoCord's own, rather than one of discord.js's. */ function isShardMessage(message) {
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var discord_js = require('discord.js');
4
- var controller_decorator = require('./controller.decorator-Ds7dj8uZ.cjs');
5
- var providers = require('./providers-BSL8vml4.cjs');
4
+ var controller_decorator = require('./controller.decorator-BywwkU9O.cjs');
5
+ var providers = require('./providers-BMMLp2SN.cjs');
6
6
  var enum_index = require('../enum/index.cjs');
7
- var translateError = require('./translate-error-Zwll3hC2.cjs');
7
+ var translateError = require('./translate-error-BnM8FbSH.cjs');
8
8
 
9
9
  /**
10
10
  * Every customId-pattern route of the given controllers, most specific first, read from metadata alone.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var controller_decorator = require('./controller.decorator-Ds7dj8uZ.cjs');
3
+ var controller_decorator = require('./controller.decorator-BywwkU9O.cjs');
4
4
  var discord_js = require('discord.js');
5
5
 
6
6
  /** The longest customId Discord accepts. */ const MAX_CUSTOM_ID_LENGTH = 100;
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var controller_decorator = require('../_shared/controller.decorator-Ds7dj8uZ.cjs');
3
+ var controller_decorator = require('../_shared/controller.decorator-BywwkU9O.cjs');
4
4
  require('reflect-metadata');
5
- var translateError = require('../_shared/translate-error-Zwll3hC2.cjs');
6
- var shardedCooldownStore = require('../_shared/sharded-cooldown-store-BGfooXEO.cjs');
5
+ var translateError = require('../_shared/translate-error-BnM8FbSH.cjs');
6
+ var shardedCooldownStore = require('../_shared/sharded-cooldown-store-B65iaiAy.cjs');
7
7
  require('../enum/index.cjs');
8
8
  require('discord.js');
9
9
  require('path');
@@ -1,14 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  require('reflect-metadata');
4
- var providers = require('../_shared/providers-BSL8vml4.cjs');
4
+ var providers = require('../_shared/providers-BMMLp2SN.cjs');
5
5
  var inversify = require('inversify');
6
6
  var discord_js = require('discord.js');
7
- var controller_decorator = require('../_shared/controller.decorator-Ds7dj8uZ.cjs');
7
+ var controller_decorator = require('../_shared/controller.decorator-BywwkU9O.cjs');
8
8
  require('node:crypto');
9
- var shardedCooldownStore = require('../_shared/sharded-cooldown-store-BGfooXEO.cjs');
9
+ var shardedCooldownStore = require('../_shared/sharded-cooldown-store-B65iaiAy.cjs');
10
10
  var path$1 = require('path');
11
- var startupRoots = require('../_shared/startup-roots-H1ssJOrz.cjs');
11
+ var startupRoots = require('../_shared/startup-roots-lFc69AxC.cjs');
12
12
  var enum_index = require('../enum/index.cjs');
13
13
  var node_fs = require('node:fs');
14
14
  var path = require('node:path');
@@ -23,7 +23,7 @@ require('dayjs/plugin/utc.js');
23
23
  require('dayjs/plugin/timezone.js');
24
24
  require('module');
25
25
  require('chalk');
26
- require('../_shared/translate-error-Zwll3hC2.cjs');
26
+ require('../_shared/translate-error-BnM8FbSH.cjs');
27
27
 
28
28
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
29
29
 
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  require('reflect-metadata');
4
- var providers = require('../_shared/providers-BSL8vml4.cjs');
5
- var controller_decorator = require('../_shared/controller.decorator-Ds7dj8uZ.cjs');
4
+ var providers = require('../_shared/providers-BMMLp2SN.cjs');
5
+ var controller_decorator = require('../_shared/controller.decorator-BywwkU9O.cjs');
6
6
  var inversify = require('inversify');
7
7
  require('node:async_hooks');
8
8
  require('../enum/index.cjs');