@fonderie/react-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.cjs CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
27
27
  CatalogScreen: () => CatalogScreen,
28
28
  ConfigScreen: () => ConfigScreen,
29
29
  DoctorScreen: () => DoctorScreen,
30
+ MigrationsScreen: () => MigrationsScreen,
30
31
  ModulesScreen: () => ModulesScreen,
31
32
  RoutesScreen: () => RoutesScreen,
32
33
  SubscriberScreen: () => SubscriberScreen,
@@ -344,37 +345,101 @@ function RoutesScreen({ client }) {
344
345
  ] });
345
346
  }
346
347
 
347
- // src/screens/TokensScreen.tsx
348
+ // src/screens/MigrationsScreen.tsx
348
349
  var import_react_admin7 = require("@fonderie/react-admin");
349
- var import_react = require("react");
350
350
  var import_jsx_runtime7 = require("react/jsx-runtime");
351
+ function why(m, everApplied) {
352
+ if (m.pending.length === 0) return null;
353
+ if (m.blockedBy) return `Apply "${m.blockedBy}" first \u2014 it runs before this one and is behind.`;
354
+ if (everApplied && m.pending.some((p) => p.impact === "destructive"))
355
+ return "Contains a migration that deletes data. No down-migration brings it back \u2014 apply this one through CI or `npm run migrate`.";
356
+ return null;
357
+ }
358
+ function MigrationsScreen({ client }) {
359
+ const { report, isLoading, error, refresh, apply } = (0, import_react_admin7.useAdminMigrations)(client);
360
+ const behind = report?.modules.filter((m) => m.pending.length > 0) ?? [];
361
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.container, children: [
362
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { style: styles.title, children: "Migrations" }),
363
+ error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.error, role: "alert", children: error.status === 403 ? "Applying migrations needs a token with the write scope." : error.explanation }) : null,
364
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { children: [
365
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: styles.button, onClick: () => void refresh(), disabled: isLoading, children: isLoading ? "Checking\u2026" : "Refresh" }),
366
+ " ",
367
+ report && !report.everApplied ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.advice, children: "This database has never been migrated \u2014 treating it as a first install, so nothing is held back." }) : null
368
+ ] }),
369
+ report && behind.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.ok, children: "Every module is up to date." }) : null,
370
+ behind.map((m) => {
371
+ const blocked = why(m, report?.everApplied ?? false);
372
+ const files = m.pending.map((p) => p.file);
373
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { style: { marginBottom: 24 }, children: [
374
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("h2", { style: styles.subtitle, children: [
375
+ m.name,
376
+ " \u2014 ",
377
+ m.pending.length,
378
+ " pending"
379
+ ] }),
380
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { children: m.pending.map((p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { children: [
381
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: p.file }),
382
+ " ",
383
+ p.impact === "destructive" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.bad, children: "destructive" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.advice, children: "additive" }),
384
+ p.destructive.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { children: p.destructive.map((s) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: s.slice(0, 120) }) }, s)) }) : null
385
+ ] }, p.file)) }),
386
+ blocked ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.advice, children: blocked }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
387
+ "button",
388
+ {
389
+ type: "button",
390
+ style: styles.button,
391
+ disabled: isLoading || !m.appliable,
392
+ onClick: () => {
393
+ if (window.confirm(
394
+ `Apply ${m.pending.length} migration(s) to "${m.name}"? This changes the database schema.`
395
+ ))
396
+ void apply(m.name, files).catch(() => {
397
+ });
398
+ },
399
+ children: [
400
+ "Apply ",
401
+ m.pending.length,
402
+ " migration",
403
+ m.pending.length === 1 ? "" : "s"
404
+ ]
405
+ }
406
+ )
407
+ ] }, m.name);
408
+ })
409
+ ] });
410
+ }
411
+
412
+ // src/screens/TokensScreen.tsx
413
+ var import_react_admin8 = require("@fonderie/react-admin");
414
+ var import_react = require("react");
415
+ var import_jsx_runtime8 = require("react/jsx-runtime");
351
416
  var ALL = ["read", "write", "secrets"];
352
417
  function TokensScreen({ client }) {
353
- const { report, isLoading, error, issue, revoke } = (0, import_react_admin7.useAdminTokens)(client);
418
+ const { report, isLoading, error, issue, revoke } = (0, import_react_admin8.useAdminTokens)(client);
354
419
  const [name, setName] = (0, import_react.useState)("");
355
420
  const [scopes, setScopes] = (0, import_react.useState)(["read"]);
356
421
  const [days, setDays] = (0, import_react.useState)("");
357
422
  const [minted, setMinted] = (0, import_react.useState)(null);
358
423
  const toggle = (s) => setScopes((prev) => prev.includes(s) ? prev.filter((x) => x !== s) : [...prev, s]);
359
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: styles.container, children: [
360
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { style: styles.title, children: "Access" }),
361
- error ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.error, role: "alert", children: error.status === 401 ? "Issuing and revoking need the root token (the one in your deployment config)." : error.explanation }) : null,
362
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: styles.subtitle, children: "Root token" }),
363
- report ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { children: [
364
- report.admin.ok ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.ok, children: "strong" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.bad, children: "weak" }),
365
- report.admin.problems.map((p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: styles.bad, children: p.message }, p.message))
424
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.container, children: [
425
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h1", { style: styles.title, children: "Access" }),
426
+ error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.error, role: "alert", children: error.status === 401 ? "Issuing and revoking need the root token (the one in your deployment config)." : error.explanation }) : null,
427
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { style: styles.subtitle, children: "Root token" }),
428
+ report ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { children: [
429
+ report.admin.ok ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.ok, children: "strong" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.bad, children: "weak" }),
430
+ report.admin.problems.map((p) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: styles.bad, children: p.message }, p.message))
366
431
  ] }) : null,
