@sixtyninecommerce/client 0.29.0 → 0.31.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 (358) hide show
  1. package/README.md +556 -16
  2. package/dist/admin/http.d.ts.map +1 -1
  3. package/dist/admin/http.js.map +1 -1
  4. package/dist/admin/types.d.ts.map +1 -1
  5. package/dist/build-client.d.ts +9 -0
  6. package/dist/build-client.d.ts.map +1 -0
  7. package/dist/build-client.js +58 -0
  8. package/dist/build-client.js.map +1 -0
  9. package/dist/cache-tags.d.ts +35 -1
  10. package/dist/cache-tags.d.ts.map +1 -1
  11. package/dist/cache-tags.js +39 -1
  12. package/dist/cache-tags.js.map +1 -1
  13. package/dist/client.d.ts +25 -0
  14. package/dist/client.d.ts.map +1 -1
  15. package/dist/client.js +9 -62
  16. package/dist/client.js.map +1 -1
  17. package/dist/commerce/age-verification.d.ts +7 -4
  18. package/dist/commerce/age-verification.d.ts.map +1 -1
  19. package/dist/commerce/age-verification.js +6 -4
  20. package/dist/commerce/age-verification.js.map +1 -1
  21. package/dist/commerce/arguments.d.ts +13 -0
  22. package/dist/commerce/arguments.d.ts.map +1 -0
  23. package/dist/commerce/arguments.js +19 -0
  24. package/dist/commerce/arguments.js.map +1 -0
  25. package/dist/commerce/branding.d.ts.map +1 -1
  26. package/dist/commerce/branding.js.map +1 -1
  27. package/dist/commerce/capabilities.d.ts +40 -0
  28. package/dist/commerce/capabilities.d.ts.map +1 -0
  29. package/dist/commerce/capabilities.js +41 -0
  30. package/dist/commerce/capabilities.js.map +1 -0
  31. package/dist/commerce/cart.d.ts +9 -12
  32. package/dist/commerce/cart.d.ts.map +1 -1
  33. package/dist/commerce/cart.js +6 -1
  34. package/dist/commerce/cart.js.map +1 -1
  35. package/dist/commerce/checkout.d.ts +95 -15
  36. package/dist/commerce/checkout.d.ts.map +1 -1
  37. package/dist/commerce/checkout.js +230 -10
  38. package/dist/commerce/checkout.js.map +1 -1
  39. package/dist/commerce/customer.d.ts +82 -38
  40. package/dist/commerce/customer.d.ts.map +1 -1
  41. package/dist/commerce/customer.js +146 -10
  42. package/dist/commerce/customer.js.map +1 -1
  43. package/dist/commerce/favorites.d.ts +2 -5
  44. package/dist/commerce/favorites.d.ts.map +1 -1
  45. package/dist/commerce/favorites.js.map +1 -1
  46. package/dist/commerce/index.d.ts +189 -133
  47. package/dist/commerce/index.d.ts.map +1 -1
  48. package/dist/commerce/index.js +9 -0
  49. package/dist/commerce/index.js.map +1 -1
  50. package/dist/commerce/order-states.d.ts +18 -0
  51. package/dist/commerce/order-states.d.ts.map +1 -0
  52. package/dist/commerce/order-states.js +30 -0
  53. package/dist/commerce/order-states.js.map +1 -0
  54. package/dist/commerce/parcel-pricing.d.ts +48 -0
  55. package/dist/commerce/parcel-pricing.d.ts.map +1 -0
  56. package/dist/commerce/parcel-pricing.js +39 -0
  57. package/dist/commerce/parcel-pricing.js.map +1 -0
  58. package/dist/commerce/parked-orders.d.ts +22 -0
  59. package/dist/commerce/parked-orders.d.ts.map +1 -0
  60. package/dist/commerce/parked-orders.js +47 -0
  61. package/dist/commerce/parked-orders.js.map +1 -0
  62. package/dist/commerce/payments.d.ts +12 -5
  63. package/dist/commerce/payments.d.ts.map +1 -1
  64. package/dist/commerce/payments.js +10 -1
  65. package/dist/commerce/payments.js.map +1 -1
  66. package/dist/commerce/placement-error.d.ts +17 -0
  67. package/dist/commerce/placement-error.d.ts.map +1 -1
  68. package/dist/commerce/placement-error.js.map +1 -1
  69. package/dist/commerce/products.d.ts +92 -38
  70. package/dist/commerce/products.d.ts.map +1 -1
  71. package/dist/commerce/products.js +162 -123
  72. package/dist/commerce/products.js.map +1 -1
  73. package/dist/commerce/queries.d.ts +204 -49
  74. package/dist/commerce/queries.d.ts.map +1 -1
  75. package/dist/commerce/queries.js +1296 -737
  76. package/dist/commerce/queries.js.map +1 -1
  77. package/dist/commerce/quotes.d.ts +5 -4
  78. package/dist/commerce/quotes.d.ts.map +1 -1
  79. package/dist/commerce/quotes.js +1 -36
  80. package/dist/commerce/quotes.js.map +1 -1
  81. package/dist/commerce/recommendations.d.ts +3 -3
  82. package/dist/commerce/recommendations.d.ts.map +1 -1
  83. package/dist/commerce/recommendations.js +3 -1
  84. package/dist/commerce/recommendations.js.map +1 -1
  85. package/dist/commerce/returns.d.ts +7 -6
  86. package/dist/commerce/returns.d.ts.map +1 -1
  87. package/dist/commerce/returns.js.map +1 -1
  88. package/dist/commerce/reviews.d.ts +24 -15
  89. package/dist/commerce/reviews.d.ts.map +1 -1
  90. package/dist/commerce/reviews.js +67 -50
  91. package/dist/commerce/reviews.js.map +1 -1
  92. package/dist/commerce/saved-lists.d.ts +15 -15
  93. package/dist/commerce/saved-lists.d.ts.map +1 -1
  94. package/dist/commerce/saved-lists.js +67 -55
  95. package/dist/commerce/saved-lists.js.map +1 -1
  96. package/dist/commerce/search.d.ts +3 -2
  97. package/dist/commerce/search.d.ts.map +1 -1
  98. package/dist/commerce/search.js +10 -2
  99. package/dist/commerce/search.js.map +1 -1
  100. package/dist/commerce/shipping.d.ts +11 -4
  101. package/dist/commerce/shipping.d.ts.map +1 -1
  102. package/dist/commerce/shipping.js +17 -2
  103. package/dist/commerce/shipping.js.map +1 -1
  104. package/dist/commerce/stock-notifications.d.ts +2 -0
  105. package/dist/commerce/stock-notifications.d.ts.map +1 -1
  106. package/dist/commerce/stock-notifications.js +2 -2
  107. package/dist/commerce/stock-notifications.js.map +1 -1
  108. package/dist/commerce/subscriptions.d.ts +35 -37
  109. package/dist/commerce/subscriptions.d.ts.map +1 -1
  110. package/dist/commerce/subscriptions.js +159 -120
  111. package/dist/commerce/subscriptions.js.map +1 -1
  112. package/dist/commerce/vat-validation.d.ts +6 -3
  113. package/dist/commerce/vat-validation.d.ts.map +1 -1
  114. package/dist/commerce/vat-validation.js +24 -19
  115. package/dist/commerce/vat-validation.js.map +1 -1
  116. package/dist/constants.d.ts.map +1 -1
  117. package/dist/constants.js.map +1 -1
  118. package/dist/content/assets.d.ts +5 -4
  119. package/dist/content/assets.d.ts.map +1 -1
  120. package/dist/content/assets.js.map +1 -1
  121. package/dist/content/collection-pages.d.ts +3 -2
  122. package/dist/content/collection-pages.d.ts.map +1 -1
  123. package/dist/content/collection-pages.js.map +1 -1
  124. package/dist/content/collections.d.ts +5 -4
  125. package/dist/content/collections.d.ts.map +1 -1
  126. package/dist/content/collections.js.map +1 -1
  127. package/dist/content/filtered-products.d.ts.map +1 -1
  128. package/dist/content/filtered-products.js.map +1 -1
  129. package/dist/content/form-field-types.d.ts +3 -3
  130. package/dist/content/form-field-types.d.ts.map +1 -1
  131. package/dist/content/form-field-types.js.map +1 -1
  132. package/dist/content/forms.d.ts +4 -3
  133. package/dist/content/forms.d.ts.map +1 -1
  134. package/dist/content/forms.js +3 -0
  135. package/dist/content/forms.js.map +1 -1
  136. package/dist/content/index.d.ts +18 -17
  137. package/dist/content/index.d.ts.map +1 -1
  138. package/dist/content/items.d.ts +5 -4
  139. package/dist/content/items.d.ts.map +1 -1
  140. package/dist/content/items.js +2 -0
  141. package/dist/content/items.js.map +1 -1
  142. package/dist/content/menus.d.ts +3 -2
  143. package/dist/content/menus.d.ts.map +1 -1
  144. package/dist/content/menus.js +7 -1
  145. package/dist/content/menus.js.map +1 -1
  146. package/dist/content/resolve.d.ts +3 -2
  147. package/dist/content/resolve.d.ts.map +1 -1
  148. package/dist/content/resolve.js +1 -1
  149. package/dist/content/resolve.js.map +1 -1
  150. package/dist/content/sitemap.d.ts +3 -2
  151. package/dist/content/sitemap.d.ts.map +1 -1
  152. package/dist/content/sitemap.js.map +1 -1
  153. package/dist/content/strings.d.ts +16 -2
  154. package/dist/content/strings.d.ts.map +1 -1
  155. package/dist/content/strings.js +32 -4
  156. package/dist/content/strings.js.map +1 -1
  157. package/dist/core/context.d.ts +127 -1
  158. package/dist/core/context.d.ts.map +1 -1
  159. package/dist/core/context.js +436 -45
  160. package/dist/core/context.js.map +1 -1
  161. package/dist/core/currency.d.ts +14 -0
  162. package/dist/core/currency.d.ts.map +1 -0
  163. package/dist/core/currency.js +52 -0
  164. package/dist/core/currency.js.map +1 -0
  165. package/dist/core/deprecation.d.ts +23 -0
  166. package/dist/core/deprecation.d.ts.map +1 -0
  167. package/dist/core/deprecation.js +81 -0
  168. package/dist/core/deprecation.js.map +1 -0
  169. package/dist/core/http.d.ts +15 -1
  170. package/dist/core/http.d.ts.map +1 -1
  171. package/dist/core/http.js +55 -3
  172. package/dist/core/http.js.map +1 -1
  173. package/dist/core/public-artifact.d.ts +72 -0
  174. package/dist/core/public-artifact.d.ts.map +1 -0
  175. package/dist/core/public-artifact.js +122 -0
  176. package/dist/core/public-artifact.js.map +1 -0
  177. package/dist/core/unknown-field-rejection.d.ts +18 -0
  178. package/dist/core/unknown-field-rejection.d.ts.map +1 -0
  179. package/dist/core/unknown-field-rejection.js +37 -0
  180. package/dist/core/unknown-field-rejection.js.map +1 -0
  181. package/dist/credit/credit-status.d.ts +2 -0
  182. package/dist/credit/credit-status.d.ts.map +1 -1
  183. package/dist/credit/credit-status.js +71 -19
  184. package/dist/credit/credit-status.js.map +1 -1
  185. package/dist/credit/index.d.ts +1 -1
  186. package/dist/credit/payment-terms.d.ts +3 -3
  187. package/dist/credit/payment-terms.d.ts.map +1 -1
  188. package/dist/credit/payment-terms.js +28 -24
  189. package/dist/credit/payment-terms.js.map +1 -1
  190. package/dist/currency/exchange.d.ts +7 -7
  191. package/dist/currency/exchange.d.ts.map +1 -1
  192. package/dist/currency/exchange.js +5 -1
  193. package/dist/currency/exchange.js.map +1 -1
  194. package/dist/errors.d.ts +17 -0
  195. package/dist/errors.d.ts.map +1 -1
  196. package/dist/errors.js +13 -0
  197. package/dist/errors.js.map +1 -1
  198. package/dist/events/index.d.ts +20 -7
  199. package/dist/events/index.d.ts.map +1 -1
  200. package/dist/events/index.js +17 -5
  201. package/dist/events/index.js.map +1 -1
  202. package/dist/events/payloads.d.ts +7 -4
  203. package/dist/events/payloads.d.ts.map +1 -1
  204. package/dist/events/payloads.js +6 -3
  205. package/dist/events/payloads.js.map +1 -1
  206. package/dist/feeds/index.d.ts +5 -0
  207. package/dist/feeds/index.d.ts.map +1 -0
  208. package/dist/feeds/index.js +12 -0
  209. package/dist/feeds/index.js.map +1 -0
  210. package/dist/feeds/types.d.ts +18 -0
  211. package/dist/feeds/types.d.ts.map +1 -0
  212. package/dist/feeds/types.js +8 -0
  213. package/dist/feeds/types.js.map +1 -0
  214. package/dist/generated/cms.d.ts +2136 -0
  215. package/dist/generated/cms.d.ts.map +1 -0
  216. package/dist/generated/cms.js +4 -0
  217. package/dist/generated/cms.js.map +1 -0
  218. package/dist/generated/plugins.d.ts +550 -0
  219. package/dist/generated/plugins.d.ts.map +1 -0
  220. package/dist/generated/plugins.js +4 -0
  221. package/dist/generated/plugins.js.map +1 -0
  222. package/dist/generated/shop.d.ts +5539 -0
  223. package/dist/generated/shop.d.ts.map +1 -0
  224. package/dist/generated/shop.js +5 -0
  225. package/dist/generated/shop.js.map +1 -0
  226. package/dist/graphql-document.d.ts +29 -0
  227. package/dist/graphql-document.d.ts.map +1 -0
  228. package/dist/graphql-document.js +21 -0
  229. package/dist/graphql-document.js.map +1 -0
  230. package/dist/index.d.ts +9 -4
  231. package/dist/index.d.ts.map +1 -1
  232. package/dist/index.js +4 -2
  233. package/dist/index.js.map +1 -1
  234. package/dist/media/urls.d.ts.map +1 -1
  235. package/dist/media/urls.js +12 -1
  236. package/dist/media/urls.js.map +1 -1
  237. package/dist/media/video.d.ts.map +1 -1
  238. package/dist/media/video.js.map +1 -1
  239. package/dist/multi-store.d.ts +200 -0
  240. package/dist/multi-store.d.ts.map +1 -0
  241. package/dist/multi-store.js +558 -0
  242. package/dist/multi-store.js.map +1 -0
  243. package/dist/navigation/routes.d.ts +4 -3
  244. package/dist/navigation/routes.d.ts.map +1 -1
  245. package/dist/navigation/routes.js.map +1 -1
  246. package/dist/next/artifact-handler.d.ts +21 -13
  247. package/dist/next/artifact-handler.d.ts.map +1 -1
  248. package/dist/next/artifact-handler.js +28 -66
  249. package/dist/next/artifact-handler.js.map +1 -1
  250. package/dist/next/event-revalidate-handler.d.ts +26 -6
  251. package/dist/next/event-revalidate-handler.d.ts.map +1 -1
  252. package/dist/next/event-revalidate-handler.js +126 -19
  253. package/dist/next/event-revalidate-handler.js.map +1 -1
  254. package/dist/next/feed-handler.d.ts +50 -0
  255. package/dist/next/feed-handler.d.ts.map +1 -0
  256. package/dist/next/feed-handler.js +61 -0
  257. package/dist/next/feed-handler.js.map +1 -0
  258. package/dist/next/index.d.ts +3 -1
  259. package/dist/next/index.d.ts.map +1 -1
  260. package/dist/next/index.js +1 -0
  261. package/dist/next/index.js.map +1 -1
  262. package/dist/next/metadata.d.ts.map +1 -1
  263. package/dist/next/metadata.js.map +1 -1
  264. package/dist/next/redirect-middleware.d.ts +5 -31
  265. package/dist/next/redirect-middleware.d.ts.map +1 -1
  266. package/dist/next/redirect-middleware.js +4 -46
  267. package/dist/next/redirect-middleware.js.map +1 -1
  268. package/dist/next/revalidate-handler.d.ts.map +1 -1
  269. package/dist/next/revalidate-handler.js.map +1 -1
  270. package/dist/pricing/index.d.ts +1 -1
  271. package/dist/pricing/index.d.ts.map +1 -1
  272. package/dist/pricing/index.js +5 -2
  273. package/dist/pricing/index.js.map +1 -1
  274. package/dist/pricing/tax-display.js +1 -1
  275. package/dist/pricing/tax-display.js.map +1 -1
  276. package/dist/pricing/tiers.d.ts +3 -2
  277. package/dist/pricing/tiers.d.ts.map +1 -1
  278. package/dist/pricing/tiers.js.map +1 -1
  279. package/dist/pricing/validation.d.ts +152 -13
  280. package/dist/pricing/validation.d.ts.map +1 -1
  281. package/dist/pricing/validation.js +167 -13
  282. package/dist/pricing/validation.js.map +1 -1
  283. package/dist/redirects/index.d.ts.map +1 -1
  284. package/dist/redirects/index.js +2 -1
  285. package/dist/redirects/index.js.map +1 -1
  286. package/dist/redirects/store.d.ts.map +1 -1
  287. package/dist/redirects/store.js +6 -2
  288. package/dist/redirects/store.js.map +1 -1
  289. package/dist/redirects/types.d.ts +5 -2
  290. package/dist/redirects/types.d.ts.map +1 -1
  291. package/dist/revalidation/event-plan.d.ts +55 -4
  292. package/dist/revalidation/event-plan.d.ts.map +1 -1
  293. package/dist/revalidation/event-plan.js +115 -8
  294. package/dist/revalidation/event-plan.js.map +1 -1
  295. package/dist/revalidation/event-verify.d.ts +8 -37
  296. package/dist/revalidation/event-verify.d.ts.map +1 -1
  297. package/dist/revalidation/event-verify.js +7 -97
  298. package/dist/revalidation/event-verify.js.map +1 -1
  299. package/dist/revalidation/types.d.ts.map +1 -1
  300. package/dist/revalidation/url-context.d.ts +17 -0
  301. package/dist/revalidation/url-context.d.ts.map +1 -1
  302. package/dist/revalidation/url-context.js +35 -2
  303. package/dist/revalidation/url-context.js.map +1 -1
  304. package/dist/seo/ai.d.ts.map +1 -1
  305. package/dist/seo/ai.js.map +1 -1
  306. package/dist/seo/artifacts.d.ts +86 -4
  307. package/dist/seo/artifacts.d.ts.map +1 -1
  308. package/dist/seo/artifacts.js +115 -16
  309. package/dist/seo/artifacts.js.map +1 -1
  310. package/dist/seo/availability.d.ts +95 -0
  311. package/dist/seo/availability.d.ts.map +1 -0
  312. package/dist/seo/availability.js +89 -0
  313. package/dist/seo/availability.js.map +1 -0
  314. package/dist/seo/index.d.ts +4 -0
  315. package/dist/seo/index.d.ts.map +1 -1
  316. package/dist/seo/index.js +6 -1
  317. package/dist/seo/index.js.map +1 -1
  318. package/dist/seo/json-ld.d.ts.map +1 -1
  319. package/dist/seo/json-ld.js +34 -1
  320. package/dist/seo/json-ld.js.map +1 -1
  321. package/dist/seo/meta-tags.d.ts +40 -1
  322. package/dist/seo/meta-tags.d.ts.map +1 -1
  323. package/dist/seo/meta-tags.js +8 -1
  324. package/dist/seo/meta-tags.js.map +1 -1
  325. package/dist/seo/metadata-parser.d.ts.map +1 -1
  326. package/dist/seo/metadata-parser.js.map +1 -1
  327. package/dist/seo/metadata-types.d.ts.map +1 -1
  328. package/dist/seo/robots.d.ts.map +1 -1
  329. package/dist/seo/robots.js.map +1 -1
  330. package/dist/seo/types.d.ts +20 -2
  331. package/dist/seo/types.d.ts.map +1 -1
  332. package/dist/seo/url-builder.d.ts +5 -3
  333. package/dist/seo/url-builder.d.ts.map +1 -1
  334. package/dist/seo/url-builder.js +3 -1
  335. package/dist/seo/url-builder.js.map +1 -1
  336. package/dist/types.d.ts +1306 -2429
  337. package/dist/types.d.ts.map +1 -1
  338. package/dist/web/artifact-responder.d.ts +69 -0
  339. package/dist/web/artifact-responder.d.ts.map +1 -0
  340. package/dist/web/artifact-responder.js +90 -0
  341. package/dist/web/artifact-responder.js.map +1 -0
  342. package/dist/web/feed-responder.d.ts +72 -0
  343. package/dist/web/feed-responder.d.ts.map +1 -0
  344. package/dist/web/feed-responder.js +81 -0
  345. package/dist/web/feed-responder.js.map +1 -0
  346. package/dist/web/index.d.ts +23 -0
  347. package/dist/web/index.d.ts.map +1 -0
  348. package/dist/web/index.js +19 -0
  349. package/dist/web/index.js.map +1 -0
  350. package/dist/web/redirect-middleware.d.ts +76 -0
  351. package/dist/web/redirect-middleware.d.ts.map +1 -0
  352. package/dist/web/redirect-middleware.js +94 -0
  353. package/dist/web/redirect-middleware.js.map +1 -0
  354. package/dist/web/respond.d.ts +20 -0
  355. package/dist/web/respond.d.ts.map +1 -0
  356. package/dist/web/respond.js +52 -0
  357. package/dist/web/respond.js.map +1 -0
  358. package/package.json +19 -3
