@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.
Files changed (71) hide show
  1. package/package.json +10 -3
  2. package/src/cli/link.test.ts +199 -0
  3. package/src/cli/link.ts +319 -0
  4. package/src/cli/main.ts +19 -1
  5. package/src/cli/schema.ts +62 -0
  6. package/src/cli/validate.test.ts +89 -0
  7. package/src/cli/validate.ts +218 -35
  8. package/src/context/bridgeContext.ts +18 -2
  9. package/src/core/bridgeAction.ts +13 -0
  10. package/src/core/bridgeFailure.ts +16 -0
  11. package/src/core/bridgeKind.ts +3 -0
  12. package/src/core/bridgeNetError.ts +10 -0
  13. package/src/core/index.ts +2 -0
  14. package/src/guides/blocks.ts +167 -0
  15. package/src/guides/compile.ts +193 -0
  16. package/src/guides/compiled.ts +28 -0
  17. package/src/guides/index.ts +6 -0
  18. package/src/guides/markdown.test.ts +374 -0
  19. package/src/guides/markdown.ts +769 -0
  20. package/src/guides/variables.ts +52 -0
  21. package/src/guides/version.ts +1 -0
  22. package/src/main.ts +2 -1
  23. package/src/manifest/assets.ts +4 -4
  24. package/src/manifest/guide.ts +23 -18
  25. package/src/manifest/index.ts +3 -2
  26. package/src/manifest/jsonSchema.ts +16 -0
  27. package/src/manifest/localized.ts +7 -0
  28. package/src/manifest/manifest.test.ts +366 -0
  29. package/src/manifest/manifest.ts +354 -120
  30. package/src/manifest/primitives.ts +63 -0
  31. package/src/manifest/source.ts +5 -4
  32. package/src/modules/bridge.ts +25 -4
  33. package/src/modules/bridgeDriver.ts +4 -0
  34. package/src/modules/bridgeModule.ts +36 -24
  35. package/src/panel/bridgeAccess.ts +3 -0
  36. package/src/panel/bridgeLayout.ts +1 -0
  37. package/src/panel/bridgePanel.ts +40 -2
  38. package/src/panel/index.ts +1 -0
  39. package/src/protocol/bridgeCatalog.ts +57 -0
  40. package/src/protocol/bridgeEgress.ts +53 -0
  41. package/src/protocol/bridgeEvents.ts +20 -0
  42. package/src/protocol/bridgeFrame.ts +16 -0
  43. package/src/protocol/bridgeLimits.ts +41 -0
  44. package/src/protocol/bridgeLine.ts +41 -6
  45. package/src/protocol/bridgeManifest.ts +15 -1
  46. package/src/protocol/bridgeVersion.ts +1 -1
  47. package/src/protocol/index.ts +5 -0
  48. package/src/runtime/bridgeActions.ts +53 -0
  49. package/src/runtime/bridgeContext.ts +29 -9
  50. package/src/runtime/bridgeDriver.test.ts +450 -0
  51. package/src/runtime/bridgeDriver.ts +246 -6
  52. package/src/runtime/bridgeEgress.ts +360 -0
  53. package/src/runtime/bridgeEvents.ts +4 -1
  54. package/src/runtime/bridgeExec.ts +15 -5
  55. package/src/runtime/bridgeFiles.test.ts +334 -0
  56. package/src/runtime/bridgeFiles.ts +130 -31
  57. package/src/runtime/bridgeLog.ts +26 -3
  58. package/src/runtime/bridgeNet.ts +75 -22
  59. package/src/runtime/bridgeRegistry.test.ts +291 -0
  60. package/src/runtime/bridgeRegistry.ts +91 -52
  61. package/src/runtime/bridgeServer.ts +35 -3
  62. package/src/runtime/bridgeSupervisor.ts +6 -6
  63. package/src/runtime/bridgeZip.ts +14 -3
  64. package/src/runtime/index.ts +0 -17
  65. package/src/runtime/serve.ts +44 -3
  66. package/src/terminal/bridgeTerminalArg.ts +11 -0
  67. package/src/terminal/bridgeTerminalCommand.ts +11 -0
  68. package/src/terminal/bridgeTerminalLevel.ts +6 -0
  69. package/src/terminal/bridgeTerminalRule.ts +8 -0
  70. package/src/terminal/index.ts +4 -0
  71. 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 { BridgeLogger } from "./bridgeLog";
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: BridgeLogger;
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
  });
@@ -18,13 +18,20 @@ const DEFLATED = 8;
18
18
 
19
19
  const ENCRYPTED_FLAG = 0x1;
20
20
 
21
- const MAX_ENTRIES = 2048;
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 > MAX_ENTRIES) {
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
 
@@ -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";
@@ -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
+
3
+ export interface BridgeTerminalArg {
4
+ key: string;
5
+ label?: LocalizedText;
6
+ required?: boolean;
7
+ variadic?: boolean;
8
+ values?: string[];
9
+ module?: string;
10
+ column?: string;
11
+ }
@@ -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
+ }
@@ -0,0 +1,6 @@
1
+ export enum BridgeTerminalLevel {
2
+ Debug = "debug",
3
+ Info = "info",
4
+ Warn = "warn",
5
+ Error = "error",
6
+ }
@@ -0,0 +1,8 @@
1
+ import type { BridgeStream } from "../core";
2
+ import type { BridgeTerminalLevel } from "./bridgeTerminalLevel";
3
+
4
+ export interface BridgeTerminalRule {
5
+ match: RegExp;
6
+ level: BridgeTerminalLevel;
7
+ stream?: BridgeStream;
8
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./bridgeTerminalArg";
2
+ export * from "./bridgeTerminalCommand";
3
+ export * from "./bridgeTerminalLevel";
4
+ export * from "./bridgeTerminalRule";
@@ -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
- };