@creezio/observability 0.22.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 +328 -0
- package/dist/.creezio-src-hash.json +4 -0
- package/dist/api-endpoints/http-routes.d.ts +11 -0
- package/dist/api-endpoints/http-routes.d.ts.map +1 -0
- package/dist/api-endpoints/http-routes.js +11 -0
- package/dist/api-endpoints/http-routes.js.map +1 -0
- package/dist/api-endpoints/index.d.ts +4 -0
- package/dist/api-endpoints/index.d.ts.map +1 -0
- package/dist/api-endpoints/index.js +3 -0
- package/dist/api-endpoints/index.js.map +1 -0
- package/dist/api-endpoints/registry.d.ts +66 -0
- package/dist/api-endpoints/registry.d.ts.map +1 -0
- package/dist/api-endpoints/registry.js +102 -0
- package/dist/api-endpoints/registry.js.map +1 -0
- package/dist/api-mount.d.ts +7 -0
- package/dist/api-mount.d.ts.map +1 -0
- package/dist/api-mount.js +114 -0
- package/dist/api-mount.js.map +1 -0
- package/dist/helpers.d.ts +23 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +36 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-store.d.ts +3 -0
- package/dist/memory-store.d.ts.map +1 -0
- package/dist/memory-store.js +113 -0
- package/dist/memory-store.js.map +1 -0
- package/dist/ops/emit.d.ts +8 -0
- package/dist/ops/emit.d.ts.map +1 -0
- package/dist/ops/emit.js +15 -0
- package/dist/ops/emit.js.map +1 -0
- package/dist/ops/fleet-activity.d.ts +50 -0
- package/dist/ops/fleet-activity.d.ts.map +1 -0
- package/dist/ops/fleet-activity.js +123 -0
- package/dist/ops/fleet-activity.js.map +1 -0
- package/dist/ops/fleet-agent.d.ts +102 -0
- package/dist/ops/fleet-agent.d.ts.map +1 -0
- package/dist/ops/fleet-agent.js +352 -0
- package/dist/ops/fleet-agent.js.map +1 -0
- package/dist/ops/fleet-samples.d.ts +33 -0
- package/dist/ops/fleet-samples.d.ts.map +1 -0
- package/dist/ops/fleet-samples.js +223 -0
- package/dist/ops/fleet-samples.js.map +1 -0
- package/dist/ops/journal.d.ts +56 -0
- package/dist/ops/journal.d.ts.map +1 -0
- package/dist/ops/journal.js +307 -0
- package/dist/ops/journal.js.map +1 -0
- package/dist/ops/rules.d.ts +16 -0
- package/dist/ops/rules.d.ts.map +1 -0
- package/dist/ops/rules.js +98 -0
- package/dist/ops/rules.js.map +1 -0
- package/dist/ops/types.d.ts +69 -0
- package/dist/ops/types.d.ts.map +1 -0
- package/dist/ops/types.js +119 -0
- package/dist/ops/types.js.map +1 -0
- package/dist/request-logs/config.d.ts +19 -0
- package/dist/request-logs/config.d.ts.map +1 -0
- package/dist/request-logs/config.js +36 -0
- package/dist/request-logs/config.js.map +1 -0
- package/dist/request-logs/http-routes.d.ts +8 -0
- package/dist/request-logs/http-routes.d.ts.map +1 -0
- package/dist/request-logs/http-routes.js +29 -0
- package/dist/request-logs/http-routes.js.map +1 -0
- package/dist/request-logs/index.d.ts +6 -0
- package/dist/request-logs/index.d.ts.map +1 -0
- package/dist/request-logs/index.js +5 -0
- package/dist/request-logs/index.js.map +1 -0
- package/dist/request-logs/middleware.d.ts +11 -0
- package/dist/request-logs/middleware.d.ts.map +1 -0
- package/dist/request-logs/middleware.js +198 -0
- package/dist/request-logs/middleware.js.map +1 -0
- package/dist/request-logs/request-logs.d.ts +60 -0
- package/dist/request-logs/request-logs.d.ts.map +1 -0
- package/dist/request-logs/request-logs.js +260 -0
- package/dist/request-logs/request-logs.js.map +1 -0
- package/dist/schema.d.ts +3 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +21 -0
- package/dist/schema.js.map +1 -0
- package/dist/sqlite-driver.d.ts +16 -0
- package/dist/sqlite-driver.d.ts.map +1 -0
- package/dist/sqlite-driver.js +15 -0
- package/dist/sqlite-driver.js.map +1 -0
- package/dist/sqlite-store.d.ts +12 -0
- package/dist/sqlite-store.d.ts.map +1 -0
- package/dist/sqlite-store.js +176 -0
- package/dist/sqlite-store.js.map +1 -0
- package/dist/types.d.ts +67 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/usage/adapters.d.ts +31 -0
- package/dist/usage/adapters.d.ts.map +1 -0
- package/dist/usage/adapters.js +37 -0
- package/dist/usage/adapters.js.map +1 -0
- package/dist/usage/http-routes.d.ts +23 -0
- package/dist/usage/http-routes.d.ts.map +1 -0
- package/dist/usage/http-routes.js +150 -0
- package/dist/usage/http-routes.js.map +1 -0
- package/dist/usage/index.d.ts +11 -0
- package/dist/usage/index.d.ts.map +1 -0
- package/dist/usage/index.js +7 -0
- package/dist/usage/index.js.map +1 -0
- package/dist/usage/ui-brand.d.ts +23 -0
- package/dist/usage/ui-brand.d.ts.map +1 -0
- package/dist/usage/ui-brand.js +18 -0
- package/dist/usage/ui-brand.js.map +1 -0
- package/dist/usage/usage-analytics-productivity.d.ts +73 -0
- package/dist/usage/usage-analytics-productivity.d.ts.map +1 -0
- package/dist/usage/usage-analytics-productivity.js +317 -0
- package/dist/usage/usage-analytics-productivity.js.map +1 -0
- package/dist/usage/usage-analytics-shared.d.ts +5 -0
- package/dist/usage/usage-analytics-shared.d.ts.map +1 -0
- package/dist/usage/usage-analytics-shared.js +20 -0
- package/dist/usage/usage-analytics-shared.js.map +1 -0
- package/dist/usage/usage-analytics.d.ts +127 -0
- package/dist/usage/usage-analytics.d.ts.map +1 -0
- package/dist/usage/usage-analytics.js +338 -0
- package/dist/usage/usage-analytics.js.map +1 -0
- package/dist-cjs/api-endpoints/http-routes.js +14 -0
- package/dist-cjs/api-endpoints/http-routes.js.map +1 -0
- package/dist-cjs/api-endpoints/index.js +10 -0
- package/dist-cjs/api-endpoints/index.js.map +1 -0
- package/dist-cjs/api-endpoints/registry.js +107 -0
- package/dist-cjs/api-endpoints/registry.js.map +1 -0
- package/dist-cjs/api-mount.js +117 -0
- package/dist-cjs/api-mount.js.map +1 -0
- package/dist-cjs/helpers.js +41 -0
- package/dist-cjs/helpers.js.map +1 -0
- package/dist-cjs/index.js +118 -0
- package/dist-cjs/index.js.map +1 -0
- package/dist-cjs/memory-store.js +119 -0
- package/dist-cjs/memory-store.js.map +1 -0
- package/dist-cjs/ops/emit.js +18 -0
- package/dist-cjs/ops/emit.js.map +1 -0
- package/dist-cjs/ops/fleet-activity.js +131 -0
- package/dist-cjs/ops/fleet-activity.js.map +1 -0
- package/dist-cjs/ops/fleet-agent.js +358 -0
- package/dist-cjs/ops/fleet-agent.js.map +1 -0
- package/dist-cjs/ops/fleet-samples.js +229 -0
- package/dist-cjs/ops/fleet-samples.js.map +1 -0
- package/dist-cjs/ops/journal.js +326 -0
- package/dist-cjs/ops/journal.js.map +1 -0
- package/dist-cjs/ops/rules.js +102 -0
- package/dist-cjs/ops/rules.js.map +1 -0
- package/dist-cjs/ops/types.js +126 -0
- package/dist-cjs/ops/types.js.map +1 -0
- package/dist-cjs/package.json +3 -0
- package/dist-cjs/request-logs/config.js +42 -0
- package/dist-cjs/request-logs/config.js.map +1 -0
- package/dist-cjs/request-logs/http-routes.js +32 -0
- package/dist-cjs/request-logs/http-routes.js.map +1 -0
- package/dist-cjs/request-logs/index.js +27 -0
- package/dist-cjs/request-logs/index.js.map +1 -0
- package/dist-cjs/request-logs/middleware.js +203 -0
- package/dist-cjs/request-logs/middleware.js.map +1 -0
- package/dist-cjs/request-logs/request-logs.js +277 -0
- package/dist-cjs/request-logs/request-logs.js.map +1 -0
- package/dist-cjs/schema.js +24 -0
- package/dist-cjs/schema.js.map +1 -0
- package/dist-cjs/sqlite-driver.js +18 -0
- package/dist-cjs/sqlite-driver.js.map +1 -0
- package/dist-cjs/sqlite-store.js +182 -0
- package/dist-cjs/sqlite-store.js.map +1 -0
- package/dist-cjs/types.js +12 -0
- package/dist-cjs/types.js.map +1 -0
- package/dist-cjs/usage/adapters.js +47 -0
- package/dist-cjs/usage/adapters.js.map +1 -0
- package/dist-cjs/usage/http-routes.js +154 -0
- package/dist-cjs/usage/http-routes.js.map +1 -0
- package/dist-cjs/usage/index.js +34 -0
- package/dist-cjs/usage/index.js.map +1 -0
- package/dist-cjs/usage/ui-brand.js +23 -0
- package/dist-cjs/usage/ui-brand.js.map +1 -0
- package/dist-cjs/usage/usage-analytics-productivity.js +321 -0
- package/dist-cjs/usage/usage-analytics-productivity.js.map +1 -0
- package/dist-cjs/usage/usage-analytics-shared.js +23 -0
- package/dist-cjs/usage/usage-analytics-shared.js.map +1 -0
- package/dist-cjs/usage/usage-analytics.js +353 -0
- package/dist-cjs/usage/usage-analytics.js.map +1 -0
- package/fleet-collector/AGENTS.md +7 -0
- package/fleet-collector/README.md +83 -0
- package/fleet-collector/configure-fleet-npm.sh +108 -0
- package/fleet-collector/env.mjs +174 -0
- package/fleet-collector/ops-api.mjs +455 -0
- package/fleet-collector/public/admin.html +696 -0
- package/fleet-collector/public/index.html +941 -0
- package/fleet-collector/server.mjs +564 -0
- package/fleet-collector/test-fleet-collector.mjs +413 -0
- package/fleet-collector/test-server-admin.mjs +475 -0
- package/package.json +109 -0
- package/scripts/test-api-endpoints-registry.mjs +60 -0
- package/ui/analytics-client.tsx +834 -0
- package/ui/analytics-productivity-panel.tsx +513 -0
- package/ui/api-endpoints-client.tsx +228 -0
- package/ui/index.ts +39 -0
- package/ui/primitives/badge.tsx +37 -0
- package/ui/primitives/button.tsx +44 -0
- package/ui/primitives/card.tsx +44 -0
- package/ui/primitives/cn.ts +6 -0
- package/ui/primitives/input.tsx +19 -0
- package/ui/primitives/tabs.tsx +51 -0
- package/ui/request-logs-client.tsx +327 -0
- package/ui/session-usage-analytics-provider.tsx +28 -0
- package/ui/usage-analytics-client.ts +479 -0
- package/ui/usage-analytics-provider.tsx +84 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boîte noire — moteur d'anomalies générique.
|
|
3
|
+
* Extrait de TempoFlow ops-rules.ts (R4).
|
|
4
|
+
*/
|
|
5
|
+
import { currentBootSummary, readPreviousBootSummaries, track, } from "./journal.js";
|
|
6
|
+
/**
|
|
7
|
+
* Règle 1 — décision négative répétée : si la MÊME décision négative est
|
|
8
|
+
* prise à N boots consécutifs, quelque chose ne s'auto-répare pas.
|
|
9
|
+
*/
|
|
10
|
+
const NEGATIVE_OUTCOMES = {
|
|
11
|
+
"meili.ready": ["full-reindex", "skip-no-meili"],
|
|
12
|
+
"meili.start": ["unavailable"],
|
|
13
|
+
"tunnel.connect": ["error"],
|
|
14
|
+
};
|
|
15
|
+
const REPEAT_BOOTS = 2;
|
|
16
|
+
/** Règle 2 — durée anormale par kind (ms). */
|
|
17
|
+
const DURATION_THRESHOLDS_MS = {
|
|
18
|
+
"boot.done": 8 * 60_000,
|
|
19
|
+
"index.run": 10 * 60_000,
|
|
20
|
+
"migrations.done": 3 * 60_000,
|
|
21
|
+
"catalog.ensure": 30 * 60_000,
|
|
22
|
+
};
|
|
23
|
+
/** Règle 3 — erreurs récurrentes dans un même boot. */
|
|
24
|
+
const ERROR_COUNT_THRESHOLD = 10;
|
|
25
|
+
function isNegative(kind, outcome) {
|
|
26
|
+
if (!outcome)
|
|
27
|
+
return false;
|
|
28
|
+
return (NEGATIVE_OUTCOMES[kind] || []).includes(outcome);
|
|
29
|
+
}
|
|
30
|
+
/** Pure — testable sans I/O. */
|
|
31
|
+
export function evaluateRulesPure(current, previous) {
|
|
32
|
+
const findings = [];
|
|
33
|
+
for (const [kind, d] of Object.entries(current.decisions || {})) {
|
|
34
|
+
if (!isNegative(kind, d.outcome))
|
|
35
|
+
continue;
|
|
36
|
+
let consecutive = 1;
|
|
37
|
+
for (const prev of previous) {
|
|
38
|
+
const pd = prev.decisions?.[kind];
|
|
39
|
+
if (pd && isNegative(kind, pd.outcome))
|
|
40
|
+
consecutive++;
|
|
41
|
+
else
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
if (consecutive >= REPEAT_BOOTS) {
|
|
45
|
+
findings.push({
|
|
46
|
+
rule: "repeated-negative-decision",
|
|
47
|
+
kind,
|
|
48
|
+
detail: `${kind} outcome=${d.outcome} sur ${consecutive} boots consécutifs (reason=${d.reason || "?"})`,
|
|
49
|
+
ctx: {
|
|
50
|
+
outcome: d.outcome,
|
|
51
|
+
reason: d.reason,
|
|
52
|
+
consecutiveBoots: consecutive,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
for (const [kind, threshold] of Object.entries(DURATION_THRESHOLDS_MS)) {
|
|
58
|
+
const observed = current.durations?.[kind];
|
|
59
|
+
if (observed != null && observed > threshold) {
|
|
60
|
+
findings.push({
|
|
61
|
+
rule: "duration-over-threshold",
|
|
62
|
+
kind,
|
|
63
|
+
detail: `${kind} a duré ${Math.round(observed / 1000)}s (seuil ${Math.round(threshold / 1000)}s)`,
|
|
64
|
+
ctx: { durationMs: observed, thresholdMs: threshold },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const errorCount = (current.counts?.error || 0) + (current.counts?.crash || 0);
|
|
69
|
+
if (errorCount >= ERROR_COUNT_THRESHOLD) {
|
|
70
|
+
findings.push({
|
|
71
|
+
rule: "recurring-errors",
|
|
72
|
+
kind: "boot.errors",
|
|
73
|
+
detail: `${errorCount} erreurs/crashes pendant le boot`,
|
|
74
|
+
ctx: { errorCount },
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return findings;
|
|
78
|
+
}
|
|
79
|
+
/** À appeler en fin de boot (après persistBootSummary). Jamais de throw. */
|
|
80
|
+
export function evaluateBootRules() {
|
|
81
|
+
try {
|
|
82
|
+
const findings = evaluateRulesPure(currentBootSummary(), readPreviousBootSummaries(REPEAT_BOOTS + 2));
|
|
83
|
+
for (const f of findings) {
|
|
84
|
+
track({
|
|
85
|
+
level: "anomaly",
|
|
86
|
+
kind: `anomaly.${f.rule}`,
|
|
87
|
+
outcome: f.kind,
|
|
88
|
+
reason: f.detail,
|
|
89
|
+
ctx: f.ctx,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
return findings;
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return [];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.js","sourceRoot":"","sources":["../../src/ops/rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boîte noire desktop — types + helpers PURS (aucun import Electron).
|
|
3
|
+
* Contrat JSONL ops (R4 / P29) — préfixe d'émission historique `TF2EVENT`
|
|
4
|
+
* conservé (wire sous-process Electron ×3). Lecture = dual-read via
|
|
5
|
+
* `OPS_EVENT_PREFIXES` ; ne pas retirer `TF2EVENT` sans cutover marques.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TF2EVENT_PREFIX = "TF2EVENT ";
|
|
8
|
+
/** Alias générique — même valeur que `TF2EVENT_PREFIX` (émission). */
|
|
9
|
+
export declare const OPS_EVENT_PREFIX = "TF2EVENT ";
|
|
10
|
+
/**
|
|
11
|
+
* Préfixes stdout acceptés en lecture (M7p / P29) :
|
|
12
|
+
* - émission SoT = `TF2EVENT`
|
|
13
|
+
* - `CertivanEVENT` = dual-read legacy marques (ne pas casser)
|
|
14
|
+
*/
|
|
15
|
+
export declare const OPS_EVENT_PREFIXES: readonly ["TF2EVENT ", "CertivanEVENT "];
|
|
16
|
+
export type OpsLevel = "decision" | "event" | "anomaly" | "error" | "crash";
|
|
17
|
+
export declare const OPS_LEVELS: readonly OpsLevel[];
|
|
18
|
+
/** Événement tel qu'émis par le code appelant. */
|
|
19
|
+
export type OpsEventInput = {
|
|
20
|
+
level: OpsLevel;
|
|
21
|
+
/** Taxonomie stable `domaine.action` : meili.ready, boot.done, updater.check… */
|
|
22
|
+
kind: string;
|
|
23
|
+
/** Process émetteur — défaut "main" côté journal. */
|
|
24
|
+
source?: string;
|
|
25
|
+
/** Branche choisie : skip, full-reindex, present, downloaded, ok, error… */
|
|
26
|
+
outcome?: string;
|
|
27
|
+
/** POURQUOI : fingerprint-absent, timeout, http-503… */
|
|
28
|
+
reason?: string;
|
|
29
|
+
durationMs?: number;
|
|
30
|
+
/** Contexte libre, redacté et plafonné à MAX_CTX_BYTES. */
|
|
31
|
+
ctx?: Record<string, unknown>;
|
|
32
|
+
};
|
|
33
|
+
/** Événement complet, tel que persisté dans le JSONL. */
|
|
34
|
+
export type OpsEvent = OpsEventInput & {
|
|
35
|
+
ts: string;
|
|
36
|
+
bootId: string;
|
|
37
|
+
seq: number;
|
|
38
|
+
source: string;
|
|
39
|
+
};
|
|
40
|
+
/** Taille max du ctx sérialisé (au-delà : tronqué avec marqueur). */
|
|
41
|
+
export declare const MAX_CTX_BYTES = 4096;
|
|
42
|
+
/** Redaction récursive : clés sensibles masquées, motifs secrets dans les strings. */
|
|
43
|
+
export declare function redactOpsCtx(value: unknown, depth?: number): unknown;
|
|
44
|
+
/** Valide + normalise un input (renvoie null si inutilisable). */
|
|
45
|
+
export declare function sanitizeOpsEventInput(raw: unknown): OpsEventInput | null;
|
|
46
|
+
/** Sérialise en plafonnant le ctx (jamais de throw). */
|
|
47
|
+
export declare function serializeOpsEvent(evt: OpsEvent): string;
|
|
48
|
+
/**
|
|
49
|
+
* Parse une ligne stdout d'un sous-process.
|
|
50
|
+
* Renvoie l'input si la ligne est un TF2EVENT valide, sinon null.
|
|
51
|
+
*/
|
|
52
|
+
export declare function parseOpsLine(line: string): OpsEventInput | null;
|
|
53
|
+
/** Résumé d'un boot (ops/index.json + heartbeat flotte). */
|
|
54
|
+
export type OpsBootSummary = {
|
|
55
|
+
bootId: string;
|
|
56
|
+
startedAt: string;
|
|
57
|
+
endedAt?: string;
|
|
58
|
+
appVersion?: string;
|
|
59
|
+
durationMs?: number;
|
|
60
|
+
counts: Partial<Record<OpsLevel, number>>;
|
|
61
|
+
/** Décisions du boot : kind → { outcome, reason }. */
|
|
62
|
+
decisions: Record<string, {
|
|
63
|
+
outcome?: string;
|
|
64
|
+
reason?: string;
|
|
65
|
+
}>;
|
|
66
|
+
/** Durée max observée par kind (événements portant durationMs). */
|
|
67
|
+
durations: Record<string, number>;
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ops/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,eAAe,cAAc,CAAC;AAC3C,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,cAAkB,CAAC;AAChD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,0CAGrB,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAE5E,eAAO,MAAM,UAAU,EAAE,SAAS,QAAQ,EAMzC,CAAC;AAEF,kDAAkD;AAClD,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,QAAQ,CAAC;IAChB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAEF,yDAAyD;AACzD,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,aAAa,OAAO,CAAC;AAOlC,sFAAsF;AACtF,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAI,GAAG,OAAO,CAmB/D;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,GAAG,IAAI,CAsBxE;AAED,wDAAwD;AACxD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,GAAG,MAAM,CAkBvD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAW/D;AAED,4DAA4D;AAC5D,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjE,mEAAmE;IACnE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Boîte noire desktop — types + helpers PURS (aucun import Electron).
|
|
3
|
+
* Contrat JSONL ops (R4 / P29) — préfixe d'émission historique `TF2EVENT`
|
|
4
|
+
* conservé (wire sous-process Electron ×3). Lecture = dual-read via
|
|
5
|
+
* `OPS_EVENT_PREFIXES` ; ne pas retirer `TF2EVENT` sans cutover marques.
|
|
6
|
+
*/
|
|
7
|
+
export const TF2EVENT_PREFIX = "TF2EVENT ";
|
|
8
|
+
/** Alias générique — même valeur que `TF2EVENT_PREFIX` (émission). */
|
|
9
|
+
export const OPS_EVENT_PREFIX = TF2EVENT_PREFIX;
|
|
10
|
+
/**
|
|
11
|
+
* Préfixes stdout acceptés en lecture (M7p / P29) :
|
|
12
|
+
* - émission SoT = `TF2EVENT`
|
|
13
|
+
* - `CertivanEVENT` = dual-read legacy marques (ne pas casser)
|
|
14
|
+
*/
|
|
15
|
+
export const OPS_EVENT_PREFIXES = [
|
|
16
|
+
TF2EVENT_PREFIX,
|
|
17
|
+
"CertivanEVENT ",
|
|
18
|
+
];
|
|
19
|
+
export const OPS_LEVELS = [
|
|
20
|
+
"decision",
|
|
21
|
+
"event",
|
|
22
|
+
"anomaly",
|
|
23
|
+
"error",
|
|
24
|
+
"crash",
|
|
25
|
+
];
|
|
26
|
+
/** Taille max du ctx sérialisé (au-delà : tronqué avec marqueur). */
|
|
27
|
+
export const MAX_CTX_BYTES = 4096;
|
|
28
|
+
const SECRET_KEY_RE = /token|secret|password|passwd|api[-_]?key|jwt|auth|bearer|cookie|master[-_]?key/i;
|
|
29
|
+
const SECRET_VALUE_RE = /(sk-[A-Za-z0-9_-]{10,}|tf2_live_[A-Za-z0-9_-]+|eyJ[A-Za-z0-9_-]{20,}|Bearer\s+[A-Za-z0-9._-]{10,})/g;
|
|
30
|
+
/** Redaction récursive : clés sensibles masquées, motifs secrets dans les strings. */
|
|
31
|
+
export function redactOpsCtx(value, depth = 0) {
|
|
32
|
+
if (depth > 6)
|
|
33
|
+
return "[depth]";
|
|
34
|
+
if (typeof value === "string") {
|
|
35
|
+
return value.replace(SECRET_VALUE_RE, "[redacted]").slice(0, 800);
|
|
36
|
+
}
|
|
37
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null) {
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
if (Array.isArray(value)) {
|
|
41
|
+
return value.slice(0, 50).map((v) => redactOpsCtx(v, depth + 1));
|
|
42
|
+
}
|
|
43
|
+
if (typeof value === "object" && value !== undefined) {
|
|
44
|
+
const out = {};
|
|
45
|
+
for (const [k, v] of Object.entries(value)) {
|
|
46
|
+
out[k] = SECRET_KEY_RE.test(k) ? "[redacted]" : redactOpsCtx(v, depth + 1);
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
return value === undefined ? undefined : String(value);
|
|
51
|
+
}
|
|
52
|
+
/** Valide + normalise un input (renvoie null si inutilisable). */
|
|
53
|
+
export function sanitizeOpsEventInput(raw) {
|
|
54
|
+
if (!raw || typeof raw !== "object")
|
|
55
|
+
return null;
|
|
56
|
+
const o = raw;
|
|
57
|
+
const level = OPS_LEVELS.includes(o.level)
|
|
58
|
+
? o.level
|
|
59
|
+
: null;
|
|
60
|
+
const kind = typeof o.kind === "string" && /^[a-z0-9_-]+\.[a-z0-9._-]+$/i.test(o.kind)
|
|
61
|
+
? o.kind.slice(0, 80)
|
|
62
|
+
: null;
|
|
63
|
+
if (!level || !kind)
|
|
64
|
+
return null;
|
|
65
|
+
const evt = { level, kind };
|
|
66
|
+
if (typeof o.source === "string")
|
|
67
|
+
evt.source = o.source.slice(0, 40);
|
|
68
|
+
if (typeof o.outcome === "string")
|
|
69
|
+
evt.outcome = o.outcome.slice(0, 120);
|
|
70
|
+
if (typeof o.reason === "string")
|
|
71
|
+
evt.reason = o.reason.slice(0, 300);
|
|
72
|
+
if (typeof o.durationMs === "number" && Number.isFinite(o.durationMs)) {
|
|
73
|
+
evt.durationMs = Math.max(0, Math.round(o.durationMs));
|
|
74
|
+
}
|
|
75
|
+
if (o.ctx && typeof o.ctx === "object" && !Array.isArray(o.ctx)) {
|
|
76
|
+
evt.ctx = redactOpsCtx(o.ctx);
|
|
77
|
+
}
|
|
78
|
+
return evt;
|
|
79
|
+
}
|
|
80
|
+
/** Sérialise en plafonnant le ctx (jamais de throw). */
|
|
81
|
+
export function serializeOpsEvent(evt) {
|
|
82
|
+
try {
|
|
83
|
+
let line = JSON.stringify(evt);
|
|
84
|
+
if (evt.ctx && Buffer.byteLength(line, "utf8") > MAX_CTX_BYTES + 1024) {
|
|
85
|
+
line = JSON.stringify({ ...evt, ctx: { _truncated: true } });
|
|
86
|
+
}
|
|
87
|
+
return line;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return JSON.stringify({
|
|
91
|
+
ts: evt.ts,
|
|
92
|
+
bootId: evt.bootId,
|
|
93
|
+
seq: evt.seq,
|
|
94
|
+
source: evt.source,
|
|
95
|
+
level: evt.level,
|
|
96
|
+
kind: evt.kind,
|
|
97
|
+
reason: "serialize-error",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Parse une ligne stdout d'un sous-process.
|
|
103
|
+
* Renvoie l'input si la ligne est un TF2EVENT valide, sinon null.
|
|
104
|
+
*/
|
|
105
|
+
export function parseOpsLine(line) {
|
|
106
|
+
const trimmed = line.trim();
|
|
107
|
+
for (const prefix of OPS_EVENT_PREFIXES) {
|
|
108
|
+
if (!trimmed.startsWith(prefix))
|
|
109
|
+
continue;
|
|
110
|
+
try {
|
|
111
|
+
return sanitizeOpsEventInput(JSON.parse(trimmed.slice(prefix.length)));
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ops/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injection host pour request-logs (évite imports `@/` marque).
|
|
3
|
+
* O5 — noyau générique kit.
|
|
4
|
+
*/
|
|
5
|
+
export type RequestLogsConfig = {
|
|
6
|
+
/**
|
|
7
|
+
* Répertoire miroir jsonl pour l’agent flotte Electron.
|
|
8
|
+
* Défaut : `CREEZIO_FLEET_STATE_DIR`, sinon la variable
|
|
9
|
+
* `${envPrefix}_FLEET_STATE_DIR` dérivée du manifest marque (posée par le
|
|
10
|
+
* host — voir brand-host-stack) : aucun préfixe marque énuméré ici.
|
|
11
|
+
*/
|
|
12
|
+
getFleetStateDir?: () => string | undefined;
|
|
13
|
+
};
|
|
14
|
+
export declare function configureRequestLogs(next: RequestLogsConfig): void;
|
|
15
|
+
export declare function getRequestLogsConfig(): RequestLogsConfig;
|
|
16
|
+
export declare function resetRequestLogsConfigForTests(): void;
|
|
17
|
+
/** Résout le dir miroir (config marque, env générique, ou envKey manifest). */
|
|
18
|
+
export declare function resolveFleetStateDir(): string | undefined;
|
|
19
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/request-logs/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;CAC7C,CAAC;AAIF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAElE;AAED,wBAAgB,oBAAoB,IAAI,iBAAiB,CAExD;AAED,wBAAgB,8BAA8B,IAAI,IAAI,CAErD;AAID,+EAA+E;AAC/E,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,SAAS,CAkBzD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Injection host pour request-logs (évite imports `@/` marque).
|
|
3
|
+
* O5 — noyau générique kit.
|
|
4
|
+
*/
|
|
5
|
+
let config = {};
|
|
6
|
+
export function configureRequestLogs(next) {
|
|
7
|
+
config = next ?? {};
|
|
8
|
+
}
|
|
9
|
+
export function getRequestLogsConfig() {
|
|
10
|
+
return config;
|
|
11
|
+
}
|
|
12
|
+
export function resetRequestLogsConfigForTests() {
|
|
13
|
+
config = {};
|
|
14
|
+
}
|
|
15
|
+
const FLEET_STATE_DIR_SUFFIX = "_FLEET_STATE_DIR";
|
|
16
|
+
/** Résout le dir miroir (config marque, env générique, ou envKey manifest). */
|
|
17
|
+
export function resolveFleetStateDir() {
|
|
18
|
+
const custom = config.getFleetStateDir?.();
|
|
19
|
+
if (custom)
|
|
20
|
+
return custom;
|
|
21
|
+
const generic = process.env.CREEZIO_FLEET_STATE_DIR;
|
|
22
|
+
if (generic)
|
|
23
|
+
return generic;
|
|
24
|
+
// Dérivation manifest/envKey : le host pose `${envPrefix}_FLEET_STATE_DIR`
|
|
25
|
+
// (préfixe issu du manifest marque) — on accepte n'importe quel préfixe,
|
|
26
|
+
// ce qui couvre aussi les préfixes legacy sans les câbler ici.
|
|
27
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
28
|
+
if (value &&
|
|
29
|
+
key.endsWith(FLEET_STATE_DIR_SUFFIX) &&
|
|
30
|
+
key !== "CREEZIO_FLEET_STATE_DIR") {
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/request-logs/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,IAAI,MAAM,GAAsB,EAAE,CAAC;AAEnC,MAAM,UAAU,oBAAoB,CAAC,IAAuB;IAC1D,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,8BAA8B;IAC5C,MAAM,GAAG,EAAE,CAAC;AACd,CAAC;AAED,MAAM,sBAAsB,GAAG,kBAAkB,CAAC;AAElD,+EAA+E;AAC/E,MAAM,UAAU,oBAAoB;IAClC,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,CAAC;IAC3C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;IACpD,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC;IAC5B,2EAA2E;IAC3E,yEAAyE;IACzE,+DAA+D;IAC/D,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvD,IACE,KAAK;YACL,GAAG,CAAC,QAAQ,CAAC,sBAAsB,CAAC;YACpC,GAAG,KAAK,yBAAyB,EACjC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin — lecture / purge des logs API + MCP (session UI).
|
|
3
|
+
* Hono « nu » : hors doc OpenAPI publique.
|
|
4
|
+
* O5 — extrait TempoFlow (gold). Auth owner reste côté marque (montage).
|
|
5
|
+
*/
|
|
6
|
+
import { Hono } from "hono";
|
|
7
|
+
export declare function createRequestLogsRoutes(): Hono;
|
|
8
|
+
//# sourceMappingURL=http-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-routes.d.ts","sourceRoot":"","sources":["../../src/request-logs/http-routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAO5B,wBAAgB,uBAAuB,IAAI,IAAI,CA0B9C"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Admin — lecture / purge des logs API + MCP (session UI).
|
|
3
|
+
* Hono « nu » : hors doc OpenAPI publique.
|
|
4
|
+
* O5 — extrait TempoFlow (gold). Auth owner reste côté marque (montage).
|
|
5
|
+
*/
|
|
6
|
+
import { Hono } from "hono";
|
|
7
|
+
import { clearRequestLogs, listRequestLogs, } from "./request-logs.js";
|
|
8
|
+
export function createRequestLogsRoutes() {
|
|
9
|
+
const app = new Hono();
|
|
10
|
+
app.get("/request-logs", (c) => {
|
|
11
|
+
const limit = Number(c.req.query("limit")) || 100;
|
|
12
|
+
const sourceRaw = (c.req.query("source") || "all").toLowerCase();
|
|
13
|
+
const source = sourceRaw === "mcp" || sourceRaw === "api"
|
|
14
|
+
? sourceRaw
|
|
15
|
+
: "all";
|
|
16
|
+
const q = c.req.query("q") || undefined;
|
|
17
|
+
const errorsOnly = c.req.query("errorsOnly") === "1" ||
|
|
18
|
+
c.req.query("errorsOnly") === "true" ||
|
|
19
|
+
c.req.query("errors") === "1";
|
|
20
|
+
const result = listRequestLogs({ limit, source, q, errorsOnly });
|
|
21
|
+
return c.json(result);
|
|
22
|
+
});
|
|
23
|
+
app.delete("/request-logs", (c) => {
|
|
24
|
+
const { cleared } = clearRequestLogs();
|
|
25
|
+
return c.json({ ok: true, cleared });
|
|
26
|
+
});
|
|
27
|
+
return app;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=http-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-routes.js","sourceRoot":"","sources":["../../src/request-logs/http-routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EACL,gBAAgB,EAChB,eAAe,GAEhB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,UAAU,uBAAuB;IACrC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,GAAG,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC;QAClD,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QACjE,MAAM,MAAM,GACV,SAAS,KAAK,KAAK,IAAI,SAAS,KAAK,KAAK;YACxC,CAAC,CAAE,SAA8B;YACjC,CAAC,CAAC,KAAK,CAAC;QACZ,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC;QACxC,MAAM,UAAU,GACd,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,GAAG;YACjC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,MAAM;YACpC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC;QAEhC,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;QACjE,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,EAAE,EAAE;QAChC,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,EAAE,CAAC;QACvC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { configureRequestLogs, getRequestLogsConfig, resetRequestLogsConfigForTests, resolveFleetStateDir, type RequestLogsConfig, } from "./config.js";
|
|
2
|
+
export type { RequestLogSource, RequestLogDetail, RequestLogEntry, ListRequestLogsOpts, } from "./request-logs.js";
|
|
3
|
+
export { getRequestLogCapacity, _resetRequestLogsForTests, isSecretKey, redactSecrets, pushRequestLog, listRequestLogs, clearRequestLogs, parseJsonRpcMessages, summarizeMcpRequest, summarizeMcpResponse, extractApiErrorMessage, shouldSkipRequestLog, } from "./request-logs.js";
|
|
4
|
+
export { requestLogApiMiddleware, requestLogMcpMiddleware, } from "./middleware.js";
|
|
5
|
+
export { createRequestLogsRoutes } from "./http-routes.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/request-logs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,8BAA8B,EAC9B,oBAAoB,EACpB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AAErB,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { configureRequestLogs, getRequestLogsConfig, resetRequestLogsConfigForTests, resolveFleetStateDir, } from "./config.js";
|
|
2
|
+
export { getRequestLogCapacity, _resetRequestLogsForTests, isSecretKey, redactSecrets, pushRequestLog, listRequestLogs, clearRequestLogs, parseJsonRpcMessages, summarizeMcpRequest, summarizeMcpResponse, extractApiErrorMessage, shouldSkipRequestLog, } from "./request-logs.js";
|
|
3
|
+
export { requestLogApiMiddleware, requestLogMcpMiddleware, } from "./middleware.js";
|
|
4
|
+
export { createRequestLogsRoutes } from "./http-routes.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/request-logs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,8BAA8B,EAC9B,oBAAoB,GAErB,MAAM,aAAa,CAAC;AASrB,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,WAAW,EACX,aAAa,EACb,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middlewares de collecte des logs API / MCP → ring buffer mémoire.
|
|
3
|
+
* Ne doit jamais faire échouer la requête (tout est try/catch).
|
|
4
|
+
* O5 — extrait TempoFlow (gold).
|
|
5
|
+
*/
|
|
6
|
+
import type { MiddlewareHandler } from "hono";
|
|
7
|
+
/** Middleware API v1 — à brancher tôt (avant auth). */
|
|
8
|
+
export declare const requestLogApiMiddleware: MiddlewareHandler;
|
|
9
|
+
/** Middleware MCP `/mcp` uniquement (pas OAuth). */
|
|
10
|
+
export declare const requestLogMcpMiddleware: MiddlewareHandler;
|
|
11
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/request-logs/middleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAW,iBAAiB,EAAE,MAAM,MAAM,CAAC;AA+GvD,uDAAuD;AACvD,eAAO,MAAM,uBAAuB,EAAE,iBA6CrC,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,uBAAuB,EAAE,iBAwDrC,CAAC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { extractApiErrorMessage, pushRequestLog, redactSecrets, shouldSkipRequestLog, summarizeMcpRequest, summarizeMcpResponse, } from "./request-logs.js";
|
|
2
|
+
async function safeReadText(resOrReq) {
|
|
3
|
+
try {
|
|
4
|
+
return await resOrReq.text();
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function safeJsonParse(text) {
|
|
11
|
+
if (!text)
|
|
12
|
+
return null;
|
|
13
|
+
const t = text.trim();
|
|
14
|
+
if (!t)
|
|
15
|
+
return null;
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(t);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function queryRecord(c) {
|
|
24
|
+
try {
|
|
25
|
+
const url = new URL(c.req.url);
|
|
26
|
+
const out = {};
|
|
27
|
+
url.searchParams.forEach((v, k) => {
|
|
28
|
+
out[k] = isSecretLookingParam(k) ? "[redacted]" : String(redactSecrets(v));
|
|
29
|
+
});
|
|
30
|
+
return Object.keys(out).length ? out : undefined;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function isSecretLookingParam(key) {
|
|
37
|
+
return /token|secret|password|key|jwt|auth/i.test(key);
|
|
38
|
+
}
|
|
39
|
+
async function readRequestJson(c) {
|
|
40
|
+
const method = c.req.method.toUpperCase();
|
|
41
|
+
if (method === "GET" ||
|
|
42
|
+
method === "HEAD" ||
|
|
43
|
+
method === "OPTIONS" ||
|
|
44
|
+
method === "DELETE") {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const ct = (c.req.header("content-type") || "").toLowerCase();
|
|
48
|
+
if (ct && !ct.includes("json") && !ct.includes("text/plain")) {
|
|
49
|
+
return { _skipped: `content-type ${ct.split(";")[0]}` };
|
|
50
|
+
}
|
|
51
|
+
const text = await safeReadText(c.req.raw.clone());
|
|
52
|
+
if (!text)
|
|
53
|
+
return null;
|
|
54
|
+
if (text.length > 64_000) {
|
|
55
|
+
return { _truncated: true, preview: redactSecrets(text.slice(0, 2000)) };
|
|
56
|
+
}
|
|
57
|
+
const parsed = safeJsonParse(text);
|
|
58
|
+
return parsed != null
|
|
59
|
+
? redactSecrets(parsed)
|
|
60
|
+
: { _raw: redactSecrets(text.slice(0, 500)) };
|
|
61
|
+
}
|
|
62
|
+
async function readResponseJson(c) {
|
|
63
|
+
const res = c.res;
|
|
64
|
+
if (!res)
|
|
65
|
+
return null;
|
|
66
|
+
const ct = (res.headers.get("content-type") || "").toLowerCase();
|
|
67
|
+
if (ct && !ct.includes("json") && !ct.includes("text/plain"))
|
|
68
|
+
return null;
|
|
69
|
+
const len = res.headers.get("content-length");
|
|
70
|
+
if (len && Number(len) > 256_000)
|
|
71
|
+
return null;
|
|
72
|
+
const text = await safeReadText(res.clone());
|
|
73
|
+
if (!text || text.length > 256_000)
|
|
74
|
+
return null;
|
|
75
|
+
return safeJsonParse(text);
|
|
76
|
+
}
|
|
77
|
+
function commitLog(source, c, started, detail) {
|
|
78
|
+
try {
|
|
79
|
+
const pathName = c.req.path || new URL(c.req.url).pathname;
|
|
80
|
+
if (shouldSkipRequestLog(pathName))
|
|
81
|
+
return;
|
|
82
|
+
const status = c.res?.status ?? 0;
|
|
83
|
+
pushRequestLog({
|
|
84
|
+
ts: new Date(started).toISOString(),
|
|
85
|
+
source,
|
|
86
|
+
method: c.req.method.toUpperCase(),
|
|
87
|
+
path: pathName,
|
|
88
|
+
status,
|
|
89
|
+
durationMs: Math.max(0, Date.now() - started),
|
|
90
|
+
detail,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
console.error("[request-logs] commit failed", err);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Middleware API v1 — à brancher tôt (avant auth). */
|
|
98
|
+
export const requestLogApiMiddleware = async (c, next) => {
|
|
99
|
+
const started = Date.now();
|
|
100
|
+
const pathName = c.req.path || "";
|
|
101
|
+
if (shouldSkipRequestLog(pathName) || c.req.method.toUpperCase() === "OPTIONS") {
|
|
102
|
+
await next();
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
let body = null;
|
|
106
|
+
try {
|
|
107
|
+
body = await readRequestJson(c);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
body = null;
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
await next();
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
commitLog("api", c, started, {
|
|
117
|
+
query: queryRecord(c),
|
|
118
|
+
body: body ?? undefined,
|
|
119
|
+
ok: false,
|
|
120
|
+
error: err instanceof Error ? err.message : String(err),
|
|
121
|
+
});
|
|
122
|
+
throw err;
|
|
123
|
+
}
|
|
124
|
+
const detail = {
|
|
125
|
+
query: queryRecord(c),
|
|
126
|
+
body: body ?? undefined,
|
|
127
|
+
};
|
|
128
|
+
const status = c.res?.status ?? 0;
|
|
129
|
+
if (status >= 400) {
|
|
130
|
+
try {
|
|
131
|
+
const resp = await readResponseJson(c);
|
|
132
|
+
const msg = extractApiErrorMessage(resp);
|
|
133
|
+
if (msg)
|
|
134
|
+
detail.error = msg;
|
|
135
|
+
detail.ok = false;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
detail.ok = false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
detail.ok = true;
|
|
143
|
+
}
|
|
144
|
+
commitLog("api", c, started, detail);
|
|
145
|
+
};
|
|
146
|
+
/** Middleware MCP `/mcp` uniquement (pas OAuth). */
|
|
147
|
+
export const requestLogMcpMiddleware = async (c, next) => {
|
|
148
|
+
const started = Date.now();
|
|
149
|
+
if (c.req.method.toUpperCase() === "OPTIONS") {
|
|
150
|
+
await next();
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
let detail = {};
|
|
154
|
+
try {
|
|
155
|
+
const text = await safeReadText(c.req.raw.clone());
|
|
156
|
+
const parsed = safeJsonParse(text);
|
|
157
|
+
if (parsed != null) {
|
|
158
|
+
detail = summarizeMcpRequest(parsed);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
/* ignore */
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
await next();
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
detail.ok = false;
|
|
169
|
+
detail.error = err instanceof Error ? err.message : String(err);
|
|
170
|
+
commitLog("mcp", c, started, detail);
|
|
171
|
+
throw err;
|
|
172
|
+
}
|
|
173
|
+
try {
|
|
174
|
+
const auth = c.get("mcpAuth");
|
|
175
|
+
if (auth) {
|
|
176
|
+
detail.authType = auth.authType;
|
|
177
|
+
detail.clientId = auth.clientId;
|
|
178
|
+
detail.userId = auth.userId;
|
|
179
|
+
}
|
|
180
|
+
const resp = await readResponseJson(c);
|
|
181
|
+
if (resp != null) {
|
|
182
|
+
const summary = summarizeMcpResponse(resp);
|
|
183
|
+
detail = { ...detail, ...summary };
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
const status = c.res?.status ?? 0;
|
|
187
|
+
detail.ok = status > 0 && status < 400;
|
|
188
|
+
if (!detail.ok && status >= 400) {
|
|
189
|
+
detail.error = detail.error || `HTTP ${status}`;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
/* ignore */
|
|
195
|
+
}
|
|
196
|
+
commitLog("mcp", c, started, detail);
|
|
197
|
+
};
|
|
198
|
+
//# sourceMappingURL=middleware.js.map
|