@mrclrchtr/supi-settings 4.5.1 → 4.7.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.
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<a href="https://github.com/mrclrchtr/supi/tree/main/packages/supi-core">
|
|
3
|
-
<
|
|
4
|
-
<img src="https://raw.githubusercontent.com/mrclrchtr/supi/main/packages/supi-core/assets/social-preview.png" alt="SuPi Core" width="100%">
|
|
5
|
-
</picture>
|
|
3
|
+
<img src="https://raw.githubusercontent.com/mrclrchtr/supi/main/packages/supi-core/assets/social-preview.png" alt="SuPi Core" width="100%">
|
|
6
4
|
</a>
|
|
7
5
|
</div>
|
|
8
6
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-core",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.7.0",
|
|
4
|
+
"description": "Shared settings, configuration, reporting, and session infrastructure",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -64,6 +64,9 @@ export interface DebugEventQueryResult {
|
|
|
64
64
|
rawAccessDenied: boolean;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/** Receives a sanitized event whenever the registry records one. */
|
|
68
|
+
export type DebugEventListener = (event: DebugEventView) => void;
|
|
69
|
+
|
|
67
70
|
export interface DebugSummary {
|
|
68
71
|
total: number;
|
|
69
72
|
byLevel: Partial<Record<DebugLevel, number>>;
|
|
@@ -73,6 +76,7 @@ export interface DebugSummary {
|
|
|
73
76
|
interface DebugRegistryState {
|
|
74
77
|
config: DebugRegistryConfig;
|
|
75
78
|
events: DebugEvent[];
|
|
79
|
+
listeners: Set<DebugEventListener>;
|
|
76
80
|
nextId: number;
|
|
77
81
|
}
|
|
78
82
|
|
|
@@ -97,10 +101,14 @@ function getState(): DebugRegistryState {
|
|
|
97
101
|
state = {
|
|
98
102
|
config: cloneConfig(DEBUG_REGISTRY_DEFAULTS),
|
|
99
103
|
events: [],
|
|
104
|
+
listeners: new Set(),
|
|
100
105
|
nextId: 1,
|
|
101
106
|
};
|
|
102
107
|
(globalThis as Record<symbol, unknown>)[REGISTRY_KEY] = state;
|
|
103
108
|
}
|
|
109
|
+
// Keep the shared registry compatible with extension reloads that reuse an
|
|
110
|
+
// instance created before listeners existed.
|
|
111
|
+
if (!state.listeners) state.listeners = new Set();
|
|
104
112
|
return state;
|
|
105
113
|
}
|
|
106
114
|
|
|
@@ -119,7 +127,16 @@ function trimToMaxEvents(state: DebugRegistryState): void {
|
|
|
119
127
|
state.events.splice(0, state.events.length - maxEvents);
|
|
120
128
|
}
|
|
121
129
|
|
|
122
|
-
|
|
130
|
+
/** Return whether a debug level is recognized by the registry. */
|
|
131
|
+
export function isDebugLevel(value: unknown): value is DebugLevel {
|
|
132
|
+
return value === "debug" || value === "info" || value === "warning" || value === "error";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Match a debug event against the supported source, level, and category filters. */
|
|
136
|
+
export function matchesDebugEventQuery(
|
|
137
|
+
event: Pick<DebugEventView, "source" | "level" | "category">,
|
|
138
|
+
query: Pick<DebugEventQuery, "source" | "level" | "category">,
|
|
139
|
+
): boolean {
|
|
123
140
|
if (query.source && event.source !== query.source) return false;
|
|
124
141
|
if (query.level && event.level !== query.level) return false;
|
|
125
142
|
if (query.category && event.category !== query.category) return false;
|
|
@@ -168,6 +185,26 @@ export function redactDebugData<T>(value: T): T {
|
|
|
168
185
|
return redactValue(value, 8) as T;
|
|
169
186
|
}
|
|
170
187
|
|
|
188
|
+
function toSanitizedView(event: DebugEvent): DebugEventView {
|
|
189
|
+
return {
|
|
190
|
+
id: event.id,
|
|
191
|
+
timestamp: event.timestamp,
|
|
192
|
+
source: event.source,
|
|
193
|
+
level: event.level,
|
|
194
|
+
category: event.category,
|
|
195
|
+
message: event.message,
|
|
196
|
+
cwd: event.cwd,
|
|
197
|
+
data: event.data,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Subscribe to sanitized events. Listeners are isolated so diagnostics cannot disrupt producers. */
|
|
202
|
+
export function subscribeDebugEvents(listener: DebugEventListener): () => void {
|
|
203
|
+
const state = getState();
|
|
204
|
+
state.listeners.add(listener);
|
|
205
|
+
return () => state.listeners.delete(listener);
|
|
206
|
+
}
|
|
207
|
+
|
|
171
208
|
/** Record a session-local debug event if debugging is enabled. */
|
|
172
209
|
export function recordDebugEvent(input: DebugEventInput): DebugEvent | null {
|
|
173
210
|
const state = getState();
|
|
@@ -183,6 +220,14 @@ export function recordDebugEvent(input: DebugEventInput): DebugEvent | null {
|
|
|
183
220
|
};
|
|
184
221
|
state.events.push(event);
|
|
185
222
|
trimToMaxEvents(state);
|
|
223
|
+
const view = toSanitizedView(event);
|
|
224
|
+
for (const listener of state.listeners) {
|
|
225
|
+
try {
|
|
226
|
+
listener(view);
|
|
227
|
+
} catch {
|
|
228
|
+
// Debug-event consumers must not alter producer behavior.
|
|
229
|
+
}
|
|
230
|
+
}
|
|
186
231
|
return { ...event };
|
|
187
232
|
}
|
|
188
233
|
|
|
@@ -196,21 +241,12 @@ export function getDebugEvents(query: DebugEventQuery = {}): DebugEventQueryResu
|
|
|
196
241
|
const limit = query.limit && query.limit > 0 ? Math.floor(query.limit) : state.config.maxEvents;
|
|
197
242
|
|
|
198
243
|
const events = state.events
|
|
199
|
-
.filter((event) =>
|
|
244
|
+
.filter((event) => matchesDebugEventQuery(event, query))
|
|
200
245
|
.slice()
|
|
201
246
|
.reverse()
|
|
202
247
|
.slice(0, limit)
|
|
203
248
|
.map((event): DebugEventView => {
|
|
204
|
-
const view
|
|
205
|
-
id: event.id,
|
|
206
|
-
timestamp: event.timestamp,
|
|
207
|
-
source: event.source,
|
|
208
|
-
level: event.level,
|
|
209
|
-
category: event.category,
|
|
210
|
-
message: event.message,
|
|
211
|
-
cwd: event.cwd,
|
|
212
|
-
data: event.data,
|
|
213
|
-
};
|
|
249
|
+
const view = toSanitizedView(event);
|
|
214
250
|
if (allowRaw && event.rawData !== undefined) {
|
|
215
251
|
view.rawData = event.rawData;
|
|
216
252
|
}
|
|
@@ -246,5 +282,6 @@ export function resetDebugRegistry(): void {
|
|
|
246
282
|
const state = getState();
|
|
247
283
|
state.config = cloneConfig(DEBUG_REGISTRY_DEFAULTS);
|
|
248
284
|
state.events = [];
|
|
285
|
+
state.listeners.clear();
|
|
249
286
|
state.nextId = 1;
|
|
250
287
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-settings",
|
|
3
|
-
"version": "4.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.7.0",
|
|
4
|
+
"description": "One project/global settings UI for SuPi packages",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"!__tests__"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@mrclrchtr/supi-core": "4.
|
|
33
|
+
"@mrclrchtr/supi-core": "4.7.0"
|
|
34
34
|
},
|
|
35
35
|
"bundledDependencies": [
|
|
36
36
|
"@mrclrchtr/supi-core"
|