@shopgate/pwa-common 7.32.1 → 7.32.2-alpha.10
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/actions/app/handleLink.js +5 -6
- package/collections/AuthRoutes.js +0 -1
- package/collections/PersistedReducers.js +0 -1
- package/collections/media-providers/YouTube.js +0 -1
- package/components/ErrorBoundary/index.js +4 -3
- package/components/I18n/components/Translate/index.js +0 -1
- package/components/Link/index.js +0 -1
- package/components/Portal/index.d.ts.map +1 -1
- package/components/Portal/index.js +4 -1
- package/components/Router/index.js +0 -1
- package/helpers/config/index.d.ts.map +1 -1
- package/helpers/config/index.js +0 -2
- package/helpers/data/index.js +0 -3
- package/helpers/dom/index.js +0 -1
- package/helpers/html/handleDOM.js +0 -3
- package/helpers/i18n/getTranslator.js +0 -1
- package/helpers/i18n/mergeTranslations.js +0 -1
- package/helpers/redux/mutable.js +0 -2
- package/helpers/router/index.js +0 -3
- package/helpers/style/index.js +0 -1
- package/package.json +11 -8
- package/reducers/page/index.js +0 -1
- package/selectors/client.js +0 -1
- package/store/index.js +3 -13
- package/store/middelwares/logger.js +113 -6
- package/streams/main.js +1 -4
- package/subscriptions/error.js +130 -80
- package/subscriptions/helpers/handleLinks.js +0 -4
- package/subscriptions/router.js +0 -5
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import "core-js/modules/es.array.includes.js";
|
|
2
|
-
import "core-js/modules/es.string.replace.js";
|
|
3
|
-
import "core-js/modules/web.url.js";
|
|
4
|
-
import "core-js/modules/web.url.to-json.js";
|
|
5
|
-
import "core-js/modules/web.url-search-params.js";
|
|
6
1
|
import { logger } from '@shopgate/pwa-core/helpers';
|
|
7
2
|
import { DEEPLINK_CART_ADD_PRODUCT_PATTERN } from '@shopgate/pwa-common-commerce/cart/constants';
|
|
8
3
|
import fetchProduct from '@shopgate/pwa-common-commerce/product/actions/fetchProduct';
|
|
@@ -44,7 +39,11 @@ export default function handleLink(payload, allowExternalLinks = false) {
|
|
|
44
39
|
pathname
|
|
45
40
|
} = new URL(link));
|
|
46
41
|
} catch (linkParseError) {
|
|
47
|
-
|
|
42
|
+
// The error is sent to Sentry. Query string, hash and credentials in front of the host can
|
|
43
|
+
// contain secrets, so they are left out, and so is the error of the browser, which can
|
|
44
|
+
// contain the whole link.
|
|
45
|
+
const loggedLink = link.split(/[?#]/)[0].replace(/^([^/]*\/\/)[^/@]*@/, '$1');
|
|
46
|
+
logger.error(new Error(`Could not parse link ${loggedLink}`));
|
|
48
47
|
}
|
|
49
48
|
} else {
|
|
50
49
|
// Remove the deeplink protocol from the link.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
|
|
2
2
|
import { PureComponent } from 'react';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
|
+
import { toError } from '@shopgate/pwa-core/helpers/error';
|
|
4
5
|
import connector from "./connector";
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -35,9 +36,9 @@ let ErrorBoundary = /*#__PURE__*/function (_PureComponent) {
|
|
|
35
36
|
};
|
|
36
37
|
var _proto = ErrorBoundary.prototype;
|
|
37
38
|
_proto.componentDidCatch = function componentDidCatch(error, errorInfo) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
this.props.appError(toError(error, {
|
|
40
|
+
componentStack: errorInfo.componentStack
|
|
41
|
+
}));
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
/**
|
package/components/Link/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/Portal/index.jsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../components/Portal/index.jsx"],"names":[],"mappings":";AAQA;;GAEG;AACH;IACE;;;;MAIE;IAEF;;;MAGE;IAEF;;;OAGG;IACH,mBAFW,MAAM,EAUhB;IALC;;MAEC;IAED,kBAAsD;IAGxD;;;;OAIG;IACH,yBAHW,KAAK,QACL,MAAM,QAKhB;IAED;;;;OAIG;IACH,wBAAyB,OAHd,MAGmB,WAa5B;IAEF;;;;OAIG;IACH,sBAAuB,MAHZ,MAGgB,WA0CzB;IAEF;;;OAGG;IACH,UAFY,GAAG,CAiCd;CACF;kBAxJ8C,OAAO;sBAChC,YAAY"}
|
|
@@ -2,6 +2,7 @@ import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
|
|
|
2
2
|
import React, { PureComponent, Suspense } from 'react';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import { logger } from '@shopgate/pwa-core/helpers';
|
|
5
|
+
import { toError } from '@shopgate/pwa-core/helpers/error';
|
|
5
6
|
import Loading from "../Loading";
|
|
6
7
|
import portalCollection from "../../helpers/portals/portalCollection";
|
|
7
8
|
import { componentsConfig } from "../../helpers/config";
|
|
@@ -104,7 +105,9 @@ let Portal = /*#__PURE__*/function (_PureComponent) {
|
|
|
104
105
|
this.setState({
|
|
105
106
|
hasError: true
|
|
106
107
|
});
|
|
107
|
-
logger.error(error,
|
|
108
|
+
logger.error(toError(error, {
|
|
109
|
+
componentStack: info.componentStack
|
|
110
|
+
}));
|
|
108
111
|
};
|
|
109
112
|
/**
|
|
110
113
|
* Renders the component.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose";
|
|
2
|
-
import "core-js/modules/es.string.replace.js";
|
|
3
2
|
import React from 'react';
|
|
4
3
|
import PropTypes from 'prop-types';
|
|
5
4
|
import { router, stack as routeStack, onDidPush, onDidPop, onDidReplace, onDidReset, onUpdate, ACTION_POP } from '@virtuous/conductor';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../helpers/config/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../helpers/config/index.js"],"names":[],"mappings":"AAwJA;;;;GAIG;AACH,yCAHW,MAAM,oBACN,mBAAmB,GAAC,IAAI,QAKlC;AA/GD;;GAEG;AACH,yBAFU,MAAM,CAEsB;AAWtC;;;GAGG;AACH,+BAFU,MAAM,CAKd;AASF;;;GAGG;AACH,wBAFU,MAAM,CAEsC;AAEtD;;;GAGG;AACH,0BAFU,WAAW,CAEkC;AAEvD,yBAAyB;AACzB,8BAA8C;AAC9C,0BAA0B;AAC1B,+BAAgD;AAChD,4BAA4B;AAC5B,iCAAoD;AACpD,wBAAwB;AACxB,6BAA4C;AAK5C;;;;;;;;;;GAUG;AACH,2CANU,mBAAmB,CA8B3B;AAWK,gDAPI,MAAM,SACN,GAAC,SACD,GAAC,aACD,MAAM,aACN,MAAM,GACJ,OAAO,CAGK;AAiBzB,6BAAkE;;AA/FlE;;;;GAIG;AACH,6BAA8F"}
|
package/helpers/config/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import "core-js/modules/es.string.replace.js";
|
|
2
1
|
import pck from "../../package.json";
|
|
3
2
|
import { buildThemeConfig } from "./theme";
|
|
4
3
|
import { assignObjectDeep } from "../data";
|
|
@@ -27,7 +26,6 @@ const defaultAppConfig = {
|
|
|
27
26
|
shopCNAME: null,
|
|
28
27
|
currency: 'USD',
|
|
29
28
|
showGmdMenuSubHeaders: false,
|
|
30
|
-
benchmark: false,
|
|
31
29
|
sentry: {},
|
|
32
30
|
theme: {},
|
|
33
31
|
cartShippingHideAnonymousLegacy: null,
|
package/helpers/data/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import "core-js/modules/es.array.includes.js";
|
|
2
|
-
import "core-js/modules/es.array.reduce.js";
|
|
3
|
-
import "core-js/modules/es.string.replace.js";
|
|
4
1
|
import { logger } from '@shopgate/pwa-core/helpers';
|
|
5
2
|
import { isAndroidOs } from '@shopgate/pwa-core';
|
|
6
3
|
import { isObject, isArray } from "../validation";
|
package/helpers/dom/index.js
CHANGED
package/helpers/redux/mutable.js
CHANGED
package/helpers/router/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import "core-js/modules/es.array.reduce.js";
|
|
2
|
-
import "core-js/modules/es.string.replace.js";
|
|
3
|
-
import "core-js/modules/web.url-search-params.js";
|
|
4
1
|
import { createBrowserHistory } from 'history';
|
|
5
2
|
import { router } from '@virtuous/conductor';
|
|
6
3
|
import { logger } from '@shopgate/pwa-core/helpers';
|
package/helpers/style/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shopgate/pwa-common",
|
|
3
|
-
"version": "7.32.
|
|
3
|
+
"version": "7.32.2-alpha.10",
|
|
4
4
|
"description": "Common library for the Shopgate Connect PWA.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Shopgate <support@shopgate.com>",
|
|
7
|
-
"repository":
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/shopgate/pwa.git",
|
|
10
|
+
"directory": "libraries/common"
|
|
11
|
+
},
|
|
8
12
|
"bugs": "https://github.com/shopgate/pwa/issues",
|
|
9
13
|
"homepage": "https://github.com/shopgate/pwa/tree/master/libraries/common",
|
|
10
14
|
"keywords": [
|
|
@@ -16,8 +20,7 @@
|
|
|
16
20
|
],
|
|
17
21
|
"dependencies": {
|
|
18
22
|
"@redux-devtools/extension": "^3.3.0",
|
|
19
|
-
"@sentry/browser": "
|
|
20
|
-
"@shopgate/pwa-benchmark": "7.32.1",
|
|
23
|
+
"@sentry/browser": "^7.120.4",
|
|
21
24
|
"@virtuous/conductor": "~2.5.0",
|
|
22
25
|
"@virtuous/react-conductor": "~2.5.0",
|
|
23
26
|
"@virtuous/redux-persister": "1.1.0-beta.7",
|
|
@@ -28,22 +31,22 @@
|
|
|
28
31
|
"history": "^4.9.0",
|
|
29
32
|
"intl-messageformat": "^11.2.9",
|
|
30
33
|
"path-match": "^1.2.4",
|
|
34
|
+
"react-cookie": "^8.1.2",
|
|
31
35
|
"react-dotdotdot": "~1.3.1",
|
|
32
36
|
"react-helmet": "^6.1.0",
|
|
33
37
|
"react-portal": "^3.1.0",
|
|
34
38
|
"react-redux": "^8.1.3",
|
|
35
39
|
"redux": "^5.0.1",
|
|
36
|
-
"redux-logger": "^3.0.6",
|
|
37
40
|
"redux-thunk": "^3.1.0",
|
|
38
41
|
"reselect": "^4.1.8",
|
|
39
42
|
"rxjs": "~5.5.12",
|
|
40
43
|
"swiper": "12.2.0"
|
|
41
44
|
},
|
|
42
45
|
"devDependencies": {
|
|
43
|
-
"@shopgate/pwa-core": "7.32.
|
|
44
|
-
"@types/lodash": "^4.17.
|
|
46
|
+
"@shopgate/pwa-core": "7.32.2-alpha.10",
|
|
47
|
+
"@types/lodash": "^4.17.25",
|
|
45
48
|
"@types/react-portal": "^3.0.9",
|
|
46
|
-
"lodash": "^4.
|
|
49
|
+
"lodash": "^4.18.1",
|
|
47
50
|
"prop-types": "~15.8.1",
|
|
48
51
|
"react": "^17.0.2",
|
|
49
52
|
"react-dom": "^17.0.2"
|
package/reducers/page/index.js
CHANGED
package/selectors/client.js
CHANGED
package/store/index.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import "core-js/modules/es.string.replace.js";
|
|
2
1
|
import { createStore, applyMiddleware } from 'redux';
|
|
3
2
|
import { thunk } from 'redux-thunk';
|
|
4
3
|
import { composeWithDevTools } from '@redux-devtools/extension';
|
|
5
4
|
import { persistState } from '@virtuous/redux-persister';
|
|
6
|
-
import benchmarkMiddleware from '@shopgate/pwa-benchmark/profilers/redux';
|
|
7
|
-
import benchmarkController from '@shopgate/pwa-benchmark';
|
|
8
5
|
import persistedReducers from "../collections/PersistedReducers";
|
|
9
6
|
import initSubscribers from "../subscriptions";
|
|
10
|
-
import
|
|
7
|
+
import { themeName, shopNumber } from "../helpers/config";
|
|
11
8
|
import makeRootReducer from "../reducers";
|
|
12
9
|
import streams from "./middelwares/streams";
|
|
13
10
|
import logger from "./middelwares/logger";
|
|
@@ -31,7 +28,7 @@ function getInitialState() {
|
|
|
31
28
|
if (!storedState) {
|
|
32
29
|
return undefined;
|
|
33
30
|
}
|
|
34
|
-
const normalizedState = storedState.replace(
|
|
31
|
+
const normalizedState = storedState.replace(/"isFetching":true/g, '"isFetching":false');
|
|
35
32
|
return JSON.parse(normalizedState);
|
|
36
33
|
}
|
|
37
34
|
|
|
@@ -42,18 +39,11 @@ function getInitialState() {
|
|
|
42
39
|
* @return {Object} The redux store.
|
|
43
40
|
*/
|
|
44
41
|
export function configureStore(reducers, subscribers) {
|
|
45
|
-
|
|
46
|
-
if (appConfig.benchmark) {
|
|
47
|
-
benchmarkController.startup();
|
|
48
|
-
}
|
|
49
|
-
const store = createStore(makeRootReducer(reducers), getInitialState(), composeWithDevTools(applyMiddleware.apply(void 0, [thunk].concat(appConfig.benchmark ? [benchmarkMiddleware] : [], [streams, logger])), persistState({
|
|
42
|
+
const store = createStore(makeRootReducer(reducers), getInitialState(), composeWithDevTools(applyMiddleware.apply(void 0, [thunk, streams, logger]), persistState({
|
|
50
43
|
key: storeKey,
|
|
51
44
|
paths: persistedReducers.getAll()
|
|
52
45
|
})));
|
|
53
46
|
initSubscribers(subscribers);
|
|
54
|
-
if (window.Cypress) {
|
|
55
|
-
window.store = store;
|
|
56
|
-
}
|
|
57
47
|
return store;
|
|
58
48
|
}
|
|
59
49
|
|
|
@@ -1,7 +1,114 @@
|
|
|
1
|
-
import { createLogger } from 'redux-logger';
|
|
2
1
|
import { logger } from '@shopgate/pwa-core';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
const STORAGE_KEY = 'sgReduxLogger';
|
|
3
|
+
const MUTED = 'color: gray; font-weight: lighter;';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Reads whether the logger was switched off with sgReduxLogger.off().
|
|
7
|
+
* @return {boolean}
|
|
8
|
+
*/
|
|
9
|
+
const isSwitchedOff = () => {
|
|
10
|
+
try {
|
|
11
|
+
return window.localStorage.getItem(STORAGE_KEY) === 'off';
|
|
12
|
+
} catch (e) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
let enabled = !isSwitchedOff();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Remembers the switch for the next app start.
|
|
20
|
+
* @param {boolean} value Whether actions are logged.
|
|
21
|
+
* @return {boolean} Whether the switch could be saved.
|
|
22
|
+
*/
|
|
23
|
+
const saveSwitch = value => {
|
|
24
|
+
try {
|
|
25
|
+
if (value) {
|
|
26
|
+
window.localStorage.removeItem(STORAGE_KEY);
|
|
27
|
+
} else {
|
|
28
|
+
window.localStorage.setItem(STORAGE_KEY, 'off');
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Switches the logger on or off.
|
|
38
|
+
* @param {boolean} value Whether actions are logged.
|
|
39
|
+
*/
|
|
40
|
+
const setEnabled = value => {
|
|
41
|
+
enabled = value;
|
|
42
|
+
const saved = saveSwitch(value);
|
|
43
|
+
logger.info(`Redux logger switched ${value ? 'on' : 'off'}${saved ? '' : ' until the next reload'}`);
|
|
44
|
+
};
|
|
45
|
+
window.sgReduxLogger = {
|
|
46
|
+
on: () => setEnabled(true),
|
|
47
|
+
off: () => setEnabled(false)
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Formats the time of a date, e.g. 14:03:07.042.
|
|
52
|
+
* @param {Date} date The date.
|
|
53
|
+
* @return {string}
|
|
54
|
+
*/
|
|
55
|
+
const formatTime = date => [date.getHours(), date.getMinutes(), date.getSeconds()].map(value => String(value).padStart(2, '0')).join(':').concat(`.${String(date.getMilliseconds()).padStart(3, '0')}`);
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Prints an action as a collapsed console group.
|
|
59
|
+
* @param {Object} entry The logged action with the states before and after it.
|
|
60
|
+
*/
|
|
61
|
+
const printEntry = ({
|
|
62
|
+
action,
|
|
63
|
+
prevState,
|
|
64
|
+
nextState,
|
|
65
|
+
error,
|
|
66
|
+
startedAt,
|
|
67
|
+
took
|
|
68
|
+
}) => {
|
|
69
|
+
logger.groupCollapsed(`%c action %c${String(action.type)} %c@ ${formatTime(startedAt)} %c(in ${took.toFixed(2)} ms)`, MUTED, 'color: inherit;', MUTED, MUTED);
|
|
70
|
+
logger.log('%c prev state', 'color: #9E9E9E; font-weight: bold', prevState);
|
|
71
|
+
logger.log('%c action ', 'color: #03A9F4; font-weight: bold', action);
|
|
72
|
+
if (error) {
|
|
73
|
+
logger.log('%c error ', 'color: #F20404; font-weight: bold;', error);
|
|
74
|
+
}
|
|
75
|
+
logger.log('%c next state', 'color: #4CAF50; font-weight: bold', nextState);
|
|
76
|
+
logger.groupEnd();
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Logs every action with the state before and after it to the console, unless the logger was
|
|
81
|
+
* switched off with sgReduxLogger.off() in the console.
|
|
82
|
+
* @param {Object} store The redux store.
|
|
83
|
+
* @return {Function}
|
|
84
|
+
*/
|
|
85
|
+
const loggerMiddleware = ({
|
|
86
|
+
getState
|
|
87
|
+
}) => next => action => {
|
|
88
|
+
if (!enabled) {
|
|
89
|
+
return next(action);
|
|
90
|
+
}
|
|
91
|
+
const startedAt = new Date();
|
|
92
|
+
const started = performance.now();
|
|
93
|
+
const prevState = getState();
|
|
94
|
+
let result;
|
|
95
|
+
let error;
|
|
96
|
+
try {
|
|
97
|
+
result = next(action);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
error = e;
|
|
100
|
+
}
|
|
101
|
+
printEntry({
|
|
102
|
+
action,
|
|
103
|
+
prevState,
|
|
104
|
+
nextState: getState(),
|
|
105
|
+
error,
|
|
106
|
+
startedAt,
|
|
107
|
+
took: performance.now() - started
|
|
108
|
+
});
|
|
109
|
+
if (error) {
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
return result;
|
|
113
|
+
};
|
|
114
|
+
export default loggerMiddleware;
|
package/streams/main.js
CHANGED
|
@@ -23,7 +23,4 @@ import { mainSubject } from "../store/middelwares/streams";
|
|
|
23
23
|
* Gets triggered on every redux action that is dispatched.
|
|
24
24
|
* @type {Observable}
|
|
25
25
|
*/
|
|
26
|
-
export const main$ = Observable.from(mainSubject);
|
|
27
|
-
if (window.Cypress) {
|
|
28
|
-
window.main$ = main$;
|
|
29
|
-
}
|
|
26
|
+
export const main$ = Observable.from(mainSubject);
|
package/subscriptions/error.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import "core-js/modules/es.array.includes.js";
|
|
2
1
|
import { isAvailable } from '@shopgate/native-modules';
|
|
3
|
-
import { init, addBreadcrumb,
|
|
2
|
+
import { init, addBreadcrumb, setTags, captureException, captureEvent, withScope } from '@sentry/browser';
|
|
3
|
+
import { router } from '@virtuous/conductor';
|
|
4
4
|
import { EBIGAPI, emitter, errorManager, ETIMEOUT, ENETUNREACH, EUNKNOWN, EFAVORITE } from '@shopgate/pwa-core';
|
|
5
5
|
import { hasWebBridge } from '@shopgate/engage/core';
|
|
6
6
|
import { SOURCE_TRACKING, SOURCE_CONSOLE, Severity } from '@shopgate/pwa-core/constants/ErrorManager';
|
|
7
|
+
import { describeValue } from '@shopgate/pwa-core/helpers/error';
|
|
7
8
|
import { main$ } from "../streams/main";
|
|
8
9
|
import {
|
|
9
10
|
// eslint-disable-next-line import/no-named-default
|
|
@@ -12,23 +13,45 @@ import { env } from "../helpers/environment";
|
|
|
12
13
|
import { transformGeneralPipelineError, getDisplayErrorMessage } from "./helpers/pipeline";
|
|
13
14
|
import { historyPop } from "../actions/router";
|
|
14
15
|
import showModal from "../actions/modal/showModal";
|
|
15
|
-
import { getUserData } from "../selectors/user";
|
|
16
|
-
import { userDidUpdate$ } from "../streams/user";
|
|
17
16
|
import { clientInformationDidUpdate$ } from "../streams/client";
|
|
18
|
-
import { appWillInit$, appWillStart
|
|
17
|
+
import { appWillInit$, appWillStart$ } from "../streams/app";
|
|
19
18
|
import { appError$, pipelineError$ } from "../streams/error";
|
|
20
19
|
import { getRouterStack } from "../selectors/router";
|
|
21
20
|
import { MODAL_PIPELINE_ERROR } from "../constants/ModalTypes";
|
|
21
|
+
import { APP_ERROR } from "../constants/ActionTypes";
|
|
22
22
|
import ToastProvider from "../providers/toast";
|
|
23
23
|
|
|
24
24
|
// Generic, translated fallback shown when a backend error carries no code we can map to a message.
|
|
25
25
|
const GENERIC_ERROR_MESSAGE = 'modal.body_error';
|
|
26
26
|
|
|
27
|
+
/**
|
|
28
|
+
* @param {*} error The rejection reason or exception.
|
|
29
|
+
* @returns {boolean} Whether the error was created by the PipelineManager.
|
|
30
|
+
*/
|
|
31
|
+
const isPipelineError = error => !!error && typeof error.code === 'string' && typeof error.handled === 'boolean';
|
|
32
|
+
|
|
27
33
|
/**
|
|
28
34
|
* App errors subscriptions.
|
|
29
35
|
* @param {Function} subscribe The subscribe function.
|
|
30
36
|
*/
|
|
31
37
|
export default subscribe => {
|
|
38
|
+
subscribe(appWillInit$, () => {
|
|
39
|
+
window.addEventListener('unhandledrejection', event => {
|
|
40
|
+
const {
|
|
41
|
+
reason
|
|
42
|
+
} = event;
|
|
43
|
+
if (!isPipelineError(reason)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
if (env === 'development') {
|
|
48
|
+
const hint = reason.handled ? 'The default error handling already handled it' : 'The request excluded it from the default error handling (blacklisted or suppressed), so the action is expected to handle it';
|
|
49
|
+
// eslint-disable-next-line no-console
|
|
50
|
+
console.info(`Pipeline error not handled by the caller: ${reason.code} (${reason.message}). ${hint}; add .catch() if the caller needs to react.`);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
32
55
|
/** Set general error transformations */
|
|
33
56
|
subscribe(appWillStart$, () => {
|
|
34
57
|
errorManager.setMessage({
|
|
@@ -160,16 +183,30 @@ export default subscribe => {
|
|
|
160
183
|
return;
|
|
161
184
|
}
|
|
162
185
|
const severityMap = {
|
|
163
|
-
[Severity.Fatal]:
|
|
164
|
-
[Severity.Error]:
|
|
165
|
-
[Severity.Critical]:
|
|
166
|
-
[Severity.Warning]:
|
|
167
|
-
[Severity.Info]:
|
|
168
|
-
[Severity.Debug]:
|
|
186
|
+
[Severity.Fatal]: 'fatal',
|
|
187
|
+
[Severity.Error]: 'error',
|
|
188
|
+
[Severity.Critical]: 'fatal',
|
|
189
|
+
[Severity.Warning]: 'warning',
|
|
190
|
+
[Severity.Info]: 'info',
|
|
191
|
+
[Severity.Debug]: 'debug'
|
|
169
192
|
};
|
|
170
193
|
const ignoredDefaultBreadcrumbs = ['console', 'fetch', 'xhr', 'ui.click'];
|
|
171
|
-
|
|
172
|
-
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* @param {string} url An absolute or relative URL of the app.
|
|
197
|
+
* @returns {string} The URL with its route path replaced by the route pattern, e.g.
|
|
198
|
+
* `/orders/:orderId`, and without query string and hash.
|
|
199
|
+
*/
|
|
200
|
+
const redactUrl = url => {
|
|
201
|
+
if (typeof url !== 'string') {
|
|
202
|
+
return url;
|
|
203
|
+
}
|
|
204
|
+
const [path] = url.split(/[?#]/);
|
|
205
|
+
const [, base, routePath] = /^(.*?index\.html)(.*)$/.exec(path) || /^([a-z][a-z\d+.-]*:\/\/[^/]+)(.*)$/i.exec(path) || [null, '', path];
|
|
206
|
+
return `${base}${router.findPattern(routePath || '/') || '/(unknown route)'}`;
|
|
207
|
+
};
|
|
208
|
+
let trackedSeverities = Object.values(severityMap);
|
|
209
|
+
const minSeverityIndex = Object.keys(severityMap).indexOf(level);
|
|
173
210
|
if (minSeverityIndex > -1) {
|
|
174
211
|
trackedSeverities = trackedSeverities.slice(0, minSeverityIndex + 1);
|
|
175
212
|
}
|
|
@@ -183,54 +220,86 @@ export default subscribe => {
|
|
|
183
220
|
release: pckVersion,
|
|
184
221
|
attachStacktrace: true,
|
|
185
222
|
sampleRate,
|
|
223
|
+
ignoreErrors: [/play\(\) failed because the user didn't interact/],
|
|
186
224
|
beforeBreadcrumb(breadcrumb) {
|
|
187
225
|
if (ignoredDefaultBreadcrumbs.includes(breadcrumb.category)) {
|
|
188
226
|
return null;
|
|
189
227
|
}
|
|
228
|
+
if (breadcrumb.category === 'navigation' && breadcrumb.data) {
|
|
229
|
+
return {
|
|
230
|
+
...breadcrumb,
|
|
231
|
+
data: {
|
|
232
|
+
from: redactUrl(breadcrumb.data.from),
|
|
233
|
+
to: redactUrl(breadcrumb.data.to)
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
190
237
|
return breadcrumb;
|
|
191
238
|
},
|
|
192
|
-
beforeSend(event) {
|
|
239
|
+
beforeSend(event, hint) {
|
|
193
240
|
if (event.level && !trackedSeverities.includes(event.level)) {
|
|
194
241
|
return null;
|
|
195
242
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
243
|
+
if (isPipelineError(hint?.originalException)) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
...event,
|
|
248
|
+
request: event.request && {
|
|
249
|
+
...event.request,
|
|
250
|
+
url: redactUrl(event.request.url),
|
|
251
|
+
headers: event.request.headers && {
|
|
252
|
+
...event.request.headers,
|
|
253
|
+
Referer: redactUrl(event.request.headers.Referer)
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
extra: {
|
|
257
|
+
...(event.extra || {}),
|
|
258
|
+
routerStack: getRouterStack(getState()).slice(-5).map(({
|
|
259
|
+
pattern
|
|
260
|
+
}) => ({
|
|
261
|
+
pattern
|
|
262
|
+
}))
|
|
263
|
+
}
|
|
200
264
|
};
|
|
201
|
-
return event;
|
|
202
265
|
}
|
|
203
266
|
});
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
267
|
+
setTags({
|
|
268
|
+
marketId: appConfig.marketId,
|
|
269
|
+
appId: appConfig.appId,
|
|
270
|
+
pwaVersion: pckVersion,
|
|
271
|
+
theme: themeName,
|
|
272
|
+
language: appConfig.language,
|
|
273
|
+
isWebsite: hasWebBridge(),
|
|
274
|
+
isReactNativeApp: isAvailable(),
|
|
275
|
+
merchantCode: appConfig.omniMerchantCode
|
|
213
276
|
});
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
277
|
+
emitter.addListener(SOURCE_CONSOLE, args => {
|
|
278
|
+
const error = args.find(arg => arg instanceof Error);
|
|
279
|
+
const texts = args.filter(arg => arg !== error).map(describeValue);
|
|
280
|
+
if (!error) {
|
|
281
|
+
addBreadcrumb({
|
|
282
|
+
category: 'logger',
|
|
283
|
+
message: texts.join(' '),
|
|
284
|
+
level: 'error'
|
|
285
|
+
});
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
220
288
|
withScope(scope => {
|
|
221
|
-
|
|
289
|
+
scope.setLevel('error');
|
|
290
|
+
scope.setTag('source', SOURCE_CONSOLE);
|
|
291
|
+
if (texts.length > 0) {
|
|
292
|
+
scope.setExtra('details', texts);
|
|
293
|
+
}
|
|
294
|
+
if (error.source === SOURCE_TRACKING && error.context) {
|
|
222
295
|
scope.setExtra('trackerName', error.context);
|
|
223
296
|
}
|
|
297
|
+
if (error.componentStack) {
|
|
298
|
+
scope.setExtra('componentStack', error.componentStack);
|
|
299
|
+
}
|
|
224
300
|
captureException(error);
|
|
225
301
|
});
|
|
226
302
|
});
|
|
227
|
-
emitter.addListener(SOURCE_CONSOLE, args => {
|
|
228
|
-
withScope(scope => {
|
|
229
|
-
scope.setLevel(SentrySeverity.Error);
|
|
230
|
-
scope.setExtra('error', args);
|
|
231
|
-
captureMessage('Console error');
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
303
|
});
|
|
235
304
|
subscribe(main$, ({
|
|
236
305
|
action
|
|
@@ -238,20 +307,7 @@ export default subscribe => {
|
|
|
238
307
|
addBreadcrumb({
|
|
239
308
|
category: 'redux',
|
|
240
309
|
message: `[Redux] ${action.type}`,
|
|
241
|
-
level:
|
|
242
|
-
data: {
|
|
243
|
-
...action
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
subscribe(userDidUpdate$, ({
|
|
248
|
-
getState
|
|
249
|
-
}) => {
|
|
250
|
-
const {
|
|
251
|
-
id: userId
|
|
252
|
-
} = getUserData(getState());
|
|
253
|
-
configureScope(scope => {
|
|
254
|
-
scope.setTag('userId', userId);
|
|
310
|
+
level: 'info'
|
|
255
311
|
});
|
|
256
312
|
});
|
|
257
313
|
|
|
@@ -261,21 +317,11 @@ export default subscribe => {
|
|
|
261
317
|
}) => {
|
|
262
318
|
const {
|
|
263
319
|
appVersion,
|
|
264
|
-
libVersion
|
|
265
|
-
deviceId
|
|
320
|
+
libVersion
|
|
266
321
|
} = action.data;
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
scope.setTag('deviceId', deviceId);
|
|
271
|
-
});
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
// Add app start event for debugging
|
|
275
|
-
subscribe(appDidStart$, () => {
|
|
276
|
-
withScope(scope => {
|
|
277
|
-
scope.setLevel(SentrySeverity.Debug);
|
|
278
|
-
captureMessage('App did start');
|
|
322
|
+
setTags({
|
|
323
|
+
appVersion,
|
|
324
|
+
libVersion
|
|
279
325
|
});
|
|
280
326
|
});
|
|
281
327
|
|
|
@@ -283,9 +329,12 @@ export default subscribe => {
|
|
|
283
329
|
subscribe(appError$, ({
|
|
284
330
|
action
|
|
285
331
|
}) => {
|
|
332
|
+
if (!(action.error instanceof Error)) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
286
335
|
withScope(scope => {
|
|
287
|
-
if (action.error.
|
|
288
|
-
scope.setExtra('
|
|
336
|
+
if (action.error.componentStack) {
|
|
337
|
+
scope.setExtra('componentStack', action.error.componentStack);
|
|
289
338
|
}
|
|
290
339
|
captureException(action.error);
|
|
291
340
|
});
|
|
@@ -299,19 +348,20 @@ export default subscribe => {
|
|
|
299
348
|
error = {}
|
|
300
349
|
} = action;
|
|
301
350
|
const {
|
|
302
|
-
code
|
|
303
|
-
message,
|
|
304
|
-
meta: {
|
|
305
|
-
message: metaMessage
|
|
306
|
-
} = {}
|
|
351
|
+
code
|
|
307
352
|
} = error;
|
|
353
|
+
if (action.type === APP_ERROR && error instanceof Error) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
308
356
|
withScope(scope => {
|
|
309
357
|
scope.setTag('error', 'E_USER');
|
|
310
358
|
scope.setTag('errorCode', code);
|
|
311
|
-
scope.setTag('errorMessage', message);
|
|
312
359
|
captureEvent({
|
|
313
|
-
message:
|
|
314
|
-
extra:
|
|
360
|
+
message: code ? `User error ${code}` : 'User error',
|
|
361
|
+
extra: {
|
|
362
|
+
code,
|
|
363
|
+
pipeline: error.context
|
|
364
|
+
}
|
|
315
365
|
});
|
|
316
366
|
});
|
|
317
367
|
});
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import "core-js/modules/es.array.includes.js";
|
|
2
|
-
import "core-js/modules/web.url.js";
|
|
3
|
-
import "core-js/modules/web.url.to-json.js";
|
|
4
|
-
import "core-js/modules/web.url-search-params.js";
|
|
5
1
|
import { router, ACTION_REPLACE } from '@virtuous/conductor';
|
|
6
2
|
import flushTab from '@shopgate/pwa-core/commands/flushTab';
|
|
7
3
|
import openPage from '@shopgate/pwa-core/commands/openPage';
|
package/subscriptions/router.js
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import "core-js/modules/es.array.includes.js";
|
|
2
|
-
import "core-js/modules/es.string.replace.js";
|
|
3
|
-
import "core-js/modules/web.url.js";
|
|
4
|
-
import "core-js/modules/web.url.to-json.js";
|
|
5
|
-
import "core-js/modules/web.url-search-params.js";
|
|
6
1
|
import queryString from 'query-string';
|
|
7
2
|
import { router, ACTION_POP, ACTION_PUSH, ACTION_REPLACE, ACTION_RESET } from '@virtuous/conductor';
|
|
8
3
|
import Route from '@virtuous/conductor/Route';
|