@se-studio/contentful-rest-api 1.0.36 → 1.0.38

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
@@ -41,7 +41,7 @@ type BaseMediaSkeleton = EntrySkeletonType<BaseMediaFields, 'media'>;
41
41
 
42
42
  interface BaseSchemaFields {
43
43
  cmsLabel: EntryFieldTypes.Symbol;
44
- markup: EntryFieldTypes.Object;
44
+ markup?: EntryFieldTypes.Text;
45
45
  }
46
46
  type BaseSchemaSkeleton = EntrySkeletonType<BaseSchemaFields, 'schema'>;
47
47
 
@@ -61,7 +61,6 @@ interface BaseArticleTypeFields {
61
61
  name: EntryFieldTypes.Symbol;
62
62
  slug: EntryFieldTypes.Symbol;
63
63
  indexPageName: EntryFieldTypes.Symbol;
64
- indexPageSlug: EntryFieldTypes.Symbol;
65
64
  indexPageDescription: EntryFieldTypes.Symbol;
66
65
  featuredImage: EntryFieldTypes.AssetLink;
67
66
  menu?: EntryFieldTypes.EntryLink<BaseNavigationSkeleton>;
@@ -324,7 +323,6 @@ interface BaseCustomTypeFields {
324
323
  name: EntryFieldTypes.Symbol;
325
324
  slug: EntryFieldTypes.Symbol;
326
325
  indexPageName: EntryFieldTypes.Symbol;
327
- indexPageSlug: EntryFieldTypes.Symbol;
328
326
  indexPageDescription: EntryFieldTypes.Symbol;
329
327
  featuredImage: EntryFieldTypes.AssetLink;
330
328
  menu?: EntryFieldTypes.EntryLink<BaseNavigationSkeleton>;
@@ -383,7 +381,7 @@ interface CmsResponse<T> {
383
381
  }
384
382
 
385
383
  declare function baseArticleConverter(context: ConverterContext, entry: Entry<BaseArticleSkeleton, DefaultChainModifier, string>): IBaseArticle;
386
- declare function baseArticleTypeConverter(context: ConverterContext, entry: Entry<BaseArticleTypeSkeleton, DefaultChainModifier, string>): IBaseArticleType;
384
+ declare function baseArticleTypeConverter(context: ConverterContext, entry: Entry<BaseArticleTypeSkeleton, DefaultChainModifier, string>, customTypeEntry?: Entry<BaseCustomTypeSkeleton, DefaultChainModifier, string>): IBaseArticleType;
387
385
 
388
386
  type IContentfulCollection<TContents = BaseCollectionContent> = IBaseCollection<TContents> & {
389
387
  body?: IContentfulRichText | null;
@@ -405,7 +403,7 @@ declare function basePageConverter(context: ConverterContext, entry: Entry<BaseP
405
403
  declare function calculatePageHref(slug: string): string;
406
404
  declare function calculatePageVariantHref(slug: string): string;
407
405
 
408
- declare function baseTagConverter(context: ConverterContext, entry: Entry<BaseTagSkeleton, DefaultChainModifier, string>): IBaseTag;
406
+ declare function baseTagConverter(context: ConverterContext, entry: Entry<BaseTagSkeleton, DefaultChainModifier, string>, customTypeEntry?: Entry<BaseCustomTypeSkeleton, DefaultChainModifier, string>): IBaseTag;
409
407
 
410
408
  declare function lookupAsset(context: ConverterContext, asset: UnresolvedLink<'Asset'> | undefined): IVisual | undefined;
411
409
  type ContentResolverFunction = (context: ConverterContext, entry: Entry<BaseContent, DefaultChainModifier, string>) => unknown;
@@ -445,7 +443,10 @@ type ConverterContext = BaseConverterContext & {
445
443
 
446
444
  declare function contentfulArticleRest(context: BaseConverterContext, config: ContentfulConfig, slug: string, articleTypeSlug: string, options?: FetchOptions): Promise<CmsResponse<IBaseArticle | null>>;
447
445
 
448
- declare function contentfulArticleTypeRest(context: BaseConverterContext, config: ContentfulConfig, indexPageSlug: string, options?: FetchOptions): Promise<CmsResponse<IBaseArticleType | null>>;
446
+ interface ArticleTypeFetchOptions extends FetchOptions {
447
+ customType?: string;
448
+ }
449
+ declare function contentfulArticleTypeRest(context: BaseConverterContext, config: ContentfulConfig, slug: string, options?: ArticleTypeFetchOptions): Promise<CmsResponse<IBaseArticleType | null>>;
449
450
 
450
451
  interface ContentfulResponse<T = any> {
451
452
  sys: {
@@ -523,7 +524,7 @@ declare function createDownloadHandler(config: DownloadHandlerConfig): (_request
523
524
 
524
525
  declare function createBaseConverterContext(urlCalculators: UrlCalculators): BaseConverterContext;
525
526
 
526
- declare function contentfulCustomTypeRest(context: BaseConverterContext, config: ContentfulConfig, indexPageSlug: string, options?: FetchOptions): Promise<CmsResponse<IBaseCustomType | null>>;
527
+ declare function contentfulCustomTypeRest(context: BaseConverterContext, config: ContentfulConfig, slug: string, options?: FetchOptions): Promise<CmsResponse<IBaseCustomType | null>>;
527
528
 
528
529
  type DefaultChainModifier = 'WITHOUT_LINK_RESOLUTION';
529
530
  interface IContentfulRichText {
@@ -595,7 +596,10 @@ declare function contentfulPersonSitemapEntries(context: BaseConverterContext, c
595
596
  declare function getAllSitemapEntries(context: BaseConverterContext, config: ContentfulConfig, sitemapConfig: SitemapConfig, options?: FetchOptions): Promise<CmsResponse<ISitemapEntry[]>>;
596
597
  declare function createSitemapProvider(fetcher: (context: BaseConverterContext, config: ContentfulConfig, sitemapConfig?: SitemapContentTypeConfig, options?: FetchOptions) => Promise<CmsResponse<ISitemapEntry[]>>, sitemapConfig?: SitemapContentTypeConfig): SitemapEntryProvider;
597
598
 
598
- declare function contentfulTagRest(context: BaseConverterContext, config: ContentfulConfig, slug: string, options?: FetchOptions): Promise<CmsResponse<IBaseTag | null>>;
599
+ interface TagFetchOptions extends FetchOptions {
600
+ customType?: string;
601
+ }
602
+ declare function contentfulTagRest(context: BaseConverterContext, config: ContentfulConfig, slug: string, options?: TagFetchOptions): Promise<CmsResponse<IBaseTag | null>>;
599
603
 
600
604
  interface IFetchedTemplate {
601
605
  id: string;
@@ -705,4 +709,4 @@ declare class RateLimiter {
705
709
  getIntervalMs(): number;
706
710
  }
707
711
 
708
- export { AllTags, ArticleTag, ArticleTypeTag, AssetTag, AuthenticationError, BannerTag, type BaseConverterContext, type CmsError, type CmsResponse, type ContentResolverFunction, ContentfulFetchClient as ContentfulClient, type ContentfulConfig, ContentfulError, ContentfulFetchClient, type ConverterContext, CustomTypeTag, type DefaultChainModifier, type DownloadHandlerConfig, type DownloadRouteParams, EntryNotFoundError, type FetchOptions, GlobalTag, type IContentfulCollection, type IContentfulComponent, type IContentfulPerson, type IContentfulRichText, type IFetchedTemplate, type ISitemapEntry, LocationTag, NavigationTag, PageTag, PersonTag, type PreviewContentType, type PreviewEntryInfo, RateLimitError, RateLimiter, type RelatedArticlesOptions, type RetryConfig, type RevalidationConfig, type SitemapChangeFrequency, type SitemapConfig, type SitemapContentTypeConfig, type SitemapEntryProvider, TagTag, TemplateTag, type UrlCalculators, ValidationError, arrayOrUndefined, articleTag, articleTypeIndexTag, articleTypeTag, assetTag, basePageConverter, calculateBackoffDelay, calculatePageHref, calculatePageVariantHref, contentfulAllArticleLinks, contentfulAllArticleTypeLinks, contentfulAllPageLinks, contentfulAllPersonLinks, contentfulAllTagLinks, contentfulArticleRest, contentfulArticleSitemapEntries, contentfulArticleTypeRest, contentfulArticleTypeSitemapEntries, contentfulAssetRest, contentfulCustomTypeRest, contentfulPageRest, contentfulPageSitemapEntries, contentfulPersonRest, contentfulPersonSitemapEntries, contentfulTagRest, contentfulTagSitemapEntries, contentfulTemplateRest, createBaseConverterContext, createContentfulClient, createContentfulPreviewClient, createDownloadHandler, createResponsiveVisual, createRevalidationHandler, createSitemapProvider, customTypeTag, filterRelatedArticles, getAllSitemapEntries, getCacheTags, getCacheTagsForPreview, getCacheTagsForProduction, getContentfulClient, getPreviewEntryInfo, getRetryAfter, isBrowserViewable, isContentfulError, isRateLimitError, isRetryableError, isValidDate, locationTag, lookupAsset, notEmpty, pageTag, personTag, resolveLink, resolveLinks, resolveRichTextDocument, revalidateSingleTag, revalidateTags, safeDate, tagTag, templateTag, withRetry };
712
+ export { AllTags, ArticleTag, type ArticleTypeFetchOptions, ArticleTypeTag, AssetTag, AuthenticationError, BannerTag, type BaseConverterContext, type CmsError, type CmsResponse, type ContentResolverFunction, ContentfulFetchClient as ContentfulClient, type ContentfulConfig, ContentfulError, ContentfulFetchClient, type ConverterContext, CustomTypeTag, type DefaultChainModifier, type DownloadHandlerConfig, type DownloadRouteParams, EntryNotFoundError, type FetchOptions, GlobalTag, type IContentfulCollection, type IContentfulComponent, type IContentfulPerson, type IContentfulRichText, type IFetchedTemplate, type ISitemapEntry, LocationTag, NavigationTag, PageTag, type PersonFetchOptions, PersonTag, type PreviewContentType, type PreviewEntryInfo, RateLimitError, RateLimiter, type RelatedArticlesOptions, type RetryConfig, type RevalidationConfig, type SitemapChangeFrequency, type SitemapConfig, type SitemapContentTypeConfig, type SitemapEntryProvider, type TagFetchOptions, TagTag, TemplateTag, type UrlCalculators, ValidationError, arrayOrUndefined, articleTag, articleTypeIndexTag, articleTypeTag, assetTag, basePageConverter, calculateBackoffDelay, calculatePageHref, calculatePageVariantHref, contentfulAllArticleLinks, contentfulAllArticleTypeLinks, contentfulAllPageLinks, contentfulAllPersonLinks, contentfulAllTagLinks, contentfulArticleRest, contentfulArticleSitemapEntries, contentfulArticleTypeRest, contentfulArticleTypeSitemapEntries, contentfulAssetRest, contentfulCustomTypeRest, contentfulPageRest, contentfulPageSitemapEntries, contentfulPersonRest, contentfulPersonSitemapEntries, contentfulTagRest, contentfulTagSitemapEntries, contentfulTemplateRest, createBaseConverterContext, createContentfulClient, createContentfulPreviewClient, createDownloadHandler, createResponsiveVisual, createRevalidationHandler, createSitemapProvider, customTypeTag, filterRelatedArticles, getAllSitemapEntries, getCacheTags, getCacheTagsForPreview, getCacheTagsForProduction, getContentfulClient, getPreviewEntryInfo, getRetryAfter, isBrowserViewable, isContentfulError, isRateLimitError, isRetryableError, isValidDate, locationTag, lookupAsset, notEmpty, pageTag, personTag, resolveLink, resolveLinks, resolveRichTextDocument, revalidateSingleTag, revalidateTags, safeDate, tagTag, templateTag, withRetry };
package/dist/index.js CHANGED
@@ -1175,6 +1175,13 @@ async function fetchSingleEntity(context, config, fetchConfig, options) {
1175
1175
  },
1176
1176
  requestOptions
1177
1177
  );
1178
+ if (typeof process !== "undefined" && process.env?.NODE_ENV !== "production") {
1179
+ console.log(`[Contentful Fetch] ${fetchConfig.contentType}`, {
1180
+ query: fetchConfig.query,
1181
+ cacheTags,
1182
+ total: response.total
1183
+ });
1184
+ }
1178
1185
  const entry = response.items[0];
1179
1186
  if (!entry || !entry.fields) {
1180
1187
  return { data: null, errors: [] };
@@ -1315,20 +1322,97 @@ async function contentfulArticleRest(context, config, slug, articleTypeSlug, opt
1315
1322
  }
1316
1323
 
1317
1324
  // src/api/article-type.ts
1318
- async function contentfulArticleTypeRest(context, config, indexPageSlug, options) {
1319
- return fetchSingleEntity(
1320
- context,
1321
- config,
1322
- {
1323
- contentType: "articleType",
1324
- cacheTagType: "articleType",
1325
- cacheTagIdentifier: indexPageSlug,
1326
- query: { "fields.indexPageSlug": indexPageSlug },
1327
- resolver: (ctx, entry) => ctx.articleTypeResolver(ctx, entry),
1328
- errorLogContext: { indexPageSlug }
1329
- },
1330
- options
1331
- );
1325
+ init_utils();
1326
+ async function contentfulArticleTypeRest(context, config, slug, options) {
1327
+ const client = getContentfulClient(config, options?.preview);
1328
+ const articleTypeCacheTags = getCacheTags("articleType", slug, options?.preview);
1329
+ const customTypeCacheTags = options?.customType ? getCacheTags("customType", options.customType, options?.preview) : [];
1330
+ const requestOptions = {
1331
+ ...options,
1332
+ next: {
1333
+ ...options?.next,
1334
+ tags: [...articleTypeCacheTags, ...customTypeCacheTags]
1335
+ }
1336
+ };
1337
+ const fetchFn = async () => {
1338
+ const articleTypePromise = client.getEntries(
1339
+ {
1340
+ content_type: "articleType",
1341
+ "fields.slug": slug,
1342
+ include: 10,
1343
+ locale: options?.locale,
1344
+ limit: 1
1345
+ },
1346
+ requestOptions
1347
+ );
1348
+ const customTypePromise = options?.customType ? client.getEntries(
1349
+ {
1350
+ content_type: "customType",
1351
+ "fields.slug": options.customType,
1352
+ include: 10,
1353
+ locale: options?.locale,
1354
+ limit: 1
1355
+ },
1356
+ requestOptions
1357
+ ) : Promise.resolve(null);
1358
+ const [articleTypeResponse, customTypeResponse] = await Promise.all([
1359
+ articleTypePromise,
1360
+ customTypePromise
1361
+ ]);
1362
+ const articleTypeEntry = articleTypeResponse.items[0];
1363
+ if (!articleTypeEntry || !articleTypeEntry.fields) {
1364
+ return { data: null, errors: [] };
1365
+ }
1366
+ const customTypeEntry = customTypeResponse?.items[0];
1367
+ try {
1368
+ const assets = convertAllAssets(articleTypeResponse, context);
1369
+ const rawAssets = convertAllRawAssets(articleTypeResponse);
1370
+ const includes = convertAllIncludes(articleTypeResponse);
1371
+ if (customTypeResponse) {
1372
+ const customAssets = convertAllAssets(customTypeResponse, context);
1373
+ const customRawAssets = convertAllRawAssets(customTypeResponse);
1374
+ const customIncludes = convertAllIncludes(customTypeResponse);
1375
+ for (const [key, value] of customAssets) assets.set(key, value);
1376
+ for (const [key, value] of customRawAssets) rawAssets.set(key, value);
1377
+ for (const [key, value] of customIncludes) includes.set(key, value);
1378
+ }
1379
+ const fullContext = {
1380
+ ...context,
1381
+ includes,
1382
+ assets,
1383
+ rawAssets,
1384
+ errors: []
1385
+ };
1386
+ const converted = context.articleTypeResolver(fullContext, articleTypeEntry, customTypeEntry);
1387
+ if (converted?.icons && converted.icons.length > 0) {
1388
+ const processedIcons = await processIconsForSprite(converted.icons);
1389
+ converted.icons = processedIcons.length > 0 ? processedIcons : void 0;
1390
+ }
1391
+ if (fullContext.errors.length > 0 && typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
1392
+ console.error(`CMS conversion errors for articleType:`, {
1393
+ entryId: articleTypeEntry.sys.id,
1394
+ slug,
1395
+ errors: fullContext.errors
1396
+ });
1397
+ }
1398
+ return { data: converted, errors: fullContext.errors };
1399
+ } catch (error) {
1400
+ const entryId = articleTypeEntry?.sys.id || "unknown";
1401
+ const entryType = articleTypeEntry?.sys.contentType?.sys?.id;
1402
+ const errorMessage = error instanceof Error ? error.message : "Unknown conversion error";
1403
+ const cmsError = {
1404
+ entryId,
1405
+ entryType,
1406
+ message: errorMessage,
1407
+ error
1408
+ };
1409
+ return { data: null, errors: [cmsError] };
1410
+ }
1411
+ };
1412
+ if (options?.retry) {
1413
+ return await withRetry(fetchFn, options.retry);
1414
+ }
1415
+ return await fetchFn();
1332
1416
  }
1333
1417
 
1334
1418
  // src/api/asset.ts
@@ -1405,6 +1489,18 @@ function createDownloadHandler(config) {
1405
1489
  };
1406
1490
  }
1407
1491
 
1492
+ // src/converters/schema.ts
1493
+ function baseSchemaConverter(_context, entry) {
1494
+ const { sys, fields } = entry;
1495
+ const { cmsLabel, markup } = fields;
1496
+ return {
1497
+ id: sys.id,
1498
+ name: cmsLabel,
1499
+ markup: markup ?? "",
1500
+ description: `Schema for ${cmsLabel}`
1501
+ };
1502
+ }
1503
+
1408
1504
  // src/converters/resolver.ts
1409
1505
  function resolveHelper(context, fromId, entry, getResolver) {
1410
1506
  const id = entry.sys.id;
@@ -1431,6 +1527,14 @@ function resolveHelper(context, fromId, entry, getResolver) {
1431
1527
  }
1432
1528
  return possibleEntry.resolved;
1433
1529
  }
1530
+ function resolveSchema(context, fromId, entry) {
1531
+ return resolveHelper(
1532
+ context,
1533
+ fromId,
1534
+ entry,
1535
+ () => baseSchemaConverter
1536
+ );
1537
+ }
1434
1538
  function resolveLink(context, fromId, entry) {
1435
1539
  return resolveHelper(
1436
1540
  context,
@@ -1853,6 +1957,7 @@ function baseArticleConverter(context, entry) {
1853
1957
  topContent: topContentLinks,
1854
1958
  bottomContent: bottomContentLinks,
1855
1959
  articleType,
1960
+ structuredData,
1856
1961
  ...simpleFields
1857
1962
  } = fields;
1858
1963
  const articleTypeLink = resolveLink(context, id, articleType);
@@ -1887,6 +1992,7 @@ function baseArticleConverter(context, entry) {
1887
1992
  tags: tags?.map((tag) => resolveLink(context, id, tag)),
1888
1993
  contents,
1889
1994
  icons,
1995
+ structuredData: structuredData?.map((link) => resolveSchema(context, id, link)).filter((item) => item !== null),
1890
1996
  ...simpleFields,
1891
1997
  // Note: summary field exists in Contentful but is not part of IArticle interface
1892
1998
  // Keeping it in simpleFields for potential future use
@@ -1931,29 +2037,25 @@ function baseArticleTypeLinkConverter(context, entry) {
1931
2037
  `Invalid content type: expected "articleType", got "${sys.contentType.sys.id}"`
1932
2038
  );
1933
2039
  }
2040
+ const { name, featuredImage, slug, ...simpleFields } = fields;
1934
2041
  return createInternalLink(
1935
2042
  sys.id,
1936
2043
  {
1937
- cmsLabel: fields.name,
1938
- title: fields.name,
1939
- featuredImage: fields.featuredImage,
1940
- backgroundColour: fields.backgroundColour,
1941
- textColour: fields.textColour,
1942
- indexed: fields.indexed,
1943
- hidden: fields.hidden,
1944
- slug: fields.slug
2044
+ cmsLabel: name,
2045
+ title: name,
2046
+ featuredImage,
2047
+ slug,
2048
+ ...simpleFields
1945
2049
  },
1946
2050
  context,
1947
- context.urlCalculators.articleType(fields.slug),
1948
- "ArticleType",
1949
- { indexPageSlug: fields.indexPageSlug }
2051
+ context.urlCalculators.articleType(slug),
2052
+ "ArticleType"
1950
2053
  );
1951
2054
  }
1952
- function baseArticleTypeConverter(context, entry) {
2055
+ function baseArticleTypeConverter(context, entry, customTypeEntry) {
1953
2056
  const { sys, fields } = entry;
1954
2057
  const { id } = sys;
1955
2058
  const {
1956
- indexPageSlug,
1957
2059
  indexPageName,
1958
2060
  indexPageDescription,
1959
2061
  featuredImage,
@@ -1962,12 +2064,17 @@ function baseArticleTypeConverter(context, entry) {
1962
2064
  indexPageTemplate: templateLink,
1963
2065
  indexPageTopContent: topContentLinks,
1964
2066
  structuredData,
1965
- slug: _slug,
2067
+ indexPageStructuredData,
2068
+ slug,
1966
2069
  ...other
1967
2070
  } = fields;
1968
- const template = templateLink ? resolveTemplate(context, templateLink) : null;
1969
- const menu = menuLink ? resolveNavigation(context, menuLink) : template?.menu;
1970
- const footer = footerLink ? resolveNavigation(context, footerLink) : template?.footer;
2071
+ const customType = customTypeEntry ? context.customTypeResolver(context, customTypeEntry) : void 0;
2072
+ let template = templateLink ? resolveTemplate(context, templateLink) : null;
2073
+ if (!template && customTypeEntry?.fields.template) {
2074
+ template = resolveTemplate(context, customTypeEntry.fields.template);
2075
+ }
2076
+ const menu = menuLink ? resolveNavigation(context, menuLink) : customTypeEntry?.fields.menu ? resolveNavigation(context, customTypeEntry.fields.menu) : template?.menu;
2077
+ const footer = footerLink ? resolveNavigation(context, footerLink) : customTypeEntry?.fields.footer ? resolveNavigation(context, customTypeEntry.fields.footer) : template?.footer;
1971
2078
  const topContent = topContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
1972
2079
  const preContent = template?.preContent ?? [];
1973
2080
  const postContent = template?.postContent ?? [];
@@ -1982,17 +2089,23 @@ function baseArticleTypeConverter(context, entry) {
1982
2089
  const articleType = {
1983
2090
  type: "Article type",
1984
2091
  id,
1985
- slug: indexPageSlug,
2092
+ slug,
1986
2093
  title: makeContentfulTitle(indexPageName, sys.id),
1987
2094
  description: makeContentfulDescription(indexPageDescription, sys.id),
1988
2095
  featuredImage: lookupAsset(context, featuredImage),
1989
2096
  contents,
1990
2097
  icons,
1991
- structuredData,
2098
+ structuredData: [
2099
+ ...structuredData?.map((link) => resolveSchema(context, id, link)) ?? [],
2100
+ ...indexPageStructuredData?.map((link) => resolveSchema(context, id, link)) ?? []
2101
+ ].filter((item) => item !== null),
1992
2102
  menu: finalMenu,
1993
2103
  footer: finalFooter,
1994
2104
  ...other
1995
2105
  };
2106
+ if (customType) {
2107
+ articleType.customType = customType;
2108
+ }
1996
2109
  return articleType;
1997
2110
  }
1998
2111
 
@@ -2106,7 +2219,6 @@ function baseCustomTypeConverter(context, entry) {
2106
2219
  const { id } = sys;
2107
2220
  const {
2108
2221
  slug,
2109
- indexPageSlug,
2110
2222
  indexPageName,
2111
2223
  indexPageDescription,
2112
2224
  featuredImage,
@@ -2115,6 +2227,7 @@ function baseCustomTypeConverter(context, entry) {
2115
2227
  indexPageTemplate: templateLink,
2116
2228
  indexPageTopContent: topContentLinks,
2117
2229
  structuredData,
2230
+ indexPageStructuredData,
2118
2231
  ...other
2119
2232
  } = fields;
2120
2233
  const template = templateLink ? resolveTemplate(context, templateLink) : null;
@@ -2133,7 +2246,6 @@ function baseCustomTypeConverter(context, entry) {
2133
2246
  type: "Custom type",
2134
2247
  id,
2135
2248
  slug,
2136
- indexPageSlug,
2137
2249
  indexPageName: makeContentfulTitle(indexPageName, sys.id),
2138
2250
  indexPageDescription: makeContentfulDescription(indexPageDescription, sys.id),
2139
2251
  title: makeContentfulTitle(indexPageName, sys.id),
@@ -2141,7 +2253,10 @@ function baseCustomTypeConverter(context, entry) {
2141
2253
  featuredImage: lookupAsset(context, featuredImage),
2142
2254
  contents,
2143
2255
  icons,
2144
- structuredData,
2256
+ structuredData: [
2257
+ ...structuredData?.map((link) => resolveSchema(context, id, link)) ?? [],
2258
+ ...indexPageStructuredData?.map((link) => resolveSchema(context, id, link)) ?? []
2259
+ ].filter((item) => item !== null),
2145
2260
  menu,
2146
2261
  footer,
2147
2262
  ...other
@@ -2166,10 +2281,10 @@ function baseCustomTypeLinkConverter(context, entry) {
2166
2281
  textColour: fields.textColour,
2167
2282
  indexed: fields.indexed,
2168
2283
  hidden: fields.hidden,
2169
- slug: fields.indexPageSlug
2284
+ slug: fields.slug
2170
2285
  },
2171
2286
  context,
2172
- context.urlCalculators.customType(fields.indexPageSlug),
2287
+ context.urlCalculators.customType(fields.slug),
2173
2288
  "CustomType"
2174
2289
  );
2175
2290
  }
@@ -2292,6 +2407,7 @@ function basePageConverter(context, entry) {
2292
2407
  template: templateLink,
2293
2408
  topContent: topContentLinks,
2294
2409
  bottomContent: bottomContentLinks,
2410
+ structuredData,
2295
2411
  ...simpleFields
2296
2412
  } = fields;
2297
2413
  const pageMenuNav = pageMenu ? resolveNavigation(context, pageMenu) : void 0;
@@ -2327,6 +2443,7 @@ function basePageConverter(context, entry) {
2327
2443
  tags: tags?.map((tag) => resolveLink(context, id, tag)),
2328
2444
  contents,
2329
2445
  icons,
2446
+ structuredData: structuredData?.map((link) => resolveSchema(context, id, link)).filter((item) => item !== null),
2330
2447
  ...simpleFields,
2331
2448
  menu: finalMenu,
2332
2449
  footer: finalFooter
@@ -2442,7 +2559,16 @@ function basePersonConverter(context, entry, customTypeEntry) {
2442
2559
  if (contentType.sys.id !== "person") {
2443
2560
  throw new Error(`Invalid content type: expected "person", got "${contentType.sys.id}"`);
2444
2561
  }
2445
- const { slug, name, description, media, bio: bioField, content: contentLinks, ...rest } = fields;
2562
+ const {
2563
+ slug,
2564
+ name,
2565
+ description,
2566
+ media,
2567
+ bio: bioField,
2568
+ content: contentLinks,
2569
+ structuredData,
2570
+ ...rest
2571
+ } = fields;
2446
2572
  const customType = customTypeEntry ? context.customTypeResolver(context, customTypeEntry) : void 0;
2447
2573
  const template = customTypeEntry?.fields.template ? resolveTemplate(context, customTypeEntry.fields.template) : null;
2448
2574
  const personContent = contentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
@@ -2471,6 +2597,7 @@ function basePersonConverter(context, entry, customTypeEntry) {
2471
2597
  footer,
2472
2598
  icons,
2473
2599
  customType,
2600
+ structuredData: structuredData?.map((link) => resolveSchema(context, id, link)).filter((item) => item !== null),
2474
2601
  ...rest
2475
2602
  };
2476
2603
  }
@@ -2493,7 +2620,7 @@ function baseTagLinkConverter(context, entry) {
2493
2620
  "Tag"
2494
2621
  );
2495
2622
  }
2496
- function baseTagConverter(context, entry) {
2623
+ function baseTagConverter(context, entry, customTypeEntry) {
2497
2624
  const { sys, fields } = entry;
2498
2625
  const { id } = sys;
2499
2626
  const {
@@ -2506,11 +2633,16 @@ function baseTagConverter(context, entry) {
2506
2633
  footer: footerLink,
2507
2634
  template: templateLink,
2508
2635
  topContent: topContentLinks,
2636
+ structuredData,
2509
2637
  ...rest
2510
2638
  } = fields;
2511
- const template = templateLink ? resolveTemplate(context, templateLink) : null;
2512
- const menu = menuLink ? resolveNavigation(context, menuLink) : template?.menu;
2513
- const footer = footerLink ? resolveNavigation(context, footerLink) : template?.footer;
2639
+ const customType = customTypeEntry ? context.customTypeResolver(context, customTypeEntry) : void 0;
2640
+ let template = templateLink ? resolveTemplate(context, templateLink) : null;
2641
+ if (!template && customTypeEntry?.fields.template) {
2642
+ template = resolveTemplate(context, customTypeEntry.fields.template);
2643
+ }
2644
+ const menu = menuLink ? resolveNavigation(context, menuLink) : customTypeEntry?.fields.menu ? resolveNavigation(context, customTypeEntry.fields.menu) : template?.menu;
2645
+ const footer = footerLink ? resolveNavigation(context, footerLink) : customTypeEntry?.fields.footer ? resolveNavigation(context, customTypeEntry.fields.footer) : template?.footer;
2514
2646
  const topContent = topContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
2515
2647
  const preContent = template?.preContent ?? [];
2516
2648
  const postContent = template?.postContent ?? [];
@@ -2532,10 +2664,14 @@ function baseTagConverter(context, entry) {
2532
2664
  tagType: tagTypeName ?? null,
2533
2665
  contents,
2534
2666
  icons,
2667
+ structuredData: structuredData?.map((link) => resolveSchema(context, id, link)).filter((item) => item !== null),
2535
2668
  ...rest,
2536
2669
  menu,
2537
2670
  footer
2538
2671
  };
2672
+ if (customType) {
2673
+ tag.customType = customType;
2674
+ }
2539
2675
  return tag;
2540
2676
  }
2541
2677
 
@@ -2578,17 +2714,17 @@ function createBaseConverterContext(urlCalculators) {
2578
2714
  }
2579
2715
 
2580
2716
  // src/api/custom-type.ts
2581
- async function contentfulCustomTypeRest(context, config, indexPageSlug, options) {
2717
+ async function contentfulCustomTypeRest(context, config, slug, options) {
2582
2718
  return fetchSingleEntity(
2583
2719
  context,
2584
2720
  config,
2585
2721
  {
2586
2722
  contentType: "customType",
2587
2723
  cacheTagType: "customType",
2588
- cacheTagIdentifier: indexPageSlug,
2589
- query: { "fields.indexPageSlug": indexPageSlug },
2724
+ cacheTagIdentifier: slug,
2725
+ query: { "fields.slug": slug },
2590
2726
  resolver: (ctx, entry) => ctx.customTypeResolver(ctx, entry),
2591
- errorLogContext: { indexPageSlug }
2727
+ errorLogContext: { slug }
2592
2728
  },
2593
2729
  options
2594
2730
  );
@@ -2882,7 +3018,7 @@ async function getPreviewEntryInfo(context, config, entryId, options) {
2882
3018
  };
2883
3019
  }
2884
3020
  case "articleType": {
2885
- const slug = fields.indexPageSlug ?? fields.slug;
3021
+ const slug = fields.slug;
2886
3022
  if (!slug) return null;
2887
3023
  return {
2888
3024
  contentType: "articleType",
@@ -2912,7 +3048,7 @@ async function getPreviewEntryInfo(context, config, entryId, options) {
2912
3048
  };
2913
3049
  }
2914
3050
  case "customType": {
2915
- const slug = fields.indexPageSlug ?? fields.slug;
3051
+ const slug = fields.slug;
2916
3052
  if (!slug) return null;
2917
3053
  return {
2918
3054
  contentType: "customType",
@@ -3063,20 +3199,94 @@ function createSitemapProvider(fetcher, sitemapConfig) {
3063
3199
  }
3064
3200
 
3065
3201
  // src/api/tag.ts
3202
+ init_utils();
3066
3203
  async function contentfulTagRest(context, config, slug, options) {
3067
- return fetchSingleEntity(
3068
- context,
3069
- config,
3070
- {
3071
- contentType: "tag",
3072
- cacheTagType: "tag",
3073
- cacheTagIdentifier: slug,
3074
- query: { "fields.slug": slug },
3075
- resolver: (ctx, entry) => ctx.tagResolver(ctx, entry),
3076
- errorLogContext: { slug }
3077
- },
3078
- options
3079
- );
3204
+ const client = getContentfulClient(config, options?.preview);
3205
+ const tagCacheTags = getCacheTags("tag", slug, options?.preview);
3206
+ const customTypeCacheTags = options?.customType ? getCacheTags("customType", options.customType, options?.preview) : [];
3207
+ const requestOptions = {
3208
+ ...options,
3209
+ next: {
3210
+ ...options?.next,
3211
+ tags: [...tagCacheTags, ...customTypeCacheTags]
3212
+ }
3213
+ };
3214
+ const fetchFn = async () => {
3215
+ const tagPromise = client.getEntries(
3216
+ {
3217
+ content_type: "tag",
3218
+ "fields.slug": slug,
3219
+ include: 10,
3220
+ locale: options?.locale,
3221
+ limit: 1
3222
+ },
3223
+ requestOptions
3224
+ );
3225
+ const customTypePromise = options?.customType ? client.getEntries(
3226
+ {
3227
+ content_type: "customType",
3228
+ "fields.slug": options.customType,
3229
+ include: 10,
3230
+ locale: options?.locale,
3231
+ limit: 1
3232
+ },
3233
+ requestOptions
3234
+ ) : Promise.resolve(null);
3235
+ const [tagResponse, customTypeResponse] = await Promise.all([tagPromise, customTypePromise]);
3236
+ const tagEntry = tagResponse.items[0];
3237
+ if (!tagEntry || !tagEntry.fields) {
3238
+ return { data: null, errors: [] };
3239
+ }
3240
+ const customTypeEntry = customTypeResponse?.items[0];
3241
+ try {
3242
+ const assets = convertAllAssets(tagResponse, context);
3243
+ const rawAssets = convertAllRawAssets(tagResponse);
3244
+ const includes = convertAllIncludes(tagResponse);
3245
+ if (customTypeResponse) {
3246
+ const customAssets = convertAllAssets(customTypeResponse, context);
3247
+ const customRawAssets = convertAllRawAssets(customTypeResponse);
3248
+ const customIncludes = convertAllIncludes(customTypeResponse);
3249
+ for (const [key, value] of customAssets) assets.set(key, value);
3250
+ for (const [key, value] of customRawAssets) rawAssets.set(key, value);
3251
+ for (const [key, value] of customIncludes) includes.set(key, value);
3252
+ }
3253
+ const fullContext = {
3254
+ ...context,
3255
+ includes,
3256
+ assets,
3257
+ rawAssets,
3258
+ errors: []
3259
+ };
3260
+ const converted = context.tagResolver(fullContext, tagEntry, customTypeEntry);
3261
+ if (converted?.icons && converted.icons.length > 0) {
3262
+ const processedIcons = await processIconsForSprite(converted.icons);
3263
+ converted.icons = processedIcons.length > 0 ? processedIcons : void 0;
3264
+ }
3265
+ if (fullContext.errors.length > 0 && typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
3266
+ console.error(`CMS conversion errors for tag:`, {
3267
+ entryId: tagEntry.sys.id,
3268
+ slug,
3269
+ errors: fullContext.errors
3270
+ });
3271
+ }
3272
+ return { data: converted, errors: fullContext.errors };
3273
+ } catch (error) {
3274
+ const entryId = tagEntry?.sys.id || "unknown";
3275
+ const entryType = tagEntry?.sys.contentType?.sys?.id;
3276
+ const errorMessage = error instanceof Error ? error.message : "Unknown conversion error";
3277
+ const cmsError = {
3278
+ entryId,
3279
+ entryType,
3280
+ message: errorMessage,
3281
+ error
3282
+ };
3283
+ return { data: null, errors: [cmsError] };
3284
+ }
3285
+ };
3286
+ if (options?.retry) {
3287
+ return await withRetry(fetchFn, options.retry);
3288
+ }
3289
+ return await fetchFn();
3080
3290
  }
3081
3291
 
3082
3292
  // src/api/template.ts
@@ -3135,13 +3345,9 @@ init_utils();
3135
3345
  var defaultLocale = "en-US";
3136
3346
  var articleTypeHandler = {
3137
3347
  extract: (data) => ({
3138
- slug: data.fields?.slug?.[defaultLocale],
3139
- indexPageSlug: data.fields?.indexPageSlug?.[defaultLocale]
3348
+ slug: data.fields?.slug?.[defaultLocale]
3140
3349
  }),
3141
- makeTags: (extracted) => [
3142
- extracted.slug ? articleTypeTag(extracted.slug) : void 0,
3143
- extracted.indexPageSlug ? articleTypeIndexTag(extracted.indexPageSlug) : void 0
3144
- ],
3350
+ makeTags: (extracted) => [extracted.slug ? articleTypeIndexTag(extracted.slug) : void 0],
3145
3351
  getGlobalTags: () => [ArticleTypeTag, ArticleTypeIndexTag]
3146
3352
  };
3147
3353
  var articleHandler = {