@contentful/experiences-core 1.30.0-beta.0 → 1.30.0-dev-20250124T1739-560b81b.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.
@@ -10,15 +10,13 @@ type EntityStoreArgs = {
10
10
  locale: string;
11
11
  };
12
12
  declare class EntityStore extends EntityStoreBase {
13
- private _experienceEntryFields;
14
- private _experienceEntryId;
13
+ private _experienceEntry;
15
14
  private _unboundValues;
16
15
  private _usedComponentsWithDeepReferences;
17
16
  constructor(json: string);
18
17
  constructor({ experienceEntry, entities, locale }: EntityStoreArgs);
19
18
  getCurrentLocale(): string;
20
19
  get experienceEntryFields(): ExperienceFields | undefined;
21
- get experienceEntryId(): string | undefined;
22
20
  get schemaVersion(): "2023-09-28" | undefined;
23
21
  get breakpoints(): {
24
22
  id: string;
@@ -56,8 +54,7 @@ declare class EntityStore extends EntityStoreBase {
56
54
  [k: string]: Asset<contentful.ChainModifiers, string>;
57
55
  };
58
56
  locale: string;
59
- _experienceEntryFields: ExperienceFields | undefined;
60
- _experienceEntryId: string | undefined;
57
+ _experienceEntry: ExperienceFields | undefined;
61
58
  _unboundValues: Record<string, {
62
59
  value?: string | number | boolean | Record<any, any> | undefined;
63
60
  }> | undefined;
package/dist/index.js CHANGED
@@ -1563,7 +1563,7 @@ const detachExperienceStyles = (experience) => {
1563
1563
  }, {});
1564
1564
  // getting the breakpoint ids
1565
1565
  const breakpointIds = Object.keys(mediaQueriesTemplate);
1566
- const iterateOverTreeAndExtractStyles = ({ componentTree, dataSource, unboundValues, componentSettings, componentVariablesOverwrites, patternWrapper, wrappingPatternIds, }) => {
1566
+ const iterateOverTreeAndExtractStyles = ({ componentTree, dataSource, unboundValues, componentSettings, componentVariablesOverwrites, patternWrapper, }) => {
1567
1567
  // traversing the tree
1568
1568
  const queue = [];
1569
1569
  queue.push(...componentTree.children);
@@ -1580,10 +1580,6 @@ const detachExperienceStyles = (experience) => {
1580
1580
  usedComponents,
1581
1581
  });
1582
1582
  if (isPatternNode) {
1583
- // When detecting a circular dependency among patterns, stop to avoid an infinite loop
1584
- if (wrappingPatternIds.has(currentNode.definitionId)) {
1585
- continue;
1586
- }
1587
1583
  const patternEntry = usedComponents.find((component) => component.sys.id === currentNode.definitionId);
1588
1584
  if (!patternEntry || !('fields' in patternEntry)) {
1589
1585
  continue;
@@ -1624,7 +1620,6 @@ const detachExperienceStyles = (experience) => {
1624
1620
  componentVariablesOverwrites: currentNode.variables,
1625
1621
  // pass top-level pattern node to store instance-specific child styles for rendering
1626
1622
  patternWrapper: currentNode,
1627
- wrappingPatternIds: new Set([...wrappingPatternIds, currentNode.definitionId]),
1628
1623
  });
1629
1624
  continue;
1630
1625
  }
@@ -1781,7 +1776,6 @@ const detachExperienceStyles = (experience) => {
1781
1776
  dataSource: experience.entityStore?.dataSource ?? {},
1782
1777
  unboundValues: experience.entityStore?.unboundValues ?? {},
1783
1778
  componentSettings: experience.entityStore?.experienceEntryFields?.componentSettings,
1784
- wrappingPatternIds: new Set(experience.entityStore?.experienceEntryId ? [experience.entityStore.experienceEntryId] : []),
1785
1779
  });
1786
1780
  // once the whole tree was traversed, for each breakpoint, I aggregate the styles
1787
1781
  // for each generated className into one css string
@@ -3144,76 +3138,64 @@ class EditorModeEntityStore extends EditorEntityStore {
3144
3138
  }
3145
3139
  }
3146
3140
 
3147
- const resolveDeepUsedComponents = ({ experienceEntryFields, parentComponents, }) => {
3148
- const totalUsedComponents = [];
3141
+ const gatherUsedComponentsWithDeepRefernces = (experienceEntryFields) => {
3142
+ const usedComponentDeepReferences = [];
3149
3143
  const usedComponents = experienceEntryFields?.usedComponents;
3150
3144
  if (!usedComponents || usedComponents.length === 0) {
3151
3145
  return [];
3152
3146
  }
3153
3147
  for (const component of usedComponents) {
3154
3148
  if ('fields' in component) {
3155
- totalUsedComponents.push(component);
3156
- if (parentComponents.has(component.sys.id)) {
3157
- continue;
3158
- }
3159
- totalUsedComponents.push(...resolveDeepUsedComponents({
3160
- experienceEntryFields: component.fields,
3161
- parentComponents: new Set([...parentComponents, component.sys.id]),
3162
- }));
3149
+ usedComponentDeepReferences.push(component);
3150
+ usedComponentDeepReferences.push(...gatherUsedComponentsWithDeepRefernces(component.fields));
3163
3151
  }
3164
3152
  }
3165
- return totalUsedComponents;
3153
+ return usedComponentDeepReferences;
3166
3154
  };
3167
3155
 
3168
3156
  class EntityStore extends EntityStoreBase {
3169
3157
  constructor(options) {
3170
3158
  if (typeof options === 'string') {
3171
- // For SSR/SSG, the entity store is created server-side and passed to the client as a serialised JSON.
3172
- // So the properties in data.entityStore are equal to the attributes of this class (see `toJSON()`)
3173
- const serializedAttributes = JSON.parse(options).entityStore;
3159
+ const data = JSON.parse(options);
3160
+ const { _experienceEntry, _unboundValues, locale, entryMap, assetMap } = data.entityStore;
3174
3161
  super({
3175
3162
  entities: [
3176
- ...Object.values(serializedAttributes.entryMap),
3177
- ...Object.values(serializedAttributes.assetMap),
3163
+ ...Object.values(entryMap),
3164
+ ...Object.values(assetMap),
3178
3165
  ],
3179
- locale: serializedAttributes.locale,
3166
+ locale,
3180
3167
  });
3181
- this._experienceEntryFields = serializedAttributes._experienceEntryFields;
3182
- this._experienceEntryId = serializedAttributes._experienceEntryId;
3183
- this._unboundValues = serializedAttributes._unboundValues;
3168
+ this._experienceEntry = _experienceEntry;
3169
+ this._unboundValues = _unboundValues;
3170
+ this._usedComponentsWithDeepReferences = gatherUsedComponentsWithDeepRefernces(this._experienceEntry);
3184
3171
  }
3185
3172
  else {
3186
3173
  const { experienceEntry, entities, locale } = options;
3187
- if (!isExperienceEntry(experienceEntry)) {
3174
+ super({ entities, locale });
3175
+ if (isExperienceEntry(experienceEntry)) {
3176
+ this._experienceEntry = experienceEntry.fields;
3177
+ this._unboundValues = experienceEntry.fields.unboundValues;
3178
+ this._usedComponentsWithDeepReferences = gatherUsedComponentsWithDeepRefernces(this._experienceEntry);
3179
+ }
3180
+ else {
3188
3181
  throw new Error('Provided entry is not experience entry');
3189
3182
  }
3190
- super({ entities, locale });
3191
- this._experienceEntryFields = experienceEntry.fields;
3192
- this._experienceEntryId = experienceEntry.sys.id;
3193
- this._unboundValues = experienceEntry.fields.unboundValues;
3194
3183
  }
3195
- this._usedComponentsWithDeepReferences = resolveDeepUsedComponents({
3196
- experienceEntryFields: this._experienceEntryFields,
3197
- parentComponents: new Set([this._experienceEntryId]),
3198
- });
3199
3184
  }
3200
3185
  getCurrentLocale() {
3201
3186
  return this.locale;
3202
3187
  }
3203
3188
  get experienceEntryFields() {
3204
- return this._experienceEntryFields;
3205
- }
3206
- get experienceEntryId() {
3207
- return this._experienceEntryId;
3189
+ return this._experienceEntry;
3208
3190
  }
3209
3191
  get schemaVersion() {
3210
- return this._experienceEntryFields?.componentTree.schemaVersion;
3192
+ return this._experienceEntry?.componentTree.schemaVersion;
3211
3193
  }
3212
3194
  get breakpoints() {
3213
- return this._experienceEntryFields?.componentTree.breakpoints ?? [];
3195
+ return this._experienceEntry?.componentTree.breakpoints ?? [];
3214
3196
  }
3215
3197
  get dataSource() {
3216
- return this._experienceEntryFields?.dataSource ?? {};
3198
+ return this._experienceEntry?.dataSource ?? {};
3217
3199
  }
3218
3200
  get unboundValues() {
3219
3201
  return this._unboundValues ?? {};
@@ -3244,8 +3226,7 @@ class EntityStore extends EntityStoreBase {
3244
3226
  }
3245
3227
  toJSON() {
3246
3228
  return {
3247
- _experienceEntryFields: this._experienceEntryFields,
3248
- _experienceEntryId: this._experienceEntryId,
3229
+ _experienceEntry: this._experienceEntry,
3249
3230
  _unboundValues: this._unboundValues,
3250
3231
  ...super.toJSON(),
3251
3232
  };
@@ -3570,22 +3551,22 @@ const fetchReferencedEntities = async ({ client, experienceEntry, locale, }) =>
3570
3551
  throw new Error('Failed to fetch experience entities. Provided "experienceEntry" does not match experience entry schema');
3571
3552
  }
3572
3553
  const deepReferences = gatherDeepReferencesFromExperienceEntry(experienceEntry);
3573
- const entryIds = new Set();
3574
- const assetIds = new Set();
3554
+ const entryIds = [];
3555
+ const assetIds = [];
3575
3556
  for (const dataBinding of Object.values(experienceEntry.fields.dataSource)) {
3576
3557
  if (!('sys' in dataBinding)) {
3577
3558
  continue;
3578
3559
  }
3579
3560
  if (dataBinding.sys.linkType === 'Entry') {
3580
- entryIds.add(dataBinding.sys.id);
3561
+ entryIds.push(dataBinding.sys.id);
3581
3562
  }
3582
3563
  if (dataBinding.sys.linkType === 'Asset') {
3583
- assetIds.add(dataBinding.sys.id);
3564
+ assetIds.push(dataBinding.sys.id);
3584
3565
  }
3585
3566
  }
3586
3567
  const [entriesResponse, assetsResponse] = await Promise.all([
3587
- fetchAllEntries({ client, ids: [...entryIds], locale }),
3588
- fetchAllAssets({ client, ids: [...assetIds], locale }),
3568
+ fetchAllEntries({ client, ids: entryIds, locale }),
3569
+ fetchAllAssets({ client, ids: assetIds, locale }),
3589
3570
  ]);
3590
3571
  const { autoFetchedReferentAssets, autoFetchedReferentEntries } = gatherAutoFetchedReferentsFromIncludes(deepReferences, entriesResponse);
3591
3572
  // Using client getEntries resolves all linked entry references, so we do not need to resolve entries in usedComponents
@@ -3606,68 +3587,6 @@ const fetchReferencedEntities = async ({ client, experienceEntry, locale, }) =>
3606
3587
  };
3607
3588
  };
3608
3589
 
3609
- /**
3610
- * The CMA client will automatically replace links with entry references.
3611
- * As we're including all referenced pattern entries in usedComponents, this can lead
3612
- * to a circular reference. This function replaces those with plain links inplace (!).
3613
- *
3614
- * @see https://github.com/contentful/contentful.js/issues/377
3615
- */
3616
- const removeCircularPatternReferences = (experienceEntry, _parentIds) => {
3617
- const parentIds = _parentIds ?? new Set([experienceEntry.sys.id]);
3618
- const usedComponents = experienceEntry.fields.usedComponents;
3619
- const newUsedComponents = usedComponents?.reduce((acc, linkOrEntry) => {
3620
- if (!('fields' in linkOrEntry)) {
3621
- // It is a link, we're good
3622
- return [...acc, linkOrEntry];
3623
- }
3624
- const entry = linkOrEntry;
3625
- if (parentIds.has(entry.sys.id)) {
3626
- // It is an entry that already occurred -> turn it into a link to remove the circularity
3627
- const link = {
3628
- sys: {
3629
- id: entry.sys.id,
3630
- linkType: 'Entry',
3631
- type: 'Link',
3632
- },
3633
- };
3634
- return [...acc, link];
3635
- }
3636
- // Remove circularity for its usedComponents as well (inplace)
3637
- removeCircularPatternReferences(entry, new Set([...parentIds, entry.sys.id]));
3638
- return [...acc, entry];
3639
- }, []);
3640
- // @ts-expect-error - type of usedComponents doesn't yet allow a mixed list of both links and entries
3641
- experienceEntry.fields.usedComponents = newUsedComponents;
3642
- };
3643
- /**
3644
- * The CMA client will automatically replace links with entry references if they are available.
3645
- * While we're not fetching the data sources, a self reference would be replaced as the entry is
3646
- * fetched. Any circuar reference in the object breaks SSR where we have to stringify the JSON.
3647
- * This would fail if the object contains circular references.
3648
- */
3649
- const removeSelfReferencingDataSource = (experienceEntry) => {
3650
- const dataSources = experienceEntry.fields.dataSource;
3651
- const newDataSource = Object.entries(dataSources).reduce((acc, [key, linkOrEntry]) => {
3652
- if ('fields' in linkOrEntry && linkOrEntry.sys.id === experienceEntry.sys.id) {
3653
- const entry = linkOrEntry;
3654
- acc[key] = {
3655
- sys: {
3656
- id: entry.sys.id,
3657
- linkType: 'Entry',
3658
- type: 'Link',
3659
- },
3660
- };
3661
- }
3662
- else {
3663
- const link = linkOrEntry;
3664
- acc[key] = link;
3665
- }
3666
- return acc;
3667
- }, {});
3668
- experienceEntry.fields.dataSource = newDataSource;
3669
- };
3670
-
3671
3590
  const errorMessagesWhileFetching$1 = {
3672
3591
  experience: 'Failed to fetch experience',
3673
3592
  experienceReferences: 'Failed to fetch entities, referenced in experience',
@@ -3681,7 +3600,7 @@ const handleError$1 = (generalMessage, error) => {
3681
3600
  * @param {FetchBySlugParams} options - options to fetch the experience
3682
3601
  */
3683
3602
  async function fetchBySlug({ client, experienceTypeId, slug, localeCode, isEditorMode, }) {
3684
- // Be a no-op if in editor mode
3603
+ //Be a no-op if in editor mode
3685
3604
  if (isEditorMode)
3686
3605
  return;
3687
3606
  let experienceEntry = undefined;
@@ -3697,8 +3616,6 @@ async function fetchBySlug({ client, experienceTypeId, slug, localeCode, isEdito
3697
3616
  if (!experienceEntry) {
3698
3617
  throw new Error(`No experience entry with slug: ${slug} exists`);
3699
3618
  }
3700
- removeCircularPatternReferences(experienceEntry);
3701
- removeSelfReferencingDataSource(experienceEntry);
3702
3619
  try {
3703
3620
  const { entries, assets } = await fetchReferencedEntities({
3704
3621
  client,
@@ -3751,8 +3668,6 @@ async function fetchById({ client, experienceTypeId, id, localeCode, isEditorMod
3751
3668
  if (!experienceEntry) {
3752
3669
  throw new Error(`No experience entry with id: ${id} exists`);
3753
3670
  }
3754
- removeCircularPatternReferences(experienceEntry);
3755
- removeSelfReferencingDataSource(experienceEntry);
3756
3671
  try {
3757
3672
  const { entries, assets } = await fetchReferencedEntities({
3758
3673
  client,