@serverkgg/bridge 0.0.7 → 0.0.9
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 +4 -3
- package/src/cli/validate.ts +1 -0
- package/src/context/bridgeContext.ts +10 -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 +2 -0
- package/src/core/bridgeUserError.test.ts +23 -0
- package/src/core/bridgeUserError.ts +12 -0
- package/src/core/index.ts +3 -0
- package/src/manifest/index.ts +1 -0
- package/src/manifest/manifest.test.ts +85 -0
- package/src/manifest/manifest.ts +21 -0
- package/src/manifest/presence.ts +48 -0
- package/src/manifest/primitives.ts +6 -0
- package/src/modules/bridge.ts +45 -2
- package/src/modules/bridgeDriver.ts +2 -0
- package/src/modules/bridgeModule.ts +25 -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/protocol/bridgeEgress.ts +8 -1
- package/src/protocol/bridgeEvents.ts +4 -0
- package/src/protocol/bridgeFrame.ts +28 -1
- package/src/protocol/bridgeLimits.ts +10 -0
- package/src/runtime/bridgeActions.ts +7 -0
- package/src/runtime/bridgeDriver.test.ts +477 -2
- package/src/runtime/bridgeDriver.ts +116 -3
- package/src/runtime/bridgeEgress.ts +3 -0
- package/src/runtime/bridgeEvents.ts +7 -5
- 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/bridgePrivilege.test.ts +77 -0
- package/src/runtime/bridgePrivilege.ts +5 -3
- package/src/runtime/bridgeRegistry.test.ts +134 -0
- package/src/runtime/bridgeRegistry.ts +26 -4
- package/src/runtime/bridgeServer.test.ts +338 -0
- package/src/runtime/bridgeServer.ts +25 -3
- package/src/runtime/bridgeSupervisor.ts +18 -0
- package/src/runtime/bridgeZip.ts +179 -58
- package/src/runtime/serve.ts +64 -4
- package/src/wire/index.ts +2 -0
- package/src/wire/panel.test.ts +451 -0
- package/src/wire/panel.ts +295 -0
- package/src/wire/zEnvKey.ts +7 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serverkgg/bridge",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Serverk game bridge
|
|
3
|
+
"version": "0.0.9",
|
|
4
|
+
"description": "Serverk game bridge and driver runtime, wire protocol, manifest schema, and maintainer CLI",
|
|
5
5
|
"homepage": "https://serverk.gg",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
7
7
|
"repository": {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"./protocol": "./src/protocol/index.ts",
|
|
22
22
|
"./manifest": "./src/manifest/index.ts",
|
|
23
23
|
"./guides": "./src/guides/index.ts",
|
|
24
|
+
"./wire": "./src/wire/index.ts",
|
|
24
25
|
"./package.json": "./package.json"
|
|
25
26
|
},
|
|
26
27
|
"scripts": {
|
|
@@ -28,6 +29,6 @@
|
|
|
28
29
|
"test": "bun test --parallel"
|
|
29
30
|
},
|
|
30
31
|
"dependencies": {
|
|
31
|
-
"zod": "4.4
|
|
32
|
+
"zod": "4.5.4"
|
|
32
33
|
}
|
|
33
34
|
}
|
package/src/cli/validate.ts
CHANGED
|
@@ -229,6 +229,7 @@ const validateGamePackage = async (source: PackageSource, manifest: Manifest, di
|
|
|
229
229
|
console.log(
|
|
230
230
|
` driver: ${Object.keys(driver.modules ?? {}).length} panel module(s), ${driver.panel?.tabs.length ?? 0} tab(s)`,
|
|
231
231
|
);
|
|
232
|
+
console.log(` pending: ${driver.pending ? `declared (${driver.pending.extensions.length} extension(s))` : "none"}`);
|
|
232
233
|
reportEvents(driver);
|
|
233
234
|
reportActionTargets(driver);
|
|
234
235
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BridgeStream, BridgeValues } from "../core";
|
|
2
|
+
import type { BridgeHttpMethod } from "../protocol";
|
|
2
3
|
|
|
3
4
|
export interface BridgeServer {
|
|
4
5
|
code: string;
|
|
@@ -15,16 +16,22 @@ export interface BridgeFileEntry {
|
|
|
15
16
|
modifiedAt: string;
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
export type BridgeDigestAlgorithm = "sha1" | "sha256" | "sha512";
|
|
20
|
+
|
|
18
21
|
export interface BridgeDownloadOptions {
|
|
19
22
|
digest?: string;
|
|
20
23
|
sizeBytes?: number;
|
|
21
24
|
cache?: boolean;
|
|
25
|
+
quiet?: boolean;
|
|
26
|
+
timeoutMs?: number;
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
export interface BridgeExtractOptions {
|
|
25
30
|
extensions?: string[];
|
|
26
31
|
tree?: boolean;
|
|
27
32
|
select?: string;
|
|
33
|
+
selects?: string[];
|
|
34
|
+
exclude?: string[];
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
export interface BridgeFiles {
|
|
@@ -36,6 +43,7 @@ export interface BridgeFiles {
|
|
|
36
43
|
ensure(...paths: string[]): Promise<void>;
|
|
37
44
|
exists(path: string): Promise<boolean>;
|
|
38
45
|
size(path: string): Promise<number>;
|
|
46
|
+
digest(path: string, algorithm: BridgeDigestAlgorithm): Promise<string>;
|
|
39
47
|
download(path: string, url: string, options?: BridgeDownloadOptions): Promise<void>;
|
|
40
48
|
extract(path: string, destination: string, options?: BridgeExtractOptions): Promise<string[]>;
|
|
41
49
|
}
|
|
@@ -57,6 +65,8 @@ export interface BridgeCodecs {
|
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
export interface BridgeRequestOptions {
|
|
68
|
+
httpMethod?: BridgeHttpMethod;
|
|
69
|
+
body?: string;
|
|
60
70
|
headers?: Record<string, string>;
|
|
61
71
|
timeoutMs?: number;
|
|
62
72
|
cache?: boolean;
|
package/src/context/index.ts
CHANGED
package/src/core/bridgeKind.ts
CHANGED
|
@@ -4,11 +4,13 @@ export enum BridgeKind {
|
|
|
4
4
|
Backup = "backup",
|
|
5
5
|
Catalog = "catalog",
|
|
6
6
|
Collection = "collection",
|
|
7
|
+
Detail = "detail",
|
|
7
8
|
Terminal = "terminal",
|
|
8
9
|
Events = "events",
|
|
9
10
|
Install = "install",
|
|
10
11
|
Lifecycle = "lifecycle",
|
|
11
12
|
Options = "options",
|
|
13
|
+
Pending = "pending",
|
|
12
14
|
Preview = "preview",
|
|
13
15
|
Query = "query",
|
|
14
16
|
Settings = "settings",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { Bridge } from "../modules";
|
|
3
|
+
import { BridgeUserError } from "./bridgeUserError";
|
|
4
|
+
|
|
5
|
+
describe("BridgeUserError", () => {
|
|
6
|
+
const text = {
|
|
7
|
+
ar: "هذا مو الملف اللي ننتظره",
|
|
8
|
+
en: "this is not a file we are waiting for",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
test("reads as english in a log line and keeps both languages for the player", () => {
|
|
12
|
+
const error = new BridgeUserError(text);
|
|
13
|
+
|
|
14
|
+
expect(error).toBeInstanceOf(Error);
|
|
15
|
+
expect(error.name).toBe("BridgeUserError");
|
|
16
|
+
expect(error.message).toBe(text.en);
|
|
17
|
+
expect(error.text).toEqual(text);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("is the class a driver reaches through the published namespace", () => {
|
|
21
|
+
expect(new Bridge.UserError(text)).toBeInstanceOf(BridgeUserError);
|
|
22
|
+
});
|
|
23
|
+
});
|
package/src/core/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export * from "./bridgeAction";
|
|
2
|
+
export * from "./bridgeDownloadError";
|
|
2
3
|
export * from "./bridgeFailure";
|
|
4
|
+
export * from "./bridgeHold";
|
|
3
5
|
export * from "./bridgeId";
|
|
4
6
|
export * from "./bridgeKind";
|
|
5
7
|
export * from "./bridgeNetError";
|
|
@@ -7,4 +9,5 @@ export * from "./bridgePort";
|
|
|
7
9
|
export * from "./bridgeRuntime";
|
|
8
10
|
export * from "./bridgeSecretError";
|
|
9
11
|
export * from "./bridgeStream";
|
|
12
|
+
export * from "./bridgeUserError";
|
|
10
13
|
export * from "./bridgeValue";
|
package/src/manifest/index.ts
CHANGED
|
@@ -586,3 +586,88 @@ describe("packageSchema", () => {
|
|
|
586
586
|
expect(result.error && z.prettifyError(result.error)).toContain('tag "start" is not declared in guideTags');
|
|
587
587
|
});
|
|
588
588
|
});
|
|
589
|
+
|
|
590
|
+
describe("presence", () => {
|
|
591
|
+
test("is optional, so a game that declares none parses", () => {
|
|
592
|
+
const result = manifestSchema.safeParse(base());
|
|
593
|
+
|
|
594
|
+
expect(result.success).toBe(true);
|
|
595
|
+
expect(result.success && result.data.presence).toBeUndefined();
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
test("defaults the name key to player and the field list to empty", () => {
|
|
599
|
+
const result = manifestSchema.safeParse({
|
|
600
|
+
...base(),
|
|
601
|
+
presence: {},
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
expect(result.success).toBe(true);
|
|
605
|
+
expect(result.success && result.data.presence?.name).toBe("player");
|
|
606
|
+
expect(result.success && result.data.presence?.fields).toEqual([]);
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
test("accepts an avatar template and localized fields", () => {
|
|
610
|
+
const result = manifestSchema.safeParse({
|
|
611
|
+
...base(),
|
|
612
|
+
presence: {
|
|
613
|
+
name: "player",
|
|
614
|
+
id: "uuid",
|
|
615
|
+
avatar: "https://mc-heads.net/avatar/{skin}/128",
|
|
616
|
+
fields: [
|
|
617
|
+
{
|
|
618
|
+
key: "platform",
|
|
619
|
+
label: text("Platform"),
|
|
620
|
+
},
|
|
621
|
+
],
|
|
622
|
+
},
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
expect(result.success).toBe(true);
|
|
626
|
+
expect(result.success && result.data.presence?.fields[0]?.inline).toBe(true);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
test("refuses an avatar template that is not https", () => {
|
|
630
|
+
const result = manifestSchema.safeParse({
|
|
631
|
+
...base(),
|
|
632
|
+
presence: {
|
|
633
|
+
avatar: "http://mc-heads.net/avatar/{skin}/128",
|
|
634
|
+
},
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
expect(result.success).toBe(false);
|
|
638
|
+
expect(result.error && z.prettifyError(result.error)).toContain("must be an https url template");
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
test("refuses a payload key that could never be a capture group", () => {
|
|
642
|
+
const result = manifestSchema.safeParse({
|
|
643
|
+
...base(),
|
|
644
|
+
presence: {
|
|
645
|
+
name: "player name",
|
|
646
|
+
},
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
expect(result.success).toBe(false);
|
|
650
|
+
expect(result.error && z.prettifyError(result.error)).toContain("must be a valid capture group name");
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
test("refuses the same field declared twice", () => {
|
|
654
|
+
const result = manifestSchema.safeParse({
|
|
655
|
+
...base(),
|
|
656
|
+
presence: {
|
|
657
|
+
fields: [
|
|
658
|
+
{
|
|
659
|
+
key: "platform",
|
|
660
|
+
label: text("Platform"),
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
key: "platform",
|
|
664
|
+
label: text("Platform again"),
|
|
665
|
+
},
|
|
666
|
+
],
|
|
667
|
+
},
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
expect(result.success).toBe(false);
|
|
671
|
+
expect(result.error && z.prettifyError(result.error)).toContain('"platform" is declared more than once');
|
|
672
|
+
});
|
|
673
|
+
});
|
package/src/manifest/manifest.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { GameCategory } from "./category";
|
|
|
6
6
|
import { type GuideEntry, type GuideTag, guideEntrySchema, guideTagSchema } from "./guide";
|
|
7
7
|
import { IMAGE_NAMESPACE } from "./image";
|
|
8
8
|
import { localizedText } from "./localized";
|
|
9
|
+
import { type ManifestPresence, manifestPresenceSchema } from "./presence";
|
|
9
10
|
import {
|
|
10
11
|
HOST_RANGE_MAX_SIZE,
|
|
11
12
|
zAssetPath,
|
|
@@ -205,6 +206,24 @@ const duplicateIssues = <Item>(
|
|
|
205
206
|
}));
|
|
206
207
|
};
|
|
207
208
|
|
|
209
|
+
const presenceIssues = (presence: ManifestPresence | undefined): CheckIssue[] => {
|
|
210
|
+
if (!presence) {
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return duplicateIssues(
|
|
215
|
+
presence.fields,
|
|
216
|
+
(field) => field.key,
|
|
217
|
+
(index) => [
|
|
218
|
+
"presence",
|
|
219
|
+
"fields",
|
|
220
|
+
index,
|
|
221
|
+
"key",
|
|
222
|
+
],
|
|
223
|
+
(key) => `"${key}" is declared more than once`,
|
|
224
|
+
);
|
|
225
|
+
};
|
|
226
|
+
|
|
208
227
|
const hostRangesOverlap = (a: ManifestPort, b: ManifestPort) => {
|
|
209
228
|
return a.hostRange.min <= b.hostRange.max && b.hostRange.min <= a.hostRange.max;
|
|
210
229
|
};
|
|
@@ -355,6 +374,7 @@ export const manifestSchema = z
|
|
|
355
374
|
reset: manifestResetSchema.prefault({}),
|
|
356
375
|
secrets: z.array(manifestSecretSchema).max(16).default([]),
|
|
357
376
|
files: manifestFilesSchema.prefault({}),
|
|
377
|
+
presence: manifestPresenceSchema.optional(),
|
|
358
378
|
})
|
|
359
379
|
.check((ctx) => {
|
|
360
380
|
if (ctx.issues.length > 0) {
|
|
@@ -410,6 +430,7 @@ export const manifestSchema = z
|
|
|
410
430
|
(key) => `"${key}" already has a note`,
|
|
411
431
|
),
|
|
412
432
|
...guideIssues(manifest.guideTags, manifest.guides),
|
|
433
|
+
...presenceIssues(manifest.presence),
|
|
413
434
|
);
|
|
414
435
|
});
|
|
415
436
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { localizedText } from "./localized";
|
|
3
|
+
import { zPayloadKey } from "./primitives";
|
|
4
|
+
|
|
5
|
+
export const PRESENCE_FIELDS_LIMIT = 6;
|
|
6
|
+
|
|
7
|
+
export const PRESENCE_AVATAR_LENGTH_LIMIT = 300;
|
|
8
|
+
|
|
9
|
+
export const manifestPresenceFieldSchema = z.object({
|
|
10
|
+
key: zPayloadKey,
|
|
11
|
+
label: localizedText(32),
|
|
12
|
+
inline: z.boolean().default(true),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export type ManifestPresenceField = z.infer<typeof manifestPresenceFieldSchema>;
|
|
16
|
+
|
|
17
|
+
export const manifestPresenceSchema = z.object({
|
|
18
|
+
name: zPayloadKey.default("player"),
|
|
19
|
+
id: zPayloadKey.optional(),
|
|
20
|
+
avatar: z
|
|
21
|
+
.string()
|
|
22
|
+
.max(PRESENCE_AVATAR_LENGTH_LIMIT)
|
|
23
|
+
.regex(/^https:\/\//, "must be an https url template")
|
|
24
|
+
.optional(),
|
|
25
|
+
fields: z.array(manifestPresenceFieldSchema).max(PRESENCE_FIELDS_LIMIT).default([]),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export type ManifestPresence = z.infer<typeof manifestPresenceSchema>;
|
|
29
|
+
|
|
30
|
+
export const PRESENCE_PLACEHOLDER = /\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
31
|
+
|
|
32
|
+
export const presencePlaceholders = (template: string): string[] => {
|
|
33
|
+
PRESENCE_PLACEHOLDER.lastIndex = 0;
|
|
34
|
+
|
|
35
|
+
const names: string[] = [];
|
|
36
|
+
|
|
37
|
+
let match = PRESENCE_PLACEHOLDER.exec(template);
|
|
38
|
+
|
|
39
|
+
while (match) {
|
|
40
|
+
if (match[1]) {
|
|
41
|
+
names.push(match[1]);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
match = PRESENCE_PLACEHOLDER.exec(template);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return names;
|
|
48
|
+
};
|
|
@@ -26,6 +26,12 @@ export const zEnvKey = z
|
|
|
26
26
|
.max(32)
|
|
27
27
|
.regex(/^[A-Z][A-Z0-9_]*$/, "must be SCREAMING_SNAKE_CASE, starting with a letter");
|
|
28
28
|
|
|
29
|
+
export const zPayloadKey = z
|
|
30
|
+
.string()
|
|
31
|
+
.min(1)
|
|
32
|
+
.max(64)
|
|
33
|
+
.regex(/^[A-Za-z_][A-Za-z0-9_]*$/, "must be a valid capture group name, starting with a letter or underscore");
|
|
34
|
+
|
|
29
35
|
export const zImageReference = z.templateLiteral([
|
|
30
36
|
`${IMAGE_NAMESPACE}/`,
|
|
31
37
|
zSlug,
|
package/src/modules/bridge.ts
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
1
|
import type { BridgeContext, BridgeExecResult, BridgeFileEntry, BridgeReply } from "../context";
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type {
|
|
3
|
+
BridgeInstallHold,
|
|
4
|
+
BridgeInstallOutcome,
|
|
5
|
+
BridgeOption,
|
|
6
|
+
BridgeRow,
|
|
7
|
+
BridgeValue,
|
|
8
|
+
BridgeValues,
|
|
9
|
+
LocalizedText,
|
|
10
|
+
} from "../core";
|
|
11
|
+
import { BridgeUserError } from "../core";
|
|
12
|
+
import type {
|
|
13
|
+
BridgeDetail,
|
|
14
|
+
BridgeDetailBadge,
|
|
15
|
+
BridgeDetailLink,
|
|
16
|
+
BridgeDetailOutcome,
|
|
17
|
+
BridgeDetailStat,
|
|
18
|
+
BridgeField,
|
|
19
|
+
BridgeFormClear,
|
|
20
|
+
BridgePanel,
|
|
21
|
+
BridgeSection,
|
|
22
|
+
BridgeSectionAction,
|
|
23
|
+
BridgeTab,
|
|
24
|
+
BridgeTabRef,
|
|
25
|
+
BridgeUploadMode,
|
|
26
|
+
} from "../panel";
|
|
4
27
|
import type {
|
|
5
28
|
BridgeCatalogEntry,
|
|
6
29
|
BridgeCatalogFacet,
|
|
@@ -9,6 +32,7 @@ import type {
|
|
|
9
32
|
BridgeCatalogProvider,
|
|
10
33
|
BridgeCatalogQuery,
|
|
11
34
|
} from "../protocol/bridgeCatalog";
|
|
35
|
+
import type { BridgePendingFile } from "../protocol/bridgeFrame";
|
|
12
36
|
import type { BridgePreview } from "../protocol/bridgePreview";
|
|
13
37
|
import type { BridgeTerminalArg, BridgeTerminalCommand, BridgeTerminalRule } from "../terminal";
|
|
14
38
|
import type { BridgeDriver } from "./bridgeDriver";
|
|
@@ -18,11 +42,14 @@ import type {
|
|
|
18
42
|
BridgeBackupModule,
|
|
19
43
|
BridgeCatalogModule,
|
|
20
44
|
BridgeCollectionModule,
|
|
45
|
+
BridgeDetailAction,
|
|
46
|
+
BridgeDetailModule,
|
|
21
47
|
BridgeEventPattern,
|
|
22
48
|
BridgeEventsModule,
|
|
23
49
|
BridgeInstallModule,
|
|
24
50
|
BridgeLifecycleModule,
|
|
25
51
|
BridgeOptionsModule,
|
|
52
|
+
BridgePendingModule,
|
|
26
53
|
BridgePreviewModule,
|
|
27
54
|
BridgeQueryModule,
|
|
28
55
|
BridgeRowAction,
|
|
@@ -45,17 +72,29 @@ export namespace Bridge {
|
|
|
45
72
|
export type CatalogQuery = BridgeCatalogQuery;
|
|
46
73
|
export type Collection<Row extends BridgeRow = BridgeRow> = BridgeCollectionModule<Row>;
|
|
47
74
|
export type Context = BridgeContext;
|
|
75
|
+
export type Detail = BridgeDetailModule;
|
|
76
|
+
export type DetailAction = BridgeDetailAction;
|
|
77
|
+
export type DetailBadge = BridgeDetailBadge;
|
|
78
|
+
export type DetailLink = BridgeDetailLink;
|
|
79
|
+
export type DetailOutcome = BridgeDetailOutcome;
|
|
80
|
+
export type DetailResult = BridgeDetail;
|
|
81
|
+
export type DetailStat = BridgeDetailStat;
|
|
48
82
|
export type Driver = BridgeDriver;
|
|
49
83
|
export type EventPattern = BridgeEventPattern;
|
|
50
84
|
export type Events = BridgeEventsModule;
|
|
51
85
|
export type ExecResult = BridgeExecResult;
|
|
52
86
|
export type Field = BridgeField;
|
|
53
87
|
export type FileEntry = BridgeFileEntry;
|
|
88
|
+
export type FormClear = BridgeFormClear;
|
|
54
89
|
export type Install = BridgeInstallModule;
|
|
90
|
+
export type InstallHold = BridgeInstallHold;
|
|
91
|
+
export type InstallOutcome = BridgeInstallOutcome;
|
|
55
92
|
export type Lifecycle = BridgeLifecycleModule;
|
|
56
93
|
export type Option = BridgeOption;
|
|
57
94
|
export type Options = BridgeOptionsModule;
|
|
58
95
|
export type Panel = BridgePanel;
|
|
96
|
+
export type Pending = BridgePendingModule;
|
|
97
|
+
export type PendingFile = BridgePendingFile;
|
|
59
98
|
export type Preview = BridgePreviewModule;
|
|
60
99
|
export type PreviewResult = BridgePreview;
|
|
61
100
|
export type Query = BridgeQueryModule;
|
|
@@ -72,6 +111,10 @@ export namespace Bridge {
|
|
|
72
111
|
export type TerminalCommand = BridgeTerminalCommand;
|
|
73
112
|
export type TerminalRule = BridgeTerminalRule;
|
|
74
113
|
export type Tab = BridgeTab;
|
|
114
|
+
export type TabRef = BridgeTabRef;
|
|
115
|
+
export type UploadMode = BridgeUploadMode;
|
|
116
|
+
export const UserError = BridgeUserError;
|
|
117
|
+
export type UserError = BridgeUserError;
|
|
75
118
|
export type Text = LocalizedText;
|
|
76
119
|
export type Value = BridgeValue;
|
|
77
120
|
export type Values = BridgeValues;
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
BridgeInstallModule,
|
|
7
7
|
BridgeLifecycleModule,
|
|
8
8
|
BridgePanelModule,
|
|
9
|
+
BridgePendingModule,
|
|
9
10
|
BridgeQueryModule,
|
|
10
11
|
BridgeTerminalModule,
|
|
11
12
|
} from "./bridgeModule";
|
|
@@ -17,6 +18,7 @@ export interface BridgeDriver {
|
|
|
17
18
|
query?: BridgeQueryModule;
|
|
18
19
|
backup?: BridgeBackupModule;
|
|
19
20
|
announce?: BridgeAnnounceModule;
|
|
21
|
+
pending?: BridgePendingModule;
|
|
20
22
|
terminal?: BridgeTerminalModule;
|
|
21
23
|
panel?: BridgePanel;
|
|
22
24
|
modules?: Record<string, BridgePanelModule>;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { BridgeContext } from "../context";
|
|
2
|
-
import type { BridgeKind, BridgeOption, BridgeRow, BridgeStream, BridgeValues } from "../core";
|
|
2
|
+
import type { BridgeInstallOutcome, BridgeKind, BridgeOption, BridgeRow, BridgeStream, BridgeValues } from "../core";
|
|
3
|
+
import type { BridgeDetail, BridgeDetailOutcome } from "../panel";
|
|
3
4
|
import type { BridgeCatalogEntry, BridgeCatalogPage, BridgeCatalogQuery } from "../protocol/bridgeCatalog";
|
|
4
|
-
import type { BridgeDescribeResult } from "../protocol/bridgeFrame";
|
|
5
|
+
import type { BridgeDescribeResult, BridgePendingFile } from "../protocol/bridgeFrame";
|
|
5
6
|
import type { BridgePreview } from "../protocol/bridgePreview";
|
|
6
7
|
import type { BridgeTerminalCommand, BridgeTerminalRule } from "../terminal";
|
|
7
8
|
|
|
@@ -9,7 +10,7 @@ export type BridgeDescription = Omit<BridgeDescribeResult, "supported">;
|
|
|
9
10
|
|
|
10
11
|
export interface BridgeInstallModule {
|
|
11
12
|
kind: BridgeKind.Install;
|
|
12
|
-
run(context: BridgeContext): Promise<
|
|
13
|
+
run(context: BridgeContext): Promise<BridgeInstallOutcome | undefined>;
|
|
13
14
|
describe?(context: BridgeContext): Promise<BridgeDescription>;
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -34,6 +35,14 @@ export interface BridgeBackupModule {
|
|
|
34
35
|
release?(context: BridgeContext): Promise<void>;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
export interface BridgePendingModule {
|
|
39
|
+
kind: BridgeKind.Pending;
|
|
40
|
+
staging: string;
|
|
41
|
+
extensions: string[];
|
|
42
|
+
list(context: BridgeContext): Promise<BridgePendingFile[]>;
|
|
43
|
+
add(context: BridgeContext, input: string): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
|
|
37
46
|
export interface BridgeSample {
|
|
38
47
|
online: number | null;
|
|
39
48
|
max: number | null;
|
|
@@ -49,6 +58,7 @@ export interface BridgeEventPattern {
|
|
|
49
58
|
match: RegExp;
|
|
50
59
|
emit: string;
|
|
51
60
|
stream?: BridgeStream;
|
|
61
|
+
payload?: BridgeValues;
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
export interface BridgeEventsModule {
|
|
@@ -104,6 +114,16 @@ export interface BridgeCollectionModule<Row extends BridgeRow = BridgeRow> {
|
|
|
104
114
|
actions?: Record<string, BridgeRowAction<Row>>;
|
|
105
115
|
}
|
|
106
116
|
|
|
117
|
+
export type BridgeDetailAction = (context: BridgeContext, args: BridgeValues) => Promise<BridgeDetailOutcome | null>;
|
|
118
|
+
|
|
119
|
+
export interface BridgeDetailModule {
|
|
120
|
+
kind: BridgeKind.Detail;
|
|
121
|
+
requiresRunning?: boolean;
|
|
122
|
+
refreshSeconds?: number;
|
|
123
|
+
read(context: BridgeContext): Promise<BridgeDetail | null>;
|
|
124
|
+
actions?: Record<string, BridgeDetailAction>;
|
|
125
|
+
}
|
|
126
|
+
|
|
107
127
|
export interface BridgeCatalogModule {
|
|
108
128
|
kind: BridgeKind.Catalog;
|
|
109
129
|
pageSize?: number;
|
|
@@ -118,6 +138,7 @@ export type BridgePanelModule =
|
|
|
118
138
|
| BridgeActionsModule
|
|
119
139
|
| BridgeCatalogModule
|
|
120
140
|
| BridgeCollectionModule
|
|
141
|
+
| BridgeDetailModule
|
|
121
142
|
| BridgeOptionsModule
|
|
122
143
|
| BridgePreviewModule
|
|
123
144
|
| BridgeSettingsModule;
|
|
@@ -130,4 +151,5 @@ export type BridgeModule =
|
|
|
130
151
|
| BridgeInstallModule
|
|
131
152
|
| BridgeLifecycleModule
|
|
132
153
|
| BridgePanelModule
|
|
154
|
+
| BridgePendingModule
|
|
133
155
|
| BridgeQueryModule;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { BridgeValue, LocalizedText } from "../core";
|
|
2
|
+
|
|
3
|
+
export enum BridgeDetailTone {
|
|
4
|
+
Neutral = "neutral",
|
|
5
|
+
Success = "success",
|
|
6
|
+
Warning = "warning",
|
|
7
|
+
Danger = "danger",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export enum BridgeDetailFormat {
|
|
11
|
+
Bytes = "bytes",
|
|
12
|
+
Date = "date",
|
|
13
|
+
Number = "number",
|
|
14
|
+
Text = "text",
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface BridgeDetailBadge {
|
|
18
|
+
label: LocalizedText;
|
|
19
|
+
tone: BridgeDetailTone;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface BridgeDetailStat {
|
|
23
|
+
key: string;
|
|
24
|
+
label: LocalizedText;
|
|
25
|
+
value: BridgeValue;
|
|
26
|
+
format: BridgeDetailFormat;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface BridgeDetailLink {
|
|
30
|
+
label: LocalizedText;
|
|
31
|
+
url: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface BridgeDetail {
|
|
35
|
+
id: string;
|
|
36
|
+
title: string;
|
|
37
|
+
subtitle: string | null;
|
|
38
|
+
description: string | null;
|
|
39
|
+
image: string | null;
|
|
40
|
+
badges: BridgeDetailBadge[];
|
|
41
|
+
stats: BridgeDetailStat[];
|
|
42
|
+
links: BridgeDetailLink[];
|
|
43
|
+
stale: boolean;
|
|
44
|
+
actions: string[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface BridgeDetailOutcome {
|
|
48
|
+
variables: Record<string, string> | null;
|
|
49
|
+
}
|