@fat-zebra/sdk 2.0.1 → 2.0.2-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/hpp/hpp.d.ts CHANGED
@@ -50,16 +50,10 @@ declare class Hpp {
50
50
  private postMessageClient;
51
51
  private test;
52
52
  private hppOptions;
53
- private headlessLoaded;
54
- private headlessPreviouslyLoaded;
55
- private iframeLoaded;
56
53
  private isThreeDSecureEnabled;
57
54
  private challengeWindowSize;
58
55
  private scaHandler;
59
- private crossFrameListenersBound;
60
- private publicEventListenersBound;
61
56
  constructor(config: HppModuleConfig);
62
- setListenersAndEmitReady(): void;
63
57
  load(config: HppLoadParams): void;
64
58
  purchase(): void;
65
59
  getPayNowUrl(options?: {
@@ -71,6 +65,7 @@ declare class Hpp {
71
65
  createPurchase(extra?: {
72
66
  [key: string]: boolean | string;
73
67
  }): void;
74
- private reportHppStatus;
68
+ private reportIframeLoaded;
69
+ private reportTokenizeCardResponse;
75
70
  }
76
71
  export { Hpp, type HppLoadParams, HPP_DEFAULT_OPTIONS, };
package/dist/hpp/hpp.js CHANGED
@@ -40,66 +40,33 @@ class Hpp {
40
40
  this.sca = config.sca;
41
41
  this.test = config.test;
42
42
  this.version = config.version || 2;
43
- this.headlessLoaded = false;
44
- this.headlessPreviouslyLoaded = false;
45
- this.iframeLoaded = false;
46
43
  this.threeDSecure = config.threeDSecure;
47
- this.crossFrameListenersBound = false;
48
- this.publicEventListenersBound = false;
49
44
  this.isThreeDSecureEnabled = (_a = config.isThreeDSecureEnabled) !== null && _a !== void 0 ? _a : false;
50
45
  configureLogger({
51
46
  baseUrl: env[process.env.API_ENV].payNowUrl
52
47
  });
53
48
  }
54
- setListenersAndEmitReady() {
55
- this.reportHppStatus(this);
56
- if (!this.crossFrameListenersBound) {
57
- this.setCrossFramesEventListeners();
58
- this.crossFrameListenersBound = true;
59
- }
60
- if (this.headlessLoaded && this.iframeLoaded) {
61
- if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled) {
62
- this.setPublicEventListeners();
63
- this.publicEventListenersBound = true;
64
- }
65
- emit(PublicEvent.HPP_READY);
66
- }
67
- else if (this.headlessPreviouslyLoaded && this.iframeLoaded) {
68
- // subsequent iframe loads after headless has been previously loaded
69
- // this caters for the SPA scenario
70
- if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled) {
71
- this.setPublicEventListeners();
72
- this.publicEventListenersBound = true;
73
- }
74
- emit(PublicEvent.HPP_READY);
75
- }
76
- }
77
49
  load(config) {
78
50
  var _a;
79
51
  this.challengeWindowSize = (_a = config.options) === null || _a === void 0 ? void 0 : _a.challengeWindowSize;
80
52
  setTransactionReference(config.paymentIntent.payment.reference);
81
53
  this.hppOptions = config.options || {};
82
- const { el, isExisting } = bridge.load2(process.env.PAYNOW_BRIDGE_URL);
54
+ const { el } = bridge.load2(process.env.PAYNOW_BRIDGE_URL);
83
55
  this.headless = el;
84
- this.headlessPreviouslyLoaded = isExisting;
85
56
  this.iframe = document.createElement('iframe');
86
57
  document.getElementById(config.containerId).appendChild(this.iframe);
87
58
  this.postMessageClient = new PostMessageClient({
88
59
  channel: 'sca',
89
60
  target: this.iframe
90
61
  });
91
- this.headless.addEventListener('load', () => {
92
- this.headlessLoaded = true;
93
- this.setListenersAndEmitReady();
94
- });
62
+ this.setCrossFramesEventListeners();
95
63
  this.iframe.onload = () => {
96
- this.iframeLoaded = true;
97
- this.setListenersAndEmitReady();
64
+ this.reportIframeLoaded();
65
+ if (!this.isThreeDSecureEnabled) {
66
+ this.setPublicEventListeners();
67
+ }
68
+ emit(PublicEvent.HPP_READY);
98
69
  };
99
- if (this.headlessPreviouslyLoaded) {
100
- this.headlessLoaded = true;
101
- this.setListenersAndEmitReady();
102
- }
103
70
  const payNowUrl = this.getPayNowUrl(config.options);
104
71
  this.iframe.setAttribute("src", payNowUrl);
105
72
  this.iframe.setAttribute('allow', 'payment');
@@ -140,6 +107,7 @@ class Hpp {
140
107
  const handlers = {};
141
108
  handlers[BridgeEvent.TOKENIZE_CARD_RESPONSE] = (data) => {
142
109
  var _a;
110
+ this.reportTokenizeCardResponse(data);
143
111
  if (data.source === 'verifyCard')
144
112
  return;
145
113
  if (data.errors) {
@@ -250,14 +218,11 @@ class Hpp {
250
218
  on(PublicEvent.SCA_SUCCESS, this.scaHandler);
251
219
  }
252
220
  destroy() {
253
- if (this.publicEventListenersBound && this.scaHandler) {
221
+ var _a;
222
+ if (this.scaHandler) {
254
223
  off(PublicEvent.SCA_SUCCESS, this.scaHandler);
255
- this.publicEventListenersBound = false;
256
- }
257
- if (this.crossFrameListenersBound) {
258
- this.postMessageClient.removeEventListeners();
259
- this.crossFrameListenersBound = false;
260
224
  }
225
+ (_a = this.postMessageClient) === null || _a === void 0 ? void 0 : _a.removeEventListeners();
261
226
  }
262
227
  createPurchase(extra = null) {
263
228
  console.log('createPurchase');
@@ -280,7 +245,11 @@ class Hpp {
280
245
  }
281
246
  this.headless.contentWindow.postMessage(message, '*');
282
247
  }
283
- reportHppStatus(hpp) {
248
+ reportIframeLoaded() {
249
+ console.log('Iframe loaded');
250
+ }
251
+ reportTokenizeCardResponse(data) {
252
+ console.log('Tokenize card response received');
284
253
  }
285
254
  }
286
255
  __decorate([
@@ -293,20 +262,9 @@ __decorate([
293
262
  logMethod()
294
263
  ], Hpp.prototype, "createPurchase", null);
295
264
  __decorate([
296
- logMethod({
297
- mapArgs: (args) => {
298
- const hpp = args[0];
299
- return [
300
- {
301
- crossFrameListenersBound: hpp.crossFrameListenersBound,
302
- publicEventListenersBound: hpp.publicEventListenersBound,
303
- isThreeDSecureEnabled: hpp.isThreeDSecureEnabled,
304
- headlessLoaded: hpp.headlessLoaded,
305
- headlessPreviouslyLoaded: hpp.headlessPreviouslyLoaded,
306
- iframeLoaded: hpp.iframeLoaded,
307
- },
308
- ];
309
- },
310
- })
311
- ], Hpp.prototype, "reportHppStatus", null);
265
+ logMethod()
266
+ ], Hpp.prototype, "reportIframeLoaded", null);
267
+ __decorate([
268
+ logMethod()
269
+ ], Hpp.prototype, "reportTokenizeCardResponse", null);
312
270
  export { Hpp, HPP_DEFAULT_OPTIONS, };
@@ -2,6 +2,7 @@ export type LogOptions<A extends unknown[]> = {
2
2
  endpoint?: string | ((...args: A) => string);
3
3
  mapArgs?: (args: A) => unknown;
4
4
  enabled?: () => boolean;
5
+ className?: string;
5
6
  };
6
7
  type LoggerConfig = {
7
8
  baseUrl?: string;
@@ -17,7 +17,6 @@ function sendLog(endpoint, payload) {
17
17
  void axios.post(endpoint, payload);
18
18
  }
19
19
  else {
20
- // fallback for non-browser or older environments
21
20
  void axios.post(endpoint, payload);
22
21
  }
23
22
  }
@@ -35,11 +34,14 @@ export function instrumentFunction(methodName, fn, opts = {}) {
35
34
  const endpoint = typeof opts.endpoint === "function"
36
35
  ? opts.endpoint(...args)
37
36
  : (_a = opts.endpoint) !== null && _a !== void 0 ? _a : defaultEndpoint();
37
+ // evaluate mapArgs(args) before constructing payload so any side effects in mapArgs (like setTransactionReference) are propagated
38
+ const mappedArgs = mapArgs(args);
38
39
  const payload = {
39
40
  username: getLoggerUsername(),
40
41
  reference: getTransactionReference(),
42
+ className: opts.className,
41
43
  method: methodName,
42
- arguments: mapArgs(args),
44
+ arguments: mappedArgs,
43
45
  timestamp: new Date().toISOString(),
44
46
  };
45
47
  sendLog(endpoint, payload);
@@ -31,13 +31,16 @@ import { instrumentFunction } from "./instrument";
31
31
  // Decorator factory
32
32
  export function logMethod(opts = {}) {
33
33
  return function (target, propertyKey, descriptor) {
34
- var _a;
34
+ var _a, _b;
35
35
  const original = descriptor.value;
36
36
  if (typeof original !== "function") {
37
37
  console.error(`@logMethod can only decorate methods (${propertyKey})`);
38
38
  return descriptor;
39
39
  }
40
- descriptor.value = instrumentFunction(propertyKey, original, Object.assign(Object.assign({}, opts), { mapArgs: (_a = opts.mapArgs) !== null && _a !== void 0 ? _a : ((args) => args.map((a) => {
40
+ const className = typeof target === "function"
41
+ ? target.name || "UnknownClass"
42
+ : ((_a = target === null || target === void 0 ? void 0 : target.constructor) === null || _a === void 0 ? void 0 : _a.name) || "UnknownClass";
43
+ descriptor.value = instrumentFunction(propertyKey, original, Object.assign(Object.assign({}, opts), { className, mapArgs: (_b = opts.mapArgs) !== null && _b !== void 0 ? _b : ((args) => args.map((a) => {
41
44
  if (!a || typeof a !== "object")
42
45
  return a;
43
46
  return Object.assign(Object.assign({}, a), { js_sdk: true });
package/dist/main.d.ts CHANGED
@@ -45,6 +45,7 @@ export default class FatZebra {
45
45
  private setThreeDSecureListeners;
46
46
  private reportThreeDSecureFetched;
47
47
  private reportRequestThreedsEnabledTimeout;
48
+ private reportTokenizeCardResponse;
48
49
  checkout(): void;
49
50
  on(event: PublicEvent, callback: (e: any) => void): void;
50
51
  off(event: PublicEvent, callback: (e: any) => void): void;
package/dist/main.js CHANGED
@@ -103,6 +103,7 @@ export default class FatZebra {
103
103
  });
104
104
  const handlers = {};
105
105
  handlers[BridgeEvent.TOKENIZE_CARD_RESPONSE] = (data) => {
106
+ this.reportTokenizeCardResponse(data);
106
107
  callback(data);
107
108
  };
108
109
  postMessageClient.setEventListeners(handlers, { once: true });
@@ -158,7 +159,6 @@ export default class FatZebra {
158
159
  });
159
160
  return;
160
161
  }
161
- setTransactionReference(params.paymentIntent.payment.reference);
162
162
  yield this.authReady;
163
163
  switch (params.paymentMethod.type) {
164
164
  case PaymentMethodType.CARD: {
@@ -307,6 +307,9 @@ export default class FatZebra {
307
307
  reportRequestThreedsEnabledTimeout(paymentIntent) {
308
308
  console.log('3DS enabled check timed out');
309
309
  }
310
+ reportTokenizeCardResponse(data) {
311
+ console.log('Tokenize card response received');
312
+ }
310
313
  checkout() {
311
314
  window.HPP.purchase();
312
315
  }
@@ -334,13 +337,15 @@ __decorate([
334
337
  __decorate([
335
338
  logMethod({
336
339
  mapArgs: (args) => {
337
- var _a;
340
+ var _a, _b, _c;
338
341
  const params = args[0];
342
+ setTransactionReference((_b = (_a = params.paymentIntent) === null || _a === void 0 ? void 0 : _a.payment) === null || _b === void 0 ? void 0 : _b.reference);
339
343
  return [
340
344
  {
341
345
  merchant_username: window.MerchantUsername,
342
346
  payment_intent: params === null || params === void 0 ? void 0 : params.paymentIntent,
343
- payment_method: (_a = params === null || params === void 0 ? void 0 : params.paymentMethod) === null || _a === void 0 ? void 0 : _a.type,
347
+ payment_method: (_c = params === null || params === void 0 ? void 0 : params.paymentMethod) === null || _c === void 0 ? void 0 : _c.type,
348
+ options: params === null || params === void 0 ? void 0 : params.options,
344
349
  },
345
350
  ];
346
351
  },
@@ -349,16 +354,22 @@ __decorate([
349
354
  __decorate([
350
355
  logMethod({
351
356
  mapArgs: (args) => {
357
+ var _a, _b;
352
358
  const params = args[0];
359
+ setTransactionReference((_b = (_a = params.paymentIntent) === null || _a === void 0 ? void 0 : _a.payment) === null || _b === void 0 ? void 0 : _b.reference);
353
360
  return [
354
361
  {
355
362
  payment_intent: params.paymentIntent,
356
- version: params.version
363
+ version: params.version,
364
+ options: params.options
357
365
  },
358
366
  ];
359
367
  },
360
368
  })
361
369
  ], FatZebra.prototype, "renderPaymentsPage", null);
370
+ __decorate([
371
+ logMethod()
372
+ ], FatZebra.prototype, "renderClickToPay", null);
362
373
  __decorate([
363
374
  logMethod({
364
375
  mapArgs: (args) => {
@@ -382,4 +393,10 @@ __decorate([
382
393
  },
383
394
  })
384
395
  ], FatZebra.prototype, "reportRequestThreedsEnabledTimeout", null);
396
+ __decorate([
397
+ logMethod()
398
+ ], FatZebra.prototype, "reportTokenizeCardResponse", null);
399
+ __decorate([
400
+ logMethod()
401
+ ], FatZebra.prototype, "checkout", null);
385
402
  export { FatZebra, };
@@ -46,7 +46,7 @@ const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
46
46
  cardToken: data.token,
47
47
  merchantUsername: config.username,
48
48
  test: config.environment !== Environment.production,
49
- tokenizeOnly: config.options.tokenize_only,
49
+ tokenizeOnly: true,
50
50
  iframe: iframe
51
51
  });
52
52
  return;
package/dist/sca/index.js CHANGED
@@ -236,7 +236,6 @@ __decorate([
236
236
  {
237
237
  message: args[0],
238
238
  data: args[1],
239
- source: 'sca'
240
239
  },
241
240
  ];
242
241
  },
@@ -249,7 +248,6 @@ __decorate([
249
248
  {
250
249
  message: args[0],
251
250
  data: args[1],
252
- source: 'sca'
253
251
  },
254
252
  ];
255
253
  },
@@ -262,7 +260,9 @@ __decorate([
262
260
  return [
263
261
  {
264
262
  source: params.source,
265
- payment_intent: params.paymentIntent
263
+ payment_intent: params.paymentIntent,
264
+ card_token: params.cardToken,
265
+ challenge_window_size: params.challengeWindowSize,
266
266
  },
267
267
  ];
268
268
  },
@@ -9,6 +9,15 @@ interface ThreeDSecureConfig {
9
9
  bridge: HTMLIFrameElement;
10
10
  iframe?: HTMLIFrameElement;
11
11
  }
12
+ interface ThreeDSecureRunProps {
13
+ paymentIntent: PaymentIntent;
14
+ cardToken: string;
15
+ merchantUsername: string;
16
+ challengeWindowSize?: ChallengeWindowSize;
17
+ tokenizeOnly?: boolean;
18
+ iframe?: HTMLIFrameElement;
19
+ test: boolean;
20
+ }
12
21
  declare class ThreeDSecure {
13
22
  private headlessBridge;
14
23
  private cybersourceReferenceId;
@@ -23,15 +32,7 @@ declare class ThreeDSecure {
23
32
  private tokenizeOnly;
24
33
  private iframe?;
25
34
  constructor({ successCallback, failureCallback, environment, bridge }: ThreeDSecureConfig);
26
- run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test, tokenizeOnly, iframe }: {
27
- paymentIntent: PaymentIntent;
28
- cardToken: string;
29
- merchantUsername: string;
30
- challengeWindowSize?: ChallengeWindowSize;
31
- test: boolean;
32
- tokenizeOnly?: boolean;
33
- iframe?: HTMLIFrameElement;
34
- }): void;
35
+ run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test, tokenizeOnly, iframe }: ThreeDSecureRunProps): void;
35
36
  setupResponse(data: DeviceDataCollectionMessage): void;
36
37
  messageHandlers(): {
37
38
  [key: string]: (data: any) => void;
@@ -102,7 +102,7 @@ class ThreeDSecure {
102
102
  const message = {
103
103
  channel: 'sca',
104
104
  subject: BridgeEvent.ENROL_THREE_D_SECURE_REQUEST,
105
- data: Object.assign(Object.assign(Object.assign({ access_token: window.localStorage.getItem(LocalStorageAccessTokenKey), merchant_username: merchantUsername, card_token: cardToken }, paymentIntent.payment), { verification: paymentIntent.verification, reference_id: cybersourceReferenceId, return_url: env[this.environment].returnCybersourceUrl, acs_window_size: (_a = this.challengeWindowSize) !== null && _a !== void 0 ? _a : ChallengeWindowSize.SIZE_FULL_PAGE, device_channel: "BROWSER" }), snakeCaseKeys(DeviceDataCollection.collectDeviceData()))
105
+ data: Object.assign(Object.assign(Object.assign({ access_token: window.localStorage.getItem(LocalStorageAccessTokenKey), merchant_username: merchantUsername, card_token: cardToken }, paymentIntent.payment), { verification: paymentIntent.verification, reference_id: cybersourceReferenceId, return_url: env[this.environment].returnCybersourceUrl, acs_window_size: (_a = this.challengeWindowSize) !== null && _a !== void 0 ? _a : ChallengeWindowSize.SIZE_500X600, device_channel: "BROWSER" }), snakeCaseKeys(DeviceDataCollection.collectDeviceData()))
106
106
  };
107
107
  this.headlessBridge.contentWindow.postMessage(message, '*');
108
108
  }
@@ -115,7 +115,7 @@ class ThreeDSecure {
115
115
  stepUpUrl: data.step_up_url,
116
116
  cardToken: this.cardToken,
117
117
  accessToken: data.access_token,
118
- challengeWindowSize: (_a = this.challengeWindowSize) !== null && _a !== void 0 ? _a : ChallengeWindowSize.SIZE_FULL_PAGE,
118
+ challengeWindowSize: (_a = this.challengeWindowSize) !== null && _a !== void 0 ? _a : ChallengeWindowSize.SIZE_500X600,
119
119
  });
120
120
  return;
121
121
  }
@@ -197,6 +197,21 @@ class ThreeDSecure {
197
197
  }
198
198
  }
199
199
  }
200
+ __decorate([
201
+ logMethod({
202
+ mapArgs: (args) => {
203
+ const params = args[0];
204
+ return [
205
+ {
206
+ payment_intent: params.paymentIntent,
207
+ card_token: params.cardToken,
208
+ challenge_window_size: params.challengeWindowSize,
209
+ tokenize_only: params.tokenizeOnly,
210
+ },
211
+ ];
212
+ },
213
+ })
214
+ ], ThreeDSecure.prototype, "run", null);
200
215
  __decorate([
201
216
  logMethod({
202
217
  mapArgs: (args) => {
@@ -204,7 +219,6 @@ __decorate([
204
219
  {
205
220
  message: args[0],
206
221
  data: args[1],
207
- source: 'three_d_secure'
208
222
  },
209
223
  ];
210
224
  },
@@ -217,7 +231,6 @@ __decorate([
217
231
  {
218
232
  message: args[0],
219
233
  data: args[1],
220
- source: 'three_d_secure'
221
234
  },
222
235
  ];
223
236
  },
@@ -1,5 +1,6 @@
1
1
  import { toFzSli } from "../../sca/eci-mappings";
2
2
  const threeDResponseData = (response) => {
3
+ var _a;
3
4
  return {
4
5
  // CAVV: Visa & Amex only
5
6
  // AAV: Mastercard only, known as UCAF
@@ -8,7 +9,7 @@ const threeDResponseData = (response) => {
8
9
  sli: toFzSli(response.eci),
9
10
  eci: response.eci,
10
11
  xid: response.xid,
11
- ver: response === null || response === void 0 ? void 0 : response.veres,
12
+ ver: (_a = response === null || response === void 0 ? void 0 : response.veres) !== null && _a !== void 0 ? _a : null,
12
13
  directoryServerTxnId: response.directory_server_txn_id,
13
14
  threedsVersion: response.threeds_version,
14
15
  };
@@ -13,5 +13,6 @@ declare class ThreeDSecureChallengeWindow {
13
13
  cardToken: string;
14
14
  challengeWindowSize?: ChallengeWindowSize;
15
15
  }): void;
16
+ private static reportChallengeIframeError;
16
17
  }
17
18
  export default ThreeDSecureChallengeWindow;
@@ -1,3 +1,10 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { logMethod } from "../../logging/logMethod";
1
8
  import { ChallengeWindowSize } from "../../sca/types";
2
9
  class ThreeDSecureChallengeWindow {
3
10
  // Treat these as the *iframe viewport* sizes per 3DS spec.
@@ -134,7 +141,7 @@ class ThreeDSecureChallengeWindow {
134
141
  Object.assign(iframe.style, { border: "0", display: "block" });
135
142
  iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms allow-popups allow-top-navigation-by-user-activation");
136
143
  iframe.addEventListener("load", () => console.log("✅ step-up iframe loaded"));
137
- iframe.addEventListener("error", () => console.log("❌ step-up iframe error"));
144
+ iframe.addEventListener("error", ThreeDSecureChallengeWindow.reportChallengeIframeError);
138
145
  frameWrap.appendChild(iframe);
139
146
  // Hidden POST form -> targets the iframe
140
147
  let form = document.getElementById(ThreeDSecureChallengeWindow.CHALLENGE_FORM_ID);
@@ -162,9 +169,18 @@ class ThreeDSecureChallengeWindow {
162
169
  overlay.style.display = "flex";
163
170
  form.submit();
164
171
  }
172
+ static reportChallengeIframeError() {
173
+ console.log("❌ step-up iframe error");
174
+ }
165
175
  }
166
176
  ThreeDSecureChallengeWindow.OVERLAY_ID = "three_d_secure_challenge_overlay";
167
177
  ThreeDSecureChallengeWindow.CONTENT_ID = "three_d_secure_challenge_content";
168
178
  ThreeDSecureChallengeWindow.FRAME_WRAP_ID = "three_d_secure_challenge_frame_wrap";
169
179
  ThreeDSecureChallengeWindow.CHALLENGE_FORM_ID = "three_d_secure_challenge_form";
180
+ __decorate([
181
+ logMethod()
182
+ ], ThreeDSecureChallengeWindow, "showChallengeIframe", null);
183
+ __decorate([
184
+ logMethod()
185
+ ], ThreeDSecureChallengeWindow, "reportChallengeIframeError", null);
170
186
  export default ThreeDSecureChallengeWindow;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fat-zebra/sdk",
3
- "version": "2.0.1",
3
+ "version": "2.0.2-beta.2",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {