@tap-payments/auth-jsconnect 2.2.5-test → 2.3.2-test

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.
@@ -51,7 +51,7 @@ import API from '../../../api';
51
51
  import { FlowsTypes } from '../../../@types';
52
52
  import { handleNextScreenStep, handleSetCountryByIso2 } from '../../../app/settings';
53
53
  import { BRAND_STEP_NAMES } from '../../../constants';
54
- import { isKW, isTwitter, isWebsite, sleep } from '../../../utils';
54
+ import { findInArrayOrSubArray, isKW, isTwitter, isWebsite, sleep } from '../../../utils';
55
55
  export var verifyLeadToken = createAsyncThunk('brandVerifyLeadToken', function (_a, thunkApi) {
56
56
  var token = _a.token, isInternally = _a.isInternally;
57
57
  return __awaiter(void 0, void 0, void 0, function () {
@@ -284,19 +284,19 @@ export var updateBrand = createAsyncThunk('brandUpdateBrand', function (params,
284
284
  };
285
285
  return [4, API.brandService.updateBrandInfo(requestBody)];
286
286
  case 1:
287
- brandData = (_f.sent()).data;
287
+ brandData = (_f.sent()).brand;
288
288
  activities = (((_c = brand.data.verify.responseBody) === null || _c === void 0 ? void 0 : _c.entity) || {}).activities;
289
289
  return [4, thunkApi.dispatch(retrieveDataList())];
290
290
  case 2:
291
291
  _f.sent();
292
292
  if (activities) {
293
- brandData = __assign(__assign({}, brandData), { brand_activities: activities || {} });
293
+ brandData = __assign(__assign({}, brandData), { entity_activities: activities || {} });
294
294
  }
295
295
  if (!!activities) return [3, 4];
296
296
  return [4, API.dataService.getActivities()];
297
297
  case 3:
298
298
  activityList = (_f.sent()).list;
299
- brandData = __assign(__assign({}, brandData), { brand_activities: activityList || {} });
299
+ brandData = __assign(__assign({}, brandData), { entity_activities: activityList || {} });
300
300
  _f.label = 4;
301
301
  case 4:
302
302
  thunkApi.dispatch(handleNextScreenStep());
@@ -317,7 +317,7 @@ export var retrieveEntityList = createAsyncThunk('retrieveEntityList', function
317
317
  });
318
318
  }); });
