@serverkgg/bridge 0.0.8 → 0.0.10
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 -3
- package/src/cli/validate.ts +2 -0
- package/src/context/bridgeContext.ts +17 -0
- package/src/context/index.ts +1 -0
- package/src/core/bridgeDownloadError.ts +10 -0
- package/src/core/bridgeHold.ts +12 -0
- package/src/core/bridgeKind.ts +3 -0
- package/src/core/bridgeProbeError.ts +16 -0
- package/src/core/bridgeSetup.ts +20 -0
- package/src/core/bridgeUserError.test.ts +23 -0
- package/src/core/bridgeUserError.ts +12 -0
- package/src/core/bridgeValue.test.ts +29 -0
- package/src/core/bridgeValue.ts +12 -0
- package/src/core/index.ts +5 -0
- package/src/guides/blocks.ts +8 -0
- package/src/guides/markdown.test.ts +18 -0
- package/src/guides/markdown.ts +7 -1
- package/src/manifest/index.ts +1 -0
- package/src/manifest/manifest.test.ts +132 -0
- package/src/manifest/manifest.ts +21 -0
- package/src/manifest/presence.ts +56 -0
- package/src/manifest/primitives.ts +6 -0
- package/src/modules/bridge.ts +65 -2
- package/src/modules/bridgeDriver.ts +4 -0
- package/src/modules/bridgeModule.ts +32 -3
- package/src/panel/bridgeDetail.ts +49 -0
- package/src/panel/bridgeLayout.ts +1 -0
- package/src/panel/bridgePanel.ts +30 -0
- package/src/panel/bridgeUploadMode.ts +4 -0
- package/src/panel/index.ts +2 -0
- package/src/probes/a2s.test.ts +71 -0
- package/src/probes/a2s.ts +38 -11
- package/src/protocol/bridgeEgress.ts +8 -1
- package/src/protocol/bridgeEvents.ts +4 -0
- package/src/protocol/bridgeFrame.ts +33 -1
- package/src/protocol/bridgeLimits.ts +12 -0
- package/src/protocol/bridgeManifest.ts +2 -0
- package/src/protocol/bridgeSetup.ts +97 -0
- package/src/protocol/index.ts +1 -0
- package/src/runtime/bridgeActions.ts +7 -0
- package/src/runtime/bridgeConfigReader.ts +12 -8
- package/src/runtime/bridgeContext.ts +28 -2
- package/src/runtime/bridgeDriver.test.ts +748 -3
- package/src/runtime/bridgeDriver.ts +198 -4
- package/src/runtime/bridgeEgress.ts +3 -0
- package/src/runtime/bridgeEvents.test.ts +96 -0
- package/src/runtime/bridgeEvents.ts +11 -6
- package/src/runtime/bridgeFiles.test.ts +625 -15
- package/src/runtime/bridgeFiles.ts +152 -45
- package/src/runtime/bridgeInstall.test.ts +118 -0
- package/src/runtime/bridgeInstall.ts +55 -0
- package/src/runtime/bridgeNet.ts +32 -3
- package/src/runtime/bridgePending.test.ts +148 -0
- package/src/runtime/bridgePending.ts +43 -0
- package/src/runtime/bridgeRegistry.test.ts +172 -1
- package/src/runtime/bridgeRegistry.ts +40 -5
- package/src/runtime/bridgeSecrets.test.ts +121 -0
- package/src/runtime/bridgeSecrets.ts +43 -0
- package/src/runtime/bridgeServer.test.ts +598 -0
- package/src/runtime/bridgeServer.ts +42 -3
- package/src/runtime/bridgeSetup.test.ts +189 -0
- package/src/runtime/bridgeSetup.ts +63 -0
- package/src/runtime/bridgeSignal.test.ts +114 -0
- package/src/runtime/bridgeSignal.ts +31 -0
- package/src/runtime/bridgeSupervisor.test.ts +111 -0
- package/src/runtime/bridgeSupervisor.ts +55 -5
- package/src/runtime/bridgeZip.ts +179 -58
- package/src/runtime/serve.ts +115 -4
- package/src/utils/index.ts +1 -0
- package/src/utils/stripAnsi.ts +12 -0
- package/src/wire/panel.test.ts +259 -0
- package/src/wire/panel.ts +72 -0
package/src/runtime/bridgeZip.ts
CHANGED
|
@@ -6,12 +6,26 @@ const CENTRAL_SIGNATURE = 0x02_01_4b_50;
|
|
|
6
6
|
|
|
7
7
|
const LOCAL_SIGNATURE = 0x04_03_4b_50;
|
|
8
8
|
|
|
9
|
+
const ZIP64_LOCATOR_SIGNATURE = 0x07_06_4b_50;
|
|
10
|
+
|
|
11
|
+
const ZIP64_EOCD_SIGNATURE = 0x06_06_4b_50;
|
|
12
|
+
|
|
9
13
|
const EOCD_MIN_LENGTH = 22;
|
|
10
14
|
|
|
11
15
|
const EOCD_SEARCH_LIMIT = 65_557;
|
|
12
16
|
|
|
17
|
+
const ZIP64_LOCATOR_LENGTH = 20;
|
|
18
|
+
|
|
19
|
+
const ZIP64_EOCD_MIN_LENGTH = 56;
|
|
20
|
+
|
|
21
|
+
const ZIP64_EXTRA_ID = 0x00_01;
|
|
22
|
+
|
|
23
|
+
const CENTRAL_HEADER_LENGTH = 46;
|
|
24
|
+
|
|
13
25
|
const LOCAL_HEADER_LENGTH = 30;
|
|
14
26
|
|
|
27
|
+
const SIZE_SENTINEL = 0xff_ff_ff_ff;
|
|
28
|
+
|
|
15
29
|
const STORED = 0;
|
|
16
30
|
|
|
17
31
|
const DEFLATED = 8;
|
|
@@ -20,7 +34,7 @@ const ENCRYPTED_FLAG = 0x1;
|
|
|
20
34
|
|
|
21
35
|
export const ZIP_ENTRY_LIMIT = 2048;
|
|
22
36
|
|
|
23
|
-
export const ZIP_TREE_ENTRY_LIMIT =
|
|
37
|
+
export const ZIP_TREE_ENTRY_LIMIT = 16_384;
|
|
24
38
|
|
|
25
39
|
const MAX_ENTRY_BYTES = 128 * 1024 * 1024;
|
|
26
40
|
|
|
@@ -30,14 +44,34 @@ const UNIX_MODE_SYMLINK = 0xa0_00;
|
|
|
30
44
|
|
|
31
45
|
export interface ZipEntry {
|
|
32
46
|
name: string;
|
|
33
|
-
data: Uint8Array;
|
|
34
47
|
symlink: boolean;
|
|
48
|
+
sizeBytes: number;
|
|
49
|
+
compressedSize: number;
|
|
50
|
+
method: number;
|
|
51
|
+
localOffset: number;
|
|
35
52
|
}
|
|
36
53
|
|
|
37
|
-
|
|
38
|
-
|
|
54
|
+
export interface ZipArchive {
|
|
55
|
+
entries: ZipEntry[];
|
|
56
|
+
read(entry: ZipEntry): Promise<Uint8Array>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const readRange = async (path: string, start: number, end: number) => {
|
|
60
|
+
return Buffer.from(await Bun.file(path).slice(start, end).arrayBuffer());
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const readOffset = (buffer: Buffer, offset: number) => {
|
|
64
|
+
const value = buffer.readBigUInt64LE(offset);
|
|
65
|
+
|
|
66
|
+
if (value > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
67
|
+
throw new Error("archive declares an offset this runtime cannot address");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return Number(value);
|
|
71
|
+
};
|
|
39
72
|
|
|
40
|
-
|
|
73
|
+
const findEndOfCentralDirectory = (buffer: Buffer) => {
|
|
74
|
+
for (let offset = buffer.length - EOCD_MIN_LENGTH; offset >= 0; offset--) {
|
|
41
75
|
if (buffer.readUInt32LE(offset) === EOCD_SIGNATURE) {
|
|
42
76
|
return offset;
|
|
43
77
|
}
|
|
@@ -46,88 +80,175 @@ const findEndOfCentralDirectory = (buffer: Buffer) => {
|
|
|
46
80
|
return -1;
|
|
47
81
|
};
|
|
48
82
|
|
|
49
|
-
|
|
50
|
-
|
|
83
|
+
interface CentralDirectory {
|
|
84
|
+
total: number;
|
|
85
|
+
offset: number;
|
|
86
|
+
sizeBytes: number;
|
|
87
|
+
}
|
|
51
88
|
|
|
52
|
-
|
|
53
|
-
|
|
89
|
+
const readZip64Directory = async (path: string, tail: Buffer, eocd: number): Promise<CentralDirectory | null> => {
|
|
90
|
+
const locator = eocd - ZIP64_LOCATOR_LENGTH;
|
|
91
|
+
|
|
92
|
+
if (locator < 0 || tail.readUInt32LE(locator) !== ZIP64_LOCATOR_SIGNATURE) {
|
|
93
|
+
return null;
|
|
54
94
|
}
|
|
55
95
|
|
|
56
|
-
const
|
|
57
|
-
const
|
|
96
|
+
const record = readOffset(tail, locator + 8);
|
|
97
|
+
const buffer = await readRange(path, record, record + ZIP64_EOCD_MIN_LENGTH);
|
|
58
98
|
|
|
59
|
-
if (
|
|
60
|
-
throw new Error(
|
|
99
|
+
if (buffer.length < ZIP64_EOCD_MIN_LENGTH || buffer.readUInt32LE(0) !== ZIP64_EOCD_SIGNATURE) {
|
|
100
|
+
throw new Error("archive has a corrupt zip64 central directory record");
|
|
61
101
|
}
|
|
62
102
|
|
|
63
|
-
|
|
103
|
+
return {
|
|
104
|
+
total: readOffset(buffer, 32),
|
|
105
|
+
sizeBytes: readOffset(buffer, 40),
|
|
106
|
+
offset: readOffset(buffer, 48),
|
|
107
|
+
};
|
|
108
|
+
};
|
|
64
109
|
|
|
65
|
-
|
|
110
|
+
interface Zip64Extended {
|
|
111
|
+
sizeBytes: number | null;
|
|
112
|
+
compressedSize: number | null;
|
|
113
|
+
localOffset: number | null;
|
|
114
|
+
}
|
|
66
115
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
116
|
+
const readZip64Extra = (extra: Buffer, sizeBytes: number, compressedSize: number, localOffset: number) => {
|
|
117
|
+
const extended: Zip64Extended = {
|
|
118
|
+
sizeBytes: null,
|
|
119
|
+
compressedSize: null,
|
|
120
|
+
localOffset: null,
|
|
121
|
+
};
|
|
71
122
|
|
|
72
|
-
|
|
73
|
-
const method = buffer.readUInt16LE(cursor + 10);
|
|
74
|
-
const compressedSize = buffer.readUInt32LE(cursor + 20);
|
|
75
|
-
const uncompressedSize = buffer.readUInt32LE(cursor + 24);
|
|
76
|
-
const nameLength = buffer.readUInt16LE(cursor + 28);
|
|
77
|
-
const extraLength = buffer.readUInt16LE(cursor + 30);
|
|
78
|
-
const commentLength = buffer.readUInt16LE(cursor + 32);
|
|
79
|
-
const externalAttributes = buffer.readUInt32LE(cursor + 38);
|
|
80
|
-
const localOffset = buffer.readUInt32LE(cursor + 42);
|
|
81
|
-
const name = buffer.subarray(cursor + 46, cursor + 46 + nameLength).toString("utf8");
|
|
82
|
-
const symlink = ((externalAttributes >>> 16) & UNIX_MODE_FORMAT_MASK) === UNIX_MODE_SYMLINK;
|
|
123
|
+
let cursor = 0;
|
|
83
124
|
|
|
84
|
-
|
|
125
|
+
while (cursor + 4 <= extra.length) {
|
|
126
|
+
const id = extra.readUInt16LE(cursor);
|
|
127
|
+
const length = extra.readUInt16LE(cursor + 2);
|
|
128
|
+
const body = extra.subarray(cursor + 4, cursor + 4 + length);
|
|
85
129
|
|
|
86
|
-
|
|
130
|
+
cursor += 4 + length;
|
|
131
|
+
|
|
132
|
+
if (id !== ZIP64_EXTRA_ID) {
|
|
87
133
|
continue;
|
|
88
134
|
}
|
|
89
135
|
|
|
90
|
-
|
|
91
|
-
|
|
136
|
+
let field = 0;
|
|
137
|
+
|
|
138
|
+
if (sizeBytes === SIZE_SENTINEL && field + 8 <= body.length) {
|
|
139
|
+
extended.sizeBytes = readOffset(body, field);
|
|
140
|
+
field += 8;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (compressedSize === SIZE_SENTINEL && field + 8 <= body.length) {
|
|
144
|
+
extended.compressedSize = readOffset(body, field);
|
|
145
|
+
field += 8;
|
|
92
146
|
}
|
|
93
147
|
|
|
94
|
-
if (localOffset
|
|
95
|
-
|
|
148
|
+
if (localOffset === SIZE_SENTINEL && field + 8 <= body.length) {
|
|
149
|
+
extended.localOffset = readOffset(body, field);
|
|
96
150
|
}
|
|
97
151
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const dataOffset = localOffset + LOCAL_HEADER_LENGTH + localNameLength + localExtraLength;
|
|
101
|
-
const compressed = buffer.subarray(dataOffset, dataOffset + compressedSize);
|
|
152
|
+
return extended;
|
|
153
|
+
}
|
|
102
154
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
name,
|
|
106
|
-
data: compressed,
|
|
107
|
-
symlink,
|
|
108
|
-
});
|
|
155
|
+
return extended;
|
|
156
|
+
};
|
|
109
157
|
|
|
110
|
-
|
|
111
|
-
|
|
158
|
+
export const openZip = async (path: string, maxEntries: number = ZIP_ENTRY_LIMIT): Promise<ZipArchive> => {
|
|
159
|
+
const size = Bun.file(path).size;
|
|
160
|
+
const tailStart = Math.max(0, size - (EOCD_SEARCH_LIMIT + ZIP64_LOCATOR_LENGTH));
|
|
161
|
+
const tail = await readRange(path, tailStart, size);
|
|
162
|
+
const eocd = tail.length < EOCD_MIN_LENGTH ? -1 : findEndOfCentralDirectory(tail);
|
|
163
|
+
|
|
164
|
+
if (eocd === -1) {
|
|
165
|
+
throw new Error("archive has no zip central directory");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const directory = (await readZip64Directory(path, tail, eocd)) ?? {
|
|
169
|
+
total: tail.readUInt16LE(eocd + 10),
|
|
170
|
+
sizeBytes: tail.readUInt32LE(eocd + 12),
|
|
171
|
+
offset: tail.readUInt32LE(eocd + 16),
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
if (directory.total > maxEntries) {
|
|
175
|
+
throw new Error(`archive has too many entries (${directory.total})`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const central = await readRange(path, directory.offset, directory.offset + directory.sizeBytes);
|
|
179
|
+
const entries: ZipEntry[] = [];
|
|
112
180
|
|
|
113
|
-
|
|
114
|
-
|
|
181
|
+
let cursor = 0;
|
|
182
|
+
|
|
183
|
+
for (let index = 0; index < directory.total; index++) {
|
|
184
|
+
if (cursor + CENTRAL_HEADER_LENGTH > central.length || central.readUInt32LE(cursor) !== CENTRAL_SIGNATURE) {
|
|
185
|
+
throw new Error("archive central directory is corrupt");
|
|
115
186
|
}
|
|
116
187
|
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
188
|
+
const flags = central.readUInt16LE(cursor + 8);
|
|
189
|
+
const method = central.readUInt16LE(cursor + 10);
|
|
190
|
+
const compressedSize = central.readUInt32LE(cursor + 20);
|
|
191
|
+
const sizeBytes = central.readUInt32LE(cursor + 24);
|
|
192
|
+
const nameLength = central.readUInt16LE(cursor + 28);
|
|
193
|
+
const extraLength = central.readUInt16LE(cursor + 30);
|
|
194
|
+
const commentLength = central.readUInt16LE(cursor + 32);
|
|
195
|
+
const externalAttributes = central.readUInt32LE(cursor + 38);
|
|
196
|
+
const localOffset = central.readUInt32LE(cursor + 42);
|
|
197
|
+
const nameStart = cursor + CENTRAL_HEADER_LENGTH;
|
|
198
|
+
const name = central.subarray(nameStart, nameStart + nameLength).toString("utf8");
|
|
199
|
+
const extra = central.subarray(nameStart + nameLength, nameStart + nameLength + extraLength);
|
|
200
|
+
const extended = readZip64Extra(extra, sizeBytes, compressedSize, localOffset);
|
|
201
|
+
|
|
202
|
+
cursor = nameStart + nameLength + extraLength + commentLength;
|
|
120
203
|
|
|
121
|
-
if (
|
|
122
|
-
|
|
204
|
+
if (name.endsWith("/") || (flags & ENCRYPTED_FLAG) !== 0) {
|
|
205
|
+
continue;
|
|
123
206
|
}
|
|
124
207
|
|
|
125
208
|
entries.push({
|
|
126
209
|
name,
|
|
127
|
-
|
|
128
|
-
|
|
210
|
+
symlink: ((externalAttributes >>> 16) & UNIX_MODE_FORMAT_MASK) === UNIX_MODE_SYMLINK,
|
|
211
|
+
sizeBytes: extended.sizeBytes ?? sizeBytes,
|
|
212
|
+
compressedSize: extended.compressedSize ?? compressedSize,
|
|
213
|
+
method,
|
|
214
|
+
localOffset: extended.localOffset ?? localOffset,
|
|
129
215
|
});
|
|
130
216
|
}
|
|
131
217
|
|
|
132
|
-
return
|
|
218
|
+
return {
|
|
219
|
+
entries,
|
|
220
|
+
|
|
221
|
+
async read(entry) {
|
|
222
|
+
if (entry.sizeBytes > MAX_ENTRY_BYTES || entry.compressedSize > MAX_ENTRY_BYTES) {
|
|
223
|
+
throw new Error(`archive entry "${entry.name}" is too large`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const header = await readRange(path, entry.localOffset, entry.localOffset + LOCAL_HEADER_LENGTH);
|
|
227
|
+
|
|
228
|
+
if (header.length < LOCAL_HEADER_LENGTH || header.readUInt32LE(0) !== LOCAL_SIGNATURE) {
|
|
229
|
+
throw new Error(`archive entry "${entry.name}" has a corrupt local header`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const dataOffset = entry.localOffset + LOCAL_HEADER_LENGTH + header.readUInt16LE(26) + header.readUInt16LE(28);
|
|
233
|
+
const compressed = await readRange(path, dataOffset, dataOffset + entry.compressedSize);
|
|
234
|
+
|
|
235
|
+
if (entry.method === STORED) {
|
|
236
|
+
return compressed;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (entry.method !== DEFLATED) {
|
|
240
|
+
throw new Error(`archive entry "${entry.name}" uses unsupported compression ${entry.method}`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const data = inflateRawSync(compressed, {
|
|
244
|
+
maxOutputLength: MAX_ENTRY_BYTES,
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (data.length !== entry.sizeBytes) {
|
|
248
|
+
throw new Error(`archive entry "${entry.name}" did not inflate to its declared size`);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return data;
|
|
252
|
+
},
|
|
253
|
+
};
|
|
133
254
|
};
|
package/src/runtime/serve.ts
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
import { chmod, chown, mkdir, rm } from "node:fs/promises";
|
|
2
|
-
import { BridgeDesired, BridgeRuntime } from "../core";
|
|
2
|
+
import { BridgeDesired, type BridgeInstallHold, BridgeRuntime, BridgeUserError, type LocalizedText } from "../core";
|
|
3
3
|
import type { BridgeDriver } from "../modules";
|
|
4
4
|
import {
|
|
5
5
|
BRIDGE_INSTALL_ERROR_LIMIT,
|
|
6
6
|
BRIDGE_VERSION,
|
|
7
7
|
type BridgeConfig,
|
|
8
|
+
type BridgePendingResult,
|
|
8
9
|
type BridgeSampleResult,
|
|
10
|
+
type BridgeSetupResult,
|
|
11
|
+
type BridgeSetupRuntime,
|
|
9
12
|
type BridgeStatus,
|
|
10
13
|
} from "../protocol";
|
|
11
14
|
import { configPath, readConfig, socketPath, statePath } from "./bridgeConfigReader";
|
|
12
15
|
import { createContext } from "./bridgeContext";
|
|
13
16
|
import { validateDriver } from "./bridgeDriver";
|
|
14
17
|
import { createEventRing } from "./bridgeEvents";
|
|
18
|
+
import { decideInstall, recountHold } from "./bridgeInstall";
|
|
15
19
|
import { errorText, log } from "./bridgeLog";
|
|
20
|
+
import { pendingResult, rejectedPending, unsupportedPending } from "./bridgePending";
|
|
16
21
|
import { createRegistry } from "./bridgeRegistry";
|
|
17
22
|
import { createServer } from "./bridgeServer";
|
|
23
|
+
import { failedSetup, setupSummaryOf, unsupportedSetup } from "./bridgeSetup";
|
|
18
24
|
import { readDesired, writeDesired } from "./bridgeState";
|
|
19
25
|
import { createSupervisor } from "./bridgeSupervisor";
|
|
20
26
|
|
|
@@ -64,6 +70,12 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
64
70
|
|
|
65
71
|
let installError: string | null = null;
|
|
66
72
|
|
|
73
|
+
let installErrorText: LocalizedText | null = null;
|
|
74
|
+
|
|
75
|
+
let installHold: BridgeInstallHold | null = null;
|
|
76
|
+
|
|
77
|
+
let setupRuntime: BridgeSetupRuntime | null = null;
|
|
78
|
+
|
|
67
79
|
const supervisor = createSupervisor({
|
|
68
80
|
cwd: config.cwd,
|
|
69
81
|
uid: config.gameUid,
|
|
@@ -93,6 +105,9 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
93
105
|
onEmit(event, payload) {
|
|
94
106
|
ring.emit(event, payload);
|
|
95
107
|
},
|
|
108
|
+
onSetup(runtime) {
|
|
109
|
+
setupRuntime = runtime;
|
|
110
|
+
},
|
|
96
111
|
});
|
|
97
112
|
|
|
98
113
|
const registry = createRegistry(driver, context, supervisor, ring);
|
|
@@ -105,8 +120,12 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
105
120
|
runtime: supervisor.runtime,
|
|
106
121
|
desired: current,
|
|
107
122
|
exitCode: supervisor.exitCode,
|
|
123
|
+
outOfMemory: supervisor.outOfMemory,
|
|
108
124
|
restarts: supervisor.restarts,
|
|
109
125
|
installError,
|
|
126
|
+
installErrorText,
|
|
127
|
+
installHold,
|
|
128
|
+
setup: setupSummaryOf(setupRuntime),
|
|
110
129
|
};
|
|
111
130
|
};
|
|
112
131
|
|
|
@@ -152,6 +171,20 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
152
171
|
return value;
|
|
153
172
|
};
|
|
154
173
|
|
|
174
|
+
const pending = async (): Promise<BridgePendingResult> => {
|
|
175
|
+
const module = driver.pending;
|
|
176
|
+
|
|
177
|
+
if (!module) {
|
|
178
|
+
return unsupportedPending();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const files = await module.list(context);
|
|
182
|
+
|
|
183
|
+
installHold = recountHold(installHold, files.length);
|
|
184
|
+
|
|
185
|
+
return pendingResult(module.staging, module.extensions, files, log);
|
|
186
|
+
};
|
|
187
|
+
|
|
155
188
|
const server = createServer({
|
|
156
189
|
socket: socketPath(config),
|
|
157
190
|
token: config.token,
|
|
@@ -260,6 +293,70 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
260
293
|
delivered: true,
|
|
261
294
|
};
|
|
262
295
|
},
|
|
296
|
+
async onPendingList() {
|
|
297
|
+
return await pending();
|
|
298
|
+
},
|
|
299
|
+
async onPendingAdd(input) {
|
|
300
|
+
const module = driver.pending;
|
|
301
|
+
|
|
302
|
+
if (!module) {
|
|
303
|
+
return unsupportedPending();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
try {
|
|
307
|
+
await module.add(context, input);
|
|
308
|
+
} catch (error) {
|
|
309
|
+
if (!(error instanceof BridgeUserError)) {
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
log.warn("pending upload rejected", {
|
|
314
|
+
error: error.message,
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
return rejectedPending(await pending());
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return await pending();
|
|
321
|
+
},
|
|
322
|
+
onSetupStatus() {
|
|
323
|
+
if (!driver.setup) {
|
|
324
|
+
return unsupportedSetup();
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
supported: true,
|
|
329
|
+
runtime: setupRuntime,
|
|
330
|
+
};
|
|
331
|
+
},
|
|
332
|
+
async onSetupSubmit(step, action, args): Promise<BridgeSetupResult> {
|
|
333
|
+
const module = driver.setup;
|
|
334
|
+
|
|
335
|
+
if (!module?.submit) {
|
|
336
|
+
return unsupportedSetup();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
await module.submit(context, step, action, args);
|
|
341
|
+
} catch (error) {
|
|
342
|
+
if (!(error instanceof BridgeUserError)) {
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
log.warn("setup submit rejected", {
|
|
347
|
+
step,
|
|
348
|
+
action,
|
|
349
|
+
error: error.message,
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
return failedSetup(setupRuntime, error.text);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
supported: true,
|
|
357
|
+
runtime: setupRuntime,
|
|
358
|
+
};
|
|
359
|
+
},
|
|
263
360
|
});
|
|
264
361
|
|
|
265
362
|
await chmod(socketPath(config), SOCKET_MODE);
|
|
@@ -303,12 +400,15 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
303
400
|
|
|
304
401
|
log("installing");
|
|
305
402
|
|
|
403
|
+
let decision = decideInstall(undefined, current);
|
|
404
|
+
|
|
306
405
|
try {
|
|
307
|
-
await driver.install.run(context);
|
|
406
|
+
decision = decideInstall(await driver.install.run(context), current);
|
|
308
407
|
|
|
309
408
|
log("install complete");
|
|
310
409
|
} catch (error) {
|
|
311
410
|
installError = errorText(error).slice(0, BRIDGE_INSTALL_ERROR_LIMIT);
|
|
411
|
+
installErrorText = error instanceof BridgeUserError ? error.text : null;
|
|
312
412
|
|
|
313
413
|
supervisor.setRuntime(BridgeRuntime.Crashed);
|
|
314
414
|
|
|
@@ -319,9 +419,20 @@ export const serve = async (driver: BridgeDriver) => {
|
|
|
319
419
|
return;
|
|
320
420
|
}
|
|
321
421
|
|
|
322
|
-
|
|
422
|
+
installHold = decision.hold;
|
|
423
|
+
|
|
424
|
+
supervisor.setRuntime(decision.runtime);
|
|
425
|
+
|
|
426
|
+
if (installHold) {
|
|
427
|
+
log("install held", {
|
|
428
|
+
reason: installHold.reason,
|
|
429
|
+
count: installHold.count,
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
323
434
|
|
|
324
|
-
if (
|
|
435
|
+
if (decision.start) {
|
|
325
436
|
try {
|
|
326
437
|
await supervisor.start();
|
|
327
438
|
} catch (error) {
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const ANSI_PATTERN = new RegExp(
|
|
2
|
+
[
|
|
3
|
+
"\\u001B\\][^\\u0007\\u001B]*(?:\\u0007|\\u001B\\\\)",
|
|
4
|
+
"\\u001B\\[[0-9;?]*[ -/]*[@-~]",
|
|
5
|
+
"\\u001B[@-Z\\\\-_]",
|
|
6
|
+
].join("|"),
|
|
7
|
+
"g",
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
export const stripAnsi = (line: string): string => {
|
|
11
|
+
return line.replace(ANSI_PATTERN, "");
|
|
12
|
+
};
|