@contentful/experiences-core 3.7.0-prerelease-20250915T1724-8825648.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -16,11 +16,12 @@ export { transformVisibility } from './utils/styleUtils/styleTransformers.js';
16
16
  export { transformBoundContentValue } from './utils/transformers/transformBoundContentValue.js';
17
17
  export { treeMap, treeVisit } from './utils/treeTraversal.js';
18
18
  export { isArrayOfLinks, isAsset, isEntry, isExperienceEntry, isPatternEntry } from './utils/typeguards.js';
19
- export { checkIsAssemblyDefinition, checkIsAssemblyEntry, checkIsAssemblyNode, generateRandomId, getDataFromTree, getTargetValueInPixels, parseCSSValue } from './utils/utils.js';
19
+ export { checkIsAssemblyDefinition, checkIsAssemblyEntry, checkIsAssemblyNode, createAssemblyDefinition, generateRandomId, getDataFromTree, getTargetValueInPixels, parseCSSValue } from './utils/utils.js';
20
20
  export { doesMismatchMessageSchema, tryParseMessage, validateExperienceBuilderConfig } from './utils/validations.js';
21
21
  export { extractLeafLinksReferencedFromExperience } from './utils/schema/experienceSchema.js';
22
22
  export { FnShouldFollowReferencesOfEntryField, extractReferencesFromEntries, extractReferencesFromEntriesAsIds, referencesOf, uniqueById } from './utils/schema/references.js';
23
23
  export { splitDirectAndSlotChildren } from './utils/splitDirectAndSlotChildren.js';
24
+ export { PrebindingData, extractPrebindingDataByPatternId, flattenNestedPatterns, generateDefaultDataSourceForPrebindingDefinition, getTargetPatternMappingsForParameter } from './utils/extractPrebindingData.js';
24
25
  export { builtInStyles, columnsBuiltInStyles, containerBuiltInStyles, dividerBuiltInStyles, optionalBuiltInStyles, sectionBuiltInStyles, singleColumnBuiltInStyles } from './definitions/styles.js';
25
26
  export { EditorModeEntityStore } from './entity/EditorModeEntityStore.js';
26
27
  export { EntityStore } from './entity/EntityStore.js';
@@ -36,6 +37,6 @@ export { createExperience } from './fetchers/createExperience.js';
36
37
  export { fetchReferencedEntities } from './fetchers/fetchReferencedEntities.js';
37
38
  export { fetchExperienceEntry } from './fetchers/fetchExperienceEntry.js';
38
39
  export { defineDesignTokens, designTokensRegistry, getDesignTokenRegistration, resetDesignTokenRegistry } from './registries/designTokenRegistry.js';
39
- export { breakpointsRegistry, defineBreakpoints, getBreakpointRegistration, resetBreakpointsRegistry, runBreakpointsValidation } from './registries/breakpointsRegistry.js';
40
+ export { breakpointsRegistry, defineBreakpoints, runBreakpointsValidation } from './registries/breakpointsRegistry.js';
40
41
  export { defineSdkOptions, getSdkOptions, sdkOptionsRegistry } from './registries/sdkOptionsRegistry.js';
41
- export { DeepReference, gatherDeepReferencesFromExperienceEntry, gatherDeepReferencesFromTree } from './deep-binding/DeepReference.js';
42
+ export { DeepReference, gatherDeepPrebindingReferencesFromExperienceEntry, gatherDeepPrebindingReferencesFromPatternEntry, gatherDeepReferencesFromExperienceEntry, gatherDeepReferencesFromTree } from './deep-binding/DeepReference.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { z, ZodIssueCode } from 'zod';
2
- import { cloneDeep, omit, isArray, uniqBy } from 'lodash-es';
2
+ import cloneDeep from 'lodash.clonedeep';
3
3
  import md5 from 'md5';
4
4
  import { BLOCKS } from '@contentful/rich-text-types';
5
5
  import { create } from 'zustand';
