@hook-sdk/template 0.19.0 → 0.21.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.d.cts CHANGED
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode, ComponentType, Component } from 'react';
4
4
  import * as _hook_sdk_sdk from '@hook-sdk/sdk';
5
- import { CheckoutMethod as CheckoutMethod$1, CheckoutCycle, CheckoutResult, CheckoutCardData, CheckoutHolderInfo, PlanState, ReminderSlot } from '@hook-sdk/sdk';
5
+ import { HookContextValue, CheckoutMethod as CheckoutMethod$1, CheckoutCycle, CheckoutResult, CheckoutCardData, CheckoutHolderInfo, PlanState, ReminderSlot } from '@hook-sdk/sdk';
6
6
  export { PlanInfo, PlanState, useTrackOnboardingStep } from '@hook-sdk/sdk';
7
7
  import { z } from 'zod';
8
8
 
@@ -19,7 +19,27 @@ type PaywallConfig = {
19
19
  mode: 'free';
20
20
  } | {
21
21
  mode: 'trial' | 'pay_first';
22
+ /**
23
+ * Legacy flat trial — fallback when per-method fields aren't set.
24
+ * Read via `trialDaysForMethod(method)` helper on `usePaywallState`.
25
+ */
22
26
  trialDays?: number;
27
+ /**
28
+ * Per-method trial overrides (ADR-022 Amendment 2026-05-12 + G154).
29
+ * - `trialDaysCard` — days of free trial on the card method.
30
+ * Default 7 in the backend, but apps can opt down to 0 if they want
31
+ * PIX-style "pay now" semantics on cards too.
32
+ * - `trialDaysPix` — days of free trial on PIX Auto. Default 0 because
33
+ * Asaas does not implement BCB Jornada 2 (consent-only authorization).
34
+ * Any value > 0 forces the R$ 0,01 capture workaround — see G123-G127.
35
+ */
36
+ trialDaysCard?: number;
37
+ trialDaysPix?: number;
38
+ /**
39
+ * Which method the paywall preselects. Reflects creator audience,
40
+ * not Hook bias. `null`/`undefined` = no preselection — user picks.
41
+ */
42
+ defaultMethod?: CheckoutMethod | null;
23
43
  cycles: Cycle[];
24
44
  prices: {
25
45
  monthlyCents: number;
@@ -120,6 +140,33 @@ interface AuthScreenProps {
120
140
  onNavigate?: (target: 'login' | 'signup' | 'forgot' | 'reset') => void;
121
141
  }
122
142
 
143
+ interface SkipDefaults {
144
+ /**
145
+ * Final flag the host app's ProtectedRoute reads. If unset here, the helper
146
+ * forces it to `true` after merging defaults.
147
+ */
148
+ onboarding_completed?: boolean;
149
+ /**
150
+ * Free-form per-app fields (userName, mainGoal, faixa, kids[], etc.). The
151
+ * helper merges this object verbatim into `appData.set('onboarding_data', …)`.
152
+ */
153
+ [field: string]: unknown;
154
+ /**
155
+ * Optional per-app seed callback. Use to insert anything that lives outside
156
+ * `onboarding_data` (e.g. seed first workout in `hook.db.collection('workouts')`).
157
+ * Awaited after `appData.set` and before the hard reload.
158
+ */
159
+ __seed?: (hook: HookContextValue) => Promise<void>;
160
+ }
161
+ /**
162
+ * Programmatic skip helper. Exposed for advanced consumers / tests; the FAB
163
+ * just calls this on confirm.
164
+ */
165
+ declare function skipOnboarding(hook: HookContextValue, defaults: SkipDefaults, appSlug: string): Promise<void>;
166
+ declare function DevSkipOnboardingFab({ defaults }: {
167
+ defaults: SkipDefaults;
168
+ }): react_jsx_runtime.JSX.Element;
169
+
123
170
  declare function PaymentReturnHandler({ children }: {
124
171
  children: ReactNode;
125
172
  }): react_jsx_runtime.JSX.Element;
@@ -145,27 +192,54 @@ type AppRootProps = AppRootSlots & {
145
192
  testRouter?: 'memory';
146
193
  /** Test-only: initial entries for MemoryRouter. */
147
194
  testInitialEntries?: string[];
195
+ /**
196
+ * Staging-only dev tools. When this prop is set AND
197
+ * `VITE_HOOK_DEV_TOOLS=1` AND the hostname is staging/localhost, AppRoot
198
+ * mounts a floating "skip onboarding" button that pre-fills
199
+ * `appData.onboarding_data` with the supplied defaults and lands the user
200
+ * on `/app/<slug>/`. Tree-shaken from prod builds via the build-time env
201
+ * replacement (see `dev/env.ts`).
202
+ */
203
+ devSkipOnboarding?: {
204
+ defaults: SkipDefaults;
205
+ };
148
206
  };
149
207
 
150
208
  declare function AppRoot(props: AppRootProps): react_jsx_runtime.JSX.Element;
151
209
 
210
+ /**
211
+ * Build-time + runtime gate for dev-only tools (e.g. <DevSkipOnboardingFab>).
212
+ *
213
+ * Two independent signals must agree:
214
+ *
215
+ * 1. Build-time: `import.meta.env.VITE_HOOK_DEV_TOOLS === '1'`. Vite folds
216
+ * this constant at build time — when unset, the entire dev tree is
217
+ * tree-shaken from the prod bundle (sideEffects:false in package.json
218
+ * makes that effective). Set `VITE_HOOK_DEV_TOOLS=1` only in
219
+ * `.env.staging` builds.
220
+ *
221
+ * 2. Runtime: hostname must be staging-ish. Belt-and-suspenders against
222
+ * a misconfigured build that somehow ships the FAB to prod.
223
+ */
224
+ declare function isDevToolsEnabled(): boolean;
225
+
152
226
  interface PushPromptTexts {
153
227
  cta: string;
154
228
  declineCta: string;
155
229
  iosInstallTitle: string;
156
230
  iosInstallBody: string;
157
231
  iosInstallCta?: string;
158
- deniedTitle: string;
159
- deniedBody: string;
160
- /**
161
- * Audit Wave 3 — Fix #33: per-platform recovery copy shown when permission
162
- * is denied. All four are optional; if the matching platform's copy is
163
- * missing the recovery paragraph is omitted (back-compat for callers that
164
- * haven't supplied them yet).
165
- */
232
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
233
+ deniedTitle?: string;
234
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
235
+ deniedBody?: string;
236
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
166
237
  deniedRecoveryIos?: string;
238
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
167
239
  deniedRecoveryAndroid?: string;
240
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
168
241
  deniedRecoveryDesktop?: string;
242
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
169
243
  deniedRecoveryInApp?: string;
170
244
  unsupportedBody: string;
171
245
  }
@@ -464,6 +538,16 @@ declare function usePaywallState(): {
464
538
  methods: readonly CheckoutMethod$1[];
465
539
  selectedMethod: CheckoutMethod$1;
466
540
  setSelectedMethod: react.Dispatch<react.SetStateAction<CheckoutMethod$1>>;
541
+ hasConsumedTrial: boolean;
542
+ currentPriceCents: number;
543
+ currentMonthlyEquivCents: number;
544
+ anchorPriceCents: number | null;
545
+ selectMethod: (next: CheckoutMethod$1) => void;
546
+ selectCycle: (next: CheckoutCycle) => void;
547
+ isFree: boolean;
548
+ trialDaysForMethod: (method: CheckoutMethod$1) => number;
549
+ trialDaysCard: number;
550
+ trialDaysPix: number;
467
551
  cpfState: CpfState;
468
552
  cardState: CardFormStateWithSetter;
469
553
  submit: () => Promise<CheckoutResult | undefined>;
@@ -882,6 +966,13 @@ declare const AppConfigSchema: z.ZodObject<{
882
966
  pay_first: "pay_first";
883
967
  }>;
884
968
  trialDays: z.ZodOptional<z.ZodNumber>;
969
+ trialDaysCard: z.ZodOptional<z.ZodNumber>;
970
+ trialDaysPix: z.ZodOptional<z.ZodNumber>;
971
+ defaultMethod: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
972
+ card: "card";
973
+ "pix-auto": "pix-auto";
974
+ "pix-once": "pix-once";
975
+ }>>>;
885
976
  cycles: z.ZodArray<z.ZodEnum<{
886
977
  MONTHLY: "MONTHLY";
887
978
  YEARLY: "YEARLY";
@@ -950,4 +1041,153 @@ declare const AppConfigSchema: z.ZodObject<{
950
1041
  }, z.core.$strict>;
951
1042
  declare function parseAppConfig(input: unknown): AppConfig;
952
1043
 
953
- export { type AndroidBrowser, type AppConfig, AppConfigProvider, AppConfigSchema, AppRoot, type AppRootProps, type AppRootSlots, type AuthFlowConfig, type AuthFormError, type AuthFormErrorCode, type AuthScreenProps, type CheckoutMethod, type Cycle, DeepLinkHandler, type DeepLinks, EmptyState, ErrorBoundary, type I18nConfig, I18nProvider, type I18nProviderProps, type IOSBrowser, type InAppApp, type InstallActions, InstallGate, InstallSplash, type InstallState, type InstallVariant, LanguageSwitcher, type LanguageSwitcherProps, LoadingState, type OnboardingConfig, OnboardingFlow, type OnboardingFlowProps, type OnboardingStep, type OnboardingStepCtx, type OnboardingStepDef, type PaymentMethod, PaymentReturnHandler, type PaywallConfig, type PersistedKey, PersistenceRegistry, type PersistenceRegistryProps, type PixPending, type Platform, PreAuthShell, type PreAuthShellProps, PushPrompt, type PushPromptProps, type PushPromptTexts, type PushUiState, RouteBoundary, type RouteBoundaryProps, type SubscriptionStatus, type ToastItem, type UseLoginFormResult, type UseResetFormResult, asaasErrorMessage, computeAnchorCents, dailyFromYearly, detectAndroidBrowser, detectIOSBrowser, detectInAppApp, detectPlatform, detectStandalone, discountPercent, formatBRL, monthlyFromYearly, parseAppConfig, shouldBlockInstall, shouldShowPermanentOption, useAppConfig, useAuth, useAuthPrimitives, useFeature, useForgotForm, useInstallPrompt, useLoginForm, useOnboardingStep, usePaywallState, usePlan, usePush, useReminders, useResetForm, useSignupForm, useSubscription, useToast };
1044
+ type PaywallMethodCopy = {
1045
+ /** Tab label, e.g. "⚡ PIX" or "💳 Cartão" */
1046
+ tabLabel: string;
1047
+ /** 3 body rows under the active tab. Use literal strings; price/days come from the hook. */
1048
+ bodyRows: [string, string, string];
1049
+ /** CTA label template. `{price}` and `{days}` placeholders are interpolated. */
1050
+ ctaTemplate: string;
1051
+ /** Switch-hint copy shown under the CTA when the OTHER tab is available. */
1052
+ switchHint: string;
1053
+ };
1054
+ type PaywallCopy = {
1055
+ headline: string;
1056
+ features: readonly string[];
1057
+ socialProof?: string;
1058
+ /** Trust line above sticky CTA. Shared across methods. */
1059
+ trustLine: string;
1060
+ pix: PaywallMethodCopy;
1061
+ card: PaywallMethodCopy;
1062
+ /** Used when `usePaywallState().hasConsumedTrial === true`. Card tab body + CTA shift. */
1063
+ cardConsumedTrial: Omit<PaywallMethodCopy, 'tabLabel' | 'switchHint'>;
1064
+ cycle: {
1065
+ annualLabel: string;
1066
+ monthlyLabel: string;
1067
+ /** Append after price on annual card, e.g. "/mês · anual" */
1068
+ annualSuffix: string;
1069
+ /** Append after price on monthly card, e.g. "/mês" */
1070
+ monthlySuffix: string;
1071
+ };
1072
+ /** Optional override for the "free" CTA when `paywall.mode === 'free'`. */
1073
+ freeCta?: string;
1074
+ };
1075
+ type PaywallThemeClasses = {
1076
+ /** Container wrapper. Default: empty. */
1077
+ container?: string;
1078
+ /** Headline `<h1>`. */
1079
+ headline?: string;
1080
+ /** Feature row `<li>`. */
1081
+ feature?: string;
1082
+ /** Cycle picker card. */
1083
+ cycleCard?: string;
1084
+ /** Cycle picker card when selected. */
1085
+ cycleCardSelected?: string;
1086
+ /** Method tabs wrapper (pill background). */
1087
+ tabs?: string;
1088
+ /** Individual tab. */
1089
+ tab?: string;
1090
+ /** Individual tab when active. */
1091
+ tabActive?: string;
1092
+ /** Tab body card. */
1093
+ tabContent?: string;
1094
+ /** Tab body row (one row per icon+text). */
1095
+ tabContentRow?: string;
1096
+ /** CTA button — applied when method=pix-auto. */
1097
+ ctaPix?: string;
1098
+ /** CTA button — applied when method=card. */
1099
+ ctaCard?: string;
1100
+ /** Switch-hint line under CTA. */
1101
+ switchHint?: string;
1102
+ /** Trust line under switch hint. */
1103
+ trustLine?: string;
1104
+ /** Social proof badge. */
1105
+ socialProof?: string;
1106
+ /** Anchor strikethrough price. */
1107
+ anchorPrice?: string;
1108
+ };
1109
+ type PaywallSlots = {
1110
+ /** Above headline (hero image, brand visual). */
1111
+ heroSlot?: ReactNode;
1112
+ /** Below tab content, above CTA (e.g. testimonials). */
1113
+ beforeCtaSlot?: ReactNode;
1114
+ /** Replace the cycle picker entirely. */
1115
+ cyclePickerSlot?: ReactNode;
1116
+ };
1117
+ type PaywallProps = {
1118
+ copy: PaywallCopy;
1119
+ themeClasses?: PaywallThemeClasses;
1120
+ slots?: PaywallSlots;
1121
+ /** Called immediately before checkout dispatches. Use for opening CPF modal etc. */
1122
+ onBeforeCheckout?: (method: CheckoutMethod, cycle: Cycle) => void | Promise<void>;
1123
+ };
1124
+
1125
+ /**
1126
+ * Composed top-level paywall component. Apps wrap it in their `PaywallOffer.tsx`
1127
+ * (or `Offer.tsx`) and pass copy + themeClasses + slots. Logic + telemetry live
1128
+ * here. To customize layout entirely, drop down to the primitives.
1129
+ */
1130
+ declare function Paywall({ copy, themeClasses, slots, onBeforeCheckout, }: PaywallProps): react_jsx_runtime.JSX.Element;
1131
+
1132
+ type PaywallMethodTabsProps = {
1133
+ methods: readonly CheckoutMethod[];
1134
+ selected: CheckoutMethod;
1135
+ onSelect: (m: CheckoutMethod) => void;
1136
+ labels: Partial<Record<CheckoutMethod, string>>;
1137
+ className?: string;
1138
+ tabClassName?: string;
1139
+ tabActiveClassName?: string;
1140
+ };
1141
+ declare function PaywallMethodTabs({ methods, selected, onSelect, labels, className, tabClassName, tabActiveClassName, }: PaywallMethodTabsProps): react_jsx_runtime.JSX.Element | null;
1142
+
1143
+ type PaywallMethodContentProps = {
1144
+ method: CheckoutMethod;
1145
+ copy: Pick<PaywallCopy, 'pix' | 'card'> & {
1146
+ cardConsumedTrial?: PaywallCopy['cardConsumedTrial'];
1147
+ };
1148
+ hasConsumedTrial?: boolean;
1149
+ className?: string;
1150
+ rowClassName?: string;
1151
+ };
1152
+ declare function PaywallMethodContent({ method, copy, hasConsumedTrial, className, rowClassName, }: PaywallMethodContentProps): react_jsx_runtime.JSX.Element;
1153
+
1154
+ type CycleLabels = {
1155
+ annualLabel: string;
1156
+ monthlyLabel: string;
1157
+ annualSuffix: string;
1158
+ monthlySuffix: string;
1159
+ };
1160
+ type PaywallCyclePickerProps = {
1161
+ cycles: readonly Cycle[];
1162
+ selected: Cycle;
1163
+ onSelect: (c: Cycle) => void;
1164
+ /** Raw price for the cycle (used to show full annual/monthly). */
1165
+ priceCentsByCycle: Record<Cycle, number>;
1166
+ /** Anchor strikethrough price, null when not set. */
1167
+ anchorCentsByCycle: Record<Cycle, number | null>;
1168
+ /** Monthly-equiv for YEARLY (priceCents / 12). Same as priceCentsByCycle for MONTHLY. */
1169
+ monthlyEquivByCycle: Record<Cycle, number>;
1170
+ labels: CycleLabels;
1171
+ className?: string;
1172
+ cardClassName?: string;
1173
+ cardSelectedClassName?: string;
1174
+ anchorClassName?: string;
1175
+ };
1176
+ declare function PaywallCyclePicker({ cycles, selected, onSelect, priceCentsByCycle, anchorCentsByCycle, monthlyEquivByCycle, labels, className, cardClassName, cardSelectedClassName, anchorClassName, }: PaywallCyclePickerProps): react_jsx_runtime.JSX.Element | null;
1177
+
1178
+ type PaywallCtaProps = {
1179
+ ctaLabel: string;
1180
+ loadingLabel?: string;
1181
+ switchHint?: string;
1182
+ trustLine: string;
1183
+ onClick: () => void;
1184
+ disabled?: boolean;
1185
+ loading?: boolean;
1186
+ className?: string;
1187
+ buttonClassName?: string;
1188
+ switchHintClassName?: string;
1189
+ trustClassName?: string;
1190
+ };
1191
+ declare function PaywallCta({ ctaLabel, loadingLabel, switchHint, trustLine, onClick, disabled, loading, className, buttonClassName, switchHintClassName, trustClassName, }: PaywallCtaProps): react_jsx_runtime.JSX.Element;
1192
+
1193
+ export { type AndroidBrowser, type AppConfig, AppConfigProvider, AppConfigSchema, AppRoot, type AppRootProps, type AppRootSlots, type AuthFlowConfig, type AuthFormError, type AuthFormErrorCode, type AuthScreenProps, type CheckoutMethod, type Cycle, type CycleLabels, DeepLinkHandler, type DeepLinks, DevSkipOnboardingFab, EmptyState, ErrorBoundary, type I18nConfig, I18nProvider, type I18nProviderProps, type IOSBrowser, type InAppApp, type InstallActions, InstallGate, InstallSplash, type InstallState, type InstallVariant, LanguageSwitcher, type LanguageSwitcherProps, LoadingState, type OnboardingConfig, OnboardingFlow, type OnboardingFlowProps, type OnboardingStep, type OnboardingStepCtx, type OnboardingStepDef, type PaymentMethod, PaymentReturnHandler, Paywall, type PaywallConfig, type PaywallCopy, PaywallCta, type PaywallCtaProps, PaywallCyclePicker, type PaywallCyclePickerProps, PaywallMethodContent, type PaywallMethodContentProps, type PaywallMethodCopy, PaywallMethodTabs, type PaywallMethodTabsProps, type PaywallProps, type PaywallSlots, type PaywallThemeClasses, type PersistedKey, PersistenceRegistry, type PersistenceRegistryProps, type PixPending, type Platform, PreAuthShell, type PreAuthShellProps, PushPrompt, type PushPromptProps, type PushPromptTexts, type PushUiState, RouteBoundary, type RouteBoundaryProps, type SkipDefaults, type SubscriptionStatus, type ToastItem, type UseLoginFormResult, type UseResetFormResult, asaasErrorMessage, computeAnchorCents, dailyFromYearly, detectAndroidBrowser, detectIOSBrowser, detectInAppApp, detectPlatform, detectStandalone, discountPercent, formatBRL, isDevToolsEnabled, monthlyFromYearly, parseAppConfig, shouldBlockInstall, shouldShowPermanentOption, skipOnboarding, useAppConfig, useAuth, useAuthPrimitives, useFeature, useForgotForm, useInstallPrompt, useLoginForm, useOnboardingStep, usePaywallState, usePlan, usePush, useReminders, useResetForm, useSignupForm, useSubscription, useToast };
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { ReactNode, ComponentType, Component } from 'react';
4
4
  import * as _hook_sdk_sdk from '@hook-sdk/sdk';
5
- import { CheckoutMethod as CheckoutMethod$1, CheckoutCycle, CheckoutResult, CheckoutCardData, CheckoutHolderInfo, PlanState, ReminderSlot } from '@hook-sdk/sdk';
5
+ import { HookContextValue, CheckoutMethod as CheckoutMethod$1, CheckoutCycle, CheckoutResult, CheckoutCardData, CheckoutHolderInfo, PlanState, ReminderSlot } from '@hook-sdk/sdk';
6
6
  export { PlanInfo, PlanState, useTrackOnboardingStep } from '@hook-sdk/sdk';
7
7
  import { z } from 'zod';
8
8
 
@@ -19,7 +19,27 @@ type PaywallConfig = {
19
19
  mode: 'free';
20
20
  } | {
21
21
  mode: 'trial' | 'pay_first';
22
+ /**
23
+ * Legacy flat trial — fallback when per-method fields aren't set.
24
+ * Read via `trialDaysForMethod(method)` helper on `usePaywallState`.
25
+ */
22
26
  trialDays?: number;
27
+ /**
28
+ * Per-method trial overrides (ADR-022 Amendment 2026-05-12 + G154).
29
+ * - `trialDaysCard` — days of free trial on the card method.
30
+ * Default 7 in the backend, but apps can opt down to 0 if they want
31
+ * PIX-style "pay now" semantics on cards too.
32
+ * - `trialDaysPix` — days of free trial on PIX Auto. Default 0 because
33
+ * Asaas does not implement BCB Jornada 2 (consent-only authorization).
34
+ * Any value > 0 forces the R$ 0,01 capture workaround — see G123-G127.
35
+ */
36
+ trialDaysCard?: number;
37
+ trialDaysPix?: number;
38
+ /**
39
+ * Which method the paywall preselects. Reflects creator audience,
40
+ * not Hook bias. `null`/`undefined` = no preselection — user picks.
41
+ */
42
+ defaultMethod?: CheckoutMethod | null;
23
43
  cycles: Cycle[];
24
44
  prices: {
25
45
  monthlyCents: number;
@@ -120,6 +140,33 @@ interface AuthScreenProps {
120
140
  onNavigate?: (target: 'login' | 'signup' | 'forgot' | 'reset') => void;
121
141
  }
122
142
 
143
+ interface SkipDefaults {
144
+ /**
145
+ * Final flag the host app's ProtectedRoute reads. If unset here, the helper
146
+ * forces it to `true` after merging defaults.
147
+ */
148
+ onboarding_completed?: boolean;
149
+ /**
150
+ * Free-form per-app fields (userName, mainGoal, faixa, kids[], etc.). The
151
+ * helper merges this object verbatim into `appData.set('onboarding_data', …)`.
152
+ */
153
+ [field: string]: unknown;
154
+ /**
155
+ * Optional per-app seed callback. Use to insert anything that lives outside
156
+ * `onboarding_data` (e.g. seed first workout in `hook.db.collection('workouts')`).
157
+ * Awaited after `appData.set` and before the hard reload.
158
+ */
159
+ __seed?: (hook: HookContextValue) => Promise<void>;
160
+ }
161
+ /**
162
+ * Programmatic skip helper. Exposed for advanced consumers / tests; the FAB
163
+ * just calls this on confirm.
164
+ */
165
+ declare function skipOnboarding(hook: HookContextValue, defaults: SkipDefaults, appSlug: string): Promise<void>;
166
+ declare function DevSkipOnboardingFab({ defaults }: {
167
+ defaults: SkipDefaults;
168
+ }): react_jsx_runtime.JSX.Element;
169
+
123
170
  declare function PaymentReturnHandler({ children }: {
124
171
  children: ReactNode;
125
172
  }): react_jsx_runtime.JSX.Element;
@@ -145,27 +192,54 @@ type AppRootProps = AppRootSlots & {
145
192
  testRouter?: 'memory';
146
193
  /** Test-only: initial entries for MemoryRouter. */
147
194
  testInitialEntries?: string[];
195
+ /**
196
+ * Staging-only dev tools. When this prop is set AND
197
+ * `VITE_HOOK_DEV_TOOLS=1` AND the hostname is staging/localhost, AppRoot
198
+ * mounts a floating "skip onboarding" button that pre-fills
199
+ * `appData.onboarding_data` with the supplied defaults and lands the user
200
+ * on `/app/<slug>/`. Tree-shaken from prod builds via the build-time env
201
+ * replacement (see `dev/env.ts`).
202
+ */
203
+ devSkipOnboarding?: {
204
+ defaults: SkipDefaults;
205
+ };
148
206
  };
149
207
 
150
208
  declare function AppRoot(props: AppRootProps): react_jsx_runtime.JSX.Element;
151
209
 
210
+ /**
211
+ * Build-time + runtime gate for dev-only tools (e.g. <DevSkipOnboardingFab>).
212
+ *
213
+ * Two independent signals must agree:
214
+ *
215
+ * 1. Build-time: `import.meta.env.VITE_HOOK_DEV_TOOLS === '1'`. Vite folds
216
+ * this constant at build time — when unset, the entire dev tree is
217
+ * tree-shaken from the prod bundle (sideEffects:false in package.json
218
+ * makes that effective). Set `VITE_HOOK_DEV_TOOLS=1` only in
219
+ * `.env.staging` builds.
220
+ *
221
+ * 2. Runtime: hostname must be staging-ish. Belt-and-suspenders against
222
+ * a misconfigured build that somehow ships the FAB to prod.
223
+ */
224
+ declare function isDevToolsEnabled(): boolean;
225
+
152
226
  interface PushPromptTexts {
153
227
  cta: string;
154
228
  declineCta: string;
155
229
  iosInstallTitle: string;
156
230
  iosInstallBody: string;
157
231
  iosInstallCta?: string;
158
- deniedTitle: string;
159
- deniedBody: string;
160
- /**
161
- * Audit Wave 3 — Fix #33: per-platform recovery copy shown when permission
162
- * is denied. All four are optional; if the matching platform's copy is
163
- * missing the recovery paragraph is omitted (back-compat for callers that
164
- * haven't supplied them yet).
165
- */
232
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
233
+ deniedTitle?: string;
234
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
235
+ deniedBody?: string;
236
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
166
237
  deniedRecoveryIos?: string;
238
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
167
239
  deniedRecoveryAndroid?: string;
240
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
168
241
  deniedRecoveryDesktop?: string;
242
+ /** @deprecated denied state no longer renders UI; field retained for back-compat. */
169
243
  deniedRecoveryInApp?: string;
170
244
  unsupportedBody: string;
171
245
  }
@@ -464,6 +538,16 @@ declare function usePaywallState(): {
464
538
  methods: readonly CheckoutMethod$1[];
465
539
  selectedMethod: CheckoutMethod$1;
466
540
  setSelectedMethod: react.Dispatch<react.SetStateAction<CheckoutMethod$1>>;
541
+ hasConsumedTrial: boolean;
542
+ currentPriceCents: number;
543
+ currentMonthlyEquivCents: number;
544
+ anchorPriceCents: number | null;
545
+ selectMethod: (next: CheckoutMethod$1) => void;
546
+ selectCycle: (next: CheckoutCycle) => void;
547
+ isFree: boolean;
548
+ trialDaysForMethod: (method: CheckoutMethod$1) => number;
549
+ trialDaysCard: number;
550
+ trialDaysPix: number;
467
551
  cpfState: CpfState;
468
552
  cardState: CardFormStateWithSetter;
469
553
  submit: () => Promise<CheckoutResult | undefined>;
@@ -882,6 +966,13 @@ declare const AppConfigSchema: z.ZodObject<{
882
966
  pay_first: "pay_first";
883
967
  }>;
884
968
  trialDays: z.ZodOptional<z.ZodNumber>;
969
+ trialDaysCard: z.ZodOptional<z.ZodNumber>;
970
+ trialDaysPix: z.ZodOptional<z.ZodNumber>;
971
+ defaultMethod: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
972
+ card: "card";
973
+ "pix-auto": "pix-auto";
974
+ "pix-once": "pix-once";
975
+ }>>>;
885
976
  cycles: z.ZodArray<z.ZodEnum<{
886
977
  MONTHLY: "MONTHLY";
887
978
  YEARLY: "YEARLY";
@@ -950,4 +1041,153 @@ declare const AppConfigSchema: z.ZodObject<{
950
1041
  }, z.core.$strict>;
951
1042
  declare function parseAppConfig(input: unknown): AppConfig;
952
1043
 
953
- export { type AndroidBrowser, type AppConfig, AppConfigProvider, AppConfigSchema, AppRoot, type AppRootProps, type AppRootSlots, type AuthFlowConfig, type AuthFormError, type AuthFormErrorCode, type AuthScreenProps, type CheckoutMethod, type Cycle, DeepLinkHandler, type DeepLinks, EmptyState, ErrorBoundary, type I18nConfig, I18nProvider, type I18nProviderProps, type IOSBrowser, type InAppApp, type InstallActions, InstallGate, InstallSplash, type InstallState, type InstallVariant, LanguageSwitcher, type LanguageSwitcherProps, LoadingState, type OnboardingConfig, OnboardingFlow, type OnboardingFlowProps, type OnboardingStep, type OnboardingStepCtx, type OnboardingStepDef, type PaymentMethod, PaymentReturnHandler, type PaywallConfig, type PersistedKey, PersistenceRegistry, type PersistenceRegistryProps, type PixPending, type Platform, PreAuthShell, type PreAuthShellProps, PushPrompt, type PushPromptProps, type PushPromptTexts, type PushUiState, RouteBoundary, type RouteBoundaryProps, type SubscriptionStatus, type ToastItem, type UseLoginFormResult, type UseResetFormResult, asaasErrorMessage, computeAnchorCents, dailyFromYearly, detectAndroidBrowser, detectIOSBrowser, detectInAppApp, detectPlatform, detectStandalone, discountPercent, formatBRL, monthlyFromYearly, parseAppConfig, shouldBlockInstall, shouldShowPermanentOption, useAppConfig, useAuth, useAuthPrimitives, useFeature, useForgotForm, useInstallPrompt, useLoginForm, useOnboardingStep, usePaywallState, usePlan, usePush, useReminders, useResetForm, useSignupForm, useSubscription, useToast };
1044
+ type PaywallMethodCopy = {
1045
+ /** Tab label, e.g. "⚡ PIX" or "💳 Cartão" */
1046
+ tabLabel: string;
1047
+ /** 3 body rows under the active tab. Use literal strings; price/days come from the hook. */
1048
+ bodyRows: [string, string, string];
1049
+ /** CTA label template. `{price}` and `{days}` placeholders are interpolated. */
1050
+ ctaTemplate: string;
1051
+ /** Switch-hint copy shown under the CTA when the OTHER tab is available. */
1052
+ switchHint: string;
1053
+ };
1054
+ type PaywallCopy = {
1055
+ headline: string;
1056
+ features: readonly string[];
1057
+ socialProof?: string;
1058
+ /** Trust line above sticky CTA. Shared across methods. */
1059
+ trustLine: string;
1060
+ pix: PaywallMethodCopy;
1061
+ card: PaywallMethodCopy;
1062
+ /** Used when `usePaywallState().hasConsumedTrial === true`. Card tab body + CTA shift. */
1063
+ cardConsumedTrial: Omit<PaywallMethodCopy, 'tabLabel' | 'switchHint'>;
1064
+ cycle: {
1065
+ annualLabel: string;
1066
+ monthlyLabel: string;
1067
+ /** Append after price on annual card, e.g. "/mês · anual" */
1068
+ annualSuffix: string;
1069
+ /** Append after price on monthly card, e.g. "/mês" */
1070
+ monthlySuffix: string;
1071
+ };
1072
+ /** Optional override for the "free" CTA when `paywall.mode === 'free'`. */
1073
+ freeCta?: string;
1074
+ };
1075
+ type PaywallThemeClasses = {
1076
+ /** Container wrapper. Default: empty. */
1077
+ container?: string;
1078
+ /** Headline `<h1>`. */
1079
+ headline?: string;
1080
+ /** Feature row `<li>`. */
1081
+ feature?: string;
1082
+ /** Cycle picker card. */
1083
+ cycleCard?: string;
1084
+ /** Cycle picker card when selected. */
1085
+ cycleCardSelected?: string;
1086
+ /** Method tabs wrapper (pill background). */
1087
+ tabs?: string;
1088
+ /** Individual tab. */
1089
+ tab?: string;
1090
+ /** Individual tab when active. */
1091
+ tabActive?: string;
1092
+ /** Tab body card. */
1093
+ tabContent?: string;
1094
+ /** Tab body row (one row per icon+text). */
1095
+ tabContentRow?: string;
1096
+ /** CTA button — applied when method=pix-auto. */
1097
+ ctaPix?: string;
1098
+ /** CTA button — applied when method=card. */
1099
+ ctaCard?: string;
1100
+ /** Switch-hint line under CTA. */
1101
+ switchHint?: string;
1102
+ /** Trust line under switch hint. */
1103
+ trustLine?: string;
1104
+ /** Social proof badge. */
1105
+ socialProof?: string;
1106
+ /** Anchor strikethrough price. */
1107
+ anchorPrice?: string;
1108
+ };
1109
+ type PaywallSlots = {
1110
+ /** Above headline (hero image, brand visual). */
1111
+ heroSlot?: ReactNode;
1112
+ /** Below tab content, above CTA (e.g. testimonials). */
1113
+ beforeCtaSlot?: ReactNode;
1114
+ /** Replace the cycle picker entirely. */
1115
+ cyclePickerSlot?: ReactNode;
1116
+ };
1117
+ type PaywallProps = {
1118
+ copy: PaywallCopy;
1119
+ themeClasses?: PaywallThemeClasses;
1120
+ slots?: PaywallSlots;
1121
+ /** Called immediately before checkout dispatches. Use for opening CPF modal etc. */
1122
+ onBeforeCheckout?: (method: CheckoutMethod, cycle: Cycle) => void | Promise<void>;
1123
+ };
1124
+
1125
+ /**
1126
+ * Composed top-level paywall component. Apps wrap it in their `PaywallOffer.tsx`
1127
+ * (or `Offer.tsx`) and pass copy + themeClasses + slots. Logic + telemetry live
1128
+ * here. To customize layout entirely, drop down to the primitives.
1129
+ */
1130
+ declare function Paywall({ copy, themeClasses, slots, onBeforeCheckout, }: PaywallProps): react_jsx_runtime.JSX.Element;
1131
+
1132
+ type PaywallMethodTabsProps = {
1133
+ methods: readonly CheckoutMethod[];
1134
+ selected: CheckoutMethod;
1135
+ onSelect: (m: CheckoutMethod) => void;
1136
+ labels: Partial<Record<CheckoutMethod, string>>;
1137
+ className?: string;
1138
+ tabClassName?: string;
1139
+ tabActiveClassName?: string;
1140
+ };
1141
+ declare function PaywallMethodTabs({ methods, selected, onSelect, labels, className, tabClassName, tabActiveClassName, }: PaywallMethodTabsProps): react_jsx_runtime.JSX.Element | null;
1142
+
1143
+ type PaywallMethodContentProps = {
1144
+ method: CheckoutMethod;
1145
+ copy: Pick<PaywallCopy, 'pix' | 'card'> & {
1146
+ cardConsumedTrial?: PaywallCopy['cardConsumedTrial'];
1147
+ };
1148
+ hasConsumedTrial?: boolean;
1149
+ className?: string;
1150
+ rowClassName?: string;
1151
+ };
1152
+ declare function PaywallMethodContent({ method, copy, hasConsumedTrial, className, rowClassName, }: PaywallMethodContentProps): react_jsx_runtime.JSX.Element;
1153
+
1154
+ type CycleLabels = {
1155
+ annualLabel: string;
1156
+ monthlyLabel: string;
1157
+ annualSuffix: string;
1158
+ monthlySuffix: string;
1159
+ };
1160
+ type PaywallCyclePickerProps = {
1161
+ cycles: readonly Cycle[];
1162
+ selected: Cycle;
1163
+ onSelect: (c: Cycle) => void;
1164
+ /** Raw price for the cycle (used to show full annual/monthly). */
1165
+ priceCentsByCycle: Record<Cycle, number>;
1166
+ /** Anchor strikethrough price, null when not set. */
1167
+ anchorCentsByCycle: Record<Cycle, number | null>;
1168
+ /** Monthly-equiv for YEARLY (priceCents / 12). Same as priceCentsByCycle for MONTHLY. */
1169
+ monthlyEquivByCycle: Record<Cycle, number>;
1170
+ labels: CycleLabels;
1171
+ className?: string;
1172
+ cardClassName?: string;
1173
+ cardSelectedClassName?: string;
1174
+ anchorClassName?: string;
1175
+ };
1176
+ declare function PaywallCyclePicker({ cycles, selected, onSelect, priceCentsByCycle, anchorCentsByCycle, monthlyEquivByCycle, labels, className, cardClassName, cardSelectedClassName, anchorClassName, }: PaywallCyclePickerProps): react_jsx_runtime.JSX.Element | null;
1177
+
1178
+ type PaywallCtaProps = {
1179
+ ctaLabel: string;
1180
+ loadingLabel?: string;
1181
+ switchHint?: string;
1182
+ trustLine: string;
1183
+ onClick: () => void;
1184
+ disabled?: boolean;
1185
+ loading?: boolean;
1186
+ className?: string;
1187
+ buttonClassName?: string;
1188
+ switchHintClassName?: string;
1189
+ trustClassName?: string;
1190
+ };
1191
+ declare function PaywallCta({ ctaLabel, loadingLabel, switchHint, trustLine, onClick, disabled, loading, className, buttonClassName, switchHintClassName, trustClassName, }: PaywallCtaProps): react_jsx_runtime.JSX.Element;
1192
+
1193
+ export { type AndroidBrowser, type AppConfig, AppConfigProvider, AppConfigSchema, AppRoot, type AppRootProps, type AppRootSlots, type AuthFlowConfig, type AuthFormError, type AuthFormErrorCode, type AuthScreenProps, type CheckoutMethod, type Cycle, type CycleLabels, DeepLinkHandler, type DeepLinks, DevSkipOnboardingFab, EmptyState, ErrorBoundary, type I18nConfig, I18nProvider, type I18nProviderProps, type IOSBrowser, type InAppApp, type InstallActions, InstallGate, InstallSplash, type InstallState, type InstallVariant, LanguageSwitcher, type LanguageSwitcherProps, LoadingState, type OnboardingConfig, OnboardingFlow, type OnboardingFlowProps, type OnboardingStep, type OnboardingStepCtx, type OnboardingStepDef, type PaymentMethod, PaymentReturnHandler, Paywall, type PaywallConfig, type PaywallCopy, PaywallCta, type PaywallCtaProps, PaywallCyclePicker, type PaywallCyclePickerProps, PaywallMethodContent, type PaywallMethodContentProps, type PaywallMethodCopy, PaywallMethodTabs, type PaywallMethodTabsProps, type PaywallProps, type PaywallSlots, type PaywallThemeClasses, type PersistedKey, PersistenceRegistry, type PersistenceRegistryProps, type PixPending, type Platform, PreAuthShell, type PreAuthShellProps, PushPrompt, type PushPromptProps, type PushPromptTexts, type PushUiState, RouteBoundary, type RouteBoundaryProps, type SkipDefaults, type SubscriptionStatus, type ToastItem, type UseLoginFormResult, type UseResetFormResult, asaasErrorMessage, computeAnchorCents, dailyFromYearly, detectAndroidBrowser, detectIOSBrowser, detectInAppApp, detectPlatform, detectStandalone, discountPercent, formatBRL, isDevToolsEnabled, monthlyFromYearly, parseAppConfig, shouldBlockInstall, shouldShowPermanentOption, skipOnboarding, useAppConfig, useAuth, useAuthPrimitives, useFeature, useForgotForm, useInstallPrompt, useLoginForm, useOnboardingStep, usePaywallState, usePlan, usePush, useReminders, useResetForm, useSignupForm, useSubscription, useToast };