@fonderie/react-admin-screens 1.1.0 → 1.2.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
@@ -29,6 +29,7 @@ __export(index_exports, {
29
29
  EnvironmentScreen: () => EnvironmentScreen,
30
30
  MigrationsScreen: () => MigrationsScreen,
31
31
  ModulesScreen: () => ModulesScreen,
32
+ OperatorsScreen: () => OperatorsScreen,
32
33
  RoutesScreen: () => RoutesScreen,
33
34
  SubscriberScreen: () => SubscriberScreen,
34
35
  TokensScreen: () => TokensScreen,
@@ -39,7 +40,7 @@ module.exports = __toCommonJS(index_exports);
39
40
  // src/screens/AdminShell.tsx
40
41
  var import_react_config_admin_screens = require("@fonderie/react-config-admin-screens");
41
42
  var import_react_courier_admin_screens = require("@fonderie/react-courier-admin-screens");
42
- var import_react6 = require("react");
43
+ var import_react7 = require("react");
43
44
 
44
45
  // src/styles.ts
45
46
  var t = {
@@ -1111,33 +1112,265 @@ function MigrationsScreen({ client }) {
1111
1112
  ] });
1112
1113
  }
1113
1114
 
1114
- // src/screens/TokensScreen.tsx
1115
+ // src/screens/OperatorsScreen.tsx
1115
1116
  var import_react_admin8 = require("@fonderie/react-admin");
1116
1117
  var import_react2 = require("react");
1117
1118
  var import_jsx_runtime9 = require("react/jsx-runtime");
1118
- var ALL = ["read", "write", "secrets"];
1119
- function TokensScreen({ client }) {
1120
- const { report, isLoading, error, issue, revoke } = (0, import_react_admin8.useAdminTokens)(client);
1121
- const [name, setName] = (0, import_react2.useState)("");
1122
- const [scopes, setScopes] = (0, import_react2.useState)(["read"]);
1123
- const [days, setDays] = (0, import_react2.useState)("");
1119
+ var LEVELS = [
1120
+ { label: "Read only", scopes: ["read"], hint: "look around, change nothing" },
1121
+ { label: "Editor", scopes: ["read", "write"], hint: "change config, templates, users" },
1122
+ {
1123
+ label: "Owner",
1124
+ scopes: ["read", "write", "secrets"],
1125
+ hint: "secrets, tokens and operators too"
1126
+ }
1127
+ ];
1128
+ var levelOf = (scopes) => scopes.includes("secrets") ? "Owner" : scopes.includes("write") ? "Editor" : "Read only";
1129
+ function Minted({ link, onClose }) {
1130
+ const [copied, setCopied] = (0, import_react2.useState)(false);
1131
+ const url = `${window.location.origin}${link.url}`;
1132
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1133
+ "div",
1134
+ {
1135
+ style: {
1136
+ ...styles.notice,
1137
+ background: "color-mix(in srgb, var(--fonderie-accent,#00d294) 10%, transparent)",
1138
+ borderColor: "color-mix(in srgb, var(--fonderie-accent,#00d294) 35%, transparent)"
1139
+ },
1140
+ children: [
1141
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("strong", { children: [
1142
+ "Send this link to ",
1143
+ link.email,
1144
+ ". It is shown once."
1145
+ ] }),
1146
+ " It works once and expires",
1147
+ " ",
1148
+ new Date(link.expiresAt).toLocaleString(),
1149
+ ".",
1150
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { display: "flex", gap: 8, marginTop: 8, alignItems: "center" }, children: [
1151
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("code", { style: { ...styles.code, flex: 1, padding: "7px 10px", wordBreak: "break-all" }, children: url }),
1152
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1153
+ "button",
1154
+ {
1155
+ type: "button",
1156
+ style: styles.button,
1157
+ onClick: () => {
1158
+ void navigator.clipboard?.writeText(url);
1159
+ setCopied(true);
1160
+ },
1161
+ children: copied ? "Copied" : "Copy"
1162
+ }
1163
+ ),
1164
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", style: styles.buttonGhost, onClick: onClose, "aria-label": "Dismiss", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon, { name: "close", size: 14 }) })
1165
+ ] })
1166
+ ]
1167
+ }
1168
+ );
1169
+ }
1170
+ function OperatorsScreen({ client, me }) {
1171
+ const { report, isLoading, error, invite, recover, update, revokeLink } = (0, import_react_admin8.useAdminOperators)(client);
1172
+ const [email, setEmail] = (0, import_react2.useState)("");
1173
+ const [level, setLevel] = (0, import_react2.useState)("Editor");
1124
1174
  const [minted, setMinted] = (0, import_react2.useState)(null);
1125
- const toggle = (s) => setScopes((prev) => prev.includes(s) ? prev.filter((x) => x !== s) : [...prev, s]);
1175
+ const scopesFor = (label) => LEVELS.find((l) => l.label === label)?.scopes ?? ["read"];
1176
+ const status = (o) => o.disabledAt ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pill, { tone: "neutral", children: "disabled" }) : o.locked ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pill, { tone: "warn", children: "locked" }) : !o.enrolled ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pill, { tone: "warn", children: "setting up" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pill, { tone: "ok", children: "active" });
1126
1177
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: styles.container, children: [
1127
1178
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1128
1179
  PageHeader,
1129
1180
  {
1130
- title: "Access",
1131
- lead: "Who can open this surface: the root token's strength, scoped tokens you have issued, and any legacy per-module tokens."
1181
+ title: "Operators",
1182
+ lead: "The people who can sign in to this console. Each one uses a password and an authenticator app; there is no sign-up."
1183
+ }
1184
+ ),
1185
+ error ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.error, role: "alert", children: error.status === 403 && error.reason === "FORBIDDEN" ? "Managing operators needs the Owner level." : error.explanation }) : null,
1186
+ minted ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Minted, { link: minted, onClose: () => setMinted(null) }) : null,
1187
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1188
+ "form",
1189
+ {
1190
+ style: {
1191
+ ...styles.card,
1192
+ display: "flex",
1193
+ gap: 8,
1194
+ alignItems: "center",
1195
+ flexWrap: "wrap",
1196
+ marginBottom: 20
1197
+ },
1198
+ onSubmit: (e) => {
1199
+ e.preventDefault();
1200
+ void invite({ email: email.trim(), scopes: scopesFor(level) }).then((l) => {
1201
+ setMinted(l);
1202
+ setEmail("");
1203
+ }).catch(() => {
1204
+ });
1205
+ },
1206
+ children: [
1207
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon, { name: "users", size: 16 }),
1208
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { style: { fontSize: 13.5, marginRight: 4 }, children: "Invite" }),
1209
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1210
+ "input",
1211
+ {
1212
+ type: "email",
1213
+ required: true,
1214
+ value: email,
1215
+ onChange: (e) => setEmail(e.target.value),
1216
+ placeholder: "teammate@company.com",
1217
+ style: { ...styles.input, flex: 1, minWidth: 220 },
1218
+ "aria-label": "Email to invite"
1219
+ }
1220
+ ),
1221
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1222
+ "select",
1223
+ {
1224
+ value: level,
1225
+ onChange: (e) => setLevel(e.target.value),
1226
+ style: styles.input,
1227
+ "aria-label": "Access level",
1228
+ children: LEVELS.map((l) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("option", { value: l.label, children: [
1229
+ l.label,
1230
+ " \u2014 ",
1231
+ l.hint
1232
+ ] }, l.label))
1233
+ }
1234
+ ),
1235
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", { type: "submit", style: styles.buttonPrimary, disabled: !email.trim(), children: [
1236
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon, { name: "plus", size: 14 }),
1237
+ "Create invite link"
1238
+ ] })
1239
+ ]
1240
+ }
1241
+ ),
1242
+ isLoading && !report ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : report && report.operators.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Empty, { icon: "users", title: "No operators yet" }) : report ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { style: styles.table, children: [
1243
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
1244
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Operator" }),
1245
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Access" }),
1246
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Status" }),
1247
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Last sign-in" }),
1248
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th })
1249
+ ] }) }),
1250
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: report.operators.map((o) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
1251
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: styles.td, children: [
1252
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { fontWeight: 600 }, children: o.name || o.email }),
1253
+ o.name ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: styles.muted, children: o.email }) : null
1254
+ ] }),
1255
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1256
+ "select",
1257
+ {
1258
+ value: levelOf(o.scopes),
1259
+ onChange: (e) => void update(o.id, { scopes: scopesFor(e.target.value) }).catch(() => {
1260
+ }),
1261
+ style: { ...styles.input, height: 28, fontSize: 12.5 },
1262
+ disabled: o.email === me,
1263
+ "aria-label": `Access level for ${o.email}`,
1264
+ children: LEVELS.map((l) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("option", { value: l.label, children: l.label }, l.label))
1265
+ }
1266
+ ) }),
1267
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: styles.td, children: [
1268
+ status(o),
1269
+ o.enrolled && o.backupCodesLeft <= 2 && !o.disabledAt ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { ...styles.muted, marginTop: 4 }, children: [
1270
+ o.backupCodesLeft,
1271
+ " backup code(s) left"
1272
+ ] }) : null
1273
+ ] }),
1274
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: { ...styles.td, ...styles.muted, whiteSpace: "nowrap" }, children: o.lastLoginAt ? new Date(o.lastLoginAt).toLocaleString() : "never" }),
1275
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: { ...styles.td, textAlign: "right", whiteSpace: "nowrap" }, children: o.email === me ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.muted, children: "you" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1276
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1277
+ "button",
1278
+ {
1279
+ type: "button",
1280
+ style: { ...styles.button, height: 28, marginRight: 6 },
1281
+ onClick: () => {
1282
+ if (window.confirm(
1283
+ `Create a recovery link for ${o.email}? It signs them out everywhere; the link sets a new password and a new authenticator.`
1284
+ ))
1285
+ void recover(o.id).then(setMinted).catch(() => {
1286
+ });
1287
+ },
1288
+ children: "Recovery link"
1289
+ }
1290
+ ),
1291
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1292
+ "button",
1293
+ {
1294
+ type: "button",
1295
+ style: {
1296
+ ...o.disabledAt ? styles.button : styles.buttonDanger,
1297
+ height: 28
1298
+ },
1299
+ onClick: () => {
1300
+ if (o.disabledAt || window.confirm(`Disable ${o.email}? They are signed out immediately.`))
1301
+ void update(o.id, { disabled: !o.disabledAt }).catch(() => {
1302
+ });
1303
+ },
1304
+ children: o.disabledAt ? "Enable" : "Disable"
1305
+ }
1306
+ )
1307
+ ] }) })
1308
+ ] }, o.id)) })
1309
+ ] }) : null,
1310
+ report && report.links.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1311
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: styles.subtitle, children: "Pending links" }),
1312
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { style: styles.list, children: report.links.map((l) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1313
+ "li",
1314
+ {
1315
+ style: { ...styles.row, display: "flex", gap: 12, alignItems: "center" },
1316
+ children: [
1317
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pill, { tone: l.kind === "invite" ? "info" : "warn", dot: false, children: l.kind }),
1318
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: { flex: 1 }, children: [
1319
+ l.email,
1320
+ l.kind === "invite" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: styles.muted, children: [
1321
+ " \xB7 ",
1322
+ levelOf(l.scopes)
1323
+ ] }) : null
1324
+ ] }),
1325
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { style: styles.muted, children: [
1326
+ "expires ",
1327
+ new Date(l.expiresAt).toLocaleString()
1328
+ ] }),
1329
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1330
+ "button",
1331
+ {
1332
+ type: "button",
1333
+ style: { ...styles.buttonDanger, height: 28 },
1334
+ onClick: () => void revokeLink(l.id).catch(() => {
1335
+ }),
1336
+ children: "Revoke"
1337
+ }
1338
+ )
1339
+ ]
1340
+ },
1341
+ l.id
1342
+ )) })
1343
+ ] }) : null
1344
+ ] });
1345
+ }
1346
+
1347
+ // src/screens/TokensScreen.tsx
1348
+ var import_react_admin9 = require("@fonderie/react-admin");
1349
+ var import_react3 = require("react");
1350
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1351
+ var ALL = ["read", "write", "secrets"];
1352
+ function TokensScreen({ client }) {
1353
+ const { report, isLoading, error, issue, revoke } = (0, import_react_admin9.useAdminTokens)(client);
1354
+ const [name, setName] = (0, import_react3.useState)("");
1355
+ const [scopes, setScopes] = (0, import_react3.useState)(["read"]);
1356
+ const [days, setDays] = (0, import_react3.useState)("");
1357
+ const [minted, setMinted] = (0, import_react3.useState)(null);
1358
+ const toggle = (s) => setScopes((prev) => prev.includes(s) ? prev.filter((x) => x !== s) : [...prev, s]);
1359
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.container, children: [
1360
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1361
+ PageHeader,
1362
+ {
1363
+ title: "Tokens",
1364
+ lead: "Credentials for machines: the root token's strength, scoped tokens for the CLI and CI, and any legacy per-module tokens. People sign in as operators."
1132
1365
  }
1133
1366
  ),
1134
- error ? /* @__PURE__ */ (0, import_jsx_runtime9.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,
1135
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "Root token" }),
1136
- report ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { ...styles.card, display: "flex", gap: 12, alignItems: "flex-start" }, children: [
1137
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon, { name: "lock", size: 18, style: { marginTop: 2 } }),
1138
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
1139
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pill, { tone: report.admin.ok ? "ok" : "bad", children: report.admin.ok ? "strong" : "weak" }),
1140
- report.admin.problems.map((p) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1367
+ error ? /* @__PURE__ */ (0, import_jsx_runtime10.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,
1368
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "Root token" }),
1369
+ report ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { ...styles.card, display: "flex", gap: 12, alignItems: "flex-start" }, children: [
1370
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: "lock", size: 18, style: { marginTop: 2 } }),
1371
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1372
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: report.admin.ok ? "ok" : "bad", children: report.admin.ok ? "strong" : "weak" }),
1373
+ report.admin.problems.map((p) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1141
1374
  "div",
1142
1375
  {
1143
1376
  style: { marginTop: 6, color: "var(--fonderie-danger,#e00)", fontSize: 13 },
@@ -1147,9 +1380,9 @@ function TokensScreen({ client }) {
1147
1380
  ))
1148
1381
  ] })
