@serverkgg/bridge 0.0.1 → 0.0.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 +10 -3
- package/src/cli/link.test.ts +199 -0
- package/src/cli/link.ts +319 -0
- package/src/cli/main.ts +19 -1
- package/src/cli/schema.ts +62 -0
- package/src/cli/validate.test.ts +89 -0
- package/src/cli/validate.ts +218 -35
- package/src/context/bridgeContext.ts +18 -2
- package/src/core/bridgeAction.ts +13 -0
- package/src/core/bridgeFailure.ts +16 -0
- package/src/core/bridgeKind.ts +3 -0
- package/src/core/bridgeNetError.ts +10 -0
- package/src/core/index.ts +2 -0
- package/src/guides/blocks.ts +167 -0
- package/src/guides/compile.ts +193 -0
- package/src/guides/compiled.ts +28 -0
- package/src/guides/index.ts +6 -0
- package/src/guides/markdown.test.ts +374 -0
- package/src/guides/markdown.ts +769 -0
- package/src/guides/variables.ts +52 -0
- package/src/guides/version.ts +1 -0
- package/src/main.ts +2 -1
- package/src/manifest/assets.ts +4 -4
- package/src/manifest/guide.ts +23 -18
- package/src/manifest/index.ts +3 -2
- package/src/manifest/jsonSchema.ts +16 -0
- package/src/manifest/localized.ts +7 -0
- package/src/manifest/manifest.test.ts +366 -0
- package/src/manifest/manifest.ts +354 -120
- package/src/manifest/primitives.ts +63 -0
- package/src/manifest/source.ts +5 -4
- package/src/modules/bridge.ts +25 -4
- package/src/modules/bridgeDriver.ts +4 -0
- package/src/modules/bridgeModule.ts +36 -24
- package/src/panel/bridgeAccess.ts +3 -0
- package/src/panel/bridgeLayout.ts +1 -0
- package/src/panel/bridgePanel.ts +40 -2
- package/src/panel/index.ts +1 -0
- package/src/protocol/bridgeCatalog.ts +57 -0
- package/src/protocol/bridgeEgress.ts +53 -0
- package/src/protocol/bridgeEvents.ts +20 -0
- package/src/protocol/bridgeFrame.ts +16 -0
- package/src/protocol/bridgeLimits.ts +41 -0
- package/src/protocol/bridgeLine.ts +41 -6
- package/src/protocol/bridgeManifest.ts +15 -1
- package/src/protocol/bridgeVersion.ts +1 -1
- package/src/protocol/index.ts +5 -0
- package/src/runtime/bridgeActions.ts +53 -0
- package/src/runtime/bridgeContext.ts +29 -9
- package/src/runtime/bridgeDriver.test.ts +450 -0
- package/src/runtime/bridgeDriver.ts +246 -6
- package/src/runtime/bridgeEgress.ts +360 -0
- package/src/runtime/bridgeEvents.ts +4 -1
- package/src/runtime/bridgeExec.ts +15 -5
- package/src/runtime/bridgeFiles.test.ts +334 -0
- package/src/runtime/bridgeFiles.ts +130 -31
- package/src/runtime/bridgeLog.ts +26 -3
- package/src/runtime/bridgeNet.ts +75 -22
- package/src/runtime/bridgeRegistry.test.ts +291 -0
- package/src/runtime/bridgeRegistry.ts +91 -52
- package/src/runtime/bridgeServer.ts +35 -3
- package/src/runtime/bridgeSupervisor.ts +6 -6
- package/src/runtime/bridgeZip.ts +14 -3
- package/src/runtime/index.ts +0 -17
- package/src/runtime/serve.ts +44 -3
- package/src/terminal/bridgeTerminalArg.ts +11 -0
- package/src/terminal/bridgeTerminalCommand.ts +11 -0
- package/src/terminal/bridgeTerminalLevel.ts +6 -0
- package/src/terminal/bridgeTerminalRule.ts +8 -0
- package/src/terminal/index.ts +4 -0
- package/src/manifest/checks.ts +0 -50
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BridgeCommandOptions, BridgeReply } from "../context";
|
|
2
2
|
import { BridgeRuntime, BridgeStream } from "../core";
|
|
3
|
-
import type {
|
|
3
|
+
import type { BridgeLeveledLogger } from "./bridgeLog";
|
|
4
4
|
import { errorText } from "./bridgeLog";
|
|
5
5
|
import { settleUid, unprivilegedArgv } from "./bridgePrivilege";
|
|
6
6
|
|
|
@@ -32,7 +32,7 @@ export interface SupervisorOptions {
|
|
|
32
32
|
resolveCommand: () => Promise<string[]>;
|
|
33
33
|
gracefulStop?: () => Promise<void>;
|
|
34
34
|
onReady?: () => void;
|
|
35
|
-
onLog:
|
|
35
|
+
onLog: BridgeLeveledLogger;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
type LineWatcher = (entry: SupervisorLine) => void;
|
|
@@ -295,7 +295,7 @@ export const createSupervisor = (options: SupervisorOptions) => {
|
|
|
295
295
|
} catch (error) {
|
|
296
296
|
runtime = BridgeRuntime.Crashed;
|
|
297
297
|
|
|
298
|
-
options.onLog("game failed to restart", {
|
|
298
|
+
options.onLog.error("game failed to restart", {
|
|
299
299
|
error: errorText(error),
|
|
300
300
|
});
|
|
301
301
|
}
|
|
@@ -322,7 +322,7 @@ export const createSupervisor = (options: SupervisorOptions) => {
|
|
|
322
322
|
breaker = true;
|
|
323
323
|
runtime = BridgeRuntime.Crashed;
|
|
324
324
|
|
|
325
|
-
options.onLog("game crash loop detected, not restarting", {
|
|
325
|
+
options.onLog.error("game crash loop detected, not restarting", {
|
|
326
326
|
code,
|
|
327
327
|
restarts,
|
|
328
328
|
});
|
|
@@ -332,7 +332,7 @@ export const createSupervisor = (options: SupervisorOptions) => {
|
|
|
332
332
|
|
|
333
333
|
runtime = BridgeRuntime.Starting;
|
|
334
334
|
|
|
335
|
-
options.onLog("game exited, restarting", {
|
|
335
|
+
options.onLog.warn("game exited, restarting", {
|
|
336
336
|
code,
|
|
337
337
|
restarts,
|
|
338
338
|
});
|
|
@@ -405,7 +405,7 @@ export const createSupervisor = (options: SupervisorOptions) => {
|
|
|
405
405
|
|
|
406
406
|
if (options.gracefulStop) {
|
|
407
407
|
const graceful = options.gracefulStop().catch((error: unknown) => {
|
|
408
|
-
options.onLog("graceful stop failed", {
|
|
408
|
+
options.onLog.warn("graceful stop failed", {
|
|
409
409
|
error: errorText(error),
|
|
410
410
|
});
|
|
411
411
|
});
|
package/src/runtime/bridgeZip.ts
CHANGED
|
@@ -18,13 +18,20 @@ const DEFLATED = 8;
|
|
|
18
18
|
|
|
19
19
|
const ENCRYPTED_FLAG = 0x1;
|
|
20
20
|
|
|
21
|
-
const
|
|
21
|
+
export const ZIP_ENTRY_LIMIT = 2048;
|
|
22
|
+
|
|
23
|
+
export const ZIP_TREE_ENTRY_LIMIT = 8192;
|
|
22
24
|
|
|
23
25
|
const MAX_ENTRY_BYTES = 128 * 1024 * 1024;
|
|
24
26
|
|
|
27
|
+
const UNIX_MODE_FORMAT_MASK = 0xf0_00;
|
|
28
|
+
|
|
29
|
+
const UNIX_MODE_SYMLINK = 0xa0_00;
|
|
30
|
+
|
|
25
31
|
export interface ZipEntry {
|
|
26
32
|
name: string;
|
|
27
33
|
data: Uint8Array;
|
|
34
|
+
symlink: boolean;
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
const findEndOfCentralDirectory = (buffer: Buffer) => {
|
|
@@ -39,7 +46,7 @@ const findEndOfCentralDirectory = (buffer: Buffer) => {
|
|
|
39
46
|
return -1;
|
|
40
47
|
};
|
|
41
48
|
|
|
42
|
-
export const readZip = (buffer: Buffer): ZipEntry[] => {
|
|
49
|
+
export const readZip = (buffer: Buffer, maxEntries: number = ZIP_ENTRY_LIMIT): ZipEntry[] => {
|
|
43
50
|
const eocd = findEndOfCentralDirectory(buffer);
|
|
44
51
|
|
|
45
52
|
if (eocd === -1) {
|
|
@@ -49,7 +56,7 @@ export const readZip = (buffer: Buffer): ZipEntry[] => {
|
|
|
49
56
|
const total = buffer.readUInt16LE(eocd + 10);
|
|
50
57
|
const directoryOffset = buffer.readUInt32LE(eocd + 16);
|
|
51
58
|
|
|
52
|
-
if (total >
|
|
59
|
+
if (total > maxEntries) {
|
|
53
60
|
throw new Error(`archive has too many entries (${total})`);
|
|
54
61
|
}
|
|
55
62
|
|
|
@@ -69,8 +76,10 @@ export const readZip = (buffer: Buffer): ZipEntry[] => {
|
|
|
69
76
|
const nameLength = buffer.readUInt16LE(cursor + 28);
|
|
70
77
|
const extraLength = buffer.readUInt16LE(cursor + 30);
|
|
71
78
|
const commentLength = buffer.readUInt16LE(cursor + 32);
|
|
79
|
+
const externalAttributes = buffer.readUInt32LE(cursor + 38);
|
|
72
80
|
const localOffset = buffer.readUInt32LE(cursor + 42);
|
|
73
81
|
const name = buffer.subarray(cursor + 46, cursor + 46 + nameLength).toString("utf8");
|
|
82
|
+
const symlink = ((externalAttributes >>> 16) & UNIX_MODE_FORMAT_MASK) === UNIX_MODE_SYMLINK;
|
|
74
83
|
|
|
75
84
|
cursor += 46 + nameLength + extraLength + commentLength;
|
|
76
85
|
|
|
@@ -95,6 +104,7 @@ export const readZip = (buffer: Buffer): ZipEntry[] => {
|
|
|
95
104
|
entries.push({
|
|
96
105
|
name,
|
|
97
106
|
data: compressed,
|
|
107
|
+
symlink,
|
|
98
108
|
});
|
|
99
109
|
|
|
100
110
|
continue;
|
|
@@ -115,6 +125,7 @@ export const readZip = (buffer: Buffer): ZipEntry[] => {
|
|
|
115
125
|
entries.push({
|
|
116
126
|
name,
|
|
117
127
|
data,
|
|
128
|
+
symlink,
|
|
118
129
|
});
|
|
119
130
|
}
|
|
120
131
|
|
package/src/runtime/index.ts
CHANGED
|
@@ -1,18 +1 @@
|
|
|
1
|
-
export * from "./bridgeCodec";
|
|
2
|
-
export * from "./bridgeConfigReader";
|
|
3
|
-
export * from "./bridgeContext";
|
|
4
|
-
export * from "./bridgeDriver";
|
|
5
|
-
export * from "./bridgeEvents";
|
|
6
|
-
export * from "./bridgeExec";
|
|
7
|
-
export * from "./bridgeFiles";
|
|
8
|
-
export * from "./bridgeLog";
|
|
9
|
-
export * from "./bridgeNet";
|
|
10
|
-
export * from "./bridgePath";
|
|
11
|
-
export * from "./bridgePrivilege";
|
|
12
|
-
export * from "./bridgeProbe";
|
|
13
|
-
export * from "./bridgeRegistry";
|
|
14
|
-
export * from "./bridgeServer";
|
|
15
|
-
export * from "./bridgeState";
|
|
16
|
-
export * from "./bridgeSupervisor";
|
|
17
|
-
export * from "./bridgeZip";
|
|
18
1
|
export * from "./serve";
|
package/src/runtime/serve.ts
CHANGED
|
@@ -79,7 +79,7 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
79
79
|
},
|
|
80
80
|
onReady() {
|
|
81
81
|
void Promise.resolve(driver.lifecycle.onReady?.(context)).catch((error: unknown) => {
|
|
82
|
-
log("lifecycle ready hook failed", {
|
|
82
|
+
log.warn("lifecycle ready hook failed", {
|
|
83
83
|
error: errorText(error),
|
|
84
84
|
});
|
|
85
85
|
});
|
|
@@ -219,6 +219,47 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
219
219
|
await driver.backup?.release?.(context);
|
|
220
220
|
}
|
|
221
221
|
},
|
|
222
|
+
async onDescribe() {
|
|
223
|
+
const describe = driver.install.describe;
|
|
224
|
+
|
|
225
|
+
if (!describe) {
|
|
226
|
+
return {
|
|
227
|
+
supported: false,
|
|
228
|
+
version: null,
|
|
229
|
+
variant: null,
|
|
230
|
+
build: null,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
supported: true,
|
|
236
|
+
...(await describe(context)),
|
|
237
|
+
};
|
|
238
|
+
},
|
|
239
|
+
async onAnnounce(message) {
|
|
240
|
+
const announce = driver.announce;
|
|
241
|
+
|
|
242
|
+
if (!announce) {
|
|
243
|
+
return {
|
|
244
|
+
supported: false,
|
|
245
|
+
delivered: false,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (!supervisor.running) {
|
|
250
|
+
return {
|
|
251
|
+
supported: true,
|
|
252
|
+
delivered: false,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
await announce.announce(context, message);
|
|
257
|
+
|
|
258
|
+
return {
|
|
259
|
+
supported: true,
|
|
260
|
+
delivered: true,
|
|
261
|
+
};
|
|
262
|
+
},
|
|
222
263
|
});
|
|
223
264
|
|
|
224
265
|
await chmod(socketPath(config), SOCKET_MODE);
|
|
@@ -271,7 +312,7 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
271
312
|
|
|
272
313
|
supervisor.setRuntime(BridgeRuntime.Crashed);
|
|
273
314
|
|
|
274
|
-
log("install failed", {
|
|
315
|
+
log.error("install failed", {
|
|
275
316
|
error: installError,
|
|
276
317
|
});
|
|
277
318
|
|
|
@@ -286,7 +327,7 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
286
327
|
} catch (error) {
|
|
287
328
|
supervisor.setRuntime(BridgeRuntime.Crashed);
|
|
288
329
|
|
|
289
|
-
log("start failed", {
|
|
330
|
+
log.error("start failed", {
|
|
290
331
|
error: errorText(error),
|
|
291
332
|
});
|
|
292
333
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { LocalizedText } from "../core";
|
|
2
|
+
import type { BridgeTerminalArg } from "./bridgeTerminalArg";
|
|
3
|
+
|
|
4
|
+
export interface BridgeTerminalCommand {
|
|
5
|
+
name: string;
|
|
6
|
+
summary: LocalizedText;
|
|
7
|
+
syntax?: string;
|
|
8
|
+
args?: BridgeTerminalArg[];
|
|
9
|
+
danger?: boolean;
|
|
10
|
+
requiresRunning?: boolean;
|
|
11
|
+
}
|
package/src/manifest/checks.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import type { Manifest, ManifestPort } from "./manifest";
|
|
2
|
-
|
|
3
|
-
const overlaps = (a: ManifestPort, b: ManifestPort) => {
|
|
4
|
-
return a.host.min <= b.host.max && b.host.min <= a.host.max;
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export const checkManifest = (manifest: Manifest) => {
|
|
8
|
-
const portKeys = manifest.runtime.ports.map((port) => port.key);
|
|
9
|
-
|
|
10
|
-
if (new Set(portKeys).size !== portKeys.length) {
|
|
11
|
-
throw new Error("runtime declares duplicate port keys");
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const ports = manifest.runtime.ports;
|
|
15
|
-
|
|
16
|
-
for (let index = 0; index < ports.length; index += 1) {
|
|
17
|
-
for (let other = index + 1; other < ports.length; other += 1) {
|
|
18
|
-
const a = ports[index];
|
|
19
|
-
const b = ports[other];
|
|
20
|
-
|
|
21
|
-
if (!a || !b || a.protocol !== b.protocol) {
|
|
22
|
-
continue;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (overlaps(a, b)) {
|
|
26
|
-
throw new Error(`ports "${a.key}" and "${b.key}" declare overlapping ${a.protocol} host ranges`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const guideIds = manifest.guides.map((guide) => guide.id);
|
|
32
|
-
|
|
33
|
-
if (new Set(guideIds).size !== guideIds.length) {
|
|
34
|
-
throw new Error("guides declare duplicate ids");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const bodies: string[] = [];
|
|
38
|
-
|
|
39
|
-
for (const guide of manifest.guides) {
|
|
40
|
-
if (guide.body.ar === guide.body.en) {
|
|
41
|
-
throw new Error(`guide "${guide.id}" reuses one body file for both locales`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
bodies.push(guide.body.ar, guide.body.en);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (new Set(bodies).size !== bodies.length) {
|
|
48
|
-
throw new Error("guides declare duplicate body paths");
|
|
49
|
-
}
|
|
50
|
-
};
|