@hook-sdk/template 0.14.0 → 0.15.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
@@ -69,9 +69,9 @@ __export(index_exports, {
69
69
  module.exports = __toCommonJS(index_exports);
70
70
 
71
71
  // src/AppRoot.tsx
72
- var import_react12 = require("react");
72
+ var import_react13 = require("react");
73
73
  var import_react_router_dom2 = require("react-router-dom");
74
- var import_sdk5 = require("@hook-sdk/sdk");
74
+ var import_sdk6 = require("@hook-sdk/sdk");
75
75
 
76
76
  // src/config/AppConfigContext.tsx
77
77
  var import_react = require("react");
@@ -147,7 +147,11 @@ var DeepLinksSchema = import_zod.z.object({
147
147
  var AppConfigSchema = import_zod.z.object({
148
148
  slug: import_zod.z.string().regex(/^[a-z0-9-]+$/),
149
149
  name: import_zod.z.string().min(1),
150
- branding: import_zod.z.object({ primaryColor: import_zod.z.string(), logoUrl: import_zod.z.string().url() }),
150
+ branding: import_zod.z.object({
151
+ primaryColor: import_zod.z.string(),
152
+ logoUrl: import_zod.z.string().url(),
153
+ iconUrl: import_zod.z.string().url().optional()
154
+ }),
151
155
  authFlow: AuthFlowSchema,
152
156
  paywall: PaywallSchema,
153
157
  persistedKeys: import_zod.z.array(PersistedKeySchema),
@@ -244,8 +248,8 @@ function ThemeProvider({ children }) {
244
248
  }
245
249
 
246
250
  // src/hooks/usePaywallState.ts
247
- var import_react5 = require("react");
248
- var import_sdk2 = require("@hook-sdk/sdk");
251
+ var import_react6 = require("react");
252
+ var import_sdk3 = require("@hook-sdk/sdk");
249
253
 
250
254
  // src/errors/asaas-pt-br.ts
251
255
  var MAP = {
@@ -266,6 +270,35 @@ function asaasErrorMessage(code) {
266
270
  return MAP[code] ?? "Ocorreu um erro inesperado. Tente novamente em instantes.";
267
271
  }
268
272
 
273
+ // src/hooks/usePaywallTracker.ts
274
+ var import_react5 = require("react");
275
+ var import_sdk2 = require("@hook-sdk/sdk");
276
+ function deriveStep(s) {
277
+ if (s.pixPaid) return "success";
278
+ if (s.hasError) return "error";
279
+ if (s.pixPendingShown) return "pix_qr_shown";
280
+ if (s.selectedMethod === "card" && s.cpfValid) return "card_form";
281
+ if (s.cpfRequired && !s.cpfValid) return "cpf_input";
282
+ if (s.selectedMethod) return "method_select";
283
+ return "plan_select";
284
+ }
285
+ function usePaywallTracker(snapshot) {
286
+ const ctx = (0, import_sdk2.useHook)();
287
+ const track2 = typeof ctx.track === "function" ? ctx.track : void 0;
288
+ const lastStepRef = (0, import_react5.useRef)(null);
289
+ const step = deriveStep(snapshot);
290
+ (0, import_react5.useEffect)(() => {
291
+ if (lastStepRef.current === step) return;
292
+ lastStepRef.current = step;
293
+ if (!track2) return;
294
+ track2("paywall_step_viewed", {
295
+ step,
296
+ method: snapshot.selectedMethod,
297
+ cycle: snapshot.cycle
298
+ });
299
+ }, [step]);
300
+ }
301
+
269
302
  // src/hooks/usePaywallState.ts
270
303
  function isCheckoutFailure(r) {
271
304
  return "ok" in r && r.ok === false;
@@ -280,11 +313,11 @@ var FALLBACK_PAYWALL = {
280
313
  };
281
314
  var isMethodAvailable = (availability, method) => availability[method] !== false;
282
315
  function usePaywallState() {
283
- const { subscription, plan } = (0, import_sdk2.useHook)();
284
- const configFromCtx = (0, import_react5.useContext)(AppConfigContext);
316
+ const { subscription, plan } = (0, import_sdk3.useHook)();
317
+ const configFromCtx = (0, import_react6.useContext)(AppConfigContext);
285
318
  const paywall = configFromCtx?.paywall ?? FALLBACK_PAYWALL;
286
319
  const isFree = paywall.mode === "free";
287
- const declaredMethods = (0, import_react5.useMemo)(
320
+ const declaredMethods = (0, import_react6.useMemo)(
288
321
  () => isFree ? [] : paywall.checkoutMethods,
289
322
  [isFree, paywall]
290
323
  );
@@ -293,33 +326,33 @@ function usePaywallState() {
293
326
  "pix-auto": null,
294
327
  "pix-once": null
295
328
  };
296
- const methods = (0, import_react5.useMemo)(
329
+ const methods = (0, import_react6.useMemo)(
297
330
  () => declaredMethods.filter((m) => isMethodAvailable(availability, m)),
298
331
  [declaredMethods, availability]
299
332
  );
300
333
  const defaultMethod = methods[0] ?? declaredMethods[0] ?? "card";
301
- const [selectedMethodRaw, setSelectedMethod] = (0, import_react5.useState)(defaultMethod);
334
+ const [selectedMethodRaw, setSelectedMethod] = (0, import_react6.useState)(defaultMethod);
302
335
  const selectedMethod = methods.includes(selectedMethodRaw) ? selectedMethodRaw : methods[0] ?? selectedMethodRaw;
303
336
  const initialCycle = isFree ? "MONTHLY" : paywall.cycles[0] ?? "MONTHLY";
304
- const [cycle, setCycle] = (0, import_react5.useState)(initialCycle);
337
+ const [cycle, setCycle] = (0, import_react6.useState)(initialCycle);
305
338
  const cpfRequired = !isFree && paywall.requiresCpf;
306
- const [cpf, setCpf] = (0, import_react5.useState)("");
307
- const cpfValid = (0, import_react5.useMemo)(() => /^[0-9]{11}$/.test(cpf), [cpf]);
308
- const [card, setCardState] = (0, import_react5.useState)({
339
+ const [cpf, setCpf] = (0, import_react6.useState)("");
340
+ const cpfValid = (0, import_react6.useMemo)(() => /^[0-9]{11}$/.test(cpf), [cpf]);
341
+ const [card, setCardState] = (0, import_react6.useState)({
309
342
  number: "",
310
343
  cvv: "",
311
344
  expiry: "",
312
345
  holder: ""
313
346
  });
314
- const setCard = (0, import_react5.useCallback)((patch) => {
347
+ const setCard = (0, import_react6.useCallback)((patch) => {
315
348
  setCardState((prev) => ({ ...prev, ...patch }));
316
349
  }, []);
317
- const [error, setError] = (0, import_react5.useState)(null);
318
- const [submitting, setSubmitting] = (0, import_react5.useState)(false);
350
+ const [error, setError] = (0, import_react6.useState)(null);
351
+ const [submitting, setSubmitting] = (0, import_react6.useState)(false);
319
352
  const status = subscription.status();
320
353
  const daysLeftInTrial = subscription.daysLeftInTrial();
321
354
  const initialLoadComplete = subscription.initialLoadComplete;
322
- const pixPending = (0, import_react5.useMemo)(() => {
355
+ const pixPending = (0, import_react6.useMemo)(() => {
323
356
  const sdkPix = subscription.pixPending;
324
357
  if (!sdkPix) return null;
325
358
  const liveStatus = subscription.current?.status;
@@ -332,7 +365,7 @@ function usePaywallState() {
332
365
  paid
333
366
  };
334
367
  }, [subscription.pixPending, subscription.current]);
335
- const monthlyEquivalent = (0, import_react5.useCallback)(
368
+ const monthlyEquivalent = (0, import_react6.useCallback)(
336
369
  (c) => {
337
370
  const monthlyCents = plan.data?.priceCents ?? (isFree ? 0 : paywall.prices.monthlyCents);
338
371
  const yearlyCents = plan.data?.yearlyPriceCents ?? (isFree ? null : paywall.prices.yearlyCents);
@@ -341,7 +374,7 @@ function usePaywallState() {
341
374
  },
342
375
  [plan, paywall, isFree]
343
376
  );
344
- const planDerived = (0, import_react5.useMemo)(() => {
377
+ const planDerived = (0, import_react6.useMemo)(() => {
345
378
  if (isFree) return null;
346
379
  const monthlyCents = paywall.prices.monthlyCents;
347
380
  const yearlyCents = paywall.prices.yearlyCents;
@@ -357,7 +390,7 @@ function usePaywallState() {
357
390
  };
358
391
  }, [paywall, cycle, isFree]);
359
392
  const useDefaultMessages = paywall.mode !== "free" && paywall.errorMessages === "default";
360
- const buildError = (0, import_react5.useCallback)(
393
+ const buildError = (0, import_react6.useCallback)(
361
394
  (code, fallbackMessage) => ({
362
395
  code,
363
396
  message: fallbackMessage,
@@ -365,7 +398,7 @@ function usePaywallState() {
365
398
  }),
366
399
  [useDefaultMessages]
367
400
  );
368
- const submit = (0, import_react5.useCallback)(async () => {
401
+ const submit = (0, import_react6.useCallback)(async () => {
369
402
  setSubmitting(true);
370
403
  setError(null);
371
404
  const methodToUse = selectedMethod;
@@ -427,7 +460,7 @@ function usePaywallState() {
427
460
  return void 0;
428
461
  }
429
462
  }, [selectedMethod, availability, subscription, cycle, cpf, card, buildError]);
430
- const checkout = (0, import_react5.useCallback)(
463
+ const checkout = (0, import_react6.useCallback)(
431
464
  async (args) => {
432
465
  setSubmitting(true);
433
466
  setError(null);
@@ -491,7 +524,7 @@ function usePaywallState() {
491
524
  },
492
525
  [subscription, buildError]
493
526
  );
494
- const cancel = (0, import_react5.useCallback)(async () => {
527
+ const cancel = (0, import_react6.useCallback)(async () => {
495
528
  try {
496
529
  await subscription.cancel();
497
530
  await subscription.refresh();
@@ -501,14 +534,24 @@ function usePaywallState() {
501
534
  setError(buildError(code, message));
502
535
  }
503
536
  }, [subscription, buildError]);
504
- const cardState = (0, import_react5.useMemo)(
537
+ const cardState = (0, import_react6.useMemo)(
505
538
  () => ({ ...card, set: setCard }),
506
539
  [card, setCard]
507
540
  );
508
- const cpfState = (0, import_react5.useMemo)(
541
+ const cpfState = (0, import_react6.useMemo)(
509
542
  () => ({ required: cpfRequired, value: cpf, set: setCpf, valid: cpfValid }),
510
543
  [cpfRequired, cpf, cpfValid]
511
544
  );
545
+ usePaywallTracker({
546
+ selectedMethod,
547
+ cycle,
548
+ cpfRequired,
549
+ cpfValid,
550
+ pixPendingShown: pixPending !== null,
551
+ pixPaid: pixPending?.paid === true,
552
+ hasError: error !== null,
553
+ submitting
554
+ });
512
555
  return {
513
556
  // Subscription status (reactive, proxied from SDK)
514
557
  status,
@@ -563,10 +606,11 @@ function SubscriptionGate({ Paywall, children }) {
563
606
  }
564
607
 
565
608
  // src/components/InstallGate/InstallGate.tsx
566
- var import_react8 = require("react");
609
+ var import_react9 = require("react");
567
610
 
568
611
  // src/hooks/useInstallPrompt.ts
569
- var import_react6 = require("react");
612
+ var import_react7 = require("react");
613
+ var ANDROID_PROMPT_WAIT_MS = 3e3;
570
614
  var IOS_RE = /iPad|iPhone|iPod/;
571
615
  var IOS_NON_SAFARI_RE = /CriOS|FxiOS|EdgiOS/;
572
616
  var ANDROID_RE = /Android/;
@@ -636,11 +680,12 @@ function track(event, props) {
636
680
  if (typeof window === "undefined") return;
637
681
  window.posthog?.capture?.(event, props);
638
682
  }
639
- function pickVariant(state) {
683
+ function pickVariant(state, promptWaitElapsed) {
640
684
  if (state.isInstalled) return "none";
641
685
  switch (state.platform) {
642
686
  case "android":
643
- return state.isInstallable ? "android-native" : "android-manual";
687
+ if (state.isInstallable) return "android-native";
688
+ return promptWaitElapsed ? "android-manual" : "android-pending";
644
689
  case "ios-safari":
645
690
  return "ios-safari";
646
691
  case "ios-other":
@@ -699,18 +744,27 @@ function useInstallPrompt(slug) {
699
744
  const iosBrowser = detectIOSBrowser(ua);
700
745
  const androidBrowser = detectAndroidBrowser(ua);
701
746
  const inAppApp = detectInAppApp(ua);
702
- const [isInstallable, setIsInstallable] = (0, import_react6.useState)(() => {
747
+ const [isInstallable, setIsInstallable] = (0, import_react7.useState)(() => {
703
748
  if (typeof window === "undefined") return false;
704
749
  return window.__pwaInstallPrompt != null;
705
750
  });
706
- const [isInstalled, setIsInstalled] = (0, import_react6.useState)(() => {
751
+ const [isInstalled, setIsInstalled] = (0, import_react7.useState)(() => {
707
752
  const { installed } = detectStandalone();
708
753
  return installed || readInstalledMarker(slug);
709
754
  });
710
- const [isDismissedSession, setIsDismissedSession] = (0, import_react6.useState)(() => readSessionSkip(slug));
711
- const [isDismissedPermanent, setIsDismissedPermanent] = (0, import_react6.useState)(() => readPermanentDismiss(slug).dismissed);
712
- const [skipCount, setSkipCount] = (0, import_react6.useState)(() => readSkipCount(slug));
713
- (0, import_react6.useEffect)(() => {
755
+ const [isDismissedSession, setIsDismissedSession] = (0, import_react7.useState)(() => readSessionSkip(slug));
756
+ const [isDismissedPermanent, setIsDismissedPermanent] = (0, import_react7.useState)(() => readPermanentDismiss(slug).dismissed);
757
+ const [skipCount, setSkipCount] = (0, import_react7.useState)(() => readSkipCount(slug));
758
+ const [promptWaitElapsed, setPromptWaitElapsed] = (0, import_react7.useState)(() => {
759
+ if (typeof window === "undefined") return true;
760
+ return window.__pwaInstallPrompt != null;
761
+ });
762
+ (0, import_react7.useEffect)(() => {
763
+ if (promptWaitElapsed) return;
764
+ const id = setTimeout(() => setPromptWaitElapsed(true), ANDROID_PROMPT_WAIT_MS);
765
+ return () => clearTimeout(id);
766
+ }, [promptWaitElapsed]);
767
+ (0, import_react7.useEffect)(() => {
714
768
  if (typeof window === "undefined") return;
715
769
  if (window.__pwaInstallPrompt) {
716
770
  setIsInstallable(true);
@@ -734,7 +788,7 @@ function useInstallPrompt(slug) {
734
788
  window.removeEventListener("appinstalled", onInstalled);
735
789
  };
736
790
  }, [slug]);
737
- (0, import_react6.useEffect)(() => {
791
+ (0, import_react7.useEffect)(() => {
738
792
  if (typeof window === "undefined") return;
739
793
  const mq = window.matchMedia?.("(display-mode: standalone)");
740
794
  if (!mq) return;
@@ -747,18 +801,21 @@ function useInstallPrompt(slug) {
747
801
  mq.addEventListener?.("change", handler);
748
802
  return () => mq.removeEventListener?.("change", handler);
749
803
  }, [slug]);
750
- const variant = pickVariant({
751
- platform,
752
- iosBrowser,
753
- androidBrowser,
754
- inAppApp,
755
- isInstallable,
756
- isInstalled,
757
- isDismissedSession,
758
- isDismissedPermanent,
759
- skipCount
760
- });
761
- const promptInstall = (0, import_react6.useCallback)(async () => {
804
+ const variant = pickVariant(
805
+ {
806
+ platform,
807
+ iosBrowser,
808
+ androidBrowser,
809
+ inAppApp,
810
+ isInstallable,
811
+ isInstalled,
812
+ isDismissedSession,
813
+ isDismissedPermanent,
814
+ skipCount
815
+ },
816
+ promptWaitElapsed
817
+ );
818
+ const promptInstall = (0, import_react7.useCallback)(async () => {
762
819
  if (typeof window === "undefined") return false;
763
820
  const prompt = window.__pwaInstallPrompt;
764
821
  if (!prompt) return false;
@@ -780,7 +837,7 @@ function useInstallPrompt(slug) {
780
837
  return false;
781
838
  }
782
839
  }, [slug]);
783
- const dismissSession = (0, import_react6.useCallback)(() => {
840
+ const dismissSession = (0, import_react7.useCallback)(() => {
784
841
  if (typeof sessionStorage !== "undefined") {
785
842
  try {
786
843
  sessionStorage.setItem(storageKey.sessionSkip(slug), "true");
@@ -794,20 +851,20 @@ function useInstallPrompt(slug) {
794
851
  setIsDismissedSession(true);
795
852
  track("pwa_install_session_skip", { slug, platform, skip_count: newCount });
796
853
  }, [slug, skipCount, platform]);
797
- const dismissPermanent = (0, import_react6.useCallback)(() => {
854
+ const dismissPermanent = (0, import_react7.useCallback)(() => {
798
855
  const storage = safeStorage();
799
856
  if (storage) storage.setItem(storageKey.dismissedAt(slug), (/* @__PURE__ */ new Date()).toISOString());
800
857
  setIsDismissedPermanent(true);
801
858
  track("pwa_install_permanent_dismiss", { slug, platform, prior_skip_count: skipCount });
802
859
  }, [slug, platform, skipCount]);
803
- const copyLink = (0, import_react6.useCallback)(async () => {
860
+ const copyLink = (0, import_react7.useCallback)(async () => {
804
861
  if (typeof navigator === "undefined" || typeof location === "undefined") return;
805
862
  try {
806
863
  await navigator.clipboard?.writeText?.(location.href);
807
864
  } catch {
808
865
  }
809
866
  }, []);
810
- const reset = (0, import_react6.useCallback)(() => {
867
+ const reset = (0, import_react7.useCallback)(() => {
811
868
  const storage = safeStorage();
812
869
  if (storage) {
813
870
  storage.removeItem(storageKey.dismissedAt(slug));
@@ -1293,15 +1350,51 @@ function Step({ n, icon, children }) {
1293
1350
  );
1294
1351
  }
1295
1352
 
1296
- // src/components/InstallGate/Step.tsx
1353
+ // src/components/InstallGate/variants/AndroidPendingVariant.tsx
1297
1354
  var import_jsx_runtime10 = require("react/jsx-runtime");
1355
+ function AndroidPendingVariant() {
1356
+ const copy = INSTALL_COPY.android.native;
1357
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(InstallSplash, { title: copy.title, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1358
+ "div",
1359
+ {
1360
+ style: {
1361
+ display: "flex",
1362
+ flexDirection: "column",
1363
+ alignItems: "center",
1364
+ gap: 16,
1365
+ padding: "24px 0"
1366
+ },
1367
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Spinner, {})
1368
+ }
1369
+ ) });
1370
+ }
1371
+ function Spinner() {
1372
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1373
+ "div",
1374
+ {
1375
+ "aria-hidden": true,
1376
+ style: {
1377
+ width: 28,
1378
+ height: 28,
1379
+ borderRadius: "50%",
1380
+ border: "3px solid #e5e5e7",
1381
+ borderTopColor: "var(--hook-color-primary)",
1382
+ animation: "hook-install-spin 0.8s linear infinite"
1383
+ },
1384
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("style", { children: `@keyframes hook-install-spin { to { transform: rotate(360deg); } }` })
1385
+ }
1386
+ );
1387
+ }
1388
+
1389
+ // src/components/InstallGate/Step.tsx
1390
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1298
1391
  function Step2({
1299
1392
  n,
1300
1393
  title,
1301
1394
  subtitle,
1302
1395
  visual
1303
1396
  }) {
1304
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1397
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1305
1398
  "div",
1306
1399
  {
1307
1400
  style: {
@@ -1312,7 +1405,7 @@ function Step2({
1312
1405
  textAlign: "left"
1313
1406
  },
1314
1407
  children: [
1315
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1408
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1316
1409
  "div",
1317
1410
  {
1318
1411
  style: {
@@ -1331,9 +1424,9 @@ function Step2({
1331
1424
  children: n
1332
1425
  }
1333
1426
  ),
1334
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: { flex: 1 }, children: [
1335
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { margin: 0, fontSize: 15, fontWeight: 500, color: "#111", lineHeight: 1.3 }, children: title }),
1336
- subtitle && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { style: { margin: "4px 0 0 0", fontSize: 13, color: "#777" }, children: subtitle }),
1427
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { flex: 1 }, children: [
1428
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { margin: 0, fontSize: 15, fontWeight: 500, color: "#111", lineHeight: 1.3 }, children: title }),
1429
+ subtitle && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { style: { margin: "4px 0 0 0", fontSize: 13, color: "#777" }, children: subtitle }),
1337
1430
  visual
1338
1431
  ] })
1339
1432
  ]
@@ -1342,21 +1435,21 @@ function Step2({
1342
1435
  }
1343
1436
 
1344
1437
  // src/components/InstallGate/variants/IOSafariVariant.tsx
1345
- var import_jsx_runtime11 = require("react/jsx-runtime");
1438
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1346
1439
  function IOSafariVariant({
1347
1440
  state,
1348
1441
  actions
1349
1442
  }) {
1350
1443
  const copy = INSTALL_COPY.iosSafari;
1351
1444
  const showPermanent = shouldShowPermanentOption(state);
1352
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
1353
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1445
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
1446
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1354
1447
  Step2,
1355
1448
  {
1356
1449
  n: 1,
1357
1450
  title: copy.step1.title,
1358
1451
  subtitle: copy.step1.subtitle,
1359
- visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1452
+ visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1360
1453
  "div",
1361
1454
  {
1362
1455
  style: {
@@ -1368,17 +1461,17 @@ function IOSafariVariant({
1368
1461
  padding: "12px 0",
1369
1462
  marginTop: 8
1370
1463
  },
1371
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
1464
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
1372
1465
  }
1373
1466
  )
1374
1467
  }
1375
1468
  ),
1376
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1469
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1377
1470
  Step2,
1378
1471
  {
1379
1472
  n: 2,
1380
1473
  title: copy.step2.title,
1381
- visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1474
+ visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1382
1475
  "div",
1383
1476
  {
1384
1477
  style: {
@@ -1391,19 +1484,19 @@ function IOSafariVariant({
1391
1484
  marginTop: 8
1392
1485
  },
1393
1486
  children: [
1394
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
1395
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
1487
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
1488
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
1396
1489
  ]
1397
1490
  }
1398
1491
  )
1399
1492
  }
1400
1493
  ),
1401
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1494
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1402
1495
  Step2,
1403
1496
  {
1404
1497
  n: 3,
1405
1498
  title: copy.step3.title,
1406
- visual: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1499
+ visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1407
1500
  "div",
1408
1501
  {
1409
1502
  style: {
@@ -1414,7 +1507,7 @@ function IOSafariVariant({
1414
1507
  padding: "10px 14px",
1415
1508
  marginTop: 8
1416
1509
  },
1417
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1510
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1418
1511
  "span",
1419
1512
  {
1420
1513
  style: {
@@ -1429,7 +1522,7 @@ function IOSafariVariant({
1429
1522
  )
1430
1523
  }
1431
1524
  ),
1432
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1525
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1433
1526
  "button",
1434
1527
  {
1435
1528
  "data-testid": "install-prompt-skip-session",
@@ -1439,7 +1532,7 @@ function IOSafariVariant({
1439
1532
  children: copy.skip
1440
1533
  }
1441
1534
  ),
1442
- showPermanent && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1535
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1443
1536
  "button",
1444
1537
  {
1445
1538
  "data-testid": "install-prompt-skip-permanent",
@@ -1453,21 +1546,21 @@ function IOSafariVariant({
1453
1546
  }
1454
1547
 
1455
1548
  // src/components/InstallGate/variants/IOSOtherVariant.tsx
1456
- var import_jsx_runtime12 = require("react/jsx-runtime");
1549
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1457
1550
  function IOSOtherVariant({
1458
1551
  state,
1459
1552
  actions
1460
1553
  }) {
1461
1554
  const copy = INSTALL_COPY.iosOther;
1462
1555
  const showPermanent = shouldShowPermanentOption(state);
1463
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
1464
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1556
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(InstallSplash, { title: copy.title, subtitle: copy.subtitle, children: [
1557
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1465
1558
  Step2,
1466
1559
  {
1467
1560
  n: 1,
1468
1561
  title: copy.step1.title,
1469
1562
  subtitle: copy.step1.subtitle,
1470
- visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1563
+ visual: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1471
1564
  "div",
1472
1565
  {
1473
1566
  style: {
@@ -1479,17 +1572,17 @@ function IOSOtherVariant({
1479
1572
  padding: "12px 0",
1480
1573
  marginTop: 8
1481
1574
  },
1482
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
1575
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ShareIconIOS, { size: 32, style: { color: "var(--hook-color-primary)" } })
1483
1576
  }
1484
1577
  )
1485
1578
  }
1486
1579
  ),
1487
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1580
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1488
1581
  Step2,
1489
1582
  {
1490
1583
  n: 2,
1491
1584
  title: copy.step2.title,
1492
- visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1585
+ visual: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1493
1586
  "div",
1494
1587
  {
1495
1588
  style: {
@@ -1502,19 +1595,19 @@ function IOSOtherVariant({
1502
1595
  marginTop: 8
1503
1596
  },
1504
1597
  children: [
1505
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
1506
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
1598
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SquarePlusIcon, { size: 22, style: { color: "#555" } }),
1599
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: 14, color: "#333" }, children: copy.step2.iconLabel })
1507
1600
  ]
1508
1601
  }
1509
1602
  )
1510
1603
  }
1511
1604
  ),
1512
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1605
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1513
1606
  Step2,
1514
1607
  {
1515
1608
  n: 3,
1516
1609
  title: copy.step3.title,
1517
- visual: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1610
+ visual: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1518
1611
  "div",
1519
1612
  {
1520
1613
  style: {
@@ -1525,7 +1618,7 @@ function IOSOtherVariant({
1525
1618
  padding: "10px 14px",
1526
1619
  marginTop: 8
1527
1620
  },
1528
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1621
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1529
1622
  "span",
1530
1623
  {
1531
1624
  style: {
@@ -1540,7 +1633,7 @@ function IOSOtherVariant({
1540
1633
  )
1541
1634
  }
1542
1635
  ),
1543
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1636
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1544
1637
  "button",
1545
1638
  {
1546
1639
  "data-testid": "install-prompt-skip-session",
@@ -1550,7 +1643,7 @@ function IOSOtherVariant({
1550
1643
  children: copy.skip
1551
1644
  }
1552
1645
  ),
1553
- showPermanent && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1646
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1554
1647
  "button",
1555
1648
  {
1556
1649
  "data-testid": "install-prompt-skip-permanent",
@@ -1564,8 +1657,8 @@ function IOSOtherVariant({
1564
1657
  }
1565
1658
 
1566
1659
  // src/components/InstallGate/variants/InAppBrowserVariant.tsx
1567
- var import_react7 = require("react");
1568
- var import_jsx_runtime13 = require("react/jsx-runtime");
1660
+ var import_react8 = require("react");
1661
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1569
1662
  function InAppBrowserVariant({
1570
1663
  state,
1571
1664
  actions
@@ -1574,17 +1667,17 @@ function InAppBrowserVariant({
1574
1667
  const appCopy = INSTALL_COPY.inApp[app] ?? INSTALL_COPY.inApp.other;
1575
1668
  const copy = INSTALL_COPY.inApp;
1576
1669
  const showPermanent = shouldShowPermanentOption(state);
1577
- const [copied, setCopied] = (0, import_react7.useState)(false);
1670
+ const [copied, setCopied] = (0, import_react8.useState)(false);
1578
1671
  const handleCopy = async () => {
1579
1672
  await actions.copyLink();
1580
1673
  setCopied(true);
1581
1674
  setTimeout(() => setCopied(false), 2e3);
1582
1675
  };
1583
1676
  const DotsIcon = app === "facebook" || app === "telegram" ? MenuDotsVerticalIcon : MenuDotsHorizontalIcon;
1584
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(InstallSplash, { title: appCopy.title, children: [
1585
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Step3, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(DotsIcon, { size: 20 }), children: appCopy.step1 }),
1586
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Step3, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ExternalLinkIcon, { size: 18 }), children: appCopy.step2 }),
1587
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1677
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(InstallSplash, { title: appCopy.title, children: [
1678
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Step3, { n: 1, icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DotsIcon, { size: 20 }), children: appCopy.step1 }),
1679
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Step3, { n: 2, icon: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ExternalLinkIcon, { size: 18 }), children: appCopy.step2 }),
1680
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1588
1681
  "button",
1589
1682
  {
1590
1683
  "data-testid": "install-prompt-cta-inapp-copy",
@@ -1594,7 +1687,7 @@ function InAppBrowserVariant({
1594
1687
  children: copied ? copy.copiedToast : copy.copy
1595
1688
  }
1596
1689
  ),
1597
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1690
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1598
1691
  "button",
1599
1692
  {
1600
1693
  "data-testid": "install-prompt-skip-session",
@@ -1604,7 +1697,7 @@ function InAppBrowserVariant({
1604
1697
  children: copy.skip
1605
1698
  }
1606
1699
  ),
1607
- showPermanent && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1700
+ showPermanent && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1608
1701
  "button",
1609
1702
  {
1610
1703
  "data-testid": "install-prompt-skip-permanent",
@@ -1621,7 +1714,7 @@ function Step3({
1621
1714
  icon,
1622
1715
  children
1623
1716
  }) {
1624
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1717
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1625
1718
  "div",
1626
1719
  {
1627
1720
  style: {
@@ -1635,7 +1728,7 @@ function Step3({
1635
1728
  textAlign: "left"
1636
1729
  },
1637
1730
  children: [
1638
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1731
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1639
1732
  "div",
1640
1733
  {
1641
1734
  style: {
@@ -1654,15 +1747,15 @@ function Step3({
1654
1747
  children: n
1655
1748
  }
1656
1749
  ),
1657
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flex: 1, fontSize: 14, color: "#333" }, children }),
1658
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
1750
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { flex: 1, fontSize: 14, color: "#333" }, children }),
1751
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "#888", flexShrink: 0 }, children: icon })
1659
1752
  ]
1660
1753
  }
1661
1754
  );
1662
1755
  }
1663
1756
 
1664
1757
  // src/components/InstallGate/variants/DesktopVariant.tsx
1665
- var import_jsx_runtime14 = require("react/jsx-runtime");
1758
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1666
1759
  function DesktopVariant({
1667
1760
  state,
1668
1761
  actions
@@ -1671,21 +1764,21 @@ function DesktopVariant({
1671
1764
  const copy = INSTALL_COPY.desktop;
1672
1765
  const iconUrl = theme.icon_url || theme.logo_url || null;
1673
1766
  if (!state.isInstallable) return null;
1674
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1767
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1675
1768
  "div",
1676
1769
  {
1677
1770
  role: "complementary",
1678
1771
  "aria-label": copy.title,
1679
1772
  style: bannerStyle,
1680
1773
  children: [
1681
- iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1774
+ iconUrl ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1682
1775
  "img",
1683
1776
  {
1684
1777
  src: iconUrl,
1685
1778
  alt: "",
1686
1779
  style: { width: 40, height: 40, borderRadius: 10, objectFit: "cover", flexShrink: 0 }
1687
1780
  }
1688
- ) : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1781
+ ) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1689
1782
  "div",
1690
1783
  {
1691
1784
  style: {
@@ -1704,11 +1797,11 @@ function DesktopVariant({
1704
1797
  children: name.charAt(0).toUpperCase()
1705
1798
  }
1706
1799
  ),
1707
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
1708
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 14, fontWeight: 600, color: "#111" }, children: copy.title }),
1709
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 12, color: "#666" }, children: copy.subtitle })
1800
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
1801
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontSize: 14, fontWeight: 600, color: "#111" }, children: copy.title }),
1802
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { fontSize: 12, color: "#666" }, children: copy.subtitle })
1710
1803
  ] }),
1711
- /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1804
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
1712
1805
  "button",
1713
1806
  {
1714
1807
  "data-testid": "install-prompt-cta-desktop",
@@ -1729,12 +1822,12 @@ function DesktopVariant({
1729
1822
  flexShrink: 0
1730
1823
  },
1731
1824
  children: [
1732
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(DownloadIcon, { size: 14 }),
1825
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DownloadIcon, { size: 14 }),
1733
1826
  copy.cta
1734
1827
  ]
1735
1828
  }
1736
1829
  ),
1737
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1830
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1738
1831
  "button",
1739
1832
  {
1740
1833
  "data-testid": "install-prompt-desktop-close",
@@ -1749,7 +1842,7 @@ function DesktopVariant({
1749
1842
  padding: 4,
1750
1843
  flexShrink: 0
1751
1844
  },
1752
- children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(XIcon, { size: 16 })
1845
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(XIcon, { size: 16 })
1753
1846
  }
1754
1847
  )
1755
1848
  ]
@@ -1773,14 +1866,14 @@ var bannerStyle = {
1773
1866
  };
1774
1867
 
1775
1868
  // src/components/InstallGate/InstallGate.tsx
1776
- var import_jsx_runtime15 = require("react/jsx-runtime");
1869
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1777
1870
  function InstallGate({ children }) {
1778
1871
  const { slug, features_enabled } = useTemplateConfig();
1779
1872
  const enabled = features_enabled.includes("install_prompt");
1780
1873
  const installState = useInstallPrompt(slug);
1781
1874
  const shouldBlock = enabled && shouldBlockInstall(installState);
1782
- const trackedRef = (0, import_react8.useRef)(null);
1783
- (0, import_react8.useEffect)(() => {
1875
+ const trackedRef = (0, import_react9.useRef)(null);
1876
+ (0, import_react9.useEffect)(() => {
1784
1877
  if (!shouldBlock) return;
1785
1878
  if (typeof window === "undefined") return;
1786
1879
  const variantKey = `${slug}:${installState.variant}`;
@@ -1794,30 +1887,32 @@ function InstallGate({ children }) {
1794
1887
  variant: installState.variant
1795
1888
  });
1796
1889
  }, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp]);
1797
- if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
1798
- if (installState.isInstalled) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
1890
+ if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1891
+ if (installState.isInstalled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1799
1892
  if (installState.variant === "desktop") {
1800
1893
  const showBanner = !installState.isDismissedSession && !installState.isDismissedPermanent;
1801
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
1894
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1802
1895
  children,
1803
- showBanner && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DesktopVariant, { state: installState, actions: installState })
1896
+ showBanner && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(DesktopVariant, { state: installState, actions: installState })
1804
1897
  ] });
1805
1898
  }
1806
- if (!shouldBlock) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
1899
+ if (!shouldBlock) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1807
1900
  switch (installState.variant) {
1808
1901
  case "android-native":
1809
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AndroidNativeVariant, { state: installState, actions: installState });
1902
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AndroidNativeVariant, { state: installState, actions: installState });
1810
1903
  case "android-manual":
1811
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(AndroidManualVariant, { state: installState, actions: installState });
1904
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AndroidManualVariant, { state: installState, actions: installState });
1905
+ case "android-pending":
1906
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AndroidPendingVariant, {});
1812
1907
  case "ios-safari":
1813
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IOSafariVariant, { state: installState, actions: installState });
1908
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IOSafariVariant, { state: installState, actions: installState });
1814
1909
  case "ios-other":
1815
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(IOSOtherVariant, { state: installState, actions: installState });
1910
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IOSOtherVariant, { state: installState, actions: installState });
1816
1911
  case "in-app":
1817
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(InAppBrowserVariant, { state: installState, actions: installState });
1912
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(InAppBrowserVariant, { state: installState, actions: installState });
1818
1913
  case "none":
1819
1914
  default:
1820
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_jsx_runtime15.Fragment, { children });
1915
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1821
1916
  }
1822
1917
  }
1823
1918
 
@@ -1827,16 +1922,16 @@ function PushPrompt() {
1827
1922
  }
1828
1923
 
1829
1924
  // src/internal/SessionExpiredBanner.tsx
1830
- var import_react9 = require("react");
1831
- var import_sdk3 = require("@hook-sdk/sdk");
1832
- var import_jsx_runtime16 = require("react/jsx-runtime");
1925
+ var import_react10 = require("react");
1926
+ var import_sdk4 = require("@hook-sdk/sdk");
1927
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1833
1928
  var DISMISS_KEY = "hook:session-expired-dismissed-until";
1834
1929
  var DISMISS_TTL_MS = 60 * 60 * 1e3;
1835
1930
  function SessionExpiredBanner() {
1836
- const { authStatus } = (0, import_sdk3.useHook)();
1837
- const wasAuthRef = (0, import_react9.useRef)(false);
1838
- const [show, setShow] = (0, import_react9.useState)(false);
1839
- (0, import_react9.useEffect)(() => {
1931
+ const { authStatus } = (0, import_sdk4.useHook)();
1932
+ const wasAuthRef = (0, import_react10.useRef)(false);
1933
+ const [show, setShow] = (0, import_react10.useState)(false);
1934
+ (0, import_react10.useEffect)(() => {
1840
1935
  if (authStatus === "authenticated") {
1841
1936
  wasAuthRef.current = true;
1842
1937
  setShow(false);
@@ -1856,13 +1951,13 @@ function SessionExpiredBanner() {
1856
1951
  localStorage.setItem(DISMISS_KEY, String(Date.now() + DISMISS_TTL_MS));
1857
1952
  setShow(false);
1858
1953
  }
1859
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { role: "alert", className: "fixed top-0 inset-x-0 bg-red-600 text-white px-4 py-2 flex items-center justify-between gap-3 text-sm shadow", style: { zIndex: 10001 }, children: [
1860
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { children: [
1861
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: "Sua sess\xE3o expirou." }),
1954
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { role: "alert", className: "fixed top-0 inset-x-0 bg-red-600 text-white px-4 py-2 flex items-center justify-between gap-3 text-sm shadow", style: { zIndex: 10001 }, children: [
1955
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { children: [
1956
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "Sua sess\xE3o expirou." }),
1862
1957
  " Fa\xE7a login novamente para continuar."
1863
1958
  ] }),
1864
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center gap-2", children: [
1865
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1959
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", children: [
1960
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1866
1961
  "button",
1867
1962
  {
1868
1963
  type: "button",
@@ -1871,7 +1966,7 @@ function SessionExpiredBanner() {
1871
1966
  children: "Fazer login"
1872
1967
  }
1873
1968
  ),
1874
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1969
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1875
1970
  "button",
1876
1971
  {
1877
1972
  type: "button",
@@ -1886,9 +1981,9 @@ function SessionExpiredBanner() {
1886
1981
  }
1887
1982
 
1888
1983
  // src/defaults/ErrorBoundary.tsx
1889
- var import_react10 = require("react");
1890
- var import_jsx_runtime17 = require("react/jsx-runtime");
1891
- var ErrorBoundary = class extends import_react10.Component {
1984
+ var import_react11 = require("react");
1985
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1986
+ var ErrorBoundary = class extends import_react11.Component {
1892
1987
  state = { error: null };
1893
1988
  static getDerivedStateFromError(error) {
1894
1989
  return { error };
@@ -1905,30 +2000,30 @@ var ErrorBoundary = class extends import_react10.Component {
1905
2000
  }
1906
2001
  render() {
1907
2002
  if (this.state.error) {
1908
- return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
1909
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { children: "Algo deu errado" }),
1910
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
2003
+ return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { role: "alert", style: { padding: 24, textAlign: "center" }, children: [
2004
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h2", { children: "Algo deu errado" }),
2005
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { style: { opacity: 0.7 }, children: "Recarregue a p\xE1gina pra tentar de novo." })
1911
2006
  ] });
1912
2007
  }
1913
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children: this.props.children });
2008
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children: this.props.children });
1914
2009
  }
1915
2010
  };
1916
2011
 
1917
2012
  // src/internal/PaymentReturnHandler.tsx
1918
- var import_react11 = require("react");
1919
- var import_sdk4 = require("@hook-sdk/sdk");
1920
- var import_jsx_runtime18 = require("react/jsx-runtime");
2013
+ var import_react12 = require("react");
2014
+ var import_sdk5 = require("@hook-sdk/sdk");
2015
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1921
2016
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
1922
2017
  var MAX_CYCLES = 3;
1923
2018
  var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
1924
2019
  function PaymentReturnHandler({ children }) {
1925
- const { subscription } = (0, import_sdk4.useHook)();
1926
- const subRef = (0, import_react11.useRef)(subscription);
2020
+ const { subscription } = (0, import_sdk5.useHook)();
2021
+ const subRef = (0, import_react12.useRef)(subscription);
1927
2022
  subRef.current = subscription;
1928
- const runIdRef = (0, import_react11.useRef)(0);
1929
- const cyclesRef = (0, import_react11.useRef)(0);
1930
- const [state, setState] = (0, import_react11.useState)("idle");
1931
- const runPoll = (0, import_react11.useCallback)(() => {
2023
+ const runIdRef = (0, import_react12.useRef)(0);
2024
+ const cyclesRef = (0, import_react12.useRef)(0);
2025
+ const [state, setState] = (0, import_react12.useState)("idle");
2026
+ const runPoll = (0, import_react12.useCallback)(() => {
1932
2027
  const runId = ++runIdRef.current;
1933
2028
  cyclesRef.current += 1;
1934
2029
  setState("confirming");
@@ -1963,7 +2058,7 @@ function PaymentReturnHandler({ children }) {
1963
2058
  };
1964
2059
  void tick();
1965
2060
  }, []);
1966
- (0, import_react11.useEffect)(() => {
2061
+ (0, import_react12.useEffect)(() => {
1967
2062
  if (typeof window === "undefined") return;
1968
2063
  const url = new URL(window.location.href);
1969
2064
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -1973,26 +2068,26 @@ function PaymentReturnHandler({ children }) {
1973
2068
  runIdRef.current++;
1974
2069
  };
1975
2070
  }, [runPoll]);
1976
- const goHome = (0, import_react11.useCallback)(() => {
2071
+ const goHome = (0, import_react12.useCallback)(() => {
1977
2072
  const cleanUrl = new URL(window.location.href);
1978
2073
  cleanUrl.searchParams.delete("paymentReturn");
1979
2074
  cleanUrl.pathname = "/app/home";
1980
2075
  window.location.href = cleanUrl.toString();
1981
2076
  }, []);
1982
2077
  if (state === "confirming") {
1983
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2078
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
1984
2079
  }
1985
2080
  if (state === "waiting") {
1986
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
1987
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
1988
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2081
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2082
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2083
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
1989
2084
  ] }) });
1990
2085
  }
1991
2086
  if (state === "timeout") {
1992
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
1993
- /* @__PURE__ */ (0, import_jsx_runtime18.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." }),
1994
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
1995
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2087
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
2088
+ /* @__PURE__ */ (0, import_jsx_runtime19.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." }),
2089
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2090
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
1996
2091
  "button",
1997
2092
  {
1998
2093
  type: "button",
@@ -2005,7 +2100,7 @@ function PaymentReturnHandler({ children }) {
2005
2100
  children: "Tentar de novo"
2006
2101
  }
2007
2102
  ),
2008
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2103
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2009
2104
  "button",
2010
2105
  {
2011
2106
  type: "button",
@@ -2015,7 +2110,7 @@ function PaymentReturnHandler({ children }) {
2015
2110
  children: "Voltar pro app"
2016
2111
  }
2017
2112
  ),
2018
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
2113
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2019
2114
  "a",
2020
2115
  {
2021
2116
  href: SUPPORT_MAILTO,
@@ -2027,7 +2122,7 @@ function PaymentReturnHandler({ children }) {
2027
2122
  ] })
2028
2123
  ] }) });
2029
2124
  }
2030
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_jsx_runtime18.Fragment, { children });
2125
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children });
2031
2126
  }
2032
2127
  var overlayStyle2 = {
2033
2128
  position: "fixed",
@@ -2066,7 +2161,7 @@ var linkStyle = {
2066
2161
  };
2067
2162
 
2068
2163
  // src/AppRoot.tsx
2069
- var import_jsx_runtime19 = require("react/jsx-runtime");
2164
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2070
2165
  function buildLegacyConfigShim(config) {
2071
2166
  const paywall = config.paywall;
2072
2167
  const isFree = paywall.mode === "free";
@@ -2076,7 +2171,16 @@ function buildLegacyConfigShim(config) {
2076
2171
  slug: config.slug,
2077
2172
  name: config.name,
2078
2173
  email_alias: config.slug,
2079
- theme: { primary_color: config.branding.primaryColor },
2174
+ // Map branding into the legacy theme shape so InstallSplash (and
2175
+ // anything else reading theme.icon_url / theme.logo_url) can surface
2176
+ // the app icon instead of the generic "first letter of name" fallback.
2177
+ // Falls back to logoUrl when iconUrl is unset — apps that haven't
2178
+ // adopted iconUrl keep their previous behavior unchanged.
2179
+ theme: {
2180
+ primary_color: config.branding.primaryColor,
2181
+ icon_url: config.branding.iconUrl ?? config.branding.logoUrl,
2182
+ logo_url: config.branding.logoUrl
2183
+ },
2080
2184
  features_enabled: config.features_enabled ?? [],
2081
2185
  dependencies_allowlist: ["react", "react-dom"],
2082
2186
  subscription: {
@@ -2130,14 +2234,14 @@ function AppRoot(props) {
2130
2234
  "[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
2131
2235
  );
2132
2236
  }
2133
- const legacyShim = (0, import_react12.useMemo)(() => buildLegacyConfigShim(config), [config]);
2237
+ const legacyShim = (0, import_react13.useMemo)(() => buildLegacyConfigShim(config), [config]);
2134
2238
  const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
2135
2239
  const basename = `/app/${config.slug}`;
2136
2240
  const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
2137
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(Router, { ...routerProps, children: [
2138
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2139
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SessionExpiredBanner, {}),
2140
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2241
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Router, { ...routerProps, children: [
2242
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2243
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SessionExpiredBanner, {}),
2244
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2141
2245
  AuthGated,
2142
2246
  {
2143
2247
  config,
@@ -2149,9 +2253,9 @@ function AppRoot(props) {
2149
2253
  Paywall,
2150
2254
  Onboarding,
2151
2255
  PreAuthFlow,
2152
- children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: [
2256
+ children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: [
2153
2257
  children,
2154
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PushPrompt, {})
2258
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PushPrompt, {})
2155
2259
  ] })
2156
2260
  }
2157
2261
  ) })
@@ -2167,37 +2271,37 @@ function AuthGated({
2167
2271
  EmailVerify,
2168
2272
  PreAuthFlow
2169
2273
  }) {
2170
- const { authStatus } = (0, import_sdk5.useHook)();
2274
+ const { authStatus } = (0, import_sdk6.useHook)();
2171
2275
  if (authStatus === "loading") return null;
2172
2276
  if (authStatus !== "authenticated") {
2173
2277
  if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
2174
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_router_dom2.Routes, { children: [
2175
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Login, {}) }),
2176
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Signup, {}) }),
2177
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Forgot, {}) }),
2178
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Reset, {}) }),
2179
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmailVerify, {}) }) : null,
2180
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PreAuthFlow, {}) })
2278
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_router_dom2.Routes, { children: [
2279
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Login, {}) }),
2280
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Signup, {}) }),
2281
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Forgot, {}) }),
2282
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Reset, {}) }),
2283
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EmailVerify, {}) }) : null,
2284
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PreAuthFlow, {}) })
2181
2285
  ] });
2182
2286
  }
2183
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_react_router_dom2.Routes, { children: [
2184
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Login, {}) }),
2185
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Signup, {}) }),
2186
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Forgot, {}) }),
2187
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Reset, {}) }),
2188
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(EmailVerify, {}) }) : null,
2189
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
2287
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_router_dom2.Routes, { children: [
2288
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Login, {}) }),
2289
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Signup, {}) }),
2290
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Forgot, {}) }),
2291
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Reset, {}) }),
2292
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EmailVerify, {}) }) : null,
2293
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
2190
2294
  ] });
