@hook-sdk/template 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -34,6 +34,7 @@ __export(index_exports, {
34
34
  AppConfigSchema: () => AppConfigSchema,
35
35
  AppRoot: () => AppRoot,
36
36
  DeepLinkHandler: () => DeepLinkHandler,
37
+ DevSkipOnboardingFab: () => DevSkipOnboardingFab,
37
38
  EmptyState: () => EmptyState,
38
39
  ErrorBoundary: () => ErrorBoundary,
39
40
  I18nProvider: () => I18nProvider,
@@ -43,6 +44,11 @@ __export(index_exports, {
43
44
  LoadingState: () => LoadingState,
44
45
  OnboardingFlow: () => OnboardingFlow,
45
46
  PaymentReturnHandler: () => PaymentReturnHandler,
47
+ Paywall: () => Paywall,
48
+ PaywallCta: () => PaywallCta,
49
+ PaywallCyclePicker: () => PaywallCyclePicker,
50
+ PaywallMethodContent: () => PaywallMethodContent,
51
+ PaywallMethodTabs: () => PaywallMethodTabs,
46
52
  PersistenceRegistry: () => PersistenceRegistry,
47
53
  PreAuthShell: () => PreAuthShell,
48
54
  PushPrompt: () => PushPrompt2,
@@ -57,10 +63,12 @@ __export(index_exports, {
57
63
  detectStandalone: () => detectStandalone,
58
64
  discountPercent: () => discountPercent,
59
65
  formatBRL: () => formatBRL,
66
+ isDevToolsEnabled: () => isDevToolsEnabled,
60
67
  monthlyFromYearly: () => monthlyFromYearly,
61
68
  parseAppConfig: () => parseAppConfig,
62
69
  shouldBlockInstall: () => shouldBlockInstall,
63
70
  shouldShowPermanentOption: () => shouldShowPermanentOption,
71
+ skipOnboarding: () => skipOnboarding,
64
72
  useAppConfig: () => useAppConfig,
65
73
  useAuth: () => useAuth,
66
74
  useAuthPrimitives: () => useAuthPrimitives,
@@ -77,14 +85,14 @@ __export(index_exports, {
77
85
  useSignupForm: () => useSignupForm,
78
86
  useSubscription: () => useSubscription,
79
87
  useToast: () => useToast,
80
- useTrackOnboardingStep: () => import_sdk21.useTrackOnboardingStep
88
+ useTrackOnboardingStep: () => import_sdk23.useTrackOnboardingStep
81
89
  });
82
90
  module.exports = __toCommonJS(index_exports);
83
91
 
84
92
  // src/AppRoot.tsx
85
- var import_react14 = require("react");
93
+ var import_react15 = require("react");
86
94
  var import_react_router_dom2 = require("react-router-dom");
87
- var import_sdk7 = require("@hook-sdk/sdk");
95
+ var import_sdk8 = require("@hook-sdk/sdk");
88
96
 
89
97
  // src/config/AppConfigContext.tsx
90
98
  var import_react = require("react");
@@ -118,7 +126,16 @@ var AuthFlowSchema = import_zod.z.object({
118
126
  });
119
127
  var PaywallNonFreeSchema = import_zod.z.object({
120
128
  mode: import_zod.z.enum(["trial", "pay_first"]),
129
+ // Legacy flat trial — fallback when per-method fields aren't set.
121
130
  trialDays: import_zod.z.number().int().nonnegative().optional(),
131
+ // Per-method trial (ADR-022 Amendment 2026-05-12 + G154). PIX Auto can't
132
+ // offer trial on Asaas today (Jornada 2 unavailable), so apps that mix
133
+ // methods must split the value to avoid bait-and-switch on PIX shoppers.
134
+ trialDaysCard: import_zod.z.number().int().nonnegative().optional(),
135
+ trialDaysPix: import_zod.z.number().int().nonnegative().optional(),
136
+ // Which method the paywall preselects. null/undefined = no preselection
137
+ // (user picks). Per-app override reflects audience, not Hook bias.
138
+ defaultMethod: import_zod.z.enum(["card", "pix-auto", "pix-once"]).nullable().optional(),
122
139
  cycles: import_zod.z.array(import_zod.z.enum(["MONTHLY", "YEARLY"])).min(1),
123
140
  prices: import_zod.z.object({
124
141
  monthlyCents: import_zod.z.number().int().nonnegative(),
@@ -369,10 +386,11 @@ function usePaywallState() {
369
386
  () => declaredMethods.filter((m) => isMethodAvailable(availability, m)),
370
387
  [declaredMethods, availability]
371
388
  );
372
- const defaultMethod = methods[0] ?? declaredMethods[0] ?? "card";
389
+ const configDefault = !isFree && "defaultMethod" in paywall ? paywall.defaultMethod ?? null : null;
390
+ const defaultMethod = (configDefault && methods.includes(configDefault) ? configDefault : null) ?? methods[0] ?? declaredMethods[0] ?? "card";
373
391
  const [selectedMethodRaw, setSelectedMethod] = (0, import_react6.useState)(defaultMethod);
374
392
  const selectedMethod = methods.includes(selectedMethodRaw) ? selectedMethodRaw : methods[0] ?? selectedMethodRaw;
375
- const initialCycle = isFree ? "MONTHLY" : paywall.cycles[0] ?? "MONTHLY";
393
+ const initialCycle = isFree ? "MONTHLY" : paywall.cycles.includes("YEARLY") ? "YEARLY" : paywall.cycles[0] ?? "MONTHLY";
376
394
  const [cycle, setCycle] = (0, import_react6.useState)(initialCycle);
377
395
  const cpfRequired = !isFree && paywall.requiresCpf;
378
396
  const [cpf, setCpf] = (0, import_react6.useState)("");
@@ -390,6 +408,22 @@ function usePaywallState() {
390
408
  const [submitting, setSubmitting] = (0, import_react6.useState)(false);
391
409
  const status = subscription.status();
392
410
  const daysLeftInTrial = subscription.daysLeftInTrial();
411
+ const trialDaysForMethod = (0, import_react6.useCallback)(
412
+ (method) => {
413
+ if (isFree) return 0;
414
+ if (method === "card") {
415
+ if (typeof paywall.trialDaysCard === "number") return paywall.trialDaysCard;
416
+ if (typeof paywall.trialDays === "number") return paywall.trialDays;
417
+ return 7;
418
+ }
419
+ if (typeof paywall.trialDaysPix === "number") return paywall.trialDaysPix;
420
+ if (typeof paywall.trialDays === "number") return paywall.trialDays;
421
+ return 0;
422
+ },
423
+ [isFree, paywall]
424
+ );
425
+ const trialDaysCard = trialDaysForMethod("card");
426
+ const trialDaysPix = trialDaysForMethod("pix-auto");
393
427
  const initialLoadComplete = subscription.initialLoadComplete;
394
428
  const hasAccess = subscription.hasAccess;
395
429
  const pixPending = (0, import_react6.useMemo)(() => {
@@ -429,6 +463,40 @@ function usePaywallState() {
429
463
  discountPercent: discount
430
464
  };
431
465
  }, [paywall, cycle, isFree]);
466
+ const hasConsumedTrial = (0, import_react6.useMemo)(() => {
467
+ return ["active", "trialing", "past_due", "canceled", "expired"].includes(status);
468
+ }, [status]);
469
+ const currentPriceCents = (0, import_react6.useMemo)(() => {
470
+ if (isFree) return 0;
471
+ return cycle === "YEARLY" ? paywall.prices.yearlyCents : paywall.prices.monthlyCents;
472
+ }, [paywall, cycle, isFree]);
473
+ const currentMonthlyEquivCents = (0, import_react6.useMemo)(() => {
474
+ if (isFree) return 0;
475
+ if (cycle === "YEARLY") return Math.round(paywall.prices.yearlyCents / 12);
476
+ return paywall.prices.monthlyCents;
477
+ }, [paywall, cycle, isFree]);
478
+ const anchorPriceCents = (0, import_react6.useMemo)(() => {
479
+ if (isFree) return null;
480
+ const a = paywall.anchorPrices;
481
+ if (!a) return null;
482
+ return cycle === "YEARLY" ? a.yearlyCents : a.monthlyCents;
483
+ }, [paywall, cycle, isFree]);
484
+ const selectMethod = (0, import_react6.useCallback)(
485
+ (next) => {
486
+ if (next === selectedMethod) return;
487
+ track2("paywall_method_tab_clicked", { method: next, from_method: selectedMethod });
488
+ setSelectedMethod(next);
489
+ },
490
+ [selectedMethod, track2]
491
+ );
492
+ const selectCycle = (0, import_react6.useCallback)(
493
+ (next) => {
494
+ if (next === cycle) return;
495
+ track2("paywall_cycle_clicked", { cycle: next, from_cycle: cycle });
496
+ setCycle(next);
497
+ },
498
+ [cycle, track2]
499
+ );
432
500
  const useDefaultMessages = paywall.mode !== "free" && paywall.errorMessages === "default";
433
501
  const buildError = (0, import_react6.useCallback)(
434
502
  (code, fallbackMessage) => ({
@@ -623,6 +691,20 @@ function usePaywallState() {
623
691
  methods,
624
692
  selectedMethod,
625
693
  setSelectedMethod,
694
+ // Conversion-max derivations (template 0.21)
695
+ hasConsumedTrial,
696
+ currentPriceCents,
697
+ currentMonthlyEquivCents,
698
+ anchorPriceCents,
699
+ selectMethod,
700
+ selectCycle,
701
+ isFree,
702
+ // Per-method trial (ADR-022 Amendment 2026-05-12). Use these to render
703
+ // asymmetric copy per method card on the paywall — never a global
704
+ // "free trial!" headline when both methods are visible.
705
+ trialDaysForMethod,
706
+ trialDaysCard,
707
+ trialDaysPix,
626
708
  // Form state
627
709
  cpfState,
628
710
  cardState,
@@ -654,13 +736,13 @@ var BLOCKING = /* @__PURE__ */ new Set([
654
736
  "canceled",
655
737
  "none"
656
738
  ]);
657
- function SubscriptionGate({ Paywall, children }) {
739
+ function SubscriptionGate({ Paywall: Paywall2, children }) {
658
740
  const { mode } = useTemplateConfig();
659
741
  const { status, hasAccess, initialLoadComplete } = usePaywallState();
660
742
  if (mode === "free") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
661
743
  if (!initialLoadComplete && status === "none") return null;
662
744
  if (hasAccess === true && status !== "none") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
663
- if (BLOCKING.has(status)) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Paywall, {});
745
+ if (BLOCKING.has(status)) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Paywall2, {});
664
746
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
665
747
  }
666
748
 
@@ -2106,22 +2188,156 @@ function I18nProvider({
2106
2188
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_i18next.I18nextProvider, { i18n: import_i18next.default, children });
2107
2189
  }
2108
2190
 
2109
- // src/internal/PaymentReturnHandler.tsx
2191
+ // src/dev/env.ts
2192
+ var import_meta = {};
2193
+ function isDevToolsEnabled() {
2194
+ const meta = import_meta;
2195
+ if (meta.env?.VITE_HOOK_DEV_TOOLS !== "1") return false;
2196
+ if (typeof window === "undefined") return false;
2197
+ const host = window.location.hostname;
2198
+ return host.includes(".staging.") || host === "localhost" || host === "127.0.0.1";
2199
+ }
2200
+
2201
+ // src/dev/DevSkipOnboardingFab.tsx
2110
2202
  var import_react13 = require("react");
2111
2203
  var import_sdk6 = require("@hook-sdk/sdk");
2112
2204
  var import_jsx_runtime20 = require("react/jsx-runtime");
2205
+ var STORAGE_KEY = "hook_dev_skip_email";
2206
+ var TEST_EMAIL_DOMAIN = "@hook.test";
2207
+ var TEST_PASSWORD = "SkipTest!2026";
2208
+ function makeEmail() {
2209
+ return `ryan+skip-${Date.now()}${TEST_EMAIL_DOMAIN}`;
2210
+ }
2211
+ async function ensureSignedIn(hook, maxAttempts = 3) {
2212
+ if (hook.authStatus === "authenticated") return null;
2213
+ let lastErr;
2214
+ for (let i = 0; i < maxAttempts; i += 1) {
2215
+ const email = makeEmail();
2216
+ try {
2217
+ await hook.auth.signup({ email, password: TEST_PASSWORD, name: "Ryan Test" });
2218
+ try {
2219
+ window.sessionStorage.setItem(STORAGE_KEY, email);
2220
+ } catch {
2221
+ }
2222
+ return email;
2223
+ } catch (err) {
2224
+ lastErr = err;
2225
+ await new Promise((r) => setTimeout(r, 30));
2226
+ }
2227
+ }
2228
+ throw lastErr ?? new Error("signup failed after retries");
2229
+ }
2230
+ async function skipOnboarding(hook, defaults, appSlug) {
2231
+ const { __seed, ...rest } = defaults;
2232
+ await ensureSignedIn(hook);
2233
+ await hook.appData.set("onboarding_data", {
2234
+ ...rest,
2235
+ onboarding_completed: true
2236
+ });
2237
+ if (__seed) {
2238
+ await __seed(hook);
2239
+ }
2240
+ console.info("[hook-template] dev_skip_onboarding fired", {
2241
+ app_slug: appSlug,
2242
+ hostname: window.location.hostname
2243
+ });
2244
+ window.location.assign(`/app/${appSlug}/`);
2245
+ }
2246
+ var STYLES = {
2247
+ base: {
2248
+ position: "fixed",
2249
+ bottom: "16px",
2250
+ right: "16px",
2251
+ zIndex: 2147483647,
2252
+ padding: "10px 14px",
2253
+ borderRadius: "999px",
2254
+ border: "none",
2255
+ background: "#F59E0B",
2256
+ color: "#111827",
2257
+ fontWeight: 600,
2258
+ fontSize: "13px",
2259
+ fontFamily: "system-ui, -apple-system, sans-serif",
2260
+ boxShadow: "0 4px 14px rgba(0, 0, 0, 0.25)",
2261
+ cursor: "pointer",
2262
+ display: "flex",
2263
+ alignItems: "center",
2264
+ gap: "6px"
2265
+ },
2266
+ confirm: { background: "#DC2626", color: "#FFFFFF" },
2267
+ busy: { opacity: 0.6, cursor: "wait" }
2268
+ };
2269
+ var CONFIRM_TIMEOUT_MS = 3e3;
2270
+ function DevSkipOnboardingFab({ defaults }) {
2271
+ const hook = (0, import_sdk6.useHook)();
2272
+ const { slug } = useAppConfig();
2273
+ const [state, setState] = (0, import_react13.useState)("idle");
2274
+ const [errorMsg, setErrorMsg] = (0, import_react13.useState)(null);
2275
+ const timerRef = (0, import_react13.useRef)(null);
2276
+ const clearTimer = (0, import_react13.useCallback)(() => {
2277
+ if (timerRef.current) {
2278
+ clearTimeout(timerRef.current);
2279
+ timerRef.current = null;
2280
+ }
2281
+ }, []);
2282
+ const onClick = (0, import_react13.useCallback)(async () => {
2283
+ if (state === "busy") return;
2284
+ if (state === "idle" || state === "error") {
2285
+ setState("confirm");
2286
+ setErrorMsg(null);
2287
+ clearTimer();
2288
+ timerRef.current = setTimeout(() => setState("idle"), CONFIRM_TIMEOUT_MS);
2289
+ return;
2290
+ }
2291
+ clearTimer();
2292
+ setState("busy");
2293
+ try {
2294
+ await skipOnboarding(hook, defaults, slug);
2295
+ } catch (err) {
2296
+ setState("error");
2297
+ setErrorMsg(err instanceof Error ? err.message : String(err));
2298
+ }
2299
+ }, [state, hook, defaults, slug, clearTimer]);
2300
+ const label = (() => {
2301
+ if (state === "busy") return "skipping\u2026";
2302
+ if (state === "confirm") return "tap again to confirm";
2303
+ if (state === "error") return `failed \u2014 tap to retry`;
2304
+ return hook.authStatus === "authenticated" ? "\u26A1 skip onboarding" : "\u26A1 skip + signup";
2305
+ })();
2306
+ const style = {
2307
+ ...STYLES.base,
2308
+ ...state === "confirm" || state === "error" ? STYLES.confirm : {},
2309
+ ...state === "busy" ? STYLES.busy : {}
2310
+ };
2311
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2312
+ "button",
2313
+ {
2314
+ type: "button",
2315
+ "data-testid": "dev-skip-onboarding-fab",
2316
+ "aria-label": "Skip onboarding (staging dev only)",
2317
+ style,
2318
+ onClick,
2319
+ title: errorMsg ?? void 0,
2320
+ children: label
2321
+ }
2322
+ );
2323
+ }
2324
+
2325
+ // src/internal/PaymentReturnHandler.tsx
2326
+ var import_react14 = require("react");
2327
+ var import_sdk7 = require("@hook-sdk/sdk");
2328
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2113
2329
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
2114
2330
  var MAX_CYCLES = 3;
2115
2331
  var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
2116
2332
  function PaymentReturnHandler({ children }) {
2117
- const { subscription, track: track2 } = (0, import_sdk6.useHook)();
2118
- const subRef = (0, import_react13.useRef)(subscription);
2333
+ const { subscription, track: track2 } = (0, import_sdk7.useHook)();
2334
+ const subRef = (0, import_react14.useRef)(subscription);
2119
2335
  subRef.current = subscription;
2120
- const runIdRef = (0, import_react13.useRef)(0);
2121
- const cyclesRef = (0, import_react13.useRef)(0);
2122
- const startMsRef = (0, import_react13.useRef)(0);
2123
- const [state, setState] = (0, import_react13.useState)("idle");
2124
- const runPoll = (0, import_react13.useCallback)(() => {
2336
+ const runIdRef = (0, import_react14.useRef)(0);
2337
+ const cyclesRef = (0, import_react14.useRef)(0);
2338
+ const startMsRef = (0, import_react14.useRef)(0);
2339
+ const [state, setState] = (0, import_react14.useState)("idle");
2340
+ const runPoll = (0, import_react14.useCallback)(() => {
2125
2341
  const runId = ++runIdRef.current;
2126
2342
  const isFirstRun = cyclesRef.current === 0;
2127
2343
  cyclesRef.current += 1;
@@ -2169,7 +2385,7 @@ function PaymentReturnHandler({ children }) {
2169
2385
  };
2170
2386
  void tick();
2171
2387
  }, [track2]);
2172
- (0, import_react13.useEffect)(() => {
2388
+ (0, import_react14.useEffect)(() => {
2173
2389
  if (typeof window === "undefined") return;
2174
2390
  const url = new URL(window.location.href);
2175
2391
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -2179,26 +2395,26 @@ function PaymentReturnHandler({ children }) {
2179
2395
  runIdRef.current++;
2180
2396
  };
2181
2397
  }, [runPoll]);
2182
- const goHome = (0, import_react13.useCallback)(() => {
2398
+ const goHome = (0, import_react14.useCallback)(() => {
2183
2399
  const cleanUrl = new URL(window.location.href);
2184
2400
  cleanUrl.searchParams.delete("paymentReturn");
2185
2401
  cleanUrl.pathname = "/app/home";
2186
2402
  window.location.href = cleanUrl.toString();
2187
2403
  }, []);
2188
2404
  if (state === "confirming") {
2189
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2405
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2190
2406
  }
2191
2407
  if (state === "waiting") {
2192
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2193
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2194
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2408
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2409
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2410
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2195
2411
  ] }) });
2196
2412
  }
2197
2413
  if (state === "timeout") {
2198
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
2199
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginBottom: 16 }, children: "Ainda n\xE3o conseguimos confirmar seu pagamento com o banco. Voc\xEA pode tentar de novo, voltar pro app, ou falar com a gente." }),
2200
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2201
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2414
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
2415
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { style: { marginBottom: 16 }, children: "Ainda n\xE3o conseguimos confirmar seu pagamento com o banco. Voc\xEA pode tentar de novo, voltar pro app, ou falar com a gente." }),
2416
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2417
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2202
2418
  "button",
2203
2419
  {
2204
2420
  type: "button",
@@ -2211,7 +2427,7 @@ function PaymentReturnHandler({ children }) {
2211
2427
  children: "Tentar de novo"
2212
2428
  }
2213
2429
  ),
2214
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2430
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2215
2431
  "button",
2216
2432
  {
2217
2433
  type: "button",
@@ -2221,7 +2437,7 @@ function PaymentReturnHandler({ children }) {
2221
2437
  children: "Voltar pro app"
2222
2438
  }
2223
2439
  ),
2224
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2440
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2225
2441
  "a",
2226
2442
  {
2227
2443
  href: SUPPORT_MAILTO,
@@ -2233,7 +2449,7 @@ function PaymentReturnHandler({ children }) {
2233
2449
  ] })
2234
2450
  ] }) });
2235
2451
  }
2236
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, { children });
2452
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children });
2237
2453
  }
2238
2454
  var overlayStyle2 = {
2239
2455
  position: "fixed",
@@ -2272,7 +2488,7 @@ var linkStyle = {
2272
2488
  };
2273
2489
 
2274
2490
  // src/AppRoot.tsx
2275
- var import_jsx_runtime21 = require("react/jsx-runtime");
2491
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2276
2492
  function buildLegacyConfigShim(config) {
2277
2493
  const paywall = config.paywall;
2278
2494
  const isFree = paywall.mode === "free";
@@ -2320,9 +2536,10 @@ function AppRoot(props) {
2320
2536
  Forgot,
2321
2537
  Reset,
2322
2538
  EmailVerify,
2323
- Paywall,
2539
+ Paywall: Paywall2,
2324
2540
  Onboarding,
2325
- PreAuthFlow
2541
+ PreAuthFlow,
2542
+ devSkipOnboarding
2326
2543
  } = props;
2327
2544
  if (!Login || !Signup || !Forgot || !Reset) {
2328
2545
  throw new Error(
@@ -2330,7 +2547,7 @@ function AppRoot(props) {
2330
2547
  );
2331
2548
  }
2332
2549
  const config = parseAppConfig(rawConfig);
2333
- if (config.paywall.mode !== "free" && !Paywall) {
2550
+ if (config.paywall.mode !== "free" && !Paywall2) {
2334
2551
  throw new Error(
2335
2552
  "[hook-template] <AppRoot>: Paywall slot prop is required when config.paywall.mode != 'free'."
2336
2553
  );
@@ -2345,19 +2562,19 @@ function AppRoot(props) {
2345
2562
  "[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
2346
2563
  );
2347
2564
  }
2348
- const legacyShim = (0, import_react14.useMemo)(() => buildLegacyConfigShim(config), [config]);
2565
+ const legacyShim = (0, import_react15.useMemo)(() => buildLegacyConfigShim(config), [config]);
2349
2566
  const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
2350
2567
  const basename = `/app/${config.slug}`;
2351
2568
  const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
2352
2569
  const position = config.install_prompt?.position ?? "post-paywall";
2353
- const subscriptionGated = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: position === "post-paywall" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(InstallGate, { position: "post-paywall", children: [
2570
+ const subscriptionGated = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SubscriptionGate, { Paywall: Paywall2 ?? FallbackPaywall, children: position === "post-paywall" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(InstallGate, { position: "post-paywall", children: [
2354
2571
  children,
2355
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PushPrompt, {})
2356
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2572
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PushPrompt, {})
2573
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
2357
2574
  children,
2358
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PushPrompt, {})
2575
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PushPrompt, {})
2359
2576
  ] }) });
2360
- const authGated = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2577
+ const authGated = /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2361
2578
  AuthGated,
2362
2579
  {
2363
2580
  config,
@@ -2366,18 +2583,19 @@ function AppRoot(props) {
2366
2583
  Forgot,
2367
2584
  Reset,
2368
2585
  EmailVerify,
2369
- Paywall,
2586
+ Paywall: Paywall2,
2370
2587
  Onboarding,
2371
2588
  PreAuthFlow,
2372
2589
  children: subscriptionGated
2373
2590
  }
2374
2591
  );
2375
- const routedTree = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Router, { ...routerProps, children: [
2376
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2377
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SessionExpiredBanner, {}),
2378
- position === "pre-auth" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InstallGate, { position: "pre-auth", children: authGated }) : authGated
2592
+ const routedTree = /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Router, { ...routerProps, children: [
2593
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2594
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SessionExpiredBanner, {}),
2595
+ position === "pre-auth" ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(InstallGate, { position: "pre-auth", children: authGated }) : authGated,
2596
+ isDevToolsEnabled() && devSkipOnboarding ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DevSkipOnboardingFab, { defaults: devSkipOnboarding.defaults }) : null
2379
2597
  ] });
