@fonderie/vue-admin-screens 0.6.0 → 0.7.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,7 +1,7 @@
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
7
  var styles = {
@@ -379,11 +379,92 @@ var RoutesScreen = defineComponent6({
379
379
  }
380
380
  });
381
381
 
382
+ // src/screens/MigrationsScreen.ts
383
+ import { useAdminMigrations } from "@fonderie/vue-admin";
384
+ import { defineComponent as defineComponent7, h as h8 } from "vue";
385
+ function why(m, everApplied) {
386
+ if (m.pending.length === 0) return null;
387
+ if (m.blockedBy) return `Apply "${m.blockedBy}" first \u2014 it runs before this one and is behind.`;
388
+ if (everApplied && m.pending.some((p) => p.impact === "destructive"))
389
+ return "Contains a migration that deletes data. No down-migration brings it back \u2014 apply this one through CI or `npm run migrate`.";
390
+ return null;
391
+ }
392
+ var MigrationsScreen = defineComponent7({
393
+ name: "FonderieMigrationsScreen",
394
+ props: { client: { type: Object, required: true } },
395
+ setup(props) {
396
+ const { report, isLoading, error, refresh, apply } = useAdminMigrations(props.client);
397
+ const section = (m, everApplied) => {
398
+ const blocked = why(m, everApplied);
399
+ const files = m.pending.map((p) => p.file);
400
+ return h8("section", { style: { marginBottom: "24px" } }, [
401
+ h8("h2", { style: styles.subtitle }, `${m.name} \u2014 ${m.pending.length} pending`),
402
+ h8(
403
+ "ul",
404
+ m.pending.map(
405
+ (p) => h8("li", [
406
+ h8("code", p.file),
407
+ " ",
408
+ h8(
409
+ "span",
410
+ { style: p.impact === "destructive" ? styles.bad : styles.advice },
411
+ p.impact
412
+ ),
413
+ p.destructive.length > 0 ? h8(
414
+ "ul",
415
+ p.destructive.map((s) => h8("li", [h8("code", s.slice(0, 120))]))
416
+ ) : null
417
+ ])
418
+ )
419
+ ),
420
+ blocked ? h8("p", { style: styles.advice }, blocked) : h8(
421
+ "button",
422
+ {
423
+ type: "button",
424
+ style: styles.button,
425
+ disabled: isLoading.value || !m.appliable,
426
+ onClick: () => {
427
+ if (window.confirm(
428
+ `Apply ${m.pending.length} migration(s) to "${m.name}"? This changes the database schema.`
429
+ ))
430
+ void apply(m.name, files).catch(() => {
431
+ });
432
+ }
433
+ },
434
+ `Apply ${m.pending.length} migration${m.pending.length === 1 ? "" : "s"}`
435
+ )
436
+ ]);
437
+ };
438
+ return () => page(
439
+ "Migrations",
440
+ { isLoading, error },
441
+ () => {
442
+ const r = report.value;
443
+ if (!r) return null;
444
+ const behind = r.modules.filter((m) => m.pending.length > 0);
445
+ if (behind.length === 0) return h8("p", { style: styles.ok }, "Every module is up to date.");
446
+ return [
447
+ r.everApplied ? null : h8(
448
+ "p",
449
+ { style: styles.advice },
450
+ "This database has never been migrated \u2014 treating it as a first install, so nothing is held back."
451
+ ),
452
+ ...behind.map((m) => section(m, r.everApplied))
453
+ ].filter(Boolean);
454
+ },
455
+ [refreshButton("Refresh", isLoading.value, () => void refresh())],
456
+ {
457
+ errorText: (e) => e.status === 403 ? "Applying migrations needs a token with the write scope." : e.explanation
458
+ }
459
+ );
460
+ }
461
+ });
462
+
382
463
  // src/screens/TokensScreen.ts
383
464
  import { useAdminTokens } from "@fonderie/vue-admin";
384
- import { defineComponent as defineComponent7, h as h8, ref } from "vue";
465
+ import { defineComponent as defineComponent8, h as h9, ref } from "vue";
385
466
  var ALL = ["read", "write", "secrets"];