2191
2295
  }
2192
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children });
2296
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, { children });
2193
2297
  }
2194
2298
  function FallbackPaywall() {
2195
2299
  return null;
2196
2300
  }
2197
2301
 
2198
2302
  // src/hooks/usePush.ts
2199
- var import_react13 = require("react");
2200
- var import_sdk6 = require("@hook-sdk/sdk");
2303
+ var import_react14 = require("react");
2304
+ var import_sdk7 = require("@hook-sdk/sdk");
2201
2305
  var DISMISS_STORAGE_KEY = "push:dismissed-until";
2202
2306
  var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
2203
2307
  function detectIosNeedsInstall() {
@@ -2241,12 +2345,12 @@ function deriveState(push) {
2241
2345
  return { kind: "prompt" };
2242
2346
  }
2243
2347
  function usePush() {
2244
- const { push } = (0, import_sdk6.useHook)();
2245
- const [state, setState] = (0, import_react13.useState)(() => deriveState(push));
2246
- (0, import_react13.useEffect)(() => {
2348
+ const { push } = (0, import_sdk7.useHook)();
2349
+ const [state, setState] = (0, import_react14.useState)(() => deriveState(push));
2350
+ (0, import_react14.useEffect)(() => {
2247
2351
  setState(deriveState(push));
2248
2352
  }, [push]);
2249
- const subscribe = (0, import_react13.useCallback)(async () => {
2353
+ const subscribe = (0, import_react14.useCallback)(async () => {
2250
2354
  try {
2251
2355
  await push.subscribe();
2252
2356
  setState({ kind: "subscribed" });
@@ -2258,7 +2362,7 @@ function usePush() {
2258
2362
  throw e;
2259
2363
  }
2260
2364
  }, [push]);
2261
- const unsubscribe = (0, import_react13.useCallback)(async () => {
2365
+ const unsubscribe = (0, import_react14.useCallback)(async () => {
2262
2366
  try {
2263
2367
  await push.unsubscribe();
2264
2368
  setState({ kind: "prompt" });
@@ -2267,7 +2371,7 @@ function usePush() {
2267
2371
  throw e;
2268
2372
  }
2269
2373
  }, [push]);
2270
- const dismiss = (0, import_react13.useCallback)(() => {
2374
+ const dismiss = (0, import_react14.useCallback)(() => {
2271
2375
  if (typeof localStorage !== "undefined") {
2272
2376
  try {
2273
2377
  localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
@@ -2280,7 +2384,7 @@ function usePush() {
2280
2384
  }
2281
2385
 
2282
2386
  // src/components/PushPrompt.tsx
2283
- var import_jsx_runtime20 = require("react/jsx-runtime");
2387
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2284
2388
  function platformRecoveryCopy(texts) {
2285
2389
  if (typeof navigator === "undefined") return null;
2286
2390
  const ua = navigator.userAgent || "";
@@ -2303,28 +2407,28 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2303
2407
  const { state, subscribe } = usePush();
2304
2408
  if (state.kind === "subscribed" || state.kind === "dismissed") return null;
2305
2409
  if (state.kind === "ios_needs_install") {
2306
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2307
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { children: texts.iosInstallTitle }),
2308
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: texts.iosInstallBody }),
2309
- onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2410
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2411
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { children: texts.iosInstallTitle }),
2412
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.iosInstallBody }),
2413
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2310
2414
  ] });
2311
2415
  }
2312
2416
  if (state.kind === "denied") {
2313
2417
  const recovery = platformRecoveryCopy(texts);
2314
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2315
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("h3", { children: texts.deniedTitle }),
2316
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: texts.deniedBody }),
2317
- recovery && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { "data-testid": "denied-recovery", children: recovery })
2418
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2419
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { children: texts.deniedTitle }),
2420
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.deniedBody }),
2421
+ recovery && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { "data-testid": "denied-recovery", children: recovery })
2318
2422
  ] });
