@usethrottle/auth 0.2.1 → 0.2.3

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.
@@ -24,6 +24,7 @@ __export(components_exports, {
24
24
  ACCOUNT_TABS: () => ACCOUNT_TABS,
25
25
  AccountDashboard: () => AccountDashboard,
26
26
  AccountModal: () => AccountModal,
27
+ AddCardDialog: () => AddCardDialog,
27
28
  AddressesPanel: () => AddressesPanel,
28
29
  AuthFlow: () => AuthFlow,
29
30
  AuthModal: () => AuthModal,
@@ -78,7 +79,7 @@ __export(components_exports, {
78
79
  module.exports = __toCommonJS(components_exports);
79
80
 
80
81
  // src/react/components/provider.tsx
81
- var import_react29 = require("react");
82
+ var import_react31 = require("react");
82
83
 
83
84
  // src/errors.ts
84
85
  var ThrottleAuthError = class extends Error {
@@ -444,6 +445,13 @@ function createAccount(auth) {
444
445
  // this is how a buyer changes what they are billed on: move the default.
445
446
  setDefaultPaymentMethod: (id) => call("PATCH", `/me/payment-methods/${seg(id)}`, { isDefault: true }),
446
447
  deletePaymentMethod: (id) => call("DELETE", `/me/payment-methods/${seg(id)}`),
448
+ // Saving a card is two calls because the card number never reaches us: the
449
+ // first mints a processor-hosted embed session, the buyer types their card
450
+ // into that, and the second records what the processor vaulted. Everything
451
+ // about the saved card is read back from the processor, so nothing here
452
+ // trusts what the browser claims the card was.
453
+ startCardSetup: () => call("POST", "/me/payment-methods/embed-token"),
454
+ confirmCardSetup: (transactionId) => call("POST", "/me/payment-methods/confirm", { transactionId }),
447
455
  listOrders: (page) => call("GET", `/me/orders${query(page)}`),
448
456
  getOrder: (id) => call("GET", `/me/orders/${seg(id)}`),
449
457
  listInvoices: (page) => call("GET", `/me/invoices${query(page)}`),
@@ -595,6 +603,7 @@ var VARIABLE_PROPERTY = {
595
603
  colorMuted: "--throttle-color-muted",
596
604
  colorMutedForeground: "--throttle-color-muted-foreground",
597
605
  colorBorder: "--throttle-color-border",
606
+ colorBorderControl: "--throttle-color-border-control",
598
607
  colorDanger: "--throttle-color-danger",
599
608
  colorDangerSurface: "--throttle-color-danger-surface",
600
609
  colorDangerBorder: "--throttle-color-danger-border",
@@ -609,6 +618,12 @@ var VARIABLE_PROPERTY = {
609
618
  borderRadius: "--throttle-radius",
610
619
  borderWidth: "--throttle-border-width",
611
620
  spacing: "--throttle-spacing",
621
+ // The account dashboard's own surface and outer padding. Separate from
622
+ // colorBackground/colorSurface because a merchant embedding the dashboard
623
+ // in their page usually wants it to paint nothing at all, while still
624
+ // theming the cards inside it.
625
+ accountSurface: "--throttle-color-account-surface",
626
+ accountPadding: "--throttle-account-padding",
612
627
  shadowCard: "--throttle-shadow-card",
613
628
  shadowPopover: "--throttle-shadow-popover",
614
629
  transition: "--throttle-transition",
@@ -743,6 +758,8 @@ var THROTTLE_ELEMENT_KEYS = [
743
758
  "paymentMethodsPanel.item",
744
759
  "paymentMethodsPanel.defaultButton",
745
760
  "paymentMethodsPanel.deleteButton",
761
+ "paymentMethodsPanel.addButton",
762
+ "paymentMethodsPanel.addDialog",
746
763
  "paymentMethodsPanel.table",
747
764
  "paymentMethodsPanel.row",
748
765
  "ordersPanel.root",
@@ -851,6 +868,10 @@ function waitCopy(seconds) {
851
868
  const minutes = Math.ceil(seconds / 60);
852
869
  return `Please wait ${minutes} ${minutes === 1 ? "minute" : "minutes"} and try again.`;
853
870
  }
871
+ function fieldLabel(path) {
872
+ const words = path.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/([a-zA-Z])([0-9])/g, "$1 $2").toLowerCase().trim();
873
+ return words.charAt(0).toUpperCase() + words.slice(1);
874
+ }
854
875
  function messageForError(err) {
855
876
  const e = err;
856
877
  switch (e?.code) {
@@ -883,6 +904,13 @@ function messageForError(err) {
883
904
  return "We could not find that.";
884
905
  case "payment_method_in_use":
885
906
  return e.message || "That payment method is in use and cannot be removed.";
907
+ case "validation_error": {
908
+ const first2 = e.details?.[0];
909
+ if (first2?.path && first2?.message) {
910
+ return `${fieldLabel(first2.path)} ${first2.message.replace(/\bNOT\b/g, "not")}.`;
911
+ }
912
+ return "Please check the highlighted fields and try again.";
913
+ }
886
914
  default:
887
915
  return "Something went wrong. Please try again.";
888
916
  }
@@ -1017,8 +1045,9 @@ var enUS = {
1017
1045
  },
1018
1046
  paymentMethods: {
1019
1047
  empty: "No saved cards",
1020
- // True today and still true once a buyer-plane add-card route exists.
1021
- emptyDescription: "Cards you use at checkout will be saved here.",
1048
+ emptyDescription: "Add a card here, or one will be saved when you check out.",
1049
+ addButton: "Add card",
1050
+ addTitle: "Add a card",
1022
1051
  // Shown whenever the panel is empty with no error and the buyer is not
1023
1052
  // verified — including simply being signed out — matching the copy
1024
1053
  // orders/invoices/subscriptions already show in that state.
@@ -1209,6 +1238,19 @@ var THROTTLE_STYLES = `
1209
1238
  --throttle-color-muted: #eceef2;
1210
1239
  --throttle-color-muted-foreground: #5b6472;
1211
1240
  --throttle-color-border: #e2e8f0;
1241
+ /* The boundary of an INTERACTIVE control, which WCAG 1.4.11 requires to
1242
+ reach 3:1 against its adjacent colour \u2014 an input identified only by a
1243
+ 1.23:1 hairline is not identifiable at all. Decorative separators (card
1244
+ edges, table rules, dividers) keep --throttle-color-border: they do not
1245
+ identify a control, so the requirement does not apply and darkening
1246
+ them would only add noise. */
1247
+ /* The account dashboard paints nothing by default so it can drop into a
1248
+ merchant's page without fighting their background. The accountSurface and
1249
+ accountPadding appearance variables opt back into a card.
1250
+ No backticks in this comment: the sheet is a TS template literal. */
1251
+ --throttle-color-account-surface: transparent;
1252
+ --throttle-account-padding: 0;
1253
+ --throttle-color-border-control: #8b93a1;
1212
1254
  --throttle-color-danger: #c2321f;
1213
1255
  --throttle-color-danger-surface: #fef2f2;
1214
1256
  --throttle-color-danger-border: #fecaca;
@@ -1261,6 +1303,7 @@ var THROTTLE_STYLES = `
1261
1303
  --throttle-color-muted: #21262d;
1262
1304
  --throttle-color-muted-foreground: #9aa4b2;
1263
1305
  --throttle-color-border: #30363d;
1306
+ --throttle-color-border-control: #5c6570;
1264
1307
  --throttle-color-danger: #ff6b58;
1265
1308
  --throttle-color-danger-surface: #2a1513;
1266
1309
  --throttle-color-danger-border: #5c2b25;
@@ -1283,6 +1326,7 @@ var THROTTLE_STYLES = `
1283
1326
  --throttle-color-muted: #21262d;
1284
1327
  --throttle-color-muted-foreground: #9aa4b2;
1285
1328
  --throttle-color-border: #30363d;
1329
+ --throttle-color-border-control: #5c6570;
1286
1330
  --throttle-color-danger: #ff6b58;
1287
1331
  --throttle-color-danger-surface: #2a1513;
1288
1332
  --throttle-color-danger-border: #5c2b25;
@@ -1330,7 +1374,7 @@ var THROTTLE_STYLES = `
1330
1374
  font-size: var(--throttle-font-size);
1331
1375
  color: var(--throttle-color-foreground);
1332
1376
  background: var(--throttle-color-background);
1333
- border: var(--throttle-border-width) solid var(--throttle-color-border);
1377
+ border: var(--throttle-border-width) solid var(--throttle-color-border-control);
1334
1378
  border-radius: var(--throttle-radius-sm);
1335
1379
  /* padding-block stays 0 so min-height alone owns the height, exactly as
1336
1380
  .throttle-button does. With 12px vertical padding the box computed to
@@ -1354,7 +1398,13 @@ var THROTTLE_STYLES = `
1354
1398
  /* Always mounted, so it reserves its line whether or not there is an error:
1355
1399
  an error appearing on submit must not push the submit button out from
1356
1400
  under the buyer's pointer. */
1357
- .throttle-field__error { color: var(--throttle-color-danger); font-size: var(--throttle-font-size-xs); min-height: 1rem; line-height: 1rem; }
1401
+ .throttle-field__error { color: var(--throttle-color-danger); font-size: var(--throttle-font-size-xs); line-height: 1rem; }
1402
+ /* Reserved a full line under EVERY input even with nothing to say, which
1403
+ with the stack gap put 28px of dead space beneath each field, on every
1404
+ form and all seven account panels. The element stays mounted when empty
1405
+ because role=alert only announces changes to a live region that was
1406
+ already there; it just stops occupying a line. */
1407
+ .throttle-field__error:empty { display: none; }
1358
1408
 
1359
1409
  .throttle-field-group {
1360
1410
  display: flex;
@@ -1385,7 +1435,7 @@ var THROTTLE_STYLES = `
1385
1435
  .throttle-button:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--throttle-color-background), 0 0 0 4px var(--throttle-color-primary); }
1386
1436
  .throttle-button--primary { background: var(--throttle-color-primary); color: var(--throttle-color-primary-foreground); width: 100%; }
1387
1437
  .throttle-button--primary:hover:not(:disabled) { filter: brightness(0.92); }
1388
- .throttle-button--secondary { background: var(--throttle-color-surface); color: var(--throttle-color-foreground); border-color: var(--throttle-color-border); }
1438
+ .throttle-button--secondary { background: var(--throttle-color-surface); color: var(--throttle-color-foreground); border-color: var(--throttle-color-border-control); }
1389
1439
  .throttle-button--secondary:hover:not(:disabled) { background: var(--throttle-color-muted); }
1390
1440
  .throttle-button--danger { background: transparent; color: var(--throttle-color-danger); border-color: var(--throttle-color-border); }
1391
1441
  .throttle-button--danger:hover:not(:disabled) { background: color-mix(in srgb, var(--throttle-color-danger) 10%, transparent); }
@@ -1413,6 +1463,11 @@ var THROTTLE_STYLES = `
1413
1463
  animation: throttle-spin 700ms linear infinite;
1414
1464
  }
1415
1465
  @keyframes throttle-spin { to { transform: rotate(360deg); } }
1466
+ .throttle-button--loading { position: relative; }
1467
+ .throttle-button__label { display: inline-flex; align-items: center; justify-content: center; gap: var(--throttle-space-2); }
1468
+ .throttle-button__label--hidden { visibility: hidden; }
1469
+ .throttle-spinner--centred { position: absolute; top: 50%; left: 50%; margin: -0.5em 0 0 -0.5em; }
1470
+
1416
1471
  @media (prefers-reduced-motion: reduce) { .throttle-spinner { animation-duration: 2.4s; } }
1417
1472
 
1418
1473
  .throttle-skeleton {
@@ -1495,7 +1550,9 @@ var THROTTLE_STYLES = `
1495
1550
  /* Paints its own ground. A UserButton in a navbar should stay transparent, but
1496
1551
  the dashboard is a large surface of themed text: in dark theme its foreground
1497
1552
  is near-white, so on a light host page it was rendering white-on-white. */
1498
- .throttle-account-root { container-type: inline-size; background: var(--throttle-color-background); color: var(--throttle-color-foreground); }
1553
+ .throttle-cardframe { width: 100%; min-height: 420px; border: 0; display: block; }
1554
+ .throttle-centre { display: flex; align-items: center; justify-content: center; min-height: 160px; }
1555
+ .throttle-account-root { container-type: inline-size; background: var(--throttle-color-account-surface); color: var(--throttle-color-foreground); padding: var(--throttle-account-padding); }
1499
1556
  .throttle-account { display: flex; gap: var(--throttle-space-5); align-items: flex-start; }
1500
1557
  .throttle-account__content { flex: 1; min-width: 0; }
1501
1558
  .throttle-tabs__rail { flex: none; width: 220px; display: flex; flex-direction: column; gap: 2px; }
@@ -1675,11 +1732,12 @@ function CardFooter(props) {
1675
1732
 
1676
1733
  // src/react/components/primitives/Spinner.tsx
1677
1734
  var import_jsx_runtime7 = require("react/jsx-runtime");
1678
- function Spinner() {
1735
+ function Spinner({ centred } = {}) {
1679
1736
  const a = useAppearance();
1680
1737
  const Slot = a.slots.Spinner;
1681
1738
  if (Slot) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Slot, {});
1682
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { ...a.el("spinner", "throttle-spinner"), "aria-hidden": "true" });
1739
+ const cls = `throttle-spinner${centred ? " throttle-spinner--centred" : ""}`;
1740
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { ...a.el("spinner", cls), "aria-hidden": "true" });
1683
1741
  }
1684
1742
 
1685
1743
  // src/react/components/primitives/Button.tsx
@@ -1688,7 +1746,7 @@ function Button({ variant = "primary", size = "default", elementKey, loading, ch
1688
1746
  const a = useAppearance();
1689
1747
  const Slot = a.slots.Button;
1690
1748
  if (Slot) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Slot, { variant, loading, ...rest, children });
1691
- const base = `throttle-button throttle-button--${variant}${size === "xs" ? " throttle-button--xs" : ""}`;
1749
+ const base = `throttle-button throttle-button--${variant}${size === "xs" ? " throttle-button--xs" : ""}${loading ? " throttle-button--loading" : ""}`;
1692
1750
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1693
1751
  "button",
1694
1752
  {
@@ -1696,9 +1754,10 @@ function Button({ variant = "primary", size = "default", elementKey, loading, ch
1696
1754
  ...rest,
1697
1755
  ...a.el(elementKey ?? "button", base),
1698
1756
  disabled: rest.disabled || loading,
1757
+ "aria-busy": loading ? true : void 0,
1699
1758
  children: [
1700
- loading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Spinner, {}) : null,
1701
- children
1759
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Spinner, { centred: true }) : null,
1760
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: `throttle-button__label${loading ? " throttle-button__label--hidden" : ""}`, children })
1702
1761
  ]
1703
1762
  }
1704
1763
  );
@@ -1808,14 +1867,14 @@ function Modal(props) {
1808
1867
  e.preventDefault();
1809
1868
  return;
1810
1869
  }
1811
- const first = items[0];
1870
+ const first2 = items[0];
1812
1871
  const last = items[items.length - 1];
1813
- if (e.shiftKey && document.activeElement === first) {
1872
+ if (e.shiftKey && document.activeElement === first2) {
1814
1873
  e.preventDefault();
1815
1874
  last.focus();
1816
1875
  } else if (!e.shiftKey && document.activeElement === last) {
1817
1876
  e.preventDefault();
1818
- first.focus();
1877
+ first2.focus();
1819
1878
  }
1820
1879
  };
1821
1880
  document.addEventListener("keydown", onKeyDown);
@@ -2621,10 +2680,10 @@ function AuthModal(props) {
2621
2680
  }
2622
2681
 
2623
2682
  // src/react/components/account/AccountModal.tsx
2624
- var import_react28 = require("react");
2683
+ var import_react30 = require("react");
2625
2684
 
2626
2685
  // src/react/components/account/AccountDashboard.tsx
2627
- var import_react27 = require("react");
2686
+ var import_react29 = require("react");
2628
2687
 
2629
2688
  // src/react/components/account/VerifyEmailBanner.tsx
2630
2689
  var import_react19 = require("react");
@@ -2899,16 +2958,16 @@ function ProfilePanel(props) {
2899
2958
  const { status } = useAuth();
2900
2959
  const resource = useCustomer();
2901
2960
  const { submitting, error, notice, run } = useAction();
2902
- const [form, setForm] = (0, import_react21.useState)({ firstName: "", lastName: "", phone: "", company: "", acceptsMarketing: false });
2961
+ const [form, setForm] = (0, import_react21.useState)({ firstName: "", lastName: "", phone: "", company: "" });
2962
+ const edited = (0, import_react21.useRef)(false);
2903
2963
  (0, import_react21.useEffect)(() => {
2904
2964
  const c = resource.data;
2905
- if (!c) return;
2965
+ if (!c || edited.current) return;
2906
2966
  setForm({
2907
2967
  firstName: c.firstName ?? "",
2908
2968
  lastName: c.lastName ?? "",
2909
2969
  phone: c.phone ?? "",
2910
- company: c.company ?? "",
2911
- acceptsMarketing: Boolean(c.acceptsMarketing)
2970
+ company: c.company ?? ""
2912
2971
  });
2913
2972
  }, [resource.data]);
2914
2973
  if (status === "unauthenticated") return null;
@@ -2926,12 +2985,12 @@ function ProfilePanel(props) {
2926
2985
  onSubmit: (e) => {
2927
2986
  e.preventDefault();
2928
2987
  void run(async () => {
2988
+ edited.current = false;
2929
2989
  await resource.update({
2930
2990
  firstName: form.firstName,
2931
2991
  lastName: form.lastName,
2932
2992
  phone: form.phone,
2933
- company: form.company || null,
2934
- acceptsMarketing: form.acceptsMarketing
2993
+ company: form.company || null
2935
2994
  });
2936
2995
  return t.profile.savedNotice;
2937
2996
  });
@@ -2955,7 +3014,10 @@ function ProfilePanel(props) {
2955
3014
  label: t.profile.firstName,
2956
3015
  value: form.firstName,
2957
3016
  autoComplete: "given-name",
2958
- onChange: (v) => setForm((f) => ({ ...f, firstName: v }))
3017
+ onChange: (v) => {
3018
+ edited.current = true;
3019
+ setForm((f) => ({ ...f, firstName: v }));
3020
+ }
2959
3021
  }
2960
3022
  ),
2961
3023
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
@@ -2964,7 +3026,10 @@ function ProfilePanel(props) {
2964
3026
  label: t.profile.lastName,
2965
3027
  value: form.lastName,
2966
3028
  autoComplete: "family-name",
2967
- onChange: (v) => setForm((f) => ({ ...f, lastName: v }))
3029
+ onChange: (v) => {
3030
+ edited.current = true;
3031
+ setForm((f) => ({ ...f, lastName: v }));
3032
+ }
2968
3033
  }
2969
3034
  ),
2970
3035
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
@@ -2974,7 +3039,10 @@ function ProfilePanel(props) {
2974
3039
  type: "tel",
2975
3040
  value: form.phone,
2976
3041
  autoComplete: "tel",
2977
- onChange: (v) => setForm((f) => ({ ...f, phone: v }))
3042
+ onChange: (v) => {
3043
+ edited.current = true;
3044
+ setForm((f) => ({ ...f, phone: v }));
3045
+ }
2978
3046
  }
2979
3047
  ),
2980
3048
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
@@ -2983,20 +3051,12 @@ function ProfilePanel(props) {
2983
3051
  label: t.profile.company,
2984
3052
  value: form.company,
2985
3053
  autoComplete: "organization",
2986
- onChange: (v) => setForm((f) => ({ ...f, company: v }))
3054
+ onChange: (v) => {
3055
+ edited.current = true;
3056
+ setForm((f) => ({ ...f, company: v }));
3057
+ }
2987
3058
  }
2988
3059
  ),
2989
- /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("label", { className: "throttle-row", children: [
2990
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
2991
- "input",
2992
- {
2993
- type: "checkbox",
2994
- checked: form.acceptsMarketing,
2995
- onChange: (e) => setForm((f) => ({ ...f, acceptsMarketing: e.target.checked }))
2996
- }
2997
- ),
2998
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("span", { children: t.profile.acceptsMarketing })
2999
- ] }),
3000
3060
  error ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Alert, { tone: "error", children: error }) : null,
3001
3061
  notice ? /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Alert, { tone: "success", children: notice }) : null,
3002
3062
  /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Button, { type: "submit", loading: submitting, elementKey: "profilePanel.submitButton", children: t.profile.saveButton })
@@ -3149,7 +3209,7 @@ function AddressesPanel(props) {
3149
3209
  })
3150
3210
  }
3151
3211
  ) : /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_jsx_runtime32.Fragment, { children: [
3152
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Button, { elementKey: "addressesPanel.addButton", variant: "secondary", onClick: () => setEditing("new"), children: t.addresses.addButton }),
3212
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Button, { elementKey: "addressesPanel.addButton", variant: "secondary", onClick: () => setEditing("new"), children: t.addresses.addButton }) }),
3153
3213
  /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
3154
3214
  PanelState,
3155
3215
  {
@@ -3256,7 +3316,102 @@ function AddressesPanel(props) {
3256
3316
  }
3257
3317
 
3258
3318
  // src/react/components/account/PaymentMethodsPanel.tsx
3319
+ var import_react25 = require("react");
3320
+
3321
+ // src/react/components/account/AddCardDialog.tsx
3322
+ var import_react24 = require("react");
3259
3323
  var import_jsx_runtime33 = require("react/jsx-runtime");
3324
+ function AddCardDialog(props) {
3325
+ const { account } = useAuth();
3326
+ const titleId = (0, import_react24.useId)();
3327
+ const { t } = useCopy(props.localization);
3328
+ const [src, setSrc] = (0, import_react24.useState)(null);
3329
+ const [error, setError] = (0, import_react24.useState)(null);
3330
+ const [busy, setBusy] = (0, import_react24.useState)(false);
3331
+ const onAdded = (0, import_react24.useRef)(props.onAdded);
3332
+ const onClose = (0, import_react24.useRef)(props.onClose);
3333
+ onAdded.current = props.onAdded;
3334
+ onClose.current = props.onClose;
3335
+ (0, import_react24.useEffect)(() => {
3336
+ if (!props.open) {
3337
+ setSrc(null);
3338
+ setError(null);
3339
+ return;
3340
+ }
3341
+ let live = true;
3342
+ setError(null);
3343
+ account.startCardSetup().then(
3344
+ (session) => {
3345
+ if (!live) return;
3346
+ let url = session.embedUrl;
3347
+ try {
3348
+ const u = new URL(session.embedUrl, window.location.origin);
3349
+ u.searchParams.set("parentOrigin", window.location.origin);
3350
+ url = u.toString();
3351
+ } catch {
3352
+ }
3353
+ setSrc(url);
3354
+ },
3355
+ (err) => {
3356
+ if (live) setError(messageForError(err));
3357
+ }
3358
+ );
3359
+ return () => {
3360
+ live = false;
3361
+ };
3362
+ }, [props.open, account]);
3363
+ (0, import_react24.useEffect)(() => {
3364
+ if (!src) return;
3365
+ const frameOrigin = (() => {
3366
+ try {
3367
+ return new URL(src).origin;
3368
+ } catch {
3369
+ return null;
3370
+ }
3371
+ })();
3372
+ if (!frameOrigin) return;
3373
+ async function onMessage(event) {
3374
+ if (event.origin !== frameOrigin) return;
3375
+ const data = event.data;
3376
+ if (!data || typeof data.type !== "string") return;
3377
+ if (data.type === "throttle.completed" && data.paymentId) {
3378
+ setBusy(true);
3379
+ try {
3380
+ await account.confirmCardSetup(data.paymentId);
3381
+ onAdded.current();
3382
+ onClose.current();
3383
+ } catch (err) {
3384
+ setError(messageForError(err));
3385
+ } finally {
3386
+ setBusy(false);
3387
+ }
3388
+ } else if (data.type === "throttle.error") {
3389
+ setError(data.message || t.common.somethingWentWrong);
3390
+ } else if (data.type === "throttle.cancelled") {
3391
+ onClose.current();
3392
+ }
3393
+ }
3394
+ window.addEventListener("message", onMessage);
3395
+ return () => window.removeEventListener("message", onMessage);
3396
+ }, [src, account, t]);
3397
+ if (!props.open) return null;
3398
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(Modal, { open: true, onClose: props.onClose, labelledBy: titleId, children: [
3399
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("h2", { id: titleId, children: t.paymentMethods.addTitle }),
3400
+ error ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Alert, { tone: "error", children: error }) : null,
3401
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "throttle-centre", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Spinner, {}) }) : src ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3402
+ "iframe",
3403
+ {
3404
+ className: "throttle-cardframe",
3405
+ src,
3406
+ title: t.paymentMethods.addTitle,
3407
+ sandbox: "allow-scripts allow-forms allow-same-origin"
3408
+ }
3409
+ ) : !error ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { className: "throttle-centre", children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Spinner, {}) }) : null
3410
+ ] });
3411
+ }
3412
+
3413
+ // src/react/components/account/PaymentMethodsPanel.tsx
3414
+ var import_jsx_runtime34 = require("react/jsx-runtime");
3260
3415
  function PaymentMethodsPanel(props) {
3261
3416
  const a = useAppearance(props.appearance);
3262
3417
  const scoped = useAppearanceProviderValue(props.appearance);
@@ -3264,6 +3419,7 @@ function PaymentMethodsPanel(props) {
3264
3419
  const { emailVerified } = useAuth();
3265
3420
  const resource = useSavedCards();
3266
3421
  const { submitting, error, run } = useAction();
3422
+ const [adding, setAdding] = (0, import_react25.useState)(false);
3267
3423
  const variant = props.variant ?? "rows";
3268
3424
  const rowsVariant = variant === "rows";
3269
3425
  const listBase = rowsVariant ? "throttle-rows" : "throttle-stack";
@@ -3271,9 +3427,21 @@ function PaymentMethodsPanel(props) {
3271
3427
  const actionVariant = (base) => rowsVariant ? base === "danger" ? "linkDanger" : "link" : base;
3272
3428
  const cardLabel = (card) => `${(card.cardBrand ?? card.methodType).toUpperCase()} \u2022\u2022\u2022\u2022 ${card.cardLastFour ?? "____"}`;
3273
3429
  const expiryLabel = (card) => card.cardExpMonth && card.cardExpYear ? `${String(card.cardExpMonth).padStart(2, "0")}/${card.cardExpYear}` : "";
3274
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { ...a.el("paymentMethodsPanel.root", "throttle-panel"), children: [
3275
- error ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Alert, { tone: "error", children: error }) : null,
3276
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3430
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { ...a.el("paymentMethodsPanel.root", "throttle-panel"), children: [
3431
+ error ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Alert, { tone: "error", children: error }) : null,
3432
+ emailVerified ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Button, { elementKey: "paymentMethodsPanel.addButton", variant: "secondary", onClick: () => setAdding(true), children: t.paymentMethods.addButton }) }) : null,
3433
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3434
+ AddCardDialog,
3435
+ {
3436
+ open: adding,
3437
+ onClose: () => setAdding(false),
3438
+ onAdded: () => {
3439
+ void resource.refetch();
3440
+ },
3441
+ localization: props.localization
3442
+ }
3443
+ ),
3444
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3277
3445
  PanelState,
3278
3446
  {
3279
3447
  resource,
@@ -3282,7 +3450,7 @@ function PaymentMethodsPanel(props) {
3282
3450
  isEmpty: (rows) => rows.length === 0,
3283
3451
  emptyTitle: t.paymentMethods.empty,
3284
3452
  emptyDescription: t.paymentMethods.emptyDescription,
3285
- children: (rows) => variant === "table" ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3453
+ children: (rows) => variant === "table" ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3286
3454
  DataTable,
3287
3455
  {
3288
3456
  tableKey: "paymentMethodsPanel.table",
@@ -3292,9 +3460,9 @@ function PaymentMethodsPanel(props) {
3292
3460
  columns: [
3293
3461
  { key: "card", label: t.paymentMethods.columnCard, render: (card) => cardLabel(card) },
3294
3462
  { key: "expires", label: t.paymentMethods.expires, render: (card) => expiryLabel(card) },
3295
- { key: "default", label: t.paymentMethods.defaultBadge, render: (card) => card.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Badge, { tone: "success", children: t.paymentMethods.defaultBadge }) : null },
3296
- { key: "actions", label: t.common.actions, render: (card) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "throttle-actions", children: [
3297
- !card.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3463
+ { key: "default", label: t.paymentMethods.defaultBadge, render: (card) => card.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Badge, { tone: "success", children: t.paymentMethods.defaultBadge }) : null },
3464
+ { key: "actions", label: t.common.actions, render: (card) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "throttle-actions", children: [
3465
+ !card.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3298
3466
  Button,
3299
3467
  {
3300
3468
  variant: "secondary",
@@ -3304,7 +3472,7 @@ function PaymentMethodsPanel(props) {
3304
3472
  children: t.paymentMethods.makeDefault
3305
3473
  }
3306
3474
  ) : null,
3307
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3475
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3308
3476
  Button,
3309
3477
  {
3310
3478
  variant: "danger",
@@ -3320,13 +3488,13 @@ function PaymentMethodsPanel(props) {
3320
3488
  ] }) }
3321
3489
  ]
3322
3490
  }
3323
- ) : /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("div", { ...a.el("paymentMethodsPanel.list", listBase), children: rows.map((card) => /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { ...a.el("paymentMethodsPanel.item", itemBase), children: [
3324
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { children: [
3325
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "throttle-row", children: [
3326
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("strong", { children: cardLabel(card) }),
3327
- card.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(Badge, { tone: "success", children: t.paymentMethods.defaultBadge }) : null
3491
+ ) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("div", { ...a.el("paymentMethodsPanel.list", listBase), children: rows.map((card) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { ...a.el("paymentMethodsPanel.item", itemBase), children: [
3492
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { children: [
3493
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "throttle-row", children: [
3494
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("strong", { children: cardLabel(card) }),
3495
+ card.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Badge, { tone: "success", children: t.paymentMethods.defaultBadge }) : null
3328
3496
  ] }),
3329
- card.cardExpMonth && card.cardExpYear ? /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("p", { className: "throttle-muted", children: [
3497
+ card.cardExpMonth && card.cardExpYear ? /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("p", { className: "throttle-muted", children: [
3330
3498
  t.paymentMethods.expires,
3331
3499
  " ",
3332
3500
  String(card.cardExpMonth).padStart(2, "0"),
@@ -3334,8 +3502,8 @@ function PaymentMethodsPanel(props) {
3334
3502
  card.cardExpYear
3335
3503
  ] }) : null
3336
3504
  ] }),
3337
- /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className: "throttle-actions", children: [
3338
- !card.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3505
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: "throttle-actions", children: [
3506
+ !card.isDefault ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3339
3507
  Button,
3340
3508
  {
3341
3509
  variant: actionVariant("secondary"),
@@ -3345,7 +3513,7 @@ function PaymentMethodsPanel(props) {
3345
3513
  children: t.paymentMethods.makeDefault
3346
3514
  }
3347
3515
  ) : null,
3348
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3516
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3349
3517
  Button,
3350
3518
  {
3351
3519
  variant: actionVariant("danger"),
@@ -3366,7 +3534,7 @@ function PaymentMethodsPanel(props) {
3366
3534
  }
3367
3535
 
3368
3536
  // src/react/components/account/OrdersPanel.tsx
3369
- var import_react24 = require("react");
3537
+ var import_react26 = require("react");
3370
3538
 
3371
3539
  // src/react/components/format.ts
3372
3540
  function formatMoney(minorUnits, currency, locale) {
@@ -3398,7 +3566,7 @@ function formatDate(value, locale) {
3398
3566
  }
3399
3567
 
3400
3568
  // src/react/components/account/OrderStatus.tsx
3401
- var import_jsx_runtime34 = require("react/jsx-runtime");
3569
+ var import_jsx_runtime35 = require("react/jsx-runtime");
3402
3570
  function copyKey(wire) {
3403
3571
  return wire.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
3404
3572
  }
@@ -3406,25 +3574,25 @@ var ATTENTION_PAYMENT_STATES = /* @__PURE__ */ new Set(["pending", "failed", "di
3406
3574
  var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["cancelled", "closed", "void", "expired", "voided"]);
3407
3575
  function StatusBadge(props) {
3408
3576
  const label = props.labels[copyKey(props.status)] ?? props.status.replace(/_/g, " ");
3409
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Badge, { tone: TERMINAL_STATUSES.has(props.status) ? "muted" : "neutral", children: label });
3577
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Badge, { tone: TERMINAL_STATUSES.has(props.status) ? "muted" : "neutral", children: label });
3410
3578
  }
3411
3579
  function OrderStatus(props) {
3412
3580
  const labels = props.t.orders.statusLabels;
3413
3581
  const payLabels = props.t.orders.paymentLabels;
3414
3582
  const lifecycle = labels[copyKey(props.status)] ?? props.status.replace(/_/g, " ");
3415
3583
  const money = props.paymentStatus ? payLabels[copyKey(props.paymentStatus)] : void 0;
3416
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_jsx_runtime34.Fragment, { children: [
3417
- /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Badge, { tone: TERMINAL_STATUSES.has(props.status) ? "muted" : "neutral", children: lifecycle }),
3418
- money ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Badge, { tone: ATTENTION_PAYMENT_STATES.has(props.paymentStatus) ? "warning" : "neutral", children: money }) : null
3584
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
3585
+ /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Badge, { tone: TERMINAL_STATUSES.has(props.status) ? "muted" : "neutral", children: lifecycle }),
3586
+ money ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Badge, { tone: ATTENTION_PAYMENT_STATES.has(props.paymentStatus) ? "warning" : "neutral", children: money }) : null
3419
3587
  ] });
3420
3588
  }
3421
3589
 
3422
3590
  // src/react/components/account/OrderDetail.tsx
3423
- var import_jsx_runtime35 = require("react/jsx-runtime");
3591
+ var import_jsx_runtime36 = require("react/jsx-runtime");
3424
3592
  function Line(props) {
3425
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "throttle-row", children: [
3426
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { className: "throttle-muted", children: props.label }),
3427
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { children: props.value })
3593
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "throttle-row", children: [
3594
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "throttle-muted", children: props.label }),
3595
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { children: props.value })
3428
3596
  ] });
3429
3597
  }
3430
3598
  function OrderDetail(props) {
@@ -3432,27 +3600,35 @@ function OrderDetail(props) {
3432
3600
  const scoped = useAppearanceProviderValue(props.appearance);
3433
3601
  const { t, locale } = useCopy(props.localization);
3434
3602
  const resource = useOrder(props.orderId);
3435
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { ...a.el("orderDetail.root", "throttle-panel"), children: [
3436
- props.onBack ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Button, { variant: "link", elementKey: "orderDetail.backButton", onClick: props.onBack, children: t.common.back }) : null,
3437
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
3603
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { ...a.el("orderDetail.root", "throttle-panel"), children: [
3604
+ props.onBack ? (
3605
+ // Wrapped on purpose. The panel is a column flex container, so a
3606
+ // direct child stretches to its full width however `width: auto`
3607
+ // the link variant is — the control rendered 748px wide with a
3608
+ // centred label. The wrapper takes the stretch; the button keeps
3609
+ // its own width. A CSS fix would need a compound selector, and
3610
+ // those outrank the merchant overrides in `appearance.elements`.
3611
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Button, { variant: "link", elementKey: "orderDetail.backButton", onClick: props.onBack, children: t.common.back }) })
3612
+ ) : null,
3613
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3438
3614
  PanelState,
3439
3615
  {
3440
3616
  resource,
3441
3617
  isEmpty: (o) => o === null,
3442
3618
  emptyTitle: t.orders.empty,
3443
3619
  skeletonRows: 5,
3444
- children: (order) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_jsx_runtime35.Fragment, { children: [
3445
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { className: "throttle-row", children: [
3446
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("h3", { children: order.orderNumber }),
3447
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(OrderStatus, { status: order.status, paymentStatus: order.paymentStatus, t })
3620
+ children: (order) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
3621
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "throttle-row", children: [
3622
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("h3", { children: order.orderNumber }),
3623
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(OrderStatus, { status: order.status, paymentStatus: order.paymentStatus, t })
3448
3624
  ] }),
3449
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "throttle-muted", children: formatDate(order.createdAt, locale) }),
3450
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("div", { ...a.el("orderDetail.lineItems", "throttle-stack"), children: order.lineItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { ...a.el("orderDetail.lineItem", "throttle-lineitem"), children: [
3451
- item.imageUrl ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("img", { className: "throttle-lineitem__image", src: item.imageUrl, alt: "" }) : null,
3452
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { style: { flex: 1 }, children: [
3453
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("strong", { children: item.name }),
3454
- item.description ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("p", { className: "throttle-muted", children: item.description }) : null,
3455
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("p", { className: "throttle-muted", children: [
3625
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "throttle-muted", children: formatDate(order.createdAt, locale) }),
3626
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { ...a.el("orderDetail.lineItems", "throttle-stack"), children: order.lineItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { ...a.el("orderDetail.lineItem", "throttle-lineitem"), children: [
3627
+ item.imageUrl ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("img", { className: "throttle-lineitem__image", src: item.imageUrl, alt: "" }) : null,
3628
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { style: { flex: 1 }, children: [
3629
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("strong", { children: item.name }),
3630
+ item.description ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "throttle-muted", children: item.description }) : null,
3631
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("p", { className: "throttle-muted", children: [
3456
3632
  t.orders.quantity,
3457
3633
  " ",
3458
3634
  item.quantity,
@@ -3460,16 +3636,16 @@ function OrderDetail(props) {
3460
3636
  formatMoney(item.unitPrice, order.currency, locale)
3461
3637
  ] })
3462
3638
  ] }),
3463
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)("span", { children: formatMoney(item.total, order.currency, locale) })
3639
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { children: formatMoney(item.total, order.currency, locale) })
3464
3640
  ] }, item.id)) }),
3465
- /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)("div", { ...a.el("orderDetail.totals", "throttle-totals"), children: [
3466
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Line, { label: t.orders.subtotal, value: formatMoney(order.subtotal, order.currency, locale) }),
3467
- order.discountTotal ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Line, { label: t.orders.discount, value: formatMoney(-order.discountTotal, order.currency, locale) }) : null,
3468
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Line, { label: t.orders.shipping, value: formatMoney(order.shippingTotal, order.currency, locale) }),
3469
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Line, { label: t.orders.tax, value: formatMoney(order.taxTotal, order.currency, locale) }),
3470
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Line, { label: t.orders.total, value: formatMoney(order.total, order.currency, locale) })
3641
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { ...a.el("orderDetail.totals", "throttle-totals"), children: [
3642
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Line, { label: t.orders.subtotal, value: formatMoney(order.subtotal, order.currency, locale) }),
3643
+ order.discountTotal ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Line, { label: t.orders.discount, value: formatMoney(-order.discountTotal, order.currency, locale) }) : null,
3644
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Line, { label: t.orders.shipping, value: formatMoney(order.shippingTotal, order.currency, locale) }),
3645
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Line, { label: t.orders.tax, value: formatMoney(order.taxTotal, order.currency, locale) }),
3646
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Line, { label: t.orders.total, value: formatMoney(order.total, order.currency, locale) })
3471
3647
  ] }),
3472
- order.subscriptionId && props.onViewSubscription ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Button, { variant: "secondary", onClick: () => props.onViewSubscription(order.subscriptionId), children: t.orders.viewSubscription }) : null
3648
+ order.subscriptionId && props.onViewSubscription ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Button, { variant: "secondary", onClick: () => props.onViewSubscription(order.subscriptionId), children: t.orders.viewSubscription }) : null
3473
3649
  ] })
3474
3650
  }
3475
3651
  )
@@ -3477,20 +3653,20 @@ function OrderDetail(props) {
3477
3653
  }
3478
3654
 
3479
3655
  // src/react/components/account/OrdersPanel.tsx
3480
- var import_jsx_runtime36 = require("react/jsx-runtime");
3656
+ var import_jsx_runtime37 = require("react/jsx-runtime");
3481
3657
  function OrdersPanel(props) {
3482
3658
  const a = useAppearance(props.appearance);
3483
3659
  const scoped = useAppearanceProviderValue(props.appearance);
3484
3660
  const { t, locale } = useCopy(props.localization);
3485
3661
  const { emailVerified } = useAuth();
3486
3662
  const resource = useOrders();
3487
- const [openId, setOpenId] = (0, import_react24.useState)(null);
3663
+ const [openId, setOpenId] = (0, import_react26.useState)(null);
3488
3664
  const variant = props.variant ?? "table";
3489
3665
  const rowsVariant = variant === "rows";
3490
3666
  const listBase = rowsVariant ? "throttle-rows" : "throttle-stack";
3491
3667
  const itemBase = rowsVariant ? "throttle-rowitem" : "throttle-listitem";
3492
3668
  if (openId) {
3493
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3669
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3494
3670
  OrderDetail,
3495
3671
  {
3496
3672
  orderId: openId,
@@ -3501,7 +3677,7 @@ function OrdersPanel(props) {
3501
3677
  }
3502
3678
  );
3503
3679
  }
3504
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { ...a.el("ordersPanel.root", "throttle-panel"), children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3680
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { ...a.el("ordersPanel.root", "throttle-panel"), children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3505
3681
  PanelState,
3506
3682
  {
3507
3683
  resource,
@@ -3510,7 +3686,7 @@ function OrdersPanel(props) {
3510
3686
  isEmpty: (rows) => rows.length === 0,
3511
3687
  emptyTitle: t.orders.empty,
3512
3688
  emptyDescription: t.orders.emptyDescription,
3513
- children: (rows) => variant === "table" ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3689
+ children: (rows) => variant === "table" ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3514
3690
  DataTable,
3515
3691
  {
3516
3692
  tableKey: "ordersPanel.table",
@@ -3524,25 +3700,25 @@ function OrdersPanel(props) {
3524
3700
  {
3525
3701
  key: "status",
3526
3702
  label: t.orders.status,
3527
- render: (o) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(OrderStatus, { status: o.status, paymentStatus: o.paymentStatus, t })
3703
+ render: (o) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(OrderStatus, { status: o.status, paymentStatus: o.paymentStatus, t })
3528
3704
  },
3529
3705
  {
3530
3706
  key: "total",
3531
3707
  label: t.orders.total,
3532
- render: (o) => /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("span", { className: "throttle-table__money", children: formatMoney(o.total, o.currency, locale) })
3708
+ render: (o) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "throttle-table__money", children: formatMoney(o.total, o.currency, locale) })
3533
3709
  }
3534
3710
  ]
3535
3711
  }
3536
- ) : /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { ...a.el("ordersPanel.list", listBase), children: rows.map((o) => /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { ...a.el("ordersPanel.item", itemBase), children: [
3537
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { children: [
3538
- /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)("div", { className: "throttle-row", children: [
3539
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("strong", { children: o.orderNumber }),
3540
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(OrderStatus, { status: o.status, paymentStatus: o.paymentStatus, t })
3712
+ ) : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { ...a.el("ordersPanel.list", listBase), children: rows.map((o) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { ...a.el("ordersPanel.item", itemBase), children: [
3713
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { children: [
3714
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "throttle-row", children: [
3715
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("strong", { children: o.orderNumber }),
3716
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(OrderStatus, { status: o.status, paymentStatus: o.paymentStatus, t })
3541
3717
  ] }),
3542
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "throttle-muted", children: formatDate(o.createdAt, locale) }),
3543
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("p", { className: "throttle-muted", children: formatMoney(o.total, o.currency, locale) })
3718
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "throttle-muted", children: formatDate(o.createdAt, locale) }),
3719
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("p", { className: "throttle-muted", children: formatMoney(o.total, o.currency, locale) })
3544
3720
  ] }),
3545
- /* @__PURE__ */ (0, import_jsx_runtime36.jsx)("div", { className: "throttle-actions", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
3721
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { className: "throttle-actions", children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3546
3722
  Button,
3547
3723
  {
3548
3724
  variant: rowsVariant ? "link" : "secondary",
@@ -3557,14 +3733,14 @@ function OrdersPanel(props) {
3557
3733
  }
3558
3734
 
3559
3735
  // src/react/components/account/InvoicesPanel.tsx
3560
- var import_react25 = require("react");
3736
+ var import_react27 = require("react");
3561
3737
 
3562
3738
  // src/react/components/account/InvoiceDetail.tsx
3563
- var import_jsx_runtime37 = require("react/jsx-runtime");
3739
+ var import_jsx_runtime38 = require("react/jsx-runtime");
3564
3740
  function Line2(props) {
3565
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "throttle-row", children: [
3566
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { className: "throttle-muted", children: props.label }),
3567
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("span", { children: props.value })
3741
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "throttle-row", children: [
3742
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "throttle-muted", children: props.label }),
3743
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { children: props.value })
3568
3744
  ] });
3569
3745
  }
3570
3746
  function InvoiceDetail(props) {
@@ -3574,25 +3750,33 @@ function InvoiceDetail(props) {
3574
3750
  const { account } = useAuth();
3575
3751
  const resource = useInvoice(props.invoiceId);
3576
3752
  const { submitting, error, run } = useAction();
3577
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { ...a.el("invoiceDetail.root", "throttle-panel"), children: [
3578
- props.onBack ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Button, { variant: "link", elementKey: "invoiceDetail.backButton", onClick: props.onBack, children: t.common.back }) : null,
3579
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PanelState, { resource, isEmpty: (i) => i === null, emptyTitle: t.invoices.empty, skeletonRows: 4, children: (invoice) => /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_jsx_runtime37.Fragment, { children: [
3580
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { className: "throttle-row", children: [
3581
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("h3", { children: invoice.number }),
3582
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(StatusBadge, { status: invoice.status, labels: t.invoices.statusLabels })
3753
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { ...a.el("invoiceDetail.root", "throttle-panel"), children: [
3754
+ props.onBack ? (
3755
+ // Wrapped on purpose. The panel is a column flex container, so a
3756
+ // direct child stretches to its full width however `width: auto`
3757
+ // the link variant is — the control rendered 748px wide with a
3758
+ // centred label. The wrapper takes the stretch; the button keeps
3759
+ // its own width. A CSS fix would need a compound selector, and
3760
+ // those outrank the merchant overrides in `appearance.elements`.
3761
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Button, { variant: "link", elementKey: "invoiceDetail.backButton", onClick: props.onBack, children: t.common.back }) })
3762
+ ) : null,
3763
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PanelState, { resource, isEmpty: (i) => i === null, emptyTitle: t.invoices.empty, skeletonRows: 4, children: (invoice) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_jsx_runtime38.Fragment, { children: [
3764
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "throttle-row", children: [
3765
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("h3", { children: invoice.number }),
3766
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(StatusBadge, { status: invoice.status, labels: t.invoices.statusLabels })
3583
3767
  ] }),
3584
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)("div", { ...a.el("invoiceDetail.totals", "throttle-totals"), children: [
3585
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Line2, { label: t.invoices.issued, value: formatDate(invoice.issuedAt, locale) }),
3586
- invoice.dueAt ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Line2, { label: t.invoices.due, value: formatDate(invoice.dueAt, locale) }) : null,
3587
- invoice.periodStart && invoice.periodEnd ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3768
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { ...a.el("invoiceDetail.totals", "throttle-totals"), children: [
3769
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Line2, { label: t.invoices.issued, value: formatDate(invoice.issuedAt, locale) }),
3770
+ invoice.dueAt ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Line2, { label: t.invoices.due, value: formatDate(invoice.dueAt, locale) }) : null,
3771
+ invoice.periodStart && invoice.periodEnd ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3588
3772
  Line2,
3589
3773
  {
3590
3774
  label: t.invoices.period,
3591
3775
  value: `${formatDate(invoice.periodStart, locale)} \u2013 ${formatDate(invoice.periodEnd, locale)}`
3592
3776
  }
3593
3777
  ) : null,
3594
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Line2, { label: t.invoices.total, value: formatMoney(invoice.total, invoice.currency, locale) }),
3595
- invoice.amountRefunded ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3778
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Line2, { label: t.invoices.total, value: formatMoney(invoice.total, invoice.currency, locale) }),
3779
+ invoice.amountRefunded ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3596
3780
  Line2,
3597
3781
  {
3598
3782
  label: t.invoices.refunded,
@@ -3600,8 +3784,8 @@ function InvoiceDetail(props) {
3600
3784
  }
3601
3785
  ) : null
3602
3786
  ] }),
3603
- error ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Alert, { tone: "error", children: error }) : null,
3604
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
3787
+ error ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(Alert, { tone: "error", children: error }) : null,
3788
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3605
3789
  Button,
3606
3790
  {
3607
3791
  variant: "secondary",
@@ -3620,20 +3804,20 @@ function InvoiceDetail(props) {
3620
3804
  }
3621
3805
 
3622
3806
  // src/react/components/account/InvoicesPanel.tsx
3623
- var import_jsx_runtime38 = require("react/jsx-runtime");
3807
+ var import_jsx_runtime39 = require("react/jsx-runtime");
3624
3808
  function InvoicesPanel(props) {
3625
3809
  const a = useAppearance(props.appearance);
3626
3810
  const scoped = useAppearanceProviderValue(props.appearance);
3627
3811
  const { t, locale } = useCopy(props.localization);
3628
3812
  const { emailVerified } = useAuth();
3629
3813
  const resource = useInvoices();
3630
- const [openId, setOpenId] = (0, import_react25.useState)(null);
3814
+ const [openId, setOpenId] = (0, import_react27.useState)(null);
3631
3815
  const variant = props.variant ?? "table";
3632
3816
  const rowsVariant = variant === "rows";
3633
3817
  const listBase = rowsVariant ? "throttle-rows" : "throttle-stack";
3634
3818
  const itemBase = rowsVariant ? "throttle-rowitem" : "throttle-listitem";
3635
3819
  if (openId) {
3636
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3820
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3637
3821
  InvoiceDetail,
3638
3822
  {
3639
3823
  invoiceId: openId,
@@ -3643,7 +3827,7 @@ function InvoicesPanel(props) {
3643
3827
  }
3644
3828
  );
3645
3829
  }
3646
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { ...a.el("invoicesPanel.root", "throttle-panel"), children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3830
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { ...a.el("invoicesPanel.root", "throttle-panel"), children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3647
3831
  PanelState,
3648
3832
  {
3649
3833
  resource,
@@ -3652,7 +3836,7 @@ function InvoicesPanel(props) {
3652
3836
  isEmpty: (rows) => rows.length === 0,
3653
3837
  emptyTitle: t.invoices.empty,
3654
3838
  emptyDescription: t.invoices.emptyDescription,
3655
- children: (rows) => variant === "table" ? /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3839
+ children: (rows) => variant === "table" ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3656
3840
  DataTable,
3657
3841
  {
3658
3842
  tableKey: "invoicesPanel.table",
@@ -3663,24 +3847,24 @@ function InvoicesPanel(props) {
3663
3847
  columns: [
3664
3848
  { key: "number", label: t.invoices.number },
3665
3849
  { key: "issuedAt", label: t.invoices.issued, render: (i) => formatDate(i.issuedAt, locale) },
3666
- { key: "status", label: t.invoices.status, render: (i) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(StatusBadge, { status: i.status, labels: t.invoices.statusLabels }) },
3850
+ { key: "status", label: t.invoices.status, render: (i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(StatusBadge, { status: i.status, labels: t.invoices.statusLabels }) },
3667
3851
  {
3668
3852
  key: "total",
3669
3853
  label: t.invoices.total,
3670
- render: (i) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("span", { className: "throttle-table__money", children: formatMoney(i.total, i.currency, locale) })
3854
+ render: (i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "throttle-table__money", children: formatMoney(i.total, i.currency, locale) })
3671
3855
  }
3672
3856
  ]
3673
3857
  }
3674
- ) : /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { ...a.el("invoicesPanel.list", listBase), children: rows.map((i) => /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { ...a.el("invoicesPanel.item", itemBase), children: [
3675
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { children: [
3676
- /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)("div", { className: "throttle-row", children: [
3677
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("strong", { children: i.number }),
3678
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(StatusBadge, { status: i.status, labels: t.invoices.statusLabels })
3858
+ ) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { ...a.el("invoicesPanel.list", listBase), children: rows.map((i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { ...a.el("invoicesPanel.item", itemBase), children: [
3859
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { children: [
3860
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "throttle-row", children: [
3861
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("strong", { children: i.number }),
3862
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(StatusBadge, { status: i.status, labels: t.invoices.statusLabels })
3679
3863
  ] }),
3680
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "throttle-muted", children: formatDate(i.issuedAt, locale) }),
3681
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("p", { className: "throttle-muted", children: formatMoney(i.total, i.currency, locale) })
3864
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "throttle-muted", children: formatDate(i.issuedAt, locale) }),
3865
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("p", { className: "throttle-muted", children: formatMoney(i.total, i.currency, locale) })
3682
3866
  ] }),
3683
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { className: "throttle-actions", children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
3867
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { className: "throttle-actions", children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3684
3868
  Button,
3685
3869
  {
3686
3870
  variant: rowsVariant ? "link" : "secondary",
@@ -3695,7 +3879,7 @@ function InvoicesPanel(props) {
3695
3879
  }
3696
3880
 
3697
3881
  // src/react/components/account/SubscriptionsPanel.tsx
3698
- var import_jsx_runtime39 = require("react/jsx-runtime");
3882
+ var import_jsx_runtime40 = require("react/jsx-runtime");
3699
3883
  var CAN_PAUSE = /* @__PURE__ */ new Set(["active", "trialing"]);
3700
3884
  var CAN_RESUME = /* @__PURE__ */ new Set(["paused"]);
3701
3885
  var CAN_CANCEL = /* @__PURE__ */ new Set(["active", "trialing", "paused", "past_due", "unpaid"]);
@@ -3717,8 +3901,8 @@ function SubscriptionsPanel(props) {
3717
3901
  };
3718
3902
  const priceLabel = (sub) => `${formatMoney(sub.amount, sub.currency, locale)} / ${sub.interval}${sub.quantity > 1 ? ` \xD7 ${sub.quantity}` : ""}`;
3719
3903
  const renewsLabel = (sub) => formatDate(sub.status === "cancelled" ? sub.cancelledAt ?? sub.currentPeriodEnd : sub.currentPeriodEnd, locale);
3720
- const lifecycleActions = (sub, variantFor) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "throttle-actions", children: [
3721
- CAN_PAUSE.has(sub.status) ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3904
+ const lifecycleActions = (sub, variantFor) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "throttle-actions", children: [
3905
+ CAN_PAUSE.has(sub.status) ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3722
3906
  Button,
3723
3907
  {
3724
3908
  variant: variantFor("secondary"),
@@ -3728,7 +3912,7 @@ function SubscriptionsPanel(props) {
3728
3912
  children: t.subscriptions.pauseButton
3729
3913
  }
3730
3914
  ) : null,
3731
- CAN_RESUME.has(sub.status) ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3915
+ CAN_RESUME.has(sub.status) ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3732
3916
  Button,
3733
3917
  {
3734
3918
  variant: variantFor("secondary"),
@@ -3738,7 +3922,7 @@ function SubscriptionsPanel(props) {
3738
3922
  children: t.subscriptions.resumeButton
3739
3923
  }
3740
3924
  ) : null,
3741
- CAN_CANCEL.has(sub.status) && !sub.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3925
+ CAN_CANCEL.has(sub.status) && !sub.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3742
3926
  Button,
3743
3927
  {
3744
3928
  variant: variantFor("secondary"),
@@ -3748,7 +3932,7 @@ function SubscriptionsPanel(props) {
3748
3932
  children: t.subscriptions.cancelAtPeriodEnd
3749
3933
  }
3750
3934
  ) : null,
3751
- CAN_CANCEL.has(sub.status) ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3935
+ CAN_CANCEL.has(sub.status) ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3752
3936
  Button,
3753
3937
  {
3754
3938
  variant: variantFor("danger"),
@@ -3759,9 +3943,9 @@ function SubscriptionsPanel(props) {
3759
3943
  }
3760
3944
  ) : null
3761
3945
  ] });
3762
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { ...a.el("subscriptionsPanel.root", "throttle-panel"), children: [
3763
- error ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Alert, { tone: "error", children: error }) : null,
3764
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3946
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { ...a.el("subscriptionsPanel.root", "throttle-panel"), children: [
3947
+ error ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Alert, { tone: "error", children: error }) : null,
3948
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3765
3949
  PanelState,
3766
3950
  {
3767
3951
  resource,
@@ -3770,7 +3954,7 @@ function SubscriptionsPanel(props) {
3770
3954
  isEmpty: (rows) => rows.length === 0,
3771
3955
  emptyTitle: t.subscriptions.empty,
3772
3956
  emptyDescription: t.subscriptions.emptyDescription,
3773
- children: (rows) => variant === "table" ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
3957
+ children: (rows) => variant === "table" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
3774
3958
  DataTable,
3775
3959
  {
3776
3960
  tableKey: "subscriptionsPanel.table",
@@ -3779,42 +3963,42 @@ function SubscriptionsPanel(props) {
3779
3963
  rows,
3780
3964
  columns: [
3781
3965
  { key: "plan", label: t.subscriptions.columnPlan, render: (sub) => sub.planName ?? sub.planReference },
3782
- { key: "price", label: t.subscriptions.columnPrice, render: (sub) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "throttle-table__money", children: priceLabel(sub) }) },
3966
+ { key: "price", label: t.subscriptions.columnPrice, render: (sub) => /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { className: "throttle-table__money", children: priceLabel(sub) }) },
3783
3967
  { key: "renews", label: t.subscriptions.columnRenews, render: (sub) => renewsLabel(sub) },
3784
- { key: "status", label: t.subscriptions.columnStatus, render: (sub) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "throttle-row", children: [
3785
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(StatusBadge, { status: sub.status, labels: t.subscriptions.statusLabels }),
3786
- sub.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Badge, { tone: "warning", children: t.subscriptions.cancelScheduled }) : null
3968
+ { key: "status", label: t.subscriptions.columnStatus, render: (sub) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "throttle-row", children: [
3969
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(StatusBadge, { status: sub.status, labels: t.subscriptions.statusLabels }),
3970
+ sub.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Badge, { tone: "warning", children: t.subscriptions.cancelScheduled }) : null
3787
3971
  ] }) },
3788
3972
  { key: "actions", label: t.common.actions, render: (sub) => lifecycleActions(sub, (base) => base) }
3789
3973
  ]
3790
3974
  }
3791
- ) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { ...a.el("subscriptionsPanel.list", listBase), children: rows.map((sub) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { ...a.el("subscriptionsPanel.item", itemBase), children: [
3792
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { children: [
3793
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "throttle-row", children: [
3794
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("strong", { children: sub.planName ?? sub.planReference }),
3795
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(StatusBadge, { status: sub.status, labels: t.subscriptions.statusLabels })
3975
+ ) : /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { ...a.el("subscriptionsPanel.list", listBase), children: rows.map((sub) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { ...a.el("subscriptionsPanel.item", itemBase), children: [
3976
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { children: [
3977
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "throttle-row", children: [
3978
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("strong", { children: sub.planName ?? sub.planReference }),
3979
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(StatusBadge, { status: sub.status, labels: t.subscriptions.statusLabels })
3796
3980
  ] }),
3797
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "throttle-muted", children: [
3981
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("p", { className: "throttle-muted", children: [
3798
3982
  formatMoney(sub.amount, sub.currency, locale),
3799
3983
  " / ",
3800
3984
  sub.interval,
3801
3985
  sub.quantity > 1 ? ` \xD7 ${sub.quantity}` : ""
3802
3986
  ] }),
3803
- sub.status === "cancelled" ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "throttle-muted", children: [
3987
+ sub.status === "cancelled" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("p", { className: "throttle-muted", children: [
3804
3988
  t.subscriptions.cancelledOn,
3805
3989
  " ",
3806
3990
  formatDate(sub.cancelledAt ?? sub.currentPeriodEnd, locale)
3807
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "throttle-muted", children: [
3991
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("p", { className: "throttle-muted", children: [
3808
3992
  sub.cancelAtPeriodEnd ? t.subscriptions.endsOn : t.subscriptions.renewsOn,
3809
3993
  " ",
3810
3994
  formatDate(sub.currentPeriodEnd, locale)
3811
3995
  ] }),
3812
- sub.trialEnd ? /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("p", { className: "throttle-muted", children: [
3996
+ sub.trialEnd ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("p", { className: "throttle-muted", children: [
3813
3997
  t.subscriptions.trialEnds,
3814
3998
  " ",
3815
3999
  formatDate(sub.trialEnd, locale)
3816
4000
  ] }) : null,
3817
- sub.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Badge, { tone: "warning", children: t.subscriptions.cancelScheduled }) : null
4001
+ sub.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Badge, { tone: "warning", children: t.subscriptions.cancelScheduled }) : null
3818
4002
  ] }),
3819
4003
  lifecycleActions(sub, actionVariant)
3820
4004
  ] }, sub.id)) })
@@ -3824,8 +4008,40 @@ function SubscriptionsPanel(props) {
3824
4008
  }
3825
4009
 
3826
4010
  // src/react/components/account/SecurityPanel.tsx
3827
- var import_react26 = require("react");
3828
- var import_jsx_runtime40 = require("react/jsx-runtime");
4011
+ var import_react28 = require("react");
4012
+
4013
+ // src/react/components/account/device.ts
4014
+ var BROWSERS = [
4015
+ [/\bEdg(?:e|A|iOS)?\//, "Edge"],
4016
+ [/\bOPR\/|\bOpera\b/, "Opera"],
4017
+ // No leading \b: real agents ship prefixed builds (HeadlessChrome), and a
4018
+ // word boundary there sends them to the Safari rule instead.
4019
+ [/Chrome\/|CriOS\//, "Chrome"],
4020
+ [/\bFirefox\/|\bFxiOS\//, "Firefox"],
4021
+ [/\bSafari\//, "Safari"]
4022
+ ];
4023
+ var PLATFORMS = [
4024
+ [/\biPhone\b|\biPad\b|\biPod\b/, "iOS"],
4025
+ [/\bAndroid\b/, "Android"],
4026
+ [/\bMac OS X\b|\bMacintosh\b/, "macOS"],
4027
+ [/\bWindows\b/, "Windows"],
4028
+ [/\bLinux\b|\bX11\b/, "Linux"]
4029
+ ];
4030
+ function first(ua, table) {
4031
+ for (const [pattern, label] of table) if (pattern.test(ua)) return label;
4032
+ return null;
4033
+ }
4034
+ function describeDevice(userAgent) {
4035
+ const ua = (userAgent ?? "").trim();
4036
+ if (!ua) return "";
4037
+ const browser = first(ua, BROWSERS);
4038
+ if (!browser) return ua;
4039
+ const platform = first(ua, PLATFORMS);
4040
+ return platform ? `${browser} on ${platform}` : browser;
4041
+ }
4042
+
4043
+ // src/react/components/account/SecurityPanel.tsx
4044
+ var import_jsx_runtime41 = require("react/jsx-runtime");
3829
4045
  function SecurityPanel(props) {
3830
4046
  const a = useAppearance(props.appearance);
3831
4047
  const scoped = useAppearanceProviderValue(props.appearance);
@@ -3835,16 +4051,16 @@ function SecurityPanel(props) {
3835
4051
  const rowsVariant = variant === "rows";
3836
4052
  const itemBase = rowsVariant ? "throttle-rowitem" : "throttle-listitem";
3837
4053
  const revokeVariant = rowsVariant ? "linkDanger" : "danger";
3838
- const [password, setPassword] = (0, import_react26.useState)("");
4054
+ const [password, setPassword] = (0, import_react28.useState)("");
3839
4055
  const passwordAction = useAction();
3840
4056
  const sessionAction = useAction();
3841
- const [sessions, setSessions] = (0, import_react26.useState)(null);
3842
- const [listError, setListError] = (0, import_react26.useState)(null);
3843
- const errorMessageRef = (0, import_react26.useRef)(errorMessage);
3844
- (0, import_react26.useEffect)(() => {
4057
+ const [sessions, setSessions] = (0, import_react28.useState)(null);
4058
+ const [listError, setListError] = (0, import_react28.useState)(null);
4059
+ const errorMessageRef = (0, import_react28.useRef)(errorMessage);
4060
+ (0, import_react28.useEffect)(() => {
3845
4061
  errorMessageRef.current = errorMessage;
3846
4062
  });
3847
- const load = (0, import_react26.useCallback)(async () => {
4063
+ const load = (0, import_react28.useCallback)(async () => {
3848
4064
  try {
3849
4065
  setSessions(await auth.listSessions());
3850
4066
  setListError(null);
@@ -3852,12 +4068,12 @@ function SecurityPanel(props) {
3852
4068
  setListError(errorMessageRef.current(err));
3853
4069
  }
3854
4070
  }, [auth]);
3855
- (0, import_react26.useEffect)(() => {
4071
+ (0, import_react28.useEffect)(() => {
3856
4072
  void load();
3857
4073
  }, [load]);
3858
4074
  const others = (sessions ?? []).filter((s) => !s.current);
3859
- return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { ...a.el("securityPanel.root", "throttle-panel"), children: [
3860
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
4075
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ...a.el("securityPanel.root", "throttle-panel"), children: [
4076
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
3861
4077
  "form",
3862
4078
  {
3863
4079
  ...a.el("securityPanel.passwordForm", "throttle-stack"),
@@ -3870,8 +4086,8 @@ function SecurityPanel(props) {
3870
4086
  });
3871
4087
  },
3872
4088
  children: [
3873
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("h3", { children: t.security.passwordTitle }),
3874
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
4089
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("h3", { children: t.security.passwordTitle }),
4090
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
3875
4091
  Field,
3876
4092
  {
3877
4093
  label: t.security.newPassword,
@@ -3882,21 +4098,21 @@ function SecurityPanel(props) {
3882
4098
  onChange: setPassword
3883
4099
  }
3884
4100
  ),
3885
- passwordAction.error ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Alert, { tone: "error", children: passwordAction.error }) : null,
3886
- passwordAction.notice ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Alert, { tone: "success", children: passwordAction.notice }) : null,
3887
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Button, { type: "submit", loading: passwordAction.submitting, elementKey: "securityPanel.passwordButton", children: t.security.changeButton })
4101
+ passwordAction.error ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Alert, { tone: "error", children: passwordAction.error }) : null,
4102
+ passwordAction.notice ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Alert, { tone: "success", children: passwordAction.notice }) : null,
4103
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Button, { type: "submit", loading: passwordAction.submitting, elementKey: "securityPanel.passwordButton", children: t.security.changeButton })
3888
4104
  ]
3889
4105
  }
3890
4106
  ),
3891
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { ...a.el("securityPanel.sessionList", "throttle-stack"), children: [
3892
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("h3", { children: t.security.sessionsTitle }),
3893
- listError ? /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_jsx_runtime40.Fragment, { children: [
3894
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Alert, { tone: "error", children: listError }),
3895
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Button, { variant: "secondary", onClick: () => void load(), children: t.common.retry })
4107
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ...a.el("securityPanel.sessionList", "throttle-stack"), children: [
4108
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("h3", { children: t.security.sessionsTitle }),
4109
+ listError ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
4110
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Alert, { tone: "error", children: listError }),
4111
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Button, { variant: "secondary", onClick: () => void load(), children: t.common.retry })
3896
4112
  ] }) : null,
3897
- sessionAction.error ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Alert, { tone: "error", children: sessionAction.error }) : null,
3898
- sessions === null && !listError ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Skeleton, { count: 2 }) : null,
3899
- sessions !== null && !listError && variant === "table" ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
4113
+ sessionAction.error ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Alert, { tone: "error", children: sessionAction.error }) : null,
4114
+ sessions === null && !listError ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Skeleton, { count: 2 }) : null,
4115
+ sessions !== null && !listError && variant === "table" ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
3900
4116
  DataTable,
3901
4117
  {
3902
4118
  tableKey: "securityPanel.table",
@@ -3904,12 +4120,12 @@ function SecurityPanel(props) {
3904
4120
  rowKey: (session) => session.id,
3905
4121
  rows: sessions,
3906
4122
  columns: [
3907
- { key: "device", label: t.security.columnDevice, render: (session) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "throttle-row", children: [
3908
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("span", { children: session.userAgent || session.ipPrefix || session.id }),
3909
- session.current ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Badge, { tone: "success", children: t.security.thisDevice }) : null
4123
+ { key: "device", label: t.security.columnDevice, render: (session) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "throttle-row", children: [
4124
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: describeDevice(session.userAgent) || session.ipPrefix || session.id }),
4125
+ session.current ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Badge, { tone: "success", children: t.security.thisDevice }) : null
3910
4126
  ] }) },
3911
4127
  { key: "lastActive", label: t.security.lastActive, render: (session) => formatDate(session.lastUsedAt, locale) },
3912
- { key: "actions", label: t.common.actions, render: (session) => !session.current ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
4128
+ { key: "actions", label: t.common.actions, render: (session) => !session.current ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
3913
4129
  Button,
3914
4130
  {
3915
4131
  variant: "danger",
@@ -3924,19 +4140,19 @@ function SecurityPanel(props) {
3924
4140
  ) : null }
3925
4141
  ]
3926
4142
  }
3927
- ) : (sessions ?? []).map((session) => /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { ...a.el("securityPanel.sessionItem", itemBase), children: [
3928
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { children: [
3929
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("div", { className: "throttle-row", children: [
3930
- /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("strong", { children: session.userAgent || session.ipPrefix || session.id }),
3931
- session.current ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Badge, { tone: "success", children: t.security.thisDevice }) : null
4143
+ ) : (sessions ?? []).map((session) => /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ...a.el("securityPanel.sessionItem", itemBase), children: [
4144
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { children: [
4145
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "throttle-row", children: [
4146
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("strong", { children: describeDevice(session.userAgent) || session.ipPrefix || session.id }),
4147
+ session.current ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Badge, { tone: "success", children: t.security.thisDevice }) : null
3932
4148
  ] }),
3933
- /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)("p", { className: "throttle-muted", children: [
4149
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("p", { className: "throttle-muted", children: [
3934
4150
  t.security.lastActive,
3935
4151
  " ",
3936
4152
  formatDate(session.lastUsedAt, locale)
3937
4153
  ] })
3938
4154
  ] }),
3939
- !session.current ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
4155
+ !session.current ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
3940
4156
  Button,
3941
4157
  {
3942
4158
  variant: revokeVariant,
@@ -3950,8 +4166,8 @@ function SecurityPanel(props) {
3950
4166
  }
3951
4167
  ) : null
3952
4168
  ] }, session.id)),
3953
- sessions !== null && others.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)("p", { className: "throttle-muted", children: t.security.sessionsEmpty }) : null,
3954
- others.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
4169
+ sessions !== null && others.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("p", { className: "throttle-muted", children: t.security.sessionsEmpty }) : null,
4170
+ others.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
3955
4171
  Button,
3956
4172
  {
3957
4173
  variant: "danger",
@@ -3971,7 +4187,7 @@ function SecurityPanel(props) {
3971
4187
  }
3972
4188
 
3973
4189
  // src/react/components/account/AccountDashboard.tsx
3974
- var import_jsx_runtime41 = require("react/jsx-runtime");
4190
+ var import_jsx_runtime42 = require("react/jsx-runtime");
3975
4191
  var ACCOUNT_TABS = [
3976
4192
  "profile",
3977
4193
  "addresses",
@@ -4000,9 +4216,9 @@ function AccountDashboard(props) {
4000
4216
  const { status } = useAuth();
4001
4217
  const shown = props.tabs ?? [...ACCOUNT_TABS];
4002
4218
  const controlled = props.tab !== void 0;
4003
- const [internal, setInternal] = (0, import_react27.useState)(shown[0] ?? "profile");
4004
- const idBase = (0, import_react27.useId)();
4005
- (0, import_react27.useEffect)(() => {
4219
+ const [internal, setInternal] = (0, import_react29.useState)(shown[0] ?? "profile");
4220
+ const idBase = (0, import_react29.useId)();
4221
+ (0, import_react29.useEffect)(() => {
4006
4222
  if (props.routing !== "hash" || typeof window === "undefined") return;
4007
4223
  const apply = () => {
4008
4224
  const next = TAB_FOR_HASH[window.location.hash] ?? shown[0];
@@ -4023,7 +4239,7 @@ function AccountDashboard(props) {
4023
4239
  };
4024
4240
  const shared = { appearance: props.appearance, localization: props.localization };
4025
4241
  const sidebar = (props.layout ?? "sidebar") === "sidebar";
4026
- const nav = /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4242
+ const nav = /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
4027
4243
  Tabs,
4028
4244
  {
4029
4245
  idBase,
@@ -4039,7 +4255,7 @@ function AccountDashboard(props) {
4039
4255
  }))
4040
4256
  }
4041
4257
  );
4042
- const panel = /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
4258
+ const panel = /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
4043
4259
  "div",
4044
4260
  {
4045
4261
  ...a.el("accountDashboard.panel", sidebar ? "throttle-account__content" : "throttle-tabs__panel"),
@@ -4048,36 +4264,36 @@ function AccountDashboard(props) {
4048
4264
  "aria-labelledby": `${idBase}-tab-${active}`,
4049
4265
  tabIndex: 0,
4050
4266
  children: [
4051
- active === "profile" ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ProfilePanel, { ...shared }) : null,
4052
- active === "addresses" ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(AddressesPanel, { ...shared, variant: props.panelVariant }) : null,
4053
- active === "paymentMethods" ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PaymentMethodsPanel, { ...shared, variant: props.panelVariant }) : null,
4054
- active === "orders" ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(OrdersPanel, { ...shared, variant: props.panelVariant, onViewSubscription: () => go("subscriptions") }) : null,
4055
- active === "invoices" ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(InvoicesPanel, { ...shared, variant: props.panelVariant }) : null,
4056
- active === "subscriptions" ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(SubscriptionsPanel, { ...shared, variant: props.panelVariant }) : null,
4057
- active === "security" ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(SecurityPanel, { ...shared, variant: props.panelVariant }) : null
4267
+ active === "profile" ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(ProfilePanel, { ...shared }) : null,
4268
+ active === "addresses" ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AddressesPanel, { ...shared, variant: props.panelVariant }) : null,
4269
+ active === "paymentMethods" ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(PaymentMethodsPanel, { ...shared, variant: props.panelVariant }) : null,
4270
+ active === "orders" ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(OrdersPanel, { ...shared, variant: props.panelVariant, onViewSubscription: () => go("subscriptions") }) : null,
4271
+ active === "invoices" ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(InvoicesPanel, { ...shared, variant: props.panelVariant }) : null,
4272
+ active === "subscriptions" ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(SubscriptionsPanel, { ...shared, variant: props.panelVariant }) : null,
4273
+ active === "security" ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(SecurityPanel, { ...shared, variant: props.panelVariant }) : null
4058
4274
  ]
4059
4275
  }
4060
4276
  );
4061
- return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ...a.el("accountDashboard.root", "throttle-panel throttle-account-root"), children: [
4062
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(VerifyEmailBanner, { ...shared }),
4063
- sidebar ? /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "throttle-account", children: [
4064
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { ...a.el("accountDashboard.sidebar"), children: nav }),
4277
+ return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { ...a.el("accountDashboard.root", "throttle-panel throttle-account-root"), children: [
4278
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(VerifyEmailBanner, { ...shared }),
4279
+ sidebar ? /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)("div", { className: "throttle-account", children: [
4280
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { ...a.el("accountDashboard.sidebar"), children: nav }),
4065
4281
  panel
4066
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
4067
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { ...a.el("accountDashboard.tabs"), children: nav }),
4282
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_jsx_runtime42.Fragment, { children: [
4283
+ /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { ...a.el("accountDashboard.tabs"), children: nav }),
4068
4284
  panel
4069
4285
  ] })
4070
4286
  ] }) }) });
4071
4287
  }
4072
4288
 
4073
4289
  // src/react/components/account/AccountModal.tsx
4074
- var import_jsx_runtime42 = require("react/jsx-runtime");
4290
+ var import_jsx_runtime43 = require("react/jsx-runtime");
4075
4291
  function AccountModal(props) {
4076
4292
  const a = useAppearance(props.appearance);
4077
4293
  const scoped = useAppearanceProviderValue(props.appearance);
4078
4294
  const { t } = useCopy(props.localization);
4079
- const titleId = (0, import_react28.useId)();
4080
- return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
4295
+ const titleId = (0, import_react30.useId)();
4296
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
4081
4297
  Modal,
4082
4298
  {
4083
4299
  open: props.open,
@@ -4087,15 +4303,15 @@ function AccountModal(props) {
4087
4303
  overlayKey: "accountModal.overlay",
4088
4304
  containerKey: "accountModal.container",
4089
4305
  children: [
4090
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { ...a.el("accountModal.header", "throttle-modal__header"), children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("h2", { id: titleId, ...a.el("accountModal.title", "throttle-modal__title"), children: t.account.title }) }),
4091
- /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("div", { ...a.el("accountModal.body", "throttle-modal__body"), children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AccountDashboard, { tabs: props.tabs, appearance: props.appearance, localization: props.localization }) })
4306
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { ...a.el("accountModal.header", "throttle-modal__header"), children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("h2", { id: titleId, ...a.el("accountModal.title", "throttle-modal__title"), children: t.account.title }) }),
4307
+ /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { ...a.el("accountModal.body", "throttle-modal__body"), children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AccountDashboard, { tabs: props.tabs, appearance: props.appearance, localization: props.localization }) })
4092
4308
  ]
4093
4309
  }
4094
4310
  ) });
4095
4311
  }
4096
4312
 
4097
4313
  // src/react/components/provider.tsx
4098
- var import_jsx_runtime43 = require("react/jsx-runtime");
4314
+ var import_jsx_runtime44 = require("react/jsx-runtime");
4099
4315
  var warned = /* @__PURE__ */ new Set();
4100
4316
  function warnOnce(key, message) {
4101
4317
  if (process.env.NODE_ENV === "production") return;
@@ -4103,9 +4319,9 @@ function warnOnce(key, message) {
4103
4319
  warned.add(key);
4104
4320
  console.warn(`[@usethrottle/auth] ${message}`);
4105
4321
  }
4106
- var ThrottleUIContext = (0, import_react29.createContext)(null);
4322
+ var ThrottleUIContext = (0, import_react31.createContext)(null);
4107
4323
  function useThrottle() {
4108
- const ctx = (0, import_react29.useContext)(ThrottleUIContext);
4324
+ const ctx = (0, import_react31.useContext)(ThrottleUIContext);
4109
4325
  if (!ctx) {
4110
4326
  warnOnce(
4111
4327
  "use-throttle-no-provider",
@@ -4140,51 +4356,51 @@ function ThrottleProvider(props) {
4140
4356
  __captureStepUp
4141
4357
  } = props;
4142
4358
  useInjectStyles(injectStyles);
4143
- const [stepUpOpen, setStepUpOpen] = (0, import_react29.useState)(false);
4144
- const resolveStepUp = (0, import_react29.useRef)(null);
4145
- const claimRef = (0, import_react29.useRef)(claimCartOnSignIn);
4359
+ const [stepUpOpen, setStepUpOpen] = (0, import_react31.useState)(false);
4360
+ const resolveStepUp = (0, import_react31.useRef)(null);
4361
+ const claimRef = (0, import_react31.useRef)(claimCartOnSignIn);
4146
4362
  claimRef.current = claimCartOnSignIn;
4147
- const [overlay, setOverlay] = (0, import_react29.useState)(null);
4148
- const overlayRestoreFocus = (0, import_react29.useRef)(null);
4149
- const [accountTabs, setAccountTabs] = (0, import_react29.useState)(void 0);
4150
- const onOverlaySuccess = (0, import_react29.useRef)(null);
4151
- const openSignIn = (0, import_react29.useCallback)((onSuccess) => {
4363
+ const [overlay, setOverlay] = (0, import_react31.useState)(null);
4364
+ const overlayRestoreFocus = (0, import_react31.useRef)(null);
4365
+ const [accountTabs, setAccountTabs] = (0, import_react31.useState)(void 0);
4366
+ const onOverlaySuccess = (0, import_react31.useRef)(null);
4367
+ const openSignIn = (0, import_react31.useCallback)((onSuccess) => {
4152
4368
  onOverlaySuccess.current = onSuccess ?? null;
4153
4369
  setOverlay("signIn");
4154
4370
  }, []);
4155
- const openSignUp = (0, import_react29.useCallback)((onSuccess) => {
4371
+ const openSignUp = (0, import_react31.useCallback)((onSuccess) => {
4156
4372
  onOverlaySuccess.current = onSuccess ?? null;
4157
4373
  setOverlay("signUp");
4158
4374
  }, []);
4159
- const openAccount = (0, import_react29.useCallback)((opts) => {
4375
+ const openAccount = (0, import_react31.useCallback)((opts) => {
4160
4376
  onOverlaySuccess.current = null;
4161
4377
  overlayRestoreFocus.current = opts?.restoreFocusTo ?? null;
4162
4378
  setAccountTabs(opts?.tabs);
4163
4379
  setOverlay("account");
4164
4380
  }, []);
4165
- const closeOverlay = (0, import_react29.useCallback)(() => {
4381
+ const closeOverlay = (0, import_react31.useCallback)(() => {
4166
4382
  onOverlaySuccess.current = null;
4167
4383
  overlayRestoreFocus.current = null;
4168
4384
  setOverlay(null);
4169
4385
  }, []);
4170
- const handleOverlaySuccess = (0, import_react29.useCallback)(() => {
4386
+ const handleOverlaySuccess = (0, import_react31.useCallback)(() => {
4171
4387
  const fn = onOverlaySuccess.current;
4172
4388
  onOverlaySuccess.current = null;
4173
4389
  setOverlay(null);
4174
4390
  fn?.();
4175
4391
  }, []);
4176
- const ui = (0, import_react29.useMemo)(
4392
+ const ui = (0, import_react31.useMemo)(
4177
4393
  () => ({ overlay, openSignIn, openSignUp, openAccount, close: closeOverlay }),
4178
4394
  [overlay, openSignIn, openSignUp, openAccount, closeOverlay]
4179
4395
  );
4180
- const askForStepUp = (0, import_react29.useCallback)(
4396
+ const askForStepUp = (0, import_react31.useCallback)(
4181
4397
  () => new Promise((resolve) => {
4182
4398
  resolveStepUp.current = resolve;
4183
4399
  setStepUpOpen(true);
4184
4400
  }),
4185
4401
  []
4186
4402
  );
4187
- const auth = (0, import_react29.useMemo)(() => {
4403
+ const auth = (0, import_react31.useMemo)(() => {
4188
4404
  __captureStepUp?.(askForStepUp);
4189
4405
  const client = injected ?? createThrottleAuth({ publishableKey, baseUrl, storage, onStepUpRequired: askForStepUp });
4190
4406
  const account = createAccount(client);
@@ -4217,10 +4433,10 @@ function ThrottleProvider(props) {
4217
4433
  resolve?.(password);
4218
4434
  };
4219
4435
  const authOverlayOpen = overlay === "signIn" || overlay === "signUp";
4220
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AppearanceProvider, { value: appearance ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(LocalizationProvider, { value: localization ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(BrandLogoProvider, { value: logo ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ThrottleAuthProvider, { auth, publishableKey, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(ThrottleUIContext.Provider, { value: ui, children: [
4436
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AppearanceProvider, { value: appearance ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(LocalizationProvider, { value: localization ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(BrandLogoProvider, { value: logo ?? null, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(ThrottleAuthProvider, { auth, publishableKey, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(ThrottleUIContext.Provider, { value: ui, children: [
4221
4437
  children,
4222
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StepUpDialog, { open: stepUpOpen, onResolve: finishStepUp }),
4223
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
4438
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(StepUpDialog, { open: stepUpOpen, onResolve: finishStepUp }),
4439
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
4224
4440
  AuthModal,
4225
4441
  {
4226
4442
  open: authOverlayOpen,
@@ -4231,23 +4447,23 @@ function ThrottleProvider(props) {
4231
4447
  },
4232
4448
  overlay === "signUp" ? "signUp" : "signIn"
4233
4449
  ),
4234
- /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AccountModal, { open: overlay === "account", onClose: closeOverlay, tabs: accountTabs, restoreFocusTo: overlayRestoreFocus.current })
4450
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AccountModal, { open: overlay === "account", onClose: closeOverlay, tabs: accountTabs, restoreFocusTo: overlayRestoreFocus.current })
4235
4451
  ] }) }) }) }) });
4236
4452
  }
4237
4453
 
4238
4454
  // src/react/components/auth/SignInButton.tsx
4239
- var import_react30 = require("react");
4240
- var import_jsx_runtime44 = require("react/jsx-runtime");
4455
+ var import_react32 = require("react");
4456
+ var import_jsx_runtime45 = require("react/jsx-runtime");
4241
4457
  function SignInButton(props) {
4242
4458
  const a = useAppearance(props.appearance);
4243
4459
  const scoped = useAppearanceProviderValue(props.appearance);
4244
4460
  const { t } = useCopy(props.localization);
4245
- const ui = (0, import_react30.useContext)(ThrottleUIContext);
4246
- const [localOpen, setLocalOpen] = (0, import_react30.useState)(false);
4461
+ const ui = (0, import_react32.useContext)(ThrottleUIContext);
4462
+ const [localOpen, setLocalOpen] = (0, import_react32.useState)(false);
4247
4463
  const useShared = ui !== null && props.initialView === void 0;
4248
4464
  const label = props.children ?? t.signIn.submitButton;
4249
4465
  if (props.mode === "redirect") {
4250
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("a", { ...a.el("signInButton.root", "throttle-button throttle-button--primary"), href: props.url ?? "#", children: label }) }) });
4466
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("a", { ...a.el("signInButton.root", "throttle-button throttle-button--primary"), href: props.url ?? "#", children: label }) }) });
4251
4467
  }
4252
4468
  const openModal = () => {
4253
4469
  if (useShared) ui.openSignIn(props.afterSignIn);
@@ -4257,10 +4473,10 @@ function SignInButton(props) {
4257
4473
  if (useShared) ui.close();
4258
4474
  else setLocalOpen(false);
4259
4475
  };
4260
- const trigger = props.asChild && (0, import_react30.isValidElement)(props.children) ? (0, import_react30.cloneElement)(props.children, { onClick: openModal }) : /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(Button, { elementKey: "signInButton.root", onClick: openModal, children: label });
4261
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(AppearanceProvider, { value: scoped, children: [
4262
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("span", { ...a.rootProps, children: trigger }),
4263
- !useShared ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
4476
+ const trigger = props.asChild && (0, import_react32.isValidElement)(props.children) ? (0, import_react32.cloneElement)(props.children, { onClick: openModal }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { elementKey: "signInButton.root", onClick: openModal, children: label });
4477
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(AppearanceProvider, { value: scoped, children: [
4478
+ /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { ...a.rootProps, children: trigger }),
4479
+ !useShared ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
4264
4480
  AuthModal,
4265
4481
  {
4266
4482
  open: localOpen,
@@ -4278,18 +4494,18 @@ function SignInButton(props) {
4278
4494
  }
4279
4495
 
4280
4496
  // src/react/components/auth/SignUpButton.tsx
4281
- var import_react31 = require("react");
4282
- var import_jsx_runtime45 = require("react/jsx-runtime");
4497
+ var import_react33 = require("react");
4498
+ var import_jsx_runtime46 = require("react/jsx-runtime");
4283
4499
  function SignUpButton(props) {
4284
4500
  const a = useAppearance(props.appearance);
4285
4501
  const scoped = useAppearanceProviderValue(props.appearance);
4286
4502
  const { t } = useCopy(props.localization);
4287
- const ui = (0, import_react31.useContext)(ThrottleUIContext);
4288
- const [localOpen, setLocalOpen] = (0, import_react31.useState)(false);
4503
+ const ui = (0, import_react33.useContext)(ThrottleUIContext);
4504
+ const [localOpen, setLocalOpen] = (0, import_react33.useState)(false);
4289
4505
  const useShared = ui !== null && props.initialView === void 0;
4290
4506
  const label = props.children ?? t.signUp.submitButton;
4291
4507
  if (props.mode === "redirect") {
4292
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("a", { ...a.el("signUpButton.root", "throttle-button throttle-button--primary"), href: props.url ?? "#", children: label }) }) });
4508
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("a", { ...a.el("signUpButton.root", "throttle-button throttle-button--primary"), href: props.url ?? "#", children: label }) }) });
4293
4509
  }
4294
4510
  const openModal = () => {
4295
4511
  if (useShared) ui.openSignUp(props.afterSignUp);
@@ -4299,10 +4515,10 @@ function SignUpButton(props) {
4299
4515
  if (useShared) ui.close();
4300
4516
  else setLocalOpen(false);
4301
4517
  };
4302
- const trigger = props.asChild && (0, import_react31.isValidElement)(props.children) ? (0, import_react31.cloneElement)(props.children, { onClick: openModal }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(Button, { elementKey: "signUpButton.root", onClick: openModal, children: label });
4303
- return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(AppearanceProvider, { value: scoped, children: [
4304
- /* @__PURE__ */ (0, import_jsx_runtime45.jsx)("span", { ...a.rootProps, children: trigger }),
4305
- !useShared ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
4518
+ const trigger = props.asChild && (0, import_react33.isValidElement)(props.children) ? (0, import_react33.cloneElement)(props.children, { onClick: openModal }) : /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(Button, { elementKey: "signUpButton.root", onClick: openModal, children: label });
4519
+ return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(AppearanceProvider, { value: scoped, children: [
4520
+ /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { ...a.rootProps, children: trigger }),
4521
+ !useShared ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
4306
4522
  AuthModal,
4307
4523
  {
4308
4524
  open: localOpen,
@@ -4320,14 +4536,14 @@ function SignUpButton(props) {
4320
4536
  }
4321
4537
 
4322
4538
  // src/react/components/auth/SignOutButton.tsx
4323
- var import_jsx_runtime46 = require("react/jsx-runtime");
4539
+ var import_jsx_runtime47 = require("react/jsx-runtime");
4324
4540
  function SignOutButton(props) {
4325
4541
  const a = useAppearance();
4326
4542
  const { auth } = useAuth();
4327
4543
  const { t } = useCopy(props.localization);
4328
4544
  const { submitting, run } = useAction();
4329
4545
  const label = props.children ?? (props.everywhere ? t.userButton.signOutAll : t.userButton.signOut);
4330
- return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)("span", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
4546
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4331
4547
  Button,
4332
4548
  {
4333
4549
  variant: "secondary",
@@ -4344,13 +4560,13 @@ function SignOutButton(props) {
4344
4560
  }
4345
4561
 
4346
4562
  // src/react/components/auth/SignInPage.tsx
4347
- var import_jsx_runtime47 = require("react/jsx-runtime");
4563
+ var import_jsx_runtime48 = require("react/jsx-runtime");
4348
4564
  function SignInPage(props) {
4349
4565
  const a = useAppearance(props.appearance);
4350
4566
  const scoped = useAppearanceProviderValue(props.appearance);
4351
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { ...a.el("signInPage.root", "throttle-page"), children: [
4352
- props.logo ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { ...a.el("signInPage.logo", "throttle-page__logo"), children: props.logo }) : null,
4353
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
4567
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { ...a.el("signInPage.root", "throttle-page"), children: [
4568
+ props.logo ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { ...a.el("signInPage.logo", "throttle-page__logo"), children: props.logo }) : null,
4569
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
4354
4570
  SignIn,
4355
4571
  {
4356
4572
  onSuccess: props.onSuccess,
@@ -4360,18 +4576,18 @@ function SignInPage(props) {
4360
4576
  localization: props.localization
4361
4577
  }
4362
4578
  ),
4363
- props.footer ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { ...a.el("signInPage.footer", "throttle-page__footer"), children: props.footer }) : null
4579
+ props.footer ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { ...a.el("signInPage.footer", "throttle-page__footer"), children: props.footer }) : null
4364
4580
  ] }) }) });
4365
4581
  }
4366
4582
 
4367
4583
  // src/react/components/auth/SignUpPage.tsx
4368
- var import_jsx_runtime48 = require("react/jsx-runtime");
4584
+ var import_jsx_runtime49 = require("react/jsx-runtime");
4369
4585
  function SignUpPage(props) {
4370
4586
  const a = useAppearance(props.appearance);
4371
4587
  const scoped = useAppearanceProviderValue(props.appearance);
4372
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { ...a.el("signUpPage.root", "throttle-page"), children: [
4373
- props.logo ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { ...a.el("signUpPage.logo", "throttle-page__logo"), children: props.logo }) : null,
4374
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
4588
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { ...a.el("signUpPage.root", "throttle-page"), children: [
4589
+ props.logo ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { ...a.el("signUpPage.logo", "throttle-page__logo"), children: props.logo }) : null,
4590
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
4375
4591
  SignUp,
4376
4592
  {
4377
4593
  onSuccess: props.onSuccess,
@@ -4380,42 +4596,42 @@ function SignUpPage(props) {
4380
4596
  localization: props.localization
4381
4597
  }
4382
4598
  ),
4383
- props.footer ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { ...a.el("signUpPage.footer", "throttle-page__footer"), children: props.footer }) : null
4599
+ props.footer ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { ...a.el("signUpPage.footer", "throttle-page__footer"), children: props.footer }) : null
4384
4600
  ] }) }) });
4385
4601
  }
4386
4602
 
4387
4603
  // src/react/components/guards.tsx
4388
- var import_jsx_runtime49 = require("react/jsx-runtime");
4604
+ var import_jsx_runtime50 = require("react/jsx-runtime");
4389
4605
  function SignedIn(props) {
4390
4606
  const { status } = useAuth();
4391
- return status === "authenticated" ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_jsx_runtime49.Fragment, { children: props.children }) : null;
4607
+ return status === "authenticated" ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_jsx_runtime50.Fragment, { children: props.children }) : null;
4392
4608
  }
4393
4609
  function SignedOut(props) {
4394
4610
  const { status } = useAuth();
4395
- return status === "unauthenticated" ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_jsx_runtime49.Fragment, { children: props.children }) : null;
4611
+ return status === "unauthenticated" ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_jsx_runtime50.Fragment, { children: props.children }) : null;
4396
4612
  }
4397
4613
  function Protect(props) {
4398
4614
  const { status, emailVerified } = useAuth();
4399
4615
  if (status === "loading") return null;
4400
- if (status !== "authenticated") return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_jsx_runtime49.Fragment, { children: props.fallback ?? null });
4401
- if (props.requireVerified && !emailVerified) return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_jsx_runtime49.Fragment, { children: props.fallback ?? null });
4402
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(import_jsx_runtime49.Fragment, { children: props.children });
4616
+ if (status !== "authenticated") return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_jsx_runtime50.Fragment, { children: props.fallback ?? null });
4617
+ if (props.requireVerified && !emailVerified) return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_jsx_runtime50.Fragment, { children: props.fallback ?? null });
4618
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_jsx_runtime50.Fragment, { children: props.children });
4403
4619
  }
4404
4620
 
4405
4621
  // src/react/components/UserButton.tsx
4406
- var import_react32 = require("react");
4407
- var import_jsx_runtime50 = require("react/jsx-runtime");
4622
+ var import_react34 = require("react");
4623
+ var import_jsx_runtime51 = require("react/jsx-runtime");
4408
4624
  function UserButtonRoot(props) {
4409
4625
  const a = useAppearance(props.appearance);
4410
4626
  const scoped = useAppearanceProviderValue(props.appearance);
4411
4627
  const { t } = useCopy(props.localization);
4412
4628
  const { auth, status, customer, emailVerified } = useAuth();
4413
- const ui = (0, import_react32.useContext)(ThrottleUIContext);
4414
- const [localOpen, setLocalOpen] = (0, import_react32.useState)(false);
4629
+ const ui = (0, import_react34.useContext)(ThrottleUIContext);
4630
+ const [localOpen, setLocalOpen] = (0, import_react34.useState)(false);
4415
4631
  const accountOpen = ui ? false : localOpen;
4416
- const titleId = (0, import_react32.useId)();
4417
- const rootRef = (0, import_react32.useRef)(null);
4418
- const openerRef = (0, import_react32.useRef)(null);
4632
+ const titleId = (0, import_react34.useId)();
4633
+ const rootRef = (0, import_react34.useRef)(null);
4634
+ const openerRef = (0, import_react34.useRef)(null);
4419
4635
  const openAccount = () => {
4420
4636
  const opener = rootRef.current?.querySelector('button[aria-haspopup="menu"]') ?? null;
4421
4637
  openerRef.current = opener;
@@ -4424,25 +4640,25 @@ function UserButtonRoot(props) {
4424
4640
  };
4425
4641
  if (status !== "authenticated" || !customer) return null;
4426
4642
  const name = [customer.firstName, customer.lastName].filter(Boolean).join(" ");
4427
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { ref: rootRef, ...a.el("userButton.root"), children: [
4428
- /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
4643
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("span", { ref: rootRef, ...a.el("userButton.root"), children: [
4644
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
4429
4645
  Dropdown,
4430
4646
  {
4431
4647
  label: t.userButton.openMenu,
4432
4648
  triggerKey: "userButton.trigger",
4433
4649
  menuKey: "userButton.menu",
4434
- trigger: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Avatar, { name, email: customer.email }),
4650
+ trigger: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(Avatar, { name, email: customer.email }),
4435
4651
  children: [
4436
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { ...a.el("userButton.identity", "throttle-dropdown__item"), children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("span", { children: [
4437
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { ...a.el("userButton.email"), children: customer.email }),
4438
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("br", {}),
4439
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Badge, { tone: emailVerified ? "success" : "warning", elementKey: "userButton.badge", children: emailVerified ? t.userButton.verified : t.userButton.unverified })
4652
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { ...a.el("userButton.identity", "throttle-dropdown__item"), children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("span", { children: [
4653
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { ...a.el("userButton.email"), children: customer.email }),
4654
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("br", {}),
4655
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(Badge, { tone: emailVerified ? "success" : "warning", elementKey: "userButton.badge", children: emailVerified ? t.userButton.verified : t.userButton.unverified })
4440
4656
  ] }) }),
4441
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(DropdownSeparator, {}),
4442
- props.mode === "navigate" ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(DropdownItem, { itemKey: "userButton.manageButton", href: props.accountUrl ?? "#", children: t.userButton.manage }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(DropdownItem, { itemKey: "userButton.manageButton", onClick: openAccount, children: t.userButton.manage }),
4657
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(DropdownSeparator, {}),
4658
+ props.mode === "navigate" ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(DropdownItem, { itemKey: "userButton.manageButton", href: props.accountUrl ?? "#", children: t.userButton.manage }) : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(DropdownItem, { itemKey: "userButton.manageButton", onClick: openAccount, children: t.userButton.manage }),
4443
4659
  props.children,
4444
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(DropdownSeparator, {}),
4445
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
4660
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(DropdownSeparator, {}),
4661
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
4446
4662
  DropdownItem,
4447
4663
  {
4448
4664
  itemKey: "userButton.signOutButton",
@@ -4450,7 +4666,7 @@ function UserButtonRoot(props) {
4450
4666
  children: t.userButton.signOut
4451
4667
  }
4452
4668
  ),
4453
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
4669
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
4454
4670
  DropdownItem,
4455
4671
  {
4456
4672
  itemKey: "userButton.signOutAllButton",
@@ -4461,7 +4677,7 @@ function UserButtonRoot(props) {
4461
4677
  ]
4462
4678
  }
4463
4679
  ),
4464
- props.mode !== "navigate" && !ui ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
4680
+ props.mode !== "navigate" && !ui ? /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
4465
4681
  Modal,
4466
4682
  {
4467
4683
  open: accountOpen,
@@ -4469,8 +4685,8 @@ function UserButtonRoot(props) {
4469
4685
  labelledBy: titleId,
4470
4686
  restoreFocusTo: openerRef.current,
4471
4687
  children: [
4472
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("h2", { id: titleId, style: { padding: "16px 16px 0", margin: 0 }, children: t.account.title }),
4473
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { style: { padding: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
4688
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("h2", { id: titleId, style: { padding: "16px 16px 0", margin: 0 }, children: t.account.title }),
4689
+ /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { style: { padding: 16 }, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
4474
4690
  AccountDashboard,
4475
4691
  {
4476
4692
  tabs: props.tabs,
@@ -4484,13 +4700,13 @@ function UserButtonRoot(props) {
4484
4700
  ] }) }) });
4485
4701
  }
4486
4702
  function UserButtonLink(props) {
4487
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(DropdownItem, { itemKey: "userButton.item", href: props.href, children: [
4703
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(DropdownItem, { itemKey: "userButton.item", href: props.href, children: [
4488
4704
  props.icon,
4489
4705
  props.label
4490
4706
  ] });
4491
4707
  }
4492
4708
  function UserButtonAction(props) {
4493
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(DropdownItem, { itemKey: "userButton.item", onClick: props.onClick, children: [
4709
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(DropdownItem, { itemKey: "userButton.item", onClick: props.onClick, children: [
4494
4710
  props.icon,
4495
4711
  props.label
4496
4712
  ] });
@@ -4504,6 +4720,7 @@ var UserButton = Object.assign(UserButtonRoot, {
4504
4720
  ACCOUNT_TABS,
4505
4721
  AccountDashboard,
4506
4722
  AccountModal,
4723
+ AddCardDialog,
4507
4724
  AddressesPanel,
4508
4725
  AuthFlow,
4509
4726
  AuthModal,