@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.
- 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 +41 -11
- package/src/bot/botPanel.ts +13 -5
- 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 +123 -29
- package/src/cli/validate.ts +37 -1
- 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/context/bridgeContext.ts +6 -1
- package/src/core/bridgeAction.ts +2 -0
- package/src/core/bridgeActivity.ts +9 -0
- package/src/core/bridgeAvailability.ts +10 -0
- package/src/core/bridgePort.test.ts +6 -6
- package/src/core/bridgeUserError.test.ts +13 -3
- package/src/core/bridgeUserError.ts +6 -2
- package/src/core/bridgeValue.test.ts +5 -5
- package/src/core/describeDownloadFailure.test.ts +58 -0
- package/src/core/describeDownloadFailure.ts +69 -0
- package/src/core/index.ts +3 -0
- 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/modules/bridge.ts +8 -1
- package/src/modules/bridgeModule.ts +13 -1
- package/src/net/loopback.test.ts +10 -10
- package/src/panel/bridgeDetail.ts +2 -1
- 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/bridgeActivity.ts +54 -0
- package/src/protocol/bridgeEvents.ts +30 -0
- package/src/protocol/bridgeFrame.ts +10 -1
- package/src/protocol/index.ts +1 -0
- 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/bridgeActions.ts +19 -2
- package/src/runtime/bridgeActivity.test.ts +318 -0
- package/src/runtime/bridgeActivity.ts +268 -0
- 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 +11 -5
- package/src/runtime/bridgeContext.ts +8 -1
- package/src/runtime/bridgeDriver.test.ts +114 -93
- package/src/runtime/bridgeDriver.ts +10 -7
- 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/bridgeLog.ts +10 -0
- package/src/runtime/bridgePending.test.ts +6 -6
- package/src/runtime/bridgeRedaction.test.ts +16 -16
- package/src/runtime/bridgeRefusalError.ts +13 -0
- package/src/runtime/bridgeRegistry.test.ts +1077 -34
- package/src/runtime/bridgeRegistry.ts +464 -65
- package/src/runtime/bridgeScopedContext.ts +55 -0
- package/src/runtime/bridgeServer.test.ts +424 -24
- package/src/runtime/bridgeServer.ts +125 -35
- package/src/runtime/bridgeSetup.test.ts +27 -27
- package/src/runtime/bridgeSetup.ts +1 -1
- package/src/runtime/bridgeSetupHandlers.test.ts +80 -17
- package/src/runtime/bridgeSetupHandlers.ts +45 -10
- package/src/runtime/bridgeSignal.test.ts +7 -7
- package/src/runtime/bridgeSupervisor.test.ts +42 -42
- package/src/runtime/serve.ts +45 -3
- package/src/steam/avatars.test.ts +13 -13
- package/src/steam/steamApp.test.ts +8 -8
- package/src/steam/steamcmd.test.ts +44 -13
- package/src/steam/steamcmd.ts +27 -4
- package/src/steam/steamcmdNarrator.test.ts +4 -4
- package/src/steam/workshop.test.ts +5 -5
- package/src/utils/changedSettingKeys.test.ts +65 -0
- package/src/utils/changedSettingKeys.ts +6 -0
- package/src/utils/describeExecFailure.test.ts +34 -0
- package/src/utils/describeExecFailure.ts +9 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/sameSettingValue.test.ts +35 -0
- package/src/utils/sameSettingValue.ts +40 -0
- 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 +95 -0
- package/src/wire/activity.ts +41 -0
- package/src/wire/index.ts +1 -0
- package/src/wire/panel.test.ts +91 -25
- package/src/wire/panel.ts +11 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect,
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
|
2
2
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import {
|
|
6
|
+
type BridgeActivity,
|
|
6
7
|
BridgeDesired,
|
|
7
8
|
BridgeFailureCode,
|
|
8
9
|
BridgeFailureError,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
BridgeUserError,
|
|
13
14
|
} from "../core";
|
|
14
15
|
import {
|
|
16
|
+
BridgeEventName,
|
|
15
17
|
BridgeMethod,
|
|
16
18
|
type BridgePendingResult,
|
|
17
19
|
type BridgeResponse,
|
|
@@ -19,6 +21,7 @@ import {
|
|
|
19
21
|
type BridgeSetupRuntime,
|
|
20
22
|
type BridgeValues,
|
|
21
23
|
} from "../protocol";
|
|
24
|
+
import { BridgeRefusalError } from "./bridgeRefusalError";
|
|
22
25
|
import { createServer, type ServerOptions } from "./bridgeServer";
|
|
23
26
|
import { failedSetup, unsupportedSetup } from "./bridgeSetup";
|
|
24
27
|
|
|
@@ -61,11 +64,41 @@ const baseOptions = (socket: string): ServerOptions => ({
|
|
|
61
64
|
onPendingAdd: unreachable("pendingAdd"),
|
|
62
65
|
onSetupStatus: unreachable("setupStatus"),
|
|
63
66
|
onSetupSubmit: unreachable("setupSubmit"),
|
|
67
|
+
onUndelivered: unreachable("undelivered"),
|
|
64
68
|
onLog: () => {
|
|
65
69
|
return;
|
|
66
70
|
},
|
|
67
71
|
});
|
|
68
72
|
|
|
73
|
+
const abandon = async (socket: string, frame: Record<string, unknown>) => {
|
|
74
|
+
await new Promise<void>((resolve, reject) => {
|
|
75
|
+
void Bun.connect({
|
|
76
|
+
unix: socket,
|
|
77
|
+
socket: {
|
|
78
|
+
open(connection) {
|
|
79
|
+
connection.write(`${JSON.stringify(frame)}\n`);
|
|
80
|
+
connection.end();
|
|
81
|
+
},
|
|
82
|
+
close() {
|
|
83
|
+
resolve();
|
|
84
|
+
},
|
|
85
|
+
data() {
|
|
86
|
+
return;
|
|
87
|
+
},
|
|
88
|
+
error(_connection, error) {
|
|
89
|
+
reject(error);
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
}).catch(reject);
|
|
93
|
+
});
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const until = async (check: () => boolean) => {
|
|
97
|
+
for (let attempt = 0; attempt < 100 && !check(); attempt++) {
|
|
98
|
+
await Bun.sleep(10);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
69
102
|
const call = async (socket: string, frame: Record<string, unknown>): Promise<BridgeResponse> => {
|
|
70
103
|
return await new Promise<BridgeResponse>((resolve, reject) => {
|
|
71
104
|
void Bun.connect<{
|
|
@@ -129,7 +162,7 @@ describe("pending dispatch", () => {
|
|
|
129
162
|
rejected: null,
|
|
130
163
|
};
|
|
131
164
|
|
|
132
|
-
|
|
165
|
+
it("answers pendingList with what the driver lists", async () => {
|
|
133
166
|
const server = createServer({
|
|
134
167
|
...baseOptions(socket),
|
|
135
168
|
onPendingList: async () => listed,
|
|
@@ -150,7 +183,7 @@ describe("pending dispatch", () => {
|
|
|
150
183
|
});
|
|
151
184
|
});
|
|
152
185
|
|
|
153
|
-
|
|
186
|
+
it("answers pendingList with the unsupported sentinel when the driver declares no pending module", async () => {
|
|
154
187
|
const server = createServer({
|
|
155
188
|
...baseOptions(socket),
|
|
156
189
|
onPendingList: async () => ({
|
|
@@ -183,7 +216,7 @@ describe("pending dispatch", () => {
|
|
|
183
216
|
});
|
|
184
217
|
});
|
|
185
218
|
|
|
186
|
-
|
|
219
|
+
it("passes the uploaded path to pendingAdd and answers with the refreshed list", async () => {
|
|
187
220
|
const received: string[] = [];
|
|
188
221
|
|
|
189
222
|
const server = createServer({
|
|
@@ -214,7 +247,7 @@ describe("pending dispatch", () => {
|
|
|
214
247
|
});
|
|
215
248
|
});
|
|
216
249
|
|
|
217
|
-
|
|
250
|
+
it("refuses a pendingAdd carrying no path", async () => {
|
|
218
251
|
const server = createServer({
|
|
219
252
|
...baseOptions(socket),
|
|
220
253
|
onPendingAdd: unreachable("pendingAdd"),
|
|
@@ -235,7 +268,7 @@ describe("pending dispatch", () => {
|
|
|
235
268
|
});
|
|
236
269
|
});
|
|
237
270
|
|
|
238
|
-
|
|
271
|
+
it("answers pendingAdd with the rejection the driver reported beside the refreshed list", async () => {
|
|
239
272
|
const rejected: BridgePendingResult = {
|
|
240
273
|
...listed,
|
|
241
274
|
rejected: {
|
|
@@ -266,7 +299,7 @@ describe("pending dispatch", () => {
|
|
|
266
299
|
});
|
|
267
300
|
});
|
|
268
301
|
|
|
269
|
-
|
|
302
|
+
it("names an unknown method so an older agent can degrade", async () => {
|
|
270
303
|
const server = createServer(baseOptions(socket));
|
|
271
304
|
|
|
272
305
|
const response = await call(socket, {
|
|
@@ -334,7 +367,7 @@ describe("setup dispatch", () => {
|
|
|
334
367
|
runtime,
|
|
335
368
|
};
|
|
336
369
|
|
|
337
|
-
|
|
370
|
+
it("answers setupStatus with what the driver reported", async () => {
|
|
338
371
|
const server = createServer({
|
|
339
372
|
...baseOptions(socket),
|
|
340
373
|
onSetupStatus: () => reported,
|
|
@@ -355,7 +388,7 @@ describe("setup dispatch", () => {
|
|
|
355
388
|
});
|
|
356
389
|
});
|
|
357
390
|
|
|
358
|
-
|
|
391
|
+
it("answers setupStatus with the unsupported sentinel when the driver declares no setup", async () => {
|
|
359
392
|
const server = createServer({
|
|
360
393
|
...baseOptions(socket),
|
|
361
394
|
onSetupStatus: () => unsupportedSetup(),
|
|
@@ -379,7 +412,7 @@ describe("setup dispatch", () => {
|
|
|
379
412
|
});
|
|
380
413
|
});
|
|
381
414
|
|
|
382
|
-
|
|
415
|
+
it("passes the step, action and args of a setupSubmit to the driver", async () => {
|
|
383
416
|
const received: {
|
|
384
417
|
step: string;
|
|
385
418
|
action: string;
|
|
@@ -395,7 +428,10 @@ describe("setup dispatch", () => {
|
|
|
395
428
|
args,
|
|
396
429
|
});
|
|
397
430
|
|
|
398
|
-
return
|
|
431
|
+
return {
|
|
432
|
+
result: reported,
|
|
433
|
+
activity: [],
|
|
434
|
+
};
|
|
399
435
|
},
|
|
400
436
|
});
|
|
401
437
|
|
|
@@ -425,10 +461,11 @@ describe("setup dispatch", () => {
|
|
|
425
461
|
id: 3,
|
|
426
462
|
ok: true,
|
|
427
463
|
result: reported,
|
|
464
|
+
activity: [],
|
|
428
465
|
});
|
|
429
466
|
});
|
|
430
467
|
|
|
431
|
-
|
|
468
|
+
it("refuses a setupSubmit carrying no step id", async () => {
|
|
432
469
|
const server = createServer({
|
|
433
470
|
...baseOptions(socket),
|
|
434
471
|
onSetupSubmit: unreachable("setupSubmit"),
|
|
@@ -450,14 +487,16 @@ describe("setup dispatch", () => {
|
|
|
450
487
|
});
|
|
451
488
|
});
|
|
452
489
|
|
|
453
|
-
|
|
490
|
+
it("answers a rejected setupSubmit with a failed prompt instead of a failed call", async () => {
|
|
454
491
|
const server = createServer({
|
|
455
492
|
...baseOptions(socket),
|
|
456
|
-
onSetupSubmit: async () =>
|
|
457
|
-
failedSetup(runtime, {
|
|
493
|
+
onSetupSubmit: async () => ({
|
|
494
|
+
result: failedSetup(runtime, {
|
|
458
495
|
ar: "الكود ما عاد ينفع",
|
|
459
496
|
en: "this code cannot be renewed any more",
|
|
460
497
|
}),
|
|
498
|
+
activity: [],
|
|
499
|
+
}),
|
|
461
500
|
});
|
|
462
501
|
|
|
463
502
|
const response = await call(socket, {
|
|
@@ -495,13 +534,17 @@ describe("setup dispatch", () => {
|
|
|
495
534
|
},
|
|
496
535
|
},
|
|
497
536
|
},
|
|
537
|
+
activity: [],
|
|
498
538
|
});
|
|
499
539
|
});
|
|
500
540
|
|
|
501
|
-
|
|
541
|
+
it("answers setupSubmit with the unsupported sentinel when the driver implements no submit", async () => {
|
|
502
542
|
const server = createServer({
|
|
503
543
|
...baseOptions(socket),
|
|
504
|
-
onSetupSubmit: async () =>
|
|
544
|
+
onSetupSubmit: async () => ({
|
|
545
|
+
result: unsupportedSetup(),
|
|
546
|
+
activity: [],
|
|
547
|
+
}),
|
|
505
548
|
});
|
|
506
549
|
|
|
507
550
|
const response = await call(socket, {
|
|
@@ -521,6 +564,7 @@ describe("setup dispatch", () => {
|
|
|
521
564
|
supported: false,
|
|
522
565
|
runtime: null,
|
|
523
566
|
},
|
|
567
|
+
activity: [],
|
|
524
568
|
});
|
|
525
569
|
});
|
|
526
570
|
});
|
|
@@ -561,7 +605,7 @@ describe("error serialisation", () => {
|
|
|
561
605
|
return response;
|
|
562
606
|
};
|
|
563
607
|
|
|
564
|
-
|
|
608
|
+
it("carries the localized text of a user error beside the message", async () => {
|
|
565
609
|
expect(
|
|
566
610
|
await thrown(
|
|
567
611
|
new BridgeUserError({
|
|
@@ -580,7 +624,7 @@ describe("error serialisation", () => {
|
|
|
580
624
|
});
|
|
581
625
|
});
|
|
582
626
|
|
|
583
|
-
|
|
627
|
+
it("carries the failure code of a failure error and no text", async () => {
|
|
584
628
|
expect(await thrown(new BridgeFailureError(BridgeFailureCode.CatalogRestricted, "the author blocked it"))).toEqual({
|
|
585
629
|
id: 1,
|
|
586
630
|
ok: false,
|
|
@@ -589,7 +633,36 @@ describe("error serialisation", () => {
|
|
|
589
633
|
});
|
|
590
634
|
});
|
|
591
635
|
|
|
592
|
-
|
|
636
|
+
it("marks a runtime refusal unchanged and carries its text", async () => {
|
|
637
|
+
expect(
|
|
638
|
+
await thrown(
|
|
639
|
+
new BridgeRefusalError('module "worlds" cannot run "delete" right now', {
|
|
640
|
+
ar: "ما تقدر تحذف العالم الشغّال",
|
|
641
|
+
en: "You cannot delete the active world",
|
|
642
|
+
}),
|
|
643
|
+
),
|
|
644
|
+
).toEqual({
|
|
645
|
+
id: 1,
|
|
646
|
+
ok: false,
|
|
647
|
+
error: 'module "worlds" cannot run "delete" right now',
|
|
648
|
+
unchanged: true,
|
|
649
|
+
text: {
|
|
650
|
+
ar: "ما تقدر تحذف العالم الشغّال",
|
|
651
|
+
en: "You cannot delete the active world",
|
|
652
|
+
},
|
|
653
|
+
});
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
it("marks a runtime refusal without text unchanged and sends no text", async () => {
|
|
657
|
+
expect(await thrown(new BridgeRefusalError('no module named "worlds"'))).toEqual({
|
|
658
|
+
id: 1,
|
|
659
|
+
ok: false,
|
|
660
|
+
error: 'no module named "worlds"',
|
|
661
|
+
unchanged: true,
|
|
662
|
+
});
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
it("carries the message alone for an ordinary error", async () => {
|
|
593
666
|
expect(await thrown(new Error("the file could not be read"))).toEqual({
|
|
594
667
|
id: 1,
|
|
595
668
|
ok: false,
|
|
@@ -609,7 +682,7 @@ describe("backup ownership dispatch", () => {
|
|
|
609
682
|
recursive: true,
|
|
610
683
|
});
|
|
611
684
|
});
|
|
612
|
-
|
|
685
|
+
it("carries the lease token through renew and release frames", async () => {
|
|
613
686
|
const socket = join(dir, "bridge.sock");
|
|
614
687
|
const renewals: (string | undefined)[] = [];
|
|
615
688
|
const releases: (string | undefined)[] = [];
|
|
@@ -673,7 +746,7 @@ describe("error replies", () => {
|
|
|
673
746
|
});
|
|
674
747
|
});
|
|
675
748
|
|
|
676
|
-
|
|
749
|
+
it("hide a secret value from the error and the customer text", async () => {
|
|
677
750
|
const server = createServer({
|
|
678
751
|
...baseOptions(socket),
|
|
679
752
|
redact: (value) => value.split(SECRET).join("••••"),
|
|
@@ -757,7 +830,7 @@ describe("failure logging", () => {
|
|
|
757
830
|
return lines;
|
|
758
831
|
};
|
|
759
832
|
|
|
760
|
-
|
|
833
|
+
it("logs a refused action as a refusal with its message and no stack", async () => {
|
|
761
834
|
expect(
|
|
762
835
|
await logged(
|
|
763
836
|
new BridgeUserError({
|
|
@@ -776,11 +849,338 @@ describe("failure logging", () => {
|
|
|
776
849
|
]);
|
|
777
850
|
});
|
|
778
851
|
|
|
779
|
-
|
|
852
|
+
it("logs an ordinary error as a failure with its stack", async () => {
|
|
780
853
|
const [line] = await logged(new Error("the marker could not be written"));
|
|
781
854
|
|
|
782
855
|
expect(line?.message).toBe("bridge call failed");
|
|
783
856
|
expect(line?.fields.error).toBe("the marker could not be written");
|
|
784
857
|
expect(String(line?.fields.stack)).toContain("the marker could not be written");
|
|
785
858
|
});
|
|
859
|
+
|
|
860
|
+
it("logs a refusal with the cause the driver attached", async () => {
|
|
861
|
+
expect(
|
|
862
|
+
await logged(
|
|
863
|
+
new BridgeUserError(
|
|
864
|
+
{
|
|
865
|
+
ar: "المصدر رفض التنزيل",
|
|
866
|
+
en: "the source refused the download",
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
cause: new Error("cdn.modrinth.com answered 403"),
|
|
870
|
+
},
|
|
871
|
+
),
|
|
872
|
+
),
|
|
873
|
+
).toEqual([
|
|
874
|
+
{
|
|
875
|
+
message: "bridge call refused",
|
|
876
|
+
fields: {
|
|
877
|
+
method: BridgeMethod.Invoke,
|
|
878
|
+
error: "the source refused the download — cdn.modrinth.com answered 403",
|
|
879
|
+
},
|
|
880
|
+
},
|
|
881
|
+
]);
|
|
882
|
+
});
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
describe("activity on the answer frame", () => {
|
|
886
|
+
let dir = "";
|
|
887
|
+
let socket = "";
|
|
888
|
+
|
|
889
|
+
beforeEach(async () => {
|
|
890
|
+
dir = await mkdtemp(join(tmpdir(), "bridge-server-"));
|
|
891
|
+
socket = join(dir, "bridge.sock");
|
|
892
|
+
});
|
|
893
|
+
|
|
894
|
+
afterEach(async () => {
|
|
895
|
+
await rm(dir, {
|
|
896
|
+
force: true,
|
|
897
|
+
recursive: true,
|
|
898
|
+
});
|
|
899
|
+
});
|
|
900
|
+
|
|
901
|
+
const entry: BridgeActivity = {
|
|
902
|
+
name: BridgeEventName.AccessGranted,
|
|
903
|
+
text: {
|
|
904
|
+
ar: "أضفت Steve للقائمة البيضاء",
|
|
905
|
+
en: "Added Steve to the whitelist",
|
|
906
|
+
},
|
|
907
|
+
subject: "Steve",
|
|
908
|
+
};
|
|
909
|
+
|
|
910
|
+
it("carries the entries an invoke reported beside its result", async () => {
|
|
911
|
+
const server = createServer({
|
|
912
|
+
...baseOptions(socket),
|
|
913
|
+
onInvoke: async () => ({
|
|
914
|
+
result: null,
|
|
915
|
+
activity: [
|
|
916
|
+
entry,
|
|
917
|
+
],
|
|
918
|
+
}),
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
const response = await call(socket, {
|
|
922
|
+
id: 11,
|
|
923
|
+
token: TOKEN,
|
|
924
|
+
method: BridgeMethod.Invoke,
|
|
925
|
+
module: "whitelist",
|
|
926
|
+
action: "add",
|
|
927
|
+
args: {
|
|
928
|
+
input: "Steve",
|
|
929
|
+
},
|
|
930
|
+
});
|
|
931
|
+
|
|
932
|
+
server.stop(true);
|
|
933
|
+
|
|
934
|
+
expect(response).toEqual({
|
|
935
|
+
id: 11,
|
|
936
|
+
ok: true,
|
|
937
|
+
result: null,
|
|
938
|
+
activity: [
|
|
939
|
+
entry,
|
|
940
|
+
],
|
|
941
|
+
});
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
it("carries the entries a setup submit reported beside its result", async () => {
|
|
945
|
+
const server = createServer({
|
|
946
|
+
...baseOptions(socket),
|
|
947
|
+
onSetupSubmit: async () => ({
|
|
948
|
+
result: unsupportedSetup(),
|
|
949
|
+
activity: [
|
|
950
|
+
entry,
|
|
951
|
+
],
|
|
952
|
+
}),
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
const response = await call(socket, {
|
|
956
|
+
id: 12,
|
|
957
|
+
token: TOKEN,
|
|
958
|
+
method: BridgeMethod.SetupSubmit,
|
|
959
|
+
module: "sign-in",
|
|
960
|
+
action: "renew",
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
server.stop(true);
|
|
964
|
+
|
|
965
|
+
expect(response).toMatchObject({
|
|
966
|
+
ok: true,
|
|
967
|
+
activity: [
|
|
968
|
+
entry,
|
|
969
|
+
],
|
|
970
|
+
});
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
it("carries an empty list when nothing was reported, so the platform knows the runtime reports", async () => {
|
|
974
|
+
const server = createServer({
|
|
975
|
+
...baseOptions(socket),
|
|
976
|
+
onInvoke: async () => ({
|
|
977
|
+
result: "done",
|
|
978
|
+
activity: [],
|
|
979
|
+
}),
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
const response = await call(socket, {
|
|
983
|
+
id: 13,
|
|
984
|
+
token: TOKEN,
|
|
985
|
+
method: BridgeMethod.Invoke,
|
|
986
|
+
module: "whitelist",
|
|
987
|
+
action: "add",
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
server.stop(true);
|
|
991
|
+
|
|
992
|
+
expect(response).toEqual({
|
|
993
|
+
id: 13,
|
|
994
|
+
ok: true,
|
|
995
|
+
result: "done",
|
|
996
|
+
activity: [],
|
|
997
|
+
});
|
|
998
|
+
});
|
|
999
|
+
|
|
1000
|
+
it("leaves the field off the answers of methods that report no activity", async () => {
|
|
1001
|
+
const server = createServer(baseOptions(socket));
|
|
1002
|
+
|
|
1003
|
+
const response = await call(socket, {
|
|
1004
|
+
id: 14,
|
|
1005
|
+
token: TOKEN,
|
|
1006
|
+
method: BridgeMethod.Status,
|
|
1007
|
+
});
|
|
1008
|
+
|
|
1009
|
+
server.stop(true);
|
|
1010
|
+
|
|
1011
|
+
expect(response.ok).toBe(true);
|
|
1012
|
+
expect("activity" in response).toBe(false);
|
|
1013
|
+
});
|
|
1014
|
+
|
|
1015
|
+
const invokeFrame = {
|
|
1016
|
+
id: 21,
|
|
1017
|
+
token: TOKEN,
|
|
1018
|
+
method: BridgeMethod.Invoke,
|
|
1019
|
+
module: "whitelist",
|
|
1020
|
+
action: "add",
|
|
1021
|
+
};
|
|
1022
|
+
|
|
1023
|
+
it("sends the entries to the events ring once when the caller left before the answer", async () => {
|
|
1024
|
+
const ring: BridgeActivity[][] = [];
|
|
1025
|
+
|
|
1026
|
+
let finish: () => void = () => undefined;
|
|
1027
|
+
let started = false;
|
|
1028
|
+
let answered = false;
|
|
1029
|
+
|
|
1030
|
+
const server = createServer({
|
|
1031
|
+
...baseOptions(socket),
|
|
1032
|
+
onInvoke: async () => {
|
|
1033
|
+
started = true;
|
|
1034
|
+
|
|
1035
|
+
await new Promise<void>((resolve) => {
|
|
1036
|
+
finish = resolve;
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
answered = true;
|
|
1040
|
+
|
|
1041
|
+
return {
|
|
1042
|
+
result: null,
|
|
1043
|
+
activity: [
|
|
1044
|
+
entry,
|
|
1045
|
+
],
|
|
1046
|
+
};
|
|
1047
|
+
},
|
|
1048
|
+
onUndelivered: (activity) => {
|
|
1049
|
+
ring.push(activity);
|
|
1050
|
+
},
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
await abandon(socket, invokeFrame);
|
|
1054
|
+
await until(() => started);
|
|
1055
|
+
await Bun.sleep(20);
|
|
1056
|
+
|
|
1057
|
+
finish();
|
|
1058
|
+
|
|
1059
|
+
await until(() => answered && ring.length > 0);
|
|
1060
|
+
await Bun.sleep(20);
|
|
1061
|
+
|
|
1062
|
+
server.stop(true);
|
|
1063
|
+
|
|
1064
|
+
expect(ring).toEqual([
|
|
1065
|
+
[
|
|
1066
|
+
entry,
|
|
1067
|
+
],
|
|
1068
|
+
]);
|
|
1069
|
+
});
|
|
1070
|
+
|
|
1071
|
+
it("sends nothing to the ring when the answer reached the caller", async () => {
|
|
1072
|
+
const ring: BridgeActivity[][] = [];
|
|
1073
|
+
|
|
1074
|
+
const server = createServer({
|
|
1075
|
+
...baseOptions(socket),
|
|
1076
|
+
onInvoke: async () => ({
|
|
1077
|
+
result: null,
|
|
1078
|
+
activity: [
|
|
1079
|
+
entry,
|
|
1080
|
+
],
|
|
1081
|
+
}),
|
|
1082
|
+
onUndelivered: (activity) => {
|
|
1083
|
+
ring.push(activity);
|
|
1084
|
+
},
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
const response = await call(socket, invokeFrame);
|
|
1088
|
+
|
|
1089
|
+
await Bun.sleep(20);
|
|
1090
|
+
|
|
1091
|
+
server.stop(true);
|
|
1092
|
+
|
|
1093
|
+
expect(response).toMatchObject({
|
|
1094
|
+
ok: true,
|
|
1095
|
+
activity: [
|
|
1096
|
+
entry,
|
|
1097
|
+
],
|
|
1098
|
+
});
|
|
1099
|
+
expect(ring).toEqual([]);
|
|
1100
|
+
});
|
|
1101
|
+
|
|
1102
|
+
it("sends the entries to the ring when the answer cannot be written", async () => {
|
|
1103
|
+
const ring: BridgeActivity[][] = [];
|
|
1104
|
+
|
|
1105
|
+
const server = createServer({
|
|
1106
|
+
...baseOptions(socket),
|
|
1107
|
+
onInvoke: async () => ({
|
|
1108
|
+
result: BigInt(1),
|
|
1109
|
+
activity: [
|
|
1110
|
+
entry,
|
|
1111
|
+
],
|
|
1112
|
+
}),
|
|
1113
|
+
onUndelivered: (activity) => {
|
|
1114
|
+
ring.push(activity);
|
|
1115
|
+
},
|
|
1116
|
+
});
|
|
1117
|
+
|
|
1118
|
+
const response = await call(socket, invokeFrame);
|
|
1119
|
+
|
|
1120
|
+
server.stop(true);
|
|
1121
|
+
|
|
1122
|
+
expect(response.ok).toBe(false);
|
|
1123
|
+
expect(ring).toEqual([
|
|
1124
|
+
[
|
|
1125
|
+
entry,
|
|
1126
|
+
],
|
|
1127
|
+
]);
|
|
1128
|
+
});
|
|
1129
|
+
});
|
|
1130
|
+
|
|
1131
|
+
describe("failure frames", () => {
|
|
1132
|
+
let dir = "";
|
|
1133
|
+
let socket = "";
|
|
1134
|
+
|
|
1135
|
+
beforeEach(async () => {
|
|
1136
|
+
dir = await mkdtemp(join(tmpdir(), "bridge-server-"));
|
|
1137
|
+
socket = join(dir, "bridge.sock");
|
|
1138
|
+
});
|
|
1139
|
+
|
|
1140
|
+
afterEach(async () => {
|
|
1141
|
+
await rm(dir, {
|
|
1142
|
+
force: true,
|
|
1143
|
+
recursive: true,
|
|
1144
|
+
});
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
it("carry the cause in the staff error and keep the customer text friendly", async () => {
|
|
1148
|
+
const SECRET = "tok-1234567890-secret";
|
|
1149
|
+
|
|
1150
|
+
const server = createServer({
|
|
1151
|
+
...baseOptions(socket),
|
|
1152
|
+
redact: (value) => value.split(SECRET).join("••••"),
|
|
1153
|
+
onInvoke: async () => {
|
|
1154
|
+
throw new BridgeUserError(
|
|
1155
|
+
{
|
|
1156
|
+
ar: "المصدر رفض التنزيل",
|
|
1157
|
+
en: "the source refused the download",
|
|
1158
|
+
},
|
|
1159
|
+
{
|
|
1160
|
+
cause: new Error(`cdn.modrinth.com answered 403 for ${SECRET}`),
|
|
1161
|
+
},
|
|
1162
|
+
);
|
|
1163
|
+
},
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
const response = await call(socket, {
|
|
1167
|
+
id: 31,
|
|
1168
|
+
token: TOKEN,
|
|
1169
|
+
method: BridgeMethod.Invoke,
|
|
1170
|
+
module: "mods",
|
|
1171
|
+
action: "install",
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
server.stop(true);
|
|
1175
|
+
|
|
1176
|
+
expect(response).toEqual({
|
|
1177
|
+
id: 31,
|
|
1178
|
+
ok: false,
|
|
1179
|
+
error: "the source refused the download — cdn.modrinth.com answered 403 for ••••",
|
|
1180
|
+
text: {
|
|
1181
|
+
ar: "المصدر رفض التنزيل",
|
|
1182
|
+
en: "the source refused the download",
|
|
1183
|
+
},
|
|
1184
|
+
});
|
|
1185
|
+
});
|
|
786
1186
|
});
|