@serverkgg/bridge 0.0.8 → 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.
Files changed (48) hide show
  1. package/package.json +3 -3
  2. package/src/cli/validate.ts +1 -0
  3. package/src/context/bridgeContext.ts +10 -0
  4. package/src/context/index.ts +1 -0
  5. package/src/core/bridgeDownloadError.ts +10 -0
  6. package/src/core/bridgeHold.ts +12 -0
  7. package/src/core/bridgeKind.ts +2 -0
  8. package/src/core/bridgeUserError.test.ts +23 -0
  9. package/src/core/bridgeUserError.ts +12 -0
  10. package/src/core/index.ts +3 -0
  11. package/src/manifest/index.ts +1 -0
  12. package/src/manifest/manifest.test.ts +85 -0
  13. package/src/manifest/manifest.ts +21 -0
  14. package/src/manifest/presence.ts +48 -0
  15. package/src/manifest/primitives.ts +6 -0
  16. package/src/modules/bridge.ts +45 -2
  17. package/src/modules/bridgeDriver.ts +2 -0
  18. package/src/modules/bridgeModule.ts +25 -3
  19. package/src/panel/bridgeDetail.ts +49 -0
  20. package/src/panel/bridgeLayout.ts +1 -0
  21. package/src/panel/bridgePanel.ts +30 -0
  22. package/src/panel/bridgeUploadMode.ts +4 -0
  23. package/src/panel/index.ts +2 -0
  24. package/src/protocol/bridgeEgress.ts +8 -1
  25. package/src/protocol/bridgeEvents.ts +4 -0
  26. package/src/protocol/bridgeFrame.ts +28 -1
  27. package/src/protocol/bridgeLimits.ts +10 -0
  28. package/src/runtime/bridgeActions.ts +7 -0
  29. package/src/runtime/bridgeDriver.test.ts +477 -2
  30. package/src/runtime/bridgeDriver.ts +116 -3
  31. package/src/runtime/bridgeEgress.ts +3 -0
  32. package/src/runtime/bridgeEvents.ts +7 -5
  33. package/src/runtime/bridgeFiles.test.ts +625 -15
  34. package/src/runtime/bridgeFiles.ts +152 -45
  35. package/src/runtime/bridgeInstall.test.ts +118 -0
  36. package/src/runtime/bridgeInstall.ts +55 -0
  37. package/src/runtime/bridgeNet.ts +32 -3
  38. package/src/runtime/bridgePending.test.ts +148 -0
  39. package/src/runtime/bridgePending.ts +43 -0
  40. package/src/runtime/bridgeRegistry.test.ts +134 -0
  41. package/src/runtime/bridgeRegistry.ts +26 -4
  42. package/src/runtime/bridgeServer.test.ts +338 -0
  43. package/src/runtime/bridgeServer.ts +25 -3
  44. package/src/runtime/bridgeSupervisor.ts +18 -0
  45. package/src/runtime/bridgeZip.ts +179 -58
  46. package/src/runtime/serve.ts +64 -4
  47. package/src/wire/panel.test.ts +166 -0
  48. package/src/wire/panel.ts +32 -0
@@ -8,6 +8,7 @@ import {
8
8
  BridgeKind,
9
9
  BridgeLayout,
10
10
  type BridgeManifest,
11
+ BridgeUploadMode,
11
12
  } from "@serverkgg/bridge/protocol";
12
13
  import { bridgeManifestSchema } from "./panel";
13
14
 
@@ -283,3 +284,168 @@ describe("the panel mirror", () => {
283
284
  ).toBe(false);
284
285
  });
285
286
  });
