@base316/react 0.5.1 → 0.5.2

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
@@ -2037,7 +2037,9 @@ function SignIn({
2037
2037
  if (cause instanceof DOMException && (cause.name === "NotAllowedError" || cause.name === "AbortError")) {
2038
2038
  return;
2039
2039
  }
2040
- if (!conditional) {
2040
+ if (cause instanceof Base316Error2 && cause.reason === "EMAIL_NOT_VERIFIED") {
2041
+ setError(cause.message);
2042
+ } else if (!conditional) {
2041
2043
  console.error("[base316] passkey sign-in failed", cause);
2042
2044
  setError("That passkey did not work.");
2043
2045
  }
@@ -3041,7 +3043,61 @@ function PrivacyControls({
3041
3043
 
3042
3044
  // src/TwoFactorManager.tsx
3043
3045
  import { useState as useState14 } from "react";
3046
+
3047
+ // src/QrCode.tsx
3048
+ import qrcode from "qrcode-generator";
3049
+ import { useMemo as useMemo2 } from "react";
3044
3050
  import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
3051
+ var QUIET_ZONE = 4;
3052
+ function utf8Binary(value) {
3053
+ let binary = "";
3054
+ for (const byte of new TextEncoder().encode(value)) {
3055
+ binary += String.fromCharCode(byte);
3056
+ }
3057
+ return binary;
3058
+ }
3059
+ function qrPath(value) {
3060
+ const code = qrcode(0, "M");
3061
+ code.addData(utf8Binary(value), "Byte");
3062
+ code.make();
3063
+ const modules = code.getModuleCount();
3064
+ let path = "";
3065
+ for (let row = 0; row < modules; row += 1) {
3066
+ for (let col = 0; col < modules; col += 1) {
3067
+ if (code.isDark(row, col)) {
3068
+ path += `M${col + QUIET_ZONE} ${row + QUIET_ZONE}h1v1h-1z`;
3069
+ }
3070
+ }
3071
+ }
3072
+ return { path, modules };
3073
+ }
3074
+ function QrCode({ value, label, size = 180, className }) {
3075
+ const { path, modules } = useMemo2(() => qrPath(value), [value]);
3076
+ const extent = modules + QUIET_ZONE * 2;
3077
+ return /* @__PURE__ */ jsxs15(
3078
+ "svg",
3079
+ {
3080
+ className,
3081
+ role: "img",
3082
+ "aria-label": label,
3083
+ width: size,
3084
+ height: size,
3085
+ viewBox: `0 0 ${extent} ${extent}`,
3086
+ shapeRendering: "crispEdges",
3087
+ xmlns: "http://www.w3.org/2000/svg",
3088
+ children: [
3089
+ /* @__PURE__ */ jsx16("rect", { width: extent, height: extent, fill: "#ffffff" }),
3090
+ /* @__PURE__ */ jsx16("path", { d: path, fill: "#000000" })
3091
+ ]
3092
+ }
3093
+ );
3094
+ }
3095
+
3096
+ // src/TwoFactorManager.tsx
3097
+ import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
3098
+ function groupKey(secret) {
3099
+ return secret.replace(/\s+/g, "").replace(/(.{4})(?=.)/g, "$1 ");
3100
+ }
3045
3101
  function TwoFactorManager({
3046
3102
  enabled = false,
3047
3103
  allowSms = false,
@@ -3134,17 +3190,17 @@ function TwoFactorManager({
3134
3190
  setBusy(false);
3135
3191
  }
3136
3192
  }
3137
- return /* @__PURE__ */ jsxs15("div", { className: cls("b316-card b316-mfa", className), style, children: [
3138
- /* @__PURE__ */ jsx16("h3", { className: "b316-mfa-title", children: "Two-factor authentication" }),
3139
- error ? /* @__PURE__ */ jsx16("div", { className: "b316-error", role: "alert", children: error }) : null,
3140
- stage.name === "saved" ? /* @__PURE__ */ jsxs15("div", { className: "b316-mfa-codes", children: [
3141
- /* @__PURE__ */ jsx16("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." }),
3142
- /* @__PURE__ */ jsx16("ul", { className: "b316-mfa-code-list", children: stage.recoveryCodes.map((recovery) => /* @__PURE__ */ jsx16("li", { children: /* @__PURE__ */ jsx16("code", { children: recovery }) }, recovery)) }),
3143
- /* @__PURE__ */ jsx16("button", { type: "button", className: "b316-button", onClick: () => setStage({ name: "idle" }), children: "I have saved them" })
3144
- ] }) : stage.name === "smsNumber" ? /* @__PURE__ */ jsxs15("div", { className: "b316-mfa-enrol", children: [
3145
- /* @__PURE__ */ jsx16("p", { children: "We will text a code to this number now, and each time you sign in." }),
3146
- /* @__PURE__ */ jsx16("label", { className: "b316-label", htmlFor: "b316-mfa-phone", children: "Mobile number" }),
3147
- /* @__PURE__ */ jsx16(
3193
+ return /* @__PURE__ */ jsxs16("div", { className: cls("b316-card b316-mfa", className), style, children: [
3194
+ /* @__PURE__ */ jsx17("h3", { className: "b316-mfa-title", children: "Two-factor authentication" }),
3195
+ error ? /* @__PURE__ */ jsx17("div", { className: "b316-error", role: "alert", children: error }) : null,
3196
+ stage.name === "saved" ? /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-codes", children: [
3197
+ /* @__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." }),
3198
+ /* @__PURE__ */ jsx17("ul", { className: "b316-mfa-code-list", children: stage.recoveryCodes.map((recovery) => /* @__PURE__ */ jsx17("li", { children: /* @__PURE__ */ jsx17("code", { children: recovery }) }, recovery)) }),
3199
+ /* @__PURE__ */ jsx17("button", { type: "button", className: "b316-button", onClick: () => setStage({ name: "idle" }), children: "I have saved them" })
3200
+ ] }) : stage.name === "smsNumber" ? /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-enrol", children: [
3201
+ /* @__PURE__ */ jsx17("p", { children: "We will text a code to this number now, and each time you sign in." }),
3202
+ /* @__PURE__ */ jsx17("label", { className: "b316-label", htmlFor: "b316-mfa-phone", children: "Mobile number" }),
3203
+ /* @__PURE__ */ jsx17(
3148
3204
  "input",
3149
3205
  {
3150
3206
  id: "b316-mfa-phone",
@@ -3156,8 +3212,8 @@ function TwoFactorManager({
3156
3212
  onChange: (event) => setPhone(event.target.value)
3157
3213
  }
3158
3214
  ),
3159
- /* @__PURE__ */ jsxs15("div", { className: "b316-mfa-actions", children: [
3160
- /* @__PURE__ */ jsx16(
3215
+ /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-actions", children: [
3216
+ /* @__PURE__ */ jsx17(
3161
3217
  "button",
3162
3218
  {
3163
3219
  type: "button",
@@ -3166,16 +3222,16 @@ function TwoFactorManager({
3166
3222
  children: "Cancel"
3167
3223
  }
3168
3224
  ),
3169
- /* @__PURE__ */ jsx16("button", { type: "button", className: "b316-button", disabled: busy, onClick: beginSms, children: busy ? "Sending\u2026" : "Send code" })
3225
+ /* @__PURE__ */ jsx17("button", { type: "button", className: "b316-button", disabled: busy, onClick: beginSms, children: busy ? "Sending\u2026" : "Send code" })
3170
3226
  ] })
3171
- ] }) : stage.name === "enrollingEmail" ? /* @__PURE__ */ jsxs15("div", { className: "b316-mfa-enrol", children: [
3172
- /* @__PURE__ */ jsxs15("p", { children: [
3227
+ ] }) : stage.name === "enrollingEmail" ? /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-enrol", children: [
3228
+ /* @__PURE__ */ jsxs16("p", { children: [
3173
3229
  "We sent a code to ",
3174
3230
  stage.destinationHint,
3175
3231
  ". Enter it below to turn this on."
3176
3232
  ] }),
3177
- /* @__PURE__ */ jsx16("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3178
- /* @__PURE__ */ jsx16(
3233
+ /* @__PURE__ */ jsx17("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3234
+ /* @__PURE__ */ jsx17(
3179
3235
  "input",
3180
3236
  {
3181
3237
  id: "b316-mfa-code",
@@ -3186,8 +3242,8 @@ function TwoFactorManager({
3186
3242
  onChange: (event) => setCode(event.target.value)
3187
3243
  }
3188
3244
  ),
3189
- /* @__PURE__ */ jsxs15("div", { className: "b316-mfa-actions", children: [
3190
- /* @__PURE__ */ jsx16(
3245
+ /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-actions", children: [
3246
+ /* @__PURE__ */ jsx17(
3191
3247
  "button",
3192
3248
  {
3193
3249
  type: "button",
@@ -3196,7 +3252,7 @@ function TwoFactorManager({
3196
3252
  children: "Cancel"
3197
3253
  }
3198
3254
  ),
3199
- /* @__PURE__ */ jsx16(
3255
+ /* @__PURE__ */ jsx17(
3200
3256
  "button",
3201
3257
  {
3202
3258
  type: "button",
@@ -3207,12 +3263,23 @@ function TwoFactorManager({
3207
3263
  }
3208
3264
  )
3209
3265
  ] })
3210
- ] }) : stage.name === "enrolling" ? /* @__PURE__ */ jsxs15("div", { className: "b316-mfa-enrol", children: [
3211
- /* @__PURE__ */ jsx16("p", { children: "Add this to your authenticator app, then enter the six-digit code it shows." }),
3212
- /* @__PURE__ */ jsx16("div", { className: "b316-mfa-secret", children: /* @__PURE__ */ jsx16("code", { children: stage.secret }) }),
3213
- /* @__PURE__ */ jsx16("a", { className: "b316-mfa-uri", href: stage.uri, children: "Open in an authenticator app" }),
3214
- /* @__PURE__ */ jsx16("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3215
- /* @__PURE__ */ jsx16(
3266
+ ] }) : stage.name === "enrolling" ? /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-enrol", children: [
3267
+ /* @__PURE__ */ jsx17("p", { children: "Scan this with your authenticator app (Google Authenticator, 1Password, Authy\u2026), then enter the six-digit code it shows." }),
3268
+ /* @__PURE__ */ jsx17(
3269
+ QrCode,
3270
+ {
3271
+ className: "b316-mfa-qr",
3272
+ value: stage.uri,
3273
+ label: "QR code for your authenticator app"
3274
+ }
3275
+ ),
3276
+ /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-secret", children: [
3277
+ /* @__PURE__ */ jsx17("span", { className: "b316-label", id: "b316-mfa-manual-key", children: "Can't scan? Enter this key" }),
3278
+ /* @__PURE__ */ jsx17("code", { "aria-labelledby": "b316-mfa-manual-key", children: groupKey(stage.secret) })
3279
+ ] }),
3280
+ /* @__PURE__ */ jsx17("a", { className: "b316-mfa-uri", href: stage.uri, children: "Open in an authenticator app" }),
3281
+ /* @__PURE__ */ jsx17("label", { className: "b316-label", htmlFor: "b316-mfa-code", children: "Code" }),
3282
+ /* @__PURE__ */ jsx17(
3216
3283
  "input",
3217
3284
  {
3218
3285
  id: "b316-mfa-code",
@@ -3223,8 +3290,8 @@ function TwoFactorManager({
3223
3290
  onChange: (event) => setCode(event.target.value)
3224
3291
  }
3225
3292
  ),
3226
- /* @__PURE__ */ jsxs15("div", { className: "b316-mfa-actions", children: [
3227
- /* @__PURE__ */ jsx16(
3293
+ /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-actions", children: [
3294
+ /* @__PURE__ */ jsx17(
3228
3295
  "button",
3229
3296
  {
3230
3297
  type: "button",
@@ -3233,7 +3300,7 @@ function TwoFactorManager({
3233
3300
  children: "Cancel"
3234
3301
  }
3235
3302
  ),
3236
- /* @__PURE__ */ jsx16(
3303
+ /* @__PURE__ */ jsx17(
3237
3304
  "button",
3238
3305
  {
3239
3306
  type: "button",
@@ -3244,9 +3311,9 @@ function TwoFactorManager({
3244
3311
  }
3245
3312
  )
3246
3313
  ] })
3247
- ] }) : on ? /* @__PURE__ */ jsxs15("div", { className: "b316-mfa-on", children: [
3248
- /* @__PURE__ */ jsx16("p", { className: "b316-muted", children: "On. You will be asked for a code when you sign in." }),
3249
- /* @__PURE__ */ jsx16(
3314
+ ] }) : on ? /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-on", children: [
3315
+ /* @__PURE__ */ jsx17("p", { className: "b316-muted", children: "On. You will be asked for a code when you sign in." }),
3316
+ /* @__PURE__ */ jsx17(
3250
3317
  ConfirmButton,
3251
3318
  {
3252
3319
  className: "b316-button-quiet b316-danger",
@@ -3256,11 +3323,11 @@ function TwoFactorManager({
3256
3323
  children: "Turn off"
3257
3324
  }
3258
3325
  )
3259
- ] }) : /* @__PURE__ */ jsxs15("div", { className: "b316-mfa-off", children: [
3260
- /* @__PURE__ */ jsx16("p", { className: "b316-muted", children: "Off. Turning it on means a code as well as your password, every time you sign in." }),
3261
- /* @__PURE__ */ jsxs15("div", { className: "b316-mfa-actions", children: [
3262
- /* @__PURE__ */ jsx16("button", { type: "button", className: "b316-button", disabled: busy, onClick: begin, children: busy ? "Starting\u2026" : "Use an authenticator app" }),
3263
- /* @__PURE__ */ jsx16(
3326
+ ] }) : /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-off", children: [
3327
+ /* @__PURE__ */ jsx17("p", { className: "b316-muted", children: "Off. Turning it on means a code as well as your password, every time you sign in." }),
3328
+ /* @__PURE__ */ jsxs16("div", { className: "b316-mfa-actions", children: [
3329
+ /* @__PURE__ */ jsx17("button", { type: "button", className: "b316-button", disabled: busy, onClick: begin, children: busy ? "Starting\u2026" : "Use an authenticator app" }),
3330
+ /* @__PURE__ */ jsx17(
3264
3331
  "button",
3265
3332
  {
3266
3333
  type: "button",
@@ -3270,7 +3337,7 @@ function TwoFactorManager({
3270
3337
  children: "Email me a code"
3271
3338
  }
3272
3339
  ),
3273
- allowSms ? /* @__PURE__ */ jsx16(
3340
+ allowSms ? /* @__PURE__ */ jsx17(
3274
3341
  "button",
3275
3342
  {
3276
3343
  type: "button",
@@ -3287,7 +3354,7 @@ function TwoFactorManager({
3287
3354
 
3288
3355
  // src/ForgotPassword.tsx
3289
3356
  import { useState as useState15 } from "react";
3290
- import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
3357
+ import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
3291
3358
  function ForgotPassword({ onSent, signInUrl, className, style }) {
3292
3359
  const { client } = useBase316();
3293
3360
  const [email, setEmail] = useState15("");
@@ -3309,22 +3376,22 @@ function ForgotPassword({ onSent, signInUrl, className, style }) {
3309
3376
  }
3310
3377
  }
3311
3378
  if (sent) {
3312
- return /* @__PURE__ */ jsxs16("div", { className: cls("b316-card", className), style, children: [
3313
- /* @__PURE__ */ jsx17("h3", { className: "b316-form-title", children: "Check your email" }),
3314
- /* @__PURE__ */ jsxs16("p", { className: "b316-muted", children: [
3379
+ return /* @__PURE__ */ jsxs17("div", { className: cls("b316-card", className), style, children: [
3380
+ /* @__PURE__ */ jsx18("h3", { className: "b316-form-title", children: "Check your email" }),
3381
+ /* @__PURE__ */ jsxs17("p", { className: "b316-muted", children: [
3315
3382
  "If there is an account for ",
3316
3383
  email.trim(),
3317
3384
  ", a link to set a new password is on its way."
3318
3385
  ] }),
3319
- signInUrl ? /* @__PURE__ */ jsx17("a", { className: "b316-button-link", href: signInUrl, children: "Back to sign in" }) : null
3386
+ signInUrl ? /* @__PURE__ */ jsx18("a", { className: "b316-button-link", href: signInUrl, children: "Back to sign in" }) : null
3320
3387
  ] });
3321
3388
  }
3322
- return /* @__PURE__ */ jsxs16("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
3323
- /* @__PURE__ */ jsx17("h3", { className: "b316-form-title", children: "Reset your password" }),
3324
- error ? /* @__PURE__ */ jsx17("div", { className: "b316-error", role: "alert", children: error }) : null,
3325
- /* @__PURE__ */ jsxs16("div", { className: "b316-field", children: [
3326
- /* @__PURE__ */ jsx17("label", { className: "b316-label", htmlFor: "b316-forgot-email", children: "Email" }),
3327
- /* @__PURE__ */ jsx17(
3389
+ return /* @__PURE__ */ jsxs17("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
3390
+ /* @__PURE__ */ jsx18("h3", { className: "b316-form-title", children: "Reset your password" }),
3391
+ error ? /* @__PURE__ */ jsx18("div", { className: "b316-error", role: "alert", children: error }) : null,
3392
+ /* @__PURE__ */ jsxs17("div", { className: "b316-field", children: [
3393
+ /* @__PURE__ */ jsx18("label", { className: "b316-label", htmlFor: "b316-forgot-email", children: "Email" }),
3394
+ /* @__PURE__ */ jsx18(
3328
3395
  "input",
3329
3396
  {
3330
3397
  id: "b316-forgot-email",
@@ -3337,14 +3404,14 @@ function ForgotPassword({ onSent, signInUrl, className, style }) {
3337
3404
  }
3338
3405
  )
3339
3406
  ] }),
3340
- /* @__PURE__ */ jsx17("button", { type: "submit", className: "b316-button", disabled: busy || !email, children: busy ? "Sending\u2026" : "Send reset link" }),
3341
- signInUrl ? /* @__PURE__ */ jsx17("a", { className: "b316-button-link", href: signInUrl, children: "Back to sign in" }) : null
3407
+ /* @__PURE__ */ jsx18("button", { type: "submit", className: "b316-button", disabled: busy || !email, children: busy ? "Sending\u2026" : "Send reset link" }),
3408
+ signInUrl ? /* @__PURE__ */ jsx18("a", { className: "b316-button-link", href: signInUrl, children: "Back to sign in" }) : null
3342
3409
  ] });
3343
3410
  }
3344
3411
 
3345
3412
  // src/ResetPassword.tsx
3346
3413
  import { useEffect as useEffect12, useState as useState16 } from "react";
3347
- import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
3414
+ import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
3348
3415
  function ResetPassword({
3349
3416
  token: supplied,
3350
3417
  onReset,
@@ -3394,24 +3461,24 @@ function ResetPassword({
3394
3461
  }
3395
3462
  }
3396
3463
  if (done) {
3397
- return /* @__PURE__ */ jsxs17("div", { className: cls("b316-card", className), style, children: [
3398
- /* @__PURE__ */ jsx18("h3", { className: "b316-form-title", children: "Password changed" }),
3399
- /* @__PURE__ */ jsx18("p", { className: "b316-muted", children: "You can sign in with your new password." }),
3400
- signInUrl ? /* @__PURE__ */ jsx18("a", { className: "b316-button-link", href: signInUrl, children: "Sign in" }) : null
3464
+ return /* @__PURE__ */ jsxs18("div", { className: cls("b316-card", className), style, children: [
3465
+ /* @__PURE__ */ jsx19("h3", { className: "b316-form-title", children: "Password changed" }),
3466
+ /* @__PURE__ */ jsx19("p", { className: "b316-muted", children: "You can sign in with your new password." }),
3467
+ signInUrl ? /* @__PURE__ */ jsx19("a", { className: "b316-button-link", href: signInUrl, children: "Sign in" }) : null
3401
3468
  ] });
3402
3469
  }
3403
3470
  if (!token) {
3404
- return /* @__PURE__ */ jsxs17("div", { className: cls("b316-card", className), style, children: [
3405
- /* @__PURE__ */ jsx18("h3", { className: "b316-form-title", children: "Nothing to reset" }),
3406
- /* @__PURE__ */ jsx18("p", { className: "b316-muted", children: "This page needs the link from your email. Request a new one if yours has expired." })
3471
+ return /* @__PURE__ */ jsxs18("div", { className: cls("b316-card", className), style, children: [
3472
+ /* @__PURE__ */ jsx19("h3", { className: "b316-form-title", children: "Nothing to reset" }),
3473
+ /* @__PURE__ */ jsx19("p", { className: "b316-muted", children: "This page needs the link from your email. Request a new one if yours has expired." })
3407
3474
  ] });
3408
3475
  }
3409
- return /* @__PURE__ */ jsxs17("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
3410
- /* @__PURE__ */ jsx18("h3", { className: "b316-form-title", children: "Choose a new password" }),
3411
- error ? /* @__PURE__ */ jsx18("div", { className: "b316-error", role: "alert", children: error }) : null,
3412
- /* @__PURE__ */ jsxs17("div", { className: "b316-field", children: [
3413
- /* @__PURE__ */ jsx18("label", { className: "b316-label", htmlFor: "b316-reset-password", children: "New password" }),
3414
- /* @__PURE__ */ jsx18(
3476
+ return /* @__PURE__ */ jsxs18("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
3477
+ /* @__PURE__ */ jsx19("h3", { className: "b316-form-title", children: "Choose a new password" }),
3478
+ error ? /* @__PURE__ */ jsx19("div", { className: "b316-error", role: "alert", children: error }) : null,
3479
+ /* @__PURE__ */ jsxs18("div", { className: "b316-field", children: [
3480
+ /* @__PURE__ */ jsx19("label", { className: "b316-label", htmlFor: "b316-reset-password", children: "New password" }),
3481
+ /* @__PURE__ */ jsx19(
3415
3482
  "input",
3416
3483
  {
3417
3484
  id: "b316-reset-password",
@@ -3424,9 +3491,9 @@ function ResetPassword({
3424
3491
  }
3425
3492
  )
3426
3493
  ] }),
3427
- /* @__PURE__ */ jsxs17("div", { className: "b316-field", children: [
3428
- /* @__PURE__ */ jsx18("label", { className: "b316-label", htmlFor: "b316-reset-confirm", children: "Repeat it" }),
3429
- /* @__PURE__ */ jsx18(
3494
+ /* @__PURE__ */ jsxs18("div", { className: "b316-field", children: [
3495
+ /* @__PURE__ */ jsx19("label", { className: "b316-label", htmlFor: "b316-reset-confirm", children: "Repeat it" }),
3496
+ /* @__PURE__ */ jsx19(
3430
3497
  "input",
3431
3498
  {
3432
3499
  id: "b316-reset-confirm",
@@ -3439,13 +3506,13 @@ function ResetPassword({
3439
3506
  }
3440
3507
  )
3441
3508
  ] }),
3442
- /* @__PURE__ */ jsx18("button", { type: "submit", className: "b316-button", disabled: busy || !password, children: busy ? "Saving\u2026" : "Set password" })
3509
+ /* @__PURE__ */ jsx19("button", { type: "submit", className: "b316-button", disabled: busy || !password, children: busy ? "Saving\u2026" : "Set password" })
3443
3510
  ] });
3444
3511
  }
3445
3512
 
3446
3513
  // src/VerifyEmail.tsx
3447
3514
  import { useEffect as useEffect13, useRef as useRef4, useState as useState17 } from "react";
3448
- import { Fragment as Fragment5, jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
3515
+ import { Fragment as Fragment5, jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
3449
3516
  function VerifyEmail({
3450
3517
  token: supplied,
3451
3518
  onVerified,
@@ -3482,22 +3549,22 @@ function VerifyEmail({
3482
3549
  setState("failed");
3483
3550
  });
3484
3551
  }, [client, supplied, onVerified]);
3485
- return /* @__PURE__ */ jsx19("div", { className: cls("b316-card", className), style, children: state === "verified" ? /* @__PURE__ */ jsxs18(Fragment5, { children: [
3486
- /* @__PURE__ */ jsx19("h3", { className: "b316-form-title", children: "Email confirmed" }),
3487
- /* @__PURE__ */ jsx19("p", { className: "b316-muted", children: "Thanks \u2014 your address is verified." }),
3488
- continueUrl ? /* @__PURE__ */ jsx19("a", { className: "b316-button-link", href: continueUrl, children: "Continue" }) : null
3489
- ] }) : state === "failed" ? /* @__PURE__ */ jsxs18(Fragment5, { children: [
3490
- /* @__PURE__ */ jsx19("h3", { className: "b316-form-title", children: "That link did not work" }),
3491
- /* @__PURE__ */ jsx19("p", { className: "b316-muted", children: "It may have expired or already been used. Ask for a new one and try again." })
3492
- ] }) : state === "missing" ? /* @__PURE__ */ jsxs18(Fragment5, { children: [
3493
- /* @__PURE__ */ jsx19("h3", { className: "b316-form-title", children: "Nothing to confirm" }),
3494
- /* @__PURE__ */ jsx19("p", { className: "b316-muted", children: "This page needs the link from your email." })
3495
- ] }) : /* @__PURE__ */ jsx19("p", { className: "b316-muted", children: "Confirming your email\u2026" }) });
3552
+ return /* @__PURE__ */ jsx20("div", { className: cls("b316-card", className), style, children: state === "verified" ? /* @__PURE__ */ jsxs19(Fragment5, { children: [
3553
+ /* @__PURE__ */ jsx20("h3", { className: "b316-form-title", children: "Email confirmed" }),
3554
+ /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "Thanks \u2014 your address is verified." }),
3555
+ continueUrl ? /* @__PURE__ */ jsx20("a", { className: "b316-button-link", href: continueUrl, children: "Continue" }) : null
3556
+ ] }) : state === "failed" ? /* @__PURE__ */ jsxs19(Fragment5, { children: [
3557
+ /* @__PURE__ */ jsx20("h3", { className: "b316-form-title", children: "That link did not work" }),
3558
+ /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "It may have expired or already been used. Ask for a new one and try again." })
3559
+ ] }) : state === "missing" ? /* @__PURE__ */ jsxs19(Fragment5, { children: [
3560
+ /* @__PURE__ */ jsx20("h3", { className: "b316-form-title", children: "Nothing to confirm" }),
3561
+ /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "This page needs the link from your email." })
3562
+ ] }) : /* @__PURE__ */ jsx20("p", { className: "b316-muted", children: "Confirming your email\u2026" }) });
3496
3563
  }
3497
3564
 
3498
3565
  // src/TeamMembers.tsx
3499
3566
  import { useCallback as useCallback7, useEffect as useEffect14, useState as useState18 } from "react";
3500
- import { Fragment as Fragment6, jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
3567
+ import { Fragment as Fragment6, jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
3501
3568
  function TeamMembers({
3502
3569
  organizationId,
3503
3570
  onInvited,
@@ -3556,10 +3623,10 @@ function TeamMembers({
3556
3623
  return null;
3557
3624
  }
3558
3625
  if (!teams) {
3559
- return /* @__PURE__ */ jsx20("div", { className: cls("b316-card", className), style, children: error ?? "Loading\u2026" });
3626
+ return /* @__PURE__ */ jsx21("div", { className: cls("b316-card", className), style, children: error ?? "Loading\u2026" });
3560
3627
  }
3561
3628
  if (!chosen) {
3562
- return /* @__PURE__ */ jsx20("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." });
3629
+ 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." });
3563
3630
  }
3564
3631
  const canManage = invitations !== null;
3565
3632
  async function invite(event) {
@@ -3609,30 +3676,30 @@ function TeamMembers({
3609
3676
  setError(cause instanceof Error ? cause.message : "That invitation could not be withdrawn.");
3610
3677
  }
3611
3678
  }
3612
- return /* @__PURE__ */ jsxs19("div", { className: cls("b316-card b316-team", className), style, children: [
3613
- /* @__PURE__ */ jsx20("h3", { className: "b316-team-title", children: team?.name ?? "Team" }),
3679
+ return /* @__PURE__ */ jsxs20("div", { className: cls("b316-card b316-team", className), style, children: [
3680
+ /* @__PURE__ */ jsx21("h3", { className: "b316-team-title", children: team?.name ?? "Team" }),
3614
3681
  team?.inherited ? (
3615
3682
  // Not a member of this team, so not in the list below and with nothing
3616
3683
  // to leave: access comes from the team that manages it, and ends there.
3617
- /* @__PURE__ */ jsxs19("div", { className: "b316-muted", children: [
3684
+ /* @__PURE__ */ jsxs20("div", { className: "b316-muted", children: [
3618
3685
  "You have access through",
3619
3686
  " ",
3620
3687
  teams.find((candidate) => candidate.id === team.via)?.name ?? "the organization that manages this team",
3621
3688
  "."
3622
3689
  ] })
3623
3690
  ) : null,
3624
- error ? /* @__PURE__ */ jsx20("div", { className: "b316-error", role: "alert", children: error }) : null,
3625
- /* @__PURE__ */ jsx20("ul", { className: "b316-team-list", children: (members ?? []).map((member) => /* @__PURE__ */ jsxs19("li", { className: "b316-team-member", children: [
3626
- /* @__PURE__ */ jsxs19("div", { children: [
3627
- /* @__PURE__ */ jsx20("div", { children: member.user.name ?? member.user.email ?? "Someone" }),
3628
- /* @__PURE__ */ jsxs19("div", { className: "b316-muted", children: [
3691
+ error ? /* @__PURE__ */ jsx21("div", { className: "b316-error", role: "alert", children: error }) : null,
3692
+ /* @__PURE__ */ jsx21("ul", { className: "b316-team-list", children: (members ?? []).map((member) => /* @__PURE__ */ jsxs20("li", { className: "b316-team-member", children: [
3693
+ /* @__PURE__ */ jsxs20("div", { children: [
3694
+ /* @__PURE__ */ jsx21("div", { children: member.user.name ?? member.user.email ?? "Someone" }),
3695
+ /* @__PURE__ */ jsxs20("div", { className: "b316-muted", children: [
3629
3696
  member.user.email,
3630
3697
  member.user.id === session?.userId ? " \xB7 you" : ""
3631
3698
  ] })
3632
3699
  ] }),
3633
- /* @__PURE__ */ jsxs19("div", { className: "b316-team-member-side", children: [
3634
- /* @__PURE__ */ jsx20("span", { className: "b316-chip", children: member.role.name }),
3635
- canManage || member.user.id === session?.userId ? /* @__PURE__ */ jsx20(
3700
+ /* @__PURE__ */ jsxs20("div", { className: "b316-team-member-side", children: [
3701
+ /* @__PURE__ */ jsx21("span", { className: "b316-chip", children: member.role.name }),
3702
+ canManage || member.user.id === session?.userId ? /* @__PURE__ */ jsx21(
3636
3703
  ConfirmButton,
3637
3704
  {
3638
3705
  className: "b316-button-quiet b316-danger",
@@ -3644,19 +3711,19 @@ function TeamMembers({
3644
3711
  ) : null
3645
3712
  ] })
3646
3713
  ] }, member.id)) }),
3647
- canManage && (invitations ?? []).length > 0 ? /* @__PURE__ */ jsxs19(Fragment6, { children: [
3648
- /* @__PURE__ */ jsx20("h4", { className: "b316-team-subtitle", children: "Invited" }),
3649
- /* @__PURE__ */ jsx20("ul", { className: "b316-team-list", children: (invitations ?? []).map((invitation) => /* @__PURE__ */ jsxs19("li", { className: "b316-team-member", children: [
3650
- /* @__PURE__ */ jsxs19("div", { children: [
3651
- /* @__PURE__ */ jsx20("div", { children: invitation.email }),
3652
- /* @__PURE__ */ jsxs19("div", { className: "b316-muted", children: [
3714
+ canManage && (invitations ?? []).length > 0 ? /* @__PURE__ */ jsxs20(Fragment6, { children: [
3715
+ /* @__PURE__ */ jsx21("h4", { className: "b316-team-subtitle", children: "Invited" }),
3716
+ /* @__PURE__ */ jsx21("ul", { className: "b316-team-list", children: (invitations ?? []).map((invitation) => /* @__PURE__ */ jsxs20("li", { className: "b316-team-member", children: [
3717
+ /* @__PURE__ */ jsxs20("div", { children: [
3718
+ /* @__PURE__ */ jsx21("div", { children: invitation.email }),
3719
+ /* @__PURE__ */ jsxs20("div", { className: "b316-muted", children: [
3653
3720
  invitation.role.name,
3654
3721
  " \xB7 expires",
3655
3722
  " ",
3656
3723
  new Date(invitation.expiresAt).toLocaleDateString()
3657
3724
  ] })
3658
3725
  ] }),
3659
- /* @__PURE__ */ jsx20(
3726
+ /* @__PURE__ */ jsx21(
3660
3727
  "button",
3661
3728
  {
3662
3729
  type: "button",
@@ -3667,10 +3734,10 @@ function TeamMembers({
3667
3734
  )
3668
3735
  ] }, invitation.id)) })
3669
3736
  ] }) : null,
3670
- canManage ? /* @__PURE__ */ jsxs19("form", { className: "b316-team-invite", onSubmit: invite, children: [
3671
- /* @__PURE__ */ jsx20("label", { className: "b316-label", htmlFor: "b316-invite-email", children: "Invite by email" }),
3672
- /* @__PURE__ */ jsxs19("div", { className: "b316-team-invite-row", children: [
3673
- /* @__PURE__ */ jsx20(
3737
+ canManage ? /* @__PURE__ */ jsxs20("form", { className: "b316-team-invite", onSubmit: invite, children: [
3738
+ /* @__PURE__ */ jsx21("label", { className: "b316-label", htmlFor: "b316-invite-email", children: "Invite by email" }),
3739
+ /* @__PURE__ */ jsxs20("div", { className: "b316-team-invite-row", children: [
3740
+ /* @__PURE__ */ jsx21(
3674
3741
  "input",
3675
3742
  {
3676
3743
  id: "b316-invite-email",
@@ -3682,19 +3749,19 @@ function TeamMembers({
3682
3749
  onChange: (event) => setEmail(event.target.value)
3683
3750
  }
3684
3751
  ),
3685
- /* @__PURE__ */ jsx20("button", { type: "submit", className: "b316-button", disabled: busy || !email, children: busy ? "Sending\u2026" : "Invite" })
3752
+ /* @__PURE__ */ jsx21("button", { type: "submit", className: "b316-button", disabled: busy || !email, children: busy ? "Sending\u2026" : "Invite" })
3686
3753
  ] })
3687
3754
  ] }) : null,
3688
- copied ? /* @__PURE__ */ jsxs19("div", { className: "b316-team-link", children: [
3689
- /* @__PURE__ */ jsx20("div", { className: "b316-muted", children: "Send them this link. It is shown once and cannot be fetched again." }),
3690
- /* @__PURE__ */ jsx20("code", { children: copied })
3755
+ copied ? /* @__PURE__ */ jsxs20("div", { className: "b316-team-link", children: [
3756
+ /* @__PURE__ */ jsx21("div", { className: "b316-muted", children: "Send them this link. It is shown once and cannot be fetched again." }),
3757
+ /* @__PURE__ */ jsx21("code", { children: copied })
3691
3758
  ] }) : null
3692
3759
  ] });
3693
3760
  }
3694
3761
 
3695
3762
  // src/AcceptInvitation.tsx
3696
3763
  import { useEffect as useEffect15, useState as useState19 } from "react";
3697
- import { Fragment as Fragment7, jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
3764
+ import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
3698
3765
  function signUpUrlWithInvitation(url, token) {
3699
3766
  const [beforeHash, ...hash] = url.split("#");
3700
3767
  const base = beforeHash ?? "";
@@ -3761,42 +3828,42 @@ function AcceptInvitation({
3761
3828
  }
3762
3829
  }
3763
3830
  if (state === "loading") {
3764
- return /* @__PURE__ */ jsx21("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
3831
+ return /* @__PURE__ */ jsx22("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
3765
3832
  }
3766
3833
  if (state === "invalid") {
3767
- return /* @__PURE__ */ jsxs20("div", { className: cls("b316-card", className), style, children: [
3768
- /* @__PURE__ */ jsx21("h3", { className: "b316-form-title", children: "That invitation is no longer valid" }),
3769
- /* @__PURE__ */ jsx21("p", { className: "b316-muted", children: "It may have expired, been withdrawn, or already been used. Ask for a new one." })
3834
+ return /* @__PURE__ */ jsxs21("div", { className: cls("b316-card", className), style, children: [
3835
+ /* @__PURE__ */ jsx22("h3", { className: "b316-form-title", children: "That invitation is no longer valid" }),
3836
+ /* @__PURE__ */ jsx22("p", { className: "b316-muted", children: "It may have expired, been withdrawn, or already been used. Ask for a new one." })
3770
3837
  ] });
3771
3838
  }
3772
3839
  if (state === "accepted") {
3773
- return /* @__PURE__ */ jsx21("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsxs20("h3", { className: "b316-form-title", children: [
3840
+ return /* @__PURE__ */ jsx22("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsxs21("h3", { className: "b316-form-title", children: [
3774
3841
  "You have joined ",
3775
3842
  preview?.organizationName
3776
3843
  ] }) });
3777
3844
  }
3778
3845
  const matches = !user || (user.user.email ?? "").toLowerCase() === preview?.email.toLowerCase();
3779
- return /* @__PURE__ */ jsxs20("div", { className: cls("b316-card b316-invitation", className), style, children: [
3780
- /* @__PURE__ */ jsxs20("h3", { className: "b316-form-title", children: [
3846
+ return /* @__PURE__ */ jsxs21("div", { className: cls("b316-card b316-invitation", className), style, children: [
3847
+ /* @__PURE__ */ jsxs21("h3", { className: "b316-form-title", children: [
3781
3848
  "Join ",
3782
3849
  preview?.organizationName
3783
3850
  ] }),
3784
- /* @__PURE__ */ jsxs20("p", { className: "b316-muted", children: [
3851
+ /* @__PURE__ */ jsxs21("p", { className: "b316-muted", children: [
3785
3852
  "Invited as ",
3786
3853
  preview?.email,
3787
3854
  " \xB7 ",
3788
3855
  preview?.roleName
3789
3856
  ] }),
3790
- error ? /* @__PURE__ */ jsx21("div", { className: "b316-error", role: "alert", children: error }) : null,
3791
- !session ? /* @__PURE__ */ jsxs20(Fragment7, { children: [
3792
- /* @__PURE__ */ jsxs20("p", { children: [
3857
+ error ? /* @__PURE__ */ jsx22("div", { className: "b316-error", role: "alert", children: error }) : null,
3858
+ !session ? /* @__PURE__ */ jsxs21(Fragment7, { children: [
3859
+ /* @__PURE__ */ jsxs21("p", { children: [
3793
3860
  "Sign in as ",
3794
3861
  preview?.email,
3795
3862
  " to accept."
3796
3863
  ] }),
3797
- /* @__PURE__ */ jsxs20("div", { className: "b316-invitation-actions", children: [
3798
- signInUrl ? /* @__PURE__ */ jsx21("a", { className: "b316-button", href: signInUrl, children: "Sign in" }) : null,
3799
- signUpUrl ? /* @__PURE__ */ jsx21(
3864
+ /* @__PURE__ */ jsxs21("div", { className: "b316-invitation-actions", children: [
3865
+ signInUrl ? /* @__PURE__ */ jsx22("a", { className: "b316-button", href: signInUrl, children: "Sign in" }) : null,
3866
+ signUpUrl ? /* @__PURE__ */ jsx22(
3800
3867
  "a",
3801
3868
  {
3802
3869
  className: "b316-button-link",
@@ -3809,20 +3876,20 @@ function AcceptInvitation({
3809
3876
  // Said before they press anything. The server refuses this, but
3810
3877
  // finding out after a click reads as a broken invitation rather than
3811
3878
  // as being signed in as the wrong person.
3812
- /* @__PURE__ */ jsxs20("p", { children: [
3879
+ /* @__PURE__ */ jsxs21("p", { children: [
3813
3880
  "You are signed in as ",
3814
3881
  user?.user.email,
3815
3882
  ". This invitation was sent to ",
3816
3883
  preview?.email,
3817
3884
  " \u2014 sign in as that address to accept it."
3818
3885
  ] })
3819
- ) : /* @__PURE__ */ jsx21("button", { type: "button", className: "b316-button", disabled: busy, onClick: accept, children: busy ? "Joining\u2026" : `Join ${preview?.organizationName}` })
3886
+ ) : /* @__PURE__ */ jsx22("button", { type: "button", className: "b316-button", disabled: busy, onClick: accept, children: busy ? "Joining\u2026" : `Join ${preview?.organizationName}` })
3820
3887
  ] });
3821
3888
  }
3822
3889
 
3823
3890
  // src/PayInvoice.tsx
3824
3891
  import { useEffect as useEffect16, useRef as useRef5, useState as useState20 } from "react";
3825
- import { jsx as jsx22, jsxs as jsxs21 } from "react/jsx-runtime";
3892
+ import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
3826
3893
  var STRIPE_SRC = "https://js.stripe.com/v3/";
3827
3894
  function loadStripeScript() {
3828
3895
  if (typeof window === "undefined") {
@@ -3914,12 +3981,12 @@ function PayInvoice({
3914
3981
  onPaid?.();
3915
3982
  };
3916
3983
  if (done) {
3917
- return /* @__PURE__ */ jsx22("div", { className: cls("b316-pay", className), style, children: /* @__PURE__ */ jsx22("p", { className: "b316-pay__done", children: "Paid \u2014 thank you." }) });
3984
+ return /* @__PURE__ */ jsx23("div", { className: cls("b316-pay", className), style, children: /* @__PURE__ */ jsx23("p", { className: "b316-pay__done", children: "Paid \u2014 thank you." }) });
3918
3985
  }
3919
- return /* @__PURE__ */ jsxs21("form", { className: cls("b316-pay", className), style, onSubmit: submit, children: [
3920
- error ? /* @__PURE__ */ jsx22("p", { className: "b316-pay__error", role: "alert", children: error }) : null,
3921
- /* @__PURE__ */ jsx22("div", { ref: mountRef, className: "b316-pay__element" }),
3922
- /* @__PURE__ */ jsx22("button", { className: "b316-pay__submit", type: "submit", disabled: !ready || paying, children: paying ? "Paying\u2026" : "Pay" })
3986
+ return /* @__PURE__ */ jsxs22("form", { className: cls("b316-pay", className), style, onSubmit: submit, children: [
3987
+ error ? /* @__PURE__ */ jsx23("p", { className: "b316-pay__error", role: "alert", children: error }) : null,
3988
+ /* @__PURE__ */ jsx23("div", { ref: mountRef, className: "b316-pay__element" }),
3989
+ /* @__PURE__ */ jsx23("button", { className: "b316-pay__submit", type: "submit", disabled: !ready || paying, children: paying ? "Paying\u2026" : "Pay" })
3923
3990
  ] });
3924
3991
  }
3925
3992
 
@@ -4105,7 +4172,7 @@ function usePlans(options = {}) {
4105
4172
  }
4106
4173
 
4107
4174
  // src/PricingTable.tsx
4108
- import { jsx as jsx23, jsxs as jsxs22 } from "react/jsx-runtime";
4175
+ import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
4109
4176
  function formatAmount(amount, currency) {
4110
4177
  if (amount === null) return "Free";
4111
4178
  const value = Number(amount);
@@ -4171,50 +4238,50 @@ function PricingTable({
4171
4238
  }
4172
4239
  }
4173
4240
  if (error) {
4174
- return /* @__PURE__ */ jsx23("div", { className: cls("b316-card", className), style, children: "Plans are unavailable right now." });
4241
+ return /* @__PURE__ */ jsx24("div", { className: cls("b316-card", className), style, children: "Plans are unavailable right now." });
4175
4242
  }
4176
4243
  if (!plans) {
4177
- return /* @__PURE__ */ jsx23("div", { className: cls("b316-card", className), style, children: "Loading plans\u2026" });
4244
+ return /* @__PURE__ */ jsx24("div", { className: cls("b316-card", className), style, children: "Loading plans\u2026" });
4178
4245
  }
4179
4246
  if (plans.length === 0) {
4180
- return /* @__PURE__ */ jsx23("div", { className: cls("b316-card", className), style, children: "No plans are published yet." });
4247
+ return /* @__PURE__ */ jsx24("div", { className: cls("b316-card", className), style, children: "No plans are published yet." });
4181
4248
  }
4182
4249
  const anyTrial = plans.some((plan) => Boolean(plan.trialDays));
4183
4250
  const anyDescription = plans.some((plan) => Boolean(plan.description));
4184
4251
  const anyFeatured = plans.some((plan) => plan.key === featuredPlanKey);
4185
- return /* @__PURE__ */ jsxs22("div", { className: cls("b316-plans", className), style, children: [
4252
+ return /* @__PURE__ */ jsxs23("div", { className: cls("b316-plans", className), style, children: [
4186
4253
  managedBy ? (
4187
4254
  // A client company's plan comes from the firm that runs it. The table
4188
4255
  // still shows what is on offer, with the current plan marked, but
4189
4256
  // nothing here can be bought: it would grant this account nothing.
4190
- /* @__PURE__ */ jsxs22("div", { className: "b316-plans-managed b316-muted", children: [
4257
+ /* @__PURE__ */ jsxs23("div", { className: "b316-plans-managed b316-muted", children: [
4191
4258
  "Your plan is provided by ",
4192
4259
  managedBy.name ?? "the organization that manages your account",
4193
4260
  ". Ask them to change it."
4194
4261
  ] })
4195
- ) : lastError ? /* @__PURE__ */ jsx23("div", { className: "b316-plans-error", role: "alert", children: lastError }) : scheduled ? /* @__PURE__ */ jsx23("div", { className: "b316-plans-managed b316-muted", role: "status", children: scheduled }) : null,
4262
+ ) : 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,
4196
4263
  plans.map((plan) => {
4197
4264
  const base = plan.prices.find((price) => price.featureId === null) ?? plan.prices[0];
4198
4265
  const isCurrent = current === plan.planVersionId;
4199
4266
  const featured = featuredPlanKey === plan.key;
4200
- return /* @__PURE__ */ jsxs22(
4267
+ return /* @__PURE__ */ jsxs23(
4201
4268
  "div",
4202
4269
  {
4203
4270
  className: featured ? "b316-card b316-plan b316-plan-featured" : "b316-card b316-plan",
4204
4271
  children: [
4205
- /* @__PURE__ */ jsxs22("div", { className: "b316-plan-head", children: [
4206
- anyFeatured ? /* @__PURE__ */ jsx23("div", { className: featured ? "b316-plan-badge" : "b316-plan-badge-spacer", children: featured ? "Recommended" : "\xA0" }) : null,
4207
- /* @__PURE__ */ jsx23("div", { className: "b316-plan-name", children: plan.name }),
4208
- anyDescription ? /* @__PURE__ */ jsx23("div", { className: "b316-plan-desc", children: plan.description ?? "\xA0" }) : null
4272
+ /* @__PURE__ */ jsxs23("div", { className: "b316-plan-head", children: [
4273
+ anyFeatured ? /* @__PURE__ */ jsx24("div", { className: featured ? "b316-plan-badge" : "b316-plan-badge-spacer", children: featured ? "Recommended" : "\xA0" }) : null,
4274
+ /* @__PURE__ */ jsx24("div", { className: "b316-plan-name", children: plan.name }),
4275
+ anyDescription ? /* @__PURE__ */ jsx24("div", { className: "b316-plan-desc", children: plan.description ?? "\xA0" }) : null
4209
4276
  ] }),
4210
- /* @__PURE__ */ jsxs22("div", { className: "b316-plan-pricing", children: [
4211
- /* @__PURE__ */ jsx23("div", { className: "b316-plan-price", children: formatAmount(base?.amount ?? null, plan.currency) }),
4212
- /* @__PURE__ */ jsx23("div", { className: "b316-plan-cadence", children: cadence(plan, base?.amount ?? null) }),
4213
- anyTrial ? /* @__PURE__ */ jsx23("div", { className: "b316-plan-trial", children: describeTrial(plan, plans) ?? "\xA0" }) : null
4277
+ /* @__PURE__ */ jsxs23("div", { className: "b316-plan-pricing", children: [
4278
+ /* @__PURE__ */ jsx24("div", { className: "b316-plan-price", children: formatAmount(base?.amount ?? null, plan.currency) }),
4279
+ /* @__PURE__ */ jsx24("div", { className: "b316-plan-cadence", children: cadence(plan, base?.amount ?? null) }),
4280
+ anyTrial ? /* @__PURE__ */ jsx24("div", { className: "b316-plan-trial", children: describeTrial(plan, plans) ?? "\xA0" }) : null
4214
4281
  ] }),
4215
- /* @__PURE__ */ jsx23("ul", { className: "b316-plan-features", children: plan.entitlements.filter((entitlement) => entitlement.enabled).map((entitlement) => /* @__PURE__ */ jsxs22("li", { className: "b316-plan-feature", children: [
4216
- /* @__PURE__ */ jsx23("span", { children: entitlement.featureName }),
4217
- /* @__PURE__ */ jsx23("span", { className: "b316-plan-feature-value", children: entitlement.limit === null ? "Unlimited" : (
4282
+ /* @__PURE__ */ jsx24("ul", { className: "b316-plan-features", children: plan.entitlements.filter((entitlement) => entitlement.enabled).map((entitlement) => /* @__PURE__ */ jsxs23("li", { className: "b316-plan-feature", children: [
4283
+ /* @__PURE__ */ jsx24("span", { children: entitlement.featureName }),
4284
+ /* @__PURE__ */ jsx24("span", { className: "b316-plan-feature-value", children: entitlement.limit === null ? "Unlimited" : (
4218
4285
  // A usage price on the feature makes the limit an
4219
4286
  // allowance billed past, not a ceiling — the same
4220
4287
  // rule `check()` applies (any non-FLAT price).
@@ -4223,7 +4290,7 @@ function PricingTable({
4223
4290
  ) ? `${entitlement.limit} included` : entitlement.limit
4224
4291
  ) })
4225
4292
  ] }, entitlement.featureId)) }),
4226
- /* @__PURE__ */ jsx23("div", { className: "b316-plan-action", children: /* @__PURE__ */ jsx23(
4293
+ /* @__PURE__ */ jsx24("div", { className: "b316-plan-action", children: /* @__PURE__ */ jsx24(
4227
4294
  "button",
4228
4295
  {
4229
4296
  type: "button",
@@ -4252,7 +4319,7 @@ import {
4252
4319
  formatAddress,
4253
4320
  specFor
4254
4321
  } from "@base316/sdk";
4255
- import { jsx as jsx24, jsxs as jsxs23 } from "react/jsx-runtime";
4322
+ import { jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
4256
4323
  function formatNumber(value, fraction = 0) {
4257
4324
  const number = Number(value);
4258
4325
  return Number.isFinite(number) ? new Intl.NumberFormat(void 0, {
@@ -4274,10 +4341,10 @@ function formatDuration(value) {
4274
4341
  }
4275
4342
  function FieldCell({ value, field, related }) {
4276
4343
  if (field.type === "RELATION") {
4277
- return related?.title ?? (related?.id ? /* @__PURE__ */ jsx24("code", { className: "b316-muted", children: related.id }) : "\u2014");
4344
+ return related?.title ?? (related?.id ? /* @__PURE__ */ jsx25("code", { className: "b316-muted", children: related.id }) : "\u2014");
4278
4345
  }
4279
4346
  if (value === null || value === void 0 || value === "") {
4280
- return /* @__PURE__ */ jsx24("span", { className: "b316-muted", children: "\u2014" });
4347
+ return /* @__PURE__ */ jsx25("span", { className: "b316-muted", children: "\u2014" });
4281
4348
  }
4282
4349
  switch (field.type) {
4283
4350
  case "BOOLEAN":
@@ -4290,9 +4357,9 @@ function FieldCell({ value, field, related }) {
4290
4357
  return formatDuration(value);
4291
4358
  case "RATING": {
4292
4359
  const stars = Math.round(Number(value));
4293
- return /* @__PURE__ */ jsxs23("span", { "aria-label": `${stars} out of 5`, children: [
4360
+ return /* @__PURE__ */ jsxs24("span", { "aria-label": `${stars} out of 5`, children: [
4294
4361
  "\u2605".repeat(stars),
4295
- /* @__PURE__ */ jsx24("span", { className: "b316-muted", children: "\u2605".repeat(Math.max(0, 5 - stars)) })
4362
+ /* @__PURE__ */ jsx25("span", { className: "b316-muted", children: "\u2605".repeat(Math.max(0, 5 - stars)) })
4296
4363
  ] });
4297
4364
  }
4298
4365
  case "DATE":
@@ -4300,15 +4367,15 @@ function FieldCell({ value, field, related }) {
4300
4367
  case "DATETIME":
4301
4368
  return new Date(String(value)).toLocaleString();
4302
4369
  case "SELECT":
4303
- return /* @__PURE__ */ jsx24("span", { className: "b316-chip", children: String(value) });
4370
+ return /* @__PURE__ */ jsx25("span", { className: "b316-chip", children: String(value) });
4304
4371
  case "MULTISELECT":
4305
- return /* @__PURE__ */ jsx24("span", { className: "b316-chips", children: (Array.isArray(value) ? value : [value]).map((item) => /* @__PURE__ */ jsx24("span", { className: "b316-chip", children: String(item) }, String(item))) });
4372
+ 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))) });
4306
4373
  case "URL":
4307
- return /* @__PURE__ */ jsx24("a", { href: String(value), target: "_blank", rel: "noreferrer noopener", children: String(value) });
4374
+ return /* @__PURE__ */ jsx25("a", { href: String(value), target: "_blank", rel: "noreferrer noopener", children: String(value) });
4308
4375
  case "EMAIL":
4309
- return /* @__PURE__ */ jsx24("a", { href: `mailto:${String(value)}`, children: String(value) });
4376
+ return /* @__PURE__ */ jsx25("a", { href: `mailto:${String(value)}`, children: String(value) });
4310
4377
  case "PHONE":
4311
- return /* @__PURE__ */ jsx24("a", { href: `tel:${String(value)}`, children: String(value) });
4378
+ return /* @__PURE__ */ jsx25("a", { href: `tel:${String(value)}`, children: String(value) });
4312
4379
  case "ADDRESS":
4313
4380
  return formatAddress(value);
4314
4381
  case "ATTACHMENT": {
@@ -4320,7 +4387,7 @@ function FieldCell({ value, field, related }) {
4320
4387
  return text.length > 80 ? `${text.slice(0, 80)}\u2026` : text;
4321
4388
  }
4322
4389
  case "JSON":
4323
- return /* @__PURE__ */ jsx24("code", { className: "b316-muted", children: JSON.stringify(value).slice(0, 60) });
4390
+ return /* @__PURE__ */ jsx25("code", { className: "b316-muted", children: JSON.stringify(value).slice(0, 60) });
4324
4391
  default:
4325
4392
  return String(value);
4326
4393
  }
@@ -4341,7 +4408,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4341
4408
  function control() {
4342
4409
  switch (field.type) {
4343
4410
  case "LONGTEXT":
4344
- return /* @__PURE__ */ jsx24(
4411
+ return /* @__PURE__ */ jsx25(
4345
4412
  "textarea",
4346
4413
  {
4347
4414
  ...common,
@@ -4351,7 +4418,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4351
4418
  }
4352
4419
  );
4353
4420
  case "BOOLEAN":
4354
- return /* @__PURE__ */ jsx24(
4421
+ return /* @__PURE__ */ jsx25(
4355
4422
  "input",
4356
4423
  {
4357
4424
  ...common,
@@ -4362,22 +4429,22 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4362
4429
  }
4363
4430
  );
4364
4431
  case "SELECT":
4365
- return /* @__PURE__ */ jsxs23(
4432
+ return /* @__PURE__ */ jsxs24(
4366
4433
  "select",
4367
4434
  {
4368
4435
  ...common,
4369
4436
  value: value === null || value === void 0 ? "" : String(value),
4370
4437
  onChange: (event) => onChange(event.target.value === "" ? null : event.target.value),
4371
4438
  children: [
4372
- field.required ? null : /* @__PURE__ */ jsx24("option", { value: "", children: "\u2014" }),
4373
- (field.options ?? []).map((option) => /* @__PURE__ */ jsx24("option", { value: option, children: option }, option))
4439
+ field.required ? null : /* @__PURE__ */ jsx25("option", { value: "", children: "\u2014" }),
4440
+ (field.options ?? []).map((option) => /* @__PURE__ */ jsx25("option", { value: option, children: option }, option))
4374
4441
  ]
4375
4442
  }
4376
4443
  );
4377
4444
  case "MULTISELECT": {
4378
4445
  const selected = new Set(Array.isArray(value) ? value.map(String) : []);
4379
- return /* @__PURE__ */ jsx24("div", { className: "b316-choices", children: (field.options ?? []).map((option) => /* @__PURE__ */ jsxs23("label", { className: "b316-choice", children: [
4380
- /* @__PURE__ */ jsx24(
4446
+ return /* @__PURE__ */ jsx25("div", { className: "b316-choices", children: (field.options ?? []).map((option) => /* @__PURE__ */ jsxs24("label", { className: "b316-choice", children: [
4447
+ /* @__PURE__ */ jsx25(
4381
4448
  "input",
4382
4449
  {
4383
4450
  type: "checkbox",
@@ -4400,7 +4467,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4400
4467
  case "NUMBER":
4401
4468
  case "MONEY":
4402
4469
  case "PERCENT":
4403
- return /* @__PURE__ */ jsx24(
4470
+ return /* @__PURE__ */ jsx25(
4404
4471
  "input",
4405
4472
  {
4406
4473
  ...common,
@@ -4411,7 +4478,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4411
4478
  }
4412
4479
  );
4413
4480
  case "RATING":
4414
- return /* @__PURE__ */ jsx24(
4481
+ return /* @__PURE__ */ jsx25(
4415
4482
  "input",
4416
4483
  {
4417
4484
  ...common,
@@ -4425,8 +4492,8 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4425
4492
  );
4426
4493
  case "DURATION": {
4427
4494
  const minutes = value === null || value === void 0 ? "" : String(Number(value) / 60);
4428
- return /* @__PURE__ */ jsxs23("div", { className: "b316-suffixed", children: [
4429
- /* @__PURE__ */ jsx24(
4495
+ return /* @__PURE__ */ jsxs24("div", { className: "b316-suffixed", children: [
4496
+ /* @__PURE__ */ jsx25(
4430
4497
  "input",
4431
4498
  {
4432
4499
  ...common,
@@ -4436,11 +4503,11 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4436
4503
  onChange: (event) => onChange(event.target.value === "" ? null : Number(event.target.value) * 60)
4437
4504
  }
4438
4505
  ),
4439
- /* @__PURE__ */ jsx24("span", { className: "b316-muted", children: "minutes" })
4506
+ /* @__PURE__ */ jsx25("span", { className: "b316-muted", children: "minutes" })
4440
4507
  ] });
4441
4508
  }
4442
4509
  case "DATE":
4443
- return /* @__PURE__ */ jsx24(
4510
+ return /* @__PURE__ */ jsx25(
4444
4511
  "input",
4445
4512
  {
4446
4513
  ...common,
@@ -4450,7 +4517,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4450
4517
  }
4451
4518
  );
4452
4519
  case "DATETIME":
4453
- return /* @__PURE__ */ jsx24(
4520
+ return /* @__PURE__ */ jsx25(
4454
4521
  "input",
4455
4522
  {
4456
4523
  ...common,
@@ -4463,7 +4530,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4463
4530
  );
4464
4531
  case "ADDRESS": {
4465
4532
  const address = value ?? {};
4466
- const part = (key, label) => /* @__PURE__ */ jsx24(
4533
+ const part = (key, label) => /* @__PURE__ */ jsx25(
4467
4534
  "input",
4468
4535
  {
4469
4536
  className: "b316-input",
@@ -4475,7 +4542,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4475
4542
  },
4476
4543
  key
4477
4544
  );
4478
- return /* @__PURE__ */ jsxs23("div", { className: "b316-address", children: [
4545
+ return /* @__PURE__ */ jsxs24("div", { className: "b316-address", children: [
4479
4546
  part("line1", "Address line 1"),
4480
4547
  part("line2", "Address line 2"),
4481
4548
  part("city", "City"),
@@ -4485,7 +4552,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4485
4552
  ] });
4486
4553
  }
4487
4554
  case "EMAIL":
4488
- return /* @__PURE__ */ jsx24(
4555
+ return /* @__PURE__ */ jsx25(
4489
4556
  "input",
4490
4557
  {
4491
4558
  ...common,
@@ -4495,7 +4562,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4495
4562
  }
4496
4563
  );
4497
4564
  case "URL":
4498
- return /* @__PURE__ */ jsx24(
4565
+ return /* @__PURE__ */ jsx25(
4499
4566
  "input",
4500
4567
  {
4501
4568
  ...common,
@@ -4505,7 +4572,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4505
4572
  }
4506
4573
  );
4507
4574
  case "PHONE":
4508
- return /* @__PURE__ */ jsx24(
4575
+ return /* @__PURE__ */ jsx25(
4509
4576
  "input",
4510
4577
  {
4511
4578
  ...common,
@@ -4515,7 +4582,7 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4515
4582
  }
4516
4583
  );
4517
4584
  default:
4518
- return /* @__PURE__ */ jsx24(
4585
+ return /* @__PURE__ */ jsx25(
4519
4586
  "input",
4520
4587
  {
4521
4588
  ...common,
@@ -4526,14 +4593,14 @@ function FieldInput({ value, field, onChange, error, disabled }) {
4526
4593
  );
4527
4594
  }
4528
4595
  }
4529
- return /* @__PURE__ */ jsxs23("div", { className: "b316-field", children: [
4530
- /* @__PURE__ */ jsxs23("label", { className: "b316-label", htmlFor: id, children: [
4596
+ return /* @__PURE__ */ jsxs24("div", { className: "b316-field", children: [
4597
+ /* @__PURE__ */ jsxs24("label", { className: "b316-label", htmlFor: id, children: [
4531
4598
  field.label,
4532
- field.required ? /* @__PURE__ */ jsx24("span", { "aria-hidden": "true", children: " *" }) : null
4599
+ field.required ? /* @__PURE__ */ jsx25("span", { "aria-hidden": "true", children: " *" }) : null
4533
4600
  ] }),
4534
4601
  control(),
4535
- field.description ? /* @__PURE__ */ jsx24("div", { className: "b316-hint", children: field.description }) : null,
4536
- error ? /* @__PURE__ */ jsx24("div", { className: "b316-error", id: described, role: "alert", children: error }) : null
4602
+ field.description ? /* @__PURE__ */ jsx25("div", { className: "b316-hint", children: field.description }) : null,
4603
+ error ? /* @__PURE__ */ jsx25("div", { className: "b316-error", id: described, role: "alert", children: error }) : null
4537
4604
  ] });
4538
4605
  }
4539
4606
 
@@ -4543,7 +4610,7 @@ import { useEffect as useEffect21, useState as useState26 } from "react";
4543
4610
 
4544
4611
  // src/RelationPicker.tsx
4545
4612
  import { useEffect as useEffect19, useRef as useRef7, useState as useState24 } from "react";
4546
- import { Fragment as Fragment8, jsx as jsx25, jsxs as jsxs24 } from "react/jsx-runtime";
4613
+ import { Fragment as Fragment8, jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
4547
4614
  function RelationPicker({
4548
4615
  field,
4549
4616
  value,
@@ -4614,14 +4681,14 @@ function RelationPicker({
4614
4681
  document.removeEventListener("mousedown", onDocumentClick);
4615
4682
  };
4616
4683
  }, [open]);
4617
- return /* @__PURE__ */ jsxs24("div", { className: "b316-field", ref: box, children: [
4618
- /* @__PURE__ */ jsxs24("label", { className: "b316-label", htmlFor: id, children: [
4684
+ return /* @__PURE__ */ jsxs25("div", { className: "b316-field", ref: box, children: [
4685
+ /* @__PURE__ */ jsxs25("label", { className: "b316-label", htmlFor: id, children: [
4619
4686
  field.label,
4620
- field.required ? /* @__PURE__ */ jsx25("span", { "aria-hidden": "true", children: " *" }) : null
4687
+ field.required ? /* @__PURE__ */ jsx26("span", { "aria-hidden": "true", children: " *" }) : null
4621
4688
  ] }),
4622
- value && !open ? /* @__PURE__ */ jsxs24("div", { className: "b316-relation-chosen", children: [
4623
- /* @__PURE__ */ jsx25("span", { children: chosenTitle ?? value }),
4624
- disabled ? null : /* @__PURE__ */ jsx25(
4689
+ value && !open ? /* @__PURE__ */ jsxs25("div", { className: "b316-relation-chosen", children: [
4690
+ /* @__PURE__ */ jsx26("span", { children: chosenTitle ?? value }),
4691
+ disabled ? null : /* @__PURE__ */ jsx26(
4625
4692
  "button",
4626
4693
  {
4627
4694
  type: "button",
@@ -4633,7 +4700,7 @@ function RelationPicker({
4633
4700
  children: "Change"
4634
4701
  }
4635
4702
  ),
4636
- disabled || field.required ? null : /* @__PURE__ */ jsx25(
4703
+ disabled || field.required ? null : /* @__PURE__ */ jsx26(
4637
4704
  "button",
4638
4705
  {
4639
4706
  type: "button",
@@ -4643,8 +4710,8 @@ function RelationPicker({
4643
4710
  children: "Clear"
4644
4711
  }
4645
4712
  )
4646
- ] }) : /* @__PURE__ */ jsxs24(Fragment8, { children: [
4647
- /* @__PURE__ */ jsx25(
4713
+ ] }) : /* @__PURE__ */ jsxs25(Fragment8, { children: [
4714
+ /* @__PURE__ */ jsx26(
4648
4715
  "input",
4649
4716
  {
4650
4717
  id,
@@ -4665,7 +4732,7 @@ function RelationPicker({
4665
4732
  }
4666
4733
  }
4667
4734
  ),
4668
- open ? /* @__PURE__ */ jsx25("ul", { className: "b316-relation-results", id: `${id}-results`, role: "listbox", children: results.length === 0 ? /* @__PURE__ */ jsx25("li", { className: "b316-muted b316-relation-empty", children: "No matches" }) : results.map((result) => /* @__PURE__ */ jsx25("li", { children: /* @__PURE__ */ jsx25(
4735
+ 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(
4669
4736
  "button",
4670
4737
  {
4671
4738
  type: "button",
@@ -4681,13 +4748,13 @@ function RelationPicker({
4681
4748
  }
4682
4749
  ) }, result.id)) }) : null
4683
4750
  ] }),
4684
- field.description ? /* @__PURE__ */ jsx25("div", { className: "b316-hint", children: field.description }) : null,
4685
- error ? /* @__PURE__ */ jsx25("div", { className: "b316-error", role: "alert", children: error }) : null
4751
+ field.description ? /* @__PURE__ */ jsx26("div", { className: "b316-hint", children: field.description }) : null,
4752
+ error ? /* @__PURE__ */ jsx26("div", { className: "b316-error", role: "alert", children: error }) : null
4686
4753
  ] });
4687
4754
  }
4688
4755
 
4689
4756
  // src/useCollection.ts
4690
- import { useCallback as useCallback9, useEffect as useEffect20, useMemo as useMemo2, useState as useState25 } from "react";
4757
+ import { useCallback as useCallback9, useEffect as useEffect20, useMemo as useMemo3, useState as useState25 } from "react";
4691
4758
  function fieldErrorFrom(cause) {
4692
4759
  const param = cause?.param;
4693
4760
  const message = cause instanceof Error ? cause.message : "That value was not accepted.";
@@ -4711,7 +4778,7 @@ function useCollection(collection, options = {}) {
4711
4778
  const [saving, setSaving] = useState25(false);
4712
4779
  const { tenant, limit, recordId } = options;
4713
4780
  const fixedFilters = JSON.stringify(options.filters ?? []);
4714
- const scope = useMemo2(() => tenant ? { tenant } : void 0, [tenant]);
4781
+ const scope = useMemo3(() => tenant ? { tenant } : void 0, [tenant]);
4715
4782
  useEffect20(() => {
4716
4783
  if (!token) {
4717
4784
  return;
@@ -4923,7 +4990,7 @@ function useCollection(collection, options = {}) {
4923
4990
  }
4924
4991
 
4925
4992
  // src/RecordForm.tsx
4926
- import { jsx as jsx26, jsxs as jsxs25 } from "react/jsx-runtime";
4993
+ import { jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
4927
4994
  function RecordForm({
4928
4995
  collection,
4929
4996
  recordId,
@@ -4954,10 +5021,10 @@ function RecordForm({
4954
5021
  }
4955
5022
  }, [existing, loaded]);
4956
5023
  if (error) {
4957
- return /* @__PURE__ */ jsx26("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx26("div", { className: "b316-error", role: "alert", children: error }) });
5024
+ return /* @__PURE__ */ jsx27("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx27("div", { className: "b316-error", role: "alert", children: error }) });
4958
5025
  }
4959
5026
  if (!schema || !loaded) {
4960
- return /* @__PURE__ */ jsx26("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5027
+ return /* @__PURE__ */ jsx27("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
4961
5028
  }
4962
5029
  const editable = schema.fields.filter((field) => !specFor2(field).computed);
4963
5030
  async function submit(event) {
@@ -4967,11 +5034,11 @@ function RecordForm({
4967
5034
  onSaved?.(saved.id);
4968
5035
  }
4969
5036
  }
4970
- return /* @__PURE__ */ jsxs25("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
4971
- /* @__PURE__ */ jsx26("h3", { className: "b316-form-title", children: recordId ? `Edit ${schema.name.toLowerCase()}` : `New ${schema.name.toLowerCase()}` }),
4972
- fieldErrors._ ? /* @__PURE__ */ jsx26("div", { className: "b316-error", role: "alert", children: fieldErrors._ }) : null,
5037
+ return /* @__PURE__ */ jsxs26("form", { className: cls("b316-card b316-form", className), style, onSubmit: submit, children: [
5038
+ /* @__PURE__ */ jsx27("h3", { className: "b316-form-title", children: recordId ? `Edit ${schema.name.toLowerCase()}` : `New ${schema.name.toLowerCase()}` }),
5039
+ fieldErrors._ ? /* @__PURE__ */ jsx27("div", { className: "b316-error", role: "alert", children: fieldErrors._ }) : null,
4973
5040
  editable.map(
4974
- (field) => field.type === "RELATION" ? /* @__PURE__ */ jsx26(
5041
+ (field) => field.type === "RELATION" ? /* @__PURE__ */ jsx27(
4975
5042
  RelationPicker,
4976
5043
  {
4977
5044
  field,
@@ -4982,7 +5049,7 @@ function RecordForm({
4982
5049
  onChange: (next) => setValues((current) => ({ ...current, [field.key]: next }))
4983
5050
  },
4984
5051
  field.key
4985
- ) : /* @__PURE__ */ jsx26(
5052
+ ) : /* @__PURE__ */ jsx27(
4986
5053
  FieldInput,
4987
5054
  {
4988
5055
  field,
@@ -4994,15 +5061,15 @@ function RecordForm({
4994
5061
  field.key
4995
5062
  )
4996
5063
  ),
4997
- /* @__PURE__ */ jsxs25("div", { className: "b316-form-actions", children: [
4998
- onCancel ? /* @__PURE__ */ jsx26("button", { type: "button", className: "b316-button-quiet", onClick: onCancel, disabled: saving, children: "Cancel" }) : null,
4999
- /* @__PURE__ */ jsx26("button", { type: "submit", className: "b316-button", disabled: saving, children: saving ? "Saving\u2026" : "Save" })
5064
+ /* @__PURE__ */ jsxs26("div", { className: "b316-form-actions", children: [
5065
+ onCancel ? /* @__PURE__ */ jsx27("button", { type: "button", className: "b316-button-quiet", onClick: onCancel, disabled: saving, children: "Cancel" }) : null,
5066
+ /* @__PURE__ */ jsx27("button", { type: "submit", className: "b316-button", disabled: saving, children: saving ? "Saving\u2026" : "Save" })
5000
5067
  ] })
5001
5068
  ] });
5002
5069
  }
5003
5070
 
5004
5071
  // src/DataTable.tsx
5005
- import { jsx as jsx27, jsxs as jsxs26 } from "react/jsx-runtime";
5072
+ import { jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
5006
5073
  function DataTable({
5007
5074
  collection,
5008
5075
  columns,
@@ -5034,10 +5101,10 @@ function DataTable({
5034
5101
  const [editing, setEditing] = useState27(null);
5035
5102
  const [removeFailed, setRemoveFailed] = useState27(null);
5036
5103
  if (error) {
5037
- return /* @__PURE__ */ jsx27("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx27("div", { className: "b316-error", role: "alert", children: error }) });
5104
+ return /* @__PURE__ */ jsx28("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx28("div", { className: "b316-error", role: "alert", children: error }) });
5038
5105
  }
5039
5106
  if (!schema) {
5040
- return /* @__PURE__ */ jsx27("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5107
+ return /* @__PURE__ */ jsx28("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5041
5108
  }
5042
5109
  const shown = columns ? (
5043
5110
  // Ordered by what was asked for, not by the schema: a caller naming
@@ -5046,10 +5113,10 @@ function DataTable({
5046
5113
  ) : schema.fields;
5047
5114
  const searchable = schema.fields.some((field) => specFor3(field).capabilities.searchable);
5048
5115
  const writable = canWrite && !readOnly;
5049
- return /* @__PURE__ */ jsxs26("div", { className: cls("b316-table-wrap", className), style, children: [
5050
- removeFailed ? /* @__PURE__ */ jsx27("div", { className: "b316-error", role: "alert", children: removeFailed }) : null,
5051
- /* @__PURE__ */ jsxs26("div", { className: "b316-table-bar", children: [
5052
- searchable && !hideSearch ? /* @__PURE__ */ jsx27(
5116
+ return /* @__PURE__ */ jsxs27("div", { className: cls("b316-table-wrap", className), style, children: [
5117
+ removeFailed ? /* @__PURE__ */ jsx28("div", { className: "b316-error", role: "alert", children: removeFailed }) : null,
5118
+ /* @__PURE__ */ jsxs27("div", { className: "b316-table-bar", children: [
5119
+ searchable && !hideSearch ? /* @__PURE__ */ jsx28(
5053
5120
  "input",
5054
5121
  {
5055
5122
  type: "search",
@@ -5059,25 +5126,25 @@ function DataTable({
5059
5126
  value: search,
5060
5127
  onChange: (event) => setSearch(event.target.value)
5061
5128
  }
5062
- ) : /* @__PURE__ */ jsx27("span", {}),
5063
- /* @__PURE__ */ jsxs26("div", { className: "b316-table-actions", children: [
5064
- /* @__PURE__ */ jsxs26("span", { className: "b316-muted", children: [
5129
+ ) : /* @__PURE__ */ jsx28("span", {}),
5130
+ /* @__PURE__ */ jsxs27("div", { className: "b316-table-actions", children: [
5131
+ /* @__PURE__ */ jsxs27("span", { className: "b316-muted", children: [
5065
5132
  total,
5066
5133
  " ",
5067
5134
  total === 1 ? schema.name.toLowerCase() : schema.namePlural.toLowerCase()
5068
5135
  ] }),
5069
- writable ? /* @__PURE__ */ jsxs26("button", { type: "button", className: "b316-button", onClick: () => setEditing("new"), children: [
5136
+ writable ? /* @__PURE__ */ jsxs27("button", { type: "button", className: "b316-button", onClick: () => setEditing("new"), children: [
5070
5137
  "New ",
5071
5138
  schema.name.toLowerCase()
5072
5139
  ] }) : null
5073
5140
  ] })
5074
5141
  ] }),
5075
- /* @__PURE__ */ jsx27("div", { className: "b316-table-scroll", children: /* @__PURE__ */ jsxs26("table", { className: "b316-table", children: [
5076
- /* @__PURE__ */ jsx27("thead", { children: /* @__PURE__ */ jsxs26("tr", { children: [
5142
+ /* @__PURE__ */ jsx28("div", { className: "b316-table-scroll", children: /* @__PURE__ */ jsxs27("table", { className: "b316-table", children: [
5143
+ /* @__PURE__ */ jsx28("thead", { children: /* @__PURE__ */ jsxs27("tr", { children: [
5077
5144
  shown.map((field) => {
5078
5145
  const sortable = specFor3(field).capabilities.sortable;
5079
5146
  const active = sort?.field === field.key;
5080
- return /* @__PURE__ */ jsx27("th", { scope: "col", "aria-sort": ariaSort(active, sort?.direction), children: sortable ? /* @__PURE__ */ jsxs26(
5147
+ return /* @__PURE__ */ jsx28("th", { scope: "col", "aria-sort": ariaSort(active, sort?.direction), children: sortable ? /* @__PURE__ */ jsxs27(
5081
5148
  "button",
5082
5149
  {
5083
5150
  type: "button",
@@ -5085,20 +5152,20 @@ function DataTable({
5085
5152
  onClick: () => toggleSort(field.key),
5086
5153
  children: [
5087
5154
  field.label,
5088
- /* @__PURE__ */ jsx27("span", { "aria-hidden": "true", children: active ? sort?.direction === "desc" ? " \u2193" : " \u2191" : " \u2195" })
5155
+ /* @__PURE__ */ jsx28("span", { "aria-hidden": "true", children: active ? sort?.direction === "desc" ? " \u2193" : " \u2191" : " \u2195" })
5089
5156
  ]
5090
5157
  }
5091
5158
  ) : field.label }, field.key);
5092
5159
  }),
5093
- writable ? /* @__PURE__ */ jsx27("th", { scope: "col", className: "b316-table-rowactions" }) : null
5160
+ writable ? /* @__PURE__ */ jsx28("th", { scope: "col", className: "b316-table-rowactions" }) : null
5094
5161
  ] }) }),
5095
- /* @__PURE__ */ jsx27("tbody", { children: records.map((record) => /* @__PURE__ */ jsxs26(
5162
+ /* @__PURE__ */ jsx28("tbody", { children: records.map((record) => /* @__PURE__ */ jsxs27(
5096
5163
  "tr",
5097
5164
  {
5098
5165
  className: onSelect ? "b316-row-clickable" : void 0,
5099
5166
  onClick: onSelect ? () => onSelect(record) : void 0,
5100
5167
  children: [
5101
- shown.map((field) => /* @__PURE__ */ jsx27("td", { children: renderCell?.(record, field) ?? /* @__PURE__ */ jsx27(
5168
+ shown.map((field) => /* @__PURE__ */ jsx28("td", { children: renderCell?.(record, field) ?? /* @__PURE__ */ jsx28(
5102
5169
  FieldCell,
5103
5170
  {
5104
5171
  value: record.fields[field.key] ?? null,
@@ -5106,8 +5173,8 @@ function DataTable({
5106
5173
  related: record.related[field.key]
5107
5174
  }
5108
5175
  ) }, field.key)),
5109
- writable ? /* @__PURE__ */ jsxs26("td", { className: "b316-table-rowactions", children: [
5110
- /* @__PURE__ */ jsx27(
5176
+ writable ? /* @__PURE__ */ jsxs27("td", { className: "b316-table-rowactions", children: [
5177
+ /* @__PURE__ */ jsx28(
5111
5178
  "button",
5112
5179
  {
5113
5180
  type: "button",
@@ -5119,7 +5186,7 @@ function DataTable({
5119
5186
  children: "Edit"
5120
5187
  }
5121
5188
  ),
5122
- /* @__PURE__ */ jsx27(
5189
+ /* @__PURE__ */ jsx28(
5123
5190
  ConfirmButton,
5124
5191
  {
5125
5192
  className: "b316-button-quiet b316-danger",
@@ -5143,10 +5210,10 @@ function DataTable({
5143
5210
  record.id
5144
5211
  )) })
5145
5212
  ] }) }),
5146
- records.length === 0 && !loading ? /* @__PURE__ */ jsx27("div", { className: "b316-empty", children: emptyState ?? `No ${schema.namePlural.toLowerCase()} yet.` }) : null,
5147
- loading ? /* @__PURE__ */ jsx27("div", { className: "b316-empty", children: "Loading\u2026" }) : null,
5148
- hasMore ? /* @__PURE__ */ jsx27("div", { className: "b316-table-more", children: /* @__PURE__ */ jsx27("button", { type: "button", className: "b316-button-quiet", onClick: loadMore, disabled: loading, children: "Load more" }) }) : null,
5149
- editing ? /* @__PURE__ */ jsx27(
5213
+ records.length === 0 && !loading ? /* @__PURE__ */ jsx28("div", { className: "b316-empty", children: emptyState ?? `No ${schema.namePlural.toLowerCase()} yet.` }) : null,
5214
+ loading ? /* @__PURE__ */ jsx28("div", { className: "b316-empty", children: "Loading\u2026" }) : null,
5215
+ 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,
5216
+ editing ? /* @__PURE__ */ jsx28(
5150
5217
  RecordForm,
5151
5218
  {
5152
5219
  collection,
@@ -5175,7 +5242,7 @@ import {
5175
5242
  titleFieldOf
5176
5243
  } from "@base316/sdk";
5177
5244
  import { useState as useState28 } from "react";
5178
- import { jsx as jsx28, jsxs as jsxs27 } from "react/jsx-runtime";
5245
+ import { jsx as jsx29, jsxs as jsxs28 } from "react/jsx-runtime";
5179
5246
  function Kanban({
5180
5247
  collection,
5181
5248
  groupBy,
@@ -5195,14 +5262,14 @@ function Kanban({
5195
5262
  const [dragging, setDragging] = useState28(null);
5196
5263
  const [over, setOver] = useState28(null);
5197
5264
  if (error) {
5198
- return /* @__PURE__ */ jsx28("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx28("div", { className: "b316-error", role: "alert", children: error }) });
5265
+ return /* @__PURE__ */ jsx29("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx29("div", { className: "b316-error", role: "alert", children: error }) });
5199
5266
  }
5200
5267
  if (!schema) {
5201
- return /* @__PURE__ */ jsx28("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5268
+ return /* @__PURE__ */ jsx29("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5202
5269
  }
5203
5270
  const field = groupBy ? schema.fields.find((candidate) => candidate.key === groupBy) ?? null : defaultGroupFieldOf(schema.fields);
5204
5271
  if (!field || !specFor4(field).capabilities.groupable) {
5205
- return /* @__PURE__ */ jsx28("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.` });
5272
+ 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.` });
5206
5273
  }
5207
5274
  const columns = columnsFor(field);
5208
5275
  const shown = cardFields ? cardFields.map((key) => schema.fields.find((candidate) => candidate.key === key)).filter((candidate) => Boolean(candidate)) : (
@@ -5219,12 +5286,12 @@ function Kanban({
5219
5286
  }
5220
5287
  await update(record.id, { [field.key]: value });
5221
5288
  }
5222
- return /* @__PURE__ */ jsxs27("div", { className: cls("b316-board-wrap", className), style, children: [
5223
- /* @__PURE__ */ jsx28("div", { className: "b316-board", role: "list", children: columns.map((column) => {
5289
+ return /* @__PURE__ */ jsxs28("div", { className: cls("b316-board-wrap", className), style, children: [
5290
+ /* @__PURE__ */ jsx29("div", { className: "b316-board", role: "list", children: columns.map((column) => {
5224
5291
  const inColumn = records.filter(
5225
5292
  (record) => String(record.fields[field.key] ?? "") === String(column.value ?? "")
5226
5293
  );
5227
- return /* @__PURE__ */ jsxs27(
5294
+ return /* @__PURE__ */ jsxs28(
5228
5295
  "section",
5229
5296
  {
5230
5297
  className: over === String(column.value) ? "b316-board-column b316-board-over" : "b316-board-column",
@@ -5248,12 +5315,12 @@ function Kanban({
5248
5315
  setDragging(null);
5249
5316
  },
5250
5317
  children: [
5251
- /* @__PURE__ */ jsxs27("header", { className: "b316-board-head", children: [
5252
- /* @__PURE__ */ jsx28("span", { className: "b316-board-title", children: column.label }),
5253
- /* @__PURE__ */ jsx28("span", { className: "b316-muted", children: inColumn.length })
5318
+ /* @__PURE__ */ jsxs28("header", { className: "b316-board-head", children: [
5319
+ /* @__PURE__ */ jsx29("span", { className: "b316-board-title", children: column.label }),
5320
+ /* @__PURE__ */ jsx29("span", { className: "b316-muted", children: inColumn.length })
5254
5321
  ] }),
5255
- /* @__PURE__ */ jsxs27("div", { className: "b316-board-cards", children: [
5256
- inColumn.map((record) => /* @__PURE__ */ jsxs27(
5322
+ /* @__PURE__ */ jsxs28("div", { className: "b316-board-cards", children: [
5323
+ inColumn.map((record) => /* @__PURE__ */ jsxs28(
5257
5324
  "article",
5258
5325
  {
5259
5326
  className: "b316-board-card",
@@ -5265,10 +5332,10 @@ function Kanban({
5265
5332
  },
5266
5333
  onClick: onSelect ? () => onSelect(record) : void 0,
5267
5334
  children: [
5268
- /* @__PURE__ */ jsx28("div", { className: "b316-board-card-title", children: record.title ?? "Untitled" }),
5269
- shown.map((candidate) => /* @__PURE__ */ jsxs27("div", { className: "b316-board-card-field", children: [
5270
- /* @__PURE__ */ jsx28("span", { className: "b316-muted", children: candidate.label }),
5271
- /* @__PURE__ */ jsx28(
5335
+ /* @__PURE__ */ jsx29("div", { className: "b316-board-card-title", children: record.title ?? "Untitled" }),
5336
+ shown.map((candidate) => /* @__PURE__ */ jsxs28("div", { className: "b316-board-card-field", children: [
5337
+ /* @__PURE__ */ jsx29("span", { className: "b316-muted", children: candidate.label }),
5338
+ /* @__PURE__ */ jsx29(
5272
5339
  FieldCell,
5273
5340
  {
5274
5341
  value: record.fields[candidate.key] ?? null,
@@ -5281,9 +5348,9 @@ function Kanban({
5281
5348
  // Dragging is not reachable by keyboard and is awkward on a
5282
5349
  // phone. This is the same action by other means, not a
5283
5350
  // lesser fallback.
5284
- /* @__PURE__ */ jsxs27("label", { className: "b316-board-move", children: [
5285
- /* @__PURE__ */ jsx28("span", { className: "b316-muted", children: "Move to" }),
5286
- /* @__PURE__ */ jsx28(
5351
+ /* @__PURE__ */ jsxs28("label", { className: "b316-board-move", children: [
5352
+ /* @__PURE__ */ jsx29("span", { className: "b316-muted", children: "Move to" }),
5353
+ /* @__PURE__ */ jsx29(
5287
5354
  "select",
5288
5355
  {
5289
5356
  className: "b316-input",
@@ -5295,7 +5362,7 @@ function Kanban({
5295
5362
  );
5296
5363
  void move(record, chosen?.value ?? null);
5297
5364
  },
5298
- children: columns.map((candidate) => /* @__PURE__ */ jsx28("option", { value: String(candidate.value), children: candidate.label }, String(candidate.value)))
5365
+ children: columns.map((candidate) => /* @__PURE__ */ jsx29("option", { value: String(candidate.value), children: candidate.label }, String(candidate.value)))
5299
5366
  }
5300
5367
  )
5301
5368
  ] })
@@ -5304,14 +5371,14 @@ function Kanban({
5304
5371
  },
5305
5372
  record.id
5306
5373
  )),
5307
- inColumn.length === 0 ? /* @__PURE__ */ jsx28("div", { className: "b316-board-empty", children: emptyState ?? "Nothing here" }) : null
5374
+ inColumn.length === 0 ? /* @__PURE__ */ jsx29("div", { className: "b316-board-empty", children: emptyState ?? "Nothing here" }) : null
5308
5375
  ] })
5309
5376
  ]
5310
5377
  },
5311
5378
  String(column.value)
5312
5379
  );
5313
5380
  }) }),
5314
- hasMore ? /* @__PURE__ */ jsx28("div", { className: "b316-table-more", children: /* @__PURE__ */ jsxs27("button", { type: "button", className: "b316-button-quiet", onClick: loadMore, disabled: loading, children: [
5381
+ hasMore ? /* @__PURE__ */ jsx29("div", { className: "b316-table-more", children: /* @__PURE__ */ jsxs28("button", { type: "button", className: "b316-button-quiet", onClick: loadMore, disabled: loading, children: [
5315
5382
  "Showing ",
5316
5383
  records.length,
5317
5384
  " of ",
@@ -5337,8 +5404,8 @@ import {
5337
5404
  fieldsFor,
5338
5405
  specFor as specFor5
5339
5406
  } from "@base316/sdk";
5340
- import { useMemo as useMemo3 } from "react";
5341
- import { jsx as jsx29, jsxs as jsxs28 } from "react/jsx-runtime";
5407
+ import { useMemo as useMemo4 } from "react";
5408
+ import { jsx as jsx30, jsxs as jsxs29 } from "react/jsx-runtime";
5342
5409
  function Chart({
5343
5410
  collection,
5344
5411
  x,
@@ -5357,7 +5424,7 @@ function Chart({
5357
5424
  limit: options.limit ?? 200,
5358
5425
  ...options
5359
5426
  });
5360
- const axis = useMemo3(() => {
5427
+ const axis = useMemo4(() => {
5361
5428
  if (!schema) {
5362
5429
  return null;
5363
5430
  }
@@ -5365,35 +5432,35 @@ function Chart({
5365
5432
  const chosen = x ? schema.fields.find((field) => field.key === x) ?? null : timeFields[0] ?? null;
5366
5433
  return chosen && specFor5(chosen).capabilities.timeAxis ? chosen : null;
5367
5434
  }, [schema, x]);
5368
- const measure = useMemo3(() => {
5435
+ const measure = useMemo4(() => {
5369
5436
  if (!schema || !y) {
5370
5437
  return null;
5371
5438
  }
5372
5439
  const candidates = fieldsAggregatableBy(schema.fields, aggregate);
5373
5440
  return candidates.find((field) => field.key === y) ?? null;
5374
5441
  }, [schema, y, aggregate]);
5375
- const buckets = useMemo3(
5442
+ const buckets = useMemo4(
5376
5443
  () => axis ? bucketise(records, axis, measure, y ? aggregate : "count", bucket) : [],
5377
5444
  [records, axis, measure, aggregate, bucket, y]
5378
5445
  );
5379
5446
  if (error) {
5380
- return /* @__PURE__ */ jsx29("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx29("div", { className: "b316-error", role: "alert", children: error }) });
5447
+ return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx30("div", { className: "b316-error", role: "alert", children: error }) });
5381
5448
  }
5382
5449
  if (!schema || loading) {
5383
- return /* @__PURE__ */ jsx29("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5450
+ return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5384
5451
  }
5385
5452
  if (!axis) {
5386
- return /* @__PURE__ */ jsx29("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.` });
5453
+ 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.` });
5387
5454
  }
5388
5455
  if (y && !measure) {
5389
- return /* @__PURE__ */ jsx29("div", { className: cls("b316-card", className), style, children: `"${y}" cannot be ${aggregate === "avg" ? "averaged" : `combined with ${aggregate}`}.` });
5456
+ return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: `"${y}" cannot be ${aggregate === "avg" ? "averaged" : `combined with ${aggregate}`}.` });
5390
5457
  }
5391
5458
  const peak = Math.max(...buckets.map((entry) => entry.value), 0);
5392
5459
  const heading = title ?? `${measure ? `${aggregate} of ${measure.label}` : schema.namePlural} by ${axis.label}`;
5393
- return /* @__PURE__ */ jsxs28("figure", { className: cls("b316-card b316-chart", className), style, children: [
5394
- /* @__PURE__ */ jsx29("figcaption", { className: "b316-chart-title", children: heading }),
5395
- buckets.length === 0 || peak === 0 ? /* @__PURE__ */ jsx29("div", { className: "b316-empty", children: "Nothing to chart yet." }) : /* @__PURE__ */ jsx29("div", { className: "b316-chart-plot", style: { height }, children: buckets.map((entry) => /* @__PURE__ */ jsxs28("div", { className: "b316-chart-col", children: [
5396
- /* @__PURE__ */ jsx29(
5460
+ return /* @__PURE__ */ jsxs29("figure", { className: cls("b316-card b316-chart", className), style, children: [
5461
+ /* @__PURE__ */ jsx30("figcaption", { className: "b316-chart-title", children: heading }),
5462
+ 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: [
5463
+ /* @__PURE__ */ jsx30(
5397
5464
  "div",
5398
5465
  {
5399
5466
  className: "b316-chart-bar",
@@ -5401,18 +5468,18 @@ function Chart({
5401
5468
  title: `${entry.label}: ${format(entry.value)}`
5402
5469
  }
5403
5470
  ),
5404
- /* @__PURE__ */ jsx29("span", { className: "b316-chart-label", children: entry.label })
5471
+ /* @__PURE__ */ jsx30("span", { className: "b316-chart-label", children: entry.label })
5405
5472
  ] }, entry.key)) }),
5406
- /* @__PURE__ */ jsxs28("details", { className: "b316-chart-data", children: [
5407
- /* @__PURE__ */ jsx29("summary", { children: "Values" }),
5408
- /* @__PURE__ */ jsxs28("table", { className: "b316-table", children: [
5409
- /* @__PURE__ */ jsx29("thead", { children: /* @__PURE__ */ jsxs28("tr", { children: [
5410
- /* @__PURE__ */ jsx29("th", { scope: "col", children: axis.label }),
5411
- /* @__PURE__ */ jsx29("th", { scope: "col", children: measure ? measure.label : "Count" })
5473
+ /* @__PURE__ */ jsxs29("details", { className: "b316-chart-data", children: [
5474
+ /* @__PURE__ */ jsx30("summary", { children: "Values" }),
5475
+ /* @__PURE__ */ jsxs29("table", { className: "b316-table", children: [
5476
+ /* @__PURE__ */ jsx30("thead", { children: /* @__PURE__ */ jsxs29("tr", { children: [
5477
+ /* @__PURE__ */ jsx30("th", { scope: "col", children: axis.label }),
5478
+ /* @__PURE__ */ jsx30("th", { scope: "col", children: measure ? measure.label : "Count" })
5412
5479
  ] }) }),
5413
- /* @__PURE__ */ jsx29("tbody", { children: buckets.map((entry) => /* @__PURE__ */ jsxs28("tr", { children: [
5414
- /* @__PURE__ */ jsx29("td", { children: entry.label }),
5415
- /* @__PURE__ */ jsx29("td", { children: format(entry.value) })
5480
+ /* @__PURE__ */ jsx30("tbody", { children: buckets.map((entry) => /* @__PURE__ */ jsxs29("tr", { children: [
5481
+ /* @__PURE__ */ jsx30("td", { children: entry.label }),
5482
+ /* @__PURE__ */ jsx30("td", { children: format(entry.value) })
5416
5483
  ] }, entry.key)) })
5417
5484
  ] })
5418
5485
  ] })
@@ -5472,7 +5539,7 @@ function combine(values, aggregate) {
5472
5539
  // src/RecordDetail.tsx
5473
5540
  import { specFor as specFor6 } from "@base316/sdk";
5474
5541
  import { useState as useState29 } from "react";
5475
- import { jsx as jsx30, jsxs as jsxs29 } from "react/jsx-runtime";
5542
+ import { jsx as jsx31, jsxs as jsxs30 } from "react/jsx-runtime";
5476
5543
  function RecordDetail({
5477
5544
  collection,
5478
5545
  recordId,
@@ -5491,20 +5558,20 @@ function RecordDetail({
5491
5558
  const [editing, setEditing] = useState29(false);
5492
5559
  const record = records.find((candidate) => candidate.id === recordId);
5493
5560
  if (error) {
5494
- return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx30("div", { className: "b316-error", role: "alert", children: error }) });
5561
+ return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx31("div", { className: "b316-error", role: "alert", children: error }) });
5495
5562
  }
5496
5563
  if (!schema || loading) {
5497
- return /* @__PURE__ */ jsx30("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5564
+ return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5498
5565
  }
5499
5566
  if (!record) {
5500
- return /* @__PURE__ */ jsxs29("div", { className: cls("b316-card", className), style, children: [
5567
+ return /* @__PURE__ */ jsxs30("div", { className: cls("b316-card", className), style, children: [
5501
5568
  "That ",
5502
5569
  schema.name.toLowerCase(),
5503
5570
  " is not available."
5504
5571
  ] });
5505
5572
  }
5506
5573
  if (editing) {
5507
- return /* @__PURE__ */ jsx30(
5574
+ return /* @__PURE__ */ jsx31(
5508
5575
  RecordForm,
5509
5576
  {
5510
5577
  collection,
@@ -5518,12 +5585,12 @@ function RecordDetail({
5518
5585
  );
5519
5586
  }
5520
5587
  const writable = canWrite && !readOnly;
5521
- return /* @__PURE__ */ jsxs29("div", { className: cls("b316-card b316-detail", className), style, children: [
5522
- /* @__PURE__ */ jsxs29("div", { className: "b316-detail-head", children: [
5523
- /* @__PURE__ */ jsx30("h3", { className: "b316-detail-title", children: record.title ?? schema.name }),
5524
- /* @__PURE__ */ jsxs29("div", { className: "b316-detail-actions", children: [
5525
- writable ? /* @__PURE__ */ jsx30("button", { type: "button", className: "b316-button-quiet", onClick: () => setEditing(true), children: "Edit" }) : null,
5526
- writable ? /* @__PURE__ */ jsx30(
5588
+ return /* @__PURE__ */ jsxs30("div", { className: cls("b316-card b316-detail", className), style, children: [
5589
+ /* @__PURE__ */ jsxs30("div", { className: "b316-detail-head", children: [
5590
+ /* @__PURE__ */ jsx31("h3", { className: "b316-detail-title", children: record.title ?? schema.name }),
5591
+ /* @__PURE__ */ jsxs30("div", { className: "b316-detail-actions", children: [
5592
+ writable ? /* @__PURE__ */ jsx31("button", { type: "button", className: "b316-button-quiet", onClick: () => setEditing(true), children: "Edit" }) : null,
5593
+ writable ? /* @__PURE__ */ jsx31(
5527
5594
  ConfirmButton,
5528
5595
  {
5529
5596
  className: "b316-button-quiet b316-danger",
@@ -5536,15 +5603,15 @@ function RecordDetail({
5536
5603
  children: "Delete"
5537
5604
  }
5538
5605
  ) : null,
5539
- onClose ? /* @__PURE__ */ jsx30("button", { type: "button", className: "b316-button-quiet", onClick: onClose, children: "Close" }) : null
5606
+ onClose ? /* @__PURE__ */ jsx31("button", { type: "button", className: "b316-button-quiet", onClick: onClose, children: "Close" }) : null
5540
5607
  ] })
5541
5608
  ] }),
5542
- /* @__PURE__ */ jsx30("dl", { className: "b316-detail-fields", children: schema.fields.map((field) => /* @__PURE__ */ jsxs29("div", { className: "b316-detail-row", children: [
5543
- /* @__PURE__ */ jsxs29("dt", { className: "b316-label", children: [
5609
+ /* @__PURE__ */ jsx31("dl", { className: "b316-detail-fields", children: schema.fields.map((field) => /* @__PURE__ */ jsxs30("div", { className: "b316-detail-row", children: [
5610
+ /* @__PURE__ */ jsxs30("dt", { className: "b316-label", children: [
5544
5611
  field.label,
5545
- specFor6(field).computed ? /* @__PURE__ */ jsx30("span", { className: "b316-muted", children: " (calculated)" }) : null
5612
+ specFor6(field).computed ? /* @__PURE__ */ jsx31("span", { className: "b316-muted", children: " (calculated)" }) : null
5546
5613
  ] }),
5547
- /* @__PURE__ */ jsx30("dd", { children: /* @__PURE__ */ jsx30(
5614
+ /* @__PURE__ */ jsx31("dd", { children: /* @__PURE__ */ jsx31(
5548
5615
  FieldCell,
5549
5616
  {
5550
5617
  value: record.fields[field.key] ?? null,
@@ -5559,11 +5626,40 @@ function RecordDetail({
5559
5626
 
5560
5627
  // src/SubscriptionManager.tsx
5561
5628
  import { useCallback as useCallback10, useEffect as useEffect22, useState as useState30 } from "react";
5562
- import { jsx as jsx31, jsxs as jsxs30 } from "react/jsx-runtime";
5629
+ import { jsx as jsx32, jsxs as jsxs31 } from "react/jsx-runtime";
5563
5630
  function statusLabel(status2) {
5564
5631
  const words = status2.toLowerCase().split("_");
5565
5632
  return words.map((w, i) => i === 0 ? w.charAt(0).toUpperCase() + w.slice(1) : w).join(" ");
5566
5633
  }
5634
+ var REASONS = [
5635
+ { value: "TOO_EXPENSIVE", label: "It costs too much" },
5636
+ { value: "NOT_USING", label: "I am not using it enough" },
5637
+ { value: "MISSING_FEATURES", label: "It is missing something I need" },
5638
+ { value: "SWITCHING", label: "I am switching to something else" },
5639
+ { value: "TECHNICAL_ISSUES", label: "It did not work well for me" },
5640
+ { value: "TEMPORARY", label: "I only needed it for a while" },
5641
+ { value: "OTHER", label: "Something else" }
5642
+ ];
5643
+ function describeRetentionOffer(offer, currency) {
5644
+ let amount;
5645
+ if (offer.type === "PERCENTAGE") {
5646
+ amount = `${Number(offer.percentOff ?? "0")}% off`;
5647
+ } else {
5648
+ try {
5649
+ amount = `${new Intl.NumberFormat(void 0, {
5650
+ style: "currency",
5651
+ currency: offer.currency ?? currency
5652
+ }).format(Number(offer.amountOff ?? "0"))} off`;
5653
+ } catch {
5654
+ amount = `${offer.amountOff} ${offer.currency ?? currency} off`;
5655
+ }
5656
+ }
5657
+ if (offer.duration === "FOREVER") {
5658
+ return `${amount} for as long as you stay subscribed`;
5659
+ }
5660
+ const periods = offer.duration === "ONCE" ? 1 : offer.durationInPeriods ?? 1;
5661
+ return periods === 1 ? `${amount} your next invoice` : `${amount} your next ${periods} invoices`;
5662
+ }
5567
5663
  function SubscriptionManager({
5568
5664
  onChange,
5569
5665
  className,
@@ -5576,6 +5672,9 @@ function SubscriptionManager({
5576
5672
  const [schedule, setSchedule] = useState30([]);
5577
5673
  const [busy, setBusy] = useState30(false);
5578
5674
  const [error, setError] = useState30(null);
5675
+ const [step, setStep] = useState30({ kind: "idle" });
5676
+ const [reason, setReason] = useState30(null);
5677
+ const [comment, setComment] = useState30("");
5579
5678
  const load = useCallback10(async () => {
5580
5679
  if (!token) {
5581
5680
  setSubscription(null);
@@ -5612,29 +5711,29 @@ function SubscriptionManager({
5612
5711
  }
5613
5712
  };
5614
5713
  if (sessionLoading || loading) {
5615
- return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5714
+ return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
5616
5715
  }
5617
5716
  if (!token) {
5618
- return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: "Sign in to manage your subscription." });
5717
+ return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: "Sign in to manage your subscription." });
5619
5718
  }
5620
5719
  if (error) {
5621
- return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx31("div", { className: "b316-error", role: "alert", children: error }) });
5720
+ return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx32("div", { className: "b316-error", role: "alert", children: error }) });
5622
5721
  }
5623
5722
  if (!subscription) {
5624
- return /* @__PURE__ */ jsx31("div", { className: cls("b316-card", className), style, children: "You are not subscribed to a plan." });
5723
+ return /* @__PURE__ */ jsx32("div", { className: cls("b316-card", className), style, children: "You are not subscribed to a plan." });
5625
5724
  }
5626
5725
  const renews = new Date(subscription.currentPeriodEnd).toLocaleDateString();
5627
5726
  const next = schedule[0] ?? null;
5628
5727
  const nextOn = next?.effectiveAt ? new Date(next.effectiveAt).toLocaleDateString() : renews;
5629
- return /* @__PURE__ */ jsxs30("div", { className: cls("b316-card", className), style, children: [
5630
- error ? /* @__PURE__ */ jsx31("div", { className: "b316-error", role: "alert", children: error }) : null,
5631
- /* @__PURE__ */ jsx31("div", { className: "b316-plan-name", children: subscription.planVersion.plan.name }),
5632
- /* @__PURE__ */ jsxs30("div", { className: "b316-muted", children: [
5728
+ return /* @__PURE__ */ jsxs31("div", { className: cls("b316-card", className), style, children: [
5729
+ error ? /* @__PURE__ */ jsx32("div", { className: "b316-error", role: "alert", children: error }) : null,
5730
+ /* @__PURE__ */ jsx32("div", { className: "b316-plan-name", children: subscription.planVersion.plan.name }),
5731
+ /* @__PURE__ */ jsxs31("div", { className: "b316-muted", children: [
5633
5732
  statusLabel(subscription.status),
5634
5733
  " \xB7 ",
5635
5734
  subscription.cancelAtPeriodEnd ? `Ends ${renews}` : `Renews ${renews}`
5636
5735
  ] }),
5637
- next && !managedBy ? /* @__PURE__ */ jsxs30("div", { className: "b316-muted", role: "status", style: { marginTop: 10 }, children: [
5736
+ next && !managedBy ? /* @__PURE__ */ jsxs31("div", { className: "b316-muted", role: "status", style: { marginTop: 10 }, children: [
5638
5737
  "Moves to ",
5639
5738
  next.plan.name,
5640
5739
  " on ",
@@ -5642,7 +5741,7 @@ function SubscriptionManager({
5642
5741
  ". You keep ",
5643
5742
  subscription.planVersion.plan.name,
5644
5743
  " until then.",
5645
- /* @__PURE__ */ jsx31("div", { children: /* @__PURE__ */ jsx31(
5744
+ /* @__PURE__ */ jsx32("div", { children: /* @__PURE__ */ jsx32(
5646
5745
  "button",
5647
5746
  {
5648
5747
  type: "button",
@@ -5667,17 +5766,17 @@ function SubscriptionManager({
5667
5766
  }
5668
5767
  ) })
5669
5768
  ] }) : null,
5670
- managedBy ? /* @__PURE__ */ jsxs30("p", { className: "b316-muted", children: [
5769
+ managedBy ? /* @__PURE__ */ jsxs31("p", { className: "b316-muted", children: [
5671
5770
  "Provided by ",
5672
5771
  managedBy.name ?? "the organization that manages your account",
5673
5772
  ". Ask them to change or cancel it."
5674
- ] }) : subscription.cancelAtPeriodEnd ? /* @__PURE__ */ jsxs30("div", { children: [
5675
- /* @__PURE__ */ jsxs30("p", { className: "b316-muted", children: [
5773
+ ] }) : subscription.cancelAtPeriodEnd ? /* @__PURE__ */ jsxs31("div", { children: [
5774
+ /* @__PURE__ */ jsxs31("p", { className: "b316-muted", children: [
5676
5775
  "This subscription will not renew. You keep access until ",
5677
5776
  renews,
5678
5777
  "."
5679
5778
  ] }),
5680
- /* @__PURE__ */ jsx31(
5779
+ /* @__PURE__ */ jsx32(
5681
5780
  "button",
5682
5781
  {
5683
5782
  type: "button",
@@ -5687,18 +5786,129 @@ function SubscriptionManager({
5687
5786
  children: busy ? "Working\u2026" : "Resume subscription"
5688
5787
  }
5689
5788
  )
5690
- ] }) : /* @__PURE__ */ jsx31("div", { style: { marginTop: 14 }, children: /* @__PURE__ */ jsx31(
5691
- ConfirmButton,
5789
+ ] }) : step.kind === "offer" ? /* @__PURE__ */ jsxs31("section", { style: { marginTop: 14 }, "aria-label": "Retention offer", children: [
5790
+ /* @__PURE__ */ jsx32("div", { className: "b316-plan-name", children: step.cancellation.offer.headline ?? "Before you go" }),
5791
+ /* @__PURE__ */ jsx32("p", { className: "b316-muted", children: step.cancellation.offer.message ?? `Stay on ${subscription.planVersion.plan.name} and get ${describeRetentionOffer(
5792
+ step.cancellation.offer,
5793
+ step.cancellation.currency
5794
+ )}.` }),
5795
+ /* @__PURE__ */ jsxs31("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
5796
+ /* @__PURE__ */ jsx32(
5797
+ "button",
5798
+ {
5799
+ type: "button",
5800
+ className: "b316-button",
5801
+ disabled: busy,
5802
+ onClick: () => void act(async () => {
5803
+ await client.billing.acceptRetentionOffer(token, step.cancellation.id);
5804
+ setStep({ kind: "idle" });
5805
+ }, "Could not apply the offer. Try again."),
5806
+ children: busy ? "Working\u2026" : "Accept offer and stay"
5807
+ }
5808
+ ),
5809
+ /* @__PURE__ */ jsx32(
5810
+ "button",
5811
+ {
5812
+ type: "button",
5813
+ className: "b316-button b316-button-secondary",
5814
+ disabled: busy,
5815
+ onClick: () => void act(async () => {
5816
+ await client.billing.confirmCancellation(token, step.cancellation.id);
5817
+ setStep({ kind: "idle" });
5818
+ }, "Could not cancel. Try again."),
5819
+ children: "No thanks, cancel"
5820
+ }
5821
+ )
5822
+ ] }),
5823
+ /* @__PURE__ */ jsxs31("p", { className: "b316-muted", children: [
5824
+ "If you cancel, you keep access until ",
5825
+ renews,
5826
+ "."
5827
+ ] })
5828
+ ] }) : step.kind === "survey" ? /* @__PURE__ */ jsxs31(
5829
+ "form",
5830
+ {
5831
+ style: { marginTop: 14 },
5832
+ onSubmit: (event) => {
5833
+ event.preventDefault();
5834
+ void act(async () => {
5835
+ const started = await client.billing.startCancellation(token, {
5836
+ reason,
5837
+ comment: comment.trim() || null
5838
+ });
5839
+ if (started.offer) {
5840
+ setStep({ kind: "offer", cancellation: { ...started, offer: started.offer } });
5841
+ return;
5842
+ }
5843
+ await client.billing.confirmCancellation(token, started.id);
5844
+ setStep({ kind: "idle" });
5845
+ }, "Could not cancel. Try again.");
5846
+ },
5847
+ children: [
5848
+ /* @__PURE__ */ jsxs31("p", { className: "b316-muted", children: [
5849
+ "You keep access until ",
5850
+ renews,
5851
+ ". It will not renew after that."
5852
+ ] }),
5853
+ /* @__PURE__ */ jsxs31("fieldset", { className: "b316-fieldset", children: [
5854
+ /* @__PURE__ */ jsx32("legend", { className: "b316-label", children: "Why are you leaving? (optional)" }),
5855
+ REASONS.map((option) => /* @__PURE__ */ jsxs31("label", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
5856
+ /* @__PURE__ */ jsx32(
5857
+ "input",
5858
+ {
5859
+ type: "radio",
5860
+ name: "b316-cancel-reason",
5861
+ value: option.value,
5862
+ checked: reason === option.value,
5863
+ onChange: () => setReason(option.value)
5864
+ }
5865
+ ),
5866
+ /* @__PURE__ */ jsx32("span", { children: option.label })
5867
+ ] }, option.value))
5868
+ ] }),
5869
+ /* @__PURE__ */ jsxs31("label", { className: "b316-field", children: [
5870
+ /* @__PURE__ */ jsx32("span", { className: "b316-label", children: "Anything else? (optional)" }),
5871
+ /* @__PURE__ */ jsx32(
5872
+ "textarea",
5873
+ {
5874
+ className: "b316-input",
5875
+ rows: 3,
5876
+ maxLength: 2e3,
5877
+ value: comment,
5878
+ onChange: (event) => setComment(event.target.value)
5879
+ }
5880
+ )
5881
+ ] }),
5882
+ /* @__PURE__ */ jsxs31("div", { style: { display: "flex", gap: 8, flexWrap: "wrap" }, children: [
5883
+ /* @__PURE__ */ jsx32("button", { type: "submit", className: "b316-button b316-button-secondary", disabled: busy, children: busy ? "Working\u2026" : "Cancel subscription" }),
5884
+ /* @__PURE__ */ jsxs31(
5885
+ "button",
5886
+ {
5887
+ type: "button",
5888
+ className: "b316-button",
5889
+ disabled: busy,
5890
+ onClick: () => setStep({ kind: "idle" }),
5891
+ children: [
5892
+ "Keep ",
5893
+ subscription.planVersion.plan.name
5894
+ ]
5895
+ }
5896
+ )
5897
+ ] })
5898
+ ]
5899
+ }
5900
+ ) : /* @__PURE__ */ jsx32("div", { style: { marginTop: 14 }, children: /* @__PURE__ */ jsx32(
5901
+ "button",
5692
5902
  {
5903
+ type: "button",
5693
5904
  className: "b316-button b316-button-secondary",
5694
- confirmLabel: `Cancel at the end of the period (${renews})`,
5695
5905
  disabled: busy,
5696
- onConfirm: () => (
5697
- // Cancels at period end: the user paid for the period they
5698
- // are in, and ending it now would forfeit it.
5699
- act(() => client.billing.cancel(token), "Could not cancel. Try again.")
5700
- ),
5701
- children: busy ? "Working\u2026" : "Cancel subscription"
5906
+ onClick: () => {
5907
+ setReason(null);
5908
+ setComment("");
5909
+ setStep({ kind: "survey" });
5910
+ },
5911
+ children: "Cancel subscription"
5702
5912
  }
5703
5913
  ) })
5704
5914
  ] });
@@ -5709,7 +5919,7 @@ import { useCallback as useCallback12, useEffect as useEffect26, useState as use
5709
5919
 
5710
5920
  // src/CreditBalances.tsx
5711
5921
  import { useEffect as useEffect23, useState as useState31 } from "react";
5712
- import { Fragment as Fragment9, jsx as jsx32, jsxs as jsxs31 } from "react/jsx-runtime";
5922
+ import { Fragment as Fragment9, jsx as jsx33, jsxs as jsxs32 } from "react/jsx-runtime";
5713
5923
  function units(value) {
5714
5924
  return value === null ? "Unlimited" : Number(value).toLocaleString("en");
5715
5925
  }
@@ -5801,33 +6011,33 @@ function Feature({
5801
6011
  setBusy(false);
5802
6012
  }
5803
6013
  };
5804
- return /* @__PURE__ */ jsxs31("div", { className: "b316-card b316-credit-balance", children: [
5805
- /* @__PURE__ */ jsx32("div", { className: "b316-label", children: feature.featureName }),
5806
- /* @__PURE__ */ jsxs31("div", { children: [
5807
- /* @__PURE__ */ jsx32("strong", { children: units(feature.remaining) }),
6014
+ return /* @__PURE__ */ jsxs32("div", { className: "b316-card b316-credit-balance", children: [
6015
+ /* @__PURE__ */ jsx33("div", { className: "b316-label", children: feature.featureName }),
6016
+ /* @__PURE__ */ jsxs32("div", { children: [
6017
+ /* @__PURE__ */ jsx33("strong", { children: units(feature.remaining) }),
5808
6018
  unit,
5809
6019
  " left"
5810
6020
  ] }),
5811
- /* @__PURE__ */ jsxs31("div", { className: "b316-muted", children: [
6021
+ /* @__PURE__ */ jsxs32("div", { className: "b316-muted", children: [
5812
6022
  feature.allowance === null ? "Unlimited allowance" : `${units(feature.allowanceRemaining)} of ${units(feature.allowance)} included this period`,
5813
6023
  " ",
5814
6024
  "\xB7 ",
5815
6025
  units(feature.purchasedRemaining),
5816
6026
  " purchased"
5817
6027
  ] }),
5818
- warning && !managed ? /* @__PURE__ */ jsx32("div", { className: "b316-error", role: "alert", children: warning }) : null,
5819
- error ? /* @__PURE__ */ jsx32("div", { className: "b316-error", role: "alert", children: error }) : null,
5820
- saved ? /* @__PURE__ */ jsx32("div", { className: "b316-notice", role: "status", children: saved }) : null,
5821
- managed || feature.packs.length === 0 ? null : /* @__PURE__ */ jsxs31(Fragment9, { children: [
5822
- /* @__PURE__ */ jsxs31("div", { className: "b316-row", style: { marginTop: 12 }, children: [
5823
- /* @__PURE__ */ jsx32(
6028
+ warning && !managed ? /* @__PURE__ */ jsx33("div", { className: "b316-error", role: "alert", children: warning }) : null,
6029
+ error ? /* @__PURE__ */ jsx33("div", { className: "b316-error", role: "alert", children: error }) : null,
6030
+ saved ? /* @__PURE__ */ jsx33("div", { className: "b316-notice", role: "status", children: saved }) : null,
6031
+ managed || feature.packs.length === 0 ? null : /* @__PURE__ */ jsxs32(Fragment9, { children: [
6032
+ /* @__PURE__ */ jsxs32("div", { className: "b316-row", style: { marginTop: 12 }, children: [
6033
+ /* @__PURE__ */ jsx33(
5824
6034
  "select",
5825
6035
  {
5826
6036
  className: "b316-input",
5827
6037
  "aria-label": "Pack to buy",
5828
6038
  value: pack,
5829
6039
  onChange: (event) => setPack(event.target.value),
5830
- children: feature.packs.map((option) => /* @__PURE__ */ jsxs31("option", { value: option.id, children: [
6040
+ children: feature.packs.map((option) => /* @__PURE__ */ jsxs32("option", { value: option.id, children: [
5831
6041
  option.name,
5832
6042
  " \u2014 ",
5833
6043
  units(option.units),
@@ -5836,7 +6046,7 @@ function Feature({
5836
6046
  ] }, option.id))
5837
6047
  }
5838
6048
  ),
5839
- /* @__PURE__ */ jsx32(
6049
+ /* @__PURE__ */ jsx33(
5840
6050
  "button",
5841
6051
  {
5842
6052
  type: "button",
@@ -5847,19 +6057,19 @@ function Feature({
5847
6057
  }
5848
6058
  )
5849
6059
  ] }),
5850
- /* @__PURE__ */ jsxs31("form", { onSubmit: save, style: { marginTop: 16 }, children: [
5851
- /* @__PURE__ */ jsxs31("label", { className: "b316-checkbox", children: [
5852
- /* @__PURE__ */ jsx32("input", { type: "checkbox", name: "enabled", defaultChecked: setting?.enabled ?? false }),
6060
+ /* @__PURE__ */ jsxs32("form", { onSubmit: save, style: { marginTop: 16 }, children: [
6061
+ /* @__PURE__ */ jsxs32("label", { className: "b316-checkbox", children: [
6062
+ /* @__PURE__ */ jsx33("input", { type: "checkbox", name: "enabled", defaultChecked: setting?.enabled ?? false }),
5853
6063
  " ",
5854
6064
  "Buy credits automatically when my balance runs low"
5855
6065
  ] }),
5856
- /* @__PURE__ */ jsxs31("label", { className: "b316-field", children: [
5857
- /* @__PURE__ */ jsxs31("span", { className: "b316-label", children: [
6066
+ /* @__PURE__ */ jsxs32("label", { className: "b316-field", children: [
6067
+ /* @__PURE__ */ jsxs32("span", { className: "b316-label", children: [
5858
6068
  "When fewer than this many",
5859
6069
  unit,
5860
6070
  " are left"
5861
6071
  ] }),
5862
- /* @__PURE__ */ jsx32(
6072
+ /* @__PURE__ */ jsx33(
5863
6073
  "input",
5864
6074
  {
5865
6075
  className: "b316-input",
@@ -5870,21 +6080,21 @@ function Feature({
5870
6080
  }
5871
6081
  )
5872
6082
  ] }),
5873
- /* @__PURE__ */ jsxs31("label", { className: "b316-field", children: [
5874
- /* @__PURE__ */ jsx32("span", { className: "b316-label", children: "Buy" }),
5875
- /* @__PURE__ */ jsx32(
6083
+ /* @__PURE__ */ jsxs32("label", { className: "b316-field", children: [
6084
+ /* @__PURE__ */ jsx33("span", { className: "b316-label", children: "Buy" }),
6085
+ /* @__PURE__ */ jsx33(
5876
6086
  "select",
5877
6087
  {
5878
6088
  className: "b316-input",
5879
6089
  name: "creditPackId",
5880
6090
  defaultValue: setting?.creditPackId ?? feature.packs[0]?.id,
5881
- children: feature.packs.map((option) => /* @__PURE__ */ jsx32("option", { value: option.id, children: option.name }, option.id))
6091
+ children: feature.packs.map((option) => /* @__PURE__ */ jsx33("option", { value: option.id, children: option.name }, option.id))
5882
6092
  }
5883
6093
  )
5884
6094
  ] }),
5885
- /* @__PURE__ */ jsxs31("label", { className: "b316-field", children: [
5886
- /* @__PURE__ */ jsx32("span", { className: "b316-label", children: "At most this many times a month" }),
5887
- /* @__PURE__ */ jsx32(
6095
+ /* @__PURE__ */ jsxs32("label", { className: "b316-field", children: [
6096
+ /* @__PURE__ */ jsx33("span", { className: "b316-label", children: "At most this many times a month" }),
6097
+ /* @__PURE__ */ jsx33(
5888
6098
  "input",
5889
6099
  {
5890
6100
  className: "b316-input",
@@ -5894,13 +6104,13 @@ function Feature({
5894
6104
  }
5895
6105
  )
5896
6106
  ] }),
5897
- /* @__PURE__ */ jsxs31("label", { className: "b316-field", children: [
5898
- /* @__PURE__ */ jsxs31("span", { className: "b316-label", children: [
6107
+ /* @__PURE__ */ jsxs32("label", { className: "b316-field", children: [
6108
+ /* @__PURE__ */ jsxs32("span", { className: "b316-label", children: [
5899
6109
  "Spending at most (",
5900
6110
  setting?.currency ?? feature.packs[0]?.currency ?? "USD",
5901
6111
  ") a month"
5902
6112
  ] }),
5903
- /* @__PURE__ */ jsx32(
6113
+ /* @__PURE__ */ jsx33(
5904
6114
  "input",
5905
6115
  {
5906
6116
  className: "b316-input",
@@ -5910,7 +6120,7 @@ function Feature({
5910
6120
  }
5911
6121
  )
5912
6122
  ] }),
5913
- /* @__PURE__ */ jsx32("button", { type: "submit", className: "b316-button", disabled: busy, children: "Save auto-recharge" })
6123
+ /* @__PURE__ */ jsx33("button", { type: "submit", className: "b316-button", disabled: busy, children: "Save auto-recharge" })
5914
6124
  ] })
5915
6125
  ] })
5916
6126
  ] });
@@ -5932,24 +6142,24 @@ function CreditBalances({ onChange, className, style }) {
5932
6142
  cancelled = true;
5933
6143
  };
5934
6144
  }, [client, token, version]);
5935
- const wrap = (content) => /* @__PURE__ */ jsx32("div", { className: cls("b316-credit-balances", className), style, children: content });
6145
+ const wrap = (content) => /* @__PURE__ */ jsx33("div", { className: cls("b316-credit-balances", className), style, children: content });
5936
6146
  if (sessionLoading || !token || state.kind === "loading") return null;
5937
6147
  if (state.kind === "error") {
5938
6148
  return wrap(
5939
- /* @__PURE__ */ jsx32("div", { className: "b316-card", children: /* @__PURE__ */ jsx32("div", { className: "b316-error", role: "alert", children: "Could not load your credits." }) })
6149
+ /* @__PURE__ */ jsx33("div", { className: "b316-card", children: /* @__PURE__ */ jsx33("div", { className: "b316-error", role: "alert", children: "Could not load your credits." }) })
5940
6150
  );
5941
6151
  }
5942
6152
  const { credits } = state;
5943
6153
  if (credits.features.length === 0) return null;
5944
6154
  return wrap(
5945
- /* @__PURE__ */ jsxs31(Fragment9, { children: [
5946
- credits.managedBy ? /* @__PURE__ */ jsxs31("p", { className: "b316-muted", children: [
6155
+ /* @__PURE__ */ jsxs32(Fragment9, { children: [
6156
+ credits.managedBy ? /* @__PURE__ */ jsxs32("p", { className: "b316-muted", children: [
5947
6157
  "Credits for this account come from",
5948
6158
  " ",
5949
6159
  credits.managedBy.name ?? "the organization that manages it",
5950
6160
  ", which manages them."
5951
6161
  ] }) : null,
5952
- credits.features.map((feature) => /* @__PURE__ */ jsx32(
6162
+ credits.features.map((feature) => /* @__PURE__ */ jsx33(
5953
6163
  Feature,
5954
6164
  {
5955
6165
  feature,
@@ -5967,7 +6177,7 @@ function CreditBalances({ onChange, className, style }) {
5967
6177
 
5968
6178
  // src/PaymentMethod.tsx
5969
6179
  import { useEffect as useEffect24, useState as useState32 } from "react";
5970
- import { Fragment as Fragment10, jsx as jsx33, jsxs as jsxs32 } from "react/jsx-runtime";
6180
+ import { Fragment as Fragment10, jsx as jsx34, jsxs as jsxs33 } from "react/jsx-runtime";
5971
6181
  function brandName(brand) {
5972
6182
  if (!brand) return "Card";
5973
6183
  return brand.charAt(0).toUpperCase() + brand.slice(1);
@@ -5994,7 +6204,7 @@ function PaymentMethod({ returnUrl, className, style }) {
5994
6204
  cancelled = true;
5995
6205
  };
5996
6206
  }, [client, token, version]);
5997
- const wrap = (content) => /* @__PURE__ */ jsx33("div", { className: cls("b316-card b316-payment-method", className), style, children: content });
6207
+ const wrap = (content) => /* @__PURE__ */ jsx34("div", { className: cls("b316-card b316-payment-method", className), style, children: content });
5998
6208
  if (sessionLoading) return wrap("Loading\u2026");
5999
6209
  if (!token) return wrap("Sign in to manage your payment method.");
6000
6210
  switch (state.kind) {
@@ -6002,11 +6212,11 @@ function PaymentMethod({ returnUrl, className, style }) {
6002
6212
  return wrap("Loading\u2026");
6003
6213
  case "error":
6004
6214
  return wrap(
6005
- /* @__PURE__ */ jsx33("div", { className: "b316-error", role: "alert", children: "Could not load your payment method." })
6215
+ /* @__PURE__ */ jsx34("div", { className: "b316-error", role: "alert", children: "Could not load your payment method." })
6006
6216
  );
6007
6217
  case "managed":
6008
6218
  return wrap(
6009
- /* @__PURE__ */ jsx33("p", { className: "b316-muted", children: "Your plan is paid for by the organization that manages it." })
6219
+ /* @__PURE__ */ jsx34("p", { className: "b316-muted", children: "Your plan is paid for by the organization that manages it." })
6010
6220
  );
6011
6221
  }
6012
6222
  const card = state.cards.find((saved) => saved.isDefault) ?? null;
@@ -6025,31 +6235,31 @@ function PaymentMethod({ returnUrl, className, style }) {
6025
6235
  }
6026
6236
  };
6027
6237
  return wrap(
6028
- /* @__PURE__ */ jsxs32(Fragment10, { children: [
6029
- /* @__PURE__ */ jsx33("div", { className: "b316-label", children: "Payment method" }),
6030
- card ? /* @__PURE__ */ jsxs32("div", { children: [
6031
- /* @__PURE__ */ jsxs32("div", { children: [
6238
+ /* @__PURE__ */ jsxs33(Fragment10, { children: [
6239
+ /* @__PURE__ */ jsx34("div", { className: "b316-label", children: "Payment method" }),
6240
+ card ? /* @__PURE__ */ jsxs33("div", { children: [
6241
+ /* @__PURE__ */ jsxs33("div", { children: [
6032
6242
  brandName(card.brand),
6033
6243
  " ending ",
6034
6244
  card.last4 ?? "????"
6035
6245
  ] }),
6036
- card.expMonth && card.expYear ? /* @__PURE__ */ jsxs32("div", { className: "b316-muted", children: [
6246
+ card.expMonth && card.expYear ? /* @__PURE__ */ jsxs33("div", { className: "b316-muted", children: [
6037
6247
  "Expires ",
6038
6248
  String(card.expMonth).padStart(2, "0"),
6039
6249
  "/",
6040
6250
  card.expYear
6041
6251
  ] }) : null
6042
- ] }) : /* @__PURE__ */ jsx33("p", { className: "b316-muted", children: "No card on file." }),
6043
- others.length > 0 ? /* @__PURE__ */ jsxs32("div", { style: { marginTop: 12 }, children: [
6044
- /* @__PURE__ */ jsx33("div", { className: "b316-label", children: "Other saved cards" }),
6045
- others.map((saved) => /* @__PURE__ */ jsxs32("div", { className: "b316-row", style: { marginTop: 6 }, children: [
6046
- /* @__PURE__ */ jsxs32("span", { children: [
6252
+ ] }) : /* @__PURE__ */ jsx34("p", { className: "b316-muted", children: "No card on file." }),
6253
+ others.length > 0 ? /* @__PURE__ */ jsxs33("div", { style: { marginTop: 12 }, children: [
6254
+ /* @__PURE__ */ jsx34("div", { className: "b316-label", children: "Other saved cards" }),
6255
+ others.map((saved) => /* @__PURE__ */ jsxs33("div", { className: "b316-row", style: { marginTop: 6 }, children: [
6256
+ /* @__PURE__ */ jsxs33("span", { children: [
6047
6257
  brandName(saved.brand),
6048
6258
  " ending ",
6049
6259
  saved.last4 ?? "????"
6050
6260
  ] }),
6051
- /* @__PURE__ */ jsxs32("span", { children: [
6052
- /* @__PURE__ */ jsx33(
6261
+ /* @__PURE__ */ jsxs33("span", { children: [
6262
+ /* @__PURE__ */ jsx34(
6053
6263
  "button",
6054
6264
  {
6055
6265
  type: "button",
@@ -6063,7 +6273,7 @@ function PaymentMethod({ returnUrl, className, style }) {
6063
6273
  }
6064
6274
  ),
6065
6275
  " ",
6066
- /* @__PURE__ */ jsx33(
6276
+ /* @__PURE__ */ jsx34(
6067
6277
  "button",
6068
6278
  {
6069
6279
  type: "button",
@@ -6079,8 +6289,8 @@ function PaymentMethod({ returnUrl, className, style }) {
6079
6289
  ] })
6080
6290
  ] }, saved.id))
6081
6291
  ] }) : null,
6082
- error ? /* @__PURE__ */ jsx33("div", { className: "b316-error", role: "alert", children: error }) : null,
6083
- /* @__PURE__ */ jsx33(
6292
+ error ? /* @__PURE__ */ jsx34("div", { className: "b316-error", role: "alert", children: error }) : null,
6293
+ /* @__PURE__ */ jsx34(
6084
6294
  "button",
6085
6295
  {
6086
6296
  type: "button",
@@ -6110,7 +6320,7 @@ function PaymentMethod({ returnUrl, className, style }) {
6110
6320
 
6111
6321
  // src/PlanChangeReview.tsx
6112
6322
  import { useCallback as useCallback11, useEffect as useEffect25, useState as useState33 } from "react";
6113
- import { Fragment as Fragment11, jsx as jsx34, jsxs as jsxs33 } from "react/jsx-runtime";
6323
+ import { Fragment as Fragment11, jsx as jsx35, jsxs as jsxs34 } from "react/jsx-runtime";
6114
6324
  function money5(amount, currency) {
6115
6325
  if (amount === null) return "\u2014";
6116
6326
  const value = Number(amount);
@@ -6200,12 +6410,12 @@ function PlanChangeReview({
6200
6410
  setError("Cards cannot be added here right now.");
6201
6411
  }
6202
6412
  }, [client, token, onNeedsCard]);
6203
- const card = (content) => /* @__PURE__ */ jsx34("div", { className: cls("b316-card b316-plan-review", className), style, children: content });
6413
+ const card = (content) => /* @__PURE__ */ jsx35("div", { className: cls("b316-card b316-plan-review", className), style, children: content });
6204
6414
  if (error && !preview) {
6205
6415
  return card(
6206
- /* @__PURE__ */ jsxs33(Fragment11, { children: [
6207
- /* @__PURE__ */ jsx34("div", { className: "b316-error", role: "alert", children: error }),
6208
- onCancel ? /* @__PURE__ */ jsx34("button", { type: "button", className: "b316-button b316-button-secondary", onClick: onCancel, children: "Back" }) : null
6416
+ /* @__PURE__ */ jsxs34(Fragment11, { children: [
6417
+ /* @__PURE__ */ jsx35("div", { className: "b316-error", role: "alert", children: error }),
6418
+ onCancel ? /* @__PURE__ */ jsx35("button", { type: "button", className: "b316-button b316-button-secondary", onClick: onCancel, children: "Back" }) : null
6209
6419
  ] })
6210
6420
  );
6211
6421
  }
@@ -6218,26 +6428,26 @@ function PlanChangeReview({
6218
6428
  const otherReason = preview.timings[other]?.reason ?? null;
6219
6429
  const changes = preview.entitlements.filter((change) => change.change !== "UNCHANGED");
6220
6430
  return card(
6221
- /* @__PURE__ */ jsxs33(Fragment11, { children: [
6222
- /* @__PURE__ */ jsxs33("div", { className: "b316-plan-name", children: [
6431
+ /* @__PURE__ */ jsxs34(Fragment11, { children: [
6432
+ /* @__PURE__ */ jsxs34("div", { className: "b316-plan-name", children: [
6223
6433
  "Change to ",
6224
6434
  to.planName
6225
6435
  ] }),
6226
- /* @__PURE__ */ jsxs33("div", { className: "b316-muted", children: [
6436
+ /* @__PURE__ */ jsxs34("div", { className: "b316-muted", children: [
6227
6437
  "From ",
6228
6438
  from.planName
6229
6439
  ] }),
6230
- error ? /* @__PURE__ */ jsx34("div", { className: "b316-error", role: "alert", children: error }) : null,
6231
- changes.length === 0 ? /* @__PURE__ */ jsx34("p", { className: "b316-muted", children: "Every feature stays the same." }) : /* @__PURE__ */ jsxs33("table", { className: "b316-review-table", children: [
6232
- /* @__PURE__ */ jsx34("thead", { children: /* @__PURE__ */ jsxs33("tr", { children: [
6233
- /* @__PURE__ */ jsx34("th", { children: "Feature" }),
6234
- /* @__PURE__ */ jsx34("th", { children: from.planName }),
6235
- /* @__PURE__ */ jsx34("th", { children: to.planName })
6440
+ error ? /* @__PURE__ */ jsx35("div", { className: "b316-error", role: "alert", children: error }) : null,
6441
+ changes.length === 0 ? /* @__PURE__ */ jsx35("p", { className: "b316-muted", children: "Every feature stays the same." }) : /* @__PURE__ */ jsxs34("table", { className: "b316-review-table", children: [
6442
+ /* @__PURE__ */ jsx35("thead", { children: /* @__PURE__ */ jsxs34("tr", { children: [
6443
+ /* @__PURE__ */ jsx35("th", { children: "Feature" }),
6444
+ /* @__PURE__ */ jsx35("th", { children: from.planName }),
6445
+ /* @__PURE__ */ jsx35("th", { children: to.planName })
6236
6446
  ] }) }),
6237
- /* @__PURE__ */ jsx34("tbody", { children: changes.map((change) => /* @__PURE__ */ jsxs33("tr", { children: [
6238
- /* @__PURE__ */ jsx34("td", { children: change.featureName }),
6239
- /* @__PURE__ */ jsx34("td", { children: limitText(change.before, change.type) }),
6240
- /* @__PURE__ */ jsx34(
6447
+ /* @__PURE__ */ jsx35("tbody", { children: changes.map((change) => /* @__PURE__ */ jsxs34("tr", { children: [
6448
+ /* @__PURE__ */ jsx35("td", { children: change.featureName }),
6449
+ /* @__PURE__ */ jsx35("td", { children: limitText(change.before, change.type) }),
6450
+ /* @__PURE__ */ jsx35(
6241
6451
  "td",
6242
6452
  {
6243
6453
  className: change.change === "GAINED" || change.change === "INCREASED" ? "b316-review-gain" : "b316-review-loss",
@@ -6246,40 +6456,40 @@ function PlanChangeReview({
6246
6456
  )
6247
6457
  ] }, change.featureId)) })
6248
6458
  ] }),
6249
- preview.timing === "NOW" ? now.trialing ? /* @__PURE__ */ jsxs33("p", { children: [
6459
+ preview.timing === "NOW" ? now.trialing ? /* @__PURE__ */ jsxs34("p", { children: [
6250
6460
  "The change happens now. Your trial carries on until ",
6251
6461
  day4(now.trialEndsAt),
6252
6462
  ", and nothing is charged before then."
6253
- ] }) : /* @__PURE__ */ jsxs33("div", { children: [
6254
- Number(now.credit) > 0 ? /* @__PURE__ */ jsxs33("div", { className: "b316-row", children: [
6255
- /* @__PURE__ */ jsxs33("span", { className: "b316-muted", children: [
6463
+ ] }) : /* @__PURE__ */ jsxs34("div", { children: [
6464
+ Number(now.credit) > 0 ? /* @__PURE__ */ jsxs34("div", { className: "b316-row", children: [
6465
+ /* @__PURE__ */ jsxs34("span", { className: "b316-muted", children: [
6256
6466
  "Credit for the unused part of ",
6257
6467
  from.planName
6258
6468
  ] }),
6259
- /* @__PURE__ */ jsxs33("span", { className: "b316-num", children: [
6469
+ /* @__PURE__ */ jsxs34("span", { className: "b316-num", children: [
6260
6470
  "\u2212",
6261
6471
  money5(now.credit, from.currency)
6262
6472
  ] })
6263
6473
  ] }) : null,
6264
- Number(now.closingUsage) > 0 ? /* @__PURE__ */ jsxs33("div", { className: "b316-row", children: [
6265
- /* @__PURE__ */ jsx34("span", { className: "b316-muted", children: "Usage so far this period" }),
6266
- /* @__PURE__ */ jsx34("span", { className: "b316-num", children: money5(now.closingUsage, from.currency) })
6474
+ Number(now.closingUsage) > 0 ? /* @__PURE__ */ jsxs34("div", { className: "b316-row", children: [
6475
+ /* @__PURE__ */ jsx35("span", { className: "b316-muted", children: "Usage so far this period" }),
6476
+ /* @__PURE__ */ jsx35("span", { className: "b316-num", children: money5(now.closingUsage, from.currency) })
6267
6477
  ] }) : null,
6268
- /* @__PURE__ */ jsxs33("div", { className: "b316-row", children: [
6269
- /* @__PURE__ */ jsxs33("span", { className: "b316-muted", children: [
6478
+ /* @__PURE__ */ jsxs34("div", { className: "b316-row", children: [
6479
+ /* @__PURE__ */ jsxs34("span", { className: "b316-muted", children: [
6270
6480
  to.planName,
6271
6481
  ", ",
6272
6482
  day4(now.newPeriod.start),
6273
6483
  " \u2013 ",
6274
6484
  day4(now.newPeriod.end)
6275
6485
  ] }),
6276
- /* @__PURE__ */ jsx34("span", { className: "b316-num", children: money5(now.newPeriodCharge, to.currency) })
6486
+ /* @__PURE__ */ jsx35("span", { className: "b316-num", children: money5(now.newPeriodCharge, to.currency) })
6277
6487
  ] }),
6278
- now.net !== null ? /* @__PURE__ */ jsxs33("div", { className: "b316-row b316-invoice-total", children: [
6279
- /* @__PURE__ */ jsx34("span", { children: "Due now" }),
6280
- /* @__PURE__ */ jsx34("span", { className: "b316-num", children: money5(now.net, to.currency) })
6488
+ now.net !== null ? /* @__PURE__ */ jsxs34("div", { className: "b316-row b316-invoice-total", children: [
6489
+ /* @__PURE__ */ jsx35("span", { children: "Due now" }),
6490
+ /* @__PURE__ */ jsx35("span", { className: "b316-num", children: money5(now.net, to.currency) })
6281
6491
  ] }) : null
6282
- ] }) : /* @__PURE__ */ jsxs33("p", { children: [
6492
+ ] }) : /* @__PURE__ */ jsxs34("p", { children: [
6283
6493
  "You keep ",
6284
6494
  from.planName,
6285
6495
  " until ",
@@ -6292,7 +6502,7 @@ function PlanChangeReview({
6292
6502
  preview.atPeriodEnd.nextInvoice.currency
6293
6503
  )}.` : ""
6294
6504
  ] }),
6295
- otherOpen ? /* @__PURE__ */ jsx34(
6505
+ otherOpen ? /* @__PURE__ */ jsx35(
6296
6506
  "button",
6297
6507
  {
6298
6508
  type: "button",
@@ -6303,12 +6513,12 @@ function PlanChangeReview({
6303
6513
  },
6304
6514
  children: other === "NOW" ? "Change now instead" : "Wait until the end of the period instead"
6305
6515
  }
6306
- ) : otherReason && TIMING_CLOSED[otherReason] ? /* @__PURE__ */ jsx34("p", { className: "b316-muted", children: TIMING_CLOSED[otherReason] }) : null,
6307
- needsCard ? /* @__PURE__ */ jsxs33("div", { className: "b316-notice", role: "status", children: [
6516
+ ) : otherReason && TIMING_CLOSED[otherReason] ? /* @__PURE__ */ jsx35("p", { className: "b316-muted", children: TIMING_CLOSED[otherReason] }) : null,
6517
+ needsCard ? /* @__PURE__ */ jsxs34("div", { className: "b316-notice", role: "status", children: [
6308
6518
  "A card is needed for a change that is charged now.",
6309
- /* @__PURE__ */ jsx34("div", { className: "b316-review-actions", children: /* @__PURE__ */ jsx34("button", { type: "button", className: "b316-button", onClick: () => void addCard(), children: "Add a card" }) })
6310
- ] }) : /* @__PURE__ */ jsxs33("div", { className: "b316-review-actions", children: [
6311
- /* @__PURE__ */ jsx34(
6519
+ /* @__PURE__ */ jsx35("div", { className: "b316-review-actions", children: /* @__PURE__ */ jsx35("button", { type: "button", className: "b316-button", onClick: () => void addCard(), children: "Add a card" }) })
6520
+ ] }) : /* @__PURE__ */ jsxs34("div", { className: "b316-review-actions", children: [
6521
+ /* @__PURE__ */ jsx35(
6312
6522
  "button",
6313
6523
  {
6314
6524
  type: "button",
@@ -6318,7 +6528,7 @@ function PlanChangeReview({
6318
6528
  children: busy ? "Working\u2026" : preview.timing === "NOW" ? `Change to ${to.planName} now` : `Schedule ${to.planName}`
6319
6529
  }
6320
6530
  ),
6321
- onCancel ? /* @__PURE__ */ jsxs33("button", { type: "button", className: "b316-button b316-button-secondary", onClick: onCancel, children: [
6531
+ onCancel ? /* @__PURE__ */ jsxs34("button", { type: "button", className: "b316-button b316-button-secondary", onClick: onCancel, children: [
6322
6532
  "Keep ",
6323
6533
  from.planName
6324
6534
  ] }) : null
@@ -6328,7 +6538,7 @@ function PlanChangeReview({
6328
6538
  }
6329
6539
 
6330
6540
  // src/BillingPortal.tsx
6331
- import { Fragment as Fragment12, jsx as jsx35, jsxs as jsxs34 } from "react/jsx-runtime";
6541
+ import { Fragment as Fragment12, jsx as jsx36, jsxs as jsxs35 } from "react/jsx-runtime";
6332
6542
  function BillingPortal({
6333
6543
  returnUrl,
6334
6544
  featuredPlanKey,
@@ -6366,24 +6576,24 @@ function BillingPortal({
6366
6576
  setNotice(null);
6367
6577
  setVersion((value) => value + 1);
6368
6578
  }, []);
6369
- const shell = (content) => /* @__PURE__ */ jsx35("div", { className: cls("b316-billing-portal", className), style, children: content });
6370
- if (sessionLoading) return shell(/* @__PURE__ */ jsx35("div", { className: "b316-card", children: "Loading\u2026" }));
6371
- if (!token) return shell(/* @__PURE__ */ jsx35("div", { className: "b316-card", children: "Sign in to manage your billing." }));
6579
+ const shell = (content) => /* @__PURE__ */ jsx36("div", { className: cls("b316-billing-portal", className), style, children: content });
6580
+ if (sessionLoading) return shell(/* @__PURE__ */ jsx36("div", { className: "b316-card", children: "Loading\u2026" }));
6581
+ if (!token) return shell(/* @__PURE__ */ jsx36("div", { className: "b316-card", children: "Sign in to manage your billing." }));
6372
6582
  if (failed) {
6373
6583
  return shell(
6374
- /* @__PURE__ */ jsx35("div", { className: "b316-card", children: /* @__PURE__ */ jsx35("div", { className: "b316-error", role: "alert", children: "Could not load your billing." }) })
6584
+ /* @__PURE__ */ jsx36("div", { className: "b316-card", children: /* @__PURE__ */ jsx36("div", { className: "b316-error", role: "alert", children: "Could not load your billing." }) })
6375
6585
  );
6376
6586
  }
6377
- if (!overview) return shell(/* @__PURE__ */ jsx35("div", { className: "b316-card", children: "Loading\u2026" }));
6587
+ if (!overview) return shell(/* @__PURE__ */ jsx36("div", { className: "b316-card", children: "Loading\u2026" }));
6378
6588
  const { subscription, managedBy, quantityPriced } = overview;
6379
6589
  const canChange = Boolean(subscription) && !managedBy;
6380
6590
  return shell(
6381
- /* @__PURE__ */ jsxs34(Fragment12, { children: [
6382
- notice ? /* @__PURE__ */ jsx35("div", { className: "b316-card b316-notice", role: "status", children: notice }) : null,
6383
- /* @__PURE__ */ jsx35(SubscriptionManager, { onChange: refresh }, `plan-${version}`),
6384
- canChange ? /* @__PURE__ */ jsx35(UpcomingInvoice, {}, `next-${version}`) : null,
6385
- canChange && quantityPriced ? /* @__PURE__ */ jsx35(SeatManager, { unitLabel, onChange: refresh }, `seats-${version}`) : null,
6386
- reviewing ? /* @__PURE__ */ jsx35(
6591
+ /* @__PURE__ */ jsxs35(Fragment12, { children: [
6592
+ notice ? /* @__PURE__ */ jsx36("div", { className: "b316-card b316-notice", role: "status", children: notice }) : null,
6593
+ /* @__PURE__ */ jsx36(SubscriptionManager, { onChange: refresh }, `plan-${version}`),
6594
+ canChange ? /* @__PURE__ */ jsx36(UpcomingInvoice, {}, `next-${version}`) : null,
6595
+ canChange && quantityPriced ? /* @__PURE__ */ jsx36(SeatManager, { unitLabel, onChange: refresh }, `seats-${version}`) : null,
6596
+ reviewing ? /* @__PURE__ */ jsx36(
6387
6597
  PlanChangeReview,
6388
6598
  {
6389
6599
  planVersionId: reviewing,
@@ -6396,9 +6606,9 @@ function BillingPortal({
6396
6606
  );
6397
6607
  }
6398
6608
  }
6399
- ) : /* @__PURE__ */ jsxs34("section", { children: [
6400
- /* @__PURE__ */ jsx35("h2", { className: "b316-billing-portal-section-title", children: subscription ? "Change plan" : "Choose a plan" }),
6401
- /* @__PURE__ */ jsx35(
6609
+ ) : /* @__PURE__ */ jsxs35("section", { children: [
6610
+ /* @__PURE__ */ jsx36("h2", { className: "b316-billing-portal-section-title", children: subscription ? "Change plan" : "Choose a plan" }),
6611
+ /* @__PURE__ */ jsx36(
6402
6612
  PricingTable,
6403
6613
  {
6404
6614
  featuredPlanKey,
@@ -6410,17 +6620,17 @@ function BillingPortal({
6410
6620
  `plans-${version}`
6411
6621
  )
6412
6622
  ] }),
6413
- /* @__PURE__ */ jsx35(CreditBalances, {}, `credits-${version}`),
6414
- managedBy ? null : /* @__PURE__ */ jsx35(PaymentMethod, { returnUrl }, `card-${version}`),
6415
- /* @__PURE__ */ jsx35(Invoices, {}, `invoices-${version}`),
6416
- billingDetails === void 0 ? /* @__PURE__ */ jsx35(BillingDetailsForm, {}, `details-${version}`) : billingDetails
6623
+ /* @__PURE__ */ jsx36(CreditBalances, {}, `credits-${version}`),
6624
+ managedBy ? null : /* @__PURE__ */ jsx36(PaymentMethod, { returnUrl }, `card-${version}`),
6625
+ /* @__PURE__ */ jsx36(Invoices, {}, `invoices-${version}`),
6626
+ billingDetails === void 0 ? /* @__PURE__ */ jsx36(BillingDetailsForm, {}, `details-${version}`) : billingDetails
6417
6627
  ] })
6418
6628
  );
6419
6629
  }
6420
6630
 
6421
6631
  // src/ApiKeyManager.tsx
6422
6632
  import { useCallback as useCallback13, useEffect as useEffect27, useState as useState35 } from "react";
6423
- import { jsx as jsx36, jsxs as jsxs35 } from "react/jsx-runtime";
6633
+ import { jsx as jsx37, jsxs as jsxs36 } from "react/jsx-runtime";
6424
6634
  function duration(seconds) {
6425
6635
  if (seconds % 3600 === 0) {
6426
6636
  return `${seconds / 3600}h`;
@@ -6472,16 +6682,16 @@ function ApiKeyManager({
6472
6682
  void load();
6473
6683
  }, [load]);
6474
6684
  if (sessionLoading || loading) {
6475
- return /* @__PURE__ */ jsx36("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
6685
+ return /* @__PURE__ */ jsx37("div", { className: cls("b316-card", className), style, children: "Loading\u2026" });
6476
6686
  }
6477
6687
  if (!token) {
6478
- return /* @__PURE__ */ jsx36("div", { className: cls("b316-card", className), style, children: "Sign in to manage your API keys." });
6688
+ return /* @__PURE__ */ jsx37("div", { className: cls("b316-card", className), style, children: "Sign in to manage your API keys." });
6479
6689
  }
6480
6690
  if (error) {
6481
- return /* @__PURE__ */ jsx36("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx36("div", { className: "b316-error", role: "alert", children: error }) });
6691
+ return /* @__PURE__ */ jsx37("div", { className: cls("b316-card", className), style, children: /* @__PURE__ */ jsx37("div", { className: "b316-error", role: "alert", children: error }) });
6482
6692
  }
6483
6693
  if (resources.length === 0) {
6484
- return /* @__PURE__ */ jsx36("div", { className: cls("b316-card", className), style, children: "There are no APIs available to your account." });
6694
+ return /* @__PURE__ */ jsx37("div", { className: cls("b316-card", className), style, children: "There are no APIs available to your account." });
6485
6695
  }
6486
6696
  const resource = resources.find((item) => item.id === resourceId) ?? resources[0];
6487
6697
  const reset = () => {
@@ -6490,37 +6700,37 @@ function ApiKeyManager({
6490
6700
  setChosen([]);
6491
6701
  setIssued(null);
6492
6702
  };
6493
- return /* @__PURE__ */ jsxs35("div", { className: cls("b316-card", className), style, children: [
6494
- error ? /* @__PURE__ */ jsx36("div", { className: "b316-error", role: "alert", children: error }) : null,
6495
- resources.length > 1 ? /* @__PURE__ */ jsx36(
6703
+ return /* @__PURE__ */ jsxs36("div", { className: cls("b316-card", className), style, children: [
6704
+ error ? /* @__PURE__ */ jsx37("div", { className: "b316-error", role: "alert", children: error }) : null,
6705
+ resources.length > 1 ? /* @__PURE__ */ jsx37(
6496
6706
  "select",
6497
6707
  {
6498
6708
  className: "b316-input",
6499
6709
  value: resource.id,
6500
6710
  onChange: (event) => setResourceId(event.target.value),
6501
6711
  style: { marginBottom: 14 },
6502
- children: resources.map((item) => /* @__PURE__ */ jsx36("option", { value: item.id, children: item.name }, item.id))
6712
+ children: resources.map((item) => /* @__PURE__ */ jsx37("option", { value: item.id, children: item.name }, item.id))
6503
6713
  }
6504
- ) : /* @__PURE__ */ jsx36("div", { className: "b316-plan-name", children: resource.name }),
6505
- resource.rateLimit ? /* @__PURE__ */ jsxs35("div", { className: "b316-muted", children: [
6714
+ ) : /* @__PURE__ */ jsx37("div", { className: "b316-plan-name", children: resource.name }),
6715
+ resource.rateLimit ? /* @__PURE__ */ jsxs36("div", { className: "b316-muted", children: [
6506
6716
  resource.rateLimit.requestsPerWindow,
6507
6717
  " requests per",
6508
6718
  " ",
6509
6719
  duration(resource.rateLimit.windowSeconds),
6510
6720
  resource.rateLimit.burst > resource.rateLimit.requestsPerWindow ? `, bursting to ${resource.rateLimit.burst}` : null
6511
- ] }) : /* @__PURE__ */ jsx36("div", { className: "b316-muted", children: "No rate limit." }),
6512
- credentials.length === 0 ? /* @__PURE__ */ jsx36("p", { className: "b316-muted", style: { marginTop: 14 }, children: "You have no API keys yet." }) : /* @__PURE__ */ jsx36("ul", { className: "b316-list", style: { marginTop: 14 }, children: credentials.map((credential) => /* @__PURE__ */ jsxs35("li", { className: "b316-list-item", children: [
6513
- /* @__PURE__ */ jsxs35("div", { children: [
6514
- /* @__PURE__ */ jsx36("div", { className: "b316-plan-name", children: credential.name }),
6515
- /* @__PURE__ */ jsxs35("div", { className: "b316-muted", children: [
6516
- /* @__PURE__ */ jsx36("code", { children: credential.clientId }),
6721
+ ] }) : /* @__PURE__ */ jsx37("div", { className: "b316-muted", children: "No rate limit." }),
6722
+ 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: [
6723
+ /* @__PURE__ */ jsxs36("div", { children: [
6724
+ /* @__PURE__ */ jsx37("div", { className: "b316-plan-name", children: credential.name }),
6725
+ /* @__PURE__ */ jsxs36("div", { className: "b316-muted", children: [
6726
+ /* @__PURE__ */ jsx37("code", { children: credential.clientId }),
6517
6727
  credential.secretLastFour ? ` \xB7 \u2026${credential.secretLastFour}` : null,
6518
6728
  credential.disabled ? " \xB7 Disabled" : null
6519
6729
  ] }),
6520
- /* @__PURE__ */ jsx36("div", { className: "b316-muted", children: credential.scopes.join(", ") })
6730
+ /* @__PURE__ */ jsx37("div", { className: "b316-muted", children: credential.scopes.join(", ") })
6521
6731
  ] }),
6522
- /* @__PURE__ */ jsxs35("div", { style: { display: "flex", gap: 8 }, children: [
6523
- /* @__PURE__ */ jsx36(
6732
+ /* @__PURE__ */ jsxs36("div", { style: { display: "flex", gap: 8 }, children: [
6733
+ /* @__PURE__ */ jsx37(
6524
6734
  "button",
6525
6735
  {
6526
6736
  type: "button",
@@ -6549,7 +6759,7 @@ function ApiKeyManager({
6549
6759
  children: "Rotate"
6550
6760
  }
6551
6761
  ),
6552
- /* @__PURE__ */ jsx36(
6762
+ /* @__PURE__ */ jsx37(
6553
6763
  ConfirmButton,
6554
6764
  {
6555
6765
  className: "b316-button b316-button-secondary",
@@ -6573,11 +6783,11 @@ function ApiKeyManager({
6573
6783
  )
6574
6784
  ] })
6575
6785
  ] }, credential.clientId)) }),
6576
- issued ? /* @__PURE__ */ jsxs35("div", { className: "b316-notice", style: { marginTop: 14 }, children: [
6577
- /* @__PURE__ */ jsx36("strong", { children: "Copy this now." }),
6786
+ issued ? /* @__PURE__ */ jsxs36("div", { className: "b316-notice", style: { marginTop: 14 }, children: [
6787
+ /* @__PURE__ */ jsx37("strong", { children: "Copy this now." }),
6578
6788
  " It is shown once and cannot be retrieved again.",
6579
- /* @__PURE__ */ jsx36("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsx36("code", { style: { wordBreak: "break-all" }, children: issued.secret }) }),
6580
- /* @__PURE__ */ jsx36(
6789
+ /* @__PURE__ */ jsx37("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsx37("code", { style: { wordBreak: "break-all" }, children: issued.secret }) }),
6790
+ /* @__PURE__ */ jsx37(
6581
6791
  "button",
6582
6792
  {
6583
6793
  type: "button",
@@ -6590,7 +6800,7 @@ function ApiKeyManager({
6590
6800
  children: "Copy"
6591
6801
  }
6592
6802
  ),
6593
- /* @__PURE__ */ jsx36(
6803
+ /* @__PURE__ */ jsx37(
6594
6804
  "button",
6595
6805
  {
6596
6806
  type: "button",
@@ -6601,8 +6811,8 @@ function ApiKeyManager({
6601
6811
  }
6602
6812
  )
6603
6813
  ] }) : null,
6604
- creating && !issued ? /* @__PURE__ */ jsxs35("div", { style: { marginTop: 14 }, children: [
6605
- /* @__PURE__ */ jsx36(
6814
+ creating && !issued ? /* @__PURE__ */ jsxs36("div", { style: { marginTop: 14 }, children: [
6815
+ /* @__PURE__ */ jsx37(
6606
6816
  "input",
6607
6817
  {
6608
6818
  className: "b316-input",
@@ -6611,9 +6821,9 @@ function ApiKeyManager({
6611
6821
  onChange: (event) => setName(event.target.value)
6612
6822
  }
6613
6823
  ),
6614
- /* @__PURE__ */ jsxs35("div", { style: { marginTop: 10 }, children: [
6615
- resource.availableScopes.map((scope) => /* @__PURE__ */ jsxs35("label", { className: "b316-checkbox", children: [
6616
- /* @__PURE__ */ jsx36(
6824
+ /* @__PURE__ */ jsxs36("div", { style: { marginTop: 10 }, children: [
6825
+ resource.availableScopes.map((scope) => /* @__PURE__ */ jsxs36("label", { className: "b316-checkbox", children: [
6826
+ /* @__PURE__ */ jsx37(
6617
6827
  "input",
6618
6828
  {
6619
6829
  type: "checkbox",
@@ -6623,19 +6833,19 @@ function ApiKeyManager({
6623
6833
  )
6624
6834
  }
6625
6835
  ),
6626
- /* @__PURE__ */ jsx36("code", { children: scope.key }),
6627
- scope.description ? /* @__PURE__ */ jsxs35("span", { className: "b316-muted", children: [
6836
+ /* @__PURE__ */ jsx37("code", { children: scope.key }),
6837
+ scope.description ? /* @__PURE__ */ jsxs36("span", { className: "b316-muted", children: [
6628
6838
  " \u2014 ",
6629
6839
  scope.description
6630
6840
  ] }) : null
6631
6841
  ] }, scope.key)),
6632
- resource.lockedScopes.map((scope) => /* @__PURE__ */ jsxs35("label", { className: "b316-checkbox b316-muted", children: [
6633
- /* @__PURE__ */ jsx36("input", { type: "checkbox", disabled: true }),
6634
- /* @__PURE__ */ jsx36("code", { children: scope.key }),
6635
- /* @__PURE__ */ jsx36("span", { children: " \u2014 not included in your plan" })
6842
+ resource.lockedScopes.map((scope) => /* @__PURE__ */ jsxs36("label", { className: "b316-checkbox b316-muted", children: [
6843
+ /* @__PURE__ */ jsx37("input", { type: "checkbox", disabled: true }),
6844
+ /* @__PURE__ */ jsx37("code", { children: scope.key }),
6845
+ /* @__PURE__ */ jsx37("span", { children: " \u2014 not included in your plan" })
6636
6846
  ] }, scope.key))
6637
6847
  ] }),
6638
- /* @__PURE__ */ jsx36(
6848
+ /* @__PURE__ */ jsx37(
6639
6849
  "button",
6640
6850
  {
6641
6851
  type: "button",
@@ -6669,7 +6879,7 @@ function ApiKeyManager({
6669
6879
  children: "Create key"
6670
6880
  }
6671
6881
  ),
6672
- /* @__PURE__ */ jsx36(
6882
+ /* @__PURE__ */ jsx37(
6673
6883
  "button",
6674
6884
  {
6675
6885
  type: "button",
@@ -6680,7 +6890,7 @@ function ApiKeyManager({
6680
6890
  }
6681
6891
  )
6682
6892
  ] }) : null,
6683
- !creating && !issued ? /* @__PURE__ */ jsx36(
6893
+ !creating && !issued ? /* @__PURE__ */ jsx37(
6684
6894
  "button",
6685
6895
  {
6686
6896
  type: "button",
@@ -6964,7 +7174,7 @@ var MANIFEST = [
6964
7174
  {
6965
7175
  name: "TwoFactorManager",
6966
7176
  kind: "component",
6967
- summary: "Turn two-factor authentication on or off, by authenticator app, a code to the inbox or a code by text message.",
7177
+ summary: "Turn two-factor authentication on or off, by authenticator app (QR code and key), a code to the inbox or a code by text message.",
6968
7178
  useWhen: "A security settings page. The app is strongest; the emailed or texted code is the one people who will not install an app actually use.",
6969
7179
  requires: ["session"],
6970
7180
  props: [
@@ -7108,7 +7318,7 @@ var MANIFEST = [
7108
7318
  {
7109
7319
  name: "SubscriptionManager",
7110
7320
  kind: "component",
7111
- summary: "The current plan, its renewal date, a scheduled plan change with its undo, cancelling at the period end (confirmed in the page) and resuming a cancelled one.",
7321
+ 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.",
7112
7322
  useWhen: "A billing settings page.",
7113
7323
  requires: ["session"],
7114
7324
  props: [