openclaw-observability 1.0.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.
Files changed (66) hide show
  1. package/dist/config.d.ts +60 -0
  2. package/dist/config.d.ts.map +1 -0
  3. package/dist/config.js +140 -0
  4. package/dist/config.js.map +1 -0
  5. package/dist/index.d.ts +37 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +1114 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/redaction.d.ts +20 -0
  10. package/dist/redaction.d.ts.map +1 -0
  11. package/dist/redaction.js +93 -0
  12. package/dist/redaction.js.map +1 -0
  13. package/dist/security/chain-detector.d.ts +37 -0
  14. package/dist/security/chain-detector.d.ts.map +1 -0
  15. package/dist/security/chain-detector.js +187 -0
  16. package/dist/security/chain-detector.js.map +1 -0
  17. package/dist/security/rules.d.ts +22 -0
  18. package/dist/security/rules.d.ts.map +1 -0
  19. package/dist/security/rules.js +479 -0
  20. package/dist/security/rules.js.map +1 -0
  21. package/dist/security/scanner.d.ts +47 -0
  22. package/dist/security/scanner.d.ts.map +1 -0
  23. package/dist/security/scanner.js +150 -0
  24. package/dist/security/scanner.js.map +1 -0
  25. package/dist/security/types.d.ts +47 -0
  26. package/dist/security/types.d.ts.map +1 -0
  27. package/dist/security/types.js +23 -0
  28. package/dist/security/types.js.map +1 -0
  29. package/dist/storage/buffer.d.ts +64 -0
  30. package/dist/storage/buffer.d.ts.map +1 -0
  31. package/dist/storage/buffer.js +120 -0
  32. package/dist/storage/buffer.js.map +1 -0
  33. package/dist/storage/duckdb-local-writer.d.ts +26 -0
  34. package/dist/storage/duckdb-local-writer.d.ts.map +1 -0
  35. package/dist/storage/duckdb-local-writer.js +454 -0
  36. package/dist/storage/duckdb-local-writer.js.map +1 -0
  37. package/dist/storage/mysql-writer.d.ts +55 -0
  38. package/dist/storage/mysql-writer.d.ts.map +1 -0
  39. package/dist/storage/mysql-writer.js +287 -0
  40. package/dist/storage/mysql-writer.js.map +1 -0
  41. package/dist/storage/schema.d.ts +13 -0
  42. package/dist/storage/schema.d.ts.map +1 -0
  43. package/dist/storage/schema.js +94 -0
  44. package/dist/storage/schema.js.map +1 -0
  45. package/dist/storage/writer.d.ts +31 -0
  46. package/dist/storage/writer.d.ts.map +1 -0
  47. package/dist/storage/writer.js +7 -0
  48. package/dist/storage/writer.js.map +1 -0
  49. package/dist/types.d.ts +72 -0
  50. package/dist/types.d.ts.map +1 -0
  51. package/dist/types.js +44 -0
  52. package/dist/types.js.map +1 -0
  53. package/dist/web/api.d.ts +115 -0
  54. package/dist/web/api.d.ts.map +1 -0
  55. package/dist/web/api.js +219 -0
  56. package/dist/web/api.js.map +1 -0
  57. package/dist/web/routes.d.ts +20 -0
  58. package/dist/web/routes.d.ts.map +1 -0
  59. package/dist/web/routes.js +175 -0
  60. package/dist/web/routes.js.map +1 -0
  61. package/dist/web/ui.d.ts +9 -0
  62. package/dist/web/ui.d.ts.map +1 -0
  63. package/dist/web/ui.js +1327 -0
  64. package/dist/web/ui.js.map +1 -0
  65. package/openclaw.plugin.json +231 -0
  66. package/package.json +41 -0
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Audit Web API — query database and return structured data
3
+ * Compatible with both MySQL and DuckDB backends
4
+ */
5
+ import { QueryPool } from '../storage/writer';
6
+ export interface StatsResult {
7
+ totalSessions: number;
8
+ totalActions: number;
9
+ totalTokens: number;
10
+ avgLatencyMs: number;
11
+ successRate: number;
12
+ actionTypeCounts: Record<string, number>;
13
+ }
14
+ export interface SessionRow {
15
+ session_id: string;
16
+ user_id: string;
17
+ model_name: string;
18
+ start_time: string;
19
+ end_time: string | null;
20
+ total_actions: number;
21
+ total_tokens: number;
22
+ }
23
+ export interface ActionRow {
24
+ id: number;
25
+ session_id: string;
26
+ action_type: string;
27
+ action_name: string;
28
+ model_name: string;
29
+ input_params: string | null;
30
+ output_result: string | null;
31
+ prompt_tokens: number | null;
32
+ completion_tokens: number | null;
33
+ duration_ms: number | null;
34
+ user_id: string;
35
+ created_at: string;
36
+ }
37
+ /** Get summary statistics */
38
+ export declare function getStats(pool: QueryPool): Promise<StatsResult>;
39
+ /** Get session list */
40
+ export declare function getSessions(pool: QueryPool, params: {
41
+ page?: number;
42
+ limit?: number;
43
+ userId?: string;
44
+ model?: string;
45
+ sessionId?: string;
46
+ search?: string;
47
+ timeFrom?: string;
48
+ timeTo?: string;
49
+ }): Promise<{
50
+ sessions: SessionRow[];
51
+ total: number;
52
+ }>;
53
+ /** Get actions for a session (supports field selection and limit) */
54
+ export declare function getSessionActions(pool: QueryPool, sessionId: string, options?: {
55
+ fields?: string;
56
+ limit?: number;
57
+ }): Promise<ActionRow[]>;
58
+ /** Get action list */
59
+ export declare function getActions(pool: QueryPool, params: {
60
+ page?: number;
61
+ limit?: number;
62
+ actionType?: string;
63
+ sessionId?: string;
64
+ }): Promise<{
65
+ actions: ActionRow[];
66
+ total: number;
67
+ }>;
68
+ export interface AlertRow {
69
+ id: number;
70
+ alert_id: string;
71
+ session_id: string;
72
+ action_type: string;
73
+ action_name: string;
74
+ rule_id: string;
75
+ rule_name: string;
76
+ category: string;
77
+ severity: string;
78
+ finding: string;
79
+ context: string;
80
+ status: string;
81
+ resolved_by: string | null;
82
+ resolved_at: string | null;
83
+ user_id: string;
84
+ model_name: string;
85
+ created_at: string;
86
+ }
87
+ /** Get security alert list */
88
+ export declare function getAlerts(pool: QueryPool, params: {
89
+ page?: number;
90
+ limit?: number;
91
+ severity?: string;
92
+ category?: string;
93
+ status?: string;
94
+ sessionId?: string;
95
+ ruleId?: string;
96
+ search?: string;
97
+ timeFrom?: string;
98
+ timeTo?: string;
99
+ }): Promise<{
100
+ alerts: AlertRow[];
101
+ total: number;
102
+ }>;
103
+ /** Get security alert statistics */
104
+ export declare function getAlertStats(pool: QueryPool): Promise<{
105
+ total: number;
106
+ bySeverity: Record<string, number>;
107
+ byCategory: Record<string, number>;
108
+ byStatus: Record<string, number>;
109
+ recent24h: number;
110
+ }>;
111
+ /** Update alert status */
112
+ export declare function updateAlertStatus(pool: QueryPool, alertId: string, status: string, resolvedBy?: string): Promise<boolean>;
113
+ /** Get alerts for a session */
114
+ export declare function getSessionAlerts(pool: QueryPool, sessionId: string): Promise<AlertRow[]>;
115
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/web/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,219 @@
1
+ "use strict";
2
+ /**
3
+ * Audit Web API — query database and return structured data
4
+ * Compatible with both MySQL and DuckDB backends
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.getStats = getStats;
8
+ exports.getSessions = getSessions;
9
+ exports.getSessionActions = getSessionActions;
10
+ exports.getActions = getActions;
11
+ exports.getAlerts = getAlerts;
12
+ exports.getAlertStats = getAlertStats;
13
+ exports.updateAlertStatus = updateAlertStatus;
14
+ exports.getSessionAlerts = getSessionAlerts;
15
+ /* ------------------------------------------------------------------ */
16
+ /* API functions */
17
+ /* ------------------------------------------------------------------ */
18
+ /** Get summary statistics */
19
+ async function getStats(pool) {
20
+ const [sessionRows] = await pool.query('SELECT COUNT(*) as cnt FROM audit_sessions');
21
+ const [actionRows] = await pool.query(`SELECT COUNT(*) as cnt,
22
+ COALESCE(SUM(COALESCE(prompt_tokens,0) + COALESCE(completion_tokens,0)), 0) as tokens,
23
+ COALESCE(AVG(NULLIF(duration_ms, 0)), 0) as avg_latency
24
+ FROM audit_actions`);
25
+ const [successRows] = await pool.query(`SELECT COUNT(*) as cnt FROM audit_actions
26
+ WHERE action_type = 'agent_end' AND output_result LIKE '%"success":true%'`);
27
+ const [totalEndRows] = await pool.query(`SELECT COUNT(*) as cnt FROM audit_actions WHERE action_type = 'agent_end'`);
28
+ // Count by action_type
29
+ const [typeCounts] = await pool.query('SELECT action_type, COUNT(*) as cnt FROM audit_actions GROUP BY action_type ORDER BY cnt DESC');
30
+ const actionTypeCounts = {};
31
+ for (const row of typeCounts) {
32
+ actionTypeCounts[row.action_type] = Number(row.cnt);
33
+ }
34
+ const totalEnd = Number(totalEndRows[0]?.cnt ?? 0);
35
+ return {
36
+ totalSessions: Number(sessionRows[0]?.cnt ?? 0),
37
+ totalActions: Number(actionRows[0]?.cnt ?? 0),
38
+ totalTokens: Number(actionRows[0]?.tokens ?? 0),
39
+ avgLatencyMs: Math.round(Number(actionRows[0]?.avg_latency ?? 0)),
40
+ successRate: totalEnd > 0
41
+ ? Math.round(Number(successRows[0]?.cnt ?? 0) / totalEnd * 100)
42
+ : 100,
43
+ actionTypeCounts,
44
+ };
45
+ }
46
+ /** Get session list */
47
+ async function getSessions(pool, params) {
48
+ const page = params.page || 1;
49
+ const limit = Math.min(params.limit || 20, 100);
50
+ const offset = (page - 1) * limit;
51
+ let where = '1=1';
52
+ const values = [];
53
+ if (params.sessionId) {
54
+ where += ' AND session_id = ?';
55
+ values.push(params.sessionId);
56
+ }
57
+ if (params.userId) {
58
+ where += ' AND user_id = ?';
59
+ values.push(params.userId);
60
+ }
61
+ if (params.model) {
62
+ where += ' AND model_name LIKE ?';
63
+ values.push('%' + params.model + '%');
64
+ }
65
+ // Full-text search: search session metadata first, then action content (input_params / output_result)
66
+ if (params.search) {
67
+ const like = '%' + params.search + '%';
68
+ where += ` AND (
69
+ session_id LIKE ? OR user_id LIKE ? OR model_name LIKE ?
70
+ OR session_id IN (
71
+ SELECT DISTINCT session_id FROM audit_actions
72
+ WHERE input_params LIKE ? OR output_result LIKE ? OR action_name LIKE ?
73
+ )
74
+ )`;
75
+ values.push(like, like, like, like, like, like);
76
+ }
77
+ // Time range filter
78
+ if (params.timeFrom) {
79
+ where += ' AND start_time >= ?';
80
+ values.push(params.timeFrom);
81
+ }
82
+ if (params.timeTo) {
83
+ where += ' AND start_time <= ?';
84
+ values.push(params.timeTo);
85
+ }
86
+ const [countRows] = await pool.query('SELECT COUNT(*) as cnt FROM audit_sessions WHERE ' + where, values);
87
+ const [rows] = await pool.query('SELECT * FROM audit_sessions WHERE ' + where + ' ORDER BY start_time DESC LIMIT ? OFFSET ?', [...values, limit, offset]);
88
+ return {
89
+ sessions: rows,
90
+ total: Number(countRows[0]?.cnt ?? 0),
91
+ };
92
+ }
93
+ /** Get actions for a session (supports field selection and limit) */
94
+ async function getSessionActions(pool, sessionId, options) {
95
+ // If fields=action_type, return only minimal fields (for mini trace)
96
+ const selectCols = options?.fields === 'action_type'
97
+ ? 'action_type, created_at'
98
+ : '*';
99
+ const limitClause = options?.limit ? ` LIMIT ${Math.min(options.limit, 1000)}` : '';
100
+ const [rows] = await pool.query(`SELECT ${selectCols} FROM audit_actions WHERE session_id = ? ORDER BY created_at ASC, id ASC${limitClause}`, [sessionId]);
101
+ return rows;
102
+ }
103
+ /** Get action list */
104
+ async function getActions(pool, params) {
105
+ const page = params.page || 1;
106
+ const limit = Math.min(params.limit || 50, 200);
107
+ const offset = (page - 1) * limit;
108
+ let where = '1=1';
109
+ const values = [];
110
+ if (params.actionType) {
111
+ where += ' AND action_type = ?';
112
+ values.push(params.actionType);
113
+ }
114
+ if (params.sessionId) {
115
+ where += ' AND session_id = ?';
116
+ values.push(params.sessionId);
117
+ }
118
+ const [countRows] = await pool.query('SELECT COUNT(*) as cnt FROM audit_actions WHERE ' + where, values);
119
+ const [rows] = await pool.query('SELECT * FROM audit_actions WHERE ' + where + ' ORDER BY created_at DESC, id DESC LIMIT ? OFFSET ?', [...values, limit, offset]);
120
+ return {
121
+ actions: rows,
122
+ total: Number(countRows[0]?.cnt ?? 0),
123
+ };
124
+ }
125
+ /** Get security alert list */
126
+ async function getAlerts(pool, params) {
127
+ const page = params.page || 1;
128
+ const limit = Math.min(params.limit || 20, 100);
129
+ const offset = (page - 1) * limit;
130
+ let where = '1=1';
131
+ const values = [];
132
+ if (params.severity) {
133
+ where += ' AND severity = ?';
134
+ values.push(params.severity);
135
+ }
136
+ if (params.category) {
137
+ where += ' AND category = ?';
138
+ values.push(params.category);
139
+ }
140
+ if (params.status) {
141
+ where += ' AND status = ?';
142
+ values.push(params.status);
143
+ }
144
+ if (params.sessionId) {
145
+ where += ' AND session_id = ?';
146
+ values.push(params.sessionId);
147
+ }
148
+ if (params.ruleId) {
149
+ where += ' AND rule_id = ?';
150
+ values.push(params.ruleId);
151
+ }
152
+ // Full-text search across alert fields
153
+ if (params.search) {
154
+ const like = '%' + params.search + '%';
155
+ where += ` AND (
156
+ rule_name LIKE ? OR rule_id LIKE ? OR finding LIKE ?
157
+ OR session_id LIKE ? OR action_name LIKE ? OR context LIKE ?
158
+ )`;
159
+ values.push(like, like, like, like, like, like);
160
+ }
161
+ if (params.timeFrom) {
162
+ where += ' AND created_at >= ?';
163
+ values.push(params.timeFrom);
164
+ }
165
+ if (params.timeTo) {
166
+ where += ' AND created_at <= ?';
167
+ values.push(params.timeTo);
168
+ }
169
+ const [countRows] = await pool.query('SELECT COUNT(*) as cnt FROM audit_alerts WHERE ' + where, values);
170
+ const [rows] = await pool.query('SELECT * FROM audit_alerts WHERE ' + where + ' ORDER BY created_at DESC LIMIT ? OFFSET ?', [...values, limit, offset]);
171
+ return {
172
+ alerts: rows,
173
+ total: Number(countRows[0]?.cnt ?? 0),
174
+ };
175
+ }
176
+ /** Get security alert statistics */
177
+ async function getAlertStats(pool) {
178
+ const [totalRows] = await pool.query('SELECT COUNT(*) as cnt FROM audit_alerts');
179
+ const [sevRows] = await pool.query('SELECT severity, COUNT(*) as cnt FROM audit_alerts GROUP BY severity');
180
+ const [catRows] = await pool.query('SELECT category, COUNT(*) as cnt FROM audit_alerts GROUP BY category');
181
+ const [statusRows] = await pool.query('SELECT status, COUNT(*) as cnt FROM audit_alerts GROUP BY status');
182
+ // NOW() - INTERVAL 24 HOUR compatible with MySQL and DuckDB
183
+ const [recentRows] = await pool.query('SELECT COUNT(*) as cnt FROM audit_alerts WHERE created_at >= (NOW() - INTERVAL 24 HOUR)');
184
+ const bySeverity = {};
185
+ for (const r of sevRows)
186
+ bySeverity[r.severity] = Number(r.cnt);
187
+ const byCategory = {};
188
+ for (const r of catRows)
189
+ byCategory[r.category] = Number(r.cnt);
190
+ const byStatus = {};
191
+ for (const r of statusRows)
192
+ byStatus[r.status] = Number(r.cnt);
193
+ return {
194
+ total: Number(totalRows[0]?.cnt ?? 0),
195
+ bySeverity,
196
+ byCategory,
197
+ byStatus,
198
+ recent24h: Number(recentRows[0]?.cnt ?? 0),
199
+ };
200
+ }
201
+ /** Update alert status */
202
+ async function updateAlertStatus(pool, alertId, status, resolvedBy) {
203
+ const validStatuses = ['open', 'acknowledged', 'resolved', 'false_positive'];
204
+ if (!validStatuses.includes(status))
205
+ return false;
206
+ const resolvedAt = (status === 'resolved' || status === 'false_positive')
207
+ ? new Date().toISOString().replace('T', ' ').slice(0, 19) // compatible with MySQL & DuckDB
208
+ : null;
209
+ await pool.query(`UPDATE audit_alerts SET status = ?, resolved_by = ?, resolved_at = ? WHERE alert_id = ?`, [status, resolvedBy || null, resolvedAt, alertId]);
210
+ // Verify update result (compatible with MySQL and DuckDB, not relying on affectedRows)
211
+ const [rows] = await pool.query('SELECT 1 FROM audit_alerts WHERE alert_id = ? AND status = ?', [alertId, status]);
212
+ return rows.length > 0;
213
+ }
214
+ /** Get alerts for a session */
215
+ async function getSessionAlerts(pool, sessionId) {
216
+ const [rows] = await pool.query('SELECT * FROM audit_alerts WHERE session_id = ? ORDER BY created_at ASC', [sessionId]);
217
+ return rows;
218
+ }
219
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/web/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Audit panel HTTP route registration
3
+ * Mounts API and UI pages on the OpenClaw Gateway
4
+ */
5
+ import { IncomingMessage, ServerResponse } from 'node:http';
6
+ import { AuditWriter } from '../storage/writer';
7
+ export interface RegisterHttpRoute {
8
+ (params: {
9
+ path: string;
10
+ handler: (req: IncomingMessage, res: ServerResponse) => Promise<boolean | void> | boolean | void;
11
+ auth: 'gateway' | 'plugin';
12
+ match?: 'exact' | 'prefix';
13
+ replaceExisting?: boolean;
14
+ }): void;
15
+ }
16
+ /**
17
+ * Register all audit panel HTTP routes
18
+ */
19
+ export declare function registerAuditRoutes(registerHttpRoute: RegisterHttpRoute, writer: AuditWriter): void;
20
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/web/routes.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG5D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMhD,MAAM,WAAW,iBAAiB;IAChC,CAAC,MAAM,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC;QACjG,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;QAC3B,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;QAC3B,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,GAAG,IAAI,CAAC;CACV;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,iBAAiB,EAAE,iBAAiB,EACpC,MAAM,EAAE,WAAW,GAClB,IAAI,CAuIN"}
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ /**
3
+ * Audit panel HTTP route registration
4
+ * Mounts API and UI pages on the OpenClaw Gateway
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.registerAuditRoutes = registerAuditRoutes;
8
+ const api_1 = require("./api");
9
+ const ui_1 = require("./ui");
10
+ /**
11
+ * Register all audit panel HTTP routes
12
+ */
13
+ function registerAuditRoutes(registerHttpRoute, writer) {
14
+ // Single prefix route handles all requests
15
+ registerHttpRoute({
16
+ path: '/plugins/audit',
17
+ handler: async (req, res) => {
18
+ try {
19
+ const url = parseUrl(req);
20
+ const path = url.pathname;
21
+ // Non-API paths return UI HTML directly (no database needed)
22
+ if (!path.startsWith('/plugins/audit/api/')) {
23
+ sendHtml(res, (0, ui_1.getAppHtml)());
24
+ return;
25
+ }
26
+ // API paths require database, attempt lazy initialization
27
+ await writer.ensureReady();
28
+ const pool = writer.getPool();
29
+ if (!pool) {
30
+ sendJson(res, 503, { error: 'Database not ready — will retry automatically' });
31
+ return;
32
+ }
33
+ // ---------- API routes ----------
34
+ // GET /plugins/audit/api/stats
35
+ if (path === '/plugins/audit/api/stats') {
36
+ const stats = await (0, api_1.getStats)(pool);
37
+ sendJson(res, 200, stats);
38
+ return;
39
+ }
40
+ // GET /plugins/audit/api/sessions
41
+ if (path === '/plugins/audit/api/sessions') {
42
+ const page = intParam(url, 'page', 1);
43
+ const limit = intParam(url, 'limit', 20);
44
+ const userId = url.searchParams.get('user_id') || undefined;
45
+ const model = url.searchParams.get('model') || undefined;
46
+ const sessionId = url.searchParams.get('sessionId') || undefined;
47
+ const search = url.searchParams.get('search') || undefined;
48
+ const timeFrom = url.searchParams.get('timeFrom') || undefined;
49
+ const timeTo = url.searchParams.get('timeTo') || undefined;
50
+ const result = await (0, api_1.getSessions)(pool, { page, limit, userId, model, sessionId, search, timeFrom, timeTo });
51
+ sendJson(res, 200, result);
52
+ return;
53
+ }
54
+ // GET /plugins/audit/api/sessions/:id/actions
55
+ const sessionActionsMatch = path.match(/^\/plugins\/audit\/api\/sessions\/([^/]+)\/actions$/);
56
+ if (sessionActionsMatch) {
57
+ const sessionId = decodeURIComponent(sessionActionsMatch[1]);
58
+ const fields = url.searchParams.get('fields') || undefined;
59
+ const limitParam = url.searchParams.get('limit');
60
+ const limit = limitParam ? parseInt(limitParam, 10) : undefined;
61
+ const actions = await (0, api_1.getSessionActions)(pool, sessionId, { fields, limit });
62
+ sendJson(res, 200, { actions });
63
+ return;
64
+ }
65
+ // GET /plugins/audit/api/actions
66
+ if (path === '/plugins/audit/api/actions') {
67
+ const page = intParam(url, 'page', 1);
68
+ const limit = intParam(url, 'limit', 50);
69
+ const actionType = url.searchParams.get('action_type') || undefined;
70
+ const sessionId = url.searchParams.get('session_id') || undefined;
71
+ const result = await (0, api_1.getActions)(pool, { page, limit, actionType, sessionId });
72
+ sendJson(res, 200, result);
73
+ return;
74
+ }
75
+ // ---------- Security Alert API routes ----------
76
+ // GET /plugins/audit/api/alerts/stats
77
+ if (path === '/plugins/audit/api/alerts/stats') {
78
+ const stats = await (0, api_1.getAlertStats)(pool);
79
+ sendJson(res, 200, stats);
80
+ return;
81
+ }
82
+ // GET /plugins/audit/api/alerts
83
+ if (path === '/plugins/audit/api/alerts') {
84
+ const page = intParam(url, 'page', 1);
85
+ const limit = intParam(url, 'limit', 20);
86
+ const severity = url.searchParams.get('severity') || undefined;
87
+ const category = url.searchParams.get('category') || undefined;
88
+ const status = url.searchParams.get('status') || undefined;
89
+ const sessionId = url.searchParams.get('session_id') || undefined;
90
+ const ruleId = url.searchParams.get('rule_id') || undefined;
91
+ const search = url.searchParams.get('search') || undefined;
92
+ const timeFrom = url.searchParams.get('timeFrom') || undefined;
93
+ const timeTo = url.searchParams.get('timeTo') || undefined;
94
+ const result = await (0, api_1.getAlerts)(pool, { page, limit, severity, category, status, sessionId, ruleId, search, timeFrom, timeTo });
95
+ sendJson(res, 200, result);
96
+ return;
97
+ }
98
+ // POST /plugins/audit/api/alerts/:id/status
99
+ const alertStatusMatch = path.match(/^\/plugins\/audit\/api\/alerts\/([^/]+)\/status$/);
100
+ if (alertStatusMatch && req.method === 'POST') {
101
+ const alertId = decodeURIComponent(alertStatusMatch[1]);
102
+ // Read POST body
103
+ const body = await readBody(req);
104
+ const { status: newStatus, resolvedBy } = JSON.parse(body);
105
+ const ok = await (0, api_1.updateAlertStatus)(pool, alertId, newStatus, resolvedBy);
106
+ sendJson(res, ok ? 200 : 404, { success: ok });
107
+ return;
108
+ }
109
+ // GET /plugins/audit/api/sessions/:id/alerts
110
+ const sessionAlertsMatch = path.match(/^\/plugins\/audit\/api\/sessions\/([^/]+)\/alerts$/);
111
+ if (sessionAlertsMatch) {
112
+ const sessionId = decodeURIComponent(sessionAlertsMatch[1]);
113
+ const alerts = await (0, api_1.getSessionAlerts)(pool, sessionId);
114
+ sendJson(res, 200, { alerts });
115
+ return;
116
+ }
117
+ // No matching API route
118
+ sendJson(res, 404, { error: 'Not found' });
119
+ }
120
+ catch (err) {
121
+ console.error('[audit-duckdb] HTTP handler error:', err);
122
+ sendJson(res, 500, { error: String(err) });
123
+ }
124
+ },
125
+ auth: 'plugin',
126
+ match: 'prefix',
127
+ });
128
+ console.log('[audit-duckdb] Audit UI registered at /plugins/audit/');
129
+ }
130
+ /* ------------------------------------------------------------------ */
131
+ /* Helpers */
132
+ /* ------------------------------------------------------------------ */
133
+ function parseUrl(req) {
134
+ return new URL(req.url || '/', 'http://' + (req.headers.host || 'localhost'));
135
+ }
136
+ function intParam(url, name, defaultVal) {
137
+ const v = url.searchParams.get(name);
138
+ if (!v)
139
+ return defaultVal;
140
+ const n = parseInt(v, 10);
141
+ return isNaN(n) ? defaultVal : n;
142
+ }
143
+ function sendJson(res, status, data) {
144
+ res.writeHead(status, {
145
+ 'Content-Type': 'application/json; charset=utf-8',
146
+ 'Cache-Control': 'no-cache',
147
+ });
148
+ res.end(JSON.stringify(data));
149
+ }
150
+ function sendHtml(res, html) {
151
+ res.writeHead(200, {
152
+ 'Content-Type': 'text/html; charset=utf-8',
153
+ 'Cache-Control': 'no-cache',
154
+ });
155
+ res.end(html);
156
+ }
157
+ /** Read request body with max size limit to prevent DoS */
158
+ function readBody(req, maxBytes = 1024 * 64 /* 64KB */) {
159
+ return new Promise((resolve, reject) => {
160
+ let data = '';
161
+ let bytes = 0;
162
+ req.on('data', (chunk) => {
163
+ bytes += chunk.length;
164
+ if (bytes > maxBytes) {
165
+ req.destroy();
166
+ reject(new Error(`Request body too large (max ${maxBytes} bytes)`));
167
+ return;
168
+ }
169
+ data += chunk.toString();
170
+ });
171
+ req.on('end', () => resolve(data));
172
+ req.on('error', reject);
173
+ });
174
+ }
175
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/web/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Audit panel SPA — single-page HTML application
3
+ * Contains Dashboard overview + Session Trace detail views
4
+ * Uses hash routing: #/ = Dashboard, #/trace/{sessionId} = Trace
5
+ *
6
+ * Fully aligned with OpenClaw Control design system (CSS variables + dark/light themes)
7
+ */
8
+ export declare function getAppHtml(): string;
9
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,wBAAgB,UAAU,IAAI,MAAM,CAmBnC"}