@serverkgg/bridge 0.0.1 → 0.0.2

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 (59) hide show
  1. package/package.json +10 -3
  2. package/src/cli/main.ts +11 -1
  3. package/src/cli/schema.ts +62 -0
  4. package/src/cli/validate.ts +119 -36
  5. package/src/context/bridgeContext.ts +11 -1
  6. package/src/core/bridgeAction.ts +13 -0
  7. package/src/core/bridgeFailure.ts +16 -0
  8. package/src/core/bridgeKind.ts +2 -0
  9. package/src/core/bridgeNetError.ts +10 -0
  10. package/src/core/index.ts +2 -0
  11. package/src/guides/blocks.ts +167 -0
  12. package/src/guides/compile.ts +193 -0
  13. package/src/guides/compiled.ts +28 -0
  14. package/src/guides/index.ts +6 -0
  15. package/src/guides/markdown.test.ts +374 -0
  16. package/src/guides/markdown.ts +769 -0
  17. package/src/guides/variables.ts +52 -0
  18. package/src/guides/version.ts +1 -0
  19. package/src/main.ts +2 -1
  20. package/src/manifest/assets.ts +4 -4
  21. package/src/manifest/guide.ts +23 -18
  22. package/src/manifest/index.ts +3 -2
  23. package/src/manifest/jsonSchema.ts +16 -0
  24. package/src/manifest/localized.ts +7 -0
  25. package/src/manifest/manifest.test.ts +366 -0
  26. package/src/manifest/manifest.ts +354 -120
  27. package/src/manifest/primitives.ts +63 -0
  28. package/src/manifest/source.ts +5 -4
  29. package/src/modules/bridge.ts +19 -3
  30. package/src/modules/bridgeDriver.ts +4 -0
  31. package/src/modules/bridgeModule.ts +22 -24
  32. package/src/panel/bridgeAccess.ts +3 -0
  33. package/src/panel/bridgePanel.ts +6 -0
  34. package/src/panel/index.ts +1 -0
  35. package/src/protocol/bridgeCatalog.ts +56 -0
  36. package/src/protocol/bridgeEgress.ts +53 -0
  37. package/src/protocol/bridgeFrame.ts +17 -1
  38. package/src/protocol/bridgeLine.ts +41 -6
  39. package/src/protocol/bridgeManifest.ts +15 -1
  40. package/src/protocol/bridgeVersion.ts +1 -1
  41. package/src/protocol/index.ts +3 -0
  42. package/src/runtime/bridgeContext.ts +29 -9
  43. package/src/runtime/bridgeDriver.ts +1 -0
  44. package/src/runtime/bridgeEgress.ts +360 -0
  45. package/src/runtime/bridgeExec.ts +15 -5
  46. package/src/runtime/bridgeFiles.ts +58 -21
  47. package/src/runtime/bridgeLog.ts +26 -3
  48. package/src/runtime/bridgeNet.ts +75 -22
  49. package/src/runtime/bridgeRegistry.ts +51 -6
  50. package/src/runtime/bridgeServer.ts +48 -1
  51. package/src/runtime/bridgeSupervisor.ts +6 -6
  52. package/src/runtime/index.ts +0 -17
  53. package/src/runtime/serve.ts +44 -3
  54. package/src/terminal/bridgeTerminalArg.ts +11 -0
  55. package/src/terminal/bridgeTerminalCommand.ts +11 -0
  56. package/src/terminal/bridgeTerminalLevel.ts +6 -0
  57. package/src/terminal/bridgeTerminalRule.ts +8 -0
  58. package/src/terminal/index.ts +4 -0
  59. package/src/manifest/checks.ts +0 -50
@@ -1,9 +1,15 @@
1
1
  import type { BridgeContext } from "../context";
