@crosspay-lb/js 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/README.md CHANGED
@@ -17,7 +17,20 @@ const fields = await cp.card.mount({ container: '#card', clientSecret })
17
17
  const result = await fields.pay()
18
18
  ```
19
19
 
20
- O por CDN: `<script src="https://cdn.jsdelivr.net/npm/@crosspay-lb/js@0.2/dist/crosspay.min.js"></script>` → `window.Crosspay`.
20
+ Si la orden se crea recién al pagar, monta el formulario antes con el monto y la
21
+ moneda, y pasa la sesión en `pay` (desde 0.4.0, solo cobro único):
22
+
23
+ ```ts
24
+ const fields = await cp.card.mountDeferred({ container: '#card', amount: 50000, currency: 'COP' })
25
+ // …el pagador llena la tarjeta y le da a pagar:
26
+ const { clientSecret } = await crearOrdenEnTuServidor()
27
+ const result = await fields.pay({ clientSecret })
28
+ ```
29
+
30
+ Si la sesión no es de ese monto y moneda, `pay` rechaza con `AMOUNT_MISMATCH`
31
+ sin tocar la tarjeta: cuando el total cambie, `destroy()` y vuelve a montar.
32
+
33
+ O por CDN: `<script src="https://cdn.jsdelivr.net/npm/@crosspay-lb/js@0.4/dist/crosspay.min.js"></script>` → `window.Crosspay`.
21
34
 
22
35
  Requisitos: llave pública del comercio, sitio en sus **dominios autorizados** y
23
36
  una sesión de pago creada en el servidor con la llave secreta.
@@ -1 +1 @@
1
- "use strict";var Crosspay=(()=>{var v=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var H=Object.prototype.hasOwnProperty;var z=(e,t)=>{for(var n in t)v(e,n,{get:t[n],enumerable:!0})},K=(e,t,n,p)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of N(t))!H.call(e,r)&&r!==n&&v(e,r,{get:()=>t[r],enumerable:!(p=q(t,r))||p.enumerable});return e};var Y=e=>K(v({},"__esModule",{value:!0}),e);var ee={};z(ee,{API_BASE_URLS:()=>f,CrosspayError:()=>a,init:()=>b,version:()=>$});var a=class extends Error{constructor(n,p,r){super(n);this.code=p;this.details=r;this.name="CrosspayError"}};var w="crosspay-fields/2";function I(e,t){return typeof e=="object"&&e!==null&&e.protocol===w&&e.channel===t&&typeof e.kind=="string"}function T(e){return new URLSearchParams({channel:e.channel,origin:e.parentOrigin}).toString()}var V=3e4,W={position:"fixed",inset:"0",width:"100%",height:"100%",zIndex:"2147483647"};function O(e,t,n){let p=typeof n.container=="string"?document.querySelector(n.container):n.container;if(!p)return Promise.reject(new a(`No existe el contenedor ${String(n.container)}.`,"INVALID_CONTAINER"));let r=new URL(e).origin,o=R(),i=document.createElement("div");i.style.position="relative";let s=document.createElement("iframe");s.src=`${e}#${T({channel:o,parentOrigin:window.location.origin})}`,s.title="Formulario seguro de tarjeta",s.setAttribute("scrolling","no"),s.setAttribute("allow","payment"),Object.assign(s.style,{display:"block",width:"100%",height:"0px",border:"0",background:"transparent",colorScheme:"normal"}),i.appendChild(s),p.replaceChildren(i);let l=0,d=new Map,u=m=>{s.contentWindow?.postMessage({...m,protocol:w,channel:o},r)},D=m=>{m?(i.style.height=`${l}px`,Object.assign(s.style,W)):(i.style.height="",Object.assign(s.style,{position:"",inset:"",width:"100%",height:`${l}px`,zIndex:""}))},h=!1,x=()=>{if(!h){h=!0,window.removeEventListener("message",k);for(let m of d.values())m.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));d.clear(),i.remove()}},y=null;function k(m){if(m.source!==s.contentWindow||m.origin!==r||!I(m.data,o))return;let c=m.data;switch(c.kind){case"ready":u({kind:"init",options:{publishableKey:t,clientSecret:n.clientSecret,installments:n.installments,labels:n.labels,styles:n.styles}});break;case"mounted":y?.(c.session);break;case"mount-error":y?.(new a(c.message,c.code));break;case"resize":l=Math.max(0,Math.ceil(c.height)),s.style.position!=="fixed"?s.style.height=`${l}px`:i.style.height=`${l}px`;break;case"validity":n.onValidityChange?.(c.valid);break;case"overlay":D(c.active);break;case"paid":{let g=d.get(c.requestId);d.delete(c.requestId),g?.resolve(c.result);break}case"pay-error":{let g=d.get(c.requestId);d.delete(c.requestId),g?.reject(new a(c.message,c.code));break}}}return window.addEventListener("message",k),new Promise((m,c)=>{let g=setTimeout(()=>{y?.(new a("No se pudo cargar el formulario de tarjeta.","FIELDS_TIMEOUT"))},V);y=S=>{if(y=null,clearTimeout(g),S instanceof a){x(),c(S);return}m({session:S,pay(){if(h)return Promise.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));let P=R();return new Promise((j,B)=>{d.set(P,{resolve:j,reject:B}),u({kind:"pay",requestId:P})})},destroy:x})}})}function R(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`}var f={development:"https://api-dev.crosspaysolutions.financial",production:"https://api.crosspaysolutions.financial"};function F(e){let t=f[e];if(!t)throw new TypeError(`Ambiente de Crosspay no valido: "${String(e)}". Usa "development" o "production".`);return t}var C={development:"https://fields-dev.crosspaysolutions.financial/",production:"https://fields.crosspaysolutions.financial/"};function U(e){let t=(r,o)=>(e.fetch??globalThis.fetch)(r,o);async function n(r,o,i){let s={Accept:"application/json"};i!==void 0&&(s["Content-Type"]="application/json"),e.locale&&(s["Accept-Language"]=e.locale);let l;try{l=await t(`${e.baseUrl}${o}`,{method:r,headers:s,body:i===void 0?void 0:JSON.stringify(i),credentials:"omit"})}catch(u){throw new a("No se pudo conectar con Crosspay.","NETWORK_ERROR",u)}let d=await l.json().catch(()=>null);if(!l.ok||d?.success===!1){let u=d?.message||d?.error||`Crosspay respondio ${l.status}.`;throw new a(u,`HTTP_${l.status}`,d)}return d}async function p(r,o,i){let s=await n(r,o,i);return s&&typeof s=="object"&&"data"in s?s.data:s}return{get:r=>p("GET",r),post:(r,o)=>p("POST",r,o),postRaw:(r,o)=>n("POST",r,o)}}var _="cp_device_id";function G(){try{let e=localStorage.getItem(_);return e||(e=typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`,localStorage.setItem(_,e)),e}catch{return""}}function J(){return typeof navigator>"u"?"":[navigator.userAgent,navigator.language,typeof screen<"u"?`${screen.width}x${screen.height}`:"",E()].join("|")}function Q(e){let t=5381;for(let n=0;n<e.length;n+=1)t=(t<<5)+t+e.charCodeAt(n)|0;return(t>>>0).toString(16)}function E(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone||""}catch{return""}}function L(){let e=G(),t=Q(J());return e?`${e}.${t}`:t}function X(){let e=typeof navigator<"u"?navigator.language?.split("-")[0]:void 0;return{fingerprint:L(),timezone:E(),...e?{language:e}:{}}}function M(e){return{status(t){return e.get(`/payments/status/${encodeURIComponent(t)}`)}}}function A(e,t){return{async listBanks(n="COP"){return(await e.get(`/payments/pse/banks?currency=${encodeURIComponent(n)}`)??[]).filter(r=>{let o=String(r.code??"").trim(),i=String(r.name??"").normalize("NFD").replace(/\p{Diacritic}/gu,"").toLowerCase();return o!==""&&o!=="0"&&!i.includes("seleccione su banco")})},async pay(n){let{clientSecret:p,...r}=n,o=await e.postRaw("/payments/sessions/pay",{publishableKey:t,clientSecret:p,parentOrigin:window.location.origin,method:"pse",pse:r,meta:X()}),{data:i,...s}=o??{},l=i?.sessionId;return{...s,...l?{sessionId:l}:{}}}}}var Z={development:"pk_test_",production:"pk_live_"};function b(e){let t=F(e.environment),n=String(e.publishableKey??"").trim(),p=Z[e.environment];if(!n.startsWith(p))throw new TypeError(`\`publishableKey\` debe empezar por "${p}" en el ambiente "${e.environment}".`);if(e.fieldsUrl&&e.environment!=="development")throw new TypeError('`fieldsUrl` solo se admite en el ambiente "development".');let r=e.fieldsUrl??C[e.environment],o=U({baseUrl:t,locale:e.locale,fetch:e.fetch});return{environment:e.environment,card:{async mount(i){if(!String(i.clientSecret??"").trim())throw new a("Falta `clientSecret`: crea la sesion de pago en tu servidor con @crosspay-lb/node.","INVALID_REQUEST");return O(r,n,i)}},payments:M(o),pse:A(o,n)}}var $="0.2.0";return Y(ee);})();
1
+ "use strict";var Crosspay=(()=>{var v=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var z=Object.prototype.hasOwnProperty;var V=(e,t)=>{for(var n in t)v(e,n,{get:t[n],enumerable:!0})},K=(e,t,n,d)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of H(t))!z.call(e,s)&&s!==n&&v(e,s,{get:()=>t[s],enumerable:!(d=q(t,s))||d.enumerable});return e};var Y=e=>K(v({},"__esModule",{value:!0}),e);var ne={};V(ne,{API_BASE_URLS:()=>S,CrosspayError:()=>i,init:()=>P,version:()=>j});var i=class extends Error{constructor(n,d,s){super(n);this.code=d;this.details=s;this.name="CrosspayError"}};var C="crosspay-fields/2";function R(e,t){return typeof e=="object"&&e!==null&&e.protocol===C&&e.channel===t&&typeof e.kind=="string"}function k(e){return new URLSearchParams({channel:e.channel,origin:e.parentOrigin}).toString()}var Q=3e4,W={position:"fixed",inset:"0",width:"100%",height:"100%",zIndex:"2147483647"};function b(e,t,n){let d=typeof n.container=="string"?document.querySelector(n.container):n.container;if(!d)return Promise.reject(new i(`No existe el contenedor ${String(n.container)}.`,"INVALID_CONTAINER"));let s=new URL(e).origin,a=D(),o=document.createElement("div");o.style.position="relative";let r=document.createElement("iframe");r.src=`${e}#${k({channel:a,parentOrigin:window.location.origin})}`,r.title="Formulario seguro de tarjeta",r.setAttribute("scrolling","no"),r.setAttribute("allow","payment"),Object.assign(r.style,{display:"block",width:"100%",height:"0px",border:"0",background:"transparent",colorScheme:"normal"}),o.appendChild(r),d.replaceChildren(o);let c=0,p=new Map,m=u=>{r.contentWindow?.postMessage({...u,protocol:C,channel:a},s)},f=u=>{u?(o.style.height=`${c}px`,Object.assign(r.style,W)):(o.style.height="",Object.assign(r.style,{position:"",inset:"",width:"100%",height:`${c}px`,zIndex:""}))},h=!1,x=()=>{if(!h){h=!0,window.removeEventListener("message",O);for(let u of p.values())u.reject(new i("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));p.clear(),o.remove()}},y=null;function O(u){if(u.source!==r.contentWindow||u.origin!==s||!R(u.data,a))return;let l=u.data;switch(l.kind){case"ready":m({kind:"init",options:{publishableKey:t,clientSecret:n.clientSecret,amount:n.amount,currency:n.currency,installments:n.installments,labels:n.labels,styles:n.styles}});break;case"mounted":y?.({session:l.session});break;case"mount-error":y?.(new i(l.message,l.code));break;case"resize":c=Math.max(0,Math.ceil(l.height)),r.style.position!=="fixed"?r.style.height=`${c}px`:o.style.height=`${c}px`;break;case"validity":n.onValidityChange?.(l.valid);break;case"overlay":f(l.active);break;case"paid":{let g=p.get(l.requestId);p.delete(l.requestId),g?.resolve(l.result);break}case"pay-error":{let g=p.get(l.requestId);p.delete(l.requestId),g?.reject(new i(l.message,l.code));break}}}return window.addEventListener("message",O),new Promise((u,l)=>{let g=setTimeout(()=>{y?.(new i("No se pudo cargar el formulario de tarjeta.","FIELDS_TIMEOUT"))},Q);y=w=>{if(y=null,clearTimeout(g),w instanceof i){x(),l(w);return}u({session:w.session,pay(F){if(h)return Promise.reject(new i("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));let T=D();return new Promise((N,B)=>{p.set(T,{resolve:N,reject:B}),m({kind:"pay",requestId:T,...F?{clientSecret:F}:{}})})},destroy:x})}})}function D(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`}var S={development:"https://api-dev.crosspaysolutions.financial",production:"https://api.crosspaysolutions.financial"};function U(e){let t=S[e];if(!t)throw new TypeError(`Ambiente de Crosspay no valido: "${String(e)}". Usa "development" o "production".`);return t}var E={development:"https://fields-dev.crosspaysolutions.financial/",production:"https://fields.crosspaysolutions.financial/"};function _(e){let t=(s,a)=>(e.fetch??globalThis.fetch)(s,a);async function n(s,a,o){let r={Accept:"application/json"};o!==void 0&&(r["Content-Type"]="application/json"),e.locale&&(r["Accept-Language"]=e.locale);let c;try{c=await t(`${e.baseUrl}${a}`,{method:s,headers:r,body:o===void 0?void 0:JSON.stringify(o),credentials:"omit"})}catch(m){throw new i("No se pudo conectar con Crosspay.","NETWORK_ERROR",m)}let p=await c.json().catch(()=>null);if(!c.ok||p?.success===!1){let m=p?.message||p?.error||`Crosspay respondio ${c.status}.`;throw new i(m,`HTTP_${c.status}`,p)}return p}async function d(s,a,o){let r=await n(s,a,o);return r&&typeof r=="object"&&"data"in r?r.data:r}return{get:s=>d("GET",s),post:(s,a)=>d("POST",s,a),postRaw:(s,a)=>n("POST",s,a)}}var L="cp_device_id";function G(){try{let e=localStorage.getItem(L);return e||(e=typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`,localStorage.setItem(L,e)),e}catch{return""}}function Z(){return typeof navigator>"u"?"":[navigator.userAgent,navigator.language,typeof screen<"u"?`${screen.width}x${screen.height}`:"",I()].join("|")}function J(e){let t=5381;for(let n=0;n<e.length;n+=1)t=(t<<5)+t+e.charCodeAt(n)|0;return(t>>>0).toString(16)}function I(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone||""}catch{return""}}function M(){let e=G(),t=J(Z());return e?`${e}.${t}`:t}function X(){let e=typeof navigator<"u"?navigator.language?.split("-")[0]:void 0;return{fingerprint:M(),timezone:I(),...e?{language:e}:{}}}function A(e){return{status(t){return e.get(`/payments/status/${encodeURIComponent(t)}`)}}}function $(e,t){return{async listBanks(n="COP"){return(await e.get(`/payments/pse/banks?currency=${encodeURIComponent(n)}`)??[]).filter(s=>{let a=String(s.code??"").trim(),o=String(s.name??"").normalize("NFD").replace(/\p{Diacritic}/gu,"").toLowerCase();return a!==""&&a!=="0"&&!o.includes("seleccione su banco")})},async pay(n){let{clientSecret:d,...s}=n,a=await e.postRaw("/payments/sessions/pay",{publishableKey:t,clientSecret:d,parentOrigin:window.location.origin,method:"pse",pse:s,meta:X()}),{data:o,...r}=a??{},c=o?.sessionId;return{...r,...c?{sessionId:c}:{}}}}}var ee={development:"pk_test_",production:"pk_live_"};function P(e){let t=U(e.environment),n=String(e.publishableKey??"").trim(),d=ee[e.environment];if(!n.startsWith(d))throw new TypeError(`\`publishableKey\` debe empezar por "${d}" en el ambiente "${e.environment}".`);if(e.fieldsUrl&&e.environment!=="development")throw new TypeError('`fieldsUrl` solo se admite en el ambiente "development".');let s=e.fieldsUrl??E[e.environment],a=_({baseUrl:t,locale:e.locale,fetch:e.fetch});return{environment:e.environment,card:{async mount(o){if(!String(o.clientSecret??"").trim())throw new i("Falta `clientSecret`: crea la sesion de pago en tu servidor con @crosspay-lb/node.","INVALID_REQUEST");let r=await b(s,n,o);return{session:r.session,pay:()=>r.pay(),destroy:r.destroy}},async mountDeferred(o){let{amount:r,currency:c}=te(o),p=await b(s,n,{...o,amount:r,currency:c});return{amount:r,currency:c,pay(m){let f=String(m?.clientSecret??"").trim();return f?p.pay(f):Promise.reject(new i("Falta `clientSecret`: crea la sesion de pago en tu servidor antes de pagar.","INVALID_REQUEST"))},destroy:p.destroy}}},payments:A(a),pse:$(a,n)}}function te(e){if("clientSecret"in e)throw new i("`mountDeferred` no recibe `clientSecret`: pasalo en `pay()`, o usa `mount` si ya tienes la sesion.","INVALID_REQUEST");let t=Number(e.amount);if(!Number.isFinite(t)||t<=0)throw new i("`amount` debe ser un numero mayor que cero.","INVALID_REQUEST");let n=String(e.currency??"").trim().toUpperCase();if(!/^[A-Z]{3}$/.test(n))throw new i('`currency` debe ser un codigo ISO 4217, p. ej. "COP".',"INVALID_REQUEST");return{amount:t,currency:n}}var j="0.4.0";return Y(ne);})();
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var S=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var H=(e,t)=>{for(var n in t)S(e,n,{get:t[n],enumerable:!0})},z=(e,t,n,p)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of q(t))!N.call(e,r)&&r!==n&&S(e,r,{get:()=>t[r],enumerable:!(p=B(t,r))||p.enumerable});return e};var K=e=>z(S({},"__esModule",{value:!0}),e);var ee={};H(ee,{API_BASE_URLS:()=>C,CrosspayError:()=>a,FIELDS_URLS:()=>f,init:()=>$,version:()=>Z});module.exports=K(ee);var a=class extends Error{constructor(n,p,r){super(n);this.code=p;this.details=r;this.name="CrosspayError"}};var w="crosspay-fields/2";function P(e,t){return typeof e=="object"&&e!==null&&e.protocol===w&&e.channel===t&&typeof e.kind=="string"}function T(e){return new URLSearchParams({channel:e.channel,origin:e.parentOrigin}).toString()}var Y=3e4,V={position:"fixed",inset:"0",width:"100%",height:"100%",zIndex:"2147483647"};function R(e,t,n){let p=typeof n.container=="string"?document.querySelector(n.container):n.container;if(!p)return Promise.reject(new a(`No existe el contenedor ${String(n.container)}.`,"INVALID_CONTAINER"));let r=new URL(e).origin,o=I(),i=document.createElement("div");i.style.position="relative";let s=document.createElement("iframe");s.src=`${e}#${T({channel:o,parentOrigin:window.location.origin})}`,s.title="Formulario seguro de tarjeta",s.setAttribute("scrolling","no"),s.setAttribute("allow","payment"),Object.assign(s.style,{display:"block",width:"100%",height:"0px",border:"0",background:"transparent",colorScheme:"normal"}),i.appendChild(s),p.replaceChildren(i);let l=0,d=new Map,u=m=>{s.contentWindow?.postMessage({...m,protocol:w,channel:o},r)},A=m=>{m?(i.style.height=`${l}px`,Object.assign(s.style,V)):(i.style.height="",Object.assign(s.style,{position:"",inset:"",width:"100%",height:`${l}px`,zIndex:""}))},h=!1,b=()=>{if(!h){h=!0,window.removeEventListener("message",x);for(let m of d.values())m.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));d.clear(),i.remove()}},y=null;function x(m){if(m.source!==s.contentWindow||m.origin!==r||!P(m.data,o))return;let c=m.data;switch(c.kind){case"ready":u({kind:"init",options:{publishableKey:t,clientSecret:n.clientSecret,installments:n.installments,labels:n.labels,styles:n.styles}});break;case"mounted":y?.(c.session);break;case"mount-error":y?.(new a(c.message,c.code));break;case"resize":l=Math.max(0,Math.ceil(c.height)),s.style.position!=="fixed"?s.style.height=`${l}px`:i.style.height=`${l}px`;break;case"validity":n.onValidityChange?.(c.valid);break;case"overlay":A(c.active);break;case"paid":{let g=d.get(c.requestId);d.delete(c.requestId),g?.resolve(c.result);break}case"pay-error":{let g=d.get(c.requestId);d.delete(c.requestId),g?.reject(new a(c.message,c.code));break}}}return window.addEventListener("message",x),new Promise((m,c)=>{let g=setTimeout(()=>{y?.(new a("No se pudo cargar el formulario de tarjeta.","FIELDS_TIMEOUT"))},Y);y=v=>{if(y=null,clearTimeout(g),v instanceof a){b(),c(v);return}m({session:v,pay(){if(h)return Promise.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));let k=I();return new Promise((D,j)=>{d.set(k,{resolve:D,reject:j}),u({kind:"pay",requestId:k})})},destroy:b})}})}function I(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`}var C={development:"https://api-dev.crosspaysolutions.financial",production:"https://api.crosspaysolutions.financial"};function O(e){let t=C[e];if(!t)throw new TypeError(`Ambiente de Crosspay no valido: "${String(e)}". Usa "development" o "production".`);return t}var f={development:"https://fields-dev.crosspaysolutions.financial/",production:"https://fields.crosspaysolutions.financial/"};function F(e){let t=(r,o)=>(e.fetch??globalThis.fetch)(r,o);async function n(r,o,i){let s={Accept:"application/json"};i!==void 0&&(s["Content-Type"]="application/json"),e.locale&&(s["Accept-Language"]=e.locale);let l;try{l=await t(`${e.baseUrl}${o}`,{method:r,headers:s,body:i===void 0?void 0:JSON.stringify(i),credentials:"omit"})}catch(u){throw new a("No se pudo conectar con Crosspay.","NETWORK_ERROR",u)}let d=await l.json().catch(()=>null);if(!l.ok||d?.success===!1){let u=d?.message||d?.error||`Crosspay respondio ${l.status}.`;throw new a(u,`HTTP_${l.status}`,d)}return d}async function p(r,o,i){let s=await n(r,o,i);return s&&typeof s=="object"&&"data"in s?s.data:s}return{get:r=>p("GET",r),post:(r,o)=>p("POST",r,o),postRaw:(r,o)=>n("POST",r,o)}}var U="cp_device_id";function W(){try{let e=localStorage.getItem(U);return e||(e=typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`,localStorage.setItem(U,e)),e}catch{return""}}function G(){return typeof navigator>"u"?"":[navigator.userAgent,navigator.language,typeof screen<"u"?`${screen.width}x${screen.height}`:"",E()].join("|")}function J(e){let t=5381;for(let n=0;n<e.length;n+=1)t=(t<<5)+t+e.charCodeAt(n)|0;return(t>>>0).toString(16)}function E(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone||""}catch{return""}}function L(){let e=W(),t=J(G());return e?`${e}.${t}`:t}function Q(){let e=typeof navigator<"u"?navigator.language?.split("-")[0]:void 0;return{fingerprint:L(),timezone:E(),...e?{language:e}:{}}}function M(e){return{status(t){return e.get(`/payments/status/${encodeURIComponent(t)}`)}}}function _(e,t){return{async listBanks(n="COP"){return(await e.get(`/payments/pse/banks?currency=${encodeURIComponent(n)}`)??[]).filter(r=>{let o=String(r.code??"").trim(),i=String(r.name??"").normalize("NFD").replace(/\p{Diacritic}/gu,"").toLowerCase();return o!==""&&o!=="0"&&!i.includes("seleccione su banco")})},async pay(n){let{clientSecret:p,...r}=n,o=await e.postRaw("/payments/sessions/pay",{publishableKey:t,clientSecret:p,parentOrigin:window.location.origin,method:"pse",pse:r,meta:Q()}),{data:i,...s}=o??{},l=i?.sessionId;return{...s,...l?{sessionId:l}:{}}}}}var X={development:"pk_test_",production:"pk_live_"};function $(e){let t=O(e.environment),n=String(e.publishableKey??"").trim(),p=X[e.environment];if(!n.startsWith(p))throw new TypeError(`\`publishableKey\` debe empezar por "${p}" en el ambiente "${e.environment}".`);if(e.fieldsUrl&&e.environment!=="development")throw new TypeError('`fieldsUrl` solo se admite en el ambiente "development".');let r=e.fieldsUrl??f[e.environment],o=F({baseUrl:t,locale:e.locale,fetch:e.fetch});return{environment:e.environment,card:{async mount(i){if(!String(i.clientSecret??"").trim())throw new a("Falta `clientSecret`: crea la sesion de pago en tu servidor con @crosspay-lb/node.","INVALID_REQUEST");return R(r,n,i)}},payments:M(o),pse:_(o,n)}}var Z="0.2.0";0&&(module.exports={API_BASE_URLS,CrosspayError,FIELDS_URLS,init,version});
1
+ "use strict";var v=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var H=Object.prototype.hasOwnProperty;var z=(e,t)=>{for(var n in t)v(e,n,{get:t[n],enumerable:!0})},V=(e,t,n,d)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of q(t))!H.call(e,s)&&s!==n&&v(e,s,{get:()=>t[s],enumerable:!(d=B(t,s))||d.enumerable});return e};var K=e=>V(v({},"__esModule",{value:!0}),e);var ne={};z(ne,{API_BASE_URLS:()=>E,CrosspayError:()=>a,FIELDS_URLS:()=>h,init:()=>$,version:()=>te});module.exports=K(ne);var a=class extends Error{constructor(n,d,s){super(n);this.code=d;this.details=s;this.name="CrosspayError"}};var C="crosspay-fields/2";function T(e,t){return typeof e=="object"&&e!==null&&e.protocol===C&&e.channel===t&&typeof e.kind=="string"}function k(e){return new URLSearchParams({channel:e.channel,origin:e.parentOrigin}).toString()}var Y=3e4,Q={position:"fixed",inset:"0",width:"100%",height:"100%",zIndex:"2147483647"};function b(e,t,n){let d=typeof n.container=="string"?document.querySelector(n.container):n.container;if(!d)return Promise.reject(new a(`No existe el contenedor ${String(n.container)}.`,"INVALID_CONTAINER"));let s=new URL(e).origin,i=R(),o=document.createElement("div");o.style.position="relative";let r=document.createElement("iframe");r.src=`${e}#${k({channel:i,parentOrigin:window.location.origin})}`,r.title="Formulario seguro de tarjeta",r.setAttribute("scrolling","no"),r.setAttribute("allow","payment"),Object.assign(r.style,{display:"block",width:"100%",height:"0px",border:"0",background:"transparent",colorScheme:"normal"}),o.appendChild(r),d.replaceChildren(o);let c=0,p=new Map,m=u=>{r.contentWindow?.postMessage({...u,protocol:C,channel:i},s)},f=u=>{u?(o.style.height=`${c}px`,Object.assign(r.style,Q)):(o.style.height="",Object.assign(r.style,{position:"",inset:"",width:"100%",height:`${c}px`,zIndex:""}))},S=!1,P=()=>{if(!S){S=!0,window.removeEventListener("message",x);for(let u of p.values())u.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));p.clear(),o.remove()}},y=null;function x(u){if(u.source!==r.contentWindow||u.origin!==s||!T(u.data,i))return;let l=u.data;switch(l.kind){case"ready":m({kind:"init",options:{publishableKey:t,clientSecret:n.clientSecret,amount:n.amount,currency:n.currency,installments:n.installments,labels:n.labels,styles:n.styles}});break;case"mounted":y?.({session:l.session});break;case"mount-error":y?.(new a(l.message,l.code));break;case"resize":c=Math.max(0,Math.ceil(l.height)),r.style.position!=="fixed"?r.style.height=`${c}px`:o.style.height=`${c}px`;break;case"validity":n.onValidityChange?.(l.valid);break;case"overlay":f(l.active);break;case"paid":{let g=p.get(l.requestId);p.delete(l.requestId),g?.resolve(l.result);break}case"pay-error":{let g=p.get(l.requestId);p.delete(l.requestId),g?.reject(new a(l.message,l.code));break}}}return window.addEventListener("message",x),new Promise((u,l)=>{let g=setTimeout(()=>{y?.(new a("No se pudo cargar el formulario de tarjeta.","FIELDS_TIMEOUT"))},Y);y=w=>{if(y=null,clearTimeout(g),w instanceof a){P(),l(w);return}u({session:w.session,pay(O){if(S)return Promise.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));let F=R();return new Promise((j,N)=>{p.set(F,{resolve:j,reject:N}),m({kind:"pay",requestId:F,...O?{clientSecret:O}:{}})})},destroy:P})}})}function R(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`}var E={development:"https://api-dev.crosspaysolutions.financial",production:"https://api.crosspaysolutions.financial"};function D(e){let t=E[e];if(!t)throw new TypeError(`Ambiente de Crosspay no valido: "${String(e)}". Usa "development" o "production".`);return t}var h={development:"https://fields-dev.crosspaysolutions.financial/",production:"https://fields.crosspaysolutions.financial/"};function U(e){let t=(s,i)=>(e.fetch??globalThis.fetch)(s,i);async function n(s,i,o){let r={Accept:"application/json"};o!==void 0&&(r["Content-Type"]="application/json"),e.locale&&(r["Accept-Language"]=e.locale);let c;try{c=await t(`${e.baseUrl}${i}`,{method:s,headers:r,body:o===void 0?void 0:JSON.stringify(o),credentials:"omit"})}catch(m){throw new a("No se pudo conectar con Crosspay.","NETWORK_ERROR",m)}let p=await c.json().catch(()=>null);if(!c.ok||p?.success===!1){let m=p?.message||p?.error||`Crosspay respondio ${c.status}.`;throw new a(m,`HTTP_${c.status}`,p)}return p}async function d(s,i,o){let r=await n(s,i,o);return r&&typeof r=="object"&&"data"in r?r.data:r}return{get:s=>d("GET",s),post:(s,i)=>d("POST",s,i),postRaw:(s,i)=>n("POST",s,i)}}var L="cp_device_id";function W(){try{let e=localStorage.getItem(L);return e||(e=typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`,localStorage.setItem(L,e)),e}catch{return""}}function G(){return typeof navigator>"u"?"":[navigator.userAgent,navigator.language,typeof screen<"u"?`${screen.width}x${screen.height}`:"",I()].join("|")}function Z(e){let t=5381;for(let n=0;n<e.length;n+=1)t=(t<<5)+t+e.charCodeAt(n)|0;return(t>>>0).toString(16)}function I(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone||""}catch{return""}}function _(){let e=W(),t=Z(G());return e?`${e}.${t}`:t}function J(){let e=typeof navigator<"u"?navigator.language?.split("-")[0]:void 0;return{fingerprint:_(),timezone:I(),...e?{language:e}:{}}}function M(e){return{status(t){return e.get(`/payments/status/${encodeURIComponent(t)}`)}}}function A(e,t){return{async listBanks(n="COP"){return(await e.get(`/payments/pse/banks?currency=${encodeURIComponent(n)}`)??[]).filter(s=>{let i=String(s.code??"").trim(),o=String(s.name??"").normalize("NFD").replace(/\p{Diacritic}/gu,"").toLowerCase();return i!==""&&i!=="0"&&!o.includes("seleccione su banco")})},async pay(n){let{clientSecret:d,...s}=n,i=await e.postRaw("/payments/sessions/pay",{publishableKey:t,clientSecret:d,parentOrigin:window.location.origin,method:"pse",pse:s,meta:J()}),{data:o,...r}=i??{},c=o?.sessionId;return{...r,...c?{sessionId:c}:{}}}}}var X={development:"pk_test_",production:"pk_live_"};function $(e){let t=D(e.environment),n=String(e.publishableKey??"").trim(),d=X[e.environment];if(!n.startsWith(d))throw new TypeError(`\`publishableKey\` debe empezar por "${d}" en el ambiente "${e.environment}".`);if(e.fieldsUrl&&e.environment!=="development")throw new TypeError('`fieldsUrl` solo se admite en el ambiente "development".');let s=e.fieldsUrl??h[e.environment],i=U({baseUrl:t,locale:e.locale,fetch:e.fetch});return{environment:e.environment,card:{async mount(o){if(!String(o.clientSecret??"").trim())throw new a("Falta `clientSecret`: crea la sesion de pago en tu servidor con @crosspay-lb/node.","INVALID_REQUEST");let r=await b(s,n,o);return{session:r.session,pay:()=>r.pay(),destroy:r.destroy}},async mountDeferred(o){let{amount:r,currency:c}=ee(o),p=await b(s,n,{...o,amount:r,currency:c});return{amount:r,currency:c,pay(m){let f=String(m?.clientSecret??"").trim();return f?p.pay(f):Promise.reject(new a("Falta `clientSecret`: crea la sesion de pago en tu servidor antes de pagar.","INVALID_REQUEST"))},destroy:p.destroy}}},payments:M(i),pse:A(i,n)}}function ee(e){if("clientSecret"in e)throw new a("`mountDeferred` no recibe `clientSecret`: pasalo en `pay()`, o usa `mount` si ya tienes la sesion.","INVALID_REQUEST");let t=Number(e.amount);if(!Number.isFinite(t)||t<=0)throw new a("`amount` debe ser un numero mayor que cero.","INVALID_REQUEST");let n=String(e.currency??"").trim().toUpperCase();if(!/^[A-Z]{3}$/.test(n))throw new a('`currency` debe ser un codigo ISO 4217, p. ej. "COP".',"INVALID_REQUEST");return{amount:t,currency:n}}var te="0.4.0";0&&(module.exports={API_BASE_URLS,CrosspayError,FIELDS_URLS,init,version});
package/dist/index.d.cts CHANGED
@@ -36,6 +36,10 @@ interface PaymentResult {
36
36
  /** PSE: URL del banco a la que hay que llevar al pagador. */
37
37
  redirectUrl?: string;
38
38
  declineReason?: string | null;
39
+ /** Sesion de suscripcion: id de la suscripcion creada. */
40
+ subscriptionId?: string;
41
+ /** Sesion de suscripcion: transaccion del primer cobro, si ya se confirmo. */
42
+ firstTransactionId?: string;
39
43
  amount?: number;
40
44
  currency?: string;
41
45
  reference?: string;
@@ -71,12 +75,24 @@ declare function createPseApi(http: HttpClient, publishableKey: string): {
71
75
  pay(input: PsePayInput): Promise<PaymentResult>;
72
76
  };
73
77
 
78
+ /** Plan de una sesion de suscripcion. Lo fija el servidor del comercio. */
79
+ interface SubscriptionPlan {
80
+ /** `daily`, `weekly`, `biweekly`, `monthly`, `bimonthly`, `quarterly`, `semiannual` o `annual`. */
81
+ periodicity: string;
82
+ planName: string;
83
+ }
74
84
  /** Lo que la pagina de campos confirma de la sesion al montar. */
75
85
  interface SessionSummary {
76
86
  sessionId: string;
77
87
  amount: number;
78
88
  currency: string;
79
89
  description: string;
90
+ /**
91
+ * `payment` (cobro unico) o `subscription` (el pago crea una suscripcion y
92
+ * cobra el primer ciclo). Desde 0.3.0; una pagina de campos anterior no lo envia.
93
+ */
94
+ mode?: 'payment' | 'subscription';
95
+ subscription?: SubscriptionPlan;
80
96
  }
81
97
 
82
98
  interface CardFieldLabels {
@@ -86,15 +102,10 @@ interface CardFieldLabels {
86
102
  cvv?: string;
87
103
  installments?: string;
88
104
  }
89
- interface CardFieldsOptions {
105
+ /** Opciones comunes a los dos modos de montaje. */
106
+ interface BaseCardFieldsOptions {
90
107
  /** Donde se inserta el formulario: un selector CSS o el elemento. */
91
108
  container: string | HTMLElement;
92
- /**
93
- * `clientSecret` de la sesion de pago que creo el SERVIDOR del comercio con
94
- * su llave secreta (`sessions.create` de @crosspay-lb/node). Monto, moneda y
95
- * cliente salen de la sesion: el navegador no puede cambiarlos.
96
- */
97
- clientSecret: string;
98
109
  /** Muestra el selector de cuotas. */
99
110
  installments?: boolean;
100
111
  labels?: CardFieldLabels;
@@ -107,6 +118,48 @@ interface CardFieldsOptions {
107
118
  /** Se dispara cada vez que cambia la validez del formulario. */
108
119
  onValidityChange?: (isValid: boolean) => void;
109
120
  }
121
+ interface CardFieldsOptions extends BaseCardFieldsOptions {
122
+ /**
123
+ * `clientSecret` de la sesion de pago que creo el SERVIDOR del comercio con
124
+ * su llave secreta (`sessions.create` de @crosspay-lb/node). Monto, moneda y
125
+ * cliente salen de la sesion: el navegador no puede cambiarlos.
126
+ */
127
+ clientSecret: string;
128
+ }
129
+ /**
130
+ * Montaje diferido (0.4.0): el formulario aparece antes de que exista la
131
+ * sesion, y la sesion se pasa en `pay()`. Sirve para crear la orden recien
132
+ * cuando el pagador le da a pagar.
133
+ *
134
+ * `amount` y `currency` son los que vera el banco en la verificacion 3DS. NO
135
+ * deciden el cobro: al pagar, la pagina de campos compara con la sesion y, si
136
+ * no coinciden, rechaza con `AMOUNT_MISMATCH` sin tocar la tarjeta. Si el total
137
+ * cambia (cupon, envio…), retira el formulario y vuelve a montarlo.
138
+ *
139
+ * Solo cobro unico: una sesion de suscripcion se monta con `clientSecret`.
140
+ */
141
+ interface DeferredCardFieldsOptions extends BaseCardFieldsOptions {
142
+ amount: number;
143
+ /** ISO 4217, p. ej. `COP` o `USD`. */
144
+ currency: string;
145
+ }
146
+ /** Lo que `pay()` de un montaje diferido necesita. */
147
+ interface DeferredPayInput {
148
+ /** `clientSecret` de la sesion que el servidor acaba de crear para este cobro. */
149
+ clientSecret: string;
150
+ }
151
+ interface DeferredCardFields {
152
+ /** Monto y moneda con que se monto, en mayusculas. */
153
+ readonly amount: number;
154
+ readonly currency: string;
155
+ /**
156
+ * Valida la sesion, tokeniza y cobra. Lanza `CrosspayError` con
157
+ * `AMOUNT_MISMATCH` si la sesion no es del monto y moneda montados.
158
+ */
159
+ pay(input: DeferredPayInput): Promise<PaymentResult>;
160
+ /** Retira el formulario. */
161
+ destroy(): void;
162
+ }
110
163
  interface MountedCardFields {
111
164
  /** Monto, moneda y descripcion de la sesion que se va a pagar. */
112
165
  readonly session: SessionSummary;
@@ -167,6 +220,12 @@ interface Crosspay {
167
220
  * la sesion o el dominio no son validos.
168
221
  */
169
222
  mount(options: CardFieldsOptions): Promise<MountedCardFields>;
223
+ /**
224
+ * Monta el formulario ANTES de que exista la sesion, con el monto y la
225
+ * moneda que se van a cobrar; la sesion se pasa en `pay({ clientSecret })`.
226
+ * Rechaza con `CrosspayError` si la llave o el dominio no son validos.
227
+ */
228
+ mountDeferred(options: DeferredCardFieldsOptions): Promise<DeferredCardFields>;
170
229
  };
171
230
  payments: ReturnType<typeof createPaymentsApi>;
172
231
  pse: ReturnType<typeof createPseApi>;
@@ -189,4 +248,4 @@ declare class CrosspayError extends Error {
189
248
  /** Version de la libreria, inyectada en el build. */
190
249
  declare const version: string;
191
250
 
192
- export { API_BASE_URLS, type Bank, type CardFieldLabels, type CardFieldsOptions, type Crosspay, type CrosspayEnvironment, CrosspayError, type CrosspayOptions, FIELDS_URLS, type MountedCardFields, type PaymentResult, type PaymentStatus, type PsePayInput, type SessionSummary, init, version };
251
+ export { API_BASE_URLS, type Bank, type CardFieldLabels, type CardFieldsOptions, type Crosspay, type CrosspayEnvironment, CrosspayError, type CrosspayOptions, type DeferredCardFields, type DeferredCardFieldsOptions, type DeferredPayInput, FIELDS_URLS, type MountedCardFields, type PaymentResult, type PaymentStatus, type PsePayInput, type SessionSummary, init, version };
package/dist/index.d.ts CHANGED
@@ -36,6 +36,10 @@ interface PaymentResult {
36
36
  /** PSE: URL del banco a la que hay que llevar al pagador. */
37
37
  redirectUrl?: string;
38
38
  declineReason?: string | null;
39
+ /** Sesion de suscripcion: id de la suscripcion creada. */
40
+ subscriptionId?: string;
41
+ /** Sesion de suscripcion: transaccion del primer cobro, si ya se confirmo. */
42
+ firstTransactionId?: string;
39
43
  amount?: number;
40
44
  currency?: string;
41
45
  reference?: string;
@@ -71,12 +75,24 @@ declare function createPseApi(http: HttpClient, publishableKey: string): {
71
75
  pay(input: PsePayInput): Promise<PaymentResult>;
72
76
  };
73
77
 
78
+ /** Plan de una sesion de suscripcion. Lo fija el servidor del comercio. */
79
+ interface SubscriptionPlan {
80
+ /** `daily`, `weekly`, `biweekly`, `monthly`, `bimonthly`, `quarterly`, `semiannual` o `annual`. */
81
+ periodicity: string;
82
+ planName: string;
83
+ }
74
84
  /** Lo que la pagina de campos confirma de la sesion al montar. */
75
85
  interface SessionSummary {
76
86
  sessionId: string;
77
87
  amount: number;
78
88
  currency: string;
79
89
  description: string;
90
+ /**
91
+ * `payment` (cobro unico) o `subscription` (el pago crea una suscripcion y
92
+ * cobra el primer ciclo). Desde 0.3.0; una pagina de campos anterior no lo envia.
93
+ */
94
+ mode?: 'payment' | 'subscription';
95
+ subscription?: SubscriptionPlan;
80
96
  }
81
97
 
82
98
  interface CardFieldLabels {
@@ -86,15 +102,10 @@ interface CardFieldLabels {
86
102
  cvv?: string;
87
103
  installments?: string;
88
104
  }
89
- interface CardFieldsOptions {
105
+ /** Opciones comunes a los dos modos de montaje. */
106
+ interface BaseCardFieldsOptions {
90
107
  /** Donde se inserta el formulario: un selector CSS o el elemento. */
91
108
  container: string | HTMLElement;
92
- /**
93
- * `clientSecret` de la sesion de pago que creo el SERVIDOR del comercio con
94
- * su llave secreta (`sessions.create` de @crosspay-lb/node). Monto, moneda y
95
- * cliente salen de la sesion: el navegador no puede cambiarlos.
96
- */
97
- clientSecret: string;
98
109
  /** Muestra el selector de cuotas. */
99
110
  installments?: boolean;
100
111
  labels?: CardFieldLabels;
@@ -107,6 +118,48 @@ interface CardFieldsOptions {
107
118
  /** Se dispara cada vez que cambia la validez del formulario. */
108
119
  onValidityChange?: (isValid: boolean) => void;
109
120
  }
121
+ interface CardFieldsOptions extends BaseCardFieldsOptions {
122
+ /**
123
+ * `clientSecret` de la sesion de pago que creo el SERVIDOR del comercio con
124
+ * su llave secreta (`sessions.create` de @crosspay-lb/node). Monto, moneda y
125
+ * cliente salen de la sesion: el navegador no puede cambiarlos.
126
+ */
127
+ clientSecret: string;
128
+ }
129
+ /**
130
+ * Montaje diferido (0.4.0): el formulario aparece antes de que exista la
131
+ * sesion, y la sesion se pasa en `pay()`. Sirve para crear la orden recien
132
+ * cuando el pagador le da a pagar.
133
+ *
134
+ * `amount` y `currency` son los que vera el banco en la verificacion 3DS. NO
135
+ * deciden el cobro: al pagar, la pagina de campos compara con la sesion y, si
136
+ * no coinciden, rechaza con `AMOUNT_MISMATCH` sin tocar la tarjeta. Si el total
137
+ * cambia (cupon, envio…), retira el formulario y vuelve a montarlo.
138
+ *
139
+ * Solo cobro unico: una sesion de suscripcion se monta con `clientSecret`.
140
+ */
141
+ interface DeferredCardFieldsOptions extends BaseCardFieldsOptions {
142
+ amount: number;
143
+ /** ISO 4217, p. ej. `COP` o `USD`. */
144
+ currency: string;
145
+ }
146
+ /** Lo que `pay()` de un montaje diferido necesita. */
147
+ interface DeferredPayInput {
148
+ /** `clientSecret` de la sesion que el servidor acaba de crear para este cobro. */
149
+ clientSecret: string;
150
+ }
151
+ interface DeferredCardFields {
152
+ /** Monto y moneda con que se monto, en mayusculas. */
153
+ readonly amount: number;
154
+ readonly currency: string;
155
+ /**
156
+ * Valida la sesion, tokeniza y cobra. Lanza `CrosspayError` con
157
+ * `AMOUNT_MISMATCH` si la sesion no es del monto y moneda montados.
158
+ */
159
+ pay(input: DeferredPayInput): Promise<PaymentResult>;
160
+ /** Retira el formulario. */
161
+ destroy(): void;
162
+ }
110
163
  interface MountedCardFields {
111
164
  /** Monto, moneda y descripcion de la sesion que se va a pagar. */
112
165
  readonly session: SessionSummary;
@@ -167,6 +220,12 @@ interface Crosspay {
167
220
  * la sesion o el dominio no son validos.
168
221
  */
169
222
  mount(options: CardFieldsOptions): Promise<MountedCardFields>;
223
+ /**
224
+ * Monta el formulario ANTES de que exista la sesion, con el monto y la
225
+ * moneda que se van a cobrar; la sesion se pasa en `pay({ clientSecret })`.
226
+ * Rechaza con `CrosspayError` si la llave o el dominio no son validos.
227
+ */
228
+ mountDeferred(options: DeferredCardFieldsOptions): Promise<DeferredCardFields>;
170
229
  };
171
230
  payments: ReturnType<typeof createPaymentsApi>;
172
231
  pse: ReturnType<typeof createPseApi>;
@@ -189,4 +248,4 @@ declare class CrosspayError extends Error {
189
248
  /** Version de la libreria, inyectada en el build. */
190
249
  declare const version: string;
191
250
 
192
- export { API_BASE_URLS, type Bank, type CardFieldLabels, type CardFieldsOptions, type Crosspay, type CrosspayEnvironment, CrosspayError, type CrosspayOptions, FIELDS_URLS, type MountedCardFields, type PaymentResult, type PaymentStatus, type PsePayInput, type SessionSummary, init, version };
251
+ export { API_BASE_URLS, type Bank, type CardFieldLabels, type CardFieldsOptions, type Crosspay, type CrosspayEnvironment, CrosspayError, type CrosspayOptions, type DeferredCardFields, type DeferredCardFieldsOptions, type DeferredPayInput, FIELDS_URLS, type MountedCardFields, type PaymentResult, type PaymentStatus, type PsePayInput, type SessionSummary, init, version };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var c=class extends Error{constructor(t,d,s){super(t);this.code=d;this.details=s;this.name="CrosspayError"}};var v="crosspay-fields/2";function x(e,r){return typeof e=="object"&&e!==null&&e.protocol===v&&e.channel===r&&typeof e.kind=="string"}function k(e){return new URLSearchParams({channel:e.channel,origin:e.parentOrigin}).toString()}var D=3e4,j={position:"fixed",inset:"0",width:"100%",height:"100%",zIndex:"2147483647"};function T(e,r,t){let d=typeof t.container=="string"?document.querySelector(t.container):t.container;if(!d)return Promise.reject(new c(`No existe el contenedor ${String(t.container)}.`,"INVALID_CONTAINER"));let s=new URL(e).origin,o=P(),i=document.createElement("div");i.style.position="relative";let n=document.createElement("iframe");n.src=`${e}#${k({channel:o,parentOrigin:window.location.origin})}`,n.title="Formulario seguro de tarjeta",n.setAttribute("scrolling","no"),n.setAttribute("allow","payment"),Object.assign(n.style,{display:"block",width:"100%",height:"0px",border:"0",background:"transparent",colorScheme:"normal"}),i.appendChild(n),d.replaceChildren(i);let p=0,l=new Map,u=m=>{n.contentWindow?.postMessage({...m,protocol:v,channel:o},s)},_=m=>{m?(i.style.height=`${p}px`,Object.assign(n.style,j)):(i.style.height="",Object.assign(n.style,{position:"",inset:"",width:"100%",height:`${p}px`,zIndex:""}))},f=!1,C=()=>{if(!f){f=!0,window.removeEventListener("message",E);for(let m of l.values())m.reject(new c("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));l.clear(),i.remove()}},y=null;function E(m){if(m.source!==n.contentWindow||m.origin!==s||!x(m.data,o))return;let a=m.data;switch(a.kind){case"ready":u({kind:"init",options:{publishableKey:r,clientSecret:t.clientSecret,installments:t.installments,labels:t.labels,styles:t.styles}});break;case"mounted":y?.(a.session);break;case"mount-error":y?.(new c(a.message,a.code));break;case"resize":p=Math.max(0,Math.ceil(a.height)),n.style.position!=="fixed"?n.style.height=`${p}px`:i.style.height=`${p}px`;break;case"validity":t.onValidityChange?.(a.valid);break;case"overlay":_(a.active);break;case"paid":{let g=l.get(a.requestId);l.delete(a.requestId),g?.resolve(a.result);break}case"pay-error":{let g=l.get(a.requestId);l.delete(a.requestId),g?.reject(new c(a.message,a.code));break}}}return window.addEventListener("message",E),new Promise((m,a)=>{let g=setTimeout(()=>{y?.(new c("No se pudo cargar el formulario de tarjeta.","FIELDS_TIMEOUT"))},D);y=h=>{if(y=null,clearTimeout(g),h instanceof c){C(),a(h);return}m({session:h,pay(){if(f)return Promise.reject(new c("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));let b=P();return new Promise(($,A)=>{l.set(b,{resolve:$,reject:A}),u({kind:"pay",requestId:b})})},destroy:C})}})}function P(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`}var I={development:"https://api-dev.crosspaysolutions.financial",production:"https://api.crosspaysolutions.financial"};function R(e){let r=I[e];if(!r)throw new TypeError(`Ambiente de Crosspay no valido: "${String(e)}". Usa "development" o "production".`);return r}var S={development:"https://fields-dev.crosspaysolutions.financial/",production:"https://fields.crosspaysolutions.financial/"};function O(e){let r=(s,o)=>(e.fetch??globalThis.fetch)(s,o);async function t(s,o,i){let n={Accept:"application/json"};i!==void 0&&(n["Content-Type"]="application/json"),e.locale&&(n["Accept-Language"]=e.locale);let p;try{p=await r(`${e.baseUrl}${o}`,{method:s,headers:n,body:i===void 0?void 0:JSON.stringify(i),credentials:"omit"})}catch(u){throw new c("No se pudo conectar con Crosspay.","NETWORK_ERROR",u)}let l=await p.json().catch(()=>null);if(!p.ok||l?.success===!1){let u=l?.message||l?.error||`Crosspay respondio ${p.status}.`;throw new c(u,`HTTP_${p.status}`,l)}return l}async function d(s,o,i){let n=await t(s,o,i);return n&&typeof n=="object"&&"data"in n?n.data:n}return{get:s=>d("GET",s),post:(s,o)=>d("POST",s,o),postRaw:(s,o)=>t("POST",s,o)}}var F="cp_device_id";function B(){try{let e=localStorage.getItem(F);return e||(e=typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`,localStorage.setItem(F,e)),e}catch{return""}}function q(){return typeof navigator>"u"?"":[navigator.userAgent,navigator.language,typeof screen<"u"?`${screen.width}x${screen.height}`:"",w()].join("|")}function N(e){let r=5381;for(let t=0;t<e.length;t+=1)r=(r<<5)+r+e.charCodeAt(t)|0;return(r>>>0).toString(16)}function w(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone||""}catch{return""}}function U(){let e=B(),r=N(q());return e?`${e}.${r}`:r}function H(){let e=typeof navigator<"u"?navigator.language?.split("-")[0]:void 0;return{fingerprint:U(),timezone:w(),...e?{language:e}:{}}}function L(e){return{status(r){return e.get(`/payments/status/${encodeURIComponent(r)}`)}}}function M(e,r){return{async listBanks(t="COP"){return(await e.get(`/payments/pse/banks?currency=${encodeURIComponent(t)}`)??[]).filter(s=>{let o=String(s.code??"").trim(),i=String(s.name??"").normalize("NFD").replace(/\p{Diacritic}/gu,"").toLowerCase();return o!==""&&o!=="0"&&!i.includes("seleccione su banco")})},async pay(t){let{clientSecret:d,...s}=t,o=await e.postRaw("/payments/sessions/pay",{publishableKey:r,clientSecret:d,parentOrigin:window.location.origin,method:"pse",pse:s,meta:H()}),{data:i,...n}=o??{},p=i?.sessionId;return{...n,...p?{sessionId:p}:{}}}}}var z={development:"pk_test_",production:"pk_live_"};function K(e){let r=R(e.environment),t=String(e.publishableKey??"").trim(),d=z[e.environment];if(!t.startsWith(d))throw new TypeError(`\`publishableKey\` debe empezar por "${d}" en el ambiente "${e.environment}".`);if(e.fieldsUrl&&e.environment!=="development")throw new TypeError('`fieldsUrl` solo se admite en el ambiente "development".');let s=e.fieldsUrl??S[e.environment],o=O({baseUrl:r,locale:e.locale,fetch:e.fetch});return{environment:e.environment,card:{async mount(i){if(!String(i.clientSecret??"").trim())throw new c("Falta `clientSecret`: crea la sesion de pago en tu servidor con @crosspay-lb/node.","INVALID_REQUEST");return T(s,t,i)}},payments:L(o),pse:M(o,t)}}var pe="0.2.0";export{I as API_BASE_URLS,c as CrosspayError,S as FIELDS_URLS,K as init,pe as version};
1
+ var a=class extends Error{constructor(t,d,s){super(t);this.code=d;this.details=s;this.name="CrosspayError"}};var w="crosspay-fields/2";function O(e,r){return typeof e=="object"&&e!==null&&e.protocol===w&&e.channel===r&&typeof e.kind=="string"}function F(e){return new URLSearchParams({channel:e.channel,origin:e.parentOrigin}).toString()}var j=3e4,N={position:"fixed",inset:"0",width:"100%",height:"100%",zIndex:"2147483647"};function v(e,r,t){let d=typeof t.container=="string"?document.querySelector(t.container):t.container;if(!d)return Promise.reject(new a(`No existe el contenedor ${String(t.container)}.`,"INVALID_CONTAINER"));let s=new URL(e).origin,i=T(),o=document.createElement("div");o.style.position="relative";let n=document.createElement("iframe");n.src=`${e}#${F({channel:i,parentOrigin:window.location.origin})}`,n.title="Formulario seguro de tarjeta",n.setAttribute("scrolling","no"),n.setAttribute("allow","payment"),Object.assign(n.style,{display:"block",width:"100%",height:"0px",border:"0",background:"transparent",colorScheme:"normal"}),o.appendChild(n),d.replaceChildren(o);let c=0,p=new Map,m=u=>{n.contentWindow?.postMessage({...u,protocol:w,channel:i},s)},f=u=>{u?(o.style.height=`${c}px`,Object.assign(n.style,N)):(o.style.height="",Object.assign(n.style,{position:"",inset:"",width:"100%",height:`${c}px`,zIndex:""}))},h=!1,E=()=>{if(!h){h=!0,window.removeEventListener("message",I);for(let u of p.values())u.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));p.clear(),o.remove()}},y=null;function I(u){if(u.source!==n.contentWindow||u.origin!==s||!O(u.data,i))return;let l=u.data;switch(l.kind){case"ready":m({kind:"init",options:{publishableKey:r,clientSecret:t.clientSecret,amount:t.amount,currency:t.currency,installments:t.installments,labels:t.labels,styles:t.styles}});break;case"mounted":y?.({session:l.session});break;case"mount-error":y?.(new a(l.message,l.code));break;case"resize":c=Math.max(0,Math.ceil(l.height)),n.style.position!=="fixed"?n.style.height=`${c}px`:o.style.height=`${c}px`;break;case"validity":t.onValidityChange?.(l.valid);break;case"overlay":f(l.active);break;case"paid":{let g=p.get(l.requestId);p.delete(l.requestId),g?.resolve(l.result);break}case"pay-error":{let g=p.get(l.requestId);p.delete(l.requestId),g?.reject(new a(l.message,l.code));break}}}return window.addEventListener("message",I),new Promise((u,l)=>{let g=setTimeout(()=>{y?.(new a("No se pudo cargar el formulario de tarjeta.","FIELDS_TIMEOUT"))},j);y=S=>{if(y=null,clearTimeout(g),S instanceof a){E(),l(S);return}u({session:S.session,pay(P){if(h)return Promise.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));let x=T();return new Promise((A,$)=>{p.set(x,{resolve:A,reject:$}),m({kind:"pay",requestId:x,...P?{clientSecret:P}:{}})})},destroy:E})}})}function T(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`}var k={development:"https://api-dev.crosspaysolutions.financial",production:"https://api.crosspaysolutions.financial"};function R(e){let r=k[e];if(!r)throw new TypeError(`Ambiente de Crosspay no valido: "${String(e)}". Usa "development" o "production".`);return r}var C={development:"https://fields-dev.crosspaysolutions.financial/",production:"https://fields.crosspaysolutions.financial/"};function D(e){let r=(s,i)=>(e.fetch??globalThis.fetch)(s,i);async function t(s,i,o){let n={Accept:"application/json"};o!==void 0&&(n["Content-Type"]="application/json"),e.locale&&(n["Accept-Language"]=e.locale);let c;try{c=await r(`${e.baseUrl}${i}`,{method:s,headers:n,body:o===void 0?void 0:JSON.stringify(o),credentials:"omit"})}catch(m){throw new a("No se pudo conectar con Crosspay.","NETWORK_ERROR",m)}let p=await c.json().catch(()=>null);if(!c.ok||p?.success===!1){let m=p?.message||p?.error||`Crosspay respondio ${c.status}.`;throw new a(m,`HTTP_${c.status}`,p)}return p}async function d(s,i,o){let n=await t(s,i,o);return n&&typeof n=="object"&&"data"in n?n.data:n}return{get:s=>d("GET",s),post:(s,i)=>d("POST",s,i),postRaw:(s,i)=>t("POST",s,i)}}var U="cp_device_id";function B(){try{let e=localStorage.getItem(U);return e||(e=typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`,localStorage.setItem(U,e)),e}catch{return""}}function q(){return typeof navigator>"u"?"":[navigator.userAgent,navigator.language,typeof screen<"u"?`${screen.width}x${screen.height}`:"",b()].join("|")}function H(e){let r=5381;for(let t=0;t<e.length;t+=1)r=(r<<5)+r+e.charCodeAt(t)|0;return(r>>>0).toString(16)}function b(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone||""}catch{return""}}function L(){let e=B(),r=H(q());return e?`${e}.${r}`:r}function z(){let e=typeof navigator<"u"?navigator.language?.split("-")[0]:void 0;return{fingerprint:L(),timezone:b(),...e?{language:e}:{}}}function _(e){return{status(r){return e.get(`/payments/status/${encodeURIComponent(r)}`)}}}function M(e,r){return{async listBanks(t="COP"){return(await e.get(`/payments/pse/banks?currency=${encodeURIComponent(t)}`)??[]).filter(s=>{let i=String(s.code??"").trim(),o=String(s.name??"").normalize("NFD").replace(/\p{Diacritic}/gu,"").toLowerCase();return i!==""&&i!=="0"&&!o.includes("seleccione su banco")})},async pay(t){let{clientSecret:d,...s}=t,i=await e.postRaw("/payments/sessions/pay",{publishableKey:r,clientSecret:d,parentOrigin:window.location.origin,method:"pse",pse:s,meta:z()}),{data:o,...n}=i??{},c=o?.sessionId;return{...n,...c?{sessionId:c}:{}}}}}var V={development:"pk_test_",production:"pk_live_"};function K(e){let r=R(e.environment),t=String(e.publishableKey??"").trim(),d=V[e.environment];if(!t.startsWith(d))throw new TypeError(`\`publishableKey\` debe empezar por "${d}" en el ambiente "${e.environment}".`);if(e.fieldsUrl&&e.environment!=="development")throw new TypeError('`fieldsUrl` solo se admite en el ambiente "development".');let s=e.fieldsUrl??C[e.environment],i=D({baseUrl:r,locale:e.locale,fetch:e.fetch});return{environment:e.environment,card:{async mount(o){if(!String(o.clientSecret??"").trim())throw new a("Falta `clientSecret`: crea la sesion de pago en tu servidor con @crosspay-lb/node.","INVALID_REQUEST");let n=await v(s,t,o);return{session:n.session,pay:()=>n.pay(),destroy:n.destroy}},async mountDeferred(o){let{amount:n,currency:c}=Y(o),p=await v(s,t,{...o,amount:n,currency:c});return{amount:n,currency:c,pay(m){let f=String(m?.clientSecret??"").trim();return f?p.pay(f):Promise.reject(new a("Falta `clientSecret`: crea la sesion de pago en tu servidor antes de pagar.","INVALID_REQUEST"))},destroy:p.destroy}}},payments:_(i),pse:M(i,t)}}function Y(e){if("clientSecret"in e)throw new a("`mountDeferred` no recibe `clientSecret`: pasalo en `pay()`, o usa `mount` si ya tienes la sesion.","INVALID_REQUEST");let r=Number(e.amount);if(!Number.isFinite(r)||r<=0)throw new a("`amount` debe ser un numero mayor que cero.","INVALID_REQUEST");let t=String(e.currency??"").trim().toUpperCase();if(!/^[A-Z]{3}$/.test(t))throw new a('`currency` debe ser un codigo ISO 4217, p. ej. "COP".',"INVALID_REQUEST");return{amount:r,currency:t}}var de="0.4.0";export{k as API_BASE_URLS,a as CrosspayError,C as FIELDS_URLS,K as init,de as version};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crosspay-lb/js",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Librería de navegador de Crosspay: formulario seguro de tarjeta, PSE y estado de pagos.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",