nuxt-devtools-observatory 0.1.7 → 0.1.8
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/client/dist/assets/index-CVI-arV5.js +17 -0
- package/client/dist/assets/{index-mu192QeW.css → index-RdqCF5ft.css} +1 -1
- package/client/dist/index.html +2 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +34 -78
- package/dist/runtime/composables/composable-registry.js +10 -4
- package/dist/runtime/composables/fetch-registry.d.ts +16 -2
- package/dist/runtime/composables/fetch-registry.js +50 -120
- package/dist/runtime/composables/provide-inject-registry.d.ts +4 -0
- package/dist/runtime/composables/provide-inject-registry.js +4 -0
- package/dist/runtime/composables/render-registry.d.ts +1 -2
- package/dist/runtime/composables/render-registry.js +24 -57
- package/dist/runtime/plugin.js +49 -21
- package/package.json +1 -1
- package/client/dist/assets/index-CgZM5MBX.js +0 -17
- package/dist/nitro/fetch-capture.d.mts +0 -3
- package/dist/nitro/fetch-capture.mjs +0 -16
|
@@ -95,10 +95,16 @@ export function __trackComposable(name, callFn, meta) {
|
|
|
95
95
|
}
|
|
96
96
|
originalClearInterval(id2);
|
|
97
97
|
});
|
|
98
|
-
const
|
|
98
|
+
const effectsBefore = new Set(instance?.scope?.effects ?? []);
|
|
99
|
+
const mountedHooksBefore = instance?.bm?.length ?? 0;
|
|
100
|
+
const unmountedHooksBefore = instance?.um?.length ?? 0;
|
|
99
101
|
const result = callFn();
|
|
100
102
|
window.setInterval = originalSetInterval;
|
|
101
103
|
window.clearInterval = originalClearInterval;
|
|
104
|
+
const trackedWatchers = (instance?.scope?.effects ?? []).filter((effect) => !effectsBefore.has(effect)).map((effect) => ({
|
|
105
|
+
effect,
|
|
106
|
+
stop: () => effect.stop?.()
|
|
107
|
+
}));
|
|
102
108
|
const refs = {};
|
|
103
109
|
if (result && typeof result === "object") {
|
|
104
110
|
for (const [key, val] of Object.entries(result)) {
|
|
@@ -121,8 +127,8 @@ export function __trackComposable(name, callFn, meta) {
|
|
|
121
127
|
watcherCount: trackedWatchers.length,
|
|
122
128
|
intervalCount: trackedIntervals.length,
|
|
123
129
|
lifecycle: {
|
|
124
|
-
hasOnMounted:
|
|
125
|
-
hasOnUnmounted:
|
|
130
|
+
hasOnMounted: (instance?.bm?.length ?? 0) > mountedHooksBefore,
|
|
131
|
+
hasOnUnmounted: (instance?.um?.length ?? 0) > unmountedHooksBefore,
|
|
126
132
|
watchersCleaned: true,
|
|
127
133
|
intervalsCleaned: true
|
|
128
134
|
},
|
|
@@ -131,7 +137,7 @@ export function __trackComposable(name, callFn, meta) {
|
|
|
131
137
|
};
|
|
132
138
|
registry.register(entry);
|
|
133
139
|
onUnmounted(() => {
|
|
134
|
-
const leakedWatchers = trackedWatchers.filter((w) =>
|
|
140
|
+
const leakedWatchers = trackedWatchers.filter((w) => w.effect.active);
|
|
135
141
|
const leakedIntervals = trackedIntervals.filter((id2) => !clearedIntervals.has(id2));
|
|
136
142
|
const leak = leakedWatchers.length > 0 || leakedIntervals.length > 0;
|
|
137
143
|
const reasons = [];
|
|
@@ -14,6 +14,19 @@ export interface FetchEntry {
|
|
|
14
14
|
file?: string;
|
|
15
15
|
line?: number;
|
|
16
16
|
}
|
|
17
|
+
interface FetchResponse extends Response {
|
|
18
|
+
_data?: unknown;
|
|
19
|
+
}
|
|
20
|
+
interface FetchOptions {
|
|
21
|
+
server?: boolean;
|
|
22
|
+
onResponse?: (ctx: {
|
|
23
|
+
response: FetchResponse;
|
|
24
|
+
}) => void;
|
|
25
|
+
onResponseError?: (ctx: {
|
|
26
|
+
response: FetchResponse;
|
|
27
|
+
}) => void;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
}
|
|
17
30
|
/**
|
|
18
31
|
* Sets up the fetch registry, which tracks all fetch requests and their
|
|
19
32
|
* associated metadata (e.g. duration, size, origin).
|
|
@@ -56,8 +69,9 @@ export declare function setupFetchRegistry(): {
|
|
|
56
69
|
readonly line?: number | undefined;
|
|
57
70
|
}>>>;
|
|
58
71
|
};
|
|
59
|
-
export declare function __devFetch(originalFn: (
|
|
72
|
+
export declare function __devFetch(originalFn: (url: string, opts: FetchOptions) => Promise<unknown>, url: string, opts: FetchOptions, meta: {
|
|
60
73
|
key: string;
|
|
61
74
|
file: string;
|
|
62
75
|
line: number;
|
|
63
|
-
}): unknown
|
|
76
|
+
}): Promise<unknown>;
|
|
77
|
+
export {};
|
|
@@ -14,42 +14,8 @@ export function setupFetchRegistry() {
|
|
|
14
14
|
entries.value.set(id, updated);
|
|
15
15
|
emit("fetch:update", updated);
|
|
16
16
|
}
|
|
17
|
-
function safeValue(val) {
|
|
18
|
-
if (val === void 0 || val === null) {
|
|
19
|
-
return val;
|
|
20
|
-
}
|
|
21
|
-
if (typeof val === "function") {
|
|
22
|
-
return void 0;
|
|
23
|
-
}
|
|
24
|
-
if (typeof val === "object") {
|
|
25
|
-
try {
|
|
26
|
-
return JSON.parse(JSON.stringify(val));
|
|
27
|
-
} catch {
|
|
28
|
-
return String(val);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return val;
|
|
32
|
-
}
|
|
33
|
-
function sanitize(entry) {
|
|
34
|
-
return {
|
|
35
|
-
id: entry.id,
|
|
36
|
-
key: entry.key,
|
|
37
|
-
url: entry.url,
|
|
38
|
-
status: entry.status,
|
|
39
|
-
origin: entry.origin,
|
|
40
|
-
startTime: entry.startTime,
|
|
41
|
-
endTime: entry.endTime,
|
|
42
|
-
ms: entry.ms,
|
|
43
|
-
size: entry.size,
|
|
44
|
-
cached: entry.cached,
|
|
45
|
-
payload: safeValue(entry.payload),
|
|
46
|
-
error: safeValue(entry.error),
|
|
47
|
-
file: entry.file,
|
|
48
|
-
line: entry.line
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
17
|
function getAll() {
|
|
52
|
-
return [...entries.value.values()]
|
|
18
|
+
return [...entries.value.values()];
|
|
53
19
|
}
|
|
54
20
|
function clear() {
|
|
55
21
|
entries.value.clear();
|
|
@@ -64,97 +30,61 @@ export function setupFetchRegistry() {
|
|
|
64
30
|
}
|
|
65
31
|
return { register, update, getAll, clear, entries: readonly(entries) };
|
|
66
32
|
}
|
|
67
|
-
export function __devFetch(originalFn,
|
|
33
|
+
export function __devFetch(originalFn, url, opts, meta) {
|
|
68
34
|
if (!import.meta.dev || !import.meta.client) {
|
|
69
|
-
|
|
70
|
-
return (...args) => arg1(...args);
|
|
71
|
-
}
|
|
72
|
-
return originalFn(arg1, arg2);
|
|
35
|
+
return originalFn(url, opts);
|
|
73
36
|
}
|
|
74
37
|
const registry = window.__observatory__?.fetch;
|
|
75
38
|
if (!registry) {
|
|
76
|
-
return
|
|
39
|
+
return originalFn(url, opts);
|
|
40
|
+
}
|
|
41
|
+
const id = `${meta.key}::${Date.now()}`;
|
|
42
|
+
const startTime = performance.now();
|
|
43
|
+
const payload = window.__NUXT__?.data ?? {};
|
|
44
|
+
const fromPayload = Object.prototype.hasOwnProperty.call(payload, meta.key);
|
|
45
|
+
const origin = fromPayload ? "ssr" : "csr";
|
|
46
|
+
registry.register({
|
|
47
|
+
id,
|
|
48
|
+
key: meta.key,
|
|
49
|
+
url: typeof url === "string" ? url : String(url),
|
|
50
|
+
status: fromPayload ? "cached" : "pending",
|
|
51
|
+
origin,
|
|
52
|
+
startTime,
|
|
53
|
+
cached: fromPayload,
|
|
54
|
+
payload: fromPayload ? payload[meta.key] : void 0,
|
|
55
|
+
file: meta.file,
|
|
56
|
+
line: meta.line
|
|
57
|
+
});
|
|
58
|
+
if (fromPayload) {
|
|
59
|
+
return originalFn(url, opts);
|
|
77
60
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
registry.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
startTime,
|
|
92
|
-
cached: false,
|
|
93
|
-
file: meta.file,
|
|
94
|
-
line: meta.line
|
|
61
|
+
return originalFn(url, {
|
|
62
|
+
...opts,
|
|
63
|
+
onResponse({ response }) {
|
|
64
|
+
const ms = Math.round(performance.now() - startTime);
|
|
65
|
+
const size = Number(response.headers?.get("content-length")) || void 0;
|
|
66
|
+
const cached = response.headers?.get("x-nuxt-cache") === "HIT";
|
|
67
|
+
registry.update(id, {
|
|
68
|
+
status: cached ? "cached" : response.ok ? "ok" : "error",
|
|
69
|
+
endTime: performance.now(),
|
|
70
|
+
ms,
|
|
71
|
+
size,
|
|
72
|
+
cached,
|
|
73
|
+
payload: response._data
|
|
95
74
|
});
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
registry.update(id, {
|
|
106
|
-
status: "error",
|
|
107
|
-
endTime: performance.now(),
|
|
108
|
-
ms: Math.round(performance.now() - startTime),
|
|
109
|
-
error
|
|
110
|
-
});
|
|
111
|
-
throw error;
|
|
75
|
+
if (typeof opts.onResponse === "function") {
|
|
76
|
+
opts.onResponse({ response });
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
onResponseError({ response }) {
|
|
80
|
+
registry.update(id, {
|
|
81
|
+
status: "error",
|
|
82
|
+
endTime: performance.now(),
|
|
83
|
+
ms: Math.round(performance.now() - startTime)
|
|
112
84
|
});
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const url = arg1;
|
|
116
|
-
const opts = arg2 || {};
|
|
117
|
-
const id = `${meta.key}::${Date.now()}`;
|
|
118
|
-
const startTime = performance.now();
|
|
119
|
-
const origin = import.meta.server ? "ssr" : "csr";
|
|
120
|
-
registry.register({
|
|
121
|
-
id,
|
|
122
|
-
key: meta.key,
|
|
123
|
-
url: typeof url === "string" ? url : String(url),
|
|
124
|
-
status: "pending",
|
|
125
|
-
origin,
|
|
126
|
-
startTime,
|
|
127
|
-
cached: false,
|
|
128
|
-
file: meta.file,
|
|
129
|
-
line: meta.line
|
|
130
|
-
});
|
|
131
|
-
return originalFn(url, {
|
|
132
|
-
...opts,
|
|
133
|
-
onResponse({ response }) {
|
|
134
|
-
const ms = Math.round(performance.now() - startTime);
|
|
135
|
-
const size = Number(response.headers?.get("content-length")) || void 0;
|
|
136
|
-
const cached = response.headers?.get("x-nuxt-cache") === "HIT";
|
|
137
|
-
registry.update(id, {
|
|
138
|
-
status: response.ok ? "ok" : "error",
|
|
139
|
-
endTime: performance.now(),
|
|
140
|
-
ms,
|
|
141
|
-
size,
|
|
142
|
-
cached
|
|
143
|
-
});
|
|
144
|
-
if (typeof opts.onResponse === "function") {
|
|
145
|
-
opts.onResponse({ response });
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
onResponseError({ response }) {
|
|
149
|
-
registry.update(id, {
|
|
150
|
-
status: "error",
|
|
151
|
-
endTime: performance.now(),
|
|
152
|
-
ms: Math.round(performance.now() - startTime)
|
|
153
|
-
});
|
|
154
|
-
if (typeof opts.onResponseError === "function") {
|
|
155
|
-
opts.onResponseError({ response });
|
|
156
|
-
}
|
|
85
|
+
if (typeof opts.onResponseError === "function") {
|
|
86
|
+
opts.onResponseError({ response });
|
|
157
87
|
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
160
90
|
}
|
|
@@ -3,6 +3,8 @@ export interface ProvideEntry {
|
|
|
3
3
|
componentName: string;
|
|
4
4
|
componentFile: string;
|
|
5
5
|
componentUid: number;
|
|
6
|
+
parentUid?: number;
|
|
7
|
+
parentFile?: string;
|
|
6
8
|
isReactive: boolean;
|
|
7
9
|
valueSnapshot: unknown;
|
|
8
10
|
line: number;
|
|
@@ -12,6 +14,8 @@ export interface InjectEntry {
|
|
|
12
14
|
componentName: string;
|
|
13
15
|
componentFile: string;
|
|
14
16
|
componentUid: number;
|
|
17
|
+
parentUid?: number;
|
|
18
|
+
parentFile?: string;
|
|
15
19
|
resolved: boolean;
|
|
16
20
|
resolvedFromFile?: string;
|
|
17
21
|
resolvedFromUid?: number;
|
|
@@ -79,6 +79,8 @@ export function __devProvide(key, value, meta) {
|
|
|
79
79
|
componentName: instance?.type?.__name ?? "unknown",
|
|
80
80
|
componentFile: meta.file,
|
|
81
81
|
componentUid: instance?.uid ?? -1,
|
|
82
|
+
parentUid: instance?.parent?.uid,
|
|
83
|
+
parentFile: instance?.parent?.type?.__file,
|
|
82
84
|
isReactive: isRef(value) || isReactive(value),
|
|
83
85
|
valueSnapshot: safeSnapshot(unref(value)),
|
|
84
86
|
line: meta.line
|
|
@@ -100,6 +102,8 @@ export function __devInject(key, defaultValue, meta) {
|
|
|
100
102
|
componentName: instance?.type?.__name ?? "unknown",
|
|
101
103
|
componentFile: meta.file,
|
|
102
104
|
componentUid: instance?.uid ?? -1,
|
|
105
|
+
parentUid: instance?.parent?.uid,
|
|
106
|
+
parentFile: instance?.parent?.type?.__file,
|
|
103
107
|
resolved: resolved !== void 0,
|
|
104
108
|
resolvedFromFile: providerInfo?.file,
|
|
105
109
|
resolvedFromUid: providerInfo?.uid,
|
|
@@ -25,12 +25,11 @@ export interface RenderEntry {
|
|
|
25
25
|
* Sets up a render registry for the given Nuxt app.
|
|
26
26
|
* @param {{ vueApp: import('vue').App }} nuxtApp - The Nuxt app object.
|
|
27
27
|
* @param {object} nuxtApp.vueApp - The Vue app instance.
|
|
28
|
-
* @param {number} threshold - The minimum number of renders required for a component to be tracked.
|
|
29
28
|
* @returns {object} The render registry object.
|
|
30
29
|
*/
|
|
31
30
|
export declare function setupRenderRegistry(nuxtApp: {
|
|
32
31
|
vueApp: import('vue').App;
|
|
33
|
-
}
|
|
32
|
+
}): {
|
|
34
33
|
getAll: () => RenderEntry[];
|
|
35
34
|
snapshot: () => RenderEntry[];
|
|
36
35
|
};
|
|
@@ -1,62 +1,42 @@
|
|
|
1
1
|
import { ref } from "vue";
|
|
2
|
-
export function setupRenderRegistry(nuxtApp
|
|
2
|
+
export function setupRenderRegistry(nuxtApp) {
|
|
3
3
|
const entries = ref(/* @__PURE__ */ new Map());
|
|
4
|
-
function
|
|
5
|
-
const uid =
|
|
6
|
-
let isFirstRender = false;
|
|
4
|
+
function ensureEntry(instance) {
|
|
5
|
+
const uid = instance.$.uid;
|
|
7
6
|
if (!entries.value.has(uid)) {
|
|
8
|
-
entries.value.set(uid, makeEntry(uid,
|
|
9
|
-
isFirstRender = true;
|
|
10
|
-
}
|
|
11
|
-
if (isFirstRender) {
|
|
12
|
-
const parent = this.$parent?.$;
|
|
13
|
-
if (parent) {
|
|
14
|
-
const parentUid = parent.uid;
|
|
15
|
-
if (!entries.value.has(parentUid)) {
|
|
16
|
-
entries.value.set(parentUid, makeEntry(parentUid, this.$parent));
|
|
17
|
-
}
|
|
18
|
-
const parentEntry = entries.value.get(parentUid);
|
|
19
|
-
if (!parentEntry.children.includes(uid)) {
|
|
20
|
-
parentEntry.children.push(uid);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
7
|
+
entries.value.set(uid, makeEntry(uid, instance));
|
|
23
8
|
}
|
|
24
9
|
return entries.value.get(uid);
|
|
25
10
|
}
|
|
11
|
+
function syncRect(entry, instance) {
|
|
12
|
+
const rect = instance.$el?.getBoundingClientRect?.();
|
|
13
|
+
entry.rect = rect ? {
|
|
14
|
+
x: Math.round(rect.x),
|
|
15
|
+
y: Math.round(rect.y),
|
|
16
|
+
width: Math.round(rect.width),
|
|
17
|
+
height: Math.round(rect.height),
|
|
18
|
+
top: Math.round(rect.top),
|
|
19
|
+
left: Math.round(rect.left)
|
|
20
|
+
} : void 0;
|
|
21
|
+
}
|
|
26
22
|
nuxtApp.vueApp.mixin({
|
|
27
23
|
mounted() {
|
|
28
|
-
|
|
24
|
+
const entry = ensureEntry(this);
|
|
25
|
+
entry.renders++;
|
|
26
|
+
syncRect(entry, this);
|
|
27
|
+
emit("render:update", { uid: entry.uid, renders: entry.renders });
|
|
29
28
|
},
|
|
30
29
|
renderTriggered({ key, type }) {
|
|
31
|
-
const
|
|
32
|
-
if (!entries.value.has(uid)) {
|
|
33
|
-
entries.value.set(uid, makeEntry(uid, this));
|
|
34
|
-
}
|
|
35
|
-
const entry = entries.value.get(uid);
|
|
30
|
+
const entry = ensureEntry(this);
|
|
36
31
|
entry.triggers.push({ key: String(key), type, timestamp: performance.now() });
|
|
37
32
|
if (entry.triggers.length > 50) {
|
|
38
33
|
entry.triggers.shift();
|
|
39
34
|
}
|
|
40
35
|
},
|
|
41
36
|
updated() {
|
|
42
|
-
const entry =
|
|
37
|
+
const entry = ensureEntry(this);
|
|
43
38
|
entry.renders++;
|
|
44
|
-
|
|
45
|
-
name: entry.name,
|
|
46
|
-
uid: entry.uid,
|
|
47
|
-
file: entry.file,
|
|
48
|
-
renders: entry.renders,
|
|
49
|
-
instance: this
|
|
50
|
-
});
|
|
51
|
-
const r = this.$el?.getBoundingClientRect?.();
|
|
52
|
-
entry.rect = r ? {
|
|
53
|
-
x: Math.round(r.x),
|
|
54
|
-
y: Math.round(r.y),
|
|
55
|
-
width: Math.round(r.width),
|
|
56
|
-
height: Math.round(r.height),
|
|
57
|
-
top: Math.round(r.top),
|
|
58
|
-
left: Math.round(r.left)
|
|
59
|
-
} : void 0;
|
|
39
|
+
syncRect(entry, this);
|
|
60
40
|
emit("render:update", { uid: entry.uid, renders: entry.renders });
|
|
61
41
|
}
|
|
62
42
|
});
|
|
@@ -120,23 +100,10 @@ export function setupRenderRegistry(nuxtApp, threshold) {
|
|
|
120
100
|
return { getAll, snapshot };
|
|
121
101
|
}
|
|
122
102
|
function makeEntry(uid, instance) {
|
|
123
|
-
const type = instance.$.type;
|
|
124
|
-
let name = "";
|
|
125
|
-
if (typeof type.__name === "string" && type.__name.trim()) {
|
|
126
|
-
name = type.__name;
|
|
127
|
-
} else if (typeof type.name === "string" && type.name.trim()) {
|
|
128
|
-
name = type.name;
|
|
129
|
-
} else if (typeof type.__file === "string" && type.__file.trim()) {
|
|
130
|
-
name = type.__file.split("/").pop()?.replace(/\.vue$/, "") || "";
|
|
131
|
-
}
|
|
132
|
-
if (!name) {
|
|
133
|
-
name = `Component#${uid}`;
|
|
134
|
-
}
|
|
135
|
-
console.log("[Observatory] makeEntry:", { uid, name, file: type.__file, type });
|
|
136
103
|
return {
|
|
137
104
|
uid,
|
|
138
|
-
name
|
|
139
|
-
file: type.__file ?? "unknown",
|
|
105
|
+
name: instance.$.type.__name ?? instance.$.type.__file?.split("/").pop() ?? `Component#${uid}`,
|
|
106
|
+
file: instance.$.type.__file ?? "unknown",
|
|
140
107
|
renders: 0,
|
|
141
108
|
totalMs: 0,
|
|
142
109
|
avgMs: 0,
|
package/dist/runtime/plugin.js
CHANGED
|
@@ -4,6 +4,39 @@ import { setupProvideInjectRegistry } from "./composables/provide-inject-registr
|
|
|
4
4
|
import { setupComposableRegistry } from "./composables/composable-registry.js";
|
|
5
5
|
import { setupRenderRegistry } from "./composables/render-registry.js";
|
|
6
6
|
import { setupTransitionRegistry } from "./composables/transition-registry.js";
|
|
7
|
+
function toSerializable(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
8
|
+
if (value === null || value === void 0) {
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === "bigint") {
|
|
15
|
+
return value.toString();
|
|
16
|
+
}
|
|
17
|
+
if (typeof value === "function" || typeof value === "symbol") {
|
|
18
|
+
return `[${typeof value}]`;
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(value)) {
|
|
21
|
+
return value.map((entry) => toSerializable(entry, seen));
|
|
22
|
+
}
|
|
23
|
+
if (typeof value === "object") {
|
|
24
|
+
if (seen.has(value)) {
|
|
25
|
+
return "[circular]";
|
|
26
|
+
}
|
|
27
|
+
seen.add(value);
|
|
28
|
+
if (value instanceof Date) {
|
|
29
|
+
return value.toISOString();
|
|
30
|
+
}
|
|
31
|
+
const plain = {};
|
|
32
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
33
|
+
plain[key] = toSerializable(entry, seen);
|
|
34
|
+
}
|
|
35
|
+
seen.delete(value);
|
|
36
|
+
return plain;
|
|
37
|
+
}
|
|
38
|
+
return String(value);
|
|
39
|
+
}
|
|
7
40
|
export default defineNuxtPlugin(() => {
|
|
8
41
|
if (!import.meta.dev) {
|
|
9
42
|
return;
|
|
@@ -14,7 +47,7 @@ export default defineNuxtPlugin(() => {
|
|
|
14
47
|
const fetchRegistry = setupFetchRegistry();
|
|
15
48
|
const provideInjectRegistry = setupProvideInjectRegistry();
|
|
16
49
|
const composableRegistry = setupComposableRegistry();
|
|
17
|
-
const renderRegistry = setupRenderRegistry(nuxtApp
|
|
50
|
+
const renderRegistry = setupRenderRegistry(nuxtApp);
|
|
18
51
|
const transitionRegistry = setupTransitionRegistry();
|
|
19
52
|
if (import.meta.client) {
|
|
20
53
|
delete window.__observatory__;
|
|
@@ -29,26 +62,18 @@ export default defineNuxtPlugin(() => {
|
|
|
29
62
|
if (event.data?.type !== "observatory:request") {
|
|
30
63
|
return;
|
|
31
64
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const snapshot = {
|
|
35
|
-
fetch: fetchRegistry.getAll(),
|
|
36
|
-
provideInject: provideInjectRegistry.getAll(),
|
|
37
|
-
composables: composableRegistry.getAll(),
|
|
38
|
-
renders: renderRegistry.getAll(),
|
|
39
|
-
transitions: transitionRegistry.getAll()
|
|
40
|
-
};
|
|
41
|
-
const payload = JSON.stringify(snapshot);
|
|
42
|
-
source?.postMessage(
|
|
43
|
-
{
|
|
44
|
-
type: "observatory:snapshot",
|
|
45
|
-
data: payload
|
|
46
|
-
},
|
|
47
|
-
"*"
|
|
48
|
-
);
|
|
49
|
-
} catch (err) {
|
|
50
|
-
console.warn("Observatory snapshot serialization failed:", err);
|
|
65
|
+
if (config.clientOrigin && event.origin !== config.clientOrigin) {
|
|
66
|
+
return;
|
|
51
67
|
}
|
|
68
|
+
const source = event.source;
|
|
69
|
+
const snapshot = buildSnapshot();
|
|
70
|
+
source?.postMessage(
|
|
71
|
+
{
|
|
72
|
+
type: "observatory:snapshot",
|
|
73
|
+
data: snapshot
|
|
74
|
+
},
|
|
75
|
+
event.origin
|
|
76
|
+
);
|
|
52
77
|
});
|
|
53
78
|
}
|
|
54
79
|
nuxtApp.hook("app:mounted", () => {
|
|
@@ -67,7 +92,10 @@ export default defineNuxtPlugin(() => {
|
|
|
67
92
|
if (!channel) {
|
|
68
93
|
return;
|
|
69
94
|
}
|
|
70
|
-
channel.send("observatory:snapshot",
|
|
95
|
+
channel.send("observatory:snapshot", buildSnapshot());
|
|
96
|
+
}
|
|
97
|
+
function buildSnapshot() {
|
|
98
|
+
return toSerializable({
|
|
71
99
|
fetch: fetchRegistry.getAll(),
|
|
72
100
|
provideInject: provideInjectRegistry.getAll(),
|
|
73
101
|
composables: composableRegistry.getAll(),
|
package/package.json
CHANGED