@serverkgg/bridge 0.1.5 → 0.1.7
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/package.json +3 -3
- package/src/bot/botCauses.test.ts +56 -0
- package/src/bot/botCauses.ts +8 -2
- package/src/bot/detect/botFrameworks.ts +1 -0
- package/src/bot/detect/botInspectWarning.ts +1 -0
- package/src/bot/detect/corpus/anasty17-mirror-leech-telegram-bot.json +2 -2
- package/src/bot/detect/corpus/anidiotsguide-guidebot.json +2 -1
- package/src/bot/detect/corpus/anonymousx1025-anonxmusic.json +2 -2
- package/src/bot/detect/corpus/latand-tgbot_template_v3.json +2 -1
- package/src/bot/detect/corpus/mericcan41-discordjs-v14-template-ts.json +3 -1
- package/src/bot/detect/corpus/nezdemkovski-telegram-bot-boilerplate.json +2 -1
- package/src/bot/detect/corpus/tgbot-collection-ytdlbot.json +2 -2
- package/src/bot/detect/detect.test.ts +68 -0
- package/src/bot/detect/detect.ts +30 -0
- package/src/bot/detect/envExample.test.ts +8 -0
- package/src/bot/detect/envExample.ts +3 -1
- package/src/probes/minecraftPing.test.ts +2 -1
- package/src/rcon/rconClient.test.ts +3 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serverkgg/bridge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.7",
|
|
4
4
|
"description": "Serverk game bridge and driver runtime, wire protocol, manifest schema, and maintainer CLI",
|
|
5
5
|
"homepage": "https://serverk.gg",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"tsc": "tsc",
|
|
42
|
-
"test": "bun test --parallel"
|
|
42
|
+
"test": "bun test --parallel=8"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"zod": "4.6.
|
|
45
|
+
"zod": "4.6.5"
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -13,6 +13,10 @@ const CASES: readonly {
|
|
|
13
13
|
line: "Error [TokenInvalid]: An invalid token was provided.",
|
|
14
14
|
cause: BridgeCrashCause.TokenInvalid,
|
|
15
15
|
},
|
|
16
|
+
{
|
|
17
|
+
line: "Error [TOKEN_INVALID]: An invalid token was provided.",
|
|
18
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
19
|
+
},
|
|
16
20
|
{
|
|
17
21
|
line: "discord.errors.LoginFailure: Improper token has been passed.",
|
|
18
22
|
cause: BridgeCrashCause.TokenInvalid,
|
|
@@ -37,6 +41,46 @@ const CASES: readonly {
|
|
|
37
41
|
line: "aiogram.exceptions.TelegramUnauthorizedError: Telegram server says - Unauthorized",
|
|
38
42
|
cause: BridgeCrashCause.TokenInvalid,
|
|
39
43
|
},
|
|
44
|
+
{
|
|
45
|
+
line: "pyrogram.errors.exceptions.bad_request_400.AccessTokenInvalid: Telegram says: [400 ACCESS_TOKEN_INVALID] - The bot access token is invalid",
|
|
46
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
line: "pyrogram.errors.exceptions.bad_request_400.AccessTokenExpired: Telegram says: [400 ACCESS_TOKEN_EXPIRED] - The bot token has expired",
|
|
50
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
line: "TypeError: expected token to be a str, received NoneType instead",
|
|
54
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
line: "TypeError: expected token to be a str, received <class 'NoneType'> instead",
|
|
58
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
line: "TypeError: token must be of type str, not NoneType",
|
|
62
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
line: "TypeError: token must be of type str, got NoneType instead",
|
|
66
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
line: "TypeError: The token provided was of type <class 'NoneType'> but was expected to be str",
|
|
70
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
line: "Error: Empty token!",
|
|
74
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
line: "aiogram.utils.token.TokenValidationError: Token is invalid!",
|
|
78
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
line: "aiogram.utils.token.TokenValidationError: Token is invalid! It must be 'str' type instead of <class 'NoneType'> type.",
|
|
82
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
83
|
+
},
|
|
40
84
|
{
|
|
41
85
|
line: "Error: Used disallowed intents",
|
|
42
86
|
cause: BridgeCrashCause.IntentsDisallowed,
|
|
@@ -45,6 +89,10 @@ const CASES: readonly {
|
|
|
45
89
|
line: "Error [DisallowedIntents]: Privileged intent provided is not enabled or whitelisted.",
|
|
46
90
|
cause: BridgeCrashCause.IntentsDisallowed,
|
|
47
91
|
},
|
|
92
|
+
{
|
|
93
|
+
line: "Error [DISALLOWED_INTENTS]: Privileged intent provided is not enabled or whitelisted.",
|
|
94
|
+
cause: BridgeCrashCause.IntentsDisallowed,
|
|
95
|
+
},
|
|
48
96
|
{
|
|
49
97
|
line: "discord.errors.PrivilegedIntentsRequired: Shard ID None is requesting privileged intents that have not been explicitly enabled in the developer portal.",
|
|
50
98
|
cause: BridgeCrashCause.IntentsDisallowed,
|
|
@@ -257,6 +305,14 @@ describe("BOT_CRASH_EVIDENCE", () => {
|
|
|
257
305
|
expect(ring.crash(recordOf())).toBe(BridgeCrashCause.Unknown);
|
|
258
306
|
});
|
|
259
307
|
|
|
308
|
+
it("leaves a TypeError about something other than the token unexplained", () => {
|
|
309
|
+
const { ring, print } = botRing();
|
|
310
|
+
|
|
311
|
+
print("TypeError: expected str, bytes or os.PathLike object, not NoneType");
|
|
312
|
+
|
|
313
|
+
expect(ring.crash(recordOf())).toBe(BridgeCrashCause.Unknown);
|
|
314
|
+
});
|
|
315
|
+
|
|
260
316
|
it("calls exit 137 out of memory only when the record carries the flag", () => {
|
|
261
317
|
const unflagged = botRing();
|
|
262
318
|
|
package/src/bot/botCauses.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { BridgeEventName } from "../protocol";
|
|
|
4
4
|
export const BOT_CRASH_EVIDENCE: readonly BridgeEventPattern[] = [
|
|
5
5
|
{
|
|
6
6
|
match:
|
|
7
|
-
/\[TokenInvalid\]|An invalid token was provided|LoginFailure: Improper token|\b401:? Unauthorized\b|\bInvalidToken\b|TelegramUnauthorizedError/,
|
|
7
|
+
/\[TokenInvalid\]|An invalid token was provided|LoginFailure: Improper token|\b401:? Unauthorized\b|\bInvalidToken\b|TelegramUnauthorizedError|\bACCESS_TOKEN_(?:INVALID|EXPIRED)\b/,
|
|
8
8
|
emit: BridgeEventName.TokenInvalid,
|
|
9
9
|
},
|
|
10
10
|
{
|
|
@@ -13,7 +13,13 @@ export const BOT_CRASH_EVIDENCE: readonly BridgeEventPattern[] = [
|
|
|
13
13
|
emit: BridgeEventName.TokenInvalid,
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
|
-
match:
|
|
16
|
+
match:
|
|
17
|
+
/TypeError: (?:expected token to be a str, received|token must be of type str, (?:not|got) |The token provided was of type .+ but was expected to be str)|\bError: Empty token!|TokenValidationError: Token is invalid!/,
|
|
18
|
+
emit: BridgeEventName.TokenInvalid,
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
match:
|
|
22
|
+
/Used disallowed intents|\[DisallowedIntents\]|Privileged intent provided is not enabled or whitelisted|PrivilegedIntentsRequired|close code:? 4014\b/,
|
|
17
23
|
emit: BridgeEventName.IntentsDisallowed,
|
|
18
24
|
},
|
|
19
25
|
{
|
|
@@ -3,6 +3,7 @@ export enum BotInspectWarning {
|
|
|
3
3
|
NodeVersionUnmet = "node-version-unmet",
|
|
4
4
|
LockfileNotHonoured = "lockfile-not-honoured",
|
|
5
5
|
NoStart = "no-start",
|
|
6
|
+
WindowsCommand = "windows-command",
|
|
6
7
|
NoManifest = "no-manifest",
|
|
7
8
|
EnvCommitted = "env-committed",
|
|
8
9
|
NodeModulesCommitted = "node-modules-committed",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"expected": {
|
|
36
36
|
"runtime": "python",
|
|
37
37
|
"packageManager": "pip",
|
|
38
|
-
"framework":
|
|
39
|
-
"platform":
|
|
38
|
+
"framework": "pyrogram",
|
|
39
|
+
"platform": "telegram",
|
|
40
40
|
"install": "uv pip install -r requirements.txt",
|
|
41
41
|
"build": null,
|
|
42
42
|
"start": "python -m bot",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"yarn.lock"
|
|
19
19
|
],
|
|
20
20
|
"contents": {
|
|
21
|
+
".env-example": "DISCORD_TOKEN=\nOWNER=",
|
|
21
22
|
"package.json": "{\n \"name\": \"guidebot\",\n \"version\": \"2.1.0\",\n \"description\": \"A boilerplate example bot with command handler and reloadable commands. Updated and Maintained by the Idiot's Guide Community\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"start\": \"node index.js\"\n },\n \"engines\": {\n \"node\": \">=16\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/AnIdiotsGuide/guidebot.git\"\n },\n \"author\": \"Evelyne Lachance <eslachance@gmail.com> (http://evie.codes)\",\n \"contributors\": [\n \"York (http://anidiots.guide)\"\n ],\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/AnIdiotsGuide/guidebot/issues\"\n },\n \"homepage\": \"https://github.com/AnIdiotsGuide/guidebot#readme\",\n \"dependencies\": {\n \"@discordjs/builders\": \"^0.2.0\",\n \"@sapphire/time-utilities\": \"^1.3.8\",\n \"colorette\": \"^1.3.0\",\n \"discord.js\": \"^13.0.1\",\n \"dotenv\": \"^10.0.0\",\n \"enmap\": \"^5.8.5\"\n },\n \"devDependencies\": {\n \"eslint\": \"^7.30.0\",\n \"eslint-config-airbnb-base\": \"^14.2.1\",\n \"eslint-config-standard\": \"^16.0.3\",\n \"eslint-plugin-import\": \"^2.23.4\",\n \"eslint-plugin-node\": \"^11.1.0\",\n \"eslint-plugin-promise\": \"^5.1.0\"\n }\n}\n"
|
|
22
23
|
},
|
|
23
24
|
"expected": {
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
"start": "node index.js",
|
|
31
32
|
"nodeVersion": "16",
|
|
32
33
|
"pythonVersion": null,
|
|
33
|
-
"tokenKey":
|
|
34
|
+
"tokenKey": "DISCORD_TOKEN",
|
|
34
35
|
"warnings": []
|
|
35
36
|
}
|
|
36
37
|
}
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"expected": {
|
|
33
33
|
"runtime": "python",
|
|
34
34
|
"packageManager": "pip",
|
|
35
|
-
"framework":
|
|
36
|
-
"platform":
|
|
35
|
+
"framework": "pyrogram",
|
|
36
|
+
"platform": "telegram",
|
|
37
37
|
"install": "uv pip install -r requirements.txt",
|
|
38
38
|
"build": null,
|
|
39
39
|
"start": "bash start",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"requirements.txt"
|
|
18
18
|
],
|
|
19
19
|
"contents": {
|
|
20
|
+
".env.dist": "BOT_TOKEN=123456:Your-TokEn_ExaMple\nADMINS=123456,654321\nUSE_REDIS=False\n\n#POSTGRES_USER=someusername\n#POSTGRES_PASSWORD=postgres_pass12345\n#POSTGRES_DB=bot\n#DB_HOST=pg_database\n\n# REDIS_HOST=redis_cache\n# REDIS_PORT=6388\n# REDIS_DB=1\n# REDIS_PASSWORD=someredispass\n\n\n#WEBHOOK_EXPOSE=8001\n#WEBHOOK_APP_NAME=webhook\n",
|
|
20
21
|
"requirements.txt": "aiogram~=3.0\nenvirons~=9.0\nredis\nbetterlogging\n\n# # For enabling api:\n# backoff\n# ujson\n# yarl\n\n# # For PostgreSQL sqlalchemy + alembic:\n# sqlalchemy~=2.0\n# alembic~=1.0\n# asyncpg\n"
|
|
21
22
|
},
|
|
22
23
|
"expected": {
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
"start": "python bot.py",
|
|
30
31
|
"nodeVersion": null,
|
|
31
32
|
"pythonVersion": null,
|
|
32
|
-
"tokenKey":
|
|
33
|
+
"tokenKey": "BOT_TOKEN",
|
|
33
34
|
"warnings": [
|
|
34
35
|
"unpinned-requirements"
|
|
35
36
|
]
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"tsconfig.json"
|
|
22
22
|
],
|
|
23
23
|
"contents": {
|
|
24
|
+
".env-sample": "BOT_TOKEN=\"\"\nUSERNAME=\"\"\nWEBHOOK_URL=\"\"\nPORT=\"3000\"\nNODE_ENV=\"development\"\n",
|
|
24
25
|
"package.json": "{\n \"name\": \"telegram-bot-boilerplate\",\n \"version\": \"1.0.0\",\n \"description\": \"Telegram Bot Boilerplate\",\n \"author\": \"Yuri Nezdemkovski <yuri@nezdemkovski.com> (https://nezdemkovski.com/)\",\n \"homepage\": \"https://github.com/nezdemkovski/telegram-bot-boilerplate\",\n \"license\": \"MIT\",\n \"engines\": {\n \"bun\": \">=1\"\n },\n \"dependencies\": {\n \"grammy\": \"^1.40.0\"\n },\n \"devDependencies\": {\n \"bun-types\": \"1.3.9\",\n \"eslint\": \"^10.0.1\",\n \"eslint-config-prettier\": \"^10.1.8\",\n \"prettier\": \"^3.8.1\",\n \"typescript\": \"^5.9.3\",\n \"typescript-eslint\": \"^8.56.0\"\n },\n \"scripts\": {\n \"dev\": \"bun --watch src/index.ts\",\n \"build\": \"bun build src/index.ts --outdir dist --target bun --minify\",\n \"start\": \"NODE_ENV=production bun dist/index.js\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"eslint src\",\n \"format\": \"prettier --write 'src/**/*.ts'\"\n }\n}\n"
|
|
25
26
|
},
|
|
26
27
|
"expected": {
|
|
@@ -33,7 +34,7 @@
|
|
|
33
34
|
"start": "NODE_ENV=production bun dist/index.js",
|
|
34
35
|
"nodeVersion": null,
|
|
35
36
|
"pythonVersion": null,
|
|
36
|
-
"tokenKey":
|
|
37
|
+
"tokenKey": "BOT_TOKEN",
|
|
37
38
|
"warnings": []
|
|
38
39
|
}
|
|
39
40
|
}
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"expected": {
|
|
29
29
|
"runtime": "python",
|
|
30
30
|
"packageManager": "pip",
|
|
31
|
-
"framework":
|
|
32
|
-
"platform":
|
|
31
|
+
"framework": "pyrogram",
|
|
32
|
+
"platform": "telegram",
|
|
33
33
|
"install": "uv pip install -r requirements.txt",
|
|
34
34
|
"build": null,
|
|
35
35
|
"start": "python src/main.py",
|
|
@@ -604,6 +604,24 @@ describe("detect warnings", () => {
|
|
|
604
604
|
]);
|
|
605
605
|
});
|
|
606
606
|
|
|
607
|
+
it("warns when a start or build script runs a Windows-only command", () => {
|
|
608
|
+
const scripts = (start: string, build: string) => {
|
|
609
|
+
return project({
|
|
610
|
+
"package.json": JSON.stringify({
|
|
611
|
+
scripts: {
|
|
612
|
+
start,
|
|
613
|
+
build,
|
|
614
|
+
},
|
|
615
|
+
}),
|
|
616
|
+
"package-lock.json": "{}",
|
|
617
|
+
}).warnings;
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
expect(scripts("cls && node build/index.js", "cls && node build.js")).toContain(BotInspectWarning.WindowsCommand);
|
|
621
|
+
expect(scripts("node build/index.js", "CLS&&node build.js")).toContain(BotInspectWarning.WindowsCommand);
|
|
622
|
+
expect(scripts("node index.js", "tsc")).not.toContain(BotInspectWarning.WindowsCommand);
|
|
623
|
+
});
|
|
624
|
+
|
|
607
625
|
it("flags two runtimes and picks the one whose framework it found", () => {
|
|
608
626
|
const result = project({
|
|
609
627
|
...DISCORD_NODE,
|
|
@@ -630,6 +648,17 @@ describe("detect warnings", () => {
|
|
|
630
648
|
expect(result.warnings).toContain(BotInspectWarning.TwoPlatforms);
|
|
631
649
|
});
|
|
632
650
|
|
|
651
|
+
it("reads kurigram, the Pyrogram fork the corpus bots install, as Pyrogram on Telegram", () => {
|
|
652
|
+
const result = project({
|
|
653
|
+
"requirements.txt": "kurigram>=2.2.25\ntgcrypto\n",
|
|
654
|
+
"bot/__main__.py": "",
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
expect(result.framework).toBe(BotFramework.Pyrogram);
|
|
658
|
+
expect(result.platform).toBe(BotPlatform.Telegram);
|
|
659
|
+
expect(result.warnings).not.toContain(BotInspectWarning.TwoPlatforms);
|
|
660
|
+
});
|
|
661
|
+
|
|
633
662
|
it("drops keys the platform owns and warns, but keeps quiet about keys the runtime gives anyway", () => {
|
|
634
663
|
const result = project({
|
|
635
664
|
...DISCORD_NODE,
|
|
@@ -784,6 +813,45 @@ describe("detect env suggestions", () => {
|
|
|
784
813
|
]);
|
|
785
814
|
});
|
|
786
815
|
|
|
816
|
+
const CASES: readonly {
|
|
817
|
+
file: string;
|
|
818
|
+
}[] = [
|
|
819
|
+
{
|
|
820
|
+
file: ".env-example",
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
file: ".env-sample",
|
|
824
|
+
},
|
|
825
|
+
{
|
|
826
|
+
file: ".env.dist",
|
|
827
|
+
},
|
|
828
|
+
];
|
|
829
|
+
|
|
830
|
+
for (const item of CASES) {
|
|
831
|
+
it(`reads ${item.file} the way it reads .env.example`, () => {
|
|
832
|
+
const result = project({
|
|
833
|
+
"package.json": "{}",
|
|
834
|
+
[item.file]: "DISCORD_TOKEN=\nOWNER=\n",
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
expect(result.env).toEqual([
|
|
838
|
+
{
|
|
839
|
+
key: "DISCORD_TOKEN",
|
|
840
|
+
sensitive: true,
|
|
841
|
+
source: item.file,
|
|
842
|
+
example: null,
|
|
843
|
+
},
|
|
844
|
+
{
|
|
845
|
+
key: "OWNER",
|
|
846
|
+
sensitive: false,
|
|
847
|
+
source: item.file,
|
|
848
|
+
example: null,
|
|
849
|
+
},
|
|
850
|
+
]);
|
|
851
|
+
expect(result.tokenKey).toBe("DISCORD_TOKEN");
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
|
|
787
855
|
it("suggests the keys of a skipped .env after the example files, never its values", () => {
|
|
788
856
|
const result = detect({
|
|
789
857
|
files: [
|
package/src/bot/detect/detect.ts
CHANGED
|
@@ -53,6 +53,12 @@ const NOT_A_BOT_PACKAGE: ReadonlySet<string> = new Set([
|
|
|
53
53
|
"scripts",
|
|
54
54
|
]);
|
|
55
55
|
|
|
56
|
+
const WINDOWS_COMMANDS: ReadonlySet<string> = new Set([
|
|
57
|
+
"cls",
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
const COMMAND_SEPARATOR = /&&|\|\||;|\|/;
|
|
61
|
+
|
|
56
62
|
const MANAGER_FIELD = /^(npm|pnpm|yarn|bun)@(\d+)/;
|
|
57
63
|
|
|
58
64
|
const ENGINE_MANAGERS: readonly string[] = [
|
|
@@ -394,6 +400,18 @@ const frameworksOf = (
|
|
|
394
400
|
return declared.length > 0 ? declared : specs.filter((spec) => spec.modules.some((name) => imports.has(name)));
|
|
395
401
|
};
|
|
396
402
|
|
|
403
|
+
const runsWindowsCommand = (command: string | null) => {
|
|
404
|
+
if (command === null) {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return command.split(COMMAND_SEPARATOR).some((segment) => {
|
|
409
|
+
const program = segment.trim().split(/\s+/)[0] ?? "";
|
|
410
|
+
|
|
411
|
+
return WINDOWS_COMMANDS.has(program.toLowerCase());
|
|
412
|
+
});
|
|
413
|
+
};
|
|
414
|
+
|
|
397
415
|
const procfileCommand = (text: string | null): DetectedCommand | null => {
|
|
398
416
|
if (text === null) {
|
|
399
417
|
return null;
|
|
@@ -1094,6 +1112,18 @@ export const detect = (input: DetectInput): DetectResult => {
|
|
|
1094
1112
|
warnings.add(BotInspectWarning.NoStart);
|
|
1095
1113
|
}
|
|
1096
1114
|
|
|
1115
|
+
const buildScript = recordOf(packageJson?.scripts)[DETECT_TABLE.node.buildScript];
|
|
1116
|
+
|
|
1117
|
+
const commands = [
|
|
1118
|
+
start?.command ?? null,
|
|
1119
|
+
build?.command ?? null,
|
|
1120
|
+
build?.source === DETECT_TABLE.node.manifest && typeof buildScript === "string" ? buildScript : null,
|
|
1121
|
+
];
|
|
1122
|
+
|
|
1123
|
+
if (commands.some(runsWindowsCommand)) {
|
|
1124
|
+
warnings.add(BotInspectWarning.WindowsCommand);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1097
1127
|
committedWarnings(paths, warnings);
|
|
1098
1128
|
|
|
1099
1129
|
const env = envCollector(warnings);
|
|
@@ -4,11 +4,13 @@ export const ENV_EXAMPLE_FILES: readonly string[] = [
|
|
|
4
4
|
".env.example",
|
|
5
5
|
".env.sample",
|
|
6
6
|
".env.template",
|
|
7
|
+
".env-example",
|
|
8
|
+
".env-sample",
|
|
9
|
+
".env.dist",
|
|
7
10
|
];
|
|
8
11
|
|
|
9
12
|
const ENV_TEMPLATE_FILES: ReadonlySet<string> = new Set([
|
|
10
13
|
...ENV_EXAMPLE_FILES,
|
|
11
|
-
".env.dist",
|
|
12
14
|
".env.defaults",
|
|
13
15
|
]);
|
|
14
16
|
|
|
@@ -5,6 +5,7 @@ import { parseStatus, probeMinecraftPing } from "./minecraftPing";
|
|
|
5
5
|
const HOST = "127.0.0.1";
|
|
6
6
|
|
|
7
7
|
const CLOSED_PORT = 59_441;
|
|
8
|
+
const CLOSED_HOST = "::1";
|
|
8
9
|
|
|
9
10
|
const varInt = (value: number) => {
|
|
10
11
|
const bytes: number[] = [];
|
|
@@ -294,7 +295,7 @@ describe("probeMinecraftPing", () => {
|
|
|
294
295
|
it("rejects as unreachable when nothing listens on the port", async () => {
|
|
295
296
|
const error = await probeMinecraftPing(
|
|
296
297
|
{
|
|
297
|
-
address:
|
|
298
|
+
address: CLOSED_HOST,
|
|
298
299
|
port: CLOSED_PORT,
|
|
299
300
|
},
|
|
300
301
|
2000,
|
|
@@ -19,6 +19,7 @@ import { createRconWriter, type RconWriter } from "./rconWriter";
|
|
|
19
19
|
const HOST = "127.0.0.1";
|
|
20
20
|
|
|
21
21
|
const CLOSED_PORT = 59_433;
|
|
22
|
+
const CLOSED_HOST = "::1";
|
|
22
23
|
|
|
23
24
|
const PASSWORD = "kX7-forbidden-in-errors";
|
|
24
25
|
|
|
@@ -1005,7 +1006,7 @@ describe("RconClient failures", () => {
|
|
|
1005
1006
|
|
|
1006
1007
|
it("reports a port nothing listens on", async () => {
|
|
1007
1008
|
const client = new RconClient({
|
|
1008
|
-
host:
|
|
1009
|
+
host: CLOSED_HOST,
|
|
1009
1010
|
port: CLOSED_PORT,
|
|
1010
1011
|
password: PASSWORD,
|
|
1011
1012
|
timeoutMs: 1000,
|
|
@@ -1475,7 +1476,7 @@ describe("RconClient secrecy", () => {
|
|
|
1475
1476
|
});
|
|
1476
1477
|
|
|
1477
1478
|
const unreachable = new RconClient({
|
|
1478
|
-
host:
|
|
1479
|
+
host: CLOSED_HOST,
|
|
1479
1480
|
port: CLOSED_PORT,
|
|
1480
1481
|
password: PASSWORD,
|
|
1481
1482
|
timeoutMs: 500,
|