@sixtyninecommerce/client 0.23.1 → 0.25.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 (299) hide show
  1. package/README.md +25 -0
  2. package/dist/admin/forms.js +19 -0
  3. package/dist/admin/forms.js.map +1 -1
  4. package/dist/admin/http.d.ts +9 -0
  5. package/dist/admin/http.d.ts.map +1 -1
  6. package/dist/admin/http.js +3 -0
  7. package/dist/admin/http.js.map +1 -1
  8. package/dist/admin/index.d.ts +63 -0
  9. package/dist/admin/index.d.ts.map +1 -1
  10. package/dist/admin/index.js +67 -0
  11. package/dist/admin/index.js.map +1 -1
  12. package/dist/admin/redirects.d.ts +6 -0
  13. package/dist/admin/redirects.d.ts.map +1 -1
  14. package/dist/admin/redirects.js +12 -0
  15. package/dist/admin/redirects.js.map +1 -1
  16. package/dist/admin/types.d.ts +63 -0
  17. package/dist/admin/types.d.ts.map +1 -1
  18. package/dist/cache-tags.d.ts +19 -0
  19. package/dist/cache-tags.d.ts.map +1 -1
  20. package/dist/cache-tags.js +19 -0
  21. package/dist/cache-tags.js.map +1 -1
  22. package/dist/client.d.ts +17 -0
  23. package/dist/client.d.ts.map +1 -1
  24. package/dist/client.js +17 -0
  25. package/dist/client.js.map +1 -1
  26. package/dist/commerce/age-verification.js +3 -3
  27. package/dist/commerce/age-verification.js.map +1 -1
  28. package/dist/commerce/branding.js +7 -0
  29. package/dist/commerce/branding.js.map +1 -1
  30. package/dist/commerce/cart.js +25 -0
  31. package/dist/commerce/cart.js.map +1 -1
  32. package/dist/commerce/checkout.d.ts +68 -0
  33. package/dist/commerce/checkout.d.ts.map +1 -1
  34. package/dist/commerce/checkout.js +83 -0
  35. package/dist/commerce/checkout.js.map +1 -1
  36. package/dist/commerce/customer.d.ts +58 -0
  37. package/dist/commerce/customer.d.ts.map +1 -1
  38. package/dist/commerce/customer.js +65 -0
  39. package/dist/commerce/customer.js.map +1 -1
  40. package/dist/commerce/index.d.ts +17 -1
  41. package/dist/commerce/index.d.ts.map +1 -1
  42. package/dist/commerce/pickup-location-parser.d.ts +18 -0
  43. package/dist/commerce/pickup-location-parser.d.ts.map +1 -1
  44. package/dist/commerce/pickup-location-parser.js +28 -0
  45. package/dist/commerce/pickup-location-parser.js.map +1 -1
  46. package/dist/commerce/placement-error.d.ts +52 -0
  47. package/dist/commerce/placement-error.d.ts.map +1 -1
  48. package/dist/commerce/placement-error.js +87 -0
  49. package/dist/commerce/placement-error.js.map +1 -1
  50. package/dist/commerce/products.d.ts +48 -0
  51. package/dist/commerce/products.d.ts.map +1 -1
  52. package/dist/commerce/products.js +95 -2
  53. package/dist/commerce/products.js.map +1 -1
  54. package/dist/commerce/queries.d.ts +114 -27
  55. package/dist/commerce/queries.d.ts.map +1 -1
  56. package/dist/commerce/queries.js +219 -1
  57. package/dist/commerce/queries.js.map +1 -1
  58. package/dist/commerce/quotes.js +33 -0
  59. package/dist/commerce/quotes.js.map +1 -1
  60. package/dist/commerce/saved-lists.d.ts +7 -7
  61. package/dist/commerce/saved-lists.d.ts.map +1 -1
  62. package/dist/commerce/saved-lists.js +1 -1
  63. package/dist/commerce/search.js +3 -0
  64. package/dist/commerce/search.js.map +1 -1
  65. package/dist/commerce/shipping.js +3 -3
  66. package/dist/commerce/shipping.js.map +1 -1
  67. package/dist/commerce/stock-notifications.d.ts +11 -0
  68. package/dist/commerce/stock-notifications.d.ts.map +1 -1
  69. package/dist/commerce/stock-notifications.js +11 -0
  70. package/dist/commerce/stock-notifications.js.map +1 -1
  71. package/dist/commerce/subscriptions.d.ts +32 -8
  72. package/dist/commerce/subscriptions.d.ts.map +1 -1
  73. package/dist/commerce/subscriptions.js +90 -2
  74. package/dist/commerce/subscriptions.js.map +1 -1
  75. package/dist/commerce/vat-validation.js +4 -4
  76. package/dist/commerce/vat-validation.js.map +1 -1
  77. package/dist/constants.d.ts +31 -0
  78. package/dist/constants.d.ts.map +1 -1
  79. package/dist/constants.js +32 -0
  80. package/dist/constants.js.map +1 -1
  81. package/dist/content/asset-urls.d.ts +50 -0
  82. package/dist/content/asset-urls.d.ts.map +1 -1
  83. package/dist/content/asset-urls.js +92 -0
  84. package/dist/content/asset-urls.js.map +1 -1
  85. package/dist/content/assets.d.ts +15 -0
  86. package/dist/content/assets.d.ts.map +1 -1
  87. package/dist/content/assets.js +15 -0
  88. package/dist/content/assets.js.map +1 -1
  89. package/dist/content/collection-pages.d.ts +5 -0
  90. package/dist/content/collection-pages.d.ts.map +1 -1
  91. package/dist/content/collection-pages.js +8 -0
  92. package/dist/content/collection-pages.js.map +1 -1
  93. package/dist/content/collections.d.ts +14 -0
  94. package/dist/content/collections.d.ts.map +1 -1
  95. package/dist/content/collections.js +16 -0
  96. package/dist/content/collections.js.map +1 -1
  97. package/dist/content/filtered-products.d.ts +18 -0
  98. package/dist/content/filtered-products.d.ts.map +1 -1
  99. package/dist/content/filtered-products.js +16 -0
  100. package/dist/content/filtered-products.js.map +1 -1
  101. package/dist/content/form-field-types.d.ts +6 -0
  102. package/dist/content/form-field-types.d.ts.map +1 -1
  103. package/dist/content/form-field-types.js +12 -0
  104. package/dist/content/form-field-types.js.map +1 -1
  105. package/dist/content/forms.d.ts +16 -0
  106. package/dist/content/forms.d.ts.map +1 -1
  107. package/dist/content/forms.js +23 -0
  108. package/dist/content/forms.js.map +1 -1
  109. package/dist/content/items.d.ts +26 -0
  110. package/dist/content/items.d.ts.map +1 -1
  111. package/dist/content/items.js +33 -0
  112. package/dist/content/items.js.map +1 -1
  113. package/dist/content/resolve.js +6 -0
  114. package/dist/content/resolve.js.map +1 -1
  115. package/dist/content/sitemap.d.ts +5 -0
  116. package/dist/content/sitemap.d.ts.map +1 -1
  117. package/dist/content/sitemap.js +5 -0
  118. package/dist/content/sitemap.js.map +1 -1
  119. package/dist/core/context.js +6 -0
  120. package/dist/core/context.js.map +1 -1
  121. package/dist/core/headers.js +2 -0
  122. package/dist/core/headers.js.map +1 -1
  123. package/dist/core/http.d.ts +8 -0
  124. package/dist/core/http.d.ts.map +1 -1
  125. package/dist/core/http.js +89 -1
  126. package/dist/core/http.js.map +1 -1
  127. package/dist/credit/credit-status.js +2 -2
  128. package/dist/credit/credit-status.js.map +1 -1
  129. package/dist/credit/payment-terms.js +2 -2
  130. package/dist/credit/payment-terms.js.map +1 -1
  131. package/dist/currency/exchange.d.ts +11 -0
  132. package/dist/currency/exchange.d.ts.map +1 -1
  133. package/dist/currency/exchange.js +11 -0
  134. package/dist/currency/exchange.js.map +1 -1
  135. package/dist/errors.d.ts +50 -2
  136. package/dist/errors.d.ts.map +1 -1
  137. package/dist/errors.js +50 -3
  138. package/dist/errors.js.map +1 -1
  139. package/dist/events/envelope.d.ts +36 -0
  140. package/dist/events/envelope.d.ts.map +1 -1
  141. package/dist/events/envelope.js +12 -0
  142. package/dist/events/envelope.js.map +1 -1
  143. package/dist/events/index.d.ts +13 -0
  144. package/dist/events/index.d.ts.map +1 -1
  145. package/dist/events/index.js +13 -0
  146. package/dist/events/index.js.map +1 -1
  147. package/dist/events/payloads.d.ts +19 -0
  148. package/dist/events/payloads.d.ts.map +1 -1
  149. package/dist/events/payloads.js +12 -0
  150. package/dist/events/payloads.js.map +1 -1
  151. package/dist/index.d.ts +8 -1
  152. package/dist/index.d.ts.map +1 -1
  153. package/dist/index.js +7 -0
  154. package/dist/index.js.map +1 -1
  155. package/dist/media/index.js +2 -0
  156. package/dist/media/index.js.map +1 -1
  157. package/dist/media/urls.d.ts +52 -0
  158. package/dist/media/urls.d.ts.map +1 -1
  159. package/dist/media/urls.js +38 -0
  160. package/dist/media/urls.js.map +1 -1
  161. package/dist/media/video.d.ts +16 -0
  162. package/dist/media/video.d.ts.map +1 -1
  163. package/dist/media/video.js +16 -0
  164. package/dist/media/video.js.map +1 -1
  165. package/dist/next/artifact-handler.d.ts +22 -0
  166. package/dist/next/artifact-handler.d.ts.map +1 -1
  167. package/dist/next/artifact-handler.js +22 -0
  168. package/dist/next/artifact-handler.js.map +1 -1
  169. package/dist/next/event-revalidate-handler.d.ts +67 -0
  170. package/dist/next/event-revalidate-handler.d.ts.map +1 -1
  171. package/dist/next/event-revalidate-handler.js +48 -0
  172. package/dist/next/event-revalidate-handler.js.map +1 -1
  173. package/dist/next/index.d.ts +6 -0
  174. package/dist/next/index.d.ts.map +1 -1
  175. package/dist/next/index.js +6 -0
  176. package/dist/next/index.js.map +1 -1
  177. package/dist/next/json-ld.d.ts +9 -0
  178. package/dist/next/json-ld.d.ts.map +1 -1
  179. package/dist/next/json-ld.js +9 -0
  180. package/dist/next/json-ld.js.map +1 -1
  181. package/dist/next/metadata.d.ts +18 -0
  182. package/dist/next/metadata.d.ts.map +1 -1
  183. package/dist/next/metadata.js +21 -0
  184. package/dist/next/metadata.js.map +1 -1
  185. package/dist/next/redirect-middleware.d.ts +39 -0
  186. package/dist/next/redirect-middleware.d.ts.map +1 -1
  187. package/dist/next/redirect-middleware.js +32 -0
  188. package/dist/next/redirect-middleware.js.map +1 -1
  189. package/dist/next/revalidate-handler.d.ts +30 -0
  190. package/dist/next/revalidate-handler.d.ts.map +1 -1
  191. package/dist/next/revalidate-handler.js +22 -0
  192. package/dist/next/revalidate-handler.js.map +1 -1
  193. package/dist/order-scope.d.ts +27 -0
  194. package/dist/order-scope.d.ts.map +1 -1
  195. package/dist/order-scope.js +29 -0
  196. package/dist/order-scope.js.map +1 -1
  197. package/dist/pricing/format.d.ts +17 -0
  198. package/dist/pricing/format.d.ts.map +1 -1
  199. package/dist/pricing/format.js +19 -0
  200. package/dist/pricing/format.js.map +1 -1
  201. package/dist/pricing/index.d.ts +8 -1
  202. package/dist/pricing/index.d.ts.map +1 -1
  203. package/dist/pricing/index.js +18 -2
  204. package/dist/pricing/index.js.map +1 -1
  205. package/dist/pricing/tax-display.d.ts +77 -0
  206. package/dist/pricing/tax-display.d.ts.map +1 -1
  207. package/dist/pricing/tax-display.js +85 -0
  208. package/dist/pricing/tax-display.js.map +1 -1
  209. package/dist/pricing/tiers.d.ts +9 -0
  210. package/dist/pricing/tiers.d.ts.map +1 -1
  211. package/dist/pricing/tiers.js +9 -0
  212. package/dist/pricing/tiers.js.map +1 -1
  213. package/dist/pricing/validation.d.ts +56 -1
  214. package/dist/pricing/validation.d.ts.map +1 -1
  215. package/dist/pricing/validation.js +61 -0
  216. package/dist/pricing/validation.js.map +1 -1
  217. package/dist/redirects/index.d.ts +1 -0
  218. package/dist/redirects/index.d.ts.map +1 -1
  219. package/dist/redirects/index.js +1 -0
  220. package/dist/redirects/index.js.map +1 -1
  221. package/dist/redirects/store.d.ts +20 -0
  222. package/dist/redirects/store.d.ts.map +1 -1
  223. package/dist/redirects/store.js +57 -0
  224. package/dist/redirects/store.js.map +1 -1
  225. package/dist/redirects/types.d.ts +24 -0
  226. package/dist/redirects/types.d.ts.map +1 -1
  227. package/dist/redirects/types.js +1 -0
  228. package/dist/redirects/types.js.map +1 -1
  229. package/dist/revalidation/event-plan.d.ts +48 -0
  230. package/dist/revalidation/event-plan.d.ts.map +1 -1
  231. package/dist/revalidation/event-plan.js +61 -0
  232. package/dist/revalidation/event-plan.js.map +1 -1
  233. package/dist/revalidation/event-verify.d.ts +25 -0
  234. package/dist/revalidation/event-verify.d.ts.map +1 -1
  235. package/dist/revalidation/event-verify.js +27 -0
  236. package/dist/revalidation/event-verify.js.map +1 -1
  237. package/dist/revalidation/types.d.ts +20 -0
  238. package/dist/revalidation/types.d.ts.map +1 -1
  239. package/dist/revalidation/types.js +10 -0
  240. package/dist/revalidation/types.js.map +1 -1
  241. package/dist/revalidation/url-context.d.ts +25 -0
  242. package/dist/revalidation/url-context.d.ts.map +1 -1
  243. package/dist/revalidation/url-context.js +17 -0
  244. package/dist/revalidation/url-context.js.map +1 -1
  245. package/dist/revalidation/verify.d.ts +8 -0
  246. package/dist/revalidation/verify.d.ts.map +1 -1
  247. package/dist/revalidation/verify.js +8 -0
  248. package/dist/revalidation/verify.js.map +1 -1
  249. package/dist/seo/ai.d.ts +17 -0
  250. package/dist/seo/ai.d.ts.map +1 -1
  251. package/dist/seo/ai.js +12 -0
  252. package/dist/seo/ai.js.map +1 -1
  253. package/dist/seo/alternates.js +13 -0
  254. package/dist/seo/alternates.js.map +1 -1
  255. package/dist/seo/artifacts.d.ts +13 -0
  256. package/dist/seo/artifacts.d.ts.map +1 -1
  257. package/dist/seo/artifacts.js +19 -0
  258. package/dist/seo/artifacts.js.map +1 -1
  259. package/dist/seo/canonical.d.ts +15 -0
  260. package/dist/seo/canonical.d.ts.map +1 -1
  261. package/dist/seo/canonical.js +24 -0
  262. package/dist/seo/canonical.js.map +1 -1
  263. package/dist/seo/index.js +6 -0
  264. package/dist/seo/index.js.map +1 -1
  265. package/dist/seo/json-ld.d.ts +13 -0
  266. package/dist/seo/json-ld.d.ts.map +1 -1
  267. package/dist/seo/json-ld.js +32 -0
  268. package/dist/seo/json-ld.js.map +1 -1
  269. package/dist/seo/locale-tag.d.ts +31 -0
  270. package/dist/seo/locale-tag.d.ts.map +1 -1
  271. package/dist/seo/locale-tag.js +31 -0
  272. package/dist/seo/locale-tag.js.map +1 -1
  273. package/dist/seo/meta-tags.d.ts +29 -0
  274. package/dist/seo/meta-tags.d.ts.map +1 -1
  275. package/dist/seo/meta-tags.js +28 -0
  276. package/dist/seo/meta-tags.js.map +1 -1
  277. package/dist/seo/metadata-parser.d.ts +24 -0
  278. package/dist/seo/metadata-parser.d.ts.map +1 -1
  279. package/dist/seo/metadata-parser.js +38 -0
  280. package/dist/seo/metadata-parser.js.map +1 -1
  281. package/dist/seo/metadata-types.d.ts +16 -0
  282. package/dist/seo/metadata-types.d.ts.map +1 -1
  283. package/dist/seo/product-path.d.ts +96 -0
  284. package/dist/seo/product-path.d.ts.map +1 -1
  285. package/dist/seo/product-path.js +96 -0
  286. package/dist/seo/product-path.js.map +1 -1
  287. package/dist/seo/robots.d.ts +17 -0
  288. package/dist/seo/robots.d.ts.map +1 -1
  289. package/dist/seo/robots.js +12 -0
  290. package/dist/seo/robots.js.map +1 -1
  291. package/dist/seo/types.d.ts +39 -0
  292. package/dist/seo/types.d.ts.map +1 -1
  293. package/dist/seo/url-builder.d.ts +31 -0
  294. package/dist/seo/url-builder.d.ts.map +1 -1
  295. package/dist/seo/url-builder.js +36 -0
  296. package/dist/seo/url-builder.js.map +1 -1
  297. package/dist/types.d.ts +1283 -2
  298. package/dist/types.d.ts.map +1 -1
  299. package/package.json +1 -1
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Parsed, strict types for the per-product SEO/social/AI metadata exposed by
3
+ * `Product.metadata` on the shop API. The raw GraphQL payload uses `JSON`
4
+ * scalars for several fields — we parse and validate at the SDK boundary so
5
+ * business logic only ever sees these typed shapes.
6
+ */
1
7
  import type { Asset } from '../types.js';
