@brandlab-digital/site-next 2.1.0 → 3.1.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.
Files changed (96) hide show
  1. package/dist/analytics.d.ts +111 -52
  2. package/dist/analytics.d.ts.map +1 -1
  3. package/dist/analytics.js +281 -153
  4. package/dist/analytics.js.map +1 -1
  5. package/dist/blog.d.ts +4 -2
  6. package/dist/blog.d.ts.map +1 -1
  7. package/dist/blog.js +7 -7
  8. package/dist/blog.js.map +1 -1
  9. package/dist/contact/client-entry.d.ts +2 -0
  10. package/dist/contact/client-entry.d.ts.map +1 -1
  11. package/dist/contact/client-entry.js +1 -0
  12. package/dist/contact/client-entry.js.map +1 -1
  13. package/dist/contact/client.d.ts +12 -22
  14. package/dist/contact/client.d.ts.map +1 -1
  15. package/dist/contact/client.js +28 -21
  16. package/dist/contact/client.js.map +1 -1
  17. package/dist/contact/form-client.d.ts +159 -0
  18. package/dist/contact/form-client.d.ts.map +1 -0
  19. package/dist/contact/form-client.js +257 -0
  20. package/dist/contact/form-client.js.map +1 -0
  21. package/dist/contact/index.d.ts +1 -1
  22. package/dist/contact/index.d.ts.map +1 -1
  23. package/dist/contact/index.js +1 -1
  24. package/dist/contact/index.js.map +1 -1
  25. package/dist/contact/route-handler.d.ts +32 -0
  26. package/dist/contact/route-handler.d.ts.map +1 -0
  27. package/dist/contact/route-handler.js +44 -0
  28. package/dist/contact/route-handler.js.map +1 -0
  29. package/dist/contact/server-entry.d.ts +1 -0
  30. package/dist/contact/server-entry.d.ts.map +1 -1
  31. package/dist/contact/server-entry.js +1 -0
  32. package/dist/contact/server-entry.js.map +1 -1
  33. package/dist/contact/server.d.ts +5 -0
  34. package/dist/contact/server.d.ts.map +1 -1
  35. package/dist/contact/server.js +13 -7
  36. package/dist/contact/server.js.map +1 -1
  37. package/dist/contact/shared.d.ts +4 -0
  38. package/dist/contact/shared.d.ts.map +1 -1
  39. package/dist/contact/shared.js.map +1 -1
  40. package/dist/contact/testing.d.ts +29 -0
  41. package/dist/contact/testing.d.ts.map +1 -1
  42. package/dist/contact/testing.js +27 -0
  43. package/dist/contact/testing.js.map +1 -1
  44. package/dist/google-tag-plan.d.ts +1 -4
  45. package/dist/google-tag-plan.d.ts.map +1 -1
  46. package/dist/google-tag-plan.js +1 -14
  47. package/dist/google-tag-plan.js.map +1 -1
  48. package/dist/google-tag.d.ts +5 -4
  49. package/dist/google-tag.d.ts.map +1 -1
  50. package/dist/google-tag.js +5 -4
  51. package/dist/google-tag.js.map +1 -1
  52. package/dist/headers.d.ts +54 -27
  53. package/dist/headers.d.ts.map +1 -1
  54. package/dist/headers.js +122 -51
  55. package/dist/headers.js.map +1 -1
  56. package/dist/instrumentation-client.d.ts +21 -1
  57. package/dist/instrumentation-client.d.ts.map +1 -1
  58. package/dist/instrumentation-client.js +62 -7
  59. package/dist/instrumentation-client.js.map +1 -1
  60. package/dist/lead-registry.d.ts +34 -0
  61. package/dist/lead-registry.d.ts.map +1 -0
  62. package/dist/lead-registry.js +30 -0
  63. package/dist/lead-registry.js.map +1 -0
  64. package/dist/lead-reporting.d.ts +37 -0
  65. package/dist/lead-reporting.d.ts.map +1 -0
  66. package/dist/lead-reporting.js +74 -0
  67. package/dist/lead-reporting.js.map +1 -0
  68. package/dist/metadata.d.ts +10 -11
  69. package/dist/metadata.d.ts.map +1 -1
  70. package/dist/metadata.js +17 -19
  71. package/dist/metadata.js.map +1 -1
  72. package/dist/next-config.d.ts +113 -0
  73. package/dist/next-config.d.ts.map +1 -0
  74. package/dist/next-config.js +213 -0
  75. package/dist/next-config.js.map +1 -0
  76. package/dist/robots.d.ts +14 -6
  77. package/dist/robots.d.ts.map +1 -1
  78. package/dist/robots.js +26 -17
  79. package/dist/robots.js.map +1 -1
  80. package/dist/sitemaps.d.ts +34 -0
  81. package/dist/sitemaps.d.ts.map +1 -1
  82. package/dist/sitemaps.js +66 -1
  83. package/dist/sitemaps.js.map +1 -1
  84. package/dist/testing/server-only.d.ts +8 -0
  85. package/dist/testing/server-only.d.ts.map +1 -0
  86. package/dist/testing/server-only.js +8 -0
  87. package/dist/testing/server-only.js.map +1 -0
  88. package/dist/ui-client.d.ts +1 -12
  89. package/dist/ui-client.d.ts.map +1 -1
  90. package/dist/ui-client.js +0 -17
  91. package/dist/ui-client.js.map +1 -1
  92. package/dist/ui.d.ts +22 -2
  93. package/dist/ui.d.ts.map +1 -1
  94. package/dist/ui.js +67 -6
  95. package/dist/ui.js.map +1 -1
  96. package/package.json +16 -3
package/dist/metadata.js CHANGED
@@ -1,37 +1,35 @@
1
- import { buildBrandlabMetadata, buildSeoMetadata, } from '@brandlab-digital/site-core/metadata';
1
+ import { buildBrandlabMetadata, } from '@brandlab-digital/site-core/metadata';
2
2
  import { getRouteById, resolveBrandlabRouteIndexing, } from '@brandlab-digital/site-core/routes';
3
3
  import { defineSeoPage } from '@brandlab-digital/site-core/seo-page';
4
4
  export function toNextMetadata(metadata) {
5
5
  const { canonicalPath: _canonicalPath, canonicalUrl: _canonicalUrl, resolvedTitle: _resolvedTitle, ...next } = metadata;
6
6
  return next;
7
7
  }
