@hook-sdk/template 0.2.0 → 0.4.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 +1600 -184
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +114 -1
- package/dist/index.d.ts +114 -1
- package/dist/index.js +1581 -175
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -23,6 +23,7 @@ declare const AppConfigSchema: z.ZodObject<{
|
|
|
23
23
|
leaderboard: "leaderboard";
|
|
24
24
|
push: "push";
|
|
25
25
|
subscription: "subscription";
|
|
26
|
+
install_prompt: "install_prompt";
|
|
26
27
|
}>>;
|
|
27
28
|
persistedKeys: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
28
29
|
dependencies_allowlist: z.ZodArray<z.ZodString>;
|
|
@@ -105,6 +106,18 @@ interface PushPromptProps {
|
|
|
105
106
|
}
|
|
106
107
|
declare function PushPrompt({ texts, onSubscribed, onDeclined, onInstallRequested, className }: PushPromptProps): react_jsx_runtime.JSX.Element | null;
|
|
107
108
|
|
|
109
|
+
interface InstallGateProps {
|
|
110
|
+
children: ReactNode;
|
|
111
|
+
}
|
|
112
|
+
declare function InstallGate({ children }: InstallGateProps): react_jsx_runtime.JSX.Element;
|
|
113
|
+
|
|
114
|
+
interface InstallSplashProps {
|
|
115
|
+
children: ReactNode;
|
|
116
|
+
title: string;
|
|
117
|
+
subtitle?: string;
|
|
118
|
+
}
|
|
119
|
+
declare function InstallSplash({ children, title, subtitle }: InstallSplashProps): react_jsx_runtime.JSX.Element;
|
|
120
|
+
|
|
108
121
|
declare function DefaultSignupScreen({ onNavigate }: AuthScreenProps): react_jsx_runtime.JSX.Element;
|
|
109
122
|
|
|
110
123
|
declare function DefaultForgotScreen({ onNavigate }: AuthScreenProps): react_jsx_runtime.JSX.Element;
|
|
@@ -168,6 +181,12 @@ interface UseLoginFormResult {
|
|
|
168
181
|
submitting: boolean;
|
|
169
182
|
canSubmit: boolean;
|
|
170
183
|
error: AuthFormError | null;
|
|
184
|
+
/**
|
|
185
|
+
* Dispara OAuth Google: redireciona pro backend `/api/auth/oauth/google/start`.
|
|
186
|
+
* Fire-and-forget — a página é descarregada antes de qualquer retorno.
|
|
187
|
+
* Volta pro app logado (ou com `?oauth_error=...` em falha).
|
|
188
|
+
*/
|
|
189
|
+
loginWithGoogle: () => void;
|
|
171
190
|
}
|
|
172
191
|
declare function useLoginForm(): UseLoginFormResult;
|
|
173
192
|
|
|
@@ -190,6 +209,13 @@ interface UseSignupFormResult {
|
|
|
190
209
|
submitting: boolean;
|
|
191
210
|
canSubmit: boolean;
|
|
192
211
|
error: AuthFormError | null;
|
|
212
|
+
/**
|
|
213
|
+
* Dispara OAuth Google: mesmo endpoint que `useLoginForm.loginWithGoogle`.
|
|
214
|
+
* Backend decide entre `signup_new`, `auto_linked`, ou `login_existing`
|
|
215
|
+
* via `linkPolicy` — do ponto de vista do usuário "criar conta com Google"
|
|
216
|
+
* e "entrar com Google" são o mesmo botão.
|
|
217
|
+
*/
|
|
218
|
+
loginWithGoogle: () => void;
|
|
193
219
|
}
|
|
194
220
|
declare function useSignupForm(): UseSignupFormResult;
|
|
195
221
|
|
|
@@ -380,4 +406,91 @@ declare function useToast(): {
|
|
|
380
406
|
dismiss: (id: string) => void;
|
|
381
407
|
};
|
|
382
408
|
|
|
383
|
-
|
|
409
|
+
/**
|
|
410
|
+
* useInstallPrompt — headless hook pra PWA install prompt.
|
|
411
|
+
*
|
|
412
|
+
* Responsabilidades:
|
|
413
|
+
* - Detectar plataforma (Android / iOS Safari / iOS outros / in-app / desktop)
|
|
414
|
+
* - Detectar browser específico (Chrome, Firefox, Samsung, Instagram, ...)
|
|
415
|
+
* - Detectar standalone mode (PWA já instalado)
|
|
416
|
+
* - Gerenciar dismissal graduada (session → permanente 14d)
|
|
417
|
+
* - Expor `promptInstall()` que dispara `window.__pwaInstallPrompt.prompt()`
|
|
418
|
+
*
|
|
419
|
+
* Não renderiza UI. Componente `<InstallGate>` consome o hook e renderiza.
|
|
420
|
+
*
|
|
421
|
+
* Porta regexes + lógica de `hook-old/src/hooks/usePWAInstall.ts` com
|
|
422
|
+
* divergências deliberadas (ver docs/adr/017 + P20 plan):
|
|
423
|
+
* - enum InAppApp granular pra copy por rede social (G60 amendment)
|
|
424
|
+
* - dismissal graduada em vez de permanente direto
|
|
425
|
+
* - TTL de 14d no permanent dismiss
|
|
426
|
+
* - tracking `skipCount` separado
|
|
427
|
+
*
|
|
428
|
+
* Gotchas de referência:
|
|
429
|
+
* - G61: beforeinstallprompt capturado pré-React (shell main.tsx faz)
|
|
430
|
+
* - G62: distinção ios-safari vs ios-other (Chrome iOS não instala)
|
|
431
|
+
* - G63: in-app browsers checados ANTES de Android/iOS
|
|
432
|
+
*/
|
|
433
|
+
type Platform = 'android' | 'ios-safari' | 'ios-other' | 'in-app' | 'desktop' | 'unknown';
|
|
434
|
+
type IOSBrowser = 'safari' | 'chrome' | 'firefox' | 'edge' | 'other';
|
|
435
|
+
type AndroidBrowser = 'chrome' | 'firefox' | 'opera' | 'samsung' | 'edge' | 'other';
|
|
436
|
+
type InAppApp = 'instagram' | 'facebook' | 'tiktok' | 'whatsapp' | 'twitter' | 'linkedin' | 'telegram' | 'line' | 'snapchat' | 'pinterest' | 'wechat' | 'other';
|
|
437
|
+
type InstallVariant = 'android-native' | 'android-manual' | 'ios-safari' | 'ios-other' | 'in-app' | 'desktop' | 'none';
|
|
438
|
+
interface BeforeInstallPromptEvent extends Event {
|
|
439
|
+
prompt: () => Promise<void>;
|
|
440
|
+
userChoice: Promise<{
|
|
441
|
+
outcome: 'accepted' | 'dismissed';
|
|
442
|
+
platform: string;
|
|
443
|
+
}>;
|
|
444
|
+
}
|
|
445
|
+
declare global {
|
|
446
|
+
interface Window {
|
|
447
|
+
__pwaInstallPrompt?: BeforeInstallPromptEvent | null;
|
|
448
|
+
posthog?: {
|
|
449
|
+
capture?: (event: string, props?: Record<string, unknown>) => void;
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
interface InstallState {
|
|
454
|
+
platform: Platform;
|
|
455
|
+
iosBrowser: IOSBrowser | null;
|
|
456
|
+
androidBrowser: AndroidBrowser | null;
|
|
457
|
+
inAppApp: InAppApp | null;
|
|
458
|
+
isInstallable: boolean;
|
|
459
|
+
isInstalled: boolean;
|
|
460
|
+
isDismissedSession: boolean;
|
|
461
|
+
isDismissedPermanent: boolean;
|
|
462
|
+
skipCount: number;
|
|
463
|
+
variant: InstallVariant;
|
|
464
|
+
}
|
|
465
|
+
interface InstallActions {
|
|
466
|
+
promptInstall: () => Promise<boolean>;
|
|
467
|
+
dismissSession: () => void;
|
|
468
|
+
dismissPermanent: () => void;
|
|
469
|
+
redirectToSafari: () => void;
|
|
470
|
+
copyLink: () => Promise<void>;
|
|
471
|
+
reset: () => void;
|
|
472
|
+
}
|
|
473
|
+
declare function detectPlatform(ua: string): Platform;
|
|
474
|
+
declare function detectIOSBrowser(ua: string): IOSBrowser | null;
|
|
475
|
+
declare function detectAndroidBrowser(ua: string): AndroidBrowser | null;
|
|
476
|
+
declare function detectInAppApp(ua: string): InAppApp | null;
|
|
477
|
+
declare function detectStandalone(): {
|
|
478
|
+
installed: boolean;
|
|
479
|
+
source: 'match_media' | 'navigator_standalone' | 'storage_marker' | null;
|
|
480
|
+
};
|
|
481
|
+
/**
|
|
482
|
+
* Hook principal. Passar o slug do app (usado pra namespacing de storage +
|
|
483
|
+
* analytics). Componentes do template pegam via useTemplateConfig().slug.
|
|
484
|
+
*/
|
|
485
|
+
declare function useInstallPrompt(slug: string): InstallState & InstallActions;
|
|
486
|
+
/**
|
|
487
|
+
* Exposto pra InstallGate decidir se renderiza splash (não faz parte do hook
|
|
488
|
+
* retornado pra manter surface pequena — componente usa).
|
|
489
|
+
*/
|
|
490
|
+
declare function shouldBlockInstall(state: InstallState, now?: number): boolean;
|
|
491
|
+
/**
|
|
492
|
+
* Exposto pra decidir se mostra "Não me pergunte mais".
|
|
493
|
+
*/
|
|
494
|
+
declare function shouldShowPermanentOption(state: InstallState): boolean;
|
|
495
|
+
|
|
496
|
+
export { type AndroidBrowser, AppRoot, type AppRootProps, type AuthFormError, type AuthFormErrorCode, type AuthScreen, type AuthScreenProps, DefaultForgotScreen, DefaultLoginScreen, DefaultPaywall, DefaultResetScreen, DefaultSignupScreen, EmptyState, ErrorBoundary, type IOSBrowser, type InAppApp, type InstallActions, InstallGate, InstallSplash, type InstallState, type InstallVariant, LoadingState, type Platform, PushPrompt, type PushPromptProps, type PushPromptTexts, type PushUiState, type SubscriptionStatus, type ToastItem, type UseLoginFormResult, type UseResetFormResult, detectAndroidBrowser, detectIOSBrowser, detectInAppApp, detectPlatform, detectStandalone, shouldBlockInstall, shouldShowPermanentOption, useAuth, useAuthPrimitives, useForgotForm, useInstallPrompt, useLoginForm, usePaywallState, usePush, useReminders, useResetForm, useSignupForm, useSubscription, useToast };
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ declare const AppConfigSchema: z.ZodObject<{
|
|
|
23
23
|
leaderboard: "leaderboard";
|
|
24
24
|
push: "push";
|
|
25
25
|
subscription: "subscription";
|
|
26
|
+
install_prompt: "install_prompt";
|
|
26
27
|
}>>;
|
|
27
28
|
persistedKeys: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
28
29
|
dependencies_allowlist: z.ZodArray<z.ZodString>;
|
|
@@ -105,6 +106,18 @@ interface PushPromptProps {
|
|
|
105
106
|
}
|
|
106
107
|
declare function PushPrompt({ texts, onSubscribed, onDeclined, onInstallRequested, className }: PushPromptProps): react_jsx_runtime.JSX.Element | null;
|
|
107
108
|
|
|
109
|
+
interface InstallGateProps {
|
|
110
|
+
children: ReactNode;
|
|
111
|
+
}
|
|
112
|
+
declare function InstallGate({ children }: InstallGateProps): react_jsx_runtime.JSX.Element;
|
|
113
|
+
|
|
114
|
+
interface InstallSplashProps {
|
|
115
|
+
children: ReactNode;
|
|
116
|
+
title: string;
|
|
117
|
+
subtitle?: string;
|
|
118
|
+
}
|
|
119
|
+
declare function InstallSplash({ children, title, subtitle }: InstallSplashProps): react_jsx_runtime.JSX.Element;
|
|
120
|
+
|
|
108
121
|
declare function DefaultSignupScreen({ onNavigate }: AuthScreenProps): react_jsx_runtime.JSX.Element;
|
|
109
122
|
|
|
110
123
|
declare function DefaultForgotScreen({ onNavigate }: AuthScreenProps): react_jsx_runtime.JSX.Element;
|
|
@@ -168,6 +181,12 @@ interface UseLoginFormResult {
|
|
|
168
181
|
submitting: boolean;
|
|
169
182
|
canSubmit: boolean;
|
|
170
183
|
error: AuthFormError | null;
|
|
184
|
+
/**
|
|
185
|
+
* Dispara OAuth Google: redireciona pro backend `/api/auth/oauth/google/start`.
|
|
186
|
+
* Fire-and-forget — a página é descarregada antes de qualquer retorno.
|
|
187
|
+
* Volta pro app logado (ou com `?oauth_error=...` em falha).
|
|
188
|
+
*/
|
|
189
|
+
loginWithGoogle: () => void;
|
|
171
190
|
}
|
|
172
191
|
declare function useLoginForm(): UseLoginFormResult;
|
|
173
192
|
|
|
@@ -190,6 +209,13 @@ interface UseSignupFormResult {
|
|
|
190
209
|
submitting: boolean;
|
|
191
210
|
canSubmit: boolean;
|
|
192
211
|
error: AuthFormError | null;
|
|
212
|
+
/**
|
|
213
|
+
* Dispara OAuth Google: mesmo endpoint que `useLoginForm.loginWithGoogle`.
|
|
214
|
+
* Backend decide entre `signup_new`, `auto_linked`, ou `login_existing`
|
|
215
|
+
* via `linkPolicy` — do ponto de vista do usuário "criar conta com Google"
|
|
216
|
+
* e "entrar com Google" são o mesmo botão.
|
|
217
|
+
*/
|
|
218
|
+
loginWithGoogle: () => void;
|
|
193
219
|
}
|
|
194
220
|
declare function useSignupForm(): UseSignupFormResult;
|
|
195
221
|
|
|
@@ -380,4 +406,91 @@ declare function useToast(): {
|
|
|
380
406
|
dismiss: (id: string) => void;
|
|
381
407
|
};
|
|
382
408
|
|
|
383
|
-
|
|
409
|
+
/**
|
|
410
|
+
* useInstallPrompt — headless hook pra PWA install prompt.
|
|
411
|
+
*
|
|
412
|
+
* Responsabilidades:
|
|
413
|
+
* - Detectar plataforma (Android / iOS Safari / iOS outros / in-app / desktop)
|
|
414
|
+
* - Detectar browser específico (Chrome, Firefox, Samsung, Instagram, ...)
|
|
415
|
+
* - Detectar standalone mode (PWA já instalado)
|
|
416
|
+
* - Gerenciar dismissal graduada (session → permanente 14d)
|
|
417
|
+
* - Expor `promptInstall()` que dispara `window.__pwaInstallPrompt.prompt()`
|
|
418
|
+
*
|
|
419
|
+
* Não renderiza UI. Componente `<InstallGate>` consome o hook e renderiza.
|
|
420
|
+
*
|
|
421
|
+
* Porta regexes + lógica de `hook-old/src/hooks/usePWAInstall.ts` com
|
|
422
|
+
* divergências deliberadas (ver docs/adr/017 + P20 plan):
|
|
423
|
+
* - enum InAppApp granular pra copy por rede social (G60 amendment)
|
|
424
|
+
* - dismissal graduada em vez de permanente direto
|
|
425
|
+
* - TTL de 14d no permanent dismiss
|
|
426
|
+
* - tracking `skipCount` separado
|
|
427
|
+
*
|
|
428
|
+
* Gotchas de referência:
|
|
429
|
+
* - G61: beforeinstallprompt capturado pré-React (shell main.tsx faz)
|
|
430
|
+
* - G62: distinção ios-safari vs ios-other (Chrome iOS não instala)
|
|
431
|
+
* - G63: in-app browsers checados ANTES de Android/iOS
|
|
432
|
+
*/
|
|
433
|
+
type Platform = 'android' | 'ios-safari' | 'ios-other' | 'in-app' | 'desktop' | 'unknown';
|
|
434
|
+
type IOSBrowser = 'safari' | 'chrome' | 'firefox' | 'edge' | 'other';
|
|
435
|
+
type AndroidBrowser = 'chrome' | 'firefox' | 'opera' | 'samsung' | 'edge' | 'other';
|
|
436
|
+
type InAppApp = 'instagram' | 'facebook' | 'tiktok' | 'whatsapp' | 'twitter' | 'linkedin' | 'telegram' | 'line' | 'snapchat' | 'pinterest' | 'wechat' | 'other';
|
|
437
|
+
type InstallVariant = 'android-native' | 'android-manual' | 'ios-safari' | 'ios-other' | 'in-app' | 'desktop' | 'none';
|
|
438
|
+
interface BeforeInstallPromptEvent extends Event {
|
|
439
|
+
prompt: () => Promise<void>;
|
|
440
|
+
userChoice: Promise<{
|
|
441
|
+
outcome: 'accepted' | 'dismissed';
|
|
442
|
+
platform: string;
|
|
443
|
+
}>;
|
|
444
|
+
}
|
|
445
|
+
declare global {
|
|
446
|
+
interface Window {
|
|
447
|
+
__pwaInstallPrompt?: BeforeInstallPromptEvent | null;
|
|
448
|
+
posthog?: {
|
|
449
|
+
capture?: (event: string, props?: Record<string, unknown>) => void;
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
interface InstallState {
|
|
454
|
+
platform: Platform;
|
|
455
|
+
iosBrowser: IOSBrowser | null;
|
|
456
|
+
androidBrowser: AndroidBrowser | null;
|
|
457
|
+
inAppApp: InAppApp | null;
|
|
458
|
+
isInstallable: boolean;
|
|
459
|
+
isInstalled: boolean;
|
|
460
|
+
isDismissedSession: boolean;
|
|
461
|
+
isDismissedPermanent: boolean;
|
|
462
|
+
skipCount: number;
|
|
463
|
+
variant: InstallVariant;
|
|
464
|
+
}
|
|
465
|
+
interface InstallActions {
|
|
466
|
+
promptInstall: () => Promise<boolean>;
|
|
467
|
+
dismissSession: () => void;
|
|
468
|
+
dismissPermanent: () => void;
|
|
469
|
+
redirectToSafari: () => void;
|
|
470
|
+
copyLink: () => Promise<void>;
|
|
471
|
+
reset: () => void;
|
|
472
|
+
}
|
|
473
|
+
declare function detectPlatform(ua: string): Platform;
|
|
474
|
+
declare function detectIOSBrowser(ua: string): IOSBrowser | null;
|
|
475
|
+
declare function detectAndroidBrowser(ua: string): AndroidBrowser | null;
|
|
476
|
+
declare function detectInAppApp(ua: string): InAppApp | null;
|
|
477
|
+
declare function detectStandalone(): {
|
|
478
|
+
installed: boolean;
|
|
479
|
+
source: 'match_media' | 'navigator_standalone' | 'storage_marker' | null;
|
|
480
|
+
};
|
|
481
|
+
/**
|
|
482
|
+
* Hook principal. Passar o slug do app (usado pra namespacing de storage +
|
|
483
|
+
* analytics). Componentes do template pegam via useTemplateConfig().slug.
|
|
484
|
+
*/
|
|
485
|
+
declare function useInstallPrompt(slug: string): InstallState & InstallActions;
|
|
486
|
+
/**
|
|
487
|
+
* Exposto pra InstallGate decidir se renderiza splash (não faz parte do hook
|
|
488
|
+
* retornado pra manter surface pequena — componente usa).
|
|
489
|
+
*/
|
|
490
|
+
declare function shouldBlockInstall(state: InstallState, now?: number): boolean;
|
|
491
|
+
/**
|
|
492
|
+
* Exposto pra decidir se mostra "Não me pergunte mais".
|
|
493
|
+
*/
|
|
494
|
+
declare function shouldShowPermanentOption(state: InstallState): boolean;
|
|
495
|
+
|
|
496
|
+
export { type AndroidBrowser, AppRoot, type AppRootProps, type AuthFormError, type AuthFormErrorCode, type AuthScreen, type AuthScreenProps, DefaultForgotScreen, DefaultLoginScreen, DefaultPaywall, DefaultResetScreen, DefaultSignupScreen, EmptyState, ErrorBoundary, type IOSBrowser, type InAppApp, type InstallActions, InstallGate, InstallSplash, type InstallState, type InstallVariant, LoadingState, type Platform, PushPrompt, type PushPromptProps, type PushPromptTexts, type PushUiState, type SubscriptionStatus, type ToastItem, type UseLoginFormResult, type UseResetFormResult, detectAndroidBrowser, detectIOSBrowser, detectInAppApp, detectPlatform, detectStandalone, shouldBlockInstall, shouldShowPermanentOption, useAuth, useAuthPrimitives, useForgotForm, useInstallPrompt, useLoginForm, usePaywallState, usePush, useReminders, useResetForm, useSignupForm, useSubscription, useToast };
|