owlservable 0.2.9 → 0.2.11
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/auto.cjs +1 -1
- package/auto.js +1 -1
- package/dashboard.html +34 -7
- package/index.cjs +14 -6
- package/index.js +14 -6
- package/package.json +1 -1
package/auto.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
require('./index.cjs').init()
|
|
1
|
+
require('./index.cjs').init({ save: true })
|
package/auto.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { init } from './index.js'
|
|
2
|
-
init()
|
|
2
|
+
init({ save: true })
|
package/dashboard.html
CHANGED
|
@@ -227,20 +227,21 @@ function detailHtml(r){
|
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
function addRow(r,prepend){
|
|
230
|
-
total++;if(!r.status||r.error)errs++;sumMs+=r.latency||0;
|
|
230
|
+
if(!r.pending){total++;if(!r.status||r.error)errs++;sumMs+=r.latency||0;}
|
|
231
231
|
if(r.tokens)totalTok+=r.tokens.total||0;
|
|
232
232
|
storeSize=Math.min(storeSize+1,500);
|
|
233
233
|
nReq.textContent=total;nErr.textContent=errs;
|
|
234
|
-
nLat.textContent=fms(Math.round(sumMs/total));
|
|
234
|
+
nLat.textContent=total?fms(Math.round(sumMs/total)):'—';
|
|
235
235
|
nTok.textContent=fn(totalTok);nStore.textContent=storeSize+'/500';
|
|
236
236
|
var method=r.method||'GET',parts=splitUrl(r.url||'');
|
|
237
|
-
var
|
|
237
|
+
var statusHtml=r.pending?'<span class="pending" title="in-flight"></span>':'<span class="badge '+sc(r.status)+'">'+esc(r.status||(r.error?'ERR':'—'))+'</span>';
|
|
238
|
+
var latHtml=r.pending?'<span class="muted">…</span>':fms(r.latency||0);
|
|
238
239
|
var tr=document.createElement('tr');tr.className='req new';tr.dataset.id=r.id;
|
|
239
240
|
tr.innerHTML=
|
|
240
241
|
'<td class="c-time muted">'+ftime(r.timestamp)+'</td>'+
|
|
241
242
|
'<td class="c-method"><span class="'+esc(method)+'">'+esc(method)+'</span></td>'+
|
|
242
|
-
'<td class="c-status"
|
|
243
|
-
'<td class="c-lat muted">'+
|
|
243
|
+
'<td class="c-status">'+statusHtml+'</td>'+
|
|
244
|
+
'<td class="c-lat muted">'+latHtml+'</td>'+
|
|
244
245
|
'<td class="c-tok">'+tokHtml(r)+'</td>'+
|
|
245
246
|
'<td class="c-url" title="'+esc(r.url||'')+'"><span class="muted">'+esc(parts.host)+'</span>'+esc(parts.path)+'</td>';
|
|
246
247
|
var dtd=document.createElement('td');dtd.colSpan=6;dtd.innerHTML=detailHtml(r);
|
|
@@ -257,9 +258,18 @@ function addRow(r,prepend){
|
|
|
257
258
|
|
|
258
259
|
function applyUpdate(id,patch){
|
|
259
260
|
var e=byId[id];if(!e)return;
|
|
261
|
+
var prevTok=(e.data.tokens&&e.data.tokens.total)||0;
|
|
262
|
+
var wasPending=e.data.pending;
|
|
260
263
|
Object.assign(e.data,patch);
|
|
264
|
+
if(wasPending&&!e.data.pending){
|
|
265
|
+
total++;if(!e.data.status||e.data.error)errs++;sumMs+=e.data.latency||0;
|
|
266
|
+
nReq.textContent=total;nErr.textContent=errs;
|
|
267
|
+
nLat.textContent=total?fms(Math.round(sumMs/total)):'—';
|
|
268
|
+
e.tr.querySelector('.c-status').innerHTML='<span class="badge '+sc(e.data.status)+'">'+esc(e.data.status||(e.data.error?'ERR':'—'))+'</span>';
|
|
269
|
+
e.tr.querySelector('.c-lat').innerHTML=fms(e.data.latency||0);
|
|
270
|
+
}
|
|
261
271
|
if(patch.tokens){
|
|
262
|
-
totalTok+=patch.tokens.total||0;
|
|
272
|
+
totalTok+=(patch.tokens.total||0)-prevTok;
|
|
263
273
|
nTok.textContent=fn(totalTok);
|
|
264
274
|
e.tr.querySelector('.c-tok').innerHTML=tokHtml(e.data);
|
|
265
275
|
}else if('metaPending' in patch&&!patch.metaPending){
|
|
@@ -307,7 +317,7 @@ function handleMsg(msg){
|
|
|
307
317
|
msg.requests.slice().reverse().forEach(function(r){addRow(r,false);});
|
|
308
318
|
renderSave(msg.save);
|
|
309
319
|
}else if(msg.type==='request'){
|
|
310
|
-
addRow(msg.record,true);
|
|
320
|
+
if(!byId[msg.record.id])addRow(msg.record,true);
|
|
311
321
|
}else if(msg.type==='update'){
|
|
312
322
|
applyUpdate(msg.id,msg.patch);
|
|
313
323
|
}else if(msg.type==='saveConfig'){
|
|
@@ -352,6 +362,23 @@ function connect(){
|
|
|
352
362
|
try{handleMsg(msg);}catch(_){}
|
|
353
363
|
});
|
|
354
364
|
}
|
|
365
|
+
var pollGen=1;
|
|
366
|
+
function poll(){
|
|
367
|
+
fetch('/api/requests').then(function(r){return r.json();}).then(function(d){
|
|
368
|
+
var reqs=d.requests||[],gen=d.generation||1;
|
|
369
|
+
if(gen!==pollGen){
|
|
370
|
+
pollGen=gen;reset();
|
|
371
|
+
reqs.slice().reverse().forEach(function(r){addRow(r,false);});
|
|
372
|
+
renderSave(d.save);return;
|
|
373
|
+
}
|
|
374
|
+
reqs.forEach(function(r){
|
|
375
|
+
if(!byId[r.id]){addRow(r,true);}
|
|
376
|
+
else{var e=byId[r.id];if((e.data.pending&&!r.pending)||(e.data.metaPending&&!r.metaPending)){applyUpdate(r.id,r);}}
|
|
377
|
+
});
|
|
378
|
+
}).catch(function(){});
|
|
379
|
+
}
|
|
380
|
+
setInterval(poll,2000);
|
|
381
|
+
setTimeout(poll,500);
|
|
355
382
|
connect();
|
|
356
383
|
})();
|
|
357
384
|
</script>
|
package/index.cjs
CHANGED
|
@@ -17,6 +17,7 @@ emitter.setMaxListeners(100)
|
|
|
17
17
|
|
|
18
18
|
const requests = []
|
|
19
19
|
let nextId = 1
|
|
20
|
+
let generation = 1
|
|
20
21
|
|
|
21
22
|
function addRequest(entry) {
|
|
22
23
|
try {
|
|
@@ -43,6 +44,7 @@ function updateRequest(id, patch) {
|
|
|
43
44
|
function getRequests() { try { return requests.slice() } catch (_) { return [] } }
|
|
44
45
|
|
|
45
46
|
function clearRequests() {
|
|
47
|
+
generation++
|
|
46
48
|
requests.splice(0)
|
|
47
49
|
if (saveState.enabled) try { fs.writeFileSync(saveState.filePath, '') } catch (_) {}
|
|
48
50
|
emitter.emit('reload', { requests: [], save: getSaveInfo() })
|
|
@@ -163,18 +165,19 @@ function patchFetch() {
|
|
|
163
165
|
reqBody = bodyFromInit(init?.body ?? null)
|
|
164
166
|
} catch (_) {}
|
|
165
167
|
|
|
168
|
+
const r = addRequest({ url, method, status: null, latency: null, reqBody, metaPending: false, pending: true })
|
|
166
169
|
const start = Date.now()
|
|
167
170
|
try {
|
|
168
171
|
const res = await orig.call(this, input, init)
|
|
169
172
|
const ct = res.headers.get('content-type') || ''
|
|
170
173
|
const isJson = ct.includes('application/json')
|
|
171
174
|
const isSse = ct.includes('text/event-stream')
|
|
172
|
-
|
|
175
|
+
updateRequest(r.id, { status: res.status, latency: Date.now() - start, pending: false, metaPending: isJson || isSse })
|
|
173
176
|
if (r && isJson) handleJsonResponse(r, () => res.clone().text())
|
|
174
177
|
if (r && isSse) handleSseResponse(r, () => res.clone().text())
|
|
175
178
|
return res
|
|
176
179
|
} catch (err) {
|
|
177
|
-
try {
|
|
180
|
+
try { updateRequest(r.id, { status: 0, latency: Date.now() - start, pending: false, error: err.message }) } catch (_) {}
|
|
178
181
|
throw err
|
|
179
182
|
}
|
|
180
183
|
}
|
|
@@ -196,6 +199,7 @@ function patchHttpModule(mod, protocol) {
|
|
|
196
199
|
} catch (_) {}
|
|
197
200
|
|
|
198
201
|
const req = orig.apply(mod, args)
|
|
202
|
+
const r = addRequest({ url, method: method.toUpperCase(), status: null, latency: null, reqBody: null, metaPending: false, pending: true })
|
|
199
203
|
const reqChunks = []; let reqSize = 0
|
|
200
204
|
const origWrite = req.write
|
|
201
205
|
req.write = function(chunk, encoding, cb) {
|
|
@@ -213,8 +217,7 @@ function patchHttpModule(mod, protocol) {
|
|
|
213
217
|
const reqBody = reqSize > 0 ? reqChunks.join('').slice(0, MAX_REQ_BODY) : null
|
|
214
218
|
const ct = res.headers['content-type'] || ''
|
|
215
219
|
const isJson = ct.includes('application/json')
|
|
216
|
-
|
|
217
|
-
const r = addRequest({ url, method: method.toUpperCase(), status: res.statusCode, latency: Date.now() - start, reqBody, metaPending: isJson })
|
|
220
|
+
updateRequest(r.id, { status: res.statusCode, latency: Date.now() - start, reqBody, pending: false, metaPending: isJson })
|
|
218
221
|
if (r && isJson) {
|
|
219
222
|
try {
|
|
220
223
|
const chunks = []; let size = 0
|
|
@@ -225,12 +228,11 @@ function patchHttpModule(mod, protocol) {
|
|
|
225
228
|
res.once('error', reject)
|
|
226
229
|
})
|
|
227
230
|
if (isJson) handleJsonResponse(r, getText)
|
|
228
|
-
if (isSse) handleSseResponse(r, getText)
|
|
229
231
|
} catch (_) { updateRequest(r.id, { metaPending: false }) }
|
|
230
232
|
}
|
|
231
233
|
})
|
|
232
234
|
req.once('error', err => {
|
|
233
|
-
try {
|
|
235
|
+
try { updateRequest(r.id, { status: 0, latency: Date.now() - start, pending: false, error: err.message }) } catch (_) {}
|
|
234
236
|
})
|
|
235
237
|
} catch (_) {}
|
|
236
238
|
|
|
@@ -383,6 +385,12 @@ function startDashboard(port) {
|
|
|
383
385
|
return
|
|
384
386
|
}
|
|
385
387
|
|
|
388
|
+
if (urlPath === '/api/requests' && req.method === 'GET') {
|
|
389
|
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'no-cache' })
|
|
390
|
+
res.end(JSON.stringify({ requests: getRequests(), save: getSaveInfo(), generation }))
|
|
391
|
+
return
|
|
392
|
+
}
|
|
393
|
+
|
|
386
394
|
if (urlPath === '/owl.png') {
|
|
387
395
|
try {
|
|
388
396
|
const data = fs.readFileSync(path.join(__dir, 'owl.png'))
|
package/index.js
CHANGED
|
@@ -17,6 +17,7 @@ emitter.setMaxListeners(100)
|
|
|
17
17
|
|
|
18
18
|
const requests = []
|
|
19
19
|
let nextId = 1
|
|
20
|
+
let generation = 1
|
|
20
21
|
|
|
21
22
|
function addRequest(entry) {
|
|
22
23
|
try {
|
|
@@ -43,6 +44,7 @@ function updateRequest(id, patch) {
|
|
|
43
44
|
function getRequests() { try { return requests.slice() } catch (_) { return [] } }
|
|
44
45
|
|
|
45
46
|
function clearRequests() {
|
|
47
|
+
generation++
|
|
46
48
|
requests.splice(0)
|
|
47
49
|
if (saveState.enabled) try { fs.writeFileSync(saveState.filePath, '') } catch (_) {}
|
|
48
50
|
emitter.emit('reload', { requests: [], save: getSaveInfo() })
|
|
@@ -163,18 +165,19 @@ function patchFetch() {
|
|
|
163
165
|
reqBody = bodyFromInit(init?.body ?? null)
|
|
164
166
|
} catch (_) {}
|
|
165
167
|
|
|
168
|
+
const r = addRequest({ url, method, status: null, latency: null, reqBody, metaPending: false, pending: true })
|
|
166
169
|
const start = Date.now()
|
|
167
170
|
try {
|
|
168
171
|
const res = await orig.call(this, input, init)
|
|
169
172
|
const ct = res.headers.get('content-type') || ''
|
|
170
173
|
const isJson = ct.includes('application/json')
|
|
171
174
|
const isSse = ct.includes('text/event-stream')
|
|
172
|
-
|
|
175
|
+
updateRequest(r.id, { status: res.status, latency: Date.now() - start, pending: false, metaPending: isJson || isSse })
|
|
173
176
|
if (r && isJson) handleJsonResponse(r, () => res.clone().text())
|
|
174
177
|
if (r && isSse) handleSseResponse(r, () => res.clone().text())
|
|
175
178
|
return res
|
|
176
179
|
} catch (err) {
|
|
177
|
-
try {
|
|
180
|
+
try { updateRequest(r.id, { status: 0, latency: Date.now() - start, pending: false, error: err.message }) } catch (_) {}
|
|
178
181
|
throw err
|
|
179
182
|
}
|
|
180
183
|
}
|
|
@@ -196,6 +199,7 @@ function patchHttpModule(mod, protocol) {
|
|
|
196
199
|
} catch (_) {}
|
|
197
200
|
|
|
198
201
|
const req = orig.apply(mod, args)
|
|
202
|
+
const r = addRequest({ url, method: method.toUpperCase(), status: null, latency: null, reqBody: null, metaPending: false, pending: true })
|
|
199
203
|
const reqChunks = []; let reqSize = 0
|
|
200
204
|
const origWrite = req.write
|
|
201
205
|
req.write = function(chunk, encoding, cb) {
|
|
@@ -213,8 +217,7 @@ function patchHttpModule(mod, protocol) {
|
|
|
213
217
|
const reqBody = reqSize > 0 ? reqChunks.join('').slice(0, MAX_REQ_BODY) : null
|
|
214
218
|
const ct = res.headers['content-type'] || ''
|
|
215
219
|
const isJson = ct.includes('application/json')
|
|
216
|
-
|
|
217
|
-
const r = addRequest({ url, method: method.toUpperCase(), status: res.statusCode, latency: Date.now() - start, reqBody, metaPending: isJson })
|
|
220
|
+
updateRequest(r.id, { status: res.statusCode, latency: Date.now() - start, reqBody, pending: false, metaPending: isJson })
|
|
218
221
|
if (r && isJson) {
|
|
219
222
|
try {
|
|
220
223
|
const chunks = []; let size = 0
|
|
@@ -225,12 +228,11 @@ function patchHttpModule(mod, protocol) {
|
|
|
225
228
|
res.once('error', reject)
|
|
226
229
|
})
|
|
227
230
|
if (isJson) handleJsonResponse(r, getText)
|
|
228
|
-
if (isSse) handleSseResponse(r, getText)
|
|
229
231
|
} catch (_) { updateRequest(r.id, { metaPending: false }) }
|
|
230
232
|
}
|
|
231
233
|
})
|
|
232
234
|
req.once('error', err => {
|
|
233
|
-
try {
|
|
235
|
+
try { updateRequest(r.id, { status: 0, latency: Date.now() - start, pending: false, error: err.message }) } catch (_) {}
|
|
234
236
|
})
|
|
235
237
|
} catch (_) {}
|
|
236
238
|
|
|
@@ -383,6 +385,12 @@ function startDashboard(port) {
|
|
|
383
385
|
return
|
|
384
386
|
}
|
|
385
387
|
|
|
388
|
+
if (urlPath === '/api/requests' && req.method === 'GET') {
|
|
389
|
+
res.writeHead(200, { 'Content-Type': 'application/json', 'Cache-Control': 'no-cache' })
|
|
390
|
+
res.end(JSON.stringify({ requests: getRequests(), save: getSaveInfo(), generation }))
|
|
391
|
+
return
|
|
392
|
+
}
|
|
393
|
+
|
|
386
394
|
if (urlPath === '/owl.png') {
|
|
387
395
|
try {
|
|
388
396
|
const data = fs.readFileSync(path.join(__dir, 'owl.png'))
|