287
+
288
+ const detailManifest = (): BridgeManifest => ({
289
+ version: "1.0.0",
290
+ panel: {
291
+ tabs: [
292
+ {
293
+ id: "version",
294
+ title: text("Version"),
295
+ sections: [
296
+ {
297
+ layout: BridgeLayout.Form,
298
+ id: "version",
299
+ target: BridgeFormTarget.Variables,
300
+ reinstall: true,
301
+ fields: [
302
+ {
303
+ key: "MC_VERSION",
304
+ control: BridgeControl.Text,
305
+ label: text("Version"),
306
+ },
307
+ ],
308
+ clears: [
309
+ {
310
+ variable: "MODPACK",
311
+ warning: text("Applying this removes the modpack"),
312
+ },
313
+ ],
314
+ },
315
+ {
316
+ layout: BridgeLayout.Detail,
317
+ id: "modpack-status",
318
+ title: text("Running a modpack"),
319
+ module: "modpackStatus",
320
+ reinstall: true,
321
+ variable: "MODPACK",
322
+ confirm: BridgeConfirm.Strong,
323
+ related: {
324
+ tab: "modpacks",
325
+ label: text("Browse modpacks"),
326
+ },
327
+ actions: [
328
+ {
329
+ id: "update",
330
+ label: text("Update"),
331
+ confirm: BridgeConfirm.Strong,
332
+ },
333
+ ],
334
+ },
335
+ ],
336
+ },
337
+ ],
338
+ },
339
+ terminal: null,
340
+ modules: [
341
+ {
342
+ id: "modpackStatus",
343
+ kind: BridgeKind.Detail,
344
+ requiresRunning: false,
345
+ refreshSeconds: null,
346
+ pageSize: null,
347
+ dependsOn: [],
348
+ actions: [
349
+ BridgeAction.Read,
350
+ "update",
351
+ ],
352
+ },
353
+ ],
354
+ events: [],
355
+ });
356
+
357
+ describe("detail sections", () => {
358
+ test("round-trips a detail section and a clearing form", () => {
359
+ const source = detailManifest();
360
+
361
+ expect(bridgeManifestSchema.parse(source)).toEqual(source);
362
+ });
363
+
364
+ test("refuses a clear whose variable is not an env key", () => {
365
+ const source = detailManifest();
366
+ const [form] = source.panel?.tabs[0]?.sections ?? [];
367
+
368
+ if (form?.layout !== BridgeLayout.Form) {
369
+ throw new Error("fixture is missing its form section");
370
+ }
371
+
372
+ form.clears = [
373
+ {
374
+ variable: "mod pack",
375
+ warning: text("Broken"),
376
+ },
377
+ ];
378
+
379
+ expect(bridgeManifestSchema.safeParse(source).success).toBe(false);
380
+ });
381
+ });
382
+
383
+ const uploadManifest = (mode?: BridgeUploadMode): BridgeManifest => ({
384
+ version: "1.0.0",
385
+ panel: {
386
+ tabs: [
387
+ {
388
+ id: "modpacks",
389
+ title: text("Modpacks"),
390
+ sections: [
391
+ {
392
+ layout: BridgeLayout.Table,
393
+ id: "pending",
394
+ module: "pending",
395
+ columns: [
396
+ {
397
+ key: "name",
398
+ label: text("Name"),
399
+ },
400
+ ],
401
+ upload: {
402
+ label: text("Upload"),
403
+ extensions: [
404
+ "jar",
405
+ ],
406
+ staging: ".serverk-staging/pending-upload",
407
+ mode,
408
+ },
409
+ },
410
+ ],
411
+ },
412
+ ],
413
+ },
414
+ terminal: null,
415
+ modules: [
416
+ {
417
+ id: "pending",
418
+ kind: BridgeKind.Collection,
419
+ requiresRunning: false,
420
+ refreshSeconds: null,
421
+ pageSize: null,
422
+ dependsOn: [],
423
+ actions: [],
424
+ },
425
+ ],
426
+ events: [],
427
+ });
428
+
429
+ describe("the upload mirror", () => {
430
+ test("carries the file upload mode through unchanged", () => {
431
+ const source = uploadManifest(BridgeUploadMode.File);
432
+ const parsed = bridgeManifestSchema.parse(source);
433
+ const [section] = parsed.panel?.tabs[0]?.sections ?? [];
434
+
435
+ if (section?.layout !== BridgeLayout.Table) {
436
+ throw new Error("fixture is missing its table section");
437
+ }
438
+
439
+ expect(section.upload?.mode).toBe(BridgeUploadMode.File);
440
+ });
441
+
442
+ test("takes an upload that declares no mode", () => {
443
+ expect(bridgeManifestSchema.safeParse(uploadManifest()).success).toBe(true);
444
+ });
445
+
446
+ test("refuses an upload mode the platform does not know", () => {
447
+ const source = uploadManifest("stream" as BridgeUploadMode);
448
+
449
+ expect(bridgeManifestSchema.safeParse(source).success).toBe(false);
450
+ });
451
+ });
package/src/wire/panel.ts CHANGED
@@ -17,6 +17,7 @@ import {
17
17
  BridgeTerminalLevel,
18
18
  type BridgeTerminalManifest,
19
19
  type BridgeTerminalRuleManifest,
20
+ BridgeUploadMode,
20
21
  } from "@serverkgg/bridge/protocol";