2380
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2598
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2381
2599
  I18nProvider,
2382
2600
  {
2383
2601
  defaultLocale: config.i18n.defaultLocale,
@@ -2397,37 +2615,37 @@ function AuthGated({
2397
2615
  EmailVerify,
2398
2616
  PreAuthFlow
2399
2617
  }) {
2400
- const { authStatus } = (0, import_sdk7.useHook)();
2618
+ const { authStatus } = (0, import_sdk8.useHook)();
2401
2619
  if (authStatus === "loading") return null;
2402
2620
  if (authStatus !== "authenticated") {
2403
2621
  if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
2404
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_router_dom2.Routes, { children: [
2405
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Login, {}) }),
2406
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Signup, {}) }),
2407
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Forgot, {}) }),
2408
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Reset, {}) }),
2409
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EmailVerify, {}) }) : null,
2410
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PreAuthFlow, {}) })
2622
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_router_dom2.Routes, { children: [
2623
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Login, {}) }),
2624
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Signup, {}) }),
2625
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Forgot, {}) }),
2626
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Reset, {}) }),
2627
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmailVerify, {}) }) : null,
2628
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(PreAuthFlow, {}) })
2411
2629
  ] });
2412
2630
  }
2413
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_router_dom2.Routes, { children: [
2414
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Login, {}) }),
2415
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Signup, {}) }),
2416
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Forgot, {}) }),
2417
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Reset, {}) }),
2418
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EmailVerify, {}) }) : null,
2419
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
2631
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_react_router_dom2.Routes, { children: [
2632
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Login, {}) }),
2633
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Signup, {}) }),
2634
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Forgot, {}) }),
2635
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Reset, {}) }),
2636
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EmailVerify, {}) }) : null,
2637
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
2420
2638
  ] });
