@akc42/app-utils 3.2.1 → 3.3.1

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 CHANGED
@@ -20,12 +20,12 @@
20
20
 
21
21
  let configPromise;
22
22
 
23
- export function mockConfig(promise) {
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/log' url with
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,91 @@
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 comma separated list of topics
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 and for the client to be restarted to enable
50
- the appropriate debug topics, an alternative could be for client side function
51
- to use the `mockConfig` call to replace the promise with one which contained a
52
- different list of topics. debug checks the list of topics on every call so
53
- would dynamically pick up the changes
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
+ }
60
94
 
95
+ function initialiseDebug() {
96
+ initialised = true;
97
+ buffer = [];
98
+ performance.setResourceTimingBufferSize(150)
99
+ window.addEventListener('resourcetimingbufferfull', bufferFull)
100
+ }
61
101
 
62
- function Debug (t) {
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
+ let message = '';
109
+ for (let i = 0; i < buffer.length; i++) {
110
+ message += `(${buffer[i].topic}) ${buffer[i].message} :gap ${i < buffer.length - 1 ? buffer[i].time - buffer[i + 1].time : 0}ms\n`;
111
+ }
112
+ const blob = new Blob([JSON.stringify({
113
+ message: message
114
+ })], { type: 'application/json' });
115
+ navigator.sendBeacon(`/api/debuglog/clientpath`, blob);
116
+
117
+ buffer = []; //we will start our buffer from scratch again
118
+
119
+ }
120
+
121
+
122
+ function Debug(t) {
63
123
  if (typeof t !== 'string' || t.length === 0 || !/^[a-zA-Z]+$/.test(t)) {
64
124
  console.error('Debug requires topic which is a non zero length string of only letters', t, 'Received');
65
125
  throw new Error('Invalid Debug Topic');
66
126
  }
67
- const tl = t.toLowerCase();
68
- if (topicMap.has(tl) ) {
127
+ const tl = t.toLowerCase();
128
+ if (topicMap.has(tl)) {
69
129
  const topic = topicMap.get(tl);
70
130
  return topic.debug;
71
131
  }
@@ -74,30 +134,30 @@ function Debug (t) {
74
134
  topic: tl,
75
135
  timestamp: new Date().getTime(),
76
136
  defined: false, //has the config been defined yet
77
- enabled: false, //is this topic enabled
78
137
  debug: async function (...args) {
79
138
  //do time calc before potential delay to see if we are enabled
80
139
  const now = new Date().getTime();
81
140
  const gap = now - this.timestamp;
82
141
  this.timestamp = now;
142
+ const message = args.reduce((cum, arg) => {
143
+ return `${cum} ${arg}`.trim();
144
+ }, '');
145
+ if (initialised) performance.mark(this.topic, { detail: message }); //save our message locally regardless of if enabled
83
146
  if (!this.defined) {
84
- await config();
147
+ await config();
85
148
  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
149
  }
92
- if (this.enabled) {
93
- const message = args.reduce((cum, arg) => {
94
- return `${cum} ${arg}`.trim();
95
- }, '');
96
- console.log(`+${gap}ms`, this.topic, message);
150
+ let enabled = false;
151
+ const debugConf = sessionStorage.getItem('debug');
152
+ if (debugConf) {
153
+ const topics = debugConf.split(':');
154
+ if (topics.includes(this.topic)) enabled = true;
155
+ }
156
+ if (enabled) {
97
157
  const blob = new Blob([JSON.stringify({
98
158
  message: message,
99
159
  gap: gap
100
- })], { type: 'application/json' })
160
+ })], { type: 'application/json' });
101
161
 
102
162
  navigator.sendBeacon(`/api/debuglog/${this.topic}`, blob);
103
163
  }
@@ -108,4 +168,4 @@ function Debug (t) {
108
168
  return topicHandler.debug
109
169
  }
110
170
 
111
- export default Debug;
171
+ export { Debug as default, initialiseDebug, unloadDebug, debugDump };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akc42/app-utils",
3
- "version": "3.2.1",
3
+ "version": "3.3.1",
4
4
  "description": "General Utilities for SPAs",
5
5
  "exports": {
6
6
  ".": "./*.js"