nuxt-schema-org 6.1.3 → 6.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.
Files changed (127) hide show
  1. package/dist/devtools/components/schema-org/SchemaValidator.vue +326 -0
  2. package/dist/devtools/lib/schema-org/fetch.ts +13 -0
  3. package/dist/devtools/lib/schema-org/rpc.ts +46 -0
  4. package/dist/devtools/lib/schema-org/util/schema-validation.ts +470 -0
  5. package/dist/devtools/nuxt.config.ts +7 -0
  6. package/dist/devtools/pages/schema-org/debug.vue +23 -0
  7. package/dist/devtools/pages/schema-org/docs.vue +3 -0
  8. package/dist/devtools/pages/schema-org/index.vue +8 -0
  9. package/dist/devtools/pages/schema-org/raw.vue +25 -0
  10. package/dist/devtools/pages/schema-org.vue +54 -0
  11. package/dist/module.cjs +28 -7
  12. package/dist/module.d.cts +1 -1
  13. package/dist/module.d.mts +1 -1
  14. package/dist/module.d.ts +1 -1
  15. package/dist/module.json +1 -1
  16. package/dist/module.mjs +28 -7
  17. package/dist/schema.cjs +2147 -9
  18. package/dist/schema.d.cts +185 -1
  19. package/dist/schema.d.mts +185 -1
  20. package/dist/schema.d.ts +185 -1
  21. package/dist/schema.mjs +2035 -1
  22. package/dist/shared/nuxt-schema-org.BQ-jW5j5.d.cts +2770 -0
  23. package/dist/shared/nuxt-schema-org.BQ-jW5j5.d.mts +2770 -0
  24. package/dist/shared/nuxt-schema-org.BQ-jW5j5.d.ts +2770 -0
  25. package/dist/vendor/schema-org-v2/LICENSE +21 -0
  26. package/dist/vendor/schema-org-v2/chunks/index.mjs +23 -0
  27. package/dist/vendor/schema-org-v2/chunks/index10.mjs +63 -0
  28. package/dist/vendor/schema-org-v2/chunks/index11.mjs +35 -0
  29. package/dist/vendor/schema-org-v2/chunks/index12.mjs +48 -0
  30. package/dist/vendor/schema-org-v2/chunks/index13.mjs +36 -0
  31. package/dist/vendor/schema-org-v2/chunks/index14.mjs +25 -0
  32. package/dist/vendor/schema-org-v2/chunks/index15.mjs +37 -0
  33. package/dist/vendor/schema-org-v2/chunks/index16.mjs +27 -0
  34. package/dist/vendor/schema-org-v2/chunks/index17.mjs +34 -0
  35. package/dist/vendor/schema-org-v2/chunks/index18.mjs +32 -0
  36. package/dist/vendor/schema-org-v2/chunks/index19.mjs +31 -0
  37. package/dist/vendor/schema-org-v2/chunks/index2.mjs +12 -0
  38. package/dist/vendor/schema-org-v2/chunks/index20.mjs +31 -0
  39. package/dist/vendor/schema-org-v2/chunks/index21.mjs +30 -0
  40. package/dist/vendor/schema-org-v2/chunks/index22.mjs +30 -0
  41. package/dist/vendor/schema-org-v2/chunks/index23.mjs +82 -0
  42. package/dist/vendor/schema-org-v2/chunks/index24.mjs +14 -0
  43. package/dist/vendor/schema-org-v2/chunks/index25.mjs +33 -0
  44. package/dist/vendor/schema-org-v2/chunks/index26.mjs +31 -0
  45. package/dist/vendor/schema-org-v2/chunks/index27.mjs +29 -0
  46. package/dist/vendor/schema-org-v2/chunks/index28.mjs +12 -0
  47. package/dist/vendor/schema-org-v2/chunks/index29.mjs +46 -0
  48. package/dist/vendor/schema-org-v2/chunks/index3.mjs +317 -0
  49. package/dist/vendor/schema-org-v2/chunks/index30.mjs +53 -0
  50. package/dist/vendor/schema-org-v2/chunks/index31.mjs +41 -0
  51. package/dist/vendor/schema-org-v2/chunks/index32.mjs +26 -0
  52. package/dist/vendor/schema-org-v2/chunks/index33.mjs +47 -0
  53. package/dist/vendor/schema-org-v2/chunks/index34.mjs +29 -0
  54. package/dist/vendor/schema-org-v2/chunks/index35.mjs +34 -0
  55. package/dist/vendor/schema-org-v2/chunks/index36.mjs +33 -0
  56. package/dist/vendor/schema-org-v2/chunks/index37.mjs +34 -0
  57. package/dist/vendor/schema-org-v2/chunks/index38.mjs +51 -0
  58. package/dist/vendor/schema-org-v2/chunks/index39.mjs +17 -0
  59. package/dist/vendor/schema-org-v2/chunks/index4.mjs +54 -0
  60. package/dist/vendor/schema-org-v2/chunks/index40.mjs +29 -0
  61. package/dist/vendor/schema-org-v2/chunks/index5.mjs +31 -0
  62. package/dist/vendor/schema-org-v2/chunks/index6.mjs +29 -0
  63. package/dist/vendor/schema-org-v2/chunks/index7.mjs +35 -0
  64. package/dist/vendor/schema-org-v2/chunks/index8.mjs +18 -0
  65. package/dist/vendor/schema-org-v2/chunks/index9.mjs +20 -0
  66. package/dist/vendor/schema-org-v2/index.d.mts +32 -0
  67. package/dist/vendor/schema-org-v2/index.d.ts +32 -0
  68. package/dist/vendor/schema-org-v2/index.mjs +46 -0
  69. package/dist/vendor/schema-org-v2/shared/schema-org.BR4WcSqZ.d.ts +21 -0
  70. package/dist/vendor/schema-org-v2/shared/schema-org.Ba7D0Hp1.mjs +19 -0
  71. package/dist/vendor/schema-org-v2/shared/schema-org.CAKsqzbX.d.ts +1022 -0
  72. package/dist/vendor/schema-org-v2/shared/schema-org.CFcsqFfN.d.mts +1824 -0
  73. package/dist/vendor/schema-org-v2/shared/schema-org.CFcsqFfN.d.ts +1824 -0
  74. package/dist/vendor/schema-org-v2/shared/schema-org.CHbRCiep.mjs +52 -0
  75. package/dist/vendor/schema-org-v2/shared/schema-org.Dryb3EoR.mjs +884 -0
  76. package/dist/vendor/schema-org-v2/shared/schema-org.F44ipjVJ.mjs +27 -0
  77. package/dist/vendor/schema-org-v2/shared/schema-org.UT1u1UYq.d.mts +1022 -0
  78. package/dist/vendor/schema-org-v2/shared/schema-org.oFHFm6my.d.mts +21 -0
  79. package/dist/vendor/schema-org-v2/vendor.json +4 -0
  80. package/dist/vendor/schema-org-v2/vue.d.mts +88 -0
  81. package/dist/vendor/schema-org-v2/vue.d.ts +88 -0
  82. package/dist/vendor/schema-org-v2/vue.mjs +262 -0
  83. package/dist/vendor/schema-org-v3/LICENSE +21 -0
  84. package/dist/vendor/schema-org-v3/index.d.mts +34 -0
  85. package/dist/vendor/schema-org-v3/index.d.ts +34 -0
  86. package/dist/vendor/schema-org-v3/index.mjs +4 -0
  87. package/dist/vendor/schema-org-v3/shared/schema-org.D9o9UOh2.d.mts +11 -0
  88. package/dist/vendor/schema-org-v3/shared/schema-org.DNQroCjX.d.mts +2770 -0
  89. package/dist/vendor/schema-org-v3/shared/schema-org.DNQroCjX.d.ts +2770 -0
  90. package/dist/vendor/schema-org-v3/shared/schema-org.DYFTMLZ0.mjs +2035 -0
  91. package/dist/vendor/schema-org-v3/shared/schema-org.DjDPlqPB.d.mts +150 -0
  92. package/dist/vendor/schema-org-v3/shared/schema-org.mKZYVZ3E.d.ts +150 -0
  93. package/dist/vendor/schema-org-v3/shared/schema-org.rS-TANmN.d.ts +11 -0
  94. package/dist/vendor/schema-org-v3/vendor.json +4 -0
  95. package/dist/vendor/schema-org-v3/vue.d.mts +100 -0
  96. package/dist/vendor/schema-org-v3/vue.d.ts +100 -0
  97. package/dist/vendor/schema-org-v3/vue.mjs +302 -0
  98. package/package.json +12 -12
  99. package/dist/devtools/200.html +0 -1
  100. package/dist/devtools/404.html +0 -1
  101. package/dist/devtools/_nuxt/B1DdtD2d.js +0 -30
  102. package/dist/devtools/_nuxt/BOpHBWj1.js +0 -1
  103. package/dist/devtools/_nuxt/BdQEHo9i.js +0 -1
  104. package/dist/devtools/_nuxt/BvDCh0XJ.js +0 -1
  105. package/dist/devtools/_nuxt/C6vgB62o.js +0 -1
  106. package/dist/devtools/_nuxt/CCjZBs6a.js +0 -3
  107. package/dist/devtools/_nuxt/CHHO6nw6.js +0 -1
  108. package/dist/devtools/_nuxt/CQr7N5ou.js +0 -6
  109. package/dist/devtools/_nuxt/CRABcd13.js +0 -1
  110. package/dist/devtools/_nuxt/Cy67RPmZ.js +0 -1
  111. package/dist/devtools/_nuxt/D-Oj-loM.js +0 -154
  112. package/dist/devtools/_nuxt/D6u4txBo.js +0 -1
  113. package/dist/devtools/_nuxt/DKZUJ--l.js +0 -1
  114. package/dist/devtools/_nuxt/DLXftbE1.js +0 -1
  115. package/dist/devtools/_nuxt/DevtoolsSnippet.CuW0O0Zu.css +0 -1
  116. package/dist/devtools/_nuxt/QcnxyHc5.js +0 -1
  117. package/dist/devtools/_nuxt/builds/latest.json +0 -1
  118. package/dist/devtools/_nuxt/builds/meta/b29085bd-1521-40f3-8c81-bdc818184bef.json +0 -1
  119. package/dist/devtools/_nuxt/entry.DprwPCib.css +0 -2
  120. package/dist/devtools/_nuxt/fira-code.Bc8wnsZt.woff2 +0 -0
  121. package/dist/devtools/_nuxt/hubot-sans.DLGyhQVu.woff2 +0 -0
  122. package/dist/devtools/_nuxt/pages.BpqfEWCe.css +0 -1
  123. package/dist/devtools/debug/index.html +0 -1
  124. package/dist/devtools/docs/index.html +0 -1
  125. package/dist/devtools/index.html +0 -1
  126. package/dist/devtools/nodes/index.html +0 -1
  127. package/dist/devtools/raw/index.html +0 -1
