@vobs/devtools 1.0.0 → 1.2.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.
- package/dist/index.cjs +1846 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +399 -0
- package/dist/index.d.ts +399 -0
- package/dist/index.js +1837 -0
- package/dist/index.js.map +1 -0
- package/package.json +23 -8
- package/src/index.ts +8 -6
package/dist/index.js
ADDED
|
@@ -0,0 +1,1837 @@
|
|
|
1
|
+
import 'axios';
|
|
2
|
+
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
5
|
+
|
|
6
|
+
// packages/reactivity/src/debug.ts
|
|
7
|
+
var activeDebugHooks = null;
|
|
8
|
+
var signalNames = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
function setDebugHooks(hooks) {
|
|
10
|
+
const previous = activeDebugHooks;
|
|
11
|
+
activeDebugHooks = hooks;
|
|
12
|
+
return previous;
|
|
13
|
+
}
|
|
14
|
+
__name(setDebugHooks, "setDebugHooks");
|
|
15
|
+
function getDebugHooks() {
|
|
16
|
+
return activeDebugHooks;
|
|
17
|
+
}
|
|
18
|
+
__name(getDebugHooks, "getDebugHooks");
|
|
19
|
+
function hasDebugHooks() {
|
|
20
|
+
return activeDebugHooks !== null;
|
|
21
|
+
}
|
|
22
|
+
__name(hasDebugHooks, "hasDebugHooks");
|
|
23
|
+
function getSignalDebugName(signal) {
|
|
24
|
+
return signalNames.get(signal);
|
|
25
|
+
}
|
|
26
|
+
__name(getSignalDebugName, "getSignalDebugName");
|
|
27
|
+
function invokeDebug(name, ...args) {
|
|
28
|
+
const callback = activeDebugHooks?.[name];
|
|
29
|
+
if (!callback) return;
|
|
30
|
+
try {
|
|
31
|
+
callback(...args);
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
__name(invokeDebug, "invokeDebug");
|
|
36
|
+
|
|
37
|
+
// packages/reactivity/src/owner.ts
|
|
38
|
+
var ownerNames = /* @__PURE__ */ new WeakMap();
|
|
39
|
+
function getOwnerDebugName(owner) {
|
|
40
|
+
return ownerNames.get(owner);
|
|
41
|
+
}
|
|
42
|
+
__name(getOwnerDebugName, "getOwnerDebugName");
|
|
43
|
+
function untrack(fn) {
|
|
44
|
+
try {
|
|
45
|
+
return fn();
|
|
46
|
+
} finally {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
__name(untrack, "untrack");
|
|
50
|
+
|
|
51
|
+
// packages/reactivity/src/scheduler.ts
|
|
52
|
+
var _Scheduler = class _Scheduler {
|
|
53
|
+
constructor() {
|
|
54
|
+
this.dirtyEffects = /* @__PURE__ */ new Set();
|
|
55
|
+
this.lowPriorityEffects = /* @__PURE__ */ new Set();
|
|
56
|
+
// flush 不可重入(flushing 标志保证),缓冲数组可在轮次间安全复用,避免每轮分配。
|
|
57
|
+
this.normalBuffer = [];
|
|
58
|
+
this.lowBuffer = [];
|
|
59
|
+
this.flushing = false;
|
|
60
|
+
this.scheduled = false;
|
|
61
|
+
this.batchDepth = 0;
|
|
62
|
+
}
|
|
63
|
+
schedule(effect2) {
|
|
64
|
+
if (effect2.disposed) return;
|
|
65
|
+
this.dirtyEffects.add(effect2);
|
|
66
|
+
this.lowPriorityEffects.delete(effect2);
|
|
67
|
+
this.ensureScheduled();
|
|
68
|
+
}
|
|
69
|
+
/** Queue an effect behind normal updates while preserving deterministic order. */
|
|
70
|
+
scheduleLow(effect2) {
|
|
71
|
+
if (effect2.disposed) return;
|
|
72
|
+
if (!this.dirtyEffects.has(effect2)) this.lowPriorityEffects.add(effect2);
|
|
73
|
+
this.ensureScheduled();
|
|
74
|
+
}
|
|
75
|
+
ensureScheduled() {
|
|
76
|
+
if (this.batchDepth === 0 && !this.flushing && !this.scheduled) {
|
|
77
|
+
this.scheduled = true;
|
|
78
|
+
queueMicrotask(() => {
|
|
79
|
+
this.scheduled = false;
|
|
80
|
+
this.flush();
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
remove(effect2) {
|
|
85
|
+
this.dirtyEffects.delete(effect2);
|
|
86
|
+
this.lowPriorityEffects.delete(effect2);
|
|
87
|
+
}
|
|
88
|
+
batch(fn) {
|
|
89
|
+
this.batchDepth++;
|
|
90
|
+
try {
|
|
91
|
+
return fn();
|
|
92
|
+
} finally {
|
|
93
|
+
this.batchDepth--;
|
|
94
|
+
if (this.batchDepth === 0) this.flush();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
flush() {
|
|
98
|
+
if (this.flushing || this.batchDepth > 0) return;
|
|
99
|
+
this.flushing = true;
|
|
100
|
+
const debugEnabled = hasDebugHooks();
|
|
101
|
+
if (debugEnabled) invokeDebug("flushStart");
|
|
102
|
+
let rounds = 0;
|
|
103
|
+
let firstError;
|
|
104
|
+
let hasError = false;
|
|
105
|
+
try {
|
|
106
|
+
while (this.dirtyEffects.size > 0 || this.lowPriorityEffects.size > 0) {
|
|
107
|
+
if (++rounds > 100) {
|
|
108
|
+
this.dirtyEffects.clear();
|
|
109
|
+
this.lowPriorityEffects.clear();
|
|
110
|
+
throw new Error("Vobs: \u54CD\u5E94\u5F0F\u66F4\u65B0\u8D85\u8FC7 100 \u8F6E\uFF0C\u53EF\u80FD\u5B58\u5728\u5FAA\u73AF\u4F9D\u8D56");
|
|
111
|
+
}
|
|
112
|
+
this.collectRunnable(this.dirtyEffects, this.normalBuffer);
|
|
113
|
+
this.collectRunnable(this.lowPriorityEffects, this.lowBuffer);
|
|
114
|
+
sortEffects(this.normalBuffer);
|
|
115
|
+
sortEffects(this.lowBuffer);
|
|
116
|
+
for (const effect2 of this.normalBuffer) {
|
|
117
|
+
try {
|
|
118
|
+
effect2.run();
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (!hasError) {
|
|
121
|
+
firstError = error;
|
|
122
|
+
hasError = true;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
for (const effect2 of this.lowBuffer) {
|
|
127
|
+
try {
|
|
128
|
+
effect2.run();
|
|
129
|
+
} catch (error) {
|
|
130
|
+
if (!hasError) {
|
|
131
|
+
firstError = error;
|
|
132
|
+
hasError = true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
this.normalBuffer.length = 0;
|
|
137
|
+
this.lowBuffer.length = 0;
|
|
138
|
+
}
|
|
139
|
+
} finally {
|
|
140
|
+
this.normalBuffer.length = 0;
|
|
141
|
+
this.lowBuffer.length = 0;
|
|
142
|
+
this.flushing = false;
|
|
143
|
+
if (debugEnabled) invokeDebug("flushEnd");
|
|
144
|
+
}
|
|
145
|
+
if (hasError) throw firstError;
|
|
146
|
+
}
|
|
147
|
+
/** 收集未 disposed 的 effect 并清空源集合;run() 期间新调度的 effect 留给下一轮。 */
|
|
148
|
+
collectRunnable(source, target) {
|
|
149
|
+
for (const effect2 of source) {
|
|
150
|
+
if (!effect2.disposed) target.push(effect2);
|
|
151
|
+
}
|
|
152
|
+
source.clear();
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
__name(_Scheduler, "Scheduler");
|
|
156
|
+
function sortEffects(effects) {
|
|
157
|
+
if (effects.length > 1) {
|
|
158
|
+
effects.sort((a, b) => b.depth - a.depth || a.order - b.order);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
__name(sortEffects, "sortEffects");
|
|
162
|
+
|
|
163
|
+
// packages/runtime/src/debug.ts
|
|
164
|
+
var activeRuntimeDebugHooks = null;
|
|
165
|
+
var activeRuntimeDebugContext = null;
|
|
166
|
+
function setRuntimeDebugHooks(hooks) {
|
|
167
|
+
const previous = activeRuntimeDebugHooks;
|
|
168
|
+
activeRuntimeDebugHooks = hooks;
|
|
169
|
+
return previous;
|
|
170
|
+
}
|
|
171
|
+
__name(setRuntimeDebugHooks, "setRuntimeDebugHooks");
|
|
172
|
+
function getRuntimeDebugHooks() {
|
|
173
|
+
return activeRuntimeDebugHooks;
|
|
174
|
+
}
|
|
175
|
+
__name(getRuntimeDebugHooks, "getRuntimeDebugHooks");
|
|
176
|
+
function getRuntimeDebugContext() {
|
|
177
|
+
return activeRuntimeDebugContext;
|
|
178
|
+
}
|
|
179
|
+
__name(getRuntimeDebugContext, "getRuntimeDebugContext");
|
|
180
|
+
|
|
181
|
+
// packages/runtime/src/hmr.ts
|
|
182
|
+
var globalTarget = globalThis;
|
|
183
|
+
var hmrGlobal = globalTarget.__VOBS_HMR__ ?? { modules: /* @__PURE__ */ new Map() };
|
|
184
|
+
globalTarget.__VOBS_HMR__ = hmrGlobal;
|
|
185
|
+
|
|
186
|
+
// packages/runtime/src/error.ts
|
|
187
|
+
var _VobsError = class _VobsError extends Error {
|
|
188
|
+
constructor(options) {
|
|
189
|
+
super(options.message);
|
|
190
|
+
this.name = "VobsError";
|
|
191
|
+
this.code = options.code;
|
|
192
|
+
this.severity = options.severity ?? "error";
|
|
193
|
+
this.layer = options.layer ?? "runtime";
|
|
194
|
+
this.cause = options.cause;
|
|
195
|
+
this.fix = options.fix;
|
|
196
|
+
this.location = options.location;
|
|
197
|
+
this.trace = options.trace;
|
|
198
|
+
this.example = options.example;
|
|
199
|
+
this.docs = options.docs;
|
|
200
|
+
this.codeFrame = options.codeFrame;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
__name(_VobsError, "VobsError");
|
|
204
|
+
var VobsError = _VobsError;
|
|
205
|
+
function isVobsError(value) {
|
|
206
|
+
return value instanceof VobsError || Boolean(value && typeof value === "object" && typeof value.code === "string" && typeof value.message === "string" && typeof value.layer === "string");
|
|
207
|
+
}
|
|
208
|
+
__name(isVobsError, "isVobsError");
|
|
209
|
+
function normalizeVobsError(value, defaults = {}) {
|
|
210
|
+
if (value instanceof VobsError) return value;
|
|
211
|
+
if (value instanceof Error) {
|
|
212
|
+
const metadata = value;
|
|
213
|
+
const code = defaults.code ?? (typeof metadata.vobsCode === "string" ? metadata.vobsCode : void 0);
|
|
214
|
+
if (code) defineErrorMetadata(value, "code", code);
|
|
215
|
+
defineErrorMetadata(value, "severity", defaults.severity ?? "error");
|
|
216
|
+
defineErrorMetadata(value, "layer", defaults.layer ?? "runtime");
|
|
217
|
+
const fix = defaults.fix ?? (typeof metadata.vobsHint === "string" ? metadata.vobsHint : void 0);
|
|
218
|
+
if (fix) defineErrorMetadata(value, "fix", fix);
|
|
219
|
+
const source = metadata.vobsSource;
|
|
220
|
+
if (source && typeof source === "object" && typeof source.file === "string" && typeof source.line === "number" && typeof source.column === "number") {
|
|
221
|
+
defineErrorMetadata(value, "location", source);
|
|
222
|
+
}
|
|
223
|
+
return value;
|
|
224
|
+
}
|
|
225
|
+
if (isVobsError(value)) {
|
|
226
|
+
const candidate = value;
|
|
227
|
+
return new VobsError({
|
|
228
|
+
code: candidate.code,
|
|
229
|
+
message: candidate.message,
|
|
230
|
+
severity: candidate.severity ?? defaults.severity,
|
|
231
|
+
layer: candidate.layer ?? defaults.layer,
|
|
232
|
+
cause: candidate.cause,
|
|
233
|
+
fix: candidate.fix ?? defaults.fix,
|
|
234
|
+
location: candidate.location,
|
|
235
|
+
trace: candidate.trace,
|
|
236
|
+
example: candidate.example,
|
|
237
|
+
docs: candidate.docs,
|
|
238
|
+
codeFrame: candidate.codeFrame
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
const message = String(value);
|
|
242
|
+
return new VobsError({
|
|
243
|
+
code: defaults.code ?? "VOBS_UNKNOWN",
|
|
244
|
+
message,
|
|
245
|
+
severity: defaults.severity ?? "error",
|
|
246
|
+
layer: defaults.layer ?? "runtime",
|
|
247
|
+
cause: void 0,
|
|
248
|
+
fix: defaults.fix
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
__name(normalizeVobsError, "normalizeVobsError");
|
|
252
|
+
function defineErrorMetadata(target, key, value) {
|
|
253
|
+
if (key in target) return;
|
|
254
|
+
try {
|
|
255
|
+
Object.defineProperty(target, key, { configurable: true, enumerable: false, value, writable: true });
|
|
256
|
+
} catch {
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
__name(defineErrorMetadata, "defineErrorMetadata");
|
|
260
|
+
|
|
261
|
+
// packages/vobs/src/app.ts
|
|
262
|
+
function createInjectionKey(description) {
|
|
263
|
+
return Symbol(description);
|
|
264
|
+
}
|
|
265
|
+
__name(createInjectionKey, "createInjectionKey");
|
|
266
|
+
|
|
267
|
+
// packages/http/src/debug.ts
|
|
268
|
+
var activeHTTPDebugHooks = null;
|
|
269
|
+
function setHTTPDebugHooks(hooks) {
|
|
270
|
+
const previous = activeHTTPDebugHooks;
|
|
271
|
+
activeHTTPDebugHooks = hooks;
|
|
272
|
+
return previous;
|
|
273
|
+
}
|
|
274
|
+
__name(setHTTPDebugHooks, "setHTTPDebugHooks");
|
|
275
|
+
function getHTTPDebugHooks() {
|
|
276
|
+
return activeHTTPDebugHooks;
|
|
277
|
+
}
|
|
278
|
+
__name(getHTTPDebugHooks, "getHTTPDebugHooks");
|
|
279
|
+
|
|
280
|
+
// packages/devtools/src/index.ts
|
|
281
|
+
var DEVTOOLS_REACTIVITY_EVENTS = [
|
|
282
|
+
"owner-created",
|
|
283
|
+
"owner-named",
|
|
284
|
+
"owner-disposed",
|
|
285
|
+
"signal-created",
|
|
286
|
+
"signal-named",
|
|
287
|
+
"signal-update",
|
|
288
|
+
"signal-disposed",
|
|
289
|
+
"effect-created",
|
|
290
|
+
"effect-invalidated",
|
|
291
|
+
"effect-run-start",
|
|
292
|
+
"effect-run",
|
|
293
|
+
"effect-disposed",
|
|
294
|
+
"memo-created",
|
|
295
|
+
"memo-update",
|
|
296
|
+
"update"
|
|
297
|
+
];
|
|
298
|
+
var DEVTOOLS_EVENTS = [...DEVTOOLS_REACTIVITY_EVENTS, "lifecycle", "dom-update", "network-request", "router", "error", "collection", "collection-cleared", "extension"];
|
|
299
|
+
var activeDevTools = null;
|
|
300
|
+
function createDevTools(options = {}) {
|
|
301
|
+
activeDevTools?.dispose();
|
|
302
|
+
const owners = /* @__PURE__ */ new Map();
|
|
303
|
+
const ownerIds = /* @__PURE__ */ new WeakMap();
|
|
304
|
+
const signals = /* @__PURE__ */ new Map();
|
|
305
|
+
const signalIds = /* @__PURE__ */ new WeakMap();
|
|
306
|
+
const effects = /* @__PURE__ */ new Map();
|
|
307
|
+
const effectIds = /* @__PURE__ */ new WeakMap();
|
|
308
|
+
const memoSignalIds = /* @__PURE__ */ new WeakMap();
|
|
309
|
+
const edges = /* @__PURE__ */ new Map();
|
|
310
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
311
|
+
const updates = [];
|
|
312
|
+
const lifecycleEvents = [];
|
|
313
|
+
const networkRequests = /* @__PURE__ */ new Map();
|
|
314
|
+
const errors = /* @__PURE__ */ new Map();
|
|
315
|
+
const inspectors = /* @__PURE__ */ new Map();
|
|
316
|
+
const timelines = /* @__PURE__ */ new Map();
|
|
317
|
+
const metrics = /* @__PURE__ */ new Map();
|
|
318
|
+
let routerContext = null;
|
|
319
|
+
const routerStops = /* @__PURE__ */ new Map();
|
|
320
|
+
let nextErrorId = 1;
|
|
321
|
+
let collectionPaused = false;
|
|
322
|
+
const pendingUpdates = [];
|
|
323
|
+
const updateDurations = [];
|
|
324
|
+
const maxUpdates = Math.max(1, Math.floor(options.maxUpdates ?? 100));
|
|
325
|
+
const slowUpdateThreshold = Math.max(0, options.slowUpdateThreshold ?? 16);
|
|
326
|
+
let nextId = 1;
|
|
327
|
+
let updateCount = 0;
|
|
328
|
+
let effectExecutionCount = 0;
|
|
329
|
+
let disposed = false;
|
|
330
|
+
let pendingFlushScheduled = false;
|
|
331
|
+
let activeEffectId = null;
|
|
332
|
+
const privacy = normalizePrivacyOptions(options.privacy);
|
|
333
|
+
const allowMutations = options.allowMutations === true;
|
|
334
|
+
function now() {
|
|
335
|
+
return typeof performance === "undefined" ? Date.now() : performance.now();
|
|
336
|
+
}
|
|
337
|
+
__name(now, "now");
|
|
338
|
+
function emit(event, ...args) {
|
|
339
|
+
if (collectionPaused && event !== "collection" && event !== "collection-cleared") return;
|
|
340
|
+
const callbacks = [
|
|
341
|
+
...listeners.get(event) ?? [],
|
|
342
|
+
...listeners.get("*") ?? []
|
|
343
|
+
];
|
|
344
|
+
for (const callback of callbacks) {
|
|
345
|
+
try {
|
|
346
|
+
callback(...args);
|
|
347
|
+
} catch {
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
__name(emit, "emit");
|
|
352
|
+
function safeExtensionCall(read, fallback) {
|
|
353
|
+
try {
|
|
354
|
+
return read();
|
|
355
|
+
} catch {
|
|
356
|
+
return fallback;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
__name(safeExtensionCall, "safeExtensionCall");
|
|
360
|
+
function getExtensionSnapshot() {
|
|
361
|
+
const extensionMetrics = {};
|
|
362
|
+
const extensionTimelineEvents = {};
|
|
363
|
+
for (const [id, timeline] of timelines) {
|
|
364
|
+
const events = safeExtensionCall(() => timeline.getEvents?.() ?? [], []);
|
|
365
|
+
extensionTimelineEvents[id] = events.map((event) => ({
|
|
366
|
+
...event,
|
|
367
|
+
data: serializeForDevTools(event.data, /* @__PURE__ */ new Set(), 0, privacy)
|
|
368
|
+
})).slice(-maxUpdates);
|
|
369
|
+
}
|
|
370
|
+
for (const [id, metric] of metrics) {
|
|
371
|
+
const value = safeExtensionCall(() => metric.read(), 0);
|
|
372
|
+
extensionMetrics[id] = typeof value === "number" || typeof value === "string" ? value : 0;
|
|
373
|
+
}
|
|
374
|
+
return {
|
|
375
|
+
inspectors: [...inspectors.keys()],
|
|
376
|
+
timelines: [...timelines.keys()],
|
|
377
|
+
timelineEvents: extensionTimelineEvents,
|
|
378
|
+
metrics: extensionMetrics
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
__name(getExtensionSnapshot, "getExtensionSnapshot");
|
|
382
|
+
function recordLifecycle(type, targetId, name, ownerId, status) {
|
|
383
|
+
if (disposed || collectionPaused || isInternalOwnerId(targetId) || ownerId !== void 0 && isInternalOwnerId(ownerId)) return;
|
|
384
|
+
const event = {
|
|
385
|
+
id: `lifecycle-${nextId++}`,
|
|
386
|
+
type,
|
|
387
|
+
timestamp: now(),
|
|
388
|
+
targetId,
|
|
389
|
+
name,
|
|
390
|
+
ownerId,
|
|
391
|
+
status
|
|
392
|
+
};
|
|
393
|
+
lifecycleEvents.push(event);
|
|
394
|
+
while (lifecycleEvents.length > maxUpdates) lifecycleEvents.shift();
|
|
395
|
+
emit("lifecycle", event);
|
|
396
|
+
}
|
|
397
|
+
__name(recordLifecycle, "recordLifecycle");
|
|
398
|
+
function reportError(phase, error, context = {}) {
|
|
399
|
+
if (collectionPaused) return;
|
|
400
|
+
const debugError = toDebugError(error, phase);
|
|
401
|
+
const metadata = classifyError(phase, error, context);
|
|
402
|
+
const code = context.code ?? debugError.code ?? metadata.code;
|
|
403
|
+
const hint = context.hint ?? debugError.hint ?? metadata.hint;
|
|
404
|
+
const origin = context.origin ?? metadata.origin;
|
|
405
|
+
const ownerId = context.ownerId ?? readErrorProperty(error, "vobsOwnerId");
|
|
406
|
+
const component = context.component ?? readErrorProperty(error, "vobsComponent");
|
|
407
|
+
const source = context.source ?? debugError.source ?? readErrorProperty(error, "vobsSource");
|
|
408
|
+
const activeRoute = context.route ?? getRuntimeDebugContext()?.route ?? routerContext?.route;
|
|
409
|
+
const activeNavigationId = context.navigationId ?? getRuntimeDebugContext()?.navigationId ?? routerContext?.navigationId;
|
|
410
|
+
const key = diagnosticErrorKey({ origin, code, name: debugError.name, message: debugError.message, source, component });
|
|
411
|
+
const previous = errors.get(key);
|
|
412
|
+
const nowValue = Date.now();
|
|
413
|
+
const trace = previous ? {
|
|
414
|
+
...previous,
|
|
415
|
+
...context,
|
|
416
|
+
phase,
|
|
417
|
+
phases: previous.phases.includes(phase) ? previous.phases : [...previous.phases, phase],
|
|
418
|
+
lastOccurredAt: nowValue,
|
|
419
|
+
count: previous.count + 1,
|
|
420
|
+
code,
|
|
421
|
+
hint,
|
|
422
|
+
origin,
|
|
423
|
+
handled: context.handled ?? previous.handled,
|
|
424
|
+
recovery: mergeRecovery(previous.recovery, context.recovery),
|
|
425
|
+
ownerId: ownerId ?? previous.ownerId,
|
|
426
|
+
component: component ?? previous.component,
|
|
427
|
+
source: source ?? previous.source,
|
|
428
|
+
updateId: context.updateId ?? previous.updateId,
|
|
429
|
+
effectId: context.effectId ?? previous.effectId,
|
|
430
|
+
requestId: context.requestId ?? previous.requestId,
|
|
431
|
+
route: activeRoute ?? previous.route,
|
|
432
|
+
navigationId: activeNavigationId ?? previous.navigationId
|
|
433
|
+
} : {
|
|
434
|
+
...debugError,
|
|
435
|
+
...context,
|
|
436
|
+
source,
|
|
437
|
+
code,
|
|
438
|
+
hint,
|
|
439
|
+
id: nextErrorId++,
|
|
440
|
+
phase,
|
|
441
|
+
phases: [phase],
|
|
442
|
+
origin,
|
|
443
|
+
handled: context.handled ?? false,
|
|
444
|
+
recovery: context.recovery ?? "propagated",
|
|
445
|
+
firstOccurredAt: nowValue,
|
|
446
|
+
lastOccurredAt: nowValue,
|
|
447
|
+
count: 1,
|
|
448
|
+
ownerId,
|
|
449
|
+
component,
|
|
450
|
+
route: activeRoute,
|
|
451
|
+
navigationId: activeNavigationId
|
|
452
|
+
};
|
|
453
|
+
errors.set(key, trace);
|
|
454
|
+
while (errors.size > maxUpdates) {
|
|
455
|
+
const oldest = errors.keys().next().value;
|
|
456
|
+
if (typeof oldest !== "string") break;
|
|
457
|
+
errors.delete(oldest);
|
|
458
|
+
}
|
|
459
|
+
emit("error", trace);
|
|
460
|
+
}
|
|
461
|
+
__name(reportError, "reportError");
|
|
462
|
+
function ensureOwner(owner) {
|
|
463
|
+
const existingId = ownerIds.get(owner);
|
|
464
|
+
if (existingId) {
|
|
465
|
+
const existing = owners.get(existingId);
|
|
466
|
+
if (existing) return existing;
|
|
467
|
+
}
|
|
468
|
+
const record = {
|
|
469
|
+
owner,
|
|
470
|
+
id: owner.id,
|
|
471
|
+
parentId: owner.parent?.id ?? null,
|
|
472
|
+
name: getOwnerDebugName(owner) ?? (owner.parent ? "Owner" : "App"),
|
|
473
|
+
disposed: owner.disposed
|
|
474
|
+
};
|
|
475
|
+
ownerIds.set(owner, record.id);
|
|
476
|
+
owners.set(record.id, record);
|
|
477
|
+
return record;
|
|
478
|
+
}
|
|
479
|
+
__name(ensureOwner, "ensureOwner");
|
|
480
|
+
function isInternalOwnerId(ownerId) {
|
|
481
|
+
const visited = /* @__PURE__ */ new Set();
|
|
482
|
+
let current = ownerId === void 0 ? null : ownerId;
|
|
483
|
+
while (current && !visited.has(current)) {
|
|
484
|
+
visited.add(current);
|
|
485
|
+
const record = owners.get(current);
|
|
486
|
+
if (!record) return false;
|
|
487
|
+
if (debugComponentName(record.name).startsWith("DevTools")) return true;
|
|
488
|
+
current = record.parentId;
|
|
489
|
+
}
|
|
490
|
+
return false;
|
|
491
|
+
}
|
|
492
|
+
__name(isInternalOwnerId, "isInternalOwnerId");
|
|
493
|
+
function isInternalSignal(record) {
|
|
494
|
+
return isInternalOwnerId(record.ownerId);
|
|
495
|
+
}
|
|
496
|
+
__name(isInternalSignal, "isInternalSignal");
|
|
497
|
+
function isNoisyViewportSignal(record) {
|
|
498
|
+
return record.explicitName && (record.name === "layout.viewport.width" || record.name === "layout.viewport.height");
|
|
499
|
+
}
|
|
500
|
+
__name(isNoisyViewportSignal, "isNoisyViewportSignal");
|
|
501
|
+
function hasMeaningfulDomUpdate(updates2) {
|
|
502
|
+
return updates2.some((update) => update.operation === "insert" || update.operation === "remove" || !Object.is(update.previousValue, update.nextValue));
|
|
503
|
+
}
|
|
504
|
+
__name(hasMeaningfulDomUpdate, "hasMeaningfulDomUpdate");
|
|
505
|
+
function isInternalEffect(record) {
|
|
506
|
+
return isInternalOwnerId(record.ownerId);
|
|
507
|
+
}
|
|
508
|
+
__name(isInternalEffect, "isInternalEffect");
|
|
509
|
+
function errorComponentForOwner(ownerId) {
|
|
510
|
+
if (!ownerId) return void 0;
|
|
511
|
+
const record = owners.get(ownerId);
|
|
512
|
+
if (!record) return void 0;
|
|
513
|
+
if (record.name !== "Owner" && record.name !== "dynamic") return record.name;
|
|
514
|
+
return errorComponentForOwner(record.parentId ?? void 0);
|
|
515
|
+
}
|
|
516
|
+
__name(errorComponentForOwner, "errorComponentForOwner");
|
|
517
|
+
function ensureSignal(signal, owner = null) {
|
|
518
|
+
const existingId = signalIds.get(signal);
|
|
519
|
+
if (existingId) {
|
|
520
|
+
const existing = signals.get(existingId);
|
|
521
|
+
if (existing) return existing;
|
|
522
|
+
}
|
|
523
|
+
const id = `signal-${nextId++}`;
|
|
524
|
+
const explicitName = getSignalDebugName(signal);
|
|
525
|
+
const ownerName = owner ? getOwnerDebugName(owner) : void 0;
|
|
526
|
+
const record = {
|
|
527
|
+
signal,
|
|
528
|
+
id,
|
|
529
|
+
ownerId: owner ? ensureOwner(owner).id : null,
|
|
530
|
+
createdAt: Date.now(),
|
|
531
|
+
name: explicitName ?? (ownerName ? `${ownerName} state` : "runtime state"),
|
|
532
|
+
explicitName: explicitName !== void 0,
|
|
533
|
+
kind: "state",
|
|
534
|
+
disposed: false
|
|
535
|
+
};
|
|
536
|
+
signalIds.set(signal, id);
|
|
537
|
+
signals.set(id, record);
|
|
538
|
+
return record;
|
|
539
|
+
}
|
|
540
|
+
__name(ensureSignal, "ensureSignal");
|
|
541
|
+
function ensureEffect(effect2, owner = null) {
|
|
542
|
+
const existingId = effectIds.get(effect2);
|
|
543
|
+
if (existingId) {
|
|
544
|
+
const existing = effects.get(existingId);
|
|
545
|
+
if (existing) return existing;
|
|
546
|
+
}
|
|
547
|
+
const id = `effect-${nextId++}`;
|
|
548
|
+
const record = {
|
|
549
|
+
effect: effect2,
|
|
550
|
+
id,
|
|
551
|
+
ownerId: owner ? ensureOwner(owner).id : null,
|
|
552
|
+
status: "dirty",
|
|
553
|
+
executionCount: 0,
|
|
554
|
+
lastExecutionTime: 0,
|
|
555
|
+
lastRunStatus: void 0,
|
|
556
|
+
lastDuration: 0,
|
|
557
|
+
lastUpdateId: void 0,
|
|
558
|
+
lastError: void 0,
|
|
559
|
+
lastDomUpdates: 0,
|
|
560
|
+
runningSince: null,
|
|
561
|
+
disposed: effect2.disposed
|
|
562
|
+
};
|
|
563
|
+
effectIds.set(effect2, id);
|
|
564
|
+
effects.set(id, record);
|
|
565
|
+
return record;
|
|
566
|
+
}
|
|
567
|
+
__name(ensureEffect, "ensureEffect");
|
|
568
|
+
function ensureDependencySignal(dependency) {
|
|
569
|
+
const existingId = signalIds.get(dependency);
|
|
570
|
+
if (existingId) return signals.get(existingId) ?? null;
|
|
571
|
+
if (!("value" in dependency)) return null;
|
|
572
|
+
return ensureSignal(dependency);
|
|
573
|
+
}
|
|
574
|
+
__name(ensureDependencySignal, "ensureDependencySignal");
|
|
575
|
+
function edgeKey(from, to) {
|
|
576
|
+
return `${from}->${to}`;
|
|
577
|
+
}
|
|
578
|
+
__name(edgeKey, "edgeKey");
|
|
579
|
+
function trackDependency2(dependency, subscriber) {
|
|
580
|
+
const source = ensureDependencySignal(dependency);
|
|
581
|
+
if (!source) return;
|
|
582
|
+
const memoId = memoSignalIds.get(subscriber);
|
|
583
|
+
const effectId = effectIds.get(subscriber);
|
|
584
|
+
const targetId = memoId ?? effectId;
|
|
585
|
+
if (!targetId) return;
|
|
586
|
+
const type = memoId ? source.kind === "memo" ? "memo-to-memo" : "state-to-memo" : source.kind === "memo" ? "memo-to-effect" : "state-to-effect";
|
|
587
|
+
edges.set(edgeKey(source.id, targetId), {
|
|
588
|
+
from: source.id,
|
|
589
|
+
to: targetId,
|
|
590
|
+
type
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
__name(trackDependency2, "trackDependency");
|
|
594
|
+
function collectEffectIds(signalId) {
|
|
595
|
+
const effectsForSignal = /* @__PURE__ */ new Set();
|
|
596
|
+
const visited = /* @__PURE__ */ new Set();
|
|
597
|
+
const visit = /* @__PURE__ */ __name((sourceId) => {
|
|
598
|
+
if (visited.has(sourceId)) return;
|
|
599
|
+
visited.add(sourceId);
|
|
600
|
+
for (const edge of edges.values()) {
|
|
601
|
+
if (edge.from !== sourceId) continue;
|
|
602
|
+
if (effects.has(edge.to)) {
|
|
603
|
+
const effect2 = effects.get(edge.to);
|
|
604
|
+
if (effect2 && !isInternalEffect(effect2)) effectsForSignal.add(edge.to);
|
|
605
|
+
} else visit(edge.to);
|
|
606
|
+
}
|
|
607
|
+
}, "visit");
|
|
608
|
+
visit(signalId);
|
|
609
|
+
return effectsForSignal;
|
|
610
|
+
}
|
|
611
|
+
__name(collectEffectIds, "collectEffectIds");
|
|
612
|
+
function collectAffectedSignals(signalId) {
|
|
613
|
+
const affected = /* @__PURE__ */ new Set();
|
|
614
|
+
const visited = /* @__PURE__ */ new Set();
|
|
615
|
+
const visit = /* @__PURE__ */ __name((sourceId) => {
|
|
616
|
+
if (visited.has(sourceId)) return;
|
|
617
|
+
visited.add(sourceId);
|
|
618
|
+
if (signals.has(sourceId)) affected.add(sourceId);
|
|
619
|
+
for (const edge of edges.values()) {
|
|
620
|
+
if (edge.from === sourceId && signals.has(edge.to)) visit(edge.to);
|
|
621
|
+
}
|
|
622
|
+
}, "visit");
|
|
623
|
+
visit(signalId);
|
|
624
|
+
return affected;
|
|
625
|
+
}
|
|
626
|
+
__name(collectAffectedSignals, "collectAffectedSignals");
|
|
627
|
+
function untrackDependency(dependency, subscriber) {
|
|
628
|
+
const source = ensureDependencySignal(dependency);
|
|
629
|
+
if (!source) return;
|
|
630
|
+
const targetId = memoSignalIds.get(subscriber) ?? effectIds.get(subscriber);
|
|
631
|
+
if (targetId) edges.delete(edgeKey(source.id, targetId));
|
|
632
|
+
}
|
|
633
|
+
__name(untrackDependency, "untrackDependency");
|
|
634
|
+
function signalInfo(record, readValue = true) {
|
|
635
|
+
return {
|
|
636
|
+
id: record.id,
|
|
637
|
+
name: record.name,
|
|
638
|
+
value: readValue ? serializeForDevTools(readSignal(record.signal), /* @__PURE__ */ new Set(), 0, privacy) : void 0,
|
|
639
|
+
component: record.ownerId ? owners.get(record.ownerId)?.name ?? "unknown" : "unknown",
|
|
640
|
+
subscribers: [...edges.values()].filter((edge) => edge.from === record.id).length,
|
|
641
|
+
createdAt: record.createdAt,
|
|
642
|
+
kind: record.kind
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
__name(signalInfo, "signalInfo");
|
|
646
|
+
function readSignal(signal) {
|
|
647
|
+
try {
|
|
648
|
+
return untrack(() => signal.value);
|
|
649
|
+
} catch (error) {
|
|
650
|
+
return { type: "thrown", message: toErrorMessage(error) };
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
__name(readSignal, "readSignal");
|
|
654
|
+
function effectInfo(record) {
|
|
655
|
+
const component = record.ownerId ? owners.get(record.ownerId)?.name ?? "unknown" : "runtime";
|
|
656
|
+
return {
|
|
657
|
+
id: record.id,
|
|
658
|
+
name: `${debugComponentName(component)} effect`,
|
|
659
|
+
component,
|
|
660
|
+
dependencies: [...edges.values()].filter((edge) => edge.to === record.id).map((edge) => edge.from),
|
|
661
|
+
status: record.status,
|
|
662
|
+
executionCount: record.executionCount,
|
|
663
|
+
lastExecutionTime: record.lastExecutionTime,
|
|
664
|
+
lastRunStatus: record.lastRunStatus,
|
|
665
|
+
lastDuration: record.lastDuration,
|
|
666
|
+
lastUpdateId: record.lastUpdateId,
|
|
667
|
+
lastError: record.lastError,
|
|
668
|
+
lastDomUpdates: record.lastDomUpdates
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
__name(effectInfo, "effectInfo");
|
|
672
|
+
function removeEdgesFor(ids) {
|
|
673
|
+
for (const [key, edge] of edges) {
|
|
674
|
+
if (ids.has(edge.from) || ids.has(edge.to)) edges.delete(key);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
__name(removeEdgesFor, "removeEdgesFor");
|
|
678
|
+
function cleanupSignalRecord(record) {
|
|
679
|
+
if (signals.get(record.id) !== record) return;
|
|
680
|
+
removeEdgesFor(/* @__PURE__ */ new Set([record.id]));
|
|
681
|
+
signals.delete(record.id);
|
|
682
|
+
}
|
|
683
|
+
__name(cleanupSignalRecord, "cleanupSignalRecord");
|
|
684
|
+
function cleanupEffectRecord(record) {
|
|
685
|
+
if (effects.get(record.id) !== record) return;
|
|
686
|
+
removeEdgesFor(/* @__PURE__ */ new Set([record.id]));
|
|
687
|
+
effects.delete(record.id);
|
|
688
|
+
}
|
|
689
|
+
__name(cleanupEffectRecord, "cleanupEffectRecord");
|
|
690
|
+
function cleanupOwnerRecord(record) {
|
|
691
|
+
if (owners.get(record.id) !== record) return;
|
|
692
|
+
const removedIds = /* @__PURE__ */ new Set([record.id]);
|
|
693
|
+
for (const [id, signal] of signals) {
|
|
694
|
+
if (signal.ownerId === record.id) {
|
|
695
|
+
removedIds.add(id);
|
|
696
|
+
signals.delete(id);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
for (const [id, effect2] of effects) {
|
|
700
|
+
if (effect2.ownerId === record.id) {
|
|
701
|
+
removedIds.add(id);
|
|
702
|
+
effects.delete(id);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
removeEdgesFor(removedIds);
|
|
706
|
+
owners.delete(record.id);
|
|
707
|
+
}
|
|
708
|
+
__name(cleanupOwnerRecord, "cleanupOwnerRecord");
|
|
709
|
+
function debugComponentName(value) {
|
|
710
|
+
const separator = value.indexOf(" (");
|
|
711
|
+
return separator > 0 ? value.slice(0, separator) : value;
|
|
712
|
+
}
|
|
713
|
+
__name(debugComponentName, "debugComponentName");
|
|
714
|
+
function buildComponentNode(record, activeIds) {
|
|
715
|
+
const componentEffects = [...effects.values()].filter((effect2) => !effect2.disposed && effect2.ownerId === record.id);
|
|
716
|
+
const componentEffectIds = new Set(componentEffects.map((effect2) => effect2.id));
|
|
717
|
+
const componentUpdates = updates.filter((update) => update.effects.some((effect2) => componentEffectIds.has(effect2.effectId)));
|
|
718
|
+
return {
|
|
719
|
+
id: record.id,
|
|
720
|
+
name: record.name,
|
|
721
|
+
ownerId: record.id,
|
|
722
|
+
signals: [...signals.values()].filter((signal) => !signal.disposed && signal.ownerId === record.id).map((signal) => signal.id),
|
|
723
|
+
effects: componentEffects.map((effect2) => effect2.id),
|
|
724
|
+
recentUpdates: componentUpdates.slice(-10).map((update) => update.id),
|
|
725
|
+
domUpdates: componentUpdates.reduce((count, update) => count + update.domUpdates.length, 0),
|
|
726
|
+
children: [...owners.values()].filter((child) => !child.disposed && child.parentId === record.id && activeIds.has(child.id)).map((child) => buildComponentNode(child, activeIds)),
|
|
727
|
+
mounted: !record.disposed
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
__name(buildComponentNode, "buildComponentNode");
|
|
731
|
+
function recordUpdate(pending) {
|
|
732
|
+
if (disposed || collectionPaused || isInternalSignal(pending.signal)) return;
|
|
733
|
+
if (isNoisyViewportSignal(pending.signal) && !hasMeaningfulDomUpdate(pending.domUpdates)) return;
|
|
734
|
+
const duration = Math.max(0, now() - pending.timestamp);
|
|
735
|
+
const trace = {
|
|
736
|
+
id: pending.id,
|
|
737
|
+
signalId: pending.signal.id,
|
|
738
|
+
signalName: pending.signal.name,
|
|
739
|
+
previousValue: serializeForDevTools(pending.previousValue, /* @__PURE__ */ new Set(), 0, privacy),
|
|
740
|
+
nextValue: serializeForDevTools(pending.nextValue, /* @__PURE__ */ new Set(), 0, privacy),
|
|
741
|
+
timestamp: pending.timestamp,
|
|
742
|
+
effects: [...pending.executions.values()],
|
|
743
|
+
affectedSignals: [...pending.affectedSignals],
|
|
744
|
+
affectedEffects: [...pending.effectIds],
|
|
745
|
+
domUpdates: pending.domUpdates.slice(),
|
|
746
|
+
status: pending.status,
|
|
747
|
+
error: pending.error,
|
|
748
|
+
duration,
|
|
749
|
+
route: pending.context.route,
|
|
750
|
+
navigationId: pending.context.navigationId,
|
|
751
|
+
requestIds: [...pending.context.requestIds]
|
|
752
|
+
};
|
|
753
|
+
updates.push(trace);
|
|
754
|
+
while (updates.length > maxUpdates) updates.shift();
|
|
755
|
+
updateDurations.push(duration);
|
|
756
|
+
while (updateDurations.length > maxUpdates) updateDurations.shift();
|
|
757
|
+
updateCount++;
|
|
758
|
+
emit("update", trace);
|
|
759
|
+
}
|
|
760
|
+
__name(recordUpdate, "recordUpdate");
|
|
761
|
+
function onFlushEnd() {
|
|
762
|
+
const current = pendingUpdates.splice(0);
|
|
763
|
+
for (const pending of current) recordUpdate(pending);
|
|
764
|
+
}
|
|
765
|
+
__name(onFlushEnd, "onFlushEnd");
|
|
766
|
+
function schedulePendingFlush() {
|
|
767
|
+
if (pendingFlushScheduled) return;
|
|
768
|
+
pendingFlushScheduled = true;
|
|
769
|
+
queueMicrotask(() => {
|
|
770
|
+
if (disposed) {
|
|
771
|
+
pendingUpdates.length = 0;
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
pendingFlushScheduled = false;
|
|
775
|
+
for (let index = pendingUpdates.length - 1; index >= 0; index--) {
|
|
776
|
+
const pending = pendingUpdates[index];
|
|
777
|
+
if (!pending || pending.effectIds.size > 0) continue;
|
|
778
|
+
pendingUpdates.splice(index, 1);
|
|
779
|
+
recordUpdate(pending);
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
__name(schedulePendingFlush, "schedulePendingFlush");
|
|
784
|
+
const hooks = {
|
|
785
|
+
ownerCreated(owner) {
|
|
786
|
+
const record = ensureOwner(owner);
|
|
787
|
+
recordLifecycle("owner-created", record.id, record.name, record.parentId ?? void 0);
|
|
788
|
+
emit("owner-created", record);
|
|
789
|
+
},
|
|
790
|
+
ownerNamed(owner, name) {
|
|
791
|
+
const record = ensureOwner(owner);
|
|
792
|
+
record.name = name;
|
|
793
|
+
if (isInternalOwnerId(record.id)) return;
|
|
794
|
+
for (const signal of signals.values()) {
|
|
795
|
+
if (signal.ownerId === record.id && !signal.explicitName) signal.name = `${name} state`;
|
|
796
|
+
}
|
|
797
|
+
recordLifecycle("owner-named", record.id, name, record.parentId ?? void 0);
|
|
798
|
+
emit("owner-named", record);
|
|
799
|
+
},
|
|
800
|
+
ownerDisposed(owner) {
|
|
801
|
+
const record = ensureOwner(owner);
|
|
802
|
+
record.disposed = true;
|
|
803
|
+
const internal = isInternalOwnerId(record.id);
|
|
804
|
+
if (!internal) {
|
|
805
|
+
recordLifecycle("owner-disposed", record.id, record.name, record.parentId ?? void 0);
|
|
806
|
+
emit("owner-disposed", record);
|
|
807
|
+
}
|
|
808
|
+
cleanupOwnerRecord(record);
|
|
809
|
+
},
|
|
810
|
+
signalCreated(signal, owner) {
|
|
811
|
+
const record = ensureSignal(signal, owner);
|
|
812
|
+
if (isInternalSignal(record)) return;
|
|
813
|
+
recordLifecycle("signal-created", record.id, record.name, record.ownerId ?? void 0);
|
|
814
|
+
emit("signal-created", signalInfo(record, false));
|
|
815
|
+
},
|
|
816
|
+
signalNamed(signal, name) {
|
|
817
|
+
const record = ensureSignal(signal);
|
|
818
|
+
record.name = name;
|
|
819
|
+
record.explicitName = true;
|
|
820
|
+
if (isInternalSignal(record)) return;
|
|
821
|
+
recordLifecycle("signal-named", record.id, name, record.ownerId ?? void 0);
|
|
822
|
+
emit("signal-named", signalInfo(record));
|
|
823
|
+
},
|
|
824
|
+
signalRead(signal, subscriber) {
|
|
825
|
+
ensureSignal(signal);
|
|
826
|
+
emit("signal-read", signal, subscriber);
|
|
827
|
+
},
|
|
828
|
+
signalChanged(signal, previousValue, nextValue) {
|
|
829
|
+
const record = ensureSignal(signal);
|
|
830
|
+
if (isInternalSignal(record)) return;
|
|
831
|
+
let pending = pendingUpdates.find((item) => item.signal.signal === signal);
|
|
832
|
+
if (pending) {
|
|
833
|
+
pending.nextValue = nextValue;
|
|
834
|
+
} else {
|
|
835
|
+
pending = {
|
|
836
|
+
id: `update-${nextId++}`,
|
|
837
|
+
signal: record,
|
|
838
|
+
timestamp: now(),
|
|
839
|
+
previousValue,
|
|
840
|
+
nextValue,
|
|
841
|
+
affectedSignals: collectAffectedSignals(record.id),
|
|
842
|
+
effectIds: collectEffectIds(record.id),
|
|
843
|
+
executions: /* @__PURE__ */ new Map(),
|
|
844
|
+
domUpdates: [],
|
|
845
|
+
status: "completed",
|
|
846
|
+
error: void 0,
|
|
847
|
+
context: {
|
|
848
|
+
route: getRuntimeDebugContext()?.route,
|
|
849
|
+
navigationId: getRuntimeDebugContext()?.navigationId,
|
|
850
|
+
requestIds: new Set(
|
|
851
|
+
[]
|
|
852
|
+
)
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
pendingUpdates.push(pending);
|
|
856
|
+
}
|
|
857
|
+
emit("signal-update", {
|
|
858
|
+
...signalInfo(record),
|
|
859
|
+
previousValue: serializeForDevTools(previousValue, /* @__PURE__ */ new Set(), 0, privacy),
|
|
860
|
+
nextValue: serializeForDevTools(nextValue, /* @__PURE__ */ new Set(), 0, privacy),
|
|
861
|
+
updateId: pending.id
|
|
862
|
+
});
|
|
863
|
+
recordLifecycle("signal-changed", record.id, record.name, record.ownerId ?? void 0);
|
|
864
|
+
if (pending.effectIds.size === 0) schedulePendingFlush();
|
|
865
|
+
},
|
|
866
|
+
signalDisposed(signal) {
|
|
867
|
+
const record = ensureSignal(signal);
|
|
868
|
+
record.disposed = true;
|
|
869
|
+
const internal = isInternalSignal(record);
|
|
870
|
+
if (!internal) {
|
|
871
|
+
recordLifecycle("signal-disposed", record.id, record.name, record.ownerId ?? void 0);
|
|
872
|
+
emit("signal-disposed", record);
|
|
873
|
+
}
|
|
874
|
+
cleanupSignalRecord(record);
|
|
875
|
+
},
|
|
876
|
+
dependencyTracked(dependency, subscriber) {
|
|
877
|
+
trackDependency2(dependency, subscriber);
|
|
878
|
+
},
|
|
879
|
+
dependencyUntracked(dependency, subscriber) {
|
|
880
|
+
untrackDependency(dependency, subscriber);
|
|
881
|
+
},
|
|
882
|
+
effectCreated(effect2, owner) {
|
|
883
|
+
const record = ensureEffect(effect2, owner);
|
|
884
|
+
if (isInternalEffect(record)) return;
|
|
885
|
+
recordLifecycle("effect-created", record.id, effectInfo(record).name, record.ownerId ?? void 0);
|
|
886
|
+
emit("effect-created", effectInfo(record));
|
|
887
|
+
},
|
|
888
|
+
effectInvalidated(effect2) {
|
|
889
|
+
const record = ensureEffect(effect2);
|
|
890
|
+
if (isInternalEffect(record)) return;
|
|
891
|
+
record.status = "dirty";
|
|
892
|
+
recordLifecycle("effect-invalidated", record.id, effectInfo(record).name, record.ownerId ?? void 0);
|
|
893
|
+
emit("effect-invalidated", effectInfo(record));
|
|
894
|
+
},
|
|
895
|
+
effectRunStart(effect2) {
|
|
896
|
+
const record = ensureEffect(effect2);
|
|
897
|
+
if (isInternalEffect(record)) return;
|
|
898
|
+
record.status = "running";
|
|
899
|
+
record.runningSince = now();
|
|
900
|
+
activeEffectId = record.id;
|
|
901
|
+
recordLifecycle("effect-run-start", record.id, effectInfo(record).name, record.ownerId ?? void 0);
|
|
902
|
+
emit("effect-run-start", effectInfo(record));
|
|
903
|
+
},
|
|
904
|
+
effectRunEnd(effect2, error, handled = false) {
|
|
905
|
+
const record = ensureEffect(effect2);
|
|
906
|
+
if (isInternalEffect(record)) return;
|
|
907
|
+
const end = now();
|
|
908
|
+
const duration = record.runningSince === null ? 0 : Math.max(0, end - record.runningSince);
|
|
909
|
+
const runStatus = error === void 0 ? "success" : "error";
|
|
910
|
+
const debugError = error === void 0 ? void 0 : toDebugError(error, "effect");
|
|
911
|
+
record.status = runStatus;
|
|
912
|
+
record.runningSince = null;
|
|
913
|
+
record.executionCount++;
|
|
914
|
+
record.lastExecutionTime = end;
|
|
915
|
+
record.lastRunStatus = runStatus;
|
|
916
|
+
record.lastDuration = duration;
|
|
917
|
+
record.lastError = debugError;
|
|
918
|
+
effectExecutionCount++;
|
|
919
|
+
const execution = {
|
|
920
|
+
effectId: record.id,
|
|
921
|
+
component: record.ownerId ? owners.get(record.ownerId)?.name ?? "unknown" : "unknown",
|
|
922
|
+
duration,
|
|
923
|
+
domUpdates: 0,
|
|
924
|
+
status: runStatus,
|
|
925
|
+
error: debugError
|
|
926
|
+
};
|
|
927
|
+
for (const pending of pendingUpdates) {
|
|
928
|
+
if (!pending.effectIds.has(record.id)) continue;
|
|
929
|
+
const domUpdates = pending.domUpdates.filter((update) => update.effectId === record.id).length;
|
|
930
|
+
const completedExecution = { ...execution, domUpdates };
|
|
931
|
+
pending.executions.set(record.id, completedExecution);
|
|
932
|
+
if (error !== void 0) {
|
|
933
|
+
pending.status = "error";
|
|
934
|
+
pending.error = debugError;
|
|
935
|
+
}
|
|
936
|
+
record.lastUpdateId = pending.id;
|
|
937
|
+
record.lastDomUpdates = domUpdates;
|
|
938
|
+
}
|
|
939
|
+
activeEffectId = null;
|
|
940
|
+
if (error !== void 0) {
|
|
941
|
+
const update = [...pendingUpdates].reverse().find((item) => item.effectIds.has(record.id));
|
|
942
|
+
const errorOwnerId = readErrorProperty(error, "vobsOwnerId");
|
|
943
|
+
const errorComponent = readErrorProperty(error, "vobsComponent");
|
|
944
|
+
reportError("effect", error, {
|
|
945
|
+
effectId: record.id,
|
|
946
|
+
updateId: update?.id,
|
|
947
|
+
ownerId: errorOwnerId ?? record.ownerId ?? void 0,
|
|
948
|
+
component: errorComponent ?? errorComponentForOwner(record.ownerId ?? void 0),
|
|
949
|
+
handled,
|
|
950
|
+
recovery: handled ? "handled" : "propagated"
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
recordLifecycle("effect-run", record.id, effectInfo(record).name, record.ownerId ?? void 0, runStatus);
|
|
954
|
+
emit("effect-run", execution);
|
|
955
|
+
},
|
|
956
|
+
effectDisposed(effect2) {
|
|
957
|
+
const record = ensureEffect(effect2);
|
|
958
|
+
const internal = isInternalEffect(record);
|
|
959
|
+
record.disposed = true;
|
|
960
|
+
record.status = "idle";
|
|
961
|
+
if (!internal) {
|
|
962
|
+
recordLifecycle("effect-disposed", record.id, effectInfo(record).name, record.ownerId ?? void 0);
|
|
963
|
+
emit("effect-disposed", record);
|
|
964
|
+
}
|
|
965
|
+
cleanupEffectRecord(record);
|
|
966
|
+
},
|
|
967
|
+
memoCreated(signal, subscriber, owner) {
|
|
968
|
+
const record = ensureSignal(signal, owner);
|
|
969
|
+
record.kind = "memo";
|
|
970
|
+
memoSignalIds.set(subscriber, record.id);
|
|
971
|
+
if (isInternalSignal(record)) return;
|
|
972
|
+
recordLifecycle("memo-created", record.id, record.name, record.ownerId ?? void 0);
|
|
973
|
+
emit("memo-created", signalInfo(record));
|
|
974
|
+
},
|
|
975
|
+
memoInvalidated(signal) {
|
|
976
|
+
const record = ensureSignal(signal);
|
|
977
|
+
if (isInternalSignal(record)) return;
|
|
978
|
+
recordLifecycle("memo-invalidated", record.id, record.name, record.ownerId ?? void 0);
|
|
979
|
+
emit("memo-update", signalInfo(record));
|
|
980
|
+
},
|
|
981
|
+
flushEnd: onFlushEnd
|
|
982
|
+
};
|
|
983
|
+
const runtimeHooks = {
|
|
984
|
+
domMutation(mutation) {
|
|
985
|
+
if (!activeEffectId) return;
|
|
986
|
+
const effect2 = effects.get(activeEffectId);
|
|
987
|
+
if (!effect2 || isInternalEffect(effect2)) return;
|
|
988
|
+
const safeMutation = {
|
|
989
|
+
...mutation,
|
|
990
|
+
previousValue: privacy.redactDomValues ? privacy.replacement : serializeForDevTools(mutation.previousValue, /* @__PURE__ */ new Set(), 0, privacy),
|
|
991
|
+
nextValue: privacy.redactDomValues ? privacy.replacement : serializeForDevTools(mutation.nextValue, /* @__PURE__ */ new Set(), 0, privacy),
|
|
992
|
+
effectId: activeEffectId,
|
|
993
|
+
route: getRuntimeDebugContext()?.route,
|
|
994
|
+
navigationId: getRuntimeDebugContext()?.navigationId,
|
|
995
|
+
requestId: getRuntimeDebugContext()?.dataRequestId
|
|
996
|
+
};
|
|
997
|
+
for (const pending of pendingUpdates) {
|
|
998
|
+
if (pending.effectIds.has(activeEffectId)) {
|
|
999
|
+
pending.domUpdates.push(safeMutation);
|
|
1000
|
+
if (safeMutation.route) pending.context = { ...pending.context, route: safeMutation.route };
|
|
1001
|
+
if (safeMutation.navigationId !== void 0) pending.context = { ...pending.context, navigationId: safeMutation.navigationId };
|
|
1002
|
+
if (safeMutation.requestId !== void 0) pending.context.requestIds.add(safeMutation.requestId);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
emit("dom-update", safeMutation);
|
|
1006
|
+
},
|
|
1007
|
+
hydrationMismatch(event) {
|
|
1008
|
+
reportError("hydration", Object.assign(new Error(event.message), {
|
|
1009
|
+
name: "HydrationMismatchError",
|
|
1010
|
+
vobsCode: "VOBS_HYDRATION_MISMATCH",
|
|
1011
|
+
vobsHydration: event
|
|
1012
|
+
}), {
|
|
1013
|
+
route: getRuntimeDebugContext()?.route,
|
|
1014
|
+
navigationId: getRuntimeDebugContext()?.navigationId
|
|
1015
|
+
});
|
|
1016
|
+
},
|
|
1017
|
+
error(event) {
|
|
1018
|
+
const owner = ensureOwner(event.owner);
|
|
1019
|
+
const errorOwnerId = readErrorProperty(event.error, "vobsOwnerId");
|
|
1020
|
+
const errorComponent = readErrorProperty(event.error, "vobsComponent");
|
|
1021
|
+
reportError(event.phase === "boundary" ? "boundary" : "event", event.error, {
|
|
1022
|
+
ownerId: errorOwnerId ?? owner.id,
|
|
1023
|
+
component: errorComponent ?? errorComponentForOwner(owner.id ?? void 0) ?? owner.name,
|
|
1024
|
+
handled: event.handled,
|
|
1025
|
+
recovery: event.recovery
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
const httpHooks = {
|
|
1030
|
+
request(event) {
|
|
1031
|
+
if (collectionPaused) return;
|
|
1032
|
+
const previous = networkRequests.get(event.id);
|
|
1033
|
+
const trace = {
|
|
1034
|
+
id: event.id,
|
|
1035
|
+
url: event.url,
|
|
1036
|
+
method: event.method,
|
|
1037
|
+
status: event.status,
|
|
1038
|
+
headers: redactHeaders(event.headers, privacy),
|
|
1039
|
+
requestBody: serializeForDevTools(event.requestBody, /* @__PURE__ */ new Set(), 0, privacy),
|
|
1040
|
+
startedAt: previous?.startedAt ?? event.startedAt,
|
|
1041
|
+
endedAt: event.endedAt,
|
|
1042
|
+
duration: event.duration,
|
|
1043
|
+
attempt: Math.max(event.attempt, previous?.attempt ?? 0),
|
|
1044
|
+
retries: Math.max(event.retries, previous?.retries ?? 0),
|
|
1045
|
+
responseStatus: event.responseStatus,
|
|
1046
|
+
responseBody: serializeForDevTools(event.responseBody, /* @__PURE__ */ new Set(), 0, privacy),
|
|
1047
|
+
error: event.error,
|
|
1048
|
+
source: event.context?.environment === "server" ? "ssr" : "http",
|
|
1049
|
+
test: event.context?.test,
|
|
1050
|
+
route: event.context?.route,
|
|
1051
|
+
navigationId: event.context?.navigationId,
|
|
1052
|
+
dataRequestId: event.context?.dataRequestId,
|
|
1053
|
+
environment: event.context?.environment
|
|
1054
|
+
};
|
|
1055
|
+
for (const pending of pendingUpdates) {
|
|
1056
|
+
if (event.context?.dataRequestId !== void 0 && pending.context.requestIds.has(event.context.dataRequestId)) pending.context.requestIds.add(event.id);
|
|
1057
|
+
if (activeEffectId !== null && pending.effectIds.has(activeEffectId)) pending.context.requestIds.add(event.id);
|
|
1058
|
+
}
|
|
1059
|
+
networkRequests.set(event.id, trace);
|
|
1060
|
+
while (networkRequests.size > maxUpdates) {
|
|
1061
|
+
const oldest = networkRequests.keys().next().value;
|
|
1062
|
+
if (typeof oldest !== "number") break;
|
|
1063
|
+
networkRequests.delete(oldest);
|
|
1064
|
+
}
|
|
1065
|
+
emit("network-request", trace);
|
|
1066
|
+
if (event.error) reportError("network", new Error(event.error.message), {
|
|
1067
|
+
requestId: event.id,
|
|
1068
|
+
route: event.context?.route,
|
|
1069
|
+
navigationId: event.context?.navigationId
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1073
|
+
function importSSRRequests(snapshot) {
|
|
1074
|
+
if (disposed) return;
|
|
1075
|
+
const events = parseSSRRequestSnapshot(snapshot);
|
|
1076
|
+
const ids = /* @__PURE__ */ new Map();
|
|
1077
|
+
for (const event of events) {
|
|
1078
|
+
const importedId = ids.get(event.id) ?? -(event.id + 1);
|
|
1079
|
+
ids.set(event.id, importedId);
|
|
1080
|
+
const trace = {
|
|
1081
|
+
id: importedId,
|
|
1082
|
+
url: event.url,
|
|
1083
|
+
method: event.method,
|
|
1084
|
+
status: event.status,
|
|
1085
|
+
headers: redactHeaders(event.headers, privacy),
|
|
1086
|
+
requestBody: serializeForDevTools(event.requestBody, /* @__PURE__ */ new Set(), 0, privacy),
|
|
1087
|
+
startedAt: event.startedAt,
|
|
1088
|
+
endedAt: event.endedAt,
|
|
1089
|
+
duration: event.duration,
|
|
1090
|
+
attempt: event.attempt,
|
|
1091
|
+
retries: event.retries,
|
|
1092
|
+
responseStatus: event.responseStatus,
|
|
1093
|
+
responseBody: serializeForDevTools(event.responseBody, /* @__PURE__ */ new Set(), 0, privacy),
|
|
1094
|
+
error: event.error,
|
|
1095
|
+
source: "ssr",
|
|
1096
|
+
test: event.context?.test,
|
|
1097
|
+
route: event.context?.route,
|
|
1098
|
+
navigationId: event.context?.navigationId,
|
|
1099
|
+
dataRequestId: event.context?.dataRequestId,
|
|
1100
|
+
environment: "server"
|
|
1101
|
+
};
|
|
1102
|
+
networkRequests.set(importedId, trace);
|
|
1103
|
+
}
|
|
1104
|
+
while (networkRequests.size > maxUpdates) {
|
|
1105
|
+
const oldest = networkRequests.keys().next().value;
|
|
1106
|
+
if (typeof oldest !== "number") break;
|
|
1107
|
+
networkRequests.delete(oldest);
|
|
1108
|
+
}
|
|
1109
|
+
emit("network-request", { source: "ssr", imported: events.length });
|
|
1110
|
+
}
|
|
1111
|
+
__name(importSSRRequests, "importSSRRequests");
|
|
1112
|
+
const previousHooks = getDebugHooks();
|
|
1113
|
+
const previousRuntimeHooks = getRuntimeDebugHooks();
|
|
1114
|
+
const previousHTTPHooks = getHTTPDebugHooks();
|
|
1115
|
+
setDebugHooks(hooks);
|
|
1116
|
+
setRuntimeDebugHooks(runtimeHooks);
|
|
1117
|
+
setHTTPDebugHooks(httpHooks);
|
|
1118
|
+
const target = options.target ?? defaultTarget();
|
|
1119
|
+
const shouldExpose = options.expose ?? Boolean(target);
|
|
1120
|
+
const previousGlobal = target?.__VOBS_DEVTOOLS__;
|
|
1121
|
+
let api;
|
|
1122
|
+
const onGlobalError = /* @__PURE__ */ __name((event) => {
|
|
1123
|
+
const source = typeof event.filename === "string" && event.filename ? `${event.filename}:${typeof event.lineno === "number" ? event.lineno : 0}:${typeof event.colno === "number" ? event.colno : 0}` : void 0;
|
|
1124
|
+
reportError("global", event.error ?? event.message ?? "Unknown global error", { source });
|
|
1125
|
+
}, "onGlobalError");
|
|
1126
|
+
const onUnhandledRejection = /* @__PURE__ */ __name((event) => {
|
|
1127
|
+
reportError("unhandledrejection", event.reason ?? "Unhandled promise rejection");
|
|
1128
|
+
}, "onUnhandledRejection");
|
|
1129
|
+
target?.addEventListener?.("error", onGlobalError);
|
|
1130
|
+
target?.addEventListener?.("unhandledrejection", onUnhandledRejection);
|
|
1131
|
+
function subscribe(event, callback) {
|
|
1132
|
+
if (disposed) return () => void 0;
|
|
1133
|
+
const callbacks = listeners.get(event) ?? /* @__PURE__ */ new Set();
|
|
1134
|
+
callbacks.add(callback);
|
|
1135
|
+
listeners.set(event, callbacks);
|
|
1136
|
+
return () => {
|
|
1137
|
+
callbacks.delete(callback);
|
|
1138
|
+
if (callbacks.size === 0 && listeners.get(event) === callbacks) listeners.delete(event);
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
__name(subscribe, "subscribe");
|
|
1142
|
+
function attachRouter(router) {
|
|
1143
|
+
const existing = routerStops.get(router);
|
|
1144
|
+
if (existing) {
|
|
1145
|
+
existing.refs++;
|
|
1146
|
+
let released2 = false;
|
|
1147
|
+
return () => {
|
|
1148
|
+
if (released2) return;
|
|
1149
|
+
released2 = true;
|
|
1150
|
+
existing.refs--;
|
|
1151
|
+
if (existing.refs === 0) existing.stop();
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
const source = router.devtools;
|
|
1155
|
+
const initialRoute = source.getCurrentRoute?.();
|
|
1156
|
+
const initialState = source.getNavigationState?.();
|
|
1157
|
+
routerContext = {
|
|
1158
|
+
route: typeof initialRoute?.fullPath === "string" ? initialRoute.fullPath : routerContext?.route,
|
|
1159
|
+
navigationId: typeof initialState?.traceId === "number" ? initialState.traceId : routerContext?.navigationId,
|
|
1160
|
+
navigationStatus: typeof initialState?.status === "string" ? initialState.status : routerContext?.navigationStatus,
|
|
1161
|
+
dataRequests: source.getDataRequests?.() ?? routerContext?.dataRequests ?? []
|
|
1162
|
+
};
|
|
1163
|
+
const stops = [
|
|
1164
|
+
router.devtools.subscribe("navigation:start", (payload) => {
|
|
1165
|
+
const value = payload;
|
|
1166
|
+
routerContext = {
|
|
1167
|
+
route: typeof value.to === "string" ? value.to : routerContext?.route,
|
|
1168
|
+
navigationId: typeof value.traceId === "number" ? value.traceId : routerContext?.navigationId,
|
|
1169
|
+
navigationStatus: typeof value.status === "string" ? value.status : void 0,
|
|
1170
|
+
dataRequests: routerContext?.dataRequests ?? []
|
|
1171
|
+
};
|
|
1172
|
+
emit("router", { type: "navigation:start", payload });
|
|
1173
|
+
}),
|
|
1174
|
+
router.devtools.subscribe("navigation:end", (payload) => {
|
|
1175
|
+
const value = payload;
|
|
1176
|
+
routerContext = {
|
|
1177
|
+
route: typeof value.to === "string" ? value.to : routerContext?.route,
|
|
1178
|
+
navigationId: typeof value.id === "number" ? value.id : routerContext?.navigationId,
|
|
1179
|
+
navigationStatus: typeof value.status === "string" ? value.status : void 0,
|
|
1180
|
+
dataRequests: routerContext?.dataRequests ?? []
|
|
1181
|
+
};
|
|
1182
|
+
emit("router", { type: "navigation:end", payload });
|
|
1183
|
+
}),
|
|
1184
|
+
router.devtools.subscribe("data-request", (payload) => {
|
|
1185
|
+
const request = payload;
|
|
1186
|
+
const requests = [...routerContext?.dataRequests ?? []];
|
|
1187
|
+
const existingIndex = requests.findIndex((item) => item.id === request.id);
|
|
1188
|
+
if (existingIndex >= 0) requests[existingIndex] = request;
|
|
1189
|
+
else requests.push(request);
|
|
1190
|
+
requests.splice(0, Math.max(0, requests.length - maxUpdates));
|
|
1191
|
+
routerContext = { ...routerContext, dataRequests: requests };
|
|
1192
|
+
emit("router", { type: "data-request", payload });
|
|
1193
|
+
}),
|
|
1194
|
+
router.devtools.subscribe("route:update", (payload) => {
|
|
1195
|
+
const value = payload;
|
|
1196
|
+
if (typeof value.fullPath === "string") routerContext = { ...routerContext, route: value.fullPath, dataRequests: routerContext?.dataRequests ?? [] };
|
|
1197
|
+
emit("router", { type: "route:update", payload });
|
|
1198
|
+
}),
|
|
1199
|
+
router.devtools.subscribe("error", (payload) => {
|
|
1200
|
+
const value = payload;
|
|
1201
|
+
reportError("route", Object.assign(new Error(typeof value.message === "string" ? value.message : "Router error"), {
|
|
1202
|
+
stack: value.stack
|
|
1203
|
+
}), {
|
|
1204
|
+
route: typeof value.route === "string" ? value.route : routerContext?.route,
|
|
1205
|
+
requestId: typeof value.requestId === "number" ? value.requestId : void 0,
|
|
1206
|
+
navigationId: typeof value.navigationId === "number" ? value.navigationId : void 0
|
|
1207
|
+
});
|
|
1208
|
+
emit("router", { type: "error", payload });
|
|
1209
|
+
})
|
|
1210
|
+
];
|
|
1211
|
+
const stop = /* @__PURE__ */ __name(() => {
|
|
1212
|
+
const current = routerStops.get(router);
|
|
1213
|
+
if (!current || current.stop !== stop) return;
|
|
1214
|
+
for (const stop2 of stops) stop2();
|
|
1215
|
+
routerStops.delete(router);
|
|
1216
|
+
}, "stop");
|
|
1217
|
+
routerStops.set(router, { stop, refs: 1 });
|
|
1218
|
+
let released = false;
|
|
1219
|
+
return () => {
|
|
1220
|
+
if (released) return;
|
|
1221
|
+
released = true;
|
|
1222
|
+
const current = routerStops.get(router);
|
|
1223
|
+
if (!current) return;
|
|
1224
|
+
current.refs--;
|
|
1225
|
+
if (current.refs === 0) current.stop();
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
__name(attachRouter, "attachRouter");
|
|
1229
|
+
api = {
|
|
1230
|
+
getComponentTree() {
|
|
1231
|
+
const active = [...owners.values()].filter((owner) => !owner.disposed && !isInternalOwnerId(owner.id));
|
|
1232
|
+
const activeIds = new Set(active.map((owner) => owner.id));
|
|
1233
|
+
return active.filter((owner) => owner.parentId === null || !activeIds.has(owner.parentId)).map((owner) => buildComponentNode(owner, activeIds));
|
|
1234
|
+
},
|
|
1235
|
+
getComponent(ownerId) {
|
|
1236
|
+
const active = [...owners.values()].filter((owner) => !owner.disposed && !isInternalOwnerId(owner.id));
|
|
1237
|
+
const activeIds = new Set(active.map((owner) => owner.id));
|
|
1238
|
+
const find = /* @__PURE__ */ __name((records) => {
|
|
1239
|
+
for (const record of records) {
|
|
1240
|
+
if (!activeIds.has(record.id)) continue;
|
|
1241
|
+
if (record.id === ownerId) return buildComponentNode(record, activeIds);
|
|
1242
|
+
const child = find(active.filter((candidate) => candidate.parentId === record.id));
|
|
1243
|
+
if (child) return child;
|
|
1244
|
+
}
|
|
1245
|
+
return null;
|
|
1246
|
+
}, "find");
|
|
1247
|
+
return find(active.filter((owner) => owner.parentId === null || !activeIds.has(owner.parentId)));
|
|
1248
|
+
},
|
|
1249
|
+
getSignals() {
|
|
1250
|
+
return [...signals.values()].filter((signal) => !signal.disposed && !isInternalSignal(signal)).map((signal) => signalInfo(signal));
|
|
1251
|
+
},
|
|
1252
|
+
getSignal(signalId) {
|
|
1253
|
+
const record = signals.get(signalId);
|
|
1254
|
+
return record && !record.disposed && !isInternalSignal(record) ? signalInfo(record) : null;
|
|
1255
|
+
},
|
|
1256
|
+
canMutate() {
|
|
1257
|
+
return allowMutations && !disposed;
|
|
1258
|
+
},
|
|
1259
|
+
setSignalValue(signalId, value) {
|
|
1260
|
+
if (!allowMutations || disposed) return false;
|
|
1261
|
+
const record = signals.get(signalId);
|
|
1262
|
+
if (!record || record.disposed || record.kind !== "state") return false;
|
|
1263
|
+
try {
|
|
1264
|
+
;
|
|
1265
|
+
record.signal.value = value;
|
|
1266
|
+
return true;
|
|
1267
|
+
} catch (error) {
|
|
1268
|
+
reportError("render", error);
|
|
1269
|
+
return false;
|
|
1270
|
+
}
|
|
1271
|
+
},
|
|
1272
|
+
getDependencies(signalId) {
|
|
1273
|
+
return [...edges.values()].filter((edge) => edge.from === signalId);
|
|
1274
|
+
},
|
|
1275
|
+
getDependents(subscriberId) {
|
|
1276
|
+
return [...edges.values()].filter((edge) => edge.to === subscriberId);
|
|
1277
|
+
},
|
|
1278
|
+
getEffects() {
|
|
1279
|
+
return [...effects.values()].filter((effect2) => !effect2.disposed && !isInternalEffect(effect2)).map(effectInfo);
|
|
1280
|
+
},
|
|
1281
|
+
getUpdates() {
|
|
1282
|
+
return updates.slice();
|
|
1283
|
+
},
|
|
1284
|
+
getLifecycleEvents() {
|
|
1285
|
+
return lifecycleEvents.slice();
|
|
1286
|
+
},
|
|
1287
|
+
getNetworkRequests() {
|
|
1288
|
+
return [...networkRequests.values()];
|
|
1289
|
+
},
|
|
1290
|
+
importSSRRequests,
|
|
1291
|
+
getRouterContext() {
|
|
1292
|
+
return routerContext ? { ...routerContext, dataRequests: [...routerContext.dataRequests] } : null;
|
|
1293
|
+
},
|
|
1294
|
+
attachRouter,
|
|
1295
|
+
getErrors() {
|
|
1296
|
+
return [...errors.values()];
|
|
1297
|
+
},
|
|
1298
|
+
getPerformanceEntries() {
|
|
1299
|
+
const entries = [];
|
|
1300
|
+
for (const update of updates) {
|
|
1301
|
+
entries.push({
|
|
1302
|
+
kind: "update",
|
|
1303
|
+
id: update.id,
|
|
1304
|
+
label: update.signalName,
|
|
1305
|
+
duration: update.duration,
|
|
1306
|
+
timestamp: update.timestamp,
|
|
1307
|
+
status: update.status
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
for (const effect2 of effects.values()) {
|
|
1311
|
+
if (effect2.disposed || isInternalEffect(effect2) || effect2.lastDuration <= 0) continue;
|
|
1312
|
+
entries.push({
|
|
1313
|
+
kind: "effect",
|
|
1314
|
+
id: effect2.id,
|
|
1315
|
+
label: effectInfo(effect2).name,
|
|
1316
|
+
duration: effect2.lastDuration,
|
|
1317
|
+
timestamp: effect2.lastExecutionTime,
|
|
1318
|
+
status: effect2.lastRunStatus ?? effect2.status
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
for (const request of networkRequests.values()) {
|
|
1322
|
+
if (request.duration === void 0) continue;
|
|
1323
|
+
entries.push({
|
|
1324
|
+
kind: "request",
|
|
1325
|
+
id: request.id,
|
|
1326
|
+
label: `${request.method} ${request.url}`,
|
|
1327
|
+
duration: request.duration,
|
|
1328
|
+
timestamp: request.startedAt,
|
|
1329
|
+
status: request.status
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
return entries.sort((left, right) => right.duration - left.duration);
|
|
1333
|
+
},
|
|
1334
|
+
reportError,
|
|
1335
|
+
getCollectionState() {
|
|
1336
|
+
return { paused: collectionPaused };
|
|
1337
|
+
},
|
|
1338
|
+
setCollectionPaused(paused) {
|
|
1339
|
+
collectionPaused = paused;
|
|
1340
|
+
if (paused) pendingUpdates.length = 0;
|
|
1341
|
+
emit("collection", { paused });
|
|
1342
|
+
},
|
|
1343
|
+
clearUpdates() {
|
|
1344
|
+
pendingUpdates.length = 0;
|
|
1345
|
+
updates.length = 0;
|
|
1346
|
+
updateDurations.length = 0;
|
|
1347
|
+
updateCount = 0;
|
|
1348
|
+
emit("collection-cleared", "updates");
|
|
1349
|
+
},
|
|
1350
|
+
clearNetworkRequests() {
|
|
1351
|
+
networkRequests.clear();
|
|
1352
|
+
emit("collection-cleared", "network");
|
|
1353
|
+
},
|
|
1354
|
+
clearErrors() {
|
|
1355
|
+
errors.clear();
|
|
1356
|
+
emit("collection-cleared", "errors");
|
|
1357
|
+
},
|
|
1358
|
+
clearLifecycleEvents() {
|
|
1359
|
+
lifecycleEvents.length = 0;
|
|
1360
|
+
emit("collection-cleared", "lifecycle");
|
|
1361
|
+
},
|
|
1362
|
+
getPerformanceMetrics() {
|
|
1363
|
+
const total = updateDurations.reduce((sum, duration) => sum + duration, 0);
|
|
1364
|
+
const effectDurations = [...effects.values()].filter((effect2) => !effect2.disposed).map((effect2) => effect2.lastDuration).filter((duration) => duration > 0);
|
|
1365
|
+
const requestDurations = [...networkRequests.values()].map((request) => request.duration ?? 0).filter((duration) => duration > 0);
|
|
1366
|
+
return {
|
|
1367
|
+
updateCount,
|
|
1368
|
+
averageUpdateDuration: updateDurations.length === 0 ? 0 : total / updateDurations.length,
|
|
1369
|
+
slowUpdateCount: updateDurations.filter((duration) => duration > slowUpdateThreshold).length,
|
|
1370
|
+
effectExecutionCount,
|
|
1371
|
+
slowEffectCount: effectDurations.filter((duration) => duration > slowUpdateThreshold).length,
|
|
1372
|
+
slowRequestCount: requestDurations.filter((duration) => duration > slowUpdateThreshold).length,
|
|
1373
|
+
maxUpdateDuration: updateDurations.length === 0 ? 0 : Math.max(...updateDurations),
|
|
1374
|
+
maxEffectDuration: effectDurations.length === 0 ? 0 : Math.max(...effectDurations),
|
|
1375
|
+
maxRequestDuration: requestDurations.length === 0 ? 0 : Math.max(...requestDurations)
|
|
1376
|
+
};
|
|
1377
|
+
},
|
|
1378
|
+
takeMemorySnapshot() {
|
|
1379
|
+
return {
|
|
1380
|
+
signalCount: [...signals.values()].filter((signal) => !signal.disposed && !isInternalSignal(signal)).length,
|
|
1381
|
+
effectCount: [...effects.values()].filter((effect2) => !effect2.disposed && !isInternalEffect(effect2)).length,
|
|
1382
|
+
ownerCount: [...owners.values()].filter((owner) => !owner.disposed && !isInternalOwnerId(owner.id)).length,
|
|
1383
|
+
dependencyEdgeCount: edges.size,
|
|
1384
|
+
leakedOwners: [...owners.values()].filter((owner) => owner.disposed).length
|
|
1385
|
+
};
|
|
1386
|
+
},
|
|
1387
|
+
exportDiagnostics() {
|
|
1388
|
+
return {
|
|
1389
|
+
version: 1,
|
|
1390
|
+
exportedAt: Date.now(),
|
|
1391
|
+
updates: api.getUpdates(),
|
|
1392
|
+
lifecycle: api.getLifecycleEvents(),
|
|
1393
|
+
network: api.getNetworkRequests(),
|
|
1394
|
+
errors: api.getErrors(),
|
|
1395
|
+
performance: api.getPerformanceMetrics(),
|
|
1396
|
+
memory: api.takeMemorySnapshot(),
|
|
1397
|
+
extensions: getExtensionSnapshot()
|
|
1398
|
+
};
|
|
1399
|
+
},
|
|
1400
|
+
importDiagnostics(snapshot) {
|
|
1401
|
+
const imported = parseDiagnosticSnapshot(snapshot);
|
|
1402
|
+
updates.splice(0, updates.length, ...imported.updates.slice(-maxUpdates).map((update) => sanitizeImportedUpdate(update, privacy)));
|
|
1403
|
+
lifecycleEvents.splice(0, lifecycleEvents.length, ...imported.lifecycle.slice(-maxUpdates));
|
|
1404
|
+
networkRequests.clear();
|
|
1405
|
+
for (const request of imported.network.slice(-maxUpdates)) networkRequests.set(request.id, sanitizeImportedRequest(request, privacy));
|
|
1406
|
+
errors.clear();
|
|
1407
|
+
for (const error of imported.errors.slice(-maxUpdates)) {
|
|
1408
|
+
const normalized = sanitizeImportedError(error);
|
|
1409
|
+
errors.set(diagnosticErrorKey(normalized), normalized);
|
|
1410
|
+
}
|
|
1411
|
+
updateDurations.splice(0, updateDurations.length, ...updates.map((update) => update.duration));
|
|
1412
|
+
updateCount = imported.performance.updateCount;
|
|
1413
|
+
effectExecutionCount = imported.performance.effectExecutionCount;
|
|
1414
|
+
emit("collection", { imported: true });
|
|
1415
|
+
},
|
|
1416
|
+
registerInspector(id, inspector) {
|
|
1417
|
+
if (disposed || !id) return () => void 0;
|
|
1418
|
+
inspectors.set(id, inspector);
|
|
1419
|
+
emit("extension", { type: "inspector", id });
|
|
1420
|
+
return () => {
|
|
1421
|
+
if (inspectors.get(id) === inspector) inspectors.delete(id);
|
|
1422
|
+
};
|
|
1423
|
+
},
|
|
1424
|
+
registerTimeline(id, timeline = {}) {
|
|
1425
|
+
if (disposed || !id) return () => void 0;
|
|
1426
|
+
timelines.set(id, timeline);
|
|
1427
|
+
emit("extension", { type: "timeline", id });
|
|
1428
|
+
return () => {
|
|
1429
|
+
if (timelines.get(id) === timeline) timelines.delete(id);
|
|
1430
|
+
};
|
|
1431
|
+
},
|
|
1432
|
+
registerMetric(id, metric) {
|
|
1433
|
+
if (disposed || !id) return () => void 0;
|
|
1434
|
+
metrics.set(id, metric);
|
|
1435
|
+
emit("extension", { type: "metric", id });
|
|
1436
|
+
return () => {
|
|
1437
|
+
if (metrics.get(id) === metric) metrics.delete(id);
|
|
1438
|
+
};
|
|
1439
|
+
},
|
|
1440
|
+
getExtensionSnapshot,
|
|
1441
|
+
inspectExtension(id, value) {
|
|
1442
|
+
const inspector = inspectors.get(id);
|
|
1443
|
+
if (!inspector) return void 0;
|
|
1444
|
+
return safeExtensionCall(
|
|
1445
|
+
() => serializeForDevTools(inspector.inspect(value), /* @__PURE__ */ new Set(), 0, privacy),
|
|
1446
|
+
void 0
|
|
1447
|
+
);
|
|
1448
|
+
},
|
|
1449
|
+
onUpdate(callback) {
|
|
1450
|
+
return subscribe("update", callback);
|
|
1451
|
+
},
|
|
1452
|
+
subscribe,
|
|
1453
|
+
dispose() {
|
|
1454
|
+
if (disposed) return;
|
|
1455
|
+
disposed = true;
|
|
1456
|
+
if (getDebugHooks() === hooks) setDebugHooks(previousHooks);
|
|
1457
|
+
if (getRuntimeDebugHooks() === runtimeHooks) setRuntimeDebugHooks(previousRuntimeHooks);
|
|
1458
|
+
if (getHTTPDebugHooks() === httpHooks) setHTTPDebugHooks(previousHTTPHooks);
|
|
1459
|
+
if (activeDevTools === api) activeDevTools = null;
|
|
1460
|
+
if (target && target.__VOBS_DEVTOOLS__ === api) {
|
|
1461
|
+
if (previousGlobal) target.__VOBS_DEVTOOLS__ = previousGlobal;
|
|
1462
|
+
else delete target.__VOBS_DEVTOOLS__;
|
|
1463
|
+
}
|
|
1464
|
+
target?.removeEventListener?.("error", onGlobalError);
|
|
1465
|
+
target?.removeEventListener?.("unhandledrejection", onUnhandledRejection);
|
|
1466
|
+
listeners.clear();
|
|
1467
|
+
for (const { stop } of [...routerStops.values()]) stop();
|
|
1468
|
+
routerStops.clear();
|
|
1469
|
+
routerContext = null;
|
|
1470
|
+
pendingUpdates.length = 0;
|
|
1471
|
+
pendingFlushScheduled = false;
|
|
1472
|
+
activeEffectId = null;
|
|
1473
|
+
inspectors.clear();
|
|
1474
|
+
timelines.clear();
|
|
1475
|
+
metrics.clear();
|
|
1476
|
+
}
|
|
1477
|
+
};
|
|
1478
|
+
if (shouldExpose && target) target.__VOBS_DEVTOOLS__ = api;
|
|
1479
|
+
activeDevTools = api;
|
|
1480
|
+
if (options.router) attachRouter(options.router);
|
|
1481
|
+
return api;
|
|
1482
|
+
}
|
|
1483
|
+
__name(createDevTools, "createDevTools");
|
|
1484
|
+
function enableDevTools(options = {}) {
|
|
1485
|
+
return createDevTools(options);
|
|
1486
|
+
}
|
|
1487
|
+
__name(enableDevTools, "enableDevTools");
|
|
1488
|
+
function disableDevTools() {
|
|
1489
|
+
activeDevTools?.dispose();
|
|
1490
|
+
}
|
|
1491
|
+
__name(disableDevTools, "disableDevTools");
|
|
1492
|
+
function getDevTools() {
|
|
1493
|
+
return activeDevTools;
|
|
1494
|
+
}
|
|
1495
|
+
__name(getDevTools, "getDevTools");
|
|
1496
|
+
function connectDevTools(options = {}) {
|
|
1497
|
+
const target = options.target ?? defaultMessageTarget();
|
|
1498
|
+
const api = options.api ?? activeDevTools;
|
|
1499
|
+
if (!target || !api) return () => void 0;
|
|
1500
|
+
const send = /* @__PURE__ */ __name((message) => {
|
|
1501
|
+
try {
|
|
1502
|
+
target.postMessage(message, "*");
|
|
1503
|
+
} catch {
|
|
1504
|
+
}
|
|
1505
|
+
}, "send");
|
|
1506
|
+
const unsubscribes = DEVTOOLS_EVENTS.map((event) => api.subscribe(event, (...args) => {
|
|
1507
|
+
send({
|
|
1508
|
+
source: "vobs-devtools",
|
|
1509
|
+
type: "event",
|
|
1510
|
+
event,
|
|
1511
|
+
payload: args.length === 1 ? args[0] : args
|
|
1512
|
+
});
|
|
1513
|
+
}));
|
|
1514
|
+
const onMessage = /* @__PURE__ */ __name((event) => {
|
|
1515
|
+
const request = parseRequest(event.data);
|
|
1516
|
+
if (!request) return;
|
|
1517
|
+
try {
|
|
1518
|
+
send({
|
|
1519
|
+
source: "vobs-devtools",
|
|
1520
|
+
type: "response",
|
|
1521
|
+
id: request.id,
|
|
1522
|
+
ok: true,
|
|
1523
|
+
result: invokeRequest(api, request)
|
|
1524
|
+
});
|
|
1525
|
+
} catch (error) {
|
|
1526
|
+
send({
|
|
1527
|
+
source: "vobs-devtools",
|
|
1528
|
+
type: "response",
|
|
1529
|
+
id: request.id,
|
|
1530
|
+
ok: false,
|
|
1531
|
+
error: toErrorMessage(error)
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
}, "onMessage");
|
|
1535
|
+
target.addEventListener("message", onMessage);
|
|
1536
|
+
return () => {
|
|
1537
|
+
target.removeEventListener("message", onMessage);
|
|
1538
|
+
for (const unsubscribe of unsubscribes) unsubscribe();
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1541
|
+
__name(connectDevTools, "connectDevTools");
|
|
1542
|
+
function devtoolsPlugin(options = {}) {
|
|
1543
|
+
return {
|
|
1544
|
+
name: "@vobs/devtools",
|
|
1545
|
+
version: "0.1.0",
|
|
1546
|
+
install(context) {
|
|
1547
|
+
if (options.enabled === false) return;
|
|
1548
|
+
const devtools = createDevTools(options);
|
|
1549
|
+
const removeErrorObserver = context.onError((error) => {
|
|
1550
|
+
const phase = readErrorProperty(error, "vobsCode") === "VOBS_HYDRATION_MISMATCH" || Boolean(readErrorProperty(error, "vobsHydration")) ? "hydration" : "application";
|
|
1551
|
+
devtools.reportError(phase, error, {
|
|
1552
|
+
handled: false,
|
|
1553
|
+
recovery: "propagated"
|
|
1554
|
+
});
|
|
1555
|
+
});
|
|
1556
|
+
return () => {
|
|
1557
|
+
removeErrorObserver();
|
|
1558
|
+
devtools.dispose();
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
__name(devtoolsPlugin, "devtoolsPlugin");
|
|
1564
|
+
function defaultTarget() {
|
|
1565
|
+
return typeof window === "undefined" ? void 0 : window;
|
|
1566
|
+
}
|
|
1567
|
+
__name(defaultTarget, "defaultTarget");
|
|
1568
|
+
function defaultMessageTarget() {
|
|
1569
|
+
return typeof window === "undefined" ? void 0 : window;
|
|
1570
|
+
}
|
|
1571
|
+
__name(defaultMessageTarget, "defaultMessageTarget");
|
|
1572
|
+
function parseRequest(value) {
|
|
1573
|
+
if (!value || typeof value !== "object") return null;
|
|
1574
|
+
const request = value;
|
|
1575
|
+
if (request.source !== "vobs-devtools" || request.type !== "request") return null;
|
|
1576
|
+
if (typeof request.id !== "string" || typeof request.method !== "string") return null;
|
|
1577
|
+
return request;
|
|
1578
|
+
}
|
|
1579
|
+
__name(parseRequest, "parseRequest");
|
|
1580
|
+
function invokeRequest(api, request) {
|
|
1581
|
+
const args = request.args ?? [];
|
|
1582
|
+
switch (request.method) {
|
|
1583
|
+
case "getComponentTree":
|
|
1584
|
+
return api.getComponentTree();
|
|
1585
|
+
case "getComponent":
|
|
1586
|
+
return api.getComponent(String(args[0] ?? ""));
|
|
1587
|
+
case "getSignals":
|
|
1588
|
+
return api.getSignals();
|
|
1589
|
+
case "getSignal":
|
|
1590
|
+
return api.getSignal(String(args[0] ?? ""));
|
|
1591
|
+
case "canMutate":
|
|
1592
|
+
return api.canMutate();
|
|
1593
|
+
case "setSignalValue":
|
|
1594
|
+
return api.setSignalValue(String(args[0] ?? ""), args[1]);
|
|
1595
|
+
case "getDependencies":
|
|
1596
|
+
return api.getDependencies(String(args[0] ?? ""));
|
|
1597
|
+
case "getDependents":
|
|
1598
|
+
return api.getDependents(String(args[0] ?? ""));
|
|
1599
|
+
case "getEffects":
|
|
1600
|
+
return api.getEffects();
|
|
1601
|
+
case "getUpdates":
|
|
1602
|
+
return api.getUpdates();
|
|
1603
|
+
case "getLifecycleEvents":
|
|
1604
|
+
return api.getLifecycleEvents();
|
|
1605
|
+
case "getNetworkRequests":
|
|
1606
|
+
return api.getNetworkRequests();
|
|
1607
|
+
case "importSSRRequests":
|
|
1608
|
+
api.importSSRRequests(args[0]);
|
|
1609
|
+
return void 0;
|
|
1610
|
+
case "getRouterContext":
|
|
1611
|
+
return api.getRouterContext();
|
|
1612
|
+
case "getErrors":
|
|
1613
|
+
return api.getErrors();
|
|
1614
|
+
case "getPerformanceEntries":
|
|
1615
|
+
return api.getPerformanceEntries();
|
|
1616
|
+
case "getCollectionState":
|
|
1617
|
+
return api.getCollectionState();
|
|
1618
|
+
case "setCollectionPaused":
|
|
1619
|
+
api.setCollectionPaused(Boolean(args[0]));
|
|
1620
|
+
return void 0;
|
|
1621
|
+
case "clearUpdates":
|
|
1622
|
+
api.clearUpdates();
|
|
1623
|
+
return void 0;
|
|
1624
|
+
case "clearNetworkRequests":
|
|
1625
|
+
api.clearNetworkRequests();
|
|
1626
|
+
return void 0;
|
|
1627
|
+
case "clearErrors":
|
|
1628
|
+
api.clearErrors();
|
|
1629
|
+
return void 0;
|
|
1630
|
+
case "clearLifecycleEvents":
|
|
1631
|
+
api.clearLifecycleEvents();
|
|
1632
|
+
return void 0;
|
|
1633
|
+
case "getPerformanceMetrics":
|
|
1634
|
+
return api.getPerformanceMetrics();
|
|
1635
|
+
case "takeMemorySnapshot":
|
|
1636
|
+
return api.takeMemorySnapshot();
|
|
1637
|
+
case "exportDiagnostics":
|
|
1638
|
+
return api.exportDiagnostics();
|
|
1639
|
+
case "importDiagnostics":
|
|
1640
|
+
api.importDiagnostics(args[0]);
|
|
1641
|
+
return void 0;
|
|
1642
|
+
case "getExtensionSnapshot":
|
|
1643
|
+
return api.getExtensionSnapshot();
|
|
1644
|
+
case "inspectExtension":
|
|
1645
|
+
return api.inspectExtension(String(args[0] ?? ""), args[1]);
|
|
1646
|
+
default:
|
|
1647
|
+
throw new Error(`Vobs DevTools: \u672A\u77E5\u8BF7\u6C42 ${request.method}`);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
__name(invokeRequest, "invokeRequest");
|
|
1651
|
+
function toErrorMessage(error) {
|
|
1652
|
+
return error instanceof Error ? error.message : String(error);
|
|
1653
|
+
}
|
|
1654
|
+
__name(toErrorMessage, "toErrorMessage");
|
|
1655
|
+
function toDebugError(error, phase) {
|
|
1656
|
+
const normalized = normalizeVobsError(error);
|
|
1657
|
+
const value = error;
|
|
1658
|
+
const source = value?.vobsSource ?? normalized.location;
|
|
1659
|
+
return {
|
|
1660
|
+
name: typeof value?.name === "string" ? value.name : normalized.name,
|
|
1661
|
+
message: typeof value?.message === "string" ? value.message : normalized.message,
|
|
1662
|
+
stack: typeof value?.stack === "string" ? value.stack : normalized.stack,
|
|
1663
|
+
phase,
|
|
1664
|
+
source: source && typeof source.file === "string" ? `${source.file}:${source.line ?? 0}:${source.column ?? 0}` : void 0,
|
|
1665
|
+
location: source && typeof source.file === "string" && typeof source.line === "number" && typeof source.column === "number" ? { file: source.file, line: source.line, column: source.column } : void 0,
|
|
1666
|
+
code: typeof value?.vobsCode === "string" ? value.vobsCode : typeof value?.code === "string" ? value.code : void 0,
|
|
1667
|
+
hint: typeof value?.vobsHint === "string" ? value.vobsHint : void 0,
|
|
1668
|
+
cause: normalized.cause instanceof Error ? `${normalized.cause.name}: ${normalized.cause.message}` : normalized.cause === void 0 ? void 0 : String(normalized.cause),
|
|
1669
|
+
fix: normalized.fix,
|
|
1670
|
+
hydration: value?.vobsHydration && typeof value.vobsHydration === "object" ? value.vobsHydration : void 0
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
__name(toDebugError, "toDebugError");
|
|
1674
|
+
var FRAMEWORK_ERROR_RULES = [
|
|
1675
|
+
{ pattern: /响应式更新超过\s*100\s*轮/, origin: "framework", code: "VOBS_REACTIVITY_LOOP", hint: "\u68C0\u67E5 Effect \u662F\u5426\u5728\u6267\u884C\u65F6\u6301\u7EED\u5199\u5165\u5B83\u4F9D\u8D56\u7684 Signal\u3002" },
|
|
1676
|
+
{ pattern: /Fragment: (?:不能跨父节点移动|Fragment 不属于指定父节点|找不到结束锚点)/, origin: "framework", code: "VOBS_FRAGMENT_INVARIANT", hint: "\u68C0\u67E5 Fragment \u7684\u7236\u8282\u70B9\u548C\u63D2\u5165/\u5220\u9664\u987A\u5E8F\uFF0C\u901A\u5E38\u8868\u793A\u8FD0\u884C\u65F6\u6811\u7ED3\u6784\u5DF2\u4E0D\u4E00\u81F4\u3002" },
|
|
1677
|
+
{ pattern: /当前渲染器不支持 Hydration/, origin: "usage", code: "VOBS_HYDRATION_UNSUPPORTED", hint: "\u8BF7\u4F7F\u7528\u652F\u6301 Hydration \u7684 Renderer\uFF0C\u6216\u6539\u7528 app.mount()\u3002" },
|
|
1678
|
+
{ pattern: /(?:HydrationMismatchError|Vobs hydration:|服务端 DOM 与客户端渲染结构不一致|节点位置与客户端渲染结果不一致)/, origin: "framework", code: "VOBS_HYDRATION_MISMATCH", hint: "\u68C0\u67E5\u670D\u52A1\u7AEF\u548C\u5BA2\u6237\u7AEF\u662F\u5426\u751F\u6210\u4E86\u76F8\u540C\u7684\u8282\u70B9\u7ED3\u6784\u4E0E\u521D\u59CB\u72B6\u6001\u3002" },
|
|
1679
|
+
{ pattern: /渲染器未初始化/, origin: "usage", code: "VOBS_RENDERER_NOT_INITIALIZED", hint: "\u8BF7\u5728\u5E94\u7528 mount \u6216 hydrate \u540E\u8C03\u7528 Runtime DOM API\u3002" },
|
|
1680
|
+
{ pattern: /节点不属于指定父节点/, origin: "framework", code: "VOBS_DOM_PARENT_MISMATCH", hint: "\u68C0\u67E5\u8282\u70B9\u662F\u5426\u88AB\u91CD\u590D\u79FB\u52A8\u3001\u5220\u9664\uFF0C\u6216\u88AB\u9519\u8BEF\u7684 Renderer \u5B9E\u4F8B\u7BA1\u7406\u3002" }
|
|
1681
|
+
];
|
|
1682
|
+
function classifyError(phase, error, context) {
|
|
1683
|
+
const message = toErrorMessage(error);
|
|
1684
|
+
const explicitCode = context.code ?? readErrorProperty(error, "vobsCode") ?? readErrorProperty(error, "code") ?? extractErrorCode(message);
|
|
1685
|
+
const frameworkRule = FRAMEWORK_ERROR_RULES.find((rule) => rule.pattern.test(message));
|
|
1686
|
+
if (frameworkRule) return { origin: context.origin ?? frameworkRule.origin, code: explicitCode ?? frameworkRule.code, hint: context.hint ?? frameworkRule.hint };
|
|
1687
|
+
if (context.origin) return { origin: context.origin, code: explicitCode, hint: context.hint };
|
|
1688
|
+
if (explicitCode && isUsageErrorCode(explicitCode) || /^Vobs(?:\s|:)|^VOBS_/.test(message) && /必须|不能为空|找不到|缺少|不存在|无效|不能直接|重复|未配置|已销毁/.test(message)) {
|
|
1689
|
+
return { origin: "usage", code: explicitCode, hint: context.hint ?? "\u68C0\u67E5\u8C03\u7528\u53C2\u6570\u3001Owner \u4F5C\u7528\u57DF\u548C\u76F8\u5173\u63D2\u4EF6\u662F\u5426\u5DF2\u5B89\u88C5\u3002" };
|
|
1690
|
+
}
|
|
1691
|
+
if (phase === "global") return { origin: "unknown", code: explicitCode, hint: context.hint };
|
|
1692
|
+
return { origin: "application", code: explicitCode, hint: context.hint };
|
|
1693
|
+
}
|
|
1694
|
+
__name(classifyError, "classifyError");
|
|
1695
|
+
function isUsageErrorCode(code) {
|
|
1696
|
+
return /^(?:INVALID_|.*_(?:CONTEXT_MISSING|CONTEXT_DISPOSED|OPTIONS|MISSING|UNAVAILABLE))/.test(code);
|
|
1697
|
+
}
|
|
1698
|
+
__name(isUsageErrorCode, "isUsageErrorCode");
|
|
1699
|
+
function extractErrorCode(message) {
|
|
1700
|
+
return message.match(/\b[A-Z][A-Z0-9_]{2,}_[A-Z0-9_]+\b/)?.[0];
|
|
1701
|
+
}
|
|
1702
|
+
__name(extractErrorCode, "extractErrorCode");
|
|
1703
|
+
function readErrorProperty(error, key) {
|
|
1704
|
+
if (!error || typeof error !== "object" && typeof error !== "function") return void 0;
|
|
1705
|
+
const value = error[key];
|
|
1706
|
+
return typeof value === "string" ? value : void 0;
|
|
1707
|
+
}
|
|
1708
|
+
__name(readErrorProperty, "readErrorProperty");
|
|
1709
|
+
function mergeRecovery(previous, next) {
|
|
1710
|
+
if (!next) return previous;
|
|
1711
|
+
if (next === "retrying") return next;
|
|
1712
|
+
if (next === "recovered") return next;
|
|
1713
|
+
if (next === "fallback") return next;
|
|
1714
|
+
if (previous === "fallback") return previous;
|
|
1715
|
+
return next;
|
|
1716
|
+
}
|
|
1717
|
+
__name(mergeRecovery, "mergeRecovery");
|
|
1718
|
+
function diagnosticErrorKey(error) {
|
|
1719
|
+
return [error.origin, error.code ?? error.name, error.message, error.source ?? "", error.component ?? ""].join(":");
|
|
1720
|
+
}
|
|
1721
|
+
__name(diagnosticErrorKey, "diagnosticErrorKey");
|
|
1722
|
+
function sanitizeImportedError(error) {
|
|
1723
|
+
const phase = error.phase ?? "global";
|
|
1724
|
+
return {
|
|
1725
|
+
...error,
|
|
1726
|
+
phase,
|
|
1727
|
+
phases: Array.isArray(error.phases) && error.phases.length > 0 ? error.phases : [phase],
|
|
1728
|
+
origin: error.origin ?? "unknown",
|
|
1729
|
+
handled: error.handled === true,
|
|
1730
|
+
recovery: error.recovery ?? "propagated"
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
__name(sanitizeImportedError, "sanitizeImportedError");
|
|
1734
|
+
function parseDiagnosticSnapshot(value) {
|
|
1735
|
+
if (!value || typeof value !== "object") throw new Error("Vobs DevTools: invalid diagnostic snapshot");
|
|
1736
|
+
const snapshot = value;
|
|
1737
|
+
if (snapshot.version !== 1 || !Array.isArray(snapshot.updates) || !Array.isArray(snapshot.lifecycle) || !Array.isArray(snapshot.network) || !Array.isArray(snapshot.errors) || !snapshot.performance || !snapshot.memory) {
|
|
1738
|
+
throw new Error("Vobs DevTools: unsupported diagnostic snapshot");
|
|
1739
|
+
}
|
|
1740
|
+
if (!snapshot.updates.every((item) => isRecord(item) && typeof item.id === "string" && typeof item.duration === "number" && Array.isArray(item.effects) && Array.isArray(item.affectedSignals) && Array.isArray(item.affectedEffects) && Array.isArray(item.domUpdates)) || !snapshot.lifecycle.every((item) => isRecord(item) && typeof item.id === "string" && typeof item.type === "string") || !snapshot.network.every((item) => isRecord(item) && typeof item.id === "number" && typeof item.url === "string" && isRecord(item.headers)) || !snapshot.errors.every((item) => isRecord(item) && typeof item.id === "number" && typeof item.message === "string") || !isRecord(snapshot.performance) || typeof snapshot.performance.updateCount !== "number" || typeof snapshot.performance.effectExecutionCount !== "number" || !isRecord(snapshot.memory)) {
|
|
1741
|
+
throw new Error("Vobs DevTools: malformed diagnostic snapshot");
|
|
1742
|
+
}
|
|
1743
|
+
return snapshot;
|
|
1744
|
+
}
|
|
1745
|
+
__name(parseDiagnosticSnapshot, "parseDiagnosticSnapshot");
|
|
1746
|
+
function parseSSRRequestSnapshot(value) {
|
|
1747
|
+
const candidate = value && typeof value === "object" && !Array.isArray(value) ? value : { version: 1, environment: "server", requests: value };
|
|
1748
|
+
if (candidate.version !== 1 || candidate.environment !== "server" || !Array.isArray(candidate.requests)) {
|
|
1749
|
+
throw new Error("Vobs DevTools: invalid SSR request snapshot");
|
|
1750
|
+
}
|
|
1751
|
+
if (!candidate.requests.every((item) => isRecord(item) && typeof item.id === "number" && typeof item.url === "string" && typeof item.method === "string" && typeof item.startedAt === "number" && isRecord(item.headers))) {
|
|
1752
|
+
throw new Error("Vobs DevTools: malformed SSR request snapshot");
|
|
1753
|
+
}
|
|
1754
|
+
return candidate.requests;
|
|
1755
|
+
}
|
|
1756
|
+
__name(parseSSRRequestSnapshot, "parseSSRRequestSnapshot");
|
|
1757
|
+
function isRecord(value) {
|
|
1758
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1759
|
+
}
|
|
1760
|
+
__name(isRecord, "isRecord");
|
|
1761
|
+
function normalizePrivacyOptions(options) {
|
|
1762
|
+
return {
|
|
1763
|
+
redactedHeaders: options?.redactedHeaders ?? [],
|
|
1764
|
+
redactedFields: options?.redactedFields ?? [],
|
|
1765
|
+
redactDomValues: options?.redactDomValues ?? false,
|
|
1766
|
+
replacement: options?.replacement ?? "[Redacted]"
|
|
1767
|
+
};
|
|
1768
|
+
}
|
|
1769
|
+
__name(normalizePrivacyOptions, "normalizePrivacyOptions");
|
|
1770
|
+
function sanitizeImportedUpdate(update, privacy) {
|
|
1771
|
+
return {
|
|
1772
|
+
...update,
|
|
1773
|
+
previousValue: serializeForDevTools(update.previousValue, /* @__PURE__ */ new Set(), 0, privacy),
|
|
1774
|
+
nextValue: serializeForDevTools(update.nextValue, /* @__PURE__ */ new Set(), 0, privacy),
|
|
1775
|
+
domUpdates: update.domUpdates.map((mutation) => ({
|
|
1776
|
+
...mutation,
|
|
1777
|
+
previousValue: privacy.redactDomValues ? privacy.replacement : serializeForDevTools(mutation.previousValue, /* @__PURE__ */ new Set(), 0, privacy),
|
|
1778
|
+
nextValue: privacy.redactDomValues ? privacy.replacement : serializeForDevTools(mutation.nextValue, /* @__PURE__ */ new Set(), 0, privacy)
|
|
1779
|
+
}))
|
|
1780
|
+
};
|
|
1781
|
+
}
|
|
1782
|
+
__name(sanitizeImportedUpdate, "sanitizeImportedUpdate");
|
|
1783
|
+
function sanitizeImportedRequest(request, privacy) {
|
|
1784
|
+
return {
|
|
1785
|
+
...request,
|
|
1786
|
+
headers: redactHeaders(request.headers, privacy),
|
|
1787
|
+
requestBody: serializeForDevTools(request.requestBody, /* @__PURE__ */ new Set(), 0, privacy),
|
|
1788
|
+
responseBody: serializeForDevTools(request.responseBody, /* @__PURE__ */ new Set(), 0, privacy)
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
__name(sanitizeImportedRequest, "sanitizeImportedRequest");
|
|
1792
|
+
function redactHeaders(headers, privacy) {
|
|
1793
|
+
const result = {};
|
|
1794
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
1795
|
+
if (/authorization|cookie|token|password|secret|api[-_]?key/i.test(key) || privacy.redactedHeaders.some((fragment) => key.toLowerCase().includes(fragment.toLowerCase()))) continue;
|
|
1796
|
+
result[key] = value;
|
|
1797
|
+
}
|
|
1798
|
+
return result;
|
|
1799
|
+
}
|
|
1800
|
+
__name(redactHeaders, "redactHeaders");
|
|
1801
|
+
function serializeForDevTools(value, seen = /* @__PURE__ */ new Set(), depth = 0, privacy) {
|
|
1802
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
1803
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : String(value);
|
|
1804
|
+
if (typeof value === "bigint") return `${value}n`;
|
|
1805
|
+
if (typeof value === "undefined") return void 0;
|
|
1806
|
+
if (typeof value === "function") return `[Function ${value.name || "anonymous"}]`;
|
|
1807
|
+
if (typeof value === "symbol") return String(value);
|
|
1808
|
+
if (depth >= 4) return "[MaxDepth]";
|
|
1809
|
+
const object = value;
|
|
1810
|
+
if (seen.has(object)) return "[Circular]";
|
|
1811
|
+
seen.add(object);
|
|
1812
|
+
try {
|
|
1813
|
+
if (value instanceof Date) return value.toISOString();
|
|
1814
|
+
if (value instanceof Error) return { name: value.name, message: value.message };
|
|
1815
|
+
if (Array.isArray(value)) return value.slice(0, 100).map((item) => serializeForDevTools(item, seen, depth + 1, privacy));
|
|
1816
|
+
const result = {};
|
|
1817
|
+
for (const key of Object.keys(object).slice(0, 100)) {
|
|
1818
|
+
try {
|
|
1819
|
+
if (privacy?.redactedFields.some((field) => field.toLowerCase() === key.toLowerCase())) {
|
|
1820
|
+
result[key] = privacy.replacement;
|
|
1821
|
+
} else {
|
|
1822
|
+
result[key] = serializeForDevTools(object[key], seen, depth + 1, privacy);
|
|
1823
|
+
}
|
|
1824
|
+
} catch {
|
|
1825
|
+
result[key] = "[Uninspectable]";
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
return result;
|
|
1829
|
+
} finally {
|
|
1830
|
+
seen.delete(object);
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
__name(serializeForDevTools, "serializeForDevTools");
|
|
1834
|
+
|
|
1835
|
+
export { DEVTOOLS_EVENTS, DEVTOOLS_REACTIVITY_EVENTS, connectDevTools, createDevTools, devtoolsPlugin, disableDevTools, enableDevTools, getDevTools };
|
|
1836
|
+
//# sourceMappingURL=index.js.map
|
|
1837
|
+
//# sourceMappingURL=index.js.map
|