@serverkgg/bridge 0.1.1 → 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.
Files changed (121) hide show
  1. package/package.json +3 -2
  2. package/rules/package.md +60 -0
  3. package/src/blog/articleFrontmatter.test.ts +10 -10
  4. package/src/blog/compile.test.ts +9 -9
  5. package/src/bot/botDeploy.test.ts +16 -16
  6. package/src/bot/botEnvironment.test.ts +8 -8
  7. package/src/bot/botIdentity.test.ts +12 -12
  8. package/src/bot/botPanel.test.ts +41 -11
  9. package/src/bot/botPanel.ts +13 -5
  10. package/src/bot/botState.test.ts +3 -3
  11. package/src/bot/botTerminal.test.ts +5 -5
  12. package/src/bot/botVariables.test.ts +8 -8
  13. package/src/bot/detect/botToken.test.ts +6 -6
  14. package/src/bot/detect/detect.test.ts +21 -21
  15. package/src/bot/detect/detectTable.test.ts +5 -5
  16. package/src/bot/detect/envExample.test.ts +2 -2
  17. package/src/bot/detect/envScan.test.ts +4 -4
  18. package/src/bot/detect/inferBotPlatform.test.ts +4 -4
  19. package/src/bot/detect/keys.test.ts +3 -3
  20. package/src/bot/detect/sensitiveKey.test.ts +5 -5
  21. package/src/bot/detect/serverkJson.test.ts +5 -5
  22. package/src/catalogs/curseforge.test.ts +35 -35
  23. package/src/catalogs/thunderstore.test.ts +9 -9
  24. package/src/cli/detectTable.test.ts +3 -3
  25. package/src/cli/link.test.ts +11 -11
  26. package/src/cli/main.ts +8 -0
  27. package/src/cli/rules.test.ts +198 -0
  28. package/src/cli/rules.ts +188 -0
  29. package/src/cli/validate.test.ts +123 -29
  30. package/src/cli/validate.ts +37 -1
  31. package/src/codecs/ini.test.ts +13 -13
  32. package/src/codecs/javaProperties.test.ts +11 -11
  33. package/src/codecs/sourceCfg.test.ts +14 -14
  34. package/src/codecs/xmlProperties.test.ts +10 -10
  35. package/src/context/bridgeContext.ts +6 -1
  36. package/src/core/bridgeAction.ts +2 -0
  37. package/src/core/bridgeActivity.ts +9 -0
  38. package/src/core/bridgeAvailability.ts +10 -0
  39. package/src/core/bridgePort.test.ts +6 -6
  40. package/src/core/bridgeUserError.test.ts +13 -3
  41. package/src/core/bridgeUserError.ts +6 -2
  42. package/src/core/bridgeValue.test.ts +5 -5
  43. package/src/core/describeDownloadFailure.test.ts +58 -0
  44. package/src/core/describeDownloadFailure.ts +69 -0
  45. package/src/core/index.ts +3 -0
  46. package/src/guides/markdown.test.ts +31 -31
  47. package/src/install/installStamp.test.ts +9 -9
  48. package/src/manifest/extension.ts +36 -0
  49. package/src/manifest/index.ts +1 -0
  50. package/src/manifest/manifest.test.ts +208 -90
  51. package/src/manifest/manifest.ts +34 -0
  52. package/src/modules/bridge.ts +8 -1
  53. package/src/modules/bridgeModule.ts +13 -1
  54. package/src/net/loopback.test.ts +10 -10
  55. package/src/panel/bridgeDetail.ts +2 -1
  56. package/src/presence/rosterSync.test.ts +7 -7
  57. package/src/probes/a2s.test.ts +5 -5
  58. package/src/probes/minecraftPing.test.ts +17 -17
  59. package/src/probes/raknetPing.test.ts +13 -13
  60. package/src/protocol/bridgeActivity.ts +54 -0
  61. package/src/protocol/bridgeEvents.ts +30 -0
  62. package/src/protocol/bridgeFrame.ts +10 -1
  63. package/src/protocol/index.ts +1 -0
  64. package/src/rcon/rconAccess.test.ts +20 -20
  65. package/src/rcon/rconAccess.ts +13 -13
  66. package/src/rcon/rconClient.test.ts +49 -49
  67. package/src/rcon/rconFrame.test.ts +14 -14
  68. package/src/rcon/rconIds.test.ts +4 -4
  69. package/src/rcon/rconWriter.test.ts +6 -6
  70. package/src/runtime/bridgeActions.ts +19 -2
  71. package/src/runtime/bridgeActivity.test.ts +318 -0
  72. package/src/runtime/bridgeActivity.ts +268 -0
  73. package/src/runtime/bridgeBackupLease.test.ts +9 -9
  74. package/src/runtime/bridgeConfigReader.test.ts +5 -5
  75. package/src/runtime/bridgeConsoleHandler.test.ts +8 -8
  76. package/src/runtime/bridgeContext.test.ts +11 -5
  77. package/src/runtime/bridgeContext.ts +8 -1
  78. package/src/runtime/bridgeDriver.test.ts +114 -93
  79. package/src/runtime/bridgeDriver.ts +10 -7
  80. package/src/runtime/bridgeEvents.test.ts +15 -15
  81. package/src/runtime/bridgeFiles.test.ts +54 -54
  82. package/src/runtime/bridgeInstall.test.ts +10 -10
  83. package/src/runtime/bridgeLiveConfig.test.ts +6 -6
  84. package/src/runtime/bridgeLog.ts +10 -0
  85. package/src/runtime/bridgePending.test.ts +6 -6
  86. package/src/runtime/bridgeRedaction.test.ts +16 -16
  87. package/src/runtime/bridgeRefusalError.ts +13 -0
  88. package/src/runtime/bridgeRegistry.test.ts +1077 -34
  89. package/src/runtime/bridgeRegistry.ts +464 -65
  90. package/src/runtime/bridgeScopedContext.ts +55 -0
  91. package/src/runtime/bridgeServer.test.ts +424 -24
  92. package/src/runtime/bridgeServer.ts +125 -35
  93. package/src/runtime/bridgeSetup.test.ts +27 -27
  94. package/src/runtime/bridgeSetup.ts +1 -1
  95. package/src/runtime/bridgeSetupHandlers.test.ts +80 -17
  96. package/src/runtime/bridgeSetupHandlers.ts +45 -10
  97. package/src/runtime/bridgeSignal.test.ts +7 -7
  98. package/src/runtime/bridgeSupervisor.test.ts +42 -42
  99. package/src/runtime/serve.ts +45 -3
  100. package/src/steam/avatars.test.ts +13 -13
  101. package/src/steam/steamApp.test.ts +8 -8
  102. package/src/steam/steamcmd.test.ts +44 -13
  103. package/src/steam/steamcmd.ts +27 -4
  104. package/src/steam/steamcmdNarrator.test.ts +4 -4
  105. package/src/steam/workshop.test.ts +5 -5
  106. package/src/utils/changedSettingKeys.test.ts +65 -0
  107. package/src/utils/changedSettingKeys.ts +6 -0
  108. package/src/utils/describeExecFailure.test.ts +34 -0
  109. package/src/utils/describeExecFailure.ts +9 -0
  110. package/src/utils/index.ts +3 -0
  111. package/src/utils/sameSettingValue.test.ts +35 -0
  112. package/src/utils/sameSettingValue.ts +40 -0
  113. package/src/utils/token.test.ts +7 -7
  114. package/src/wine/protonCommand.test.ts +5 -5
  115. package/src/wine/wineCommand.test.ts +6 -6
  116. package/src/wine/winePrefix.test.ts +6 -6
  117. package/src/wire/activity.test.ts +95 -0
  118. package/src/wire/activity.ts +41 -0
  119. package/src/wire/index.ts +1 -0
  120. package/src/wire/panel.test.ts +91 -25
  121. package/src/wire/panel.ts +11 -0