367
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: styles.subtitle, children: "Issued tokens" }),
368
- report?.issued === null ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.muted, children: "Issuing is off \u2014 give AdminModule a store and run its migrations." }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
369
- minted ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: styles.ok, children: [
432
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { style: styles.subtitle, children: "Issued tokens" }),
433
+ report?.issued === null ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.muted, children: "Issuing is off \u2014 give AdminModule a store and run its migrations." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
434
+ minted ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("p", { style: styles.ok, children: [
370
435
  "Copy this now \u2014 it is never shown again.",
371
436
  " ",
372
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.mono, children: minted.token }),
437
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.mono, children: minted.token }),
373
438
  " (",
374
439
  minted.name,
375
440
  ")"
376
441
  ] }) : null,
377
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
442
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
378
443
  "form",
379
444
  {
380
445
  style: styles.toolbar,
@@ -393,7 +458,7 @@ function TokensScreen({ client }) {
393
458
  });
394
459
  },
395
460
  children: [
396
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
461
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
397
462
  "input",
398
463
  {
399
464
  value: name,
@@ -403,12 +468,12 @@ function TokensScreen({ client }) {
403
468
  "aria-label": "Name"
404
469
  }
405
470
  ),
406
- ALL.map((s) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: { ...styles.badge, cursor: "pointer" }, children: [
407
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: scopes.includes(s), onChange: () => toggle(s) }),
471
+ ALL.map((s) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { style: { ...styles.badge, cursor: "pointer" }, children: [
472
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("input", { type: "checkbox", checked: scopes.includes(s), onChange: () => toggle(s) }),
408
473
  " ",
409
474
  s
410
475
  ] }, s)),
411
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
476
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
412
477
  "input",
413
478
  {
414
479
  value: days,
@@ -418,7 +483,7 @@ function TokensScreen({ client }) {
418
483
  "aria-label": "Days"
419
484
  }
420
485
  ),
421
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
486
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
422
487
  "button",
423
488
  {
424
489
  type: "submit",
@@ -430,29 +495,29 @@ function TokensScreen({ client }) {
430
495
  ]
431
496
  }
432
497
  ),
433
- report?.issued && report.issued.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("table", { style: styles.table, children: [
434
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("tr", { children: [
435
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th, children: "Name" }),
436
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th, children: "Scopes" }),
437
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th, children: "Created" }),
438
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th, children: "Expires" }),
439
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th, children: "Last used" }),
440
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("th", { style: styles.th })
498
+ report?.issued && report.issued.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("table", { style: styles.table, children: [
499
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
500
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Name" }),
501
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Scopes" }),
502
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Created" }),
503
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Expires" }),
504
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Last used" }),
505
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th })
441
506
  ] }) }),
442
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("tbody", { children: report.issued.map((t) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("tr", { children: [
443
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("td", { style: styles.td, children: [
507
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tbody", { children: report.issued.map((t) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
508
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("td", { style: styles.td, children: [
444
509
  t.name,
445
- t.revokedAt ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.badge, children: " revoked" }) : null
510
+ t.revokedAt ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.badge, children: " revoked" }) : null
446
511
  ] }),
447
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: t.scopes.join(", ") }),
448
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("td", { style: { ...styles.td, ...styles.muted }, children: [
512
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: t.scopes.join(", ") }),
513
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("td", { style: { ...styles.td, ...styles.muted }, children: [
449
514
  new Date(t.createdAt).toLocaleDateString(),
450
515
  " \xB7 ",
451
516
  t.createdBy
452
517
  ] }),
453
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t.expiresAt ? new Date(t.expiresAt).toLocaleDateString() : "never" }),
454
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t.lastUsedAt ? new Date(t.lastUsedAt).toLocaleString() : "never" }),
455
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("td", { style: styles.td, children: t.revokedAt ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
518
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t.expiresAt ? new Date(t.expiresAt).toLocaleDateString() : "never" }),
519
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t.lastUsedAt ? new Date(t.lastUsedAt).toLocaleString() : "never" }),
520
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: t.revokedAt ? null : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
456
521
  "button",
457
522
  {
458
523
  type: "button",
@@ -468,40 +533,40 @@ function TokensScreen({ client }) {
468
533
  }
469
534
  ) })
470
535
  ] }, t.id)) })
471
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.muted, children: "None issued." })
536
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.muted, children: "None issued." })
472
537
  ] }),
473
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { style: styles.subtitle, children: "Legacy per-brick tokens" }),
474
- report && report.legacy.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { style: styles.muted, children: "None \u2014 every brick's admin surface goes through this token." }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { style: styles.list, children: report?.legacy.map((l) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { style: styles.row, children: [
475
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.mono, children: l.module }),
538
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { style: styles.subtitle, children: "Legacy per-brick tokens" }),
539
+ report && report.legacy.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.muted, children: "None \u2014 every brick's admin surface goes through this token." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { style: styles.list, children: report?.legacy.map((l) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { style: styles.row, children: [
540
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.mono, children: l.module }),
476
541
  " ",
477
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: styles.muted, children: "still registers its standalone routes with its own token (deprecated)" })
542
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: "still registers its standalone routes with its own token (deprecated)" })
478
543
  ] }, l.module)) })
479
544
  ] });
480
545
  }
481
546
 
482
547
  // src/screens/UsersScreen.tsx
483
- var import_react_admin8 = require("@fonderie/react-admin");
548
+ var import_react_admin9 = require("@fonderie/react-admin");
484
549
  var import_react2 = require("react");
