@wix/web5-core 1.63.21 → 1.63.23

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 (47) hide show
  1. package/dist/cjs/components/ui/OptimizedImage.js +12 -30
  2. package/dist/cjs/components/ui/OptimizedImage.js.map +1 -1
  3. package/dist/cjs/entity/entityHref.js +53 -0
  4. package/dist/cjs/entity/entityHref.js.map +1 -0
  5. package/dist/cjs/entity/entityPayload.js +58 -4
  6. package/dist/cjs/entity/entityPayload.js.map +1 -1
  7. package/dist/cjs/entity/index.js +5 -2
  8. package/dist/cjs/entity/index.js.map +1 -1
  9. package/dist/cjs/index.js +5 -16
  10. package/dist/cjs/index.js.map +1 -1
  11. package/dist/cjs/types/dependencies.js.map +1 -1
  12. package/dist/esm/components/ui/OptimizedImage.js +3 -21
  13. package/dist/esm/components/ui/OptimizedImage.js.map +1 -1
  14. package/dist/esm/entity/entityHref.js +49 -0
  15. package/dist/esm/entity/entityHref.js.map +1 -0
  16. package/dist/esm/entity/entityPayload.js +57 -4
  17. package/dist/esm/entity/entityPayload.js.map +1 -1
  18. package/dist/esm/entity/index.js +2 -1
  19. package/dist/esm/entity/index.js.map +1 -1
  20. package/dist/esm/index.js +1 -9
  21. package/dist/esm/index.js.map +1 -1
  22. package/dist/esm/types/dependencies.js.map +1 -1
  23. package/dist/types/components/ui/OptimizedImage.d.ts +0 -12
  24. package/dist/types/components/ui/OptimizedImage.d.ts.map +1 -1
  25. package/dist/types/entity/entityHref.d.ts +39 -0
  26. package/dist/types/entity/entityHref.d.ts.map +1 -0
  27. package/dist/types/entity/entityPayload.d.ts +34 -0
  28. package/dist/types/entity/entityPayload.d.ts.map +1 -1
  29. package/dist/types/entity/index.d.ts +2 -1
  30. package/dist/types/entity/index.d.ts.map +1 -1
  31. package/dist/types/index.d.ts +1 -4
  32. package/dist/types/index.d.ts.map +1 -1
  33. package/dist/types/types/dependencies.d.ts +0 -15
  34. package/dist/types/types/dependencies.d.ts.map +1 -1
  35. package/package.json +2 -2
  36. package/dist/cjs/context/ImageSetContext.js +0 -234
  37. package/dist/cjs/context/ImageSetContext.js.map +0 -1
  38. package/dist/cjs/image/imageSetTypes.js +0 -108
  39. package/dist/cjs/image/imageSetTypes.js.map +0 -1
  40. package/dist/esm/context/ImageSetContext.js +0 -221
  41. package/dist/esm/context/ImageSetContext.js.map +0 -1
  42. package/dist/esm/image/imageSetTypes.js +0 -100
  43. package/dist/esm/image/imageSetTypes.js.map +0 -1
  44. package/dist/types/context/ImageSetContext.d.ts +0 -74
  45. package/dist/types/context/ImageSetContext.d.ts.map +0 -1
  46. package/dist/types/image/imageSetTypes.d.ts +0 -185
  47. package/dist/types/image/imageSetTypes.d.ts.map +0 -1
@@ -8,12 +8,10 @@ var _imageBackdrop = require("../../utils/imageBackdrop");
8
8
  var _linkTypes = require("../../types/link-types");
9
9
  var _ComponentDependenciesContext = require("../../context/ComponentDependenciesContext");
10
10
  var _useResolvedImageSources = require("../../hooks/useResolvedImageSources");
11
- var _imageSetTypes = require("../../image/imageSetTypes");
12
11
  var _jsxFileName = "/home/builduser/work/c2b6ca0b3fa984ee/packages/web5-core/dist/cjs/components/ui/OptimizedImage.tsx";
13
12
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
13
  const lowResFallbackCache = new Map();
