@akc42/app-utils 3.2.0 → 3.3.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/config-promise.js +3 -3
- package/debug.js +83 -25
- package/package.json +1 -1
- package/post-api.js +5 -3
package/config-promise.js
CHANGED
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
|
|
21
21
|
let configPromise;
|
|
22
22
|
|
|
23
|
-
export function
|
|
24
|
-
configPromise = promise;
|
|
23
|
+
export function setConfig(promise) {
|
|
24
|
+
configPromise = promise; //set to undefined to allow config call to request from server again.
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
async function config() {
|
|
28
|
-
if (configPromise === undefined) {
|
|
28
|
+
if (typeof configPromise === 'undefined') {
|
|
29
29
|
let resolved = false;
|
|
30
30
|
let resolver;
|
|
31
31
|
configPromise = new Promise(accept => resolver = accept);
|
package/debug.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
/*
|
|
22
22
|
The purpose of this module is to provide a debugable capability which can be
|
|
23
23
|
dynamically switched on and off browser by setting a key in the config
|
|
24
|
-
returned by the server. It will post request to '/api/
|
|
24
|
+
returned by the server. It will post request to '/api/debuglog' url with
|
|
25
25
|
application/json body part containing message, topic and gap, where message is
|
|
26
26
|
the concatenation of the debug parameters separated by space, topic is the
|
|
27
27
|
topic of this debug message and gap is the number of milliseconds since the
|
|
@@ -41,31 +41,89 @@
|
|
|
41
41
|
|
|
42
42
|
debug(..messages) //messages will be concatenated by space
|
|
43
43
|
|
|
44
|
-
the debug function will only log the message if config.debug (see
|
|
45
|
-
config-promise) is set to a string which is a
|
|
44
|
+
the debug function will only log the message on the server if config.debug (see
|
|
45
|
+
config-promise) is set to a string which is a colon separated list of topics
|
|
46
46
|
and that list has the topic for this debug call in it.
|
|
47
47
|
|
|
48
48
|
NOTE: It is normally expected for the server to provide a mechanism to update
|
|
49
|
-
the config before it is returned
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
the config before it is returned, However an alternative approach would be to
|
|
50
|
+
specifically overwrite sessionStorage 'debug' item with a new list of topics when you want
|
|
51
|
+
debug to switch on and off dynamically.
|
|
52
|
+
|
|
53
|
+
regardless of whether the message is logged on the server, it is also added to the performance.mark buffer
|
|
54
|
+
so that it can be sent to the server on a crash.
|
|
55
|
+
|
|
56
|
+
Although Debug is the default export this module also provides the following named exports
|
|
57
|
+
|
|
58
|
+
initialiseDebug - this function is used to manage tracing of debug messages regardless of whether the topic is set
|
|
59
|
+
It also adds an event handler to handle resource buffer full events. NOTE if the buffer fills up priority is given
|
|
60
|
+
|
|
61
|
+
unloadDebug - this function tidies up and reverses the initialiseDebug
|
|
62
|
+
|
|
63
|
+
debugDump - perform a dump to the server (and and a clearing out of the buffered info) of the debug calls made to date
|
|
54
64
|
|
|
55
65
|
*/
|
|
56
66
|
import config from './config-promise.js';
|
|
57
67
|
|
|
68
|
+
const BUFFER_SIZE = 50;
|
|
69
|
+
const KEY_TOPIC = 'key'; //topic name which will get kept from a full resource buffer when we empty it.
|
|
70
|
+
let buffer = []; //buffer of up to 50 topic/message pairs to allow us to hold some if resource buffer becomes full;
|
|
71
|
+
|
|
58
72
|
const topicMap = new Map();
|
|
59
73
|
|
|
74
|
+
let initialised = false;
|
|
75
|
+
|
|
76
|
+
function bufferFull() {
|
|
77
|
+
const entries = performance.getEntriesByType('mark');
|
|
78
|
+
performance.clearMarks();
|
|
79
|
+
if (entries.length > BUFFER_SIZE) {
|
|
80
|
+
let i = 0;
|
|
81
|
+
buffer = entries.filter((entry) => {
|
|
82
|
+
if (entry.name !== KEY_TOPIC) i++; //don't count critical topics in our
|
|
83
|
+
return i <= BUFFER_SIZE || entry.name === KEY_TOPIC;
|
|
84
|
+
}).map(entry => ({ topic: entry.name, message: entry.detail, time: Math.round(entry.startTime) }));
|
|
85
|
+
} else {
|
|
86
|
+
const len = buffer.length;
|
|
87
|
+
if ((len + entries.length) > BUFFER_SIZE) {
|
|
88
|
+
buffer.splice(0, len + entries.length - BUFFER_SIZE); //get rid of the head entries that would cause overflow
|
|
89
|
+
}
|
|
90
|
+
buffer = buffer.concat(entries.map(entry => ({ topic: entry.name, message: entry.detail, time: Math.round(entry.startTime) })))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function initialiseDebug() {
|
|
96
|
+
initialised = true;
|
|
97
|
+
buffer = [];
|
|
98
|
+
performance.setResourceTimingBufferSize(150)
|
|
99
|
+
window.addEventListener('resourcetimingbufferfull', bufferFull)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function unloadDebug() {
|
|
103
|
+
window.removeEventListener('resourcetimingbufferfull', bufferFull);
|
|
104
|
+
}
|
|
105
|
+
function debugDump() {
|
|
106
|
+
bufferFull(); //this clears out the marks and gives us a buffer to now send to
|
|
107
|
+
buffer.reverse();
|
|
108
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
109
|
+
const blob = new Blob([JSON.stringify({
|
|
110
|
+
message: buffer[i].message,
|
|
111
|
+
gap: i < buffer.length - 1 ? buffer[i].time - buffer[i + 1].time : 0
|
|
112
|
+
})], { type: 'application/json' });
|
|
113
|
+
navigator.sendBeacon(`/api/debuglog/${buffer[i].topic}`, blob);
|
|
114
|
+
}
|
|
115
|
+
buffer = []; //we will start our buffer from scratch again
|
|
116
|
+
|
|
117
|
+
}
|
|
60
118
|
|
|
61
119
|
|
|
62
|
-
function Debug
|
|
120
|
+
function Debug(t) {
|
|
63
121
|
if (typeof t !== 'string' || t.length === 0 || !/^[a-zA-Z]+$/.test(t)) {
|
|
64
122
|
console.error('Debug requires topic which is a non zero length string of only letters', t, 'Received');
|
|
65
123
|
throw new Error('Invalid Debug Topic');
|
|
66
124
|
}
|
|
67
|
-
const tl = t.toLowerCase();
|
|
68
|
-
if (topicMap.has(tl)
|
|
125
|
+
const tl = t.toLowerCase();
|
|
126
|
+
if (topicMap.has(tl)) {
|
|
69
127
|
const topic = topicMap.get(tl);
|
|
70
128
|
return topic.debug;
|
|
71
129
|
}
|
|
@@ -74,30 +132,30 @@ function Debug (t) {
|
|
|
74
132
|
topic: tl,
|
|
75
133
|
timestamp: new Date().getTime(),
|
|
76
134
|
defined: false, //has the config been defined yet
|
|
77
|
-
enabled: false, //is this topic enabled
|
|
78
135
|
debug: async function (...args) {
|
|
79
136
|
//do time calc before potential delay to see if we are enabled
|
|
80
137
|
const now = new Date().getTime();
|
|
81
138
|
const gap = now - this.timestamp;
|
|
82
139
|
this.timestamp = now;
|
|
140
|
+
const message = args.reduce((cum, arg) => {
|
|
141
|
+
return `${cum} ${arg}`.trim();
|
|
142
|
+
}, '');
|
|
143
|
+
if (initialised) performance.mark(this.topic, { detail: message }); //save our message locally regardless of if enabled
|
|
83
144
|
if (!this.defined) {
|
|
84
|
-
await config();
|
|
145
|
+
await config();
|
|
85
146
|
this.defined = true;
|
|
86
|
-
const debugConf = sessionStorage.getItem('debug');
|
|
87
|
-
if (debugConf) {
|
|
88
|
-
const topics = debugConf.split(':');
|
|
89
|
-
if (topics.includes(this.topic)) this.enabled = true;
|
|
90
|
-
}
|
|
91
147
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
148
|
+
let enabled = false;
|
|
149
|
+
const debugConf = sessionStorage.getItem('debug');
|
|
150
|
+
if (debugConf) {
|
|
151
|
+
const topics = debugConf.split(':');
|
|
152
|
+
if (topics.includes(this.topic)) enabled = true;
|
|
153
|
+
}
|
|
154
|
+
if (enabled) {
|
|
97
155
|
const blob = new Blob([JSON.stringify({
|
|
98
156
|
message: message,
|
|
99
157
|
gap: gap
|
|
100
|
-
})], { type: 'application/json' })
|
|
158
|
+
})], { type: 'application/json' });
|
|
101
159
|
|
|
102
160
|
navigator.sendBeacon(`/api/debuglog/${this.topic}`, blob);
|
|
103
161
|
}
|
|
@@ -108,4 +166,4 @@ function Debug (t) {
|
|
|
108
166
|
return topicHandler.debug
|
|
109
167
|
}
|
|
110
168
|
|
|
111
|
-
export default
|
|
169
|
+
export { Debug as default, initialiseDebug, unloadDebug, debugDump };
|
package/package.json
CHANGED
package/post-api.js
CHANGED
|
@@ -47,8 +47,10 @@ export default async function api(url, params, blob, signal) {
|
|
|
47
47
|
return {};
|
|
48
48
|
}
|
|
49
49
|
} catch (err) {
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
if (!options.signal || !options.signal.aborted) {
|
|
51
|
+
if (err.type === 'api-error') throw err; //just throw whatever error we had
|
|
52
|
+
//we failed to parse the json - the actual code should be in the text near the end;
|
|
53
|
+
throw new CustomEvent('api-error', { composed: true, bubbles: true, detail: parseInt((text?? '---502---').slice(-6, -3), 10) });
|
|
54
|
+
}
|
|
53
55
|
}
|
|
54
56
|
}
|