@@ -26,7 +26,9 @@ const INCOMING_EVENTS = {
26
26
  /** @deprecated will be removed when dropping backward compatibility for old DND */
27
27
  HoverComponent: 'hoverComponent',
28
28
  UpdatedEntity: 'updatedEntity',
29
+ /** @deprecated not needed after `patternResolution` was introduced. Will be removed in the next major version. */
29
30
  AssembliesAdded: 'assembliesAdded',
31
+ /** @deprecated not needed after `patternResolution` was introduced. Will be removed in the next major version. */
30
32
  AssembliesRegistered: 'assembliesRegistered',
31
33
  /** @deprecated will be removed when dropping backward compatibility for old DND */
32
34
  MouseMove: 'mouseMove',
@@ -998,7 +1000,7 @@ const BreakpointSchema = z
998
1000
  id: propertyKeySchema,
999
1001
  // Can be replace with z.templateLiteral when upgrading to zod v4
1000
1002
  query: z.string().refine((s) => BREAKPOINT_QUERY_REGEX.test(s)),
1001
- previewSize: z.string(),
1003
+ previewSize: z.string().optional(),
1002
1004
  displayName: z.string(),
1003
1005
  displayIcon: z.enum(['desktop', 'tablet', 'mobile']).optional(),
1004
1006
  })
@@ -1200,7 +1202,8 @@ const validateAtMostOneNativeParameterDefinition = (parameterDefinitions, ctx) =
1200
1202
  };
