@hook-sdk/template 0.18.0 → 0.19.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);
@@ -267,7 +296,16 @@ var MAP = {
267
296
  pix_expired: "QR Code do PIX expirou. Gere um novo.",
268
297
  pix_not_paid_yet: "PIX ainda n\xE3o foi pago. Aguardando confirma\xE7\xE3o."
269
298
  };
270
- function asaasErrorMessage(code) {
299
+ function asaasErrorMessage(code, description) {
300
+ if (description) {
301
+ const lower = description.toLowerCase();
302
+ if (lower.includes("cep")) {
303
+ return "Nosso processador de pagamentos n\xE3o reconheceu esse CEP \u2014 a base deles pode estar desatualizada. Tente outro CEP.";
304
+ }
305
+ if (lower.includes("telefone") || lower.includes("contato com ddd")) {
306
+ return "Telefone inv\xE1lido. Confira o n\xFAmero com DDD e tente novamente.";
307
+ }
308
+ }
271
309
  return MAP[code] ?? "Ocorreu um erro inesperado. Tente novamente em instantes.";
272
310
  }
273
311
 
@@ -396,7 +434,9 @@ function usePaywallState() {
396
434
  (code, fallbackMessage) => ({
397
435
  code,
398
436
  message: fallbackMessage,
399
- userMessage: useDefaultMessages ? asaasErrorMessage(code) : fallbackMessage
437
+ // fallbackMessage carries Asaas's PT-BR description ("O CEP informado é inválido.")
438
+ // that distinguishes invalid_holderInfo sub-cases (CEP vs phone vs name).
439
+ userMessage: useDefaultMessages ? asaasErrorMessage(code, fallbackMessage) : fallbackMessage
400
440
  }),
401
441
  [useDefaultMessages]
402
442
  );
@@ -1871,9 +1911,9 @@ var bannerStyle = {
1871
1911
 
1872
1912
  // src/components/InstallGate/InstallGate.tsx
1873
1913
  var import_jsx_runtime16 = require("react/jsx-runtime");
1874
- function InstallGate({ children }) {
1914
+ function InstallGate({ children, position }) {
1875
1915
  const { slug, features_enabled } = useTemplateConfig();
1876
- const enabled = features_enabled.includes("install_prompt");
1916
+ const enabled = features_enabled.includes("pwa-install");
1877
1917
  const installState = useInstallPrompt(slug);
1878
1918
  const shouldBlock = enabled && shouldBlockInstall(installState);
1879
1919
  const trackedRef = (0, import_react9.useRef)(null);
@@ -1888,9 +1928,10 @@ function InstallGate({ children }) {
1888
1928
  platform: installState.platform,
1889
1929
  browser: installState.iosBrowser ?? installState.androidBrowser ?? null,
1890
1930
  in_app_app: installState.inAppApp,
1891
- variant: installState.variant
1931
+ variant: installState.variant,
1932
+ ...position !== void 0 ? { position } : {}
1892
1933
  });
1893
- }, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp]);
1934
+ }, [shouldBlock, slug, installState.variant, installState.platform, installState.iosBrowser, installState.androidBrowser, installState.inAppApp, position]);
1894
1935
  if (!enabled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1895
1936
  if (installState.isInstalled) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
1896
1937
  if (installState.variant === "desktop") {
@@ -2013,21 +2054,58 @@ var ErrorBoundary = class extends import_react11.Component {
2013
2054
  }
2014
2055
  };
2015
2056
 
2016
- // src/internal/PaymentReturnHandler.tsx
2057
+ // src/i18n/I18nProvider.tsx
2017
2058
  var import_react12 = require("react");
2059
+ var import_i18next = __toESM(require("i18next"), 1);
2060
+ var import_react_i18next = require("react-i18next");
2018
2061
  var import_sdk5 = require("@hook-sdk/sdk");
2019
2062
  var import_jsx_runtime19 = require("react/jsx-runtime");
2063
+ function ensureInitialized(defaultLocale, supportedLocales, resources, initialLocale) {
2064
+ if (import_i18next.default.isInitialized) return;
2065
+ import_i18next.default.use(import_react_i18next.initReactI18next).init({
2066
+ resources: Object.fromEntries(
2067
+ supportedLocales.map((l) => [l, { translation: resources[l] ?? {} }])
2068
+ ),
2069
+ lng: initialLocale,
2070
+ fallbackLng: defaultLocale,
2071
+ interpolation: { escapeValue: false },
2072
+ // useTranslation suspends by default until i18next is "ready". Inline
2073
+ // resources are sync, so suspending creates a guaranteed empty render
2074
+ // tick — confusing in apps and breaks tests that don't use Suspense.
2075
+ react: { useSuspense: false }
2076
+ });
2077
+ }
2078
+ function I18nProvider({
2079
+ defaultLocale,
2080
+ supportedLocales,
2081
+ resources,
2082
+ children
2083
+ }) {
2084
+ const [userLocale] = (0, import_sdk5.usePersistedState)("user-locale", defaultLocale);
2085
+ ensureInitialized(defaultLocale, supportedLocales, resources, userLocale);
2086
+ (0, import_react12.useEffect)(() => {
2087
+ if (import_i18next.default.isInitialized && import_i18next.default.language !== userLocale) {
2088
+ import_i18next.default.changeLanguage(userLocale);
2089
+ }
2090
+ }, [userLocale]);
2091
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_i18next.I18nextProvider, { i18n: import_i18next.default, children });
2092
+ }
2093
+
2094
+ // src/internal/PaymentReturnHandler.tsx
2095
+ var import_react13 = require("react");
2096
+ var import_sdk6 = require("@hook-sdk/sdk");
2097
+ var import_jsx_runtime20 = require("react/jsx-runtime");
2020
2098
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
2021
2099
  var MAX_CYCLES = 3;
2022
2100
  var SUPPORT_MAILTO = "mailto:suporte@usehook.net?subject=Pagamento%20pendente";
