@hook-sdk/template 0.7.1 → 0.7.3

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
@@ -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 useEffect7, useRef as useRef2, useState as useState11 } from "react";
2
+ import { useCallback as useCallback7, useEffect as useEffect8, useRef as useRef3, useState as useState11 } from "react";
3
3
  import { useHook as useHook8 } from "@hook-sdk/sdk";
4
4
 
5
5
  // src/internal/TemplateConfigContext.tsx
@@ -92,7 +92,7 @@ function AuthGate({ Login, Signup, Forgot, Reset, children }) {
92
92
  }
93
93
 
94
94
  // src/hooks/usePaywallState.ts
95
- import { useCallback, useState as useState2 } from "react";
95
+ import { useCallback, useEffect as useEffect2, useRef, useState as useState2 } from "react";
96
96
  import { useHook as useHook2 } from "@hook-sdk/sdk";
97
97
  function usePaywallState() {
98
98
  const { subscription } = useHook2();
@@ -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;
@@ -153,6 +155,33 @@ function usePaywallState() {
153
155
  }
154
156
  }, [subscription]);
155
157
  const dismissPix = useCallback(() => setPixPending(null), []);
158
+ const subRef = useRef(subscription);
159
+ subRef.current = subscription;
160
+ useEffect2(() => {
161
+ if (!pixPending || pixPending.paid) return;
162
+ let attempts = 0;
163
+ const MAX_ATTEMPTS = 60;
164
+ let cancelled = false;
165
+ const tick = async () => {
166
+ if (cancelled || attempts >= MAX_ATTEMPTS) return;
167
+ attempts++;
168
+ try {
169
+ await subRef.current.refresh();
170
+ if (cancelled) return;
171
+ const s = subRef.current.status();
172
+ if (s === "active" || s === "trialing") {
173
+ setPixPending((prev) => prev ? { ...prev, paid: true } : prev);
174
+ return;
175
+ }
176
+ } catch {
177
+ }
178
+ if (!cancelled) setTimeout(tick, 3e3);
179
+ };
180
+ setTimeout(tick, 3e3);
181
+ return () => {
182
+ cancelled = true;
183
+ };
184
+ }, [pixPending]);
156
185
  return {
157
186
  status,
158
187
  daysLeftInTrial,
@@ -184,13 +213,13 @@ function SubscriptionGate({ Paywall, children }) {
184
213
  }
185
214
 
186
215
  // src/internal/PersistedKeysPrefetch.tsx
187
- import { useEffect as useEffect2 } from "react";
216
+ import { useEffect as useEffect3 } from "react";
188
217
  import { useHook as useHook3 } from "@hook-sdk/sdk";
189
218
  import { Fragment as Fragment3, jsx as jsx6 } from "react/jsx-runtime";
190
219
  function PersistedKeysPrefetch({ children }) {
191
220
  const { appData } = useHook3();
192
221
  const config = useTemplateConfig();
193
- useEffect2(() => {
222
+ useEffect3(() => {
194
223
  const keys = config.persistedKeys;
195
224
  if (!keys || keys.length === 0) return;
196
225
  appData.cache.startPrefetch(keys, (ks) => appData.bulkRead(ks));
@@ -204,10 +233,10 @@ function PushPrompt() {
204
233
  }
205
234
 
206
235
  // src/components/InstallGate/InstallGate.tsx
207
- import { useEffect as useEffect4, useRef } from "react";
236
+ import { useEffect as useEffect5, useRef as useRef2 } from "react";
208
237
 
209
238
  // src/hooks/useInstallPrompt.ts
210
- import { useCallback as useCallback2, useEffect as useEffect3, useState as useState3 } from "react";
239
+ import { useCallback as useCallback2, useEffect as useEffect4, useState as useState3 } from "react";
211
240
  var IOS_RE = /iPad|iPhone|iPod/;
212
241
  var IOS_NON_SAFARI_RE = /CriOS|FxiOS|EdgiOS/;
213
242
  var ANDROID_RE = /Android/;
@@ -351,7 +380,7 @@ function useInstallPrompt(slug) {
351
380
  const [isDismissedSession, setIsDismissedSession] = useState3(() => readSessionSkip(slug));
352
381
  const [isDismissedPermanent, setIsDismissedPermanent] = useState3(() => readPermanentDismiss(slug).dismissed);
353
382
  const [skipCount, setSkipCount] = useState3(() => readSkipCount(slug));
354
- useEffect3(() => {
383
+ useEffect4(() => {
355
384
  if (typeof window === "undefined") return;
356
385
  if (window.__pwaInstallPrompt) {
357
386
  setIsInstallable(true);
@@ -375,7 +404,7 @@ function useInstallPrompt(slug) {
375
404
  window.removeEventListener("appinstalled", onInstalled);
376
405
  };
377
406
  }, [slug]);
378
- useEffect3(() => {
407
+ useEffect4(() => {
379
408
  if (typeof window === "undefined") return;
380
409
  const mq = window.matchMedia?.("(display-mode: standalone)");
381
410
  if (!mq) return;
@@ -1420,8 +1449,8 @@ function InstallGate({ children }) {
1420
1449
  const enabled = features_enabled.includes("install_prompt");
1421
1450
  const installState = useInstallPrompt(slug);
1422
1451
  const shouldBlock = enabled && shouldBlockInstall(installState);
1423
- const trackedRef = useRef(null);
1424
- useEffect4(() => {
1452
+ const trackedRef = useRef2(null);
1453
+ useEffect5(() => {
1425
1454
  if (!shouldBlock) return;
1426
1455
  if (typeof window === "undefined") return;
1427
1456
  const variantKey = `${slug}:${installState.variant}`;
@@ -1635,7 +1664,7 @@ function GoogleGlyph() {
1635
1664
  }
1636
1665
 
1637
1666
  // src/internal/OAuthErrorBanner.tsx
1638
- import { useEffect as useEffect5, useState as useState6 } from "react";
1667
+ import { useEffect as useEffect6, useState as useState6 } from "react";
1639
1668
  import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
1640
1669
  var ERROR_MESSAGES = {
1641
1670
  invalid_state: "Sess\xE3o expirou, tente de novo.",
@@ -1657,7 +1686,7 @@ function stripErrorFromUrl() {
1657
1686
  }
1658
1687
  function OAuthErrorBanner() {
1659
1688
  const [code, setCode] = useState6(() => readErrorCode());
1660
- useEffect5(() => {
1689
+ useEffect6(() => {
1661
1690
  if (code !== null) stripErrorFromUrl();
1662
1691
  }, [code]);
1663
1692
  if (!code) return null;
@@ -1979,7 +2008,7 @@ function DefaultForgotScreen({ onNavigate }) {
1979
2008
  }
1980
2009
 
1981
2010
  // src/hooks/useResetForm.ts
1982
- import { useCallback as useCallback6, useEffect as useEffect6, useMemo as useMemo5, useState as useState9 } from "react";
2011
+ import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo5, useState as useState9 } from "react";
1983
2012
  import { useHook as useHook7 } from "@hook-sdk/sdk";
1984
2013
  var MIN_PASSWORD3 = 12;
1985
2014
  function useResetForm() {
@@ -1990,7 +2019,7 @@ function useResetForm() {
1990
2019
  const [submitting, setSubmitting] = useState9(false);
1991
2020
  const [done, setDone] = useState9(false);
1992
2021
  const [error, setError] = useState9(null);
1993
- useEffect6(() => {
2022
+ useEffect7(() => {
1994
2023
  if (typeof window === "undefined") return;
1995
2024
  const params = new URLSearchParams(window.location.search);
1996
2025
  const t = params.get("token");
@@ -2148,9 +2177,9 @@ import { Fragment as Fragment6, jsx as jsx25, jsxs as jsxs19 } from "react/jsx-r
2148
2177
  var BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 4e4];
2149
2178
  function PaymentReturnHandler({ children }) {
2150
2179
  const { subscription } = useHook8();
2151
- const subRef = useRef2(subscription);
2180
+ const subRef = useRef3(subscription);
2152
2181
  subRef.current = subscription;
2153
- const runIdRef = useRef2(0);
2182
+ const runIdRef = useRef3(0);
2154
2183
  const [state, setState] = useState11("idle");
2155
2184
  const runPoll = useCallback7(() => {
2156
2185
  const runId = ++runIdRef.current;
@@ -2181,7 +2210,7 @@ function PaymentReturnHandler({ children }) {
2181
2210
  };
2182
2211
  void tick();
2183
2212
  }, []);
2184
- useEffect7(() => {
2213
+ useEffect8(() => {
2185
2214
  if (typeof window === "undefined") return;
2186
2215
  const url = new URL(window.location.href);
2187
2216
  if (url.searchParams.get("paymentReturn") !== "1") return;
@@ -2255,7 +2284,7 @@ function AppRoot({
2255
2284
  }
2256
2285
 
2257
2286
  // src/hooks/usePush.ts
2258
- import { useCallback as useCallback8, useEffect as useEffect8, useState as useState12 } from "react";
2287
+ import { useCallback as useCallback8, useEffect as useEffect9, useState as useState12 } from "react";
2259
2288
  import { useHook as useHook9 } from "@hook-sdk/sdk";
2260
2289
  function detectIosNeedsInstall() {
2261
2290
  if (typeof navigator === "undefined" || typeof window === "undefined") return false;
@@ -2284,7 +2313,7 @@ function deriveState(push) {
2284
2313
  function usePush() {
2285
2314
  const { push } = useHook9();
2286
2315
  const [state, setState] = useState12(() => deriveState(push));
2287
- useEffect8(() => {
2316
+ useEffect9(() => {
2288
2317
  setState(deriveState(push));
2289
2318
  }, [push]);
2290
2319
  const subscribe = useCallback8(async () => {
@@ -2400,12 +2429,12 @@ function discountPercent(anchorCents, realCents) {
2400
2429
  }
2401
2430
 
2402
2431
  // src/hooks/useAuthPrimitives.ts
2403
- import { useEffect as useEffect9 } from "react";
2432
+ import { useEffect as useEffect10 } from "react";
2404
2433
  import { useHook as useHook11 } from "@hook-sdk/sdk";
2405
2434
  var warned = false;
2406
2435
  function useAuthPrimitives() {
2407
2436
  const { auth } = useHook11();
2408
- useEffect9(() => {
2437
+ useEffect10(() => {
2409
2438
  if (!warned && process.env.NODE_ENV !== "production") {
2410
2439
  warned = true;
2411
2440
  console.warn(
@@ -2436,7 +2465,7 @@ function useSubscription() {
2436
2465
  }
2437
2466
 
2438
2467
  // src/hooks/useReminders.ts
2439
- import { useCallback as useCallback9, useEffect as useEffect10, useState as useState13 } from "react";
2468
+ import { useCallback as useCallback9, useEffect as useEffect11, useState as useState13 } from "react";
2440
2469
  import { useHook as useHook13 } from "@hook-sdk/sdk";
2441
2470
  function useReminders() {
2442
2471
  const { push } = useHook13();
@@ -2452,7 +2481,7 @@ function useReminders() {
2452
2481
  setLoading(false);
2453
2482
  }
2454
2483
  }, [r]);
2455
- useEffect10(() => {
2484
+ useEffect11(() => {
2456
2485
  void reload();
2457
2486
  }, [reload]);
2458
2487
  const setReminder = useCallback9(async (input) => {