1149
1382
  ] }) : null,
1150
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: styles.subtitle, children: "Issued tokens" }),
1151
- report?.issued === null ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.muted, children: "Issuing is off \u2014 give AdminModule a store and run its migrations." }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1152
- minted ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1383
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Issued tokens" }),
1384
+ report?.issued === null ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "Issuing is off \u2014 give AdminModule a store and run its migrations." }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1385
+ minted ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1153
1386
  "div",
1154
1387
  {
1155
1388
  style: {
@@ -1158,11 +1391,11 @@ function TokensScreen({ client }) {
1158
1391
  borderColor: "color-mix(in srgb, var(--fonderie-accent,#00d294) 35%, transparent)"
1159
1392
  },
1160
1393
  children: [
1161
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("strong", { children: "Copy this now \u2014 it is never shown again." }),
1394
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("strong", { children: "Copy this now \u2014 it is never shown again." }),
1162
1395
  " (",
1163
1396
  minted.name,
1164
1397
  ")",
1165
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1398
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1166
1399
  "div",
1167
1400
  {
1168
1401
  style: {
@@ -1178,7 +1411,7 @@ function TokensScreen({ client }) {
1178
1411
  ]
1179
1412
  }
1180
1413
  ) : null,
1181
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1414
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1182
1415
  "form",
1183
1416
  {
1184
1417
  style: styles.toolbar,
@@ -1197,7 +1430,7 @@ function TokensScreen({ client }) {
1197
1430
  });
1198
1431
  },
1199
1432
  children: [
1200
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1433
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1201
1434
  "input",
1202
1435
  {
1203
1436
  value: name,
@@ -1207,7 +1440,7 @@ function TokensScreen({ client }) {
1207
1440
  "aria-label": "Name"
1208
1441
  }
1209
1442
  ),
1210
- ALL.map((s) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1443
+ ALL.map((s) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1211
1444
  "label",
1212
1445
  {
1213
1446
  style: {
@@ -1219,14 +1452,14 @@ function TokensScreen({ client }) {
1219
1452
  fontSize: 13
1220
1453
  },
1221
1454
  children: [
1222
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { type: "checkbox", checked: scopes.includes(s), onChange: () => toggle(s) }),
1455
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { type: "checkbox", checked: scopes.includes(s), onChange: () => toggle(s) }),
1223
1456
  " ",
1224
1457
  s
1225
1458
  ]
1226
1459
  },
1227
1460
  s
1228
1461
  )),
1229
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1462
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1230
1463
  "input",
1231
1464
  {
1232
1465
  value: days,
@@ -1236,14 +1469,14 @@ function TokensScreen({ client }) {
1236
1469
  "aria-label": "Days"
1237
1470
  }
1238
1471
  ),
1239
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1472
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1240
1473
  "button",
1241
1474
  {
1242
1475
  type: "submit",
1243
1476
  style: styles.buttonPrimary,
1244
1477
  disabled: !name.trim() || scopes.length === 0 || isLoading,
1245
1478
  children: [
1246
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon, { name: "plus", size: 14 }),
1479
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: "plus", size: 14 }),
1247
1480
  "Issue token"
1248
1481
  ]
1249
1482
  }
@@ -1251,32 +1484,32 @@ function TokensScreen({ client }) {
1251
1484
  ]