2421
2639
  }
2422
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children });
2640
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_jsx_runtime22.Fragment, { children });
2423
2641
  }
2424
2642
  function FallbackPaywall() {
2425
2643
  return null;
2426
2644
  }
2427
2645
 
2428
2646
  // src/hooks/usePush.ts
2429
- var import_react15 = require("react");
2430
- var import_sdk8 = require("@hook-sdk/sdk");
2647
+ var import_react16 = require("react");
2648
+ var import_sdk9 = require("@hook-sdk/sdk");
2431
2649
  var DISMISS_STORAGE_KEY = "push:dismissed-until";
2432
2650
  var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
2433
2651
  function detectIosNeedsInstall() {
@@ -2471,12 +2689,12 @@ function deriveState(push) {
2471
2689
  return { kind: "prompt" };
2472
2690
  }
2473
2691
  function usePush() {
2474
- const { push } = (0, import_sdk8.useHook)();
2475
- const [state, setState] = (0, import_react15.useState)(() => deriveState(push));
2476
- (0, import_react15.useEffect)(() => {
2692
+ const { push } = (0, import_sdk9.useHook)();
2693
+ const [state, setState] = (0, import_react16.useState)(() => deriveState(push));
2694
+ (0, import_react16.useEffect)(() => {
2477
2695
  setState(deriveState(push));
2478
2696
  }, [push]);
2479
- const subscribe = (0, import_react15.useCallback)(async () => {
2697
+ const subscribe = (0, import_react16.useCallback)(async () => {
2480
2698
  try {
2481
2699
  await push.subscribe();
2482
2700
  setState({ kind: "subscribed" });
@@ -2488,7 +2706,7 @@ function usePush() {
2488
2706
  throw e;
2489
2707
  }
2490
2708
  }, [push]);
2491
- const unsubscribe = (0, import_react15.useCallback)(async () => {
2709
+ const unsubscribe = (0, import_react16.useCallback)(async () => {
2492
2710
  try {
2493
2711
  await push.unsubscribe();
2494
2712
  setState({ kind: "prompt" });
@@ -2497,7 +2715,7 @@ function usePush() {
2497
2715
  throw e;
2498
2716
  }
2499
2717
  }, [push]);
2500
- const dismiss = (0, import_react15.useCallback)(() => {
2718
+ const dismiss = (0, import_react16.useCallback)(() => {
2501
2719
  if (typeof localStorage !== "undefined") {
2502
2720
  try {
2503
2721
  localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
@@ -2510,27 +2728,27 @@ function usePush() {
2510
2728
  }
2511
2729
 
2512
2730
  // src/components/PushPrompt.tsx
2513
- var import_jsx_runtime22 = require("react/jsx-runtime");
2731
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2514
2732
  function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
2515
2733
  const { state, subscribe } = usePush();
2516
2734
  if (state.kind === "denied" || state.kind === "dismissed" || state.kind === "subscribed") {
2517
2735
  return null;
2518
2736
  }
2519
2737
  if (state.kind === "ios_needs_install") {
2520
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2521
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { children: texts.iosInstallTitle }),
2522
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: texts.iosInstallBody }),
2523
- onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2738
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2739
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h3", { children: texts.iosInstallTitle }),
2740
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: texts.iosInstallBody }),
2741
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2524
2742
  ] });
2525
2743
  }
2526
2744
  if (state.kind === "unsupported") {
2527
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: texts.unsupportedBody }) });
2745
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: texts.unsupportedBody }) });
2528
2746
  }
