@hook-sdk/template 0.18.1 → 0.20.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
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -26,8 +36,10 @@ __export(index_exports, {
26
36
  DeepLinkHandler: () => DeepLinkHandler,
27
37
  EmptyState: () => EmptyState,
28
38
  ErrorBoundary: () => ErrorBoundary,
39
+ I18nProvider: () => I18nProvider,
29
40
  InstallGate: () => InstallGate,
30
41
  InstallSplash: () => InstallSplash,
42
+ LanguageSwitcher: () => LanguageSwitcher,
31
43
  LoadingState: () => LoadingState,
32
44
  OnboardingFlow: () => OnboardingFlow,
33
45
  PaymentReturnHandler: () => PaymentReturnHandler,
@@ -65,14 +77,14 @@ __export(index_exports, {
65
77
  useSignupForm: () => useSignupForm,
66
78
  useSubscription: () => useSubscription,
67
79
  useToast: () => useToast,
68
- useTrackOnboardingStep: () => import_sdk19.useTrackOnboardingStep
80
+ useTrackOnboardingStep: () => import_sdk21.useTrackOnboardingStep
69
81
  });
70
82
  module.exports = __toCommonJS(index_exports);
71
83
 
72
84
  // src/AppRoot.tsx
73
- var import_react13 = require("react");
85
+ var import_react14 = require("react");
74
86
  var import_react_router_dom2 = require("react-router-dom");
75
- var import_sdk6 = require("@hook-sdk/sdk");
87
+ var import_sdk7 = require("@hook-sdk/sdk");
76
88
 
77
89
  // src/config/AppConfigContext.tsx
78
90
  var import_react = require("react");
@@ -145,6 +157,17 @@ var DeepLinksSchema = import_zod.z.object({
145
157
  passwordReset: import_zod.z.string().startsWith("/").optional(),
146
158
  emailVerify: import_zod.z.string().startsWith("/").optional()
147
159
  }).strict();
160
+ var I18nConfigSchema = import_zod.z.object({
161
+ defaultLocale: import_zod.z.string().min(2),
162
+ supportedLocales: import_zod.z.array(import_zod.z.string().min(2)).min(1),
163
+ resources: import_zod.z.record(import_zod.z.string(), import_zod.z.record(import_zod.z.string(), import_zod.z.string()))
164
+ }).strict().refine((v) => v.supportedLocales.includes(v.defaultLocale), {
165
+ message: "i18n.defaultLocale must be a member of i18n.supportedLocales",
166
+ path: ["defaultLocale"]
167
+ });
168
+ var InstallPromptSchema = import_zod.z.object({
169
+ position: import_zod.z.enum(["pre-auth", "post-paywall"]).optional()
170
+ }).strict();
148
171
  var AppConfigSchema = import_zod.z.object({
149
172
  slug: import_zod.z.string().regex(/^[a-z0-9-]+$/),
150
173
  name: import_zod.z.string().min(1),
@@ -158,12 +181,18 @@ var AppConfigSchema = import_zod.z.object({
158
181
  persistedKeys: import_zod.z.array(PersistedKeySchema),
159
182
  onboarding: OnboardingSchema.optional(),
160
183
  deepLinks: DeepLinksSchema.optional(),
184
+ i18n: I18nConfigSchema.optional(),
161
185
  features_enabled: import_zod.z.array(import_zod.z.string()).optional(),
186
+ install_prompt: InstallPromptSchema.optional(),
162
187
  // Build-time injected theme metadata (e.g. icon_url for InstallSplash).
163
188
  // Apps don't author this directly; deploy workflows fill it from
164
189
  // env-resolved bundle host. Permissive shape so apps/workflows can
165
190
  // extend without re-bumping the template schema.
166
- theme: import_zod.z.object({}).passthrough().optional()
191
+ theme: import_zod.z.object({}).passthrough().optional(),
192
+ // G133 — per-tenant public app-data keys allowlist. Optional; default
193
+ // backfill em migration 0044 = canonical 6. Apps com keys próprias
194
+ // declaram aqui pra evitar 402 spam pós-signup no SubscriptionGate.
195
+ publicKeys: import_zod.z.array(import_zod.z.string().regex(SnakeKeyRE)).optional()
167
196
  }).strict();
168
197
  function parseAppConfig(input) {
169
198
  const r = AppConfigSchema.safeParse(input);
@@ -323,7 +352,7 @@ var FALLBACK_PAYWALL = {
323
352
  };
324
353
  var isMethodAvailable = (availability, method) => availability[method] !== false;
325
354
  function usePaywallState() {
326
- const { subscription, plan } = (0, import_sdk3.useHook)();
355
+ const { subscription, plan, authStatus, track: track2 } = (0, import_sdk3.useHook)();
327
356
  const configFromCtx = (0, import_react6.useContext)(AppConfigContext);
328
357
  const paywall = configFromCtx?.paywall ?? FALLBACK_PAYWALL;
329
358
  const isFree = paywall.mode === "free";
@@ -412,6 +441,21 @@ function usePaywallState() {
412
441
  [useDefaultMessages]
413
442
  );
414
443
  const submit = (0, import_react6.useCallback)(async () => {
444
+ if (authStatus === "loading") return void 0;
445
+ if (authStatus !== "authenticated") {
446
+ track2("unauthenticated_submit_attempted", {
447
+ method: selectedMethod,
448
+ cycle,
449
+ cpf_valid: cpfValid
450
+ });
451
+ return void 0;
452
+ }
453
+ track2("payment_attempted", {
454
+ method: selectedMethod,
455
+ cycle,
456
+ cpf_valid: cpfValid,
457
+ selected_amount_cents: cycle === "YEARLY" ? plan.data?.yearlyPriceCents ?? (isFree ? 0 : paywall.prices.yearlyCents) : plan.data?.priceCents ?? (isFree ? 0 : paywall.prices.monthlyCents)
458
+ });
415
459
  setSubmitting(true);
416
460
  setError(null);
417
461
  const methodToUse = selectedMethod;
@@ -472,7 +516,7 @@ function usePaywallState() {
472
516
  setSubmitting(false);
473
517
  return void 0;
474
518
  }
475
- }, [selectedMethod, availability, subscription, cycle, cpf, card, buildError]);
519
+ }, [authStatus, track2, selectedMethod, availability, subscription, cycle, cpf, cpfValid, card, buildError, plan, paywall]);
476
520
  const checkout = (0, import_react6.useCallback)(
477
521
  async (args) => {
478
522
  setSubmitting(true);
@@ -1882,9 +1926,9 @@ var bannerStyle = {
1882
1926
 
1883
1927
  // src/components/InstallGate/InstallGate.tsx
1884
1928
  var import_jsx_runtime16 = require("react/jsx-runtime");
1885
- function InstallGate({ children }) {
1929
+ function InstallGate({ children, position }) {
1886
1930
  const { slug, features_enabled } = useTemplateConfig();
1887
- const enabled = features_enabled.includes("install_prompt");
1931
+ const enabled = features_enabled.includes("pwa-install");
1888
1932
  const installState = useInstallPrompt(slug);
1889
1933
  const shouldBlock = enabled && shouldBlockInstall(installState);
1890
1934
  const trackedRef = (0, import_react9.useRef)(null);
@@ -1899,9 +1943,10 @@ function InstallGate({ children }) {
1899
1943
  platform: installState.platform,
1900
1944
  browser: installState.iosBrowser ?? installState.androidBrowser ?? null,
1901
1945
  in_app_app: installState.inAppApp,
1902
- variant: installState.variant
1946
+ variant: installState.variant,
1947
+ ...position !== void 0 ? { position } : {}
1903
1948
  });
1904
- }, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp]);
1949
+ }, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp, position]);
1905
1950
  if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1906
1951
  if (installState.isInstalled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1907
1952
  if (installState.variant === "desktop") {
@@ -2024,23 +2069,66 @@ var ErrorBoundary = class extends import_react11.Component {
2024
2069
  }
2025
2070
  };
2026
2071
 
2027
- // src/internal/PaymentReturnHandler.tsx
2072
+ // src/i18n/I18nProvider.tsx
2028
2073
  var import_react12 = require("react");
2074
+ var import_i18next = __toESM(require("i18next"), 1);
2075
+ var import_react_i18next = require("react-i18next");
2029
2076
  var import_sdk5 = require("@hook-sdk/sdk");
2030
2077
  var import_jsx_runtime19 = require("react/jsx-runtime");
2078
+ function ensureInitialized(defaultLocale, supportedLocales, resources, initialLocale) {
2079
+ if (import_i18next.default.isInitialized) return;
2080
+ import_i18next.default.use(import_react_i18next.initReactI18next).init({
2081
+ resources: Object.fromEntries(
2082
+ supportedLocales.map((l) => [l, { translation: resources[l] ?? {} }])
2083
+ ),
2084
+ lng: initialLocale,
2085
+ fallbackLng: defaultLocale,
2086
+ interpolation: { escapeValue: false },
2087
+ // useTranslation suspends by default until i18next is "ready". Inline
2088
+ // resources are sync, so suspending creates a guaranteed empty render
2089
+ // tick — confusing in apps and breaks tests that don't use Suspense.
2090
+ react: { useSuspense: false }
2091
+ });
2092
+ }
2093
+ function I18nProvider({
2094
+ defaultLocale,
2095
+ supportedLocales,
2096
+ resources,
2097
+ children
2098
+ }) {
2099
+ const [userLocale] = (0, import_sdk5.usePersistedState)("user-locale", defaultLocale);
2100
+ ensureInitialized(defaultLocale, supportedLocales, resources, userLocale);
2101
+ (0, import_react12.useEffect)(() => {
2102
+ if (import_i18next.default.isInitialized && import_i18next.default.language !== userLocale) {
2103
+ import_i18next.default.changeLanguage(userLocale);
2104
+ }
2105
+ }, [userLocale]);
2106
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_i18next.I18nextProvider, { i18n: import_i18next.default, children });
2107
+ }
2108
+
2109
+ // src/internal/PaymentReturnHandler.tsx
2110
+ var import_react13 = require("react");
2111
+ var import_sdk6 = require("@hook-sdk/sdk");
2112
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2031
2113
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
2032
2114
  var MAX_CYCLES = 3;
2033
2115
  var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
2034
2116
  function PaymentReturnHandler({ children }) {
2035
- const { subscription } = (0, import_sdk5.useHook)();
2036
- const subRef = (0, import_react12.useRef)(subscription);
2117
+ const { subscription, track: track2 } = (0, import_sdk6.useHook)();
2118
+ const subRef = (0, import_react13.useRef)(subscription);
2037
2119
  subRef.current = subscription;
2038
- const runIdRef = (0, import_react12.useRef)(0);
2039
- const cyclesRef = (0, import_react12.useRef)(0);
2040
- const [state, setState] = (0, import_react12.useState)("idle");
2041
- const runPoll = (0, import_react12.useCallback)(() => {
2120
+ const runIdRef = (0, import_react13.useRef)(0);
2121
+ const cyclesRef = (0, import_react13.useRef)(0);
2122
+ const startMsRef = (0, import_react13.useRef)(0);
2123
+ const [state, setState] = (0, import_react13.useState)("idle");
2124
+ const runPoll = (0, import_react13.useCallback)(() => {
2042
2125
  const runId = ++runIdRef.current;
2126
+ const isFirstRun = cyclesRef.current === 0;
2043
2127
  cyclesRef.current += 1;
2128
+ if (isFirstRun) {
2129
+ startMsRef.current = Date.now();
2130
+ track2("payment_confirmation_started", {});
2131
+ }
2044
2132
  setState("confirming");
2045
2133
  let attempts = 0;
2046
2134
  const tick = async () => {
@@ -2053,6 +2141,11 @@ function PaymentReturnHandler({ children }) {
2053
2141
  if (runIdRef.current !== runId) return;
2054
2142
  const status = subRef.current.status();
2055
2143
  if (status === "active" || status === "trialing") {
2144
+ track2("payment_confirmation_succeeded", {
2145
+ cycle_count: cyclesRef.current,
2146
+ attempt_count: attempts,
2147
+ duration_ms: Date.now() - startMsRef.current
2148
+ });
2056
2149
  const cleanUrl = new URL(window.location.href);
2057
2150
  cleanUrl.searchParams.delete("paymentReturn");
2058
2151
  window.history.replaceState({}, "", cleanUrl.toString());
@@ -2063,6 +2156,9 @@ function PaymentReturnHandler({ children }) {
2063
2156
  const delay = BACKOFF_MS[attempts - 1];
2064
2157
  if (delay === void 0) {
2065
2158
  if (cyclesRef.current >= MAX_CYCLES) {
2159
+ track2("payment_confirmation_timed_out", {
2160
+ total_duration_ms: Date.now() - startMsRef.current
2161
+ });
2066
2162
  setState("timeout");
2067
2163
  } else {
2068
2164
  setState("waiting");
@@ -2072,8 +2168,8 @@ function PaymentReturnHandler({ children }) {
2072
2168
  setTimeout(tick, delay);
2073
2169
  };
2074
2170
  void tick();
2075
- }, []);
2076
- (0, import_react12.useEffect)(() => {
2171
+ }, [track2]);
2172
+ (0, import_react13.useEffect)(() => {
2077
2173
  if (typeof window === "undefined") return;
2078
2174
  const url = new URL(window.location.href);
2079
2175
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -2083,26 +2179,26 @@ function PaymentReturnHandler({ children }) {
2083
2179
  runIdRef.current++;
2084
2180
  };
2085
2181
  }, [runPoll]);
2086
- const goHome = (0, import_react12.useCallback)(() => {
2182
+ const goHome = (0, import_react13.useCallback)(() => {
2087
2183
  const cleanUrl = new URL(window.location.href);
2088
2184
  cleanUrl.searchParams.delete("paymentReturn");
2089
2185
  cleanUrl.pathname = "/app/home";
2090
2186
  window.location.href = cleanUrl.toString();
2091
2187
  }, []);
2092
2188
  if (state === "confirming") {
2093
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2189
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2094
2190
  }
2095
2191
  if (state === "waiting") {
2096
- 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: [
2097
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2098
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2192
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { maxWidth: 320, textAlign: "center", lineHeight: 1.5 }, children: [
2193
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2194
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2099
2195
  ] }) });
2100
2196
  }
2101
2197
  if (state === "timeout") {
2102
- 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: [
2103
- /* @__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." }),
2104
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2105
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2198
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "alert", "aria-live": "assertive", style: overlayStyle2, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { maxWidth: 360, textAlign: "center", lineHeight: 1.5 }, children: [
2199
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginBottom: 16 }, children: "Ainda n\xE3o conseguimos confirmar seu pagamento com o banco. Voc\xEA pode tentar de novo, voltar pro app, ou falar com a gente." }),
2200
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2201
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2106
2202
  "button",
2107
2203
  {
2108
2204
  type: "button",
@@ -2115,7 +2211,7 @@ function PaymentReturnHandler({ children }) {
2115
2211
  children: "Tentar de novo"
2116
2212
  }
2117
2213
  ),
2118
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2214
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2119
2215
  "button",
2120
2216
  {
2121
2217
  type: "button",
@@ -2125,7 +2221,7 @@ function PaymentReturnHandler({ children }) {
2125
2221
  children: "Voltar pro app"
2126
2222
  }
2127
2223
  ),
2128
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2224
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2129
2225
  "a",
2130
2226
  {
2131
2227
  href: SUPPORT_MAILTO,
@@ -2137,7 +2233,7 @@ function PaymentReturnHandler({ children }) {
2137
2233
  ] })
2138
2234
  ] }) });
2139
2235
  }
2140
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children });
2236
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, { children });
2141
2237
  }
2142
2238
  var overlayStyle2 = {
2143
2239
  position: "fixed",
@@ -2176,7 +2272,7 @@ var linkStyle = {
2176
2272
  };
2177
2273
 
2178
2274
  // src/AppRoot.tsx
2179
- var import_jsx_runtime20 = require("react/jsx-runtime");
2275
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2180
2276
  function buildLegacyConfigShim(config) {
2181
2277
  const paywall = config.paywall;
2182
2278
  const isFree = paywall.mode === "free";
@@ -2249,32 +2345,47 @@ function AppRoot(props) {
2249
2345
  "[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
2250
2346
  );
2251
2347
  }
2252
- const legacyShim = (0, import_react13.useMemo)(() => buildLegacyConfigShim(config), [config]);
2348
+ const legacyShim = (0, import_react14.useMemo)(() => buildLegacyConfigShim(config), [config]);
2253
2349
  const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
2254
2350
  const basename = `/app/${config.slug}`;
2255
2351
  const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
2256
- 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: [
2257
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2258
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SessionExpiredBanner, {}),
2259
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2260
- AuthGated,
2261
- {
2262
- config,
2263
- Login,
2264
- Signup,
2265
- Forgot,
2266
- Reset,
2267
- EmailVerify,
2268
- Paywall,
2269
- Onboarding,
2270
- PreAuthFlow,
2271
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: [
2272
- children,
2273
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PushPrompt, {})
2274
- ] })
2275
- }
2276
- ) })
2277
- ] }) }) }) }) }) });
2352
+ const position = config.install_prompt?.position ?? "post-paywall";
2353
+ const subscriptionGated = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: position === "post-paywall" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(InstallGate, { position: "post-paywall", children: [
2354
+ children,
2355
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PushPrompt, {})
2356
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2357
+ children,
2358
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PushPrompt, {})
2359
+ ] }) });
2360
+ const authGated = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2361
+ AuthGated,
2362
+ {
2363
+ config,
2364
+ Login,
2365
+ Signup,
2366
+ Forgot,
2367
+ Reset,
2368
+ EmailVerify,
2369
+ Paywall,
2370
+ Onboarding,
2371
+ PreAuthFlow,
2372
+ children: subscriptionGated
2373
+ }
2374
+ );
2375
+ const routedTree = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Router, { ...routerProps, children: [
2376
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2377
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SessionExpiredBanner, {}),
2378
+ position === "pre-auth" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InstallGate, { position: "pre-auth", children: authGated }) : authGated
2379
+ ] });
2380
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AppConfigProvider, { config, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(TemplateConfigProvider, { config: legacyShim, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ThemeProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PersistenceRegistry, { config: config.persistedKeys, children: config.i18n ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2381
+ I18nProvider,
2382
+ {
2383
+ defaultLocale: config.i18n.defaultLocale,
2384
+ supportedLocales: config.i18n.supportedLocales,
2385
+ resources: config.i18n.resources,
2386
+ children: routedTree
2387
+ }
2388
+ ) : routedTree }) }) }) }) });
2278
2389
  }
2279
2390
  function AuthGated({
2280
2391
  children,
@@ -2286,37 +2397,37 @@ function AuthGated({
2286
2397
  EmailVerify,
2287
2398
  PreAuthFlow
2288
2399
  }) {
2289
- const { authStatus } = (0, import_sdk6.useHook)();
2400
+ const { authStatus } = (0, import_sdk7.useHook)();
2290
2401
  if (authStatus === "loading") return null;
2291
2402
  if (authStatus !== "authenticated") {
2292
2403
  if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
2293
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_router_dom2.Routes, { children: [
2294
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Login, {}) }),
2295
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Signup, {}) }),
2296
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Forgot, {}) }),
2297
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Reset, {}) }),
2298
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EmailVerify, {}) }) : null,
2299
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PreAuthFlow, {}) })
2404
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_router_dom2.Routes, { children: [
2405
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Login, {}) }),
2406
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Signup, {}) }),
2407
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Forgot, {}) }),
2408
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Reset, {}) }),
2409
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EmailVerify, {}) }) : null,
2410
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PreAuthFlow, {}) })
2300
2411
  ] });
2301
2412
  }
2302
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_router_dom2.Routes, { children: [
2303
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Login, {}) }),
2304
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Signup, {}) }),
2305
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Forgot, {}) }),
2306
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Reset, {}) }),
2307
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EmailVerify, {}) }) : null,
2308
- /* @__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 }) })
2413
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_router_dom2.Routes, { children: [
2414
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Login, {}) }),
2415
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Signup, {}) }),
2416
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Forgot, {}) }),
2417
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Reset, {}) }),
2418
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EmailVerify, {}) }) : null,
2419
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Navigate, { to: "/", replace: true }) })
2309
2420
  ] });
2310
2421
  }
2311
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, { children });
2422
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children });
2312
2423
  }
2313
2424
  function FallbackPaywall() {
2314
2425
  return null;
2315
2426
  }
2316
2427
 
2317
2428
  // src/hooks/usePush.ts
2318
- var import_react14 = require("react");
2319
- var import_sdk7 = require("@hook-sdk/sdk");
2429
+ var import_react15 = require("react");
2430
+ var import_sdk8 = require("@hook-sdk/sdk");
2320
2431
  var DISMISS_STORAGE_KEY = "push:dismissed-until";
2321
2432
  var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
2322
2433
  function detectIosNeedsInstall() {
@@ -2360,12 +2471,12 @@ function deriveState(push) {
2360
2471
  return { kind: "prompt" };
2361
2472
  }
2362
2473
  function usePush() {
2363
- const { push } = (0, import_sdk7.useHook)();
2364
- const [state, setState] = (0, import_react14.useState)(() => deriveState(push));
2365
- (0, import_react14.useEffect)(() => {
2474
+ const { push } = (0, import_sdk8.useHook)();
2475
+ const [state, setState] = (0, import_react15.useState)(() => deriveState(push));
2476
+ (0, import_react15.useEffect)(() => {
2366
2477
  setState(deriveState(push));
2367
2478
  }, [push]);
2368
- const subscribe = (0, import_react14.useCallback)(async () => {
2479
+ const subscribe = (0, import_react15.useCallback)(async () => {
2369
2480
  try {
2370
2481
  await push.subscribe();
2371
2482
  setState({ kind: "subscribed" });
@@ -2377,7 +2488,7 @@ function usePush() {
2377
2488
  throw e;
2378
2489
  }
2379
2490
  }, [push]);
2380
- const unsubscribe = (0, import_react14.useCallback)(async () => {
2491
+ const unsubscribe = (0, import_react15.useCallback)(async () => {
2381
2492
  try {
2382
2493
  await push.unsubscribe();
2383
2494
  setState({ kind: "prompt" });
@@ -2386,7 +2497,7 @@ function usePush() {
2386
2497
  throw e;
2387
2498
  }
2388
2499
  }, [push]);
2389
- const dismiss = (0, import_react14.useCallback)(() => {
2500
+ const dismiss = (0, import_react15.useCallback)(() => {
2390
2501
  if (typeof localStorage !== "undefined") {
2391
2502
  try {
2392
2503
  localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
@@ -2399,51 +2510,27 @@ function usePush() {
2399
2510
  }
2400
2511
 
2401
2512
  // src/components/PushPrompt.tsx
2402
- var import_jsx_runtime21 = require("react/jsx-runtime");
2403
- function platformRecoveryCopy(texts) {
2404
- if (typeof navigator === "undefined") return null;
2405
- const ua = navigator.userAgent || "";
2406
- const platform = detectPlatform(ua);
2407
- switch (platform) {
2408
- case "ios-safari":
2409
- case "ios-other":
2410
- return texts.deniedRecoveryIos ?? null;
2411
- case "android":
2412
- return texts.deniedRecoveryAndroid ?? null;
2413
- case "desktop":
2414
- return texts.deniedRecoveryDesktop ?? null;
2415
- case "in-app":
2416
- return texts.deniedRecoveryInApp ?? null;
2417
- default:
2418
- return null;
2419
- }
2420
- }
2513
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2421
2514
  function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, className }) {
2422
2515
  const { state, subscribe } = usePush();
2423
- if (state.kind === "subscribed" || state.kind === "dismissed") return null;
2424
- if (state.kind === "ios_needs_install") {
2425
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2426
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { children: texts.iosInstallTitle }),
2427
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.iosInstallBody }),
2428
- onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2429
- ] });
2516
+ if (state.kind === "denied" || state.kind === "dismissed" || state.kind === "subscribed") {
2517
+ return null;
2430
2518
  }
2431
- if (state.kind === "denied") {
2432
- const recovery = platformRecoveryCopy(texts);
2433
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2434
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { children: texts.deniedTitle }),
2435
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.deniedBody }),
2436
- recovery && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { "data-testid": "denied-recovery", children: recovery })
2519
+ if (state.kind === "ios_needs_install") {
2520
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2521
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { children: texts.iosInstallTitle }),
2522
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: texts.iosInstallBody }),
2523
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2437
2524
  ] });
2438
2525
  }
2439
2526
  if (state.kind === "unsupported") {
2440
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.unsupportedBody }) });
2527
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: texts.unsupportedBody }) });
2441
2528
  }
2442
2529
  if (state.kind === "error") {
2443
- 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 }) });
2530
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className, role: "region", "aria-label": "error", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: state.message }) });
2444
2531
  }
2445
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", children: [
2446
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2532
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, role: "region", children: [
2533
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2447
2534
  "button",
2448
2535
  {
2449
2536
  type: "button",
@@ -2457,41 +2544,67 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2457
2544
  children: texts.cta
2458
2545
  }
2459
2546
  ),
2460
- onDeclined && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2547
+ onDeclined && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2548
+ ] });
2549
+ }
2550
+
2551
+ // src/components/LanguageSwitcher.tsx
2552
+ var import_sdk9 = require("@hook-sdk/sdk");
2553
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2554
+ function LanguageSwitcher({ id, className, label = "Language" }) {
2555
+ const config = useAppConfig();
2556
+ const i18nConfig = config.i18n;
2557
+ const [userLocale, setUserLocale] = (0, import_sdk9.usePersistedState)(
2558
+ "user-locale",
2559
+ i18nConfig?.defaultLocale ?? "en-US"
2560
+ );
2561
+ if (!i18nConfig) return null;
2562
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className, children: [
2563
+ label ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: label }) : null,
2564
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2565
+ "select",
2566
+ {
2567
+ id,
2568
+ value: userLocale,
2569
+ onChange: (e) => setUserLocale(e.target.value),
2570
+ "data-testid": "language-switcher",
2571
+ children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: loc, children: loc }, loc))
2572
+ }
2573
+ )
2461
2574
  ] });
2462
2575
  }
2463
2576
 
2464
2577
  // src/defaults/LoadingState.tsx
2465
- var import_jsx_runtime22 = require("react/jsx-runtime");
2578
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2466
2579
  function LoadingState({ message }) {
2467
- 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..." }) });
2580
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "status", "aria-live": "polite", style: { padding: 24, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("span", { children: message ?? "Carregando..." }) });
2468
2581
  }
2469
2582
 
2470
2583
  // src/defaults/EmptyState.tsx
2471
- var import_jsx_runtime23 = require("react/jsx-runtime");
2584
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2472
2585
  function EmptyState({ title, description, action }) {
2473
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2474
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2475
- description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2476
- action && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { marginTop: 16 }, children: action })
2586
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2587
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2588
+ description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2589
+ action && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { marginTop: 16 }, children: action })
2477
2590
  ] });
2478
2591
  }
2479
2592
 
2480
2593
  // src/hooks/useLoginForm.ts
2481
- var import_react15 = require("react");
2482
- var import_sdk9 = require("@hook-sdk/sdk");
2594
+ var import_react16 = require("react");
2595
+ var import_sdk11 = require("@hook-sdk/sdk");
2483
2596
 
2484
2597
  // src/errors.ts
2485
- var import_sdk8 = require("@hook-sdk/sdk");
2598
+ var import_sdk10 = require("@hook-sdk/sdk");
2486
2599
  function mapSdkError(err) {
2487
- if (err instanceof import_sdk8.SdkRateLimitError) {
2600
+ if (err instanceof import_sdk10.SdkRateLimitError) {
2488
2601
  return {
2489
2602
  code: "rate_limited",
2490
2603
  message: `Aguarde ${err.retryAfter}s e tente novamente.`,
2491
2604
  retryAfter: err.retryAfter
2492
2605
  };
2493
2606
  }
2494
- if (err instanceof import_sdk8.SdkAuthError) {
2607
+ if (err instanceof import_sdk10.SdkAuthError) {
2495
2608
  const detail = err.detail;
2496
2609
  if (detail === "email_unverified") {
2497
2610
  return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
@@ -2501,7 +2614,7 @@ function mapSdkError(err) {
2501
2614
  }
2502
2615
  return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
2503
2616
  }
2504
- if (err instanceof import_sdk8.SdkError && err.httpStatus === 0) {
2617
+ if (err instanceof import_sdk10.SdkError && err.httpStatus === 0) {
2505
2618
  return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
2506
2619
  }
2507
2620
  if (err instanceof TypeError) {
@@ -2514,20 +2627,20 @@ function mapSdkError(err) {
2514
2627
  var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2515
2628
  var MIN_PASSWORD = 8;
2516
2629
  function useLoginForm() {
2517
- const { auth } = (0, import_sdk9.useHook)();
2518
- const [email, setEmail] = (0, import_react15.useState)("");
2519
- const [password, setPassword] = (0, import_react15.useState)("");
2520
- const [submitting, setSubmitting] = (0, import_react15.useState)(false);
2521
- const [error, setError] = (0, import_react15.useState)(null);
2522
- const [touchedEmail, setTouchedEmail] = (0, import_react15.useState)(false);
2523
- const [touchedPassword, setTouchedPassword] = (0, import_react15.useState)(false);
2524
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react15.useState)(false);
2525
- const validateEmail = (0, import_react15.useMemo)(() => {
2630
+ const { auth } = (0, import_sdk11.useHook)();
2631
+ const [email, setEmail] = (0, import_react16.useState)("");
2632
+ const [password, setPassword] = (0, import_react16.useState)("");
2633
+ const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2634
+ const [error, setError] = (0, import_react16.useState)(null);
2635
+ const [touchedEmail, setTouchedEmail] = (0, import_react16.useState)(false);
2636
+ const [touchedPassword, setTouchedPassword] = (0, import_react16.useState)(false);
2637
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react16.useState)(false);
2638
+ const validateEmail = (0, import_react16.useMemo)(() => {
2526
2639
  if (email.length === 0) return null;
2527
2640
  if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
2528
2641
  return null;
2529
2642
  }, [email]);
2530
- const validatePassword = (0, import_react15.useMemo)(() => {
2643
+ const validatePassword = (0, import_react16.useMemo)(() => {
2531
2644
  if (password.length === 0) return null;
2532
2645
  if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
2533
2646
  return null;
@@ -2535,7 +2648,7 @@ function useLoginForm() {
2535
2648
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2536
2649
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2537
2650
  const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
2538
- const submit = (0, import_react15.useCallback)(async () => {
2651
+ const submit = (0, import_react16.useCallback)(async () => {
2539
2652
  setFormSubmitAttempted(true);
2540
2653
  if (!canSubmit) return false;
2541
2654
  setSubmitting(true);
@@ -2569,32 +2682,32 @@ function useLoginForm() {
2569
2682
  }
2570
2683
 
2571
2684
  // src/hooks/useSignupForm.ts
2572
- var import_react16 = require("react");
2573
- var import_sdk10 = require("@hook-sdk/sdk");
2685
+ var import_react17 = require("react");
2686
+ var import_sdk12 = require("@hook-sdk/sdk");
2574
2687
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2575
2688
  var MIN_PASSWORD2 = 8;
2576
2689
  function useSignupForm() {
2577
- const { auth } = (0, import_sdk10.useHook)();
2578
- const [name, setName] = (0, import_react16.useState)("");
2579
- const [email, setEmail] = (0, import_react16.useState)("");
2580
- const [password, setPassword] = (0, import_react16.useState)("");
2581
- const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2582
- const [error, setError] = (0, import_react16.useState)(null);
2583
- const [touchedName, setTouchedName] = (0, import_react16.useState)(false);
2584
- const [touchedEmail, setTouchedEmail] = (0, import_react16.useState)(false);
2585
- const [touchedPassword, setTouchedPassword] = (0, import_react16.useState)(false);
2586
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react16.useState)(false);
2587
- const validateName = (0, import_react16.useMemo)(() => {
2690
+ const { auth } = (0, import_sdk12.useHook)();
2691
+ const [name, setName] = (0, import_react17.useState)("");
2692
+ const [email, setEmail] = (0, import_react17.useState)("");
2693
+ const [password, setPassword] = (0, import_react17.useState)("");
2694
+ const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2695
+ const [error, setError] = (0, import_react17.useState)(null);
2696
+ const [touchedName, setTouchedName] = (0, import_react17.useState)(false);
2697
+ const [touchedEmail, setTouchedEmail] = (0, import_react17.useState)(false);
2698
+ const [touchedPassword, setTouchedPassword] = (0, import_react17.useState)(false);
2699
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
2700
+ const validateName = (0, import_react17.useMemo)(() => {
2588
2701
  if (name.length === 0) return null;
2589
2702
  if (name.trim().length < 2) return "Nome muito curto.";
2590
2703
  return null;
2591
2704
  }, [name]);
2592
- const validateEmail = (0, import_react16.useMemo)(() => {
2705
+ const validateEmail = (0, import_react17.useMemo)(() => {
2593
2706
  if (email.length === 0) return null;
2594
2707
  if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
2595
2708
  return null;
2596
2709
  }, [email]);
2597
- const validatePassword = (0, import_react16.useMemo)(() => {
2710
+ const validatePassword = (0, import_react17.useMemo)(() => {
2598
2711
  if (password.length === 0) return null;
2599
2712
  if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
2600
2713
  return null;
@@ -2603,7 +2716,7 @@ function useSignupForm() {
2603
2716
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2604
2717
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2605
2718
  const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
2606
- const submit = (0, import_react16.useCallback)(async () => {
2719
+ const submit = (0, import_react17.useCallback)(async () => {
2607
2720
  setFormSubmitAttempted(true);
2608
2721
  if (!canSubmit) return false;
2609
2722
  setSubmitting(true);
@@ -2641,25 +2754,25 @@ function useSignupForm() {
2641
2754
  }
2642
2755
 
2643
2756
  // src/hooks/useForgotForm.ts
2644
- var import_react17 = require("react");
2645
- var import_sdk11 = require("@hook-sdk/sdk");
2757
+ var import_react18 = require("react");
2758
+ var import_sdk13 = require("@hook-sdk/sdk");
2646
2759
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2647
2760
  function useForgotForm() {
2648
- const { auth } = (0, import_sdk11.useHook)();
2649
- const [email, setEmail] = (0, import_react17.useState)("");
2650
- const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2651
- const [sent, setSent] = (0, import_react17.useState)(false);
2652
- const [error, setError] = (0, import_react17.useState)(null);
2653
- const [touchedEmail, setTouchedEmail] = (0, import_react17.useState)(false);
2654
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
2655
- const validateEmail = (0, import_react17.useMemo)(() => {
2761
+ const { auth } = (0, import_sdk13.useHook)();
2762
+ const [email, setEmail] = (0, import_react18.useState)("");
2763
+ const [submitting, setSubmitting] = (0, import_react18.useState)(false);
2764
+ const [sent, setSent] = (0, import_react18.useState)(false);
2765
+ const [error, setError] = (0, import_react18.useState)(null);
2766
+ const [touchedEmail, setTouchedEmail] = (0, import_react18.useState)(false);
2767
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
2768
+ const validateEmail = (0, import_react18.useMemo)(() => {
2656
2769
  if (email.length === 0) return null;
2657
2770
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
2658
2771
  return null;
2659
2772
  }, [email]);
2660
2773
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2661
2774
  const canSubmit = email.length > 0 && validateEmail === null && !submitting;
2662
- const submit = (0, import_react17.useCallback)(async () => {
2775
+ const submit = (0, import_react18.useCallback)(async () => {
2663
2776
  setFormSubmitAttempted(true);
2664
2777
  if (!canSubmit) return false;
2665
2778
  setSubmitting(true);
@@ -2690,32 +2803,32 @@ function useForgotForm() {
2690
2803
  }
2691
2804
 
2692
2805
  // src/hooks/useResetForm.ts
2693
- var import_react18 = require("react");
2694
- var import_sdk12 = require("@hook-sdk/sdk");
2806
+ var import_react19 = require("react");
2807
+ var import_sdk14 = require("@hook-sdk/sdk");
2695
2808
  var MIN_PASSWORD3 = 12;
2696
2809
  function useResetForm() {
2697
- const { auth } = (0, import_sdk12.useHook)();
2698
- const [token, setToken] = (0, import_react18.useState)(null);
2699
- const [password, setPassword] = (0, import_react18.useState)("");
2700
- const [confirm, setConfirm] = (0, import_react18.useState)("");
2701
- const [submitting, setSubmitting] = (0, import_react18.useState)(false);
2702
- const [done, setDone] = (0, import_react18.useState)(false);
2703
- const [error, setError] = (0, import_react18.useState)(null);
2704
- const [touchedPassword, setTouchedPassword] = (0, import_react18.useState)(false);
2705
- const [touchedConfirm, setTouchedConfirm] = (0, import_react18.useState)(false);
2706
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
2707
- (0, import_react18.useEffect)(() => {
2810
+ const { auth } = (0, import_sdk14.useHook)();
2811
+ const [token, setToken] = (0, import_react19.useState)(null);
2812
+ const [password, setPassword] = (0, import_react19.useState)("");
2813
+ const [confirm, setConfirm] = (0, import_react19.useState)("");
2814
+ const [submitting, setSubmitting] = (0, import_react19.useState)(false);
2815
+ const [done, setDone] = (0, import_react19.useState)(false);
2816
+ const [error, setError] = (0, import_react19.useState)(null);
2817
+ const [touchedPassword, setTouchedPassword] = (0, import_react19.useState)(false);
2818
+ const [touchedConfirm, setTouchedConfirm] = (0, import_react19.useState)(false);
2819
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react19.useState)(false);
2820
+ (0, import_react19.useEffect)(() => {
2708
2821
  if (typeof window === "undefined") return;
2709
2822
  const params = new URLSearchParams(window.location.search);
2710
2823
  const t = params.get("token");
2711
2824
  setToken(t && t.length > 0 ? t : null);
2712
2825
  }, []);
2713
- const validatePassword = (0, import_react18.useMemo)(() => {
2826
+ const validatePassword = (0, import_react19.useMemo)(() => {
2714
2827
  if (password.length === 0) return null;
2715
2828
  if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
2716
2829
  return null;
2717
2830
  }, [password]);
2718
- const validateConfirm = (0, import_react18.useMemo)(() => {
2831
+ const validateConfirm = (0, import_react19.useMemo)(() => {
2719
2832
  if (confirm.length === 0) return null;
2720
2833
  if (confirm !== password) return "Senhas n\xE3o coincidem.";
2721
2834
  return null;
@@ -2723,7 +2836,7 @@ function useResetForm() {
2723
2836
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2724
2837
  const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
2725
2838
  const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
2726
- const submit = (0, import_react18.useCallback)(async () => {
2839
+ const submit = (0, import_react19.useCallback)(async () => {
2727
2840
  setFormSubmitAttempted(true);
2728
2841
  if (!canSubmit || token === null) return;
2729
2842
  setSubmitting(true);
@@ -2763,9 +2876,9 @@ function useResetForm() {
2763
2876
  }
2764
2877
 
2765
2878
  // src/hooks/usePlan.ts
2766
- var import_sdk13 = require("@hook-sdk/sdk");
2879
+ var import_sdk15 = require("@hook-sdk/sdk");
2767
2880
  function usePlan() {
2768
- const { plan } = (0, import_sdk13.useHook)();
2881
+ const { plan } = (0, import_sdk15.useHook)();
2769
2882
  return plan;
2770
2883
  }
2771
2884
 
@@ -2798,12 +2911,12 @@ function discountPercent(anchorCents, realCents) {
2798
2911
  }
2799
2912
 
2800
2913
  // src/hooks/useAuthPrimitives.ts
2801
- var import_react19 = require("react");
2802
- var import_sdk14 = require("@hook-sdk/sdk");
2914
+ var import_react20 = require("react");
2915
+ var import_sdk16 = require("@hook-sdk/sdk");
2803
2916
  var warned = false;
2804
2917
  function useAuthPrimitives() {
2805
- const { auth } = (0, import_sdk14.useHook)();
2806
- (0, import_react19.useEffect)(() => {
2918
+ const { auth } = (0, import_sdk16.useHook)();
2919
+ (0, import_react20.useEffect)(() => {
2807
2920
  if (!warned && process.env.NODE_ENV !== "production") {
2808
2921
  warned = true;
2809
2922
  console.warn(
@@ -2825,9 +2938,9 @@ function useAuthPrimitives() {
2825
2938
  }
2826
2939
 
2827
2940
  // src/hooks/useAuth.ts
2828
- var import_sdk15 = require("@hook-sdk/sdk");
2941
+ var import_sdk17 = require("@hook-sdk/sdk");
2829
2942
  function useAuth() {
2830
- const { user, authStatus, auth } = (0, import_sdk15.useHook)();
2943
+ const { user, authStatus, auth } = (0, import_sdk17.useHook)();
2831
2944
  return {
2832
2945
  user,
2833
2946
  authStatus,
@@ -2836,26 +2949,26 @@ function useAuth() {
2836
2949
  }
2837
2950
 
2838
2951
  // src/index.ts
2839
- var import_sdk19 = require("@hook-sdk/sdk");
2952
+ var import_sdk21 = require("@hook-sdk/sdk");
2840
2953
 
2841
2954
  // src/hooks/useSubscription.ts
2842
- var import_sdk16 = require("@hook-sdk/sdk");
2955
+ var import_sdk18 = require("@hook-sdk/sdk");
2843
2956
  function useSubscription() {
2844
- const { subscription } = (0, import_sdk16.useHook)();
2957
+ const { subscription } = (0, import_sdk18.useHook)();
2845
2958
  return {
2846
2959
  status: subscription.status()
2847
2960
  };
2848
2961
  }
2849
2962
 
2850
2963
  // src/hooks/useReminders.ts
2851
- var import_react20 = require("react");
2852
- var import_sdk17 = require("@hook-sdk/sdk");
2964
+ var import_react21 = require("react");
2965
+ var import_sdk19 = require("@hook-sdk/sdk");
2853
2966
  function useReminders() {
2854
- const { push } = (0, import_sdk17.useHook)();
2967
+ const { push } = (0, import_sdk19.useHook)();
2855
2968
  const r = push.reminders;
2856
- const [reminders, setReminders] = (0, import_react20.useState)([]);
2857
- const [loading, setLoading] = (0, import_react20.useState)(true);
2858
- const reload = (0, import_react20.useCallback)(async () => {
2969
+ const [reminders, setReminders] = (0, import_react21.useState)([]);
2970
+ const [loading, setLoading] = (0, import_react21.useState)(true);
2971
+ const reload = (0, import_react21.useCallback)(async () => {
2859
2972
  setLoading(true);
2860
2973
  try {
2861
2974
  const next = await r.list();
@@ -2864,38 +2977,38 @@ function useReminders() {
2864
2977
  setLoading(false);
2865
2978
  }
2866
2979
  }, [r]);
2867
- (0, import_react20.useEffect)(() => {
2980
+ (0, import_react21.useEffect)(() => {
2868
2981
  void reload();
2869
2982
  }, [reload]);
2870
- const setReminder = (0, import_react20.useCallback)(async (input) => {
2983
+ const setReminder = (0, import_react21.useCallback)(async (input) => {
2871
2984
  await r.set(input);
2872
2985
  await reload();
2873
2986
  }, [r, reload]);
2874
- const deleteReminder = (0, import_react20.useCallback)(async (slot) => {
2987
+ const deleteReminder = (0, import_react21.useCallback)(async (slot) => {
2875
2988
  await r.delete(slot);
2876
2989
  await reload();
2877
2990
  }, [r, reload]);
2878
- const schedule = (0, import_react20.useCallback)(async (items) => {
2991
+ const schedule = (0, import_react21.useCallback)(async (items) => {
2879
2992
  return r.schedule(items);
2880
2993
  }, [r]);
2881
- const setFallbacks = (0, import_react20.useCallback)(async (items) => {
2994
+ const setFallbacks = (0, import_react21.useCallback)(async (items) => {
2882
2995
  return r.setFallbacks(items);
2883
2996
  }, [r]);
2884
2997
  return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
2885
2998
  }
2886
2999
 
2887
3000
  // src/hooks/useToast.ts
2888
- var import_react21 = require("react");
3001
+ var import_react22 = require("react");
2889
3002
  function useToast() {
2890
- const [items, setItems] = (0, import_react21.useState)([]);
2891
- const show = (0, import_react21.useCallback)((message, kind = "info") => {
3003
+ const [items, setItems] = (0, import_react22.useState)([]);
3004
+ const show = (0, import_react22.useCallback)((message, kind = "info") => {
2892
3005
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2893
3006
  setItems((prev) => [...prev, { id, message, kind }]);
2894
3007
  setTimeout(() => {
2895
3008
  setItems((prev) => prev.filter((t) => t.id !== id));
2896
3009
  }, 4e3);
2897
3010
  }, []);
2898
- const dismiss = (0, import_react21.useCallback)((id) => {
3011
+ const dismiss = (0, import_react22.useCallback)((id) => {
2899
3012
  setItems((prev) => prev.filter((t) => t.id !== id));
2900
3013
  }, []);
2901
3014
  return { items, show, dismiss };
@@ -2903,20 +3016,20 @@ function useToast() {
2903
3016
 
2904
3017
  // src/RouteBoundary.tsx
2905
3018
  var import_react_router_dom3 = require("react-router-dom");
2906
- var import_jsx_runtime24 = require("react/jsx-runtime");
3019
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2907
3020
  function RouteBoundary({ children }) {
2908
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_router_dom3.Routes, { children: [
3021
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_router_dom3.Routes, { children: [
2909
3022
  children,
2910
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DefaultNotFound, {}) })
3023
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DefaultNotFound, {}) })
2911
3024
  ] });
2912
3025
  }
2913
3026
  function DefaultNotFound() {
2914
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
3027
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
2915
3028
  }
2916
3029
 
2917
3030
  // src/PreAuthShell.tsx
2918
3031
  var import_react_router_dom4 = require("react-router-dom");
2919
- var import_jsx_runtime25 = require("react/jsx-runtime");
3032
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2920
3033
  function PreAuthShell({
2921
3034
  basename,
2922
3035
  testRouter,
@@ -2924,20 +3037,20 @@ function PreAuthShell({
2924
3037
  children
2925
3038
  }) {
2926
3039
  if (testRouter === "memory") {
2927
- 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 }) });
3040
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.MemoryRouter, { basename, initialEntries: testInitialEntries, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.Routes, { children }) });
2928
3041
  }
2929
- 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 }) });
3042
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.BrowserRouter, { basename, children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom4.Routes, { children }) });
2930
3043
  }
2931
3044
 
2932
3045
  // src/OnboardingFlow.tsx
2933
- var import_react23 = require("react");
2934
- var import_sdk18 = require("@hook-sdk/sdk");
3046
+ var import_react24 = require("react");
3047
+ var import_sdk20 = require("@hook-sdk/sdk");
2935
3048
 
2936
3049
  // src/hooks/useOnboardingStep.ts
2937
- var import_react22 = require("react");
2938
- var OnboardingStepContext = (0, import_react22.createContext)(null);
3050
+ var import_react23 = require("react");
3051
+ var OnboardingStepContext = (0, import_react23.createContext)(null);
2939
3052
  function useOnboardingStep() {
2940
- const ctx = (0, import_react22.useContext)(OnboardingStepContext);
3053
+ const ctx = (0, import_react23.useContext)(OnboardingStepContext);
2941
3054
  if (!ctx) {
2942
3055
  throw new Error(
2943
3056
  "[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
@@ -2947,7 +3060,7 @@ function useOnboardingStep() {
2947
3060
  }
2948
3061
 
2949
3062
  // src/OnboardingFlow.tsx
2950
- var import_jsx_runtime26 = require("react/jsx-runtime");
3063
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2951
3064
  var isFilled = (v) => v != null && v !== "";
2952
3065
  var CURRENT_STEP_FIELD = "currentStep";
2953
3066
  function readPersistedStepIdx(draft) {
@@ -2960,12 +3073,12 @@ function OnboardingFlow({
2960
3073
  onComplete,
2961
3074
  persistKey
2962
3075
  }) {
2963
- const [draft, setDraft, status] = (0, import_sdk18.usePersistedState)(persistKey, {});
2964
- const draftRef = (0, import_react23.useRef)(draft);
3076
+ const [draft, setDraft, status] = (0, import_sdk20.usePersistedState)(persistKey, {});
3077
+ const draftRef = (0, import_react24.useRef)(draft);
2965
3078
  draftRef.current = draft;
2966
3079
  const idx = readPersistedStepIdx(draft);
2967
3080
  const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
2968
- const setIdx = (0, import_react23.useCallback)(
3081
+ const setIdx = (0, import_react24.useCallback)(
2969
3082
  (n) => {
2970
3083
  setDraft((prev) => {
2971
3084
  const prevIdx = readPersistedStepIdx(prev);
@@ -2975,7 +3088,7 @@ function OnboardingFlow({
2975
3088
  },
2976
3089
  [setDraft]
2977
3090
  );
2978
- const setValue = (0, import_react23.useCallback)(
3091
+ const setValue = (0, import_react24.useCallback)(
2979
3092
  (patch) => {
2980
3093
  draftRef.current = { ...draftRef.current, ...patch };
2981
3094
  setDraft((prev) => ({ ...prev, ...patch }));
@@ -2983,9 +3096,9 @@ function OnboardingFlow({
2983
3096
  [setDraft]
2984
3097
  );
2985
3098
  const step = steps[clampedIdx];
2986
- const hookCtx = (0, import_sdk18.useHook)();
3099
+ const hookCtx = (0, import_sdk20.useHook)();
2987
3100
  const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
2988
- (0, import_react23.useEffect)(() => {
3101
+ (0, import_react24.useEffect)(() => {
2989
3102
  if (status.loading) return;
2990
3103
  if (!step) return;
2991
3104
  if (!track2) return;
@@ -2995,11 +3108,11 @@ function OnboardingFlow({
2995
3108
  total_steps: steps.length
2996
3109
  });
2997
3110
  }, [step?.id, clampedIdx, steps.length, status.loading, track2]);
2998
- const valid = (0, import_react23.useMemo)(
3111
+ const valid = (0, import_react24.useMemo)(
2999
3112
  () => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
3000
3113
  [draft, step]
3001
3114
  );
3002
- const next = (0, import_react23.useCallback)(() => {
3115
+ const next = (0, import_react24.useCallback)(() => {
3003
3116
  if (!step) return;
3004
3117
  const current = draftRef.current;
3005
3118
  const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
@@ -3010,8 +3123,8 @@ function OnboardingFlow({
3010
3123
  setIdx(clampedIdx + 1);
3011
3124
  }
3012
3125
  }, [clampedIdx, onComplete, step, steps.length, setIdx]);
3013
- const prevStep = (0, import_react23.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3014
- const ctx = (0, import_react23.useMemo)(
3126
+ const prevStep = (0, import_react24.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3127
+ const ctx = (0, import_react24.useMemo)(
3015
3128
  () => ({
3016
3129
  stepIndex: clampedIdx,
3017
3130
  totalSteps: steps.length,
@@ -3037,7 +3150,7 @@ function OnboardingFlow({
3037
3150
  `[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
3038
3151
  );
3039
3152
  }
3040
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Screen, {}) });
3153
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Screen, {}) });
3041
3154
  }
3042
3155
 
3043
3156
  // src/hooks/useFeature.ts
@@ -3053,8 +3166,10 @@ function useFeature(name) {
3053
3166
  DeepLinkHandler,
3054
3167
  EmptyState,
3055
3168
  ErrorBoundary,
3169
+ I18nProvider,
3056
3170
  InstallGate,
3057
3171
  InstallSplash,
3172
+ LanguageSwitcher,
3058
3173
  LoadingState,
3059
3174
  OnboardingFlow,
3060
3175
  PaymentReturnHandler,