@@ -0,0 +1,326 @@
1
+ <script setup lang="ts">
2
+ import {
3
+ analyzeNodeProperties,
4
+ formatPropertyValue,
5
+ getNestedProperty,
6
+ getNodeDescription,
7
+ getNodeType,
8
+ getSchemaIcon,
9
+ googleRichResultsRequirements,
10
+ isRichResultType,
11
+ nodeToSchemaOrgLink,
12
+ validateGraph,
13
+ } from '../../lib/schema-org/util/schema-validation'
14
+
15
+ const { graph } = defineProps<{
16
+ graph: string
17
+ }>()
18
+
19
+ const parsed = computed(() => {
20
+ try {
21
+ return JSON.parse(graph)
22
+ }
23
+ catch {
24
+ return null
25
+ }
26
+ })
27
+
28
+ const validation = computed(() => {
29
+ if (!parsed.value)
30
+ return null
31
+ return validateGraph(parsed.value)
32
+ })
33
+
34
+ const overallStatus = computed(() => {
35
+ if (!validation.value)
36
+ return null
37
+
38
+ const { summary } = validation.value
39
+
40
+ if (summary.totalNodes === 0) {
41
+ return {
42
+ variant: 'warning' as const,
43
+ icon: 'carbon:warning',
44
+ message: 'No structured data nodes detected on this page.',
45
+ }
46
+ }
47
+
48
+ if (summary.totalErrors > 0) {
49
+ return {
50
+ variant: 'error' as const,
51
+ icon: 'carbon:close-filled',
52
+ message: `Found ${summary.totalErrors} missing required property${summary.totalErrors > 1 ? 'ies' : 'y'} across ${summary.totalNodes} node${summary.totalNodes > 1 ? 's' : ''}`,
53
+ }
54
+ }
55
+
56
+ if (summary.totalWarnings > 0) {
57
+ return {
58
+ variant: 'warning' as const,
59
+ icon: 'carbon:warning',
60
+ message: `${summary.totalWarnings} missing recommended property${summary.totalWarnings > 1 ? 'ies' : 'y'}, but all required fields present`,
61
+ }
62
+ }
63
+
64
+ return {
65
+ variant: 'success' as const,
66
+ icon: 'carbon:checkmark-filled',
67
+ message: `All ${summary.totalNodes} node${summary.totalNodes > 1 ? 's' : ''} validated successfully.`,
68
+ }
69
+ })
70
+
71
+ const displayNodes = computed(() => {
72
+ if (!validation.value)
73
+ return []
74
+ return validation.value.nodes.filter((node) => {
75
+ return getNodeType(node) !== 'Unknown'
76
+ })
77
+ })
78
+
79
+ // Per-card view mode: 'validate' or 'json'
80
+ const cardViewModes = reactive(new Map<number, 'validate' | 'json'>())
81
+
82
+ function getCardView(index: number): 'validate' | 'json' {
83
+ return cardViewModes.get(index) ?? 'validate'
84
+ }
85
+
86
+ function nodeCardClass(node: any) {
87
+ const type = getNodeType(node)
88
+ const requirements = googleRichResultsRequirements[type]
89
+ const analysis = analyzeNodeProperties(node)
90
+
91
+ if (requirements?.recommended?.length && analysis.missingRecommended.length === 0 && analysis.missingRequired.length === 0)
92
+ return 'node-card-success'
93
+ if (isRichResultType(type) && (analysis.missingRecommended.length > 0 || analysis.missingRequired.length > 0))
94
+ return 'node-card-active'
95
+ return ''
96
+ }
97
+
98
+ const foundationOnlyTypes = new Set(['WebSite', 'WebPage', 'ImageObject'])
99
+ const hasOnlyFoundationSchemas = computed(() => {
100
+ return displayNodes.value.length > 0 && displayNodes.value.every(n => foundationOnlyTypes.has(getNodeType(n)))
101
+ })
102
+ </script>
103
+
104
+ <template>
105
+ <div class="space-y-4 stagger-children">
106
+ <!-- Overall Status -->
107
+ <DevtoolsAlert
108
+ v-if="overallStatus"
109
+ :variant="overallStatus.variant"
110
+ :icon="overallStatus.icon"
111
+ >
112
+ <span class="font-medium">{{ overallStatus.message }}</span>
113
+ <template v-if="validation" #action>
114
+ <div class="flex items-center gap-2">
115
+ <UBadge>
116
+ {{ validation.summary.totalNodes }} nodes
117
+ </UBadge>
118
+ <UBadge v-if="validation.summary.richResultNodes > 0" color="primary">
119
+ {{ validation.summary.richResultNodes }} rich result eligible
120
+ </UBadge>
121
+ </div>
122
+ </template>
123
+ </DevtoolsAlert>
124
+
125
+ <!-- Foundation-only message -->
126
+ <DevtoolsEmptyState
127
+ v-if="hasOnlyFoundationSchemas"
128
+ title="Only foundation schemas detected"
129
+ description="Only WebSite, WebPage, and ImageObject found. Consider adding rich result schemas for better search visibility."
130
+ icon="carbon:information"
131
+ />
132
+
133
+ <!-- Node Cards -->
134
+ <div v-for="(node, index) in displayNodes" :key="index" class="node-card" :class="nodeCardClass(node)">
135
+ <!-- Header -->
136
+ <div class="flex items-start justify-between mb-3">
137
+ <div class="flex items-center gap-2 min-w-0">
138
+ <UIcon
139
+ :name="getSchemaIcon(getNodeType(node))"
140
+ :class="isRichResultType(getNodeType(node)) ? 'text-[var(--seo-green)]' : 'text-[var(--color-text-muted)]'"
141
+ class="shrink-0"
142
+ />
143
+ <span class="font-semibold text-sm">{{ getNodeType(node) }}</span>
144
+ <UBadge v-if="isRichResultType(getNodeType(node))" color="primary">
145
+ Rich Result
146
+ </UBadge>
147
+ </div>
148
+ <div class="flex items-center shrink-0">
149
+ <!-- View mode toggle -->
150
+ <UButton
151
+ icon="carbon:checkmark-outline"
152
+ size="xs"
153
+ :variant="getCardView(index) === 'validate' ? 'subtle' : 'ghost'"
154
+ :color="getCardView(index) === 'validate' ? 'primary' : 'neutral'"
155
+ title="Validation view"
156
+ @click="cardViewModes.set(index, 'validate')"
157
+ />
158
+ <UButton
159
+ icon="carbon:code"
160
+ size="xs"
161
+ :variant="getCardView(index) === 'json' ? 'subtle' : 'ghost'"
162
+ :color="getCardView(index) === 'json' ? 'primary' : 'neutral'"
163
+ title="JSON view"
164
+ @click="cardViewModes.set(index, 'json')"
165
+ />
166
+ <!-- Docs link -->
167
+ <UButton
168
+ v-if="googleRichResultsRequirements[getNodeType(node)]"
169
+ icon="carbon:launch"
170
+ size="xs"
171
+ variant="ghost"
172
+ color="neutral"
173
+ :to="googleRichResultsRequirements[getNodeType(node)].documentationUrl"
174
+ target="_blank"
175
+ title="Google Rich Results docs"
176
+ />
177
+ </div>
178
+ </div>
179
+
180
+ <!-- Description / ID -->
181
+ <p v-if="getNodeDescription(node)" class="text-xs text-[var(--color-text-muted)] mb-3 truncate">
182
+ {{ getNodeDescription(node) }}
183
+ </p>
184
+
185
+ <!-- ===== Validate View ===== -->
186
+ <template v-if="getCardView(index) === 'validate'">
187
+ <!-- Validation Status -->
188
+ <DevtoolsAlert v-if="analyzeNodeProperties(node).missingRequired.length > 0" variant="error" class="mb-3">
189
+ <span class="font-medium">Missing required:</span>
190
+ <span class="ml-1 opacity-80">{{ analyzeNodeProperties(node).missingRequired.join(', ') }}</span>
191
+ </DevtoolsAlert>
192
+
193
+ <DevtoolsAlert
194
+ v-else-if="googleRichResultsRequirements[getNodeType(node)]?.recommended?.length > 0 && analyzeNodeProperties(node).missingRecommended.length === 0"
195
+ variant="success"
196
+ class="mb-3"
197
+ >
198
+ <span class="font-medium">Excellent!</span>
199
+ <span class="ml-1 opacity-80">All recommended properties present</span>
200
+ </DevtoolsAlert>
201
+
202
+ <DevtoolsAlert
203
+ v-else-if="analyzeNodeProperties(node).missingRecommended.length > 0 && analyzeNodeProperties(node).missingRecommended.length <= 5"
204
+ variant="warning"
205
+ class="mb-3"
206
+ >
207
+ <span class="font-medium">Missing recommended:</span>
208
+ <span class="ml-1 opacity-80">{{ analyzeNodeProperties(node).missingRecommended.slice(0, 5).join(', ') }}</span>
209
+ </DevtoolsAlert>
210
+
211
+ <!-- Property Checklists -->
212
+ <div class="space-y-3">
213
+ <!-- Required Properties -->
214
+ <div v-if="googleRichResultsRequirements[getNodeType(node)]?.required?.length > 0">
215
+ <h5 class="text-xs font-medium mb-2">
216
+ Required Properties
217
+ </h5>
218
+ <div class="space-y-1.5">
219
+ <div
220
+ v-for="prop in googleRichResultsRequirements[getNodeType(node)].required"
221
+ :key="prop"
222
+ class="flex items-center gap-2 text-xs"
223
+ >
224
+ <UIcon
225
+ :name="getNestedProperty(node, prop) ? 'carbon:checkmark-filled' : 'carbon:close-filled'"
226
+ :class="getNestedProperty(node, prop) ? 'text-green-500' : 'text-red-500'"
227
+ />
228
+ <span class="font-mono text-[var(--seo-green)]">{{ prop }}:</span>
229
+ <span v-if="getNestedProperty(node, prop)" class="text-[var(--color-text-subtle)] truncate">
230
+ {{ formatPropertyValue(getNestedProperty(node, prop)) }}
231
+ </span>
232
+ <span v-else class="text-red-500">missing</span>
233
+ </div>
234
+ </div>
235
+ </div>
236
+
237
+ <!-- Recommended Properties -->
238
+ <DevtoolsSection
239
+ v-if="googleRichResultsRequirements[getNodeType(node)]?.recommended?.length > 0"
240
+ :text="`Recommended Properties (${Object.keys(analyzeNodeProperties(node).presentProperties).filter(p => googleRichResultsRequirements[getNodeType(node)]?.recommended.includes(p)).length}/${googleRichResultsRequirements[getNodeType(node)]?.recommended.length})`"
241
+ :open="false"
242
+ >
243
+ <div class="space-y-1.5">
244
+ <div
245
+ v-for="prop in googleRichResultsRequirements[getNodeType(node)].recommended"
246
+ :key="prop"
247
+ class="flex items-center gap-2 text-xs"
248
+ >
249
+ <UIcon
250
+ :name="getNestedProperty(node, prop) ? 'carbon:checkmark' : 'carbon:subtract'"
251
+ :class="getNestedProperty(node, prop) ? 'text-green-500' : 'text-[var(--color-text-subtle)]'"
252
+ />
253
+ <span class="font-mono text-[var(--seo-green)] opacity-70">{{ prop }}:</span>
254
+ <span v-if="getNestedProperty(node, prop)" class="text-[var(--color-text-subtle)] truncate">
255
+ {{ formatPropertyValue(getNestedProperty(node, prop)) }}
256
+ </span>
257
+ <span v-else class="text-[var(--color-text-subtle)] opacity-50">not set</span>
258
+ </div>
259
+ </div>
260
+ </DevtoolsSection>
261
+ </div>
262
+ </template>
263
+
264
+ <!-- ===== JSON View ===== -->
265
+ <template v-else>
266
+ <div class="json-view">
267
+ <DevtoolsSnippet
268
+ :code="JSON.stringify(node, null, 2)"
269
+ lang="json"
270
+ :label="getNodeType(node)"
271
+ />
272
+ <!-- Schema.org / Rich Results links -->
273
+ <div class="flex items-center gap-1 mt-2">
274
+ <UButton
275
+ :to="nodeToSchemaOrgLink(getNodeType(node)).schemaOrg"
276
+ target="_blank"
277
+ size="xs"
278
+ variant="ghost"
279
+ color="neutral"
280
+ trailing-icon="carbon:launch"
281
+ label="Schema.org"
282
+ />
283
+ <UButton
284
+ v-if="nodeToSchemaOrgLink(getNodeType(node)).googlePage"
285
+ :to="nodeToSchemaOrgLink(getNodeType(node)).googlePage!"
286
+ target="_blank"
287
+ size="xs"
288
+ variant="ghost"
289
+ color="neutral"
290
+ trailing-icon="carbon:launch"
291
+ label="Rich Results"
292
+ />
293
+ </div>
294
+ </div>
295
+ </template>
296
+ </div>
297
+ </div>
298
+ </template>
299
+
300
+ <style scoped>
301
+ .node-card {
302
+ background: var(--color-surface-elevated);
303
+ border: 1px solid var(--color-border);
304
+ border-radius: var(--radius-lg);
305
+ padding: 1rem;
306
+ transition: border-color 200ms ease;
307
+ }
308
+
309
+ .node-card:hover {
310
+ border-color: var(--color-neutral-300);
311
+ }
312
+ .dark .node-card:hover {
313
+ border-color: var(--color-neutral-700);
314
+ }
315
+
316
+ .node-card-success {
317
+ border-color: oklch(65% 0.2 145 / 0.3);
318
+ }
319
+ .node-card-success:hover {
320
+ border-color: oklch(65% 0.2 145 / 0.5);
321
+ }
322
+
323
+ .node-card-active {
324
+ border-color: oklch(65% 0.15 250 / 0.2);
325
+ }
326
+ </style>
@@ -0,0 +1,13 @@
1
+ import { refreshTime, useAsyncData } from '#imports'
2
+
3
+ export function fetchGlobalDebug() {
4
+ return useAsyncData<{
5
+ nitroOrigin: string
6
+ runtimeConfig: any
7
+ }>(() => {
8
+ // @ts-expect-error untyped
9
+ return appFetch.value('/__schema-org__/debug.json')
10
+ }, {
11
+ watch: [refreshTime],
12
+ })
13
+ }
@@ -0,0 +1,46 @@
1
+ import { onDevtoolsClientConnected, useDevtoolsClient } from '@nuxt/devtools-kit/iframe-client'
2
+ import { ref, watch } from 'vue'
3
+ import { refreshTime, useDevtoolsConnection } from '#imports'
4
+
5
+ // Mirror the layer's workaround: initialize the devtools client ref before any
6
+ // onDevtoolsClientConnected call, or the devtools-kit alpha getter on
7
+ // window.__NUXT_DEVTOOLS__ reads an uninitialized clientRef and throws
8
+ // "Cannot read properties of undefined (reading 'value')", crashing the panel.
9
+ useDevtoolsClient()
10
+
11
+ // The host's rendered `<script data-nuxt-schema-org>` JSON-LD is the source of
12
+ // truth for the graph. Reading it straight from the host document is resilient
13
+ // across unhead majors: v3 dropped the v2 `resolveTags()` we used to call on the
14
+ // injected head instance, which silently left this panel empty.
15
+ export const schemaOrgGraph = ref<string>('loading')
16
+
17
+ let hostDocument: Document | undefined
18
+
19
+ function fetchGraph(): void {
20
+ if (!hostDocument)
21
+ return
22
+ const script = hostDocument.querySelector('script[data-nuxt-schema-org]')
23
+ // Fall back to an empty-object string (not '') so the layout's loading guard
24
+ // clears and the validator shows its "no nodes" state instead of spinning.
25
+ schemaOrgGraph.value = script?.textContent || '{}'
26
+ }
27
+
28
+ // The layer's useDevtoolsConnection only surfaces app provides, not the host DOM,
29
+ // so open our own devtools-kit client handle to reach the host document via the
30
+ // mounted Vue app's container element.
31
+ onDevtoolsClientConnected((client) => {
32
+ const nuxt: any = client.host?.nuxt
33
+ hostDocument = nuxt?.vueApp?._container?.ownerDocument
34
+ || nuxt?.vueApp?._instance?.vnode?.el?.ownerDocument
35
+ fetchGraph()
36
+ })
37
+
38
+ useDevtoolsConnection({
39
+ // Layer refreshes data on route change; re-read the graph once nav settles.
40
+ onRouteChange() {
41
+ setTimeout(fetchGraph, 100)
42
+ },
43
+ })
44
+
45
+ // The Refresh button bumps the shared clock; re-read the rendered graph with it.
46
+ watch(refreshTime, () => fetchGraph())