2529
2747
  if (state.kind === "error") {
2530
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: state.message }) });
2748
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { children: state.message }) });
2531
2749
  }
2532
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, role: "region", children: [
2533
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2750
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className, role: "region", children: [
2751
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2534
2752
  "button",
2535
2753
  {
2536
2754
  type: "button",
@@ -2544,67 +2762,67 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2544
2762
  children: texts.cta
2545
2763
  }
2546
2764
  ),
2547
- onDeclined && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2765
+ onDeclined && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2548
2766
  ] });
2549
2767
  }
2550
2768
 
2551
2769
  // src/components/LanguageSwitcher.tsx
2552
- var import_sdk9 = require("@hook-sdk/sdk");
2553
- var import_jsx_runtime23 = require("react/jsx-runtime");
2770
+ var import_sdk10 = require("@hook-sdk/sdk");
2771
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2554
2772
  function LanguageSwitcher({ id, className, label = "Language" }) {
2555
2773
  const config = useAppConfig();
2556
2774
  const i18nConfig = config.i18n;
2557
- const [userLocale, setUserLocale] = (0, import_sdk9.usePersistedState)(
2775
+ const [userLocale, setUserLocale] = (0, import_sdk10.usePersistedState)(
2558
2776
  "user-locale",
2559
2777
  i18nConfig?.defaultLocale ?? "en-US"
2560
2778
  );
2561
2779
  if (!i18nConfig) return null;
2562
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className, children: [
2563
- label ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: label }) : null,
2564
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2780
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("label", { className, children: [
2781
+ label ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: label }) : null,
2782
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
2565
2783
  "select",
2566
2784
  {
2567
2785
  id,
2568
2786
  value: userLocale,
2569
2787
  onChange: (e) => setUserLocale(e.target.value),
2570
2788
  "data-testid": "language-switcher",
2571
- children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: loc, children: loc }, loc))
2789
+ children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("option", { value: loc, children: loc }, loc))
2572
2790
  }
2573
2791
  )
2574
2792
  ] });
2575
2793
  }
2576
2794
 
2577
2795
  // src/defaults/LoadingState.tsx
2578
- var import_jsx_runtime24 = require("react/jsx-runtime");
2796
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2579
2797
  function LoadingState({ message }) {
2580
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: message ?? "Carregando..." }) });
2798
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { children: message ?? "Carregando..." }) });
2581
2799
  }
2582
2800
 
2583
2801
  // src/defaults/EmptyState.tsx
2584
- var import_jsx_runtime25 = require("react/jsx-runtime");
2802
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2585
2803
  function EmptyState({ title, description, action }) {
2586
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2587
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2588
- description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2589
- action && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { marginTop: 16 }, children: action })
2804
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2805
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2806
+ description && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2807
+ action && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { style: { marginTop: 16 }, children: action })
2590
2808
  ] });
2591
2809
  }
2592
2810
 
2593
2811
  // src/hooks/useLoginForm.ts
2594
- var import_react16 = require("react");
2595
- var import_sdk11 = require("@hook-sdk/sdk");
2812
+ var import_react17 = require("react");
2813
+ var import_sdk12 = require("@hook-sdk/sdk");
2596
2814
 
2597
2815
  // src/errors.ts
