@wildo-ai/saas-website 1.1.5 → 1.1.6

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 (182) hide show
  1. package/dist/esm/astro/blog-post-bridge.d.ts +9 -0
  2. package/dist/esm/astro/blog-post-bridge.d.ts.map +1 -1
  3. package/dist/esm/astro/blog-post-bridge.js +10 -5
  4. package/dist/esm/astro/blog-post-bridge.js.map +1 -1
  5. package/dist/esm/astro/bridge-runtime.d.ts +25 -6
  6. package/dist/esm/astro/bridge-runtime.d.ts.map +1 -1
  7. package/dist/esm/astro/bridge-runtime.js +10 -6
  8. package/dist/esm/astro/bridge-runtime.js.map +1 -1
  9. package/dist/esm/astro/label-pack-loader.d.ts +4 -4
  10. package/dist/esm/astro/label-pack-loader.d.ts.map +1 -1
  11. package/dist/esm/astro/label-pack-loader.js +9 -4
  12. package/dist/esm/astro/label-pack-loader.js.map +1 -1
  13. package/dist/esm/astro/robots-renderer.d.ts +9 -8
  14. package/dist/esm/astro/robots-renderer.d.ts.map +1 -1
  15. package/dist/esm/astro/robots-renderer.js +15 -15
  16. package/dist/esm/astro/robots-renderer.js.map +1 -1
  17. package/dist/esm/astro/website-page-head.renderer.d.ts +1 -1
  18. package/dist/esm/astro/website-page-head.renderer.d.ts.map +1 -1
  19. package/dist/esm/astro/website-page-head.renderer.js +2 -1
  20. package/dist/esm/astro/website-page-head.renderer.js.map +1 -1
  21. package/dist/esm/astro/website-site-context.d.ts +5 -2
  22. package/dist/esm/astro/website-site-context.d.ts.map +1 -1
  23. package/dist/esm/astro/website-site-context.js.map +1 -1
  24. package/dist/esm/companion-exports.d.ts +8 -15
  25. package/dist/esm/companion-exports.d.ts.map +1 -1
  26. package/dist/esm/companion-exports.js +8 -15
  27. package/dist/esm/companion-exports.js.map +1 -1
  28. package/dist/esm/config/define-website-config.d.ts +3 -2
  29. package/dist/esm/config/define-website-config.d.ts.map +1 -1
  30. package/dist/esm/config/define-website-config.js +10 -10
  31. package/dist/esm/config/define-website-config.js.map +1 -1
  32. package/dist/esm/config/load-website-config.d.ts +6 -0
  33. package/dist/esm/config/load-website-config.d.ts.map +1 -1
  34. package/dist/esm/config/load-website-config.js +18 -9
  35. package/dist/esm/config/load-website-config.js.map +1 -1
  36. package/dist/esm/config/load-website-pricing-catalog.d.ts +13 -0
  37. package/dist/esm/config/load-website-pricing-catalog.d.ts.map +1 -0
  38. package/dist/esm/config/load-website-pricing-catalog.js +34 -0
  39. package/dist/esm/config/load-website-pricing-catalog.js.map +1 -0
  40. package/dist/esm/config/load-website-site-context.d.ts +53 -0
  41. package/dist/esm/config/load-website-site-context.d.ts.map +1 -0
  42. package/dist/esm/config/load-website-site-context.js +98 -0
  43. package/dist/esm/config/load-website-site-context.js.map +1 -0
  44. package/dist/esm/config-loader.d.ts +2 -0
  45. package/dist/esm/config-loader.d.ts.map +1 -1
  46. package/dist/esm/config-loader.js +2 -0
  47. package/dist/esm/config-loader.js.map +1 -1
  48. package/dist/esm/core/anonymous-session/InboundContactForm.d.ts +26 -6
  49. package/dist/esm/core/anonymous-session/InboundContactForm.d.ts.map +1 -1
  50. package/dist/esm/core/anonymous-session/InboundContactForm.js +51 -33
  51. package/dist/esm/core/anonymous-session/InboundContactForm.js.map +1 -1
  52. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.d.ts +11 -0
  53. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.d.ts.map +1 -1
  54. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.js +15 -4
  55. package/dist/esm/core/anonymous-session/inbound-contact-form.schema.js.map +1 -1
  56. package/dist/esm/core/anonymous-session/website-anonymous-session-client.d.ts +14 -2
  57. package/dist/esm/core/anonymous-session/website-anonymous-session-client.d.ts.map +1 -1
  58. package/dist/esm/core/anonymous-session/website-anonymous-session-client.js +34 -4
  59. package/dist/esm/core/anonymous-session/website-anonymous-session-client.js.map +1 -1
  60. package/dist/esm/core/anonymous-session/website-submission-challenge.d.ts +36 -0
  61. package/dist/esm/core/anonymous-session/website-submission-challenge.d.ts.map +1 -0
  62. package/dist/esm/core/anonymous-session/website-submission-challenge.js +69 -0
  63. package/dist/esm/core/anonymous-session/website-submission-challenge.js.map +1 -0
  64. package/dist/esm/core/consent/WebsiteConsentBanner.d.ts.map +1 -1
  65. package/dist/esm/core/consent/WebsiteConsentBanner.js +11 -10
  66. package/dist/esm/core/consent/WebsiteConsentBanner.js.map +1 -1
  67. package/dist/esm/core/contexts/WebsiteRuntimeContext.d.ts +25 -5
  68. package/dist/esm/core/contexts/WebsiteRuntimeContext.d.ts.map +1 -1
  69. package/dist/esm/core/contexts/WebsiteRuntimeContext.js.map +1 -1
  70. package/dist/esm/core/contexts/useWebsiteRuntime.d.ts +18 -0
  71. package/dist/esm/core/contexts/useWebsiteRuntime.d.ts.map +1 -1
  72. package/dist/esm/core/contexts/useWebsiteRuntime.js +28 -2
  73. package/dist/esm/core/contexts/useWebsiteRuntime.js.map +1 -1
  74. package/dist/esm/core/external-providers/WebsiteProviderComponent.d.ts +57 -0
  75. package/dist/esm/core/external-providers/WebsiteProviderComponent.d.ts.map +1 -0
  76. package/dist/esm/core/external-providers/WebsiteProviderComponent.js +56 -0
  77. package/dist/esm/core/external-providers/WebsiteProviderComponent.js.map +1 -0
  78. package/dist/esm/core/external-providers/provider-component-registry.website.d.ts +63 -0
  79. package/dist/esm/core/external-providers/provider-component-registry.website.d.ts.map +1 -0
  80. package/dist/esm/core/external-providers/provider-component-registry.website.js +68 -0
  81. package/dist/esm/core/external-providers/provider-component-registry.website.js.map +1 -0
  82. package/dist/esm/core/external-providers/useWebsiteProviderComponent.d.ts +36 -0
  83. package/dist/esm/core/external-providers/useWebsiteProviderComponent.d.ts.map +1 -0
  84. package/dist/esm/core/external-providers/useWebsiteProviderComponent.js +59 -0
  85. package/dist/esm/core/external-providers/useWebsiteProviderComponent.js.map +1 -0
  86. package/dist/esm/core/external-providers/useWebsiteProviderScripts.d.ts +15 -5
  87. package/dist/esm/core/external-providers/useWebsiteProviderScripts.d.ts.map +1 -1
  88. package/dist/esm/core/external-providers/useWebsiteProviderScripts.js +39 -24
  89. package/dist/esm/core/external-providers/useWebsiteProviderScripts.js.map +1 -1
  90. package/dist/esm/core/external-providers/website-provider-sdk-activations.d.ts +11 -0
  91. package/dist/esm/core/external-providers/website-provider-sdk-activations.d.ts.map +1 -0
  92. package/dist/esm/core/external-providers/website-provider-sdk-activations.js +14 -0
  93. package/dist/esm/core/external-providers/website-provider-sdk-activations.js.map +1 -0
  94. package/dist/esm/core/factories/define-website-section.d.ts +3 -3
  95. package/dist/esm/core/factories/define-website-section.js +3 -3
  96. package/dist/esm/core/factories/define-website-section.js.map +1 -1
  97. package/dist/esm/core/layouts/WebsitePageLayout.d.ts.map +1 -1
  98. package/dist/esm/core/layouts/WebsitePageLayout.js +10 -7
  99. package/dist/esm/core/layouts/WebsitePageLayout.js.map +1 -1
  100. package/dist/esm/index.d.ts +30 -65
  101. package/dist/esm/index.d.ts.map +1 -1
  102. package/dist/esm/index.js +30 -65
  103. package/dist/esm/index.js.map +1 -1
  104. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.d.ts +35 -6
  105. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.d.ts.map +1 -1
  106. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.js +39 -5
  107. package/dist/esm/schemas/design-tokens/website-design-tokens.shared.schemas.js.map +1 -1
  108. package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.d.ts +32 -0
  109. package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.d.ts.map +1 -0
  110. package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.js +36 -0
  111. package/dist/esm/schemas/label-keys/website-provider-component-label-keys.schemas.js.map +1 -0
  112. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.d.ts +6 -5
  113. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.d.ts.map +1 -1
  114. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.js +8 -7
  115. package/dist/esm/schemas/manifests/website-root-config.shared.schemas.js.map +1 -1
  116. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.d.ts +14 -7
  117. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.d.ts.map +1 -1
  118. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.js +14 -7
  119. package/dist/esm/schemas/sections/website-section-definition.shared.schemas.js.map +1 -1
  120. package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.d.ts +57 -0
  121. package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.d.ts.map +1 -0
  122. package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.js +76 -0
  123. package/dist/esm/schemas/structured-data/pricing-offer-structured-data.shared.js.map +1 -0
  124. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.d.ts +23 -0
  125. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.d.ts.map +1 -1
  126. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.js +20 -2
  127. package/dist/esm/schemas/structured-data/structured-data-reconciliation.shared.js.map +1 -1
  128. package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.d.ts +7 -5
  129. package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.d.ts.map +1 -1
  130. package/dist/esm/schemas/structured-data/website-structured-data.shared.schemas.js.map +1 -1
  131. package/dist/tsconfig.build.tsbuildinfo +1 -1
  132. package/package.json +5 -5
  133. package/src/__tests__/bundle-isolation.test.ts +19 -22
  134. package/src/astro/__tests__/blog-post-bridge.test.tsx +18 -2
  135. package/src/astro/__tests__/bridge-runtime.test.tsx +21 -3
  136. package/src/astro/__tests__/label-pack-loader.test.ts +7 -4
  137. package/src/astro/blog-post-bridge.tsx +19 -5
  138. package/src/astro/bridge-runtime.tsx +35 -11
  139. package/src/astro/label-pack-loader.ts +8 -4
  140. package/src/astro/robots-renderer.ts +15 -15
  141. package/src/astro/website-page-head.renderer.ts +2 -2
  142. package/src/astro/website-site-context.ts +5 -2
  143. package/src/companion-exports.ts +8 -15
  144. package/src/config/__tests__/website-build-origins.test.ts +52 -0
  145. package/src/config/define-website-config.ts +10 -10
  146. package/src/config/load-website-config.ts +25 -14
  147. package/src/config/load-website-pricing-catalog.ts +52 -0
  148. package/src/config/load-website-site-context.ts +145 -0
  149. package/src/config-loader.ts +2 -0
  150. package/src/core/__tests__/contexts.test.tsx +20 -1
  151. package/src/core/__tests__/website-consent.test.tsx +2 -1
  152. package/src/core/anonymous-session/InboundContactForm.tsx +100 -45
  153. package/src/core/anonymous-session/__tests__/InboundContactForm.labels.test.tsx +108 -0
  154. package/src/core/anonymous-session/__tests__/InboundContactForm.submission-challenge.test.tsx +139 -0
  155. package/src/core/anonymous-session/inbound-contact-form.schema.ts +16 -4
  156. package/src/core/anonymous-session/website-anonymous-session-client.ts +39 -4
  157. package/src/core/anonymous-session/website-submission-challenge.ts +99 -0
  158. package/src/core/consent/WebsiteConsentBanner.tsx +11 -10
  159. package/src/core/contexts/WebsiteRuntimeContext.tsx +25 -5
  160. package/src/core/contexts/useWebsiteRuntime.ts +33 -2
  161. package/src/core/external-providers/WebsiteProviderComponent.tsx +153 -0
  162. package/src/core/external-providers/__tests__/frontend-provider-registry.website.test.ts +4 -0
  163. package/src/core/external-providers/__tests__/website-provider-component.test.tsx +238 -0
  164. package/src/core/external-providers/__tests__/website-provider-sdks.test.tsx +72 -0
  165. package/src/core/external-providers/provider-component-registry.website.ts +115 -0
  166. package/src/core/external-providers/useWebsiteProviderComponent.ts +76 -0
  167. package/src/core/external-providers/useWebsiteProviderScripts.ts +56 -37
  168. package/src/core/external-providers/website-provider-sdk-activations.ts +23 -0
  169. package/src/core/factories/define-website-section.ts +3 -3
  170. package/src/core/layouts/WebsitePageLayout.tsx +11 -6
  171. package/src/index.ts +31 -65
  172. package/src/schemas/__tests__/design-token-css-property.test.ts +72 -0
  173. package/src/schemas/__tests__/pricing-offer-structured-data.test.ts +122 -0
  174. package/src/schemas/__tests__/structured-data-reconciliation.test.ts +35 -0
  175. package/src/schemas/design-tokens/website-design-tokens.shared.schemas.ts +45 -5
  176. package/src/schemas/label-keys/__tests__/scaffolded-consent-label-pack.parity.test.ts +12 -0
  177. package/src/schemas/label-keys/website-provider-component-label-keys.schemas.ts +40 -0
  178. package/src/schemas/manifests/website-root-config.shared.schemas.ts +10 -9
  179. package/src/schemas/sections/website-section-definition.shared.schemas.ts +14 -7
  180. package/src/schemas/structured-data/pricing-offer-structured-data.shared.ts +144 -0
  181. package/src/schemas/structured-data/structured-data-reconciliation.shared.ts +46 -1
  182. package/src/schemas/structured-data/website-structured-data.shared.schemas.ts +7 -5