485
- var import_jsx_runtime8 = require("react/jsx-runtime");
550
+ var import_jsx_runtime9 = require("react/jsx-runtime");
486
551
  function UsersScreen({ client, pageSize = 50 }) {
487
552
  const [input, setInput] = (0, import_react2.useState)("");
488
553
  const [selected, setSelected] = (0, import_react2.useState)(null);
489
- const list = (0, import_react_admin8.useAdminUsers)(client, { limit: pageSize });
490
- const { user, isLoading, error, suspend, unsuspend, revokeSessions } = (0, import_react_admin8.useAdminUser)(
554
+ const list = (0, import_react_admin9.useAdminUsers)(client, { limit: pageSize });
555
+ const { user, isLoading, error, suspend, unsuspend, revokeSessions } = (0, import_react_admin9.useAdminUser)(
491
556
  client,
492
557
  selected ?? {}
493
558
  );
494
559
  const userId = user?.id ?? null;
495
- const sessions = (0, import_react_admin8.useAdminUserSessions)(client, userId);
496
- const history = (0, import_react_admin8.useAdminLoginHistory)(client, userId, { limit: 20 });
497
- const yesNo = (v) => v ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.ok, children: "yes" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: "no" });
560
+ const sessions = (0, import_react_admin9.useAdminUserSessions)(client, userId);
561
+ const history = (0, import_react_admin9.useAdminLoginHistory)(client, userId, { limit: 20 });
562
+ const yesNo = (v) => v ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.ok, children: "yes" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.muted, children: "no" });
498
563
  const clear = () => {
499
564
  setSelected(null);
500
565
  setInput("");
501
566
  };
502
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: styles.container, children: [
503
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h1", { style: styles.title, children: "Users" }),
504
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
567
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.container, children: [
568
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h1", { style: styles.title, children: "Users" }),
569
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
505
570
  "form",
506
571
  {
507
572
  style: styles.toolbar,
@@ -511,7 +576,7 @@ function UsersScreen({ client, pageSize = 50 }) {
511
576
  setSelected(email ? { email } : null);
512
577
  },
513
578
  children: [
514
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
579
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
515
580
  "input",
516
581
  {
517
582
  type: "email",
@@ -522,8 +587,8 @@ function UsersScreen({ client, pageSize = 50 }) {
522
587
  "aria-label": "Email"
523
588
  }
524
589
  ),
525
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" }),
526
- selected ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", style: styles.button, onClick: clear, children: "\u2190 All users" }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
590
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" }),
591
+ selected ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", style: styles.button, onClick: clear, children: "\u2190 All users" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
527
592
  "button",
528
593
  {
529
594
  type: "button",
@@ -536,18 +601,18 @@ function UsersScreen({ client, pageSize = 50 }) {
536
601
  ]
537
602
  }
538
603
  ),
539
- error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.error, role: "alert", children: error.status === 404 ? "No user with that email." : error.explanation }) : null,
540
- !selected ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
541
- list.error ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
542
- list.users.length === 0 && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.muted, children: "No users yet." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("table", { style: styles.table, children: [
543
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
544
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Email" }),
545
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Name" }),
546
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Created" }),
547
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("th", { style: styles.th, children: "Status" })
604
+ error ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.error, role: "alert", children: error.status === 404 ? "No user with that email." : error.explanation }) : null,
605
+ !selected ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
606
+ list.error ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
607
+ list.users.length === 0 && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.muted, children: "No users yet." }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { style: styles.table, children: [
608
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
609
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Email" }),
610
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Name" }),
611
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Created" }),
612
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Status" })
548
613
  ] }) }),
549
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("tbody", { children: list.users.map((u) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
550
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
614
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: list.users.map((u) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
615
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
551
616
  "button",
552
617
  {
553
618
  type: "button",
@@ -556,17 +621,17 @@ function UsersScreen({ client, pageSize = 50 }) {
556
621
  children: u.email
557
622
  }
558
623
  ) }),
559
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: `${u.firstName ?? ""} ${u.lastName ?? ""}`.trim() || /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: "\u2014" }) }),
560
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: new Date(u.createdAt).toLocaleDateString() }),
561
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("td", { style: styles.td, children: [
562
- u.suspended ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.badge, children: "suspended" }) : null,
563
- u.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.badge, children: "deleted" }) : null,
564
- !u.suspended && !u.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: "active" }) : null
624
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: `${u.firstName ?? ""} ${u.lastName ?? ""}`.trim() || /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.muted, children: "\u2014" }) }),
625
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: new Date(u.createdAt).toLocaleDateString() }),
626
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: styles.td, children: [
627
+ u.suspended ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.badge, children: "suspended" }) : null,
628
+ u.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.badge, children: "deleted" }) : null,
629
+ !u.suspended && !u.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.muted, children: "active" }) : null
565
630
  ] })
566
631
  ] }, u.id)) })
567
632
  ] }),
568
- list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
569
- list.hasMore && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
633
+ list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
634
+ list.hasMore && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
570
635
  "button",
571
636
  {
572
637
  type: "button",
@@ -576,48 +641,48 @@ function UsersScreen({ client, pageSize = 50 }) {
576
641
  }
577
642
  ) : null
578
643
  ] }) : null,
579
- user ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
580
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("h2", { style: styles.subtitle, children: [
644
+ user ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
645
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("h2", { style: styles.subtitle, children: [
581
646
  user.firstName || user.lastName ? `${user.firstName} ${user.lastName}`.trim() : user.email,
582
647
  " ",
583
- user.suspended ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.badge, children: "suspended" }) : null,
584
- user.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.badge, children: "deleted" }) : null
648
+ user.suspended ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.badge, children: "suspended" }) : null,
649
+ user.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.badge, children: "deleted" }) : null
585
650
  ] }),
586
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("table", { style: styles.table, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tbody", { children: [
587
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
588
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: "id" }),
589
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: user.id })
651
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("table", { style: styles.table, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tbody", { children: [
652
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
653
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: "id" }),
654
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: user.id })
590
655
  ] }),
591
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
592
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: "email" }),
593
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("td", { style: styles.td, children: [
656
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
657
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: "email" }),
658
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: styles.td, children: [
594
659
  user.email,
595
660
  " \xB7 verified ",
596
661
  yesNo(user.isEmailVerified)
597
662
  ] })
598
663
  ] }),
599
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
600
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: "MFA" }),
601
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: yesNo(user.mfaEnabled) })
664
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
665
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: "MFA" }),
666
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: yesNo(user.mfaEnabled) })
602
667
  ] }),
603
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
604
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: "provider" }),
605
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("td", { style: styles.td, children: [
668
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
669
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: "provider" }),
670
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: styles.td, children: [
606
671
  user.provider || "password",
607
672
  user.hasPassword ? "" : " \xB7 no password set"
608
673
  ] })
609
674
  ] }),
610
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
611
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: "last login" }),
612
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: user.lastLogin ? new Date(user.lastLogin).toLocaleString() : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: "never" }) })
675
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
676
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: "last login" }),
677
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: user.lastLogin ? new Date(user.lastLogin).toLocaleString() : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.muted, children: "never" }) })
613
678
  ] }),
614
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("tr", { children: [
615
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: "created" }),
616
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("td", { style: styles.td, children: new Date(user.createdAt).toLocaleString() })
679
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
680
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: "created" }),
681
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: new Date(user.createdAt).toLocaleString() })
617
682
  ] })
618
683
  ] }) }),
619
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { ...styles.toolbar, marginTop: 12 }, children: [
620
- user.suspended ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
684
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { ...styles.toolbar, marginTop: 12 }, children: [
685
+ user.suspended ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
621
686
  "button",
622
687
  {
623
688
  type: "button",
@@ -626,7 +691,7 @@ function UsersScreen({ client, pageSize = 50 }) {
626
691
  disabled: isLoading,
627
692
  children: "Unsuspend"
628
693
  }
629
- ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
694
+ ) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
630
695
  "button",
631
696
  {
632
697
  type: "button",
@@ -636,7 +701,7 @@ function UsersScreen({ client, pageSize = 50 }) {
636
701
  children: "Suspend"
637
702
  }
638
703
  ),
639
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
704
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
640
705
  "button",
641
706
  {
642
707
  type: "button",
@@ -647,26 +712,26 @@ function UsersScreen({ client, pageSize = 50 }) {
647
712
  }
648
713
  )
649
714
  ] }),
650
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { style: styles.subtitle, children: "Live sessions" }),
651
- sessions.sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.muted, children: "None." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { style: styles.list, children: sessions.sessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { style: styles.row, children: [
652
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.mono, children: s.ipAddress ?? "\u2014" }),
715
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: styles.subtitle, children: "Live sessions" }),
716
+ sessions.sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.muted, children: "None." }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { style: styles.list, children: sessions.sessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { style: styles.row, children: [
717
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.mono, children: s.ipAddress ?? "\u2014" }),
653
718
  " ",
654
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: s.userAgent ?? "" }),
719
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.muted, children: s.userAgent ?? "" }),
655
720
  " ",
656
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { style: styles.muted, children: [
721
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: styles.muted, children: [
657
722
  "since ",
658
723
  new Date(s.createdAt).toLocaleString()
659
724
  ] })
660
725
  ] }, s.id)) }),
661
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { style: styles.subtitle, children: "Recent sign-ins" }),
662
- history.events.length === 0 && !history.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { style: styles.muted, children: "None recorded." }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("ul", { style: styles.list, children: history.events.map((e) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("li", { style: styles.row, children: [
663
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: e.outcome === "success" ? styles.ok : styles.bad, children: e.outcome }),
726
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: styles.subtitle, children: "Recent sign-ins" }),
727
+ history.events.length === 0 && !history.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.muted, children: "None recorded." }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { style: styles.list, children: history.events.map((e) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { style: styles.row, children: [
728
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: e.outcome === "success" ? styles.ok : styles.bad, children: e.outcome }),
664
729
  " ",
665
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: e.method }),
730
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.muted, children: e.method }),
666
731
  " ",
667
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: styles.muted, children: new Date(e.createdAt).toLocaleString() })
732
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.muted, children: new Date(e.createdAt).toLocaleString() })
668
733
  ] }, e.id)) }),
669
- history.hasMore && !history.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
734
+ history.hasMore && !history.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
670
735
  "button",
671
736
  {
672
737
  type: "button",
@@ -680,15 +745,15 @@ function UsersScreen({ client, pageSize = 50 }) {
680
745
  }
681
746
 
682
747
  // src/screens/CatalogScreen.tsx
683
- var import_react_admin9 = require("@fonderie/react-admin");
684
- var import_jsx_runtime9 = require("react/jsx-runtime");
748
+ var import_react_admin10 = require("@fonderie/react-admin");
749
+ var import_jsx_runtime10 = require("react/jsx-runtime");
685
750
  function CatalogScreen({ client }) {
686
- const { catalog, isLoading, error, refresh, deletePlan } = (0, import_react_admin9.useAdminCatalog)(client);
751
+ const { catalog, isLoading, error, refresh, deletePlan } = (0, import_react_admin10.useAdminCatalog)(client);
687
752
  const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
688
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.container, children: [
689
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.toolbar, children: [
690
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h1", { style: { ...styles.title, marginBottom: 0 }, children: "Catalog" }),
691
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
753
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.container, children: [
754
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.toolbar, children: [
755
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { style: { ...styles.title, marginBottom: 0 }, children: "Catalog" }),
756
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
692
757
  "button",
693
758
  {
694
759
  type: "button",
@@ -699,37 +764,37 @@ function CatalogScreen({ client }) {
699
764
  }
700
765
  )
701
766
  ] }),
702
- error ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
703
- isLoading && !catalog ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
704
- catalog ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
705
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: styles.subtitle, children: "Configured (code)" }),
706
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("pre", { style: { ...styles.mono, background: "#f9fafb", padding: 12, overflowX: "auto" }, children: JSON.stringify(catalog.configured, null, 2) }),
707
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: styles.subtitle, children: "Stored (database)" }),
708
- catalog.stored.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.muted, children: "No stored plans." }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { style: styles.table, children: [
709
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
710
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Plan" }),
711
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Tier" }),
712
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Seats" }),
713
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Monthly" }),
714
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Yearly" }),
715
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Trial" }),
716
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th })
767
+ error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
768
+ isLoading && !catalog ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
769
+ catalog ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
770
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Configured (code)" }),
771
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("pre", { style: { ...styles.mono, background: "#f9fafb", padding: 12, overflowX: "auto" }, children: JSON.stringify(catalog.configured, null, 2) }),
772
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Stored (database)" }),
773
+ catalog.stored.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "No stored plans." }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { style: styles.table, children: [
774
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
775
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Plan" }),
776
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Tier" }),
777
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Seats" }),
778
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Monthly" }),
779
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Yearly" }),
780
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Trial" }),
781
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th })
717
782
  ] }) }),
