@ecomiq/storefront 2.1.3 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +150 -123
  3. package/dist/account-Dx4e3syi.js +258 -0
  4. package/dist/account-forms-AVk71ko7.js +39 -0
  5. package/dist/account-forms.d.ts +13 -0
  6. package/dist/account.d.ts +240 -0
  7. package/dist/address-defaults-BqjRhS82.js +14 -0
  8. package/dist/address-defaults.d.ts +11 -0
  9. package/dist/analytics/analytics-CG1Qagwl.js +148 -0
  10. package/dist/analytics/analytics.d.ts +1 -0
  11. package/dist/analytics/config-DJr-GRhs.js +62 -0
  12. package/dist/analytics/config.d.ts +22 -0
  13. package/dist/analytics/consent-B13rBpBs.js +57 -0
  14. package/dist/analytics/consent-banner-9QvRRy8v.js +239 -0
  15. package/dist/analytics/consent-banner.d.ts +20 -0
  16. package/dist/analytics/cookies-pLozllyB.js +100 -0
  17. package/dist/analytics/cookies.d.ts +6 -0
  18. package/dist/analytics/destinations-iECrlLIr.js +144 -0
  19. package/dist/analytics/events-Dt81tIp1.js +102 -0
  20. package/dist/analytics/events.d.ts +51 -0
  21. package/dist/analytics/tracker-p4yaoOyk.js +51 -0
  22. package/dist/api-cache-DsuIn5hX.js +159 -0
  23. package/dist/bank-accounts-DlEczQQ5.js +81 -0
  24. package/dist/bank-accounts.d.ts +4 -0
  25. package/dist/captcha-DAqaIx8m.js +117 -0
  26. package/dist/captcha.d.ts +34 -0
  27. package/dist/cart-D7DxZ2lD.js +30 -0
  28. package/dist/cart-actions-Bsub_FFG.js +116 -0
  29. package/dist/cart-actions.d.ts +15 -0
  30. package/dist/cart-drawer-B7PPsR69.js +22 -0
  31. package/dist/cart-drawer.d.ts +9 -0
  32. package/dist/cart-form-y9P1r_EX.js +81 -0
  33. package/dist/cart-form.d.ts +24 -0
  34. package/dist/cart-summary-ur2VWKr-.js +89 -0
  35. package/dist/cart-summary.d.ts +31 -0
  36. package/dist/cart.d.ts +4 -0
  37. package/dist/catalog-7gJ-l5hW.js +67 -0
  38. package/dist/catalog-hooks-B7ZP4wYY.js +312 -0
  39. package/dist/catalog-hooks.d.ts +111 -0
  40. package/dist/catalog.d.ts +5 -0
  41. package/dist/checkout-DVWSXANi.js +474 -0
  42. package/dist/checkout-form-CbOIdENC.js +131 -0
  43. package/dist/checkout-form.d.ts +20 -0
  44. package/dist/checkout.d.ts +86 -0
  45. package/dist/complaint-book-BvwLvfx0.js +117 -0
  46. package/dist/complaint-book.d.ts +62 -0
  47. package/dist/culqi-authentication-BGr20vAJ.js +204 -0
  48. package/dist/culqi-authentication.d.ts +15 -0
  49. package/dist/culqi-checkout-CTXpKgp_.js +55 -0
  50. package/dist/culqi-three-ds-HP3mfrvV.js +33 -0
  51. package/dist/culqi-three-ds.d.ts +29 -0
  52. package/dist/customer-avatar-CJXSDroK.js +12 -0
  53. package/dist/customer-avatar.d.ts +5 -0
  54. package/dist/customer-cookies-DHOgFAMV.js +45 -0
  55. package/dist/customer-csrf-C1oDX-Py.js +17 -0
  56. package/dist/customer-csrf.d.ts +3 -0
  57. package/dist/customer-document-fields-C1K-_DAD.js +70 -0
  58. package/dist/customer-document-fields.d.ts +9 -0
  59. package/dist/customer-login-form-C7AC6vXd.js +144 -0
  60. package/dist/customer-login-form.d.ts +17 -0
  61. package/dist/customer-registration-form-BEm_NEfP.js +93 -0
  62. package/dist/customer-registration-form.d.ts +8 -0
  63. package/dist/document-url-CGsAl5Tf.js +9 -0
  64. package/dist/documents-T1mzc_j8.js +38 -0
  65. package/dist/documents.d.ts +16 -0
  66. package/dist/entries/account.d.ts +11 -0
  67. package/dist/entries/account.js +10 -0
  68. package/dist/entries/analytics.d.ts +6 -0
  69. package/dist/entries/analytics.js +5 -0
  70. package/dist/entries/cart.d.ts +8 -0
  71. package/dist/entries/cart.js +7 -0
  72. package/dist/entries/checkout.d.ts +12 -0
  73. package/dist/entries/checkout.js +11 -0
  74. package/dist/entries/order.d.ts +11 -0
  75. package/dist/entries/order.js +11 -0
  76. package/dist/favicon-YpyhVJ9H.js +28 -0
  77. package/dist/favicon.d.ts +4 -0
  78. package/dist/form-BtQcbXlJ.js +18 -0
  79. package/dist/form-contracts-BNpHaTGJ.js +166 -0
  80. package/dist/form-contracts.d.ts +42 -0
  81. package/dist/form.d.ts +3 -0
  82. package/dist/hidden-CCWtOWKR.js +3 -0
  83. package/dist/hidden.d.ts +4 -0
  84. package/dist/index.d.ts +50 -0
  85. package/dist/index.js +50 -0
  86. package/dist/invoice-fields-BG0HjL6T.js +103 -0
  87. package/dist/invoice-fields.d.ts +39 -0
  88. package/dist/links-kFxBZfdb.js +96 -0
  89. package/dist/links.d.ts +21 -0
  90. package/dist/mercadopago-checkout-DC7RXa8k.js +27 -0
  91. package/dist/mercadopago-dialog-UTQev0MG.js +180 -0
  92. package/dist/mercadopago-dialog.d.ts +21 -0
  93. package/dist/money-DtGOtDri.js +32 -0
  94. package/dist/money.d.ts +1 -0
  95. package/dist/optimistic-cart-BveVOHuh.js +53 -0
  96. package/dist/optimistic-cart.d.ts +16 -0
  97. package/dist/order-display-DTt5WBbc.js +112 -0
  98. package/dist/order-display.d.ts +20 -0
  99. package/dist/order-draft-DxV1Uhm3.js +38 -0
  100. package/dist/order-draft.d.ts +16 -0
  101. package/dist/order-pages-Dm6l5m0m.js +38 -0
  102. package/dist/order-pages.d.ts +12 -0
  103. package/dist/order-payment-continuation-D_d5PGA4.js +212 -0
  104. package/dist/order-payment-continuation.d.ts +10 -0
  105. package/dist/order-payment-in-review-x4gdLFHZ.js +65 -0
  106. package/dist/order-payment-in-review.d.ts +5 -0
  107. package/dist/order-status-BJXLJwxq.js +162 -0
  108. package/dist/order-status.d.ts +89 -0
  109. package/dist/order-view-9IlBg5AF.js +62 -0
  110. package/dist/order-view.d.ts +12 -0
  111. package/dist/page-action-Ctkf4xC6.js +7 -0
  112. package/dist/page-seo-a5FJl8x5.js +262 -0
  113. package/dist/page-seo.d.ts +34 -0
  114. package/dist/pages-Ca_Gt6mq.js +150 -0
  115. package/dist/pages.d.ts +45 -0
  116. package/dist/payment-dialog-frame-B-Q_xQ94.js +57 -0
  117. package/dist/payment-logo-BoPaGJc_.js +46 -0
  118. package/dist/payment-logo-svgs-By9lDTLK.js +20 -0
  119. package/dist/payment-logo.d.ts +11 -0
  120. package/dist/payment-logos-BYvdwYyJ.js +23 -0
  121. package/dist/payment-methods-B8ocTgFZ.js +73 -0
  122. package/dist/payment-methods.d.ts +58 -0
  123. package/dist/payment-return-5cjypwIw.js +7 -0
  124. package/dist/place-CmW4hBWY.js +13 -0
  125. package/dist/place.d.ts +4 -0
  126. package/dist/preview-BiIBif3C.js +427 -0
  127. package/dist/preview-address-Cf0sJ-9p.js +21 -0
  128. package/dist/preview-cart-Dg2CVktS.js +376 -0
  129. package/dist/product-preview-BspMAecJ.js +51 -0
  130. package/dist/product-preview.d.ts +5 -0
  131. package/dist/product-variants-BNDHvs1y.js +46 -0
  132. package/dist/product-variants.d.ts +12 -0
  133. package/dist/public-pages-XtwlaLwt.js +194 -0
  134. package/dist/public-pages.d.ts +67 -0
  135. package/dist/registration-CpDcv8ql.js +91 -0
  136. package/dist/registration.d.ts +12 -0
  137. package/dist/request-security-CRsRMgwj.js +76 -0
  138. package/dist/rich-text-M-Ju8RL4.js +9 -0
  139. package/dist/rich-text.d.ts +5 -0
  140. package/dist/route-text-DcJw2SsK.js +9 -0
  141. package/dist/route-text.d.ts +4 -0
  142. package/dist/section-preview-CmsMl3yu.js +83 -0
  143. package/dist/section-preview.d.ts +12 -0
  144. package/dist/sections/account-addresses.d.ts +18 -0
  145. package/dist/sections/account-addresses.js +375 -0
  146. package/dist/sections/account-order.d.ts +12 -0
  147. package/dist/sections/account-order.js +592 -0
  148. package/dist/sections/account-orders.d.ts +8 -0
  149. package/dist/sections/account-orders.js +359 -0
  150. package/dist/sections/account-profile.d.ts +16 -0
  151. package/dist/sections/account-profile.js +123 -0
  152. package/dist/sections/checkout.d.ts +24 -0
  153. package/dist/sections/checkout.js +963 -0
  154. package/dist/sections/complaint-book.d.ts +8 -0
  155. package/dist/sections/complaint-book.js +538 -0
  156. package/dist/sections/design-system.d.ts +1 -0
  157. package/dist/sections/design-system.js +310 -0
  158. package/dist/sections/draft-invoice.d.ts +20 -0
  159. package/dist/sections/draft-invoice.js +158 -0
  160. package/dist/sections/order-tracking.d.ts +19 -0
  161. package/dist/sections/order-tracking.js +141 -0
  162. package/dist/sections-CNUMWTF_.js +77 -0
  163. package/dist/sections.d.ts +19 -0
  164. package/dist/seo-GpDRhAAA.js +78 -0
  165. package/dist/session-CKvmFJyg.js +379 -0
  166. package/dist/session.d.ts +24 -0
  167. package/dist/settings-B0NO2A6Y.js +78 -0
  168. package/dist/settings.d.ts +51 -0
  169. package/dist/source-marker-DhqSkW7n.js +4 -0
  170. package/dist/sources-B-3JFJfb.js +46 -0
  171. package/dist/sources.d.ts +7 -0
  172. package/dist/store-8Q-_LFrQ.js +152 -0
  173. package/dist/store-contact--hY6CoFb.js +19 -0
  174. package/dist/store-contact.d.ts +6 -0
  175. package/dist/store.d.ts +17 -0
  176. package/dist/storefront-language-DrMjVbmk.js +29 -0
  177. package/dist/storefront-language.d.ts +14 -0
  178. package/dist/storefront-text-D25ae1qf.js +11 -0
  179. package/dist/storefront-text-en-ljjjSS4q.js +1030 -0
  180. package/dist/storefront-text-pt-BtHaJLcp.js +1030 -0
  181. package/dist/storefront-text.d.ts +4 -0
  182. package/dist/stripe-dialog-Ev9s3Z62.js +396 -0
  183. package/dist/stripe-dialog.d.ts +30 -0
  184. package/dist/telemetry-HuZXWBPi.js +114 -0
  185. package/dist/telemetry.d.ts +10 -0
  186. package/dist/templates-CAqoNyTW.js +40 -0
  187. package/dist/templates.d.ts +15 -0
  188. package/dist/urls-CpGQPxvf.js +71 -0
  189. package/dist/urls.d.ts +18 -0
  190. package/dist/use-checkout-CZcxXJXi.js +42 -0
  191. package/dist/use-checkout-payment-9R-zacrJ.js +80 -0
  192. package/dist/use-checkout-payment.d.ts +18 -0
  193. package/dist/use-checkout.d.ts +36 -0
  194. package/dist/use-culqi-checkout-CrjLAipU.js +109 -0
  195. package/dist/use-order-payment-BKIz_IO0.js +45 -0
  196. package/dist/use-order-payment.d.ts +18 -0
  197. package/dist/use-payment-token-CErx-tN-.js +105 -0
  198. package/dist/vite-payment-logos-kziu7wKb.js +27 -0
  199. package/dist/vite-payment-logos.d.ts +24 -0
  200. package/dist/vite-public-assets-DW2fgtVb.js +209 -0
  201. package/dist/vite-public-assets.d.ts +29 -0
  202. package/dist/vite-sections-DTBr0-Kg.js +464 -0
  203. package/dist/vite-sections.d.ts +21 -0
  204. package/dist/vite-theme-ui-BMO-CDi3.js +41 -0
  205. package/dist/vite-theme-ui.d.ts +10 -0
  206. package/dist/vite.d.ts +36 -0
  207. package/dist/vite.js +127 -0
  208. package/dist/voucher-payment-CVFDZ1L8.js +66 -0
  209. package/dist/worker-CNi-gzCu.js +86 -0
  210. package/dist/worker.d.ts +27 -0
  211. package/package.json +100 -81
  212. package/src/sections/account-addresses.tsx +215 -0
  213. package/src/sections/account-order.tsx +424 -0
  214. package/src/sections/account-orders.tsx +259 -0
  215. package/src/sections/account-profile.tsx +70 -0
  216. package/src/sections/checkout.tsx +586 -0
  217. package/src/sections/complaint-book.tsx +325 -0
  218. package/src/sections/design-system.tsx +146 -0
  219. package/src/sections/draft-invoice.tsx +105 -0
  220. package/src/sections/order-tracking.tsx +81 -0
  221. package/src/vite-client.d.ts +4 -0
  222. package/bin/ecomiq.mjs +0 -179
  223. package/public/design-bridge.js +0 -318
  224. package/src/api-proxy.ts +0 -194
  225. package/src/auth/create-storefront-auth.ts +0 -94
  226. package/src/auth/ecomiq-oauth-password-client.ts +0 -26
  227. package/src/auth/ecomiq-oauth-password-constants.ts +0 -24
  228. package/src/auth/ecomiq-oauth-password-plugin.ts +0 -294
  229. package/src/auth/ecomiq-oauth-password-types.ts +0 -24
  230. package/src/auth/ecomiq-storefront-sign-in.ts +0 -44
  231. package/src/auth/env.ts +0 -7
  232. package/src/auth/secure-cookies.ts +0 -23
  233. package/src/auth/storefront-auth-base-url.ts +0 -117
  234. package/src/auth/storefront-auth.ts +0 -7
  235. package/src/cart-session.ts +0 -239
  236. package/src/client.ts +0 -48
  237. package/src/cloud-runtime-client.ts +0 -378
  238. package/src/codegen.mjs +0 -789
  239. package/src/components/account/customer-addresses-panel.tsx +0 -678
  240. package/src/components/account/customer-order-detail-panel.tsx +0 -285
  241. package/src/components/account/customer-orders-panel.tsx +0 -192
  242. package/src/components/account/customer-profile-panel.tsx +0 -379
  243. package/src/components/checkout/cart-sync.ts +0 -143
  244. package/src/components/checkout/checkout-contact-section.tsx +0 -76
  245. package/src/components/checkout/checkout-external-update-banner.tsx +0 -15
  246. package/src/components/checkout/checkout-form-controls.tsx +0 -139
  247. package/src/components/checkout/checkout-line-items.tsx +0 -43
  248. package/src/components/checkout/checkout-order-summary.tsx +0 -165
  249. package/src/components/checkout/checkout-payment-section.tsx +0 -212
  250. package/src/components/checkout/checkout-session-view.tsx +0 -564
  251. package/src/components/checkout/checkout-shipping-address-section.tsx +0 -400
  252. package/src/components/checkout/checkout-shipping-section.tsx +0 -98
  253. package/src/components/checkout/checkout-states.tsx +0 -73
  254. package/src/components/checkout/checkout-step-card.tsx +0 -101
  255. package/src/components/checkout/checkout-steps.ts +0 -111
  256. package/src/components/checkout/form-schema.ts +0 -281
  257. package/src/components/checkout/format.ts +0 -15
  258. package/src/components/checkout/index.ts +0 -5
  259. package/src/components/checkout/map-customer-to-checkout.ts +0 -188
  260. package/src/components/checkout/types.ts +0 -41
  261. package/src/components/checkout/use-checkout-customer-prefill.ts +0 -409
  262. package/src/components/checkout/use-checkout-geo.ts +0 -50
  263. package/src/components/checkout/use-checkout-session.ts +0 -640
  264. package/src/components/hero.tsx +0 -291
  265. package/src/config.d.ts +0 -94
  266. package/src/config.mjs +0 -146
  267. package/src/format-money.ts +0 -31
  268. package/src/health.ts +0 -90
  269. package/src/hooks/index.ts +0 -9
  270. package/src/hooks/recently-viewed.ts +0 -125
  271. package/src/index.ts +0 -354
  272. package/src/link.tsx +0 -2
  273. package/src/pages/account/account-page-skeleton.tsx +0 -69
  274. package/src/pages/account/account-page-view.tsx +0 -270
  275. package/src/pages/account/account-shell.tsx +0 -101
  276. package/src/pages/account/parse-account-route.ts +0 -36
  277. package/src/pages/account.tsx +0 -16
  278. package/src/pages/api.$.ts +0 -20
  279. package/src/pages/api.auth.$.ts +0 -16
  280. package/src/pages/checkout.$checkoutId.tsx +0 -60
  281. package/src/pages/checkout.tsx +0 -31
  282. package/src/pages/pages.$pageSlug.tsx +0 -111
  283. package/src/pages/thank-you.tsx +0 -53
  284. package/src/providers/auth.tsx +0 -96
  285. package/src/providers/cart.tsx +0 -275
  286. package/src/providers/ecomiq.ts +0 -137
  287. package/src/providers/index.ts +0 -26
  288. package/src/proxy-api.ts +0 -20
  289. package/src/public-config.ts +0 -24
  290. package/src/review-submission.ts +0 -89
  291. package/src/runtime/context.ts +0 -2
  292. package/src/runtime/default-layout.tsx +0 -64
  293. package/src/runtime/head.ts +0 -149
  294. package/src/runtime/page.tsx +0 -143
  295. package/src/runtime/postcss-browser-stub.mjs +0 -5
  296. package/src/server-config-store.ts +0 -35
  297. package/src/server.ts +0 -301
  298. package/src/storefront-definition/contract.ts +0 -1
  299. package/src/storefront-definition/data.ts +0 -188
  300. package/src/storefront-definition/index.ts +0 -2
  301. package/src/storefront-definition/renderer.tsx +0 -1481
  302. package/src/storefront-layout.ts +0 -59
  303. package/src/storefront-runtime.ts +0 -173
  304. package/src/styles.css +0 -97
  305. package/src/ui/badge.tsx +0 -32
  306. package/src/ui/button.tsx +0 -31
  307. package/src/ui/card.tsx +0 -31
  308. package/src/ui/carousel.tsx +0 -218
  309. package/src/ui/cn.ts +0 -6
  310. package/src/ui/index.ts +0 -8
  311. package/src/ui/separator.tsx +0 -6
  312. package/src/ui/skeleton.tsx +0 -6
  313. package/src/ui/storefront-error.tsx +0 -49
  314. package/src/utils.ts +0 -36
  315. package/src/vite-inline.mjs +0 -263
  316. package/templates/__root.tsx +0 -83
  317. package/templates/router.tsx +0 -19