319
319
  export var updateBrandActivities = createAsyncThunk('brandUpdateBrandActivities', function (params, thunkApi) { return __awaiter(void 0, void 0, void 0, function () {
320
- var _a, settings, brand, brandResponse, id, isActivitiesEditable, isCustomerLocationEditable, isSalesRangeEditable, activities, customerLocations, expectedCustomer, expectedSale, customerLocation, customerBase, sales, stepName, requestBody, brandData;
320
+ var _a, settings, brand, brandResponse, id, isActivitiesEditable, isCustomerLocationEditable, isSalesRangeEditable, activities, customerLocations, expectedCustomer, expectedSale, requestBody, customerLocation, customerBaseId, salesId, customerBase, brandData;
321
321
  var _b, _c;
322
322
  return __generator(this, function (_d) {
323
323
  switch (_d.label) {
@@ -329,28 +329,26 @@ export var updateBrandActivities = createAsyncThunk('brandUpdateBrandActivities'
329
329
  isCustomerLocationEditable = true;
330
330
  isSalesRangeEditable = true;
331
331
  activities = params.activities, customerLocations = params.customerLocations, expectedCustomer = params.expectedCustomer, expectedSale = params.expectedSale;
332
- customerLocation = customerLocations.map(function (location) { return ({
333
- id: location.id
334
- }); });
335
- customerBase = ((expectedCustomer === null || expectedCustomer === void 0 ? void 0 : expectedCustomer.id) || customerLocation) && __assign(__assign({}, ((expectedCustomer === null || expectedCustomer === void 0 ? void 0 : expectedCustomer.id) && { id: expectedCustomer.id, period: 'monthly' })), (isCustomerLocationEditable && { location: customerLocation }));
336
- sales = (expectedSale === null || expectedSale === void 0 ? void 0 : expectedSale.id) && { id: expectedSale.id, period: 'monthly' };
337
- stepName = BRAND_STEP_NAMES.BRAND_ACTIVITIES;
338
332
  requestBody = {
339
333
  id: id,
340
334
  activities: isActivitiesEditable && activities,
341
- operations: {
342
- customer_base: customerBase,
343
- sales: (isSalesRangeEditable && sales)
344
- },
345
335
  term: ['general', 'refund', 'chargeback'],
346
- step_name: stepName
336
+ step_name: BRAND_STEP_NAMES.BRAND_ACTIVITIES
347
337
  };
338
+ customerLocation = customerLocations.map(function (location) { return ({
339
+ id: location.id
340
+ }); });
341
+ customerBaseId = (expectedCustomer === null || expectedCustomer === void 0 ? void 0 : expectedCustomer.id) && { id: expectedCustomer.id, period: 'monthly' };
342
+ salesId = (expectedSale === null || expectedSale === void 0 ? void 0 : expectedSale.id) && { id: expectedSale.id, period: 'monthly' };
343
+ customerBase = (customerBaseId || customerLocation.length) && __assign(__assign({}, (customerBaseId && { id: expectedCustomer.id, period: 'monthly' })), (customerLocation.length && { location: customerLocation }));
344
+ if (customerBase)
345
+ requestBody = __assign(__assign({}, requestBody), { operations: __assign(__assign({}, requestBody.operations), { customer_base: customerBase }) });
346
+ if (salesId && isSalesRangeEditable) {
347
+ requestBody = __assign(__assign({}, requestBody), { operations: __assign(__assign({}, requestBody.operations), { sales: salesId }) });
348
+ }
348
349
  return [4, API.brandService.updateBrandInfo(requestBody)];
349
350
  case 1:
350
351
  brandData = (_d.sent()).data;
351
- return [4, thunkApi.dispatch(retrieveDataList())];
352
- case 2:
353
- _d.sent();
354
352
  thunkApi.dispatch(handleNextScreenStep());
355
353
  (_c = (_b = settings.data.appConfig).onStepCompleted) === null || _c === void 0 ? void 0 : _c.call(_b, settings.data.activeScreen.name, id);
356
354
  return [2, { data: __assign({}, brandData), formData: params }];
@@ -402,14 +400,12 @@ export var updateBoardSuccess = createAsyncThunk('updateBoardBrandSuccess', func
402
400
  step_name: BRAND_STEP_NAMES.BRAND_SUCCESS,
403
401
  id: id
404
402
  };
405
- return [4, API.boardService.updateBoardInfo(__assign({ id: id, infoId: infoId }, payload))];
406
- case 1:
407
- data = _g.sent();
403
+ data = {};
408
404
  return [4, API.boardService.retrieveBoardInfoStatus(id)];
409
- case 2:
405
+ case 1:
410
406
  boardInfoData = _g.sent();
411
- return [4, thunkApi.dispatch(retrieveBoardDetails(id))];
412
- case 3:
407
+ return [4, thunkApi.dispatch(retrieveBoardDetails(id)).unwrap()];
408
+ case 2:
413
409
  _g.sent();
414
410
  (_d = (_c = settings.data.appConfig).onStepCompleted) === null || _d === void 0 ? void 0 : _d.call(_c, settings.data.activeScreen.name, {});
415
411
  (_f = (_e = settings.data.appConfig).onFlowCompleted) === null || _f === void 0 ? void 0 : _f.call(_e, { data: data });
@@ -577,14 +573,20 @@ export var brandSlice = createSlice({
577
573
  state.loading = false;
578
574
  state.error = null;
579
575
  var _a = action.payload, data = _a.data, formData = _a.formData;
580
- var brand = (state.data.verify.responseBody || {}).brand;
581
- var activities = data.brand_activities;
582
- var selectedActivity = activities === null || activities === void 0 ? void 0 : activities.filter(function (activity) {
583
- var activities = (brand || {}).activities;
576
+ var entity_activities = data.entity_activities, activities = data.activities, operations = data.operations;
577
+ var selectedActivity = entity_activities === null || entity_activities === void 0 ? void 0 : entity_activities.filter(function (activity) {
584
578
  return activities === null || activities === void 0 ? void 0 : activities.find(function (value) { return activity.id === value.id; });
585
579
  });
586
580
  state.data.brandData = formData;
587
581
  state.data.brandActivities.activities = (selectedActivity === null || selectedActivity === void 0 ? void 0 : selectedActivity.length) > 0 ? selectedActivity : [];
582
+ var _b = operations || {}, customer_base = _b.customer_base, sales = _b.sales;
583
+ var _c = state.data.brandActivities.responseBody || {}, customerBases = _c.customerBases, expectedSales = _c.expectedSales, expectedCustomerSales = _c.expectedCustomerSales;
584
+ var findCustomerBase = findInArrayOrSubArray(expectedCustomerSales, customer_base === null || customer_base === void 0 ? void 0 : customer_base.id);
585
+ var findSale = findInArrayOrSubArray(expectedSales, sales === null || sales === void 0 ? void 0 : sales.id);
586
+ if (!!findSale)
587
+ state.data.brandActivities.expectedSale = findSale;
588
+ if (!!findCustomerBase)
589
+ state.data.brandActivities.expectedCustomer = findCustomerBase;
588
590
  state.data.verify.responseBody = __assign(__assign({}, state.data.verify.responseBody), { activities: data === null || data === void 0 ? void 0 : data.brand_activities });
589
591
  })
590
592
  .addCase(updateBrandActivities.rejected, function (state, action) {
@@ -612,9 +614,9 @@ export var brandSlice = createSlice({
612
614
  state.error = null;
613
615
  var _a = action.payload, customerBases = _a.customerBases, expectedSales = _a.expectedSales, expectedCustomerSales = _a.expectedCustomerSales, countryISO2 = _a.countryISO2;
614
616
  var local = customerBases.at(0);
615
- state.data.brandActivities.responseBody = __assign(__assign({}, state.data.brandActivities.responseBody), { customerBases: customerBases, expectedSales: expectedSales, expectedCustomerSales: expectedCustomerSales });
616
617
  if (local && isKW(countryISO2))
617
618
  state.data.brandActivities.customerLocations = [local];
619
+ state.data.brandActivities.responseBody = __assign(__assign({}, state.data.brandActivities.responseBody), { customerBases: customerBases, expectedSales: expectedSales, expectedCustomerSales: expectedCustomerSales });
618
620
  })
619
621
  .addCase(retrieveDataList.rejected, function (state, action) {
620
622
  state.loading = false;
@@ -638,13 +640,7 @@ export var brandSlice = createSlice({
638
640
  var _a;
639
641
  state.loading = false;
640
642
  state.error = null;
641
- var response = (action.payload || {}).response;
642
- var description = (((_a = response === null || response === void 0 ? void 0 : response.errors) === null || _a === void 0 ? void 0 : _a[0]) || {}).description;
643
- if (description) {
644
- state.error = description;
645
- return;
646
- }
647
- var flows = response.flows;
643
+ var flows = (((_a = action.payload) === null || _a === void 0 ? void 0 : _a.response) || {}).flows;
648
644
  state.data.verify.responseBody = __assign(__assign({}, state.data.verify.responseBody), { flows: flows });
649
645
  })
650
646
  .addCase(updateBoardSuccess.pending, function (state) {
@@ -97,7 +97,7 @@ export default function CustomButton(_a) {
97
97
  if (!loading)
98
98
  setTimeout(function () {
99
99
  setBtnLoading(false);
100
- }, 1500);
100
+ }, 1000);
101
101
  }, [loading]);
102
102
  React.useEffect(function () {
103
103
  setBtnLoading(false);
@@ -63,3 +63,4 @@ export declare const fixBrandList: (items: Array<{
63
63
  export declare const findFirstId: (items: Array<SaleChannel>) => string;
64
64
  export declare const sortActivitiesByName: (items: Array<Activity>, path: string) => Activity[];
65
65
  export declare const getRecentDocumentFiles: (documents: Array<any>, purpose: string) => any;
66
+ export declare const findInArrayOrSubArray: (items: Array<any>, value: string | number) => null;
@@ -150,3 +150,17 @@ export var getRecentDocumentFiles = function (documents, purpose) {
150
150
  .filter(function (doc) { return (doc.file_details || []).find(function (file) { return file.purpose === purpose; }); })
151
151
  .sort(function (a, b) { return b.created - a.created; })[0]) === null || _a === void 0 ? void 0 : _a.file_details) || []);
152
152
  };
153
+ export var findInArrayOrSubArray = function (items, value) {
154
+ var found = null;
155
+ items.forEach(function (item) {
156
+ if (item.id === value)
157
+ found = item;
158
+ if (Array.isArray(item.sub)) {
159
+ item.sub.forEach(function (subItem) {
160
+ if (subItem.id === value)
161
+ found = subItem;
162
+ });
163
+ }
164
+ });
165
+ return found;
166
+ };
package/package.json CHANGED
@@ -1,129 +1,129 @@
1
- {
2
- "name": "@tap-payments/auth-jsconnect",
3
- "version": "2.2.5-test",
4
- "description": "connect library, auth",
5
- "private": false,
6
- "main": "build/index.js",
7
- "module": "build/index.js",
8
- "types": "build/index.d.ts",
9
- "files": [
10
- "build",
11
- "README.md"
12
- ],
13
- "scripts": {
14
- "husky:setup": "npx husky install",
15
- "prettier": "prettier --list-different \"src/**/*.{md,mdx,ts,js,tsx,jsx,json}\" *.json *.js",
16
- "prettier:fix": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,md,css,json}\" *.json *.js",
17
- "lint": "eslint src --color --ext .js,.jsx,.ts,.tsx,.json",
18
- "lint:fix": "eslint src --ext .js,.jsx,.ts,.tsx --fix",
19
- "start": "cross-env NODE_ENV=development webpack serve",
20
- "build": "rm -rf build && cross-env NODE_ENV=production webpack",
21
- "copy:files": "copyfiles -u 1 src/**/*.css build/",
22
- "tsc:alias": "tsc-alias -p tsconfig.json",
23
- "ts:build": "rm -rf build && tsc -p tsconfig.json && tsc-alias -p tsconfig.json && yarn copy:files",
24
- "push": "npm publish --access public"
25
- },
26
- "keywords": [],
27
- "author": {
28
- "name": "Ahmed Elsharkawy",
29
- "email": "a.elsharkawy@tap.company"
30
- },
31
- "license": "ISC",
32
- "devDependencies": {
33
- "@babel/core": "^7.18.6",
34
- "@babel/preset-env": "^7.18.6",
35
- "@babel/preset-react": "^7.18.6",
36
- "@babel/preset-typescript": "^7.18.6",
37
- "@types/lodash-es": "^4.17.6",
38
- "@types/react": "^18.0.15",
39
- "@types/react-calendar": "~3.5.1",
40
- "@types/react-dom": "^18.0.6",
41
- "@typescript-eslint/eslint-plugin": "^5.30.5",
42
- "@typescript-eslint/parser": "^5.30.5",
43
- "babel-loader": "^8.2.5",
44
- "copyfiles": "^2.4.1",
45
- "cross-env": "^7.0.3",
46
- "css-loader": "^6.7.1",
47
- "css-minimizer-webpack-plugin": "^4.0.0",
48
- "eslint": "^8.19.0",
49
- "eslint-config-airbnb": "^19.0.4",
50
- "eslint-config-prettier": "^8.5.0",
51
- "eslint-plugin-import": "^2.26.0",
52
- "eslint-plugin-jsx-a11y": "^6.6.0",
53
- "eslint-plugin-node": "^11.1.0",
54
- "eslint-plugin-prettier": "^4.2.1",
55
- "eslint-plugin-react": "^7.30.1",
56
- "eslint-plugin-react-hooks": "^4.6.0",
57
- "file-loader": "^6.2.0",
58
- "fork-ts-checker-webpack-plugin": "^7.2.12",
59
- "html-loader": "^3.1.2",
60
- "html-webpack-plugin": "^5.5.0",
61
- "husky": "^8.0.1",
62
- "lint-staged": "^13.0.3",
63
- "mini-css-extract-plugin": "^2.6.1",
64
- "prettier": "^2.7.1",
65
- "sass": "^1.53.0",
66
- "sass-loader": "^13.0.2",
67
- "style-loader": "^3.3.1",
68
- "terser-webpack-plugin": "^5.3.3",
69
- "tsc-alias": "^1.6.11",
70
- "typescript": "^4.7.4",
71
- "webpack": "^5.73.0",
72
- "webpack-cli": "^4.10.0",
73
- "webpack-dev-server": "^4.9.3",
74
- "webpack-merge": "^5.8.0"
75
- },
76
- "dependencies": {
77
- "@emotion/react": "^11.9.3",
78
- "@emotion/styled": "^11.9.3",
79
- "@fingerprintjs/fingerprintjs": "~3.3.4",
80
- "@hookform/resolvers": "^2.9.6",
81
- "@mui/icons-material": "^5.8.4",
82
- "@mui/material": "^5.8.7",
83
- "@reduxjs/toolkit": "^1.8.3",
84
- "axios": "^0.27.2",
85
- "device-detector-js": "^3.0.3",
86
- "i18next": "^21.8.14",
87
- "i18next-browser-languagedetector": "^6.1.4",
88
- "i18next-http-backend": "^1.4.1",
89
- "jsencrypt": "^2.3.1",
90
- "lodash-es": "^4.17.21",
91
- "lottie-web": "^5.9.6",
92
- "moment": "^2.29.4",
93
- "react": "^18.2.0",
94
- "react-calendar": "~3.7.0",
95
- "react-device-detect": "^2.2.2",
96
- "react-dom": "^18.2.0",
97
- "react-dropzone": "^14.2.2",
98
- "react-hook-form": "^7.33.1",
99
- "react-i18next": "^11.18.1",
100
- "react-multi-date-picker": "^3.3.4",
101
- "react-otp-input": "^2.4.0",
102
- "react-redux": "^8.0.2",
103
- "react-spring-bottom-sheet": "^3.4.1",
104
- "yup": "^0.32.11"
105
- },
106
- "peerDependencies": {
107
- "react": "^18.2.0",
108
- "react-dom": "^18.2.0"
109
- },
110
- "lint-staged": {
111
- "src/**/*.{ts,tsx,json,js,jsx}": [
112
- "yarn run prettier:fix",
113
- "yarn run lint",
114
- "git add ."
115
- ]
116
- },
117
- "browserslist": {
118
- "production": [
119
- ">0.2%",
120
- "not dead",
121
- "not op_mini all"
122
- ],
123
- "development": [
124
- "last 1 chrome version",
125
- "last 1 firefox version",
126
- "last 1 safari version"
127
- ]
128
- }
129
- }
1
+ {
2
+ "name": "@tap-payments/auth-jsconnect",
3
+ "version": "2.3.2-test",
4
+ "description": "connect library, auth",
5
+ "private": false,
6
+ "main": "build/index.js",
7
+ "module": "build/index.js",
8
+ "types": "build/index.d.ts",
9
+ "files": [
10
+ "build",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "husky:setup": "npx husky install",
15
+ "prettier": "prettier --list-different \"src/**/*.{md,mdx,ts,js,tsx,jsx,json}\" *.json *.js",
16
+ "prettier:fix": "prettier --write \"src/**/*.{ts,tsx,js,jsx,json,md,css,json}\" *.json *.js",
17
+ "lint": "eslint src --color --ext .js,.jsx,.ts,.tsx,.json",
18
+ "lint:fix": "eslint src --ext .js,.jsx,.ts,.tsx --fix",
19
+ "start": "cross-env NODE_ENV=development webpack serve",
20
+ "build": "rm -rf build && cross-env NODE_ENV=production webpack",
21
+ "copy:files": "copyfiles -u 1 src/**/*.css build/",
22
+ "tsc:alias": "tsc-alias -p tsconfig.json",
23
+ "ts:build": "rm -rf build && tsc -p tsconfig.json && tsc-alias -p tsconfig.json && yarn copy:files",
24
+ "push": "npm publish --access public"
25
+ },
26
+ "keywords": [],
27
+ "author": {
28
+ "name": "Ahmed Elsharkawy",
29
+ "email": "a.elsharkawy@tap.company"
30
+ },
31
+ "license": "ISC",
32
+ "devDependencies": {
33
+ "@babel/core": "^7.18.6",
34
+ "@babel/preset-env": "^7.18.6",
35
+ "@babel/preset-react": "^7.18.6",
36
+ "@babel/preset-typescript": "^7.18.6",
37
+ "@types/lodash-es": "^4.17.6",
38
+ "@types/react": "^18.0.15",
39
+ "@types/react-calendar": "~3.5.1",
40
+ "@types/react-dom": "^18.0.6",
41
+ "@typescript-eslint/eslint-plugin": "^5.30.5",
42
+ "@typescript-eslint/parser": "^5.30.5",
43
+ "babel-loader": "^8.2.5",
44
+ "copyfiles": "^2.4.1",
45
+ "cross-env": "^7.0.3",
46
+ "css-loader": "^6.7.1",
47
+ "css-minimizer-webpack-plugin": "^4.0.0",
48
+ "eslint": "^8.19.0",
49
+ "eslint-config-airbnb": "^19.0.4",
50
+ "eslint-config-prettier": "^8.5.0",
51
+ "eslint-plugin-import": "^2.26.0",
52
+ "eslint-plugin-jsx-a11y": "^6.6.0",
53
+ "eslint-plugin-node": "^11.1.0",
54
+ "eslint-plugin-prettier": "^4.2.1",
55
+ "eslint-plugin-react": "^7.30.1",
56
+ "eslint-plugin-react-hooks": "^4.6.0",
57
+ "file-loader": "^6.2.0",
58
+ "fork-ts-checker-webpack-plugin": "^7.2.12",
59
+ "html-loader": "^3.1.2",
60
+ "html-webpack-plugin": "^5.5.0",
61
+ "husky": "^8.0.1",
62
+ "lint-staged": "^13.0.3",
63
+ "mini-css-extract-plugin": "^2.6.1",
64
+ "prettier": "^2.7.1",
65
+ "sass": "^1.53.0",
66
+ "sass-loader": "^13.0.2",
67
+ "style-loader": "^3.3.1",
68
+ "terser-webpack-plugin": "^5.3.3",
69
+ "tsc-alias": "^1.6.11",
70
+ "typescript": "^4.7.4",
71
+ "webpack": "^5.73.0",
72
+ "webpack-cli": "^4.10.0",
73
+ "webpack-dev-server": "^4.9.3",
74
+ "webpack-merge": "^5.8.0"
75
+ },
76
+ "dependencies": {
77
+ "@emotion/react": "^11.9.3",
78
+ "@emotion/styled": "^11.9.3",
79
+ "@fingerprintjs/fingerprintjs": "~3.3.4",
80
+ "@hookform/resolvers": "^2.9.6",
81
+ "@mui/icons-material": "^5.8.4",
82
+ "@mui/material": "^5.8.7",
83
+ "@reduxjs/toolkit": "^1.8.3",
84
+ "axios": "^0.27.2",
85
+ "device-detector-js": "^3.0.3",
86
+ "i18next": "^21.8.14",
87
+ "i18next-browser-languagedetector": "^6.1.4",
88
+ "i18next-http-backend": "^1.4.1",
89
+ "jsencrypt": "^2.3.1",
90
+ "lodash-es": "^4.17.21",
91
+ "lottie-web": "^5.9.6",
92
+ "moment": "^2.29.4",
93
+ "react": "^18.2.0",
94
+ "react-calendar": "~3.7.0",
95
+ "react-device-detect": "^2.2.2",
96
+ "react-dom": "^18.2.0",
97
+ "react-dropzone": "^14.2.2",
98
+ "react-hook-form": "^7.33.1",
99
+ "react-i18next": "^11.18.1",
100
+ "react-multi-date-picker": "^3.3.4",
101
+ "react-otp-input": "^2.4.0",
102
+ "react-redux": "^8.0.2",
103
+ "react-spring-bottom-sheet": "^3.4.1",
104
+ "yup": "^0.32.11"
105
+ },
106
+ "peerDependencies": {
107
+ "react": "^18.2.0",
108
+ "react-dom": "^18.2.0"
109
+ },
110
+ "lint-staged": {
111
+ "src/**/*.{ts,tsx,json,js,jsx}": [
112
+ "yarn run prettier:fix",
113
+ "yarn run lint",
114
+ "git add ."
115
+ ]
116
+ },
117
+ "browserslist": {
118
+ "production": [
119
+ ">0.2%",
120
+ "not dead",
121
+ "not op_mini all"
122
+ ],
123
+ "development": [
124
+ "last 1 chrome version",
125
+ "last 1 firefox version",
126
+ "last 1 safari version"
127
+ ]
128
+ }
129
+ }