718
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: catalog.stored.map((p) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
719
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: styles.td, children: [
720
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: p.name }),
721
- p.description ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.muted, children: p.description }) : null
783
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: catalog.stored.map((p) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
784
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
785
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: p.name }),
786
+ p.description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: styles.muted, children: p.description }) : null
722
787
  ] }),
723
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: p.tier }),
724
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: p.seats ?? "\u221E" }),
725
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: styles.td, children: [
788
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: p.tier }),
789
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: p.seats ?? "\u221E" }),
790
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
726
791
  money(p.pricing?.monthly),
727
792
  " ",
728
793
  p.pricing?.currency ?? ""
729
794
  ] }),
730
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: money(p.pricing?.yearly) }),
731
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: p.trialDays ? `${p.trialDays} d` : "\u2014" }),
732
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
795
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: money(p.pricing?.yearly) }),
796
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: p.trialDays ? `${p.trialDays} d` : "\u2014" }),
797
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
733
798
  "button",
734
799
  {
735
800
  type: "button",
@@ -749,15 +814,15 @@ function CatalogScreen({ client }) {
749
814
  }
750
815
 
751
816
  // src/screens/SubscriberScreen.tsx
752
- var import_react_admin10 = require("@fonderie/react-admin");
817
+ var import_react_admin11 = require("@fonderie/react-admin");
753
818
  var import_react3 = require("react");
754
- var import_jsx_runtime10 = require("react/jsx-runtime");
819
+ var import_jsx_runtime11 = require("react/jsx-runtime");
755
820
  function SubscriberScreen({ client, pageSize = 50 }) {
756
821
  const [type, setType] = (0, import_react3.useState)("user");
757
822
  const [idInput, setIdInput] = (0, import_react3.useState)("");
758
823
  const [subscriber, setSubscriber] = (0, import_react3.useState)(null);
759
- const list = (0, import_react_admin10.useAdminSubscribers)(client, { limit: pageSize });
760
- const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0, import_react_admin10.useAdminSubscriber)(client, subscriber, { limit: 20 });
824
+ const list = (0, import_react_admin11.useAdminSubscribers)(client, { limit: pageSize });
825
+ const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0, import_react_admin11.useAdminSubscriber)(client, subscriber, { limit: 20 });
761
826
  const [amount, setAmount] = (0, import_react3.useState)("");
762
827
  const [note, setNote] = (0, import_react3.useState)("");
763
828
  const [granted, setGranted] = (0, import_react3.useState)(null);
@@ -767,9 +832,9 @@ function SubscriberScreen({ client, pageSize = 50 }) {
767
832
  setIdInput(id);
768
833
  setSubscriber({ type: t, id });
769
834
  };
770
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.container, children: [
771
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h1", { style: styles.title, children: "Subscriber" }),
772
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
835
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.container, children: [
836
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: styles.title, children: "Subscriber" }),
837
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
773
838
  "form",
774
839
  {
775
840
  style: styles.toolbar,
@@ -779,7 +844,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
779
844
  setSubscriber(idInput.trim() ? { type, id: idInput.trim() } : null);
780
845
  },
781
846
  children: [
782
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
847
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
783
848
  "select",
784
849
  {
785
850
  value: type,
@@ -787,12 +852,12 @@ function SubscriberScreen({ client, pageSize = 50 }) {
787
852
  style: styles.button,
788
853
  "aria-label": "Type",
789
854
  children: [
790
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "user", children: "user" }),
791
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("option", { value: "workspace", children: "workspace" })
855
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "user", children: "user" }),
856
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("option", { value: "workspace", children: "workspace" })
792
857
  ]
793
858
  }
794
859
  ),
795
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
860
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
796
861
  "input",
797
862
  {
798
863
  value: idInput,
@@ -802,8 +867,8 @@ function SubscriberScreen({ client, pageSize = 50 }) {
802
867
  "aria-label": "Subscriber id"
803
868
  }
804
869
  ),
805
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" }),
806
- subscriber ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
870
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Look up" }),
871
+ subscriber ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
807
872
  "button",
808
873
  {
809
874
  type: "button",
@@ -815,7 +880,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
815
880
  },
816
881
  children: "\u2190 All subscribers"
817
882
  }
818
- ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
883
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
819
884
  "button",
820
885
  {
821
886
  type: "button",
@@ -828,18 +893,18 @@ function SubscriberScreen({ client, pageSize = 50 }) {
828
893
  ]
829
894
  }
830
895
  ),