@@ -1,239 +0,0 @@
1
- import {
2
- ApiError,
3
- type RemoveCartItemParams,
4
- type StorefrontCart,
5
- type StorefrontClient,
6
- type UpdateCartItemQuantityParams,
7
- } from '@ecomiq/core'
8
- import { z } from 'zod'
9
-
10
- type CartClient = Pick<StorefrontClient, 'getCart' | 'createCart' | 'addCartItem'>
11
-
12
- export interface LoadActiveCartInput {
13
- cartToken: string
14
- }
15
-
16
- export type ActiveCartLoadResult =
17
- | { ok: true; value: StorefrontCart | null }
18
- | {
19
- ok: false
20
- error: {
21
- kind: 'failed'
22
- message: string
23
- }
24
- }
25
-
26
- export type CartItemMutationResult =
27
- | { ok: true; value: StorefrontCart }
28
- | {
29
- ok: false
30
- error: {
31
- kind: 'cart-unavailable' | 'unavailable' | 'failed'
32
- message: string
33
- }
34
- }
35
-
36
- export interface AddProductToCartInput {
37
- cartToken?: string
38
- currencyCode: string
39
- variantId: string
40
- quantity: number
41
- }
42
-
43
- export interface AddProductToCartResult {
44
- cartToken: string
45
- cart: StorefrontCart
46
- created: boolean
47
- }
48
-
49
- export type ProductCartMutationResult =
50
- | { ok: true; value: AddProductToCartResult }
51
- | {
52
- ok: false
53
- error: {
54
- kind: 'unavailable' | 'failed'
55
- message: string
56
- }
57
- }
58
-
59
- const StorefrontProblemSchema = z.object({
60
- code: z.string().optional(),
61
- }).passthrough()
62
-
63
- function cartIsUnavailable(error: unknown) {
64
- if (!(error instanceof ApiError)) return false
65
- const problem = StorefrontProblemSchema.safeParse(error.body)
66
- if (!problem.success) return false
67
- if (error.status === 404 && problem.data.code === 'Carts.NotFound') return true
68
- return error.status === 400 && problem.data.code === 'Carts.NotActive'
69
- }
70
-
71
- function cartIsActive(cart: StorefrontCart) {
72
- return cart.status === 'inProgress' || cart.status === 'pending'
73
- }
74
-
75
- function cartItemMutationFailure(error: ApiError): CartItemMutationResult {
76
- if (cartIsUnavailable(error)) {
77
- return {
78
- ok: false,
79
- error: {
80
- kind: 'cart-unavailable',
81
- message: 'Este carrito ya no está disponible.',
82
- },
83
- }
84
- }
85
-
86
- const problem = StorefrontProblemSchema.safeParse(error.body)
87
- if (problem.success && problem.data.code === 'Catalog.InsufficientStock') {
88
- return {
89
- ok: false,
90
- error: {
91
- kind: 'unavailable',
92
- message: 'No hay stock suficiente para esa cantidad.',
93
- },
94
- }
95
- }
96
- if (problem.success && problem.data.code === 'Carts.ItemNotFound') {
97
- return {
98
- ok: false,
99
- error: {
100
- kind: 'unavailable',
101
- message: 'Este producto ya no está en el carrito.',
102
- },
103
- }
104
- }
105
-
106
- return {
107
- ok: false,
108
- error: {
109
- kind: 'failed',
110
- message: 'No pudimos actualizar el carrito. Inténtalo nuevamente.',
111
- },
112
- }
113
- }
114
-
115
- export async function loadActiveCart(
116
- client: Pick<StorefrontClient, 'getCart'>,
117
- input: LoadActiveCartInput,
118
- ): Promise<ActiveCartLoadResult> {
119
- try {
120
- const cart = await client.getCart({ cartToken: input.cartToken })
121
- return { ok: true as const, value: cartIsActive(cart) ? cart : null }
122
- } catch (error) {
123
- if (cartIsUnavailable(error)) return { ok: true as const, value: null }
124
- if (error instanceof ApiError) {
125
- return {
126
- ok: false,
127
- error: {
128
- kind: 'failed',
129
- message: 'No pudimos cargar el carrito. Inténtalo nuevamente.',
130
- },
131
- }
132
- }
133
- throw error
134
- }
135
- }
136
-
137
- export async function submitCartItemQuantity(
138
- client: Pick<StorefrontClient, 'updateCartItemQuantity'>,
139
- input: UpdateCartItemQuantityParams,
140
- ): Promise<CartItemMutationResult> {
141
- try {
142
- const cart = await client.updateCartItemQuantity(input)
143
- return { ok: true, value: cart }
144
- } catch (error) {
145
- if (!(error instanceof ApiError)) throw error
146
- return cartItemMutationFailure(error)
147
- }
148
- }
149
-
150
- export async function submitCartItemRemoval(
151
- client: Pick<StorefrontClient, 'updateCartItemQuantity'>,
152
- input: RemoveCartItemParams,
153
- ): Promise<CartItemMutationResult> {
154
- try {
155
- const cart = await client.updateCartItemQuantity({ ...input, quantity: 0 })
156
- return { ok: true, value: cart }
157
- } catch (error) {
158
- if (!(error instanceof ApiError)) throw error
159
- return cartItemMutationFailure(error)
160
- }
161
- }
162
-
163
- export async function addProductToCart(
164
- client: CartClient,
165
- input: AddProductToCartInput,
166
- ): Promise<AddProductToCartResult> {
167
- let current: StorefrontCart | undefined
168
- let created = false
169
-
170
- if (input.cartToken) {
171
- try {
172
- const persisted = await client.getCart({ cartToken: input.cartToken })
173
- if (cartIsActive(persisted)) current = persisted
174
- } catch (error) {
175
- if (!cartIsUnavailable(error)) throw error
176
- }
177
- }
178
-
179
- if (!current) {
180
- current = await client.createCart({ currencyCode: input.currencyCode })
181
- created = true
182
- }
183
-
184
- const add = (cartToken: string) => client.addCartItem({
185
- cartToken,
186
- variantId: input.variantId,
187
- quantity: input.quantity,
188
- })
189
-
190
- try {
191
- const cart = await add(current.token)
192
- return { cartToken: cart.token, cart, created }
193
- } catch (error) {
194
- if (!cartIsUnavailable(error)) throw error
195
- const replacement = await client.createCart({ currencyCode: input.currencyCode })
196
- const cart = await add(replacement.token)
197
- return { cartToken: cart.token, cart, created: true }
198
- }
199
- }
200
-
201
- export async function submitProductToCart(
202
- client: CartClient,
203
- input: AddProductToCartInput,
204
- ): Promise<ProductCartMutationResult> {
205
- try {
206
- return { ok: true, value: await addProductToCart(client, input) }
207
- } catch (error) {
208
- if (!(error instanceof ApiError)) throw error
209
-
210
- const problem = StorefrontProblemSchema.safeParse(error.body)
211
- const code = problem.success ? problem.data.code : undefined
212
- if (code === 'Catalog.InsufficientStock') {
213
- return {
214
- ok: false,
215
- error: {
216
- kind: 'unavailable',
217
- message: 'No hay stock suficiente para esa cantidad.',
218
- },
219
- }
220
- }
221
- if (code === 'Catalog.VariantNotFound') {
222
- return {
223
- ok: false,
224
- error: {
225
- kind: 'unavailable',
226
- message: 'Esta variante ya no está disponible.',
227
- },
228
- }
229
- }
230
-
231
- return {
232
- ok: false,
233
- error: {
234
- kind: 'failed',
235
- message: 'No pudimos actualizar el carrito. Inténtalo nuevamente.',
236
- },
237
- }
238
- }
239
- }
package/src/client.ts DELETED
@@ -1,48 +0,0 @@
1
- import {
2
- createClient as createCoreClient,
3
- type CreateApiOptions,
4
- type StorefrontClient,
5
- } from '@ecomiq/core/client'
6
- import { getServerConfig } from './server-config-store'
7
-
8
- let sharedClient: StorefrontClient | null = null
9
-
10
- /** Cliente storefront compartido (cache de settings incluido). */
11
- export function getStorefrontClient(options: CreateApiOptions = {}): StorefrontClient {
12
- if (!sharedClient) {
13
- const config = getServerConfig()
14
- const headers = {
15
- ...config.api?.headers,
16
- ...options.headers,
17
- }
18
- for (const key of Object.keys(headers)) {
19
- const lower = key.toLowerCase()
20
- if (lower === 'x-store-id' || lower === 'x-store-domain') delete headers[key]
21
- }
22
- sharedClient = createCoreClient({
23
- domain: config.domain,
24
- ...config.api,
25
- ...options,
26
- headers,
27
- })
28
- }
29
- return sharedClient
30
- }
31
-
32
- /** Invalida el singleton (tests / hot reload). */
33
- export function resetStorefrontClient(): void {
34
- sharedClient?.clearCache()
35
- sharedClient = null
36
- }
37
-
38
- /**
39
- * Cliente storefront. Domain y defaults de API salen del config de la tienda.
40
- *
41
- * ```ts
42
- * export const api = createClient()
43
- * const collections = await api.getCollections()
44
- * ```
45
- */
46
- export function createClient(_options: CreateApiOptions = {}): StorefrontClient {
47
- return getStorefrontClient(_options)
48
- }
@@ -1,378 +0,0 @@
1
- import { z } from 'zod'
2
- import { StorefrontDefinitionSchema } from '@ecomiq/storefront-definition'
3
-
4
- export const CloudRuntimeStoreSlugSchema = z
5
- .string()
6
- .trim()
7
- .min(2)
8
- .max(100)
9
- .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/)
10
-
11
- export const ActiveStorefrontRuntimeSchema = z
12
- .object({
13
- schemaVersion: z.literal(1),
14
- store: z
15
- .object({
16
- slug: CloudRuntimeStoreSlugSchema,
17
- })
18
- .strict(),
19
- environment: z
20
- .object({
21
- name: z.literal('production'),
22
- status: z.literal('ready'),
23
- })
24
- .strict(),
25
- publication: z
26
- .object({
27
- sequence: z.number().int().nonnegative(),
28
- releaseSequence: z.number().int().nonnegative(),
29
- publishedAt: z.string().datetime({ offset: true }),
30
- runtimeReleaseId: z.string().optional(),
31
- artifactDigest: z.string().optional(),
32
- })
33
- .strict(),
34
- definition: StorefrontDefinitionSchema,
35
- })
36
- .strict()
37
-
38
- export type ActiveStorefrontRuntime = z.infer<
39
- typeof ActiveStorefrontRuntimeSchema
40
- >
41
-
42
- export const EnvironmentPointerSchema = z
43
- .object({
44
- schemaVersion: z.literal(1),
45
- storeSlug: CloudRuntimeStoreSlugSchema,
46
- projectId: z.string().min(1),
47
- environmentId: z.string().min(1),
48
- generation: z.number().int().nonnegative(),
49
- releaseSequence: z.number().int().nonnegative(),
50
- deploymentSequence: z.number().int().nonnegative(),
51
- artifactDigest: z.string().min(1),
52
- artifactKey: z.string().min(1),
53
- manifestDigest: z.string().min(1),
54
- manifestKey: z.string().min(1),
55
- runtimeReleaseId: z.string().min(1),
56
- publishedAt: z.string().datetime({ offset: true }),
57
- cachePolicy: z
58
- .object({
59
- pointerMaxAgeSeconds: z.number().int().nonnegative(),
60
- staleIfErrorSeconds: z.number().int().nonnegative(),
61
- })
62
- .strict(),
63
- })
64
- .strict()
65
-
66
- export type EnvironmentPointer = z.infer<typeof EnvironmentPointerSchema>
67
-
68
- export type CloudRuntimeFetch = (
69
- input: RequestInfo | URL,
70
- init?: RequestInit,
71
- ) => Promise<Response>
72
-
73
- export interface CloudRuntimeClientOptions {
74
- baseUrl: string
75
- artifactBaseUrl?: string
76
- timeoutMs?: number
77
- cacheTtlMs?: number
78
- fetch?: CloudRuntimeFetch
79
- now?: () => number
80
- }
81
-
82
- interface RuntimeCacheEntry {
83
- value: ActiveStorefrontRuntime | null
84
- etag?: string
85
- expiresAt: number
86
- }
87
-
88
- export class CloudRuntimeResponseError extends Error {
89
- readonly status: number
90
-
91
- constructor(status: number) {
92
- super(`Cloud runtime respondió HTTP ${status}`)
93
- this.name = 'CloudRuntimeResponseError'
94
- this.status = status
95
- }
96
- }
97
-
98
- const DEFAULT_TIMEOUT_MS = 3_000
99
- const DEFAULT_CACHE_TTL_MS = 15_000
100
- const MAX_CACHE_ENTRIES = 100
101
-
102
- interface LastKnownGood {
103
- runtime: ActiveStorefrontRuntime
104
- generation: number
105
- }
106
-
107
- export class CloudRuntimeClient {
108
- readonly baseUrl: string
109
- readonly artifactBaseUrl: string | null
110
- readonly timeoutMs: number
111
- readonly cacheTtlMs: number
112
-
113
- private readonly fetchRuntime: CloudRuntimeFetch
114
- private readonly now: () => number
115
- private readonly cache = new Map<string, RuntimeCacheEntry>()
116
- private readonly lastKnownGood = new Map<string, LastKnownGood>()
117
- private readonly artifactCache = new Map<string, ActiveStorefrontRuntime>()
118
- private readonly inFlight = new Map<
119
- string,
120
- Promise<ActiveStorefrontRuntime | null>
121
- >()
122
-
123
- constructor(options: CloudRuntimeClientOptions) {
124
- this.baseUrl = new URL(options.baseUrl).toString().replace(/\/$/, '')
125
- this.artifactBaseUrl = options.artifactBaseUrl
126
- ? new URL(options.artifactBaseUrl).toString().replace(/\/$/, '')
127
- : null
128
- this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS
129
- this.cacheTtlMs = options.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS
130
- this.fetchRuntime = options.fetch ?? globalThis.fetch
131
- this.now = options.now ?? Date.now
132
- }
133
-
134
- async resolveActiveStorefront(
135
- storeSlugInput: string,
136
- ): Promise<ActiveStorefrontRuntime | null> {
137
- const storeSlug = CloudRuntimeStoreSlugSchema.parse(storeSlugInput)
138
- const cached = this.cache.get(storeSlug)
139
- if (cached && cached.expiresAt > this.now()) {
140
- return cached.value
141
- }
142
-
143
- const activeRequest = this.inFlight.get(storeSlug)
144
- if (activeRequest) return activeRequest
145
-
146
- const request = (
147
- this.artifactBaseUrl
148
- ? this.requestFromArtifactStore(storeSlug)
149
- : this.requestActiveStorefront(storeSlug, cached)
150
- ).finally(() => {
151
- this.inFlight.delete(storeSlug)
152
- })
153
- this.inFlight.set(storeSlug, request)
154
- return request
155
- }
156
-
157
- clearCache(): void {
158
- this.cache.clear()
159
- this.lastKnownGood.clear()
160
- this.artifactCache.clear()
161
- this.inFlight.clear()
162
- }
163
-
164
- private async requestFromArtifactStore(
165
- storeSlug: string,
166
- ): Promise<ActiveStorefrontRuntime | null> {
167
- const survivor = this.lastKnownGood.get(storeSlug)
168
- let pointer: EnvironmentPointer | null
169
- try {
170
- pointer = await this.fetchPointer(storeSlug)
171
- } catch {
172
- if (survivor) return survivor.runtime
173
- throw new CloudRuntimeResponseError(503)
174
- }
175
-
176
- if (pointer === null) {
177
- if (survivor) return survivor.runtime
178
- this.setCache(storeSlug, {
179
- value: null,
180
- expiresAt: this.now() + this.cacheTtlMs,
181
- })
182
- return null
183
- }
184
-
185
- if (survivor && pointer.generation < survivor.generation) {
186
- this.setCache(storeSlug, {
187
- value: survivor.runtime,
188
- expiresAt: this.now() + this.cacheTtlMs,
189
- })
190
- return survivor.runtime
191
- }
192
-
193
- let runtime: ActiveStorefrontRuntime
194
- try {
195
- runtime = await this.fetchArtifactRuntime(pointer)
196
- } catch {
197
- if (survivor) return survivor.runtime
198
- throw new CloudRuntimeResponseError(503)
199
- }
200
-
201
- if (runtime.store.slug !== storeSlug) {
202
- throw new Error(
203
- `El pointer de ${storeSlug} apunta a un artifact de ${runtime.store.slug}`,
204
- )
205
- }
206
-
207
- const ttlMs = pointer.cachePolicy.pointerMaxAgeSeconds * 1_000
208
- this.setCache(storeSlug, {
209
- value: runtime,
210
- expiresAt: this.now() + (ttlMs > 0 ? ttlMs : this.cacheTtlMs),
211
- })
212
- this.lastKnownGood.set(storeSlug, {
213
- runtime,
214
- generation: pointer.generation,
215
- })
216
- return runtime
217
- }
218
-
219
- private async fetchPointer(
220
- storeSlug: string,
221
- ): Promise<EnvironmentPointer | null> {
222
- const response = await this.fetchWithTimeout(
223
- `${this.artifactBaseUrl}/stores/${encodeURIComponent(storeSlug)}/pointer.json`,
224
- )
225
- if (response.status === 404) return null
226
- if (!response.ok) throw new CloudRuntimeResponseError(response.status)
227
- return EnvironmentPointerSchema.parse(await response.json())
228
- }
229
-
230
- private async fetchArtifactRuntime(
231
- pointer: EnvironmentPointer,
232
- ): Promise<ActiveStorefrontRuntime> {
233
- const cached = this.artifactCache.get(pointer.artifactKey)
234
- const base =
235
- cached ?? (await this.requestArtifactBody(pointer.artifactKey))
236
- if (!cached) {
237
- if (this.artifactCache.size >= MAX_CACHE_ENTRIES) {
238
- const oldestKey = this.artifactCache.keys().next().value
239
- if (oldestKey !== undefined) this.artifactCache.delete(oldestKey)
240
- }
241
- this.artifactCache.set(pointer.artifactKey, base)
242
- }
243
- return {
244
- ...base,
245
- publication: {
246
- sequence: pointer.deploymentSequence,
247
- releaseSequence: pointer.releaseSequence,
248
- publishedAt: pointer.publishedAt,
249
- runtimeReleaseId: pointer.runtimeReleaseId,
250
- artifactDigest: pointer.artifactDigest,
251
- },
252
- }
253
- }
254
-
255
- private async requestArtifactBody(
256
- artifactKey: string,
257
- ): Promise<ActiveStorefrontRuntime> {
258
- const response = await this.fetchWithTimeout(
259
- `${this.artifactBaseUrl}/${artifactKey}`,
260
- )
261
- if (!response.ok) throw new CloudRuntimeResponseError(response.status)
262
- return ActiveStorefrontRuntimeSchema.parse(await response.json())
263
- }
264
-
265
- private async fetchWithTimeout(url: string): Promise<Response> {
266
- const controller = new AbortController()
267
- const timeout = setTimeout(() => controller.abort(), this.timeoutMs)
268
- try {
269
- return await this.fetchRuntime(url, {
270
- method: 'GET',
271
- headers: { accept: 'application/json' },
272
- signal: controller.signal,
273
- })
274
- } finally {
275
- clearTimeout(timeout)
276
- }
277
- }
278
-
279
- private setCache(storeSlug: string, entry: RuntimeCacheEntry): void {
280
- if (!this.cache.has(storeSlug) && this.cache.size >= MAX_CACHE_ENTRIES) {
281
- const oldestKey = this.cache.keys().next().value
282
- if (oldestKey !== undefined) this.cache.delete(oldestKey)
283
- }
284
- this.cache.set(storeSlug, entry)
285
- }
286
-
287
- private async requestActiveStorefront(
288
- storeSlug: string,
289
- cached?: RuntimeCacheEntry,
290
- ): Promise<ActiveStorefrontRuntime | null> {
291
- const controller = new AbortController()
292
- const timeout = setTimeout(() => controller.abort(), this.timeoutMs)
293
- const headers = new Headers({ accept: 'application/json' })
294
- if (cached?.etag) headers.set('if-none-match', cached.etag)
295
-
296
- try {
297
- const response = await this.fetchRuntime(
298
- new URL(
299
- `/v1/runtime/storefronts/${encodeURIComponent(storeSlug)}`,
300
- this.baseUrl,
301
- ),
302
- {
303
- method: 'GET',
304
- headers,
305
- signal: controller.signal,
306
- },
307
- )
308
-
309
- if (response.status === 304) {
310
- if (!cached) throw new CloudRuntimeResponseError(304)
311
- this.setCache(storeSlug, {
312
- ...cached,
313
- expiresAt: this.now() + this.cacheTtlMs,
314
- })
315
- return cached.value
316
- }
317
-
318
- if (response.status === 404) {
319
- this.setCache(storeSlug, {
320
- value: null,
321
- etag: response.headers.get('etag') ?? undefined,
322
- expiresAt: this.now() + this.cacheTtlMs,
323
- })
324
- return null
325
- }
326
-
327
- if (!response.ok) {
328
- throw new CloudRuntimeResponseError(response.status)
329
- }
330
-
331
- const runtime = ActiveStorefrontRuntimeSchema.parse(
332
- await response.json(),
333
- )
334
- if (runtime.store.slug !== storeSlug) {
335
- throw new Error(
336
- `Cloud runtime devolvió el store slug ${runtime.store.slug} para ${storeSlug}`,
337
- )
338
- }
339
-
340
- this.setCache(storeSlug, {
341
- value: runtime,
342
- etag: response.headers.get('etag') ?? undefined,
343
- expiresAt: this.now() + this.cacheTtlMs,
344
- })
345
- return runtime
346
- } finally {
347
- clearTimeout(timeout)
348
- }
349
- }
350
- }
351
-
352
- const sharedClients = new Map<string, CloudRuntimeClient>()
353
-
354
- export function getCloudRuntimeClient(
355
- options: Omit<CloudRuntimeClientOptions, 'fetch' | 'now'>,
356
- ): CloudRuntimeClient {
357
- const key = [
358
- new URL(options.baseUrl).toString(),
359
- options.artifactBaseUrl ? new URL(options.artifactBaseUrl).toString() : '',
360
- options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
361
- options.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS,
362
- ].join('|')
363
- const current = sharedClients.get(key)
364
- if (current) return current
365
-
366
- const client = new CloudRuntimeClient(options)
367
- if (sharedClients.size >= 8) {
368
- const oldestKey = sharedClients.keys().next().value
369
- if (oldestKey !== undefined) sharedClients.delete(oldestKey)
370
- }
371
- sharedClients.set(key, client)
372
- return client
373
- }
374
-
375
- export function resetCloudRuntimeClients(): void {
376
- for (const client of sharedClients.values()) client.clearCache()
377
- sharedClients.clear()
378
- }