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

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
 
@@ -383,7 +383,7 @@ interface CmsResponse<T> {
383
383
  }
384
384
 
385
385
  declare function baseArticleConverter(context: ConverterContext, entry: Entry<BaseArticleSkeleton, DefaultChainModifier, string>): IBaseArticle;
386
- declare function baseArticleTypeConverter(context: ConverterContext, entry: Entry<BaseArticleTypeSkeleton, DefaultChainModifier, string>): IBaseArticleType;
386
+ declare function baseArticleTypeConverter(context: ConverterContext, entry: Entry<BaseArticleTypeSkeleton, DefaultChainModifier, string>, customTypeEntry?: Entry<BaseCustomTypeSkeleton, DefaultChainModifier, string>): IBaseArticleType;
387
387
 
388
388
  type IContentfulCollection<TContents = BaseCollectionContent> = IBaseCollection<TContents> & {
389
389
  body?: IContentfulRichText | null;
@@ -405,7 +405,7 @@ declare function basePageConverter(context: ConverterContext, entry: Entry<BaseP
405
405
  declare function calculatePageHref(slug: string): string;
406
406
  declare function calculatePageVariantHref(slug: string): string;
407
407
 
408
- declare function baseTagConverter(context: ConverterContext, entry: Entry<BaseTagSkeleton, DefaultChainModifier, string>): IBaseTag;
408
+ declare function baseTagConverter(context: ConverterContext, entry: Entry<BaseTagSkeleton, DefaultChainModifier, string>, customTypeEntry?: Entry<BaseCustomTypeSkeleton, DefaultChainModifier, string>): IBaseTag;
409
409
 
410
410
  declare function lookupAsset(context: ConverterContext, asset: UnresolvedLink<'Asset'> | undefined): IVisual | undefined;
411
411
  type ContentResolverFunction = (context: ConverterContext, entry: Entry<BaseContent, DefaultChainModifier, string>) => unknown;
@@ -445,7 +445,10 @@ type ConverterContext = BaseConverterContext & {
445
445
 
446
446
  declare function contentfulArticleRest(context: BaseConverterContext, config: ContentfulConfig, slug: string, articleTypeSlug: string, options?: FetchOptions): Promise<CmsResponse<IBaseArticle | null>>;
447
447
 
448
- declare function contentfulArticleTypeRest(context: BaseConverterContext, config: ContentfulConfig, indexPageSlug: string, options?: FetchOptions): Promise<CmsResponse<IBaseArticleType | null>>;
448
+ interface ArticleTypeFetchOptions extends FetchOptions {
449
+ customType?: string;
450
+ }
451
+ declare function contentfulArticleTypeRest(context: BaseConverterContext, config: ContentfulConfig, indexPageSlug: string, options?: ArticleTypeFetchOptions): Promise<CmsResponse<IBaseArticleType | null>>;
449
452
 
450
453
  interface ContentfulResponse<T = any> {
451
454
  sys: {
@@ -595,7 +598,10 @@ declare function contentfulPersonSitemapEntries(context: BaseConverterContext, c
595
598
  declare function getAllSitemapEntries(context: BaseConverterContext, config: ContentfulConfig, sitemapConfig: SitemapConfig, options?: FetchOptions): Promise<CmsResponse<ISitemapEntry[]>>;
596
599
  declare function createSitemapProvider(fetcher: (context: BaseConverterContext, config: ContentfulConfig, sitemapConfig?: SitemapContentTypeConfig, options?: FetchOptions) => Promise<CmsResponse<ISitemapEntry[]>>, sitemapConfig?: SitemapContentTypeConfig): SitemapEntryProvider;
597
600
 
598
- declare function contentfulTagRest(context: BaseConverterContext, config: ContentfulConfig, slug: string, options?: FetchOptions): Promise<CmsResponse<IBaseTag | null>>;
601
+ interface TagFetchOptions extends FetchOptions {
602
+ customType?: string;
603
+ }
604
+ declare function contentfulTagRest(context: BaseConverterContext, config: ContentfulConfig, slug: string, options?: TagFetchOptions): Promise<CmsResponse<IBaseTag | null>>;
599
605
 
600
606
  interface IFetchedTemplate {
601
607
  id: string;
@@ -705,4 +711,4 @@ declare class RateLimiter {
705
711
  getIntervalMs(): number;
706
712
  }
707
713
 
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 };
714
+ 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
1325
+ init_utils();
1318
1326
  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
- );
1327
+ const client = getContentfulClient(config, options?.preview);
1328
+ const articleTypeCacheTags = getCacheTags("articleType", indexPageSlug, 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.indexPageSlug": indexPageSlug,
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
+ indexPageSlug,
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
@@ -1949,7 +2055,7 @@ function baseArticleTypeLinkConverter(context, entry) {
1949
2055
  { indexPageSlug: fields.indexPageSlug }
1950
2056
  );
1951
2057
  }
1952
- function baseArticleTypeConverter(context, entry) {
2058
+ function baseArticleTypeConverter(context, entry, customTypeEntry) {
1953
2059
  const { sys, fields } = entry;
1954
2060
  const { id } = sys;
1955
2061
  const {
@@ -1962,12 +2068,17 @@ function baseArticleTypeConverter(context, entry) {
1962
2068
  indexPageTemplate: templateLink,
1963
2069
  indexPageTopContent: topContentLinks,
1964
2070
  structuredData,
2071
+ indexPageStructuredData,
1965
2072
  slug: _slug,
1966
2073
  ...other
1967
2074
  } = 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;
2075
+ const customType = customTypeEntry ? context.customTypeResolver(context, customTypeEntry) : void 0;
2076
+ let template = templateLink ? resolveTemplate(context, templateLink) : null;
2077
+ if (!template && customTypeEntry?.fields.indexPageTemplate) {
2078
+ template = resolveTemplate(context, customTypeEntry.fields.indexPageTemplate);
2079
+ }
2080
+ const menu = menuLink ? resolveNavigation(context, menuLink) : customTypeEntry?.fields.menu ? resolveNavigation(context, customTypeEntry.fields.menu) : template?.menu;
2081
+ const footer = footerLink ? resolveNavigation(context, footerLink) : customTypeEntry?.fields.footer ? resolveNavigation(context, customTypeEntry.fields.footer) : template?.footer;
1971
2082
  const topContent = topContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
1972
2083
  const preContent = template?.preContent ?? [];
1973
2084
  const postContent = template?.postContent ?? [];
@@ -1988,11 +2099,17 @@ function baseArticleTypeConverter(context, entry) {
1988
2099
  featuredImage: lookupAsset(context, featuredImage),
1989
2100
  contents,
1990
2101
  icons,
1991
- structuredData,
2102
+ structuredData: [
2103
+ ...structuredData?.map((link) => resolveSchema(context, id, link)) ?? [],
2104
+ ...indexPageStructuredData?.map((link) => resolveSchema(context, id, link)) ?? []
2105
+ ].filter((item) => item !== null),
1992
2106
  menu: finalMenu,
1993
2107
  footer: finalFooter,
1994
2108
  ...other
1995
2109
  };
2110
+ if (customType) {
2111
+ articleType.customType = customType;
2112
+ }
1996
2113
  return articleType;
1997
2114
  }
1998
2115
 
@@ -2115,6 +2232,7 @@ function baseCustomTypeConverter(context, entry) {
2115
2232
  indexPageTemplate: templateLink,
2116
2233
  indexPageTopContent: topContentLinks,
2117
2234
  structuredData,
2235
+ indexPageStructuredData,
2118
2236
  ...other
2119
2237
  } = fields;
2120
2238
  const template = templateLink ? resolveTemplate(context, templateLink) : null;
@@ -2141,7 +2259,10 @@ function baseCustomTypeConverter(context, entry) {
2141
2259
  featuredImage: lookupAsset(context, featuredImage),
2142
2260
  contents,
2143
2261
  icons,
2144
- structuredData,
2262
+ structuredData: [
2263
+ ...structuredData?.map((link) => resolveSchema(context, id, link)) ?? [],
2264
+ ...indexPageStructuredData?.map((link) => resolveSchema(context, id, link)) ?? []
2265
+ ].filter((item) => item !== null),
2145
2266
  menu,
2146
2267
  footer,
2147
2268
  ...other
@@ -2292,6 +2413,7 @@ function basePageConverter(context, entry) {
2292
2413
  template: templateLink,
2293
2414
  topContent: topContentLinks,
2294
2415
  bottomContent: bottomContentLinks,
2416
+ structuredData,
2295
2417
  ...simpleFields
2296
2418
  } = fields;
2297
2419
  const pageMenuNav = pageMenu ? resolveNavigation(context, pageMenu) : void 0;
@@ -2327,6 +2449,7 @@ function basePageConverter(context, entry) {
2327
2449
  tags: tags?.map((tag) => resolveLink(context, id, tag)),
2328
2450
  contents,
2329
2451
  icons,
2452
+ structuredData: structuredData?.map((link) => resolveSchema(context, id, link)).filter((item) => item !== null),
2330
2453
  ...simpleFields,
2331
2454
  menu: finalMenu,
2332
2455
  footer: finalFooter
@@ -2442,7 +2565,16 @@ function basePersonConverter(context, entry, customTypeEntry) {
2442
2565
  if (contentType.sys.id !== "person") {
2443
2566
  throw new Error(`Invalid content type: expected "person", got "${contentType.sys.id}"`);
2444
2567
  }
2445
- const { slug, name, description, media, bio: bioField, content: contentLinks, ...rest } = fields;
2568
+ const {
2569
+ slug,
2570
+ name,
2571
+ description,
2572
+ media,
2573
+ bio: bioField,
2574
+ content: contentLinks,
2575
+ structuredData,
2576
+ ...rest
2577
+ } = fields;
2446
2578
  const customType = customTypeEntry ? context.customTypeResolver(context, customTypeEntry) : void 0;
2447
2579
  const template = customTypeEntry?.fields.template ? resolveTemplate(context, customTypeEntry.fields.template) : null;
2448
2580
  const personContent = contentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
@@ -2471,6 +2603,7 @@ function basePersonConverter(context, entry, customTypeEntry) {
2471
2603
  footer,
2472
2604
  icons,
2473
2605
  customType,
2606
+ structuredData: structuredData?.map((link) => resolveSchema(context, id, link)).filter((item) => item !== null),
2474
2607
  ...rest
2475
2608
  };
2476
2609
  }
@@ -2493,7 +2626,7 @@ function baseTagLinkConverter(context, entry) {
2493
2626
  "Tag"
2494
2627
  );
2495
2628
  }
2496
- function baseTagConverter(context, entry) {
2629
+ function baseTagConverter(context, entry, customTypeEntry) {
2497
2630
  const { sys, fields } = entry;
2498
2631
  const { id } = sys;
2499
2632
  const {
@@ -2506,11 +2639,16 @@ function baseTagConverter(context, entry) {
2506
2639
  footer: footerLink,
2507
2640
  template: templateLink,
2508
2641
  topContent: topContentLinks,
2642
+ structuredData,
2509
2643
  ...rest
2510
2644
  } = 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;
2645
+ const customType = customTypeEntry ? context.customTypeResolver(context, customTypeEntry) : void 0;
2646
+ let template = templateLink ? resolveTemplate(context, templateLink) : null;
2647
+ if (!template && customTypeEntry?.fields.template) {
2648
+ template = resolveTemplate(context, customTypeEntry.fields.template);
2649
+ }
2650
+ const menu = menuLink ? resolveNavigation(context, menuLink) : customTypeEntry?.fields.menu ? resolveNavigation(context, customTypeEntry.fields.menu) : template?.menu;
2651
+ const footer = footerLink ? resolveNavigation(context, footerLink) : customTypeEntry?.fields.footer ? resolveNavigation(context, customTypeEntry.fields.footer) : template?.footer;
2514
2652
  const topContent = topContentLinks?.map((c) => resolvePageContent(context, id, c)).filter((item) => item !== null) ?? [];
2515
2653
  const preContent = template?.preContent ?? [];
2516
2654
  const postContent = template?.postContent ?? [];
@@ -2532,10 +2670,14 @@ function baseTagConverter(context, entry) {
2532
2670
  tagType: tagTypeName ?? null,
2533
2671
  contents,
2534
2672
  icons,
2673
+ structuredData: structuredData?.map((link) => resolveSchema(context, id, link)).filter((item) => item !== null),
2535
2674
  ...rest,
2536
2675
  menu,
2537
2676
  footer
2538
2677
  };
2678
+ if (customType) {
2679
+ tag.customType = customType;
2680
+ }
2539
2681
  return tag;
2540
2682
  }
2541
2683
 
@@ -3063,20 +3205,94 @@ function createSitemapProvider(fetcher, sitemapConfig) {
3063
3205
  }
3064
3206
 
3065
3207
  // src/api/tag.ts
3208
+ init_utils();
3066
3209
  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
- );
3210
+ const client = getContentfulClient(config, options?.preview);
3211
+ const tagCacheTags = getCacheTags("tag", slug, options?.preview);
3212
+ const customTypeCacheTags = options?.customType ? getCacheTags("customType", options.customType, options?.preview) : [];
3213
+ const requestOptions = {
3214
+ ...options,
3215
+ next: {
3216
+ ...options?.next,
3217
+ tags: [...tagCacheTags, ...customTypeCacheTags]
3218
+ }
3219
+ };
3220
+ const fetchFn = async () => {
3221
+ const tagPromise = client.getEntries(
3222
+ {
3223
+ content_type: "tag",
3224
+ "fields.slug": slug,
3225
+ include: 10,
3226
+ locale: options?.locale,
3227
+ limit: 1
3228
+ },
3229
+ requestOptions
3230
+ );
3231
+ const customTypePromise = options?.customType ? client.getEntries(
3232
+ {
3233
+ content_type: "customType",
3234
+ "fields.slug": options.customType,
3235
+ include: 10,
3236
+ locale: options?.locale,
3237
+ limit: 1
3238
+ },
3239
+ requestOptions
3240
+ ) : Promise.resolve(null);
3241
+ const [tagResponse, customTypeResponse] = await Promise.all([tagPromise, customTypePromise]);
3242
+ const tagEntry = tagResponse.items[0];
3243
+ if (!tagEntry || !tagEntry.fields) {
3244
+ return { data: null, errors: [] };
3245
+ }
3246
+ const customTypeEntry = customTypeResponse?.items[0];
3247
+ try {
3248
+ const assets = convertAllAssets(tagResponse, context);
3249
+ const rawAssets = convertAllRawAssets(tagResponse);
3250
+ const includes = convertAllIncludes(tagResponse);
3251
+ if (customTypeResponse) {
3252
+ const customAssets = convertAllAssets(customTypeResponse, context);
3253
+ const customRawAssets = convertAllRawAssets(customTypeResponse);
3254
+ const customIncludes = convertAllIncludes(customTypeResponse);
3255
+ for (const [key, value] of customAssets) assets.set(key, value);
3256
+ for (const [key, value] of customRawAssets) rawAssets.set(key, value);
3257
+ for (const [key, value] of customIncludes) includes.set(key, value);
3258
+ }
3259
+ const fullContext = {
3260
+ ...context,
3261
+ includes,
3262
+ assets,
3263
+ rawAssets,
3264
+ errors: []
3265
+ };
3266
+ const converted = context.tagResolver(fullContext, tagEntry, customTypeEntry);
3267
+ if (converted?.icons && converted.icons.length > 0) {
3268
+ const processedIcons = await processIconsForSprite(converted.icons);
3269
+ converted.icons = processedIcons.length > 0 ? processedIcons : void 0;
3270
+ }
3271
+ if (fullContext.errors.length > 0 && typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
3272
+ console.error(`CMS conversion errors for tag:`, {
3273
+ entryId: tagEntry.sys.id,
3274
+ slug,
3275
+ errors: fullContext.errors
3276
+ });
3277
+ }
3278
+ return { data: converted, errors: fullContext.errors };
3279
+ } catch (error) {
3280
+ const entryId = tagEntry?.sys.id || "unknown";
3281
+ const entryType = tagEntry?.sys.contentType?.sys?.id;
3282
+ const errorMessage = error instanceof Error ? error.message : "Unknown conversion error";
3283
+ const cmsError = {
3284
+ entryId,
3285
+ entryType,
3286
+ message: errorMessage,
3287
+ error
3288
+ };
3289
+ return { data: null, errors: [cmsError] };
3290
+ }
3291
+ };
3292
+ if (options?.retry) {
3293
+ return await withRetry(fetchFn, options.retry);
3294
+ }
3295
+ return await fetchFn();
3080
3296
  }
3081
3297
 
3082
3298
  // src/api/template.ts