831
- error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
832
- !subscriber ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
833
- list.error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
834
- list.subscriptions.length === 0 && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "No subscribers yet." }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { style: styles.table, children: [
835
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
836
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Subscriber" }),
837
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Plan" }),
838
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Status" }),
839
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Renews" })
896
+ error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
897
+ !subscriber ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
898
+ list.error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
899
+ list.subscriptions.length === 0 && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.muted, children: "No subscribers yet." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { style: styles.table, children: [
900
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
901
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Subscriber" }),
902
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Plan" }),
903
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Status" }),
904
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Renews" })
840
905
  ] }) }),
841
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: list.subscriptions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
842
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
906
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: list.subscriptions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
907
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
843
908
  "button",
844
909
  {
845
910
  type: "button",
@@ -852,20 +917,20 @@ function SubscriberScreen({ client, pageSize = 50 }) {
852
917
  ]
853
918
  }
854
919
  ) }),
855
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
856
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: s.plan }),
920
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { style: styles.td, children: [
921
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: s.plan }),
857
922
  " \xB7 ",
858
923
  s.interval
859
924
  ] }),
860
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
925
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { style: styles.td, children: [
861
926
  s.status,
862
- s.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.badge, children: "cancels" }) : null
927
+ s.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.badge, children: "cancels" }) : null
863
928
  ] }),
864
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.muted, children: "\u2014" }) })
929
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.muted, children: "\u2014" }) })
865
930
  ] }, s.id)) })
866
931
  ] }),
867
- list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
868
- list.hasMore && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
932
+ list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
933
+ list.hasMore && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
869
934
  "button",
870
935
  {
871
936
  type: "button",
@@ -875,27 +940,27 @@ function SubscriberScreen({ client, pageSize = 50 }) {
875
940
  }
876
941
  ) : null
877
942
  ] }) : null,
878
- subscriber && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
879
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Subscription" }),
880
- subscription ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("table", { style: styles.table, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tbody", { children: [
881
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
882
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "plan" }),
883
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
884
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: subscription.plan }),
943
+ subscriber && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
944
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { style: styles.subtitle, children: "Subscription" }),
945
+ subscription ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("table", { style: styles.table, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tbody", { children: [
946
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
947
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: "plan" }),
948
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { style: styles.td, children: [
949
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: subscription.plan }),
885
950
  " \xB7 ",
886
951
  subscription.interval
887
952
  ] })
888
953
  ] }),
889
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
890
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "status" }),
891
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
954
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
955
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: "status" }),
956
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { style: styles.td, children: [
892
957
  subscription.status,
893
958
  subscription.cancelAtPeriodEnd ? " \xB7 cancels at period end" : ""
894
959
  ] })
895
960
  ] }),
896
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
897
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "period" }),
898
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
961
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
962
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: "period" }),
963
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { style: styles.td, children: [
899
964
  subscription.currentPeriodStart ? new Date(subscription.currentPeriodStart).toLocaleDateString() : "\u2014",
900
965
  " ",
901
966
  "\u2192",
@@ -903,19 +968,19 @@ function SubscriberScreen({ client, pageSize = 50 }) {
903
968
  subscription.currentPeriodEnd ? new Date(subscription.currentPeriodEnd).toLocaleDateString() : "\u2014"
904
969
  ] })
905
970
  ] }),
906
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
907
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "provider" }),
908
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: subscription.providerSubscriptionId ?? "\u2014" })
971
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
972
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: "provider" }),
973
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: subscription.providerSubscriptionId ?? "\u2014" })
909
974
  ] })
910
- ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "No subscription." }),
911
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Wallet" }),
912
- wallet ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
913
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("p", { children: [
914
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: wallet.balance }),
975
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.muted, children: "No subscription." }),
976
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { style: styles.subtitle, children: "Wallet" }),
977
+ wallet ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
978
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("p", { children: [
979
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: wallet.balance }),
915
980
  " ",
916
981
  wallet.currency,
917
982
  " ",
918
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { style: styles.muted, children: [
983
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: styles.muted, children: [
919
984
  "(granted ",
920
985
  wallet.granted ?? "0",
921
986
  " \xB7 purchased ",
@@ -924,7 +989,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
924
989
  wallet.precision
925
990
  ] })
926
991
  ] }),
927
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
992
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
928
993
  "form",
929
994
  {
930
995
  style: styles.toolbar,
@@ -943,7 +1008,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
943
1008
  });
944
1009
  },
945
1010
  children: [
946
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1011
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
947
1012
  "input",
948
1013
  {
949
1014
  value: amount,
@@ -953,7 +1018,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
953
1018
  "aria-label": "Amount"
954
1019
  }
955
1020
  ),
956
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1021
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
957
1022
  "input",
958
1023
  {
959
1024
  value: note,
@@ -963,27 +1028,27 @@ function SubscriberScreen({ client, pageSize = 50 }) {
963
1028
  "aria-label": "Reason"
964
1029
  }
965
1030
  ),
966
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "submit", style: styles.button, disabled: !/^\d+$/.test(amount.trim()), children: "Grant" }),
967
- granted ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.ok, children: granted }) : null
1031
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "submit", style: styles.button, disabled: !/^\d+$/.test(amount.trim()), children: "Grant" }),
1032
+ granted ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.ok, children: granted }) : null
968
1033
  ]
969
1034
  }
970
1035
  ),
971
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Ledger" }),
972
- ledger.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "Nothing moved yet." }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { style: styles.table, children: [
973
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
974
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "When" }),
975
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Kind" }),
976
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Amount" }),
977
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Note" })
1036
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { style: styles.subtitle, children: "Ledger" }),
1037
+ ledger.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.muted, children: "Nothing moved yet." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { style: styles.table, children: [
1038
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1039
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "When" }),
1040
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Kind" }),
1041
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Amount" }),
1042
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Note" })
978
1043
  ] }) }),
