@serverkgg/bridge 0.1.2 → 0.1.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/package.json +3 -2
- package/rules/package.md +60 -0
- package/src/blog/articleFrontmatter.test.ts +10 -10
- package/src/blog/compile.test.ts +9 -9
- package/src/bot/botDeploy.test.ts +16 -16
- package/src/bot/botEnvironment.test.ts +8 -8
- package/src/bot/botIdentity.test.ts +12 -12
- package/src/bot/botPanel.test.ts +13 -13
- package/src/bot/botPanel.ts +4 -4
- package/src/bot/botState.test.ts +3 -3
- package/src/bot/botTerminal.test.ts +5 -5
- package/src/bot/botVariables.test.ts +8 -8
- package/src/bot/detect/botToken.test.ts +6 -6
- package/src/bot/detect/detect.test.ts +21 -21
- package/src/bot/detect/detectTable.test.ts +5 -5
- package/src/bot/detect/envExample.test.ts +2 -2
- package/src/bot/detect/envScan.test.ts +4 -4
- package/src/bot/detect/inferBotPlatform.test.ts +4 -4
- package/src/bot/detect/keys.test.ts +3 -3
- package/src/bot/detect/sensitiveKey.test.ts +5 -5
- package/src/bot/detect/serverkJson.test.ts +5 -5
- package/src/catalogs/curseforge.test.ts +35 -35
- package/src/catalogs/thunderstore.test.ts +9 -9
- package/src/cli/detectTable.test.ts +3 -3
- package/src/cli/link.test.ts +11 -11
- package/src/cli/main.ts +8 -0
- package/src/cli/rules.test.ts +198 -0
- package/src/cli/rules.ts +188 -0
- package/src/cli/validate.test.ts +52 -30
- package/src/cli/validate.ts +2 -0
- package/src/codecs/ini.test.ts +13 -13
- package/src/codecs/javaProperties.test.ts +11 -11
- package/src/codecs/sourceCfg.test.ts +14 -14
- package/src/codecs/xmlProperties.test.ts +10 -10
- package/src/core/bridgePort.test.ts +6 -6
- package/src/core/bridgeUserError.test.ts +4 -4
- package/src/core/bridgeValue.test.ts +5 -5
- package/src/core/describeDownloadFailure.test.ts +12 -12
- package/src/core/describeDownloadFailure.ts +10 -10
- package/src/guides/markdown.test.ts +31 -31
- package/src/install/installStamp.test.ts +9 -9
- package/src/manifest/extension.ts +36 -0
- package/src/manifest/index.ts +1 -0
- package/src/manifest/manifest.test.ts +208 -90
- package/src/manifest/manifest.ts +34 -0
- package/src/net/loopback.test.ts +10 -10
- package/src/presence/rosterSync.test.ts +7 -7
- package/src/probes/a2s.test.ts +5 -5
- package/src/probes/minecraftPing.test.ts +17 -17
- package/src/probes/raknetPing.test.ts +13 -13
- package/src/rcon/rconAccess.test.ts +20 -20
- package/src/rcon/rconAccess.ts +13 -13
- package/src/rcon/rconClient.test.ts +49 -49
- package/src/rcon/rconFrame.test.ts +14 -14
- package/src/rcon/rconIds.test.ts +4 -4
- package/src/rcon/rconWriter.test.ts +6 -6
- package/src/runtime/bridgeActivity.test.ts +15 -15
- package/src/runtime/bridgeBackupLease.test.ts +9 -9
- package/src/runtime/bridgeConfigReader.test.ts +5 -5
- package/src/runtime/bridgeConsoleHandler.test.ts +8 -8
- package/src/runtime/bridgeContext.test.ts +5 -5
- package/src/runtime/bridgeDriver.test.ts +94 -94
- package/src/runtime/bridgeEvents.test.ts +15 -15
- package/src/runtime/bridgeFiles.test.ts +54 -54
- package/src/runtime/bridgeInstall.test.ts +10 -10
- package/src/runtime/bridgeLiveConfig.test.ts +6 -6
- package/src/runtime/bridgePending.test.ts +6 -6
- package/src/runtime/bridgeRedaction.test.ts +16 -16
- package/src/runtime/bridgeRegistry.test.ts +52 -52
- package/src/runtime/bridgeRegistry.ts +2 -2
- package/src/runtime/bridgeServer.test.ts +31 -31
- package/src/runtime/bridgeSetup.test.ts +27 -27
- package/src/runtime/bridgeSetup.ts +1 -1
- package/src/runtime/bridgeSetupHandlers.test.ts +13 -13
- package/src/runtime/bridgeSignal.test.ts +7 -7
- package/src/runtime/bridgeSupervisor.test.ts +42 -42
- package/src/runtime/serve.ts +4 -4
- package/src/steam/avatars.test.ts +13 -13
- package/src/steam/steamApp.test.ts +8 -8
- package/src/steam/steamcmd.test.ts +17 -17
- package/src/steam/steamcmd.ts +4 -4
- package/src/steam/steamcmdNarrator.test.ts +4 -4
- package/src/steam/workshop.test.ts +5 -5
- package/src/utils/changedSettingKeys.test.ts +5 -5
- package/src/utils/describeExecFailure.test.ts +4 -4
- package/src/utils/describeExecFailure.ts +1 -1
- package/src/utils/sameSettingValue.test.ts +7 -7
- package/src/utils/token.test.ts +7 -7
- package/src/wine/protonCommand.test.ts +5 -5
- package/src/wine/wineCommand.test.ts +6 -6
- package/src/wine/winePrefix.test.ts +6 -6
- package/src/wire/activity.test.ts +8 -8
- package/src/wire/panel.test.ts +28 -28
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
2
|
import { GuideOpenTab } from "./blocks";
|
|
3
3
|
import { parseGuideMarkdown } from "./markdown";
|
|
4
4
|
|
|
5
5
|
const parse = (text: string) => parseGuideMarkdown("guides/test/en.md", text);
|
|
6
6
|
|
|
7
7
|
describe("static blocks", () => {
|
|
8
|
-
|
|
8
|
+
it("parses the existing block vocabulary", () => {
|
|
9
9
|
const { blocks } = parse(
|
|
10
10
|
[
|
|
11
11
|
"## Join the game",
|
|
@@ -32,7 +32,7 @@ describe("static blocks", () => {
|
|
|
32
32
|
]);
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
it("still rejects what it always rejected", () => {
|
|
36
36
|
expect(() => parse("# Title")).toThrow(/h1 is not supported/);
|
|
37
37
|
expect(() => parse("| a | b |")).toThrow(/tables are not supported/);
|
|
38
38
|
expect(() => parse("<div>hi</div>")).toThrow(/raw HTML/);
|
|
@@ -41,7 +41,7 @@ describe("static blocks", () => {
|
|
|
41
41
|
});
|
|
42
42
|
|
|
43
43
|
describe("variables", () => {
|
|
44
|
-
|
|
44
|
+
it("parses an inline variable", () => {
|
|
45
45
|
const { blocks } = parse("Your address is {{server.address}} — paste it in.");
|
|
46
46
|
|
|
47
47
|
expect(blocks[0]).toEqual({
|
|
@@ -63,7 +63,7 @@ describe("variables", () => {
|
|
|
63
63
|
});
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
it("accepts a panel variable", () => {
|
|
67
67
|
const { blocks } = parse("The motd is {{panel.MOTD}}.");
|
|
68
68
|
|
|
69
69
|
expect(blocks[0]).toMatchObject({
|
|
@@ -76,19 +76,19 @@ describe("variables", () => {
|
|
|
76
76
|
});
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
it("rejects an unknown key", () => {
|
|
80
80
|
expect(() => parse("Your address is {{server.adress}}.")).toThrow(/unknown variable "server.adress"/);
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
it("rejects a lowercase panel key", () => {
|
|
84
84
|
expect(() => parse("{{panel.motd}} is set.")).toThrow(/unknown variable/);
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
it("rejects an unterminated marker", () => {
|
|
88
88
|
expect(() => parse("Your address is {{server.address.")).toThrow(/unterminated \{\{ marker/);
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
-
|
|
91
|
+
it("rejects a variable inside a link target", () => {
|
|
92
92
|
expect(() => parse("See [your server](/server/{{server.code}}).")).toThrow(
|
|
93
93
|
/variables cannot be used inside a link target/,
|
|
94
94
|
);
|
|
@@ -96,7 +96,7 @@ describe("variables", () => {
|
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
describe("directives", () => {
|
|
99
|
-
|
|
99
|
+
it("parses a field", () => {
|
|
100
100
|
const { blocks } = parse("@[field](server.address)");
|
|
101
101
|
|
|
102
102
|
expect(blocks[0]).toEqual({
|
|
@@ -105,11 +105,11 @@ describe("directives", () => {
|
|
|
105
105
|
});
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
it("rejects a field with an unknown key", () => {
|
|
109
109
|
expect(() => parse("@[field](server.nope)")).toThrow(/unknown variable "server.nope"/);
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
it("parses a command and collects it", () => {
|
|
113
113
|
const result = parse("@[command](whitelist on)");
|
|
114
114
|
|
|
115
115
|
expect(result.blocks[0]).toEqual({
|
|
@@ -121,11 +121,11 @@ describe("directives", () => {
|
|
|
121
121
|
]);
|
|
122
122
|
});
|
|
123
123
|
|
|
124
|
-
|
|
124
|
+
it("rejects an empty command", () => {
|
|
125
125
|
expect(() => parse("@[command]()")).toThrow(/a command must be a single line/);
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
it("parses every open target", () => {
|
|
129
129
|
const { blocks } = parse(
|
|
130
130
|
[
|
|
131
131
|
"@[open](console)",
|
|
@@ -187,27 +187,27 @@ describe("directives", () => {
|
|
|
187
187
|
]);
|
|
188
188
|
});
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
it("rejects a panel target without a tab id", () => {
|
|
191
191
|
expect(() => parse("@[open](panel)")).toThrow(/panel target needs a tab id/);
|
|
192
192
|
});
|
|
193
193
|
|
|
194
|
-
|
|
194
|
+
it("rejects an unknown open target", () => {
|
|
195
195
|
expect(() => parse("@[open](nowhere)")).toThrow(/unknown open target "nowhere"/);
|
|
196
196
|
});
|
|
197
197
|
|
|
198
|
-
|
|
198
|
+
it("rejects an argument on a target that takes none", () => {
|
|
199
199
|
expect(() => parse("@[open](setup:sign-in)")).toThrow(/"setup" target does not take an argument/);
|
|
200
200
|
});
|
|
201
201
|
|
|
202
|
-
|
|
202
|
+
it("rejects a traversing file path", () => {
|
|
203
203
|
expect(() => parse("@[open](files:../../etc/passwd)")).toThrow();
|
|
204
204
|
});
|
|
205
205
|
|
|
206
|
-
|
|
206
|
+
it("rejects an unknown directive", () => {
|
|
207
207
|
expect(() => parse("@[embed](something)")).toThrow(/unknown directive @\[embed\]/);
|
|
208
208
|
});
|
|
209
209
|
|
|
210
|
-
|
|
210
|
+
it("keeps the youtube directive working", () => {
|
|
211
211
|
const { blocks } = parse("@[youtube](dQw4w9WgXcQ)");
|
|
212
212
|
|
|
213
213
|
expect(blocks[0]).toEqual({
|
|
@@ -216,7 +216,7 @@ describe("directives", () => {
|
|
|
216
216
|
});
|
|
217
217
|
});
|
|
218
218
|
|
|
219
|
-
|
|
219
|
+
it("does not swallow a directive into the paragraph above it", () => {
|
|
220
220
|
const { blocks } = parse(
|
|
221
221
|
[
|
|
222
222
|
"Copy your address:",
|
|
@@ -232,7 +232,7 @@ describe("directives", () => {
|
|
|
232
232
|
});
|
|
233
233
|
|
|
234
234
|
describe("conditionals", () => {
|
|
235
|
-
|
|
235
|
+
it("parses both branches", () => {
|
|
236
236
|
const { blocks } = parse(
|
|
237
237
|
[
|
|
238
238
|
":::when server.address",
|
|
@@ -279,7 +279,7 @@ describe("conditionals", () => {
|
|
|
279
279
|
]);
|
|
280
280
|
});
|
|
281
281
|
|
|
282
|
-
|
|
282
|
+
it("allows a missing else branch", () => {
|
|
283
283
|
const { blocks } = parse(
|
|
284
284
|
[
|
|
285
285
|
":::when server.address",
|
|
@@ -294,7 +294,7 @@ describe("conditionals", () => {
|
|
|
294
294
|
});
|
|
295
295
|
});
|
|
296
296
|
|
|
297
|
-
|
|
297
|
+
it("keeps blocks around a conditional", () => {
|
|
298
298
|
const { blocks } = parse(
|
|
299
299
|
[
|
|
300
300
|
"## Join the game",
|
|
@@ -314,7 +314,7 @@ describe("conditionals", () => {
|
|
|
314
314
|
]);
|
|
315
315
|
});
|
|
316
316
|
|
|
317
|
-
|
|
317
|
+
it("parses two conditionals in a row", () => {
|
|
318
318
|
const { blocks } = parse(
|
|
319
319
|
[
|
|
320
320
|
":::when server.address",
|
|
@@ -332,7 +332,7 @@ describe("conditionals", () => {
|
|
|
332
332
|
]);
|
|
333
333
|
});
|
|
334
334
|
|
|
335
|
-
|
|
335
|
+
it("rejects nesting", () => {
|
|
336
336
|
expect(() =>
|
|
337
337
|
parse(
|
|
338
338
|
[
|
|
@@ -346,7 +346,7 @@ describe("conditionals", () => {
|
|
|
346
346
|
).toThrow(/conditionals cannot be nested/);
|
|
347
347
|
});
|
|
348
348
|
|
|
349
|
-
|
|
349
|
+
it("rejects an unterminated block", () => {
|
|
350
350
|
expect(() =>
|
|
351
351
|
parse(
|
|
352
352
|
[
|
|
@@ -357,7 +357,7 @@ describe("conditionals", () => {
|
|
|
357
357
|
).toThrow(/unterminated :::when block/);
|
|
358
358
|
});
|
|
359
359
|
|
|
360
|
-
|
|
360
|
+
it("rejects an empty when branch", () => {
|
|
361
361
|
expect(() =>
|
|
362
362
|
parse(
|
|
363
363
|
[
|
|
@@ -370,11 +370,11 @@ describe("conditionals", () => {
|
|
|
370
370
|
).toThrow(/empty :::when branch/);
|
|
371
371
|
});
|
|
372
372
|
|
|
373
|
-
|
|
373
|
+
it("rejects a stray close", () => {
|
|
374
374
|
expect(() => parse(":::")).toThrow(/unexpected ::: without a matching :::when/);
|
|
375
375
|
});
|
|
376
376
|
|
|
377
|
-
|
|
377
|
+
it("rejects an unknown key", () => {
|
|
378
378
|
expect(() =>
|
|
379
379
|
parse(
|
|
380
380
|
[
|
|
@@ -386,7 +386,7 @@ describe("conditionals", () => {
|
|
|
386
386
|
).toThrow(/unknown variable "server.nope"/);
|
|
387
387
|
});
|
|
388
388
|
|
|
389
|
-
|
|
389
|
+
it("rejects a malformed opener", () => {
|
|
390
390
|
expect(() => parse(":::if server.address")).toThrow(/conditionals open with :::when/);
|
|
391
391
|
});
|
|
392
392
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
2
|
import type { BridgeContext } from "../context";
|
|
3
3
|
import { INSTALL_STAMP_FILE, parseStamp, readStamp, writeStamp } from "./installStamp";
|
|
4
4
|
|
|
@@ -31,7 +31,7 @@ const testContext = (seed: Record<string, string> = {}) => {
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
describe("parseStamp", () => {
|
|
34
|
-
|
|
34
|
+
it("reads a json object", () => {
|
|
35
35
|
expect(
|
|
36
36
|
parseStamp<TestStamp>(
|
|
37
37
|
JSON.stringify({
|
|
@@ -43,7 +43,7 @@ describe("parseStamp", () => {
|
|
|
43
43
|
});
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
it("returns null for anything that is not a json object", () => {
|
|
47
47
|
expect(parseStamp("")).toBeNull();
|
|
48
48
|
expect(parseStamp("{")).toBeNull();
|
|
49
49
|
expect(parseStamp("null")).toBeNull();
|
|
@@ -53,13 +53,13 @@ describe("parseStamp", () => {
|
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
describe("readStamp", () => {
|
|
56
|
-
|
|
56
|
+
it("returns null when the stamp file is absent", async () => {
|
|
57
57
|
const { context } = testContext();
|
|
58
58
|
|
|
59
59
|
expect(await readStamp(context)).toBeNull();
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
it("reads the stamp the writer left behind", async () => {
|
|
63
63
|
const { context } = testContext();
|
|
64
64
|
|
|
65
65
|
await writeStamp<TestStamp>(context, {
|
|
@@ -73,7 +73,7 @@ describe("readStamp", () => {
|
|
|
73
73
|
});
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
it("writes pretty json ending in a newline", async () => {
|
|
77
77
|
const { context, stored } = testContext();
|
|
78
78
|
|
|
79
79
|
await writeStamp(context, {
|
|
@@ -83,7 +83,7 @@ describe("readStamp", () => {
|
|
|
83
83
|
expect(stored.get(INSTALL_STAMP_FILE)).toBe('{\n "buildId": "1"\n}\n');
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
it("honours a custom stamp path", async () => {
|
|
87
87
|
const { context, stored } = testContext();
|
|
88
88
|
|
|
89
89
|
await writeStamp(
|
|
@@ -100,7 +100,7 @@ describe("readStamp", () => {
|
|
|
100
100
|
});
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
it("returns null when the read fails after the file was seen", async () => {
|
|
104
104
|
const context = {
|
|
105
105
|
files: {
|
|
106
106
|
async exists() {
|
|
@@ -115,7 +115,7 @@ describe("readStamp", () => {
|
|
|
115
115
|
expect(await readStamp(context)).toBeNull();
|
|
116
116
|
});
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
it("returns null when the stamp file is corrupt", async () => {
|
|
119
119
|
const { context } = testContext({
|
|
120
120
|
[INSTALL_STAMP_FILE]: "not json",
|
|
121
121
|
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export enum ManifestExtensionKind {
|
|
4
|
+
Mods = "mods",
|
|
5
|
+
Plugins = "plugins",
|
|
6
|
+
Addons = "addons",
|
|
7
|
+
Modpacks = "modpacks",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export enum ManifestExtensionSource {
|
|
11
|
+
Modrinth = "modrinth",
|
|
12
|
+
CurseForge = "curseforge",
|
|
13
|
+
Hangar = "hangar",
|
|
14
|
+
Thunderstore = "thunderstore",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const EXTENSIONS_LIMIT = Object.values(ManifestExtensionKind).length;
|
|
18
|
+
|
|
19
|
+
export const EXTENSION_SOURCES_LIMIT = Object.values(ManifestExtensionSource).length;
|
|
20
|
+
|
|
21
|
+
export const manifestExtensionSchema = z.object({
|
|
22
|
+
kind: z.enum(ManifestExtensionKind).meta({
|
|
23
|
+
description: "What the customer adds to the game: mods, plugins, add-ons or modpacks.",
|
|
24
|
+
}),
|
|
25
|
+
sources: z.array(z.enum(ManifestExtensionSource)).max(EXTENSION_SOURCES_LIMIT).default([]).meta({
|
|
26
|
+
description:
|
|
27
|
+
"The catalogs the panel installs this kind from. Leave it empty when the customer adds them by hand through the files.",
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export type ManifestExtension = z.infer<typeof manifestExtensionSchema>;
|
|
32
|
+
|
|
33
|
+
export const manifestExtensionsSchema = z.array(manifestExtensionSchema).max(EXTENSIONS_LIMIT).default([]).meta({
|
|
34
|
+
description:
|
|
35
|
+
"What a customer can add to this game, and from which catalogs. The public pages claim only what is declared here; declare nothing when the game takes no additions.",
|
|
36
|
+
});
|