@@ -1,5 +1,6 @@
1
1
  export function reconcileStructuredDataAgainstCatalog(options) {
2
2
  const findings = [];
3
+ const recommendations = [];
3
4
  const pages = [];
4
5
  const sectionsByRef = new Map(options.sections.map((section) => [section.sectionRef, section]));
5
6
  const pagePayloadsByPageRef = new Map();
@@ -138,7 +139,7 @@ export function reconcileStructuredDataAgainstCatalog(options) {
138
139
  }
139
140
  const routeFindingStart = findings.length;
140
141
  for (const payloadContext of payloadContexts) {
141
- validatePayloadAgainstCatalog(payloadContext, catalogByType, declaredEntityIds, findings);
142
+ validatePayloadAgainstCatalog(payloadContext, catalogByType, declaredEntityIds, findings, recommendations);
142
143
  }
143
144
  pages.push({
144
145
  pageRef: page.ref,
@@ -164,6 +165,7 @@ export function reconcileStructuredDataAgainstCatalog(options) {
164
165
  }
165
166
  return {
166
167
  findings,
168
+ recommendations,
167
169
  pages,
168
170
  };
169
171
  }
@@ -215,7 +217,7 @@ function collectNormalizedPayloadContexts(input) {
215
217
  });
216
218
  }
217
219
  }