21
22
  import { z } from "zod";
22
23
  import { zEnvKey } from "./zEnvKey";
@@ -27,6 +28,8 @@ const ACTION_FIELDS_LIMIT = 5;
27
28
 
28
29
  const SECTION_ACTIONS_LIMIT = 10;
29
30
 
31
+ const FORM_CLEARS_LIMIT = 8;
32
+
30
33
  const zKey = z
31
34
  .string()
32
35
  .min(1)
@@ -107,6 +110,16 @@ export const bridgeSectionActionSchema = z.object({
107
110
  fields: z.array(bridgeFieldSchema).max(ACTION_FIELDS_LIMIT).optional(),
108
111
  });
109
112
 
113
+ export const bridgeTabRefSchema = z.object({
114
+ tab: zBridgeId,
115
+ label: panelTextSchema,
116
+ });
117
+
118
+ export const bridgeFormClearSchema = z.object({
119
+ variable: zEnvKey,
120
+ warning: panelTextSchema,
121
+ });
122
+
110
123
  export const bridgeSectionAddSchema = z.object({
111
124
  label: panelTextSchema,
112
125
  placeholder: z.string().max(256).optional(),
@@ -116,6 +129,7 @@ export const bridgeSectionUploadSchema = z.object({
116
129
  label: panelTextSchema,
117
130
  extensions: z.array(z.string().min(1).max(16)).min(1).max(8),
118
131
  staging: z.string().min(1).max(128),
132
+ mode: z.enum(BridgeUploadMode).optional(),
119
133
  });
120
134
 
121
135
  export const bridgeActionsSectionSchema = z.object({
@@ -141,6 +155,23 @@ export const bridgeFormSectionSchema = z.object({
141
155
  confirm: z.enum(BridgeConfirm).optional(),
142
156
  confirmText: panelTextSchema.optional(),
143
157
  fields: z.array(bridgeFieldSchema).min(1).max(32),
158
+ clears: z.array(bridgeFormClearSchema).max(FORM_CLEARS_LIMIT).optional(),
159
+ visibleWhen: bridgeVisibleWhenSchema.optional(),
160
+ access: z.enum(BridgeAccess).optional(),
161
+ });
162
+
163
+ export const bridgeDetailSectionSchema = z.object({
164
+ layout: z.literal(BridgeLayout.Detail),
165
+ id: zBridgeId,
166
+ title: panelTextSchema.optional(),
167
+ module: zBridgeModuleId,
168
+ actions: z.array(bridgeSectionActionSchema).max(SECTION_ACTIONS_LIMIT).optional(),
169
+ reinstall: z.boolean().optional(),
170
+ variable: zEnvKey.optional(),
171
+ confirm: z.enum(BridgeConfirm).optional(),
172
+ confirmText: panelTextSchema.optional(),
173
+ related: bridgeTabRefSchema.optional(),
174
+ empty: panelTextSchema.optional(),
144
175
  visibleWhen: bridgeVisibleWhenSchema.optional(),
145
176
  access: z.enum(BridgeAccess).optional(),
146
177
  });
@@ -197,6 +228,7 @@ export const bridgeSectionSchema: z.ZodType<BridgeSection> = z.discriminatedUnio
197
228
  bridgeActionsSectionSchema,
198
229
  bridgeCardsSectionSchema,
199
230
  bridgeCatalogSectionSchema,
231
+ bridgeDetailSectionSchema,
200
232
  bridgeFormSectionSchema,
201
233
  bridgeTableSectionSchema,
202
234
  ]);