dreaction-react 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +255 -0
- package/lib/components/ConfigPanel.d.ts +12 -0
- package/lib/components/ConfigPanel.d.ts.map +1 -0
- package/lib/components/ConfigPanel.js +151 -0
- package/lib/dreaction.d.ts +32 -0
- package/lib/dreaction.d.ts.map +1 -0
- package/lib/dreaction.js +110 -0
- package/lib/hooks.d.ts +17 -0
- package/lib/hooks.d.ts.map +1 -0
- package/lib/hooks.js +111 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +23 -0
- package/lib/plugins/localStorage.d.ts +14 -0
- package/lib/plugins/localStorage.d.ts.map +1 -0
- package/lib/plugins/localStorage.js +85 -0
- package/lib/plugins/networking.d.ts +11 -0
- package/lib/plugins/networking.d.ts.map +1 -0
- package/lib/plugins/networking.js +263 -0
- package/lib/plugins/trackGlobalErrors.d.ts +25 -0
- package/lib/plugins/trackGlobalErrors.d.ts.map +1 -0
- package/lib/plugins/trackGlobalErrors.js +149 -0
- package/lib/plugins/trackGlobalLogs.d.ts +10 -0
- package/lib/plugins/trackGlobalLogs.d.ts.map +1 -0
- package/lib/plugins/trackGlobalLogs.js +42 -0
- package/package.json +35 -0
- package/src/components/ConfigPanel.tsx +247 -0
- package/src/dreaction.ts +181 -0
- package/src/hooks.ts +129 -0
- package/src/index.ts +17 -0
- package/src/plugins/localStorage.ts +100 -0
- package/src/plugins/networking.ts +333 -0
- package/src/plugins/trackGlobalErrors.ts +203 -0
- package/src/plugins/trackGlobalLogs.ts +53 -0
package/lib/hooks.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useConnectionStatus = useConnectionStatus;
|
|
4
|
+
exports.useDReactionConfig = useDReactionConfig;
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const dreaction_1 = require("./dreaction");
|
|
7
|
+
const STORAGE_KEY_HOST = 'DREACTION_host';
|
|
8
|
+
const STORAGE_KEY_PORT = 'DREACTION_port';
|
|
9
|
+
const STORAGE_KEY_AUTO_CONNECT = 'DREACTION_autoConnect';
|
|
10
|
+
/**
|
|
11
|
+
* Hook to manage DReaction connection status
|
|
12
|
+
*/
|
|
13
|
+
function useConnectionStatus() {
|
|
14
|
+
const [isConnected, setIsConnected] = (0, react_1.useState)(dreaction_1.dreaction.connected);
|
|
15
|
+
(0, react_1.useEffect)(() => {
|
|
16
|
+
const checkConnection = () => {
|
|
17
|
+
setIsConnected(dreaction_1.dreaction.connected);
|
|
18
|
+
};
|
|
19
|
+
// Check connection status periodically
|
|
20
|
+
const interval = setInterval(checkConnection, 1000);
|
|
21
|
+
return () => clearInterval(interval);
|
|
22
|
+
}, []);
|
|
23
|
+
return isConnected;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Hook to manage DReaction configuration
|
|
27
|
+
*/
|
|
28
|
+
function useDReactionConfig() {
|
|
29
|
+
const [host, setHost] = (0, react_1.useState)(() => {
|
|
30
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
31
|
+
return window.localStorage.getItem(STORAGE_KEY_HOST) || 'localhost';
|
|
32
|
+
}
|
|
33
|
+
return 'localhost';
|
|
34
|
+
});
|
|
35
|
+
const [port, setPort] = (0, react_1.useState)(() => {
|
|
36
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
37
|
+
const stored = window.localStorage.getItem(STORAGE_KEY_PORT);
|
|
38
|
+
return stored ? parseInt(stored, 10) : 9600;
|
|
39
|
+
}
|
|
40
|
+
return 9600;
|
|
41
|
+
});
|
|
42
|
+
const [isConnected, setIsConnected] = (0, react_1.useState)(dreaction_1.dreaction.connected);
|
|
43
|
+
const hasAutoConnected = (0, react_1.useRef)(false);
|
|
44
|
+
// Auto-connect on mount if previously connected
|
|
45
|
+
(0, react_1.useEffect)(() => {
|
|
46
|
+
if (hasAutoConnected.current)
|
|
47
|
+
return;
|
|
48
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
49
|
+
const shouldAutoConnect = window.localStorage.getItem(STORAGE_KEY_AUTO_CONNECT);
|
|
50
|
+
if (shouldAutoConnect === 'true' && !dreaction_1.dreaction.connected) {
|
|
51
|
+
hasAutoConnected.current = true;
|
|
52
|
+
// Auto-reconnect with saved settings
|
|
53
|
+
dreaction_1.dreaction.configure({
|
|
54
|
+
host,
|
|
55
|
+
port,
|
|
56
|
+
});
|
|
57
|
+
dreaction_1.dreaction.connect();
|
|
58
|
+
setIsConnected(true);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}, [host, port]);
|
|
62
|
+
(0, react_1.useEffect)(() => {
|
|
63
|
+
const checkConnection = () => {
|
|
64
|
+
setIsConnected(dreaction_1.dreaction.connected);
|
|
65
|
+
};
|
|
66
|
+
// Check connection status periodically
|
|
67
|
+
const interval = setInterval(checkConnection, 1000);
|
|
68
|
+
return () => clearInterval(interval);
|
|
69
|
+
}, []);
|
|
70
|
+
const updateHost = (newHost) => {
|
|
71
|
+
setHost(newHost);
|
|
72
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
73
|
+
window.localStorage.setItem(STORAGE_KEY_HOST, newHost);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
const updatePort = (newPort) => {
|
|
77
|
+
setPort(newPort);
|
|
78
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
79
|
+
window.localStorage.setItem(STORAGE_KEY_PORT, newPort.toString());
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const connect = () => {
|
|
83
|
+
dreaction_1.dreaction.configure({
|
|
84
|
+
host,
|
|
85
|
+
port,
|
|
86
|
+
});
|
|
87
|
+
dreaction_1.dreaction.connect();
|
|
88
|
+
setIsConnected(true);
|
|
89
|
+
// Save auto-connect preference
|
|
90
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
91
|
+
window.localStorage.setItem(STORAGE_KEY_AUTO_CONNECT, 'true');
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const disconnect = () => {
|
|
95
|
+
dreaction_1.dreaction.close();
|
|
96
|
+
setIsConnected(false);
|
|
97
|
+
// Clear auto-connect preference
|
|
98
|
+
if (typeof window !== 'undefined' && window.localStorage) {
|
|
99
|
+
window.localStorage.setItem(STORAGE_KEY_AUTO_CONNECT, 'false');
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
host,
|
|
104
|
+
port,
|
|
105
|
+
isConnected,
|
|
106
|
+
updateHost,
|
|
107
|
+
updatePort,
|
|
108
|
+
connect,
|
|
109
|
+
disconnect,
|
|
110
|
+
};
|
|
111
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { dreaction, reactCorePlugins } from './dreaction';
|
|
2
|
+
export type { DReactionReact, UseReactOptions } from './dreaction';
|
|
3
|
+
export { ConfigPanel } from './components/ConfigPanel';
|
|
4
|
+
export type { ConfigPanelProps } from './components/ConfigPanel';
|
|
5
|
+
export { useConnectionStatus, useDReactionConfig } from './hooks';
|
|
6
|
+
export { default as networking } from './plugins/networking';
|
|
7
|
+
export type { NetworkingOptions } from './plugins/networking';
|
|
8
|
+
export { default as localStorage } from './plugins/localStorage';
|
|
9
|
+
export type { LocalStorageOptions } from './plugins/localStorage';
|
|
10
|
+
export { default as trackGlobalLogs } from './plugins/trackGlobalLogs';
|
|
11
|
+
export { default as trackGlobalErrors } from './plugins/trackGlobalErrors';
|
|
12
|
+
export type { TrackGlobalErrorsOptions, ErrorStackFrame, } from './plugins/trackGlobalErrors';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1D,YAAY,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGlE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACjE,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,YAAY,EACV,wBAAwB,EACxB,eAAe,GAChB,MAAM,6BAA6B,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.trackGlobalErrors = exports.trackGlobalLogs = exports.localStorage = exports.networking = exports.useDReactionConfig = exports.useConnectionStatus = exports.ConfigPanel = exports.reactCorePlugins = exports.dreaction = void 0;
|
|
7
|
+
var dreaction_1 = require("./dreaction");
|
|
8
|
+
Object.defineProperty(exports, "dreaction", { enumerable: true, get: function () { return dreaction_1.dreaction; } });
|
|
9
|
+
Object.defineProperty(exports, "reactCorePlugins", { enumerable: true, get: function () { return dreaction_1.reactCorePlugins; } });
|
|
10
|
+
var ConfigPanel_1 = require("./components/ConfigPanel");
|
|
11
|
+
Object.defineProperty(exports, "ConfigPanel", { enumerable: true, get: function () { return ConfigPanel_1.ConfigPanel; } });
|
|
12
|
+
var hooks_1 = require("./hooks");
|
|
13
|
+
Object.defineProperty(exports, "useConnectionStatus", { enumerable: true, get: function () { return hooks_1.useConnectionStatus; } });
|
|
14
|
+
Object.defineProperty(exports, "useDReactionConfig", { enumerable: true, get: function () { return hooks_1.useDReactionConfig; } });
|
|
15
|
+
// Plugin exports
|
|
16
|
+
var networking_1 = require("./plugins/networking");
|
|
17
|
+
Object.defineProperty(exports, "networking", { enumerable: true, get: function () { return __importDefault(networking_1).default; } });
|
|
18
|
+
var localStorage_1 = require("./plugins/localStorage");
|
|
19
|
+
Object.defineProperty(exports, "localStorage", { enumerable: true, get: function () { return __importDefault(localStorage_1).default; } });
|
|
20
|
+
var trackGlobalLogs_1 = require("./plugins/trackGlobalLogs");
|
|
21
|
+
Object.defineProperty(exports, "trackGlobalLogs", { enumerable: true, get: function () { return __importDefault(trackGlobalLogs_1).default; } });
|
|
22
|
+
var trackGlobalErrors_1 = require("./plugins/trackGlobalErrors");
|
|
23
|
+
Object.defineProperty(exports, "trackGlobalErrors", { enumerable: true, get: function () { return __importDefault(trackGlobalErrors_1).default; } });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DReactionCore } from 'dreaction-client-core';
|
|
2
|
+
export interface LocalStorageOptions {
|
|
3
|
+
ignore?: string[];
|
|
4
|
+
}
|
|
5
|
+
declare const localStorage: (options?: LocalStorageOptions) => (dreaction: DReactionCore) => {
|
|
6
|
+
onConnect: () => void;
|
|
7
|
+
onDisconnect: () => void;
|
|
8
|
+
features: {
|
|
9
|
+
trackLocalStorage: () => void;
|
|
10
|
+
untrackLocalStorage: () => void;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
export default localStorage;
|
|
14
|
+
//# sourceMappingURL=localStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localStorage.d.ts","sourceRoot":"","sources":["../../src/plugins/localStorage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAU,MAAM,uBAAuB,CAAC;AAEnE,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAMD,QAAA,MAAM,YAAY,aACL,mBAAmB,iBAAiB,aAAa;;;;;;;CAsF3D,CAAC;AAEJ,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const PLUGIN_DEFAULTS = {
|
|
4
|
+
ignore: [],
|
|
5
|
+
};
|
|
6
|
+
const localStorage = (options) => (dreaction) => {
|
|
7
|
+
// setup configuration
|
|
8
|
+
const config = Object.assign({}, PLUGIN_DEFAULTS, options || {});
|
|
9
|
+
const ignore = config.ignore || PLUGIN_DEFAULTS.ignore;
|
|
10
|
+
let originalSetItem;
|
|
11
|
+
let originalRemoveItem;
|
|
12
|
+
let originalClear;
|
|
13
|
+
let isIntercepted = false;
|
|
14
|
+
const sendToDReaction = (action, data) => {
|
|
15
|
+
dreaction.send('asyncStorage.mutation', { action: action, data });
|
|
16
|
+
};
|
|
17
|
+
const setItem = function (key, value) {
|
|
18
|
+
try {
|
|
19
|
+
if (ignore.indexOf(key) < 0) {
|
|
20
|
+
sendToDReaction('setItem', { key, value });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
// ignore errors
|
|
25
|
+
}
|
|
26
|
+
return originalSetItem.call(this, key, value);
|
|
27
|
+
};
|
|
28
|
+
const removeItem = function (key) {
|
|
29
|
+
try {
|
|
30
|
+
if (ignore.indexOf(key) < 0) {
|
|
31
|
+
sendToDReaction('removeItem', { key });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
// ignore errors
|
|
36
|
+
}
|
|
37
|
+
return originalRemoveItem.call(this, key);
|
|
38
|
+
};
|
|
39
|
+
const clear = function () {
|
|
40
|
+
try {
|
|
41
|
+
sendToDReaction('clear');
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
// ignore errors
|
|
45
|
+
}
|
|
46
|
+
return originalClear.call(this);
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Hijacks the localStorage API.
|
|
50
|
+
*/
|
|
51
|
+
const trackLocalStorage = () => {
|
|
52
|
+
if (isIntercepted)
|
|
53
|
+
return;
|
|
54
|
+
if (typeof window === 'undefined' || !window.localStorage)
|
|
55
|
+
return;
|
|
56
|
+
originalSetItem = Storage.prototype.setItem;
|
|
57
|
+
Storage.prototype.setItem = setItem;
|
|
58
|
+
originalRemoveItem = Storage.prototype.removeItem;
|
|
59
|
+
Storage.prototype.removeItem = removeItem;
|
|
60
|
+
originalClear = Storage.prototype.clear;
|
|
61
|
+
Storage.prototype.clear = clear;
|
|
62
|
+
isIntercepted = true;
|
|
63
|
+
};
|
|
64
|
+
const untrackLocalStorage = () => {
|
|
65
|
+
if (!isIntercepted)
|
|
66
|
+
return;
|
|
67
|
+
Storage.prototype.setItem = originalSetItem;
|
|
68
|
+
Storage.prototype.removeItem = originalRemoveItem;
|
|
69
|
+
Storage.prototype.clear = originalClear;
|
|
70
|
+
isIntercepted = false;
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
onConnect: () => {
|
|
74
|
+
trackLocalStorage();
|
|
75
|
+
},
|
|
76
|
+
onDisconnect: () => {
|
|
77
|
+
untrackLocalStorage();
|
|
78
|
+
},
|
|
79
|
+
features: {
|
|
80
|
+
trackLocalStorage,
|
|
81
|
+
untrackLocalStorage,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
exports.default = localStorage;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DReactionCore } from 'dreaction-client-core';
|
|
2
|
+
export interface NetworkingOptions {
|
|
3
|
+
ignoreContentTypes?: RegExp;
|
|
4
|
+
ignoreUrls?: RegExp;
|
|
5
|
+
}
|
|
6
|
+
declare const networking: (pluginConfig?: NetworkingOptions) => (dreaction: DReactionCore) => {
|
|
7
|
+
onConnect: () => void;
|
|
8
|
+
onDisconnect: () => void;
|
|
9
|
+
};
|
|
10
|
+
export default networking;
|
|
11
|
+
//# sourceMappingURL=networking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"networking.d.ts","sourceRoot":"","sources":["../../src/plugins/networking.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAU,MAAM,uBAAuB,CAAC;AAOnE,MAAM,WAAW,iBAAiB;IAChC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,QAAA,MAAM,UAAU,kBACC,iBAAiB,iBACpB,aAAa;;;CAwTxB,CAAC;AAEJ,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Don't include the response bodies for images by default.
|
|
5
|
+
*/
|
|
6
|
+
const DEFAULT_CONTENT_TYPES_RX = /^(image)\/.*$/i;
|
|
7
|
+
const DEFAULTS = {
|
|
8
|
+
ignoreUrls: /symbolicate/,
|
|
9
|
+
};
|
|
10
|
+
const networking = (pluginConfig = {}) => (dreaction) => {
|
|
11
|
+
const options = Object.assign({}, DEFAULTS, pluginConfig);
|
|
12
|
+
// a RegExp to suppress adding the body cuz it costs a lot to serialize
|
|
13
|
+
const ignoreContentTypes = options.ignoreContentTypes || DEFAULT_CONTENT_TYPES_RX;
|
|
14
|
+
// a XHR call tracker
|
|
15
|
+
let dreactionCounter = 1000;
|
|
16
|
+
// a temporary cache to hold requests so we can match up the data
|
|
17
|
+
const requestCache = {};
|
|
18
|
+
// Store original functions
|
|
19
|
+
let originalXHROpen;
|
|
20
|
+
let originalXHRSend;
|
|
21
|
+
let originalFetch;
|
|
22
|
+
/**
|
|
23
|
+
* Intercept XMLHttpRequest
|
|
24
|
+
*/
|
|
25
|
+
const interceptXHR = () => {
|
|
26
|
+
originalXHROpen = XMLHttpRequest.prototype.open;
|
|
27
|
+
originalXHRSend = XMLHttpRequest.prototype.send;
|
|
28
|
+
XMLHttpRequest.prototype.open = function (method, url, ...rest) {
|
|
29
|
+
this._method = method;
|
|
30
|
+
this._url = url.toString();
|
|
31
|
+
return originalXHROpen.apply(this, [method, url, ...rest]);
|
|
32
|
+
};
|
|
33
|
+
XMLHttpRequest.prototype.send = function (data) {
|
|
34
|
+
const xhr = this;
|
|
35
|
+
if (options.ignoreUrls && options.ignoreUrls.test(xhr._url)) {
|
|
36
|
+
xhr._skipDReaction = true;
|
|
37
|
+
return originalXHRSend.apply(this, [data]);
|
|
38
|
+
}
|
|
39
|
+
// bump the counter
|
|
40
|
+
dreactionCounter++;
|
|
41
|
+
// tag
|
|
42
|
+
xhr._trackingName = dreactionCounter;
|
|
43
|
+
// cache
|
|
44
|
+
requestCache[dreactionCounter] = {
|
|
45
|
+
data,
|
|
46
|
+
xhr,
|
|
47
|
+
stopTimer: dreaction.startTimer(),
|
|
48
|
+
};
|
|
49
|
+
// Setup listener for response
|
|
50
|
+
const originalOnReadyStateChange = xhr.onreadystatechange;
|
|
51
|
+
xhr.onreadystatechange = function () {
|
|
52
|
+
if (originalOnReadyStateChange) {
|
|
53
|
+
originalOnReadyStateChange.apply(this, arguments);
|
|
54
|
+
}
|
|
55
|
+
if (xhr.readyState === 4) {
|
|
56
|
+
handleXHRResponse(xhr);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
return originalXHRSend.apply(this, [data]);
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Handle XHR response
|
|
64
|
+
*/
|
|
65
|
+
const handleXHRResponse = (xhr) => {
|
|
66
|
+
if (xhr._skipDReaction) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const url = xhr._url;
|
|
70
|
+
let params = null;
|
|
71
|
+
const queryParamIdx = url ? url.indexOf('?') : -1;
|
|
72
|
+
if (queryParamIdx > -1) {
|
|
73
|
+
params = {};
|
|
74
|
+
url
|
|
75
|
+
.substr(queryParamIdx + 1)
|
|
76
|
+
.split('&')
|
|
77
|
+
.forEach((pair) => {
|
|
78
|
+
const [key, value] = pair.split('=');
|
|
79
|
+
if (key && value !== undefined) {
|
|
80
|
+
params[key] = decodeURIComponent(value.replace(/\+/g, ' '));
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
// fetch and clear the request data from the cache
|
|
85
|
+
const rid = xhr._trackingName;
|
|
86
|
+
const cachedRequest = requestCache[rid] || { xhr };
|
|
87
|
+
requestCache[rid] = null;
|
|
88
|
+
// assemble the request object
|
|
89
|
+
const { data, stopTimer } = cachedRequest;
|
|
90
|
+
// Parse request headers
|
|
91
|
+
let requestHeaders = {};
|
|
92
|
+
try {
|
|
93
|
+
const requestHeaderString = xhr._requestHeaders;
|
|
94
|
+
if (requestHeaderString) {
|
|
95
|
+
requestHeaders = requestHeaderString;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
// ignore
|
|
100
|
+
}
|
|
101
|
+
const tronRequest = {
|
|
102
|
+
url: url || cachedRequest.xhr._url,
|
|
103
|
+
method: xhr._method || null,
|
|
104
|
+
data,
|
|
105
|
+
headers: requestHeaders || null,
|
|
106
|
+
params,
|
|
107
|
+
};
|
|
108
|
+
// Parse response headers
|
|
109
|
+
let responseHeaders = {};
|
|
110
|
+
try {
|
|
111
|
+
const headersString = xhr.getAllResponseHeaders();
|
|
112
|
+
if (headersString) {
|
|
113
|
+
headersString.split('\r\n').forEach((line) => {
|
|
114
|
+
const parts = line.split(': ');
|
|
115
|
+
if (parts.length === 2) {
|
|
116
|
+
responseHeaders[parts[0]] = parts[1];
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
// ignore
|
|
123
|
+
}
|
|
124
|
+
// what type of content is this?
|
|
125
|
+
const contentType = responseHeaders['content-type'] ||
|
|
126
|
+
responseHeaders['Content-Type'] ||
|
|
127
|
+
'';
|
|
128
|
+
let body = `~~~ skipped ~~~`;
|
|
129
|
+
const response = xhr.response || xhr.responseText;
|
|
130
|
+
// can we use the real response?
|
|
131
|
+
const useRealResponse = (typeof response === 'string' || typeof response === 'object') &&
|
|
132
|
+
!ignoreContentTypes.test(contentType || '');
|
|
133
|
+
if (useRealResponse && response) {
|
|
134
|
+
try {
|
|
135
|
+
// Try to parse JSON
|
|
136
|
+
if (typeof response === 'string') {
|
|
137
|
+
body = JSON.parse(response);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
body = response;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
body = response;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const tronResponse = {
|
|
148
|
+
body,
|
|
149
|
+
status: xhr.status,
|
|
150
|
+
headers: responseHeaders || null,
|
|
151
|
+
};
|
|
152
|
+
dreaction.apiResponse(tronRequest, tronResponse, stopTimer ? stopTimer() : null);
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Intercept fetch API
|
|
156
|
+
*/
|
|
157
|
+
const interceptFetch = () => {
|
|
158
|
+
originalFetch = window.fetch;
|
|
159
|
+
window.fetch = function (input, init) {
|
|
160
|
+
const url = typeof input === 'string'
|
|
161
|
+
? input
|
|
162
|
+
: input instanceof Request
|
|
163
|
+
? input.url
|
|
164
|
+
: input.toString();
|
|
165
|
+
if (options.ignoreUrls && options.ignoreUrls.test(url)) {
|
|
166
|
+
return originalFetch.call(this, input, init);
|
|
167
|
+
}
|
|
168
|
+
// bump the counter
|
|
169
|
+
dreactionCounter++;
|
|
170
|
+
const requestId = dreactionCounter;
|
|
171
|
+
const stopTimer = dreaction.startTimer();
|
|
172
|
+
// Parse URL and params
|
|
173
|
+
let params = null;
|
|
174
|
+
const queryParamIdx = url.indexOf('?');
|
|
175
|
+
if (queryParamIdx > -1) {
|
|
176
|
+
params = {};
|
|
177
|
+
url
|
|
178
|
+
.substr(queryParamIdx + 1)
|
|
179
|
+
.split('&')
|
|
180
|
+
.forEach((pair) => {
|
|
181
|
+
const [key, value] = pair.split('=');
|
|
182
|
+
if (key && value !== undefined) {
|
|
183
|
+
params[key] = decodeURIComponent(value.replace(/\+/g, ' '));
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
const tronRequest = {
|
|
188
|
+
url,
|
|
189
|
+
method: init?.method || 'GET',
|
|
190
|
+
data: init?.body || null,
|
|
191
|
+
headers: init?.headers || {},
|
|
192
|
+
params,
|
|
193
|
+
};
|
|
194
|
+
return originalFetch
|
|
195
|
+
.call(this, input, init)
|
|
196
|
+
.then(async (response) => {
|
|
197
|
+
const contentType = response.headers.get('content-type') || '';
|
|
198
|
+
// Clone the response so we can read it
|
|
199
|
+
const clonedResponse = response.clone();
|
|
200
|
+
let body = `~~~ skipped ~~~`;
|
|
201
|
+
const useRealResponse = !ignoreContentTypes.test(contentType);
|
|
202
|
+
if (useRealResponse) {
|
|
203
|
+
try {
|
|
204
|
+
if (contentType.includes('application/json')) {
|
|
205
|
+
body = await clonedResponse.json();
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
body = await clonedResponse.text();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (e) {
|
|
212
|
+
// ignore parsing errors
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Parse response headers
|
|
216
|
+
const responseHeaders = {};
|
|
217
|
+
response.headers.forEach((value, key) => {
|
|
218
|
+
responseHeaders[key] = value;
|
|
219
|
+
});
|
|
220
|
+
const tronResponse = {
|
|
221
|
+
body,
|
|
222
|
+
status: response.status,
|
|
223
|
+
headers: responseHeaders,
|
|
224
|
+
};
|
|
225
|
+
dreaction.apiResponse(tronRequest, tronResponse, stopTimer());
|
|
226
|
+
return response;
|
|
227
|
+
});
|
|
228
|
+
};
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* Restore original functions
|
|
232
|
+
*/
|
|
233
|
+
const restoreXHR = () => {
|
|
234
|
+
if (originalXHROpen) {
|
|
235
|
+
XMLHttpRequest.prototype.open = originalXHROpen;
|
|
236
|
+
}
|
|
237
|
+
if (originalXHRSend) {
|
|
238
|
+
XMLHttpRequest.prototype.send = originalXHRSend;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const restoreFetch = () => {
|
|
242
|
+
if (originalFetch) {
|
|
243
|
+
window.fetch = originalFetch;
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
return {
|
|
247
|
+
onConnect: () => {
|
|
248
|
+
// register our interceptors
|
|
249
|
+
if (typeof XMLHttpRequest !== 'undefined') {
|
|
250
|
+
interceptXHR();
|
|
251
|
+
}
|
|
252
|
+
if (typeof window !== 'undefined' &&
|
|
253
|
+
typeof window.fetch === 'function') {
|
|
254
|
+
interceptFetch();
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
onDisconnect: () => {
|
|
258
|
+
restoreXHR();
|
|
259
|
+
restoreFetch();
|
|
260
|
+
},
|
|
261
|
+
};
|
|
262
|
+
};
|
|
263
|
+
exports.default = networking;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides a global error handler to report errors.
|
|
3
|
+
*/
|
|
4
|
+
import { DReactionCore } from 'dreaction-client-core';
|
|
5
|
+
export interface ErrorStackFrame {
|
|
6
|
+
fileName: string;
|
|
7
|
+
functionName: string;
|
|
8
|
+
lineNumber: number;
|
|
9
|
+
columnNumber?: number | null;
|
|
10
|
+
}
|
|
11
|
+
export interface TrackGlobalErrorsOptions {
|
|
12
|
+
veto?: (frame: ErrorStackFrame) => boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Track global errors and send them to DReaction logger.
|
|
16
|
+
*/
|
|
17
|
+
declare const trackGlobalErrors: (options?: TrackGlobalErrorsOptions) => (dreaction: DReactionCore) => {
|
|
18
|
+
onConnect: () => void;
|
|
19
|
+
onDisconnect: () => void;
|
|
20
|
+
features: {
|
|
21
|
+
reportError: (error: Error, stack?: ErrorStackFrame[]) => void;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export default trackGlobalErrors;
|
|
25
|
+
//# sourceMappingURL=trackGlobalErrors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trackGlobalErrors.d.ts","sourceRoot":"","sources":["../../src/plugins/trackGlobalErrors.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAGL,aAAa,EAGd,MAAM,uBAAuB,CAAC;AAE/B,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,OAAO,CAAC;CAC5C;AAuED;;GAEG;AACH,QAAA,MAAM,iBAAiB,aACV,wBAAwB,iBAAiB,aAAa;;;;6BAenC,KAAK,UAAU,eAAe,EAAE;;CA0F7D,CAAC;AAEJ,eAAe,iBAAiB,CAAC"}
|