@base316/react 0.6.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);
@@ -325,6 +325,23 @@ var STYLESHEET_EXTRA = `
325
325
  border-bottom: 2px solid transparent; margin-bottom: -1px;
326
326
  }
327
327
  .b316-tab-on { color: var(--b316-color-text); border-bottom-color: var(--b316-color-primary); }
328
+ .b316-social { display: flex; flex-direction: column; gap: 8px; }
329
+ .b316-social-button {
330
+ display: flex; align-items: center; justify-content: center; gap: 10px;
331
+ width: 100%; min-height: 40px; padding: 9px 14px;
332
+ border: 1px solid; border-radius: calc(var(--b316-radius) / 1.6);
333
+ font: inherit; font-weight: 500; cursor: pointer;
334
+ }
335
+ .b316-social-button:hover:not([disabled]) { filter: brightness(.96); }
336
+ .b316-social-button:focus-visible { outline: 2px solid var(--b316-color-primary); outline-offset: 2px; }
337
+ .b316-social-button[disabled] { opacity: .55; cursor: not-allowed; }
338
+ .b316-social-icon { display: inline-flex; width: 18px; height: 18px; flex: none; }
339
+ .b316-social-icon svg { width: 18px; height: 18px; }
340
+ .b316-divider {
341
+ display: flex; align-items: center; gap: 10px; margin: 14px 0;
342
+ color: var(--b316-color-muted); font-size: .87em;
343
+ }
344
+ .b316-divider::before, .b316-divider::after { content: ""; flex: 1; border-top: 1px solid var(--b316-color-border); }
328
345
  .b316-branding { display: flex; flex-direction: column; gap: 4px; }
329
346
  .b316-branding-logo { max-height: 40px; width: auto; align-self: flex-start; }
330
347
  .b316-branding-name { font-size: 1.5em; font-weight: 650; letter-spacing: -.01em; }
@@ -532,7 +549,7 @@ var STYLESHEET_EXTRA = `
532
549
  .b316-mfa-uri { font-size: 0.9em; }
533
550
  .b316-mfa-code-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
534
551
  .b316-mfa-code-list code { user-select: all; }
535
- /* The enrolment choices: whole-width buttons with their explanation inside,
552
+ /* The enrollment choices: whole-width buttons with their explanation inside,
536
553
  so the explanation is part of what a screen reader announces. */
537
554
  .b316-mfa-methods { display: flex; flex-direction: column; gap: 8px; border: 0; margin: 0; padding: 0; min-width: 0; }
538
555
  .b316-mfa-method { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%; text-align: left; }