2023
2101
  function PaymentReturnHandler({ children }) {
2024
- const { subscription } = (0, import_sdk5.useHook)();
2025
- const subRef = (0, import_react12.useRef)(subscription);
2102
+ const { subscription } = (0, import_sdk6.useHook)();
2103
+ const subRef = (0, import_react13.useRef)(subscription);
2026
2104
  subRef.current = subscription;
2027
- const runIdRef = (0, import_react12.useRef)(0);
2028
- const cyclesRef = (0, import_react12.useRef)(0);
2029
- const [state, setState] = (0, import_react12.useState)("idle");
2030
- const runPoll = (0, import_react12.useCallback)(() => {
2105
+ const runIdRef = (0, import_react13.useRef)(0);
2106
+ const cyclesRef = (0, import_react13.useRef)(0);
2107
+ const [state, setState] = (0, import_react13.useState)("idle");
2108
+ const runPoll = (0, import_react13.useCallback)(() => {
2031
2109
  const runId = ++runIdRef.current;
2032
2110
  cyclesRef.current += 1;
2033
2111
  setState("confirming");
@@ -2062,7 +2140,7 @@ function PaymentReturnHandler({ children }) {
2062
2140
  };
2063
2141
  void tick();
2064
2142
  }, []);
2065
- (0, import_react12.useEffect)(() => {
2143
+ (0, import_react13.useEffect)(() => {
2066
2144
  if (typeof window === "undefined") return;
2067
2145
  const url = new URL(window.location.href);
2068
2146
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -2072,26 +2150,26 @@ function PaymentReturnHandler({ children }) {
2072
2150
  runIdRef.current++;
2073
2151
  };
2074
2152
  }, [runPoll]);
2075
- const goHome = (0, import_react12.useCallback)(() => {
2153
+ const goHome = (0, import_react13.useCallback)(() => {
2076
2154
  const cleanUrl = new URL(window.location.href);
2077
2155
  cleanUrl.searchParams.delete("paymentReturn");
2078
2156
  cleanUrl.pathname = "/app/home";
2079
2157
  window.location.href = cleanUrl.toString();
2080
2158
  }, []);
2081
2159
  if (state === "confirming") {
2082
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2160
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { role: "status", "aria-live": "polite", style: overlayStyle2, children: "Confirmando pagamento\u2026" });
2083
2161
  }
2084
2162
  if (state === "waiting") {
2085
- 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: [
2086
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2087
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2163
+ 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: [
2164
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { style: { marginBottom: 16 }, children: "Pagamento aceito. Estamos confirmando com o banco \u2014 pode levar alguns minutos." }),
2165
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("button", { type: "button", onClick: runPoll, style: buttonStyle, children: "Atualizar" })
2088
2166
  ] }) });
2089
2167
  }
2090
2168
  if (state === "timeout") {
2091
- 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: [
2092
- /* @__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." }),
2093
- /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2094
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2169
+ 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: [
2170
+ /* @__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." }),
2171
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: [
2172
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2095
2173
  "button",
2096
2174
  {
2097
2175
  type: "button",
@@ -2104,7 +2182,7 @@ function PaymentReturnHandler({ children }) {
2104
2182
  children: "Tentar de novo"
2105
2183
  }
2106
2184
  ),
2107
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2185
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2108
2186
  "button",
2109
2187
  {
2110
2188
  type: "button",
@@ -2114,7 +2192,7 @@ function PaymentReturnHandler({ children }) {
2114
2192
  children: "Voltar pro app"
2115
2193
  }
2116
2194
  ),
2117
- /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
2195
+ /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2118
2196
  "a",
2119
2197
  {
2120
2198
  href: SUPPORT_MAILTO,
@@ -2126,7 +2204,7 @@ function PaymentReturnHandler({ children }) {
2126
2204
  ] })
2127
2205
  ] }) });
2128
2206
  }
2129
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_jsx_runtime19.Fragment, { children });
2207
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, { children });
2130
2208
  }
2131
2209
  var overlayStyle2 = {
2132
2210
  position: "fixed",
@@ -2165,7 +2243,7 @@ var linkStyle = {
2165
2243
  };
2166
2244
 
2167
2245
  // src/AppRoot.tsx
2168
- var import_jsx_runtime20 = require("react/jsx-runtime");
2246
+ var import_jsx_runtime21 = require("react/jsx-runtime");
2169
2247
  function buildLegacyConfigShim(config) {
2170
2248
  const paywall = config.paywall;
2171
2249
  const isFree = paywall.mode === "free";
@@ -2238,32 +2316,47 @@ function AppRoot(props) {
2238
2316
  "[hook-template] <AppRoot>: PreAuthFlow slot prop is required when config.onboarding.trigger === 'pre_signup_custom'."
2239
2317
  );
2240
2318
  }
2241
- const legacyShim = (0, import_react13.useMemo)(() => buildLegacyConfigShim(config), [config]);
2319
+ const legacyShim = (0, import_react14.useMemo)(() => buildLegacyConfigShim(config), [config]);
2242
2320
  const Router = testRouter === "memory" ? import_react_router_dom2.MemoryRouter : import_react_router_dom2.BrowserRouter;
2243
2321
  const basename = `/app/${config.slug}`;
2244
2322
  const routerProps = testRouter === "memory" ? { basename, initialEntries: testInitialEntries } : { basename };
2245
- 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: [
2246
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2247
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SessionExpiredBanner, {}),
2248
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(InstallGate, { children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
2249
- AuthGated,
2250
- {
2251
- config,
2252
- Login,
2253
- Signup,
2254
- Forgot,
2255
- Reset,
2256
- EmailVerify,
2257
- Paywall,
2258
- Onboarding,
2259
- PreAuthFlow,
2260
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(SubscriptionGate, { Paywall: Paywall ?? FallbackPaywall, children: [
2261
- children,
2262
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PushPrompt, {})
2263
- ] })
2264
- }
2265
- ) })
2266
- ] }) }) }) }) }) });
2323
+ const position = config.install_prompt?.position ?? "post-paywall";
2324
+ 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: [
2325
+ children,
2326
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PushPrompt, {})
2327
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
2328
+ children,
2329
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PushPrompt, {})
2330
+ ] }) });
2331
+ const authGated = /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2332
+ AuthGated,
2333
+ {
2334
+ config,
2335
+ Login,
2336
+ Signup,
2337
+ Forgot,
2338
+ Reset,
2339
+ EmailVerify,
2340
+ Paywall,
2341
+ Onboarding,
2342
+ PreAuthFlow,
2343
+ children: subscriptionGated
2344
+ }
2345
+ );
2346
+ const routedTree = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Router, { ...routerProps, children: [
2347
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(DeepLinkHandler, { deepLinks: config.deepLinks }),
2348
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(SessionExpiredBanner, {}),
2349
+ position === "pre-auth" ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(InstallGate, { position: "pre-auth", children: authGated }) : authGated
2350
+ ] });
2351
+ 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)(
2352
+ I18nProvider,
2353
+ {
2354
+ defaultLocale: config.i18n.defaultLocale,
2355
+ supportedLocales: config.i18n.supportedLocales,
2356
+ resources: config.i18n.resources,
2357
+ children: routedTree
2358
+ }
2359
+ ) : routedTree }) }) }) }) });
2267
2360
  }
2268
2361
  function AuthGated({
2269
2362
  children,
@@ -2275,37 +2368,37 @@ function AuthGated({
2275
2368
  EmailVerify,
2276
2369
  PreAuthFlow
2277
2370
  }) {
2278
- const { authStatus } = (0, import_sdk6.useHook)();
2371
+ const { authStatus } = (0, import_sdk7.useHook)();
2279
2372
  if (authStatus === "loading") return null;
2280
2373
  if (authStatus !== "authenticated") {
2281
2374
  if (config.onboarding?.trigger === "pre_signup_custom" && PreAuthFlow) {
2282
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_router_dom2.Routes, { children: [
2283
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Login, {}) }),
2284
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Signup, {}) }),
2285
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Forgot, {}) }),
2286
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Reset, {}) }),
2287
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EmailVerify, {}) }) : null,
2288
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PreAuthFlow, {}) })
2375
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_router_dom2.Routes, { children: [
2376
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signin", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Login, {}) }),
2377
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Signup, {}) }),
2378
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Forgot, {}) }),
2379
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Reset, {}) }),
2380
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EmailVerify, {}) }) : null,
2381
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/*", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(PreAuthFlow, {}) })
2289
2382
  ] });
2290
2383
  }
2291
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react_router_dom2.Routes, { children: [
2292
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Login, {}) }),
2293
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Signup, {}) }),
2294
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Forgot, {}) }),
2295
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(Reset, {}) }),
2296
- EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(EmailVerify, {}) }) : null,
2297
- /* @__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 }) })
2384
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_react_router_dom2.Routes, { children: [
2385
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Login, {}) }),
2386
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/signup", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Signup, {}) }),
2387
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/forgot", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Forgot, {}) }),
2388
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/reset", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Reset, {}) }),
2389
+ EmailVerify ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_router_dom2.Route, { path: "/verify", element: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(EmailVerify, {}) }) : null,
2390
+ /* @__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 }) })
2298
2391
  ] });
2299
2392
  }
2300
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_jsx_runtime20.Fragment, { children });
2393
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_jsx_runtime21.Fragment, { children });
2301
2394
  }
2302
2395
  function FallbackPaywall() {
2303
2396
  return null;
2304
2397
  }
2305
2398
 
2306
2399
  // src/hooks/usePush.ts
2307
- var import_react14 = require("react");
2308
- var import_sdk7 = require("@hook-sdk/sdk");
2400
+ var import_react15 = require("react");
2401
+ var import_sdk8 = require("@hook-sdk/sdk");
2309
2402
  var DISMISS_STORAGE_KEY = "push:dismissed-until";
2310
2403
  var DISMISS_TTL_MS2 = 7 * 24 * 60 * 60 * 1e3;
2311
2404
  function detectIosNeedsInstall() {
@@ -2349,12 +2442,12 @@ function deriveState(push) {
2349
2442
  return { kind: "prompt" };
2350
2443
  }
2351
2444
  function usePush() {
2352
- const { push } = (0, import_sdk7.useHook)();
2353
- const [state, setState] = (0, import_react14.useState)(() => deriveState(push));
2354
- (0, import_react14.useEffect)(() => {
2445
+ const { push } = (0, import_sdk8.useHook)();
2446
+ const [state, setState] = (0, import_react15.useState)(() => deriveState(push));
2447
+ (0, import_react15.useEffect)(() => {
2355
2448
  setState(deriveState(push));
2356
2449
  }, [push]);
2357
- const subscribe = (0, import_react14.useCallback)(async () => {
2450
+ const subscribe = (0, import_react15.useCallback)(async () => {
2358
2451
  try {
2359
2452
  await push.subscribe();
2360
2453
  setState({ kind: "subscribed" });
@@ -2366,7 +2459,7 @@ function usePush() {
2366
2459
  throw e;
2367
2460
  }
2368
2461
  }, [push]);
2369
- const unsubscribe = (0, import_react14.useCallback)(async () => {
2462
+ const unsubscribe = (0, import_react15.useCallback)(async () => {
2370
2463
  try {
2371
2464
  await push.unsubscribe();
2372
2465
  setState({ kind: "prompt" });
@@ -2375,7 +2468,7 @@ function usePush() {
2375
2468
  throw e;
2376
2469
  }
2377
2470
  }, [push]);
2378
- const dismiss = (0, import_react14.useCallback)(() => {
2471
+ const dismiss = (0, import_react15.useCallback)(() => {
2379
2472
  if (typeof localStorage !== "undefined") {
2380
2473
  try {
2381
2474
  localStorage.setItem(DISMISS_STORAGE_KEY, String(Date.now() + DISMISS_TTL_MS2));
@@ -2388,7 +2481,7 @@ function usePush() {
2388
2481
  }
2389
2482
 
2390
2483
  // src/components/PushPrompt.tsx
2391
- var import_jsx_runtime21 = require("react/jsx-runtime");
2484
+ var import_jsx_runtime22 = require("react/jsx-runtime");
2392
2485
  function platformRecoveryCopy(texts) {
2393
2486
  if (typeof navigator === "undefined") return null;
2394
2487
  const ua = navigator.userAgent || "";
@@ -2411,28 +2504,28 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2411
2504
  const { state, subscribe } = usePush();
2412
2505
  if (state.kind === "subscribed" || state.kind === "dismissed") return null;
2413
2506
  if (state.kind === "ios_needs_install") {
2414
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2415
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { children: texts.iosInstallTitle }),
2416
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.iosInstallBody }),
2417
- onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2507
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, role: "region", "aria-label": texts.iosInstallTitle, children: [
2508
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { children: texts.iosInstallTitle }),
2509
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: texts.iosInstallBody }),
2510
+ onInstallRequested && texts.iosInstallCta && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { onClick: onInstallRequested, children: texts.iosInstallCta })
2418
2511
  ] });
2419
2512
  }
2420
2513
  if (state.kind === "denied") {
2421
2514
  const recovery = platformRecoveryCopy(texts);
2422
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2423
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("h3", { children: texts.deniedTitle }),
2424
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.deniedBody }),
2425
- recovery && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { "data-testid": "denied-recovery", children: recovery })
2515
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, role: "region", "aria-label": texts.deniedTitle, children: [
2516
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("h3", { children: texts.deniedTitle }),
2517
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: texts.deniedBody }),
2518
+ recovery && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { "data-testid": "denied-recovery", children: recovery })
2426
2519
  ] });
2427
2520
  }
2428
2521
  if (state.kind === "unsupported") {
2429
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { children: texts.unsupportedBody }) });
2522
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("div", { className, role: "region", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("p", { children: texts.unsupportedBody }) });
2430
2523
  }
2431
2524
  if (state.kind === "error") {
2432
- 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 }) });
2525
+ 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 }) });
2433
2526
  }
2434
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className, role: "region", children: [
2435
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
2527
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)("div", { className, role: "region", children: [
2528
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
2436
2529
  "button",
2437
2530
  {
2438
2531
  type: "button",
@@ -2446,41 +2539,67 @@ function PushPrompt2({ texts, onSubscribed, onDeclined, onInstallRequested, clas
2446
2539
  children: texts.cta
2447
2540
  }
2448
2541
  ),
2449
- onDeclined && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2542
+ onDeclined && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("button", { type: "button", onClick: onDeclined, children: texts.declineCta })
2543
+ ] });
2544
+ }
2545
+
2546
+ // src/components/LanguageSwitcher.tsx
2547
+ var import_sdk9 = require("@hook-sdk/sdk");
2548
+ var import_jsx_runtime23 = require("react/jsx-runtime");
2549
+ function LanguageSwitcher({ id, className, label = "Language" }) {
2550
+ const config = useAppConfig();
2551
+ const i18nConfig = config.i18n;
2552
+ const [userLocale, setUserLocale] = (0, import_sdk9.usePersistedState)(
2553
+ "user-locale",
2554
+ i18nConfig?.defaultLocale ?? "en-US"
2555
+ );
2556
+ if (!i18nConfig) return null;
2557
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("label", { className, children: [
2558
+ label ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: label }) : null,
2559
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
2560
+ "select",
2561
+ {
2562
+ id,
2563
+ value: userLocale,
2564
+ onChange: (e) => setUserLocale(e.target.value),
2565
+ "data-testid": "language-switcher",
2566
+ children: i18nConfig.supportedLocales.map((loc) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("option", { value: loc, children: loc }, loc))
2567
+ }
2568
+ )
2450
2569
  ] });
2451
2570
  }
2452
2571
 
2453
2572
  // src/defaults/LoadingState.tsx
2454
- var import_jsx_runtime22 = require("react/jsx-runtime");
2573
+ var import_jsx_runtime24 = require("react/jsx-runtime");
2455
2574
  function LoadingState({ message }) {
2456
- 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..." }) });
2575
+ 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..." }) });
2457
2576
  }
2458
2577
 
2459
2578
  // src/defaults/EmptyState.tsx
2460
- var import_jsx_runtime23 = require("react/jsx-runtime");
2579
+ var import_jsx_runtime25 = require("react/jsx-runtime");
2461
2580
  function EmptyState({ title, description, action }) {
2462
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2463
- /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2464
- description && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2465
- action && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { style: { marginTop: 16 }, children: action })
2581
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { role: "status", style: { padding: 32, textAlign: "center" }, children: [
2582
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("h2", { style: { marginBottom: 8 }, children: title }),
2583
+ description && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("p", { style: { opacity: 0.7 }, children: description }),
2584
+ action && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { style: { marginTop: 16 }, children: action })
2466
2585
  ] });
2467
2586
  }
2468
2587
 
2469
2588
  // src/hooks/useLoginForm.ts
2470
- var import_react15 = require("react");
2471
- var import_sdk9 = require("@hook-sdk/sdk");
2589
+ var import_react16 = require("react");
2590
+ var import_sdk11 = require("@hook-sdk/sdk");
2472
2591
 
2473
2592
  // src/errors.ts
2474
- var import_sdk8 = require("@hook-sdk/sdk");
2593
+ var import_sdk10 = require("@hook-sdk/sdk");
2475
2594
  function mapSdkError(err) {
2476
- if (err instanceof import_sdk8.SdkRateLimitError) {
2595
+ if (err instanceof import_sdk10.SdkRateLimitError) {
2477
2596
  return {
2478
2597
  code: "rate_limited",
2479
2598
  message: `Aguarde ${err.retryAfter}s e tente novamente.`,
2480
2599
  retryAfter: err.retryAfter
2481
2600
  };
2482
2601
  }
2483
- if (err instanceof import_sdk8.SdkAuthError) {
2602
+ if (err instanceof import_sdk10.SdkAuthError) {
2484
2603
  const detail = err.detail;
2485
2604
  if (detail === "email_unverified") {
2486
2605
  return { code: "email_unverified", message: "Confirme seu e-mail antes de entrar." };
@@ -2490,7 +2609,7 @@ function mapSdkError(err) {
2490
2609
  }
2491
2610
  return { code: "invalid_credentials", message: "E-mail ou senha inv\xE1lidos." };
2492
2611
  }
2493
- if (err instanceof import_sdk8.SdkError && err.httpStatus === 0) {
2612
+ if (err instanceof import_sdk10.SdkError && err.httpStatus === 0) {
2494
2613
  return { code: "network", message: "Sem conex\xE3o com o servidor. Verifique sua internet." };
2495
2614
  }
2496
2615
  if (err instanceof TypeError) {
@@ -2503,20 +2622,20 @@ function mapSdkError(err) {
2503
2622
  var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2504
2623
  var MIN_PASSWORD = 8;
2505
2624
  function useLoginForm() {
2506
- const { auth } = (0, import_sdk9.useHook)();
2507
- const [email, setEmail] = (0, import_react15.useState)("");
2508
- const [password, setPassword] = (0, import_react15.useState)("");
2509
- const [submitting, setSubmitting] = (0, import_react15.useState)(false);
2510
- const [error, setError] = (0, import_react15.useState)(null);
2511
- const [touchedEmail, setTouchedEmail] = (0, import_react15.useState)(false);
2512
- const [touchedPassword, setTouchedPassword] = (0, import_react15.useState)(false);
2513
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react15.useState)(false);
2514
- const validateEmail = (0, import_react15.useMemo)(() => {
2625
+ const { auth } = (0, import_sdk11.useHook)();
2626
+ const [email, setEmail] = (0, import_react16.useState)("");
2627
+ const [password, setPassword] = (0, import_react16.useState)("");
2628
+ const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2629
+ const [error, setError] = (0, import_react16.useState)(null);
2630
+ const [touchedEmail, setTouchedEmail] = (0, import_react16.useState)(false);
2631
+ const [touchedPassword, setTouchedPassword] = (0, import_react16.useState)(false);
2632
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react16.useState)(false);
2633
+ const validateEmail = (0, import_react16.useMemo)(() => {
2515
2634
  if (email.length === 0) return null;
2516
2635
  if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
2517
2636
  return null;
2518
2637
  }, [email]);
2519
- const validatePassword = (0, import_react15.useMemo)(() => {
2638
+ const validatePassword = (0, import_react16.useMemo)(() => {
2520
2639
  if (password.length === 0) return null;
2521
2640
  if (password.length < MIN_PASSWORD) return `M\xEDnimo de ${MIN_PASSWORD} caracteres.`;
2522
2641
  return null;
@@ -2524,7 +2643,7 @@ function useLoginForm() {
2524
2643
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2525
2644
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2526
2645
  const canSubmit = email.length > 0 && password.length >= MIN_PASSWORD && validateEmail === null && validatePassword === null && !submitting;
2527
- const submit = (0, import_react15.useCallback)(async () => {
2646
+ const submit = (0, import_react16.useCallback)(async () => {
2528
2647
  setFormSubmitAttempted(true);
2529
2648
  if (!canSubmit) return false;
2530
2649
  setSubmitting(true);
@@ -2558,32 +2677,32 @@ function useLoginForm() {
2558
2677
  }
2559
2678
 
2560
2679
  // src/hooks/useSignupForm.ts
2561
- var import_react16 = require("react");
2562
- var import_sdk10 = require("@hook-sdk/sdk");
2680
+ var import_react17 = require("react");
2681
+ var import_sdk12 = require("@hook-sdk/sdk");
2563
2682
  var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2564
2683
  var MIN_PASSWORD2 = 8;
2565
2684
  function useSignupForm() {
2566
- const { auth } = (0, import_sdk10.useHook)();
2567
- const [name, setName] = (0, import_react16.useState)("");
2568
- const [email, setEmail] = (0, import_react16.useState)("");
2569
- const [password, setPassword] = (0, import_react16.useState)("");
2570
- const [submitting, setSubmitting] = (0, import_react16.useState)(false);
2571
- const [error, setError] = (0, import_react16.useState)(null);
2572
- const [touchedName, setTouchedName] = (0, import_react16.useState)(false);
2573
- const [touchedEmail, setTouchedEmail] = (0, import_react16.useState)(false);
2574
- const [touchedPassword, setTouchedPassword] = (0, import_react16.useState)(false);
2575
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react16.useState)(false);
2576
- const validateName = (0, import_react16.useMemo)(() => {
2685
+ const { auth } = (0, import_sdk12.useHook)();
2686
+ const [name, setName] = (0, import_react17.useState)("");
2687
+ const [email, setEmail] = (0, import_react17.useState)("");
2688
+ const [password, setPassword] = (0, import_react17.useState)("");
2689
+ const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2690
+ const [error, setError] = (0, import_react17.useState)(null);
2691
+ const [touchedName, setTouchedName] = (0, import_react17.useState)(false);
2692
+ const [touchedEmail, setTouchedEmail] = (0, import_react17.useState)(false);
2693
+ const [touchedPassword, setTouchedPassword] = (0, import_react17.useState)(false);
2694
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
2695
+ const validateName = (0, import_react17.useMemo)(() => {
2577
2696
  if (name.length === 0) return null;
2578
2697
  if (name.trim().length < 2) return "Nome muito curto.";
2579
2698
  return null;
2580
2699
  }, [name]);
2581
- const validateEmail = (0, import_react16.useMemo)(() => {
2700
+ const validateEmail = (0, import_react17.useMemo)(() => {
2582
2701
  if (email.length === 0) return null;
2583
2702
  if (!EMAIL_RE2.test(email)) return "Formato de e-mail inv\xE1lido.";
2584
2703
  return null;
2585
2704
  }, [email]);
2586
- const validatePassword = (0, import_react16.useMemo)(() => {
2705
+ const validatePassword = (0, import_react17.useMemo)(() => {
2587
2706
  if (password.length === 0) return null;
2588
2707
  if (password.length < MIN_PASSWORD2) return `M\xEDnimo de ${MIN_PASSWORD2} caracteres.`;
2589
2708
  return null;
@@ -2592,7 +2711,7 @@ function useSignupForm() {
2592
2711
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2593
2712
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2594
2713
  const canSubmit = name.trim().length >= 2 && email.length > 0 && password.length >= MIN_PASSWORD2 && validateName === null && validateEmail === null && validatePassword === null && !submitting;
2595
- const submit = (0, import_react16.useCallback)(async () => {
2714
+ const submit = (0, import_react17.useCallback)(async () => {
2596
2715
  setFormSubmitAttempted(true);
2597
2716
  if (!canSubmit) return false;
2598
2717
  setSubmitting(true);
@@ -2630,25 +2749,25 @@ function useSignupForm() {
2630
2749
  }
2631
2750
 
2632
2751
  // src/hooks/useForgotForm.ts
2633
- var import_react17 = require("react");
2634
- var import_sdk11 = require("@hook-sdk/sdk");
2752
+ var import_react18 = require("react");
2753
+ var import_sdk13 = require("@hook-sdk/sdk");
2635
2754
  var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
2636
2755
  function useForgotForm() {
2637
- const { auth } = (0, import_sdk11.useHook)();
2638
- const [email, setEmail] = (0, import_react17.useState)("");
2639
- const [submitting, setSubmitting] = (0, import_react17.useState)(false);
2640
- const [sent, setSent] = (0, import_react17.useState)(false);
2641
- const [error, setError] = (0, import_react17.useState)(null);
2642
- const [touchedEmail, setTouchedEmail] = (0, import_react17.useState)(false);
2643
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react17.useState)(false);
2644
- const validateEmail = (0, import_react17.useMemo)(() => {
2756
+ const { auth } = (0, import_sdk13.useHook)();
2757
+ const [email, setEmail] = (0, import_react18.useState)("");
2758
+ const [submitting, setSubmitting] = (0, import_react18.useState)(false);
2759
+ const [sent, setSent] = (0, import_react18.useState)(false);
2760
+ const [error, setError] = (0, import_react18.useState)(null);
2761
+ const [touchedEmail, setTouchedEmail] = (0, import_react18.useState)(false);
2762
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
2763
+ const validateEmail = (0, import_react18.useMemo)(() => {
2645
2764
  if (email.length === 0) return null;
2646
2765
  if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
2647
2766
  return null;
2648
2767
  }, [email]);
2649
2768
  const emailError = touchedEmail || formSubmitAttempted ? validateEmail : null;
2650
2769
  const canSubmit = email.length > 0 && validateEmail === null && !submitting;
2651
- const submit = (0, import_react17.useCallback)(async () => {
2770
+ const submit = (0, import_react18.useCallback)(async () => {
2652
2771
  setFormSubmitAttempted(true);
2653
2772
  if (!canSubmit) return false;
2654
2773
  setSubmitting(true);
@@ -2679,32 +2798,32 @@ function useForgotForm() {
2679
2798
  }
2680
2799
 
2681
2800
  // src/hooks/useResetForm.ts
2682
- var import_react18 = require("react");
2683
- var import_sdk12 = require("@hook-sdk/sdk");
2801
+ var import_react19 = require("react");
2802
+ var import_sdk14 = require("@hook-sdk/sdk");
2684
2803
  var MIN_PASSWORD3 = 12;
2685
2804
  function useResetForm() {
2686
- const { auth } = (0, import_sdk12.useHook)();
2687
- const [token, setToken] = (0, import_react18.useState)(null);
2688
- const [password, setPassword] = (0, import_react18.useState)("");
2689
- const [confirm, setConfirm] = (0, import_react18.useState)("");
2690
- const [submitting, setSubmitting] = (0, import_react18.useState)(false);
2691
- const [done, setDone] = (0, import_react18.useState)(false);
2692
- const [error, setError] = (0, import_react18.useState)(null);
2693
- const [touchedPassword, setTouchedPassword] = (0, import_react18.useState)(false);
2694
- const [touchedConfirm, setTouchedConfirm] = (0, import_react18.useState)(false);
2695
- const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react18.useState)(false);
2696
- (0, import_react18.useEffect)(() => {
2805
+ const { auth } = (0, import_sdk14.useHook)();
2806
+ const [token, setToken] = (0, import_react19.useState)(null);
2807
+ const [password, setPassword] = (0, import_react19.useState)("");
2808
+ const [confirm, setConfirm] = (0, import_react19.useState)("");
2809
+ const [submitting, setSubmitting] = (0, import_react19.useState)(false);
2810
+ const [done, setDone] = (0, import_react19.useState)(false);
2811
+ const [error, setError] = (0, import_react19.useState)(null);
2812
+ const [touchedPassword, setTouchedPassword] = (0, import_react19.useState)(false);
2813
+ const [touchedConfirm, setTouchedConfirm] = (0, import_react19.useState)(false);
2814
+ const [formSubmitAttempted, setFormSubmitAttempted] = (0, import_react19.useState)(false);
2815
+ (0, import_react19.useEffect)(() => {
2697
2816
  if (typeof window === "undefined") return;
2698
2817
  const params = new URLSearchParams(window.location.search);
2699
2818
  const t = params.get("token");
2700
2819
  setToken(t && t.length > 0 ? t : null);
2701
2820
  }, []);
2702
- const validatePassword = (0, import_react18.useMemo)(() => {
2821
+ const validatePassword = (0, import_react19.useMemo)(() => {
2703
2822
  if (password.length === 0) return null;
2704
2823
  if (password.length < MIN_PASSWORD3) return `M\xEDnimo de ${MIN_PASSWORD3} caracteres.`;
2705
2824
  return null;
2706
2825
  }, [password]);
2707
- const validateConfirm = (0, import_react18.useMemo)(() => {
2826
+ const validateConfirm = (0, import_react19.useMemo)(() => {
2708
2827
  if (confirm.length === 0) return null;
2709
2828
  if (confirm !== password) return "Senhas n\xE3o coincidem.";
2710
2829
  return null;
@@ -2712,7 +2831,7 @@ function useResetForm() {
2712
2831
  const passwordError = touchedPassword || formSubmitAttempted ? validatePassword : null;
2713
2832
  const confirmError = touchedConfirm || formSubmitAttempted ? validateConfirm : null;
2714
2833
  const canSubmit = token !== null && password.length >= MIN_PASSWORD3 && confirm === password && validatePassword === null && validateConfirm === null && !submitting && !done;
2715
- const submit = (0, import_react18.useCallback)(async () => {
2834
+ const submit = (0, import_react19.useCallback)(async () => {
2716
2835
  setFormSubmitAttempted(true);
2717
2836
  if (!canSubmit || token === null) return;
2718
2837
  setSubmitting(true);
@@ -2752,9 +2871,9 @@ function useResetForm() {
2752
2871
  }
2753
2872
 
2754
2873
  // src/hooks/usePlan.ts
2755
- var import_sdk13 = require("@hook-sdk/sdk");
2874
+ var import_sdk15 = require("@hook-sdk/sdk");
2756
2875
  function usePlan() {
2757
- const { plan } = (0, import_sdk13.useHook)();
2876
+ const { plan } = (0, import_sdk15.useHook)();
2758
2877
  return plan;
2759
2878
  }
2760
2879
 
@@ -2787,12 +2906,12 @@ function discountPercent(anchorCents, realCents) {
2787
2906
  }
2788
2907
 
2789
2908
  // src/hooks/useAuthPrimitives.ts
2790
- var import_react19 = require("react");
2791
- var import_sdk14 = require("@hook-sdk/sdk");
2909
+ var import_react20 = require("react");
2910
+ var import_sdk16 = require("@hook-sdk/sdk");
2792
2911
  var warned = false;
2793
2912
  function useAuthPrimitives() {
2794
- const { auth } = (0, import_sdk14.useHook)();
2795
- (0, import_react19.useEffect)(() => {
2913
+ const { auth } = (0, import_sdk16.useHook)();
2914
+ (0, import_react20.useEffect)(() => {
2796
2915
  if (!warned && process.env.NODE_ENV !== "production") {
2797
2916
  warned = true;
2798
2917
  console.warn(
@@ -2814,9 +2933,9 @@ function useAuthPrimitives() {
2814
2933
  }
2815
2934
 
2816
2935
  // src/hooks/useAuth.ts
2817
- var import_sdk15 = require("@hook-sdk/sdk");
2936
+ var import_sdk17 = require("@hook-sdk/sdk");
2818
2937
  function useAuth() {
2819
- const { user, authStatus, auth } = (0, import_sdk15.useHook)();
2938
+ const { user, authStatus, auth } = (0, import_sdk17.useHook)();
2820
2939
  return {
2821
2940
  user,
2822
2941
  authStatus,
@@ -2825,26 +2944,26 @@ function useAuth() {
2825
2944
  }
2826
2945
 
2827
2946
  // src/index.ts
2828
- var import_sdk19 = require("@hook-sdk/sdk");
2947
+ var import_sdk21 = require("@hook-sdk/sdk");
2829
2948
 
2830
2949
  // src/hooks/useSubscription.ts
2831
- var import_sdk16 = require("@hook-sdk/sdk");
2950
+ var import_sdk18 = require("@hook-sdk/sdk");
2832
2951
  function useSubscription() {
2833
- const { subscription } = (0, import_sdk16.useHook)();
2952
+ const { subscription } = (0, import_sdk18.useHook)();
2834
2953
  return {
2835
2954
  status: subscription.status()
2836
2955
  };
2837
2956
  }
2838
2957
 
2839
2958
  // src/hooks/useReminders.ts
2840
- var import_react20 = require("react");
2841
- var import_sdk17 = require("@hook-sdk/sdk");
2959
+ var import_react21 = require("react");
2960
+ var import_sdk19 = require("@hook-sdk/sdk");
2842
2961
  function useReminders() {
2843
- const { push } = (0, import_sdk17.useHook)();
2962
+ const { push } = (0, import_sdk19.useHook)();
2844
2963
  const r = push.reminders;
2845
- const [reminders, setReminders] = (0, import_react20.useState)([]);
2846
- const [loading, setLoading] = (0, import_react20.useState)(true);
2847
- const reload = (0, import_react20.useCallback)(async () => {
2964
+ const [reminders, setReminders] = (0, import_react21.useState)([]);
2965
+ const [loading, setLoading] = (0, import_react21.useState)(true);
2966
+ const reload = (0, import_react21.useCallback)(async () => {
2848
2967
  setLoading(true);
2849
2968
  try {
2850
2969
  const next = await r.list();
@@ -2853,38 +2972,38 @@ function useReminders() {
2853
2972
  setLoading(false);
2854
2973
  }
2855
2974
  }, [r]);
2856
- (0, import_react20.useEffect)(() => {
2975
+ (0, import_react21.useEffect)(() => {
2857
2976
  void reload();
2858
2977
  }, [reload]);
2859
- const setReminder = (0, import_react20.useCallback)(async (input) => {
2978
+ const setReminder = (0, import_react21.useCallback)(async (input) => {
2860
2979
  await r.set(input);
2861
2980
  await reload();
2862
2981
  }, [r, reload]);
2863
- const deleteReminder = (0, import_react20.useCallback)(async (slot) => {
2982
+ const deleteReminder = (0, import_react21.useCallback)(async (slot) => {
2864
2983
  await r.delete(slot);
2865
2984
  await reload();
2866
2985
  }, [r, reload]);
2867
- const schedule = (0, import_react20.useCallback)(async (items) => {
2986
+ const schedule = (0, import_react21.useCallback)(async (items) => {
2868
2987
  return r.schedule(items);
2869
2988
  }, [r]);
2870
- const setFallbacks = (0, import_react20.useCallback)(async (items) => {
2989
+ const setFallbacks = (0, import_react21.useCallback)(async (items) => {
2871
2990
  return r.setFallbacks(items);
2872
2991
  }, [r]);
2873
2992
  return { reminders, loading, setReminder, deleteReminder, schedule, setFallbacks };
2874
2993
  }
2875
2994
 
2876
2995
  // src/hooks/useToast.ts
2877
- var import_react21 = require("react");
2996
+ var import_react22 = require("react");
2878
2997
  function useToast() {
2879
- const [items, setItems] = (0, import_react21.useState)([]);
2880
- const show = (0, import_react21.useCallback)((message, kind = "info") => {
2998
+ const [items, setItems] = (0, import_react22.useState)([]);
2999
+ const show = (0, import_react22.useCallback)((message, kind = "info") => {
2881
3000
  const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
2882
3001
  setItems((prev) => [...prev, { id, message, kind }]);
2883
3002
  setTimeout(() => {
2884
3003
  setItems((prev) => prev.filter((t) => t.id !== id));
2885
3004
  }, 4e3);
2886
3005
  }, []);
2887
- const dismiss = (0, import_react21.useCallback)((id) => {
3006
+ const dismiss = (0, import_react22.useCallback)((id) => {
2888
3007
  setItems((prev) => prev.filter((t) => t.id !== id));
2889
3008
  }, []);
2890
3009
  return { items, show, dismiss };
@@ -2892,20 +3011,20 @@ function useToast() {
2892
3011
 
2893
3012
  // src/RouteBoundary.tsx
2894
3013
  var import_react_router_dom3 = require("react-router-dom");
2895
- var import_jsx_runtime24 = require("react/jsx-runtime");
3014
+ var import_jsx_runtime26 = require("react/jsx-runtime");
2896
3015
  function RouteBoundary({ children }) {
2897
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_react_router_dom3.Routes, { children: [
3016
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_react_router_dom3.Routes, { children: [
2898
3017
  children,
2899
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(DefaultNotFound, {}) })
3018
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_router_dom3.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(DefaultNotFound, {}) })
2900
3019
  ] });
2901
3020
  }
2902
3021
  function DefaultNotFound() {
2903
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
3022
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)("div", { role: "alert", children: "P\xE1gina n\xE3o encontrada" });
2904
3023
  }
2905
3024
 
2906
3025
  // src/PreAuthShell.tsx
2907
3026
  var import_react_router_dom4 = require("react-router-dom");
2908
- var import_jsx_runtime25 = require("react/jsx-runtime");
3027
+ var import_jsx_runtime27 = require("react/jsx-runtime");
2909
3028
  function PreAuthShell({
2910
3029
  basename,
2911
3030
  testRouter,
@@ -2913,20 +3032,20 @@ function PreAuthShell({
2913
3032
  children
2914
3033
  }) {
2915
3034
  if (testRouter === "memory") {
2916
- 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 }) });
3035
+ 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 }) });
2917
3036
  }
2918
- 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 }) });
3037
+ 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 }) });
2919
3038
  }
2920
3039
 
2921
3040
  // src/OnboardingFlow.tsx
2922
- var import_react23 = require("react");
2923
- var import_sdk18 = require("@hook-sdk/sdk");
3041
+ var import_react24 = require("react");
3042
+ var import_sdk20 = require("@hook-sdk/sdk");
2924
3043
 
2925
3044
  // src/hooks/useOnboardingStep.ts
2926
- var import_react22 = require("react");
2927
- var OnboardingStepContext = (0, import_react22.createContext)(null);
3045
+ var import_react23 = require("react");
3046
+ var OnboardingStepContext = (0, import_react23.createContext)(null);
2928
3047
  function useOnboardingStep() {
2929
- const ctx = (0, import_react22.useContext)(OnboardingStepContext);
3048
+ const ctx = (0, import_react23.useContext)(OnboardingStepContext);
2930
3049
  if (!ctx) {
2931
3050
  throw new Error(
2932
3051
  "[hook-template] useOnboardingStep must be used inside <OnboardingFlow>. (G75)"
@@ -2936,7 +3055,7 @@ function useOnboardingStep() {
2936
3055
  }
2937
3056
 
2938
3057
  // src/OnboardingFlow.tsx
2939
- var import_jsx_runtime26 = require("react/jsx-runtime");
3058
+ var import_jsx_runtime28 = require("react/jsx-runtime");
2940
3059
  var isFilled = (v) => v != null && v !== "";
2941
3060
  var CURRENT_STEP_FIELD = "currentStep";
2942
3061
  function readPersistedStepIdx(draft) {
@@ -2949,12 +3068,12 @@ function OnboardingFlow({
2949
3068
  onComplete,
2950
3069
  persistKey
2951
3070
  }) {
2952
- const [draft, setDraft, status] = (0, import_sdk18.usePersistedState)(persistKey, {});
2953
- const draftRef = (0, import_react23.useRef)(draft);
3071
+ const [draft, setDraft, status] = (0, import_sdk20.usePersistedState)(persistKey, {});
3072
+ const draftRef = (0, import_react24.useRef)(draft);
2954
3073
  draftRef.current = draft;
2955
3074
  const idx = readPersistedStepIdx(draft);
2956
3075
  const clampedIdx = Math.min(Math.max(idx, 0), Math.max(steps.length - 1, 0));
2957
- const setIdx = (0, import_react23.useCallback)(
3076
+ const setIdx = (0, import_react24.useCallback)(
2958
3077
  (n) => {
2959
3078
  setDraft((prev) => {
2960
3079
  const prevIdx = readPersistedStepIdx(prev);
@@ -2964,7 +3083,7 @@ function OnboardingFlow({
2964
3083
  },
2965
3084
  [setDraft]
2966
3085
  );
2967
- const setValue = (0, import_react23.useCallback)(
3086
+ const setValue = (0, import_react24.useCallback)(
2968
3087
  (patch) => {
2969
3088
  draftRef.current = { ...draftRef.current, ...patch };
2970
3089
  setDraft((prev) => ({ ...prev, ...patch }));
@@ -2972,9 +3091,9 @@ function OnboardingFlow({
2972
3091
  [setDraft]
2973
3092
  );
2974
3093
  const step = steps[clampedIdx];
2975
- const hookCtx = (0, import_sdk18.useHook)();
3094
+ const hookCtx = (0, import_sdk20.useHook)();
2976
3095
  const track2 = typeof hookCtx.track === "function" ? hookCtx.track : void 0;
2977
- (0, import_react23.useEffect)(() => {
3096
+ (0, import_react24.useEffect)(() => {
2978
3097
  if (status.loading) return;
2979
3098
  if (!step) return;
2980
3099
  if (!track2) return;
@@ -2984,11 +3103,11 @@ function OnboardingFlow({
2984
3103
  total_steps: steps.length
2985
3104
  });
2986
3105
  }, [step?.id, clampedIdx, steps.length, status.loading, track2]);
2987
- const valid = (0, import_react23.useMemo)(
3106
+ const valid = (0, import_react24.useMemo)(
2988
3107
  () => step ? (step.validates ?? []).every((field) => isFilled(draft[field])) : false,
2989
3108
  [draft, step]
2990
3109
  );
2991
- const next = (0, import_react23.useCallback)(() => {
3110
+ const next = (0, import_react24.useCallback)(() => {
2992
3111
  if (!step) return;
2993
3112
  const current = draftRef.current;
2994
3113
  const validNow = (step.validates ?? []).every((field) => isFilled(current[field]));
@@ -2999,8 +3118,8 @@ function OnboardingFlow({
2999
3118
  setIdx(clampedIdx + 1);
3000
3119
  }
3001
3120
  }, [clampedIdx, onComplete, step, steps.length, setIdx]);
3002
- const prevStep = (0, import_react23.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3003
- const ctx = (0, import_react23.useMemo)(
3121
+ const prevStep = (0, import_react24.useCallback)(() => setIdx((i) => Math.max(0, i - 1)), [setIdx]);
3122
+ const ctx = (0, import_react24.useMemo)(
3004
3123
  () => ({
3005
3124
  stepIndex: clampedIdx,
3006
3125
  totalSteps: steps.length,
@@ -3026,7 +3145,7 @@ function OnboardingFlow({
3026
3145
  `[hook-template] OnboardingFlow: missing screen component for step '${step.id}' (expected key '${step.screen}' in screens prop)`
3027
3146
  );
3028
3147
  }
3029
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(Screen, {}) });
3148
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(OnboardingStepContext.Provider, { value: ctx, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Screen, {}) });
3030
3149
  }
3031
3150
 
3032
3151
  // src/hooks/useFeature.ts
@@ -3042,8 +3161,10 @@ function useFeature(name) {
3042
3161
  DeepLinkHandler,
3043
3162
  EmptyState,
3044
3163
  ErrorBoundary,
3164
+ I18nProvider,
3045
3165
  InstallGate,
3046
3166
  InstallSplash,
3167
+ LanguageSwitcher,
3047
3168
  LoadingState,
3048
3169
  OnboardingFlow,
3049
3170
  PaymentReturnHandler,