@@ -1,10 +1,73 @@
1
1
  /**
2
- * Platform artifact URLs + the 404 beacon. The platform renders sitemap.xml,
3
- * robots.txt, llms.txt and the IndexNow key file per channel; the storefront
4
- * proxies them on its own origin (see `@sixtyninecommerce/client/next`'s
5
- * `createSeoArtifactHandler`).
2
+ * Platform artifact URLs, the framework-neutral artifact read, and the 404
3
+ * beacon. The platform renders sitemap.xml, robots.txt, llms.txt and the
4
+ * IndexNow key file per channel; the storefront serves them on its own origin
5
+ * (`createSeoArtifactResponder` from `@sixtyninecommerce/client/web`, or
6
+ * `createSeoArtifactHandler` from `@sixtyninecommerce/client/next`).
6
7
  */
8
+ import { type PublicArtifactRead } from '../core/public-artifact.js';
9
+ import type * as Plugins from '../generated/plugins.js';
7
10
  import type { StoreContext } from '../types.js';
11
+ /** Every artifact the platform renders per store. */
12
+ export declare const SEO_ARTIFACTS: readonly ["sitemap", "sitemap-child", "robots", "llms-txt", "indexnow-key"];
13
+ export type SeoArtifact = (typeof SEO_ARTIFACTS)[number];
14
+ /** The `200` body a path item's GET declares, whatever its media type. */
15
+ type DeclaredBody<PathItem> = PathItem extends {
16
+ get: {
17
+ responses: {
18
+ 200: {
19
+ content: infer Content;
20
+ };
21
+ };
22
+ };
23
+ } ? Content[keyof Content] : never;
24
+ /**
25
+ * One artifact read — see `client.seo.artifacts.fetch`. Narrow on `status`:
26
+ * only a `200` has a `body`: the text (`robots.txt`, `llms.txt`, the IndexNow
27
+ * key) or XML (the sitemaps) the plugins service declares — a `string`.
28
+ */
29
+ export type SeoArtifactResult = PublicArtifactRead<DeclaredBody<Plugins.paths['/seo/artifacts/{channelCode}/sitemap.xml']> | DeclaredBody<Plugins.paths['/seo/artifacts/{channelCode}/sitemaps/{file}']> | DeclaredBody<Plugins.paths['/seo/artifacts/{channelCode}/robots.txt']> | DeclaredBody<Plugins.paths['/seo/artifacts/{channelCode}/llms.txt']> | DeclaredBody<Plugins.paths['/seo/artifacts/{channelCode}/indexnow-key.txt']>>;
30
+ export interface SeoArtifactFetchOptions {
31
+ /**
32
+ * The child sitemap's file name (`products-1.xml`) — required for
33
+ * `'sitemap-child'`, refused for every other artifact.
34
+ */
35
+ childFile?: string;
36
+ /** The validator your caller sent (`If-None-Match`); a match answers `304`. */
37
+ ifNoneMatch?: string;
38
+ /** Cancels the read; an abort through it rejects with the signal's reason. */
39
+ signal?: AbortSignal;
40
+ /** Deadline for the whole read, body included; past it the result is `503`. Default 15s. */
41
+ timeoutMs?: number;
42
+ }
43
+ export interface SeoArtifactsModule {
44
+ /**
45
+ * Read one platform-rendered SEO artifact for this store — framework-neutral,
46
+ * so any server can serve it on the storefront's own origin.
47
+ *
48
+ * Never throws for an upstream problem: the result is `200` (body, content
49
+ * type, `ETag`), `304` (unchanged since `ifNoneMatch`), `404` (the platform
50
+ * has no such file for this store; `detail` says why — llms.txt is off, no
51
+ * SEO plugin or storefront URL, the child sitemap is gone) or `503` with
52
+ * `retryAfterSeconds` (another upstream status, in `upstreamStatus` with the
53
+ * platform's `detail`; or a network failure or the timeout, in `error`).
54
+ * Throws `StorefrontError` `INVALID_ARGUMENT` before any request
55
+ * for an unknown artifact, a missing or malformed `childFile` on
56
+ * `'sitemap-child'` (the platform's own rule: `<kind>-<n>.xml`), or a
57
+ * `childFile` on any other artifact; rejects with the signal's reason when
58
+ * YOUR `signal` aborts.
59
+ *
60
+ * Sends no credential (the files are public) and no `User-Agent` of the
61
+ * caller's, uses the client's configured `fetch`, and sets no cache policy.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const robots = await client.seo.artifacts.fetch('robots');
66
+ * if (robots.status === 200) console.log(robots.etag, robots.body);
67
+ * ```
68
+ */
69
+ fetch(artifact: SeoArtifact, options?: SeoArtifactFetchOptions): Promise<SeoArtifactResult>;
70
+ }
8
71
  export interface SeoArtifactUrls {
9
72
  /** Platform URL of the sitemap index, or of one child file when `childFile` is given. */
10
73
  sitemapUrl(childFile?: string): string;
@@ -14,6 +77,24 @@ export interface SeoArtifactUrls {
14
77
  indexnowKeyUrl(): string;
15
78
  }
16
79
  export declare function createArtifactUrls(ctx: StoreContext): SeoArtifactUrls;
80
+ /** Upstream deadline when the caller names none. */
81
+ export declare const DEFAULT_ARTIFACT_TIMEOUT_MS = 15000;
82
+ /** Whether `name` is a child-sitemap file name the platform can serve. */
83
+ export declare function isSitemapChildFile(name: string): boolean;
84
+ export declare function isSeoArtifact(value: unknown): value is SeoArtifact;
85
+ /**
86
+ * The platform URL of one artifact, with every argument refused before a
87
+ * request is made. Reads only the builder it needs, so a caller may pass any
88
+ * object carrying them (`client.seo` does).
89
+ */
90
+ export declare function seoArtifactUrl(urls: Partial<SeoArtifactUrls>, artifact: SeoArtifact, childFile: string | undefined): string;
91
+ /**
92
+ * The one artifact read every surface shares: `client.seo.artifacts.fetch`,
93
+ * the `/web` responder, the `/next` handler and the MCP preview. `init` adds
94
+ * framework keys to the request (the Next handler's `next: { tags }`).
95
+ */
96
+ export declare function fetchSeoArtifact(urls: Partial<SeoArtifactUrls>, fetchFn: typeof globalThis.fetch, artifact: SeoArtifact, options: SeoArtifactFetchOptions | undefined, init?: Record<string, unknown>): Promise<SeoArtifactResult>;
97
+ export declare function createArtifactsModule(ctx: StoreContext, urls: SeoArtifactUrls): SeoArtifactsModule;
17
98
  /**
18
99
  * Fire-and-forget 404 report — call from the storefront's not-found handler
19
100
  * so the platform can suggest redirects for dead URLs. Never throws, never
@@ -22,4 +103,5 @@ export declare function createArtifactUrls(ctx: StoreContext): SeoArtifactUrls;
22
103
  export declare function reportNotFound(ctx: StoreContext, path: string, options?: {
23
104
  referrer?: string;
24
105
  }): void;
106
+ export {};
25
107
  //# sourceMappingURL=artifacts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../src/seo/artifacts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,eAAe;IAC9B,yFAAyF;IACzF,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvC,SAAS,IAAI,MAAM,CAAC;IACpB,UAAU,IAAI,MAAM,CAAC;IACrB,6EAA6E;IAC7E,cAAc,IAAI,MAAM,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,YAAY,GAAG,eAAe,CAkBrE;AAYD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9B,IAAI,CA0BN"}
1
+ {"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../src/seo/artifacts.ts"],"names":[],"mappings":"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"}
@@ -1,34 +1,128 @@
1
1
  /**
2
- * Platform artifact URLs + the 404 beacon. The platform renders sitemap.xml,
3
- * robots.txt, llms.txt and the IndexNow key file per channel; the storefront
4
- * proxies them on its own origin (see `@sixtyninecommerce/client/next`'s
5
- * `createSeoArtifactHandler`).
2
+ * Platform artifact URLs, the framework-neutral artifact read, and the 404
3
+ * beacon. The platform renders sitemap.xml, robots.txt, llms.txt and the
4
+ * IndexNow key file per channel; the storefront serves them on its own origin
5
+ * (`createSeoArtifactResponder` from `@sixtyninecommerce/client/web`, or
6
+ * `createSeoArtifactHandler` from `@sixtyninecommerce/client/next`).
6
7
  */
8
+ import { readPublicArtifact } from '../core/public-artifact.js';
9
+ import { StorefrontError } from '../errors.js';
10
+ /** Every artifact the platform renders per store. */
11
+ export const SEO_ARTIFACTS = [
12
+ 'sitemap',
13
+ 'sitemap-child',
14
+ 'robots',
15
+ 'llms-txt',
16
+ 'indexnow-key',
17
+ ];
7
18
  export function createArtifactUrls(ctx) {
8
- const base = `${ctx.pluginsUrl}/seo/artifacts/${encodeURIComponent(ctx.channel.code)}`;
19
+ // Per call, never at build: the store's code can move under a running client (a rename), and
20
+ // the old code's URLs stop answering a while after it.
21
+ const base = () => `${ctx.pluginsUrl}/seo/artifacts/${encodeURIComponent(ctx.channel.code)}`;
9
22
  return {
10
23
  sitemapUrl(childFile) {
11
24
  return childFile
12
- ? `${base}/sitemaps/${encodeURIComponent(childFile)}`
13
- : `${base}/sitemap.xml`;
25
+ ? `${base()}/sitemaps/${encodeURIComponent(childFile)}`
26
+ : `${base()}/sitemap.xml`;
14
27
  },
15
28
  robotsUrl() {
16
- return `${base}/robots.txt`;
29
+ return `${base()}/robots.txt`;
17
30
  },
18
31
  llmsTxtUrl() {
19
- return `${base}/llms.txt`;
32
+ return `${base()}/llms.txt`;
20
33
  },
21
34
  indexnowKeyUrl() {
22
- return `${base}/indexnow-key.txt`;
35
+ return `${base()}/indexnow-key.txt`;
36
+ },
37
+ };
38
+ }
39
+ /** Upstream deadline when the caller names none. */
40
+ export const DEFAULT_ARTIFACT_TIMEOUT_MS = 15_000;
41
+ /**
42
+ * The platform's child-sitemap rule, verbatim from the plugins service
43
+ * (`seo/artifacts/artifacts.controller.ts`): `products-1.xml`, `collections-2.xml`.
44
+ * Checked here too so a crawler probing `/sitemaps/<anything>` is a `404` on
45
+ * the storefront, not a platform `400` a proxy would report as an outage.
46
+ * Locked to the controller AND the sitemap builder by
47
+ * `services/plugins/src/seo/__tests__/sitemap-child-name-parity.spec.ts`: widen
48
+ * the grammar there and here in the same change, and release this SDK before
49
+ * the platform emits the new names.
50
+ */
51
+ const SITEMAP_CHILD_FILE = /^[a-z]+-\d+\.xml$/;
52
+ /** Whether `name` is a child-sitemap file name the platform can serve. */
53
+ export function isSitemapChildFile(name) {
54
+ return SITEMAP_CHILD_FILE.test(name);
55
+ }
56
+ function invalidArtifactArgument(message) {
57
+ return new StorefrontError(message, 'plugins', 400, 'INVALID_ARGUMENT');
58
+ }
59
+ export function isSeoArtifact(value) {
60
+ return typeof value === 'string' && SEO_ARTIFACTS.includes(value);
61
+ }
62
+ /**
63
+ * The platform URL of one artifact, with every argument refused before a
64
+ * request is made. Reads only the builder it needs, so a caller may pass any
65
+ * object carrying them (`client.seo` does).
66
+ */
67
+ export function seoArtifactUrl(urls, artifact, childFile) {
68
+ if (!isSeoArtifact(artifact)) {
69
+ throw invalidArtifactArgument(`Unknown SEO artifact "${String(artifact)}". Expected one of: ${SEO_ARTIFACTS.join(', ')}.`);
70
+ }
71
+ if (artifact !== 'sitemap-child' && childFile !== undefined) {
72
+ throw invalidArtifactArgument(`childFile is only for 'sitemap-child'; '${artifact}' has no child files.`);
73
+ }
74
+ const builder = artifactUrlBuilder(urls, artifact);
75
+ if (artifact === 'sitemap-child') {
76
+ if (childFile === undefined || childFile === '') {
77
+ throw invalidArtifactArgument("'sitemap-child' requires childFile, the child sitemap's file name (e.g. products-1.xml).");
78
+ }
79
+ if (!isSitemapChildFile(childFile)) {
80
+ throw invalidArtifactArgument(`"${childFile}" is not a child sitemap file name; the platform serves <kind>-<n>.xml (e.g. products-1.xml).`);
81
+ }
82
+ return builder(childFile);
83
+ }
84
+ return builder();
85
+ }
86
+ function artifactUrlBuilder(urls, artifact) {
87
+ const builder = artifact === 'sitemap' || artifact === 'sitemap-child'
88
+ ? urls.sitemapUrl
89
+ : artifact === 'robots'
90
+ ? urls.robotsUrl
91
+ : artifact === 'llms-txt'
92
+ ? urls.llmsTxtUrl
93
+ : urls.indexnowKeyUrl;
94
+ if (typeof builder !== 'function') {
95
+ throw new TypeError(`The client has no URL builder for the '${artifact}' artifact.`);
96
+ }
97
+ return builder;
98
+ }
99
+ /**
100
+ * The one artifact read every surface shares: `client.seo.artifacts.fetch`,
101
+ * the `/web` responder, the `/next` handler and the MCP preview. `init` adds
102
+ * framework keys to the request (the Next handler's `next: { tags }`).
103
+ */
104
+ export function fetchSeoArtifact(urls, fetchFn, artifact, options, init) {
105
+ const url = seoArtifactUrl(urls, artifact, options?.childFile);
106
+ return readPublicArtifact(fetchFn, url, (response) => response.text(), {
107
+ timeoutMs: options?.timeoutMs ?? DEFAULT_ARTIFACT_TIMEOUT_MS,
108
+ ...(options?.ifNoneMatch ? { ifNoneMatch: options.ifNoneMatch } : {}),
109
+ ...(options?.signal ? { signal: options.signal } : {}),
110
+ ...(init ? { init } : {}),
111
+ });
112
+ }
113
+ export function createArtifactsModule(ctx, urls) {
114
+ return {
115
+ async fetch(artifact, options) {
116
+ return fetchSeoArtifact(urls, ctx.fetch, artifact, options);
23
117
  },
24
118
  };
25
119
  }
26
120
  const BEACON_TIMEOUT_MS = 2_000;
27
121
  /**
28
- * Per-process dedup set, capped so a long-lived server process being crawled
29
- * for random URLs can't grow it without bound. Past the cap the set resets:
30
- * occasional re-reports are fine (the platform aggregates), unbounded memory
31
- * is not.
122
+ * Per-process dedup set of `<channel id>\0<path>`, capped so a long-lived
123
+ * server process being crawled for random URLs can't grow it without bound.
124
+ * Past the cap the set resets: occasional re-reports are fine (the platform
125
+ * aggregates), unbounded memory is not.
32
126
  */
33
127
  const MAX_REPORTED_PATHS = 5_000;
34
128
  const reportedPaths = new Set();
@@ -38,13 +132,18 @@ const reportedPaths = new Set();
38
132
  * blocks rendering; deduped per process/session.
39
133
  */
40
134
  export function reportNotFound(ctx, path, options) {
41
- if (!path.startsWith('/') || path.length > 2000 || reportedPaths.has(path)) {
135
+ // Keyed by STORE and path: the set is per process, and a process may serve
136
+ // several stores (`createStorefrontClient({ resolveStore })`, or two clients
137
+ // side by side) — keyed by path alone, store B's dead `/sale` was never
138
+ // reported once store A had reported its own.
139
+ const key = `${ctx.channel.id}\u0000${path}`;
140
+ if (!path.startsWith('/') || path.length > 2000 || reportedPaths.has(key)) {
42
141
  return;
43
142
  }
44
143
  if (reportedPaths.size >= MAX_REPORTED_PATHS) {
45
144
  reportedPaths.clear();
46
145
  }
47
- reportedPaths.add(path);
146
+ reportedPaths.add(key);
48
147
  try {
49
148
  void ctx
50
149
  .fetch(`${ctx.pluginsUrl}/seo/not-found-reports`, {
@@ -1 +1 @@
1
- {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/seo/artifacts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,MAAM,UAAU,kBAAkB,CAAC,GAAiB;IAClD,MAAM,IAAI,GAAG,GAAG,GAAG,CAAC,UAAU,kBAAkB,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IACvF,OAAO;QACL,UAAU,CAAC,SAAkB;YAC3B,OAAO,SAAS;gBACd,CAAC,CAAC,GAAG,IAAI,aAAa,kBAAkB,CAAC,SAAS,CAAC,EAAE;gBACrD,CAAC,CAAC,GAAG,IAAI,cAAc,CAAC;QAC5B,CAAC;QACD,SAAS;YACP,OAAO,GAAG,IAAI,aAAa,CAAC;QAC9B,CAAC;QACD,UAAU;YACR,OAAO,GAAG,IAAI,WAAW,CAAC;QAC5B,CAAC;QACD,cAAc;YACZ,OAAO,GAAG,IAAI,mBAAmB,CAAC;QACpC,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAChC;;;;;GAKG;AACH,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACjC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;AAExC;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAiB,EACjB,IAAY,EACZ,OAA+B;IAE/B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,IAAI,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3E,OAAO;IACT,CAAC;IACD,IAAI,aAAa,CAAC,IAAI,IAAI,kBAAkB,EAAE,CAAC;QAC7C,aAAa,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IACD,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAExB,IAAI,CAAC;QACH,KAAK,GAAG;aACL,KAAK,CAAC,GAAG,GAAG,CAAC,UAAU,wBAAwB,EAAE;YAChD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,cAAc,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE;aAC/B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,IAAI,EAAE,CAAC;YACnE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,iBAAiB,CAAC;SAC/C,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,mCAAmC;QACrC,CAAC,CAAC,CAAC;IACP,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;IAC/D,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/seo/artifacts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Availability for structured data: one variant's stock + merchant publication
3
+ * state, expressed as the schema.org `ItemAvailability` URL that
4
+ * `Offer.availability` wants and the OpenGraph token `product:availability`
5
+ * wants.
6
+ *
7
+ * These are separate vocabularies for the same fact, and `ProductSeoExtras`
8
+ * carries ONE `availability` string that feeds both tags. So the schema.org URL
9
+ * is the value a storefront passes, and `openGraphAvailability` translates it
10
+ * back for the OpenGraph tag. Anything the SDK does not recognise is passed
11
+ * through untouched, which is what every caller that predates this file gets.
12
+ */
13
+ import type { ProductAvailabilityFragment } from '../generated/shop.js';
14
+ /** The three `ItemAvailability` members this SDK emits. */
15
+ export type SchemaOrgAvailability = 'https://schema.org/InStock' | 'https://schema.org/OutOfStock' | 'https://schema.org/PreOrder';
16
+ /**
17
+ * What `schemaOrgAvailability` reads; satisfied by every SDK variant shape AND
18
+ * by a search row. The stock signals are the ones `isPreorderOnly` reads, read
19
+ * the same way (`knownNothingSaleable`), so the feed and the badge cannot
20
+ * disagree about whether a pre-order is buyable today.
21
+ */
22
+ export interface AvailabilityForSeo {
23
+ /**
24
+ * The merchant publication state in force. Absent or `null` (a search row
25
+ * that predates the attribute, an older engine) is read as "nothing in
26
+ * force" — the pre-order-free behaviour.
27
+ */
28
+ availability?: ProductAvailabilityFragment | null;
29
+ /** Available-to-promise units — the precise signal, preferred when present. */
30
+ saleable?: number | null;
31
+ /** A search row's stock flag, the only stock signal `SEARCH_PRODUCTS` selects. */
32
+ inStock?: boolean | null;
33
+ /** Vendure's display string — `'IN_STOCK'` / `'OUT_OF_STOCK'`. */
34
+ stockLevel?: string | null;
35
+ }
36
+ /**
37
+ * The schema.org `ItemAvailability` URL for a variant. Pass the result as
38
+ * `extras.availability` to `metaTagsFor` — JSON-LD emits it verbatim as
39
+ * `Offer.availability`, and the OpenGraph `product:availability` tag gets the
40
+ * matching Facebook token automatically.
41
+ *
42
+ * ```ts
43
+ * const extras = {
44
+ * availability: schemaOrgAvailability(variant),
45
+ * availabilityStarts: variant.availability?.availableFrom,
46
+ * ...
47
+ * };
48
+ * ```
49
+ *
50
+ * | state | stock the storefront can SEE | result |
51
+ * |---|---|---|
52
+ * | `comingSoon` | anything | `OutOfStock` |
53
+ * | `preorder` | known nothing to buy | `PreOrder` |
54
+ * | `preorder` | known stock, or no signal | `InStock` |
55
+ * | anything else | known nothing to buy | `OutOfStock` |
56
+ * | anything else | known stock, or no signal | `InStock` |
57
+ *
58
+ * **Coming soon is `OutOfStock`, whatever the stock.** schema.org defines
59
+ * `PreOrder` as "Indicates that the item is available for pre-order" — an
60
+ * assertion that it can be ORDERED now for later delivery, which is the one
61
+ * thing this SDK guarantees a coming-soon item is not (`orderable: false`,
62
+ * `canAddToCart` false, and the engine refuses every add with
63
+ * `quantityAvailable: 0`, stock on hand or not). Emitting it would advertise a
64
+ * purchasable offer behind a disabled buy button — a Merchant Center
65
+ * availability-versus-landing-page mismatch. `OutOfStock` is the honest
66
+ * member for "not currently purchasable". (`SoldOut` is wrong the other way:
67
+ * it says the item HAD stock and it went, not that it has not launched.)
68
+ *
69
+ * **A pre-order is `PreOrder` only while there is nothing to buy outright** —
70
+ * exactly when `isPreorderOnly(variant)` is true, through the same
71
+ * `knownNothingSaleable` predicate. Stock never ENDS a pre-order state (the
72
+ * merchant may keep selling from the warehouse while it stands), but a variant
73
+ * with stock on hand ships today: the page shows the ordinary in-stock UI, and
74
+ * a feed saying "Pre-order, available 12 March" for it is the same mismatch in
75
+ * the other direction. So it is `InStock`, and the JSON-LD composer drops
76
+ * `availabilityStarts` for an `InStock` offer. When no stock signal is
77
+ * readable it is not claimed as a pre-order either, matching the label.
78
+ *
79
+ * Everything else is today's rule, read through the same predicate:
80
+ * `saleable` when the channel exposes it, then a search row's `inStock`, then
81
+ * the `stockLevel` string, and `InStock` when nothing says otherwise. An
82
+ * unknown state — one a later engine added — falls through to the stock rule
83
+ * rather than throwing, which is why this is a chain of comparisons and not a
84
+ * `switch`.
85
+ */
86
+ export declare function schemaOrgAvailability(variant: AvailabilityForSeo): SchemaOrgAvailability;
87
+ /**
88
+ * The OpenGraph `product:availability` token for an availability value.
89
+ *
90
+ * Translates the three schema.org URLs into Facebook's vocabulary and passes
91
+ * anything else through verbatim — so a storefront that has always passed
92
+ * `'in stock'` keeps emitting `'in stock'`, byte for byte.
93
+ */
94
+ export declare function openGraphAvailability(availability: string): string;
95
+ //# sourceMappingURL=availability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability.d.ts","sourceRoot":"","sources":["../../src/seo/availability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;AAIxE,2DAA2D;AAC3D,MAAM,MAAM,qBAAqB,GAC7B,4BAA4B,GAC5B,+BAA+B,GAC/B,6BAA6B,CAAC;AAGlC;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,YAAY,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAC;IAClD,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,GAAG,qBAAqB,CAMxF;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAKlE"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Availability for structured data: one variant's stock + merchant publication
3
+ * state, expressed as the schema.org `ItemAvailability` URL that
4
+ * `Offer.availability` wants and the OpenGraph token `product:availability`
5
+ * wants.
6
+ *
7
+ * These are separate vocabularies for the same fact, and `ProductSeoExtras`
8
+ * carries ONE `availability` string that feeds both tags. So the schema.org URL
9
+ * is the value a storefront passes, and `openGraphAvailability` translates it
10
+ * back for the OpenGraph tag. Anything the SDK does not recognise is passed
11
+ * through untouched, which is what every caller that predates this file gets.
12
+ */
13
+ import { knownNothingSaleable } from '../pricing/validation.js';
14
+ /**
15
+ * The schema.org `ItemAvailability` URL for a variant. Pass the result as
16
+ * `extras.availability` to `metaTagsFor` — JSON-LD emits it verbatim as
17
+ * `Offer.availability`, and the OpenGraph `product:availability` tag gets the
18
+ * matching Facebook token automatically.
19
+ *
20
+ * ```ts
21
+ * const extras = {
22
+ * availability: schemaOrgAvailability(variant),
23
+ * availabilityStarts: variant.availability?.availableFrom,
24
+ * ...
25
+ * };
26
+ * ```
27
+ *
28
+ * | state | stock the storefront can SEE | result |
29
+ * |---|---|---|
30
+ * | `comingSoon` | anything | `OutOfStock` |
31
+ * | `preorder` | known nothing to buy | `PreOrder` |
32
+ * | `preorder` | known stock, or no signal | `InStock` |
33
+ * | anything else | known nothing to buy | `OutOfStock` |
34
+ * | anything else | known stock, or no signal | `InStock` |
35
+ *
36
+ * **Coming soon is `OutOfStock`, whatever the stock.** schema.org defines
37
+ * `PreOrder` as "Indicates that the item is available for pre-order" — an
38
+ * assertion that it can be ORDERED now for later delivery, which is the one
39
+ * thing this SDK guarantees a coming-soon item is not (`orderable: false`,
40
+ * `canAddToCart` false, and the engine refuses every add with
41
+ * `quantityAvailable: 0`, stock on hand or not). Emitting it would advertise a
42
+ * purchasable offer behind a disabled buy button — a Merchant Center
43
+ * availability-versus-landing-page mismatch. `OutOfStock` is the honest
44
+ * member for "not currently purchasable". (`SoldOut` is wrong the other way:
45
+ * it says the item HAD stock and it went, not that it has not launched.)
46
+ *
47
+ * **A pre-order is `PreOrder` only while there is nothing to buy outright** —
48
+ * exactly when `isPreorderOnly(variant)` is true, through the same
49
+ * `knownNothingSaleable` predicate. Stock never ENDS a pre-order state (the
50
+ * merchant may keep selling from the warehouse while it stands), but a variant
51
+ * with stock on hand ships today: the page shows the ordinary in-stock UI, and
52
+ * a feed saying "Pre-order, available 12 March" for it is the same mismatch in
53
+ * the other direction. So it is `InStock`, and the JSON-LD composer drops
54
+ * `availabilityStarts` for an `InStock` offer. When no stock signal is
55
+ * readable it is not claimed as a pre-order either, matching the label.
56
+ *
57
+ * Everything else is today's rule, read through the same predicate:
58
+ * `saleable` when the channel exposes it, then a search row's `inStock`, then
59
+ * the `stockLevel` string, and `InStock` when nothing says otherwise. An
60
+ * unknown state — one a later engine added — falls through to the stock rule
61
+ * rather than throwing, which is why this is a chain of comparisons and not a
62
+ * `switch`.
63
+ */
64
+ export function schemaOrgAvailability(variant) {
65
+ const state = variant.availability?.state;
66
+ if (state === 'comingSoon')
67
+ return 'https://schema.org/OutOfStock';
68
+ const nothingSaleable = knownNothingSaleable(variant) === true;
69
+ if (state === 'preorder' && nothingSaleable)
70
+ return 'https://schema.org/PreOrder';
71
+ return nothingSaleable ? 'https://schema.org/OutOfStock' : 'https://schema.org/InStock';
72
+ }
73
+ /**
74
+ * The OpenGraph `product:availability` token for an availability value.
75
+ *
76
+ * Translates the three schema.org URLs into Facebook's vocabulary and passes
77
+ * anything else through verbatim — so a storefront that has always passed
78
+ * `'in stock'` keeps emitting `'in stock'`, byte for byte.
79
+ */
80
+ export function openGraphAvailability(availability) {
81
+ if (availability === 'https://schema.org/InStock')
82
+ return 'in stock';
83
+ if (availability === 'https://schema.org/OutOfStock')
84
+ return 'out of stock';
85
+ if (availability === 'https://schema.org/PreOrder')
86
+ return 'preorder';
87
+ return availability;
88
+ }
89
+ //# sourceMappingURL=availability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability.js","sourceRoot":"","sources":["../../src/seo/availability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AA+BhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAA2B;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC;IAC1C,IAAI,KAAK,KAAK,YAAY;QAAE,OAAO,+BAA+B,CAAC;IACnE,MAAM,eAAe,GAAG,oBAAoB,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;IAC/D,IAAI,KAAK,KAAK,UAAU,IAAI,eAAe;QAAE,OAAO,6BAA6B,CAAC;IAClF,OAAO,eAAe,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,4BAA4B,CAAC;AAC1F,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,YAAoB;IACxD,IAAI,YAAY,KAAK,4BAA4B;QAAE,OAAO,UAAU,CAAC;IACrE,IAAI,YAAY,KAAK,+BAA+B;QAAE,OAAO,cAAc,CAAC;IAC5E,IAAI,YAAY,KAAK,6BAA6B;QAAE,OAAO,UAAU,CAAC;IACtE,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -2,6 +2,10 @@ import type { StoreContext } from '../types.js';
2
2
  import type { SeoModule } from './types.js';
3
3
  export declare function createSeoModule(ctx: StoreContext): SeoModule;
4
4
  export type { AiSummaryInput, LlmsTxtEntryInput, } from './ai.js';
5
+ export type { SeoArtifact, SeoArtifactFetchOptions, SeoArtifactResult, SeoArtifactsModule, } from './artifacts.js';
6
+ export { isSitemapChildFile, SEO_ARTIFACTS } from './artifacts.js';
7
+ export type { AvailabilityForSeo, SchemaOrgAvailability } from './availability.js';
8
+ export { openGraphAvailability, schemaOrgAvailability } from './availability.js';
5
9
  export type { CmsMetaTagsInput, CmsSeoExtras, CollectionMetaTagsInput, CollectionSeoExtras, HreflangLinkTag, MetaTagsEntityInput, MetaTagsResult, OpenGraphTag, ProductMetaTagsInput, ProductSeoExtras, TwitterTag, } from './meta-tags.js';
6
10
  export type { RawCmsSeo, RawCollectionSeo, RawProductMetadata } from './metadata-parser.js';
7
11
  export { parseCmsItemMetadata, parseCollectionMetadata, parseProductMetadata, robotsFromFlags, } from './metadata-parser.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOhD,OAAO,KAAK,EAAkB,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5D,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,CAyE5D;AAED,YAAY,EACV,cAAc,EACd,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,GACX,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC5F,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,YAAY,EACZ,uBAAuB,EACvB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,EACV,yBAAyB,EACzB,wBAAwB,EACxB,yBAAyB,EACzB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,MAAM,EACN,YAAY,EACZ,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,4BAA4B,EAC5B,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,mBAAmB,GACpB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,OAAO,EACP,SAAS,EACT,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQhD,OAAO,KAAK,EAAkB,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5D,wBAAgB,eAAe,CAAC,GAAG,EAAE,YAAY,GAAG,SAAS,CA2E5D;AAED,YAAY,EACV,cAAc,EACd,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,WAAW,EACX,uBAAuB,EACvB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACnE,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACjF,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,uBAAuB,EACvB,mBAAmB,EACnB,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,UAAU,GACX,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC5F,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,EACpB,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,YAAY,EACZ,uBAAuB,EACvB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,UAAU,EACV,yBAAyB,EACzB,wBAAwB,EACxB,yBAAyB,EACzB,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,MAAM,EACN,YAAY,EACZ,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,4BAA4B,EAC5B,gBAAgB,EAChB,2BAA2B,EAC3B,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,aAAa,EACb,mBAAmB,GACpB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,OAAO,EACP,SAAS,EACT,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/seo/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { createContextAssetUrlResolver } from '../media/urls.js';
2
2
  import { aiSummaryFor, llmsTxtEntryFor } from './ai.js';
3
3
  import { alternatesFor } from './alternates.js';
4
- import { createArtifactUrls, reportNotFound } from './artifacts.js';
4
+ import { createArtifactsModule, createArtifactUrls, reportNotFound } from './artifacts.js';
5
+ import { schemaOrgAvailability } from './availability.js';
5
6
  import { canonicalFor } from './canonical.js';
6
7
  import { metaTagsFor } from './meta-tags.js';
7
8
  import { composePerBotDirectives } from './robots.js';
@@ -16,6 +17,7 @@ export function createSeoModule(ctx) {
16
17
  robotsUrl: artifacts.robotsUrl,
17
18
  llmsTxtUrl: artifacts.llmsTxtUrl,
18
19
  indexnowKeyUrl: artifacts.indexnowKeyUrl,
20
+ artifacts: createArtifactsModule(ctx, artifacts),
19
21
  reportNotFound(path, options) {
20
22
  reportNotFound(ctx, path, options);
21
23
  },
@@ -72,6 +74,7 @@ export function createSeoModule(ctx) {
72
74
  xRobotsHeaders: [],
73
75
  };
74
76
  },
77
+ schemaOrgAvailability,
75
78
  aiSummaryFor(entity) {
76
79
  return aiSummaryFor(entity);
77
80
  },
@@ -80,6 +83,8 @@ export function createSeoModule(ctx) {
80
83
  },
81
84
  };
82
85
  }
86
+ export { isSitemapChildFile, SEO_ARTIFACTS } from './artifacts.js';
87
+ export { openGraphAvailability, schemaOrgAvailability } from './availability.js';
83
88
  export { parseCmsItemMetadata, parseCollectionMetadata, parseProductMetadata, robotsFromFlags, } from './metadata-parser.js';
84
89
  export { DEFAULT_PRODUCT_PATH_SEGMENT, isUserFacingRoot, normalizeProductPathSegment, pickCanonicalRootIndex, } from './product-path.js';
85
90
  export { buildUrl, readUrlStrategy } from './url-builder.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/seo/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"json-ld.d.ts","sourceRoot":"","sources":["../../src/seo/json-ld.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC5F,OAAO,KAAK,EAAoB,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAuB1D,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,eAAe,EAAE,gBAAgB,CAAC;IAClC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACrC,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC9D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyDvF;AAED,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,iBAAiB,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;CAClD;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkB7F;AAqCD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,gFAAgF;IAChF,eAAe,EAAE,gBAAgB,CAAC;CACnC;AAQD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWvF;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWhF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUtF"}
1
+ {"version":3,"file":"json-ld.d.ts","sourceRoot":"","sources":["../../src/seo/json-ld.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC5F,OAAO,KAAK,EAAoB,aAAa,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAwB1D,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,eAAe,EAAE,gBAAgB,CAAC;IAClC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACrC,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC9D;AAYD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiFvF;AAGD,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,iBAAiB,CAAC;IACvB,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAC;CAClD;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkB7F;AAsCD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,gFAAgF;IAChF,eAAe,EAAE,gBAAgB,CAAC;CACnC;AAQD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWvF;AAED,4DAA4D;AAC5D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWhF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUtF"}
@@ -24,6 +24,15 @@ function pickImageUrls(resolveAssetUrl, ...assets) {
24
24
  }
25
25
  return urls;
26
26
  }
27
+ /**
28
+ * The two `ItemAvailability` values `schemaOrgAvailability` returns for an
29
+ * offer that cannot be bought outright today — the only ones a future
30
+ * `availabilityStarts` is consistent with. `InStock` is deliberately absent.
31
+ */
32
+ const NOT_PURCHASABLE_NOW = new Set([
33
+ 'https://schema.org/PreOrder',
34
+ 'https://schema.org/OutOfStock',
35
+ ]);
27
36
  export function composeProductJsonLd(input) {
28
37
  const { product, metadata, canonical, title, description, extras, reviews } = input;
29
38
  const out = {
@@ -50,9 +59,33 @@ export function composeProductJsonLd(input) {
50
59
  };
51
60
  if (extras.availability) {
52
61
  // schema.org expects an ItemAvailability URL, but text is also widely
53
- // accepted by validators. Pass-through whatever the storefront provides.
62
+ // accepted by validators. Pass-through whatever the storefront provides —
63
+ // `schemaOrgAvailability(variant)` (`./availability.js`) is what produces
64
+ // the URL, and it is the only way `PreOrder` ever gets emitted: a
65
+ // pre-order with nothing on hand reads 0 stock, so anything derived from
66
+ // `stockLevel` alone would say `OutOfStock` and hide a product the
67
+ // merchant is actively taking orders for.
54
68
  offer.availability = extras.availability;
55
69
  }
70
+ if (extras.availabilityStarts && NOT_PURCHASABLE_NOW.has(extras.availability ?? '')) {
71
+ // `https://schema.org/availabilityStarts` — "The beginning of the
72
+ // availability of the product or service included in the offer", a
73
+ // property of `Offer` (verified against schema.org). It is the date half
74
+ // of the two merchant states: a `PreOrder` with no availability date is
75
+ // an item-level feed error, and a coming-soon item (mapped to
76
+ // `OutOfStock`, which says nothing about WHEN) has no other way to say
77
+ // it is arriving.
78
+ //
79
+ // Only beside an offer that is NOT purchasable now. A pre-order with stock
80
+ // on hand is `InStock` — it ships today — and "in stock, available from
81
+ // 12 March" contradicts itself; a storefront passing
82
+ // `variant.availability?.availableFrom` unconditionally must not produce
83
+ // that. A hand-written availability string is not recognised either: the
84
+ // SDK cannot tell whether that offer is purchasable now. Nothing is
85
+ // emitted without a date, so an offer from a storefront that predates this
86
+ // field is byte-identical.
87
+ offer.availabilityStarts = extras.availabilityStarts;
88
+ }
56
89
  if (extras.condition) {
57
90
  offer.itemCondition = `https://schema.org/${extras.condition === 'new'
58
91
  ? 'NewCondition'