@cosmo-frameworks/paywall-react 0.1.1 → 0.1.2

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/CHANGELOG.md CHANGED
@@ -7,6 +7,24 @@ y el versionado es [SemVer](https://semver.org/lang/es/).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.2] - 2026-08-22
11
+
12
+ ### Corregido
13
+
14
+ - **Bucle de peticiones al montar.** El efecto que programaba la recarga tenía
15
+ el estado entre sus dependencias, así que cada respuesta lo reprogramaba y
16
+ disparaba otra petición, encadenando llamadas hasta agotar el rate limit del
17
+ servidor (HTTP 429). Ahora la cadencia vive en una referencia y el temporizador
18
+ se encadena con `setTimeout`, de modo que el efecto solo depende de la función
19
+ de carga. Con 429 el SDK caía además en fail-open, así que el bloqueo dejaba
20
+ de aplicarse: quien actualice desde 0.1.x debería hacerlo.
21
+
22
+ ## [0.1.1] - 2026-08-21
23
+
24
+ ### Añadido
25
+
26
+ Cambiado el provider a npm
27
+
10
28
  ## [0.1.0] - 2026-08-21
11
29
 
12
30
  Primera versión.
package/README.md CHANGED
@@ -158,68 +158,4 @@ Solo la license key. La respuesta no incluye importes ni datos personales salvo
158
158
  que la licencia lo autorice explícitamente.
159
159
 
160
160
  **¿Y si borro `localStorage`?**
161
- Se dispara una consulta nueva, que es más estricta, no menos.
162
-
163
- ---
164
-
165
- ## Desarrollo
166
-
167
- ```bash
168
- npm install
169
- npm test # Vitest
170
- npm run build # ESM + CJS + tipos
171
- npm pack # tarball para probar la integración en otro proyecto
172
- ```
173
-
174
- ## Publicación
175
-
176
- El código vive en `cosmo-frameworks/paywall-react` (repositorio privado) y el
177
- paquete se publica en **npmjs.com** bajo el scope `@cosmo-frameworks`.
178
-
179
- Se eligió npmjs y no GitHub Packages porque este último exige un token de
180
- acceso **incluso para paquetes públicos**, lo que obligaría a cada cliente a
181
- configurar un `.npmrc` con credenciales y a resolver la autenticación dentro de
182
- su Dockerfile. En npmjs un paquete público se instala sin nada.
183
-
184
- La publicación usa **trusted publishing (OIDC)**: el workflow obtiene una
185
- credencial efímera de npm y no hay ningún secreto guardado en el repositorio.
186
- Se eligió así porque los tokens de npm ya no son una opción sostenible — los
187
- classic fueron revocados en diciembre de 2025, los granulares de escritura
188
- caducan a los 90 días, y los de bypass-2FA pierden la capacidad de publicar en
189
- enero de 2027.
190
-
191
- Requisitos, una sola vez:
192
-
193
- - La organización `cosmo-frameworks` creada en npmjs.com (gratis para paquetes
194
- públicos).
195
- - El **trusted publisher** configurado en los ajustes del paquete, apuntando a
196
- este repositorio y a `.github/workflows/publish.yml`.
197
- - El primer `npm publish` hecho a mano desde tu máquina, porque el trusted
198
- publisher se configura sobre un paquete que ya existe.
199
-
200
- La procedencia firmada se genera sola en este modo: no hace falta
201
- `--provenance`.
202
-
203
- > **No ejecutes `git init` aquí mientras la carpeta siga dentro del monorepo.**
204
- > Un repositorio anidado hace que el monorepo trate esta carpeta como repo
205
- > externo y deje de versionar su contenido **en silencio**: los commits pasan
206
- > sin error y el paquete no viaja. Si alguna herramienta gráfica (GitKraken y
207
- > similares crean un `.git` al detectar carpetas nuevas) lo ha creado, bórralo
208
- > con `rm -rf packages/paywall-react/.git` antes de commitear.
209
-
210
- El **repositorio es privado** y el **paquete es público**: el `src/` y el
211
- historial no se ven, y solo se distribuye lo que declara `files` — el bundle de
212
- `dist/` y este README, sin sourcemaps, que embeberían el TypeScript original.
213
-
214
- Primera publicación, ya con la carpeta **fuera** del monorepo:
215
-
216
- ```bash
217
- cd paywall-react
218
- git init && git add . && git commit -m "chore: primera versión"
219
- git remote add origin git@github.com:cosmo-frameworks/paywall-react.git
220
- git push -u origin main
221
- git tag v0.1.0 && git push --tags # dispara el workflow
222
- ```
223
-
224
- A partir de ahí, ese repositorio es la fuente de verdad y esta carpeta puede
225
- eliminarse del monorepo.
161
+ Se dispara una consulta nueva, que es más estricta, no menos.
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("react"),t=require("react/jsx-runtime");var n=`/api/public/license/v1/status`,r=`cpl:state:`,i=1e4,a=1e3,o=3e4,s=()=>typeof window<`u`&&window.document!==void 0,c=new Map,l=e=>`${r}${e.slice(0,12)}`,u=e=>(e.storage??`local`)===`local`&&s(),d=e=>{if(typeof e!=`object`||!e)return!1;let t=e;return t.version!==1||typeof t.receivedAt!=`number`?!1:typeof t.payload?.status==`string`},f=(e,t,n)=>{if((n.storage??`local`)===`none`)return;let r={version:1,payload:t,receivedAt:Date.now()},i=l(e);if(c.set(i,r),u(n))try{window.localStorage.setItem(i,JSON.stringify(r))}catch{}},p=(e,t)=>{if((t.storage??`local`)===`none`)return null;let n=l(e),r=c.get(n)??null;if(!r&&u(t))try{let e=window.localStorage.getItem(n);if(e){let t=JSON.parse(e);d(t)&&(r=t)}}catch{}if(!r)return null;let i=t.maxCacheAgeMs??6048e5;return Date.now()-r.receivedAt>i?(m(e),null):r},m=e=>{let t=l(e);if(c.delete(t),s())try{window.localStorage.removeItem(t)}catch{}},h=1,g=e=>{if(typeof e!=`object`||!e)return!1;let t=e;return t.v===h&&typeof t.status==`string`&&typeof t.licenseId==`string`},_=async e=>{let{licenseKey:t}=e;if(!t)return v(e,Error(`[paywall] Falta licenseKey en la configuración.`));let r=e.fetchImpl??globalThis.fetch;if(typeof r!=`function`)return v(e,Error(`[paywall] No hay implementación de fetch disponible.`));let a=`${(e.apiUrl??`https://api.clients.ridel.dev`).replace(/\/+$/,``)}${n}?key=${encodeURIComponent(t)}&t=${Date.now()}`,o=new AbortController,s=setTimeout(()=>o.abort(),i);try{let n=await r(a,{method:`GET`,credentials:`omit`,signal:e.signal??o.signal}),i=await n.json();if(!n.ok){let t=i?.error??`HTTP ${n.status}`;return v(e,Error(`[paywall] El servidor rechazó la licencia: ${t}`))}return g(i)?(f(t,i,e),{payload:i,source:`network`,isStale:!1,error:null}):v(e,Error(`[paywall] Respuesta con un formato que esta versión del SDK no entiende. Actualiza el paquete.`))}catch(t){return v(e,y(t))}finally{clearTimeout(s)}},v=(e,t)=>{let n=e.licenseKey?p(e.licenseKey,e):null;return n?{payload:n.payload,source:`cache`,isStale:Date.parse(n.payload.expiresAt)<Date.now(),error:t}:{payload:null,source:`none`,isStale:!1,error:t}},y=e=>e instanceof Error?e:Error(`[paywall] Fallo al consultar la licencia: ${String(e)}`),b=(0,e.createContext)(null),x=e=>e?new Date(e):null,S=new Map,C=(0,e.memo)(({config:n,children:r})=>{let[i,c]=(0,e.useState)(()=>{let e=s()?p(n.licenseKey,n):null;return{payload:e?.payload??null,source:e?`cache`:`none`,isStale:e?Date.parse(e.payload.expiresAt)<Date.now():!1,isLoading:!0,error:null}}),l=(0,e.useRef)(0),u=(0,e.useRef)(null),d=(0,e.useRef)(n.onStatusChange);d.current=n.onStatusChange;let f=(0,e.useCallback)(async()=>{if(!s())return;u.current?.abort();let e=new AbortController;u.current=e;let t=`${n.apiUrl??``}|${n.licenseKey}`,r=S.get(t),i=r??_({licenseKey:n.licenseKey,apiUrl:n.apiUrl,storage:n.storage,maxCacheAgeMs:n.maxCacheAgeMs,fetchImpl:n.fetchImpl,signal:e.signal});r||S.set(t,i);try{let t=await i;if(e.signal.aborted)return;l.current=t.source===`network`?0:l.current+1,c({payload:t.payload,source:t.source,isStale:t.isStale,isLoading:!1,error:t.error}),n.debug&&console.info(`[paywall]`,t.source,t.payload?.status,t.error)}finally{r||S.delete(t)}},[n.apiUrl,n.licenseKey,n.storage,n.maxCacheAgeMs,n.fetchImpl,n.debug]);(0,e.useEffect)(()=>{if(!s())return;f();let e=i.payload?.refreshAfterSeconds,t=n.refreshIntervalMs??9e5,r=Math.min(t,e?e*1e3:t),c=l.current>0?Math.min(o,a*2**Math.min(l.current,5)):r,d=setInterval(()=>void f(),c);return()=>{clearInterval(d),u.current?.abort()}},[f,n.refreshIntervalMs,i.payload]),(0,e.useEffect)(()=>{if(!s())return;let e=()=>{document.visibilityState===`visible`&&f()};return document.addEventListener(`visibilitychange`,e),window.addEventListener(`online`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`online`,e)}},[f]);let m=(0,e.useMemo)(()=>{let e=i.payload;return{state:e?.status??`OK`,reason:e?.reason??`NONE`,isBlocked:e?.status===`BLOCKED`,isLoading:i.isLoading,isStale:i.isStale,source:i.source,graceUntil:x(e?.graceUntil),nextTransitionAt:x(e?.nextTransitionAt),message:e?.message??null,contactUrl:e?.contactUrl??null,payload:e,error:i.error,refresh:()=>void f()}},[i,f]);(0,e.useEffect)(()=>{d.current?.(m)},[m]);let h=(0,e.useMemo)(()=>({status:m,config:n}),[m,n]);return(0,t.jsx)(b.Provider,{value:h,children:r})});C.displayName=`PaywallProvider`;var w=[`BLOCKED`],T={OK:`allow`,WARNING:`warn`,GRACE:`grace`,BLOCKED:`grace`},E=(e,t)=>{let n=T[e]??`allow`;return e===`OK`?`allow`:(t.blockOn??w).includes(e)?`block`:n},D=`system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif`,O={position:`fixed`,inset:0,zIndex:2147483647,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,background:`rgba(9, 9, 11, 0.92)`,backdropFilter:`blur(6px)`,fontFamily:D,color:`#fafafa`,overflowY:`auto`},k={width:`100%`,maxWidth:`440px`,background:`#18181b`,border:`1px solid #27272a`,borderRadius:`16px`,padding:`32px`,boxShadow:`0 24px 48px rgba(0, 0, 0, 0.45)`,textAlign:`center`},A={display:`inline-flex`,alignItems:`center`,justifyContent:`center`,width:`48px`,height:`48px`,borderRadius:`50%`,background:`rgba(239, 68, 68, 0.14)`,color:`#f87171`,fontSize:`24px`,marginBottom:`20px`},j={margin:`0 0 12px`,fontSize:`20px`,fontWeight:600,lineHeight:1.3},M={margin:`0 0 24px`,fontSize:`15px`,lineHeight:1.55,color:`#a1a1aa`},N={display:`inline-block`,padding:`11px 22px`,borderRadius:`10px`,background:`#fafafa`,color:`#18181b`,fontSize:`14px`,fontWeight:600,textDecoration:`none`},P={margin:`20px 0 0`,fontSize:`12px`,color:`#71717a`},F={position:`sticky`,top:0,zIndex:2147483e3,display:`flex`,alignItems:`center`,gap:`12px`,padding:`10px 16px`,fontFamily:D,fontSize:`14px`,lineHeight:1.4,boxSizing:`border-box`},I={...F,background:`#fef3c7`,color:`#78350f`,borderBottom:`1px solid #fcd34d`},L={...F,background:`#fee2e2`,color:`#7f1d1d`,borderBottom:`1px solid #fca5a5`},R={color:`inherit`,fontWeight:600,textDecoration:`underline`,whiteSpace:`nowrap`},z={marginLeft:`auto`,padding:`2px 8px`,border:`none`,borderRadius:`6px`,background:`transparent`,color:`inherit`,fontSize:`18px`,lineHeight:1,cursor:`pointer`},B={flex:1,minWidth:0},V=`Este servicio está temporalmente suspendido. Ponte en contacto con el proveedor para restablecerlo.`,H=(0,e.memo)(({status:n,config:r})=>{let i=(0,e.useMemo)(()=>r.productName?`${r.productName} no está disponible`:`Servicio no disponible`,[r.productName]);return(0,t.jsx)(`div`,{style:O,role:`alertdialog`,"aria-modal":`true`,children:(0,t.jsxs)(`div`,{style:k,children:[(0,t.jsx)(`div`,{style:A,"aria-hidden":`true`,children:`⚠`}),(0,t.jsx)(`h1`,{style:j,children:i}),(0,t.jsx)(`p`,{style:M,children:n.message??V}),n.contactUrl?(0,t.jsx)(`a`,{style:N,href:n.contactUrl,target:`_blank`,rel:`noreferrer noopener`,children:`Resolver ahora`}):null,r.contactEmail?(0,t.jsxs)(`p`,{style:P,children:[`¿Dudas? Escribe a`,` `,(0,t.jsx)(`a`,{href:`mailto:${r.contactEmail}`,style:R,children:r.contactEmail})]}):null]})})});H.displayName=`BlockedOverlay`;var U=e=>{if(!e)return null;let t=e.getTime()-Date.now();if(t<=0)return null;let n=Math.floor(t/864e5);if(n>=1)return n===1?`1 día`:`${n} días`;let r=Math.max(1,Math.floor(t/36e5));return r===1?`1 hora`:`${r} horas`},W=(0,e.memo)(({status:n,variant:r})=>{let[i,a]=(0,e.useState)(!1),o=(0,e.useMemo)(()=>U(n.graceUntil),[n.graceUntil]);if(i)return null;let s=r===`grace`?L:I;return(0,t.jsxs)(`div`,{style:s,role:`status`,children:[(0,t.jsxs)(`span`,{style:B,children:[n.message,o?(0,t.jsxs)(`strong`,{children:[` El servicio se suspenderá en `,o,`.`]}):null]}),n.contactUrl?(0,t.jsx)(`a`,{style:R,href:n.contactUrl,target:`_blank`,rel:`noreferrer noopener`,children:`Resolver`}):null,r===`warning`?(0,t.jsx)(`button`,{type:`button`,style:z,onClick:()=>a(!0),"aria-label":`Descartar aviso`,children:`×`}):null]})});W.displayName=`StatusBanner`;var G=(0,e.memo)(({children:n,renderBlocked:r,renderWarning:i,renderGrace:a,showBanners:o=!0})=>{let s=(0,e.useContext)(b);if(!s)throw Error(`[paywall] <PaywallGate> debe usarse dentro de <PaywallProvider>.`);let{status:c,config:l}=s,u=(0,e.useMemo)(()=>E(c.state,l),[c.state,l]);if(u===`block`)return(0,t.jsx)(t.Fragment,{children:r?r(c):(0,t.jsx)(H,{status:c,config:l})});let d=o?u===`warn`?i?i(c):(0,t.jsx)(W,{status:c,variant:`warning`}):u===`grace`?a?a(c):(0,t.jsx)(W,{status:c,variant:`grace`}):null:null;return(0,t.jsxs)(t.Fragment,{children:[d,n]})});G.displayName=`PaywallGate`;var K=()=>{let t=(0,e.useContext)(b);if(!t)throw Error(`[paywall] useLicenseStatus debe usarse dentro de <PaywallProvider>.`);return t.status};exports.PaywallGate=G,exports.PaywallProvider=C,exports.clearLicenseCache=m,exports.useLicenseStatus=K;
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("react"),t=require("react/jsx-runtime");var n=`/api/public/license/v1/status`,r=9e5,i=`cpl:state:`,a=1e4,o=1e3,s=3e4,c=()=>typeof window<`u`&&window.document!==void 0,l=new Map,u=e=>`${i}${e.slice(0,12)}`,d=e=>(e.storage??`local`)===`local`&&c(),f=e=>{if(typeof e!=`object`||!e)return!1;let t=e;return t.version!==1||typeof t.receivedAt!=`number`?!1:typeof t.payload?.status==`string`},p=(e,t,n)=>{if((n.storage??`local`)===`none`)return;let r={version:1,payload:t,receivedAt:Date.now()},i=u(e);if(l.set(i,r),d(n))try{window.localStorage.setItem(i,JSON.stringify(r))}catch{}},m=(e,t)=>{if((t.storage??`local`)===`none`)return null;let n=u(e),r=l.get(n)??null;if(!r&&d(t))try{let e=window.localStorage.getItem(n);if(e){let t=JSON.parse(e);f(t)&&(r=t)}}catch{}if(!r)return null;let i=t.maxCacheAgeMs??6048e5;return Date.now()-r.receivedAt>i?(h(e),null):r},h=e=>{let t=u(e);if(l.delete(t),c())try{window.localStorage.removeItem(t)}catch{}},g=1,_=e=>{if(typeof e!=`object`||!e)return!1;let t=e;return t.v===g&&typeof t.status==`string`&&typeof t.licenseId==`string`},v=async e=>{let{licenseKey:t}=e;if(!t)return y(e,Error(`[paywall] Falta licenseKey en la configuración.`));let r=e.fetchImpl??globalThis.fetch;if(typeof r!=`function`)return y(e,Error(`[paywall] No hay implementación de fetch disponible.`));let i=`${(e.apiUrl??`https://api.clients.ridel.dev`).replace(/\/+$/,``)}${n}?key=${encodeURIComponent(t)}&t=${Date.now()}`,o=new AbortController,s=setTimeout(()=>o.abort(),a);try{let n=await r(i,{method:`GET`,credentials:`omit`,signal:e.signal??o.signal}),a=await n.json();if(!n.ok){let t=a?.error??`HTTP ${n.status}`;return y(e,Error(`[paywall] El servidor rechazó la licencia: ${t}`))}return _(a)?(p(t,a,e),{payload:a,source:`network`,isStale:!1,error:null}):y(e,Error(`[paywall] Respuesta con un formato que esta versión del SDK no entiende. Actualiza el paquete.`))}catch(t){return y(e,b(t))}finally{clearTimeout(s)}},y=(e,t)=>{let n=e.licenseKey?m(e.licenseKey,e):null;return n?{payload:n.payload,source:`cache`,isStale:Date.parse(n.payload.expiresAt)<Date.now(),error:t}:{payload:null,source:`none`,isStale:!1,error:t}},b=e=>e instanceof Error?e:Error(`[paywall] Fallo al consultar la licencia: ${String(e)}`),x=(0,e.createContext)(null),S=e=>e?new Date(e):null,C=new Map,w=e=>{if(e.failures>0)return Math.min(s,o*2**Math.min(e.failures,5));let t=e.configuredMs??9e5;return e.serverHintSeconds?Math.min(t,e.serverHintSeconds*1e3):t},T=(0,e.memo)(({config:n,children:i})=>{let[a,o]=(0,e.useState)(()=>{let e=c()?m(n.licenseKey,n):null;return{payload:e?.payload??null,source:e?`cache`:`none`,isStale:e?Date.parse(e.payload.expiresAt)<Date.now():!1,isLoading:!0,error:null}}),s=(0,e.useRef)(0),l=(0,e.useRef)(null),u=(0,e.useRef)(r),d=(0,e.useRef)(n.onStatusChange);d.current=n.onStatusChange;let f=(0,e.useCallback)(async()=>{if(!c())return;l.current?.abort();let e=new AbortController;l.current=e;let t=`${n.apiUrl??``}|${n.licenseKey}`,r=C.get(t),i=r??v({licenseKey:n.licenseKey,apiUrl:n.apiUrl,storage:n.storage,maxCacheAgeMs:n.maxCacheAgeMs,fetchImpl:n.fetchImpl,signal:e.signal});r||C.set(t,i);try{let t=await i;if(e.signal.aborted)return;s.current=t.source===`network`?0:s.current+1,u.current=w({failures:s.current,serverHintSeconds:t.payload?.refreshAfterSeconds,configuredMs:n.refreshIntervalMs}),o({payload:t.payload,source:t.source,isStale:t.isStale,isLoading:!1,error:t.error}),n.debug&&console.info(`[paywall]`,t.source,t.payload?.status,t.error)}finally{r||C.delete(t)}},[n.apiUrl,n.licenseKey,n.storage,n.maxCacheAgeMs,n.fetchImpl,n.debug,n.refreshIntervalMs]);(0,e.useEffect)(()=>{if(!c())return;let e=!1,t,n=()=>{e||(t=setTimeout(()=>{f().then(n)},u.current))};return f().then(n),()=>{e=!0,t&&clearTimeout(t),l.current?.abort()}},[f]),(0,e.useEffect)(()=>{if(!c())return;let e=()=>{document.visibilityState===`visible`&&f()};return document.addEventListener(`visibilitychange`,e),window.addEventListener(`online`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`online`,e)}},[f]);let p=(0,e.useMemo)(()=>{let e=a.payload;return{state:e?.status??`OK`,reason:e?.reason??`NONE`,isBlocked:e?.status===`BLOCKED`,isLoading:a.isLoading,isStale:a.isStale,source:a.source,graceUntil:S(e?.graceUntil),nextTransitionAt:S(e?.nextTransitionAt),message:e?.message??null,contactUrl:e?.contactUrl??null,payload:e,error:a.error,refresh:()=>void f()}},[a,f]);(0,e.useEffect)(()=>{d.current?.(p)},[p]);let h=(0,e.useMemo)(()=>({status:p,config:n}),[p,n]);return(0,t.jsx)(x.Provider,{value:h,children:i})});T.displayName=`PaywallProvider`;var E=[`BLOCKED`],D={OK:`allow`,WARNING:`warn`,GRACE:`grace`,BLOCKED:`grace`},O=(e,t)=>{let n=D[e]??`allow`;return e===`OK`?`allow`:(t.blockOn??E).includes(e)?`block`:n},k=`system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif`,A={position:`fixed`,inset:0,zIndex:2147483647,display:`flex`,alignItems:`center`,justifyContent:`center`,padding:`24px`,background:`rgba(9, 9, 11, 0.92)`,backdropFilter:`blur(6px)`,fontFamily:k,color:`#fafafa`,overflowY:`auto`},j={width:`100%`,maxWidth:`440px`,background:`#18181b`,border:`1px solid #27272a`,borderRadius:`16px`,padding:`32px`,boxShadow:`0 24px 48px rgba(0, 0, 0, 0.45)`,textAlign:`center`},M={display:`inline-flex`,alignItems:`center`,justifyContent:`center`,width:`48px`,height:`48px`,borderRadius:`50%`,background:`rgba(239, 68, 68, 0.14)`,color:`#f87171`,fontSize:`24px`,marginBottom:`20px`},N={margin:`0 0 12px`,fontSize:`20px`,fontWeight:600,lineHeight:1.3},P={margin:`0 0 24px`,fontSize:`15px`,lineHeight:1.55,color:`#a1a1aa`},F={display:`inline-block`,padding:`11px 22px`,borderRadius:`10px`,background:`#fafafa`,color:`#18181b`,fontSize:`14px`,fontWeight:600,textDecoration:`none`},I={margin:`20px 0 0`,fontSize:`12px`,color:`#71717a`},L={position:`sticky`,top:0,zIndex:2147483e3,display:`flex`,alignItems:`center`,gap:`12px`,padding:`10px 16px`,fontFamily:k,fontSize:`14px`,lineHeight:1.4,boxSizing:`border-box`},R={...L,background:`#fef3c7`,color:`#78350f`,borderBottom:`1px solid #fcd34d`},z={...L,background:`#fee2e2`,color:`#7f1d1d`,borderBottom:`1px solid #fca5a5`},B={color:`inherit`,fontWeight:600,textDecoration:`underline`,whiteSpace:`nowrap`},V={marginLeft:`auto`,padding:`2px 8px`,border:`none`,borderRadius:`6px`,background:`transparent`,color:`inherit`,fontSize:`18px`,lineHeight:1,cursor:`pointer`},H={flex:1,minWidth:0},U=`Este servicio está temporalmente suspendido. Ponte en contacto con el proveedor para restablecerlo.`,W=(0,e.memo)(({status:n,config:r})=>{let i=(0,e.useMemo)(()=>r.productName?`${r.productName} no está disponible`:`Servicio no disponible`,[r.productName]);return(0,t.jsx)(`div`,{style:A,role:`alertdialog`,"aria-modal":`true`,children:(0,t.jsxs)(`div`,{style:j,children:[(0,t.jsx)(`div`,{style:M,"aria-hidden":`true`,children:`⚠`}),(0,t.jsx)(`h1`,{style:N,children:i}),(0,t.jsx)(`p`,{style:P,children:n.message??U}),n.contactUrl?(0,t.jsx)(`a`,{style:F,href:n.contactUrl,target:`_blank`,rel:`noreferrer noopener`,children:`Resolver ahora`}):null,r.contactEmail?(0,t.jsxs)(`p`,{style:I,children:[`¿Dudas? Escribe a`,` `,(0,t.jsx)(`a`,{href:`mailto:${r.contactEmail}`,style:B,children:r.contactEmail})]}):null]})})});W.displayName=`BlockedOverlay`;var G=e=>{if(!e)return null;let t=e.getTime()-Date.now();if(t<=0)return null;let n=Math.floor(t/864e5);if(n>=1)return n===1?`1 día`:`${n} días`;let r=Math.max(1,Math.floor(t/36e5));return r===1?`1 hora`:`${r} horas`},K=(0,e.memo)(({status:n,variant:r})=>{let[i,a]=(0,e.useState)(!1),o=(0,e.useMemo)(()=>G(n.graceUntil),[n.graceUntil]);if(i)return null;let s=r===`grace`?z:R;return(0,t.jsxs)(`div`,{style:s,role:`status`,children:[(0,t.jsxs)(`span`,{style:H,children:[n.message,o?(0,t.jsxs)(`strong`,{children:[` El servicio se suspenderá en `,o,`.`]}):null]}),n.contactUrl?(0,t.jsx)(`a`,{style:B,href:n.contactUrl,target:`_blank`,rel:`noreferrer noopener`,children:`Resolver`}):null,r===`warning`?(0,t.jsx)(`button`,{type:`button`,style:V,onClick:()=>a(!0),"aria-label":`Descartar aviso`,children:`×`}):null]})});K.displayName=`StatusBanner`;var q=(0,e.memo)(({children:n,renderBlocked:r,renderWarning:i,renderGrace:a,showBanners:o=!0})=>{let s=(0,e.useContext)(x);if(!s)throw Error(`[paywall] <PaywallGate> debe usarse dentro de <PaywallProvider>.`);let{status:c,config:l}=s,u=(0,e.useMemo)(()=>O(c.state,l),[c.state,l]);if(u===`block`)return(0,t.jsx)(t.Fragment,{children:r?r(c):(0,t.jsx)(W,{status:c,config:l})});let d=o?u===`warn`?i?i(c):(0,t.jsx)(K,{status:c,variant:`warning`}):u===`grace`?a?a(c):(0,t.jsx)(K,{status:c,variant:`grace`}):null:null;return(0,t.jsxs)(t.Fragment,{children:[d,n]})});q.displayName=`PaywallGate`;var J=()=>{let t=(0,e.useContext)(x);if(!t)throw Error(`[paywall] useLicenseStatus debe usarse dentro de <PaywallProvider>.`);return t.status};exports.PaywallGate=q,exports.PaywallProvider=T,exports.clearLicenseCache=h,exports.useLicenseStatus=J;
package/dist/index.js CHANGED
@@ -1,48 +1,48 @@
1
1
  "use client";
2
2
  import { createContext as e, memo as t, useCallback as n, useContext as r, useEffect as i, useMemo as a, useRef as o, useState as s } from "react";
3
3
  import { Fragment as c, jsx as l, jsxs as u } from "react/jsx-runtime";
4
- var d = "/api/public/license/v1/status", f = "cpl:state:", p = 1e4, m = 1e3, h = 3e4, g = () => typeof window < "u" && window.document !== void 0, _ = /* @__PURE__ */ new Map(), v = (e) => `${f}${e.slice(0, 12)}`, y = (e) => (e.storage ?? "local") === "local" && g(), b = (e) => {
4
+ var d = "/api/public/license/v1/status", f = 9e5, p = "cpl:state:", m = 1e4, h = 1e3, g = 3e4, _ = () => typeof window < "u" && window.document !== void 0, v = /* @__PURE__ */ new Map(), y = (e) => `${p}${e.slice(0, 12)}`, b = (e) => (e.storage ?? "local") === "local" && _(), x = (e) => {
5
5
  if (typeof e != "object" || !e) return !1;
6
6
  let t = e;
7
7
  return t.version !== 1 || typeof t.receivedAt != "number" ? !1 : typeof t.payload?.status == "string";
8
- }, x = (e, t, n) => {
8
+ }, S = (e, t, n) => {
9
9
  if ((n.storage ?? "local") === "none") return;
10
10
  let r = {
11
11
  version: 1,
12
12
  payload: t,
13
13
  receivedAt: Date.now()
14
- }, i = v(e);
15
- if (_.set(i, r), y(n)) try {
14
+ }, i = y(e);
15
+ if (v.set(i, r), b(n)) try {
16
16
  window.localStorage.setItem(i, JSON.stringify(r));
17
17
  } catch {}
18
- }, S = (e, t) => {
18
+ }, C = (e, t) => {
19
19
  if ((t.storage ?? "local") === "none") return null;
20
- let n = v(e), r = _.get(n) ?? null;
21
- if (!r && y(t)) try {
20
+ let n = y(e), r = v.get(n) ?? null;
21
+ if (!r && b(t)) try {
22
22
  let e = window.localStorage.getItem(n);
23
23
  if (e) {
24
24
  let t = JSON.parse(e);
25
- b(t) && (r = t);
25
+ x(t) && (r = t);
26
26
  }
27
27
  } catch {}
28
28
  if (!r) return null;
29
29
  let i = t.maxCacheAgeMs ?? 6048e5;
30
- return Date.now() - r.receivedAt > i ? (C(e), null) : r;
31
- }, C = (e) => {
32
- let t = v(e);
33
- if (_.delete(t), g()) try {
30
+ return Date.now() - r.receivedAt > i ? (w(e), null) : r;
31
+ }, w = (e) => {
32
+ let t = y(e);
33
+ if (v.delete(t), _()) try {
34
34
  window.localStorage.removeItem(t);
35
35
  } catch {}
36
- }, w = 1, ee = (e) => {
36
+ }, T = 1, E = (e) => {
37
37
  if (typeof e != "object" || !e) return !1;
38
38
  let t = e;
39
- return t.v === w && typeof t.status == "string" && typeof t.licenseId == "string";
40
- }, T = async (e) => {
39
+ return t.v === T && typeof t.status == "string" && typeof t.licenseId == "string";
40
+ }, D = async (e) => {
41
41
  let { licenseKey: t } = e;
42
- if (!t) return E(e, /* @__PURE__ */ Error("[paywall] Falta licenseKey en la configuración."));
42
+ if (!t) return O(e, /* @__PURE__ */ Error("[paywall] Falta licenseKey en la configuración."));
43
43
  let n = e.fetchImpl ?? globalThis.fetch;
44
- if (typeof n != "function") return E(e, /* @__PURE__ */ Error("[paywall] No hay implementación de fetch disponible."));
45
- let r = `${(e.apiUrl ?? "https://api.clients.ridel.dev").replace(/\/+$/, "")}${d}?key=${encodeURIComponent(t)}&t=${Date.now()}`, i = new AbortController(), a = setTimeout(() => i.abort(), p);
44
+ if (typeof n != "function") return O(e, /* @__PURE__ */ Error("[paywall] No hay implementación de fetch disponible."));
45
+ let r = `${(e.apiUrl ?? "https://api.clients.ridel.dev").replace(/\/+$/, "")}${d}?key=${encodeURIComponent(t)}&t=${Date.now()}`, i = new AbortController(), a = setTimeout(() => i.abort(), m);
46
46
  try {
47
47
  let a = await n(r, {
48
48
  method: "GET",
@@ -51,21 +51,21 @@ var d = "/api/public/license/v1/status", f = "cpl:state:", p = 1e4, m = 1e3, h =
51
51
  }), o = await a.json();
52
52
  if (!a.ok) {
53
53
  let t = o?.error ?? `HTTP ${a.status}`;
54
- return E(e, /* @__PURE__ */ Error(`[paywall] El servidor rechazó la licencia: ${t}`));
54
+ return O(e, /* @__PURE__ */ Error(`[paywall] El servidor rechazó la licencia: ${t}`));
55
55
  }
56
- return ee(o) ? (x(t, o, e), {
56
+ return E(o) ? (S(t, o, e), {
57
57
  payload: o,
58
58
  source: "network",
59
59
  isStale: !1,
60
60
  error: null
61
- }) : E(e, /* @__PURE__ */ Error("[paywall] Respuesta con un formato que esta versión del SDK no entiende. Actualiza el paquete."));
61
+ }) : O(e, /* @__PURE__ */ Error("[paywall] Respuesta con un formato que esta versión del SDK no entiende. Actualiza el paquete."));
62
62
  } catch (t) {
63
- return E(e, D(t));
63
+ return O(e, ee(t));
64
64
  } finally {
65
65
  clearTimeout(a);
66
66
  }
67
- }, E = (e, t) => {
68
- let n = e.licenseKey ? S(e.licenseKey, e) : null;
67
+ }, O = (e, t) => {
68
+ let n = e.licenseKey ? C(e.licenseKey, e) : null;
69
69
  return n ? {
70
70
  payload: n.payload,
71
71
  source: "cache",
@@ -77,9 +77,13 @@ var d = "/api/public/license/v1/status", f = "cpl:state:", p = 1e4, m = 1e3, h =
77
77
  isStale: !1,
78
78
  error: t
79
79
  };
80
- }, D = (e) => e instanceof Error ? e : /* @__PURE__ */ Error(`[paywall] Fallo al consultar la licencia: ${String(e)}`), O = e(null), k = (e) => e ? new Date(e) : null, A = /* @__PURE__ */ new Map(), j = t(({ config: e, children: t }) => {
80
+ }, ee = (e) => e instanceof Error ? e : /* @__PURE__ */ Error(`[paywall] Fallo al consultar la licencia: ${String(e)}`), k = e(null), A = (e) => e ? new Date(e) : null, j = /* @__PURE__ */ new Map(), M = (e) => {
81
+ if (e.failures > 0) return Math.min(g, h * 2 ** Math.min(e.failures, 5));
82
+ let t = e.configuredMs ?? 9e5;
83
+ return e.serverHintSeconds ? Math.min(t, e.serverHintSeconds * 1e3) : t;
84
+ }, N = t(({ config: e, children: t }) => {
81
85
  let [r, c] = s(() => {
82
- let t = g() ? S(e.licenseKey, e) : null;
86
+ let t = _() ? C(e.licenseKey, e) : null;
83
87
  return {
84
88
  payload: t?.payload ?? null,
85
89
  source: t ? "cache" : "none",
@@ -87,14 +91,14 @@ var d = "/api/public/license/v1/status", f = "cpl:state:", p = 1e4, m = 1e3, h =
87
91
  isLoading: !0,
88
92
  error: null
89
93
  };
90
- }), u = o(0), d = o(null), f = o(e.onStatusChange);
91
- f.current = e.onStatusChange;
92
- let p = n(async () => {
93
- if (!g()) return;
94
+ }), u = o(0), d = o(null), p = o(f), m = o(e.onStatusChange);
95
+ m.current = e.onStatusChange;
96
+ let h = n(async () => {
97
+ if (!_()) return;
94
98
  d.current?.abort();
95
99
  let t = new AbortController();
96
100
  d.current = t;
97
- let n = `${e.apiUrl ?? ""}|${e.licenseKey}`, r = A.get(n), i = r ?? T({
101
+ let n = `${e.apiUrl ?? ""}|${e.licenseKey}`, r = j.get(n), i = r ?? D({
98
102
  licenseKey: e.licenseKey,
99
103
  apiUrl: e.apiUrl,
100
104
  storage: e.storage,
@@ -102,11 +106,15 @@ var d = "/api/public/license/v1/status", f = "cpl:state:", p = 1e4, m = 1e3, h =
102
106
  fetchImpl: e.fetchImpl,
103
107
  signal: t.signal
104
108
  });
105
- r || A.set(n, i);
109
+ r || j.set(n, i);
106
110
  try {
107
111
  let n = await i;
108
112
  if (t.signal.aborted) return;
109
- u.current = n.source === "network" ? 0 : u.current + 1, c({
113
+ u.current = n.source === "network" ? 0 : u.current + 1, p.current = M({
114
+ failures: u.current,
115
+ serverHintSeconds: n.payload?.refreshAfterSeconds,
116
+ configuredMs: e.refreshIntervalMs
117
+ }), c({
110
118
  payload: n.payload,
111
119
  source: n.source,
112
120
  isStale: n.isStale,
@@ -114,7 +122,7 @@ var d = "/api/public/license/v1/status", f = "cpl:state:", p = 1e4, m = 1e3, h =
114
122
  error: n.error
115
123
  }), e.debug && console.info("[paywall]", n.source, n.payload?.status, n.error);
116
124
  } finally {
117
- r || A.delete(n);
125
+ r || j.delete(n);
118
126
  }
119
127
  }, [
120
128
  e.apiUrl,
@@ -122,29 +130,29 @@ var d = "/api/public/license/v1/status", f = "cpl:state:", p = 1e4, m = 1e3, h =
122
130
  e.storage,
123
131
  e.maxCacheAgeMs,
124
132
  e.fetchImpl,
125
- e.debug
133
+ e.debug,
134
+ e.refreshIntervalMs
126
135
  ]);
127
136
  i(() => {
128
- if (!g()) return;
129
- p();
130
- let t = r.payload?.refreshAfterSeconds, n = e.refreshIntervalMs ?? 9e5, i = Math.min(n, t ? t * 1e3 : n), a = u.current > 0 ? Math.min(h, m * 2 ** Math.min(u.current, 5)) : i, o = setInterval(() => void p(), a);
131
- return () => {
132
- clearInterval(o), d.current?.abort();
137
+ if (!_()) return;
138
+ let e = !1, t, n = () => {
139
+ e || (t = setTimeout(() => {
140
+ h().then(n);
141
+ }, p.current));
133
142
  };
134
- }, [
135
- p,
136
- e.refreshIntervalMs,
137
- r.payload
138
- ]), i(() => {
139
- if (!g()) return;
143
+ return h().then(n), () => {
144
+ e = !0, t && clearTimeout(t), d.current?.abort();
145
+ };
146
+ }, [h]), i(() => {
147
+ if (!_()) return;
140
148
  let e = () => {
141
- document.visibilityState === "visible" && p();
149
+ document.visibilityState === "visible" && h();
142
150
  };
143
151
  return document.addEventListener("visibilitychange", e), window.addEventListener("online", e), () => {
144
152
  document.removeEventListener("visibilitychange", e), window.removeEventListener("online", e);
145
153
  };
146
- }, [p]);
147
- let _ = a(() => {
154
+ }, [h]);
155
+ let g = a(() => {
148
156
  let e = r.payload;
149
157
  return {
150
158
  state: e?.status ?? "OK",
@@ -153,39 +161,39 @@ var d = "/api/public/license/v1/status", f = "cpl:state:", p = 1e4, m = 1e3, h =
153
161
  isLoading: r.isLoading,
154
162
  isStale: r.isStale,
155
163
  source: r.source,
156
- graceUntil: k(e?.graceUntil),
157
- nextTransitionAt: k(e?.nextTransitionAt),
164
+ graceUntil: A(e?.graceUntil),
165
+ nextTransitionAt: A(e?.nextTransitionAt),
158
166
  message: e?.message ?? null,
159
167
  contactUrl: e?.contactUrl ?? null,
160
168
  payload: e,
161
169
  error: r.error,
162
- refresh: () => void p()
170
+ refresh: () => void h()
163
171
  };
164
- }, [r, p]);
172
+ }, [r, h]);
165
173
  i(() => {
166
- f.current?.(_);
167
- }, [_]);
174
+ m.current?.(g);
175
+ }, [g]);
168
176
  let v = a(() => ({
169
- status: _,
177
+ status: g,
170
178
  config: e
171
- }), [_, e]);
172
- return /* @__PURE__ */ l(O.Provider, {
179
+ }), [g, e]);
180
+ return /* @__PURE__ */ l(k.Provider, {
173
181
  value: v,
174
182
  children: t
175
183
  });
176
184
  });
177
- j.displayName = "PaywallProvider";
185
+ N.displayName = "PaywallProvider";
178
186
  //#endregion
179
187
  //#region src/core/resolveGateDecision.ts
180
- var M = ["BLOCKED"], N = {
188
+ var te = ["BLOCKED"], P = {
181
189
  OK: "allow",
182
190
  WARNING: "warn",
183
191
  GRACE: "grace",
184
192
  BLOCKED: "grace"
185
- }, P = (e, t) => {
186
- let n = N[e] ?? "allow";
187
- return e === "OK" ? "allow" : (t.blockOn ?? M).includes(e) ? "block" : n;
188
- }, F = "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif", I = {
193
+ }, F = (e, t) => {
194
+ let n = P[e] ?? "allow";
195
+ return e === "OK" ? "allow" : (t.blockOn ?? te).includes(e) ? "block" : n;
196
+ }, I = "system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif", L = {
189
197
  position: "fixed",
190
198
  inset: 0,
191
199
  zIndex: 2147483647,
@@ -195,10 +203,10 @@ var M = ["BLOCKED"], N = {
195
203
  padding: "24px",
196
204
  background: "rgba(9, 9, 11, 0.92)",
197
205
  backdropFilter: "blur(6px)",
198
- fontFamily: F,
206
+ fontFamily: I,
199
207
  color: "#fafafa",
200
208
  overflowY: "auto"
201
- }, L = {
209
+ }, R = {
202
210
  width: "100%",
203
211
  maxWidth: "440px",
204
212
  background: "#18181b",
@@ -207,7 +215,7 @@ var M = ["BLOCKED"], N = {
207
215
  padding: "32px",
208
216
  boxShadow: "0 24px 48px rgba(0, 0, 0, 0.45)",
209
217
  textAlign: "center"
210
- }, R = {
218
+ }, z = {
211
219
  display: "inline-flex",
212
220
  alignItems: "center",
213
221
  justifyContent: "center",
@@ -218,17 +226,17 @@ var M = ["BLOCKED"], N = {
218
226
  color: "#f87171",
219
227
  fontSize: "24px",
220
228
  marginBottom: "20px"
221
- }, z = {
229
+ }, B = {
222
230
  margin: "0 0 12px",
223
231
  fontSize: "20px",
224
232
  fontWeight: 600,
225
233
  lineHeight: 1.3
226
- }, B = {
234
+ }, V = {
227
235
  margin: "0 0 24px",
228
236
  fontSize: "15px",
229
237
  lineHeight: 1.55,
230
238
  color: "#a1a1aa"
231
- }, V = {
239
+ }, H = {
232
240
  display: "inline-block",
233
241
  padding: "11px 22px",
234
242
  borderRadius: "10px",
@@ -237,11 +245,11 @@ var M = ["BLOCKED"], N = {
237
245
  fontSize: "14px",
238
246
  fontWeight: 600,
239
247
  textDecoration: "none"
240
- }, H = {
248
+ }, U = {
241
249
  margin: "20px 0 0",
242
250
  fontSize: "12px",
243
251
  color: "#71717a"
244
- }, U = {
252
+ }, W = {
245
253
  position: "sticky",
246
254
  top: 0,
247
255
  zIndex: 2147483e3,
@@ -249,26 +257,26 @@ var M = ["BLOCKED"], N = {
249
257
  alignItems: "center",
250
258
  gap: "12px",
251
259
  padding: "10px 16px",
252
- fontFamily: F,
260
+ fontFamily: I,
253
261
  fontSize: "14px",
254
262
  lineHeight: 1.4,
255
263
  boxSizing: "border-box"
256
- }, W = {
257
- ...U,
264
+ }, G = {
265
+ ...W,
258
266
  background: "#fef3c7",
259
267
  color: "#78350f",
260
268
  borderBottom: "1px solid #fcd34d"
261
- }, G = {
262
- ...U,
269
+ }, K = {
270
+ ...W,
263
271
  background: "#fee2e2",
264
272
  color: "#7f1d1d",
265
273
  borderBottom: "1px solid #fca5a5"
266
- }, K = {
274
+ }, q = {
267
275
  color: "inherit",
268
276
  fontWeight: 600,
269
277
  textDecoration: "underline",
270
278
  whiteSpace: "nowrap"
271
- }, q = {
279
+ }, J = {
272
280
  marginLeft: "auto",
273
281
  padding: "2px 8px",
274
282
  border: "none",
@@ -278,46 +286,46 @@ var M = ["BLOCKED"], N = {
278
286
  fontSize: "18px",
279
287
  lineHeight: 1,
280
288
  cursor: "pointer"
281
- }, J = {
289
+ }, Y = {
282
290
  flex: 1,
283
291
  minWidth: 0
284
- }, Y = "Este servicio está temporalmente suspendido. Ponte en contacto con el proveedor para restablecerlo.", X = t(({ status: e, config: t }) => {
292
+ }, X = "Este servicio está temporalmente suspendido. Ponte en contacto con el proveedor para restablecerlo.", Z = t(({ status: e, config: t }) => {
285
293
  let n = a(() => t.productName ? `${t.productName} no está disponible` : "Servicio no disponible", [t.productName]);
286
294
  return /* @__PURE__ */ l("div", {
287
- style: I,
295
+ style: L,
288
296
  role: "alertdialog",
289
297
  "aria-modal": "true",
290
298
  children: /* @__PURE__ */ u("div", {
291
- style: L,
299
+ style: R,
292
300
  children: [
293
301
  /* @__PURE__ */ l("div", {
294
- style: R,
302
+ style: z,
295
303
  "aria-hidden": "true",
296
304
  children: "⚠"
297
305
  }),
298
306
  /* @__PURE__ */ l("h1", {
299
- style: z,
307
+ style: B,
300
308
  children: n
301
309
  }),
302
310
  /* @__PURE__ */ l("p", {
303
- style: B,
304
- children: e.message ?? Y
311
+ style: V,
312
+ children: e.message ?? X
305
313
  }),
306
314
  e.contactUrl ? /* @__PURE__ */ l("a", {
307
- style: V,
315
+ style: H,
308
316
  href: e.contactUrl,
309
317
  target: "_blank",
310
318
  rel: "noreferrer noopener",
311
319
  children: "Resolver ahora"
312
320
  }) : null,
313
321
  t.contactEmail ? /* @__PURE__ */ u("p", {
314
- style: H,
322
+ style: U,
315
323
  children: [
316
324
  "¿Dudas? Escribe a",
317
325
  " ",
318
326
  /* @__PURE__ */ l("a", {
319
327
  href: `mailto:${t.contactEmail}`,
320
- style: K,
328
+ style: q,
321
329
  children: t.contactEmail
322
330
  })
323
331
  ]
@@ -326,10 +334,10 @@ var M = ["BLOCKED"], N = {
326
334
  })
327
335
  });
328
336
  });
329
- X.displayName = "BlockedOverlay";
337
+ Z.displayName = "BlockedOverlay";
330
338
  //#endregion
331
339
  //#region src/react/ui/StatusBanner.tsx
332
- var Z = (e) => {
340
+ var ne = (e) => {
333
341
  if (!e) return null;
334
342
  let t = e.getTime() - Date.now();
335
343
  if (t <= 0) return null;
@@ -338,13 +346,13 @@ var Z = (e) => {
338
346
  let r = Math.max(1, Math.floor(t / 36e5));
339
347
  return r === 1 ? "1 hora" : `${r} horas`;
340
348
  }, Q = t(({ status: e, variant: t }) => {
341
- let [n, r] = s(!1), i = a(() => Z(e.graceUntil), [e.graceUntil]);
349
+ let [n, r] = s(!1), i = a(() => ne(e.graceUntil), [e.graceUntil]);
342
350
  return n ? null : /* @__PURE__ */ u("div", {
343
- style: t === "grace" ? G : W,
351
+ style: t === "grace" ? K : G,
344
352
  role: "status",
345
353
  children: [
346
354
  /* @__PURE__ */ u("span", {
347
- style: J,
355
+ style: Y,
348
356
  children: [e.message, i ? /* @__PURE__ */ u("strong", { children: [
349
357
  " El servicio se suspenderá en ",
350
358
  i,
@@ -352,7 +360,7 @@ var Z = (e) => {
352
360
  ] }) : null]
353
361
  }),
354
362
  e.contactUrl ? /* @__PURE__ */ l("a", {
355
- style: K,
363
+ style: q,
356
364
  href: e.contactUrl,
357
365
  target: "_blank",
358
366
  rel: "noreferrer noopener",
@@ -360,7 +368,7 @@ var Z = (e) => {
360
368
  }) : null,
361
369
  t === "warning" ? /* @__PURE__ */ l("button", {
362
370
  type: "button",
363
- style: q,
371
+ style: J,
364
372
  onClick: () => r(!0),
365
373
  "aria-label": "Descartar aviso",
366
374
  children: "×"
@@ -372,10 +380,10 @@ Q.displayName = "StatusBanner";
372
380
  //#endregion
373
381
  //#region src/react/PaywallGate.tsx
374
382
  var $ = t(({ children: e, renderBlocked: t, renderWarning: n, renderGrace: i, showBanners: o = !0 }) => {
375
- let s = r(O);
383
+ let s = r(k);
376
384
  if (!s) throw Error("[paywall] <PaywallGate> debe usarse dentro de <PaywallProvider>.");
377
- let { status: d, config: f } = s, p = a(() => P(d.state, f), [d.state, f]);
378
- if (p === "block") return /* @__PURE__ */ l(c, { children: t ? t(d) : /* @__PURE__ */ l(X, {
385
+ let { status: d, config: f } = s, p = a(() => F(d.state, f), [d.state, f]);
386
+ if (p === "block") return /* @__PURE__ */ l(c, { children: t ? t(d) : /* @__PURE__ */ l(Z, {
379
387
  status: d,
380
388
  config: f
381
389
  }) });
@@ -391,10 +399,10 @@ var $ = t(({ children: e, renderBlocked: t, renderWarning: n, renderGrace: i, sh
391
399
  $.displayName = "PaywallGate";
392
400
  //#endregion
393
401
  //#region src/react/useLicenseStatus.ts
394
- var te = () => {
395
- let e = r(O);
402
+ var re = () => {
403
+ let e = r(k);
396
404
  if (!e) throw Error("[paywall] useLicenseStatus debe usarse dentro de <PaywallProvider>.");
397
405
  return e.status;
398
406
  };
399
407
  //#endregion
400
- export { $ as PaywallGate, j as PaywallProvider, C as clearLicenseCache, te as useLicenseStatus };
408
+ export { $ as PaywallGate, N as PaywallProvider, w as clearLicenseCache, re as useLicenseStatus };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmo-frameworks/paywall-react",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Bloqueo remoto de aplicaciones React por estado de pago.",
5
5
  "type": "module",
6
6
  "sideEffects": false,