@base316/react 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -162,7 +162,7 @@ var STYLESHEET = `
162
162
  }
163
163
 
164
164
  /* The recommended plan. Lifted rather than merely tinted: on a pricing table
165
- the eye needs one obvious default, and colour alone does not survive being
165
+ the eye needs one obvious default, and color alone does not survive being
166
166
  viewed in greyscale or by someone who cannot distinguish the accent. */
167
167
  .b316-plan-featured {
168
168
  border-color: var(--b316-color-primary);
@@ -549,7 +549,7 @@ var STYLESHEET_EXTRA = `
549
549
  .b316-mfa-uri { font-size: 0.9em; }
550
550
  .b316-mfa-code-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
551
551
  .b316-mfa-code-list code { user-select: all; }
552
- /* The enrolment choices: whole-width buttons with their explanation inside,
552
+ /* The enrollment choices: whole-width buttons with their explanation inside,
553
553
  so the explanation is part of what a screen reader announces. */
554
554
  .b316-mfa-methods { display: flex; flex-direction: column; gap: 8px; border: 0; margin: 0; padding: 0; min-width: 0; }
555
555
  .b316-mfa-method { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%; text-align: left; }
@@ -680,7 +680,7 @@ function Base316Provider({
680
680
  const [internalToken, setInternalToken] = useState(null);
681
681
  const [session, setSession] = useState(null);
682
682
  const [branding, setBranding] = useState(null);
683
- const [loading, setLoading] = useState(true);
683
+ const [loading2, setLoading] = useState(true);
684
684
  const token = controlled ? controlledToken : internalToken;
685
685
  useEffect(() => {
686
686
  if (controlled) {
@@ -742,8 +742,8 @@ function Base316Provider({
742
742
  setSession(null);
743
743
  }, [client, token, setToken]);
744
744
  const value = useMemo(
745
- () => ({ client, branding, token, setToken, session, loading, refresh, signOut }),
746
- [client, branding, token, setToken, session, loading, refresh, signOut]
745
+ () => ({ client, branding, token, setToken, session, loading: loading2, refresh, signOut }),
746
+ [client, branding, token, setToken, session, loading2, refresh, signOut]
747
747
  );
748
748
  return /* @__PURE__ */ jsx(Base316Context.Provider, { value, children: /* @__PURE__ */ jsx(
749
749
  "div",
@@ -752,7 +752,7 @@ function Base316Provider({
752
752
  style: appearanceToStyle({
753
753
  // Whatever was set in the sign-in designer arrives here, so a
754
754
  // customer styles their login once on Base316 and the embedded
755
- // components follow — rather than configuring the same colours
755
+ // components follow — rather than configuring the same colors
756
756
  // twice and watching them drift apart.
757
757
  //
758
758
  // An explicit `appearance` still wins, because a host that has
@@ -775,8 +775,8 @@ function useBase316() {
775
775
  return value;
776
776
  }
777
777
  function useSession() {
778
- const { session, loading } = useBase316();
779
- return { session, loading };
778
+ const { session, loading: loading2 } = useBase316();
779
+ return { session, loading: loading2 };
780
780
  }
781
781
 
782
782
  // src/Branding.tsx
@@ -2651,8 +2651,72 @@ import {
2651
2651
  Base316Error as Base316Error3,
2652
2652
  needsSecondFactor as needsSecondFactor2
2653
2653
  } from "@base316/sdk";
2654
- import { useEffect as useEffect9, useState as useState9 } from "react";
2655
- import { Fragment as Fragment6, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2654
+ import { useEffect as useEffect10, useState as useState9 } from "react";
2655
+
2656
+ // src/CaptchaWidget.tsx
2657
+ import { useEffect as useEffect9, useRef as useRef3 } from "react";
2658
+ import { jsx as jsx11 } from "react/jsx-runtime";
2659
+ var SCRIPT_URL = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
2660
+ var loading = null;
2661
+ function loadTurnstile() {
2662
+ if (window.turnstile) {
2663
+ return Promise.resolve(window.turnstile);
2664
+ }
2665
+ loading ??= new Promise((resolve, reject) => {
2666
+ const script = document.createElement("script");
2667
+ script.src = SCRIPT_URL;
2668
+ script.async = true;
2669
+ script.onload = () => {
2670
+ if (window.turnstile) {
2671
+ resolve(window.turnstile);
2672
+ } else {
2673
+ reject(new Error("Turnstile did not start"));
2674
+ }
2675
+ };
2676
+ script.onerror = () => {
2677
+ loading = null;
2678
+ reject(new Error("Turnstile could not be loaded"));
2679
+ };
2680
+ document.head.appendChild(script);
2681
+ });
2682
+ return loading;
2683
+ }
2684
+ function CaptchaWidget({
2685
+ siteKey,
2686
+ onToken
2687
+ }) {
2688
+ const container = useRef3(null);
2689
+ const latest = useRef3(onToken);
2690
+ useEffect9(() => {
2691
+ latest.current = onToken;
2692
+ }, [onToken]);
2693
+ useEffect9(() => {
2694
+ let widgetId = null;
2695
+ let cancelled = false;
2696
+ loadTurnstile().then((turnstile) => {
2697
+ if (cancelled || !container.current) {
2698
+ return;
2699
+ }
2700
+ widgetId = turnstile.render(container.current, {
2701
+ sitekey: siteKey,
2702
+ size: "flexible",
2703
+ callback: (token) => latest.current(token),
2704
+ "expired-callback": () => latest.current(null),
2705
+ "error-callback": () => latest.current(null)
2706
+ });
2707
+ }).catch((cause) => console.error("[base316] CAPTCHA unavailable", cause));
2708
+ return () => {
2709
+ cancelled = true;
2710
+ if (widgetId) {
2711
+ window.turnstile?.remove(widgetId);
2712
+ }
2713
+ };
2714
+ }, [siteKey]);
2715
+ return /* @__PURE__ */ jsx11("div", { ref: container, className: "b316-captcha" });
2716
+ }
2717
+
2718
+ // src/SignUp.tsx
2719
+ import { Fragment as Fragment6, jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
2656
2720
  var DEFAULT_SIGN_UP_LABELS = {
2657
2721
  name: "Name",
2658
2722
  email: "Email",
@@ -2672,7 +2736,8 @@ var DEFAULT_SIGN_UP_LABELS = {
2672
2736
  joining: (organizationName, roleName) => `You are joining ${organizationName} as ${roleName}. Sign up with the address the invitation was sent to.`,
2673
2737
  continueWith: (name) => `Continue with ${name}`,
2674
2738
  or: "or",
2675
- closed: "This application is not accepting new accounts right now."
2739
+ closed: "This application is not accepting new accounts right now.",
2740
+ noMethods: "Creating an account is not available here right now."
2676
2741
  };
2677
2742
  function describeRules(policy, labels) {
2678
2743
  const extras = [
@@ -2711,15 +2776,17 @@ function SignUp({
2711
2776
  const [confirmEmail, setConfirmEmail] = useState9(false);
2712
2777
  const [urlInvitation, setUrlInvitation] = useState9(null);
2713
2778
  const [loaded, setLoaded] = useState9(null);
2779
+ const [captchaToken, setCaptchaToken] = useState9(null);
2780
+ const [captchaRound, setCaptchaRound] = useState9(0);
2714
2781
  const invitation = suppliedInvitation === void 0 ? urlInvitation : suppliedInvitation;
2715
2782
  const preview = loaded && loaded.token === invitation ? loaded.preview : null;
2716
- useEffect9(() => {
2783
+ useEffect10(() => {
2717
2784
  if (suppliedInvitation !== void 0 || typeof window === "undefined") {
2718
2785
  return;
2719
2786
  }
2720
2787
  setUrlInvitation(new URL(window.location.href).searchParams.get("invitation"));
2721
2788
  }, [suppliedInvitation]);
2722
- useEffect9(() => {
2789
+ useEffect10(() => {
2723
2790
  if (!invitation) {
2724
2791
  return;
2725
2792
  }
@@ -2734,7 +2801,7 @@ function SignUp({
2734
2801
  cancelled = true;
2735
2802
  };
2736
2803
  }, [client, invitation]);
2737
- useEffect9(() => {
2804
+ useEffect10(() => {
2738
2805
  let cancelled = false;
2739
2806
  client.auth.passwordPolicy().then((loaded2) => {
2740
2807
  if (!cancelled) {
@@ -2754,7 +2821,8 @@ function SignUp({
2754
2821
  email,
2755
2822
  password,
2756
2823
  name: name || void 0,
2757
- invitationToken: invitation ?? void 0
2824
+ invitationToken: invitation ?? void 0,
2825
+ captchaToken: captchaToken ?? void 0
2758
2826
  });
2759
2827
  if (created.invitationAccepted && created.organizationId) {
2760
2828
  onJoined?.(created.organizationId);
@@ -2764,6 +2832,8 @@ function SignUp({
2764
2832
  setError(
2765
2833
  cause instanceof Base316Error3 && (cause.code === "INVALID_REQUEST" || cause.code === "RATE_LIMITED" || cause.code === "CONFLICT") && cause.message ? cause.message : labels.genericError
2766
2834
  );
2835
+ setCaptchaToken(null);
2836
+ setCaptchaRound((round) => round + 1);
2767
2837
  setBusy(false);
2768
2838
  return;
2769
2839
  }
@@ -2792,21 +2862,24 @@ function SignUp({
2792
2862
  }
2793
2863
  }
2794
2864
  if (pending) {
2795
- return /* @__PURE__ */ jsx11("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx11(SecondFactorStep, { pending, labels: secondFactorLabels, onSignedIn: onSignedUp }) });
2865
+ return /* @__PURE__ */ jsx12("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx12(SecondFactorStep, { pending, labels: secondFactorLabels, onSignedIn: onSignedUp }) });
2796
2866
  }
2797
2867
  if (confirmEmail) {
2798
2868
  return /* @__PURE__ */ jsxs10("div", { className: cls("b316-card", className), style, children: [
2799
- /* @__PURE__ */ jsx11("h3", { className: "b316-form-title", children: labels.confirmEmailTitle }),
2800
- /* @__PURE__ */ jsx11("output", { className: "b316-muted", children: labels.confirmEmail(email) })
2869
+ /* @__PURE__ */ jsx12("h3", { className: "b316-form-title", children: labels.confirmEmailTitle }),
2870
+ /* @__PURE__ */ jsx12("output", { className: "b316-muted", children: labels.confirmEmail(email) })
2801
2871
  ] });
2802
2872
  }
2803
2873
  if (!offered.signUp && !invitation) {
2804
- return /* @__PURE__ */ jsx11("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx11("output", { className: "b316-muted", children: labels.closed }) });
2874
+ return /* @__PURE__ */ jsx12("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx12("output", { className: "b316-muted", children: labels.closed }) });
2805
2875
  }
2806
2876
  const socialOptions = invitation ? [] : offered.social;
2877
+ if (!offered.password && socialOptions.length === 0) {
2878
+ return /* @__PURE__ */ jsx12("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx12("output", { className: "b316-muted", children: labels.noMethods }) });
2879
+ }
2807
2880
  return /* @__PURE__ */ jsxs10("form", { onSubmit: submit, className: cls("b316-card", className), style, children: [
2808
2881
  socialOptions.length > 0 ? /* @__PURE__ */ jsxs10(Fragment6, { children: [
2809
- /* @__PURE__ */ jsx11(
2882
+ /* @__PURE__ */ jsx12(
2810
2883
  SocialButtons,
2811
2884
  {
2812
2885
  options: socialOptions,
@@ -2829,14 +2902,14 @@ function SignUp({
2829
2902
  }
2830
2903
  }
2831
2904
  ),
2832
- offered.password ? /* @__PURE__ */ jsx11("div", { className: "b316-divider", children: labels.or }) : null
2905
+ offered.password ? /* @__PURE__ */ jsx12("div", { className: "b316-divider", children: labels.or }) : null
2833
2906
  ] }) : null,
2834
- preview ? /* @__PURE__ */ jsx11("p", { className: "b316-muted", children: labels.joining(preview.organizationName, preview.roleName) }) : null,
2835
- error ? /* @__PURE__ */ jsx11("div", { className: "b316-error", role: "alert", children: error }) : null,
2907
+ preview ? /* @__PURE__ */ jsx12("p", { className: "b316-muted", children: labels.joining(preview.organizationName, preview.roleName) }) : null,
2908
+ error ? /* @__PURE__ */ jsx12("div", { className: "b316-error", role: "alert", children: error }) : null,
2836
2909
  offered.password || socialOptions.length === 0 ? /* @__PURE__ */ jsxs10(Fragment6, { children: [
2837
2910
  /* @__PURE__ */ jsxs10("div", { className: "b316-field", children: [
2838
- /* @__PURE__ */ jsx11("label", { className: "b316-label", htmlFor: "b316-name", children: labels.name }),
2839
- /* @__PURE__ */ jsx11(
2911
+ /* @__PURE__ */ jsx12("label", { className: "b316-label", htmlFor: "b316-name", children: labels.name }),
2912
+ /* @__PURE__ */ jsx12(
2840
2913
  "input",
2841
2914
  {
2842
2915
  id: "b316-name",
@@ -2848,8 +2921,8 @@ function SignUp({
2848
2921
  )
2849
2922
  ] }),
2850
2923
  /* @__PURE__ */ jsxs10("div", { className: "b316-field", children: [
2851
- /* @__PURE__ */ jsx11("label", { className: "b316-label", htmlFor: "b316-signup-email", children: labels.email }),
2852
- /* @__PURE__ */ jsx11(
2924
+ /* @__PURE__ */ jsx12("label", { className: "b316-label", htmlFor: "b316-signup-email", children: labels.email }),
2925
+ /* @__PURE__ */ jsx12(
2853
2926
  "input",
2854
2927
  {
2855
2928
  id: "b316-signup-email",
@@ -2863,8 +2936,8 @@ function SignUp({
2863
2936
  )
2864
2937
  ] }),
2865
2938
  /* @__PURE__ */ jsxs10("div", { className: "b316-field", children: [
2866
- /* @__PURE__ */ jsx11("label", { className: "b316-label", htmlFor: "b316-signup-password", children: labels.password }),
2867
- /* @__PURE__ */ jsx11(
2939
+ /* @__PURE__ */ jsx12("label", { className: "b316-label", htmlFor: "b316-signup-password", children: labels.password }),
2940
+ /* @__PURE__ */ jsx12(
2868
2941
  "input",
2869
2942
  {
2870
2943
  id: "b316-signup-password",
@@ -2879,31 +2952,39 @@ function SignUp({
2879
2952
  required: true
2880
2953
  }
2881
2954
  ),
2882
- policy ? /* @__PURE__ */ jsx11("span", { id: "b316-signup-password-rules", className: "b316-muted", children: describeRules(policy, labels) }) : null
2955
+ policy ? /* @__PURE__ */ jsx12("span", { id: "b316-signup-password-rules", className: "b316-muted", children: describeRules(policy, labels) }) : null
2883
2956
  ] }),
2884
- /* @__PURE__ */ jsx11("button", { className: "b316-button", type: "submit", disabled: busy, children: busy ? labels.working : labels.submit })
2957
+ methodsState.methods?.captcha && !invitation ? /* @__PURE__ */ jsx12(
2958
+ CaptchaWidget,
2959
+ {
2960
+ siteKey: methodsState.methods.captcha.siteKey,
2961
+ onToken: setCaptchaToken
2962
+ },
2963
+ captchaRound
2964
+ ) : null,
2965
+ /* @__PURE__ */ jsx12("button", { className: "b316-button", type: "submit", disabled: busy, children: busy ? labels.working : labels.submit })
2885
2966
  ] }) : null
2886
2967
  ] });
2887
2968
  }
2888
2969
 
2889
2970
  // src/UserProfile.tsx
2890
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2971
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2891
2972
  function UserProfile({ className, style }) {
2892
- const { session, loading, signOut } = useBase316();
2893
- if (loading) {
2894
- return /* @__PURE__ */ jsx12("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
2973
+ const { session, loading: loading2, signOut } = useBase316();
2974
+ if (loading2) {
2975
+ return /* @__PURE__ */ jsx13("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
2895
2976
  }
2896
2977
  if (!session) {
2897
- return /* @__PURE__ */ jsx12("div", { className: cls("b316-card", className), style, children: "Not signed in." });
2978
+ return /* @__PURE__ */ jsx13("div", { className: cls("b316-card", className), style, children: "Not signed in." });
2898
2979
  }
2899
2980
  const user = session.user ?? {};
2900
- return /* @__PURE__ */ jsx12("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsxs11("div", { className: "b316-row", children: [
2981
+ return /* @__PURE__ */ jsx13("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsxs11("div", { className: "b316-row", children: [
2901
2982
  /* @__PURE__ */ jsxs11("div", { children: [
2902
- /* @__PURE__ */ jsx12("div", { style: { fontWeight: 600 }, children: user.name || user.email || "Signed in" }),
2903
- user.name && user.email ? /* @__PURE__ */ jsx12("div", { className: "b316-muted", children: user.email }) : null,
2904
- user.emailVerified === false ? /* @__PURE__ */ jsx12("div", { className: "b316-muted", children: "Email not verified" }) : null
2983
+ /* @__PURE__ */ jsx13("div", { style: { fontWeight: 600 }, children: user.name || user.email || "Signed in" }),
2984
+ user.name && user.email ? /* @__PURE__ */ jsx13("div", { className: "b316-muted", children: user.email }) : null,
2985
+ user.emailVerified === false ? /* @__PURE__ */ jsx13("div", { className: "b316-muted", children: "Email not verified" }) : null
2905
2986
  ] }),
2906
- /* @__PURE__ */ jsx12(
2987
+ /* @__PURE__ */ jsx13(
2907
2988
  "button",
2908
2989
  {
2909
2990
  type: "button",
@@ -2917,11 +2998,11 @@ function UserProfile({ className, style }) {
2917
2998
 
2918
2999
  // src/PasskeyManager.tsx
2919
3000
  import { isPasskeySupported as isPasskeySupported2 } from "@base316/sdk";
2920
- import { useCallback as useCallback5, useEffect as useEffect11, useState as useState11 } from "react";
3001
+ import { useCallback as useCallback5, useEffect as useEffect12, useState as useState11 } from "react";
2921
3002
 
2922
3003
  // src/confirm.tsx
2923
- import { useEffect as useEffect10, useRef as useRef3, useState as useState10 } from "react";
2924
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
3004
+ import { useEffect as useEffect11, useRef as useRef4, useState as useState10 } from "react";
3005
+ import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
2925
3006
  var DEFAULT_TIMEOUT_MS = 5e3;
2926
3007
  function ConfirmButton({
2927
3008
  children,
@@ -2932,8 +3013,8 @@ function ConfirmButton({
2932
3013
  timeoutMs = DEFAULT_TIMEOUT_MS
2933
3014
  }) {
2934
3015
  const [armed, setArmed] = useState10(false);
2935
- const confirmRef = useRef3(null);
2936
- useEffect10(() => {
3016
+ const confirmRef = useRef4(null);
3017
+ useEffect11(() => {
2937
3018
  if (!armed) {
2938
3019
  return;
2939
3020
  }
@@ -2942,7 +3023,7 @@ function ConfirmButton({
2942
3023
  return () => clearTimeout(timer);
2943
3024
  }, [armed, timeoutMs]);
2944
3025
  if (!armed) {
2945
- return /* @__PURE__ */ jsx13(
3026
+ return /* @__PURE__ */ jsx14(
2946
3027
  "button",
2947
3028
  {
2948
3029
  type: "button",
@@ -2957,7 +3038,7 @@ function ConfirmButton({
2957
3038
  // No `role="group"`: both buttons already say what they do, and the
2958
3039
  // grouping would only repeat the question a screen reader has just read.
2959
3040
  /* @__PURE__ */ jsxs12("span", { className: "b316-confirm", children: [
2960
- /* @__PURE__ */ jsx13(
3041
+ /* @__PURE__ */ jsx14(
2961
3042
  "button",
2962
3043
  {
2963
3044
  ref: confirmRef,
@@ -2971,7 +3052,7 @@ function ConfirmButton({
2971
3052
  children: confirmLabel
2972
3053
  }
2973
3054
  ),
2974
- /* @__PURE__ */ jsx13(
3055
+ /* @__PURE__ */ jsx14(
2975
3056
  "button",
2976
3057
  {
2977
3058
  type: "button",
@@ -2985,7 +3066,7 @@ function ConfirmButton({
2985
3066
  }
2986
3067
 
2987
3068
  // src/PasskeyManager.tsx
2988
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
3069
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2989
3070
  function PasskeyManager({
2990
3071
  className,
2991
3072
  style,
@@ -3010,7 +3091,7 @@ function PasskeyManager({
3010
3091
  setPasskeys(null);
3011
3092
  }
3012
3093
  }, [client, token]);
3013
- useEffect11(() => {
3094
+ useEffect12(() => {
3014
3095
  if (!isPasskeySupported2()) {
3015
3096
  return;
3016
3097
  }
@@ -3047,17 +3128,17 @@ function PasskeyManager({
3047
3128
  }
3048
3129
  };
3049
3130
  return /* @__PURE__ */ jsxs13("div", { className: cls("b316-card", className), style, children: [
3050
- /* @__PURE__ */ jsx14("div", { style: { fontWeight: 600, marginBottom: 4 }, children: title }),
3051
- /* @__PURE__ */ jsx14("div", { className: "b316-muted", style: { marginBottom: 12 }, children: "Sign in with your fingerprint, face or a security key \u2014 nothing to type and nothing to remember." }),
3052
- passkeys === null ? /* @__PURE__ */ jsx14("div", { className: "b316-muted", children: "Loading\u2026" }) : passkeys.length === 0 ? /* @__PURE__ */ jsx14("div", { className: "b316-muted", children: "No passkeys yet." }) : /* @__PURE__ */ jsx14("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: passkeys.map((passkey) => /* @__PURE__ */ jsxs13("li", { className: "b316-row", style: { padding: "8px 0" }, children: [
3131
+ /* @__PURE__ */ jsx15("div", { style: { fontWeight: 600, marginBottom: 4 }, children: title }),
3132
+ /* @__PURE__ */ jsx15("div", { className: "b316-muted", style: { marginBottom: 12 }, children: "Sign in with your fingerprint, face or a security key \u2014 nothing to type and nothing to remember." }),
3133
+ passkeys === null ? /* @__PURE__ */ jsx15("div", { className: "b316-muted", children: "Loading\u2026" }) : passkeys.length === 0 ? /* @__PURE__ */ jsx15("div", { className: "b316-muted", children: "No passkeys yet." }) : /* @__PURE__ */ jsx15("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: passkeys.map((passkey) => /* @__PURE__ */ jsxs13("li", { className: "b316-row", style: { padding: "8px 0" }, children: [
3053
3134
  /* @__PURE__ */ jsxs13("div", { children: [
3054
- /* @__PURE__ */ jsx14("div", { children: passkey.name || "Passkey" }),
3135
+ /* @__PURE__ */ jsx15("div", { children: passkey.name || "Passkey" }),
3055
3136
  /* @__PURE__ */ jsxs13("div", { className: "b316-muted", children: [
3056
3137
  passkey.lastUsedAt ? `Last used ${formatDate(passkey.lastUsedAt)}` : `Added ${formatDate(passkey.createdAt)}`,
3057
3138
  passkey.backedUp ? "" : " \xB7 this device only"
3058
3139
  ] })
3059
3140
  ] }),
3060
- /* @__PURE__ */ jsx14(
3141
+ /* @__PURE__ */ jsx15(
3061
3142
  ConfirmButton,
3062
3143
  {
3063
3144
  className: "b316-button b316-button-secondary",
@@ -3067,9 +3148,9 @@ function PasskeyManager({
3067
3148
  }
3068
3149
  )
3069
3150
  ] }, passkey.id)) }),
3070
- error ? /* @__PURE__ */ jsx14("div", { className: "b316-error", role: "alert", style: { marginTop: 12 }, children: error }) : null,
3151
+ error ? /* @__PURE__ */ jsx15("div", { className: "b316-error", role: "alert", style: { marginTop: 12 }, children: error }) : null,
3071
3152
  /* @__PURE__ */ jsxs13("div", { className: "b316-row", style: { marginTop: 12, gap: 8 }, children: [
3072
- /* @__PURE__ */ jsx14(
3153
+ /* @__PURE__ */ jsx15(
3073
3154
  "input",
3074
3155
  {
3075
3156
  className: "b316-input",
@@ -3078,7 +3159,7 @@ function PasskeyManager({
3078
3159
  onChange: (event) => setName(event.target.value)
3079
3160
  }
3080
3161
  ),
3081
- /* @__PURE__ */ jsx14("button", { type: "button", className: "b316-button", disabled: busy, onClick: () => void add(), children: busy ? "Waiting\u2026" : "Add a passkey" })
3162
+ /* @__PURE__ */ jsx15("button", { type: "button", className: "b316-button", disabled: busy, onClick: () => void add(), children: busy ? "Waiting\u2026" : "Add a passkey" })
3082
3163
  ] })
3083
3164
  ] });
3084
3165
  }
@@ -3088,8 +3169,8 @@ function formatDate(value) {
3088
3169
  }
3089
3170
 
3090
3171
  // src/ActiveSessions.tsx
3091
- import { useCallback as useCallback6, useEffect as useEffect12, useState as useState12 } from "react";
3092
- import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
3172
+ import { useCallback as useCallback6, useEffect as useEffect13, useState as useState12 } from "react";
3173
+ import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
3093
3174
  function describeDevice(userAgent) {
3094
3175
  if (!userAgent) {
3095
3176
  return null;
@@ -3121,15 +3202,15 @@ function ActiveSessions({ onRevoked, className, style }) {
3121
3202
  setError(cause instanceof Error ? cause.message : "Could not load your sessions.");
3122
3203
  });
3123
3204
  }, [client, token]);
3124
- useEffect12(load, [load]);
3205
+ useEffect13(load, [load]);
3125
3206
  if (!token) {
3126
3207
  return null;
3127
3208
  }
3128
3209
  if (error) {
3129
- return /* @__PURE__ */ jsx15("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx15("div", { className: "b316-error", role: "alert", children: error }) });
3210
+ return /* @__PURE__ */ jsx16("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx16("div", { className: "b316-error", role: "alert", children: error }) });
3130
3211
  }
3131
3212
  if (!sessions) {
3132
- return /* @__PURE__ */ jsx15("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
3213
+ return /* @__PURE__ */ jsx16("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
3133
3214
  }
3134
3215
  async function revokeOthers() {
3135
3216
  setBusy(true);
@@ -3145,15 +3226,15 @@ function ActiveSessions({ onRevoked, className, style }) {
3145
3226
  }
3146
3227
  return /* @__PURE__ */ jsxs14("div", { className: cls("b316-card b316-sessions", className), style, children: [
3147
3228
  /* @__PURE__ */ jsxs14("div", { className: "b316-sessions-head", children: [
3148
- /* @__PURE__ */ jsx15("h3", { className: "b316-sessions-title", children: "Where you are signed in" }),
3149
- sessions.length > 1 ? /* @__PURE__ */ jsx15("button", { type: "button", className: "b316-button", disabled: busy, onClick: revokeOthers, children: busy ? "Ending\u2026" : "Sign out other devices" }) : null
3229
+ /* @__PURE__ */ jsx16("h3", { className: "b316-sessions-title", children: "Where you are signed in" }),
3230
+ sessions.length > 1 ? /* @__PURE__ */ jsx16("button", { type: "button", className: "b316-button", disabled: busy, onClick: revokeOthers, children: busy ? "Ending\u2026" : "Sign out other devices" }) : null
3150
3231
  ] }),
3151
- /* @__PURE__ */ jsx15("ul", { className: "b316-sessions-list", children: sessions.map((session) => /* @__PURE__ */ jsxs14("li", { className: "b316-session", children: [
3232
+ /* @__PURE__ */ jsx16("ul", { className: "b316-sessions-list", children: sessions.map((session) => /* @__PURE__ */ jsxs14("li", { className: "b316-session", children: [
3152
3233
  /* @__PURE__ */ jsxs14("div", { className: "b316-session-device", children: [
3153
3234
  describeDevice(session.userAgent) ?? "Unknown device",
3154
3235
  session.impersonatedBy ? (
3155
3236
  // Worth saying loudly: somebody is acting as this account.
3156
- /* @__PURE__ */ jsx15("span", { className: "b316-chip", children: " Support access" })
3237
+ /* @__PURE__ */ jsx16("span", { className: "b316-chip", children: " Support access" })
3157
3238
  ) : null
3158
3239
  ] }),
3159
3240
  /* @__PURE__ */ jsxs14("div", { className: "b316-muted", children: [
@@ -3162,13 +3243,13 @@ function ActiveSessions({ onRevoked, className, style }) {
3162
3243
  when(session.lastSeenAt)
3163
3244
  ] })
3164
3245
  ] }, session.id)) }),
3165
- sessions.length === 0 ? /* @__PURE__ */ jsx15("div", { className: "b316-muted", children: "No active sessions." }) : null
3246
+ sessions.length === 0 ? /* @__PURE__ */ jsx16("div", { className: "b316-muted", children: "No active sessions." }) : null
3166
3247
  ] });
3167
3248
  }
3168
3249
 
3169
3250
  // src/DeviceApproval.tsx
3170
3251
  import { useState as useState13 } from "react";
3171
- import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
3252
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
3172
3253
  function DeviceApproval({
3173
3254
  userCode = "",
3174
3255
  onDecided,
@@ -3214,8 +3295,8 @@ function DeviceApproval({
3214
3295
  }
3215
3296
  if (decided !== null) {
3216
3297
  return /* @__PURE__ */ jsxs15("div", { className: cls("b316-card b316-device", className), style, children: [
3217
- /* @__PURE__ */ jsx16("h3", { className: "b316-device-title", children: decided ? "You're all set" : "Not approved" }),
3218
- /* @__PURE__ */ jsx16("p", { className: "b316-muted", children: decided ? "You can close this page and go back to your device." : "Nothing was granted. You can close this page." })
3298
+ /* @__PURE__ */ jsx17("h3", { className: "b316-device-title", children: decided ? "You're all set" : "Not approved" }),
3299
+ /* @__PURE__ */ jsx17("p", { className: "b316-muted", children: decided ? "You can close this page and go back to your device." : "Nothing was granted. You can close this page." })
3219
3300
  ] });
3220
3301
  }
3221
3302
  if (request) {
@@ -3228,10 +3309,10 @@ function DeviceApproval({
3228
3309
  request.clientName,
3229
3310
  " is asking to sign in as you."
3230
3311
  ] }),
3231
- request.scopes.length > 0 ? /* @__PURE__ */ jsx16("ul", { className: "b316-device-scopes", children: request.scopes.map((scope) => /* @__PURE__ */ jsx16("li", { children: scope }, scope)) }) : null,
3232
- error ? /* @__PURE__ */ jsx16("div", { className: "b316-error", role: "alert", children: error }) : null,
3312
+ request.scopes.length > 0 ? /* @__PURE__ */ jsx17("ul", { className: "b316-device-scopes", children: request.scopes.map((scope) => /* @__PURE__ */ jsx17("li", { children: scope }, scope)) }) : null,
3313
+ error ? /* @__PURE__ */ jsx17("div", { className: "b316-error", role: "alert", children: error }) : null,
3233
3314
  /* @__PURE__ */ jsxs15("div", { className: "b316-device-actions", children: [
3234
- /* @__PURE__ */ jsx16(
3315
+ /* @__PURE__ */ jsx17(
3235
3316
  "button",
3236
3317
  {
3237
3318
  type: "button",
@@ -3241,7 +3322,7 @@ function DeviceApproval({
3241
3322
  children: busy ? "Approving\u2026" : "Approve"
3242
3323
  }
3243
3324
  ),
3244
- /* @__PURE__ */ jsx16(
3325
+ /* @__PURE__ */ jsx17(
3245
3326
  "button",
3246
3327
  {
3247
3328
  type: "button",
@@ -3255,10 +3336,10 @@ function DeviceApproval({
3255
3336
  ] });
3256
3337
  }
3257
3338
  return /* @__PURE__ */ jsxs15("form", { className: cls("b316-card b316-device", className), style, onSubmit: lookUp, children: [
3258
- /* @__PURE__ */ jsx16("h3", { className: "b316-device-title", children: "Connect your device" }),
3259
- /* @__PURE__ */ jsx16("p", { className: "b316-muted", children: "Enter the code shown on your device." }),
3260
- error ? /* @__PURE__ */ jsx16("div", { className: "b316-error", role: "alert", children: error }) : null,
3261
- /* @__PURE__ */ jsx16(
3339
+ /* @__PURE__ */ jsx17("h3", { className: "b316-device-title", children: "Connect your device" }),
3340
+ /* @__PURE__ */ jsx17("p", { className: "b316-muted", children: "Enter the code shown on your device." }),
3341
+ error ? /* @__PURE__ */ jsx17("div", { className: "b316-error", role: "alert", children: error }) : null,
3342
+ /* @__PURE__ */ jsx17(
3262
3343
  "input",
3263
3344
  {
3264
3345
  className: "b316-input",
@@ -3271,13 +3352,13 @@ function DeviceApproval({
3271
3352
  "aria-label": "Device code"
3272
3353
  }
3273
3354
  ),
3274
- /* @__PURE__ */ jsx16("button", { type: "submit", className: "b316-button", disabled: busy || code.trim().length < 4, children: busy ? "Checking\u2026" : "Continue" })
3355
+ /* @__PURE__ */ jsx17("button", { type: "submit", className: "b316-button", disabled: busy || code.trim().length < 4, children: busy ? "Checking\u2026" : "Continue" })
3275
3356
  ] });
3276
3357
  }
3277
3358
 
3278
3359
  // src/PrivacyControls.tsx
3279
3360
  import { useState as useState14 } from "react";
3280
- import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
3361
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
3281
3362
  function PrivacyControls({
3282
3363
  confirmWord = "DELETE",
3283
3364
  onErased,
@@ -3324,21 +3405,21 @@ function PrivacyControls({
3324
3405
  }
3325
3406
  }
3326
3407
  return /* @__PURE__ */ jsxs16("div", { className: cls("b316-card b316-privacy", className), style, children: [
3327
- /* @__PURE__ */ jsx17("h3", { className: "b316-privacy-title", children: "Your data" }),
3328
- error ? /* @__PURE__ */ jsx17("div", { className: "b316-error", role: "alert", children: error }) : null,
3408
+ /* @__PURE__ */ jsx18("h3", { className: "b316-privacy-title", children: "Your data" }),
3409
+ error ? /* @__PURE__ */ jsx18("div", { className: "b316-error", role: "alert", children: error }) : null,
3329
3410
  /* @__PURE__ */ jsxs16("div", { className: "b316-privacy-row", children: [
3330
3411
  /* @__PURE__ */ jsxs16("div", { children: [
3331
- /* @__PURE__ */ jsx17("p", { children: "Download a copy" }),
3332
- /* @__PURE__ */ jsx17("p", { className: "b316-muted", children: "Everything we hold about you, as a file. Passwords and security keys are not included \u2014 they are what protect the account rather than anything you can use." })
3412
+ /* @__PURE__ */ jsx18("p", { children: "Download a copy" }),
3413
+ /* @__PURE__ */ jsx18("p", { className: "b316-muted", children: "Everything we hold about you, as a file. Passwords and security keys are not included \u2014 they are what protect the account rather than anything you can use." })
3333
3414
  ] }),
3334
- /* @__PURE__ */ jsx17("button", { type: "button", className: "b316-button-quiet", disabled: busy, onClick: download, children: busy ? "Preparing\u2026" : "Download" })
3415
+ /* @__PURE__ */ jsx18("button", { type: "button", className: "b316-button-quiet", disabled: busy, onClick: download, children: busy ? "Preparing\u2026" : "Download" })
3335
3416
  ] }),
3336
3417
  /* @__PURE__ */ jsxs16("div", { className: "b316-privacy-row", children: [
3337
3418
  /* @__PURE__ */ jsxs16("div", { children: [
3338
- /* @__PURE__ */ jsx17("p", { children: "Delete your account" }),
3339
- /* @__PURE__ */ jsx17("p", { className: "b316-muted", children: "Permanent. Invoices already raised are kept, because the law requires it; everything that identifies you is removed from them." })
3419
+ /* @__PURE__ */ jsx18("p", { children: "Delete your account" }),
3420
+ /* @__PURE__ */ jsx18("p", { className: "b316-muted", children: "Permanent. Invoices already raised are kept, because the law requires it; everything that identifies you is removed from them." })
3340
3421
  ] }),
3341
- confirming ? null : /* @__PURE__ */ jsx17(
3422
+ confirming ? null : /* @__PURE__ */ jsx18(
3342
3423
  "button",
3343
3424
  {
3344
3425
  type: "button",
@@ -3355,7 +3436,7 @@ function PrivacyControls({
3355
3436
  confirmWord,
3356
3437
  " to confirm"
3357
3438
  ] }),
3358
- /* @__PURE__ */ jsx17(
3439
+ /* @__PURE__ */ jsx18(
3359
3440
  "input",
3360
3441
  {
3361
3442
  id: "b316-privacy-confirm",
@@ -3366,7 +3447,7 @@ function PrivacyControls({
3366
3447
  }
3367
3448
  ),
3368
3449
  /* @__PURE__ */ jsxs16("div", { className: "b316-privacy-actions", children: [
3369
- /* @__PURE__ */ jsx17(
3450
+ /* @__PURE__ */ jsx18(
3370
3451
  "button",
3371
3452
  {
3372
3453
  type: "button",
@@ -3378,7 +3459,7 @@ function PrivacyControls({
3378
3459
  children: "Cancel"
3379
3460
  }
3380
3461
  ),
3381
- /* @__PURE__ */ jsx17(
3462
+ /* @__PURE__ */ jsx18(
3382
3463
  "button",
3383
3464
  {
3384
3465
  type: "button",
@@ -3399,7 +3480,7 @@ import { useState as useState15 } from "react";
3399
3480
  // src/QrCode.tsx
3400
3481
  import qrcode from "qrcode-generator";
3401
3482
  import { useMemo as useMemo2 } from "react";
3402
- import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
3483
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
3403
3484
  var QUIET_ZONE = 4;
3404
3485
  function utf8Binary(value) {
3405
3486
  let binary = "";
@@ -3438,15 +3519,15 @@ function QrCode({ value, label, size = 180, className }) {
3438
3519
  shapeRendering: "crispEdges",
3439
3520
  xmlns: "http://www.w3.org/2000/svg",
3440
3521
  children: [
3441
- /* @__PURE__ */ jsx18("rect", { width: extent, height: extent, fill: "#ffffff" }),
3442
- /* @__PURE__ */ jsx18("path", { d: path, fill: "#000000" })
3522
+ /* @__PURE__ */ jsx19("rect", { width: extent, height: extent, fill: "#ffffff" }),
3523
+ /* @__PURE__ */ jsx19("path", { d: path, fill: "#000000" })
3443
3524
  ]
3444
3525
  }
3445
3526
  );
3446
3527
  }
3447
3528
 
3448
3529
  // src/TwoFactorManager.tsx
3449
- import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
3530
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
3450
3531
  function groupKey(secret) {
3451
3532
  return secret.replace(/\s+/g, "").replace(/(.{4})(?=.)/g, "$1 ");
3452
3533
  }
@@ -3543,16 +3624,16 @@ function TwoFactorManager({
3543
3624
  }
3544
3625
  }
3545
3626
  return /* @__PURE__ */ jsxs18("div", { className: cls("b316-card b316-mfa", className), style, children: [
3546
- /* @__PURE__ */ jsx19("h3", { className: "b316-mfa-title", children: "Two-factor authentication" }),
3547
- error ? /* @__PURE__ */ jsx19("div", { className: "b316-error", role: "alert", children: error }) : null,
3627
+ /* @__PURE__ */ jsx20("h3", { className: "b316-mfa-title", children: "Two-factor authentication" }),
3628
+ error ? /* @__PURE__ */ jsx20("div", { className: "b316-error", role: "alert", children: error }) : null,
3548
3629
  stage.name === "saved" ? /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-codes", children: [
3549
- /* @__PURE__ */ jsx19("p", { children: "Save these recovery codes somewhere safe. Each one signs you in once if you lose your authenticator, and they are not shown again." }),
3550
- /* @__PURE__ */ jsx19("ul", { className: "b316-mfa-code-list", children: stage.recoveryCodes.map((recovery) => /* @__PURE__ */ jsx19("li", { children: /* @__PURE__ */ jsx19("code", { children: recovery }) }, recovery)) }),
3551
- /* @__PURE__ */ jsx19("button", { type: "button", className: "b316-button", onClick: () => setStage({ name: "idle" }), children: "I have saved them" })
3630
+ /* @__PURE__ */ jsx20("p", { children: "Save these recovery codes somewhere safe. Each one signs you in once if you lose your authenticator, and they are not shown again." }),
3631
+ /* @__PURE__ */ jsx20("ul", { className: "b316-mfa-code-list", children: stage.recoveryCodes.map((recovery) => /* @__PURE__ */ jsx20("li", { children: /* @__PURE__ */ jsx20("code", { children: recovery }) }, recovery)) }),
3632
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "b316-button", onClick: () => setStage({ name: "idle" }), children: "I have saved them" })
3552
3633
  ] }) : stage.name === "smsNumber" ? /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-enrol", children: [
3553
- /* @__PURE__ */ jsx19("p", { children: "We will text a code to this number now, and each time you sign in." }),
3554
- /* @__PURE__ */ jsx19("label", { className: "b316-label", htmlFor: "b316-mfa-phone", children: "Mobile number" }),
3555
- /* @__PURE__ */ jsx19(
3634
+ /* @__PURE__ */ jsx20("p", { children: "We will text a code to this number now, and each time you sign in." }),
3635
+ /* @__PURE__ */ jsx20("label", { className: "b316-label", htmlFor: "b316-mfa-phone", children: "Mobile number" }),
3636
+ /* @__PURE__ */ jsx20(
3556
3637
  "input",
3557
3638
  {
3558
3639
  id: "b316-mfa-phone",
@@ -3565,7 +3646,7 @@ function TwoFactorManager({
3565
3646
  }
3566
3647
  ),
3567
3648
  /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-actions", children: [
3568
- /* @__PURE__ */ jsx19(
3649
+ /* @__PURE__ */ jsx20(
3569
3650
  "button",
3570
3651
  {
3571
3652
  type: "button",
@@ -3574,7 +3655,7 @@ function TwoFactorManager({
3574
3655
  children: "Cancel"
3575
3656
  }
3576
3657
  ),
3577
- /* @__PURE__ */ jsx19("button", { type: "button", className: "b316-button", disabled: busy, onClick: beginSms, children: busy ? "Sending\u2026" : "Send code" })
3658
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "b316-button", disabled: busy, onClick: beginSms, children: busy ? "Sending\u2026" : "Send code" })
3578
3659
  ] })
3579
3660
  ] }) : stage.name === "enrollingEmail" ? /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-enrol", children: [
3580
3661
  /* @__PURE__ */ jsxs18("p", { children: [
@@ -3582,8 +3663,8 @@ function TwoFactorManager({
3582
3663
  stage.destinationHint,
3583
3664
  ". Enter it below to turn this on."
3584
3665
  ] }),
3585
- /* @__PURE__ */ jsx19("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3586
- /* @__PURE__ */ jsx19(
3666
+ /* @__PURE__ */ jsx20("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3667
+ /* @__PURE__ */ jsx20(
3587
3668
  "input",
3588
3669
  {
3589
3670
  id: "b316-mfa-code",
@@ -3595,7 +3676,7 @@ function TwoFactorManager({
3595
3676
  }
3596
3677
  ),
3597
3678
  /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-actions", children: [
3598
- /* @__PURE__ */ jsx19(
3679
+ /* @__PURE__ */ jsx20(
3599
3680
  "button",
3600
3681
  {
3601
3682
  type: "button",
@@ -3604,7 +3685,7 @@ function TwoFactorManager({
3604
3685
  children: "Cancel"
3605
3686
  }
3606
3687
  ),
3607
- /* @__PURE__ */ jsx19(
3688
+ /* @__PURE__ */ jsx20(
3608
3689
  "button",
3609
3690
  {
3610
3691
  type: "button",
@@ -3616,8 +3697,8 @@ function TwoFactorManager({
3616
3697
  )
3617
3698
  ] })
3618
3699
  ] }) : stage.name === "enrolling" ? /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-enrol", children: [
3619
- /* @__PURE__ */ jsx19("p", { children: "Scan this with your authenticator app (Google Authenticator, 1Password, Authy\u2026), then enter the six-digit code it shows." }),
3620
- /* @__PURE__ */ jsx19(
3700
+ /* @__PURE__ */ jsx20("p", { children: "Scan this with your authenticator app (Google Authenticator, 1Password, Authy\u2026), then enter the six-digit code it shows." }),
3701
+ /* @__PURE__ */ jsx20(
3621
3702
  QrCode,
3622
3703
  {
3623
3704
  className: "b316-mfa-qr",
@@ -3626,12 +3707,12 @@ function TwoFactorManager({
3626
3707
  }
3627
3708
  ),
3628
3709
  /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-secret", children: [
3629
- /* @__PURE__ */ jsx19("span", { className: "b316-label", id: "b316-mfa-manual-key", children: "Can't scan? Enter this key" }),
3630
- /* @__PURE__ */ jsx19("code", { "aria-labelledby": "b316-mfa-manual-key", children: groupKey(stage.secret) })
3710
+ /* @__PURE__ */ jsx20("span", { className: "b316-label", id: "b316-mfa-manual-key", children: "Can't scan? Enter this key" }),
3711
+ /* @__PURE__ */ jsx20("code", { "aria-labelledby": "b316-mfa-manual-key", children: groupKey(stage.secret) })
3631
3712
  ] }),
3632
- /* @__PURE__ */ jsx19("a", { className: "b316-mfa-uri", href: stage.uri, children: "Open in an authenticator app" }),
3633
- /* @__PURE__ */ jsx19("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3634
- /* @__PURE__ */ jsx19(
3713
+ /* @__PURE__ */ jsx20("a", { className: "b316-mfa-uri", href: stage.uri, children: "Open in an authenticator app" }),
3714
+ /* @__PURE__ */ jsx20("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3715
+ /* @__PURE__ */ jsx20(
3635
3716
  "input",
3636
3717
  {
3637
3718
  id: "b316-mfa-code",
@@ -3643,7 +3724,7 @@ function TwoFactorManager({
3643
3724
  }
3644
3725
  ),
3645
3726
  /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-actions", children: [
3646
- /* @__PURE__ */ jsx19(
3727
+ /* @__PURE__ */ jsx20(
3647
3728
  "button",
3648
3729
  {
3649
3730
  type: "button",
@@ -3652,7 +3733,7 @@ function TwoFactorManager({
3652
3733
  children: "Cancel"
3653
3734
  }
3654
3735
  ),
3655
- /* @__PURE__ */ jsx19(
3736
+ /* @__PURE__ */ jsx20(
3656
3737
  "button",
3657
3738
  {
3658
3739
  type: "button",
@@ -3664,8 +3745,8 @@ function TwoFactorManager({
3664
3745
  )
3665
3746
  ] })
3666
3747
  ] }) : on ? /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-on", children: [
3667
- /* @__PURE__ */ jsx19("p", { className: "b316-muted", children: "On. You will be asked for a code when you sign in." }),
3668
- /* @__PURE__ */ jsx19(
3748
+ /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "On. You will be asked for a code when you sign in." }),
3749
+ /* @__PURE__ */ jsx20(
3669
3750
  ConfirmButton,
3670
3751
  {
3671
3752
  className: "b316-button-quiet b316-danger",
@@ -3676,10 +3757,10 @@ function TwoFactorManager({
3676
3757
  }
3677
3758
  )
3678
3759
  ] }) : /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-off", children: [
3679
- /* @__PURE__ */ jsx19("p", { className: "b316-muted", children: "Off. Turning it on means a code as well as your password, every time you sign in." }),
3760
+ /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "Off. Turning it on means a code as well as your password, every time you sign in." }),
3680
3761
  /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-actions", children: [
3681
- /* @__PURE__ */ jsx19("button", { type: "button", className: "b316-button", disabled: busy, onClick: begin, children: busy ? "Starting\u2026" : "Use an authenticator app" }),
3682
- /* @__PURE__ */ jsx19(
3762
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "b316-button", disabled: busy, onClick: begin, children: busy ? "Starting\u2026" : "Use an authenticator app" }),
3763
+ /* @__PURE__ */ jsx20(
3683
3764
  "button",
3684
3765
  {
3685
3766
  type: "button",
@@ -3689,7 +3770,7 @@ function TwoFactorManager({
3689
3770
  children: "Email me a code"
3690
3771
  }
3691
3772
  ),
3692
- allowSms ? /* @__PURE__ */ jsx19(
3773
+ allowSms ? /* @__PURE__ */ jsx20(
3693
3774
  "button",
3694
3775
  {
3695
3776
  type: "button",
@@ -3706,7 +3787,7 @@ function TwoFactorManager({
3706
3787
 
3707
3788
  // src/ForgotPassword.tsx
3708
3789
  import { useState as useState16 } from "react";
3709
- import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
3790
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
3710
3791
  function ForgotPassword({ onSent, signInUrl, className, style }) {
3711
3792
  const { client } = useBase316();
3712
3793
  const [email, setEmail] = useState16("");
@@ -3729,21 +3810,21 @@ function ForgotPassword({ onSent, signInUrl, className, style }) {
3729
3810
  }
3730
3811
  if (sent) {
3731
3812
  return /* @__PURE__ */ jsxs19("div", { className: cls("b316-card", className), style, children: [
3732
- /* @__PURE__ */ jsx20("h3", { className: "b316-form-title", children: "Check your email" }),
3813
+ /* @__PURE__ */ jsx21("h3", { className: "b316-form-title", children: "Check your email" }),
3733
3814
  /* @__PURE__ */ jsxs19("p", { className: "b316-muted", children: [
3734
3815
  "If there is an account for ",
3735
3816
  email.trim(),
3736
3817
  ", a link to set a new password is on its way."
3737
3818
  ] }),
3738
- signInUrl ? /* @__PURE__ */ jsx20("a", { className: "b316-button-link", href: signInUrl, children: "Back to sign in" }) : null
3819
+ signInUrl ? /* @__PURE__ */ jsx21("a", { className: "b316-button-link", href: signInUrl, children: "Back to sign in" }) : null
3739
3820
  ] });
3740
3821
  }
3741
3822
  return /* @__PURE__ */ jsxs19("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
3742
- /* @__PURE__ */ jsx20("h3", { className: "b316-form-title", children: "Reset your password" }),
3743
- error ? /* @__PURE__ */ jsx20("div", { className: "b316-error", role: "alert", children: error }) : null,
3823
+ /* @__PURE__ */ jsx21("h3", { className: "b316-form-title", children: "Reset your password" }),
3824
+ error ? /* @__PURE__ */ jsx21("div", { className: "b316-error", role: "alert", children: error }) : null,
3744
3825
  /* @__PURE__ */ jsxs19("div", { className: "b316-field", children: [
3745
- /* @__PURE__ */ jsx20("label", { className: "b316-label", htmlFor: "b316-forgot-email", children: "Email" }),
3746
- /* @__PURE__ */ jsx20(
3826
+ /* @__PURE__ */ jsx21("label", { className: "b316-label", htmlFor: "b316-forgot-email", children: "Email" }),
3827
+ /* @__PURE__ */ jsx21(
3747
3828
  "input",
3748
3829
  {
3749
3830
  id: "b316-forgot-email",
@@ -3756,14 +3837,14 @@ function ForgotPassword({ onSent, signInUrl, className, style }) {
3756
3837
  }
3757
3838
  )
3758
3839
  ] }),
3759
- /* @__PURE__ */ jsx20("button", { type: "submit", className: "b316-button", disabled: busy || !email, children: busy ? "Sending\u2026" : "Send reset link" }),
3760
- signInUrl ? /* @__PURE__ */ jsx20("a", { className: "b316-button-link", href: signInUrl, children: "Back to sign in" }) : null
3840
+ /* @__PURE__ */ jsx21("button", { type: "submit", className: "b316-button", disabled: busy || !email, children: busy ? "Sending\u2026" : "Send reset link" }),
3841
+ signInUrl ? /* @__PURE__ */ jsx21("a", { className: "b316-button-link", href: signInUrl, children: "Back to sign in" }) : null
3761
3842
  ] });
3762
3843
  }
3763
3844
 
3764
3845
  // src/ResetPassword.tsx
3765
- import { useEffect as useEffect13, useState as useState17 } from "react";
3766
- import { jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
3846
+ import { useEffect as useEffect14, useState as useState17 } from "react";
3847
+ import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
3767
3848
  function ResetPassword({
3768
3849
  token: supplied,
3769
3850
  onReset,
@@ -3778,7 +3859,7 @@ function ResetPassword({
3778
3859
  const [done, setDone] = useState17(false);
3779
3860
  const [busy, setBusy] = useState17(false);
3780
3861
  const [error, setError] = useState17(null);
3781
- useEffect13(() => {
3862
+ useEffect14(() => {
3782
3863
  if (supplied || typeof window === "undefined") {
3783
3864
  return;
3784
3865
  }
@@ -3814,23 +3895,23 @@ function ResetPassword({
3814
3895
  }
3815
3896
  if (done) {
3816
3897
  return /* @__PURE__ */ jsxs20("div", { className: cls("b316-card", className), style, children: [
3817
- /* @__PURE__ */ jsx21("h3", { className: "b316-form-title", children: "Password changed" }),
3818
- /* @__PURE__ */ jsx21("p", { className: "b316-muted", children: "You can sign in with your new password." }),
3819
- signInUrl ? /* @__PURE__ */ jsx21("a", { className: "b316-button-link", href: signInUrl, children: "Sign in" }) : null
3898
+ /* @__PURE__ */ jsx22("h3", { className: "b316-form-title", children: "Password changed" }),
3899
+ /* @__PURE__ */ jsx22("p", { className: "b316-muted", children: "You can sign in with your new password." }),
3900
+ signInUrl ? /* @__PURE__ */ jsx22("a", { className: "b316-button-link", href: signInUrl, children: "Sign in" }) : null
3820
3901
  ] });
3821
3902
  }
3822
3903
  if (!token) {
3823
3904
  return /* @__PURE__ */ jsxs20("div", { className: cls("b316-card", className), style, children: [
3824
- /* @__PURE__ */ jsx21("h3", { className: "b316-form-title", children: "Nothing to reset" }),
3825
- /* @__PURE__ */ jsx21("p", { className: "b316-muted", children: "This page needs the link from your email. Request a new one if yours has expired." })
3905
+ /* @__PURE__ */ jsx22("h3", { className: "b316-form-title", children: "Nothing to reset" }),
3906
+ /* @__PURE__ */ jsx22("p", { className: "b316-muted", children: "This page needs the link from your email. Request a new one if yours has expired." })
3826
3907
  ] });
3827
3908
  }
3828
3909
  return /* @__PURE__ */ jsxs20("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
3829
- /* @__PURE__ */ jsx21("h3", { className: "b316-form-title", children: "Choose a new password" }),
3830
- error ? /* @__PURE__ */ jsx21("div", { className: "b316-error", role: "alert", children: error }) : null,
3910
+ /* @__PURE__ */ jsx22("h3", { className: "b316-form-title", children: "Choose a new password" }),
3911
+ error ? /* @__PURE__ */ jsx22("div", { className: "b316-error", role: "alert", children: error }) : null,
3831
3912
  /* @__PURE__ */ jsxs20("div", { className: "b316-field", children: [
3832
- /* @__PURE__ */ jsx21("label", { className: "b316-label", htmlFor: "b316-reset-password", children: "New password" }),
3833
- /* @__PURE__ */ jsx21(
3913
+ /* @__PURE__ */ jsx22("label", { className: "b316-label", htmlFor: "b316-reset-password", children: "New password" }),
3914
+ /* @__PURE__ */ jsx22(
3834
3915
  "input",
3835
3916
  {
3836
3917
  id: "b316-reset-password",
@@ -3844,8 +3925,8 @@ function ResetPassword({
3844
3925
  )
3845
3926
  ] }),
3846
3927
  /* @__PURE__ */ jsxs20("div", { className: "b316-field", children: [
3847
- /* @__PURE__ */ jsx21("label", { className: "b316-label", htmlFor: "b316-reset-confirm", children: "Repeat it" }),
3848
- /* @__PURE__ */ jsx21(
3928
+ /* @__PURE__ */ jsx22("label", { className: "b316-label", htmlFor: "b316-reset-confirm", children: "Repeat it" }),
3929
+ /* @__PURE__ */ jsx22(
3849
3930
  "input",
3850
3931
  {
3851
3932
  id: "b316-reset-confirm",
@@ -3858,13 +3939,13 @@ function ResetPassword({
3858
3939
  }
3859
3940
  )
3860
3941
  ] }),
3861
- /* @__PURE__ */ jsx21("button", { type: "submit", className: "b316-button", disabled: busy || !password, children: busy ? "Saving\u2026" : "Set password" })
3942
+ /* @__PURE__ */ jsx22("button", { type: "submit", className: "b316-button", disabled: busy || !password, children: busy ? "Saving\u2026" : "Set password" })
3862
3943
  ] });
3863
3944
  }
3864
3945
 
3865
3946
  // src/VerifyEmail.tsx
3866
- import { useEffect as useEffect14, useRef as useRef4, useState as useState18 } from "react";
3867
- import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
3947
+ import { useEffect as useEffect15, useRef as useRef5, useState as useState18 } from "react";
3948
+ import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
3868
3949
  function VerifyEmail({
3869
3950
  token: supplied,
3870
3951
  onVerified,
@@ -3874,8 +3955,8 @@ function VerifyEmail({
3874
3955
  }) {
3875
3956
  const { client } = useBase316();
3876
3957
  const [state, setState] = useState18("waiting");
3877
- const spent = useRef4(false);
3878
- useEffect14(() => {
3958
+ const spent = useRef5(false);
3959
+ useEffect15(() => {
3879
3960
  if (spent.current) {
3880
3961
  return;
3881
3962
  }
@@ -3901,22 +3982,22 @@ function VerifyEmail({
3901
3982
  setState("failed");
3902
3983
  });
3903
3984
  }, [client, supplied, onVerified]);
3904
- return /* @__PURE__ */ jsx22("div", { className: cls("b316-card", className), style, children: state === "verified" ? /* @__PURE__ */ jsxs21(Fragment7, { children: [
3905
- /* @__PURE__ */ jsx22("h3", { className: "b316-form-title", children: "Email confirmed" }),
3906
- /* @__PURE__ */ jsx22("p", { className: "b316-muted", children: "Thanks \u2014 your address is verified." }),
3907
- continueUrl ? /* @__PURE__ */ jsx22("a", { className: "b316-button-link", href: continueUrl, children: "Continue" }) : null
3985
+ return /* @__PURE__ */ jsx23("div", { className: cls("b316-card", className), style, children: state === "verified" ? /* @__PURE__ */ jsxs21(Fragment7, { children: [
3986
+ /* @__PURE__ */ jsx23("h3", { className: "b316-form-title", children: "Email confirmed" }),
3987
+ /* @__PURE__ */ jsx23("p", { className: "b316-muted", children: "Thanks \u2014 your address is verified." }),
3988
+ continueUrl ? /* @__PURE__ */ jsx23("a", { className: "b316-button-link", href: continueUrl, children: "Continue" }) : null
3908
3989
  ] }) : state === "failed" ? /* @__PURE__ */ jsxs21(Fragment7, { children: [
3909
- /* @__PURE__ */ jsx22("h3", { className: "b316-form-title", children: "That link did not work" }),
3910
- /* @__PURE__ */ jsx22("p", { className: "b316-muted", children: "It may have expired or already been used. Ask for a new one and try again." })
3990
+ /* @__PURE__ */ jsx23("h3", { className: "b316-form-title", children: "That link did not work" }),
3991
+ /* @__PURE__ */ jsx23("p", { className: "b316-muted", children: "It may have expired or already been used. Ask for a new one and try again." })
3911
3992
  ] }) : state === "missing" ? /* @__PURE__ */ jsxs21(Fragment7, { children: [
3912
- /* @__PURE__ */ jsx22("h3", { className: "b316-form-title", children: "Nothing to confirm" }),
3913
- /* @__PURE__ */ jsx22("p", { className: "b316-muted", children: "This page needs the link from your email." })
3914
- ] }) : /* @__PURE__ */ jsx22("p", { className: "b316-muted", children: "Confirming your email\u2026" }) });
3993
+ /* @__PURE__ */ jsx23("h3", { className: "b316-form-title", children: "Nothing to confirm" }),
3994
+ /* @__PURE__ */ jsx23("p", { className: "b316-muted", children: "This page needs the link from your email." })
3995
+ ] }) : /* @__PURE__ */ jsx23("p", { className: "b316-muted", children: "Confirming your email\u2026" }) });
3915
3996
  }
3916
3997
 
3917
3998
  // src/TeamMembers.tsx
3918
- import { useCallback as useCallback7, useEffect as useEffect15, useState as useState19 } from "react";
3919
- import { Fragment as Fragment8, jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
3999
+ import { useCallback as useCallback7, useEffect as useEffect16, useState as useState19 } from "react";
4000
+ import { Fragment as Fragment8, jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
3920
4001
  function TeamMembers({
3921
4002
  organizationId,
3922
4003
  onInvited,
@@ -3943,8 +4024,8 @@ function TeamMembers({
3943
4024
  (cause) => setError(cause instanceof Error ? cause.message : "Could not load your teams.")
3944
4025
  );
3945
4026
  }, [client, token]);
3946
- useEffect15(load, [load]);
3947
- useEffect15(() => {
4027
+ useEffect16(load, [load]);
4028
+ useEffect16(() => {
3948
4029
  if (!token || !chosen) {
3949
4030
  return;
3950
4031
  }
@@ -3975,10 +4056,10 @@ function TeamMembers({
3975
4056
  return null;
3976
4057
  }
3977
4058
  if (!teams) {
3978
- return /* @__PURE__ */ jsx23("div", { className: cls("b316-card", className), style, children: error ?? "Loading\u2026" });
4059
+ return /* @__PURE__ */ jsx24("div", { className: cls("b316-card", className), style, children: error ?? "Loading\u2026" });
3979
4060
  }
3980
4061
  if (!chosen) {
3981
- return /* @__PURE__ */ jsx23("div", { className: cls("b316-card", className), style, children: teams.length === 0 ? "You are not in a team yet." : "You are in more than one team. Name which with the organizationId prop." });
4062
+ return /* @__PURE__ */ jsx24("div", { className: cls("b316-card", className), style, children: teams.length === 0 ? "You are not in a team yet." : "You are in more than one team. Name which with the organizationId prop." });
3982
4063
  }
3983
4064
  const canManage = invitations !== null;
3984
4065
  async function invite(event) {
@@ -4029,7 +4110,7 @@ function TeamMembers({
4029
4110
  }
4030
4111
  }
4031
4112
  return /* @__PURE__ */ jsxs22("div", { className: cls("b316-card b316-team", className), style, children: [
4032
- /* @__PURE__ */ jsx23("h3", { className: "b316-team-title", children: team?.name ?? "Team" }),
4113
+ /* @__PURE__ */ jsx24("h3", { className: "b316-team-title", children: team?.name ?? "Team" }),
4033
4114
  team?.inherited ? (
4034
4115
  // Not a member of this team, so not in the list below and with nothing
4035
4116
  // to leave: access comes from the team that manages it, and ends there.
@@ -4040,18 +4121,18 @@ function TeamMembers({
4040
4121
  "."
4041
4122
  ] })
4042
4123
  ) : null,
4043
- error ? /* @__PURE__ */ jsx23("div", { className: "b316-error", role: "alert", children: error }) : null,
4044
- /* @__PURE__ */ jsx23("ul", { className: "b316-team-list", children: (members ?? []).map((member) => /* @__PURE__ */ jsxs22("li", { className: "b316-team-member", children: [
4124
+ error ? /* @__PURE__ */ jsx24("div", { className: "b316-error", role: "alert", children: error }) : null,
4125
+ /* @__PURE__ */ jsx24("ul", { className: "b316-team-list", children: (members ?? []).map((member) => /* @__PURE__ */ jsxs22("li", { className: "b316-team-member", children: [
4045
4126
  /* @__PURE__ */ jsxs22("div", { children: [
4046
- /* @__PURE__ */ jsx23("div", { children: member.user.name ?? member.user.email ?? "Someone" }),
4127
+ /* @__PURE__ */ jsx24("div", { children: member.user.name ?? member.user.email ?? "Someone" }),
4047
4128
  /* @__PURE__ */ jsxs22("div", { className: "b316-muted", children: [
4048
4129
  member.user.email,
4049
4130
  member.user.id === session?.userId ? " \xB7 you" : ""
4050
4131
  ] })
4051
4132
  ] }),
4052
4133
  /* @__PURE__ */ jsxs22("div", { className: "b316-team-member-side", children: [
4053
- /* @__PURE__ */ jsx23("span", { className: "b316-chip", children: member.role.name }),
4054
- canManage || member.user.id === session?.userId ? /* @__PURE__ */ jsx23(
4134
+ /* @__PURE__ */ jsx24("span", { className: "b316-chip", children: member.role.name }),
4135
+ canManage || member.user.id === session?.userId ? /* @__PURE__ */ jsx24(
4055
4136
  ConfirmButton,
4056
4137
  {
4057
4138
  className: "b316-button-quiet b316-danger",
@@ -4064,10 +4145,10 @@ function TeamMembers({
4064
4145
  ] })
4065
4146
  ] }, member.id)) }),
4066
4147
  canManage && (invitations ?? []).length > 0 ? /* @__PURE__ */ jsxs22(Fragment8, { children: [
4067
- /* @__PURE__ */ jsx23("h4", { className: "b316-team-subtitle", children: "Invited" }),
4068
- /* @__PURE__ */ jsx23("ul", { className: "b316-team-list", children: (invitations ?? []).map((invitation) => /* @__PURE__ */ jsxs22("li", { className: "b316-team-member", children: [
4148
+ /* @__PURE__ */ jsx24("h4", { className: "b316-team-subtitle", children: "Invited" }),
4149
+ /* @__PURE__ */ jsx24("ul", { className: "b316-team-list", children: (invitations ?? []).map((invitation) => /* @__PURE__ */ jsxs22("li", { className: "b316-team-member", children: [
4069
4150
  /* @__PURE__ */ jsxs22("div", { children: [
4070
- /* @__PURE__ */ jsx23("div", { children: invitation.email }),
4151
+ /* @__PURE__ */ jsx24("div", { children: invitation.email }),
4071
4152
  /* @__PURE__ */ jsxs22("div", { className: "b316-muted", children: [
4072
4153
  invitation.role.name,
4073
4154
  " \xB7 expires",
@@ -4075,7 +4156,7 @@ function TeamMembers({
4075
4156
  new Date(invitation.expiresAt).toLocaleDateString()
4076
4157
  ] })
4077
4158
  ] }),
4078
- /* @__PURE__ */ jsx23(
4159
+ /* @__PURE__ */ jsx24(
4079
4160
  "button",
4080
4161
  {
4081
4162
  type: "button",
@@ -4087,9 +4168,9 @@ function TeamMembers({
4087
4168
  ] }, invitation.id)) })
4088
4169
  ] }) : null,
4089
4170
  canManage ? /* @__PURE__ */ jsxs22("form", { className: "b316-team-invite", onSubmit: invite, children: [
4090
- /* @__PURE__ */ jsx23("label", { className: "b316-label", htmlFor: "b316-invite-email", children: "Invite by email" }),
4171
+ /* @__PURE__ */ jsx24("label", { className: "b316-label", htmlFor: "b316-invite-email", children: "Invite by email" }),
4091
4172
  /* @__PURE__ */ jsxs22("div", { className: "b316-team-invite-row", children: [
4092
- /* @__PURE__ */ jsx23(
4173
+ /* @__PURE__ */ jsx24(
4093
4174
  "input",
4094
4175
  {
4095
4176
  id: "b316-invite-email",
@@ -4101,19 +4182,19 @@ function TeamMembers({
4101
4182
  onChange: (event) => setEmail(event.target.value)
4102
4183
  }
4103
4184
  ),
4104
- /* @__PURE__ */ jsx23("button", { type: "submit", className: "b316-button", disabled: busy || !email, children: busy ? "Sending\u2026" : "Invite" })
4185
+ /* @__PURE__ */ jsx24("button", { type: "submit", className: "b316-button", disabled: busy || !email, children: busy ? "Sending\u2026" : "Invite" })
4105
4186
  ] })
4106
4187
  ] }) : null,
4107
4188
  copied ? /* @__PURE__ */ jsxs22("div", { className: "b316-team-link", children: [
4108
- /* @__PURE__ */ jsx23("div", { className: "b316-muted", children: "Send them this link. It is shown once and cannot be fetched again." }),
4109
- /* @__PURE__ */ jsx23("code", { children: copied })
4189
+ /* @__PURE__ */ jsx24("div", { className: "b316-muted", children: "Send them this link. It is shown once and cannot be fetched again." }),
4190
+ /* @__PURE__ */ jsx24("code", { children: copied })
4110
4191
  ] }) : null
4111
4192
  ] });
4112
4193
  }
4113
4194
 
4114
4195
  // src/AcceptInvitation.tsx
4115
- import { useEffect as useEffect16, useState as useState20 } from "react";
4116
- import { Fragment as Fragment9, jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
4196
+ import { useEffect as useEffect17, useState as useState20 } from "react";
4197
+ import { Fragment as Fragment9, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
4117
4198
  function signUpUrlWithInvitation(url, token) {
4118
4199
  const [beforeHash, ...hash] = url.split("#");
4119
4200
  const base = beforeHash ?? "";
@@ -4137,13 +4218,13 @@ function AcceptInvitation({
4137
4218
  const [state, setState] = useState20("loading");
4138
4219
  const [error, setError] = useState20(null);
4139
4220
  const [busy, setBusy] = useState20(false);
4140
- useEffect16(() => {
4221
+ useEffect17(() => {
4141
4222
  if (supplied || typeof window === "undefined") {
4142
4223
  return;
4143
4224
  }
4144
4225
  setInvitationToken(new URL(window.location.href).searchParams.get("invitation"));
4145
4226
  }, [supplied]);
4146
- useEffect16(() => {
4227
+ useEffect17(() => {
4147
4228
  if (!invitationToken) {
4148
4229
  setState(supplied === void 0 ? "loading" : "invalid");
4149
4230
  return;
@@ -4180,16 +4261,16 @@ function AcceptInvitation({
4180
4261
  }
4181
4262
  }
4182
4263
  if (state === "loading") {
4183
- return /* @__PURE__ */ jsx24("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
4264
+ return /* @__PURE__ */ jsx25("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
4184
4265
  }
4185
4266
  if (state === "invalid") {
4186
4267
  return /* @__PURE__ */ jsxs23("div", { className: cls("b316-card", className), style, children: [
4187
- /* @__PURE__ */ jsx24("h3", { className: "b316-form-title", children: "That invitation is no longer valid" }),
4188
- /* @__PURE__ */ jsx24("p", { className: "b316-muted", children: "It may have expired, been withdrawn, or already been used. Ask for a new one." })
4268
+ /* @__PURE__ */ jsx25("h3", { className: "b316-form-title", children: "That invitation is no longer valid" }),
4269
+ /* @__PURE__ */ jsx25("p", { className: "b316-muted", children: "It may have expired, been withdrawn, or already been used. Ask for a new one." })
4189
4270
  ] });
4190
4271
  }
4191
4272
  if (state === "accepted") {
4192
- return /* @__PURE__ */ jsx24("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsxs23("h3", { className: "b316-form-title", children: [
4273
+ return /* @__PURE__ */ jsx25("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsxs23("h3", { className: "b316-form-title", children: [
4193
4274
  "You have joined ",
4194
4275
  preview?.organizationName
4195
4276
  ] }) });
@@ -4206,7 +4287,7 @@ function AcceptInvitation({
4206
4287
  " \xB7 ",
4207
4288
  preview?.roleName
4208
4289
  ] }),
4209
- error ? /* @__PURE__ */ jsx24("div", { className: "b316-error", role: "alert", children: error }) : null,
4290
+ error ? /* @__PURE__ */ jsx25("div", { className: "b316-error", role: "alert", children: error }) : null,
4210
4291
  !session ? /* @__PURE__ */ jsxs23(Fragment9, { children: [
4211
4292
  /* @__PURE__ */ jsxs23("p", { children: [
4212
4293
  "Sign in as ",
@@ -4214,8 +4295,8 @@ function AcceptInvitation({
4214
4295
  " to accept."
4215
4296
  ] }),
4216
4297
  /* @__PURE__ */ jsxs23("div", { className: "b316-invitation-actions", children: [
4217
- signInUrl ? /* @__PURE__ */ jsx24("a", { className: "b316-button", href: signInUrl, children: "Sign in" }) : null,
4218
- signUpUrl ? /* @__PURE__ */ jsx24(
4298
+ signInUrl ? /* @__PURE__ */ jsx25("a", { className: "b316-button", href: signInUrl, children: "Sign in" }) : null,
4299
+ signUpUrl ? /* @__PURE__ */ jsx25(
4219
4300
  "a",
4220
4301
  {
4221
4302
  className: "b316-button-link",
@@ -4235,13 +4316,13 @@ function AcceptInvitation({
4235
4316
  preview?.email,
4236
4317
  " \u2014 sign in as that address to accept it."
4237
4318
  ] })
4238
- ) : /* @__PURE__ */ jsx24("button", { type: "button", className: "b316-button", disabled: busy, onClick: accept, children: busy ? "Joining\u2026" : `Join ${preview?.organizationName}` })
4319
+ ) : /* @__PURE__ */ jsx25("button", { type: "button", className: "b316-button", disabled: busy, onClick: accept, children: busy ? "Joining\u2026" : `Join ${preview?.organizationName}` })
4239
4320
  ] });
4240
4321
  }
4241
4322
 
4242
4323
  // src/PayInvoice.tsx
4243
- import { useEffect as useEffect17, useRef as useRef5, useState as useState21 } from "react";
4244
- import { jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
4324
+ import { useEffect as useEffect18, useRef as useRef6, useState as useState21 } from "react";
4325
+ import { jsx as jsx26, jsxs as jsxs24 } from "react/jsx-runtime";
4245
4326
  var STRIPE_SRC = "https://js.stripe.com/v3/";
4246
4327
  function loadStripeScript() {
4247
4328
  if (typeof window === "undefined") {
@@ -4273,14 +4354,14 @@ function PayInvoice({
4273
4354
  style
4274
4355
  }) {
4275
4356
  const { client } = useBase316();
4276
- const mountRef = useRef5(null);
4277
- const stripeRef = useRef5(null);
4278
- const elementsRef = useRef5(null);
4357
+ const mountRef = useRef6(null);
4358
+ const stripeRef = useRef6(null);
4359
+ const elementsRef = useRef6(null);
4279
4360
  const [ready, setReady] = useState21(false);
4280
4361
  const [paying, setPaying] = useState21(false);
4281
4362
  const [done, setDone] = useState21(false);
4282
4363
  const [error, setError] = useState21(null);
4283
- useEffect17(() => {
4364
+ useEffect18(() => {
4284
4365
  let cancelled = false;
4285
4366
  async function start() {
4286
4367
  const base = `${client.baseUrl}/pay/${encodeURIComponent(environmentId)}/${encodeURIComponent(token)}`;
@@ -4333,17 +4414,17 @@ function PayInvoice({
4333
4414
  onPaid?.();
4334
4415
  };
4335
4416
  if (done) {
4336
- return /* @__PURE__ */ jsx25("div", { className: cls("b316-pay", className), style, children: /* @__PURE__ */ jsx25("p", { className: "b316-pay__done", children: "Paid \u2014 thank you." }) });
4417
+ return /* @__PURE__ */ jsx26("div", { className: cls("b316-pay", className), style, children: /* @__PURE__ */ jsx26("p", { className: "b316-pay__done", children: "Paid \u2014 thank you." }) });
4337
4418
  }
4338
4419
  return /* @__PURE__ */ jsxs24("form", { className: cls("b316-pay", className), style, onSubmit: submit, children: [
4339
- error ? /* @__PURE__ */ jsx25("p", { className: "b316-pay__error", role: "alert", children: error }) : null,
4340
- /* @__PURE__ */ jsx25("div", { ref: mountRef, className: "b316-pay__element" }),
4341
- /* @__PURE__ */ jsx25("button", { className: "b316-pay__submit", type: "submit", disabled: !ready || paying, children: paying ? "Paying\u2026" : "Pay" })
4420
+ error ? /* @__PURE__ */ jsx26("p", { className: "b316-pay__error", role: "alert", children: error }) : null,
4421
+ /* @__PURE__ */ jsx26("div", { ref: mountRef, className: "b316-pay__element" }),
4422
+ /* @__PURE__ */ jsx26("button", { className: "b316-pay__submit", type: "submit", disabled: !ready || paying, children: paying ? "Paying\u2026" : "Pay" })
4342
4423
  ] });
4343
4424
  }
4344
4425
 
4345
4426
  // src/usePaymentLink.ts
4346
- import { useEffect as useEffect18, useRef as useRef6, useState as useState22 } from "react";
4427
+ import { useEffect as useEffect19, useRef as useRef7, useState as useState22 } from "react";
4347
4428
  function usePaymentLink({
4348
4429
  token,
4349
4430
  environmentId,
@@ -4352,9 +4433,9 @@ function usePaymentLink({
4352
4433
  }) {
4353
4434
  const { client } = useBase316();
4354
4435
  const [status2, setStatus] = useState22({ state: "loading" });
4355
- const onPaidRef = useRef6(onPaid);
4436
+ const onPaidRef = useRef7(onPaid);
4356
4437
  onPaidRef.current = onPaid;
4357
- useEffect18(() => {
4438
+ useEffect19(() => {
4358
4439
  let stopped = false;
4359
4440
  let timer;
4360
4441
  const statusUrl = `${client.baseUrl}/pay/${encodeURIComponent(environmentId)}/${encodeURIComponent(token)}/status`;
@@ -4406,7 +4487,7 @@ function usePaymentLink({
4406
4487
  import { useState as useState24 } from "react";
4407
4488
 
4408
4489
  // src/usePlans.ts
4409
- import { useCallback as useCallback8, useEffect as useEffect19, useState as useState23 } from "react";
4490
+ import { useCallback as useCallback8, useEffect as useEffect20, useState as useState23 } from "react";
4410
4491
  var CHECKOUT_STATUSES = /* @__PURE__ */ new Set([402, 409]);
4411
4492
  function usePlans(options = {}) {
4412
4493
  const { client, token } = useBase316();
@@ -4419,7 +4500,7 @@ function usePlans(options = {}) {
4419
4500
  const [reloadCount, setReloadCount] = useState23(0);
4420
4501
  const supplied = options.currentPlanVersionId;
4421
4502
  const discover = supplied === void 0;
4422
- useEffect19(() => {
4503
+ useEffect20(() => {
4423
4504
  let cancelled = false;
4424
4505
  client.billing.plans().then((result) => {
4425
4506
  if (!cancelled) {
@@ -4435,7 +4516,7 @@ function usePlans(options = {}) {
4435
4516
  cancelled = true;
4436
4517
  };
4437
4518
  }, [client, reloadCount]);
4438
- useEffect19(() => {
4519
+ useEffect20(() => {
4439
4520
  if (!token) {
4440
4521
  return;
4441
4522
  }
@@ -4524,7 +4605,7 @@ function usePlans(options = {}) {
4524
4605
  }
4525
4606
 
4526
4607
  // src/PricingTable.tsx
4527
- import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
4608
+ import { jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
4528
4609
  function formatAmount(amount, currency) {
4529
4610
  if (amount === null) return "Free";
4530
4611
  const value = Number(amount);
@@ -4590,13 +4671,13 @@ function PricingTable({
4590
4671
  }
4591
4672
  }
4592
4673
  if (error) {
4593
- return /* @__PURE__ */ jsx26("div", { className: cls("b316-card", className), style, children: "Plans are unavailable right now." });
4674
+ return /* @__PURE__ */ jsx27("div", { className: cls("b316-card", className), style, children: "Plans are unavailable right now." });
4594
4675
  }
4595
4676
  if (!plans) {
4596
- return /* @__PURE__ */ jsx26("div", { className: cls("b316-card", className), style, children: "Loading plans\u2026" });
4677
+ return /* @__PURE__ */ jsx27("div", { className: cls("b316-card", className), style, children: "Loading plans\u2026" });
4597
4678
  }
4598
4679
  if (plans.length === 0) {
4599
- return /* @__PURE__ */ jsx26("div", { className: cls("b316-card", className), style, children: "No plans are published yet." });
4680
+ return /* @__PURE__ */ jsx27("div", { className: cls("b316-card", className), style, children: "No plans are published yet." });
4600
4681
  }
4601
4682
  const anyTrial = plans.some((plan) => Boolean(plan.trialDays));
4602
4683
  const anyDescription = plans.some((plan) => Boolean(plan.description));
@@ -4611,7 +4692,7 @@ function PricingTable({
4611
4692
  managedBy.name ?? "the organization that manages your account",
4612
4693
  ". Ask them to change it."
4613
4694
  ] })
4614
- ) : lastError ? /* @__PURE__ */ jsx26("div", { className: "b316-plans-error", role: "alert", children: lastError }) : scheduled ? /* @__PURE__ */ jsx26("div", { className: "b316-plans-managed b316-muted", role: "status", children: scheduled }) : null,
4695
+ ) : lastError ? /* @__PURE__ */ jsx27("div", { className: "b316-plans-error", role: "alert", children: lastError }) : scheduled ? /* @__PURE__ */ jsx27("div", { className: "b316-plans-managed b316-muted", role: "status", children: scheduled }) : null,
4615
4696
  plans.map((plan) => {
4616
4697
  const base = plan.prices.find((price) => price.featureId === null) ?? plan.prices[0];
4617
4698
  const isCurrent = current === plan.planVersionId;
@@ -4622,18 +4703,18 @@ function PricingTable({
4622
4703
  className: featured ? "b316-card b316-plan b316-plan-featured" : "b316-card b316-plan",
4623
4704
  children: [
4624
4705
  /* @__PURE__ */ jsxs25("div", { className: "b316-plan-head", children: [
4625
- anyFeatured ? /* @__PURE__ */ jsx26("div", { className: featured ? "b316-plan-badge" : "b316-plan-badge-spacer", children: featured ? "Recommended" : "\xA0" }) : null,
4626
- /* @__PURE__ */ jsx26("div", { className: "b316-plan-name", children: plan.name }),
4627
- anyDescription ? /* @__PURE__ */ jsx26("div", { className: "b316-plan-desc", children: plan.description ?? "\xA0" }) : null
4706
+ anyFeatured ? /* @__PURE__ */ jsx27("div", { className: featured ? "b316-plan-badge" : "b316-plan-badge-spacer", children: featured ? "Recommended" : "\xA0" }) : null,
4707
+ /* @__PURE__ */ jsx27("div", { className: "b316-plan-name", children: plan.name }),
4708
+ anyDescription ? /* @__PURE__ */ jsx27("div", { className: "b316-plan-desc", children: plan.description ?? "\xA0" }) : null
4628
4709
  ] }),
4629
4710
  /* @__PURE__ */ jsxs25("div", { className: "b316-plan-pricing", children: [
4630
- /* @__PURE__ */ jsx26("div", { className: "b316-plan-price", children: formatAmount(base?.amount ?? null, plan.currency) }),
4631
- /* @__PURE__ */ jsx26("div", { className: "b316-plan-cadence", children: cadence(plan, base?.amount ?? null) }),
4632
- anyTrial ? /* @__PURE__ */ jsx26("div", { className: "b316-plan-trial", children: describeTrial(plan, plans) ?? "\xA0" }) : null
4711
+ /* @__PURE__ */ jsx27("div", { className: "b316-plan-price", children: formatAmount(base?.amount ?? null, plan.currency) }),
4712
+ /* @__PURE__ */ jsx27("div", { className: "b316-plan-cadence", children: cadence(plan, base?.amount ?? null) }),
4713
+ anyTrial ? /* @__PURE__ */ jsx27("div", { className: "b316-plan-trial", children: describeTrial(plan, plans) ?? "\xA0" }) : null
4633
4714
  ] }),
4634
- /* @__PURE__ */ jsx26("ul", { className: "b316-plan-features", children: plan.entitlements.filter((entitlement) => entitlement.enabled).map((entitlement) => /* @__PURE__ */ jsxs25("li", { className: "b316-plan-feature", children: [
4635
- /* @__PURE__ */ jsx26("span", { children: entitlement.featureName }),
4636
- /* @__PURE__ */ jsx26("span", { className: "b316-plan-feature-value", children: entitlement.limit === null ? "Unlimited" : (
4715
+ /* @__PURE__ */ jsx27("ul", { className: "b316-plan-features", children: plan.entitlements.filter((entitlement) => entitlement.enabled).map((entitlement) => /* @__PURE__ */ jsxs25("li", { className: "b316-plan-feature", children: [
4716
+ /* @__PURE__ */ jsx27("span", { children: entitlement.featureName }),
4717
+ /* @__PURE__ */ jsx27("span", { className: "b316-plan-feature-value", children: entitlement.limit === null ? "Unlimited" : (
4637
4718
  // A usage price on the feature makes the limit an
4638
4719
  // allowance billed past, not a ceiling — the same
4639
4720
  // rule `check()` applies (any non-FLAT price).
@@ -4642,7 +4723,7 @@ function PricingTable({
4642
4723
  ) ? `${entitlement.limit} included` : entitlement.limit
4643
4724
  ) })
4644
4725
  ] }, entitlement.featureId)) }),
4645
- /* @__PURE__ */ jsx26("div", { className: "b316-plan-action", children: /* @__PURE__ */ jsx26(
4726
+ /* @__PURE__ */ jsx27("div", { className: "b316-plan-action", children: /* @__PURE__ */ jsx27(
4646
4727
  "button",
4647
4728
  {
4648
4729
  type: "button",
@@ -4662,16 +4743,104 @@ function PricingTable({
4662
4743
  ] });
4663
4744
  }
4664
4745
 
4746
+ // src/useAddons.ts
4747
+ import { useCallback as useCallback9, useEffect as useEffect21, useState as useState25 } from "react";
4748
+ function codeOf(cause) {
4749
+ const reason = cause?.reason;
4750
+ return typeof reason === "string" ? reason : "request_failed";
4751
+ }
4752
+ function useAddons() {
4753
+ const { client, token } = useBase316();
4754
+ const [attached, setAttached] = useState25(null);
4755
+ const [available, setAvailable] = useState25(null);
4756
+ const [loading2, setLoading] = useState25(true);
4757
+ const [lastError, setLastError] = useState25(null);
4758
+ const [busy, setBusy] = useState25(null);
4759
+ const [reloadCount, setReloadCount] = useState25(0);
4760
+ useEffect21(() => {
4761
+ let cancelled = false;
4762
+ if (!token) {
4763
+ return;
4764
+ }
4765
+ client.billing.addonsForSubscription(token).then((result) => {
4766
+ if (!cancelled) {
4767
+ setAttached(result.attached);
4768
+ setAvailable(result.available);
4769
+ setLastError(null);
4770
+ }
4771
+ }).catch((cause) => {
4772
+ if (!cancelled) {
4773
+ setAttached(null);
4774
+ setAvailable(null);
4775
+ setLastError(codeOf(cause));
4776
+ }
4777
+ }).finally(() => {
4778
+ if (!cancelled) {
4779
+ setLoading(false);
4780
+ }
4781
+ });
4782
+ return () => {
4783
+ cancelled = true;
4784
+ };
4785
+ }, [client, token, reloadCount]);
4786
+ const reload = useCallback9(() => {
4787
+ setLoading(true);
4788
+ setReloadCount((count) => count + 1);
4789
+ }, []);
4790
+ const run = useCallback9(
4791
+ async (key, action) => {
4792
+ if (!token) {
4793
+ setLastError("needs_sign_in");
4794
+ return null;
4795
+ }
4796
+ setBusy(key);
4797
+ setLastError(null);
4798
+ try {
4799
+ const outcome = await action(token);
4800
+ reload();
4801
+ return outcome;
4802
+ } catch (cause) {
4803
+ setLastError(codeOf(cause));
4804
+ return null;
4805
+ } finally {
4806
+ setBusy(null);
4807
+ }
4808
+ },
4809
+ [token, reload]
4810
+ );
4811
+ return {
4812
+ attached,
4813
+ available,
4814
+ loading: Boolean(token) && loading2,
4815
+ lastError,
4816
+ busy,
4817
+ signedIn: Boolean(token),
4818
+ attach: (addonId, quantity) => run(
4819
+ addonId,
4820
+ (session) => client.billing.attachAddon(session, {
4821
+ addonId,
4822
+ ...quantity === void 0 ? {} : { quantity }
4823
+ })
4824
+ ),
4825
+ setQuantity: (attachmentId, quantity) => run(
4826
+ attachmentId,
4827
+ (session) => client.billing.setAddonQuantity(session, attachmentId, quantity)
4828
+ ),
4829
+ remove: (attachmentId) => run(attachmentId, (session) => client.billing.removeAddon(session, attachmentId)),
4830
+ reload
4831
+ };
4832
+ }
4833
+
4665
4834
  // src/DataTable.tsx
4666
4835
  import { specFor as specFor3 } from "@base316/sdk";
4667
- import { useState as useState28 } from "react";
4836
+ import { useState as useState29 } from "react";
4668
4837
 
4669
4838
  // src/fields.tsx
4670
4839
  import {
4671
4840
  formatAddress,
4672
4841
  specFor
4673
4842
  } from "@base316/sdk";
4674
- import { jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
4843
+ import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
4675
4844
  function formatNumber(value, fraction = 0) {
4676
4845
  const number = Number(value);
4677
4846
  return Number.isFinite(number) ? new Intl.NumberFormat(void 0, {
@@ -4693,10 +4862,10 @@ function formatDuration(value) {
4693
4862
  }
4694
4863
  function FieldCell({ value, field, related }) {
4695
4864
  if (field.type === "RELATION") {
4696
- return related?.title ?? (related?.id ? /* @__PURE__ */ jsx27("code", { className: "b316-muted", children: related.id }) : "\u2014");
4865
+ return related?.title ?? (related?.id ? /* @__PURE__ */ jsx28("code", { className: "b316-muted", children: related.id }) : "\u2014");
4697
4866
  }
4698
4867
  if (value === null || value === void 0 || value === "") {
4699
- return /* @__PURE__ */ jsx27("span", { className: "b316-muted", children: "\u2014" });
4868
+ return /* @__PURE__ */ jsx28("span", { className: "b316-muted", children: "\u2014" });
4700
4869
  }
4701
4870
  switch (field.type) {
4702
4871
  case "BOOLEAN":
@@ -4711,7 +4880,7 @@ function FieldCell({ value, field, related }) {
4711
4880
  const stars = Math.round(Number(value));
4712
4881
  return /* @__PURE__ */ jsxs26("span", { "aria-label": `${stars} out of 5`, children: [
4713
4882
  "\u2605".repeat(stars),
4714
- /* @__PURE__ */ jsx27("span", { className: "b316-muted", children: "\u2605".repeat(Math.max(0, 5 - stars)) })
4883
+ /* @__PURE__ */ jsx28("span", { className: "b316-muted", children: "\u2605".repeat(Math.max(0, 5 - stars)) })
4715
4884
  ] });
4716
4885
  }
4717
4886
  case "DATE":
@@ -4719,15 +4888,15 @@ function FieldCell({ value, field, related }) {
4719
4888
  case "DATETIME":
4720
4889
  return new Date(String(value)).toLocaleString();
4721
4890
  case "SELECT":
4722
- return /* @__PURE__ */ jsx27("span", { className: "b316-chip", children: String(value) });
4891
+ return /* @__PURE__ */ jsx28("span", { className: "b316-chip", children: String(value) });
4723
4892
  case "MULTISELECT":
4724
- return /* @__PURE__ */ jsx27("span", { className: "b316-chips", children: (Array.isArray(value) ? value : [value]).map((item) => /* @__PURE__ */ jsx27("span", { className: "b316-chip", children: String(item) }, String(item))) });
4893
+ return /* @__PURE__ */ jsx28("span", { className: "b316-chips", children: (Array.isArray(value) ? value : [value]).map((item) => /* @__PURE__ */ jsx28("span", { className: "b316-chip", children: String(item) }, String(item))) });
4725
4894
  case "URL":
4726
- return /* @__PURE__ */ jsx27("a", { href: String(value), target: "_blank", rel: "noreferrer noopener", children: String(value) });
4895
+ return /* @__PURE__ */ jsx28("a", { href: String(value), target: "_blank", rel: "noreferrer noopener", children: String(value) });
4727
4896
  case "EMAIL":
4728
- return /* @__PURE__ */ jsx27("a", { href: `mailto:${String(value)}`, children: String(value) });
4897
+ return /* @__PURE__ */ jsx28("a", { href: `mailto:${String(value)}`, children: String(value) });
4729
4898
  case "PHONE":
4730
- return /* @__PURE__ */ jsx27("a", { href: `tel:${String(value)}`, children: String(value) });
4899
+ return /* @__PURE__ */ jsx28("a", { href: `tel:${String(value)}`, children: String(value) });
4731
4900
  case "ADDRESS":
4732
4901
  return formatAddress(value);
4733
4902
  case "ATTACHMENT": {
@@ -4739,7 +4908,7 @@ function FieldCell({ value, field, related }) {
4739
4908
  return text.length > 80 ? `${text.slice(0, 80)}\u2026` : text;
4740
4909
  }
4741
4910
  case "JSON":
4742
- return /* @__PURE__ */ jsx27("code", { className: "b316-muted", children: JSON.stringify(value).slice(0, 60) });
4911
+ return /* @__PURE__ */ jsx28("code", { className: "b316-muted", children: JSON.stringify(value).slice(0, 60) });
4743
4912
  default:
4744
4913
  return String(value);
4745
4914
  }
@@ -4760,7 +4929,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4760
4929
  function control() {
4761
4930
  switch (field.type) {
4762
4931
  case "LONGTEXT":
4763
- return /* @__PURE__ */ jsx27(
4932
+ return /* @__PURE__ */ jsx28(
4764
4933
  "textarea",
4765
4934
  {
4766
4935
  ...common,
@@ -4770,7 +4939,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4770
4939
  }
4771
4940
  );
4772
4941
  case "BOOLEAN":
4773
- return /* @__PURE__ */ jsx27(
4942
+ return /* @__PURE__ */ jsx28(
4774
4943
  "input",
4775
4944
  {
4776
4945
  ...common,
@@ -4788,15 +4957,15 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4788
4957
  value: value === null || value === void 0 ? "" : String(value),
4789
4958
  onChange: (event) => onChange(event.target.value === "" ? null : event.target.value),
4790
4959
  children: [
4791
- field.required ? null : /* @__PURE__ */ jsx27("option", { value: "", children: "\u2014" }),
4792
- (field.options ?? []).map((option) => /* @__PURE__ */ jsx27("option", { value: option, children: option }, option))
4960
+ field.required ? null : /* @__PURE__ */ jsx28("option", { value: "", children: "\u2014" }),
4961
+ (field.options ?? []).map((option) => /* @__PURE__ */ jsx28("option", { value: option, children: option }, option))
4793
4962
  ]
4794
4963
  }
4795
4964
  );
4796
4965
  case "MULTISELECT": {
4797
4966
  const selected = new Set(Array.isArray(value) ? value.map(String) : []);
4798
- return /* @__PURE__ */ jsx27("div", { className: "b316-choices", children: (field.options ?? []).map((option) => /* @__PURE__ */ jsxs26("label", { className: "b316-choice", children: [
4799
- /* @__PURE__ */ jsx27(
4967
+ return /* @__PURE__ */ jsx28("div", { className: "b316-choices", children: (field.options ?? []).map((option) => /* @__PURE__ */ jsxs26("label", { className: "b316-choice", children: [
4968
+ /* @__PURE__ */ jsx28(
4800
4969
  "input",
4801
4970
  {
4802
4971
  type: "checkbox",
@@ -4819,7 +4988,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4819
4988
  case "NUMBER":
4820
4989
  case "MONEY":
4821
4990
  case "PERCENT":
4822
- return /* @__PURE__ */ jsx27(
4991
+ return /* @__PURE__ */ jsx28(
4823
4992
  "input",
4824
4993
  {
4825
4994
  ...common,
@@ -4830,7 +4999,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4830
4999
  }
4831
5000
  );
4832
5001
  case "RATING":
4833
- return /* @__PURE__ */ jsx27(
5002
+ return /* @__PURE__ */ jsx28(
4834
5003
  "input",
4835
5004
  {
4836
5005
  ...common,
@@ -4845,7 +5014,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4845
5014
  case "DURATION": {
4846
5015
  const minutes = value === null || value === void 0 ? "" : String(Number(value) / 60);
4847
5016
  return /* @__PURE__ */ jsxs26("div", { className: "b316-suffixed", children: [
4848
- /* @__PURE__ */ jsx27(
5017
+ /* @__PURE__ */ jsx28(
4849
5018
  "input",
4850
5019
  {
4851
5020
  ...common,
@@ -4855,11 +5024,11 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4855
5024
  onChange: (event) => onChange(event.target.value === "" ? null : Number(event.target.value) * 60)
4856
5025
  }
4857
5026
  ),
4858
- /* @__PURE__ */ jsx27("span", { className: "b316-muted", children: "minutes" })
5027
+ /* @__PURE__ */ jsx28("span", { className: "b316-muted", children: "minutes" })
4859
5028
  ] });
4860
5029
  }
4861
5030
  case "DATE":
4862
- return /* @__PURE__ */ jsx27(
5031
+ return /* @__PURE__ */ jsx28(
4863
5032
  "input",
4864
5033
  {
4865
5034
  ...common,
@@ -4869,7 +5038,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4869
5038
  }
4870
5039
  );
4871
5040
  case "DATETIME":
4872
- return /* @__PURE__ */ jsx27(
5041
+ return /* @__PURE__ */ jsx28(
4873
5042
  "input",
4874
5043
  {
4875
5044
  ...common,
@@ -4882,7 +5051,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4882
5051
  );
4883
5052
  case "ADDRESS": {
4884
5053
  const address = value ?? {};
4885
- const part = (key, label) => /* @__PURE__ */ jsx27(
5054
+ const part = (key, label) => /* @__PURE__ */ jsx28(
4886
5055
  "input",
4887
5056
  {
4888
5057
  className: "b316-input",
@@ -4904,7 +5073,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4904
5073
  ] });
4905
5074
  }
4906
5075
  case "EMAIL":
4907
- return /* @__PURE__ */ jsx27(
5076
+ return /* @__PURE__ */ jsx28(
4908
5077
  "input",
4909
5078
  {
4910
5079
  ...common,
@@ -4914,7 +5083,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4914
5083
  }
4915
5084
  );
4916
5085
  case "URL":
4917
- return /* @__PURE__ */ jsx27(
5086
+ return /* @__PURE__ */ jsx28(
4918
5087
  "input",
4919
5088
  {
4920
5089
  ...common,
@@ -4924,7 +5093,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4924
5093
  }
4925
5094
  );
4926
5095
  case "PHONE":
4927
- return /* @__PURE__ */ jsx27(
5096
+ return /* @__PURE__ */ jsx28(
4928
5097
  "input",
4929
5098
  {
4930
5099
  ...common,
@@ -4934,7 +5103,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4934
5103
  }
4935
5104
  );
4936
5105
  default:
4937
- return /* @__PURE__ */ jsx27(
5106
+ return /* @__PURE__ */ jsx28(
4938
5107
  "input",
4939
5108
  {
4940
5109
  ...common,
@@ -4948,21 +5117,21 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4948
5117
  return /* @__PURE__ */ jsxs26("div", { className: "b316-field", children: [
4949
5118
  /* @__PURE__ */ jsxs26("label", { className: "b316-label", htmlFor: id, children: [
4950
5119
  field.label,
4951
- field.required ? /* @__PURE__ */ jsx27("span", { "aria-hidden": "true", children: " *" }) : null
5120
+ field.required ? /* @__PURE__ */ jsx28("span", { "aria-hidden": "true", children: " *" }) : null
4952
5121
  ] }),
4953
5122
  control(),
4954
- field.description ? /* @__PURE__ */ jsx27("div", { className: "b316-hint", children: field.description }) : null,
4955
- error ? /* @__PURE__ */ jsx27("div", { className: "b316-error", id: described, role: "alert", children: error }) : null
5123
+ field.description ? /* @__PURE__ */ jsx28("div", { className: "b316-hint", children: field.description }) : null,
5124
+ error ? /* @__PURE__ */ jsx28("div", { className: "b316-error", id: described, role: "alert", children: error }) : null
4956
5125
  ] });
4957
5126
  }
4958
5127
 
4959
5128
  // src/RecordForm.tsx
4960
5129
  import { specFor as specFor2 } from "@base316/sdk";
4961
- import { useEffect as useEffect22, useState as useState27 } from "react";
5130
+ import { useEffect as useEffect24, useState as useState28 } from "react";
4962
5131
 
4963
5132
  // src/RelationPicker.tsx
4964
- import { useEffect as useEffect20, useRef as useRef7, useState as useState25 } from "react";
4965
- import { Fragment as Fragment10, jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
5133
+ import { useEffect as useEffect22, useRef as useRef8, useState as useState26 } from "react";
5134
+ import { Fragment as Fragment10, jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
4966
5135
  function RelationPicker({
4967
5136
  field,
4968
5137
  value,
@@ -4972,13 +5141,13 @@ function RelationPicker({
4972
5141
  tenant
4973
5142
  }) {
4974
5143
  const { client, token } = useBase316();
4975
- const [query, setQuery] = useState25("");
4976
- const [results, setResults] = useState25([]);
4977
- const [chosenTitle, setChosenTitle] = useState25(null);
4978
- const [open, setOpen] = useState25(false);
5144
+ const [query, setQuery] = useState26("");
5145
+ const [results, setResults] = useState26([]);
5146
+ const [chosenTitle, setChosenTitle] = useState26(null);
5147
+ const [open, setOpen] = useState26(false);
4979
5148
  const id = `b316-field-${field.key}`;
4980
- const box = useRef7(null);
4981
- useEffect20(() => {
5149
+ const box = useRef8(null);
5150
+ useEffect22(() => {
4982
5151
  if (!token || !value || !field.relationTo) {
4983
5152
  setChosenTitle(null);
4984
5153
  return;
@@ -4993,7 +5162,7 @@ function RelationPicker({
4993
5162
  cancelled = true;
4994
5163
  };
4995
5164
  }, [client, token, value, field.relationTo, tenant]);
4996
- useEffect20(() => {
5165
+ useEffect22(() => {
4997
5166
  if (!token || !field.relationTo || !open) {
4998
5167
  return;
4999
5168
  }
@@ -5019,7 +5188,7 @@ function RelationPicker({
5019
5188
  clearTimeout(timer);
5020
5189
  };
5021
5190
  }, [client, token, field.relationTo, query, open, tenant]);
5022
- useEffect20(() => {
5191
+ useEffect22(() => {
5023
5192
  if (!open || typeof document === "undefined") {
5024
5193
  return;
5025
5194
  }
@@ -5036,11 +5205,11 @@ function RelationPicker({
5036
5205
  return /* @__PURE__ */ jsxs27("div", { className: "b316-field", ref: box, children: [
5037
5206
  /* @__PURE__ */ jsxs27("label", { className: "b316-label", htmlFor: id, children: [
5038
5207
  field.label,
5039
- field.required ? /* @__PURE__ */ jsx28("span", { "aria-hidden": "true", children: " *" }) : null
5208
+ field.required ? /* @__PURE__ */ jsx29("span", { "aria-hidden": "true", children: " *" }) : null
5040
5209
  ] }),
5041
5210
  value && !open ? /* @__PURE__ */ jsxs27("div", { className: "b316-relation-chosen", children: [
5042
- /* @__PURE__ */ jsx28("span", { children: chosenTitle ?? value }),
5043
- disabled ? null : /* @__PURE__ */ jsx28(
5211
+ /* @__PURE__ */ jsx29("span", { children: chosenTitle ?? value }),
5212
+ disabled ? null : /* @__PURE__ */ jsx29(
5044
5213
  "button",
5045
5214
  {
5046
5215
  type: "button",
@@ -5052,7 +5221,7 @@ function RelationPicker({
5052
5221
  children: "Change"
5053
5222
  }
5054
5223
  ),
5055
- disabled || field.required ? null : /* @__PURE__ */ jsx28(
5224
+ disabled || field.required ? null : /* @__PURE__ */ jsx29(
5056
5225
  "button",
5057
5226
  {
5058
5227
  type: "button",
@@ -5063,7 +5232,7 @@ function RelationPicker({
5063
5232
  }
5064
5233
  )
5065
5234
  ] }) : /* @__PURE__ */ jsxs27(Fragment10, { children: [
5066
- /* @__PURE__ */ jsx28(
5235
+ /* @__PURE__ */ jsx29(
5067
5236
  "input",
5068
5237
  {
5069
5238
  id,
@@ -5084,7 +5253,7 @@ function RelationPicker({
5084
5253
  }
5085
5254
  }
5086
5255
  ),
5087
- open ? /* @__PURE__ */ jsx28("ul", { className: "b316-relation-results", id: `${id}-results`, role: "listbox", children: results.length === 0 ? /* @__PURE__ */ jsx28("li", { className: "b316-muted b316-relation-empty", children: "No matches" }) : results.map((result) => /* @__PURE__ */ jsx28("li", { children: /* @__PURE__ */ jsx28(
5256
+ open ? /* @__PURE__ */ jsx29("ul", { className: "b316-relation-results", id: `${id}-results`, role: "listbox", children: results.length === 0 ? /* @__PURE__ */ jsx29("li", { className: "b316-muted b316-relation-empty", children: "No matches" }) : results.map((result) => /* @__PURE__ */ jsx29("li", { children: /* @__PURE__ */ jsx29(
5088
5257
  "button",
5089
5258
  {
5090
5259
  type: "button",
@@ -5100,13 +5269,13 @@ function RelationPicker({
5100
5269
  }
5101
5270
  ) }, result.id)) }) : null
5102
5271
  ] }),
5103
- field.description ? /* @__PURE__ */ jsx28("div", { className: "b316-hint", children: field.description }) : null,
5104
- error ? /* @__PURE__ */ jsx28("div", { className: "b316-error", role: "alert", children: error }) : null
5272
+ field.description ? /* @__PURE__ */ jsx29("div", { className: "b316-hint", children: field.description }) : null,
5273
+ error ? /* @__PURE__ */ jsx29("div", { className: "b316-error", role: "alert", children: error }) : null
5105
5274
  ] });
5106
5275
  }
5107
5276
 
5108
5277
  // src/useCollection.ts
5109
- import { useCallback as useCallback9, useEffect as useEffect21, useMemo as useMemo3, useState as useState26 } from "react";
5278
+ import { useCallback as useCallback10, useEffect as useEffect23, useMemo as useMemo3, useState as useState27 } from "react";
5110
5279
  function fieldErrorFrom(cause) {
5111
5280
  const param = cause?.param;
5112
5281
  const message = cause instanceof Error ? cause.message : "That value was not accepted.";
@@ -5114,24 +5283,24 @@ function fieldErrorFrom(cause) {
5114
5283
  }
5115
5284
  function useCollection(collection, options = {}) {
5116
5285
  const { client, token } = useBase316();
5117
- const [schema, setSchema] = useState26(null);
5118
- const [records, setRecords] = useState26([]);
5119
- const [error, setError] = useState26(null);
5120
- const [loading, setLoading] = useState26(true);
5121
- const [total, setTotal] = useState26(0);
5122
- const [cursor, setCursor] = useState26(null);
5123
- const [reloadCount, setReloadCount] = useState26(0);
5124
- const [search, setSearch] = useState26("");
5125
- const [filters, setFilters] = useState26([]);
5126
- const [sort, setSort] = useState26(
5286
+ const [schema, setSchema] = useState27(null);
5287
+ const [records, setRecords] = useState27([]);
5288
+ const [error, setError] = useState27(null);
5289
+ const [loading2, setLoading] = useState27(true);
5290
+ const [total, setTotal] = useState27(0);
5291
+ const [cursor, setCursor] = useState27(null);
5292
+ const [reloadCount, setReloadCount] = useState27(0);
5293
+ const [search, setSearch] = useState27("");
5294
+ const [filters, setFilters] = useState27([]);
5295
+ const [sort, setSort] = useState27(
5127
5296
  options.sort ?? null
5128
5297
  );
5129
- const [fieldErrors, setFieldErrors] = useState26({});
5130
- const [saving, setSaving] = useState26(false);
5298
+ const [fieldErrors, setFieldErrors] = useState27({});
5299
+ const [saving, setSaving] = useState27(false);
5131
5300
  const { tenant, limit, recordId } = options;
5132
5301
  const fixedFilters = JSON.stringify(options.filters ?? []);
5133
5302
  const scope = useMemo3(() => tenant ? { tenant } : void 0, [tenant]);
5134
- useEffect21(() => {
5303
+ useEffect23(() => {
5135
5304
  if (!token) {
5136
5305
  return;
5137
5306
  }
@@ -5150,7 +5319,7 @@ function useCollection(collection, options = {}) {
5150
5319
  cancelled = true;
5151
5320
  };
5152
5321
  }, [client, token, collection, scope]);
5153
- useEffect21(() => {
5322
+ useEffect23(() => {
5154
5323
  if (!token || !schema) {
5155
5324
  return;
5156
5325
  }
@@ -5220,10 +5389,10 @@ function useCollection(collection, options = {}) {
5220
5389
  scope,
5221
5390
  reloadCount
5222
5391
  ]);
5223
- const reload = useCallback9(() => {
5392
+ const reload = useCallback10(() => {
5224
5393
  setReloadCount((count) => count + 1);
5225
5394
  }, []);
5226
- const loadMore = useCallback9(() => {
5395
+ const loadMore = useCallback10(() => {
5227
5396
  if (!token || !cursor) {
5228
5397
  return;
5229
5398
  }
@@ -5247,7 +5416,7 @@ function useCollection(collection, options = {}) {
5247
5416
  setLoading(false);
5248
5417
  });
5249
5418
  }, [client, token, collection, cursor, fixedFilters, filters, search, sort, limit, scope]);
5250
- const toggleSort = useCallback9((field) => {
5419
+ const toggleSort = useCallback10((field) => {
5251
5420
  setSort((current) => {
5252
5421
  if (current?.field !== field) {
5253
5422
  return { field, direction: "asc" };
@@ -5255,7 +5424,7 @@ function useCollection(collection, options = {}) {
5255
5424
  return current.direction === "asc" ? { field, direction: "desc" } : null;
5256
5425
  });
5257
5426
  }, []);
5258
- const create = useCallback9(
5427
+ const create = useCallback10(
5259
5428
  async (fields) => {
5260
5429
  if (!token) {
5261
5430
  return null;
@@ -5275,7 +5444,7 @@ function useCollection(collection, options = {}) {
5275
5444
  },
5276
5445
  [client, token, collection, scope, reload]
5277
5446
  );
5278
- const update = useCallback9(
5447
+ const update = useCallback10(
5279
5448
  async (id, fields) => {
5280
5449
  if (!token) {
5281
5450
  return null;
@@ -5297,7 +5466,7 @@ function useCollection(collection, options = {}) {
5297
5466
  },
5298
5467
  [client, token, collection, scope]
5299
5468
  );
5300
- const remove = useCallback9(
5469
+ const remove = useCallback10(
5301
5470
  async (id) => {
5302
5471
  if (!token) {
5303
5472
  return false;
@@ -5320,7 +5489,7 @@ function useCollection(collection, options = {}) {
5320
5489
  return {
5321
5490
  schema,
5322
5491
  records,
5323
- loading,
5492
+ loading: loading2,
5324
5493
  error,
5325
5494
  total,
5326
5495
  hasMore: cursor !== null,
@@ -5342,7 +5511,7 @@ function useCollection(collection, options = {}) {
5342
5511
  }
5343
5512
 
5344
5513
  // src/RecordForm.tsx
5345
- import { jsx as jsx29, jsxs as jsxs28 } from "react/jsx-runtime";
5514
+ import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
5346
5515
  function RecordForm({
5347
5516
  collection,
5348
5517
  recordId,
@@ -5363,20 +5532,20 @@ function RecordForm({
5363
5532
  recordId
5364
5533
  }
5365
5534
  );
5366
- const [values, setValues] = useState27(defaults ?? {});
5367
- const [loaded, setLoaded] = useState27(!recordId);
5535
+ const [values, setValues] = useState28(defaults ?? {});
5536
+ const [loaded, setLoaded] = useState28(!recordId);
5368
5537
  const existing = recordId ? records.find((record) => record.id === recordId) : void 0;
5369
- useEffect22(() => {
5538
+ useEffect24(() => {
5370
5539
  if (existing && !loaded) {
5371
5540
  setValues(existing.fields);
5372
5541
  setLoaded(true);
5373
5542
  }
5374
5543
  }, [existing, loaded]);
5375
5544
  if (error) {
5376
- return /* @__PURE__ */ jsx29("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx29("div", { className: "b316-error", role: "alert", children: error }) });
5545
+ return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx30("div", { className: "b316-error", role: "alert", children: error }) });
5377
5546
  }
5378
5547
  if (!schema || !loaded) {
5379
- return /* @__PURE__ */ jsx29("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5548
+ return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5380
5549
  }
5381
5550
  const editable = schema.fields.filter((field) => !specFor2(field).computed);
5382
5551
  async function submit(event) {
@@ -5387,10 +5556,10 @@ function RecordForm({
5387
5556
  }
5388
5557
  }
5389
5558
  return /* @__PURE__ */ jsxs28("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
5390
- /* @__PURE__ */ jsx29("h3", { className: "b316-form-title", children: recordId ? `Edit ${schema.name.toLowerCase()}` : `New ${schema.name.toLowerCase()}` }),
5391
- fieldErrors._ ? /* @__PURE__ */ jsx29("div", { className: "b316-error", role: "alert", children: fieldErrors._ }) : null,
5559
+ /* @__PURE__ */ jsx30("h3", { className: "b316-form-title", children: recordId ? `Edit ${schema.name.toLowerCase()}` : `New ${schema.name.toLowerCase()}` }),
5560
+ fieldErrors._ ? /* @__PURE__ */ jsx30("div", { className: "b316-error", role: "alert", children: fieldErrors._ }) : null,
5392
5561
  editable.map(
5393
- (field) => field.type === "RELATION" ? /* @__PURE__ */ jsx29(
5562
+ (field) => field.type === "RELATION" ? /* @__PURE__ */ jsx30(
5394
5563
  RelationPicker,
5395
5564
  {
5396
5565
  field,
@@ -5401,7 +5570,7 @@ function RecordForm({
5401
5570
  onChange: (next) => setValues((current) => ({ ...current, [field.key]: next }))
5402
5571
  },
5403
5572
  field.key
5404
- ) : /* @__PURE__ */ jsx29(
5573
+ ) : /* @__PURE__ */ jsx30(
5405
5574
  FieldInput,
5406
5575
  {
5407
5576
  field,
@@ -5414,14 +5583,14 @@ function RecordForm({
5414
5583
  )
5415
5584
  ),
5416
5585
  /* @__PURE__ */ jsxs28("div", { className: "b316-form-actions", children: [
5417
- onCancel ? /* @__PURE__ */ jsx29("button", { type: "button", className: "b316-button-quiet", onClick: onCancel, disabled: saving, children: "Cancel" }) : null,
5418
- /* @__PURE__ */ jsx29("button", { type: "submit", className: "b316-button", disabled: saving, children: saving ? "Saving\u2026" : "Save" })
5586
+ onCancel ? /* @__PURE__ */ jsx30("button", { type: "button", className: "b316-button-quiet", onClick: onCancel, disabled: saving, children: "Cancel" }) : null,
5587
+ /* @__PURE__ */ jsx30("button", { type: "submit", className: "b316-button", disabled: saving, children: saving ? "Saving\u2026" : "Save" })
5419
5588
  ] })
5420
5589
  ] });
5421
5590
  }
5422
5591
 
5423
5592
  // src/DataTable.tsx
5424
- import { jsx as jsx30, jsxs as jsxs29 } from "react/jsx-runtime";
5593
+ import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
5425
5594
  function DataTable({
5426
5595
  collection,
5427
5596
  columns,
@@ -5438,7 +5607,7 @@ function DataTable({
5438
5607
  const {
5439
5608
  schema,
5440
5609
  records,
5441
- loading,
5610
+ loading: loading2,
5442
5611
  error,
5443
5612
  total,
5444
5613
  hasMore,
@@ -5450,13 +5619,13 @@ function DataTable({
5450
5619
  loadMore,
5451
5620
  remove
5452
5621
  } = useCollection(collection, options);
5453
- const [editing, setEditing] = useState28(null);
5454
- const [removeFailed, setRemoveFailed] = useState28(null);
5622
+ const [editing, setEditing] = useState29(null);
5623
+ const [removeFailed, setRemoveFailed] = useState29(null);
5455
5624
  if (error) {
5456
- return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx30("div", { className: "b316-error", role: "alert", children: error }) });
5625
+ return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx31("div", { className: "b316-error", role: "alert", children: error }) });
5457
5626
  }
5458
5627
  if (!schema) {
5459
- return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5628
+ return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5460
5629
  }
5461
5630
  const shown = columns ? (
5462
5631
  // Ordered by what was asked for, not by the schema: a caller naming
@@ -5466,9 +5635,9 @@ function DataTable({
5466
5635
  const searchable = schema.fields.some((field) => specFor3(field).capabilities.searchable);
5467
5636
  const writable = canWrite && !readOnly;
5468
5637
  return /* @__PURE__ */ jsxs29("div", { className: cls("b316-table-wrap", className), style, children: [
5469
- removeFailed ? /* @__PURE__ */ jsx30("div", { className: "b316-error", role: "alert", children: removeFailed }) : null,
5638
+ removeFailed ? /* @__PURE__ */ jsx31("div", { className: "b316-error", role: "alert", children: removeFailed }) : null,
5470
5639
  /* @__PURE__ */ jsxs29("div", { className: "b316-table-bar", children: [
5471
- searchable && !hideSearch ? /* @__PURE__ */ jsx30(
5640
+ searchable && !hideSearch ? /* @__PURE__ */ jsx31(
5472
5641
  "input",
5473
5642
  {
5474
5643
  type: "search",
@@ -5478,7 +5647,7 @@ function DataTable({
5478
5647
  value: search,
5479
5648
  onChange: (event) => setSearch(event.target.value)
5480
5649
  }
5481
- ) : /* @__PURE__ */ jsx30("span", {}),
5650
+ ) : /* @__PURE__ */ jsx31("span", {}),
5482
5651
  /* @__PURE__ */ jsxs29("div", { className: "b316-table-actions", children: [
5483
5652
  /* @__PURE__ */ jsxs29("span", { className: "b316-muted", children: [
5484
5653
  total,
@@ -5491,12 +5660,12 @@ function DataTable({
5491
5660
  ] }) : null
5492
5661
  ] })
5493
5662
  ] }),
5494
- /* @__PURE__ */ jsx30("div", { className: "b316-table-scroll", children: /* @__PURE__ */ jsxs29("table", { className: "b316-table", children: [
5495
- /* @__PURE__ */ jsx30("thead", { children: /* @__PURE__ */ jsxs29("tr", { children: [
5663
+ /* @__PURE__ */ jsx31("div", { className: "b316-table-scroll", children: /* @__PURE__ */ jsxs29("table", { className: "b316-table", children: [
5664
+ /* @__PURE__ */ jsx31("thead", { children: /* @__PURE__ */ jsxs29("tr", { children: [
5496
5665
  shown.map((field) => {
5497
5666
  const sortable = specFor3(field).capabilities.sortable;
5498
5667
  const active = sort?.field === field.key;
5499
- return /* @__PURE__ */ jsx30("th", { scope: "col", "aria-sort": ariaSort(active, sort?.direction), children: sortable ? /* @__PURE__ */ jsxs29(
5668
+ return /* @__PURE__ */ jsx31("th", { scope: "col", "aria-sort": ariaSort(active, sort?.direction), children: sortable ? /* @__PURE__ */ jsxs29(
5500
5669
  "button",
5501
5670
  {
5502
5671
  type: "button",
@@ -5504,20 +5673,20 @@ function DataTable({
5504
5673
  onClick: () => toggleSort(field.key),
5505
5674
  children: [
5506
5675
  field.label,
5507
- /* @__PURE__ */ jsx30("span", { "aria-hidden": "true", children: active ? sort?.direction === "desc" ? " \u2193" : " \u2191" : " \u2195" })
5676
+ /* @__PURE__ */ jsx31("span", { "aria-hidden": "true", children: active ? sort?.direction === "desc" ? " \u2193" : " \u2191" : " \u2195" })
5508
5677
  ]
5509
5678
  }
5510
5679
  ) : field.label }, field.key);
5511
5680
  }),
5512
- writable ? /* @__PURE__ */ jsx30("th", { scope: "col", className: "b316-table-rowactions" }) : null
5681
+ writable ? /* @__PURE__ */ jsx31("th", { scope: "col", className: "b316-table-rowactions" }) : null
5513
5682
  ] }) }),
5514
- /* @__PURE__ */ jsx30("tbody", { children: records.map((record) => /* @__PURE__ */ jsxs29(
5683
+ /* @__PURE__ */ jsx31("tbody", { children: records.map((record) => /* @__PURE__ */ jsxs29(
5515
5684
  "tr",
5516
5685
  {
5517
5686
  className: onSelect ? "b316-row-clickable" : void 0,
5518
5687
  onClick: onSelect ? () => onSelect(record) : void 0,
5519
5688
  children: [
5520
- shown.map((field) => /* @__PURE__ */ jsx30("td", { children: renderCell?.(record, field) ?? /* @__PURE__ */ jsx30(
5689
+ shown.map((field) => /* @__PURE__ */ jsx31("td", { children: renderCell?.(record, field) ?? /* @__PURE__ */ jsx31(
5521
5690
  FieldCell,
5522
5691
  {
5523
5692
  value: record.fields[field.key] ?? null,
@@ -5526,7 +5695,7 @@ function DataTable({
5526
5695
  }
5527
5696
  ) }, field.key)),
5528
5697
  writable ? /* @__PURE__ */ jsxs29("td", { className: "b316-table-rowactions", children: [
5529
- /* @__PURE__ */ jsx30(
5698
+ /* @__PURE__ */ jsx31(
5530
5699
  "button",
5531
5700
  {
5532
5701
  type: "button",
@@ -5538,7 +5707,7 @@ function DataTable({
5538
5707
  children: "Edit"
5539
5708
  }
5540
5709
  ),
5541
- /* @__PURE__ */ jsx30(
5710
+ /* @__PURE__ */ jsx31(
5542
5711
  ConfirmButton,
5543
5712
  {
5544
5713
  className: "b316-button-quiet b316-danger",
@@ -5562,10 +5731,10 @@ function DataTable({
5562
5731
  record.id
5563
5732
  )) })
5564
5733
  ] }) }),
5565
- records.length === 0 && !loading ? /* @__PURE__ */ jsx30("div", { className: "b316-empty", children: emptyState ?? `No ${schema.namePlural.toLowerCase()} yet.` }) : null,
5566
- loading ? /* @__PURE__ */ jsx30("div", { className: "b316-empty", children: "Loading\u2026" }) : null,
5567
- hasMore ? /* @__PURE__ */ jsx30("div", { className: "b316-table-more", children: /* @__PURE__ */ jsx30("button", { type: "button", className: "b316-button-quiet", onClick: loadMore, disabled: loading, children: "Load more" }) }) : null,
5568
- editing ? /* @__PURE__ */ jsx30(
5734
+ records.length === 0 && !loading2 ? /* @__PURE__ */ jsx31("div", { className: "b316-empty", children: emptyState ?? `No ${schema.namePlural.toLowerCase()} yet.` }) : null,
5735
+ loading2 ? /* @__PURE__ */ jsx31("div", { className: "b316-empty", children: "Loading\u2026" }) : null,
5736
+ hasMore ? /* @__PURE__ */ jsx31("div", { className: "b316-table-more", children: /* @__PURE__ */ jsx31("button", { type: "button", className: "b316-button-quiet", onClick: loadMore, disabled: loading2, children: "Load more" }) }) : null,
5737
+ editing ? /* @__PURE__ */ jsx31(
5569
5738
  RecordForm,
5570
5739
  {
5571
5740
  collection,
@@ -5593,8 +5762,8 @@ import {
5593
5762
  specFor as specFor4,
5594
5763
  titleFieldOf
5595
5764
  } from "@base316/sdk";
5596
- import { useState as useState29 } from "react";
5597
- import { jsx as jsx31, jsxs as jsxs30 } from "react/jsx-runtime";
5765
+ import { useState as useState30 } from "react";
5766
+ import { jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
5598
5767
  function Kanban({
5599
5768
  collection,
5600
5769
  groupBy,
@@ -5605,23 +5774,23 @@ function Kanban({
5605
5774
  style,
5606
5775
  ...options
5607
5776
  }) {
5608
- const { schema, records, loading, error, canWrite, update, total, hasMore, loadMore } = useCollection(collection, {
5777
+ const { schema, records, loading: loading2, error, canWrite, update, total, hasMore, loadMore } = useCollection(collection, {
5609
5778
  // A board shows everything at once by its nature — a column holding the
5610
5779
  // first twenty-five of two hundred is misleading rather than partial.
5611
5780
  limit: options.limit ?? 100,
5612
5781
  ...options
5613
5782
  });
5614
- const [dragging, setDragging] = useState29(null);
5615
- const [over, setOver] = useState29(null);
5783
+ const [dragging, setDragging] = useState30(null);
5784
+ const [over, setOver] = useState30(null);
5616
5785
  if (error) {
5617
- return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx31("div", { className: "b316-error", role: "alert", children: error }) });
5786
+ return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx32("div", { className: "b316-error", role: "alert", children: error }) });
5618
5787
  }
5619
5788
  if (!schema) {
5620
- return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5789
+ return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5621
5790
  }
5622
5791
  const field = groupBy ? schema.fields.find((candidate) => candidate.key === groupBy) ?? null : defaultGroupFieldOf(schema.fields);
5623
5792
  if (!field || !specFor4(field).capabilities.groupable) {
5624
- return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: groupBy ? `"${groupBy}" cannot make columns. A board groups by a choice, a yes/no or a date.` : `${schema.namePlural} have no field to group by. Add a choice field \u2014 a status or a stage \u2014 and this board will use it.` });
5793
+ return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: groupBy ? `"${groupBy}" cannot make columns. A board groups by a choice, a yes/no or a date.` : `${schema.namePlural} have no field to group by. Add a choice field \u2014 a status or a stage \u2014 and this board will use it.` });
5625
5794
  }
5626
5795
  const columns = columnsFor(field);
5627
5796
  const shown = cardFields ? cardFields.map((key) => schema.fields.find((candidate) => candidate.key === key)).filter((candidate) => Boolean(candidate)) : (
@@ -5639,7 +5808,7 @@ function Kanban({
5639
5808
  await update(record.id, { [field.key]: value });
5640
5809
  }
5641
5810
  return /* @__PURE__ */ jsxs30("div", { className: cls("b316-board-wrap", className), style, children: [
5642
- /* @__PURE__ */ jsx31("div", { className: "b316-board", role: "list", children: columns.map((column) => {
5811
+ /* @__PURE__ */ jsx32("div", { className: "b316-board", role: "list", children: columns.map((column) => {
5643
5812
  const inColumn = records.filter(
5644
5813
  (record) => String(record.fields[field.key] ?? "") === String(column.value ?? "")
5645
5814
  );
@@ -5668,8 +5837,8 @@ function Kanban({
5668
5837
  },
5669
5838
  children: [
5670
5839
  /* @__PURE__ */ jsxs30("header", { className: "b316-board-head", children: [
5671
- /* @__PURE__ */ jsx31("span", { className: "b316-board-title", children: column.label }),
5672
- /* @__PURE__ */ jsx31("span", { className: "b316-muted", children: inColumn.length })
5840
+ /* @__PURE__ */ jsx32("span", { className: "b316-board-title", children: column.label }),
5841
+ /* @__PURE__ */ jsx32("span", { className: "b316-muted", children: inColumn.length })
5673
5842
  ] }),
5674
5843
  /* @__PURE__ */ jsxs30("div", { className: "b316-board-cards", children: [
5675
5844
  inColumn.map((record) => /* @__PURE__ */ jsxs30(
@@ -5684,10 +5853,10 @@ function Kanban({
5684
5853
  },
5685
5854
  onClick: onSelect ? () => onSelect(record) : void 0,
5686
5855
  children: [
5687
- /* @__PURE__ */ jsx31("div", { className: "b316-board-card-title", children: record.title ?? "Untitled" }),
5856
+ /* @__PURE__ */ jsx32("div", { className: "b316-board-card-title", children: record.title ?? "Untitled" }),
5688
5857
  shown.map((candidate) => /* @__PURE__ */ jsxs30("div", { className: "b316-board-card-field", children: [
5689
- /* @__PURE__ */ jsx31("span", { className: "b316-muted", children: candidate.label }),
5690
- /* @__PURE__ */ jsx31(
5858
+ /* @__PURE__ */ jsx32("span", { className: "b316-muted", children: candidate.label }),
5859
+ /* @__PURE__ */ jsx32(
5691
5860
  FieldCell,
5692
5861
  {
5693
5862
  value: record.fields[candidate.key] ?? null,
@@ -5701,8 +5870,8 @@ function Kanban({
5701
5870
  // phone. This is the same action by other means, not a
5702
5871
  // lesser fallback.
5703
5872
  /* @__PURE__ */ jsxs30("label", { className: "b316-board-move", children: [
5704
- /* @__PURE__ */ jsx31("span", { className: "b316-muted", children: "Move to" }),
5705
- /* @__PURE__ */ jsx31(
5873
+ /* @__PURE__ */ jsx32("span", { className: "b316-muted", children: "Move to" }),
5874
+ /* @__PURE__ */ jsx32(
5706
5875
  "select",
5707
5876
  {
5708
5877
  className: "b316-input",
@@ -5714,7 +5883,7 @@ function Kanban({
5714
5883
  );
5715
5884
  void move(record, chosen?.value ?? null);
5716
5885
  },
5717
- children: columns.map((candidate) => /* @__PURE__ */ jsx31("option", { value: String(candidate.value), children: candidate.label }, String(candidate.value)))
5886
+ children: columns.map((candidate) => /* @__PURE__ */ jsx32("option", { value: String(candidate.value), children: candidate.label }, String(candidate.value)))
5718
5887
  }
5719
5888
  )
5720
5889
  ] })
@@ -5723,14 +5892,14 @@ function Kanban({
5723
5892
  },
5724
5893
  record.id
5725
5894
  )),
5726
- inColumn.length === 0 ? /* @__PURE__ */ jsx31("div", { className: "b316-board-empty", children: emptyState ?? "Nothing here" }) : null
5895
+ inColumn.length === 0 ? /* @__PURE__ */ jsx32("div", { className: "b316-board-empty", children: emptyState ?? "Nothing here" }) : null
5727
5896
  ] })
5728
5897
  ]
5729
5898
  },
5730
5899
  String(column.value)
5731
5900
  );
5732
5901
  }) }),
5733
- hasMore ? /* @__PURE__ */ jsx31("div", { className: "b316-table-more", children: /* @__PURE__ */ jsxs30("button", { type: "button", className: "b316-button-quiet", onClick: loadMore, disabled: loading, children: [
5902
+ hasMore ? /* @__PURE__ */ jsx32("div", { className: "b316-table-more", children: /* @__PURE__ */ jsxs30("button", { type: "button", className: "b316-button-quiet", onClick: loadMore, disabled: loading2, children: [
5734
5903
  "Showing ",
5735
5904
  records.length,
5736
5905
  " of ",
@@ -5757,7 +5926,7 @@ import {
5757
5926
  specFor as specFor5
5758
5927
  } from "@base316/sdk";
5759
5928
  import { useMemo as useMemo4 } from "react";
5760
- import { jsx as jsx32, jsxs as jsxs31 } from "react/jsx-runtime";
5929
+ import { jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
5761
5930
  function Chart({
5762
5931
  collection,
5763
5932
  x,
@@ -5770,7 +5939,7 @@ function Chart({
5770
5939
  style,
5771
5940
  ...options
5772
5941
  }) {
5773
- const { schema, records, error, loading } = useCollection(collection, {
5942
+ const { schema, records, error, loading: loading2 } = useCollection(collection, {
5774
5943
  // A chart of one page is a chart of an arbitrary subset, which is worse
5775
5944
  // than no chart: it looks like an answer.
5776
5945
  limit: options.limit ?? 200,
@@ -5796,23 +5965,23 @@ function Chart({
5796
5965
  [records, axis, measure, aggregate, bucket, y]
5797
5966
  );
5798
5967
  if (error) {
5799
- return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx32("div", { className: "b316-error", role: "alert", children: error }) });
5968
+ return /* @__PURE__ */ jsx33("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx33("div", { className: "b316-error", role: "alert", children: error }) });
5800
5969
  }
5801
- if (!schema || loading) {
5802
- return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5970
+ if (!schema || loading2) {
5971
+ return /* @__PURE__ */ jsx33("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5803
5972
  }
5804
5973
  if (!axis) {
5805
- return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: x ? `"${x}" is not a date, so it cannot be a time axis.` : `${schema.namePlural} have no date field to chart against. Add one and this chart will use it.` });
5974
+ return /* @__PURE__ */ jsx33("div", { className: cls("b316-card", className), style, children: x ? `"${x}" is not a date, so it cannot be a time axis.` : `${schema.namePlural} have no date field to chart against. Add one and this chart will use it.` });
5806
5975
  }
5807
5976
  if (y && !measure) {
5808
- return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: `"${y}" cannot be ${aggregate === "avg" ? "averaged" : `combined with ${aggregate}`}.` });
5977
+ return /* @__PURE__ */ jsx33("div", { className: cls("b316-card", className), style, children: `"${y}" cannot be ${aggregate === "avg" ? "averaged" : `combined with ${aggregate}`}.` });
5809
5978
  }
5810
5979
  const peak = Math.max(...buckets.map((entry) => entry.value), 0);
5811
5980
  const heading = title ?? `${measure ? `${aggregate} of ${measure.label}` : schema.namePlural} by ${axis.label}`;
5812
5981
  return /* @__PURE__ */ jsxs31("figure", { className: cls("b316-card b316-chart", className), style, children: [
5813
- /* @__PURE__ */ jsx32("figcaption", { className: "b316-chart-title", children: heading }),
5814
- buckets.length === 0 || peak === 0 ? /* @__PURE__ */ jsx32("div", { className: "b316-empty", children: "Nothing to chart yet." }) : /* @__PURE__ */ jsx32("div", { className: "b316-chart-plot", style: { height }, children: buckets.map((entry) => /* @__PURE__ */ jsxs31("div", { className: "b316-chart-col", children: [
5815
- /* @__PURE__ */ jsx32(
5982
+ /* @__PURE__ */ jsx33("figcaption", { className: "b316-chart-title", children: heading }),
5983
+ buckets.length === 0 || peak === 0 ? /* @__PURE__ */ jsx33("div", { className: "b316-empty", children: "Nothing to chart yet." }) : /* @__PURE__ */ jsx33("div", { className: "b316-chart-plot", style: { height }, children: buckets.map((entry) => /* @__PURE__ */ jsxs31("div", { className: "b316-chart-col", children: [
5984
+ /* @__PURE__ */ jsx33(
5816
5985
  "div",
5817
5986
  {
5818
5987
  className: "b316-chart-bar",
@@ -5820,18 +5989,18 @@ function Chart({
5820
5989
  title: `${entry.label}: ${format(entry.value)}`
5821
5990
  }
5822
5991
  ),
5823
- /* @__PURE__ */ jsx32("span", { className: "b316-chart-label", children: entry.label })
5992
+ /* @__PURE__ */ jsx33("span", { className: "b316-chart-label", children: entry.label })
5824
5993
  ] }, entry.key)) }),
5825
5994
  /* @__PURE__ */ jsxs31("details", { className: "b316-chart-data", children: [
5826
- /* @__PURE__ */ jsx32("summary", { children: "Values" }),
5995
+ /* @__PURE__ */ jsx33("summary", { children: "Values" }),
5827
5996
  /* @__PURE__ */ jsxs31("table", { className: "b316-table", children: [
5828
- /* @__PURE__ */ jsx32("thead", { children: /* @__PURE__ */ jsxs31("tr", { children: [
5829
- /* @__PURE__ */ jsx32("th", { scope: "col", children: axis.label }),
5830
- /* @__PURE__ */ jsx32("th", { scope: "col", children: measure ? measure.label : "Count" })
5997
+ /* @__PURE__ */ jsx33("thead", { children: /* @__PURE__ */ jsxs31("tr", { children: [
5998
+ /* @__PURE__ */ jsx33("th", { scope: "col", children: axis.label }),
5999
+ /* @__PURE__ */ jsx33("th", { scope: "col", children: measure ? measure.label : "Count" })
5831
6000
  ] }) }),
5832
- /* @__PURE__ */ jsx32("tbody", { children: buckets.map((entry) => /* @__PURE__ */ jsxs31("tr", { children: [
5833
- /* @__PURE__ */ jsx32("td", { children: entry.label }),
5834
- /* @__PURE__ */ jsx32("td", { children: format(entry.value) })
6001
+ /* @__PURE__ */ jsx33("tbody", { children: buckets.map((entry) => /* @__PURE__ */ jsxs31("tr", { children: [
6002
+ /* @__PURE__ */ jsx33("td", { children: entry.label }),
6003
+ /* @__PURE__ */ jsx33("td", { children: format(entry.value) })
5835
6004
  ] }, entry.key)) })
5836
6005
  ] })
5837
6006
  ] })
@@ -5890,8 +6059,8 @@ function combine(values, aggregate) {
5890
6059
 
5891
6060
  // src/RecordDetail.tsx
5892
6061
  import { specFor as specFor6 } from "@base316/sdk";
5893
- import { useState as useState30 } from "react";
5894
- import { jsx as jsx33, jsxs as jsxs32 } from "react/jsx-runtime";
6062
+ import { useState as useState31 } from "react";
6063
+ import { jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
5895
6064
  function RecordDetail({
5896
6065
  collection,
5897
6066
  recordId,
@@ -5903,17 +6072,17 @@ function RecordDetail({
5903
6072
  className,
5904
6073
  style
5905
6074
  }) {
5906
- const { schema, records, canWrite, remove, loading, error } = useCollection(collection, {
6075
+ const { schema, records, canWrite, remove, loading: loading2, error } = useCollection(collection, {
5907
6076
  tenant,
5908
6077
  recordId
5909
6078
  });
5910
- const [editing, setEditing] = useState30(false);
6079
+ const [editing, setEditing] = useState31(false);
5911
6080
  const record = records.find((candidate) => candidate.id === recordId);
5912
6081
  if (error) {
5913
- return /* @__PURE__ */ jsx33("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx33("div", { className: "b316-error", role: "alert", children: error }) });
6082
+ return /* @__PURE__ */ jsx34("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx34("div", { className: "b316-error", role: "alert", children: error }) });
5914
6083
  }
5915
- if (!schema || loading) {
5916
- return /* @__PURE__ */ jsx33("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
6084
+ if (!schema || loading2) {
6085
+ return /* @__PURE__ */ jsx34("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5917
6086
  }
5918
6087
  if (!record) {
5919
6088
  return /* @__PURE__ */ jsxs32("div", { className: cls("b316-card", className), style, children: [
@@ -5923,7 +6092,7 @@ function RecordDetail({
5923
6092
  ] });
5924
6093
  }
5925
6094
  if (editing) {
5926
- return /* @__PURE__ */ jsx33(
6095
+ return /* @__PURE__ */ jsx34(
5927
6096
  RecordForm,
5928
6097
  {
5929
6098
  collection,
@@ -5939,10 +6108,10 @@ function RecordDetail({
5939
6108
  const writable = canWrite && !readOnly;
5940
6109
  return /* @__PURE__ */ jsxs32("div", { className: cls("b316-card b316-detail", className), style, children: [
5941
6110
  /* @__PURE__ */ jsxs32("div", { className: "b316-detail-head", children: [
5942
- /* @__PURE__ */ jsx33("h3", { className: "b316-detail-title", children: record.title ?? schema.name }),
6111
+ /* @__PURE__ */ jsx34("h3", { className: "b316-detail-title", children: record.title ?? schema.name }),
5943
6112
  /* @__PURE__ */ jsxs32("div", { className: "b316-detail-actions", children: [
5944
- writable ? /* @__PURE__ */ jsx33("button", { type: "button", className: "b316-button-quiet", onClick: () => setEditing(true), children: "Edit" }) : null,
5945
- writable ? /* @__PURE__ */ jsx33(
6113
+ writable ? /* @__PURE__ */ jsx34("button", { type: "button", className: "b316-button-quiet", onClick: () => setEditing(true), children: "Edit" }) : null,
6114
+ writable ? /* @__PURE__ */ jsx34(
5946
6115
  ConfirmButton,
5947
6116
  {
5948
6117
  className: "b316-button-quiet b316-danger",
@@ -5955,15 +6124,15 @@ function RecordDetail({
5955
6124
  children: "Delete"
5956
6125
  }
5957
6126
  ) : null,
5958
- onClose ? /* @__PURE__ */ jsx33("button", { type: "button", className: "b316-button-quiet", onClick: onClose, children: "Close" }) : null
6127
+ onClose ? /* @__PURE__ */ jsx34("button", { type: "button", className: "b316-button-quiet", onClick: onClose, children: "Close" }) : null
5959
6128
  ] })
5960
6129
  ] }),
5961
- /* @__PURE__ */ jsx33("dl", { className: "b316-detail-fields", children: schema.fields.map((field) => /* @__PURE__ */ jsxs32("div", { className: "b316-detail-row", children: [
6130
+ /* @__PURE__ */ jsx34("dl", { className: "b316-detail-fields", children: schema.fields.map((field) => /* @__PURE__ */ jsxs32("div", { className: "b316-detail-row", children: [
5962
6131
  /* @__PURE__ */ jsxs32("dt", { className: "b316-label", children: [
5963
6132
  field.label,
5964
- specFor6(field).computed ? /* @__PURE__ */ jsx33("span", { className: "b316-muted", children: " (calculated)" }) : null
6133
+ specFor6(field).computed ? /* @__PURE__ */ jsx34("span", { className: "b316-muted", children: " (calculated)" }) : null
5965
6134
  ] }),
5966
- /* @__PURE__ */ jsx33("dd", { children: /* @__PURE__ */ jsx33(
6135
+ /* @__PURE__ */ jsx34("dd", { children: /* @__PURE__ */ jsx34(
5967
6136
  FieldCell,
5968
6137
  {
5969
6138
  value: record.fields[field.key] ?? null,
@@ -5977,8 +6146,8 @@ function RecordDetail({
5977
6146
  }
5978
6147
 
5979
6148
  // src/SubscriptionManager.tsx
5980
- import { useCallback as useCallback10, useEffect as useEffect23, useState as useState31 } from "react";
5981
- import { jsx as jsx34, jsxs as jsxs33 } from "react/jsx-runtime";
6149
+ import { useCallback as useCallback11, useEffect as useEffect25, useState as useState32 } from "react";
6150
+ import { jsx as jsx35, jsxs as jsxs33 } from "react/jsx-runtime";
5982
6151
  function statusLabel(status2) {
5983
6152
  const words = status2.toLowerCase().split("_");
5984
6153
  return words.map((w, i) => i === 0 ? w.charAt(0).toUpperCase() + w.slice(1) : w).join(" ");
@@ -6018,16 +6187,16 @@ function SubscriptionManager({
6018
6187
  style
6019
6188
  }) {
6020
6189
  const { client, token, loading: sessionLoading } = useBase316();
6021
- const [subscription, setSubscription] = useState31(null);
6022
- const [loading, setLoading] = useState31(true);
6023
- const [managedBy, setManagedBy] = useState31(null);
6024
- const [schedule, setSchedule] = useState31([]);
6025
- const [busy, setBusy] = useState31(false);
6026
- const [error, setError] = useState31(null);
6027
- const [step, setStep] = useState31({ kind: "idle" });
6028
- const [reason, setReason] = useState31(null);
6029
- const [comment, setComment] = useState31("");
6030
- const load = useCallback10(async () => {
6190
+ const [subscription, setSubscription] = useState32(null);
6191
+ const [loading2, setLoading] = useState32(true);
6192
+ const [managedBy, setManagedBy] = useState32(null);
6193
+ const [schedule, setSchedule] = useState32([]);
6194
+ const [busy, setBusy] = useState32(false);
6195
+ const [error, setError] = useState32(null);
6196
+ const [step, setStep] = useState32({ kind: "idle" });
6197
+ const [reason, setReason] = useState32(null);
6198
+ const [comment, setComment] = useState32("");
6199
+ const load = useCallback11(async () => {
6031
6200
  if (!token) {
6032
6201
  setSubscription(null);
6033
6202
  setLoading(false);
@@ -6045,7 +6214,7 @@ function SubscriptionManager({
6045
6214
  setLoading(false);
6046
6215
  }
6047
6216
  }, [client, token]);
6048
- useEffect23(() => {
6217
+ useEffect25(() => {
6049
6218
  void load();
6050
6219
  }, [load]);
6051
6220
  const act = async (change, failure) => {
@@ -6062,24 +6231,24 @@ function SubscriptionManager({
6062
6231
  setBusy(false);
6063
6232
  }
6064
6233
  };
6065
- if (sessionLoading || loading) {
6066
- return /* @__PURE__ */ jsx34("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
6234
+ if (sessionLoading || loading2) {
6235
+ return /* @__PURE__ */ jsx35("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
6067
6236
  }
6068
6237
  if (!token) {
6069
- return /* @__PURE__ */ jsx34("div", { className: cls("b316-card", className), style, children: "Sign in to manage your subscription." });
6238
+ return /* @__PURE__ */ jsx35("div", { className: cls("b316-card", className), style, children: "Sign in to manage your subscription." });
6070
6239
  }
6071
6240
  if (error) {
6072
- return /* @__PURE__ */ jsx34("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx34("div", { className: "b316-error", role: "alert", children: error }) });
6241
+ return /* @__PURE__ */ jsx35("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx35("div", { className: "b316-error", role: "alert", children: error }) });
6073
6242
  }
6074
6243
  if (!subscription) {
6075
- return /* @__PURE__ */ jsx34("div", { className: cls("b316-card", className), style, children: "You are not subscribed to a plan." });
6244
+ return /* @__PURE__ */ jsx35("div", { className: cls("b316-card", className), style, children: "You are not subscribed to a plan." });
6076
6245
  }
6077
6246
  const renews = new Date(subscription.currentPeriodEnd).toLocaleDateString();
6078
6247
  const next = schedule[0] ?? null;
6079
6248
  const nextOn = next?.effectiveAt ? new Date(next.effectiveAt).toLocaleDateString() : renews;
6080
6249
  return /* @__PURE__ */ jsxs33("div", { className: cls("b316-card", className), style, children: [
6081
- error ? /* @__PURE__ */ jsx34("div", { className: "b316-error", role: "alert", children: error }) : null,
6082
- /* @__PURE__ */ jsx34("div", { className: "b316-plan-name", children: subscription.planVersion.plan.name }),
6250
+ error ? /* @__PURE__ */ jsx35("div", { className: "b316-error", role: "alert", children: error }) : null,
6251
+ /* @__PURE__ */ jsx35("div", { className: "b316-plan-name", children: subscription.planVersion.plan.name }),
6083
6252
  /* @__PURE__ */ jsxs33("div", { className: "b316-muted", children: [
6084
6253
  statusLabel(subscription.status),
6085
6254
  " \xB7 ",
@@ -6093,7 +6262,7 @@ function SubscriptionManager({
6093
6262
  ". You keep ",
6094
6263
  subscription.planVersion.plan.name,
6095
6264
  " until then.",
6096
- /* @__PURE__ */ jsx34("div", { children: /* @__PURE__ */ jsx34(
6265
+ /* @__PURE__ */ jsx35("div", { children: /* @__PURE__ */ jsx35(
6097
6266
  "button",
6098
6267
  {
6099
6268
  type: "button",
@@ -6128,7 +6297,7 @@ function SubscriptionManager({
6128
6297
  renews,
6129
6298
  "."
6130
6299
  ] }),
6131
- /* @__PURE__ */ jsx34(
6300
+ /* @__PURE__ */ jsx35(
6132
6301
  "button",
6133
6302
  {
6134
6303
  type: "button",
@@ -6139,13 +6308,13 @@ function SubscriptionManager({
6139
6308
  }
6140
6309
  )
6141
6310
  ] }) : step.kind === "offer" ? /* @__PURE__ */ jsxs33("section", { style: { marginTop: 14 }, "aria-label": "Retention offer", children: [
6142
- /* @__PURE__ */ jsx34("div", { className: "b316-plan-name", children: step.cancellation.offer.headline ?? "Before you go" }),
6143
- /* @__PURE__ */ jsx34("p", { className: "b316-muted", children: step.cancellation.offer.message ?? `Stay on ${subscription.planVersion.plan.name} and get ${describeRetentionOffer(
6311
+ /* @__PURE__ */ jsx35("div", { className: "b316-plan-name", children: step.cancellation.offer.headline ?? "Before you go" }),
6312
+ /* @__PURE__ */ jsx35("p", { className: "b316-muted", children: step.cancellation.offer.message ?? `Stay on ${subscription.planVersion.plan.name} and get ${describeRetentionOffer(
6144
6313
  step.cancellation.offer,
6145
6314
  step.cancellation.currency
6146
6315
  )}.` }),
6147
6316
  /* @__PURE__ */ jsxs33("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
6148
- /* @__PURE__ */ jsx34(
6317
+ /* @__PURE__ */ jsx35(
6149
6318
  "button",
6150
6319
  {
6151
6320
  type: "button",
@@ -6158,7 +6327,7 @@ function SubscriptionManager({
6158
6327
  children: busy ? "Working\u2026" : "Accept offer and stay"
6159
6328
  }
6160
6329
  ),
6161
- /* @__PURE__ */ jsx34(
6330
+ /* @__PURE__ */ jsx35(
6162
6331
  "button",
6163
6332
  {
6164
6333
  type: "button",
@@ -6203,9 +6372,9 @@ function SubscriptionManager({
6203
6372
  ". It will not renew after that."
6204
6373
  ] }),
6205
6374
  /* @__PURE__ */ jsxs33("fieldset", { className: "b316-fieldset", children: [
6206
- /* @__PURE__ */ jsx34("legend", { className: "b316-label", children: "Why are you leaving? (optional)" }),
6375
+ /* @__PURE__ */ jsx35("legend", { className: "b316-label", children: "Why are you leaving? (optional)" }),
6207
6376
  REASONS.map((option) => /* @__PURE__ */ jsxs33("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
6208
- /* @__PURE__ */ jsx34(
6377
+ /* @__PURE__ */ jsx35(
6209
6378
  "input",
6210
6379
  {
6211
6380
  type: "radio",
@@ -6215,12 +6384,12 @@ function SubscriptionManager({
6215
6384
  onChange: () => setReason(option.value)
6216
6385
  }
6217
6386
  ),
6218
- /* @__PURE__ */ jsx34("span", { children: option.label })
6387
+ /* @__PURE__ */ jsx35("span", { children: option.label })
6219
6388
  ] }, option.value))
6220
6389
  ] }),
6221
6390
  /* @__PURE__ */ jsxs33("label", { className: "b316-field", children: [
6222
- /* @__PURE__ */ jsx34("span", { className: "b316-label", children: "Anything else? (optional)" }),
6223
- /* @__PURE__ */ jsx34(
6391
+ /* @__PURE__ */ jsx35("span", { className: "b316-label", children: "Anything else? (optional)" }),
6392
+ /* @__PURE__ */ jsx35(
6224
6393
  "textarea",
6225
6394
  {
6226
6395
  className: "b316-input",
@@ -6232,7 +6401,7 @@ function SubscriptionManager({
6232
6401
  )
6233
6402
  ] }),
6234
6403
  /* @__PURE__ */ jsxs33("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
6235
- /* @__PURE__ */ jsx34("button", { type: "submit", className: "b316-button b316-button-secondary", disabled: busy, children: busy ? "Working\u2026" : "Cancel subscription" }),
6404
+ /* @__PURE__ */ jsx35("button", { type: "submit", className: "b316-button b316-button-secondary", disabled: busy, children: busy ? "Working\u2026" : "Cancel subscription" }),
6236
6405
  /* @__PURE__ */ jsxs33(
6237
6406
  "button",
6238
6407
  {
@@ -6249,7 +6418,7 @@ function SubscriptionManager({
6249
6418
  ] })
6250
6419
  ]
6251
6420
  }
6252
- ) : /* @__PURE__ */ jsx34("div", { style: { marginTop: 14 }, children: /* @__PURE__ */ jsx34(
6421
+ ) : /* @__PURE__ */ jsx35("div", { style: { marginTop: 14 }, children: /* @__PURE__ */ jsx35(
6253
6422
  "button",
6254
6423
  {
6255
6424
  type: "button",
@@ -6267,11 +6436,11 @@ function SubscriptionManager({
6267
6436
  }
6268
6437
 
6269
6438
  // src/BillingPortal.tsx
6270
- import { useCallback as useCallback12, useEffect as useEffect27, useState as useState35 } from "react";
6439
+ import { useCallback as useCallback13, useEffect as useEffect29, useState as useState36 } from "react";
6271
6440
 
6272
6441
  // src/CreditBalances.tsx
6273
- import { useEffect as useEffect24, useState as useState32 } from "react";
6274
- import { Fragment as Fragment11, jsx as jsx35, jsxs as jsxs34 } from "react/jsx-runtime";
6442
+ import { useEffect as useEffect26, useState as useState33 } from "react";
6443
+ import { Fragment as Fragment11, jsx as jsx36, jsxs as jsxs34 } from "react/jsx-runtime";
6275
6444
  function units(value) {
6276
6445
  return value === null ? "Unlimited" : Number(value).toLocaleString("en");
6277
6446
  }
@@ -6306,10 +6475,10 @@ function Feature({
6306
6475
  }) {
6307
6476
  const { client, token } = useBase316();
6308
6477
  const setting = feature.autoRecharge;
6309
- const [busy, setBusy] = useState32(false);
6310
- const [error, setError] = useState32(null);
6311
- const [saved, setSaved] = useState32(null);
6312
- const [pack, setPack] = useState32(feature.packs[0]?.id ?? "");
6478
+ const [busy, setBusy] = useState33(false);
6479
+ const [error, setError] = useState33(null);
6480
+ const [saved, setSaved] = useState33(null);
6481
+ const [pack, setPack] = useState33(feature.packs[0]?.id ?? "");
6313
6482
  const unit = feature.unit ? ` ${feature.unit}` : "";
6314
6483
  const warning = status(feature);
6315
6484
  const buy = async () => {
@@ -6364,9 +6533,9 @@ function Feature({
6364
6533
  }
6365
6534
  };
6366
6535
  return /* @__PURE__ */ jsxs34("div", { className: "b316-card b316-credit-balance", children: [
6367
- /* @__PURE__ */ jsx35("div", { className: "b316-label", children: feature.featureName }),
6536
+ /* @__PURE__ */ jsx36("div", { className: "b316-label", children: feature.featureName }),
6368
6537
  /* @__PURE__ */ jsxs34("div", { children: [
6369
- /* @__PURE__ */ jsx35("strong", { children: units(feature.remaining) }),
6538
+ /* @__PURE__ */ jsx36("strong", { children: units(feature.remaining) }),
6370
6539
  unit,
6371
6540
  " left"
6372
6541
  ] }),
@@ -6377,12 +6546,12 @@ function Feature({
6377
6546
  units(feature.purchasedRemaining),
6378
6547
  " purchased"
6379
6548
  ] }),
6380
- warning && !managed ? /* @__PURE__ */ jsx35("div", { className: "b316-error", role: "alert", children: warning }) : null,
6381
- error ? /* @__PURE__ */ jsx35("div", { className: "b316-error", role: "alert", children: error }) : null,
6382
- saved ? /* @__PURE__ */ jsx35("div", { className: "b316-notice", role: "status", children: saved }) : null,
6549
+ warning && !managed ? /* @__PURE__ */ jsx36("div", { className: "b316-error", role: "alert", children: warning }) : null,
6550
+ error ? /* @__PURE__ */ jsx36("div", { className: "b316-error", role: "alert", children: error }) : null,
6551
+ saved ? /* @__PURE__ */ jsx36("div", { className: "b316-notice", role: "status", children: saved }) : null,
6383
6552
  managed || feature.packs.length === 0 ? null : /* @__PURE__ */ jsxs34(Fragment11, { children: [
6384
6553
  /* @__PURE__ */ jsxs34("div", { className: "b316-row", style: { marginTop: 12 }, children: [
6385
- /* @__PURE__ */ jsx35(
6554
+ /* @__PURE__ */ jsx36(
6386
6555
  "select",
6387
6556
  {
6388
6557
  className: "b316-input",
@@ -6398,7 +6567,7 @@ function Feature({
6398
6567
  ] }, option.id))
6399
6568
  }
6400
6569
  ),
6401
- /* @__PURE__ */ jsx35(
6570
+ /* @__PURE__ */ jsx36(
6402
6571
  "button",
6403
6572
  {
6404
6573
  type: "button",
@@ -6411,7 +6580,7 @@ function Feature({
6411
6580
  ] }),
6412
6581
  /* @__PURE__ */ jsxs34("form", { onSubmit: save, style: { marginTop: 16 }, children: [
6413
6582
  /* @__PURE__ */ jsxs34("label", { className: "b316-checkbox", children: [
6414
- /* @__PURE__ */ jsx35("input", { type: "checkbox", name: "enabled", defaultChecked: setting?.enabled ?? false }),
6583
+ /* @__PURE__ */ jsx36("input", { type: "checkbox", name: "enabled", defaultChecked: setting?.enabled ?? false }),
6415
6584
  " ",
6416
6585
  "Buy credits automatically when my balance runs low"
6417
6586
  ] }),
@@ -6421,7 +6590,7 @@ function Feature({
6421
6590
  unit,
6422
6591
  " are left"
6423
6592
  ] }),
6424
- /* @__PURE__ */ jsx35(
6593
+ /* @__PURE__ */ jsx36(
6425
6594
  "input",
6426
6595
  {
6427
6596
  className: "b316-input",
@@ -6433,20 +6602,20 @@ function Feature({
6433
6602
  )
6434
6603
  ] }),
6435
6604
  /* @__PURE__ */ jsxs34("label", { className: "b316-field", children: [
6436
- /* @__PURE__ */ jsx35("span", { className: "b316-label", children: "Buy" }),
6437
- /* @__PURE__ */ jsx35(
6605
+ /* @__PURE__ */ jsx36("span", { className: "b316-label", children: "Buy" }),
6606
+ /* @__PURE__ */ jsx36(
6438
6607
  "select",
6439
6608
  {
6440
6609
  className: "b316-input",
6441
6610
  name: "creditPackId",
6442
6611
  defaultValue: setting?.creditPackId ?? feature.packs[0]?.id,
6443
- children: feature.packs.map((option) => /* @__PURE__ */ jsx35("option", { value: option.id, children: option.name }, option.id))
6612
+ children: feature.packs.map((option) => /* @__PURE__ */ jsx36("option", { value: option.id, children: option.name }, option.id))
6444
6613
  }
6445
6614
  )
6446
6615
  ] }),
6447
6616
  /* @__PURE__ */ jsxs34("label", { className: "b316-field", children: [
6448
- /* @__PURE__ */ jsx35("span", { className: "b316-label", children: "At most this many times a month" }),
6449
- /* @__PURE__ */ jsx35(
6617
+ /* @__PURE__ */ jsx36("span", { className: "b316-label", children: "At most this many times a month" }),
6618
+ /* @__PURE__ */ jsx36(
6450
6619
  "input",
6451
6620
  {
6452
6621
  className: "b316-input",
@@ -6462,7 +6631,7 @@ function Feature({
6462
6631
  setting?.currency ?? feature.packs[0]?.currency ?? "USD",
6463
6632
  ") a month"
6464
6633
  ] }),
6465
- /* @__PURE__ */ jsx35(
6634
+ /* @__PURE__ */ jsx36(
6466
6635
  "input",
6467
6636
  {
6468
6637
  className: "b316-input",
@@ -6472,16 +6641,16 @@ function Feature({
6472
6641
  }
6473
6642
  )
6474
6643
  ] }),
6475
- /* @__PURE__ */ jsx35("button", { type: "submit", className: "b316-button", disabled: busy, children: "Save auto-recharge" })
6644
+ /* @__PURE__ */ jsx36("button", { type: "submit", className: "b316-button", disabled: busy, children: "Save auto-recharge" })
6476
6645
  ] })
6477
6646
  ] })
6478
6647
  ] });
6479
6648
  }
6480
6649
  function CreditBalances({ onChange, className, style }) {
6481
6650
  const { client, token, loading: sessionLoading } = useBase316();
6482
- const [state, setState] = useState32({ kind: "loading" });
6483
- const [version, setVersion] = useState32(0);
6484
- useEffect24(() => {
6651
+ const [state, setState] = useState33({ kind: "loading" });
6652
+ const [version, setVersion] = useState33(0);
6653
+ useEffect26(() => {
6485
6654
  if (!token) return;
6486
6655
  let cancelled = false;
6487
6656
  client.billing.credits(token).then((credits2) => {
@@ -6494,11 +6663,11 @@ function CreditBalances({ onChange, className, style }) {
6494
6663
  cancelled = true;
6495
6664
  };
6496
6665
  }, [client, token, version]);
6497
- const wrap = (content) => /* @__PURE__ */ jsx35("div", { className: cls("b316-credit-balances", className), style, children: content });
6666
+ const wrap = (content) => /* @__PURE__ */ jsx36("div", { className: cls("b316-credit-balances", className), style, children: content });
6498
6667
  if (sessionLoading || !token || state.kind === "loading") return null;
6499
6668
  if (state.kind === "error") {
6500
6669
  return wrap(
6501
- /* @__PURE__ */ jsx35("div", { className: "b316-card", children: /* @__PURE__ */ jsx35("div", { className: "b316-error", role: "alert", children: "Could not load your credits." }) })
6670
+ /* @__PURE__ */ jsx36("div", { className: "b316-card", children: /* @__PURE__ */ jsx36("div", { className: "b316-error", role: "alert", children: "Could not load your credits." }) })
6502
6671
  );
6503
6672
  }
6504
6673
  const { credits } = state;
@@ -6511,7 +6680,7 @@ function CreditBalances({ onChange, className, style }) {
6511
6680
  credits.managedBy.name ?? "the organization that manages it",
6512
6681
  ", which manages them."
6513
6682
  ] }) : null,
6514
- credits.features.map((feature) => /* @__PURE__ */ jsx35(
6683
+ credits.features.map((feature) => /* @__PURE__ */ jsx36(
6515
6684
  Feature,
6516
6685
  {
6517
6686
  feature,
@@ -6528,19 +6697,19 @@ function CreditBalances({ onChange, className, style }) {
6528
6697
  }
6529
6698
 
6530
6699
  // src/PaymentMethod.tsx
6531
- import { useEffect as useEffect25, useState as useState33 } from "react";
6532
- import { Fragment as Fragment12, jsx as jsx36, jsxs as jsxs35 } from "react/jsx-runtime";
6700
+ import { useEffect as useEffect27, useState as useState34 } from "react";
6701
+ import { Fragment as Fragment12, jsx as jsx37, jsxs as jsxs35 } from "react/jsx-runtime";
6533
6702
  function brandName(brand) {
6534
6703
  if (!brand) return "Card";
6535
6704
  return brand.charAt(0).toUpperCase() + brand.slice(1);
6536
6705
  }
6537
6706
  function PaymentMethod({ returnUrl, className, style }) {
6538
6707
  const { client, token, loading: sessionLoading } = useBase316();
6539
- const [state, setState] = useState33({ kind: "loading" });
6540
- const [busy, setBusy] = useState33(false);
6541
- const [error, setError] = useState33(null);
6542
- const [version, setVersion] = useState33(0);
6543
- useEffect25(() => {
6708
+ const [state, setState] = useState34({ kind: "loading" });
6709
+ const [busy, setBusy] = useState34(false);
6710
+ const [error, setError] = useState34(null);
6711
+ const [version, setVersion] = useState34(0);
6712
+ useEffect27(() => {
6544
6713
  if (!token) return;
6545
6714
  let cancelled = false;
6546
6715
  client.billing.paymentMethods(token).then((result) => {
@@ -6556,7 +6725,7 @@ function PaymentMethod({ returnUrl, className, style }) {
6556
6725
  cancelled = true;
6557
6726
  };
6558
6727
  }, [client, token, version]);
6559
- const wrap = (content) => /* @__PURE__ */ jsx36("div", { className: cls("b316-card b316-payment-method", className), style, children: content });
6728
+ const wrap = (content) => /* @__PURE__ */ jsx37("div", { className: cls("b316-card b316-payment-method", className), style, children: content });
6560
6729
  if (sessionLoading) return wrap("Loading\u2026");
6561
6730
  if (!token) return wrap("Sign in to manage your payment method.");
6562
6731
  switch (state.kind) {
@@ -6564,11 +6733,11 @@ function PaymentMethod({ returnUrl, className, style }) {
6564
6733
  return wrap("Loading\u2026");
6565
6734
  case "error":
6566
6735
  return wrap(
6567
- /* @__PURE__ */ jsx36("div", { className: "b316-error", role: "alert", children: "Could not load your payment method." })
6736
+ /* @__PURE__ */ jsx37("div", { className: "b316-error", role: "alert", children: "Could not load your payment method." })
6568
6737
  );
6569
6738
  case "managed":
6570
6739
  return wrap(
6571
- /* @__PURE__ */ jsx36("p", { className: "b316-muted", children: "Your plan is paid for by the organization that manages it." })
6740
+ /* @__PURE__ */ jsx37("p", { className: "b316-muted", children: "Your plan is paid for by the organization that manages it." })
6572
6741
  );
6573
6742
  }
6574
6743
  const card = state.cards.find((saved) => saved.isDefault) ?? null;
@@ -6588,7 +6757,7 @@ function PaymentMethod({ returnUrl, className, style }) {
6588
6757
  };
6589
6758
  return wrap(
6590
6759
  /* @__PURE__ */ jsxs35(Fragment12, { children: [
6591
- /* @__PURE__ */ jsx36("div", { className: "b316-label", children: "Payment method" }),
6760
+ /* @__PURE__ */ jsx37("div", { className: "b316-label", children: "Payment method" }),
6592
6761
  card ? /* @__PURE__ */ jsxs35("div", { children: [
6593
6762
  /* @__PURE__ */ jsxs35("div", { children: [
6594
6763
  brandName(card.brand),
@@ -6601,9 +6770,9 @@ function PaymentMethod({ returnUrl, className, style }) {
6601
6770
  "/",
6602
6771
  card.expYear
6603
6772
  ] }) : null
6604
- ] }) : /* @__PURE__ */ jsx36("p", { className: "b316-muted", children: "No card on file." }),
6773
+ ] }) : /* @__PURE__ */ jsx37("p", { className: "b316-muted", children: "No card on file." }),
6605
6774
  others.length > 0 ? /* @__PURE__ */ jsxs35("div", { style: { marginTop: 12 }, children: [
6606
- /* @__PURE__ */ jsx36("div", { className: "b316-label", children: "Other saved cards" }),
6775
+ /* @__PURE__ */ jsx37("div", { className: "b316-label", children: "Other saved cards" }),
6607
6776
  others.map((saved) => /* @__PURE__ */ jsxs35("div", { className: "b316-row", style: { marginTop: 6 }, children: [
6608
6777
  /* @__PURE__ */ jsxs35("span", { children: [
6609
6778
  brandName(saved.brand),
@@ -6611,7 +6780,7 @@ function PaymentMethod({ returnUrl, className, style }) {
6611
6780
  saved.last4 ?? "????"
6612
6781
  ] }),
6613
6782
  /* @__PURE__ */ jsxs35("span", { children: [
6614
- /* @__PURE__ */ jsx36(
6783
+ /* @__PURE__ */ jsx37(
6615
6784
  "button",
6616
6785
  {
6617
6786
  type: "button",
@@ -6625,7 +6794,7 @@ function PaymentMethod({ returnUrl, className, style }) {
6625
6794
  }
6626
6795
  ),
6627
6796
  " ",
6628
- /* @__PURE__ */ jsx36(
6797
+ /* @__PURE__ */ jsx37(
6629
6798
  "button",
6630
6799
  {
6631
6800
  type: "button",
@@ -6641,8 +6810,8 @@ function PaymentMethod({ returnUrl, className, style }) {
6641
6810
  ] })
6642
6811
  ] }, saved.id))
6643
6812
  ] }) : null,
6644
- error ? /* @__PURE__ */ jsx36("div", { className: "b316-error", role: "alert", children: error }) : null,
6645
- /* @__PURE__ */ jsx36(
6813
+ error ? /* @__PURE__ */ jsx37("div", { className: "b316-error", role: "alert", children: error }) : null,
6814
+ /* @__PURE__ */ jsx37(
6646
6815
  "button",
6647
6816
  {
6648
6817
  type: "button",
@@ -6671,8 +6840,8 @@ function PaymentMethod({ returnUrl, className, style }) {
6671
6840
  }
6672
6841
 
6673
6842
  // src/PlanChangeReview.tsx
6674
- import { useCallback as useCallback11, useEffect as useEffect26, useState as useState34 } from "react";
6675
- import { Fragment as Fragment13, jsx as jsx37, jsxs as jsxs36 } from "react/jsx-runtime";
6843
+ import { useCallback as useCallback12, useEffect as useEffect28, useState as useState35 } from "react";
6844
+ import { Fragment as Fragment13, jsx as jsx38, jsxs as jsxs36 } from "react/jsx-runtime";
6676
6845
  function money5(amount, currency) {
6677
6846
  if (amount === null) return "\u2014";
6678
6847
  const value = Number(amount);
@@ -6705,12 +6874,12 @@ function PlanChangeReview({
6705
6874
  style
6706
6875
  }) {
6707
6876
  const { client, token } = useBase316();
6708
- const [timing, setTiming] = useState34(void 0);
6709
- const [preview, setPreview] = useState34(null);
6710
- const [error, setError] = useState34(null);
6711
- const [needsCard, setNeedsCard] = useState34(false);
6712
- const [busy, setBusy] = useState34(false);
6713
- useEffect26(() => {
6877
+ const [timing, setTiming] = useState35(void 0);
6878
+ const [preview, setPreview] = useState35(null);
6879
+ const [error, setError] = useState35(null);
6880
+ const [needsCard, setNeedsCard] = useState35(false);
6881
+ const [busy, setBusy] = useState35(false);
6882
+ useEffect28(() => {
6714
6883
  if (!token) return;
6715
6884
  let cancelled = false;
6716
6885
  client.billing.previewPlanChange(token, planVersionId, timing).then((result) => {
@@ -6727,7 +6896,7 @@ function PlanChangeReview({
6727
6896
  cancelled = true;
6728
6897
  };
6729
6898
  }, [client, token, planVersionId, timing]);
6730
- const confirm = useCallback11(async () => {
6899
+ const confirm = useCallback12(async () => {
6731
6900
  if (!token || !preview) return;
6732
6901
  setBusy(true);
6733
6902
  setError(null);
@@ -6748,7 +6917,7 @@ function PlanChangeReview({
6748
6917
  setBusy(false);
6749
6918
  }
6750
6919
  }, [client, token, preview, planVersionId, onDone]);
6751
- const addCard = useCallback11(async () => {
6920
+ const addCard = useCallback12(async () => {
6752
6921
  if (onNeedsCard) {
6753
6922
  onNeedsCard();
6754
6923
  return;
@@ -6762,12 +6931,12 @@ function PlanChangeReview({
6762
6931
  setError("Cards cannot be added here right now.");
6763
6932
  }
6764
6933
  }, [client, token, onNeedsCard]);
6765
- const card = (content) => /* @__PURE__ */ jsx37("div", { className: cls("b316-card b316-plan-review", className), style, children: content });
6934
+ const card = (content) => /* @__PURE__ */ jsx38("div", { className: cls("b316-card b316-plan-review", className), style, children: content });
6766
6935
  if (error && !preview) {
6767
6936
  return card(
6768
6937
  /* @__PURE__ */ jsxs36(Fragment13, { children: [
6769
- /* @__PURE__ */ jsx37("div", { className: "b316-error", role: "alert", children: error }),
6770
- onCancel ? /* @__PURE__ */ jsx37("button", { type: "button", className: "b316-button b316-button-secondary", onClick: onCancel, children: "Back" }) : null
6938
+ /* @__PURE__ */ jsx38("div", { className: "b316-error", role: "alert", children: error }),
6939
+ onCancel ? /* @__PURE__ */ jsx38("button", { type: "button", className: "b316-button b316-button-secondary", onClick: onCancel, children: "Back" }) : null
6771
6940
  ] })
6772
6941
  );
6773
6942
  }
@@ -6789,17 +6958,17 @@ function PlanChangeReview({
6789
6958
  "From ",
6790
6959
  from.planName
6791
6960
  ] }),
6792
- error ? /* @__PURE__ */ jsx37("div", { className: "b316-error", role: "alert", children: error }) : null,
6793
- changes.length === 0 ? /* @__PURE__ */ jsx37("p", { className: "b316-muted", children: "Every feature stays the same." }) : /* @__PURE__ */ jsxs36("table", { className: "b316-review-table", children: [
6794
- /* @__PURE__ */ jsx37("thead", { children: /* @__PURE__ */ jsxs36("tr", { children: [
6795
- /* @__PURE__ */ jsx37("th", { children: "Feature" }),
6796
- /* @__PURE__ */ jsx37("th", { children: from.planName }),
6797
- /* @__PURE__ */ jsx37("th", { children: to.planName })
6961
+ error ? /* @__PURE__ */ jsx38("div", { className: "b316-error", role: "alert", children: error }) : null,
6962
+ changes.length === 0 ? /* @__PURE__ */ jsx38("p", { className: "b316-muted", children: "Every feature stays the same." }) : /* @__PURE__ */ jsxs36("table", { className: "b316-review-table", children: [
6963
+ /* @__PURE__ */ jsx38("thead", { children: /* @__PURE__ */ jsxs36("tr", { children: [
6964
+ /* @__PURE__ */ jsx38("th", { children: "Feature" }),
6965
+ /* @__PURE__ */ jsx38("th", { children: from.planName }),
6966
+ /* @__PURE__ */ jsx38("th", { children: to.planName })
6798
6967
  ] }) }),
6799
- /* @__PURE__ */ jsx37("tbody", { children: changes.map((change) => /* @__PURE__ */ jsxs36("tr", { children: [
6800
- /* @__PURE__ */ jsx37("td", { children: change.featureName }),
6801
- /* @__PURE__ */ jsx37("td", { children: limitText(change.before, change.type) }),
6802
- /* @__PURE__ */ jsx37(
6968
+ /* @__PURE__ */ jsx38("tbody", { children: changes.map((change) => /* @__PURE__ */ jsxs36("tr", { children: [
6969
+ /* @__PURE__ */ jsx38("td", { children: change.featureName }),
6970
+ /* @__PURE__ */ jsx38("td", { children: limitText(change.before, change.type) }),
6971
+ /* @__PURE__ */ jsx38(
6803
6972
  "td",
6804
6973
  {
6805
6974
  className: change.change === "GAINED" || change.change === "INCREASED" ? "b316-review-gain" : "b316-review-loss",
@@ -6824,8 +6993,8 @@ function PlanChangeReview({
6824
6993
  ] })
6825
6994
  ] }) : null,
6826
6995
  Number(now.closingUsage) > 0 ? /* @__PURE__ */ jsxs36("div", { className: "b316-row", children: [
6827
- /* @__PURE__ */ jsx37("span", { className: "b316-muted", children: "Usage so far this period" }),
6828
- /* @__PURE__ */ jsx37("span", { className: "b316-num", children: money5(now.closingUsage, from.currency) })
6996
+ /* @__PURE__ */ jsx38("span", { className: "b316-muted", children: "Usage so far this period" }),
6997
+ /* @__PURE__ */ jsx38("span", { className: "b316-num", children: money5(now.closingUsage, from.currency) })
6829
6998
  ] }) : null,
6830
6999
  /* @__PURE__ */ jsxs36("div", { className: "b316-row", children: [
6831
7000
  /* @__PURE__ */ jsxs36("span", { className: "b316-muted", children: [
@@ -6835,11 +7004,11 @@ function PlanChangeReview({
6835
7004
  " \u2013 ",
6836
7005
  day4(now.newPeriod.end)
6837
7006
  ] }),
6838
- /* @__PURE__ */ jsx37("span", { className: "b316-num", children: money5(now.newPeriodCharge, to.currency) })
7007
+ /* @__PURE__ */ jsx38("span", { className: "b316-num", children: money5(now.newPeriodCharge, to.currency) })
6839
7008
  ] }),
6840
7009
  now.net !== null ? /* @__PURE__ */ jsxs36("div", { className: "b316-row b316-invoice-total", children: [
6841
- /* @__PURE__ */ jsx37("span", { children: "Due now" }),
6842
- /* @__PURE__ */ jsx37("span", { className: "b316-num", children: money5(now.net, to.currency) })
7010
+ /* @__PURE__ */ jsx38("span", { children: "Due now" }),
7011
+ /* @__PURE__ */ jsx38("span", { className: "b316-num", children: money5(now.net, to.currency) })
6843
7012
  ] }) : null
6844
7013
  ] }) : /* @__PURE__ */ jsxs36("p", { children: [
6845
7014
  "You keep ",
@@ -6854,7 +7023,7 @@ function PlanChangeReview({
6854
7023
  preview.atPeriodEnd.nextInvoice.currency
6855
7024
  )}.` : ""
6856
7025
  ] }),
6857
- otherOpen ? /* @__PURE__ */ jsx37(
7026
+ otherOpen ? /* @__PURE__ */ jsx38(
6858
7027
  "button",
6859
7028
  {
6860
7029
  type: "button",
@@ -6865,12 +7034,12 @@ function PlanChangeReview({
6865
7034
  },
6866
7035
  children: other === "NOW" ? "Change now instead" : "Wait until the end of the period instead"
6867
7036
  }
6868
- ) : otherReason && TIMING_CLOSED[otherReason] ? /* @__PURE__ */ jsx37("p", { className: "b316-muted", children: TIMING_CLOSED[otherReason] }) : null,
7037
+ ) : otherReason && TIMING_CLOSED[otherReason] ? /* @__PURE__ */ jsx38("p", { className: "b316-muted", children: TIMING_CLOSED[otherReason] }) : null,
6869
7038
  needsCard ? /* @__PURE__ */ jsxs36("div", { className: "b316-notice", role: "status", children: [
6870
7039
  "A card is needed for a change that is charged now.",
6871
- /* @__PURE__ */ jsx37("div", { className: "b316-review-actions", children: /* @__PURE__ */ jsx37("button", { type: "button", className: "b316-button", onClick: () => void addCard(), children: "Add a card" }) })
7040
+ /* @__PURE__ */ jsx38("div", { className: "b316-review-actions", children: /* @__PURE__ */ jsx38("button", { type: "button", className: "b316-button", onClick: () => void addCard(), children: "Add a card" }) })
6872
7041
  ] }) : /* @__PURE__ */ jsxs36("div", { className: "b316-review-actions", children: [
6873
- /* @__PURE__ */ jsx37(
7042
+ /* @__PURE__ */ jsx38(
6874
7043
  "button",
6875
7044
  {
6876
7045
  type: "button",
@@ -6890,7 +7059,7 @@ function PlanChangeReview({
6890
7059
  }
6891
7060
 
6892
7061
  // src/BillingPortal.tsx
6893
- import { Fragment as Fragment14, jsx as jsx38, jsxs as jsxs37 } from "react/jsx-runtime";
7062
+ import { Fragment as Fragment14, jsx as jsx39, jsxs as jsxs37 } from "react/jsx-runtime";
6894
7063
  function BillingPortal({
6895
7064
  returnUrl,
6896
7065
  featuredPlanKey,
@@ -6900,12 +7069,12 @@ function BillingPortal({
6900
7069
  style
6901
7070
  }) {
6902
7071
  const { client, token, loading: sessionLoading } = useBase316();
6903
- const [overview, setOverview] = useState35(null);
6904
- const [failed, setFailed] = useState35(false);
6905
- const [version, setVersion] = useState35(0);
6906
- const [reviewing, setReviewing] = useState35(null);
6907
- const [notice, setNotice] = useState35(null);
6908
- useEffect27(() => {
7072
+ const [overview, setOverview] = useState36(null);
7073
+ const [failed, setFailed] = useState36(false);
7074
+ const [version, setVersion] = useState36(0);
7075
+ const [reviewing, setReviewing] = useState36(null);
7076
+ const [notice, setNotice] = useState36(null);
7077
+ useEffect29(() => {
6909
7078
  if (!token) return;
6910
7079
  let cancelled = false;
6911
7080
  client.billing.subscription(token).then((result) => {
@@ -6924,28 +7093,28 @@ function BillingPortal({
6924
7093
  cancelled = true;
6925
7094
  };
6926
7095
  }, [client, token, version]);
6927
- const refresh = useCallback12(() => {
7096
+ const refresh = useCallback13(() => {
6928
7097
  setNotice(null);
6929
7098
  setVersion((value) => value + 1);
6930
7099
  }, []);
6931
- const shell = (content) => /* @__PURE__ */ jsx38("div", { className: cls("b316-billing-portal", className), style, children: content });
6932
- if (sessionLoading) return shell(/* @__PURE__ */ jsx38("div", { className: "b316-card", children: "Loading\u2026" }));
6933
- if (!token) return shell(/* @__PURE__ */ jsx38("div", { className: "b316-card", children: "Sign in to manage your billing." }));
7100
+ const shell = (content) => /* @__PURE__ */ jsx39("div", { className: cls("b316-billing-portal", className), style, children: content });
7101
+ if (sessionLoading) return shell(/* @__PURE__ */ jsx39("div", { className: "b316-card", children: "Loading\u2026" }));
7102
+ if (!token) return shell(/* @__PURE__ */ jsx39("div", { className: "b316-card", children: "Sign in to manage your billing." }));
6934
7103
  if (failed) {
6935
7104
  return shell(
6936
- /* @__PURE__ */ jsx38("div", { className: "b316-card", children: /* @__PURE__ */ jsx38("div", { className: "b316-error", role: "alert", children: "Could not load your billing." }) })
7105
+ /* @__PURE__ */ jsx39("div", { className: "b316-card", children: /* @__PURE__ */ jsx39("div", { className: "b316-error", role: "alert", children: "Could not load your billing." }) })
6937
7106
  );
6938
7107
  }
6939
- if (!overview) return shell(/* @__PURE__ */ jsx38("div", { className: "b316-card", children: "Loading\u2026" }));
7108
+ if (!overview) return shell(/* @__PURE__ */ jsx39("div", { className: "b316-card", children: "Loading\u2026" }));
6940
7109
  const { subscription, managedBy, quantityPriced } = overview;
6941
7110
  const canChange = Boolean(subscription) && !managedBy;
6942
7111
  return shell(
6943
7112
  /* @__PURE__ */ jsxs37(Fragment14, { children: [
6944
- notice ? /* @__PURE__ */ jsx38("div", { className: "b316-card b316-notice", role: "status", children: notice }) : null,
6945
- /* @__PURE__ */ jsx38(SubscriptionManager, { onChange: refresh }, `plan-${version}`),
6946
- canChange ? /* @__PURE__ */ jsx38(UpcomingInvoice, {}, `next-${version}`) : null,
6947
- canChange && quantityPriced ? /* @__PURE__ */ jsx38(SeatManager, { unitLabel, onChange: refresh }, `seats-${version}`) : null,
6948
- reviewing ? /* @__PURE__ */ jsx38(
7113
+ notice ? /* @__PURE__ */ jsx39("div", { className: "b316-card b316-notice", role: "status", children: notice }) : null,
7114
+ /* @__PURE__ */ jsx39(SubscriptionManager, { onChange: refresh }, `plan-${version}`),
7115
+ canChange ? /* @__PURE__ */ jsx39(UpcomingInvoice, {}, `next-${version}`) : null,
7116
+ canChange && quantityPriced ? /* @__PURE__ */ jsx39(SeatManager, { unitLabel, onChange: refresh }, `seats-${version}`) : null,
7117
+ reviewing ? /* @__PURE__ */ jsx39(
6949
7118
  PlanChangeReview,
6950
7119
  {
6951
7120
  planVersionId: reviewing,
@@ -6959,8 +7128,8 @@ function BillingPortal({
6959
7128
  }
6960
7129
  }
6961
7130
  ) : /* @__PURE__ */ jsxs37("section", { children: [
6962
- /* @__PURE__ */ jsx38("h2", { className: "b316-billing-portal-section-title", children: subscription ? "Change plan" : "Choose a plan" }),
6963
- /* @__PURE__ */ jsx38(
7131
+ /* @__PURE__ */ jsx39("h2", { className: "b316-billing-portal-section-title", children: subscription ? "Change plan" : "Choose a plan" }),
7132
+ /* @__PURE__ */ jsx39(
6964
7133
  PricingTable,
6965
7134
  {
6966
7135
  featuredPlanKey,
@@ -6972,17 +7141,17 @@ function BillingPortal({
6972
7141
  `plans-${version}`
6973
7142
  )
6974
7143
  ] }),
6975
- /* @__PURE__ */ jsx38(CreditBalances, {}, `credits-${version}`),
6976
- managedBy ? null : /* @__PURE__ */ jsx38(PaymentMethod, { returnUrl }, `card-${version}`),
6977
- /* @__PURE__ */ jsx38(Invoices, {}, `invoices-${version}`),
6978
- billingDetails === void 0 ? /* @__PURE__ */ jsx38(BillingDetailsForm, {}, `details-${version}`) : billingDetails
7144
+ /* @__PURE__ */ jsx39(CreditBalances, {}, `credits-${version}`),
7145
+ managedBy ? null : /* @__PURE__ */ jsx39(PaymentMethod, { returnUrl }, `card-${version}`),
7146
+ /* @__PURE__ */ jsx39(Invoices, {}, `invoices-${version}`),
7147
+ billingDetails === void 0 ? /* @__PURE__ */ jsx39(BillingDetailsForm, {}, `details-${version}`) : billingDetails
6979
7148
  ] })
6980
7149
  );
6981
7150
  }
6982
7151
 
6983
7152
  // src/ApiKeyManager.tsx
6984
- import { useCallback as useCallback13, useEffect as useEffect28, useState as useState36 } from "react";
6985
- import { jsx as jsx39, jsxs as jsxs38 } from "react/jsx-runtime";
7153
+ import { useCallback as useCallback14, useEffect as useEffect30, useState as useState37 } from "react";
7154
+ import { jsx as jsx40, jsxs as jsxs38 } from "react/jsx-runtime";
6986
7155
  function duration(seconds) {
6987
7156
  if (seconds % 3600 === 0) {
6988
7157
  return `${seconds / 3600}h`;
@@ -6999,17 +7168,17 @@ function ApiKeyManager({
6999
7168
  audience
7000
7169
  }) {
7001
7170
  const { client, token, loading: sessionLoading } = useBase316();
7002
- const [resources, setResources] = useState36([]);
7003
- const [credentials, setCredentials] = useState36([]);
7004
- const [loading, setLoading] = useState36(true);
7005
- const [busy, setBusy] = useState36(false);
7006
- const [error, setError] = useState36(null);
7007
- const [creating, setCreating] = useState36(false);
7008
- const [name, setName] = useState36("");
7009
- const [chosen, setChosen] = useState36([]);
7010
- const [resourceId, setResourceId] = useState36(null);
7011
- const [issued, setIssued] = useState36(null);
7012
- const load = useCallback13(async () => {
7171
+ const [resources, setResources] = useState37([]);
7172
+ const [credentials, setCredentials] = useState37([]);
7173
+ const [loading2, setLoading] = useState37(true);
7174
+ const [busy, setBusy] = useState37(false);
7175
+ const [error, setError] = useState37(null);
7176
+ const [creating, setCreating] = useState37(false);
7177
+ const [name, setName] = useState37("");
7178
+ const [chosen, setChosen] = useState37([]);
7179
+ const [resourceId, setResourceId] = useState37(null);
7180
+ const [issued, setIssued] = useState37(null);
7181
+ const load = useCallback14(async () => {
7013
7182
  if (!token) {
7014
7183
  setLoading(false);
7015
7184
  return;
@@ -7030,20 +7199,20 @@ function ApiKeyManager({
7030
7199
  setLoading(false);
7031
7200
  }
7032
7201
  }, [client, token, audience]);
7033
- useEffect28(() => {
7202
+ useEffect30(() => {
7034
7203
  void load();
7035
7204
  }, [load]);
7036
- if (sessionLoading || loading) {
7037
- return /* @__PURE__ */ jsx39("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
7205
+ if (sessionLoading || loading2) {
7206
+ return /* @__PURE__ */ jsx40("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
7038
7207
  }
7039
7208
  if (!token) {
7040
- return /* @__PURE__ */ jsx39("div", { className: cls("b316-card", className), style, children: "Sign in to manage your API keys." });
7209
+ return /* @__PURE__ */ jsx40("div", { className: cls("b316-card", className), style, children: "Sign in to manage your API keys." });
7041
7210
  }
7042
7211
  if (error) {
7043
- return /* @__PURE__ */ jsx39("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx39("div", { className: "b316-error", role: "alert", children: error }) });
7212
+ return /* @__PURE__ */ jsx40("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx40("div", { className: "b316-error", role: "alert", children: error }) });
7044
7213
  }
7045
7214
  if (resources.length === 0) {
7046
- return /* @__PURE__ */ jsx39("div", { className: cls("b316-card", className), style, children: "There are no APIs available to your account." });
7215
+ return /* @__PURE__ */ jsx40("div", { className: cls("b316-card", className), style, children: "There are no APIs available to your account." });
7047
7216
  }
7048
7217
  const resource = resources.find((item) => item.id === resourceId) ?? resources[0];
7049
7218
  const reset = () => {
@@ -7053,36 +7222,36 @@ function ApiKeyManager({
7053
7222
  setIssued(null);
7054
7223
  };
7055
7224
  return /* @__PURE__ */ jsxs38("div", { className: cls("b316-card", className), style, children: [
7056
- error ? /* @__PURE__ */ jsx39("div", { className: "b316-error", role: "alert", children: error }) : null,
7057
- resources.length > 1 ? /* @__PURE__ */ jsx39(
7225
+ error ? /* @__PURE__ */ jsx40("div", { className: "b316-error", role: "alert", children: error }) : null,
7226
+ resources.length > 1 ? /* @__PURE__ */ jsx40(
7058
7227
  "select",
7059
7228
  {
7060
7229
  className: "b316-input",
7061
7230
  value: resource.id,
7062
7231
  onChange: (event) => setResourceId(event.target.value),
7063
7232
  style: { marginBottom: 14 },
7064
- children: resources.map((item) => /* @__PURE__ */ jsx39("option", { value: item.id, children: item.name }, item.id))
7233
+ children: resources.map((item) => /* @__PURE__ */ jsx40("option", { value: item.id, children: item.name }, item.id))
7065
7234
  }
7066
- ) : /* @__PURE__ */ jsx39("div", { className: "b316-plan-name", children: resource.name }),
7235
+ ) : /* @__PURE__ */ jsx40("div", { className: "b316-plan-name", children: resource.name }),
7067
7236
  resource.rateLimit ? /* @__PURE__ */ jsxs38("div", { className: "b316-muted", children: [
7068
7237
  resource.rateLimit.requestsPerWindow,
7069
7238
  " requests per",
7070
7239
  " ",
7071
7240
  duration(resource.rateLimit.windowSeconds),
7072
7241
  resource.rateLimit.burst > resource.rateLimit.requestsPerWindow ? `, bursting to ${resource.rateLimit.burst}` : null
7073
- ] }) : /* @__PURE__ */ jsx39("div", { className: "b316-muted", children: "No rate limit." }),
7074
- credentials.length === 0 ? /* @__PURE__ */ jsx39("p", { className: "b316-muted", style: { marginTop: 14 }, children: "You have no API keys yet." }) : /* @__PURE__ */ jsx39("ul", { className: "b316-list", style: { marginTop: 14 }, children: credentials.map((credential) => /* @__PURE__ */ jsxs38("li", { className: "b316-list-item", children: [
7242
+ ] }) : /* @__PURE__ */ jsx40("div", { className: "b316-muted", children: "No rate limit." }),
7243
+ credentials.length === 0 ? /* @__PURE__ */ jsx40("p", { className: "b316-muted", style: { marginTop: 14 }, children: "You have no API keys yet." }) : /* @__PURE__ */ jsx40("ul", { className: "b316-list", style: { marginTop: 14 }, children: credentials.map((credential) => /* @__PURE__ */ jsxs38("li", { className: "b316-list-item", children: [
7075
7244
  /* @__PURE__ */ jsxs38("div", { children: [
7076
- /* @__PURE__ */ jsx39("div", { className: "b316-plan-name", children: credential.name }),
7245
+ /* @__PURE__ */ jsx40("div", { className: "b316-plan-name", children: credential.name }),
7077
7246
  /* @__PURE__ */ jsxs38("div", { className: "b316-muted", children: [
7078
- /* @__PURE__ */ jsx39("code", { children: credential.clientId }),
7247
+ /* @__PURE__ */ jsx40("code", { children: credential.clientId }),
7079
7248
  credential.secretLastFour ? ` \xB7 \u2026${credential.secretLastFour}` : null,
7080
7249
  credential.disabled ? " \xB7 Disabled" : null
7081
7250
  ] }),
7082
- /* @__PURE__ */ jsx39("div", { className: "b316-muted", children: credential.scopes.join(", ") })
7251
+ /* @__PURE__ */ jsx40("div", { className: "b316-muted", children: credential.scopes.join(", ") })
7083
7252
  ] }),
7084
7253
  /* @__PURE__ */ jsxs38("div", { style: { display: "flex", gap: 8 }, children: [
7085
- /* @__PURE__ */ jsx39(
7254
+ /* @__PURE__ */ jsx40(
7086
7255
  "button",
7087
7256
  {
7088
7257
  type: "button",
@@ -7111,7 +7280,7 @@ function ApiKeyManager({
7111
7280
  children: "Rotate"
7112
7281
  }
7113
7282
  ),
7114
- /* @__PURE__ */ jsx39(
7283
+ /* @__PURE__ */ jsx40(
7115
7284
  ConfirmButton,
7116
7285
  {
7117
7286
  className: "b316-button b316-button-secondary",
@@ -7136,10 +7305,10 @@ function ApiKeyManager({
7136
7305
  ] })
7137
7306
  ] }, credential.clientId)) }),
7138
7307
  issued ? /* @__PURE__ */ jsxs38("div", { className: "b316-notice", style: { marginTop: 14 }, children: [
7139
- /* @__PURE__ */ jsx39("strong", { children: "Copy this now." }),
7308
+ /* @__PURE__ */ jsx40("strong", { children: "Copy this now." }),
7140
7309
  " It is shown once and cannot be retrieved again.",
7141
- /* @__PURE__ */ jsx39("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsx39("code", { style: { wordBreak: "break-all" }, children: issued.secret }) }),
7142
- /* @__PURE__ */ jsx39(
7310
+ /* @__PURE__ */ jsx40("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsx40("code", { style: { wordBreak: "break-all" }, children: issued.secret }) }),
7311
+ /* @__PURE__ */ jsx40(
7143
7312
  "button",
7144
7313
  {
7145
7314
  type: "button",
@@ -7152,7 +7321,7 @@ function ApiKeyManager({
7152
7321
  children: "Copy"
7153
7322
  }
7154
7323
  ),
7155
- /* @__PURE__ */ jsx39(
7324
+ /* @__PURE__ */ jsx40(
7156
7325
  "button",
7157
7326
  {
7158
7327
  type: "button",
@@ -7164,7 +7333,7 @@ function ApiKeyManager({
7164
7333
  )
7165
7334
  ] }) : null,
7166
7335
  creating && !issued ? /* @__PURE__ */ jsxs38("div", { style: { marginTop: 14 }, children: [
7167
- /* @__PURE__ */ jsx39(
7336
+ /* @__PURE__ */ jsx40(
7168
7337
  "input",
7169
7338
  {
7170
7339
  className: "b316-input",
@@ -7175,7 +7344,7 @@ function ApiKeyManager({
7175
7344
  ),
7176
7345
  /* @__PURE__ */ jsxs38("div", { style: { marginTop: 10 }, children: [
7177
7346
  resource.availableScopes.map((scope) => /* @__PURE__ */ jsxs38("label", { className: "b316-checkbox", children: [
7178
- /* @__PURE__ */ jsx39(
7347
+ /* @__PURE__ */ jsx40(
7179
7348
  "input",
7180
7349
  {
7181
7350
  type: "checkbox",
@@ -7185,19 +7354,19 @@ function ApiKeyManager({
7185
7354
  )
7186
7355
  }
7187
7356
  ),
7188
- /* @__PURE__ */ jsx39("code", { children: scope.key }),
7357
+ /* @__PURE__ */ jsx40("code", { children: scope.key }),
7189
7358
  scope.description ? /* @__PURE__ */ jsxs38("span", { className: "b316-muted", children: [
7190
7359
  " \u2014 ",
7191
7360
  scope.description
7192
7361
  ] }) : null
7193
7362
  ] }, scope.key)),
7194
7363
  resource.lockedScopes.map((scope) => /* @__PURE__ */ jsxs38("label", { className: "b316-checkbox b316-muted", children: [
7195
- /* @__PURE__ */ jsx39("input", { type: "checkbox", disabled: true }),
7196
- /* @__PURE__ */ jsx39("code", { children: scope.key }),
7197
- /* @__PURE__ */ jsx39("span", { children: " \u2014 not included in your plan" })
7364
+ /* @__PURE__ */ jsx40("input", { type: "checkbox", disabled: true }),
7365
+ /* @__PURE__ */ jsx40("code", { children: scope.key }),
7366
+ /* @__PURE__ */ jsx40("span", { children: " \u2014 not included in your plan" })
7198
7367
  ] }, scope.key))
7199
7368
  ] }),
7200
- /* @__PURE__ */ jsx39(
7369
+ /* @__PURE__ */ jsx40(
7201
7370
  "button",
7202
7371
  {
7203
7372
  type: "button",
@@ -7231,7 +7400,7 @@ function ApiKeyManager({
7231
7400
  children: "Create key"
7232
7401
  }
7233
7402
  ),
7234
- /* @__PURE__ */ jsx39(
7403
+ /* @__PURE__ */ jsx40(
7235
7404
  "button",
7236
7405
  {
7237
7406
  type: "button",
@@ -7242,7 +7411,7 @@ function ApiKeyManager({
7242
7411
  }
7243
7412
  )
7244
7413
  ] }) : null,
7245
- !creating && !issued ? /* @__PURE__ */ jsx39(
7414
+ !creating && !issued ? /* @__PURE__ */ jsx40(
7246
7415
  "button",
7247
7416
  {
7248
7417
  type: "button",
@@ -7284,12 +7453,12 @@ var MANIFEST = [
7284
7453
  },
7285
7454
  {
7286
7455
  name: "appearance",
7287
- summary: "Colours, radius and font as tokens. Restyles everything at once.",
7456
+ summary: "Colors, radius and font as tokens. Restyles everything at once.",
7288
7457
  required: false
7289
7458
  },
7290
7459
  {
7291
7460
  name: "tenant",
7292
- summary: "White-label everything inside for one tenant \u2014 `{ organizationId }` or `{ organizationExternalId }`. A firm's name, logo and colours on the screens it runs its clients on; its own branding, then its parent's, then the environment's. Change it when the user switches team.",
7461
+ summary: "White-label everything inside for one tenant \u2014 `{ organizationId }` or `{ organizationExternalId }`. A firm's name, logo and colors on the screens it runs its clients on; its own branding, then its parent's, then the environment's. Change it when the user switches team.",
7293
7462
  required: false
7294
7463
  },
7295
7464
  ...appearance
@@ -7358,7 +7527,7 @@ var MANIFEST = [
7358
7527
  { name: "labels", summary: "Wording for the form, for translation.", required: false },
7359
7528
  {
7360
7529
  name: "secondFactorLabels",
7361
- summary: "Wording for the second-factor step (code box, or enrolment when the environment requires a factor and the user has none), for translation. English when omitted.",
7530
+ summary: "Wording for the second-factor step (code box, or enrollment when the environment requires a factor and the user has none), for translation. English when omitted.",
7362
7531
  required: false
7363
7532
  },
7364
7533
  ...appearance
@@ -7733,10 +7902,20 @@ var MANIFEST = [
7733
7902
  props: [],
7734
7903
  seeAlso: ["PricingTable"]
7735
7904
  },
7905
+ {
7906
+ name: "useAddons",
7907
+ kind: "hook",
7908
+ summary: "The signed-in user's addons and the ones on sale for their plan, with buy, resize and remove \u2014 settled by the API (more now and charged for the rest of the period, fewer at the period end). No markup.",
7909
+ useWhen: "You sell extras on top of a plan (more apps, seats, storage) as self-serve addons.",
7910
+ requires: ["session"],
7911
+ props: [],
7912
+ whenUnmet: "Loads nothing without a session; `lastError` carries the API's code.",
7913
+ seeAlso: ["usePlans", "SubscriptionManager"]
7914
+ },
7736
7915
  {
7737
7916
  name: "SubscriptionManager",
7738
7917
  kind: "component",
7739
- summary: "The current plan, its renewal date, a scheduled plan change with its undo, cancelling at the period end \u2014 asking why, and showing the environment's retention offer when it makes one \u2014 and resuming a cancelled one.",
7918
+ summary: "The current plan, its renewal date, a scheduled plan change with its undo, canceling at the period end \u2014 asking why, and showing the environment's retention offer when it makes one \u2014 and resuming a canceled one.",
7740
7919
  useWhen: "A billing settings page.",
7741
7920
  requires: ["session"],
7742
7921
  props: [
@@ -8017,7 +8196,7 @@ var MANIFEST = [
8017
8196
  {
8018
8197
  name: "Chart",
8019
8198
  kind: "component",
8020
- summary: "Records over time, counted or totalled.",
8199
+ summary: "Records over time, counted or totaled.",
8021
8200
  useWhen: "The question is how many or how much, by day, week or month.",
8022
8201
  requires: ["session", "collection"],
8023
8202
  bindsToCollection: true,
@@ -8220,6 +8399,7 @@ export {
8220
8399
  VerifyEmail,
8221
8400
  componentsRequiring,
8222
8401
  describeComponent,
8402
+ useAddons,
8223
8403
  useBase316,
8224
8404
  useCollection,
8225
8405
  usePaymentLink,