979
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: ledger.map((t) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
980
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(t.createdAt).toLocaleString() }),
981
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: t.type }),
982
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: t.amount }),
983
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t.description ?? "" })
1044
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: ledger.map((t) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1045
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(t.createdAt).toLocaleString() }),
1046
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: t.type }),
1047
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: t.amount }),
1048
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t.description ?? "" })
984
1049
  ] }, t.id)) })
985
1050
  ] }),
986
- hasMoreLedger ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1051
+ hasMoreLedger ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
987
1052
  "button",
988
1053
  {
989
1054
  type: "button",
@@ -992,25 +1057,25 @@ function SubscriberScreen({ client, pageSize = 50 }) {
992
1057
  children: "Load more"
993
1058
  }
994
1059
  ) : null
995
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "No wallet \u2014 billing has no wallet configuration." })
1060
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.muted, children: "No wallet \u2014 billing has no wallet configuration." })
996
1061
  ] }) : null
997
1062
  ] });
998
1063
  }
999
1064
 
1000
1065
  // src/screens/AuditScreen.tsx
1001
- var import_react_admin11 = require("@fonderie/react-admin");
1066
+ var import_react_admin12 = require("@fonderie/react-admin");
1002
1067
  var import_react4 = require("react");
1003
- var import_jsx_runtime11 = require("react/jsx-runtime");
1068
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1004
1069
  function AuditScreen({ client, pageSize = 50 }) {
1005
1070
  const [draft, setDraft] = (0, import_react4.useState)({ workspaceId: "", type: "", actorId: "" });
1006
1071
  const [filter, setFilter] = (0, import_react4.useState)(
1007
1072
  {}
1008
1073
  );
1009
- const { events, hasMore, isLoading, error, refresh, loadMore } = (0, import_react_admin11.useAdminAudit)(client, {
1074
+ const { events, hasMore, isLoading, error, refresh, loadMore } = (0, import_react_admin12.useAdminAudit)(client, {
1010
1075
  ...filter,
1011
1076
  limit: pageSize
1012
1077
  });
1013
- const field = (key, placeholder) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1078
+ const field = (key, placeholder) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1014
1079
  "input",
1015
1080
  {
1016
1081
  value: draft[key],
@@ -1020,9 +1085,9 @@ function AuditScreen({ client, pageSize = 50 }) {
1020
1085
  "aria-label": placeholder
1021
1086
  }
1022
1087
  );
1023
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.container, children: [
1024
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h1", { style: styles.title, children: "Audit" }),
1025
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1088
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: styles.container, children: [
1089
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h1", { style: styles.title, children: "Audit" }),
1090
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1026
1091
  "form",
1027
1092
  {
1028
1093
  style: styles.toolbar,
@@ -1038,8 +1103,8 @@ function AuditScreen({ client, pageSize = 50 }) {
1038
1103
  field("workspaceId", "workspace id (all if empty)"),
1039
1104
  field("type", "event type"),
1040
1105
  field("actorId", "actor id"),
1041
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Filter" }),
1042
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1106
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "submit", style: styles.button, disabled: isLoading, children: "Filter" }),
1107
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1043
1108
  "button",
1044
1109
  {
1045
1110
  type: "button",
@@ -1052,25 +1117,25 @@ function AuditScreen({ client, pageSize = 50 }) {
1052
1117
  ]
1053
1118
  }
1054
1119
  ),
1055
- error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
1056
- events.length === 0 && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.muted, children: "Nothing recorded for this filter." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { style: styles.table, children: [
1057
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1058
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "When" }),
1059
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Type" }),
1060
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Workspace" }),
1061
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Actor" }),
1062
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Request" })
1120
+ error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
1121
+ events.length === 0 && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.muted, children: "Nothing recorded for this filter." }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("table", { style: styles.table, children: [
1122
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1123
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "When" }),
1124
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Type" }),
1125
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Workspace" }),
1126
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Actor" }),
1127
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Request" })
1063
1128
  ] }) }),
1064
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: events.map((e) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1065
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(e.createdAt).toLocaleString() }),
1066
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.type }),
1067
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: String(e.payload["workspaceId"] ?? "\u2014") }),
1068
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.actorId ?? "\u2014" }),
1069
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: e.requestId ?? "" })
1129
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tbody", { children: events.map((e) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1130
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(e.createdAt).toLocaleString() }),
1131
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.type }),
1132
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: String(e.payload["workspaceId"] ?? "\u2014") }),
1133
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.actorId ?? "\u2014" }),
1134
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: e.requestId ?? "" })
1070
1135
  ] }, e.id)) })
1071
1136
  ] }),
1072
- isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
1073
- hasMore && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1137
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
1138
+ hasMore && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1074
1139
  "button",
1075
1140
  {
1076
1141
  type: "button",
@@ -1083,7 +1148,7 @@ function AuditScreen({ client, pageSize = 50 }) {
1083
1148
  }
1084
1149
 
1085
1150
  // src/screens/AdminShell.tsx
1086
- var import_jsx_runtime12 = require("react/jsx-runtime");
1151
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1087
1152
  var NAV = [
1088
1153
  { group: "Today", items: [{ page: "attention", label: "Attention" }] },
1089
1154
  {
@@ -1110,7 +1175,8 @@ var NAV = [
1110
1175
  items: [
1111
1176
  { page: "audit", label: "Audit", needs: "audit" },
1112
1177
  { page: "log", label: "Admin log" },
1113
- { page: "tokens", label: "Access" }
1178
+ { page: "tokens", label: "Access" },
1179
+ { page: "migrations", label: "Migrations" }
1114
1180
  ]
1115
1181
  }
1116
1182
  ];
@@ -1142,42 +1208,45 @@ function AdminShell({
1142
1208
  let body;
1143
1209
  switch (current) {
1144
1210
  case "attention":
1145
- body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AttentionScreen, { client });
1211
+ body = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AttentionScreen, { client });
1146
1212
  break;
1147
1213
  case "modules":
1148
- body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ModulesScreen, { client });
1214
+ body = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ModulesScreen, { client });
1149
1215
  break;
1150
1216
  case "doctor":
1151
- body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(DoctorScreen, { client });
1217
+ body = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DoctorScreen, { client });
1152
1218
  break;