1252
1485
  }
1253
1486
  ),
1254
- report?.issued && report.issued.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { style: styles.table, children: [
1255
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
1256
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Name" }),
1257
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Scopes" }),
1258
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Created" }),
1259
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Expires" }),
1260
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th, children: "Last used" }),
1261
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("th", { style: styles.th })
1487
+ report?.issued && report.issued.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { style: styles.table, children: [
1488
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
1489
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Name" }),
1490
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Scopes" }),
1491
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Created" }),
1492
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Expires" }),
1493
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Last used" }),
1494
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th })
1262
1495
  ] }) }),
1263
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tbody", { children: report.issued.map((t2) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tr", { children: [
1264
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: styles.td, children: [
1496
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: report.issued.map((t2) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
1497
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
1265
1498
  t2.name,
1266
- t2.revokedAt ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1499
+ t2.revokedAt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1267
1500
  " ",
1268
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pill, { tone: "neutral", children: "revoked" })
1501
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: "neutral", children: "revoked" })
1269
1502
  ] }) : null
1270
1503
  ] }),
1271
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: t2.scopes.join(", ") }),
1272
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("td", { style: { ...styles.td, ...styles.muted }, children: [
1504
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: t2.scopes.join(", ") }),
1505
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: { ...styles.td, ...styles.muted }, children: [
1273
1506
  new Date(t2.createdAt).toLocaleDateString(),
1274
1507
  " \xB7 ",
1275
1508
  t2.createdBy
1276
1509
  ] }),
1277
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t2.expiresAt ? new Date(t2.expiresAt).toLocaleDateString() : "never" }),
1278
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t2.lastUsedAt ? new Date(t2.lastUsedAt).toLocaleString() : "never" }),
1279
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("td", { style: styles.td, children: t2.revokedAt ? null : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1510
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t2.expiresAt ? new Date(t2.expiresAt).toLocaleDateString() : "never" }),
1511
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t2.lastUsedAt ? new Date(t2.lastUsedAt).toLocaleString() : "never" }),
1512
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: t2.revokedAt ? null : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1280
1513
  "button",
1281
1514
  {
1282
1515
  type: "button",
@@ -1292,47 +1525,47 @@ function TokensScreen({ client }) {
1292
1525
  }
1293
1526
  ) })
1294
1527
  ] }, t2.id)) })
1295
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Empty, { icon: "tokens", title: "No scoped tokens yet", children: "Issue a read-only token for a dashboard or a teammate instead of sharing the root." })
1528
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Empty, { icon: "tokens", title: "No scoped tokens yet", children: "Issue a read-only token for a dashboard or a teammate instead of sharing the root." })
1296
1529
  ] }),
1297
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { style: styles.subtitle, children: "Legacy per-brick tokens" }),
1298
- report && report.legacy.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { style: styles.muted, children: "None \u2014 every brick's admin surface goes through this token." }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { style: styles.list, children: report?.legacy.map((l) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("li", { style: styles.row, children: [
1299
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.mono, children: l.module }),
1530
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Legacy per-brick tokens" }),
1531
+ report && report.legacy.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "None \u2014 every brick's admin surface goes through this token." }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { style: styles.list, children: report?.legacy.map((l) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("li", { style: styles.row, children: [
1532
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.mono, children: l.module }),
1300
1533
  " ",
1301
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: styles.muted, children: "still registers its standalone routes with its own token (deprecated)" })
1534
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.muted, children: "still registers its standalone routes with its own token (deprecated)" })
1302
1535
  ] }, l.module)) })
1303
1536
  ] });
1304
1537
  }
1305
1538
 
1306
1539
  // src/screens/UsersScreen.tsx
1307
1540
  var import_client = require("@fonderie/client");
1308
- var import_react_admin9 = require("@fonderie/react-admin");
1309
- var import_react3 = require("react");
1310
- var import_jsx_runtime10 = require("react/jsx-runtime");
1541
+ var import_react_admin10 = require("@fonderie/react-admin");
1542
+ var import_react4 = require("react");
1543
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1311
1544
  function UsersScreen({ client, pageSize = 50 }) {
1312
- const [input, setInput] = (0, import_react3.useState)("");
1313
- const [selected, setSelected] = (0, import_react3.useState)(null);
1314
- const list = (0, import_react_admin9.useAdminUsers)(client, { limit: pageSize });
1315
- const { user, isLoading, error, suspend, unsuspend, revokeSessions } = (0, import_react_admin9.useAdminUser)(
1545
+ const [input, setInput] = (0, import_react4.useState)("");
1546
+ const [selected, setSelected] = (0, import_react4.useState)(null);
1547
+ const list = (0, import_react_admin10.useAdminUsers)(client, { limit: pageSize });
1548
+ const { user, isLoading, error, suspend, unsuspend, revokeSessions } = (0, import_react_admin10.useAdminUser)(
1316
1549
  client,
1317
1550
  selected ?? {}
1318
1551
  );
1319
1552
  const userId = user?.id ?? null;
1320
- const sessions = (0, import_react_admin9.useAdminUserSessions)(client, userId);
1321
- const history = (0, import_react_admin9.useAdminLoginHistory)(client, userId, { limit: 20 });
1322
- const yesNo = (v) => v ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: "ok", children: "yes" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: "neutral", children: "no" });
1553
+ const sessions = (0, import_react_admin10.useAdminUserSessions)(client, userId);
1554
+ const history = (0, import_react_admin10.useAdminLoginHistory)(client, userId, { limit: 20 });
1555
+ const yesNo = (v) => v ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Pill, { tone: "ok", children: "yes" }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Pill, { tone: "neutral", children: "no" });
1323
1556
  const clear = () => {
1324
1557
  setSelected(null);
1325
1558
  setInput("");
1326
1559
  };
1327
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: styles.container, children: [
1328
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1560
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.container, children: [
1561
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1329
1562
  PageHeader,
1330
1563
  {
1331
1564
  title: "Users",
1332
1565
  lead: "Everyone signed up. Open an account for its sessions, sign-ins and the suspend and sign-out controls."
1333
1566
  }
1334
1567
  ),
1335
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1568
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1336
1569
  "form",
1337
1570
  {
1338
1571
  style: styles.toolbar,
@@ -1342,7 +1575,7 @@ function UsersScreen({ client, pageSize = 50 }) {
1342
1575
  setSelected(email ? { email } : null);
1343
1576
  },
1344
1577
  children: [
1345
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1578
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1346
1579
  "input",
1347
1580
  {
1348
1581
  type: "email",
@@ -1353,14 +1586,14 @@ function UsersScreen({ client, pageSize = 50 }) {
1353
1586
  "aria-label": "Email"
1354
1587
  }
1355
1588
  ),
1356
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
1357
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: "search", size: 14 }),
1589
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
1590
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { name: "search", size: 14 }),
1358
1591
  "Look up"
1359
1592
  ] }),
1360
- selected ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { type: "button", style: styles.buttonGhost, onClick: clear, children: [
1361
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { name: "back", size: 14 }),
1593
+ selected ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("button", { type: "button", style: styles.buttonGhost, onClick: clear, children: [
1594
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Icon, { name: "back", size: 14 }),
1362
1595
  "All users"
1363
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1596
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1364
1597
  "button",
1365
1598
  {
1366
1599
  type: "button",
@@ -1373,18 +1606,18 @@ function UsersScreen({ client, pageSize = 50 }) {
1373
1606
  ]
1374
1607
  }
1375
1608
  ),
1376
- error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.error, role: "alert", children: error.status === 404 ? "No user with that email." : error.explanation }) : null,
1377
- !selected ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1378
- list.error ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
1379
- list.users.length === 0 && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Empty, { icon: "users", title: "No users yet", children: "Sign-ups appear here as they happen." }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("table", { style: styles.table, children: [
1380
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
1381
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Email" }),
1382
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Name" }),
1383
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Created" }),
1384
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("th", { style: styles.th, children: "Status" })
1609
+ error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.error, role: "alert", children: error.status === 404 ? "No user with that email." : error.explanation }) : null,
1610
+ !selected ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1611
+ list.error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
1612
+ list.users.length === 0 && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Empty, { icon: "users", title: "No users yet", children: "Sign-ups appear here as they happen." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { style: styles.table, children: [
1613
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1614
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Email" }),
1615
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Name" }),
1616
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Created" }),
1617
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Status" })
1385
1618
  ] }) }),
