@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
@@ -1,96 +0,0 @@
1
- /**
2
- * Auth storefront: Better Auth client + sesión via context.
3
- *
4
- * El framework monta `<AuthProvider>` en `__root` (cliente por defecto).
5
- * Puedes pasar un `client` propio si necesitas opciones custom.
6
- *
7
- * ```tsx
8
- * const { session, signIn, signOut } = useAuth()
9
- * ```
10
- */
11
- import { createContext, useContext, type ReactNode } from 'react'
12
- import { createAuthClient } from 'better-auth/react'
13
- import { ecomiqOAuthPasswordClient } from '../auth/ecomiq-oauth-password-client'
14
- import {
15
- signInWithEcomiqCredentials,
16
- type EcomiqSignInCredentials,
17
- } from '../auth/ecomiq-storefront-sign-in'
18
- import { AppEcomiqContext } from './ecomiq'
19
-
20
- export type CreateStorefrontAuthClientOptions = {
21
- baseURL?: string
22
- basePath?: string
23
- }
24
-
25
- export function createStorefrontAuthClient(
26
- options: CreateStorefrontAuthClientOptions = {},
27
- ) {
28
- return createAuthClient({
29
- ...options,
30
- plugins: [ecomiqOAuthPasswordClient()],
31
- })
32
- }
33
-
34
- export type StorefrontAuthClientInstance = ReturnType<typeof createStorefrontAuthClient>
35
- /** Sesión tipada de Better Auth (`{ user, session }`). */
36
- export type StorefrontSession = StorefrontAuthClientInstance['$Infer']['Session']
37
-
38
- const AuthContext = createContext<StorefrontAuthClientInstance | null>(null)
39
-
40
- /** Cliente por defecto del framework (una instancia por bundle). */
41
- let defaultAuthClient: StorefrontAuthClientInstance | null = null
42
-
43
- function getDefaultAuthClient(): StorefrontAuthClientInstance {
44
- if (!defaultAuthClient) {
45
- defaultAuthClient = createStorefrontAuthClient()
46
- }
47
- return defaultAuthClient
48
- }
49
-
50
- export function AuthProvider({
51
- client,
52
- children,
53
- }: {
54
- /** Si se omite, usa el cliente por defecto del storefront. */
55
- client?: StorefrontAuthClientInstance
56
- children: ReactNode
57
- }) {
58
- return (
59
- <AuthContext.Provider value={client ?? getDefaultAuthClient()}>
60
- {children}
61
- </AuthContext.Provider>
62
- )
63
- }
64
-
65
- /** Acceso a sesión y acciones de auth. Requiere `<AuthProvider>` + `<AppEcomiqProvider>`. */
66
- export function useAuth() {
67
- const client = useContext(AuthContext)
68
- if (!client) throw new Error('useAuth debe usarse dentro de AuthProvider')
69
-
70
- const sessionQuery = client.useSession()
71
- // Mismo módulo que AppEcomiqProvider (no useSettings del barrel) + soft read
72
- // para no tumbar el árbol si hay re-render concurrente post-sesión.
73
- const ecomiq = useContext(AppEcomiqContext)
74
-
75
- return {
76
- client,
77
- session: sessionQuery.data,
78
- isPending: sessionQuery.isPending,
79
- error: sessionQuery.error,
80
- signIn: async (credentials: EcomiqSignInCredentials) => {
81
- if (!ecomiq) {
82
- throw new Error('signIn requiere AppEcomiqProvider')
83
- }
84
- await signInWithEcomiqCredentials(client, ecomiq.settings, credentials)
85
- const result = await client.getSession()
86
- const session = (result as { data?: StorefrontSession | null })?.data ?? null
87
- if (!session?.user) {
88
- throw new Error(
89
- 'No se pudo establecer la sesión. Revisa cookies / certificado HTTPS e inténtalo de nuevo.',
90
- )
91
- }
92
- return session
93
- },
94
- signOut: () => client.signOut(),
95
- }
96
- }
@@ -1,275 +0,0 @@
1
- /**
2
- * Estado de carrito storefront: sesión en localStorage + mutaciones vía serverApi.
3
- *
4
- * ```tsx
5
- * <CartProvider storeId={settings.store.id} currencyCode={settings.store.currency}>
6
- * <App />
7
- * </CartProvider>
8
- *
9
- * const { cart, addItem } = useCart()
10
- * ```
11
- */
12
- import {
13
- createContext,
14
- useContext,
15
- useEffect,
16
- useRef,
17
- useState,
18
- type ReactNode,
19
- } from 'react'
20
- import { CartTokenSchema, type StorefrontCart } from '@ecomiq/core'
21
- import { z } from 'zod'
22
- import { serverApi } from '../server'
23
-
24
- const CartSessionSchema = z.object({
25
- version: z.literal(1),
26
- storeId: z.string().min(1),
27
- cartToken: CartTokenSchema,
28
- })
29
-
30
- export type CartLoadStatus = 'loading' | 'ready' | 'error'
31
-
32
- export type CartMutation = {
33
- kind: 'adding' | 'updating' | 'removing'
34
- itemId?: string
35
- }
36
-
37
- export interface CartContextValue {
38
- cart: StorefrontCart | null
39
- cartToken: string | undefined
40
- itemCount: number
41
- loadStatus: CartLoadStatus
42
- mutation: CartMutation | null
43
- error: string | undefined
44
- addItem: (input: { variantId: string; quantity: number }) => Promise<StorefrontCart>
45
- setItemQuantity: (itemId: string, quantity: number) => Promise<void>
46
- removeItem: (itemId: string) => Promise<void>
47
- reload: () => Promise<void>
48
- clearCart: () => void
49
- }
50
-
51
- const CartContext = createContext<CartContextValue | null>(null)
52
-
53
- function sessionKey(storeId: string) {
54
- return `ecomiq:cart:v1:${storeId}`
55
- }
56
-
57
- function readCartSession(key: string) {
58
- if (typeof localStorage === 'undefined') return undefined
59
- const raw = localStorage.getItem(key)
60
- if (!raw) return undefined
61
- try {
62
- const result = CartSessionSchema.safeParse(JSON.parse(raw))
63
- return result.success ? result.data : undefined
64
- } catch {
65
- return undefined
66
- }
67
- }
68
-
69
- export function CartProvider({
70
- storeId,
71
- currencyCode,
72
- children,
73
- }: {
74
- storeId: string
75
- currencyCode: string
76
- children: ReactNode
77
- }) {
78
- const key = sessionKey(storeId)
79
- const [cart, setCart] = useState<StorefrontCart | null>(null)
80
- const [cartToken, setCartToken] = useState<string>()
81
- const [loadStatus, setLoadStatus] = useState<CartLoadStatus>('loading')
82
- const [mutation, setMutation] = useState<CartMutation | null>(null)
83
- const [error, setError] = useState<string>()
84
- const mutationInFlight = useRef(false)
85
-
86
- const persist = (nextCartToken: string) => {
87
- setCartToken(nextCartToken)
88
- localStorage.setItem(key, JSON.stringify({ version: 1, storeId, cartToken: nextCartToken }))
89
- }
90
-
91
- const clear = () => {
92
- setCart(null)
93
- setCartToken(undefined)
94
- localStorage.removeItem(key)
95
- }
96
-
97
- const reload = async () => {
98
- setLoadStatus('loading')
99
- setError(undefined)
100
- const stored = readCartSession(key)
101
- if (!stored || stored.storeId !== storeId) {
102
- clear()
103
- setLoadStatus('ready')
104
- return
105
- }
106
-
107
- setCartToken(stored.cartToken)
108
- try {
109
- const result = await serverApi.loadCart({ cartToken: stored.cartToken })
110
- if (!result.ok) {
111
- setError(result.error.message)
112
- setLoadStatus('error')
113
- return
114
- }
115
- if (!result.value) {
116
- clear()
117
- } else {
118
- setCart(result.value)
119
- }
120
- setLoadStatus('ready')
121
- } catch {
122
- setError('No pudimos cargar el carrito. Inténtalo nuevamente.')
123
- setLoadStatus('error')
124
- }
125
- }
126
-
127
- useEffect(() => {
128
- void reload()
129
- const sync = (event: StorageEvent) => {
130
- if (event.key === key) void reload()
131
- }
132
- window.addEventListener('storage', sync)
133
- return () => window.removeEventListener('storage', sync)
134
- }, [key])
135
-
136
- const addItem = async (input: { variantId: string; quantity: number }) => {
137
- if (mutationInFlight.current) {
138
- const message = 'El carrito se está actualizando. Inténtalo nuevamente.'
139
- setError(message)
140
- throw new Error(message)
141
- }
142
-
143
- mutationInFlight.current = true
144
- setMutation({ kind: 'adding' })
145
- setError(undefined)
146
- try {
147
- let result
148
- try {
149
- result = await serverApi.addProductToCart({
150
- cartToken,
151
- currencyCode,
152
- variantId: input.variantId,
153
- quantity: input.quantity,
154
- })
155
- } catch {
156
- const message = 'No pudimos actualizar el carrito. Inténtalo nuevamente.'
157
- setError(message)
158
- throw new Error(message)
159
- }
160
-
161
- if (!result.ok) {
162
- setError(result.error.message)
163
- throw new Error(result.error.message)
164
- }
165
-
166
- setError(undefined)
167
- persist(result.value.cartToken)
168
- setCart(result.value.cart)
169
- return result.value.cart
170
- } finally {
171
- mutationInFlight.current = false
172
- setMutation(null)
173
- }
174
- }
175
-
176
- const setItemQuantity = async (itemId: string, quantity: number) => {
177
- if (!cartToken) {
178
- setError('No hay un carrito activo.')
179
- return
180
- }
181
- if (mutationInFlight.current) {
182
- setError('El carrito se está actualizando. Inténtalo nuevamente.')
183
- return
184
- }
185
-
186
- mutationInFlight.current = true
187
- setMutation({ kind: 'updating', itemId })
188
- setError(undefined)
189
- try {
190
- let result
191
- try {
192
- result = await serverApi.setCartItemQuantity({
193
- cartToken,
194
- cartItemId: itemId,
195
- quantity,
196
- })
197
- } catch {
198
- setError('No pudimos actualizar el carrito. Inténtalo nuevamente.')
199
- return
200
- }
201
-
202
- if (!result.ok) {
203
- if (result.error.kind === 'cart-unavailable') clear()
204
- setError(result.error.message)
205
- return
206
- }
207
-
208
- setCart(result.value)
209
- } finally {
210
- mutationInFlight.current = false
211
- setMutation(null)
212
- }
213
- }
214
-
215
- const removeItem = async (itemId: string) => {
216
- if (!cartToken) {
217
- setError('No hay un carrito activo.')
218
- return
219
- }
220
- if (mutationInFlight.current) {
221
- setError('El carrito se está actualizando. Inténtalo nuevamente.')
222
- return
223
- }
224
-
225
- mutationInFlight.current = true
226
- setMutation({ kind: 'removing', itemId })
227
- setError(undefined)
228
- try {
229
- let result
230
- try {
231
- result = await serverApi.removeCartItem({
232
- cartToken,
233
- cartItemId: itemId,
234
- })
235
- } catch {
236
- setError('No pudimos actualizar el carrito. Inténtalo nuevamente.')
237
- return
238
- }
239
-
240
- if (!result.ok) {
241
- if (result.error.kind === 'cart-unavailable') clear()
242
- setError(result.error.message)
243
- return
244
- }
245
-
246
- setCart(result.value)
247
- } finally {
248
- mutationInFlight.current = false
249
- setMutation(null)
250
- }
251
- }
252
-
253
- const value: CartContextValue = {
254
- cart,
255
- cartToken,
256
- itemCount: cart?.items.reduce((sum, item) => sum + item.quantity, 0) ?? 0,
257
- loadStatus,
258
- mutation,
259
- error,
260
- addItem,
261
- setItemQuantity,
262
- removeItem,
263
- reload,
264
- clearCart: clear,
265
- }
266
-
267
- return <CartContext.Provider value={value}>{children}</CartContext.Provider>
268
- }
269
-
270
- /** Acceso al carrito. Requiere `<CartProvider>` en el layout. */
271
- export function useCart() {
272
- const value = useContext(CartContext)
273
- if (!value) throw new Error('useCart debe usarse dentro de CartProvider')
274
- return value
275
- }
@@ -1,137 +0,0 @@
1
- /**
2
- * Provider + hooks públicos de Ecomiq (settings, config, queries).
3
- */
4
- import {
5
- createContext,
6
- createElement,
7
- useContext,
8
- type ReactNode,
9
- } from 'react'
10
- import { hashKey, keepPreviousData, useQuery } from '@tanstack/react-query'
11
- import { useNavigate } from '@tanstack/react-router'
12
- import {
13
- getMenuItems,
14
- type StorefrontMenuItem,
15
- type StorefrontSettings,
16
- } from '@ecomiq/core'
17
- import type { PublicEcomiqConfig } from '../public-config'
18
-
19
- export interface ApiQueryOptions<T> {
20
- /** Datos iniciales (ej. los del loader SSR) para render inmediato. */
21
- initialData?: T
22
- /** Tiempo en ms que los datos se consideran frescos. Default 30s. */
23
- freshForMs?: number
24
- /** Habilita/deshabilita la consulta. */
25
- enabled?: boolean
26
- /** Reintentos ante error. Default 1. */
27
- retry?: number
28
- keepPreviousData?: boolean
29
- seed?: { key: readonly unknown[]; data: T }
30
- }
31
-
32
- export interface ApiQueryResult<T> {
33
- data: T | undefined
34
- isLoading: boolean
35
- isRefreshing: boolean
36
- error: Error | null
37
- refresh: () => void
38
- }
39
-
40
- /**
41
- * Consulta datos en el cliente con caché y deduplicación automáticas.
42
- *
43
- * ```ts
44
- * const { data, isLoading } = useApiQuery(['products'], () => api.get('/products', schema))
45
- * ```
46
- */
47
- export function useApiQuery<T>(
48
- key: readonly unknown[],
49
- fetcher: (context: { signal: AbortSignal }) => Promise<T>,
50
- options: ApiQueryOptions<T> = {},
51
- ): ApiQueryResult<T> {
52
- let initialData = options.initialData
53
- if (options.seed && hashKey(options.seed.key) === hashKey(key)) {
54
- initialData = options.seed.data
55
- }
56
- const query = useQuery({
57
- queryKey: key,
58
- queryFn: ({ signal }) => fetcher({ signal }),
59
- initialData,
60
- placeholderData: options.keepPreviousData ? keepPreviousData : undefined,
61
- staleTime: options.freshForMs ?? 30_000,
62
- enabled: options.enabled,
63
- retry: options.retry ?? 1,
64
- })
65
- return {
66
- data: query.data,
67
- isLoading: query.isPending,
68
- isRefreshing: query.isFetching && !query.isPending,
69
- error: query.error,
70
- refresh: () => void query.refetch(),
71
- }
72
- }
73
-
74
- /** Valor único del shell: config local + settings storefront. */
75
- export interface AppEcomiqValue {
76
- config: PublicEcomiqConfig
77
- settings: StorefrontSettings
78
- }
79
-
80
- /** Contexto único de la app Ecomiq (lo provee el root generado). */
81
- export const AppEcomiqContext = createContext<AppEcomiqValue | null>(null)
82
-
83
- /**
84
- * Provider del shell storefront (config + settings).
85
- *
86
- * ```tsx
87
- * <AppEcomiqProvider config={publicConfig} settings={settings}>
88
- * <App />
89
- * </AppEcomiqProvider>
90
- * ```
91
- */
92
- export function AppEcomiqProvider({
93
- config,
94
- settings,
95
- children,
96
- }: AppEcomiqValue & { children: ReactNode }) {
97
- return createElement(
98
- AppEcomiqContext.Provider,
99
- { value: { config, settings } },
100
- children,
101
- )
102
- }
103
-
104
- function useAppEcomiq(): AppEcomiqValue {
105
- const value = useContext(AppEcomiqContext)
106
- if (!value) {
107
- throw new Error('Hooks de Ecomiq deben usarse dentro de AppEcomiqProvider')
108
- }
109
- return value
110
- }
111
-
112
- /** Acceso al ecomiq.config.js resuelto. */
113
- export function useAppConfig(): PublicEcomiqConfig {
114
- return useAppEcomiq().config
115
- }
116
-
117
- /** Acceso a /v1/settings (CMS, store, menus). */
118
- export function useSettings(): StorefrontSettings {
119
- return useAppEcomiq().settings
120
- }
121
-
122
- /** Items de un menú CMS (`main`, `footer`, `account`, …). */
123
- export function useMenu(key: string): StorefrontMenuItem[] {
124
- return getMenuItems(useSettings(), key)
125
- }
126
-
127
- /**
128
- * Navegación cliente a una ruta con query params (sin full page reload).
129
- *
130
- * ```ts
131
- * const go = useSearchNavigate()
132
- * go('/products', { sort: 'price_asc', page: 1 })
133
- * ```
134
- */
135
- export function useSearchNavigate() {
136
- return useNavigate()
137
- }
@@ -1,26 +0,0 @@
1
- export {
2
- AppEcomiqContext,
3
- AppEcomiqProvider,
4
- useApiQuery,
5
- useAppConfig,
6
- useSettings,
7
- useMenu,
8
- useSearchNavigate,
9
- type AppEcomiqValue,
10
- type ApiQueryOptions,
11
- type ApiQueryResult,
12
- } from './ecomiq'
13
- export {
14
- CartProvider,
15
- useCart,
16
- type CartContextValue,
17
- type CartLoadStatus,
18
- type CartMutation,
19
- } from './cart'
20
- export {
21
- AuthProvider,
22
- createStorefrontAuthClient,
23
- useAuth,
24
- type StorefrontAuthClientInstance,
25
- type StorefrontSession,
26
- } from './auth'
package/src/proxy-api.ts DELETED
@@ -1,20 +0,0 @@
1
- import { createApi, type Api } from '@ecomiq/core'
2
-
3
- /**
4
- * Cliente HTTP hacia el BFF same-origin (`/api/*`).
5
- * El proxy inyecta `x-Store-Id` y el Bearer desde la cookie OAuth
6
- * (`ecomiq_sf_oauth_at`, path `/api`).
7
- *
8
- * Usar con los services de `@ecomiq/core` (p. ej. `getCustomerAddresses(api)`).
9
- * `version` vacío: el path del proxy ya es `/api/...` (el upstream añade `/v1`).
10
- */
11
- export function createStorefrontProxyApi(): Api {
12
- const origin =
13
- typeof window !== 'undefined' && window.location?.origin
14
- ? window.location.origin
15
- : 'http://localhost'
16
- return createApi({
17
- baseUrl: `${origin}/api`,
18
- version: '',
19
- })
20
- }
@@ -1,24 +0,0 @@
1
- export interface EcomiqThemeConfig {
2
- primary?: string
3
- primaryForeground?: string
4
- background?: string
5
- foreground?: string
6
- accent?: string
7
- radius?: string
8
- }
9
-
10
- /**
11
- * Proyección pública de ecomiq.config.js (seguro para el bundle cliente).
12
- * Nombre, SEO, analytics y menús viven en `/v1/settings`.
13
- */
14
- export interface PublicEcomiqConfig {
15
- /**
16
- * Identidad de tienda para `x-Store-Domain`.
17
- * Acepta slug corto o dominio completo, p. ej. `marketplace`,
18
- * `marketplace.ecomiq.app` o `marketplace.pe`.
19
- */
20
- domain: string
21
- theme?: EcomiqThemeConfig
22
- }
23
-
24
- export type EcomiqConfig = PublicEcomiqConfig
@@ -1,89 +0,0 @@
1
- import type {
2
- CreateProductReviewParams,
3
- StorefrontReview,
4
- } from '@ecomiq/core'
5
- import { ApiError } from '@ecomiq/core'
6
- import { z } from 'zod'
7
-
8
- const ReviewProblemSchema = z.object({
9
- code: z.string().max(120).regex(/^[A-Za-z0-9._-]+$/).optional(),
10
- })
11
-
12
- interface ProductReviewClient {
13
- createProductReview(
14
- params: CreateProductReviewParams,
15
- ): Promise<StorefrontReview>
16
- }
17
-
18
- export interface ProductReviewSubmissionError {
19
- status: 400 | 409 | 429 | 500
20
- code?: string
21
- message: string
22
- }
23
-
24
- export type ProductReviewSubmissionResult =
25
- | {
26
- ok: true
27
- review: StorefrontReview
28
- }
29
- | {
30
- ok: false
31
- error: ProductReviewSubmissionError
32
- }
33
-
34
- export async function submitProductReview(
35
- client: ProductReviewClient,
36
- input: CreateProductReviewParams,
37
- ): Promise<ProductReviewSubmissionResult> {
38
- try {
39
- const review = await client.createProductReview(input)
40
- return { ok: true, review }
41
- } catch (error) {
42
- if (!(error instanceof ApiError)) throw error
43
-
44
- let code: string | undefined
45
- const problem = ReviewProblemSchema.safeParse(error.body)
46
- if (problem.success) code = problem.data.code
47
-
48
- if (error.status === 400) {
49
- let message = 'Revisa los datos de la reseña e inténtalo nuevamente.'
50
- if (
51
- code === 'ProductReview.OrderInvalid' ||
52
- code === 'ProductReview.OrderOwnerMismatch' ||
53
- code === 'ProductReview.ProductNotPurchased'
54
- ) {
55
- message = 'No pudimos verificar la compra con los datos ingresados.'
56
- }
57
- return { ok: false, error: { status: 400, code, message } }
58
- }
59
-
60
- if (error.status === 409) {
61
- let message = 'No pudimos registrar esta reseña porque ya existe una similar.'
62
- if (code === 'ProductReview.AlreadyExists') {
63
- message = 'Ya enviaste una reseña para este producto.'
64
- }
65
- return { ok: false, error: { status: 409, code, message } }
66
- }
67
-
68
- if (error.status === 429) {
69
- return {
70
- ok: false,
71
- error: {
72
- status: 429,
73
- code,
74
- message:
75
- 'Enviaste varias reseñas en poco tiempo. Espera un momento e inténtalo nuevamente.',
76
- },
77
- }
78
- }
79
-
80
- return {
81
- ok: false,
82
- error: {
83
- status: 500,
84
- code,
85
- message: 'No pudimos enviar la reseña. Inténtalo nuevamente.',
86
- },
87
- }
88
- }
89
- }
@@ -1,2 +0,0 @@
1
- export { AppEcomiqContext, AppEcomiqProvider, type AppEcomiqValue } from '../providers/ecomiq'
2
- export { AuthProvider } from '../providers/auth'