nuxt-devtools-observatory 0.1.18 → 0.1.19
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/README.md +1 -1
- package/client/.env +14 -0
- package/client/.env.example +14 -0
- package/client/dist/assets/index-BUdwtn9n.js +17 -0
- package/client/dist/assets/{index-B9TLcAbk.css → index-PBRECUGt.css} +1 -1
- package/client/dist/index.html +2 -2
- package/client/env.d.ts +10 -0
- package/client/src/views/RenderHeatmap.vue +42 -11
- package/dist/module.d.mts +37 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +53 -49
- package/dist/runtime/composables/composable-registry.d.ts +15 -1
- package/dist/runtime/composables/composable-registry.js +57 -24
- package/dist/runtime/composables/fetch-registry.d.ts +5 -19
- package/dist/runtime/composables/fetch-registry.js +33 -14
- package/dist/runtime/composables/provide-inject-registry.d.ts +1 -0
- package/dist/runtime/composables/provide-inject-registry.js +24 -1
- package/dist/runtime/composables/render-registry.d.ts +2 -1
- package/dist/runtime/composables/render-registry.js +35 -11
- package/dist/runtime/composables/transition-registry.d.ts +1 -0
- package/dist/runtime/composables/transition-registry.js +32 -12
- package/dist/runtime/plugin.js +56 -54
- package/package.json +1 -1
- package/client/dist/assets/index-BlwWZDDl.js +0 -17
|
@@ -177,14 +177,19 @@ const activeRoute = ref('')
|
|
|
177
177
|
// Separate thresholds per mode so switching modes doesn't produce nonsense results.
|
|
178
178
|
// Count: flag components that rendered 3+ times (1 hydration mount is normal).
|
|
179
179
|
// Time: flag components averaging 16ms+ (one animation frame budget).
|
|
180
|
-
const
|
|
181
|
-
const
|
|
180
|
+
const COUNT_THRESHOLD = import.meta.env.VITE_OBSERVATORY_HEATMAP_THRESHOLD_COUNT ?? 3
|
|
181
|
+
const TIME_THRESHOLD = import.meta.env.VITE_OBSERVATORY_HEATMAP_THRESHOLD_TIME ?? 1600
|
|
182
|
+
const countThreshold = ref(Number(COUNT_THRESHOLD))
|
|
183
|
+
const timeThreshold = ref(Number(TIME_THRESHOLD))
|
|
182
184
|
// Writable computed so the threshold slider can use v-model directly.
|
|
183
185
|
const activeThreshold = computed({
|
|
184
186
|
get: () => (activeMode.value === 'count' ? countThreshold.value : timeThreshold.value),
|
|
185
187
|
set: (val: number) => {
|
|
186
|
-
if (activeMode.value === 'count')
|
|
187
|
-
|
|
188
|
+
if (activeMode.value === 'count') {
|
|
189
|
+
countThreshold.value = val
|
|
190
|
+
} else {
|
|
191
|
+
timeThreshold.value = val
|
|
192
|
+
}
|
|
188
193
|
},
|
|
189
194
|
})
|
|
190
195
|
const activeHotOnly = ref(false)
|
|
@@ -299,6 +304,7 @@ function countSubtree(node: ComponentNode): number {
|
|
|
299
304
|
function collectIds(node: ComponentNode, target = new Set<string>()) {
|
|
300
305
|
target.add(node.id)
|
|
301
306
|
node.children.forEach((child) => collectIds(child, target))
|
|
307
|
+
|
|
302
308
|
return target
|
|
303
309
|
}
|
|
304
310
|
|
|
@@ -344,13 +350,16 @@ function defaultExpandedIds(root: ComponentNode | null) {
|
|
|
344
350
|
// Expand all nodes that have children — gives a fully-open tree on first load.
|
|
345
351
|
// The user can collapse individual branches as needed.
|
|
346
352
|
const expanded = new Set<string>()
|
|
353
|
+
|
|
347
354
|
function expandAll(node: ComponentNode) {
|
|
348
355
|
if (node.children.length > 0) {
|
|
349
356
|
expanded.add(node.id)
|
|
350
357
|
node.children.forEach(expandAll)
|
|
351
358
|
}
|
|
352
359
|
}
|
|
360
|
+
|
|
353
361
|
expandAll(root)
|
|
362
|
+
|
|
354
363
|
return expanded
|
|
355
364
|
}
|
|
356
365
|
|
|
@@ -413,10 +422,16 @@ function subtreeHasHotNode(node: ComponentNode): boolean {
|
|
|
413
422
|
}
|
|
414
423
|
|
|
415
424
|
function nodeMatchesRoute(node: ComponentNode): boolean {
|
|
416
|
-
if (!activeRoute.value)
|
|
425
|
+
if (!activeRoute.value) {
|
|
426
|
+
return true
|
|
427
|
+
}
|
|
428
|
+
|
|
417
429
|
// A component is visible for a route if it was first seen on that route
|
|
418
430
|
// OR if any of its timeline events happened on that route.
|
|
419
|
-
if (node.route === activeRoute.value)
|
|
431
|
+
if (node.route === activeRoute.value) {
|
|
432
|
+
return true
|
|
433
|
+
}
|
|
434
|
+
|
|
420
435
|
return node.timeline.some((e) => e.route === activeRoute.value)
|
|
421
436
|
}
|
|
422
437
|
|
|
@@ -495,8 +510,12 @@ const appEntries = computed(() =>
|
|
|
495
510
|
|
|
496
511
|
const knownRoutes = computed(() => {
|
|
497
512
|
const routes = new Set<string>()
|
|
513
|
+
|
|
498
514
|
for (const node of allComponents.value) {
|
|
499
|
-
if (node.route)
|
|
515
|
+
if (node.route) {
|
|
516
|
+
routes.add(node.route)
|
|
517
|
+
}
|
|
518
|
+
|
|
500
519
|
for (const event of node.timeline) {
|
|
501
520
|
if (event.route) routes.add(event.route)
|
|
502
521
|
}
|
|
@@ -525,6 +544,7 @@ watch(
|
|
|
525
544
|
activeSelectedId.value = null
|
|
526
545
|
expandedIds.value = new Set()
|
|
527
546
|
expansionReady.value = false
|
|
547
|
+
|
|
528
548
|
return
|
|
529
549
|
}
|
|
530
550
|
|
|
@@ -544,12 +564,12 @@ watch(
|
|
|
544
564
|
if (!expansionReady.value) {
|
|
545
565
|
expandedIds.value = defaultExpandedIds(activeRoot.value)
|
|
546
566
|
expansionReady.value = true
|
|
567
|
+
|
|
547
568
|
return
|
|
548
569
|
}
|
|
549
570
|
|
|
550
571
|
if (!search.value.trim() && activeSelectedId.value && activeRoot.value) {
|
|
551
572
|
const selectedPath = pathToNode(activeRoot.value, activeSelectedId.value) ?? []
|
|
552
|
-
|
|
553
573
|
selectedPath.forEach((id) => preserved.add(id))
|
|
554
574
|
}
|
|
555
575
|
|
|
@@ -567,13 +587,14 @@ watch(search, (term) => {
|
|
|
567
587
|
|
|
568
588
|
if (normalized) {
|
|
569
589
|
expandedIds.value = searchExpandedIds(activeRoot.value, normalized)
|
|
590
|
+
|
|
570
591
|
return
|
|
571
592
|
}
|
|
572
593
|
|
|
573
594
|
if (activeSelectedId.value) {
|
|
574
595
|
const selectedPath = pathToNode(activeRoot.value, activeSelectedId.value)
|
|
575
|
-
|
|
576
596
|
expandedIds.value = selectedPath ? new Set(selectedPath) : defaultExpandedIds(activeRoot.value)
|
|
597
|
+
|
|
577
598
|
return
|
|
578
599
|
}
|
|
579
600
|
|
|
@@ -589,6 +610,7 @@ watch([activeHotOnly, activeThreshold, activeMode, filteredRoots], () => {
|
|
|
589
610
|
|
|
590
611
|
if (!topLevelRoot) {
|
|
591
612
|
activeSelectedId.value = null
|
|
613
|
+
|
|
592
614
|
return
|
|
593
615
|
}
|
|
594
616
|
|
|
@@ -596,6 +618,7 @@ watch([activeHotOnly, activeThreshold, activeMode, filteredRoots], () => {
|
|
|
596
618
|
|
|
597
619
|
if (!firstHot) {
|
|
598
620
|
activeSelectedId.value = null
|
|
621
|
+
|
|
599
622
|
return
|
|
600
623
|
}
|
|
601
624
|
|
|
@@ -646,6 +669,7 @@ function toggleFreeze() {
|
|
|
646
669
|
if (frozen.value) {
|
|
647
670
|
frozen.value = false
|
|
648
671
|
frozenSnapshot.value = []
|
|
672
|
+
|
|
649
673
|
return
|
|
650
674
|
}
|
|
651
675
|
|
|
@@ -663,9 +687,16 @@ function basename(file: string) {
|
|
|
663
687
|
}
|
|
664
688
|
|
|
665
689
|
function openInEditor(file: string) {
|
|
666
|
-
if (!file || file === 'unknown')
|
|
690
|
+
if (!file || file === 'unknown') {
|
|
691
|
+
return
|
|
692
|
+
}
|
|
693
|
+
|
|
667
694
|
const origin = getObservatoryOrigin()
|
|
668
|
-
|
|
695
|
+
|
|
696
|
+
if (!origin) {
|
|
697
|
+
return
|
|
698
|
+
}
|
|
699
|
+
|
|
669
700
|
window.top?.postMessage({ type: 'observatory:open-in-editor', file }, origin)
|
|
670
701
|
}
|
|
671
702
|
|
package/dist/module.d.mts
CHANGED
|
@@ -1,6 +1,36 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
2
|
|
|
3
3
|
interface ModuleOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Maximum number of fetch entries to keep in memory
|
|
6
|
+
* @default 200
|
|
7
|
+
*/
|
|
8
|
+
maxFetchEntries?: number;
|
|
9
|
+
/**
|
|
10
|
+
* Maximum payload size (bytes) to store per fetch entry
|
|
11
|
+
* @default 10000
|
|
12
|
+
*/
|
|
13
|
+
maxPayloadBytes?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Maximum number of transition entries to keep in memory
|
|
16
|
+
* @default 500
|
|
17
|
+
*/
|
|
18
|
+
maxTransitions?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Maximum number of composable history events per entry
|
|
21
|
+
* @default 50
|
|
22
|
+
*/
|
|
23
|
+
maxComposableHistory?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Maximum number of composable entries to keep in memory
|
|
26
|
+
* @default 300
|
|
27
|
+
*/
|
|
28
|
+
maxComposableEntries?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Maximum number of render timeline events per entry
|
|
31
|
+
* @default 100
|
|
32
|
+
*/
|
|
33
|
+
maxRenderTimeline?: number;
|
|
4
34
|
/**
|
|
5
35
|
* Enable the useFetch / useAsyncData dashboard tab
|
|
6
36
|
* @default true
|
|
@@ -28,9 +58,14 @@ interface ModuleOptions {
|
|
|
28
58
|
transitionTracker?: boolean;
|
|
29
59
|
/**
|
|
30
60
|
* Minimum render count / ms threshold to highlight in the heatmap
|
|
31
|
-
* @default
|
|
61
|
+
* @default 3
|
|
62
|
+
*/
|
|
63
|
+
heatmapThresholdCount?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Minimum render count / ms threshold to highlight in the heatmap
|
|
66
|
+
* @default 1600
|
|
32
67
|
*/
|
|
33
|
-
|
|
68
|
+
heatmapThresholdTime?: number;
|
|
34
69
|
}
|
|
35
70
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
36
71
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -524,7 +524,14 @@ const module$1 = defineNuxtModule({
|
|
|
524
524
|
composableTracker: true,
|
|
525
525
|
renderHeatmap: true,
|
|
526
526
|
transitionTracker: true,
|
|
527
|
-
|
|
527
|
+
heatmapThresholdCount: process.env.OBSERVATORY_HEATMAP_THRESHOLD_COUNT ? Number(process.env.OBSERVATORY_HEATMAP_THRESHOLD_COUNT) : 3,
|
|
528
|
+
heatmapThresholdTime: process.env.OBSERVATORY_HEATMAP_THRESHOLD_TIME ? Number(process.env.OBSERVATORY_HEATMAP_THRESHOLD_TIME) : 1600,
|
|
529
|
+
maxFetchEntries: process.env.OBSERVATORY_MAX_FETCH_ENTRIES ? Number(process.env.OBSERVATORY_MAX_FETCH_ENTRIES) : 200,
|
|
530
|
+
maxPayloadBytes: process.env.OBSERVATORY_MAX_PAYLOAD_BYTES ? Number(process.env.OBSERVATORY_MAX_PAYLOAD_BYTES) : 1e4,
|
|
531
|
+
maxTransitions: process.env.OBSERVATORY_MAX_TRANSITIONS ? Number(process.env.OBSERVATORY_MAX_TRANSITIONS) : 500,
|
|
532
|
+
maxComposableHistory: process.env.OBSERVATORY_MAX_COMPOSABLE_HISTORY ? Number(process.env.OBSERVATORY_MAX_COMPOSABLE_HISTORY) : 50,
|
|
533
|
+
maxComposableEntries: process.env.OBSERVATORY_MAX_COMPOSABLE_ENTRIES ? Number(process.env.OBSERVATORY_MAX_COMPOSABLE_ENTRIES) : 300,
|
|
534
|
+
maxRenderTimeline: process.env.OBSERVATORY_MAX_RENDER_TIMELINE ? Number(process.env.OBSERVATORY_MAX_RENDER_TIMELINE) : 100
|
|
528
535
|
},
|
|
529
536
|
setup(options, nuxt) {
|
|
530
537
|
if (!nuxt.options.dev) {
|
|
@@ -534,6 +541,21 @@ const module$1 = defineNuxtModule({
|
|
|
534
541
|
process.env.LAUNCH_EDITOR = "code";
|
|
535
542
|
}
|
|
536
543
|
const resolver = createResolver(import.meta.url);
|
|
544
|
+
const resolved = {
|
|
545
|
+
fetchDashboard: options.fetchDashboard ?? (process.env.OBSERVATORY_FETCH_DASHBOARD ? process.env.OBSERVATORY_FETCH_DASHBOARD === "true" : true),
|
|
546
|
+
provideInjectGraph: options.provideInjectGraph ?? (process.env.OBSERVATORY_PROVIDE_INJECT_GRAPH ? process.env.OBSERVATORY_PROVIDE_INJECT_GRAPH === "true" : true),
|
|
547
|
+
composableTracker: options.composableTracker ?? (process.env.OBSERVATORY_COMPOSABLE_TRACKER ? process.env.OBSERVATORY_COMPOSABLE_TRACKER === "true" : true),
|
|
548
|
+
renderHeatmap: options.renderHeatmap ?? (process.env.OBSERVATORY_RENDER_HEATMAP ? process.env.OBSERVATORY_RENDER_HEATMAP === "true" : true),
|
|
549
|
+
transitionTracker: options.transitionTracker ?? (process.env.OBSERVATORY_TRANSITION_TRACKER ? process.env.OBSERVATORY_TRANSITION_TRACKER === "true" : true),
|
|
550
|
+
heatmapThresholdCount: options.heatmapThresholdCount ?? (process.env.OBSERVATORY_HEATMAP_THRESHOLD_COUNT ? Number(process.env.OBSERVATORY_HEATMAP_THRESHOLD_COUNT) : 3),
|
|
551
|
+
heatmapThresholdTime: options.heatmapThresholdTime ?? (process.env.OBSERVATORY_HEATMAP_THRESHOLD_TIME ? Number(process.env.OBSERVATORY_HEATMAP_THRESHOLD_TIME) : 1600),
|
|
552
|
+
maxFetchEntries: options.maxFetchEntries ?? (process.env.OBSERVATORY_MAX_FETCH_ENTRIES ? Number(process.env.OBSERVATORY_MAX_FETCH_ENTRIES) : 200),
|
|
553
|
+
maxPayloadBytes: options.maxPayloadBytes ?? (process.env.OBSERVATORY_MAX_PAYLOAD_BYTES ? Number(process.env.OBSERVATORY_MAX_PAYLOAD_BYTES) : 1e4),
|
|
554
|
+
maxTransitions: options.maxTransitions ?? (process.env.OBSERVATORY_MAX_TRANSITIONS ? Number(process.env.OBSERVATORY_MAX_TRANSITIONS) : 500),
|
|
555
|
+
maxComposableHistory: options.maxComposableHistory ?? (process.env.OBSERVATORY_MAX_COMPOSABLE_HISTORY ? Number(process.env.OBSERVATORY_MAX_COMPOSABLE_HISTORY) : 50),
|
|
556
|
+
maxComposableEntries: options.maxComposableEntries ?? (process.env.OBSERVATORY_MAX_COMPOSABLE_ENTRIES ? Number(process.env.OBSERVATORY_MAX_COMPOSABLE_ENTRIES) : 300),
|
|
557
|
+
maxRenderTimeline: options.maxRenderTimeline ?? (process.env.OBSERVATORY_MAX_RENDER_TIMELINE ? Number(process.env.OBSERVATORY_MAX_RENDER_TIMELINE) : 100)
|
|
558
|
+
};
|
|
537
559
|
nuxt.hook("vite:extendConfig", (config) => {
|
|
538
560
|
const alias = config.resolve?.alias;
|
|
539
561
|
const aliases = Array.isArray(alias) ? {} : alias ?? {};
|
|
@@ -544,22 +566,22 @@ const module$1 = defineNuxtModule({
|
|
|
544
566
|
aliases["nuxt-devtools-observatory/runtime/fetch-registry"] = resolver.resolve("./runtime/composables/fetch-registry");
|
|
545
567
|
config.resolve = { ...config.resolve, alias: aliases };
|
|
546
568
|
});
|
|
547
|
-
if (
|
|
569
|
+
if (resolved.fetchDashboard) {
|
|
548
570
|
addVitePlugin(fetchInstrumentPlugin());
|
|
549
571
|
}
|
|
550
|
-
if (
|
|
572
|
+
if (resolved.provideInjectGraph) {
|
|
551
573
|
addVitePlugin(provideInjectPlugin());
|
|
552
574
|
}
|
|
553
|
-
if (
|
|
575
|
+
if (resolved.composableTracker) {
|
|
554
576
|
addVitePlugin(composableTrackerPlugin());
|
|
555
577
|
}
|
|
556
|
-
if (
|
|
578
|
+
if (resolved.transitionTracker) {
|
|
557
579
|
addVitePlugin(transitionTrackerPlugin());
|
|
558
580
|
}
|
|
559
|
-
if (
|
|
581
|
+
if (resolved.fetchDashboard || resolved.provideInjectGraph || resolved.composableTracker || resolved.renderHeatmap || resolved.transitionTracker) {
|
|
560
582
|
addPlugin(resolver.resolve("./runtime/plugin"));
|
|
561
583
|
}
|
|
562
|
-
if (
|
|
584
|
+
if (resolved.fetchDashboard) {
|
|
563
585
|
addServerPlugin(resolver.resolve("./runtime/nitro/fetch-capture"));
|
|
564
586
|
}
|
|
565
587
|
const CLIENT_PORT = 4949;
|
|
@@ -590,56 +612,38 @@ const module$1 = defineNuxtModule({
|
|
|
590
612
|
});
|
|
591
613
|
});
|
|
592
614
|
const base = clientOrigin;
|
|
593
|
-
nuxt.hook("
|
|
594
|
-
if (
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
icon: "carbon:radio-button",
|
|
599
|
-
view: { type: "iframe", src: `${base}/fetch` }
|
|
600
|
-
});
|
|
615
|
+
nuxt.hook("render:response", (response, { url }) => {
|
|
616
|
+
if (url.startsWith("/trackers") || url === "/" || url.startsWith("/index.html")) {
|
|
617
|
+
const configScript = `<script>window.__observatoryConfig = ${JSON.stringify(nuxt.options.runtimeConfig.public.observatory)};<\/script>`;
|
|
618
|
+
response.body = response.body.replace("<head>", `<head>
|
|
619
|
+
${configScript}`);
|
|
601
620
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
title: "provide/inject",
|
|
606
|
-
icon: "carbon:branch",
|
|
607
|
-
view: { type: "iframe", src: `${base}/provide` }
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
if (options.composableTracker) {
|
|
611
|
-
tabs.push({
|
|
612
|
-
name: "observatory-composables",
|
|
613
|
-
title: "Composables",
|
|
614
|
-
icon: "carbon:function",
|
|
615
|
-
view: { type: "iframe", src: `${base}/composables` }
|
|
616
|
-
});
|
|
617
|
-
}
|
|
618
|
-
if (options.renderHeatmap) {
|
|
621
|
+
});
|
|
622
|
+
nuxt.hook("devtools:customTabs", (tabs) => {
|
|
623
|
+
if (resolved.fetchDashboard || resolved.provideInjectGraph || resolved.composableTracker || resolved.renderHeatmap || resolved.transitionTracker) {
|
|
619
624
|
tabs.push({
|
|
620
|
-
name: "observatory-
|
|
621
|
-
title: "
|
|
625
|
+
name: "observatory-trackers",
|
|
626
|
+
title: "Observatory Trackers",
|
|
622
627
|
icon: "carbon:heat-map",
|
|
623
|
-
view: { type: "iframe", src: `${base}/
|
|
624
|
-
});
|
|
625
|
-
}
|
|
626
|
-
if (options.transitionTracker) {
|
|
627
|
-
tabs.push({
|
|
628
|
-
name: "observatory-transitions",
|
|
629
|
-
title: "Transitions",
|
|
630
|
-
icon: "carbon:movement",
|
|
631
|
-
view: { type: "iframe", src: `${base}/transitions` }
|
|
628
|
+
view: { type: "iframe", src: `${base}/trackers` }
|
|
632
629
|
});
|
|
633
630
|
}
|
|
634
631
|
});
|
|
635
632
|
nuxt.options.runtimeConfig.public.observatory = {
|
|
636
|
-
|
|
633
|
+
heatmapThresholdCount: resolved.heatmapThresholdCount,
|
|
634
|
+
heatmapThresholdTime: resolved.heatmapThresholdTime,
|
|
637
635
|
clientOrigin,
|
|
638
|
-
fetchDashboard:
|
|
639
|
-
provideInjectGraph:
|
|
640
|
-
composableTracker:
|
|
641
|
-
renderHeatmap:
|
|
642
|
-
transitionTracker:
|
|
636
|
+
fetchDashboard: resolved.fetchDashboard,
|
|
637
|
+
provideInjectGraph: resolved.provideInjectGraph,
|
|
638
|
+
composableTracker: resolved.composableTracker,
|
|
639
|
+
renderHeatmap: resolved.renderHeatmap,
|
|
640
|
+
transitionTracker: resolved.transitionTracker,
|
|
641
|
+
maxFetchEntries: resolved.maxFetchEntries,
|
|
642
|
+
maxPayloadBytes: resolved.maxPayloadBytes,
|
|
643
|
+
maxTransitions: resolved.maxTransitions,
|
|
644
|
+
maxComposableHistory: resolved.maxComposableHistory,
|
|
645
|
+
maxComposableEntries: resolved.maxComposableEntries,
|
|
646
|
+
maxRenderTimeline: resolved.maxRenderTimeline
|
|
643
647
|
};
|
|
644
648
|
}
|
|
645
649
|
});
|
|
@@ -41,7 +41,20 @@ export interface ComposableEntry {
|
|
|
41
41
|
* - `register`: Registers a new composable entry.
|
|
42
42
|
* - `update`: Updates an existing composable entry.
|
|
43
43
|
* - `getAll`: Retrieves all composable entries.
|
|
44
|
-
*
|
|
44
|
+
* - `getSnapshot`: Returns a cached pre-serialized JSON string, rebuilt only when dirty.
|
|
45
|
+
* @returns {{
|
|
46
|
+
* register: (entry: ComposableEntry) => void,
|
|
47
|
+
* registerLiveRefs: (id: string, refs: Record<string, import('vue').Ref<unknown>>) => void,
|
|
48
|
+
* registerRawRefs: (id: string, refs: Record<string, unknown>) => void,
|
|
49
|
+
* onComposableChange: (cb: () => void) => void,
|
|
50
|
+
* clear: () => void,
|
|
51
|
+
* setRoute: (path: string) => void,
|
|
52
|
+
* getRoute: () => string,
|
|
53
|
+
* update: (id: string, patch: Partial<ComposableEntry>) => void,
|
|
54
|
+
* getAll: () => ComposableEntry[],
|
|
55
|
+
* getSnapshot: () => string,
|
|
56
|
+
* editValue: (id: string, key: string, value: unknown) => void
|
|
57
|
+
* }} An object with `register`, `update`, `getAll`, `getSnapshot`, and related methods.
|
|
45
58
|
*/
|
|
46
59
|
export declare function setupComposableRegistry(): {
|
|
47
60
|
register: (entry: ComposableEntry) => void;
|
|
@@ -53,6 +66,7 @@ export declare function setupComposableRegistry(): {
|
|
|
53
66
|
getRoute: () => string;
|
|
54
67
|
update: (id: string, patch: Partial<ComposableEntry>) => void;
|
|
55
68
|
getAll: () => ComposableEntry[];
|
|
69
|
+
getSnapshot: () => string;
|
|
56
70
|
editValue: (id: string, key: string, value: unknown) => void;
|
|
57
71
|
};
|
|
58
72
|
export declare function __trackComposable<T>(name: string, callFn: () => T, meta: {
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isRef, isReactive, isReadonly, unref, computed, watchEffect, getCurrentInstance, onUnmounted } from "vue";
|
|
2
2
|
export function setupComposableRegistry() {
|
|
3
|
-
const entries =
|
|
3
|
+
const entries = /* @__PURE__ */ new Map();
|
|
4
4
|
const liveRefs = /* @__PURE__ */ new Map();
|
|
5
5
|
const liveRefWatchers = /* @__PURE__ */ new Map();
|
|
6
|
-
const MAX_HISTORY = 50;
|
|
7
|
-
const MAX_COMPOSABLE_ENTRIES = 300;
|
|
8
|
-
const
|
|
6
|
+
const MAX_HISTORY = typeof process !== "undefined" && process.env.OBSERVATORY_MAX_COMPOSABLE_HISTORY ? Number(process.env.OBSERVATORY_MAX_COMPOSABLE_HISTORY) : 50;
|
|
7
|
+
const MAX_COMPOSABLE_ENTRIES = typeof process !== "undefined" && process.env.OBSERVATORY_MAX_COMPOSABLE_ENTRIES ? Number(process.env.OBSERVATORY_MAX_COMPOSABLE_ENTRIES) : 300;
|
|
8
|
+
const entryHistory = /* @__PURE__ */ new Map();
|
|
9
9
|
const prevValues = /* @__PURE__ */ new Map();
|
|
10
10
|
const rawRefs = /* @__PURE__ */ new Map();
|
|
11
11
|
const sharedKeysCache = /* @__PURE__ */ new Map();
|
|
12
|
+
let dirty = true;
|
|
13
|
+
let cachedSnapshot = "[]";
|
|
14
|
+
function markDirty() {
|
|
15
|
+
dirty = true;
|
|
16
|
+
}
|
|
12
17
|
function invalidateSharedKeysForName(name) {
|
|
13
18
|
sharedKeysCache.delete(name);
|
|
19
|
+
markDirty();
|
|
14
20
|
}
|
|
15
21
|
function deleteEntry(entryId, entryName) {
|
|
16
22
|
const stop = liveRefWatchers.get(entryId);
|
|
@@ -21,8 +27,8 @@ export function setupComposableRegistry() {
|
|
|
21
27
|
liveRefs.delete(entryId);
|
|
22
28
|
rawRefs.delete(entryId);
|
|
23
29
|
prevValues.delete(entryId);
|
|
24
|
-
|
|
25
|
-
entries.
|
|
30
|
+
entryHistory.delete(entryId);
|
|
31
|
+
entries.delete(entryId);
|
|
26
32
|
invalidateSharedKeysForName(entryName);
|
|
27
33
|
}
|
|
28
34
|
function getSharedKeys(id, name) {
|
|
@@ -32,7 +38,7 @@ export function setupComposableRegistry() {
|
|
|
32
38
|
}
|
|
33
39
|
nameCache = /* @__PURE__ */ new Map();
|
|
34
40
|
sharedKeysCache.set(name, nameCache);
|
|
35
|
-
const peers = [...entries.
|
|
41
|
+
const peers = [...entries.entries()].filter(([, e]) => e.name === name);
|
|
36
42
|
for (const [eid] of peers) {
|
|
37
43
|
const ownRaw = rawRefs.get(eid);
|
|
38
44
|
if (!ownRaw) {
|
|
@@ -66,16 +72,17 @@ export function setupComposableRegistry() {
|
|
|
66
72
|
return currentRoute;
|
|
67
73
|
}
|
|
68
74
|
function register(entry) {
|
|
69
|
-
if (entries.
|
|
70
|
-
const unmountedId = [...entries.
|
|
71
|
-
const evictId = unmountedId ?? entries.
|
|
75
|
+
if (entries.size >= MAX_COMPOSABLE_ENTRIES) {
|
|
76
|
+
const unmountedId = [...entries.entries()].find(([, e]) => e.status === "unmounted")?.[0];
|
|
77
|
+
const evictId = unmountedId ?? entries.keys().next().value;
|
|
72
78
|
if (evictId !== void 0) {
|
|
73
|
-
const evictName = entries.
|
|
79
|
+
const evictName = entries.get(evictId)?.name ?? "";
|
|
74
80
|
deleteEntry(evictId, evictName);
|
|
75
81
|
}
|
|
76
82
|
}
|
|
77
|
-
entries.
|
|
83
|
+
entries.set(entry.id, entry);
|
|
78
84
|
invalidateSharedKeysForName(entry.name);
|
|
85
|
+
markDirty();
|
|
79
86
|
emit("composable:register", entry);
|
|
80
87
|
}
|
|
81
88
|
function registerLiveRefs(id, refs) {
|
|
@@ -111,13 +118,14 @@ export function setupComposableRegistry() {
|
|
|
111
118
|
const prev = prevValues.get(id);
|
|
112
119
|
if (prev && serialised !== prev[k]) {
|
|
113
120
|
const t = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
114
|
-
const history =
|
|
121
|
+
const history = entryHistory.get(id) ?? [];
|
|
115
122
|
history.push({ t, key: k, value: safeValue(val) });
|
|
116
123
|
if (history.length > MAX_HISTORY) {
|
|
117
124
|
history.shift();
|
|
118
125
|
}
|
|
119
|
-
|
|
126
|
+
entryHistory.set(id, history);
|
|
120
127
|
prev[k] = serialised;
|
|
128
|
+
markDirty();
|
|
121
129
|
_scheduleOnChange();
|
|
122
130
|
}
|
|
123
131
|
});
|
|
@@ -144,12 +152,13 @@ export function setupComposableRegistry() {
|
|
|
144
152
|
_onChange = cb;
|
|
145
153
|
}
|
|
146
154
|
function update(id, patch) {
|
|
147
|
-
const existing = entries.
|
|
155
|
+
const existing = entries.get(id);
|
|
148
156
|
if (!existing) {
|
|
149
157
|
return;
|
|
150
158
|
}
|
|
151
159
|
const updated = { ...existing, ...patch };
|
|
152
|
-
entries.
|
|
160
|
+
entries.set(id, updated);
|
|
161
|
+
markDirty();
|
|
153
162
|
emit("composable:update", updated);
|
|
154
163
|
}
|
|
155
164
|
function safeValue(val) {
|
|
@@ -197,7 +206,7 @@ export function setupComposableRegistry() {
|
|
|
197
206
|
leak: entry.leak,
|
|
198
207
|
leakReason: entry.leakReason,
|
|
199
208
|
refs: freshRefs,
|
|
200
|
-
history:
|
|
209
|
+
history: entryHistory.get(entry.id) ?? [],
|
|
201
210
|
sharedKeys: getSharedKeys(entry.id, entry.name),
|
|
202
211
|
watcherCount: entry.watcherCount,
|
|
203
212
|
intervalCount: entry.intervalCount,
|
|
@@ -208,7 +217,19 @@ export function setupComposableRegistry() {
|
|
|
208
217
|
};
|
|
209
218
|
}
|
|
210
219
|
function getAll() {
|
|
211
|
-
return [...entries.
|
|
220
|
+
return [...entries.values()].map(sanitize);
|
|
221
|
+
}
|
|
222
|
+
function getSnapshot() {
|
|
223
|
+
if (!dirty) {
|
|
224
|
+
return cachedSnapshot;
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
cachedSnapshot = JSON.stringify([...entries.values()].map(sanitize)) ?? "[]";
|
|
228
|
+
} catch {
|
|
229
|
+
cachedSnapshot = "[]";
|
|
230
|
+
}
|
|
231
|
+
dirty = false;
|
|
232
|
+
return cachedSnapshot;
|
|
212
233
|
}
|
|
213
234
|
function emit(event, data) {
|
|
214
235
|
if (!import.meta.client) {
|
|
@@ -227,9 +248,10 @@ export function setupComposableRegistry() {
|
|
|
227
248
|
liveRefs.clear();
|
|
228
249
|
rawRefs.clear();
|
|
229
250
|
prevValues.clear();
|
|
230
|
-
|
|
251
|
+
entryHistory.clear();
|
|
231
252
|
sharedKeysCache.clear();
|
|
232
|
-
entries.
|
|
253
|
+
entries.clear();
|
|
254
|
+
markDirty();
|
|
233
255
|
emit("composable:clear", {});
|
|
234
256
|
}
|
|
235
257
|
function editValue(id, key, value) {
|
|
@@ -241,7 +263,7 @@ export function setupComposableRegistry() {
|
|
|
241
263
|
if (!r) {
|
|
242
264
|
return;
|
|
243
265
|
}
|
|
244
|
-
const entry = entries.
|
|
266
|
+
const entry = entries.get(id);
|
|
245
267
|
if (!entry) {
|
|
246
268
|
return;
|
|
247
269
|
}
|
|
@@ -250,7 +272,19 @@ export function setupComposableRegistry() {
|
|
|
250
272
|
}
|
|
251
273
|
r.value = value;
|
|
252
274
|
}
|
|
253
|
-
return {
|
|
275
|
+
return {
|
|
276
|
+
register,
|
|
277
|
+
registerLiveRefs,
|
|
278
|
+
registerRawRefs,
|
|
279
|
+
onComposableChange,
|
|
280
|
+
clear,
|
|
281
|
+
setRoute,
|
|
282
|
+
getRoute,
|
|
283
|
+
update,
|
|
284
|
+
getAll,
|
|
285
|
+
getSnapshot,
|
|
286
|
+
editValue
|
|
287
|
+
};
|
|
254
288
|
}
|
|
255
289
|
export function __trackComposable(name, callFn, meta) {
|
|
256
290
|
if (!import.meta.dev) {
|
|
@@ -367,7 +401,6 @@ export function __trackComposable(name, callFn, meta) {
|
|
|
367
401
|
}
|
|
368
402
|
});
|
|
369
403
|
registry.registerLiveRefs(id, {});
|
|
370
|
-
entryHistory.delete(id);
|
|
371
404
|
});
|
|
372
405
|
}
|
|
373
406
|
return result;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface FetchEntry {
|
|
2
|
-
id: string;
|
|
2
|
+
id: number | string;
|
|
3
3
|
key: string;
|
|
4
4
|
url: string;
|
|
5
5
|
status: 'pending' | 'ok' | 'error' | 'cached';
|
|
@@ -45,9 +45,10 @@ export declare function setupFetchRegistry(): {
|
|
|
45
45
|
register: (entry: FetchEntry) => void;
|
|
46
46
|
update: (id: string, patch: Partial<FetchEntry>) => void;
|
|
47
47
|
getAll: () => FetchEntry[];
|
|
48
|
+
getSnapshot: () => FetchEntry[];
|
|
48
49
|
clear: () => void;
|
|
49
|
-
entries:
|
|
50
|
-
readonly id: string;
|
|
50
|
+
entries: ReadonlyMap<string | number, {
|
|
51
|
+
readonly id: number | string;
|
|
51
52
|
readonly key: string;
|
|
52
53
|
readonly url: string;
|
|
53
54
|
readonly status: "pending" | "ok" | "error" | "cached";
|
|
@@ -61,22 +62,7 @@ export declare function setupFetchRegistry(): {
|
|
|
61
62
|
readonly error?: Readonly<unknown> | undefined;
|
|
62
63
|
readonly file?: string | undefined;
|
|
63
64
|
readonly line?: number | undefined;
|
|
64
|
-
}
|
|
65
|
-
readonly id: string;
|
|
66
|
-
readonly key: string;
|
|
67
|
-
readonly url: string;
|
|
68
|
-
readonly status: "pending" | "ok" | "error" | "cached";
|
|
69
|
-
readonly origin: "ssr" | "csr";
|
|
70
|
-
readonly startTime: number;
|
|
71
|
-
readonly endTime?: number | undefined;
|
|
72
|
-
readonly ms?: number | undefined;
|
|
73
|
-
readonly size?: number | undefined;
|
|
74
|
-
readonly cached: boolean;
|
|
75
|
-
readonly payload?: Readonly<unknown> | undefined;
|
|
76
|
-
readonly error?: Readonly<unknown> | undefined;
|
|
77
|
-
readonly file?: string | undefined;
|
|
78
|
-
readonly line?: number | undefined;
|
|
79
|
-
}>>>;
|
|
65
|
+
}>;
|
|
80
66
|
};
|
|
81
67
|
export declare function __devFetchHandler(handler: (...args: unknown[]) => unknown, key: unknown, meta: FetchMeta): (...args: unknown[]) => Promise<unknown>;
|
|
82
68
|
export declare function __devFetchCall(originalFn: (url: string, opts: FetchOptions) => FetchResult, url: string, opts: FetchOptions, meta: FetchMeta): FetchResult;
|