2319
2423
  }
2320
2424
  if (state.kind === "unsupported") {
2321
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: texts.unsupportedBody }) });
2425
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.unsupportedBody }) });
2322
2426
  }
2323
2427
  if (state.kind === "error") {
2324
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { children: state.message }) });
2428
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: state.message }) });
2325
2429
  }
2326
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className, role: "region", children: [
2327
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2430
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", children: [
2431
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2328
2432
  "button",
2329
2433
  {
2330
2434
  type: "button",
@@ -2338,41 +2442,41 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2338
2442
  children: texts.cta
2339
2443
  }
2340
2444
  ),
2341
- onDeclined && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2445
+ onDeclined && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2342
2446
  ] });
2343
2447
  }
2344
2448
 
2345
2449
  // src/defaults/LoadingState.tsx
2346
- var import_jsx_runtime21 = require("react/jsx-runtime");
2450
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2347
2451
  function LoadingState({ message }) {
2348
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { children: message ?? "Carregando..." }) });
2452
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { children: message ?? "Carregando..." }) });
2349
2453
  }
2350
2454
 
2351
2455
  // src/defaults/EmptyState.tsx
2352
- var import_jsx_runtime22 = require("react/jsx-runtime");
2456
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2353
2457
  function EmptyState({ title, description, action }) {
2354
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2355
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2356
- description && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2357
- action && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { style: { marginTop: 16 }, children: action })
2458
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2459
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2460
+ description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2461
+ action && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { marginTop: 16 }, children: action })
2358
2462
  ] });
