@serverkgg/bridge 0.1.2 → 0.1.4
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 +65 -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 +179 -31
- package/src/cli/validate.ts +44 -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/protocol/bridgePreview.ts +1 -0
- package/src/rcon/rconAccess.test.ts +20 -20
- package/src/rcon/rconAccess.ts +14 -14
- 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 +84 -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,7 +1,8 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { PORT_BLOCK_MAX_COUNT, PortJoin, PortProtocol } from "../core";
|
|
4
4
|
import { GameCategory } from "./category";
|
|
5
|
+
import { ManifestExtensionKind, ManifestExtensionSource } from "./extension";
|
|
5
6
|
import { buildJsonSchema } from "./jsonSchema";
|
|
6
7
|
import { PackageKind } from "./kind";
|
|
7
8
|
import {
|
|
@@ -174,7 +175,7 @@ const withPortActiveWhen = (activeWhen: unknown) => {
|
|
|
174
175
|
};
|
|
175
176
|
|
|
176
177
|
describe("defaults", () => {
|
|
177
|
-
|
|
178
|
+
it("fills in the optional sections so consumers never guard", () => {
|
|
178
179
|
const manifest = manifestSchema.parse(base());
|
|
179
180
|
|
|
180
181
|
expect(manifest.backup).toEqual({
|
|
@@ -195,11 +196,127 @@ describe("defaults", () => {
|
|
|
195
196
|
expect(manifest.container.ports[0]?.hint).toBeUndefined();
|
|
196
197
|
expect(manifest.container.ports[0]?.join).toBe(PortJoin.Combined);
|
|
197
198
|
expect(manifest.container.ports[0]?.activeWhen).toEqual([]);
|
|
199
|
+
expect(manifest.metadata.extensions).toEqual([]);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe("extensions", () => {
|
|
204
|
+
const withExtensions = (extensions: unknown) => {
|
|
205
|
+
const manifest = base();
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
...manifest,
|
|
209
|
+
metadata: {
|
|
210
|
+
...manifest.metadata,
|
|
211
|
+
extensions,
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
it("carry each kind with its catalogs, and no catalog when it is added by hand", () => {
|
|
217
|
+
const manifest = manifestSchema.parse(
|
|
218
|
+
withExtensions([
|
|
219
|
+
{
|
|
220
|
+
kind: ManifestExtensionKind.Mods,
|
|
221
|
+
sources: [
|
|
222
|
+
ManifestExtensionSource.Modrinth,
|
|
223
|
+
ManifestExtensionSource.CurseForge,
|
|
224
|
+
],
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
kind: ManifestExtensionKind.Plugins,
|
|
228
|
+
},
|
|
229
|
+
]),
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
expect(manifest.metadata.extensions).toEqual([
|
|
233
|
+
{
|
|
234
|
+
kind: ManifestExtensionKind.Mods,
|
|
235
|
+
sources: [
|
|
236
|
+
ManifestExtensionSource.Modrinth,
|
|
237
|
+
ManifestExtensionSource.CurseForge,
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
kind: ManifestExtensionKind.Plugins,
|
|
242
|
+
sources: [],
|
|
243
|
+
},
|
|
244
|
+
]);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("refuse a kind declared twice", () => {
|
|
248
|
+
expect(
|
|
249
|
+
failure(
|
|
250
|
+
withExtensions([
|
|
251
|
+
{
|
|
252
|
+
kind: ManifestExtensionKind.Mods,
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
kind: ManifestExtensionKind.Mods,
|
|
256
|
+
sources: [
|
|
257
|
+
ManifestExtensionSource.CurseForge,
|
|
258
|
+
],
|
|
259
|
+
},
|
|
260
|
+
]),
|
|
261
|
+
),
|
|
262
|
+
).toEqual([
|
|
263
|
+
{
|
|
264
|
+
path: "metadata.extensions.1.kind",
|
|
265
|
+
message: 'extension "mods" is declared twice',
|
|
266
|
+
},
|
|
267
|
+
]);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("refuse a catalog listed twice for one kind", () => {
|
|
271
|
+
expect(
|
|
272
|
+
failure(
|
|
273
|
+
withExtensions([
|
|
274
|
+
{
|
|
275
|
+
kind: ManifestExtensionKind.Mods,
|
|
276
|
+
sources: [
|
|
277
|
+
ManifestExtensionSource.Modrinth,
|
|
278
|
+
ManifestExtensionSource.Modrinth,
|
|
279
|
+
],
|
|
280
|
+
},
|
|
281
|
+
]),
|
|
282
|
+
),
|
|
283
|
+
).toEqual([
|
|
284
|
+
{
|
|
285
|
+
path: "metadata.extensions.0.sources.1",
|
|
286
|
+
message: 'source "modrinth" is listed twice for mods',
|
|
287
|
+
},
|
|
288
|
+
]);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("refuse a catalog the platform does not know", () => {
|
|
292
|
+
expect(
|
|
293
|
+
manifestSchema.safeParse(
|
|
294
|
+
withExtensions([
|
|
295
|
+
{
|
|
296
|
+
kind: ManifestExtensionKind.Mods,
|
|
297
|
+
sources: [
|
|
298
|
+
"steam-workshop",
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
]),
|
|
302
|
+
).success,
|
|
303
|
+
).toBe(false);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it("render into the JSON schema", () => {
|
|
307
|
+
const rendered = JSON.stringify(buildJsonSchema());
|
|
308
|
+
|
|
309
|
+
for (const value of [
|
|
310
|
+
...Object.values(ManifestExtensionKind),
|
|
311
|
+
...Object.values(ManifestExtensionSource),
|
|
312
|
+
]) {
|
|
313
|
+
expect(rendered).toContain(`"${value}"`);
|
|
314
|
+
}
|
|
198
315
|
});
|
|
199
316
|
});
|
|
200
317
|
|
|
201
318
|
describe("port presentation", () => {
|
|
202
|
-
|
|
319
|
+
it("keeps the localized name, hint and join style a port declares", () => {
|
|
203
320
|
const manifest = manifestSchema.parse(
|
|
204
321
|
withPort({
|
|
205
322
|
name: {
|
|
@@ -222,7 +339,7 @@ describe("port presentation", () => {
|
|
|
222
339
|
expect(manifest.container.ports[0]?.join).toBe(PortJoin.Separate);
|
|
223
340
|
});
|
|
224
341
|
|
|
225
|
-
|
|
342
|
+
it("rejects a port name missing one language", () => {
|
|
226
343
|
expect(
|
|
227
344
|
failure(
|
|
228
345
|
withPort({
|
|
@@ -241,7 +358,7 @@ describe("port presentation", () => {
|
|
|
241
358
|
});
|
|
242
359
|
|
|
243
360
|
describe("port srv", () => {
|
|
244
|
-
|
|
361
|
+
it("keeps the service label a port declares", () => {
|
|
245
362
|
const manifest = manifestSchema.parse(
|
|
246
363
|
withPortSrv({
|
|
247
364
|
service: "_minecraft",
|
|
@@ -253,7 +370,7 @@ describe("port srv", () => {
|
|
|
253
370
|
});
|
|
254
371
|
});
|
|
255
372
|
|
|
256
|
-
|
|
373
|
+
it("rejects a service label without its underscore", () => {
|
|
257
374
|
expect(
|
|
258
375
|
failure(
|
|
259
376
|
withPortSrv({
|
|
@@ -270,7 +387,7 @@ describe("port srv", () => {
|
|
|
270
387
|
});
|
|
271
388
|
|
|
272
389
|
describe("port activeWhen", () => {
|
|
273
|
-
|
|
390
|
+
it("keeps every condition a port declares", () => {
|
|
274
391
|
const manifest = manifestSchema.parse(
|
|
275
392
|
withPortActiveWhen([
|
|
276
393
|
{
|
|
@@ -306,7 +423,7 @@ describe("port activeWhen", () => {
|
|
|
306
423
|
]);
|
|
307
424
|
});
|
|
308
425
|
|
|
309
|
-
|
|
426
|
+
it("rejects a condition that declares neither values nor empty", () => {
|
|
310
427
|
expect(
|
|
311
428
|
failure(
|
|
312
429
|
withPortActiveWhen([
|
|
@@ -323,7 +440,7 @@ describe("port activeWhen", () => {
|
|
|
323
440
|
]);
|
|
324
441
|
});
|
|
325
442
|
|
|
326
|
-
|
|
443
|
+
it("rejects a condition whose values list is empty", () => {
|
|
327
444
|
expect(
|
|
328
445
|
failure(
|
|
329
446
|
withPortActiveWhen([
|
|
@@ -341,7 +458,7 @@ describe("port activeWhen", () => {
|
|
|
341
458
|
]);
|
|
342
459
|
});
|
|
343
460
|
|
|
344
|
-
|
|
461
|
+
it("rejects a fifth condition", () => {
|
|
345
462
|
expect(
|
|
346
463
|
failure(
|
|
347
464
|
withPortActiveWhen(
|
|
@@ -361,7 +478,7 @@ describe("port activeWhen", () => {
|
|
|
361
478
|
]);
|
|
362
479
|
});
|
|
363
480
|
|
|
364
|
-
|
|
481
|
+
it("rejects a variable that is not an environment key", () => {
|
|
365
482
|
expect(
|
|
366
483
|
failure(
|
|
367
484
|
withPortActiveWhen([
|
|
@@ -381,7 +498,7 @@ describe("port activeWhen", () => {
|
|
|
381
498
|
});
|
|
382
499
|
|
|
383
500
|
describe("cross-entry checks", () => {
|
|
384
|
-
|
|
501
|
+
it("rejects an image that does not match metadata.id", () => {
|
|
385
502
|
const manifest = base();
|
|
386
503
|
|
|
387
504
|
manifest.container.image = "serverkgg/minecraft-java";
|
|
@@ -394,7 +511,7 @@ describe("cross-entry checks", () => {
|
|
|
394
511
|
]);
|
|
395
512
|
});
|
|
396
513
|
|
|
397
|
-
|
|
514
|
+
it("rejects duplicate secret keys", () => {
|
|
398
515
|
const manifest = {
|
|
399
516
|
...base(),
|
|
400
517
|
secrets: [
|
|
@@ -417,7 +534,7 @@ describe("cross-entry checks", () => {
|
|
|
417
534
|
]);
|
|
418
535
|
});
|
|
419
536
|
|
|
420
|
-
|
|
537
|
+
it("rejects duplicate protected paths and notable matches", () => {
|
|
421
538
|
const manifest = {
|
|
422
539
|
...base(),
|
|
423
540
|
files: {
|
|
@@ -452,7 +569,7 @@ describe("cross-entry checks", () => {
|
|
|
452
569
|
]);
|
|
453
570
|
});
|
|
454
571
|
|
|
455
|
-
|
|
572
|
+
it("rejects duplicate port keys and overlapping host ranges", () => {
|
|
456
573
|
const manifest = base();
|
|
457
574
|
const [game] = manifest.container.ports;
|
|
458
575
|
|
|
@@ -481,7 +598,7 @@ describe("cross-entry checks", () => {
|
|
|
481
598
|
]);
|
|
482
599
|
});
|
|
483
600
|
|
|
484
|
-
|
|
601
|
+
it("rejects a guide tag that is not declared", () => {
|
|
485
602
|
const manifest = {
|
|
486
603
|
...base(),
|
|
487
604
|
guides: [
|
|
@@ -508,7 +625,7 @@ describe("cross-entry checks", () => {
|
|
|
508
625
|
]);
|
|
509
626
|
});
|
|
510
627
|
|
|
511
|
-
|
|
628
|
+
it("rejects one body file serving both locales", () => {
|
|
512
629
|
const manifest = {
|
|
513
630
|
...base(),
|
|
514
631
|
guides: [
|
|
@@ -534,7 +651,7 @@ describe("cross-entry checks", () => {
|
|
|
534
651
|
});
|
|
535
652
|
|
|
536
653
|
describe("field validation", () => {
|
|
537
|
-
|
|
654
|
+
it("explains a bad host range instead of saying nothing", () => {
|
|
538
655
|
const manifest = base();
|
|
539
656
|
const [game] = manifest.container.ports;
|
|
540
657
|
|
|
@@ -556,7 +673,7 @@ describe("field validation", () => {
|
|
|
556
673
|
]);
|
|
557
674
|
});
|
|
558
675
|
|
|
559
|
-
|
|
676
|
+
it("explains a default that sits outside its range", () => {
|
|
560
677
|
const manifest = base();
|
|
561
678
|
const [game] = manifest.container.ports;
|
|
562
679
|
|
|
@@ -574,7 +691,7 @@ describe("field validation", () => {
|
|
|
574
691
|
]);
|
|
575
692
|
});
|
|
576
693
|
|
|
577
|
-
|
|
694
|
+
it("explains a bad colour", () => {
|
|
578
695
|
const manifest = {
|
|
579
696
|
...base(),
|
|
580
697
|
files: {
|
|
@@ -597,7 +714,7 @@ describe("field validation", () => {
|
|
|
597
714
|
]);
|
|
598
715
|
});
|
|
599
716
|
|
|
600
|
-
|
|
717
|
+
it("field failures short-circuit the cross-entry checks", () => {
|
|
601
718
|
const manifest = base();
|
|
602
719
|
|
|
603
720
|
manifest.metadata.id = "Minecraft";
|
|
@@ -615,7 +732,7 @@ describe("field validation", () => {
|
|
|
615
732
|
});
|
|
616
733
|
|
|
617
734
|
describe("packageSchema", () => {
|
|
618
|
-
|
|
735
|
+
it("routes on kind without a separate pre-parse", () => {
|
|
619
736
|
const game = packageSchema.parse(base());
|
|
620
737
|
|
|
621
738
|
expect(game.kind).toBe(PackageKind.Game);
|
|
@@ -642,7 +759,7 @@ describe("packageSchema", () => {
|
|
|
642
759
|
expect(guides.kind).toBe(PackageKind.Guide);
|
|
643
760
|
});
|
|
644
761
|
|
|
645
|
-
|
|
762
|
+
it("guide packages get the same guide checks", () => {
|
|
646
763
|
const result = guidePackageSchema.safeParse({
|
|
647
764
|
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
648
765
|
kind: "GuidePackage",
|
|
@@ -669,7 +786,7 @@ describe("packageSchema", () => {
|
|
|
669
786
|
expect(result.error && z.prettifyError(result.error)).toContain('tag "start" is not declared in guideTags');
|
|
670
787
|
});
|
|
671
788
|
|
|
672
|
-
|
|
789
|
+
it("carries up to 64 guides", () => {
|
|
673
790
|
const many = (count: number) =>
|
|
674
791
|
Array.from(
|
|
675
792
|
{
|
|
@@ -684,14 +801,14 @@ describe("packageSchema", () => {
|
|
|
684
801
|
});
|
|
685
802
|
|
|
686
803
|
describe("presence", () => {
|
|
687
|
-
|
|
804
|
+
it("is optional, so a game that declares none parses", () => {
|
|
688
805
|
const result = manifestSchema.safeParse(base());
|
|
689
806
|
|
|
690
807
|
expect(result.success).toBe(true);
|
|
691
808
|
expect(result.success && result.data.presence).toBeUndefined();
|
|
692
809
|
});
|
|
693
810
|
|
|
694
|
-
|
|
811
|
+
it("defaults the name key to player and the field list to empty", () => {
|
|
695
812
|
const result = manifestSchema.safeParse({
|
|
696
813
|
...base(),
|
|
697
814
|
presence: {},
|
|
@@ -702,7 +819,7 @@ describe("presence", () => {
|
|
|
702
819
|
expect(result.success && result.data.presence?.fields).toEqual([]);
|
|
703
820
|
});
|
|
704
821
|
|
|
705
|
-
|
|
822
|
+
it("accepts an avatar template and localized fields", () => {
|
|
706
823
|
const result = manifestSchema.safeParse({
|
|
707
824
|
...base(),
|
|
708
825
|
presence: {
|
|
@@ -722,7 +839,7 @@ describe("presence", () => {
|
|
|
722
839
|
expect(result.success && result.data.presence?.fields[0]?.inline).toBe(true);
|
|
723
840
|
});
|
|
724
841
|
|
|
725
|
-
|
|
842
|
+
it("accepts a serverk avatar template", () => {
|
|
726
843
|
const result = manifestSchema.safeParse({
|
|
727
844
|
...base(),
|
|
728
845
|
presence: {
|
|
@@ -736,7 +853,7 @@ describe("presence", () => {
|
|
|
736
853
|
expect(result.success && result.data.presence?.avatar).toBe("serverk://avatars/hytale/{playerId}");
|
|
737
854
|
});
|
|
738
855
|
|
|
739
|
-
|
|
856
|
+
it("refuses an avatar template that is neither https nor a serverk avatar", () => {
|
|
740
857
|
const result = manifestSchema.safeParse({
|
|
741
858
|
...base(),
|
|
742
859
|
presence: {
|
|
@@ -750,7 +867,7 @@ describe("presence", () => {
|
|
|
750
867
|
);
|
|
751
868
|
});
|
|
752
869
|
|
|
753
|
-
|
|
870
|
+
it("refuses a serverk scheme that is not an avatar path", () => {
|
|
754
871
|
const result = manifestSchema.safeParse({
|
|
755
872
|
...base(),
|
|
756
873
|
presence: {
|
|
@@ -764,7 +881,7 @@ describe("presence", () => {
|
|
|
764
881
|
);
|
|
765
882
|
});
|
|
766
883
|
|
|
767
|
-
|
|
884
|
+
it("refuses a serverk avatar template longer than the limit", () => {
|
|
768
885
|
const result = manifestSchema.safeParse({
|
|
769
886
|
...base(),
|
|
770
887
|
presence: {
|
|
@@ -775,12 +892,12 @@ describe("presence", () => {
|
|
|
775
892
|
expect(result.success).toBe(false);
|
|
776
893
|
});
|
|
777
894
|
|
|
778
|
-
|
|
895
|
+
it("tells a serverk avatar template apart from an https one", () => {
|
|
779
896
|
expect(isServerkAvatarTemplate("serverk://avatars/hytale/{playerId}")).toBe(true);
|
|
780
897
|
expect(isServerkAvatarTemplate("https://mc-heads.net/avatar/{skin}/128")).toBe(false);
|
|
781
898
|
});
|
|
782
899
|
|
|
783
|
-
|
|
900
|
+
it("refuses a payload key that could never be a capture group", () => {
|
|
784
901
|
const result = manifestSchema.safeParse({
|
|
785
902
|
...base(),
|
|
786
903
|
presence: {
|
|
@@ -792,7 +909,7 @@ describe("presence", () => {
|
|
|
792
909
|
expect(result.error && z.prettifyError(result.error)).toContain("must be a valid capture group name");
|
|
793
910
|
});
|
|
794
911
|
|
|
795
|
-
|
|
912
|
+
it("refuses the same field declared twice", () => {
|
|
796
913
|
const result = manifestSchema.safeParse({
|
|
797
914
|
...base(),
|
|
798
915
|
presence: {
|
|
@@ -815,7 +932,7 @@ describe("presence", () => {
|
|
|
815
932
|
});
|
|
816
933
|
|
|
817
934
|
describe("container runtime", () => {
|
|
818
|
-
|
|
935
|
+
it("materializes the defaults when the manifest declares no runtime", () => {
|
|
819
936
|
const manifest = manifestSchema.parse(base());
|
|
820
937
|
|
|
821
938
|
expect(manifest.container.runtime).toEqual({
|
|
@@ -829,7 +946,7 @@ describe("container runtime", () => {
|
|
|
829
946
|
expect(MANIFEST_RUNTIME_DEFAULTS).toEqual(manifest.container.runtime);
|
|
830
947
|
});
|
|
831
948
|
|
|
832
|
-
|
|
949
|
+
it("keeps every field a manifest declares", () => {
|
|
833
950
|
const manifest = manifestSchema.parse(
|
|
834
951
|
withRuntime({
|
|
835
952
|
platform: ManifestPlatform.Wine,
|
|
@@ -857,7 +974,7 @@ describe("container runtime", () => {
|
|
|
857
974
|
});
|
|
858
975
|
});
|
|
859
976
|
|
|
860
|
-
|
|
977
|
+
it("clamps an install budget above the ceiling", () => {
|
|
861
978
|
expect(
|
|
862
979
|
failure(
|
|
863
980
|
withRuntime({
|
|
@@ -872,7 +989,7 @@ describe("container runtime", () => {
|
|
|
872
989
|
]);
|
|
873
990
|
});
|
|
874
991
|
|
|
875
|
-
|
|
992
|
+
it("clamps a boot budget below the floor", () => {
|
|
876
993
|
expect(
|
|
877
994
|
failure(
|
|
878
995
|
withRuntime({
|
|
@@ -887,7 +1004,7 @@ describe("container runtime", () => {
|
|
|
887
1004
|
]);
|
|
888
1005
|
});
|
|
889
1006
|
|
|
890
|
-
|
|
1007
|
+
it("clamps shared memory and the pids limit to their range", () => {
|
|
891
1008
|
expect(
|
|
892
1009
|
failure(
|
|
893
1010
|
withRuntime({
|
|
@@ -907,7 +1024,7 @@ describe("container runtime", () => {
|
|
|
907
1024
|
]);
|
|
908
1025
|
});
|
|
909
1026
|
|
|
910
|
-
|
|
1027
|
+
it("refuses a fourth capability", () => {
|
|
911
1028
|
expect(
|
|
912
1029
|
failure(
|
|
913
1030
|
withRuntime({
|
|
@@ -927,7 +1044,7 @@ describe("container runtime", () => {
|
|
|
927
1044
|
]);
|
|
928
1045
|
});
|
|
929
1046
|
|
|
930
|
-
|
|
1047
|
+
it("refuses a capability outside the allow-list", () => {
|
|
931
1048
|
expect(
|
|
932
1049
|
failure(
|
|
933
1050
|
withRuntime({
|
|
@@ -944,7 +1061,7 @@ describe("container runtime", () => {
|
|
|
944
1061
|
]);
|
|
945
1062
|
});
|
|
946
1063
|
|
|
947
|
-
|
|
1064
|
+
it("refuses a wine platform running on the default shared memory", () => {
|
|
948
1065
|
expect(
|
|
949
1066
|
failure(
|
|
950
1067
|
withRuntime({
|
|
@@ -959,7 +1076,7 @@ describe("container runtime", () => {
|
|
|
959
1076
|
]);
|
|
960
1077
|
});
|
|
961
1078
|
|
|
962
|
-
|
|
1079
|
+
it("accepts a wine platform once shared memory clears the floor", () => {
|
|
963
1080
|
const manifest = manifestSchema.parse(
|
|
964
1081
|
withRuntime({
|
|
965
1082
|
platform: ManifestPlatform.Wine,
|
|
@@ -972,7 +1089,7 @@ describe("container runtime", () => {
|
|
|
972
1089
|
});
|
|
973
1090
|
|
|
974
1091
|
describe("manifestRuntimeOf", () => {
|
|
975
|
-
|
|
1092
|
+
it("reads the runtime a manifest declares", () => {
|
|
976
1093
|
const manifest = manifestSchema.parse(
|
|
977
1094
|
withRuntime({
|
|
978
1095
|
platform: ManifestPlatform.Wine,
|
|
@@ -987,7 +1104,7 @@ describe("manifestRuntimeOf", () => {
|
|
|
987
1104
|
});
|
|
988
1105
|
});
|
|
989
1106
|
|
|
990
|
-
|
|
1107
|
+
it("falls back to the defaults for a bundle published before the field existed", () => {
|
|
991
1108
|
const manifest = manifestSchema.parse(base());
|
|
992
1109
|
const legacy = {
|
|
993
1110
|
...manifest,
|
|
@@ -1002,14 +1119,14 @@ describe("manifestRuntimeOf", () => {
|
|
|
1002
1119
|
});
|
|
1003
1120
|
|
|
1004
1121
|
describe("port mirroring", () => {
|
|
1005
|
-
|
|
1122
|
+
it("defaults to no mirror and no follower", () => {
|
|
1006
1123
|
const manifest = manifestSchema.parse(base());
|
|
1007
1124
|
|
|
1008
1125
|
expect(manifest.container.ports[0]?.mirror).toBe(false);
|
|
1009
1126
|
expect(manifest.container.ports[0]?.follows).toBeUndefined();
|
|
1010
1127
|
});
|
|
1011
1128
|
|
|
1012
|
-
|
|
1129
|
+
it("keeps the mirror flag and the follow rule a manifest declares", () => {
|
|
1013
1130
|
const manifest = manifestSchema.parse(
|
|
1014
1131
|
withPorts([
|
|
1015
1132
|
udpPort("game", 27_015, 27_015),
|
|
@@ -1030,7 +1147,7 @@ describe("port mirroring", () => {
|
|
|
1030
1147
|
});
|
|
1031
1148
|
});
|
|
1032
1149
|
|
|
1033
|
-
|
|
1150
|
+
it("refuses a follow rule naming a port that is not declared", () => {
|
|
1034
1151
|
expect(
|
|
1035
1152
|
failure(
|
|
1036
1153
|
withPorts([
|
|
@@ -1051,7 +1168,7 @@ describe("port mirroring", () => {
|
|
|
1051
1168
|
]);
|
|
1052
1169
|
});
|
|
1053
1170
|
|
|
1054
|
-
|
|
1171
|
+
it("refuses a port that follows itself", () => {
|
|
1055
1172
|
expect(
|
|
1056
1173
|
failure(
|
|
1057
1174
|
withPorts([
|
|
@@ -1072,7 +1189,7 @@ describe("port mirroring", () => {
|
|
|
1072
1189
|
]);
|
|
1073
1190
|
});
|
|
1074
1191
|
|
|
1075
|
-
|
|
1192
|
+
it("refuses a follow rule crossing protocols", () => {
|
|
1076
1193
|
const [tcp] = base().container.ports;
|
|
1077
1194
|
|
|
1078
1195
|
if (!tcp) {
|
|
@@ -1100,7 +1217,7 @@ describe("port mirroring", () => {
|
|
|
1100
1217
|
]);
|
|
1101
1218
|
});
|
|
1102
1219
|
|
|
1103
|
-
|
|
1220
|
+
it("refuses a port that both follows and is followed", () => {
|
|
1104
1221
|
expect(
|
|
1105
1222
|
failure(
|
|
1106
1223
|
withPorts([
|
|
@@ -1129,7 +1246,7 @@ describe("port mirroring", () => {
|
|
|
1129
1246
|
]);
|
|
1130
1247
|
});
|
|
1131
1248
|
|
|
1132
|
-
|
|
1249
|
+
it("lets a follower's host range overlap the port it follows", () => {
|
|
1133
1250
|
const manifest = manifestSchema.parse(
|
|
1134
1251
|
withPorts([
|
|
1135
1252
|
udpPort("game", 27_015, 27_015),
|
|
@@ -1146,7 +1263,7 @@ describe("port mirroring", () => {
|
|
|
1146
1263
|
expect(manifest.container.ports[1]?.hostRange.min).toBe(27_016);
|
|
1147
1264
|
});
|
|
1148
1265
|
|
|
1149
|
-
|
|
1266
|
+
it("still refuses two independent ports whose host ranges overlap", () => {
|
|
1150
1267
|
expect(
|
|
1151
1268
|
failure(
|
|
1152
1269
|
withPorts([
|
|
@@ -1162,7 +1279,7 @@ describe("port mirroring", () => {
|
|
|
1162
1279
|
]);
|
|
1163
1280
|
});
|
|
1164
1281
|
|
|
1165
|
-
|
|
1282
|
+
it("refuses an offset outside its range", () => {
|
|
1166
1283
|
expect(
|
|
1167
1284
|
failure(
|
|
1168
1285
|
withPorts([
|
|
@@ -1204,13 +1321,13 @@ describe("port pairs and blocks", () => {
|
|
|
1204
1321
|
},
|
|
1205
1322
|
});
|
|
1206
1323
|
|
|
1207
|
-
|
|
1324
|
+
it("defaults a port to a single binding", () => {
|
|
1208
1325
|
const manifest = manifestSchema.parse(base());
|
|
1209
1326
|
|
|
1210
1327
|
expect(manifest.container.ports[0]?.count).toBe(1);
|
|
1211
1328
|
});
|
|
1212
1329
|
|
|
1213
|
-
|
|
1330
|
+
it("accepts a tcp+udp join port beside a udp media block", () => {
|
|
1214
1331
|
const manifest = manifestSchema.parse(
|
|
1215
1332
|
withPorts([
|
|
1216
1333
|
pairPort("game", 19_132),
|
|
@@ -1235,7 +1352,7 @@ describe("port pairs and blocks", () => {
|
|
|
1235
1352
|
]);
|
|
1236
1353
|
});
|
|
1237
1354
|
|
|
1238
|
-
|
|
1355
|
+
it("refuses a count above the block limit", () => {
|
|
1239
1356
|
expect(
|
|
1240
1357
|
failure(
|
|
1241
1358
|
withPorts([
|
|
@@ -1250,7 +1367,7 @@ describe("port pairs and blocks", () => {
|
|
|
1250
1367
|
]);
|
|
1251
1368
|
});
|
|
1252
1369
|
|
|
1253
|
-
|
|
1370
|
+
it("refuses a block whose host range cannot hold it", () => {
|
|
1254
1371
|
expect(
|
|
1255
1372
|
failure(
|
|
1256
1373
|
withPorts([
|
|
@@ -1281,7 +1398,7 @@ describe("port pairs and blocks", () => {
|
|
|
1281
1398
|
},
|
|
1282
1399
|
});
|
|
1283
1400
|
|
|
1284
|
-
|
|
1401
|
+
it("lets a single port span the whole cap", () => {
|
|
1285
1402
|
const manifest = manifestSchema.parse(
|
|
1286
1403
|
withPorts([
|
|
1287
1404
|
spanning("game", 20_000, 20_999, 1),
|
|
@@ -1291,7 +1408,7 @@ describe("port pairs and blocks", () => {
|
|
|
1291
1408
|
expect(manifest.container.ports[0]?.hostRange.max).toBe(20_999);
|
|
1292
1409
|
});
|
|
1293
1410
|
|
|
1294
|
-
|
|
1411
|
+
it("refuses a single port spanning one more than the cap", () => {
|
|
1295
1412
|
expect(
|
|
1296
1413
|
failure(
|
|
1297
1414
|
withPorts([
|
|
@@ -1306,7 +1423,7 @@ describe("port pairs and blocks", () => {
|
|
|
1306
1423
|
]);
|
|
1307
1424
|
});
|
|
1308
1425
|
|
|
1309
|
-
|
|
1426
|
+
it("counts the span of a block in slots, so 100 slots of 64 pass", () => {
|
|
1310
1427
|
const manifest = manifestSchema.parse(
|
|
1311
1428
|
withPorts([
|
|
1312
1429
|
spanning("media", 20_000, 26_399, 64),
|
|
@@ -1316,7 +1433,7 @@ describe("port pairs and blocks", () => {
|
|
|
1316
1433
|
expect(manifest.container.ports[0]?.count).toBe(64);
|
|
1317
1434
|
});
|
|
1318
1435
|
|
|
1319
|
-
|
|
1436
|
+
it("refuses a block spanning more slots than the cap", () => {
|
|
1320
1437
|
expect(
|
|
1321
1438
|
failure(
|
|
1322
1439
|
withPorts([
|
|
@@ -1331,7 +1448,7 @@ describe("port pairs and blocks", () => {
|
|
|
1331
1448
|
]);
|
|
1332
1449
|
});
|
|
1333
1450
|
|
|
1334
|
-
|
|
1451
|
+
it("refuses a block whose default leaves no room for the whole block", () => {
|
|
1335
1452
|
expect(
|
|
1336
1453
|
failure(
|
|
1337
1454
|
withPorts([
|
|
@@ -1353,7 +1470,7 @@ describe("port pairs and blocks", () => {
|
|
|
1353
1470
|
]);
|
|
1354
1471
|
});
|
|
1355
1472
|
|
|
1356
|
-
|
|
1473
|
+
it("refuses a non-mirrored block that runs past the last port", () => {
|
|
1357
1474
|
expect(
|
|
1358
1475
|
failure(
|
|
1359
1476
|
withPorts([
|
|
@@ -1372,7 +1489,7 @@ describe("port pairs and blocks", () => {
|
|
|
1372
1489
|
]);
|
|
1373
1490
|
});
|
|
1374
1491
|
|
|
1375
|
-
|
|
1492
|
+
it("refuses the player-address fields on a block", () => {
|
|
1376
1493
|
expect(
|
|
1377
1494
|
failure(
|
|
1378
1495
|
withPorts([
|
|
@@ -1407,7 +1524,7 @@ describe("port pairs and blocks", () => {
|
|
|
1407
1524
|
]);
|
|
1408
1525
|
});
|
|
1409
1526
|
|
|
1410
|
-
|
|
1527
|
+
it("refuses a block that follows a port", () => {
|
|
1411
1528
|
expect(
|
|
1412
1529
|
failure(
|
|
1413
1530
|
withPorts([
|
|
@@ -1429,7 +1546,7 @@ describe("port pairs and blocks", () => {
|
|
|
1429
1546
|
]);
|
|
1430
1547
|
});
|
|
1431
1548
|
|
|
1432
|
-
|
|
1549
|
+
it("refuses a port that follows a block", () => {
|
|
1433
1550
|
expect(
|
|
1434
1551
|
failure(
|
|
1435
1552
|
withPorts([
|
|
@@ -1451,7 +1568,7 @@ describe("port pairs and blocks", () => {
|
|
|
1451
1568
|
]);
|
|
1452
1569
|
});
|
|
1453
1570
|
|
|
1454
|
-
|
|
1571
|
+
it("refuses srv on a tcp+udp port", () => {
|
|
1455
1572
|
expect(
|
|
1456
1573
|
failure(
|
|
1457
1574
|
withPorts([
|
|
@@ -1471,7 +1588,7 @@ describe("port pairs and blocks", () => {
|
|
|
1471
1588
|
]);
|
|
1472
1589
|
});
|
|
1473
1590
|
|
|
1474
|
-
|
|
1591
|
+
it("refuses a tcp+udp port that follows another", () => {
|
|
1475
1592
|
expect(
|
|
1476
1593
|
failure(
|
|
1477
1594
|
withPorts([
|
|
@@ -1493,7 +1610,7 @@ describe("port pairs and blocks", () => {
|
|
|
1493
1610
|
]);
|
|
1494
1611
|
});
|
|
1495
1612
|
|
|
1496
|
-
|
|
1613
|
+
it("refuses a port that follows a tcp+udp port", () => {
|
|
1497
1614
|
expect(
|
|
1498
1615
|
failure(
|
|
1499
1616
|
withPorts([
|
|
@@ -1515,7 +1632,7 @@ describe("port pairs and blocks", () => {
|
|
|
1515
1632
|
]);
|
|
1516
1633
|
});
|
|
1517
1634
|
|
|
1518
|
-
|
|
1635
|
+
it("refuses a tcp+udp port overlapping a udp port on the shared protocol", () => {
|
|
1519
1636
|
expect(
|
|
1520
1637
|
failure(
|
|
1521
1638
|
withPorts([
|
|
@@ -1531,7 +1648,7 @@ describe("port pairs and blocks", () => {
|
|
|
1531
1648
|
]);
|
|
1532
1649
|
});
|
|
1533
1650
|
|
|
1534
|
-
|
|
1651
|
+
it("lets a tcp port and a udp port share a host range", () => {
|
|
1535
1652
|
const [tcp] = base().container.ports;
|
|
1536
1653
|
|
|
1537
1654
|
if (!tcp) {
|
|
@@ -1548,7 +1665,7 @@ describe("port pairs and blocks", () => {
|
|
|
1548
1665
|
expect(manifest.container.ports).toHaveLength(2);
|
|
1549
1666
|
});
|
|
1550
1667
|
|
|
1551
|
-
|
|
1668
|
+
it("refuses a manifest whose pairs expand past the socket port limit", () => {
|
|
1552
1669
|
expect(
|
|
1553
1670
|
failure(
|
|
1554
1671
|
withPorts(
|
|
@@ -1625,17 +1742,18 @@ const yamlSource = (document: unknown): PackageSource => {
|
|
|
1625
1742
|
};
|
|
1626
1743
|
|
|
1627
1744
|
describe("bot packages", () => {
|
|
1628
|
-
|
|
1745
|
+
it("parse with no ports and no category", () => {
|
|
1629
1746
|
const manifest = botManifestSchema.parse(botBase());
|
|
1630
1747
|
|
|
1631
1748
|
expect(manifest.kind).toBe(PackageKind.Bot);
|
|
1632
1749
|
expect(manifest.container.ports).toEqual([]);
|
|
1633
1750
|
expect("category" in manifest.metadata).toBe(false);
|
|
1751
|
+
expect("extensions" in manifest.metadata).toBe(false);
|
|
1634
1752
|
expect(manifest.secrets).toBeUndefined();
|
|
1635
1753
|
expect(manifest.presence).toBeUndefined();
|
|
1636
1754
|
});
|
|
1637
1755
|
|
|
1638
|
-
|
|
1756
|
+
it("default the ports to none when a bot declares no ports key", () => {
|
|
1639
1757
|
const { container, ...rest } = botBase();
|
|
1640
1758
|
const manifest = botManifestSchema.parse({
|
|
1641
1759
|
...rest,
|
|
@@ -1647,7 +1765,7 @@ describe("bot packages", () => {
|
|
|
1647
1765
|
expect(manifest.container.ports).toEqual([]);
|
|
1648
1766
|
});
|
|
1649
1767
|
|
|
1650
|
-
|
|
1768
|
+
it("refuse a secrets list with the environment vault named as the place for per-bot values", () => {
|
|
1651
1769
|
expect(
|
|
1652
1770
|
botFailure({
|
|
1653
1771
|
...botBase(),
|
|
@@ -1661,7 +1779,7 @@ describe("bot packages", () => {
|
|
|
1661
1779
|
]);
|
|
1662
1780
|
});
|
|
1663
1781
|
|
|
1664
|
-
|
|
1782
|
+
it("keep the environment vault off unless the package turns it on", () => {
|
|
1665
1783
|
expect(botManifestSchema.parse(botBase()).environment.vault).toBe(false);
|
|
1666
1784
|
expect(
|
|
1667
1785
|
botManifestSchema.parse({
|
|
@@ -1673,7 +1791,7 @@ describe("bot packages", () => {
|
|
|
1673
1791
|
).toBe(true);
|
|
1674
1792
|
});
|
|
1675
1793
|
|
|
1676
|
-
|
|
1794
|
+
it("refuse a vault flag that is not a boolean", () => {
|
|
1677
1795
|
expect(
|
|
1678
1796
|
botFailure({
|
|
1679
1797
|
...botBase(),
|
|
@@ -1686,7 +1804,7 @@ describe("bot packages", () => {
|
|
|
1686
1804
|
]);
|
|
1687
1805
|
});
|
|
1688
1806
|
|
|
1689
|
-
|
|
1807
|
+
it("refuse a presence block", () => {
|
|
1690
1808
|
expect(
|
|
1691
1809
|
botFailure({
|
|
1692
1810
|
...botBase(),
|
|
@@ -1702,7 +1820,7 @@ describe("bot packages", () => {
|
|
|
1702
1820
|
]);
|
|
1703
1821
|
});
|
|
1704
1822
|
|
|
1705
|
-
|
|
1823
|
+
it("still run the shared package checks", () => {
|
|
1706
1824
|
expect(
|
|
1707
1825
|
botFailure({
|
|
1708
1826
|
...botBase(),
|
|
@@ -1719,7 +1837,7 @@ describe("bot packages", () => {
|
|
|
1719
1837
|
]);
|
|
1720
1838
|
});
|
|
1721
1839
|
|
|
1722
|
-
|
|
1840
|
+
it("keep a port a bot declares for a webhook", () => {
|
|
1723
1841
|
const manifest = botManifestSchema.parse({
|
|
1724
1842
|
...botBase(),
|
|
1725
1843
|
container: {
|
|
@@ -1731,7 +1849,7 @@ describe("bot packages", () => {
|
|
|
1731
1849
|
expect(manifest.container.ports).toHaveLength(1);
|
|
1732
1850
|
});
|
|
1733
1851
|
|
|
1734
|
-
|
|
1852
|
+
it("reach the runtime reader like a game does", () => {
|
|
1735
1853
|
expect(manifestRuntimeOf(botManifestSchema.parse(botBase()))).toEqual({
|
|
1736
1854
|
...MANIFEST_RUNTIME_DEFAULTS,
|
|
1737
1855
|
pidsLimit: 256,
|
|
@@ -1740,7 +1858,7 @@ describe("bot packages", () => {
|
|
|
1740
1858
|
});
|
|
1741
1859
|
|
|
1742
1860
|
describe("package kinds", () => {
|
|
1743
|
-
|
|
1861
|
+
it("route all three kinds through packageSchema", () => {
|
|
1744
1862
|
expect(packageSchema.parse(base()).kind).toBe(PackageKind.Game);
|
|
1745
1863
|
expect(packageSchema.parse(botBase()).kind).toBe(PackageKind.Bot);
|
|
1746
1864
|
expect(
|
|
@@ -1752,13 +1870,13 @@ describe("package kinds", () => {
|
|
|
1752
1870
|
).toBe(PackageKind.Guide);
|
|
1753
1871
|
});
|
|
1754
1872
|
|
|
1755
|
-
|
|
1873
|
+
it("keep a game package on the game rules, so it still needs a port", () => {
|
|
1756
1874
|
const result = packageSchema.safeParse(withPorts([]));
|
|
1757
1875
|
|
|
1758
1876
|
expect(result.success).toBe(false);
|
|
1759
1877
|
});
|
|
1760
1878
|
|
|
1761
|
-
|
|
1879
|
+
it("refuse a guide package where a runnable package is expected", () => {
|
|
1762
1880
|
expect(
|
|
1763
1881
|
runnablePackageSchema.safeParse(
|
|
1764
1882
|
guidePackage([
|
|
@@ -1768,7 +1886,7 @@ describe("package kinds", () => {
|
|
|
1768
1886
|
).toBe(false);
|
|
1769
1887
|
});
|
|
1770
1888
|
|
|
1771
|
-
|
|
1889
|
+
it("tell a game from a bot", () => {
|
|
1772
1890
|
const game = runnablePackageSchema.parse(base());
|
|
1773
1891
|
const bot = runnablePackageSchema.parse(botBase());
|
|
1774
1892
|
|
|
@@ -1778,24 +1896,24 @@ describe("package kinds", () => {
|
|
|
1778
1896
|
expect(isGameManifest(bot)).toBe(false);
|
|
1779
1897
|
});
|
|
1780
1898
|
|
|
1781
|
-
|
|
1899
|
+
it("keep the old game schema name pointing at the game schema for this release", () => {
|
|
1782
1900
|
expect(manifestSchema).toBe(gameManifestSchema);
|
|
1783
1901
|
});
|
|
1784
1902
|
|
|
1785
|
-
|
|
1903
|
+
it("read a bot package from its source", () => {
|
|
1786
1904
|
const { manifest } = readPackage(yamlSource(botBase()));
|
|
1787
1905
|
|
|
1788
1906
|
expect(manifest.kind).toBe(PackageKind.Bot);
|
|
1789
1907
|
expect(manifest.metadata.id).toBe("bot-node");
|
|
1790
1908
|
});
|
|
1791
1909
|
|
|
1792
|
-
|
|
1910
|
+
it("read a game package from its source unchanged", () => {
|
|
1793
1911
|
const { manifest } = readPackage(yamlSource(base()));
|
|
1794
1912
|
|
|
1795
1913
|
expect(isGameManifest(manifest) && manifest.secrets).toEqual([]);
|
|
1796
1914
|
});
|
|
1797
1915
|
|
|
1798
|
-
|
|
1916
|
+
it("render every kind literal into the JSON schema", () => {
|
|
1799
1917
|
const rendered = JSON.stringify(buildJsonSchema());
|
|
1800
1918
|
|
|
1801
1919
|
for (const kind of Object.values(PackageKind)) {
|