2
- import type { BridgeKind, BridgeOption, BridgeRow, BridgeStream, BridgeValues } from "../core";
2
+ import type { BridgeKind, BridgeOption, BridgeRow, BridgeStream, BridgeValues, LocalizedText } from "../core";
3
+ import type { BridgeCatalogEntry, BridgeCatalogPage, BridgeCatalogQuery } from "../protocol/bridgeCatalog";
4
+ import type { BridgeDescribeResult } from "../protocol/bridgeFrame";
5
+ import type { BridgeTerminalCommand, BridgeTerminalRule } from "../terminal";
6
+
7
+ export type BridgeDescription = Omit<BridgeDescribeResult, "supported">;
3
8
 
4
9
  export interface BridgeInstallModule {
5
10
  kind: BridgeKind.Install;
6
11
  run(context: BridgeContext): Promise<void>;
12
+ describe?(context: BridgeContext): Promise<BridgeDescription>;
7
13
  }
8
14
 
9
15
  export interface BridgeLifecycleModule {
@@ -15,6 +21,11 @@ export interface BridgeLifecycleModule {
15
21
  onReady?(context: BridgeContext): Promise<void>;
16
22
  }
17
23
 
24
+ export interface BridgeAnnounceModule {
25
+ kind: BridgeKind.Announce;
26
+ announce(context: BridgeContext, message: LocalizedText): Promise<void>;
27
+ }
28
+
18
29
  export interface BridgeBackupModule {
19
30
  kind: BridgeKind.Backup;
20
31
  settleSeconds?: number;
@@ -44,6 +55,12 @@ export interface BridgeEventsModule {
44
55
  patterns: BridgeEventPattern[];
45
56
  }
46
57
 
58
+ export interface BridgeTerminalModule {
59
+ kind: BridgeKind.Terminal;
60
+ commands: BridgeTerminalCommand[];
61
+ rules?: BridgeTerminalRule[];
62
+ }
63
+
47
64
  export interface BridgeOptionsModule {
48
65
  kind: BridgeKind.Options;
49
66
  dependsOn?: string[];
@@ -68,35 +85,14 @@ export interface BridgeCollectionModule<Row extends BridgeRow = BridgeRow> {
68
85
  actions?: Record<string, BridgeRowAction<Row>>;
69
86
  }
70
87
 
71
- export interface BridgeCatalogHit {
72
- id: string;
73
- title: string;
74
- description: string;
75
- icon: string | null;
76
- downloads: number;
77
- pageUrl?: string | null;
78
- }
79
-
80
- export interface BridgeCatalogPage {
81
- hits: BridgeCatalogHit[];
82
- total: number;
83
- }
84
-
85
- export interface BridgeCatalogEntry {
86
- id: string;
87
- path: string;
88
- title: string;
89
- version: string | null;
90
- sizeBytes: number;
91
- }
92
-
93
88
  export interface BridgeCatalogModule {
94
89
  kind: BridgeKind.Catalog;
95
90
  pageSize?: number;
96
- search(context: BridgeContext, query: string, page: number): Promise<BridgeCatalogPage>;
91
+ search(context: BridgeContext, query: BridgeCatalogQuery): Promise<BridgeCatalogPage>;
97
92
  installed(context: BridgeContext): Promise<BridgeCatalogEntry[]>;
98
93
  install(context: BridgeContext, id: string): Promise<BridgeCatalogEntry>;
99
94
  remove(context: BridgeContext, id: string): Promise<void>;
95
+ toggle?(context: BridgeContext, id: string, enabled: boolean): Promise<void>;
100
96
  }
101
97
 
102
98
  export type BridgePanelModule =
@@ -106,7 +102,9 @@ export type BridgePanelModule =
106
102
  | BridgeSettingsModule;
107
103
 
108
104
  export type BridgeModule =
105
+ | BridgeAnnounceModule
109
106
  | BridgeBackupModule
107
+ | BridgeTerminalModule
110
108
  | BridgeEventsModule
111
109
  | BridgeInstallModule
112
110
  | BridgeLifecycleModule
@@ -0,0 +1,3 @@
1
+ export enum BridgeAccess {
2
+ Invoke = "invoke",
3
+ }
@@ -1,4 +1,5 @@
1
1
  import type { BridgeOption, LocalizedText } from "../core";
2
+ import type { BridgeAccess } from "./bridgeAccess";
2
3
  import type { BridgeConfirm } from "./bridgeConfirm";
3
4
  import type { BridgeControl } from "./bridgeControl";
4
5
  import type { BridgeFormTarget } from "./bridgeFormTarget";
@@ -52,6 +53,7 @@ export interface BridgeFormSection {
52
53
  confirmText?: LocalizedText;
53
54
  fields: BridgeField[];
54
55
  visibleWhen?: BridgeVisibleWhen;
56
+ access?: BridgeAccess;
55
57
  }
56
58
 
57
59
  export interface BridgeColumn {
@@ -69,6 +71,7 @@ export interface BridgeTableSection {
69
71
  actions?: BridgeSectionAction[];
70
72
  empty?: LocalizedText;
71
73
  visibleWhen?: BridgeVisibleWhen;
74
+ access?: BridgeAccess;
72
75
  }
73
76
 
74
77
  export interface BridgeCardsSection {
@@ -81,6 +84,7 @@ export interface BridgeCardsSection {
81
84
  actions?: BridgeSectionAction[];
82
85
  empty?: LocalizedText;
83
86
  visibleWhen?: BridgeVisibleWhen;
87
+ access?: BridgeAccess;
84
88
  }
85
89
 
86
90
  export interface BridgeCatalogSection {
@@ -91,6 +95,7 @@ export interface BridgeCatalogSection {
91
95
  restartHint?: boolean;
92
96
  empty?: LocalizedText;
93
97
  visibleWhen?: BridgeVisibleWhen;
98
+ access?: BridgeAccess;
94
99
  }
95
100
 
96
101
  export type BridgeSection = BridgeCardsSection | BridgeCatalogSection | BridgeFormSection | BridgeTableSection;
@@ -100,6 +105,7 @@ export interface BridgeTab {
100
105
  title: LocalizedText;
101
106
  icon?: BridgeIcon;
102
107
  sections: BridgeSection[];
108
+ access?: BridgeAccess;
103
109
  }
104
110
 
105
111
  export interface BridgePanel {
@@ -1,3 +1,4 @@
1
+ export * from "./bridgeAccess";
1
2
  export * from "./bridgeConfirm";
2
3
  export * from "./bridgeControl";
3
4
  export * from "./bridgeFormTarget";
@@ -0,0 +1,56 @@
1
+ import type { LocalizedText } from "../core";
2
+
3
+ export interface BridgeCatalogProvider {
4
+ id: string;
5
+ label: LocalizedText;
6
+ ready: boolean;
7
+ note?: LocalizedText;
8
+ }
9
+
10
+ export interface BridgeCatalogFacet {
11
+ value: string;
12
+ label: LocalizedText;
13
+ }
14
+
15
+ export interface BridgeCatalogHit {
16
+ id: string;
17
+ provider: string;
18
+ title: string;
19
+ description: string;
20
+ icon: string | null;
21
+ downloads: number;
22
+ author: string | null;
23
+ categories: string[];
24
+ updatedAt: string | null;
25
+ pageUrl: string | null;
26
+ }
27
+
28
+ export interface BridgeCatalogPage {
29
+ hits: BridgeCatalogHit[];
30
+ total: number;
31
+ providers: BridgeCatalogProvider[];
32
+ categories: BridgeCatalogFacet[];
33
+ sorts: BridgeCatalogFacet[];
34
+ }
35
+
36
+ export interface BridgeCatalogEntry {
37
+ id: string;
38
+ provider: string | null;
39
+ path: string;
40
+ title: string;
41
+ version: string | null;
42
+ sizeBytes: number;
43
+ enabled: boolean;
44
+ gameVersion: string | null;
45
+ stale: boolean;
46
+ pageUrl: string | null;
47
+ icon: string | null;
48
+ }
49
+
50
+ export interface BridgeCatalogQuery {
51
+ query: string;
52
+ page: number;
53
+ provider: string | null;
54
+ category: string | null;
55
+ sort: string | null;
56
+ }
@@ -0,0 +1,53 @@
1
+ export const BRIDGE_EGRESS_SOCKET_NAME = "egress.sock";
2
+
3
+ export const BRIDGE_EGRESS_FRAME_LIMIT = 16 * 1024 * 1024;
4
+
5
+ export const BRIDGE_EGRESS_BODY_LIMIT = 8 * 1024 * 1024;
6
+
7
+ export const BRIDGE_EGRESS_DOWNLOAD_LIMIT = 512 * 1024 * 1024;
8
+
9
+ export enum BridgeEgressMethod {
10
+ Fetch = "fetch",
11
+ Download = "download",
12
+ }
13
+
14
+ export interface BridgeEgressRequest {
15
+ id: number;
16
+ token: string;
17
+ method: BridgeEgressMethod;
18
+ url: string;
19
+ headers?: Record<string, string>;
20
+ timeoutMs?: number;
21
+ cache?: boolean;
22
+ cacheSeconds?: number;
23
+ refresh?: boolean;
24
+ digest?: string;
25
+ sizeBytes?: number;
26
+ }
27
+
28
+ export interface BridgeEgressFetchResult {
29
+ status: number;
30
+ body: string;
31
+ fromCache: boolean;
32
+ }
33
+
34
+ export interface BridgeEgressDownloadResult {
35
+ status: number;
36
+ sizeBytes: number;
37
+ fromCache: boolean;
38
+ }
39
+
40
+ export interface BridgeEgressSuccess<Result> {
41
+ id: number | null;
42
+ ok: true;
43
+ result: Result;
44
+ }
45
+
46
+ export interface BridgeEgressFailure {
47
+ id: number | null;
48
+ ok: false;
49
+ error: string;
50
+ status: number | null;
51
+ }
52
+
53
+ export type BridgeEgressResponse<Result> = BridgeEgressFailure | BridgeEgressSuccess<Result>;
@@ -1,4 +1,4 @@
1
- import type { BridgeDesired, BridgeRuntime, BridgeValues } from "../core";
1
+ import type { BridgeDesired, BridgeRuntime, BridgeValues, LocalizedText } from "../core";
2
2
 
3
3
  export const BRIDGE_SOCKET_NAME = "bridge.sock";
4
4
 
@@ -13,7 +13,9 @@ export const BRIDGE_FRAME_LIMIT = 1024 * 1024;
13
13
  export const BRIDGE_INSTALL_ERROR_LIMIT = 2048;
14
14
 
15
15
  export enum BridgeMethod {
16
+ Announce = "announce",
16
17
  Command = "command",
18
+ Describe = "describe",
17
19
  Events = "events",
18
20
  Invoke = "invoke",
19
21
  Manifest = "manifest",
@@ -36,6 +38,7 @@ export interface BridgeRequest {
36
38
  action?: string;
37
39
  args?: BridgeValues;
38
40
  cursor?: number;
41
+ message?: LocalizedText;
39
42
  }
40
43
 
41
44
  export interface BridgeCommandResult {
@@ -55,6 +58,7 @@ export interface BridgeFailure {
55
58
  ok: false;
56
59
  error: string;
57
60
  secret?: string;
61
+ failure?: string;
58
62
  }
59
63
 
60
64
  export type BridgeResponse = BridgeFailure | BridgeSuccess;
@@ -73,12 +77,24 @@ export interface BridgeSampleResult {
73
77
  max: number | null;
74
78
  }
75
79
 
80
+ export interface BridgeAnnounceResult {
81
+ supported: boolean;
82
+ delivered: boolean;
83
+ }
84
+
76
85
  export interface BridgeQuiesceResult {
77
86
  supported: boolean;
78
87
  quiesced: boolean;
79
88
  settleSeconds: number;
80
89
  }
81
90
 
91
+ export interface BridgeDescribeResult {
92
+ supported: boolean;
93
+ version: string | null;
94
+ variant: string | null;
95
+ build: string | null;
96
+ }
97
+
82
98
  export interface BridgeEvent {
83
99
  seq: number;
84
100
  event: string;
@@ -1,10 +1,31 @@
1
+ import { BridgeTerminalLevel } from "../terminal";
2
+
1
3
  export const BRIDGE_LOG_SOURCE = "bridge";
2
4
 
5
+ const FIELD_LIMIT = 16;
6
+
7
+ const FIELD_KEY_LIMIT = 64;
8
+
9
+ const FIELD_VALUE_LIMIT = 512;
10
+
3
11
  export interface BridgeLogLine {
12
+ level: BridgeTerminalLevel;
4
13
  message: string;
5
- text: string;
14
+ fields: Record<string, string>;
6
15
  }
7
16
 
17
+ const LEVELS = new Set<string>(Object.values(BridgeTerminalLevel));
18
+
19
+ const levelOf = (value: unknown): BridgeTerminalLevel => {
20
+ return typeof value === "string" && LEVELS.has(value) ? (value as BridgeTerminalLevel) : BridgeTerminalLevel.Info;
21
+ };
22
+
23
+ const textOf = (value: unknown) => {
24
+ const text = typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
25
+
26
+ return text.slice(0, FIELD_VALUE_LIMIT);
27
+ };
28
+
8
29
  export const parseBridgeLine = (line: string): BridgeLogLine | null => {
9
30
  if (!line.startsWith("{") || !line.endsWith("}")) {
10
31
  return null;
@@ -28,13 +49,27 @@ export const parseBridgeLine = (line: string): BridgeLogLine | null => {
28
49
  return null;
29
50
  }
30
51
 
31
- const fields = Object.entries(entry)
32
- .filter(([key]) => key !== "source" && key !== "message")
33
- .map(([key, value]) => `${key}=${typeof value === "object" ? JSON.stringify(value) : String(value)}`)
34
- .join(" ");
52
+ const fields: Record<string, string> = {};
53
+
54
+ for (const [key, value] of Object.entries(entry)) {
55
+ if (key === "source" || key === "message" || key === "level" || key === "driver") {
56
+ continue;
57
+ }
58
+
59
+ if (key.length > FIELD_KEY_LIMIT) {
60
+ continue;
61
+ }
62
+
63
+ if (Object.keys(fields).length >= FIELD_LIMIT) {
64
+ break;
65
+ }
66
+
67
+ fields[key] = textOf(value);
68
+ }
35
69
 
36
70
  return {
71
+ level: levelOf(entry.level),
37
72
  message: entry.message,
38
- text: fields.length > 0 ? `${entry.message} ${fields}` : entry.message,
73
+ fields,
39
74
  };
40
75
  };
@@ -1,5 +1,18 @@
1
- import type { BridgeKind } from "../core";
1
+ import type { BridgeKind, BridgeStream } from "../core";
2
2
  import type { BridgePanel } from "../panel";
3
+ import type { BridgeTerminalCommand, BridgeTerminalLevel } from "../terminal";
4
+
5
+ export interface BridgeTerminalRuleManifest {
6
+ match: string;
7
+ flags: string;
8
+ level: BridgeTerminalLevel;
9
+ stream?: BridgeStream;
10
+ }
11
+
12
+ export interface BridgeTerminalManifest {
13
+ commands: BridgeTerminalCommand[];
14
+ rules: BridgeTerminalRuleManifest[];
15
+ }
3
16
 
4
17
  export interface BridgeModuleManifest {
5
18
  id: string;
@@ -14,6 +27,7 @@ export interface BridgeModuleManifest {
14
27
  export interface BridgeManifest {
15
28
  version: string;
16
29
  panel: BridgePanel | null;
30
+ terminal: BridgeTerminalManifest | null;
17
31
  modules: BridgeModuleManifest[];
18
32
  events: string[];
19
33
  }
@@ -1,4 +1,4 @@
1
- import pkg from "../../package.json";
1
+ import pkg from "../../package.json" with { type: "json" };
2
2
 
3
3
  export const BRIDGE_VERSION: string = pkg.version;
4
4
 
@@ -1,6 +1,9 @@
1
1
  export * from "../core";
2
2
  export * from "../panel";
3
+ export * from "../terminal";
4
+ export * from "./bridgeCatalog";
3
5
  export * from "./bridgeConfig";
6
+ export * from "./bridgeEgress";
4
7
  export * from "./bridgeFrame";
5
8
  export * from "./bridgeLine";
6
9
  export * from "./bridgeManifest";
@@ -2,15 +2,16 @@ import type { BridgeContext } from "../context";
2
2
  import type { BridgeValues } from "../core";
3
3
  import type { BridgeConfig } from "../protocol";
4
4
  import { createBridgeCodecs } from "./bridgeCodec";
5
+ import { createBridgeEgress } from "./bridgeEgress";
5
6
  import { createBridgeExec } from "./bridgeExec";
6
7
  import { createBridgeFiles } from "./bridgeFiles";
7
- import type { BridgeLogger } from "./bridgeLog";
8
+ import type { BridgeLeveledLogger } from "./bridgeLog";
8
9
  import { createBridgeNet } from "./bridgeNet";
9
10
  import { createBridgeProbes } from "./bridgeProbe";
10
11
  import type { BridgeSupervisor } from "./bridgeSupervisor";
11
12
 
12
13
  export interface ContextHooks {
13
- onLog: BridgeLogger;
14
+ onLog: BridgeLeveledLogger;
14
15
  onEmit: (event: string, payload?: BridgeValues) => void;
15
16
  }
16
17
 
@@ -19,10 +20,13 @@ export const createContext = (
19
20
  supervisor: BridgeSupervisor,
20
21
  hooks: ContextHooks,
21
22
  ): BridgeContext => {
23
+ const egress = createBridgeEgress(config);
24
+
22
25
  const files = createBridgeFiles({
23
26
  root: config.cwd,
24
27
  uid: config.gameUid,
25
28
  gid: config.gameGid,
29
+ egress,
26
30
  onLog: hooks.onLog,
27
31
  });
28
32
 
@@ -58,7 +62,7 @@ export const createContext = (
58
62
 
59
63
  codec: createBridgeCodecs(files),
60
64
 
61
- net: createBridgeNet(),
65
+ net: createBridgeNet(egress),
62
66
 
63
67
  probe: createBridgeProbes(),
64
68
 
@@ -86,11 +90,27 @@ export const createContext = (
86
90
  hooks.onEmit(event, payload);
87
91
  },
88
92
 
89
- log(message, fields) {
90
- hooks.onLog(message, {
91
- driver: true,
92
- ...fields,
93
- });
94
- },
93
+ log: Object.assign(
94
+ (message: string, fields?: BridgeValues) => {
95
+ hooks.onLog(message, {
96
+ ...fields,
97
+ driver: true,
98
+ });
99
+ },
100
+ {
101
+ warn(message: string, fields?: BridgeValues) {
102
+ hooks.onLog.warn(message, {
103
+ ...fields,
104
+ driver: true,
105
+ });
106
+ },
107
+ error(message: string, fields?: BridgeValues) {
108
+ hooks.onLog.error(message, {
109
+ ...fields,
110
+ driver: true,
111
+ });
112
+ },
113
+ },
114
+ ),
95
115
  };
96
116
  };
@@ -3,6 +3,7 @@ import type { BridgeDriver, BridgePanelModule } from "../modules";
3
3
  import { type BridgeField, BridgeFormTarget, BridgeLayout, type BridgeSection, type BridgeTab } from "../panel";
4
4
 
5
5
  const RESERVED_MODULE_IDS = new Set([
6
+ "announce",
6
7
  "backup",
7
8
  "events",
8
9
  "install",