1386
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("tbody", { children: list.users.map((u) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
1387
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1619
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: list.users.map((u) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1620
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1388
1621
  "button",
1389
1622
  {
1390
1623
  type: "button",
@@ -1393,17 +1626,17 @@ function UsersScreen({ client, pageSize = 50 }) {
1393
1626
  children: u.email
1394
1627
  }
1395
1628
  ) }),
1396
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: `${u.firstName ?? ""} ${u.lastName ?? ""}`.trim() || /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.muted, children: "\u2014" }) }),
1397
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: new Date(u.createdAt).toLocaleDateString() }),
1398
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
1399
- u.suspended ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: "warn", children: "suspended" }) : null,
1400
- u.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: "neutral", children: "deleted" }) : null,
1401
- !u.suspended && !u.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: "ok", children: "active" }) : null
1629
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: `${u.firstName ?? ""} ${u.lastName ?? ""}`.trim() || /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.muted, children: "\u2014" }) }),
1630
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: new Date(u.createdAt).toLocaleDateString() }),
1631
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { style: styles.td, children: [
1632
+ u.suspended ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Pill, { tone: "warn", children: "suspended" }) : null,
1633
+ u.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Pill, { tone: "neutral", children: "deleted" }) : null,
1634
+ !u.suspended && !u.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Pill, { tone: "ok", children: "active" }) : null
1402
1635
  ] })
1403
1636
  ] }, u.id)) })
1404
1637
  ] }),
1405
- list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
1406
- list.hasMore && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1638
+ list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
1639
+ list.hasMore && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1407
1640
  "button",
1408
1641
  {
1409
1642
  type: "button",
@@ -1413,48 +1646,48 @@ function UsersScreen({ client, pageSize = 50 }) {
1413
1646
  }
1414
1647
  ) : null
1415
1648
  ] }) : null,
1416
- user ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1417
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("h2", { style: styles.subtitle, children: [
1649
+ user ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1650
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("h2", { style: styles.subtitle, children: [
1418
1651
  user.firstName || user.lastName ? `${user.firstName} ${user.lastName}`.trim() : user.email,
1419
1652
  " ",
1420
- user.suspended ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: "warn", children: "suspended" }) : null,
1421
- user.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: "neutral", children: "deleted" }) : null
1653
+ user.suspended ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Pill, { tone: "warn", children: "suspended" }) : null,
1654
+ user.deletedAt ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Pill, { tone: "neutral", children: "deleted" }) : null
1422
1655
  ] }),
1423
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("table", { style: styles.table, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tbody", { children: [
1424
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
1425
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "id" }),
1426
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: user.id })
1656
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("table", { style: styles.table, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tbody", { children: [
1657
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1658
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: "id" }),
1659
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: user.id })
1427
1660
  ] }),
1428
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
1429
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "email" }),
1430
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
1661
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1662
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: "email" }),
1663
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { style: styles.td, children: [
1431
1664
  user.email,
1432
1665
  " \xB7 verified ",
1433
1666
  yesNo(user.isEmailVerified)
1434
1667
  ] })
1435
1668
  ] }),
1436
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
1437
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "MFA" }),
1438
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: yesNo(user.mfaEnabled) })
1669
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1670
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: "MFA" }),
1671
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: yesNo(user.mfaEnabled) })
1439
1672
  ] }),
1440
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
1441
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "provider" }),
1442
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("td", { style: styles.td, children: [
1673
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1674
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: "provider" }),
1675
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { style: styles.td, children: [
1443
1676
  user.provider || "password",
1444
1677
  user.hasPassword ? "" : " \xB7 no password set"
1445
1678
  ] })
1446
1679
  ] }),
1447
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
1448
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "last login" }),
1449
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: user.lastLogin ? new Date(user.lastLogin).toLocaleString() : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.muted, children: "never" }) })
1680
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1681
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: "last login" }),
1682
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: user.lastLogin ? new Date(user.lastLogin).toLocaleString() : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.muted, children: "never" }) })
1450
1683
  ] }),
1451
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("tr", { children: [
1452
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: "created" }),
1453
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("td", { style: styles.td, children: new Date(user.createdAt).toLocaleString() })
1684
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1685
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: "created" }),
1686
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: new Date(user.createdAt).toLocaleString() })
1454
1687
  ] })
1455
1688
  ] }) }),
1456
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { ...styles.toolbar, marginTop: 12 }, children: [
1457
- user.suspended ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1689
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { ...styles.toolbar, marginTop: 12 }, children: [
1690
+ user.suspended ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1458
1691
  "button",
1459
1692
  {
1460
1693
  type: "button",
@@ -1463,7 +1696,7 @@ function UsersScreen({ client, pageSize = 50 }) {
1463
1696
  disabled: isLoading,
1464
1697
  children: "Unsuspend"
1465
1698
  }
1466
- ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1699
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1467
1700
  "button",
1468
1701
  {
1469
1702
  type: "button",
@@ -1473,7 +1706,7 @@ function UsersScreen({ client, pageSize = 50 }) {
1473
1706
  children: "Suspend"
1474
1707
  }
1475
1708
  ),
1476
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1709
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1477
1710
  "button",
1478
1711
  {
1479
1712
  type: "button",
@@ -1484,38 +1717,38 @@ function UsersScreen({ client, pageSize = 50 }) {
1484
1717
  }
1485
1718
  )
1486
1719
  ] }),
1487
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Live sessions" }),
1488
- sessions.sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "None." }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { style: styles.list, children: sessions.sessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("li", { style: styles.row, children: [
1489
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.mono, children: s.ipAddress ?? "\u2014" }),
1720
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { style: styles.subtitle, children: "Live sessions" }),
1721
+ sessions.sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.muted, children: "None." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ul", { style: styles.list, children: sessions.sessions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("li", { style: styles.row, children: [
1722
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.mono, children: s.ipAddress ?? "\u2014" }),
1490
1723
  " ",
1491
- (0, import_client.describeLocation)(s.location) ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { style: styles.muted, children: [
1724
+ (0, import_client.describeLocation)(s.location) ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: styles.muted, children: [
1492
1725
  (0, import_client.describeLocation)(s.location),
1493
1726
  " "
1494
1727
  ] }) : null,
1495
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.muted, children: s.userAgent ?? "" }),
1728
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.muted, children: s.userAgent ?? "" }),
1496
1729
  " ",
1497
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("span", { style: styles.muted, children: [
1730
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("span", { style: styles.muted, children: [
1498
1731
  "since ",
1499
1732
  new Date(s.createdAt).toLocaleString()
1500
1733
  ] })
1501
1734
  ] }, s.id)) }),
1502
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h2", { style: styles.subtitle, children: "Recent sign-ins" }),
1503
- history.events.length === 0 && !history.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: styles.muted, children: "None recorded." }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("ul", { style: styles.list, children: history.events.map((e) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("li", { style: styles.row, children: [
1504
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: e.outcome === "success" ? "ok" : "bad", children: e.outcome }),
1735
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { style: styles.subtitle, children: "Recent sign-ins" }),
1736
+ history.events.length === 0 && !history.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.muted, children: "None recorded." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("ul", { style: styles.list, children: history.events.map((e) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("li", { style: styles.row, children: [
1737
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Pill, { tone: e.outcome === "success" ? "ok" : "bad", children: e.outcome }),
1505
1738
  " ",
1506
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.muted, children: e.method }),
1739
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.muted, children: e.method }),
1507
1740
  " ",
1508
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.mono, children: e.ipAddress ?? "\u2014" }),
1741
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.mono, children: e.ipAddress ?? "\u2014" }),
1509
1742
  " ",
1510
- (0, import_client.describeLocation)(e.location) ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.muted, children: (0, import_client.describeLocation)(e.location) }) : null,
1511
- e.location?.proxy || e.location?.hosting ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1743
+ (0, import_client.describeLocation)(e.location) ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.muted, children: (0, import_client.describeLocation)(e.location) }) : null,
1744
+ e.location?.proxy || e.location?.hosting ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1512
1745
  " ",
1513
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Pill, { tone: "warn", children: e.location.proxy ? "proxy/VPN" : "hosting" })
1746
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Pill, { tone: "warn", children: e.location.proxy ? "proxy/VPN" : "hosting" })
1514
1747
  ] }) : null,
1515
1748
  " ",
1516
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: styles.muted, children: new Date(e.createdAt).toLocaleString() })
1749
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: styles.muted, children: new Date(e.createdAt).toLocaleString() })
1517
1750
  ] }, e.id)) }),
1518
- history.hasMore && !history.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1751
+ history.hasMore && !history.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1519
1752
  "button",
