@ecomiq/storefront 2.1.4 → 3.0.1

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 (310) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +377 -76
  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 -76
  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/codegen.mjs +0 -801
  238. package/src/components/account/customer-addresses-panel.tsx +0 -678
  239. package/src/components/account/customer-order-detail-panel.tsx +0 -285
  240. package/src/components/account/customer-orders-panel.tsx +0 -192
  241. package/src/components/account/customer-profile-panel.tsx +0 -379
  242. package/src/components/checkout/cart-sync.ts +0 -143
  243. package/src/components/checkout/checkout-contact-section.tsx +0 -76
  244. package/src/components/checkout/checkout-external-update-banner.tsx +0 -15
  245. package/src/components/checkout/checkout-form-controls.tsx +0 -139
  246. package/src/components/checkout/checkout-line-items.tsx +0 -43
  247. package/src/components/checkout/checkout-order-summary.tsx +0 -165
  248. package/src/components/checkout/checkout-payment-section.tsx +0 -212
  249. package/src/components/checkout/checkout-session-view.tsx +0 -564
  250. package/src/components/checkout/checkout-shipping-address-section.tsx +0 -400
  251. package/src/components/checkout/checkout-shipping-section.tsx +0 -98
  252. package/src/components/checkout/checkout-states.tsx +0 -73
  253. package/src/components/checkout/checkout-step-card.tsx +0 -101
  254. package/src/components/checkout/checkout-steps.ts +0 -111
  255. package/src/components/checkout/form-schema.ts +0 -281
  256. package/src/components/checkout/format.ts +0 -15
  257. package/src/components/checkout/index.ts +0 -5
  258. package/src/components/checkout/map-customer-to-checkout.ts +0 -188
  259. package/src/components/checkout/types.ts +0 -41
  260. package/src/components/checkout/use-checkout-customer-prefill.ts +0 -409
  261. package/src/components/checkout/use-checkout-geo.ts +0 -50
  262. package/src/components/checkout/use-checkout-session.ts +0 -640
  263. package/src/components/hero.tsx +0 -291
  264. package/src/config.d.ts +0 -94
  265. package/src/config.mjs +0 -146
  266. package/src/format-money.ts +0 -31
  267. package/src/health.ts +0 -90
  268. package/src/hooks/index.ts +0 -9
  269. package/src/hooks/recently-viewed.ts +0 -125
  270. package/src/index.ts +0 -349
  271. package/src/link.tsx +0 -2
  272. package/src/pages/account/account-page-skeleton.tsx +0 -69
  273. package/src/pages/account/account-page-view.tsx +0 -270
  274. package/src/pages/account/account-shell.tsx +0 -101
  275. package/src/pages/account/parse-account-route.ts +0 -36
  276. package/src/pages/account.tsx +0 -16
  277. package/src/pages/api.$.ts +0 -20
  278. package/src/pages/api.auth.$.ts +0 -16
  279. package/src/pages/checkout.$checkoutId.tsx +0 -60
  280. package/src/pages/checkout.tsx +0 -31
  281. package/src/pages/pages.$pageSlug.tsx +0 -74
  282. package/src/pages/thank-you.tsx +0 -53
  283. package/src/providers/auth.tsx +0 -96
  284. package/src/providers/cart.tsx +0 -275
  285. package/src/providers/ecomiq.ts +0 -137
  286. package/src/providers/index.ts +0 -26
  287. package/src/proxy-api.ts +0 -20
  288. package/src/public-config.ts +0 -24
  289. package/src/review-submission.ts +0 -89
  290. package/src/runtime/context.ts +0 -2
  291. package/src/runtime/default-layout.tsx +0 -64
  292. package/src/runtime/head.ts +0 -149
  293. package/src/runtime/page.tsx +0 -143
  294. package/src/runtime/postcss-browser-stub.mjs +0 -5
  295. package/src/server-config-store.ts +0 -35
  296. package/src/server.ts +0 -286
  297. package/src/styles.css +0 -76
  298. package/src/ui/badge.tsx +0 -32
  299. package/src/ui/button.tsx +0 -31
  300. package/src/ui/card.tsx +0 -31
  301. package/src/ui/carousel.tsx +0 -218
  302. package/src/ui/cn.ts +0 -6
  303. package/src/ui/index.ts +0 -8
  304. package/src/ui/separator.tsx +0 -6
  305. package/src/ui/skeleton.tsx +0 -6
  306. package/src/ui/storefront-error.tsx +0 -49
  307. package/src/utils.ts +0 -36
  308. package/src/vite-inline.mjs +0 -263
  309. package/templates/__root.tsx +0 -83
  310. package/templates/router.tsx +0 -19
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ecomiq
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,113 +1,414 @@
1
1
  # @ecomiq/storefront
