@webda/debug 4.0.0-beta.3
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/LICENSE +166 -0
- package/README.md +95 -0
- package/lib/bodycapture.d.ts +66 -0
- package/lib/bodycapture.js +162 -0
- package/lib/bodycapture.js.map +1 -0
- package/lib/debugservice.service.d.ts +166 -0
- package/lib/debugservice.service.js +609 -0
- package/lib/debugservice.service.js.map +1 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +7 -0
- package/lib/index.js.map +1 -0
- package/lib/introspection.d.ts +115 -0
- package/lib/introspection.js +260 -0
- package/lib/introspection.js.map +1 -0
- package/lib/logbuffer.d.ts +75 -0
- package/lib/logbuffer.js +98 -0
- package/lib/logbuffer.js.map +1 -0
- package/lib/requestlog.d.ts +181 -0
- package/lib/requestlog.js +153 -0
- package/lib/requestlog.js.map +1 -0
- package/lib/tui/client.d.ts +165 -0
- package/lib/tui/client.js +220 -0
- package/lib/tui/client.js.map +1 -0
- package/lib/tui/panels/config.d.ts +79 -0
- package/lib/tui/panels/config.js +291 -0
- package/lib/tui/panels/config.js.map +1 -0
- package/lib/tui/panels/logs.d.ts +106 -0
- package/lib/tui/panels/logs.js +342 -0
- package/lib/tui/panels/logs.js.map +1 -0
- package/lib/tui/panels/models.d.ts +47 -0
- package/lib/tui/panels/models.js +193 -0
- package/lib/tui/panels/models.js.map +1 -0
- package/lib/tui/panels/operations.d.ts +55 -0
- package/lib/tui/panels/operations.js +241 -0
- package/lib/tui/panels/operations.js.map +1 -0
- package/lib/tui/panels/panel.d.ts +55 -0
- package/lib/tui/panels/panel.js +31 -0
- package/lib/tui/panels/panel.js.map +1 -0
- package/lib/tui/panels/requests.d.ts +156 -0
- package/lib/tui/panels/requests.js +512 -0
- package/lib/tui/panels/requests.js.map +1 -0
- package/lib/tui/panels/routes.d.ts +45 -0
- package/lib/tui/panels/routes.js +154 -0
- package/lib/tui/panels/routes.js.map +1 -0
- package/lib/tui/panels/services.d.ts +49 -0
- package/lib/tui/panels/services.js +266 -0
- package/lib/tui/panels/services.js.map +1 -0
- package/lib/tui/tui.d.ts +58 -0
- package/lib/tui/tui.js +236 -0
- package/lib/tui/tui.js.map +1 -0
- package/package.json +60 -0
- package/webui/app.js +177 -0
- package/webui/components/logs.js +128 -0
- package/webui/components/model-graph.js +292 -0
- package/webui/components/models.js +213 -0
- package/webui/components/operations.js +315 -0
- package/webui/components/requests.js +264 -0
- package/webui/components/schema-form.js +268 -0
- package/webui/components/services.js +248 -0
- package/webui/index.html +22 -0
- package/webui/logo.svg +1 -0
- package/webui/styles.css +685 -0
- package/webui/vendor/htm.js +1 -0
- package/webui/vendor/preact-hooks.js +2 -0
- package/webui/vendor/preact.js +2 -0
- package/webui/webda.png +0 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Information about a registered model.
|
|
3
|
+
*/
|
|
4
|
+
export interface ModelInfo {
|
|
5
|
+
/** Fully-qualified model identifier, e.g. "MyApp/Task" */
|
|
6
|
+
id: string;
|
|
7
|
+
/** Plural name used in REST URLs, e.g. "Tasks" */
|
|
8
|
+
plural: string;
|
|
9
|
+
/** List of action names defined on the model */
|
|
10
|
+
actions: string[];
|
|
11
|
+
/** Relation graph (links, queries, maps, binaries) */
|
|
12
|
+
relations: any;
|
|
13
|
+
/** Full raw ModelMetadata object */
|
|
14
|
+
metadata: any;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Information about a running service.
|
|
18
|
+
*/
|
|
19
|
+
export interface ServiceInfo {
|
|
20
|
+
/** Service registration name */
|
|
21
|
+
name: string;
|
|
22
|
+
/** Service type string (e.g. "Webda/Router") */
|
|
23
|
+
type: string;
|
|
24
|
+
/** Current lifecycle state (e.g. "running") */
|
|
25
|
+
state: string;
|
|
26
|
+
/** Capabilities advertised by the service */
|
|
27
|
+
capabilities: Record<string, any>;
|
|
28
|
+
/** Service configuration parameters */
|
|
29
|
+
configuration: Record<string, any>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Information about a registered operation.
|
|
33
|
+
*/
|
|
34
|
+
export interface OperationInfo {
|
|
35
|
+
/** Operation identifier, e.g. "Task.Create" */
|
|
36
|
+
id: string;
|
|
37
|
+
/** Input schema identifier. "void" means no input. */
|
|
38
|
+
input: string;
|
|
39
|
+
/** Output schema identifier. "void" means no output. */
|
|
40
|
+
output: string;
|
|
41
|
+
/** Parameters schema identifier, if any */
|
|
42
|
+
parameters?: string;
|
|
43
|
+
/** Additional fields from the operation definition */
|
|
44
|
+
[key: string]: any;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Information about a single route entry.
|
|
48
|
+
*/
|
|
49
|
+
export interface RouteInfoEntry {
|
|
50
|
+
/** URL path pattern, e.g. "/tasks/{uuid}" */
|
|
51
|
+
path: string;
|
|
52
|
+
/** HTTP methods accepted by this route, e.g. ["GET","POST"] */
|
|
53
|
+
methods: string[];
|
|
54
|
+
/** Name of the executor service */
|
|
55
|
+
executor: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Returns introspection data for all models registered in the application.
|
|
59
|
+
*
|
|
60
|
+
* Each entry contains the model identifier, plural name, action names, relation
|
|
61
|
+
* graph, and the full raw ModelMetadata object.
|
|
62
|
+
*
|
|
63
|
+
* @returns Array of {@link ModelInfo} objects, one per registered model.
|
|
64
|
+
*/
|
|
65
|
+
export declare function getModels(): ModelInfo[];
|
|
66
|
+
/**
|
|
67
|
+
* Returns introspection data for a single model by its identifier.
|
|
68
|
+
*
|
|
69
|
+
* @param id - Fully-qualified model identifier, e.g. "MyApp/Task".
|
|
70
|
+
* @returns The matching {@link ModelInfo}, or `undefined` if not found.
|
|
71
|
+
*/
|
|
72
|
+
export declare function getModel(id: string): ModelInfo | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Returns introspection data for all services currently registered with Core.
|
|
75
|
+
*
|
|
76
|
+
* Null / undefined service slots are filtered out before mapping.
|
|
77
|
+
*
|
|
78
|
+
* @returns Array of {@link ServiceInfo} objects, one per registered service.
|
|
79
|
+
*/
|
|
80
|
+
export declare function getServices(): ServiceInfo[];
|
|
81
|
+
/**
|
|
82
|
+
* Returns introspection data for all operations registered in the instance storage.
|
|
83
|
+
*
|
|
84
|
+
* The `service` and `method` internal fields are omitted by {@link listOperations};
|
|
85
|
+
* each entry gets a synthetic `id` field added.
|
|
86
|
+
*
|
|
87
|
+
* @returns Array of {@link OperationInfo} objects.
|
|
88
|
+
*/
|
|
89
|
+
export declare function getOperations(): OperationInfo[];
|
|
90
|
+
/**
|
|
91
|
+
* Returns introspection data for all routes registered with the Router service.
|
|
92
|
+
*
|
|
93
|
+
* A single path can have multiple route entries (one per executor / method set);
|
|
94
|
+
* each is returned as a separate {@link RouteInfoEntry}.
|
|
95
|
+
*
|
|
96
|
+
* @returns Array of {@link RouteInfoEntry} objects.
|
|
97
|
+
*/
|
|
98
|
+
export declare function getRoutes(): RouteInfoEntry[];
|
|
99
|
+
/**
|
|
100
|
+
* Returns the active application configuration object.
|
|
101
|
+
*
|
|
102
|
+
* This is the merged configuration (global + deployment overrides) that the
|
|
103
|
+
* running application was started with.
|
|
104
|
+
*
|
|
105
|
+
* @returns Plain configuration record.
|
|
106
|
+
*/
|
|
107
|
+
export declare function getConfig(): Record<string, any>;
|
|
108
|
+
/**
|
|
109
|
+
* Returns project information including package.json data, git info, and deployment details.
|
|
110
|
+
*
|
|
111
|
+
* Adds the current working directory to the result.
|
|
112
|
+
*
|
|
113
|
+
* @returns Project information or a minimal fallback from package.json.
|
|
114
|
+
*/
|
|
115
|
+
export declare function getAppInfo(): Record<string, any>;
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { useApplication, useCore, useRouter, listFullOperations, useModelMetadata } from "@webda/core";
|
|
2
|
+
/**
|
|
3
|
+
* Returns introspection data for all models registered in the application.
|
|
4
|
+
*
|
|
5
|
+
* Each entry contains the model identifier, plural name, action names, relation
|
|
6
|
+
* graph, and the full raw ModelMetadata object.
|
|
7
|
+
*
|
|
8
|
+
* @returns Array of {@link ModelInfo} objects, one per registered model.
|
|
9
|
+
*/
|
|
10
|
+
export function getModels() {
|
|
11
|
+
const app = useApplication();
|
|
12
|
+
const core = useCore();
|
|
13
|
+
const models = app.getModels();
|
|
14
|
+
return Object.entries(models).map(([key, model]) => {
|
|
15
|
+
const metadata = useModelMetadata(model);
|
|
16
|
+
let storeName;
|
|
17
|
+
let storeType;
|
|
18
|
+
try {
|
|
19
|
+
const store = core.getModelStore(model);
|
|
20
|
+
if (store) {
|
|
21
|
+
storeName = store.getName();
|
|
22
|
+
storeType = store.constructor?.name;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// No store assigned
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
id: metadata?.Identifier || key,
|
|
30
|
+
plural: metadata?.Plural || key,
|
|
31
|
+
actions: Object.keys(metadata?.Actions || {}),
|
|
32
|
+
relations: metadata?.Relations || {},
|
|
33
|
+
store: storeName,
|
|
34
|
+
storeType,
|
|
35
|
+
schemas: metadata?.Schemas,
|
|
36
|
+
metadata
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns introspection data for a single model by its identifier.
|
|
42
|
+
*
|
|
43
|
+
* @param id - Fully-qualified model identifier, e.g. "MyApp/Task".
|
|
44
|
+
* @returns The matching {@link ModelInfo}, or `undefined` if not found.
|
|
45
|
+
*/
|
|
46
|
+
export function getModel(id) {
|
|
47
|
+
return getModels().find(m => m.id === id);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Returns introspection data for all services currently registered with Core.
|
|
51
|
+
*
|
|
52
|
+
* Null / undefined service slots are filtered out before mapping.
|
|
53
|
+
*
|
|
54
|
+
* @returns Array of {@link ServiceInfo} objects, one per registered service.
|
|
55
|
+
*/
|
|
56
|
+
export function getServices() {
|
|
57
|
+
const core = useCore();
|
|
58
|
+
const app = useApplication();
|
|
59
|
+
const services = core.getServices();
|
|
60
|
+
const config = core.getConfiguration?.() || {};
|
|
61
|
+
return Object.entries(services)
|
|
62
|
+
.filter(([, svc]) => svc != null)
|
|
63
|
+
.map(([name, svc]) => {
|
|
64
|
+
const type = svc.parameters?.type || "unknown";
|
|
65
|
+
// Collect metric definitions and current values from the service's metrics object
|
|
66
|
+
const metricsInfo = [];
|
|
67
|
+
const metricsObj = svc.metrics;
|
|
68
|
+
if (metricsObj && typeof metricsObj === "object") {
|
|
69
|
+
for (const [key, metric] of Object.entries(metricsObj)) {
|
|
70
|
+
if (!metric || typeof metric !== "object")
|
|
71
|
+
continue;
|
|
72
|
+
const m = metric;
|
|
73
|
+
try {
|
|
74
|
+
const values = m.hashMap ? Object.values(m.hashMap).map((v) => ({
|
|
75
|
+
value: v.value,
|
|
76
|
+
labels: v.labels
|
|
77
|
+
})) : [];
|
|
78
|
+
metricsInfo.push({
|
|
79
|
+
name: key,
|
|
80
|
+
fullName: m.name,
|
|
81
|
+
help: m.help,
|
|
82
|
+
type: m.constructor?.name?.toLowerCase() || "unknown",
|
|
83
|
+
labelNames: m.labelNames || [],
|
|
84
|
+
values
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Skip unreadable metrics
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
name,
|
|
94
|
+
type,
|
|
95
|
+
state: svc.getState(),
|
|
96
|
+
capabilities: svc.getCapabilities(),
|
|
97
|
+
configuration: config[name] || {},
|
|
98
|
+
schema: app.getSchema?.(app.completeNamespace(type)) || undefined,
|
|
99
|
+
metrics: metricsInfo.length > 0 ? metricsInfo : undefined
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Returns introspection data for all operations registered in the instance storage.
|
|
105
|
+
*
|
|
106
|
+
* The `service` and `method` internal fields are omitted by {@link listOperations};
|
|
107
|
+
* each entry gets a synthetic `id` field added.
|
|
108
|
+
*
|
|
109
|
+
* @returns Array of {@link OperationInfo} objects.
|
|
110
|
+
*/
|
|
111
|
+
export function getOperations() {
|
|
112
|
+
const ops = listFullOperations();
|
|
113
|
+
const app = useApplication();
|
|
114
|
+
const core = useCore();
|
|
115
|
+
// Build a map of operation ID → full route URL by scanning the router's openapi metadata
|
|
116
|
+
const operationRoutes = {};
|
|
117
|
+
try {
|
|
118
|
+
const router = useRouter();
|
|
119
|
+
const routes = router.getRoutes();
|
|
120
|
+
for (const [path, infos] of Object.entries(routes)) {
|
|
121
|
+
for (const info of infos) {
|
|
122
|
+
if (!info.openapi)
|
|
123
|
+
continue;
|
|
124
|
+
// One route can serve several verbs (PUT and PATCH), each with its own operation
|
|
125
|
+
for (const [method, methodDef] of Object.entries(info.openapi)) {
|
|
126
|
+
if (methodDef?.operationId) {
|
|
127
|
+
operationRoutes[methodDef.operationId] = { url: path, method: method.toLowerCase() };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// Router may not be available
|
|
135
|
+
}
|
|
136
|
+
return Object.entries(ops).map(([opId, def]) => {
|
|
137
|
+
const entry = { ...def, id: opId };
|
|
138
|
+
// Resolve input/output schema refs to actual JSON Schema objects
|
|
139
|
+
for (const key of ["input", "output"]) {
|
|
140
|
+
if (entry[key] && entry[key] !== "void") {
|
|
141
|
+
entry[`${key}Schema`] = app.getSchema?.(entry[key]) || undefined;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Enrich rest with full URL from router
|
|
145
|
+
const route = operationRoutes[opId];
|
|
146
|
+
if (route) {
|
|
147
|
+
entry.rest = { ...(typeof entry.rest === "object" ? entry.rest : {}), url: route.url, method: entry.rest?.method || route.method };
|
|
148
|
+
}
|
|
149
|
+
// Dedent: find the smallest leading whitespace (skipping the first line which
|
|
150
|
+
// Function.toString() always returns at column 0) and strip it from all lines
|
|
151
|
+
const dedent = (code) => {
|
|
152
|
+
const lines = code.split("\n");
|
|
153
|
+
if (lines.length <= 1)
|
|
154
|
+
return code;
|
|
155
|
+
// Compute min indent from lines 1+ (skip first line and empty lines)
|
|
156
|
+
const indents = lines.slice(1).filter(l => l.trim().length > 0).map(l => (l.match(/^(\s*)/) || ["", ""])[1].length);
|
|
157
|
+
if (indents.length === 0)
|
|
158
|
+
return code;
|
|
159
|
+
const min = Math.min(...indents);
|
|
160
|
+
if (min === 0)
|
|
161
|
+
return code;
|
|
162
|
+
return [lines[0], ...lines.slice(1).map(l => l.slice(min))].join("\n");
|
|
163
|
+
};
|
|
164
|
+
// Resolve implementor info
|
|
165
|
+
try {
|
|
166
|
+
if (def.service) {
|
|
167
|
+
const svc = core.getService(def.service);
|
|
168
|
+
entry.implementor = { type: "service", name: def.service };
|
|
169
|
+
if (svc && def.method) {
|
|
170
|
+
// For model actions, the real code is on the model prototype
|
|
171
|
+
const actionName = def.context?.action?.name;
|
|
172
|
+
const modelClass = def.context?.model;
|
|
173
|
+
if (actionName && modelClass?.prototype?.[actionName]) {
|
|
174
|
+
const fn = modelClass.prototype[actionName];
|
|
175
|
+
const modelId = modelClass.getIdentifier?.() || modelClass.name || def.service;
|
|
176
|
+
entry.implementor = { type: "model", name: modelId, method: actionName };
|
|
177
|
+
entry.implementor.code = dedent((fn.__original || fn).toString());
|
|
178
|
+
}
|
|
179
|
+
else if (typeof svc[def.method] === "function") {
|
|
180
|
+
entry.implementor.method = def.method;
|
|
181
|
+
const fn = svc[def.method];
|
|
182
|
+
entry.implementor.code = dedent((fn.__original || fn).toString());
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else if (def.model) {
|
|
187
|
+
const modelClass = app.getModel(def.model);
|
|
188
|
+
entry.implementor = { type: "model", name: def.model };
|
|
189
|
+
if (modelClass && def.method) {
|
|
190
|
+
const fn = modelClass.prototype?.[def.method] || modelClass[def.method];
|
|
191
|
+
if (typeof fn === "function") {
|
|
192
|
+
entry.implementor.method = def.method;
|
|
193
|
+
entry.implementor.code = dedent((fn.__original || fn).toString());
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
// Service/model may not be resolvable
|
|
200
|
+
}
|
|
201
|
+
// Strip internal fields not useful for the UI
|
|
202
|
+
delete entry.service;
|
|
203
|
+
delete entry.model;
|
|
204
|
+
delete entry.method;
|
|
205
|
+
delete entry.context;
|
|
206
|
+
delete entry.permissionQuery;
|
|
207
|
+
return entry;
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Returns introspection data for all routes registered with the Router service.
|
|
212
|
+
*
|
|
213
|
+
* A single path can have multiple route entries (one per executor / method set);
|
|
214
|
+
* each is returned as a separate {@link RouteInfoEntry}.
|
|
215
|
+
*
|
|
216
|
+
* @returns Array of {@link RouteInfoEntry} objects.
|
|
217
|
+
*/
|
|
218
|
+
export function getRoutes() {
|
|
219
|
+
const router = useRouter();
|
|
220
|
+
const routes = router.getRoutes();
|
|
221
|
+
const result = [];
|
|
222
|
+
for (const [path, infos] of Object.entries(routes)) {
|
|
223
|
+
for (const info of infos) {
|
|
224
|
+
result.push({ path, methods: info.methods, executor: info.executor });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Returns the active application configuration object.
|
|
231
|
+
*
|
|
232
|
+
* This is the merged configuration (global + deployment overrides) that the
|
|
233
|
+
* running application was started with.
|
|
234
|
+
*
|
|
235
|
+
* @returns Plain configuration record.
|
|
236
|
+
*/
|
|
237
|
+
export function getConfig() {
|
|
238
|
+
return useApplication().getConfiguration();
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Returns project information including package.json data, git info, and deployment details.
|
|
242
|
+
*
|
|
243
|
+
* Adds the current working directory to the result.
|
|
244
|
+
*
|
|
245
|
+
* @returns Project information or a minimal fallback from package.json.
|
|
246
|
+
*/
|
|
247
|
+
export function getAppInfo() {
|
|
248
|
+
const app = useApplication();
|
|
249
|
+
const projectInfo = app.getProjectInfo?.();
|
|
250
|
+
if (projectInfo) {
|
|
251
|
+
return { ...projectInfo, workingDirectory: process.cwd() };
|
|
252
|
+
}
|
|
253
|
+
// Fallback for unpacked apps without full project info
|
|
254
|
+
const pkg = app.getPackageDescription();
|
|
255
|
+
return {
|
|
256
|
+
package: pkg,
|
|
257
|
+
workingDirectory: process.cwd()
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
//# sourceMappingURL=introspection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspection.js","sourceRoot":"","sources":["../src/introspection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { type WorkerLogLevel } from "@webda/workout";
|
|
2
|
+
/**
|
|
3
|
+
* A single captured log entry.
|
|
4
|
+
*/
|
|
5
|
+
export interface LogEntry {
|
|
6
|
+
/** Unique identifier for this entry */
|
|
7
|
+
id: string;
|
|
8
|
+
/** Unix timestamp when the log was emitted */
|
|
9
|
+
timestamp: number;
|
|
10
|
+
/** Severity level */
|
|
11
|
+
level: WorkerLogLevel;
|
|
12
|
+
/** Formatted message string */
|
|
13
|
+
message: string;
|
|
14
|
+
/** Raw arguments from the log call */
|
|
15
|
+
args: any[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Event emitted when a new log entry is captured.
|
|
19
|
+
*/
|
|
20
|
+
export type LogEvent = {
|
|
21
|
+
type: "log";
|
|
22
|
+
id: string;
|
|
23
|
+
timestamp: number;
|
|
24
|
+
level: WorkerLogLevel;
|
|
25
|
+
message: string;
|
|
26
|
+
};
|
|
27
|
+
type LogEventCallback = (event: LogEvent) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Ring buffer that captures application logs from WorkerOutput
|
|
30
|
+
* and notifies subscribers of new entries in real time.
|
|
31
|
+
*/
|
|
32
|
+
export declare class LogBuffer {
|
|
33
|
+
private maxSize;
|
|
34
|
+
/** Stored log entries */
|
|
35
|
+
private entries;
|
|
36
|
+
/** Active event subscribers */
|
|
37
|
+
private subscribers;
|
|
38
|
+
/** Listener function attached to WorkerOutput */
|
|
39
|
+
private listener;
|
|
40
|
+
/**
|
|
41
|
+
* Create a new LogBuffer.
|
|
42
|
+
* @param maxSize - Maximum number of entries to retain (oldest are evicted)
|
|
43
|
+
*/
|
|
44
|
+
constructor(maxSize?: number);
|
|
45
|
+
/**
|
|
46
|
+
* Start listening to WorkerOutput messages.
|
|
47
|
+
*/
|
|
48
|
+
subscribe(): void;
|
|
49
|
+
/**
|
|
50
|
+
* Stop listening to WorkerOutput messages.
|
|
51
|
+
*/
|
|
52
|
+
unsubscribe(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Return a shallow copy of all stored entries.
|
|
55
|
+
* @returns array of log entries
|
|
56
|
+
*/
|
|
57
|
+
getEntries(): LogEntry[];
|
|
58
|
+
/** Log level severity order — higher index means more severe. */
|
|
59
|
+
private static readonly LOG_LEVELS;
|
|
60
|
+
/**
|
|
61
|
+
* Filter entries by query. If the query matches a log level name,
|
|
62
|
+
* filter by severity (>= that level). Otherwise, do a text search
|
|
63
|
+
* on message and level.
|
|
64
|
+
* @param query - search string or log level name
|
|
65
|
+
* @returns matching entries
|
|
66
|
+
*/
|
|
67
|
+
search(query: string): LogEntry[];
|
|
68
|
+
/**
|
|
69
|
+
* Register a callback for new log events.
|
|
70
|
+
* @param callback - function invoked on each new log event
|
|
71
|
+
* @returns unsubscribe function
|
|
72
|
+
*/
|
|
73
|
+
onEvent(callback: LogEventCallback): () => void;
|
|
74
|
+
}
|
|
75
|
+
export {};
|
package/lib/logbuffer.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useWorkerOutput } from "@webda/workout";
|
|
2
|
+
/**
|
|
3
|
+
* Ring buffer that captures application logs from WorkerOutput
|
|
4
|
+
* and notifies subscribers of new entries in real time.
|
|
5
|
+
*/
|
|
6
|
+
export class LogBuffer {
|
|
7
|
+
/**
|
|
8
|
+
* Create a new LogBuffer.
|
|
9
|
+
* @param maxSize - Maximum number of entries to retain (oldest are evicted)
|
|
10
|
+
*/
|
|
11
|
+
constructor(maxSize = 2000) {
|
|
12
|
+
this.maxSize = maxSize;
|
|
13
|
+
/** Stored log entries */
|
|
14
|
+
this.entries = [];
|
|
15
|
+
/** Active event subscribers */
|
|
16
|
+
this.subscribers = new Set();
|
|
17
|
+
this.listener = (msg) => {
|
|
18
|
+
if (msg.type !== "log" || !msg.log)
|
|
19
|
+
return;
|
|
20
|
+
const id = Math.random().toString(36).substring(2);
|
|
21
|
+
const entry = {
|
|
22
|
+
id,
|
|
23
|
+
timestamp: msg.timestamp,
|
|
24
|
+
level: msg.log.level,
|
|
25
|
+
message: msg.log.args
|
|
26
|
+
.map((a) => (typeof a === "object" ? JSON.stringify(a) : String(a)))
|
|
27
|
+
.join(" "),
|
|
28
|
+
args: msg.log.args
|
|
29
|
+
};
|
|
30
|
+
if (this.entries.length >= this.maxSize) {
|
|
31
|
+
this.entries.shift();
|
|
32
|
+
}
|
|
33
|
+
this.entries.push(entry);
|
|
34
|
+
const event = {
|
|
35
|
+
type: "log",
|
|
36
|
+
id,
|
|
37
|
+
timestamp: entry.timestamp,
|
|
38
|
+
level: entry.level,
|
|
39
|
+
message: entry.message
|
|
40
|
+
};
|
|
41
|
+
for (const cb of this.subscribers) {
|
|
42
|
+
cb(event);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Start listening to WorkerOutput messages.
|
|
48
|
+
*/
|
|
49
|
+
subscribe() {
|
|
50
|
+
useWorkerOutput().on("message", this.listener);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Stop listening to WorkerOutput messages.
|
|
54
|
+
*/
|
|
55
|
+
unsubscribe() {
|
|
56
|
+
try {
|
|
57
|
+
useWorkerOutput().removeListener("message", this.listener);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// WorkerOutput may not be available
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Return a shallow copy of all stored entries.
|
|
65
|
+
* @returns array of log entries
|
|
66
|
+
*/
|
|
67
|
+
getEntries() {
|
|
68
|
+
return [...this.entries];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Filter entries by query. If the query matches a log level name,
|
|
72
|
+
* filter by severity (>= that level). Otherwise, do a text search
|
|
73
|
+
* on message and level.
|
|
74
|
+
* @param query - search string or log level name
|
|
75
|
+
* @returns matching entries
|
|
76
|
+
*/
|
|
77
|
+
search(query) {
|
|
78
|
+
const upper = query.toUpperCase();
|
|
79
|
+
const levelIndex = LogBuffer.LOG_LEVELS.indexOf(upper);
|
|
80
|
+
if (levelIndex >= 0) {
|
|
81
|
+
return this.entries.filter(e => LogBuffer.LOG_LEVELS.indexOf(e.level) >= levelIndex);
|
|
82
|
+
}
|
|
83
|
+
const lower = query.toLowerCase();
|
|
84
|
+
return this.entries.filter(e => e.message.toLowerCase().includes(lower) || e.level.toLowerCase().includes(lower));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Register a callback for new log events.
|
|
88
|
+
* @param callback - function invoked on each new log event
|
|
89
|
+
* @returns unsubscribe function
|
|
90
|
+
*/
|
|
91
|
+
onEvent(callback) {
|
|
92
|
+
this.subscribers.add(callback);
|
|
93
|
+
return () => this.subscribers.delete(callback);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Log level severity order — higher index means more severe. */
|
|
97
|
+
LogBuffer.LOG_LEVELS = ["TRACE", "DEBUG", "INFO", "WARN", "ERROR"];
|
|
98
|
+
//# sourceMappingURL=logbuffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logbuffer.js","sourceRoot":"","sources":["../src/logbuffer.ts"],"names":[],"mappings":"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"}
|