@serverkgg/bridge 0.1.4 → 0.1.6
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 +292 -0
- package/src/bot/botCauses.ts +58 -0
- package/src/bot/botDeploy.test.ts +260 -1
- package/src/bot/botDeploy.ts +125 -6
- package/src/bot/botState.ts +6 -0
- package/src/bot/detect/botFrameworks.ts +1 -0
- package/src/bot/detect/botInspectWarning.ts +4 -1
- package/src/bot/detect/botPackageManager.ts +3 -0
- package/src/bot/detect/corpus/alexmubarakshin-ts-telegraf-boilerplate.json +37 -0
- package/src/bot/detect/corpus/alsarmad-discord-quran-bot.json +40 -0
- package/src/bot/detect/corpus/anasty17-mirror-leech-telegram-bot.json +50 -0
- package/src/bot/detect/corpus/anidiotsguide-guidebot.json +36 -0
- package/src/bot/detect/corpus/anonymousx1025-anonxmusic.json +45 -0
- package/src/bot/detect/corpus/bot-base-telegram-bot-template.json +35 -0
- package/src/bot/detect/corpus/bracketed-templates-discordjs.json +40 -0
- package/src/bot/detect/corpus/cog-creators-red-discordbot.json +49 -0
- package/src/bot/detect/corpus/cranberriez-discord.ts-bot-template.json +35 -0
- package/src/bot/detect/corpus/crazycat256-nextcord-bot-template.json +38 -0
- package/src/bot/detect/corpus/discord-tickets-bot.json +45 -0
- package/src/bot/detect/corpus/edjopato-telegram-typescript-bot-template.json +37 -0
- package/src/bot/detect/corpus/haniali3161-bot-adhkar-telegram.json +33 -0
- package/src/bot/detect/corpus/hellosverre-discord-ts-template.json +34 -0
- package/src/bot/detect/corpus/kevinnovak-discord-bot-typescript-template.json +43 -0
- package/src/bot/detect/corpus/kkrypt0nn-python-discord-bot-template.json +41 -0
- package/src/bot/detect/corpus/kolezka-telegram-grammy-template.json +37 -0
- package/src/bot/detect/corpus/latand-tgbot_template_v3.json +37 -0
- package/src/bot/detect/corpus/mahmoudbm77-zekr-telegram-bot.json +36 -0
- package/src/bot/detect/corpus/mericcan41-discordjs-v14-template-ts.json +35 -0
- package/src/bot/detect/corpus/modmail-dev-modmail.json +52 -0
- package/src/bot/detect/corpus/nezdemkovski-telegram-bot-boilerplate.json +39 -0
- package/src/bot/detect/corpus/notchum-discord-bot-template.json +39 -0
- package/src/bot/detect/corpus/python-discord-bot.json +44 -0
- package/src/bot/detect/corpus/python-telegram-bot-rules-bot.json +39 -0
- package/src/bot/detect/corpus/rajdave69-pycord-bot-template.json +31 -0
- package/src/bot/detect/corpus/rapptz-robodanny.json +36 -0
- package/src/bot/detect/corpus/ry2x-typescript-discord.js-v.14-template.json +35 -0
- package/src/bot/detect/corpus/saiteja-madha-discord-js-bot.json +45 -0
- package/src/bot/detect/corpus/seegreatness-discord.js-for-heroku.json +37 -0
- package/src/bot/detect/corpus/serverk-discord-node.json +36 -0
- package/src/bot/detect/corpus/serverk-discord-python.json +35 -0
- package/src/bot/detect/corpus/serverk-telegram-node.json +36 -0
- package/src/bot/detect/corpus/serverk-telegram-python.json +35 -0
- package/src/bot/detect/corpus/shuruhatik-quran-radio-bot-discord.json +33 -0
- package/src/bot/detect/corpus/skyra-project-skyra.json +46 -0
- package/src/bot/detect/corpus/tgbot-collection-ytdlbot.json +41 -0
- package/src/bot/detect/corpus/zeriodev-music-bot.json +38 -0
- package/src/bot/detect/detect.corpus.test.ts +77 -0
- package/src/bot/detect/detect.test.ts +443 -17
- package/src/bot/detect/detect.ts +375 -34
- package/src/bot/detect/detectResult.ts +4 -0
- package/src/bot/detect/detectTable.test.ts +22 -6
- package/src/bot/detect/detectTable.ts +187 -19
- package/src/bot/detect/detectedVersion.ts +5 -0
- package/src/bot/detect/envExample.test.ts +55 -1
- package/src/bot/detect/envExample.ts +14 -0
- package/src/bot/detect/index.ts +1 -0
- package/src/bot/detect/keys.test.ts +32 -1
- package/src/bot/detect/keys.ts +15 -0
- package/src/bot/detect/serverkJson.test.ts +2 -0
- package/src/bot/detect/serverkJson.ts +4 -1
- package/src/bot/index.ts +1 -0
- package/src/manifest/manifest.ts +2 -1
- package/src/modules/bridge.ts +2 -0
- package/src/modules/bridgeModule.ts +5 -0
- package/src/probes/minecraftPing.test.ts +2 -1
- package/src/protocol/bridgeCrash.ts +49 -0
- package/src/protocol/bridgeEvents.ts +9 -0
- package/src/rcon/rconClient.test.ts +3 -2
- package/src/runtime/bridgeDriver.test.ts +45 -0
- package/src/runtime/bridgeDriver.ts +25 -0
- package/src/runtime/bridgeEvents.ts +2 -0
- package/src/runtime/bridgeSupervisor.test.ts +163 -3
- package/src/runtime/bridgeSupervisor.ts +42 -1
- package/src/runtime/serve.ts +26 -5
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
SERVERK_JSON_EXAMPLE_LENGTH_LIMIT,
|
|
10
10
|
} from "./serverkJson";
|
|
11
11
|
|
|
12
|
-
export const DETECT_TABLE_VERSION =
|
|
12
|
+
export const DETECT_TABLE_VERSION = 2;
|
|
13
13
|
|
|
14
14
|
export const DETECT_TABLE_FILE = "image/detect.json";
|
|
15
15
|
|
|
@@ -18,6 +18,13 @@ export interface DetectLockfile {
|
|
|
18
18
|
manager: string;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
export interface DetectVersionFile {
|
|
22
|
+
file: string;
|
|
23
|
+
tool?: string;
|
|
24
|
+
prefix?: string;
|
|
25
|
+
key?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
21
28
|
export interface DetectProcfile {
|
|
22
29
|
file: string;
|
|
23
30
|
line: string;
|
|
@@ -38,16 +45,28 @@ export interface ServerkJsonDetectTable {
|
|
|
38
45
|
|
|
39
46
|
export interface NodeDetectTable {
|
|
40
47
|
manifest: string;
|
|
48
|
+
managerField: string;
|
|
49
|
+
berryFile: string;
|
|
50
|
+
enginesKey: string;
|
|
51
|
+
buildScript: string;
|
|
41
52
|
startFiles: string[];
|
|
42
53
|
lockfiles: DetectLockfile[];
|
|
43
|
-
installCommands:
|
|
44
|
-
|
|
54
|
+
installCommands: {
|
|
55
|
+
locked: Record<string, string[]>;
|
|
56
|
+
unlocked: Record<string, string[]>;
|
|
57
|
+
};
|
|
58
|
+
runCommands: Record<string, string[]>;
|
|
59
|
+
versionFiles: DetectVersionFile[];
|
|
60
|
+
defaultVersion: string;
|
|
45
61
|
}
|
|
46
62
|
|
|
47
63
|
export interface PythonDetectTable {
|
|
48
64
|
startFiles: string[];
|
|
49
65
|
manifests: DetectLockfile[];
|
|
50
|
-
|
|
66
|
+
installCommands: Record<string, string[]>;
|
|
67
|
+
unhonouredManagers: string[];
|
|
68
|
+
versionFiles: DetectVersionFile[];
|
|
69
|
+
defaultVersion: string;
|
|
51
70
|
}
|
|
52
71
|
|
|
53
72
|
export interface DetectTable {
|
|
@@ -81,6 +100,10 @@ export const DETECT_TABLE: DetectTable = {
|
|
|
81
100
|
},
|
|
82
101
|
node: {
|
|
83
102
|
manifest: "package.json",
|
|
103
|
+
managerField: "packageManager",
|
|
104
|
+
berryFile: ".yarnrc.yml",
|
|
105
|
+
enginesKey: "node",
|
|
106
|
+
buildScript: "build",
|
|
84
107
|
startFiles: [
|
|
85
108
|
"index.js",
|
|
86
109
|
"src/index.js",
|
|
@@ -90,44 +113,125 @@ export const DETECT_TABLE: DetectTable = {
|
|
|
90
113
|
],
|
|
91
114
|
lockfiles: [
|
|
92
115
|
{
|
|
93
|
-
file: "
|
|
94
|
-
manager: "
|
|
116
|
+
file: "pnpm-lock.yaml",
|
|
117
|
+
manager: "pnpm",
|
|
95
118
|
},
|
|
96
119
|
{
|
|
97
|
-
file: "
|
|
98
|
-
manager: "
|
|
120
|
+
file: "bun.lock",
|
|
121
|
+
manager: "bun",
|
|
99
122
|
},
|
|
100
123
|
{
|
|
101
|
-
file: "
|
|
102
|
-
manager: "
|
|
124
|
+
file: "bun.lockb",
|
|
125
|
+
manager: "bun",
|
|
103
126
|
},
|
|
104
127
|
{
|
|
105
128
|
file: "yarn.lock",
|
|
106
129
|
manager: "yarn",
|
|
107
130
|
},
|
|
131
|
+
{
|
|
132
|
+
file: "package-lock.json",
|
|
133
|
+
manager: "npm",
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
file: "npm-shrinkwrap.json",
|
|
137
|
+
manager: "npm",
|
|
138
|
+
},
|
|
108
139
|
],
|
|
109
140
|
installCommands: {
|
|
141
|
+
locked: {
|
|
142
|
+
npm: [
|
|
143
|
+
"npm",
|
|
144
|
+
"ci",
|
|
145
|
+
],
|
|
146
|
+
pnpm: [
|
|
147
|
+
"corepack",
|
|
148
|
+
"pnpm",
|
|
149
|
+
"install",
|
|
150
|
+
"--frozen-lockfile",
|
|
151
|
+
],
|
|
152
|
+
yarn: [
|
|
153
|
+
"corepack",
|
|
154
|
+
"yarn",
|
|
155
|
+
"install",
|
|
156
|
+
"--frozen-lockfile",
|
|
157
|
+
],
|
|
158
|
+
"yarn-berry": [
|
|
159
|
+
"corepack",
|
|
160
|
+
"yarn",
|
|
161
|
+
"install",
|
|
162
|
+
"--immutable",
|
|
163
|
+
],
|
|
164
|
+
bun: [
|
|
165
|
+
"bun",
|
|
166
|
+
"install",
|
|
167
|
+
"--frozen-lockfile",
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
unlocked: {
|
|
171
|
+
npm: [
|
|
172
|
+
"npm",
|
|
173
|
+
"install",
|
|
174
|
+
],
|
|
175
|
+
pnpm: [
|
|
176
|
+
"corepack",
|
|
177
|
+
"pnpm",
|
|
178
|
+
"install",
|
|
179
|
+
],
|
|
180
|
+
yarn: [
|
|
181
|
+
"corepack",
|
|
182
|
+
"yarn",
|
|
183
|
+
"install",
|
|
184
|
+
],
|
|
185
|
+
"yarn-berry": [
|
|
186
|
+
"corepack",
|
|
187
|
+
"yarn",
|
|
188
|
+
"install",
|
|
189
|
+
"--no-immutable",
|
|
190
|
+
],
|
|
191
|
+
bun: [
|
|
192
|
+
"bun",
|
|
193
|
+
"install",
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
runCommands: {
|
|
110
198
|
npm: [
|
|
111
199
|
"npm",
|
|
112
|
-
"
|
|
200
|
+
"run",
|
|
113
201
|
],
|
|
114
202
|
pnpm: [
|
|
115
203
|
"corepack",
|
|
116
204
|
"pnpm",
|
|
117
|
-
"
|
|
118
|
-
"--frozen-lockfile",
|
|
205
|
+
"run",
|
|
119
206
|
],
|
|
120
207
|
yarn: [
|
|
121
208
|
"corepack",
|
|
122
209
|
"yarn",
|
|
123
|
-
"
|
|
210
|
+
"run",
|
|
124
211
|
],
|
|
125
|
-
"
|
|
126
|
-
"
|
|
127
|
-
"
|
|
212
|
+
"yarn-berry": [
|
|
213
|
+
"corepack",
|
|
214
|
+
"yarn",
|
|
215
|
+
"run",
|
|
216
|
+
],
|
|
217
|
+
bun: [
|
|
218
|
+
"bun",
|
|
219
|
+
"run",
|
|
128
220
|
],
|
|
129
221
|
},
|
|
130
|
-
|
|
222
|
+
versionFiles: [
|
|
223
|
+
{
|
|
224
|
+
file: ".nvmrc",
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
file: ".node-version",
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
file: ".tool-versions",
|
|
231
|
+
tool: "nodejs",
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
defaultVersion: "24",
|
|
131
235
|
},
|
|
132
236
|
python: {
|
|
133
237
|
startFiles: [
|
|
@@ -142,22 +246,86 @@ export const DETECT_TABLE: DetectTable = {
|
|
|
142
246
|
file: "requirements.txt",
|
|
143
247
|
manager: "requirements",
|
|
144
248
|
},
|
|
249
|
+
{
|
|
250
|
+
file: "uv.lock",
|
|
251
|
+
manager: "uv",
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
file: "poetry.lock",
|
|
255
|
+
manager: "poetry",
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
file: "pdm.lock",
|
|
259
|
+
manager: "pdm",
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
file: "Pipfile",
|
|
263
|
+
manager: "pipenv",
|
|
264
|
+
},
|
|
145
265
|
{
|
|
146
266
|
file: "pyproject.toml",
|
|
147
267
|
manager: "project",
|
|
148
268
|
},
|
|
149
269
|
],
|
|
150
|
-
|
|
270
|
+
installCommands: {
|
|
151
271
|
requirements: [
|
|
272
|
+
"uv",
|
|
273
|
+
"pip",
|
|
152
274
|
"install",
|
|
153
275
|
"-r",
|
|
154
276
|
"requirements.txt",
|
|
155
277
|
],
|
|
278
|
+
uv: [
|
|
279
|
+
"uv",
|
|
280
|
+
"sync",
|
|
281
|
+
"--locked",
|
|
282
|
+
"--no-dev",
|
|
283
|
+
],
|
|
284
|
+
poetry: [
|
|
285
|
+
"uv",
|
|
286
|
+
"pip",
|
|
287
|
+
"install",
|
|
288
|
+
".",
|
|
289
|
+
],
|
|
290
|
+
pdm: [
|
|
291
|
+
"uv",
|
|
292
|
+
"pip",
|
|
293
|
+
"install",
|
|
294
|
+
".",
|
|
295
|
+
],
|
|
296
|
+
pipenv: [
|
|
297
|
+
"pipenv",
|
|
298
|
+
"install",
|
|
299
|
+
],
|
|
156
300
|
project: [
|
|
301
|
+
"uv",
|
|
302
|
+
"pip",
|
|
157
303
|
"install",
|
|
158
304
|
".",
|
|
159
305
|
],
|
|
160
306
|
},
|
|
307
|
+
unhonouredManagers: [
|
|
308
|
+
"poetry",
|
|
309
|
+
"pdm",
|
|
310
|
+
],
|
|
311
|
+
versionFiles: [
|
|
312
|
+
{
|
|
313
|
+
file: ".python-version",
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
file: "runtime.txt",
|
|
317
|
+
prefix: "python-",
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
file: "Pipfile",
|
|
321
|
+
key: "python_version",
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
file: ".tool-versions",
|
|
325
|
+
tool: "python",
|
|
326
|
+
},
|
|
327
|
+
],
|
|
328
|
+
defaultVersion: "3.12",
|
|
161
329
|
},
|
|
162
330
|
};
|
|
163
331
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import { parseEnvExample } from "./envExample";
|
|
2
|
+
import { isSecretEnvFile, parseEnvExample } from "./envExample";
|
|
3
3
|
|
|
4
4
|
describe("parseEnvExample", () => {
|
|
5
5
|
it("reads keys and example values the way dotenv files write them", () => {
|
|
@@ -27,3 +27,57 @@ describe("parseEnvExample", () => {
|
|
|
27
27
|
]);
|
|
28
28
|
});
|
|
29
29
|
});
|
|
30
|
+
|
|
31
|
+
describe("isSecretEnvFile", () => {
|
|
32
|
+
const CASES: readonly {
|
|
33
|
+
name: string;
|
|
34
|
+
secret: boolean;
|
|
35
|
+
}[] = [
|
|
36
|
+
{
|
|
37
|
+
name: ".env",
|
|
38
|
+
secret: true,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: ".env.local",
|
|
42
|
+
secret: true,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: ".env.production",
|
|
46
|
+
secret: true,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: ".env.example",
|
|
50
|
+
secret: false,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: ".env.sample",
|
|
54
|
+
secret: false,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: ".env.template",
|
|
58
|
+
secret: false,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: ".env.dist",
|
|
62
|
+
secret: false,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: ".env.defaults",
|
|
66
|
+
secret: false,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "env.py",
|
|
70
|
+
secret: false,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: ".envrc",
|
|
74
|
+
secret: false,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
for (const item of CASES) {
|
|
79
|
+
it(`${item.secret ? "holds values" : "holds no values"} in ${item.name}`, () => {
|
|
80
|
+
expect(isSecretEnvFile(item.name)).toBe(item.secret);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
});
|
|
@@ -6,6 +6,16 @@ export const ENV_EXAMPLE_FILES: readonly string[] = [
|
|
|
6
6
|
".env.template",
|
|
7
7
|
];
|
|
8
8
|
|
|
9
|
+
const ENV_TEMPLATE_FILES: ReadonlySet<string> = new Set([
|
|
10
|
+
...ENV_EXAMPLE_FILES,
|
|
11
|
+
".env.dist",
|
|
12
|
+
".env.defaults",
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
export const ENV_FILE = ".env";
|
|
16
|
+
|
|
17
|
+
const ENV_FILE_NAME = /^\.env(?:\..+)?$/;
|
|
18
|
+
|
|
9
19
|
export interface EnvExampleEntry {
|
|
10
20
|
key: string;
|
|
11
21
|
value: string;
|
|
@@ -46,3 +56,7 @@ export const parseEnvExample = (text: string): EnvExampleEntry[] => {
|
|
|
46
56
|
|
|
47
57
|
return entries;
|
|
48
58
|
};
|
|
59
|
+
|
|
60
|
+
export const isSecretEnvFile = (name: string) => {
|
|
61
|
+
return ENV_FILE_NAME.test(name) && !ENV_TEMPLATE_FILES.has(name);
|
|
62
|
+
};
|
package/src/bot/detect/index.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
BOT_AMBIENT_KEYS,
|
|
4
|
+
BOT_PLATFORM_KEYS,
|
|
5
|
+
BOT_PLATFORM_SECRET_KEYS,
|
|
6
|
+
BOT_PROTECTED_KEYS,
|
|
7
|
+
BOT_PROVIDED_KEYS,
|
|
8
|
+
isReservedBotKey,
|
|
9
|
+
} from "./keys";
|
|
3
10
|
|
|
4
11
|
describe("isReservedBotKey", () => {
|
|
5
12
|
it("reserves every platform-owned key, the protected runtime keys and the SERVERK_ prefix", () => {
|
|
@@ -26,3 +33,27 @@ describe("isReservedBotKey", () => {
|
|
|
26
33
|
}
|
|
27
34
|
});
|
|
28
35
|
});
|
|
36
|
+
|
|
37
|
+
describe("BOT_AMBIENT_KEYS", () => {
|
|
38
|
+
it("holds every key the runtime protects or the platform provides, beside the ones code reads with a default", () => {
|
|
39
|
+
for (const key of [
|
|
40
|
+
...BOT_PROTECTED_KEYS,
|
|
41
|
+
...BOT_PROVIDED_KEYS,
|
|
42
|
+
"NODE_ENV",
|
|
43
|
+
"PORT",
|
|
44
|
+
"PYTHONPATH",
|
|
45
|
+
]) {
|
|
46
|
+
expect(BOT_AMBIENT_KEYS.includes(key)).toBe(true);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("leaves a bot's own keys out", () => {
|
|
51
|
+
for (const key of [
|
|
52
|
+
"DISCORD_TOKEN",
|
|
53
|
+
"GUILD_ID",
|
|
54
|
+
"node_env",
|
|
55
|
+
]) {
|
|
56
|
+
expect(BOT_AMBIENT_KEYS.includes(key)).toBe(false);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
});
|
package/src/bot/detect/keys.ts
CHANGED
|
@@ -54,6 +54,21 @@ export const BOT_PROVIDED_KEYS: readonly string[] = [
|
|
|
54
54
|
BOT_PLATFORM,
|
|
55
55
|
];
|
|
56
56
|
|
|
57
|
+
export const BOT_AMBIENT_KEYS: readonly string[] = [
|
|
58
|
+
...BOT_PROTECTED_KEYS,
|
|
59
|
+
...BOT_PROVIDED_KEYS,
|
|
60
|
+
"NODE_ENV",
|
|
61
|
+
"NODE_OPTIONS",
|
|
62
|
+
"PORT",
|
|
63
|
+
"HOST",
|
|
64
|
+
"HOSTNAME",
|
|
65
|
+
"DEBUG",
|
|
66
|
+
"LOG_LEVEL",
|
|
67
|
+
"CI",
|
|
68
|
+
"PYTHONPATH",
|
|
69
|
+
"PYTHONDONTWRITEBYTECODE",
|
|
70
|
+
];
|
|
71
|
+
|
|
57
72
|
export const isReservedBotKey = (key: string) => {
|
|
58
73
|
return (
|
|
59
74
|
key.startsWith(SERVERK_PREFIX)
|
|
@@ -30,6 +30,7 @@ describe("parseServerkJson", () => {
|
|
|
30
30
|
framework: BotFramework.DiscordPy,
|
|
31
31
|
start: "python -m bot",
|
|
32
32
|
install: "pip install -r requirements/prod.txt",
|
|
33
|
+
build: null,
|
|
33
34
|
env: [
|
|
34
35
|
{
|
|
35
36
|
key: "GUILD_ID",
|
|
@@ -52,6 +53,7 @@ describe("parseServerkJson", () => {
|
|
|
52
53
|
framework: null,
|
|
53
54
|
start: null,
|
|
54
55
|
install: null,
|
|
56
|
+
build: null,
|
|
55
57
|
env: [],
|
|
56
58
|
});
|
|
57
59
|
});
|
|
@@ -17,6 +17,7 @@ export interface ServerkJson {
|
|
|
17
17
|
framework: BotFramework | null;
|
|
18
18
|
start: string | null;
|
|
19
19
|
install: string | null;
|
|
20
|
+
build: string | null;
|
|
20
21
|
env: ServerkJsonEnv[];
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -157,9 +158,10 @@ export const parseServerkJson = (text: string): ServerkJson | null => {
|
|
|
157
158
|
const framework = optionalOf(document.framework, isBotFramework);
|
|
158
159
|
const start = commandOf(document.start);
|
|
159
160
|
const install = commandOf(document.install);
|
|
161
|
+
const build = commandOf(document.build);
|
|
160
162
|
const env = envOf(document.env);
|
|
161
163
|
|
|
162
|
-
if (!runtime.ok || !platform.ok || !framework.ok || !start.ok || !install.ok || !env.ok) {
|
|
164
|
+
if (!runtime.ok || !platform.ok || !framework.ok || !start.ok || !install.ok || !build.ok || !env.ok) {
|
|
163
165
|
return null;
|
|
164
166
|
}
|
|
165
167
|
|
|
@@ -169,6 +171,7 @@ export const parseServerkJson = (text: string): ServerkJson | null => {
|
|
|
169
171
|
framework: framework.value,
|
|
170
172
|
start: start.value,
|
|
171
173
|
install: install.value,
|
|
174
|
+
build: build.value,
|
|
172
175
|
env: env.value,
|
|
173
176
|
};
|
|
174
177
|
};
|
package/src/bot/index.ts
CHANGED
package/src/manifest/manifest.ts
CHANGED
|
@@ -224,7 +224,8 @@ export type ManifestFileNote = z.infer<typeof manifestFileNoteSchema>;
|
|
|
224
224
|
|
|
225
225
|
const manifestFilesSchema = z.object({
|
|
226
226
|
protected: z.array(zGlob).max(64).default([]).meta({
|
|
227
|
-
description:
|
|
227
|
+
description:
|
|
228
|
+
"Platform state inside the server directory: hidden from the file manager and left out of archives and copies. Only what the bridge cannot manage without and cannot detect losing.",
|
|
228
229
|
}),
|
|
229
230
|
notable: z.array(manifestFileNoteSchema).max(32).default([]).meta({
|
|
230
231
|
description: "Paths the file manager annotates with a label, note and icon.",
|
package/src/modules/bridge.ts
CHANGED
|
@@ -39,6 +39,7 @@ import type {
|
|
|
39
39
|
BridgeCatalogProvider,
|
|
40
40
|
BridgeCatalogQuery,
|
|
41
41
|
} from "../protocol/bridgeCatalog";
|
|
42
|
+
import type { BridgeCrashReport } from "../protocol/bridgeCrash";
|
|
42
43
|
import type { BridgePendingFile } from "../protocol/bridgeFrame";
|
|
43
44
|
import type { BridgePreview } from "../protocol/bridgePreview";
|
|
44
45
|
import type {
|
|
@@ -96,6 +97,7 @@ export namespace Bridge {
|
|
|
96
97
|
export type Collection<Row extends BridgeRow = BridgeRow> = BridgeCollectionModule<Row>;
|
|
97
98
|
export type Context = BridgeContext;
|
|
98
99
|
export type Copy = BridgeCopy;
|
|
100
|
+
export type CrashReport = BridgeCrashReport;
|
|
99
101
|
export type Detail = BridgeDetailModule;
|
|
100
102
|
export type DetailAction = BridgeDetailAction;
|
|
101
103
|
export type DetailBadge = BridgeDetailBadge;
|
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
BridgeCatalogQuery,
|
|
16
16
|
BridgeCatalogRelease,
|
|
17
17
|
} from "../protocol/bridgeCatalog";
|
|
18
|
+
import type { BridgeCrashReport } from "../protocol/bridgeCrash";
|
|
18
19
|
import type { BridgeBackupSnapshot, BridgeDescribeResult, BridgePendingFile } from "../protocol/bridgeFrame";
|
|
19
20
|
import type { BridgePreview } from "../protocol/bridgePreview";
|
|
20
21
|
import type { BridgeSetupStep } from "../protocol/bridgeSetup";
|
|
@@ -34,6 +35,8 @@ export interface BridgeLifecycleModule {
|
|
|
34
35
|
kind: BridgeKind.Lifecycle;
|
|
35
36
|
ready?: RegExp;
|
|
36
37
|
failed?: RegExp;
|
|
38
|
+
graceSeconds?: number;
|
|
39
|
+
stableLine?: RegExp;
|
|
37
40
|
stopTimeoutSeconds?: number;
|
|
38
41
|
readyTimeoutSeconds?: number;
|
|
39
42
|
stopSignal?: BridgeStopSignal;
|
|
@@ -42,6 +45,8 @@ export interface BridgeLifecycleModule {
|
|
|
42
45
|
environment?(context: BridgeContext): Promise<Record<string, string>>;
|
|
43
46
|
stop?(context: BridgeContext): Promise<void>;
|
|
44
47
|
onReady?(context: BridgeContext): Promise<void>;
|
|
48
|
+
onStable?(context: BridgeContext): Promise<void>;
|
|
49
|
+
onExit?(context: BridgeContext, report: BridgeCrashReport): Promise<void>;
|
|
45
50
|
}
|
|
46
51
|
|
|
47
52
|
export interface BridgeAnnounceModule {
|
|
@@ -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,
|
|
@@ -8,6 +8,15 @@ export enum BridgeCrashCause {
|
|
|
8
8
|
WorldCorrupt = "world-corrupt",
|
|
9
9
|
MissingDependency = "missing-dependency",
|
|
10
10
|
ModCrashed = "mod-crashed",
|
|
11
|
+
TokenInvalid = "token-invalid",
|
|
12
|
+
IntentsDisallowed = "intents-disallowed",
|
|
13
|
+
TokenInUse = "token-in-use",
|
|
14
|
+
WrongTelegramPackage = "wrong-telegram-package",
|
|
15
|
+
WrongDiscordPackage = "wrong-discord-package",
|
|
16
|
+
BuildTools = "build-tools",
|
|
17
|
+
FfmpegMissing = "ffmpeg-missing",
|
|
18
|
+
AudioopRemoved = "audioop-removed",
|
|
19
|
+
RateLimited = "rate-limited",
|
|
11
20
|
Unknown = "unknown",
|
|
12
21
|
}
|
|
13
22
|
|
|
@@ -38,6 +47,22 @@ export const BRIDGE_CRASH_EVIDENCE: readonly BridgeCrashEvidence[] = [
|
|
|
38
47
|
name: BridgeEventName.WorldCorrupt,
|
|
39
48
|
cause: BridgeCrashCause.WorldCorrupt,
|
|
40
49
|
},
|
|
50
|
+
{
|
|
51
|
+
name: BridgeEventName.AudioopRemoved,
|
|
52
|
+
cause: BridgeCrashCause.AudioopRemoved,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: BridgeEventName.WrongTelegramPackage,
|
|
56
|
+
cause: BridgeCrashCause.WrongTelegramPackage,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: BridgeEventName.WrongDiscordPackage,
|
|
60
|
+
cause: BridgeCrashCause.WrongDiscordPackage,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: BridgeEventName.BuildToolsMissing,
|
|
64
|
+
cause: BridgeCrashCause.BuildTools,
|
|
65
|
+
},
|
|
41
66
|
{
|
|
42
67
|
name: BridgeEventName.MissingDependency,
|
|
43
68
|
cause: BridgeCrashCause.MissingDependency,
|
|
@@ -46,6 +71,26 @@ export const BRIDGE_CRASH_EVIDENCE: readonly BridgeCrashEvidence[] = [
|
|
|
46
71
|
name: BridgeEventName.ModCrashed,
|
|
47
72
|
cause: BridgeCrashCause.ModCrashed,
|
|
48
73
|
},
|
|
74
|
+
{
|
|
75
|
+
name: BridgeEventName.FfmpegMissing,
|
|
76
|
+
cause: BridgeCrashCause.FfmpegMissing,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: BridgeEventName.IntentsDisallowed,
|
|
80
|
+
cause: BridgeCrashCause.IntentsDisallowed,
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: BridgeEventName.TokenInvalid,
|
|
84
|
+
cause: BridgeCrashCause.TokenInvalid,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: BridgeEventName.TokenInUse,
|
|
88
|
+
cause: BridgeCrashCause.TokenInUse,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: BridgeEventName.RateLimited,
|
|
92
|
+
cause: BridgeCrashCause.RateLimited,
|
|
93
|
+
},
|
|
49
94
|
];
|
|
50
95
|
|
|
51
96
|
const BRIDGE_CRASH_EVIDENCE_NAMES: ReadonlySet<string> = new Set(BRIDGE_CRASH_EVIDENCE.map((entry) => entry.name));
|
|
@@ -81,3 +126,7 @@ export interface BridgeCrashRecord {
|
|
|
81
126
|
restarts: number;
|
|
82
127
|
lastLine: string | null;
|
|
83
128
|
}
|
|
129
|
+
|
|
130
|
+
export interface BridgeCrashReport extends BridgeCrashRecord {
|
|
131
|
+
cause: BridgeCrashCause;
|
|
132
|
+
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
export enum BridgeEventName {
|
|
2
2
|
AccessGranted = "AccessGranted",
|
|
3
3
|
AccessRevoked = "AccessRevoked",
|
|
4
|
+
AudioopRemoved = "AudioopRemoved",
|
|
4
5
|
BroadcastSent = "BroadcastSent",
|
|
6
|
+
BuildToolsMissing = "BuildToolsMissing",
|
|
7
|
+
FfmpegMissing = "FfmpegMissing",
|
|
5
8
|
GameInstalled = "GameInstalled",
|
|
6
9
|
GameModeChanged = "GameModeChanged",
|
|
7
10
|
GameplayChanged = "GameplayChanged",
|
|
8
11
|
InstallFailed = "InstallFailed",
|
|
12
|
+
IntentsDisallowed = "IntentsDisallowed",
|
|
9
13
|
MemoryUndersized = "MemoryUndersized",
|
|
10
14
|
MissingDependency = "MissingDependency",
|
|
11
15
|
ModCrashed = "ModCrashed",
|
|
@@ -28,6 +32,7 @@ export enum BridgeEventName {
|
|
|
28
32
|
PlayerLeft = "PlayerLeft",
|
|
29
33
|
PlayerUnbanned = "PlayerUnbanned",
|
|
30
34
|
PortBindFailed = "PortBindFailed",
|
|
35
|
+
RateLimited = "RateLimited",
|
|
31
36
|
SecretRotated = "SecretRotated",
|
|
32
37
|
ServerCrashed = "ServerCrashed",
|
|
33
38
|
ServerStarted = "ServerStarted",
|
|
@@ -40,6 +45,8 @@ export enum BridgeEventName {
|
|
|
40
45
|
SetupRejected = "SetupRejected",
|
|
41
46
|
SignInExpired = "SignInExpired",
|
|
42
47
|
TickLagging = "TickLagging",
|
|
48
|
+
TokenInUse = "TokenInUse",
|
|
49
|
+
TokenInvalid = "TokenInvalid",
|
|
43
50
|
WorldActivated = "WorldActivated",
|
|
44
51
|
WorldCloned = "WorldCloned",
|
|
45
52
|
WorldCorrupt = "WorldCorrupt",
|
|
@@ -48,7 +55,9 @@ export enum BridgeEventName {
|
|
|
48
55
|
WorldImported = "WorldImported",
|
|
49
56
|
WorldSaved = "WorldSaved",
|
|
50
57
|
WorldWiped = "WorldWiped",
|
|
58
|
+
WrongDiscordPackage = "WrongDiscordPackage",
|
|
51
59
|
WrongJavaVersion = "WrongJavaVersion",
|
|
60
|
+
WrongTelegramPackage = "WrongTelegramPackage",
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
export const BRIDGE_EVENT_NAMES: readonly string[] = Object.values(BridgeEventName);
|