@zintrust/trace 0.4.75
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 +288 -0
- package/dist/build-manifest.json +365 -0
- package/dist/cli-register.d.ts +9 -0
- package/dist/cli-register.js +32 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.js +38 -0
- package/dist/context.d.ts +18 -0
- package/dist/context.js +86 -0
- package/dist/dashboard/handlers.d.ts +15 -0
- package/dist/dashboard/handlers.js +179 -0
- package/dist/dashboard/routes.d.ts +19 -0
- package/dist/dashboard/routes.js +50 -0
- package/dist/dashboard/ui.d.ts +2 -0
- package/dist/dashboard/ui.js +870 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +50 -0
- package/dist/migrations/20260331000001_create_zin_debugger_entries_table.d.ts +10 -0
- package/dist/migrations/20260331000001_create_zin_debugger_entries_table.js +28 -0
- package/dist/migrations/20260331000002_create_zin_debugger_entries_tags_table.d.ts +10 -0
- package/dist/migrations/20260331000002_create_zin_debugger_entries_tags_table.js +21 -0
- package/dist/migrations/20260331000003_create_zin_debugger_monitoring_table.d.ts +10 -0
- package/dist/migrations/20260331000003_create_zin_debugger_monitoring_table.js +17 -0
- package/dist/migrations/index.d.ts +6 -0
- package/dist/migrations/index.js +4 -0
- package/dist/plugin.d.ts +1 -0
- package/dist/plugin.js +3 -0
- package/dist/register.d.ts +1 -0
- package/dist/register.js +140 -0
- package/dist/storage/DebuggerStorage.d.ts +13 -0
- package/dist/storage/DebuggerStorage.js +195 -0
- package/dist/storage/TraceStorage.d.ts +13 -0
- package/dist/storage/TraceStorage.js +195 -0
- package/dist/storage/index.d.ts +2 -0
- package/dist/storage/index.js +1 -0
- package/dist/types.d.ts +270 -0
- package/dist/types.js +25 -0
- package/dist/ui.d.ts +8 -0
- package/dist/ui.js +7 -0
- package/dist/utils/authTag.d.ts +5 -0
- package/dist/utils/authTag.js +18 -0
- package/dist/utils/familyHash.d.ts +1 -0
- package/dist/utils/familyHash.js +8 -0
- package/dist/utils/redact.d.ts +6 -0
- package/dist/utils/redact.js +49 -0
- package/dist/utils/requestFilter.d.ts +4 -0
- package/dist/utils/requestFilter.js +26 -0
- package/dist/utils/stackFrame.d.ts +6 -0
- package/dist/utils/stackFrame.js +38 -0
- package/dist/watchers/AuthWatcher.d.ts +6 -0
- package/dist/watchers/AuthWatcher.js +49 -0
- package/dist/watchers/BatchWatcher.d.ts +6 -0
- package/dist/watchers/BatchWatcher.js +46 -0
- package/dist/watchers/CacheWatcher.d.ts +6 -0
- package/dist/watchers/CacheWatcher.js +51 -0
- package/dist/watchers/CommandWatcher.d.ts +6 -0
- package/dist/watchers/CommandWatcher.js +49 -0
- package/dist/watchers/DumpWatcher.d.ts +7 -0
- package/dist/watchers/DumpWatcher.js +41 -0
- package/dist/watchers/EventWatcher.d.ts +6 -0
- package/dist/watchers/EventWatcher.js +42 -0
- package/dist/watchers/ExceptionWatcher.d.ts +4 -0
- package/dist/watchers/ExceptionWatcher.js +103 -0
- package/dist/watchers/GateWatcher.d.ts +6 -0
- package/dist/watchers/GateWatcher.js +45 -0
- package/dist/watchers/HttpClientWatcher.d.ts +6 -0
- package/dist/watchers/HttpClientWatcher.js +50 -0
- package/dist/watchers/HttpWatcher.d.ts +2 -0
- package/dist/watchers/HttpWatcher.js +71 -0
- package/dist/watchers/JobWatcher.d.ts +10 -0
- package/dist/watchers/JobWatcher.js +108 -0
- package/dist/watchers/LogWatcher.d.ts +2 -0
- package/dist/watchers/LogWatcher.js +50 -0
- package/dist/watchers/MailWatcher.d.ts +6 -0
- package/dist/watchers/MailWatcher.js +45 -0
- package/dist/watchers/MiddlewareWatcher.d.ts +6 -0
- package/dist/watchers/MiddlewareWatcher.js +41 -0
- package/dist/watchers/ModelWatcher.d.ts +6 -0
- package/dist/watchers/ModelWatcher.js +42 -0
- package/dist/watchers/NotificationWatcher.d.ts +6 -0
- package/dist/watchers/NotificationWatcher.js +42 -0
- package/dist/watchers/QueryWatcher.d.ts +2 -0
- package/dist/watchers/QueryWatcher.js +72 -0
- package/dist/watchers/RedisWatcher.d.ts +7 -0
- package/dist/watchers/RedisWatcher.js +38 -0
- package/dist/watchers/ScheduleWatcher.d.ts +6 -0
- package/dist/watchers/ScheduleWatcher.js +46 -0
- package/dist/watchers/ViewWatcher.d.ts +6 -0
- package/dist/watchers/ViewWatcher.js +36 -0
- package/package.json +59 -0
- package/src/cli-register.ts +63 -0
- package/src/config.ts +46 -0
- package/src/context.ts +101 -0
- package/src/dashboard/handlers.ts +197 -0
- package/src/dashboard/routes.ts +101 -0
- package/src/dashboard/ui.ts +879 -0
- package/src/dashboard/zintrust-debuger.svg +30 -0
- package/src/index.ts +88 -0
- package/src/plugin.ts +9 -0
- package/src/register.ts +219 -0
- package/src/storage/TraceStorage.ts +306 -0
- package/src/storage/index.ts +2 -0
- package/src/types.ts +317 -0
- package/src/ui.ts +9 -0
- package/src/utils/authTag.ts +20 -0
- package/src/utils/familyHash.ts +8 -0
- package/src/utils/redact.ts +64 -0
- package/src/utils/requestFilter.ts +33 -0
- package/src/utils/stackFrame.ts +44 -0
- package/src/watchers/AuthWatcher.ts +50 -0
- package/src/watchers/BatchWatcher.ts +52 -0
- package/src/watchers/CacheWatcher.ts +58 -0
- package/src/watchers/CommandWatcher.ts +55 -0
- package/src/watchers/DumpWatcher.ts +42 -0
- package/src/watchers/EventWatcher.ts +43 -0
- package/src/watchers/ExceptionWatcher.ts +114 -0
- package/src/watchers/GateWatcher.ts +50 -0
- package/src/watchers/HttpClientWatcher.ts +56 -0
- package/src/watchers/HttpWatcher.ts +94 -0
- package/src/watchers/JobWatcher.ts +121 -0
- package/src/watchers/LogWatcher.ts +61 -0
- package/src/watchers/MailWatcher.ts +47 -0
- package/src/watchers/MiddlewareWatcher.ts +42 -0
- package/src/watchers/ModelWatcher.ts +48 -0
- package/src/watchers/NotificationWatcher.ts +43 -0
- package/src/watchers/QueryWatcher.ts +85 -0
- package/src/watchers/RedisWatcher.ts +39 -0
- package/src/watchers/ScheduleWatcher.ts +54 -0
- package/src/watchers/ViewWatcher.ts +37 -0
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TraceConfig — defaults and merge helper for @zintrust/trace
|
|
3
|
+
*/
|
|
4
|
+
import type { ITraceConfig, TraceConfigOverrides } from './types';
|
|
5
|
+
export declare const TraceConfig: Readonly<{
|
|
6
|
+
defaults(): ITraceConfig;
|
|
7
|
+
merge(overrides?: TraceConfigOverrides): ITraceConfig;
|
|
8
|
+
isWatcherEnabled: (config: ITraceConfig, key: keyof ITraceConfig["watchers"]) => boolean;
|
|
9
|
+
}>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const DEFAULTS = Object.freeze({
|
|
2
|
+
enabled: false,
|
|
3
|
+
connection: undefined,
|
|
4
|
+
pruneAfterHours: 24,
|
|
5
|
+
ignoreRoutes: ['/trace', '/health', '/ping'],
|
|
6
|
+
slowQueryThreshold: 100,
|
|
7
|
+
logMinLevel: 'info',
|
|
8
|
+
watchers: {},
|
|
9
|
+
redaction: {
|
|
10
|
+
headers: ['authorization', 'cookie', 'x-api-key', 'x-auth-token'],
|
|
11
|
+
body: ['password', 'token', 'secret', 'apiKey', 'api_key', 'jwt', 'bearer'],
|
|
12
|
+
query: [],
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
const isWatcherEnabled = (config, key) => {
|
|
16
|
+
const override = config.watchers[key];
|
|
17
|
+
return override !== false; // undefined = enabled by default; explicit false = disabled
|
|
18
|
+
};
|
|
19
|
+
export const TraceConfig = Object.freeze({
|
|
20
|
+
defaults() {
|
|
21
|
+
return DEFAULTS;
|
|
22
|
+
},
|
|
23
|
+
merge(overrides) {
|
|
24
|
+
if (overrides === undefined || overrides === null)
|
|
25
|
+
return DEFAULTS;
|
|
26
|
+
return Object.freeze({
|
|
27
|
+
...DEFAULTS,
|
|
28
|
+
...overrides,
|
|
29
|
+
watchers: { ...DEFAULTS.watchers, ...(overrides.watchers ?? {}) },
|
|
30
|
+
redaction: {
|
|
31
|
+
...DEFAULTS.redaction,
|
|
32
|
+
...(overrides.redaction ?? {}),
|
|
33
|
+
},
|
|
34
|
+
ignoreRoutes: overrides.ignoreRoutes ?? DEFAULTS.ignoreRoutes,
|
|
35
|
+
});
|
|
36
|
+
},
|
|
37
|
+
isWatcherEnabled,
|
|
38
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TraceContext — sealed namespace for batch_id, userId, hostname, and memory.
|
|
3
|
+
* Piggybacks on RequestContext (already available in core) — no new ALS store.
|
|
4
|
+
*/
|
|
5
|
+
type RequestContextProvider = {
|
|
6
|
+
current?: () => unknown;
|
|
7
|
+
peek?: () => unknown;
|
|
8
|
+
};
|
|
9
|
+
export declare const TraceContext: Readonly<{
|
|
10
|
+
getBatchId: () => string;
|
|
11
|
+
getUserId: () => string | undefined;
|
|
12
|
+
getRequestPath: () => string | undefined;
|
|
13
|
+
getHostname: () => string;
|
|
14
|
+
getMemory: () => number | null;
|
|
15
|
+
now: () => number;
|
|
16
|
+
setRequestContextImpl: (impl: RequestContextProvider) => void;
|
|
17
|
+
}>;
|
|
18
|
+
export {};
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Lazy reference to ZinTrust RequestContext — typed as unknown to stay runtime-agnostic.
|
|
2
|
+
let _reqCtx;
|
|
3
|
+
const getRequestContext = () => {
|
|
4
|
+
return _reqCtx;
|
|
5
|
+
};
|
|
6
|
+
const setRequestContextImpl = (impl) => {
|
|
7
|
+
_reqCtx = impl;
|
|
8
|
+
};
|
|
9
|
+
const isPromiseLike = (value) => {
|
|
10
|
+
return typeof value === 'object' && value !== null && 'then' in value;
|
|
11
|
+
};
|
|
12
|
+
const getCurrentContext = () => {
|
|
13
|
+
const provider = getRequestContext();
|
|
14
|
+
if (!provider)
|
|
15
|
+
return undefined;
|
|
16
|
+
let currentValue;
|
|
17
|
+
if (typeof provider.peek === 'function') {
|
|
18
|
+
currentValue = provider.peek();
|
|
19
|
+
}
|
|
20
|
+
else if (typeof provider.current === 'function') {
|
|
21
|
+
currentValue = provider.current();
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
currentValue = undefined;
|
|
25
|
+
}
|
|
26
|
+
if (isPromiseLike(currentValue))
|
|
27
|
+
return undefined;
|
|
28
|
+
if (typeof currentValue !== 'object' || currentValue === null)
|
|
29
|
+
return undefined;
|
|
30
|
+
return currentValue;
|
|
31
|
+
};
|
|
32
|
+
const getContextString = (key) => {
|
|
33
|
+
const value = getCurrentContext()?.[key];
|
|
34
|
+
if (typeof value === 'string' && value.trim() !== '')
|
|
35
|
+
return value;
|
|
36
|
+
if (typeof value === 'number')
|
|
37
|
+
return String(value);
|
|
38
|
+
return undefined;
|
|
39
|
+
};
|
|
40
|
+
const getBatchId = () => {
|
|
41
|
+
return getContextString('traceId') ?? crypto.randomUUID();
|
|
42
|
+
};
|
|
43
|
+
const getUserId = () => {
|
|
44
|
+
return getContextString('userId');
|
|
45
|
+
};
|
|
46
|
+
const getRequestPath = () => {
|
|
47
|
+
return getContextString('path');
|
|
48
|
+
};
|
|
49
|
+
const getHostname = () => {
|
|
50
|
+
// Workers do not expose `os` or `process` — return 'worker' as fallback.
|
|
51
|
+
if (typeof process !== 'undefined' && typeof process.env === 'object') {
|
|
52
|
+
try {
|
|
53
|
+
// Dynamic import avoids the need for a node-singletons wrapper at the type level.
|
|
54
|
+
// Hostname is non-critical; we fall back gracefully.
|
|
55
|
+
const hostname = process.env['HOSTNAME'];
|
|
56
|
+
if (typeof hostname === 'string' && hostname.length > 0)
|
|
57
|
+
return hostname;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// fall through
|
|
61
|
+
}
|
|
62
|
+
return 'node';
|
|
63
|
+
}
|
|
64
|
+
return 'worker';
|
|
65
|
+
};
|
|
66
|
+
const getMemory = () => {
|
|
67
|
+
if (typeof process !== 'undefined' && typeof process.memoryUsage === 'function') {
|
|
68
|
+
try {
|
|
69
|
+
return Math.round(process.memoryUsage().heapUsed / 1024 / 1024);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
};
|
|
77
|
+
const now = () => Date.now();
|
|
78
|
+
export const TraceContext = Object.freeze({
|
|
79
|
+
getBatchId,
|
|
80
|
+
getUserId,
|
|
81
|
+
getRequestPath,
|
|
82
|
+
getHostname,
|
|
83
|
+
getMemory,
|
|
84
|
+
now,
|
|
85
|
+
setRequestContextImpl,
|
|
86
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TraceDashboard handlers — pure handler functions wired to ITraceStorage.
|
|
3
|
+
* No auth in this layer — caller mounts middleware as needed.
|
|
4
|
+
*/
|
|
5
|
+
import type { IRequest, IResponse } from '@zintrust/core';
|
|
6
|
+
import type { ITraceStorage } from '../types';
|
|
7
|
+
export declare const setHandlerStorage: (s: ITraceStorage) => void;
|
|
8
|
+
export declare function listEntries(req: IRequest, res: IResponse): Promise<void>;
|
|
9
|
+
export declare function getEntry(req: IRequest, res: IResponse): Promise<void>;
|
|
10
|
+
export declare function getBatch(req: IRequest, res: IResponse): Promise<void>;
|
|
11
|
+
export declare function getStats(_req: IRequest, res: IResponse): Promise<void>;
|
|
12
|
+
export declare function clearEntries(_req: IRequest, res: IResponse): Promise<void>;
|
|
13
|
+
export declare function getMonitoring(_req: IRequest, res: IResponse): Promise<void>;
|
|
14
|
+
export declare function addMonitoring(req: IRequest, res: IResponse): Promise<void>;
|
|
15
|
+
export declare function removeMonitoring(req: IRequest, res: IResponse): Promise<void>;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Storage holder (set once from routes.ts)
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
let _storage = null;
|
|
5
|
+
export const setHandlerStorage = (s) => {
|
|
6
|
+
_storage = s;
|
|
7
|
+
};
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Helpers
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
const requireStorage = (res) => {
|
|
12
|
+
if (_storage) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
res.setStatus(503).json({ error: 'Trace not initialised' });
|
|
16
|
+
return false;
|
|
17
|
+
};
|
|
18
|
+
const getStorage = (res) => {
|
|
19
|
+
if (requireStorage(res)) {
|
|
20
|
+
return _storage;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
};
|
|
24
|
+
const qp = (req, key) => {
|
|
25
|
+
const v = req.getQueryParam(key);
|
|
26
|
+
return Array.isArray(v) ? v[0] : v;
|
|
27
|
+
};
|
|
28
|
+
const qpInt = (req, key, fallback) => {
|
|
29
|
+
const raw = qp(req, key);
|
|
30
|
+
const n = typeof raw === 'string' ? Number.parseInt(raw, 10) : Number.NaN;
|
|
31
|
+
return Number.isNaN(n) ? fallback : n;
|
|
32
|
+
};
|
|
33
|
+
const getNumericQueryParam = (req, key) => {
|
|
34
|
+
const raw = qp(req, key);
|
|
35
|
+
if (typeof raw === 'string') {
|
|
36
|
+
const parsed = Number(raw);
|
|
37
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
};
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Entry handlers
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
export async function listEntries(req, res) {
|
|
45
|
+
const storage = getStorage(res);
|
|
46
|
+
if (storage !== null) {
|
|
47
|
+
const opts = {
|
|
48
|
+
type: qp(req, 'type'),
|
|
49
|
+
tag: qp(req, 'tag'),
|
|
50
|
+
batchId: qp(req, 'batchId'),
|
|
51
|
+
from: getNumericQueryParam(req, 'from'),
|
|
52
|
+
to: getNumericQueryParam(req, 'to'),
|
|
53
|
+
page: qpInt(req, 'page', 1),
|
|
54
|
+
perPage: Math.min(qpInt(req, 'perPage', 50), 200),
|
|
55
|
+
};
|
|
56
|
+
try {
|
|
57
|
+
const result = await storage.queryEntries(opts);
|
|
58
|
+
res.json({ ok: true, ...result, page: opts.page, perPage: opts.perPage });
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
res.setStatus(500).json({ error: err.message });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export async function getEntry(req, res) {
|
|
66
|
+
const storage = getStorage(res);
|
|
67
|
+
if (storage === null)
|
|
68
|
+
return;
|
|
69
|
+
const uuid = req.getParam('uuid');
|
|
70
|
+
if (uuid) {
|
|
71
|
+
try {
|
|
72
|
+
const entry = await storage.getEntry(uuid);
|
|
73
|
+
if (entry) {
|
|
74
|
+
res.json({ ok: true, entry });
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
res.setStatus(404).json({ error: 'Not found' });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
res.setStatus(500).json({ error: err.message });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
res.setStatus(400).json({ error: 'uuid required' });
|
|
86
|
+
}
|
|
87
|
+
export async function getBatch(req, res) {
|
|
88
|
+
const storage = getStorage(res);
|
|
89
|
+
if (storage === null)
|
|
90
|
+
return;
|
|
91
|
+
const batchId = req.getParam('batchId');
|
|
92
|
+
if (batchId) {
|
|
93
|
+
try {
|
|
94
|
+
const entries = await storage.getBatch(batchId);
|
|
95
|
+
res.json({ ok: true, entries });
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
res.setStatus(500).json({ error: err.message });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
res.setStatus(400).json({ error: 'batchId required' });
|
|
104
|
+
}
|
|
105
|
+
export async function getStats(_req, res) {
|
|
106
|
+
const storage = getStorage(res);
|
|
107
|
+
if (storage === null)
|
|
108
|
+
return;
|
|
109
|
+
try {
|
|
110
|
+
const stats = await storage.stats();
|
|
111
|
+
res.json({ ok: true, stats });
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
res.setStatus(500).json({ error: err.message });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export async function clearEntries(_req, res) {
|
|
118
|
+
const storage = getStorage(res);
|
|
119
|
+
if (storage === null)
|
|
120
|
+
return;
|
|
121
|
+
try {
|
|
122
|
+
await storage.clear();
|
|
123
|
+
res.json({ ok: true });
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
res.setStatus(500).json({ error: err.message });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Monitoring handlers
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
export async function getMonitoring(_req, res) {
|
|
133
|
+
const storage = getStorage(res);
|
|
134
|
+
if (storage === null)
|
|
135
|
+
return;
|
|
136
|
+
try {
|
|
137
|
+
const tags = await storage.getMonitoring();
|
|
138
|
+
res.json({ ok: true, tags });
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
res.setStatus(500).json({ error: err.message });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
export async function addMonitoring(req, res) {
|
|
145
|
+
const storage = getStorage(res);
|
|
146
|
+
if (storage === null)
|
|
147
|
+
return;
|
|
148
|
+
const tag = req.getParam('tag');
|
|
149
|
+
if (tag) {
|
|
150
|
+
try {
|
|
151
|
+
await storage.addMonitoring(tag);
|
|
152
|
+
res.json({ ok: true });
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
res.setStatus(500).json({ error: err.message });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
res.setStatus(400).json({ error: 'tag required' });
|
|
161
|
+
}
|
|
162
|
+
export async function removeMonitoring(req, res) {
|
|
163
|
+
const storage = getStorage(res);
|
|
164
|
+
if (storage === null)
|
|
165
|
+
return;
|
|
166
|
+
const tag = req.getParam('tag');
|
|
167
|
+
if (tag) {
|
|
168
|
+
try {
|
|
169
|
+
await storage.removeMonitoring(tag);
|
|
170
|
+
res.json({ ok: true });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
res.setStatus(500).json({ error: err.message });
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
res.setStatus(400).json({ error: 'tag required' });
|
|
179
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard route registrar for @zintrust/trace.
|
|
3
|
+
* Mounts the SPA + all REST API endpoints under the configured basePath.
|
|
4
|
+
* Auth is NOT applied here — callers add middleware via routeOptions.
|
|
5
|
+
*/
|
|
6
|
+
import { type IRouter } from '@zintrust/core';
|
|
7
|
+
import type { ITraceStorage } from '../types';
|
|
8
|
+
export type TraceDashboardOptions = {
|
|
9
|
+
/** Base path for the dashboard, e.g. '/trace'. Defaults to '/trace'. */
|
|
10
|
+
basePath?: string;
|
|
11
|
+
/** Optional ZinTrust middleware names to apply to all routes. */
|
|
12
|
+
middleware?: ReadonlyArray<string>;
|
|
13
|
+
};
|
|
14
|
+
export type TraceDashboardRegistrationOptions = TraceDashboardOptions & {
|
|
15
|
+
/** Optional trace storage connection override. Defaults to TraceConfig / runtime default. */
|
|
16
|
+
connectionName?: string;
|
|
17
|
+
};
|
|
18
|
+
export declare const registerTraceRoutes: (router: IRouter, storage: ITraceStorage, options?: TraceDashboardOptions) => void;
|
|
19
|
+
export declare const registerTraceDashboard: (router: IRouter, options?: TraceDashboardRegistrationOptions) => void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard route registrar for @zintrust/trace.
|
|
3
|
+
* Mounts the SPA + all REST API endpoints under the configured basePath.
|
|
4
|
+
* Auth is NOT applied here — callers add middleware via routeOptions.
|
|
5
|
+
*/
|
|
6
|
+
import { appConfig, Router, useDatabase } from '@zintrust/core';
|
|
7
|
+
import { TraceConfig } from '../config';
|
|
8
|
+
import { TraceStorage } from '../storage';
|
|
9
|
+
import { addMonitoring, clearEntries, getBatch, getEntry, getMonitoring, getStats, listEntries, removeMonitoring, setHandlerStorage, } from './handlers';
|
|
10
|
+
import { buildDashboardHtml } from './ui';
|
|
11
|
+
const resolveDashboardConnectionName = (connectionName) => {
|
|
12
|
+
const explicitConnection = connectionName?.trim();
|
|
13
|
+
if (explicitConnection !== undefined && explicitConnection !== '') {
|
|
14
|
+
return explicitConnection;
|
|
15
|
+
}
|
|
16
|
+
const configuredConnection = TraceConfig.merge().connection?.trim();
|
|
17
|
+
return configuredConnection === undefined || configuredConnection === ''
|
|
18
|
+
? undefined
|
|
19
|
+
: configuredConnection;
|
|
20
|
+
};
|
|
21
|
+
export const registerTraceRoutes = (router, storage, options = {}) => {
|
|
22
|
+
setHandlerStorage(storage);
|
|
23
|
+
const base = options.basePath ?? '/trace';
|
|
24
|
+
const routeOptions = (options.middleware?.length ?? 0) > 0
|
|
25
|
+
? { middleware: options.middleware }
|
|
26
|
+
: undefined;
|
|
27
|
+
// SPA shell
|
|
28
|
+
Router.get(router, base, (_req, res) => {
|
|
29
|
+
res.html(buildDashboardHtml(base, appConfig.name));
|
|
30
|
+
}, routeOptions);
|
|
31
|
+
// Serve the SPA for any /<basePath>/* sub-path (client-side routing)
|
|
32
|
+
Router.get(router, `${base}/*`, (_req, res) => {
|
|
33
|
+
res.html(buildDashboardHtml(base, appConfig.name));
|
|
34
|
+
}, routeOptions);
|
|
35
|
+
// REST API
|
|
36
|
+
Router.group(router, `${base}/api`, (r) => {
|
|
37
|
+
Router.get(r, '/entries', listEntries, routeOptions);
|
|
38
|
+
Router.get(r, '/entries/:uuid', getEntry, routeOptions);
|
|
39
|
+
Router.del(r, '/entries', clearEntries, routeOptions);
|
|
40
|
+
Router.get(r, '/batch/:batchId', getBatch, routeOptions);
|
|
41
|
+
Router.get(r, '/stats', getStats, routeOptions);
|
|
42
|
+
Router.get(r, '/monitoring', getMonitoring, routeOptions);
|
|
43
|
+
Router.post(r, '/monitoring/:tag', addMonitoring, routeOptions);
|
|
44
|
+
Router.del(r, '/monitoring/:tag', removeMonitoring, routeOptions);
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
export const registerTraceDashboard = (router, options = {}) => {
|
|
48
|
+
const storage = TraceStorage.resolveStorage(useDatabase(undefined, resolveDashboardConnectionName(options.connectionName)));
|
|
49
|
+
registerTraceRoutes(router, storage, options);
|
|
50
|
+
};
|