2598
- var import_sdk10 = require("@hook-sdk/sdk");
2816
+ var import_sdk11 = require("@hook-sdk/sdk");
2599
2817
  function mapSdkError(err) {
2600
- if (err instanceof import_sdk10.SdkRateLimitError) {
2818
+ if (err instanceof import_sdk11.SdkRateLimitError) {
2601
2819
  return {
2602
2820
  code: "rate_limited",
2603
2821
  message: `Aguarde ${err.retryAfter}s e tente novamente.`,
2604
2822
  retryAfter: err.retryAfter
2605
2823
  };
2606
2824
  }
2607
- if (err instanceof import_sdk10.SdkAuthError) {
2825
+ if (err instanceof import_sdk11.SdkAuthError) {
2608
2826
  const detail = err.detail;
2609
2827
  if (detail === "email_unverified") {
2610
2828
  return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
@@ -2614,7 +2832,7 @@ function mapSdkError(err) {
2614
2832
  }
2615
2833
  return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
2616
2834
  }
2617
- if (err instanceof import_sdk10.SdkError && err.httpStatus === 0) {
2835
+ if (err instanceof import_sdk11.SdkError && err.httpStatus === 0) {
2618
2836
  return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
2619
2837
  }
2620
2838
  if (err instanceof TypeError) {
@@ -2627,20 +2845,20 @@ function mapSdkError(err) {
2627
2845
  var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2628
2846
  var MIN_PASSWORD = 8;
2629
2847
  function useLoginForm() {
2630
- const { auth } = (0, import_sdk11.useHook)();
2631
- const [email, setEmail] = (0, import_react16.useState)("");
2632
- const [password, setPassword] = (0, import_react16.useState)("");
2633
- const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2634
- const [error, setError] = (0, import_react16.useState)(null);
2635
- const [touchedEmail, setTouchedEmail] = (0, import_react16.useState)(false);
2636
- const [touchedPassword, setTouchedPassword] = (0, import_react16.useState)(false);
2637
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react16.useState)(false);
2638
- const validateEmail = (0, import_react16.useMemo)(() => {
2848
+ const { auth } = (0, import_sdk12.useHook)();
2849
+ const [email, setEmail] = (0, import_react17.useState)("");
2850
+ const [password, setPassword] = (0, import_react17.useState)("");
2851
+ const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2852
+ const [error, setError] = (0, import_react17.useState)(null);
2853
+ const [touchedEmail, setTouchedEmail] = (0, import_react17.useState)(false);
2854
+ const [touchedPassword, setTouchedPassword] = (0, import_react17.useState)(false);
2855
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
2856
+ const validateEmail = (0, import_react17.useMemo)(() => {
2639
2857
  if (email.length === 0) return null;
2640
2858
  if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
2641
2859
  return null;
2642
2860
  }, [email]);
2643
- const validatePassword = (0, import_react16.useMemo)(() => {
2861
+ const validatePassword = (0, import_react17.useMemo)(() => {
2644
2862
  if (password.length === 0) return null;
2645
2863
  if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
2646
2864
  return null;
@@ -2648,7 +2866,7 @@ function useLoginForm() {
2648
2866
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2649
2867
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2650
2868
  const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
2651
- const submit = (0, import_react16.useCallback)(async () => {
2869
+ const submit = (0, import_react17.useCallback)(async () => {
2652
2870
  setFormSubmitAttempted(true);
2653
2871
  if (!canSubmit) return false;
2654
2872
  setSubmitting(true);
@@ -2682,32 +2900,32 @@ function useLoginForm() {
2682
2900
  }
2683
2901
 
2684
2902
  // src/hooks/useSignupForm.ts
2685
- var import_react17 = require("react");
2686
- var import_sdk12 = require("@hook-sdk/sdk");
2903
+ var import_react18 = require("react");
2904
+ var import_sdk13 = require("@hook-sdk/sdk");
2687
2905
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2688
2906
  var MIN_PASSWORD2 = 8;
2689
2907
  function useSignupForm() {
2690
- const { auth } = (0, import_sdk12.useHook)();
2691
- const [name, setName] = (0, import_react17.useState)("");
2692
- const [email, setEmail] = (0, import_react17.useState)("");
2693
- const [password, setPassword] = (0, import_react17.useState)("");
2694
- const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2695
- const [error, setError] = (0, import_react17.useState)(null);
2696
- const [touchedName, setTouchedName] = (0, import_react17.useState)(false);
2697
- const [touchedEmail, setTouchedEmail] = (0, import_react17.useState)(false);
2698
- const [touchedPassword, setTouchedPassword] = (0, import_react17.useState)(false);
2699
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
2700
- const validateName = (0, import_react17.useMemo)(() => {
2908
+ const { auth } = (0, import_sdk13.useHook)();
2909
+ const [name, setName] = (0, import_react18.useState)("");
2910
+ const [email, setEmail] = (0, import_react18.useState)("");
2911
+ const [password, setPassword] = (0, import_react18.useState)("");
2912
+ const [submitting, setSubmitting] = (0, import_react18.useState)(false);
2913
+ const [error, setError] = (0, import_react18.useState)(null);
2914
+ const [touchedName, setTouchedName] = (0, import_react18.useState)(false);
2915
+ const [touchedEmail, setTouchedEmail] = (0, import_react18.useState)(false);
2916
+ const [touchedPassword, setTouchedPassword] = (0, import_react18.useState)(false);
2917
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
2918
+ const validateName = (0, import_react18.useMemo)(() => {
2701
2919
  if (name.length === 0) return null;
2702
2920
  if (name.trim().length < 2) return "Nome muito curto.";
2703
2921
  return null;
2704
2922
  }, [name]);
2705
- const validateEmail = (0, import_react17.useMemo)(() => {
2923
+ const validateEmail = (0, import_react18.useMemo)(() => {
2706
2924
  if (email.length === 0) return null;
2707
2925
  if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
2708
2926
  return null;
2709
2927
  }, [email]);
2710
- const validatePassword = (0, import_react17.useMemo)(() => {
2928
+ const validatePassword = (0, import_react18.useMemo)(() => {
2711
2929
  if (password.length === 0) return null;
2712
2930
  if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
2713
2931
  return null;
@@ -2716,7 +2934,7 @@ function useSignupForm() {
2716
2934
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2717
2935
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2718
2936
  const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
2719
- const submit = (0, import_react17.useCallback)(async () => {
2937
+ const submit = (0, import_react18.useCallback)(async () => {
2720
2938
  setFormSubmitAttempted(true);
2721
2939
  if (!canSubmit) return false;
2722
2940
  setSubmitting(true);
@@ -2754,25 +2972,25 @@ function useSignupForm() {
2754
2972
  }
2755
2973
 
2756
2974
  // src/hooks/useForgotForm.ts
2757
- var import_react18 = require("react");
2758
- var import_sdk13 = require("@hook-sdk/sdk");
2975
+ var import_react19 = require("react");
2976
+ var import_sdk14 = require("@hook-sdk/sdk");
2759
2977
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2760
2978
  function useForgotForm() {
2761
- const { auth } = (0, import_sdk13.useHook)();
2762
- const [email, setEmail] = (0, import_react18.useState)("");
2763
- const [submitting, setSubmitting] = (0, import_react18.useState)(false);
2764
- const [sent, setSent] = (0, import_react18.useState)(false);
2765
- const [error, setError] = (0, import_react18.useState)(null);
2766
- const [touchedEmail, setTouchedEmail] = (0, import_react18.useState)(false);
2767
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
2768
- const validateEmail = (0, import_react18.useMemo)(() => {
2979
+ const { auth } = (0, import_sdk14.useHook)();
2980
+ const [email, setEmail] = (0, import_react19.useState)("");
2981
+ const [submitting, setSubmitting] = (0, import_react19.useState)(false);
2982
+ const [sent, setSent] = (0, import_react19.useState)(false);
2983
+ const [error, setError] = (0, import_react19.useState)(null);
2984
+ const [touchedEmail, setTouchedEmail] = (0, import_react19.useState)(false);
2985
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react19.useState)(false);
2986
+ const validateEmail = (0, import_react19.useMemo)(() => {
2769
2987
  if (email.length === 0) return null;
2770
2988
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
2771
2989
  return null;
2772
2990
  }, [email]);
2773
2991
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2774
2992
  const canSubmit = email.length > 0 && validateEmail === null && !submitting;
2775
- const submit = (0, import_react18.useCallback)(async () => {
2993
+ const submit = (0, import_react19.useCallback)(async () => {
2776
2994
  setFormSubmitAttempted(true);
2777
2995
  if (!canSubmit) return false;
2778
2996
  setSubmitting(true);
@@ -2803,32 +3021,32 @@ function useForgotForm() {
2803
3021
  }
2804
3022
 
2805
3023
  // src/hooks/useResetForm.ts
2806
- var import_react19 = require("react");
2807
- var import_sdk14 = require("@hook-sdk/sdk");
3024
+ var import_react20 = require("react");
3025
+ var import_sdk15 = require("@hook-sdk/sdk");
2808
3026
  var MIN_PASSWORD3 = 12;
2809
3027
  function useResetForm() {
2810
- const { auth } = (0, import_sdk14.useHook)();
2811
- const [token, setToken] = (0, import_react19.useState)(null);
2812
- const [password, setPassword] = (0, import_react19.useState)("");
2813
- const [confirm, setConfirm] = (0, import_react19.useState)("");
2814
- const [submitting, setSubmitting] = (0, import_react19.useState)(false);
2815
- const [done, setDone] = (0, import_react19.useState)(false);
2816
- const [error, setError] = (0, import_react19.useState)(null);
2817
- const [touchedPassword, setTouchedPassword] = (0, import_react19.useState)(false);
2818
- const [touchedConfirm, setTouchedConfirm] = (0, import_react19.useState)(false);
2819
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react19.useState)(false);
2820
- (0, import_react19.useEffect)(() => {
3028
+ const { auth } = (0, import_sdk15.useHook)();
3029
+ const [token, setToken] = (0, import_react20.useState)(null);
3030
+ const [password, setPassword] = (0, import_react20.useState)("");
3031
+ const [confirm, setConfirm] = (0, import_react20.useState)("");
3032
+ const [submitting, setSubmitting] = (0, import_react20.useState)(false);
3033
+ const [done, setDone] = (0, import_react20.useState)(false);
3034
+ const [error, setError] = (0, import_react20.useState)(null);
3035
+ const [touchedPassword, setTouchedPassword] = (0, import_react20.useState)(false);
3036
+ const [touchedConfirm, setTouchedConfirm] = (0, import_react20.useState)(false);
3037
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react20.useState)(false);
3038
+ (0, import_react20.useEffect)(() => {
2821
3039
  if (typeof window === "undefined") return;
2822
3040
  const params = new URLSearchParams(window.location.search);
2823
3041
  const t = params.get("token");
2824
3042
  setToken(t && t.length > 0 ? t : null);
2825
3043
  }, []);
2826
- const validatePassword = (0, import_react19.useMemo)(() => {
3044
+ const validatePassword = (0, import_react20.useMemo)(() => {
2827
3045
  if (password.length === 0) return null;
2828
3046
  if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
2829
3047
  return null;
2830
3048
  }, [password]);
2831
- const validateConfirm = (0, import_react19.useMemo)(() => {
3049
+ const validateConfirm = (0, import_react20.useMemo)(() => {
2832
3050
  if (confirm.length === 0) return null;
2833
3051
  if (confirm !== password) return "Senhas n\xE3o coincidem.";
2834
3052
  return null;
@@ -2836,7 +3054,7 @@ function useResetForm() {
2836
3054
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2837
3055
  const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
2838
3056
  const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
2839
- const submit = (0, import_react19.useCallback)(async () => {
3057
+ const submit = (0, import_react20.useCallback)(async () => {
2840
3058
  setFormSubmitAttempted(true);
2841
3059
  if (!canSubmit || token === null) return;
2842
3060
  setSubmitting(true);
@@ -2876,9 +3094,9 @@ function useResetForm() {
2876
3094
  }
2877
3095
 
2878
3096
  // src/hooks/usePlan.ts
2879
- var import_sdk15 = require("@hook-sdk/sdk");
3097
+ var import_sdk16 = require("@hook-sdk/sdk");
2880
3098
  function usePlan() {
2881
- const { plan } = (0, import_sdk15.useHook)();
3099
+ const { plan } = (0, import_sdk16.useHook)();
2882
3100
  return plan;
2883
3101
  }
2884
3102
 
@@ -2911,12 +3129,12 @@ function discountPercent(anchorCents, realCents) {
2911
3129
  }
2912
3130
 
2913
3131
  // src/hooks/useAuthPrimitives.ts
2914
- var import_react20 = require("react");
2915
- var import_sdk16 = require("@hook-sdk/sdk");
3132
+ var import_react21 = require("react");
3133
+ var import_sdk17 = require("@hook-sdk/sdk");
2916
3134
  var warned = false;
2917
3135
  function useAuthPrimitives() {
2918
- const { auth } = (0, import_sdk16.useHook)();
2919
- (0, import_react20.useEffect)(() => {
3136
+ const { auth } = (0, import_sdk17.useHook)();
3137
+ (0, import_react21.useEffect)(() => {
2920
3138
  if (!warned && process.env.NODE_ENV !== "production") {
2921
3139
  warned = true;
2922
3140
  console.warn(
@@ -2938,9 +3156,9 @@ function useAuthPrimitives() {
2938
3156
  }
2939
3157
 
2940
3158
  // src/hooks/useAuth.ts
2941
- var import_sdk17 = require("@hook-sdk/sdk");
3159
+ var import_sdk18 = require("@hook-sdk/sdk");
2942
3160
  function useAuth() {
2943
- const { user, authStatus, auth } = (0, import_sdk17.useHook)();
3161
+ const { user, authStatus, auth } = (0, import_sdk18.useHook)();
2944
3162
  return {
2945
3163
  user,
2946
3164
  authStatus,
@@ -2949,26 +3167,26 @@ function useAuth() {
2949
3167
  }
2950
3168
 
2951
3169
  // src/index.ts
2952
- var import_sdk21 = require("@hook-sdk/sdk");
3170
+ var import_sdk23 = require("@hook-sdk/sdk");
2953
3171
 
2954
3172
  // src/hooks/useSubscription.ts
2955
- var import_sdk18 = require("@hook-sdk/sdk");
3173
+ var import_sdk19 = require("@hook-sdk/sdk");
2956
3174
  function useSubscription() {
2957
- const { subscription } = (0, import_sdk18.useHook)();
3175
+ const { subscription } = (0, import_sdk19.useHook)();
2958
3176
  return {
2959
3177
  status: subscription.status()
2960
3178
  };
2961
3179
  }
2962
3180
 
2963
3181
  // src/hooks/useReminders.ts
2964
- var import_react21 = require("react");
2965
- var import_sdk19 = require("@hook-sdk/sdk");
3182
+ var import_react22 = require("react");
3183
+ var import_sdk20 = require("@hook-sdk/sdk");
2966
3184
  function useReminders() {
2967
- const { push } = (0, import_sdk19.useHook)();
3185
+ const { push } = (0, import_sdk20.useHook)();
2968
3186
  const r = push.reminders;
2969
- const [reminders, setReminders] = (0, import_react21.useState)([]);
2970
- const [loading, setLoading] = (0, import_react21.useState)(true);
2971
- const reload = (0, import_react21.useCallback)(async () => {
3187
+ const [reminders, setReminders] = (0, import_react22.useState)([]);
3188
+ const [loading, setLoading] = (0, import_react22.useState)(true);
3189
+ const reload = (0, import_react22.useCallback)(async () => {
2972
3190
  setLoading(true);
2973
3191
  try {
2974
3192
  const next = await r.list();
@@ -2977,38 +3195,38 @@ function useReminders() {
2977
3195
  setLoading(false);
2978
3196
  }
2979
3197
  }, [r]);
2980
- (0, import_react21.useEffect)(() => {
3198
+ (0, import_react22.useEffect)(() => {
2981
3199
  void reload();
2982
3200
  }, [reload]);
2983
- const setReminder = (0, import_react21.useCallback)(async (input) => {
3201
+ const setReminder = (0, import_react22.useCallback)(async (input) => {
2984
3202
  await r.set(input);
2985
3203
  await reload();
2986
3204
  }, [r, reload]);
2987
- const deleteReminder = (0, import_react21.useCallback)(async (slot) => {
3205
+ const deleteReminder = (0, import_react22.useCallback)(async (slot) => {
2988
3206
  await r.delete(slot);
2989
3207
  await reload();
2990
3208
  }, [r, reload]);
2991
- const schedule = (0, import_react21.useCallback)(async (items) => {
3209
+ const schedule = (0, import_react22.useCallback)(async (items) => {
2992
3210
  return r.schedule(items);
2993
3211
  }, [r]);
2994
- const setFallbacks = (0, import_react21.useCallback)(async (items) => {
3212
+ const setFallbacks = (0, import_react22.useCallback)(async (items) => {
2995
3213
  return r.setFallbacks(items);
2996
3214
  }, [r]);
2997
3215
  return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
2998
3216
  }
2999
3217
 
3000
3218
  // src/hooks/useToast.ts
3001
- var import_react22 = require("react");
3219
+ var import_react23 = require("react");
3002
3220
  function useToast() {
3003
- const [items, setItems] = (0, import_react22.useState)([]);
3004
- const show = (0, import_react22.useCallback)((message, kind = "info") => {
3221
+ const [items, setItems] = (0, import_react23.useState)([]);
3222
+ const show = (0, import_react23.useCallback)((message, kind = "info") => {
3005
3223
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
3006
3224
  setItems((prev) => [...prev, { id, message, kind }]);
3007
3225
  setTimeout(() => {
3008
3226
  setItems((prev) => prev.filter((t) => t.id !== id));
3009
3227
  }, 4e3);
3010
3228
  }, []);
3011
- const dismiss = (0, import_react22.useCallback)((id) => {
3229
+ const dismiss = (0, import_react23.useCallback)((id) => {
3012
3230
  setItems((prev) => prev.filter((t) => t.id !== id));
3013
3231
  }, []);
3014
3232
  return { items, show, dismiss };
@@ -3016,20 +3234,20 @@ function useToast() {
3016
3234
 
3017
3235
  // src/RouteBoundary.tsx
3018
3236
  var import_react_router_dom3 = require("react-router-dom");
3019
- var import_jsx_runtime26 = require("react/jsx-runtime");
3237
+ var import_jsx_runtime27 = require("react/jsx-runtime");
3020
3238
  function RouteBoundary({ children }) {
3021
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_router_dom3.Routes, { children: [
3239
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_react_router_dom3.Routes, { children: [
3022
3240
  children,
3023
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DefaultNotFound, {}) })
3241
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(DefaultNotFound, {}) })
3024
3242
  ] });
3025
3243
  }
3026
3244
  function DefaultNotFound() {
3027
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
3245
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
3028
3246
  }
3029
3247
 
3030
3248
  // src/PreAuthShell.tsx
3031
3249
  var import_react_router_dom4 = require("react-router-dom");
3032
- var import_jsx_runtime27 = require("react/jsx-runtime");
3250
+ var import_jsx_runtime28 = require("react/jsx-runtime");
3033
3251
  function PreAuthShell({
3034
3252
  basename,
3035
3253
  testRouter,
@@ -3037,20 +3255,20 @@ function PreAuthShell({
3037
3255
  children
3038
3256
  }) {
3039
3257
  if (testRouter === "memory") {
3040
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.Routes, { children }) });
3258
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom4.Routes, { children }) });
3041
3259
  }
3042
- return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.Routes, { children }) });
3260
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom4.Routes, { children }) });
3043
3261
  }
3044
3262
 
3045
3263
  // src/OnboardingFlow.tsx
3046
- var import_react24 = require("react");
3047
- var import_sdk20 = require("@hook-sdk/sdk");
3264
+ var import_react25 = require("react");
3265
+ var import_sdk21 = require("@hook-sdk/sdk");
3048
3266
 
3049
3267
  // src/hooks/useOnboardingStep.ts
3050
- var import_react23 = require("react");
3051
- var OnboardingStepContext = (0, import_react23.createContext)(null);
3268
+ var import_react24 = require("react");
3269
+ var OnboardingStepContext = (0, import_react24.createContext)(null);
3052
3270
  function useOnboardingStep() {
3053
- const ctx = (0, import_react23.useContext)(OnboardingStepContext);
3271
+ const ctx = (0, import_react24.useContext)(OnboardingStepContext);
3054
3272
  if (!ctx) {
3055
3273
  throw new Error(
3056
3274
  "[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
@@ -3060,7 +3278,7 @@ function useOnboardingStep() {
3060
3278
  }
3061
3279
 
3062
3280
  // src/OnboardingFlow.tsx
3063
- var import_jsx_runtime28 = require("react/jsx-runtime");
3281
+ var import_jsx_runtime29 = require("react/jsx-runtime");
3064
3282
  var isFilled = (v) => v != null && v !== "";
3065
3283
  var CURRENT_STEP_FIELD = "currentStep";
3066
3284
  function readPersistedStepIdx(draft) {
@@ -3073,12 +3291,12 @@ function OnboardingFlow({
3073
3291
  onComplete,
3074
3292
  persistKey
3075
3293
  }) {
3076
- const [draft, setDraft, status] = (0, import_sdk20.usePersistedState)(persistKey, {});
3077
- const draftRef = (0, import_react24.useRef)(draft);
3294
+ const [draft, setDraft, status] = (0, import_sdk21.usePersistedState)(persistKey, {});
3295
+ const draftRef = (0, import_react25.useRef)(draft);
3078
3296
  draftRef.current = draft;
3079
3297
  const idx = readPersistedStepIdx(draft);
3080
3298
  const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
3081
- const setIdx = (0, import_react24.useCallback)(
3299
+ const setIdx = (0, import_react25.useCallback)(
3082
3300
  (n) => {
3083
3301
  setDraft((prev) => {
3084
3302
  const prevIdx = readPersistedStepIdx(prev);
@@ -3088,7 +3306,7 @@ function OnboardingFlow({
3088
3306
  },
3089
3307
  [setDraft]
3090
3308
  );
3091
- const setValue = (0, import_react24.useCallback)(
3309
+ const setValue = (0, import_react25.useCallback)(
3092
3310
  (patch) => {
3093
3311
  draftRef.current = { ...draftRef.current, ...patch };
3094
3312
  setDraft((prev) => ({ ...prev, ...patch }));
@@ -3096,9 +3314,9 @@ function OnboardingFlow({
3096
3314
  [setDraft]
3097
3315
  );
3098
3316
  const step = steps[clampedIdx];
3099
- const hookCtx = (0, import_sdk20.useHook)();
3317
+ const hookCtx = (0, import_sdk21.useHook)();
3100
3318
  const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
3101
- (0, import_react24.useEffect)(() => {
3319
+ (0, import_react25.useEffect)(() => {
3102
3320
  if (status.loading) return;
3103
3321
  if (!step) return;
3104
3322
  if (!track2) return;
@@ -3108,11 +3326,11 @@ function OnboardingFlow({
3108
3326
  total_steps: steps.length
3109
3327
  });
3110
3328
  }, [step?.id, clampedIdx, steps.length, status.loading, track2]);
3111
- const valid = (0, import_react24.useMemo)(
3329
+ const valid = (0, import_react25.useMemo)(
3112
3330
  () => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
3113
3331
  [draft, step]
3114
3332
  );
3115
- const next = (0, import_react24.useCallback)(() => {
3333
+ const next = (0, import_react25.useCallback)(() => {
3116
3334
  if (!step) return;
3117
3335
  const current = draftRef.current;
3118
3336
  const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
@@ -3123,8 +3341,8 @@ function OnboardingFlow({
3123
3341
  setIdx(clampedIdx + 1);
3124
3342
  }
3125
3343
  }, [clampedIdx, onComplete, step, steps.length, setIdx]);
3126
- const prevStep = (0, import_react24.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3127
- const ctx = (0, import_react24.useMemo)(
3344
+ const prevStep = (0, import_react25.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3345
+ const ctx = (0, import_react25.useMemo)(
3128
3346
  () => ({
3129
3347
  stepIndex: clampedIdx,
3130
3348
  totalSteps: steps.length,
@@ -3150,7 +3368,7 @@ function OnboardingFlow({
3150
3368
  `[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
3151
3369
  );
3152
3370
  }
3153
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Screen, {}) });
3371
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(Screen, {}) });
3154
3372
  }
3155
3373
 
3156
3374
  // src/hooks/useFeature.ts
@@ -3158,12 +3376,299 @@ function useFeature(name) {
3158
3376
  const config = useAppConfig();
3159
3377
  return Array.isArray(config.features_enabled) && config.features_enabled.includes(name);
3160
3378
  }
3379
+
3380
+ // src/components/paywall/Paywall.tsx
3381
+ var import_react26 = require("react");
3382
+ var import_sdk22 = require("@hook-sdk/sdk");
3383
+
3384
+ // src/components/paywall/PaywallMethodTabs.tsx
3385
+ var import_jsx_runtime30 = require("react/jsx-runtime");
3386
+ function PaywallMethodTabs({
3387
+ methods,
3388
+ selected,
3389
+ onSelect,
3390
+ labels,
3391
+ className,
3392
+ tabClassName,
3393
+ tabActiveClassName
3394
+ }) {
3395
+ if (methods.length < 2) return null;
3396
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("div", { role: "tablist", "aria-label": "M\xE9todo de pagamento", className, children: methods.map((m) => {
3397
+ const active = m === selected;
3398
+ const label = labels[m] ?? m;
3399
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
3400
+ "button",
3401
+ {
3402
+ type: "button",
3403
+ role: "tab",
3404
+ "aria-selected": active,
3405
+ "aria-controls": `paywall-tab-${m}`,
3406
+ tabIndex: active ? 0 : -1,
3407
+ onClick: () => onSelect(m),
3408
+ className: [tabClassName, active ? tabActiveClassName : ""].filter(Boolean).join(" "),
3409
+ children: label
3410
+ },
3411
+ m
3412
+ );
3413
+ }) });
3414
+ }
3415
+
3416
+ // src/components/paywall/PaywallMethodContent.tsx
3417
+ var import_jsx_runtime31 = require("react/jsx-runtime");
3418
+ function PaywallMethodContent({
3419
+ method,
3420
+ copy,
3421
+ hasConsumedTrial = false,
3422
+ className,
3423
+ rowClassName
3424
+ }) {
3425
+ const useCardConsumed = method === "card" && hasConsumedTrial && copy.cardConsumedTrial;
3426
+ const rows = useCardConsumed ? copy.cardConsumedTrial.bodyRows : method === "pix-auto" || method === "pix-once" ? copy.pix.bodyRows : copy.card.bodyRows;
3427
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { role: "tabpanel", id: `paywall-tab-${method}`, className, children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: rowClassName, children: row }, i)) });
3428
+ }
3429
+
3430
+ // src/components/paywall/PaywallCyclePicker.tsx
3431
+ var import_jsx_runtime32 = require("react/jsx-runtime");
3432
+ function PaywallCyclePicker({
3433
+ cycles,
3434
+ selected,
3435
+ onSelect,
3436
+ priceCentsByCycle,
3437
+ anchorCentsByCycle,
3438
+ monthlyEquivByCycle,
3439
+ labels,
3440
+ className,
3441
+ cardClassName,
3442
+ cardSelectedClassName,
3443
+ anchorClassName
3444
+ }) {
3445
+ if (cycles.length < 2) return null;
3446
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { role: "radiogroup", "aria-label": "Ciclo de cobran\xE7a", className, children: cycles.map((c) => {
3447
+ const active = c === selected;
3448
+ const label = c === "YEARLY" ? labels.annualLabel : labels.monthlyLabel;
3449
+ const suffix = c === "YEARLY" ? labels.annualSuffix : labels.monthlySuffix;
3450
+ const mainCents = c === "YEARLY" ? monthlyEquivByCycle[c] : priceCentsByCycle[c];
3451
+ const anchorCents = anchorCentsByCycle[c];
3452
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
3453
+ "button",
3454
+ {
3455
+ type: "button",
3456
+ role: "radio",
3457
+ "aria-checked": active,
3458
+ onClick: () => onSelect(c),
3459
+ className: ["flex flex-col items-center gap-0.5", cardClassName, active ? cardSelectedClassName : ""].filter(Boolean).join(" "),
3460
+ children: [
3461
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "font-bold text-base leading-tight", children: formatBRL(mainCents) }),
3462
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-xs opacity-70 leading-tight", children: suffix }),
3463
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-xs opacity-60 leading-tight", children: label }),
3464
+ anchorCents != null && anchorCents > mainCents ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: anchorClassName ?? "text-xs opacity-50", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("s", { children: formatBRL(anchorCents) }) }) : null
3465
+ ]
3466
+ },
3467
+ c
3468
+ );
3469
+ }) });
3470
+ }
3471
+
3472
+ // src/components/paywall/PaywallCta.tsx
3473
+ var import_jsx_runtime33 = require("react/jsx-runtime");
3474
+ function PaywallCta({
3475
+ ctaLabel,
3476
+ loadingLabel,
3477
+ switchHint,
3478
+ trustLine,
3479
+ onClick,
3480
+ disabled = false,
3481
+ loading = false,
3482
+ className,
3483
+ buttonClassName,
3484
+ switchHintClassName,
3485
+ trustClassName
3486
+ }) {
3487
+ const label = loading && loadingLabel ? loadingLabel : ctaLabel;
3488
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)("div", { className, children: [
3489
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
3490
+ "button",
3491
+ {
3492
+ type: "button",
3493
+ onClick,
3494
+ disabled: disabled || loading,
3495
+ className: buttonClassName,
3496
+ children: label
3497
+ }
3498
+ ),
3499
+ switchHint ? /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: switchHintClassName, children: switchHint }) : null,
3500
+ /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { className: trustClassName, children: trustLine })
3501
+ ] });
3502
+ }
3503
+
3504
+ // src/components/paywall/Paywall.tsx
3505
+ var import_jsx_runtime34 = require("react/jsx-runtime");
3506
+ var NBSP = "\xA0";
3507
+ function Paywall({
3508
+ copy,
3509
+ themeClasses = {},
3510
+ slots = {},
3511
+ onBeforeCheckout
3512
+ }) {
3513
+ const { track: track2 } = (0, import_sdk22.useHook)();
3514
+ const s = usePaywallState();
3515
+ const priceLabel = formatBRL(s.currentPriceCents).replace(new RegExp(NBSP, "g"), " ");
3516
+ const monthlyEquivLabel = formatBRL(s.currentMonthlyEquivCents).replace(new RegExp(NBSP, "g"), " ");
3517
+ const trialDaysCardLabel = String(s.trialDaysCard);
3518
+ const ctaLabel = (0, import_react26.useMemo)(() => {
3519
+ if (s.isFree) return copy.freeCta ?? "Come\xE7ar agora";
3520
+ if (s.selectedMethod === "card") {
3521
+ if (s.hasConsumedTrial && copy.cardConsumedTrial) {
3522
+ return interp(copy.cardConsumedTrial.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
3523
+ }
3524
+ if (s.trialDaysCard > 0) {
3525
+ return interp(copy.card.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
3526
+ }
3527
+ return copy.cardConsumedTrial ? interp(copy.cardConsumedTrial.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel }) : `Assinar por ${priceLabel}`;
3528
+ }
3529
+ return interp(copy.pix.ctaTemplate, { price: priceLabel, days: trialDaysCardLabel });
3530
+ }, [
3531
+ s.isFree,
3532
+ s.selectedMethod,
3533
+ s.hasConsumedTrial,
3534
+ s.trialDaysCard,
3535
+ copy,
3536
+ priceLabel,
3537
+ trialDaysCardLabel
3538
+ ]);
3539
+ const switchHint = (0, import_react26.useMemo)(() => {
3540
+ if (s.methods.length < 2) return void 0;
3541
+ return s.selectedMethod === "card" ? copy.card.switchHint : copy.pix.switchHint;
3542
+ }, [s.methods.length, s.selectedMethod, copy]);
3543
+ (0, import_react26.useEffect)(() => {
3544
+ if (!s.initialLoadComplete) return;
3545
+ track2("paywall_view", {
3546
+ default_method: s.selectedMethod,
3547
+ default_cycle: s.cycle,
3548
+ available_methods: s.methods
3549
+ });
3550
+ }, [s.initialLoadComplete]);
3551
+ const handleCta = async () => {
3552
+ track2("paywall_cta_clicked", {
3553
+ method: s.selectedMethod,
3554
+ cycle: s.cycle,
3555
+ price_cents: s.currentPriceCents,
3556
+ had_consumed_trial: s.hasConsumedTrial
3557
+ });
3558
+ if (onBeforeCheckout) {
3559
+ await onBeforeCheckout(s.selectedMethod, s.cycle);
3560
+ return;
3561
+ }
3562
+ await s.submit();
3563
+ };
3564
+ const ctaTheme = s.selectedMethod === "card" ? themeClasses.ctaCard : themeClasses.ctaPix;
3565
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("div", { className: themeClasses.container, children: [
3566
+ slots.heroSlot,
3567
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("h1", { className: themeClasses.headline, children: copy.headline }),
3568
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("ul", { children: copy.features.map((f) => /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)("li", { className: themeClasses.feature, children: [
3569
+ "\u2713 ",
3570
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("span", { children: f })
3571
+ ] }, f)) }),
3572
+ copy.socialProof ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)("p", { className: themeClasses.socialProof, children: copy.socialProof }) : null,
3573
+ slots.cyclePickerSlot ?? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3574
+ PaywallCyclePicker,
3575
+ {
3576
+ cycles: ["MONTHLY", "YEARLY"],
3577
+ selected: s.cycle,
3578
+ onSelect: s.selectCycle,
3579
+ priceCentsByCycle: {
3580
+ MONTHLY: priceCentsForCycle(s, "MONTHLY"),
3581
+ YEARLY: priceCentsForCycle(s, "YEARLY")
3582
+ },
3583
+ anchorCentsByCycle: {
3584
+ MONTHLY: anchorForCycle(s, "MONTHLY"),
3585
+ YEARLY: anchorForCycle(s, "YEARLY")
3586
+ },
3587
+ monthlyEquivByCycle: {
3588
+ MONTHLY: priceCentsForCycle(s, "MONTHLY"),
3589
+ YEARLY: Math.round(priceCentsForCycle(s, "YEARLY") / 12)
3590
+ },
3591
+ labels: copy.cycle,
3592
+ cardClassName: themeClasses.cycleCard,
3593
+ cardSelectedClassName: themeClasses.cycleCardSelected,
3594
+ anchorClassName: themeClasses.anchorPrice
3595
+ }
3596
+ ),
3597
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3598
+ PaywallMethodTabs,
3599
+ {
3600
+ methods: s.methods,
3601
+ selected: s.selectedMethod,
3602
+ onSelect: s.selectMethod,
3603
+ labels: { "pix-auto": copy.pix.tabLabel, card: copy.card.tabLabel },
3604
+ className: themeClasses.tabs,
3605
+ tabClassName: themeClasses.tab,
3606
+ tabActiveClassName: themeClasses.tabActive
3607
+ }
3608
+ ),
3609
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3610
+ PaywallMethodContent,
3611
+ {
3612
+ method: s.selectedMethod,
3613
+ copy: {
3614
+ pix: interpolateCopy(copy.pix, priceLabel, trialDaysCardLabel),
3615
+ card: interpolateCopy(copy.card, priceLabel, trialDaysCardLabel),
3616
+ cardConsumedTrial: copy.cardConsumedTrial ? {
3617
+ bodyRows: copy.cardConsumedTrial.bodyRows.map(
3618
+ (r) => interp(r, { price: priceLabel, days: trialDaysCardLabel })
3619
+ ),
3620
+ ctaTemplate: copy.cardConsumedTrial.ctaTemplate
3621
+ } : void 0
3622
+ },
3623
+ hasConsumedTrial: s.hasConsumedTrial,
3624
+ className: themeClasses.tabContent,
3625
+ rowClassName: themeClasses.tabContentRow
3626
+ }
3627
+ ),
3628
+ slots.beforeCtaSlot,
3629
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
3630
+ PaywallCta,
3631
+ {
3632
+ ctaLabel,
3633
+ loadingLabel: "Abrindo checkout\u2026",
3634
+ switchHint,
3635
+ trustLine: copy.trustLine,
3636
+ onClick: handleCta,
3637
+ disabled: s.submitting,
3638
+ loading: s.submitting,
3639
+ buttonClassName: ctaTheme,
3640
+ switchHintClassName: themeClasses.switchHint,
3641
+ trustClassName: themeClasses.trustLine
3642
+ }
3643
+ )
3644
+ ] });
3645
+ }
3646
+ function interp(tpl, vars) {
3647
+ return tpl.replace(/\{(\w+)\}/g, (_m, k) => vars[k] ?? "");
3648
+ }
3649
+ function interpolateCopy(m, price, days) {
3650
+ return {
3651
+ tabLabel: m.tabLabel,
3652
+ bodyRows: m.bodyRows.map((r) => interp(r, { price, days })),
3653
+ ctaTemplate: m.ctaTemplate,
3654
+ switchHint: m.switchHint
3655
+ };
3656
+ }
3657
+ function priceCentsForCycle(s, c) {
3658
+ return s.plan ? c === "YEARLY" ? s.plan.yearlyCents ?? 0 : s.plan.monthlyCents : 0;
3659
+ }
3660
+ function anchorForCycle(s, c) {
3661
+ if (!s.plan) return null;
3662
+ if (c === "YEARLY") return s.plan.anchorYearlyCents ?? null;
3663
+ return s.plan.anchorMonthlyCents ?? null;
3664
+ }
3161
3665
  // Annotate the CommonJS export names for ESM import in node:
3162
3666
  0 && (module.exports = {
3163
3667
  AppConfigProvider,
3164
3668
  AppConfigSchema,
3165
3669
  AppRoot,
3166
3670
  DeepLinkHandler,
3671
+ DevSkipOnboardingFab,
3167
3672
  EmptyState,
3168
3673
  ErrorBoundary,
3169
3674
  I18nProvider,
@@ -3173,6 +3678,11 @@ function useFeature(name) {
3173
3678
  LoadingState,
3174
3679
  OnboardingFlow,
3175
3680
  PaymentReturnHandler,
3681
+ Paywall,
3682
+ PaywallCta,
3683
+ PaywallCyclePicker,
3684
+ PaywallMethodContent,
3685
+ PaywallMethodTabs,
3176
3686
  PersistenceRegistry,
3177
3687
  PreAuthShell,
3178
3688
  PushPrompt,
@@ -3187,10 +3697,12 @@ function useFeature(name) {
3187
3697
  detectStandalone,
3188
3698
  discountPercent,
3189
3699
  formatBRL,
3700
+ isDevToolsEnabled,
3190
3701
  monthlyFromYearly,
3191
3702
  parseAppConfig,
3192
3703
  shouldBlockInstall,
3193
3704
  shouldShowPermanentOption,
3705
+ skipOnboarding,
3194
3706
  useAppConfig,
3195
3707
  useAuth,
3196
3708
  useAuthPrimitives,