2
2
 
3
- Micro framework SSR de Ecomiq para storefronts. Páginas, datos y deploy sin
4
- configurar TanStack Start, Vite ni Cloudflare a mano.
3
+ SDK de temas de Ecomiq para React Router 8. Trae los loaders y actions de
4
+ catálogo, carrito, checkout y cuenta de cliente, las secciones editables y los
5
+ plugins de Vite que corren la tienda en un Worker de Cloudflare. Los datos
6
+ vienen de tu tienda en Ecomiq; el diseño es tuyo.
5
7
 
6
- ## Instalación
8
+ - [Empezar](#empezar)
9
+ - [Archivos de la plataforma](#archivos-de-la-plataforma)
10
+ - [Entradas del paquete](#entradas-del-paquete)
11
+ - [Uso básico](#uso-básico)
12
+ - [Login de clientes](#login-de-clientes)
13
+ - [Registro de clientes](#registro-de-clientes)
14
+ - [Enlaces de catálogo](#enlaces-de-catálogo)
15
+ - [Logos de medios de pago](#logos-de-medios-de-pago)
16
+ - [Medición y consentimiento](#medición-y-consentimiento)
17
+ - [Secciones de Ecomiq](#secciones-de-ecomiq)
18
+ - [Temas publicados](#temas-publicados)
19
+
20
+ ## Empezar
21
+
22
+ La forma más corta es bajar el código de tu tienda, que ya trae este paquete:
23
+
24
+ ```bash
25
+ npm create ecomiq@latest mi-tienda
26
+ cd mi-tienda && npm install
27
+ npx ecomiq dev
28
+ ```
29
+
30
+ Para agregarlo a un proyecto React Router existente:
7
31
 
8
32
  ```bash
9
- npm install @ecomiq/storefront
10
- # o
11
- yarn add @ecomiq/storefront
12
- # o
13
- pnpm add @ecomiq/storefront
33
+ npm install @ecomiq/storefront @ecomiq/core react react-dom react-router
14
34
  ```
15
35
 
16
- Peer deps: `react` y `react-dom` ^19.
36
+ | Requisito | Versión |
37
+ | ------------ | ---------------------------------------------- |
38
+ | Node.js | 22.22 o superior |
39
+ | React | 19 |
40
+ | React Router | 8, en modo framework con SSR |
41
+ | Runtime | Cloudflare Workers (`@cloudflare/vite-plugin`) |
42
+
43
+ `react` y `react-router` son dependencias peer: el SDK usa las del tema.
44
+
45
+ Guía completa: <https://docs.ecomiq.pe/es/docs/guides/storefront/themes>
46
+
47
+ ## Archivos de la plataforma
17
48
 
18
- ## Uso
49
+ `ecomiq init` y el editor de Ecomiq escriben estos archivos; no los edites en
50
+ un tema.
19
51
 
20
- ```js
21
- // ecomiq.config.js
22
- import { defineConfig } from '@ecomiq/storefront/config'
52
+ ```ts title="vite.config.ts"
53
+ import { publicAssets, catalogLinks, paymentLogos, sectionLoaders, themeUi } from "@ecomiq/storefront/vite";
54
+ import { fileURLToPath } from "node:url";
55
+ import { cloudflare } from "@cloudflare/vite-plugin";
56
+ import { reactRouter } from "@react-router/dev/vite";
57
+ import tailwindcss from "@tailwindcss/vite";
58
+ import { defineConfig } from "vite";
23
59
 
24
60
  export default defineConfig({
25
- domain: 'mi-tienda',
26
- // Server-only. Obligatorio en producción para usar una publicación de Cloud.
27
- cloud: { baseUrl: 'https://cloud.internal.example' },
28
- })
61
+ plugins: [publicAssets(), catalogLinks(), sectionLoaders(), paymentLogos(), themeUi(), cloudflare({ viteEnvironment: { name: "ssr" } }), tailwindcss(), reactRouter()],
62
+ resolve: { alias: { "~": fileURLToPath(new URL("./app", import.meta.url)) } },
63
+ build: { rolldownOptions: { output: { codeSplitting: { groups: [{ name: "icons", test: /[\\/]node_modules[\\/](?:@phosphor-icons|@heroicons|@mdi|@remixicon|lucide-react|iconoir-react)[\\/]/ }] } } } },
64
+ });
29
65
  ```
30
66
 
31
- ```tsx
32
- // pages/index.tsx
33
- import { definePage, serverApi } from '@ecomiq/storefront'
67
+ ```ts title="workers/app.ts"
68
+ import { createRequestHandler } from "@ecomiq/storefront";
34
69
 
35
- export default definePage({
36
- loader: () => serverApi.getProducts({ page: 1, pageSize: 12 }),
37
- component: ({ data }) => <pre>{JSON.stringify(data.products, null, 2)}</pre>,
38
- })
70
+ export default createRequestHandler(() => import("virtual:react-router/server-build"), import.meta.env.MODE);
39
71
  ```
40
72
 
41
- CLI:
73
+ `wrangler.jsonc` define la tienda en `vars`: `ECOMIQ_STORE` (el slug) y
74
+ `ECOMIQ_API_URL` (la API Storefront, `https://storefront.ecomiq.pe`). Los tipos
75
+ de los módulos virtuales del SDK se cargan con
76
+ `/// <reference types="@ecomiq/storefront/vite-client" />`.
42
77
 
43
- ```bash
44
- npx ecomiq dev
45
- npx ecomiq build
46
- npx ecomiq deploy
78
+ | Plugin | Qué hace |
79
+ | ------------------ | ----------------------------------------------------------------------------------------------------------- |
80
+ | `publicAssets()` | Versiona las imágenes y fuentes de `public/` y, al compilar, genera sus anchos en WebP. |
81
+ | `catalogLinks()` | Genera `virtual:ecomiq-links` con los enlaces editables del tema. |
82
+ | `sectionLoaders()` | Suma al loader de cada ruta el `load` de las secciones que usa y aplica las plantillas de `app/templates/`. |
83
+ | `paymentLogos()` | Escribe los SVG de medios de pago en el build. |
84
+ | `themeUi()` | Lleva `@theme/ui/*` a `app/components/ui/*` del tema. |
85
+
86
+ ## Entradas del paquete
87
+
88
+ | Import | Para qué |
89
+ | ---------------------------------- | ---------------------------------------------------------------- |
90
+ | `@ecomiq/storefront` | Cliente de la tienda, loaders de páginas, sesión, enlaces y SEO. |
91
+ | `@ecomiq/storefront/vite` | Plugins de Vite. |
92
+ | `@ecomiq/storefront/cart` | Carrito: `CartForm`, `useCart`, drawer y carrito optimista. |
93
+ | `@ecomiq/storefront/checkout` | Checkout, medios de pago y comprobante. |
94
+ | `@ecomiq/storefront/account` | Cuenta: pedidos, direcciones y perfil. |
95
+ | `@ecomiq/storefront/order` | Estado y pago de un pedido. |
96
+ | `@ecomiq/storefront/analytics` | Medición, píxeles y aviso de consentimiento. |
97
+ | `@ecomiq/storefront/sections/<id>` | [Secciones de Ecomiq](#secciones-de-ecomiq) listas para usar. |
98
+ | `@ecomiq/storefront/vite-client` | Tipos de los módulos virtuales. |
99
+
100
+ ## Uso básico
101
+
102
+ ### Loader raíz
103
+
104
+ `store(context)` devuelve el cliente de la tienda configurada en el Worker.
105
+ `readStorefrontLayout` lee la configuración, las colecciones y los enlaces del
106
+ tema en una sola pasada.
107
+
108
+ ```tsx title="app/root.tsx"
109
+ import manifestLinks from "virtual:ecomiq-links";
110
+ import { readCart, readStorefrontLayout, store } from "@ecomiq/storefront";
111
+ import { readAnalytics } from "@ecomiq/storefront/analytics";
112
+ import type { Route } from "./+types/root";
113
+
114
+ export { shouldRevalidateCatalogRoot as shouldRevalidate } from "@ecomiq/storefront";
115
+
116
+ export async function loader({ request, context }: Route.LoaderArgs) {
117
+ const client = store(context);
118
+ const [{ settings, storefrontLinks }, cart] = await Promise.all([
119
+ readStorefrontLayout({ client, links: manifestLinks }),
120
+ readCart(request, client),
121
+ ]);
122
+ return {
123
+ storefrontLinks,
124
+ publishedPages: settings.cms.pages.map((page) => `/pages/${page.slug}`),
125
+ analytics: readAnalytics(context, settings, cart),
126
+ cart,
127
+ };
128
+ }
47
129
  ```
48
130
 
49
- Si actualizas el package y `.ecomiq` quedó de una versión anterior:
131
+ ### Una sección editable
50
132
 
51
- ```bash
52
- npx ecomiq clean
53
- npx ecomiq dev
133
+ Una sección exporta `settings` con lo que el comerciante cambia en el editor.
134
+ El loader de la ruta lee esos ajustes; nunca escribas a mano precios, stock ni
135
+ productos.
136
+
137
+ ```tsx title="app/components/sections/new-arrivals.tsx"
138
+ import type { ProductSummary } from "@ecomiq/core";
139
+ import { money, setting, StorefrontLink } from "@ecomiq/storefront";
140
+
141
+ export const settings = {
142
+ arrivals: {
143
+ title: setting.text("Recién llegados", "Título"),
144
+ collection: setting.collection("novedades", "Colección"),
145
+ limit: setting.number(8, "Cantidad"),
146
+ link: setting.link("/collections/novedades", "Enlace"),
147
+ },
148
+ };
149
+
150
+ type Props = { products: ProductSummary[]; currency: string; language: string };
151
+
152
+ export function NewArrivals({ products, currency, language }: Props) {
153
+ return (
154
+ <section>
155
+ <h2>{settings.arrivals.title}</h2>
156
+ <StorefrontLink to={settings.arrivals.link}>Ver todo</StorefrontLink>
157
+ <ul>
158
+ {products.map((product) => (
159
+ <li key={product.id}>
160
+ {product.name} · {money(product.price, currency, language)}
161
+ </li>
162
+ ))}
163
+ </ul>
164
+ </section>
165
+ );
166
+ }
54
167
  ```
55
168
 
56
- ### Runtime de desarrollo
169
+ ```tsx title="app/routes/home.tsx"
170
+ import { pickProducts, store } from "@ecomiq/storefront";
171
+ import { NewArrivals, settings } from "~/components/sections/new-arrivals";
172
+ import type { Route } from "./+types/home";
57
173
 
58
- `ecomiq dev` usa **Node** por defecto. Para emular Workers en local:
174
+ export async function loader({ context }: Route.LoaderArgs) {
175
+ const client = store(context);
176
+ const [shop, products] = await Promise.all([
177
+ client.getSettings(),
178
+ pickProducts(client, { collection: settings.arrivals.collection, limit: settings.arrivals.limit }),
179
+ ]);
180
+ return { products, currency: shop.store.currency, language: shop.store.language };
181
+ }
59
182
 
60
- ```js
61
- dev: { port: 3000, runtime: 'workerd' },
183
+ export default function Home({ loaderData }: Route.ComponentProps) {
184
+ return <NewArrivals {...loaderData} />;
185
+ }
62
186
  ```
63
187
 
64
- `ecomiq build` / `deploy` siempre empaquetan para Cloudflare Workers.
188
+ `pickProducts` acepta `collection`, `category`, `products`, `limit` y `sort`.
189
+ Los ajustes disponibles son `setting.text`, `image`, `link`, `collection`,
190
+ `category`, `product`, `products`, `number` y `toggle`. El primer argumento es
191
+ el valor inicial y debe ser literal; el segundo, la etiqueta que ve el
192
+ comerciante.
65
193
 
66
- Durante `ecomiq dev`, si `cloud.baseUrl` se omite, el framework conecta a
67
- `http://127.0.0.1:8020`. En producción no se inventa un hostname: si falta la
68
- URL o Cloud no tiene una publicación activa, el template conserva su home
69
- clásica.
194
+ ### Carrito
70
195
 
71
- Ver el monorepo [ecomiq-storefront](https://github.com/ecomiq/ecomiq-storefront) para la app de referencia y más documentación.
196
+ ```tsx title="app/routes/cart.tsx"
197
+ import { cartAction, loadCart } from "@ecomiq/storefront";
198
+ import type { Route } from "./+types/cart";
72
199
 
73
- ## Storefront declarativo
200
+ export async function loader({ request, context }: Route.LoaderArgs) {
201
+ return loadCart(request, context);
202
+ }
74
203
 
75
- El contrato y el renderer viven fuera de este package:
204
+ export async function action({ request, context }: Route.ActionArgs) {
205
+ return cartAction(request, context);
206
+ }
207
+ ```
76
208
 
77
- - `@ecomiq/storefront-definition` — schema Zod, patches, migraciones
78
- - `@ecomiq/storefront-definition/react` — `DefinitionRenderer`, loaders y hooks
209
+ Con un cliente con sesión, el Worker rechaza con 403 cualquier petición que no
210
+ sea de lectura si no trae el token de la sesión: los formularios llevan
211
+ `<CustomerCsrfField />` y los `fetch` propios, la cabecera `X-Customer-Csrf`.
212
+ `FORM_CONTRACTS` lista los `intent` y los campos que acepta cada acción.
79
213
 
80
- ```tsx
81
- import { createDefaultStorefrontDefinition } from '@ecomiq/storefront-definition'
82
- import { DefinitionRenderer } from '@ecomiq/storefront-definition/react'
214
+ ## Login de clientes
83
215
 
84
- const definition = createDefaultStorefrontDefinition({
85
- storeName: 'Casa Lumbre',
86
- description: 'Cerámica producida localmente.',
87
- })
216
+ La tienda elige el modo de acceso en Admin, en **Configuración → Compra →
217
+ Cuentas de clientes**. El SDK lee esa configuración: `hosted` redirige a
218
+ Identity y `storefront` muestra el formulario del tema. Los dos modos usan las
219
+ mismas cuentas y la misma sesión de cliente.
88
220
 
89
- export function Home() {
90
- return (
91
- <DefinitionRenderer
92
- definition={definition}
93
- locale="es-PE"
94
- currency="PEN"
95
- data={{
96
- productsBySectionId: {
97
- 'featured-products': [],
98
- },
99
- collectionsBySectionId: {
100
- 'featured-collections': [],
101
- },
102
- }}
103
- />
104
- )
221
+ La ruta `/account/login` usa dos helpers:
222
+
223
+ ```tsx title="app/routes/login.tsx"
224
+ import { CustomerLoginForm, startCustomerLogin, submitCustomerLogin } from "@ecomiq/storefront";
225
+ import type { Route } from "./+types/login";
226
+
227
+ export function loader({ request, context }: Route.LoaderArgs) {
228
+ return startCustomerLogin(request, context);
105
229
  }
106
- ```
107
230
 
108
- ```ts
109
- import {
110
- StorefrontDefinitionSchema,
111
- applyStorefrontDefinitionPatch,
112
- } from '@ecomiq/storefront-definition'
231
+ export function action({ request, context }: Route.ActionArgs) {
232
+ return submitCustomerLogin(request, context);
233
+ }
113
234
  ```
235
+
236
+ El componente de la ruta pinta `CustomerLoginForm` con
237
+ `data={actionData ?? loaderData}`. Su prop `classNames` define `form`, `field`,
238
+ `label`, `input`, `button`, `secondary`, `error` y `hint`; la página, la
239
+ tipografía, los colores y los controles siguen siendo del tema. Los temas de
240
+ Ecomiq ya traen esta integración.
241
+
242
+ Para una interfaz propia, usa `<Form method="post">` de React Router con los
243
+ mismos helpers y este contrato:
244
+
245
+ | `intent` | Campos del formulario |
246
+ | -------- | --------------------------------------------------------------------------------------------------------------- |
247
+ | `send` | `email` y el token CAPTCHA si está habilitado. |
248
+ | `verify` | `code` de seis dígitos; en el paso `secondFactor`, el código de autenticación o recuperación en `secondFactor`. |
249
+ | `resend` | El token CAPTCHA si está habilitado; respeta `retryAt`. |
250
+ | `reset` | Ninguno; vuelve al ingreso del correo. |
251
+
252
+ Los datos públicos son `step`, `email`, `captcha`, `retryAt` y `error`. La
253
+ transacción OAuth, PKCE y las claves de verificación viajan en una cookie
254
+ firmada HttpOnly; el formulario propio no envía esos valores.
255
+
256
+ CAPTCHA es opcional por tienda e independiente del modo: `off`, Turnstile o
257
+ Google reCAPTCHA v2. `CustomerLoginForm` carga y reinicia el proveedor
258
+ configurado. Una interfaz propia envía `cf-turnstile-response` o
259
+ `g-recaptcha-response`; Turnstile usa la acción `customer_login_code`.
260
+
261
+ ## Registro de clientes
262
+
263
+ La tienda configura nombre, apellido, teléfono y fecha de nacimiento como
264
+ `hidden`, `optional` o `required`. Después del código, los dos modos de login
265
+ crean la sesión y consultan `GET /v1/customer/registration`. Si falta completar
266
+ el alta, redirigen a `/account/register?next=...`; el destino se limita a una
267
+ ruta interna segura.
268
+
269
+ La ruta de registro usa `loadCustomerRegistration` en el loader,
270
+ `submitCustomerRegistration` en la action y `CustomerRegistrationForm` con las
271
+ mismas clases del login. Los datos incluyen `registration`, `storeName`, `next`,
272
+ `today` (la fecha local de la tienda) y `error`. Una interfaz propia envía
273
+ `firstName`, `lastName`, `phone` y `dateOfBirth` (`YYYY-MM-DD`) con
274
+ `<CustomerCsrfField />`.
275
+
276
+ `intent=complete` guarda los campos visibles; `intent=skip` omite los opcionales
277
+ cuando no hay obligatorios. Los dos llaman `POST /v1/customer/registration`. El
278
+ backend valida los requisitos vigentes y recuerda que el cliente completó el
279
+ paso: un cliente existente solo vuelve si faltan datos que ahora son
280
+ obligatorios.
281
+
282
+ Las rutas de cuenta usan `requireCustomer`. El checkout admite invitados y llama
283
+ `requireCustomerRegistration(request, context, current)` cuando hay sesión. La
284
+ ruta de registro usa `customer` para no redirigirse a sí misma. La API también
285
+ exige el registro completo antes de las operaciones protegidas.
286
+
287
+ ## Enlaces de catálogo
288
+
289
+ Los enlaces a productos y categorías siguen funcionando aunque cambien su
290
+ patrón, slug o URL personalizada. Los menús se resuelven en la configuración
291
+ cacheada del servidor. Para botones y otros enlaces editables, `catalogLinks()`
292
+ genera `virtual:ecomiq-links` al compilar; no analiza código durante las
293
+ visitas.
294
+
295
+ El loader raíz pasa ese manifiesto a `readStorefrontLayout` y devuelve
296
+ `storefrontLinks`. `StorefrontLink` y `StorefrontAnchor` usan ese mapa sin hacer
297
+ peticiones. El SDK deduplica los destinos, agrupa hasta 100 por petición y
298
+ comparte los resultados durante 30 segundos; los cambios se ven al renovar esa
299
+ caché.
300
+
301
+ El loader también devuelve `publishedPages` con las rutas `/pages/<slug>` del
302
+ snapshot público. Los dos componentes ocultan los enlaces a `/pages/...` que
303
+ todavía no están publicados; al publicar la página, el siguiente snapshot
304
+ recupera el enlace sin consultar la API por cada enlace.
305
+
306
+ El selector del editor guarda la identidad del destino con
307
+ `setting.link("/products/cuaderno", "Comprar", { type: "product", id: "42" })`.
308
+ Con referencia devuelve un `CatalogLink`; sin referencia conserva la URL como
309
+ texto. Los dos sirven para `StorefrontLink` y `StorefrontAnchor`, que mantienen
310
+ el destino aunque otro producto reutilice la URL antigua, y reconocen los
311
+ enlaces viejos que resuelve el historial del catálogo. Los enlaces externos,
312
+ las rutas fuera del catálogo, los parámetros y las anclas se conservan.
313
+
314
+ En código propio, usa esos componentes para los enlaces editables. Las tarjetas
315
+ que ya reciben `product.url` o `category.url` pueden usar esos valores tal cual.
316
+
317
+ ## Logos de medios de pago
318
+
319
+ `PaymentLogo` pinta un `<img>` de 38×24 que apunta a
320
+ `/assets/payment-logos/<código>.svg`; el JavaScript de la tienda solo lleva los
321
+ nombres. `paymentLogos()` escribe esos SVG en el build del navegador y los sirve
322
+ en desarrollo. `paymentLogoCodes` convierte los medios de pago de la tienda en
323
+ esos códigos.
324
+
325
+ ## Medición y consentimiento
326
+
327
+ `@ecomiq/storefront/analytics` carga GA4, Google Tag Manager, Meta Pixel y el
328
+ código propio que la tienda configura en Admin (**Tienda online → Ajustes →
329
+ Medición y píxeles**), y solo después de que el cliente los acepta. Cada
330
+ herramienta pide su finalidad: GA4, «Medición»; Meta Pixel, «Publicidad»;
331
+ Google Tag Manager y el código propio, las dos, porque pueden llevar cualquier
332
+ etiqueta.
333
+
334
+ El loader raíz devuelve `analytics: readAnalytics(context, settings, cart)`, que
335
+ es `null` sin IDs ni código propio y en el lienzo del editor. El `Layout` pinta
336
+ `<Analytics />` y `<ConsentBanner />`. El aviso no trae estilos: el tema le pasa
337
+ `className` y `classNames` (`text`, `link`, `configure`, `options`, `option`,
338
+ `actions`, `accept`, `reject`; sin `configure` usa la clase de `link`). Nombra
339
+ los proveedores que usa la tienda, avisa que los datos pueden tratarse fuera del
340
+ país y enlaza `/pages/privacidad` si existe. «Rechazar» y «Aceptar» van en la
341
+ primera capa; «Configurar» muestra una casilla sin marcar por finalidad y
342
+ «Guardar». Se pinta solo en el navegador.
343
+
344
+ La decisión se guarda 12 meses en la cookie `__Host-ecomiq-consent` como
345
+ `<elección>|<versión>|<fecha ISO>`, por ejemplo
346
+ `analytics.marketing|2.gm.4|2026-10-12T15:30:00.000Z` o `none|…`. La versión
347
+ junta la del aviso, las herramientas activas y la versión publicada de la página
348
+ de privacidad: si cambia, el aviso vuelve a preguntar y nada se carga hasta la
349
+ nueva decisión. Una cookie sin versión no cuenta como decisión. Las cookies del
350
+ SDK usan el prefijo `__Host-` y `Secure`, así que otra tienda del mismo dominio
351
+ no puede escribirlas.
352
+
353
+ Para otros scripts, `window.ecomiq.consent.get()` devuelve
354
+ `{ analytics, marketing, version, date }` o `null`,
355
+ `window.ecomiq.consent.set({ analytics, marketing })` guarda una decisión y el
356
+ evento `ecomiq:consent` avisa cada cambio.
357
+
358
+ Para cambiar o retirar la decisión, el pie del tema pinta `<ConsentLink />`
359
+ («Cookies», con las clases de los enlaces vecinos): vuelve a abrir el aviso y no
360
+ pinta nada cuando la tienda no mide. Retirar una finalidad borra sus cookies
361
+ (`_ga*`, `_gid`, `_gat*`, `_fbp`, `_fbc`, `_gcl_*`), avisa a Google y Meta y
362
+ recarga la página si alguna herramienta ya estaba cargada.
363
+
364
+ Los loaders del SDK agregan `analytics` a sus datos (`productPage`,
365
+ `resolvePage`, `collectionPage`, `loadCheckout`, `loadOrderStatus`) y la ruta
366
+ `/products` usa `catalogAnalytics(q, result.products)`; las rutas devuelven esa
367
+ clave tal cual. `<Analytics />` envía `page_view`, `view_item`,
368
+ `view_item_list`, `search`, `add_to_cart` y `remove_from_cart` (comparando el
369
+ carrito de la raíz), `begin_checkout` una vez por carrito y `purchase`, que lee
370
+ la cookie `__Host-ecomiq-purchase` de 10 minutos que deja el pago cuando hay
371
+ consentimiento.
372
+
373
+ ## Secciones de Ecomiq
374
+
375
+ `@ecomiq/storefront/sections/<id>` trae secciones de página listas:
376
+
377
+ | Sección | Nombre en el editor | Componente y datos |
378
+ | ---------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
379
+ | `order-tracking` | Seguimiento | `<OrderTracking loaderData={…} />` con `loadTracking`. |
380
+ | `draft-invoice` | Pedido por pagar | `<DraftInvoice loaderData={…} actionData={…} />` con `loadOrderDraft` y `orderDraftAction`. |
381
+ | `complaint-book` | Libro de Reclamaciones | `<ComplaintBook loaderData={…} actionData={…} />` con `loadComplaintBook` y `complaintBookAction`, en la ruta `libro-de-reclamaciones`. |
382
+
383
+ Cada una exporta `catalog` y `settings` como las secciones del tema;
384
+ `complaint-book` no tiene ajustes. `complaintBookLinks(settings)` devuelve el
385
+ enlace del pie solo para tiendas en soles, igual que la API, que responde 404 al
386
+ resto. Su formulario usa `<Captcha>` con la acción Turnstile `complaint_book` y
387
+ va en multipart con hasta 3 adjuntos (JPG, PNG, WebP o PDF de hasta 5 MB);
388
+ `complaintBookAttachmentError(files)` los valida en el navegador y en la action.
389
+
390
+ Las secciones se pintan con el kit del tema: importan `@theme/ui/*` (`button`,
391
+ `input`, `label`, `textarea`, `checkbox`, `radio-group`, `select`), que
392
+ `themeUi()` lleva a `app/components/ui/*`, y solo usan clases con los tokens del
393
+ tema. Si al tema le falta un componente, el build falla con el archivo que falta
394
+ y la sección que lo usa.
395
+
396
+ El código fuente viaja en `src/sections` del paquete: «Personalizar» en el
397
+ editor lo copia a `app/components/sections/<id>.tsx` y apunta la ruta a esa
398
+ copia.
399
+
400
+ ## Temas publicados
401
+
402
+ Un tema publicado es un build compilado. Para que una tienda use una función
403
+ nueva del SDK, como el login dentro de la tienda o los enlaces de catálogo, hay
404
+ que actualizar el tema y volver a publicarlo. Cambiar solo la configuración de
405
+ la tienda no modifica builds anteriores. Los cambios posteriores de URLs del
406
+ catálogo no necesitan otra publicación.
407
+
408
+ En desarrollo contra un Identity local, `ECOMIQ_AUTH_URL` (por ejemplo
409
+ `http://localhost:8000`) cambia el transporte del BFF hacia Identity sin tocar
410
+ la autoridad OAuth pública ni la validación TLS.
411
+
412
+ ## Licencia
413
+
414
+ MIT