@crosspay-lb/js 0.1.0 → 0.3.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 +9 -9
- package/dist/crosspay.min.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +119 -136
- package/dist/index.d.ts +119 -136
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,17 +10,17 @@ npm install @crosspay-lb/js
|
|
|
10
10
|
```ts
|
|
11
11
|
import { init } from '@crosspay-lb/js'
|
|
12
12
|
|
|
13
|
-
const cp = init({ environment: 'production' })
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
description: 'Orden 1001',
|
|
19
|
-
customer: { firstName: 'Ana', lastName: 'Díaz', email: 'ana@correo.com' },
|
|
20
|
-
})
|
|
13
|
+
const cp = init({ environment: 'production', publishableKey: 'pk_live_…' })
|
|
14
|
+
|
|
15
|
+
// clientSecret: lo crea TU servidor con @crosspay-lb/node (sessions.create)
|
|
16
|
+
const fields = await cp.card.mount({ container: '#card', clientSecret })
|
|
17
|
+
const result = await fields.pay()
|
|
21
18
|
```
|
|
22
19
|
|
|
23
|
-
O por CDN: `<script src="https://cdn.jsdelivr.net/npm/@crosspay-lb/js@0/dist/crosspay.min.js"></script>` → `window.Crosspay`.
|
|
20
|
+
O por CDN: `<script src="https://cdn.jsdelivr.net/npm/@crosspay-lb/js@0.3/dist/crosspay.min.js"></script>` → `window.Crosspay`.
|
|
21
|
+
|
|
22
|
+
Requisitos: llave pública del comercio, sitio en sus **dominios autorizados** y
|
|
23
|
+
una sesión de pago creada en el servidor con la llave secreta.
|
|
24
24
|
|
|
25
25
|
Documentación completa: panel de Crosspay → **Documentación de la API** → *crosspay.js*.
|
|
26
26
|
|
package/dist/crosspay.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var Crosspay=(()=>{var
|
|
1
|
+
"use strict";var Crosspay=(()=>{var v=Object.defineProperty;var N=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})},K=(e,t,n,p)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of q(t))!H.call(e,r)&&r!==n&&v(e,r,{get:()=>t[r],enumerable:!(p=N(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:()=>E,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,m=u=>{s.contentWindow?.postMessage({...u,protocol:w,channel:o},r)},D=u=>{u?(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",P);for(let u of d.values())u.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));d.clear(),i.remove()}},y=null;function P(u){if(u.source!==s.contentWindow||u.origin!==r||!I(u.data,o))return;let c=u.data;switch(c.kind){case"ready":m({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",P),new Promise((u,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}u({session:S,pay(){if(h)return Promise.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));let k=R();return new Promise((j,B)=>{d.set(k,{resolve:j,reject:B}),m({kind:"pay",requestId:k})})},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(m){throw new a("No se pudo conectar con Crosspay.","NETWORK_ERROR",m)}let d=await l.json().catch(()=>null);if(!l.ok||d?.success===!1){let m=d?.message||d?.error||`Crosspay respondio ${l.status}.`;throw new a(m,`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}`:"",b()].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 b(){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:b(),...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 E(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.3.0";return Y(ee);})();
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var v=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var q=Object.prototype.hasOwnProperty;var H=(e,t)=>{for(var n in t)v(e,n,{get:t[n],enumerable:!0})},z=(e,t,n,p)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of N(t))!q.call(e,r)&&r!==n&&v(e,r,{get:()=>t[r],enumerable:!(p=B(t,r))||p.enumerable});return e};var K=e=>z(v({},"__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 k(e,t){return typeof e=="object"&&e!==null&&e.protocol===w&&e.channel===t&&typeof e.kind=="string"}function I(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=T(),i=document.createElement("div");i.style.position="relative";let s=document.createElement("iframe");s.src=`${e}#${I({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,m=u=>{s.contentWindow?.postMessage({...u,protocol:w,channel:o},r)},A=u=>{u?(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,E=()=>{if(!h){h=!0,window.removeEventListener("message",x);for(let u of d.values())u.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));d.clear(),i.remove()}},y=null;function x(u){if(u.source!==s.contentWindow||u.origin!==r||!k(u.data,o))return;let c=u.data;switch(c.kind){case"ready":m({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((u,c)=>{let g=setTimeout(()=>{y?.(new a("No se pudo cargar el formulario de tarjeta.","FIELDS_TIMEOUT"))},Y);y=S=>{if(y=null,clearTimeout(g),S instanceof a){E(),c(S);return}u({session:S,pay(){if(h)return Promise.reject(new a("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));let P=T();return new Promise((D,j)=>{d.set(P,{resolve:D,reject:j}),m({kind:"pay",requestId: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 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(m){throw new a("No se pudo conectar con Crosspay.","NETWORK_ERROR",m)}let d=await l.json().catch(()=>null);if(!l.ok||d?.success===!1){let m=d?.message||d?.error||`Crosspay respondio ${l.status}.`;throw new a(m,`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}`:"",b()].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 b(){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:b(),...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.3.0";0&&(module.exports={API_BASE_URLS,CrosspayError,FIELDS_URLS,init,version});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,100 @@
|
|
|
1
|
+
interface HttpClientOptions {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
locale?: string;
|
|
4
|
+
fetch?: typeof fetch;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Cliente HTTP minimo sobre `fetch`.
|
|
8
|
+
*
|
|
9
|
+
* Desde el navegador NO se manda la llave secreta: el backend reconoce al
|
|
10
|
+
* comercio por su llave publica, el `Origin` de su dominio autorizado y la
|
|
11
|
+
* sesion que creo su servidor. La llave secreta solo va en `@crosspay-lb/node`.
|
|
12
|
+
*
|
|
13
|
+
* El backend responde `{ success, data }`; aqui se desenvuelve `data` y un
|
|
14
|
+
* `success: false` se convierte en `CrosspayError`.
|
|
15
|
+
*/
|
|
16
|
+
declare function createHttpClient(options: HttpClientOptions): {
|
|
17
|
+
get: <T>(path: string) => Promise<T>;
|
|
18
|
+
post: <T>(path: string, body: unknown) => Promise<T>;
|
|
19
|
+
/** Sin desenvolver: para respuestas planas como la del cobro. */
|
|
20
|
+
postRaw: (path: string, body: unknown) => Promise<{
|
|
21
|
+
success?: boolean;
|
|
22
|
+
data?: unknown;
|
|
23
|
+
message?: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
} | null>;
|
|
26
|
+
};
|
|
27
|
+
type HttpClient = ReturnType<typeof createHttpClient>;
|
|
28
|
+
|
|
29
|
+
type PaymentStatus = 'approved' | 'pending' | 'declined' | 'failed' | 'cancelled' | 'refunded' | (string & {});
|
|
30
|
+
interface PaymentResult {
|
|
31
|
+
success: boolean;
|
|
32
|
+
status: PaymentStatus;
|
|
33
|
+
message?: string;
|
|
34
|
+
transactionId: string | null;
|
|
35
|
+
sessionId?: string;
|
|
36
|
+
/** PSE: URL del banco a la que hay que llevar al pagador. */
|
|
37
|
+
redirectUrl?: string;
|
|
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;
|
|
43
|
+
amount?: number;
|
|
44
|
+
currency?: string;
|
|
45
|
+
reference?: string;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
interface Bank {
|
|
49
|
+
code: string;
|
|
50
|
+
name: string;
|
|
51
|
+
}
|
|
52
|
+
interface PsePayInput {
|
|
53
|
+
/** `clientSecret` de la sesion creada por el servidor del comercio. */
|
|
54
|
+
clientSecret: string;
|
|
55
|
+
/** Codigo del banco, de `pse.listBanks()`. */
|
|
56
|
+
bank: string;
|
|
57
|
+
documentType: string;
|
|
58
|
+
documentNumber: string;
|
|
59
|
+
/** `natural` o `juridica`. */
|
|
60
|
+
personType: string;
|
|
61
|
+
/** Direccion del pagador. Obligatoria para PSE. */
|
|
62
|
+
address?: string;
|
|
63
|
+
}
|
|
64
|
+
declare function createPaymentsApi(http: HttpClient): {
|
|
65
|
+
/** Estado publico de una transaccion (el mismo recurso del comprobante). */
|
|
66
|
+
status(transactionId: string): Promise<PaymentResult>;
|
|
67
|
+
};
|
|
68
|
+
declare function createPseApi(http: HttpClient, publishableKey: string): {
|
|
69
|
+
/** Bancos PSE (Colombia). Se quita la entrada guia "seleccione su banco". */
|
|
70
|
+
listBanks(currency?: string): Promise<Bank[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Inicia el pago PSE de la sesion. Devuelve `redirectUrl`: hay que llevar
|
|
73
|
+
* al pagador al banco. Monto y cliente salen de la sesion.
|
|
74
|
+
*/
|
|
75
|
+
pay(input: PsePayInput): Promise<PaymentResult>;
|
|
76
|
+
};
|
|
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
|
+
}
|
|
84
|
+
/** Lo que la pagina de campos confirma de la sesion al montar. */
|
|
85
|
+
interface SessionSummary {
|
|
86
|
+
sessionId: string;
|
|
87
|
+
amount: number;
|
|
88
|
+
currency: string;
|
|
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;
|
|
96
|
+
}
|
|
97
|
+
|
|
1
98
|
interface CardFieldLabels {
|
|
2
99
|
cardholderName?: string;
|
|
3
100
|
cardNumber?: string;
|
|
@@ -8,12 +105,12 @@ interface CardFieldLabels {
|
|
|
8
105
|
interface CardFieldsOptions {
|
|
9
106
|
/** Donde se inserta el formulario: un selector CSS o el elemento. */
|
|
10
107
|
container: string | HTMLElement;
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
108
|
+
/**
|
|
109
|
+
* `clientSecret` de la sesion de pago que creo el SERVIDOR del comercio con
|
|
110
|
+
* su llave secreta (`sessions.create` de @crosspay-lb/node). Monto, moneda y
|
|
111
|
+
* cliente salen de la sesion: el navegador no puede cambiarlos.
|
|
112
|
+
*/
|
|
113
|
+
clientSecret: string;
|
|
17
114
|
/** Muestra el selector de cuotas. */
|
|
18
115
|
installments?: boolean;
|
|
19
116
|
labels?: CardFieldLabels;
|
|
@@ -26,25 +123,15 @@ interface CardFieldsOptions {
|
|
|
26
123
|
/** Se dispara cada vez que cambia la validez del formulario. */
|
|
27
124
|
onValidityChange?: (isValid: boolean) => void;
|
|
28
125
|
}
|
|
29
|
-
/** Token de un solo uso. Nunca contiene el numero de tarjeta. */
|
|
30
|
-
interface CardToken {
|
|
31
|
-
token: string;
|
|
32
|
-
deferred?: {
|
|
33
|
-
months?: number;
|
|
34
|
-
creditType?: string;
|
|
35
|
-
graceMonths?: number;
|
|
36
|
-
};
|
|
37
|
-
bin?: string;
|
|
38
|
-
lastFourDigits?: string;
|
|
39
|
-
brand?: string;
|
|
40
|
-
}
|
|
41
126
|
interface MountedCardFields {
|
|
127
|
+
/** Monto, moneda y descripcion de la sesion que se va a pagar. */
|
|
128
|
+
readonly session: SessionSummary;
|
|
42
129
|
/**
|
|
43
|
-
*
|
|
44
|
-
* completa, asi que puede tardar. Lanza `CrosspayError` si la
|
|
45
|
-
* rechaza.
|
|
130
|
+
* Tokeniza y cobra la sesion. Puede abrir la verificacion 3DS del banco a
|
|
131
|
+
* pantalla completa, asi que puede tardar. Lanza `CrosspayError` si la
|
|
132
|
+
* tarjeta se rechaza o la sesion ya no se puede pagar.
|
|
46
133
|
*/
|
|
47
|
-
|
|
134
|
+
pay(): Promise<PaymentResult>;
|
|
48
135
|
/** Retira el formulario. */
|
|
49
136
|
destroy(): void;
|
|
50
137
|
}
|
|
@@ -66,115 +153,16 @@ declare const API_BASE_URLS: Record<CrosspayEnvironment, string>;
|
|
|
66
153
|
*/
|
|
67
154
|
declare const FIELDS_URLS: Record<CrosspayEnvironment, string>;
|
|
68
155
|
|
|
69
|
-
interface HttpClientOptions {
|
|
70
|
-
baseUrl: string;
|
|
71
|
-
/** Id publico de la empresa (20 digitos). Viaja como `X-Company-Id`. */
|
|
72
|
-
companyId?: string;
|
|
73
|
-
locale?: string;
|
|
74
|
-
fetch?: typeof fetch;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Cliente HTTP minimo sobre `fetch`.
|
|
78
|
-
*
|
|
79
|
-
* Desde el navegador NO se manda API key: el backend autentica por el `Origin`
|
|
80
|
-
* del sitio del comercio, que debe estar registrado en el CORS de su empresa.
|
|
81
|
-
* La API key de integracion es secreta y solo va en `@crosspay-lb/node`.
|
|
82
|
-
*
|
|
83
|
-
* El backend responde `{ success, data }`; aqui se desenvuelve `data` y un
|
|
84
|
-
* `success: false` se convierte en `CrosspayError`.
|
|
85
|
-
*/
|
|
86
|
-
declare function createHttpClient(options: HttpClientOptions): {
|
|
87
|
-
get: <T>(path: string) => Promise<T>;
|
|
88
|
-
post: <T>(path: string, body: unknown) => Promise<T>;
|
|
89
|
-
};
|
|
90
|
-
type HttpClient = ReturnType<typeof createHttpClient>;
|
|
91
|
-
|
|
92
|
-
interface Customer {
|
|
93
|
-
firstName: string;
|
|
94
|
-
lastName: string;
|
|
95
|
-
email: string;
|
|
96
|
-
phone?: string;
|
|
97
|
-
documentType?: string;
|
|
98
|
-
documentNumber?: string;
|
|
99
|
-
}
|
|
100
|
-
interface PseData {
|
|
101
|
-
/** Codigo del banco, de `pse.listBanks()`. */
|
|
102
|
-
bank: string;
|
|
103
|
-
documentType: string;
|
|
104
|
-
documentNumber: string;
|
|
105
|
-
/** `natural` o `juridica`. */
|
|
106
|
-
personType: string;
|
|
107
|
-
/** Direccion del pagador. Obligatoria para PSE. */
|
|
108
|
-
address?: string;
|
|
109
|
-
}
|
|
110
|
-
interface BasePaymentInput {
|
|
111
|
-
amount: number;
|
|
112
|
-
currency: string;
|
|
113
|
-
description: string;
|
|
114
|
-
/** Referencia del comercio (numero de orden, factura…). */
|
|
115
|
-
reference?: string;
|
|
116
|
-
customer: Customer;
|
|
117
|
-
/** A donde vuelve el pagador cuando el medio lo saca de la pagina (PSE, 3DS). */
|
|
118
|
-
returnUrl?: string;
|
|
119
|
-
/** Datos libres del comercio. Viajan en `meta`. */
|
|
120
|
-
metadata?: Record<string, unknown>;
|
|
121
|
-
}
|
|
122
|
-
interface CardPaymentInput extends BasePaymentInput {
|
|
123
|
-
method: 'card';
|
|
124
|
-
cardToken: CardToken;
|
|
125
|
-
}
|
|
126
|
-
interface PsePaymentInput extends BasePaymentInput {
|
|
127
|
-
method: 'pse';
|
|
128
|
-
pse: PseData;
|
|
129
|
-
}
|
|
130
|
-
type PaymentInput = CardPaymentInput | PsePaymentInput;
|
|
131
|
-
type PaymentStatus = 'approved' | 'pending' | 'declined' | 'failed' | 'cancelled' | 'refunded' | (string & {});
|
|
132
|
-
interface PaymentResult {
|
|
133
|
-
success: boolean;
|
|
134
|
-
status: PaymentStatus;
|
|
135
|
-
message?: string;
|
|
136
|
-
transactionId: string | null;
|
|
137
|
-
gatewayTransactionId?: string | null;
|
|
138
|
-
/** PSE: URL del banco a la que hay que llevar al pagador. */
|
|
139
|
-
redirectUrl?: string;
|
|
140
|
-
declineReason?: string | null;
|
|
141
|
-
amount?: number;
|
|
142
|
-
currency?: string;
|
|
143
|
-
reference?: string;
|
|
144
|
-
[key: string]: unknown;
|
|
145
|
-
}
|
|
146
|
-
interface Bank {
|
|
147
|
-
code: string;
|
|
148
|
-
name: string;
|
|
149
|
-
}
|
|
150
|
-
declare function createPaymentsApi(http: HttpClient): {
|
|
151
|
-
/** Crea el cobro. Para tarjeta, el `cardToken` sale de `card.tokenize()`. */
|
|
152
|
-
create(input: PaymentInput): Promise<PaymentResult>;
|
|
153
|
-
/**
|
|
154
|
-
* Registra un rechazo en la tokenizacion como transaccion declinada, para
|
|
155
|
-
* trazabilidad. No cobra nada ni lleva datos de tarjeta.
|
|
156
|
-
*/
|
|
157
|
-
reportTokenizationDecline(input: Omit<CardPaymentInput, "cardToken">, decline: {
|
|
158
|
-
code?: string;
|
|
159
|
-
message?: string;
|
|
160
|
-
}): Promise<PaymentResult>;
|
|
161
|
-
/** Estado publico de una transaccion (el mismo recurso del comprobante). */
|
|
162
|
-
status(transactionId: string): Promise<PaymentResult>;
|
|
163
|
-
};
|
|
164
|
-
declare function createPseApi(http: HttpClient): {
|
|
165
|
-
/** Bancos PSE (Colombia). Se quita la entrada guia "seleccione su banco". */
|
|
166
|
-
listBanks(currency?: string): Promise<Bank[]>;
|
|
167
|
-
};
|
|
168
|
-
|
|
169
156
|
interface CrosspayOptions {
|
|
170
157
|
/** `development` → api-dev.crosspaysolutions.financial · `production` → api.crosspaysolutions.financial */
|
|
171
158
|
environment: CrosspayEnvironment;
|
|
172
159
|
/**
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* del
|
|
160
|
+
* Llave publica del comercio (panel → Integracion). `pk_test_…` en
|
|
161
|
+
* development, `pk_live_…` en production. Es publica por diseno: solo
|
|
162
|
+
* funciona desde los dominios autorizados del comercio y con una sesion
|
|
163
|
+
* creada por su servidor.
|
|
176
164
|
*/
|
|
177
|
-
|
|
165
|
+
publishableKey: string;
|
|
178
166
|
/** Idioma de los correos al pagador (`es`, `en`…). */
|
|
179
167
|
locale?: string;
|
|
180
168
|
/** Para pruebas. Por defecto, el `fetch` del navegador. */
|
|
@@ -190,18 +178,13 @@ interface Crosspay {
|
|
|
190
178
|
readonly environment: CrosspayEnvironment;
|
|
191
179
|
card: {
|
|
192
180
|
/**
|
|
193
|
-
* Monta el formulario seguro de tarjeta en `options.container
|
|
194
|
-
* con `
|
|
181
|
+
* Monta el formulario seguro de tarjeta en `options.container` para la
|
|
182
|
+
* sesion `options.clientSecret`. Rechaza con `CrosspayError` si la llave,
|
|
183
|
+
* la sesion o el dominio no son validos.
|
|
195
184
|
*/
|
|
196
185
|
mount(options: CardFieldsOptions): Promise<MountedCardFields>;
|
|
197
186
|
};
|
|
198
|
-
payments: ReturnType<typeof createPaymentsApi
|
|
199
|
-
/**
|
|
200
|
-
* Atajo: tokeniza y cobra. Si la tarjeta se rechaza al tokenizar, deja
|
|
201
|
-
* registrada la transaccion declinada y relanza el `CrosspayError`.
|
|
202
|
-
*/
|
|
203
|
-
payWithCard(fields: MountedCardFields, input: Omit<CardPaymentInput, 'cardToken' | 'method'>): Promise<PaymentResult>;
|
|
204
|
-
};
|
|
187
|
+
payments: ReturnType<typeof createPaymentsApi>;
|
|
205
188
|
pse: ReturnType<typeof createPseApi>;
|
|
206
189
|
}
|
|
207
190
|
declare function init(options: CrosspayOptions): Crosspay;
|
|
@@ -222,4 +205,4 @@ declare class CrosspayError extends Error {
|
|
|
222
205
|
/** Version de la libreria, inyectada en el build. */
|
|
223
206
|
declare const version: string;
|
|
224
207
|
|
|
225
|
-
export { API_BASE_URLS, type Bank, type CardFieldLabels, type CardFieldsOptions, type
|
|
208
|
+
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,100 @@
|
|
|
1
|
+
interface HttpClientOptions {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
locale?: string;
|
|
4
|
+
fetch?: typeof fetch;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Cliente HTTP minimo sobre `fetch`.
|
|
8
|
+
*
|
|
9
|
+
* Desde el navegador NO se manda la llave secreta: el backend reconoce al
|
|
10
|
+
* comercio por su llave publica, el `Origin` de su dominio autorizado y la
|
|
11
|
+
* sesion que creo su servidor. La llave secreta solo va en `@crosspay-lb/node`.
|
|
12
|
+
*
|
|
13
|
+
* El backend responde `{ success, data }`; aqui se desenvuelve `data` y un
|
|
14
|
+
* `success: false` se convierte en `CrosspayError`.
|
|
15
|
+
*/
|
|
16
|
+
declare function createHttpClient(options: HttpClientOptions): {
|
|
17
|
+
get: <T>(path: string) => Promise<T>;
|
|
18
|
+
post: <T>(path: string, body: unknown) => Promise<T>;
|
|
19
|
+
/** Sin desenvolver: para respuestas planas como la del cobro. */
|
|
20
|
+
postRaw: (path: string, body: unknown) => Promise<{
|
|
21
|
+
success?: boolean;
|
|
22
|
+
data?: unknown;
|
|
23
|
+
message?: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
} | null>;
|
|
26
|
+
};
|
|
27
|
+
type HttpClient = ReturnType<typeof createHttpClient>;
|
|
28
|
+
|
|
29
|
+
type PaymentStatus = 'approved' | 'pending' | 'declined' | 'failed' | 'cancelled' | 'refunded' | (string & {});
|
|
30
|
+
interface PaymentResult {
|
|
31
|
+
success: boolean;
|
|
32
|
+
status: PaymentStatus;
|
|
33
|
+
message?: string;
|
|
34
|
+
transactionId: string | null;
|
|
35
|
+
sessionId?: string;
|
|
36
|
+
/** PSE: URL del banco a la que hay que llevar al pagador. */
|
|
37
|
+
redirectUrl?: string;
|
|
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;
|
|
43
|
+
amount?: number;
|
|
44
|
+
currency?: string;
|
|
45
|
+
reference?: string;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
interface Bank {
|
|
49
|
+
code: string;
|
|
50
|
+
name: string;
|
|
51
|
+
}
|
|
52
|
+
interface PsePayInput {
|
|
53
|
+
/** `clientSecret` de la sesion creada por el servidor del comercio. */
|
|
54
|
+
clientSecret: string;
|
|
55
|
+
/** Codigo del banco, de `pse.listBanks()`. */
|
|
56
|
+
bank: string;
|
|
57
|
+
documentType: string;
|
|
58
|
+
documentNumber: string;
|
|
59
|
+
/** `natural` o `juridica`. */
|
|
60
|
+
personType: string;
|
|
61
|
+
/** Direccion del pagador. Obligatoria para PSE. */
|
|
62
|
+
address?: string;
|
|
63
|
+
}
|
|
64
|
+
declare function createPaymentsApi(http: HttpClient): {
|
|
65
|
+
/** Estado publico de una transaccion (el mismo recurso del comprobante). */
|
|
66
|
+
status(transactionId: string): Promise<PaymentResult>;
|
|
67
|
+
};
|
|
68
|
+
declare function createPseApi(http: HttpClient, publishableKey: string): {
|
|
69
|
+
/** Bancos PSE (Colombia). Se quita la entrada guia "seleccione su banco". */
|
|
70
|
+
listBanks(currency?: string): Promise<Bank[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Inicia el pago PSE de la sesion. Devuelve `redirectUrl`: hay que llevar
|
|
73
|
+
* al pagador al banco. Monto y cliente salen de la sesion.
|
|
74
|
+
*/
|
|
75
|
+
pay(input: PsePayInput): Promise<PaymentResult>;
|
|
76
|
+
};
|
|
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
|
+
}
|
|
84
|
+
/** Lo que la pagina de campos confirma de la sesion al montar. */
|
|
85
|
+
interface SessionSummary {
|
|
86
|
+
sessionId: string;
|
|
87
|
+
amount: number;
|
|
88
|
+
currency: string;
|
|
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;
|
|
96
|
+
}
|
|
97
|
+
|
|
1
98
|
interface CardFieldLabels {
|
|
2
99
|
cardholderName?: string;
|
|
3
100
|
cardNumber?: string;
|
|
@@ -8,12 +105,12 @@ interface CardFieldLabels {
|
|
|
8
105
|
interface CardFieldsOptions {
|
|
9
106
|
/** Donde se inserta el formulario: un selector CSS o el elemento. */
|
|
10
107
|
container: string | HTMLElement;
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
108
|
+
/**
|
|
109
|
+
* `clientSecret` de la sesion de pago que creo el SERVIDOR del comercio con
|
|
110
|
+
* su llave secreta (`sessions.create` de @crosspay-lb/node). Monto, moneda y
|
|
111
|
+
* cliente salen de la sesion: el navegador no puede cambiarlos.
|
|
112
|
+
*/
|
|
113
|
+
clientSecret: string;
|
|
17
114
|
/** Muestra el selector de cuotas. */
|
|
18
115
|
installments?: boolean;
|
|
19
116
|
labels?: CardFieldLabels;
|
|
@@ -26,25 +123,15 @@ interface CardFieldsOptions {
|
|
|
26
123
|
/** Se dispara cada vez que cambia la validez del formulario. */
|
|
27
124
|
onValidityChange?: (isValid: boolean) => void;
|
|
28
125
|
}
|
|
29
|
-
/** Token de un solo uso. Nunca contiene el numero de tarjeta. */
|
|
30
|
-
interface CardToken {
|
|
31
|
-
token: string;
|
|
32
|
-
deferred?: {
|
|
33
|
-
months?: number;
|
|
34
|
-
creditType?: string;
|
|
35
|
-
graceMonths?: number;
|
|
36
|
-
};
|
|
37
|
-
bin?: string;
|
|
38
|
-
lastFourDigits?: string;
|
|
39
|
-
brand?: string;
|
|
40
|
-
}
|
|
41
126
|
interface MountedCardFields {
|
|
127
|
+
/** Monto, moneda y descripcion de la sesion que se va a pagar. */
|
|
128
|
+
readonly session: SessionSummary;
|
|
42
129
|
/**
|
|
43
|
-
*
|
|
44
|
-
* completa, asi que puede tardar. Lanza `CrosspayError` si la
|
|
45
|
-
* rechaza.
|
|
130
|
+
* Tokeniza y cobra la sesion. Puede abrir la verificacion 3DS del banco a
|
|
131
|
+
* pantalla completa, asi que puede tardar. Lanza `CrosspayError` si la
|
|
132
|
+
* tarjeta se rechaza o la sesion ya no se puede pagar.
|
|
46
133
|
*/
|
|
47
|
-
|
|
134
|
+
pay(): Promise<PaymentResult>;
|
|
48
135
|
/** Retira el formulario. */
|
|
49
136
|
destroy(): void;
|
|
50
137
|
}
|
|
@@ -66,115 +153,16 @@ declare const API_BASE_URLS: Record<CrosspayEnvironment, string>;
|
|
|
66
153
|
*/
|
|
67
154
|
declare const FIELDS_URLS: Record<CrosspayEnvironment, string>;
|
|
68
155
|
|
|
69
|
-
interface HttpClientOptions {
|
|
70
|
-
baseUrl: string;
|
|
71
|
-
/** Id publico de la empresa (20 digitos). Viaja como `X-Company-Id`. */
|
|
72
|
-
companyId?: string;
|
|
73
|
-
locale?: string;
|
|
74
|
-
fetch?: typeof fetch;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Cliente HTTP minimo sobre `fetch`.
|
|
78
|
-
*
|
|
79
|
-
* Desde el navegador NO se manda API key: el backend autentica por el `Origin`
|
|
80
|
-
* del sitio del comercio, que debe estar registrado en el CORS de su empresa.
|
|
81
|
-
* La API key de integracion es secreta y solo va en `@crosspay-lb/node`.
|
|
82
|
-
*
|
|
83
|
-
* El backend responde `{ success, data }`; aqui se desenvuelve `data` y un
|
|
84
|
-
* `success: false` se convierte en `CrosspayError`.
|
|
85
|
-
*/
|
|
86
|
-
declare function createHttpClient(options: HttpClientOptions): {
|
|
87
|
-
get: <T>(path: string) => Promise<T>;
|
|
88
|
-
post: <T>(path: string, body: unknown) => Promise<T>;
|
|
89
|
-
};
|
|
90
|
-
type HttpClient = ReturnType<typeof createHttpClient>;
|
|
91
|
-
|
|
92
|
-
interface Customer {
|
|
93
|
-
firstName: string;
|
|
94
|
-
lastName: string;
|
|
95
|
-
email: string;
|
|
96
|
-
phone?: string;
|
|
97
|
-
documentType?: string;
|
|
98
|
-
documentNumber?: string;
|
|
99
|
-
}
|
|
100
|
-
interface PseData {
|
|
101
|
-
/** Codigo del banco, de `pse.listBanks()`. */
|
|
102
|
-
bank: string;
|
|
103
|
-
documentType: string;
|
|
104
|
-
documentNumber: string;
|
|
105
|
-
/** `natural` o `juridica`. */
|
|
106
|
-
personType: string;
|
|
107
|
-
/** Direccion del pagador. Obligatoria para PSE. */
|
|
108
|
-
address?: string;
|
|
109
|
-
}
|
|
110
|
-
interface BasePaymentInput {
|
|
111
|
-
amount: number;
|
|
112
|
-
currency: string;
|
|
113
|
-
description: string;
|
|
114
|
-
/** Referencia del comercio (numero de orden, factura…). */
|
|
115
|
-
reference?: string;
|
|
116
|
-
customer: Customer;
|
|
117
|
-
/** A donde vuelve el pagador cuando el medio lo saca de la pagina (PSE, 3DS). */
|
|
118
|
-
returnUrl?: string;
|
|
119
|
-
/** Datos libres del comercio. Viajan en `meta`. */
|
|
120
|
-
metadata?: Record<string, unknown>;
|
|
121
|
-
}
|
|
122
|
-
interface CardPaymentInput extends BasePaymentInput {
|
|
123
|
-
method: 'card';
|
|
124
|
-
cardToken: CardToken;
|
|
125
|
-
}
|
|
126
|
-
interface PsePaymentInput extends BasePaymentInput {
|
|
127
|
-
method: 'pse';
|
|
128
|
-
pse: PseData;
|
|
129
|
-
}
|
|
130
|
-
type PaymentInput = CardPaymentInput | PsePaymentInput;
|
|
131
|
-
type PaymentStatus = 'approved' | 'pending' | 'declined' | 'failed' | 'cancelled' | 'refunded' | (string & {});
|
|
132
|
-
interface PaymentResult {
|
|
133
|
-
success: boolean;
|
|
134
|
-
status: PaymentStatus;
|
|
135
|
-
message?: string;
|
|
136
|
-
transactionId: string | null;
|
|
137
|
-
gatewayTransactionId?: string | null;
|
|
138
|
-
/** PSE: URL del banco a la que hay que llevar al pagador. */
|
|
139
|
-
redirectUrl?: string;
|
|
140
|
-
declineReason?: string | null;
|
|
141
|
-
amount?: number;
|
|
142
|
-
currency?: string;
|
|
143
|
-
reference?: string;
|
|
144
|
-
[key: string]: unknown;
|
|
145
|
-
}
|
|
146
|
-
interface Bank {
|
|
147
|
-
code: string;
|
|
148
|
-
name: string;
|
|
149
|
-
}
|
|
150
|
-
declare function createPaymentsApi(http: HttpClient): {
|
|
151
|
-
/** Crea el cobro. Para tarjeta, el `cardToken` sale de `card.tokenize()`. */
|
|
152
|
-
create(input: PaymentInput): Promise<PaymentResult>;
|
|
153
|
-
/**
|
|
154
|
-
* Registra un rechazo en la tokenizacion como transaccion declinada, para
|
|
155
|
-
* trazabilidad. No cobra nada ni lleva datos de tarjeta.
|
|
156
|
-
*/
|
|
157
|
-
reportTokenizationDecline(input: Omit<CardPaymentInput, "cardToken">, decline: {
|
|
158
|
-
code?: string;
|
|
159
|
-
message?: string;
|
|
160
|
-
}): Promise<PaymentResult>;
|
|
161
|
-
/** Estado publico de una transaccion (el mismo recurso del comprobante). */
|
|
162
|
-
status(transactionId: string): Promise<PaymentResult>;
|
|
163
|
-
};
|
|
164
|
-
declare function createPseApi(http: HttpClient): {
|
|
165
|
-
/** Bancos PSE (Colombia). Se quita la entrada guia "seleccione su banco". */
|
|
166
|
-
listBanks(currency?: string): Promise<Bank[]>;
|
|
167
|
-
};
|
|
168
|
-
|
|
169
156
|
interface CrosspayOptions {
|
|
170
157
|
/** `development` → api-dev.crosspaysolutions.financial · `production` → api.crosspaysolutions.financial */
|
|
171
158
|
environment: CrosspayEnvironment;
|
|
172
159
|
/**
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
* del
|
|
160
|
+
* Llave publica del comercio (panel → Integracion). `pk_test_…` en
|
|
161
|
+
* development, `pk_live_…` en production. Es publica por diseno: solo
|
|
162
|
+
* funciona desde los dominios autorizados del comercio y con una sesion
|
|
163
|
+
* creada por su servidor.
|
|
176
164
|
*/
|
|
177
|
-
|
|
165
|
+
publishableKey: string;
|
|
178
166
|
/** Idioma de los correos al pagador (`es`, `en`…). */
|
|
179
167
|
locale?: string;
|
|
180
168
|
/** Para pruebas. Por defecto, el `fetch` del navegador. */
|
|
@@ -190,18 +178,13 @@ interface Crosspay {
|
|
|
190
178
|
readonly environment: CrosspayEnvironment;
|
|
191
179
|
card: {
|
|
192
180
|
/**
|
|
193
|
-
* Monta el formulario seguro de tarjeta en `options.container
|
|
194
|
-
* con `
|
|
181
|
+
* Monta el formulario seguro de tarjeta en `options.container` para la
|
|
182
|
+
* sesion `options.clientSecret`. Rechaza con `CrosspayError` si la llave,
|
|
183
|
+
* la sesion o el dominio no son validos.
|
|
195
184
|
*/
|
|
196
185
|
mount(options: CardFieldsOptions): Promise<MountedCardFields>;
|
|
197
186
|
};
|
|
198
|
-
payments: ReturnType<typeof createPaymentsApi
|
|
199
|
-
/**
|
|
200
|
-
* Atajo: tokeniza y cobra. Si la tarjeta se rechaza al tokenizar, deja
|
|
201
|
-
* registrada la transaccion declinada y relanza el `CrosspayError`.
|
|
202
|
-
*/
|
|
203
|
-
payWithCard(fields: MountedCardFields, input: Omit<CardPaymentInput, 'cardToken' | 'method'>): Promise<PaymentResult>;
|
|
204
|
-
};
|
|
187
|
+
payments: ReturnType<typeof createPaymentsApi>;
|
|
205
188
|
pse: ReturnType<typeof createPseApi>;
|
|
206
189
|
}
|
|
207
190
|
declare function init(options: CrosspayOptions): Crosspay;
|
|
@@ -222,4 +205,4 @@ declare class CrosspayError extends Error {
|
|
|
222
205
|
/** Version de la libreria, inyectada en el build. */
|
|
223
206
|
declare const version: string;
|
|
224
207
|
|
|
225
|
-
export { API_BASE_URLS, type Bank, type CardFieldLabels, type CardFieldsOptions, type
|
|
208
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var c=class extends Error{constructor(t,d,s){super(t);this.code=d;this.details=s;this.name="CrosspayError"}};var S="crosspay-fields/2";function x(e,r){return typeof e=="object"&&e!==null&&e.protocol===S&&e.channel===r&&typeof e.kind=="string"}function P(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 I(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=k(),i=document.createElement("div");i.style.position="relative";let n=document.createElement("iframe");n.src=`${e}#${P({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,m=u=>{n.contentWindow?.postMessage({...u,protocol:S,channel:o},s)},_=u=>{u?(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",b);for(let u of l.values())u.reject(new c("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));l.clear(),i.remove()}},y=null;function b(u){if(u.source!==n.contentWindow||u.origin!==s||!x(u.data,o))return;let a=u.data;switch(a.kind){case"ready":m({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",b),new Promise((u,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}u({session:h,pay(){if(f)return Promise.reject(new c("El formulario de tarjeta se retiro.","FIELDS_DESTROYED"));let E=k();return new Promise(($,A)=>{l.set(E,{resolve:$,reject:A}),m({kind:"pay",requestId:E})})},destroy:C})}})}function k(){return typeof crypto<"u"&&"randomUUID"in crypto?crypto.randomUUID():`${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`}var T={development:"https://api-dev.crosspaysolutions.financial",production:"https://api.crosspaysolutions.financial"};function R(e){let r=T[e];if(!r)throw new TypeError(`Ambiente de Crosspay no valido: "${String(e)}". Usa "development" o "production".`);return r}var v={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(m){throw new c("No se pudo conectar con Crosspay.","NETWORK_ERROR",m)}let l=await p.json().catch(()=>null);if(!p.ok||l?.success===!1){let m=l?.message||l?.error||`Crosspay respondio ${p.status}.`;throw new c(m,`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 N(){return typeof navigator>"u"?"":[navigator.userAgent,navigator.language,typeof screen<"u"?`${screen.width}x${screen.height}`:"",w()].join("|")}function q(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=q(N());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??v[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 I(s,t,i)}},payments:L(o),pse:M(o,t)}}var pe="0.3.0";export{T as API_BASE_URLS,c as CrosspayError,v as FIELDS_URLS,K as init,pe as version};
|
package/package.json
CHANGED