8
- export function buildNextMetadata(input) {
9
- return toNextMetadata(buildSeoMetadata(input));
10
- }
11
- export function buildBrandlabNextMetadata(input) {
12
- return toNextMetadata(buildBrandlabMetadata(input));
13
- }
14
- export function createNextMetadataBuilder(defaults) {
15
- return (page) => buildNextMetadata({ ...defaults, ...page });
16
- }
17
- export function createBrandlabNextMetadataBuilder(defaults) {
18
- return (page) => buildBrandlabNextMetadata({ ...defaults, ...page });
19
- }
20
- /** Builds page metadata from the same route identity used by breadcrumbs and sitemaps. */
21
- export function createRouteMetadataBuilder(defaults, routes) {
8
+ /**
9
+ * The project's one page-metadata binding (`src/lib/seo/metadata.ts`):
10
+ * `export const pageMetadata = createRouteMetadataBuilder(site, routes)`.
11
+ * Canonical path and robots come from the route catalogue; the title mode is
12
+ * explicit per page. Keywords keep their form: a comma-separated string renders
13
+ * exactly as given, a list renders joined with commas, as Next renders them.
14
+ */
15
+ export function createRouteMetadataBuilder(site, routes) {
22
16
  return (input) => {
23
17
  const page = defineSeoPage(input);
24
18
  const route = getRouteById(routes, page.routeId);
25
19
  if (!route)
26
20
  throw new Error(`Unknown metadata route ID "${page.routeId}".`);
27
- return buildBrandlabNextMetadata({
28
- ...defaults,
21
+ return toNextMetadata(buildBrandlabMetadata({
22
+ brandName: site.name,
23
+ siteUrl: site.canonicalUrl,
24
+ locale: site.locale,
25
+ titleTemplate: site.titleTemplate,
26
+ defaultSocialImage: site.defaultSocialImage,
29
27
  title: page.title,
30
28
  description: page.description,
31
29
  pathname: route.canonicalPath ?? route.path,
32
30
  indexing: resolveBrandlabRouteIndexing(route),
33
31
  ...(page.titleMode ? { titleMode: page.titleMode } : {}),
34
- ...(page.keywords ? { keywords: [...page.keywords] } : {}),
32
+ ...(page.keywords !== undefined ? { keywords: page.keywords } : {}),
35
33
  ...(page.socialImage ? { socialImage: page.socialImage } : {}),
36
34
  ...(page.article
37
35
  ? {
@@ -44,7 +42,7 @@ export function createRouteMetadataBuilder(defaults, routes) {
44
42
  },
45
43
  }
46
44
  : {}),
47
- });
45
+ }));
48
46
  };
49
47
  }
50
48
  //# sourceMappingURL=metadata.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,gBAAgB,GAIjB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EACL,YAAY,EACZ,4BAA4B,GAE7B,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAwB,MAAM,sCAAsC,CAAA;AAwB1F,MAAM,UAAU,cAAc,CAAC,QAA6B;IAC1D,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,GAC1G,QAAQ,CAAA;IACV,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAA4B;IAC5D,OAAO,cAAc,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAA;AAChD,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,KAAiC;IAEjC,OAAO,cAAc,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAA;AACrD,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAAkC;IAC1E,OAAO,CAAC,IAA+B,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;AACzF,CAAC;AAED,MAAM,UAAU,iCAAiC,CAAC,QAAwC;IACxF,OAAO,CAAC,IAAqC,EAAE,EAAE,CAC/C,yBAAyB,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;AACvD,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,0BAA0B,CACxC,QAAwC,EACxC,MAA4B;IAE5B,OAAO,CAAC,KAAsB,EAA0B,EAAE;QACxD,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QAChD,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,CAAC,OAAO,IAAI,CAAC,CAAA;QAE3E,OAAO,yBAAyB,CAAC;YAC/B,GAAG,QAAQ;YACX,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI;YAC3C,QAAQ,EAAE,4BAA4B,CAAC,KAAK,CAAC;YAC7C,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,IAAI,CAAC,OAAO;gBACd,CAAC,CAAC;oBACE,OAAO,EAAE;wBACP,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa;wBACzC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY;4BAC3B,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;4BAC7C,CAAC,CAAC,EAAE,CAAC;wBACP,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;qBACnC;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC","sourcesContent":["import {\n buildBrandlabMetadata,\n buildSeoMetadata,\n type BrandlabSeoMetadata,\n type BuildBrandlabMetadataInput,\n type BuildSeoMetadataInput,\n} from '@brandlab-digital/site-core/metadata'\nimport {\n getRouteById,\n resolveBrandlabRouteIndexing,\n type BrandlabRouteCatalog,\n} from '@brandlab-digital/site-core/routes'\nimport { defineSeoPage, type BrandlabSeoPage } from '@brandlab-digital/site-core/seo-page'\n\nexport type NextCompatibleMetadata = Omit<\n BrandlabSeoMetadata,\n 'canonicalPath' | 'canonicalUrl' | 'resolvedTitle'\n>\n\nexport type BrandlabMetadataDefaults = Pick<\n BuildSeoMetadataInput,\n 'brandName' | 'siteUrl' | 'locale' | 'titleTemplate' | 'defaultSocialImage'\n>\n\nexport type BrandlabPageMetadataInput = Omit<BuildSeoMetadataInput, keyof BrandlabMetadataDefaults>\n\nexport type BrandlabStrictMetadataDefaults = Pick<\n BuildBrandlabMetadataInput,\n 'brandName' | 'siteUrl' | 'locale' | 'titleTemplate' | 'defaultSocialImage'\n>\n\nexport type BrandlabStrictPageMetadataInput = Omit<\n BuildBrandlabMetadataInput,\n keyof BrandlabStrictMetadataDefaults\n>\n\nexport function toNextMetadata(metadata: BrandlabSeoMetadata): NextCompatibleMetadata {\n const { canonicalPath: _canonicalPath, canonicalUrl: _canonicalUrl, resolvedTitle: _resolvedTitle, ...next } =\n metadata\n return next\n}\n\nexport function buildNextMetadata(input: BuildSeoMetadataInput): NextCompatibleMetadata {\n return toNextMetadata(buildSeoMetadata(input))\n}\n\nexport function buildBrandlabNextMetadata(\n input: BuildBrandlabMetadataInput,\n): NextCompatibleMetadata {\n return toNextMetadata(buildBrandlabMetadata(input))\n}\n\nexport function createNextMetadataBuilder(defaults: BrandlabMetadataDefaults) {\n return (page: BrandlabPageMetadataInput) => buildNextMetadata({ ...defaults, ...page })\n}\n\nexport function createBrandlabNextMetadataBuilder(defaults: BrandlabStrictMetadataDefaults) {\n return (page: BrandlabStrictPageMetadataInput) =>\n buildBrandlabNextMetadata({ ...defaults, ...page })\n}\n\n/** Builds page metadata from the same route identity used by breadcrumbs and sitemaps. */\nexport function createRouteMetadataBuilder(\n defaults: BrandlabStrictMetadataDefaults,\n routes: BrandlabRouteCatalog,\n) {\n return (input: BrandlabSeoPage): NextCompatibleMetadata => {\n const page = defineSeoPage(input)\n const route = getRouteById(routes, page.routeId)\n if (!route) throw new Error(`Unknown metadata route ID \"${page.routeId}\".`)\n\n return buildBrandlabNextMetadata({\n ...defaults,\n title: page.title,\n description: page.description,\n pathname: route.canonicalPath ?? route.path,\n indexing: resolveBrandlabRouteIndexing(route),\n ...(page.titleMode ? { titleMode: page.titleMode } : {}),\n ...(page.keywords ? { keywords: [...page.keywords] } : {}),\n ...(page.socialImage ? { socialImage: page.socialImage } : {}),\n ...(page.article\n ? {\n article: {\n publishedTime: page.article.publishedTime,\n ...(page.article.modifiedTime\n ? { modifiedTime: page.article.modifiedTime }\n : {}),\n authors: [...page.article.authors],\n },\n }\n : {}),\n })\n }\n}\n"]}
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,GAEtB,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EACL,YAAY,EACZ,4BAA4B,GAE7B,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAwB,MAAM,sCAAsC,CAAA;AAQ1F,MAAM,UAAU,cAAc,CAAC,QAA6B;IAC1D,MAAM,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAI,EAAE,GAC1G,QAAQ,CAAA;IACV,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CACxC,IAAkB,EAClB,MAA4B;IAE5B,OAAO,CAAC,KAAsB,EAA0B,EAAE;QACxD,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;QACjC,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;QAChD,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,CAAC,OAAO,IAAI,CAAC,CAAA;QAE3E,OAAO,cAAc,CAAC,qBAAqB,CAAC;YAC1C,SAAS,EAAE,IAAI,CAAC,IAAI;YACpB,OAAO,EAAE,IAAI,CAAC,YAAY;YAC1B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;YAC3C,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,QAAQ,EAAE,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,IAAI;YAC3C,QAAQ,EAAE,4BAA4B,CAAC,KAAK,CAAC;YAC7C,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,GAAG,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnE,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9D,GAAG,CAAC,IAAI,CAAC,OAAO;gBACd,CAAC,CAAC;oBACE,OAAO,EAAE;wBACP,aAAa,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa;wBACzC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY;4BAC3B,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;4BAC7C,CAAC,CAAC,EAAE,CAAC;wBACP,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;qBACnC;iBACF;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAC,CAAA;IACL,CAAC,CAAA;AACH,CAAC","sourcesContent":["import {\n buildBrandlabMetadata,\n type BrandlabSeoMetadata,\n} from '@brandlab-digital/site-core/metadata'\nimport {\n getRouteById,\n resolveBrandlabRouteIndexing,\n type BrandlabRouteCatalog,\n} from '@brandlab-digital/site-core/routes'\nimport { defineSeoPage, type BrandlabSeoPage } from '@brandlab-digital/site-core/seo-page'\nimport type { BrandlabSite } from '@brandlab-digital/site-core/site'\n\nexport type NextCompatibleMetadata = Omit<\n BrandlabSeoMetadata,\n 'canonicalPath' | 'canonicalUrl' | 'resolvedTitle'\n>\n\nexport function toNextMetadata(metadata: BrandlabSeoMetadata): NextCompatibleMetadata {\n const { canonicalPath: _canonicalPath, canonicalUrl: _canonicalUrl, resolvedTitle: _resolvedTitle, ...next } =\n metadata\n return next\n}\n\n/**\n * The project's one page-metadata binding (`src/lib/seo/metadata.ts`):\n * `export const pageMetadata = createRouteMetadataBuilder(site, routes)`.\n * Canonical path and robots come from the route catalogue; the title mode is\n * explicit per page. Keywords keep their form: a comma-separated string renders\n * exactly as given, a list renders joined with commas, as Next renders them.\n */\nexport function createRouteMetadataBuilder(\n site: BrandlabSite,\n routes: BrandlabRouteCatalog,\n) {\n return (input: BrandlabSeoPage): NextCompatibleMetadata => {\n const page = defineSeoPage(input)\n const route = getRouteById(routes, page.routeId)\n if (!route) throw new Error(`Unknown metadata route ID \"${page.routeId}\".`)\n\n return toNextMetadata(buildBrandlabMetadata({\n brandName: site.name,\n siteUrl: site.canonicalUrl,\n locale: site.locale,\n titleTemplate: site.titleTemplate,\n defaultSocialImage: site.defaultSocialImage,\n title: page.title,\n description: page.description,\n pathname: route.canonicalPath ?? route.path,\n indexing: resolveBrandlabRouteIndexing(route),\n ...(page.titleMode ? { titleMode: page.titleMode } : {}),\n ...(page.keywords !== undefined ? { keywords: page.keywords } : {}),\n ...(page.socialImage ? { socialImage: page.socialImage } : {}),\n ...(page.article\n ? {\n article: {\n publishedTime: page.article.publishedTime,\n ...(page.article.modifiedTime\n ? { modifiedTime: page.article.modifiedTime }\n : {}),\n authors: [...page.article.authors],\n },\n }\n : {}),\n }))\n }\n}\n"]}
@@ -0,0 +1,113 @@
1
+ import { type BrandlabRedirectTable } from '@brandlab-digital/site-core/redirects';
2
+ import { type BrandlabDeploymentEnvironment, type BrandlabEnvironment, type BrandlabSite } from '@brandlab-digital/site-core/site';
3
+ import { type BrandlabContentSecurityPolicyExtensions, type BrandlabHeader, type BrandlabHeaderRule, type BrandlabHstsExpansion } from './headers.js';
4
+ /** Next redirect records: 308 stays `permanent: true`, 301 stays `statusCode: 301`. */
5
+ export type BrandlabNextRedirect = {
6
+ source: string;
7
+ destination: string;
8
+ has?: {
9
+ type: 'host';
10
+ value: string;
11
+ }[];
12
+ } & ({
13
+ permanent: true;
14
+ statusCode?: never;
15
+ } | {
16
+ statusCode: 301;
17
+ permanent?: never;
18
+ });
19
+ export interface BrandlabNextRemotePattern {
20
+ protocol?: 'http' | 'https';
21
+ hostname: string;
22
+ port?: string;
23
+ pathname?: string;
24
+ search?: string;
25
+ }
26
+ /** The site's own image settings; the output format is always WebP. */
27
+ export interface BrandlabNextImagesOptions {
28
+ deviceSizes?: readonly number[];
29
+ imageSizes?: readonly number[];
30
+ qualities?: readonly number[];
31
+ minimumCacheTTL?: number;
32
+ remotePatterns?: readonly BrandlabNextRemotePattern[];
33
+ }
34
+ export interface BrandlabNextImagesConfig {
35
+ formats: 'image/webp'[];
36
+ deviceSizes?: number[];
37
+ imageSizes?: number[];
38
+ qualities?: number[];
39
+ minimumCacheTTL?: number;
40
+ remotePatterns?: BrandlabNextRemotePattern[];
41
+ }
42
+ export interface BrandlabNextConfig {
43
+ poweredByHeader: false;
44
+ /** Trailing slashes are handled by single-hop redirect rules instead. */
45
+ skipTrailingSlashRedirect: true;
46
+ env: {
47
+ NEXT_PUBLIC_VERCEL_ENV: BrandlabDeploymentEnvironment;
48
+ };
49
+ outputFileTracingIncludes: Record<string, string[]>;
50
+ images: BrandlabNextImagesConfig;
51
+ pageExtensions?: string[];
52
+ headers: () => Promise<BrandlabHeaderRule[]>;
53
+ redirects: () => Promise<BrandlabNextRedirect[]>;
54
+ }
55
+ export interface BrandlabNextConfigOptions {
56
+ site: BrandlabSite;
57
+ /** The src/data/redirects.ts table (defineRedirects). */
58
+ redirects: BrandlabRedirectTable;
59
+ images: BrandlabNextImagesOptions;
60
+ /** Reviewed CSP origins for declared integrations such as Meta Pixel or map embeds. */
61
+ csp?: BrandlabContentSecurityPolicyExtensions;
62
+ hsts?: BrandlabHstsExpansion;
63
+ /** Reviewed exception to the default Permissions-Policy that is already live. */
64
+ permissionsPolicy?: string;
65
+ /** Reviewed response headers that are already live; protected headers cannot be replaced. */
66
+ extraHeaders?: readonly BrandlabHeader[];
67
+ /**
68
+ * Public folders of static files that never change in place, written as Next
69
+ * sources such as `['/images/:path*', '/fonts/:path*']`. Production builds serve
70
+ * their files (names with an extension) with `public, max-age=31536000, immutable`;
71
+ * Previews keep `private, no-store`. Each folder must exist under `public/`, and
72
+ * no route under `src/app` or `app` may answer below it.
73
+ */
74
+ staticAssetCache?: readonly string[];
75
+ /** Defaults to process.env; tests supply a fixed environment. */
76
+ environment?: BrandlabEnvironment;
77
+ /** The project root for the staticAssetCache checks; defaults to process.cwd(). */
78
+ projectRoot?: string;
79
+ }
80
+ /** Sharp's Linux binaries must travel with the contact route's image sanitiser. */
81
+ export declare const BRANDLAB_CONTACT_OUTPUT_FILE_TRACING: Readonly<{
82
+ '/api/contact': readonly string[];
83
+ }>;
84
+ /**
85
+ * Converts the redirect table to Next redirects: each entry keeps its 301 or
86
+ * 308 status (Next forwards the query string), gains a single-hop
87
+ * trailing-slash variant, then one trailing-slash rule and one permanent
88
+ * canonical-host rule per alias host follow. There is no x-forwarded-proto
89
+ * rule: Vercel's edge already enforces HTTPS.
90
+ */
91
+ export declare function buildBrandlabRedirects(options: {
92
+ site: BrandlabSite;
93
+ redirects: BrandlabRedirectTable;
94
+ }): BrandlabNextRedirect[];
95
+ /**
96
+ * The whole next.config.ts after its first line
97
+ * `import '@brandlab-digital/site-next/image-runtime'`:
98
+ * `export default defineBrandlabNextConfig({ site, redirects, images })`.
99
+ *
100
+ * Sets poweredByHeader: false, WebP image output, Sharp output tracing for
101
+ * /api/contact, NEXT_PUBLIC_VERCEL_ENV for browser gates, the deployment's
102
+ * header rules (with immutable caching for the declared static public folders on
103
+ * production builds) and the redirect table. Validation runs when the config
104
+ * loads, so an invalid table, header exception or static folder fails the build.
105
+ */
106
+ export declare function defineBrandlabNextConfig(options: BrandlabNextConfigOptions & {
107
+ mdx?: undefined;
108
+ }): BrandlabNextConfig;
109
+ export declare function defineBrandlabNextConfig<Wrapped>(options: BrandlabNextConfigOptions & {
110
+ /** The @next/mdx wrapper: createMDX({ options: { remarkPlugins: ['remark-gfm'] } }). */
111
+ mdx: (config: BrandlabNextConfig) => Wrapped;
112
+ }): Wrapped;
113
+ //# sourceMappingURL=next-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-config.d.ts","sourceRoot":"","sources":["../src/next-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,213 @@
1
+ import { readdirSync, statSync } from 'node:fs';
2
+ import { join, posix } from 'node:path';
3
+ import { defineRedirects } from '@brandlab-digital/site-core/redirects';
4
+ import { resolveBrandlabDeployment, } from '@brandlab-digital/site-core/site';
5
+ import { buildBrandlabHeaderRules, parseBrandlabStaticAssetCache, } from './headers.js';
6
+ /** Sharp's Linux binaries must travel with the contact route's image sanitiser. */
7
+ export const BRANDLAB_CONTACT_OUTPUT_FILE_TRACING = Object.freeze({
8
+ '/api/contact': Object.freeze([
9
+ 'node_modules/sharp/**/*',
10
+ 'node_modules/@img/sharp-linux-x64/**/*',
11
+ 'node_modules/@img/sharp-libvips-linux-x64/**/*',
12
+ ]),
13
+ });
14
+ const MDX_PAGE_EXTENSIONS = ['tsx', 'ts', 'jsx', 'js', 'mdx', 'md'];
15
+ const OPTION_KEYS = new Set([
16
+ 'site',
17
+ 'redirects',
18
+ 'images',
19
+ 'csp',
20
+ 'hsts',
21
+ 'permissionsPolicy',
22
+ 'extraHeaders',
23
+ 'staticAssetCache',
24
+ 'mdx',
25
+ 'environment',
26
+ 'projectRoot',
27
+ ]);
28
+ const IMAGE_KEYS = new Set(['deviceSizes', 'imageSizes', 'qualities', 'minimumCacheTTL', 'remotePatterns']);
29
+ function assertKnownKeys(value, allowed, field, hint = '') {
30
+ const unsupported = Object.keys(value).filter((key) => !allowed.has(key));
31
+ if (unsupported.length > 0) {
32
+ throw new Error(`${field} contains unsupported keys: ${unsupported.join(', ')}.${hint}`);
33
+ }
34
+ }
35
+ function positiveIntegers(values, field) {
36
+ if (values === undefined)
37
+ return undefined;
38
+ if (!Array.isArray(values) ||
39
+ values.length === 0 ||
40
+ values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
41
+ throw new Error(`images.${field} must list positive integers.`);
42
+ }
43
+ return [...values];
44
+ }
45
+ function buildImagesConfig(images) {
46
+ if (!images || typeof images !== 'object' || Array.isArray(images)) {
47
+ throw new Error('images must declare the site image settings ({} for Next defaults).');
48
+ }
49
+ assertKnownKeys(images, IMAGE_KEYS, 'images', ' The output format is always image/webp.');
50
+ const deviceSizes = positiveIntegers(images.deviceSizes, 'deviceSizes');
51
+ const imageSizes = positiveIntegers(images.imageSizes, 'imageSizes');
52
+ const qualities = positiveIntegers(images.qualities, 'qualities');
53
+ if (qualities?.some((quality) => quality > 100)) {
54
+ throw new Error('images.qualities must be between 1 and 100.');
55
+ }
56
+ if (images.minimumCacheTTL !== undefined &&
57
+ (!Number.isSafeInteger(images.minimumCacheTTL) || images.minimumCacheTTL < 0)) {
58
+ throw new Error('images.minimumCacheTTL must be a non-negative integer of seconds.');
59
+ }
60
+ if (images.remotePatterns !== undefined && !Array.isArray(images.remotePatterns)) {
61
+ throw new Error('images.remotePatterns must be an array.');
62
+ }
63
+ return {
64
+ formats: ['image/webp'],
65
+ ...(deviceSizes ? { deviceSizes } : {}),
66
+ ...(imageSizes ? { imageSizes } : {}),
67
+ ...(qualities ? { qualities } : {}),
68
+ ...(images.minimumCacheTTL !== undefined ? { minimumCacheTTL: images.minimumCacheTTL } : {}),
69
+ ...(images.remotePatterns
70
+ ? { remotePatterns: images.remotePatterns.map((pattern) => ({ ...pattern })) }
71
+ : {}),
72
+ };
73
+ }
74
+ const PAGE_OR_ROUTE_FILE = /^(?:page|route)\.[A-Za-z0-9]+$/;
75
+ const METADATA_ROUTE_FILE = /^(?:opengraph-image|twitter-image|icon|apple-icon|sitemap|robots|manifest)(?:[\w.-]*)\.[A-Za-z0-9]+$/;
76
+ function isDirectory(path) {
77
+ try {
78
+ return statSync(path).isDirectory();
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ }
84
+ /**
85
+ * The first route file under an app directory that can answer a path strictly
86
+ * below `/<folder>/`. `depth` counts the folder segments matched so far: route
87
+ * groups, intercepts and parallel slots add none, a dynamic segment matches any
88
+ * one, and a catch-all reaches every path below the folder.
89
+ */
90
+ function routeBelowFolder(directory, folder, depth, relative) {
91
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
92
+ const name = entry.name;
93
+ if (name.startsWith('_') || name.startsWith('.') || name === 'node_modules')
94
+ continue;
95
+ const path = join(directory, name);
96
+ const nextRelative = posix.join(relative, name);
97
+ if (entry.isFile()) {
98
+ // Page and route files serve their own directory; metadata files serve a path below it.
99
+ const below = depth > folder.length && PAGE_OR_ROUTE_FILE.test(name);
100
+ const metadata = depth >= folder.length && METADATA_ROUTE_FILE.test(name);
101
+ if (below || metadata)
102
+ return nextRelative;
103
+ continue;
104
+ }
105
+ if (!entry.isDirectory())
106
+ continue;
107
+ let next = null;
108
+ if (name.startsWith('(') || name.startsWith('@'))
109
+ next = depth;
110
+ else if (/^\[\[?\.\.\./.test(name))
111
+ next = folder.length + 1;
112
+ else if (depth >= folder.length || name.startsWith('[') || name === folder[depth])
113
+ next = depth + 1;
114
+ if (next === null)
115
+ continue;
116
+ const found = routeBelowFolder(path, folder, next, nextRelative);
117
+ if (found)
118
+ return found;
119
+ }
120
+ return null;
121
+ }
122
+ /** Each declared folder exists under public/ and no app route answers below it. */
123
+ function assertStaticAssetFolders(folders, root) {
124
+ for (const { source, folder } of folders) {
125
+ const publicFolder = posix.join('public', ...folder);
126
+ if (!isDirectory(join(root, publicFolder))) {
127
+ throw new Error(`staticAssetCache "${source}": ${publicFolder} is not a folder of static files in ${root}.`);
128
+ }
129
+ for (const appDirectory of ['src/app', 'app']) {
130
+ if (!isDirectory(join(root, appDirectory)))
131
+ continue;
132
+ const route = routeBelowFolder(join(root, appDirectory), folder, 0, appDirectory);
133
+ if (route) {
134
+ throw new Error(`staticAssetCache "${source}": ${route} answers below /${folder.join('/')}, so immutable caching could reach a page or route.`);
135
+ }
136
+ }
137
+ }
138
+ }
139
+ /**
140
+ * Converts the redirect table to Next redirects: each entry keeps its 301 or
141
+ * 308 status (Next forwards the query string), gains a single-hop
142
+ * trailing-slash variant, then one trailing-slash rule and one permanent
143
+ * canonical-host rule per alias host follow. There is no x-forwarded-proto
144
+ * rule: Vercel's edge already enforces HTTPS.
145
+ */
146
+ export function buildBrandlabRedirects(options) {
147
+ const table = defineRedirects(options.redirects);
148
+ const entries = table.flatMap((redirect) => {
149
+ const status = redirect.status === 301
150
+ ? { statusCode: 301 }
151
+ : { permanent: true };
152
+ const has = redirect.host ? { has: [{ type: 'host', value: redirect.host }] } : {};
153
+ const record = (source) => ({
154
+ source,
155
+ destination: redirect.destination,
156
+ ...status,
157
+ ...has,
158
+ });
159
+ return redirect.source === '/'
160
+ ? [record(redirect.source)]
161
+ : [record(redirect.source), record(`${redirect.source}/`)];
162
+ });
163
+ return [
164
+ ...entries,
165
+ { source: '/:path+/', destination: '/:path+', permanent: true },
166
+ ...options.site.aliasHosts.map((host) => ({
167
+ source: '/:path*',
168
+ has: [{ type: 'host', value: host }],
169
+ destination: `${options.site.canonicalUrl}/:path*`,
170
+ permanent: true,
171
+ })),
172
+ ];
173
+ }
174
+ export function defineBrandlabNextConfig(options) {
175
+ if (!options || typeof options !== 'object') {
176
+ throw new TypeError('defineBrandlabNextConfig requires the site, redirects and images.');
177
+ }
178
+ assertKnownKeys(options, OPTION_KEYS, 'next.config options');
179
+ if (!options.site?.canonicalUrl || !Array.isArray(options.site.aliasHosts)) {
180
+ throw new Error('site must come from defineBrandlabSite.');
181
+ }
182
+ if (options.mdx !== undefined && typeof options.mdx !== 'function') {
183
+ throw new TypeError('mdx must be the @next/mdx config wrapper.');
184
+ }
185
+ const deployment = resolveBrandlabDeployment(options.environment ?? process.env);
186
+ if (options.staticAssetCache !== undefined) {
187
+ assertStaticAssetFolders(parseBrandlabStaticAssetCache(options.staticAssetCache), options.projectRoot ?? process.cwd());
188
+ }
189
+ const headerRules = buildBrandlabHeaderRules({
190
+ deployment,
191
+ ...(options.csp ? { contentSecurityPolicyExtensions: options.csp } : {}),
192
+ ...(options.hsts ? { hsts: options.hsts } : {}),
193
+ ...(options.permissionsPolicy ? { permissionsPolicy: options.permissionsPolicy } : {}),
194
+ ...(options.extraHeaders ? { extraHeaders: options.extraHeaders } : {}),
195
+ ...(options.staticAssetCache ? { staticAssetCache: options.staticAssetCache } : {}),
196
+ });
197
+ const redirects = buildBrandlabRedirects({ site: options.site, redirects: options.redirects });
198
+ const config = {
199
+ poweredByHeader: false,
200
+ skipTrailingSlashRedirect: true,
201
+ env: { NEXT_PUBLIC_VERCEL_ENV: deployment.environment },
202
+ outputFileTracingIncludes: Object.fromEntries(Object.entries(BRANDLAB_CONTACT_OUTPUT_FILE_TRACING).map(([route, globs]) => [route, [...globs]])),
203
+ images: buildImagesConfig(options.images),
204
+ ...(options.mdx ? { pageExtensions: [...MDX_PAGE_EXTENSIONS] } : {}),
205
+ headers: async () => headerRules.map((rule) => ({ source: rule.source, headers: rule.headers.map((header) => ({ ...header })) })),
206
+ redirects: async () => redirects.map((redirect) => ({
207
+ ...redirect,
208
+ ...(redirect.has ? { has: redirect.has.map((condition) => ({ ...condition })) } : {}),
209
+ })),
210
+ };
211
+ return options.mdx ? options.mdx(config) : config;
212
+ }
213
+ //# sourceMappingURL=next-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next-config.js","sourceRoot":"","sources":["../src/next-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, statSync } from 'node:fs'\nimport { join, posix } from 'node:path'\nimport { defineRedirects, type BrandlabRedirectTable } from '@brandlab-digital/site-core/redirects'\nimport {\n resolveBrandlabDeployment,\n type BrandlabDeploymentEnvironment,\n type BrandlabEnvironment,\n type BrandlabSite,\n} from '@brandlab-digital/site-core/site'\nimport {\n buildBrandlabHeaderRules,\n parseBrandlabStaticAssetCache,\n type BrandlabContentSecurityPolicyExtensions,\n type BrandlabHeader,\n type BrandlabHeaderRule,\n type BrandlabHstsExpansion,\n type BrandlabStaticAssetFolder,\n} from './headers.js'\n\n/** Next redirect records: 308 stays `permanent: true`, 301 stays `statusCode: 301`. */\nexport type BrandlabNextRedirect = {\n source: string\n destination: string\n has?: { type: 'host'; value: string }[]\n} & ({ permanent: true; statusCode?: never } | { statusCode: 301; permanent?: never })\n\nexport interface BrandlabNextRemotePattern {\n protocol?: 'http' | 'https'\n hostname: string\n port?: string\n pathname?: string\n search?: string\n}\n\n/** The site's own image settings; the output format is always WebP. */\nexport interface BrandlabNextImagesOptions {\n deviceSizes?: readonly number[]\n imageSizes?: readonly number[]\n qualities?: readonly number[]\n minimumCacheTTL?: number\n remotePatterns?: readonly BrandlabNextRemotePattern[]\n}\n\nexport interface BrandlabNextImagesConfig {\n formats: 'image/webp'[]\n deviceSizes?: number[]\n imageSizes?: number[]\n qualities?: number[]\n minimumCacheTTL?: number\n remotePatterns?: BrandlabNextRemotePattern[]\n}\n\nexport interface BrandlabNextConfig {\n poweredByHeader: false\n /** Trailing slashes are handled by single-hop redirect rules instead. */\n skipTrailingSlashRedirect: true\n env: { NEXT_PUBLIC_VERCEL_ENV: BrandlabDeploymentEnvironment }\n outputFileTracingIncludes: Record<string, string[]>\n images: BrandlabNextImagesConfig\n pageExtensions?: string[]\n headers: () => Promise<BrandlabHeaderRule[]>\n redirects: () => Promise<BrandlabNextRedirect[]>\n}\n\nexport interface BrandlabNextConfigOptions {\n site: BrandlabSite\n /** The src/data/redirects.ts table (defineRedirects). */\n redirects: BrandlabRedirectTable\n images: BrandlabNextImagesOptions\n /** Reviewed CSP origins for declared integrations such as Meta Pixel or map embeds. */\n csp?: BrandlabContentSecurityPolicyExtensions\n hsts?: BrandlabHstsExpansion\n /** Reviewed exception to the default Permissions-Policy that is already live. */\n permissionsPolicy?: string\n /** Reviewed response headers that are already live; protected headers cannot be replaced. */\n extraHeaders?: readonly BrandlabHeader[]\n /**\n * Public folders of static files that never change in place, written as Next\n * sources such as `['/images/:path*', '/fonts/:path*']`. Production builds serve\n * their files (names with an extension) with `public, max-age=31536000, immutable`;\n * Previews keep `private, no-store`. Each folder must exist under `public/`, and\n * no route under `src/app` or `app` may answer below it.\n */\n staticAssetCache?: readonly string[]\n /** Defaults to process.env; tests supply a fixed environment. */\n environment?: BrandlabEnvironment\n /** The project root for the staticAssetCache checks; defaults to process.cwd(). */\n projectRoot?: string\n}\n\n/** Sharp's Linux binaries must travel with the contact route's image sanitiser. */\nexport const BRANDLAB_CONTACT_OUTPUT_FILE_TRACING = Object.freeze({\n '/api/contact': Object.freeze([\n 'node_modules/sharp/**/*',\n 'node_modules/@img/sharp-linux-x64/**/*',\n 'node_modules/@img/sharp-libvips-linux-x64/**/*',\n ]),\n})\n\nconst MDX_PAGE_EXTENSIONS = ['tsx', 'ts', 'jsx', 'js', 'mdx', 'md']\nconst OPTION_KEYS = new Set([\n 'site',\n 'redirects',\n 'images',\n 'csp',\n 'hsts',\n 'permissionsPolicy',\n 'extraHeaders',\n 'staticAssetCache',\n 'mdx',\n 'environment',\n 'projectRoot',\n])\nconst IMAGE_KEYS = new Set(['deviceSizes', 'imageSizes', 'qualities', 'minimumCacheTTL', 'remotePatterns'])\n\nfunction assertKnownKeys(value: object, allowed: ReadonlySet<string>, field: string, hint = '') {\n const unsupported = Object.keys(value).filter((key) => !allowed.has(key))\n if (unsupported.length > 0) {\n throw new Error(`${field} contains unsupported keys: ${unsupported.join(', ')}.${hint}`)\n }\n}\n\nfunction positiveIntegers(values: readonly number[] | undefined, field: string) {\n if (values === undefined) return undefined\n if (\n !Array.isArray(values) ||\n values.length === 0 ||\n values.some((value) => !Number.isSafeInteger(value) || value < 1)\n ) {\n throw new Error(`images.${field} must list positive integers.`)\n }\n return [...values]\n}\n\nfunction buildImagesConfig(images: BrandlabNextImagesOptions): BrandlabNextImagesConfig {\n if (!images || typeof images !== 'object' || Array.isArray(images)) {\n throw new Error('images must declare the site image settings ({} for Next defaults).')\n }\n assertKnownKeys(images, IMAGE_KEYS, 'images', ' The output format is always image/webp.')\n const deviceSizes = positiveIntegers(images.deviceSizes, 'deviceSizes')\n const imageSizes = positiveIntegers(images.imageSizes, 'imageSizes')\n const qualities = positiveIntegers(images.qualities, 'qualities')\n if (qualities?.some((quality) => quality > 100)) {\n throw new Error('images.qualities must be between 1 and 100.')\n }\n if (\n images.minimumCacheTTL !== undefined &&\n (!Number.isSafeInteger(images.minimumCacheTTL) || images.minimumCacheTTL < 0)\n ) {\n throw new Error('images.minimumCacheTTL must be a non-negative integer of seconds.')\n }\n if (images.remotePatterns !== undefined && !Array.isArray(images.remotePatterns)) {\n throw new Error('images.remotePatterns must be an array.')\n }\n return {\n formats: ['image/webp'],\n ...(deviceSizes ? { deviceSizes } : {}),\n ...(imageSizes ? { imageSizes } : {}),\n ...(qualities ? { qualities } : {}),\n ...(images.minimumCacheTTL !== undefined ? { minimumCacheTTL: images.minimumCacheTTL } : {}),\n ...(images.remotePatterns\n ? { remotePatterns: images.remotePatterns.map((pattern) => ({ ...pattern })) }\n : {}),\n }\n}\n\nconst PAGE_OR_ROUTE_FILE = /^(?:page|route)\\.[A-Za-z0-9]+$/\nconst METADATA_ROUTE_FILE = /^(?:opengraph-image|twitter-image|icon|apple-icon|sitemap|robots|manifest)(?:[\\w.-]*)\\.[A-Za-z0-9]+$/\n\nfunction isDirectory(path: string) {\n try {\n return statSync(path).isDirectory()\n } catch {\n return false\n }\n}\n\n/**\n * The first route file under an app directory that can answer a path strictly\n * below `/<folder>/`. `depth` counts the folder segments matched so far: route\n * groups, intercepts and parallel slots add none, a dynamic segment matches any\n * one, and a catch-all reaches every path below the folder.\n */\nfunction routeBelowFolder(\n directory: string,\n folder: readonly string[],\n depth: number,\n relative: string,\n): string | null {\n for (const entry of readdirSync(directory, { withFileTypes: true })) {\n const name = entry.name\n if (name.startsWith('_') || name.startsWith('.') || name === 'node_modules') continue\n const path = join(directory, name)\n const nextRelative = posix.join(relative, name)\n if (entry.isFile()) {\n // Page and route files serve their own directory; metadata files serve a path below it.\n const below = depth > folder.length && PAGE_OR_ROUTE_FILE.test(name)\n const metadata = depth >= folder.length && METADATA_ROUTE_FILE.test(name)\n if (below || metadata) return nextRelative\n continue\n }\n if (!entry.isDirectory()) continue\n let next: number | null = null\n if (name.startsWith('(') || name.startsWith('@')) next = depth\n else if (/^\\[\\[?\\.\\.\\./.test(name)) next = folder.length + 1\n else if (depth >= folder.length || name.startsWith('[') || name === folder[depth]) next = depth + 1\n if (next === null) continue\n const found = routeBelowFolder(path, folder, next, nextRelative)\n if (found) return found\n }\n return null\n}\n\n/** Each declared folder exists under public/ and no app route answers below it. */\nfunction assertStaticAssetFolders(folders: readonly BrandlabStaticAssetFolder[], root: string) {\n for (const { source, folder } of folders) {\n const publicFolder = posix.join('public', ...folder)\n if (!isDirectory(join(root, publicFolder))) {\n throw new Error(`staticAssetCache \"${source}\": ${publicFolder} is not a folder of static files in ${root}.`)\n }\n for (const appDirectory of ['src/app', 'app']) {\n if (!isDirectory(join(root, appDirectory))) continue\n const route = routeBelowFolder(join(root, appDirectory), folder, 0, appDirectory)\n if (route) {\n throw new Error(\n `staticAssetCache \"${source}\": ${route} answers below /${folder.join('/')}, so immutable caching could reach a page or route.`,\n )\n }\n }\n }\n}\n\n/**\n * Converts the redirect table to Next redirects: each entry keeps its 301 or\n * 308 status (Next forwards the query string), gains a single-hop\n * trailing-slash variant, then one trailing-slash rule and one permanent\n * canonical-host rule per alias host follow. There is no x-forwarded-proto\n * rule: Vercel's edge already enforces HTTPS.\n */\nexport function buildBrandlabRedirects(options: {\n site: BrandlabSite\n redirects: BrandlabRedirectTable\n}): BrandlabNextRedirect[] {\n const table = defineRedirects(options.redirects)\n const entries = table.flatMap((redirect): BrandlabNextRedirect[] => {\n const status = redirect.status === 301\n ? { statusCode: 301 as const }\n : { permanent: true as const }\n const has = redirect.host ? { has: [{ type: 'host' as const, value: redirect.host }] } : {}\n const record = (source: string): BrandlabNextRedirect => ({\n source,\n destination: redirect.destination,\n ...status,\n ...has,\n })\n return redirect.source === '/'\n ? [record(redirect.source)]\n : [record(redirect.source), record(`${redirect.source}/`)]\n })\n return [\n ...entries,\n { source: '/:path+/', destination: '/:path+', permanent: true },\n ...options.site.aliasHosts.map((host): BrandlabNextRedirect => ({\n source: '/:path*',\n has: [{ type: 'host', value: host }],\n destination: `${options.site.canonicalUrl}/:path*`,\n permanent: true,\n })),\n ]\n}\n\n/**\n * The whole next.config.ts after its first line\n * `import '@brandlab-digital/site-next/image-runtime'`:\n * `export default defineBrandlabNextConfig({ site, redirects, images })`.\n *\n * Sets poweredByHeader: false, WebP image output, Sharp output tracing for\n * /api/contact, NEXT_PUBLIC_VERCEL_ENV for browser gates, the deployment's\n * header rules (with immutable caching for the declared static public folders on\n * production builds) and the redirect table. Validation runs when the config\n * loads, so an invalid table, header exception or static folder fails the build.\n */\nexport function defineBrandlabNextConfig(\n options: BrandlabNextConfigOptions & { mdx?: undefined },\n): BrandlabNextConfig\nexport function defineBrandlabNextConfig<Wrapped>(\n options: BrandlabNextConfigOptions & {\n /** The @next/mdx wrapper: createMDX({ options: { remarkPlugins: ['remark-gfm'] } }). */\n mdx: (config: BrandlabNextConfig) => Wrapped\n },\n): Wrapped\nexport function defineBrandlabNextConfig(\n options: BrandlabNextConfigOptions & { mdx?: (config: BrandlabNextConfig) => unknown },\n): unknown {\n if (!options || typeof options !== 'object') {\n throw new TypeError('defineBrandlabNextConfig requires the site, redirects and images.')\n }\n assertKnownKeys(options, OPTION_KEYS, 'next.config options')\n if (!options.site?.canonicalUrl || !Array.isArray(options.site.aliasHosts)) {\n throw new Error('site must come from defineBrandlabSite.')\n }\n if (options.mdx !== undefined && typeof options.mdx !== 'function') {\n throw new TypeError('mdx must be the @next/mdx config wrapper.')\n }\n const deployment = resolveBrandlabDeployment(options.environment ?? process.env)\n if (options.staticAssetCache !== undefined) {\n assertStaticAssetFolders(\n parseBrandlabStaticAssetCache(options.staticAssetCache),\n options.projectRoot ?? process.cwd(),\n )\n }\n const headerRules = buildBrandlabHeaderRules({\n deployment,\n ...(options.csp ? { contentSecurityPolicyExtensions: options.csp } : {}),\n ...(options.hsts ? { hsts: options.hsts } : {}),\n ...(options.permissionsPolicy ? { permissionsPolicy: options.permissionsPolicy } : {}),\n ...(options.extraHeaders ? { extraHeaders: options.extraHeaders } : {}),\n ...(options.staticAssetCache ? { staticAssetCache: options.staticAssetCache } : {}),\n })\n const redirects = buildBrandlabRedirects({ site: options.site, redirects: options.redirects })\n\n const config: BrandlabNextConfig = {\n poweredByHeader: false,\n skipTrailingSlashRedirect: true,\n env: { NEXT_PUBLIC_VERCEL_ENV: deployment.environment },\n outputFileTracingIncludes: Object.fromEntries(\n Object.entries(BRANDLAB_CONTACT_OUTPUT_FILE_TRACING).map(([route, globs]) => [route, [...globs]]),\n ),\n images: buildImagesConfig(options.images),\n ...(options.mdx ? { pageExtensions: [...MDX_PAGE_EXTENSIONS] } : {}),\n headers: async () =>\n headerRules.map((rule) => ({ source: rule.source, headers: rule.headers.map((header) => ({ ...header })) })),\n redirects: async () =>\n redirects.map((redirect) => ({\n ...redirect,\n ...(redirect.has ? { has: redirect.has.map((condition) => ({ ...condition })) } : {}),\n })),\n }\n return options.mdx ? options.mdx(config) : config\n}\n"]}
package/dist/robots.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type BrandlabDeployment, type BrandlabEnvironment, type BrandlabSite } from '@brandlab-digital/site-core/site';
1
2
  export interface BrandlabRobotsMetadata {
2
3
  rules: Array<{
3
4
  userAgent: string;
@@ -6,10 +7,17 @@ export interface BrandlabRobotsMetadata {
6
7
  }>;
7
8
  sitemap?: string;
8
9
  }
9
- export declare function buildRobotsMetadata(options: {
10
- siteUrl: string;
11
- nodeEnv?: string;
12
- vercelEnv?: string;
13
- allowIndexing?: string;
14
- }): BrandlabRobotsMetadata;
10
+ /**
11
+ * Crawlers may index any production build except a Vercel Preview: the real
12
+ * production deployment and a local `next start`. `next dev` and every
13
+ * Preview are closed. There is no environment override.
14
+ */
15
+ export declare function isBrandlabIndexableDeployment(deployment: BrandlabDeployment): boolean;
16
+ /**
17
+ * `src/app/robots.ts`: `export default createBrandlabRobots(site)`.
18
+ * The deployment is resolved when Next renders robots.txt.
19
+ */
20
+ export declare function createBrandlabRobots(site: BrandlabSite, options?: {
21
+ environment?: BrandlabEnvironment;
22
+ }): () => BrandlabRobotsMetadata;
15
23
  //# sourceMappingURL=robots.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACtE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE;IAC3C,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,GAAG,sBAAsB,CAoBzB"}
1
+ {"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EAClB,MAAM,kCAAkC,CAAA;AAEzC,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACtE,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,kBAAkB,WAG3E;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,mBAAmB,CAAA;CAAO,SAGzB,sBAAsB,CAajD"}
package/dist/robots.js CHANGED
@@ -1,22 +1,31 @@
1
- import { getAbsoluteUrl } from '@brandlab-digital/site-core/metadata';
2
- import { shouldIndexSite } from '@brandlab-digital/site-core/sitemaps';
3
- export function buildRobotsMetadata(options) {
4
- const shouldIndex = shouldIndexSite({
5
- nodeEnv: options.nodeEnv,
6
- vercelEnv: options.vercelEnv,
7
- allowIndexing: options.allowIndexing,
8
- });
9
- if (!shouldIndex) {
1
+ import { resolveBrandlabDeployment, } from '@brandlab-digital/site-core/site';
2
+ /**
3
+ * Crawlers may index any production build except a Vercel Preview: the real
4
+ * production deployment and a local `next start`. `next dev` and every
5
+ * Preview are closed. There is no environment override.
6
+ */
7
+ export function isBrandlabIndexableDeployment(deployment) {
8
+ return deployment.environment === 'production' ||
9
+ (deployment.environment === 'development' && deployment.productionBuild);
10
+ }
11
+ /**
12
+ * `src/app/robots.ts`: `export default createBrandlabRobots(site)`.
13
+ * The deployment is resolved when Next renders robots.txt.
14
+ */
15
+ export function createBrandlabRobots(site, options = {}) {
16
+ const sitemap = `${site.canonicalUrl}/sitemap.xml`;
17
+ return function robots() {
18
+ const deployment = resolveBrandlabDeployment(options.environment ?? process.env);
19
+ if (!isBrandlabIndexableDeployment(deployment)) {
20
+ return { rules: [{ userAgent: '*', disallow: '/' }] };
21
+ }
22
+ // No `host` directive: it is a non-standard robots.txt extension ignored
23
+ // by Google and Bing; canonical-host consolidation is owned by permanent
24
+ // redirects and canonical URLs.
10
25
  return {
11
- rules: [{ userAgent: '*', disallow: '/' }],
26
+ rules: [{ userAgent: '*', allow: '/' }],
27
+ sitemap,
12
28
  };
13
- }
14
- // No `host` directive: it is a non-standard robots.txt extension ignored
15
- // by Google and Bing; canonical-host consolidation is owned by permanent
16
- // edge redirects + canonical URLs (Brandlab Project Standard §5).
17
- return {
18
- rules: [{ userAgent: '*', allow: '/' }],
19
- sitemap: getAbsoluteUrl(options.siteUrl, '/sitemap.xml'),
20
29
  };
21
30
  }
22
31
  //# sourceMappingURL=robots.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"robots.js","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAA;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAA;AAOtE,MAAM,UAAU,mBAAmB,CAAC,OAKnC;IACC,MAAM,WAAW,GAAG,eAAe,CAAC;QAClC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,aAAa,EAAE,OAAO,CAAC,aAAa;KACrC,CAAC,CAAA;IAEF,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,OAAO;YACL,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;SAC3C,CAAA;IACH,CAAC;IAED,yEAAyE;IACzE,yEAAyE;IACzE,kEAAkE;IAClE,OAAO;QACL,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;QACvC,OAAO,EAAE,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC;KACzD,CAAA;AACH,CAAC","sourcesContent":["import { getAbsoluteUrl } from '@brandlab-digital/site-core/metadata'\nimport { shouldIndexSite } from '@brandlab-digital/site-core/sitemaps'\n\nexport interface BrandlabRobotsMetadata {\n rules: Array<{ userAgent: string; allow?: string; disallow?: string }>\n sitemap?: string\n}\n\nexport function buildRobotsMetadata(options: {\n siteUrl: string\n nodeEnv?: string\n vercelEnv?: string\n allowIndexing?: string\n}): BrandlabRobotsMetadata {\n const shouldIndex = shouldIndexSite({\n nodeEnv: options.nodeEnv,\n vercelEnv: options.vercelEnv,\n allowIndexing: options.allowIndexing,\n })\n\n if (!shouldIndex) {\n return {\n rules: [{ userAgent: '*', disallow: '/' }],\n }\n }\n\n // No `host` directive: it is a non-standard robots.txt extension ignored\n // by Google and Bing; canonical-host consolidation is owned by permanent\n // edge redirects + canonical URLs (Brandlab Project Standard §5).\n return {\n rules: [{ userAgent: '*', allow: '/' }],\n sitemap: getAbsoluteUrl(options.siteUrl, '/sitemap.xml'),\n }\n}\n"]}
1
+ {"version":3,"file":"robots.js","sourceRoot":"","sources":["../src/robots.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,GAI1B,MAAM,kCAAkC,CAAA;AAOzC;;;;GAIG;AACH,MAAM,UAAU,6BAA6B,CAAC,UAA8B;IAC1E,OAAO,UAAU,CAAC,WAAW,KAAK,YAAY;QAC5C,CAAC,UAAU,CAAC,WAAW,KAAK,aAAa,IAAI,UAAU,CAAC,eAAe,CAAC,CAAA;AAC5E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAkB,EAClB,UAAiD,EAAE;IAEnD,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,YAAY,cAAc,CAAA;IAClD,OAAO,SAAS,MAAM;QACpB,MAAM,UAAU,GAAG,yBAAyB,CAAC,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,CAAA;QAChF,IAAI,CAAC,6BAA6B,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/C,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,CAAA;QACvD,CAAC;QACD,yEAAyE;QACzE,yEAAyE;QACzE,gCAAgC;QAChC,OAAO;YACL,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;YACvC,OAAO;SACR,CAAA;IACH,CAAC,CAAA;AACH,CAAC","sourcesContent":["import {\n resolveBrandlabDeployment,\n type BrandlabDeployment,\n type BrandlabEnvironment,\n type BrandlabSite,\n} from '@brandlab-digital/site-core/site'\n\nexport interface BrandlabRobotsMetadata {\n rules: Array<{ userAgent: string; allow?: string; disallow?: string }>\n sitemap?: string\n}\n\n/**\n * Crawlers may index any production build except a Vercel Preview: the real\n * production deployment and a local `next start`. `next dev` and every\n * Preview are closed. There is no environment override.\n */\nexport function isBrandlabIndexableDeployment(deployment: BrandlabDeployment) {\n return deployment.environment === 'production' ||\n (deployment.environment === 'development' && deployment.productionBuild)\n}\n\n/**\n * `src/app/robots.ts`: `export default createBrandlabRobots(site)`.\n * The deployment is resolved when Next renders robots.txt.\n */\nexport function createBrandlabRobots(\n site: BrandlabSite,\n options: { environment?: BrandlabEnvironment } = {},\n) {\n const sitemap = `${site.canonicalUrl}/sitemap.xml`\n return function robots(): BrandlabRobotsMetadata {\n const deployment = resolveBrandlabDeployment(options.environment ?? process.env)\n if (!isBrandlabIndexableDeployment(deployment)) {\n return { rules: [{ userAgent: '*', disallow: '/' }] }\n }\n // No `host` directive: it is a non-standard robots.txt extension ignored\n // by Google and Bing; canonical-host consolidation is owned by permanent\n // redirects and canonical URLs.\n return {\n rules: [{ userAgent: '*', allow: '/' }],\n sitemap,\n }\n }\n}\n"]}
@@ -1,6 +1,40 @@
1
+ import type { BrandlabRouteCatalog } from '@brandlab-digital/site-core/routes';
2
+ import type { BrandlabSite } from '@brandlab-digital/site-core/site';
1
3
  import { type SitemapEntry } from '@brandlab-digital/site-core/sitemaps';
2
4
  export declare function sitemapXmlResponse(entries: readonly SitemapEntry[]): Response;
3
5
  export declare function sitemapIndexXmlResponse(paths: readonly string[], options: {
4
6
  absoluteUrl: (path: string) => string;
5
7
  }): Response;
8
+ export type BrandlabSitemapMode = 'single' | 'split';
9
+ export interface BrandlabSitemapRouteOptions {
10
+ /** `split` only when brandlab.config declares `sitemap.mode: 'split'`. */
11
+ mode: BrandlabSitemapMode;
12
+ /** Split mode: URLs per child sitemap (default 1000). */
13
+ maxUrlsPerSitemap?: number;
14
+ }
15
+ export interface BrandlabSitemapChunkRouteContext {
16
+ params: Promise<{
17
+ chunk: string;
18
+ }>;
19
+ }
20
+ export interface BrandlabSitemapRoute {
21
+ readonly mode: BrandlabSitemapMode;
22
+ /** `src/app/sitemap.xml/route.ts`: the URL set, or the sitemap index in split mode. */
23
+ GET(): Response;
24
+ /** Child sitemap paths listed by the index; empty in single mode. */
25
+ chunkPaths(): string[];
26
+ /** `src/app/sitemaps/[chunk]/route.ts` (split mode, with `dynamicParams = false`). */
27
+ chunk: {
28
+ generateStaticParams(): {
29
+ chunk: string;
30
+ }[];
31
+ GET(request: Request, context: BrandlabSitemapChunkRouteContext): Promise<Response>;
32
+ };
33
+ }
34
+ /**
35
+ * The route-catalogue sitemap. `lastmod` comes only from each route's
36
+ * `lastSignificantChange`, never from build time. Entries are resolved once,
37
+ * so an invalid catalogue fails the build.
38
+ */
39
+ export declare function createBrandlabSitemapRoute(routes: BrandlabRouteCatalog, site: BrandlabSite, options?: BrandlabSitemapRouteOptions): BrandlabSitemapRoute;
6
40
  //# sourceMappingURL=sitemaps.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sitemaps.d.ts","sourceRoot":"","sources":["../src/sitemaps.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,sCAAsC,CAAA;AAE7C,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,QAAQ,CAI7E;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE;IAAE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,GACjD,QAAQ,CAIV"}
1
+ {"version":3,"file":"sitemaps.d.ts","sourceRoot":"","sources":["../src/sitemaps.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAqB,MAAM,oCAAoC,CAAA;AACjG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,EAOL,KAAK,YAAY,EAClB,MAAM,sCAAsC,CAAA;AAE7C,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,QAAQ,CAI7E;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE;IAAE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,GACjD,QAAQ,CAIV;AAED,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,OAAO,CAAA;AAEpD,MAAM,WAAW,2BAA2B;IAC1C,0EAA0E;IAC1E,IAAI,EAAE,mBAAmB,CAAA;IACzB,yDAAyD;IACzD,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,gCAAgC;IAC/C,MAAM,EAAE,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACnC;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAA;IAClC,uFAAuF;IACvF,GAAG,IAAI,QAAQ,CAAA;IACf,qEAAqE;IACrE,UAAU,IAAI,MAAM,EAAE,CAAA;IACtB,sFAAsF;IACtF,KAAK,EAAE;QACL,oBAAoB,IAAI;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;QAC3C,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,gCAAgC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;KACpF,CAAA;CACF;AAiCD;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,oBAAoB,EAC5B,IAAI,EAAE,YAAY,EAClB,OAAO,GAAE,2BAAgD,GACxD,oBAAoB,CAsCtB"}