@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
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type BridgeSection,
|
|
9
9
|
type BridgeSectionAction,
|
|
10
10
|
type BridgeTab,
|
|
11
|
+
BridgeUploadMode,
|
|
11
12
|
type BridgeVisibleWhen,
|
|
12
13
|
} from "../panel";
|
|
13
14
|
import {
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
BRIDGE_EVENTS_LIMIT,
|
|
17
18
|
BRIDGE_EXTENSION_LENGTH_LIMIT,
|
|
18
19
|
BRIDGE_FIELD_OPTIONS_LIMIT,
|
|
20
|
+
BRIDGE_FORM_CLEARS_LIMIT,
|
|
19
21
|
BRIDGE_FORM_FIELDS_LIMIT,
|
|
20
22
|
BRIDGE_ID_LENGTH_LIMIT,
|
|
21
23
|
BRIDGE_KEY_LENGTH_LIMIT,
|
|
@@ -35,12 +37,15 @@ import {
|
|
|
35
37
|
} from "../protocol";
|
|
36
38
|
import { actionsOf } from "./bridgeActions";
|
|
37
39
|
|
|
40
|
+
const UPLOAD_MODES = new Set<string>(Object.values(BridgeUploadMode));
|
|
41
|
+
|
|
38
42
|
const RESERVED_MODULE_IDS = new Set([
|
|
39
43
|
"announce",
|
|
40
44
|
"backup",
|
|
41
45
|
"events",
|
|
42
46
|
"install",
|
|
43
47
|
"lifecycle",
|
|
48
|
+
"pending",
|
|
44
49
|
"query",
|
|
45
50
|
]);
|
|
46
51
|
|
|
@@ -259,6 +264,58 @@ const validateSection = (modules: Record<string, BridgePanelModule>, section: Br
|
|
|
259
264
|
countIn(section.fields.length, BRIDGE_FORM_FIELDS_LIMIT, "fields", where);
|
|
260
265
|
validateFields(modules, section.fields, where);
|
|
261
266
|
|
|
267
|
+
const clears = section.clears ?? [];
|
|
268
|
+
|
|
269
|
+
if (clears.length > 0 && section.target !== BridgeFormTarget.Variables) {
|
|
270
|
+
fail(`${where} clears variables but does not target variables`);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
countIn(clears.length, BRIDGE_FORM_CLEARS_LIMIT, "cleared variables", where);
|
|
274
|
+
|
|
275
|
+
const cleared = new Set<string>();
|
|
276
|
+
|
|
277
|
+
for (const clear of clears) {
|
|
278
|
+
if (cleared.has(clear.variable)) {
|
|
279
|
+
fail(`${where} clears "${clear.variable}" more than once`);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
cleared.add(clear.variable);
|
|
283
|
+
|
|
284
|
+
if (section.fields.some((field) => field.key === clear.variable)) {
|
|
285
|
+
fail(`${where} clears "${clear.variable}", which is one of its own fields`);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
validateText(clear.warning, `clear "${clear.variable}" warning`, where);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
case BridgeLayout.Detail: {
|
|
295
|
+
const module = moduleOf(modules, section.module, where);
|
|
296
|
+
|
|
297
|
+
if (module.kind !== BridgeKind.Detail) {
|
|
298
|
+
fail(`${where} references "${section.module}", which is not a detail module`);
|
|
299
|
+
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
countIn((section.actions ?? []).length, BRIDGE_SECTION_ACTIONS_LIMIT, "actions", where);
|
|
304
|
+
validateActions(modules, section.actions ?? [], where);
|
|
305
|
+
|
|
306
|
+
for (const action of section.actions ?? []) {
|
|
307
|
+
if (action.download) {
|
|
308
|
+
fail(`${where} declares action "${action.id}" as a download, which a detail cannot serve`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (!module.actions?.[action.id]) {
|
|
312
|
+
fail(`${where} declares action "${action.id}", which module "${section.module}" does not implement`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
validateText(section.confirmText, "confirm text", where);
|
|
317
|
+
validateText(section.related?.label, "related label", where);
|
|
318
|
+
|
|
262
319
|
return;
|
|
263
320
|
}
|
|
264
321
|
|
|
@@ -313,6 +370,10 @@ const validateSection = (modules: Record<string, BridgePanelModule>, section: Br
|
|
|
313
370
|
for (const extension of section.upload.extensions) {
|
|
314
371
|
lengthIn(extension, BRIDGE_EXTENSION_LENGTH_LIMIT, `upload extension "${extension}"`, where);
|
|
315
372
|
}
|
|
373
|
+
|
|
374
|
+
if (section.upload.mode !== undefined && !UPLOAD_MODES.has(section.upload.mode)) {
|
|
375
|
+
fail(`${where} declares an unknown upload mode "${section.upload.mode}"`);
|
|
376
|
+
}
|
|
316
377
|
}
|
|
317
378
|
}
|
|
318
379
|
|
|
@@ -346,6 +407,36 @@ const validateSection = (modules: Record<string, BridgePanelModule>, section: Br
|
|
|
346
407
|
}
|
|
347
408
|
};
|
|
348
409
|
|
|
410
|
+
const validatePending = (driver: BridgeDriver) => {
|
|
411
|
+
const pending = driver.pending;
|
|
412
|
+
|
|
413
|
+
if (!pending) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const where = "the pending module";
|
|
418
|
+
|
|
419
|
+
if (pending.kind !== BridgeKind.Pending) {
|
|
420
|
+
fail(`${where} declares kind "${pending.kind}", which is not "${BridgeKind.Pending}"`);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (pending.staging.length === 0) {
|
|
424
|
+
fail(`${where} declares no staging path`);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
lengthIn(pending.staging, BRIDGE_STAGING_LENGTH_LIMIT, "staging path", where);
|
|
428
|
+
|
|
429
|
+
if (pending.extensions.length === 0) {
|
|
430
|
+
fail(`${where} declares no extensions`);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
countIn(pending.extensions.length, BRIDGE_UPLOAD_EXTENSIONS_LIMIT, "extensions", where);
|
|
434
|
+
|
|
435
|
+
for (const extension of pending.extensions) {
|
|
436
|
+
lengthIn(extension, BRIDGE_EXTENSION_LENGTH_LIMIT, `extension "${extension}"`, where);
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
|
|
349
440
|
const validateTab = (modules: Record<string, BridgePanelModule>, tab: BridgeTab) => {
|
|
350
441
|
const sections = new Set<string>();
|
|
351
442
|
|
|
@@ -382,6 +473,8 @@ export const validateDriver = (driver: BridgeDriver) => {
|
|
|
382
473
|
|
|
383
474
|
countIn(emitted.size, BRIDGE_EVENTS_LIMIT, "event names", "the driver");
|
|
384
475
|
|
|
476
|
+
validatePending(driver);
|
|
477
|
+
|
|
385
478
|
for (const [id, module] of Object.entries(modules)) {
|
|
386
479
|
validateModuleId(id, "module");
|
|
387
480
|
|
|
@@ -401,7 +494,7 @@ export const validateDriver = (driver: BridgeDriver) => {
|
|
|
401
494
|
}
|
|
402
495
|
}
|
|
403
496
|
|
|
404
|
-
if (module.kind === BridgeKind.Collection) {
|
|
497
|
+
if (module.kind === BridgeKind.Collection || module.kind === BridgeKind.Detail) {
|
|
405
498
|
for (const action of Object.keys(module.actions ?? {})) {
|
|
406
499
|
validateModuleId(action, `module "${id}" action`);
|
|
407
500
|
}
|
|
@@ -429,6 +522,26 @@ export const validateDriver = (driver: BridgeDriver) => {
|
|
|
429
522
|
|
|
430
523
|
validateTab(modules, tab);
|
|
431
524
|
}
|
|
525
|
+
|
|
526
|
+
const declared = declaredVariables(driver);
|
|
527
|
+
|
|
528
|
+
for (const tab of driver.panel.tabs) {
|
|
529
|
+
for (const section of tab.sections) {
|
|
530
|
+
const where = `tab "${tab.id}" section "${section.id}"`;
|
|
531
|
+
|
|
532
|
+
if (section.layout === BridgeLayout.Detail && section.related && !tabs.has(section.related.tab)) {
|
|
533
|
+
fail(`${where} relates to tab "${section.related.tab}", which the panel does not declare`);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (section.layout === BridgeLayout.Form) {
|
|
537
|
+
for (const clear of section.clears ?? []) {
|
|
538
|
+
if (!declared.has(clear.variable)) {
|
|
539
|
+
fail(`${where} clears "${clear.variable}", which no variables form, catalog or detail declares`);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
432
545
|
};
|
|
433
546
|
|
|
434
547
|
const declaredVariables = (driver: BridgeDriver) => {
|
|
@@ -442,7 +555,7 @@ const declaredVariables = (driver: BridgeDriver) => {
|
|
|
442
555
|
}
|
|
443
556
|
}
|
|
444
557
|
|
|
445
|
-
if (section.layout === BridgeLayout.Catalog && section.variable) {
|
|
558
|
+
if ((section.layout === BridgeLayout.Catalog || section.layout === BridgeLayout.Detail) && section.variable) {
|
|
446
559
|
declared.add(section.variable);
|
|
447
560
|
}
|
|
448
561
|
}
|
|
@@ -461,7 +574,7 @@ export const validatePortActivation = (ports: ManifestPort[], driver: BridgeDriv
|
|
|
461
574
|
}
|
|
462
575
|
|
|
463
576
|
fail(
|
|
464
|
-
`port "${port.key}" activeWhen[${index}] names "${rule.variable}", which no variables form or
|
|
577
|
+
`port "${port.key}" activeWhen[${index}] names "${rule.variable}", which no variables form, catalog or detail declares`,
|
|
465
578
|
);
|
|
466
579
|
}
|
|
467
580
|
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
BridgeEgressMethod,
|
|
8
8
|
type BridgeEgressRequest,
|
|
9
9
|
type BridgeEgressResponse,
|
|
10
|
+
type BridgeHttpMethod,
|
|
10
11
|
} from "../protocol";
|
|
11
12
|
|
|
12
13
|
const CONNECT_RETRY_MS = 10_000;
|
|
@@ -39,6 +40,8 @@ export class BridgeEgressCallError extends Error {
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
export interface BridgeEgressCallOptions {
|
|
43
|
+
httpMethod?: BridgeHttpMethod;
|
|
44
|
+
body?: string;
|
|
42
45
|
headers?: Record<string, string>;
|
|
43
46
|
timeoutMs?: number;
|
|
44
47
|
cache?: boolean;
|
|
@@ -37,11 +37,13 @@ export const createEventRing = (events: BridgeEventsModule | undefined, supervis
|
|
|
37
37
|
continue;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const groups =
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
const groups =
|
|
41
|
+
match.groups || pattern.payload
|
|
42
|
+
? {
|
|
43
|
+
...pattern.payload,
|
|
44
|
+
...match.groups,
|
|
45
|
+
}
|
|
46
|
+
: null;
|
|
45
47
|
|
|
46
48
|
push(pattern.emit, groups);
|
|
47
49
|
}
|