@serverkgg/bridge 0.0.2 → 0.0.4
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/README.md +1 -1
- package/package.json +1 -1
- package/src/cli/compile.ts +19 -37
- package/src/cli/link.test.ts +199 -0
- package/src/cli/link.ts +319 -0
- package/src/cli/main.ts +9 -1
- package/src/cli/validate.test.ts +89 -0
- package/src/cli/validate.ts +100 -0
- package/src/context/bridgeContext.ts +7 -1
- package/src/core/bridgeKind.ts +1 -0
- package/src/modules/bridge.ts +6 -1
- package/src/modules/bridgeModule.ts +17 -3
- package/src/panel/bridgeLayout.ts +1 -0
- package/src/panel/bridgePanel.ts +34 -2
- package/src/protocol/bridgeCatalog.ts +1 -0
- package/src/protocol/bridgeEvents.ts +20 -0
- package/src/protocol/bridgeFrame.ts +2 -2
- package/src/protocol/bridgeLimits.ts +41 -0
- package/src/protocol/index.ts +2 -0
- package/src/runtime/bridgeActions.ts +53 -0
- package/src/runtime/bridgeDriver.test.ts +450 -0
- package/src/runtime/bridgeDriver.ts +245 -6
- package/src/runtime/bridgeEvents.ts +4 -1
- package/src/runtime/bridgeFiles.test.ts +334 -0
- package/src/runtime/bridgeFiles.ts +72 -10
- package/src/runtime/bridgeRegistry.test.ts +291 -0
- package/src/runtime/bridgeRegistry.ts +45 -51
- package/src/runtime/bridgeServer.ts +5 -20
- package/src/runtime/bridgeZip.ts +14 -3
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ bunx serverk-bridge validate
|
|
|
41
41
|
bunx serverk-bridge compile
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
`validate` checks `serverk.yml` against the real platform schema, verifies the logo and banner, and validates the driver's panel wiring. `compile` produces `dist/bridge
|
|
44
|
+
`validate` checks `serverk.yml` against the real platform schema, verifies the logo and banner, and validates the driver's panel wiring. `compile` produces `dist/bridge`, an amd64 binary — serverk publishes game images for `linux/amd64` only.
|
|
45
45
|
|
|
46
46
|
## Compatibility
|
|
47
47
|
|
package/package.json
CHANGED
package/src/cli/compile.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { parseArgs } from "node:util";
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
amd64: "bun-linux-x64",
|
|
5
|
-
arm64: "bun-linux-arm64",
|
|
6
|
-
};
|
|
3
|
+
const TARGET = "bun-linux-x64";
|
|
7
4
|
|
|
8
5
|
const HELP = `serverk-bridge compile [options]
|
|
9
6
|
|
|
10
7
|
options:
|
|
11
|
-
--arch <amd64|arm64> architecture to compile (repeatable, default: both)
|
|
12
8
|
--entry <path> entrypoint (default: src/main.ts)
|
|
13
9
|
--outdir <path> output directory (default: dist)
|
|
14
10
|
--help show this help`;
|
|
@@ -17,10 +13,6 @@ export const runCompile = async (args: string[]) => {
|
|
|
17
13
|
const { values } = parseArgs({
|
|
18
14
|
args,
|
|
19
15
|
options: {
|
|
20
|
-
arch: {
|
|
21
|
-
type: "string",
|
|
22
|
-
multiple: true,
|
|
23
|
-
},
|
|
24
16
|
entry: {
|
|
25
17
|
type: "string",
|
|
26
18
|
default: "src/main.ts",
|
|
@@ -42,34 +34,24 @@ export const runCompile = async (args: string[]) => {
|
|
|
42
34
|
return;
|
|
43
35
|
}
|
|
44
36
|
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
values.entry,
|
|
62
|
-
"--outfile",
|
|
63
|
-
outfile,
|
|
64
|
-
],
|
|
65
|
-
{
|
|
66
|
-
stderr: "inherit",
|
|
67
|
-
stdout: "inherit",
|
|
68
|
-
},
|
|
69
|
-
);
|
|
37
|
+
const outfile = `${values.outdir}/bridge`;
|
|
38
|
+
const child = Bun.spawn(
|
|
39
|
+
[
|
|
40
|
+
"bun",
|
|
41
|
+
"build",
|
|
42
|
+
"--compile",
|
|
43
|
+
`--target=${TARGET}`,
|
|
44
|
+
values.entry,
|
|
45
|
+
"--outfile",
|
|
46
|
+
outfile,
|
|
47
|
+
],
|
|
48
|
+
{
|
|
49
|
+
stderr: "inherit",
|
|
50
|
+
stdout: "inherit",
|
|
51
|
+
},
|
|
52
|
+
);
|
|
70
53
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
54
|
+
if ((await child.exited) !== 0) {
|
|
55
|
+
throw new Error("compile failed");
|
|
74
56
|
}
|
|
75
57
|
};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import {
|
|
3
|
+
existsSync,
|
|
4
|
+
lstatSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
mkdtempSync,
|
|
7
|
+
realpathSync,
|
|
8
|
+
rmSync,
|
|
9
|
+
symlinkSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
} from "node:fs";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { checkBridge, linkBridge, unlinkBridge } from "./link";
|
|
15
|
+
|
|
16
|
+
const SOURCE = "../serverk/modules/bridge";
|
|
17
|
+
|
|
18
|
+
describe("link", () => {
|
|
19
|
+
let root = "";
|
|
20
|
+
let cwd = "";
|
|
21
|
+
let source = "";
|
|
22
|
+
let target = "";
|
|
23
|
+
|
|
24
|
+
const writePackage = (dir: string, name: string, version: string) => {
|
|
25
|
+
mkdirSync(dir, {
|
|
26
|
+
recursive: true,
|
|
27
|
+
});
|
|
28
|
+
writeFileSync(
|
|
29
|
+
join(dir, "package.json"),
|
|
30
|
+
JSON.stringify({
|
|
31
|
+
name,
|
|
32
|
+
version,
|
|
33
|
+
}),
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const link = (env: Record<string, string | undefined> = {}) => {
|
|
38
|
+
return linkBridge({
|
|
39
|
+
cwd,
|
|
40
|
+
source: SOURCE,
|
|
41
|
+
env,
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
root = realpathSync(mkdtempSync(`${tmpdir()}/serverk-link-`));
|
|
47
|
+
cwd = join(root, "game");
|
|
48
|
+
source = join(root, "serverk/modules/bridge");
|
|
49
|
+
target = join(cwd, "node_modules/@serverkgg/bridge");
|
|
50
|
+
|
|
51
|
+
mkdirSync(cwd, {
|
|
52
|
+
recursive: true,
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
afterEach(() => {
|
|
57
|
+
rmSync(root, {
|
|
58
|
+
force: true,
|
|
59
|
+
recursive: true,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("skips when CI is set", () => {
|
|
64
|
+
writePackage(source, "@serverkgg/bridge", "0.0.3");
|
|
65
|
+
writePackage(target, "@serverkgg/bridge", "0.0.2");
|
|
66
|
+
|
|
67
|
+
expect(
|
|
68
|
+
link({
|
|
69
|
+
CI: "true",
|
|
70
|
+
}),
|
|
71
|
+
).toMatchObject({
|
|
72
|
+
kind: "skipped",
|
|
73
|
+
reason: "ci",
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
expect(lstatSync(target).isSymbolicLink()).toBe(false);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("skips when the local checkout is missing", () => {
|
|
80
|
+
expect(link()).toMatchObject({
|
|
81
|
+
kind: "skipped",
|
|
82
|
+
reason: "source-missing",
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("skips when the local checkout is another package", () => {
|
|
87
|
+
writePackage(source, "@serverkgg/minecraft", "0.0.0");
|
|
88
|
+
|
|
89
|
+
expect(link()).toMatchObject({
|
|
90
|
+
kind: "skipped",
|
|
91
|
+
reason: "source-mismatch",
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("replaces the registry directory with a symlink", () => {
|
|
96
|
+
writePackage(source, "@serverkgg/bridge", "0.0.3");
|
|
97
|
+
writePackage(target, "@serverkgg/bridge", "0.0.2");
|
|
98
|
+
writeFileSync(join(target, "installed.txt"), "registry");
|
|
99
|
+
|
|
100
|
+
expect(link()).toEqual({
|
|
101
|
+
kind: "linked",
|
|
102
|
+
source,
|
|
103
|
+
version: "0.0.3",
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
expect(lstatSync(target).isSymbolicLink()).toBe(true);
|
|
107
|
+
expect(realpathSync(target)).toBe(source);
|
|
108
|
+
expect(existsSync(join(target, "installed.txt"))).toBe(false);
|
|
109
|
+
expect(existsSync(join(source, "package.json"))).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("creates the scope directory when nothing is installed", () => {
|
|
113
|
+
writePackage(source, "@serverkgg/bridge", "0.0.3");
|
|
114
|
+
|
|
115
|
+
expect(link()).toMatchObject({
|
|
116
|
+
kind: "linked",
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(realpathSync(target)).toBe(source);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("is idempotent once linked", () => {
|
|
123
|
+
writePackage(source, "@serverkgg/bridge", "0.0.3");
|
|
124
|
+
|
|
125
|
+
expect(link()).toMatchObject({
|
|
126
|
+
kind: "linked",
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
expect(link()).toEqual({
|
|
130
|
+
kind: "already-linked",
|
|
131
|
+
source,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
expect(realpathSync(target)).toBe(source);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("relinks a symlink pointing somewhere else", () => {
|
|
138
|
+
const other = join(root, "other");
|
|
139
|
+
|
|
140
|
+
writePackage(source, "@serverkgg/bridge", "0.0.3");
|
|
141
|
+
writePackage(other, "@serverkgg/bridge", "0.0.1");
|
|
142
|
+
mkdirSync(join(cwd, "node_modules/@serverkgg"), {
|
|
143
|
+
recursive: true,
|
|
144
|
+
});
|
|
145
|
+
symlinkSync(other, target, "dir");
|
|
146
|
+
|
|
147
|
+
expect(link()).toMatchObject({
|
|
148
|
+
kind: "linked",
|
|
149
|
+
version: "0.0.3",
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
expect(realpathSync(target)).toBe(source);
|
|
153
|
+
expect(existsSync(join(other, "package.json"))).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("unlink removes the symlink and keeps the checkout", () => {
|
|
157
|
+
writePackage(source, "@serverkgg/bridge", "0.0.3");
|
|
158
|
+
link();
|
|
159
|
+
|
|
160
|
+
expect(unlinkBridge(cwd)).toEqual({
|
|
161
|
+
kind: "unlinked",
|
|
162
|
+
source,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(existsSync(target)).toBe(false);
|
|
166
|
+
expect(existsSync(join(source, "package.json"))).toBe(true);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("unlink leaves a registry install alone", () => {
|
|
170
|
+
writePackage(target, "@serverkgg/bridge", "0.0.2");
|
|
171
|
+
|
|
172
|
+
expect(unlinkBridge(cwd)).toEqual({
|
|
173
|
+
kind: "not-linked",
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
expect(existsSync(join(target, "package.json"))).toBe(true);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test("check reports every state", () => {
|
|
180
|
+
expect(checkBridge(cwd)).toEqual({
|
|
181
|
+
kind: "missing",
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
writePackage(target, "@serverkgg/bridge", "0.0.2");
|
|
185
|
+
|
|
186
|
+
expect(checkBridge(cwd)).toEqual({
|
|
187
|
+
kind: "registry",
|
|
188
|
+
version: "0.0.2",
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
writePackage(source, "@serverkgg/bridge", "0.0.3");
|
|
192
|
+
link();
|
|
193
|
+
|
|
194
|
+
expect(checkBridge(cwd)).toEqual({
|
|
195
|
+
kind: "linked",
|
|
196
|
+
source,
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
});
|
package/src/cli/link.ts
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { lstatSync, mkdirSync, readFileSync, realpathSync, rmSync, symlinkSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
|
|
5
|
+
const PACKAGE_NAME = "@serverkgg/bridge";
|
|
6
|
+
|
|
7
|
+
const DEFAULT_SOURCE = "../serverk/modules/bridge";
|
|
8
|
+
|
|
9
|
+
const INSTALL_PATH = `node_modules/${PACKAGE_NAME}`;
|
|
10
|
+
|
|
11
|
+
const HELP = `serverk-bridge link [options]
|
|
12
|
+
|
|
13
|
+
point ${INSTALL_PATH} at a local bridge checkout without touching package.json or bun.lock.
|
|
14
|
+
does nothing when CI is set or the checkout is absent, so the registry package is used everywhere else.
|
|
15
|
+
|
|
16
|
+
options:
|
|
17
|
+
--source <dir> local bridge checkout (default: ${DEFAULT_SOURCE})
|
|
18
|
+
--check print which bridge is installed, change nothing
|
|
19
|
+
--unlink drop the link so the next install restores the registry package
|
|
20
|
+
--help show this help`;
|
|
21
|
+
|
|
22
|
+
interface PackageFile {
|
|
23
|
+
name: string;
|
|
24
|
+
version: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface LinkInput {
|
|
28
|
+
cwd: string;
|
|
29
|
+
source: string;
|
|
30
|
+
env: Record<string, string | undefined>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type LinkSkip = "ci" | "source-missing" | "source-mismatch";
|
|
34
|
+
|
|
35
|
+
export type LinkResult =
|
|
36
|
+
| {
|
|
37
|
+
kind: "skipped";
|
|
38
|
+
reason: LinkSkip;
|
|
39
|
+
source: string;
|
|
40
|
+
}
|
|
41
|
+
| {
|
|
42
|
+
kind: "already-linked";
|
|
43
|
+
source: string;
|
|
44
|
+
}
|
|
45
|
+
| {
|
|
46
|
+
kind: "linked";
|
|
47
|
+
source: string;
|
|
48
|
+
version: string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type CheckResult =
|
|
52
|
+
| {
|
|
53
|
+
kind: "linked";
|
|
54
|
+
source: string;
|
|
55
|
+
}
|
|
56
|
+
| {
|
|
57
|
+
kind: "registry";
|
|
58
|
+
version: string;
|
|
59
|
+
}
|
|
60
|
+
| {
|
|
61
|
+
kind: "missing";
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export type UnlinkResult =
|
|
65
|
+
| {
|
|
66
|
+
kind: "unlinked";
|
|
67
|
+
source: string;
|
|
68
|
+
}
|
|
69
|
+
| {
|
|
70
|
+
kind: "not-linked";
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const readPackageFile = (dir: string): PackageFile | null => {
|
|
74
|
+
let text: string;
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
text = readFileSync(join(dir, "package.json"), "utf8");
|
|
78
|
+
} catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let parsed: unknown;
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
parsed = JSON.parse(text);
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (typeof parsed !== "object" || parsed === null || !("name" in parsed) || !("version" in parsed)) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const { name, version } = parsed;
|
|
95
|
+
|
|
96
|
+
if (typeof name !== "string" || typeof version !== "string") {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
name,
|
|
102
|
+
version,
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const linkedSource = (target: string): string | null => {
|
|
107
|
+
try {
|
|
108
|
+
if (!lstatSync(target).isSymbolicLink()) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return realpathSync(target);
|
|
113
|
+
} catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const installPath = (cwd: string) => {
|
|
119
|
+
return resolve(cwd, INSTALL_PATH);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const linkBridge = (input: LinkInput): LinkResult => {
|
|
123
|
+
const source = resolve(input.cwd, input.source);
|
|
124
|
+
|
|
125
|
+
if (input.env.CI) {
|
|
126
|
+
return {
|
|
127
|
+
kind: "skipped",
|
|
128
|
+
reason: "ci",
|
|
129
|
+
source,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const local = readPackageFile(source);
|
|
134
|
+
|
|
135
|
+
if (!local) {
|
|
136
|
+
return {
|
|
137
|
+
kind: "skipped",
|
|
138
|
+
reason: "source-missing",
|
|
139
|
+
source,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (local.name !== PACKAGE_NAME) {
|
|
144
|
+
return {
|
|
145
|
+
kind: "skipped",
|
|
146
|
+
reason: "source-mismatch",
|
|
147
|
+
source,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const target = installPath(input.cwd);
|
|
152
|
+
|
|
153
|
+
if (linkedSource(target) === realpathSync(source)) {
|
|
154
|
+
return {
|
|
155
|
+
kind: "already-linked",
|
|
156
|
+
source,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
rmSync(target, {
|
|
161
|
+
force: true,
|
|
162
|
+
recursive: true,
|
|
163
|
+
});
|
|
164
|
+
mkdirSync(dirname(target), {
|
|
165
|
+
recursive: true,
|
|
166
|
+
});
|
|
167
|
+
symlinkSync(source, target, "dir");
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
kind: "linked",
|
|
171
|
+
source,
|
|
172
|
+
version: local.version,
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const checkBridge = (cwd: string): CheckResult => {
|
|
177
|
+
const target = installPath(cwd);
|
|
178
|
+
const source = linkedSource(target);
|
|
179
|
+
|
|
180
|
+
if (source) {
|
|
181
|
+
return {
|
|
182
|
+
kind: "linked",
|
|
183
|
+
source,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const installed = readPackageFile(target);
|
|
188
|
+
|
|
189
|
+
if (!installed) {
|
|
190
|
+
return {
|
|
191
|
+
kind: "missing",
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
kind: "registry",
|
|
197
|
+
version: installed.version,
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export const unlinkBridge = (cwd: string): UnlinkResult => {
|
|
202
|
+
const target = installPath(cwd);
|
|
203
|
+
const source = linkedSource(target);
|
|
204
|
+
|
|
205
|
+
if (!source) {
|
|
206
|
+
return {
|
|
207
|
+
kind: "not-linked",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
rmSync(target, {
|
|
212
|
+
force: true,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
kind: "unlinked",
|
|
217
|
+
source,
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const linkText = (result: LinkResult): string | null => {
|
|
222
|
+
switch (result.kind) {
|
|
223
|
+
case "skipped": {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
case "already-linked": {
|
|
228
|
+
return `${PACKAGE_NAME} already linked -> ${result.source}`;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
case "linked": {
|
|
232
|
+
return `${PACKAGE_NAME} linked -> ${result.source} (${result.version})`;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const checkText = (result: CheckResult): string => {
|
|
238
|
+
switch (result.kind) {
|
|
239
|
+
case "linked": {
|
|
240
|
+
return `${PACKAGE_NAME} linked -> ${result.source}`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
case "registry": {
|
|
244
|
+
return `${PACKAGE_NAME} registry ${result.version}`;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
case "missing": {
|
|
248
|
+
return `${PACKAGE_NAME} missing`;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
const unlinkText = (result: UnlinkResult): string => {
|
|
254
|
+
switch (result.kind) {
|
|
255
|
+
case "unlinked": {
|
|
256
|
+
return `${PACKAGE_NAME} unlinked — run "bun install" to restore the registry package`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
case "not-linked": {
|
|
260
|
+
return `${PACKAGE_NAME} is not linked`;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
export const runLink = async (args: string[]) => {
|
|
266
|
+
const { values } = parseArgs({
|
|
267
|
+
args,
|
|
268
|
+
options: {
|
|
269
|
+
source: {
|
|
270
|
+
type: "string",
|
|
271
|
+
default: DEFAULT_SOURCE,
|
|
272
|
+
},
|
|
273
|
+
check: {
|
|
274
|
+
type: "boolean",
|
|
275
|
+
default: false,
|
|
276
|
+
},
|
|
277
|
+
unlink: {
|
|
278
|
+
type: "boolean",
|
|
279
|
+
default: false,
|
|
280
|
+
},
|
|
281
|
+
help: {
|
|
282
|
+
type: "boolean",
|
|
283
|
+
default: false,
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
if (values.help) {
|
|
289
|
+
console.log(HELP);
|
|
290
|
+
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const cwd = process.cwd();
|
|
295
|
+
|
|
296
|
+
if (values.check) {
|
|
297
|
+
console.log(checkText(checkBridge(cwd)));
|
|
298
|
+
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (values.unlink) {
|
|
303
|
+
console.log(unlinkText(unlinkBridge(cwd)));
|
|
304
|
+
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const message = linkText(
|
|
309
|
+
linkBridge({
|
|
310
|
+
cwd,
|
|
311
|
+
source: values.source,
|
|
312
|
+
env: process.env,
|
|
313
|
+
}),
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
if (message) {
|
|
317
|
+
console.log(message);
|
|
318
|
+
}
|
|
319
|
+
};
|
package/src/cli/main.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { errorText } from "../runtime/bridgeLog";
|
|
4
4
|
import { runCompile } from "./compile";
|
|
5
|
+
import { runLink } from "./link";
|
|
5
6
|
import { runSchema } from "./schema";
|
|
6
7
|
import { runValidate } from "./validate";
|
|
7
8
|
|
|
@@ -10,7 +11,8 @@ const USAGE = `serverk-bridge <command>
|
|
|
10
11
|
commands:
|
|
11
12
|
validate validate serverk.yml, assets, and driver wiring
|
|
12
13
|
schema write the serverk.yml JSON Schema for editor tooling
|
|
13
|
-
compile compile the bridge binary for amd64
|
|
14
|
+
compile compile the bridge binary for amd64
|
|
15
|
+
link use a local bridge checkout while developing
|
|
14
16
|
|
|
15
17
|
run "serverk-bridge <command> --help" for options`;
|
|
16
18
|
|
|
@@ -36,6 +38,12 @@ try {
|
|
|
36
38
|
break;
|
|
37
39
|
}
|
|
38
40
|
|
|
41
|
+
case "link": {
|
|
42
|
+
await runLink(args);
|
|
43
|
+
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
|
|
39
47
|
case undefined:
|
|
40
48
|
case "--help": {
|
|
41
49
|
console.log(USAGE);
|