@hook-sdk/template 0.7.2 → 0.8.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 +27 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +72 -50
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -273,6 +273,13 @@ interface PixPending {
|
|
|
273
273
|
qrCodePayload: string | null;
|
|
274
274
|
qrCodeBase64: string | null;
|
|
275
275
|
expiresAt: string | null;
|
|
276
|
+
/**
|
|
277
|
+
* Flipa `true` quando o polling detecta subscription ACTIVE/TRIAL (webhook
|
|
278
|
+
* PAYMENT_RECEIVED ou AUTHORIZATION_ACTIVATED chegou). UI deve renderizar
|
|
279
|
+
* confirmação visual nesse momento; após 2-3s chama `dismissPix` pra
|
|
280
|
+
* limpar o modal e deixar SubscriptionGate liberar o app.
|
|
281
|
+
*/
|
|
282
|
+
paid: boolean;
|
|
276
283
|
}
|
|
277
284
|
/**
|
|
278
285
|
* Hook headless pro Paywall. Expõe status atual da subscription + ação
|
package/dist/index.d.ts
CHANGED
|
@@ -273,6 +273,13 @@ interface PixPending {
|
|
|
273
273
|
qrCodePayload: string | null;
|
|
274
274
|
qrCodeBase64: string | null;
|
|
275
275
|
expiresAt: string | null;
|
|
276
|
+
/**
|
|
277
|
+
* Flipa `true` quando o polling detecta subscription ACTIVE/TRIAL (webhook
|
|
278
|
+
* PAYMENT_RECEIVED ou AUTHORIZATION_ACTIVATED chegou). UI deve renderizar
|
|
279
|
+
* confirmação visual nesse momento; após 2-3s chama `dismissPix` pra
|
|
280
|
+
* limpar o modal e deixar SubscriptionGate liberar o app.
|
|
281
|
+
*/
|
|
282
|
+
paid: boolean;
|
|
276
283
|
}
|
|
277
284
|
/**
|
|
278
285
|
* Hook headless pro Paywall. Expõe status atual da subscription + ação
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/AppRoot.tsx
|
|
2
|
-
import { useCallback as useCallback7, useEffect as useEffect8, useRef as useRef3, useState as
|
|
2
|
+
import { useCallback as useCallback7, useEffect as useEffect8, useRef as useRef3, useState as useState12 } from "react";
|
|
3
3
|
import { useHook as useHook8 } from "@hook-sdk/sdk";
|
|
4
4
|
|
|
5
5
|
// src/internal/TemplateConfigContext.tsx
|
|
@@ -121,7 +121,8 @@ function usePaywallState() {
|
|
|
121
121
|
method: "pix-auto",
|
|
122
122
|
qrCodePayload: result.qrCodePayload,
|
|
123
123
|
qrCodeBase64: result.qrCodeBase64,
|
|
124
|
-
expiresAt: null
|
|
124
|
+
expiresAt: null,
|
|
125
|
+
paid: false
|
|
125
126
|
});
|
|
126
127
|
setOpening(false);
|
|
127
128
|
return;
|
|
@@ -132,7 +133,8 @@ function usePaywallState() {
|
|
|
132
133
|
method: "pix-once",
|
|
133
134
|
qrCodePayload: result.qrCodePayload,
|
|
134
135
|
qrCodeBase64: result.qrCodeBase64,
|
|
135
|
-
expiresAt: result.expiresAt
|
|
136
|
+
expiresAt: result.expiresAt,
|
|
137
|
+
paid: false
|
|
136
138
|
});
|
|
137
139
|
setOpening(false);
|
|
138
140
|
return;
|
|
@@ -156,7 +158,7 @@ function usePaywallState() {
|
|
|
156
158
|
const subRef = useRef(subscription);
|
|
157
159
|
subRef.current = subscription;
|
|
158
160
|
useEffect2(() => {
|
|
159
|
-
if (!pixPending) return;
|
|
161
|
+
if (!pixPending || pixPending.paid) return;
|
|
160
162
|
let attempts = 0;
|
|
161
163
|
const MAX_ATTEMPTS = 60;
|
|
162
164
|
let cancelled = false;
|
|
@@ -168,7 +170,7 @@ function usePaywallState() {
|
|
|
168
170
|
if (cancelled) return;
|
|
169
171
|
const s = subRef.current.status();
|
|
170
172
|
if (s === "active" || s === "trialing") {
|
|
171
|
-
setPixPending(
|
|
173
|
+
setPixPending((prev) => prev ? { ...prev, paid: true } : prev);
|
|
172
174
|
return;
|
|
173
175
|
}
|
|
174
176
|
} catch {
|
|
@@ -211,17 +213,37 @@ function SubscriptionGate({ Paywall, children }) {
|
|
|
211
213
|
}
|
|
212
214
|
|
|
213
215
|
// src/internal/PersistedKeysPrefetch.tsx
|
|
214
|
-
import { useEffect as useEffect3 } from "react";
|
|
216
|
+
import { useEffect as useEffect3, useState as useState3 } from "react";
|
|
215
217
|
import { useHook as useHook3 } from "@hook-sdk/sdk";
|
|
216
218
|
import { Fragment as Fragment3, jsx as jsx6 } from "react/jsx-runtime";
|
|
219
|
+
var SAFETY_TIMEOUT_MS = 3e3;
|
|
217
220
|
function PersistedKeysPrefetch({ children }) {
|
|
218
221
|
const { appData } = useHook3();
|
|
219
222
|
const config = useTemplateConfig();
|
|
223
|
+
const hasKeys = !!config.persistedKeys && config.persistedKeys.length > 0;
|
|
224
|
+
const [ready, setReady] = useState3(!hasKeys);
|
|
220
225
|
useEffect3(() => {
|
|
221
226
|
const keys = config.persistedKeys;
|
|
222
|
-
if (!keys || keys.length === 0)
|
|
227
|
+
if (!keys || keys.length === 0) {
|
|
228
|
+
setReady(true);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
let cancelled = false;
|
|
223
232
|
appData.cache.startPrefetch(keys, (ks) => appData.bulkRead(ks));
|
|
233
|
+
void appData.cache.waitForPrimed(SAFETY_TIMEOUT_MS).then((result) => {
|
|
234
|
+
if (cancelled) return;
|
|
235
|
+
if (result === "timeout") {
|
|
236
|
+
console.warn(
|
|
237
|
+
`[@hook-sdk/template] PersistedKeysPrefetch: bulk-read n\xE3o completou em ${SAFETY_TIMEOUT_MS}ms. Liberando render mesmo assim \u2014 usePersistedState pode expor defaultValue at\xE9 o fetch terminar (G77).`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
setReady(true);
|
|
241
|
+
});
|
|
242
|
+
return () => {
|
|
243
|
+
cancelled = true;
|
|
244
|
+
};
|
|
224
245
|
}, [appData, config.persistedKeys]);
|
|
246
|
+
if (!ready) return null;
|
|
225
247
|
return /* @__PURE__ */ jsx6(Fragment3, { children });
|
|
226
248
|
}
|
|
227
249
|
|
|
@@ -234,7 +256,7 @@ function PushPrompt() {
|
|
|
234
256
|
import { useEffect as useEffect5, useRef as useRef2 } from "react";
|
|
235
257
|
|
|
236
258
|
// src/hooks/useInstallPrompt.ts
|
|
237
|
-
import { useCallback as useCallback2, useEffect as useEffect4, useState as
|
|
259
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useState as useState4 } from "react";
|
|
238
260
|
var IOS_RE = /iPad|iPhone|iPod/;
|
|
239
261
|
var IOS_NON_SAFARI_RE = /CriOS|FxiOS|EdgiOS/;
|
|
240
262
|
var ANDROID_RE = /Android/;
|
|
@@ -367,17 +389,17 @@ function useInstallPrompt(slug) {
|
|
|
367
389
|
const iosBrowser = detectIOSBrowser(ua);
|
|
368
390
|
const androidBrowser = detectAndroidBrowser(ua);
|
|
369
391
|
const inAppApp = detectInAppApp(ua);
|
|
370
|
-
const [isInstallable, setIsInstallable] =
|
|
392
|
+
const [isInstallable, setIsInstallable] = useState4(() => {
|
|
371
393
|
if (typeof window === "undefined") return false;
|
|
372
394
|
return window.__pwaInstallPrompt != null;
|
|
373
395
|
});
|
|
374
|
-
const [isInstalled, setIsInstalled] =
|
|
396
|
+
const [isInstalled, setIsInstalled] = useState4(() => {
|
|
375
397
|
const { installed } = detectStandalone();
|
|
376
398
|
return installed || readInstalledMarker(slug);
|
|
377
399
|
});
|
|
378
|
-
const [isDismissedSession, setIsDismissedSession] =
|
|
379
|
-
const [isDismissedPermanent, setIsDismissedPermanent] =
|
|
380
|
-
const [skipCount, setSkipCount] =
|
|
400
|
+
const [isDismissedSession, setIsDismissedSession] = useState4(() => readSessionSkip(slug));
|
|
401
|
+
const [isDismissedPermanent, setIsDismissedPermanent] = useState4(() => readPermanentDismiss(slug).dismissed);
|
|
402
|
+
const [skipCount, setSkipCount] = useState4(() => readSkipCount(slug));
|
|
381
403
|
useEffect4(() => {
|
|
382
404
|
if (typeof window === "undefined") return;
|
|
383
405
|
if (window.__pwaInstallPrompt) {
|
|
@@ -1232,7 +1254,7 @@ function IOSOtherVariant({
|
|
|
1232
1254
|
}
|
|
1233
1255
|
|
|
1234
1256
|
// src/components/InstallGate/variants/InAppBrowserVariant.tsx
|
|
1235
|
-
import { useState as
|
|
1257
|
+
import { useState as useState5 } from "react";
|
|
1236
1258
|
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1237
1259
|
function InAppBrowserVariant({
|
|
1238
1260
|
state,
|
|
@@ -1242,7 +1264,7 @@ function InAppBrowserVariant({
|
|
|
1242
1264
|
const appCopy = INSTALL_COPY.inApp[app] ?? INSTALL_COPY.inApp.other;
|
|
1243
1265
|
const copy = INSTALL_COPY.inApp;
|
|
1244
1266
|
const showPermanent = shouldShowPermanentOption(state);
|
|
1245
|
-
const [copied, setCopied] =
|
|
1267
|
+
const [copied, setCopied] = useState5(false);
|
|
1246
1268
|
const handleCopy = async () => {
|
|
1247
1269
|
await actions.copyLink();
|
|
1248
1270
|
setCopied(true);
|
|
@@ -1511,7 +1533,7 @@ var ErrorBoundary = class extends Component {
|
|
|
1511
1533
|
};
|
|
1512
1534
|
|
|
1513
1535
|
// src/hooks/useLoginForm.ts
|
|
1514
|
-
import { useCallback as useCallback3, useMemo as useMemo2, useState as
|
|
1536
|
+
import { useCallback as useCallback3, useMemo as useMemo2, useState as useState6 } from "react";
|
|
1515
1537
|
import { useHook as useHook4 } from "@hook-sdk/sdk";
|
|
1516
1538
|
|
|
1517
1539
|
// src/errors.ts
|
|
@@ -1548,10 +1570,10 @@ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
1548
1570
|
var MIN_PASSWORD = 8;
|
|
1549
1571
|
function useLoginForm() {
|
|
1550
1572
|
const { auth } = useHook4();
|
|
1551
|
-
const [email, setEmail] =
|
|
1552
|
-
const [password, setPassword] =
|
|
1553
|
-
const [submitting, setSubmitting] =
|
|
1554
|
-
const [error, setError] =
|
|
1573
|
+
const [email, setEmail] = useState6("");
|
|
1574
|
+
const [password, setPassword] = useState6("");
|
|
1575
|
+
const [submitting, setSubmitting] = useState6(false);
|
|
1576
|
+
const [error, setError] = useState6(null);
|
|
1555
1577
|
const emailError = useMemo2(() => {
|
|
1556
1578
|
if (email.length === 0) return null;
|
|
1557
1579
|
if (!EMAIL_RE.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
@@ -1662,7 +1684,7 @@ function GoogleGlyph() {
|
|
|
1662
1684
|
}
|
|
1663
1685
|
|
|
1664
1686
|
// src/internal/OAuthErrorBanner.tsx
|
|
1665
|
-
import { useEffect as useEffect6, useState as
|
|
1687
|
+
import { useEffect as useEffect6, useState as useState7 } from "react";
|
|
1666
1688
|
import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1667
1689
|
var ERROR_MESSAGES = {
|
|
1668
1690
|
invalid_state: "Sess\xE3o expirou, tente de novo.",
|
|
@@ -1683,7 +1705,7 @@ function stripErrorFromUrl() {
|
|
|
1683
1705
|
window.history.replaceState({}, "", url.toString());
|
|
1684
1706
|
}
|
|
1685
1707
|
function OAuthErrorBanner() {
|
|
1686
|
-
const [code, setCode] =
|
|
1708
|
+
const [code, setCode] = useState7(() => readErrorCode());
|
|
1687
1709
|
useEffect6(() => {
|
|
1688
1710
|
if (code !== null) stripErrorFromUrl();
|
|
1689
1711
|
}, [code]);
|
|
@@ -1817,17 +1839,17 @@ function DefaultLoginScreen({ onNavigate }) {
|
|
|
1817
1839
|
}
|
|
1818
1840
|
|
|
1819
1841
|
// src/hooks/useSignupForm.ts
|
|
1820
|
-
import { useCallback as useCallback4, useMemo as useMemo3, useState as
|
|
1842
|
+
import { useCallback as useCallback4, useMemo as useMemo3, useState as useState8 } from "react";
|
|
1821
1843
|
import { useHook as useHook5 } from "@hook-sdk/sdk";
|
|
1822
1844
|
var EMAIL_RE2 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1823
1845
|
var MIN_PASSWORD2 = 8;
|
|
1824
1846
|
function useSignupForm() {
|
|
1825
1847
|
const { auth } = useHook5();
|
|
1826
|
-
const [name, setName] =
|
|
1827
|
-
const [email, setEmail] =
|
|
1828
|
-
const [password, setPassword] =
|
|
1829
|
-
const [submitting, setSubmitting] =
|
|
1830
|
-
const [error, setError] =
|
|
1848
|
+
const [name, setName] = useState8("");
|
|
1849
|
+
const [email, setEmail] = useState8("");
|
|
1850
|
+
const [password, setPassword] = useState8("");
|
|
1851
|
+
const [submitting, setSubmitting] = useState8(false);
|
|
1852
|
+
const [error, setError] = useState8(null);
|
|
1831
1853
|
const nameError = useMemo3(() => {
|
|
1832
1854
|
if (name.length === 0) return null;
|
|
1833
1855
|
if (name.trim().length < 2) return "Nome muito curto.";
|
|
@@ -1932,15 +1954,15 @@ function DefaultSignupScreen({ onNavigate }) {
|
|
|
1932
1954
|
}
|
|
1933
1955
|
|
|
1934
1956
|
// src/hooks/useForgotForm.ts
|
|
1935
|
-
import { useCallback as useCallback5, useMemo as useMemo4, useState as
|
|
1957
|
+
import { useCallback as useCallback5, useMemo as useMemo4, useState as useState9 } from "react";
|
|
1936
1958
|
import { useHook as useHook6 } from "@hook-sdk/sdk";
|
|
1937
1959
|
var EMAIL_RE3 = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1938
1960
|
function useForgotForm() {
|
|
1939
1961
|
const { auth } = useHook6();
|
|
1940
|
-
const [email, setEmail] =
|
|
1941
|
-
const [submitting, setSubmitting] =
|
|
1942
|
-
const [sent, setSent] =
|
|
1943
|
-
const [error, setError] =
|
|
1962
|
+
const [email, setEmail] = useState9("");
|
|
1963
|
+
const [submitting, setSubmitting] = useState9(false);
|
|
1964
|
+
const [sent, setSent] = useState9(false);
|
|
1965
|
+
const [error, setError] = useState9(null);
|
|
1944
1966
|
const emailError = useMemo4(() => {
|
|
1945
1967
|
if (email.length === 0) return null;
|
|
1946
1968
|
if (!EMAIL_RE3.test(email)) return "Formato de e-mail inv\xE1lido.";
|
|
@@ -2006,17 +2028,17 @@ function DefaultForgotScreen({ onNavigate }) {
|
|
|
2006
2028
|
}
|
|
2007
2029
|
|
|
2008
2030
|
// src/hooks/useResetForm.ts
|
|
2009
|
-
import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo5, useState as
|
|
2031
|
+
import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo5, useState as useState10 } from "react";
|
|
2010
2032
|
import { useHook as useHook7 } from "@hook-sdk/sdk";
|
|
2011
2033
|
var MIN_PASSWORD3 = 12;
|
|
2012
2034
|
function useResetForm() {
|
|
2013
2035
|
const { auth } = useHook7();
|
|
2014
|
-
const [token, setToken] =
|
|
2015
|
-
const [password, setPassword] =
|
|
2016
|
-
const [confirm, setConfirm] =
|
|
2017
|
-
const [submitting, setSubmitting] =
|
|
2018
|
-
const [done, setDone] =
|
|
2019
|
-
const [error, setError] =
|
|
2036
|
+
const [token, setToken] = useState10(null);
|
|
2037
|
+
const [password, setPassword] = useState10("");
|
|
2038
|
+
const [confirm, setConfirm] = useState10("");
|
|
2039
|
+
const [submitting, setSubmitting] = useState10(false);
|
|
2040
|
+
const [done, setDone] = useState10(false);
|
|
2041
|
+
const [error, setError] = useState10(null);
|
|
2020
2042
|
useEffect7(() => {
|
|
2021
2043
|
if (typeof window === "undefined") return;
|
|
2022
2044
|
const params = new URLSearchParams(window.location.search);
|
|
@@ -2112,13 +2134,13 @@ function DefaultResetScreen({ onNavigate }) {
|
|
|
2112
2134
|
}
|
|
2113
2135
|
|
|
2114
2136
|
// src/defaults/DefaultPaywall.tsx
|
|
2115
|
-
import { useState as
|
|
2137
|
+
import { useState as useState11 } from "react";
|
|
2116
2138
|
import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2117
2139
|
function DefaultPaywall() {
|
|
2118
2140
|
const config = useTemplateConfig();
|
|
2119
2141
|
const { checkout, opening, error } = usePaywallState();
|
|
2120
2142
|
const p = config.subscription.paywall_config;
|
|
2121
|
-
const [cpf, setCpf] =
|
|
2143
|
+
const [cpf, setCpf] = useState11("");
|
|
2122
2144
|
const cpfDigits = cpf.replace(/\D/g, "");
|
|
2123
2145
|
const canCheckout = cpfDigits.length === 11 && !opening;
|
|
2124
2146
|
return /* @__PURE__ */ jsxs18("main", { style: { padding: 24, maxWidth: 440, margin: "0 auto", textAlign: "center" }, children: [
|
|
@@ -2178,7 +2200,7 @@ function PaymentReturnHandler({ children }) {
|
|
|
2178
2200
|
const subRef = useRef3(subscription);
|
|
2179
2201
|
subRef.current = subscription;
|
|
2180
2202
|
const runIdRef = useRef3(0);
|
|
2181
|
-
const [state, setState] =
|
|
2203
|
+
const [state, setState] = useState12("idle");
|
|
2182
2204
|
const runPoll = useCallback7(() => {
|
|
2183
2205
|
const runId = ++runIdRef.current;
|
|
2184
2206
|
setState("confirming");
|
|
@@ -2282,7 +2304,7 @@ function AppRoot({
|
|
|
2282
2304
|
}
|
|
2283
2305
|
|
|
2284
2306
|
// src/hooks/usePush.ts
|
|
2285
|
-
import { useCallback as useCallback8, useEffect as useEffect9, useState as
|
|
2307
|
+
import { useCallback as useCallback8, useEffect as useEffect9, useState as useState13 } from "react";
|
|
2286
2308
|
import { useHook as useHook9 } from "@hook-sdk/sdk";
|
|
2287
2309
|
function detectIosNeedsInstall() {
|
|
2288
2310
|
if (typeof navigator === "undefined" || typeof window === "undefined") return false;
|
|
@@ -2310,7 +2332,7 @@ function deriveState(push) {
|
|
|
2310
2332
|
}
|
|
2311
2333
|
function usePush() {
|
|
2312
2334
|
const { push } = useHook9();
|
|
2313
|
-
const [state, setState] =
|
|
2335
|
+
const [state, setState] = useState13(() => deriveState(push));
|
|
2314
2336
|
useEffect9(() => {
|
|
2315
2337
|
setState(deriveState(push));
|
|
2316
2338
|
}, [push]);
|
|
@@ -2463,13 +2485,13 @@ function useSubscription() {
|
|
|
2463
2485
|
}
|
|
2464
2486
|
|
|
2465
2487
|
// src/hooks/useReminders.ts
|
|
2466
|
-
import { useCallback as useCallback9, useEffect as useEffect11, useState as
|
|
2488
|
+
import { useCallback as useCallback9, useEffect as useEffect11, useState as useState14 } from "react";
|
|
2467
2489
|
import { useHook as useHook13 } from "@hook-sdk/sdk";
|
|
2468
2490
|
function useReminders() {
|
|
2469
2491
|
const { push } = useHook13();
|
|
2470
2492
|
const r = push.reminders;
|
|
2471
|
-
const [reminders, setReminders] =
|
|
2472
|
-
const [loading, setLoading] =
|
|
2493
|
+
const [reminders, setReminders] = useState14([]);
|
|
2494
|
+
const [loading, setLoading] = useState14(true);
|
|
2473
2495
|
const reload = useCallback9(async () => {
|
|
2474
2496
|
setLoading(true);
|
|
2475
2497
|
try {
|
|
@@ -2500,9 +2522,9 @@ function useReminders() {
|
|
|
2500
2522
|
}
|
|
2501
2523
|
|
|
2502
2524
|
// src/hooks/useToast.ts
|
|
2503
|
-
import { useCallback as useCallback10, useState as
|
|
2525
|
+
import { useCallback as useCallback10, useState as useState15 } from "react";
|
|
2504
2526
|
function useToast() {
|
|
2505
|
-
const [items, setItems] =
|
|
2527
|
+
const [items, setItems] = useState15([]);
|
|
2506
2528
|
const show = useCallback10((message, kind = "info") => {
|
|
2507
2529
|
const id = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2508
2530
|
setItems((prev) => [...prev, { id, message, kind }]);
|