1520
1753
  {
1521
1754
  type: "button",
@@ -1529,25 +1762,25 @@ function UsersScreen({ client, pageSize = 50 }) {
1529
1762
  }
1530
1763
 
1531
1764
  // src/screens/CatalogScreen.tsx
1532
- var import_react_admin10 = require("@fonderie/react-admin");
1533
- var import_jsx_runtime11 = require("react/jsx-runtime");
1765
+ var import_react_admin11 = require("@fonderie/react-admin");
1766
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1534
1767
  function CatalogScreen({ client }) {
1535
- const { catalog, isLoading, error, refresh, deletePlan } = (0, import_react_admin10.useAdminCatalog)(client);
1768
+ const { catalog, isLoading, error, refresh, deletePlan } = (0, import_react_admin11.useAdminCatalog)(client);
1536
1769
  const money = (v) => v == null ? "\u2014" : (v / 100).toFixed(2);
1537
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: styles.container, children: [
1538
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1770
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: styles.container, children: [
1771
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1539
1772
  PageHeader,
1540
1773
  {
1541
1774
  title: "Catalog",
1542
1775
  lead: "What you sell: plans as configured in code, and as stored in the database, side by side.",
1543
- actions: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RefreshButton, { onClick: () => void refresh(), busy: isLoading })
1776
+ actions: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RefreshButton, { onClick: () => void refresh(), busy: isLoading })
1544
1777
  }
1545
1778
  ),
1546
- error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
1547
- isLoading && !catalog ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
1548
- catalog ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
1549
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "Configured (code)" }),
1550
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1779
+ error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
1780
+ isLoading && !catalog ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
1781
+ catalog ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1782
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { style: { ...styles.subtitle, marginTop: 0 }, children: "Configured (code)" }),
1783
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1551
1784
  "pre",
1552
1785
  {
1553
1786
  style: {
@@ -1561,32 +1794,32 @@ function CatalogScreen({ client }) {
1561
1794
  children: JSON.stringify(catalog.configured, null, 2)
1562
1795
  }
1563
1796
  ),
1564
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h2", { style: styles.subtitle, children: "Stored (database)" }),
1565
- catalog.stored.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Empty, { icon: "catalog", title: "No stored plans", children: "Plans are configured in code; nothing has been written to the database." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("table", { style: styles.table, children: [
1566
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1567
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Plan" }),
1568
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Tier" }),
1569
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Seats" }),
1570
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Monthly" }),
1571
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Yearly" }),
1572
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th, children: "Trial" }),
1573
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("th", { style: styles.th })
1797
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { style: styles.subtitle, children: "Stored (database)" }),
1798
+ catalog.stored.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Empty, { icon: "catalog", title: "No stored plans", children: "Plans are configured in code; nothing has been written to the database." }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("table", { style: styles.table, children: [
1799
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1800
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Plan" }),
1801
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Tier" }),
1802
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Seats" }),
1803
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Monthly" }),
1804
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Yearly" }),
1805
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Trial" }),
1806
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th })
1574
1807
  ] }) }),
1575
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("tbody", { children: catalog.stored.map((p) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("tr", { children: [
1576
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { style: styles.td, children: [
1577
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("strong", { children: p.name }),
1578
- p.description ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: styles.muted, children: p.description }) : null
1808
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tbody", { children: catalog.stored.map((p) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1809
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("td", { style: styles.td, children: [
1810
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: p.name }),
1811
+ p.description ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: styles.muted, children: p.description }) : null
1579
1812
  ] }),
1580
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: p.tier }),
1581
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: p.seats ?? "\u221E" }),
1582
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("td", { style: styles.td, children: [
1813
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: p.tier }),
1814
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: p.seats ?? "\u221E" }),
1815
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("td", { style: styles.td, children: [
1583
1816
  money(p.pricing?.monthly),
1584
1817
  " ",
1585
1818
  p.pricing?.currency ?? ""
1586
1819
  ] }),
1587
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: money(p.pricing?.yearly) }),
1588
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: p.trialDays ? `${p.trialDays} d` : "\u2014" }),
1589
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1820
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: money(p.pricing?.yearly) }),
1821
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: p.trialDays ? `${p.trialDays} d` : "\u2014" }),
1822
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1590
1823
  "button",
1591
1824
  {
1592
1825
  type: "button",
@@ -1606,33 +1839,33 @@ function CatalogScreen({ client }) {
1606
1839
  }
1607
1840
 
1608
1841
  // src/screens/SubscriberScreen.tsx
1609
- var import_react_admin11 = require("@fonderie/react-admin");
1610
- var import_react4 = require("react");
1611
- var import_jsx_runtime12 = require("react/jsx-runtime");
1842
+ var import_react_admin12 = require("@fonderie/react-admin");
1843
+ var import_react5 = require("react");
1844
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1612
1845
  function SubscriberScreen({ client, pageSize = 50 }) {
1613
- const [type, setType] = (0, import_react4.useState)("user");
1614
- const [idInput, setIdInput] = (0, import_react4.useState)("");
1615
- const [subscriber, setSubscriber] = (0, import_react4.useState)(null);
1616
- const list = (0, import_react_admin11.useAdminSubscribers)(client, { limit: pageSize });
1617
- const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0, import_react_admin11.useAdminSubscriber)(client, subscriber, { limit: 20 });
1618
- const [amount, setAmount] = (0, import_react4.useState)("");
1619
- const [note, setNote] = (0, import_react4.useState)("");
1620
- const [granted, setGranted] = (0, import_react4.useState)(null);
1846
+ const [type, setType] = (0, import_react5.useState)("user");
1847
+ const [idInput, setIdInput] = (0, import_react5.useState)("");
1848
+ const [subscriber, setSubscriber] = (0, import_react5.useState)(null);
1849
+ const list = (0, import_react_admin12.useAdminSubscribers)(client, { limit: pageSize });
1850
+ const { subscription, wallet, ledger, hasMoreLedger, isLoading, error, loadMoreLedger, grant } = (0, import_react_admin12.useAdminSubscriber)(client, subscriber, { limit: 20 });
1851
+ const [amount, setAmount] = (0, import_react5.useState)("");
1852
+ const [note, setNote] = (0, import_react5.useState)("");
1853
+ const [granted, setGranted] = (0, import_react5.useState)(null);
1621
1854
  const open = (t2, id) => {
1622
1855
  setGranted(null);
1623
1856
  setType(t2);
1624
1857
  setIdInput(id);
1625
1858
  setSubscriber({ type: t2, id });
1626
1859
  };
1627
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: styles.container, children: [
1628
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1860
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: styles.container, children: [
1861
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1629
1862
  PageHeader,
1630
1863
  {
1631
1864
  title: "Subscribers",
1632
1865
  lead: "Who is subscribed. Open one for their plan, wallet and ledger, and to grant credit."
1633
1866
  }
1634
1867
  ),
1635
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1868
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1636
1869
  "form",
1637
1870
  {
1638
1871
  style: styles.toolbar,
@@ -1642,7 +1875,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1642
1875
  setSubscriber(idInput.trim() ? { type, id: idInput.trim() } : null);
1643
1876
  },
1644
1877
  children: [
1645
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1878
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1646
1879
  "select",
1647
1880
  {
1648
1881
  value: type,
@@ -1650,12 +1883,12 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1650
1883
  style: styles.input,
1651
1884
  "aria-label": "Type",
1652
1885
  children: [
1653
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "user", children: "user" }),
1654
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: "workspace", children: "workspace" })
1886
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "user", children: "user" }),
1887
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "workspace", children: "workspace" })
1655
1888
  ]
1656
1889
  }
1657
1890
  ),
1658
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1891
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1659
1892
  "input",
1660
1893
  {
1661
1894
  value: idInput,
@@ -1665,11 +1898,11 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1665
1898
  "aria-label": "Subscriber id"
1666
1899
  }
1667
1900
  ),
1668
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
1669
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: "search", size: 14 }),
1901
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
1902
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "search", size: 14 }),
1670
1903
  "Look up"
1671
1904
  ] }),
1672
- subscriber ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1905
+ subscriber ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1673
1906
  "button",
1674
1907
  {
1675
1908
  type: "button",
@@ -1680,11 +1913,11 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1680
1913
  setGranted(null);
1681
1914
  },
1682
1915
  children: [
1683
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: "back", size: 14 }),
1916
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "back", size: 14 }),
1684
1917
  "All subscribers"
1685
1918
  ]
1686
1919
  }
1687
- ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1920
+ ) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1688
1921
  "button",
1689
1922
  {
1690
1923
  type: "button",
@@ -1697,18 +1930,18 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1697
1930
  ]
1698
1931
  }
1699
1932
  ),
1700
- error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
1701
- !subscriber ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1702
- list.error ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
1703
- list.subscriptions.length === 0 && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Empty, { icon: "subscriber", title: "No subscribers yet", children: "Subscriptions appear here once someone checks out." }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("table", { style: styles.table, children: [
1704
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1705
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Subscriber" }),
1706
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Plan" }),
1707
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Status" }),
1708
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Renews" })
1933
+ error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
1934
+ !subscriber ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1935
+ list.error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.error, role: "alert", children: list.error.explanation }) : null,
1936
+ list.subscriptions.length === 0 && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Empty, { icon: "subscriber", title: "No subscribers yet", children: "Subscriptions appear here once someone checks out." }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("table", { style: styles.table, children: [
1937
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { children: [
1938
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Subscriber" }),
1939
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Plan" }),
1940
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Status" }),
1941
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Renews" })
1709
1942
  ] }) }),
1710
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tbody", { children: list.subscriptions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1711
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1943
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: list.subscriptions.map((s) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { children: [
1944
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: styles.td, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1712
1945
  "button",
1713
1946
  {
1714
1947
  type: "button",
@@ -1721,29 +1954,29 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1721
1954
  ]
1722
1955
  }
1723
1956
  ) }),