15
14
  const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(props => {
16
- var _slot$visualMetadata, _slot$crop;
17
15
  const {
18
16
  alt,
19
17
  className = '',
@@ -31,7 +29,6 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
31
29
  disableResize = false,
32
30
  imageMode = 'fit',
33
31
  adaptiveBackdrop = false,
34
- slot,
35
32
  fallbackOnLowRes,
36
33
  lowResThreshold = 550
37
34
  } = props;
@@ -130,21 +127,6 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
130
127
  const effectiveObjectFit = adaptiveActive ? backdrop != null && backdrop.hasBackdrop ? 'contain' : 'cover' : objectFit;
131
128
  const effectiveImageMode = adaptiveActive ? backdrop != null && backdrop.hasBackdrop ? 'fit' : 'fill' : imageMode;
132
129
  const adaptiveBackgroundColor = adaptiveActive && backdrop != null && backdrop.hasBackdrop ? backdrop.backgroundColor : undefined;
133
-
134
- // A resolved slot answers the same two questions the canvas probe was asking,
135
- // from the server's own decode. It wins wherever it is present.
136
- //
137
- // `contained` (ADR 0220) forces `contain` regardless of anything else: the
138
- // server deliberately returned a crop at a different aspect than the slot
139
- // asked for, so that the whole product stays in frame. Cropping it again with
140
- // `cover` would undo exactly the cut it went out of its way to avoid, and the
141
- // padding it leaves behind is what `backgroundColor` is for — guaranteed
142
- // non-empty in that case.
143
- const slotBackground = slot == null || (_slot$visualMetadata = slot.visualMetadata) == null ? void 0 : _slot$visualMetadata.background;
144
- const slotIsSolid = slotBackground === 'IMAGE_BACKGROUND_SOLID';
145
- const slotWantsContain = Boolean(slot == null || (_slot$crop = slot.crop) == null ? void 0 : _slot$crop.contained) || slotIsSolid;
146
- const resolvedObjectFit = slot ? slotWantsContain ? 'contain' : 'cover' : effectiveObjectFit;
147
- const resolvedBackgroundColor = slot ? slotWantsContain ? (0, _imageSetTypes.backdropColorOf)(slot) : undefined : adaptiveBackgroundColor;
148
130
  (0, _react.useEffect)(() => {
149
131
  if (!adaptiveActive) {
150
132
  return;
@@ -363,7 +345,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
363
345
  className: ['block', layout === 'intrinsic' ? '' : 'relative overflow-hidden', showDynamicBadge ? 'relative' : '', className].filter(Boolean).join(' '),
364
346
  style: layout === 'intrinsic' ? undefined : {
365
347
  minHeight: '1px',
366
- backgroundColor: resolvedBackgroundColor
348
+ backgroundColor: adaptiveBackgroundColor
367
349
  },
368
350
  onClick: clickable ? onClick : undefined,
369
351
  onKeyDown: clickable ? handleKeyDown : undefined,
@@ -373,7 +355,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
373
355
  __self: void 0,
374
356
  __source: {
375
357
  fileName: _jsxFileName,
376
- lineNumber: 648,
358
+ lineNumber: 609,
377
359
  columnNumber: 7
378
360
  }
379
361
  }, showDynamicBadge && /*#__PURE__*/_react.default.createElement("span", {
@@ -381,7 +363,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
381
363
  __self: void 0,
382
364
  __source: {
383
365
  fileName: _jsxFileName,
384
- lineNumber: 670,
366
+ lineNumber: 631,
385
367
  columnNumber: 11
386
368
  }
387
369
  }, contextualImageKey), !isLoaded && !isError && sourceIdentifier && /*#__PURE__*/_react.default.createElement("span", {
@@ -392,7 +374,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
392
374
  __self: void 0,
393
375
  __source: {
394
376
  fileName: _jsxFileName,
395
- lineNumber: 675,
377
+ lineNumber: 636,
396
378
  columnNumber: 11
397
379
  }
398
380
  }), isError && /*#__PURE__*/_react.default.createElement("span", {
@@ -402,7 +384,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
402
384
  __self: void 0,
403
385
  __source: {
404
386
  fileName: _jsxFileName,
405
- lineNumber: 684,
387
+ lineNumber: 645,
406
388
  columnNumber: 11
407
389
  }
408
390
  }, /*#__PURE__*/_react.default.createElement("span", {
@@ -410,7 +392,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
410
392
  __self: void 0,
411
393
  __source: {
412
394
  fileName: _jsxFileName,
413
- lineNumber: 689,
395
+ lineNumber: 650,
414
396
  columnNumber: 13
415
397
  }
416
398
  }, /*#__PURE__*/_react.default.createElement("svg", {
@@ -423,7 +405,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
423
405
  __self: void 0,
424
406
  __source: {
425
407
  fileName: _jsxFileName,
426
- lineNumber: 690,
408
+ lineNumber: 651,
427
409
  columnNumber: 15
428
410
  }
429
411
  }, /*#__PURE__*/_react.default.createElement("path", {
@@ -434,7 +416,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
434
416
  __self: void 0,
435
417
  __source: {
436
418
  fileName: _jsxFileName,
437
- lineNumber: 698,
419
+ lineNumber: 659,
438
420
  columnNumber: 17
439
421
  }
440
422
  })), /*#__PURE__*/_react.default.createElement("span", {
@@ -442,13 +424,13 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
442
424
  __self: void 0,
443
425
  __source: {
444
426
  fileName: _jsxFileName,
445
- lineNumber: 705,
427
+ lineNumber: 666,
446
428
  columnNumber: 15
447
429
  }
448
430
  }, "Failed to load image"))), imageUrl && !isError && /*#__PURE__*/_react.default.createElement("img", {
449
431
  src: imageUrl,
450
432
  alt: alt,
451
- className: `${layout === 'intrinsic' ? 'w-full h-auto' : 'absolute inset-0 w-full h-full'} transition-opacity duration-300 ${isLoaded ? 'opacity-100' : 'opacity-0'} ${resolvedObjectFit === 'contain' ? 'object-contain' : resolvedObjectFit === 'cover' ? 'object-cover' : resolvedObjectFit === 'fill' ? 'object-fill' : resolvedObjectFit === 'none' ? 'object-none' : resolvedObjectFit === 'scale-down' ? 'object-scale-down' : ''}`,
433
+ className: `${layout === 'intrinsic' ? 'w-full h-auto' : 'absolute inset-0 w-full h-full'} transition-opacity duration-300 ${isLoaded ? 'opacity-100' : 'opacity-0'} ${effectiveObjectFit === 'contain' ? 'object-contain' : effectiveObjectFit === 'cover' ? 'object-cover' : effectiveObjectFit === 'fill' ? 'object-fill' : effectiveObjectFit === 'none' ? 'object-none' : effectiveObjectFit === 'scale-down' ? 'object-scale-down' : ''}`,
452
434
  style: layout === 'intrinsic' ? {
453
435
  width: '100%',
454
436
  height: 'auto',
@@ -459,7 +441,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
459
441
  inset: 0,
460
442
  width: '100%',
461
443
  height: '100%',
462
- objectFit: resolvedObjectFit,
444
+ objectFit: effectiveObjectFit,
463
445
  maxWidth: '100%',
464
446
  display: 'block'
465
447
  },
@@ -469,7 +451,7 @@ const OptimizedImage = exports.OptimizedImage = /*#__PURE__*/(0, _react.memo)(pr
469
451
  __self: void 0,
470
452
  __source: {
471
453
  fileName: _jsxFileName,
472
- lineNumber: 711,
454
+ lineNumber: 672,
473
455
  columnNumber: 11
474
456
  }
475
457
  })));
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireWildcard","require","_imageUtils","_imageBackdrop","_linkTypes","_ComponentDependenciesContext","_useResolvedImageSources","_imageSetTypes","_jsxFileName","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","lowResFallbackCache","Map","OptimizedImage","exports","memo","props","_slot$visualMetadata","_slot$crop","alt","className","quality","format","progressive","placeholderColor","objectFit","layout","onLoad","onError","onClick","clickable","imageFromText","disableResize","imageMode","adaptiveBackdrop","slot","fallbackOnLowRes","lowResThreshold","isResolvedMode","unresolvedSource","filename","preResolvedUrl","resolvedUrl","filter","undefined","sourceIdentifier","deps","useComponentDependencies","isLoaded","setIsLoaded","useState","isError","setIsError","imageUrl","setImageUrl","isFallback","setIsFallback","backdrop","setBackdrop","isDebugImageEnabled","useDebugImageContext","dimensions","setDimensions","containerRef","useRef","observerRef","isContextualImage","useMemo","isWeb5ImageUrl","contextualImageKey","rawKey","slice","length","decodeURIComponent","trim","resolutionInputs","src","images","resolvedSources","loading","isResolutionLoading","useResolvedImageSources","resolvedSource","useEffect","logContextualImage","url","contextualTerm","imageEventType","isImageResolved","isFallbackImage","contextualImageFallback","fallbacks","fallbackImages","Math","floor","random","effectiveFilename","sourceCacheKey","normalizeImageUrl","hasResolvedSourceDimensions","width","height","isLowResResolvedAsset","cachedFallbackUrl","showDynamicBadge","adaptiveActive","adaptiveResolved","effectiveObjectFit","hasBackdrop","effectiveImageMode","adaptiveBackgroundColor","backgroundColor","slotBackground","visualMetadata","background","slotIsSolid","slotWantsContain","Boolean","crop","contained","resolvedObjectFit","resolvedBackgroundColor","backdropColorOf","token","aborted","loadBackdropAnalysis","then","result","container","current","updateDimensions","rect","getBoundingClientRect","ceil","window","ResizeObserver","observe","handleResize","addEventListener","disconnect","removeEventListener","normalizedUrl","isExternalNonWixUrl","startsWith","includes","imageFilename","match","replace","dpr","devicePixelRatio","optimizedUrl","getResizedImageUrl","handleImageLoad","img","currentTarget","naturalWidth","naturalHeight","originalImageUrl","currentSrc","console","warn","fallbackImageUrl","handleImageError","error","source","Error","isTransparentPlaceholder","placeholderStyles","animation","backgroundSize","handleKeyDown","key","preventDefault","createElement","Fragment","ref","join","style","minHeight","onKeyDown","tabIndex","role","__self","__source","fileName","lineNumber","columnNumber","fill","stroke","viewBox","focusable","strokeLinecap","strokeLinejoin","strokeWidth","d","maxWidth","display","position","inset"],"sources":["../../../../src/components/ui/OptimizedImage.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect, memo, useMemo } from 'react';\nimport { getResizedImageUrl, normalizeImageUrl } from '../../utils/image-utils';\nimport {\n loadBackdropAnalysis,\n type BackdropAnalysis,\n} from '../../utils/imageBackdrop';\nimport { isWeb5ImageUrl } from '../../types/link-types';\nimport { useComponentDependencies } from '../../context/ComponentDependenciesContext';\nimport type { ImageSearchFilterString } from '../../image/imageSearchFilterTypes';\nimport { useResolvedImageSources } from '../../hooks/useResolvedImageSources';\nimport {\n backdropColorOf,\n type ResolvedImageSlot,\n} from '../../image/imageSetTypes';\n\nconst lowResFallbackCache = new Map<string, string>();\n\ninterface OptimizedImageBaseProps {\n /** Accessible alternative text for the rendered image. */\n alt: string;\n /** Additional CSS classes applied to the outer image container. */\n className?: string;\n /** Preferred output quality for resized Wix media URLs. */\n quality?: number;\n /** Requested output format for future image delivery customization. */\n format?: 'auto' | 'webp' | 'jpg' | 'png';\n /** Enables progressive loading behavior when supported by the delivery layer. */\n progressive?: boolean;\n /** Placeholder background color shown before the image loads. */\n placeholderColor?: string;\n /** CSS object-fit behavior applied to the rendered `<img>`. */\n objectFit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';\n /** Layout strategy for the image container. */\n layout?: 'fill' | 'intrinsic';\n /** Called after the final rendered image successfully loads. */\n onLoad?: () => void;\n /** Called when the final rendered image fails to load. */\n onError?: (error: Error) => void;\n /** Click handler for interactive image surfaces. */\n onClick?: () => void;\n /** Makes the image container keyboard-focusable and clickable. */\n clickable?: boolean;\n /** Marks the source as originating from text-driven image generation for BI logging. */\n imageFromText?: boolean;\n /** Skips Wix fitted delivery URL rewriting and uses the normalized original URL directly. */\n disableResize?: boolean;\n /** CDN resize mode. 'fill' crops to exact container dimensions (sharp at slot size).\n * 'fit' (default) preserves aspect ratio. */\n imageMode?: 'fit' | 'fill';\n /**\n * Auto-pick `objectFit`/`imageMode` per image by sniffing its edges on a\n * canvas (see `imageBackdrop.ts`). Images shot on a seamless backdrop are\n * rendered `contain` with the slot painted that backdrop colour (the subject\n * is never cropped, the letterbox is invisible); full-bleed scenes fall back\n * to `cover`. Overrides `objectFit`/`imageMode` once analysis resolves; until\n * then, and on any probe/CORS failure, the passed `objectFit`/`imageMode`\n * apply. No effect for `layout=\"intrinsic\"`. */\n adaptiveBackdrop?: boolean;\n /**\n * A slot resolved by `ResolveImageSet` (ADR 0221). Supplying it makes the\n * server's own decode authoritative over `adaptiveBackdrop`'s canvas probe:\n * fit comes from `visualMetadata.background` and the backdrop colour from\n * `backgroundColor` (falling back to the dominant swatch for a scene), so no\n * pixel is read back, no CORS is needed and nothing is guessed.\n *\n * Pair it with `resolvedUrl={slot.imageUrl}` and `disableResize` — the URL\n * already carries the crop and the render size.\n */\n slot?: ResolvedImageSlot;\n /** Full URL to a fallback image used when the primary image is considered low resolution. */\n fallbackOnLowRes?: string;\n /** Minimum acceptable width or height before low-resolution fallback is triggered. */\n lowResThreshold?: number;\n}\n\ninterface OptimizedImageWithFilenameProps {\n /** Image source to render. Supports full URLs and `web5://image/...` contextual image tokens. */\n filename: string;\n /** Optional contextual search filter used only when resolving a `web5://image/...` source. */\n filter?: ImageSearchFilterString;\n /** Mutually exclusive with `filename`; provide this only when the image URL is already resolved. */\n resolvedUrl?: never;\n}\n\ninterface OptimizedImageWithResolvedUrlProps {\n /** Already-resolved image URL. When provided, OptimizedImage skips all source resolution. */\n resolvedUrl: string;\n /** Mutually exclusive with `resolvedUrl`; use `filename` when the source still needs resolving. */\n filename?: never;\n /** Not applicable for already-resolved image URLs. */\n filter?: never;\n}\n\nexport type OptimizedImageProps = OptimizedImageBaseProps &\n (OptimizedImageWithFilenameProps | OptimizedImageWithResolvedUrlProps);\n\nexport const OptimizedImage: React.FC<OptimizedImageProps> = memo((props) => {\n const {\n alt,\n className = '',\n quality = 85,\n format = 'auto',\n progressive = true,\n placeholderColor = '#f3f4f6',\n objectFit = 'contain',\n layout = 'fill',\n onLoad,\n onError,\n onClick,\n clickable = false,\n imageFromText = false,\n disableResize = false,\n imageMode = 'fit',\n adaptiveBackdrop = false,\n slot,\n fallbackOnLowRes,\n lowResThreshold = 550,\n } = props;\n void format;\n void progressive;\n\n const isResolvedMode = 'resolvedUrl' in props;\n const unresolvedSource = 'filename' in props ? props.filename ?? '' : '';\n const preResolvedUrl = 'resolvedUrl' in props ? props.resolvedUrl : '';\n const filter = 'filename' in props ? props.filter : undefined;\n const sourceIdentifier = isResolvedMode ? preResolvedUrl : unresolvedSource;\n\n const deps = useComponentDependencies();\n const [isLoaded, setIsLoaded] = useState(false);\n const [isError, setIsError] = useState(false);\n const [imageUrl, setImageUrl] = useState<string>('');\n const [isFallback, setIsFallback] = useState(false);\n // null = adaptive analysis pending (only meaningful when adaptiveBackdrop).\n const [backdrop, setBackdrop] = useState<BackdropAnalysis | null>(null);\n const isDebugImageEnabled = deps.useDebugImageContext();\n const [dimensions, setDimensions] = useState<{\n width: number;\n height: number;\n } | null>(null);\n\n const containerRef = useRef<HTMLDivElement>(null);\n const observerRef = useRef<ResizeObserver | null>(null);\n\n const isContextualImage = useMemo(\n () =>\n !isResolvedMode &&\n !!(unresolvedSource && isWeb5ImageUrl(unresolvedSource)),\n [isResolvedMode, unresolvedSource],\n );\n\n const contextualImageKey = useMemo(() => {\n if (!isContextualImage) {\n return '';\n }\n const rawKey = unresolvedSource.slice('web5://image/'.length);\n try {\n return decodeURIComponent(rawKey).trim();\n } catch {\n return rawKey.trim();\n }\n }, [isContextualImage, unresolvedSource]);\n const resolutionInputs = useMemo(\n () =>\n isResolvedMode || !unresolvedSource\n ? []\n : [\n {\n src: unresolvedSource,\n filter,\n },\n ],\n [filter, isResolvedMode, unresolvedSource],\n );\n const { images: resolvedSources, loading: isResolutionLoading } =\n useResolvedImageSources(resolutionInputs);\n const resolvedSource = useMemo(\n () => (!isResolvedMode ? resolvedSources?.[0] ?? null : null),\n [isResolvedMode, resolvedSources],\n );\n\n useEffect(() => {\n if (\n !isContextualImage ||\n isResolvedMode ||\n isResolutionLoading ||\n resolvedSources === null\n ) {\n return;\n }\n\n deps.logContextualImage?.({\n imageUrl: resolvedSource?.url ?? '',\n contextualTerm: contextualImageKey,\n imageEventType: imageFromText\n ? 'web5_image_link_from_text'\n : 'web5_image_link',\n isImageResolved: !!resolvedSource?.url,\n isFallbackImage: false,\n });\n }, [\n contextualImageKey,\n deps,\n imageFromText,\n isContextualImage,\n isResolvedMode,\n isResolutionLoading,\n resolvedSource?.url,\n resolvedSources,\n ]);\n\n // When imageFromText contextual image resolution returns empty, use a random fallback\n const contextualImageFallback = useMemo(() => {\n if (\n !imageFromText ||\n !isContextualImage ||\n isResolutionLoading ||\n resolvedSources === null ||\n resolvedSource?.url\n ) {\n return '';\n }\n const fallbacks = deps.fallbackImages;\n if (!fallbacks || fallbacks.length === 0) {\n return '';\n }\n return fallbacks[Math.floor(Math.random() * fallbacks.length)];\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n imageFromText,\n isContextualImage,\n isResolutionLoading,\n resolvedSources,\n resolvedSource?.url,\n deps.fallbackImages,\n ]);\n\n // Log when a fallback image is used for an unresolved contextual image\n useEffect(() => {\n if (!contextualImageFallback) {\n return;\n }\n deps.logContextualImage?.({\n imageUrl: contextualImageFallback,\n contextualTerm: contextualImageKey,\n imageEventType: 'web5_image_fallback',\n isImageResolved: false,\n isFallbackImage: true,\n });\n }, [contextualImageFallback, contextualImageKey, deps]);\n\n const effectiveFilename = isResolvedMode\n ? preResolvedUrl\n : resolvedSource?.url || contextualImageFallback;\n const sourceCacheKey = useMemo(\n () =>\n effectiveFilename ? normalizeImageUrl(effectiveFilename).trim() : '',\n [effectiveFilename],\n );\n const hasResolvedSourceDimensions =\n typeof resolvedSource?.width === 'number' &&\n typeof resolvedSource?.height === 'number';\n const isLowResResolvedAsset =\n hasResolvedSourceDimensions &&\n (resolvedSource.width! < lowResThreshold ||\n resolvedSource.height! < lowResThreshold);\n const cachedFallbackUrl = useMemo(\n () => (sourceCacheKey ? lowResFallbackCache.get(sourceCacheKey) ?? '' : ''),\n [sourceCacheKey],\n );\n const showDynamicBadge = isContextualImage && isDebugImageEnabled;\n\n // Adaptive fit: probe the resolved image's edges, then map to fit/object-fit.\n // Until analysis resolves (`backdrop === null`) the displayed URL is held back\n // so we never fetch with the wrong mode and flash a re-crop. On a backdrop we\n // render `contain` (whole subject visible) and paint the slot its colour; on a\n // busy scene we `cover`. Failures resolve to `hasBackdrop: false` → `cover`.\n const adaptiveActive = adaptiveBackdrop && layout !== 'intrinsic';\n const adaptiveResolved = !adaptiveActive || backdrop !== null;\n const effectiveObjectFit = adaptiveActive\n ? backdrop?.hasBackdrop\n ? 'contain'\n : 'cover'\n : objectFit;\n const effectiveImageMode = adaptiveActive\n ? backdrop?.hasBackdrop\n ? 'fit'\n : 'fill'\n : imageMode;\n const adaptiveBackgroundColor =\n adaptiveActive && backdrop?.hasBackdrop\n ? backdrop.backgroundColor\n : undefined;\n\n // A resolved slot answers the same two questions the canvas probe was asking,\n // from the server's own decode. It wins wherever it is present.\n //\n // `contained` (ADR 0220) forces `contain` regardless of anything else: the\n // server deliberately returned a crop at a different aspect than the slot\n // asked for, so that the whole product stays in frame. Cropping it again with\n // `cover` would undo exactly the cut it went out of its way to avoid, and the\n // padding it leaves behind is what `backgroundColor` is for — guaranteed\n // non-empty in that case.\n const slotBackground = slot?.visualMetadata?.background;\n const slotIsSolid = slotBackground === 'IMAGE_BACKGROUND_SOLID';\n const slotWantsContain = Boolean(slot?.crop?.contained) || slotIsSolid;\n const resolvedObjectFit = slot\n ? slotWantsContain\n ? 'contain'\n : 'cover'\n : effectiveObjectFit;\n const resolvedBackgroundColor = slot\n ? slotWantsContain\n ? backdropColorOf(slot)\n : undefined\n : adaptiveBackgroundColor;\n\n useEffect(() => {\n if (!adaptiveActive) {\n return;\n }\n setBackdrop(null);\n if (\n !effectiveFilename ||\n isFallback ||\n cachedFallbackUrl ||\n (isLowResResolvedAsset && fallbackOnLowRes)\n ) {\n // No analyzable primary source → behave like a busy scene (cover).\n setBackdrop({ hasBackdrop: false });\n return;\n }\n const token = { aborted: false };\n loadBackdropAnalysis(effectiveFilename, token).then((result) => {\n if (!token.aborted) {\n setBackdrop(result);\n }\n });\n return () => {\n token.aborted = true;\n };\n }, [\n adaptiveActive,\n effectiveFilename,\n isFallback,\n cachedFallbackUrl,\n isLowResResolvedAsset,\n fallbackOnLowRes,\n ]);\n\n useEffect(() => {\n setIsLoaded(false);\n setIsError(false);\n setIsFallback(false);\n setImageUrl('');\n }, [sourceCacheKey, fallbackOnLowRes]);\n\n useEffect(() => {\n if (!sourceCacheKey || !fallbackOnLowRes) {\n return;\n }\n\n if (isLowResResolvedAsset) {\n lowResFallbackCache.set(sourceCacheKey, fallbackOnLowRes);\n setIsFallback(true);\n setImageUrl(fallbackOnLowRes);\n return;\n }\n\n if (!cachedFallbackUrl) {\n return;\n }\n\n setIsFallback(true);\n setImageUrl(cachedFallbackUrl);\n }, [\n cachedFallbackUrl,\n fallbackOnLowRes,\n isLowResResolvedAsset,\n sourceCacheKey,\n ]);\n\n // For fill layout, measure container so we can request a resized Wix image.\n useEffect(() => {\n if (layout === 'intrinsic' || disableResize) {\n return;\n }\n const container = containerRef.current;\n if (!container) {\n return;\n }\n\n const updateDimensions = () => {\n const rect = container.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n setDimensions({\n width: Math.ceil(rect.width),\n height: Math.ceil(rect.height),\n });\n }\n };\n\n updateDimensions();\n\n if ('ResizeObserver' in window) {\n observerRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n observerRef.current.observe(container);\n }\n\n const handleResize = () => updateDimensions();\n window.addEventListener('resize', handleResize);\n\n return () => {\n if (observerRef.current) {\n observerRef.current.disconnect();\n }\n window.removeEventListener('resize', handleResize);\n };\n }, [disableResize, layout]);\n\n // Intrinsic layout: use normalized URL without resize logic.\n useEffect(() => {\n if (layout !== 'intrinsic') {\n return;\n }\n if (\n !effectiveFilename ||\n isFallback ||\n cachedFallbackUrl ||\n (isLowResResolvedAsset && fallbackOnLowRes)\n ) {\n return;\n }\n\n const normalizedUrl = normalizeImageUrl(effectiveFilename);\n setImageUrl(normalizedUrl);\n }, [\n cachedFallbackUrl,\n effectiveFilename,\n isFallback,\n isLowResResolvedAsset,\n layout,\n ]);\n\n // External non-Wix URLs skip resizing; use them immediately.\n useEffect(() => {\n if (layout === 'intrinsic') {\n return;\n }\n if (\n !effectiveFilename ||\n isFallback ||\n cachedFallbackUrl ||\n (isLowResResolvedAsset && fallbackOnLowRes)\n ) {\n return;\n }\n\n const normalizedUrl = normalizeImageUrl(effectiveFilename);\n const isExternalNonWixUrl =\n (normalizedUrl.startsWith('http://') ||\n normalizedUrl.startsWith('https://')) &&\n !normalizedUrl.includes('static.wixstatic.com');\n\n if (isExternalNonWixUrl) {\n setImageUrl(normalizedUrl);\n }\n }, [\n cachedFallbackUrl,\n effectiveFilename,\n isFallback,\n isLowResResolvedAsset,\n layout,\n ]);\n\n // Explicit opt-out: use original normalized URL even in fill layouts.\n useEffect(() => {\n if (layout === 'intrinsic') {\n return;\n }\n if (\n !disableResize ||\n !effectiveFilename ||\n isFallback ||\n cachedFallbackUrl ||\n (isLowResResolvedAsset && fallbackOnLowRes)\n ) {\n return;\n }\n\n setImageUrl(normalizeImageUrl(effectiveFilename));\n }, [\n cachedFallbackUrl,\n disableResize,\n effectiveFilename,\n isFallback,\n isLowResResolvedAsset,\n layout,\n ]);\n\n // Wix/local URLs: wait for dimensions, then build a resized URL.\n useEffect(() => {\n if (layout === 'intrinsic') {\n return;\n }\n if (disableResize) {\n return;\n }\n // Hold the fetch until adaptive analysis picks fit vs fill, so we request\n // the right CDN mode once instead of fetching twice and re-cropping.\n if (!adaptiveResolved) {\n return;\n }\n if (\n !dimensions ||\n !effectiveFilename ||\n isFallback ||\n cachedFallbackUrl ||\n (isLowResResolvedAsset && fallbackOnLowRes)\n ) {\n return;\n }\n\n const normalizedUrl = normalizeImageUrl(effectiveFilename);\n const isExternalNonWixUrl =\n (normalizedUrl.startsWith('http://') ||\n normalizedUrl.startsWith('https://')) &&\n !normalizedUrl.includes('static.wixstatic.com');\n\n if (isExternalNonWixUrl) {\n return;\n }\n\n let imageFilename = effectiveFilename;\n if (normalizedUrl.includes('static.wixstatic.com')) {\n const match = normalizedUrl.match(/media\\/([^/?]+)/);\n if (match && match[1]) {\n imageFilename = match[1];\n } else {\n setImageUrl(normalizedUrl);\n return;\n }\n } else if (\n normalizedUrl.startsWith('https://static.wixstatic.com/media/')\n ) {\n imageFilename = normalizedUrl.replace(\n 'https://static.wixstatic.com/media/',\n '',\n );\n }\n\n const dpr = window.devicePixelRatio ?? 1;\n const optimizedUrl = getResizedImageUrl(\n imageFilename,\n dimensions.width * dpr,\n dimensions.height * dpr,\n { quality, imageMode: effectiveImageMode },\n );\n setImageUrl(optimizedUrl);\n }, [\n dimensions,\n cachedFallbackUrl,\n effectiveFilename,\n isFallback,\n isLowResResolvedAsset,\n layout,\n disableResize,\n quality,\n effectiveImageMode,\n adaptiveResolved,\n ]);\n\n const handleImageLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n const img = e.currentTarget;\n\n if (\n fallbackOnLowRes &&\n !isFallback &&\n !hasResolvedSourceDimensions &&\n (img.naturalWidth < lowResThreshold ||\n img.naturalHeight < lowResThreshold)\n ) {\n const originalImageUrl =\n img.currentSrc || imageUrl || effectiveFilename || sourceIdentifier;\n\n if (sourceCacheKey) {\n lowResFallbackCache.set(sourceCacheKey, fallbackOnLowRes);\n }\n\n setIsFallback(true);\n setImageUrl(fallbackOnLowRes);\n setIsLoaded(false);\n\n console.warn('OptimizedImage applied a low-res fallback image.', {\n originalImageUrl,\n fallbackImageUrl: fallbackOnLowRes,\n naturalWidth: img.naturalWidth,\n naturalHeight: img.naturalHeight,\n lowResThreshold,\n });\n\n deps.logContextualImage?.({\n imageUrl: fallbackOnLowRes,\n contextualTerm: contextualImageKey,\n imageEventType: 'web5_image_fallback',\n isImageResolved: true,\n isFallbackImage: true,\n });\n return;\n }\n\n setIsLoaded(true);\n onLoad?.();\n };\n\n const handleImageError = () => {\n setIsError(true);\n console.error('Failed to load image:', {\n source: sourceIdentifier,\n imageUrl,\n alt,\n });\n onError?.(new Error(`Failed to load image: ${sourceIdentifier}`));\n };\n\n const isTransparentPlaceholder = placeholderColor === 'transparent';\n const placeholderStyles = isTransparentPlaceholder\n ? {\n background: 'transparent',\n animation: 'none',\n }\n : {\n background: `linear-gradient(90deg, ${placeholderColor} 0%, #e5e7eb 50%, ${placeholderColor} 100%)`,\n backgroundSize: '200% 100%',\n animation: 'shimmer 2s infinite ease-in-out',\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (onClick && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n onClick();\n }\n };\n\n return (\n <>\n <span\n ref={containerRef}\n className={[\n 'block',\n layout === 'intrinsic' ? '' : 'relative overflow-hidden',\n showDynamicBadge ? 'relative' : '',\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n style={\n layout === 'intrinsic'\n ? undefined\n : { minHeight: '1px', backgroundColor: resolvedBackgroundColor }\n }\n onClick={clickable ? onClick : undefined}\n onKeyDown={clickable ? handleKeyDown : undefined}\n tabIndex={clickable ? 0 : undefined}\n role={clickable ? 'button' : undefined}\n aria-label={clickable ? alt : undefined}\n >\n {showDynamicBadge && (\n <span className=\"absolute left-2 top-2 z-10 rounded bg-blue-600/90 px-2 py-1 text-[10px] font-semibold tracking-wide text-white shadow block\">\n {contextualImageKey}\n </span>\n )}\n {!isLoaded && !isError && sourceIdentifier && (\n <span\n className=\"absolute inset-0 rounded block\"\n style={placeholderStyles}\n role=\"status\"\n aria-label=\"Loading image\"\n />\n )}\n\n {isError && (\n <span\n className=\"absolute inset-0 flex items-center justify-center bg-gray-100 text-gray-500 rounded block\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n <span className=\"text-center p-4 block\">\n <svg\n className=\"w-8 h-8 mx-auto mb-2 text-gray-400\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n <span className=\"text-xs block\">Failed to load image</span>\n </span>\n </span>\n )}\n\n {imageUrl && !isError && (\n <img\n src={imageUrl}\n alt={alt}\n className={`${\n layout === 'intrinsic'\n ? 'w-full h-auto'\n : 'absolute inset-0 w-full h-full'\n } transition-opacity duration-300 ${\n isLoaded ? 'opacity-100' : 'opacity-0'\n } ${\n resolvedObjectFit === 'contain'\n ? 'object-contain'\n : resolvedObjectFit === 'cover'\n ? 'object-cover'\n : resolvedObjectFit === 'fill'\n ? 'object-fill'\n : resolvedObjectFit === 'none'\n ? 'object-none'\n : resolvedObjectFit === 'scale-down'\n ? 'object-scale-down'\n : ''\n }`}\n style={\n layout === 'intrinsic'\n ? {\n width: '100%',\n height: 'auto',\n maxWidth: '100%',\n display: 'block',\n }\n : {\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n objectFit: resolvedObjectFit,\n maxWidth: '100%',\n display: 'block',\n }\n }\n onLoad={handleImageLoad}\n onError={handleImageError}\n loading={imageUrl.startsWith('data:') ? 'eager' : 'lazy'}\n />\n )}\n </span>\n </>\n );\n});\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireWildcard","require","_imageUtils","_imageBackdrop","_linkTypes","_ComponentDependenciesContext","_useResolvedImageSources","_jsxFileName","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","lowResFallbackCache","Map","OptimizedImage","exports","memo","props","alt","className","quality","format","progressive","placeholderColor","objectFit","layout","onLoad","onError","onClick","clickable","imageFromText","disableResize","imageMode","adaptiveBackdrop","fallbackOnLowRes","lowResThreshold","isResolvedMode","unresolvedSource","filename","preResolvedUrl","resolvedUrl","filter","undefined","sourceIdentifier","deps","useComponentDependencies","isLoaded","setIsLoaded","useState","isError","setIsError","imageUrl","setImageUrl","isFallback","setIsFallback","backdrop","setBackdrop","isDebugImageEnabled","useDebugImageContext","dimensions","setDimensions","containerRef","useRef","observerRef","isContextualImage","useMemo","isWeb5ImageUrl","contextualImageKey","rawKey","slice","length","decodeURIComponent","trim","resolutionInputs","src","images","resolvedSources","loading","isResolutionLoading","useResolvedImageSources","resolvedSource","useEffect","logContextualImage","url","contextualTerm","imageEventType","isImageResolved","isFallbackImage","contextualImageFallback","fallbacks","fallbackImages","Math","floor","random","effectiveFilename","sourceCacheKey","normalizeImageUrl","hasResolvedSourceDimensions","width","height","isLowResResolvedAsset","cachedFallbackUrl","showDynamicBadge","adaptiveActive","adaptiveResolved","effectiveObjectFit","hasBackdrop","effectiveImageMode","adaptiveBackgroundColor","backgroundColor","token","aborted","loadBackdropAnalysis","then","result","container","current","updateDimensions","rect","getBoundingClientRect","ceil","window","ResizeObserver","observe","handleResize","addEventListener","disconnect","removeEventListener","normalizedUrl","isExternalNonWixUrl","startsWith","includes","imageFilename","match","replace","dpr","devicePixelRatio","optimizedUrl","getResizedImageUrl","handleImageLoad","img","currentTarget","naturalWidth","naturalHeight","originalImageUrl","currentSrc","console","warn","fallbackImageUrl","handleImageError","error","source","Error","isTransparentPlaceholder","placeholderStyles","background","animation","backgroundSize","handleKeyDown","key","preventDefault","createElement","Fragment","ref","Boolean","join","style","minHeight","onKeyDown","tabIndex","role","__self","__source","fileName","lineNumber","columnNumber","fill","stroke","viewBox","focusable","strokeLinecap","strokeLinejoin","strokeWidth","d","maxWidth","display","position","inset"],"sources":["../../../../src/components/ui/OptimizedImage.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect, memo, useMemo } from 'react';\nimport { getResizedImageUrl, normalizeImageUrl } from '../../utils/image-utils';\nimport {\n loadBackdropAnalysis,\n type BackdropAnalysis,\n} from '../../utils/imageBackdrop';\nimport { isWeb5ImageUrl } from '../../types/link-types';\nimport { useComponentDependencies } from '../../context/ComponentDependenciesContext';\nimport type { ImageSearchFilterString } from '../../image/imageSearchFilterTypes';\nimport { useResolvedImageSources } from '../../hooks/useResolvedImageSources';\n\nconst lowResFallbackCache = new Map<string, string>();\n\ninterface OptimizedImageBaseProps {\n /** Accessible alternative text for the rendered image. */\n alt: string;\n /** Additional CSS classes applied to the outer image container. */\n className?: string;\n /** Preferred output quality for resized Wix media URLs. */\n quality?: number;\n /** Requested output format for future image delivery customization. */\n format?: 'auto' | 'webp' | 'jpg' | 'png';\n /** Enables progressive loading behavior when supported by the delivery layer. */\n progressive?: boolean;\n /** Placeholder background color shown before the image loads. */\n placeholderColor?: string;\n /** CSS object-fit behavior applied to the rendered `<img>`. */\n objectFit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';\n /** Layout strategy for the image container. */\n layout?: 'fill' | 'intrinsic';\n /** Called after the final rendered image successfully loads. */\n onLoad?: () => void;\n /** Called when the final rendered image fails to load. */\n onError?: (error: Error) => void;\n /** Click handler for interactive image surfaces. */\n onClick?: () => void;\n /** Makes the image container keyboard-focusable and clickable. */\n clickable?: boolean;\n /** Marks the source as originating from text-driven image generation for BI logging. */\n imageFromText?: boolean;\n /** Skips Wix fitted delivery URL rewriting and uses the normalized original URL directly. */\n disableResize?: boolean;\n /** CDN resize mode. 'fill' crops to exact container dimensions (sharp at slot size).\n * 'fit' (default) preserves aspect ratio. */\n imageMode?: 'fit' | 'fill';\n /**\n * Auto-pick `objectFit`/`imageMode` per image by sniffing its edges on a\n * canvas (see `imageBackdrop.ts`). Images shot on a seamless backdrop are\n * rendered `contain` with the slot painted that backdrop colour (the subject\n * is never cropped, the letterbox is invisible); full-bleed scenes fall back\n * to `cover`. Overrides `objectFit`/`imageMode` once analysis resolves; until\n * then, and on any probe/CORS failure, the passed `objectFit`/`imageMode`\n * apply. No effect for `layout=\"intrinsic\"`. */\n adaptiveBackdrop?: boolean;\n /** Full URL to a fallback image used when the primary image is considered low resolution. */\n fallbackOnLowRes?: string;\n /** Minimum acceptable width or height before low-resolution fallback is triggered. */\n lowResThreshold?: number;\n}\n\ninterface OptimizedImageWithFilenameProps {\n /** Image source to render. Supports full URLs and `web5://image/...` contextual image tokens. */\n filename: string;\n /** Optional contextual search filter used only when resolving a `web5://image/...` source. */\n filter?: ImageSearchFilterString;\n /** Mutually exclusive with `filename`; provide this only when the image URL is already resolved. */\n resolvedUrl?: never;\n}\n\ninterface OptimizedImageWithResolvedUrlProps {\n /** Already-resolved image URL. When provided, OptimizedImage skips all source resolution. */\n resolvedUrl: string;\n /** Mutually exclusive with `resolvedUrl`; use `filename` when the source still needs resolving. */\n filename?: never;\n /** Not applicable for already-resolved image URLs. */\n filter?: never;\n}\n\nexport type OptimizedImageProps = OptimizedImageBaseProps &\n (OptimizedImageWithFilenameProps | OptimizedImageWithResolvedUrlProps);\n\nexport const OptimizedImage: React.FC<OptimizedImageProps> = memo((props) => {\n const {\n alt,\n className = '',\n quality = 85,\n format = 'auto',\n progressive = true,\n placeholderColor = '#f3f4f6',\n objectFit = 'contain',\n layout = 'fill',\n onLoad,\n onError,\n onClick,\n clickable = false,\n imageFromText = false,\n disableResize = false,\n imageMode = 'fit',\n adaptiveBackdrop = false,\n fallbackOnLowRes,\n lowResThreshold = 550,\n } = props;\n void format;\n void progressive;\n\n const isResolvedMode = 'resolvedUrl' in props;\n const unresolvedSource = 'filename' in props ? props.filename ?? '' : '';\n const preResolvedUrl = 'resolvedUrl' in props ? props.resolvedUrl : '';\n const filter = 'filename' in props ? props.filter : undefined;\n const sourceIdentifier = isResolvedMode ? preResolvedUrl : unresolvedSource;\n\n const deps = useComponentDependencies();\n const [isLoaded, setIsLoaded] = useState(false);\n const [isError, setIsError] = useState(false);\n const [imageUrl, setImageUrl] = useState<string>('');\n const [isFallback, setIsFallback] = useState(false);\n // null = adaptive analysis pending (only meaningful when adaptiveBackdrop).\n const [backdrop, setBackdrop] = useState<BackdropAnalysis | null>(null);\n const isDebugImageEnabled = deps.useDebugImageContext();\n const [dimensions, setDimensions] = useState<{\n width: number;\n height: number;\n } | null>(null);\n\n const containerRef = useRef<HTMLDivElement>(null);\n const observerRef = useRef<ResizeObserver | null>(null);\n\n const isContextualImage = useMemo(\n () =>\n !isResolvedMode &&\n !!(unresolvedSource && isWeb5ImageUrl(unresolvedSource)),\n [isResolvedMode, unresolvedSource],\n );\n\n const contextualImageKey = useMemo(() => {\n if (!isContextualImage) {\n return '';\n }\n const rawKey = unresolvedSource.slice('web5://image/'.length);\n try {\n return decodeURIComponent(rawKey).trim();\n } catch {\n return rawKey.trim();\n }\n }, [isContextualImage, unresolvedSource]);\n const resolutionInputs = useMemo(\n () =>\n isResolvedMode || !unresolvedSource\n ? []\n : [\n {\n src: unresolvedSource,\n filter,\n },\n ],\n [filter, isResolvedMode, unresolvedSource],\n );\n const { images: resolvedSources, loading: isResolutionLoading } =\n useResolvedImageSources(resolutionInputs);\n const resolvedSource = useMemo(\n () => (!isResolvedMode ? resolvedSources?.[0] ?? null : null),\n [isResolvedMode, resolvedSources],\n );\n\n useEffect(() => {\n if (\n !isContextualImage ||\n isResolvedMode ||\n isResolutionLoading ||\n resolvedSources === null\n ) {\n return;\n }\n\n deps.logContextualImage?.({\n imageUrl: resolvedSource?.url ?? '',\n contextualTerm: contextualImageKey,\n imageEventType: imageFromText\n ? 'web5_image_link_from_text'\n : 'web5_image_link',\n isImageResolved: !!resolvedSource?.url,\n isFallbackImage: false,\n });\n }, [\n contextualImageKey,\n deps,\n imageFromText,\n isContextualImage,\n isResolvedMode,\n isResolutionLoading,\n resolvedSource?.url,\n resolvedSources,\n ]);\n\n // When imageFromText contextual image resolution returns empty, use a random fallback\n const contextualImageFallback = useMemo(() => {\n if (\n !imageFromText ||\n !isContextualImage ||\n isResolutionLoading ||\n resolvedSources === null ||\n resolvedSource?.url\n ) {\n return '';\n }\n const fallbacks = deps.fallbackImages;\n if (!fallbacks || fallbacks.length === 0) {\n return '';\n }\n return fallbacks[Math.floor(Math.random() * fallbacks.length)];\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n imageFromText,\n isContextualImage,\n isResolutionLoading,\n resolvedSources,\n resolvedSource?.url,\n deps.fallbackImages,\n ]);\n\n // Log when a fallback image is used for an unresolved contextual image\n useEffect(() => {\n if (!contextualImageFallback) {\n return;\n }\n deps.logContextualImage?.({\n imageUrl: contextualImageFallback,\n contextualTerm: contextualImageKey,\n imageEventType: 'web5_image_fallback',\n isImageResolved: false,\n isFallbackImage: true,\n });\n }, [contextualImageFallback, contextualImageKey, deps]);\n\n const effectiveFilename = isResolvedMode\n ? preResolvedUrl\n : resolvedSource?.url || contextualImageFallback;\n const sourceCacheKey = useMemo(\n () =>\n effectiveFilename ? normalizeImageUrl(effectiveFilename).trim() : '',\n [effectiveFilename],\n );\n const hasResolvedSourceDimensions =\n typeof resolvedSource?.width === 'number' &&\n typeof resolvedSource?.height === 'number';\n const isLowResResolvedAsset =\n hasResolvedSourceDimensions &&\n (resolvedSource.width! < lowResThreshold ||\n resolvedSource.height! < lowResThreshold);\n const cachedFallbackUrl = useMemo(\n () => (sourceCacheKey ? lowResFallbackCache.get(sourceCacheKey) ?? '' : ''),\n [sourceCacheKey],\n );\n const showDynamicBadge = isContextualImage && isDebugImageEnabled;\n\n // Adaptive fit: probe the resolved image's edges, then map to fit/object-fit.\n // Until analysis resolves (`backdrop === null`) the displayed URL is held back\n // so we never fetch with the wrong mode and flash a re-crop. On a backdrop we\n // render `contain` (whole subject visible) and paint the slot its colour; on a\n // busy scene we `cover`. Failures resolve to `hasBackdrop: false` → `cover`.\n const adaptiveActive = adaptiveBackdrop && layout !== 'intrinsic';\n const adaptiveResolved = !adaptiveActive || backdrop !== null;\n const effectiveObjectFit = adaptiveActive\n ? backdrop?.hasBackdrop\n ? 'contain'\n : 'cover'\n : objectFit;\n const effectiveImageMode = adaptiveActive\n ? backdrop?.hasBackdrop\n ? 'fit'\n : 'fill'\n : imageMode;\n const adaptiveBackgroundColor =\n adaptiveActive && backdrop?.hasBackdrop\n ? backdrop.backgroundColor\n : undefined;\n\n useEffect(() => {\n if (!adaptiveActive) {\n return;\n }\n setBackdrop(null);\n if (\n !effectiveFilename ||\n isFallback ||\n cachedFallbackUrl ||\n (isLowResResolvedAsset && fallbackOnLowRes)\n ) {\n // No analyzable primary source → behave like a busy scene (cover).\n setBackdrop({ hasBackdrop: false });\n return;\n }\n const token = { aborted: false };\n loadBackdropAnalysis(effectiveFilename, token).then((result) => {\n if (!token.aborted) {\n setBackdrop(result);\n }\n });\n return () => {\n token.aborted = true;\n };\n }, [\n adaptiveActive,\n effectiveFilename,\n isFallback,\n cachedFallbackUrl,\n isLowResResolvedAsset,\n fallbackOnLowRes,\n ]);\n\n useEffect(() => {\n setIsLoaded(false);\n setIsError(false);\n setIsFallback(false);\n setImageUrl('');\n }, [sourceCacheKey, fallbackOnLowRes]);\n\n useEffect(() => {\n if (!sourceCacheKey || !fallbackOnLowRes) {\n return;\n }\n\n if (isLowResResolvedAsset) {\n lowResFallbackCache.set(sourceCacheKey, fallbackOnLowRes);\n setIsFallback(true);\n setImageUrl(fallbackOnLowRes);\n return;\n }\n\n if (!cachedFallbackUrl) {\n return;\n }\n\n setIsFallback(true);\n setImageUrl(cachedFallbackUrl);\n }, [\n cachedFallbackUrl,\n fallbackOnLowRes,\n isLowResResolvedAsset,\n sourceCacheKey,\n ]);\n\n // For fill layout, measure container so we can request a resized Wix image.\n useEffect(() => {\n if (layout === 'intrinsic' || disableResize) {\n return;\n }\n const container = containerRef.current;\n if (!container) {\n return;\n }\n\n const updateDimensions = () => {\n const rect = container.getBoundingClientRect();\n if (rect.width > 0 && rect.height > 0) {\n setDimensions({\n width: Math.ceil(rect.width),\n height: Math.ceil(rect.height),\n });\n }\n };\n\n updateDimensions();\n\n if ('ResizeObserver' in window) {\n observerRef.current = new ResizeObserver(() => {\n updateDimensions();\n });\n observerRef.current.observe(container);\n }\n\n const handleResize = () => updateDimensions();\n window.addEventListener('resize', handleResize);\n\n return () => {\n if (observerRef.current) {\n observerRef.current.disconnect();\n }\n window.removeEventListener('resize', handleResize);\n };\n }, [disableResize, layout]);\n\n // Intrinsic layout: use normalized URL without resize logic.\n useEffect(() => {\n if (layout !== 'intrinsic') {\n return;\n }\n if (\n !effectiveFilename ||\n isFallback ||\n cachedFallbackUrl ||\n (isLowResResolvedAsset && fallbackOnLowRes)\n ) {\n return;\n }\n\n const normalizedUrl = normalizeImageUrl(effectiveFilename);\n setImageUrl(normalizedUrl);\n }, [\n cachedFallbackUrl,\n effectiveFilename,\n isFallback,\n isLowResResolvedAsset,\n layout,\n ]);\n\n // External non-Wix URLs skip resizing; use them immediately.\n useEffect(() => {\n if (layout === 'intrinsic') {\n return;\n }\n if (\n !effectiveFilename ||\n isFallback ||\n cachedFallbackUrl ||\n (isLowResResolvedAsset && fallbackOnLowRes)\n ) {\n return;\n }\n\n const normalizedUrl = normalizeImageUrl(effectiveFilename);\n const isExternalNonWixUrl =\n (normalizedUrl.startsWith('http://') ||\n normalizedUrl.startsWith('https://')) &&\n !normalizedUrl.includes('static.wixstatic.com');\n\n if (isExternalNonWixUrl) {\n setImageUrl(normalizedUrl);\n }\n }, [\n cachedFallbackUrl,\n effectiveFilename,\n isFallback,\n isLowResResolvedAsset,\n layout,\n ]);\n\n // Explicit opt-out: use original normalized URL even in fill layouts.\n useEffect(() => {\n if (layout === 'intrinsic') {\n return;\n }\n if (\n !disableResize ||\n !effectiveFilename ||\n isFallback ||\n cachedFallbackUrl ||\n (isLowResResolvedAsset && fallbackOnLowRes)\n ) {\n return;\n }\n\n setImageUrl(normalizeImageUrl(effectiveFilename));\n }, [\n cachedFallbackUrl,\n disableResize,\n effectiveFilename,\n isFallback,\n isLowResResolvedAsset,\n layout,\n ]);\n\n // Wix/local URLs: wait for dimensions, then build a resized URL.\n useEffect(() => {\n if (layout === 'intrinsic') {\n return;\n }\n if (disableResize) {\n return;\n }\n // Hold the fetch until adaptive analysis picks fit vs fill, so we request\n // the right CDN mode once instead of fetching twice and re-cropping.\n if (!adaptiveResolved) {\n return;\n }\n if (\n !dimensions ||\n !effectiveFilename ||\n isFallback ||\n cachedFallbackUrl ||\n (isLowResResolvedAsset && fallbackOnLowRes)\n ) {\n return;\n }\n\n const normalizedUrl = normalizeImageUrl(effectiveFilename);\n const isExternalNonWixUrl =\n (normalizedUrl.startsWith('http://') ||\n normalizedUrl.startsWith('https://')) &&\n !normalizedUrl.includes('static.wixstatic.com');\n\n if (isExternalNonWixUrl) {\n return;\n }\n\n let imageFilename = effectiveFilename;\n if (normalizedUrl.includes('static.wixstatic.com')) {\n const match = normalizedUrl.match(/media\\/([^/?]+)/);\n if (match && match[1]) {\n imageFilename = match[1];\n } else {\n setImageUrl(normalizedUrl);\n return;\n }\n } else if (\n normalizedUrl.startsWith('https://static.wixstatic.com/media/')\n ) {\n imageFilename = normalizedUrl.replace(\n 'https://static.wixstatic.com/media/',\n '',\n );\n }\n\n const dpr = window.devicePixelRatio ?? 1;\n const optimizedUrl = getResizedImageUrl(\n imageFilename,\n dimensions.width * dpr,\n dimensions.height * dpr,\n { quality, imageMode: effectiveImageMode },\n );\n setImageUrl(optimizedUrl);\n }, [\n dimensions,\n cachedFallbackUrl,\n effectiveFilename,\n isFallback,\n isLowResResolvedAsset,\n layout,\n disableResize,\n quality,\n effectiveImageMode,\n adaptiveResolved,\n ]);\n\n const handleImageLoad = (e: React.SyntheticEvent<HTMLImageElement>) => {\n const img = e.currentTarget;\n\n if (\n fallbackOnLowRes &&\n !isFallback &&\n !hasResolvedSourceDimensions &&\n (img.naturalWidth < lowResThreshold ||\n img.naturalHeight < lowResThreshold)\n ) {\n const originalImageUrl =\n img.currentSrc || imageUrl || effectiveFilename || sourceIdentifier;\n\n if (sourceCacheKey) {\n lowResFallbackCache.set(sourceCacheKey, fallbackOnLowRes);\n }\n\n setIsFallback(true);\n setImageUrl(fallbackOnLowRes);\n setIsLoaded(false);\n\n console.warn('OptimizedImage applied a low-res fallback image.', {\n originalImageUrl,\n fallbackImageUrl: fallbackOnLowRes,\n naturalWidth: img.naturalWidth,\n naturalHeight: img.naturalHeight,\n lowResThreshold,\n });\n\n deps.logContextualImage?.({\n imageUrl: fallbackOnLowRes,\n contextualTerm: contextualImageKey,\n imageEventType: 'web5_image_fallback',\n isImageResolved: true,\n isFallbackImage: true,\n });\n return;\n }\n\n setIsLoaded(true);\n onLoad?.();\n };\n\n const handleImageError = () => {\n setIsError(true);\n console.error('Failed to load image:', {\n source: sourceIdentifier,\n imageUrl,\n alt,\n });\n onError?.(new Error(`Failed to load image: ${sourceIdentifier}`));\n };\n\n const isTransparentPlaceholder = placeholderColor === 'transparent';\n const placeholderStyles = isTransparentPlaceholder\n ? {\n background: 'transparent',\n animation: 'none',\n }\n : {\n background: `linear-gradient(90deg, ${placeholderColor} 0%, #e5e7eb 50%, ${placeholderColor} 100%)`,\n backgroundSize: '200% 100%',\n animation: 'shimmer 2s infinite ease-in-out',\n };\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (onClick && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n onClick();\n }\n };\n\n return (\n <>\n <span\n ref={containerRef}\n className={[\n 'block',\n layout === 'intrinsic' ? '' : 'relative overflow-hidden',\n showDynamicBadge ? 'relative' : '',\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n style={\n layout === 'intrinsic'\n ? undefined\n : { minHeight: '1px', backgroundColor: adaptiveBackgroundColor }\n }\n onClick={clickable ? onClick : undefined}\n onKeyDown={clickable ? handleKeyDown : undefined}\n tabIndex={clickable ? 0 : undefined}\n role={clickable ? 'button' : undefined}\n aria-label={clickable ? alt : undefined}\n >\n {showDynamicBadge && (\n <span className=\"absolute left-2 top-2 z-10 rounded bg-blue-600/90 px-2 py-1 text-[10px] font-semibold tracking-wide text-white shadow block\">\n {contextualImageKey}\n </span>\n )}\n {!isLoaded && !isError && sourceIdentifier && (\n <span\n className=\"absolute inset-0 rounded block\"\n style={placeholderStyles}\n role=\"status\"\n aria-label=\"Loading image\"\n />\n )}\n\n {isError && (\n <span\n className=\"absolute inset-0 flex items-center justify-center bg-gray-100 text-gray-500 rounded block\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n <span className=\"text-center p-4 block\">\n <svg\n className=\"w-8 h-8 mx-auto mb-2 text-gray-400\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z\"\n />\n </svg>\n <span className=\"text-xs block\">Failed to load image</span>\n </span>\n </span>\n )}\n\n {imageUrl && !isError && (\n <img\n src={imageUrl}\n alt={alt}\n className={`${\n layout === 'intrinsic'\n ? 'w-full h-auto'\n : 'absolute inset-0 w-full h-full'\n } transition-opacity duration-300 ${\n isLoaded ? 'opacity-100' : 'opacity-0'\n } ${\n effectiveObjectFit === 'contain'\n ? 'object-contain'\n : effectiveObjectFit === 'cover'\n ? 'object-cover'\n : effectiveObjectFit === 'fill'\n ? 'object-fill'\n : effectiveObjectFit === 'none'\n ? 'object-none'\n : effectiveObjectFit === 'scale-down'\n ? 'object-scale-down'\n : ''\n }`}\n style={\n layout === 'intrinsic'\n ? {\n width: '100%',\n height: 'auto',\n maxWidth: '100%',\n display: 'block',\n }\n : {\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n objectFit: effectiveObjectFit,\n maxWidth: '100%',\n display: 'block',\n }\n }\n onLoad={handleImageLoad}\n onError={handleImageError}\n loading={imageUrl.startsWith('data:') ? 'eager' : 'lazy'}\n />\n )}\n </span>\n </>\n );\n});\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.entityHref = entityHref;
5
+ /**
6
+ * The url an entity card links to.
7
+ *
8
+ * Every entity surface was carrying its own copy of this rule — three of them
9
+ * byte-identical (`EntityProductListSection`, `EntityCollectionSection`,
10
+ * `ComparisonSection`), two more spelled inline (`EntityArticleListSection`,
11
+ * `HeroEntityImageSection`) — in every client bundle. It lives here for the
12
+ * same reason `formatProductPriceLabel` does (DL #218): every seed template
13
+ * externalizes `@wix/web5-core`, so the card, the hero and the comparison
14
+ * surface all get one implementation and no template needs a change.
15
+ *
16
+ * ## It picks; it does not rewrite
17
+ *
18
+ * Deciding WHICH url an item links to is a property of the item, and this
19
+ * knows the item. Deciding what ORIGIN that url should be on is a property of
20
+ * the surface — it needs the storefront the shopper is standing on and the set
21
+ * of origins that count as this site's — and this knows neither. That belongs
22
+ * to the link layer (`useWeb5Link().resolveUrl`), which has both.
23
+ *
24
+ * So the contract is one line: `resolveUrl(entityHref(item))`. One picker, one
25
+ * resolver, nothing in between. A second rewriter sitting between them is how
26
+ * you get two authorities on the same href fighting over it.
27
+ */
28
+
29
+ /** An entity reference that never resolved — linking it navigates nowhere. */
30
+ const UNRESOLVED_SCHEME = 'web5://';
31
+
32
+ /**
33
+ * The url an entity links to, or `undefined` when it has none worth linking.
34
+ *
35
+ * `data.url` is the resolved catalog url and wins: it is the row the turn sent,
36
+ * so on a variant question it is the matched child's url — the one carrying
37
+ * `?variant=` (DL #216). `entityUrl` is what parsing recovered from the
38
+ * markdown link and is the fallback for an item resolution never reached.
39
+ *
40
+ * A `web5://` url means the entity resolved to nothing. The caller renders the
41
+ * card unlinked rather than linking a scheme the browser cannot follow — which
42
+ * is what every copy of this rule already did, and worth keeping central so it
43
+ * cannot drift on one surface.
44
+ */
45
+ function entityHref(item) {
46
+ var _item$data;
47
+ const url = ((_item$data = item.data) == null ? void 0 : _item$data.url) || item.entityUrl || undefined;
48
+ if (!url || url.startsWith(UNRESOLVED_SCHEME)) {
49
+ return undefined;
50
+ }
51
+ return url;
52
+ }
53
+ //# sourceMappingURL=entityHref.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["UNRESOLVED_SCHEME","entityHref","item","_item$data","url","data","entityUrl","undefined","startsWith"],"sources":["../../../src/entity/entityHref.ts"],"sourcesContent":["/**\n * The url an entity card links to.\n *\n * Every entity surface was carrying its own copy of this rule — three of them\n * byte-identical (`EntityProductListSection`, `EntityCollectionSection`,\n * `ComparisonSection`), two more spelled inline (`EntityArticleListSection`,\n * `HeroEntityImageSection`) — in every client bundle. It lives here for the\n * same reason `formatProductPriceLabel` does (DL #218): every seed template\n * externalizes `@wix/web5-core`, so the card, the hero and the comparison\n * surface all get one implementation and no template needs a change.\n *\n * ## It picks; it does not rewrite\n *\n * Deciding WHICH url an item links to is a property of the item, and this\n * knows the item. Deciding what ORIGIN that url should be on is a property of\n * the surface — it needs the storefront the shopper is standing on and the set\n * of origins that count as this site's — and this knows neither. That belongs\n * to the link layer (`useWeb5Link().resolveUrl`), which has both.\n *\n * So the contract is one line: `resolveUrl(entityHref(item))`. One picker, one\n * resolver, nothing in between. A second rewriter sitting between them is how\n * you get two authorities on the same href fighting over it.\n */\nimport type { EntityItem } from '../component/types';\n\n/** An entity reference that never resolved — linking it navigates nowhere. */\nconst UNRESOLVED_SCHEME = 'web5://';\n\n/**\n * The url an entity links to, or `undefined` when it has none worth linking.\n *\n * `data.url` is the resolved catalog url and wins: it is the row the turn sent,\n * so on a variant question it is the matched child's url — the one carrying\n * `?variant=` (DL #216). `entityUrl` is what parsing recovered from the\n * markdown link and is the fallback for an item resolution never reached.\n *\n * A `web5://` url means the entity resolved to nothing. The caller renders the\n * card unlinked rather than linking a scheme the browser cannot follow — which\n * is what every copy of this rule already did, and worth keeping central so it\n * cannot drift on one surface.\n */\nexport function entityHref(item: EntityItem): string | undefined {\n const url = item.data?.url || item.entityUrl || undefined;\n if (!url || url.startsWith(UNRESOLVED_SCHEME)) {\n return undefined;\n }\n return url;\n}\n"],"mappings":";;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAGA;AACA,MAAMA,iBAAiB,GAAG,SAAS;;AAEnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,UAAUA,CAACC,IAAgB,EAAsB;EAAA,IAAAC,UAAA;EAC/D,MAAMC,GAAG,GAAG,EAAAD,UAAA,GAAAD,IAAI,CAACG,IAAI,qBAATF,UAAA,CAAWC,GAAG,KAAIF,IAAI,CAACI,SAAS,IAAIC,SAAS;EACzD,IAAI,CAACH,GAAG,IAAIA,GAAG,CAACI,UAAU,CAACR,iBAAiB,CAAC,EAAE;IAC7C,OAAOO,SAAS;EAClB;EACA,OAAOH,GAAG;AACZ","ignoreList":[]}
@@ -3,6 +3,56 @@
3
3
  exports.__esModule = true;
4
4
  exports.entityPayloadFromItems = entityPayloadFromItems;
5
5
  exports.normalizeEntityItem = normalizeEntityItem;
6
+ exports.toCatalogPath = toCatalogPath;
7
+ /**
8
+ * A catalog url reduced to `path + query + hash`, so it resolves against the
9
+ * storefront the shopper is actually on.
10
+ *
11
+ * A site's index stores each entity's url from the mapping schema's
12
+ * `payload.url` template, and a live site writes that template ABSOLUTE —
13
+ * `https://www.smallflower.com/products/{handle}`. A demo, staging or clone
14
+ * store serves the same catalog from a different origin, so rendered as
15
+ * indexed, every product link in an answer walks the shopper off the store
16
+ * they are on and onto the canonical one — a different cart, a different
17
+ * inventory, a different checkout.
18
+ *
19
+ * The quieter half is worse. `useWeb5Link.appendWeb5Id` classifies such a url
20
+ * as external and, by design, refuses to stamp `?web5_id=` on an external
21
+ * link, so the destination page never learns which conversation sent the
22
+ * shopper there and every warm-guarded placement on it stays inert.
23
+ *
24
+ * The origin is the one thing in the row the index cannot know and the client
25
+ * can: an entity url names a resource in THIS site's catalog, and the catalog
26
+ * is served by the storefront the page is running on. So the path is
27
+ * authoritative and the origin is advisory. `linkConfig.baseUrl` remains the
28
+ * escape hatch — a client that means its links to leave the current origin
29
+ * says so there, and `resolveRelativeUrl` puts that base back on.
30
+ *
31
+ * Only `url` is reduced. Images legitimately live on another origin
32
+ * (`cdn.shopify.com`), and `img` is left exactly as indexed.
33
+ *
34
+ * This is the client's half. The mapping schema is where it should be
35
+ * corrected — the reference schema in `web5-collection-mapping/schema/
36
+ * examples/ecom-site.schema.json` already ships the right shape
37
+ * (`{"template": "/products/{handle}"}`) — and a site whose schema is already
38
+ * relative passes through here untouched, so the two do not fight.
39
+ */
40
+ function toCatalogPath(url) {
41
+ // Not absolute http(s): a root-relative path is already right, and a
42
+ // `mailto:`/`web5://`/protocol-relative url is not a catalog path at all.
43
+ if (!/^https?:\/\//i.test(url)) {
44
+ return url;
45
+ }
46
+ try {
47
+ const parsed = new URL(url);
48
+ // `?variant=…` is exactly how a resolved variant travels (DL #216), and
49
+ // the hash can carry an anchor the answer meant — both survive.
50
+ return parsed.pathname + parsed.search + parsed.hash;
51
+ } catch {
52
+ return url;
53
+ }
54
+ }
55
+
6
56
  /**
7
57
  * One entity row, normalized onto the `ApiPayloadItem` shape both resolution
8
58
  * paths key off.
@@ -33,15 +83,19 @@ function normalizeEntityItem(raw) {
33
83
  }
34
84
 
35
85
  // Rows travel as-is apart from the `doc_id` → `id` alias every consumer keys
36
- // off, and the image alias below.
86
+ // off, the origin reduction below, and the image alias after it.
37
87
  //
38
- // `url` is deliberately NOT rewritten `?variant=…` is exactly how a
39
- // resolved variant travels, and rebuilding the path from `handle` would
40
- // throw it away.
88
+ // The url is never REBUILTrebuilding the path from `handle` would throw
89
+ // away the `?variant=…` that is exactly how a resolved variant travels.
90
+ // `toCatalogPath` only drops the origin the index stamped; path, query and
91
+ // hash are carried over verbatim.
41
92
  const normalized = {
42
93
  ...rec,
43
94
  id
44
95
  };
96
+ if (typeof rec.url === 'string' && rec.url) {
97
+ normalized.url = toCatalogPath(rec.url);
98
+ }
45
99
 
46
100
  // Product rows carry the image as `thumbnail` / `images[]` (the Vespa doc
47
101
  // shape), but the shared transform (`transformToGenericEntityData`) reads
@@ -1 +1 @@
1
- {"version":3,"names":["normalizeEntityItem","raw","Array","isArray","rec","docId","doc_id","ownId","id","normalized","img","thumbnail","images","entityPayloadFromItems","container","items","payload","item","push"],"sources":["../../../src/entity/entityPayload.ts"],"sourcesContent":["import type { ApiPayloadItem } from '../types/entity';\n\n/**\n * One entity row, normalized onto the `ApiPayloadItem` shape both resolution\n * paths key off.\n *\n * Two producers, one document. `list-items` answers with the raw retrieval\n * document; the turn answers with the engine's allowlisted projection of the\n * SAME document — same field names, plus the keys only a card reads (`type`,\n * `variantId`, and the matched child's `url`/`img`/`price` already overlaid).\n * Normalizing both here is what lets `findEntityInPayload` resolve a reference\n * without caring which one answered.\n *\n * `id` is what a `web5://entity/<type>/<id>` reference resolves against, and\n * the reference carries the DOCUMENT id — so `doc_id` becomes `id`, exactly as\n * the `list-items` path has always done. The fallback to a row's own `id` is\n * for the day a store publishes one (none does today); a row with neither has\n * nothing to be keyed by and is dropped.\n */\nexport function normalizeEntityItem(raw: unknown): ApiPayloadItem | null {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n return null;\n }\n const rec = raw as Record<string, unknown>;\n const docId = typeof rec.doc_id === 'string' ? rec.doc_id : '';\n const ownId = typeof rec.id === 'string' ? rec.id : '';\n const id = docId || ownId;\n if (!id) {\n return null;\n }\n\n // Rows travel as-is apart from the `doc_id` → `id` alias every consumer keys\n // off, and the image alias below.\n //\n // `url` is deliberately NOT rewritten — `?variant=…` is exactly how a\n // resolved variant travels, and rebuilding the path from `handle` would\n // throw it away.\n const normalized: Record<string, unknown> = { ...rec, id };\n\n // Product rows carry the image as `thumbnail` / `images[]` (the Vespa doc\n // shape), but the shared transform (`transformToGenericEntityData`) reads\n // `img`. Alias it so product cards keep their image.\n //\n // A bridge, not a contract: a row that already carries `img` — a CMS doc, or\n // one where retrieval overlaid a matched child's presentation fields — passes\n // through untouched. Drop the alias once every producer emits `img`.\n if (normalized.img == null) {\n if (typeof rec.thumbnail === 'string' && rec.thumbnail) {\n normalized.img = rec.thumbnail;\n } else if (\n Array.isArray(rec.images) &&\n typeof rec.images[0] === 'string' &&\n rec.images[0]\n ) {\n normalized.img = rec.images[0];\n }\n }\n\n return normalized as unknown as ApiPayloadItem;\n}\n\n/**\n * Read an `{ items: [...] }` container into a normalized payload.\n *\n * Both carriers of the turn's resolved entities use that shape: the live\n * stream's `entities` frame (`TurnEntities.items`) and the persisted\n * `additional_data[\"documents\"]` the reload path reads back. A bare array is\n * accepted too, so a caller that already unwrapped one can pass it straight in.\n *\n * Anything that isn't a keyable row is dropped rather than passed on — a\n * payload entry with no id can only ever fail to match.\n */\nexport function entityPayloadFromItems(container: unknown): ApiPayloadItem[] {\n let items: unknown;\n if (Array.isArray(container)) {\n items = container;\n } else if (container && typeof container === 'object') {\n items = (container as { items?: unknown }).items;\n }\n if (!Array.isArray(items)) {\n return [];\n }\n\n const payload: ApiPayloadItem[] = [];\n for (const item of items) {\n const normalized = normalizeEntityItem(item);\n if (normalized) {\n payload.push(normalized);\n }\n }\n return payload;\n}\n"],"mappings":";;;;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,mBAAmBA,CAACC,GAAY,EAAyB;EACvE,IAAI,CAACA,GAAG,IAAI,OAAOA,GAAG,KAAK,QAAQ,IAAIC,KAAK,CAACC,OAAO,CAACF,GAAG,CAAC,EAAE;IACzD,OAAO,IAAI;EACb;EACA,MAAMG,GAAG,GAAGH,GAA8B;EAC1C,MAAMI,KAAK,GAAG,OAAOD,GAAG,CAACE,MAAM,KAAK,QAAQ,GAAGF,GAAG,CAACE,MAAM,GAAG,EAAE;EAC9D,MAAMC,KAAK,GAAG,OAAOH,GAAG,CAACI,EAAE,KAAK,QAAQ,GAAGJ,GAAG,CAACI,EAAE,GAAG,EAAE;EACtD,MAAMA,EAAE,GAAGH,KAAK,IAAIE,KAAK;EACzB,IAAI,CAACC,EAAE,EAAE;IACP,OAAO,IAAI;EACb;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMC,UAAmC,GAAG;IAAE,GAAGL,GAAG;IAAEI;EAAG,CAAC;;EAE1D;EACA;EACA;EACA;EACA;EACA;EACA;EACA,IAAIC,UAAU,CAACC,GAAG,IAAI,IAAI,EAAE;IAC1B,IAAI,OAAON,GAAG,CAACO,SAAS,KAAK,QAAQ,IAAIP,GAAG,CAACO,SAAS,EAAE;MACtDF,UAAU,CAACC,GAAG,GAAGN,GAAG,CAACO,SAAS;IAChC,CAAC,MAAM,IACLT,KAAK,CAACC,OAAO,CAACC,GAAG,CAACQ,MAAM,CAAC,IACzB,OAAOR,GAAG,CAACQ,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ,IACjCR,GAAG,CAACQ,MAAM,CAAC,CAAC,CAAC,EACb;MACAH,UAAU,CAACC,GAAG,GAAGN,GAAG,CAACQ,MAAM,CAAC,CAAC,CAAC;IAChC;EACF;EAEA,OAAOH,UAAU;AACnB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASI,sBAAsBA,CAACC,SAAkB,EAAoB;EAC3E,IAAIC,KAAc;EAClB,IAAIb,KAAK,CAACC,OAAO,CAACW,SAAS,CAAC,EAAE;IAC5BC,KAAK,GAAGD,SAAS;EACnB,CAAC,MAAM,IAAIA,SAAS,IAAI,OAAOA,SAAS,KAAK,QAAQ,EAAE;IACrDC,KAAK,GAAID,SAAS,CAAyBC,KAAK;EAClD;EACA,IAAI,CAACb,KAAK,CAACC,OAAO,CAACY,KAAK,CAAC,EAAE;IACzB,OAAO,EAAE;EACX;EAEA,MAAMC,OAAyB,GAAG,EAAE;EACpC,KAAK,MAAMC,IAAI,IAAIF,KAAK,EAAE;IACxB,MAAMN,UAAU,GAAGT,mBAAmB,CAACiB,IAAI,CAAC;IAC5C,IAAIR,UAAU,EAAE;MACdO,OAAO,CAACE,IAAI,CAACT,UAAU,CAAC;IAC1B;EACF;EACA,OAAOO,OAAO;AAChB","ignoreList":[]}
1
+ {"version":3,"names":["toCatalogPath","url","test","parsed","URL","pathname","search","hash","normalizeEntityItem","raw","Array","isArray","rec","docId","doc_id","ownId","id","normalized","img","thumbnail","images","entityPayloadFromItems","container","items","payload","item","push"],"sources":["../../../src/entity/entityPayload.ts"],"sourcesContent":["import type { ApiPayloadItem } from '../types/entity';\n\n/**\n * A catalog url reduced to `path + query + hash`, so it resolves against the\n * storefront the shopper is actually on.\n *\n * A site's index stores each entity's url from the mapping schema's\n * `payload.url` template, and a live site writes that template ABSOLUTE —\n * `https://www.smallflower.com/products/{handle}`. A demo, staging or clone\n * store serves the same catalog from a different origin, so rendered as\n * indexed, every product link in an answer walks the shopper off the store\n * they are on and onto the canonical one — a different cart, a different\n * inventory, a different checkout.\n *\n * The quieter half is worse. `useWeb5Link.appendWeb5Id` classifies such a url\n * as external and, by design, refuses to stamp `?web5_id=` on an external\n * link, so the destination page never learns which conversation sent the\n * shopper there and every warm-guarded placement on it stays inert.\n *\n * The origin is the one thing in the row the index cannot know and the client\n * can: an entity url names a resource in THIS site's catalog, and the catalog\n * is served by the storefront the page is running on. So the path is\n * authoritative and the origin is advisory. `linkConfig.baseUrl` remains the\n * escape hatch — a client that means its links to leave the current origin\n * says so there, and `resolveRelativeUrl` puts that base back on.\n *\n * Only `url` is reduced. Images legitimately live on another origin\n * (`cdn.shopify.com`), and `img` is left exactly as indexed.\n *\n * This is the client's half. The mapping schema is where it should be\n * corrected — the reference schema in `web5-collection-mapping/schema/\n * examples/ecom-site.schema.json` already ships the right shape\n * (`{\"template\": \"/products/{handle}\"}`) — and a site whose schema is already\n * relative passes through here untouched, so the two do not fight.\n */\nexport function toCatalogPath(url: string): string {\n // Not absolute http(s): a root-relative path is already right, and a\n // `mailto:`/`web5://`/protocol-relative url is not a catalog path at all.\n if (!/^https?:\\/\\//i.test(url)) {\n return url;\n }\n try {\n const parsed = new URL(url);\n // `?variant=…` is exactly how a resolved variant travels (DL #216), and\n // the hash can carry an anchor the answer meant — both survive.\n return parsed.pathname + parsed.search + parsed.hash;\n } catch {\n return url;\n }\n}\n\n/**\n * One entity row, normalized onto the `ApiPayloadItem` shape both resolution\n * paths key off.\n *\n * Two producers, one document. `list-items` answers with the raw retrieval\n * document; the turn answers with the engine's allowlisted projection of the\n * SAME document — same field names, plus the keys only a card reads (`type`,\n * `variantId`, and the matched child's `url`/`img`/`price` already overlaid).\n * Normalizing both here is what lets `findEntityInPayload` resolve a reference\n * without caring which one answered.\n *\n * `id` is what a `web5://entity/<type>/<id>` reference resolves against, and\n * the reference carries the DOCUMENT id — so `doc_id` becomes `id`, exactly as\n * the `list-items` path has always done. The fallback to a row's own `id` is\n * for the day a store publishes one (none does today); a row with neither has\n * nothing to be keyed by and is dropped.\n */\nexport function normalizeEntityItem(raw: unknown): ApiPayloadItem | null {\n if (!raw || typeof raw !== 'object' || Array.isArray(raw)) {\n return null;\n }\n const rec = raw as Record<string, unknown>;\n const docId = typeof rec.doc_id === 'string' ? rec.doc_id : '';\n const ownId = typeof rec.id === 'string' ? rec.id : '';\n const id = docId || ownId;\n if (!id) {\n return null;\n }\n\n // Rows travel as-is apart from the `doc_id` → `id` alias every consumer keys\n // off, the origin reduction below, and the image alias after it.\n //\n // The url is never REBUILTrebuilding the path from `handle` would throw\n // away the `?variant=…` that is exactly how a resolved variant travels.\n // `toCatalogPath` only drops the origin the index stamped; path, query and\n // hash are carried over verbatim.\n const normalized: Record<string, unknown> = { ...rec, id };\n\n if (typeof rec.url === 'string' && rec.url) {\n normalized.url = toCatalogPath(rec.url);\n }\n\n // Product rows carry the image as `thumbnail` / `images[]` (the Vespa doc\n // shape), but the shared transform (`transformToGenericEntityData`) reads\n // `img`. Alias it so product cards keep their image.\n //\n // A bridge, not a contract: a row that already carries `img` — a CMS doc, or\n // one where retrieval overlaid a matched child's presentation fields — passes\n // through untouched. Drop the alias once every producer emits `img`.\n if (normalized.img == null) {\n if (typeof rec.thumbnail === 'string' && rec.thumbnail) {\n normalized.img = rec.thumbnail;\n } else if (\n Array.isArray(rec.images) &&\n typeof rec.images[0] === 'string' &&\n rec.images[0]\n ) {\n normalized.img = rec.images[0];\n }\n }\n\n return normalized as unknown as ApiPayloadItem;\n}\n\n/**\n * Read an `{ items: [...] }` container into a normalized payload.\n *\n * Both carriers of the turn's resolved entities use that shape: the live\n * stream's `entities` frame (`TurnEntities.items`) and the persisted\n * `additional_data[\"documents\"]` the reload path reads back. A bare array is\n * accepted too, so a caller that already unwrapped one can pass it straight in.\n *\n * Anything that isn't a keyable row is dropped rather than passed on — a\n * payload entry with no id can only ever fail to match.\n */\nexport function entityPayloadFromItems(container: unknown): ApiPayloadItem[] {\n let items: unknown;\n if (Array.isArray(container)) {\n items = container;\n } else if (container && typeof container === 'object') {\n items = (container as { items?: unknown }).items;\n }\n if (!Array.isArray(items)) {\n return [];\n }\n\n const payload: ApiPayloadItem[] = [];\n for (const item of items) {\n const normalized = normalizeEntityItem(item);\n if (normalized) {\n payload.push(normalized);\n }\n }\n return payload;\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
- exports.formatProductPriceLabel = exports.formatPriceField = exports.formatMoney = exports.fetchEntityListData = exports.entityPayloadFromItems = exports.enrichEntitiesFromPayload = exports.LIST_ITEMS_ENDPOINT = void 0;
4
+ exports.formatProductPriceLabel = exports.formatPriceField = exports.formatMoney = exports.fetchEntityListData = exports.entityPayloadFromItems = exports.entityHref = exports.enrichEntitiesFromPayload = exports.LIST_ITEMS_ENDPOINT = void 0;
5
5
  exports.getEntityExtractor = getEntityExtractor;
6
6
  exports.readCurrencyCode = exports.normalizeEntityItem = exports.mergeEntityData = exports.listEntityItems = exports.isProductFamilyEntityType = void 0;
7
7
  exports.registerEntityExtractor = registerEntityExtractor;
8
- exports.transformToSolutionEntityData = exports.transformToGenericEntityData = exports.transformToBlogPostEntityData = exports.toMatchedOptions = void 0;
8
+ exports.transformToSolutionEntityData = exports.transformToGenericEntityData = exports.transformToBlogPostEntityData = exports.toMatchedOptions = exports.toCatalogPath = void 0;
9
9
  var _defaultExtractor = require("./defaultExtractor");
10
10
  exports.defaultExtractor = _defaultExtractor.defaultExtractor;
11
11
  exports.transformToSolutionEntityData = _defaultExtractor.transformToSolutionEntityData;
@@ -13,9 +13,12 @@ exports.transformToBlogPostEntityData = _defaultExtractor.transformToBlogPostEnt
13
13
  exports.transformToGenericEntityData = _defaultExtractor.transformToGenericEntityData;
14
14
  var _enrichEntitiesFromPayload = require("./enrichEntitiesFromPayload");
15
15
  exports.enrichEntitiesFromPayload = _enrichEntitiesFromPayload.enrichEntitiesFromPayload;
16
+ var _entityHref = require("./entityHref");
17
+ exports.entityHref = _entityHref.entityHref;
16
18
  var _entityPayload = require("./entityPayload");
17
19
  exports.normalizeEntityItem = _entityPayload.normalizeEntityItem;
18
20
  exports.entityPayloadFromItems = _entityPayload.entityPayloadFromItems;
21
+ exports.toCatalogPath = _entityPayload.toCatalogPath;
19
22
  var _entityFamily = require("./entityFamily");
20
23
  exports.isProductFamilyEntityType = _entityFamily.isProductFamilyEntityType;
21
24
  var _mergeEntityData = require("./mergeEntityData");
@@ -1 +1 @@
1
- {"version":3,"names":["_defaultExtractor","require","exports","defaultExtractor","transformToSolutionEntityData","transformToBlogPostEntityData","transformToGenericEntityData","_enrichEntitiesFromPayload","enrichEntitiesFromPayload","_entityPayload","normalizeEntityItem","entityPayloadFromItems","_entityFamily","isProductFamilyEntityType","_mergeEntityData","mergeEntityData","_matchedVariant","toMatchedOptions","formatMoney","readCurrencyCode","formatPriceField","formatProductPriceLabel","_fetchEntityListData","fetchEntityListData","_listEntityItems","listEntityItems","LIST_ITEMS_ENDPOINT","extractorRegistry","getEntityExtractor","clientId","registerEntityExtractor","extractor"],"sources":["../../../src/entity/index.ts"],"sourcesContent":["import type { EntityExtractor } from './types';\nimport { defaultExtractor } from './defaultExtractor';\n\nexport {\n defaultExtractor,\n transformToSolutionEntityData,\n transformToBlogPostEntityData,\n transformToGenericEntityData,\n} from './defaultExtractor';\n\nexport { enrichEntitiesFromPayload } from './enrichEntitiesFromPayload';\nexport { normalizeEntityItem, entityPayloadFromItems } from './entityPayload';\nexport { isProductFamilyEntityType } from './entityFamily';\nexport { mergeEntityData } from './mergeEntityData';\nexport {\n toMatchedOptions,\n formatMoney,\n readCurrencyCode,\n formatPriceField,\n formatProductPriceLabel,\n type MatchedOption,\n type ProductPriceFields,\n} from './matchedVariant';\nexport {\n fetchEntityListData,\n type FetchEntityListDataOptions,\n} from './fetchEntityListData';\nexport {\n listEntityItems,\n LIST_ITEMS_ENDPOINT,\n type ListEntityItemsOptions,\n} from './listEntityItems';\n\nexport type { EntityExtractor } from './types';\n\n/**\n * Registry of client-specific entity extractors.\n * Only needed if a client requires custom extraction logic beyond the config-driven default.\n */\nconst extractorRegistry: Record<string, EntityExtractor> = {};\n\n/**\n * Get the entity extractor for a specific client.\n * The default extractor is config-driven and works for any client with entityConfig.\n */\nexport function getEntityExtractor(clientId?: string): EntityExtractor {\n if (clientId && extractorRegistry[clientId]) {\n return extractorRegistry[clientId];\n }\n return defaultExtractor;\n}\n\n/**\n * Register a custom entity extractor for a client\n * Useful for runtime registration or testing\n */\nexport function registerEntityExtractor(\n clientId: string,\n extractor: EntityExtractor,\n): void {\n extractorRegistry[clientId] = extractor;\n}\n"],"mappings":";;;;;;;;AACA,IAAAA,iBAAA,GAAAC,OAAA;AAAsDC,OAAA,CAAAC,gBAAA,GAAAH,iBAAA,CAAAG,gBAAA;AAAAD,OAAA,CAAAE,6BAAA,GAAAJ,iBAAA,CAAAI,6BAAA;AAAAF,OAAA,CAAAG,6BAAA,GAAAL,iBAAA,CAAAK,6BAAA;AAAAH,OAAA,CAAAI,4BAAA,GAAAN,iBAAA,CAAAM,4BAAA;AAStD,IAAAC,0BAAA,GAAAN,OAAA;AAAwEC,OAAA,CAAAM,yBAAA,GAAAD,0BAAA,CAAAC,yBAAA;AACxE,IAAAC,cAAA,GAAAR,OAAA;AAA8EC,OAAA,CAAAQ,mBAAA,GAAAD,cAAA,CAAAC,mBAAA;AAAAR,OAAA,CAAAS,sBAAA,GAAAF,cAAA,CAAAE,sBAAA;AAC9E,IAAAC,aAAA,GAAAX,OAAA;AAA2DC,OAAA,CAAAW,yBAAA,GAAAD,aAAA,CAAAC,yBAAA;AAC3D,IAAAC,gBAAA,GAAAb,OAAA;AAAoDC,OAAA,CAAAa,eAAA,GAAAD,gBAAA,CAAAC,eAAA;AACpD,IAAAC,eAAA,GAAAf,OAAA;AAQ0BC,OAAA,CAAAe,gBAAA,GAAAD,eAAA,CAAAC,gBAAA;AAAAf,OAAA,CAAAgB,WAAA,GAAAF,eAAA,CAAAE,WAAA;AAAAhB,OAAA,CAAAiB,gBAAA,GAAAH,eAAA,CAAAG,gBAAA;AAAAjB,OAAA,CAAAkB,gBAAA,GAAAJ,eAAA,CAAAI,gBAAA;AAAAlB,OAAA,CAAAmB,uBAAA,GAAAL,eAAA,CAAAK,uBAAA;AAC1B,IAAAC,oBAAA,GAAArB,OAAA;AAG+BC,OAAA,CAAAqB,mBAAA,GAAAD,oBAAA,CAAAC,mBAAA;AAC/B,IAAAC,gBAAA,GAAAvB,OAAA;AAI2BC,OAAA,CAAAuB,eAAA,GAAAD,gBAAA,CAAAC,eAAA;AAAAvB,OAAA,CAAAwB,mBAAA,GAAAF,gBAAA,CAAAE,mBAAA;AAI3B;AACA;AACA;AACA;AACA,MAAMC,iBAAkD,GAAG,CAAC,CAAC;;AAE7D;AACA;AACA;AACA;AACO,SAASC,kBAAkBA,CAACC,QAAiB,EAAmB;EACrE,IAAIA,QAAQ,IAAIF,iBAAiB,CAACE,QAAQ,CAAC,EAAE;IAC3C,OAAOF,iBAAiB,CAACE,QAAQ,CAAC;EACpC;EACA,OAAO1B,kCAAgB;AACzB;;AAEA;AACA;AACA;AACA;AACO,SAAS2B,uBAAuBA,CACrCD,QAAgB,EAChBE,SAA0B,EACpB;EACNJ,iBAAiB,CAACE,QAAQ,CAAC,GAAGE,SAAS;AACzC","ignoreList":[]}
1
+ {"version":3,"names":["_defaultExtractor","require","exports","defaultExtractor","transformToSolutionEntityData","transformToBlogPostEntityData","transformToGenericEntityData","_enrichEntitiesFromPayload","enrichEntitiesFromPayload","_entityHref","entityHref","_entityPayload","normalizeEntityItem","entityPayloadFromItems","toCatalogPath","_entityFamily","isProductFamilyEntityType","_mergeEntityData","mergeEntityData","_matchedVariant","toMatchedOptions","formatMoney","readCurrencyCode","formatPriceField","formatProductPriceLabel","_fetchEntityListData","fetchEntityListData","_listEntityItems","listEntityItems","LIST_ITEMS_ENDPOINT","extractorRegistry","getEntityExtractor","clientId","registerEntityExtractor","extractor"],"sources":["../../../src/entity/index.ts"],"sourcesContent":["import type { EntityExtractor } from './types';\nimport { defaultExtractor } from './defaultExtractor';\n\nexport {\n defaultExtractor,\n transformToSolutionEntityData,\n transformToBlogPostEntityData,\n transformToGenericEntityData,\n} from './defaultExtractor';\n\nexport { enrichEntitiesFromPayload } from './enrichEntitiesFromPayload';\nexport { entityHref } from './entityHref';\nexport {\n normalizeEntityItem,\n entityPayloadFromItems,\n toCatalogPath,\n} from './entityPayload';\nexport { isProductFamilyEntityType } from './entityFamily';\nexport { mergeEntityData } from './mergeEntityData';\nexport {\n toMatchedOptions,\n formatMoney,\n readCurrencyCode,\n formatPriceField,\n formatProductPriceLabel,\n type MatchedOption,\n type ProductPriceFields,\n} from './matchedVariant';\nexport {\n fetchEntityListData,\n type FetchEntityListDataOptions,\n} from './fetchEntityListData';\nexport {\n listEntityItems,\n LIST_ITEMS_ENDPOINT,\n type ListEntityItemsOptions,\n} from './listEntityItems';\n\nexport type { EntityExtractor } from './types';\n\n/**\n * Registry of client-specific entity extractors.\n * Only needed if a client requires custom extraction logic beyond the config-driven default.\n */\nconst extractorRegistry: Record<string, EntityExtractor> = {};\n\n/**\n * Get the entity extractor for a specific client.\n * The default extractor is config-driven and works for any client with entityConfig.\n */\nexport function getEntityExtractor(clientId?: string): EntityExtractor {\n if (clientId && extractorRegistry[clientId]) {\n return extractorRegistry[clientId];\n }\n return defaultExtractor;\n}\n\n/**\n * Register a custom entity extractor for a client\n * Useful for runtime registration or testing\n */\nexport function registerEntityExtractor(\n clientId: string,\n extractor: EntityExtractor,\n): void {\n extractorRegistry[clientId] = extractor;\n}\n"],"mappings":";;;;;;;;AACA,IAAAA,iBAAA,GAAAC,OAAA;AAAsDC,OAAA,CAAAC,gBAAA,GAAAH,iBAAA,CAAAG,gBAAA;AAAAD,OAAA,CAAAE,6BAAA,GAAAJ,iBAAA,CAAAI,6BAAA;AAAAF,OAAA,CAAAG,6BAAA,GAAAL,iBAAA,CAAAK,6BAAA;AAAAH,OAAA,CAAAI,4BAAA,GAAAN,iBAAA,CAAAM,4BAAA;AAStD,IAAAC,0BAAA,GAAAN,OAAA;AAAwEC,OAAA,CAAAM,yBAAA,GAAAD,0BAAA,CAAAC,yBAAA;AACxE,IAAAC,WAAA,GAAAR,OAAA;AAA0CC,OAAA,CAAAQ,UAAA,GAAAD,WAAA,CAAAC,UAAA;AAC1C,IAAAC,cAAA,GAAAV,OAAA;AAIyBC,OAAA,CAAAU,mBAAA,GAAAD,cAAA,CAAAC,mBAAA;AAAAV,OAAA,CAAAW,sBAAA,GAAAF,cAAA,CAAAE,sBAAA;AAAAX,OAAA,CAAAY,aAAA,GAAAH,cAAA,CAAAG,aAAA;AACzB,IAAAC,aAAA,GAAAd,OAAA;AAA2DC,OAAA,CAAAc,yBAAA,GAAAD,aAAA,CAAAC,yBAAA;AAC3D,IAAAC,gBAAA,GAAAhB,OAAA;AAAoDC,OAAA,CAAAgB,eAAA,GAAAD,gBAAA,CAAAC,eAAA;AACpD,IAAAC,eAAA,GAAAlB,OAAA;AAQ0BC,OAAA,CAAAkB,gBAAA,GAAAD,eAAA,CAAAC,gBAAA;AAAAlB,OAAA,CAAAmB,WAAA,GAAAF,eAAA,CAAAE,WAAA;AAAAnB,OAAA,CAAAoB,gBAAA,GAAAH,eAAA,CAAAG,gBAAA;AAAApB,OAAA,CAAAqB,gBAAA,GAAAJ,eAAA,CAAAI,gBAAA;AAAArB,OAAA,CAAAsB,uBAAA,GAAAL,eAAA,CAAAK,uBAAA;AAC1B,IAAAC,oBAAA,GAAAxB,OAAA;AAG+BC,OAAA,CAAAwB,mBAAA,GAAAD,oBAAA,CAAAC,mBAAA;AAC/B,IAAAC,gBAAA,GAAA1B,OAAA;AAI2BC,OAAA,CAAA0B,eAAA,GAAAD,gBAAA,CAAAC,eAAA;AAAA1B,OAAA,CAAA2B,mBAAA,GAAAF,gBAAA,CAAAE,mBAAA;AAI3B;AACA;AACA;AACA;AACA,MAAMC,iBAAkD,GAAG,CAAC,CAAC;;AAE7D;AACA;AACA;AACA;AACO,SAASC,kBAAkBA,CAACC,QAAiB,EAAmB;EACrE,IAAIA,QAAQ,IAAIF,iBAAiB,CAACE,QAAQ,CAAC,EAAE;IAC3C,OAAOF,iBAAiB,CAACE,QAAQ,CAAC;EACpC;EACA,OAAO7B,kCAAgB;AACzB;;AAEA;AACA;AACA;AACA;AACO,SAAS8B,uBAAuBA,CACrCD,QAAgB,EAChBE,SAA0B,EACpB;EACNJ,iBAAiB,CAACE,QAAQ,CAAC,GAAGE,SAAS;AACzC","ignoreList":[]}