@rinnebr/js 0.1.0-alpha.12 → 0.1.0-alpha.17
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 +20 -14
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/index.umd.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -45,11 +45,9 @@ const rinne = new Rinne({
|
|
|
45
45
|
environment: 'production' // or 'sandbox'
|
|
46
46
|
})
|
|
47
47
|
|
|
48
|
-
// 2. Create a transaction
|
|
48
|
+
// 2. Create a transaction (currency and country default to 'BRL' and 'BR')
|
|
49
49
|
const transaction = await rinne.transaction.create({
|
|
50
50
|
amount: 1000, // Amount in cents
|
|
51
|
-
currency: 'BRL',
|
|
52
|
-
country: 'BR',
|
|
53
51
|
lineItems: [
|
|
54
52
|
{ label: 'Product Name', amount: 1000 }
|
|
55
53
|
]
|
|
@@ -64,7 +62,8 @@ const applePay = await rinne.elements.applePay(transaction, {
|
|
|
64
62
|
onCapture: async (payload, fail) => {
|
|
65
63
|
try {
|
|
66
64
|
// Send encrypted card data to your backend
|
|
67
|
-
|
|
65
|
+
// payload includes card_data, payment_method ('CREDIT_CARD' | 'DEBIT_CARD'), and transaction
|
|
66
|
+
await processPayment(payload.card_data, payload.payment_method, payload.transaction)
|
|
68
67
|
} catch (error) {
|
|
69
68
|
// Call fail() to notify the wallet dialog that payment processing failed
|
|
70
69
|
fail({ message: 'Payment processing failed' })
|
|
@@ -104,8 +103,8 @@ Every payment requires a transaction object that defines the payment amount, cur
|
|
|
104
103
|
```typescript
|
|
105
104
|
const transaction = await rinne.transaction.create({
|
|
106
105
|
amount: number // Required: Amount in cents (e.g., 1000 = $10.00)
|
|
107
|
-
currency
|
|
108
|
-
country?: string // Optional: ISO 3166 country code (
|
|
106
|
+
currency?: string // Optional: ISO 4217 currency code (default: 'BRL')
|
|
107
|
+
country?: string // Optional: ISO 3166 country code (default: 'BR')
|
|
109
108
|
lineItems?: Array<{ // Optional: Itemized list for wallet display
|
|
110
109
|
label: string // Line item description
|
|
111
110
|
amount: number // Line item amount in cents
|
|
@@ -152,18 +151,16 @@ Creates a new transaction for a payment.
|
|
|
152
151
|
|
|
153
152
|
**Parameters:**
|
|
154
153
|
- `amount: number` - Payment amount in cents
|
|
155
|
-
- `currency
|
|
156
|
-
- `country?: string` - ISO 3166 country code
|
|
154
|
+
- `currency?: string` - ISO 4217 currency code (default: `'BRL'`)
|
|
155
|
+
- `country?: string` - ISO 3166 country code (default: `'BR'`)
|
|
157
156
|
- `lineItems?: WalletLineItem[]` - Itemized breakdown
|
|
158
157
|
|
|
159
158
|
**Returns:** Transaction object to be used with payment elements
|
|
160
159
|
|
|
161
|
-
**
|
|
160
|
+
**Examples:**
|
|
162
161
|
```typescript
|
|
163
162
|
const transaction = await rinne.transaction.create({
|
|
164
163
|
amount: 5000,
|
|
165
|
-
currency: 'BRL',
|
|
166
|
-
country: 'BR',
|
|
167
164
|
lineItems: [
|
|
168
165
|
{ label: 'Subtotal', amount: 4500 },
|
|
169
166
|
{ label: 'Shipping', amount: 500 }
|
|
@@ -317,6 +314,7 @@ onCapture: (payload: WalletSuccessPayload, fail: (error) => void) => void
|
|
|
317
314
|
```typescript
|
|
318
315
|
{
|
|
319
316
|
card_data: CardData // Encrypted payment token and card details
|
|
317
|
+
payment_method: 'CREDIT_CARD' | 'DEBIT_CARD' // Card funding type
|
|
320
318
|
transaction: Transaction // Original transaction object
|
|
321
319
|
}
|
|
322
320
|
```
|
|
@@ -337,6 +335,12 @@ onCapture: (payload: WalletSuccessPayload, fail: (error) => void) => void
|
|
|
337
335
|
}
|
|
338
336
|
```
|
|
339
337
|
|
|
338
|
+
**Payment Method:**
|
|
339
|
+
- `'CREDIT_CARD'` - Credit card (default if funding type is not available)
|
|
340
|
+
- `'DEBIT_CARD'` - Debit card
|
|
341
|
+
|
|
342
|
+
The payment method is automatically determined from the card's funding type. If the funding type is not available in the wallet response, it defaults to `'CREDIT_CARD'`.
|
|
343
|
+
|
|
340
344
|
2. **`fail: (error: { message: string }) => void`**
|
|
341
345
|
|
|
342
346
|
**CRITICAL**: This callback must be called if payment processing fails on your backend. It notifies the wallet dialog to show an error state to the user and allows them to retry or cancel.
|
|
@@ -353,7 +357,8 @@ onCapture: async (payload, fail) => {
|
|
|
353
357
|
headers: { 'Content-Type': 'application/json' },
|
|
354
358
|
body: JSON.stringify({
|
|
355
359
|
cardData: payload.card_data,
|
|
356
|
-
|
|
360
|
+
paymentMethod: payload.payment_method,
|
|
361
|
+
amount: payload.transaction.details.amount
|
|
357
362
|
})
|
|
358
363
|
})
|
|
359
364
|
|
|
@@ -438,8 +443,8 @@ async function setupPayment() {
|
|
|
438
443
|
// Create transaction
|
|
439
444
|
const transaction = await rinne.transaction.create({
|
|
440
445
|
amount: 2500, // $25.00
|
|
441
|
-
currency: 'USD',
|
|
442
|
-
country: 'US',
|
|
446
|
+
currency: 'USD', // Override default 'BRL'
|
|
447
|
+
country: 'US', // Override default 'BR'
|
|
443
448
|
lineItems: [
|
|
444
449
|
{ label: 'Premium Subscription', amount: 2000 },
|
|
445
450
|
{ label: 'Tax', amount: 500 }
|
|
@@ -464,6 +469,7 @@ async function setupPayment() {
|
|
|
464
469
|
headers: { 'Content-Type': 'application/json' },
|
|
465
470
|
body: JSON.stringify({
|
|
466
471
|
cardData: payload.card_data,
|
|
472
|
+
paymentMethod: payload.payment_method,
|
|
467
473
|
transactionId: payload.transaction.id
|
|
468
474
|
})
|
|
469
475
|
})
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let e=null;async function o(){if(window.Evervault)return window.Evervault;try{return await async function(){return e||(e=new Promise((o,r)=>{const t=document.createElement("script");if(t.src="https://js.evervault.com/v2",t.onload=()=>o(),t.onerror=()=>{e=null,r()},!document.head)throw new Error("Expected document.head not to be null. Evervault.js requires a <head> element.");document.head.appendChild(t)}),e)}(),window.Evervault}catch{throw new Error("Failed to load Evervault.js")}}Promise.resolve().then(()=>{o()});const r={pt:{errors:{targetElementNotFound:"Elemento alvo não encontrado",failedToInitialize:"Falha ao inicializar Rinne SDK",failedToProcessApplePay:"Falha ao processar dados do Apple Pay",failedToProcessGooglePay:"Falha ao processar dados do Google Pay",applePayError:"Erro do Apple Pay",googlePayError:"Erro do Google Pay",failedToMountApplePay:"Falha ao montar botão do Apple Pay",failedToMountGooglePay:"Falha ao montar botão do Google Pay",failedToFetchConfig:"Falha ao buscar configuração do comerciante",invalidConfig:"Configuração de comerciante inválida: campos obrigatórios ausentes",configFetchFailed:"Falha ao buscar configuração",unknownError:"Erro desconhecido"}},en:{errors:{targetElementNotFound:"Target element not found",failedToInitialize:"Failed to initialize Rinne SDK",failedToProcessApplePay:"Failed to process Apple Pay data",failedToProcessGooglePay:"Failed to process Google Pay data",applePayError:"Apple Pay error occurred",googlePayError:"Google Pay error occurred",failedToMountApplePay:"Failed to mount Apple Pay button",failedToMountGooglePay:"Failed to mount Google Pay button",failedToFetchConfig:"Failed to fetch merchant config",invalidConfig:"Invalid merchant config: missing required fields",configFetchFailed:"Configuration fetch failed",unknownError:"Unknown error"}},es:{errors:{targetElementNotFound:"Elemento objetivo no encontrado",failedToInitialize:"Error al inicializar Rinne SDK",failedToProcessApplePay:"Error al procesar datos de Apple Pay",failedToProcessGooglePay:"Error al procesar datos de Google Pay",applePayError:"Error de Apple Pay",googlePayError:"Error de Google Pay",failedToMountApplePay:"Error al montar botón de Apple Pay",failedToMountGooglePay:"Error al montar botón de Google Pay",failedToFetchConfig:"Error al obtener configuración del comerciante",invalidConfig:"Configuración de comerciante inválida: faltan campos requeridos",configFetchFailed:"Error al obtener configuración",unknownError:"Error desconocido"}}};function t(e="pt"){return r[e]}const n={sandbox:"https://api-sandbox.rinne.com.br/core",production:"https://api.rinne.com.br/core"};function a(e){return String(e).padStart(2,"0")}function i(e){const o=String(e);return 2===o.length?`20${o}`:o}function s(e){if(void 0!==e)return 0===e?"0":e}function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let e=null;async function o(){if(window.Evervault)return window.Evervault;try{return await async function(){return e||(e=new Promise((o,r)=>{const t=document.createElement("script");if(t.src="https://js.evervault.com/v2",t.onload=()=>o(),t.onerror=()=>{e=null,r()},!document.head)throw new Error("Expected document.head not to be null. Evervault.js requires a <head> element.");document.head.appendChild(t)}),e)}(),window.Evervault}catch{throw new Error("Failed to load Evervault.js")}}Promise.resolve().then(()=>{o()});const r={pt:{errors:{targetElementNotFound:"Elemento alvo não encontrado",failedToInitialize:"Falha ao inicializar Rinne SDK",failedToProcessApplePay:"Falha ao processar dados do Apple Pay",failedToProcessGooglePay:"Falha ao processar dados do Google Pay",applePayError:"Erro do Apple Pay",googlePayError:"Erro do Google Pay",failedToMountApplePay:"Falha ao montar botão do Apple Pay",failedToMountGooglePay:"Falha ao montar botão do Google Pay",failedToFetchConfig:"Falha ao buscar configuração do comerciante",invalidConfig:"Configuração de comerciante inválida: campos obrigatórios ausentes",configFetchFailed:"Falha ao buscar configuração",unknownError:"Erro desconhecido"}},en:{errors:{targetElementNotFound:"Target element not found",failedToInitialize:"Failed to initialize Rinne SDK",failedToProcessApplePay:"Failed to process Apple Pay data",failedToProcessGooglePay:"Failed to process Google Pay data",applePayError:"Apple Pay error occurred",googlePayError:"Google Pay error occurred",failedToMountApplePay:"Failed to mount Apple Pay button",failedToMountGooglePay:"Failed to mount Google Pay button",failedToFetchConfig:"Failed to fetch merchant config",invalidConfig:"Invalid merchant config: missing required fields",configFetchFailed:"Configuration fetch failed",unknownError:"Unknown error"}},es:{errors:{targetElementNotFound:"Elemento objetivo no encontrado",failedToInitialize:"Error al inicializar Rinne SDK",failedToProcessApplePay:"Error al procesar datos de Apple Pay",failedToProcessGooglePay:"Error al procesar datos de Google Pay",applePayError:"Error de Apple Pay",googlePayError:"Error de Google Pay",failedToMountApplePay:"Error al montar botón de Apple Pay",failedToMountGooglePay:"Error al montar botón de Google Pay",failedToFetchConfig:"Error al obtener configuración del comerciante",invalidConfig:"Configuración de comerciante inválida: faltan campos requeridos",configFetchFailed:"Error al obtener configuración",unknownError:"Error desconocido"}}};function t(e="pt"){return r[e]}const n={sandbox:"https://api-sandbox.rinne.com.br/core/v1",production:"https://api.rinne.com.br/core/v1"};function a(e){return String(e).padStart(2,"0")}function i(e){const o=String(e);return 2===o.length?`20${o}`:o}function s(e,o,r){const t=(e.card.funding??"credit").toLowerCase(),n="APPLE_PAY"===r?function(e){const{networkToken:o,card:r,cryptogram:t,eci:n,paymentDataType:s,deviceManufacturerIdentifier:c}=e;return{network_token:o.number,expiry_month:a(o.expiry.month),expiry_year:i(o.expiry.year),cryptogram:t,eci:n,token_provider:o.tokenServiceProvider,brand:r.brand,device_id:c,authentication_type:"3DSecure"===s?"3DS":void 0,last_digits:r.lastFour,issuer:"issuer"in r?r.issuer:void 0,segment:"segment"in r?r.segment:void 0,country:"country"in r?r.country:void 0,wallet_type:"APPLE_PAY",display_name:r.displayName}}(e):function(e){if(!function(e){return"token"in e&&"tokenServiceProvider"in e.token}(e))throw new Error("Google Pay response must contain a network token (3DS authentication)");const{token:o,card:r,cryptogram:t,eci:n}=e;return{network_token:o.number,expiry_month:a(o.expiry.month),expiry_year:i(o.expiry.year),cryptogram:t,eci:n??null,token_provider:o.tokenServiceProvider,brand:r.brand,authentication_type:"3DS",last_digits:r.lastFour,issuer:"issuer"in r?r.issuer:void 0,segment:"segment"in r?r.segment:void 0,country:"country"in r?r.country:void 0,wallet_type:"GOOGLE_PAY",display_name:r.displayName}}(e);return{card_data:n,payment_method:"debit"===t?"DEBIT_CARD":"CREDIT_CARD",transaction:o}}function c(e){if(void 0!==e)return 0===e?"0":e}function l(e){return{pt:"pt-BR",en:"en-US",es:"es-ES"}[e]}function d(e,o="pt"){if("string"==typeof e){const r=document.querySelector(e);if(!r){const r=t(o).errors.targetElementNotFound;throw new Error(`${r}: ${e}`)}return r}return e}function u(e,o,r){return{code:e,message:o,details:r}}exports.Rinne=class{constructor(e){this.options=e,this.transaction=this.createTransactionNamespace(),this.elements=this.createElementsNamespace()}config=null;evervault=null;initPromise=null;transaction;elements;async initialize(){return this.initPromise||(this.initPromise=(async()=>{try{const e=await async function(e){const o=t("pt"),r=`${e.baseUrl??n[e.environment??"production"]}/merchants/${e.merchantId}/public-settings`;try{const e=await fetch(r);if(!e.ok){const r=String(e.status);throw new Error(`${o.errors.failedToFetchConfig}: ${r} ${e.statusText}`)}const t=await e.json();if(!t.merchant_id||!t.team_id||!t.app_id)throw new Error(o.errors.invalidConfig);return{merchantId:t.merchant_id,teamId:t.team_id,appId:t.app_id,availableMethods:t.available_methods,name:t.name}}catch(a){if(a instanceof Error)throw new Error(`${o.errors.configFetchFailed}: ${a.message}`);throw new Error(`${o.errors.configFetchFailed}: ${o.errors.unknownError}`)}}({merchantId:this.options.merchantId,environment:this.options.environment??"production",baseUrl:this.options.rinneUrl});this.config=e,this.evervault=await async function(e,r,t){return new(await o())(e,r,t)}(this.config.teamId,this.config.appId)}catch(e){throw this.initPromise=null,e}})()),this.initPromise}createElementsNamespace(){return{applePay:async(e,o)=>{if(await this.initialize(),!this.evervault||!this.config){const e=t(o.button?.locale??"pt");throw new Error(e.errors.failedToInitialize)}const r=(n=this.evervault,this.config,(e,o)=>{let r=!1,a=!1;const i=o.button?.locale??"pt",p=t(i),h=o.button?.size??{width:"100%",height:"40px"},{width:y,height:m}=h,f={locale:l(o.button?.locale??"pt"),type:(P=o.button?.type??"plain",{book:"book",buy:"buy",checkout:"check-out",donate:"donate",order:"order",pay:"pay",plain:"plain",subscribe:"subscribe"}[P]),style:(g=o.button?.color??"black","white"===g?"white-outline":g),borderRadius:c(o.button?.borderRadius),...!!y&&!!m&&{size:{width:y,height:m}},process:async(t,n)=>{if(a||r)return Promise.resolve();try{r=!0;const i=s(t,e,"APPLE_PAY");let c=!1;const l=e=>{c=!0,n.fail(e)};return await(o.onCapture?.(i,l)),void(c||(a=!0))}catch(i){return n.fail({message:i instanceof Error?i.message:p.errors.failedToProcessApplePay}),Promise.resolve()}finally{a||(r=!1)}}};var g,P;const v=n.ui.applePay(e,f);return v.on("error",(...e)=>{if(r)return;r=!0;const t="string"==typeof e[0]?e[0]:void 0;if("CANCELLED"===t?.toUpperCase())return r=!1,void o.onCancel?.();const n={code:"PROVIDER_ERROR",message:t??p.errors.applePayError};o.onError?.(n)}),v.on("cancel",()=>{r=!1,o.onCancel?.()}),Promise.resolve({async mount(e){try{const o=d(e,i);return await v.mount(o),{unmount:()=>{v.unmount()}}}catch(r){const e=u("PROVIDER_ERROR",r instanceof Error?r.message:p.errors.failedToMountApplePay,r);throw o.onError&&o.onError(e),r}}})});var n;return r(e,o)},googlePay:async(e,o)=>{if(await this.initialize(),!this.evervault||!this.config){const e=t(o.button?.locale??"pt");throw new Error(e.errors.failedToInitialize)}const r=(n=this.evervault,this.config,(e,o)=>{let r=!1,a=!1;const i=o.button?.locale??"pt",l=t(i),p=o.button?.size??{width:"100%",height:"40px"},{width:h,height:y}=p,m={locale:o.button?.locale??"pt",type:o.button?.type??"plain",color:o.button?.color??"black",borderRadius:c(o.button?.borderRadius),...!!h&&!!y&&{size:{width:h,height:y}},allowedAuthMethods:["CRYPTOGRAM_3DS"],process:async(t,n)=>{if(a||r)return Promise.resolve();try{r=!0;const i=s(t,e,"GOOGLE_PAY");let c=!1;const l=e=>{c=!0,n.fail(e)};return await(o.onCapture?.(i,l)),void(c||(a=!0))}catch(i){return n.fail({message:i instanceof Error?i.message:l.errors.failedToProcessGooglePay}),Promise.resolve()}finally{a||(r=!1)}}},f=n.ui.googlePay(e,m);return f.on("error",(...e)=>{if(r)return;r=!0;const t={code:"PROVIDER_ERROR",message:("string"==typeof e[0]?e[0]:void 0)??l.errors.googlePayError};o.onError?.(t)}),f.on("cancel",()=>{r=!1,o.onCancel?.()}),Promise.resolve({mount(e){try{const o=d(e,i);return f.mount(o),Promise.resolve({unmount:()=>{f.unmount()}})}catch(r){const e=u("PROVIDER_ERROR",r instanceof Error?r.message:l.errors.failedToMountGooglePay,r);throw o.onError&&o.onError(e),r}}})});var n;return r(e,o)}}}createTransactionNamespace(){return{create:async e=>{if(await this.initialize(),!this.evervault||!this.config?.merchantId){const e=t("pt");throw new Error(e.errors.failedToInitialize)}return this.evervault.transactions.create({type:"payment",...e,country:e.country??"BR",currency:e.currency??"BRL",merchantId:this.config.merchantId,priceLabel:this.config.name})}}}};
|
package/dist/index.d.ts
CHANGED
|
@@ -76,7 +76,7 @@ export declare class Rinne {
|
|
|
76
76
|
|
|
77
77
|
export declare interface TransactionCreateParams {
|
|
78
78
|
amount: number;
|
|
79
|
-
currency
|
|
79
|
+
currency?: string;
|
|
80
80
|
country?: string;
|
|
81
81
|
lineItems?: WalletLineItem[];
|
|
82
82
|
}
|
|
@@ -125,6 +125,7 @@ export declare type WalletLocale = 'pt' | 'en' | 'es';
|
|
|
125
125
|
|
|
126
126
|
export declare interface WalletSuccessPayload {
|
|
127
127
|
card_data: CardData;
|
|
128
|
+
payment_method: 'DEBIT_CARD' | 'CREDIT_CARD';
|
|
128
129
|
transaction: EvTransaction;
|
|
129
130
|
}
|
|
130
131
|
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let e=null;async function o(){if(window.Evervault)return window.Evervault;try{return await async function(){return e||(e=new Promise((o,r)=>{const t=document.createElement("script");if(t.src="https://js.evervault.com/v2",t.onload=()=>o(),t.onerror=()=>{e=null,r()},!document.head)throw new Error("Expected document.head not to be null. Evervault.js requires a <head> element.");document.head.appendChild(t)}),e)}(),window.Evervault}catch{throw new Error("Failed to load Evervault.js")}}Promise.resolve().then(()=>{o()});const r={pt:{errors:{targetElementNotFound:"Elemento alvo não encontrado",failedToInitialize:"Falha ao inicializar Rinne SDK",failedToProcessApplePay:"Falha ao processar dados do Apple Pay",failedToProcessGooglePay:"Falha ao processar dados do Google Pay",applePayError:"Erro do Apple Pay",googlePayError:"Erro do Google Pay",failedToMountApplePay:"Falha ao montar botão do Apple Pay",failedToMountGooglePay:"Falha ao montar botão do Google Pay",failedToFetchConfig:"Falha ao buscar configuração do comerciante",invalidConfig:"Configuração de comerciante inválida: campos obrigatórios ausentes",configFetchFailed:"Falha ao buscar configuração",unknownError:"Erro desconhecido"}},en:{errors:{targetElementNotFound:"Target element not found",failedToInitialize:"Failed to initialize Rinne SDK",failedToProcessApplePay:"Failed to process Apple Pay data",failedToProcessGooglePay:"Failed to process Google Pay data",applePayError:"Apple Pay error occurred",googlePayError:"Google Pay error occurred",failedToMountApplePay:"Failed to mount Apple Pay button",failedToMountGooglePay:"Failed to mount Google Pay button",failedToFetchConfig:"Failed to fetch merchant config",invalidConfig:"Invalid merchant config: missing required fields",configFetchFailed:"Configuration fetch failed",unknownError:"Unknown error"}},es:{errors:{targetElementNotFound:"Elemento objetivo no encontrado",failedToInitialize:"Error al inicializar Rinne SDK",failedToProcessApplePay:"Error al procesar datos de Apple Pay",failedToProcessGooglePay:"Error al procesar datos de Google Pay",applePayError:"Error de Apple Pay",googlePayError:"Error de Google Pay",failedToMountApplePay:"Error al montar botón de Apple Pay",failedToMountGooglePay:"Error al montar botón de Google Pay",failedToFetchConfig:"Error al obtener configuración del comerciante",invalidConfig:"Configuración de comerciante inválida: faltan campos requeridos",configFetchFailed:"Error al obtener configuración",unknownError:"Error desconocido"}}};function t(e="pt"){return r[e]}const n={sandbox:"https://api-sandbox.rinne.com.br/core",production:"https://api.rinne.com.br/core"};function a(e){return String(e).padStart(2,"0")}function i(e){const o=String(e);return 2===o.length?`20${o}`:o}function s(e){if(void 0!==e)return 0===e?"0":e}function
|
|
1
|
+
let e=null;async function o(){if(window.Evervault)return window.Evervault;try{return await async function(){return e||(e=new Promise((o,r)=>{const t=document.createElement("script");if(t.src="https://js.evervault.com/v2",t.onload=()=>o(),t.onerror=()=>{e=null,r()},!document.head)throw new Error("Expected document.head not to be null. Evervault.js requires a <head> element.");document.head.appendChild(t)}),e)}(),window.Evervault}catch{throw new Error("Failed to load Evervault.js")}}Promise.resolve().then(()=>{o()});const r={pt:{errors:{targetElementNotFound:"Elemento alvo não encontrado",failedToInitialize:"Falha ao inicializar Rinne SDK",failedToProcessApplePay:"Falha ao processar dados do Apple Pay",failedToProcessGooglePay:"Falha ao processar dados do Google Pay",applePayError:"Erro do Apple Pay",googlePayError:"Erro do Google Pay",failedToMountApplePay:"Falha ao montar botão do Apple Pay",failedToMountGooglePay:"Falha ao montar botão do Google Pay",failedToFetchConfig:"Falha ao buscar configuração do comerciante",invalidConfig:"Configuração de comerciante inválida: campos obrigatórios ausentes",configFetchFailed:"Falha ao buscar configuração",unknownError:"Erro desconhecido"}},en:{errors:{targetElementNotFound:"Target element not found",failedToInitialize:"Failed to initialize Rinne SDK",failedToProcessApplePay:"Failed to process Apple Pay data",failedToProcessGooglePay:"Failed to process Google Pay data",applePayError:"Apple Pay error occurred",googlePayError:"Google Pay error occurred",failedToMountApplePay:"Failed to mount Apple Pay button",failedToMountGooglePay:"Failed to mount Google Pay button",failedToFetchConfig:"Failed to fetch merchant config",invalidConfig:"Invalid merchant config: missing required fields",configFetchFailed:"Configuration fetch failed",unknownError:"Unknown error"}},es:{errors:{targetElementNotFound:"Elemento objetivo no encontrado",failedToInitialize:"Error al inicializar Rinne SDK",failedToProcessApplePay:"Error al procesar datos de Apple Pay",failedToProcessGooglePay:"Error al procesar datos de Google Pay",applePayError:"Error de Apple Pay",googlePayError:"Error de Google Pay",failedToMountApplePay:"Error al montar botón de Apple Pay",failedToMountGooglePay:"Error al montar botón de Google Pay",failedToFetchConfig:"Error al obtener configuración del comerciante",invalidConfig:"Configuración de comerciante inválida: faltan campos requeridos",configFetchFailed:"Error al obtener configuración",unknownError:"Error desconocido"}}};function t(e="pt"){return r[e]}const n={sandbox:"https://api-sandbox.rinne.com.br/core/v1",production:"https://api.rinne.com.br/core/v1"};function a(e){return String(e).padStart(2,"0")}function i(e){const o=String(e);return 2===o.length?`20${o}`:o}function s(e,o,r){const t=(e.card.funding??"credit").toLowerCase(),n="APPLE_PAY"===r?function(e){const{networkToken:o,card:r,cryptogram:t,eci:n,paymentDataType:s,deviceManufacturerIdentifier:c}=e;return{network_token:o.number,expiry_month:a(o.expiry.month),expiry_year:i(o.expiry.year),cryptogram:t,eci:n,token_provider:o.tokenServiceProvider,brand:r.brand,device_id:c,authentication_type:"3DSecure"===s?"3DS":void 0,last_digits:r.lastFour,issuer:"issuer"in r?r.issuer:void 0,segment:"segment"in r?r.segment:void 0,country:"country"in r?r.country:void 0,wallet_type:"APPLE_PAY",display_name:r.displayName}}(e):function(e){if(!function(e){return"token"in e&&"tokenServiceProvider"in e.token}(e))throw new Error("Google Pay response must contain a network token (3DS authentication)");const{token:o,card:r,cryptogram:t,eci:n}=e;return{network_token:o.number,expiry_month:a(o.expiry.month),expiry_year:i(o.expiry.year),cryptogram:t,eci:n??null,token_provider:o.tokenServiceProvider,brand:r.brand,authentication_type:"3DS",last_digits:r.lastFour,issuer:"issuer"in r?r.issuer:void 0,segment:"segment"in r?r.segment:void 0,country:"country"in r?r.country:void 0,wallet_type:"GOOGLE_PAY",display_name:r.displayName}}(e);return{card_data:n,payment_method:"debit"===t?"DEBIT_CARD":"CREDIT_CARD",transaction:o}}function c(e){if(void 0!==e)return 0===e?"0":e}function l(e){return{pt:"pt-BR",en:"en-US",es:"es-ES"}[e]}function d(e,o="pt"){if("string"==typeof e){const r=document.querySelector(e);if(!r){const r=t(o).errors.targetElementNotFound;throw new Error(`${r}: ${e}`)}return r}return e}function u(e,o,r){return{code:e,message:o,details:r}}class p{constructor(e){this.options=e,this.transaction=this.createTransactionNamespace(),this.elements=this.createElementsNamespace()}config=null;evervault=null;initPromise=null;transaction;elements;async initialize(){return this.initPromise||(this.initPromise=(async()=>{try{const e=await async function(e){const o=t("pt"),r=`${e.baseUrl??n[e.environment??"production"]}/merchants/${e.merchantId}/public-settings`;try{const e=await fetch(r);if(!e.ok){const r=String(e.status);throw new Error(`${o.errors.failedToFetchConfig}: ${r} ${e.statusText}`)}const t=await e.json();if(!t.merchant_id||!t.team_id||!t.app_id)throw new Error(o.errors.invalidConfig);return{merchantId:t.merchant_id,teamId:t.team_id,appId:t.app_id,availableMethods:t.available_methods,name:t.name}}catch(a){if(a instanceof Error)throw new Error(`${o.errors.configFetchFailed}: ${a.message}`);throw new Error(`${o.errors.configFetchFailed}: ${o.errors.unknownError}`)}}({merchantId:this.options.merchantId,environment:this.options.environment??"production",baseUrl:this.options.rinneUrl});this.config=e,this.evervault=await async function(e,r,t){return new(await o())(e,r,t)}(this.config.teamId,this.config.appId)}catch(e){throw this.initPromise=null,e}})()),this.initPromise}createElementsNamespace(){return{applePay:async(e,o)=>{if(await this.initialize(),!this.evervault||!this.config){const e=t(o.button?.locale??"pt");throw new Error(e.errors.failedToInitialize)}const r=(n=this.evervault,this.config,(e,o)=>{let r=!1,a=!1;const i=o.button?.locale??"pt",p=t(i),h=o.button?.size??{width:"100%",height:"40px"},{width:y,height:m}=h,f={locale:l(o.button?.locale??"pt"),type:(P=o.button?.type??"plain",{book:"book",buy:"buy",checkout:"check-out",donate:"donate",order:"order",pay:"pay",plain:"plain",subscribe:"subscribe"}[P]),style:(g=o.button?.color??"black","white"===g?"white-outline":g),borderRadius:c(o.button?.borderRadius),...!!y&&!!m&&{size:{width:y,height:m}},process:async(t,n)=>{if(a||r)return Promise.resolve();try{r=!0;const i=s(t,e,"APPLE_PAY");let c=!1;const l=e=>{c=!0,n.fail(e)};return await(o.onCapture?.(i,l)),void(c||(a=!0))}catch(i){return n.fail({message:i instanceof Error?i.message:p.errors.failedToProcessApplePay}),Promise.resolve()}finally{a||(r=!1)}}};var g,P;const E=n.ui.applePay(e,f);return E.on("error",(...e)=>{if(r)return;r=!0;const t="string"==typeof e[0]?e[0]:void 0;if("CANCELLED"===t?.toUpperCase())return r=!1,void o.onCancel?.();const n={code:"PROVIDER_ERROR",message:t??p.errors.applePayError};o.onError?.(n)}),E.on("cancel",()=>{r=!1,o.onCancel?.()}),Promise.resolve({async mount(e){try{const o=d(e,i);return await E.mount(o),{unmount:()=>{E.unmount()}}}catch(r){const e=u("PROVIDER_ERROR",r instanceof Error?r.message:p.errors.failedToMountApplePay,r);throw o.onError&&o.onError(e),r}}})});var n;return r(e,o)},googlePay:async(e,o)=>{if(await this.initialize(),!this.evervault||!this.config){const e=t(o.button?.locale??"pt");throw new Error(e.errors.failedToInitialize)}const r=(n=this.evervault,this.config,(e,o)=>{let r=!1,a=!1;const i=o.button?.locale??"pt",l=t(i),p=o.button?.size??{width:"100%",height:"40px"},{width:h,height:y}=p,m={locale:o.button?.locale??"pt",type:o.button?.type??"plain",color:o.button?.color??"black",borderRadius:c(o.button?.borderRadius),...!!h&&!!y&&{size:{width:h,height:y}},allowedAuthMethods:["CRYPTOGRAM_3DS"],process:async(t,n)=>{if(a||r)return Promise.resolve();try{r=!0;const i=s(t,e,"GOOGLE_PAY");let c=!1;const l=e=>{c=!0,n.fail(e)};return await(o.onCapture?.(i,l)),void(c||(a=!0))}catch(i){return n.fail({message:i instanceof Error?i.message:l.errors.failedToProcessGooglePay}),Promise.resolve()}finally{a||(r=!1)}}},f=n.ui.googlePay(e,m);return f.on("error",(...e)=>{if(r)return;r=!0;const t={code:"PROVIDER_ERROR",message:("string"==typeof e[0]?e[0]:void 0)??l.errors.googlePayError};o.onError?.(t)}),f.on("cancel",()=>{r=!1,o.onCancel?.()}),Promise.resolve({mount(e){try{const o=d(e,i);return f.mount(o),Promise.resolve({unmount:()=>{f.unmount()}})}catch(r){const e=u("PROVIDER_ERROR",r instanceof Error?r.message:l.errors.failedToMountGooglePay,r);throw o.onError&&o.onError(e),r}}})});var n;return r(e,o)}}}createTransactionNamespace(){return{create:async e=>{if(await this.initialize(),!this.evervault||!this.config?.merchantId){const e=t("pt");throw new Error(e.errors.failedToInitialize)}return this.evervault.transactions.create({type:"payment",...e,country:e.country??"BR",currency:e.currency??"BRL",merchantId:this.config.merchantId,priceLabel:this.config.name})}}}}export{p as Rinne};
|
package/dist/index.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,o){"object"==typeof exports&&"undefined"!=typeof module?o(exports):"function"==typeof define&&define.amd?define(["exports"],o):o((e="undefined"!=typeof globalThis?globalThis:e||self).Rinne={})}(this,function(e){"use strict";let o=null;async function r(){if(window.Evervault)return window.Evervault;try{return await async function(){return o||(o=new Promise((e,r)=>{const t=document.createElement("script");if(t.src="https://js.evervault.com/v2",t.onload=()=>e(),t.onerror=()=>{o=null,r()},!document.head)throw new Error("Expected document.head not to be null. Evervault.js requires a <head> element.");document.head.appendChild(t)}),o)}(),window.Evervault}catch{throw new Error("Failed to load Evervault.js")}}Promise.resolve().then(()=>{r()});const t={pt:{errors:{targetElementNotFound:"Elemento alvo não encontrado",failedToInitialize:"Falha ao inicializar Rinne SDK",failedToProcessApplePay:"Falha ao processar dados do Apple Pay",failedToProcessGooglePay:"Falha ao processar dados do Google Pay",applePayError:"Erro do Apple Pay",googlePayError:"Erro do Google Pay",failedToMountApplePay:"Falha ao montar botão do Apple Pay",failedToMountGooglePay:"Falha ao montar botão do Google Pay",failedToFetchConfig:"Falha ao buscar configuração do comerciante",invalidConfig:"Configuração de comerciante inválida: campos obrigatórios ausentes",configFetchFailed:"Falha ao buscar configuração",unknownError:"Erro desconhecido"}},en:{errors:{targetElementNotFound:"Target element not found",failedToInitialize:"Failed to initialize Rinne SDK",failedToProcessApplePay:"Failed to process Apple Pay data",failedToProcessGooglePay:"Failed to process Google Pay data",applePayError:"Apple Pay error occurred",googlePayError:"Google Pay error occurred",failedToMountApplePay:"Failed to mount Apple Pay button",failedToMountGooglePay:"Failed to mount Google Pay button",failedToFetchConfig:"Failed to fetch merchant config",invalidConfig:"Invalid merchant config: missing required fields",configFetchFailed:"Configuration fetch failed",unknownError:"Unknown error"}},es:{errors:{targetElementNotFound:"Elemento objetivo no encontrado",failedToInitialize:"Error al inicializar Rinne SDK",failedToProcessApplePay:"Error al procesar datos de Apple Pay",failedToProcessGooglePay:"Error al procesar datos de Google Pay",applePayError:"Error de Apple Pay",googlePayError:"Error de Google Pay",failedToMountApplePay:"Error al montar botón de Apple Pay",failedToMountGooglePay:"Error al montar botón de Google Pay",failedToFetchConfig:"Error al obtener configuración del comerciante",invalidConfig:"Configuración de comerciante inválida: faltan campos requeridos",configFetchFailed:"Error al obtener configuración",unknownError:"Error desconocido"}}};function n(e="pt"){return t[e]}const i={sandbox:"https://api-sandbox.rinne.com.br/core",production:"https://api.rinne.com.br/core"};function a(e){return String(e).padStart(2,"0")}function s(e){const o=String(e);return 2===o.length?`20${o}`:o}function c(e){if(void 0!==e)return 0===e?"0":e}function
|
|
1
|
+
!function(e,o){"object"==typeof exports&&"undefined"!=typeof module?o(exports):"function"==typeof define&&define.amd?define(["exports"],o):o((e="undefined"!=typeof globalThis?globalThis:e||self).Rinne={})}(this,function(e){"use strict";let o=null;async function r(){if(window.Evervault)return window.Evervault;try{return await async function(){return o||(o=new Promise((e,r)=>{const t=document.createElement("script");if(t.src="https://js.evervault.com/v2",t.onload=()=>e(),t.onerror=()=>{o=null,r()},!document.head)throw new Error("Expected document.head not to be null. Evervault.js requires a <head> element.");document.head.appendChild(t)}),o)}(),window.Evervault}catch{throw new Error("Failed to load Evervault.js")}}Promise.resolve().then(()=>{r()});const t={pt:{errors:{targetElementNotFound:"Elemento alvo não encontrado",failedToInitialize:"Falha ao inicializar Rinne SDK",failedToProcessApplePay:"Falha ao processar dados do Apple Pay",failedToProcessGooglePay:"Falha ao processar dados do Google Pay",applePayError:"Erro do Apple Pay",googlePayError:"Erro do Google Pay",failedToMountApplePay:"Falha ao montar botão do Apple Pay",failedToMountGooglePay:"Falha ao montar botão do Google Pay",failedToFetchConfig:"Falha ao buscar configuração do comerciante",invalidConfig:"Configuração de comerciante inválida: campos obrigatórios ausentes",configFetchFailed:"Falha ao buscar configuração",unknownError:"Erro desconhecido"}},en:{errors:{targetElementNotFound:"Target element not found",failedToInitialize:"Failed to initialize Rinne SDK",failedToProcessApplePay:"Failed to process Apple Pay data",failedToProcessGooglePay:"Failed to process Google Pay data",applePayError:"Apple Pay error occurred",googlePayError:"Google Pay error occurred",failedToMountApplePay:"Failed to mount Apple Pay button",failedToMountGooglePay:"Failed to mount Google Pay button",failedToFetchConfig:"Failed to fetch merchant config",invalidConfig:"Invalid merchant config: missing required fields",configFetchFailed:"Configuration fetch failed",unknownError:"Unknown error"}},es:{errors:{targetElementNotFound:"Elemento objetivo no encontrado",failedToInitialize:"Error al inicializar Rinne SDK",failedToProcessApplePay:"Error al procesar datos de Apple Pay",failedToProcessGooglePay:"Error al procesar datos de Google Pay",applePayError:"Error de Apple Pay",googlePayError:"Error de Google Pay",failedToMountApplePay:"Error al montar botón de Apple Pay",failedToMountGooglePay:"Error al montar botón de Google Pay",failedToFetchConfig:"Error al obtener configuración del comerciante",invalidConfig:"Configuración de comerciante inválida: faltan campos requeridos",configFetchFailed:"Error al obtener configuración",unknownError:"Error desconocido"}}};function n(e="pt"){return t[e]}const i={sandbox:"https://api-sandbox.rinne.com.br/core/v1",production:"https://api.rinne.com.br/core/v1"};function a(e){return String(e).padStart(2,"0")}function s(e){const o=String(e);return 2===o.length?`20${o}`:o}function c(e,o,r){const t=(e.card.funding??"credit").toLowerCase(),n="APPLE_PAY"===r?function(e){const{networkToken:o,card:r,cryptogram:t,eci:n,paymentDataType:i,deviceManufacturerIdentifier:c}=e;return{network_token:o.number,expiry_month:a(o.expiry.month),expiry_year:s(o.expiry.year),cryptogram:t,eci:n,token_provider:o.tokenServiceProvider,brand:r.brand,device_id:c,authentication_type:"3DSecure"===i?"3DS":void 0,last_digits:r.lastFour,issuer:"issuer"in r?r.issuer:void 0,segment:"segment"in r?r.segment:void 0,country:"country"in r?r.country:void 0,wallet_type:"APPLE_PAY",display_name:r.displayName}}(e):function(e){if(!function(e){return"token"in e&&"tokenServiceProvider"in e.token}(e))throw new Error("Google Pay response must contain a network token (3DS authentication)");const{token:o,card:r,cryptogram:t,eci:n}=e;return{network_token:o.number,expiry_month:a(o.expiry.month),expiry_year:s(o.expiry.year),cryptogram:t,eci:n??null,token_provider:o.tokenServiceProvider,brand:r.brand,authentication_type:"3DS",last_digits:r.lastFour,issuer:"issuer"in r?r.issuer:void 0,segment:"segment"in r?r.segment:void 0,country:"country"in r?r.country:void 0,wallet_type:"GOOGLE_PAY",display_name:r.displayName}}(e);return{card_data:n,payment_method:"debit"===t?"DEBIT_CARD":"CREDIT_CARD",transaction:o}}function l(e){if(void 0!==e)return 0===e?"0":e}function d(e){return{pt:"pt-BR",en:"en-US",es:"es-ES"}[e]}function u(e,o="pt"){if("string"==typeof e){const r=document.querySelector(e);if(!r){const r=n(o).errors.targetElementNotFound;throw new Error(`${r}: ${e}`)}return r}return e}function p(e,o,r){return{code:e,message:o,details:r}}e.Rinne=class{constructor(e){this.options=e,this.transaction=this.createTransactionNamespace(),this.elements=this.createElementsNamespace()}config=null;evervault=null;initPromise=null;transaction;elements;async initialize(){return this.initPromise||(this.initPromise=(async()=>{try{const e=await async function(e){const o=n("pt"),r=`${e.baseUrl??i[e.environment??"production"]}/merchants/${e.merchantId}/public-settings`;try{const e=await fetch(r);if(!e.ok){const r=String(e.status);throw new Error(`${o.errors.failedToFetchConfig}: ${r} ${e.statusText}`)}const t=await e.json();if(!t.merchant_id||!t.team_id||!t.app_id)throw new Error(o.errors.invalidConfig);return{merchantId:t.merchant_id,teamId:t.team_id,appId:t.app_id,availableMethods:t.available_methods,name:t.name}}catch(t){if(t instanceof Error)throw new Error(`${o.errors.configFetchFailed}: ${t.message}`);throw new Error(`${o.errors.configFetchFailed}: ${o.errors.unknownError}`)}}({merchantId:this.options.merchantId,environment:this.options.environment??"production",baseUrl:this.options.rinneUrl});this.config=e,this.evervault=await async function(e,o,t){return new(await r())(e,o,t)}(this.config.teamId,this.config.appId)}catch(e){throw this.initPromise=null,e}})()),this.initPromise}createElementsNamespace(){return{applePay:async(e,o)=>{if(await this.initialize(),!this.evervault||!this.config){const e=n(o.button?.locale??"pt");throw new Error(e.errors.failedToInitialize)}const r=(t=this.evervault,this.config,(e,o)=>{let r=!1,i=!1;const a=o.button?.locale??"pt",s=n(a),h=o.button?.size??{width:"100%",height:"40px"},{width:f,height:y}=h,m={locale:d(o.button?.locale??"pt"),type:(P=o.button?.type??"plain",{book:"book",buy:"buy",checkout:"check-out",donate:"donate",order:"order",pay:"pay",plain:"plain",subscribe:"subscribe"}[P]),style:(g=o.button?.color??"black","white"===g?"white-outline":g),borderRadius:l(o.button?.borderRadius),...!!f&&!!y&&{size:{width:f,height:y}},process:async(t,n)=>{if(i||r)return Promise.resolve();try{r=!0;const a=c(t,e,"APPLE_PAY");let s=!1;const l=e=>{s=!0,n.fail(e)};return await(o.onCapture?.(a,l)),void(s||(i=!0))}catch(a){return n.fail({message:a instanceof Error?a.message:s.errors.failedToProcessApplePay}),Promise.resolve()}finally{i||(r=!1)}}};var g,P;const v=t.ui.applePay(e,m);return v.on("error",(...e)=>{if(r)return;r=!0;const t="string"==typeof e[0]?e[0]:void 0;if("CANCELLED"===t?.toUpperCase())return r=!1,void o.onCancel?.();const n={code:"PROVIDER_ERROR",message:t??s.errors.applePayError};o.onError?.(n)}),v.on("cancel",()=>{r=!1,o.onCancel?.()}),Promise.resolve({async mount(e){try{const o=u(e,a);return await v.mount(o),{unmount:()=>{v.unmount()}}}catch(r){const e=p("PROVIDER_ERROR",r instanceof Error?r.message:s.errors.failedToMountApplePay,r);throw o.onError&&o.onError(e),r}}})});var t;return r(e,o)},googlePay:async(e,o)=>{if(await this.initialize(),!this.evervault||!this.config){const e=n(o.button?.locale??"pt");throw new Error(e.errors.failedToInitialize)}const r=(t=this.evervault,this.config,(e,o)=>{let r=!1,i=!1;const a=o.button?.locale??"pt",s=n(a),d=o.button?.size??{width:"100%",height:"40px"},{width:h,height:f}=d,y={locale:o.button?.locale??"pt",type:o.button?.type??"plain",color:o.button?.color??"black",borderRadius:l(o.button?.borderRadius),...!!h&&!!f&&{size:{width:h,height:f}},allowedAuthMethods:["CRYPTOGRAM_3DS"],process:async(t,n)=>{if(i||r)return Promise.resolve();try{r=!0;const a=c(t,e,"GOOGLE_PAY");let s=!1;const l=e=>{s=!0,n.fail(e)};return await(o.onCapture?.(a,l)),void(s||(i=!0))}catch(a){return n.fail({message:a instanceof Error?a.message:s.errors.failedToProcessGooglePay}),Promise.resolve()}finally{i||(r=!1)}}},m=t.ui.googlePay(e,y);return m.on("error",(...e)=>{if(r)return;r=!0;const t={code:"PROVIDER_ERROR",message:("string"==typeof e[0]?e[0]:void 0)??s.errors.googlePayError};o.onError?.(t)}),m.on("cancel",()=>{r=!1,o.onCancel?.()}),Promise.resolve({mount(e){try{const o=u(e,a);return m.mount(o),Promise.resolve({unmount:()=>{m.unmount()}})}catch(r){const e=p("PROVIDER_ERROR",r instanceof Error?r.message:s.errors.failedToMountGooglePay,r);throw o.onError&&o.onError(e),r}}})});var t;return r(e,o)}}}createTransactionNamespace(){return{create:async e=>{if(await this.initialize(),!this.evervault||!this.config?.merchantId){const e=n("pt");throw new Error(e.errors.failedToInitialize)}return this.evervault.transactions.create({type:"payment",...e,country:e.country??"BR",currency:e.currency??"BRL",merchantId:this.config.merchantId,priceLabel:this.config.name})}}}},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"})}),"undefined"!=typeof window&&window.Rinne&&window.Rinne.Rinne&&(window.Rinne=window.Rinne.Rinne);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rinnebr/js",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.17",
|
|
4
4
|
"description": "Modern payment elements library for Apple Pay, Google Pay, and other payment methods",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "yarn@4.9.1",
|
|
@@ -75,6 +75,6 @@
|
|
|
75
75
|
"vitest": "^4.0.8"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@evervault/js": "^2.
|
|
78
|
+
"@evervault/js": "^2.7.0"
|
|
79
79
|
}
|
|
80
80
|
}
|