@beignet/devtools 0.0.1 → 0.0.2
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/CHANGELOG.md +13 -0
- package/README.md +1 -0
- package/dist/access.d.ts +20 -0
- package/dist/access.d.ts.map +1 -1
- package/dist/access.js +11 -0
- package/dist/access.js.map +1 -1
- package/dist/audit.d.ts +21 -0
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +6 -0
- package/dist/audit.js.map +1 -1
- package/dist/events.d.ts +18 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +6 -0
- package/dist/events.js.map +1 -1
- package/dist/instrumentation.d.ts +40 -0
- package/dist/instrumentation.d.ts.map +1 -1
- package/dist/instrumentation.js +10 -0
- package/dist/instrumentation.js.map +1 -1
- package/dist/persistence.d.ts +24 -0
- package/dist/persistence.d.ts.map +1 -1
- package/dist/persistence.js +6 -0
- package/dist/persistence.js.map +1 -1
- package/dist/provider-instrumentation.d.ts +18 -0
- package/dist/provider-instrumentation.d.ts.map +1 -1
- package/dist/provider-instrumentation.js +9 -0
- package/dist/provider-instrumentation.js.map +1 -1
- package/dist/provider.d.ts +42 -0
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +3 -0
- package/dist/provider.js.map +1 -1
- package/dist/redaction.d.ts +9 -0
- package/dist/redaction.d.ts.map +1 -1
- package/dist/redaction.js +9 -0
- package/dist/redaction.js.map +1 -1
- package/dist/routes.d.ts +12 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js.map +1 -1
- package/dist/trace-context.d.ts +51 -0
- package/dist/trace-context.d.ts.map +1 -1
- package/dist/trace-context.js +18 -0
- package/dist/trace-context.js.map +1 -1
- package/dist/ui.js +7 -2
- package/dist/ui.js.map +1 -1
- package/dist/watchers.d.ts +43 -1
- package/dist/watchers.d.ts.map +1 -1
- package/dist/watchers.js +20 -0
- package/dist/watchers.js.map +1 -1
- package/package.json +1 -1
- package/src/access.ts +20 -0
- package/src/audit.ts +21 -0
- package/src/events.ts +18 -0
- package/src/instrumentation.ts +40 -0
- package/src/persistence.ts +24 -0
- package/src/provider-instrumentation.ts +20 -0
- package/src/provider.ts +42 -0
- package/src/redaction.ts +9 -0
- package/src/routes.ts +12 -0
- package/src/trace-context.ts +51 -0
- package/src/ui.ts +7 -2
- package/src/watchers.ts +50 -0
package/src/events.ts
CHANGED
|
@@ -156,14 +156,23 @@ export type DevtoolsEvent =
|
|
|
156
156
|
| ProviderEvent
|
|
157
157
|
| CustomDevtoolsEvent;
|
|
158
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Input accepted by `createDevtoolsEvent(...)`.
|
|
161
|
+
*/
|
|
159
162
|
export type DevtoolsEventInput = DevtoolsEvent extends infer Event
|
|
160
163
|
? Event extends DevtoolsEvent
|
|
161
164
|
? Omit<Event, "id" | "timestamp"> & Partial<Pick<Event, "id" | "timestamp">>
|
|
162
165
|
: never
|
|
163
166
|
: never;
|
|
164
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Function that redacts a normalized devtools event before storage.
|
|
170
|
+
*/
|
|
165
171
|
export type DevtoolsRedactor = (event: DevtoolsEvent) => DevtoolsEvent;
|
|
166
172
|
|
|
173
|
+
/**
|
|
174
|
+
* Event emitted to live devtools subscribers.
|
|
175
|
+
*/
|
|
167
176
|
export type DevtoolsSubscriptionEvent =
|
|
168
177
|
| {
|
|
169
178
|
type: "record";
|
|
@@ -173,8 +182,14 @@ export type DevtoolsSubscriptionEvent =
|
|
|
173
182
|
type: "clear";
|
|
174
183
|
};
|
|
175
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Devtools subscription listener.
|
|
187
|
+
*/
|
|
176
188
|
export type DevtoolsListener = (event: DevtoolsSubscriptionEvent) => void;
|
|
177
189
|
|
|
190
|
+
/**
|
|
191
|
+
* All built-in devtools event types.
|
|
192
|
+
*/
|
|
178
193
|
export const DEVTOOLS_EVENT_TYPES = [
|
|
179
194
|
"request",
|
|
180
195
|
"error",
|
|
@@ -186,6 +201,9 @@ export const DEVTOOLS_EVENT_TYPES = [
|
|
|
186
201
|
"custom",
|
|
187
202
|
] as const satisfies readonly DevtoolsEvent["type"][];
|
|
188
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Check whether a string is a built-in devtools event type.
|
|
206
|
+
*/
|
|
189
207
|
export function isDevtoolsEventType(
|
|
190
208
|
value: string,
|
|
191
209
|
): value is DevtoolsEvent["type"] {
|
package/src/instrumentation.ts
CHANGED
|
@@ -32,6 +32,9 @@ type ContextWithPorts = {
|
|
|
32
32
|
};
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Options for server hooks that record request/error events to devtools.
|
|
37
|
+
*/
|
|
35
38
|
export interface DevtoolsHooksOptions<Ctx> {
|
|
36
39
|
/**
|
|
37
40
|
* Devtools route prefix. Requests under this path are ignored to avoid
|
|
@@ -41,6 +44,9 @@ export interface DevtoolsHooksOptions<Ctx> {
|
|
|
41
44
|
*/
|
|
42
45
|
basePath?: string;
|
|
43
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the request ID used for event correlation.
|
|
49
|
+
*/
|
|
44
50
|
getRequestId?: (args: {
|
|
45
51
|
req: HttpRequestLike;
|
|
46
52
|
ctx?: Ctx;
|
|
@@ -66,6 +72,9 @@ export interface DevtoolsHooksOptions<Ctx> {
|
|
|
66
72
|
*/
|
|
67
73
|
traceContextHeader?: string | false;
|
|
68
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Resolve a trace context from request/context/response data.
|
|
77
|
+
*/
|
|
69
78
|
getTraceContext?: (args: {
|
|
70
79
|
req: HttpRequestLike;
|
|
71
80
|
ctx?: Ctx;
|
|
@@ -78,6 +87,9 @@ export interface DevtoolsHooksOptions<Ctx> {
|
|
|
78
87
|
*/
|
|
79
88
|
redact?: DevtoolsRedactor;
|
|
80
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Decide whether to capture a completed request event.
|
|
92
|
+
*/
|
|
81
93
|
shouldCapture?: (args: {
|
|
82
94
|
req: HttpRequestLike;
|
|
83
95
|
ctx?: Ctx;
|
|
@@ -87,6 +99,9 @@ export interface DevtoolsHooksOptions<Ctx> {
|
|
|
87
99
|
}) => boolean;
|
|
88
100
|
}
|
|
89
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Use-case run event shape consumed by the devtools observer.
|
|
104
|
+
*/
|
|
90
105
|
export interface DevtoolsUseCaseRunEvent<Ctx> {
|
|
91
106
|
name: string;
|
|
92
107
|
kind: "command" | "query";
|
|
@@ -96,10 +111,25 @@ export interface DevtoolsUseCaseRunEvent<Ctx> {
|
|
|
96
111
|
ctx: Ctx;
|
|
97
112
|
}
|
|
98
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Options for `createDevtoolsUseCaseObserver(...)`.
|
|
116
|
+
*/
|
|
99
117
|
export interface DevtoolsUseCaseObserverOptions<Ctx> {
|
|
118
|
+
/**
|
|
119
|
+
* Resolve a devtools port from use-case context.
|
|
120
|
+
*/
|
|
100
121
|
getDevtools?: (ctx: Ctx) => DevtoolsPort | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* Resolve the request ID used for event correlation.
|
|
124
|
+
*/
|
|
101
125
|
getRequestId?: (ctx: Ctx) => string | undefined;
|
|
126
|
+
/**
|
|
127
|
+
* Whether use-case error phases should also emit `error` events.
|
|
128
|
+
*/
|
|
102
129
|
logErrorEvents?: boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Optional redactor applied before events are recorded.
|
|
132
|
+
*/
|
|
103
133
|
redact?: DevtoolsRedactor;
|
|
104
134
|
}
|
|
105
135
|
|
|
@@ -175,6 +205,13 @@ function isWatcherEnabled(
|
|
|
175
205
|
return devtools.isWatcherEnabled(name);
|
|
176
206
|
}
|
|
177
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Create server hooks that record Beignet request and error activity.
|
|
210
|
+
*
|
|
211
|
+
* Devtools routes under `basePath` are ignored so polling and SSE traffic do not
|
|
212
|
+
* fill the event buffer. Request IDs and trace context are also written to
|
|
213
|
+
* response headers unless disabled.
|
|
214
|
+
*/
|
|
178
215
|
export function createDevtoolsHooks<
|
|
179
216
|
Ctx,
|
|
180
217
|
Ports extends PortsWithDevtools = PortsWithDevtools,
|
|
@@ -359,6 +396,9 @@ export function createDevtoolsHooks<
|
|
|
359
396
|
};
|
|
360
397
|
}
|
|
361
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Create a use-case observer compatible with `createUseCase({ onRun })`.
|
|
401
|
+
*/
|
|
362
402
|
export function createDevtoolsUseCaseObserver<Ctx>(
|
|
363
403
|
options: DevtoolsUseCaseObserverOptions<Ctx> = {},
|
|
364
404
|
): (event: DevtoolsUseCaseRunEvent<Ctx>) => void {
|
package/src/persistence.ts
CHANGED
|
@@ -1,15 +1,33 @@
|
|
|
1
1
|
import type { DevtoolsEvent } from "./events";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Persistence interface for devtools event stores.
|
|
5
|
+
*/
|
|
3
6
|
export interface DevtoolsEventStore {
|
|
7
|
+
/**
|
|
8
|
+
* Store name used in diagnostics.
|
|
9
|
+
*/
|
|
4
10
|
name?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Load persisted events at startup.
|
|
13
|
+
*/
|
|
5
14
|
load?(): DevtoolsEvent[] | Promise<DevtoolsEvent[]>;
|
|
15
|
+
/**
|
|
16
|
+
* Append one event. The second argument is the current bounded buffer.
|
|
17
|
+
*/
|
|
6
18
|
append?(
|
|
7
19
|
event: DevtoolsEvent,
|
|
8
20
|
events: readonly DevtoolsEvent[],
|
|
9
21
|
): void | Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Clear persisted events.
|
|
24
|
+
*/
|
|
10
25
|
clear?(): void | Promise<void>;
|
|
11
26
|
}
|
|
12
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Options for the Node-only file-backed devtools store.
|
|
30
|
+
*/
|
|
13
31
|
export interface FileDevtoolsStoreOptions {
|
|
14
32
|
/**
|
|
15
33
|
* JSONL file used for persisted devtools events.
|
|
@@ -80,6 +98,12 @@ async function loadNodeModules(): Promise<{
|
|
|
80
98
|
return { fs, path };
|
|
81
99
|
}
|
|
82
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Create a JSONL file-backed devtools store.
|
|
103
|
+
*
|
|
104
|
+
* This store lazily imports Node fs/path modules and is intended for Node
|
|
105
|
+
* runtimes. It compacts periodically to keep the persisted file bounded.
|
|
106
|
+
*/
|
|
83
107
|
export function createFileDevtoolsStore(
|
|
84
108
|
options: FileDevtoolsStoreOptions = {},
|
|
85
109
|
): DevtoolsEventStore {
|
|
@@ -7,11 +7,25 @@ import {
|
|
|
7
7
|
} from "@beignet/core/providers";
|
|
8
8
|
import type { DevtoolsPort } from "./index";
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Provider devtools instrumentation options.
|
|
12
|
+
*/
|
|
10
13
|
export type ProviderDevtoolsOptions = ProviderInstrumentationOptions;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Custom provider event input accepted by provider devtools instrumentation.
|
|
17
|
+
*/
|
|
11
18
|
export type ProviderCustomDevtoolsEventInput =
|
|
12
19
|
ProviderCustomInstrumentationEventInput;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Provider instrumentation object backed by devtools.
|
|
23
|
+
*/
|
|
13
24
|
export type ProviderDevtools = ProviderInstrumentation;
|
|
14
25
|
|
|
26
|
+
/**
|
|
27
|
+
* Check whether an unknown value implements the devtools port shape.
|
|
28
|
+
*/
|
|
15
29
|
export function isDevtoolsPort(value: unknown): value is DevtoolsPort {
|
|
16
30
|
return (
|
|
17
31
|
isProviderInstrumentationPort(value) &&
|
|
@@ -24,6 +38,9 @@ export function isDevtoolsPort(value: unknown): value is DevtoolsPort {
|
|
|
24
38
|
);
|
|
25
39
|
}
|
|
26
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a devtools port from a direct port or `{ devtools }` object.
|
|
43
|
+
*/
|
|
27
44
|
export function resolveDevtoolsPort(target: unknown): DevtoolsPort | undefined {
|
|
28
45
|
if (isDevtoolsPort(target)) return target;
|
|
29
46
|
|
|
@@ -39,6 +56,9 @@ export function resolveDevtoolsPort(target: unknown): DevtoolsPort | undefined {
|
|
|
39
56
|
return undefined;
|
|
40
57
|
}
|
|
41
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Create provider instrumentation backed by a devtools port when available.
|
|
61
|
+
*/
|
|
42
62
|
export function createProviderDevtools(
|
|
43
63
|
target: unknown,
|
|
44
64
|
options: ProviderDevtoolsOptions,
|
package/src/provider.ts
CHANGED
|
@@ -37,11 +37,29 @@ import {
|
|
|
37
37
|
*/
|
|
38
38
|
const MAX_EVENTS = 500;
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Options for `createInMemoryDevtools(...)`.
|
|
42
|
+
*/
|
|
40
43
|
export interface InMemoryDevtoolsOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Maximum events kept in memory.
|
|
46
|
+
*/
|
|
41
47
|
maxEvents?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Custom redactor applied after the default devtools redactor.
|
|
50
|
+
*/
|
|
42
51
|
redact?: DevtoolsRedactor;
|
|
52
|
+
/**
|
|
53
|
+
* Watcher configuration.
|
|
54
|
+
*/
|
|
43
55
|
watchers?: DevtoolsWatchersOptions;
|
|
56
|
+
/**
|
|
57
|
+
* Events loaded into the buffer at startup.
|
|
58
|
+
*/
|
|
44
59
|
initialEvents?: readonly DevtoolsEvent[];
|
|
60
|
+
/**
|
|
61
|
+
* Optional persistence store.
|
|
62
|
+
*/
|
|
45
63
|
store?: DevtoolsEventStore;
|
|
46
64
|
}
|
|
47
65
|
|
|
@@ -52,6 +70,9 @@ function createEventId(): string {
|
|
|
52
70
|
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
53
71
|
}
|
|
54
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Normalize a devtools event by filling `id` and `timestamp`.
|
|
75
|
+
*/
|
|
55
76
|
export function createDevtoolsEvent(event: DevtoolsEventInput): DevtoolsEvent {
|
|
56
77
|
return {
|
|
57
78
|
...event,
|
|
@@ -247,13 +268,34 @@ const DevtoolsConfigSchema = z.object({
|
|
|
247
268
|
PERSIST_PATH: z.string().optional(),
|
|
248
269
|
});
|
|
249
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Devtools provider config loaded from `DEVTOOLS_*` env vars.
|
|
273
|
+
*/
|
|
250
274
|
export type DevtoolsConfig = z.infer<typeof DevtoolsConfigSchema>;
|
|
251
275
|
|
|
276
|
+
/**
|
|
277
|
+
* Options for `createDevtoolsProvider(...)`.
|
|
278
|
+
*/
|
|
252
279
|
export interface DevtoolsProviderOptions {
|
|
280
|
+
/**
|
|
281
|
+
* Whether devtools are enabled. Defaults to non-production.
|
|
282
|
+
*/
|
|
253
283
|
enabled?: boolean;
|
|
284
|
+
/**
|
|
285
|
+
* Maximum events kept in memory.
|
|
286
|
+
*/
|
|
254
287
|
maxEvents?: number;
|
|
288
|
+
/**
|
|
289
|
+
* Custom redactor applied after the default redactor.
|
|
290
|
+
*/
|
|
255
291
|
redact?: DevtoolsRedactor;
|
|
292
|
+
/**
|
|
293
|
+
* Watcher configuration.
|
|
294
|
+
*/
|
|
256
295
|
watchers?: DevtoolsWatchersOptions;
|
|
296
|
+
/**
|
|
297
|
+
* Optional persistence store or async store factory.
|
|
298
|
+
*/
|
|
257
299
|
store?:
|
|
258
300
|
| DevtoolsEventStore
|
|
259
301
|
| (() => DevtoolsEventStore | Promise<DevtoolsEventStore>);
|
package/src/redaction.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { redactValue } from "@beignet/core/ports";
|
|
2
2
|
import type { DevtoolsEvent, DevtoolsRedactor } from "./events";
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Default devtools event redactor.
|
|
6
|
+
*/
|
|
4
7
|
export const defaultDevtoolsRedactor: DevtoolsRedactor = (event) =>
|
|
5
8
|
redactValue(event);
|
|
6
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Apply default redaction and then an optional custom redactor.
|
|
12
|
+
*/
|
|
7
13
|
export function applyDevtoolsRedaction(
|
|
8
14
|
event: DevtoolsEvent,
|
|
9
15
|
redact?: DevtoolsRedactor,
|
|
@@ -13,6 +19,9 @@ export function applyDevtoolsRedaction(
|
|
|
13
19
|
return redact(redacted);
|
|
14
20
|
}
|
|
15
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Create a devtools error event when redaction fails.
|
|
24
|
+
*/
|
|
16
25
|
export function createRedactionFailureEvent(error: unknown): DevtoolsEvent {
|
|
17
26
|
return {
|
|
18
27
|
id: `${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
package/src/routes.ts
CHANGED
|
@@ -13,6 +13,9 @@ import { isDevtoolsEventType } from "./events";
|
|
|
13
13
|
import type { DevtoolsFilter, DevtoolsPort } from "./index";
|
|
14
14
|
import { handleDevtoolsUIRequest } from "./ui";
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Devtools route options shared by route handlers.
|
|
18
|
+
*/
|
|
16
19
|
export interface DevtoolsRequestOptions extends DevtoolsRouteAccessOptions {
|
|
17
20
|
/**
|
|
18
21
|
* URL path prefix where devtools routes are mounted.
|
|
@@ -22,8 +25,17 @@ export interface DevtoolsRequestOptions extends DevtoolsRouteAccessOptions {
|
|
|
22
25
|
basePath: string;
|
|
23
26
|
}
|
|
24
27
|
|
|
28
|
+
/**
|
|
29
|
+
* GET/POST route handlers returned by `createDevtoolsRoute(...)`.
|
|
30
|
+
*/
|
|
25
31
|
export interface DevtoolsRouteHandlers {
|
|
32
|
+
/**
|
|
33
|
+
* Handle devtools GET requests.
|
|
34
|
+
*/
|
|
26
35
|
GET(req: Request): Promise<Response>;
|
|
36
|
+
/**
|
|
37
|
+
* Handle devtools POST requests.
|
|
38
|
+
*/
|
|
27
39
|
POST(req: Request): Promise<Response>;
|
|
28
40
|
}
|
|
29
41
|
|
package/src/trace-context.ts
CHANGED
|
@@ -1,19 +1,52 @@
|
|
|
1
1
|
const TRACEPARENT_PATTERN = /^00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Devtools trace context used to correlate related events.
|
|
5
|
+
*/
|
|
3
6
|
export interface DevtoolsTraceContext {
|
|
7
|
+
/**
|
|
8
|
+
* W3C trace ID.
|
|
9
|
+
*/
|
|
4
10
|
traceId: string;
|
|
11
|
+
/**
|
|
12
|
+
* Current span ID.
|
|
13
|
+
*/
|
|
5
14
|
spanId: string;
|
|
15
|
+
/**
|
|
16
|
+
* Parent span ID when available.
|
|
17
|
+
*/
|
|
6
18
|
parentSpanId?: string;
|
|
19
|
+
/**
|
|
20
|
+
* W3C traceparent header value.
|
|
21
|
+
*/
|
|
7
22
|
traceparent: string;
|
|
8
23
|
}
|
|
9
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Parsed W3C traceparent header.
|
|
27
|
+
*/
|
|
10
28
|
export interface ParsedTraceparent {
|
|
29
|
+
/**
|
|
30
|
+
* W3C trace ID.
|
|
31
|
+
*/
|
|
11
32
|
traceId: string;
|
|
33
|
+
/**
|
|
34
|
+
* Span ID from the traceparent header.
|
|
35
|
+
*/
|
|
12
36
|
spanId: string;
|
|
37
|
+
/**
|
|
38
|
+
* Trace flags from the traceparent header.
|
|
39
|
+
*/
|
|
13
40
|
traceFlags: string;
|
|
41
|
+
/**
|
|
42
|
+
* Normalized traceparent header value.
|
|
43
|
+
*/
|
|
14
44
|
traceparent: string;
|
|
15
45
|
}
|
|
16
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Input accepted when creating devtools trace context.
|
|
49
|
+
*/
|
|
17
50
|
export interface DevtoolsTraceContextInput {
|
|
18
51
|
traceId?: string;
|
|
19
52
|
spanId?: string;
|
|
@@ -41,6 +74,9 @@ function isNonZeroHex(value: string): boolean {
|
|
|
41
74
|
return !/^0+$/.test(value);
|
|
42
75
|
}
|
|
43
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Create a non-zero W3C trace ID.
|
|
79
|
+
*/
|
|
44
80
|
export function createTraceId(): string {
|
|
45
81
|
let traceId = createHexId(32);
|
|
46
82
|
while (!isNonZeroHex(traceId)) {
|
|
@@ -49,6 +85,9 @@ export function createTraceId(): string {
|
|
|
49
85
|
return traceId;
|
|
50
86
|
}
|
|
51
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Create a non-zero W3C span ID.
|
|
90
|
+
*/
|
|
52
91
|
export function createSpanId(): string {
|
|
53
92
|
let spanId = createHexId(16);
|
|
54
93
|
while (!isNonZeroHex(spanId)) {
|
|
@@ -57,6 +96,9 @@ export function createSpanId(): string {
|
|
|
57
96
|
return spanId;
|
|
58
97
|
}
|
|
59
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Create a W3C traceparent header value.
|
|
101
|
+
*/
|
|
60
102
|
export function createTraceparent(args: {
|
|
61
103
|
traceId: string;
|
|
62
104
|
spanId: string;
|
|
@@ -65,6 +107,9 @@ export function createTraceparent(args: {
|
|
|
65
107
|
return `00-${args.traceId}-${args.spanId}-${args.traceFlags ?? "01"}`;
|
|
66
108
|
}
|
|
67
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Parse and validate a W3C traceparent header value.
|
|
112
|
+
*/
|
|
68
113
|
export function parseTraceparent(
|
|
69
114
|
value: string | null | undefined,
|
|
70
115
|
): ParsedTraceparent | undefined {
|
|
@@ -84,6 +129,9 @@ export function parseTraceparent(
|
|
|
84
129
|
};
|
|
85
130
|
}
|
|
86
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Create devtools trace context from explicit IDs or an existing traceparent.
|
|
134
|
+
*/
|
|
87
135
|
export function createDevtoolsTraceContext(
|
|
88
136
|
input: DevtoolsTraceContextInput = {},
|
|
89
137
|
): DevtoolsTraceContext {
|
|
@@ -104,6 +152,9 @@ export function createDevtoolsTraceContext(
|
|
|
104
152
|
};
|
|
105
153
|
}
|
|
106
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Create child trace context from a parent context.
|
|
157
|
+
*/
|
|
107
158
|
export function createChildDevtoolsTraceContext(
|
|
108
159
|
parent: DevtoolsTraceContextInput,
|
|
109
160
|
): DevtoolsTraceContext {
|
package/src/ui.ts
CHANGED
|
@@ -132,6 +132,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
132
132
|
.badge-cache{background:#f7fee7;color:#4d7c0f;border-color:#d9f99d}
|
|
133
133
|
.badge-db{background:#ecfeff;color:#0e7490;border-color:#cffafe}
|
|
134
134
|
.badge-mail{background:#fdf2f8;color:#be185d;border-color:#fbcfe8}
|
|
135
|
+
.badge-notifications{background:#f5f3ff;color:#6d28d9;border-color:#ddd6fe}
|
|
135
136
|
.badge-rateLimit{background:#fffbeb;color:#b45309;border-color:#fde68a}
|
|
136
137
|
.badge-storage{background:#f0fdf4;color:#15803d;border-color:#bbf7d0}
|
|
137
138
|
.request-id{font-family:var(--font-mono);font-size:10px;color:var(--text-muted);padding:2px 5px;background:var(--surface-2);border:1px solid var(--border);border-radius:4px}
|
|
@@ -222,13 +223,14 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
222
223
|
{id:"cache",label:"Cache",type:"custom",watcher:"cache",watcherName:"cache"},
|
|
223
224
|
{id:"storage",label:"Storage",type:"custom",watcher:"storage",watcherName:"storage"},
|
|
224
225
|
{id:"mail",label:"Mail",type:"custom",watcher:"mail",watcherName:"mail"},
|
|
226
|
+
{id:"notifications",label:"Notifications",type:"custom",watcher:"notifications",watcherName:"notifications"},
|
|
225
227
|
{id:"auth",label:"Auth",type:"custom",watcher:"auth",watcherName:"auth"},
|
|
226
228
|
{id:"audit",label:"Audit",type:"custom",watcher:"audit",watcherName:"audit"},
|
|
227
229
|
{id:"rateLimit",label:"Rate limits",type:"custom",watcher:"rateLimit",watcherName:"rateLimit"},
|
|
228
230
|
{id:"custom",label:"Custom",type:"custom",watcher:"custom"}
|
|
229
231
|
];
|
|
230
|
-
const FOCUS_PANEL_TABS={events:true,jobs:true,schedules:true,db:true,cache:true,storage:true,mail:true,auth:true,audit:true,rateLimit:true};
|
|
231
|
-
const BUILT_IN_WATCHERS={requests:true,errors:true,useCases:true,eventBus:true,jobs:true,schedules:true,providers:true,db:true,cache:true,storage:true,mail:true,auth:true,audit:true,rateLimit:true,custom:true};
|
|
232
|
+
const FOCUS_PANEL_TABS={events:true,jobs:true,schedules:true,db:true,cache:true,storage:true,mail:true,notifications:true,auth:true,audit:true,rateLimit:true};
|
|
233
|
+
const BUILT_IN_WATCHERS={requests:true,errors:true,useCases:true,eventBus:true,jobs:true,schedules:true,providers:true,db:true,cache:true,storage:true,mail:true,notifications:true,auth:true,audit:true,rateLimit:true,custom:true};
|
|
232
234
|
let events=[];
|
|
233
235
|
let watchers=[];
|
|
234
236
|
let activeTab=localStorage.getItem("beignet-devtools-tab")||"timeline";
|
|
@@ -331,6 +333,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
331
333
|
case "cache": return "cache";
|
|
332
334
|
case "db": return "database";
|
|
333
335
|
case "mail": return "mail";
|
|
336
|
+
case "notifications": return "notifications";
|
|
334
337
|
case "rateLimit": return "rate limit";
|
|
335
338
|
case "storage": return "storage";
|
|
336
339
|
default: return "custom";
|
|
@@ -347,6 +350,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
347
350
|
case "cache": return "cache";
|
|
348
351
|
case "db": return "db";
|
|
349
352
|
case "mail": return "mail";
|
|
353
|
+
case "notifications": return "notifications";
|
|
350
354
|
case "rateLimit": return "rateLimit";
|
|
351
355
|
case "storage": return "storage";
|
|
352
356
|
default: return "custom";
|
|
@@ -565,6 +569,7 @@ button.danger:hover{border-color:rgba(225,29,72,.24);background:#fff1f2}
|
|
|
565
569
|
case "cache": return {title:"Cache",subtitle:"Reads, writes, deletes, and hit rates"};
|
|
566
570
|
case "storage": return {title:"Storage",subtitle:"Object storage operations"};
|
|
567
571
|
case "mail": return {title:"Mail",subtitle:"Delivery attempts and provider results"};
|
|
572
|
+
case "notifications": return {title:"Notifications",subtitle:"Notification intent and channel delivery"};
|
|
568
573
|
case "auth": return {title:"Auth",subtitle:"Session and authentication activity"};
|
|
569
574
|
case "audit": return {title:"Audit",subtitle:"Durable activity records emitted by application code"};
|
|
570
575
|
case "rateLimit": return {title:"Rate limits",subtitle:"Allowed, blocked, and failed checks"};
|
package/src/watchers.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { DevtoolsEvent } from "./events";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Built-in devtools watcher names.
|
|
5
|
+
*/
|
|
3
6
|
export const BUILT_IN_DEVTOOLS_WATCHER_NAMES = [
|
|
4
7
|
"requests",
|
|
5
8
|
"errors",
|
|
@@ -12,25 +15,53 @@ export const BUILT_IN_DEVTOOLS_WATCHER_NAMES = [
|
|
|
12
15
|
"cache",
|
|
13
16
|
"storage",
|
|
14
17
|
"mail",
|
|
18
|
+
"notifications",
|
|
15
19
|
"auth",
|
|
16
20
|
"audit",
|
|
17
21
|
"rateLimit",
|
|
18
22
|
"custom",
|
|
19
23
|
] as const;
|
|
20
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Name of a built-in devtools watcher.
|
|
27
|
+
*/
|
|
21
28
|
export type BuiltInDevtoolsWatcherName =
|
|
22
29
|
(typeof BUILT_IN_DEVTOOLS_WATCHER_NAMES)[number];
|
|
23
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Name of a built-in or app-defined devtools watcher.
|
|
33
|
+
*/
|
|
24
34
|
export type DevtoolsWatcherName = BuiltInDevtoolsWatcherName | (string & {});
|
|
25
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Resolved devtools watcher configuration.
|
|
38
|
+
*/
|
|
26
39
|
export interface DevtoolsWatcher {
|
|
40
|
+
/**
|
|
41
|
+
* Watcher name.
|
|
42
|
+
*/
|
|
27
43
|
name: DevtoolsWatcherName;
|
|
44
|
+
/**
|
|
45
|
+
* Display label.
|
|
46
|
+
*/
|
|
28
47
|
label: string;
|
|
48
|
+
/**
|
|
49
|
+
* Display description.
|
|
50
|
+
*/
|
|
29
51
|
description?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Event types this watcher owns.
|
|
54
|
+
*/
|
|
30
55
|
eventTypes: readonly DevtoolsEvent["type"][];
|
|
56
|
+
/**
|
|
57
|
+
* Whether events owned by this watcher should be stored.
|
|
58
|
+
*/
|
|
31
59
|
enabled: boolean;
|
|
32
60
|
}
|
|
33
61
|
|
|
62
|
+
/**
|
|
63
|
+
* User-provided watcher override.
|
|
64
|
+
*/
|
|
34
65
|
export type DevtoolsWatcherOptions =
|
|
35
66
|
| boolean
|
|
36
67
|
| {
|
|
@@ -40,6 +71,9 @@ export type DevtoolsWatcherOptions =
|
|
|
40
71
|
eventTypes?: readonly DevtoolsEvent["type"][];
|
|
41
72
|
};
|
|
42
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Watcher overrides keyed by built-in or custom watcher name.
|
|
76
|
+
*/
|
|
43
77
|
export type DevtoolsWatchersOptions = Partial<
|
|
44
78
|
Record<BuiltInDevtoolsWatcherName, DevtoolsWatcherOptions>
|
|
45
79
|
> &
|
|
@@ -124,6 +158,13 @@ const BUILT_IN_DEVTOOLS_WATCHERS = {
|
|
|
124
158
|
eventTypes: ["custom"],
|
|
125
159
|
enabled: true,
|
|
126
160
|
},
|
|
161
|
+
notifications: {
|
|
162
|
+
name: "notifications",
|
|
163
|
+
label: "Notifications",
|
|
164
|
+
description: "Application notification intent and channel delivery.",
|
|
165
|
+
eventTypes: ["custom"],
|
|
166
|
+
enabled: true,
|
|
167
|
+
},
|
|
127
168
|
auth: {
|
|
128
169
|
name: "auth",
|
|
129
170
|
label: "Auth",
|
|
@@ -184,6 +225,9 @@ function normalizeWatcherOptions(
|
|
|
184
225
|
};
|
|
185
226
|
}
|
|
186
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Resolve built-in and custom watcher configuration.
|
|
230
|
+
*/
|
|
187
231
|
export function resolveDevtoolsWatchers(
|
|
188
232
|
options: DevtoolsWatchersOptions = {},
|
|
189
233
|
): DevtoolsWatcher[] {
|
|
@@ -211,6 +255,9 @@ export function resolveDevtoolsWatchers(
|
|
|
211
255
|
return watchers;
|
|
212
256
|
}
|
|
213
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Check whether a watcher is enabled.
|
|
260
|
+
*/
|
|
214
261
|
export function isDevtoolsWatcherEnabled(
|
|
215
262
|
watchers: readonly DevtoolsWatcher[],
|
|
216
263
|
name: DevtoolsWatcherName,
|
|
@@ -218,6 +265,9 @@ export function isDevtoolsWatcherEnabled(
|
|
|
218
265
|
return watchers.find((watcher) => watcher.name === name)?.enabled ?? true;
|
|
219
266
|
}
|
|
220
267
|
|
|
268
|
+
/**
|
|
269
|
+
* Check whether an event should be stored for a watcher configuration.
|
|
270
|
+
*/
|
|
221
271
|
export function isDevtoolsEventEnabled(
|
|
222
272
|
watchers: readonly DevtoolsWatcher[],
|
|
223
273
|
event: DevtoolsEvent,
|