218
- function validatePayloadAgainstCatalog(payloadContext, catalogByType, declaredEntityIds, findings) {
220
+ function validatePayloadAgainstCatalog(payloadContext, catalogByType, declaredEntityIds, findings, recommendations) {
219
221
  const { payload, pageRef, routePath, sectionRef } = payloadContext;
220
222
  const entityType = payload['@type'];
221
223
  const entityId = typeof payload['@id'] === 'string' ? payload['@id'] : undefined;
@@ -249,6 +251,22 @@ function validatePayloadAgainstCatalog(payloadContext, catalogByType, declaredEn
249
251
  });
250
252
  }
251
253
  }
254
+ if (catalogEntry.recommendOptionals === true) {
255
+ const missingOptionalFields = (catalogEntry.optionalFields ?? []).filter((field) => !hasPresentFieldValue(payload, field));
256
+ if (missingOptionalFields.length > 0) {
257
+ recommendations.push({
258
+ pageRef,
259
+ routePath,
260
+ sectionRef,
261
+ entityType,
262
+ entityId,
263
+ missingOptionalFields,
264
+ message: `Structured-data payload @type="${entityType}" emitted by section "${sectionRef}" on page "${pageRef}" ` +
265
+ `could carry ${missingOptionalFields.map((field) => `"${field}"`).join(', ')} — optional, and the catalog ` +
266
+ 'recommends them for richer search and answer-engine results.',
267
+ });
268
+ }
269
+ }
252
270
  for (const deprecatedField of catalogEntry.deprecatedFields ?? []) {
253
271
  if (!hasPresentFieldValue(payload, deprecatedField.field)) {
254
272
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"structured-data-reconciliation.shared.js","sourceRoot":"","sources":["../../../../../src/schemas/structured-data/structured-data-reconciliation.shared.ts"],"names":[],"mappings":"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","sourcesContent":["export interface StructuredDataDeprecatedField {\n field: string;\n replacedBy: string | null;\n deprecatedSince: string;\n}\n\nexport interface StructuredDataCatalogEntry {\n '@type': string;\n requiredFields: readonly string[];\n optionalFields?: readonly string[];\n deprecatedFields?: readonly StructuredDataDeprecatedField[];\n recommendOptionals?: boolean;\n}\n\nexport interface StructuredDataPayload {\n '@type': string;\n '@id'?: string;\n [key: string]: unknown;\n}\n\nexport interface StructuredDataSectionDefinitionLike {\n sectionRef: string;\n getStructuredData?: () => unknown;\n}\n\nexport interface StructuredDataPageManifestLike {\n ref: string;\n routePath: string;\n sectionRefs: readonly string[];\n}\n\nexport interface StructuredDataPagePayloadLike {\n pageRef: string;\n routePath?: string;\n sourceRef?: string;\n payloads: unknown;\n}\n\nexport type StructuredDataSpecViolationCode =\n | 'invalid-payload-shape'\n | 'missing-entity-type'\n | 'missing-required-field'\n | 'missing-section-definition'\n | 'orphan-page-payload';\n\nexport interface StructuredDataCatalogOverrideFinding {\n kind: 'catalog-override';\n entityType: string;\n count: number;\n message: string;\n}\n\nexport interface StructuredDataCatalogMissFinding {\n kind: 'catalog-miss';\n pageRef: string;\n routePath: string;\n sectionRef: string;\n entityType: string;\n entityId?: string;\n message: string;\n}\n\nexport interface StructuredDataSpecViolationFinding {\n kind: 'spec-violation';\n code: StructuredDataSpecViolationCode;\n pageRef: string;\n routePath: string;\n sectionRef: string;\n entityType?: string;\n entityId?: string;\n field?: string;\n message: string;\n}\n\nexport interface StructuredDataDeprecatedFieldFinding {\n kind: 'deprecated-field';\n pageRef: string;\n routePath: string;\n sectionRef: string;\n entityType: string;\n entityId?: string;\n field: string;\n replacedBy: string | null;\n deprecatedSince: string;\n message: string;\n}\n\nexport interface StructuredDataCrossEntityReferenceDriftFinding {\n kind: 'cross-entity-reference-drift';\n pageRef: string;\n routePath: string;\n sectionRef: string;\n entityType: string;\n entityId?: string;\n missingReferenceId: string;\n message: string;\n}\n\nexport type StructuredDataReconciliationFinding =\n | StructuredDataCatalogOverrideFinding\n | StructuredDataCatalogMissFinding\n | StructuredDataSpecViolationFinding\n | StructuredDataDeprecatedFieldFinding\n | StructuredDataCrossEntityReferenceDriftFinding;\n\nexport interface StructuredDataReconciliationPageResult {\n pageRef: string;\n routePath: string;\n payloadCount: number;\n findingCount: number;\n}\n\nexport interface StructuredDataReconciliationResult {\n findings: StructuredDataReconciliationFinding[];\n pages: StructuredDataReconciliationPageResult[];\n}\n\nexport interface ReconcileStructuredDataOptions {\n catalog: readonly StructuredDataCatalogEntry[];\n pages: readonly StructuredDataPageManifestLike[];\n sections: readonly StructuredDataSectionDefinitionLike[];\n pagePayloads?: readonly StructuredDataPagePayloadLike[];\n}\n\ninterface ReconciliationPayloadContext {\n pageRef: string;\n routePath: string;\n sectionRef: string;\n payload: StructuredDataPayload;\n}\n\nexport function reconcileStructuredDataAgainstCatalog(\n options: ReconcileStructuredDataOptions,\n): StructuredDataReconciliationResult {\n const findings: StructuredDataReconciliationFinding[] = [];\n const pages: StructuredDataReconciliationPageResult[] = [];\n const sectionsByRef = new Map(\n options.sections.map((section) => [section.sectionRef, section] as const),\n );\n const pagePayloadsByPageRef = new Map<string, StructuredDataPagePayloadLike[]>();\n for (const pagePayload of options.pagePayloads ?? []) {\n const pagePayloads = pagePayloadsByPageRef.get(pagePayload.pageRef) ?? [];\n pagePayloads.push(pagePayload);\n pagePayloadsByPageRef.set(pagePayload.pageRef, pagePayloads);\n }\n const catalogByType = new Map<string, StructuredDataCatalogEntry>();\n const catalogCounts = new Map<string, number>();\n\n for (const entry of options.catalog) {\n catalogByType.set(entry['@type'], entry);\n catalogCounts.set(entry['@type'], (catalogCounts.get(entry['@type']) ?? 0) + 1);\n }\n\n for (const [entityType, count] of catalogCounts.entries()) {\n if (count > 1) {\n findings.push({\n kind: 'catalog-override',\n entityType,\n count,\n message:\n `Merged catalog contains ${count} entries for @type=\"${entityType}\". ` +\n 'Replacement semantics are last-wins; duplicate array entries indicate an unresolved override.',\n });\n }\n }\n\n for (const page of options.pages) {\n const pageFindingStart = findings.length;\n const sectionPayloadContexts: ReconciliationPayloadContext[] = [];\n const isTemplatedRoute = page.routePath.includes('[');\n\n for (const sectionRef of page.sectionRefs) {\n const section = sectionsByRef.get(sectionRef);\n if (!section) {\n findings.push({\n kind: 'spec-violation',\n code: 'missing-section-definition',\n pageRef: page.ref,\n routePath: page.routePath,\n sectionRef,\n message:\n `Page \"${page.ref}\" references sectionRef \"${sectionRef}\" but no matching section ` +\n 'definition was supplied to the structured-data reconciliation harness.',\n });\n continue;\n }\n\n if (!section.getStructuredData) {\n continue;\n }\n\n const rawStructuredData = section.getStructuredData();\n const normalizedPayloads = normalizeStructuredDataReturn(rawStructuredData);\n\n if (normalizedPayloads === null) {\n findings.push({\n kind: 'spec-violation',\n code: 'invalid-payload-shape',\n pageRef: page.ref,\n routePath: page.routePath,\n sectionRef,\n message:\n `Section \"${sectionRef}\" on page \"${page.ref}\" returned an invalid ` +\n '`getStructuredData()` shape. Expected object, array, null, or undefined.',\n });\n continue;\n }\n\n for (const candidate of normalizedPayloads) {\n if (!isPlainObject(candidate)) {\n findings.push({\n kind: 'spec-violation',\n code: 'invalid-payload-shape',\n pageRef: page.ref,\n routePath: page.routePath,\n sectionRef,\n message:\n `Section \"${sectionRef}\" on page \"${page.ref}\" returned a non-object structured-data payload.`,\n });\n continue;\n }\n\n if (typeof candidate['@type'] !== 'string' || candidate['@type'].trim().length === 0) {\n findings.push({\n kind: 'spec-violation',\n code: 'missing-entity-type',\n pageRef: page.ref,\n routePath: page.routePath,\n sectionRef,\n entityId: typeof candidate['@id'] === 'string' ? candidate['@id'] : undefined,\n message:\n `Section \"${sectionRef}\" on page \"${page.ref}\" returned a structured-data payload ` +\n 'without a non-empty string `@type`.',\n });\n continue;\n }\n\n sectionPayloadContexts.push({\n pageRef: page.ref,\n routePath: page.routePath,\n sectionRef,\n payload: candidate as StructuredDataPayload,\n });\n }\n }\n\n const contextsByRoutePath = new Map<string, ReconciliationPayloadContext[]>();\n const collectionFindingCountByRoutePath = new Map<string, number>();\n const pagePayloadsForPage = pagePayloadsByPageRef.get(page.ref) ?? [];\n pagePayloadsByPageRef.delete(page.ref);\n const shouldEmitManifestResult =\n (sectionPayloadContexts.length > 0 && (!isTemplatedRoute || pagePayloadsForPage.length === 0))\n || findings.length > pageFindingStart\n || pagePayloadsForPage.length === 0;\n if (shouldEmitManifestResult) {\n const manifestPayloadContexts =\n isTemplatedRoute && pagePayloadsForPage.length > 0\n ? []\n : [...sectionPayloadContexts];\n contextsByRoutePath.set(page.routePath, manifestPayloadContexts);\n collectionFindingCountByRoutePath.set(page.routePath, findings.length - pageFindingStart);\n }\n\n for (const pagePayload of pagePayloadsForPage) {\n const routePath = pagePayload.routePath ?? page.routePath;\n const payloadContexts = contextsByRoutePath.get(routePath) ?? [];\n if (\n payloadContexts.length === 0\n && isTemplatedRoute\n && sectionPayloadContexts.length > 0\n ) {\n payloadContexts.push(\n ...sectionPayloadContexts.map((context) => ({\n ...context,\n routePath,\n })),\n );\n }\n contextsByRoutePath.set(routePath, payloadContexts);\n const collectionFindingStart = findings.length;\n collectNormalizedPayloadContexts({\n rawStructuredData: pagePayload.payloads,\n pageRef: page.ref,\n routePath,\n sectionRef: pagePayload.sourceRef ?? `page:${page.ref}`,\n findings,\n into: payloadContexts,\n });\n collectionFindingCountByRoutePath.set(\n routePath,\n (collectionFindingCountByRoutePath.get(routePath) ?? 0)\n + findings.length - collectionFindingStart,\n );\n }\n\n for (const [routePath, payloadContexts] of contextsByRoutePath.entries()) {\n const declaredEntityIds = new Set<string>();\n for (const payloadContext of payloadContexts) {\n collectDeclaredEntityIds(payloadContext.payload, declaredEntityIds);\n }\n\n const routeFindingStart = findings.length;\n for (const payloadContext of payloadContexts) {\n validatePayloadAgainstCatalog(payloadContext, catalogByType, declaredEntityIds, findings);\n }\n\n pages.push({\n pageRef: page.ref,\n routePath,\n payloadCount: payloadContexts.length,\n findingCount:\n (collectionFindingCountByRoutePath.get(routePath) ?? 0)\n + findings.length - routeFindingStart,\n });\n }\n }\n\n for (const [pageRef, pagePayloads] of pagePayloadsByPageRef.entries()) {\n for (const pagePayload of pagePayloads) {\n findings.push({\n kind: 'spec-violation',\n code: 'orphan-page-payload',\n pageRef,\n routePath: pagePayload.routePath ?? '',\n sectionRef: pagePayload.sourceRef ?? `page:${pageRef}`,\n message:\n `Structured-data page payload \"${pagePayload.sourceRef ?? `page:${pageRef}`}\" ` +\n `references pageRef \"${pageRef}\" but no matching page manifest was supplied.`,\n });\n }\n }\n\n return {\n findings,\n pages,\n };\n}\n\nfunction collectNormalizedPayloadContexts(input: {\n rawStructuredData: unknown;\n pageRef: string;\n routePath: string;\n sectionRef: string;\n findings: StructuredDataReconciliationFinding[];\n into: ReconciliationPayloadContext[];\n}): void {\n const {\n rawStructuredData,\n pageRef,\n routePath,\n sectionRef,\n findings,\n into,\n } = input;\n const normalizedPayloads = normalizeStructuredDataReturn(rawStructuredData);\n\n if (normalizedPayloads === null) {\n findings.push({\n kind: 'spec-violation',\n code: 'invalid-payload-shape',\n pageRef,\n routePath,\n sectionRef,\n message:\n `Structured-data source \"${sectionRef}\" on page \"${pageRef}\" returned an invalid ` +\n 'structured-data shape. Expected object, array, null, or undefined.',\n });\n return;\n }\n\n for (const candidate of normalizedPayloads) {\n if (!isPlainObject(candidate)) {\n findings.push({\n kind: 'spec-violation',\n code: 'invalid-payload-shape',\n pageRef,\n routePath,\n sectionRef,\n message:\n `Structured-data source \"${sectionRef}\" on page \"${pageRef}\" returned a non-object structured-data payload.`,\n });\n continue;\n }\n\n if (typeof candidate['@type'] !== 'string' || candidate['@type'].trim().length === 0) {\n findings.push({\n kind: 'spec-violation',\n code: 'missing-entity-type',\n pageRef,\n routePath,\n sectionRef,\n entityId: typeof candidate['@id'] === 'string' ? candidate['@id'] : undefined,\n message:\n `Structured-data source \"${sectionRef}\" on page \"${pageRef}\" returned a structured-data payload ` +\n 'without a non-empty string `@type`.',\n });\n continue;\n }\n\n into.push({\n pageRef,\n routePath,\n sectionRef,\n payload: candidate as StructuredDataPayload,\n });\n }\n}\n\nfunction validatePayloadAgainstCatalog(\n payloadContext: ReconciliationPayloadContext,\n catalogByType: ReadonlyMap<string, StructuredDataCatalogEntry>,\n declaredEntityIds: ReadonlySet<string>,\n findings: StructuredDataReconciliationFinding[],\n): void {\n const { payload, pageRef, routePath, sectionRef } = payloadContext;\n const entityType = payload['@type'];\n const entityId = typeof payload['@id'] === 'string' ? payload['@id'] : undefined;\n const catalogEntry = catalogByType.get(entityType);\n\n if (!catalogEntry) {\n findings.push({\n kind: 'catalog-miss',\n pageRef,\n routePath,\n sectionRef,\n entityType,\n entityId,\n message:\n `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" ` +\n `on page \"${pageRef}\" does not exist in the merged catalog.`,\n });\n return;\n }\n\n for (const requiredField of catalogEntry.requiredFields) {\n if (!hasPresentFieldValue(payload, requiredField)) {\n findings.push({\n kind: 'spec-violation',\n code: 'missing-required-field',\n pageRef,\n routePath,\n sectionRef,\n entityType,\n entityId,\n field: requiredField,\n message:\n `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" ` +\n `on page \"${pageRef}\" is missing required field \"${requiredField}\".`,\n });\n }\n }\n\n for (const deprecatedField of catalogEntry.deprecatedFields ?? []) {\n if (!hasPresentFieldValue(payload, deprecatedField.field)) {\n continue;\n }\n\n findings.push({\n kind: 'deprecated-field',\n pageRef,\n routePath,\n sectionRef,\n entityType,\n entityId,\n field: deprecatedField.field,\n replacedBy: deprecatedField.replacedBy,\n deprecatedSince: deprecatedField.deprecatedSince,\n message:\n deprecatedField.replacedBy === null\n ? `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" ` +\n `on page \"${pageRef}\" uses deprecated field \"${deprecatedField.field}\" ` +\n `(deprecated since ${deprecatedField.deprecatedSince}).`\n : `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" ` +\n `on page \"${pageRef}\" uses deprecated field \"${deprecatedField.field}\". ` +\n `Use \"${deprecatedField.replacedBy}\" instead ` +\n `(deprecated since ${deprecatedField.deprecatedSince}).`,\n });\n }\n\n const referencedIds = new Set<string>();\n collectReferencedEntityIds(payload, referencedIds, true);\n for (const referencedId of referencedIds) {\n if (declaredEntityIds.has(referencedId)) {\n continue;\n }\n\n findings.push({\n kind: 'cross-entity-reference-drift',\n pageRef,\n routePath,\n sectionRef,\n entityType,\n entityId,\n missingReferenceId: referencedId,\n message:\n `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" ` +\n `on page \"${pageRef}\" references @id \"${referencedId}\" but no emitted entity on the page defines it.`,\n });\n }\n}\n\nfunction normalizeStructuredDataReturn(value: unknown): unknown[] | null {\n if (value === null || value === undefined) {\n return [];\n }\n\n if (Array.isArray(value)) {\n return value.filter((item) => item !== null && item !== undefined);\n }\n\n if (isPlainObject(value)) {\n return [value];\n }\n\n return null;\n}\n\nfunction hasPresentFieldValue(payload: StructuredDataPayload, fieldName: string): boolean {\n if (!Object.prototype.hasOwnProperty.call(payload, fieldName)) {\n return false;\n }\n\n const value = payload[fieldName];\n return value !== null && value !== undefined;\n}\n\nfunction collectDeclaredEntityIds(value: unknown, into: Set<string>): void {\n if (Array.isArray(value)) {\n for (const item of value) {\n collectDeclaredEntityIds(item, into);\n }\n return;\n }\n\n if (!isPlainObject(value)) {\n return;\n }\n\n const entityId = typeof value['@id'] === 'string' ? value['@id'] : null;\n const entityType = typeof value['@type'] === 'string' ? value['@type'] : null;\n if (entityId && entityType) {\n into.add(entityId);\n }\n\n for (const child of Object.values(value)) {\n collectDeclaredEntityIds(child, into);\n }\n}\n\nfunction collectReferencedEntityIds(\n value: unknown,\n into: Set<string>,\n isRootPayload: boolean,\n): void {\n if (Array.isArray(value)) {\n for (const item of value) {\n collectReferencedEntityIds(item, into, false);\n }\n return;\n }\n\n if (!isPlainObject(value)) {\n return;\n }\n\n const entityId = typeof value['@id'] === 'string' ? value['@id'] : null;\n const entityType = typeof value['@type'] === 'string' ? value['@type'] : null;\n if (!isRootPayload && entityId && !entityType) {\n into.add(entityId);\n }\n\n for (const child of Object.values(value)) {\n collectReferencedEntityIds(child, into, false);\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
1
+ {"version":3,"file":"structured-data-reconciliation.shared.js","sourceRoot":"","sources":["../../../../../src/schemas/structured-data/structured-data-reconciliation.shared.ts"],"names":[],"mappings":"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","sourcesContent":["export interface StructuredDataDeprecatedField {\n field: string;\n replacedBy: string | null;\n deprecatedSince: string;\n}\n\nexport interface StructuredDataCatalogEntry {\n '@type': string;\n requiredFields: readonly string[];\n optionalFields?: readonly string[];\n deprecatedFields?: readonly StructuredDataDeprecatedField[];\n recommendOptionals?: boolean;\n}\n\nexport interface StructuredDataPayload {\n '@type': string;\n '@id'?: string;\n [key: string]: unknown;\n}\n\nexport interface StructuredDataSectionDefinitionLike {\n sectionRef: string;\n getStructuredData?: () => unknown;\n}\n\nexport interface StructuredDataPageManifestLike {\n ref: string;\n routePath: string;\n sectionRefs: readonly string[];\n}\n\nexport interface StructuredDataPagePayloadLike {\n pageRef: string;\n routePath?: string;\n sourceRef?: string;\n payloads: unknown;\n}\n\nexport type StructuredDataSpecViolationCode =\n | 'invalid-payload-shape'\n | 'missing-entity-type'\n | 'missing-required-field'\n | 'missing-section-definition'\n | 'orphan-page-payload';\n\nexport interface StructuredDataCatalogOverrideFinding {\n kind: 'catalog-override';\n entityType: string;\n count: number;\n message: string;\n}\n\nexport interface StructuredDataCatalogMissFinding {\n kind: 'catalog-miss';\n pageRef: string;\n routePath: string;\n sectionRef: string;\n entityType: string;\n entityId?: string;\n message: string;\n}\n\nexport interface StructuredDataSpecViolationFinding {\n kind: 'spec-violation';\n code: StructuredDataSpecViolationCode;\n pageRef: string;\n routePath: string;\n sectionRef: string;\n entityType?: string;\n entityId?: string;\n field?: string;\n message: string;\n}\n\nexport interface StructuredDataDeprecatedFieldFinding {\n kind: 'deprecated-field';\n pageRef: string;\n routePath: string;\n sectionRef: string;\n entityType: string;\n entityId?: string;\n field: string;\n replacedBy: string | null;\n deprecatedSince: string;\n message: string;\n}\n\nexport interface StructuredDataCrossEntityReferenceDriftFinding {\n kind: 'cross-entity-reference-drift';\n pageRef: string;\n routePath: string;\n sectionRef: string;\n entityType: string;\n entityId?: string;\n missingReferenceId: string;\n message: string;\n}\n\nexport type StructuredDataReconciliationFinding =\n | StructuredDataCatalogOverrideFinding\n | StructuredDataCatalogMissFinding\n | StructuredDataSpecViolationFinding\n | StructuredDataDeprecatedFieldFinding\n | StructuredDataCrossEntityReferenceDriftFinding;\n\n/**\n * An OPTIONAL field a payload leaves out, reported because its catalog entry opted in with\n * `recommendOptionals: true` — the entry's statement that for this type the optional fields are\n * where the richer search and answer-engine results come from.\n *\n * Deliberately NOT a finding. A finding says the payload is wrong (a missing required field, an\n * unknown type, a deprecated field) and `--strict` escalates every finding to a failure. A payload\n * without its optional fields is valid; reporting it through the same channel would fail strict CI for\n * following the vocabulary. So recommendations travel beside the findings, are shown as information,\n * and never change an audit's outcome.\n */\nexport interface StructuredDataOptionalFieldRecommendation {\n pageRef: string;\n routePath: string;\n sectionRef: string;\n entityType: string;\n entityId?: string;\n /** The entry's optional fields this payload does not carry, in catalog order. */\n missingOptionalFields: readonly string[];\n message: string;\n}\n\nexport interface StructuredDataReconciliationPageResult {\n pageRef: string;\n routePath: string;\n payloadCount: number;\n findingCount: number;\n}\n\nexport interface StructuredDataReconciliationResult {\n findings: StructuredDataReconciliationFinding[];\n /** Optional-field recommendations from entries that opted in — information, never a finding. */\n recommendations: StructuredDataOptionalFieldRecommendation[];\n pages: StructuredDataReconciliationPageResult[];\n}\n\nexport interface ReconcileStructuredDataOptions {\n catalog: readonly StructuredDataCatalogEntry[];\n pages: readonly StructuredDataPageManifestLike[];\n sections: readonly StructuredDataSectionDefinitionLike[];\n pagePayloads?: readonly StructuredDataPagePayloadLike[];\n}\n\ninterface ReconciliationPayloadContext {\n pageRef: string;\n routePath: string;\n sectionRef: string;\n payload: StructuredDataPayload;\n}\n\nexport function reconcileStructuredDataAgainstCatalog(\n options: ReconcileStructuredDataOptions,\n): StructuredDataReconciliationResult {\n const findings: StructuredDataReconciliationFinding[] = [];\n const recommendations: StructuredDataOptionalFieldRecommendation[] = [];\n const pages: StructuredDataReconciliationPageResult[] = [];\n const sectionsByRef = new Map(\n options.sections.map((section) => [section.sectionRef, section] as const),\n );\n const pagePayloadsByPageRef = new Map<string, StructuredDataPagePayloadLike[]>();\n for (const pagePayload of options.pagePayloads ?? []) {\n const pagePayloads = pagePayloadsByPageRef.get(pagePayload.pageRef) ?? [];\n pagePayloads.push(pagePayload);\n pagePayloadsByPageRef.set(pagePayload.pageRef, pagePayloads);\n }\n const catalogByType = new Map<string, StructuredDataCatalogEntry>();\n const catalogCounts = new Map<string, number>();\n\n for (const entry of options.catalog) {\n catalogByType.set(entry['@type'], entry);\n catalogCounts.set(entry['@type'], (catalogCounts.get(entry['@type']) ?? 0) + 1);\n }\n\n for (const [entityType, count] of catalogCounts.entries()) {\n if (count > 1) {\n findings.push({\n kind: 'catalog-override',\n entityType,\n count,\n message:\n `Merged catalog contains ${count} entries for @type=\"${entityType}\". ` +\n 'Replacement semantics are last-wins; duplicate array entries indicate an unresolved override.',\n });\n }\n }\n\n for (const page of options.pages) {\n const pageFindingStart = findings.length;\n const sectionPayloadContexts: ReconciliationPayloadContext[] = [];\n const isTemplatedRoute = page.routePath.includes('[');\n\n for (const sectionRef of page.sectionRefs) {\n const section = sectionsByRef.get(sectionRef);\n if (!section) {\n findings.push({\n kind: 'spec-violation',\n code: 'missing-section-definition',\n pageRef: page.ref,\n routePath: page.routePath,\n sectionRef,\n message:\n `Page \"${page.ref}\" references sectionRef \"${sectionRef}\" but no matching section ` +\n 'definition was supplied to the structured-data reconciliation harness.',\n });\n continue;\n }\n\n if (!section.getStructuredData) {\n continue;\n }\n\n const rawStructuredData = section.getStructuredData();\n const normalizedPayloads = normalizeStructuredDataReturn(rawStructuredData);\n\n if (normalizedPayloads === null) {\n findings.push({\n kind: 'spec-violation',\n code: 'invalid-payload-shape',\n pageRef: page.ref,\n routePath: page.routePath,\n sectionRef,\n message:\n `Section \"${sectionRef}\" on page \"${page.ref}\" returned an invalid ` +\n '`getStructuredData()` shape. Expected object, array, null, or undefined.',\n });\n continue;\n }\n\n for (const candidate of normalizedPayloads) {\n if (!isPlainObject(candidate)) {\n findings.push({\n kind: 'spec-violation',\n code: 'invalid-payload-shape',\n pageRef: page.ref,\n routePath: page.routePath,\n sectionRef,\n message:\n `Section \"${sectionRef}\" on page \"${page.ref}\" returned a non-object structured-data payload.`,\n });\n continue;\n }\n\n if (typeof candidate['@type'] !== 'string' || candidate['@type'].trim().length === 0) {\n findings.push({\n kind: 'spec-violation',\n code: 'missing-entity-type',\n pageRef: page.ref,\n routePath: page.routePath,\n sectionRef,\n entityId: typeof candidate['@id'] === 'string' ? candidate['@id'] : undefined,\n message:\n `Section \"${sectionRef}\" on page \"${page.ref}\" returned a structured-data payload ` +\n 'without a non-empty string `@type`.',\n });\n continue;\n }\n\n sectionPayloadContexts.push({\n pageRef: page.ref,\n routePath: page.routePath,\n sectionRef,\n payload: candidate as StructuredDataPayload,\n });\n }\n }\n\n const contextsByRoutePath = new Map<string, ReconciliationPayloadContext[]>();\n const collectionFindingCountByRoutePath = new Map<string, number>();\n const pagePayloadsForPage = pagePayloadsByPageRef.get(page.ref) ?? [];\n pagePayloadsByPageRef.delete(page.ref);\n const shouldEmitManifestResult =\n (sectionPayloadContexts.length > 0 && (!isTemplatedRoute || pagePayloadsForPage.length === 0))\n || findings.length > pageFindingStart\n || pagePayloadsForPage.length === 0;\n if (shouldEmitManifestResult) {\n const manifestPayloadContexts =\n isTemplatedRoute && pagePayloadsForPage.length > 0\n ? []\n : [...sectionPayloadContexts];\n contextsByRoutePath.set(page.routePath, manifestPayloadContexts);\n collectionFindingCountByRoutePath.set(page.routePath, findings.length - pageFindingStart);\n }\n\n for (const pagePayload of pagePayloadsForPage) {\n const routePath = pagePayload.routePath ?? page.routePath;\n const payloadContexts = contextsByRoutePath.get(routePath) ?? [];\n if (\n payloadContexts.length === 0\n && isTemplatedRoute\n && sectionPayloadContexts.length > 0\n ) {\n payloadContexts.push(\n ...sectionPayloadContexts.map((context) => ({\n ...context,\n routePath,\n })),\n );\n }\n contextsByRoutePath.set(routePath, payloadContexts);\n const collectionFindingStart = findings.length;\n collectNormalizedPayloadContexts({\n rawStructuredData: pagePayload.payloads,\n pageRef: page.ref,\n routePath,\n sectionRef: pagePayload.sourceRef ?? `page:${page.ref}`,\n findings,\n into: payloadContexts,\n });\n collectionFindingCountByRoutePath.set(\n routePath,\n (collectionFindingCountByRoutePath.get(routePath) ?? 0)\n + findings.length - collectionFindingStart,\n );\n }\n\n for (const [routePath, payloadContexts] of contextsByRoutePath.entries()) {\n const declaredEntityIds = new Set<string>();\n for (const payloadContext of payloadContexts) {\n collectDeclaredEntityIds(payloadContext.payload, declaredEntityIds);\n }\n\n const routeFindingStart = findings.length;\n for (const payloadContext of payloadContexts) {\n validatePayloadAgainstCatalog(payloadContext, catalogByType, declaredEntityIds, findings, recommendations);\n }\n\n pages.push({\n pageRef: page.ref,\n routePath,\n payloadCount: payloadContexts.length,\n findingCount:\n (collectionFindingCountByRoutePath.get(routePath) ?? 0)\n + findings.length - routeFindingStart,\n });\n }\n }\n\n for (const [pageRef, pagePayloads] of pagePayloadsByPageRef.entries()) {\n for (const pagePayload of pagePayloads) {\n findings.push({\n kind: 'spec-violation',\n code: 'orphan-page-payload',\n pageRef,\n routePath: pagePayload.routePath ?? '',\n sectionRef: pagePayload.sourceRef ?? `page:${pageRef}`,\n message:\n `Structured-data page payload \"${pagePayload.sourceRef ?? `page:${pageRef}`}\" ` +\n `references pageRef \"${pageRef}\" but no matching page manifest was supplied.`,\n });\n }\n }\n\n return {\n findings,\n recommendations,\n pages,\n };\n}\n\nfunction collectNormalizedPayloadContexts(input: {\n rawStructuredData: unknown;\n pageRef: string;\n routePath: string;\n sectionRef: string;\n findings: StructuredDataReconciliationFinding[];\n into: ReconciliationPayloadContext[];\n}): void {\n const {\n rawStructuredData,\n pageRef,\n routePath,\n sectionRef,\n findings,\n into,\n } = input;\n const normalizedPayloads = normalizeStructuredDataReturn(rawStructuredData);\n\n if (normalizedPayloads === null) {\n findings.push({\n kind: 'spec-violation',\n code: 'invalid-payload-shape',\n pageRef,\n routePath,\n sectionRef,\n message:\n `Structured-data source \"${sectionRef}\" on page \"${pageRef}\" returned an invalid ` +\n 'structured-data shape. Expected object, array, null, or undefined.',\n });\n return;\n }\n\n for (const candidate of normalizedPayloads) {\n if (!isPlainObject(candidate)) {\n findings.push({\n kind: 'spec-violation',\n code: 'invalid-payload-shape',\n pageRef,\n routePath,\n sectionRef,\n message:\n `Structured-data source \"${sectionRef}\" on page \"${pageRef}\" returned a non-object structured-data payload.`,\n });\n continue;\n }\n\n if (typeof candidate['@type'] !== 'string' || candidate['@type'].trim().length === 0) {\n findings.push({\n kind: 'spec-violation',\n code: 'missing-entity-type',\n pageRef,\n routePath,\n sectionRef,\n entityId: typeof candidate['@id'] === 'string' ? candidate['@id'] : undefined,\n message:\n `Structured-data source \"${sectionRef}\" on page \"${pageRef}\" returned a structured-data payload ` +\n 'without a non-empty string `@type`.',\n });\n continue;\n }\n\n into.push({\n pageRef,\n routePath,\n sectionRef,\n payload: candidate as StructuredDataPayload,\n });\n }\n}\n\nfunction validatePayloadAgainstCatalog(\n payloadContext: ReconciliationPayloadContext,\n catalogByType: ReadonlyMap<string, StructuredDataCatalogEntry>,\n declaredEntityIds: ReadonlySet<string>,\n findings: StructuredDataReconciliationFinding[],\n recommendations: StructuredDataOptionalFieldRecommendation[],\n): void {\n const { payload, pageRef, routePath, sectionRef } = payloadContext;\n const entityType = payload['@type'];\n const entityId = typeof payload['@id'] === 'string' ? payload['@id'] : undefined;\n const catalogEntry = catalogByType.get(entityType);\n\n if (!catalogEntry) {\n findings.push({\n kind: 'catalog-miss',\n pageRef,\n routePath,\n sectionRef,\n entityType,\n entityId,\n message:\n `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" ` +\n `on page \"${pageRef}\" does not exist in the merged catalog.`,\n });\n return;\n }\n\n for (const requiredField of catalogEntry.requiredFields) {\n if (!hasPresentFieldValue(payload, requiredField)) {\n findings.push({\n kind: 'spec-violation',\n code: 'missing-required-field',\n pageRef,\n routePath,\n sectionRef,\n entityType,\n entityId,\n field: requiredField,\n message:\n `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" ` +\n `on page \"${pageRef}\" is missing required field \"${requiredField}\".`,\n });\n }\n }\n\n if (catalogEntry.recommendOptionals === true) {\n const missingOptionalFields = (catalogEntry.optionalFields ?? []).filter((field) => !hasPresentFieldValue(payload, field));\n if (missingOptionalFields.length > 0) {\n recommendations.push({\n pageRef,\n routePath,\n sectionRef,\n entityType,\n entityId,\n missingOptionalFields,\n message:\n `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" on page \"${pageRef}\" ` +\n `could carry ${missingOptionalFields.map((field) => `\"${field}\"`).join(', ')} — optional, and the catalog ` +\n 'recommends them for richer search and answer-engine results.',\n });\n }\n }\n\n for (const deprecatedField of catalogEntry.deprecatedFields ?? []) {\n if (!hasPresentFieldValue(payload, deprecatedField.field)) {\n continue;\n }\n\n findings.push({\n kind: 'deprecated-field',\n pageRef,\n routePath,\n sectionRef,\n entityType,\n entityId,\n field: deprecatedField.field,\n replacedBy: deprecatedField.replacedBy,\n deprecatedSince: deprecatedField.deprecatedSince,\n message:\n deprecatedField.replacedBy === null\n ? `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" ` +\n `on page \"${pageRef}\" uses deprecated field \"${deprecatedField.field}\" ` +\n `(deprecated since ${deprecatedField.deprecatedSince}).`\n : `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" ` +\n `on page \"${pageRef}\" uses deprecated field \"${deprecatedField.field}\". ` +\n `Use \"${deprecatedField.replacedBy}\" instead ` +\n `(deprecated since ${deprecatedField.deprecatedSince}).`,\n });\n }\n\n const referencedIds = new Set<string>();\n collectReferencedEntityIds(payload, referencedIds, true);\n for (const referencedId of referencedIds) {\n if (declaredEntityIds.has(referencedId)) {\n continue;\n }\n\n findings.push({\n kind: 'cross-entity-reference-drift',\n pageRef,\n routePath,\n sectionRef,\n entityType,\n entityId,\n missingReferenceId: referencedId,\n message:\n `Structured-data payload @type=\"${entityType}\" emitted by section \"${sectionRef}\" ` +\n `on page \"${pageRef}\" references @id \"${referencedId}\" but no emitted entity on the page defines it.`,\n });\n }\n}\n\nfunction normalizeStructuredDataReturn(value: unknown): unknown[] | null {\n if (value === null || value === undefined) {\n return [];\n }\n\n if (Array.isArray(value)) {\n return value.filter((item) => item !== null && item !== undefined);\n }\n\n if (isPlainObject(value)) {\n return [value];\n }\n\n return null;\n}\n\nfunction hasPresentFieldValue(payload: StructuredDataPayload, fieldName: string): boolean {\n if (!Object.prototype.hasOwnProperty.call(payload, fieldName)) {\n return false;\n }\n\n const value = payload[fieldName];\n return value !== null && value !== undefined;\n}\n\nfunction collectDeclaredEntityIds(value: unknown, into: Set<string>): void {\n if (Array.isArray(value)) {\n for (const item of value) {\n collectDeclaredEntityIds(item, into);\n }\n return;\n }\n\n if (!isPlainObject(value)) {\n return;\n }\n\n const entityId = typeof value['@id'] === 'string' ? value['@id'] : null;\n const entityType = typeof value['@type'] === 'string' ? value['@type'] : null;\n if (entityId && entityType) {\n into.add(entityId);\n }\n\n for (const child of Object.values(value)) {\n collectDeclaredEntityIds(child, into);\n }\n}\n\nfunction collectReferencedEntityIds(\n value: unknown,\n into: Set<string>,\n isRootPayload: boolean,\n): void {\n if (Array.isArray(value)) {\n for (const item of value) {\n collectReferencedEntityIds(item, into, false);\n }\n return;\n }\n\n if (!isPlainObject(value)) {\n return;\n }\n\n const entityId = typeof value['@id'] === 'string' ? value['@id'] : null;\n const entityType = typeof value['@type'] === 'string' ? value['@type'] : null;\n if (!isRootPayload && entityId && !entityType) {\n into.add(entityId);\n }\n\n for (const child of Object.values(value)) {\n collectReferencedEntityIds(child, into, false);\n }\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n"]}
@@ -16,11 +16,13 @@
16
16
  *
17
17
  * - `@type` REQUIRED — the Schema.org entity kind (`'Article'`,
18
18
  * `'BlogPosting'`, `'FAQPage'`, …). Typed as a free-form `string`
19
- * here (not a closed enum) so app-side catalog extensions
20
- * (e.g. `'SoftwareApplication'`, custom Schema.org-extension
21
- * `@type`s) are emittable without a saas-website release. The
22
- * companion's catalog reconciliation surface validates the
23
- * `@type` value against the merged engine + app catalog.
19
+ * here (not a closed enum) because this package ships to the browser
20
+ * and must not carry the catalog: the renderer emits whatever type a
21
+ * section returns. What VALIDATES the type is the Schema.org catalog,
22
+ * through `wildo website audit` and the companion's reconciliation —
23
+ * and that catalog is a closed enum an application can override but
24
+ * not extend, so a type outside it reports `catalog-miss` until the
25
+ * framework adds it.
24
26
  * - `@id?` OPTIONAL — a stable URI identifying the entity. Used for
25
27
  * cross-referencing on the same page (e.g. `Article.publisher`
26
28
  * referencing the page-level `Organization` via `@id`). The
@@ -1 +1 @@
1
- {"version":3,"file":"website-structured-data.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/schemas/structured-data/website-structured-data.shared.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,2BAA2B,GACnC,4BAA4B,GAC5B,SAAS,4BAA4B,EAAE,GACvC,IAAI,GACJ,SAAS,CAAC;AACd,wEAAwE"}
1
+ {"version":3,"file":"website-structured-data.shared.schemas.d.ts","sourceRoot":"","sources":["../../../../../src/schemas/structured-data/website-structured-data.shared.schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,2BAA2B,GACnC,4BAA4B,GAC5B,SAAS,4BAA4B,EAAE,GACvC,IAAI,GACJ,SAAS,CAAC;AACd,wEAAwE"}
@@ -1 +1 @@
1
- {"version":3,"file":"website-structured-data.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/schemas/structured-data/website-structured-data.shared.schemas.ts"],"names":[],"mappings":"AA6DA,wEAAwE","sourcesContent":["/**\n * @wildo_source:part:start saas.website.structured-data.payload-shape facet:layer:shared facet:family:website\n *\n * `WebsiteStructuredDataPayload` — the runtime JSON-LD object shape returned\n * by a section's `getStructuredData()` and serialized into one\n * `<script type=\"application/ld+json\">` block per payload.\n *\n * **Layering note** — the payload type is defined HERE (in the\n * website runtime) rather than imported from the specification package because\n * runtime rendering must remain independent from companion semantics. The\n * application's Schema.org catalog describes the same vocabulary (per-`@type`\n * required / optional / deprecated fields); the two contracts are structurally\n * compatible by design but independently owned.\n *\n * **Authoring contract**:\n *\n * - `@type` REQUIRED — the Schema.org entity kind (`'Article'`,\n * `'BlogPosting'`, `'FAQPage'`, …). Typed as a free-form `string`\n * here (not a closed enum) so app-side catalog extensions\n * (e.g. `'SoftwareApplication'`, custom Schema.org-extension\n * `@type`s) are emittable without a saas-website release. The\n * companion's catalog reconciliation surface validates the\n * `@type` value against the merged engine + app catalog.\n * - `@id?` OPTIONAL — a stable URI identifying the entity. Used for\n * cross-referencing on the same page (e.g. `Article.publisher`\n * referencing the page-level `Organization` via `@id`). The\n * renderer uses `@id` for deduplication: two payloads with the\n * same `@id` collapse into one emitted block (last-wins).\n * - `@context?` OPTIONAL — the JSON-LD vocabulary URL. The renderer\n * auto-injects `'https://schema.org'` when omitted; the field is\n * exposed so consumers CAN override (Schema.org payload extended\n * with a custom vocabulary).\n * - All other fields are pass-through `unknown` — the catalog\n * describes the FIELD NAMES per `@type`; the per-field SHAPE\n * (e.g. `Article.author` is a `Person | Organization`) is locked\n * at the section's payload-builder TS-side.\n */\nexport interface WebsiteStructuredDataPayload {\n '@type': string;\n '@id'?: string;\n '@context'?: string | Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Convenience union for `getStructuredData()` return types.\n *\n * A section may emit:\n * - a single payload (most common — `FAQPage` for an FAQ section);\n * - a fixed-length tuple of payloads (e.g. pricing emits `Product +\n * AggregateOffer` together);\n * - `null` / `undefined` when the section has no contribution for\n * the current state (e.g. an empty FAQ list);\n * - an empty array (semantically equivalent to `null`; the renderer\n * short-circuits both).\n */\nexport type WebsiteStructuredDataReturn =\n | WebsiteStructuredDataPayload\n | readonly WebsiteStructuredDataPayload[]\n | null\n | undefined;\n/** @wildo_source:part:end saas.website.structured-data.payload-shape */\n"]}
1
+ {"version":3,"file":"website-structured-data.shared.schemas.js","sourceRoot":"","sources":["../../../../../src/schemas/structured-data/website-structured-data.shared.schemas.ts"],"names":[],"mappings":"AA+DA,wEAAwE","sourcesContent":["/**\n * @wildo_source:part:start saas.website.structured-data.payload-shape facet:layer:shared facet:family:website\n *\n * `WebsiteStructuredDataPayload` — the runtime JSON-LD object shape returned\n * by a section's `getStructuredData()` and serialized into one\n * `<script type=\"application/ld+json\">` block per payload.\n *\n * **Layering note** — the payload type is defined HERE (in the\n * website runtime) rather than imported from the specification package because\n * runtime rendering must remain independent from companion semantics. The\n * application's Schema.org catalog describes the same vocabulary (per-`@type`\n * required / optional / deprecated fields); the two contracts are structurally\n * compatible by design but independently owned.\n *\n * **Authoring contract**:\n *\n * - `@type` REQUIRED — the Schema.org entity kind (`'Article'`,\n * `'BlogPosting'`, `'FAQPage'`, …). Typed as a free-form `string`\n * here (not a closed enum) because this package ships to the browser\n * and must not carry the catalog: the renderer emits whatever type a\n * section returns. What VALIDATES the type is the Schema.org catalog,\n * through `wildo website audit` and the companion's reconciliation —\n * and that catalog is a closed enum an application can override but\n * not extend, so a type outside it reports `catalog-miss` until the\n * framework adds it.\n * - `@id?` OPTIONAL — a stable URI identifying the entity. Used for\n * cross-referencing on the same page (e.g. `Article.publisher`\n * referencing the page-level `Organization` via `@id`). The\n * renderer uses `@id` for deduplication: two payloads with the\n * same `@id` collapse into one emitted block (last-wins).\n * - `@context?` OPTIONAL — the JSON-LD vocabulary URL. The renderer\n * auto-injects `'https://schema.org'` when omitted; the field is\n * exposed so consumers CAN override (Schema.org payload extended\n * with a custom vocabulary).\n * - All other fields are pass-through `unknown` — the catalog\n * describes the FIELD NAMES per `@type`; the per-field SHAPE\n * (e.g. `Article.author` is a `Person | Organization`) is locked\n * at the section's payload-builder TS-side.\n */\nexport interface WebsiteStructuredDataPayload {\n '@type': string;\n '@id'?: string;\n '@context'?: string | Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Convenience union for `getStructuredData()` return types.\n *\n * A section may emit:\n * - a single payload (most common — `FAQPage` for an FAQ section);\n * - a fixed-length tuple of payloads (e.g. pricing emits `Product +\n * AggregateOffer` together);\n * - `null` / `undefined` when the section has no contribution for\n * the current state (e.g. an empty FAQ list);\n * - an empty array (semantically equivalent to `null`; the renderer\n * short-circuits both).\n */\nexport type WebsiteStructuredDataReturn =\n | WebsiteStructuredDataPayload\n | readonly WebsiteStructuredDataPayload[]\n | null\n | undefined;\n/** @wildo_source:part:end saas.website.structured-data.payload-shape */\n"]}