1724
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("td", { style: styles.td, children: [
1725
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: s.plan }),
1957
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("td", { style: styles.td, children: [
1958
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: s.plan }),
1726
1959
  " \xB7 ",
1727
1960
  s.interval
1728
1961
  ] }),
1729
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("td", { style: styles.td, children: [
1730
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1962
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("td", { style: styles.td, children: [
1963
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1731
1964
  Pill,
1732
1965
  {
1733
1966
  tone: s.status === "active" ? "ok" : s.status === "trialing" ? "info" : s.status === "past_due" ? "warn" : "neutral",
1734
1967
  children: s.status
1735
1968
  }
1736
1969
  ),
1737
- s.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1970
+ s.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1738
1971
  " ",
1739
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Pill, { tone: "warn", dot: false, children: "cancels" })
1972
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Pill, { tone: "warn", dot: false, children: "cancels" })
1740
1973
  ] }) : null
1741
1974
  ] }),
1742
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: styles.muted, children: "\u2014" }) })
1975
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: styles.td, children: s.currentPeriodEnd ? new Date(s.currentPeriodEnd).toLocaleDateString() : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: styles.muted, children: "\u2014" }) })
1743
1976
  ] }, s.id)) })
1744
1977
  ] }),
1745
- list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
1746
- list.hasMore && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1978
+ list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
1979
+ list.hasMore && !list.isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1747
1980
  "button",
1748
1981
  {
1749
1982
  type: "button",
@@ -1753,27 +1986,27 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1753
1986
  }
1754
1987
  ) : null
1755
1988
  ] }) : null,
1756
- subscriber && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1757
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { style: styles.subtitle, children: "Subscription" }),
1758
- subscription ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("table", { style: styles.table, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tbody", { children: [
1759
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1760
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: "plan" }),
1761
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("td", { style: styles.td, children: [
1762
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { children: subscription.plan }),
1989
+ subscriber && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
1990
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { style: styles.subtitle, children: "Subscription" }),
1991
+ subscription ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("table", { style: styles.table, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tbody", { children: [
1992
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { children: [
1993
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: styles.td, children: "plan" }),
1994
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("td", { style: styles.td, children: [
1995
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: subscription.plan }),
1763
1996
  " \xB7 ",
1764
1997
  subscription.interval
1765
1998
  ] })
1766
1999
  ] }),
1767
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1768
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: "status" }),
1769
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("td", { style: styles.td, children: [
2000
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { children: [
2001
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: styles.td, children: "status" }),
2002
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("td", { style: styles.td, children: [
1770
2003
  subscription.status,
1771
2004
  subscription.cancelAtPeriodEnd ? " \xB7 cancels at period end" : ""
1772
2005
  ] })
1773
2006
  ] }),
1774
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1775
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: "period" }),
1776
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("td", { style: styles.td, children: [
2007
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { children: [
2008
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: styles.td, children: "period" }),
2009
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("td", { style: styles.td, children: [
1777
2010
  subscription.currentPeriodStart ? new Date(subscription.currentPeriodStart).toLocaleDateString() : "\u2014",
1778
2011
  " ",
1779
2012
  "\u2192",
@@ -1781,14 +2014,14 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1781
2014
  subscription.currentPeriodEnd ? new Date(subscription.currentPeriodEnd).toLocaleDateString() : "\u2014"
1782
2015
  ] })
1783
2016
  ] }),
1784
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1785
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: "provider" }),
1786
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: subscription.providerSubscriptionId ?? "\u2014" })
2017
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { children: [
2018
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: styles.td, children: "provider" }),
2019
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: subscription.providerSubscriptionId ?? "\u2014" })
1787
2020
  ] })
1788
- ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.muted, children: "No subscription." }),
1789
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { style: styles.subtitle, children: "Wallet" }),
1790
- wallet ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1791
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2021
+ ] }) }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.muted, children: "No subscription." }),
2022
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { style: styles.subtitle, children: "Wallet" }),
2023
+ wallet ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
2024
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1792
2025
  "p",
1793
2026
  {
1794
2027
  style: {
@@ -1799,7 +2032,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1799
2032
  flexWrap: "wrap"
1800
2033
  },
1801
2034
  children: [
1802
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2035
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1803
2036
  "strong",
1804
2037
  {
1805
2038
  style: {
@@ -1812,7 +2045,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1812
2045
  " ",
1813
2046
  wallet.currency,
1814
2047
  " ",
1815
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { style: styles.muted, children: [
2048
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { style: styles.muted, children: [
1816
2049
  "(granted ",
1817
2050
  wallet.granted ?? "0",
1818
2051
  " \xB7 purchased ",
@@ -1823,7 +2056,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1823
2056
  ]
1824
2057
  }
1825
2058
  ),
1826
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2059
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1827
2060
  "form",
1828
2061
  {
1829
2062
  style: styles.toolbar,
@@ -1842,7 +2075,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1842
2075
  });
1843
2076
  },
1844
2077
  children: [
1845
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2078
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1846
2079
  "input",
1847
2080
  {
1848
2081
  value: amount,
@@ -1852,7 +2085,7 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1852
2085
  "aria-label": "Amount"
1853
2086
  }
1854
2087
  ),
1855
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2088
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1856
2089
  "input",
1857
2090
  {
1858
2091
  value: note,
@@ -1862,38 +2095,38 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1862
2095
  "aria-label": "Reason"
1863
2096
  }
1864
2097
  ),
1865
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2098
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1866
2099
  "button",
1867
2100
  {
1868
2101
  type: "submit",
1869
2102
  style: styles.buttonPrimary,
1870
2103
  disabled: !/^\d+$/.test(amount.trim()),
1871
2104
  children: [
1872
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { name: "plus", size: 14 }),
2105
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "plus", size: 14 }),
1873
2106
  "Grant"
1874
2107
  ]
1875
2108
  }
1876
2109
  ),
1877
- granted ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: styles.ok, children: granted }) : null
2110
+ granted ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: styles.ok, children: granted }) : null
1878
2111
  ]
1879
2112
  }
1880
2113
  ),
1881
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h2", { style: styles.subtitle, children: "Ledger" }),
1882
- ledger.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Empty, { icon: "subscriber", title: "Nothing moved yet" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("table", { style: styles.table, children: [
1883
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1884
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "When" }),
1885
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Kind" }),
1886
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Amount" }),
1887
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("th", { style: styles.th, children: "Note" })
2114
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { style: styles.subtitle, children: "Ledger" }),
2115
+ ledger.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Empty, { icon: "subscriber", title: "Nothing moved yet" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("table", { style: styles.table, children: [
2116
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { children: [
2117
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "When" }),
2118
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Kind" }),
2119
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Amount" }),
2120
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Note" })
1888
2121
  ] }) }),
1889
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("tbody", { children: ledger.map((t2) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("tr", { children: [
1890
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(t2.createdAt).toLocaleString() }),
1891
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: styles.td, children: t2.type }),
1892
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: t2.amount }),
1893
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t2.description ?? "" })
2122
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: ledger.map((t2) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { children: [
2123
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(t2.createdAt).toLocaleString() }),
2124
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: styles.td, children: t2.type }),
2125
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: t2.amount }),
2126
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: t2.description ?? "" })
1894
2127
  ] }, t2.id)) })
1895
2128
  ] }),
1896
- hasMoreLedger ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2129
+ hasMoreLedger ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1897
2130
  "button",
1898
2131
  {
1899
2132
  type: "button",
@@ -1902,25 +2135,25 @@ function SubscriberScreen({ client, pageSize = 50 }) {
1902
2135
  children: "Load more"
1903
2136
  }
1904
2137
  ) : null
1905
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: styles.muted, children: "No wallet \u2014 billing has no wallet configuration." })
2138
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.muted, children: "No wallet \u2014 billing has no wallet configuration." })
1906
2139
  ] }) : null
1907
2140
  ] });
1908
2141
  }
1909
2142
 
1910
2143
  // src/screens/AuditScreen.tsx