2359
2463
  }
2360
2464
 
2361
2465
  // src/hooks/useLoginForm.ts
2362
- var import_react14 = require("react");
2363
- var import_sdk8 = require("@hook-sdk/sdk");
2466
+ var import_react15 = require("react");
2467
+ var import_sdk9 = require("@hook-sdk/sdk");
2364
2468
 
2365
2469
  // src/errors.ts
2366
- var import_sdk7 = require("@hook-sdk/sdk");
2470
+ var import_sdk8 = require("@hook-sdk/sdk");
2367
2471
  function mapSdkError(err) {
2368
- if (err instanceof import_sdk7.SdkRateLimitError) {
2472
+ if (err instanceof import_sdk8.SdkRateLimitError) {
2369
2473
  return {
2370
2474
  code: "rate_limited",
2371
2475
  message: `Aguarde ${err.retryAfter}s e tente novamente.`,
2372
2476
  retryAfter: err.retryAfter
2373
2477
  };
2374
2478
  }
2375
- if (err instanceof import_sdk7.SdkAuthError) {
2479
+ if (err instanceof import_sdk8.SdkAuthError) {
2376
2480
  const detail = err.detail;
2377
2481
  if (detail === "email_unverified") {
2378
2482
  return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
@@ -2382,7 +2486,7 @@ function mapSdkError(err) {
2382
2486
  }
2383
2487
  return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
2384
2488
  }
2385
- if (err instanceof import_sdk7.SdkError && err.httpStatus === 0) {
2489
+ if (err instanceof import_sdk8.SdkError && err.httpStatus === 0) {
2386
2490
  return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
2387
2491
  }
2388
2492
  if (err instanceof TypeError) {
@@ -2395,20 +2499,20 @@ function mapSdkError(err) {
2395
2499
  var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2396
2500
  var MIN_PASSWORD = 8;
2397
2501
  function useLoginForm() {
2398
- const { auth } = (0, import_sdk8.useHook)();
2399
- const [email, setEmail] = (0, import_react14.useState)("");
2400
- const [password, setPassword] = (0, import_react14.useState)("");
2401
- const [submitting, setSubmitting] = (0, import_react14.useState)(false);
2402
- const [error, setError] = (0, import_react14.useState)(null);
2403
- const [touchedEmail, setTouchedEmail] = (0, import_react14.useState)(false);
2404
- const [touchedPassword, setTouchedPassword] = (0, import_react14.useState)(false);
2405
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react14.useState)(false);
2406
- const validateEmail = (0, import_react14.useMemo)(() => {
2502
+ const { auth } = (0, import_sdk9.useHook)();
2503
+ const [email, setEmail] = (0, import_react15.useState)("");
2504
+ const [password, setPassword] = (0, import_react15.useState)("");
2505
+ const [submitting, setSubmitting] = (0, import_react15.useState)(false);
2506
+ const [error, setError] = (0, import_react15.useState)(null);
2507
+ const [touchedEmail, setTouchedEmail] = (0, import_react15.useState)(false);
2508
+ const [touchedPassword, setTouchedPassword] = (0, import_react15.useState)(false);
2509
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react15.useState)(false);
2510
+ const validateEmail = (0, import_react15.useMemo)(() => {
2407
2511
  if (email.length === 0) return null;
2408
2512
  if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
2409
2513
  return null;
2410
2514
  }, [email]);
2411
- const validatePassword = (0, import_react14.useMemo)(() => {
2515
+ const validatePassword = (0, import_react15.useMemo)(() => {
2412
2516
  if (password.length === 0) return null;
2413
2517
  if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
2414
2518
  return null;
@@ -2416,7 +2520,7 @@ function useLoginForm() {
2416
2520
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2417
2521
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2418
2522
  const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
2419
- const submit = (0, import_react14.useCallback)(async () => {
2523
+ const submit = (0, import_react15.useCallback)(async () => {
2420
2524
  setFormSubmitAttempted(true);
2421
2525
  if (!canSubmit) return false;
2422
2526
  setSubmitting(true);
@@ -2450,32 +2554,32 @@ function useLoginForm() {
2450
2554
  }
2451
2555
 
2452
2556
  // src/hooks/useSignupForm.ts
2453
- var import_react15 = require("react");
2454
- var import_sdk9 = require("@hook-sdk/sdk");
2557
+ var import_react16 = require("react");
2558
+ var import_sdk10 = require("@hook-sdk/sdk");
2455
2559
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2456
2560
  var MIN_PASSWORD2 = 8;
2457
2561
  function useSignupForm() {
2458
- const { auth } = (0, import_sdk9.useHook)();
2459
- const [name, setName] = (0, import_react15.useState)("");
2460
- const [email, setEmail] = (0, import_react15.useState)("");
2461
- const [password, setPassword] = (0, import_react15.useState)("");
2462
- const [submitting, setSubmitting] = (0, import_react15.useState)(false);
2463
- const [error, setError] = (0, import_react15.useState)(null);
2464
- const [touchedName, setTouchedName] = (0, import_react15.useState)(false);
2465
- const [touchedEmail, setTouchedEmail] = (0, import_react15.useState)(false);
2466
- const [touchedPassword, setTouchedPassword] = (0, import_react15.useState)(false);
2467
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react15.useState)(false);
2468
- const validateName = (0, import_react15.useMemo)(() => {
2562
+ const { auth } = (0, import_sdk10.useHook)();
2563
+ const [name, setName] = (0, import_react16.useState)("");
2564
+ const [email, setEmail] = (0, import_react16.useState)("");
2565
+ const [password, setPassword] = (0, import_react16.useState)("");
2566
+ const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2567
+ const [error, setError] = (0, import_react16.useState)(null);
2568
+ const [touchedName, setTouchedName] = (0, import_react16.useState)(false);
2569
+ const [touchedEmail, setTouchedEmail] = (0, import_react16.useState)(false);
2570
+ const [touchedPassword, setTouchedPassword] = (0, import_react16.useState)(false);
2571
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react16.useState)(false);
2572
+ const validateName = (0, import_react16.useMemo)(() => {
2469
2573
  if (name.length === 0) return null;
2470
2574
  if (name.trim().length < 2) return "Nome muito curto.";
2471
2575
  return null;
2472
2576
  }, [name]);
2473
- const validateEmail = (0, import_react15.useMemo)(() => {
2577
+ const validateEmail = (0, import_react16.useMemo)(() => {
2474
2578
  if (email.length === 0) return null;
2475
2579
  if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
2476
2580
  return null;
2477
2581
  }, [email]);
2478
- const validatePassword = (0, import_react15.useMemo)(() => {
2582
+ const validatePassword = (0, import_react16.useMemo)(() => {
2479
2583
  if (password.length === 0) return null;
2480
2584
  if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
2481
2585
  return null;
@@ -2484,7 +2588,7 @@ function useSignupForm() {
2484
2588
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2485
2589
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2486
2590
  const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
2487
- const submit = (0, import_react15.useCallback)(async () => {
2591
+ const submit = (0, import_react16.useCallback)(async () => {
2488
2592
  setFormSubmitAttempted(true);
2489
2593
  if (!canSubmit) return false;
2490
2594
  setSubmitting(true);
@@ -2522,25 +2626,25 @@ function useSignupForm() {
2522
2626
  }
2523
2627
 
2524
2628
  // src/hooks/useForgotForm.ts
2525
- var import_react16 = require("react");
2526
- var import_sdk10 = require("@hook-sdk/sdk");
2629
+ var import_react17 = require("react");
2630
+ var import_sdk11 = require("@hook-sdk/sdk");
2527
2631
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2528
2632
  function useForgotForm() {
2529
- const { auth } = (0, import_sdk10.useHook)();
2530
- const [email, setEmail] = (0, import_react16.useState)("");
2531
- const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2532
- const [sent, setSent] = (0, import_react16.useState)(false);
2533
- const [error, setError] = (0, import_react16.useState)(null);
2534
- const [touchedEmail, setTouchedEmail] = (0, import_react16.useState)(false);
2535
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react16.useState)(false);
2536
- const validateEmail = (0, import_react16.useMemo)(() => {
2633
+ const { auth } = (0, import_sdk11.useHook)();
2634
+ const [email, setEmail] = (0, import_react17.useState)("");
2635
+ const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2636
+ const [sent, setSent] = (0, import_react17.useState)(false);
2637
+ const [error, setError] = (0, import_react17.useState)(null);
2638
+ const [touchedEmail, setTouchedEmail] = (0, import_react17.useState)(false);
2639
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
2640
+ const validateEmail = (0, import_react17.useMemo)(() => {
2537
2641
  if (email.length === 0) return null;
2538
2642
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
2539
2643
  return null;
2540
2644
  }, [email]);
2541
2645
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2542
2646
  const canSubmit = email.length > 0 && validateEmail === null && !submitting;
2543
- const submit = (0, import_react16.useCallback)(async () => {
2647
+ const submit = (0, import_react17.useCallback)(async () => {
2544
2648
  setFormSubmitAttempted(true);
2545
2649
  if (!canSubmit) return false;
2546
2650
  setSubmitting(true);
@@ -2571,32 +2675,32 @@ function useForgotForm() {
2571
2675
  }
2572
2676
 
2573
2677
  // src/hooks/useResetForm.ts
2574
- var import_react17 = require("react");
2575
- var import_sdk11 = require("@hook-sdk/sdk");
2678
+ var import_react18 = require("react");
2679
+ var import_sdk12 = require("@hook-sdk/sdk");
2576
2680
  var MIN_PASSWORD3 = 12;
2577
2681
  function useResetForm() {
2578
- const { auth } = (0, import_sdk11.useHook)();
2579
- const [token, setToken] = (0, import_react17.useState)(null);
2580
- const [password, setPassword] = (0, import_react17.useState)("");
2581
- const [confirm, setConfirm] = (0, import_react17.useState)("");
2582
- const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2583
- const [done, setDone] = (0, import_react17.useState)(false);
2584
- const [error, setError] = (0, import_react17.useState)(null);
2585
- const [touchedPassword, setTouchedPassword] = (0, import_react17.useState)(false);
2586
- const [touchedConfirm, setTouchedConfirm] = (0, import_react17.useState)(false);
2587
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
2588
- (0, import_react17.useEffect)(() => {
2682
+ const { auth } = (0, import_sdk12.useHook)();
2683
+ const [token, setToken] = (0, import_react18.useState)(null);
2684
+ const [password, setPassword] = (0, import_react18.useState)("");
2685
+ const [confirm, setConfirm] = (0, import_react18.useState)("");
2686
+ const [submitting, setSubmitting] = (0, import_react18.useState)(false);
2687
+ const [done, setDone] = (0, import_react18.useState)(false);
2688
+ const [error, setError] = (0, import_react18.useState)(null);
2689
+ const [touchedPassword, setTouchedPassword] = (0, import_react18.useState)(false);
2690
+ const [touchedConfirm, setTouchedConfirm] = (0, import_react18.useState)(false);
2691
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
2692
+ (0, import_react18.useEffect)(() => {
2589
2693
  if (typeof window === "undefined") return;
2590
2694
  const params = new URLSearchParams(window.location.search);
2591
2695
  const t = params.get("token");
2592
2696
  setToken(t && t.length > 0 ? t : null);
2593
2697
  }, []);
2594
- const validatePassword = (0, import_react17.useMemo)(() => {
2698
+ const validatePassword = (0, import_react18.useMemo)(() => {
2595
2699
  if (password.length === 0) return null;
2596
2700
  if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
2597
2701
  return null;
2598
2702
  }, [password]);
2599
- const validateConfirm = (0, import_react17.useMemo)(() => {
2703
+ const validateConfirm = (0, import_react18.useMemo)(() => {
2600
2704
  if (confirm.length === 0) return null;
2601
2705
  if (confirm !== password) return "Senhas n\xE3o coincidem.";
2602
2706
  return null;
@@ -2604,7 +2708,7 @@ function useResetForm() {
2604
2708
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2605
2709
  const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
2606
2710
  const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
2607
- const submit = (0, import_react17.useCallback)(async () => {
2711
+ const submit = (0, import_react18.useCallback)(async () => {
2608
2712
  setFormSubmitAttempted(true);
2609
2713
  if (!canSubmit || token === null) return;
2610
2714
  setSubmitting(true);
@@ -2644,9 +2748,9 @@ function useResetForm() {
2644
2748
  }
2645
2749
 
2646
2750
  // src/hooks/usePlan.ts
2647
- var import_sdk12 = require("@hook-sdk/sdk");
2751
+ var import_sdk13 = require("@hook-sdk/sdk");
2648
2752
  function usePlan() {
2649
- const { plan } = (0, import_sdk12.useHook)();
2753
+ const { plan } = (0, import_sdk13.useHook)();
2650
2754
  return plan;
2651
2755
  }
2652
2756
 
@@ -2679,12 +2783,12 @@ function discountPercent(anchorCents, realCents) {
2679
2783
  }
2680
2784
 
2681
2785
  // src/hooks/useAuthPrimitives.ts
2682
- var import_react18 = require("react");
2683
- var import_sdk13 = require("@hook-sdk/sdk");
2786
+ var import_react19 = require("react");
2787
+ var import_sdk14 = require("@hook-sdk/sdk");
2684
2788
  var warned = false;
2685
2789
  function useAuthPrimitives() {
2686
- const { auth } = (0, import_sdk13.useHook)();
2687
- (0, import_react18.useEffect)(() => {
2790
+ const { auth } = (0, import_sdk14.useHook)();
2791
+ (0, import_react19.useEffect)(() => {
2688
2792
  if (!warned && process.env.NODE_ENV !== "production") {
2689
2793
  warned = true;
2690
2794
  console.warn(
@@ -2706,9 +2810,9 @@ function useAuthPrimitives() {
2706
2810
  }
2707
2811
 
2708
2812
  // src/hooks/useAuth.ts
2709
- var import_sdk14 = require("@hook-sdk/sdk");
2813
+ var import_sdk15 = require("@hook-sdk/sdk");
2710
2814
  function useAuth() {
2711
- const { user, authStatus, auth } = (0, import_sdk14.useHook)();
2815
+ const { user, authStatus, auth } = (0, import_sdk15.useHook)();
2712
2816
  return {
2713
2817
  user,
2714
2818
  authStatus,
@@ -2717,23 +2821,23 @@ function useAuth() {
2717
2821
  }
2718
2822
 
2719
2823
  // src/hooks/useSubscription.ts
2720
- var import_sdk15 = require("@hook-sdk/sdk");
2824
+ var import_sdk16 = require("@hook-sdk/sdk");
2721
2825
  function useSubscription() {
2722
- const { subscription } = (0, import_sdk15.useHook)();
2826
+ const { subscription } = (0, import_sdk16.useHook)();
2723
2827
  return {
2724
2828
  status: subscription.status()
2725
2829
  };
2726
2830
  }
2727
2831
 
2728
2832
  // src/hooks/useReminders.ts
2729
- var import_react19 = require("react");
2730
- var import_sdk16 = require("@hook-sdk/sdk");
2833
+ var import_react20 = require("react");
2834
+ var import_sdk17 = require("@hook-sdk/sdk");
2731
2835
  function useReminders() {
2732
- const { push } = (0, import_sdk16.useHook)();
2836
+ const { push } = (0, import_sdk17.useHook)();
2733
2837
  const r = push.reminders;
2734
- const [reminders, setReminders] = (0, import_react19.useState)([]);
2735
- const [loading, setLoading] = (0, import_react19.useState)(true);
2736
- const reload = (0, import_react19.useCallback)(async () => {
2838
+ const [reminders, setReminders] = (0, import_react20.useState)([]);
2839
+ const [loading, setLoading] = (0, import_react20.useState)(true);
2840
+ const reload = (0, import_react20.useCallback)(async () => {
2737
2841
  setLoading(true);
2738
2842
  try {
2739
2843
  const next = await r.list();
@@ -2742,38 +2846,38 @@ function useReminders() {
2742
2846
  setLoading(false);
2743
2847
  }
2744
2848
  }, [r]);
2745
- (0, import_react19.useEffect)(() => {
2849
+ (0, import_react20.useEffect)(() => {
2746
2850
  void reload();
2747
2851
  }, [reload]);
2748
- const setReminder = (0, import_react19.useCallback)(async (input) => {
2852
+ const setReminder = (0, import_react20.useCallback)(async (input) => {
2749
2853
  await r.set(input);
2750
2854
  await reload();
2751
2855
  }, [r, reload]);
2752
- const deleteReminder = (0, import_react19.useCallback)(async (slot) => {
2856
+ const deleteReminder = (0, import_react20.useCallback)(async (slot) => {
2753
2857
  await r.delete(slot);
2754
2858
  await reload();
2755
2859
  }, [r, reload]);
2756
- const schedule = (0, import_react19.useCallback)(async (items) => {
2860
+ const schedule = (0, import_react20.useCallback)(async (items) => {
2757
2861
  return r.schedule(items);
2758
2862
  }, [r]);
2759
- const setFallbacks = (0, import_react19.useCallback)(async (items) => {
2863
+ const setFallbacks = (0, import_react20.useCallback)(async (items) => {
2760
2864
  return r.setFallbacks(items);
2761
2865
  }, [r]);
2762
2866
  return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
2763
2867
  }
2764
2868
 
2765
2869
  // src/hooks/useToast.ts
2766
- var import_react20 = require("react");
2870
+ var import_react21 = require("react");
2767
2871
  function useToast() {
2768
- const [items, setItems] = (0, import_react20.useState)([]);
2769
- const show = (0, import_react20.useCallback)((message, kind = "info") => {
2872
+ const [items, setItems] = (0, import_react21.useState)([]);
2873
+ const show = (0, import_react21.useCallback)((message, kind = "info") => {
2770
2874
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2771
2875
  setItems((prev) => [...prev, { id, message, kind }]);
2772
2876
  setTimeout(() => {
2773
2877
  setItems((prev) => prev.filter((t) => t.id !== id));
2774
2878
  }, 4e3);
2775
2879
  }, []);
2776
- const dismiss = (0, import_react20.useCallback)((id) => {
2880
+ const dismiss = (0, import_react21.useCallback)((id) => {
2777
2881
  setItems((prev) => prev.filter((t) => t.id !== id));
2778
2882
  }, []);
2779
2883
  return { items, show, dismiss };
@@ -2781,20 +2885,20 @@ function useToast() {
2781
2885
 
2782
2886
  // src/RouteBoundary.tsx
2783
2887
  var import_react_router_dom3 = require("react-router-dom");
2784
- var import_jsx_runtime23 = require("react/jsx-runtime");
2888
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2785
2889
  function RouteBoundary({ children }) {
2786
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_react_router_dom3.Routes, { children: [
2890
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_router_dom3.Routes, { children: [
2787
2891
  children,
2788
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DefaultNotFound, {}) })
2892
+ /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DefaultNotFound, {}) })
2789
2893
  ] });
2790
2894
  }
2791
2895
  function DefaultNotFound() {
2792
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
2896
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
2793
2897
  }
2794
2898
 
2795
2899
  // src/PreAuthShell.tsx
2796
2900
  var import_react_router_dom4 = require("react-router-dom");
2797
- var import_jsx_runtime24 = require("react/jsx-runtime");
2901
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2798
2902
  function PreAuthShell({
2799
2903
  basename,
2800
2904
  testRouter,
@@ -2802,20 +2906,20 @@ function PreAuthShell({
2802
2906
  children
2803
2907
  }) {
2804
2908
  if (testRouter === "memory") {
2805
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom4.Routes, { children }) });
2909
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_router_dom4.Routes, { children }) });
2806
2910
  }
2807
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom4.Routes, { children }) });
2911
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_router_dom4.Routes, { children }) });
2808
2912
  }
2809
2913
 
2810
2914
  // src/OnboardingFlow.tsx
2811
- var import_react22 = require("react");
2812
- var import_sdk17 = require("@hook-sdk/sdk");
2915
+ var import_react23 = require("react");
2916
+ var import_sdk18 = require("@hook-sdk/sdk");
2813
2917
 
2814
2918
  // src/hooks/useOnboardingStep.ts
2815
- var import_react21 = require("react");
2816
- var OnboardingStepContext = (0, import_react21.createContext)(null);
2919
+ var import_react22 = require("react");
2920
+ var OnboardingStepContext = (0, import_react22.createContext)(null);
2817
2921
  function useOnboardingStep() {
2818
- const ctx = (0, import_react21.useContext)(OnboardingStepContext);
2922
+ const ctx = (0, import_react22.useContext)(OnboardingStepContext);
2819
2923
  if (!ctx) {
2820
2924
  throw new Error(
2821
2925
  "[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
@@ -2825,7 +2929,7 @@ function useOnboardingStep() {
2825
2929
  }
2826
2930
 
2827
2931
  // src/OnboardingFlow.tsx
2828
- var import_jsx_runtime25 = require("react/jsx-runtime");
2932
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2829
2933
  var isFilled = (v) => v != null && v !== "";
2830
2934
  var CURRENT_STEP_FIELD = "currentStep";
2831
2935
  function readPersistedStepIdx(draft) {
@@ -2838,12 +2942,12 @@ function OnboardingFlow({
2838
2942
  onComplete,
2839
2943
  persistKey
2840
2944
  }) {
2841
- const [draft, setDraft, status] = (0, import_sdk17.usePersistedState)(persistKey, {});
2842
- const draftRef = (0, import_react22.useRef)(draft);
2945
+ const [draft, setDraft, status] = (0, import_sdk18.usePersistedState)(persistKey, {});
2946
+ const draftRef = (0, import_react23.useRef)(draft);
2843
2947
  draftRef.current = draft;
2844
2948
  const idx = readPersistedStepIdx(draft);
2845
2949
  const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
2846
- const setIdx = (0, import_react22.useCallback)(
2950
+ const setIdx = (0, import_react23.useCallback)(
2847
2951
  (n) => {
2848
2952
  setDraft((prev) => {
2849
2953
  const prevIdx = readPersistedStepIdx(prev);
@@ -2853,7 +2957,7 @@ function OnboardingFlow({
2853
2957
  },
2854
2958
  [setDraft]
2855
2959
  );
2856
- const setValue = (0, import_react22.useCallback)(
2960
+ const setValue = (0, import_react23.useCallback)(
2857
2961
  (patch) => {
2858
2962
  draftRef.current = { ...draftRef.current, ...patch };
2859
2963
  setDraft((prev) => ({ ...prev, ...patch }));
@@ -2861,11 +2965,23 @@ function OnboardingFlow({
2861
2965
  [setDraft]
2862
2966
  );
2863
2967
  const step = steps[clampedIdx];
2864
- const valid = (0, import_react22.useMemo)(
2968
+ const hookCtx = (0, import_sdk18.useHook)();
2969
+ const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
2970
+ (0, import_react23.useEffect)(() => {
2971
+ if (status.loading) return;
2972
+ if (!step) return;
2973
+ if (!track2) return;
2974
+ track2("onboarding_step_viewed", {
2975
+ step: step.id,
2976
+ step_index: clampedIdx,
2977
+ total_steps: steps.length
2978
+ });
2979
+ }, [step?.id, clampedIdx, steps.length, status.loading, track2]);
2980
+ const valid = (0, import_react23.useMemo)(
2865
2981
  () => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
2866
2982
  [draft, step]
2867
2983
  );
2868
- const next = (0, import_react22.useCallback)(() => {
2984
+ const next = (0, import_react23.useCallback)(() => {
2869
2985
  if (!step) return;
2870
2986
  const current = draftRef.current;
2871
2987
  const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
@@ -2876,8 +2992,8 @@ function OnboardingFlow({
2876
2992
  setIdx(clampedIdx + 1);
2877
2993
  }
2878
2994
  }, [clampedIdx, onComplete, step, steps.length, setIdx]);
2879
- const prevStep = (0, import_react22.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
2880
- const ctx = (0, import_react22.useMemo)(
2995
+ const prevStep = (0, import_react23.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
2996
+ const ctx = (0, import_react23.useMemo)(
2881
2997
  () => ({
2882
2998
  stepIndex: clampedIdx,
2883
2999
  totalSteps: steps.length,
@@ -2903,7 +3019,7 @@ function OnboardingFlow({
2903
3019
  `[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
2904
3020
  );
2905
3021
  }
2906
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(Screen, {}) });
3022
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Screen, {}) });
2907
3023
  }
2908
3024
 
2909
3025
  // src/hooks/useFeature.ts