1153
1219
  case "config":
1154
- body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ConfigScreen, { client });
1220
+ body = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ConfigScreen, { client });
1155
1221
  break;
1156
1222
  case "routes":
1157
- body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RoutesScreen, { client });
1223
+ body = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(RoutesScreen, { client });
1158
1224
  break;
1159
1225
  case "tokens":
1160
- body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TokensScreen, { client });
1226
+ body = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TokensScreen, { client });
1227
+ break;
1228
+ case "migrations":
1229
+ body = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(MigrationsScreen, { client });
1161
1230
  break;
1162
1231
  case "log":
1163
- body = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AdminLogScreen, { client });
1232
+ body = /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AdminLogScreen, { client });
1164
1233
  break;
1165
1234
  case "catalog":
1166
- body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass a BillingAdminClient to see the catalog here." });
1235
+ body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.status, children: "Pass a BillingAdminClient to see the catalog here." });
1167
1236
  break;
1168
1237
  case "subscriber":
1169
- body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SubscriberScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass a BillingAdminClient to look up subscribers here." });
1238
+ body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SubscriberScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.status, children: "Pass a BillingAdminClient to look up subscribers here." });
1170
1239
  break;
1171
1240
  case "audit":
1172
- body = auditClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AuditScreen, { client: auditClient }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass an AuditAdminClient to see the audit trail here." });
1241
+ body = auditClient ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AuditScreen, { client: auditClient }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.status, children: "Pass an AuditAdminClient to see the audit trail here." });
1173
1242
  break;
1174
1243
  case "users":
1175
- body = authClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(UsersScreen, { client: authClient }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass an AuthAdminClient to look up users here." });
1244
+ body = authClient ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(UsersScreen, { client: authClient }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.status, children: "Pass an AuthAdminClient to look up users here." });
1176
1245
  break;
1177
1246
  case "settings":
1178
- body = !configClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass a ConfigAdminClient to manage config and secrets here." }) : editing && editing.kind !== "template" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1179
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
1180
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1247
+ body = !configClient ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.status, children: "Pass a ConfigAdminClient to manage config and secrets here." }) : editing && editing.kind !== "template" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1248
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
1249
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1181
1250
  import_react_config_admin_screens.ConfigEditorScreen,
1182
1251
  {
1183
1252
  client: configClient,
@@ -1187,7 +1256,7 @@ function AdminShell({
1187
1256
  onSaved: () => setEditing(null)
1188
1257
  }
1189
1258
  )
1190
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1259
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1191
1260
  import_react_config_admin_screens.ConfigListScreen,
1192
1261
  {
1193
1262
  client: configClient,
@@ -1198,9 +1267,9 @@ function AdminShell({
1198
1267
  );
1199
1268
  break;
1200
1269
  case "templates":
1201
- body = !courierClient ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Pass a CourierAdminClient to manage templates here." }) : editing?.kind === "template" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1202
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
1203
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1270
+ body = !courierClient ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.status, children: "Pass a CourierAdminClient to manage templates here." }) : editing?.kind === "template" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1271
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { type: "button", style: styles.button, onClick: () => setEditing(null), children: "\u2190 Back" }),
1272
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1204
1273
  import_react_courier_admin_screens.TemplateEditorScreen,
1205
1274
  {
1206
1275
  client: courierClient,
@@ -1208,7 +1277,7 @@ function AdminShell({
1208
1277
  onSaved: () => setEditing(null)
1209
1278
  }
1210
1279
  )
1211
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1280
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1212
1281
  import_react_courier_admin_screens.TemplateListScreen,
1213
1282
  {
1214
1283
  client: courierClient,
@@ -1217,13 +1286,13 @@ function AdminShell({
1217
1286
  );
1218
1287
  break;
1219
1288
  }
1220
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: styles.shell, children: [
1221
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("nav", { style: styles.nav, "aria-label": "Admin", children: NAV.map((g) => {
1289
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: styles.shell, children: [
1290
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("nav", { style: styles.nav, "aria-label": "Admin", children: NAV.map((g) => {
1222
1291
  const items = g.items.filter((i) => !i.needs || has[i.needs]);
1223
1292
  if (items.length === 0) return null;
1224
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { children: [
1225
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: styles.navGroup, children: g.group }),
1226
- items.map((i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1293
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
1294
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: styles.navGroup, children: g.group }),
1295
+ items.map((i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1227
1296
  "button",
1228
1297
  {
1229
1298
  type: "button",
@@ -1239,7 +1308,7 @@ function AdminShell({
1239
1308
  ))
1240
1309
  ] }, g.group);
1241
1310
  }) }),
1242
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("main", { style: styles.main, children: body })
1311
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("main", { style: styles.main, children: body })
1243
1312
  ] });
1244
1313
  }
1245
1314
  // Annotate the CommonJS export names for ESM import in node:
@@ -1251,6 +1320,7 @@ function AdminShell({
1251
1320
  CatalogScreen,
1252
1321
  ConfigScreen,
1253
1322
  DoctorScreen,
1323
+ MigrationsScreen,
1254
1324
  ModulesScreen,
1255
1325
  RoutesScreen,
1256
1326
  SubscriberScreen,