@fonderie/vue-admin-screens 0.6.0 → 0.8.0

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/dist/index.js CHANGED
@@ -1,23 +1,52 @@
1
1
  // src/screens/AdminShell.ts
2
2
  import { ConfigEditorScreen, ConfigListScreen } from "@fonderie/vue-config-admin-screens";
3
3
  import { TemplateEditorScreen, TemplateListScreen } from "@fonderie/vue-courier-admin-screens";
4
- import { computed as computed2, defineComponent as defineComponent12, h as h13, ref as ref5 } from "vue";
4
+ import { computed as computed2, defineComponent as defineComponent13, h as h14, ref as ref5 } from "vue";
5
5
 
6
6
  // src/styles.ts
7
+ var t = {
8
+ text: "var(--fonderie-text,#171717)",
9
+ muted: "var(--fonderie-text-muted,#5c5c5c)",
10
+ bg: "var(--fonderie-bg,#fafafa)",
11
+ surface: "var(--fonderie-surface,#fff)",
12
+ surfaceAlt: "var(--fonderie-surface-alt,#fafafa)",
13
+ border: "var(--fonderie-border,#e0e0e0)",
14
+ borderLight: "var(--fonderie-border-light,#f5f5f5)",
15
+ accent: "var(--fonderie-accent,#00d294)",
16
+ accentStrong: "var(--fonderie-accent-strong,#009767)",
17
+ warning: "var(--fonderie-warning,#f5a623)",
18
+ danger: "var(--fonderie-danger,#e00)",
19
+ font: 'var(--fonderie-font,Inter,"Inter Fallback",-apple-system,BlinkMacSystemFont,"Helvetica Neue",system-ui,sans-serif)',
20
+ mono: 'var(--fonderie-mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace)',
21
+ radius: "var(--fonderie-radius,4px)",
22
+ radiusLg: "var(--fonderie-radius-lg,8px)",
23
+ trackingDisplay: "var(--fonderie-tracking-display,-0.05em)",
24
+ shadowCard: "var(--fonderie-shadow-card,0 2px 3px 0 rgba(0,0,0,.05))"
25
+ };
7
26
  var styles = {
8
27
  shell: {
9
28
  display: "flex",
10
29
  minHeight: "100vh",
11
- fontFamily: "system-ui, sans-serif",
12
- color: "#111"
30
+ fontFamily: t.font,
31
+ color: t.text,
32
+ background: t.bg
33
+ },
34
+ // The sidebar sits on the raised surface against the page canvas, which is
35
+ // what separates the two without a heavy rule between them.
36
+ nav: {
37
+ width: 220,
38
+ borderRight: `1px solid ${t.border}`,
39
+ padding: 16,
40
+ flexShrink: 0,
41
+ background: t.surface
13
42
  },
14
- nav: { width: "220px", borderRight: "1px solid #eee", padding: "16px", flexShrink: 0 },
15
43
  navGroup: {
16
- fontSize: "11px",
44
+ fontSize: 11,
17
45
  textTransform: "uppercase",
18
- letterSpacing: "0.6px",
19
- color: "#888",
20
- margin: "16px 0 6px"
46
+ letterSpacing: 0.6,
47
+ color: t.muted,
48
+ margin: "16px 0 6px",
49
+ fontWeight: 600
21
50
  },
22
51
  navItem: {
23
52
  display: "block",
@@ -25,51 +54,79 @@ var styles = {
25
54
  textAlign: "left",
26
55
  background: "none",
27
56
  border: "none",
28
- borderRadius: "6px",
57
+ borderRadius: t.radius,
29
58
  padding: "6px 8px",
30
59
  cursor: "pointer",
31
- fontSize: "14px",
32
- color: "#111"
60
+ fontSize: 14,
61
+ color: t.text,
62
+ fontFamily: "inherit"
63
+ },
64
+ navItemActive: { background: t.surfaceAlt, fontWeight: 600, color: t.accentStrong },
65
+ main: { flex: 1, padding: 24, maxWidth: 960 },
66
+ container: { padding: 24, maxWidth: 960 },
67
+ title: {
68
+ fontSize: 20,
69
+ fontWeight: 600,
70
+ marginTop: 0,
71
+ marginBottom: 12,
72
+ letterSpacing: t.trackingDisplay
33
73
  },
34
- navItemActive: { background: "#f3f4f6", fontWeight: 600 },
35
- main: { flex: 1, padding: "24px", maxWidth: "960px" },
36
- container: { padding: "24px", maxWidth: "960px" },
37
- title: { fontSize: "20px", fontWeight: 700, marginTop: 0, marginBottom: "12px" },
38
- subtitle: { fontSize: "15px", fontWeight: 600, marginTop: "24px", marginBottom: "8px" },
39
- status: { padding: "12px", color: "#666" },
40
- error: { color: "#e11d48", marginBottom: "12px", fontSize: "14px" },
41
- ok: { color: "#15803d", fontWeight: 600 },
42
- bad: { color: "#e11d48", fontWeight: 600 },
43
- advice: { color: "#b45309" },
44
- muted: { color: "#666", fontSize: "13px" },
45
- mono: { fontFamily: "ui-monospace, monospace", fontSize: "13px" },
46
- table: { width: "100%", borderCollapse: "collapse", fontSize: "14px" },
74
+ subtitle: {
75
+ fontSize: 15,
76
+ fontWeight: 600,
77
+ marginTop: 24,
78
+ marginBottom: 8,
79
+ letterSpacing: t.trackingDisplay
80
+ },
81
+ status: { padding: 12, color: t.muted },
82
+ error: { color: t.danger, marginBottom: 12, fontSize: 14 },
83
+ ok: { color: t.accentStrong, fontWeight: 600 },
84
+ bad: { color: t.danger, fontWeight: 600 },
85
+ advice: { color: t.warning },
86
+ muted: { color: t.muted, fontSize: 13 },
87
+ mono: { fontFamily: t.mono, fontSize: 13 },
88
+ table: { width: "100%", borderCollapse: "collapse", fontSize: 14 },
47
89
  th: {
48
90
  textAlign: "left",
49
- borderBottom: "1px solid #ddd",
91
+ borderBottom: `1px solid ${t.border}`,
50
92
  padding: "6px 8px",
51
93
  fontWeight: 600,
52
- color: "#444"
94
+ color: t.muted
53
95
  },
54
- td: { borderBottom: "1px solid #eee", padding: "6px 8px", verticalAlign: "top" },
96
+ td: { borderBottom: `1px solid ${t.borderLight}`, padding: "6px 8px", verticalAlign: "top" },
55
97
  list: { listStyle: "none", padding: 0, margin: 0 },
56
- row: { borderBottom: "1px solid #eee", padding: "8px 0" },
98
+ row: { borderBottom: `1px solid ${t.borderLight}`, padding: "8px 0" },
57
99
  badge: {
58
100
  display: "inline-block",
59
- borderRadius: "999px",
101
+ borderRadius: 999,
60
102
  padding: "1px 8px",
61
- fontSize: "12px",
62
- background: "#f3f4f6"
103
+ fontSize: 12,
104
+ background: t.surfaceAlt,
105
+ border: `1px solid ${t.border}`,
106
+ color: t.muted
63
107
  },
64
108
  button: {
65
- background: "none",
66
- border: "1px solid #ddd",
67
- borderRadius: "8px",
109
+ background: t.surface,
110
+ border: `1px solid ${t.border}`,
111
+ borderRadius: t.radius,
68
112
  padding: "4px 10px",
69
113
  cursor: "pointer",
70
- fontSize: "13px"
114
+ fontSize: 13,
115
+ color: t.text,
116
+ fontFamily: "inherit",
117
+ boxShadow: t.shadowCard
118
+ },
119
+ toolbar: { display: "flex", gap: 8, alignItems: "center", marginBottom: 12 },
120
+ // Surfaces the screens compose themselves, kept here so a card looks the
121
+ // same on every page rather than being re-invented per screen.
122
+ card: {
123
+ background: t.surface,
124
+ border: `1px solid ${t.border}`,
125
+ borderRadius: t.radiusLg,
126
+ padding: 16,
127
+ boxShadow: t.shadowCard
71
128
  },
72
- toolbar: { display: "flex", gap: "8px", alignItems: "center", marginBottom: "12px" }
129
+ accent: { color: t.accent }
73
130
  };
74
131
 
75
132
  // src/screens/AdminLogScreen.ts
@@ -97,7 +154,7 @@ function table(headers, rows) {
97
154
  h("thead", [
98
155
  h(
99
156
  "tr",
100
- headers.map((t) => h("th", { style: styles.th }, t))
157
+ headers.map((t2) => h("th", { style: styles.th }, t2))
101
158
  )
102
159
  ]),
103
160
  h("tbody", rows)
@@ -379,11 +436,92 @@ var RoutesScreen = defineComponent6({
379
436
  }
380
437
  });
381
438
 
439
+ // src/screens/MigrationsScreen.ts
440
+ import { useAdminMigrations } from "@fonderie/vue-admin";
441
+ import { defineComponent as defineComponent7, h as h8 } from "vue";
442
+ function why(m, everApplied) {
443
+ if (m.pending.length === 0) return null;
444
+ if (m.blockedBy) return `Apply "${m.blockedBy}" first \u2014 it runs before this one and is behind.`;
445
+ if (everApplied && m.pending.some((p) => p.impact === "destructive"))
446
+ return "Contains a migration that deletes data. No down-migration brings it back \u2014 apply this one through CI or `npm run migrate`.";
447
+ return null;
448
+ }
449
+ var MigrationsScreen = defineComponent7({
450
+ name: "FonderieMigrationsScreen",
451
+ props: { client: { type: Object, required: true } },
452
+ setup(props) {
453
+ const { report, isLoading, error, refresh, apply } = useAdminMigrations(props.client);
454
+ const section = (m, everApplied) => {
455
+ const blocked = why(m, everApplied);
456
+ const files = m.pending.map((p) => p.file);
457
+ return h8("section", { style: { marginBottom: "24px" } }, [
458
+ h8("h2", { style: styles.subtitle }, `${m.name} \u2014 ${m.pending.length} pending`),
459
+ h8(
460
+ "ul",
461
+ m.pending.map(
462
+ (p) => h8("li", [
463
+ h8("code", p.file),
464
+ " ",
465
+ h8(
466
+ "span",
467
+ { style: p.impact === "destructive" ? styles.bad : styles.advice },
468
+ p.impact
469
+ ),
470
+ p.destructive.length > 0 ? h8(
471
+ "ul",
472
+ p.destructive.map((s) => h8("li", [h8("code", s.slice(0, 120))]))
473
+ ) : null
474
+ ])
475
+ )
476
+ ),
477
+ blocked ? h8("p", { style: styles.advice }, blocked) : h8(
478
+ "button",
479
+ {
480
+ type: "button",
481
+ style: styles.button,
482
+ disabled: isLoading.value || !m.appliable,
483
+ onClick: () => {
484
+ if (window.confirm(
485
+ `Apply ${m.pending.length} migration(s) to "${m.name}"? This changes the database schema.`
486
+ ))
487
+ void apply(m.name, files).catch(() => {
488
+ });
489
+ }
490
+ },
491
+ `Apply ${m.pending.length} migration${m.pending.length === 1 ? "" : "s"}`
492
+ )
493
+ ]);
494
+ };
495
+ return () => page(
496
+ "Migrations",
497
+ { isLoading, error },
498
+ () => {
499
+ const r = report.value;
500
+ if (!r) return null;
501
+ const behind = r.modules.filter((m) => m.pending.length > 0);
502
+ if (behind.length === 0) return h8("p", { style: styles.ok }, "Every module is up to date.");
503
+ return [
504
+ r.everApplied ? null : h8(
505
+ "p",
506
+ { style: styles.advice },
507
+ "This database has never been migrated \u2014 treating it as a first install, so nothing is held back."
508
+ ),
509
+ ...behind.map((m) => section(m, r.everApplied))
510
+ ].filter(Boolean);
511
+ },
512
+ [refreshButton("Refresh", isLoading.value, () => void refresh())],
513
+ {
514
+ errorText: (e) => e.status === 403 ? "Applying migrations needs a token with the write scope." : e.explanation
515
+ }
516
+ );
517
+ }
518
+ });
519
+
382
520
  // src/screens/TokensScreen.ts
383
521
  import { useAdminTokens } from "@fonderie/vue-admin";
384
- import { defineComponent as defineComponent7, h as h8, ref } from "vue";
522
+ import { defineComponent as defineComponent8, h as h9, ref } from "vue";
385
523
  var ALL = ["read", "write", "secrets"];
386
- var TokensScreen = defineComponent7({
524
+ var TokensScreen = defineComponent8({
387
525
  name: "FonderieTokensScreen",
388
526
  props: { client: { type: Object, required: true } },
389
527
  setup(props) {
@@ -395,36 +533,36 @@ var TokensScreen = defineComponent7({
395
533
  const toggle = (s) => scopes.value = scopes.value.includes(s) ? scopes.value.filter((x) => x !== s) : [...scopes.value, s];
396
534
  return () => {
397
535
  const r = report.value;
398
- return h8("div", { style: styles.container }, [
399
- h8("h1", { style: styles.title }, "Access"),
400
- error.value ? h8(
536
+ return h9("div", { style: styles.container }, [
537
+ h9("h1", { style: styles.title }, "Access"),
538
+ error.value ? h9(
401
539
  "p",
402
540
  { style: styles.error, role: "alert" },
403
541
  error.value.status === 401 ? "Issuing and revoking need the root token (the one in your deployment config)." : error.value.explanation
404
542
  ) : null,
405
- h8("h2", { style: styles.subtitle }, "Root token"),
406
- r ? h8("p", [
407
- h8(
543
+ h9("h2", { style: styles.subtitle }, "Root token"),
544
+ r ? h9("p", [
545
+ h9(
408
546
  "span",
409
547
  { style: r.admin.ok ? styles.ok : styles.bad },
410
548
  r.admin.ok ? "strong" : "weak"
411
549
  ),
412
550
  ...r.admin.problems.map(
413
- (p) => h8("div", { key: p.message, style: styles.bad }, p.message)
551
+ (p) => h9("div", { key: p.message, style: styles.bad }, p.message)
414
552
  )
415
553
  ]) : null,
416
- h8("h2", { style: styles.subtitle }, "Issued tokens"),
417
- r?.issued === null ? h8(
554
+ h9("h2", { style: styles.subtitle }, "Issued tokens"),
555
+ r?.issued === null ? h9(
418
556
  "p",
419
557
  { style: styles.muted },
420
558
  "Issuing is off \u2014 give AdminModule a store and run its migrations."
421
559
  ) : [
422
- minted.value ? h8("p", { style: styles.ok }, [
560
+ minted.value ? h9("p", { style: styles.ok }, [
423
561
  "Copy this now \u2014 it is never shown again. ",
424
- h8("span", { style: styles.mono }, minted.value.token),
562
+ h9("span", { style: styles.mono }, minted.value.token),
425
563
  ` (${minted.value.name})`
426
564
  ]) : null,
427
- h8(
565
+ h9(
428
566
  "form",
429
567
  {
430
568
  style: styles.toolbar,
@@ -435,8 +573,8 @@ var TokensScreen = defineComponent7({
435
573
  name: name.value.trim(),
436
574
  scopes: scopes.value,
437
575
  ...days.value && Number.isInteger(d) && d > 0 ? { expiresInDays: d } : {}
438
- }).then((t) => {
439
- minted.value = { name: t.name, token: t.token };
576
+ }).then((t2) => {
577
+ minted.value = { name: t2.name, token: t2.token };
440
578
  name.value = "";
441
579
  days.value = "";
442
580
  }).catch(() => {
@@ -444,7 +582,7 @@ var TokensScreen = defineComponent7({
444
582
  }
445
583
  },
446
584
  [
447
- h8("input", {
585
+ h9("input", {
448
586
  value: name.value,
449
587
  onInput: (e) => name.value = e.target.value,
450
588
  placeholder: "name",
@@ -452,8 +590,8 @@ var TokensScreen = defineComponent7({
452
590
  "aria-label": "Name"
453
591
  }),
454
592
  ...ALL.map(
455
- (s) => h8("label", { key: s, style: { ...styles.badge, cursor: "pointer" } }, [
456
- h8("input", {
593
+ (s) => h9("label", { key: s, style: { ...styles.badge, cursor: "pointer" } }, [
594
+ h9("input", {
457
595
  type: "checkbox",
458
596
  checked: scopes.value.includes(s),
459
597
  onChange: () => toggle(s)
@@ -461,14 +599,14 @@ var TokensScreen = defineComponent7({
461
599
  ` ${s}`
462
600
  ])
463
601
  ),
464
- h8("input", {
602
+ h9("input", {
465
603
  value: days.value,
466
604
  onInput: (e) => days.value = e.target.value,
467
605
  placeholder: "days (optional)",
468
606
  style: { ...styles.button, cursor: "text", width: "140px" },
469
607
  "aria-label": "Days"
470
608
  }),
471
- h8(
609
+ h9(
472
610
  "button",
473
611
  {
474
612
  type: "submit",
@@ -482,35 +620,35 @@ var TokensScreen = defineComponent7({
482
620
  r?.issued && r.issued.length > 0 ? table(
483
621
  ["Name", "Scopes", "Created", "Expires", "Last used", ""],
484
622
  r.issued.map(
485
- (t) => h8("tr", { key: t.id }, [
623
+ (t2) => h9("tr", { key: t2.id }, [
486
624
  td([
487
- t.name,
488
- t.revokedAt ? h8("span", { style: styles.badge }, " revoked") : ""
625
+ t2.name,
626
+ t2.revokedAt ? h9("span", { style: styles.badge }, " revoked") : ""
489
627
  ]),
490
- td(t.scopes.join(", "), styles.mono),
628
+ td(t2.scopes.join(", "), styles.mono),
491
629
  td(
492
- `${new Date(t.createdAt).toLocaleDateString()} \xB7 ${t.createdBy}`,
630
+ `${new Date(t2.createdAt).toLocaleDateString()} \xB7 ${t2.createdBy}`,
493
631
  styles.muted
494
632
  ),
495
633
  td(
496
- t.expiresAt ? new Date(t.expiresAt).toLocaleDateString() : "never",
634
+ t2.expiresAt ? new Date(t2.expiresAt).toLocaleDateString() : "never",
497
635
  styles.muted
498
636
  ),
499
637
  td(
500
- t.lastUsedAt ? new Date(t.lastUsedAt).toLocaleString() : "never",
638
+ t2.lastUsedAt ? new Date(t2.lastUsedAt).toLocaleString() : "never",
501
639
  styles.muted
502
640
  ),
503
641
  td(
504
- t.revokedAt ? "" : h8(
642
+ t2.revokedAt ? "" : h9(
505
643
  "button",
506
644
  {
507
645
  type: "button",
508
646
  style: styles.button,
509
647
  onClick: () => {
510
648
  if (window.confirm(
511
- `Revoke "${t.name}"? Anything using it stops working immediately.`
649
+ `Revoke "${t2.name}"? Anything using it stops working immediately.`
512
650
  ))
513
- void revoke(t.id).catch(() => {
651
+ void revoke(t2.id).catch(() => {
514
652
  });
515
653
  }
516
654
  },
@@ -519,21 +657,21 @@ var TokensScreen = defineComponent7({
519
657
  )
520
658
  ])
521
659
  )
522
- ) : h8("p", { style: styles.muted }, "None issued.")
660
+ ) : h9("p", { style: styles.muted }, "None issued.")
523
661
  ],
524
- h8("h2", { style: styles.subtitle }, "Legacy per-brick tokens"),
525
- r && r.legacy.length === 0 ? h8(
662
+ h9("h2", { style: styles.subtitle }, "Legacy per-brick tokens"),
663
+ r && r.legacy.length === 0 ? h9(
526
664
  "p",
527
665
  { style: styles.muted },
528
666
  "None \u2014 every brick's admin surface goes through this token."
529
- ) : h8(
667
+ ) : h9(
530
668
  "ul",
531
669
  { style: styles.list },
532
670
  (r?.legacy ?? []).map(
533
- (l) => h8("li", { key: l.module, style: styles.row }, [
534
- h8("span", { style: styles.mono }, l.module),
671
+ (l) => h9("li", { key: l.module, style: styles.row }, [
672
+ h9("span", { style: styles.mono }, l.module),
535
673
  " ",
536
- h8(
674
+ h9(
537
675
  "span",
538
676
  { style: styles.muted },
539
677
  "still registers its standalone routes with its own token (deprecated)"
@@ -553,8 +691,8 @@ import {
553
691
  useAdminUserSessions,
554
692
  useAdminUsers
555
693
  } from "@fonderie/vue-admin";
556
- import { computed, defineComponent as defineComponent8, h as h9, ref as ref2 } from "vue";
557
- var UsersScreen = defineComponent8({
694
+ import { computed, defineComponent as defineComponent9, h as h10, ref as ref2 } from "vue";
695
+ var UsersScreen = defineComponent9({
558
696
  name: "FonderieUsersScreen",
559
697
  props: {
560
698
  client: { type: Object, required: true },
@@ -573,8 +711,8 @@ var UsersScreen = defineComponent8({
573
711
  const sessions = useAdminUserSessions(props.client, userId);
574
712
  const history = useAdminLoginHistory(props.client, userId, { limit: 20 });
575
713
  const showList = computed(() => !email.value && !selectedId.value);
576
- const yesNo = (v) => h9("span", { style: v ? styles.ok : styles.muted }, v ? "yes" : "no");
577
- const row = (k, v) => h9("tr", [td(k), td(v)]);
714
+ const yesNo = (v) => h10("span", { style: v ? styles.ok : styles.muted }, v ? "yes" : "no");
715
+ const row = (k, v) => h10("tr", [td(k), td(v)]);
578
716
  const clear = () => {
579
717
  email.value = "";
580
718
  selectedId.value = "";
@@ -582,9 +720,9 @@ var UsersScreen = defineComponent8({
582
720
  };
583
721
  return () => {
584
722
  const u = user.value;
585
- return h9("div", { style: styles.container }, [
586
- h9("h1", { style: styles.title }, "Users"),
587
- h9(
723
+ return h10("div", { style: styles.container }, [
724
+ h10("h1", { style: styles.title }, "Users"),
725
+ h10(
588
726
  "form",
589
727
  {
590
728
  style: styles.toolbar,
@@ -595,7 +733,7 @@ var UsersScreen = defineComponent8({
595
733
  }
596
734
  },
597
735
  [
598
- h9("input", {
736
+ h10("input", {
599
737
  type: "email",
600
738
  value: input.value,
601
739
  onInput: (e) => input.value = e.target.value,
@@ -603,7 +741,7 @@ var UsersScreen = defineComponent8({
603
741
  style: { ...styles.button, cursor: "text", minWidth: "280px" },
604
742
  "aria-label": "Email"
605
743
  }),
606
- h9(
744
+ h10(
607
745
  "button",
608
746
  { type: "submit", style: styles.button, disabled: isLoading.value },
609
747
  "Look up"
@@ -611,14 +749,14 @@ var UsersScreen = defineComponent8({
611
749
  showList.value ? refreshButton("Refresh", list.isLoading.value, () => void list.refresh()) : refreshButton("\u2190 All users", false, clear)
612
750
  ]
613
751
  ),
614
- showList.value ? h9("div", [
615
- list.error.value ? h9("p", { style: styles.error, role: "alert" }, list.error.value.explanation) : null,
616
- list.users.value.length === 0 && !list.isLoading.value ? h9("p", { style: styles.muted }, "No users yet.") : table(
752
+ showList.value ? h10("div", [
753
+ list.error.value ? h10("p", { style: styles.error, role: "alert" }, list.error.value.explanation) : null,
754
+ list.users.value.length === 0 && !list.isLoading.value ? h10("p", { style: styles.muted }, "No users yet.") : table(
617
755
  ["Email", "Name", "Created", "Status"],
618
756
  list.users.value.map(
619
- (u2) => h9("tr", { key: u2.id }, [
757
+ (u2) => h10("tr", { key: u2.id }, [
620
758
  td(
621
- h9(
759
+ h10(
622
760
  "button",
623
761
  {
624
762
  type: "button",
@@ -629,17 +767,17 @@ var UsersScreen = defineComponent8({
629
767
  )
630
768
  ),
631
769
  td(
632
- `${u2.firstName ?? ""} ${u2.lastName ?? ""}`.trim() || h9("span", { style: styles.muted }, "\u2014")
770
+ `${u2.firstName ?? ""} ${u2.lastName ?? ""}`.trim() || h10("span", { style: styles.muted }, "\u2014")
633
771
  ),
634
772
  td(new Date(u2.createdAt).toLocaleDateString()),
635
773
  td(
636
- u2.suspended ? h9("span", { style: styles.badge }, "suspended") : u2.deletedAt ? h9("span", { style: styles.badge }, "deleted") : h9("span", { style: styles.muted }, "active")
774
+ u2.suspended ? h10("span", { style: styles.badge }, "suspended") : u2.deletedAt ? h10("span", { style: styles.badge }, "deleted") : h10("span", { style: styles.muted }, "active")
637
775
  )
638
776
  ])
639
777
  )
640
778
  ),
641
- list.isLoading.value ? h9("p", { style: styles.status }, "Loading\u2026") : null,
642
- list.hasMore.value && !list.isLoading.value ? h9(
779
+ list.isLoading.value ? h10("p", { style: styles.status }, "Loading\u2026") : null,
780
+ list.hasMore.value && !list.isLoading.value ? h10(
643
781
  "button",
644
782
  {
645
783
  type: "button",
@@ -649,21 +787,21 @@ var UsersScreen = defineComponent8({
649
787
  "Load more"
650
788
  ) : null
651
789
  ]) : null,
652
- error.value ? h9(
790
+ error.value ? h10(
653
791
  "p",
654
792
  { style: styles.error, role: "alert" },
655
793
  error.value.status === 404 ? "No user with that email." : error.value.explanation
656
794
  ) : null,
657
795
  u ? [
658
- h9("h2", { style: styles.subtitle }, [
796
+ h10("h2", { style: styles.subtitle }, [
659
797
  u.firstName || u.lastName ? `${u.firstName} ${u.lastName}`.trim() : u.email,
660
798
  " ",
661
- u.suspended ? h9("span", { style: styles.badge }, "suspended") : null,
662
- u.deletedAt ? h9("span", { style: styles.badge }, "deleted") : null
799
+ u.suspended ? h10("span", { style: styles.badge }, "suspended") : null,
800
+ u.deletedAt ? h10("span", { style: styles.badge }, "deleted") : null
663
801
  ]),
664
- h9("table", { style: styles.table }, [
665
- h9("tbody", [
666
- row("id", h9("span", { style: styles.mono }, u.id)),
802
+ h10("table", { style: styles.table }, [
803
+ h10("tbody", [
804
+ row("id", h10("span", { style: styles.mono }, u.id)),
667
805
  row("email", [u.email, " \xB7 verified ", yesNo(u.isEmailVerified)]),
668
806
  row("MFA", yesNo(u.mfaEnabled)),
669
807
  row(
@@ -672,12 +810,12 @@ var UsersScreen = defineComponent8({
672
810
  ),
673
811
  row(
674
812
  "last login",
675
- u.lastLogin ? new Date(u.lastLogin).toLocaleString() : h9("span", { style: styles.muted }, "never")
813
+ u.lastLogin ? new Date(u.lastLogin).toLocaleString() : h10("span", { style: styles.muted }, "never")
676
814
  ),
677
815
  row("created", new Date(u.createdAt).toLocaleString())
678
816
  ])
679
817
  ]),
680
- h9("div", { style: { ...styles.toolbar, marginTop: "12px" } }, [
818
+ h10("div", { style: { ...styles.toolbar, marginTop: "12px" } }, [
681
819
  u.suspended ? refreshButton("Unsuspend", isLoading.value, () => void unsuspend()) : refreshButton("Suspend", isLoading.value, () => void suspend()),
682
820
  refreshButton(
683
821
  "Sign out everywhere",
@@ -685,17 +823,17 @@ var UsersScreen = defineComponent8({
685
823
  () => void revokeSessions().then(() => sessions.refresh())
686
824
  )
687
825
  ]),
688
- h9("h2", { style: styles.subtitle }, "Live sessions"),
689
- sessions.sessions.value.length === 0 ? h9("p", { style: styles.muted }, "None.") : h9(
826
+ h10("h2", { style: styles.subtitle }, "Live sessions"),
827
+ sessions.sessions.value.length === 0 ? h10("p", { style: styles.muted }, "None.") : h10(
690
828
  "ul",
691
829
  { style: styles.list },
692
830
  sessions.sessions.value.map(
693
- (s) => h9("li", { key: s.id, style: styles.row }, [
694
- h9("span", { style: styles.mono }, s.ipAddress ?? "\u2014"),
831
+ (s) => h10("li", { key: s.id, style: styles.row }, [
832
+ h10("span", { style: styles.mono }, s.ipAddress ?? "\u2014"),
695
833
  " ",
696
- h9("span", { style: styles.muted }, s.userAgent ?? ""),
834
+ h10("span", { style: styles.muted }, s.userAgent ?? ""),
697
835
  " ",
698
- h9(
836
+ h10(
699
837
  "span",
700
838
  { style: styles.muted },
701
839
  `since ${new Date(s.createdAt).toLocaleString()}`
@@ -703,25 +841,25 @@ var UsersScreen = defineComponent8({
703
841
  ])
704
842
  )
705
843
  ),
706
- h9("h2", { style: styles.subtitle }, "Recent sign-ins"),
707
- history.events.value.length === 0 && !history.isLoading.value ? h9("p", { style: styles.muted }, "None recorded.") : h9(
844
+ h10("h2", { style: styles.subtitle }, "Recent sign-ins"),
845
+ history.events.value.length === 0 && !history.isLoading.value ? h10("p", { style: styles.muted }, "None recorded.") : h10(
708
846
  "ul",
709
847
  { style: styles.list },
710
848
  history.events.value.map(
711
- (e) => h9("li", { key: e.id, style: styles.row }, [
712
- h9(
849
+ (e) => h10("li", { key: e.id, style: styles.row }, [
850
+ h10(
713
851
  "span",
714
852
  { style: e.outcome === "success" ? styles.ok : styles.bad },
715
853
  e.outcome
716
854
  ),
717
855
  " ",
718
- h9("span", { style: styles.muted }, e.method),
856
+ h10("span", { style: styles.muted }, e.method),
719
857
  " ",
720
- h9("span", { style: styles.muted }, new Date(e.createdAt).toLocaleString())
858
+ h10("span", { style: styles.muted }, new Date(e.createdAt).toLocaleString())
721
859
  ])
722
860
  )
723
861
  ),
724
- history.hasMore.value && !history.isLoading.value ? h9(
862
+ history.hasMore.value && !history.isLoading.value ? h10(
725
863
  "button",
726
864
  {
727
865
  type: "button",
@@ -738,8 +876,8 @@ var UsersScreen = defineComponent8({
738
876
 
739
877
  // src/screens/CatalogScreen.ts
740
878
  import { useAdminCatalog } from "@fonderie/vue-admin";
741
- import { defineComponent as defineComponent9, h as h10 } from "vue";
742
- var CatalogScreen = defineComponent9({
879
+ import { defineComponent as defineComponent10, h as h11 } from "vue";
880
+ var CatalogScreen = defineComponent10({
743
881
  name: "FonderieCatalogScreen",
744
882
  props: { client: { type: Object, required: true } },
745
883
  setup(props) {
@@ -747,35 +885,35 @@ var CatalogScreen = defineComponent9({
747
885
  const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
748
886
  return () => {
749
887
  const c = catalog.value;
750
- return h10("div", { style: styles.container }, [
751
- h10("div", { style: styles.toolbar }, [
752
- h10("h1", { style: { ...styles.title, marginBottom: 0 } }, "Catalog"),
888
+ return h11("div", { style: styles.container }, [
889
+ h11("div", { style: styles.toolbar }, [
890
+ h11("h1", { style: { ...styles.title, marginBottom: 0 } }, "Catalog"),
753
891
  refreshButton("Refresh", isLoading.value, () => void refresh())
754
892
  ]),
755
- error.value ? h10("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
756
- isLoading.value && !c ? h10("p", { style: styles.status }, "Loading\u2026") : null,
893
+ error.value ? h11("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
894
+ isLoading.value && !c ? h11("p", { style: styles.status }, "Loading\u2026") : null,
757
895
  c ? [
758
- h10("h2", { style: styles.subtitle }, "Configured (code)"),
759
- h10(
896
+ h11("h2", { style: styles.subtitle }, "Configured (code)"),
897
+ h11(
760
898
  "pre",
761
899
  {
762
900
  style: {
763
901
  ...styles.mono,
764
- background: "#f9fafb",
902
+ background: "var(--fonderie-surface-alt,#fafafa)",
765
903
  padding: "12px",
766
904
  overflowX: "auto"
767
905
  }
768
906
  },
769
907
  JSON.stringify(c.configured, null, 2)
770
908
  ),
771
- h10("h2", { style: styles.subtitle }, "Stored (database)"),
772
- c.stored.length === 0 ? h10("p", { style: styles.muted }, "No stored plans.") : table(
909
+ h11("h2", { style: styles.subtitle }, "Stored (database)"),
910
+ c.stored.length === 0 ? h11("p", { style: styles.muted }, "No stored plans.") : table(
773
911
  ["Plan", "Tier", "Seats", "Monthly", "Yearly", "Trial", ""],
774
912
  c.stored.map(
775
- (p) => h10("tr", { key: p.id }, [
913
+ (p) => h11("tr", { key: p.id }, [
776
914
  td([
777
- h10("strong", p.name),
778
- p.description ? h10("div", { style: styles.muted }, p.description) : ""
915
+ h11("strong", p.name),
916
+ p.description ? h11("div", { style: styles.muted }, p.description) : ""
779
917
  ]),
780
918
  td(String(p.tier)),
781
919
  td(p.seats == null ? "\u221E" : String(p.seats)),
@@ -783,7 +921,7 @@ var CatalogScreen = defineComponent9({
783
921
  td(money(p.pricing?.yearly)),
784
922
  td(p.trialDays ? `${p.trialDays} d` : "\u2014"),
785
923
  td(
786
- h10(
924
+ h11(
787
925
  "button",
788
926
  {
789
927
  type: "button",
@@ -808,8 +946,8 @@ var CatalogScreen = defineComponent9({
808
946
 
809
947
  // src/screens/SubscriberScreen.ts
810
948
  import { useAdminSubscriber, useAdminSubscribers } from "@fonderie/vue-admin";
811
- import { defineComponent as defineComponent10, h as h11, ref as ref3 } from "vue";
812
- var SubscriberScreen = defineComponent10({
949
+ import { defineComponent as defineComponent11, h as h12, ref as ref3 } from "vue";
950
+ var SubscriberScreen = defineComponent11({
813
951
  name: "FonderieSubscriberScreen",
814
952
  props: {
815
953
  client: { type: Object, required: true },
@@ -821,16 +959,16 @@ var SubscriberScreen = defineComponent10({
821
959
  const subscriber = ref3(null);
822
960
  const list = useAdminSubscribers(props.client, { limit: props.pageSize });
823
961
  const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = useAdminSubscriber(props.client, subscriber, { limit: 20 });
824
- const open = (t, id) => {
962
+ const open = (t2, id) => {
825
963
  granted.value = null;
826
- type.value = t;
964
+ type.value = t2;
827
965
  idInput.value = id;
828
- subscriber.value = { type: t, id };
966
+ subscriber.value = { type: t2, id };
829
967
  };
830
968
  const amount = ref3("");
831
969
  const note = ref3("");
832
970
  const granted = ref3(null);
833
- const input = (model, placeholder, extra = {}) => h11("input", {
971
+ const input = (model, placeholder, extra = {}) => h12("input", {
834
972
  value: model.value,
835
973
  onInput: (e) => model.value = e.target.value,
836
974
  placeholder,
@@ -840,9 +978,9 @@ var SubscriberScreen = defineComponent10({
840
978
  return () => {
841
979
  const s = subscription.value;
842
980
  const w = wallet.value;
843
- return h11("div", { style: styles.container }, [
844
- h11("h1", { style: styles.title }, "Subscriber"),
845
- h11(
981
+ return h12("div", { style: styles.container }, [
982
+ h12("h1", { style: styles.title }, "Subscriber"),
983
+ h12(
846
984
  "form",
847
985
  {
848
986
  style: styles.toolbar,
@@ -853,7 +991,7 @@ var SubscriberScreen = defineComponent10({
853
991
  }
854
992
  },
855
993
  [
856
- h11(
994
+ h12(
857
995
  "select",
858
996
  {
859
997
  value: type.value,
@@ -862,17 +1000,17 @@ var SubscriberScreen = defineComponent10({
862
1000
  "aria-label": "Type"
863
1001
  },
864
1002
  [
865
- h11("option", { value: "user" }, "user"),
866
- h11("option", { value: "workspace" }, "workspace")
1003
+ h12("option", { value: "user" }, "user"),
1004
+ h12("option", { value: "workspace" }, "workspace")
867
1005
  ]
868
1006
  ),
869
1007
  input(idInput, "subscriber id", { minWidth: "280px" }),
870
- h11(
1008
+ h12(
871
1009
  "button",
872
1010
  { type: "submit", style: styles.button, disabled: isLoading.value },
873
1011
  "Look up"
874
1012
  ),
875
- subscriber.value ? h11(
1013
+ subscriber.value ? h12(
876
1014
  "button",
877
1015
  {
878
1016
  type: "button",
@@ -884,7 +1022,7 @@ var SubscriberScreen = defineComponent10({
884
1022
  }
885
1023
  },
886
1024
  "\u2190 All subscribers"
887
- ) : h11(
1025
+ ) : h12(
888
1026
  "button",
889
1027
  {
890
1028
  type: "button",
@@ -896,14 +1034,14 @@ var SubscriberScreen = defineComponent10({
896
1034
  )
897
1035
  ]
898
1036
  ),
899
- !subscriber.value ? h11("div", [
900
- list.error.value ? h11("p", { style: styles.error, role: "alert" }, list.error.value.explanation) : null,
901
- list.subscriptions.value.length === 0 && !list.isLoading.value ? h11("p", { style: styles.muted }, "No subscribers yet.") : table(
1037
+ !subscriber.value ? h12("div", [
1038
+ list.error.value ? h12("p", { style: styles.error, role: "alert" }, list.error.value.explanation) : null,
1039
+ list.subscriptions.value.length === 0 && !list.isLoading.value ? h12("p", { style: styles.muted }, "No subscribers yet.") : table(
902
1040
  ["Subscriber", "Plan", "Status", "Renews"],
903
1041
  list.subscriptions.value.map(
904
- (sub) => h11("tr", { key: sub.id }, [
1042
+ (sub) => h12("tr", { key: sub.id }, [
905
1043
  td(
906
- h11(
1044
+ h12(
907
1045
  "button",
908
1046
  {
909
1047
  type: "button",
@@ -915,16 +1053,16 @@ var SubscriberScreen = defineComponent10({
915
1053
  ),
916
1054
  td(`${sub.plan} \xB7 ${sub.interval}`),
917
1055
  td(
918
- sub.cancelAtPeriodEnd ? [sub.status, " ", h11("span", { style: styles.badge }, "cancels")] : sub.status
1056
+ sub.cancelAtPeriodEnd ? [sub.status, " ", h12("span", { style: styles.badge }, "cancels")] : sub.status
919
1057
  ),
920
1058
  td(
921
- sub.currentPeriodEnd ? new Date(sub.currentPeriodEnd).toLocaleDateString() : h11("span", { style: styles.muted }, "\u2014")
1059
+ sub.currentPeriodEnd ? new Date(sub.currentPeriodEnd).toLocaleDateString() : h12("span", { style: styles.muted }, "\u2014")
922
1060
  )
923
1061
  ])
924
1062
  )
925
1063
  ),
926
- list.isLoading.value ? h11("p", { style: styles.status }, "Loading\u2026") : null,
927
- list.hasMore.value && !list.isLoading.value ? h11(
1064
+ list.isLoading.value ? h12("p", { style: styles.status }, "Loading\u2026") : null,
1065
+ list.hasMore.value && !list.isLoading.value ? h12(
928
1066
  "button",
929
1067
  {
930
1068
  type: "button",
@@ -934,37 +1072,37 @@ var SubscriberScreen = defineComponent10({
934
1072
  "Load more"
935
1073
  ) : null
936
1074
  ]) : null,
937
- error.value ? h11("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
1075
+ error.value ? h12("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
938
1076
  subscriber.value && !isLoading.value ? [
939
- h11("h2", { style: styles.subtitle }, "Subscription"),
940
- s ? h11("table", { style: styles.table }, [
941
- h11("tbody", [
942
- h11("tr", [td("plan"), td([h11("strong", s.plan), ` \xB7 ${s.interval}`])]),
943
- h11("tr", [
1077
+ h12("h2", { style: styles.subtitle }, "Subscription"),
1078
+ s ? h12("table", { style: styles.table }, [
1079
+ h12("tbody", [
1080
+ h12("tr", [td("plan"), td([h12("strong", s.plan), ` \xB7 ${s.interval}`])]),
1081
+ h12("tr", [
944
1082
  td("status"),
945
1083
  td(`${s.status}${s.cancelAtPeriodEnd ? " \xB7 cancels at period end" : ""}`)
946
1084
  ]),
947
- h11("tr", [
1085
+ h12("tr", [
948
1086
  td("period"),
949
1087
  td(
950
1088
  `${s.currentPeriodStart ? new Date(s.currentPeriodStart).toLocaleDateString() : "\u2014"} \u2192 ${s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : "\u2014"}`
951
1089
  )
952
1090
  ]),
953
- h11("tr", [td("provider"), td(s.providerSubscriptionId ?? "\u2014", styles.mono)])
1091
+ h12("tr", [td("provider"), td(s.providerSubscriptionId ?? "\u2014", styles.mono)])
954
1092
  ])
955
- ]) : h11("p", { style: styles.muted }, "No subscription."),
956
- h11("h2", { style: styles.subtitle }, "Wallet"),
1093
+ ]) : h12("p", { style: styles.muted }, "No subscription."),
1094
+ h12("h2", { style: styles.subtitle }, "Wallet"),
957
1095
  w ? [
958
- h11("p", [
959
- h11("strong", w.balance),
1096
+ h12("p", [
1097
+ h12("strong", w.balance),
960
1098
  ` ${w.currency} `,
961
- h11(
1099
+ h12(
962
1100
  "span",
963
1101
  { style: styles.muted },
964
1102
  `(granted ${w.granted ?? "0"} \xB7 purchased ${w.purchased ?? "0"}) \xB7 minor units, precision ${w.precision}`
965
1103
  )
966
1104
  ]),
967
- h11(
1105
+ h12(
968
1106
  "form",
969
1107
  {
970
1108
  style: styles.toolbar,
@@ -989,7 +1127,7 @@ var SubscriberScreen = defineComponent10({
989
1127
  [
990
1128
  input(amount, "amount (minor units)"),
991
1129
  input(note, "reason (optional)", { minWidth: "220px" }),
992
- h11(
1130
+ h12(
993
1131
  "button",
994
1132
  {
995
1133
  type: "submit",
@@ -998,22 +1136,22 @@ var SubscriberScreen = defineComponent10({
998
1136
  },
999
1137
  "Grant"
1000
1138
  ),
1001
- granted.value ? h11("span", { style: styles.ok }, granted.value) : null
1139
+ granted.value ? h12("span", { style: styles.ok }, granted.value) : null
1002
1140
  ]
1003
1141
  ),
1004
- h11("h2", { style: styles.subtitle }, "Ledger"),
1005
- ledger.value.length === 0 ? h11("p", { style: styles.muted }, "Nothing moved yet.") : table(
1142
+ h12("h2", { style: styles.subtitle }, "Ledger"),
1143
+ ledger.value.length === 0 ? h12("p", { style: styles.muted }, "Nothing moved yet.") : table(
1006
1144
  ["When", "Kind", "Amount", "Note"],
1007
1145
  ledger.value.map(
1008
- (t) => h11("tr", { key: t.id }, [
1009
- td(new Date(t.createdAt).toLocaleString(), styles.muted),
1010
- td(t.type),
1011
- td(t.amount, styles.mono),
1012
- td(t.description ?? "", styles.muted)
1146
+ (t2) => h12("tr", { key: t2.id }, [
1147
+ td(new Date(t2.createdAt).toLocaleString(), styles.muted),
1148
+ td(t2.type),
1149
+ td(t2.amount, styles.mono),
1150
+ td(t2.description ?? "", styles.muted)
1013
1151
  ])
1014
1152
  )
1015
1153
  ),
1016
- hasMoreLedger.value ? h11(
1154
+ hasMoreLedger.value ? h12(
1017
1155
  "button",
1018
1156
  {
1019
1157
  type: "button",
@@ -1022,7 +1160,7 @@ var SubscriberScreen = defineComponent10({
1022
1160
  },
1023
1161
  "Load more"
1024
1162
  ) : null
1025
- ] : h11(
1163
+ ] : h12(
1026
1164
  "p",
1027
1165
  { style: styles.muted },
1028
1166
  "No wallet \u2014 billing has no wallet configuration."
@@ -1035,8 +1173,8 @@ var SubscriberScreen = defineComponent10({
1035
1173
 
1036
1174
  // src/screens/AuditScreen.ts
1037
1175
  import { useAdminAudit } from "@fonderie/vue-admin";
1038
- import { defineComponent as defineComponent11, h as h12, ref as ref4 } from "vue";
1039
- var AuditScreen = defineComponent11({
1176
+ import { defineComponent as defineComponent12, h as h13, ref as ref4 } from "vue";
1177
+ var AuditScreen = defineComponent12({
1040
1178
  name: "FonderieAuditScreen",
1041
1179
  props: {
1042
1180
  client: { type: Object, required: true },
@@ -1049,16 +1187,16 @@ var AuditScreen = defineComponent11({
1049
1187
  props.client,
1050
1188
  query
1051
1189
  );
1052
- const field = (key, placeholder) => h12("input", {
1190
+ const field = (key, placeholder) => h13("input", {
1053
1191
  value: draft.value[key],
1054
1192
  onInput: (e) => draft.value = { ...draft.value, [key]: e.target.value },
1055
1193
  placeholder,
1056
1194
  style: { ...styles.button, cursor: "text" },
1057
1195
  "aria-label": placeholder
1058
1196
  });
1059
- return () => h12("div", { style: styles.container }, [
1060
- h12("h1", { style: styles.title }, "Audit"),
1061
- h12(
1197
+ return () => h13("div", { style: styles.container }, [
1198
+ h13("h1", { style: styles.title }, "Audit"),
1199
+ h13(
1062
1200
  "form",
1063
1201
  {
1064
1202
  style: styles.toolbar,
@@ -1077,7 +1215,7 @@ var AuditScreen = defineComponent11({
1077
1215
  field("workspaceId", "workspace id (all if empty)"),
1078
1216
  field("type", "event type"),
1079
1217
  field("actorId", "actor id"),
1080
- h12(
1218
+ h13(
1081
1219
  "button",
1082
1220
  { type: "submit", style: styles.button, disabled: isLoading.value },
1083
1221
  "Filter"
@@ -1085,11 +1223,11 @@ var AuditScreen = defineComponent11({
1085
1223
  refreshButton("Refresh", isLoading.value, () => void refresh())
1086
1224
  ]
1087
1225
  ),
1088
- error.value ? h12("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
1089
- events.value.length === 0 && !isLoading.value ? h12("p", { style: styles.muted }, "Nothing recorded for this filter.") : table(
1226
+ error.value ? h13("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
1227
+ events.value.length === 0 && !isLoading.value ? h13("p", { style: styles.muted }, "Nothing recorded for this filter.") : table(
1090
1228
  ["When", "Type", "Workspace", "Actor", "Request"],
1091
1229
  events.value.map(
1092
- (e) => h12("tr", { key: e.id }, [
1230
+ (e) => h13("tr", { key: e.id }, [
1093
1231
  td(new Date(e.createdAt).toLocaleString(), styles.muted),
1094
1232
  td(e.type, styles.mono),
1095
1233
  td(String(e.payload["workspaceId"] ?? "\u2014"), styles.mono),
@@ -1098,8 +1236,8 @@ var AuditScreen = defineComponent11({
1098
1236
  ])
1099
1237
  )
1100
1238
  ),
1101
- isLoading.value ? h12("p", { style: styles.status }, "Loading\u2026") : null,
1102
- hasMore.value && !isLoading.value ? h12(
1239
+ isLoading.value ? h13("p", { style: styles.status }, "Loading\u2026") : null,
1240
+ hasMore.value && !isLoading.value ? h13(
1103
1241
  "button",
1104
1242
  {
1105
1243
  type: "button",
@@ -1139,11 +1277,12 @@ var NAV = [
1139
1277
  items: [
1140
1278
  { page: "audit", label: "Audit", needs: "audit" },
1141
1279
  { page: "log", label: "Admin log" },
1142
- { page: "tokens", label: "Access" }
1280
+ { page: "tokens", label: "Access" },
1281
+ { page: "migrations", label: "Migrations" }
1143
1282
  ]
1144
1283
  }
1145
1284
  ];
1146
- var AdminShell = defineComponent12({
1285
+ var AdminShell = defineComponent13({
1147
1286
  name: "FonderieAdminShell",
1148
1287
  props: {
1149
1288
  client: { type: Object, required: true },
@@ -1172,7 +1311,7 @@ var AdminShell = defineComponent12({
1172
1311
  emit("navigate", p);
1173
1312
  if (props.page === void 0) own.value = p;
1174
1313
  };
1175
- const back = () => h13(
1314
+ const back = () => h14(
1176
1315
  "button",
1177
1316
  { type: "button", style: styles.button, onClick: () => editing.value = null },
1178
1317
  "\u2190 Back"
@@ -1181,43 +1320,45 @@ var AdminShell = defineComponent12({
1181
1320
  const c = props.client;
1182
1321
  switch (current.value) {
1183
1322
  case "attention":
1184
- return h13(AttentionScreen, { client: c });
1323
+ return h14(AttentionScreen, { client: c });
1185
1324
  case "modules":
1186
- return h13(ModulesScreen, { client: c });
1325
+ return h14(ModulesScreen, { client: c });
1187
1326
  case "doctor":
1188
- return h13(DoctorScreen, { client: c });
1327
+ return h14(DoctorScreen, { client: c });
1189
1328
  case "config":
1190
- return h13(ConfigScreen, { client: c });
1329
+ return h14(ConfigScreen, { client: c });
1191
1330
  case "routes":
1192
- return h13(RoutesScreen, { client: c });
1331
+ return h14(RoutesScreen, { client: c });
1193
1332
  case "tokens":
1194
- return h13(TokensScreen, { client: c });
1333
+ return h14(TokensScreen, { client: c });
1334
+ case "migrations":
1335
+ return h14(MigrationsScreen, { client: c });
1195
1336
  case "log":
1196
- return h13(AdminLogScreen, { client: c });
1337
+ return h14(AdminLogScreen, { client: c });
1197
1338
  case "catalog":
1198
- return props.billingClient ? h13(CatalogScreen, { client: props.billingClient }) : h13(
1339
+ return props.billingClient ? h14(CatalogScreen, { client: props.billingClient }) : h14(
1199
1340
  "p",
1200
1341
  { style: styles.status },
1201
1342
  "Pass a BillingAdminClient to see the catalog here."
1202
1343
  );
1203
1344
  case "subscriber":
1204
- return props.billingClient ? h13(SubscriberScreen, { client: props.billingClient }) : h13(
1345
+ return props.billingClient ? h14(SubscriberScreen, { client: props.billingClient }) : h14(
1205
1346
  "p",
1206
1347
  { style: styles.status },
1207
1348
  "Pass a BillingAdminClient to look up subscribers here."
1208
1349
  );
1209
1350
  case "audit":
1210
- return props.auditClient ? h13(AuditScreen, { client: props.auditClient }) : h13(
1351
+ return props.auditClient ? h14(AuditScreen, { client: props.auditClient }) : h14(
1211
1352
  "p",
1212
1353
  { style: styles.status },
1213
1354
  "Pass an AuditAdminClient to see the audit trail here."
1214
1355
  );
1215
1356
  case "users":
1216
- return props.authClient ? h13(UsersScreen, { client: props.authClient }) : h13("p", { style: styles.status }, "Pass an AuthAdminClient to look up users here.");
1357
+ return props.authClient ? h14(UsersScreen, { client: props.authClient }) : h14("p", { style: styles.status }, "Pass an AuthAdminClient to look up users here.");
1217
1358
  case "settings": {
1218
1359
  const cc = props.configClient;
1219
1360
  if (!cc)
1220
- return h13(
1361
+ return h14(
1221
1362
  "p",
1222
1363
  { style: styles.status },
1223
1364
  "Pass a ConfigAdminClient to manage config and secrets here."
@@ -1226,7 +1367,7 @@ var AdminShell = defineComponent12({
1226
1367
  if (e && e.kind !== "template")
1227
1368
  return [
1228
1369
  back(),
1229
- h13(ConfigEditorScreen, {
1370
+ h14(ConfigEditorScreen, {
1230
1371
  client: cc,
1231
1372
  kind: e.kind,
1232
1373
  configKey: e.key,
@@ -1234,7 +1375,7 @@ var AdminShell = defineComponent12({
1234
1375
  onSaved: () => editing.value = null
1235
1376
  })
1236
1377
  ];
1237
- return h13(ConfigListScreen, {
1378
+ return h14(ConfigListScreen, {
1238
1379
  client: cc,
1239
1380
  ...props.environment !== void 0 ? { environment: props.environment } : {},
1240
1381
  "onSelect-config": (key) => editing.value = { kind: "config", key },
@@ -1244,7 +1385,7 @@ var AdminShell = defineComponent12({
1244
1385
  case "templates": {
1245
1386
  const kc = props.courierClient;
1246
1387
  if (!kc)
1247
- return h13(
1388
+ return h14(
1248
1389
  "p",
1249
1390
  { style: styles.status },
1250
1391
  "Pass a CourierAdminClient to manage templates here."
@@ -1253,21 +1394,21 @@ var AdminShell = defineComponent12({
1253
1394
  if (e?.kind === "template")
1254
1395
  return [
1255
1396
  back(),
1256
- h13(TemplateEditorScreen, {
1397
+ h14(TemplateEditorScreen, {
1257
1398
  client: kc,
1258
1399
  type: e.type,
1259
1400
  onSaved: () => editing.value = null
1260
1401
  })
1261
1402
  ];
1262
- return h13(TemplateListScreen, {
1403
+ return h14(TemplateListScreen, {
1263
1404
  client: kc,
1264
- "onSelect-template": (t) => editing.value = { kind: "template", type: t.type }
1405
+ "onSelect-template": (t2) => editing.value = { kind: "template", type: t2.type }
1265
1406
  });
1266
1407
  }
1267
1408
  }
1268
1409
  };
1269
- return () => h13("div", { style: styles.shell }, [
1270
- h13(
1410
+ return () => h14("div", { style: styles.shell }, [
1411
+ h14(
1271
1412
  "nav",
1272
1413
  { style: styles.nav, "aria-label": "Admin" },
1273
1414
  NAV.map((g) => {
@@ -1275,10 +1416,10 @@ var AdminShell = defineComponent12({
1275
1416
  (i) => !i.needs || (i.needs === "config" ? props.configClient : i.needs === "courier" ? props.courierClient : i.needs === "auth" ? props.authClient : i.needs === "billing" ? props.billingClient : props.auditClient)
1276
1417
  );
1277
1418
  if (items.length === 0) return null;
1278
- return h13("div", { key: g.group }, [
1279
- h13("div", { style: styles.navGroup }, g.group),
1419
+ return h14("div", { key: g.group }, [
1420
+ h14("div", { style: styles.navGroup }, g.group),
1280
1421
  ...items.map(
1281
- (i) => h13(
1422
+ (i) => h14(
1282
1423
  "button",
1283
1424
  {
1284
1425
  key: i.page,
@@ -1296,7 +1437,7 @@ var AdminShell = defineComponent12({
1296
1437
  ]);
1297
1438
  })
1298
1439
  ),
1299
- h13("main", { style: styles.main }, body())
1440
+ h14("main", { style: styles.main }, body())
1300
1441
  ]);
1301
1442
  }
1302
1443
  });
@@ -1308,6 +1449,7 @@ export {
1308
1449
  CatalogScreen,
1309
1450
  ConfigScreen,
1310
1451
  DoctorScreen,
1452
+ MigrationsScreen,
1311
1453
  ModulesScreen,
1312
1454
  RoutesScreen,
1313
1455
  SubscriberScreen,