@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,53 +0,0 @@
1
- /**
2
- * Página de agradecimiento cerrada (`/thank-you`).
3
- * Tras un checkout exitoso (sin redirect del provider).
4
- */
5
- import { CheckCircle2 } from 'lucide-react'
6
- import { z } from 'zod'
7
- import { definePage, Link } from '../index'
8
- import { buttonVariants, cn } from '../ui'
9
-
10
- const ThankYouSearchSchema = z.object({
11
- cartToken: z.string().optional(),
12
- transactionId: z.string().optional(),
13
- })
14
-
15
- type ThankYouSearch = z.infer<typeof ThankYouSearchSchema>
16
-
17
- export default definePage<undefined, Record<string, never>, ThankYouSearch>({
18
- meta: () => ({
19
- title: 'Gracias por tu compra',
20
- description: 'Tu pedido fue recibido correctamente',
21
- noIndex: true,
22
- }),
23
- validateSearch: (raw) => ThankYouSearchSchema.parse(raw),
24
- component: ThankYouPage,
25
- })
26
-
27
- function ThankYouPage({ search }: { search: ThankYouSearch }) {
28
- return (
29
- <section className="mx-auto flex min-h-[55vh] w-full max-w-lg flex-col items-center justify-center px-4 py-16 text-center">
30
- <div className="mb-5 flex size-14 items-center justify-center rounded-full bg-emerald-500/10 text-emerald-600">
31
- <CheckCircle2 className="size-7" aria-hidden="true" />
32
- </div>
33
- <h1 className="text-3xl font-semibold tracking-tight">¡Gracias por tu compra!</h1>
34
- <p className="mt-3 text-sm leading-6 text-muted-foreground">
35
- Recibimos tu pedido y lo estamos procesando. Te enviaremos una confirmación por
36
- correo cuando esté listo.
37
- </p>
38
- {search.transactionId ? (
39
- <p className="mt-4 rounded-md bg-muted px-3 py-2 font-mono text-xs text-muted-foreground">
40
- Ref. {search.transactionId}
41
- </p>
42
- ) : null}
43
- <div className="mt-8 flex flex-wrap justify-center gap-3">
44
- <Link to="/" className={cn(buttonVariants({ size: 'lg' }))}>
45
- Volver a la tienda
46
- </Link>
47
- <Link to="/products" className={cn(buttonVariants({ size: 'lg', variant: 'outline' }))}>
48
- Seguir comprando
49
- </Link>
50
- </div>
51
- </section>
52
- )
53
- }
@@ -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