@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,5 +1,12 @@
|
|
|
1
1
|
import { timingSafeEqual } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import type { Socket } from "bun";
|
|
3
|
+
import {
|
|
4
|
+
type BridgeActivity,
|
|
5
|
+
BridgeFailureError,
|
|
6
|
+
BridgeSecretError,
|
|
7
|
+
BridgeUserError,
|
|
8
|
+
type BridgeValues,
|
|
9
|
+
} from "../core";
|
|
3
10
|
import {
|
|
4
11
|
BRIDGE_FRAME_LIMIT,
|
|
5
12
|
type BridgeAnnounceResult,
|
|
@@ -15,8 +22,10 @@ import {
|
|
|
15
22
|
type BridgeSetupResult,
|
|
16
23
|
type BridgeStatus,
|
|
17
24
|
} from "../protocol";
|
|
18
|
-
import
|
|
25
|
+
import type { BridgeActivityAnswer } from "./bridgeActivity";
|
|
26
|
+
import { type BridgeLogger, errorDetail } from "./bridgeLog";
|
|
19
27
|
import { redactLocalized } from "./bridgeRedaction";
|
|
28
|
+
import { BridgeRefusalError } from "./bridgeRefusalError";
|
|
20
29
|
|
|
21
30
|
export interface ServerOptions {
|
|
22
31
|
socket: string;
|
|
@@ -26,7 +35,12 @@ export interface ServerOptions {
|
|
|
26
35
|
onStart: () => Promise<void>;
|
|
27
36
|
onStop: () => Promise<void>;
|
|
28
37
|
onCommand: (input: string, expect: string | undefined, timeoutMs: number | undefined) => Promise<BridgeCommandResult>;
|
|
29
|
-
onInvoke: (
|
|
38
|
+
onInvoke: (
|
|
39
|
+
module: string,
|
|
40
|
+
action: string,
|
|
41
|
+
args: BridgeValues,
|
|
42
|
+
recoveryOperationId?: string,
|
|
43
|
+
) => Promise<BridgeActivityAnswer<unknown>>;
|
|
30
44
|
onEvents: (cursor: number) => BridgeEventsResult;
|
|
31
45
|
onSample: () => Promise<BridgeSampleResult>;
|
|
32
46
|
onQuiesce: (supportsSnapshot: boolean, leaseId?: string) => Promise<BridgeQuiesceResult>;
|
|
@@ -36,11 +50,17 @@ export interface ServerOptions {
|
|
|
36
50
|
onPendingList: () => Promise<BridgePendingResult>;
|
|
37
51
|
onPendingAdd: (input: string) => Promise<BridgePendingResult>;
|
|
38
52
|
onSetupStatus: () => BridgeSetupResult;
|
|
39
|
-
onSetupSubmit: (step: string, action: string, args: BridgeValues) => Promise<BridgeSetupResult
|
|
53
|
+
onSetupSubmit: (step: string, action: string, args: BridgeValues) => Promise<BridgeActivityAnswer<BridgeSetupResult>>;
|
|
54
|
+
onUndelivered: (activity: BridgeActivity[]) => void;
|
|
40
55
|
onLog: BridgeLogger;
|
|
41
56
|
redact?: (text: string) => string;
|
|
42
57
|
}
|
|
43
58
|
|
|
59
|
+
interface SocketState {
|
|
60
|
+
buffer: string;
|
|
61
|
+
closed: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
44
64
|
interface IncomingFrame {
|
|
45
65
|
leaseId?: unknown;
|
|
46
66
|
supportsSnapshot?: unknown;
|
|
@@ -73,6 +93,23 @@ const encode = (response: BridgeResponse) => {
|
|
|
73
93
|
return `${JSON.stringify(response)}\n`;
|
|
74
94
|
};
|
|
75
95
|
|
|
96
|
+
interface PlainAnswer {
|
|
97
|
+
result: unknown;
|
|
98
|
+
activity: null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const deliver = (socket: Socket<SocketState>, frame: string): boolean => {
|
|
102
|
+
if (socket.data.closed) {
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
return socket.write(frame) === Buffer.byteLength(frame);
|
|
108
|
+
} catch {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
76
113
|
const asArgs = (value: unknown): BridgeValues => {
|
|
77
114
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
78
115
|
return {};
|
|
@@ -90,10 +127,10 @@ const asArgs = (value: unknown): BridgeValues => {
|
|
|
90
127
|
};
|
|
91
128
|
|
|
92
129
|
const logFailure = (onLog: BridgeLogger, method: string, error: unknown) => {
|
|
93
|
-
if (error instanceof BridgeUserError) {
|
|
130
|
+
if (error instanceof BridgeUserError || error instanceof BridgeRefusalError) {
|
|
94
131
|
onLog("bridge call refused", {
|
|
95
132
|
method,
|
|
96
|
-
error: error
|
|
133
|
+
error: errorDetail(error),
|
|
97
134
|
});
|
|
98
135
|
|
|
99
136
|
return;
|
|
@@ -101,7 +138,7 @@ const logFailure = (onLog: BridgeLogger, method: string, error: unknown) => {
|
|
|
101
138
|
|
|
102
139
|
onLog("bridge call failed", {
|
|
103
140
|
method,
|
|
104
|
-
error:
|
|
141
|
+
error: errorDetail(error),
|
|
105
142
|
stack: error instanceof Error ? (error.stack ?? null) : null,
|
|
106
143
|
});
|
|
107
144
|
};
|
|
@@ -137,15 +174,6 @@ export const createServer = (options: ServerOptions) => {
|
|
|
137
174
|
);
|
|
138
175
|
}
|
|
139
176
|
|
|
140
|
-
case BridgeMethod.Invoke: {
|
|
141
|
-
return await options.onInvoke(
|
|
142
|
-
String(request.module ?? ""),
|
|
143
|
-
String(request.action ?? ""),
|
|
144
|
-
asArgs(request.args),
|
|
145
|
-
asText(request.recoveryOperationId) ?? undefined,
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
177
|
case BridgeMethod.Events: {
|
|
150
178
|
return options.onEvents(typeof request.cursor === "number" ? request.cursor : 0);
|
|
151
179
|
}
|
|
@@ -196,33 +224,68 @@ export const createServer = (options: ServerOptions) => {
|
|
|
196
224
|
return options.onSetupStatus();
|
|
197
225
|
}
|
|
198
226
|
|
|
199
|
-
|
|
200
|
-
|
|
227
|
+
default: {
|
|
228
|
+
throw new Error(`unknown method "${method}"`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
201
232
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
233
|
+
const answer = async (
|
|
234
|
+
method: string,
|
|
235
|
+
request: IncomingFrame,
|
|
236
|
+
): Promise<BridgeActivityAnswer<unknown> | PlainAnswer> => {
|
|
237
|
+
if (method === BridgeMethod.Invoke) {
|
|
238
|
+
return await options.onInvoke(
|
|
239
|
+
String(request.module ?? ""),
|
|
240
|
+
String(request.action ?? ""),
|
|
241
|
+
asArgs(request.args),
|
|
242
|
+
asText(request.recoveryOperationId) ?? undefined,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
205
245
|
|
|
206
|
-
|
|
207
|
-
|
|
246
|
+
if (method === BridgeMethod.SetupSubmit) {
|
|
247
|
+
const step = asText(request.module);
|
|
208
248
|
|
|
209
|
-
|
|
210
|
-
throw new Error(
|
|
249
|
+
if (!step) {
|
|
250
|
+
throw new Error("setupSubmit needs a step id");
|
|
211
251
|
}
|
|
252
|
+
|
|
253
|
+
return await options.onSetupSubmit(step, String(request.action ?? ""), asArgs(request.args));
|
|
212
254
|
}
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
result: await handle(method, request),
|
|
258
|
+
activity: null,
|
|
259
|
+
};
|
|
213
260
|
};
|
|
214
261
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
262
|
+
const undelivered = (method: string, activity: BridgeActivity[]) => {
|
|
263
|
+
if (activity.length === 0) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
options.onLog("answer not delivered, its activity goes to the events ring", {
|
|
268
|
+
method,
|
|
269
|
+
entries: activity.length,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
options.onUndelivered(activity);
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
return Bun.listen<SocketState>({
|
|
218
276
|
unix: options.socket,
|
|
219
277
|
socket: {
|
|
220
278
|
open(socket) {
|
|
221
279
|
socket.data = {
|
|
222
280
|
buffer: "",
|
|
281
|
+
closed: false,
|
|
223
282
|
};
|
|
224
283
|
},
|
|
225
284
|
|
|
285
|
+
close(socket) {
|
|
286
|
+
socket.data.closed = true;
|
|
287
|
+
},
|
|
288
|
+
|
|
226
289
|
data(socket, chunk) {
|
|
227
290
|
socket.data.buffer += chunk.toString();
|
|
228
291
|
|
|
@@ -278,15 +341,32 @@ export const createServer = (options: ServerOptions) => {
|
|
|
278
341
|
continue;
|
|
279
342
|
}
|
|
280
343
|
|
|
281
|
-
void
|
|
282
|
-
.then((result) => {
|
|
283
|
-
|
|
284
|
-
|
|
344
|
+
void answer(String(request.method ?? ""), request)
|
|
345
|
+
.then(({ result, activity }) => {
|
|
346
|
+
const method = String(request.method ?? "");
|
|
347
|
+
|
|
348
|
+
let frame: string;
|
|
349
|
+
|
|
350
|
+
try {
|
|
351
|
+
frame = encode({
|
|
285
352
|
id,
|
|
286
353
|
ok: true,
|
|
287
354
|
result,
|
|
288
|
-
|
|
289
|
-
|
|
355
|
+
...(activity === null
|
|
356
|
+
? {}
|
|
357
|
+
: {
|
|
358
|
+
activity,
|
|
359
|
+
}),
|
|
360
|
+
});
|
|
361
|
+
} catch (error) {
|
|
362
|
+
undelivered(method, activity ?? []);
|
|
363
|
+
|
|
364
|
+
throw error;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (!deliver(socket, frame)) {
|
|
368
|
+
undelivered(method, activity ?? []);
|
|
369
|
+
}
|
|
290
370
|
})
|
|
291
371
|
.catch((error: unknown) => {
|
|
292
372
|
logFailure(options.onLog, String(request.method ?? ""), error);
|
|
@@ -297,7 +377,7 @@ export const createServer = (options: ServerOptions) => {
|
|
|
297
377
|
encode({
|
|
298
378
|
id,
|
|
299
379
|
ok: false,
|
|
300
|
-
error: redact(
|
|
380
|
+
error: redact(errorDetail(error)),
|
|
301
381
|
...(error instanceof BridgeSecretError
|
|
302
382
|
? {
|
|
303
383
|
secret: error.key,
|
|
@@ -313,6 +393,16 @@ export const createServer = (options: ServerOptions) => {
|
|
|
313
393
|
text: redactLocalized(error.text, redact),
|
|
314
394
|
}
|
|
315
395
|
: {}),
|
|
396
|
+
...(error instanceof BridgeRefusalError
|
|
397
|
+
? {
|
|
398
|
+
unchanged: true,
|
|
399
|
+
...(error.text
|
|
400
|
+
? {
|
|
401
|
+
text: redactLocalized(error.text, redact),
|
|
402
|
+
}
|
|
403
|
+
: {}),
|
|
404
|
+
}
|
|
405
|
+
: {}),
|
|
316
406
|
}),
|
|
317
407
|
);
|
|
318
408
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describe, expect,
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
2
|
import { BridgeSetupPromptKind, BridgeSetupStepState } from "../core";
|
|
3
3
|
import type { BridgeSetupRuntime } from "../protocol";
|
|
4
4
|
import { failedSetup, normalizeSetupRuntime, setupSummaryOf, unsupportedSetup } from "./bridgeSetup";
|
|
@@ -23,11 +23,11 @@ const runtimeWith = (prompt: BridgeSetupRuntime["prompt"]): BridgeSetupRuntime =
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
describe("the setup summary", () => {
|
|
26
|
-
|
|
26
|
+
it("has nothing to summarise while the driver reported no runtime", () => {
|
|
27
27
|
expect(setupSummaryOf(null)).toBeNull();
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
it("names the active driver step", () => {
|
|
31
31
|
expect(
|
|
32
32
|
setupSummaryOf(
|
|
33
33
|
runtimeWith({
|
|
@@ -41,7 +41,7 @@ describe("the setup summary", () => {
|
|
|
41
41
|
});
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
it("names no step once every driver step is done", () => {
|
|
45
45
|
expect(
|
|
46
46
|
setupSummaryOf({
|
|
47
47
|
steps: [
|
|
@@ -58,7 +58,7 @@ describe("the setup summary", () => {
|
|
|
58
58
|
});
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
it("asks for attention while a link prompt waits on the customer", () => {
|
|
62
62
|
expect(
|
|
63
63
|
setupSummaryOf(
|
|
64
64
|
runtimeWith({
|
|
@@ -73,7 +73,7 @@ describe("the setup summary", () => {
|
|
|
73
73
|
).toBe(true);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
it("asks for attention on an action prompt and on a failed one", () => {
|
|
77
77
|
expect(
|
|
78
78
|
setupSummaryOf(
|
|
79
79
|
runtimeWith({
|
|
@@ -95,7 +95,7 @@ describe("the setup summary", () => {
|
|
|
95
95
|
).toBe(true);
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
it("waits quietly while a progress prompt runs", () => {
|
|
99
99
|
expect(
|
|
100
100
|
setupSummaryOf(
|
|
101
101
|
runtimeWith({
|
|
@@ -110,7 +110,7 @@ describe("the setup summary", () => {
|
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
describe("the unsupported sentinel", () => {
|
|
113
|
-
|
|
113
|
+
it("answers a driver that declares no setup", () => {
|
|
114
114
|
expect(unsupportedSetup()).toEqual({
|
|
115
115
|
supported: false,
|
|
116
116
|
runtime: null,
|
|
@@ -119,7 +119,7 @@ describe("the unsupported sentinel", () => {
|
|
|
119
119
|
});
|
|
120
120
|
|
|
121
121
|
describe("a rejected submit", () => {
|
|
122
|
-
|
|
122
|
+
it("turns the user error into a failed prompt keeping the previous actions", () => {
|
|
123
123
|
const result = failedSetup(
|
|
124
124
|
runtimeWith({
|
|
125
125
|
kind: BridgeSetupPromptKind.Link,
|
|
@@ -164,7 +164,7 @@ describe("a rejected submit", () => {
|
|
|
164
164
|
});
|
|
165
165
|
});
|
|
166
166
|
|
|
167
|
-
|
|
167
|
+
it("carries no actions over from a prompt that had none", () => {
|
|
168
168
|
const result = failedSetup(
|
|
169
169
|
runtimeWith({
|
|
170
170
|
kind: BridgeSetupPromptKind.Wait,
|
|
@@ -180,7 +180,7 @@ describe("a rejected submit", () => {
|
|
|
180
180
|
});
|
|
181
181
|
});
|
|
182
182
|
|
|
183
|
-
|
|
183
|
+
it("stays empty when the driver never reported a runtime", () => {
|
|
184
184
|
expect(failedSetup(null, text("nothing to fail"))).toEqual({
|
|
185
185
|
supported: true,
|
|
186
186
|
runtime: null,
|
|
@@ -236,7 +236,7 @@ const link = (
|
|
|
236
236
|
};
|
|
237
237
|
|
|
238
238
|
describe("normalizing a reported runtime", () => {
|
|
239
|
-
|
|
239
|
+
it("has nothing to normalize while the driver reported no runtime", () => {
|
|
240
240
|
expect(
|
|
241
241
|
normalizeSetupRuntime(null, {
|
|
242
242
|
declared,
|
|
@@ -247,7 +247,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
247
247
|
).toBeNull();
|
|
248
248
|
});
|
|
249
249
|
|
|
250
|
-
|
|
250
|
+
it("drops a step the driver never declared", () => {
|
|
251
251
|
const { normalized, reasons } = normalizing(
|
|
252
252
|
withSteps([
|
|
253
253
|
{
|
|
@@ -272,7 +272,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
272
272
|
]);
|
|
273
273
|
});
|
|
274
274
|
|
|
275
|
-
|
|
275
|
+
it("drops the second report of the same step", () => {
|
|
276
276
|
const { normalized, reasons } = normalizing(
|
|
277
277
|
withSteps([
|
|
278
278
|
{
|
|
@@ -297,7 +297,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
297
297
|
]);
|
|
298
298
|
});
|
|
299
299
|
|
|
300
|
-
|
|
300
|
+
it("keeps the first active step and pends the rest", () => {
|
|
301
301
|
const { normalized, reasons } = normalizing(
|
|
302
302
|
withSteps([
|
|
303
303
|
{
|
|
@@ -326,7 +326,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
326
326
|
]);
|
|
327
327
|
});
|
|
328
328
|
|
|
329
|
-
|
|
329
|
+
it("clamps a percent that left the scale", () => {
|
|
330
330
|
expect(
|
|
331
331
|
normalizing(
|
|
332
332
|
runtimeWith({
|
|
@@ -361,7 +361,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
361
361
|
});
|
|
362
362
|
});
|
|
363
363
|
|
|
364
|
-
|
|
364
|
+
it("drops a percent that is not a number", () => {
|
|
365
365
|
const { normalized, reasons } = normalizing(
|
|
366
366
|
runtimeWith({
|
|
367
367
|
kind: BridgeSetupPromptKind.Progress,
|
|
@@ -382,7 +382,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
382
382
|
]);
|
|
383
383
|
});
|
|
384
384
|
|
|
385
|
-
|
|
385
|
+
it("cuts a detail line to the length the platform takes", () => {
|
|
386
386
|
const { normalized, reasons } = normalizing(
|
|
387
387
|
runtimeWith({
|
|
388
388
|
kind: BridgeSetupPromptKind.Progress,
|
|
@@ -403,7 +403,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
403
403
|
]);
|
|
404
404
|
});
|
|
405
405
|
|
|
406
|
-
|
|
406
|
+
it("drops an empty detail line", () => {
|
|
407
407
|
const { normalized, reasons } = normalizing(
|
|
408
408
|
runtimeWith({
|
|
409
409
|
kind: BridgeSetupPromptKind.Progress,
|
|
@@ -421,7 +421,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
421
421
|
]);
|
|
422
422
|
});
|
|
423
423
|
|
|
424
|
-
|
|
424
|
+
it("drops an action whose id is not kebab-case and the duplicate beside it", () => {
|
|
425
425
|
const { normalized, reasons } = normalizing(
|
|
426
426
|
runtimeWith({
|
|
427
427
|
kind: BridgeSetupPromptKind.Action,
|
|
@@ -459,7 +459,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
459
459
|
]);
|
|
460
460
|
});
|
|
461
461
|
|
|
462
|
-
|
|
462
|
+
it("keeps only as many actions as the platform renders", () => {
|
|
463
463
|
const { normalized, reasons } = normalizing(
|
|
464
464
|
runtimeWith({
|
|
465
465
|
kind: BridgeSetupPromptKind.Failed,
|
|
@@ -480,7 +480,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
480
480
|
]);
|
|
481
481
|
});
|
|
482
482
|
|
|
483
|
-
|
|
483
|
+
it("cuts a long code and drops an empty one", () => {
|
|
484
484
|
expect(
|
|
485
485
|
normalizing(
|
|
486
486
|
link({
|
|
@@ -502,7 +502,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
502
502
|
]);
|
|
503
503
|
});
|
|
504
504
|
|
|
505
|
-
|
|
505
|
+
it("re-emits an expiry as an iso stamp and drops one it cannot read", () => {
|
|
506
506
|
expect(
|
|
507
507
|
normalizing(
|
|
508
508
|
link({
|
|
@@ -524,7 +524,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
524
524
|
]);
|
|
525
525
|
});
|
|
526
526
|
|
|
527
|
-
|
|
527
|
+
it("turns a link the browser cannot open into a failed prompt keeping its actions", () => {
|
|
528
528
|
const { normalized, reasons } = normalizing(
|
|
529
529
|
link({
|
|
530
530
|
url: "javascript:alert(1)",
|
|
@@ -540,7 +540,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
540
540
|
expect(normalized?.prompt).toEqual({
|
|
541
541
|
kind: BridgeSetupPromptKind.Failed,
|
|
542
542
|
message: {
|
|
543
|
-
ar: "اللعبة
|
|
543
|
+
ar: "أعادت اللعبة رابط تسجيل دخول غير صالح، جرب مرة ثانية.",
|
|
544
544
|
en: "The game reported a broken sign-in link. Try again.",
|
|
545
545
|
},
|
|
546
546
|
actions: [
|
|
@@ -555,7 +555,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
555
555
|
]);
|
|
556
556
|
});
|
|
557
557
|
|
|
558
|
-
|
|
558
|
+
it("turns a url it cannot parse into a failed prompt", () => {
|
|
559
559
|
expect(
|
|
560
560
|
normalizing(
|
|
561
561
|
link({
|
|
@@ -565,7 +565,7 @@ describe("normalizing a reported runtime", () => {
|
|
|
565
565
|
).toBe(BridgeSetupPromptKind.Failed);
|
|
566
566
|
});
|
|
567
567
|
|
|
568
|
-
|
|
568
|
+
it("leaves a healthy runtime exactly as the driver reported it", () => {
|
|
569
569
|
const source = link({});
|
|
570
570
|
const { normalized, reasons } = normalizing(source);
|
|
571
571
|
|
|
@@ -68,7 +68,7 @@ export const failedSetup = (runtime: BridgeSetupRuntime | null, text: LocalizedT
|
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
const BROKEN_LINK_TEXT: LocalizedText = {
|
|
71
|
-
ar: "اللعبة
|
|
71
|
+
ar: "أعادت اللعبة رابط تسجيل دخول غير صالح، جرب مرة ثانية.",
|
|
72
72
|
en: "The game reported a broken sign-in link. Try again.",
|
|
73
73
|
};
|
|
74
74
|
|