@@ -663,7 +680,7 @@ function Base316Provider({
663
680
  const [internalToken, setInternalToken] = useState(null);
664
681
  const [session, setSession] = useState(null);
665
682
  const [branding, setBranding] = useState(null);
666
- const [loading, setLoading] = useState(true);
683
+ const [loading2, setLoading] = useState(true);
667
684
  const token = controlled ? controlledToken : internalToken;
668
685
  useEffect(() => {
669
686
  if (controlled) {
@@ -725,8 +742,8 @@ function Base316Provider({
725
742
  setSession(null);
726
743
  }, [client, token, setToken]);
727
744
  const value = useMemo(
728
- () => ({ client, branding, token, setToken, session, loading, refresh, signOut }),
729
- [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]
730
747
  );
731
748
  return /* @__PURE__ */ jsx(Base316Context.Provider, { value, children: /* @__PURE__ */ jsx(
732
749
  "div",
@@ -735,7 +752,7 @@ function Base316Provider({
735
752
  style: appearanceToStyle({
736
753
  // Whatever was set in the sign-in designer arrives here, so a
737
754
  // customer styles their login once on Base316 and the embedded
738
- // components follow — rather than configuring the same colours
755
+ // components follow — rather than configuring the same colors
739
756
  // twice and watching them drift apart.
740
757
  //
741
758
  // An explicit `appearance` still wins, because a host that has
@@ -758,8 +775,8 @@ function useBase316() {
758
775
  return value;
759
776
  }
760
777
  function useSession() {
761
- const { session, loading } = useBase316();
762
- return { session, loading };
778
+ const { session, loading: loading2 } = useBase316();
779
+ return { session, loading: loading2 };
763
780
  }
764
781
 
765
782
  // src/Branding.tsx
@@ -1607,7 +1624,7 @@ import {
1607
1624
  isPasskeySupported,
1608
1625
  needsSecondFactor
1609
1626
  } from "@base316/sdk";
1610
- import { useEffect as useEffect7, useRef as useRef2, useState as useState7 } from "react";
1627
+ import { useEffect as useEffect8, useRef as useRef2, useState as useState8 } from "react";
1611
1628
 
1612
1629
  // src/SecondFactorStep.tsx
1613
1630
  import {
@@ -1998,33 +2015,233 @@ function SecondFactorStep({
1998
2015
  return /* @__PURE__ */ jsx7("div", { className: cls("b316-mfa", className), style, children: body });
1999
2016
  }
2000
2017
 
2018
+ // src/sign-in-methods.ts
2019
+ import {
2020
+ OAUTH_STATE_COOKIE,
2021
+ createOAuthState
2022
+ } from "@base316/sdk";
2023
+ import { useEffect as useEffect7, useState as useState7 } from "react";
2024
+ var cache = /* @__PURE__ */ new WeakMap();
2025
+ function loadSignInMethods(client) {
2026
+ let pending = cache.get(client);
2027
+ if (!pending) {
2028
+ pending = client.auth.methods();
2029
+ cache.set(client, pending);
2030
+ pending.catch(() => cache.delete(client));
2031
+ }
2032
+ return pending;
2033
+ }
2034
+ function useSignInMethods(client) {
2035
+ const [state, setState] = useState7({ status: "loading", methods: null });
2036
+ useEffect7(() => {
2037
+ let cancelled = false;
2038
+ loadSignInMethods(client).then((methods) => {
2039
+ if (!cancelled) setState({ status: "ready", methods });
2040
+ }).catch(() => {
2041
+ if (!cancelled) setState({ status: "unavailable", methods: null });
2042
+ });
2043
+ return () => {
2044
+ cancelled = true;
2045
+ };
2046
+ }, [client]);
2047
+ return state;
2048
+ }
2049
+ function resolveMethods(methods, props, currentPage) {
2050
+ if (!methods) {
2051
+ return {
2052
+ password: props.password !== false,
2053
+ passkeys: props.passkeys !== false,
2054
+ magicLink: props.magicLink !== false ? props.magicLinkRedirectUrl ?? null : null,
2055
+ phone: props.phone === true,
2056
+ social: [],
2057
+ sso: false,
2058
+ signUp: true,
2059
+ hostedUrl: void 0
2060
+ };
2061
+ }
2062
+ const redirect = props.socialRedirectUrl;
2063
+ const only = Array.isArray(props.social) ? new Set(props.social.map((entry) => entry.toLowerCase())) : null;
2064
+ return {
2065
+ password: methods.password && props.password !== false,
2066
+ passkeys: methods.passkeys && props.passkeys !== false,
2067
+ magicLink: methods.magicLink && props.magicLink !== false ? props.magicLinkRedirectUrl ?? currentPage : null,
2068
+ phone: methods.phone && props.phone !== false,
2069
+ social: redirect && props.social !== false ? methods.social.filter(
2070
+ (option) => !only || only.has(option.slug.toLowerCase()) || only.has(option.provider.toLowerCase())
2071
+ ) : [],
2072
+ sso: Boolean(redirect) && methods.sso && props.sso !== false,
2073
+ signUp: methods.signUp,
2074
+ hostedUrl: methods.hostedUrl
2075
+ };
2076
+ }
2077
+ function beginRedirect(build, appState) {
2078
+ const { state, nonce } = createOAuthState(appState);
2079
+ const secure = window.location.protocol === "https:" ? "; Secure" : "";
2080
+ document.cookie = `${OAUTH_STATE_COOKIE}=${nonce}; Path=/; Max-Age=600; SameSite=Lax${secure}`;
2081
+ window.location.assign(build(state));
2082
+ }
2083
+ function currentPageUrl() {
2084
+ if (typeof window === "undefined") {
2085
+ return null;
2086
+ }
2087
+ return `${window.location.origin}${window.location.pathname}`;
2088
+ }
2089
+
2090
+ // src/social-icons.ts
2091
+ var PROVIDER_ICON = {
2092
+ GOOGLE: `<svg viewBox="0 0 18 18" aria-hidden="true"><path fill="#4285F4" d="M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.88 2.68-6.62Z"/><path fill="#34A853" d="M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.8.54-1.84.86-3.04.86-2.34 0-4.32-1.58-5.03-3.7H.96v2.33A9 9 0 0 0 9 18Z"/><path fill="#FBBC05" d="M3.97 10.72a5.4 5.4 0 0 1 0-3.44V4.95H.96a9 9 0 0 0 0 8.1l3.01-2.33Z"/><path fill="#EA4335" d="M9 3.58c1.32 0 2.5.45 3.44 1.35l2.58-2.58C13.46.9 11.43 0 9 0A9 9 0 0 0 .96 4.95l3.01 2.33C4.68 5.16 6.66 3.58 9 3.58Z"/></svg>`,
2093
+ FACEBOOK: `<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M24 12.07C24 5.4 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.05V9.41c0-3.02 1.79-4.69 4.53-4.69 1.31 0 2.68.24 2.68.24v2.96h-1.51c-1.49 0-1.96.93-1.96 1.89v2.26h3.33l-.53 3.49h-2.8V24C19.61 23.1 24 18.1 24 12.07Z"/></svg>`,
2094
+ APPLE: `<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M17.05 12.54c-.03-2.74 2.24-4.06 2.34-4.12-1.28-1.86-3.26-2.12-3.96-2.15-1.69-.17-3.29 1-4.14 1-.85 0-2.17-.98-3.57-.95-1.83.03-3.53 1.07-4.47 2.71-1.91 3.31-.49 8.2 1.37 10.88.91 1.31 1.99 2.78 3.42 2.73 1.37-.06 1.89-.89 3.55-.89 1.66 0 2.13.89 3.58.86 1.48-.03 2.41-1.34 3.31-2.65 1.04-1.52 1.47-2.99 1.5-3.07-.03-.01-2.88-1.1-2.91-4.37ZM14.3 4.44c.75-.92 1.26-2.19 1.12-3.44-1.08.04-2.4.72-3.18 1.63-.7.81-1.31 2.11-1.15 3.35 1.21.09 2.45-.61 3.21-1.54Z"/></svg>`,
2095
+ MICROSOFT: `<svg viewBox="0 0 23 23" aria-hidden="true"><path fill="#f25022" d="M1 1h10v10H1z"/><path fill="#7fba00" d="M12 1h10v10H12z"/><path fill="#00a4ef" d="M1 12h10v10H1z"/><path fill="#ffb900" d="M12 12h10v10H12z"/></svg>`,
2096
+ GITHUB: `<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M12 .3a12 12 0 0 0-3.8 23.4c.6.1.8-.3.8-.6v-2c-3.3.7-4-1.6-4-1.6-.6-1.4-1.4-1.8-1.4-1.8-1-.7.1-.7.1-.7 1.2.1 1.8 1.2 1.8 1.2 1 1.8 2.8 1.3 3.5 1 0-.8.4-1.3.7-1.6-2.7-.3-5.5-1.3-5.5-5.9 0-1.3.5-2.4 1.2-3.2 0-.4-.5-1.6.2-3.2 0 0 1-.3 3.3 1.2a11.5 11.5 0 0 1 6 0C17.4 4.6 18.4 5 18.4 5c.7 1.6.2 2.8.1 3.2.8.8 1.2 1.9 1.2 3.2 0 4.6-2.8 5.6-5.5 5.9.5.4.9 1.1.9 2.2v3.3c0 .3.2.7.8.6A12 12 0 0 0 12 .3Z"/></svg>`,
2097
+ GITLAB: `<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="#e24329" d="m12 22.5-3.7-11.3h7.4L12 22.5Z"/><path fill="#fc6d26" d="M12 22.5 8.3 11.2H3.1L12 22.5Z"/><path fill="#fca326" d="M3.1 11.2 2 14.7a.8.8 0 0 0 .3.8l9.7 7-8.9-11.3Z"/><path fill="#e24329" d="M3.1 11.2h5.2L6.1 4.3a.4.4 0 0 0-.8 0l-2.2 6.9Z"/><path fill="#fc6d26" d="M12 22.5l3.7-11.3h5.2L12 22.5Z"/><path fill="#fca326" d="m20.9 11.2 1.1 3.5a.8.8 0 0 1-.3.8l-9.7 7 8.9-11.3Z"/><path fill="#e24329" d="M20.9 11.2h-5.2l2.2-6.9a.4.4 0 0 1 .8 0l2.2 6.9Z"/></svg>`,
2098
+ LINKEDIN: `<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M20.45 20.45h-3.56v-5.57c0-1.33-.02-3.04-1.85-3.04-1.85 0-2.14 1.45-2.14 2.94v5.67H9.35V9h3.41v1.56h.05a3.74 3.74 0 0 1 3.37-1.85c3.6 0 4.27 2.37 4.27 5.46v6.28ZM5.34 7.43a2.07 2.07 0 1 1 0-4.13 2.07 2.07 0 0 1 0 4.13Zm1.78 13.02H3.55V9h3.57v11.45ZM22.22 0H1.77C.79 0 0 .77 0 1.72v20.56C0 23.23.79 24 1.77 24h20.45c.98 0 1.78-.77 1.78-1.72V1.72C24 .77 23.2 0 22.22 0Z"/></svg>`,
2099
+ // The four below are the Simple Icons marks (CC0), https://simpleicons.org.
2100
+ DISCORD: `<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M20.317 4.3698a19.7913 19.7913 0 00-4.8851-1.5152.0741.0741 0 00-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 00-.0785-.037 19.7363 19.7363 0 00-4.8852 1.515.0699.0699 0 00-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 00.0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 00.0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 00-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 01-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 01.0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 01.0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 01-.0066.1276 12.2986 12.2986 0 01-1.873.8914.0766.0766 0 00-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 00.0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 00.0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 00-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/></svg>`,
2101
+ TWITTER: `<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"/></svg>`,
2102
+ TWITCH: `<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M11.571 4.714h1.715v5.143H11.57zm4.715 0H18v5.143h-1.714zM6 0L1.714 4.286v15.428h5.143V24l4.286-4.286h3.428L22.286 12V0zm14.571 11.143l-3.428 3.428h-3.429l-3 3v-3H6.857V1.714h13.714Z"/></svg>`,
2103
+ ROBLOX: `<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M18.926 23.998 0 18.892 5.075.002 24 5.108ZM15.348 10.09l-5.282-1.453-1.414 5.273 5.282 1.453z"/></svg>`,
2104
+ SLACK: `<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="#e01e5a" d="M5.04 15.17a2.53 2.53 0 1 1-2.52-2.53h2.52v2.53Zm1.27 0a2.53 2.53 0 1 1 5.05 0v6.31a2.53 2.53 0 1 1-5.05 0v-6.31Z"/><path fill="#36c5f0" d="M8.83 5.04a2.53 2.53 0 1 1 2.53-2.52v2.52H8.83Zm0 1.28a2.53 2.53 0 1 1 0 5.05H2.52a2.53 2.53 0 1 1 0-5.05h6.31Z"/><path fill="#2eb67d" d="M18.96 8.83a2.53 2.53 0 1 1 2.52 2.53h-2.52V8.83Zm-1.27 0a2.53 2.53 0 1 1-5.05 0V2.52a2.53 2.53 0 1 1 5.05 0v6.31Z"/><path fill="#ecb22e" d="M15.17 18.96a2.53 2.53 0 1 1-2.53 2.52v-2.52h2.53Zm0-1.27a2.53 2.53 0 1 1 0-5.05h6.31a2.53 2.53 0 1 1 0 5.05h-6.31Z"/></svg>`
2105
+ };
2106
+
2107
+ // src/SocialButtons.tsx
2108
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2109
+ function SocialButtons({
2110
+ options,
2111
+ continueWith,
2112
+ disabled,
2113
+ onChoose
2114
+ }) {
2115
+ if (options.length === 0) {
2116
+ return null;
2117
+ }
2118
+ return /* @__PURE__ */ jsx8("div", { className: "b316-social", children: options.map((option) => {
2119
+ const icon = PROVIDER_ICON[option.provider];
2120
+ const light = /^#f{3}(f{3})?$/i.test(option.buttonColor);
2121
+ return /* @__PURE__ */ jsxs7(
2122
+ "button",
2123
+ {
2124
+ type: "button",
2125
+ className: "b316-social-button",
2126
+ "data-provider": option.slug,
2127
+ disabled,
2128
+ style: {
2129
+ background: option.buttonColor,
2130
+ color: option.buttonTextColor,
2131
+ borderColor: light ? "#747775" : option.buttonColor
2132
+ },
2133
+ onClick: () => onChoose(option),
2134
+ children: [
2135
+ icon ? /* @__PURE__ */ jsx8(
2136
+ "span",
2137
+ {
2138
+ className: "b316-social-icon",
2139
+ "aria-hidden": "true",
2140
+ dangerouslySetInnerHTML: { __html: icon }
2141
+ }
2142
+ ) : null,
2143
+ /* @__PURE__ */ jsx8("span", { children: continueWith(option.name, option.provider) })
2144
+ ]
2145
+ },
2146
+ option.slug
2147
+ );
2148
+ }) });
2149
+ }
2150
+
2001
2151
  // src/SignIn.tsx
2002
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
2152
+ import { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
2153
+ var DEFAULT_SIGN_IN_LABELS = {
2154
+ email: "Email",
2155
+ password: "Password",
2156
+ mobileNumber: "Mobile number",
2157
+ code: "Code",
2158
+ tabPassword: "Password",
2159
+ tabMagicLink: "Magic link",
2160
+ tabPhone: "Text message",
2161
+ submit: "Sign in",
2162
+ working: "Working\u2026",
2163
+ emailMeALink: "Email me a link",
2164
+ textMeACode: "Text me a code",
2165
+ includeCountryCode: "Include the country code.",
2166
+ codeSent: (destination) => `We sent a code to ${destination}. It expires in ten minutes.`,
2167
+ useDifferentNumber: "Use a different number",
2168
+ or: "or",
2169
+ passkey: "Sign in with a passkey",
2170
+ continueWith: (name) => `Continue with ${name}`,
2171
+ sso: "Sign in with SSO",
2172
+ ssoEmail: "Work email",
2173
+ ssoContinue: "Continue",
2174
+ back: "Back",
2175
+ checkEmailTitle: "Check your email",
2176
+ checkEmail: (email) => `If an account exists for ${email}, a sign-in link is on its way. It expires shortly and can be used once.`,
2177
+ backToSignIn: "Back to sign in",
2178
+ wrongPassword: "That email and password did not match.",
2179
+ passkeyFailed: "That passkey did not work.",
2180
+ linkInvalid: "That sign-in link is no longer valid. Ask for a new one.",
2181
+ linkFailed: "We could not send that link. Try again.",
2182
+ wrongCode: "That code did not work. Check it, or ask for a new one.",
2183
+ codeFailed: "We could not send a code. Try again.",
2184
+ noMethods: "Signing in is not available right now."
2185
+ };
2003
2186
  function SignIn({
2004
2187
  onSignedIn,
2005
- passkeys = true,
2188
+ password: passwordProp,
2189
+ passkeys: passkeysProp,
2190
+ magicLink: magicLinkProp,
2006
2191
  magicLinkRedirectUrl,
2007
- phone = false,
2192
+ phone: phoneProp,
2193
+ social: socialProp,
2194
+ sso: ssoProp,
2195
+ socialRedirectUrl,
2196
+ socialState,
2197
+ labels: overrides,
2008
2198
  secondFactorLabels,
2009
2199
  className,
2010
2200
  style
2011
2201
  }) {
2202
+ const labels = { ...DEFAULT_SIGN_IN_LABELS, ...overrides };
2012
2203
  const { client, setToken } = useBase316();
2013
- const [email, setEmail] = useState7("");
2014
- const [password, setPassword] = useState7("");
2015
- const [code, setCode] = useState7("");
2016
- const [pending, setPending] = useState7(null);
2204
+ const loaded = useSignInMethods(client);
2205
+ const [currentPage, setCurrentPage] = useState8(null);
2206
+ const [email, setEmail] = useState8("");
2207
+ const [password, setPassword] = useState8("");
2208
+ const [code, setCode] = useState8("");
2209
+ const [pending, setPending] = useState8(null);
2017
2210
  const pendingChallenge = pending?.challengeToken ?? null;
2018
- const [phoneNumber, setPhoneNumber] = useState7("");
2019
- const [phoneChallenge, setPhoneChallenge] = useState7(
2211
+ const [phoneNumber, setPhoneNumber] = useState8("");
2212
+ const [phoneChallenge, setPhoneChallenge] = useState8(
2020
2213
  null
2021
2214
  );
2022
- const [error, setError] = useState7(null);
2023
- const [busy, setBusy] = useState7(false);
2024
- const [passkeyReady, setPasskeyReady] = useState7(false);
2025
- const [mode, setMode] = useState7("password");
2026
- const [linkSent, setLinkSent] = useState7(false);
2215
+ const [error, setError] = useState8(null);
2216
+ const [busy, setBusy] = useState8(false);
2217
+ const [passkeyReady, setPasskeyReady] = useState8(false);
2218
+ const [chosenMode, setMode] = useState8(null);
2219
+ const [linkSent, setLinkSent] = useState8(false);
2027
2220
  const abortRef = useRef2(null);
2221
+ useEffect8(() => {
2222
+ setCurrentPage(currentPageUrl());
2223
+ }, []);
2224
+ const offered = resolveMethods(
2225
+ loaded.methods,
2226
+ {
2227
+ password: passwordProp,
2228
+ passkeys: passkeysProp,
2229
+ magicLink: magicLinkProp,
2230
+ magicLinkRedirectUrl,
2231
+ phone: phoneProp,
2232
+ social: socialProp,
2233
+ sso: ssoProp,
2234
+ socialRedirectUrl
2235
+ },
2236
+ currentPage
2237
+ );
2238
+ const tabs = [
2239
+ ...offered.password ? ["password"] : [],
2240
+ ...offered.magicLink ? ["magic"] : [],
2241
+ ...offered.phone ? ["phone"] : []
2242
+ ];
2243
+ const mode = chosenMode && (chosenMode === "sso" ? offered.sso : tabs.includes(chosenMode)) ? chosenMode : tabs[0] ?? null;
2244
+ const passkeysWanted = loaded.status !== "loading" && offered.passkeys;
2028
2245
  const signInWithPasskey = async (conditional, signal) => {
2029
2246
  if (!conditional) {
2030
2247
  setBusy(true);
@@ -2042,7 +2259,7 @@ function SignIn({
2042
2259
  setError(cause.message);
2043
2260
  } else if (!conditional) {
2044
2261
  console.error("[base316] passkey sign-in failed", cause);
2045
- setError("That passkey did not work.");
2262
+ setError(labels.passkeyFailed);
2046
2263
  }
2047
2264
  } finally {
2048
2265
  if (!conditional) {
@@ -2050,8 +2267,9 @@ function SignIn({
2050
2267
  }
2051
2268
  }
2052
2269
  };
2053
- useEffect7(() => {
2054
- if (!passkeys || !isPasskeySupported() || pendingChallenge) {
2270
+ useEffect8(() => {
2271
+ if (!passkeysWanted || !isPasskeySupported() || pendingChallenge) {
2272
+ setPasskeyReady(false);
2055
2273
  return;
2056
2274
  }
2057
2275
  setPasskeyReady(true);
@@ -2065,8 +2283,8 @@ function SignIn({
2065
2283
  return () => {
2066
2284
  controller.abort();
2067
2285
  };
2068
- }, [passkeys, pendingChallenge]);
2069
- useEffect7(() => {
2286
+ }, [passkeysWanted, pendingChallenge]);
2287
+ useEffect8(() => {
2070
2288
  if (typeof window === "undefined") {
2071
2289
  return;
2072
2290
  }
@@ -2090,7 +2308,7 @@ function SignIn({
2090
2308
  onSignedIn?.();
2091
2309
  }).catch(() => {
2092
2310
  if (!cancelled) {
2093
- setError("That sign-in link is no longer valid. Ask for a new one.");
2311
+ setError(labels.linkInvalid);
2094
2312
  }
2095
2313
  });
2096
2314
  return () => {
@@ -2098,23 +2316,44 @@ function SignIn({
2098
2316
  };
2099
2317
  }, []);
2100
2318
  async function sendLink() {
2101
- if (!magicLinkRedirectUrl) {
2319
+ if (!offered.magicLink) {
2102
2320
  return;
2103
2321
  }
2104
2322
  setBusy(true);
2105
2323
  setError(null);
2106
2324
  try {
2107
- await client.auth.magicLink.request({ email, redirectUrl: magicLinkRedirectUrl });
2325
+ await client.auth.magicLink.request({ email, redirectUrl: offered.magicLink });
2108
2326
  setLinkSent(true);
2109
2327
  } catch (cause) {
2110
2328
  console.error("[base316] magic link request failed", cause);
2111
- setError("We could not send that link. Try again.");
2329
+ setError(
2330
+ cause instanceof Base316Error2 && cause.code === "INVALID_REQUEST" && cause.message ? cause.message : labels.linkFailed
2331
+ );
2112
2332
  } finally {
2113
2333
  setBusy(false);
2114
2334
  }
2115
2335
  }
2336
+ function leaveForSso() {
2337
+ if (!socialRedirectUrl) {
2338
+ return;
2339
+ }
2340
+ setBusy(true);
2341
+ beginRedirect(
2342
+ (state) => client.ssoSignInUrl({
2343
+ email,
2344
+ redirectUri: socialRedirectUrl,
2345
+ state,
2346
+ hostedUrl: offered.hostedUrl
2347
+ }),
2348
+ socialState
2349
+ );
2350
+ }
2116
2351
  async function submit(event) {
2117
2352
  event.preventDefault();
2353
+ if (mode === "sso") {
2354
+ leaveForSso();
2355
+ return;
2356
+ }
2118
2357
  setBusy(true);
2119
2358
  setError(null);
2120
2359
  try {
@@ -2151,25 +2390,23 @@ function SignIn({
2151
2390
  } catch (cause) {
2152
2391
  console.error("[base316] sign-in failed", cause);
2153
2392
  setError(
2154
- mode === "phone" ? phoneChallenge ? "That code did not work. Check it, or ask for a new one." : (
2393
+ mode === "phone" ? phoneChallenge ? labels.wrongCode : (
2155
2394
  // Why a text could not be sent is worth saying — a number in the
2156
2395
  // wrong format, or too many requests — and the server words it
2157
2396
  // without saying anything about accounts.
2158
- cause instanceof Error && cause.message ? cause.message : "We could not send a code. Try again."
2397
+ cause instanceof Error && cause.message ? cause.message : labels.codeFailed
2159
2398
  ) : (
2160
2399
  // An unconfirmed address and a throttle are worth naming; the
2161
2400
  // server words both without saying whether an account exists.
2162
- cause instanceof Base316Error2 && (cause.reason === "EMAIL_NOT_VERIFIED" || cause.code === "RATE_LIMITED") ? cause.message : "That email and password did not match."
2401
+ cause instanceof Base316Error2 && (cause.reason === "EMAIL_NOT_VERIFIED" || cause.code === "RATE_LIMITED") ? cause.message : labels.wrongPassword
2163
2402
  )
2164
2403
  );
2165
2404
  } finally {
2166
2405
  setBusy(false);
2167
2406
  }
2168
2407
  }
2169
- const magicAvailable = Boolean(magicLinkRedirectUrl) && !pendingChallenge;
2170
- const tabsShown = (magicAvailable || phone) && !pendingChallenge;
2171
2408
  if (pending) {
2172
- return /* @__PURE__ */ jsx8("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx8(
2409
+ return /* @__PURE__ */ jsx9("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx9(
2173
2410
  SecondFactorStep,
2174
2411
  {
2175
2412
  pending,
@@ -2185,59 +2422,68 @@ function SignIn({
2185
2422
  ) });
2186
2423
  }
2187
2424
  if (linkSent) {
2188
- return /* @__PURE__ */ jsxs7("div", { className: cls("b316-card", className), style, children: [
2189
- /* @__PURE__ */ jsx8("div", { style: { fontWeight: 600, marginBottom: 6 }, children: "Check your email" }),
2190
- /* @__PURE__ */ jsxs7("div", { className: "b316-muted", children: [
2191
- "If an account exists for ",
2192
- email,
2193
- ", a sign-in link is on its way. It expires shortly and can be used once."
2194
- ] }),
2195
- /* @__PURE__ */ jsx8(
2425
+ return /* @__PURE__ */ jsxs8("div", { className: cls("b316-card", className), style, children: [
2426
+ /* @__PURE__ */ jsx9("div", { style: { fontWeight: 600, marginBottom: 6 }, children: labels.checkEmailTitle }),
2427
+ /* @__PURE__ */ jsx9("div", { className: "b316-muted", children: labels.checkEmail(email) }),
2428
+ /* @__PURE__ */ jsx9(
2196
2429
  "button",
2197
2430
  {
2198
2431
  type: "button",
2199
2432
  className: "b316-button b316-button-secondary",
2200
2433
  style: { marginTop: 16 },
2201
2434
  onClick: () => setLinkSent(false),
2202
- children: "Back to sign in"
2435
+ children: labels.backToSignIn
2203
2436
  }
2204
2437
  )
2205
2438
  ] });
2206
2439
  }
2207
- return /* @__PURE__ */ jsxs7("form", { onSubmit: submit, className: cls("b316-card", className), style, children: [
2208
- error ? /* @__PURE__ */ jsx8("div", { className: "b316-error", role: "alert", children: error }) : null,
2209
- tabsShown ? /* @__PURE__ */ jsxs7("div", { className: "b316-tabs", children: [
2210
- /* @__PURE__ */ jsx8(
2211
- "button",
2440
+ const hasForm = mode !== null;
2441
+ const hasButtons = offered.social.length > 0 || passkeyReady || offered.sso && mode !== "sso";
2442
+ if (!hasForm && !hasButtons) {
2443
+ return /* @__PURE__ */ jsx9("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx9("div", { className: "b316-error", role: "alert", children: error ?? labels.noMethods }) });
2444
+ }
2445
+ const tabsShown = tabs.length > 1 && mode !== "sso";
2446
+ return /* @__PURE__ */ jsxs8("form", { onSubmit: submit, className: cls("b316-card", className), style, children: [
2447
+ error ? /* @__PURE__ */ jsx9("div", { className: "b316-error", role: "alert", children: error }) : null,
2448
+ offered.social.length > 0 && mode !== "sso" ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
2449
+ /* @__PURE__ */ jsx9(
2450
+ SocialButtons,
2212
2451
  {
2213
- type: "button",
2214
- className: cls("b316-tab", mode === "password" ? "b316-tab-on" : void 0),
2215
- onClick: () => setMode("password"),
2216
- children: "Password"
2452
+ options: offered.social,
2453
+ continueWith: labels.continueWith,
2454
+ disabled: busy,
2455
+ onChoose: (option) => {
2456
+ if (!socialRedirectUrl) {
2457
+ return;
2458
+ }
2459
+ setBusy(true);
2460
+ beginRedirect(
2461
+ (state) => client.socialSignInUrl({
2462
+ provider: option.slug,
2463
+ redirectUri: socialRedirectUrl,
2464
+ state,
2465
+ hostedUrl: offered.hostedUrl
2466
+ }),
2467
+ socialState
2468
+ );
2469
+ }
2217
2470
  }
2218
2471
  ),
2219
- magicAvailable ? /* @__PURE__ */ jsx8(
2220
- "button",
2221
- {
2222
- type: "button",
2223
- className: cls("b316-tab", mode === "magic" ? "b316-tab-on" : void 0),
2224
- onClick: () => setMode("magic"),
2225
- children: "Magic link"
2226
- }
2227
- ) : null,
2228
- phone ? /* @__PURE__ */ jsx8(
2229
- "button",
2230
- {
2231
- type: "button",
2232
- className: cls("b316-tab", mode === "phone" ? "b316-tab-on" : void 0),
2233
- onClick: () => setMode("phone"),
2234
- children: "Text message"
2235
- }
2236
- ) : null
2472
+ hasForm ? /* @__PURE__ */ jsx9("div", { className: "b316-divider", children: labels.or }) : null
2237
2473
  ] }) : null,
2238
- mode === "phone" ? phoneChallenge ? /* @__PURE__ */ jsxs7("div", { className: "b316-field", children: [
2239
- /* @__PURE__ */ jsx8("label", { className: "b316-label", htmlFor: "b316-phone-code", children: "Code" }),
2240
- /* @__PURE__ */ jsx8(
2474
+ tabsShown ? /* @__PURE__ */ jsx9("div", { className: "b316-tabs", children: tabs.map((tab) => /* @__PURE__ */ jsx9(
2475
+ "button",
2476
+ {
2477
+ type: "button",
2478
+ className: cls("b316-tab", mode === tab ? "b316-tab-on" : void 0),
2479
+ onClick: () => setMode(tab),
2480
+ children: tab === "password" ? labels.tabPassword : tab === "magic" ? labels.tabMagicLink : labels.tabPhone
2481
+ },
2482
+ tab
2483
+ )) }) : null,
2484
+ mode === "phone" ? phoneChallenge ? /* @__PURE__ */ jsxs8("div", { className: "b316-field", children: [
2485
+ /* @__PURE__ */ jsx9("label", { className: "b316-label", htmlFor: "b316-phone-code", children: labels.code }),
2486
+ /* @__PURE__ */ jsx9(
2241
2487
  "input",
2242
2488
  {
2243
2489
  id: "b316-phone-code",
@@ -2249,12 +2495,10 @@ function SignIn({
2249
2495
  required: true
2250
2496
  }
2251
2497
  ),
2252
- /* @__PURE__ */ jsxs7("span", { className: "b316-muted", children: [
2253
- "We sent a code to ",
2254
- phoneChallenge.hint,
2255
- ". It expires in ten minutes.",
2498
+ /* @__PURE__ */ jsxs8("span", { className: "b316-muted", children: [
2499
+ labels.codeSent(phoneChallenge.hint),
2256
2500
  " ",
2257
- /* @__PURE__ */ jsx8(
2501
+ /* @__PURE__ */ jsx9(
2258
2502
  "button",
2259
2503
  {
2260
2504
  type: "button",
@@ -2263,13 +2507,13 @@ function SignIn({
2263
2507
  setPhoneChallenge(null);
2264
2508
  setCode("");
2265
2509
  },
2266
- children: "Use a different number"
2510
+ children: labels.useDifferentNumber
2267
2511
  }
2268
2512
  )
2269
2513
  ] })
2270
- ] }) : /* @__PURE__ */ jsxs7("div", { className: "b316-field", children: [
2271
- /* @__PURE__ */ jsx8("label", { className: "b316-label", htmlFor: "b316-phone", children: "Mobile number" }),
2272
- /* @__PURE__ */ jsx8(
2514
+ ] }) : /* @__PURE__ */ jsxs8("div", { className: "b316-field", children: [
2515
+ /* @__PURE__ */ jsx9("label", { className: "b316-label", htmlFor: "b316-phone", children: labels.mobileNumber }),
2516
+ /* @__PURE__ */ jsx9(
2273
2517
  "input",
2274
2518
  {
2275
2519
  id: "b316-phone",
@@ -2282,11 +2526,11 @@ function SignIn({
2282
2526
  required: true
2283
2527
  }
2284
2528
  ),
2285
- /* @__PURE__ */ jsx8("span", { className: "b316-muted", children: "Include the country code." })
2286
- ] }) : /* @__PURE__ */ jsxs7(Fragment4, { children: [
2287
- /* @__PURE__ */ jsxs7("div", { className: "b316-field", children: [
2288
- /* @__PURE__ */ jsx8("label", { className: "b316-label", htmlFor: "b316-email", children: "Email" }),
2289
- /* @__PURE__ */ jsx8(
2529
+ /* @__PURE__ */ jsx9("span", { className: "b316-muted", children: labels.includeCountryCode })
2530
+ ] }) : mode !== null ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
2531
+ /* @__PURE__ */ jsxs8("div", { className: "b316-field", children: [
2532
+ /* @__PURE__ */ jsx9("label", { className: "b316-label", htmlFor: "b316-email", children: mode === "sso" ? labels.ssoEmail : labels.email }),
2533
+ /* @__PURE__ */ jsx9(
2290
2534
  "input",
2291
2535
  {
2292
2536
  id: "b316-email",
@@ -2294,14 +2538,14 @@ function SignIn({
2294
2538
  type: "email",
2295
2539
  value: email,
2296
2540
  onChange: (event) => setEmail(event.target.value),
2297
- autoComplete: passkeyReady ? "email webauthn" : "email",
2541
+ autoComplete: passkeyReady && mode !== "sso" ? "email webauthn" : "email",
2298
2542
  required: true
2299
2543
  }
2300
2544
  )
2301
2545
  ] }),
2302
- mode === "password" ? /* @__PURE__ */ jsxs7("div", { className: "b316-field", children: [
2303
- /* @__PURE__ */ jsx8("label", { className: "b316-label", htmlFor: "b316-password", children: "Password" }),
2304
- /* @__PURE__ */ jsx8(
2546
+ mode === "password" ? /* @__PURE__ */ jsxs8("div", { className: "b316-field", children: [
2547
+ /* @__PURE__ */ jsx9("label", { className: "b316-label", htmlFor: "b316-password", children: labels.password }),
2548
+ /* @__PURE__ */ jsx9(
2305
2549
  "input",
2306
2550
  {
2307
2551
  id: "b316-password",
@@ -2314,34 +2558,165 @@ function SignIn({
2314
2558
  }
2315
2559
  )
2316
2560
  ] }) : null
2317
- ] }),
2318
- /* @__PURE__ */ jsx8("button", { className: "b316-button", type: "submit", disabled: busy, children: busy ? "Working\u2026" : mode === "magic" ? "Email me a link" : mode === "phone" && !phoneChallenge ? "Text me a code" : "Sign in" }),
2319
- passkeyReady && !pendingChallenge ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
2320
- /* @__PURE__ */ jsx8("div", { className: "b316-muted", style: { textAlign: "center", margin: "10px 0" }, children: "or" }),
2321
- /* @__PURE__ */ jsx8(
2561
+ ] }) : null,
2562
+ mode !== null ? /* @__PURE__ */ jsx9("button", { className: "b316-button", type: "submit", disabled: busy, children: busy ? labels.working : mode === "magic" ? labels.emailMeALink : mode === "phone" && !phoneChallenge ? labels.textMeACode : mode === "sso" ? labels.ssoContinue : labels.submit }) : null,
2563
+ mode === "sso" ? /* @__PURE__ */ jsx9(
2564
+ "button",
2565
+ {
2566
+ type: "button",
2567
+ className: "b316-button b316-button-secondary",
2568
+ style: { marginTop: 10, width: "100%" },
2569
+ disabled: busy,
2570
+ onClick: () => setMode(null),
2571
+ children: labels.back
2572
+ }
2573
+ ) : null,
2574
+ (passkeyReady || offered.sso) && mode !== "sso" ? /* @__PURE__ */ jsxs8(Fragment4, { children: [
2575
+ hasForm ? /* @__PURE__ */ jsx9("div", { className: "b316-divider", children: labels.or }) : null,
2576
+ passkeyReady ? /* @__PURE__ */ jsx9(
2322
2577
  "button",
2323
2578
  {
2324
2579
  type: "button",
2325
2580
  className: "b316-button b316-button-secondary",
2581
+ style: { width: "100%" },
2326
2582
  disabled: busy,
2327
2583
  onClick: () => {
2328
2584
  abortRef.current?.abort();
2329
2585
  void signInWithPasskey(false);
2330
2586
  },
2331
- children: "Sign in with a passkey"
2587
+ children: labels.passkey
2332
2588
  }
2333
- )
2589
+ ) : null,
2590
+ offered.sso ? /* @__PURE__ */ jsx9(
2591
+ "button",
2592
+ {
2593
+ type: "button",
2594
+ className: "b316-button b316-button-secondary",
2595
+ style: { width: "100%", marginTop: passkeyReady ? 8 : 0 },
2596
+ disabled: busy,
2597
+ onClick: () => {
2598
+ abortRef.current?.abort();
2599
+ setError(null);
2600
+ setMode("sso");
2601
+ },
2602
+ children: labels.sso
2603
+ }
2604
+ ) : null
2334
2605
  ] }) : null
2335
2606
  ] });
2336
2607
  }
2337
2608
 
2609
+ // src/SocialSignIn.tsx
2610
+ import { Fragment as Fragment5, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2611
+ function SocialSignIn({
2612
+ socialRedirectUrl,
2613
+ socialState,
2614
+ social,
2615
+ intent = "sign-in",
2616
+ divider = false,
2617
+ labels
2618
+ }) {
2619
+ const { client } = useBase316();
2620
+ const loaded = useSignInMethods(client);
2621
+ if (!loaded.methods || intent === "sign-up" && !loaded.methods.signUp) {
2622
+ return null;
2623
+ }
2624
+ const offered = resolveMethods(loaded.methods, { social, socialRedirectUrl }, null);
2625
+ if (!socialRedirectUrl || offered.social.length === 0) {
2626
+ return null;
2627
+ }
2628
+ return /* @__PURE__ */ jsxs9(Fragment5, { children: [
2629
+ /* @__PURE__ */ jsx10(
2630
+ SocialButtons,
2631
+ {
2632
+ options: offered.social,
2633
+ continueWith: labels?.continueWith ?? ((name) => `Continue with ${name}`),
2634
+ onChoose: (option) => beginRedirect(
2635
+ (state) => client.socialSignInUrl({
2636
+ provider: option.slug,
2637
+ redirectUri: socialRedirectUrl,
2638
+ state,
2639
+ hostedUrl: offered.hostedUrl
2640
+ }),
2641
+ socialState
2642
+ )
2643
+ }
2644
+ ),
2645
+ divider ? /* @__PURE__ */ jsx10("div", { className: "b316-divider", children: labels?.or ?? "or" }) : null
2646
+ ] });
2647
+ }
2648
+
2338
2649
  // src/SignUp.tsx
2339
2650
  import {
2340
2651
  Base316Error as Base316Error3,
2341
2652
  needsSecondFactor as needsSecondFactor2
2342
2653
  } from "@base316/sdk";
2343
- import { useEffect as useEffect8, useState as useState8 } from "react";
2344
- import { jsx as jsx9, jsxs as jsxs8 } 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";
2345
2720
  var DEFAULT_SIGN_UP_LABELS = {
2346
2721
  name: "Name",
2347
2722
  email: "Email",
@@ -2358,7 +2733,11 @@ var DEFAULT_SIGN_UP_LABELS = {
2358
2733
  confirmEmail: (email) => `Your account is ready. We sent a confirmation link to ${email} \u2014 open it, then sign in.`,
2359
2734
  createdSignInFailed: (reason) => `Your account was created, but we could not sign you in: ${reason}`,
2360
2735
  genericError: "We could not create that account. Try again.",
2361
- joining: (organizationName, roleName) => `You are joining ${organizationName} as ${roleName}. Sign up with the address the invitation was sent to.`
2736
+ joining: (organizationName, roleName) => `You are joining ${organizationName} as ${roleName}. Sign up with the address the invitation was sent to.`,
2737
+ continueWith: (name) => `Continue with ${name}`,
2738
+ or: "or",
2739
+ closed: "This application is not accepting new accounts right now.",
2740
+ noMethods: "Creating an account is not available here right now."
2362
2741
  };
2363
2742
  function describeRules(policy, labels) {
2364
2743
  const extras = [
@@ -2377,30 +2756,37 @@ function SignUp({
2377
2756
  onJoined,
2378
2757
  labels: overrides,
2379
2758
  secondFactorLabels,
2759
+ social,
2760
+ socialRedirectUrl,
2761
+ socialState,
2380
2762
  className,
2381
2763
  style
2382
2764
  }) {
2383
2765
  const labels = { ...DEFAULT_SIGN_UP_LABELS, ...overrides };
2384
2766
  const { client, setToken } = useBase316();
2385
- const [name, setName] = useState8("");
2386
- const [email, setEmail] = useState8("");
2387
- const [password, setPassword] = useState8("");
2388
- const [error, setError] = useState8(null);
2389
- const [busy, setBusy] = useState8(false);
2390
- const [policy, setPolicy] = useState8(null);
2391
- const [pending, setPending] = useState8(null);
2392
- const [confirmEmail, setConfirmEmail] = useState8(false);
2393
- const [urlInvitation, setUrlInvitation] = useState8(null);
2394
- const [loaded, setLoaded] = useState8(null);
2767
+ const methodsState = useSignInMethods(client);
2768
+ const offered = resolveMethods(methodsState.methods, { social, socialRedirectUrl }, null);
2769
+ const [name, setName] = useState9("");
2770
+ const [email, setEmail] = useState9("");
2771
+ const [password, setPassword] = useState9("");
2772
+ const [error, setError] = useState9(null);
2773
+ const [busy, setBusy] = useState9(false);
2774
+ const [policy, setPolicy] = useState9(null);
2775
+ const [pending, setPending] = useState9(null);
2776
+ const [confirmEmail, setConfirmEmail] = useState9(false);
2777
+ const [urlInvitation, setUrlInvitation] = useState9(null);
2778
+ const [loaded, setLoaded] = useState9(null);
2779
+ const [captchaToken, setCaptchaToken] = useState9(null);
2780
+ const [captchaRound, setCaptchaRound] = useState9(0);
2395
2781
  const invitation = suppliedInvitation === void 0 ? urlInvitation : suppliedInvitation;
2396
2782
  const preview = loaded && loaded.token === invitation ? loaded.preview : null;
2397
- useEffect8(() => {
2783
+ useEffect10(() => {
2398
2784
  if (suppliedInvitation !== void 0 || typeof window === "undefined") {
2399
2785
  return;
2400
2786
  }
2401
2787
  setUrlInvitation(new URL(window.location.href).searchParams.get("invitation"));
2402
2788
  }, [suppliedInvitation]);
2403
- useEffect8(() => {
2789
+ useEffect10(() => {
2404
2790
  if (!invitation) {
2405
2791
  return;
2406
2792
  }
@@ -2415,7 +2801,7 @@ function SignUp({
2415
2801
  cancelled = true;
2416
2802
  };
2417
2803
  }, [client, invitation]);
2418
- useEffect8(() => {
2804
+ useEffect10(() => {
2419
2805
  let cancelled = false;
2420
2806
  client.auth.passwordPolicy().then((loaded2) => {
2421
2807
  if (!cancelled) {
@@ -2435,7 +2821,8 @@ function SignUp({
2435
2821
  email,
2436
2822
  password,
2437
2823
  name: name || void 0,
2438
- invitationToken: invitation ?? void 0
2824
+ invitationToken: invitation ?? void 0,
2825
+ captchaToken: captchaToken ?? void 0
2439
2826
  });
2440
2827
  if (created.invitationAccepted && created.organizationId) {
2441
2828
  onJoined?.(created.organizationId);
@@ -2445,6 +2832,8 @@ function SignUp({
2445
2832
  setError(
2446
2833
  cause instanceof Base316Error3 && (cause.code === "INVALID_REQUEST" || cause.code === "RATE_LIMITED" || cause.code === "CONFLICT") && cause.message ? cause.message : labels.genericError
2447
2834
  );
2835
+ setCaptchaToken(null);
2836
+ setCaptchaRound((round) => round + 1);
2448
2837
  setBusy(false);
2449
2838
  return;
2450
2839
  }
@@ -2473,86 +2862,129 @@ function SignUp({
2473
2862
  }
2474
2863
  }
2475
2864
  if (pending) {
2476
- return /* @__PURE__ */ jsx9("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx9(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 }) });
2477
2866
  }
2478
2867
  if (confirmEmail) {
2479
- return /* @__PURE__ */ jsxs8("div", { className: cls("b316-card", className), style, children: [
2480
- /* @__PURE__ */ jsx9("h3", { className: "b316-form-title", children: labels.confirmEmailTitle }),
2481
- /* @__PURE__ */ jsx9("output", { className: "b316-muted", children: labels.confirmEmail(email) })
2868
+ return /* @__PURE__ */ jsxs10("div", { className: cls("b316-card", className), style, children: [
2869
+ /* @__PURE__ */ jsx12("h3", { className: "b316-form-title", children: labels.confirmEmailTitle }),
2870
+ /* @__PURE__ */ jsx12("output", { className: "b316-muted", children: labels.confirmEmail(email) })
2482
2871
  ] });
2483
2872
  }
2484
- return /* @__PURE__ */ jsxs8("form", { onSubmit: submit, className: cls("b316-card", className), style, children: [
2485
- preview ? /* @__PURE__ */ jsx9("p", { className: "b316-muted", children: labels.joining(preview.organizationName, preview.roleName) }) : null,
2486
- error ? /* @__PURE__ */ jsx9("div", { className: "b316-error", role: "alert", children: error }) : null,
2487
- /* @__PURE__ */ jsxs8("div", { className: "b316-field", children: [
2488
- /* @__PURE__ */ jsx9("label", { className: "b316-label", htmlFor: "b316-name", children: labels.name }),
2489
- /* @__PURE__ */ jsx9(
2490
- "input",
2491
- {
2492
- id: "b316-name",
2493
- className: "b316-input",
2494
- value: name,
2495
- onChange: (event) => setName(event.target.value),
2496
- autoComplete: "name"
2497
- }
2498
- )
2499
- ] }),
2500
- /* @__PURE__ */ jsxs8("div", { className: "b316-field", children: [
2501
- /* @__PURE__ */ jsx9("label", { className: "b316-label", htmlFor: "b316-signup-email", children: labels.email }),
2502
- /* @__PURE__ */ jsx9(
2503
- "input",
2504
- {
2505
- id: "b316-signup-email",
2506
- className: "b316-input",
2507
- type: "email",
2508
- value: email,
2509
- onChange: (event) => setEmail(event.target.value),
2510
- autoComplete: "email",
2511
- required: true
2512
- }
2513
- )
2514
- ] }),
2515
- /* @__PURE__ */ jsxs8("div", { className: "b316-field", children: [
2516
- /* @__PURE__ */ jsx9("label", { className: "b316-label", htmlFor: "b316-signup-password", children: labels.password }),
2517
- /* @__PURE__ */ jsx9(
2518
- "input",
2873
+ if (!offered.signUp && !invitation) {
2874
+ return /* @__PURE__ */ jsx12("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx12("output", { className: "b316-muted", children: labels.closed }) });
2875
+ }
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
+ }
2880
+ return /* @__PURE__ */ jsxs10("form", { onSubmit: submit, className: cls("b316-card", className), style, children: [
2881
+ socialOptions.length > 0 ? /* @__PURE__ */ jsxs10(Fragment6, { children: [
2882
+ /* @__PURE__ */ jsx12(
2883
+ SocialButtons,
2519
2884
  {
2520
- id: "b316-signup-password",
2521
- className: "b316-input",
2522
- type: "password",
2523
- value: password,
2524
- onChange: (event) => setPassword(event.target.value),
2525
- autoComplete: "new-password",
2526
- minLength: policy?.minLength,
2527
- maxLength: policy?.maxLength,
2528
- "aria-describedby": policy ? "b316-signup-password-rules" : void 0,
2529
- required: true
2885
+ options: socialOptions,
2886
+ continueWith: labels.continueWith,
2887
+ disabled: busy,
2888
+ onChoose: (option) => {
2889
+ if (!socialRedirectUrl) {
2890
+ return;
2891
+ }
2892
+ setBusy(true);
2893
+ beginRedirect(
2894
+ (state) => client.socialSignInUrl({
2895
+ provider: option.slug,
2896
+ redirectUri: socialRedirectUrl,
2897
+ state,
2898
+ hostedUrl: offered.hostedUrl
2899
+ }),
2900
+ socialState
2901
+ );
2902
+ }
2530
2903
  }
2531
2904
  ),
2532
- policy ? /* @__PURE__ */ jsx9("span", { id: "b316-signup-password-rules", className: "b316-muted", children: describeRules(policy, labels) }) : null
2533
- ] }),
2534
- /* @__PURE__ */ jsx9("button", { className: "b316-button", type: "submit", disabled: busy, children: busy ? labels.working : labels.submit })
2905
+ offered.password ? /* @__PURE__ */ jsx12("div", { className: "b316-divider", children: labels.or }) : null
2906
+ ] }) : 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,
2909
+ offered.password || socialOptions.length === 0 ? /* @__PURE__ */ jsxs10(Fragment6, { children: [
2910
+ /* @__PURE__ */ jsxs10("div", { className: "b316-field", children: [
2911
+ /* @__PURE__ */ jsx12("label", { className: "b316-label", htmlFor: "b316-name", children: labels.name }),
2912
+ /* @__PURE__ */ jsx12(
2913
+ "input",
2914
+ {
2915
+ id: "b316-name",
2916
+ className: "b316-input",
2917
+ value: name,
2918
+ onChange: (event) => setName(event.target.value),
2919
+ autoComplete: "name"
2920
+ }
2921
+ )
2922
+ ] }),
2923
+ /* @__PURE__ */ jsxs10("div", { className: "b316-field", children: [
2924
+ /* @__PURE__ */ jsx12("label", { className: "b316-label", htmlFor: "b316-signup-email", children: labels.email }),
2925
+ /* @__PURE__ */ jsx12(
2926
+ "input",
2927
+ {
2928
+ id: "b316-signup-email",
2929
+ className: "b316-input",
2930
+ type: "email",
2931
+ value: email,
2932
+ onChange: (event) => setEmail(event.target.value),
2933
+ autoComplete: "email",
2934
+ required: true
2935
+ }
2936
+ )
2937
+ ] }),
2938
+ /* @__PURE__ */ jsxs10("div", { className: "b316-field", children: [
2939
+ /* @__PURE__ */ jsx12("label", { className: "b316-label", htmlFor: "b316-signup-password", children: labels.password }),
2940
+ /* @__PURE__ */ jsx12(
2941
+ "input",
2942
+ {
2943
+ id: "b316-signup-password",
2944
+ className: "b316-input",
2945
+ type: "password",
2946
+ value: password,
2947
+ onChange: (event) => setPassword(event.target.value),
2948
+ autoComplete: "new-password",
2949
+ minLength: policy?.minLength,
2950
+ maxLength: policy?.maxLength,
2951
+ "aria-describedby": policy ? "b316-signup-password-rules" : void 0,
2952
+ required: true
2953
+ }
2954
+ ),
2955
+ policy ? /* @__PURE__ */ jsx12("span", { id: "b316-signup-password-rules", className: "b316-muted", children: describeRules(policy, labels) }) : null
2956
+ ] }),
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 })
2966
+ ] }) : null
2535
2967
  ] });
2536
2968
  }
2537
2969
 
2538
2970
  // src/UserProfile.tsx
2539
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2971
+ import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
2540
2972
  function UserProfile({ className, style }) {
2541
- const { session, loading, signOut } = useBase316();
2542
- if (loading) {
2543
- return /* @__PURE__ */ jsx10("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" });
2544
2976
  }
2545
2977
  if (!session) {
2546
- return /* @__PURE__ */ jsx10("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." });
2547
2979
  }
2548
2980
  const user = session.user ?? {};
2549
- return /* @__PURE__ */ jsx10("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsxs9("div", { className: "b316-row", children: [
2550
- /* @__PURE__ */ jsxs9("div", { children: [
2551
- /* @__PURE__ */ jsx10("div", { style: { fontWeight: 600 }, children: user.name || user.email || "Signed in" }),
2552
- user.name && user.email ? /* @__PURE__ */ jsx10("div", { className: "b316-muted", children: user.email }) : null,
2553
- user.emailVerified === false ? /* @__PURE__ */ jsx10("div", { className: "b316-muted", children: "Email not verified" }) : null
2981
+ return /* @__PURE__ */ jsx13("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsxs11("div", { className: "b316-row", children: [
2982
+ /* @__PURE__ */ jsxs11("div", { children: [
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
2554
2986
  ] }),
2555
- /* @__PURE__ */ jsx10(
2987
+ /* @__PURE__ */ jsx13(
2556
2988
  "button",
2557
2989
  {
2558
2990
  type: "button",
@@ -2566,11 +2998,11 @@ function UserProfile({ className, style }) {
2566
2998
 
2567
2999
  // src/PasskeyManager.tsx
2568
3000
  import { isPasskeySupported as isPasskeySupported2 } from "@base316/sdk";
2569
- import { useCallback as useCallback5, useEffect as useEffect10, useState as useState10 } from "react";
3001
+ import { useCallback as useCallback5, useEffect as useEffect12, useState as useState11 } from "react";
2570
3002
 
2571
3003
  // src/confirm.tsx
2572
- import { useEffect as useEffect9, useRef as useRef3, useState as useState9 } from "react";
2573
- import { jsx as jsx11, jsxs as jsxs10 } 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";
2574
3006
  var DEFAULT_TIMEOUT_MS = 5e3;
2575
3007
  function ConfirmButton({
2576
3008
  children,
@@ -2580,9 +3012,9 @@ function ConfirmButton({
2580
3012
  disabled,
2581
3013
  timeoutMs = DEFAULT_TIMEOUT_MS
2582
3014
  }) {
2583
- const [armed, setArmed] = useState9(false);
2584
- const confirmRef = useRef3(null);
2585
- useEffect9(() => {
3015
+ const [armed, setArmed] = useState10(false);
3016
+ const confirmRef = useRef4(null);
3017
+ useEffect11(() => {
2586
3018
  if (!armed) {
2587
3019
  return;
2588
3020
  }
@@ -2591,7 +3023,7 @@ function ConfirmButton({
2591
3023
  return () => clearTimeout(timer);
2592
3024
  }, [armed, timeoutMs]);
2593
3025
  if (!armed) {
2594
- return /* @__PURE__ */ jsx11(
3026
+ return /* @__PURE__ */ jsx14(
2595
3027
  "button",
2596
3028
  {
2597
3029
  type: "button",
@@ -2605,8 +3037,8 @@ function ConfirmButton({
2605
3037
  return (
2606
3038
  // No `role="group"`: both buttons already say what they do, and the
2607
3039
  // grouping would only repeat the question a screen reader has just read.
2608
- /* @__PURE__ */ jsxs10("span", { className: "b316-confirm", children: [
2609
- /* @__PURE__ */ jsx11(
3040
+ /* @__PURE__ */ jsxs12("span", { className: "b316-confirm", children: [
3041
+ /* @__PURE__ */ jsx14(
2610
3042
  "button",
2611
3043
  {
2612
3044
  ref: confirmRef,
@@ -2620,7 +3052,7 @@ function ConfirmButton({
2620
3052
  children: confirmLabel
2621
3053
  }
2622
3054
  ),
2623
- /* @__PURE__ */ jsx11(
3055
+ /* @__PURE__ */ jsx14(
2624
3056
  "button",
2625
3057
  {
2626
3058
  type: "button",
@@ -2634,18 +3066,18 @@ function ConfirmButton({
2634
3066
  }
2635
3067
 
2636
3068
  // src/PasskeyManager.tsx
2637
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
3069
+ import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2638
3070
  function PasskeyManager({
2639
3071
  className,
2640
3072
  style,
2641
3073
  title = "Passkeys"
2642
3074
  }) {
2643
3075
  const { client, token, session } = useBase316();
2644
- const [passkeys, setPasskeys] = useState10(null);
2645
- const [busy, setBusy] = useState10(false);
2646
- const [error, setError] = useState10(null);
2647
- const [name, setName] = useState10("");
2648
- const [supported, setSupported] = useState10(false);
3076
+ const [passkeys, setPasskeys] = useState11(null);
3077
+ const [busy, setBusy] = useState11(false);
3078
+ const [error, setError] = useState11(null);
3079
+ const [name, setName] = useState11("");
3080
+ const [supported, setSupported] = useState11(false);
2649
3081
  const load = useCallback5(async () => {
2650
3082
  if (!token) {
2651
3083
  return;
@@ -2659,7 +3091,7 @@ function PasskeyManager({
2659
3091
  setPasskeys(null);
2660
3092
  }
2661
3093
  }, [client, token]);
2662
- useEffect10(() => {
3094
+ useEffect12(() => {
2663
3095
  if (!isPasskeySupported2()) {
2664
3096
  return;
2665
3097
  }
@@ -2695,18 +3127,18 @@ function PasskeyManager({
2695
3127
  setError(caught instanceof Error ? caught.message : "That did not work.");
2696
3128
  }
2697
3129
  };
2698
- return /* @__PURE__ */ jsxs11("div", { className: cls("b316-card", className), style, children: [
2699
- /* @__PURE__ */ jsx12("div", { style: { fontWeight: 600, marginBottom: 4 }, children: title }),
2700
- /* @__PURE__ */ jsx12("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." }),
2701
- passkeys === null ? /* @__PURE__ */ jsx12("div", { className: "b316-muted", children: "Loading\u2026" }) : passkeys.length === 0 ? /* @__PURE__ */ jsx12("div", { className: "b316-muted", children: "No passkeys yet." }) : /* @__PURE__ */ jsx12("ul", { style: { listStyle: "none", margin: 0, padding: 0 }, children: passkeys.map((passkey) => /* @__PURE__ */ jsxs11("li", { className: "b316-row", style: { padding: "8px 0" }, children: [
2702
- /* @__PURE__ */ jsxs11("div", { children: [
2703
- /* @__PURE__ */ jsx12("div", { children: passkey.name || "Passkey" }),
2704
- /* @__PURE__ */ jsxs11("div", { className: "b316-muted", children: [
3130
+ return /* @__PURE__ */ jsxs13("div", { className: cls("b316-card", className), style, 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: [
3134
+ /* @__PURE__ */ jsxs13("div", { children: [
3135
+ /* @__PURE__ */ jsx15("div", { children: passkey.name || "Passkey" }),
3136
+ /* @__PURE__ */ jsxs13("div", { className: "b316-muted", children: [
2705
3137
  passkey.lastUsedAt ? `Last used ${formatDate(passkey.lastUsedAt)}` : `Added ${formatDate(passkey.createdAt)}`,
2706
3138
  passkey.backedUp ? "" : " \xB7 this device only"
2707
3139
  ] })
2708
3140
  ] }),
2709
- /* @__PURE__ */ jsx12(
3141
+ /* @__PURE__ */ jsx15(
2710
3142
  ConfirmButton,
2711
3143
  {
2712
3144
  className: "b316-button b316-button-secondary",
@@ -2716,9 +3148,9 @@ function PasskeyManager({
2716
3148
  }
2717
3149
  )
2718
3150
  ] }, passkey.id)) }),
2719
- error ? /* @__PURE__ */ jsx12("div", { className: "b316-error", role: "alert", style: { marginTop: 12 }, children: error }) : null,
2720
- /* @__PURE__ */ jsxs11("div", { className: "b316-row", style: { marginTop: 12, gap: 8 }, children: [
2721
- /* @__PURE__ */ jsx12(
3151
+ error ? /* @__PURE__ */ jsx15("div", { className: "b316-error", role: "alert", style: { marginTop: 12 }, children: error }) : null,
3152
+ /* @__PURE__ */ jsxs13("div", { className: "b316-row", style: { marginTop: 12, gap: 8 }, children: [
3153
+ /* @__PURE__ */ jsx15(
2722
3154
  "input",
2723
3155
  {
2724
3156
  className: "b316-input",
@@ -2727,7 +3159,7 @@ function PasskeyManager({
2727
3159
  onChange: (event) => setName(event.target.value)
2728
3160
  }
2729
3161
  ),
2730
- /* @__PURE__ */ jsx12("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" })
2731
3163
  ] })
2732
3164
  ] });
2733
3165
  }
@@ -2737,8 +3169,8 @@ function formatDate(value) {
2737
3169
  }
2738
3170
 
2739
3171
  // src/ActiveSessions.tsx
2740
- import { useCallback as useCallback6, useEffect as useEffect11, useState as useState11 } from "react";
2741
- import { jsx as jsx13, jsxs as jsxs12 } 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";
2742
3174
  function describeDevice(userAgent) {
2743
3175
  if (!userAgent) {
2744
3176
  return null;
@@ -2756,9 +3188,9 @@ function when(value) {
2756
3188
  }
2757
3189
  function ActiveSessions({ onRevoked, className, style }) {
2758
3190
  const { client, token } = useBase316();
2759
- const [sessions, setSessions] = useState11(null);
2760
- const [error, setError] = useState11(null);
2761
- const [busy, setBusy] = useState11(false);
3191
+ const [sessions, setSessions] = useState12(null);
3192
+ const [error, setError] = useState12(null);
3193
+ const [busy, setBusy] = useState12(false);
2762
3194
  const load = useCallback6(() => {
2763
3195
  if (!token) {
2764
3196
  return;
@@ -2770,15 +3202,15 @@ function ActiveSessions({ onRevoked, className, style }) {
2770
3202
  setError(cause instanceof Error ? cause.message : "Could not load your sessions.");
2771
3203
  });
2772
3204
  }, [client, token]);
2773
- useEffect11(load, [load]);
3205
+ useEffect13(load, [load]);
2774
3206
  if (!token) {
2775
3207
  return null;
2776
3208
  }
2777
3209
  if (error) {
2778
- return /* @__PURE__ */ jsx13("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx13("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 }) });
2779
3211
  }
2780
3212
  if (!sessions) {
2781
- return /* @__PURE__ */ jsx13("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
3213
+ return /* @__PURE__ */ jsx16("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
2782
3214
  }
2783
3215
  async function revokeOthers() {
2784
3216
  setBusy(true);
@@ -2792,32 +3224,32 @@ function ActiveSessions({ onRevoked, className, style }) {
2792
3224
  setBusy(false);
2793
3225
  }
2794
3226
  }
2795
- return /* @__PURE__ */ jsxs12("div", { className: cls("b316-card b316-sessions", className), style, children: [
2796
- /* @__PURE__ */ jsxs12("div", { className: "b316-sessions-head", children: [
2797
- /* @__PURE__ */ jsx13("h3", { className: "b316-sessions-title", children: "Where you are signed in" }),
2798
- sessions.length > 1 ? /* @__PURE__ */ jsx13("button", { type: "button", className: "b316-button", disabled: busy, onClick: revokeOthers, children: busy ? "Ending\u2026" : "Sign out other devices" }) : null
3227
+ return /* @__PURE__ */ jsxs14("div", { className: cls("b316-card b316-sessions", className), style, children: [
3228
+ /* @__PURE__ */ jsxs14("div", { className: "b316-sessions-head", children: [
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
2799
3231
  ] }),
2800
- /* @__PURE__ */ jsx13("ul", { className: "b316-sessions-list", children: sessions.map((session) => /* @__PURE__ */ jsxs12("li", { className: "b316-session", children: [
2801
- /* @__PURE__ */ jsxs12("div", { className: "b316-session-device", children: [
3232
+ /* @__PURE__ */ jsx16("ul", { className: "b316-sessions-list", children: sessions.map((session) => /* @__PURE__ */ jsxs14("li", { className: "b316-session", children: [
3233
+ /* @__PURE__ */ jsxs14("div", { className: "b316-session-device", children: [
2802
3234
  describeDevice(session.userAgent) ?? "Unknown device",
2803
3235
  session.impersonatedBy ? (
2804
3236
  // Worth saying loudly: somebody is acting as this account.
2805
- /* @__PURE__ */ jsx13("span", { className: "b316-chip", children: " Support access" })
3237
+ /* @__PURE__ */ jsx16("span", { className: "b316-chip", children: " Support access" })
2806
3238
  ) : null
2807
3239
  ] }),
2808
- /* @__PURE__ */ jsxs12("div", { className: "b316-muted", children: [
3240
+ /* @__PURE__ */ jsxs14("div", { className: "b316-muted", children: [
2809
3241
  session.ipAddress ? `${session.ipAddress} \xB7 ` : "",
2810
3242
  "last used ",
2811
3243
  when(session.lastSeenAt)
2812
3244
  ] })
2813
3245
  ] }, session.id)) }),
2814
- sessions.length === 0 ? /* @__PURE__ */ jsx13("div", { className: "b316-muted", children: "No active sessions." }) : null
3246
+ sessions.length === 0 ? /* @__PURE__ */ jsx16("div", { className: "b316-muted", children: "No active sessions." }) : null
2815
3247
  ] });
2816
3248
  }
2817
3249
 
2818
3250
  // src/DeviceApproval.tsx
2819
- import { useState as useState12 } from "react";
2820
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
3251
+ import { useState as useState13 } from "react";
3252
+ import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2821
3253
  function DeviceApproval({
2822
3254
  userCode = "",
2823
3255
  onDecided,
@@ -2825,11 +3257,11 @@ function DeviceApproval({
2825
3257
  style
2826
3258
  }) {
2827
3259
  const { client, token } = useBase316();
2828
- const [code, setCode] = useState12(userCode);
2829
- const [request, setRequest] = useState12(null);
2830
- const [decided, setDecided] = useState12(null);
2831
- const [error, setError] = useState12(null);
2832
- const [busy, setBusy] = useState12(false);
3260
+ const [code, setCode] = useState13(userCode);
3261
+ const [request, setRequest] = useState13(null);
3262
+ const [decided, setDecided] = useState13(null);
3263
+ const [error, setError] = useState13(null);
3264
+ const [busy, setBusy] = useState13(false);
2833
3265
  if (!token) {
2834
3266
  return null;
2835
3267
  }
@@ -2862,25 +3294,25 @@ function DeviceApproval({
2862
3294
  }
2863
3295
  }
2864
3296
  if (decided !== null) {
2865
- return /* @__PURE__ */ jsxs13("div", { className: cls("b316-card b316-device", className), style, children: [
2866
- /* @__PURE__ */ jsx14("h3", { className: "b316-device-title", children: decided ? "You're all set" : "Not approved" }),
2867
- /* @__PURE__ */ jsx14("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." })
3297
+ return /* @__PURE__ */ jsxs15("div", { className: cls("b316-card b316-device", className), style, children: [
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." })
2868
3300
  ] });
2869
3301
  }
2870
3302
  if (request) {
2871
- return /* @__PURE__ */ jsxs13("div", { className: cls("b316-card b316-device", className), style, children: [
2872
- /* @__PURE__ */ jsxs13("h3", { className: "b316-device-title", children: [
3303
+ return /* @__PURE__ */ jsxs15("div", { className: cls("b316-card b316-device", className), style, children: [
3304
+ /* @__PURE__ */ jsxs15("h3", { className: "b316-device-title", children: [
2873
3305
  "Sign in to ",
2874
3306
  request.clientName
2875
3307
  ] }),
2876
- /* @__PURE__ */ jsxs13("p", { className: "b316-muted", children: [
3308
+ /* @__PURE__ */ jsxs15("p", { className: "b316-muted", children: [
2877
3309
  request.clientName,
2878
3310
  " is asking to sign in as you."
2879
3311
  ] }),
2880
- request.scopes.length > 0 ? /* @__PURE__ */ jsx14("ul", { className: "b316-device-scopes", children: request.scopes.map((scope) => /* @__PURE__ */ jsx14("li", { children: scope }, scope)) }) : null,
2881
- error ? /* @__PURE__ */ jsx14("div", { className: "b316-error", role: "alert", children: error }) : null,
2882
- /* @__PURE__ */ jsxs13("div", { className: "b316-device-actions", children: [
2883
- /* @__PURE__ */ jsx14(
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,
3314
+ /* @__PURE__ */ jsxs15("div", { className: "b316-device-actions", children: [
3315
+ /* @__PURE__ */ jsx17(
2884
3316
  "button",
2885
3317
  {
2886
3318
  type: "button",
@@ -2890,7 +3322,7 @@ function DeviceApproval({
2890
3322
  children: busy ? "Approving\u2026" : "Approve"
2891
3323
  }
2892
3324
  ),
2893
- /* @__PURE__ */ jsx14(
3325
+ /* @__PURE__ */ jsx17(
2894
3326
  "button",
2895
3327
  {
2896
3328
  type: "button",
@@ -2903,11 +3335,11 @@ function DeviceApproval({
2903
3335
  ] })
2904
3336
  ] });
2905
3337
  }
2906
- return /* @__PURE__ */ jsxs13("form", { className: cls("b316-card b316-device", className), style, onSubmit: lookUp, children: [
2907
- /* @__PURE__ */ jsx14("h3", { className: "b316-device-title", children: "Connect your device" }),
2908
- /* @__PURE__ */ jsx14("p", { className: "b316-muted", children: "Enter the code shown on your device." }),
2909
- error ? /* @__PURE__ */ jsx14("div", { className: "b316-error", role: "alert", children: error }) : null,
2910
- /* @__PURE__ */ jsx14(
3338
+ return /* @__PURE__ */ jsxs15("form", { className: cls("b316-card b316-device", className), style, onSubmit: lookUp, children: [
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(
2911
3343
  "input",
2912
3344
  {
2913
3345
  className: "b316-input",
@@ -2920,13 +3352,13 @@ function DeviceApproval({
2920
3352
  "aria-label": "Device code"
2921
3353
  }
2922
3354
  ),
2923
- /* @__PURE__ */ jsx14("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" })
2924
3356
  ] });
2925
3357
  }
2926
3358
 
2927
3359
  // src/PrivacyControls.tsx
2928
- import { useState as useState13 } from "react";
2929
- import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
3360
+ import { useState as useState14 } from "react";
3361
+ import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2930
3362
  function PrivacyControls({
2931
3363
  confirmWord = "DELETE",
2932
3364
  onErased,
@@ -2934,10 +3366,10 @@ function PrivacyControls({
2934
3366
  style
2935
3367
  }) {
2936
3368
  const { client, token } = useBase316();
2937
- const [confirming, setConfirming] = useState13(false);
2938
- const [typed, setTyped] = useState13("");
2939
- const [error, setError] = useState13(null);
2940
- const [busy, setBusy] = useState13(false);
3369
+ const [confirming, setConfirming] = useState14(false);
3370
+ const [typed, setTyped] = useState14("");
3371
+ const [error, setError] = useState14(null);
3372
+ const [busy, setBusy] = useState14(false);
2941
3373
  if (!token) {
2942
3374
  return null;
2943
3375
  }
@@ -2972,22 +3404,22 @@ function PrivacyControls({
2972
3404
  setBusy(false);
2973
3405
  }
2974
3406
  }
2975
- return /* @__PURE__ */ jsxs14("div", { className: cls("b316-card b316-privacy", className), style, children: [
2976
- /* @__PURE__ */ jsx15("h3", { className: "b316-privacy-title", children: "Your data" }),
2977
- error ? /* @__PURE__ */ jsx15("div", { className: "b316-error", role: "alert", children: error }) : null,
2978
- /* @__PURE__ */ jsxs14("div", { className: "b316-privacy-row", children: [
2979
- /* @__PURE__ */ jsxs14("div", { children: [
2980
- /* @__PURE__ */ jsx15("p", { children: "Download a copy" }),
2981
- /* @__PURE__ */ jsx15("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." })
3407
+ return /* @__PURE__ */ jsxs16("div", { className: cls("b316-card b316-privacy", className), style, children: [
3408
+ /* @__PURE__ */ jsx18("h3", { className: "b316-privacy-title", children: "Your data" }),
3409
+ error ? /* @__PURE__ */ jsx18("div", { className: "b316-error", role: "alert", children: error }) : null,
3410
+ /* @__PURE__ */ jsxs16("div", { className: "b316-privacy-row", children: [
3411
+ /* @__PURE__ */ jsxs16("div", { children: [
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." })
2982
3414
  ] }),
2983
- /* @__PURE__ */ jsx15("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" })
2984
3416
  ] }),
2985
- /* @__PURE__ */ jsxs14("div", { className: "b316-privacy-row", children: [
2986
- /* @__PURE__ */ jsxs14("div", { children: [
2987
- /* @__PURE__ */ jsx15("p", { children: "Delete your account" }),
2988
- /* @__PURE__ */ jsx15("p", { className: "b316-muted", children: "Permanent. Invoices already raised are kept, because the law requires it; everything that identifies you is removed from them." })
3417
+ /* @__PURE__ */ jsxs16("div", { className: "b316-privacy-row", children: [
3418
+ /* @__PURE__ */ jsxs16("div", { children: [
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." })
2989
3421
  ] }),
2990
- confirming ? null : /* @__PURE__ */ jsx15(
3422
+ confirming ? null : /* @__PURE__ */ jsx18(
2991
3423
  "button",
2992
3424
  {
2993
3425
  type: "button",
@@ -2998,13 +3430,13 @@ function PrivacyControls({
2998
3430
  }
2999
3431
  )
3000
3432
  ] }),
3001
- confirming ? /* @__PURE__ */ jsxs14("div", { className: "b316-privacy-confirm", children: [
3002
- /* @__PURE__ */ jsxs14("label", { className: "b316-label", htmlFor: "b316-privacy-confirm", children: [
3433
+ confirming ? /* @__PURE__ */ jsxs16("div", { className: "b316-privacy-confirm", children: [
3434
+ /* @__PURE__ */ jsxs16("label", { className: "b316-label", htmlFor: "b316-privacy-confirm", children: [
3003
3435
  "Type ",
3004
3436
  confirmWord,
3005
3437
  " to confirm"
3006
3438
  ] }),
3007
- /* @__PURE__ */ jsx15(
3439
+ /* @__PURE__ */ jsx18(
3008
3440
  "input",
3009
3441
  {
3010
3442
  id: "b316-privacy-confirm",
@@ -3014,8 +3446,8 @@ function PrivacyControls({
3014
3446
  onChange: (event) => setTyped(event.target.value)
3015
3447
  }
3016
3448
  ),
3017
- /* @__PURE__ */ jsxs14("div", { className: "b316-privacy-actions", children: [
3018
- /* @__PURE__ */ jsx15(
3449
+ /* @__PURE__ */ jsxs16("div", { className: "b316-privacy-actions", children: [
3450
+ /* @__PURE__ */ jsx18(
3019
3451
  "button",
3020
3452
  {
3021
3453
  type: "button",
@@ -3027,7 +3459,7 @@ function PrivacyControls({
3027
3459
  children: "Cancel"
3028
3460
  }
3029
3461
  ),
3030
- /* @__PURE__ */ jsx15(
3462
+ /* @__PURE__ */ jsx18(
3031
3463
  "button",
3032
3464
  {
3033
3465
  type: "button",
@@ -3043,12 +3475,12 @@ function PrivacyControls({
3043
3475
  }
3044
3476
 
3045
3477
  // src/TwoFactorManager.tsx
3046
- import { useState as useState14 } from "react";
3478
+ import { useState as useState15 } from "react";
3047
3479
 
3048
3480
  // src/QrCode.tsx
3049
3481
  import qrcode from "qrcode-generator";
3050
3482
  import { useMemo as useMemo2 } from "react";
3051
- import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
3483
+ import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
3052
3484
  var QUIET_ZONE = 4;
3053
3485
  function utf8Binary(value) {
3054
3486
  let binary = "";
@@ -3075,7 +3507,7 @@ function qrPath(value) {
3075
3507
  function QrCode({ value, label, size = 180, className }) {
3076
3508
  const { path, modules } = useMemo2(() => qrPath(value), [value]);
3077
3509
  const extent = modules + QUIET_ZONE * 2;
3078
- return /* @__PURE__ */ jsxs15(
3510
+ return /* @__PURE__ */ jsxs17(
3079
3511
  "svg",
3080
3512
  {
3081
3513
  className,
@@ -3087,15 +3519,15 @@ function QrCode({ value, label, size = 180, className }) {
3087
3519
  shapeRendering: "crispEdges",
3088
3520
  xmlns: "http://www.w3.org/2000/svg",
3089
3521
  children: [
3090
- /* @__PURE__ */ jsx16("rect", { width: extent, height: extent, fill: "#ffffff" }),
3091
- /* @__PURE__ */ jsx16("path", { d: path, fill: "#000000" })
3522
+ /* @__PURE__ */ jsx19("rect", { width: extent, height: extent, fill: "#ffffff" }),
3523
+ /* @__PURE__ */ jsx19("path", { d: path, fill: "#000000" })
3092
3524
  ]
3093
3525
  }
3094
3526
  );
3095
3527
  }
3096
3528
 
3097
3529
  // src/TwoFactorManager.tsx
3098
- import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
3530
+ import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
3099
3531
  function groupKey(secret) {
3100
3532
  return secret.replace(/\s+/g, "").replace(/(.{4})(?=.)/g, "$1 ");
3101
3533
  }
@@ -3108,12 +3540,12 @@ function TwoFactorManager({
3108
3540
  style
3109
3541
  }) {
3110
3542
  const { client, token } = useBase316();
3111
- const [stage, setStage] = useState14({ name: "idle" });
3112
- const [on, setOn] = useState14(enabled);
3113
- const [code, setCode] = useState14("");
3114
- const [phone, setPhone] = useState14("");
3115
- const [error, setError] = useState14(null);
3116
- const [busy, setBusy] = useState14(false);
3543
+ const [stage, setStage] = useState15({ name: "idle" });
3544
+ const [on, setOn] = useState15(enabled);
3545
+ const [code, setCode] = useState15("");
3546
+ const [phone, setPhone] = useState15("");
3547
+ const [error, setError] = useState15(null);
3548
+ const [busy, setBusy] = useState15(false);
3117
3549
  if (!token) {
3118
3550
  return null;
3119
3551
  }
@@ -3191,17 +3623,17 @@ function TwoFactorManager({
3191
3623
  setBusy(false);
3192
3624
  }
3193
3625
  }
3194
- return /* @__PURE__ */ jsxs16("div", { className: cls("b316-card b316-mfa", className), style, children: [
3195
- /* @__PURE__ */ jsx17("h3", { className: "b316-mfa-title", children: "Two-factor authentication" }),
3196
- error ? /* @__PURE__ */ jsx17("div", { className: "b316-error", role: "alert", children: error }) : null,
3197
- stage.name === "saved" ? /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-codes", children: [
3198
- /* @__PURE__ */ jsx17("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." }),
3199
- /* @__PURE__ */ jsx17("ul", { className: "b316-mfa-code-list", children: stage.recoveryCodes.map((recovery) => /* @__PURE__ */ jsx17("li", { children: /* @__PURE__ */ jsx17("code", { children: recovery }) }, recovery)) }),
3200
- /* @__PURE__ */ jsx17("button", { type: "button", className: "b316-button", onClick: () => setStage({ name: "idle" }), children: "I have saved them" })
3201
- ] }) : stage.name === "smsNumber" ? /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-enrol", children: [
3202
- /* @__PURE__ */ jsx17("p", { children: "We will text a code to this number now, and each time you sign in." }),
3203
- /* @__PURE__ */ jsx17("label", { className: "b316-label", htmlFor: "b316-mfa-phone", children: "Mobile number" }),
3204
- /* @__PURE__ */ jsx17(
3626
+ return /* @__PURE__ */ jsxs18("div", { className: cls("b316-card b316-mfa", className), style, children: [
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,
3629
+ stage.name === "saved" ? /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-codes", children: [
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" })
3633
+ ] }) : stage.name === "smsNumber" ? /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-enrol", children: [
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(
3205
3637
  "input",
3206
3638
  {
3207
3639
  id: "b316-mfa-phone",
@@ -3213,8 +3645,8 @@ function TwoFactorManager({
3213
3645
  onChange: (event) => setPhone(event.target.value)
3214
3646
  }
3215
3647
  ),
3216
- /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-actions", children: [
3217
- /* @__PURE__ */ jsx17(
3648
+ /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-actions", children: [
3649
+ /* @__PURE__ */ jsx20(
3218
3650
  "button",
3219
3651
  {
3220
3652
  type: "button",
@@ -3223,16 +3655,16 @@ function TwoFactorManager({
3223
3655
  children: "Cancel"
3224
3656
  }
3225
3657
  ),
3226
- /* @__PURE__ */ jsx17("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" })
3227
3659
  ] })
3228
- ] }) : stage.name === "enrollingEmail" ? /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-enrol", children: [
3229
- /* @__PURE__ */ jsxs16("p", { children: [
3660
+ ] }) : stage.name === "enrollingEmail" ? /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-enrol", children: [
3661
+ /* @__PURE__ */ jsxs18("p", { children: [
3230
3662
  "We sent a code to ",
3231
3663
  stage.destinationHint,
3232
3664
  ". Enter it below to turn this on."
3233
3665
  ] }),
3234
- /* @__PURE__ */ jsx17("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3235
- /* @__PURE__ */ jsx17(
3666
+ /* @__PURE__ */ jsx20("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3667
+ /* @__PURE__ */ jsx20(
3236
3668
  "input",
3237
3669
  {
3238
3670
  id: "b316-mfa-code",
@@ -3243,8 +3675,8 @@ function TwoFactorManager({
3243
3675
  onChange: (event) => setCode(event.target.value)
3244
3676
  }
3245
3677
  ),
3246
- /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-actions", children: [
3247
- /* @__PURE__ */ jsx17(
3678
+ /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-actions", children: [
3679
+ /* @__PURE__ */ jsx20(
3248
3680
  "button",
3249
3681
  {
3250
3682
  type: "button",
@@ -3253,7 +3685,7 @@ function TwoFactorManager({
3253
3685
  children: "Cancel"
3254
3686
  }
3255
3687
  ),
3256
- /* @__PURE__ */ jsx17(
3688
+ /* @__PURE__ */ jsx20(
3257
3689
  "button",
3258
3690
  {
3259
3691
  type: "button",
@@ -3264,9 +3696,9 @@ function TwoFactorManager({
3264
3696
  }
3265
3697
  )
3266
3698
  ] })
3267
- ] }) : stage.name === "enrolling" ? /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-enrol", children: [
3268
- /* @__PURE__ */ jsx17("p", { children: "Scan this with your authenticator app (Google Authenticator, 1Password, Authy\u2026), then enter the six-digit code it shows." }),
3269
- /* @__PURE__ */ jsx17(
3699
+ ] }) : stage.name === "enrolling" ? /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-enrol", children: [
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(
3270
3702
  QrCode,
3271
3703
  {
3272
3704
  className: "b316-mfa-qr",
@@ -3274,13 +3706,13 @@ function TwoFactorManager({
3274
3706
  label: "QR code for your authenticator app"
3275
3707
  }
3276
3708
  ),
3277
- /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-secret", children: [
3278
- /* @__PURE__ */ jsx17("span", { className: "b316-label", id: "b316-mfa-manual-key", children: "Can't scan? Enter this key" }),
3279
- /* @__PURE__ */ jsx17("code", { "aria-labelledby": "b316-mfa-manual-key", children: groupKey(stage.secret) })
3709
+ /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-secret", children: [
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) })
3280
3712
  ] }),
3281
- /* @__PURE__ */ jsx17("a", { className: "b316-mfa-uri", href: stage.uri, children: "Open in an authenticator app" }),
3282
- /* @__PURE__ */ jsx17("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3283
- /* @__PURE__ */ jsx17(
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(
3284
3716
  "input",
3285
3717
  {
3286
3718
  id: "b316-mfa-code",
@@ -3291,8 +3723,8 @@ function TwoFactorManager({
3291
3723
  onChange: (event) => setCode(event.target.value)
3292
3724
  }
3293
3725
  ),
3294
- /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-actions", children: [
3295
- /* @__PURE__ */ jsx17(
3726
+ /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-actions", children: [
3727
+ /* @__PURE__ */ jsx20(
3296
3728
  "button",
3297
3729
  {
3298
3730
  type: "button",
@@ -3301,7 +3733,7 @@ function TwoFactorManager({
3301
3733
  children: "Cancel"
3302
3734
  }
3303
3735
  ),
3304
- /* @__PURE__ */ jsx17(
3736
+ /* @__PURE__ */ jsx20(
3305
3737
  "button",
3306
3738
  {
3307
3739
  type: "button",
@@ -3312,9 +3744,9 @@ function TwoFactorManager({
3312
3744
  }
3313
3745
  )
3314
3746
  ] })
3315
- ] }) : on ? /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-on", children: [
3316
- /* @__PURE__ */ jsx17("p", { className: "b316-muted", children: "On. You will be asked for a code when you sign in." }),
3317
- /* @__PURE__ */ jsx17(
3747
+ ] }) : on ? /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-on", children: [
3748
+ /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "On. You will be asked for a code when you sign in." }),
3749
+ /* @__PURE__ */ jsx20(
3318
3750
  ConfirmButton,
3319
3751
  {
3320
3752
  className: "b316-button-quiet b316-danger",
@@ -3324,11 +3756,11 @@ function TwoFactorManager({
3324
3756
  children: "Turn off"
3325
3757
  }
3326
3758
  )
3327
- ] }) : /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-off", children: [
3328
- /* @__PURE__ */ jsx17("p", { className: "b316-muted", children: "Off. Turning it on means a code as well as your password, every time you sign in." }),
3329
- /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-actions", children: [
3330
- /* @__PURE__ */ jsx17("button", { type: "button", className: "b316-button", disabled: busy, onClick: begin, children: busy ? "Starting\u2026" : "Use an authenticator app" }),
3331
- /* @__PURE__ */ jsx17(
3759
+ ] }) : /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-off", children: [
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." }),
3761
+ /* @__PURE__ */ jsxs18("div", { className: "b316-mfa-actions", children: [
3762
+ /* @__PURE__ */ jsx20("button", { type: "button", className: "b316-button", disabled: busy, onClick: begin, children: busy ? "Starting\u2026" : "Use an authenticator app" }),
3763
+ /* @__PURE__ */ jsx20(
3332
3764
  "button",
3333
3765
  {
3334
3766
  type: "button",
@@ -3338,7 +3770,7 @@ function TwoFactorManager({
3338
3770
  children: "Email me a code"
3339
3771
  }
3340
3772
  ),
3341
- allowSms ? /* @__PURE__ */ jsx17(
3773
+ allowSms ? /* @__PURE__ */ jsx20(
3342
3774
  "button",
3343
3775
  {
3344
3776
  type: "button",
@@ -3354,14 +3786,14 @@ function TwoFactorManager({
3354
3786
  }
3355
3787
 
3356
3788
  // src/ForgotPassword.tsx
3357
- import { useState as useState15 } from "react";
3358
- import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
3789
+ import { useState as useState16 } from "react";
3790
+ import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
3359
3791
  function ForgotPassword({ onSent, signInUrl, className, style }) {
3360
3792
  const { client } = useBase316();
3361
- const [email, setEmail] = useState15("");
3362
- const [sent, setSent] = useState15(false);
3363
- const [busy, setBusy] = useState15(false);
3364
- const [error, setError] = useState15(null);
3793
+ const [email, setEmail] = useState16("");
3794
+ const [sent, setSent] = useState16(false);
3795
+ const [busy, setBusy] = useState16(false);
3796
+ const [error, setError] = useState16(null);
3365
3797
  async function submit(event) {
3366
3798
  event.preventDefault();
3367
3799
  setBusy(true);
@@ -3377,22 +3809,22 @@ function ForgotPassword({ onSent, signInUrl, className, style }) {
3377
3809
  }
3378
3810
  }
3379
3811
  if (sent) {
3380
- return /* @__PURE__ */ jsxs17("div", { className: cls("b316-card", className), style, children: [
3381
- /* @__PURE__ */ jsx18("h3", { className: "b316-form-title", children: "Check your email" }),
3382
- /* @__PURE__ */ jsxs17("p", { className: "b316-muted", children: [
3812
+ return /* @__PURE__ */ jsxs19("div", { className: cls("b316-card", className), style, children: [
3813
+ /* @__PURE__ */ jsx21("h3", { className: "b316-form-title", children: "Check your email" }),
3814
+ /* @__PURE__ */ jsxs19("p", { className: "b316-muted", children: [
3383
3815
  "If there is an account for ",
3384
3816
  email.trim(),
3385
3817
  ", a link to set a new password is on its way."
3386
3818
  ] }),
3387
- signInUrl ? /* @__PURE__ */ jsx18("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
3388
3820
  ] });
3389
3821
  }
3390
- return /* @__PURE__ */ jsxs17("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
3391
- /* @__PURE__ */ jsx18("h3", { className: "b316-form-title", children: "Reset your password" }),
3392
- error ? /* @__PURE__ */ jsx18("div", { className: "b316-error", role: "alert", children: error }) : null,
3393
- /* @__PURE__ */ jsxs17("div", { className: "b316-field", children: [
3394
- /* @__PURE__ */ jsx18("label", { className: "b316-label", htmlFor: "b316-forgot-email", children: "Email" }),
3395
- /* @__PURE__ */ jsx18(
3822
+ return /* @__PURE__ */ jsxs19("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
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,
3825
+ /* @__PURE__ */ jsxs19("div", { className: "b316-field", children: [
3826
+ /* @__PURE__ */ jsx21("label", { className: "b316-label", htmlFor: "b316-forgot-email", children: "Email" }),
3827
+ /* @__PURE__ */ jsx21(
3396
3828
  "input",
3397
3829
  {
3398
3830
  id: "b316-forgot-email",
@@ -3405,14 +3837,14 @@ function ForgotPassword({ onSent, signInUrl, className, style }) {
3405
3837
  }
3406
3838
  )
3407
3839
  ] }),
3408
- /* @__PURE__ */ jsx18("button", { type: "submit", className: "b316-button", disabled: busy || !email, children: busy ? "Sending\u2026" : "Send reset link" }),
3409
- signInUrl ? /* @__PURE__ */ jsx18("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
3410
3842
  ] });
3411
3843
  }
3412
3844
 
3413
3845
  // src/ResetPassword.tsx
3414
- import { useEffect as useEffect12, useState as useState16 } from "react";
3415
- import { jsx as jsx19, jsxs as jsxs18 } 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";
3416
3848
  function ResetPassword({
3417
3849
  token: supplied,
3418
3850
  onReset,
@@ -3421,13 +3853,13 @@ function ResetPassword({
3421
3853
  style
3422
3854
  }) {
3423
3855
  const { client } = useBase316();
3424
- const [token, setToken] = useState16(supplied ?? null);
3425
- const [password, setPassword] = useState16("");
3426
- const [confirmation, setConfirmation] = useState16("");
3427
- const [done, setDone] = useState16(false);
3428
- const [busy, setBusy] = useState16(false);
3429
- const [error, setError] = useState16(null);
3430
- useEffect12(() => {
3856
+ const [token, setToken] = useState17(supplied ?? null);
3857
+ const [password, setPassword] = useState17("");
3858
+ const [confirmation, setConfirmation] = useState17("");
3859
+ const [done, setDone] = useState17(false);
3860
+ const [busy, setBusy] = useState17(false);
3861
+ const [error, setError] = useState17(null);
3862
+ useEffect14(() => {
3431
3863
  if (supplied || typeof window === "undefined") {
3432
3864
  return;
3433
3865
  }
@@ -3462,24 +3894,24 @@ function ResetPassword({
3462
3894
  }
3463
3895
  }
3464
3896
  if (done) {
3465
- return /* @__PURE__ */ jsxs18("div", { className: cls("b316-card", className), style, children: [
3466
- /* @__PURE__ */ jsx19("h3", { className: "b316-form-title", children: "Password changed" }),
3467
- /* @__PURE__ */ jsx19("p", { className: "b316-muted", children: "You can sign in with your new password." }),
3468
- signInUrl ? /* @__PURE__ */ jsx19("a", { className: "b316-button-link", href: signInUrl, children: "Sign in" }) : null
3897
+ return /* @__PURE__ */ jsxs20("div", { className: cls("b316-card", className), style, children: [
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
3469
3901
  ] });
3470
3902
  }
3471
3903
  if (!token) {
3472
- return /* @__PURE__ */ jsxs18("div", { className: cls("b316-card", className), style, children: [
3473
- /* @__PURE__ */ jsx19("h3", { className: "b316-form-title", children: "Nothing to reset" }),
3474
- /* @__PURE__ */ jsx19("p", { className: "b316-muted", children: "This page needs the link from your email. Request a new one if yours has expired." })
3904
+ return /* @__PURE__ */ jsxs20("div", { className: cls("b316-card", className), style, children: [
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." })
3475
3907
  ] });
3476
3908
  }
3477
- return /* @__PURE__ */ jsxs18("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
3478
- /* @__PURE__ */ jsx19("h3", { className: "b316-form-title", children: "Choose a new password" }),
3479
- error ? /* @__PURE__ */ jsx19("div", { className: "b316-error", role: "alert", children: error }) : null,
3480
- /* @__PURE__ */ jsxs18("div", { className: "b316-field", children: [
3481
- /* @__PURE__ */ jsx19("label", { className: "b316-label", htmlFor: "b316-reset-password", children: "New password" }),
3482
- /* @__PURE__ */ jsx19(
3909
+ return /* @__PURE__ */ jsxs20("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
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,
3912
+ /* @__PURE__ */ jsxs20("div", { className: "b316-field", children: [
3913
+ /* @__PURE__ */ jsx22("label", { className: "b316-label", htmlFor: "b316-reset-password", children: "New password" }),
3914
+ /* @__PURE__ */ jsx22(
3483
3915
  "input",
3484
3916
  {
3485
3917
  id: "b316-reset-password",
@@ -3492,9 +3924,9 @@ function ResetPassword({
3492
3924
  }
3493
3925
  )
3494
3926
  ] }),
3495
- /* @__PURE__ */ jsxs18("div", { className: "b316-field", children: [
3496
- /* @__PURE__ */ jsx19("label", { className: "b316-label", htmlFor: "b316-reset-confirm", children: "Repeat it" }),
3497
- /* @__PURE__ */ jsx19(
3927
+ /* @__PURE__ */ jsxs20("div", { className: "b316-field", children: [
3928
+ /* @__PURE__ */ jsx22("label", { className: "b316-label", htmlFor: "b316-reset-confirm", children: "Repeat it" }),
3929
+ /* @__PURE__ */ jsx22(
3498
3930
  "input",
3499
3931
  {
3500
3932
  id: "b316-reset-confirm",
@@ -3507,13 +3939,13 @@ function ResetPassword({
3507
3939
  }
3508
3940
  )
3509
3941
  ] }),
3510
- /* @__PURE__ */ jsx19("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" })
3511
3943
  ] });
3512
3944
  }
3513
3945
 
3514
3946
  // src/VerifyEmail.tsx
3515
- import { useEffect as useEffect13, useRef as useRef4, useState as useState17 } from "react";
3516
- import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs19 } 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";
3517
3949
  function VerifyEmail({
3518
3950
  token: supplied,
3519
3951
  onVerified,
@@ -3522,9 +3954,9 @@ function VerifyEmail({
3522
3954
  style
3523
3955
  }) {
3524
3956
  const { client } = useBase316();
3525
- const [state, setState] = useState17("waiting");
3526
- const spent = useRef4(false);
3527
- useEffect13(() => {
3957
+ const [state, setState] = useState18("waiting");
3958
+ const spent = useRef5(false);
3959
+ useEffect15(() => {
3528
3960
  if (spent.current) {
3529
3961
  return;
3530
3962
  }
@@ -3550,22 +3982,22 @@ function VerifyEmail({
3550
3982
  setState("failed");
3551
3983
  });
3552
3984
  }, [client, supplied, onVerified]);
3553
- return /* @__PURE__ */ jsx20("div", { className: cls("b316-card", className), style, children: state === "verified" ? /* @__PURE__ */ jsxs19(Fragment5, { children: [
3554
- /* @__PURE__ */ jsx20("h3", { className: "b316-form-title", children: "Email confirmed" }),
3555
- /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "Thanks \u2014 your address is verified." }),
3556
- continueUrl ? /* @__PURE__ */ jsx20("a", { className: "b316-button-link", href: continueUrl, children: "Continue" }) : null
3557
- ] }) : state === "failed" ? /* @__PURE__ */ jsxs19(Fragment5, { children: [
3558
- /* @__PURE__ */ jsx20("h3", { className: "b316-form-title", children: "That link did not work" }),
3559
- /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "It may have expired or already been used. Ask for a new one and try again." })
3560
- ] }) : state === "missing" ? /* @__PURE__ */ jsxs19(Fragment5, { children: [
3561
- /* @__PURE__ */ jsx20("h3", { className: "b316-form-title", children: "Nothing to confirm" }),
3562
- /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "This page needs the link from your email." })
3563
- ] }) : /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "Confirming your email\u2026" }) });
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
3989
+ ] }) : state === "failed" ? /* @__PURE__ */ jsxs21(Fragment7, { children: [
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." })
3992
+ ] }) : state === "missing" ? /* @__PURE__ */ jsxs21(Fragment7, { children: [
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" }) });
3564
3996
  }
3565
3997
 
3566
3998
  // src/TeamMembers.tsx
3567
- import { useCallback as useCallback7, useEffect as useEffect14, useState as useState18 } from "react";
3568
- import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs20 } 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";
3569
4001
  function TeamMembers({
3570
4002
  organizationId,
3571
4003
  onInvited,
@@ -3575,13 +4007,13 @@ function TeamMembers({
3575
4007
  style
3576
4008
  }) {
3577
4009
  const { client, token, session } = useBase316();
3578
- const [teams, setTeams] = useState18(null);
3579
- const [members, setMembers] = useState18(null);
3580
- const [invitations, setInvitations] = useState18(null);
3581
- const [email, setEmail] = useState18("");
3582
- const [busy, setBusy] = useState18(false);
3583
- const [error, setError] = useState18(null);
3584
- const [copied, setCopied] = useState18(null);
4010
+ const [teams, setTeams] = useState19(null);
4011
+ const [members, setMembers] = useState19(null);
4012
+ const [invitations, setInvitations] = useState19(null);
4013
+ const [email, setEmail] = useState19("");
4014
+ const [busy, setBusy] = useState19(false);
4015
+ const [error, setError] = useState19(null);
4016
+ const [copied, setCopied] = useState19(null);
3585
4017
  const chosen = organizationId ?? (teams?.length === 1 ? teams[0].id : null);
3586
4018
  const team = teams?.find((candidate) => candidate.id === chosen) ?? null;
3587
4019
  const load = useCallback7(() => {
@@ -3592,8 +4024,8 @@ function TeamMembers({
3592
4024
  (cause) => setError(cause instanceof Error ? cause.message : "Could not load your teams.")
3593
4025
  );
3594
4026
  }, [client, token]);
3595
- useEffect14(load, [load]);
3596
- useEffect14(() => {
4027
+ useEffect16(load, [load]);
4028
+ useEffect16(() => {
3597
4029
  if (!token || !chosen) {
3598
4030
  return;
3599
4031
  }
@@ -3624,10 +4056,10 @@ function TeamMembers({
3624
4056
  return null;
3625
4057
  }
3626
4058
  if (!teams) {
3627
- return /* @__PURE__ */ jsx21("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" });
3628
4060
  }
3629
4061
  if (!chosen) {
3630
- return /* @__PURE__ */ jsx21("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." });
3631
4063
  }
3632
4064
  const canManage = invitations !== null;
3633
4065
  async function invite(event) {
@@ -3677,30 +4109,30 @@ function TeamMembers({
3677
4109
  setError(cause instanceof Error ? cause.message : "That invitation could not be withdrawn.");
3678
4110
  }
3679
4111
  }
3680
- return /* @__PURE__ */ jsxs20("div", { className: cls("b316-card b316-team", className), style, children: [
3681
- /* @__PURE__ */ jsx21("h3", { className: "b316-team-title", children: team?.name ?? "Team" }),
4112
+ return /* @__PURE__ */ jsxs22("div", { className: cls("b316-card b316-team", className), style, children: [
4113
+ /* @__PURE__ */ jsx24("h3", { className: "b316-team-title", children: team?.name ?? "Team" }),
3682
4114
  team?.inherited ? (
3683
4115
  // Not a member of this team, so not in the list below and with nothing
3684
4116
  // to leave: access comes from the team that manages it, and ends there.
3685
- /* @__PURE__ */ jsxs20("div", { className: "b316-muted", children: [
4117
+ /* @__PURE__ */ jsxs22("div", { className: "b316-muted", children: [
3686
4118
  "You have access through",
3687
4119
  " ",
3688
4120
  teams.find((candidate) => candidate.id === team.via)?.name ?? "the organization that manages this team",
3689
4121
  "."
3690
4122
  ] })
3691
4123
  ) : null,
3692
- error ? /* @__PURE__ */ jsx21("div", { className: "b316-error", role: "alert", children: error }) : null,
3693
- /* @__PURE__ */ jsx21("ul", { className: "b316-team-list", children: (members ?? []).map((member) => /* @__PURE__ */ jsxs20("li", { className: "b316-team-member", children: [
3694
- /* @__PURE__ */ jsxs20("div", { children: [
3695
- /* @__PURE__ */ jsx21("div", { children: member.user.name ?? member.user.email ?? "Someone" }),
3696
- /* @__PURE__ */ jsxs20("div", { className: "b316-muted", 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: [
4126
+ /* @__PURE__ */ jsxs22("div", { children: [
4127
+ /* @__PURE__ */ jsx24("div", { children: member.user.name ?? member.user.email ?? "Someone" }),
4128
+ /* @__PURE__ */ jsxs22("div", { className: "b316-muted", children: [
3697
4129
  member.user.email,
3698
4130
  member.user.id === session?.userId ? " \xB7 you" : ""
3699
4131
  ] })
3700
4132
  ] }),
3701
- /* @__PURE__ */ jsxs20("div", { className: "b316-team-member-side", children: [
3702
- /* @__PURE__ */ jsx21("span", { className: "b316-chip", children: member.role.name }),
3703
- canManage || member.user.id === session?.userId ? /* @__PURE__ */ jsx21(
4133
+ /* @__PURE__ */ jsxs22("div", { className: "b316-team-member-side", children: [
4134
+ /* @__PURE__ */ jsx24("span", { className: "b316-chip", children: member.role.name }),
4135
+ canManage || member.user.id === session?.userId ? /* @__PURE__ */ jsx24(
3704
4136
  ConfirmButton,
3705
4137
  {
3706
4138
  className: "b316-button-quiet b316-danger",
@@ -3712,19 +4144,19 @@ function TeamMembers({
3712
4144
  ) : null
3713
4145
  ] })
3714
4146
  ] }, member.id)) }),
3715
- canManage && (invitations ?? []).length > 0 ? /* @__PURE__ */ jsxs20(Fragment6, { children: [
3716
- /* @__PURE__ */ jsx21("h4", { className: "b316-team-subtitle", children: "Invited" }),
3717
- /* @__PURE__ */ jsx21("ul", { className: "b316-team-list", children: (invitations ?? []).map((invitation) => /* @__PURE__ */ jsxs20("li", { className: "b316-team-member", children: [
3718
- /* @__PURE__ */ jsxs20("div", { children: [
3719
- /* @__PURE__ */ jsx21("div", { children: invitation.email }),
3720
- /* @__PURE__ */ jsxs20("div", { className: "b316-muted", children: [
4147
+ canManage && (invitations ?? []).length > 0 ? /* @__PURE__ */ jsxs22(Fragment8, { 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: [
4150
+ /* @__PURE__ */ jsxs22("div", { children: [
4151
+ /* @__PURE__ */ jsx24("div", { children: invitation.email }),
4152
+ /* @__PURE__ */ jsxs22("div", { className: "b316-muted", children: [
3721
4153
  invitation.role.name,
3722
4154
  " \xB7 expires",
3723
4155
  " ",
3724
4156
  new Date(invitation.expiresAt).toLocaleDateString()
3725
4157
  ] })
3726
4158
  ] }),
3727
- /* @__PURE__ */ jsx21(
4159
+ /* @__PURE__ */ jsx24(
3728
4160
  "button",
3729
4161
  {
3730
4162
  type: "button",
@@ -3735,10 +4167,10 @@ function TeamMembers({
3735
4167
  )
3736
4168
  ] }, invitation.id)) })
3737
4169
  ] }) : null,
3738
- canManage ? /* @__PURE__ */ jsxs20("form", { className: "b316-team-invite", onSubmit: invite, children: [
3739
- /* @__PURE__ */ jsx21("label", { className: "b316-label", htmlFor: "b316-invite-email", children: "Invite by email" }),
3740
- /* @__PURE__ */ jsxs20("div", { className: "b316-team-invite-row", children: [
3741
- /* @__PURE__ */ jsx21(
4170
+ canManage ? /* @__PURE__ */ jsxs22("form", { className: "b316-team-invite", onSubmit: invite, children: [
4171
+ /* @__PURE__ */ jsx24("label", { className: "b316-label", htmlFor: "b316-invite-email", children: "Invite by email" }),
4172
+ /* @__PURE__ */ jsxs22("div", { className: "b316-team-invite-row", children: [
4173
+ /* @__PURE__ */ jsx24(
3742
4174
  "input",
3743
4175
  {
3744
4176
  id: "b316-invite-email",
@@ -3750,19 +4182,19 @@ function TeamMembers({
3750
4182
  onChange: (event) => setEmail(event.target.value)
3751
4183
  }
3752
4184
  ),
3753
- /* @__PURE__ */ jsx21("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" })
3754
4186
  ] })
3755
4187
  ] }) : null,
3756
- copied ? /* @__PURE__ */ jsxs20("div", { className: "b316-team-link", children: [
3757
- /* @__PURE__ */ jsx21("div", { className: "b316-muted", children: "Send them this link. It is shown once and cannot be fetched again." }),
3758
- /* @__PURE__ */ jsx21("code", { children: copied })
4188
+ copied ? /* @__PURE__ */ jsxs22("div", { className: "b316-team-link", children: [
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 })
3759
4191
  ] }) : null
3760
4192
  ] });
3761
4193
  }
3762
4194
 
3763
4195
  // src/AcceptInvitation.tsx
3764
- import { useEffect as useEffect15, useState as useState19 } from "react";
3765
- import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs21 } 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";
3766
4198
  function signUpUrlWithInvitation(url, token) {
3767
4199
  const [beforeHash, ...hash] = url.split("#");
3768
4200
  const base = beforeHash ?? "";
@@ -3781,18 +4213,18 @@ function AcceptInvitation({
3781
4213
  style
3782
4214
  }) {
3783
4215
  const { client, token: session, session: user } = useBase316();
3784
- const [invitationToken, setInvitationToken] = useState19(supplied ?? null);
3785
- const [preview, setPreview] = useState19(null);
3786
- const [state, setState] = useState19("loading");
3787
- const [error, setError] = useState19(null);
3788
- const [busy, setBusy] = useState19(false);
3789
- useEffect15(() => {
4216
+ const [invitationToken, setInvitationToken] = useState20(supplied ?? null);
4217
+ const [preview, setPreview] = useState20(null);
4218
+ const [state, setState] = useState20("loading");
4219
+ const [error, setError] = useState20(null);
4220
+ const [busy, setBusy] = useState20(false);
4221
+ useEffect17(() => {
3790
4222
  if (supplied || typeof window === "undefined") {
3791
4223
  return;
3792
4224
  }
3793
4225
  setInvitationToken(new URL(window.location.href).searchParams.get("invitation"));
3794
4226
  }, [supplied]);
3795
- useEffect15(() => {
4227
+ useEffect17(() => {
3796
4228
  if (!invitationToken) {
3797
4229
  setState(supplied === void 0 ? "loading" : "invalid");
3798
4230
  return;
@@ -3829,42 +4261,42 @@ function AcceptInvitation({
3829
4261
  }
3830
4262
  }
3831
4263
  if (state === "loading") {
3832
- return /* @__PURE__ */ jsx22("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
4264
+ return /* @__PURE__ */ jsx25("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
3833
4265
  }
3834
4266
  if (state === "invalid") {
3835
- return /* @__PURE__ */ jsxs21("div", { className: cls("b316-card", className), style, children: [
3836
- /* @__PURE__ */ jsx22("h3", { className: "b316-form-title", children: "That invitation is no longer valid" }),
3837
- /* @__PURE__ */ jsx22("p", { className: "b316-muted", children: "It may have expired, been withdrawn, or already been used. Ask for a new one." })
4267
+ return /* @__PURE__ */ jsxs23("div", { className: cls("b316-card", className), style, children: [
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." })
3838
4270
  ] });
3839
4271
  }
3840
4272
  if (state === "accepted") {
3841
- return /* @__PURE__ */ jsx22("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsxs21("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: [
3842
4274
  "You have joined ",
3843
4275
  preview?.organizationName
3844
4276
  ] }) });
3845
4277
  }
3846
4278
  const matches = !user || (user.user.email ?? "").toLowerCase() === preview?.email.toLowerCase();
3847
- return /* @__PURE__ */ jsxs21("div", { className: cls("b316-card b316-invitation", className), style, children: [
3848
- /* @__PURE__ */ jsxs21("h3", { className: "b316-form-title", children: [
4279
+ return /* @__PURE__ */ jsxs23("div", { className: cls("b316-card b316-invitation", className), style, children: [
4280
+ /* @__PURE__ */ jsxs23("h3", { className: "b316-form-title", children: [
3849
4281
  "Join ",
3850
4282
  preview?.organizationName
3851
4283
  ] }),
3852
- /* @__PURE__ */ jsxs21("p", { className: "b316-muted", children: [
4284
+ /* @__PURE__ */ jsxs23("p", { className: "b316-muted", children: [
3853
4285
  "Invited as ",
3854
4286
  preview?.email,
3855
4287
  " \xB7 ",
3856
4288
  preview?.roleName
3857
4289
  ] }),
3858
- error ? /* @__PURE__ */ jsx22("div", { className: "b316-error", role: "alert", children: error }) : null,
3859
- !session ? /* @__PURE__ */ jsxs21(Fragment7, { children: [
3860
- /* @__PURE__ */ jsxs21("p", { children: [
4290
+ error ? /* @__PURE__ */ jsx25("div", { className: "b316-error", role: "alert", children: error }) : null,
4291
+ !session ? /* @__PURE__ */ jsxs23(Fragment9, { children: [
4292
+ /* @__PURE__ */ jsxs23("p", { children: [
3861
4293
  "Sign in as ",
3862
4294
  preview?.email,
3863
4295
  " to accept."
3864
4296
  ] }),
3865
- /* @__PURE__ */ jsxs21("div", { className: "b316-invitation-actions", children: [
3866
- signInUrl ? /* @__PURE__ */ jsx22("a", { className: "b316-button", href: signInUrl, children: "Sign in" }) : null,
3867
- signUpUrl ? /* @__PURE__ */ jsx22(
4297
+ /* @__PURE__ */ jsxs23("div", { className: "b316-invitation-actions", children: [
4298
+ signInUrl ? /* @__PURE__ */ jsx25("a", { className: "b316-button", href: signInUrl, children: "Sign in" }) : null,
4299
+ signUpUrl ? /* @__PURE__ */ jsx25(
3868
4300
  "a",
3869
4301
  {
3870
4302
  className: "b316-button-link",
@@ -3877,20 +4309,20 @@ function AcceptInvitation({
3877
4309
  // Said before they press anything. The server refuses this, but
3878
4310
  // finding out after a click reads as a broken invitation rather than
3879
4311
  // as being signed in as the wrong person.
3880
- /* @__PURE__ */ jsxs21("p", { children: [
4312
+ /* @__PURE__ */ jsxs23("p", { children: [
3881
4313
  "You are signed in as ",
3882
4314
  user?.user.email,
3883
4315
  ". This invitation was sent to ",
3884
4316
  preview?.email,
3885
4317
  " \u2014 sign in as that address to accept it."
3886
4318
  ] })
3887
- ) : /* @__PURE__ */ jsx22("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}` })
3888
4320
  ] });
3889
4321
  }
3890
4322
 
3891
4323
  // src/PayInvoice.tsx
3892
- import { useEffect as useEffect16, useRef as useRef5, useState as useState20 } from "react";
3893
- import { jsx as jsx23, jsxs as jsxs22 } 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";
3894
4326
  var STRIPE_SRC = "https://js.stripe.com/v3/";
3895
4327
  function loadStripeScript() {
3896
4328
  if (typeof window === "undefined") {
@@ -3922,14 +4354,14 @@ function PayInvoice({
3922
4354
  style
3923
4355
  }) {
3924
4356
  const { client } = useBase316();
3925
- const mountRef = useRef5(null);
3926
- const stripeRef = useRef5(null);
3927
- const elementsRef = useRef5(null);
3928
- const [ready, setReady] = useState20(false);
3929
- const [paying, setPaying] = useState20(false);
3930
- const [done, setDone] = useState20(false);
3931
- const [error, setError] = useState20(null);
3932
- useEffect16(() => {
4357
+ const mountRef = useRef6(null);
4358
+ const stripeRef = useRef6(null);
4359
+ const elementsRef = useRef6(null);
4360
+ const [ready, setReady] = useState21(false);
4361
+ const [paying, setPaying] = useState21(false);
4362
+ const [done, setDone] = useState21(false);
4363
+ const [error, setError] = useState21(null);
4364
+ useEffect18(() => {
3933
4365
  let cancelled = false;
3934
4366
  async function start() {
3935
4367
  const base = `${client.baseUrl}/pay/${encodeURIComponent(environmentId)}/${encodeURIComponent(token)}`;
@@ -3982,17 +4414,17 @@ function PayInvoice({
3982
4414
  onPaid?.();
3983
4415
  };
3984
4416
  if (done) {
3985
- return /* @__PURE__ */ jsx23("div", { className: cls("b316-pay", className), style, children: /* @__PURE__ */ jsx23("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." }) });
3986
4418
  }
3987
- return /* @__PURE__ */ jsxs22("form", { className: cls("b316-pay", className), style, onSubmit: submit, children: [
3988
- error ? /* @__PURE__ */ jsx23("p", { className: "b316-pay__error", role: "alert", children: error }) : null,
3989
- /* @__PURE__ */ jsx23("div", { ref: mountRef, className: "b316-pay__element" }),
3990
- /* @__PURE__ */ jsx23("button", { className: "b316-pay__submit", type: "submit", disabled: !ready || paying, children: paying ? "Paying\u2026" : "Pay" })
4419
+ return /* @__PURE__ */ jsxs24("form", { className: cls("b316-pay", className), style, onSubmit: submit, children: [
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" })
3991
4423
  ] });
3992
4424
  }
3993
4425
 
3994
4426
  // src/usePaymentLink.ts
3995
- import { useEffect as useEffect17, useRef as useRef6, useState as useState21 } from "react";
4427
+ import { useEffect as useEffect19, useRef as useRef7, useState as useState22 } from "react";
3996
4428
  function usePaymentLink({
3997
4429
  token,
3998
4430
  environmentId,
@@ -4000,10 +4432,10 @@ function usePaymentLink({
4000
4432
  onPaid
4001
4433
  }) {
4002
4434
  const { client } = useBase316();
4003
- const [status2, setStatus] = useState21({ state: "loading" });
4004
- const onPaidRef = useRef6(onPaid);
4435
+ const [status2, setStatus] = useState22({ state: "loading" });
4436
+ const onPaidRef = useRef7(onPaid);
4005
4437
  onPaidRef.current = onPaid;
4006
- useEffect17(() => {
4438
+ useEffect19(() => {
4007
4439
  let stopped = false;
4008
4440
  let timer;
4009
4441
  const statusUrl = `${client.baseUrl}/pay/${encodeURIComponent(environmentId)}/${encodeURIComponent(token)}/status`;
@@ -4052,23 +4484,23 @@ function usePaymentLink({
4052
4484
  }
4053
4485
 
4054
4486
  // src/PricingTable.tsx
4055
- import { useState as useState23 } from "react";
4487
+ import { useState as useState24 } from "react";
4056
4488
 
4057
4489
  // src/usePlans.ts
4058
- import { useCallback as useCallback8, useEffect as useEffect18, useState as useState22 } from "react";
4490
+ import { useCallback as useCallback8, useEffect as useEffect20, useState as useState23 } from "react";
4059
4491
  var CHECKOUT_STATUSES = /* @__PURE__ */ new Set([402, 409]);
4060
4492
  function usePlans(options = {}) {
4061
4493
  const { client, token } = useBase316();
4062
- const [plans, setPlans] = useState22(null);
4063
- const [error, setError] = useState22(false);
4064
- const [busyPlanVersionId, setBusy] = useState22(null);
4065
- const [lastError, setLastError] = useState22(null);
4066
- const [ownPlanVersionId, setOwnPlanVersionId] = useState22(null);
4067
- const [managedBy, setManagedBy] = useState22(null);
4068
- const [reloadCount, setReloadCount] = useState22(0);
4494
+ const [plans, setPlans] = useState23(null);
4495
+ const [error, setError] = useState23(false);
4496
+ const [busyPlanVersionId, setBusy] = useState23(null);
4497
+ const [lastError, setLastError] = useState23(null);
4498
+ const [ownPlanVersionId, setOwnPlanVersionId] = useState23(null);
4499
+ const [managedBy, setManagedBy] = useState23(null);
4500
+ const [reloadCount, setReloadCount] = useState23(0);
4069
4501
  const supplied = options.currentPlanVersionId;
4070
4502
  const discover = supplied === void 0;
4071
- useEffect18(() => {
4503
+ useEffect20(() => {
4072
4504
  let cancelled = false;
4073
4505
  client.billing.plans().then((result) => {
4074
4506
  if (!cancelled) {
@@ -4084,7 +4516,7 @@ function usePlans(options = {}) {
4084
4516
  cancelled = true;
4085
4517
  };
4086
4518
  }, [client, reloadCount]);
4087
- useEffect18(() => {
4519
+ useEffect20(() => {
4088
4520
  if (!token) {
4089
4521
  return;
4090
4522
  }
@@ -4173,7 +4605,7 @@ function usePlans(options = {}) {
4173
4605
  }
4174
4606
 
4175
4607
  // src/PricingTable.tsx
4176
- import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
4608
+ import { jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
4177
4609
  function formatAmount(amount, currency) {
4178
4610
  if (amount === null) return "Free";
4179
4611
  const value = Number(amount);
@@ -4222,7 +4654,7 @@ function PricingTable({
4222
4654
  managedBy,
4223
4655
  selectPlan
4224
4656
  } = usePlans({ currentPlanVersionId });
4225
- const [scheduled, setScheduled] = useState23(null);
4657
+ const [scheduled, setScheduled] = useState24(null);
4226
4658
  async function choose(plan) {
4227
4659
  if (onSelectPlan) {
4228
4660
  await onSelectPlan(plan.planVersionId, plan);
@@ -4239,50 +4671,50 @@ function PricingTable({
4239
4671
  }
4240
4672
  }
4241
4673
  if (error) {
4242
- return /* @__PURE__ */ jsx24("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." });
4243
4675
  }
4244
4676
  if (!plans) {
4245
- return /* @__PURE__ */ jsx24("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" });
4246
4678
  }
4247
4679
  if (plans.length === 0) {
4248
- return /* @__PURE__ */ jsx24("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." });
4249
4681
  }
4250
4682
  const anyTrial = plans.some((plan) => Boolean(plan.trialDays));
4251
4683
  const anyDescription = plans.some((plan) => Boolean(plan.description));
4252
4684
  const anyFeatured = plans.some((plan) => plan.key === featuredPlanKey);
4253
- return /* @__PURE__ */ jsxs23("div", { className: cls("b316-plans", className), style, children: [
4685
+ return /* @__PURE__ */ jsxs25("div", { className: cls("b316-plans", className), style, children: [
4254
4686
  managedBy ? (
4255
4687
  // A client company's plan comes from the firm that runs it. The table
4256
4688
  // still shows what is on offer, with the current plan marked, but
4257
4689
  // nothing here can be bought: it would grant this account nothing.
4258
- /* @__PURE__ */ jsxs23("div", { className: "b316-plans-managed b316-muted", children: [
4690
+ /* @__PURE__ */ jsxs25("div", { className: "b316-plans-managed b316-muted", children: [
4259
4691
  "Your plan is provided by ",
4260
4692
  managedBy.name ?? "the organization that manages your account",
4261
4693
  ". Ask them to change it."
4262
4694
  ] })
4263
- ) : lastError ? /* @__PURE__ */ jsx24("div", { className: "b316-plans-error", role: "alert", children: lastError }) : scheduled ? /* @__PURE__ */ jsx24("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,
4264
4696
  plans.map((plan) => {
4265
4697
  const base = plan.prices.find((price) => price.featureId === null) ?? plan.prices[0];
4266
4698
  const isCurrent = current === plan.planVersionId;
4267
4699
  const featured = featuredPlanKey === plan.key;
4268
- return /* @__PURE__ */ jsxs23(
4700
+ return /* @__PURE__ */ jsxs25(
4269
4701
  "div",
4270
4702
  {
4271
4703
  className: featured ? "b316-card b316-plan b316-plan-featured" : "b316-card b316-plan",
4272
4704
  children: [
4273
- /* @__PURE__ */ jsxs23("div", { className: "b316-plan-head", children: [
4274
- anyFeatured ? /* @__PURE__ */ jsx24("div", { className: featured ? "b316-plan-badge" : "b316-plan-badge-spacer", children: featured ? "Recommended" : "\xA0" }) : null,
4275
- /* @__PURE__ */ jsx24("div", { className: "b316-plan-name", children: plan.name }),
4276
- anyDescription ? /* @__PURE__ */ jsx24("div", { className: "b316-plan-desc", children: plan.description ?? "\xA0" }) : null
4705
+ /* @__PURE__ */ jsxs25("div", { className: "b316-plan-head", children: [
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
4277
4709
  ] }),
4278
- /* @__PURE__ */ jsxs23("div", { className: "b316-plan-pricing", children: [
4279
- /* @__PURE__ */ jsx24("div", { className: "b316-plan-price", children: formatAmount(base?.amount ?? null, plan.currency) }),
4280
- /* @__PURE__ */ jsx24("div", { className: "b316-plan-cadence", children: cadence(plan, base?.amount ?? null) }),
4281
- anyTrial ? /* @__PURE__ */ jsx24("div", { className: "b316-plan-trial", children: describeTrial(plan, plans) ?? "\xA0" }) : null
4710
+ /* @__PURE__ */ jsxs25("div", { className: "b316-plan-pricing", children: [
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
4282
4714
  ] }),
4283
- /* @__PURE__ */ jsx24("ul", { className: "b316-plan-features", children: plan.entitlements.filter((entitlement) => entitlement.enabled).map((entitlement) => /* @__PURE__ */ jsxs23("li", { className: "b316-plan-feature", children: [
4284
- /* @__PURE__ */ jsx24("span", { children: entitlement.featureName }),
4285
- /* @__PURE__ */ jsx24("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" : (
4286
4718
  // A usage price on the feature makes the limit an
4287
4719
  // allowance billed past, not a ceiling — the same
4288
4720
  // rule `check()` applies (any non-FLAT price).
@@ -4291,7 +4723,7 @@ function PricingTable({
4291
4723
  ) ? `${entitlement.limit} included` : entitlement.limit
4292
4724
  ) })
4293
4725
  ] }, entitlement.featureId)) }),
4294
- /* @__PURE__ */ jsx24("div", { className: "b316-plan-action", children: /* @__PURE__ */ jsx24(
4726
+ /* @__PURE__ */ jsx27("div", { className: "b316-plan-action", children: /* @__PURE__ */ jsx27(
4295
4727
  "button",
4296
4728
  {
4297
4729
  type: "button",
@@ -4311,16 +4743,104 @@ function PricingTable({
4311
4743
  ] });
4312
4744
  }
4313
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
+
4314
4834
  // src/DataTable.tsx
4315
4835
  import { specFor as specFor3 } from "@base316/sdk";
4316
- import { useState as useState27 } from "react";
4836
+ import { useState as useState29 } from "react";
4317
4837
 
4318
4838
  // src/fields.tsx
4319
4839
  import {
4320
4840
  formatAddress,
4321
4841
  specFor
4322
4842
  } from "@base316/sdk";
4323
- import { jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
4843
+ import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
4324
4844
  function formatNumber(value, fraction = 0) {
4325
4845
  const number = Number(value);
4326
4846
  return Number.isFinite(number) ? new Intl.NumberFormat(void 0, {
@@ -4342,10 +4862,10 @@ function formatDuration(value) {
4342
4862
  }
4343
4863
  function FieldCell({ value, field, related }) {
4344
4864
  if (field.type === "RELATION") {
4345
- return related?.title ?? (related?.id ? /* @__PURE__ */ jsx25("code", { className: "b316-muted", children: related.id }) : "\u2014");
4865
+ return related?.title ?? (related?.id ? /* @__PURE__ */ jsx28("code", { className: "b316-muted", children: related.id }) : "\u2014");
4346
4866
  }
4347
4867
  if (value === null || value === void 0 || value === "") {
4348
- return /* @__PURE__ */ jsx25("span", { className: "b316-muted", children: "\u2014" });
4868
+ return /* @__PURE__ */ jsx28("span", { className: "b316-muted", children: "\u2014" });
4349
4869
  }
4350
4870
  switch (field.type) {
4351
4871
  case "BOOLEAN":
@@ -4358,9 +4878,9 @@ function FieldCell({ value, field, related }) {
4358
4878
  return formatDuration(value);
4359
4879
  case "RATING": {
4360
4880
  const stars = Math.round(Number(value));
4361
- return /* @__PURE__ */ jsxs24("span", { "aria-label": `${stars} out of 5`, children: [
4881
+ return /* @__PURE__ */ jsxs26("span", { "aria-label": `${stars} out of 5`, children: [
4362
4882
  "\u2605".repeat(stars),
4363
- /* @__PURE__ */ jsx25("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)) })
4364
4884
  ] });
4365
4885
  }
4366
4886
  case "DATE":
@@ -4368,15 +4888,15 @@ function FieldCell({ value, field, related }) {
4368
4888
  case "DATETIME":
4369
4889
  return new Date(String(value)).toLocaleString();
4370
4890
  case "SELECT":
4371
- return /* @__PURE__ */ jsx25("span", { className: "b316-chip", children: String(value) });
4891
+ return /* @__PURE__ */ jsx28("span", { className: "b316-chip", children: String(value) });
4372
4892
  case "MULTISELECT":
4373
- return /* @__PURE__ */ jsx25("span", { className: "b316-chips", children: (Array.isArray(value) ? value : [value]).map((item) => /* @__PURE__ */ jsx25("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))) });
4374
4894
  case "URL":
4375
- return /* @__PURE__ */ jsx25("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) });
4376
4896
  case "EMAIL":
4377
- return /* @__PURE__ */ jsx25("a", { href: `mailto:${String(value)}`, children: String(value) });
4897
+ return /* @__PURE__ */ jsx28("a", { href: `mailto:${String(value)}`, children: String(value) });
4378
4898
  case "PHONE":
4379
- return /* @__PURE__ */ jsx25("a", { href: `tel:${String(value)}`, children: String(value) });
4899
+ return /* @__PURE__ */ jsx28("a", { href: `tel:${String(value)}`, children: String(value) });
4380
4900
  case "ADDRESS":
4381
4901
  return formatAddress(value);
4382
4902
  case "ATTACHMENT": {
@@ -4388,7 +4908,7 @@ function FieldCell({ value, field, related }) {
4388
4908
  return text.length > 80 ? `${text.slice(0, 80)}\u2026` : text;
4389
4909
  }
4390
4910
  case "JSON":
4391
- return /* @__PURE__ */ jsx25("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) });
4392
4912
  default:
4393
4913
  return String(value);
4394
4914
  }
@@ -4409,7 +4929,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4409
4929
  function control() {
4410
4930
  switch (field.type) {
4411
4931
  case "LONGTEXT":
4412
- return /* @__PURE__ */ jsx25(
4932
+ return /* @__PURE__ */ jsx28(
4413
4933
  "textarea",
4414
4934
  {
4415
4935
  ...common,
@@ -4419,7 +4939,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4419
4939
  }
4420
4940
  );
4421
4941
  case "BOOLEAN":
4422
- return /* @__PURE__ */ jsx25(
4942
+ return /* @__PURE__ */ jsx28(
4423
4943
  "input",
4424
4944
  {
4425
4945
  ...common,
@@ -4430,22 +4950,22 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4430
4950
  }
4431
4951
  );
4432
4952
  case "SELECT":
4433
- return /* @__PURE__ */ jsxs24(
4953
+ return /* @__PURE__ */ jsxs26(
4434
4954
  "select",
4435
4955
  {
4436
4956
  ...common,
4437
4957
  value: value === null || value === void 0 ? "" : String(value),
4438
4958
  onChange: (event) => onChange(event.target.value === "" ? null : event.target.value),
4439
4959
  children: [
4440
- field.required ? null : /* @__PURE__ */ jsx25("option", { value: "", children: "\u2014" }),
4441
- (field.options ?? []).map((option) => /* @__PURE__ */ jsx25("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))
4442
4962
  ]
4443
4963
  }
4444
4964
  );
4445
4965
  case "MULTISELECT": {
4446
4966
  const selected = new Set(Array.isArray(value) ? value.map(String) : []);
4447
- return /* @__PURE__ */ jsx25("div", { className: "b316-choices", children: (field.options ?? []).map((option) => /* @__PURE__ */ jsxs24("label", { className: "b316-choice", children: [
4448
- /* @__PURE__ */ jsx25(
4967
+ return /* @__PURE__ */ jsx28("div", { className: "b316-choices", children: (field.options ?? []).map((option) => /* @__PURE__ */ jsxs26("label", { className: "b316-choice", children: [
4968
+ /* @__PURE__ */ jsx28(
4449
4969
  "input",
4450
4970
  {
4451
4971
  type: "checkbox",
@@ -4468,7 +4988,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4468
4988
  case "NUMBER":
4469
4989
  case "MONEY":
4470
4990
  case "PERCENT":
4471
- return /* @__PURE__ */ jsx25(
4991
+ return /* @__PURE__ */ jsx28(
4472
4992
  "input",
4473
4993
  {
4474
4994
  ...common,
@@ -4479,7 +4999,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4479
4999
  }
4480
5000
  );
4481
5001
  case "RATING":
4482
- return /* @__PURE__ */ jsx25(
5002
+ return /* @__PURE__ */ jsx28(
4483
5003
  "input",
4484
5004
  {
4485
5005
  ...common,
@@ -4493,8 +5013,8 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4493
5013
  );
4494
5014
  case "DURATION": {
4495
5015
  const minutes = value === null || value === void 0 ? "" : String(Number(value) / 60);
4496
- return /* @__PURE__ */ jsxs24("div", { className: "b316-suffixed", children: [
4497
- /* @__PURE__ */ jsx25(
5016
+ return /* @__PURE__ */ jsxs26("div", { className: "b316-suffixed", children: [
5017
+ /* @__PURE__ */ jsx28(
4498
5018
  "input",
4499
5019
  {
4500
5020
  ...common,
@@ -4504,11 +5024,11 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4504
5024
  onChange: (event) => onChange(event.target.value === "" ? null : Number(event.target.value) * 60)
4505
5025
  }
4506
5026
  ),
4507
- /* @__PURE__ */ jsx25("span", { className: "b316-muted", children: "minutes" })
5027
+ /* @__PURE__ */ jsx28("span", { className: "b316-muted", children: "minutes" })
4508
5028
  ] });
4509
5029
  }
4510
5030
  case "DATE":
4511
- return /* @__PURE__ */ jsx25(
5031
+ return /* @__PURE__ */ jsx28(
4512
5032
  "input",
4513
5033
  {
4514
5034
  ...common,
@@ -4518,7 +5038,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4518
5038
  }
4519
5039
  );
4520
5040
  case "DATETIME":
4521
- return /* @__PURE__ */ jsx25(
5041
+ return /* @__PURE__ */ jsx28(
4522
5042
  "input",
4523
5043
  {
4524
5044
  ...common,
@@ -4531,7 +5051,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4531
5051
  );
4532
5052
  case "ADDRESS": {
4533
5053
  const address = value ?? {};
4534
- const part = (key, label) => /* @__PURE__ */ jsx25(
5054
+ const part = (key, label) => /* @__PURE__ */ jsx28(
4535
5055
  "input",
4536
5056
  {
4537
5057
  className: "b316-input",
@@ -4543,7 +5063,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4543
5063
  },
4544
5064
  key
4545
5065
  );
4546
- return /* @__PURE__ */ jsxs24("div", { className: "b316-address", children: [
5066
+ return /* @__PURE__ */ jsxs26("div", { className: "b316-address", children: [
4547
5067
  part("line1", "Address line 1"),
4548
5068
  part("line2", "Address line 2"),
4549
5069
  part("city", "City"),
@@ -4553,7 +5073,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4553
5073
  ] });
4554
5074
  }
4555
5075
  case "EMAIL":
4556
- return /* @__PURE__ */ jsx25(
5076
+ return /* @__PURE__ */ jsx28(
4557
5077
  "input",
4558
5078
  {
4559
5079
  ...common,
@@ -4563,7 +5083,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4563
5083
  }
4564
5084
  );
4565
5085
  case "URL":
4566
- return /* @__PURE__ */ jsx25(
5086
+ return /* @__PURE__ */ jsx28(
4567
5087
  "input",
4568
5088
  {
4569
5089
  ...common,
@@ -4573,7 +5093,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4573
5093
  }
4574
5094
  );
4575
5095
  case "PHONE":
4576
- return /* @__PURE__ */ jsx25(
5096
+ return /* @__PURE__ */ jsx28(
4577
5097
  "input",
4578
5098
  {
4579
5099
  ...common,
@@ -4583,7 +5103,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4583
5103
  }
4584
5104
  );
4585
5105
  default:
4586
- return /* @__PURE__ */ jsx25(
5106
+ return /* @__PURE__ */ jsx28(
4587
5107
  "input",
4588
5108
  {
4589
5109
  ...common,
@@ -4594,24 +5114,24 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4594
5114
  );
4595
5115
  }
4596
5116
  }
4597
- return /* @__PURE__ */ jsxs24("div", { className: "b316-field", children: [
4598
- /* @__PURE__ */ jsxs24("label", { className: "b316-label", htmlFor: id, children: [
5117
+ return /* @__PURE__ */ jsxs26("div", { className: "b316-field", children: [
5118
+ /* @__PURE__ */ jsxs26("label", { className: "b316-label", htmlFor: id, children: [
4599
5119
  field.label,
4600
- field.required ? /* @__PURE__ */ jsx25("span", { "aria-hidden": "true", children: " *" }) : null
5120
+ field.required ? /* @__PURE__ */ jsx28("span", { "aria-hidden": "true", children: " *" }) : null
4601
5121
  ] }),
4602
5122
  control(),
4603
- field.description ? /* @__PURE__ */ jsx25("div", { className: "b316-hint", children: field.description }) : null,
4604
- error ? /* @__PURE__ */ jsx25("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
4605
5125
  ] });
4606
5126
  }
4607
5127
 
4608
5128
  // src/RecordForm.tsx
4609
5129
  import { specFor as specFor2 } from "@base316/sdk";
4610
- import { useEffect as useEffect21, useState as useState26 } from "react";
5130
+ import { useEffect as useEffect24, useState as useState28 } from "react";
4611
5131
 
4612
5132
  // src/RelationPicker.tsx
4613
- import { useEffect as useEffect19, useRef as useRef7, useState as useState24 } from "react";
4614
- import { Fragment as Fragment8, jsx as jsx26, jsxs as jsxs25 } 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";
4615
5135
  function RelationPicker({
4616
5136
  field,
4617
5137
  value,
@@ -4621,13 +5141,13 @@ function RelationPicker({
4621
5141
  tenant
4622
5142
  }) {
4623
5143
  const { client, token } = useBase316();
4624
- const [query, setQuery] = useState24("");
4625
- const [results, setResults] = useState24([]);
4626
- const [chosenTitle, setChosenTitle] = useState24(null);
4627
- const [open, setOpen] = useState24(false);
5144
+ const [query, setQuery] = useState26("");
5145
+ const [results, setResults] = useState26([]);
5146
+ const [chosenTitle, setChosenTitle] = useState26(null);
5147
+ const [open, setOpen] = useState26(false);
4628
5148
  const id = `b316-field-${field.key}`;
4629
- const box = useRef7(null);
4630
- useEffect19(() => {
5149
+ const box = useRef8(null);
5150
+ useEffect22(() => {
4631
5151
  if (!token || !value || !field.relationTo) {
4632
5152
  setChosenTitle(null);
4633
5153
  return;
@@ -4642,7 +5162,7 @@ function RelationPicker({
4642
5162
  cancelled = true;
4643
5163
  };
4644
5164
  }, [client, token, value, field.relationTo, tenant]);
4645
- useEffect19(() => {
5165
+ useEffect22(() => {
4646
5166
  if (!token || !field.relationTo || !open) {
4647
5167
  return;
4648
5168
  }
@@ -4668,7 +5188,7 @@ function RelationPicker({
4668
5188
  clearTimeout(timer);
4669
5189
  };
4670
5190
  }, [client, token, field.relationTo, query, open, tenant]);
4671
- useEffect19(() => {
5191
+ useEffect22(() => {
4672
5192
  if (!open || typeof document === "undefined") {
4673
5193
  return;
4674
5194
  }
@@ -4682,14 +5202,14 @@ function RelationPicker({
4682
5202
  document.removeEventListener("mousedown", onDocumentClick);
4683
5203
  };
4684
5204
  }, [open]);
4685
- return /* @__PURE__ */ jsxs25("div", { className: "b316-field", ref: box, children: [
4686
- /* @__PURE__ */ jsxs25("label", { className: "b316-label", htmlFor: id, children: [
5205
+ return /* @__PURE__ */ jsxs27("div", { className: "b316-field", ref: box, children: [
5206
+ /* @__PURE__ */ jsxs27("label", { className: "b316-label", htmlFor: id, children: [
4687
5207
  field.label,
4688
- field.required ? /* @__PURE__ */ jsx26("span", { "aria-hidden": "true", children: " *" }) : null
5208
+ field.required ? /* @__PURE__ */ jsx29("span", { "aria-hidden": "true", children: " *" }) : null
4689
5209
  ] }),
4690
- value && !open ? /* @__PURE__ */ jsxs25("div", { className: "b316-relation-chosen", children: [
4691
- /* @__PURE__ */ jsx26("span", { children: chosenTitle ?? value }),
4692
- disabled ? null : /* @__PURE__ */ jsx26(
5210
+ value && !open ? /* @__PURE__ */ jsxs27("div", { className: "b316-relation-chosen", children: [
5211
+ /* @__PURE__ */ jsx29("span", { children: chosenTitle ?? value }),
5212
+ disabled ? null : /* @__PURE__ */ jsx29(
4693
5213
  "button",
4694
5214
  {
4695
5215
  type: "button",
@@ -4701,7 +5221,7 @@ function RelationPicker({
4701
5221
  children: "Change"
4702
5222
  }
4703
5223
  ),
4704
- disabled || field.required ? null : /* @__PURE__ */ jsx26(
5224
+ disabled || field.required ? null : /* @__PURE__ */ jsx29(
4705
5225
  "button",
4706
5226
  {
4707
5227
  type: "button",
@@ -4711,8 +5231,8 @@ function RelationPicker({
4711
5231
  children: "Clear"
4712
5232
  }
4713
5233
  )
4714
- ] }) : /* @__PURE__ */ jsxs25(Fragment8, { children: [
4715
- /* @__PURE__ */ jsx26(
5234
+ ] }) : /* @__PURE__ */ jsxs27(Fragment10, { children: [
5235
+ /* @__PURE__ */ jsx29(
4716
5236
  "input",
4717
5237
  {
4718
5238
  id,
@@ -4733,7 +5253,7 @@ function RelationPicker({
4733
5253
  }
4734
5254
  }
4735
5255
  ),
4736
- open ? /* @__PURE__ */ jsx26("ul", { className: "b316-relation-results", id: `${id}-results`, role: "listbox", children: results.length === 0 ? /* @__PURE__ */ jsx26("li", { className: "b316-muted b316-relation-empty", children: "No matches" }) : results.map((result) => /* @__PURE__ */ jsx26("li", { children: /* @__PURE__ */ jsx26(
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(
4737
5257
  "button",
4738
5258
  {
4739
5259
  type: "button",
@@ -4749,13 +5269,13 @@ function RelationPicker({
4749
5269
  }
4750
5270
  ) }, result.id)) }) : null
4751
5271
  ] }),
4752
- field.description ? /* @__PURE__ */ jsx26("div", { className: "b316-hint", children: field.description }) : null,
4753
- error ? /* @__PURE__ */ jsx26("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
4754
5274
  ] });
4755
5275
  }
4756
5276
 
4757
5277
  // src/useCollection.ts
4758
- import { useCallback as useCallback9, useEffect as useEffect20, useMemo as useMemo3, useState as useState25 } from "react";
5278
+ import { useCallback as useCallback10, useEffect as useEffect23, useMemo as useMemo3, useState as useState27 } from "react";
4759
5279
  function fieldErrorFrom(cause) {
4760
5280
  const param = cause?.param;
4761
5281
  const message = cause instanceof Error ? cause.message : "That value was not accepted.";
@@ -4763,24 +5283,24 @@ function fieldErrorFrom(cause) {
4763
5283
  }
4764
5284
  function useCollection(collection, options = {}) {
4765
5285
  const { client, token } = useBase316();
4766
- const [schema, setSchema] = useState25(null);
4767
- const [records, setRecords] = useState25([]);
4768
- const [error, setError] = useState25(null);
4769
- const [loading, setLoading] = useState25(true);
4770
- const [total, setTotal] = useState25(0);
4771
- const [cursor, setCursor] = useState25(null);
4772
- const [reloadCount, setReloadCount] = useState25(0);
4773
- const [search, setSearch] = useState25("");
4774
- const [filters, setFilters] = useState25([]);
4775
- const [sort, setSort] = useState25(
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(
4776
5296
  options.sort ?? null
4777
5297
  );
4778
- const [fieldErrors, setFieldErrors] = useState25({});
4779
- const [saving, setSaving] = useState25(false);
5298
+ const [fieldErrors, setFieldErrors] = useState27({});
5299
+ const [saving, setSaving] = useState27(false);
4780
5300
  const { tenant, limit, recordId } = options;
4781
5301
  const fixedFilters = JSON.stringify(options.filters ?? []);
4782
5302
  const scope = useMemo3(() => tenant ? { tenant } : void 0, [tenant]);
4783
- useEffect20(() => {
5303
+ useEffect23(() => {
4784
5304
  if (!token) {
4785
5305
  return;
4786
5306
  }
@@ -4799,7 +5319,7 @@ function useCollection(collection, options = {}) {
4799
5319
  cancelled = true;
4800
5320
  };
4801
5321
  }, [client, token, collection, scope]);
4802
- useEffect20(() => {
5322
+ useEffect23(() => {
4803
5323
  if (!token || !schema) {
4804
5324
  return;
4805
5325
  }
@@ -4869,10 +5389,10 @@ function useCollection(collection, options = {}) {
4869
5389
  scope,
4870
5390
  reloadCount
4871
5391
  ]);
4872
- const reload = useCallback9(() => {
5392
+ const reload = useCallback10(() => {
4873
5393
  setReloadCount((count) => count + 1);
4874
5394
  }, []);
4875
- const loadMore = useCallback9(() => {
5395
+ const loadMore = useCallback10(() => {
4876
5396
  if (!token || !cursor) {
4877
5397
  return;
4878
5398
  }
@@ -4896,7 +5416,7 @@ function useCollection(collection, options = {}) {
4896
5416
  setLoading(false);
4897
5417
  });
4898
5418
  }, [client, token, collection, cursor, fixedFilters, filters, search, sort, limit, scope]);
4899
- const toggleSort = useCallback9((field) => {
5419
+ const toggleSort = useCallback10((field) => {
4900
5420
  setSort((current) => {
4901
5421
  if (current?.field !== field) {
4902
5422
  return { field, direction: "asc" };
@@ -4904,7 +5424,7 @@ function useCollection(collection, options = {}) {
4904
5424
  return current.direction === "asc" ? { field, direction: "desc" } : null;
4905
5425
  });
4906
5426
  }, []);
4907
- const create = useCallback9(
5427
+ const create = useCallback10(
4908
5428
  async (fields) => {
4909
5429
  if (!token) {
4910
5430
  return null;
@@ -4924,7 +5444,7 @@ function useCollection(collection, options = {}) {
4924
5444
  },
4925
5445
  [client, token, collection, scope, reload]
4926
5446
  );
4927
- const update = useCallback9(
5447
+ const update = useCallback10(
4928
5448
  async (id, fields) => {
4929
5449
  if (!token) {
4930
5450
  return null;
@@ -4946,7 +5466,7 @@ function useCollection(collection, options = {}) {
4946
5466
  },
4947
5467
  [client, token, collection, scope]
4948
5468
  );
4949
- const remove = useCallback9(
5469
+ const remove = useCallback10(
4950
5470
  async (id) => {
4951
5471
  if (!token) {
4952
5472
  return false;
@@ -4969,7 +5489,7 @@ function useCollection(collection, options = {}) {
4969
5489
  return {
4970
5490
  schema,
4971
5491
  records,
4972
- loading,
5492
+ loading: loading2,
4973
5493
  error,
4974
5494
  total,
4975
5495
  hasMore: cursor !== null,
@@ -4991,7 +5511,7 @@ function useCollection(collection, options = {}) {
4991
5511
  }
4992
5512
 
4993
5513
  // src/RecordForm.tsx
4994
- import { jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
5514
+ import { jsx as jsx30, jsxs as jsxs28 } from "react/jsx-runtime";
4995
5515
  function RecordForm({
4996
5516
  collection,
4997
5517
  recordId,
@@ -5012,20 +5532,20 @@ function RecordForm({
5012
5532
  recordId
5013
5533
  }
5014
5534
  );
5015
- const [values, setValues] = useState26(defaults ?? {});
5016
- const [loaded, setLoaded] = useState26(!recordId);
5535
+ const [values, setValues] = useState28(defaults ?? {});
5536
+ const [loaded, setLoaded] = useState28(!recordId);
5017
5537
  const existing = recordId ? records.find((record) => record.id === recordId) : void 0;
5018
- useEffect21(() => {
5538
+ useEffect24(() => {
5019
5539
  if (existing && !loaded) {
5020
5540
  setValues(existing.fields);
5021
5541
  setLoaded(true);
5022
5542
  }
5023
5543
  }, [existing, loaded]);
5024
5544
  if (error) {
5025
- return /* @__PURE__ */ jsx27("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx27("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 }) });
5026
5546
  }
5027
5547
  if (!schema || !loaded) {
5028
- return /* @__PURE__ */ jsx27("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5548
+ return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5029
5549
  }
5030
5550
  const editable = schema.fields.filter((field) => !specFor2(field).computed);
5031
5551
  async function submit(event) {
@@ -5035,11 +5555,11 @@ function RecordForm({
5035
5555
  onSaved?.(saved.id);
5036
5556
  }
5037
5557
  }
5038
- return /* @__PURE__ */ jsxs26("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
5039
- /* @__PURE__ */ jsx27("h3", { className: "b316-form-title", children: recordId ? `Edit ${schema.name.toLowerCase()}` : `New ${schema.name.toLowerCase()}` }),
5040
- fieldErrors._ ? /* @__PURE__ */ jsx27("div", { className: "b316-error", role: "alert", children: fieldErrors._ }) : null,
5558
+ return /* @__PURE__ */ jsxs28("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
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,
5041
5561
  editable.map(
5042
- (field) => field.type === "RELATION" ? /* @__PURE__ */ jsx27(
5562
+ (field) => field.type === "RELATION" ? /* @__PURE__ */ jsx30(
5043
5563
  RelationPicker,
5044
5564
  {
5045
5565
  field,
@@ -5050,7 +5570,7 @@ function RecordForm({
5050
5570
  onChange: (next) => setValues((current) => ({ ...current, [field.key]: next }))
5051
5571
  },
5052
5572
  field.key
5053
- ) : /* @__PURE__ */ jsx27(
5573
+ ) : /* @__PURE__ */ jsx30(
5054
5574
  FieldInput,
5055
5575
  {
5056
5576
  field,
@@ -5062,15 +5582,15 @@ function RecordForm({
5062
5582
  field.key
5063
5583
  )
5064
5584
  ),
5065
- /* @__PURE__ */ jsxs26("div", { className: "b316-form-actions", children: [
5066
- onCancel ? /* @__PURE__ */ jsx27("button", { type: "button", className: "b316-button-quiet", onClick: onCancel, disabled: saving, children: "Cancel" }) : null,
5067
- /* @__PURE__ */ jsx27("button", { type: "submit", className: "b316-button", disabled: saving, children: saving ? "Saving\u2026" : "Save" })
5585
+ /* @__PURE__ */ jsxs28("div", { className: "b316-form-actions", children: [
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" })
5068
5588
  ] })
5069
5589
  ] });
5070
5590
  }
5071
5591
 
5072
5592
  // src/DataTable.tsx
5073
- import { jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
5593
+ import { jsx as jsx31, jsxs as jsxs29 } from "react/jsx-runtime";
5074
5594
  function DataTable({
5075
5595
  collection,
5076
5596
  columns,
@@ -5087,7 +5607,7 @@ function DataTable({
5087
5607
  const {
5088
5608
  schema,
5089
5609
  records,
5090
- loading,
5610
+ loading: loading2,
5091
5611
  error,
5092
5612
  total,
5093
5613
  hasMore,
@@ -5099,13 +5619,13 @@ function DataTable({
5099
5619
  loadMore,
5100
5620
  remove
5101
5621
  } = useCollection(collection, options);
5102
- const [editing, setEditing] = useState27(null);
5103
- const [removeFailed, setRemoveFailed] = useState27(null);
5622
+ const [editing, setEditing] = useState29(null);
5623
+ const [removeFailed, setRemoveFailed] = useState29(null);
5104
5624
  if (error) {
5105
- return /* @__PURE__ */ jsx28("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx28("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 }) });
5106
5626
  }
5107
5627
  if (!schema) {
5108
- return /* @__PURE__ */ jsx28("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5628
+ return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5109
5629
  }
5110
5630
  const shown = columns ? (
5111
5631
  // Ordered by what was asked for, not by the schema: a caller naming
@@ -5114,10 +5634,10 @@ function DataTable({
5114
5634
  ) : schema.fields;
5115
5635
  const searchable = schema.fields.some((field) => specFor3(field).capabilities.searchable);
5116
5636
  const writable = canWrite && !readOnly;
5117
- return /* @__PURE__ */ jsxs27("div", { className: cls("b316-table-wrap", className), style, children: [
5118
- removeFailed ? /* @__PURE__ */ jsx28("div", { className: "b316-error", role: "alert", children: removeFailed }) : null,
5119
- /* @__PURE__ */ jsxs27("div", { className: "b316-table-bar", children: [
5120
- searchable && !hideSearch ? /* @__PURE__ */ jsx28(
5637
+ return /* @__PURE__ */ jsxs29("div", { className: cls("b316-table-wrap", className), style, children: [
5638
+ removeFailed ? /* @__PURE__ */ jsx31("div", { className: "b316-error", role: "alert", children: removeFailed }) : null,
5639
+ /* @__PURE__ */ jsxs29("div", { className: "b316-table-bar", children: [
5640
+ searchable && !hideSearch ? /* @__PURE__ */ jsx31(
5121
5641
  "input",
5122
5642
  {
5123
5643
  type: "search",
@@ -5127,25 +5647,25 @@ function DataTable({
5127
5647
  value: search,
5128
5648
  onChange: (event) => setSearch(event.target.value)
5129
5649
  }
5130
- ) : /* @__PURE__ */ jsx28("span", {}),
5131
- /* @__PURE__ */ jsxs27("div", { className: "b316-table-actions", children: [
5132
- /* @__PURE__ */ jsxs27("span", { className: "b316-muted", children: [
5650
+ ) : /* @__PURE__ */ jsx31("span", {}),
5651
+ /* @__PURE__ */ jsxs29("div", { className: "b316-table-actions", children: [
5652
+ /* @__PURE__ */ jsxs29("span", { className: "b316-muted", children: [
5133
5653
  total,
5134
5654
  " ",
5135
5655
  total === 1 ? schema.name.toLowerCase() : schema.namePlural.toLowerCase()
5136
5656
  ] }),
5137
- writable ? /* @__PURE__ */ jsxs27("button", { type: "button", className: "b316-button", onClick: () => setEditing("new"), children: [
5657
+ writable ? /* @__PURE__ */ jsxs29("button", { type: "button", className: "b316-button", onClick: () => setEditing("new"), children: [
5138
5658
  "New ",
5139
5659
  schema.name.toLowerCase()
5140
5660
  ] }) : null
5141
5661
  ] })
5142
5662
  ] }),
5143
- /* @__PURE__ */ jsx28("div", { className: "b316-table-scroll", children: /* @__PURE__ */ jsxs27("table", { className: "b316-table", children: [
5144
- /* @__PURE__ */ jsx28("thead", { children: /* @__PURE__ */ jsxs27("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: [
5145
5665
  shown.map((field) => {
5146
5666
  const sortable = specFor3(field).capabilities.sortable;
5147
5667
  const active = sort?.field === field.key;
5148
- return /* @__PURE__ */ jsx28("th", { scope: "col", "aria-sort": ariaSort(active, sort?.direction), children: sortable ? /* @__PURE__ */ jsxs27(
5668
+ return /* @__PURE__ */ jsx31("th", { scope: "col", "aria-sort": ariaSort(active, sort?.direction), children: sortable ? /* @__PURE__ */ jsxs29(
5149
5669
  "button",
5150
5670
  {
5151
5671
  type: "button",
@@ -5153,20 +5673,20 @@ function DataTable({
5153
5673
  onClick: () => toggleSort(field.key),
5154
5674
  children: [
5155
5675
  field.label,
5156
- /* @__PURE__ */ jsx28("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" })
5157
5677
  ]
5158
5678
  }
5159
5679
  ) : field.label }, field.key);
5160
5680
  }),
5161
- writable ? /* @__PURE__ */ jsx28("th", { scope: "col", className: "b316-table-rowactions" }) : null
5681
+ writable ? /* @__PURE__ */ jsx31("th", { scope: "col", className: "b316-table-rowactions" }) : null
5162
5682
  ] }) }),
5163
- /* @__PURE__ */ jsx28("tbody", { children: records.map((record) => /* @__PURE__ */ jsxs27(
5683
+ /* @__PURE__ */ jsx31("tbody", { children: records.map((record) => /* @__PURE__ */ jsxs29(
5164
5684
  "tr",
5165
5685
  {
5166
5686
  className: onSelect ? "b316-row-clickable" : void 0,
5167
5687
  onClick: onSelect ? () => onSelect(record) : void 0,
5168
5688
  children: [
5169
- shown.map((field) => /* @__PURE__ */ jsx28("td", { children: renderCell?.(record, field) ?? /* @__PURE__ */ jsx28(
5689
+ shown.map((field) => /* @__PURE__ */ jsx31("td", { children: renderCell?.(record, field) ?? /* @__PURE__ */ jsx31(
5170
5690
  FieldCell,
5171
5691
  {
5172
5692
  value: record.fields[field.key] ?? null,
@@ -5174,8 +5694,8 @@ function DataTable({
5174
5694
  related: record.related[field.key]
5175
5695
  }
5176
5696
  ) }, field.key)),
5177
- writable ? /* @__PURE__ */ jsxs27("td", { className: "b316-table-rowactions", children: [
5178
- /* @__PURE__ */ jsx28(
5697
+ writable ? /* @__PURE__ */ jsxs29("td", { className: "b316-table-rowactions", children: [
5698
+ /* @__PURE__ */ jsx31(
5179
5699
  "button",
5180
5700
  {
5181
5701
  type: "button",
@@ -5187,7 +5707,7 @@ function DataTable({
5187
5707
  children: "Edit"
5188
5708
  }
5189
5709
  ),
5190
- /* @__PURE__ */ jsx28(
5710
+ /* @__PURE__ */ jsx31(
5191
5711
  ConfirmButton,
5192
5712
  {
5193
5713
  className: "b316-button-quiet b316-danger",
@@ -5211,10 +5731,10 @@ function DataTable({
5211
5731
  record.id
5212
5732
  )) })
5213
5733
  ] }) }),
5214
- records.length === 0 && !loading ? /* @__PURE__ */ jsx28("div", { className: "b316-empty", children: emptyState ?? `No ${schema.namePlural.toLowerCase()} yet.` }) : null,
5215
- loading ? /* @__PURE__ */ jsx28("div", { className: "b316-empty", children: "Loading\u2026" }) : null,
5216
- hasMore ? /* @__PURE__ */ jsx28("div", { className: "b316-table-more", children: /* @__PURE__ */ jsx28("button", { type: "button", className: "b316-button-quiet", onClick: loadMore, disabled: loading, children: "Load more" }) }) : null,
5217
- editing ? /* @__PURE__ */ jsx28(
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(
5218
5738
  RecordForm,
5219
5739
  {
5220
5740
  collection,
@@ -5242,8 +5762,8 @@ import {
5242
5762
  specFor as specFor4,
5243
5763
  titleFieldOf
5244
5764
  } from "@base316/sdk";
5245
- import { useState as useState28 } from "react";
5246
- import { jsx as jsx29, jsxs as jsxs28 } from "react/jsx-runtime";
5765
+ import { useState as useState30 } from "react";
5766
+ import { jsx as jsx32, jsxs as jsxs30 } from "react/jsx-runtime";
5247
5767
  function Kanban({
5248
5768
  collection,
5249
5769
  groupBy,
@@ -5254,23 +5774,23 @@ function Kanban({
5254
5774
  style,
5255
5775
  ...options
5256
5776
  }) {
5257
- 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, {
5258
5778
  // A board shows everything at once by its nature — a column holding the
5259
5779
  // first twenty-five of two hundred is misleading rather than partial.
5260
5780
  limit: options.limit ?? 100,
5261
5781
  ...options
5262
5782
  });
5263
- const [dragging, setDragging] = useState28(null);
5264
- const [over, setOver] = useState28(null);
5783
+ const [dragging, setDragging] = useState30(null);
5784
+ const [over, setOver] = useState30(null);
5265
5785
  if (error) {
5266
- return /* @__PURE__ */ jsx29("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx29("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 }) });
5267
5787
  }
5268
5788
  if (!schema) {
5269
- return /* @__PURE__ */ jsx29("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5789
+ return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5270
5790
  }
5271
5791
  const field = groupBy ? schema.fields.find((candidate) => candidate.key === groupBy) ?? null : defaultGroupFieldOf(schema.fields);
5272
5792
  if (!field || !specFor4(field).capabilities.groupable) {
5273
- return /* @__PURE__ */ jsx29("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.` });
5274
5794
  }
5275
5795
  const columns = columnsFor(field);
5276
5796
  const shown = cardFields ? cardFields.map((key) => schema.fields.find((candidate) => candidate.key === key)).filter((candidate) => Boolean(candidate)) : (
@@ -5287,12 +5807,12 @@ function Kanban({
5287
5807
  }
5288
5808
  await update(record.id, { [field.key]: value });
5289
5809
  }
5290
- return /* @__PURE__ */ jsxs28("div", { className: cls("b316-board-wrap", className), style, children: [
5291
- /* @__PURE__ */ jsx29("div", { className: "b316-board", role: "list", children: columns.map((column) => {
5810
+ return /* @__PURE__ */ jsxs30("div", { className: cls("b316-board-wrap", className), style, children: [
5811
+ /* @__PURE__ */ jsx32("div", { className: "b316-board", role: "list", children: columns.map((column) => {
5292
5812
  const inColumn = records.filter(
5293
5813
  (record) => String(record.fields[field.key] ?? "") === String(column.value ?? "")
5294
5814
  );
5295
- return /* @__PURE__ */ jsxs28(
5815
+ return /* @__PURE__ */ jsxs30(
5296
5816
  "section",
5297
5817
  {
5298
5818
  className: over === String(column.value) ? "b316-board-column b316-board-over" : "b316-board-column",
@@ -5316,12 +5836,12 @@ function Kanban({
5316
5836
  setDragging(null);
5317
5837
  },
5318
5838
  children: [
5319
- /* @__PURE__ */ jsxs28("header", { className: "b316-board-head", children: [
5320
- /* @__PURE__ */ jsx29("span", { className: "b316-board-title", children: column.label }),
5321
- /* @__PURE__ */ jsx29("span", { className: "b316-muted", children: inColumn.length })
5839
+ /* @__PURE__ */ jsxs30("header", { className: "b316-board-head", children: [
5840
+ /* @__PURE__ */ jsx32("span", { className: "b316-board-title", children: column.label }),
5841
+ /* @__PURE__ */ jsx32("span", { className: "b316-muted", children: inColumn.length })
5322
5842
  ] }),
5323
- /* @__PURE__ */ jsxs28("div", { className: "b316-board-cards", children: [
5324
- inColumn.map((record) => /* @__PURE__ */ jsxs28(
5843
+ /* @__PURE__ */ jsxs30("div", { className: "b316-board-cards", children: [
5844
+ inColumn.map((record) => /* @__PURE__ */ jsxs30(
5325
5845
  "article",
5326
5846
  {
5327
5847
  className: "b316-board-card",
@@ -5333,10 +5853,10 @@ function Kanban({
5333
5853
  },
5334
5854
  onClick: onSelect ? () => onSelect(record) : void 0,
5335
5855
  children: [
5336
- /* @__PURE__ */ jsx29("div", { className: "b316-board-card-title", children: record.title ?? "Untitled" }),
5337
- shown.map((candidate) => /* @__PURE__ */ jsxs28("div", { className: "b316-board-card-field", children: [
5338
- /* @__PURE__ */ jsx29("span", { className: "b316-muted", children: candidate.label }),
5339
- /* @__PURE__ */ jsx29(
5856
+ /* @__PURE__ */ jsx32("div", { className: "b316-board-card-title", children: record.title ?? "Untitled" }),
5857
+ shown.map((candidate) => /* @__PURE__ */ jsxs30("div", { className: "b316-board-card-field", children: [
5858
+ /* @__PURE__ */ jsx32("span", { className: "b316-muted", children: candidate.label }),
5859
+ /* @__PURE__ */ jsx32(
5340
5860
  FieldCell,
5341
5861
  {
5342
5862
  value: record.fields[candidate.key] ?? null,
@@ -5349,9 +5869,9 @@ function Kanban({
5349
5869
  // Dragging is not reachable by keyboard and is awkward on a
5350
5870
  // phone. This is the same action by other means, not a
5351
5871
  // lesser fallback.
5352
- /* @__PURE__ */ jsxs28("label", { className: "b316-board-move", children: [
5353
- /* @__PURE__ */ jsx29("span", { className: "b316-muted", children: "Move to" }),
5354
- /* @__PURE__ */ jsx29(
5872
+ /* @__PURE__ */ jsxs30("label", { className: "b316-board-move", children: [
5873
+ /* @__PURE__ */ jsx32("span", { className: "b316-muted", children: "Move to" }),
5874
+ /* @__PURE__ */ jsx32(
5355
5875
  "select",
5356
5876
  {
5357
5877
  className: "b316-input",
@@ -5363,7 +5883,7 @@ function Kanban({
5363
5883
  );
5364
5884
  void move(record, chosen?.value ?? null);
5365
5885
  },
5366
- children: columns.map((candidate) => /* @__PURE__ */ jsx29("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)))
5367
5887
  }
5368
5888
  )
5369
5889
  ] })
@@ -5372,14 +5892,14 @@ function Kanban({
5372
5892
  },
5373
5893
  record.id
5374
5894
  )),
5375
- inColumn.length === 0 ? /* @__PURE__ */ jsx29("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
5376
5896
  ] })
5377
5897
  ]
5378
5898
  },
5379
5899
  String(column.value)
5380
5900
  );
5381
5901
  }) }),
5382
- hasMore ? /* @__PURE__ */ jsx29("div", { className: "b316-table-more", children: /* @__PURE__ */ jsxs28("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: [
5383
5903
  "Showing ",
5384
5904
  records.length,
5385
5905
  " of ",
@@ -5406,7 +5926,7 @@ import {
5406
5926
  specFor as specFor5
5407
5927
  } from "@base316/sdk";
5408
5928
  import { useMemo as useMemo4 } from "react";
5409
- import { jsx as jsx30, jsxs as jsxs29 } from "react/jsx-runtime";
5929
+ import { jsx as jsx33, jsxs as jsxs31 } from "react/jsx-runtime";
5410
5930
  function Chart({
5411
5931
  collection,
5412
5932
  x,
@@ -5419,7 +5939,7 @@ function Chart({
5419
5939
  style,
5420
5940
  ...options
5421
5941
  }) {
5422
- const { schema, records, error, loading } = useCollection(collection, {
5942
+ const { schema, records, error, loading: loading2 } = useCollection(collection, {
5423
5943
  // A chart of one page is a chart of an arbitrary subset, which is worse
5424
5944
  // than no chart: it looks like an answer.
5425
5945
  limit: options.limit ?? 200,
@@ -5445,23 +5965,23 @@ function Chart({
5445
5965
  [records, axis, measure, aggregate, bucket, y]
5446
5966
  );
5447
5967
  if (error) {
5448
- return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx30("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 }) });
5449
5969
  }
5450
- if (!schema || loading) {
5451
- return /* @__PURE__ */ jsx30("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" });
5452
5972
  }
5453
5973
  if (!axis) {
5454
- return /* @__PURE__ */ jsx30("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.` });
5455
5975
  }
5456
5976
  if (y && !measure) {
5457
- return /* @__PURE__ */ jsx30("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}`}.` });
5458
5978
  }
5459
5979
  const peak = Math.max(...buckets.map((entry) => entry.value), 0);
5460
5980
  const heading = title ?? `${measure ? `${aggregate} of ${measure.label}` : schema.namePlural} by ${axis.label}`;
5461
- return /* @__PURE__ */ jsxs29("figure", { className: cls("b316-card b316-chart", className), style, children: [
5462
- /* @__PURE__ */ jsx30("figcaption", { className: "b316-chart-title", children: heading }),
5463
- buckets.length === 0 || peak === 0 ? /* @__PURE__ */ jsx30("div", { className: "b316-empty", children: "Nothing to chart yet." }) : /* @__PURE__ */ jsx30("div", { className: "b316-chart-plot", style: { height }, children: buckets.map((entry) => /* @__PURE__ */ jsxs29("div", { className: "b316-chart-col", children: [
5464
- /* @__PURE__ */ jsx30(
5981
+ return /* @__PURE__ */ jsxs31("figure", { className: cls("b316-card b316-chart", className), style, children: [
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(
5465
5985
  "div",
5466
5986
  {
5467
5987
  className: "b316-chart-bar",
@@ -5469,18 +5989,18 @@ function Chart({
5469
5989
  title: `${entry.label}: ${format(entry.value)}`
5470
5990
  }
5471
5991
  ),
5472
- /* @__PURE__ */ jsx30("span", { className: "b316-chart-label", children: entry.label })
5992
+ /* @__PURE__ */ jsx33("span", { className: "b316-chart-label", children: entry.label })
5473
5993
  ] }, entry.key)) }),
5474
- /* @__PURE__ */ jsxs29("details", { className: "b316-chart-data", children: [
5475
- /* @__PURE__ */ jsx30("summary", { children: "Values" }),
5476
- /* @__PURE__ */ jsxs29("table", { className: "b316-table", children: [
5477
- /* @__PURE__ */ jsx30("thead", { children: /* @__PURE__ */ jsxs29("tr", { children: [
5478
- /* @__PURE__ */ jsx30("th", { scope: "col", children: axis.label }),
5479
- /* @__PURE__ */ jsx30("th", { scope: "col", children: measure ? measure.label : "Count" })
5994
+ /* @__PURE__ */ jsxs31("details", { className: "b316-chart-data", children: [
5995
+ /* @__PURE__ */ jsx33("summary", { children: "Values" }),
5996
+ /* @__PURE__ */ jsxs31("table", { className: "b316-table", children: [
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" })
5480
6000
  ] }) }),
5481
- /* @__PURE__ */ jsx30("tbody", { children: buckets.map((entry) => /* @__PURE__ */ jsxs29("tr", { children: [
5482
- /* @__PURE__ */ jsx30("td", { children: entry.label }),
5483
- /* @__PURE__ */ jsx30("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) })
5484
6004
  ] }, entry.key)) })
5485
6005
  ] })
5486
6006
  ] })
@@ -5539,8 +6059,8 @@ function combine(values, aggregate) {
5539
6059
 
5540
6060
  // src/RecordDetail.tsx
5541
6061
  import { specFor as specFor6 } from "@base316/sdk";
5542
- import { useState as useState29 } from "react";
5543
- import { jsx as jsx31, jsxs as jsxs30 } from "react/jsx-runtime";
6062
+ import { useState as useState31 } from "react";
6063
+ import { jsx as jsx34, jsxs as jsxs32 } from "react/jsx-runtime";
5544
6064
  function RecordDetail({
5545
6065
  collection,
5546
6066
  recordId,
@@ -5552,27 +6072,27 @@ function RecordDetail({
5552
6072
  className,
5553
6073
  style
5554
6074
  }) {
5555
- const { schema, records, canWrite, remove, loading, error } = useCollection(collection, {
6075
+ const { schema, records, canWrite, remove, loading: loading2, error } = useCollection(collection, {
5556
6076
  tenant,
5557
6077
  recordId
5558
6078
  });
5559
- const [editing, setEditing] = useState29(false);
6079
+ const [editing, setEditing] = useState31(false);
5560
6080
  const record = records.find((candidate) => candidate.id === recordId);
5561
6081
  if (error) {
5562
- return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx31("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 }) });
5563
6083
  }
5564
- if (!schema || loading) {
5565
- return /* @__PURE__ */ jsx31("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" });
5566
6086
  }
5567
6087
  if (!record) {
5568
- return /* @__PURE__ */ jsxs30("div", { className: cls("b316-card", className), style, children: [
6088
+ return /* @__PURE__ */ jsxs32("div", { className: cls("b316-card", className), style, children: [
5569
6089
  "That ",
5570
6090
  schema.name.toLowerCase(),
5571
6091
  " is not available."
5572
6092
  ] });
5573
6093
  }
5574
6094
  if (editing) {
5575
- return /* @__PURE__ */ jsx31(
6095
+ return /* @__PURE__ */ jsx34(
5576
6096
  RecordForm,
5577
6097
  {
5578
6098
  collection,
@@ -5586,12 +6106,12 @@ function RecordDetail({
5586
6106
  );
5587
6107
  }
5588
6108
  const writable = canWrite && !readOnly;
5589
- return /* @__PURE__ */ jsxs30("div", { className: cls("b316-card b316-detail", className), style, children: [
5590
- /* @__PURE__ */ jsxs30("div", { className: "b316-detail-head", children: [
5591
- /* @__PURE__ */ jsx31("h3", { className: "b316-detail-title", children: record.title ?? schema.name }),
5592
- /* @__PURE__ */ jsxs30("div", { className: "b316-detail-actions", children: [
5593
- writable ? /* @__PURE__ */ jsx31("button", { type: "button", className: "b316-button-quiet", onClick: () => setEditing(true), children: "Edit" }) : null,
5594
- writable ? /* @__PURE__ */ jsx31(
6109
+ return /* @__PURE__ */ jsxs32("div", { className: cls("b316-card b316-detail", className), style, children: [
6110
+ /* @__PURE__ */ jsxs32("div", { className: "b316-detail-head", children: [
6111
+ /* @__PURE__ */ jsx34("h3", { className: "b316-detail-title", children: record.title ?? schema.name }),
6112
+ /* @__PURE__ */ jsxs32("div", { className: "b316-detail-actions", children: [
6113
+ writable ? /* @__PURE__ */ jsx34("button", { type: "button", className: "b316-button-quiet", onClick: () => setEditing(true), children: "Edit" }) : null,
6114
+ writable ? /* @__PURE__ */ jsx34(
5595
6115
  ConfirmButton,
5596
6116
  {
5597
6117
  className: "b316-button-quiet b316-danger",
@@ -5604,15 +6124,15 @@ function RecordDetail({
5604
6124
  children: "Delete"
5605
6125
  }
5606
6126
  ) : null,
5607
- onClose ? /* @__PURE__ */ jsx31("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
5608
6128
  ] })
5609
6129
  ] }),
5610
- /* @__PURE__ */ jsx31("dl", { className: "b316-detail-fields", children: schema.fields.map((field) => /* @__PURE__ */ jsxs30("div", { className: "b316-detail-row", children: [
5611
- /* @__PURE__ */ jsxs30("dt", { className: "b316-label", children: [
6130
+ /* @__PURE__ */ jsx34("dl", { className: "b316-detail-fields", children: schema.fields.map((field) => /* @__PURE__ */ jsxs32("div", { className: "b316-detail-row", children: [
6131
+ /* @__PURE__ */ jsxs32("dt", { className: "b316-label", children: [
5612
6132
  field.label,
5613
- specFor6(field).computed ? /* @__PURE__ */ jsx31("span", { className: "b316-muted", children: " (calculated)" }) : null
6133
+ specFor6(field).computed ? /* @__PURE__ */ jsx34("span", { className: "b316-muted", children: " (calculated)" }) : null
5614
6134
  ] }),
5615
- /* @__PURE__ */ jsx31("dd", { children: /* @__PURE__ */ jsx31(
6135
+ /* @__PURE__ */ jsx34("dd", { children: /* @__PURE__ */ jsx34(
5616
6136
  FieldCell,
5617
6137
  {
5618
6138
  value: record.fields[field.key] ?? null,
@@ -5626,8 +6146,8 @@ function RecordDetail({
5626
6146
  }
5627
6147
 
5628
6148
  // src/SubscriptionManager.tsx
5629
- import { useCallback as useCallback10, useEffect as useEffect22, useState as useState30 } from "react";
5630
- import { jsx as jsx32, jsxs as jsxs31 } 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";
5631
6151
  function statusLabel(status2) {
5632
6152
  const words = status2.toLowerCase().split("_");
5633
6153
  return words.map((w, i) => i === 0 ? w.charAt(0).toUpperCase() + w.slice(1) : w).join(" ");
@@ -5667,16 +6187,16 @@ function SubscriptionManager({
5667
6187
  style
5668
6188
  }) {
5669
6189
  const { client, token, loading: sessionLoading } = useBase316();
5670
- const [subscription, setSubscription] = useState30(null);
5671
- const [loading, setLoading] = useState30(true);
5672
- const [managedBy, setManagedBy] = useState30(null);
5673
- const [schedule, setSchedule] = useState30([]);
5674
- const [busy, setBusy] = useState30(false);
5675
- const [error, setError] = useState30(null);
5676
- const [step, setStep] = useState30({ kind: "idle" });
5677
- const [reason, setReason] = useState30(null);
5678
- const [comment, setComment] = useState30("");
5679
- 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 () => {
5680
6200
  if (!token) {
5681
6201
  setSubscription(null);
5682
6202
  setLoading(false);
@@ -5694,7 +6214,7 @@ function SubscriptionManager({
5694
6214
  setLoading(false);
5695
6215
  }
5696
6216
  }, [client, token]);
5697
- useEffect22(() => {
6217
+ useEffect25(() => {
5698
6218
  void load();
5699
6219
  }, [load]);
5700
6220
  const act = async (change, failure) => {
@@ -5711,30 +6231,30 @@ function SubscriptionManager({
5711
6231
  setBusy(false);
5712
6232
  }
5713
6233
  };
5714
- if (sessionLoading || loading) {
5715
- return /* @__PURE__ */ jsx32("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" });
5716
6236
  }
5717
6237
  if (!token) {
5718
- return /* @__PURE__ */ jsx32("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." });
5719
6239
  }
5720
6240
  if (error) {
5721
- return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx32("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 }) });
5722
6242
  }
5723
6243
  if (!subscription) {
5724
- return /* @__PURE__ */ jsx32("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." });
5725
6245
  }
5726
6246
  const renews = new Date(subscription.currentPeriodEnd).toLocaleDateString();
5727
6247
  const next = schedule[0] ?? null;
5728
6248
  const nextOn = next?.effectiveAt ? new Date(next.effectiveAt).toLocaleDateString() : renews;
5729
- return /* @__PURE__ */ jsxs31("div", { className: cls("b316-card", className), style, children: [
5730
- error ? /* @__PURE__ */ jsx32("div", { className: "b316-error", role: "alert", children: error }) : null,
5731
- /* @__PURE__ */ jsx32("div", { className: "b316-plan-name", children: subscription.planVersion.plan.name }),
5732
- /* @__PURE__ */ jsxs31("div", { className: "b316-muted", children: [
6249
+ return /* @__PURE__ */ jsxs33("div", { className: cls("b316-card", className), style, children: [
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 }),
6252
+ /* @__PURE__ */ jsxs33("div", { className: "b316-muted", children: [
5733
6253
  statusLabel(subscription.status),
5734
6254
  " \xB7 ",
5735
6255
  subscription.cancelAtPeriodEnd ? `Ends ${renews}` : `Renews ${renews}`
5736
6256
  ] }),
5737
- next && !managedBy ? /* @__PURE__ */ jsxs31("div", { className: "b316-muted", role: "status", style: { marginTop: 10 }, children: [
6257
+ next && !managedBy ? /* @__PURE__ */ jsxs33("div", { className: "b316-muted", role: "status", style: { marginTop: 10 }, children: [
5738
6258
  "Moves to ",
5739
6259
  next.plan.name,
5740
6260
  " on ",
@@ -5742,7 +6262,7 @@ function SubscriptionManager({
5742
6262
  ". You keep ",
5743
6263
  subscription.planVersion.plan.name,
5744
6264
  " until then.",
5745
- /* @__PURE__ */ jsx32("div", { children: /* @__PURE__ */ jsx32(
6265
+ /* @__PURE__ */ jsx35("div", { children: /* @__PURE__ */ jsx35(
5746
6266
  "button",
5747
6267
  {
5748
6268
  type: "button",
@@ -5767,17 +6287,17 @@ function SubscriptionManager({
5767
6287
  }
5768
6288
  ) })
5769
6289
  ] }) : null,
5770
- managedBy ? /* @__PURE__ */ jsxs31("p", { className: "b316-muted", children: [
6290
+ managedBy ? /* @__PURE__ */ jsxs33("p", { className: "b316-muted", children: [
5771
6291
  "Provided by ",
5772
6292
  managedBy.name ?? "the organization that manages your account",
5773
6293
  ". Ask them to change or cancel it."
5774
- ] }) : subscription.cancelAtPeriodEnd ? /* @__PURE__ */ jsxs31("div", { children: [
5775
- /* @__PURE__ */ jsxs31("p", { className: "b316-muted", children: [
6294
+ ] }) : subscription.cancelAtPeriodEnd ? /* @__PURE__ */ jsxs33("div", { children: [
6295
+ /* @__PURE__ */ jsxs33("p", { className: "b316-muted", children: [
5776
6296
  "This subscription will not renew. You keep access until ",
5777
6297
  renews,
5778
6298
  "."
5779
6299
  ] }),
5780
- /* @__PURE__ */ jsx32(
6300
+ /* @__PURE__ */ jsx35(
5781
6301
  "button",
5782
6302
  {
5783
6303
  type: "button",
@@ -5787,14 +6307,14 @@ function SubscriptionManager({
5787
6307
  children: busy ? "Working\u2026" : "Resume subscription"
5788
6308
  }
5789
6309
  )
5790
- ] }) : step.kind === "offer" ? /* @__PURE__ */ jsxs31("section", { style: { marginTop: 14 }, "aria-label": "Retention offer", children: [
5791
- /* @__PURE__ */ jsx32("div", { className: "b316-plan-name", children: step.cancellation.offer.headline ?? "Before you go" }),
5792
- /* @__PURE__ */ jsx32("p", { className: "b316-muted", children: step.cancellation.offer.message ?? `Stay on ${subscription.planVersion.plan.name} and get ${describeRetentionOffer(
6310
+ ] }) : step.kind === "offer" ? /* @__PURE__ */ jsxs33("section", { style: { marginTop: 14 }, "aria-label": "Retention offer", children: [
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(
5793
6313
  step.cancellation.offer,
5794
6314
  step.cancellation.currency
5795
6315
  )}.` }),
5796
- /* @__PURE__ */ jsxs31("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
5797
- /* @__PURE__ */ jsx32(
6316
+ /* @__PURE__ */ jsxs33("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
6317
+ /* @__PURE__ */ jsx35(
5798
6318
  "button",
5799
6319
  {
5800
6320
  type: "button",
@@ -5807,7 +6327,7 @@ function SubscriptionManager({
5807
6327
  children: busy ? "Working\u2026" : "Accept offer and stay"
5808
6328
  }
5809
6329
  ),
5810
- /* @__PURE__ */ jsx32(
6330
+ /* @__PURE__ */ jsx35(
5811
6331
  "button",
5812
6332
  {
5813
6333
  type: "button",
@@ -5821,12 +6341,12 @@ function SubscriptionManager({
5821
6341
  }
5822
6342
  )
5823
6343
  ] }),
5824
- /* @__PURE__ */ jsxs31("p", { className: "b316-muted", children: [
6344
+ /* @__PURE__ */ jsxs33("p", { className: "b316-muted", children: [
5825
6345
  "If you cancel, you keep access until ",
5826
6346
  renews,
5827
6347
  "."
5828
6348
  ] })
5829
- ] }) : step.kind === "survey" ? /* @__PURE__ */ jsxs31(
6349
+ ] }) : step.kind === "survey" ? /* @__PURE__ */ jsxs33(
5830
6350
  "form",
5831
6351
  {
5832
6352
  style: { marginTop: 14 },
@@ -5846,15 +6366,15 @@ function SubscriptionManager({
5846
6366
  }, "Could not cancel. Try again.");
5847
6367
  },
5848
6368
  children: [
5849
- /* @__PURE__ */ jsxs31("p", { className: "b316-muted", children: [
6369
+ /* @__PURE__ */ jsxs33("p", { className: "b316-muted", children: [
5850
6370
  "You keep access until ",
5851
6371
  renews,
5852
6372
  ". It will not renew after that."
5853
6373
  ] }),
5854
- /* @__PURE__ */ jsxs31("fieldset", { className: "b316-fieldset", children: [
5855
- /* @__PURE__ */ jsx32("legend", { className: "b316-label", children: "Why are you leaving? (optional)" }),
5856
- REASONS.map((option) => /* @__PURE__ */ jsxs31("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
5857
- /* @__PURE__ */ jsx32(
6374
+ /* @__PURE__ */ jsxs33("fieldset", { className: "b316-fieldset", children: [
6375
+ /* @__PURE__ */ jsx35("legend", { className: "b316-label", children: "Why are you leaving? (optional)" }),
6376
+ REASONS.map((option) => /* @__PURE__ */ jsxs33("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
6377
+ /* @__PURE__ */ jsx35(
5858
6378
  "input",
5859
6379
  {
5860
6380
  type: "radio",
@@ -5864,12 +6384,12 @@ function SubscriptionManager({
5864
6384
  onChange: () => setReason(option.value)
5865
6385
  }
5866
6386
  ),
5867
- /* @__PURE__ */ jsx32("span", { children: option.label })
6387
+ /* @__PURE__ */ jsx35("span", { children: option.label })
5868
6388
  ] }, option.value))
5869
6389
  ] }),
5870
- /* @__PURE__ */ jsxs31("label", { className: "b316-field", children: [
5871
- /* @__PURE__ */ jsx32("span", { className: "b316-label", children: "Anything else? (optional)" }),
5872
- /* @__PURE__ */ jsx32(
6390
+ /* @__PURE__ */ jsxs33("label", { className: "b316-field", children: [
6391
+ /* @__PURE__ */ jsx35("span", { className: "b316-label", children: "Anything else? (optional)" }),
6392
+ /* @__PURE__ */ jsx35(
5873
6393
  "textarea",
5874
6394
  {
5875
6395
  className: "b316-input",
@@ -5880,9 +6400,9 @@ function SubscriptionManager({
5880
6400
  }
5881
6401
  )
5882
6402
  ] }),
5883
- /* @__PURE__ */ jsxs31("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
5884
- /* @__PURE__ */ jsx32("button", { type: "submit", className: "b316-button b316-button-secondary", disabled: busy, children: busy ? "Working\u2026" : "Cancel subscription" }),
5885
- /* @__PURE__ */ jsxs31(
6403
+ /* @__PURE__ */ jsxs33("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
6404
+ /* @__PURE__ */ jsx35("button", { type: "submit", className: "b316-button b316-button-secondary", disabled: busy, children: busy ? "Working\u2026" : "Cancel subscription" }),
6405
+ /* @__PURE__ */ jsxs33(
5886
6406
  "button",
5887
6407
  {
5888
6408
  type: "button",
@@ -5898,7 +6418,7 @@ function SubscriptionManager({
5898
6418
  ] })
5899
6419
  ]
5900
6420
  }
5901
- ) : /* @__PURE__ */ jsx32("div", { style: { marginTop: 14 }, children: /* @__PURE__ */ jsx32(
6421
+ ) : /* @__PURE__ */ jsx35("div", { style: { marginTop: 14 }, children: /* @__PURE__ */ jsx35(
5902
6422
  "button",
5903
6423
  {
5904
6424
  type: "button",
@@ -5916,11 +6436,11 @@ function SubscriptionManager({
5916
6436
  }
5917
6437
 
5918
6438
  // src/BillingPortal.tsx
5919
- import { useCallback as useCallback12, useEffect as useEffect26, useState as useState34 } from "react";
6439
+ import { useCallback as useCallback13, useEffect as useEffect29, useState as useState36 } from "react";
5920
6440
 
5921
6441
  // src/CreditBalances.tsx
5922
- import { useEffect as useEffect23, useState as useState31 } from "react";
5923
- import { Fragment as Fragment9, jsx as jsx33, jsxs as jsxs32 } 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";
5924
6444
  function units(value) {
5925
6445
  return value === null ? "Unlimited" : Number(value).toLocaleString("en");
5926
6446
  }
@@ -5955,10 +6475,10 @@ function Feature({
5955
6475
  }) {
5956
6476
  const { client, token } = useBase316();
5957
6477
  const setting = feature.autoRecharge;
5958
- const [busy, setBusy] = useState31(false);
5959
- const [error, setError] = useState31(null);
5960
- const [saved, setSaved] = useState31(null);
5961
- const [pack, setPack] = useState31(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 ?? "");
5962
6482
  const unit = feature.unit ? ` ${feature.unit}` : "";
5963
6483
  const warning = status(feature);
5964
6484
  const buy = async () => {
@@ -6012,33 +6532,33 @@ function Feature({
6012
6532
  setBusy(false);
6013
6533
  }
6014
6534
  };
6015
- return /* @__PURE__ */ jsxs32("div", { className: "b316-card b316-credit-balance", children: [
6016
- /* @__PURE__ */ jsx33("div", { className: "b316-label", children: feature.featureName }),
6017
- /* @__PURE__ */ jsxs32("div", { children: [
6018
- /* @__PURE__ */ jsx33("strong", { children: units(feature.remaining) }),
6535
+ return /* @__PURE__ */ jsxs34("div", { className: "b316-card b316-credit-balance", children: [
6536
+ /* @__PURE__ */ jsx36("div", { className: "b316-label", children: feature.featureName }),
6537
+ /* @__PURE__ */ jsxs34("div", { children: [
6538
+ /* @__PURE__ */ jsx36("strong", { children: units(feature.remaining) }),
6019
6539
  unit,
6020
6540
  " left"
6021
6541
  ] }),
6022
- /* @__PURE__ */ jsxs32("div", { className: "b316-muted", children: [
6542
+ /* @__PURE__ */ jsxs34("div", { className: "b316-muted", children: [
6023
6543
  feature.allowance === null ? "Unlimited allowance" : `${units(feature.allowanceRemaining)} of ${units(feature.allowance)} included this period`,
6024
6544
  " ",
6025
6545
  "\xB7 ",
6026
6546
  units(feature.purchasedRemaining),
6027
6547
  " purchased"
6028
6548
  ] }),
6029
- warning && !managed ? /* @__PURE__ */ jsx33("div", { className: "b316-error", role: "alert", children: warning }) : null,
6030
- error ? /* @__PURE__ */ jsx33("div", { className: "b316-error", role: "alert", children: error }) : null,
6031
- saved ? /* @__PURE__ */ jsx33("div", { className: "b316-notice", role: "status", children: saved }) : null,
6032
- managed || feature.packs.length === 0 ? null : /* @__PURE__ */ jsxs32(Fragment9, { children: [
6033
- /* @__PURE__ */ jsxs32("div", { className: "b316-row", style: { marginTop: 12 }, children: [
6034
- /* @__PURE__ */ jsx33(
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,
6552
+ managed || feature.packs.length === 0 ? null : /* @__PURE__ */ jsxs34(Fragment11, { children: [
6553
+ /* @__PURE__ */ jsxs34("div", { className: "b316-row", style: { marginTop: 12 }, children: [
6554
+ /* @__PURE__ */ jsx36(
6035
6555
  "select",
6036
6556
  {
6037
6557
  className: "b316-input",
6038
6558
  "aria-label": "Pack to buy",
6039
6559
  value: pack,
6040
6560
  onChange: (event) => setPack(event.target.value),
6041
- children: feature.packs.map((option) => /* @__PURE__ */ jsxs32("option", { value: option.id, children: [
6561
+ children: feature.packs.map((option) => /* @__PURE__ */ jsxs34("option", { value: option.id, children: [
6042
6562
  option.name,
6043
6563
  " \u2014 ",
6044
6564
  units(option.units),
@@ -6047,7 +6567,7 @@ function Feature({
6047
6567
  ] }, option.id))
6048
6568
  }
6049
6569
  ),
6050
- /* @__PURE__ */ jsx33(
6570
+ /* @__PURE__ */ jsx36(
6051
6571
  "button",
6052
6572
  {
6053
6573
  type: "button",
@@ -6058,19 +6578,19 @@ function Feature({
6058
6578
  }
6059
6579
  )
6060
6580
  ] }),
6061
- /* @__PURE__ */ jsxs32("form", { onSubmit: save, style: { marginTop: 16 }, children: [
6062
- /* @__PURE__ */ jsxs32("label", { className: "b316-checkbox", children: [
6063
- /* @__PURE__ */ jsx33("input", { type: "checkbox", name: "enabled", defaultChecked: setting?.enabled ?? false }),
6581
+ /* @__PURE__ */ jsxs34("form", { onSubmit: save, style: { marginTop: 16 }, children: [
6582
+ /* @__PURE__ */ jsxs34("label", { className: "b316-checkbox", children: [
6583
+ /* @__PURE__ */ jsx36("input", { type: "checkbox", name: "enabled", defaultChecked: setting?.enabled ?? false }),
6064
6584
  " ",
6065
6585
  "Buy credits automatically when my balance runs low"
6066
6586
  ] }),
6067
- /* @__PURE__ */ jsxs32("label", { className: "b316-field", children: [
6068
- /* @__PURE__ */ jsxs32("span", { className: "b316-label", children: [
6587
+ /* @__PURE__ */ jsxs34("label", { className: "b316-field", children: [
6588
+ /* @__PURE__ */ jsxs34("span", { className: "b316-label", children: [
6069
6589
  "When fewer than this many",
6070
6590
  unit,
6071
6591
  " are left"
6072
6592
  ] }),
6073
- /* @__PURE__ */ jsx33(
6593
+ /* @__PURE__ */ jsx36(
6074
6594
  "input",
6075
6595
  {
6076
6596
  className: "b316-input",
@@ -6081,21 +6601,21 @@ function Feature({
6081
6601
  }
6082
6602
  )
6083
6603
  ] }),
6084
- /* @__PURE__ */ jsxs32("label", { className: "b316-field", children: [
6085
- /* @__PURE__ */ jsx33("span", { className: "b316-label", children: "Buy" }),
6086
- /* @__PURE__ */ jsx33(
6604
+ /* @__PURE__ */ jsxs34("label", { className: "b316-field", children: [
6605
+ /* @__PURE__ */ jsx36("span", { className: "b316-label", children: "Buy" }),
6606
+ /* @__PURE__ */ jsx36(
6087
6607
  "select",
6088
6608
  {
6089
6609
  className: "b316-input",
6090
6610
  name: "creditPackId",
6091
6611
  defaultValue: setting?.creditPackId ?? feature.packs[0]?.id,
6092
- children: feature.packs.map((option) => /* @__PURE__ */ jsx33("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))
6093
6613
  }
6094
6614
  )
6095
6615
  ] }),
6096
- /* @__PURE__ */ jsxs32("label", { className: "b316-field", children: [
6097
- /* @__PURE__ */ jsx33("span", { className: "b316-label", children: "At most this many times a month" }),
6098
- /* @__PURE__ */ jsx33(
6616
+ /* @__PURE__ */ jsxs34("label", { className: "b316-field", children: [
6617
+ /* @__PURE__ */ jsx36("span", { className: "b316-label", children: "At most this many times a month" }),
6618
+ /* @__PURE__ */ jsx36(
6099
6619
  "input",
6100
6620
  {
6101
6621
  className: "b316-input",
@@ -6105,13 +6625,13 @@ function Feature({
6105
6625
  }
6106
6626
  )
6107
6627
  ] }),
6108
- /* @__PURE__ */ jsxs32("label", { className: "b316-field", children: [
6109
- /* @__PURE__ */ jsxs32("span", { className: "b316-label", children: [
6628
+ /* @__PURE__ */ jsxs34("label", { className: "b316-field", children: [
6629
+ /* @__PURE__ */ jsxs34("span", { className: "b316-label", children: [
6110
6630
  "Spending at most (",
6111
6631
  setting?.currency ?? feature.packs[0]?.currency ?? "USD",
6112
6632
  ") a month"
6113
6633
  ] }),
6114
- /* @__PURE__ */ jsx33(
6634
+ /* @__PURE__ */ jsx36(
6115
6635
  "input",
6116
6636
  {
6117
6637
  className: "b316-input",
@@ -6121,16 +6641,16 @@ function Feature({
6121
6641
  }
6122
6642
  )
6123
6643
  ] }),
6124
- /* @__PURE__ */ jsx33("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" })
6125
6645
  ] })
6126
6646
  ] })
6127
6647
  ] });
6128
6648
  }
6129
6649
  function CreditBalances({ onChange, className, style }) {
6130
6650
  const { client, token, loading: sessionLoading } = useBase316();
6131
- const [state, setState] = useState31({ kind: "loading" });
6132
- const [version, setVersion] = useState31(0);
6133
- useEffect23(() => {
6651
+ const [state, setState] = useState33({ kind: "loading" });
6652
+ const [version, setVersion] = useState33(0);
6653
+ useEffect26(() => {
6134
6654
  if (!token) return;
6135
6655
  let cancelled = false;
6136
6656
  client.billing.credits(token).then((credits2) => {
@@ -6143,24 +6663,24 @@ function CreditBalances({ onChange, className, style }) {
6143
6663
  cancelled = true;
6144
6664
  };
6145
6665
  }, [client, token, version]);
6146
- const wrap = (content) => /* @__PURE__ */ jsx33("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 });
6147
6667
  if (sessionLoading || !token || state.kind === "loading") return null;
6148
6668
  if (state.kind === "error") {
6149
6669
  return wrap(
6150
- /* @__PURE__ */ jsx33("div", { className: "b316-card", children: /* @__PURE__ */ jsx33("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." }) })
6151
6671
  );
6152
6672
  }
6153
6673
  const { credits } = state;
6154
6674
  if (credits.features.length === 0) return null;
6155
6675
  return wrap(
6156
- /* @__PURE__ */ jsxs32(Fragment9, { children: [
6157
- credits.managedBy ? /* @__PURE__ */ jsxs32("p", { className: "b316-muted", children: [
6676
+ /* @__PURE__ */ jsxs34(Fragment11, { children: [
6677
+ credits.managedBy ? /* @__PURE__ */ jsxs34("p", { className: "b316-muted", children: [
6158
6678
  "Credits for this account come from",
6159
6679
  " ",
6160
6680
  credits.managedBy.name ?? "the organization that manages it",
6161
6681
  ", which manages them."
6162
6682
  ] }) : null,
6163
- credits.features.map((feature) => /* @__PURE__ */ jsx33(
6683
+ credits.features.map((feature) => /* @__PURE__ */ jsx36(
6164
6684
  Feature,
6165
6685
  {
6166
6686
  feature,
@@ -6177,19 +6697,19 @@ function CreditBalances({ onChange, className, style }) {
6177
6697
  }
6178
6698
 
6179
6699
  // src/PaymentMethod.tsx
6180
- import { useEffect as useEffect24, useState as useState32 } from "react";
6181
- import { Fragment as Fragment10, jsx as jsx34, jsxs as jsxs33 } 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";
6182
6702
  function brandName(brand) {
6183
6703
  if (!brand) return "Card";
6184
6704
  return brand.charAt(0).toUpperCase() + brand.slice(1);
6185
6705
  }
6186
6706
  function PaymentMethod({ returnUrl, className, style }) {
6187
6707
  const { client, token, loading: sessionLoading } = useBase316();
6188
- const [state, setState] = useState32({ kind: "loading" });
6189
- const [busy, setBusy] = useState32(false);
6190
- const [error, setError] = useState32(null);
6191
- const [version, setVersion] = useState32(0);
6192
- useEffect24(() => {
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(() => {
6193
6713
  if (!token) return;
6194
6714
  let cancelled = false;
6195
6715
  client.billing.paymentMethods(token).then((result) => {
@@ -6205,7 +6725,7 @@ function PaymentMethod({ returnUrl, className, style }) {
6205
6725
  cancelled = true;
6206
6726
  };
6207
6727
  }, [client, token, version]);
6208
- const wrap = (content) => /* @__PURE__ */ jsx34("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 });
6209
6729
  if (sessionLoading) return wrap("Loading\u2026");
6210
6730
  if (!token) return wrap("Sign in to manage your payment method.");
6211
6731
  switch (state.kind) {
@@ -6213,11 +6733,11 @@ function PaymentMethod({ returnUrl, className, style }) {
6213
6733
  return wrap("Loading\u2026");
6214
6734
  case "error":
6215
6735
  return wrap(
6216
- /* @__PURE__ */ jsx34("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." })
6217
6737
  );
6218
6738
  case "managed":
6219
6739
  return wrap(
6220
- /* @__PURE__ */ jsx34("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." })
6221
6741
  );
6222
6742
  }
6223
6743
  const card = state.cards.find((saved) => saved.isDefault) ?? null;
@@ -6236,31 +6756,31 @@ function PaymentMethod({ returnUrl, className, style }) {
6236
6756
  }
6237
6757
  };
6238
6758
  return wrap(
6239
- /* @__PURE__ */ jsxs33(Fragment10, { children: [
6240
- /* @__PURE__ */ jsx34("div", { className: "b316-label", children: "Payment method" }),
6241
- card ? /* @__PURE__ */ jsxs33("div", { children: [
6242
- /* @__PURE__ */ jsxs33("div", { children: [
6759
+ /* @__PURE__ */ jsxs35(Fragment12, { children: [
6760
+ /* @__PURE__ */ jsx37("div", { className: "b316-label", children: "Payment method" }),
6761
+ card ? /* @__PURE__ */ jsxs35("div", { children: [
6762
+ /* @__PURE__ */ jsxs35("div", { children: [
6243
6763
  brandName(card.brand),
6244
6764
  " ending ",
6245
6765
  card.last4 ?? "????"
6246
6766
  ] }),
6247
- card.expMonth && card.expYear ? /* @__PURE__ */ jsxs33("div", { className: "b316-muted", children: [
6767
+ card.expMonth && card.expYear ? /* @__PURE__ */ jsxs35("div", { className: "b316-muted", children: [
6248
6768
  "Expires ",
6249
6769
  String(card.expMonth).padStart(2, "0"),
6250
6770
  "/",
6251
6771
  card.expYear
6252
6772
  ] }) : null
6253
- ] }) : /* @__PURE__ */ jsx34("p", { className: "b316-muted", children: "No card on file." }),
6254
- others.length > 0 ? /* @__PURE__ */ jsxs33("div", { style: { marginTop: 12 }, children: [
6255
- /* @__PURE__ */ jsx34("div", { className: "b316-label", children: "Other saved cards" }),
6256
- others.map((saved) => /* @__PURE__ */ jsxs33("div", { className: "b316-row", style: { marginTop: 6 }, children: [
6257
- /* @__PURE__ */ jsxs33("span", { children: [
6773
+ ] }) : /* @__PURE__ */ jsx37("p", { className: "b316-muted", children: "No card on file." }),
6774
+ others.length > 0 ? /* @__PURE__ */ jsxs35("div", { style: { marginTop: 12 }, children: [
6775
+ /* @__PURE__ */ jsx37("div", { className: "b316-label", children: "Other saved cards" }),
6776
+ others.map((saved) => /* @__PURE__ */ jsxs35("div", { className: "b316-row", style: { marginTop: 6 }, children: [
6777
+ /* @__PURE__ */ jsxs35("span", { children: [
6258
6778
  brandName(saved.brand),
6259
6779
  " ending ",
6260
6780
  saved.last4 ?? "????"
6261
6781
  ] }),
6262
- /* @__PURE__ */ jsxs33("span", { children: [
6263
- /* @__PURE__ */ jsx34(
6782
+ /* @__PURE__ */ jsxs35("span", { children: [
6783
+ /* @__PURE__ */ jsx37(
6264
6784
  "button",
6265
6785
  {
6266
6786
  type: "button",
@@ -6274,7 +6794,7 @@ function PaymentMethod({ returnUrl, className, style }) {
6274
6794
  }
6275
6795
  ),
6276
6796
  " ",
6277
- /* @__PURE__ */ jsx34(
6797
+ /* @__PURE__ */ jsx37(
6278
6798
  "button",
6279
6799
  {
6280
6800
  type: "button",
@@ -6290,8 +6810,8 @@ function PaymentMethod({ returnUrl, className, style }) {
6290
6810
  ] })
6291
6811
  ] }, saved.id))
6292
6812
  ] }) : null,
6293
- error ? /* @__PURE__ */ jsx34("div", { className: "b316-error", role: "alert", children: error }) : null,
6294
- /* @__PURE__ */ jsx34(
6813
+ error ? /* @__PURE__ */ jsx37("div", { className: "b316-error", role: "alert", children: error }) : null,
6814
+ /* @__PURE__ */ jsx37(
6295
6815
  "button",
6296
6816
  {
6297
6817
  type: "button",
@@ -6320,8 +6840,8 @@ function PaymentMethod({ returnUrl, className, style }) {
6320
6840
  }
6321
6841
 
6322
6842
  // src/PlanChangeReview.tsx
6323
- import { useCallback as useCallback11, useEffect as useEffect25, useState as useState33 } from "react";
6324
- import { Fragment as Fragment11, jsx as jsx35, jsxs as jsxs34 } 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";
6325
6845
  function money5(amount, currency) {
6326
6846
  if (amount === null) return "\u2014";
6327
6847
  const value = Number(amount);
@@ -6354,12 +6874,12 @@ function PlanChangeReview({
6354
6874
  style
6355
6875
  }) {
6356
6876
  const { client, token } = useBase316();
6357
- const [timing, setTiming] = useState33(void 0);
6358
- const [preview, setPreview] = useState33(null);
6359
- const [error, setError] = useState33(null);
6360
- const [needsCard, setNeedsCard] = useState33(false);
6361
- const [busy, setBusy] = useState33(false);
6362
- useEffect25(() => {
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(() => {
6363
6883
  if (!token) return;
6364
6884
  let cancelled = false;
6365
6885
  client.billing.previewPlanChange(token, planVersionId, timing).then((result) => {
@@ -6376,7 +6896,7 @@ function PlanChangeReview({
6376
6896
  cancelled = true;
6377
6897
  };
6378
6898
  }, [client, token, planVersionId, timing]);
6379
- const confirm = useCallback11(async () => {
6899
+ const confirm = useCallback12(async () => {
6380
6900
  if (!token || !preview) return;
6381
6901
  setBusy(true);
6382
6902
  setError(null);
@@ -6397,7 +6917,7 @@ function PlanChangeReview({
6397
6917
  setBusy(false);
6398
6918
  }
6399
6919
  }, [client, token, preview, planVersionId, onDone]);
6400
- const addCard = useCallback11(async () => {
6920
+ const addCard = useCallback12(async () => {
6401
6921
  if (onNeedsCard) {
6402
6922
  onNeedsCard();
6403
6923
  return;
@@ -6411,12 +6931,12 @@ function PlanChangeReview({
6411
6931
  setError("Cards cannot be added here right now.");
6412
6932
  }
6413
6933
  }, [client, token, onNeedsCard]);
6414
- const card = (content) => /* @__PURE__ */ jsx35("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 });
6415
6935
  if (error && !preview) {
6416
6936
  return card(
6417
- /* @__PURE__ */ jsxs34(Fragment11, { children: [
6418
- /* @__PURE__ */ jsx35("div", { className: "b316-error", role: "alert", children: error }),
6419
- onCancel ? /* @__PURE__ */ jsx35("button", { type: "button", className: "b316-button b316-button-secondary", onClick: onCancel, children: "Back" }) : null
6937
+ /* @__PURE__ */ jsxs36(Fragment13, { children: [
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
6420
6940
  ] })
6421
6941
  );
6422
6942
  }
@@ -6429,26 +6949,26 @@ function PlanChangeReview({
6429
6949
  const otherReason = preview.timings[other]?.reason ?? null;
6430
6950
  const changes = preview.entitlements.filter((change) => change.change !== "UNCHANGED");
6431
6951
  return card(
6432
- /* @__PURE__ */ jsxs34(Fragment11, { children: [
6433
- /* @__PURE__ */ jsxs34("div", { className: "b316-plan-name", children: [
6952
+ /* @__PURE__ */ jsxs36(Fragment13, { children: [
6953
+ /* @__PURE__ */ jsxs36("div", { className: "b316-plan-name", children: [
6434
6954
  "Change to ",
6435
6955
  to.planName
6436
6956
  ] }),
6437
- /* @__PURE__ */ jsxs34("div", { className: "b316-muted", children: [
6957
+ /* @__PURE__ */ jsxs36("div", { className: "b316-muted", children: [
6438
6958
  "From ",
6439
6959
  from.planName
6440
6960
  ] }),
6441
- error ? /* @__PURE__ */ jsx35("div", { className: "b316-error", role: "alert", children: error }) : null,
6442
- changes.length === 0 ? /* @__PURE__ */ jsx35("p", { className: "b316-muted", children: "Every feature stays the same." }) : /* @__PURE__ */ jsxs34("table", { className: "b316-review-table", children: [
6443
- /* @__PURE__ */ jsx35("thead", { children: /* @__PURE__ */ jsxs34("tr", { children: [
6444
- /* @__PURE__ */ jsx35("th", { children: "Feature" }),
6445
- /* @__PURE__ */ jsx35("th", { children: from.planName }),
6446
- /* @__PURE__ */ jsx35("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 })
6447
6967
  ] }) }),
6448
- /* @__PURE__ */ jsx35("tbody", { children: changes.map((change) => /* @__PURE__ */ jsxs34("tr", { children: [
6449
- /* @__PURE__ */ jsx35("td", { children: change.featureName }),
6450
- /* @__PURE__ */ jsx35("td", { children: limitText(change.before, change.type) }),
6451
- /* @__PURE__ */ jsx35(
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(
6452
6972
  "td",
6453
6973
  {
6454
6974
  className: change.change === "GAINED" || change.change === "INCREASED" ? "b316-review-gain" : "b316-review-loss",
@@ -6457,40 +6977,40 @@ function PlanChangeReview({
6457
6977
  )
6458
6978
  ] }, change.featureId)) })
6459
6979
  ] }),
6460
- preview.timing === "NOW" ? now.trialing ? /* @__PURE__ */ jsxs34("p", { children: [
6980
+ preview.timing === "NOW" ? now.trialing ? /* @__PURE__ */ jsxs36("p", { children: [
6461
6981
  "The change happens now. Your trial carries on until ",
6462
6982
  day4(now.trialEndsAt),
6463
6983
  ", and nothing is charged before then."
6464
- ] }) : /* @__PURE__ */ jsxs34("div", { children: [
6465
- Number(now.credit) > 0 ? /* @__PURE__ */ jsxs34("div", { className: "b316-row", children: [
6466
- /* @__PURE__ */ jsxs34("span", { className: "b316-muted", children: [
6984
+ ] }) : /* @__PURE__ */ jsxs36("div", { children: [
6985
+ Number(now.credit) > 0 ? /* @__PURE__ */ jsxs36("div", { className: "b316-row", children: [
6986
+ /* @__PURE__ */ jsxs36("span", { className: "b316-muted", children: [
6467
6987
  "Credit for the unused part of ",
6468
6988
  from.planName
6469
6989
  ] }),
6470
- /* @__PURE__ */ jsxs34("span", { className: "b316-num", children: [
6990
+ /* @__PURE__ */ jsxs36("span", { className: "b316-num", children: [
6471
6991
  "\u2212",
6472
6992
  money5(now.credit, from.currency)
6473
6993
  ] })
6474
6994
  ] }) : null,
6475
- Number(now.closingUsage) > 0 ? /* @__PURE__ */ jsxs34("div", { className: "b316-row", children: [
6476
- /* @__PURE__ */ jsx35("span", { className: "b316-muted", children: "Usage so far this period" }),
6477
- /* @__PURE__ */ jsx35("span", { className: "b316-num", children: money5(now.closingUsage, from.currency) })
6995
+ Number(now.closingUsage) > 0 ? /* @__PURE__ */ jsxs36("div", { className: "b316-row", children: [
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) })
6478
6998
  ] }) : null,
6479
- /* @__PURE__ */ jsxs34("div", { className: "b316-row", children: [
6480
- /* @__PURE__ */ jsxs34("span", { className: "b316-muted", children: [
6999
+ /* @__PURE__ */ jsxs36("div", { className: "b316-row", children: [
7000
+ /* @__PURE__ */ jsxs36("span", { className: "b316-muted", children: [
6481
7001
  to.planName,
6482
7002
  ", ",
6483
7003
  day4(now.newPeriod.start),
6484
7004
  " \u2013 ",
6485
7005
  day4(now.newPeriod.end)
6486
7006
  ] }),
6487
- /* @__PURE__ */ jsx35("span", { className: "b316-num", children: money5(now.newPeriodCharge, to.currency) })
7007
+ /* @__PURE__ */ jsx38("span", { className: "b316-num", children: money5(now.newPeriodCharge, to.currency) })
6488
7008
  ] }),
6489
- now.net !== null ? /* @__PURE__ */ jsxs34("div", { className: "b316-row b316-invoice-total", children: [
6490
- /* @__PURE__ */ jsx35("span", { children: "Due now" }),
6491
- /* @__PURE__ */ jsx35("span", { className: "b316-num", children: money5(now.net, to.currency) })
7009
+ now.net !== null ? /* @__PURE__ */ jsxs36("div", { className: "b316-row b316-invoice-total", children: [
7010
+ /* @__PURE__ */ jsx38("span", { children: "Due now" }),
7011
+ /* @__PURE__ */ jsx38("span", { className: "b316-num", children: money5(now.net, to.currency) })
6492
7012
  ] }) : null
6493
- ] }) : /* @__PURE__ */ jsxs34("p", { children: [
7013
+ ] }) : /* @__PURE__ */ jsxs36("p", { children: [
6494
7014
  "You keep ",
6495
7015
  from.planName,
6496
7016
  " until ",
@@ -6503,7 +7023,7 @@ function PlanChangeReview({
6503
7023
  preview.atPeriodEnd.nextInvoice.currency
6504
7024
  )}.` : ""
6505
7025
  ] }),
6506
- otherOpen ? /* @__PURE__ */ jsx35(
7026
+ otherOpen ? /* @__PURE__ */ jsx38(
6507
7027
  "button",
6508
7028
  {
6509
7029
  type: "button",
@@ -6514,12 +7034,12 @@ function PlanChangeReview({
6514
7034
  },
6515
7035
  children: other === "NOW" ? "Change now instead" : "Wait until the end of the period instead"
6516
7036
  }
6517
- ) : otherReason && TIMING_CLOSED[otherReason] ? /* @__PURE__ */ jsx35("p", { className: "b316-muted", children: TIMING_CLOSED[otherReason] }) : null,
6518
- needsCard ? /* @__PURE__ */ jsxs34("div", { className: "b316-notice", role: "status", children: [
7037
+ ) : otherReason && TIMING_CLOSED[otherReason] ? /* @__PURE__ */ jsx38("p", { className: "b316-muted", children: TIMING_CLOSED[otherReason] }) : null,
7038
+ needsCard ? /* @__PURE__ */ jsxs36("div", { className: "b316-notice", role: "status", children: [
6519
7039
  "A card is needed for a change that is charged now.",
6520
- /* @__PURE__ */ jsx35("div", { className: "b316-review-actions", children: /* @__PURE__ */ jsx35("button", { type: "button", className: "b316-button", onClick: () => void addCard(), children: "Add a card" }) })
6521
- ] }) : /* @__PURE__ */ jsxs34("div", { className: "b316-review-actions", children: [
6522
- /* @__PURE__ */ jsx35(
7040
+ /* @__PURE__ */ jsx38("div", { className: "b316-review-actions", children: /* @__PURE__ */ jsx38("button", { type: "button", className: "b316-button", onClick: () => void addCard(), children: "Add a card" }) })
7041
+ ] }) : /* @__PURE__ */ jsxs36("div", { className: "b316-review-actions", children: [
7042
+ /* @__PURE__ */ jsx38(
6523
7043
  "button",
6524
7044
  {
6525
7045
  type: "button",
@@ -6529,7 +7049,7 @@ function PlanChangeReview({
6529
7049
  children: busy ? "Working\u2026" : preview.timing === "NOW" ? `Change to ${to.planName} now` : `Schedule ${to.planName}`
6530
7050
  }
6531
7051
  ),
6532
- onCancel ? /* @__PURE__ */ jsxs34("button", { type: "button", className: "b316-button b316-button-secondary", onClick: onCancel, children: [
7052
+ onCancel ? /* @__PURE__ */ jsxs36("button", { type: "button", className: "b316-button b316-button-secondary", onClick: onCancel, children: [
6533
7053
  "Keep ",
6534
7054
  from.planName
6535
7055
  ] }) : null
@@ -6539,7 +7059,7 @@ function PlanChangeReview({
6539
7059
  }
6540
7060
 
6541
7061
  // src/BillingPortal.tsx
6542
- import { Fragment as Fragment12, jsx as jsx36, jsxs as jsxs35 } from "react/jsx-runtime";
7062
+ import { Fragment as Fragment14, jsx as jsx39, jsxs as jsxs37 } from "react/jsx-runtime";
6543
7063
  function BillingPortal({
6544
7064
  returnUrl,
6545
7065
  featuredPlanKey,
@@ -6549,12 +7069,12 @@ function BillingPortal({
6549
7069
  style
6550
7070
  }) {
6551
7071
  const { client, token, loading: sessionLoading } = useBase316();
6552
- const [overview, setOverview] = useState34(null);
6553
- const [failed, setFailed] = useState34(false);
6554
- const [version, setVersion] = useState34(0);
6555
- const [reviewing, setReviewing] = useState34(null);
6556
- const [notice, setNotice] = useState34(null);
6557
- useEffect26(() => {
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(() => {
6558
7078
  if (!token) return;
6559
7079
  let cancelled = false;
6560
7080
  client.billing.subscription(token).then((result) => {
@@ -6573,28 +7093,28 @@ function BillingPortal({
6573
7093
  cancelled = true;
6574
7094
  };
6575
7095
  }, [client, token, version]);
6576
- const refresh = useCallback12(() => {
7096
+ const refresh = useCallback13(() => {
6577
7097
  setNotice(null);
6578
7098
  setVersion((value) => value + 1);
6579
7099
  }, []);
6580
- const shell = (content) => /* @__PURE__ */ jsx36("div", { className: cls("b316-billing-portal", className), style, children: content });
6581
- if (sessionLoading) return shell(/* @__PURE__ */ jsx36("div", { className: "b316-card", children: "Loading\u2026" }));
6582
- if (!token) return shell(/* @__PURE__ */ jsx36("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." }));
6583
7103
  if (failed) {
6584
7104
  return shell(
6585
- /* @__PURE__ */ jsx36("div", { className: "b316-card", children: /* @__PURE__ */ jsx36("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." }) })
6586
7106
  );
6587
7107
  }
6588
- if (!overview) return shell(/* @__PURE__ */ jsx36("div", { className: "b316-card", children: "Loading\u2026" }));
7108
+ if (!overview) return shell(/* @__PURE__ */ jsx39("div", { className: "b316-card", children: "Loading\u2026" }));
6589
7109
  const { subscription, managedBy, quantityPriced } = overview;
6590
7110
  const canChange = Boolean(subscription) && !managedBy;
6591
7111
  return shell(
6592
- /* @__PURE__ */ jsxs35(Fragment12, { children: [
6593
- notice ? /* @__PURE__ */ jsx36("div", { className: "b316-card b316-notice", role: "status", children: notice }) : null,
6594
- /* @__PURE__ */ jsx36(SubscriptionManager, { onChange: refresh }, `plan-${version}`),
6595
- canChange ? /* @__PURE__ */ jsx36(UpcomingInvoice, {}, `next-${version}`) : null,
6596
- canChange && quantityPriced ? /* @__PURE__ */ jsx36(SeatManager, { unitLabel, onChange: refresh }, `seats-${version}`) : null,
6597
- reviewing ? /* @__PURE__ */ jsx36(
7112
+ /* @__PURE__ */ jsxs37(Fragment14, { children: [
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(
6598
7118
  PlanChangeReview,
6599
7119
  {
6600
7120
  planVersionId: reviewing,
@@ -6607,9 +7127,9 @@ function BillingPortal({
6607
7127
  );
6608
7128
  }
6609
7129
  }
6610
- ) : /* @__PURE__ */ jsxs35("section", { children: [
6611
- /* @__PURE__ */ jsx36("h2", { className: "b316-billing-portal-section-title", children: subscription ? "Change plan" : "Choose a plan" }),
6612
- /* @__PURE__ */ jsx36(
7130
+ ) : /* @__PURE__ */ jsxs37("section", { children: [
7131
+ /* @__PURE__ */ jsx39("h2", { className: "b316-billing-portal-section-title", children: subscription ? "Change plan" : "Choose a plan" }),
7132
+ /* @__PURE__ */ jsx39(
6613
7133
  PricingTable,
6614
7134
  {
6615
7135
  featuredPlanKey,
@@ -6621,17 +7141,17 @@ function BillingPortal({
6621
7141
  `plans-${version}`
6622
7142
  )
6623
7143
  ] }),
6624
- /* @__PURE__ */ jsx36(CreditBalances, {}, `credits-${version}`),
6625
- managedBy ? null : /* @__PURE__ */ jsx36(PaymentMethod, { returnUrl }, `card-${version}`),
6626
- /* @__PURE__ */ jsx36(Invoices, {}, `invoices-${version}`),
6627
- billingDetails === void 0 ? /* @__PURE__ */ jsx36(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
6628
7148
  ] })
6629
7149
  );
6630
7150
  }
6631
7151
 
6632
7152
  // src/ApiKeyManager.tsx
6633
- import { useCallback as useCallback13, useEffect as useEffect27, useState as useState35 } from "react";
6634
- import { jsx as jsx37, jsxs as jsxs36 } 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";
6635
7155
  function duration(seconds) {
6636
7156
  if (seconds % 3600 === 0) {
6637
7157
  return `${seconds / 3600}h`;
@@ -6648,17 +7168,17 @@ function ApiKeyManager({
6648
7168
  audience
6649
7169
  }) {
6650
7170
  const { client, token, loading: sessionLoading } = useBase316();
6651
- const [resources, setResources] = useState35([]);
6652
- const [credentials, setCredentials] = useState35([]);
6653
- const [loading, setLoading] = useState35(true);
6654
- const [busy, setBusy] = useState35(false);
6655
- const [error, setError] = useState35(null);
6656
- const [creating, setCreating] = useState35(false);
6657
- const [name, setName] = useState35("");
6658
- const [chosen, setChosen] = useState35([]);
6659
- const [resourceId, setResourceId] = useState35(null);
6660
- const [issued, setIssued] = useState35(null);
6661
- 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 () => {
6662
7182
  if (!token) {
6663
7183
  setLoading(false);
6664
7184
  return;
@@ -6679,20 +7199,20 @@ function ApiKeyManager({
6679
7199
  setLoading(false);
6680
7200
  }
6681
7201
  }, [client, token, audience]);
6682
- useEffect27(() => {
7202
+ useEffect30(() => {
6683
7203
  void load();
6684
7204
  }, [load]);
6685
- if (sessionLoading || loading) {
6686
- return /* @__PURE__ */ jsx37("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" });
6687
7207
  }
6688
7208
  if (!token) {
6689
- return /* @__PURE__ */ jsx37("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." });
6690
7210
  }
6691
7211
  if (error) {
6692
- return /* @__PURE__ */ jsx37("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx37("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 }) });
6693
7213
  }
6694
7214
  if (resources.length === 0) {
6695
- return /* @__PURE__ */ jsx37("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." });
6696
7216
  }
6697
7217
  const resource = resources.find((item) => item.id === resourceId) ?? resources[0];
6698
7218
  const reset = () => {
@@ -6701,37 +7221,37 @@ function ApiKeyManager({
6701
7221
  setChosen([]);
6702
7222
  setIssued(null);
6703
7223
  };
6704
- return /* @__PURE__ */ jsxs36("div", { className: cls("b316-card", className), style, children: [
6705
- error ? /* @__PURE__ */ jsx37("div", { className: "b316-error", role: "alert", children: error }) : null,
6706
- resources.length > 1 ? /* @__PURE__ */ jsx37(
7224
+ return /* @__PURE__ */ jsxs38("div", { className: cls("b316-card", className), style, children: [
7225
+ error ? /* @__PURE__ */ jsx40("div", { className: "b316-error", role: "alert", children: error }) : null,
7226
+ resources.length > 1 ? /* @__PURE__ */ jsx40(
6707
7227
  "select",
6708
7228
  {
6709
7229
  className: "b316-input",
6710
7230
  value: resource.id,
6711
7231
  onChange: (event) => setResourceId(event.target.value),
6712
7232
  style: { marginBottom: 14 },
6713
- children: resources.map((item) => /* @__PURE__ */ jsx37("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))
6714
7234
  }
6715
- ) : /* @__PURE__ */ jsx37("div", { className: "b316-plan-name", children: resource.name }),
6716
- resource.rateLimit ? /* @__PURE__ */ jsxs36("div", { className: "b316-muted", children: [
7235
+ ) : /* @__PURE__ */ jsx40("div", { className: "b316-plan-name", children: resource.name }),
7236
+ resource.rateLimit ? /* @__PURE__ */ jsxs38("div", { className: "b316-muted", children: [
6717
7237
  resource.rateLimit.requestsPerWindow,
6718
7238
  " requests per",
6719
7239
  " ",
6720
7240
  duration(resource.rateLimit.windowSeconds),
6721
7241
  resource.rateLimit.burst > resource.rateLimit.requestsPerWindow ? `, bursting to ${resource.rateLimit.burst}` : null
6722
- ] }) : /* @__PURE__ */ jsx37("div", { className: "b316-muted", children: "No rate limit." }),
6723
- credentials.length === 0 ? /* @__PURE__ */ jsx37("p", { className: "b316-muted", style: { marginTop: 14 }, children: "You have no API keys yet." }) : /* @__PURE__ */ jsx37("ul", { className: "b316-list", style: { marginTop: 14 }, children: credentials.map((credential) => /* @__PURE__ */ jsxs36("li", { className: "b316-list-item", children: [
6724
- /* @__PURE__ */ jsxs36("div", { children: [
6725
- /* @__PURE__ */ jsx37("div", { className: "b316-plan-name", children: credential.name }),
6726
- /* @__PURE__ */ jsxs36("div", { className: "b316-muted", children: [
6727
- /* @__PURE__ */ jsx37("code", { children: credential.clientId }),
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: [
7244
+ /* @__PURE__ */ jsxs38("div", { children: [
7245
+ /* @__PURE__ */ jsx40("div", { className: "b316-plan-name", children: credential.name }),
7246
+ /* @__PURE__ */ jsxs38("div", { className: "b316-muted", children: [
7247
+ /* @__PURE__ */ jsx40("code", { children: credential.clientId }),
6728
7248
  credential.secretLastFour ? ` \xB7 \u2026${credential.secretLastFour}` : null,
6729
7249
  credential.disabled ? " \xB7 Disabled" : null
6730
7250
  ] }),
6731
- /* @__PURE__ */ jsx37("div", { className: "b316-muted", children: credential.scopes.join(", ") })
7251
+ /* @__PURE__ */ jsx40("div", { className: "b316-muted", children: credential.scopes.join(", ") })
6732
7252
  ] }),
6733
- /* @__PURE__ */ jsxs36("div", { style: { display: "flex", gap: 8 }, children: [
6734
- /* @__PURE__ */ jsx37(
7253
+ /* @__PURE__ */ jsxs38("div", { style: { display: "flex", gap: 8 }, children: [
7254
+ /* @__PURE__ */ jsx40(
6735
7255
  "button",
6736
7256
  {
6737
7257
  type: "button",
@@ -6760,7 +7280,7 @@ function ApiKeyManager({
6760
7280
  children: "Rotate"
6761
7281
  }
6762
7282
  ),
6763
- /* @__PURE__ */ jsx37(
7283
+ /* @__PURE__ */ jsx40(
6764
7284
  ConfirmButton,
6765
7285
  {
6766
7286
  className: "b316-button b316-button-secondary",
@@ -6784,11 +7304,11 @@ function ApiKeyManager({
6784
7304
  )
6785
7305
  ] })
6786
7306
  ] }, credential.clientId)) }),
6787
- issued ? /* @__PURE__ */ jsxs36("div", { className: "b316-notice", style: { marginTop: 14 }, children: [
6788
- /* @__PURE__ */ jsx37("strong", { children: "Copy this now." }),
7307
+ issued ? /* @__PURE__ */ jsxs38("div", { className: "b316-notice", style: { marginTop: 14 }, children: [
7308
+ /* @__PURE__ */ jsx40("strong", { children: "Copy this now." }),
6789
7309
  " It is shown once and cannot be retrieved again.",
6790
- /* @__PURE__ */ jsx37("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsx37("code", { style: { wordBreak: "break-all" }, children: issued.secret }) }),
6791
- /* @__PURE__ */ jsx37(
7310
+ /* @__PURE__ */ jsx40("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsx40("code", { style: { wordBreak: "break-all" }, children: issued.secret }) }),
7311
+ /* @__PURE__ */ jsx40(
6792
7312
  "button",
6793
7313
  {
6794
7314
  type: "button",
@@ -6801,7 +7321,7 @@ function ApiKeyManager({
6801
7321
  children: "Copy"
6802
7322
  }
6803
7323
  ),
6804
- /* @__PURE__ */ jsx37(
7324
+ /* @__PURE__ */ jsx40(
6805
7325
  "button",
6806
7326
  {
6807
7327
  type: "button",
@@ -6812,8 +7332,8 @@ function ApiKeyManager({
6812
7332
  }
6813
7333
  )
6814
7334
  ] }) : null,
6815
- creating && !issued ? /* @__PURE__ */ jsxs36("div", { style: { marginTop: 14 }, children: [
6816
- /* @__PURE__ */ jsx37(
7335
+ creating && !issued ? /* @__PURE__ */ jsxs38("div", { style: { marginTop: 14 }, children: [
7336
+ /* @__PURE__ */ jsx40(
6817
7337
  "input",
6818
7338
  {
6819
7339
  className: "b316-input",
@@ -6822,9 +7342,9 @@ function ApiKeyManager({
6822
7342
  onChange: (event) => setName(event.target.value)
6823
7343
  }
6824
7344
  ),
6825
- /* @__PURE__ */ jsxs36("div", { style: { marginTop: 10 }, children: [
6826
- resource.availableScopes.map((scope) => /* @__PURE__ */ jsxs36("label", { className: "b316-checkbox", children: [
6827
- /* @__PURE__ */ jsx37(
7345
+ /* @__PURE__ */ jsxs38("div", { style: { marginTop: 10 }, children: [
7346
+ resource.availableScopes.map((scope) => /* @__PURE__ */ jsxs38("label", { className: "b316-checkbox", children: [
7347
+ /* @__PURE__ */ jsx40(
6828
7348
  "input",
6829
7349
  {
6830
7350
  type: "checkbox",
@@ -6834,19 +7354,19 @@ function ApiKeyManager({
6834
7354
  )
6835
7355
  }
6836
7356
  ),
6837
- /* @__PURE__ */ jsx37("code", { children: scope.key }),
6838
- scope.description ? /* @__PURE__ */ jsxs36("span", { className: "b316-muted", children: [
7357
+ /* @__PURE__ */ jsx40("code", { children: scope.key }),
7358
+ scope.description ? /* @__PURE__ */ jsxs38("span", { className: "b316-muted", children: [
6839
7359
  " \u2014 ",
6840
7360
  scope.description
6841
7361
  ] }) : null
6842
7362
  ] }, scope.key)),
6843
- resource.lockedScopes.map((scope) => /* @__PURE__ */ jsxs36("label", { className: "b316-checkbox b316-muted", children: [
6844
- /* @__PURE__ */ jsx37("input", { type: "checkbox", disabled: true }),
6845
- /* @__PURE__ */ jsx37("code", { children: scope.key }),
6846
- /* @__PURE__ */ jsx37("span", { children: " \u2014 not included in your plan" })
7363
+ resource.lockedScopes.map((scope) => /* @__PURE__ */ jsxs38("label", { className: "b316-checkbox b316-muted", children: [
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" })
6847
7367
  ] }, scope.key))
6848
7368
  ] }),
6849
- /* @__PURE__ */ jsx37(
7369
+ /* @__PURE__ */ jsx40(
6850
7370
  "button",
6851
7371
  {
6852
7372
  type: "button",
@@ -6880,7 +7400,7 @@ function ApiKeyManager({
6880
7400
  children: "Create key"
6881
7401
  }
6882
7402
  ),
6883
- /* @__PURE__ */ jsx37(
7403
+ /* @__PURE__ */ jsx40(
6884
7404
  "button",
6885
7405
  {
6886
7406
  type: "button",
@@ -6891,7 +7411,7 @@ function ApiKeyManager({
6891
7411
  }
6892
7412
  )
6893
7413
  ] }) : null,
6894
- !creating && !issued ? /* @__PURE__ */ jsx37(
7414
+ !creating && !issued ? /* @__PURE__ */ jsx40(
6895
7415
  "button",
6896
7416
  {
6897
7417
  type: "button",
@@ -6933,12 +7453,12 @@ var MANIFEST = [
6933
7453
  },
6934
7454
  {
6935
7455
  name: "appearance",
6936
- summary: "Colours, radius and font as tokens. Restyles everything at once.",
7456
+ summary: "Colors, radius and font as tokens. Restyles everything at once.",
6937
7457
  required: false
6938
7458
  },
6939
7459
  {
6940
7460
  name: "tenant",
6941
- 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.",
6942
7462
  required: false
6943
7463
  },
6944
7464
  ...appearance
@@ -6966,35 +7486,86 @@ var MANIFEST = [
6966
7486
  {
6967
7487
  name: "SignIn",
6968
7488
  kind: "component",
6969
- summary: "Password, passkey, magic-link and text-message sign-in in one form.",
7489
+ summary: "Sign in the ways the environment offers \u2014 password, magic link, passkeys, text message, social providers and SSO, as switched on in the dashboard (`GET /v1/auth/methods`).",
6970
7490
  useWhen: "The application renders its own sign-in rather than redirecting to the hosted page.",
6971
7491
  requires: [],
6972
7492
  props: [
6973
7493
  { name: "onSignedIn", summary: "Called once a session exists.", required: false },
7494
+ {
7495
+ name: "password",
7496
+ summary: "`false` hides the password form. Every method prop can only turn a method off.",
7497
+ required: false
7498
+ },
6974
7499
  {
6975
7500
  name: "passkeys",
6976
- summary: "Offer passkeys where supported. On by default.",
7501
+ summary: "`false` hides passkeys; otherwise offered where the environment and browser allow.",
6977
7502
  required: false
6978
7503
  },
7504
+ { name: "magicLink", summary: "`false` hides the emailed sign-in link.", required: false },
6979
7505
  {
6980
7506
  name: "magicLinkRedirectUrl",
6981
- summary: "Where an emailed link lands, which must be registered on the environment. Without it, magic link is not offered at all.",
7507
+ summary: "Where an emailed link lands; defaults to the page rendering the form, which redeems `?token=`. Must be on the environment's redirect allow-list.",
6982
7508
  required: false
6983
7509
  },
7510
+ { name: "phone", summary: "`false` hides text-message codes.", required: false },
6984
7511
  {
6985
- name: "phone",
6986
- summary: "Offer signing in with a code sent by text message. Needs text messages switched on for the environment, and its own Twilio account in production.",
7512
+ name: "social",
7513
+ summary: "`false` hides the social buttons; a list of slugs keeps only those providers.",
6987
7514
  required: false
6988
7515
  },
7516
+ { name: "sso", summary: '`false` hides "Sign in with SSO".', required: false },
7517
+ {
7518
+ name: "socialRedirectUrl",
7519
+ summary: "Your server route a social or SSO sign-in returns to with `?code=&state=`: check `state` against the `b316_oauth_state` cookie (`readOAuthState`), then `base316.auth.exchangeCode` with the secret key. On the redirect allow-list. Without it no social or SSO button is shown.",
7520
+ required: false
7521
+ },
7522
+ {
7523
+ name: "socialState",
7524
+ summary: "A short value carried through a social or SSO sign-in, returned by `readOAuthState`.",
7525
+ required: false
7526
+ },
7527
+ { name: "labels", summary: "Wording for the form, for translation.", required: false },
6989
7528
  {
6990
7529
  name: "secondFactorLabels",
6991
- 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.",
6992
7531
  required: false
6993
7532
  },
6994
7533
  ...appearance
6995
7534
  ],
6996
7535
  seeAlso: ["SignUp", "ForgotPassword", "SecondFactorStep"]
6997
7536
  },
7537
+ {
7538
+ name: "SocialSignIn",
7539
+ kind: "component",
7540
+ summary: `The environment's social sign-in buttons alone ("Continue with Google"), for a sign-in or sign-up form you draw yourself.`,
7541
+ useWhen: "Your own form needs the social providers switched on in the dashboard. SignIn and SignUp already include them.",
7542
+ requires: [],
7543
+ props: [
7544
+ {
7545
+ name: "socialRedirectUrl",
7546
+ summary: "Your server route the code lands on with `?code=&state=`; check with `readOAuthState`, redeem with `exchangeCode`. On the redirect allow-list. Without it nothing is drawn.",
7547
+ required: false
7548
+ },
7549
+ {
7550
+ name: "socialState",
7551
+ summary: "A short value carried through, returned by `readOAuthState`.",
7552
+ required: false
7553
+ },
7554
+ {
7555
+ name: "social",
7556
+ summary: "`false` hides every button; a list of slugs keeps only those providers.",
7557
+ required: false
7558
+ },
7559
+ {
7560
+ name: "intent",
7561
+ summary: "`sign-up` hides the buttons when the environment is closed to new accounts.",
7562
+ required: false
7563
+ },
7564
+ { name: "divider", summary: 'Draw an "or" rule under the buttons.', required: false },
7565
+ { name: "labels", summary: "`continueWith` and `or`, for translation.", required: false }
7566
+ ],
7567
+ seeAlso: ["SignIn", "SignUp"]
7568
+ },
6998
7569
  {
6999
7570
  name: "SignUp",
7000
7571
  kind: "component",
@@ -7023,6 +7594,21 @@ var MANIFEST = [
7023
7594
  summary: "Wording for the second-factor step, for translation.",
7024
7595
  required: false
7025
7596
  },
7597
+ {
7598
+ name: "social",
7599
+ summary: "`false` hides the social buttons; a list of slugs keeps only those providers.",
7600
+ required: false
7601
+ },
7602
+ {
7603
+ name: "socialRedirectUrl",
7604
+ summary: "Where a social sign-up returns with `?code=&state=`, as on SignIn. Without it no social button is shown.",
7605
+ required: false
7606
+ },
7607
+ {
7608
+ name: "socialState",
7609
+ summary: "A short value carried through a social sign-up, returned by `readOAuthState`.",
7610
+ required: false
7611
+ },
7026
7612
  ...appearance
7027
7613
  ],
7028
7614
  seeAlso: ["SignIn", "VerifyEmail", "SecondFactorStep"]
@@ -7316,10 +7902,20 @@ var MANIFEST = [
7316
7902
  props: [],
7317
7903
  seeAlso: ["PricingTable"]
7318
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
+ },
7319
7915
  {
7320
7916
  name: "SubscriptionManager",
7321
7917
  kind: "component",
7322
- 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.",
7323
7919
  useWhen: "A billing settings page.",
7324
7920
  requires: ["session"],
7325
7921
  props: [
@@ -7600,7 +8196,7 @@ var MANIFEST = [
7600
8196
  {
7601
8197
  name: "Chart",
7602
8198
  kind: "component",
7603
- summary: "Records over time, counted or totalled.",
8199
+ summary: "Records over time, counted or totaled.",
7604
8200
  useWhen: "The question is how many or how much, by day, week or month.",
7605
8201
  requires: ["session", "collection"],
7606
8202
  bindsToCollection: true,
@@ -7794,6 +8390,7 @@ export {
7794
8390
  SecondFactorStep,
7795
8391
  SignIn,
7796
8392
  SignUp,
8393
+ SocialSignIn,
7797
8394
  SubscriptionManager,
7798
8395
  TeamMembers,
7799
8396
  TwoFactorManager,
@@ -7802,6 +8399,7 @@ export {
7802
8399
  VerifyEmail,
7803
8400
  componentsRequiring,
7804
8401
  describeComponent,
8402
+ useAddons,
7805
8403
  useBase316,
7806
8404
  useCollection,
7807
8405
  usePaymentLink,