@fougere/calls 0.9.2-alpha.0 → 0.10.0-alpha.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 +1 -1
- package/dist/ErrorGroup.d.ts +20 -0
- package/dist/ErrorGroup.d.ts.map +1 -0
- package/dist/ErrorGroup.js +2 -0
- package/dist/ErrorGroup.js.map +1 -0
- package/dist/ErrorRing.d.ts +13 -0
- package/dist/ErrorRing.d.ts.map +1 -0
- package/dist/{rings.js → ErrorRing.js} +2 -54
- package/dist/ErrorRing.js.map +1 -0
- package/dist/KeepHandler.d.ts +3 -2
- package/dist/KeepHandler.d.ts.map +1 -1
- package/dist/KeepHandler.js +1 -1
- package/dist/KeepHandler.js.map +1 -1
- package/dist/LogLine.d.ts +12 -0
- package/dist/LogLine.d.ts.map +1 -0
- package/dist/LogLine.js +2 -0
- package/dist/LogLine.js.map +1 -0
- package/dist/LogRing.d.ts +8 -0
- package/dist/LogRing.d.ts.map +1 -0
- package/dist/LogRing.js +28 -0
- package/dist/LogRing.js.map +1 -0
- package/dist/QueryLine.d.ts +11 -0
- package/dist/QueryLine.d.ts.map +1 -0
- package/dist/QueryLine.js +2 -0
- package/dist/QueryLine.js.map +1 -0
- package/dist/QueryRing.d.ts +6 -0
- package/dist/QueryRing.d.ts.map +1 -0
- package/dist/QueryRing.js +7 -0
- package/dist/QueryRing.js.map +1 -0
- package/dist/Ring.d.ts +19 -0
- package/dist/Ring.d.ts.map +1 -0
- package/dist/Ring.js +23 -0
- package/dist/Ring.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -17
- package/dist/index.js.map +1 -1
- package/dist/panel.js +2 -2
- package/dist/panel.js.map +1 -1
- package/package.json +9 -9
- package/src/ErrorGroup.ts +16 -0
- package/src/ErrorRing.ts +53 -0
- package/src/KeepHandler.ts +3 -2
- package/src/LogLine.ts +12 -0
- package/src/LogRing.ts +28 -0
- package/src/QueryLine.ts +10 -0
- package/src/QueryRing.ts +8 -0
- package/src/Ring.ts +23 -0
- package/src/index.ts +12 -17
- package/src/panel.ts +2 -2
- package/dist/rings.d.ts +0 -74
- package/dist/rings.d.ts.map +0 -1
- package/dist/rings.js.map +0 -1
- package/src/rings.ts +0 -145
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ extensions: [calls({ max: 500, panel: true })],
|
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
What it sees that a middleware cannot: a call refused **before** any handler — an unknown
|
|
12
|
-
route, an entity hosted elsewhere, a call arriving while the
|
|
12
|
+
route, an entity hosted elsewhere, a call arriving while the facade drains — and the route
|
|
13
13
|
kind of every call, so a local execution and a hop to another process read the same way.
|
|
14
14
|
Beside the calls it keeps a bounded ring of log lines, of errors, and — when
|
|
15
15
|
`@fougere/adapter-sql` is installed — of the statements each call issued.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** One kind of refusal, and how often it happened. */
|
|
2
|
+
export interface ErrorGroup {
|
|
3
|
+
seq: number;
|
|
4
|
+
key: string;
|
|
5
|
+
code: string;
|
|
6
|
+
entity?: string;
|
|
7
|
+
operation?: string;
|
|
8
|
+
message: string;
|
|
9
|
+
count: number;
|
|
10
|
+
firstAt: number;
|
|
11
|
+
lastAt: number;
|
|
12
|
+
/** Which field was refused, for a VALIDATION_FAILED — the whole point of this source. */
|
|
13
|
+
fields: {
|
|
14
|
+
path: string;
|
|
15
|
+
message: string;
|
|
16
|
+
}[];
|
|
17
|
+
/** `dispatch` when a call carried it, `log` when it happened outside any call. */
|
|
18
|
+
from: 'dispatch' | 'log';
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=ErrorGroup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorGroup.d.ts","sourceRoot":"","sources":["../src/ErrorGroup.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,kFAAkF;IAClF,IAAI,EAAE,UAAU,GAAG,KAAK,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorGroup.js","sourceRoot":"","sources":["../src/ErrorGroup.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Ring } from './Ring.js';
|
|
2
|
+
import { type DispatchEvent, type LogRecord } from '@fougere/core';
|
|
3
|
+
import type { ErrorGroup } from './ErrorGroup.js';
|
|
4
|
+
/** What was refused, from TWO sources — and that is the point. */
|
|
5
|
+
export declare class ErrorRing extends Ring<ErrorGroup> {
|
|
6
|
+
private readonly byKey;
|
|
7
|
+
/** A refusal that a call carried. `details` reaches here intact, unlike a span's code. */
|
|
8
|
+
fromDispatch(event: DispatchEvent): void;
|
|
9
|
+
/** A line written at `error` level, which is how a failure outside any call speaks. */
|
|
10
|
+
fromLog(line: LogRecord): void;
|
|
11
|
+
private group;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=ErrorRing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorRing.d.ts","sourceRoot":"","sources":["../src/ErrorRing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAsB,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,kEAAkE;AAClE,qBAAa,SAAU,SAAQ,IAAI,CAAC,UAAU,CAAC;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAEvD,0FAA0F;IAC1F,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAYvC;IAED,uFAAuF;IACvF,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAI7B;IAED,OAAO,CAAC,KAAK;CAqBd"}
|
|
@@ -1,45 +1,6 @@
|
|
|
1
|
+
import { Ring } from './Ring.js';
|
|
1
2
|
import { dotted } from '@fougere/schema';
|
|
2
3
|
import { validationErrorsOf } from '@fougere/core';
|
|
3
|
-
/** How many each ring keeps. Bounded by a NUMBER, never by a duration. */
|
|
4
|
-
const KEPT = 300;
|
|
5
|
-
/** A bounded list that counts what it drops, so a busy moment never reads as a quiet one. */
|
|
6
|
-
class Ring {
|
|
7
|
-
max;
|
|
8
|
-
held = [];
|
|
9
|
-
seq = 0;
|
|
10
|
-
lost = 0;
|
|
11
|
-
constructor(max = KEPT) {
|
|
12
|
-
this.max = max;
|
|
13
|
-
}
|
|
14
|
-
keep(make) {
|
|
15
|
-
const record = make(++this.seq);
|
|
16
|
-
this.held.push(record);
|
|
17
|
-
if (this.held.length > this.max)
|
|
18
|
-
this.lost += this.held.splice(0, this.held.length - this.max).length;
|
|
19
|
-
return record;
|
|
20
|
-
}
|
|
21
|
-
since(cursor) {
|
|
22
|
-
return { lines: this.held.filter((one) => one.seq > cursor), cursor: this.seq, dropped: this.lost };
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
/** What this process logged. */
|
|
26
|
-
export class LogRing extends Ring {
|
|
27
|
-
record(line) {
|
|
28
|
-
this.keep((seq) => ({
|
|
29
|
-
seq,
|
|
30
|
-
level: line.level,
|
|
31
|
-
name: line.name,
|
|
32
|
-
message: line.message,
|
|
33
|
-
args: line.args.map(render),
|
|
34
|
-
at: line.at,
|
|
35
|
-
}));
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
export class QueryRing extends Ring {
|
|
39
|
-
record(event) {
|
|
40
|
-
this.keep((seq) => ({ ...event, seq }));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
4
|
/** What was refused, from TWO sources — and that is the point. */
|
|
44
5
|
export class ErrorRing extends Ring {
|
|
45
6
|
byKey = new Map();
|
|
@@ -83,17 +44,4 @@ export class ErrorRing extends Ring {
|
|
|
83
44
|
this.byKey.set(key, this.keep((seq) => ({ ...one, key, seq, count: 1, firstAt: at, lastAt: at })));
|
|
84
45
|
}
|
|
85
46
|
}
|
|
86
|
-
|
|
87
|
-
function render(value) {
|
|
88
|
-
if (typeof value === 'string')
|
|
89
|
-
return value;
|
|
90
|
-
if (value instanceof Error)
|
|
91
|
-
return `${value.name}: ${value.message}`;
|
|
92
|
-
try {
|
|
93
|
-
return JSON.stringify(value) ?? String(value);
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
return String(value);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
//# sourceMappingURL=rings.js.map
|
|
47
|
+
//# sourceMappingURL=ErrorRing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ErrorRing.js","sourceRoot":"","sources":["../src/ErrorRing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAsC,MAAM,eAAe,CAAC;AAGvF,kEAAkE;AAClE,MAAM,OAAO,SAAU,SAAQ,IAAgB;IAC5B,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IAEvD,0FAA0F;IAC1F,YAAY,CAAC,KAAoB;QAC/B,MAAM,KAAK,GAAG,KAAK,CAAC,KAA2E,CAAC;QAChG,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC;QAEjD,IAAI,CAAC,KAAK,CAAC;YACT,IAAI,EAAE,OAAO,KAAK,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB;YACrE,MAAM;YACN,SAAS;YACT,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;YAC9C,MAAM,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC1G,IAAI,EAAE,UAAU;SACjB,CAAC,CAAC;IACL,CAAC;IAED,uFAAuF;IACvF,OAAO,CAAC,IAAe;QACrB,IAAI,IAAI,CAAC,KAAK,KAAK,OAAO;YAAE,OAAO;QAEnC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClF,CAAC;IAEO,KAAK,CAAC,GAAqE;QACjF,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,EAAE,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEtB,mFAAmF;QACnF,yDAAyD;QACzD,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;YAChB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;YAC3B,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;gBAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;YACpD,kFAAkF;YAClF,mFAAmF;YACnF,yDAAyD;YACzD,IAAI,CAAC,GAAG,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;YACtB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACrG,CAAC;CACF"}
|
package/dist/KeepHandler.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Fact, LogLine } from '@fougere/core';
|
|
2
|
-
import {
|
|
2
|
+
import { ErrorRing } from './ErrorRing.js';
|
|
3
|
+
import { LogRing } from './LogRing.js';
|
|
3
4
|
/**
|
|
4
5
|
* Every line this process logged, kept for the panel.
|
|
5
6
|
*
|
|
6
7
|
* A handler and not an `onLog` sink: accepting the fact IS the subscription, so the two
|
|
7
|
-
* rings are filled by the same
|
|
8
|
+
* rings are filled by the same facade every other reader goes through — with a validator,
|
|
8
9
|
* and with whatever middleware the app declared.
|
|
9
10
|
*
|
|
10
11
|
* The rings come from the container: the extension's `up` put them there, and this
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeepHandler.d.ts","sourceRoot":"","sources":["../src/KeepHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"KeepHandler.d.ts","sourceRoot":"","sources":["../src/KeepHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,OAAO,OAAO,WAAW;IAClB,OAAO,CAAC,KAAK;IAAW,OAAO,CAAC,MAAM;IAAlD,YAAoB,KAAK,EAAE,OAAO,EAAU,MAAM,EAAE,SAAS,EAAI;IAEjE,0EAA0E;IACpE,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/C;CACF"}
|
package/dist/KeepHandler.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Every line this process logged, kept for the panel.
|
|
3
3
|
*
|
|
4
4
|
* A handler and not an `onLog` sink: accepting the fact IS the subscription, so the two
|
|
5
|
-
* rings are filled by the same
|
|
5
|
+
* rings are filled by the same facade every other reader goes through — with a validator,
|
|
6
6
|
* and with whatever middleware the app declared.
|
|
7
7
|
*
|
|
8
8
|
* The rings come from the container: the extension's `up` put them there, and this
|
package/dist/KeepHandler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeepHandler.js","sourceRoot":"","sources":["../src/KeepHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"KeepHandler.js","sourceRoot":"","sources":["../src/KeepHandler.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,OAAO,OAAO,WAAW;IACV,KAAK;IAAmB,MAAM;IAAlD,YAAoB,KAAc,EAAU,MAAiB;qBAAzC,KAAK;sBAAmB,MAAM;IAAc,CAAC;IAEjE,0EAA0E;IAC1E,KAAK,CAAC,MAAM,CAAC,IAAmB;QAC9B,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;QACzE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type LogRecord } from '@fougere/core';
|
|
2
|
+
/** One line this process wrote. `args` is the developer's own choice of what to record. */
|
|
3
|
+
export interface LogLine {
|
|
4
|
+
seq: number;
|
|
5
|
+
level: LogRecord['level'];
|
|
6
|
+
name: string;
|
|
7
|
+
message: string;
|
|
8
|
+
/** Rendered here, not held: a live object would let the panel show what it later became. */
|
|
9
|
+
args: string[];
|
|
10
|
+
at: number;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=LogLine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LogLine.d.ts","sourceRoot":"","sources":["../src/LogLine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,2FAA2F;AAC3F,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;CACZ"}
|
package/dist/LogLine.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LogLine.js","sourceRoot":"","sources":["../src/LogLine.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Ring } from './Ring.js';
|
|
2
|
+
import { type LogRecord } from '@fougere/core';
|
|
3
|
+
import type { LogLine } from './LogLine.js';
|
|
4
|
+
/** What this process logged. */
|
|
5
|
+
export declare class LogRing extends Ring<LogLine> {
|
|
6
|
+
record(line: LogRecord): void;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=LogRing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LogRing.d.ts","sourceRoot":"","sources":["../src/LogRing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,gCAAgC;AAChC,qBAAa,OAAQ,SAAQ,IAAI,CAAC,OAAO,CAAC;IACxC,MAAM,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAS5B;CACF"}
|
package/dist/LogRing.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Ring } from './Ring.js';
|
|
2
|
+
/** What this process logged. */
|
|
3
|
+
export class LogRing extends Ring {
|
|
4
|
+
record(line) {
|
|
5
|
+
this.keep((seq) => ({
|
|
6
|
+
seq,
|
|
7
|
+
level: line.level,
|
|
8
|
+
name: line.name,
|
|
9
|
+
message: line.message,
|
|
10
|
+
args: line.args.map(render),
|
|
11
|
+
at: line.at,
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** An argument as one line. A live object would change under the reader; a string cannot. */
|
|
16
|
+
function render(value) {
|
|
17
|
+
if (typeof value === 'string')
|
|
18
|
+
return value;
|
|
19
|
+
if (value instanceof Error)
|
|
20
|
+
return `${value.name}: ${value.message}`;
|
|
21
|
+
try {
|
|
22
|
+
return JSON.stringify(value) ?? String(value);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return String(value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=LogRing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LogRing.js","sourceRoot":"","sources":["../src/LogRing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,gCAAgC;AAChC,MAAM,OAAO,OAAQ,SAAQ,IAAa;IACxC,MAAM,CAAC,IAAe;QACpB,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAClB,GAAG;YACH,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC;YAC3B,EAAE,EAAE,IAAI,CAAC,EAAE;SACZ,CAAC,CAAC,CAAC;IACN,CAAC;CACF;AAED,6FAA6F;AAC7F,SAAS,MAAM,CAAC,KAAc;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,YAAY,KAAK;QAAE,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;IACrE,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** One statement, as the panel shows it — never a parameter's value. */
|
|
2
|
+
export interface QueryLine {
|
|
3
|
+
seq: number;
|
|
4
|
+
storage: string;
|
|
5
|
+
sql: string;
|
|
6
|
+
parameters: number;
|
|
7
|
+
ms: number;
|
|
8
|
+
failed: boolean;
|
|
9
|
+
at: number;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=QueryLine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryLine.d.ts","sourceRoot":"","sources":["../src/QueryLine.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryLine.js","sourceRoot":"","sources":["../src/QueryLine.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryRing.d.ts","sourceRoot":"","sources":["../src/QueryRing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,qBAAa,SAAU,SAAQ,IAAI,CAAC,SAAS,CAAC;IAC5C,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,IAAI,CAE1C;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"QueryRing.js","sourceRoot":"","sources":["../src/QueryRing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,OAAO,SAAU,SAAQ,IAAe;IAC5C,MAAM,CAAC,KAA6B;QAClC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;CACF"}
|
package/dist/Ring.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** How many entries a ring keeps before the oldest falls off. */
|
|
2
|
+
export declare const KEPT = 300;
|
|
3
|
+
/** A bounded list that counts what it drops, so a busy moment never reads as a quiet one. */
|
|
4
|
+
export declare class Ring<T extends {
|
|
5
|
+
seq: number;
|
|
6
|
+
}> {
|
|
7
|
+
private readonly max;
|
|
8
|
+
protected readonly held: T[];
|
|
9
|
+
protected seq: number;
|
|
10
|
+
private lost;
|
|
11
|
+
constructor(max?: number);
|
|
12
|
+
protected keep(make: (seq: number) => T): T;
|
|
13
|
+
since(cursor: number): {
|
|
14
|
+
lines: T[];
|
|
15
|
+
cursor: number;
|
|
16
|
+
dropped: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=Ring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Ring.d.ts","sourceRoot":"","sources":["../src/Ring.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,eAAO,MAAM,IAAI,MAAM,CAAC;AAExB,6FAA6F;AAC7F,qBAAa,IAAI,CAAC,CAAC,SAAS;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE;IAK7B,OAAO,CAAC,QAAQ,CAAC,GAAG;IAJhC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAM;IAClC,SAAS,CAAC,GAAG,SAAK;IAClB,OAAO,CAAC,IAAI,CAAK;IAEjB,YAA6B,GAAG,SAAO,EAAI;IAE3C,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,CAM1C;IAED,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAErE;CACF"}
|
package/dist/Ring.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** How many entries a ring keeps before the oldest falls off. */
|
|
2
|
+
export const KEPT = 300;
|
|
3
|
+
/** A bounded list that counts what it drops, so a busy moment never reads as a quiet one. */
|
|
4
|
+
export class Ring {
|
|
5
|
+
max;
|
|
6
|
+
held = [];
|
|
7
|
+
seq = 0;
|
|
8
|
+
lost = 0;
|
|
9
|
+
constructor(max = KEPT) {
|
|
10
|
+
this.max = max;
|
|
11
|
+
}
|
|
12
|
+
keep(make) {
|
|
13
|
+
const record = make(++this.seq);
|
|
14
|
+
this.held.push(record);
|
|
15
|
+
if (this.held.length > this.max)
|
|
16
|
+
this.lost += this.held.splice(0, this.held.length - this.max).length;
|
|
17
|
+
return record;
|
|
18
|
+
}
|
|
19
|
+
since(cursor) {
|
|
20
|
+
return { lines: this.held.filter((one) => one.seq > cursor), cursor: this.seq, dropped: this.lost };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=Ring.js.map
|
package/dist/Ring.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Ring.js","sourceRoot":"","sources":["../src/Ring.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,CAAC;AAExB,6FAA6F;AAC7F,MAAM,OAAO,IAAI;IAKc,GAAG;IAJb,IAAI,GAAQ,EAAE,CAAC;IACxB,GAAG,GAAG,CAAC,CAAC;IACV,IAAI,GAAG,CAAC,CAAC;IAEjB,YAA6B,GAAG,GAAG,IAAI;mBAAV,GAAG;IAAU,CAAC;IAEjC,IAAI,CAAC,IAAwB;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG;YAAE,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;QAEtG,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,MAAc;QAClB,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IACtG,CAAC;CACF"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8D,KAAK,SAAS,EAA0B,MAAM,eAAe,CAAC;AAMnI,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE3D,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE1D,sDAAsD;AACtD,eAAO,MAAM,QAAQ,UAAU,CAAC;AAEhC,MAAM,WAAW,YAAY;IAC3B,oFAAoF;IACpF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,YAAY,CAAC;CACzC;AA+ED,2FAA2F;AAC3F,wBAAgB,KAAK,CAAC,OAAO,GAAE,YAAiB,GAAG,SAAS,CA+E3D"}
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
import { CARRIES_LINE, frond, LogLine } from '@fougere/core';
|
|
1
|
+
import { CARRIES_LINE, declaredTopologyOf, frond, LogLine } from '@fougere/core';
|
|
2
2
|
import KeepHandler from './KeepHandler.js';
|
|
3
3
|
import { CallRing } from './CallRing.js';
|
|
4
|
-
import { ErrorRing
|
|
4
|
+
import { ErrorRing } from './ErrorRing.js';
|
|
5
|
+
import { LogRing } from './LogRing.js';
|
|
6
|
+
import { QueryRing } from './QueryRing.js';
|
|
5
7
|
import { servePanel } from './panel.js';
|
|
6
8
|
/** The rpc operation this extension answers under. */
|
|
7
9
|
export const CALLS_OP = 'calls';
|
|
8
10
|
/** What this process serves, read from the app itself. */
|
|
9
11
|
function servedModel(app) {
|
|
12
|
+
// What the config SAYS. What the runtime saw is in the ring, under `route` — and the two
|
|
13
|
+
// disagree exactly when something is misconfigured, which is the whole point of showing
|
|
14
|
+
// them side by side. `rpc.topology` calls a frond remote because it ANSWERED.
|
|
15
|
+
const declared = declaredTopologyOf(app);
|
|
16
|
+
const stated = new Map(declared.fronds.map((one) => [one.frond, one]));
|
|
10
17
|
return {
|
|
11
18
|
fronds: app.fronds.filter((frond) => !frond.brought).map((frond) => ({
|
|
12
19
|
name: frond.name,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// showing them side by side. `rpc.topology` calls a frond remote because it ANSWERED.
|
|
16
|
-
declared: app.remotes[frond.name] ? 'remote' : 'local',
|
|
17
|
-
at: app.remotes[frond.name] ? hostOf(app.remotes[frond.name]) : null,
|
|
20
|
+
declared: stated.get(frond.name)?.placement ?? 'local',
|
|
21
|
+
at: stated.get(frond.name)?.at ?? null,
|
|
18
22
|
entities: frond.entities.map((entity) => entity.name),
|
|
19
23
|
operations: frond.handlers.flatMap((handler) => {
|
|
20
24
|
const ops = app.operationsFor(handler.address);
|
|
@@ -43,16 +47,6 @@ function servedModel(app) {
|
|
|
43
47
|
})),
|
|
44
48
|
};
|
|
45
49
|
}
|
|
46
|
-
/** Host and port only — a declared address may carry credentials, and this answer leaves. */
|
|
47
|
-
function hostOf(address) {
|
|
48
|
-
try {
|
|
49
|
-
const url = new URL(address);
|
|
50
|
-
return `${url.protocol}//${url.host}`;
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
return address;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
50
|
function nameOf(schema) {
|
|
57
51
|
const named = schema;
|
|
58
52
|
if (!named)
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAoD,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/panel.js
CHANGED
|
@@ -41,7 +41,7 @@ export function servePanel(ring, options = {}) {
|
|
|
41
41
|
request.on('close', () => readers.delete(response));
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
|
-
// One
|
|
44
|
+
// One facade per ring, each taking a cursor: a reader asks for what is above its own,
|
|
45
45
|
// which is the whole protocol — no subscription to hold, nothing to replay.
|
|
46
46
|
for (const [name, read] of [['logs', options.logs], ['errors', options.errors], ['queries', options.queries]]) {
|
|
47
47
|
if (path !== `/${name}.json`)
|
|
@@ -71,7 +71,7 @@ export function servePanel(ring, options = {}) {
|
|
|
71
71
|
});
|
|
72
72
|
return new Promise((ready, refuse) => {
|
|
73
73
|
server.on('error', refuse);
|
|
74
|
-
// Loopback only. This
|
|
74
|
+
// Loopback only. This facade has no validator — `serve()` refuses to start beyond loopback
|
|
75
75
|
// without `verify`, and this one would not know how to refuse at all.
|
|
76
76
|
server.listen(options.port ?? 0, '127.0.0.1', () => {
|
|
77
77
|
const port = server.address().port;
|
package/dist/panel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel.js","sourceRoot":"","sources":["../src/panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAC;AAGtD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAqBjC,+DAA+D;AAC/D,MAAM,OAAO,GAAG,IAAI,CAAC;AAErB,oDAAoD;AACpD,MAAM,UAAU,UAAU,CAAC,IAAc,EAAE,OAAO,GAAiB,EAAE;IACnE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuD,CAAC;IAC/E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IAEzB,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,IAAa,EAAQ,EAAE;QAClD,MAAM,MAAM,GAAG,UAAU,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;QACpE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC;gBAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAAC,CAAC;QACjE,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAkB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QAC/B,IAAI,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAChH,CAAC,EAAE,OAAO,CAAC,CAAC;IACZ,IAAI,CAAC,KAAK,EAAE,CAAC;IAEb,MAAM,MAAM,GAAW,YAAY,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;QACxD,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE;gBACtB,cAAc,EAAE,mBAAmB;gBACnC,eAAe,EAAE,UAAU;gBAC3B,UAAU,EAAE,YAAY;aACzB,CAAC,CAAC;YACH,+EAA+E;YAC/E,wDAAwD;YACxD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9B,QAAQ,CAAC,KAAK,CAAC,uBAAuB,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;YACpH,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACtB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YACpD,OAAO;QACT,CAAC;QAED,
|
|
1
|
+
{"version":3,"file":"panel.js","sourceRoot":"","sources":["../src/panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAC;AAGtD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAqBjC,+DAA+D;AAC/D,MAAM,OAAO,GAAG,IAAI,CAAC;AAErB,oDAAoD;AACpD,MAAM,UAAU,UAAU,CAAC,IAAc,EAAE,OAAO,GAAiB,EAAE;IACnE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,SAAS,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuD,CAAC;IAC/E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IAEzB,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,IAAa,EAAQ,EAAE;QAClD,MAAM,MAAM,GAAG,UAAU,KAAK,WAAW,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;QACpE,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC;gBAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC;gBAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAAC,CAAC;QACjE,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,MAAkB,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE;QAC5B,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QAC/B,IAAI,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAChH,CAAC,EAAE,OAAO,CAAC,CAAC;IACZ,IAAI,CAAC,KAAK,EAAE,CAAC;IAEb,MAAM,MAAM,GAAW,YAAY,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;QACxD,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAEhD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE;gBACtB,cAAc,EAAE,mBAAmB;gBACnC,eAAe,EAAE,UAAU;gBAC3B,UAAU,EAAE,YAAY;aACzB,CAAC,CAAC;YACH,+EAA+E;YAC/E,wDAAwD;YACxD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC9B,QAAQ,CAAC,KAAK,CAAC,uBAAuB,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;YACpH,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACtB,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YACpD,OAAO;QACT,CAAC;QAED,sFAAsF;QACtF,4EAA4E;QAC5E,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,CAAU,EAAE,CAAC;YACvH,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO;gBAAE,SAAS;YACvC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,EAAE,cAAc,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YACjG,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAChE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACjH,OAAO;QACT,CAAC;QAED,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YAC3B,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAChE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QAED,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YAC3B,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;YAChE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5C,OAAO;QACT,CAAC;QAED,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YAC3C,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;YACxE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACnB,OAAO;QACT,CAAC;QAED,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC,CAAC;QAC1D,QAAQ,CAAC,GAAG,CAAC,qGAAqG,CAAC,CAAC;IACtH,CAAC,CAAC,CAAC;IAEH,OAAO,IAAI,OAAO,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QACnC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3B,2FAA2F;QAC3F,sEAAsE;QACtE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YACjD,MAAM,IAAI,GAAI,MAAM,CAAC,OAAO,EAAuB,CAAC,IAAI,CAAC;YACzD,OAAO,CAAC,QAAQ,EAAE,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC;YAE/C,KAAK,CAAC,KAAK,IAAI,EAAE;gBACf,aAAa,CAAC,IAAI,CAAC,CAAC;gBACpB,YAAY,EAAE,CAAC;gBACf,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;oBAAC,IAAI,CAAC;wBAAC,MAAM,CAAC,GAAG,EAAE,CAAC;oBAAC,CAAC;oBAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;gBAAC,CAAC;gBAClF,OAAO,CAAC,KAAK,EAAE,CAAC;gBAChB,MAAM,IAAI,OAAO,CAAO,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YACpE,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fougere/calls",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0-alpha.0",
|
|
4
4
|
"description": "Optional call log for Fougere: a bounded ring of every dispatch, served as an rpc operation. Read it with `fougere devtools`.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fougere",
|
|
@@ -30,17 +30,17 @@
|
|
|
30
30
|
"src"
|
|
31
31
|
],
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@fougere/core": "^0.
|
|
34
|
-
"@fougere/adapter-sql": "^0.
|
|
33
|
+
"@fougere/core": "^0.10.0-alpha.0",
|
|
34
|
+
"@fougere/adapter-sql": "^0.10.0-alpha.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"vitest": "^4.1.0",
|
|
38
|
-
"@fougere/
|
|
39
|
-
"@fougere/
|
|
40
|
-
"@fougere/
|
|
41
|
-
"@fougere/
|
|
42
|
-
"@fougere/
|
|
43
|
-
"@fougere/
|
|
38
|
+
"@fougere/container": "0.10.0-alpha.0",
|
|
39
|
+
"@fougere/adapter-sql": "0.10.0-alpha.0",
|
|
40
|
+
"@fougere/compiler": "0.10.0-alpha.0",
|
|
41
|
+
"@fougere/transport-http": "0.10.0-alpha.0",
|
|
42
|
+
"@fougere/schema": "0.10.0-alpha.0",
|
|
43
|
+
"@fougere/core": "0.10.0-alpha.0"
|
|
44
44
|
},
|
|
45
45
|
"publishConfig": {
|
|
46
46
|
"access": "public"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** One kind of refusal, and how often it happened. */
|
|
2
|
+
export interface ErrorGroup {
|
|
3
|
+
seq: number;
|
|
4
|
+
key: string;
|
|
5
|
+
code: string;
|
|
6
|
+
entity?: string;
|
|
7
|
+
operation?: string;
|
|
8
|
+
message: string;
|
|
9
|
+
count: number;
|
|
10
|
+
firstAt: number;
|
|
11
|
+
lastAt: number;
|
|
12
|
+
/** Which field was refused, for a VALIDATION_FAILED — the whole point of this source. */
|
|
13
|
+
fields: { path: string; message: string }[];
|
|
14
|
+
/** `dispatch` when a call carried it, `log` when it happened outside any call. */
|
|
15
|
+
from: 'dispatch' | 'log';
|
|
16
|
+
}
|
package/src/ErrorRing.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Ring } from './Ring.js';
|
|
2
|
+
import { dotted } from '@fougere/schema';
|
|
3
|
+
import { validationErrorsOf, type DispatchEvent, type LogRecord } from '@fougere/core';
|
|
4
|
+
import type { ErrorGroup } from './ErrorGroup.js';
|
|
5
|
+
|
|
6
|
+
/** What was refused, from TWO sources — and that is the point. */
|
|
7
|
+
export class ErrorRing extends Ring<ErrorGroup> {
|
|
8
|
+
private readonly byKey = new Map<string, ErrorGroup>();
|
|
9
|
+
|
|
10
|
+
/** A refusal that a call carried. `details` reaches here intact, unlike a span's code. */
|
|
11
|
+
fromDispatch(event: DispatchEvent): void {
|
|
12
|
+
const error = event.error as { code?: string; message?: string; details?: unknown } | undefined;
|
|
13
|
+
const { entity, operation } = event.call.address;
|
|
14
|
+
|
|
15
|
+
this.group({
|
|
16
|
+
code: typeof error?.code === 'string' ? error.code : 'INTERNAL_ERROR',
|
|
17
|
+
entity,
|
|
18
|
+
operation,
|
|
19
|
+
message: error?.message ?? String(event.error),
|
|
20
|
+
fields: (validationErrorsOf(error) ?? []).map((one) => ({ path: dotted(one.path), message: one.message })),
|
|
21
|
+
from: 'dispatch',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** A line written at `error` level, which is how a failure outside any call speaks. */
|
|
26
|
+
fromLog(line: LogRecord): void {
|
|
27
|
+
if (line.level !== 'error') return;
|
|
28
|
+
|
|
29
|
+
this.group({ code: line.name, message: line.message, fields: [], from: 'log' });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private group(one: Omit<ErrorGroup, 'seq' | 'key' | 'count' | 'firstAt' | 'lastAt'>): void {
|
|
33
|
+
const key = [one.from, one.code, one.entity ?? '', one.operation ?? ''].join(' ');
|
|
34
|
+
const seen = this.byKey.get(key);
|
|
35
|
+
const at = Date.now();
|
|
36
|
+
|
|
37
|
+
// Grouped, because a refusal seen forty times is one line with a count — not forty
|
|
38
|
+
// lines that push everything else out of a bounded ring.
|
|
39
|
+
if (seen) {
|
|
40
|
+
seen.count += 1;
|
|
41
|
+
seen.lastAt = at;
|
|
42
|
+
seen.message = one.message;
|
|
43
|
+
if (one.fields.length > 0) seen.fields = one.fields;
|
|
44
|
+
// Re-numbered so a reader that already saw this group is handed the higher count.
|
|
45
|
+
// Without it a refusal seen forty times reports one, forever: the group is mutated
|
|
46
|
+
// in place, and a cursor asks only for what is above it.
|
|
47
|
+
seen.seq = ++this.seq;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.byKey.set(key, this.keep((seq) => ({ ...one, key, seq, count: 1, firstAt: at, lastAt: at })));
|
|
52
|
+
}
|
|
53
|
+
}
|
package/src/KeepHandler.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Fact, LogLine } from '@fougere/core';
|
|
2
|
-
import {
|
|
2
|
+
import { ErrorRing } from './ErrorRing.js';
|
|
3
|
+
import { LogRing } from './LogRing.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Every line this process logged, kept for the panel.
|
|
6
7
|
*
|
|
7
8
|
* A handler and not an `onLog` sink: accepting the fact IS the subscription, so the two
|
|
8
|
-
* rings are filled by the same
|
|
9
|
+
* rings are filled by the same facade every other reader goes through — with a validator,
|
|
9
10
|
* and with whatever middleware the app declared.
|
|
10
11
|
*
|
|
11
12
|
* The rings come from the container: the extension's `up` put them there, and this
|
package/src/LogLine.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type LogRecord } from '@fougere/core';
|
|
2
|
+
|
|
3
|
+
/** One line this process wrote. `args` is the developer's own choice of what to record. */
|
|
4
|
+
export interface LogLine {
|
|
5
|
+
seq: number;
|
|
6
|
+
level: LogRecord['level'];
|
|
7
|
+
name: string;
|
|
8
|
+
message: string;
|
|
9
|
+
/** Rendered here, not held: a live object would let the panel show what it later became. */
|
|
10
|
+
args: string[];
|
|
11
|
+
at: number;
|
|
12
|
+
}
|
package/src/LogRing.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Ring } from './Ring.js';
|
|
2
|
+
import { type LogRecord } from '@fougere/core';
|
|
3
|
+
import type { LogLine } from './LogLine.js';
|
|
4
|
+
|
|
5
|
+
/** What this process logged. */
|
|
6
|
+
export class LogRing extends Ring<LogLine> {
|
|
7
|
+
record(line: LogRecord): void {
|
|
8
|
+
this.keep((seq) => ({
|
|
9
|
+
seq,
|
|
10
|
+
level: line.level,
|
|
11
|
+
name: line.name,
|
|
12
|
+
message: line.message,
|
|
13
|
+
args: line.args.map(render),
|
|
14
|
+
at: line.at,
|
|
15
|
+
}));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** An argument as one line. A live object would change under the reader; a string cannot. */
|
|
20
|
+
function render(value: unknown): string {
|
|
21
|
+
if (typeof value === 'string') return value;
|
|
22
|
+
if (value instanceof Error) return `${value.name}: ${value.message}`;
|
|
23
|
+
try {
|
|
24
|
+
return JSON.stringify(value) ?? String(value);
|
|
25
|
+
} catch {
|
|
26
|
+
return String(value);
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/QueryLine.ts
ADDED
package/src/QueryRing.ts
ADDED
package/src/Ring.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** How many entries a ring keeps before the oldest falls off. */
|
|
2
|
+
export const KEPT = 300;
|
|
3
|
+
|
|
4
|
+
/** A bounded list that counts what it drops, so a busy moment never reads as a quiet one. */
|
|
5
|
+
export class Ring<T extends { seq: number }> {
|
|
6
|
+
protected readonly held: T[] = [];
|
|
7
|
+
protected seq = 0;
|
|
8
|
+
private lost = 0;
|
|
9
|
+
|
|
10
|
+
constructor(private readonly max = KEPT) {}
|
|
11
|
+
|
|
12
|
+
protected keep(make: (seq: number) => T): T {
|
|
13
|
+
const record = make(++this.seq);
|
|
14
|
+
this.held.push(record);
|
|
15
|
+
if (this.held.length > this.max) this.lost += this.held.splice(0, this.held.length - this.max).length;
|
|
16
|
+
|
|
17
|
+
return record;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
since(cursor: number): { lines: T[]; cursor: number; dropped: number } {
|
|
21
|
+
return { lines: this.held.filter((one) => one.seq > cursor), cursor: this.seq, dropped: this.lost };
|
|
22
|
+
}
|
|
23
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { CARRIES_LINE, frond, LogLine, type App, type Extension, type InvocationContext } from '@fougere/core';
|
|
1
|
+
import { CARRIES_LINE, declaredTopologyOf, frond, LogLine, type App, type Extension, type InvocationContext } from '@fougere/core';
|
|
2
2
|
import KeepHandler from './KeepHandler.js';
|
|
3
3
|
import { CallRing } from './CallRing.js';
|
|
4
|
-
import { ErrorRing
|
|
4
|
+
import { ErrorRing } from './ErrorRing.js';
|
|
5
|
+
import { LogRing } from './LogRing.js';
|
|
6
|
+
import { QueryRing } from './QueryRing.js';
|
|
5
7
|
import { servePanel, type PanelOptions } from './panel.js';
|
|
6
8
|
|
|
7
9
|
export type { CallPage, CallRecord } from '@fougere/core';
|
|
@@ -18,14 +20,17 @@ export interface CallsOptions {
|
|
|
18
20
|
|
|
19
21
|
/** What this process serves, read from the app itself. */
|
|
20
22
|
function servedModel(app: App): unknown {
|
|
23
|
+
// What the config SAYS. What the runtime saw is in the ring, under `route` — and the two
|
|
24
|
+
// disagree exactly when something is misconfigured, which is the whole point of showing
|
|
25
|
+
// them side by side. `rpc.topology` calls a frond remote because it ANSWERED.
|
|
26
|
+
const declared = declaredTopologyOf(app);
|
|
27
|
+
const stated = new Map(declared.fronds.map((one) => [one.frond, one]));
|
|
28
|
+
|
|
21
29
|
return {
|
|
22
30
|
fronds: app.fronds.filter((frond) => !frond.brought).map((frond) => ({
|
|
23
31
|
name: frond.name,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// showing them side by side. `rpc.topology` calls a frond remote because it ANSWERED.
|
|
27
|
-
declared: app.remotes[frond.name] ? 'remote' as const : 'local' as const,
|
|
28
|
-
at: app.remotes[frond.name] ? hostOf(app.remotes[frond.name]!) : null,
|
|
32
|
+
declared: stated.get(frond.name)?.placement ?? 'local',
|
|
33
|
+
at: stated.get(frond.name)?.at ?? null,
|
|
29
34
|
entities: frond.entities.map((entity) => entity.name),
|
|
30
35
|
operations: frond.handlers.flatMap((handler) => {
|
|
31
36
|
const ops = app.operationsFor(handler.address);
|
|
@@ -55,16 +60,6 @@ function servedModel(app: App): unknown {
|
|
|
55
60
|
};
|
|
56
61
|
}
|
|
57
62
|
|
|
58
|
-
/** Host and port only — a declared address may carry credentials, and this answer leaves. */
|
|
59
|
-
function hostOf(address: string): string {
|
|
60
|
-
try {
|
|
61
|
-
const url = new URL(address);
|
|
62
|
-
return `${url.protocol}//${url.host}`;
|
|
63
|
-
} catch {
|
|
64
|
-
return address;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
63
|
function nameOf(schema: unknown): string | null {
|
|
69
64
|
const named = schema as { getName?: () => string; name?: string } | undefined;
|
|
70
65
|
if (!named) return null;
|
package/src/panel.ts
CHANGED
|
@@ -63,7 +63,7 @@ export function servePanel(ring: CallRing, options: PanelOptions = {}): Promise<
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
// One
|
|
66
|
+
// One facade per ring, each taking a cursor: a reader asks for what is above its own,
|
|
67
67
|
// which is the whole protocol — no subscription to hold, nothing to replay.
|
|
68
68
|
for (const [name, read] of [['logs', options.logs], ['errors', options.errors], ['queries', options.queries]] as const) {
|
|
69
69
|
if (path !== `/${name}.json`) continue;
|
|
@@ -97,7 +97,7 @@ export function servePanel(ring: CallRing, options: PanelOptions = {}): Promise<
|
|
|
97
97
|
|
|
98
98
|
return new Promise((ready, refuse) => {
|
|
99
99
|
server.on('error', refuse);
|
|
100
|
-
// Loopback only. This
|
|
100
|
+
// Loopback only. This facade has no validator — `serve()` refuses to start beyond loopback
|
|
101
101
|
// without `verify`, and this one would not know how to refuse at all.
|
|
102
102
|
server.listen(options.port ?? 0, '127.0.0.1', () => {
|
|
103
103
|
const port = (server.address() as { port: number }).port;
|
package/dist/rings.d.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { type DispatchEvent, type LogRecord } from '@fougere/core';
|
|
2
|
-
/** One line this process wrote. `args` is the developer's own choice of what to record. */
|
|
3
|
-
export interface LogLine {
|
|
4
|
-
seq: number;
|
|
5
|
-
level: LogRecord['level'];
|
|
6
|
-
name: string;
|
|
7
|
-
message: string;
|
|
8
|
-
/** Rendered here, not held: a live object would let the panel show what it later became. */
|
|
9
|
-
args: string[];
|
|
10
|
-
at: number;
|
|
11
|
-
}
|
|
12
|
-
/** One statement, as the panel shows it — never a parameter's value. */
|
|
13
|
-
export interface QueryLine {
|
|
14
|
-
seq: number;
|
|
15
|
-
storage: string;
|
|
16
|
-
sql: string;
|
|
17
|
-
parameters: number;
|
|
18
|
-
ms: number;
|
|
19
|
-
failed: boolean;
|
|
20
|
-
at: number;
|
|
21
|
-
}
|
|
22
|
-
/** One kind of refusal, and how often it happened. */
|
|
23
|
-
export interface ErrorGroup {
|
|
24
|
-
seq: number;
|
|
25
|
-
key: string;
|
|
26
|
-
code: string;
|
|
27
|
-
entity?: string;
|
|
28
|
-
operation?: string;
|
|
29
|
-
message: string;
|
|
30
|
-
count: number;
|
|
31
|
-
firstAt: number;
|
|
32
|
-
lastAt: number;
|
|
33
|
-
/** Which field was refused, for a VALIDATION_FAILED — the whole point of this source. */
|
|
34
|
-
fields: {
|
|
35
|
-
path: string;
|
|
36
|
-
message: string;
|
|
37
|
-
}[];
|
|
38
|
-
/** `dispatch` when a call carried it, `log` when it happened outside any call. */
|
|
39
|
-
from: 'dispatch' | 'log';
|
|
40
|
-
}
|
|
41
|
-
/** A bounded list that counts what it drops, so a busy moment never reads as a quiet one. */
|
|
42
|
-
declare class Ring<T extends {
|
|
43
|
-
seq: number;
|
|
44
|
-
}> {
|
|
45
|
-
private readonly max;
|
|
46
|
-
protected readonly held: T[];
|
|
47
|
-
protected seq: number;
|
|
48
|
-
private lost;
|
|
49
|
-
constructor(max?: number);
|
|
50
|
-
protected keep(make: (seq: number) => T): T;
|
|
51
|
-
since(cursor: number): {
|
|
52
|
-
lines: T[];
|
|
53
|
-
cursor: number;
|
|
54
|
-
dropped: number;
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
/** What this process logged. */
|
|
58
|
-
export declare class LogRing extends Ring<LogLine> {
|
|
59
|
-
record(line: LogRecord): void;
|
|
60
|
-
}
|
|
61
|
-
export declare class QueryRing extends Ring<QueryLine> {
|
|
62
|
-
record(event: Omit<QueryLine, 'seq'>): void;
|
|
63
|
-
}
|
|
64
|
-
/** What was refused, from TWO sources — and that is the point. */
|
|
65
|
-
export declare class ErrorRing extends Ring<ErrorGroup> {
|
|
66
|
-
private readonly byKey;
|
|
67
|
-
/** A refusal that a call carried. `details` reaches here intact, unlike a span's code. */
|
|
68
|
-
fromDispatch(event: DispatchEvent): void;
|
|
69
|
-
/** A line written at `error` level, which is how a failure outside any call speaks. */
|
|
70
|
-
fromLog(line: LogRecord): void;
|
|
71
|
-
private group;
|
|
72
|
-
}
|
|
73
|
-
export {};
|
|
74
|
-
//# sourceMappingURL=rings.d.ts.map
|
package/dist/rings.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rings.d.ts","sourceRoot":"","sources":["../src/rings.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAKvF,2FAA2F;AAC3F,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,OAAO,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,sDAAsD;AACtD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,yFAAyF;IACzF,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC5C,kFAAkF;IAClF,IAAI,EAAE,UAAU,GAAG,KAAK,CAAC;CAC1B;AAED,6FAA6F;AAC7F,cAAM,IAAI,CAAC,CAAC,SAAS;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE;IAKtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAJhC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,CAAM;IAClC,SAAS,CAAC,GAAG,SAAK;IAClB,OAAO,CAAC,IAAI,CAAK;IAEjB,YAA6B,GAAG,SAAO,EAAI;IAE3C,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,CAAC,CAM1C;IAED,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAErE;CACF;AAED,gCAAgC;AAChC,qBAAa,OAAQ,SAAQ,IAAI,CAAC,OAAO,CAAC;IACxC,MAAM,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAS5B;CACF;AAED,qBAAa,SAAU,SAAQ,IAAI,CAAC,SAAS,CAAC;IAC5C,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,IAAI,CAE1C;CACF;AAED,kEAAkE;AAClE,qBAAa,SAAU,SAAQ,IAAI,CAAC,UAAU,CAAC;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IAEvD,0FAA0F;IAC1F,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAYvC;IAED,uFAAuF;IACvF,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,CAI7B;IAED,OAAO,CAAC,KAAK;CAqBd"}
|
package/dist/rings.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rings.js","sourceRoot":"","sources":["../src/rings.ts"],"names":[],"mappings":"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"}
|
package/src/rings.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { dotted } from '@fougere/schema';
|
|
2
|
-
import { validationErrorsOf, type DispatchEvent, type LogRecord } from '@fougere/core';
|
|
3
|
-
|
|
4
|
-
/** How many each ring keeps. Bounded by a NUMBER, never by a duration. */
|
|
5
|
-
const KEPT = 300;
|
|
6
|
-
|
|
7
|
-
/** One line this process wrote. `args` is the developer's own choice of what to record. */
|
|
8
|
-
export interface LogLine {
|
|
9
|
-
seq: number;
|
|
10
|
-
level: LogRecord['level'];
|
|
11
|
-
name: string;
|
|
12
|
-
message: string;
|
|
13
|
-
/** Rendered here, not held: a live object would let the panel show what it later became. */
|
|
14
|
-
args: string[];
|
|
15
|
-
at: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/** One statement, as the panel shows it — never a parameter's value. */
|
|
19
|
-
export interface QueryLine {
|
|
20
|
-
seq: number;
|
|
21
|
-
storage: string;
|
|
22
|
-
sql: string;
|
|
23
|
-
parameters: number;
|
|
24
|
-
ms: number;
|
|
25
|
-
failed: boolean;
|
|
26
|
-
at: number;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** One kind of refusal, and how often it happened. */
|
|
30
|
-
export interface ErrorGroup {
|
|
31
|
-
seq: number;
|
|
32
|
-
key: string;
|
|
33
|
-
code: string;
|
|
34
|
-
entity?: string;
|
|
35
|
-
operation?: string;
|
|
36
|
-
message: string;
|
|
37
|
-
count: number;
|
|
38
|
-
firstAt: number;
|
|
39
|
-
lastAt: number;
|
|
40
|
-
/** Which field was refused, for a VALIDATION_FAILED — the whole point of this source. */
|
|
41
|
-
fields: { path: string; message: string }[];
|
|
42
|
-
/** `dispatch` when a call carried it, `log` when it happened outside any call. */
|
|
43
|
-
from: 'dispatch' | 'log';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** A bounded list that counts what it drops, so a busy moment never reads as a quiet one. */
|
|
47
|
-
class Ring<T extends { seq: number }> {
|
|
48
|
-
protected readonly held: T[] = [];
|
|
49
|
-
protected seq = 0;
|
|
50
|
-
private lost = 0;
|
|
51
|
-
|
|
52
|
-
constructor(private readonly max = KEPT) {}
|
|
53
|
-
|
|
54
|
-
protected keep(make: (seq: number) => T): T {
|
|
55
|
-
const record = make(++this.seq);
|
|
56
|
-
this.held.push(record);
|
|
57
|
-
if (this.held.length > this.max) this.lost += this.held.splice(0, this.held.length - this.max).length;
|
|
58
|
-
|
|
59
|
-
return record;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
since(cursor: number): { lines: T[]; cursor: number; dropped: number } {
|
|
63
|
-
return { lines: this.held.filter((one) => one.seq > cursor), cursor: this.seq, dropped: this.lost };
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** What this process logged. */
|
|
68
|
-
export class LogRing extends Ring<LogLine> {
|
|
69
|
-
record(line: LogRecord): void {
|
|
70
|
-
this.keep((seq) => ({
|
|
71
|
-
seq,
|
|
72
|
-
level: line.level,
|
|
73
|
-
name: line.name,
|
|
74
|
-
message: line.message,
|
|
75
|
-
args: line.args.map(render),
|
|
76
|
-
at: line.at,
|
|
77
|
-
}));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export class QueryRing extends Ring<QueryLine> {
|
|
82
|
-
record(event: Omit<QueryLine, 'seq'>): void {
|
|
83
|
-
this.keep((seq) => ({ ...event, seq }));
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/** What was refused, from TWO sources — and that is the point. */
|
|
88
|
-
export class ErrorRing extends Ring<ErrorGroup> {
|
|
89
|
-
private readonly byKey = new Map<string, ErrorGroup>();
|
|
90
|
-
|
|
91
|
-
/** A refusal that a call carried. `details` reaches here intact, unlike a span's code. */
|
|
92
|
-
fromDispatch(event: DispatchEvent): void {
|
|
93
|
-
const error = event.error as { code?: string; message?: string; details?: unknown } | undefined;
|
|
94
|
-
const { entity, operation } = event.call.address;
|
|
95
|
-
|
|
96
|
-
this.group({
|
|
97
|
-
code: typeof error?.code === 'string' ? error.code : 'INTERNAL_ERROR',
|
|
98
|
-
entity,
|
|
99
|
-
operation,
|
|
100
|
-
message: error?.message ?? String(event.error),
|
|
101
|
-
fields: (validationErrorsOf(error) ?? []).map((one) => ({ path: dotted(one.path), message: one.message })),
|
|
102
|
-
from: 'dispatch',
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** A line written at `error` level, which is how a failure outside any call speaks. */
|
|
107
|
-
fromLog(line: LogRecord): void {
|
|
108
|
-
if (line.level !== 'error') return;
|
|
109
|
-
|
|
110
|
-
this.group({ code: line.name, message: line.message, fields: [], from: 'log' });
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private group(one: Omit<ErrorGroup, 'seq' | 'key' | 'count' | 'firstAt' | 'lastAt'>): void {
|
|
114
|
-
const key = [one.from, one.code, one.entity ?? '', one.operation ?? ''].join(' ');
|
|
115
|
-
const seen = this.byKey.get(key);
|
|
116
|
-
const at = Date.now();
|
|
117
|
-
|
|
118
|
-
// Grouped, because a refusal seen forty times is one line with a count — not forty
|
|
119
|
-
// lines that push everything else out of a bounded ring.
|
|
120
|
-
if (seen) {
|
|
121
|
-
seen.count += 1;
|
|
122
|
-
seen.lastAt = at;
|
|
123
|
-
seen.message = one.message;
|
|
124
|
-
if (one.fields.length > 0) seen.fields = one.fields;
|
|
125
|
-
// Re-numbered so a reader that already saw this group is handed the higher count.
|
|
126
|
-
// Without it a refusal seen forty times reports one, forever: the group is mutated
|
|
127
|
-
// in place, and a cursor asks only for what is above it.
|
|
128
|
-
seen.seq = ++this.seq;
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
this.byKey.set(key, this.keep((seq) => ({ ...one, key, seq, count: 1, firstAt: at, lastAt: at })));
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/** An argument as one line. A live object would change under the reader; a string cannot. */
|
|
137
|
-
function render(value: unknown): string {
|
|
138
|
-
if (typeof value === 'string') return value;
|
|
139
|
-
if (value instanceof Error) return `${value.name}: ${value.message}`;
|
|
140
|
-
try {
|
|
141
|
-
return JSON.stringify(value) ?? String(value);
|
|
142
|
-
} catch {
|
|
143
|
-
return String(value);
|
|
144
|
-
}
|
|
145
|
-
}
|