1911
- var import_react_admin12 = require("@fonderie/react-admin");
1912
- var import_react5 = require("react");
1913
- var import_jsx_runtime13 = require("react/jsx-runtime");
2144
+ var import_react_admin13 = require("@fonderie/react-admin");
2145
+ var import_react6 = require("react");
2146
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1914
2147
  function AuditScreen({ client, pageSize = 50 }) {
1915
- const [draft, setDraft] = (0, import_react5.useState)({ workspaceId: "", type: "", actorId: "" });
1916
- const [filter, setFilter] = (0, import_react5.useState)(
2148
+ const [draft, setDraft] = (0, import_react6.useState)({ workspaceId: "", type: "", actorId: "" });
2149
+ const [filter, setFilter] = (0, import_react6.useState)(
1917
2150
  {}
1918
2151
  );
1919
- const { events, hasMore, isLoading, error, refresh, loadMore } = (0, import_react_admin12.useAdminAudit)(client, {
2152
+ const { events, hasMore, isLoading, error, refresh, loadMore } = (0, import_react_admin13.useAdminAudit)(client, {
1920
2153
  ...filter,
1921
2154
  limit: pageSize
1922
2155
  });
1923
- const field = (key, placeholder) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2156
+ const field = (key, placeholder) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1924
2157
  "input",
1925
2158
  {
1926
2159
  value: draft[key],
@@ -1930,15 +2163,15 @@ function AuditScreen({ client, pageSize = 50 }) {
1930
2163
  "aria-label": placeholder
1931
2164
  }
1932
2165
  );
1933
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: styles.container, children: [
1934
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2166
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: styles.container, children: [
2167
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1935
2168
  PageHeader,
1936
2169
  {
1937
2170
  title: "Audit",
1938
2171
  lead: "What happened, across every workspace unless you name one. The chain's integrity verdict is on the Doctor page."
1939
2172
  }
1940
2173
  ),
1941
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
2174
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1942
2175
  "form",
1943
2176
  {
1944
2177
  style: styles.toolbar,
@@ -1954,11 +2187,11 @@ function AuditScreen({ client, pageSize = 50 }) {
1954
2187
  field("workspaceId", "workspace id (all if empty)"),
1955
2188
  field("type", "event type"),
1956
2189
  field("actorId", "actor id"),
1957
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
1958
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Icon, { name: "search", size: 14 }),
2190
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { type: "submit", style: styles.buttonPrimary, disabled: isLoading, children: [
2191
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { name: "search", size: 14 }),
1959
2192
  "Filter"
1960
2193
  ] }),
1961
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2194
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1962
2195
  "button",
1963
2196
  {
1964
2197
  type: "button",
@@ -1971,25 +2204,25 @@ function AuditScreen({ client, pageSize = 50 }) {
1971
2204
  ]
1972
2205
  }
1973
2206
  ),
1974
- error ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
1975
- events.length === 0 && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Empty, { icon: "audit", title: "Nothing recorded for this filter" }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("table", { style: styles.table, children: [
1976
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { children: [
1977
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "When" }),
1978
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Type" }),
1979
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Workspace" }),
1980
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Actor" }),
1981
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("th", { style: styles.th, children: "Request" })
2207
+ error ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: styles.error, role: "alert", children: error.explanation }) : null,
2208
+ events.length === 0 && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Empty, { icon: "audit", title: "Nothing recorded for this filter" }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("table", { style: styles.table, children: [
2209
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("tr", { children: [
2210
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { style: styles.th, children: "When" }),
2211
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { style: styles.th, children: "Type" }),
2212
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { style: styles.th, children: "Workspace" }),
2213
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { style: styles.th, children: "Actor" }),
2214
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("th", { style: styles.th, children: "Request" })
1982
2215
  ] }) }),
1983
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: events.map((e) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("tr", { children: [
1984
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(e.createdAt).toLocaleString() }),
1985
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.type }),
1986
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: String(e.payload["workspaceId"] ?? "\u2014") }),
1987
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.actorId ?? "\u2014" }),
1988
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: e.requestId ?? "" })
2216
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("tbody", { children: events.map((e) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("tr", { children: [
2217
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: new Date(e.createdAt).toLocaleString() }),
2218
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.type }),
2219
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: String(e.payload["workspaceId"] ?? "\u2014") }),
2220
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { style: { ...styles.td, ...styles.mono }, children: e.actorId ?? "\u2014" }),
2221
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("td", { style: { ...styles.td, ...styles.muted }, children: e.requestId ?? "" })
1989
2222
  ] }, e.id)) })
1990
2223
  ] }),
1991
- isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
1992
- hasMore && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2224
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: styles.status, children: "Loading\u2026" }) : null,
2225
+ hasMore && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1993
2226
  "button",
1994
2227
  {
1995
2228
  type: "button",
@@ -2002,7 +2235,7 @@ function AuditScreen({ client, pageSize = 50 }) {
2002
2235
  }
2003
2236
 
2004
2237
  // src/screens/AdminShell.tsx
2005
- var import_jsx_runtime14 = require("react/jsx-runtime");
2238
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2006
2239
  var ICON = {
2007
2240
  attention: "attention",
2008
2241
  modules: "modules",
@@ -2017,13 +2250,14 @@ var ICON = {
2017
2250
  audit: "audit",
2018
2251
  log: "log",
2019
2252
  tokens: "tokens",
2253
+ operators: "users",
2020
2254
  migrations: "migrations"
2021
2255
  };
2022
2256
  var NARROW = "(max-width: 820px)";
2023
2257
  function useNarrow() {
2024
2258
  const query = typeof window !== "undefined" && window.matchMedia ? window.matchMedia(NARROW) : null;
2025
- const [narrow, setNarrow] = (0, import_react6.useState)(() => query?.matches ?? false);
2026
- (0, import_react6.useEffect)(() => {
2259
+ const [narrow, setNarrow] = (0, import_react7.useState)(() => query?.matches ?? false);
2260
+ (0, import_react7.useEffect)(() => {
2027
2261
  if (!query) return;
2028
2262
  const on = (e) => setNarrow(e.matches);
2029
2263
  query.addEventListener("change", on);
@@ -2057,7 +2291,8 @@ var NAV = [
2057
2291
  items: [
2058
2292
  { page: "audit", label: "Audit", needs: "audit" },
2059
2293
  { page: "log", label: "Admin log" },
2060
- { page: "tokens", label: "Access" },
2294
+ { page: "operators", label: "Operators", needs: "operators" },
2295
+ { page: "tokens", label: "Tokens" },
2061
2296
  { page: "migrations", label: "Migrations" }
2062
2297
  ]
2063
2298
  }
@@ -2074,70 +2309,76 @@ function AdminShell({
2074
2309
  onNavigate,
2075
2310
  appName = "Admin",
2076
2311
  envLabel,
2077
- footer
2312
+ footer,
2313
+ operators = false,
2314
+ currentOperator
2078
2315
  }) {
2079
2316
  const narrow = useNarrow();
2080
- const [drawer, setDrawer] = (0, import_react6.useState)(false);
2081
- const [own, setOwn] = (0, import_react6.useState)("attention");
2317
+ const [drawer, setDrawer] = (0, import_react7.useState)(false);
2318
+ const [own, setOwn] = (0, import_react7.useState)("attention");
2082
2319
  const current = page ?? own;
2083
2320
  const go = (p) => {
2084
2321
  if (onNavigate) onNavigate(p);
2085
2322
  if (page === void 0) setOwn(p);
2086
2323
  setDrawer(false);
2087
2324
  };
2088
- const [editing, setEditing] = (0, import_react6.useState)(null);
2325
+ const [editing, setEditing] = (0, import_react7.useState)(null);
2089
2326
  const has = {
2090
2327
  config: Boolean(configClient),
2091
2328
  courier: Boolean(courierClient),
2092
2329
  auth: Boolean(authClient),
2093
2330
  billing: Boolean(billingClient),
2094
- audit: Boolean(auditClient)
2331
+ audit: Boolean(auditClient),
2332
+ operators
2095
2333
  };
2096
2334
  let body;
2097
2335
  switch (current) {
2098
2336
  case "attention":
2099
- body = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AttentionScreen, { client });
2337
+ body = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AttentionScreen, { client });
2100
2338
  break;
2101
2339
  case "modules":
2102
- body = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ModulesScreen, { client });
2340
+ body = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ModulesScreen, { client });
2103
2341
  break;
2104
2342
  case "doctor":
2105
- body = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DoctorScreen, { client });
2343
+ body = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DoctorScreen, { client });
2106
2344
  break;
2107
2345
  case "environment":
2108
- body = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(EnvironmentScreen, { client });
2346
+ body = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(EnvironmentScreen, { client });
2109
2347
  break;
2110
2348
  case "routes":
2111
- body = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(RoutesScreen, { client });
2349
+ body = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(RoutesScreen, { client });
2112
2350
  break;
2113
2351
  case "tokens":
2114
- body = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TokensScreen, { client });
2352
+ body = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TokensScreen, { client });
2353
+ break;
2354
+ case "operators":
2355
+ body = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(OperatorsScreen, { client, me: currentOperator });
2115
2356
  break;
2116
2357
  case "migrations":
2117
- body = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(MigrationsScreen, { client });
2358
+ body = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MigrationsScreen, { client });
2118
2359
  break;