@@ -1,4 +1,4 @@
1
- import { describe, expect, test } from "bun:test";
1
+ import { describe, expect, it } from "bun:test";
2
2
  import { BridgeKind, BridgeSetupStepKind, PortJoin, PortProtocol } from "../core";
3
3
  import { GuideOpenTab } from "../guides";
4
4
  import type { ManifestPort, ManifestPortActivation } from "../manifest";
@@ -275,23 +275,44 @@ const driverWithTabs = (tabs: number, sections: number): BridgeDriver => ({
275
275
  });
276
276
 
277
277
  describe("panel caps", () => {
278
- test("takes the tab and section counts the agent mirror accepts", () => {
278
+ it("rejects a collection row action named after a read action", () => {
279
+ const driver = driverWithTabs(1, 1);
280
+
281
+ driver.modules = {
282
+ ...driver.modules,
283
+ worlds: {
284
+ kind: BridgeKind.Collection,
285
+ list: async () => [],
286
+ actions: {
287
+ preview: async () => {
288
+ return;
289
+ },
290
+ },
291
+ },
292
+ };
293
+
294
+ expect(() => validateDriver(driver)).toThrow(
295
+ 'module "worlds" declares action "preview", which is reserved for reads',
296
+ );
297
+ });
298
+
299
+ it("takes the tab and section counts the agent mirror accepts", () => {
279
300
  expect(() => validateDriver(driverWithTabs(8, 8))).not.toThrow();
280
301
  });
281
302
 
282
- test("rejects a ninth tab the agent mirror would drop", () => {
303
+ it("rejects a ninth tab the agent mirror would drop", () => {
283
304
  expect(() => validateDriver(driverWithTabs(9, 1))).toThrow(
284
305
  "the panel declares 9 tabs — the platform takes at most 8",
285
306
  );
286
307
  });
287
308
 
288
- test("rejects a ninth section the agent mirror would drop", () => {
309
+ it("rejects a ninth section the agent mirror would drop", () => {
289
310
  expect(() => validateDriver(driverWithTabs(1, 9))).toThrow(
290
311
  'tab "tab-0" declares 9 sections — the platform takes at most 8',
291
312
  );
292
313
  });
293
314
 
294
- test("rejects a form carrying more fields than the agent mirror accepts", () => {
315
+ it("rejects a form carrying more fields than the agent mirror accepts", () => {
295
316
  const driver = driverWithTabs(1, 1);
296
317
  const [tab] = driver.panel?.tabs ?? [];
297
318
  const [section] = tab?.sections ?? [];
@@ -307,7 +328,7 @@ describe("panel caps", () => {
307
328
  expect(() => validateDriver(driver)).toThrow("declares 33 fields — the platform takes at most 32");
308
329
  });
309
330
 
310
- test("rejects a table carrying more columns than the agent mirror accepts", () => {
331
+ it("rejects a table carrying more columns than the agent mirror accepts", () => {
311
332
  const driver = driverWithTabs(1, 1);
312
333
  const [tab] = driver.panel?.tabs ?? [];
313
334
 
@@ -339,7 +360,7 @@ describe("panel caps", () => {
339
360
  expect(() => validateDriver(driver)).toThrow("declares 9 columns — the platform takes at most 8");
340
361
  });
341
362
 
342
- test("rejects a label longer than the agent mirror accepts", () => {
363
+ it("rejects a label longer than the agent mirror accepts", () => {
343
364
  const driver = driverWithTabs(1, 1);
344
365
  const [tab] = driver.panel?.tabs ?? [];
345
366
 
@@ -356,7 +377,7 @@ describe("panel caps", () => {
356
377
  });
357
378
 
358
379
  describe("actions sections", () => {
359
- test("accepts an action the module implements", () => {
380
+ it("accepts an action the module implements", () => {
360
381
  expect(() =>
361
382
  validateDriver(
362
383
  driverWithActions([
@@ -372,7 +393,7 @@ describe("actions sections", () => {
372
393
  ).not.toThrow();
373
394
  });
374
395
 
375
- test("rejects an action the module does not implement", () => {
396
+ it("rejects an action the module does not implement", () => {
376
397
  expect(() =>
377
398
  validateDriver(
378
399
  driverWithActions([
@@ -385,11 +406,11 @@ describe("actions sections", () => {
385
406
  ).toThrow('declares action "shout", which module "broadcast" does not implement');
386
407
  });
387
408
 
388
- test("rejects a section with no actions", () => {
409
+ it("rejects a section with no actions", () => {
389
410
  expect(() => validateDriver(driverWithActions([]))).toThrow("declares no actions");
390
411
  });
391
412
 
392
- test("rejects an action carrying more fields than one prompt fits", () => {
413
+ it("rejects an action carrying more fields than one prompt fits", () => {
393
414
  expect(() =>
394
415
  validateDriver(
395
416
  driverWithActions([
@@ -410,7 +431,7 @@ describe("actions sections", () => {
410
431
  ).toThrow('action "say" declares 6 fields — at most 5 fit one prompt');
411
432
  });
412
433
 
413
- test("rejects a section pointing at a module that is not an actions module", () => {
434
+ it("rejects a section pointing at a module that is not an actions module", () => {
414
435
  const driver = driverWithActions([
415
436
  {
416
437
  id: "say",
@@ -428,7 +449,7 @@ describe("actions sections", () => {
428
449
  expect(() => validateDriver(driver)).toThrow('references "broadcast", which is not an actions module');
429
450
  });
430
451
 
431
- test("checks the fields a row action declares", () => {
452
+ it("checks the fields a row action declares", () => {
432
453
  const driver = driverWithActions([
433
454
  {
434
455
  id: "say",
@@ -489,7 +510,7 @@ describe("actions sections", () => {
489
510
  });
490
511
 
491
512
  describe("visibleWhen", () => {
492
- test("accepts a rule that matches on values", () => {
513
+ it("accepts a rule that matches on values", () => {
493
514
  expect(() =>
494
515
  validateDriver(
495
516
  driverWith({
@@ -502,7 +523,7 @@ describe("visibleWhen", () => {
502
523
  ).not.toThrow();
503
524
  });
504
525
 
505
- test("accepts a rule that matches on emptiness", () => {
526
+ it("accepts a rule that matches on emptiness", () => {
506
527
  expect(() =>
507
528
  validateDriver(
508
529
  driverWith({
@@ -522,7 +543,7 @@ describe("visibleWhen", () => {
522
543
  ).not.toThrow();
523
544
  });
524
545
 
525
- test("accepts a rule that narrows values inside a presence check", () => {
546
+ it("accepts a rule that narrows values inside a presence check", () => {
526
547
  expect(() =>
527
548
  validateDriver(
528
549
  driverWith({
@@ -536,7 +557,7 @@ describe("visibleWhen", () => {
536
557
  ).not.toThrow();
537
558
  });
538
559
 
539
- test("rejects a rule that declares neither values nor empty", () => {
560
+ it("rejects a rule that declares neither values nor empty", () => {
540
561
  expect(() =>
541
562
  validateDriver(
542
563
  driverWith({
@@ -546,7 +567,7 @@ describe("visibleWhen", () => {
546
567
  ).toThrow('is visible when "MODPACK" matches nothing');
547
568
  });
548
569
 
549
- test("rejects an empty values list", () => {
570
+ it("rejects an empty values list", () => {
550
571
  expect(() =>
551
572
  validateDriver(
552
573
  driverWith({
@@ -557,7 +578,7 @@ describe("visibleWhen", () => {
557
578
  ).toThrow('is visible when "MODPACK" matches nothing');
558
579
  });
559
580
 
560
- test("checks a field rule as well as a section rule", () => {
581
+ it("checks a field rule as well as a section rule", () => {
561
582
  const driver = driverWith({
562
583
  variable: "MODPACK",
563
584
  empty: true,
@@ -584,11 +605,11 @@ describe("visibleWhen", () => {
584
605
  });
585
606
 
586
607
  describe("form preview", () => {
587
- test("accepts a variables form pointing at a preview module", () => {
608
+ it("accepts a variables form pointing at a preview module", () => {
588
609
  expect(() => validateDriver(driverWithPreview())).not.toThrow();
589
610
  });
590
611
 
591
- test("rejects a preview ref to a module that is not a preview module", () => {
612
+ it("rejects a preview ref to a module that is not a preview module", () => {
592
613
  const driver = driverWithPreview();
593
614
 
594
615
  driver.modules = {
@@ -601,7 +622,7 @@ describe("form preview", () => {
601
622
  expect(() => validateDriver(driver)).toThrow('references "transition", which is not a preview module');
602
623
  });
603
624
 
604
- test("rejects a preview on a form that writes settings", () => {
625
+ it("rejects a preview on a form that writes settings", () => {
605
626
  const driver = driverWithPreview();
606
627
  const section = formSectionOf(driver);
607
628
 
@@ -624,7 +645,7 @@ describe("form preview", () => {
624
645
  });
625
646
 
626
647
  describe("validatePortActivation", () => {
627
- test("accepts a variable a variables form or a catalog section declares", () => {
648
+ it("accepts a variable a variables form or a catalog section declares", () => {
628
649
  expect(() =>
629
650
  validatePortActivation(
630
651
  [
@@ -646,7 +667,7 @@ describe("validatePortActivation", () => {
646
667
  ).not.toThrow();
647
668
  });
648
669
 
649
- test("rejects a variable nothing in the panel declares", () => {
670
+ it("rejects a variable nothing in the panel declares", () => {
650
671
  expect(() =>
651
672
  validatePortActivation(
652
673
  [
@@ -783,11 +804,11 @@ const clearingFormOf = (driver: BridgeDriver) => {
783
804
  };
784
805
 
785
806
  describe("detail sections", () => {
786
- test("accepts a detail section on a detail module", () => {
807
+ it("accepts a detail section on a detail module", () => {
787
808
  expect(() => validateDriver(withNoop(driverWithDetail()))).not.toThrow();
788
809
  });
789
810
 
790
- test("rejects a section pointing at a module that is not a detail module", () => {
811
+ it("rejects a section pointing at a module that is not a detail module", () => {
791
812
  const driver = withNoop(driverWithDetail());
792
813
 
793
814
  driver.modules = {
@@ -801,7 +822,7 @@ describe("detail sections", () => {
801
822
  expect(() => validateDriver(driver)).toThrow('references "modpackStatus", which is not a detail module');
802
823
  });
803
824
 
804
- test("rejects an action the module does not implement", () => {
825
+ it("rejects an action the module does not implement", () => {
805
826
  const driver = withNoop(driverWithDetail());
806
827
 
807
828
  detailSectionOf(driver).actions = [
@@ -816,7 +837,7 @@ describe("detail sections", () => {
816
837
  );
817
838
  });
818
839
 
819
- test("rejects a download action, since a detail has no rows to serve", () => {
840
+ it("rejects a download action, since a detail has no rows to serve", () => {
820
841
  const driver = withNoop(driverWithDetail());
821
842
 
822
843
  detailSectionOf(driver).actions = [
@@ -830,7 +851,7 @@ describe("detail sections", () => {
830
851
  expect(() => validateDriver(driver)).toThrow('declares action "update" as a download');
831
852
  });
832
853
 
833
- test("rejects a related tab the panel does not declare", () => {
854
+ it("rejects a related tab the panel does not declare", () => {
834
855
  const driver = withNoop(driverWithDetail());
835
856
 
836
857
  detailSectionOf(driver).related = {
@@ -841,7 +862,7 @@ describe("detail sections", () => {
841
862
  expect(() => validateDriver(driver)).toThrow('relates to tab "worlds", which the panel does not declare');
842
863
  });
843
864
 
844
- test("counts a detail variable as declared for port activation", () => {
865
+ it("counts a detail variable as declared for port activation", () => {
845
866
  expect(() =>
846
867
  validatePortActivation(
847
868
  [
@@ -859,11 +880,11 @@ describe("detail sections", () => {
859
880
  });
860
881
 
861
882
  describe("form clears", () => {
862
- test("accepts a clear of a variable a detail section declares", () => {
883
+ it("accepts a clear of a variable a detail section declares", () => {
863
884
  expect(() => validateDriver(withNoop(driverWithDetail()))).not.toThrow();
864
885
  });
865
886
 
866
- test("rejects a clear of a variable nothing declares", () => {
887
+ it("rejects a clear of a variable nothing declares", () => {
867
888
  const driver = withNoop(driverWithDetail());
868
889
 
869
890
  clearingFormOf(driver).clears = [
@@ -878,7 +899,7 @@ describe("form clears", () => {
878
899
  );
879
900
  });
880
901
 
881
- test("rejects a clear of one of the form's own fields", () => {
902
+ it("rejects a clear of one of the form's own fields", () => {
882
903
  const driver = withNoop(driverWithDetail());
883
904
 
884
905
  clearingFormOf(driver).clears = [
@@ -891,7 +912,7 @@ describe("form clears", () => {
891
912
  expect(() => validateDriver(driver)).toThrow('clears "MC_VERSION", which is one of its own fields');
892
913
  });
893
914
 
894
- test("rejects clears on a form that writes settings", () => {
915
+ it("rejects clears on a form that writes settings", () => {
895
916
  const driver = withNoop(driverWithDetail());
896
917
  const form = clearingFormOf(driver);
897
918
 
@@ -969,16 +990,16 @@ describe("table uploads", () => {
969
990
  mode,
970
991
  });
971
992
 
972
- test("accepts an upload that declares no mode", () => {
993
+ it("accepts an upload that declares no mode", () => {
973
994
  expect(() => validateDriver(driverWithUpload(upload()))).not.toThrow();
974
995
  });
975
996
 
976
- test("accepts both declared upload modes", () => {
997
+ it("accepts both declared upload modes", () => {
977
998
  expect(() => validateDriver(driverWithUpload(upload(BridgeUploadMode.Archive)))).not.toThrow();
978
999
  expect(() => validateDriver(driverWithUpload(upload(BridgeUploadMode.File)))).not.toThrow();
979
1000
  });
980
1001
 
981
- test("rejects an upload mode the platform does not know", () => {
1002
+ it("rejects an upload mode the platform does not know", () => {
982
1003
  const section = upload("stream" as BridgeUploadMode);
983
1004
 
984
1005
  expect(() => validateDriver(driverWithUpload(section))).toThrow('declares an unknown upload mode "stream"');
@@ -1015,7 +1036,7 @@ describe("the pending module", () => {
1015
1036
  ...overrides,
1016
1037
  });
1017
1038
 
1018
- test("accepts a driver that declares no pending module", () => {
1039
+ it("accepts a driver that declares no pending module", () => {
1019
1040
  expect(() =>
1020
1041
  validateDriver({
1021
1042
  install: {
@@ -1034,11 +1055,11 @@ describe("the pending module", () => {
1034
1055
  ).not.toThrow();
1035
1056
  });
1036
1057
 
1037
- test("accepts a pending module declaring a staging path and one extension", () => {
1058
+ it("accepts a pending module declaring a staging path and one extension", () => {
1038
1059
  expect(() => validateDriver(driverWithPending(pendingWith({})))).not.toThrow();
1039
1060
  });
1040
1061
 
1041
- test("rejects a pending module carrying another kind", () => {
1062
+ it("rejects a pending module carrying another kind", () => {
1042
1063
  const pending = pendingWith({
1043
1064
  kind: BridgeKind.Collection as BridgeKind.Pending,
1044
1065
  });
@@ -1048,7 +1069,7 @@ describe("the pending module", () => {
1048
1069
  );
1049
1070
  });
1050
1071
 
1051
- test("rejects a pending module with no staging path", () => {
1072
+ it("rejects a pending module with no staging path", () => {
1052
1073
  expect(() =>
1053
1074
  validateDriver(
1054
1075
  driverWithPending(
@@ -1060,7 +1081,7 @@ describe("the pending module", () => {
1060
1081
  ).toThrow("the pending module declares no staging path");
1061
1082
  });
1062
1083
 
1063
- test("rejects a staging path longer than the platform takes", () => {
1084
+ it("rejects a staging path longer than the platform takes", () => {
1064
1085
  expect(() =>
1065
1086
  validateDriver(
1066
1087
  driverWithPending(
@@ -1072,7 +1093,7 @@ describe("the pending module", () => {
1072
1093
  ).toThrow("the pending module staging path is 129 characters — the platform takes at most 128");
1073
1094
  });
1074
1095
 
1075
- test("rejects a pending module declaring no extensions", () => {
1096
+ it("rejects a pending module declaring no extensions", () => {
1076
1097
  expect(() =>
1077
1098
  validateDriver(
1078
1099
  driverWithPending(
@@ -1084,7 +1105,7 @@ describe("the pending module", () => {
1084
1105
  ).toThrow("the pending module declares no extensions");
1085
1106
  });
1086
1107
 
1087
- test("rejects more extensions than the platform takes", () => {
1108
+ it("rejects more extensions than the platform takes", () => {
1088
1109
  expect(() =>
1089
1110
  validateDriver(
1090
1111
  driverWithPending(
@@ -1098,7 +1119,7 @@ describe("the pending module", () => {
1098
1119
  ).toThrow("the pending module declares 9 extensions — the platform takes at most 8");
1099
1120
  });
1100
1121
 
1101
- test("rejects an extension longer than the platform takes", () => {
1122
+ it("rejects an extension longer than the platform takes", () => {
1102
1123
  expect(() =>
1103
1124
  validateDriver(
1104
1125
  driverWithPending(
@@ -1112,7 +1133,7 @@ describe("the pending module", () => {
1112
1133
  ).toThrow('the pending module extension "xxxxxxxxxxxxxxxxx" is 17 characters — the platform takes at most 16');
1113
1134
  });
1114
1135
 
1115
- test("reserves the pending module id for the singleton", () => {
1136
+ it("reserves the pending module id for the singleton", () => {
1116
1137
  expect(() =>
1117
1138
  validateDriver({
1118
1139
  install: {
@@ -1224,7 +1245,7 @@ const driverWithFields = (fields: BridgeField[]): BridgeDriver => ({
1224
1245
  });
1225
1246
 
1226
1247
  describe("the setup singleton", () => {
1227
- test("takes a driver step with both locales", () => {
1248
+ it("takes a driver step with both locales", () => {
1228
1249
  expect(() =>
1229
1250
  validateDriver(
1230
1251
  driverWithSetup(
@@ -1236,11 +1257,11 @@ describe("the setup singleton", () => {
1236
1257
  ).not.toThrow();
1237
1258
  });
1238
1259
 
1239
- test("rejects a setup that declares no steps", () => {
1260
+ it("rejects a setup that declares no steps", () => {
1240
1261
  expect(() => validateDriver(driverWithSetup(setupWith([])))).toThrow("the setup module declares no steps");
1241
1262
  });
1242
1263
 
1243
- test("rejects more steps than the platform takes", () => {
1264
+ it("rejects more steps than the platform takes", () => {
1244
1265
  expect(() =>
1245
1266
  validateDriver(
1246
1267
  driverWithSetup(
@@ -1254,7 +1275,7 @@ describe("the setup singleton", () => {
1254
1275
  ).toThrow("the setup module declares 9 steps — the platform takes at most 8");
1255
1276
  });
1256
1277
 
1257
- test("rejects a step id that is not kebab-case", () => {
1278
+ it("rejects a step id that is not kebab-case", () => {
1258
1279
  expect(() =>
1259
1280
  validateDriver(
1260
1281
  driverWithSetup(
@@ -1266,7 +1287,7 @@ describe("the setup singleton", () => {
1266
1287
  ).toThrow('the setup module step id "signIn" must be kebab-case');
1267
1288
  });
1268
1289
 
1269
- test("rejects the same step id twice", () => {
1290
+ it("rejects the same step id twice", () => {
1270
1291
  expect(() =>
1271
1292
  validateDriver(
1272
1293
  driverWithSetup(
@@ -1279,7 +1300,7 @@ describe("the setup singleton", () => {
1279
1300
  ).toThrow('the setup module declares step "sign-in" more than once');
1280
1301
  });
1281
1302
 
1282
- test("rejects a title that is missing a locale", () => {
1303
+ it("rejects a title that is missing a locale", () => {
1283
1304
  expect(() =>
1284
1305
  validateDriver(
1285
1306
  driverWithSetup(
@@ -1298,7 +1319,7 @@ describe("the setup singleton", () => {
1298
1319
  ).toThrow('the setup module step "sign-in" title needs both arabic and english text');
1299
1320
  });
1300
1321
 
1301
- test("takes a form step that names an existing form section and its own fields", () => {
1322
+ it("takes a form step that names an existing form section and its own fields", () => {
1302
1323
  expect(() =>
1303
1324
  validateDriver(
1304
1325
  driverWithSetup(
@@ -1319,7 +1340,7 @@ describe("the setup singleton", () => {
1319
1340
  ).not.toThrow();
1320
1341
  });
1321
1342
 
1322
- test("rejects a form step that names a section the panel does not declare", () => {
1343
+ it("rejects a form step that names a section the panel does not declare", () => {
1323
1344
  expect(() =>
1324
1345
  validateDriver(
1325
1346
  driverWithSetup(
@@ -1339,7 +1360,7 @@ describe("the setup singleton", () => {
1339
1360
  );
1340
1361
  });
1341
1362
 
1342
- test("rejects a form step that names a field the section does not declare", () => {
1363
+ it("rejects a form step that names a field the section does not declare", () => {
1343
1364
  expect(() =>
1344
1365
  validateDriver(
1345
1366
  driverWithSetup(
@@ -1360,7 +1381,7 @@ describe("the setup singleton", () => {
1360
1381
  ).toThrow('the setup module step "name" names field "PASSWORD", which section "server" does not declare');
1361
1382
  });
1362
1383
 
1363
- test("takes an open step that names an existing panel tab", () => {
1384
+ it("takes an open step that names an existing panel tab", () => {
1364
1385
  expect(() =>
1365
1386
  validateDriver(
1366
1387
  driverWithSetup(
@@ -1380,7 +1401,7 @@ describe("the setup singleton", () => {
1380
1401
  ).not.toThrow();
1381
1402
  });
1382
1403
 
1383
- test("rejects an open step that names a panel tab the panel does not declare", () => {
1404
+ it("rejects an open step that names a panel tab the panel does not declare", () => {
1384
1405
  expect(() =>
1385
1406
  validateDriver(
1386
1407
  driverWithSetup(
@@ -1400,7 +1421,7 @@ describe("the setup singleton", () => {
1400
1421
  ).toThrow('the setup module step "tune" opens panel tab "world", which the panel does not declare');
1401
1422
  });
1402
1423
 
1403
- test("takes an open step that leaves the panel altogether", () => {
1424
+ it("takes an open step that leaves the panel altogether", () => {
1404
1425
  expect(() =>
1405
1426
  validateDriver(
1406
1427
  driverWithSetup(
@@ -1419,7 +1440,7 @@ describe("the setup singleton", () => {
1419
1440
  ).not.toThrow();
1420
1441
  });
1421
1442
 
1422
- test("takes a form step over a secret field", () => {
1443
+ it("takes a form step over a secret field", () => {
1423
1444
  expect(() =>
1424
1445
  validateDriver(
1425
1446
  driverWithSetup(
@@ -1440,7 +1461,7 @@ describe("the setup singleton", () => {
1440
1461
  ).not.toThrow();
1441
1462
  });
1442
1463
 
1443
- test("rejects a driver step while the setup exports no submit", () => {
1464
+ it("rejects a driver step while the setup exports no submit", () => {
1444
1465
  expect(() =>
1445
1466
  validateDriver(
1446
1467
  driverWithSetup(
@@ -1452,7 +1473,7 @@ describe("the setup singleton", () => {
1452
1473
  ).toThrow("the setup module declares a driver step but exports no submit");
1453
1474
  });
1454
1475
 
1455
- test("takes a setup with no submit while every step is answered elsewhere", () => {
1476
+ it("takes a setup with no submit while every step is answered elsewhere", () => {
1456
1477
  expect(() =>
1457
1478
  validateDriver(
1458
1479
  driverWithSetup(
@@ -1471,7 +1492,7 @@ describe("the setup singleton", () => {
1471
1492
  ).not.toThrow();
1472
1493
  });
1473
1494
 
1474
- test("reserves the setup module id for the singleton", () => {
1495
+ it("reserves the setup module id for the singleton", () => {
1475
1496
  expect(() =>
1476
1497
  validateDriver({
1477
1498
  install: {
@@ -1498,7 +1519,7 @@ describe("the setup singleton", () => {
1498
1519
  });
1499
1520
 
1500
1521
  describe("field patterns", () => {
1501
- test("takes a pattern on a text field and on a secret one", () => {
1522
+ it("takes a pattern on a text field and on a secret one", () => {
1502
1523
  expect(() =>
1503
1524
  validateDriver(
1504
1525
  driverWithFields([
@@ -1506,8 +1527,8 @@ describe("field patterns", () => {
1506
1527
  key: "LICENSE_KEY",
1507
1528
  control: BridgeControl.Secret,
1508
1529
  label: text("Licence key"),
1509
- pattern: "^cfxk_\\w{1,60}_\\w{1,20}$",
1510
- patternHint: text("A licence key starts with cfxk_"),
1530
+ pattern: "^key_\\w{1,60}_\\w{1,20}$",
1531
+ patternHint: text("A licence key starts with key_"),
1511
1532
  },
1512
1533
  {
1513
1534
  key: "SERVER_NAME",
@@ -1520,7 +1541,7 @@ describe("field patterns", () => {
1520
1541
  ).not.toThrow();
1521
1542
  });
1522
1543
 
1523
- test("rejects a pattern that is not a regular expression", () => {
1544
+ it("rejects a pattern that is not a regular expression", () => {
1524
1545
  expect(() =>
1525
1546
  validateDriver(
1526
1547
  driverWithFields([
@@ -1528,14 +1549,14 @@ describe("field patterns", () => {
1528
1549
  key: "LICENSE_KEY",
1529
1550
  control: BridgeControl.Text,
1530
1551
  label: text("Licence key"),
1531
- pattern: "^cfxk_(",
1552
+ pattern: "^key_(",
1532
1553
  },
1533
1554
  ]),
1534
1555
  ),
1535
- ).toThrow('declares pattern "^cfxk_(", which is not a valid regular expression');
1556
+ ).toThrow('declares pattern "^key_(", which is not a valid regular expression');
1536
1557
  });
1537
1558
 
1538
- test("takes the FiveM licence pattern, whose repeats are all bounded", () => {
1559
+ it("takes an alternation whose repeats are all bounded", () => {
1539
1560
  expect(() =>
1540
1561
  validateDriver(
1541
1562
  driverWithFields([
@@ -1543,14 +1564,14 @@ describe("field patterns", () => {
1543
1564
  key: "LICENSE_KEY",
1544
1565
  control: BridgeControl.Secret,
1545
1566
  label: text("Licence key"),
1546
- pattern: "^(?:cfxk_\\w{1,60}_\\w{1,20}|\\w{32})$",
1567
+ pattern: "^(?:key_\\w{1,60}_\\w{1,20}|\\w{32})$",
1547
1568
  },
1548
1569
  ]),
1549
1570
  ),
1550
1571
  ).not.toThrow();
1551
1572
  });
1552
1573
 
1553
- test("rejects a pattern that repeats a group which already repeats", () => {
1574
+ it("rejects a pattern that repeats a group which already repeats", () => {
1554
1575
  expect(() =>
1555
1576
  validateDriver(
1556
1577
  driverWithFields([
@@ -1565,7 +1586,7 @@ describe("field patterns", () => {
1565
1586
  ).toThrow('declares pattern "^(a+)+$", which repeats a group that already repeats');
1566
1587
  });
1567
1588
 
1568
- test("rejects a starred group whose body repeats without a bound", () => {
1589
+ it("rejects a starred group whose body repeats without a bound", () => {
1569
1590
  expect(() =>
1570
1591
  validateDriver(
1571
1592
  driverWithFields([
@@ -1580,7 +1601,7 @@ describe("field patterns", () => {
1580
1601
  ).toThrow("repeats a group that already repeats");
1581
1602
  });
1582
1603
 
1583
- test("rejects a pattern longer than the platform takes", () => {
1604
+ it("rejects a pattern longer than the platform takes", () => {
1584
1605
  expect(() =>
1585
1606
  validateDriver(
1586
1607
  driverWithFields([
@@ -1595,7 +1616,7 @@ describe("field patterns", () => {
1595
1616
  ).toThrow("pattern is 258 characters — the platform takes at most 256");
1596
1617
  });
1597
1618
 
1598
- test("rejects a pattern hint with no pattern to explain", () => {
1619
+ it("rejects a pattern hint with no pattern to explain", () => {
1599
1620
  expect(() =>
1600
1621
  validateDriver(
1601
1622
  driverWithFields([
@@ -1603,14 +1624,14 @@ describe("field patterns", () => {
1603
1624
  key: "LICENSE_KEY",
1604
1625
  control: BridgeControl.Text,
1605
1626
  label: text("Licence key"),
1606
- patternHint: text("A licence key starts with cfxk_"),
1627
+ patternHint: text("A licence key starts with key_"),
1607
1628
  },
1608
1629
  ]),
1609
1630
  ),
1610
1631
  ).toThrow("declares a pattern hint with no pattern to explain");
1611
1632
  });
1612
1633
 
1613
- test("rejects a pattern on a control that never matches one", () => {
1634
+ it("rejects a pattern on a control that never matches one", () => {
1614
1635
  expect(() =>
1615
1636
  validateDriver(
1616
1637
  driverWithFields([
@@ -1625,7 +1646,7 @@ describe("field patterns", () => {
1625
1646
  ).toThrow('declares a pattern on a "boolean" control — only text and secret controls match one');
1626
1647
  });
1627
1648
 
1628
- test("rejects a secret control that offers options", () => {
1649
+ it("rejects a secret control that offers options", () => {
1629
1650
  expect(() =>
1630
1651
  validateDriver(
1631
1652
  driverWithFields([
@@ -1710,7 +1731,7 @@ describe("section placement", () => {
1710
1731
  return driver;
1711
1732
  };
1712
1733
 
1713
- test("accepts a table placed on the players page", () => {
1734
+ it("accepts a table placed on the players page", () => {
1714
1735
  expect(() =>
1715
1736
  validateDriver(
1716
1737
  driverWithRoster({
@@ -1720,19 +1741,19 @@ describe("section placement", () => {
1720
1741
  ).not.toThrow();
1721
1742
  });
1722
1743
 
1723
- test("rejects a form placed on the players page", () => {
1744
+ it("rejects a form placed on the players page", () => {
1724
1745
  expect(() => validateDriver(placedForm(BridgePlace.Players))).toThrow(
1725
1746
  'tab "version" section "version" places a form section on players, which that page cannot render',
1726
1747
  );
1727
1748
  });
1728
1749
 
1729
- test("rejects a form placed on the overview page", () => {
1750
+ it("rejects a form placed on the overview page", () => {
1730
1751
  expect(() => validateDriver(placedForm(BridgePlace.Overview))).toThrow(
1731
1752
  "places a form section on overview, which that page cannot render",
1732
1753
  );
1733
1754
  });
1734
1755
 
1735
- test("rejects a table placed on the overview page", () => {
1756
+ it("rejects a table placed on the overview page", () => {
1736
1757
  expect(() =>
1737
1758
  validateDriver(
1738
1759
  driverWithRoster({
@@ -1742,7 +1763,7 @@ describe("section placement", () => {
1742
1763
  ).toThrow('tab "roster" section "online" places a table section on overview, which that page cannot render');
1743
1764
  });
1744
1765
 
1745
- test("accepts an offline row action on a table", () => {
1766
+ it("accepts an offline row action on a table", () => {
1746
1767
  expect(() =>
1747
1768
  validateDriver(
1748
1769
  driverWithRoster({
@@ -1759,7 +1780,7 @@ describe("section placement", () => {
1759
1780
  ).not.toThrow();
1760
1781
  });
1761
1782
 
1762
- test("rejects an offline action on an actions section", () => {
1783
+ it("rejects an offline action on an actions section", () => {
1763
1784
  expect(() =>
1764
1785
  validateDriver(
1765
1786
  driverWithActions([
@@ -1775,7 +1796,7 @@ describe("section placement", () => {
1775
1796
  );
1776
1797
  });
1777
1798
 
1778
- test("rejects a form help that is missing a locale", () => {
1799
+ it("rejects a form help that is missing a locale", () => {
1779
1800
  const driver = driverWith(anyVisibleWhen);
1780
1801
 
1781
1802
  formSectionOf(driver).help = {
@@ -1806,7 +1827,7 @@ describe("the lifecycle module", () => {
1806
1827
  },
1807
1828
  });
1808
1829
 
1809
- test("accepts an environment resolver", () => {
1830
+ it("accepts an environment resolver", () => {
1810
1831
  expect(() =>
1811
1832
  validateDriver(
1812
1833
  lifecycleDriver({
@@ -1818,11 +1839,11 @@ describe("the lifecycle module", () => {
1818
1839
  ).not.toThrow();
1819
1840
  });
1820
1841
 
1821
- test("accepts a lifecycle that declares no environment", () => {
1842
+ it("accepts a lifecycle that declares no environment", () => {
1822
1843
  expect(() => validateDriver(lifecycleDriver({}))).not.toThrow();
1823
1844
  });
1824
1845
 
1825
- test("accepts each stop signal the bridge sends", () => {
1846
+ it("accepts each stop signal the bridge sends", () => {
1826
1847
  for (const stopSignal of Object.values(BridgeStopSignal)) {
1827
1848
  expect(() =>
1828
1849
  validateDriver(
@@ -1834,7 +1855,7 @@ describe("the lifecycle module", () => {
1834
1855
  }
1835
1856
  });
1836
1857
 
1837
- test("refuses a stop signal the bridge does not send", () => {
1858
+ it("refuses a stop signal the bridge does not send", () => {
1838
1859
  expect(() =>
1839
1860
  validateDriver(
1840
1861
  lifecycleDriver({
@@ -1844,7 +1865,7 @@ describe("the lifecycle module", () => {
1844
1865
  ).toThrow('the lifecycle module declares stop signal "SIGHUP" — the bridge sends only SIGTERM or SIGINT');
1845
1866
  });
1846
1867
 
1847
- test("accepts a ready timeout from one second to an hour", () => {
1868
+ it("accepts a ready timeout from one second to an hour", () => {
1848
1869
  for (const readyTimeoutSeconds of [
1849
1870
  1,
1850
1871
  900,
@@ -1860,7 +1881,7 @@ describe("the lifecycle module", () => {
1860
1881
  }
1861
1882
  });
1862
1883
 
1863
- test("refuses a ready timeout outside one second to an hour", () => {
1884
+ it("refuses a ready timeout outside one second to an hour", () => {
1864
1885
  for (const readyTimeoutSeconds of [
1865
1886
  0,
1866
1887
  3601,
@@ -1878,7 +1899,7 @@ describe("the lifecycle module", () => {
1878
1899
  }
1879
1900
  });
1880
1901
 
1881
- test("accepts each lifecycle subject the bridge names", () => {
1902
+ it("accepts each lifecycle subject the bridge names", () => {
1882
1903
  for (const subject of Object.values(BridgeLifecycleSubject)) {
1883
1904
  expect(() =>
1884
1905
  validateDriver(
@@ -1890,7 +1911,7 @@ describe("the lifecycle module", () => {
1890
1911
  }
1891
1912
  });
1892
1913
 
1893
- test("refuses a lifecycle subject the bridge does not name", () => {
1914
+ it("refuses a lifecycle subject the bridge does not name", () => {
1894
1915
  expect(() =>
1895
1916
  validateDriver(
1896
1917
  lifecycleDriver({
@@ -1900,7 +1921,7 @@ describe("the lifecycle module", () => {
1900
1921
  ).toThrow('the lifecycle module declares subject "server" — the bridge names only game or bot');
1901
1922
  });
1902
1923
 
1903
- test("refuses an environment that is not a function", () => {
1924
+ it("refuses an environment that is not a function", () => {
1904
1925
  expect(() =>
1905
1926
  validateDriver(
1906
1927
  lifecycleDriver({