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
package/dist/cli.json
CHANGED
|
@@ -18,26 +18,26 @@
|
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"discord.js": "^14.27.0",
|
|
21
|
-
"dotenv": "^18.0.
|
|
21
|
+
"dotenv": "^18.0.7",
|
|
22
22
|
"meocord": "^{{version}}"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@eslint/js": "^10.0.1",
|
|
26
|
-
"@types/node": "^26.6.
|
|
27
|
-
"@typescript-eslint/parser": "^8.71.
|
|
28
|
-
"@vitest/coverage-istanbul": "^5.0.
|
|
29
|
-
"eslint": "^10.
|
|
26
|
+
"@types/node": "^26.6.5",
|
|
27
|
+
"@typescript-eslint/parser": "^8.71.2",
|
|
28
|
+
"@vitest/coverage-istanbul": "^5.0.4",
|
|
29
|
+
"eslint": "^10.12.0",
|
|
30
30
|
"eslint-config-prettier": "^10.1.8",
|
|
31
31
|
"eslint-import-resolver-typescript": "^4.4.5",
|
|
32
32
|
"eslint-plugin-import-x": "^4.17.1",
|
|
33
|
-
"eslint-plugin-prettier": "^5.5.
|
|
33
|
+
"eslint-plugin-prettier": "^5.5.7",
|
|
34
34
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
35
35
|
"globals": "^17.13.0",
|
|
36
|
-
"prettier": "^3.9.
|
|
36
|
+
"prettier": "^3.9.10",
|
|
37
37
|
"reflect-metadata": "^0.2.2",
|
|
38
38
|
"typescript": "^6.0.3",
|
|
39
|
-
"typescript-eslint": "^8.71.
|
|
39
|
+
"typescript-eslint": "^8.71.2",
|
|
40
40
|
"unplugin-swc": "^2.0.0",
|
|
41
|
-
"vitest": "^5.0.
|
|
41
|
+
"vitest": "^5.0.4"
|
|
42
42
|
}
|
|
43
43
|
}
|
|
@@ -11,8 +11,9 @@ async function bootstrap() {
|
|
|
11
11
|
logger.log('Application started')
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
// An error MeoCord explained, such as an app it refuses or a token Discord refused, is already logged
|
|
14
|
+
// An error MeoCord explained, such as an app it refuses or a token Discord refused, is already logged, with the exit code set
|
|
15
15
|
bootstrap().catch(error => {
|
|
16
|
-
if (
|
|
16
|
+
if (isExplainedError(error)) return
|
|
17
|
+
logger.error('Error during startup:', error)
|
|
17
18
|
process.exitCode = 1
|
|
18
19
|
})
|
|
@@ -4,20 +4,22 @@ import { Argument } from 'commander';
|
|
|
4
4
|
import { ControllerType } from '../enum/controller.enum.js';
|
|
5
5
|
import { ControllerGeneratorHelper } from './helper/controller-generator.helper.js';
|
|
6
6
|
import { Logger } from '../common/logger.js';
|
|
7
|
-
import '../
|
|
8
|
-
import '../core/theme-validation.js';
|
|
7
|
+
import '../common/theme.js';
|
|
9
8
|
import '../common/decorator.js';
|
|
10
9
|
import 'reflect-metadata';
|
|
11
10
|
import 'discord.js';
|
|
11
|
+
import '../common/deprecation.js';
|
|
12
12
|
import '../common/response/response-state.js';
|
|
13
|
+
import '../core/theme-scope.js';
|
|
13
14
|
import '../common/errors.js';
|
|
15
|
+
import '../common/cooldown-store.js';
|
|
14
16
|
import 'node:crypto';
|
|
15
17
|
import '../decorator/controller.decorator.js';
|
|
16
18
|
import '../core/scalar-types.js';
|
|
17
|
-
import '
|
|
18
|
-
import 'node:url';
|
|
19
|
+
import '../util/refusal.util.js';
|
|
19
20
|
import '../common/translator.js';
|
|
20
21
|
import '../common/meocord-text.js';
|
|
22
|
+
import '../core/theme-resolvers.js';
|
|
21
23
|
import { ServiceGeneratorHelper } from './helper/service-generator.helper.js';
|
|
22
24
|
import { GuardGeneratorHelper } from './helper/guard-generator.helper.js';
|
|
23
25
|
import { InterceptorGeneratorHelper } from './helper/interceptor-generator.helper.js';
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { Logger } from '../../common/logger.js';
|
|
3
|
-
import '../../
|
|
4
|
-
import '../../core/theme-validation.js';
|
|
3
|
+
import '../../common/theme.js';
|
|
5
4
|
import '../../common/decorator.js';
|
|
6
5
|
import 'reflect-metadata';
|
|
7
6
|
import 'discord.js';
|
|
7
|
+
import '../../common/deprecation.js';
|
|
8
8
|
import '../../common/response/response-state.js';
|
|
9
|
+
import '../../core/theme-scope.js';
|
|
9
10
|
import '../../common/errors.js';
|
|
11
|
+
import '../../common/cooldown-store.js';
|
|
10
12
|
import 'node:crypto';
|
|
11
13
|
import '../../decorator/controller.decorator.js';
|
|
12
14
|
import '../../core/scalar-types.js';
|
|
13
|
-
import '
|
|
14
|
-
import 'node:url';
|
|
15
|
+
import '../../util/refusal.util.js';
|
|
15
16
|
import '../../common/translator.js';
|
|
16
17
|
import '../../common/meocord-text.js';
|
|
18
|
+
import '../../core/theme-resolvers.js';
|
|
17
19
|
import { validateAndFormatName, assertFilesAbsent, buildTemplate, createDirectoryIfNotExists, writeFiles } from '../../util/generator-cli.util.js';
|
|
18
20
|
|
|
19
21
|
class FilterGeneratorHelper {
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { Logger } from '../../common/logger.js';
|
|
3
|
-
import '../../
|
|
4
|
-
import '../../core/theme-validation.js';
|
|
3
|
+
import '../../common/theme.js';
|
|
5
4
|
import '../../common/decorator.js';
|
|
6
5
|
import 'reflect-metadata';
|
|
7
6
|
import 'discord.js';
|
|
7
|
+
import '../../common/deprecation.js';
|
|
8
8
|
import '../../common/response/response-state.js';
|
|
9
|
+
import '../../core/theme-scope.js';
|
|
9
10
|
import '../../common/errors.js';
|
|
11
|
+
import '../../common/cooldown-store.js';
|
|
10
12
|
import 'node:crypto';
|
|
11
13
|
import '../../decorator/controller.decorator.js';
|
|
12
14
|
import '../../core/scalar-types.js';
|
|
13
|
-
import '
|
|
14
|
-
import 'node:url';
|
|
15
|
+
import '../../util/refusal.util.js';
|
|
15
16
|
import '../../common/translator.js';
|
|
16
17
|
import '../../common/meocord-text.js';
|
|
18
|
+
import '../../core/theme-resolvers.js';
|
|
17
19
|
import { validateAndFormatName, assertFilesAbsent, buildTemplate, createDirectoryIfNotExists, writeFiles } from '../../util/generator-cli.util.js';
|
|
18
20
|
|
|
19
21
|
class GuardGeneratorHelper {
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { Logger } from '../../common/logger.js';
|
|
3
|
-
import '../../
|
|
4
|
-
import '../../core/theme-validation.js';
|
|
3
|
+
import '../../common/theme.js';
|
|
5
4
|
import '../../common/decorator.js';
|
|
6
5
|
import 'reflect-metadata';
|
|
7
6
|
import 'discord.js';
|
|
7
|
+
import '../../common/deprecation.js';
|
|
8
8
|
import '../../common/response/response-state.js';
|
|
9
|
+
import '../../core/theme-scope.js';
|
|
9
10
|
import '../../common/errors.js';
|
|
11
|
+
import '../../common/cooldown-store.js';
|
|
10
12
|
import 'node:crypto';
|
|
11
13
|
import '../../decorator/controller.decorator.js';
|
|
12
14
|
import '../../core/scalar-types.js';
|
|
13
|
-
import '
|
|
14
|
-
import 'node:url';
|
|
15
|
+
import '../../util/refusal.util.js';
|
|
15
16
|
import '../../common/translator.js';
|
|
16
17
|
import '../../common/meocord-text.js';
|
|
18
|
+
import '../../core/theme-resolvers.js';
|
|
17
19
|
import { validateAndFormatName, assertFilesAbsent, buildTemplate, createDirectoryIfNotExists, writeFiles } from '../../util/generator-cli.util.js';
|
|
18
20
|
|
|
19
21
|
class InterceptorGeneratorHelper {
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { Logger } from '../../common/logger.js';
|
|
3
|
-
import '../../
|
|
4
|
-
import '../../core/theme-validation.js';
|
|
3
|
+
import '../../common/theme.js';
|
|
5
4
|
import '../../common/decorator.js';
|
|
6
5
|
import 'reflect-metadata';
|
|
7
6
|
import 'discord.js';
|
|
7
|
+
import '../../common/deprecation.js';
|
|
8
8
|
import '../../common/response/response-state.js';
|
|
9
|
+
import '../../core/theme-scope.js';
|
|
9
10
|
import '../../common/errors.js';
|
|
11
|
+
import '../../common/cooldown-store.js';
|
|
10
12
|
import 'node:crypto';
|
|
11
13
|
import '../../decorator/controller.decorator.js';
|
|
12
14
|
import '../../core/scalar-types.js';
|
|
13
|
-
import '
|
|
14
|
-
import 'node:url';
|
|
15
|
+
import '../../util/refusal.util.js';
|
|
15
16
|
import '../../common/translator.js';
|
|
16
17
|
import '../../common/meocord-text.js';
|
|
18
|
+
import '../../core/theme-resolvers.js';
|
|
17
19
|
import { validateAndFormatName, assertFilesAbsent, buildTemplate, createDirectoryIfNotExists, writeFiles } from '../../util/generator-cli.util.js';
|
|
18
20
|
|
|
19
21
|
class ObserverGeneratorHelper {
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { Logger } from '../../common/logger.js';
|
|
3
|
-
import '../../
|
|
4
|
-
import '../../core/theme-validation.js';
|
|
3
|
+
import '../../common/theme.js';
|
|
5
4
|
import '../../common/decorator.js';
|
|
6
5
|
import 'reflect-metadata';
|
|
7
6
|
import 'discord.js';
|
|
7
|
+
import '../../common/deprecation.js';
|
|
8
8
|
import '../../common/response/response-state.js';
|
|
9
|
+
import '../../core/theme-scope.js';
|
|
9
10
|
import '../../common/errors.js';
|
|
11
|
+
import '../../common/cooldown-store.js';
|
|
10
12
|
import 'node:crypto';
|
|
11
13
|
import '../../decorator/controller.decorator.js';
|
|
12
14
|
import '../../core/scalar-types.js';
|
|
13
|
-
import '
|
|
14
|
-
import 'node:url';
|
|
15
|
+
import '../../util/refusal.util.js';
|
|
15
16
|
import '../../common/translator.js';
|
|
16
17
|
import '../../common/meocord-text.js';
|
|
18
|
+
import '../../core/theme-resolvers.js';
|
|
17
19
|
import { validateAndFormatName, assertFilesAbsent, buildTemplate, createDirectoryIfNotExists, writeFiles } from '../../util/generator-cli.util.js';
|
|
18
20
|
|
|
19
21
|
class PipeGeneratorHelper {
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { Logger } from '../../common/logger.js';
|
|
3
|
-
import '../../
|
|
4
|
-
import '../../core/theme-validation.js';
|
|
3
|
+
import '../../common/theme.js';
|
|
5
4
|
import '../../common/decorator.js';
|
|
6
5
|
import 'reflect-metadata';
|
|
7
6
|
import 'discord.js';
|
|
7
|
+
import '../../common/deprecation.js';
|
|
8
8
|
import '../../common/response/response-state.js';
|
|
9
|
+
import '../../core/theme-scope.js';
|
|
9
10
|
import '../../common/errors.js';
|
|
11
|
+
import '../../common/cooldown-store.js';
|
|
10
12
|
import 'node:crypto';
|
|
11
13
|
import '../../decorator/controller.decorator.js';
|
|
12
14
|
import '../../core/scalar-types.js';
|
|
13
|
-
import '
|
|
14
|
-
import 'node:url';
|
|
15
|
+
import '../../util/refusal.util.js';
|
|
15
16
|
import '../../common/translator.js';
|
|
16
17
|
import '../../common/meocord-text.js';
|
|
18
|
+
import '../../core/theme-resolvers.js';
|
|
17
19
|
import { validateAndFormatName, assertFilesAbsent, buildTemplate, createDirectoryIfNotExists, writeFiles } from '../../util/generator-cli.util.js';
|
|
18
20
|
|
|
19
21
|
class ServiceGeneratorHelper {
|
package/dist/esm/bin/meocord.js
CHANGED
|
@@ -3,25 +3,29 @@ import path from 'path';
|
|
|
3
3
|
import { createRsbuild } from '@rsbuild/core';
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
5
|
import { Logger } from '../common/logger.js';
|
|
6
|
-
import '../
|
|
7
|
-
import '../core/theme-validation.js';
|
|
6
|
+
import '../common/theme.js';
|
|
8
7
|
import '../common/decorator.js';
|
|
9
8
|
import 'reflect-metadata';
|
|
10
9
|
import 'discord.js';
|
|
10
|
+
import '../common/deprecation.js';
|
|
11
11
|
import '../common/response/response-state.js';
|
|
12
|
+
import '../core/theme-scope.js';
|
|
12
13
|
import '../common/errors.js';
|
|
14
|
+
import '../common/cooldown-store.js';
|
|
13
15
|
import '../decorator/controller.decorator.js';
|
|
14
16
|
import '../core/scalar-types.js';
|
|
15
|
-
import
|
|
16
|
-
import 'node:url';
|
|
17
|
+
import '../util/refusal.util.js';
|
|
17
18
|
import '../common/translator.js';
|
|
18
19
|
import '../common/meocord-text.js';
|
|
20
|
+
import '../core/theme-resolvers.js';
|
|
19
21
|
import { spawn } from 'node:child_process';
|
|
22
|
+
import { constants } from 'node:os';
|
|
20
23
|
import { capitalize } from 'lodash-es';
|
|
21
24
|
import wait from '../util/wait.util.js';
|
|
22
25
|
import { GeneratorCLI } from './generator.js';
|
|
23
26
|
import { runtimePrefixFor, AppGeneratorHelper } from './helper/app-generator.helper.js';
|
|
24
27
|
import { makeInitialCommit } from './helper/initial-commit.helper.js';
|
|
28
|
+
import * as fs from 'node:fs';
|
|
25
29
|
import { setEnvironment, compileAndValidateConfig, validateRunConfig, validateDiscordToken, checkSourceConfig, reportConfigProblem } from '../util/common.util.js';
|
|
26
30
|
import { Command } from 'commander';
|
|
27
31
|
import { execSync } from 'child_process';
|
|
@@ -37,11 +41,11 @@ import { isDevRunnerMessage, DEV_RUNNER_ENV } from '../util/dev-runner.util.js';
|
|
|
37
41
|
import packageJson from '../package.json.js';
|
|
38
42
|
import { fileURLToPath } from 'url';
|
|
39
43
|
import { assertNoWebpackHook, createRsbuildConfig, optionalExternalConflicts, optionalExternalNames } from '../build/rsbuild-config.js';
|
|
40
|
-
import { createNativeExternals, packageNameOfRequest, installedPackages, copyPackagesInto, bundledModuleFiles, assertNoBundledNativeAddons, findBundledNativeAddons } from '../build/native-addons.js';
|
|
44
|
+
import { createNativeExternals, packageNameOfRequest, installedPackages, copyPackagesInto, bundledModuleFiles, assertNoBundledNativeAddons, findBundledNativeAddons, otherCopiesWarning } from '../build/native-addons.js';
|
|
41
45
|
import { writePlatformManifest, PLATFORM_MANIFEST } from '../util/platform.util.js';
|
|
42
46
|
import { loadMeoCordSourceConfig } from '../util/meocord-source-config.util.js';
|
|
43
47
|
import { loadMeoCordConfig } from '../util/meocord-config-loader.util.js';
|
|
44
|
-
import { FORCE_REGISTER_ENV, REGISTER_ONLY_ENV, REGISTER_GUILD_ENV } from '../util/registration-mode.util.js';
|
|
48
|
+
import { FORCE_REGISTER_ENV, REGISTER_ONLY_ENV, REGISTER_GUILD_ENV, REGISTER_MODE_ENV } from '../util/registration-mode.util.js';
|
|
45
49
|
|
|
46
50
|
const __filename$1 = fileURLToPath(import.meta.url);
|
|
47
51
|
const __dirname$1 = path.dirname(__filename$1);
|
|
@@ -116,18 +120,22 @@ const UNDECOMPOSED = {
|
|
|
116
120
|
*/ function appDirectoryName(appName) {
|
|
117
121
|
return appName.normalize('NFKD').replace(/\p{M}+/gu, '').replace(/[ßẞæÆœŒøØłŁđĐþÞ]/g, (letter)=>UNDECOMPOSED[letter]).replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
118
122
|
}
|
|
123
|
+
/** How long watch mode waits after the last save to a file it reloads from before reloading. */ const RELOAD_DEBOUNCE_MS = 300;
|
|
124
|
+
/** The name watch mode taps the compiler's hooks under. */ const WATCH_HOOK_NAME = 'MeoCordWatch';
|
|
125
|
+
/** What a shell adds to a signal's number for the exit code of a process that signal ended. */ const SIGNAL_EXIT_BASE = 128;
|
|
119
126
|
/** A Command Line Interface (CLI) for managing the MeoCord application. */ class MeoCordCLI {
|
|
120
127
|
/**
|
|
121
128
|
* Configures and runs the MeoCord CLI.
|
|
122
129
|
*/ async run() {
|
|
123
|
-
this.program().
|
|
130
|
+
this.program().parse(process.argv);
|
|
124
131
|
}
|
|
125
132
|
/**
|
|
126
133
|
* The CLI's commands, options and arguments, configured but not parsed: what `run` parses, and what the build
|
|
127
134
|
* describes in `dist/cli.json`, so the two cannot differ.
|
|
128
135
|
*/ program() {
|
|
129
136
|
let program = new Command();
|
|
130
|
-
|
|
137
|
+
// Before any command is added: commander copies it to each command as the command is made
|
|
138
|
+
program.name(this.appName.toLowerCase()).description(`CLI for managing the ${this.appName} application`).version(this.version).showHelpAfterError();
|
|
131
139
|
program.command('show').description('Display information').option('-w, --warranty', 'Display warranty disclaimer').option('-c, --license', 'Display license').action((options)=>{
|
|
132
140
|
if (!options.warranty && !options.license) {
|
|
133
141
|
const show = `${program.name()} show`;
|
|
@@ -438,6 +446,9 @@ copies or substantial portions of the Software.
|
|
|
438
446
|
// A safety net behind the externals function: a native addon that still reached the
|
|
439
447
|
// bundle would run on this machine -- through its node_modules -- and fail in production.
|
|
440
448
|
assertNoBundledNativeAddons(findBundledNativeAddons(bundledFiles, this.projectRoot));
|
|
449
|
+
for (const [name, others] of natives.otherCopies){
|
|
450
|
+
this.logger.warn(otherCopiesWarning(name, natives.found.get(name).dir, others, this.projectRoot));
|
|
451
|
+
}
|
|
441
452
|
this.packDependencies(meocordConfig, natives.found);
|
|
442
453
|
} else if (!meocordConfig?.bundleDependencies) {
|
|
443
454
|
this.removePackedOutputs();
|
|
@@ -563,7 +574,7 @@ copies or substantial portions of the Software.
|
|
|
563
574
|
this.appEnv[REGISTER_ONLY_ENV] = '1';
|
|
564
575
|
this.appEnv[FORCE_REGISTER_ENV] = '1';
|
|
565
576
|
if (guild) this.appEnv[REGISTER_GUILD_ENV] = guild;
|
|
566
|
-
const child = this.spawnApp().on('exit', (code)=>process.exit(code
|
|
577
|
+
const child = this.spawnApp().on('exit', (code, signal)=>process.exit(this.exitCodeOf(code, signal, 1)));
|
|
567
578
|
this.relayStopSignals(()=>child);
|
|
568
579
|
}
|
|
569
580
|
/**
|
|
@@ -581,6 +592,7 @@ copies or substantial portions of the Software.
|
|
|
581
592
|
const kind = request();
|
|
582
593
|
if (kind === 'duplicate') return;
|
|
583
594
|
if (kind === 'first') stopping?.();
|
|
595
|
+
this.stopRelayed = true;
|
|
584
596
|
const child = app();
|
|
585
597
|
if (!stillRunning(child)) {
|
|
586
598
|
if (kind === 'repeat') process.exit(1);
|
|
@@ -598,6 +610,15 @@ copies or substantial portions of the Software.
|
|
|
598
610
|
}
|
|
599
611
|
}
|
|
600
612
|
/**
|
|
613
|
+
* The code the CLI exits with once the application has: its own, or for one a signal ended that the CLI didn't pass
|
|
614
|
+
* on, 128 plus the signal's number, as a shell gives, so a bot killed from outside doesn't read as a clean exit.
|
|
615
|
+
* @param fallback - For an application that a stop the CLI passed on ended without a code.
|
|
616
|
+
*/ exitCodeOf(code, signal, fallback) {
|
|
617
|
+
if (code !== null) return code;
|
|
618
|
+
const number = signal ? constants.signals[signal] : undefined;
|
|
619
|
+
return number !== undefined && !this.stopRelayed ? SIGNAL_EXIT_BASE + number : fallback;
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
601
622
|
* Replaces the running application once it has exited, since two would contend for one gateway session. Builds that
|
|
602
623
|
* finish meanwhile start nothing more: the replacement runs `dist/main.js` as it stands at launch, the latest build.
|
|
603
624
|
* @param build - The digest of the build asking for it; the output the running bot was launched from leaves it running.
|
|
@@ -672,7 +693,7 @@ copies or substantial portions of the Software.
|
|
|
672
693
|
const { command, args } = buildAppCommand(this.runtime, this.mainJSPath, {
|
|
673
694
|
sourceMaps
|
|
674
695
|
});
|
|
675
|
-
|
|
696
|
+
const child = spawn(command, args, {
|
|
676
697
|
cwd: this.projectRoot,
|
|
677
698
|
env: {
|
|
678
699
|
...this.inheritedEnv,
|
|
@@ -680,6 +701,8 @@ copies or substantial portions of the Software.
|
|
|
680
701
|
...process.env.NODE_ENV !== undefined && {
|
|
681
702
|
NODE_ENV: process.env.NODE_ENV
|
|
682
703
|
},
|
|
704
|
+
// And where it registers, which a bundle can't read from NODE_ENV: bundleDependencies writes in the build's mode
|
|
705
|
+
[REGISTER_MODE_ENV]: process.env.NODE_ENV === 'development' ? 'development' : 'production',
|
|
683
706
|
...this.appEnv,
|
|
684
707
|
...devRunner && {
|
|
685
708
|
[DEV_RUNNER_ENV]: '1'
|
|
@@ -692,6 +715,16 @@ copies or substantial portions of the Software.
|
|
|
692
715
|
'ipc'
|
|
693
716
|
] : 'inherit'
|
|
694
717
|
});
|
|
718
|
+
// A runtime that can't be started, such as a path that isn't there, is reported as an event, past any caller's try.
|
|
719
|
+
// So is a signal or a message the running application couldn't be sent; its exit, when it comes, still decides the code
|
|
720
|
+
child.on('error', (error)=>{
|
|
721
|
+
if (child.pid !== undefined) {
|
|
722
|
+
return this.logger.error(`Could not signal or message the running application (process ${child.pid}): ${error.message}`);
|
|
723
|
+
}
|
|
724
|
+
this.logger.error(`Failed to start: ${command} could not be run: ${error.message}`);
|
|
725
|
+
process.exit(1);
|
|
726
|
+
});
|
|
727
|
+
return child;
|
|
695
728
|
}
|
|
696
729
|
/**
|
|
697
730
|
* Starts the MeoCord application in development mode with live updates.
|
|
@@ -702,28 +735,41 @@ copies or substantial portions of the Software.
|
|
|
702
735
|
await this.compileConfig({
|
|
703
736
|
mode: 'development'
|
|
704
737
|
});
|
|
705
|
-
let isRunning = false;
|
|
706
738
|
let watching;
|
|
739
|
+
// Settles once the running build has emitted, whatever its errors; a reload waits for it before replacing the build
|
|
740
|
+
let built = Promise.resolve();
|
|
707
741
|
// The new bundler is made, its plugins set up and its config resolved, before the running build is closed: a
|
|
708
742
|
// config whose rsbuild hook or plugin throws leaves that build watching the sources, and the bot it started running
|
|
709
743
|
const watch = async ()=>{
|
|
710
|
-
const { rsbuild
|
|
744
|
+
const { rsbuild } = await this.createBundler('development');
|
|
711
745
|
await rsbuild.initConfigs({
|
|
712
746
|
action: 'build'
|
|
713
747
|
});
|
|
714
748
|
// Runs after every rebuild, which is where the application is restarted. A rebuild that fails reports its own
|
|
715
749
|
// errors, emits nothing, and leaves the running bot alone rather than replacing it with a broken build.
|
|
750
|
+
let emitted;
|
|
751
|
+
const firstBuild = new Promise((resolve)=>emitted = resolve);
|
|
716
752
|
rsbuild.onAfterBuild(({ stats })=>{
|
|
717
|
-
|
|
753
|
+
emitted();
|
|
718
754
|
if (stats?.hasErrors()) return;
|
|
719
|
-
|
|
755
|
+
// A watch build packs nothing, so a previous build's packed copies would shadow the project's packages
|
|
756
|
+
this.removePackedOutputs();
|
|
720
757
|
this.latestBuild = stats ? emittedDigest(stats) : undefined;
|
|
721
758
|
this.restartApp(this.latestBuild);
|
|
722
759
|
});
|
|
760
|
+
// A compile that fails outright never reaches onAfterBuild, so it settles the wait too: a later save still reloads
|
|
761
|
+
rsbuild.onAfterCreateCompiler(({ compiler })=>{
|
|
762
|
+
for (const each of 'compilers' in compiler ? compiler.compilers : [
|
|
763
|
+
compiler
|
|
764
|
+
]){
|
|
765
|
+
each.hooks.failed.tap(WATCH_HOOK_NAME, ()=>emitted());
|
|
766
|
+
}
|
|
767
|
+
});
|
|
723
768
|
await watching?.close();
|
|
724
769
|
watching = await rsbuild.build({
|
|
725
770
|
watch: true
|
|
726
771
|
});
|
|
772
|
+
built = firstBuild;
|
|
727
773
|
};
|
|
728
774
|
await watch();
|
|
729
775
|
// Inputs the bundler does not see: the config, and tsconfig.json, which the build reads through a copy MeoCord
|
|
@@ -743,42 +789,53 @@ copies or substantial portions of the Software.
|
|
|
743
789
|
].some((file)=>!restarts.includes(file));
|
|
744
790
|
let debounceWatcher;
|
|
745
791
|
let changed = new Set();
|
|
792
|
+
// One reload at a time, each taking every file changed since the last began
|
|
793
|
+
const reload = async ()=>{
|
|
794
|
+
const files = changed;
|
|
795
|
+
changed = new Set();
|
|
796
|
+
if (this.stopping || files.size === 0) return;
|
|
797
|
+
for (const file of files)this.logger.log(reloads[file]);
|
|
798
|
+
if (!rebuilds(files)) return this.restartApp();
|
|
799
|
+
// A config that is refused, as at startup, or doesn't compile, say mid-edit, leaves the running bot and its build
|
|
800
|
+
// as they are
|
|
801
|
+
if (files.has('meocord.config.ts')) {
|
|
802
|
+
const checked = checkSourceConfig();
|
|
803
|
+
if ('problem' in checked) {
|
|
804
|
+
// One that doesn't load, say mid-edit, is reported as a failed compile is, and watching goes on
|
|
805
|
+
if (checked.loadError !== undefined) return this.logger.error(`Failed to compile meocord.config.ts: ${checked.loadError}`);
|
|
806
|
+
return reportConfigProblem(checked.problem);
|
|
807
|
+
}
|
|
808
|
+
if (!await this.compileConfig({
|
|
809
|
+
mode: 'development',
|
|
810
|
+
exitOnFailure: false
|
|
811
|
+
})) return;
|
|
812
|
+
}
|
|
813
|
+
// The new build restarts the bot, whatever its output: the config it was launched with has changed
|
|
814
|
+
this.launchedFrom = undefined;
|
|
815
|
+
try {
|
|
816
|
+
await watch();
|
|
817
|
+
} catch (error) {
|
|
818
|
+
// As with a failed login: the bot keeps running, and saving the file again tries again
|
|
819
|
+
this.logger.error(`Rebuilding failed: ${error instanceof Error ? error.message : String(error)}. The bot keeps running its last ` + 'build; save the file again to retry.');
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
let reloading = Promise.resolve();
|
|
823
|
+
// Whether a reload waits its turn: a later save joins it rather than queueing one of its own
|
|
824
|
+
let queued = false;
|
|
825
|
+
const queueReload = ()=>{
|
|
826
|
+
if (queued) return;
|
|
827
|
+
queued = true;
|
|
828
|
+
reloading = reloading.then(()=>built).then(()=>{
|
|
829
|
+
queued = false;
|
|
830
|
+
return reload();
|
|
831
|
+
}).catch((error)=>this.logger.error('Reloading failed:', error));
|
|
832
|
+
};
|
|
746
833
|
// The folder rather than the files, so an editor that saves by replacing a file is still seen
|
|
747
834
|
const fsWatcher = fs.watch(this.projectRoot, (_event, filename)=>{
|
|
748
835
|
if (!filename || !Object.hasOwn(reloads, filename)) return;
|
|
749
836
|
changed.add(filename);
|
|
750
837
|
clearTimeout(debounceWatcher);
|
|
751
|
-
debounceWatcher = setTimeout(
|
|
752
|
-
if (!isRunning) return;
|
|
753
|
-
const files = changed;
|
|
754
|
-
changed = new Set();
|
|
755
|
-
for (const file of files)this.logger.log(reloads[file]);
|
|
756
|
-
if (!rebuilds(files)) return this.restartApp();
|
|
757
|
-
// A config that is refused, as at startup, or doesn't compile, say mid-edit, leaves the running bot and its build
|
|
758
|
-
// as they are
|
|
759
|
-
if (files.has('meocord.config.ts')) {
|
|
760
|
-
const checked = checkSourceConfig();
|
|
761
|
-
if ('problem' in checked) {
|
|
762
|
-
// One that doesn't load, say mid-edit, is reported as a failed compile is, and watching goes on
|
|
763
|
-
if (checked.loadError !== undefined) return this.logger.error(`Failed to compile meocord.config.ts: ${checked.loadError}`);
|
|
764
|
-
return reportConfigProblem(checked.problem);
|
|
765
|
-
}
|
|
766
|
-
if (!await this.compileConfig({
|
|
767
|
-
mode: 'development',
|
|
768
|
-
exitOnFailure: false
|
|
769
|
-
})) return;
|
|
770
|
-
}
|
|
771
|
-
isRunning = false;
|
|
772
|
-
// The new build restarts the bot, whatever its output: the config it was launched with has changed
|
|
773
|
-
this.launchedFrom = undefined;
|
|
774
|
-
try {
|
|
775
|
-
await watch();
|
|
776
|
-
} catch (error) {
|
|
777
|
-
// As with a failed login: the bot keeps running, and saving the file again tries again
|
|
778
|
-
isRunning = true;
|
|
779
|
-
this.logger.error(`Rebuilding failed: ${error instanceof Error ? error.message : String(error)}. The bot keeps running its last ` + 'build; save the file again to retry.');
|
|
780
|
-
}
|
|
781
|
-
}, 300);
|
|
838
|
+
debounceWatcher = setTimeout(queueReload, RELOAD_DEBOUNCE_MS);
|
|
782
839
|
});
|
|
783
840
|
const stopWatching = ()=>{
|
|
784
841
|
this.stopping = true;
|
|
@@ -818,8 +875,8 @@ copies or substantial portions of the Software.
|
|
|
818
875
|
}
|
|
819
876
|
this.logger.log('Starting...');
|
|
820
877
|
const start = this.spawnApp();
|
|
821
|
-
start.on('exit', (code)=>{
|
|
822
|
-
process.exit(code
|
|
878
|
+
start.on('exit', (code, signal)=>{
|
|
879
|
+
process.exit(this.exitCodeOf(code, signal, 0));
|
|
823
880
|
});
|
|
824
881
|
this.relayStopSignals(()=>start);
|
|
825
882
|
} catch (error) {
|
|
@@ -859,6 +916,7 @@ copies or substantial portions of the Software.
|
|
|
859
916
|
/** Binary the application is spawned with: the runtime the user chose, as {@link resolveRuntime} finds it. */ this.runtime = resolveRuntime(process.env, process.execPath);
|
|
860
917
|
/** What a bot this CLI starts inherits, taken before any config is loaded; see {@link inheritedEnvironment}. */ this.inheritedEnv = inheritedEnvironment(process.env, this.projectRoot);
|
|
861
918
|
/** Environment added to the application's own when it is spawned. */ this.appEnv = {};
|
|
919
|
+
/** Whether the CLI has passed a stop signal on to the application, whose death by it is then the stop asked for. */ this.stopRelayed = false;
|
|
862
920
|
/** The running application, while a watch session owns one, including while it exits to be replaced. */ this.appProcess = null;
|
|
863
921
|
/** Whether the running application is exiting to be replaced; a build that finishes meanwhile joins that restart. */ this.restarting = false;
|
|
864
922
|
/** Whether a watch session is stopping, when a rebuild must not start the application again. */ this.stopping = false;
|
|
@@ -895,4 +953,4 @@ if (isProcessEntry()) {
|
|
|
895
953
|
});
|
|
896
954
|
}
|
|
897
955
|
|
|
898
|
-
export { MeoCordCLI, appDirectoryName, emittedDigest, stillRunning };
|
|
956
|
+
export { MeoCordCLI, RELOAD_DEBOUNCE_MS, appDirectoryName, emittedDigest, stillRunning };
|