2
8
  export type MetaRobotsIndexDirective = 'index' | 'noindex';
3
9
  export type MetaRobotsFollowDirective = 'follow' | 'nofollow';
@@ -11,6 +17,7 @@ export interface MetaRobots {
11
17
  maxSnippet: number | null;
12
18
  maxImagePreview: MetaRobotsMaxImagePreview;
13
19
  maxVideoPreview: number | null;
20
+ /** ISO-8601 instant with timezone, or null. */
14
21
  unavailableAfter: string | null;
15
22
  }
16
23
  export interface QAPair {
@@ -48,6 +55,13 @@ export interface ProductMetadataAi {
48
55
  emitFaqpageJsonld: boolean;
49
56
  resolvedBotDirectives: Record<string, BotDirective>;
50
57
  }
58
+ /**
59
+ * The SEO/social metadata subset shared by every page kind (product,
60
+ * collection, CMS). `metaTagsFor()` operates on this shape so title,
61
+ * description, canonical, robots, OpenGraph and Twitter resolution is written
62
+ * once and reused across kinds. Product-only extras (AI directives, review
63
+ * JSON-LD, hreflang overrides, breadcrumb overrides) live on `ProductMetadata`.
64
+ */
51
65
  export interface CommonSeoMetadata {
52
66
  seoTitle: string | null;
53
67
  seoDescription: string | null;
@@ -62,7 +76,9 @@ export interface ProductMetadata extends CommonSeoMetadata {
62
76
  breadcrumbOverride: BreadcrumbOverrideEntry[];
63
77
  includeReviewsInJsonld: boolean;
64
78
  }
79
+ /** Per-collection SEO metadata (subset of the product shape). */
65
80
  export type CollectionMetadata = CommonSeoMetadata;
81
+ /** Per-CMS-item SEO metadata: the shared subset plus an optional AI summary. */
66
82
  export interface CmsItemMetadata extends CommonSeoMetadata {
67
83
  aiSummary: string | null;
68
84
  }
@@ -1 +1 @@
1
- {"version":3,"file":"metadata-types.d.ts","sourceRoot":"","sources":["../../src/seo/metadata-types.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,SAAS,CAAC;AAC3D,MAAM,MAAM,yBAAyB,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC9D,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,UAAU,GAAG,OAAO,CAAC;AAEtE,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,wBAAwB,CAAC;IAChC,MAAM,EAAE,yBAAyB,CAAC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,yBAAyB,CAAC;IAC3C,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAE/B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,qBAAqB,CAAC;AAChE,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC;AACjD,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,CAAC;AAE5C,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,eAAe,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,EAAE,KAAK,GAAG,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACrD;AASD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,qBAAqB,CAAC;IAC9B,OAAO,EAAE,sBAAsB,CAAC;IAChC,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,EAAE,EAAE,iBAAiB,CAAC;IACtB,iBAAiB,EAAE,qBAAqB,EAAE,CAAC;IAC3C,kBAAkB,EAAE,uBAAuB,EAAE,CAAC;IAC9C,sBAAsB,EAAE,OAAO,CAAC;CACjC;AAGD,MAAM,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAGnD,MAAM,WAAW,eAAgB,SAAQ,iBAAiB;IACxD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B"}
1
+ {"version":3,"file":"metadata-types.d.ts","sourceRoot":"","sources":["../../src/seo/metadata-types.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,106 @@
1
+ /**
2
+ * The ONE rule for where a product's canonical URL lives.
3
+ *
4
+ * Three surfaces used to answer this independently, and for a product in
5
+ * several collections with none flagged canonical they gave three different
6
+ * answers for the same product at the same moment:
7
+ *
8
+ * - `seo.metaTagsFor` / `canonicalFor` → /products/{slug} (hardcoded)
9
+ * - `navigation.getRoutes` → shallowest-then-lexicographic
10
+ * collection path
11
+ * - the sitemap artifact → whichever collection path the
12
+ * Shop API happened to return first
13
+ *
14
+ * None of them resolved on the storefronts they were generated for, and a
15
+ * canonical pointing at a 404 is worse than emitting none. This module holds
16
+ * the decision so the surfaces cannot drift again; `services/plugins` imports
17
+ * it from the published client rather than reimplementing it.
18
+ *
19
+ * The rule:
20
+ * 1. If the product belongs to a ROOT collection flagged
21
+ * `customFields.isCanonical`, its canonical URL nests under that
22
+ * collection. Lowest `position` wins; a caller-supplied key breaks ties so
23
+ * the choice is stable across runs and across surfaces.
24
+ * 2. Otherwise the canonical URL is FLAT: `/{productPathSegment}/{slug}`.
25
+ * Never a collection path — which collection a product happens to sit in
26
+ * is not a property of the product, and letting it decide the canonical is
27
+ * what made the three answers diverge.
28
+ */
29
+ /** Used when a channel sets no `productPathSegment`. */
1
30
  export declare const DEFAULT_PRODUCT_PATH_SEGMENT = "products";
31
+ /**
32
+ * Resolve the channel's configured product path segment.
33
+ *
34
+ * NULL, empty and whitespace all mean "unset" → the default, so a channel that
35
+ * never sets the field keeps the shape it had before the field existed. Leading
36
+ * and trailing slashes are tolerated and stripped: a merchant typing
37
+ * `/product/` means the same thing as `product`.
38
+ *
39
+ * Lowercased, because storefront routes are. A merchant typing `Products`
40
+ * would otherwise get `https://site/Products/x` as the canonical for a page
41
+ * served at `/products/x` — a canonical pointing at a 404, plus a case-variant
42
+ * duplicate for crawlers. The channel field's validator accepts either case
43
+ * precisely because this normalizes it.
44
+ */
2
45
  export declare function normalizeProductPathSegment(raw: string | null | undefined): string;
46
+ /**
47
+ * Index of the canonical-root entry, or null when the product has none and the
48
+ * caller should therefore use the flat product path.
49
+ *
50
+ * `tiebreak` keeps the result deterministic when two roots share a `position`.
51
+ * Every caller MUST pass the collection's **id**, and the reason is that the id
52
+ * is the only candidate that is language-invariant:
53
+ *
54
+ * - the route manifest fetches collections PER LANGUAGE, so its `slug` is the
55
+ * nl slug on the nl pass;
56
+ * - the SDK holds ONE fetched entity and emits every locale's URL from it, so
57
+ * its `slug` is whichever language the storefront fetched in.
58
+ *
59
+ * Tiebreaking on a slug therefore picks `wijnen` on one side and `deals` on the
60
+ * other for the same product, and the sitemap ends up flagging a different URL
61
+ * canonical than the page's own `<link rel="canonical">`. The path is worse
62
+ * still: `-` (0x2D) sorts below `/` (0x2F), so `shop` vs `shop-nl` diverges even
63
+ * in one language.
64
+ *
65
+ * The cost is that an equal-`position` tie resolves by an opaque id rather than
66
+ * something a merchant can predict. That is acceptable because it is only
67
+ * reachable by flagging two root collections canonical at the SAME position —
68
+ * give them distinct positions to choose deliberately.
69
+ */
3
70
  export declare function pickCanonicalRootIndex(entries: ReadonlyArray<{
4
71
  position: number;
5
72
  tiebreak: string;
6
73
  }>): number | null;
74
+ /** Vendure's synthetic tree root. Never a user-facing collection. */
7
75
  export declare const ROOT_COLLECTION_SLUG = "__root_collection__";
76
+ /**
77
+ * Whether a collection is a USER-FACING root — i.e. `isCanonical` can mean
78
+ * something on it.
79
+ *
80
+ * ONLY a parent that IS the sentinel counts. Two wrong answers to avoid:
81
+ *
82
+ * - `parent == null` was the original predicate and matched nothing real.
83
+ * Vendure's Shop API resolves a top-level collection's parent to the
84
+ * `__root_collection__` sentinel, not to null (verified against production:
85
+ * `collection(id: <top-level>)` returns
86
+ * `parent: { slug: "__root_collection__" }`), so canonical roots were never
87
+ * found and every product fell back to the flat path.
88
+ *
89
+ * - Treating null as root is ALSO wrong, and is why the null branch is gone.
90
+ * On the Shop API `parent` is `undefined` exactly when the real parent is
91
+ * PRIVATE (`CollectionEntityResolver.parent`: `apiType === 'shop' &&
92
+ * parent?.isPrivate ? undefined : parent`). A public collection under a
93
+ * private parent is not a root — and `CollectionService.getBreadcrumbs`
94
+ * does NOT filter private ancestors, so the routes manifest sees the full
95
+ * chain and does not treat it as one either. Calling it a root here would
96
+ * make the page self-declare `/{child}/{product}` while the manifest
97
+ * advertises the flat path: a canonical pointing at a URL no route serves.
98
+ *
99
+ * A parent with no `slug` selected is likewise not provably a root, so it takes
100
+ * the flat path. That is the conservative direction throughout — a wrong
101
+ * nesting is worse than a flat canonical — and the SDK's own product queries
102
+ * select `parent { id slug }` so its callers get the right answer by default.
103
+ */
8
104
  export declare function isUserFacingRoot(collection: {
9
105
  parent?: {
10
106
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"product-path.d.ts","sourceRoot":"","sources":["../../src/seo/product-path.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,4BAA4B,aAAa,CAAC;AAgBvD,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAQlF;AA0BD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,aAAa,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7D,MAAM,GAAG,IAAI,CAiBf;AAGD,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AA8B1D,wBAAgB,gBAAgB,CAAC,UAAU,EAAE;IAC3C,MAAM,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC/C,GAAG,OAAO,CAEV"}
1
+ {"version":3,"file":"product-path.d.ts","sourceRoot":"","sources":["../../src/seo/product-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,wDAAwD;AACxD,eAAO,MAAM,4BAA4B,aAAa,CAAC;AAEvD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAQlF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,aAAa,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,GAC7D,MAAM,GAAG,IAAI,CAiBf;AAED,qEAAqE;AACrE,eAAO,MAAM,oBAAoB,wBAAwB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE;IAC3C,MAAM,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC/C,GAAG,OAAO,CAEV"}
@@ -1,4 +1,47 @@
1
+ /**
2
+ * The ONE rule for where a product's canonical URL lives.
3
+ *
4
+ * Three surfaces used to answer this independently, and for a product in
5
+ * several collections with none flagged canonical they gave three different
6
+ * answers for the same product at the same moment:
7
+ *
8
+ * - `seo.metaTagsFor` / `canonicalFor` → /products/{slug} (hardcoded)
9
+ * - `navigation.getRoutes` → shallowest-then-lexicographic
10
+ * collection path
11
+ * - the sitemap artifact → whichever collection path the
12
+ * Shop API happened to return first
13
+ *
14
+ * None of them resolved on the storefronts they were generated for, and a
15
+ * canonical pointing at a 404 is worse than emitting none. This module holds
16
+ * the decision so the surfaces cannot drift again; `services/plugins` imports
17
+ * it from the published client rather than reimplementing it.
18
+ *
19
+ * The rule:
20
+ * 1. If the product belongs to a ROOT collection flagged
21
+ * `customFields.isCanonical`, its canonical URL nests under that
22
+ * collection. Lowest `position` wins; a caller-supplied key breaks ties so
23
+ * the choice is stable across runs and across surfaces.
24
+ * 2. Otherwise the canonical URL is FLAT: `/{productPathSegment}/{slug}`.
25
+ * Never a collection path — which collection a product happens to sit in
26
+ * is not a property of the product, and letting it decide the canonical is
27
+ * what made the three answers diverge.
28
+ */
29
+ /** Used when a channel sets no `productPathSegment`. */
1
30
  export const DEFAULT_PRODUCT_PATH_SEGMENT = 'products';
31
+ /**
32
+ * Resolve the channel's configured product path segment.
33
+ *
34
+ * NULL, empty and whitespace all mean "unset" → the default, so a channel that
35
+ * never sets the field keeps the shape it had before the field existed. Leading
36
+ * and trailing slashes are tolerated and stripped: a merchant typing
37
+ * `/product/` means the same thing as `product`.
38
+ *
39
+ * Lowercased, because storefront routes are. A merchant typing `Products`
40
+ * would otherwise get `https://site/Products/x` as the canonical for a page
41
+ * served at `/products/x` — a canonical pointing at a 404, plus a case-variant
42
+ * duplicate for crawlers. The channel field's validator accepts either case
43
+ * precisely because this normalizes it.
44
+ */
2
45
  export function normalizeProductPathSegment(raw) {
3
46
  if (typeof raw !== 'string')
4
47
  return DEFAULT_PRODUCT_PATH_SEGMENT;
@@ -9,6 +52,30 @@ export function normalizeProductPathSegment(raw) {
9
52
  .toLowerCase();
10
53
  return trimmed === '' ? DEFAULT_PRODUCT_PATH_SEGMENT : trimmed;
11
54
  }
55
+ /**
56
+ * Index of the canonical-root entry, or null when the product has none and the
57
+ * caller should therefore use the flat product path.
58
+ *
59
+ * `tiebreak` keeps the result deterministic when two roots share a `position`.
60
+ * Every caller MUST pass the collection's **id**, and the reason is that the id
61
+ * is the only candidate that is language-invariant:
62
+ *
63
+ * - the route manifest fetches collections PER LANGUAGE, so its `slug` is the
64
+ * nl slug on the nl pass;
65
+ * - the SDK holds ONE fetched entity and emits every locale's URL from it, so
66
+ * its `slug` is whichever language the storefront fetched in.
67
+ *
68
+ * Tiebreaking on a slug therefore picks `wijnen` on one side and `deals` on the
69
+ * other for the same product, and the sitemap ends up flagging a different URL
70
+ * canonical than the page's own `<link rel="canonical">`. The path is worse
71
+ * still: `-` (0x2D) sorts below `/` (0x2F), so `shop` vs `shop-nl` diverges even
72
+ * in one language.
73
+ *
74
+ * The cost is that an equal-`position` tie resolves by an opaque id rather than
75
+ * something a merchant can predict. That is acceptable because it is only
76
+ * reachable by flagging two root collections canonical at the SAME position —
77
+ * give them distinct positions to choose deliberately.
78
+ */
12
79
  export function pickCanonicalRootIndex(entries) {
13
80
  let best = null;
14
81
  for (let i = 0; i < entries.length; i += 1) {
@@ -25,7 +92,36 @@ export function pickCanonicalRootIndex(entries) {
25
92
  }
26
93
  return best;
27
94
  }
95
+ /** Vendure's synthetic tree root. Never a user-facing collection. */
28
96
  export const ROOT_COLLECTION_SLUG = '__root_collection__';
97
+ /**
98
+ * Whether a collection is a USER-FACING root — i.e. `isCanonical` can mean
99
+ * something on it.
100
+ *
101
+ * ONLY a parent that IS the sentinel counts. Two wrong answers to avoid:
102
+ *
103
+ * - `parent == null` was the original predicate and matched nothing real.
104
+ * Vendure's Shop API resolves a top-level collection's parent to the
105
+ * `__root_collection__` sentinel, not to null (verified against production:
106
+ * `collection(id: <top-level>)` returns
107
+ * `parent: { slug: "__root_collection__" }`), so canonical roots were never
108
+ * found and every product fell back to the flat path.
109
+ *
110
+ * - Treating null as root is ALSO wrong, and is why the null branch is gone.
111
+ * On the Shop API `parent` is `undefined` exactly when the real parent is
112
+ * PRIVATE (`CollectionEntityResolver.parent`: `apiType === 'shop' &&
113
+ * parent?.isPrivate ? undefined : parent`). A public collection under a
114
+ * private parent is not a root — and `CollectionService.getBreadcrumbs`
115
+ * does NOT filter private ancestors, so the routes manifest sees the full
116
+ * chain and does not treat it as one either. Calling it a root here would
117
+ * make the page self-declare `/{child}/{product}` while the manifest
118
+ * advertises the flat path: a canonical pointing at a URL no route serves.
119
+ *
120
+ * A parent with no `slug` selected is likewise not provably a root, so it takes
121
+ * the flat path. That is the conservative direction throughout — a wrong
122
+ * nesting is worse than a flat canonical — and the SDK's own product queries
123
+ * select `parent { id slug }` so its callers get the right answer by default.
124
+ */
29
125
  export function isUserFacingRoot(collection) {
30
126
  return collection.parent?.slug === ROOT_COLLECTION_SLUG;
31
127
  }
@@ -1 +1 @@
1
- {"version":3,"file":"product-path.js","sourceRoot":"","sources":["../../src/seo/product-path.ts"],"names":[],"mappings":"AA8BA,MAAM,CAAC,MAAM,4BAA4B,GAAG,UAAU,CAAC;AAgBvD,MAAM,UAAU,2BAA2B,CAAC,GAA8B;IACxE,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,4BAA4B,CAAC;IACjE,MAAM,OAAO,GAAG,GAAG;SAChB,IAAI,EAAE;SACN,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IACjB,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,OAAO,CAAC;AACjE,CAAC;AA0BD,MAAM,UAAU,sBAAsB,CACpC,OAA8D;IAE9D,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;QAC1B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,IAAI,GAAG,CAAC,CAAC;YACT,SAAS;QACX,CAAC;QACD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAE,CAAC;QACjC,IACE,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC,QAAQ;YACnC,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,EAC9E,CAAC;YACD,IAAI,GAAG,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAGD,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AA8B1D,MAAM,UAAU,gBAAgB,CAAC,UAEhC;IACC,OAAO,UAAU,CAAC,MAAM,EAAE,IAAI,KAAK,oBAAoB,CAAC;AAC1D,CAAC"}
1
+ {"version":3,"file":"product-path.js","sourceRoot":"","sources":["../../src/seo/product-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,wDAAwD;AACxD,MAAM,CAAC,MAAM,4BAA4B,GAAG,UAAU,CAAC;AAEvD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,2BAA2B,CAAC,GAA8B;IACxE,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,4BAA4B,CAAC;IACjE,MAAM,OAAO,GAAG,GAAG;SAChB,IAAI,EAAE;SACN,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IACjB,OAAO,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,OAAO,CAAC;AACjE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAA8D;IAE9D,IAAI,IAAI,GAAkB,IAAI,CAAC;IAC/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC;QAC1B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,IAAI,GAAG,CAAC,CAAC;YACT,SAAS;QACX,CAAC;QACD,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAE,CAAC;QACjC,IACE,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC,QAAQ;YACnC,CAAC,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAC,EAC9E,CAAC;YACD,IAAI,GAAG,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAEhC;IACC,OAAO,UAAU,CAAC,MAAM,EAAE,IAAI,KAAK,oBAAoB,CAAC;AAC1D,CAAC"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Robots / X-Robots directive composers. Given the parsed `metaRobots` block,
3
+ * produce the strings & tag descriptors a storefront needs to render in
4
+ * `<head>` or to attach to HTTP responses for non-HTML resources.
5
+ */
1
6
  import type { BotDirective, MetaRobots, ProductMetadata } from './metadata-types.js';
2
7
  export interface RobotsMetaTag {
3
8
  name: string;
@@ -16,6 +21,18 @@ export interface PerBotDirectives {
16
21
  metaTags: RobotsMetaTag[];
17
22
  xRobotsHeaders: RobotsXRobotsHeader[];
18
23
  }
24
+ /**
25
+ * Compose the `<meta name="robots">` value from a parsed `metaRobots` block.
26
+ * Order matches Google's documented preference: index/noindex, follow/nofollow,
27
+ * boolean flags, then `max-*` keyed values, then `unavailable_after`.
28
+ */
19
29
  export declare function composeRobotsContent(robots: MetaRobots): string;
30
+ /**
31
+ * Compose per-bot directives. Each "deny" entry gets a `noindex, nofollow`
32
+ * directive both as a `<meta>` tag (for HTML pages) and as an `X-Robots-Tag`
33
+ * header (for non-HTML resources). "allow" entries are not emitted — that's
34
+ * the implicit default; explicit allow tags would override stricter
35
+ * site-wide rules.
36
+ */
20
37
  export declare function composePerBotDirectives(metadata: ProductMetadata): PerBotDirectives;
21
38
  //# sourceMappingURL=robots.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../../src/seo/robots.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAErF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAC7C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACnC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,cAAc,EAAE,mBAAmB,EAAE,CAAC;CACvC;AAOD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAY/D;AASD,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,eAAe,GAAG,gBAAgB,CAkBnF"}
1
+ {"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../../src/seo/robots.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAErF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IAC7C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACnC,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,cAAc,EAAE,mBAAmB,EAAE,CAAC;CACvC;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAY/D;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,eAAe,GAAG,gBAAgB,CAkBnF"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Compose the `<meta name="robots">` value from a parsed `metaRobots` block.
3
+ * Order matches Google's documented preference: index/noindex, follow/nofollow,
4
+ * boolean flags, then `max-*` keyed values, then `unavailable_after`.
5
+ */
1
6
  export function composeRobotsContent(robots) {
2
7
  const parts = [robots.index, robots.follow];
3
8
  if (robots.noarchive)
@@ -16,6 +21,13 @@ export function composeRobotsContent(robots) {
16
21
  }
17
22
  return parts.join(', ');
18
23
  }
24
+ /**
25
+ * Compose per-bot directives. Each "deny" entry gets a `noindex, nofollow`
26
+ * directive both as a `<meta>` tag (for HTML pages) and as an `X-Robots-Tag`
27
+ * header (for non-HTML resources). "allow" entries are not emitted — that's
28
+ * the implicit default; explicit allow tags would override stricter
29
+ * site-wide rules.
30
+ */
19
31
  export function composePerBotDirectives(metadata) {
20
32
  const bots = metadata.ai.resolvedBotDirectives;
21
33
  const metaTags = [];
@@ -1 +1 @@
1
- {"version":3,"file":"robots.js","sourceRoot":"","sources":["../../src/seo/robots.ts"],"names":[],"mappings":"AA6BA,MAAM,UAAU,oBAAoB,CAAC,MAAkB;IACrD,MAAM,KAAK,GAAa,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACtD,IAAI,MAAM,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,YAAY;QAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACpD,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAC/E,KAAK,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;IAC1D,IAAI,MAAM,CAAC,eAAe,KAAK,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;IAC/F,IAAI,MAAM,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AASD,MAAM,UAAU,uBAAuB,CAAC,QAAyB;IAC/D,MAAM,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,qBAAqB,CAAC;IAC/C,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,MAAM,cAAc,GAA0B,EAAE,CAAC;IACjD,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACpD,IAAI,SAAS,KAAK,MAAM;YAAE,SAAS;QACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAC3D,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,GAAG,qBAAqB,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,OAAO;QACL,OAAO,EAAE;YACP,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,KAAK,KAAK,OAAO;YAC5C,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,MAAM,KAAK,QAAQ;SAChD;QACD,IAAI;QACJ,QAAQ;QACR,cAAc;KACf,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"robots.js","sourceRoot":"","sources":["../../src/seo/robots.ts"],"names":[],"mappings":"AAwBA;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAkB;IACrD,MAAM,KAAK,GAAa,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACtD,IAAI,MAAM,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC9C,IAAI,MAAM,CAAC,YAAY;QAAE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACpD,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;IAC/E,KAAK,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;IAC1D,IAAI,MAAM,CAAC,eAAe,KAAK,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;IAC/F,IAAI,MAAM,CAAC,gBAAgB,KAAK,IAAI,EAAE,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,qBAAqB,MAAM,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAyB;IAC/D,MAAM,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,qBAAqB,CAAC;IAC/C,MAAM,QAAQ,GAAoB,EAAE,CAAC;IACrC,MAAM,cAAc,GAA0B,EAAE,CAAC;IACjD,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACpD,IAAI,SAAS,KAAK,MAAM;YAAE,SAAS;QACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;QAC3D,cAAc,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,GAAG,qBAAqB,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,OAAO;QACL,OAAO,EAAE;YACP,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,KAAK,KAAK,OAAO;YAC5C,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,MAAM,KAAK,QAAQ;SAChD;QACD,IAAI;QACJ,QAAQ;QACR,cAAc;KACf,CAAC;AACJ,CAAC"}
@@ -1,8 +1,10 @@
1
1
  export type UrlLocaleStrategy = 'path-prefix' | 'subdomain' | 'none';
2
+ /** Locale-aware slug for any translatable entity. */
2
3
  export interface TranslatedSlug {
3
4
  languageCode: string;
4
5
  slug: string;
5
6
  }
7
+ /** Minimal Collection shape required for canonical / hreflang resolution. */
6
8
  export interface CollectionForSeo {
7
9
  id: string;
8
10
  slug: string;
@@ -17,15 +19,20 @@ export interface CollectionForSeo {
17
19
  isCanonical?: boolean | null;
18
20
  } | null;
19
21
  }
22
+ /** Product view needed for SEO resolution. Supply the slug + every translation you have. */
20
23
  export interface ProductForSeo {
21
24
  slug: string;
22
25
  translations?: TranslatedSlug[];
23
26
  collections: CollectionForSeo[];
24
27
  }
28
+ /** CMS resolve-layer item shape for SEO resolution. */
25
29
  export interface CmsItemForSeo {
30
+ /** Path already resolved via CMS ResolveService (locale-free canonical path). */
26
31
  path: string;
32
+ /** Per-language translated paths. `slug_translations` from the resolve response. */
27
33
  slug_translations?: Record<string, string> | null;
28
34
  }
35
+ /** Discriminated input to the SEO module methods. */
29
36
  export type SeoEntityInput = ({
30
37
  kind: 'product';
31
38
  } & ProductForSeo) | ({
@@ -34,8 +41,14 @@ export type SeoEntityInput = ({
34
41
  kind: 'cms';
35
42
  } & CmsItemForSeo);
36
43
  export interface HreflangLink {
44
+ /** BCP 47 spelling, ready to put in an `hreflang` attribute (`en-GB`). */
37
45
  hreflang: string;
38
46
  href: string;
47
+ /**
48
+ * The channel's raw Vendure `LanguageCode` for this row (`en_GB`) — the same
49
+ * locale as `hreflang`, in the spelling the commerce API and OpenGraph use.
50
+ * Optional so existing callers constructing this type keep compiling.
51
+ */
39
52
  languageCode?: string;
40
53
  }
41
54
  export interface SeoMeta {
@@ -44,18 +57,44 @@ export interface SeoMeta {
44
57
  xDefault: string;
45
58
  }
46
59
  export interface SeoModule {
60
+ /** Resolve the canonical URL for an entity (optionally per-locale). */
47
61
  canonicalFor(entity: SeoEntityInput, locale?: string): string;
62
+ /**
63
+ * Enumerate hreflang alternates. Only languages the entity actually has a
64
+ * translation in are emitted (plus `x-default`) — Google drops broken pairs.
65
+ */
48
66
  alternatesFor(entity: SeoEntityInput): HreflangLink[];
67
+ /** Combined meta bundle: canonical + alternates + xDefault. */
49
68
  metaFor(entity: SeoEntityInput): SeoMeta;
69
+ /** Low-level URL builder — composes `{storefrontUrl}{localePrefix}/{segments...}`. */
50
70
  buildUrl(segments: string[], locale?: string): string;
71
+ /**
72
+ * Full structured meta tag set for an entity: title, description, canonical,
73
+ * robots, OpenGraph, Twitter, hreflang, JSON-LD. Resolves fallbacks for
74
+ * missing per-product metadata.
75
+ */
51
76
  metaTagsFor(entity: import('./meta-tags.js').MetaTagsEntityInput): import('./meta-tags.js').MetaTagsResult;
77
+ /**
78
+ * Per-bot robots directives: composed `<meta>` tags and `X-Robots-Tag`
79
+ * headers based on the product's resolved bot directives.
80
+ */
52
81
  robotsDirectiveFor(entity: import('./ai.js').AiSummaryInput): import('./robots.js').PerBotDirectives;
82
+ /** AI summary string for storefronts to render as a head meta tag or inline section. */
53
83
  aiSummaryFor(entity: import('./ai.js').AiSummaryInput): string | null;
84
+ /** One markdown bullet for the channel `/llms.txt` file. */
54
85
  llmsTxtEntryFor(entity: import('./ai.js').LlmsTxtEntryInput): string;
86
+ /** Platform URL of the rendered sitemap index (or one child file). Proxy at /sitemap.xml. */
55
87
  sitemapUrl(childFile?: string): string;
88
+ /** Platform URL of the rendered robots.txt. Proxy at /robots.txt. */
56
89
  robotsUrl(): string;
90
+ /** Platform URL of the rendered llms.txt (404 unless enabled). Proxy at /llms.txt. */
57
91
  llmsTxtUrl(): string;
92
+ /** Platform URL of the IndexNow key file. Proxy at /{key}.txt. */
58
93
  indexnowKeyUrl(): string;
94
+ /**
95
+ * Fire-and-forget 404 beacon — call from the storefront's not-found handler
96
+ * so the platform can suggest redirects. Never throws, never blocks.
97
+ */
59
98
  reportNotFound(path: string, options?: {
60
99
  referrer?: string;
61
100
  }): void;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/seo/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG,WAAW,GAAG,MAAM,CAAC;AAGrE,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;IAChC,MAAM,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE;QACb,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;QAC5B,WAAW,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;KAC9B,GAAG,IAAI,CAAC;CACV;AAGD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;IAChC,WAAW,EAAE,gBAAgB,EAAE,CAAC;CACjC;AAGD,MAAM,WAAW,aAAa;IAE5B,IAAI,EAAE,MAAM,CAAC;IAEb,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CACnD;AAGD,MAAM,MAAM,cAAc,GACtB,CAAC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GAAG,aAAa,CAAC,GACrC,CAAC;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GAAG,gBAAgB,CAAC,GAC3C,CAAC;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GAAG,aAAa,CAAC,CAAC;AAEtC,MAAM,WAAW,YAAY;IAE3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IAMb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,YAAY,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IAExB,YAAY,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAK9D,aAAa,CAAC,MAAM,EAAE,cAAc,GAAG,YAAY,EAAE,CAAC;IAEtD,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC;IAEzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAMtD,WAAW,CACT,MAAM,EAAE,OAAO,gBAAgB,EAAE,mBAAmB,GACnD,OAAO,gBAAgB,EAAE,cAAc,CAAC;IAK3C,kBAAkB,CAChB,MAAM,EAAE,OAAO,SAAS,EAAE,cAAc,GACvC,OAAO,aAAa,EAAE,gBAAgB,CAAC;IAE1C,YAAY,CAAC,MAAM,EAAE,OAAO,SAAS,EAAE,cAAc,GAAG,MAAM,GAAG,IAAI,CAAC;IAEtE,eAAe,CAAC,MAAM,EAAE,OAAO,SAAS,EAAE,iBAAiB,GAAG,MAAM,CAAC;IAErE,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEvC,SAAS,IAAI,MAAM,CAAC;IAEpB,UAAU,IAAI,MAAM,CAAC;IAErB,cAAc,IAAI,MAAM,CAAC;IAKzB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACrE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/seo/types.ts"],"names":[],"mappings":"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"}
@@ -5,12 +5,43 @@ export interface UrlStrategyConfig {
5
5
  urlLocaleStrategy: UrlLocaleStrategy;
6
6
  urlLocalePrefixDefault: boolean;
7
7
  defaultLanguageCode: string;
8
+ /**
9
+ * Segment canonical product URLs sit under. Optional on purpose: this type is
10
+ * public API, and a hand-built config from before the field existed must keep
11
+ * working — absent normalizes to `products`, the previous hardcoded value.
12
+ */
8
13
  productPathSegment?: string | null;
14
+ /**
15
+ * Path prefix the storefront serves ALL commerce routes under, e.g. `/store`.
16
+ * Applies to products and collections, never to CMS pages — the same rule
17
+ * the routes manifest applies. Optional for the same compatibility reason.
18
+ */
9
19
  commercePathPrefix?: string | null;
20
+ /** Per-language `commercePathPrefix` overrides, `{ nl: '/winkel' }`. */
10
21
  commercePathPrefixTranslations?: Record<string, string> | null;
11
22
  }
23
+ /**
24
+ * Resolve the URL-strategy config from the channel's customFields. Throws a
25
+ * structured error when `storefrontUrl` is missing — canonical URLs must be
26
+ * absolute so there's no safe default.
27
+ */
12
28
  export declare function readUrlStrategy(ctx: StoreContext): UrlStrategyConfig;
29
+ /**
30
+ * {@link readUrlStrategy} for a channel read from anywhere — e.g. a fresh
31
+ * `activeChannel` query, whose custom fields can be newer than the snapshot the
32
+ * client took at startup.
33
+ */
13
34
  export declare function urlStrategyFromChannel(customFields: ChannelCustomFields | null | undefined, defaultLanguageCode: string): UrlStrategyConfig;
35
+ /**
36
+ * The commerce path prefix for a locale: the per-language override when one
37
+ * exists, else the channel default. Mirrors `RoutesService.applyCommercePrefix`
38
+ * exactly, including that an empty string disables prefixing for that locale.
39
+ */
14
40
  export declare function commercePrefixFor(cfg: UrlStrategyConfig, locale: string): string;
41
+ /**
42
+ * Compose an absolute URL for a given path (segments) and locale, respecting
43
+ * the channel's URL-locale strategy. Segments are joined with `/` and
44
+ * individually encoded; empty segments are dropped.
45
+ */
15
46
  export declare function buildUrl(cfg: UrlStrategyConfig, segments: string[], locale?: string): string;
16
47
  //# sourceMappingURL=url-builder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"url-builder.d.ts","sourceRoot":"","sources":["../../src/seo/url-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,sBAAsB,EAAE,OAAO,CAAC;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAM5B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAMnC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC,8BAA8B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CAChE;AAOD,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,iBAAiB,CAEpE;AAOD,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,EACpD,mBAAmB,EAAE,MAAM,GAC1B,iBAAiB,CA2BnB;AA2BD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOhF;AAOD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAwC5F"}
1
+ {"version":3,"file":"url-builder.d.ts","sourceRoot":"","sources":["../../src/seo/url-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGrE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,sBAAsB,EAAE,OAAO,CAAC;IAChC,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,wEAAwE;IACxE,8BAA8B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CAChE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,iBAAiB,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,mBAAmB,GAAG,IAAI,GAAG,SAAS,EACpD,mBAAmB,EAAE,MAAM,GAC1B,iBAAiB,CA2BnB;AAsBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAOhF;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAwC5F"}
@@ -1,9 +1,19 @@
1
1
  import { StorefrontError } from '../errors.js';
2
2
  import { toDnsLabel } from './locale-tag.js';
3
3
  import { normalizeProductPathSegment } from './product-path.js';
4
+ /**
5
+ * Resolve the URL-strategy config from the channel's customFields. Throws a
6
+ * structured error when `storefrontUrl` is missing — canonical URLs must be
7
+ * absolute so there's no safe default.
8
+ */
4
9
  export function readUrlStrategy(ctx) {
5
10
  return urlStrategyFromChannel(ctx.channel.customFields, ctx.channel.defaultLanguageCode);
6
11
  }
12
+ /**
13
+ * {@link readUrlStrategy} for a channel read from anywhere — e.g. a fresh
14
+ * `activeChannel` query, whose custom fields can be newer than the snapshot the
15
+ * client took at startup.
16
+ */
7
17
  export function urlStrategyFromChannel(customFields, defaultLanguageCode) {
8
18
  const cf = customFields ?? {};
9
19
  const storefrontUrl = typeof cf.storefrontUrl === 'string' ? cf.storefrontUrl.trim() : '';
@@ -24,6 +34,11 @@ export function urlStrategyFromChannel(customFields, defaultLanguageCode) {
24
34
  : null),
25
35
  };
26
36
  }
37
+ /**
38
+ * Parse the JSON-encoded per-language prefix overrides. Invalid JSON yields
39
+ * null rather than throwing — a malformed channel setting must not take the
40
+ * canonical URL down with it.
41
+ */
27
42
  function parsePrefixTranslations(raw) {
28
43
  if (!raw)
29
44
  return null;
@@ -42,6 +57,11 @@ function parsePrefixTranslations(raw) {
42
57
  return null;
43
58
  }
44
59
  }
60
+ /**
61
+ * The commerce path prefix for a locale: the per-language override when one
62
+ * exists, else the channel default. Mirrors `RoutesService.applyCommercePrefix`
63
+ * exactly, including that an empty string disables prefixing for that locale.
64
+ */
45
65
  export function commercePrefixFor(cfg, locale) {
46
66
  const translations = cfg.commercePathPrefixTranslations;
47
67
  const raw = translations && Object.hasOwn(translations, locale)
@@ -49,6 +69,11 @@ export function commercePrefixFor(cfg, locale) {
49
69
  : cfg.commercePathPrefix;
50
70
  return (raw ?? '').replace(/\/+$/, '');
51
71
  }
72
+ /**
73
+ * Compose an absolute URL for a given path (segments) and locale, respecting
74
+ * the channel's URL-locale strategy. Segments are joined with `/` and
75
+ * individually encoded; empty segments are dropped.
76
+ */
52
77
  export function buildUrl(cfg, segments, locale) {
53
78
  const resolvedLocale = locale ?? cfg.defaultLanguageCode;
54
79
  const clean = segments
@@ -57,16 +82,27 @@ export function buildUrl(cfg, segments, locale) {
57
82
  .map((s) => encodeURI(s));
58
83
  const path = clean.length > 0 ? `/${clean.join('/')}` : '';
59
84
  const isDefault = resolvedLocale === cfg.defaultLanguageCode;
85
+ // A blank locale emits no segment at all. The previous implementation got this
86
+ // for free because it tested the encoded prefix STRING for emptiness; deriving
87
+ // the flag from `isDefault` alone would turn `locale: ''` into `//path` and, in
88
+ // subdomain mode, the invalid host `https://.example.com`. `??` above does not
89
+ // catch `''`, and this is published API a caller may reach with `locale ?? ''`.
60
90
  const emitLocale = resolvedLocale !== '' && (!isDefault || cfg.urlLocalePrefixDefault);
61
91
  switch (cfg.urlLocaleStrategy) {
62
92
  case 'path-prefix': {
93
+ // The PATH segment keeps the raw Vendure spelling (`/en_GB/...`): the
94
+ // storefront reads this segment back out and passes it straight to the
95
+ // commerce and CMS APIs, which key on the Vendure code.
63
96
  const localePart = emitLocale ? `/${encodeURIComponent(resolvedLocale)}` : '';
64
97
  return `${cfg.storefrontUrl}${localePart}${path}`;
65
98
  }
66
99
  case 'subdomain': {
67
100
  if (!emitLocale)
68
101
  return `${cfg.storefrontUrl}${path}`;
102
+ // A hostname label may not contain `_`, so a region tag has to be
103
+ // hyphenated and lower-cased here: `en_GB` → `en-gb.example.com`.
69
104
  const label = encodeURIComponent(toDnsLabel(resolvedLocale));
105
+ // Insert subdomain after the protocol: https://host → https://nl.host
70
106
  return (cfg.storefrontUrl.replace(/^(https?:\/\/)([^/]+)/, (_match, scheme, host) => `${scheme}${label}.${host}`) + path);
71
107
  }
72
108
  case 'none':
@@ -1 +1 @@
1
- {"version":3,"file":"url-builder.js","sourceRoot":"","sources":["../../src/seo/url-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"url-builder.js","sourceRoot":"","sources":["../../src/seo/url-builder.ts"],"names":[],"mappings":"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"}