1201
1203
  const validateNoOverlapBetweenMappingAndOverrides = (variableMappings, allowedVariableOverrides, ctx) => {
1202
1204
  const variableMappingKeys = Object.keys(variableMappings || {});
1203
- const overlap = variableMappingKeys.filter((key) => allowedVariableOverrides?.includes(key));
1205
+ const overridesSet = new Set(allowedVariableOverrides || []);
1206
+ const overlap = variableMappingKeys.filter((key) => overridesSet.has(key));
1204
1207
  if (overlap.length > 0) {
1205
1208
  ctx.addIssue({
1206
1209
  code: z.ZodIssueCode.custom,
@@ -1518,11 +1521,42 @@ const validateBreakpointsDefinition = (breakpoints) => {
1518
1521
  return { success: true };
1519
1522
  };
1520
1523
 
1521
- let breakpointsRegistry = [];
1524
+ const breakpointsRegistry = [];
1522
1525
  /**
1523
- * Register custom breakpoints
1524
- * @param breakpoints - [{[key:string]: string}]
1525
- * @returns void
1526
+ * Define custom breakpoints that should be used for all your experiences.
1527
+ * A breakpoint consists of:
1528
+ * - id: a unique identifier for this breakpoint
1529
+ * - query: a media query string that defines when this breakpoint is active
1530
+ * - previewSize: an optional fixed preview size to be used in the Studio editor when selecting this breakpoint
1531
+ * - displayName: the name to be displayed in the Studio editor for this breakpoint
1532
+ * - displayIcon: an optional icon to be displayed in the Studio editor for this breakpoint
1533
+ *
1534
+ * The first breakpoint must use a wildcard query (`*`) to match all sizes.
1535
+ *
1536
+ * Every subsequent breakpoint inherits the designs of the previous ones by default.
1537
+ *
1538
+ * The order of breakpoints must be either:
1539
+ * - desktop first: from largest to smallest, using `<` operators
1540
+ * - mobile first: from smallest to largest, using `>` operators
1541
+ *
1542
+ * @note changing breakpoints after you have created experiences may break those experiences
1543
+ * @example
1544
+ * defineBreakpoints([{
1545
+ * id: 'desktop',
1546
+ * query: '*',
1547
+ * displayName: 'Desktop',
1548
+ * displayIcon: 'desktop',
1549
+ * }, {
1550
+ * id: 'tablet',
1551
+ * query: '<992px',
1552
+ * displayName: 'Tablet',
1553
+ * displayIcon: 'tablet',
1554
+ * }, {
1555
+ * id: 'mobile',
1556
+ * query: '<576px',
1557
+ * displayName: 'Mobile',
1558
+ * displayIcon: 'mobile',
1559
+ * }]);
1526
1560
  */
1527
1561
  const defineBreakpoints = (breakpoints) => {
1528
1562
  Object.assign(breakpointsRegistry, breakpoints);
@@ -1535,12 +1569,6 @@ const runBreakpointsValidation = () => {
1535
1569
  throw new Error(`Invalid breakpoints definition. Failed with errors: \n${JSON.stringify(validation.errors, null, 2)}`);
1536
1570
  }
1537
1571
  };
1538
- // Used in the tests to get a breakpoint registration
1539
- const getBreakpointRegistration = (id) => breakpointsRegistry.find((breakpoint) => breakpoint.id === id);
1540
- // Used in the tests to reset the registry
1541
- const resetBreakpointsRegistry = () => {
1542
- breakpointsRegistry = [];
1543
- };
1544
1572
 
1545
1573
  const sdkOptionsRegistry = {};
1546
1574
  /**
@@ -2147,7 +2175,9 @@ const stylesToRemove = CF_STYLE_ATTRIBUTES.filter((style) => !stylesToKeep.inclu
2147
2175
  // cfWrapColumns & cfWrapColumnsCount are no real style attributes as they are handled on the editor side
2148
2176
  const propsToRemove = ['cfSsrClassName', 'cfWrapColumns', 'cfWrapColumnsCount'];
2149
2177
  const sanitizeNodeProps = (nodeProps) => {
2150
- return omit(nodeProps, stylesToRemove, propsToRemove);
2178
+ const keysToRemove = [...stylesToRemove, ...propsToRemove];
2179
+ const sanitizedProps = Object.fromEntries(Object.entries(nodeProps).filter(([key]) => !keysToRemove.includes(key)));
2180
+ return sanitizedProps;
2151
2181
  };
2152
2182
 
2153
2183
  /** Turn the visibility value into a style object that can be used for inline styles in React */
@@ -3278,7 +3308,7 @@ function getArrayValue(entryOrAsset, path, entityStore) {
3278
3308
  }
3279
3309
  const fieldName = path.split('/').slice(2, -1);
3280
3310
  const arrayValue = get(entryOrAsset, fieldName);
3281
- if (!isArray(arrayValue)) {
3311
+ if (!Array.isArray(arrayValue)) {
3282
3312
  debug.warn(`[experiences-core::getArrayValue] A field '${fieldName}' of an entity was bound to an Array variable. Expected value of that field to be an array, but got: ${JSON.stringify(arrayValue)}`, { entity: entryOrAsset });
3283
3313
  return;
3284
3314
  }
@@ -3435,6 +3465,19 @@ function getTargetValueInPixels(targetWidthObject) {
3435
3465
  return targetWidthObject.value;
3436
3466
  }
3437
3467
  }
3468
+ /**
3469
+ * Creates a component definition for an assembly. As all assemblies use the same definition in the SDK,
3470
+ * all should be registered via this function.
3471
+ */
3472
+ const createAssemblyDefinition = (definitionId) => {
3473
+ return {
3474
+ id: definitionId,
3475
+ name: 'Component',
3476
+ variables: {},
3477
+ children: true,
3478
+ category: ASSEMBLY_DEFAULT_CATEGORY,
3479
+ };
3480
+ };
3438
3481
 
3439
3482
  class ParseError extends Error {
3440
3483
  constructor(message) {
@@ -3640,6 +3683,118 @@ const splitDirectAndSlotChildren = (allChildNodes, componentDefinition) => {
3640
3683
  return { slotNodesMap, directChildNodes };
3641
3684
  };
3642
3685
 
3686
+ const flattenNestedPatterns = (fetchedPatterns) => {
3687
+ const patternsById = {};
3688
+ const queue = [...fetchedPatterns];
3689
+ while (queue.length) {
3690
+ const pattern = queue.shift();
3691
+ if (!pattern) {
3692
+ continue;
3693
+ }
3694
+ if (patternsById[pattern.sys.id]) {
3695
+ continue;
3696
+ }
3697
+ patternsById[pattern.sys.id] = pattern;
3698
+ if (!Array.isArray(pattern.fields.usedComponents) || !pattern.fields.usedComponents.length) {
3699
+ continue;
3700
+ }
3701
+ for (const nestedPattern of pattern.fields.usedComponents) {
3702
+ if (!isLink(nestedPattern)) {
3703
+ queue.push(nestedPattern);
3704
+ }
3705
+ }
3706
+ }
3707
+ return Object.values(patternsById);
3708
+ };
3709
+ /**
3710
+ * Given a list of patterns, extract the prebinding data into a more digestable format indexed by the pattern entry id
3711
+ * @param patterns a list of pattern entries
3712
+ * @returns a map of pattern entry ids to their prebinding data
3713
+ */
3714
+ const extractPrebindingDataByPatternId = (patterns) => {
3715
+ const prebindingDataByPatternId = {};
3716
+ for (const pattern of patterns) {
3717
+ const patternId = pattern.sys.id;
3718
+ const [prebindingDefinition] = pattern.fields.componentSettings?.prebindingDefinitions ?? [];
3719
+ if (!prebindingDefinition)
3720
+ continue;
3721
+ const [nativeParameterId] = Object.entries(prebindingDefinition.parameterDefinitions ?? {}).find(([, value]) => value.passToNodes === undefined) ?? [];
3722
+ const prebindingData = {
3723
+ prebindingDefinitionId: prebindingDefinition.id,
3724
+ parameterIds: Object.keys(prebindingDefinition.parameterDefinitions),
3725
+ nativeParameterId,
3726
+ parameterDefinitions: prebindingDefinition.parameterDefinitions,
3727
+ variableMappings: prebindingDefinition.variableMappings,
3728
+ };
3729
+ prebindingDataByPatternId[patternId] = prebindingData;
3730
+ }
3731
+ return prebindingDataByPatternId;
3732
+ };
3733
+ const generateDefaultDataSourceForPrebindingDefinition = (prebindingDefinitions = []) => {
3734
+ if (!prebindingDefinitions ||
3735
+ !Array.isArray(prebindingDefinitions) ||
3736
+ !prebindingDefinitions.length) {
3737
+ return { dataSource: {}, parameters: {} };
3738
+ }
3739
+ const prebindingDefinition = prebindingDefinitions[0];
3740
+ const dataSource = {};
3741
+ const parameters = {};
3742
+ for (const [parameterId, parameterDefinition] of Object.entries(prebindingDefinition.parameterDefinitions ?? {})) {
3743
+ if (parameterDefinition.defaultSource && isLink(parameterDefinition.defaultSource.link)) {
3744
+ const dataSourceKey = generateRandomId(7);
3745
+ dataSource[dataSourceKey] = parameterDefinition.defaultSource.link;
3746
+ parameters[parameterId] = {
3747
+ type: 'BoundValue',
3748
+ path: `/${dataSourceKey}`,
3749
+ };
3750
+ }
3751
+ }
3752
+ return {
3753
+ dataSource,
3754
+ parameters,
3755
+ };
3756
+ };
3757
+ function getTargetPatternMappingsForParameter({ fetchedPatterns, prebindingDataByPatternId, patternNodeDefinitionId, parameterId, }) {
3758
+ const patternPrebindingData = prebindingDataByPatternId[patternNodeDefinitionId];
3759
+ if (!patternPrebindingData)
3760
+ return undefined;
3761
+ if (patternPrebindingData.parameterIds.includes(parameterId)) {
3762
+ if (patternPrebindingData.nativeParameterId === parameterId) {
3763
+ if (!patternPrebindingData.variableMappings)
3764
+ return undefined;
3765
+ return Object.fromEntries(Object.entries(patternPrebindingData.variableMappings).filter(([, mapping]) => mapping.parameterId === parameterId));
3766
+ }
3767
+ else {
3768
+ const parameterDefinition = patternPrebindingData.parameterDefinitions[parameterId];
3769
+ if (!parameterDefinition || !parameterDefinition.passToNodes)
3770
+ return undefined;
3771
+ const patternEntry = fetchedPatterns.find((entry) => entry.sys.id === patternNodeDefinitionId);
3772
+ if (!patternEntry)
3773
+ return undefined;
3774
+ let nestedPatternNode;
3775
+ treeVisit({
3776
+ definitionId: 'root',
3777
+ parameters: {},
3778
+ children: patternEntry.fields.componentTree.children,
3779
+ }, (node) => {
3780
+ if (node.id === parameterDefinition.passToNodes?.[0].nodeId) {
3781
+ nestedPatternNode = node;
3782
+ }
3783
+ return undefined;
3784
+ });
3785
+ if (!nestedPatternNode) {
3786
+ return undefined;
3787
+ }
3788
+ return getTargetPatternMappingsForParameter({
3789
+ fetchedPatterns,
3790
+ prebindingDataByPatternId,
3791
+ patternNodeDefinitionId: nestedPatternNode.definitionId,
3792
+ parameterId: parameterDefinition.passToNodes?.[0].parameterId,
3793
+ });
3794
+ }
3795
+ }
3796
+ }
3797
+
3643
3798
  const sendMessage = (eventType, data) => {
3644
3799
  if (typeof window === 'undefined') {
3645
3800
  return;
@@ -4466,7 +4621,7 @@ function gatherDeepReferencesFromExperienceEntry(experienceEntry) {
4466
4621
  }, (node) => {
4467
4622
  if (!node.variables)
4468
4623
  return;
4469
- for (const [, variableMapping] of Object.entries(node.variables)) {
4624
+ for (const variableMapping of Object.values(node.variables)) {
4470
4625
  if (variableMapping.type !== 'BoundValue')
4471
4626
  continue;
4472
4627
  if (!isDeepPath(variableMapping.path))
@@ -4479,6 +4634,99 @@ function gatherDeepReferencesFromExperienceEntry(experienceEntry) {
4479
4634
  });
4480
4635
  return deepReferences;
4481
4636
  }
4637
+ function gatherDeepPrebindingReferencesFromExperienceEntry({ experienceEntry, fetchedPatterns, prebindingDataByPatternId, fetchedLevel1Entries, }) {
4638
+ const deepPrebindingReferences = [];
4639
+ const dataSource = experienceEntry.fields.dataSource;
4640
+ const { children } = experienceEntry.fields.componentTree;
4641
+ treeVisit({
4642
+ definitionId: 'root',
4643
+ parameters: {},
4644
+ children,
4645
+ }, (node) => {
4646
+ if (!node.parameters)
4647
+ return;
4648
+ for (const [parameterId, parameterValue] of Object.entries(node.parameters)) {
4649
+ const dataSourceKey = parameterValue.path.split('/')[1];
4650
+ const headEntryLink = dataSource[dataSourceKey];
4651
+ if (!headEntryLink)
4652
+ continue;
4653
+ if (headEntryLink.sys.linkType !== 'Entry')
4654
+ continue;
4655
+ const headEntry = fetchedLevel1Entries.find((entry) => entry.sys.id === headEntryLink.sys.id);
4656
+ if (!headEntry)
4657
+ continue;
4658
+ const headEntryContentTypeId = headEntry.sys.contentType.sys.id;
4659
+ // if experience, we don't have any hoisted data on the given experienceEntry
4660
+ // and we have to lookup the pattern instead
4661
+ const variableMappings = getTargetPatternMappingsForParameter({
4662
+ fetchedPatterns,
4663
+ prebindingDataByPatternId,
4664
+ patternNodeDefinitionId: node.definitionId,
4665
+ parameterId,
4666
+ });
4667
+ if (!variableMappings)
4668
+ continue;
4669
+ for (const mappingData of Object.values(variableMappings)) {
4670
+ const targetMapping = mappingData.pathsByContentType[headEntryContentTypeId];
4671
+ if (!targetMapping)
4672
+ continue;
4673
+ // mapping doesn't start with /uuid, but instead starts with /fields
4674
+ // so we add /uuid to make it match the binding path format
4675
+ const path = `/${dataSourceKey}${targetMapping.path}`;
4676
+ if (!isDeepPath(path))
4677
+ continue;
4678
+ deepPrebindingReferences.push(DeepReference.from({
4679
+ path,
4680
+ dataSource,
4681
+ }));
4682
+ }
4683
+ }
4684
+ });
4685
+ return deepPrebindingReferences;
4686
+ }
4687
+ function gatherDeepPrebindingReferencesFromPatternEntry({ patternEntry, fetchedPatterns, prebindingDataByPatternId, fetchedLevel1Entries, }) {
4688
+ const deepPrebindingReferences = [];
4689
+ // patterns can't have parameters in their CDA/CMA JSON, so we can generate random ids here
4690
+ const { dataSource, parameters } = generateDefaultDataSourceForPrebindingDefinition(patternEntry.fields.componentSettings?.prebindingDefinitions);
4691
+ for (const [parameterId, parameterValue] of Object.entries(parameters)) {
4692
+ const dataSourceKey = parameterValue.path.split('/')[1];
4693
+ const headEntryLink = dataSource[dataSourceKey];
4694
+ if (!headEntryLink)
4695
+ continue;
4696
+ if (headEntryLink.sys.linkType !== 'Entry')
4697
+ continue;
4698
+ const headEntry = fetchedLevel1Entries.find((entry) => entry.sys.id === headEntryLink.sys.id);
4699
+ if (!headEntry)
4700
+ continue;
4701
+ const headEntryContentTypeId = headEntry.sys.contentType.sys.id;
4702
+ const variableMappings = getTargetPatternMappingsForParameter({
4703
+ fetchedPatterns,
4704
+ prebindingDataByPatternId,
4705
+ patternNodeDefinitionId: patternEntry.sys.id,
4706
+ parameterId,
4707
+ });
4708
+ if (!variableMappings)
4709
+ continue;
4710
+ for (const mappingData of Object.values(variableMappings)) {
4711
+ const targetMapping = mappingData.pathsByContentType[headEntryContentTypeId];
4712
+ if (!targetMapping)
4713
+ continue;
4714
+ // mapping doesn't start with /uuid, but instead starts with /fields
4715
+ // so we add /uuid to make it match the binding path format
4716
+ const path = `/${dataSourceKey}${targetMapping.path}`;
4717
+ if (!isDeepPath(path))
4718
+ continue;
4719
+ deepPrebindingReferences.push(DeepReference.from({
4720
+ path,
4721
+ dataSource,
4722
+ }));
4723
+ }
4724
+ }
4725
+ return deepPrebindingReferences;
4726
+ }
4727
+ /**
4728
+ * used in editor mode. for delivery mode see `gatherDeepReferencesFromExperienceEntry`
4729
+ */
4482
4730
  function gatherDeepReferencesFromTree(startingNode, dataSource, getEntityFromLink) {
4483
4731
  const deepReferences = [];
4484
4732
  treeVisit(startingNode, (node) => {
@@ -4600,8 +4848,8 @@ const fetchAllEntries = async ({ client, ids, locale, skip = 0, limit = 100, res
4600
4848
  responseIncludes,
4601
4849
  });
4602
4850
  }
4603
- const dedupedEntries = uniqBy(responseIncludes?.Entry, (entry) => entry.sys.id);
4604
- const dedupedAssets = uniqBy(responseIncludes?.Asset, (asset) => asset.sys.id);
4851
+ const dedupedEntries = uniqueById(responseIncludes?.Entry);
4852
+ const dedupedAssets = uniqueById(responseIncludes?.Asset);
4605
4853
  return {
4606
4854
  items: responseItems,
4607
4855
  includes: {
@@ -4685,7 +4933,6 @@ const fetchReferencedEntities = async ({ client, experienceEntry, locale, }) =>
4685
4933
  if (!isExperienceEntry(experienceEntry)) {
4686
4934
  throw new Error('Failed to fetch experience entities. Provided "experienceEntry" does not match experience entry schema');
4687
4935
  }
4688
- const deepReferences = gatherDeepReferencesFromExperienceEntry(experienceEntry);
4689
4936
  const entryIds = new Set();
4690
4937
  const assetIds = new Set();
4691
4938
  for (const dataBinding of Object.values(experienceEntry.fields.dataSource)) {
@@ -4703,12 +4950,52 @@ const fetchReferencedEntities = async ({ client, experienceEntry, locale, }) =>
4703
4950
  fetchAllEntries({ client, ids: [...entryIds], locale }),
4704
4951
  fetchAllAssets({ client, ids: [...assetIds], locale }),
4705
4952
  ]);
4706
- const { autoFetchedReferentAssets, autoFetchedReferentEntries } = gatherAutoFetchedReferentsFromIncludes(deepReferences, entriesResponse);
4953
+ const usedPatterns = experienceEntry.fields.usedComponents ?? [];
4954
+ const isRenderingExperience = Boolean(!experienceEntry.fields.componentSettings);
4955
+ const deepReferences = gatherDeepReferencesFromExperienceEntry(experienceEntry);
4956
+ // If we are previewing a pattern, we want to include the entry itself as well
4957
+ const fetchedPatterns = (isRenderingExperience ? usedPatterns : [...usedPatterns, experienceEntry]);
4958
+ const allFetchedPatterns = flattenNestedPatterns(fetchedPatterns);
4959
+ const prebindingDataByPatternId = extractPrebindingDataByPatternId(allFetchedPatterns);
4960
+ // Patterns do not have dataSource stored in their dataSource field, so head entities won't be there and we need to fetch them
4961
+ if (!isRenderingExperience) {
4962
+ const { dataSource } = generateDefaultDataSourceForPrebindingDefinition(experienceEntry.fields.componentSettings?.prebindingDefinitions);
4963
+ if (Object.keys(dataSource).length) {
4964
+ const prebindingEntriesResponse = await fetchAllEntries({
4965
+ client,
4966
+ ids: Object.values(dataSource).map((link) => link.sys.id),
4967
+ locale,
4968
+ });
4969
+ entriesResponse.items.push(...prebindingEntriesResponse.items);
4970
+ entriesResponse.includes.Asset.push(...(prebindingEntriesResponse.includes?.Asset ?? []));
4971
+ entriesResponse.includes.Entry.push(...(prebindingEntriesResponse.includes?.Entry ?? []));
4972
+ }
4973
+ }
4974
+ // normally, for experience entry, there should be no need to call this method, as `includes=2` will have them resolved
4975
+ // because the entries used for pre-binding are stored in both - the layout of the experience, as well as the dataSource field
4976
+ const deepPrebindingReferences = isRenderingExperience
4977
+ ? gatherDeepPrebindingReferencesFromExperienceEntry({
4978
+ experienceEntry: experienceEntry,
4979
+ fetchedPatterns: allFetchedPatterns,
4980
+ prebindingDataByPatternId,
4981
+ fetchedLevel1Entries: entriesResponse.items,
4982
+ })
4983
+ : // however, for patterns, we have to do it by hand, because a pattern entry doesn't save the pre-binding data neither in the
4984
+ // layout nor in the dataSource field.
4985
+ // for consistency, as well as to be future safe from the change to "includes=2", I added methods for both
4986
+ gatherDeepPrebindingReferencesFromPatternEntry({
4987
+ patternEntry: experienceEntry,
4988
+ fetchedPatterns: allFetchedPatterns,
4989
+ prebindingDataByPatternId,
4990
+ fetchedLevel1Entries: entriesResponse.items,
4991
+ });
4992
+ const allDeepReferences = [...deepReferences, ...deepPrebindingReferences];
4993
+ const { autoFetchedReferentAssets, autoFetchedReferentEntries } = gatherAutoFetchedReferentsFromIncludes(allDeepReferences, entriesResponse);
4707
4994
  // Using client getEntries resolves all linked entry references, so we do not need to resolve entries in usedComponents
4708
4995
  const allResolvedEntries = [
4709
4996
  ...(entriesResponse?.items ?? []),
4710
4997
  ...(entriesResponse.includes?.Entry ?? []),
4711
- ...(experienceEntry.fields.usedComponents || []),
4998
+ ...(usedPatterns || []),
4712
4999
  ...autoFetchedReferentEntries,
4713
5000
  ];
4714
5001
  const allResolvedAssets = [
@@ -4717,8 +5004,14 @@ const fetchReferencedEntities = async ({ client, experienceEntry, locale, }) =>
4717
5004
  ...autoFetchedReferentAssets,
4718
5005
  ];
4719
5006
  return {
4720
- entries: allResolvedEntries,
4721
- assets: allResolvedAssets,
5007
+ // we have to drop duplicates, becasue of the merge of deepReferences and deepPrebindingReferences above
5008
+ // If not, the same entity might appear in this array more than once
5009
+ entries: [
5010
+ ...new Map(allResolvedEntries.map((entry) => [entry.sys.id, entry])).values(),
5011
+ ],
5012
+ assets: [
5013
+ ...new Map(allResolvedAssets.map((asset) => [asset.sys.id, asset])).values(),
5014
+ ],
4722
5015
  };
4723
5016
  };
4724
5017
 
@@ -4997,5 +5290,5 @@ async function fetchById({ client, experienceTypeId, id, localeCode, isEditorMod
4997
5290
  }
4998
5291
  }
4999
5292
 
5000
- export { BREAKPOINTS_STRATEGY_DESKTOP_FIRST, BREAKPOINTS_STRATEGY_MOBILE_FIRST, DebugLogger, DeepReference, EditorModeEntityStore, EntityStore, EntityStoreBase, MEDIA_QUERY_REGEXP, VisualEditorMode, addLocale, addMinHeightForEmptyStructures, breakpointsRegistry, buildCfStyles, buildStyleTag, buildTemplate, builtInStyles, calculateNodeDefaultHeight, checkIsAssemblyDefinition, checkIsAssemblyEntry, checkIsAssemblyNode, columnsBuiltInStyles, containerBuiltInStyles, createExperience, debug, defineBreakpoints, defineDesignTokens, defineSdkOptions, designTokensRegistry, detachExperienceStyles, detectBreakpointsStrategy, disableDebug, dividerBuiltInStyles, doesMismatchMessageSchema, enableDebug, extractLeafLinksReferencedFromExperience, extractReferencesFromEntries, extractReferencesFromEntriesAsIds, fetchAllAssets, fetchAllEntries, fetchById, fetchBySlug, fetchExperienceEntry, fetchReferencedEntities, findOutermostCoordinates, flattenDesignTokenRegistry, gatherDeepReferencesFromExperienceEntry, gatherDeepReferencesFromTree, generateRandomId, getActiveBreakpointIndex, getBreakpointRegistration, getDataFromTree, getDesignTokenRegistration, getElementCoordinates, getFallbackBreakpointIndex, getPrebindingPathBySourceEntry, getSdkOptions, getTargetValueInPixels, getTemplateValue, getValueForBreakpoint, inMemoryEntities, inMemoryEntitiesStore, indexByBreakpoint, isArrayOfLinks, isAsset, isCfStyleAttribute, isComponentAllowedOnRoot, isContentfulComponent, isContentfulStructureComponent, isDeepPath, isDeepPrebinding, isElementHidden, isEntry, isExperienceEntry, isLink, isLinkToAsset, isLinkToEntry, isPatternComponent, isPatternEntry, isPreboundProp, isStructureWithRelativeHeight, isValidBreakpointValue, lastPathNamedSegmentEq, localizeEntity, maybePopulateDesignTokenValue, mediaQueryMatcher, mergeDesignValuesByBreakpoint, optionalBuiltInStyles, parseCSSValue, parseDataSourcePathIntoFieldset, parseDataSourcePathWithL1DeepBindings, referencesOf, resetBreakpointsRegistry, resetDesignTokenRegistry, resolveBackgroundImageBinding, resolveHyperlinkPattern, runBreakpointsValidation, sanitizeNodeProps, sdkOptionsRegistry, sectionBuiltInStyles, sendMessage, setDebugLevel, singleColumnBuiltInStyles, splitDirectAndSlotChildren, stringifyCssProperties, toCSSAttribute, toMediaQuery, transformBoundContentValue, transformVisibility, treeMap, treeVisit, tryParseMessage, uniqueById, useInMemoryEntities, validateExperienceBuilderConfig };
5293
+ export { BREAKPOINTS_STRATEGY_DESKTOP_FIRST, BREAKPOINTS_STRATEGY_MOBILE_FIRST, DebugLogger, DeepReference, EditorModeEntityStore, EntityStore, EntityStoreBase, MEDIA_QUERY_REGEXP, VisualEditorMode, addLocale, addMinHeightForEmptyStructures, breakpointsRegistry, buildCfStyles, buildStyleTag, buildTemplate, builtInStyles, calculateNodeDefaultHeight, checkIsAssemblyDefinition, checkIsAssemblyEntry, checkIsAssemblyNode, columnsBuiltInStyles, containerBuiltInStyles, createAssemblyDefinition, createExperience, debug, defineBreakpoints, defineDesignTokens, defineSdkOptions, designTokensRegistry, detachExperienceStyles, detectBreakpointsStrategy, disableDebug, dividerBuiltInStyles, doesMismatchMessageSchema, enableDebug, extractLeafLinksReferencedFromExperience, extractPrebindingDataByPatternId, extractReferencesFromEntries, extractReferencesFromEntriesAsIds, fetchAllAssets, fetchAllEntries, fetchById, fetchBySlug, fetchExperienceEntry, fetchReferencedEntities, findOutermostCoordinates, flattenDesignTokenRegistry, flattenNestedPatterns, gatherDeepPrebindingReferencesFromExperienceEntry, gatherDeepPrebindingReferencesFromPatternEntry, gatherDeepReferencesFromExperienceEntry, gatherDeepReferencesFromTree, generateDefaultDataSourceForPrebindingDefinition, generateRandomId, getActiveBreakpointIndex, getDataFromTree, getDesignTokenRegistration, getElementCoordinates, getFallbackBreakpointIndex, getPrebindingPathBySourceEntry, getSdkOptions, getTargetPatternMappingsForParameter, getTargetValueInPixels, getTemplateValue, getValueForBreakpoint, inMemoryEntities, inMemoryEntitiesStore, indexByBreakpoint, isArrayOfLinks, isAsset, isCfStyleAttribute, isComponentAllowedOnRoot, isContentfulComponent, isContentfulStructureComponent, isDeepPath, isDeepPrebinding, isElementHidden, isEntry, isExperienceEntry, isLink, isLinkToAsset, isLinkToEntry, isPatternComponent, isPatternEntry, isPreboundProp, isStructureWithRelativeHeight, isValidBreakpointValue, lastPathNamedSegmentEq, localizeEntity, maybePopulateDesignTokenValue, mediaQueryMatcher, mergeDesignValuesByBreakpoint, optionalBuiltInStyles, parseCSSValue, parseDataSourcePathIntoFieldset, parseDataSourcePathWithL1DeepBindings, referencesOf, resetDesignTokenRegistry, resolveBackgroundImageBinding, resolveHyperlinkPattern, runBreakpointsValidation, sanitizeNodeProps, sdkOptionsRegistry, sectionBuiltInStyles, sendMessage, setDebugLevel, singleColumnBuiltInStyles, splitDirectAndSlotChildren, stringifyCssProperties, toCSSAttribute, toMediaQuery, transformBoundContentValue, transformVisibility, treeMap, treeVisit, tryParseMessage, uniqueById, useInMemoryEntities, validateExperienceBuilderConfig };
5001
5294
  //# sourceMappingURL=index.js.map