386
- var TokensScreen = defineComponent7({
467
+ var TokensScreen = defineComponent8({
387
468
  name: "FonderieTokensScreen",
388
469
  props: { client: { type: Object, required: true } },
389
470
  setup(props) {
@@ -395,36 +476,36 @@ var TokensScreen = defineComponent7({
395
476
  const toggle = (s) => scopes.value = scopes.value.includes(s) ? scopes.value.filter((x) => x !== s) : [...scopes.value, s];
396
477
  return () => {
397
478
  const r = report.value;
398
- return h8("div", { style: styles.container }, [
399
- h8("h1", { style: styles.title }, "Access"),
400
- error.value ? h8(
479
+ return h9("div", { style: styles.container }, [
480
+ h9("h1", { style: styles.title }, "Access"),
481
+ error.value ? h9(
401
482
  "p",
402
483
  { style: styles.error, role: "alert" },
403
484
  error.value.status === 401 ? "Issuing and revoking need the root token (the one in your deployment config)." : error.value.explanation
404
485
  ) : null,
405
- h8("h2", { style: styles.subtitle }, "Root token"),
406
- r ? h8("p", [
407
- h8(
486
+ h9("h2", { style: styles.subtitle }, "Root token"),
487
+ r ? h9("p", [
488
+ h9(
408
489
  "span",
409
490
  { style: r.admin.ok ? styles.ok : styles.bad },
410
491
  r.admin.ok ? "strong" : "weak"
411
492
  ),
412
493
  ...r.admin.problems.map(
413
- (p) => h8("div", { key: p.message, style: styles.bad }, p.message)
494
+ (p) => h9("div", { key: p.message, style: styles.bad }, p.message)
414
495
  )
415
496
  ]) : null,
416
- h8("h2", { style: styles.subtitle }, "Issued tokens"),
417
- r?.issued === null ? h8(
497
+ h9("h2", { style: styles.subtitle }, "Issued tokens"),
498
+ r?.issued === null ? h9(
418
499
  "p",
419
500
  { style: styles.muted },
420
501
  "Issuing is off \u2014 give AdminModule a store and run its migrations."
421
502
  ) : [
422
- minted.value ? h8("p", { style: styles.ok }, [
503
+ minted.value ? h9("p", { style: styles.ok }, [
423
504
  "Copy this now \u2014 it is never shown again. ",
424
- h8("span", { style: styles.mono }, minted.value.token),
505
+ h9("span", { style: styles.mono }, minted.value.token),
425
506
  ` (${minted.value.name})`
426
507
  ]) : null,
427
- h8(
508
+ h9(
428
509
  "form",
429
510
  {
430
511
  style: styles.toolbar,
@@ -444,7 +525,7 @@ var TokensScreen = defineComponent7({
444
525
  }
445
526
  },
446
527
  [
447
- h8("input", {
528
+ h9("input", {
448
529
  value: name.value,
449
530
  onInput: (e) => name.value = e.target.value,
450
531
  placeholder: "name",
@@ -452,8 +533,8 @@ var TokensScreen = defineComponent7({
452
533
  "aria-label": "Name"
453
534
  }),
454
535
  ...ALL.map(
455
- (s) => h8("label", { key: s, style: { ...styles.badge, cursor: "pointer" } }, [
456
- h8("input", {
536
+ (s) => h9("label", { key: s, style: { ...styles.badge, cursor: "pointer" } }, [
537
+ h9("input", {
457
538
  type: "checkbox",
458
539
  checked: scopes.value.includes(s),
459
540
  onChange: () => toggle(s)
@@ -461,14 +542,14 @@ var TokensScreen = defineComponent7({
461
542
  ` ${s}`
462
543
  ])
463
544
  ),
464
- h8("input", {
545
+ h9("input", {
465
546
  value: days.value,
466
547
  onInput: (e) => days.value = e.target.value,
467
548
  placeholder: "days (optional)",
468
549
  style: { ...styles.button, cursor: "text", width: "140px" },
469
550
  "aria-label": "Days"
470
551
  }),
471
- h8(
552
+ h9(
472
553
  "button",
473
554
  {
474
555
  type: "submit",
@@ -482,10 +563,10 @@ var TokensScreen = defineComponent7({
482
563
  r?.issued && r.issued.length > 0 ? table(
483
564
  ["Name", "Scopes", "Created", "Expires", "Last used", ""],
484
565
  r.issued.map(
485
- (t) => h8("tr", { key: t.id }, [
566
+ (t) => h9("tr", { key: t.id }, [
486
567
  td([
487
568
  t.name,
488
- t.revokedAt ? h8("span", { style: styles.badge }, " revoked") : ""
569
+ t.revokedAt ? h9("span", { style: styles.badge }, " revoked") : ""
489
570
  ]),
490
571
  td(t.scopes.join(", "), styles.mono),
491
572
  td(
@@ -501,7 +582,7 @@ var TokensScreen = defineComponent7({
501
582
  styles.muted
502
583
  ),
503
584
  td(
504
- t.revokedAt ? "" : h8(
585
+ t.revokedAt ? "" : h9(
505
586
  "button",
506
587
  {
507
588
  type: "button",
@@ -519,21 +600,21 @@ var TokensScreen = defineComponent7({
519
600
  )
520
601
  ])
521
602
  )
522
- ) : h8("p", { style: styles.muted }, "None issued.")
603
+ ) : h9("p", { style: styles.muted }, "None issued.")
523
604
  ],
524
- h8("h2", { style: styles.subtitle }, "Legacy per-brick tokens"),
525
- r && r.legacy.length === 0 ? h8(
605
+ h9("h2", { style: styles.subtitle }, "Legacy per-brick tokens"),
606
+ r && r.legacy.length === 0 ? h9(
526
607
  "p",
527
608
  { style: styles.muted },
528
609
  "None \u2014 every brick's admin surface goes through this token."
529
- ) : h8(
610
+ ) : h9(
530
611
  "ul",
531
612
  { style: styles.list },
532
613
  (r?.legacy ?? []).map(
533
- (l) => h8("li", { key: l.module, style: styles.row }, [
534
- h8("span", { style: styles.mono }, l.module),
614
+ (l) => h9("li", { key: l.module, style: styles.row }, [
615
+ h9("span", { style: styles.mono }, l.module),
535
616
  " ",
536
- h8(
617
+ h9(
537
618
  "span",
538
619
  { style: styles.muted },
539
620
  "still registers its standalone routes with its own token (deprecated)"
@@ -553,8 +634,8 @@ import {
553
634
  useAdminUserSessions,
554
635
  useAdminUsers
555
636
  } from "@fonderie/vue-admin";
556
- import { computed, defineComponent as defineComponent8, h as h9, ref as ref2 } from "vue";
557
- var UsersScreen = defineComponent8({
637
+ import { computed, defineComponent as defineComponent9, h as h10, ref as ref2 } from "vue";
638
+ var UsersScreen = defineComponent9({
558
639
  name: "FonderieUsersScreen",
559
640
  props: {
560
641
  client: { type: Object, required: true },
@@ -573,8 +654,8 @@ var UsersScreen = defineComponent8({
573
654
  const sessions = useAdminUserSessions(props.client, userId);
574
655
  const history = useAdminLoginHistory(props.client, userId, { limit: 20 });
575
656
  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)]);
657
+ const yesNo = (v) => h10("span", { style: v ? styles.ok : styles.muted }, v ? "yes" : "no");
658
+ const row = (k, v) => h10("tr", [td(k), td(v)]);
578
659
  const clear = () => {
579
660
  email.value = "";
580
661
  selectedId.value = "";
@@ -582,9 +663,9 @@ var UsersScreen = defineComponent8({
582
663
  };
583
664
  return () => {
584
665
  const u = user.value;
585
- return h9("div", { style: styles.container }, [
586
- h9("h1", { style: styles.title }, "Users"),
587
- h9(
666
+ return h10("div", { style: styles.container }, [
667
+ h10("h1", { style: styles.title }, "Users"),
668
+ h10(
588
669
  "form",
589
670
  {
590
671
  style: styles.toolbar,
@@ -595,7 +676,7 @@ var UsersScreen = defineComponent8({
595
676
  }
596
677
  },
597
678
  [
598
- h9("input", {
679
+ h10("input", {
599
680
  type: "email",
600
681
  value: input.value,
601
682
  onInput: (e) => input.value = e.target.value,
@@ -603,7 +684,7 @@ var UsersScreen = defineComponent8({
603
684
  style: { ...styles.button, cursor: "text", minWidth: "280px" },
604
685
  "aria-label": "Email"
605
686
  }),
606
- h9(
687
+ h10(
607
688
  "button",
608
689
  { type: "submit", style: styles.button, disabled: isLoading.value },
609
690
  "Look up"
@@ -611,14 +692,14 @@ var UsersScreen = defineComponent8({
611
692
  showList.value ? refreshButton("Refresh", list.isLoading.value, () => void list.refresh()) : refreshButton("\u2190 All users", false, clear)
612
693
  ]
613
694
  ),
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(
695
+ showList.value ? h10("div", [
696
+ list.error.value ? h10("p", { style: styles.error, role: "alert" }, list.error.value.explanation) : null,
697
+ list.users.value.length === 0 && !list.isLoading.value ? h10("p", { style: styles.muted }, "No users yet.") : table(
617
698
  ["Email", "Name", "Created", "Status"],
618
699
  list.users.value.map(
619
- (u2) => h9("tr", { key: u2.id }, [
700
+ (u2) => h10("tr", { key: u2.id }, [
620
701
  td(
621
- h9(
702
+ h10(
622
703
  "button",
623
704
  {
624
705
  type: "button",
@@ -629,17 +710,17 @@ var UsersScreen = defineComponent8({
629
710
  )
630
711
  ),
631
712
  td(
632
- `${u2.firstName ?? ""} ${u2.lastName ?? ""}`.trim() || h9("span", { style: styles.muted }, "\u2014")
713
+ `${u2.firstName ?? ""} ${u2.lastName ?? ""}`.trim() || h10("span", { style: styles.muted }, "\u2014")
633
714
  ),
634
715
  td(new Date(u2.createdAt).toLocaleDateString()),
635
716
  td(
636
- u2.suspended ? h9("span", { style: styles.badge }, "suspended") : u2.deletedAt ? h9("span", { style: styles.badge }, "deleted") : h9("span", { style: styles.muted }, "active")
717
+ u2.suspended ? h10("span", { style: styles.badge }, "suspended") : u2.deletedAt ? h10("span", { style: styles.badge }, "deleted") : h10("span", { style: styles.muted }, "active")
637
718
  )
638
719
  ])
639
720
  )
640
721
  ),
641
- list.isLoading.value ? h9("p", { style: styles.status }, "Loading\u2026") : null,
642
- list.hasMore.value && !list.isLoading.value ? h9(
722
+ list.isLoading.value ? h10("p", { style: styles.status }, "Loading\u2026") : null,
723
+ list.hasMore.value && !list.isLoading.value ? h10(
643
724
  "button",
644
725
  {
645
726
  type: "button",
@@ -649,21 +730,21 @@ var UsersScreen = defineComponent8({
649
730
  "Load more"
650
731
  ) : null
651
732
  ]) : null,
652
- error.value ? h9(
733
+ error.value ? h10(
653
734
  "p",
654
735
  { style: styles.error, role: "alert" },
655
736
  error.value.status === 404 ? "No user with that email." : error.value.explanation
656
737
  ) : null,
657
738
  u ? [
658
- h9("h2", { style: styles.subtitle }, [
739
+ h10("h2", { style: styles.subtitle }, [
659
740
  u.firstName || u.lastName ? `${u.firstName} ${u.lastName}`.trim() : u.email,
660
741
  " ",
661
- u.suspended ? h9("span", { style: styles.badge }, "suspended") : null,
662
- u.deletedAt ? h9("span", { style: styles.badge }, "deleted") : null
742
+ u.suspended ? h10("span", { style: styles.badge }, "suspended") : null,
743
+ u.deletedAt ? h10("span", { style: styles.badge }, "deleted") : null
663
744
  ]),
664
- h9("table", { style: styles.table }, [
665
- h9("tbody", [
666
- row("id", h9("span", { style: styles.mono }, u.id)),
745
+ h10("table", { style: styles.table }, [
746
+ h10("tbody", [
747
+ row("id", h10("span", { style: styles.mono }, u.id)),
667
748
  row("email", [u.email, " \xB7 verified ", yesNo(u.isEmailVerified)]),
668
749
  row("MFA", yesNo(u.mfaEnabled)),
669
750
  row(
@@ -672,12 +753,12 @@ var UsersScreen = defineComponent8({
672
753
  ),
673
754
  row(
674
755
  "last login",
675
- u.lastLogin ? new Date(u.lastLogin).toLocaleString() : h9("span", { style: styles.muted }, "never")
756
+ u.lastLogin ? new Date(u.lastLogin).toLocaleString() : h10("span", { style: styles.muted }, "never")
676
757
  ),
677
758
  row("created", new Date(u.createdAt).toLocaleString())
678
759
  ])
679
760
  ]),
680
- h9("div", { style: { ...styles.toolbar, marginTop: "12px" } }, [
761
+ h10("div", { style: { ...styles.toolbar, marginTop: "12px" } }, [
681
762
  u.suspended ? refreshButton("Unsuspend", isLoading.value, () => void unsuspend()) : refreshButton("Suspend", isLoading.value, () => void suspend()),
682
763
  refreshButton(
683
764
  "Sign out everywhere",
@@ -685,17 +766,17 @@ var UsersScreen = defineComponent8({
685
766
  () => void revokeSessions().then(() => sessions.refresh())
686
767
  )
687
768
  ]),
688
- h9("h2", { style: styles.subtitle }, "Live sessions"),
689
- sessions.sessions.value.length === 0 ? h9("p", { style: styles.muted }, "None.") : h9(
769
+ h10("h2", { style: styles.subtitle }, "Live sessions"),
770
+ sessions.sessions.value.length === 0 ? h10("p", { style: styles.muted }, "None.") : h10(
690
771
  "ul",
691
772
  { style: styles.list },
692
773
  sessions.sessions.value.map(
693
- (s) => h9("li", { key: s.id, style: styles.row }, [
694
- h9("span", { style: styles.mono }, s.ipAddress ?? "\u2014"),
774
+ (s) => h10("li", { key: s.id, style: styles.row }, [
775
+ h10("span", { style: styles.mono }, s.ipAddress ?? "\u2014"),
695
776
  " ",
696
- h9("span", { style: styles.muted }, s.userAgent ?? ""),
777
+ h10("span", { style: styles.muted }, s.userAgent ?? ""),
697
778
  " ",
698
- h9(
779
+ h10(
699
780
  "span",
700
781
  { style: styles.muted },
701
782
  `since ${new Date(s.createdAt).toLocaleString()}`
@@ -703,25 +784,25 @@ var UsersScreen = defineComponent8({
703
784
  ])
704
785
  )
705
786
  ),
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(
787
+ h10("h2", { style: styles.subtitle }, "Recent sign-ins"),
788
+ history.events.value.length === 0 && !history.isLoading.value ? h10("p", { style: styles.muted }, "None recorded.") : h10(
708
789
  "ul",
709
790
  { style: styles.list },
710
791
  history.events.value.map(
711
- (e) => h9("li", { key: e.id, style: styles.row }, [
712
- h9(
792
+ (e) => h10("li", { key: e.id, style: styles.row }, [
793
+ h10(
713
794
  "span",
714
795
  { style: e.outcome === "success" ? styles.ok : styles.bad },
715
796
  e.outcome
716
797
  ),
717
798
  " ",
718
- h9("span", { style: styles.muted }, e.method),
799
+ h10("span", { style: styles.muted }, e.method),
719
800
  " ",
720
- h9("span", { style: styles.muted }, new Date(e.createdAt).toLocaleString())
801
+ h10("span", { style: styles.muted }, new Date(e.createdAt).toLocaleString())
721
802
  ])
722
803
  )
723
804
  ),
724
- history.hasMore.value && !history.isLoading.value ? h9(
805
+ history.hasMore.value && !history.isLoading.value ? h10(
725
806
  "button",
726
807
  {
727
808
  type: "button",
@@ -738,8 +819,8 @@ var UsersScreen = defineComponent8({
738
819
 
739
820
  // src/screens/CatalogScreen.ts
740
821
  import { useAdminCatalog } from "@fonderie/vue-admin";
741
- import { defineComponent as defineComponent9, h as h10 } from "vue";
742
- var CatalogScreen = defineComponent9({
822
+ import { defineComponent as defineComponent10, h as h11 } from "vue";
823
+ var CatalogScreen = defineComponent10({
743
824
  name: "FonderieCatalogScreen",
744
825
  props: { client: { type: Object, required: true } },
745
826
  setup(props) {
@@ -747,16 +828,16 @@ var CatalogScreen = defineComponent9({
747
828
  const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
748
829
  return () => {
749
830
  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"),
831
+ return h11("div", { style: styles.container }, [
832
+ h11("div", { style: styles.toolbar }, [
833
+ h11("h1", { style: { ...styles.title, marginBottom: 0 } }, "Catalog"),
753
834
  refreshButton("Refresh", isLoading.value, () => void refresh())
754
835
  ]),
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,
836
+ error.value ? h11("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
837
+ isLoading.value && !c ? h11("p", { style: styles.status }, "Loading\u2026") : null,
757
838
  c ? [
758
- h10("h2", { style: styles.subtitle }, "Configured (code)"),
759
- h10(
839
+ h11("h2", { style: styles.subtitle }, "Configured (code)"),
840
+ h11(
760
841
  "pre",
761
842
  {
762
843
  style: {
@@ -768,14 +849,14 @@ var CatalogScreen = defineComponent9({
768
849
  },
769
850
  JSON.stringify(c.configured, null, 2)
770
851
  ),
771
- h10("h2", { style: styles.subtitle }, "Stored (database)"),
772
- c.stored.length === 0 ? h10("p", { style: styles.muted }, "No stored plans.") : table(
852
+ h11("h2", { style: styles.subtitle }, "Stored (database)"),
853
+ c.stored.length === 0 ? h11("p", { style: styles.muted }, "No stored plans.") : table(
773
854
  ["Plan", "Tier", "Seats", "Monthly", "Yearly", "Trial", ""],
774
855
  c.stored.map(
775
- (p) => h10("tr", { key: p.id }, [
856
+ (p) => h11("tr", { key: p.id }, [
776
857
  td([
777
- h10("strong", p.name),
778
- p.description ? h10("div", { style: styles.muted }, p.description) : ""
858
+ h11("strong", p.name),
859
+ p.description ? h11("div", { style: styles.muted }, p.description) : ""
779
860
  ]),
780
861
  td(String(p.tier)),
781
862
  td(p.seats == null ? "\u221E" : String(p.seats)),
@@ -783,7 +864,7 @@ var CatalogScreen = defineComponent9({
783
864
  td(money(p.pricing?.yearly)),
784
865
  td(p.trialDays ? `${p.trialDays} d` : "\u2014"),
785
866
  td(
786
- h10(
867
+ h11(
787
868
  "button",
788
869
  {
789
870
  type: "button",
@@ -808,8 +889,8 @@ var CatalogScreen = defineComponent9({
808
889
 
809
890
  // src/screens/SubscriberScreen.ts
810
891
  import { useAdminSubscriber, useAdminSubscribers } from "@fonderie/vue-admin";
811
- import { defineComponent as defineComponent10, h as h11, ref as ref3 } from "vue";
812
- var SubscriberScreen = defineComponent10({
892
+ import { defineComponent as defineComponent11, h as h12, ref as ref3 } from "vue";
893
+ var SubscriberScreen = defineComponent11({
813
894
  name: "FonderieSubscriberScreen",
814
895
  props: {
815
896
  client: { type: Object, required: true },
@@ -830,7 +911,7 @@ var SubscriberScreen = defineComponent10({
830
911
  const amount = ref3("");
831
912
  const note = ref3("");
832
913
  const granted = ref3(null);
833
- const input = (model, placeholder, extra = {}) => h11("input", {
914
+ const input = (model, placeholder, extra = {}) => h12("input", {
834
915
  value: model.value,
835
916
  onInput: (e) => model.value = e.target.value,
836
917
  placeholder,
@@ -840,9 +921,9 @@ var SubscriberScreen = defineComponent10({
840
921
  return () => {
841
922
  const s = subscription.value;
842
923
  const w = wallet.value;
843
- return h11("div", { style: styles.container }, [
844
- h11("h1", { style: styles.title }, "Subscriber"),
845
- h11(
924
+ return h12("div", { style: styles.container }, [
925
+ h12("h1", { style: styles.title }, "Subscriber"),
926
+ h12(
846
927
  "form",
847
928
  {
848
929
  style: styles.toolbar,
@@ -853,7 +934,7 @@ var SubscriberScreen = defineComponent10({
853
934
  }
854
935
  },
855
936
  [
856
- h11(
937
+ h12(
857
938
  "select",
858
939
  {
859
940
  value: type.value,
@@ -862,17 +943,17 @@ var SubscriberScreen = defineComponent10({
862
943
  "aria-label": "Type"
863
944
  },
864
945
  [
865
- h11("option", { value: "user" }, "user"),
866
- h11("option", { value: "workspace" }, "workspace")
946
+ h12("option", { value: "user" }, "user"),
947
+ h12("option", { value: "workspace" }, "workspace")
867
948
  ]
868
949
  ),
869
950
  input(idInput, "subscriber id", { minWidth: "280px" }),
870
- h11(
951
+ h12(
871
952
  "button",
872
953
  { type: "submit", style: styles.button, disabled: isLoading.value },
873
954
  "Look up"
874
955
  ),
875
- subscriber.value ? h11(
956
+ subscriber.value ? h12(
876
957
  "button",
877
958
  {
878
959
  type: "button",
@@ -884,7 +965,7 @@ var SubscriberScreen = defineComponent10({
884
965
  }
885
966
  },
886
967
  "\u2190 All subscribers"
887
- ) : h11(
968
+ ) : h12(
888
969
  "button",
889
970
  {
890
971
  type: "button",
@@ -896,14 +977,14 @@ var SubscriberScreen = defineComponent10({
896
977
  )
897
978
  ]
898
979
  ),
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(
980
+ !subscriber.value ? h12("div", [
981
+ list.error.value ? h12("p", { style: styles.error, role: "alert" }, list.error.value.explanation) : null,
982
+ list.subscriptions.value.length === 0 && !list.isLoading.value ? h12("p", { style: styles.muted }, "No subscribers yet.") : table(
902
983
  ["Subscriber", "Plan", "Status", "Renews"],
903
984
  list.subscriptions.value.map(
904
- (sub) => h11("tr", { key: sub.id }, [
985
+ (sub) => h12("tr", { key: sub.id }, [
905
986
  td(
906
- h11(
987
+ h12(
907
988
  "button",
908
989
  {
909
990
  type: "button",
@@ -915,16 +996,16 @@ var SubscriberScreen = defineComponent10({
915
996
  ),
916
997
  td(`${sub.plan} \xB7 ${sub.interval}`),
917
998
  td(
918
- sub.cancelAtPeriodEnd ? [sub.status, " ", h11("span", { style: styles.badge }, "cancels")] : sub.status
999
+ sub.cancelAtPeriodEnd ? [sub.status, " ", h12("span", { style: styles.badge }, "cancels")] : sub.status
919
1000
  ),
920
1001
  td(
921
- sub.currentPeriodEnd ? new Date(sub.currentPeriodEnd).toLocaleDateString() : h11("span", { style: styles.muted }, "\u2014")
1002
+ sub.currentPeriodEnd ? new Date(sub.currentPeriodEnd).toLocaleDateString() : h12("span", { style: styles.muted }, "\u2014")
922
1003
  )
923
1004
  ])
924
1005
  )
925
1006
  ),
926
- list.isLoading.value ? h11("p", { style: styles.status }, "Loading\u2026") : null,
927
- list.hasMore.value && !list.isLoading.value ? h11(
1007
+ list.isLoading.value ? h12("p", { style: styles.status }, "Loading\u2026") : null,
1008
+ list.hasMore.value && !list.isLoading.value ? h12(
928
1009
  "button",
929
1010
  {
930
1011
  type: "button",
@@ -934,37 +1015,37 @@ var SubscriberScreen = defineComponent10({
934
1015
  "Load more"
935
1016
  ) : null
936
1017
  ]) : null,
937
- error.value ? h11("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
1018
+ error.value ? h12("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
938
1019
  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", [
1020
+ h12("h2", { style: styles.subtitle }, "Subscription"),
1021
+ s ? h12("table", { style: styles.table }, [
1022
+ h12("tbody", [
1023
+ h12("tr", [td("plan"), td([h12("strong", s.plan), ` \xB7 ${s.interval}`])]),
1024
+ h12("tr", [
944
1025
  td("status"),
945
1026
  td(`${s.status}${s.cancelAtPeriodEnd ? " \xB7 cancels at period end" : ""}`)
946
1027
  ]),
947
- h11("tr", [
1028
+ h12("tr", [
948
1029
  td("period"),
949
1030
  td(
950
1031
  `${s.currentPeriodStart ? new Date(s.currentPeriodStart).toLocaleDateString() : "\u2014"} \u2192 ${s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : "\u2014"}`
951
1032
  )
952
1033
  ]),
953
- h11("tr", [td("provider"), td(s.providerSubscriptionId ?? "\u2014", styles.mono)])
1034
+ h12("tr", [td("provider"), td(s.providerSubscriptionId ?? "\u2014", styles.mono)])
954
1035
  ])
955
- ]) : h11("p", { style: styles.muted }, "No subscription."),
956
- h11("h2", { style: styles.subtitle }, "Wallet"),
1036
+ ]) : h12("p", { style: styles.muted }, "No subscription."),
1037
+ h12("h2", { style: styles.subtitle }, "Wallet"),
957
1038
  w ? [
958
- h11("p", [
959
- h11("strong", w.balance),
1039
+ h12("p", [
1040
+ h12("strong", w.balance),
960
1041
  ` ${w.currency} `,
961
- h11(
1042
+ h12(
962
1043
  "span",
963
1044
  { style: styles.muted },
964
1045
  `(granted ${w.granted ?? "0"} \xB7 purchased ${w.purchased ?? "0"}) \xB7 minor units, precision ${w.precision}`
965
1046
  )
966
1047
  ]),
967
- h11(
1048
+ h12(
968
1049
  "form",
969
1050
  {
970
1051
  style: styles.toolbar,
@@ -989,7 +1070,7 @@ var SubscriberScreen = defineComponent10({
989
1070
  [
990
1071
  input(amount, "amount (minor units)"),
991
1072
  input(note, "reason (optional)", { minWidth: "220px" }),
992
- h11(
1073
+ h12(
993
1074
  "button",
994
1075
  {
995
1076
  type: "submit",
@@ -998,14 +1079,14 @@ var SubscriberScreen = defineComponent10({
998
1079
  },
999
1080
  "Grant"
1000
1081
  ),
1001
- granted.value ? h11("span", { style: styles.ok }, granted.value) : null
1082
+ granted.value ? h12("span", { style: styles.ok }, granted.value) : null
1002
1083
  ]
1003
1084
  ),
1004
- h11("h2", { style: styles.subtitle }, "Ledger"),
1005
- ledger.value.length === 0 ? h11("p", { style: styles.muted }, "Nothing moved yet.") : table(
1085
+ h12("h2", { style: styles.subtitle }, "Ledger"),
1086
+ ledger.value.length === 0 ? h12("p", { style: styles.muted }, "Nothing moved yet.") : table(
1006
1087
  ["When", "Kind", "Amount", "Note"],
1007
1088
  ledger.value.map(
1008
- (t) => h11("tr", { key: t.id }, [
1089
+ (t) => h12("tr", { key: t.id }, [
1009
1090
  td(new Date(t.createdAt).toLocaleString(), styles.muted),
1010
1091
  td(t.type),
1011
1092
  td(t.amount, styles.mono),
@@ -1013,7 +1094,7 @@ var SubscriberScreen = defineComponent10({
1013
1094
  ])
1014
1095
  )
1015
1096
  ),
1016
- hasMoreLedger.value ? h11(
1097
+ hasMoreLedger.value ? h12(
1017
1098
  "button",
1018
1099
  {
1019
1100
  type: "button",
@@ -1022,7 +1103,7 @@ var SubscriberScreen = defineComponent10({
1022
1103
  },
1023
1104
  "Load more"
1024
1105
  ) : null
1025
- ] : h11(
1106
+ ] : h12(
1026
1107
  "p",
1027
1108
  { style: styles.muted },
1028
1109
  "No wallet \u2014 billing has no wallet configuration."
@@ -1035,8 +1116,8 @@ var SubscriberScreen = defineComponent10({
1035
1116
 
1036
1117
  // src/screens/AuditScreen.ts
1037
1118
  import { useAdminAudit } from "@fonderie/vue-admin";
1038
- import { defineComponent as defineComponent11, h as h12, ref as ref4 } from "vue";
1039
- var AuditScreen = defineComponent11({
1119
+ import { defineComponent as defineComponent12, h as h13, ref as ref4 } from "vue";
1120
+ var AuditScreen = defineComponent12({
1040
1121
  name: "FonderieAuditScreen",
1041
1122
  props: {
1042
1123
  client: { type: Object, required: true },
@@ -1049,16 +1130,16 @@ var AuditScreen = defineComponent11({
1049
1130
  props.client,
1050
1131
  query
1051
1132
  );
1052
- const field = (key, placeholder) => h12("input", {
1133
+ const field = (key, placeholder) => h13("input", {
1053
1134
  value: draft.value[key],
1054
1135
  onInput: (e) => draft.value = { ...draft.value, [key]: e.target.value },
1055
1136
  placeholder,
1056
1137
  style: { ...styles.button, cursor: "text" },
1057
1138
  "aria-label": placeholder
1058
1139
  });
1059
- return () => h12("div", { style: styles.container }, [
1060
- h12("h1", { style: styles.title }, "Audit"),
1061
- h12(
1140
+ return () => h13("div", { style: styles.container }, [
1141
+ h13("h1", { style: styles.title }, "Audit"),
1142
+ h13(
1062
1143
  "form",
1063
1144
  {
1064
1145
  style: styles.toolbar,
@@ -1077,7 +1158,7 @@ var AuditScreen = defineComponent11({
1077
1158
  field("workspaceId", "workspace id (all if empty)"),
1078
1159
  field("type", "event type"),
1079
1160
  field("actorId", "actor id"),
1080
- h12(
1161
+ h13(
1081
1162
  "button",
1082
1163
  { type: "submit", style: styles.button, disabled: isLoading.value },
1083
1164
  "Filter"
@@ -1085,11 +1166,11 @@ var AuditScreen = defineComponent11({
1085
1166
  refreshButton("Refresh", isLoading.value, () => void refresh())
1086
1167
  ]
1087
1168
  ),
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(
1169
+ error.value ? h13("p", { style: styles.error, role: "alert" }, error.value.explanation) : null,
1170
+ events.value.length === 0 && !isLoading.value ? h13("p", { style: styles.muted }, "Nothing recorded for this filter.") : table(
1090
1171
  ["When", "Type", "Workspace", "Actor", "Request"],
1091
1172
  events.value.map(
1092
- (e) => h12("tr", { key: e.id }, [
1173
+ (e) => h13("tr", { key: e.id }, [
1093
1174
  td(new Date(e.createdAt).toLocaleString(), styles.muted),
1094
1175
  td(e.type, styles.mono),
1095
1176
  td(String(e.payload["workspaceId"] ?? "\u2014"), styles.mono),
@@ -1098,8 +1179,8 @@ var AuditScreen = defineComponent11({
1098
1179
  ])
1099
1180
  )
1100
1181
  ),
1101
- isLoading.value ? h12("p", { style: styles.status }, "Loading\u2026") : null,
1102
- hasMore.value && !isLoading.value ? h12(
1182
+ isLoading.value ? h13("p", { style: styles.status }, "Loading\u2026") : null,
1183
+ hasMore.value && !isLoading.value ? h13(
1103
1184
  "button",
1104
1185
  {
1105
1186
  type: "button",
@@ -1139,11 +1220,12 @@ var NAV = [
1139
1220
  items: [
1140
1221
  { page: "audit", label: "Audit", needs: "audit" },
1141
1222
  { page: "log", label: "Admin log" },
1142
- { page: "tokens", label: "Access" }
1223
+ { page: "tokens", label: "Access" },
1224
+ { page: "migrations", label: "Migrations" }
1143
1225
  ]
1144
1226
  }
1145
1227
  ];
1146
- var AdminShell = defineComponent12({
1228
+ var AdminShell = defineComponent13({
1147
1229
  name: "FonderieAdminShell",
1148
1230
  props: {
1149
1231
  client: { type: Object, required: true },
@@ -1172,7 +1254,7 @@ var AdminShell = defineComponent12({
1172
1254
  emit("navigate", p);
1173
1255
  if (props.page === void 0) own.value = p;
1174
1256
  };
1175
- const back = () => h13(
1257
+ const back = () => h14(
1176
1258
  "button",
1177
1259
  { type: "button", style: styles.button, onClick: () => editing.value = null },
1178
1260
  "\u2190 Back"
@@ -1181,43 +1263,45 @@ var AdminShell = defineComponent12({
1181
1263
  const c = props.client;
1182
1264
  switch (current.value) {
1183
1265
  case "attention":
1184
- return h13(AttentionScreen, { client: c });
1266
+ return h14(AttentionScreen, { client: c });
1185
1267
  case "modules":
1186
- return h13(ModulesScreen, { client: c });
1268
+ return h14(ModulesScreen, { client: c });
1187
1269
  case "doctor":
1188
- return h13(DoctorScreen, { client: c });
1270
+ return h14(DoctorScreen, { client: c });
1189
1271
  case "config":
1190
- return h13(ConfigScreen, { client: c });
1272
+ return h14(ConfigScreen, { client: c });
1191
1273
  case "routes":
1192
- return h13(RoutesScreen, { client: c });
1274
+ return h14(RoutesScreen, { client: c });
1193
1275
  case "tokens":
1194
- return h13(TokensScreen, { client: c });
1276
+ return h14(TokensScreen, { client: c });
1277
+ case "migrations":
1278
+ return h14(MigrationsScreen, { client: c });
1195
1279
  case "log":
1196
- return h13(AdminLogScreen, { client: c });
1280
+ return h14(AdminLogScreen, { client: c });
1197
1281
  case "catalog":
1198
- return props.billingClient ? h13(CatalogScreen, { client: props.billingClient }) : h13(
1282
+ return props.billingClient ? h14(CatalogScreen, { client: props.billingClient }) : h14(
1199
1283
  "p",
1200
1284
  { style: styles.status },
1201
1285
  "Pass a BillingAdminClient to see the catalog here."
1202
1286
  );
1203
1287
  case "subscriber":
1204
- return props.billingClient ? h13(SubscriberScreen, { client: props.billingClient }) : h13(
1288
+ return props.billingClient ? h14(SubscriberScreen, { client: props.billingClient }) : h14(
1205
1289
  "p",
1206
1290
  { style: styles.status },
1207
1291
  "Pass a BillingAdminClient to look up subscribers here."
1208
1292
  );
1209
1293
  case "audit":
1210
- return props.auditClient ? h13(AuditScreen, { client: props.auditClient }) : h13(
1294
+ return props.auditClient ? h14(AuditScreen, { client: props.auditClient }) : h14(
1211
1295
  "p",
1212
1296
  { style: styles.status },
1213
1297
  "Pass an AuditAdminClient to see the audit trail here."
1214
1298
  );
1215
1299
  case "users":
1216
- return props.authClient ? h13(UsersScreen, { client: props.authClient }) : h13("p", { style: styles.status }, "Pass an AuthAdminClient to look up users here.");
1300
+ return props.authClient ? h14(UsersScreen, { client: props.authClient }) : h14("p", { style: styles.status }, "Pass an AuthAdminClient to look up users here.");
1217
1301
  case "settings": {
1218
1302
  const cc = props.configClient;
1219
1303
  if (!cc)
1220
- return h13(
1304
+ return h14(
1221
1305
  "p",
1222
1306
  { style: styles.status },
1223
1307
  "Pass a ConfigAdminClient to manage config and secrets here."
@@ -1226,7 +1310,7 @@ var AdminShell = defineComponent12({
1226
1310
  if (e && e.kind !== "template")
1227
1311
  return [
1228
1312
  back(),
1229
- h13(ConfigEditorScreen, {
1313
+ h14(ConfigEditorScreen, {
1230
1314
  client: cc,
1231
1315
  kind: e.kind,
1232
1316
  configKey: e.key,
@@ -1234,7 +1318,7 @@ var AdminShell = defineComponent12({
1234
1318
  onSaved: () => editing.value = null
1235
1319
  })
1236
1320
  ];
1237
- return h13(ConfigListScreen, {
1321
+ return h14(ConfigListScreen, {
1238
1322
  client: cc,
1239
1323
  ...props.environment !== void 0 ? { environment: props.environment } : {},
1240
1324
  "onSelect-config": (key) => editing.value = { kind: "config", key },
@@ -1244,7 +1328,7 @@ var AdminShell = defineComponent12({
1244
1328
  case "templates": {
1245
1329
  const kc = props.courierClient;
1246
1330
  if (!kc)
1247
- return h13(
1331
+ return h14(
1248
1332
  "p",
1249
1333
  { style: styles.status },
1250
1334
  "Pass a CourierAdminClient to manage templates here."
@@ -1253,21 +1337,21 @@ var AdminShell = defineComponent12({
1253
1337
  if (e?.kind === "template")
1254
1338
  return [
1255
1339
  back(),
1256
- h13(TemplateEditorScreen, {
1340
+ h14(TemplateEditorScreen, {
1257
1341
  client: kc,
1258
1342
  type: e.type,
1259
1343
  onSaved: () => editing.value = null
1260
1344
  })
1261
1345
  ];
1262
- return h13(TemplateListScreen, {
1346
+ return h14(TemplateListScreen, {
1263
1347
  client: kc,
1264
1348
  "onSelect-template": (t) => editing.value = { kind: "template", type: t.type }
1265
1349
  });
1266
1350
  }
1267
1351
  }
1268
1352
  };
1269
- return () => h13("div", { style: styles.shell }, [
1270
- h13(
1353
+ return () => h14("div", { style: styles.shell }, [
1354
+ h14(
1271
1355
  "nav",
1272
1356
  { style: styles.nav, "aria-label": "Admin" },
1273
1357
  NAV.map((g) => {
@@ -1275,10 +1359,10 @@ var AdminShell = defineComponent12({
1275
1359
  (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
1360
  );
1277
1361
  if (items.length === 0) return null;
1278
- return h13("div", { key: g.group }, [
1279
- h13("div", { style: styles.navGroup }, g.group),
1362
+ return h14("div", { key: g.group }, [
1363
+ h14("div", { style: styles.navGroup }, g.group),
1280
1364
  ...items.map(
1281
- (i) => h13(
1365
+ (i) => h14(
1282
1366
  "button",
1283
1367
  {
1284
1368
  key: i.page,
@@ -1296,7 +1380,7 @@ var AdminShell = defineComponent12({
1296
1380
  ]);
1297
1381
  })
1298
1382
  ),
1299
- h13("main", { style: styles.main }, body())
1383
+ h14("main", { style: styles.main }, body())
1300
1384
  ]);
1301
1385
  }
1302
1386
  });
@@ -1308,6 +1392,7 @@ export {
1308
1392
  CatalogScreen,
1309
1393
  ConfigScreen,
1310
1394
  DoctorScreen,
1395
+ MigrationsScreen,
1311
1396
  ModulesScreen,
1312
1397
  RoutesScreen,
1313
1398
  SubscriberScreen,