@replohq/sdk 1.7.1 → 1.7.3

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 (246) hide show
  1. package/_vendor/replo-utils/lib/string.d.ts +0 -2
  2. package/_vendor/schemas/errors.d.ts +2 -3
  3. package/_vendor/schemas/generated/errors.d.ts +3 -0
  4. package/_vendor/schemas/loaderKeys.mjs +0 -1
  5. package/_vendor/schemas/money.d.ts +1 -1
  6. package/_vendor/schemas/money.mjs +1 -7
  7. package/_vendor/schemas/routing/locale.mjs +1 -1
  8. package/_vendor/schemas/routing/rules.mjs +1 -2
  9. package/analytics/analytics-provider.js +0 -1
  10. package/analytics/analytics-sink.js +0 -1
  11. package/analytics/get-analytics-sinks.js +0 -1
  12. package/analytics/hooks/use-product-viewed-analytics.js +0 -1
  13. package/analytics/replo-first-party-pixel.js +0 -1
  14. package/analytics/replo-pixel-script.js +0 -1
  15. package/analytics/sinks/converge-event-mapper.js +0 -1
  16. package/analytics/sinks/converge-sink.js +0 -1
  17. package/analytics/sinks/elevar-sink.js +0 -1
  18. package/analytics/sinks/ga4-sink.js +0 -4
  19. package/analytics/sinks/meta-sink.js +0 -4
  20. package/analytics/sinks/northbeam-sink.js +0 -1
  21. package/analytics/sinks/pinterest-sink.js +0 -4
  22. package/analytics/sinks/reddit-sink.js +0 -4
  23. package/analytics/sinks/replo-sink.js +0 -2
  24. package/analytics/sinks/snapchat-sink.js +0 -4
  25. package/analytics/sinks/tiktok-sink.js +0 -4
  26. package/analytics/sinks/window-sink.js +0 -3
  27. package/analytics/utils/analytics-utils.js +0 -1
  28. package/analytics/utils/navigation-tracker.js +0 -1
  29. package/analytics/utils/shopify-funnel-gate.js +0 -1
  30. package/cart/buy-now-action.js +0 -3
  31. package/cart/cart-actions.js +0 -1
  32. package/cart/cart-loader.js +0 -1
  33. package/cart/cart-provider.js +1 -2
  34. package/cart/cart-schema.js +0 -1
  35. package/cart/cart-types.js +0 -1
  36. package/cart/gateways/cart-constants.js +0 -2
  37. package/cart/gateways/cart-gateway.js +0 -1
  38. package/cart/gateways/cookie-cart-gateway.js +0 -5
  39. package/cart/gateways/default-cart-gateway.js +0 -1
  40. package/cart/gateways/resolver-cart-gateway.js +0 -5
  41. package/cart/gateways/stripe-cart-gateway.js +0 -1
  42. package/cart/hooks/use-add-to-cart.js +0 -4
  43. package/cart/hooks/use-buy-now.js +0 -1
  44. package/cart/return-urls.js +0 -1
  45. package/cart/storefront-urls.js +0 -1
  46. package/cart/utils/cart-adjustments.js +0 -1
  47. package/cart/utils/cart-analytics.js +0 -1
  48. package/cart/utils/cart-error.js +0 -1
  49. package/cart/utils/cart-utils.js +0 -1
  50. package/cart/utils/cookie-cart-persistence.js +0 -1
  51. package/cart/utils/variant-to-cart-line.js +0 -6
  52. package/chunk-7OPH5UFQ.mjs +0 -1
  53. package/chunk-AL3F36PH.mjs +5 -127
  54. package/chunk-EUQVEPSD.mjs +0 -1
  55. package/chunk-GV5FY7ZZ.mjs +0 -11
  56. package/chunk-UJCSKKID.mjs +0 -4
  57. package/chunk-VKO7P3ED.mjs +0 -2
  58. package/chunk-VPEVERWE.mjs +0 -1
  59. package/{chunk-5M7VU32I.mjs → chunk-YJQVNUW7.mjs} +1 -12
  60. package/consent/consent-action.js +0 -1
  61. package/consent/consent-actions.js +0 -1
  62. package/consent/consent-platform.js +0 -3
  63. package/consent/consent-store.js +0 -5
  64. package/consent/cookie.js +0 -1
  65. package/consent/inject-script-descriptors.js +0 -1
  66. package/consent/replo-scripts.js +0 -1
  67. package/consent/script-registration-store.js +0 -2
  68. package/consent/script-snippets.js +0 -7
  69. package/consent/types.js +0 -1
  70. package/consent/window-api.js +0 -1
  71. package/content.js +0 -1
  72. package/env.js +0 -1
  73. package/gateways/canopy-api.js +0 -10
  74. package/hooks/use-client-value.d.ts +1 -1
  75. package/hooks/use-client-value.js +0 -1
  76. package/hooks/use-formatted-price.js +0 -1
  77. package/lib/buildMetadata.js +3 -3
  78. package/lib/canopy-error.js +0 -1
  79. package/lib/external-navigation.d.ts +1 -1
  80. package/lib/external-navigation.js +0 -1
  81. package/lib/get-query-client.js +0 -1
  82. package/lib/integration-utils.js +0 -1
  83. package/lib/shopify-utils.js +0 -1
  84. package/lib/url-utils.js +0 -1
  85. package/loaders/collection-loader-args.js +0 -1
  86. package/loaders/collection-loader.js +0 -1
  87. package/loaders/collection-products-loader-args.js +0 -1
  88. package/loaders/collection-products-loader.js +0 -1
  89. package/loaders/contentful-entries-loader.js +0 -1
  90. package/loaders/contentful-entry-loader.js +0 -1
  91. package/loaders/invoke-loader-action.js +0 -1
  92. package/loaders/invoke-loader-server.js +0 -1
  93. package/loaders/invoke-loader.js +0 -1
  94. package/loaders/judgeme-review-aggregate-loader.js +0 -1
  95. package/loaders/judgeme-reviews-loader.js +0 -1
  96. package/loaders/levanta-product-loader.js +0 -1
  97. package/loaders/loader-error-boundary.d.ts +11 -2
  98. package/loaders/loader-error-boundary.js +52 -9
  99. package/loaders/loader-error-details.d.ts +2 -0
  100. package/loaders/loader-error-details.js +7 -0
  101. package/loaders/loader-keys.js +0 -1
  102. package/loaders/loader-schemas.js +0 -4
  103. package/loaders/loox-review-aggregate-loader.js +0 -1
  104. package/loaders/loox-reviews-loader.js +0 -1
  105. package/loaders/metaobject-loader.js +0 -1
  106. package/loaders/metaobjects-loader.js +0 -1
  107. package/loaders/okendo-review-aggregate-loader.js +0 -1
  108. package/loaders/okendo-reviews-loader.js +0 -1
  109. package/loaders/prefetch-loaders.js +0 -1
  110. package/loaders/preview-placeholder.js +0 -5
  111. package/loaders/product-loader-args.js +0 -1
  112. package/loaders/product-loader.js +0 -1
  113. package/loaders/rebuy-recommendations-loader.js +0 -1
  114. package/loaders/reviews-io-review-aggregate-loader.js +0 -1
  115. package/loaders/reviews-io-reviews-loader.js +0 -1
  116. package/loaders/smile-earning-rules-loader.js +0 -1
  117. package/loaders/smile-rewards-loader.js +0 -1
  118. package/loaders/smile-vip-tiers-loader.js +0 -1
  119. package/loaders/statsig-experiment-loader.js +0 -1
  120. package/loaders/yotpo-review-aggregate-loader.js +0 -1
  121. package/loaders/yotpo-reviews-loader.js +0 -1
  122. package/money.js +0 -1
  123. package/next/config.js +0 -18
  124. package/next/image-loader.js +6 -5
  125. package/next/open-next.js +0 -1
  126. package/orders/order-status-schema.js +0 -4
  127. package/orders/order-status.js +0 -3
  128. package/package.json +4 -4
  129. package/providers/query-provider.js +0 -1
  130. package/providers/replo-provider.js +4 -3
  131. package/routing/evaluate.js +0 -1
  132. package/routing/geo.js +0 -1
  133. package/routing/locale.js +0 -1
  134. package/routing/rules.js +0 -1
  135. package/analytics/analytics-provider.js.map +0 -7
  136. package/analytics/analytics-sink.js.map +0 -7
  137. package/analytics/get-analytics-sinks.js.map +0 -7
  138. package/analytics/hooks/use-product-viewed-analytics.js.map +0 -7
  139. package/analytics/replo-first-party-pixel.js.map +0 -7
  140. package/analytics/replo-pixel-script.js.map +0 -7
  141. package/analytics/sinks/converge-event-mapper.js.map +0 -7
  142. package/analytics/sinks/converge-sink.js.map +0 -7
  143. package/analytics/sinks/elevar-sink.js.map +0 -7
  144. package/analytics/sinks/ga4-sink.js.map +0 -7
  145. package/analytics/sinks/meta-sink.js.map +0 -7
  146. package/analytics/sinks/northbeam-sink.js.map +0 -7
  147. package/analytics/sinks/pinterest-sink.js.map +0 -7
  148. package/analytics/sinks/reddit-sink.js.map +0 -7
  149. package/analytics/sinks/replo-sink.js.map +0 -7
  150. package/analytics/sinks/snapchat-sink.js.map +0 -7
  151. package/analytics/sinks/tiktok-sink.js.map +0 -7
  152. package/analytics/sinks/window-sink.js.map +0 -7
  153. package/analytics/utils/analytics-utils.js.map +0 -7
  154. package/analytics/utils/navigation-tracker.js.map +0 -7
  155. package/analytics/utils/shopify-funnel-gate.js.map +0 -7
  156. package/cart/buy-now-action.js.map +0 -7
  157. package/cart/cart-actions.js.map +0 -7
  158. package/cart/cart-loader.js.map +0 -7
  159. package/cart/cart-provider.js.map +0 -7
  160. package/cart/cart-schema.js.map +0 -7
  161. package/cart/cart-types.js.map +0 -7
  162. package/cart/gateways/cart-constants.js.map +0 -7
  163. package/cart/gateways/cart-gateway.js.map +0 -7
  164. package/cart/gateways/cookie-cart-gateway.js.map +0 -7
  165. package/cart/gateways/default-cart-gateway.js.map +0 -7
  166. package/cart/gateways/resolver-cart-gateway.js.map +0 -7
  167. package/cart/gateways/stripe-cart-gateway.js.map +0 -7
  168. package/cart/hooks/use-add-to-cart.js.map +0 -7
  169. package/cart/hooks/use-buy-now.js.map +0 -7
  170. package/cart/return-urls.js.map +0 -7
  171. package/cart/storefront-urls.js.map +0 -7
  172. package/cart/utils/cart-adjustments.js.map +0 -7
  173. package/cart/utils/cart-analytics.js.map +0 -7
  174. package/cart/utils/cart-error.js.map +0 -7
  175. package/cart/utils/cart-utils.js.map +0 -7
  176. package/cart/utils/cookie-cart-persistence.js.map +0 -7
  177. package/cart/utils/variant-to-cart-line.js.map +0 -7
  178. package/consent/consent-action.js.map +0 -7
  179. package/consent/consent-actions.js.map +0 -7
  180. package/consent/consent-platform.js.map +0 -7
  181. package/consent/consent-store.js.map +0 -7
  182. package/consent/cookie.js.map +0 -7
  183. package/consent/inject-script-descriptors.js.map +0 -7
  184. package/consent/replo-scripts.js.map +0 -7
  185. package/consent/script-registration-store.js.map +0 -7
  186. package/consent/script-snippets.js.map +0 -7
  187. package/consent/types.js.map +0 -7
  188. package/consent/window-api.js.map +0 -7
  189. package/content.js.map +0 -7
  190. package/env.js.map +0 -7
  191. package/gateways/canopy-api.js.map +0 -7
  192. package/hooks/use-client-value.js.map +0 -7
  193. package/hooks/use-formatted-price.js.map +0 -7
  194. package/lib/buildMetadata.js.map +0 -7
  195. package/lib/canopy-error.js.map +0 -7
  196. package/lib/external-navigation.js.map +0 -7
  197. package/lib/get-query-client.js.map +0 -7
  198. package/lib/integration-utils.js.map +0 -7
  199. package/lib/shopify-utils.js.map +0 -7
  200. package/lib/url-utils.js.map +0 -7
  201. package/loaders/collection-loader-args.js.map +0 -7
  202. package/loaders/collection-loader.js.map +0 -7
  203. package/loaders/collection-products-loader-args.js.map +0 -7
  204. package/loaders/collection-products-loader.js.map +0 -7
  205. package/loaders/contentful-entries-loader.js.map +0 -7
  206. package/loaders/contentful-entry-loader.js.map +0 -7
  207. package/loaders/invoke-loader-action.js.map +0 -7
  208. package/loaders/invoke-loader-server.js.map +0 -7
  209. package/loaders/invoke-loader.js.map +0 -7
  210. package/loaders/judgeme-review-aggregate-loader.js.map +0 -7
  211. package/loaders/judgeme-reviews-loader.js.map +0 -7
  212. package/loaders/levanta-product-loader.js.map +0 -7
  213. package/loaders/loader-error-boundary.js.map +0 -7
  214. package/loaders/loader-keys.js.map +0 -7
  215. package/loaders/loader-schemas.js.map +0 -7
  216. package/loaders/loox-review-aggregate-loader.js.map +0 -7
  217. package/loaders/loox-reviews-loader.js.map +0 -7
  218. package/loaders/metaobject-loader.js.map +0 -7
  219. package/loaders/metaobjects-loader.js.map +0 -7
  220. package/loaders/okendo-review-aggregate-loader.js.map +0 -7
  221. package/loaders/okendo-reviews-loader.js.map +0 -7
  222. package/loaders/prefetch-loaders.js.map +0 -7
  223. package/loaders/preview-placeholder.js.map +0 -7
  224. package/loaders/product-loader-args.js.map +0 -7
  225. package/loaders/product-loader.js.map +0 -7
  226. package/loaders/rebuy-recommendations-loader.js.map +0 -7
  227. package/loaders/reviews-io-review-aggregate-loader.js.map +0 -7
  228. package/loaders/reviews-io-reviews-loader.js.map +0 -7
  229. package/loaders/smile-earning-rules-loader.js.map +0 -7
  230. package/loaders/smile-rewards-loader.js.map +0 -7
  231. package/loaders/smile-vip-tiers-loader.js.map +0 -7
  232. package/loaders/statsig-experiment-loader.js.map +0 -7
  233. package/loaders/yotpo-review-aggregate-loader.js.map +0 -7
  234. package/loaders/yotpo-reviews-loader.js.map +0 -7
  235. package/money.js.map +0 -7
  236. package/next/config.js.map +0 -7
  237. package/next/image-loader.js.map +0 -7
  238. package/next/open-next.js.map +0 -7
  239. package/orders/order-status-schema.js.map +0 -7
  240. package/orders/order-status.js.map +0 -7
  241. package/providers/query-provider.js.map +0 -7
  242. package/providers/replo-provider.js.map +0 -7
  243. package/routing/evaluate.js.map +0 -7
  244. package/routing/geo.js.map +0 -7
  245. package/routing/locale.js.map +0 -7
  246. package/routing/rules.js.map +0 -7
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../analytics/sinks/replo-sink.ts"],
4
- "sourcesContent": ["import type {\n AnalyticsSink,\n DataPayload,\n PurchasePayload,\n} from \"../analytics-sink\";\n\nimport { createMethodQueue } from \"../utils/analytics-utils\";\n\nexport class ReploSink implements AnalyticsSink {\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n private forward: (method: keyof AnalyticsSink, ...args: any[]) => void;\n\n constructor() {\n this.forward = createMethodQueue(\n () => {\n if (typeof window === \"undefined\") {\n return null;\n }\n // Legacy cast - may or may not be necessary\n // oxlint-disable-next-line replo/no-as-cast, typescript/no-explicit-any -- legacy any/cast, may or may not be needed\n const pixel = (window as any).ReploPixel;\n return pixel?.analyticsInstance ?? null;\n },\n { queueName: \"Replo analytics sink\" },\n );\n }\n\n async pageView() {\n this.forward(\"pageView\");\n return Promise.resolve();\n }\n purchase(payload: PurchasePayload) {\n this.forward(\"purchase\", payload);\n return Promise.resolve();\n }\n click(payload: DataPayload) {\n this.forward(\"click\", payload);\n return Promise.resolve();\n }\n productViewed(payload: DataPayload) {\n this.forward(\"productViewed\", payload);\n return Promise.resolve();\n }\n addToCart(payload: DataPayload) {\n this.forward(\"addToCart\", payload);\n return Promise.resolve();\n }\n removeFromCart(payload: DataPayload) {\n this.forward(\"removeFromCart\", payload);\n return Promise.resolve();\n }\n viewCart(payload: DataPayload) {\n this.forward(\"viewCart\", payload);\n return Promise.resolve();\n }\n startCheckout(payload: DataPayload) {\n this.forward(\"startCheckout\", payload);\n return Promise.resolve();\n }\n viewCollection(payload: DataPayload) {\n this.forward(\"viewCollection\", payload);\n return Promise.resolve();\n }\n}\n"],
5
- "mappings": "AAMA,SAAS,yBAAyB;AAE3B,MAAM,UAAmC;AAAA;AAAA,EAEtC;AAAA,EAER,cAAc;AACZ,SAAK,UAAU;AAAA,MACb,MAAM;AACJ,YAAI,OAAO,WAAW,aAAa;AACjC,iBAAO;AAAA,QACT;AAGA,cAAM,QAAS,OAAe;AAC9B,eAAO,OAAO,qBAAqB;AAAA,MACrC;AAAA,MACA,EAAE,WAAW,uBAAuB;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,MAAM,WAAW;AACf,SAAK,QAAQ,UAAU;AACvB,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EACA,SAAS,SAA0B;AACjC,SAAK,QAAQ,YAAY,OAAO;AAChC,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EACA,MAAM,SAAsB;AAC1B,SAAK,QAAQ,SAAS,OAAO;AAC7B,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EACA,cAAc,SAAsB;AAClC,SAAK,QAAQ,iBAAiB,OAAO;AACrC,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EACA,UAAU,SAAsB;AAC9B,SAAK,QAAQ,aAAa,OAAO;AACjC,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EACA,eAAe,SAAsB;AACnC,SAAK,QAAQ,kBAAkB,OAAO;AACtC,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EACA,SAAS,SAAsB;AAC7B,SAAK,QAAQ,YAAY,OAAO;AAChC,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EACA,cAAc,SAAsB;AAClC,SAAK,QAAQ,iBAAiB,OAAO;AACrC,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EACA,eAAe,SAAsB;AACnC,SAAK,QAAQ,kBAAkB,OAAO;AACtC,WAAO,QAAQ,QAAQ;AAAA,EACzB;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../analytics/sinks/snapchat-sink.ts"],
4
- "sourcesContent": ["import type {\n AnalyticsSink,\n DataPayload,\n PurchasePayload,\n} from \"../analytics-sink\";\n\nimport { createEventQueue } from \"../utils/analytics-utils\";\n\nexport class SnapchatSink implements AnalyticsSink {\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n private track: (event: string, params?: Record<string, any>) => void;\n\n constructor() {\n this.track = createEventQueue(\n // Legacy cast - may or may not be necessary\n // oxlint-disable-next-line replo/no-as-cast, typescript/no-explicit-any -- legacy any/cast, may or may not be needed\n () => typeof window !== \"undefined\" && Boolean((window as any).snaptr),\n (event, params) => {\n // Legacy cast - may or may not be necessary\n // oxlint-disable-next-line replo/no-as-cast, typescript/no-explicit-any -- legacy any/cast, may or may not be needed\n const snaptr = (window as any).snaptr;\n snaptr(\"track\", event, params);\n },\n \"Snapchat\",\n );\n }\n\n async pageView() {\n this.track(\"PAGE_VIEW\");\n }\n\n async purchase({ amount, currency, data }: PurchasePayload) {\n this.track(\"PURCHASE\", {\n price: amount,\n currency,\n ...data,\n });\n }\n\n async click({ data }: DataPayload) {\n this.track(\"CUSTOM_EVENT_1\", data);\n }\n\n async productViewed({ data }: DataPayload) {\n this.track(\"VIEW_CONTENT\", {\n item_ids: data.product_id ? [data.product_id] : undefined,\n price: data.price,\n currency: data.currency,\n item_category: data.category,\n ...data,\n });\n }\n\n async addToCart({ data }: DataPayload) {\n this.track(\"ADD_CART\", {\n item_ids: data.product_id ? [data.product_id] : undefined,\n price: data.price,\n num_items: data.quantity ?? 1,\n currency: data.currency,\n item_category: data.category,\n ...data,\n });\n }\n\n async removeFromCart() {\n // No direct equivalent in Snapchat\n }\n\n async viewCart() {\n // No direct equivalent in Snapchat\n }\n\n async startCheckout({ data }: DataPayload) {\n this.track(\"START_CHECKOUT\", {\n currency: data.currency,\n number_items: data.quantity,\n price: data.price,\n ...data,\n });\n }\n\n async viewCollection() {\n // No direct equivalent in Snapchat\n }\n}\n"],
5
- "mappings": "AAMA,SAAS,wBAAwB;AAE1B,MAAM,aAAsC;AAAA;AAAA,EAEzC;AAAA,EAER,cAAc;AACZ,SAAK,QAAQ;AAAA;AAAA;AAAA,MAGX,MAAM,OAAO,WAAW,eAAe,QAAS,OAAe,MAAM;AAAA,MACrE,CAAC,OAAO,WAAW;AAGjB,cAAM,SAAU,OAAe;AAC/B,eAAO,SAAS,OAAO,MAAM;AAAA,MAC/B;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,WAAW;AACf,SAAK,MAAM,WAAW;AAAA,EACxB;AAAA,EAEA,MAAM,SAAS,EAAE,QAAQ,UAAU,KAAK,GAAoB;AAC1D,SAAK,MAAM,YAAY;AAAA,MACrB,OAAO;AAAA,MACP;AAAA,MACA,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAM,EAAE,KAAK,GAAgB;AACjC,SAAK,MAAM,kBAAkB,IAAI;AAAA,EACnC;AAAA,EAEA,MAAM,cAAc,EAAE,KAAK,GAAgB;AACzC,SAAK,MAAM,gBAAgB;AAAA,MACzB,UAAU,KAAK,aAAa,CAAC,KAAK,UAAU,IAAI;AAAA,MAChD,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,eAAe,KAAK;AAAA,MACpB,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,UAAU,EAAE,KAAK,GAAgB;AACrC,SAAK,MAAM,YAAY;AAAA,MACrB,UAAU,KAAK,aAAa,CAAC,KAAK,UAAU,IAAI;AAAA,MAChD,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK,YAAY;AAAA,MAC5B,UAAU,KAAK;AAAA,MACf,eAAe,KAAK;AAAA,MACpB,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,iBAAiB;AAAA,EAEvB;AAAA,EAEA,MAAM,WAAW;AAAA,EAEjB;AAAA,EAEA,MAAM,cAAc,EAAE,KAAK,GAAgB;AACzC,SAAK,MAAM,kBAAkB;AAAA,MAC3B,UAAU,KAAK;AAAA,MACf,cAAc,KAAK;AAAA,MACnB,OAAO,KAAK;AAAA,MACZ,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,iBAAiB;AAAA,EAEvB;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../analytics/sinks/tiktok-sink.ts"],
4
- "sourcesContent": ["import type {\n AnalyticsSink,\n DataPayload,\n PurchasePayload,\n} from \"../analytics-sink\";\n\nimport { createEventQueue } from \"../utils/analytics-utils\";\n\nexport class TikTokSink implements AnalyticsSink {\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n private track: (event: string, params?: Record<string, any>) => void;\n\n constructor() {\n this.track = createEventQueue(\n // Legacy cast - may or may not be necessary\n // oxlint-disable-next-line replo/no-as-cast, typescript/no-explicit-any -- legacy any/cast, may or may not be needed\n () => typeof window !== \"undefined\" && Boolean((window as any).ttq),\n (event, params) => {\n // Legacy cast - may or may not be necessary\n // oxlint-disable-next-line replo/no-as-cast, typescript/no-explicit-any -- legacy any/cast, may or may not be needed\n const ttq = (window as any).ttq;\n ttq.track(event, params);\n },\n \"TikTok\",\n );\n }\n\n async pageView() {\n this.track(\"PageView\");\n }\n\n async purchase({ amount, currency, data }: PurchasePayload) {\n this.track(\"CompletePayment\", {\n value: amount,\n currency,\n content_type: \"product\",\n ...data,\n });\n }\n\n async click({ data }: DataPayload) {\n this.track(\"ClickButton\", data);\n }\n\n async productViewed({ data }: DataPayload) {\n this.track(\"ViewContent\", {\n content_type: \"product\",\n content_id: data.product_id,\n value: data.price,\n currency: data.currency,\n content_category: data.category,\n ...data,\n });\n }\n\n async addToCart({ data }: DataPayload) {\n this.track(\"AddToCart\", {\n content_type: \"product\",\n content_id: data.product_id,\n value: data.price,\n currency: data.currency,\n quantity: data.quantity ?? 1,\n content_category: data.category,\n ...data,\n });\n }\n\n async removeFromCart() {\n // No direct equivalent in TikTok\n }\n\n async viewCart({ data }: DataPayload) {\n this.track(\"ViewContent\", {\n content_type: \"cart\",\n ...data,\n });\n }\n\n async startCheckout({ data }: DataPayload) {\n this.track(\"InitiateCheckout\", {\n value: data.price,\n currency: data.currency,\n content_type: \"product\",\n ...data,\n });\n }\n\n async viewCollection({ data }: DataPayload) {\n this.track(\"ViewContent\", {\n content_type: \"product_group\",\n content_category: data.category,\n ...data,\n });\n }\n}\n"],
5
- "mappings": "AAMA,SAAS,wBAAwB;AAE1B,MAAM,WAAoC;AAAA;AAAA,EAEvC;AAAA,EAER,cAAc;AACZ,SAAK,QAAQ;AAAA;AAAA;AAAA,MAGX,MAAM,OAAO,WAAW,eAAe,QAAS,OAAe,GAAG;AAAA,MAClE,CAAC,OAAO,WAAW;AAGjB,cAAM,MAAO,OAAe;AAC5B,YAAI,MAAM,OAAO,MAAM;AAAA,MACzB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,WAAW;AACf,SAAK,MAAM,UAAU;AAAA,EACvB;AAAA,EAEA,MAAM,SAAS,EAAE,QAAQ,UAAU,KAAK,GAAoB;AAC1D,SAAK,MAAM,mBAAmB;AAAA,MAC5B,OAAO;AAAA,MACP;AAAA,MACA,cAAc;AAAA,MACd,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAM,EAAE,KAAK,GAAgB;AACjC,SAAK,MAAM,eAAe,IAAI;AAAA,EAChC;AAAA,EAEA,MAAM,cAAc,EAAE,KAAK,GAAgB;AACzC,SAAK,MAAM,eAAe;AAAA,MACxB,cAAc;AAAA,MACd,YAAY,KAAK;AAAA,MACjB,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,kBAAkB,KAAK;AAAA,MACvB,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,UAAU,EAAE,KAAK,GAAgB;AACrC,SAAK,MAAM,aAAa;AAAA,MACtB,cAAc;AAAA,MACd,YAAY,KAAK;AAAA,MACjB,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,UAAU,KAAK,YAAY;AAAA,MAC3B,kBAAkB,KAAK;AAAA,MACvB,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,iBAAiB;AAAA,EAEvB;AAAA,EAEA,MAAM,SAAS,EAAE,KAAK,GAAgB;AACpC,SAAK,MAAM,eAAe;AAAA,MACxB,cAAc;AAAA,MACd,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,EAAE,KAAK,GAAgB;AACzC,SAAK,MAAM,oBAAoB;AAAA,MAC7B,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,cAAc;AAAA,MACd,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eAAe,EAAE,KAAK,GAAgB;AAC1C,SAAK,MAAM,eAAe;AAAA,MACxB,cAAc;AAAA,MACd,kBAAkB,KAAK;AAAA,MACvB,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../analytics/sinks/window-sink.ts"],
4
- "sourcesContent": ["import type {\n AnalyticsSink,\n DataPayload,\n PurchasePayload,\n} from \"../analytics-sink\";\n\n/**\n * Dispatches CustomEvents to the global window object so 3rd-party scripts or\n * external tools can subscribe to analytics events without coupling directly to\n * the core analytics client. Matches Shopify analytics event naming conventions.\n */\nexport class WindowSink implements AnalyticsSink {\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n private dispatch(eventType: string, payload: any) {\n window.dispatchEvent(\n new CustomEvent(\"replo:analytics\", {\n detail: {\n event: eventType,\n payload,\n timestamp: Date.now(),\n },\n }),\n );\n }\n\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n async pageView(payload?: any) {\n this.dispatch(\"page_viewed\", payload);\n }\n\n async purchase(payload: PurchasePayload) {\n this.dispatch(\"checkout_completed\", payload);\n }\n\n async click(payload: DataPayload) {\n this.dispatch(\"clicked\", payload);\n }\n\n async productViewed(payload: DataPayload) {\n this.dispatch(\"product_viewed\", payload);\n }\n\n async addToCart(payload: DataPayload) {\n this.dispatch(\"product_added_to_cart\", payload);\n }\n\n async removeFromCart(payload: DataPayload) {\n this.dispatch(\"product_removed_from_cart\", payload);\n }\n\n async viewCart(payload: DataPayload) {\n this.dispatch(\"cart_viewed\", payload);\n }\n\n async startCheckout(payload: DataPayload) {\n this.dispatch(\"checkout_started\", payload);\n }\n\n async viewCollection(payload: DataPayload) {\n this.dispatch(\"collection_viewed\", payload);\n }\n}\n"],
5
- "mappings": "AAWO,MAAM,WAAoC;AAAA;AAAA,EAEvC,SAAS,WAAmB,SAAc;AAChD,WAAO;AAAA,MACL,IAAI,YAAY,mBAAmB;AAAA,QACjC,QAAQ;AAAA,UACN,OAAO;AAAA,UACP;AAAA,UACA,WAAW,KAAK,IAAI;AAAA,QACtB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,SAAS,SAAe;AAC5B,SAAK,SAAS,eAAe,OAAO;AAAA,EACtC;AAAA,EAEA,MAAM,SAAS,SAA0B;AACvC,SAAK,SAAS,sBAAsB,OAAO;AAAA,EAC7C;AAAA,EAEA,MAAM,MAAM,SAAsB;AAChC,SAAK,SAAS,WAAW,OAAO;AAAA,EAClC;AAAA,EAEA,MAAM,cAAc,SAAsB;AACxC,SAAK,SAAS,kBAAkB,OAAO;AAAA,EACzC;AAAA,EAEA,MAAM,UAAU,SAAsB;AACpC,SAAK,SAAS,yBAAyB,OAAO;AAAA,EAChD;AAAA,EAEA,MAAM,eAAe,SAAsB;AACzC,SAAK,SAAS,6BAA6B,OAAO;AAAA,EACpD;AAAA,EAEA,MAAM,SAAS,SAAsB;AACnC,SAAK,SAAS,eAAe,OAAO;AAAA,EACtC;AAAA,EAEA,MAAM,cAAc,SAAsB;AACxC,SAAK,SAAS,oBAAoB,OAAO;AAAA,EAC3C;AAAA,EAEA,MAAM,eAAe,SAAsB;AACzC,SAAK,SAAS,qBAAqB,OAAO;AAAA,EAC5C;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../analytics/utils/analytics-utils.ts"],
4
- "sourcesContent": ["type QueuedEvent = { event: string; params: Record<string, unknown> };\n\nconst QUEUE_TIMEOUT_MS = 30_000;\n\nexport function createAnalyticsQueue<Payload>({\n isReady,\n send,\n queueName,\n}: {\n isReady: () => boolean;\n send: (payload: Payload) => void;\n queueName: string;\n}): (payload: Payload) => void {\n const queue: Payload[] = [];\n let flushTimer: number | null = null;\n let timeoutTimer: number | null = null;\n let permanentlyDisabled = false;\n\n const cleanup = () => {\n if (flushTimer !== null) {\n window.clearInterval(flushTimer);\n flushTimer = null;\n }\n if (timeoutTimer !== null) {\n window.clearTimeout(timeoutTimer);\n timeoutTimer = null;\n }\n };\n\n const flush = () => {\n if (!isReady()) {\n return;\n }\n console.debug(\n `[analytics] flushing ${queue.length} queued events for ${queueName}`,\n );\n try {\n queue.forEach(send);\n } finally {\n queue.length = 0;\n cleanup();\n }\n };\n\n const scheduleFlush = () => {\n if (typeof window === \"undefined\" || flushTimer !== null) {\n return;\n }\n\n flushTimer = window.setInterval(flush, 500);\n timeoutTimer = window.setTimeout(() => {\n queue.length = 0;\n permanentlyDisabled = true;\n console.debug(`Analytics queue timed out for ${queueName}`);\n cleanup();\n }, QUEUE_TIMEOUT_MS);\n };\n\n return (payload: Payload) => {\n if (permanentlyDisabled) {\n console.debug(\n `[analytics] ${queueName} queue is disabled, dropping event`,\n payload,\n );\n return;\n }\n\n if (isReady()) {\n send(payload);\n } else {\n queue.push(payload);\n scheduleFlush();\n }\n };\n}\n\nexport function createEventQueue(\n checkPixelReady: () => boolean,\n sendEvent: (event: string, params: Record<string, unknown>) => void,\n pixelName: string,\n): (event: string, params?: Record<string, unknown>) => void {\n const enqueue = createAnalyticsQueue<QueuedEvent>({\n isReady: checkPixelReady,\n send: ({ event, params }) => sendEvent(event, params),\n queueName: pixelName,\n });\n\n return (event, params = {}) => enqueue({ event, params });\n}\n\ntype MethodQueueOptions = {\n queueName?: string;\n onTimeout?: () => void;\n};\n\nexport function createMethodQueue<\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n InstanceType extends Record<string, (...args: any[]) => any>,\n>(\n checkInstanceReady: () => InstanceType | null,\n options?: MethodQueueOptions,\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n): (method: keyof InstanceType, ...args: any[]) => void {\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n const queue: { method: keyof InstanceType; args: any[] }[] = [];\n let flushTimer: number | null = null;\n let timeoutTimer: number | null = null;\n let permanentlyDisabled = false;\n const queueName = options?.queueName ?? \"method queue\";\n\n const cleanup = () => {\n if (flushTimer !== null) {\n window.clearInterval(flushTimer);\n flushTimer = null;\n }\n if (timeoutTimer !== null) {\n window.clearTimeout(timeoutTimer);\n timeoutTimer = null;\n }\n };\n\n const flush = () => {\n const instance = checkInstanceReady();\n if (!instance) {\n return;\n }\n try {\n queue.forEach(({ method, args }) => {\n const methodFunction = instance[method];\n if (typeof methodFunction === \"function\") {\n void methodFunction.apply(instance, args);\n }\n });\n } finally {\n queue.length = 0;\n cleanup();\n }\n };\n\n const scheduleFlush = () => {\n if (typeof window === \"undefined\" || flushTimer !== null) {\n return;\n }\n\n flushTimer = window.setInterval(flush, 500);\n timeoutTimer = window.setTimeout(() => {\n queue.length = 0;\n permanentlyDisabled = true;\n if (typeof window !== \"undefined\") {\n console.debug(\n `[analytics] ${queueName} timed out and has been disabled`,\n );\n }\n options?.onTimeout?.();\n cleanup();\n }, QUEUE_TIMEOUT_MS);\n };\n\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n return (method: keyof InstanceType, ...args: any[]) => {\n if (permanentlyDisabled) {\n return;\n }\n\n const instance = checkInstanceReady();\n if (instance) {\n const methodFunction = instance[method];\n if (typeof methodFunction === \"function\") {\n void methodFunction.apply(instance, args);\n }\n } else {\n queue.push({ method, args });\n scheduleFlush();\n }\n };\n}\n"],
5
- "mappings": "AAEA,MAAM,mBAAmB;AAElB,SAAS,qBAA8B;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AACF,GAI+B;AAC7B,QAAM,QAAmB,CAAC;AAC1B,MAAI,aAA4B;AAChC,MAAI,eAA8B;AAClC,MAAI,sBAAsB;AAE1B,QAAM,UAAU,MAAM;AACpB,QAAI,eAAe,MAAM;AACvB,aAAO,cAAc,UAAU;AAC/B,mBAAa;AAAA,IACf;AACA,QAAI,iBAAiB,MAAM;AACzB,aAAO,aAAa,YAAY;AAChC,qBAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM;AAClB,QAAI,CAAC,QAAQ,GAAG;AACd;AAAA,IACF;AACA,YAAQ;AAAA,MACN,wBAAwB,MAAM,MAAM,sBAAsB,SAAS;AAAA,IACrE;AACA,QAAI;AACF,YAAM,QAAQ,IAAI;AAAA,IACpB,UAAE;AACA,YAAM,SAAS;AACf,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,gBAAgB,MAAM;AAC1B,QAAI,OAAO,WAAW,eAAe,eAAe,MAAM;AACxD;AAAA,IACF;AAEA,iBAAa,OAAO,YAAY,OAAO,GAAG;AAC1C,mBAAe,OAAO,WAAW,MAAM;AACrC,YAAM,SAAS;AACf,4BAAsB;AACtB,cAAQ,MAAM,iCAAiC,SAAS,EAAE;AAC1D,cAAQ;AAAA,IACV,GAAG,gBAAgB;AAAA,EACrB;AAEA,SAAO,CAAC,YAAqB;AAC3B,QAAI,qBAAqB;AACvB,cAAQ;AAAA,QACN,eAAe,SAAS;AAAA,QACxB;AAAA,MACF;AACA;AAAA,IACF;AAEA,QAAI,QAAQ,GAAG;AACb,WAAK,OAAO;AAAA,IACd,OAAO;AACL,YAAM,KAAK,OAAO;AAClB,oBAAc;AAAA,IAChB;AAAA,EACF;AACF;AAEO,SAAS,iBACd,iBACA,WACA,WAC2D;AAC3D,QAAM,UAAU,qBAAkC;AAAA,IAChD,SAAS;AAAA,IACT,MAAM,CAAC,EAAE,OAAO,OAAO,MAAM,UAAU,OAAO,MAAM;AAAA,IACpD,WAAW;AAAA,EACb,CAAC;AAED,SAAO,CAAC,OAAO,SAAS,CAAC,MAAM,QAAQ,EAAE,OAAO,OAAO,CAAC;AAC1D;AAOO,SAAS,kBAId,oBACA,SAEsD;AAEtD,QAAM,QAAuD,CAAC;AAC9D,MAAI,aAA4B;AAChC,MAAI,eAA8B;AAClC,MAAI,sBAAsB;AAC1B,QAAM,YAAY,SAAS,aAAa;AAExC,QAAM,UAAU,MAAM;AACpB,QAAI,eAAe,MAAM;AACvB,aAAO,cAAc,UAAU;AAC/B,mBAAa;AAAA,IACf;AACA,QAAI,iBAAiB,MAAM;AACzB,aAAO,aAAa,YAAY;AAChC,qBAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,QAAQ,MAAM;AAClB,UAAM,WAAW,mBAAmB;AACpC,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AACA,QAAI;AACF,YAAM,QAAQ,CAAC,EAAE,QAAQ,KAAK,MAAM;AAClC,cAAM,iBAAiB,SAAS,MAAM;AACtC,YAAI,OAAO,mBAAmB,YAAY;AACxC,eAAK,eAAe,MAAM,UAAU,IAAI;AAAA,QAC1C;AAAA,MACF,CAAC;AAAA,IACH,UAAE;AACA,YAAM,SAAS;AACf,cAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,gBAAgB,MAAM;AAC1B,QAAI,OAAO,WAAW,eAAe,eAAe,MAAM;AACxD;AAAA,IACF;AAEA,iBAAa,OAAO,YAAY,OAAO,GAAG;AAC1C,mBAAe,OAAO,WAAW,MAAM;AACrC,YAAM,SAAS;AACf,4BAAsB;AACtB,UAAI,OAAO,WAAW,aAAa;AACjC,gBAAQ;AAAA,UACN,eAAe,SAAS;AAAA,QAC1B;AAAA,MACF;AACA,eAAS,YAAY;AACrB,cAAQ;AAAA,IACV,GAAG,gBAAgB;AAAA,EACrB;AAGA,SAAO,CAAC,WAA+B,SAAgB;AACrD,QAAI,qBAAqB;AACvB;AAAA,IACF;AAEA,UAAM,WAAW,mBAAmB;AACpC,QAAI,UAAU;AACZ,YAAM,iBAAiB,SAAS,MAAM;AACtC,UAAI,OAAO,mBAAmB,YAAY;AACxC,aAAK,eAAe,MAAM,UAAU,IAAI;AAAA,MAC1C;AAAA,IACF,OAAO;AACL,YAAM,KAAK,EAAE,QAAQ,KAAK,CAAC;AAC3B,oBAAc;AAAA,IAChB;AAAA,EACF;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../analytics/utils/navigation-tracker.ts"],
4
- "sourcesContent": ["export type PageMetadata = {\n url: string;\n title: string;\n referrer: string;\n timestamp: number;\n navigationType?: \"initial\" | \"soft\";\n};\n\nexport class NavigationTracker {\n private lastUrl: string | null = null;\n private onNavigate: (metadata: PageMetadata) => void;\n private originalPushState: typeof window.history.pushState | null = null;\n\n constructor(onNavigate: (metadata: PageMetadata) => void) {\n this.onNavigate = onNavigate;\n }\n\n init() {\n this.emitNavigation(\"initial\");\n\n window.addEventListener(\"popstate\", this.handleNavigation);\n\n this.setupSPATracking();\n }\n\n private setupSPATracking() {\n this.originalPushState = window.history.pushState;\n\n window.history.pushState = (...args) => {\n this.originalPushState!.apply(window.history, args);\n this.handleNavigation();\n };\n }\n\n private handleNavigation = () => {\n this.emitNavigation(\"soft\");\n };\n\n private emitNavigation(navigationType: PageMetadata[\"navigationType\"]) {\n const currentUrl = window.location.href;\n\n if (this.lastUrl !== null && this.lastUrl === currentUrl) {\n return;\n }\n this.lastUrl = currentUrl;\n\n const metadata: PageMetadata = {\n url: currentUrl,\n title: document.title,\n referrer: document.referrer,\n timestamp: Date.now(),\n navigationType,\n };\n\n this.onNavigate(metadata);\n }\n\n cleanup() {\n window.removeEventListener(\"popstate\", this.handleNavigation);\n\n if (this.originalPushState) {\n window.history.pushState = this.originalPushState;\n }\n }\n}\n"],
5
- "mappings": "AAQO,MAAM,kBAAkB;AAAA,EACrB,UAAyB;AAAA,EACzB;AAAA,EACA,oBAA4D;AAAA,EAEpE,YAAY,YAA8C;AACxD,SAAK,aAAa;AAAA,EACpB;AAAA,EAEA,OAAO;AACL,SAAK,eAAe,SAAS;AAE7B,WAAO,iBAAiB,YAAY,KAAK,gBAAgB;AAEzD,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEQ,mBAAmB;AACzB,SAAK,oBAAoB,OAAO,QAAQ;AAExC,WAAO,QAAQ,YAAY,IAAI,SAAS;AACtC,WAAK,kBAAmB,MAAM,OAAO,SAAS,IAAI;AAClD,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,mBAAmB,MAAM;AAC/B,SAAK,eAAe,MAAM;AAAA,EAC5B;AAAA,EAEQ,eAAe,gBAAgD;AACrE,UAAM,aAAa,OAAO,SAAS;AAEnC,QAAI,KAAK,YAAY,QAAQ,KAAK,YAAY,YAAY;AACxD;AAAA,IACF;AACA,SAAK,UAAU;AAEf,UAAM,WAAyB;AAAA,MAC7B,KAAK;AAAA,MACL,OAAO,SAAS;AAAA,MAChB,UAAU,SAAS;AAAA,MACnB,WAAW,KAAK,IAAI;AAAA,MACpB;AAAA,IACF;AAEA,SAAK,WAAW,QAAQ;AAAA,EAC1B;AAAA,EAEA,UAAU;AACR,WAAO,oBAAoB,YAAY,KAAK,gBAAgB;AAE5D,QAAI,KAAK,mBAAmB;AAC1B,aAAO,QAAQ,YAAY,KAAK;AAAA,IAClC;AAAA,EACF;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../analytics/utils/shopify-funnel-gate.ts"],
4
- "sourcesContent": ["import type { AnalyticsSink } from \"../analytics-sink\";\n\n/**\n * Checkout-funnel events that Shopify's hosted checkout already reports to ad\n * platforms server-side (via native sales channels / Customer Events / CAPI).\n * When checkout is Shopify-hosted, a third-party pixel firing these from the\n * storefront double-counts against Shopify's copy \u2014 the storefront and the\n * Shopify checkout are different origins, so there is no shared event_id to\n * deduplicate against. `startCheckout` is the one fired today; `purchase` is\n * listed so the gate covers it automatically if the storefront ever emits it.\n */\nconst SHOPIFY_OWNED_FUNNEL_EVENTS = [\n \"startCheckout\",\n \"purchase\",\n] as const satisfies readonly (keyof AnalyticsSink)[];\n\nconst shopifyOwnedFunnelEvents: ReadonlySet<string> = new Set(\n SHOPIFY_OWNED_FUNNEL_EVENTS,\n);\n\n/**\n * Wraps a third-party ad-pixel sink so checkout-funnel events Shopify owns\n * become no-ops; every other event passes through untouched. Apply only to\n * third-party pixel sinks \u2014 never to the first-party `ReploSink` (the\n * storefront's own record) or the local `WindowSink` event bus.\n */\nexport function gateShopifyOwnedFunnelEvents(\n sink: AnalyticsSink,\n): AnalyticsSink {\n return new Proxy(sink, {\n get(target, property, receiver) {\n if (\n typeof property === \"string\" &&\n shopifyOwnedFunnelEvents.has(property)\n ) {\n return async () => {};\n }\n return Reflect.get(target, property, receiver);\n },\n });\n}\n"],
5
- "mappings": "AAWA,MAAM,8BAA8B;AAAA,EAClC;AAAA,EACA;AACF;AAEA,MAAM,2BAAgD,IAAI;AAAA,EACxD;AACF;AAQO,SAAS,6BACd,MACe;AACf,SAAO,IAAI,MAAM,MAAM;AAAA,IACrB,IAAI,QAAQ,UAAU,UAAU;AAC9B,UACE,OAAO,aAAa,YACpB,yBAAyB,IAAI,QAAQ,GACrC;AACA,eAAO,YAAY;AAAA,QAAC;AAAA,MACtB;AACA,aAAO,QAAQ,IAAI,QAAQ,UAAU,QAAQ;AAAA,IAC/C;AAAA,EACF,CAAC;AACH;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../cart/buy-now-action.ts"],
4
- "sourcesContent": ["\"use server\";\n\nimport type { CartLineAttribute } from \"./cart-types\";\n\nimport { headers } from \"next/headers\";\n\nimport { v4 as uuidv4 } from \"uuid\";\nimport { z } from \"zod\";\n\nimport { getEnv } from \"../env\";\nimport { CanopyError } from \"../lib/canopy-error\";\nimport { getCheckoutProvider } from \"../lib/integration-utils\";\nimport { buildBaseUrl } from \"../lib/url-utils\";\nimport { createCartAction } from \"./cart-actions\";\nimport { REPLO_ATTRIBUTION_PROPERTY } from \"./cart-types\";\nimport { getReturnUrls } from \"./return-urls\";\n\nclass BuyNowError extends CanopyError {}\nclass BuyNowCartCreationError extends CanopyError {}\n\n/**\n * Server action that handles the full buy-now flow:\n * 1. For Shopify: creates a cart via the canopy-api-backed gateway, returns checkoutUrl.\n * 2. For Stripe: creates a Stripe checkout session via canopy-api, returns session URL.\n *\n * Variant IDs are expected to already be Storefront GIDs (from data loader output).\n * No internal\u2192external ID mapping is needed.\n */\nexport async function buyNowAction(\n input: Parameters<typeof buyNowWithRecoveryAction>[0],\n) {\n const outcome = await buyNowWithRecoveryAction(input);\n if (outcome.result === \"restartCheckout\") {\n throw new BuyNowCartCreationError({ message: outcome.message });\n }\n return outcome;\n}\n\nexport async function buyNowWithRecoveryAction(input: {\n checkoutAttemptId?: string;\n lineItems: {\n variantId: string;\n quantity: number;\n sellingPlanId: string | null;\n properties: CartLineAttribute[];\n }[];\n discountCodes: string[];\n pageUrl: string;\n}): Promise<\n | { result: \"created\"; redirectUrl: string }\n | { result: \"restartCheckout\"; message: string }\n | {\n result: \"outOfStock\";\n // Each short variant with the purchasable remainder, so the cart can\n // clamp quantities to what's in stock instead of dropping whole lines.\n variants: { variantId: string; available: number }[];\n }\n> {\n const { lineItems, discountCodes, pageUrl } = input;\n\n const headersList = await headers();\n const host = headersList.get(\"host\");\n if (!host) {\n throw new BuyNowError({ message: \"Missing host header\" });\n }\n const { origin, cancelUrl } = getReturnUrls({\n host,\n forwardedHost: headersList.get(\"x-forwarded-host\"),\n forwardedProto: headersList.get(\"x-forwarded-proto\"),\n requestOrigin: headersList.get(\"origin\"),\n pageUrl,\n });\n\n const checkoutProvider = await getCheckoutProvider();\n\n const cartLines = lineItems.map((item) => {\n const hasReploAttribution = item.properties.some(\n (prop) => prop.key === REPLO_ATTRIBUTION_PROPERTY.key,\n );\n const properties = hasReploAttribution\n ? item.properties\n : [REPLO_ATTRIBUTION_PROPERTY, ...item.properties];\n\n return {\n id: item.variantId,\n quantity: item.quantity,\n sellingPlanId: item.sellingPlanId,\n properties,\n };\n });\n\n if (checkoutProvider === \"stripe\") {\n const env = await getEnv();\n const temporaryCartId = input.checkoutAttemptId ?? uuidv4();\n\n const body = {\n cartId: temporaryCartId,\n checkoutAttemptId: temporaryCartId,\n lines: cartLines.map((line) => ({\n variantId: line.id,\n quantity: line.quantity,\n properties: line.properties,\n })),\n projectId: env.PROJECT_ID,\n // canopy appends session_id={CHECKOUT_SESSION_ID} at session creation;\n // the success route resolves it into the order status page.\n successUrl: `${origin}/checkout/success`,\n cancelUrl,\n };\n\n const canopyApiUrl = `${buildBaseUrl(env.CANOPY_API_HOST)}/api/v1/stripe-checkout/create-session`;\n const response = await fetch(canopyApiUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n if (response.status === 409) {\n const terminalAttempt = z\n .object({\n error: z.literal(\"checkoutUnavailable\"),\n retry: z.literal(\"newAttempt\"),\n message: z.string().min(1),\n })\n .safeParse(await response.json());\n if (terminalAttempt.success)\n return {\n result: \"restartCheckout\",\n message: terminalAttempt.data.message,\n };\n }\n throw new BuyNowCartCreationError({\n message: \"Failed to create Stripe checkout session for buy now\",\n additionalData: {\n status: response.status,\n statusText: response.statusText,\n },\n });\n }\n\n const payload: unknown = await response.json();\n const outOfStock = z\n .object({\n result: z.literal(\"outOfStock\"),\n variants: z.array(\n z.object({\n variantId: z.string(),\n available: z.number().int().min(0),\n }),\n ),\n })\n .safeParse(payload);\n if (outOfStock.success) {\n return { result: \"outOfStock\", variants: outOfStock.data.variants };\n }\n const created = z.object({ url: z.string() }).safeParse(payload);\n if (!created.success) {\n throw new BuyNowCartCreationError({\n message: \"Stripe checkout session response missing redirect URL\",\n cause: created.error,\n });\n }\n return { result: \"created\", redirectUrl: created.data.url };\n }\n\n // Shopify and other integrations: create cart via canopy-api-backed gateway\n const cart = await createCartAction({\n lines: cartLines,\n skipStoringCart: true,\n discountCodes: discountCodes.length > 0 ? discountCodes : undefined,\n });\n\n if (!cart?.checkoutUrl) {\n throw new BuyNowCartCreationError({\n message: \"Failed to create cart or get checkout URL\",\n additionalData: { lineItems, discountCodes },\n });\n }\n\n const checkoutUrl = new URL(cart.checkoutUrl, origin);\n return { result: \"created\", redirectUrl: checkoutUrl.toString() };\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../cart/cart-actions.ts"],
4
- "sourcesContent": ["\"use server\";\n\nimport type {\n AddToCartPayload,\n Cart,\n CartLinePayload,\n RemoveFromCartPayload,\n UpdateCartLineItemPayload,\n} from \"./cart-types\";\n\nimport { cookies } from \"next/headers\";\n\nimport { getCheckoutProvider } from \"../lib/integration-utils\";\nimport {\n getCartCookieOptions,\n REPLO_CART_COOKIE_NAME,\n} from \"./gateways/cart-constants\";\nimport { getCartGateway } from \"./gateways/cart-gateway\";\nimport {\n loadCartFromCookie,\n saveCartToCookie,\n} from \"./utils/cookie-cart-persistence\";\n\nconst SHOPIFY_CART_COOKIE_NAME = \"replo_cart_id\";\n\n/**\n * Gets the existing cart or creates a new one if none exists. This is necessary\n * because we may not have cookies in the server context during initial load.\n *\n * See: https://nextjs.org/docs/app/api-reference/functions/cookies#understanding-cookie-behavior-in-server-components\n *\n * @returns The existing cart or a newly created cart\n */\nexport async function getOrCreateCartAction(): Promise<Cart | null> {\n const existingCart = await getCartAction();\n if (existingCart) {\n // The cookie cart snapshots catalog facts at add-to-cart time; a cart\n // that outlives a price change or a product removal corrects itself here,\n // on the mount round-trip, instead of lying until checkout.\n const cartGateway = await getCartGateway();\n return await cartGateway.reconcileStoredCart(existingCart);\n }\n return await createCartAction();\n}\n\n/**\n * Retrieves the current cart from cookies. Returns null if no cart exists or\n * if the cart has expired/been deleted.\n *\n * @returns The current cart or null if none exists\n */\nexport async function getCartAction(): Promise<Cart | null> {\n const checkoutProvider = await getCheckoutProvider();\n\n if (checkoutProvider === \"stripe\") {\n return await loadCartFromCookie(REPLO_CART_COOKIE_NAME);\n }\n\n const cookieStore = await cookies();\n const existingCartId = cookieStore.get(SHOPIFY_CART_COOKIE_NAME)?.value;\n\n if (!existingCartId) {\n return null;\n }\n\n const cartGateway = await getCartGateway();\n const cart = await cartGateway.getCart(existingCartId);\n\n // If we had a cart ID in the cookie but couldn't fetch the cart,\n // it means the cart is invalid/expired - clear the cookie\n if (!cart) {\n try {\n cookieStore.set(SHOPIFY_CART_COOKIE_NAME, \"\", {\n ...getCartCookieOptions(),\n maxAge: 0,\n });\n } catch (error) {\n console.warn(\"Failed to delete cart cookie:\", error);\n }\n }\n\n return cart;\n}\n\n/**\n * Creates a new cart with optional initial line items. The cart ID is stored\n * in a cookie for future retrieval.\n *\n * @param options.lines - Optional initial cart line items\n * @param options.skipStoringCart - If true, skips storing the cart in cookies (used for buy-now flows)\n * @param options.discountCodes - Optional discount codes to apply on cart creation\n * @returns The newly created cart\n */\nexport async function createCartAction(options?: {\n lines?: CartLinePayload[];\n skipStoringCart?: boolean;\n discountCodes?: string[];\n}): Promise<Cart | null> {\n const { lines, skipStoringCart = false, discountCodes } = options ?? {};\n const checkoutProvider = await getCheckoutProvider();\n const cartGateway = await getCartGateway();\n const cart = await cartGateway.createCart(lines, discountCodes);\n\n if (cart && !skipStoringCart) {\n // Set the cart ID in a cookie - this works in Server Action context\n try {\n if (checkoutProvider === \"stripe\") {\n await saveCartToCookie(cart, REPLO_CART_COOKIE_NAME);\n } else {\n const cookieStore = await cookies();\n cookieStore.set(\n SHOPIFY_CART_COOKIE_NAME,\n cart.id,\n getCartCookieOptions(),\n );\n }\n } catch (cookieError) {\n console.warn(\"Failed to set cart cookie:\", cookieError);\n }\n }\n\n return cart;\n}\n\n/**\n * Adds line items to an existing cart.\n *\n * @param lines - Array of cart line items to add\n * @param cartId - The ID of the cart to add items to\n * @returns The updated cart\n */\nexport async function addToCartAction(\n lines: AddToCartPayload[\"lines\"],\n cartId: string,\n): Promise<Cart | null> {\n const cartGateway = await getCartGateway();\n return await cartGateway.addToCart({ lines, cartId });\n}\n\n/**\n * Updates a cart line item (typically quantity).\n *\n * @param line - The cart line item with updated values\n * @param cartId - The ID of the cart containing the line item\n * @returns The updated cart\n */\nexport async function updateCartLineItemAction(\n line: UpdateCartLineItemPayload[\"line\"],\n cartId: string,\n): Promise<Cart | null> {\n const cartGateway = await getCartGateway();\n return await cartGateway.updateCartLineItem({ line, cartId });\n}\n\n/**\n * Removes one or more line items from the cart.\n *\n * @param lineIds - Array of line item IDs to remove\n * @param cartId - The ID of the cart to remove items from\n * @returns The updated cart\n */\nexport async function removeCartLineItemsAction(\n lineIds: RemoveFromCartPayload[\"lineIds\"],\n cartId: string,\n): Promise<Cart | null> {\n const cartGateway = await getCartGateway();\n return await cartGateway.removeCartLineItems({ lineIds, cartId });\n}\n\n/**\n * Updates discount codes for a cart.\n *\n * @param discountCodes - Array of discount code strings to apply\n * @param cartId - The ID of the cart to update\n * @returns The updated cart\n */\nexport async function updateCartDiscountCodesAction(\n discountCodes: string[],\n cartId: string,\n): Promise<Cart | null> {\n const cartGateway = await getCartGateway();\n return await cartGateway.updateCartDiscountCodes({ discountCodes, cartId });\n}\n"],
5
- "mappings": ";AAUA,SAAS,eAAe;AAExB,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,OACK;AAEP,MAAM,2BAA2B;AAUjC,eAAsB,wBAA8C;AAClE,QAAM,eAAe,MAAM,cAAc;AACzC,MAAI,cAAc;AAIhB,UAAM,cAAc,MAAM,eAAe;AACzC,WAAO,MAAM,YAAY,oBAAoB,YAAY;AAAA,EAC3D;AACA,SAAO,MAAM,iBAAiB;AAChC;AAQA,eAAsB,gBAAsC;AAC1D,QAAM,mBAAmB,MAAM,oBAAoB;AAEnD,MAAI,qBAAqB,UAAU;AACjC,WAAO,MAAM,mBAAmB,sBAAsB;AAAA,EACxD;AAEA,QAAM,cAAc,MAAM,QAAQ;AAClC,QAAM,iBAAiB,YAAY,IAAI,wBAAwB,GAAG;AAElE,MAAI,CAAC,gBAAgB;AACnB,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,MAAM,eAAe;AACzC,QAAM,OAAO,MAAM,YAAY,QAAQ,cAAc;AAIrD,MAAI,CAAC,MAAM;AACT,QAAI;AACF,kBAAY,IAAI,0BAA0B,IAAI;AAAA,QAC5C,GAAG,qBAAqB;AAAA,QACxB,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,SAAS,OAAO;AACd,cAAQ,KAAK,iCAAiC,KAAK;AAAA,IACrD;AAAA,EACF;AAEA,SAAO;AACT;AAWA,eAAsB,iBAAiB,SAId;AACvB,QAAM,EAAE,OAAO,kBAAkB,OAAO,cAAc,IAAI,WAAW,CAAC;AACtE,QAAM,mBAAmB,MAAM,oBAAoB;AACnD,QAAM,cAAc,MAAM,eAAe;AACzC,QAAM,OAAO,MAAM,YAAY,WAAW,OAAO,aAAa;AAE9D,MAAI,QAAQ,CAAC,iBAAiB;AAE5B,QAAI;AACF,UAAI,qBAAqB,UAAU;AACjC,cAAM,iBAAiB,MAAM,sBAAsB;AAAA,MACrD,OAAO;AACL,cAAM,cAAc,MAAM,QAAQ;AAClC,oBAAY;AAAA,UACV;AAAA,UACA,KAAK;AAAA,UACL,qBAAqB;AAAA,QACvB;AAAA,MACF;AAAA,IACF,SAAS,aAAa;AACpB,cAAQ,KAAK,8BAA8B,WAAW;AAAA,IACxD;AAAA,EACF;AAEA,SAAO;AACT;AASA,eAAsB,gBACpB,OACA,QACsB;AACtB,QAAM,cAAc,MAAM,eAAe;AACzC,SAAO,MAAM,YAAY,UAAU,EAAE,OAAO,OAAO,CAAC;AACtD;AASA,eAAsB,yBACpB,MACA,QACsB;AACtB,QAAM,cAAc,MAAM,eAAe;AACzC,SAAO,MAAM,YAAY,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAC9D;AASA,eAAsB,0BACpB,SACA,QACsB;AACtB,QAAM,cAAc,MAAM,eAAe;AACzC,SAAO,MAAM,YAAY,oBAAoB,EAAE,SAAS,OAAO,CAAC;AAClE;AASA,eAAsB,8BACpB,eACA,QACsB;AACtB,QAAM,cAAc,MAAM,eAAe;AACzC,SAAO,MAAM,YAAY,wBAAwB,EAAE,eAAe,OAAO,CAAC;AAC5E;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../cart/cart-loader.tsx"],
4
- "sourcesContent": ["import { getCartAction } from \"./cart-actions\";\nimport { CartProvider } from \"./cart-provider\";\n\n/**\n * Server component that loads the cart and provides it to child components\n * through the CartProvider context. In development mode, skips initial\n * cart loading to avoid cookie issues during development.\n *\n * @param children - Child components that will have access to the cart\n * @returns A CartProvider component wrapping the children with cart data\n */\nexport async function CartLoader({ children }: React.PropsWithChildren) {\n const cart =\n process.env.NODE_ENV === \"development\" ? null : await getCartAction();\n\n return <CartProvider cart={cart}>{children}</CartProvider>;\n}\n"],
5
- "mappings": "AAeS;AAfT,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB;AAU7B,eAAsB,WAAW,EAAE,SAAS,GAA4B;AACtE,QAAM,OACJ,QAAQ,IAAI,aAAa,gBAAgB,OAAO,MAAM,cAAc;AAEtE,SAAO,oBAAC,gBAAa,MAAa,UAAS;AAC7C;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../cart/cart-provider.tsx"],
4
- "sourcesContent": ["/**\n * Use useCart() hook to access cart UI state (itemsCount, isCartOpen, openCart, closeCart). For adding products to cart, use useAddToCart. For buy now functionality, use useBuyNow.\n * @module\n */\n\"use client\";\n\nimport type {\n Cart,\n CartLine,\n CartLineAdjustment,\n CartLinePayload,\n} from \"./cart-types\";\n\nimport React from \"react\";\n\nimport { v4 as uuidv4 } from \"uuid\";\n\nimport { useAnalyticsOptional } from \"../analytics/analytics-provider\";\nimport {\n addToCartAction,\n createCartAction,\n getCartAction,\n getOrCreateCartAction,\n removeCartLineItemsAction,\n updateCartDiscountCodesAction,\n updateCartLineItemAction,\n} from \"./cart-actions\";\nimport {\n deriveAddToCartAdjustments,\n deriveUpdateCartAdjustments,\n} from \"./utils/cart-adjustments\";\nimport {\n buildCartLineAnalyticsData,\n buildCartViewAnalyticsData,\n} from \"./utils/cart-analytics\";\nimport { CartContextError, toCartError } from \"./utils/cart-error\";\nimport { recalculateCartCost } from \"./utils/cart-utils\";\nimport { createOptimisticSellingPlanAllocation } from \"./utils/variant-to-cart-line\";\n\nexport type CartOperation = \"add\" | \"update\" | \"remove\" | \"discount\";\n\n/**\n * The most recent cart change that could not be saved. `message` is written\n * for the shopper, so a cart UI can render it as-is next to a retry.\n */\nexport interface CartError {\n /** Which cart change failed */\n operation: CartOperation;\n /** Shopper-facing explanation with a retry prompt */\n message: string;\n}\n\n// Global promise to prevent multiple cart creation attempts\nlet cartCreationPromise: Promise<Cart> | null = null;\n\nfunction getOrCreateSharedCart() {\n cartCreationPromise ??= getOrCreateCartAction()\n .then((cart) => {\n if (!cart) {\n throw new CartContextError({\n message: \"Your cart could not be loaded. Please try again.\",\n });\n }\n return cart;\n })\n .finally(() => {\n cartCreationPromise = null;\n });\n return cartCreationPromise;\n}\n\n/**\n * Client-side cart operation to add a line item. Used in editor mode.\n * Merges with existing lines if they match by merchandise ID and selling plan.\n *\n * @param cart - The cart to add the line to\n * @param line - The cart line payload to add\n * @returns The updated cart\n */\nfunction addLineToCart({\n cart,\n line,\n lineId,\n}: {\n cart: Cart;\n line: CartLinePayload;\n lineId: string;\n}): Cart {\n const existingLineIndex = cart.lines.findIndex((existingLine) => {\n return (\n existingLine.merchandise?.id === line.id &&\n // Distinguish by selling plan to avoid merging subscription with one-time\n (line.sellingPlanId ?? null) ===\n (existingLine.sellingPlanAllocation?.sellingPlan.id ?? null)\n );\n });\n\n if (existingLineIndex >= 0) {\n // Update existing line\n const updatedLines = [...cart.lines];\n updatedLines[existingLineIndex] = {\n ...updatedLines[existingLineIndex]!,\n quantity: updatedLines[existingLineIndex]!.quantity + line.quantity,\n };\n return recalculateCartCost({ ...cart, lines: updatedLines });\n } else {\n const optimisticSellingPlanAllocation =\n line.sellingPlanId && line.merchandise\n ? createOptimisticSellingPlanAllocation({\n merchandise: line.merchandise,\n sellingPlanId: line.sellingPlanId,\n currencyCode: cart.cost?.currencyCode ?? \"USD\",\n })\n : null;\n\n const newLine: CartLine = {\n id: lineId,\n quantity: line.quantity,\n merchandise: line.merchandise ?? null,\n attributes: line.properties ?? [],\n sellingPlanAllocation: optimisticSellingPlanAllocation,\n };\n return recalculateCartCost({ ...cart, lines: [newLine, ...cart.lines] });\n }\n}\n\n/**\n * Client-side cart operation to update a line item. Used in editor mode.\n *\n * @param cart - The cart containing the line to update\n * @param line - The cart line payload with updated values\n * @returns The updated cart\n */\nfunction updateLineInCart(cart: Cart, line: CartLinePayload): Cart {\n const updatedLines = cart.lines.map((existingLine) => {\n return existingLine.id === line.id\n ? { ...existingLine, quantity: line.quantity }\n : existingLine;\n });\n return recalculateCartCost({ ...cart, lines: updatedLines });\n}\n\n/**\n * Client-side cart operation to remove a line item. Used in editor mode.\n *\n * @param cart - The cart containing the line to remove\n * @param lineId - The ID of the line to remove\n * @returns The updated cart\n */\nfunction removeLineFromCart(cart: Cart, lineId: string): Cart {\n const updatedLines = cart.lines.filter((line) => line.id !== lineId);\n return recalculateCartCost({ ...cart, lines: updatedLines });\n}\n\n/**\n * Internal cart context type with full functionality.\n * This is for internal use only - external code should use the limited CartContextType.\n */\nexport interface CartContextTypeInternal {\n /** The current cart (can be null) */\n cartData: Cart | null;\n /** Array of cart line items */\n lineItems: CartLine[];\n /** Total price of all items */\n subtotal: number;\n /** Total number of items in cart */\n itemsCount: number;\n /** Currency code for the cart */\n currencyCode: string;\n /** Function to add items to cart */\n addToCart: (\n lines: CartLinePayload[],\n openCartAfterAdd?: boolean,\n ) => Promise<{ adjustments: CartLineAdjustment[] }>;\n /** Function to update cart item quantity */\n updateCartItem: (\n line: CartLinePayload,\n ) => Promise<{ adjustments: CartLineAdjustment[] }>;\n /** Function to remove item from cart */\n removeCartItem: (lineId: string) => Promise<void>;\n /** Function to update discount codes on cart */\n updateDiscountCodes: (discountCodes: string[]) => Promise<void>;\n /** Re-read the persisted cart and adopt it if no mutations are in flight */\n refreshCart: () => Promise<void>;\n /** Function to create cart and checkout immediately */\n buyNow: (\n lines: CartLinePayload[],\n discountCodes?: string[],\n ) => Promise<Cart | null>;\n /** URL to redirect to checkout */\n checkoutUrl: string;\n /** Whether the cart UI is open */\n isCartOpen: boolean;\n /** Function to open the cart UI */\n openCart: () => void;\n /** Function to close the cart UI */\n closeCart: () => void;\n /** The last cart change that failed to save; cleared when the next change starts */\n error: CartError | null;\n /** Function to dismiss the current error */\n clearError: () => void;\n}\n\n// NOTE (Gabe, 2026-01-08): We intentionally duplicate properties from CartContextTypeInternal\n// rather than using Pick<> so that TypeDoc generates expanded documentation for each property.\n/**\n * Public cart context type for LLM use.\n * For adding products to cart, use useAddToCart.\n * For buy now functionality, use useBuyNow.\n */\nexport interface CartContextType {\n /** Total number of items in cart */\n itemsCount: number;\n /** Whether the cart UI is open */\n isCartOpen: boolean;\n /** Function to open the cart UI */\n openCart: () => void;\n /** Function to close the cart UI */\n closeCart: () => void;\n /** Function to update discount codes on cart */\n updateDiscountCodes: (discountCodes: string[]) => Promise<void>;\n /**\n * Re-read the persisted cart and adopt it if no mutations are in flight.\n * Call after something outside the provider rewrote the cart \u2014 e.g. the\n * checkout route clamped it and bounced back with `?checkout=adjusted`.\n */\n refreshCart: () => Promise<void>;\n /**\n * The last cart change that could not be saved, with a shopper-ready\n * message. Set when an add, quantity change, removal, or discount fails;\n * cleared when the next change starts or via `clearError`. Render it in the\n * cart UI so the shopper knows to retry.\n */\n error: CartError | null;\n /** Function to dismiss the current error */\n clearError: () => void;\n}\n\nconst CartContext = React.createContext<CartContextTypeInternal | undefined>(\n undefined,\n);\n\n/**\n * Provider component that manages global cart state and operations. Handles both\n * server-side cart synchronization and client-side optimistic updates.\n *\n * @returns A context provider wrapping the children with cart functionality\n */\nexport function CartProvider({\n children,\n cart,\n}: React.PropsWithChildren<{\n /** Initial cart data from the server (can be null) */\n cart: Cart | null;\n}>) {\n const [cartData, setCartData] = React.useState<Cart | null>(cart);\n const optimisticCart = React.useRef(cart);\n const updateCartData = React.useCallback(\n (update: React.SetStateAction<Cart | null>) => {\n const nextCart =\n typeof update === \"function\" ? update(optimisticCart.current) : update;\n // Analytics and overlapping mutations need the snapshot before React renders it.\n optimisticCart.current = nextCart;\n setCartData(nextCart);\n return nextCart;\n },\n [],\n );\n const [isCartOpen, setIsCartOpen] = React.useState(false);\n const [error, setError] = React.useState<CartError | null>(null);\n const clearError = React.useCallback(() => setError(null), []);\n const isMounted = React.useRef(true);\n\n const runWithErrorState = async <ResultType,>(\n operation: CartOperation,\n mutate: () => Promise<ResultType>,\n ) => {\n setError(null);\n try {\n return await mutate();\n } catch (caught) {\n console.error(`[Replo] Cart ${operation} failed:`, caught);\n setError(toCartError(operation, caught));\n throw caught;\n }\n };\n const analytics = useAnalyticsOptional();\n const serverCart = React.useRef(cart);\n const needsRefresh = React.useRef(false);\n const mutationQueue = React.useRef(Promise.resolve());\n const pendingMutations = React.useRef(0);\n const optimisticLines = React.useRef(new Map<string, CartLinePayload>());\n\n const enqueueMutation = async (\n save: (currentCart: Cart) => Promise<Cart | null>,\n ) => {\n pendingMutations.current += 1;\n const request = mutationQueue.current.then(async () => {\n // An existing server cart remains usable if background initialization fails.\n await cartCreationPromise?.catch(() => null);\n if (needsRefresh.current) {\n const restoredCart = await getCartAction();\n if (!restoredCart)\n throw new CartContextError({\n message:\n \"Your cart could not be refreshed. Please reload before changing it.\",\n });\n serverCart.current = restoredCart;\n needsRefresh.current = false;\n }\n if (!serverCart.current) {\n throw new CartContextError({\n message: \"Your cart could not be loaded. Please try again.\",\n });\n }\n try {\n const savedCart = await save(serverCart.current);\n if (!savedCart)\n throw new CartContextError({\n message: \"Your cart could not be saved. Please try again.\",\n });\n serverCart.current = savedCart;\n } catch (error) {\n // A lost response may still have persisted the add that the next removal targets.\n const restoredCart = await getCartAction().catch(() => null);\n needsRefresh.current = !restoredCart;\n if (restoredCart) serverCart.current = restoredCart;\n throw error;\n }\n });\n // Cookie writes must finish in shopper order, including after a failed request.\n mutationQueue.current = request\n .catch(() => {})\n .then(() => {\n pendingMutations.current -= 1;\n if (pendingMutations.current === 0) {\n reportedLineQuantities.current.clear();\n optimisticLines.current.clear();\n updateCartData(serverCart.current);\n }\n });\n await request;\n };\n\n const findLine = ({\n currentCart,\n lineId,\n originalLine,\n }: {\n currentCart: Cart;\n lineId: string;\n originalLine?: CartLine;\n }) => {\n const existingLine = currentCart.lines.find((line) => line.id === lineId);\n if (existingLine) return existingLine;\n const optimisticLine = optimisticLines.current.get(lineId);\n const merchandiseId = optimisticLine?.id ?? originalLine?.merchandise?.id;\n const sellingPlanId =\n optimisticLine?.sellingPlanId ??\n originalLine?.sellingPlanAllocation?.sellingPlan.id ??\n null;\n return currentCart.lines.find((line) => {\n return (\n line.merchandise?.id === merchandiseId &&\n (line.sellingPlanAllocation?.sellingPlan.id ?? null) === sellingPlanId\n );\n });\n };\n\n const initializeCart = React.useCallback(async () => {\n const loadedCart = await getOrCreateSharedCart();\n if (!isMounted.current) {\n throw new DOMException(\"Cart provider was unmounted\", \"AbortError\");\n }\n serverCart.current = loadedCart;\n if (pendingMutations.current === 0) updateCartData(loadedCart);\n return loadedCart;\n }, [updateCartData]);\n\n // eslint-disable-next-line replo/no-use-effect -- Initializes the browser cart on mount.\n React.useEffect(() => {\n isMounted.current = true;\n void initializeCart().catch((error) => {\n if (isMounted.current) {\n console.error(\"[Replo] Error getting or creating cart:\", error);\n }\n });\n return () => {\n isMounted.current = false;\n };\n }, [initializeCart]);\n\n // Derived values - handle null cart gracefully\n const lineItems = cartData?.lines ?? [];\n\n const subtotal =\n cartData?.lines.reduce((sum, lineItem) => {\n if (lineItem.quantity > 0 && lineItem.merchandise) {\n sum += lineItem.merchandise.price * lineItem.quantity;\n }\n return sum;\n }, 0) ?? 0;\n\n const itemsCount =\n cartData?.lines.reduce((sum, lineItem) => {\n if (lineItem.quantity > 0) {\n sum += lineItem.quantity;\n }\n return sum;\n }, 0) ?? 0;\n\n // Cart UI state functions\n const emitCartView = React.useCallback(\n (cart: Cart | null) => {\n if (analytics) {\n void analytics.viewCart({ data: buildCartViewAnalyticsData(cart) });\n }\n },\n [analytics],\n );\n\n const openCart = React.useCallback(() => {\n setIsCartOpen(true);\n emitCartView(cartData);\n }, [cartData, emitCartView]);\n\n const closeCart = React.useCallback(() => {\n setIsCartOpen(false);\n }, []);\n\n const refreshCart = React.useCallback(async () => {\n const refreshedCart = await getCartAction();\n // In-flight mutations own serverCart; a slow refresh must not clobber\n // their newer result with this older snapshot.\n if (\n !isMounted.current ||\n !refreshedCart ||\n pendingMutations.current !== 0\n ) {\n return;\n }\n serverCart.current = refreshedCart;\n updateCartData(refreshedCart);\n }, [updateCartData]);\n\n // Last quantity reported to analytics per line with an update in flight, so\n // overlapping stepper clicks diff against it instead of the same render-time\n // quantity. Dropped once the server confirms or another mutation replaces\n // the line set.\n const reportedLineQuantities = React.useRef(new Map<string, number>());\n\n const addToCart = (\n lines: CartLinePayload[],\n openCartAfterAdd: boolean = true,\n ) => {\n return runWithErrorState(\"add\", async () => {\n // React callbacks retain their render's cart, even after initialization resolves.\n const readyCart =\n cartData ??\n serverCart.current ??\n (await initializeCart().catch((caught: unknown) => {\n // The cart UI is where the failure is shown, so a first add that fails\n // before it would have opened the cart still opens it.\n if (openCartAfterAdd) setIsCartOpen(true);\n throw caught;\n }));\n\n reportedLineQuantities.current.clear();\n const additions = lines.map((line) => {\n const lineId = `temp-${uuidv4()}`;\n optimisticLines.current.set(lineId, line);\n return { line, lineId };\n });\n const applyLines = (cart: Cart) => {\n let updatedCart = { ...cart };\n for (const { line, lineId } of additions) {\n updatedCart = addLineToCart({ cart: updatedCart, line, lineId });\n }\n return updatedCart;\n };\n\n const updatedCart = updateCartData((currentCart) => {\n return applyLines(currentCart ?? readyCart);\n });\n\n if (analytics) {\n for (const line of lines) {\n if (!line.merchandise) {\n continue;\n }\n void analytics.addToCart({\n data: buildCartLineAnalyticsData({\n merchandise: line.merchandise,\n quantity: line.quantity,\n currencyCode: readyCart.cost.currencyCode,\n }),\n });\n }\n }\n\n if (openCartAfterAdd) {\n setIsCartOpen(true);\n emitCartView(updatedCart);\n }\n\n // The write path reconciles the whole cart, so any line can be clamped\n // or dropped \u2014 not just the ones this call added. Intent comes from the\n // request itself, not the optimistic cart, whose lines can lack\n // merchandise or plan metadata.\n const adjustments: CartLineAdjustment[] = [];\n await enqueueMutation(async (currentCart) => {\n const savedCart = await addToCartAction(lines, currentCart.id);\n if (savedCart) {\n adjustments.push(\n ...deriveAddToCartAdjustments({\n cartBeforeAdd: currentCart,\n requestedLines: lines,\n savedCart,\n }),\n );\n }\n return savedCart;\n });\n return { adjustments };\n });\n };\n\n const updateCartItem = (line: CartLinePayload) => {\n return runWithErrorState(\"update\", async () => {\n // If no cart exists, we can't update it\n if (!cartData) {\n console.warn(\n \"[Replo] Cannot update cart item: no cart exists. Reach out to support@replo.app if this persists.\",\n );\n return { adjustments: [] };\n }\n\n // Ad platforms have no \"quantity changed\" event: an increase is an add of\n // the difference and a decrease is a remove of the difference, matching\n // how Shopify themes report their cart steppers.\n const currentLine = cartData.lines.find((item) => item.id === line.id);\n const merchandise = currentLine?.merchandise ?? line.merchandise;\n const quantityDelta =\n line.quantity -\n (reportedLineQuantities.current.get(line.id) ??\n currentLine?.quantity ??\n 0);\n reportedLineQuantities.current.set(line.id, line.quantity);\n if (analytics && merchandise && quantityDelta !== 0) {\n const data = buildCartLineAnalyticsData({\n merchandise,\n quantity: Math.abs(quantityDelta),\n currencyCode: cartData.cost.currencyCode,\n });\n void (quantityDelta > 0\n ? analytics.addToCart({ data })\n : analytics.removeFromCart({ data }));\n }\n\n // Optimistic update - use functional form to avoid stale state\n updateCartData((currentCart) => {\n if (!currentCart) {\n return null;\n }\n return updateLineInCart(currentCart, line);\n });\n\n const adjustments: CartLineAdjustment[] = [];\n await enqueueMutation(async (currentCart) => {\n const savedLine = findLine({\n currentCart,\n lineId: line.id,\n originalLine: currentLine,\n });\n if (!savedLine) {\n return currentCart;\n }\n const savedCart = await updateCartLineItemAction(\n { ...line, id: savedLine.id },\n currentCart.id,\n );\n if (savedCart) {\n adjustments.push(\n ...deriveUpdateCartAdjustments({\n cartBeforeUpdate: currentCart,\n editedLine: savedLine,\n requestedQuantity: line.quantity,\n requestedSellingPlanId: line.sellingPlanId,\n savedCart,\n }),\n );\n }\n return savedCart;\n });\n return { adjustments };\n });\n };\n\n const removeCartItem = (lineId: string) => {\n return runWithErrorState(\"remove\", async () => {\n if (!cartData) {\n console.warn(\n \"[Replo] Cannot remove cart item: no cart exists. Reach out to support@replo.app if this persists.\",\n );\n return;\n }\n\n const itemToRemove = cartData.lines.find((item) => item.id === lineId);\n reportedLineQuantities.current.delete(lineId);\n if (analytics && itemToRemove && itemToRemove.merchandise) {\n void analytics.removeFromCart({\n data: buildCartLineAnalyticsData({\n merchandise: itemToRemove.merchandise,\n quantity: itemToRemove.quantity,\n currencyCode: cartData.cost.currencyCode,\n }),\n });\n }\n\n // Optimistic update - use functional form to avoid stale state\n updateCartData((currentCart) => {\n if (!currentCart) {\n return null;\n }\n return removeLineFromCart(currentCart, lineId);\n });\n\n await enqueueMutation(async (currentCart) => {\n const savedLine = findLine({\n currentCart,\n lineId,\n originalLine: itemToRemove,\n });\n return savedLine\n ? await removeCartLineItemsAction([savedLine.id], currentCart.id)\n : currentCart;\n });\n });\n };\n\n const updateDiscountCodes = (discountCodes: string[]) => {\n return runWithErrorState(\"discount\", async () => {\n const readyCart =\n cartData ?? serverCart.current ?? (await initializeCart());\n\n updateCartData((currentCart) => {\n return {\n ...(currentCart ?? readyCart),\n discountCodes: discountCodes.map((code) => ({\n code,\n applicable: true,\n })),\n };\n });\n\n await enqueueMutation((currentCart) => {\n return updateCartDiscountCodesAction(discountCodes, currentCart.id);\n });\n });\n };\n\n const buyNow = async (lines: CartLinePayload[], discountCodes?: string[]) => {\n // Create a new cart with the specified lines and discount codes\n const cart = await createCartAction({\n lines,\n skipStoringCart: true,\n discountCodes,\n });\n if (cart) {\n return cart;\n } else {\n console.warn(\n \"[Replo] Failed to create cart for buy now. Reach out to support@replo.app if this persists.\",\n );\n return null;\n }\n };\n\n const checkoutUrl = cartData?.checkoutUrl ?? \"/\";\n\n return (\n <CartContext.Provider\n value={{\n cartData,\n lineItems,\n subtotal,\n itemsCount,\n currencyCode: cartData?.cost.currencyCode ?? \"USD\",\n addToCart,\n updateCartItem,\n removeCartItem,\n updateDiscountCodes,\n refreshCart,\n buyNow,\n checkoutUrl,\n isCartOpen,\n openCart,\n closeCart,\n error,\n clearError,\n }}\n >\n {children}\n </CartContext.Provider>\n );\n}\n\n/**\n * @deprecated For internal use only. Use useAddToCart or useBuyNow\n * for cart operations. Use useCart for cart UI state (itemsCount, openCart, closeCart).\n */\nexport function useCartInternal(): CartContextTypeInternal {\n const context = React.useContext(CartContext);\n if (context === undefined) {\n throw new CartContextError({\n message: \"useCartInternal must be used within a CartProvider\",\n });\n }\n return context;\n}\n\n/**\n * Hook to access cart UI state and controls. For adding products to cart,\n * use useAddToCart. For buy now functionality, use useBuyNow.\n *\n * @example\n * ```tsx\n * import { useCart } from \"@replohq/sdk/cart/cart-provider\";\n *\n * function MyComponent() {\n * const { itemsCount, openCart } = useCart();\n * ...\n * }\n * ```\n * @throws Error if used outside of a CartProvider\n */\nexport function useCart(): CartContextType {\n const context = React.useContext(CartContext);\n if (context === undefined) {\n throw new CartContextError({\n message: \"useCart must be used within a CartProvider\",\n });\n }\n return {\n itemsCount: context.itemsCount,\n isCartOpen: context.isCartOpen,\n openCart: context.openCart,\n closeCart: context.closeCart,\n updateDiscountCodes: context.updateDiscountCodes,\n refreshCart: context.refreshCart,\n error: context.error,\n clearError: context.clearError,\n };\n}\n"],
5
- "mappings": "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",
6
- "names": ["error", "cart", "updatedCart"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../cart/cart-schema.ts"],
4
- "sourcesContent": ["import { z } from \"zod\";\n\n// NOTE (Ryan, 2026-07-23, REPL-27611): Self-contained copy of the cart wire\n// schema that the SDK gateway validates on published pages, so nothing\n// shipped to a generated site imports from `schemas`. The backend keeps the\n// canonical copy in `schemas/cart.ts` (its cart services can't depend on\n// the SDK without a cycle); `cart-schema.spec.ts` keeps the two in lockstep.\n// This module is internal wire validation; public types live in `cart/cart-types`.\n\n// ---------------------------------------------------------------------------\n// Cart line attribute\n// ---------------------------------------------------------------------------\n\nconst cartLineAttributeSchema = z.object({\n key: z.string(),\n value: z.union([z.string(), z.number(), z.boolean()]),\n});\n\n// ---------------------------------------------------------------------------\n// Image (cart-scoped; lightweight compared to objectType image)\n// ---------------------------------------------------------------------------\n\nconst cartImageSchema = z.object({\n url: z.string(),\n altText: z.string().nullable(),\n});\n\n// ---------------------------------------------------------------------------\n// Selling plan types\n// ---------------------------------------------------------------------------\n\n// Integer minor units (Stripe convention): 1999 = $19.99 USD. Mirrors\n// amountSchema in schemas/money.ts, which shipped code cannot import.\nconst amountSchema = z.number().int();\nconst amountWithCurrencyCodeSchema = z.object({\n amount: amountSchema,\n currencyCode: z.string(),\n});\n\nconst sellingPlanPriceAdjustmentSchema = z.object({\n compareAtPrice: amountWithCurrencyCodeSchema,\n perDeliveryPrice: amountWithCurrencyCodeSchema,\n price: amountWithCurrencyCodeSchema,\n unitPrice: amountWithCurrencyCodeSchema.nullable(),\n});\n\nconst sellingPlanAllocationSchema = z.object({\n sellingPlan: z.object({\n id: z.string(),\n name: z.string(),\n description: z.string().nullable(),\n }),\n priceAdjustments: z.array(sellingPlanPriceAdjustmentSchema),\n checkoutChargeAmount: amountWithCurrencyCodeSchema,\n remainingBalanceChargeAmount: amountWithCurrencyCodeSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Cart line merchandise\n// ---------------------------------------------------------------------------\n\nconst cartLineMerchandiseSchema = z.object({\n id: z.string(),\n product: z.object({\n id: z.string(),\n title: z.string(),\n }),\n title: z.string(),\n price: amountSchema,\n compareAtPrice: amountSchema.nullish(),\n image: cartImageSchema.nullable(),\n selectedOptions: z.array(z.object({ name: z.string(), value: z.string() })),\n});\n\n// ---------------------------------------------------------------------------\n// Cart line\n// ---------------------------------------------------------------------------\n\nconst cartLineSchema = z.object({\n id: z.string(),\n quantity: z.number(),\n merchandise: cartLineMerchandiseSchema,\n attributes: z.array(cartLineAttributeSchema),\n sellingPlanAllocation: sellingPlanAllocationSchema.nullish(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart cost\n// ---------------------------------------------------------------------------\n\nconst cartCostSchema = z.object({\n subtotalAmount: amountSchema,\n totalAmount: amountSchema,\n currencyCode: z.string(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart discount code\n// ---------------------------------------------------------------------------\n\nconst cartDiscountCodeSchema = z.object({\n code: z.string(),\n applicable: z.boolean(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart discount allocation\n// ---------------------------------------------------------------------------\n\nconst cartDiscountAllocationSchema = z.object({\n discountedAmount: amountSchema,\n title: z.string().nullable(),\n});\n\n// ---------------------------------------------------------------------------\n// Cart (top level)\n// ---------------------------------------------------------------------------\n\nexport const cartSchema = z.object({\n id: z.string(),\n lines: z.array(cartLineSchema),\n cost: cartCostSchema,\n checkoutUrl: z.string().optional(),\n discountCodes: z.array(cartDiscountCodeSchema).optional(),\n discountAllocations: z.array(cartDiscountAllocationSchema).optional(),\n});\n\nexport type Cart = z.infer<typeof cartSchema>;\n"],
5
- "mappings": "AAAA,SAAS,SAAS;AAalB,MAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,KAAK,EAAE,OAAO;AAAA,EACd,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;AAMD,MAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,KAAK,EAAE,OAAO;AAAA,EACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAC/B,CAAC;AAQD,MAAM,eAAe,EAAE,OAAO,EAAE,IAAI;AACpC,MAAM,+BAA+B,EAAE,OAAO;AAAA,EAC5C,QAAQ;AAAA,EACR,cAAc,EAAE,OAAO;AACzB,CAAC;AAED,MAAM,mCAAmC,EAAE,OAAO;AAAA,EAChD,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,OAAO;AAAA,EACP,WAAW,6BAA6B,SAAS;AACnD,CAAC;AAED,MAAM,8BAA8B,EAAE,OAAO;AAAA,EAC3C,aAAa,EAAE,OAAO;AAAA,IACpB,IAAI,EAAE,OAAO;AAAA,IACb,MAAM,EAAE,OAAO;AAAA,IACf,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,CAAC;AAAA,EACD,kBAAkB,EAAE,MAAM,gCAAgC;AAAA,EAC1D,sBAAsB;AAAA,EACtB,8BAA8B;AAChC,CAAC;AAMD,MAAM,4BAA4B,EAAE,OAAO;AAAA,EACzC,IAAI,EAAE,OAAO;AAAA,EACb,SAAS,EAAE,OAAO;AAAA,IAChB,IAAI,EAAE,OAAO;AAAA,IACb,OAAO,EAAE,OAAO;AAAA,EAClB,CAAC;AAAA,EACD,OAAO,EAAE,OAAO;AAAA,EAChB,OAAO;AAAA,EACP,gBAAgB,aAAa,QAAQ;AAAA,EACrC,OAAO,gBAAgB,SAAS;AAAA,EAChC,iBAAiB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AAC5E,CAAC;AAMD,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,IAAI,EAAE,OAAO;AAAA,EACb,UAAU,EAAE,OAAO;AAAA,EACnB,aAAa;AAAA,EACb,YAAY,EAAE,MAAM,uBAAuB;AAAA,EAC3C,uBAAuB,4BAA4B,QAAQ;AAC7D,CAAC;AAMD,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc,EAAE,OAAO;AACzB,CAAC;AAMD,MAAM,yBAAyB,EAAE,OAAO;AAAA,EACtC,MAAM,EAAE,OAAO;AAAA,EACf,YAAY,EAAE,QAAQ;AACxB,CAAC;AAMD,MAAM,+BAA+B,EAAE,OAAO;AAAA,EAC5C,kBAAkB;AAAA,EAClB,OAAO,EAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAMM,MAAM,aAAa,EAAE,OAAO;AAAA,EACjC,IAAI,EAAE,OAAO;AAAA,EACb,OAAO,EAAE,MAAM,cAAc;AAAA,EAC7B,MAAM;AAAA,EACN,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,eAAe,EAAE,MAAM,sBAAsB,EAAE,SAAS;AAAA,EACxD,qBAAqB,EAAE,MAAM,4BAA4B,EAAE,SAAS;AACtE,CAAC;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../cart/cart-types.ts"],
4
- "sourcesContent": ["/**\n * TypeScript types for cart data structures. Use these types when working with cart data, but don't import from this module directly in components - use the cart hooks instead.\n * @module\n */\n\nimport type { SellingPlanGroup } from \"../loaders/loader-schemas\";\n\nexport interface Image {\n url: string;\n altText: string | null;\n}\n\nexport interface CartLineMerchandise {\n id: string;\n product: {\n id: string;\n title: string;\n sellingPlanGroups?: SellingPlanGroup[];\n };\n title: string;\n /** Integer minor units (Stripe convention): 1999 = $19.99 USD */\n price: number;\n compareAtPrice?: number | null;\n image: Image | null;\n selectedOptions: {\n name: string;\n value: string;\n }[];\n}\n\nexport interface CartLineAttribute {\n key: string;\n value: string | number | boolean;\n}\n\n/** Replo attribution property added to cart/buy-now line items for order attribution in Shopify. */\nexport const REPLO_ATTRIBUTION_PROPERTY: CartLineAttribute = {\n key: \"_replo\",\n value: \"true\",\n};\n\nexport interface SellingPlanPriceAdjustment {\n compareAtPrice: {\n amount: number;\n currencyCode: string;\n };\n perDeliveryPrice: {\n amount: number;\n currencyCode: string;\n };\n price: {\n amount: number;\n currencyCode: string;\n };\n unitPrice: {\n amount: number;\n currencyCode: string;\n } | null;\n}\n\nexport interface SellingPlanAllocation {\n sellingPlan: {\n id: string;\n name: string;\n description: string | null;\n };\n priceAdjustments: SellingPlanPriceAdjustment[];\n checkoutChargeAmount: {\n amount: number;\n currencyCode: string;\n };\n remainingBalanceChargeAmount: {\n amount: number;\n currencyCode: string;\n };\n}\n\nexport interface CartLine {\n id: string;\n quantity: number;\n /**\n * Null when this is an optimistic line whose merchandise couldn't be\n * resolved from the query cache or passed explicitly. Consumers should\n * render a skeleton/loading state in that case; the line is replaced\n * with real merchandise once the server roundtrip lands.\n */\n merchandise: CartLineMerchandise | null;\n attributes: CartLineAttribute[];\n sellingPlanAllocation?: SellingPlanAllocation | null;\n}\n\nexport interface CartCost {\n /** Integer minor units (Stripe convention) in currencyCode */\n subtotalAmount: number;\n totalAmount: number;\n currencyCode: string;\n}\n\n/**\n * Represents a discount code applied to a cart.\n */\nexport interface CartDiscountCode {\n /** The discount code string */\n code: string;\n /**\n * Whether the discount code is applicable to the current cart.\n * A code may not be applicable due to:\n * - Cart contents not meeting product/collection eligibility\n * - Minimum purchase amount not met\n * - Code expired or usage limits reached\n * - Customer restrictions\n * - Conflicting discount rules\n */\n applicable: boolean;\n}\n\n/**\n * One discount Shopify applied to a cart line or to the whole cart. The amount\n * is already subtracted from `cost.totalAmount` (and from `cost.subtotalAmount`\n * for line-level discounts).\n */\nexport interface CartDiscountAllocation {\n /** Integer minor units (Stripe convention) in the cart's currencyCode */\n discountedAmount: number;\n /** Automatic discount title or discount code; null when Shopify has neither */\n title: string | null;\n}\n\nexport interface Cart {\n id: string;\n lines: CartLine[];\n cost: CartCost;\n checkoutUrl?: string;\n discountCodes?: CartDiscountCode[];\n discountAllocations?: CartDiscountAllocation[];\n}\n\n/**\n * How a cart write differed from what the shopper asked for, derived by\n * comparing the requested lines against the cart the server saved. Cart UIs\n * render these as Shopify-style notices (\"Only 9 in stock \u2014 we've updated\n * your cart\"); the underlying clamp has already been applied to the cart.\n */\nexport type CartLineAdjustment =\n | {\n type: \"quantityClampedToStock\";\n variantId: string;\n requested: number;\n applied: number;\n }\n | { type: \"unavailableLineRemoved\"; variantId: string };\n\nexport interface CartLinePayload {\n id: string;\n quantity: number;\n merchandise?: CartLineMerchandise;\n properties?: CartLineAttribute[];\n sellingPlanId?: string | null;\n}\n\nexport interface AddToCartPayload {\n lines: CartLinePayload[];\n cartId: string;\n}\n\nexport interface UpdateCartLineItemPayload {\n line: CartLinePayload;\n cartId: string;\n}\n\nexport interface RemoveFromCartPayload {\n lineIds: string[];\n cartId: string;\n}\n\nexport interface UpdateCartDiscountCodesPayload {\n cartId: string;\n discountCodes: string[];\n}\n"],
5
- "mappings": "AAoCO,MAAM,6BAAgD;AAAA,EAC3D,KAAK;AAAA,EACL,OAAO;AACT;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/gateways/cart-constants.ts"],
4
- "sourcesContent": ["// NOTE (Max, 2026-07-21): the cookie holds the native Replo cart \u2014 the Stripe and\n// default gateways both use it, so the checkout provider is incidental to the name.\n// NOTE (Max, 2026-07-31): the `_v2` suffix retires cookies written before the\n// integer-minor-units flip (REPL-30044). A pre-flip cookie holds decimal\n// major-unit prices; reading it under the new SDK would reinterpret 19.99 as 19\n// minor units. The persisted cart carries no schema version, so the name is the\n// version \u2014 a bumped name abandons stale carts (they expire in 30d) instead of\n// silently rescaling them.\nexport const REPLO_CART_COOKIE_NAME = \"replo_cart_v2\";\n\n// NOTE (Max, 2026-08-25): Only the Replo sandbox renders the storefront inside\n// a cross-origin iframe (the dashboard preview), where a SameSite=Lax cookie is\n// neither sent nor set \u2014 every cart server action then runs with no cart and\n// returns null. Gate the cross-site attributes (SameSite=None + Secure, with\n// Partitioned to survive third-party-cookie blocking; same treatment as the\n// preview session cookie in cloudflare-daytona-proxy, REPL-26727) to the\n// sandbox, so published storefronts keep the Lax default: shoppers keep the\n// browser-level CSRF backstop and their existing cart cookies stay in the same\n// cookie jar.\nexport function getCartCookieOptions() {\n const sharedOptions = {\n maxAge: 60 * 60 * 24 * 30, // 30 days\n httpOnly: true,\n path: \"/\",\n } as const;\n if (process.env.IS_REPLO_SANDBOX) {\n return {\n ...sharedOptions,\n secure: true,\n sameSite: \"none\",\n partitioned: true,\n } as const;\n }\n return {\n ...sharedOptions,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n } as const;\n}\n"],
5
- "mappings": "AAQO,MAAM,yBAAyB;AAW/B,SAAS,uBAAuB;AACrC,QAAM,gBAAgB;AAAA,IACpB,QAAQ,KAAK,KAAK,KAAK;AAAA;AAAA,IACvB,UAAU;AAAA,IACV,MAAM;AAAA,EACR;AACA,MAAI,QAAQ,IAAI,kBAAkB;AAChC,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,aAAa;AAAA,IACf;AAAA,EACF;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,QAAQ,QAAQ,IAAI,aAAa;AAAA,IACjC,UAAU;AAAA,EACZ;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/gateways/cart-gateway.ts"],
4
- "sourcesContent": ["\"use server\";\n\nimport type {\n AddToCartPayload,\n Cart,\n CartLinePayload,\n RemoveFromCartPayload,\n UpdateCartDiscountCodesPayload,\n UpdateCartLineItemPayload,\n} from \"../cart-types\";\n\nimport { getCheckoutProvider } from \"../../lib/integration-utils\";\nimport { createDefaultCartGateway } from \"./default-cart-gateway\";\nimport { createResolverCartGateway } from \"./resolver-cart-gateway\";\nimport { createStripeCartGateway } from \"./stripe-cart-gateway\";\n\nexport interface CartGateway {\n getCart(cartId: string): Promise<Cart | null>;\n /**\n * Bring a stored cart back in line with its source of truth. Cookie carts\n * reprice against the catalog and drop unavailable lines (persisting the\n * result); provider-backed carts are already server-truth and return the\n * cart unchanged.\n */\n reconcileStoredCart(cart: Cart): Promise<Cart>;\n createCart(\n lines?: CartLinePayload[],\n discountCodes?: string[],\n ): Promise<Cart | null>;\n addToCart(cartPayload: AddToCartPayload): Promise<Cart | null>;\n updateCartLineItem(\n cartPayload: UpdateCartLineItemPayload,\n ): Promise<Cart | null>;\n removeCartLineItems(cartPayload: RemoveFromCartPayload): Promise<Cart | null>;\n updateCartDiscountCodes(\n cartPayload: UpdateCartDiscountCodesPayload,\n ): Promise<Cart | null>;\n}\n\nexport async function getCartGateway(): Promise<CartGateway> {\n const checkoutProvider = await getCheckoutProvider();\n\n if (checkoutProvider === \"stripe\") {\n return await createStripeCartGateway();\n } else if (checkoutProvider === \"shopify\") {\n return await createResolverCartGateway();\n } else {\n return await createDefaultCartGateway();\n }\n}\n"],
5
- "mappings": ";AAWA,SAAS,2BAA2B;AACpC,SAAS,gCAAgC;AACzC,SAAS,iCAAiC;AAC1C,SAAS,+BAA+B;AAyBxC,eAAsB,iBAAuC;AAC3D,QAAM,mBAAmB,MAAM,oBAAoB;AAEnD,MAAI,qBAAqB,UAAU;AACjC,WAAO,MAAM,wBAAwB;AAAA,EACvC,WAAW,qBAAqB,WAAW;AACzC,WAAO,MAAM,0BAA0B;AAAA,EACzC,OAAO;AACL,WAAO,MAAM,yBAAyB;AAAA,EACxC;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/gateways/cookie-cart-gateway.ts"],
4
- "sourcesContent": ["import type { ReconciledCartLine } from \"../../gateways/canopy-api\";\nimport type {\n AddToCartPayload,\n Cart,\n CartLinePayload,\n RemoveFromCartPayload,\n UpdateCartDiscountCodesPayload,\n UpdateCartLineItemPayload,\n} from \"../cart-types\";\nimport type { LineMergeFn } from \"../utils/cookie-cart-persistence\";\nimport type { CartGateway } from \"./cart-gateway\";\n\nimport { applyCartLineReconciliation } from \"../utils/cart-utils\";\nimport {\n addToCartWithPersistence,\n createCartWithPersistence,\n loadCartFromCookie,\n removeCartLineItemsWithPersistence,\n saveCartToCookie,\n updateCartLineItemWithPersistence,\n} from \"../utils/cookie-cart-persistence\";\n\n/**\n * Configuration for cookie-based cart gateways\n */\ninterface CookieCartConfig {\n cookieName: string;\n lineMergeFn: LineMergeFn;\n lineIdGenerator: () => string;\n cartIdGenerator: () => string;\n gatewayName: string; // For logging (e.g., \"Stripe\", \"Default\")\n // The catalog's per-line facts for this cart's variants. When present,\n // every cart write reconciles against it (reprice, clamp, drop\n // unavailable); absent means the gateway has no catalog to ask.\n reconcileLines?: (\n lines: { variantId: string; quantity: number }[],\n ) => Promise<ReconciledCartLine[]>;\n}\n\n/**\n * Abstract base class for cookie-based cart gateways.\n * Provides common error handling, logging, and cart operations.\n * Subclasses must provide gateway-specific configuration.\n */\nexport abstract class CookieBasedCartGateway implements CartGateway {\n protected abstract readonly config: CookieCartConfig;\n\n // Fails open (null) when the catalog can't answer: a canopy blip must not\n // block cart writes \u2014 checkout still enforces stock and price.\n private async fetchReconciledLines(\n cart: Cart,\n ): Promise<ReconciledCartLine[] | null> {\n const reconcileLines = this.config.reconcileLines;\n if (!reconcileLines) {\n return null;\n }\n const requestLines = cart.lines.flatMap((line) => {\n return line.merchandise\n ? [{ variantId: line.merchandise.id, quantity: line.quantity }]\n : [];\n });\n if (requestLines.length === 0) {\n return null;\n }\n try {\n return await reconcileLines(requestLines);\n } catch (error) {\n console.warn(\n `${this.config.gatewayName} cart reconciliation unavailable, keeping cart as written:`,\n error,\n );\n return null;\n }\n }\n\n // Catalog fetch failures fail open inside fetchReconciledLines; a\n // reconciliation mismatch from the apply still throws.\n private async reconcile(\n cart: Cart,\n { clampQuantities }: { clampQuantities: boolean },\n ): Promise<Cart> {\n const reconciledLines = await this.fetchReconciledLines(cart);\n if (!reconciledLines) {\n return cart;\n }\n return applyCartLineReconciliation(cart, reconciledLines, {\n clampQuantities,\n });\n }\n\n private reconcileForWrite = (cart: Cart): Promise<Cart> => {\n return this.reconcile(cart, { clampQuantities: true });\n };\n\n async reconcileStoredCart(cart: Cart): Promise<Cart> {\n // Reads reprice and drop unavailable lines but never clamp quantities \u2014\n // silent quantity changes are the write and checkout paths' job, where\n // they come with messaging.\n const reconciledCart = await this.reconcile(cart, {\n clampQuantities: false,\n });\n // Lines are the only thing reconciliation can change; cost derives from them.\n if (JSON.stringify(reconciledCart.lines) !== JSON.stringify(cart.lines)) {\n await saveCartToCookie(reconciledCart, this.config.cookieName);\n }\n return reconciledCart;\n }\n\n async getCart(cartId: string): Promise<Cart | null> {\n try {\n const cart = await loadCartFromCookie(this.config.cookieName);\n return cart?.id === cartId ? cart : null;\n } catch (error) {\n console.warn(\n `${this.config.gatewayName} cart ${cartId} not found, could not fetch cart:`,\n error,\n );\n return null;\n }\n }\n\n async createCart(\n lines?: CartLinePayload[],\n _discountCodes?: string[],\n ): Promise<Cart | null> {\n try {\n const cart = await createCartWithPersistence({\n cookieName: this.config.cookieName,\n lines,\n lineIdGenerator: this.config.lineIdGenerator,\n cartIdGenerator: this.config.cartIdGenerator,\n reconcile: this.reconcileForWrite,\n });\n return cart;\n } catch (createCartError) {\n console.warn(\n `Failed to create ${this.config.gatewayName} cart${lines?.length ? \" with lines\" : \"\"}:`,\n createCartError,\n );\n return null;\n }\n }\n\n async addToCart(cartPayload: AddToCartPayload): Promise<Cart | null> {\n try {\n const cartData = await addToCartWithPersistence(cartPayload, {\n cookieName: this.config.cookieName,\n mergeFn: this.config.lineMergeFn,\n lineIdGenerator: this.config.lineIdGenerator,\n reconcile: this.reconcileForWrite,\n });\n return cartData;\n } catch (error) {\n console.warn(`Failed to add items to ${this.config.gatewayName} cart:`, {\n error: error instanceof Error ? error.message : String(error),\n cartId: cartPayload.cartId,\n itemCount: cartPayload.lines.length,\n });\n return null;\n }\n }\n\n async updateCartLineItem(\n cartPayload: UpdateCartLineItemPayload,\n ): Promise<Cart | null> {\n try {\n const cartData = await updateCartLineItemWithPersistence(\n cartPayload,\n this.config.cookieName,\n this.reconcileForWrite,\n );\n return cartData;\n } catch (error) {\n console.warn(\n `Failed to update ${this.config.gatewayName} cart line item:`,\n {\n error: error instanceof Error ? error.message : String(error),\n cartId: cartPayload.cartId,\n lineId: cartPayload.line.id,\n quantity: cartPayload.line.quantity,\n },\n );\n return null;\n }\n }\n\n async removeCartLineItems(\n cartPayload: RemoveFromCartPayload,\n ): Promise<Cart | null> {\n try {\n const cartData = await removeCartLineItemsWithPersistence(\n cartPayload,\n this.config.cookieName,\n );\n return cartData;\n } catch (error) {\n console.warn(\n `Failed to remove ${this.config.gatewayName} cart line items:`,\n {\n error: error instanceof Error ? error.message : String(error),\n cartId: cartPayload.cartId,\n lineIds: cartPayload.lineIds,\n },\n );\n return null;\n }\n }\n\n async updateCartDiscountCodes(\n cartPayload: UpdateCartDiscountCodesPayload,\n ): Promise<Cart | null> {\n console.warn(\n `${this.config.gatewayName} cart gateway does not yet support discount codes`,\n );\n // Return existing cart without changes\n try {\n return await this.getCart(cartPayload.cartId);\n } catch (error) {\n console.warn(\"Failed to fetch cart for discount code update:\", error);\n return null;\n }\n }\n}\n"],
5
- "mappings": "AAYA,SAAS,mCAAmC;AAC5C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAwBA,MAAe,uBAA8C;AAAA;AAAA;AAAA,EAKlE,MAAc,qBACZ,MACsC;AACtC,UAAM,iBAAiB,KAAK,OAAO;AACnC,QAAI,CAAC,gBAAgB;AACnB,aAAO;AAAA,IACT;AACA,UAAM,eAAe,KAAK,MAAM,QAAQ,CAAC,SAAS;AAChD,aAAO,KAAK,cACR,CAAC,EAAE,WAAW,KAAK,YAAY,IAAI,UAAU,KAAK,SAAS,CAAC,IAC5D,CAAC;AAAA,IACP,CAAC;AACD,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO;AAAA,IACT;AACA,QAAI;AACF,aAAO,MAAM,eAAe,YAAY;AAAA,IAC1C,SAAS,OAAO;AACd,cAAQ;AAAA,QACN,GAAG,KAAK,OAAO,WAAW;AAAA,QAC1B;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA,EAIA,MAAc,UACZ,MACA,EAAE,gBAAgB,GACH;AACf,UAAM,kBAAkB,MAAM,KAAK,qBAAqB,IAAI;AAC5D,QAAI,CAAC,iBAAiB;AACpB,aAAO;AAAA,IACT;AACA,WAAO,4BAA4B,MAAM,iBAAiB;AAAA,MACxD;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,oBAAoB,CAAC,SAA8B;AACzD,WAAO,KAAK,UAAU,MAAM,EAAE,iBAAiB,KAAK,CAAC;AAAA,EACvD;AAAA,EAEA,MAAM,oBAAoB,MAA2B;AAInD,UAAM,iBAAiB,MAAM,KAAK,UAAU,MAAM;AAAA,MAChD,iBAAiB;AAAA,IACnB,CAAC;AAED,QAAI,KAAK,UAAU,eAAe,KAAK,MAAM,KAAK,UAAU,KAAK,KAAK,GAAG;AACvE,YAAM,iBAAiB,gBAAgB,KAAK,OAAO,UAAU;AAAA,IAC/D;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQ,QAAsC;AAClD,QAAI;AACF,YAAM,OAAO,MAAM,mBAAmB,KAAK,OAAO,UAAU;AAC5D,aAAO,MAAM,OAAO,SAAS,OAAO;AAAA,IACtC,SAAS,OAAO;AACd,cAAQ;AAAA,QACN,GAAG,KAAK,OAAO,WAAW,SAAS,MAAM;AAAA,QACzC;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,WACJ,OACA,gBACsB;AACtB,QAAI;AACF,YAAM,OAAO,MAAM,0BAA0B;AAAA,QAC3C,YAAY,KAAK,OAAO;AAAA,QACxB;AAAA,QACA,iBAAiB,KAAK,OAAO;AAAA,QAC7B,iBAAiB,KAAK,OAAO;AAAA,QAC7B,WAAW,KAAK;AAAA,MAClB,CAAC;AACD,aAAO;AAAA,IACT,SAAS,iBAAiB;AACxB,cAAQ;AAAA,QACN,oBAAoB,KAAK,OAAO,WAAW,QAAQ,OAAO,SAAS,gBAAgB,EAAE;AAAA,QACrF;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,aAAqD;AACnE,QAAI;AACF,YAAM,WAAW,MAAM,yBAAyB,aAAa;AAAA,QAC3D,YAAY,KAAK,OAAO;AAAA,QACxB,SAAS,KAAK,OAAO;AAAA,QACrB,iBAAiB,KAAK,OAAO;AAAA,QAC7B,WAAW,KAAK;AAAA,MAClB,CAAC;AACD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,KAAK,0BAA0B,KAAK,OAAO,WAAW,UAAU;AAAA,QACtE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC5D,QAAQ,YAAY;AAAA,QACpB,WAAW,YAAY,MAAM;AAAA,MAC/B,CAAC;AACD,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,mBACJ,aACsB;AACtB,QAAI;AACF,YAAM,WAAW,MAAM;AAAA,QACrB;AAAA,QACA,KAAK,OAAO;AAAA,QACZ,KAAK;AAAA,MACP;AACA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ;AAAA,QACN,oBAAoB,KAAK,OAAO,WAAW;AAAA,QAC3C;AAAA,UACE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,UAC5D,QAAQ,YAAY;AAAA,UACpB,QAAQ,YAAY,KAAK;AAAA,UACzB,UAAU,YAAY,KAAK;AAAA,QAC7B;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,oBACJ,aACsB;AACtB,QAAI;AACF,YAAM,WAAW,MAAM;AAAA,QACrB;AAAA,QACA,KAAK,OAAO;AAAA,MACd;AACA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ;AAAA,QACN,oBAAoB,KAAK,OAAO,WAAW;AAAA,QAC3C;AAAA,UACE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,UAC5D,QAAQ,YAAY;AAAA,UACpB,SAAS,YAAY;AAAA,QACvB;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,wBACJ,aACsB;AACtB,YAAQ;AAAA,MACN,GAAG,KAAK,OAAO,WAAW;AAAA,IAC5B;AAEA,QAAI;AACF,aAAO,MAAM,KAAK,QAAQ,YAAY,MAAM;AAAA,IAC9C,SAAS,OAAO;AACd,cAAQ,KAAK,kDAAkD,KAAK;AACpE,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/gateways/default-cart-gateway.ts"],
4
- "sourcesContent": ["\"use server\";\n\nimport type { CartLine, CartLinePayload } from \"../cart-types\";\n\nimport { CookieBasedCartGateway } from \"./cookie-cart-gateway\";\n\n// NOTE (Max, 2026-07-31): `_v2` retires pre-integer-minor-units cookies\n// (REPL-30044) \u2014 see REPLO_CART_COOKIE_NAME in cart-constants.ts.\nconst DEFAULT_CART_COOKIE_NAME = \"replo_default_cart_v2\";\n\n/**\n * Merges lines by merchandise ID and selling plan\n */\nfunction defaultLineMergeFn(\n existingLines: CartLine[],\n newLine: CartLinePayload,\n): number {\n return existingLines.findIndex((line) => {\n return (\n line.merchandise?.id === newLine.id &&\n (newLine.sellingPlanId ?? null) ===\n (line.sellingPlanAllocation?.sellingPlan.id ?? null)\n );\n });\n}\n\nfunction defaultLineIdGenerator(): string {\n return crypto.randomUUID();\n}\n\nfunction defaultCartIdGenerator(): string {\n return crypto.randomUUID();\n}\n\nclass DefaultCartGateway extends CookieBasedCartGateway {\n protected readonly config = {\n cookieName: DEFAULT_CART_COOKIE_NAME,\n lineMergeFn: defaultLineMergeFn,\n lineIdGenerator: defaultLineIdGenerator,\n cartIdGenerator: defaultCartIdGenerator,\n gatewayName: \"Default\",\n };\n}\n\nexport async function createDefaultCartGateway(): Promise<DefaultCartGateway> {\n return new DefaultCartGateway();\n}\n"],
5
- "mappings": ";AAIA,SAAS,8BAA8B;AAIvC,MAAM,2BAA2B;AAKjC,SAAS,mBACP,eACA,SACQ;AACR,SAAO,cAAc,UAAU,CAAC,SAAS;AACvC,WACE,KAAK,aAAa,OAAO,QAAQ,OAChC,QAAQ,iBAAiB,WACvB,KAAK,uBAAuB,YAAY,MAAM;AAAA,EAErD,CAAC;AACH;AAEA,SAAS,yBAAiC;AACxC,SAAO,OAAO,WAAW;AAC3B;AAEA,SAAS,yBAAiC;AACxC,SAAO,OAAO,WAAW;AAC3B;AAEA,MAAM,2BAA2B,uBAAuB;AAAA,EACnC,SAAS;AAAA,IAC1B,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AACF;AAEA,eAAsB,2BAAwD;AAC5E,SAAO,IAAI,mBAAmB;AAChC;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/gateways/resolver-cart-gateway.ts"],
4
- "sourcesContent": ["\"use server\";\n\nimport type {\n AddToCartPayload,\n Cart,\n CartLinePayload,\n RemoveFromCartPayload,\n UpdateCartDiscountCodesPayload,\n UpdateCartLineItemPayload,\n} from \"../cart-types\";\nimport type { CartGateway } from \"./cart-gateway\";\n\nimport { getCanopyApiGateway } from \"../../gateways/canopy-api\";\n\n/**\n * @author Ryan\n * CartGateway that delegates all mutations to the canopy-api's cart\n * endpoints. Used for \"externalCart\" integrations (Shopify). canopy-api\n * handles credential resolution and upstream API calls.\n */\nclass ResolverCartGateway implements CartGateway {\n // Shopify carts are fetched from Shopify on every read \u2014 already reconciled.\n async reconcileStoredCart(cart: Cart): Promise<Cart> {\n return cart;\n }\n\n // Returns the gateway's wire-parsed Cart where the client Cart is expected.\n // Safe because client = wire + widenings only \u2014 enforced by the widening\n // assertions in cart-schema.spec.ts.\n async getCart(cartId: string): Promise<Cart | null> {\n try {\n const gateway = await getCanopyApiGateway();\n return await gateway.cartGet({ cartId });\n } catch (error) {\n console.warn(`Cart ${cartId} not found via canopy-api:`, error);\n return null;\n }\n }\n\n async createCart(\n lines?: CartLinePayload[],\n discountCodes?: string[],\n ): Promise<Cart | null> {\n try {\n const gateway = await getCanopyApiGateway();\n return await gateway.cartCreate({\n lines: lines?.map((line) => ({\n merchandiseId: line.id,\n quantity: line.quantity,\n attributes: line.properties?.map((prop) => ({\n key: prop.key,\n value: String(prop.value),\n })),\n sellingPlanId: line.sellingPlanId,\n })),\n discountCodes,\n });\n } catch (error) {\n console.warn(\"Failed to create cart via canopy-api:\", error);\n return null;\n }\n }\n\n async addToCart(cartPayload: AddToCartPayload): Promise<Cart | null> {\n try {\n const gateway = await getCanopyApiGateway();\n return await gateway.cartAddLines({\n cartId: cartPayload.cartId,\n lines: cartPayload.lines.map((line) => ({\n merchandiseId: line.id,\n quantity: line.quantity,\n attributes: line.properties?.map((prop) => ({\n key: prop.key,\n value: String(prop.value),\n })),\n sellingPlanId: line.sellingPlanId,\n })),\n });\n } catch (error) {\n console.warn(\"Failed to add to cart via canopy-api:\", error);\n return null;\n }\n }\n\n async updateCartLineItem(\n cartPayload: UpdateCartLineItemPayload,\n ): Promise<Cart | null> {\n try {\n const gateway = await getCanopyApiGateway();\n return await gateway.cartUpdateLines({\n cartId: cartPayload.cartId,\n lines: [\n {\n lineId: cartPayload.line.id,\n quantity: cartPayload.line.quantity,\n attributes: cartPayload.line.properties?.map((prop) => ({\n key: prop.key,\n value: String(prop.value),\n })),\n sellingPlanId: cartPayload.line.sellingPlanId,\n },\n ],\n });\n } catch (error) {\n console.warn(\"Failed to update cart line via canopy-api:\", error);\n return null;\n }\n }\n\n async removeCartLineItems(\n cartPayload: RemoveFromCartPayload,\n ): Promise<Cart | null> {\n try {\n const gateway = await getCanopyApiGateway();\n return await gateway.cartRemoveLines({\n cartId: cartPayload.cartId,\n lineIds: cartPayload.lineIds,\n });\n } catch (error) {\n console.warn(\"Failed to remove cart lines via canopy-api:\", error);\n return null;\n }\n }\n\n async updateCartDiscountCodes(\n cartPayload: UpdateCartDiscountCodesPayload,\n ): Promise<Cart | null> {\n try {\n const gateway = await getCanopyApiGateway();\n return await gateway.cartUpdateDiscountCodes({\n cartId: cartPayload.cartId,\n discountCodes: cartPayload.discountCodes,\n });\n } catch (error) {\n console.warn(\"Failed to update discount codes via canopy-api:\", error);\n return null;\n }\n }\n}\n\nexport async function createResolverCartGateway(): Promise<CartGateway> {\n return new ResolverCartGateway();\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/gateways/stripe-cart-gateway.ts"],
4
- "sourcesContent": ["\"use server\";\n\nimport type { CartLine, CartLinePayload } from \"../cart-types\";\n\nimport { getCanopyApiGateway } from \"../../gateways/canopy-api\";\nimport { REPLO_CART_COOKIE_NAME } from \"./cart-constants\";\nimport { CookieBasedCartGateway } from \"./cookie-cart-gateway\";\n\n/**\n * Merges lines by merchandise ID only (unlike default which also checks selling plan)\n */\nfunction stripeLineMergeFn(\n existingLines: CartLine[],\n newLine: CartLinePayload,\n): number {\n return existingLines.findIndex((line) => line.merchandise?.id === newLine.id);\n}\n\nfunction stripeLineIdGenerator(): string {\n return crypto.randomUUID();\n}\n\nfunction stripeCartIdGenerator(): string {\n return crypto.randomUUID();\n}\n\nclass StripeCartGateway extends CookieBasedCartGateway {\n protected readonly config = {\n cookieName: REPLO_CART_COOKIE_NAME,\n lineMergeFn: stripeLineMergeFn,\n lineIdGenerator: stripeLineIdGenerator,\n cartIdGenerator: stripeCartIdGenerator,\n gatewayName: \"Stripe\",\n reconcileLines: async (\n lines: { variantId: string; quantity: number }[],\n ) => {\n const gateway = await getCanopyApiGateway();\n return await gateway.reconcileCartLines({ lines });\n },\n };\n}\n\nexport async function createStripeCartGateway(): Promise<StripeCartGateway> {\n return new StripeCartGateway();\n}\n"],
5
- "mappings": ";AAIA,SAAS,2BAA2B;AACpC,SAAS,8BAA8B;AACvC,SAAS,8BAA8B;AAKvC,SAAS,kBACP,eACA,SACQ;AACR,SAAO,cAAc,UAAU,CAAC,SAAS,KAAK,aAAa,OAAO,QAAQ,EAAE;AAC9E;AAEA,SAAS,wBAAgC;AACvC,SAAO,OAAO,WAAW;AAC3B;AAEA,SAAS,wBAAgC;AACvC,SAAO,OAAO,WAAW;AAC3B;AAEA,MAAM,0BAA0B,uBAAuB;AAAA,EAClC,SAAS;AAAA,IAC1B,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,gBAAgB,OACd,UACG;AACH,YAAM,UAAU,MAAM,oBAAoB;AAC1C,aAAO,MAAM,QAAQ,mBAAmB,EAAE,MAAM,CAAC;AAAA,IACnD;AAAA,EACF;AACF;AAEA,eAAsB,0BAAsD;AAC1E,SAAO,IAAI,kBAAkB;AAC/B;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/hooks/use-add-to-cart.ts"],
4
- "sourcesContent": ["/**\n * Hook for adding items to cart using merchandiseId directly (e.g. variant GIDs from data loaders).\n * Merchandise display data for optimistic UI is auto-resolved from the React Query cache.\n * `addToCart` resolves with `{ adjustments }` describing anything the server\n * changed about the request (a quantity clamped to stock, an unavailable line\n * removed) so the storefront can show a notice.\n * @module\n */\n\"use client\";\n\nimport type { QueryClient } from \"@tanstack/react-query\";\nimport type { Product } from \"../../loaders/loader-schemas\";\nimport type { CartError } from \"../cart-provider\";\nimport type {\n CartLineAdjustment,\n CartLineAttribute,\n CartLineMerchandise,\n} from \"../cart-types\";\n\nimport React from \"react\";\n\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { fromMajorUnitsToMinorUnits } from \"schemas/money\";\n\nimport { DATA_LOADER_KEYS } from \"../../loaders/loader-keys\";\nimport { useCartInternal } from \"../cart-provider\";\nimport { REPLO_ATTRIBUTION_PROPERTY } from \"../cart-types\";\nimport { toCartError } from \"../utils/cart-error\";\n\ntype ProductListLike = { products: Product[] };\n\n/**\n * Describes a single item to add to the cart. Uses the merchandiseId\n * (e.g. a variant GID) directly from data loader output. Product\n * display data for optimistic UI is resolved automatically from the\n * React Query cache for both single-product loaders (e.g. ProductLoader)\n * and product-list loaders (e.g. CollectionProductsLoader,\n * RebuyRecommendationsLoader). Pass `merchandise` explicitly to bypass\n * the cache lookup when the variant is known but its product was not\n * loaded via a supported loader.\n */\nexport interface AddToCartItem {\n /** The cart-addressable merchandise ID (e.g. `product.variants[N].id` from loader output). */\n merchandiseId: string;\n quantity?: number;\n sellingPlanId?: string | null;\n /** Custom line item properties (appear on the order). */\n properties?: CartLineAttribute[];\n merchandise?: CartLineMerchandise;\n}\n\n/**\n * What an `addToCart` call did. `adjustments` lists what the server changed\n * about a saved request (a quantity clamped to stock, an unavailable line\n * removed). `error` is set instead when the cart could not be created or\n * saved; the same message is on `useCart().error` for the cart UI.\n */\nexport interface AddToCartResult {\n /** What the server changed about a saved add; empty when nothing was */\n adjustments: CartLineAdjustment[];\n /** Why the add was not saved; null on success */\n error: CartError | null;\n}\n\n/**\n * Loaders whose cached value is a single Product. Scanned for variant\n * matches first since they carry the richest product data.\n */\nconst PRODUCT_LOADER_KEYS = [\n DATA_LOADER_KEYS.SHOPIFY_PRODUCT,\n DATA_LOADER_KEYS.REPLO_PRODUCT,\n] as const;\n\nconst PRODUCT_LIST_LOADER_KEYS = [\n DATA_LOADER_KEYS.SHOPIFY_COLLECTION_PRODUCTS,\n DATA_LOADER_KEYS.REBUY_RECOMMENDATIONS,\n] as const;\n\nfunction getMerchandiseFromProduct({\n product,\n merchandiseId,\n}: {\n product: Product;\n merchandiseId: string;\n}): CartLineMerchandise | undefined {\n if (!product.variants) {\n return undefined;\n }\n\n const matchingVariant = product.variants.find(\n (variant) => variant.id === merchandiseId,\n );\n\n if (!matchingVariant) {\n return undefined;\n }\n\n const image = matchingVariant.image ?? product.featuredImage ?? null;\n return {\n id: merchandiseId,\n product: {\n id: product.id,\n title: product.title ?? \"\",\n sellingPlanGroups: product.sellingPlanGroups ?? [],\n },\n title: matchingVariant.title ?? \"\",\n // NOTE (Max, 2026-08-03): loader prices are decimal MoneyV2 strings, but the\n // cart is integer minor units, so convert at this storefront\u2192cart boundary \u2014\n // a raw parseFloat would store \"19.99\" as 19 minor units (~100\u00D7 too cheap).\n price: matchingVariant.price\n ? fromMajorUnitsToMinorUnits(matchingVariant.price)\n : 0,\n compareAtPrice: matchingVariant.compareAtPrice\n ? fromMajorUnitsToMinorUnits(matchingVariant.compareAtPrice)\n : null,\n image: image ? { url: image.url, altText: image.altText } : null,\n selectedOptions: matchingVariant.selectedOptions ?? [],\n };\n}\n\nexport function findMerchandiseInQueryCache({\n queryClient,\n merchandiseId,\n}: {\n queryClient: QueryClient;\n merchandiseId: string;\n}): CartLineMerchandise | undefined {\n for (const loaderKey of PRODUCT_LOADER_KEYS) {\n const productQueries = queryClient.getQueriesData<Product>({\n queryKey: [loaderKey],\n });\n\n for (const [, productData] of productQueries) {\n if (!productData) {\n continue;\n }\n\n const merchandise = getMerchandiseFromProduct({\n product: productData,\n merchandiseId,\n });\n if (merchandise) {\n return merchandise;\n }\n }\n }\n\n for (const loaderKey of PRODUCT_LIST_LOADER_KEYS) {\n const productListQueries = queryClient.getQueriesData<ProductListLike>({\n queryKey: [loaderKey],\n });\n\n for (const [, productListData] of productListQueries) {\n for (const product of productListData?.products ?? []) {\n const merchandise = getMerchandiseFromProduct({\n product,\n merchandiseId,\n });\n if (merchandise) {\n return merchandise;\n }\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Hook for adding items to cart using merchandise IDs from data loader output.\n *\n * This is the primary hook for adding items to cart in the data-loader\n * architecture. It works with the resolver-backed CartGateway so the scaffold\n * never needs direct integration credentials.\n *\n * Merchandise display data (title, price, image) for optimistic cart UI is\n * auto-resolved from the React Query cache for both single-product loaders\n * (e.g. `ProductLoader`) and product-list loaders (e.g.\n * `CollectionProductsLoader`, `RebuyRecommendationsLoader`). Just pass the\n * merchandiseId. Pass `merchandise` explicitly only when the variant is\n * known but its product was not loaded via a supported loader.\n *\n * `addToCart` never throws. It resolves an `AddToCartResult`: `adjustments`\n * when the add was saved, or `error` when the cart could not be created or\n * saved. On failure the provider also records the error on `useCart().error`\n * and opens the cart UI, which renders it, so a click handler needs no\n * handling of its own.\n *\n * @example\n * ```tsx\n * import { useAddToCart } from \"@replohq/sdk/cart/hooks/use-add-to-cart\";\n *\n * function AddToCartButton({ variant }) {\n * const { addToCart, isAdding } = useAddToCart();\n *\n * return (\n * <button\n * disabled={!variant.availableForSale || isAdding}\n * onClick={() => {\n * void addToCart([{ merchandiseId: variant.id, quantity: 1 }]);\n * }}\n * >\n * {isAdding ? \"Adding...\" : \"Add to Cart\"}\n * </button>\n * );\n * }\n * ```\n */\nexport function useAddToCart() {\n const cart = useCartInternal();\n const queryClient = useQueryClient();\n const [isAdding, setIsAdding] = React.useState(false);\n\n const addToCart = React.useCallback(\n async (\n items: AddToCartItem[],\n openCartAfterAdd = true,\n ): Promise<AddToCartResult> => {\n setIsAdding(true);\n try {\n const cartLines = items.map((item) => {\n const hasReploAttribution = item.properties?.some(\n (prop) => prop.key === REPLO_ATTRIBUTION_PROPERTY.key,\n );\n const properties = hasReploAttribution\n ? item.properties ?? []\n : [REPLO_ATTRIBUTION_PROPERTY, ...(item.properties ?? [])];\n\n const merchandise =\n item.merchandise ??\n findMerchandiseInQueryCache({\n queryClient,\n merchandiseId: item.merchandiseId,\n });\n\n return {\n id: item.merchandiseId,\n quantity: item.quantity ?? 1,\n sellingPlanId: item.sellingPlanId ?? undefined,\n properties,\n merchandise,\n };\n });\n\n const { adjustments } = await cart.addToCart(\n cartLines,\n openCartAfterAdd,\n );\n return { adjustments, error: null };\n } catch (caught) {\n // The provider has already recorded and logged the failure.\n return { adjustments: [], error: toCartError(\"add\", caught) };\n } finally {\n setIsAdding(false);\n }\n },\n [cart, queryClient],\n );\n\n return { addToCart, isAdding };\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/hooks/use-buy-now.ts"],
4
- "sourcesContent": ["/**\n * Use useBuyNow() hook to create \"Buy Now\" buttons that skip the cart and go directly to checkout.\n * Calls a server action to create the cart/checkout session, then redirects the browser.\n * @module\n */\n\"use client\";\n\nimport React from \"react\";\n\nimport { useClientValue } from \"../../hooks/use-client-value\";\nimport { CanopyError } from \"../../lib/canopy-error\";\nimport { navigateExternal } from \"../../lib/external-navigation\";\nimport { buyNowWithRecoveryAction } from \"../buy-now-action\";\n\n// Analytics constants - defined locally to avoid dependency on analytics-client package\nconst REPLO_LOCAL_STORAGE_SESSION_KEY = \"_replo_sid\";\nconst REPLO_SESSION_ID_KEY = \"rsid\";\nconst REPLO_CLIENT_ID_KEY = \"rclid\";\n\n// Analytics session data type - defined locally to avoid dependency\ninterface AnalyticsSessionData {\n sessionId: string;\n reploId: string;\n expiresAt: number;\n createdAt: number;\n conversionsCounter: number;\n isEntryPage: boolean;\n}\n\nclass ProductHasNoVariantsError extends CanopyError {}\nclass CheckoutAttemptError extends CanopyError {}\n\nconst checkoutAttempts = new Map<string, string>();\n\n/**\n * What a `buyNow` call did. Out of stock is an expected storefront outcome\n * (a buyer can race the last unit), so it rides the return value rather than\n * a thrown error; `variants` carries each short variant with the purchasable\n * remainder so the button can render a sold-out state.\n */\nexport type BuyNowOutcome =\n | { result: \"redirected\" }\n | {\n result: \"outOfStock\";\n variants: { variantId: string; available: number }[];\n };\n\nexport interface VariantBuyNowInfo {\n variantId: string;\n quantity?: number;\n sellingPlanId?: string | null;\n}\n\n/**\n * React hook that returns a `buyNow` function for express checkout flows.\n * Handles creating the cart/checkout session server-side and redirecting\n * the browser to checkout.\n *\n * @example\n *\n * ```tsx\n * import { useBuyNow } from \"@replohq/sdk/cart/hooks/use-buy-now\";\n *\n * function MyComponent({ selectedVariant, selectedSellingPlan, quantity }) {\n * const { buyNow } = useBuyNow();\n * const [isSoldOut, setIsSoldOut] = React.useState(false);\n *\n * return (\n * <Button\n * disabled={!selectedVariant?.availableForSale || isSoldOut}\n * onClick={async () => {\n * if (selectedVariant) {\n * const outcome = await buyNow(\n * [\n * {\n * variantId: selectedVariant.id,\n * quantity,\n * sellingPlanId: selectedSellingPlan?.id,\n * },\n * ],\n * { discountCodes: [\"SUMMER2024\"] }\n * );\n * if (outcome.result === \"outOfStock\") {\n * setIsSoldOut(true);\n * }\n * }\n * }}\n * >\n * {isSoldOut ? \"Sold out\" : \"Shop Now\"}\n * </Button>\n * );\n * }\n * ```\n *\n * @returns Object containing the buyNow function\n */\nexport function useBuyNow() {\n const reploSessionString = useClientValue(\n () => localStorage.getItem(REPLO_LOCAL_STORAGE_SESSION_KEY),\n null,\n );\n\n const buyNow = React.useCallback(\n async (\n variants: VariantBuyNowInfo[],\n options?: { discountCodes?: string[] },\n ): Promise<BuyNowOutcome> => {\n if (!variants || variants.length === 0) {\n throw new ProductHasNoVariantsError({\n message: \"No variants provided\",\n });\n }\n\n const checkoutInput = {\n lineItems: variants.map((variant) => ({\n variantId: variant.variantId,\n quantity: variant.quantity ?? 1,\n sellingPlanId: variant.sellingPlanId ?? null,\n properties: [],\n })),\n discountCodes: options?.discountCodes ?? [],\n pageUrl: window.location.href,\n };\n const attemptStorageKey = `replo-checkout-attempt:${JSON.stringify(checkoutInput)}`;\n let checkoutAttemptId = checkoutAttempts.get(attemptStorageKey);\n try {\n checkoutAttemptId ??=\n sessionStorage.getItem(attemptStorageKey) ?? crypto.randomUUID();\n sessionStorage.setItem(attemptStorageKey, checkoutAttemptId);\n } catch {\n // Storage can be unavailable in embeds; retries still share the in-memory ID.\n checkoutAttemptId ??= crypto.randomUUID();\n }\n checkoutAttempts.set(attemptStorageKey, checkoutAttemptId);\n const buyNowResult = await buyNowWithRecoveryAction({\n ...checkoutInput,\n checkoutAttemptId,\n });\n checkoutAttempts.delete(attemptStorageKey);\n try {\n sessionStorage.removeItem(attemptStorageKey);\n } catch {\n // A fresh ID supersedes stale storage on the next shopper attempt.\n checkoutAttempts.set(attemptStorageKey, crypto.randomUUID());\n }\n if (buyNowResult.result === \"restartCheckout\") {\n throw new CheckoutAttemptError({ message: buyNowResult.message });\n }\n if (buyNowResult.result === \"outOfStock\") {\n return { result: \"outOfStock\", variants: buyNowResult.variants };\n }\n\n const url = new URL(buyNowResult.redirectUrl);\n\n // Only append tracking params for non-Stripe checkout URLs (e.g. Shopify).\n // Stripe checkout URLs should not be modified with extra query params.\n const isStripeCheckout = url.hostname.endsWith(\"stripe.com\");\n if (!isStripeCheckout) {\n const currentParams = new URLSearchParams(window.location.search);\n for (const [key, value] of currentParams.entries()) {\n if (!url.searchParams.has(key)) {\n url.searchParams.set(key, value);\n }\n }\n\n if (reploSessionString) {\n try {\n const sessionData: AnalyticsSessionData =\n JSON.parse(reploSessionString);\n if (sessionData.sessionId && sessionData.reploId) {\n url.searchParams.set(REPLO_SESSION_ID_KEY, sessionData.sessionId);\n url.searchParams.set(REPLO_CLIENT_ID_KEY, sessionData.reploId);\n }\n } catch {\n // Ignore invalid session data\n }\n }\n }\n\n navigateExternal(url.toString());\n return { result: \"redirected\" };\n },\n [reploSessionString],\n );\n\n return { buyNow };\n}\n"],
5
- "mappings": ";AAOA,OAAO,WAAW;AAElB,SAAS,sBAAsB;AAC/B,SAAS,mBAAmB;AAC5B,SAAS,wBAAwB;AACjC,SAAS,gCAAgC;AAGzC,MAAM,kCAAkC;AACxC,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;AAY5B,MAAM,kCAAkC,YAAY;AAAC;AACrD,MAAM,6BAA6B,YAAY;AAAC;AAEhD,MAAM,mBAAmB,oBAAI,IAAoB;AAgE1C,SAAS,YAAY;AAC1B,QAAM,qBAAqB;AAAA,IACzB,MAAM,aAAa,QAAQ,+BAA+B;AAAA,IAC1D;AAAA,EACF;AAEA,QAAM,SAAS,MAAM;AAAA,IACnB,OACE,UACA,YAC2B;AAC3B,UAAI,CAAC,YAAY,SAAS,WAAW,GAAG;AACtC,cAAM,IAAI,0BAA0B;AAAA,UAClC,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAEA,YAAM,gBAAgB;AAAA,QACpB,WAAW,SAAS,IAAI,CAAC,aAAa;AAAA,UACpC,WAAW,QAAQ;AAAA,UACnB,UAAU,QAAQ,YAAY;AAAA,UAC9B,eAAe,QAAQ,iBAAiB;AAAA,UACxC,YAAY,CAAC;AAAA,QACf,EAAE;AAAA,QACF,eAAe,SAAS,iBAAiB,CAAC;AAAA,QAC1C,SAAS,OAAO,SAAS;AAAA,MAC3B;AACA,YAAM,oBAAoB,0BAA0B,KAAK,UAAU,aAAa,CAAC;AACjF,UAAI,oBAAoB,iBAAiB,IAAI,iBAAiB;AAC9D,UAAI;AACF,8BACE,eAAe,QAAQ,iBAAiB,KAAK,OAAO,WAAW;AACjE,uBAAe,QAAQ,mBAAmB,iBAAiB;AAAA,MAC7D,QAAQ;AAEN,8BAAsB,OAAO,WAAW;AAAA,MAC1C;AACA,uBAAiB,IAAI,mBAAmB,iBAAiB;AACzD,YAAM,eAAe,MAAM,yBAAyB;AAAA,QAClD,GAAG;AAAA,QACH;AAAA,MACF,CAAC;AACD,uBAAiB,OAAO,iBAAiB;AACzC,UAAI;AACF,uBAAe,WAAW,iBAAiB;AAAA,MAC7C,QAAQ;AAEN,yBAAiB,IAAI,mBAAmB,OAAO,WAAW,CAAC;AAAA,MAC7D;AACA,UAAI,aAAa,WAAW,mBAAmB;AAC7C,cAAM,IAAI,qBAAqB,EAAE,SAAS,aAAa,QAAQ,CAAC;AAAA,MAClE;AACA,UAAI,aAAa,WAAW,cAAc;AACxC,eAAO,EAAE,QAAQ,cAAc,UAAU,aAAa,SAAS;AAAA,MACjE;AAEA,YAAM,MAAM,IAAI,IAAI,aAAa,WAAW;AAI5C,YAAM,mBAAmB,IAAI,SAAS,SAAS,YAAY;AAC3D,UAAI,CAAC,kBAAkB;AACrB,cAAM,gBAAgB,IAAI,gBAAgB,OAAO,SAAS,MAAM;AAChE,mBAAW,CAAC,KAAK,KAAK,KAAK,cAAc,QAAQ,GAAG;AAClD,cAAI,CAAC,IAAI,aAAa,IAAI,GAAG,GAAG;AAC9B,gBAAI,aAAa,IAAI,KAAK,KAAK;AAAA,UACjC;AAAA,QACF;AAEA,YAAI,oBAAoB;AACtB,cAAI;AACF,kBAAM,cACJ,KAAK,MAAM,kBAAkB;AAC/B,gBAAI,YAAY,aAAa,YAAY,SAAS;AAChD,kBAAI,aAAa,IAAI,sBAAsB,YAAY,SAAS;AAChE,kBAAI,aAAa,IAAI,qBAAqB,YAAY,OAAO;AAAA,YAC/D;AAAA,UACF,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAEA,uBAAiB,IAAI,SAAS,CAAC;AAC/B,aAAO,EAAE,QAAQ,aAAa;AAAA,IAChC;AAAA,IACA,CAAC,kBAAkB;AAAA,EACrB;AAEA,SAAO,EAAE,OAAO;AAClB;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../cart/return-urls.ts"],
4
- "sourcesContent": ["function firstHeaderValue(value: string | null) {\n const firstValue = value?.split(\",\")[0]?.trim();\n return firstValue ? firstValue : null;\n}\n\nfunction parseOrigin(value: string | null) {\n if (!value) {\n return null;\n }\n\n try {\n return new URL(value).origin;\n } catch {\n return null;\n }\n}\n\nexport function getReturnUrls({\n host,\n forwardedHost,\n forwardedProto,\n requestOrigin,\n pageUrl,\n}: {\n host: string;\n forwardedHost: string | null;\n forwardedProto: string | null;\n requestOrigin: string | null;\n pageUrl: string;\n}) {\n const protocol =\n firstHeaderValue(forwardedProto) === \"http\" ? \"http\" : \"https\";\n const proxyHost = firstHeaderValue(forwardedHost) ?? host;\n const fallbackOrigin = `${protocol}://${proxyHost}`;\n const trustedOrigins = new Set([\n fallbackOrigin,\n parseOrigin(firstHeaderValue(requestOrigin)),\n ]);\n\n try {\n const parsedPageUrl = new URL(pageUrl);\n if (trustedOrigins.has(parsedPageUrl.origin)) {\n return {\n origin: parsedPageUrl.origin,\n cancelUrl: parsedPageUrl.toString(),\n };\n }\n } catch {\n // The server-derived fallback below remains the only trusted destination.\n }\n\n return { origin: fallbackOrigin, cancelUrl: fallbackOrigin };\n}\n"],
5
- "mappings": "AAAA,SAAS,iBAAiB,OAAsB;AAC9C,QAAM,aAAa,OAAO,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK;AAC9C,SAAO,aAAa,aAAa;AACnC;AAEA,SAAS,YAAY,OAAsB;AACzC,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,IAAI,IAAI,KAAK,EAAE;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,QAAM,WACJ,iBAAiB,cAAc,MAAM,SAAS,SAAS;AACzD,QAAM,YAAY,iBAAiB,aAAa,KAAK;AACrD,QAAM,iBAAiB,GAAG,QAAQ,MAAM,SAAS;AACjD,QAAM,iBAAiB,oBAAI,IAAI;AAAA,IAC7B;AAAA,IACA,YAAY,iBAAiB,aAAa,CAAC;AAAA,EAC7C,CAAC;AAED,MAAI;AACF,UAAM,gBAAgB,IAAI,IAAI,OAAO;AACrC,QAAI,eAAe,IAAI,cAAc,MAAM,GAAG;AAC5C,aAAO;AAAA,QACL,QAAQ,cAAc;AAAA,QACtB,WAAW,cAAc,SAAS;AAAA,MACpC;AAAA,IACF;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,SAAO,EAAE,QAAQ,gBAAgB,WAAW,eAAe;AAC7D;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../cart/storefront-urls.ts"],
4
- "sourcesContent": ["// Compat alias: sites scaffolded before the return-urls rename import\n// `@replohq/sdk/cart/storefront-urls` and their source never updates, so this\n// re-export must stay published for as long as those sites are live.\n// eslint-disable-next-line replo/no-export-from -- compat alias entrypoint: deployed site code imports this path and only a re-export can keep it resolving.\nexport { getReturnUrls as getStorefrontUrls } from \"./return-urls\";\n"],
5
- "mappings": "AAIA,SAA0B,qBAAyB;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/utils/cart-adjustments.ts"],
4
- "sourcesContent": ["import type {\n Cart,\n CartLine,\n CartLineAdjustment,\n CartLinePayload,\n} from \"../cart-types\";\n\ntype VariantPlanTotals = Map<string, { variantId: string; quantity: number }>;\n\nfunction totalKey(variantId: string, sellingPlanId: string | null): string {\n return `${variantId}::${sellingPlanId ?? \"\"}`;\n}\n\nfunction addToTotals(\n totals: VariantPlanTotals,\n variantId: string,\n sellingPlanId: string | null,\n delta: number,\n) {\n const key = totalKey(variantId, sellingPlanId);\n const entry = totals.get(key);\n if (entry) {\n entry.quantity += delta;\n } else {\n totals.set(key, { variantId, quantity: delta });\n }\n}\n\n// Shopify separates lines for the same variant + plan by custom properties\n// (two engravings, two lines), so quantities are summed per variant + plan \u2014\n// notices are variant-level, never per property-split line.\nfunction totalsFromCart(cart: Cart): VariantPlanTotals {\n const totals: VariantPlanTotals = new Map();\n for (const line of cart.lines) {\n if (!line.merchandise) {\n continue;\n }\n addToTotals(\n totals,\n line.merchandise.id,\n line.sellingPlanAllocation?.sellingPlan.id ?? null,\n line.quantity,\n );\n }\n return totals;\n}\n\nfunction diffTotals(\n intended: VariantPlanTotals,\n saved: VariantPlanTotals,\n): CartLineAdjustment[] {\n const adjustments: CartLineAdjustment[] = [];\n for (const [key, entry] of intended) {\n const appliedQuantity = saved.get(key)?.quantity ?? 0;\n if (appliedQuantity >= entry.quantity) {\n continue;\n }\n adjustments.push(\n appliedQuantity > 0\n ? {\n type: \"quantityClampedToStock\",\n variantId: entry.variantId,\n requested: entry.quantity,\n applied: appliedQuantity,\n }\n : { type: \"unavailableLineRemoved\", variantId: entry.variantId },\n );\n }\n return adjustments;\n}\n\n/**\n * Diff what an add intended against the cart the server saved, as\n * Shopify-style adjustment notices. Intent is built from the request's own\n * identity (variant id + selling plan) on top of the pre-mutation server\n * cart \u2014 never from the optimistic display cart, whose lines can lack\n * merchandise (query-cache miss) or a resolvable plan allocation and would\n * silently drop or misattribute the comparison. The write reconciles the\n * whole cart, so lines the shopper didn't touch are covered too.\n */\nexport function deriveAddToCartAdjustments({\n cartBeforeAdd,\n requestedLines,\n savedCart,\n}: {\n cartBeforeAdd: Cart;\n requestedLines: CartLinePayload[];\n savedCart: Cart;\n}): CartLineAdjustment[] {\n const intended = totalsFromCart(cartBeforeAdd);\n for (const line of requestedLines) {\n addToTotals(intended, line.id, line.sellingPlanId ?? null, line.quantity);\n }\n return diffTotals(intended, totalsFromCart(savedCart));\n}\n\n/**\n * Same diff for a line update. The intended totals move the edited line's\n * quantity to the requested selling plan \u2014 `undefined` keeps the line's\n * current plan, explicit `null` removes it (the resolver forwards the\n * requested plan, so a successful A\u2192B switch must not read as a removal).\n * A deliberate removal (quantity 0) intends nothing and reports nothing.\n */\nexport function deriveUpdateCartAdjustments({\n cartBeforeUpdate,\n editedLine,\n requestedQuantity,\n requestedSellingPlanId,\n savedCart,\n}: {\n cartBeforeUpdate: Cart;\n editedLine: CartLine;\n requestedQuantity: number;\n requestedSellingPlanId: string | null | undefined;\n savedCart: Cart;\n}): CartLineAdjustment[] {\n const variantId = editedLine.merchandise?.id;\n if (!variantId) {\n return [];\n }\n const currentPlanId =\n editedLine.sellingPlanAllocation?.sellingPlan.id ?? null;\n const intended = totalsFromCart(cartBeforeUpdate);\n addToTotals(intended, variantId, currentPlanId, -editedLine.quantity);\n if (requestedQuantity > 0) {\n const intendedPlanId =\n requestedSellingPlanId === undefined\n ? currentPlanId\n : requestedSellingPlanId;\n addToTotals(intended, variantId, intendedPlanId, requestedQuantity);\n }\n return diffTotals(intended, totalsFromCart(savedCart));\n}\n"],
5
- "mappings": "AASA,SAAS,SAAS,WAAmB,eAAsC;AACzE,SAAO,GAAG,SAAS,KAAK,iBAAiB,EAAE;AAC7C;AAEA,SAAS,YACP,QACA,WACA,eACA,OACA;AACA,QAAM,MAAM,SAAS,WAAW,aAAa;AAC7C,QAAM,QAAQ,OAAO,IAAI,GAAG;AAC5B,MAAI,OAAO;AACT,UAAM,YAAY;AAAA,EACpB,OAAO;AACL,WAAO,IAAI,KAAK,EAAE,WAAW,UAAU,MAAM,CAAC;AAAA,EAChD;AACF;AAKA,SAAS,eAAe,MAA+B;AACrD,QAAM,SAA4B,oBAAI,IAAI;AAC1C,aAAW,QAAQ,KAAK,OAAO;AAC7B,QAAI,CAAC,KAAK,aAAa;AACrB;AAAA,IACF;AACA;AAAA,MACE;AAAA,MACA,KAAK,YAAY;AAAA,MACjB,KAAK,uBAAuB,YAAY,MAAM;AAAA,MAC9C,KAAK;AAAA,IACP;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,WACP,UACA,OACsB;AACtB,QAAM,cAAoC,CAAC;AAC3C,aAAW,CAAC,KAAK,KAAK,KAAK,UAAU;AACnC,UAAM,kBAAkB,MAAM,IAAI,GAAG,GAAG,YAAY;AACpD,QAAI,mBAAmB,MAAM,UAAU;AACrC;AAAA,IACF;AACA,gBAAY;AAAA,MACV,kBAAkB,IACd;AAAA,QACE,MAAM;AAAA,QACN,WAAW,MAAM;AAAA,QACjB,WAAW,MAAM;AAAA,QACjB,SAAS;AAAA,MACX,IACA,EAAE,MAAM,0BAA0B,WAAW,MAAM,UAAU;AAAA,IACnE;AAAA,EACF;AACA,SAAO;AACT;AAWO,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF,GAIyB;AACvB,QAAM,WAAW,eAAe,aAAa;AAC7C,aAAW,QAAQ,gBAAgB;AACjC,gBAAY,UAAU,KAAK,IAAI,KAAK,iBAAiB,MAAM,KAAK,QAAQ;AAAA,EAC1E;AACA,SAAO,WAAW,UAAU,eAAe,SAAS,CAAC;AACvD;AASO,SAAS,4BAA4B;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMyB;AACvB,QAAM,YAAY,WAAW,aAAa;AAC1C,MAAI,CAAC,WAAW;AACd,WAAO,CAAC;AAAA,EACV;AACA,QAAM,gBACJ,WAAW,uBAAuB,YAAY,MAAM;AACtD,QAAM,WAAW,eAAe,gBAAgB;AAChD,cAAY,UAAU,WAAW,eAAe,CAAC,WAAW,QAAQ;AACpE,MAAI,oBAAoB,GAAG;AACzB,UAAM,iBACJ,2BAA2B,SACvB,gBACA;AACN,gBAAY,UAAU,WAAW,gBAAgB,iBAAiB;AAAA,EACpE;AACA,SAAO,WAAW,UAAU,eAAe,SAAS,CAAC;AACvD;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/utils/cart-analytics.ts"],
4
- "sourcesContent": ["import type { Cart, CartLineMerchandise } from \"../cart-types\";\n\nimport { fromMinorUnitsToMajorUnits } from \"schemas/money\";\n\nconst FALLBACK_CURRENCY_CODE = \"USD\";\n\n/**\n * The per-line payload every cart event carries. Cart amounts are integer\n * minor units; analytics sinks speak decimal major units, so the conversion\n * happens here, at the one boundary between the two.\n */\nexport function buildCartLineAnalyticsData({\n merchandise,\n quantity,\n currencyCode,\n}: {\n merchandise: CartLineMerchandise;\n quantity: number;\n currencyCode: string | undefined;\n}) {\n const analyticsCurrencyCode = currencyCode ?? FALLBACK_CURRENCY_CODE;\n return {\n productId: merchandise.product.id,\n variantId: merchandise.id,\n quantity,\n price: fromMinorUnitsToMajorUnits({\n amount: merchandise.price,\n currencyCode: analyticsCurrencyCode,\n }),\n currency: currencyCode,\n productTitle: merchandise.product.title,\n variantTitle: merchandise.title,\n };\n}\n\n/** The cart-view payload, built from whichever cart snapshot the caller passes. */\nexport function buildCartViewAnalyticsData(cart: Cart | null) {\n const lines = cart?.lines ?? [];\n const currencyCode = cart?.cost.currencyCode;\n const analyticsCurrencyCode = currencyCode ?? FALLBACK_CURRENCY_CODE;\n return {\n itemCount: lines.reduce((sum, line) => {\n return line.quantity > 0 ? sum + line.quantity : sum;\n }, 0),\n subtotal: fromMinorUnitsToMajorUnits({\n amount: lines.reduce((sum, line) => {\n return line.quantity > 0 && line.merchandise\n ? sum + line.merchandise.price * line.quantity\n : sum;\n }, 0),\n currencyCode: analyticsCurrencyCode,\n }),\n currency: currencyCode,\n lineItems: lines.flatMap((line) => {\n if (!line.merchandise) {\n return [];\n }\n return [\n buildCartLineAnalyticsData({\n merchandise: line.merchandise,\n quantity: line.quantity,\n currencyCode: analyticsCurrencyCode,\n }),\n ];\n }),\n };\n}\n"],
5
- "mappings": "AAEA,SAAS,kCAAkC;AAE3C,MAAM,yBAAyB;AAOxB,SAAS,2BAA2B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,wBAAwB,gBAAgB;AAC9C,SAAO;AAAA,IACL,WAAW,YAAY,QAAQ;AAAA,IAC/B,WAAW,YAAY;AAAA,IACvB;AAAA,IACA,OAAO,2BAA2B;AAAA,MAChC,QAAQ,YAAY;AAAA,MACpB,cAAc;AAAA,IAChB,CAAC;AAAA,IACD,UAAU;AAAA,IACV,cAAc,YAAY,QAAQ;AAAA,IAClC,cAAc,YAAY;AAAA,EAC5B;AACF;AAGO,SAAS,2BAA2B,MAAmB;AAC5D,QAAM,QAAQ,MAAM,SAAS,CAAC;AAC9B,QAAM,eAAe,MAAM,KAAK;AAChC,QAAM,wBAAwB,gBAAgB;AAC9C,SAAO;AAAA,IACL,WAAW,MAAM,OAAO,CAAC,KAAK,SAAS;AACrC,aAAO,KAAK,WAAW,IAAI,MAAM,KAAK,WAAW;AAAA,IACnD,GAAG,CAAC;AAAA,IACJ,UAAU,2BAA2B;AAAA,MACnC,QAAQ,MAAM,OAAO,CAAC,KAAK,SAAS;AAClC,eAAO,KAAK,WAAW,KAAK,KAAK,cAC7B,MAAM,KAAK,YAAY,QAAQ,KAAK,WACpC;AAAA,MACN,GAAG,CAAC;AAAA,MACJ,cAAc;AAAA,IAChB,CAAC;AAAA,IACD,UAAU;AAAA,IACV,WAAW,MAAM,QAAQ,CAAC,SAAS;AACjC,UAAI,CAAC,KAAK,aAAa;AACrB,eAAO,CAAC;AAAA,MACV;AACA,aAAO;AAAA,QACL,2BAA2B;AAAA,UACzB,aAAa,KAAK;AAAA,UAClB,UAAU,KAAK;AAAA,UACf,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA,EACH;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/utils/cart-error.ts"],
4
- "sourcesContent": ["import type { CartError, CartOperation } from \"../cart-provider\";\n\nimport { CanopyError } from \"../../lib/canopy-error\";\n\nexport class CartContextError extends CanopyError {}\n\nconst FALLBACK_MESSAGES: Record<CartOperation, string> = {\n add: \"Could not add to your cart. Please try again.\",\n update: \"Could not update your cart. Please try again.\",\n remove: \"Could not remove that item. Please try again.\",\n discount: \"Could not apply that discount. Please try again.\",\n};\n\n// Only the provider's own errors carry shopper-safe text; anything else (a\n// dropped request, a null action result) is technical and gets the fallback.\nexport function toCartError(\n operation: CartOperation,\n caught: unknown,\n): CartError {\n return {\n operation,\n message:\n caught instanceof CartContextError\n ? caught.message\n : FALLBACK_MESSAGES[operation],\n };\n}\n"],
5
- "mappings": "AAEA,SAAS,mBAAmB;AAErB,MAAM,yBAAyB,YAAY;AAAC;AAEnD,MAAM,oBAAmD;AAAA,EACvD,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,UAAU;AACZ;AAIO,SAAS,YACd,WACA,QACW;AACX,SAAO;AAAA,IACL;AAAA,IACA,SACE,kBAAkB,mBACd,OAAO,UACP,kBAAkB,SAAS;AAAA,EACnC;AACF;",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../cart/utils/cart-utils.ts"],
4
- "sourcesContent": ["import type { ReconciledCartLine } from \"../../gateways/canopy-api\";\nimport type { Cart, CartLine } from \"../cart-types\";\n\nimport { formatAmount } from \"schemas/money\";\n\nimport { CanopyError } from \"../../lib/canopy-error\";\nimport { getCartLinePricing } from \"./variant-to-cart-line\";\n\nclass CartReconciliationMismatchError extends CanopyError {}\n\nexport interface CartTotals {\n subtotal: number;\n discountAmount: number;\n totalSavings: number;\n total: number;\n}\n\n/**\n * Sum the final (post selling-plan) price of every line item in the cart.\n * This is the authoritative subtotal for cookie-based carts, which have no\n * server-computed cost to rely on.\n */\nexport function calculateLineItemsSubtotal(lineItems: CartLine[]): number {\n return lineItems.reduce(\n (sum, item) => sum + getCartLinePricing(item).finalPrice * item.quantity,\n 0,\n );\n}\n\n/**\n * Recompute a cart's cost from its line items. Cookie carts are their own source\n * of truth (no server roundtrip) and apply no discounts, so subtotal equals\n * total and there are no discount allocations. Without this the cost stays at\n * the 0 it was created with, and every consumer that trusts it (cart total,\n * checkout analytics) reports $0 for a priced cart.\n */\nexport function recalculateCartCost(cart: Cart): Cart {\n const subtotal = calculateLineItemsSubtotal(cart.lines);\n return {\n ...cart,\n cost: {\n ...cart.cost,\n subtotalAmount: subtotal,\n totalAmount: subtotal,\n },\n discountAllocations: [],\n };\n}\n\n/**\n * Rewrite a cookie cart with the catalog's current facts: live prices always,\n * unavailable lines dropped, and \u2014 on write paths only \u2014 quantities clamped to\n * the purchasable remainder. Reads never clamp (`clampQuantities: false`):\n * a quantity change without messaging is worse than one the mutation or\n * checkout path reports, mirroring Shopify's cart behavior.\n *\n * `reconciledLines` must be the catalog's answer for this cart's\n * merchandise-bearing lines in order \u2014 the shape reconcileCartLines returns.\n */\nexport function applyCartLineReconciliation(\n cart: Cart,\n reconciledLines: ReconciledCartLine[],\n { clampQuantities }: { clampQuantities: boolean },\n): Cart {\n let reconciledIndex = 0;\n const lines = cart.lines.flatMap((line) => {\n if (!line.merchandise) {\n return [line];\n }\n const catalogLine = reconciledLines[reconciledIndex];\n reconciledIndex += 1;\n if (!catalogLine || catalogLine.variantId !== line.merchandise.id) {\n throw new CartReconciliationMismatchError({\n message: \"Reconciled lines do not match the cart's lines\",\n additionalData: {\n cartId: cart.id,\n variantId: line.merchandise.id,\n reconciledVariantId: catalogLine?.variantId ?? null,\n },\n });\n }\n if (catalogLine.status === \"unavailable\") {\n return [];\n }\n const quantity = clampQuantities\n ? Math.min(line.quantity, catalogLine.purchasableQuantity)\n : line.quantity;\n if (quantity <= 0) {\n return [];\n }\n return [\n {\n ...line,\n quantity,\n merchandise: {\n ...line.merchandise,\n price: catalogLine.unitPriceMinor,\n compareAtPrice: catalogLine.compareAtPriceMinor,\n },\n },\n ];\n });\n return recalculateCartCost({ ...cart, lines });\n}\n\n/**\n * Calculate cart totals including subtotal, discounts, and final total.\n * When cart cost data is provided (from Shopify), uses the actual totalAmount\n * and sums the provider's discount allocations (automatic, code, and custom\n * discounts, at both line and cart level) for the discount amount.\n *\n * @param options - Object containing lineItems and cart\n * @param options.lineItems - Array of cart line items\n * @param options.cart - Optional cart data from Shopify (includes discount allocations)\n */\nexport function calculateCartTotals({\n lineItems,\n cart,\n}: {\n lineItems: CartLine[];\n cart: Cart | null;\n}): CartTotals {\n const lineItemSubtotal = calculateLineItemsSubtotal(lineItems);\n const compareAtSubtotal = lineItems.reduce((sum, item) => {\n return sum + getCartLinePricing(item).compareAtPrice * item.quantity;\n }, 0);\n\n // NOTE (Jasmine, 2026-07-22): Trust the provider's authoritative cost when\n // present. For Shopify this is the server-computed cart cost (including a\n // legitimate $0 when items aren't purchasable), which we must not\n // second-guess; cookie carts keep their cost truthful via\n // cookie-cart-persistence.ts.\n const total = cart?.cost.totalAmount ?? lineItemSubtotal;\n\n // Shopify folds line-level discounts into cost.subtotalAmount too, so the\n // cost gap can't be used; the allocations carry every applied discount.\n const discountAmount = (cart?.discountAllocations ?? []).reduce(\n (sum, allocation) => sum + allocation.discountedAmount,\n 0,\n );\n\n const totalSavings = compareAtSubtotal - total;\n\n return {\n subtotal: lineItemSubtotal,\n discountAmount,\n totalSavings,\n total,\n };\n}\n\n/**\n * @deprecated Back-compat shim kept for surface parity with canopy-sdk, so\n * sites migrating off `import { formatPrice } from\n * \"canopy-sdk/cart/utils/cart-utils\"` keep rendering with only the package\n * specifier renamed. It formats INTEGER MINOR UNITS \u2014 the units every cart\n * value uses (`calculateCartTotals`, `getCartLinePricing`, `CartCost`):\n * passing 1999 yields \"$19.99\", not \"$1,999.00\". New code should call\n * `formatAmount({ amount, currencyCode })` from `@replohq/sdk/money` directly.\n */\nexport function formatPrice(price: number, currency: string = \"USD\"): string {\n return formatAmount({ amount: price, currencyCode: currency });\n}\n\n/**\n * Validates and formats a Shopify selling plan ID to ensure it has the correct GID format.\n *\n * @param sellingPlanId - The selling plan ID to validate and format\n * @returns The formatted selling plan ID with GID prefix, or null if no ID provided\n */\nexport function formatSellingPlanId(\n sellingPlanId: string | null | undefined,\n): string | null {\n if (!sellingPlanId) {\n return null;\n }\n\n // Check if it already has the gid format\n if (sellingPlanId.startsWith(\"gid://shopify/SellingPlan/\")) {\n return sellingPlanId;\n }\n\n // If it doesn't have the gid format, prepend it\n return `gid://shopify/SellingPlan/${sellingPlanId}`;\n}\n"],
5
- "mappings": "AAGA,SAAS,oBAAoB;AAE7B,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AAEnC,MAAM,wCAAwC,YAAY;AAAC;AAcpD,SAAS,2BAA2B,WAA+B;AACxE,SAAO,UAAU;AAAA,IACf,CAAC,KAAK,SAAS,MAAM,mBAAmB,IAAI,EAAE,aAAa,KAAK;AAAA,IAChE;AAAA,EACF;AACF;AASO,SAAS,oBAAoB,MAAkB;AACpD,QAAM,WAAW,2BAA2B,KAAK,KAAK;AACtD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,MAAM;AAAA,MACJ,GAAG,KAAK;AAAA,MACR,gBAAgB;AAAA,MAChB,aAAa;AAAA,IACf;AAAA,IACA,qBAAqB,CAAC;AAAA,EACxB;AACF;AAYO,SAAS,4BACd,MACA,iBACA,EAAE,gBAAgB,GACZ;AACN,MAAI,kBAAkB;AACtB,QAAM,QAAQ,KAAK,MAAM,QAAQ,CAAC,SAAS;AACzC,QAAI,CAAC,KAAK,aAAa;AACrB,aAAO,CAAC,IAAI;AAAA,IACd;AACA,UAAM,cAAc,gBAAgB,eAAe;AACnD,uBAAmB;AACnB,QAAI,CAAC,eAAe,YAAY,cAAc,KAAK,YAAY,IAAI;AACjE,YAAM,IAAI,gCAAgC;AAAA,QACxC,SAAS;AAAA,QACT,gBAAgB;AAAA,UACd,QAAQ,KAAK;AAAA,UACb,WAAW,KAAK,YAAY;AAAA,UAC5B,qBAAqB,aAAa,aAAa;AAAA,QACjD;AAAA,MACF,CAAC;AAAA,IACH;AACA,QAAI,YAAY,WAAW,eAAe;AACxC,aAAO,CAAC;AAAA,IACV;AACA,UAAM,WAAW,kBACb,KAAK,IAAI,KAAK,UAAU,YAAY,mBAAmB,IACvD,KAAK;AACT,QAAI,YAAY,GAAG;AACjB,aAAO,CAAC;AAAA,IACV;AACA,WAAO;AAAA,MACL;AAAA,QACE,GAAG;AAAA,QACH;AAAA,QACA,aAAa;AAAA,UACX,GAAG,KAAK;AAAA,UACR,OAAO,YAAY;AAAA,UACnB,gBAAgB,YAAY;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAAC;AAC/C;AAYO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AACF,GAGe;AACb,QAAM,mBAAmB,2BAA2B,SAAS;AAC7D,QAAM,oBAAoB,UAAU,OAAO,CAAC,KAAK,SAAS;AACxD,WAAO,MAAM,mBAAmB,IAAI,EAAE,iBAAiB,KAAK;AAAA,EAC9D,GAAG,CAAC;AAOJ,QAAM,QAAQ,MAAM,KAAK,eAAe;AAIxC,QAAM,kBAAkB,MAAM,uBAAuB,CAAC,GAAG;AAAA,IACvD,CAAC,KAAK,eAAe,MAAM,WAAW;AAAA,IACtC;AAAA,EACF;AAEA,QAAM,eAAe,oBAAoB;AAEzC,SAAO;AAAA,IACL,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAWO,SAAS,YAAY,OAAe,WAAmB,OAAe;AAC3E,SAAO,aAAa,EAAE,QAAQ,OAAO,cAAc,SAAS,CAAC;AAC/D;AAQO,SAAS,oBACd,eACe;AACf,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,EACT;AAGA,MAAI,cAAc,WAAW,4BAA4B,GAAG;AAC1D,WAAO;AAAA,EACT;AAGA,SAAO,6BAA6B,aAAa;AACnD;",
6
- "names": []
7
- }