2119
2360
  case "log":
2120
- body = /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AdminLogScreen, { client });
2361
+ body = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AdminLogScreen, { client });
2121
2362
  break;
2122
2363
  case "catalog":
2123
- body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a BillingAdminClient to see the catalog here." });
2364
+ body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(CatalogScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a BillingAdminClient to see the catalog here." });
2124
2365
  break;
2125
2366
  case "subscriber":
2126
- body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SubscriberScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a BillingAdminClient to look up subscribers here." });
2367
+ body = billingClient ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SubscriberScreen, { client: billingClient }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a BillingAdminClient to look up subscribers here." });
2127
2368
  break;
2128
2369
  case "audit":
2129
- body = auditClient ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(AuditScreen, { client: auditClient }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass an AuditAdminClient to see the audit trail here." });
2370
+ body = auditClient ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AuditScreen, { client: auditClient }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass an AuditAdminClient to see the audit trail here." });
2130
2371
  break;
2131
2372
  case "users":
2132
- body = authClient ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UsersScreen, { client: authClient }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass an AuthAdminClient to look up users here." });
2373
+ body = authClient ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(UsersScreen, { client: authClient }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass an AuthAdminClient to look up users here." });
2133
2374
  break;
2134
2375
  case "settings":
2135
- body = !configClient ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a ConfigAdminClient to manage config and secrets here." }) : editing && editing.kind !== "template" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2136
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
2137
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { name: "back", size: 14 }),
2376
+ body = !configClient ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a ConfigAdminClient to manage config and secrets here." }) : editing && editing.kind !== "template" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2377
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
2378
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, { name: "back", size: 14 }),
2138
2379
  "Config & secrets"
2139
2380
  ] }) }),
2140
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2381
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2141
2382
  import_react_config_admin_screens.ConfigEditorScreen,
2142
2383
  {
2143
2384
  client: configClient,
@@ -2147,7 +2388,7 @@ function AdminShell({
2147
2388
  onSaved: () => setEditing(null)
2148
2389
  }
2149
2390
  )
2150
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2391
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2151
2392
  import_react_config_admin_screens.ConfigListScreen,
2152
2393
  {
2153
2394
  client: configClient,
@@ -2160,12 +2401,12 @@ function AdminShell({
2160
2401
  );
2161
2402
  break;
2162
2403
  case "templates":
2163
- body = !courierClient ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a CourierAdminClient to manage templates here." }) : editing?.kind === "template" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2164
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
2165
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { name: "back", size: 14 }),
2404
+ body = !courierClient ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("p", { style: { ...styles.status, padding: "32px 40px" }, children: "Pass a CourierAdminClient to manage templates here." }) : editing?.kind === "template" ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2405
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { padding: "24px 40px 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("button", { type: "button", style: styles.buttonGhost, onClick: () => setEditing(null), children: [
2406
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, { name: "back", size: 14 }),
2166
2407
  "Templates"
2167
2408
  ] }) }),
2168
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2409
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2169
2410
  import_react_courier_admin_screens.TemplateEditorScreen,
2170
2411
  {
2171
2412
  client: courierClient,
@@ -2173,7 +2414,7 @@ function AdminShell({
2173
2414
  onSaved: () => setEditing(null)
2174
2415
  }
2175
2416
  )
2176
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2417
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2177
2418
  import_react_courier_admin_screens.TemplateListScreen,
2178
2419
  {
2179
2420
  client: courierClient,
@@ -2183,11 +2424,11 @@ function AdminShell({
2183
2424
  break;
2184
2425
  }
2185
2426
  const production = envLabel ? /^prod/i.test(envLabel) : false;
2186
- const brand = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: styles.navBrand, children: [
2187
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: styles.navMark, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { name: "mark", size: 15 }) }),
2188
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
2189
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: styles.navBrandTitle, children: appName }),
2190
- envLabel ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2427
+ const brand = /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: styles.navBrand, children: [
2428
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: styles.navMark, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, { name: "mark", size: 15 }) }),
2429
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { minWidth: 0, flex: 1 }, children: [
2430
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: styles.navBrandTitle, children: appName }),
2431
+ envLabel ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2191
2432
  "span",
2192
2433
  {
2193
2434
  style: {
@@ -2204,18 +2445,18 @@ function AdminShell({
2204
2445
  }
2205
2446
  ) : null
2206
2447
  ] }),
2207
- narrow ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2448
+ narrow ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2208
2449
  "button",
2209
2450
  {
2210
2451
  type: "button",
2211
2452
  style: styles.buttonGhost,
2212
2453
  "aria-label": "Close menu",
2213
2454
  onClick: () => setDrawer(false),
2214
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { name: "close" })
2455
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, { name: "close" })
2215
2456
  }
2216
2457
  ) : null
2217
2458
  ] });
2218
- const nav = /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2459
+ const nav = /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2219
2460
  "nav",
2220
2461
  {
2221
2462
  style: {
@@ -2225,14 +2466,14 @@ function AdminShell({
2225
2466
  "aria-label": "Admin",
2226
2467
  children: [
2227
2468
  brand,
2228
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: styles.navScroll, children: NAV.map((g) => {
2469
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: styles.navScroll, children: NAV.map((g) => {
2229
2470
  const items = g.items.filter((i) => !i.needs || has[i.needs]);
2230
2471
  if (items.length === 0) return null;
2231
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
2232
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: styles.navGroup, children: g.group }),
2472
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
2473
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: styles.navGroup, children: g.group }),
2233
2474
  items.map((i) => {
2234
2475
  const active = current === i.page;
2235
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2476
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2236
2477
  "button",
2237
2478
  {
2238
2479
  type: "button",
@@ -2244,7 +2485,7 @@ function AdminShell({
2244
2485
  go(i.page);
2245
2486
  },
2246
2487
  children: [
2247
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { name: ICON[i.page], style: active ? styles.navIconActive : void 0 }),
2488
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, { name: ICON[i.page], style: active ? styles.navIconActive : void 0 }),
2248
2489
  i.label
2249
2490
  ]
2250
2491
  },
@@ -2253,15 +2494,15 @@ function AdminShell({
2253
2494
  })
2254
2495
  ] }, g.group);
2255
2496
  }) }),
2256
- footer ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: styles.navFooter, children: footer }) : null
2497
+ footer ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: styles.navFooter, children: footer }) : null
2257
2498
  ]
2258
2499
  }
2259
2500
  );
2260
2501
  const title = NAV.flatMap((g) => g.items).find((i) => i.page === current)?.label ?? "";
2261
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { ...styles.shell, ...narrow ? { flexDirection: "column" } : {} }, children: [
2262
- narrow ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2263
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: styles.topbar, children: [
2264
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2502
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { ...styles.shell, ...narrow ? { flexDirection: "column" } : {} }, children: [
2503
+ narrow ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
2504
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: styles.topbar, children: [
2505
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2265
2506
  "button",
2266
2507
  {
2267
2508
  type: "button",
@@ -2269,18 +2510,18 @@ function AdminShell({
2269
2510
  "aria-label": "Open menu",
2270
2511
  "aria-expanded": drawer,
2271
2512
  onClick: () => setDrawer(true),
2272
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Icon, { name: "menu" })
2513
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Icon, { name: "menu" })
2273
2514
  }
2274
2515
  ),
2275
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { fontWeight: 600, fontSize: 14 }, children: title }),
2276
- envLabel ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { ...styles.badge, marginLeft: "auto" }, children: envLabel }) : null
2516
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { fontWeight: 600, fontSize: 14 }, children: title }),
2517
+ envLabel ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { ...styles.badge, marginLeft: "auto" }, children: envLabel }) : null
2277
2518
  ] }),
2278
- drawer ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: styles.drawer, children: [
2519
+ drawer ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: styles.drawer, children: [
2279
2520
  nav,
2280
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: styles.scrim, onClick: () => setDrawer(false), "aria-hidden": "true" })
2521
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: styles.scrim, onClick: () => setDrawer(false), "aria-hidden": "true" })
2281
2522
  ] }) : null
2282
2523
  ] }) : nav,
2283
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("main", { className: "fonderie-admin-main", style: styles.main, children: body })
2524
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("main", { className: "fonderie-admin-main", style: styles.main, children: body })
2284
2525
  ] });
2285
2526
  }
2286
2527
  // Annotate the CommonJS export names for ESM import in node:
@@ -2294,6 +2535,7 @@ function AdminShell({
2294
2535
  EnvironmentScreen,
2295
2536
  MigrationsScreen,
2296
2537
  ModulesScreen,
2538
+ OperatorsScreen,
2297
2539
  RoutesScreen,
2298
2540
  SubscriberScreen,
2299
2541
  TokensScreen,