@ecomiq/storefront 0.1.2 → 1.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.
@@ -1,15 +1,11 @@
1
1
  import { z } from 'zod';
2
2
  import { Modal } from '@ecomiq/ui/components/modal';
3
- import { formatCurrency as formatCurrency$1, StorefrontPageDetailSchema as StorefrontPageDetailSchema$1, useCart as useCart$1, useStore as useStore$1, useStorefrontAuthClient as useStorefrontAuthClient$1, useStorefrontSession as useStorefrontSession$1, SignInForm, SignUpForm, signInWithEcomiqCredentials } from '@ecomiq/storefront/react';
3
+ import { StorefrontPageDetailSchema as StorefrontPageDetailSchema$1, formatCurrency, useCart, useStore as useStore$1, useStorefrontAuthClient as useStorefrontAuthClient$1, useStorefrontSession as useStorefrontSession$1, SignInForm, SignUpForm, signInWithEcomiqCredentials } from '@ecomiq/storefront/react';
4
4
  import { toast, Toaster as Toaster$1 } from 'sonner';
5
5
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
6
  import { useTheme } from 'next-themes';
7
- import axios from 'axios';
8
- import { existsSync } from 'fs';
9
- import { createRequire } from 'module';
10
- import { join } from 'path';
11
- import '@opennextjs/cloudflare';
12
- import '@ecomiq/storefront/core';
7
+ import { StorefrontSettingsSchema, StorefrontProductsParamsSchema, StorefrontProductsResponseSchema, StorefrontProductDetailSchema, StorefrontCollectionsResponseSchema, StorefrontCollectionDetailSchema, StorefrontPageListItemSchema, StorefrontPageDetailSchema, CartCreateRequestSchema, CartResponseSchema, CartBuyerRequestSchema, CartAddressesRequestSchema, CartCouponRequestSchema, CartCheckoutRequestSchema, CartCheckoutResponseSchema, CartPaymentReceiptResponseSchema, CartCheckoutReadResponseSchema, ShippingOptionsResponseSchema, CartShippingMethodPutRequestSchema, CartItemRequestSchema } from '@ecomiq/storefront/core';
8
+ import { getCloudflareContext } from '@opennextjs/cloudflare';
13
9
  import { QueryClient, hydrate, QueryClientProvider, useMutation, useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
14
10
  import React2, { createContext, useRef, useEffect, useContext, useState, useMemo, useCallback } from 'react';
15
11
  import { create } from 'zustand';
@@ -18,6 +14,11 @@ import { createAuthMiddleware, createAuthEndpoint, formCsrfMiddleware } from 'be
18
14
  import { APIError } from 'better-auth';
19
15
  import { setSessionCookie } from 'better-auth/cookies';
20
16
  import { parseUserOutput } from 'better-auth/db';
17
+ import axios from 'axios';
18
+ import { existsSync } from 'fs';
19
+ import { createRequire } from 'module';
20
+ import { join } from 'path';
21
+ import { getRequestHeaders } from '@tanstack/react-start/server';
21
22
 
22
23
  var __defProp = Object.defineProperty;
23
24
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -30,6 +31,12 @@ var __export = (target, all) => {
30
31
  };
31
32
 
32
33
  // src/core/client/store-api-client.ts
34
+ function setServerRequestOrigin(getter) {
35
+ serverRequestOriginGetter = getter;
36
+ }
37
+ function setServerStoreId(storeId) {
38
+ serverStoreIdGetter = storeId?.trim() || null;
39
+ }
33
40
  function setClientStoreId(storeId) {
34
41
  if (typeof window === "undefined") return;
35
42
  clientStoreIdGetter = storeId?.trim() || null;
@@ -43,11 +50,14 @@ async function getStoreApiBaseUrl() {
43
50
  }
44
51
  return STORE_API_PATH;
45
52
  }
53
+ function createStoreApiClient(baseUrl) {
54
+ return new StoreApiClient(baseUrl);
55
+ }
46
56
  async function getStoreApiClient() {
47
57
  const baseUrl = await getStoreApiBaseUrl();
48
58
  return new StoreApiClient(baseUrl);
49
59
  }
50
- var STORE_API_PATH, serverRequestOriginGetter, serverStoreIdGetter, clientStoreIdGetter, StoreApiClient;
60
+ var STORE_API_PATH, serverRequestOriginGetter, serverStoreIdGetter, clientStoreIdGetter, StoreApiClient, storeApiClient;
51
61
  var init_store_api_client = __esm({
52
62
  "src/core/client/store-api-client.ts"() {
53
63
  STORE_API_PATH = "/api/store";
@@ -147,9 +157,26 @@ var init_store_api_client = __esm({
147
157
  return this.request(path, { method: "DELETE" }, options);
148
158
  }
149
159
  };
150
- new StoreApiClient(STORE_API_PATH);
160
+ storeApiClient = new StoreApiClient(STORE_API_PATH);
151
161
  }
152
162
  });
163
+ function customerMeToProfilePatch(me) {
164
+ return {
165
+ firstName: me.firstName,
166
+ lastName: me.lastName,
167
+ phone: me.phone ?? "",
168
+ identificationNumber: me.identificationNumber,
169
+ identificationType: me.identificationType,
170
+ entityName: me.entityName,
171
+ entityIdentificationNumber: me.entityIdentificationNumber,
172
+ gender: me.gender,
173
+ role: me.role,
174
+ companyName: me.companyName,
175
+ dateOfBirth: me.dateOfBirth,
176
+ consent: me.consent,
177
+ countryIsoCode: me.countryIsoCode || "PE"
178
+ };
179
+ }
153
180
  function customerAuthOptions(accessToken) {
154
181
  const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
155
182
  return token ? { bearerToken: token } : {};
@@ -159,12 +186,52 @@ async function registerCustomer(data) {
159
186
  const client = await getStoreApiClient();
160
187
  return client.post("customer/register", payload);
161
188
  }
189
+ async function getCustomerAddresses(accessToken) {
190
+ const client = await getStoreApiClient();
191
+ const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
192
+ const response = await client.get("customer/addresses", {
193
+ ...token ? { bearerToken: token } : {}
194
+ });
195
+ return z.array(CustomerAddressSchema).parse(response);
196
+ }
197
+ async function createCustomerAddress(data, accessToken) {
198
+ const client = await getStoreApiClient();
199
+ const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
200
+ const payload = CustomerAddressUpsertSchema.parse(data);
201
+ return client.post("customer/addresses", payload, {
202
+ ...token ? { bearerToken: token } : {}
203
+ });
204
+ }
205
+ async function updateCustomerAddress(addressId, data, accessToken) {
206
+ const client = await getStoreApiClient();
207
+ const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
208
+ const payload = CustomerAddressUpsertSchema.parse(data);
209
+ const id = addressId.trim();
210
+ if (!id) throw new Error("addressId requerido");
211
+ return client.put(`customer/addresses/${encodeURIComponent(id)}`, payload, {
212
+ ...token ? { bearerToken: token } : {}
213
+ });
214
+ }
215
+ async function deleteCustomerAddress(addressId, accessToken) {
216
+ const client = await getStoreApiClient();
217
+ const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
218
+ const id = addressId.trim();
219
+ if (!id) throw new Error("addressId requerido");
220
+ return client.delete(`customer/addresses/${encodeURIComponent(id)}`, {
221
+ ...token ? { bearerToken: token } : {}
222
+ });
223
+ }
162
224
  async function getCustomerMe(accessToken) {
163
225
  const client = await getStoreApiClient();
164
226
  const response = await client.get("customer", customerAuthOptions(accessToken));
165
227
  return CustomerMeSchema.parse(response);
166
228
  }
167
- var CustomerRegisterRequestSchema, CustomerAddressSchema, CustomerMeSchema;
229
+ async function patchCustomer(data, accessToken) {
230
+ const client = await getStoreApiClient();
231
+ const payload = CustomerProfilePatchSchema.parse(data);
232
+ await client.patch("customer", payload, customerAuthOptions(accessToken));
233
+ }
234
+ var CustomerRegisterRequestSchema, CustomerAddressSchema, CustomerAddressUpsertSchema, CustomerMeSchema, CustomerProfilePatchSchema;
168
235
  var init_store_api_customer_service = __esm({
169
236
  "src/core/client/store-api-customer.service.ts"() {
170
237
  init_store_api_client();
@@ -194,7 +261,7 @@ var init_store_api_customer_service = __esm({
194
261
  longitude: z.number().nullable(),
195
262
  isDefault: z.boolean()
196
263
  });
197
- CustomerAddressSchema.omit({ id: true });
264
+ CustomerAddressUpsertSchema = CustomerAddressSchema.omit({ id: true });
198
265
  CustomerMeSchema = z.object({
199
266
  id: z.string(),
200
267
  storeId: z.string(),
@@ -226,7 +293,7 @@ var init_store_api_customer_service = __esm({
226
293
  createdOn: z.string(),
227
294
  updatedOn: z.string().nullable()
228
295
  });
229
- z.object({
296
+ CustomerProfilePatchSchema = z.object({
230
297
  firstName: z.string().trim().min(1),
231
298
  lastName: z.string().trim().min(1),
232
299
  phone: z.string().trim(),
@@ -249,7 +316,7 @@ var init_modals_factory = __esm({
249
316
  "use client";
250
317
  init_store_api_customer_service();
251
318
  ModalsFactory = () => {
252
- const cart = useCart$1();
319
+ const cart = useCart();
253
320
  const store = useStore$1();
254
321
  const authClient = useStorefrontAuthClient$1();
255
322
  const { refetch } = useStorefrontSession$1();
@@ -390,2281 +457,2508 @@ var init_ecomiq_shell_ui = __esm({
390
457
  }
391
458
  });
392
459
 
393
- // src/core/constants/api-paths.ts
394
- var STOREFRONT_API_PATH_PREFIX = "v1";
460
+ // src/core/client/store-api-errors.ts
461
+ function isCartNotActiveApiError(error) {
462
+ if (!error || typeof error !== "object") return false;
463
+ const e = error;
464
+ if (e.status !== 400) return false;
465
+ const body = e.body;
466
+ const keys = body?.errors ? Object.keys(body.errors) : [];
467
+ return keys.includes("Carts.NotActive");
468
+ }
395
469
 
396
- // src/core/constants/storefront-ecomiq-oauth-cookie.ts
397
- var STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME = "ecomiq_sf_oauth_at";
398
- var STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH = "/api/store";
470
+ // src/core/client/index.ts
471
+ init_store_api_client();
399
472
 
400
- // src/core/constants/currency.ts
401
- var countryCurrency = {
402
- "PEN": "es-PE",
403
- "USD": "en-US",
404
- "COP": "es-CO",
405
- "MXN": "es-MX"
406
- };
473
+ // src/core/client/store-api-store.service.ts
474
+ init_store_api_client();
475
+ async function getStorefrontSettings(subdomain, cacheKey) {
476
+ const client = await getStoreApiClient();
477
+ const response = await client.get("settings", {
478
+ xStoreDomain: subdomain?.trim() || void 0,
479
+ cacheKey,
480
+ noStore: true
481
+ });
482
+ return StorefrontSettingsSchema.parse(response);
483
+ }
484
+ var ECOMIQ_CLIENTS_STORE_KV_BINDING = "ecomiq_clients_store";
485
+ var ECOMIQ_APP_APEX = "ecomiq.app";
486
+ var ECOMIQ_APP_SUFFIX = [`.${ECOMIQ_APP_APEX}`, `.localhost`];
487
+ function normalizeStoreHost(hostHeader) {
488
+ let h = hostHeader.trim().toLowerCase();
489
+ const colon = h.indexOf(":");
490
+ if (colon !== -1) h = h.slice(0, colon);
491
+ if (h.startsWith("www.")) h = h.slice(4);
492
+ return h;
493
+ }
494
+ function resolveStorefrontSettingsHost(hostHeader) {
495
+ const host = normalizeStoreHost(hostHeader);
496
+ if (!host) {
497
+ throw Object.assign(new Error("Host inv\xE1lido para tienda"), { status: 400 });
498
+ }
499
+ if (host === ECOMIQ_APP_APEX) {
500
+ throw Object.assign(new Error("Host apex ecomiq.app sin slug de tienda"), { status: 400 });
501
+ }
502
+ if (ECOMIQ_APP_SUFFIX.some((suffix) => host.endsWith(suffix))) {
503
+ const slug = host.slice(0, -(ECOMIQ_APP_SUFFIX.find((suffix) => host.endsWith(suffix))?.length ?? 0));
504
+ if (!slug) {
505
+ throw Object.assign(new Error("Host sin slug para ecomiq.app"), { status: 400 });
506
+ }
507
+ return slug;
508
+ }
509
+ return host;
510
+ }
511
+ function buildStorefrontKvSnapshotKeyFromStoreKey(storeKey) {
512
+ const key = storeKey.trim();
513
+ if (!key) {
514
+ throw Object.assign(new Error("Store key vac\xEDo para KV"), { status: 400 });
515
+ }
516
+ return `storefront:snapshots:store:${key}`;
517
+ }
518
+ function buildStorefrontKvSnapshotKey(hostHeader) {
519
+ return buildStorefrontKvSnapshotKeyFromStoreKey(
520
+ resolveStorefrontSettingsHost(hostHeader)
521
+ );
522
+ }
523
+ function getKvNamespace(env) {
524
+ if (!env || typeof env !== "object") return void 0;
525
+ const ns = env[ECOMIQ_CLIENTS_STORE_KV_BINDING];
526
+ if (!ns || typeof ns !== "object" || typeof ns.get !== "function") {
527
+ return void 0;
528
+ }
529
+ return ns;
530
+ }
531
+ async function getStorefrontSettingsFromKvByStoreKey(storeKey) {
532
+ const { env } = await getCloudflareContext({ async: true });
533
+ const kv = getKvNamespace(env);
534
+ if (!kv) {
535
+ const err = new Error(
536
+ `Binding KV "${ECOMIQ_CLIENTS_STORE_KV_BINDING}" no encontrado. Configura kv_namespaces en wrangler.`
537
+ );
538
+ throw Object.assign(err, { status: 500 });
539
+ }
540
+ const cacheKey = buildStorefrontKvSnapshotKeyFromStoreKey(storeKey);
541
+ const raw = await kv.get(cacheKey, { type: "json" });
542
+ if (raw == null) {
543
+ const err = new Error("Store settings not found in KV");
544
+ throw Object.assign(err, { status: 404 });
545
+ }
546
+ return StorefrontSettingsSchema.parse(raw);
547
+ }
548
+ async function getStorefrontSettingsFromKv(hostHeader) {
549
+ return getStorefrontSettingsFromKvByStoreKey(
550
+ resolveStorefrontSettingsHost(hostHeader)
551
+ );
552
+ }
407
553
 
408
- // src/core/utils/format-currency.ts
409
- function formatCurrency(amount, currency = "USD") {
410
- const locale = countryCurrency[currency] ?? "en-US";
411
- return new Intl.NumberFormat(locale, {
412
- style: "currency",
413
- currency
414
- }).format(amount);
554
+ // src/core/client/store-api-product.service.ts
555
+ init_store_api_client();
556
+ async function getStorefrontProducts(params, cacheKey) {
557
+ const parsed = StorefrontProductsParamsSchema.parse(params ?? {});
558
+ const searchParams = new URLSearchParams();
559
+ searchParams.set("page", String(parsed.page));
560
+ searchParams.set("pageSize", String(parsed.pageSize));
561
+ if (parsed.sort) searchParams.set("sort", parsed.sort);
562
+ if (parsed.sellerId) searchParams.set("sellerId", parsed.sellerId);
563
+ if (parsed.search) searchParams.set("search", parsed.search);
564
+ if (parsed.collection) searchParams.set("collection", parsed.collection);
565
+ if (parsed.category) searchParams.set("category", parsed.category);
566
+ if (parsed.brand) searchParams.set("brand", parsed.brand);
567
+ if (parsed.productType) searchParams.set("productType", parsed.productType);
568
+ if (parsed.inStock != null) searchParams.set("inStock", String(parsed.inStock));
569
+ if (parsed.minPrice != null) searchParams.set("minPrice", String(parsed.minPrice));
570
+ if (parsed.maxPrice != null) searchParams.set("maxPrice", String(parsed.maxPrice));
571
+ const path = `products?${searchParams.toString()}`;
572
+ const client = await getStoreApiClient();
573
+ const response = await client.get(path, {
574
+ cacheKey
575
+ });
576
+ return StorefrontProductsResponseSchema.parse(response);
415
577
  }
416
- var StorefrontCheckoutSettingsSchema = z.object({
417
- allowGuestCheckout: z.boolean().optional(),
418
- identityScope: z.enum(["store", "tenant", "global"]).optional(),
419
- signInMethods: z.array(z.string()).optional()
420
- });
421
- var looseRecord = z.record(z.string(), z.unknown());
422
- var StorefrontThemeConfigSchema = z.object({
578
+ async function getStorefrontProductBySlug(slug) {
579
+ const path = `products/${encodeURIComponent(slug)}`;
580
+ const client = await getStoreApiClient();
581
+ const response = await client.get(path);
582
+ return StorefrontProductDetailSchema.parse(response);
583
+ }
584
+
585
+ // src/core/client/store-api-collection.service.ts
586
+ init_store_api_client();
587
+ async function getStorefrontCollections() {
588
+ const client = await getStoreApiClient();
589
+ const response = await client.get("collections");
590
+ return StorefrontCollectionsResponseSchema.parse(response);
591
+ }
592
+ async function getStorefrontCollectionBySlug(slug) {
593
+ const client = await getStoreApiClient();
594
+ const response = await client.get(
595
+ `collections/by-slug/${encodeURIComponent(slug)}`
596
+ );
597
+ return StorefrontCollectionDetailSchema.parse(response);
598
+ }
599
+
600
+ // src/core/client/store-api-pages.service.ts
601
+ init_store_api_client();
602
+ async function getStorefrontPages() {
603
+ const client = await getStoreApiClient();
604
+ const response = await client.get("pages");
605
+ return z.array(StorefrontPageListItemSchema).parse(response);
606
+ }
607
+ async function getStorefrontPageBySlug(slug) {
608
+ const path = `pages/${encodeURIComponent(slug)}`;
609
+ const client = await getStoreApiClient();
610
+ const response = await client.get(path);
611
+ return StorefrontPageDetailSchema.parse(response);
612
+ }
613
+ async function getStorefrontPagePreview(slug, token) {
614
+ const path = `pages/${encodeURIComponent(slug)}/preview?token=${encodeURIComponent(token)}`;
615
+ const client = await getStoreApiClient();
616
+ const response = await client.get(path);
617
+ return StorefrontPageDetailSchema.parse(response);
618
+ }
619
+
620
+ // src/core/client/store-api-cart.service.ts
621
+ init_store_api_client();
622
+ async function createCart(data) {
623
+ const payload = CartCreateRequestSchema.parse(data);
624
+ const client = await getStoreApiClient();
625
+ const response = await client.post("carts", payload);
626
+ return CartResponseSchema.parse(response);
627
+ }
628
+ async function getCart(cartId) {
629
+ if (!cartId) throw new Error("cartId is required");
630
+ const client = await getStoreApiClient();
631
+ const response = await client.get(`carts/${cartId}`);
632
+ return CartResponseSchema.parse(response);
633
+ }
634
+ async function addCartItem(data, cartId) {
635
+ if (!cartId) throw new Error("cartId is required");
636
+ const payload = CartItemRequestSchema.parse(data);
637
+ const variantId = Number(payload.variantId);
638
+ if (!Number.isSafeInteger(variantId) || variantId <= 0) {
639
+ throw new Error("variantId must be a valid public id");
640
+ }
641
+ const modifiers = payload.modifiers?.map((modifier) => {
642
+ const modifierGroupId = Number(modifier.modifierGroupId);
643
+ const optionIds = modifier.optionIds.map((optionId) => Number(optionId));
644
+ if (!Number.isSafeInteger(modifierGroupId) || modifierGroupId <= 0 || optionIds.some((optionId) => !Number.isSafeInteger(optionId) || optionId <= 0)) {
645
+ throw new Error("modifiers must use valid public ids");
646
+ }
647
+ return { modifierGroupId, optionIds };
648
+ });
649
+ const client = await getStoreApiClient();
650
+ const response = await client.post(`carts/${cartId}/items`, {
651
+ ...payload,
652
+ variantId,
653
+ ...modifiers ? { modifiers } : {}
654
+ });
655
+ return CartResponseSchema.parse(response);
656
+ }
657
+ async function patchCartBuyer(data, cartId) {
658
+ if (!cartId) throw new Error("cartId is required");
659
+ const payload = CartBuyerRequestSchema.parse(data);
660
+ const client = await getStoreApiClient();
661
+ const response = await client.patch(
662
+ `carts/${cartId}/buyer`,
663
+ payload
664
+ );
665
+ return CartResponseSchema.parse(response);
666
+ }
667
+ async function patchCartAddresses(data, cartId) {
668
+ if (!cartId) throw new Error("cartId is required");
669
+ const payload = CartAddressesRequestSchema.parse(data);
670
+ const client = await getStoreApiClient();
671
+ const response = await client.patch(
672
+ `carts/${cartId}/addresses`,
673
+ payload
674
+ );
675
+ return CartResponseSchema.parse(response);
676
+ }
677
+ async function addCartCoupon(cartId, data) {
678
+ if (!cartId) throw new Error("cartId is required");
679
+ const payload = CartCouponRequestSchema.parse(data);
680
+ const client = await getStoreApiClient();
681
+ const response = await client.post(
682
+ `carts/${cartId}/promotion-codes`,
683
+ payload
684
+ );
685
+ return CartResponseSchema.parse(response);
686
+ }
687
+ async function removeCartCoupon(cartId, code) {
688
+ if (!cartId) throw new Error("cartId is required");
689
+ if (!code.trim()) throw new Error("code is required");
690
+ const client = await getStoreApiClient();
691
+ const response = await client.delete(
692
+ `carts/${cartId}/promotion-codes/${encodeURIComponent(code.trim())}`
693
+ );
694
+ return CartResponseSchema.parse(response);
695
+ }
696
+ async function checkoutCart(data, cartId) {
697
+ if (!cartId) throw new Error("cartId is required");
698
+ const payload = CartCheckoutRequestSchema.parse(data);
699
+ const client = await getStoreApiClient();
700
+ const response = await client.post(
701
+ `carts/${cartId}/checkout`,
702
+ payload
703
+ );
704
+ return CartCheckoutResponseSchema.parse(response);
705
+ }
706
+ async function uploadPaymentReceipt(cartId, file) {
707
+ if (!cartId) throw new Error("cartId is required");
708
+ const baseUrl = await getStoreApiBaseUrl();
709
+ const form = new FormData();
710
+ form.set("file", file);
711
+ const response = await fetch(
712
+ `${baseUrl.replace(/\/$/, "")}/carts/${encodeURIComponent(cartId)}/payment-receipt`,
713
+ {
714
+ method: "POST",
715
+ body: form,
716
+ ...typeof window === "undefined" && { cache: "no-store" }
717
+ }
718
+ );
719
+ if (!response.ok) {
720
+ let body;
721
+ try {
722
+ const errorText = await response.text();
723
+ body = errorText ? JSON.parse(errorText) : void 0;
724
+ } catch {
725
+ body = void 0;
726
+ }
727
+ const message = typeof body === "object" && body !== null && "title" in body && typeof body.title === "string" ? body.title : response.statusText || "Store API error";
728
+ const error = new Error(message);
729
+ error.status = response.status;
730
+ error.body = body;
731
+ throw error;
732
+ }
733
+ return CartPaymentReceiptResponseSchema.parse(await response.json());
734
+ }
735
+ async function getCartCheckout(cartId) {
736
+ if (!cartId) throw new Error("cartId is required");
737
+ const client = await getStoreApiClient();
738
+ const response = await client.get(`carts/${cartId}/checkout`);
739
+ return CartCheckoutReadResponseSchema.parse(response);
740
+ }
741
+ async function getShippingOptions(cartId, postalCode) {
742
+ if (!cartId) throw new Error("cartId is required");
743
+ if (!postalCode?.trim()) throw new Error("postalCode is required");
744
+ const client = await getStoreApiClient();
745
+ const q = new URLSearchParams({ postalCode: postalCode.trim() });
746
+ const response = await client.get(
747
+ `carts/${cartId}/shipping-options?${q.toString()}`
748
+ );
749
+ return ShippingOptionsResponseSchema.parse(response);
750
+ }
751
+ async function putCartShippingMethod(cartId, data) {
752
+ if (!cartId) throw new Error("cartId is required");
753
+ const payload = CartShippingMethodPutRequestSchema.parse(data);
754
+ const client = await getStoreApiClient();
755
+ const response = await client.put(
756
+ `carts/${cartId}/shipping-method`,
757
+ payload
758
+ );
759
+ return CartResponseSchema.parse(response);
760
+ }
761
+ async function getCartPaymentMethods(cartId) {
762
+ if (!cartId) throw new Error("cartId is required");
763
+ const { paymentMethods } = await getCartCheckout(cartId);
764
+ return paymentMethods;
765
+ }
766
+
767
+ // src/core/client/index.ts
768
+ init_store_api_customer_service();
769
+
770
+ // src/core/client/store-api-customer-order.service.ts
771
+ init_store_api_client();
772
+ var CustomerOrderShippingAddressSchema = z.object({
423
773
  name: z.string().nullable().optional(),
424
- mode: z.string().nullable().optional(),
425
- colors: looseRecord.optional(),
426
- fonts: looseRecord.optional(),
427
- assets: looseRecord.optional()
428
- }).passthrough();
429
- var StorefrontFeaturesEnabledSchema = z.object({
430
- flags: looseRecord.optional()
774
+ company: z.string().nullable().optional(),
775
+ address1: z.string(),
776
+ address2: z.string().nullable().optional(),
777
+ city: z.string().nullable().optional(),
778
+ countryCode: z.string(),
779
+ province: z.string().nullable().optional(),
780
+ postalCode: z.string().nullable().optional(),
781
+ district: z.string().nullable().optional(),
782
+ phone: z.string().nullable().optional(),
783
+ latitude: z.number().nullable().optional(),
784
+ longitude: z.number().nullable().optional(),
785
+ metadata: z.record(z.unknown()).nullable().optional()
431
786
  }).passthrough();
432
- var StorefrontCmsBrandingSchema = z.object({
433
- logoUrl: z.string().nullable().optional(),
434
- logoDarkUrl: z.string().nullable().optional(),
435
- faviconUrl: z.string().nullable().optional(),
436
- socialImageUrl: z.string().nullable().optional()
787
+ var CustomerOrderLineItemSchema = z.object({
788
+ id: z.string(),
789
+ orderId: z.coerce.string(),
790
+ productId: z.coerce.string().nullable(),
791
+ variantId: z.coerce.string().nullable(),
792
+ title: z.string(),
793
+ subtitle: z.string().nullable().optional(),
794
+ thumbnail: z.string().nullable().optional(),
795
+ variantTitle: z.string().nullable().optional(),
796
+ productHandle: z.string().nullable().optional(),
797
+ quantity: z.number(),
798
+ unitPrice: z.number(),
799
+ total: z.number(),
800
+ status: z.string()
437
801
  });
438
- var StorefrontCmsSeoSchema = z.object({
439
- siteName: z.string().nullable().optional(),
440
- metaTitle: z.string().nullable().optional(),
441
- metaDescription: z.string().nullable().optional(),
442
- titleTemplate: z.string().nullable().optional(),
443
- robotsIndex: z.boolean().optional()
802
+ var CustomerOrderListItemSchema = z.object({
803
+ orderId: z.coerce.string(),
804
+ orderNumber: z.string(),
805
+ orderGroup: z.string(),
806
+ orderIds: z.array(z.coerce.string()),
807
+ status: z.string(),
808
+ total: z.number(),
809
+ totalPaid: z.number(),
810
+ currencyCode: z.string(),
811
+ orderDate: z.string(),
812
+ createdOn: z.string(),
813
+ updatedOn: z.string().nullable().optional(),
814
+ paymentAt: z.string().nullable().optional(),
815
+ shippingAddress: CustomerOrderShippingAddressSchema.nullable().optional(),
816
+ shippingAddressSummary: z.string().nullable().optional(),
817
+ items: z.array(CustomerOrderLineItemSchema)
444
818
  });
445
- var StorefrontCmsSocialLinksSchema = z.object({
446
- instagram: z.string().nullable().optional(),
447
- facebook: z.string().nullable().optional(),
448
- tiktok: z.string().nullable().optional(),
449
- youtube: z.string().nullable().optional(),
450
- x: z.string().nullable().optional()
819
+ var CustomerOrderPaymentSchema = z.object({
820
+ id: z.string(),
821
+ paymentMethod: z.string(),
822
+ paymentCode: z.string(),
823
+ amount: z.number(),
824
+ paymentStatus: z.string(),
825
+ receiptUrl: z.string().nullable().optional(),
826
+ createdOn: z.string()
451
827
  });
452
- var StorefrontCmsContactSchema = z.object({
453
- supportEmail: z.string().nullable().optional(),
454
- phone: z.string().nullable().optional(),
455
- whatsapp: z.string().nullable().optional(),
456
- address: z.string().nullable().optional(),
457
- socialLinks: StorefrontCmsSocialLinksSchema.optional()
828
+ var CustomerOrderStatusTimelineSchema = z.object({
829
+ key: z.string(),
830
+ label: z.string(),
831
+ occurredAt: z.string(),
832
+ description: z.string().nullable().optional(),
833
+ status: z.string(),
834
+ source: z.string()
458
835
  });
459
- var StorefrontCmsTrackingSchema = z.object({
460
- googleAnalyticsMeasurementId: z.string().nullable().optional(),
461
- metaPixelId: z.string().nullable().optional(),
462
- googleTagManagerContainerId: z.string().nullable().optional()
836
+ var CustomerOrderDetailSchema = z.object({
837
+ id: z.coerce.string(),
838
+ orderNumber: z.string(),
839
+ orderGroup: z.string(),
840
+ status: z.string(),
841
+ total: z.number(),
842
+ totalPaid: z.number(),
843
+ currencyCode: z.string(),
844
+ orderDate: z.string(),
845
+ createdOn: z.string(),
846
+ updatedOn: z.string().nullable().optional(),
847
+ paymentAt: z.string().nullable().optional(),
848
+ subTotal: z.number(),
849
+ discount: z.number(),
850
+ shipping: z.number(),
851
+ tax: z.number(),
852
+ email: z.string(),
853
+ phone: z.string(),
854
+ firstName: z.string(),
855
+ lastName: z.string(),
856
+ shippingAddress: CustomerOrderShippingAddressSchema.nullable().optional(),
857
+ shippingAddressSummary: z.string().nullable().optional(),
858
+ billingAddress: CustomerOrderShippingAddressSchema.nullable().optional(),
859
+ items: z.array(CustomerOrderLineItemSchema),
860
+ payments: z.array(CustomerOrderPaymentSchema),
861
+ statusTimeline: z.array(CustomerOrderStatusTimelineSchema)
463
862
  });
464
- var StorefrontCmsCustomScriptsSchema = z.object({
465
- enabled: z.boolean().optional(),
466
- head: z.string().nullable().optional(),
467
- bodyEnd: z.string().nullable().optional()
863
+ function authOptions(accessToken) {
864
+ const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
865
+ return token ? { bearerToken: token } : {};
866
+ }
867
+ async function getCustomerOrders(accessToken) {
868
+ const client = await getStoreApiClient();
869
+ const response = await client.get("customer/orders", authOptions(accessToken));
870
+ return z.array(CustomerOrderListItemSchema).parse(response);
871
+ }
872
+ async function getCustomerOrder(orderId, accessToken) {
873
+ const client = await getStoreApiClient();
874
+ const id = orderId.trim();
875
+ if (!id) throw new Error("orderId requerido");
876
+ const response = await client.get(
877
+ `customer/orders/${encodeURIComponent(id)}`,
878
+ authOptions(accessToken)
879
+ );
880
+ return CustomerOrderDetailSchema.parse(response);
881
+ }
882
+ var StorefrontOrderAddressSchema = z.object({
883
+ address1: z.string().optional(),
884
+ address2: z.string().optional(),
885
+ city: z.string().optional(),
886
+ province: z.string().optional(),
887
+ country: z.string().optional(),
888
+ zip: z.string().optional(),
889
+ phone: z.string().optional(),
890
+ firstName: z.string().optional(),
891
+ lastName: z.string().optional()
892
+ }).passthrough();
893
+ var OrderDraftItemSchema = z.object({
894
+ id: z.string(),
895
+ productId: z.coerce.string().nullable().optional(),
896
+ sellerId: z.string().nullable().optional(),
897
+ shippingProfileId: z.string().nullable().optional(),
898
+ variantId: z.coerce.string().nullable().optional(),
899
+ title: z.string(),
900
+ subtitle: z.string().nullable().optional(),
901
+ thumbnail: z.string().nullable().optional(),
902
+ quantity: z.number().optional().default(1),
903
+ unitPrice: z.number().optional().default(0),
904
+ subTotal: z.number().optional().default(0),
905
+ discount: z.number().optional().default(0),
906
+ shipping: z.number().optional().default(0),
907
+ tax: z.number().optional().default(0),
908
+ warranty: z.number().optional().default(0),
909
+ total: z.number().optional().default(0),
910
+ requiresShipping: z.boolean().optional().default(true),
911
+ isTaxInclusive: z.boolean().optional().default(true),
912
+ metadata: z.record(z.unknown()).optional().default({})
468
913
  });
469
- var StorefrontCmsSettingsSchema = z.object({
470
- themeKey: z.string().optional(),
471
- branding: StorefrontCmsBrandingSchema.optional(),
472
- seo: StorefrontCmsSeoSchema.optional(),
473
- contact: StorefrontCmsContactSchema.optional(),
474
- tracking: StorefrontCmsTrackingSchema.optional(),
475
- customScripts: StorefrontCmsCustomScriptsSchema.optional(),
476
- updatedOn: z.string().nullable().optional()
477
- });
478
- var StorefrontCmsPageSchema = z.object({
914
+ var OrderDraftShippingMethodSchema = z.object({
479
915
  id: z.string(),
480
- name: z.string(),
481
- slug: z.string(),
482
- layout: z.string().optional(),
483
- version: z.number().optional(),
484
- settings: z.record(z.string(), z.unknown()).optional().nullable(),
485
- sections: z.array(z.unknown()).optional(),
486
- status: z.string().optional(),
487
- hasPublishedVersion: z.boolean().optional(),
488
- publishedOn: z.string().nullable().optional(),
489
- publishedBy: z.string().nullable().optional(),
490
- createdOn: z.string().nullable().optional(),
491
- updatedOn: z.string().nullable().optional(),
492
- createdBy: z.string().nullable().optional(),
493
- updatedBy: z.string().nullable().optional(),
494
- lastModifiedBy: z.string().nullable().optional()
495
- }).passthrough();
496
- var StorefrontSettingsLegacyFlatSchema = z.object({
497
- id: z.coerce.string(),
498
- tenantId: z.string().nullable().optional(),
499
- name: z.string(),
500
- slug: z.coerce.string().optional(),
916
+ name: z.string().optional().default(""),
501
917
  description: z.string().nullable().optional(),
502
- visibility: z.string().nullable().optional(),
503
- logo: z.string().nullable().optional(),
504
- favicon: z.string().nullable().optional(),
505
- icon: z.string().nullable().optional(),
506
- currency: z.string().nullable().optional(),
507
- language: z.string().nullable().optional(),
508
- themeConfig: z.unknown().optional().nullable(),
509
- featuresEnabled: z.unknown().optional().nullable(),
510
- checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
511
- }).passthrough();
512
- function unwrapSettingsResponseBody(v) {
513
- if (!v || typeof v !== "object" || Array.isArray(v)) return v;
514
- const o = v;
515
- if ("data" in o && o.data != null && typeof o.data === "object" && !Array.isArray(o.data)) {
516
- return o.data;
517
- }
518
- return v;
519
- }
520
- function isLegacyFlatSettingsPayload(v) {
521
- if (!v || typeof v !== "object" || Array.isArray(v)) return false;
522
- const o = v;
523
- if ("store" in o || "schemaVersion" in o || "cms" in o) return false;
524
- return (typeof o.id === "string" || typeof o.id === "number") && typeof o.name === "string";
918
+ subtotal: z.number().optional().default(0),
919
+ discountTotal: z.number().optional().default(0),
920
+ taxTotal: z.number().optional().default(0),
921
+ total: z.number().optional().default(0),
922
+ isTaxInclusive: z.boolean().optional().default(true),
923
+ sellerId: z.string().nullable().optional(),
924
+ shippingProfileId: z.string().nullable().optional(),
925
+ shippingMethodId: z.string().nullable().optional(),
926
+ connectionId: z.string().nullable().optional(),
927
+ providerName: z.string().nullable().optional(),
928
+ trackingCode: z.string().nullable().optional(),
929
+ estimatedDays: z.number().nullable().optional(),
930
+ zoneCode: z.string().nullable().optional(),
931
+ locationId: z.string().nullable().optional(),
932
+ pickupPointId: z.string().nullable().optional(),
933
+ scheduledDate: z.string().nullable().optional(),
934
+ scheduledTime: z.string().nullable().optional(),
935
+ data: z.record(z.unknown()).optional().default({})
936
+ });
937
+ var OrderDraftSchema = z.object({
938
+ id: z.string(),
939
+ storeId: z.string().optional(),
940
+ customerId: z.coerce.string().nullable().optional(),
941
+ cartId: z.string().nullable().optional(),
942
+ draftNumber: z.string(),
943
+ currencyCode: z.string().optional().default("PEN"),
944
+ source: z.string().nullable().optional(),
945
+ notes: z.string().nullable().optional(),
946
+ email: z.string().nullable().optional(),
947
+ phone: z.string().nullable().optional(),
948
+ firstName: z.string().nullable().optional(),
949
+ lastName: z.string().nullable().optional(),
950
+ identificationType: z.string().nullable().optional(),
951
+ identificationNumber: z.string().nullable().optional(),
952
+ entityTaxId: z.string().nullable().optional(),
953
+ entityName: z.string().nullable().optional(),
954
+ status: z.string(),
955
+ draftDate: z.string().nullable().optional(),
956
+ sentAt: z.string().nullable().optional(),
957
+ viewedAt: z.string().nullable().optional(),
958
+ acceptedAt: z.string().nullable().optional(),
959
+ rejectedAt: z.string().nullable().optional(),
960
+ expiredAt: z.string().nullable().optional(),
961
+ cancelledAt: z.string().nullable().optional(),
962
+ convertedAt: z.string().nullable().optional(),
963
+ shareToken: z.string().nullable().optional(),
964
+ shareExpiresAt: z.string().nullable().optional(),
965
+ allowAnonymousShareAccess: z.boolean().optional().default(false),
966
+ sharedAt: z.string().nullable().optional(),
967
+ billingAddress: StorefrontOrderAddressSchema.optional().nullable(),
968
+ shippingAddress: StorefrontOrderAddressSchema.optional().nullable(),
969
+ metadata: z.record(z.unknown()).optional().default({}),
970
+ subTotal: z.number().optional().default(0),
971
+ discount: z.number().optional().default(0),
972
+ shipping: z.number().optional().default(0),
973
+ tax: z.number().optional().default(0),
974
+ warranty: z.number().optional().default(0),
975
+ total: z.number().optional().default(0),
976
+ paymentMethod: z.string().optional().default(""),
977
+ paymentCode: z.string().optional().default(""),
978
+ items: z.array(OrderDraftItemSchema).optional().default([]),
979
+ shippingMethods: z.array(OrderDraftShippingMethodSchema).optional().default([]),
980
+ createdOn: z.string().optional(),
981
+ updatedOn: z.string().nullable().optional()
982
+ });
983
+
984
+ // src/core/client/store-api-order-draft.service.ts
985
+ init_store_api_client();
986
+ async function getSharedOrderDraft(shareToken) {
987
+ const client = await getStoreApiClient();
988
+ const response = await client.get(
989
+ `order-drafts/share/${encodeURIComponent(shareToken)}`,
990
+ { noStore: true }
991
+ );
992
+ return OrderDraftSchema.parse(response);
525
993
  }
526
- function normalizeStorefrontSettingsPayload(v) {
527
- const body = unwrapSettingsResponseBody(v);
528
- if (!isLegacyFlatSettingsPayload(body)) return body;
529
- const raw = body;
530
- const parsed = StorefrontSettingsLegacyFlatSchema.safeParse(raw);
531
- if (!parsed.success) return body;
532
- const l = parsed.data;
533
- const currency = l.currency?.trim() ? l.currency : "PEN";
534
- const language = l.language?.trim() ? l.language : "es";
535
- const slug = l.slug?.trim() ? l.slug : l.id;
536
- return {
537
- schemaVersion: 0,
538
- generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
539
- store: {
540
- id: l.id,
541
- tenantId: l.tenantId ?? void 0,
542
- name: l.name,
543
- slug,
544
- description: l.description ?? null,
545
- logo: l.logo ?? null,
546
- icon: l.icon ?? null,
547
- visibility: l.visibility ?? void 0,
548
- currency,
549
- language,
550
- themeConfig: l.themeConfig ?? void 0,
551
- featuresEnabled: l.featuresEnabled ?? void 0,
552
- checkoutSettings: l.checkoutSettings ?? void 0
553
- },
554
- cms: {
555
- settings: {
556
- branding: {
557
- faviconUrl: l.favicon ?? null,
558
- logoUrl: l.logo ?? null,
559
- logoDarkUrl: null,
560
- socialImageUrl: null
561
- }
562
- },
563
- pages: []
994
+ var defaultOptions = {
995
+ queries: {
996
+ staleTime: 60 * 1e3
997
+ }
998
+ };
999
+ function QueryProvider({ children, dehydratedState }) {
1000
+ const queryClientRef = useRef(null);
1001
+ const hydratedRef = useRef(false);
1002
+ if (queryClientRef.current === null) {
1003
+ queryClientRef.current = new QueryClient({ defaultOptions });
1004
+ }
1005
+ const queryClient = queryClientRef.current;
1006
+ useEffect(() => {
1007
+ if (dehydratedState && !hydratedRef.current) {
1008
+ hydrate(queryClient, dehydratedState);
1009
+ hydratedRef.current = true;
564
1010
  }
565
- };
1011
+ }, [queryClient, dehydratedState]);
1012
+ return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children });
566
1013
  }
567
- var StorefrontStoreSchema = z.object({
568
- id: z.string(),
569
- tenantId: z.string().optional(),
570
- sellerId: z.string().optional(),
571
- plan: z.string().optional(),
572
- storageLimitBytes: z.number().optional(),
573
- monthlyTransferLimitBytes: z.number().optional(),
574
- maxUploadSizeBytes: z.number().optional(),
575
- maxStores: z.number().optional(),
576
- maxMembers: z.number().optional(),
577
- maxProducts: z.number().optional(),
578
- maxCategories: z.number().optional(),
579
- maxBrands: z.number().optional(),
580
- maxAttributes: z.number().optional(),
581
- maxCollections: z.number().optional(),
582
- enableApi: z.boolean().optional(),
583
- isActive: z.boolean().optional(),
584
- name: z.string(),
585
- description: z.string().nullable().optional(),
586
- avatarUrl: z.string().nullable().optional(),
587
- logo: z.string().nullable().optional(),
588
- icon: z.string().nullable().optional(),
589
- slug: z.string(),
590
- domain: z.string().nullable().optional(),
591
- domains: z.array(z.string()).optional(),
592
- timeZone: z.string().nullable().optional(),
593
- currency: z.string(),
594
- language: z.string(),
595
- visibility: z.string().optional(),
596
- privateAccessHash: z.string().nullable().optional(),
597
- privateAccessVersion: z.number().optional(),
598
- themeConfig: StorefrontThemeConfigSchema.optional(),
599
- featuresEnabled: StorefrontFeaturesEnabledSchema.optional(),
600
- checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
601
- }).passthrough();
602
- var StorefrontSettingsEnvelopeSchema = z.object({
603
- schemaVersion: z.number(),
604
- generatedAt: z.string(),
605
- store: StorefrontStoreSchema,
606
- cms: z.object({
607
- settings: StorefrontCmsSettingsSchema,
608
- pages: z.array(StorefrontCmsPageSchema)
609
- })
610
- }).passthrough();
611
- var StorefrontSettingsSchema = z.preprocess(
612
- normalizeStorefrontSettingsPayload,
613
- StorefrontSettingsEnvelopeSchema
614
- );
615
- function storefrontStoreRecord(settings) {
616
- return settings?.store ?? null;
1014
+ var StorefrontAuthContext = createContext(null);
1015
+ function StorefrontAuthProvider({
1016
+ authClient,
1017
+ children
1018
+ }) {
1019
+ return /* @__PURE__ */ jsx(StorefrontAuthContext.Provider, { value: authClient, children });
617
1020
  }
618
- function storefrontFaviconUrl(settings) {
619
- const b = settings?.cms?.settings?.branding;
620
- return b?.faviconUrl ?? settings?.store?.logo ?? settings?.store?.icon ?? null;
1021
+ function useStorefrontAuthClient() {
1022
+ const client = useContext(StorefrontAuthContext);
1023
+ if (!client) {
1024
+ throw new Error(
1025
+ "useStorefrontAuthClient debe usarse dentro de StorefrontAuthProvider (o EcomiqProvider con authClient)."
1026
+ );
1027
+ }
1028
+ return client;
621
1029
  }
622
- function storefrontOgImageUrl(settings) {
623
- const b = settings?.cms?.settings?.branding;
624
- return b?.socialImageUrl ?? settings?.store?.logo ?? null;
1030
+ function storefrontSessionEndsSoon(expiresAt, skewMs = 12e4) {
1031
+ if (!expiresAt) return false;
1032
+ return Date.now() + skewMs >= expiresAt.getTime();
625
1033
  }
626
-
627
- // src/core/lib/ecomiq-oauth-identity.ts
628
- function buildEcomiqOAuthIdentityHeaders(settings) {
629
- const record = storefrontStoreRecord(settings);
630
- if (!record?.id) {
631
- throw new Error("Tienda no disponible para iniciar sesi\xF3n");
1034
+ var storefrontAccessTokenNeedsRefresh = storefrontSessionEndsSoon;
1035
+ function parseStorefrontSessionExpires(at) {
1036
+ if (!at) return void 0;
1037
+ if (at instanceof Date) return Number.isNaN(at.getTime()) ? void 0 : at;
1038
+ if (typeof at === "string") {
1039
+ const d = new Date(at);
1040
+ return Number.isNaN(d.getTime()) ? void 0 : d;
632
1041
  }
633
- const checkout = record.checkoutSettings;
634
- const identityScope = checkout?.identityScope === "tenant" ? "tenant" : "store";
635
- const headers = {
636
- "x-Identity-Scope": identityScope,
637
- "x-Store-Id": record.id
638
- };
639
- if (record.tenantId) headers["x-Tenant-Id"] = record.tenantId;
640
- return headers;
641
- }
642
-
643
- // src/core/lib/customer-order-labels.ts
644
- var ORDER_STATUS_LABELS = {
645
- New: "Pedido realizado",
646
- Confirmed: "Confirmado",
647
- Processing: "En preparaci\xF3n",
648
- InTransit: "En camino",
649
- Delivered: "Entregado",
650
- Cancelled: "Cancelado",
651
- Canceled: "Cancelado",
652
- Refunded: "Reembolsado",
653
- Pending: "Pendiente",
654
- Paid: "Pagado",
655
- Captured: "Pago confirmado"
656
- };
657
- function formatCustomerOrderStatus(status) {
658
- const trimmed = status.trim();
659
- if (!trimmed) return "Desconocido";
660
- return ORDER_STATUS_LABELS[trimmed] ?? trimmed.replace(/([A-Z])/g, " $1").trim();
661
- }
662
- function customerOrderStatusTone(status) {
663
- const s = status.toLowerCase();
664
- if (s.includes("cancel") || s.includes("refund")) return "danger";
665
- if (s.includes("deliver")) return "success";
666
- if (s.includes("transit") || s.includes("ship")) return "info";
667
- if (s.includes("confirm") || s.includes("paid") || s.includes("capture")) return "success";
668
- if (s.includes("pending") || s.includes("new") || s.includes("process")) return "warning";
669
- return "default";
670
- }
671
- function formatOrderDate(iso, locale = "es-PE") {
672
- const d = new Date(iso);
673
- if (Number.isNaN(d.getTime())) return iso;
674
- return new Intl.DateTimeFormat(locale, {
675
- day: "numeric",
676
- month: "long",
677
- year: "numeric"
678
- }).format(d);
679
- }
680
- function formatOrderDateTime(iso, locale = "es-PE") {
681
- const d = new Date(iso);
682
- if (Number.isNaN(d.getTime())) return iso;
683
- return new Intl.DateTimeFormat(locale, {
684
- day: "numeric",
685
- month: "short",
686
- year: "numeric",
687
- hour: "2-digit",
688
- minute: "2-digit"
689
- }).format(d);
1042
+ return void 0;
690
1043
  }
691
-
692
- // src/core/lib/storefront-geo-inei.ts
693
- function toGeoItems(data) {
694
- if (!Array.isArray(data)) return [];
695
- return data.map((raw) => {
696
- if (!raw || typeof raw !== "object") return null;
697
- const item = raw;
1044
+ function mapSessionUser(raw) {
1045
+ if (!raw || typeof raw !== "object") return null;
1046
+ const u = raw;
1047
+ const explicitFirst = typeof u.firstName === "string" ? u.firstName : typeof u.given_name === "string" ? u.given_name : "";
1048
+ const explicitLast = typeof u.lastName === "string" ? u.lastName : typeof u.family_name === "string" ? u.family_name : "";
1049
+ if (explicitFirst || explicitLast) {
698
1050
  return {
699
- code: String(item.code ?? ""),
700
- name: String(item.name ?? "")
1051
+ id: String(u.id ?? ""),
1052
+ email: String(u.email ?? ""),
1053
+ firstName: explicitFirst,
1054
+ lastName: explicitLast,
1055
+ name: typeof u.name === "string" ? u.name : void 0,
1056
+ phone: typeof u.phone === "string" ? u.phone : void 0
701
1057
  };
702
- }).filter((x) => !!x && !!x.code && !!x.name);
703
- }
704
- var departmentsCache = null;
705
- var departmentsRequest = null;
706
- function loadStorefrontGeoDepartments(headers) {
707
- if (departmentsCache) return Promise.resolve(departmentsCache);
708
- if (departmentsRequest) return departmentsRequest;
709
- departmentsRequest = fetch(
710
- `/api/store/geo/departments?countryCode=PE&source=inei&limit=200`,
711
- { cache: "no-store", headers }
712
- ).then((r) => r.json()).then((data) => {
713
- const items = toGeoItems(data);
714
- departmentsCache = items;
715
- return items;
716
- }).catch(() => {
717
- departmentsCache = [];
718
- return [];
719
- }).finally(() => {
720
- departmentsRequest = null;
721
- });
722
- return departmentsRequest;
723
- }
724
- async function fetchStorefrontGeoProvinces(headers, countryCode, departmentCode) {
725
- const res = await fetch(
726
- `/api/store/geo/provinces?countryCode=${encodeURIComponent(
727
- countryCode
728
- )}&departmentCode=${encodeURIComponent(departmentCode)}&source=inei&limit=200`,
729
- { headers }
730
- );
731
- const data = await res.json();
732
- return toGeoItems(data);
733
- }
734
- async function fetchStorefrontGeoDistricts(headers, countryCode, provinceCode) {
735
- const res = await fetch(
736
- `/api/store/geo/districts?countryCode=${encodeURIComponent(
737
- countryCode
738
- )}&provinceCode=${encodeURIComponent(provinceCode)}&source=inei`,
739
- { headers }
740
- );
741
- const data = await res.json();
742
- return toGeoItems(data);
743
- }
744
- async function resolveIneiCodesFromLabels(storeId, labels, countryCode = "PE") {
745
- const id = storeId.trim();
746
- if (!id) return null;
747
- const headers = { "X-Store-Id": id };
748
- const departments = await loadStorefrontGeoDepartments(headers);
749
- const dept = departments.find((d) => d.name.trim() === labels.department.trim());
750
- if (!dept) return null;
751
- const provinces = await fetchStorefrontGeoProvinces(headers, countryCode, dept.code);
752
- const prov = provinces.find((p) => p.name.trim() === labels.province.trim());
753
- if (!prov) {
754
- return { departmentCode: dept.code, provinceCode: "", districtCode: "" };
755
- }
756
- const districts = await fetchStorefrontGeoDistricts(headers, countryCode, prov.code);
757
- const dist = districts.find((d) => d.name.trim() === labels.district.trim());
1058
+ }
1059
+ const emailLocal = String(u.email ?? "").split("@")[0] ?? "";
1060
+ const full = typeof u.name === "string" ? u.name.trim() : emailLocal.trim();
1061
+ const parts = full ? full.split(/\s+/) : [];
758
1062
  return {
759
- departmentCode: dept.code,
760
- provinceCode: prov.code,
761
- districtCode: dist?.code ?? ""
1063
+ id: String(u.id ?? ""),
1064
+ email: String(u.email ?? ""),
1065
+ firstName: parts[0] ?? "",
1066
+ lastName: parts.slice(1).join(" "),
1067
+ name: typeof u.name === "string" ? u.name : void 0,
1068
+ phone: typeof u.phone === "string" ? u.phone : void 0
762
1069
  };
763
1070
  }
764
- var ApiClient = class {
765
- client;
766
- storeId;
767
- storeDomain;
768
- constructor(baseURL = "https://storefront.ecomiq.pe") {
769
- this.client = axios.create({
770
- baseURL,
771
- timeout: 1e4,
772
- headers: {
773
- "Content-Type": "application/json"
774
- }
775
- });
776
- this.client.interceptors.request.use(
777
- (config) => {
778
- if (config.headers) {
779
- if (this.storeId) config.headers["X-Store-Id"] = this.storeId;
780
- if (this.storeDomain) config.headers["X-Store-Domain"] = this.storeDomain;
781
- }
782
- return config;
1071
+ function useStorefrontSession() {
1072
+ const authClient = useStorefrontAuthClient();
1073
+ const session = authClient.useSession();
1074
+ const user = mapSessionUser(session.data?.user);
1075
+ const storefrontSession = session.data?.session;
1076
+ const sessionExpiresAt = parseStorefrontSessionExpires(storefrontSession?.expiresAt);
1077
+ return {
1078
+ session,
1079
+ user,
1080
+ sessionExpiresAt,
1081
+ isAuthenticated: Boolean(session.data?.user),
1082
+ isPending: session.isPending,
1083
+ error: session.error,
1084
+ refetch: session.refetch,
1085
+ signOut: () => authClient.signOut()
1086
+ };
1087
+ }
1088
+ function useStoreProducts() {
1089
+ const useStorefrontProductsList = (params) => {
1090
+ return useQuery({
1091
+ queryKey: ["storefront", "products", params],
1092
+ queryFn: () => getStorefrontProducts(params)
1093
+ });
1094
+ };
1095
+ const useStorefrontInfiniteProducts = (params) => {
1096
+ return useInfiniteQuery({
1097
+ queryKey: ["storefront", "products", "infinite", params],
1098
+ queryFn: ({ pageParam = 1 }) => getStorefrontProducts({ ...params, page: pageParam }),
1099
+ getNextPageParam: (lastPage) => lastPage.pageIndex < lastPage.totalPages ? lastPage.pageIndex + 1 : void 0,
1100
+ initialPageParam: 1
1101
+ });
1102
+ };
1103
+ const useProductBySlug = (slug) => {
1104
+ return useQuery({
1105
+ queryKey: ["storefront", "product", "slug", slug],
1106
+ queryFn: () => getStorefrontProductBySlug(slug),
1107
+ enabled: !!slug
1108
+ });
1109
+ };
1110
+ const useRefreshStorefrontProducts = () => {
1111
+ const queryClient = useQueryClient();
1112
+ return useMutation({
1113
+ mutationFn: (params) => getStorefrontProducts(params),
1114
+ onSuccess: () => {
1115
+ queryClient.invalidateQueries({ queryKey: ["storefront", "products"] });
783
1116
  }
784
- );
785
- this.client.interceptors.response.use(
786
- (response) => response,
787
- (error) => {
788
- console.error("API Error:", error);
789
- return Promise.reject(error);
1117
+ });
1118
+ };
1119
+ return {
1120
+ useStorefrontProductsList,
1121
+ useStorefrontInfiniteProducts,
1122
+ useProductBySlug,
1123
+ useRefreshStorefrontProducts
1124
+ };
1125
+ }
1126
+ function useStoreCollections() {
1127
+ const useStorefrontCollectionsList = () => {
1128
+ return useQuery({
1129
+ queryKey: ["storefront", "collections"],
1130
+ queryFn: () => getStorefrontCollections()
1131
+ });
1132
+ };
1133
+ const useCollectionBySlug = (slug) => {
1134
+ return useQuery({
1135
+ queryKey: ["storefront", "collection", "slug", slug],
1136
+ queryFn: () => getStorefrontCollectionBySlug(slug),
1137
+ enabled: !!slug
1138
+ });
1139
+ };
1140
+ const useRefreshStorefrontCollections = () => {
1141
+ const queryClient = useQueryClient();
1142
+ return useMutation({
1143
+ mutationFn: () => getStorefrontCollections(),
1144
+ onSuccess: () => {
1145
+ queryClient.invalidateQueries({ queryKey: ["storefront", "collections"] });
790
1146
  }
791
- );
792
- }
793
- setStoreId(storeId) {
794
- this.storeId = storeId;
795
- }
796
- /** Subdominio para endpoints que usan X-Store-Domain (ej. GET /v1/storefront/settings) */
797
- setStoreDomain(domain) {
798
- this.storeDomain = domain;
799
- }
800
- get(url, config) {
801
- return this.client.get(url, config).then((response) => response.data);
802
- }
803
- post(url, data, config) {
804
- return this.client.post(url, data, config).then((response) => response.data);
805
- }
806
- put(url, data, config) {
807
- return this.client.put(url, data, config).then((response) => response.data);
808
- }
809
- patch(url, data, config) {
810
- return this.client.patch(url, data, config).then((response) => response.data);
811
- }
812
- delete(url, config) {
813
- return this.client.delete(url, config).then((response) => response.data);
814
- }
815
- };
816
- var apiClient = new ApiClient();
817
- var ProductVariantSchema = z.object({
818
- id: z.coerce.string(),
819
- name: z.string(),
820
- storeId: z.string(),
821
- productId: z.coerce.string(),
822
- basePrice: z.number().positive().optional().nullable(),
823
- comparePrice: z.number().positive().optional().nullable(),
824
- //TODO: remove this field
825
- originalPrice: z.number().positive().optional().nullable(),
826
- costPrice: z.number().positive().optional().nullable(),
827
- isDefault: z.boolean().optional().nullable(),
828
- reserveStock: z.number().nonnegative().optional().nullable(),
829
- weight: z.number().nonnegative().optional().nullable().default(0),
830
- width: z.number().nonnegative().optional().nullable(),
831
- height: z.number().nonnegative().optional().nullable(),
832
- unitOfMeasure: z.string().optional().nullable(),
833
- order: z.number().nonnegative().optional().nullable().default(0),
834
- sku: z.string().optional().nullable(),
835
- stock: z.number().nonnegative().optional().nullable(),
836
- leadTime: z.string().optional().nullable(),
837
- barCode: z.string().optional().nullable(),
838
- shippingWeight: z.number().nonnegative().optional().nullable(),
839
- images: z.array(z.string()).optional().nullable(),
840
- attributes: z.array(z.string()).optional().nullable(),
841
- variantStatus: z.string().optional().nullable(),
842
- status: z.string().optional().nullable(),
843
- createdOn: z.string().optional().nullable(),
844
- updatedOn: z.string().optional().nullable(),
845
- deletedOn: z.string().optional().nullable()
846
- });
847
- var ProductSchema = z.object({
848
- id: z.coerce.string(),
849
- name: z.string(),
850
- images: z.array(z.object({
851
- url: z.string().url(),
852
- name: z.string().optional(),
853
- isPrimary: z.boolean().optional()
854
- })),
855
- basePrice: z.number().positive().optional(),
856
- salePrice: z.number().positive().optional(),
857
- slug: z.string(),
858
- description: z.string().optional(),
859
- categories: z.array(z.object({
860
- id: z.coerce.string(),
861
- name: z.string(),
862
- slug: z.string(),
863
- logo: z.string().optional(),
864
- icon: z.string().optional()
865
- })).optional(),
866
- tags: z.array(z.string()).optional(),
867
- inStock: z.boolean().optional(),
868
- variants: z.array(ProductVariantSchema).optional()
869
- });
870
- var ProductsResponseSchema = z.object({
871
- items: z.array(ProductSchema),
872
- meta: z.object({
873
- total: z.number().int().positive(),
874
- page: z.number().int().positive(),
875
- pageSize: z.number().int().positive(),
876
- hasNextPage: z.boolean()
877
- })
878
- });
879
- var ProductsFiltersSchema = z.object({
880
- category: z.string().optional(),
881
- search: z.string().optional(),
882
- minPrice: z.number().positive().optional(),
883
- maxPrice: z.number().positive().optional(),
884
- inStock: z.boolean().optional(),
885
- sortBy: z.enum(["name", "price", "createdAt"]).optional(),
886
- sortOrder: z.enum(["asc", "desc"]).optional(),
887
- page: z.number().int().positive().optional(),
888
- limit: z.number().int().positive().optional()
889
- });
890
- var StorefrontProductSchema = z.object({
891
- id: z.coerce.string(),
892
- name: z.string(),
893
- slug: z.string(),
894
- productType: z.string().optional().nullable(),
895
- imageUrl: z.string().optional().nullable(),
896
- price: z.number().nonnegative(),
897
- compareAtPrice: z.number().nonnegative().optional().nullable(),
898
- variantCount: z.number().int().nonnegative().optional().default(0),
899
- isAvailable: z.boolean(),
900
- totalInventory: z.number().int().nonnegative(),
901
- bundleItemsCount: z.number().int().nonnegative().optional().default(0),
902
- brand: z.string().optional().nullable(),
903
- category: z.string().optional().nullable(),
904
- status: z.string().optional().nullable(),
905
- tags: z.array(z.string()).optional().nullable()
906
- });
907
- var StorefrontFacetSchema = z.object({
908
- value: z.string(),
909
- count: z.number().int().nonnegative()
910
- });
911
- var StorefrontProductsResponseSchema = z.object({
912
- pageIndex: z.number().int().positive(),
913
- pageSize: z.number().int().positive(),
914
- totalCount: z.number().int().nonnegative(),
915
- totalPages: z.number().int().nonnegative(),
916
- products: z.array(StorefrontProductSchema),
917
- categories: z.array(StorefrontFacetSchema).optional().default([]),
918
- brands: z.array(StorefrontFacetSchema).optional().default([]),
919
- minPrice: z.number().nonnegative().optional().nullable(),
920
- maxPrice: z.number().nonnegative().optional().nullable()
921
- });
922
- var StorefrontProductsParamsSchema = z.object({
923
- page: z.number().int().positive().optional().default(1),
924
- pageSize: z.number().int().positive().optional().default(20),
925
- sort: z.enum(["price_asc", "price_desc", "name_asc", "name_desc", "newest"]).optional().default("price_asc"),
926
- sellerId: z.string().optional(),
927
- search: z.string().optional(),
928
- collection: z.string().optional(),
929
- category: z.string().optional(),
930
- brand: z.string().optional(),
931
- productType: z.string().optional(),
932
- inStock: z.boolean().optional(),
933
- minPrice: z.number().nonnegative().optional(),
934
- maxPrice: z.number().nonnegative().optional()
935
- });
936
- var StorefrontVariantOptionSchema = z.object({
937
- key: z.string(),
938
- name: z.string(),
939
- value: z.string()
940
- });
941
- var StorefrontProductImageSchema = z.object({
942
- url: z.string(),
943
- name: z.string().optional().nullable(),
944
- order: z.number().int().nonnegative().optional()
945
- });
946
- var StorefrontVariantSchema = z.object({
947
- id: z.coerce.string().optional().default(""),
948
- sku: z.string(),
949
- status: z.string().optional().nullable(),
950
- price: z.number().nonnegative(),
951
- compareAtPrice: z.number().nonnegative().optional().nullable(),
952
- quantity: z.number().int().nonnegative(),
953
- options: z.array(StorefrontVariantOptionSchema).optional().default([]),
954
- images: z.array(StorefrontProductImageSchema).optional().default([])
955
- });
956
- var StorefrontPriceTierSchema = z.object({
957
- variantId: z.coerce.string(),
958
- minQuantity: z.number().int().positive(),
959
- maxQuantity: z.number().int().positive().optional().nullable(),
960
- unitPrice: z.number().nonnegative()
961
- });
962
- var StorefrontBundleItemSchema = z.object({
963
- productId: z.coerce.string(),
964
- variantId: z.coerce.string(),
965
- productName: z.string(),
966
- variantName: z.string().optional().nullable(),
967
- sku: z.string().optional().nullable(),
968
- brand: z.string().optional().nullable(),
969
- imageUrl: z.string().optional().nullable(),
970
- quantity: z.number().int(),
971
- availableStock: z.number().int().optional().default(0),
972
- allowBackorders: z.boolean().optional().default(false),
973
- requiresShipping: z.boolean().optional().default(true)
974
- });
975
- var StorefrontProductDetailSchema = z.object({
976
- id: z.coerce.string(),
977
- name: z.string(),
978
- slug: z.string(),
979
- description: z.string().optional().nullable(),
980
- productType: z.string().optional().nullable(),
981
- status: z.string().optional().nullable(),
982
- imageUrl: z.string().optional().nullable(),
983
- price: z.number().nonnegative(),
984
- compareAtPrice: z.number().nonnegative().optional().nullable(),
985
- isAvailable: z.boolean(),
986
- totalInventory: z.number().int().nonnegative(),
987
- brand: z.string().optional().nullable(),
988
- category: z.string().optional().nullable(),
989
- categoryId: z.coerce.string().optional().nullable(),
990
- tags: z.array(z.string()).optional().nullable(),
991
- specifications: z.array(z.record(z.string(), z.unknown())).optional().default([]),
992
- variants: z.array(StorefrontVariantSchema).optional().default([]),
993
- images: z.array(StorefrontProductImageSchema).optional().default([]),
994
- bundleItems: z.array(StorefrontBundleItemSchema).optional().default([]),
995
- priceTiers: z.array(StorefrontPriceTierSchema).optional().default([]),
996
- createdAt: z.string().optional().nullable(),
997
- updatedAt: z.string().optional().nullable()
1147
+ });
1148
+ };
1149
+ return {
1150
+ useStorefrontCollectionsList,
1151
+ useCollectionBySlug,
1152
+ useRefreshStorefrontCollections
1153
+ };
1154
+ }
1155
+ function useStorePages() {
1156
+ const useStorefrontPagesList = () => {
1157
+ return useQuery({
1158
+ queryKey: ["storefront", "pages"],
1159
+ queryFn: () => getStorefrontPages()
1160
+ });
1161
+ };
1162
+ const usePageBySlug = (slug) => {
1163
+ return useQuery({
1164
+ queryKey: ["storefront", "page", "slug", slug],
1165
+ queryFn: () => getStorefrontPageBySlug(slug),
1166
+ enabled: !!slug
1167
+ });
1168
+ };
1169
+ const useRefreshStorefrontPages = () => {
1170
+ const queryClient = useQueryClient();
1171
+ return useMutation({
1172
+ mutationFn: () => getStorefrontPages(),
1173
+ onSuccess: () => {
1174
+ queryClient.invalidateQueries({ queryKey: ["storefront", "pages"] });
1175
+ }
1176
+ });
1177
+ };
1178
+ return {
1179
+ useStorefrontPagesList,
1180
+ usePageBySlug,
1181
+ useRefreshStorefrontPages
1182
+ };
1183
+ }
1184
+ function useStoreCart() {
1185
+ const useGetCart = (cartId) => useQuery({
1186
+ queryKey: ["storefront", "cart", cartId ?? null],
1187
+ queryFn: () => getCart(cartId ?? void 0),
1188
+ // Si devuelve 404 no reintentar; para otros errores solo un intento adicional como máximo.
1189
+ retry: (failureCount, error) => {
1190
+ const status = error.status;
1191
+ if (status === 404) return false;
1192
+ return failureCount < 1;
1193
+ },
1194
+ // Evitar refetch automático al enfocar la ventana; el carrito se carga una sola vez aquí.
1195
+ refetchOnWindowFocus: false,
1196
+ enabled: !!cartId
1197
+ });
1198
+ const useCreateCart = () => useMutation({
1199
+ mutationFn: (data) => createCart(data)
1200
+ });
1201
+ const useUpdateCartBuyer = () => useMutation({
1202
+ mutationFn: ({ data, cartId }) => patchCartBuyer(data, cartId)
1203
+ });
1204
+ const useUpdateCartAddresses = () => useMutation({
1205
+ mutationFn: ({ data, cartId }) => patchCartAddresses(data, cartId)
1206
+ });
1207
+ const useAddCartItem = () => useMutation({
1208
+ mutationFn: ({ cartId, ...data }) => addCartItem(data, cartId)
1209
+ });
1210
+ const useCheckoutCart = () => useMutation({
1211
+ mutationFn: ({ data, cartId }) => checkoutCart(data, cartId)
1212
+ });
1213
+ const useUploadPaymentReceipt = () => useMutation({
1214
+ mutationFn: ({ cartId, file }) => uploadPaymentReceipt(cartId, file)
1215
+ });
1216
+ const useGetCartCheckout = (cartId) => {
1217
+ const inactiveHandledRef = useRef(null);
1218
+ const query = useQuery({
1219
+ queryKey: ["storefront", "cart", cartId ?? null, "checkout"],
1220
+ queryFn: () => getCartCheckout(cartId),
1221
+ retry: (failureCount, error) => {
1222
+ const status = error.status;
1223
+ if (status === 404) return false;
1224
+ if (status === 400 && isCartNotActiveApiError(error)) return false;
1225
+ return failureCount < 1;
1226
+ },
1227
+ /** Evita GET repetidos al cambiar de paso / re-render; `refetch()` sigue forzando actualización tras mutaciones. */
1228
+ staleTime: 6e4,
1229
+ refetchOnMount: false,
1230
+ refetchOnReconnect: false,
1231
+ refetchOnWindowFocus: false,
1232
+ enabled: !!cartId
1233
+ });
1234
+ useEffect(() => {
1235
+ inactiveHandledRef.current = null;
1236
+ }, [cartId]);
1237
+ useEffect(() => {
1238
+ if (!cartId) return;
1239
+ if (!query.isError || !query.error) return;
1240
+ if (!isCartNotActiveApiError(query.error)) return;
1241
+ if (inactiveHandledRef.current === cartId) return;
1242
+ inactiveHandledRef.current = cartId;
1243
+ toast.error(
1244
+ "Este carrito ya no est\xE1 disponible. Se ha vaciado tu bolsa para que puedas empezar de nuevo."
1245
+ );
1246
+ useCart.getState().clearCartSession();
1247
+ }, [cartId, query.isError, query.error]);
1248
+ return query;
1249
+ };
1250
+ const useGetCartPaymentMethods = (cartId) => useQuery({
1251
+ queryKey: ["storefront", "cart", cartId ?? null, "payment-methods"],
1252
+ queryFn: () => getCartPaymentMethods(cartId ?? void 0),
1253
+ retry: (failureCount, error) => {
1254
+ const status = error.status;
1255
+ if (status === 404) return false;
1256
+ return failureCount < 1;
1257
+ },
1258
+ refetchOnWindowFocus: false,
1259
+ enabled: !!cartId
1260
+ });
1261
+ const useGetShippingOptions = (cartId, postalCode, enabled) => useQuery({
1262
+ queryKey: [
1263
+ "storefront",
1264
+ "cart",
1265
+ cartId ?? null,
1266
+ "shipping-options",
1267
+ postalCode ?? ""
1268
+ ],
1269
+ queryFn: () => getShippingOptions(cartId, postalCode),
1270
+ retry: (failureCount, error) => {
1271
+ const status = error.status;
1272
+ if (status === 404) return false;
1273
+ return failureCount < 1;
1274
+ },
1275
+ refetchOnWindowFocus: false,
1276
+ enabled: !!cartId && !!postalCode?.trim() && enabled
1277
+ });
1278
+ const usePutCartShippingMethod = () => useMutation({
1279
+ mutationFn: ({ cartId, data }) => putCartShippingMethod(cartId, data)
1280
+ });
1281
+ const useAddCartCoupon = () => useMutation({
1282
+ mutationFn: ({ cartId, data }) => addCartCoupon(cartId, data)
1283
+ });
1284
+ const useRemoveCartCoupon = () => useMutation({
1285
+ mutationFn: ({ cartId, code }) => removeCartCoupon(cartId, code)
1286
+ });
1287
+ return {
1288
+ useCreateCart,
1289
+ useGetCart,
1290
+ useGetCartCheckout,
1291
+ useUpdateCartBuyer,
1292
+ useUpdateCartAddresses,
1293
+ useAddCartItem,
1294
+ useCheckoutCart,
1295
+ useUploadPaymentReceipt,
1296
+ useGetCartPaymentMethods,
1297
+ useGetShippingOptions,
1298
+ usePutCartShippingMethod,
1299
+ useAddCartCoupon,
1300
+ useRemoveCartCoupon
1301
+ };
1302
+ }
1303
+ var useStore = create()(
1304
+ (set) => ({
1305
+ data: null,
1306
+ drawers: {
1307
+ cart: false,
1308
+ search: false,
1309
+ menu: false,
1310
+ filter: false
1311
+ },
1312
+ openDrawer: (drawer) => set((state) => ({
1313
+ drawers: {
1314
+ ...state.drawers,
1315
+ [drawer]: true
1316
+ }
1317
+ })),
1318
+ closeDrawer: (drawer) => set((state) => ({
1319
+ drawers: {
1320
+ ...state.drawers,
1321
+ [drawer]: false
1322
+ }
1323
+ })),
1324
+ toggleDrawer: (drawer) => set((state) => ({
1325
+ drawers: {
1326
+ ...state.drawers,
1327
+ [drawer]: !state.drawers[drawer]
1328
+ }
1329
+ })),
1330
+ closeAllDrawers: () => set((state) => ({
1331
+ drawers: Object.keys(state.drawers).reduce(
1332
+ (acc, key) => ({ ...acc, [key]: false }),
1333
+ {}
1334
+ )
1335
+ })),
1336
+ modals: {
1337
+ login: false,
1338
+ signup: false
1339
+ },
1340
+ openModal: (modal) => set((state) => ({
1341
+ modals: {
1342
+ ...state.modals,
1343
+ login: false,
1344
+ signup: false,
1345
+ [modal]: true
1346
+ }
1347
+ })),
1348
+ closeModal: (modal) => set((state) => ({
1349
+ modals: {
1350
+ ...state.modals,
1351
+ login: false,
1352
+ signup: false,
1353
+ [modal]: false
1354
+ }
1355
+ })),
1356
+ toggleModal: (modal) => set((state) => ({
1357
+ modals: {
1358
+ ...state.modals,
1359
+ [modal]: !state.modals[modal]
1360
+ }
1361
+ })),
1362
+ closeAllModals: () => set((state) => ({
1363
+ modals: Object.keys(state.modals).reduce(
1364
+ (acc, key) => ({ ...acc, [key]: false }),
1365
+ {}
1366
+ )
1367
+ }))
1368
+ })
1369
+ );
1370
+ var useCart2 = create()(
1371
+ persist(
1372
+ (set) => ({
1373
+ count: 0,
1374
+ cart: [],
1375
+ cartTokenId: null,
1376
+ setCartTokenId: (token) => set((state) => ({ ...state, cartTokenId: token })),
1377
+ checkoutStep: null,
1378
+ setCheckoutStep: (step) => set((state) => ({ ...state, checkoutStep: step })),
1379
+ checkoutCustomerLocal: null,
1380
+ setCheckoutCustomerLocal: (customer) => set((state) => {
1381
+ if (!state.cartTokenId) return state;
1382
+ return {
1383
+ checkoutCustomerLocal: {
1384
+ cartTokenId: state.cartTokenId,
1385
+ customer
1386
+ }
1387
+ };
1388
+ }),
1389
+ clearCheckoutCustomerLocal: () => set(() => ({ checkoutCustomerLocal: null })),
1390
+ addCart: (item) => set((state) => {
1391
+ const existingItem = state.cart.find(
1392
+ (cartItem) => cartItem.id === item.id
1393
+ );
1394
+ if (existingItem) {
1395
+ const newQuantity = Math.max(0, existingItem.quantity) + 1;
1396
+ const cart2 = state.cart.map(
1397
+ (cartItem) => cartItem.id === item.id ? { ...cartItem, quantity: newQuantity } : cartItem
1398
+ );
1399
+ const count2 = cart2.reduce((sum, i) => sum + Math.max(0, i.quantity), 0);
1400
+ return { count: count2, cart: cart2 };
1401
+ }
1402
+ const newItem = {
1403
+ ...item,
1404
+ quantity: Math.max(1, Math.max(0, item.quantity ?? 1))
1405
+ };
1406
+ const cart = [...state.cart, newItem];
1407
+ const count = cart.reduce((sum, i) => sum + Math.max(0, i.quantity), 0);
1408
+ return { count, cart };
1409
+ }),
1410
+ removeCart: (id) => set((state) => {
1411
+ const existingItem = state.cart.find((item) => item.id === id);
1412
+ if (!existingItem) return state;
1413
+ if (existingItem.quantity > 1) {
1414
+ const newQuantity = Math.max(0, existingItem.quantity - 1);
1415
+ const cart2 = state.cart.map(
1416
+ (cartItem) => cartItem.id === id ? { ...cartItem, quantity: newQuantity } : cartItem
1417
+ );
1418
+ const count2 = cart2.reduce((sum, i) => sum + Math.max(0, i.quantity), 0);
1419
+ return { count: count2, cart: cart2 };
1420
+ }
1421
+ const cart = state.cart.filter((item) => item.id !== id);
1422
+ const count = Math.max(0, cart.reduce((sum, i) => sum + Math.max(0, i.quantity), 0));
1423
+ return { count, cart };
1424
+ }),
1425
+ clearCartSession: () => set(() => ({
1426
+ count: 0,
1427
+ cart: [],
1428
+ cartTokenId: null,
1429
+ checkoutStep: null,
1430
+ checkoutCustomerLocal: null
1431
+ }))
1432
+ }),
1433
+ { name: "cart-storage" }
1434
+ )
1435
+ );
1436
+ init_store_api_client();
1437
+ function EcomiqProvider({
1438
+ store,
1439
+ authClient,
1440
+ children,
1441
+ withShellUi = false
1442
+ }) {
1443
+ useStore.setState({ data: store ?? null });
1444
+ useEffect(() => {
1445
+ setClientStoreId(store?.store.id ?? null);
1446
+ return () => setClientStoreId(null);
1447
+ }, [store]);
1448
+ const [queryClient] = useState(() => new QueryClient());
1449
+ const tree = /* @__PURE__ */ jsxs(QueryClientProvider, { client: queryClient, children: [
1450
+ children,
1451
+ withShellUi ? /* @__PURE__ */ jsx(EcomiqShellUi2, {}) : null
1452
+ ] });
1453
+ if (!authClient) return tree;
1454
+ return /* @__PURE__ */ jsx(StorefrontAuthProvider, { authClient, children: tree });
1455
+ }
1456
+ function EcomiqShellUi2() {
1457
+ const [ui, setUi] = useState(null);
1458
+ useEffect(() => {
1459
+ void Promise.resolve().then(() => (init_ecomiq_shell_ui(), ecomiq_shell_ui_exports)).then((mod) => setUi(() => mod.EcomiqShellUi));
1460
+ }, []);
1461
+ return ui ? React2.createElement(ui) : null;
1462
+ }
1463
+
1464
+ // src/core/constants/storefront-ecomiq-oauth-cookie.ts
1465
+ var STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME = "ecomiq_sf_oauth_at";
1466
+ var STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH = "/api/store";
1467
+
1468
+ // src/react/auth/ecomiq-oauth-password-constants.ts
1469
+ var PLUGIN_ID = "ecomiq-oauth-password";
1470
+ var ECOMIQ_OAUTH_TOKEN_URL = "https://auth.ecomiq.pe/connect/token";
1471
+ var ECOMIQ_OAUTH_USERINFO_URL = "https://auth.ecomiq.pe/connect/userinfo";
1472
+ var tokenResponseSchema = z.object({
1473
+ access_token: z.string().min(1),
1474
+ token_type: z.string().optional(),
1475
+ /** Segundos hasta expiración (Ecomiq envía ej. `86399`). Sincroniza la sesión Better Auth con el bearer. */
1476
+ expires_in: z.coerce.number().int().positive().optional()
1477
+ });
1478
+ var userInfoSchema = z.object({
1479
+ sub: z.string(),
1480
+ email: z.string().email().optional(),
1481
+ family_name: z.string().optional(),
1482
+ given_name: z.string().optional(),
1483
+ iss: z.string().optional(),
1484
+ aud: z.union([z.string(), z.array(z.string())]).optional()
1485
+ });
1486
+ var signInBody = z.object({
1487
+ email: z.string().email(),
1488
+ password: z.string().min(1),
1489
+ callbackURL: z.string().optional(),
1490
+ rememberMe: z.boolean().optional().default(true)
998
1491
  });
999
1492
 
1000
- // src/core/services/product.service.ts
1001
- var ProductService = class _ProductService {
1002
- static instance;
1003
- constructor() {
1004
- }
1005
- static getInstance() {
1006
- if (!_ProductService.instance) {
1007
- _ProductService.instance = new _ProductService();
1008
- }
1009
- return _ProductService.instance;
1010
- }
1011
- /**
1012
- * Obtiene todos los productos del store
1013
- */
1014
- async getProducts(filters) {
1015
- if (filters) {
1016
- ProductsFiltersSchema.parse(filters);
1493
+ // src/react/auth/ecomiq-oauth-password-plugin.ts
1494
+ function ecomiqOAuthPassword() {
1495
+ const secureCookie = true;
1496
+ const clearStorefrontOAuthCookieMiddleware = createAuthMiddleware(async (ctx) => {
1497
+ ctx.setCookie(STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, "", {
1498
+ path: STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH,
1499
+ httpOnly: true,
1500
+ sameSite: "lax",
1501
+ secure: secureCookie,
1502
+ maxAge: 0
1503
+ });
1504
+ });
1505
+ return {
1506
+ id: PLUGIN_ID,
1507
+ schema: {
1508
+ user: {
1509
+ fields: {
1510
+ firstName: { type: "string", required: false },
1511
+ lastName: { type: "string", required: false },
1512
+ phone: { type: "string", required: false }
1513
+ }
1514
+ }
1515
+ },
1516
+ hooks: {
1517
+ after: [
1518
+ {
1519
+ matcher: (hookCtx) => hookCtx.path === "/sign-out",
1520
+ handler: clearStorefrontOAuthCookieMiddleware
1521
+ }
1522
+ ]
1523
+ },
1524
+ endpoints: {
1525
+ signIn: createAuthEndpoint(
1526
+ "/ecomiq-oauth/sign-in",
1527
+ {
1528
+ method: "POST",
1529
+ use: [formCsrfMiddleware],
1530
+ body: signInBody
1531
+ },
1532
+ async (ctx) => {
1533
+ const { email: loginEmail, password, callbackURL, rememberMe } = ctx.body;
1534
+ const tokens = await exchangePasswordGrant(loginEmail, password, {
1535
+ identityScope: ctx.getHeader("x-Identity-Scope"),
1536
+ tenantId: ctx.getHeader("x-Tenant-Id"),
1537
+ storeId: ctx.getHeader("x-Store-Id")
1538
+ });
1539
+ const profile = await fetchUserInfo(tokens.access_token);
1540
+ const profileEmail = profile.email?.toLowerCase().trim();
1541
+ const canonicalEmail = profileEmail ?? loginEmail.toLowerCase().trim();
1542
+ if (profileEmail && profileEmail !== loginEmail.toLowerCase().trim()) {
1543
+ throw APIError.from("UNAUTHORIZED", {
1544
+ code: "ECOMIQ_EMAIL_MISMATCH",
1545
+ message: "El correo del perfil OAuth no coincide con el inicio de sesi\xF3n"
1546
+ });
1547
+ }
1548
+ const displayName = displayNameFromUserInfo(profile, canonicalEmail);
1549
+ const existing = await ctx.context.internalAdapter.findUserByEmail(canonicalEmail);
1550
+ let user = existing?.user;
1551
+ if (!user) {
1552
+ user = await ctx.context.internalAdapter.createUser({
1553
+ email: canonicalEmail,
1554
+ name: displayName,
1555
+ emailVerified: true
1556
+ });
1557
+ } else if (user.name !== displayName) {
1558
+ await ctx.context.internalAdapter.updateUser(user.id, { name: displayName });
1559
+ user = { ...user, name: displayName };
1560
+ }
1561
+ const oauthSessionExpires = tokens.expires_in !== void 0 && tokens.expires_in > 0 ? new Date(Date.now() + tokens.expires_in * 1e3) : void 0;
1562
+ const session = await ctx.context.internalAdapter.createSession(
1563
+ user.id,
1564
+ rememberMe === false,
1565
+ oauthSessionExpires ? { expiresAt: oauthSessionExpires } : {},
1566
+ Boolean(oauthSessionExpires)
1567
+ );
1568
+ if (!session) {
1569
+ throw APIError.from("INTERNAL_SERVER_ERROR", {
1570
+ code: "ECOMIQ_SESSION_FAILED",
1571
+ message: "No se pudo crear la sesi\xF3n"
1572
+ });
1573
+ }
1574
+ await setSessionCookie(ctx, { session, user }, rememberMe === false);
1575
+ const oauthMaxAgeSec = oauthSessionExpires !== void 0 ? Math.max(60, Math.ceil((oauthSessionExpires.getTime() - Date.now()) / 1e3)) : tokens.expires_in !== void 0 && tokens.expires_in > 0 ? tokens.expires_in : 60 * 60 * 24;
1576
+ await ctx.setCookie(STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, tokens.access_token, {
1577
+ path: STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH,
1578
+ httpOnly: true,
1579
+ sameSite: "lax",
1580
+ secure: secureCookie,
1581
+ maxAge: oauthMaxAgeSec
1582
+ });
1583
+ if (callbackURL) ctx.setHeader("Location", callbackURL);
1584
+ return ctx.json({
1585
+ redirect: !!callbackURL,
1586
+ token: session.token,
1587
+ url: callbackURL,
1588
+ user: parseUserOutput(ctx.context.options, user)
1589
+ });
1590
+ }
1591
+ )
1017
1592
  }
1018
- const params = new URLSearchParams();
1019
- if (filters) {
1020
- if (filters.category) params.append("category", filters.category);
1021
- if (filters.search) params.append("search", filters.search);
1022
- if (filters.minPrice) params.append("minPrice", filters.minPrice.toString());
1023
- if (filters.maxPrice) params.append("maxPrice", filters.maxPrice.toString());
1024
- if (filters.sortBy) params.append("sortBy", filters.sortBy);
1025
- if (filters.sortOrder) params.append("sortOrder", filters.sortOrder);
1026
- if (filters.page) params.append("page", filters.page.toString());
1027
- if (filters.limit) params.append("limit", filters.limit.toString());
1593
+ };
1594
+ }
1595
+ function displayNameFromUserInfo(profile, fallbackEmail) {
1596
+ const parts = [profile.given_name?.trim(), profile.family_name?.trim()].filter(Boolean);
1597
+ const joined = parts.join(" ").trim();
1598
+ if (joined) return joined;
1599
+ return fallbackEmail.split("@")[0] || "Cliente";
1600
+ }
1601
+ async function fetchUserInfo(accessToken) {
1602
+ const res = await fetch(ECOMIQ_OAUTH_USERINFO_URL, {
1603
+ method: "GET",
1604
+ headers: {
1605
+ Authorization: `Bearer ${accessToken}`,
1606
+ accept: "application/json"
1028
1607
  }
1029
- const queryString = params.toString();
1030
- const url = `/${STOREFRONT_API_PATH_PREFIX}/products${queryString ? `?${queryString}` : ""}`;
1031
- const response = await apiClient.get(url);
1032
- return ProductsResponseSchema.parse(response);
1608
+ });
1609
+ const text = await res.text();
1610
+ let json;
1611
+ try {
1612
+ json = text ? JSON.parse(text) : {};
1613
+ } catch {
1614
+ throw APIError.from("UNAUTHORIZED", {
1615
+ code: "ECOMIQ_USERINFO_INVALID_BODY",
1616
+ message: "Respuesta inv\xE1lida del endpoint userinfo"
1617
+ });
1033
1618
  }
1034
- /**
1035
- * Obtiene un producto específico por ID
1036
- */
1037
- async getProduct(id) {
1038
- const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/products/${id}`);
1039
- return ProductSchema.parse(response);
1619
+ if (!res.ok) {
1620
+ const err = json;
1621
+ throw APIError.from("UNAUTHORIZED", {
1622
+ code: "ECOMIQ_USERINFO_REJECTED",
1623
+ message: err.error_description ?? err.error ?? "No se pudo obtener el perfil del usuario"
1624
+ });
1040
1625
  }
1041
- /**
1042
- * Obtiene un producto específico por slug
1043
- */
1044
- async getProductBySlug(slug) {
1045
- const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/products/${encodeURIComponent(slug)}`);
1046
- return ProductSchema.parse(response);
1626
+ const parsed = userInfoSchema.safeParse(json);
1627
+ if (!parsed.success) {
1628
+ throw APIError.from("UNAUTHORIZED", {
1629
+ code: "ECOMIQ_USERINFO_SHAPE",
1630
+ message: "Perfil OAuth con formato inv\xE1lido"
1631
+ });
1047
1632
  }
1048
- /**
1049
- * Busca productos por término de búsqueda
1050
- */
1051
- async searchProducts(query, filters) {
1052
- return this.getProducts({ ...filters, search: query });
1633
+ return parsed.data;
1634
+ }
1635
+ async function exchangePasswordGrant(username, password, context) {
1636
+ const clientId = process.env.ECOMIQ_AUTH_CLIENT_ID ?? "";
1637
+ const clientSecret = process.env.ECOMIQ_AUTH_CLIENT_SECRET ?? "";
1638
+ const scope = process.env.ECOMIQ_AUTH_SCOPE ?? "";
1639
+ if (!clientId || !clientSecret) {
1640
+ throw APIError.from("INTERNAL_SERVER_ERROR", {
1641
+ code: "ECOMIQ_AUTH_NOT_CONFIGURED",
1642
+ message: "OAuth Ecomiq no configurado: ECOMIQ_AUTH_CLIENT_ID y ECOMIQ_AUTH_CLIENT_SECRET."
1643
+ });
1053
1644
  }
1054
- /**
1055
- * Obtiene productos por categoría
1056
- */
1057
- async getProductsByCategory(category, filters) {
1058
- return this.getProducts({ ...filters, category });
1645
+ const body = new URLSearchParams({
1646
+ grant_type: "password",
1647
+ username,
1648
+ password,
1649
+ scope,
1650
+ client_id: clientId,
1651
+ client_secret: clientSecret
1652
+ });
1653
+ const identityScope = context.identityScope;
1654
+ const tenantId = context.tenantId;
1655
+ const storeId = context.storeId;
1656
+ const headers = new Headers({
1657
+ "content-type": "application/x-www-form-urlencoded",
1658
+ accept: "application/json"
1659
+ });
1660
+ if (identityScope?.trim()) {
1661
+ headers.set("x-Identity-Scope", identityScope.trim());
1059
1662
  }
1060
- /**
1061
- * Obtiene productos en oferta (con descuento)
1062
- */
1063
- async getProductsOnSale(filters) {
1064
- return this.getProducts({ ...filters, minPrice: 0 });
1663
+ if (tenantId?.trim()) {
1664
+ headers.set("x-Tenant-Id", tenantId.trim());
1065
1665
  }
1066
- /**
1067
- * Obtiene productos en stock
1068
- */
1069
- async getProductsInStock(filters) {
1070
- return this.getProducts({ ...filters, inStock: true });
1666
+ if (storeId?.trim()) {
1667
+ headers.set("x-Store-Id", storeId.trim());
1071
1668
  }
1072
- /**
1073
- * Lista de productos del storefront (API v1/storefront/products).
1074
- * Soporta paginación, orden y filtros por categoría, marca y precio.
1075
- */
1076
- async getStorefrontProducts(params) {
1077
- const parsed = StorefrontProductsParamsSchema.parse(params ?? {});
1078
- const searchParams = new URLSearchParams();
1079
- searchParams.set("page", String(parsed.page));
1080
- searchParams.set("pageSize", String(parsed.pageSize));
1081
- if (parsed.sort) searchParams.set("sort", parsed.sort);
1082
- if (parsed.sellerId) searchParams.set("sellerId", parsed.sellerId);
1083
- if (parsed.collection) searchParams.set("collection", parsed.collection);
1084
- if (parsed.category) searchParams.set("category", parsed.category);
1085
- if (parsed.brand) searchParams.set("brand", parsed.brand);
1086
- if (parsed.productType) searchParams.set("productType", parsed.productType);
1087
- if (parsed.inStock != null) searchParams.set("inStock", String(parsed.inStock));
1088
- if (parsed.minPrice != null) searchParams.set("minPrice", String(parsed.minPrice));
1089
- if (parsed.maxPrice != null) searchParams.set("maxPrice", String(parsed.maxPrice));
1090
- if (parsed.search) searchParams.set("search", parsed.search);
1091
- const url = `/${STOREFRONT_API_PATH_PREFIX}/products?${searchParams.toString()}`;
1092
- const response = await apiClient.get(url);
1093
- return StorefrontProductsResponseSchema.parse(response);
1669
+ let res;
1670
+ let text;
1671
+ try {
1672
+ res = await fetch(ECOMIQ_OAUTH_TOKEN_URL, {
1673
+ method: "POST",
1674
+ headers,
1675
+ body
1676
+ });
1677
+ text = await res.text();
1678
+ } catch (e) {
1679
+ throw mapTokenEndpointFetchFailure(e);
1094
1680
  }
1095
- /**
1096
- * Obtiene un producto del storefront por slug (API v1/storefront/products/by-slug/:slug).
1097
- */
1098
- async getStorefrontProductBySlug(slug) {
1099
- const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/products/by-slug/${encodeURIComponent(slug)}`);
1100
- return StorefrontProductDetailSchema.parse(response);
1681
+ const json = safeParseJson(text);
1682
+ if (!res.ok) {
1683
+ throwBadRequestFromOAuth(json, res.statusText || text || `HTTP ${res.status}`);
1101
1684
  }
1102
- };
1103
- var productService = ProductService.getInstance();
1104
- var StorefrontCollectionSchema = z.object({
1105
- id: z.coerce.string(),
1106
- slug: z.string(),
1107
- name: z.string(),
1108
- description: z.string().nullable().optional(),
1109
- imageUrl: z.string().nullable().optional(),
1110
- type: z.string(),
1111
- productCount: z.number().int().nonnegative()
1112
- });
1113
- var StorefrontCollectionsResponseSchema = z.array(StorefrontCollectionSchema);
1114
- var StorefrontCollectionDetailSchema = StorefrontCollectionSchema;
1115
-
1116
- // src/core/services/collection.service.ts
1117
- var CollectionService = class _CollectionService {
1118
- static instance;
1119
- constructor() {
1120
- }
1121
- static getInstance() {
1122
- if (!_CollectionService.instance) {
1123
- _CollectionService.instance = new _CollectionService();
1124
- }
1125
- return _CollectionService.instance;
1685
+ const parsed = tokenResponseSchema.safeParse(json);
1686
+ if (!parsed.success) {
1687
+ throwBadRequestFromOAuth(json, "Token de acceso no recibido");
1126
1688
  }
1127
- /**
1128
- * Lista de colecciones del storefront (GET /v1/collections).
1129
- */
1130
- async getStorefrontCollections() {
1131
- const response = await apiClient.get(
1132
- `/${STOREFRONT_API_PATH_PREFIX}/collections`
1133
- );
1134
- return StorefrontCollectionsResponseSchema.parse(response);
1689
+ return parsed.data;
1690
+ }
1691
+ function safeParseJson(text) {
1692
+ try {
1693
+ return text ? JSON.parse(text) : {};
1694
+ } catch {
1695
+ return {};
1135
1696
  }
1136
- /**
1137
- * Obtiene una colección del storefront por slug (GET /v1/collections/by-slug/:slug).
1138
- */
1139
- async getStorefrontCollectionBySlug(slug) {
1140
- const response = await apiClient.get(
1141
- `/${STOREFRONT_API_PATH_PREFIX}/collections/by-slug/${encodeURIComponent(slug)}`
1142
- );
1143
- return StorefrontCollectionDetailSchema.parse(response);
1697
+ }
1698
+ function throwBadRequestFromOAuth(payload, fallbackMessage) {
1699
+ const err = payload;
1700
+ const errorCode = typeof err.error === "string" && err.error.trim() ? err.error.trim() : "invalid_grant";
1701
+ const errorMessage = typeof err.error_description === "string" && err.error_description.trim() ? err.error_description.trim() : typeof err.error === "string" && err.error.trim() ? err.error.trim() : fallbackMessage.trim() || "Credenciales invalidas.";
1702
+ throw APIError.from("BAD_REQUEST", {
1703
+ code: errorCode,
1704
+ message: errorMessage.slice(0, 500)
1705
+ });
1706
+ }
1707
+ function mapTokenEndpointFetchFailure(e) {
1708
+ const codes = collectNetworkErrorCodes(e);
1709
+ const msg = e instanceof Error ? e.message : String(e);
1710
+ const isDnsError = codes.some((c) => c === "ENOTFOUND" || c === "EAI_AGAIN");
1711
+ if (isDnsError) {
1712
+ throw APIError.from("BAD_GATEWAY", {
1713
+ code: "ECOMIQ_AUTH_DNS",
1714
+ message: "No se pudo resolver el servidor de autenticacion."
1715
+ });
1144
1716
  }
1145
- };
1146
- var collectionService = CollectionService.getInstance();
1147
- var StorefrontPageListItemSchema = z.object({
1148
- id: z.string(),
1149
- name: z.string(),
1150
- slug: z.string(),
1151
- layout: z.string()
1152
- });
1153
- var StorefrontPageSeoSchema = z.object({
1154
- title: z.string().optional(),
1155
- description: z.string().optional()
1156
- }).optional();
1157
- var StorefrontPageSettingsSchema = z.object({
1158
- seo: StorefrontPageSeoSchema,
1159
- html: z.string().optional(),
1160
- title: z.string().optional()
1161
- }).catchall(z.unknown());
1162
- var StorefrontPageBlockSchema = z.object({
1163
- id: z.string(),
1164
- type: z.string(),
1165
- order: z.number(),
1166
- settings: z.record(z.unknown()).optional()
1167
- });
1168
- var StorefrontPageSectionSchema = z.object({
1169
- id: z.string(),
1170
- type: z.string(),
1171
- order: z.number(),
1172
- settings: z.record(z.unknown()).optional(),
1173
- blocks: z.array(StorefrontPageBlockSchema).optional().default([])
1174
- });
1175
- var StorefrontPageDetailSchema = z.object({
1176
- id: z.string(),
1177
- name: z.string(),
1178
- slug: z.string(),
1179
- layout: z.string(),
1180
- settings: StorefrontPageSettingsSchema.optional(),
1181
- sections: z.array(StorefrontPageSectionSchema).optional()
1182
- });
1183
-
1184
- // src/core/services/page.service.ts
1185
- var PageService = class _PageService {
1186
- static instance;
1187
- constructor() {
1188
- }
1189
- static getInstance() {
1190
- if (!_PageService.instance) {
1191
- _PageService.instance = new _PageService();
1192
- }
1193
- return _PageService.instance;
1194
- }
1195
- /**
1196
- * Lista de páginas del storefront (GET /v1/pages).
1197
- */
1198
- async getPages() {
1199
- const response = await apiClient.get(
1200
- `/${STOREFRONT_API_PATH_PREFIX}/pages`
1201
- );
1202
- return z.array(StorefrontPageListItemSchema).parse(response);
1203
- }
1204
- /**
1205
- * Obtiene una página por slug (GET /v1/pages/{slug}).
1206
- * sections puede no venir en la respuesta.
1207
- */
1208
- async getPageBySlug(slug) {
1209
- const response = await apiClient.get(
1210
- `/${STOREFRONT_API_PATH_PREFIX}/pages/${encodeURIComponent(slug)}`
1211
- );
1212
- return StorefrontPageDetailSchema.parse(response);
1717
+ const isConnectionRefused = codes.includes("ECONNREFUSED");
1718
+ if (isConnectionRefused) {
1719
+ throw APIError.from("BAD_GATEWAY", {
1720
+ code: "ECOMIQ_AUTH_REFUSED",
1721
+ message: "Conexion rechazada al servidor de autenticacion."
1722
+ });
1213
1723
  }
1214
- };
1215
- var pageService = PageService.getInstance();
1216
-
1217
- // src/core/services/store.service.ts
1218
- var StoreService = class _StoreService {
1219
- static instance;
1220
- constructor() {
1221
- }
1222
- static getInstance() {
1223
- if (!_StoreService.instance) {
1224
- _StoreService.instance = new _StoreService();
1225
- }
1226
- return _StoreService.instance;
1724
+ const looksLikeAbortOrSocketClose = codes.some(
1725
+ (c) => ["UND_ERR_SOCKET", "ECONNRESET", "EPIPE", "ECONNABORTED"].includes(c)
1726
+ ) || /terminated|abort|closed|FIN|socket/i.test(msg);
1727
+ if (looksLikeAbortOrSocketClose) {
1728
+ throwBadRequestFromOAuth({}, "Credenciales invalidas o conexion cerrada por el servidor.");
1227
1729
  }
1228
- /**
1229
- * Obtiene la configuración de la tienda por subdominio (GET /v1/settings).
1230
- * Usa el header X-Store-Domain. Si se pasa domain, se configura antes de la petición.
1231
- */
1232
- async getStorefrontSettings(domain) {
1233
- if (domain) {
1234
- apiClient.setStoreDomain(domain);
1730
+ throw APIError.from("INTERNAL_SERVER_ERROR", {
1731
+ code: "ECOMIQ_AUTH_REQUEST_FAILED",
1732
+ message: msg.slice(0, 280) || "Error al contactar el servidor de autenticacion."
1733
+ });
1734
+ }
1735
+ function collectNetworkErrorCodes(e) {
1736
+ const out = [];
1737
+ const visit = (x) => {
1738
+ if (!x || typeof x !== "object") return;
1739
+ const code = "code" in x && typeof x.code === "string" ? x.code : void 0;
1740
+ if (code) out.push(code);
1741
+ if ("cause" in x && x.cause) {
1742
+ visit(x.cause);
1235
1743
  }
1236
- const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/settings`);
1237
- return StorefrontSettingsSchema.parse(response);
1238
- }
1239
- };
1240
- var storeService = StoreService.getInstance();
1241
- var CartBuyerRequestSchema = z.object({
1242
- email: z.string().email(),
1243
- firstName: z.string().min(1),
1244
- lastName: z.string().min(1),
1245
- phone: z.string().min(1)
1246
- });
1247
- var CartCreateRequestSchema = z.object({
1248
- currencyCode: z.string(),
1249
- salesChannelId: z.string(),
1250
- email: z.string().email()
1251
- });
1252
- var CartAddressSchema = z.object({
1253
- name: z.string().min(1),
1254
- address1: z.string().min(1),
1255
- city: z.string().min(1),
1256
- countryCode: z.string().min(2),
1257
- company: z.string().nullable().optional(),
1258
- address2: z.string().nullable().optional(),
1259
- province: z.string().nullable().optional(),
1260
- postalCode: z.string().nullable().optional(),
1261
- district: z.string().nullable().optional(),
1262
- phone: z.string().nullable().optional(),
1263
- latitude: z.number().nullable().optional(),
1264
- longitude: z.number().nullable().optional(),
1265
- geo: z.object({
1266
- departmentCode: z.string().nullable().optional(),
1267
- provinceCode: z.string().nullable().optional(),
1268
- districtCode: z.string().nullable().optional()
1269
- }).nullable().optional()
1270
- });
1271
- var CartAddressesRequestSchema = z.object({
1272
- shippingAddress: CartAddressSchema,
1273
- billingAddress: CartAddressSchema
1274
- });
1275
- var CartItemModifierRequestSchema = z.object({
1276
- modifierGroupId: z.coerce.string().min(1),
1277
- optionIds: z.array(z.coerce.string().min(1)).optional().default([])
1744
+ };
1745
+ visit(e);
1746
+ return out;
1747
+ }
1748
+
1749
+ // src/react/auth/ecomiq-oauth-password-client.ts
1750
+ function ecomiqOAuthPasswordClient() {
1751
+ return {
1752
+ id: PLUGIN_ID,
1753
+ pathMethods: {
1754
+ "/ecomiq-oauth/sign-in": "POST"
1755
+ },
1756
+ atomListeners: [
1757
+ {
1758
+ matcher: (path) => path === "/ecomiq-oauth/sign-in",
1759
+ signal: "$sessionSignal"
1760
+ }
1761
+ ]
1762
+ };
1763
+ }
1764
+ var StorefrontCheckoutSettingsSchema = z.object({
1765
+ allowGuestCheckout: z.boolean().optional(),
1766
+ identityScope: z.enum(["store", "tenant", "global"]).optional(),
1767
+ signInMethods: z.array(z.string()).optional()
1278
1768
  });
1279
- var CartItemRequestSchema = z.object({
1280
- variantId: z.coerce.string().min(1),
1281
- quantity: z.number().int().positive(),
1282
- modifiers: z.array(CartItemModifierRequestSchema).optional()
1769
+ var looseRecord = z.record(z.string(), z.unknown());
1770
+ var StorefrontThemeConfigSchema = z.object({
1771
+ name: z.string().nullable().optional(),
1772
+ mode: z.string().nullable().optional(),
1773
+ colors: looseRecord.optional(),
1774
+ fonts: looseRecord.optional(),
1775
+ assets: looseRecord.optional()
1776
+ }).passthrough();
1777
+ var StorefrontFeaturesEnabledSchema = z.object({
1778
+ flags: looseRecord.optional()
1779
+ }).passthrough();
1780
+ var StorefrontCmsBrandingSchema = z.object({
1781
+ logoUrl: z.string().nullable().optional(),
1782
+ logoDarkUrl: z.string().nullable().optional(),
1783
+ faviconUrl: z.string().nullable().optional(),
1784
+ socialImageUrl: z.string().nullable().optional()
1283
1785
  });
1284
- var CartCouponRequestSchema = z.object({
1285
- code: z.string().min(1)
1786
+ var StorefrontCmsSeoSchema = z.object({
1787
+ siteName: z.string().nullable().optional(),
1788
+ metaTitle: z.string().nullable().optional(),
1789
+ metaDescription: z.string().nullable().optional(),
1790
+ titleTemplate: z.string().nullable().optional(),
1791
+ robotsIndex: z.boolean().optional()
1286
1792
  });
1287
- z.object({
1288
- subtotal: z.number(),
1289
- discount: z.number(),
1290
- tax: z.number(),
1291
- warranty: z.number().optional().default(0),
1292
- total: z.number()
1793
+ var StorefrontCmsSocialLinksSchema = z.object({
1794
+ instagram: z.string().nullable().optional(),
1795
+ facebook: z.string().nullable().optional(),
1796
+ tiktok: z.string().nullable().optional(),
1797
+ youtube: z.string().nullable().optional(),
1798
+ x: z.string().nullable().optional()
1293
1799
  });
1294
- z.object({
1295
- name: z.string().nullable().optional(),
1296
- address1: z.string(),
1297
- city: z.string(),
1298
- countryCode: z.string(),
1299
- company: z.string().nullable().optional(),
1300
- address2: z.string().nullable().optional(),
1301
- province: z.string().nullable().optional(),
1302
- postalCode: z.string().nullable().optional(),
1303
- district: z.string().nullable().optional(),
1800
+ var StorefrontCmsContactSchema = z.object({
1801
+ supportEmail: z.string().nullable().optional(),
1304
1802
  phone: z.string().nullable().optional(),
1305
- latitude: z.number().nullable().optional(),
1306
- longitude: z.number().nullable().optional(),
1307
- geo: z.object({
1308
- departmentCode: z.string().nullable().optional(),
1309
- provinceCode: z.string().nullable().optional(),
1310
- districtCode: z.string().nullable().optional()
1311
- }).nullable().optional()
1803
+ whatsapp: z.string().nullable().optional(),
1804
+ address: z.string().nullable().optional(),
1805
+ socialLinks: StorefrontCmsSocialLinksSchema.optional()
1312
1806
  });
1313
- var CartResponseBundleItemSchema = z.object({
1314
- productId: z.coerce.string(),
1315
- variantId: z.coerce.string(),
1316
- productName: z.string(),
1317
- variantName: z.string().nullable().optional(),
1318
- sku: z.string().nullable().optional(),
1319
- brand: z.string().nullable().optional(),
1320
- imageUrl: z.string().nullable().optional(),
1321
- quantity: z.number().int()
1807
+ var StorefrontCmsTrackingSchema = z.object({
1808
+ googleAnalyticsMeasurementId: z.string().nullable().optional(),
1809
+ metaPixelId: z.string().nullable().optional(),
1810
+ googleTagManagerContainerId: z.string().nullable().optional()
1322
1811
  });
1323
- var CartResponseItemSchema = z.object({
1324
- id: z.string(),
1325
- title: z.string(),
1326
- variantLabel: z.string().nullable().optional(),
1327
- thumbnail: z.string().nullable().optional(),
1328
- quantity: z.number().int(),
1329
- variantId: z.coerce.string(),
1330
- variantSku: z.string().nullable().optional(),
1331
- unitPrice: z.number(),
1332
- bundleItems: z.array(CartResponseBundleItemSchema).optional().default([])
1812
+ var StorefrontCmsCustomScriptsSchema = z.object({
1813
+ enabled: z.boolean().optional(),
1814
+ head: z.string().nullable().optional(),
1815
+ bodyEnd: z.string().nullable().optional()
1333
1816
  });
1334
- z.object({
1817
+ var StorefrontCmsSettingsSchema = z.object({
1818
+ themeKey: z.string().optional(),
1819
+ branding: StorefrontCmsBrandingSchema.optional(),
1820
+ seo: StorefrontCmsSeoSchema.optional(),
1821
+ contact: StorefrontCmsContactSchema.optional(),
1822
+ tracking: StorefrontCmsTrackingSchema.optional(),
1823
+ customScripts: StorefrontCmsCustomScriptsSchema.optional(),
1824
+ updatedOn: z.string().nullable().optional()
1825
+ });
1826
+ var StorefrontCmsPageSchema = z.object({
1335
1827
  id: z.string(),
1336
1828
  name: z.string(),
1829
+ slug: z.string(),
1830
+ layout: z.string().optional(),
1831
+ version: z.number().optional(),
1832
+ settings: z.record(z.string(), z.unknown()).optional().nullable(),
1833
+ sections: z.array(z.unknown()).optional(),
1834
+ status: z.string().optional(),
1835
+ hasPublishedVersion: z.boolean().optional(),
1836
+ publishedOn: z.string().nullable().optional(),
1837
+ publishedBy: z.string().nullable().optional(),
1838
+ createdOn: z.string().nullable().optional(),
1839
+ updatedOn: z.string().nullable().optional(),
1840
+ createdBy: z.string().nullable().optional(),
1841
+ updatedBy: z.string().nullable().optional(),
1842
+ lastModifiedBy: z.string().nullable().optional()
1843
+ }).passthrough();
1844
+ var StorefrontSettingsLegacyFlatSchema = z.object({
1845
+ id: z.coerce.string(),
1846
+ tenantId: z.string().nullable().optional(),
1847
+ name: z.string(),
1848
+ slug: z.coerce.string().optional(),
1337
1849
  description: z.string().nullable().optional(),
1338
- total: z.number(),
1339
- estimatedDays: z.number().int().nullable().optional(),
1340
- pickupPointId: z.string().nullable().optional(),
1341
- scheduledDate: z.string().nullable().optional(),
1342
- scheduledTime: z.string().nullable().optional()
1343
- });
1344
- var CartResponseSchema = z.object({
1345
- id: z.string(),
1346
- regionId: z.string().nullable().optional(),
1347
- salesChannelId: z.string().nullable().optional(),
1348
- email: z.string().email().nullable().optional(),
1349
- phone: z.string().nullable().optional(),
1350
- firstName: z.string().nullable().optional(),
1351
- lastName: z.string().nullable().optional(),
1352
- currencyCode: z.string(),
1353
- completedAt: z.string().nullable().optional(),
1354
- shippingAddress: z.unknown().nullable().optional(),
1355
- billingAddress: z.unknown().nullable().optional(),
1356
- metadata: z.record(z.string(), z.unknown()).optional().default({}),
1357
- promotionCodes: z.array(z.string()).optional().default([]),
1358
- items: z.array(CartResponseItemSchema).optional().default([]),
1359
- shippingMethods: z.array(z.unknown()).optional().default([]),
1360
- totals: z.object({
1361
- discountTotal: z.number(),
1362
- shippingTotal: z.number(),
1363
- subtotal: z.number(),
1364
- taxTotal: z.number(),
1365
- total: z.number(),
1366
- warrantyTotal: z.number()
1367
- })
1368
- });
1369
- var CartCheckoutRequestSchema = z.object({
1370
- paymentMethodCode: z.string().min(1),
1371
- externalRef: z.string().min(1),
1372
- receiptUrl: z.string().min(1).optional()
1373
- });
1374
- var CartCheckoutPaymentActionSchema = z.object({
1375
- publicConfiguration: z.object({
1376
- publishableKey: z.string().nullable().optional(),
1377
- checkoutMode: z.string().nullable().optional(),
1378
- phoneNumber: z.string().nullable().optional(),
1379
- accountHolder: z.string().nullable().optional(),
1380
- qrImageUrl: z.string().nullable().optional()
1381
- }).passthrough().nullable().optional(),
1382
- url: z.string().nullable().optional(),
1383
- html: z.string().nullable().optional(),
1384
- clientSecret: z.string().nullable().optional(),
1385
- qrCode: z.string().nullable().optional(),
1386
- expiresAt: z.string().nullable().optional()
1387
- }).passthrough();
1388
- var CartCheckoutPaymentSchema = z.object({
1389
- transactionId: z.string(),
1390
- paymentMethodCode: z.string(),
1391
- providerId: z.string().nullable().optional(),
1392
- status: z.string(),
1393
- amount: z.number(),
1394
- reference: z.string(),
1395
- actionType: z.string(),
1396
- receiptUrl: z.string().nullable().optional(),
1397
- action: CartCheckoutPaymentActionSchema.nullable().optional()
1398
- }).passthrough();
1399
- var CartCheckoutResponseSchema = z.object({
1400
- publicKey: z.string().optional(),
1401
- publishableKey: z.string().optional(),
1402
- stripePublicKey: z.string().optional(),
1403
- clientSecret: z.string().optional(),
1404
- intentClientSecret: z.string().optional(),
1405
- orderId: z.coerce.string().optional(),
1406
- orderGroup: z.string().optional(),
1407
- orderIds: z.array(z.coerce.string()).optional(),
1408
- /** Payload de pago (embedded, redirect, etc.) */
1409
- payment: CartCheckoutPaymentSchema.optional(),
1410
- cart: z.unknown().optional()
1850
+ visibility: z.string().nullable().optional(),
1851
+ logo: z.string().nullable().optional(),
1852
+ favicon: z.string().nullable().optional(),
1853
+ icon: z.string().nullable().optional(),
1854
+ currency: z.string().nullable().optional(),
1855
+ language: z.string().nullable().optional(),
1856
+ themeConfig: z.unknown().optional().nullable(),
1857
+ featuresEnabled: z.unknown().optional().nullable(),
1858
+ checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
1411
1859
  }).passthrough();
1412
- var CartPaymentReceiptResponseSchema = z.object({
1860
+ function unwrapSettingsResponseBody(v) {
1861
+ if (!v || typeof v !== "object" || Array.isArray(v)) return v;
1862
+ const o = v;
1863
+ if ("data" in o && o.data != null && typeof o.data === "object" && !Array.isArray(o.data)) {
1864
+ return o.data;
1865
+ }
1866
+ return v;
1867
+ }
1868
+ function isLegacyFlatSettingsPayload(v) {
1869
+ if (!v || typeof v !== "object" || Array.isArray(v)) return false;
1870
+ const o = v;
1871
+ if ("store" in o || "schemaVersion" in o || "cms" in o) return false;
1872
+ return (typeof o.id === "string" || typeof o.id === "number") && typeof o.name === "string";
1873
+ }
1874
+ function normalizeStorefrontSettingsPayload(v) {
1875
+ const body = unwrapSettingsResponseBody(v);
1876
+ if (!isLegacyFlatSettingsPayload(body)) return body;
1877
+ const raw = body;
1878
+ const parsed = StorefrontSettingsLegacyFlatSchema.safeParse(raw);
1879
+ if (!parsed.success) return body;
1880
+ const l = parsed.data;
1881
+ const currency = l.currency?.trim() ? l.currency : "PEN";
1882
+ const language = l.language?.trim() ? l.language : "es";
1883
+ const slug = l.slug?.trim() ? l.slug : l.id;
1884
+ return {
1885
+ schemaVersion: 0,
1886
+ generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
1887
+ store: {
1888
+ id: l.id,
1889
+ tenantId: l.tenantId ?? void 0,
1890
+ name: l.name,
1891
+ slug,
1892
+ description: l.description ?? null,
1893
+ logo: l.logo ?? null,
1894
+ icon: l.icon ?? null,
1895
+ visibility: l.visibility ?? void 0,
1896
+ currency,
1897
+ language,
1898
+ themeConfig: l.themeConfig ?? void 0,
1899
+ featuresEnabled: l.featuresEnabled ?? void 0,
1900
+ checkoutSettings: l.checkoutSettings ?? void 0
1901
+ },
1902
+ cms: {
1903
+ settings: {
1904
+ branding: {
1905
+ faviconUrl: l.favicon ?? null,
1906
+ logoUrl: l.logo ?? null,
1907
+ logoDarkUrl: null,
1908
+ socialImageUrl: null
1909
+ }
1910
+ },
1911
+ pages: []
1912
+ }
1913
+ };
1914
+ }
1915
+ var StorefrontStoreSchema = z.object({
1413
1916
  id: z.string(),
1414
- url: z.string()
1415
- });
1416
- var CartPaymentMethodSchema = z.object({
1417
- code: z.string(),
1418
- name: z.string(),
1419
- description: z.string().nullable().optional(),
1420
- kind: z.string(),
1421
- isActive: z.boolean(),
1422
- isDefault: z.boolean(),
1423
- isManual: z.boolean(),
1424
- sortOrder: z.number(),
1425
- phoneNumber: z.string().nullable().optional(),
1426
- accountHolder: z.string().nullable().optional(),
1427
- qrImageUrl: z.string().nullable().optional()
1428
- });
1429
- var CartPaymentMethodsResponseSchema = z.object({
1430
- methods: z.array(CartPaymentMethodSchema)
1431
- });
1432
- var CartCheckoutReadResponseSchema = z.object({
1433
- cart: CartResponseSchema,
1434
- paymentMethods: CartPaymentMethodsResponseSchema
1435
- });
1436
- var ShippingRateSchema = z.object({
1437
- shippingMethodId: z.string(),
1917
+ tenantId: z.string().optional(),
1918
+ sellerId: z.string().optional(),
1919
+ plan: z.string().optional(),
1920
+ storageLimitBytes: z.number().optional(),
1921
+ monthlyTransferLimitBytes: z.number().optional(),
1922
+ maxUploadSizeBytes: z.number().optional(),
1923
+ maxStores: z.number().optional(),
1924
+ maxMembers: z.number().optional(),
1925
+ maxProducts: z.number().optional(),
1926
+ maxCategories: z.number().optional(),
1927
+ maxBrands: z.number().optional(),
1928
+ maxAttributes: z.number().optional(),
1929
+ maxCollections: z.number().optional(),
1930
+ enableApi: z.boolean().optional(),
1931
+ isActive: z.boolean().optional(),
1438
1932
  name: z.string(),
1439
- displayName: z.string().optional(),
1440
- type: z.string().optional(),
1441
- price: z.number(),
1442
- currency: z.string().optional(),
1443
- sortOrder: z.number().optional(),
1444
- rateId: z.string(),
1445
1933
  description: z.string().nullable().optional(),
1446
- deliveryLocationId: z.string().nullable().optional(),
1447
- deliveryLocationName: z.string().nullable().optional(),
1448
- estimatedDeliveryDays: z.number().nullable().optional(),
1449
- serviceCode: z.string().nullable().optional(),
1450
- metadata: z.record(z.string(), z.unknown()).optional()
1934
+ avatarUrl: z.string().nullable().optional(),
1935
+ logo: z.string().nullable().optional(),
1936
+ icon: z.string().nullable().optional(),
1937
+ slug: z.string(),
1938
+ domain: z.string().nullable().optional(),
1939
+ domains: z.array(z.string()).optional(),
1940
+ timeZone: z.string().nullable().optional(),
1941
+ currency: z.string(),
1942
+ language: z.string(),
1943
+ visibility: z.string().optional(),
1944
+ privateAccessHash: z.string().nullable().optional(),
1945
+ privateAccessVersion: z.number().optional(),
1946
+ themeConfig: StorefrontThemeConfigSchema.optional(),
1947
+ featuresEnabled: StorefrontFeaturesEnabledSchema.optional(),
1948
+ checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
1451
1949
  }).passthrough();
1452
- var ShippingOptionGroupSchema = z.object({
1453
- sellerId: z.string(),
1454
- shippingProfileId: z.string().nullable().optional(),
1455
- orderAmount: z.number().optional(),
1456
- totalWeight: z.number().optional(),
1457
- itemIds: z.array(z.string()).optional(),
1458
- rates: z.array(ShippingRateSchema)
1950
+ var StorefrontSettingsEnvelopeSchema = z.object({
1951
+ schemaVersion: z.number(),
1952
+ generatedAt: z.string(),
1953
+ store: StorefrontStoreSchema,
1954
+ cms: z.object({
1955
+ settings: StorefrontCmsSettingsSchema,
1956
+ pages: z.array(StorefrontCmsPageSchema)
1957
+ })
1459
1958
  }).passthrough();
1460
- var ShippingOptionsResponseSchema = z.object({
1461
- groups: z.array(ShippingOptionGroupSchema)
1462
- });
1463
- var CartShippingMethodPutRequestSchema = z.object({
1464
- rateId: z.string().min(1),
1465
- shippingMethodId: z.string().min(1),
1466
- serviceCode: z.string().nullable().optional(),
1467
- sellerId: z.string().nullable().optional(),
1468
- shippingProfileId: z.string().nullable().optional(),
1469
- locationId: z.string().nullable().optional(),
1470
- pickupPointId: z.string().nullable().optional(),
1471
- scheduledDate: z.string().nullable().optional(),
1472
- scheduledTime: z.string().nullable().optional()
1473
- });
1959
+ var StorefrontSettingsSchema3 = z.preprocess(
1960
+ normalizeStorefrontSettingsPayload,
1961
+ StorefrontSettingsEnvelopeSchema
1962
+ );
1963
+ function storefrontStoreRecord(settings) {
1964
+ return settings?.store ?? null;
1965
+ }
1474
1966
 
1475
- // src/core/services/cart.service.ts
1476
- var CartService = class _CartService {
1477
- static instance;
1478
- constructor() {
1479
- }
1480
- static getInstance() {
1481
- if (!_CartService.instance) {
1482
- _CartService.instance = new _CartService();
1483
- }
1484
- return _CartService.instance;
1485
- }
1486
- /**
1487
- * Obtiene el carrito actual (GET /v1/carts).
1488
- */
1489
- async getCart() {
1490
- const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/carts`);
1491
- return CartResponseSchema.parse(response);
1492
- }
1493
- /**
1494
- * Crea un carrito nuevo (POST /v1/carts).
1495
- */
1496
- async createCart(data) {
1497
- const payload = CartCreateRequestSchema.parse(data);
1498
- const response = await apiClient.post(`/${STOREFRONT_API_PATH_PREFIX}/carts`, payload);
1499
- return CartResponseSchema.parse(response);
1500
- }
1501
- /**
1502
- * Actualiza los datos del comprador del carrito actual (PATCH /v1/carts/buyer).
1503
- * El carrito se resuelve en backend vía contexto (token/guest), por eso no requiere cartId.
1504
- */
1505
- async updateBuyer(data) {
1506
- const payload = CartBuyerRequestSchema.parse(data);
1507
- const response = await apiClient.patch(`/${STOREFRONT_API_PATH_PREFIX}/carts/buyer`, payload);
1508
- return CartResponseSchema.parse(response);
1509
- }
1510
- /**
1511
- * Actualiza direcciones de envío y facturación del carrito (PATCH /v1/carts/addresses).
1512
- */
1513
- async updateAddresses(data) {
1514
- const payload = CartAddressesRequestSchema.parse(data);
1515
- const response = await apiClient.patch(`/${STOREFRONT_API_PATH_PREFIX}/carts/addresses`, payload);
1516
- return CartResponseSchema.parse(response);
1517
- }
1518
- /**
1519
- * Inicializa/obtiene detalles del método de pago para el checkout (POST /v1/carts/checkout).
1520
- * Usado para providers como Stripe (public key, client secret, etc).
1521
- */
1522
- async checkout(data) {
1523
- const payload = CartCheckoutRequestSchema.parse(data);
1524
- const response = await apiClient.post(`/${STOREFRONT_API_PATH_PREFIX}/carts/checkout`, payload);
1525
- return CartCheckoutResponseSchema.parse(response);
1967
+ // src/core/lib/ecomiq-oauth-identity.ts
1968
+ function buildEcomiqOAuthIdentityHeaders(settings) {
1969
+ const record = storefrontStoreRecord(settings);
1970
+ if (!record?.id) {
1971
+ throw new Error("Tienda no disponible para iniciar sesi\xF3n");
1526
1972
  }
1527
- };
1528
- var cartService = CartService.getInstance();
1529
- var ECOMIQ_APP_APEX = "ecomiq.app";
1530
- var ECOMIQ_APP_SUFFIX = [`.${ECOMIQ_APP_APEX}`, `.localhost`];
1531
- function normalizeStoreHost(hostHeader) {
1532
- let h = hostHeader.trim().toLowerCase();
1533
- const colon = h.indexOf(":");
1534
- if (colon !== -1) h = h.slice(0, colon);
1535
- if (h.startsWith("www.")) h = h.slice(4);
1536
- return h;
1537
- }
1538
- function resolveStorefrontSettingsHost(hostHeader) {
1539
- const host = normalizeStoreHost(hostHeader);
1540
- if (!host) {
1541
- throw Object.assign(new Error("Host inv\xE1lido para tienda"), { status: 400 });
1542
- }
1543
- if (host === ECOMIQ_APP_APEX) {
1544
- throw Object.assign(new Error("Host apex ecomiq.app sin slug de tienda"), { status: 400 });
1545
- }
1546
- if (ECOMIQ_APP_SUFFIX.some((suffix) => host.endsWith(suffix))) {
1547
- const slug = host.slice(0, -(ECOMIQ_APP_SUFFIX.find((suffix) => host.endsWith(suffix))?.length ?? 0));
1548
- if (!slug) {
1549
- throw Object.assign(new Error("Host sin slug para ecomiq.app"), { status: 400 });
1550
- }
1551
- return slug;
1552
- }
1553
- return host;
1973
+ const checkout = record.checkoutSettings;
1974
+ const identityScope = checkout?.identityScope === "tenant" ? "tenant" : "store";
1975
+ const headers = {
1976
+ "x-Identity-Scope": identityScope,
1977
+ "x-Store-Id": record.id
1978
+ };
1979
+ if (record.tenantId) headers["x-Tenant-Id"] = record.tenantId;
1980
+ return headers;
1554
1981
  }
1555
1982
 
1556
- // src/core/config/ecomiq-config.ts
1557
- var CONFIG_FILENAMES = [
1558
- "ecomiq.config.js",
1559
- "ecomiq.config.cjs",
1560
- "ecomiq.config.mjs"
1561
- ];
1562
- var EcomiqConfigSchema = z.object({
1563
- /**
1564
- * Slug de tienda en Ecomiq (p. ej. `mi-tienda` para `mi-tienda.ecomiq.app`).
1565
- * Si está definido, tiene prioridad sobre el `Host` de la request (útil en `localhost`).
1566
- */
1567
- slugStore: z.string().min(1).optional()
1568
- });
1569
- var cachedConfig;
1570
- function parseExportedConfig(raw) {
1571
- const candidate = raw && typeof raw === "object" && "default" in raw ? raw.default : raw;
1572
- const parsed = EcomiqConfigSchema.safeParse(candidate);
1573
- if (!parsed.success) {
1574
- console.warn(
1575
- "[ecomiq] ecomiq.config.* inv\xE1lido:",
1576
- parsed.error.flatten().fieldErrors
1577
- );
1578
- return null;
1983
+ // src/react/auth/ecomiq-storefront-sign-in.ts
1984
+ async function signInWithEcomiqCredentials2(authClient, settings, credentials) {
1985
+ const response = await authClient.$fetch("/ecomiq-oauth/sign-in", {
1986
+ method: "POST",
1987
+ headers: buildEcomiqOAuthIdentityHeaders(settings),
1988
+ body: credentials
1989
+ });
1990
+ if (response.error) {
1991
+ throw new Error(response.error.message ?? "Error al iniciar sesi\xF3n");
1579
1992
  }
1580
- const slugStore = parsed.data.slugStore?.trim();
1581
- return slugStore ? { slugStore } : {};
1993
+ return response;
1582
1994
  }
1583
- function loadEcomiqConfig(cwd = process.cwd()) {
1584
- if (cachedConfig !== void 0) return cachedConfig;
1585
- for (const filename of CONFIG_FILENAMES) {
1586
- const configPath = join(cwd, filename);
1587
- if (!existsSync(configPath)) continue;
1588
- try {
1589
- const requireFromApp = createRequire(join(cwd, "package.json"));
1590
- const loaded = requireFromApp(configPath);
1591
- const parsed = parseExportedConfig(loaded);
1592
- cachedConfig = parsed;
1593
- return cachedConfig;
1594
- } catch (error) {
1595
- console.warn(`[ecomiq] No se pudo cargar ${configPath}:`, error);
1596
- }
1597
- }
1598
- cachedConfig = null;
1599
- return null;
1995
+ function isRenderableCmsPage(p) {
1996
+ if (!p.status) return true;
1997
+ return p.status === "published";
1600
1998
  }
1601
- function clearEcomiqConfigCache() {
1602
- cachedConfig = void 0;
1999
+ function findStorefrontCmsPageBySlug(settings, slug) {
2000
+ const pages = settings?.cms?.pages;
2001
+ if (!pages?.length) return null;
2002
+ const raw = pages.find(
2003
+ (p) => p.slug === slug && isRenderableCmsPage(p)
2004
+ );
2005
+ if (!raw) return null;
2006
+ const parsed = StorefrontPageDetailSchema$1.safeParse(raw);
2007
+ return parsed.success ? parsed.data : null;
1603
2008
  }
1604
- function resolvePublicStoreKey(hostHeader, cwd) {
1605
- const slugFromConfig = loadEcomiqConfig(cwd)?.slugStore?.trim();
1606
- if (slugFromConfig) return slugFromConfig;
1607
- if (!hostHeader?.trim()) {
1608
- throw Object.assign(
1609
- new Error(
1610
- "Host is required, o define slugStore en ecomiq.config.js en la ra\xEDz del proyecto"
1611
- ),
1612
- { status: 400 }
1613
- );
2009
+ function buildOptionGroups(variants) {
2010
+ const map = /* @__PURE__ */ new Map();
2011
+ for (const v of variants) {
2012
+ for (const opt of v.options ?? []) {
2013
+ const key = opt.key;
2014
+ const name = opt.name ?? key;
2015
+ if (!map.has(key)) map.set(key, /* @__PURE__ */ new Map());
2016
+ map.get(key).set(opt.value, name);
2017
+ }
1614
2018
  }
1615
- return resolveStorefrontSettingsHost(hostHeader);
1616
- }
1617
- function hasEcomiqSlugStoreConfig(cwd) {
1618
- return Boolean(loadEcomiqConfig(cwd)?.slugStore?.trim());
2019
+ return Array.from(map.entries()).map(([key, valueMap]) => ({
2020
+ key,
2021
+ name: Array.from(valueMap.values())[0] ?? key,
2022
+ values: Array.from(valueMap.keys())
2023
+ }));
1619
2024
  }
1620
- var defaultOptions = {
1621
- queries: {
1622
- staleTime: 60 * 1e3
2025
+ function findVariant(variants, selected, hasConfigurableOptions) {
2026
+ if (!hasConfigurableOptions && variants.length > 0) {
2027
+ return variants[0] ?? null;
1623
2028
  }
1624
- };
1625
- function QueryProvider({ children, dehydratedState }) {
1626
- const queryClientRef = useRef(null);
1627
- const hydratedRef = useRef(false);
1628
- if (queryClientRef.current === null) {
1629
- queryClientRef.current = new QueryClient({ defaultOptions });
2029
+ if (Object.keys(selected).length === 0) return null;
2030
+ for (const v of variants) {
2031
+ const opts = v.options ?? [];
2032
+ const match = opts.length > 0 && opts.every((o) => selected[o.key] === o.value);
2033
+ if (match) return v;
1630
2034
  }
1631
- const queryClient = queryClientRef.current;
1632
- useEffect(() => {
1633
- if (dehydratedState && !hydratedRef.current) {
1634
- hydrate(queryClient, dehydratedState);
1635
- hydratedRef.current = true;
1636
- }
1637
- }, [queryClient, dehydratedState]);
1638
- return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children });
1639
- }
1640
- var StorefrontAuthContext = createContext(null);
1641
- function StorefrontAuthProvider({
1642
- authClient,
1643
- children
1644
- }) {
1645
- return /* @__PURE__ */ jsx(StorefrontAuthContext.Provider, { value: authClient, children });
2035
+ return null;
1646
2036
  }
1647
- function useStorefrontAuthClient() {
1648
- const client = useContext(StorefrontAuthContext);
1649
- if (!client) {
1650
- throw new Error(
1651
- "useStorefrontAuthClient debe usarse dentro de StorefrontAuthProvider (o EcomiqProvider con authClient)."
1652
- );
2037
+ function getInitialOptions(variants, optionGroups) {
2038
+ const first = variants[0];
2039
+ if (!first) return {};
2040
+ const opts = first.options ?? [];
2041
+ const selected = {};
2042
+ for (const g of optionGroups) {
2043
+ const o = opts.find((x) => x.key === g.key);
2044
+ if (o) selected[g.key] = o.value;
1653
2045
  }
1654
- return client;
2046
+ return selected;
1655
2047
  }
1656
- function storefrontSessionEndsSoon(expiresAt, skewMs = 12e4) {
1657
- if (!expiresAt) return false;
1658
- return Date.now() + skewMs >= expiresAt.getTime();
2048
+ function ProductVariantSelector({
2049
+ product,
2050
+ currency = "USD",
2051
+ features = [],
2052
+ onVariantChange,
2053
+ children
2054
+ }) {
2055
+ const variants = useMemo(() => product.variants ?? [], [product.variants]);
2056
+ const optionGroups = useMemo(() => buildOptionGroups(variants), [variants]);
2057
+ const hasConfigurableOptions = optionGroups.length > 0;
2058
+ const [selectedOptions, setSelectedOptions] = useState(
2059
+ () => getInitialOptions(variants, optionGroups)
2060
+ );
2061
+ const selectedVariant = useMemo(
2062
+ () => findVariant(variants, selectedOptions, hasConfigurableOptions),
2063
+ [variants, selectedOptions, hasConfigurableOptions]
2064
+ );
2065
+ const displayPrice = selectedVariant?.price ?? product.price ?? 0;
2066
+ const compareAtPrice = selectedVariant?.compareAtPrice ?? product.compareAtPrice;
2067
+ const isAvailable = (selectedVariant ? (selectedVariant.quantity ?? 0) > 0 : product.isAvailable) ?? true;
2068
+ useEffect(() => {
2069
+ onVariantChange?.(selectedVariant, displayPrice);
2070
+ }, [selectedVariant, displayPrice, onVariantChange]);
2071
+ const setOption = useCallback((key, value) => {
2072
+ setSelectedOptions((prev) => ({ ...prev, [key]: value }));
2073
+ }, []);
2074
+ const hasVariants = hasConfigurableOptions;
2075
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
2076
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
2077
+ /* @__PURE__ */ jsx(
2078
+ "span",
2079
+ {
2080
+ className: "inline-flex items-center rounded-md bg-primary/10 px-2.5 py-0.5 text-base font-semibold text-primary",
2081
+ "data-testid": "product-display-price",
2082
+ children: formatCurrency(displayPrice, currency)
2083
+ }
2084
+ ),
2085
+ compareAtPrice != null && compareAtPrice > displayPrice && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground line-through", children: formatCurrency(compareAtPrice, currency) })
2086
+ ] }),
2087
+ hasVariants && optionGroups.map((group) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2088
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: group.name }),
2089
+ /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: group.values.map((value) => {
2090
+ const isSelected = selectedOptions[group.key] === value;
2091
+ const isColorLike = group.key.toLowerCase().includes("color") || group.key.toLowerCase().includes("colour");
2092
+ return /* @__PURE__ */ jsx(
2093
+ "button",
2094
+ {
2095
+ type: "button",
2096
+ onClick: () => setOption(group.key, value),
2097
+ className: isColorLike ? `min-w-[72px] rounded-md border-2 px-3 py-2 text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 ${isSelected ? "border-primary bg-primary text-foreground" : "border-border bg-muted/30 text-foreground hover:border-muted-foreground/50"}` : `rounded-md border px-3 py-2 text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 ${isSelected ? "border-primary bg-muted ring-1 ring-primary" : "border-border bg-transparent text-muted-foreground hover:border-muted-foreground/50 hover:text-foreground"}`,
2098
+ style: isColorLike && isSelected && value.toLowerCase() === "black" ? { backgroundColor: "#1a1a1a", borderColor: "#1a1a1a", color: "#fff" } : isColorLike && value.toLowerCase() === "white" ? { backgroundColor: "#fafafa", color: "#1a1a1a", borderColor: "#e5e5e5" } : void 0,
2099
+ "data-testid": `variant-option-${group.key}-${value}`,
2100
+ children: value
2101
+ },
2102
+ value
2103
+ );
2104
+ }) })
2105
+ ] }, group.key)),
2106
+ features.length > 0 && /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside space-y-1 text-sm text-muted-foreground", children: features.map((f, i) => /* @__PURE__ */ jsx("li", { children: f }, i)) }),
2107
+ children?.({
2108
+ product,
2109
+ selectedVariant,
2110
+ displayPrice,
2111
+ compareAtPrice,
2112
+ isAvailable,
2113
+ selectedOptions
2114
+ })
2115
+ ] });
1659
2116
  }
1660
- var storefrontAccessTokenNeedsRefresh = storefrontSessionEndsSoon;
1661
- function parseStorefrontSessionExpires(at) {
1662
- if (!at) return void 0;
1663
- if (at instanceof Date) return Number.isNaN(at.getTime()) ? void 0 : at;
1664
- if (typeof at === "string") {
1665
- const d = new Date(at);
1666
- return Number.isNaN(d.getTime()) ? void 0 : d;
1667
- }
1668
- return void 0;
2117
+
2118
+ // src/core/constants/api-paths.ts
2119
+ var STOREFRONT_API_PATH_PREFIX = "v1";
2120
+
2121
+ // src/core/constants/currency.ts
2122
+ var countryCurrency = {
2123
+ "PEN": "es-PE",
2124
+ "USD": "en-US",
2125
+ "COP": "es-CO",
2126
+ "MXN": "es-MX"
2127
+ };
2128
+
2129
+ // src/core/utils/format-currency.ts
2130
+ function formatCurrency2(amount, currency = "USD") {
2131
+ const locale = countryCurrency[currency] ?? "en-US";
2132
+ return new Intl.NumberFormat(locale, {
2133
+ style: "currency",
2134
+ currency
2135
+ }).format(amount);
1669
2136
  }
1670
- function mapSessionUser(raw) {
1671
- if (!raw || typeof raw !== "object") return null;
1672
- const u = raw;
1673
- const explicitFirst = typeof u.firstName === "string" ? u.firstName : typeof u.given_name === "string" ? u.given_name : "";
1674
- const explicitLast = typeof u.lastName === "string" ? u.lastName : typeof u.family_name === "string" ? u.family_name : "";
1675
- if (explicitFirst || explicitLast) {
1676
- return {
1677
- id: String(u.id ?? ""),
1678
- email: String(u.email ?? ""),
1679
- firstName: explicitFirst,
1680
- lastName: explicitLast,
1681
- name: typeof u.name === "string" ? u.name : void 0,
1682
- phone: typeof u.phone === "string" ? u.phone : void 0
1683
- };
1684
- }
1685
- const emailLocal = String(u.email ?? "").split("@")[0] ?? "";
1686
- const full = typeof u.name === "string" ? u.name.trim() : emailLocal.trim();
1687
- const parts = full ? full.split(/\s+/) : [];
1688
- return {
1689
- id: String(u.id ?? ""),
1690
- email: String(u.email ?? ""),
1691
- firstName: parts[0] ?? "",
1692
- lastName: parts.slice(1).join(" "),
1693
- name: typeof u.name === "string" ? u.name : void 0,
1694
- phone: typeof u.phone === "string" ? u.phone : void 0
1695
- };
1696
- }
1697
- function useStorefrontSession() {
1698
- const authClient = useStorefrontAuthClient();
1699
- const session = authClient.useSession();
1700
- const user = mapSessionUser(session.data?.user);
1701
- const storefrontSession = session.data?.session;
1702
- const sessionExpiresAt = parseStorefrontSessionExpires(storefrontSession?.expiresAt);
1703
- return {
1704
- session,
1705
- user,
1706
- sessionExpiresAt,
1707
- isAuthenticated: Boolean(session.data?.user),
1708
- isPending: session.isPending,
1709
- error: session.error,
1710
- refetch: session.refetch,
1711
- signOut: () => authClient.signOut()
1712
- };
1713
- }
1714
-
1715
- // src/react/hooks/use-user.ts
1716
- function useUser() {
1717
- return {};
1718
- }
1719
-
1720
- // src/react/hooks/use-config.ts
1721
- function useConfig() {
1722
- return {};
1723
- }
1724
- var useProducts = (storeId) => {
1725
- if (storeId) {
1726
- apiClient.setStoreId(storeId);
1727
- }
1728
- const useProductsList = (filters) => {
1729
- return useQuery({
1730
- queryKey: ["products", filters],
1731
- queryFn: () => productService.getProducts(filters),
1732
- enabled: !!storeId
1733
- });
1734
- };
1735
- const useInfiniteProducts = (filters) => {
1736
- return useInfiniteQuery({
1737
- queryKey: ["products", "infinite", filters],
1738
- queryFn: ({ pageParam = 1 }) => productService.getProducts({ ...filters, page: pageParam }),
1739
- getNextPageParam: (lastPage) => lastPage.meta.hasNextPage ? lastPage.meta.page + 1 : void 0,
1740
- initialPageParam: 1,
1741
- enabled: !!storeId
1742
- });
1743
- };
1744
- const useProduct = (id) => {
1745
- return useQuery({
1746
- queryKey: ["product", id],
1747
- queryFn: () => productService.getProduct(id),
1748
- enabled: !!id && !!storeId
1749
- });
1750
- };
1751
- const useProductBySlug = (slug) => {
1752
- return useQuery({
1753
- queryKey: ["product", "slug", slug],
1754
- queryFn: () => productService.getProductBySlug(slug),
1755
- enabled: !!slug && !!storeId
1756
- });
1757
- };
1758
- const useSearchProducts = (query, filters) => {
1759
- return useQuery({
1760
- queryKey: ["products", "search", query, filters],
1761
- queryFn: () => productService.searchProducts(query, filters),
1762
- enabled: !!query && !!storeId
1763
- });
1764
- };
1765
- const useProductsByCategory = (category, filters) => {
1766
- return useQuery({
1767
- queryKey: ["products", "category", category, filters],
1768
- queryFn: () => productService.getProductsByCategory(category, filters),
1769
- enabled: !!category && !!storeId
1770
- });
1771
- };
1772
- const useProductsOnSale = (filters) => {
1773
- return useQuery({
1774
- queryKey: ["products", "sale", filters],
1775
- queryFn: () => productService.getProductsOnSale(filters),
1776
- enabled: !!storeId
1777
- });
1778
- };
1779
- const useProductsInStock = (filters) => {
1780
- return useQuery({
1781
- queryKey: ["products", "stock", filters],
1782
- queryFn: () => productService.getProductsInStock(filters),
1783
- enabled: !!storeId
1784
- });
1785
- };
1786
- const useRefreshProducts = () => {
1787
- const queryClient = useQueryClient();
1788
- return useMutation({
1789
- mutationFn: () => productService.getProducts(),
1790
- onSuccess: (data) => {
1791
- queryClient.setQueryData(["products"], data);
2137
+ var ApiClient = class {
2138
+ client;
2139
+ storeId;
2140
+ storeDomain;
2141
+ constructor(baseURL = "https://storefront.ecomiq.pe") {
2142
+ this.client = axios.create({
2143
+ baseURL,
2144
+ timeout: 1e4,
2145
+ headers: {
2146
+ "Content-Type": "application/json"
1792
2147
  }
1793
2148
  });
1794
- };
1795
- const useStorefrontProductsList = (params) => {
1796
- return useQuery({
1797
- queryKey: ["storefront", "products", params],
1798
- queryFn: () => productService.getStorefrontProducts(params),
1799
- enabled: !!storeId
1800
- });
1801
- };
1802
- const useStorefrontInfiniteProducts = (params) => {
1803
- return useInfiniteQuery({
1804
- queryKey: ["storefront", "products", "infinite", params],
1805
- queryFn: ({ pageParam = 1 }) => productService.getStorefrontProducts({ ...params, page: pageParam }),
1806
- getNextPageParam: (lastPage) => lastPage.pageIndex < lastPage.totalPages ? lastPage.pageIndex + 1 : void 0,
1807
- initialPageParam: 1,
1808
- enabled: !!storeId
1809
- });
1810
- };
1811
- const useRefreshStorefrontProducts = () => {
1812
- const queryClient = useQueryClient();
1813
- return useMutation({
1814
- mutationFn: (params) => productService.getStorefrontProducts(params),
1815
- onSuccess: () => {
1816
- queryClient.invalidateQueries({ queryKey: ["storefront", "products"] });
2149
+ this.client.interceptors.request.use(
2150
+ (config) => {
2151
+ if (config.headers) {
2152
+ if (this.storeId) config.headers["X-Store-Id"] = this.storeId;
2153
+ if (this.storeDomain) config.headers["X-Store-Domain"] = this.storeDomain;
2154
+ }
2155
+ return config;
1817
2156
  }
1818
- });
1819
- };
1820
- return {
1821
- useProductsList,
1822
- useInfiniteProducts,
1823
- useProduct,
1824
- useProductBySlug,
1825
- useSearchProducts,
1826
- useProductsByCategory,
1827
- useProductsOnSale,
1828
- useProductsInStock,
1829
- useRefreshProducts,
1830
- useStorefrontProductsList,
1831
- useStorefrontInfiniteProducts,
1832
- useRefreshStorefrontProducts
1833
- };
1834
- };
1835
- var useCollections = (storeId) => {
1836
- if (storeId) {
1837
- apiClient.setStoreId(storeId);
1838
- }
1839
- const useStorefrontCollectionsList = () => {
1840
- return useQuery({
1841
- queryKey: ["storefront", "collections"],
1842
- queryFn: () => collectionService.getStorefrontCollections(),
1843
- enabled: !!storeId
1844
- });
1845
- };
1846
- const useStorefrontCollectionBySlug = (slug) => {
1847
- return useQuery({
1848
- queryKey: ["storefront", "collection", "slug", slug],
1849
- queryFn: () => collectionService.getStorefrontCollectionBySlug(slug),
1850
- enabled: !!slug && !!storeId
1851
- });
1852
- };
1853
- const useRefreshStorefrontCollections = () => {
1854
- const queryClient = useQueryClient();
1855
- return useMutation({
1856
- mutationFn: () => collectionService.getStorefrontCollections(),
1857
- onSuccess: () => {
1858
- queryClient.invalidateQueries({ queryKey: ["storefront", "collections"] });
2157
+ );
2158
+ this.client.interceptors.response.use(
2159
+ (response) => response,
2160
+ (error) => {
2161
+ console.error("API Error:", error);
2162
+ return Promise.reject(error);
1859
2163
  }
1860
- });
1861
- };
1862
- return {
1863
- useStorefrontCollectionsList,
1864
- useStorefrontCollectionBySlug,
1865
- useRefreshStorefrontCollections
1866
- };
1867
- };
1868
- var usePages = (storeId) => {
1869
- if (storeId) {
1870
- apiClient.setStoreId(storeId);
2164
+ );
2165
+ }
2166
+ setStoreId(storeId) {
2167
+ this.storeId = storeId;
2168
+ }
2169
+ /** Subdominio para endpoints que usan X-Store-Domain (ej. GET /v1/storefront/settings) */
2170
+ setStoreDomain(domain) {
2171
+ this.storeDomain = domain;
2172
+ }
2173
+ get(url, config) {
2174
+ return this.client.get(url, config).then((response) => response.data);
2175
+ }
2176
+ post(url, data, config) {
2177
+ return this.client.post(url, data, config).then((response) => response.data);
2178
+ }
2179
+ put(url, data, config) {
2180
+ return this.client.put(url, data, config).then((response) => response.data);
2181
+ }
2182
+ patch(url, data, config) {
2183
+ return this.client.patch(url, data, config).then((response) => response.data);
2184
+ }
2185
+ delete(url, config) {
2186
+ return this.client.delete(url, config).then((response) => response.data);
1871
2187
  }
1872
- const usePagesList = () => {
1873
- return useQuery({
1874
- queryKey: ["storefront", "pages"],
1875
- queryFn: () => pageService.getPages(),
1876
- enabled: !!storeId
1877
- });
1878
- };
1879
- const usePageBySlug = (slug) => {
1880
- return useQuery({
1881
- queryKey: ["storefront", "page", "slug", slug],
1882
- queryFn: () => pageService.getPageBySlug(slug),
1883
- enabled: !!slug && !!storeId
1884
- });
1885
- };
1886
- const useRefreshPages = () => {
1887
- const queryClient = useQueryClient();
1888
- return useMutation({
1889
- mutationFn: () => pageService.getPages(),
1890
- onSuccess: () => {
1891
- queryClient.invalidateQueries({ queryKey: ["storefront", "pages"] });
1892
- }
1893
- });
1894
- };
1895
- return {
1896
- usePagesList,
1897
- usePageBySlug,
1898
- useRefreshPages
1899
- };
1900
- };
1901
- var useCartAddresses = () => {
1902
- return useMutation({
1903
- mutationFn: (data) => cartService.updateAddresses(data)
1904
- });
1905
- };
1906
- var useCartGet = () => {
1907
- return useQuery({
1908
- queryKey: ["cart"],
1909
- queryFn: () => cartService.getCart()
1910
- });
1911
- };
1912
- var useCartCreate = () => {
1913
- return useMutation({
1914
- mutationFn: (data) => cartService.createCart(data)
1915
- });
1916
2188
  };
1917
- function useStorefrontGeoInei(storeId, form) {
1918
- const [departments, setDepartments] = useState([]);
1919
- const [provinces, setProvinces] = useState([]);
1920
- const [districts, setDistricts] = useState([]);
1921
- const [loadingDepartments, setLoadingDepartments] = useState(false);
1922
- const [loadingProvinces, setLoadingProvinces] = useState(false);
1923
- const [loadingDistricts, setLoadingDistricts] = useState(false);
1924
- const prevDepartmentCode = useRef(void 0);
1925
- const prevProvinceCode = useRef(void 0);
1926
- const countryCode = (form.watch("countryCode") || "PE").toUpperCase();
1927
- const departmentCode = form.watch("departmentCode");
1928
- const provinceCode = form.watch("provinceCode");
1929
- const districtCode = form.watch("districtCode");
1930
- const storeRequestHeaders = useMemo(() => {
1931
- const id = storeId.trim();
1932
- if (!id) return null;
1933
- return { "X-Store-Id": id };
1934
- }, [storeId]);
1935
- const selectedDepartment = useMemo(
1936
- () => departments.find((d) => d.code === departmentCode),
1937
- [departments, departmentCode]
1938
- );
1939
- const selectedProvince = useMemo(
1940
- () => provinces.find((p) => p.code === provinceCode),
1941
- [provinces, provinceCode]
1942
- );
1943
- const selectedDistrict = useMemo(
1944
- () => districts.find((d) => d.code === districtCode),
1945
- [districts, districtCode]
1946
- );
1947
- useEffect(() => {
1948
- let active = true;
1949
- if (!storeRequestHeaders) {
1950
- setDepartments([]);
1951
- setLoadingDepartments(false);
1952
- return () => {
1953
- active = false;
1954
- };
1955
- }
1956
- setLoadingDepartments(true);
1957
- loadStorefrontGeoDepartments(storeRequestHeaders).then((items) => {
1958
- if (!active) return;
1959
- setDepartments(items);
1960
- }).finally(() => {
1961
- if (!active) return;
1962
- setLoadingDepartments(false);
1963
- });
1964
- return () => {
1965
- active = false;
1966
- };
1967
- }, [storeRequestHeaders]);
1968
- useEffect(() => {
1969
- const prev = prevDepartmentCode.current;
1970
- const dept = departmentCode;
1971
- const departmentChanged = prev !== void 0 && prev !== dept;
1972
- prevDepartmentCode.current = dept;
1973
- if (!dept) {
1974
- setProvinces([]);
1975
- setDistricts([]);
1976
- prevProvinceCode.current = "";
1977
- prevDepartmentCode.current = "";
1978
- return;
1979
- }
1980
- if (!storeRequestHeaders) {
1981
- setProvinces([]);
1982
- return;
1983
- }
1984
- if (departmentChanged) {
1985
- form.setValue("provinceCode", "", { shouldValidate: true });
1986
- form.setValue("provinceName", "", { shouldValidate: true });
1987
- form.setValue("districtCode", "", { shouldValidate: true });
1988
- form.setValue("districtName", "", { shouldValidate: true });
1989
- setDistricts([]);
1990
- prevProvinceCode.current = "";
1991
- }
1992
- if (selectedDepartment?.name) {
1993
- form.setValue("departmentName", selectedDepartment.name, {
1994
- shouldValidate: true
1995
- });
1996
- }
1997
- let active = true;
1998
- setLoadingProvinces(true);
1999
- fetchStorefrontGeoProvinces(storeRequestHeaders, countryCode, dept).then((items) => {
2000
- if (!active) return;
2001
- setProvinces(items);
2002
- }).catch(() => {
2003
- if (!active) return;
2004
- setProvinces([]);
2005
- }).finally(() => {
2006
- if (!active) return;
2007
- setLoadingProvinces(false);
2008
- });
2009
- return () => {
2010
- active = false;
2011
- };
2012
- }, [departmentCode, countryCode, selectedDepartment?.name, form, storeRequestHeaders]);
2013
- useEffect(() => {
2014
- const prev = prevProvinceCode.current;
2015
- const prov = provinceCode;
2016
- const provinceChanged = prev !== void 0 && prev !== prov;
2017
- prevProvinceCode.current = prov;
2018
- if (!prov) {
2019
- setDistricts([]);
2020
- prevProvinceCode.current = "";
2021
- return;
2022
- }
2023
- if (!storeRequestHeaders) {
2024
- setDistricts([]);
2025
- return;
2026
- }
2027
- if (provinceChanged) {
2028
- form.setValue("districtCode", "", { shouldValidate: true });
2029
- form.setValue("districtName", "", { shouldValidate: true });
2030
- }
2031
- if (selectedProvince?.name) {
2032
- form.setValue("provinceName", selectedProvince.name, {
2033
- shouldValidate: true
2034
- });
2035
- }
2036
- let active = true;
2037
- setLoadingDistricts(true);
2038
- fetchStorefrontGeoDistricts(storeRequestHeaders, countryCode, prov).then((items) => {
2039
- if (!active) return;
2040
- setDistricts(items);
2041
- }).catch(() => {
2042
- if (!active) return;
2043
- setDistricts([]);
2044
- }).finally(() => {
2045
- if (!active) return;
2046
- setLoadingDistricts(false);
2047
- });
2048
- return () => {
2049
- active = false;
2050
- };
2051
- }, [provinceCode, countryCode, selectedProvince?.name, form, storeRequestHeaders]);
2052
- useEffect(() => {
2053
- if (selectedDistrict?.name) {
2054
- form.setValue("districtName", selectedDistrict.name, {
2055
- shouldValidate: true
2056
- });
2057
- }
2058
- }, [selectedDistrict?.name, form]);
2059
- return {
2060
- departments,
2061
- provinces,
2062
- districts,
2063
- loadingDepartments,
2064
- loadingProvinces,
2065
- loadingDistricts,
2066
- departmentCode,
2067
- provinceCode,
2068
- districtCode,
2069
- selectedDepartment,
2070
- selectedProvince,
2071
- selectedDistrict,
2072
- storeRequestHeaders
2073
- };
2074
- }
2075
- var useStore = create()(
2076
- (set) => ({
2077
- data: null,
2078
- drawers: {
2079
- cart: false,
2080
- search: false,
2081
- menu: false,
2082
- filter: false
2083
- },
2084
- openDrawer: (drawer) => set((state) => ({
2085
- drawers: {
2086
- ...state.drawers,
2087
- [drawer]: true
2088
- }
2089
- })),
2090
- closeDrawer: (drawer) => set((state) => ({
2091
- drawers: {
2092
- ...state.drawers,
2093
- [drawer]: false
2094
- }
2095
- })),
2096
- toggleDrawer: (drawer) => set((state) => ({
2097
- drawers: {
2098
- ...state.drawers,
2099
- [drawer]: !state.drawers[drawer]
2100
- }
2101
- })),
2102
- closeAllDrawers: () => set((state) => ({
2103
- drawers: Object.keys(state.drawers).reduce(
2104
- (acc, key) => ({ ...acc, [key]: false }),
2105
- {}
2106
- )
2107
- })),
2108
- modals: {
2109
- login: false,
2110
- signup: false
2111
- },
2112
- openModal: (modal) => set((state) => ({
2113
- modals: {
2114
- ...state.modals,
2115
- login: false,
2116
- signup: false,
2117
- [modal]: true
2118
- }
2119
- })),
2120
- closeModal: (modal) => set((state) => ({
2121
- modals: {
2122
- ...state.modals,
2123
- login: false,
2124
- signup: false,
2125
- [modal]: false
2126
- }
2127
- })),
2128
- toggleModal: (modal) => set((state) => ({
2129
- modals: {
2130
- ...state.modals,
2131
- [modal]: !state.modals[modal]
2132
- }
2133
- })),
2134
- closeAllModals: () => set((state) => ({
2135
- modals: Object.keys(state.modals).reduce(
2136
- (acc, key) => ({ ...acc, [key]: false }),
2137
- {}
2138
- )
2139
- }))
2189
+ new ApiClient();
2190
+ var ProductVariantSchema = z.object({
2191
+ id: z.coerce.string(),
2192
+ name: z.string(),
2193
+ storeId: z.string(),
2194
+ productId: z.coerce.string(),
2195
+ basePrice: z.number().positive().optional().nullable(),
2196
+ comparePrice: z.number().positive().optional().nullable(),
2197
+ //TODO: remove this field
2198
+ originalPrice: z.number().positive().optional().nullable(),
2199
+ costPrice: z.number().positive().optional().nullable(),
2200
+ isDefault: z.boolean().optional().nullable(),
2201
+ reserveStock: z.number().nonnegative().optional().nullable(),
2202
+ weight: z.number().nonnegative().optional().nullable().default(0),
2203
+ width: z.number().nonnegative().optional().nullable(),
2204
+ height: z.number().nonnegative().optional().nullable(),
2205
+ unitOfMeasure: z.string().optional().nullable(),
2206
+ order: z.number().nonnegative().optional().nullable().default(0),
2207
+ sku: z.string().optional().nullable(),
2208
+ stock: z.number().nonnegative().optional().nullable(),
2209
+ leadTime: z.string().optional().nullable(),
2210
+ barCode: z.string().optional().nullable(),
2211
+ shippingWeight: z.number().nonnegative().optional().nullable(),
2212
+ images: z.array(z.string()).optional().nullable(),
2213
+ attributes: z.array(z.string()).optional().nullable(),
2214
+ variantStatus: z.string().optional().nullable(),
2215
+ status: z.string().optional().nullable(),
2216
+ createdOn: z.string().optional().nullable(),
2217
+ updatedOn: z.string().optional().nullable(),
2218
+ deletedOn: z.string().optional().nullable()
2219
+ });
2220
+ var ProductSchema = z.object({
2221
+ id: z.coerce.string(),
2222
+ name: z.string(),
2223
+ images: z.array(z.object({
2224
+ url: z.string().url(),
2225
+ name: z.string().optional(),
2226
+ isPrimary: z.boolean().optional()
2227
+ })),
2228
+ basePrice: z.number().positive().optional(),
2229
+ salePrice: z.number().positive().optional(),
2230
+ slug: z.string(),
2231
+ description: z.string().optional(),
2232
+ categories: z.array(z.object({
2233
+ id: z.coerce.string(),
2234
+ name: z.string(),
2235
+ slug: z.string(),
2236
+ logo: z.string().optional(),
2237
+ icon: z.string().optional()
2238
+ })).optional(),
2239
+ tags: z.array(z.string()).optional(),
2240
+ inStock: z.boolean().optional(),
2241
+ variants: z.array(ProductVariantSchema).optional()
2242
+ });
2243
+ z.object({
2244
+ items: z.array(ProductSchema),
2245
+ meta: z.object({
2246
+ total: z.number().int().positive(),
2247
+ page: z.number().int().positive(),
2248
+ pageSize: z.number().int().positive(),
2249
+ hasNextPage: z.boolean()
2250
+ })
2251
+ });
2252
+ z.object({
2253
+ category: z.string().optional(),
2254
+ search: z.string().optional(),
2255
+ minPrice: z.number().positive().optional(),
2256
+ maxPrice: z.number().positive().optional(),
2257
+ inStock: z.boolean().optional(),
2258
+ sortBy: z.enum(["name", "price", "createdAt"]).optional(),
2259
+ sortOrder: z.enum(["asc", "desc"]).optional(),
2260
+ page: z.number().int().positive().optional(),
2261
+ limit: z.number().int().positive().optional()
2262
+ });
2263
+ var StorefrontProductSchema = z.object({
2264
+ id: z.coerce.string(),
2265
+ name: z.string(),
2266
+ slug: z.string(),
2267
+ productType: z.string().optional().nullable(),
2268
+ imageUrl: z.string().optional().nullable(),
2269
+ price: z.number().nonnegative(),
2270
+ compareAtPrice: z.number().nonnegative().optional().nullable(),
2271
+ variantCount: z.number().int().nonnegative().optional().default(0),
2272
+ isAvailable: z.boolean(),
2273
+ totalInventory: z.number().int().nonnegative(),
2274
+ bundleItemsCount: z.number().int().nonnegative().optional().default(0),
2275
+ brand: z.string().optional().nullable(),
2276
+ category: z.string().optional().nullable(),
2277
+ status: z.string().optional().nullable(),
2278
+ tags: z.array(z.string()).optional().nullable()
2279
+ });
2280
+ var StorefrontFacetSchema = z.object({
2281
+ value: z.string(),
2282
+ count: z.number().int().nonnegative()
2283
+ });
2284
+ var StorefrontProductsResponseSchema2 = z.object({
2285
+ pageIndex: z.number().int().positive(),
2286
+ pageSize: z.number().int().positive(),
2287
+ totalCount: z.number().int().nonnegative(),
2288
+ totalPages: z.number().int().nonnegative(),
2289
+ products: z.array(StorefrontProductSchema),
2290
+ categories: z.array(StorefrontFacetSchema).optional().default([]),
2291
+ brands: z.array(StorefrontFacetSchema).optional().default([]),
2292
+ minPrice: z.number().nonnegative().optional().nullable(),
2293
+ maxPrice: z.number().nonnegative().optional().nullable()
2294
+ });
2295
+ z.object({
2296
+ page: z.number().int().positive().optional().default(1),
2297
+ pageSize: z.number().int().positive().optional().default(20),
2298
+ sort: z.enum(["price_asc", "price_desc", "name_asc", "name_desc", "newest"]).optional().default("price_asc"),
2299
+ sellerId: z.string().optional(),
2300
+ search: z.string().optional(),
2301
+ collection: z.string().optional(),
2302
+ category: z.string().optional(),
2303
+ brand: z.string().optional(),
2304
+ productType: z.string().optional(),
2305
+ inStock: z.boolean().optional(),
2306
+ minPrice: z.number().nonnegative().optional(),
2307
+ maxPrice: z.number().nonnegative().optional()
2308
+ });
2309
+ var StorefrontVariantOptionSchema = z.object({
2310
+ key: z.string(),
2311
+ name: z.string(),
2312
+ value: z.string()
2313
+ });
2314
+ var StorefrontProductImageSchema = z.object({
2315
+ url: z.string(),
2316
+ name: z.string().optional().nullable(),
2317
+ order: z.number().int().nonnegative().optional()
2318
+ });
2319
+ var StorefrontVariantSchema = z.object({
2320
+ id: z.coerce.string().optional().default(""),
2321
+ sku: z.string(),
2322
+ status: z.string().optional().nullable(),
2323
+ price: z.number().nonnegative(),
2324
+ compareAtPrice: z.number().nonnegative().optional().nullable(),
2325
+ quantity: z.number().int().nonnegative(),
2326
+ options: z.array(StorefrontVariantOptionSchema).optional().default([]),
2327
+ images: z.array(StorefrontProductImageSchema).optional().default([])
2328
+ });
2329
+ var StorefrontPriceTierSchema = z.object({
2330
+ variantId: z.coerce.string(),
2331
+ minQuantity: z.number().int().positive(),
2332
+ maxQuantity: z.number().int().positive().optional().nullable(),
2333
+ unitPrice: z.number().nonnegative()
2334
+ });
2335
+ var StorefrontBundleItemSchema = z.object({
2336
+ productId: z.coerce.string(),
2337
+ variantId: z.coerce.string(),
2338
+ productName: z.string(),
2339
+ variantName: z.string().optional().nullable(),
2340
+ sku: z.string().optional().nullable(),
2341
+ brand: z.string().optional().nullable(),
2342
+ imageUrl: z.string().optional().nullable(),
2343
+ quantity: z.number().int(),
2344
+ availableStock: z.number().int().optional().default(0),
2345
+ allowBackorders: z.boolean().optional().default(false),
2346
+ requiresShipping: z.boolean().optional().default(true)
2347
+ });
2348
+ z.object({
2349
+ id: z.coerce.string(),
2350
+ name: z.string(),
2351
+ slug: z.string(),
2352
+ description: z.string().optional().nullable(),
2353
+ productType: z.string().optional().nullable(),
2354
+ status: z.string().optional().nullable(),
2355
+ imageUrl: z.string().optional().nullable(),
2356
+ price: z.number().nonnegative(),
2357
+ compareAtPrice: z.number().nonnegative().optional().nullable(),
2358
+ isAvailable: z.boolean(),
2359
+ totalInventory: z.number().int().nonnegative(),
2360
+ brand: z.string().optional().nullable(),
2361
+ category: z.string().optional().nullable(),
2362
+ categoryId: z.coerce.string().optional().nullable(),
2363
+ tags: z.array(z.string()).optional().nullable(),
2364
+ specifications: z.array(z.record(z.string(), z.unknown())).optional().default([]),
2365
+ variants: z.array(StorefrontVariantSchema).optional().default([]),
2366
+ images: z.array(StorefrontProductImageSchema).optional().default([]),
2367
+ bundleItems: z.array(StorefrontBundleItemSchema).optional().default([]),
2368
+ priceTiers: z.array(StorefrontPriceTierSchema).optional().default([]),
2369
+ createdAt: z.string().optional().nullable(),
2370
+ updatedAt: z.string().optional().nullable()
2371
+ });
2372
+ var StorefrontCollectionSchema = z.object({
2373
+ id: z.coerce.string(),
2374
+ slug: z.string(),
2375
+ name: z.string(),
2376
+ description: z.string().nullable().optional(),
2377
+ imageUrl: z.string().nullable().optional(),
2378
+ type: z.string(),
2379
+ productCount: z.number().int().nonnegative()
2380
+ });
2381
+ z.array(StorefrontCollectionSchema);
2382
+ z.object({
2383
+ id: z.string(),
2384
+ name: z.string(),
2385
+ slug: z.string(),
2386
+ layout: z.string()
2387
+ });
2388
+ var StorefrontPageSeoSchema = z.object({
2389
+ title: z.string().optional(),
2390
+ description: z.string().optional()
2391
+ }).optional();
2392
+ var StorefrontPageSettingsSchema = z.object({
2393
+ seo: StorefrontPageSeoSchema,
2394
+ html: z.string().optional(),
2395
+ title: z.string().optional()
2396
+ }).catchall(z.unknown());
2397
+ var StorefrontPageBlockSchema = z.object({
2398
+ id: z.string(),
2399
+ type: z.string(),
2400
+ order: z.number(),
2401
+ settings: z.record(z.unknown()).optional()
2402
+ });
2403
+ var StorefrontPageSectionSchema = z.object({
2404
+ id: z.string(),
2405
+ type: z.string(),
2406
+ order: z.number(),
2407
+ settings: z.record(z.unknown()).optional(),
2408
+ blocks: z.array(StorefrontPageBlockSchema).optional().default([])
2409
+ });
2410
+ z.object({
2411
+ id: z.string(),
2412
+ name: z.string(),
2413
+ slug: z.string(),
2414
+ layout: z.string(),
2415
+ settings: StorefrontPageSettingsSchema.optional(),
2416
+ sections: z.array(StorefrontPageSectionSchema).optional()
2417
+ });
2418
+ z.object({
2419
+ email: z.string().email(),
2420
+ firstName: z.string().min(1),
2421
+ lastName: z.string().min(1),
2422
+ phone: z.string().min(1)
2423
+ });
2424
+ z.object({
2425
+ currencyCode: z.string(),
2426
+ salesChannelId: z.string(),
2427
+ email: z.string().email()
2428
+ });
2429
+ var CartAddressSchema = z.object({
2430
+ name: z.string().min(1),
2431
+ address1: z.string().min(1),
2432
+ city: z.string().min(1),
2433
+ countryCode: z.string().min(2),
2434
+ company: z.string().nullable().optional(),
2435
+ address2: z.string().nullable().optional(),
2436
+ province: z.string().nullable().optional(),
2437
+ postalCode: z.string().nullable().optional(),
2438
+ district: z.string().nullable().optional(),
2439
+ phone: z.string().nullable().optional(),
2440
+ latitude: z.number().nullable().optional(),
2441
+ longitude: z.number().nullable().optional(),
2442
+ geo: z.object({
2443
+ departmentCode: z.string().nullable().optional(),
2444
+ provinceCode: z.string().nullable().optional(),
2445
+ districtCode: z.string().nullable().optional()
2446
+ }).nullable().optional()
2447
+ });
2448
+ z.object({
2449
+ shippingAddress: CartAddressSchema,
2450
+ billingAddress: CartAddressSchema
2451
+ });
2452
+ var CartItemModifierRequestSchema = z.object({
2453
+ modifierGroupId: z.coerce.string().min(1),
2454
+ optionIds: z.array(z.coerce.string().min(1)).optional().default([])
2455
+ });
2456
+ z.object({
2457
+ variantId: z.coerce.string().min(1),
2458
+ quantity: z.number().int().positive(),
2459
+ modifiers: z.array(CartItemModifierRequestSchema).optional()
2460
+ });
2461
+ z.object({
2462
+ code: z.string().min(1)
2463
+ });
2464
+ z.object({
2465
+ subtotal: z.number(),
2466
+ discount: z.number(),
2467
+ tax: z.number(),
2468
+ warranty: z.number().optional().default(0),
2469
+ total: z.number()
2470
+ });
2471
+ z.object({
2472
+ name: z.string().nullable().optional(),
2473
+ address1: z.string(),
2474
+ city: z.string(),
2475
+ countryCode: z.string(),
2476
+ company: z.string().nullable().optional(),
2477
+ address2: z.string().nullable().optional(),
2478
+ province: z.string().nullable().optional(),
2479
+ postalCode: z.string().nullable().optional(),
2480
+ district: z.string().nullable().optional(),
2481
+ phone: z.string().nullable().optional(),
2482
+ latitude: z.number().nullable().optional(),
2483
+ longitude: z.number().nullable().optional(),
2484
+ geo: z.object({
2485
+ departmentCode: z.string().nullable().optional(),
2486
+ provinceCode: z.string().nullable().optional(),
2487
+ districtCode: z.string().nullable().optional()
2488
+ }).nullable().optional()
2489
+ });
2490
+ var CartResponseBundleItemSchema = z.object({
2491
+ productId: z.coerce.string(),
2492
+ variantId: z.coerce.string(),
2493
+ productName: z.string(),
2494
+ variantName: z.string().nullable().optional(),
2495
+ sku: z.string().nullable().optional(),
2496
+ brand: z.string().nullable().optional(),
2497
+ imageUrl: z.string().nullable().optional(),
2498
+ quantity: z.number().int()
2499
+ });
2500
+ var CartResponseItemSchema = z.object({
2501
+ id: z.string(),
2502
+ title: z.string(),
2503
+ variantLabel: z.string().nullable().optional(),
2504
+ thumbnail: z.string().nullable().optional(),
2505
+ quantity: z.number().int(),
2506
+ variantId: z.coerce.string(),
2507
+ variantSku: z.string().nullable().optional(),
2508
+ unitPrice: z.number(),
2509
+ bundleItems: z.array(CartResponseBundleItemSchema).optional().default([])
2510
+ });
2511
+ z.object({
2512
+ id: z.string(),
2513
+ name: z.string(),
2514
+ description: z.string().nullable().optional(),
2515
+ total: z.number(),
2516
+ estimatedDays: z.number().int().nullable().optional(),
2517
+ pickupPointId: z.string().nullable().optional(),
2518
+ scheduledDate: z.string().nullable().optional(),
2519
+ scheduledTime: z.string().nullable().optional()
2520
+ });
2521
+ var CartResponseSchema2 = z.object({
2522
+ id: z.string(),
2523
+ regionId: z.string().nullable().optional(),
2524
+ salesChannelId: z.string().nullable().optional(),
2525
+ email: z.string().email().nullable().optional(),
2526
+ phone: z.string().nullable().optional(),
2527
+ firstName: z.string().nullable().optional(),
2528
+ lastName: z.string().nullable().optional(),
2529
+ currencyCode: z.string(),
2530
+ completedAt: z.string().nullable().optional(),
2531
+ shippingAddress: z.unknown().nullable().optional(),
2532
+ billingAddress: z.unknown().nullable().optional(),
2533
+ metadata: z.record(z.string(), z.unknown()).optional().default({}),
2534
+ promotionCodes: z.array(z.string()).optional().default([]),
2535
+ items: z.array(CartResponseItemSchema).optional().default([]),
2536
+ shippingMethods: z.array(z.unknown()).optional().default([]),
2537
+ totals: z.object({
2538
+ discountTotal: z.number(),
2539
+ shippingTotal: z.number(),
2540
+ subtotal: z.number(),
2541
+ taxTotal: z.number(),
2542
+ total: z.number(),
2543
+ warrantyTotal: z.number()
2140
2544
  })
2141
- );
2142
- var useCart = create()(
2143
- persist(
2144
- (set) => ({
2145
- count: 0,
2146
- cart: [],
2147
- cartTokenId: null,
2148
- setCartTokenId: (token) => set((state) => ({ ...state, cartTokenId: token })),
2149
- checkoutStep: null,
2150
- setCheckoutStep: (step) => set((state) => ({ ...state, checkoutStep: step })),
2151
- checkoutCustomerLocal: null,
2152
- setCheckoutCustomerLocal: (customer) => set((state) => {
2153
- if (!state.cartTokenId) return state;
2154
- return {
2155
- checkoutCustomerLocal: {
2156
- cartTokenId: state.cartTokenId,
2157
- customer
2158
- }
2159
- };
2160
- }),
2161
- clearCheckoutCustomerLocal: () => set(() => ({ checkoutCustomerLocal: null })),
2162
- addCart: (item) => set((state) => {
2163
- const existingItem = state.cart.find(
2164
- (cartItem) => cartItem.id === item.id
2165
- );
2166
- if (existingItem) {
2167
- const newQuantity = Math.max(0, existingItem.quantity) + 1;
2168
- const cart2 = state.cart.map(
2169
- (cartItem) => cartItem.id === item.id ? { ...cartItem, quantity: newQuantity } : cartItem
2170
- );
2171
- const count2 = cart2.reduce((sum, i) => sum + Math.max(0, i.quantity), 0);
2172
- return { count: count2, cart: cart2 };
2173
- }
2174
- const newItem = {
2175
- ...item,
2176
- quantity: Math.max(1, Math.max(0, item.quantity ?? 1))
2177
- };
2178
- const cart = [...state.cart, newItem];
2179
- const count = cart.reduce((sum, i) => sum + Math.max(0, i.quantity), 0);
2180
- return { count, cart };
2181
- }),
2182
- removeCart: (id) => set((state) => {
2183
- const existingItem = state.cart.find((item) => item.id === id);
2184
- if (!existingItem) return state;
2185
- if (existingItem.quantity > 1) {
2186
- const newQuantity = Math.max(0, existingItem.quantity - 1);
2187
- const cart2 = state.cart.map(
2188
- (cartItem) => cartItem.id === id ? { ...cartItem, quantity: newQuantity } : cartItem
2189
- );
2190
- const count2 = cart2.reduce((sum, i) => sum + Math.max(0, i.quantity), 0);
2191
- return { count: count2, cart: cart2 };
2192
- }
2193
- const cart = state.cart.filter((item) => item.id !== id);
2194
- const count = Math.max(0, cart.reduce((sum, i) => sum + Math.max(0, i.quantity), 0));
2195
- return { count, cart };
2196
- }),
2197
- clearCartSession: () => set(() => ({
2198
- count: 0,
2199
- cart: [],
2200
- cartTokenId: null,
2201
- checkoutStep: null,
2202
- checkoutCustomerLocal: null
2203
- }))
2204
- }),
2205
- { name: "cart-storage" }
2206
- )
2207
- );
2208
- init_store_api_client();
2209
- function EcomiqProvider({
2210
- store,
2211
- authClient,
2212
- children,
2213
- withShellUi = false
2214
- }) {
2215
- useStore.setState({ data: store ?? null });
2216
- useEffect(() => {
2217
- setClientStoreId(store?.store.id ?? null);
2218
- return () => setClientStoreId(null);
2219
- }, [store]);
2220
- const [queryClient] = useState(() => new QueryClient());
2221
- const tree = /* @__PURE__ */ jsxs(QueryClientProvider, { client: queryClient, children: [
2222
- children,
2223
- withShellUi ? /* @__PURE__ */ jsx(EcomiqShellUi2, {}) : null
2224
- ] });
2225
- if (!authClient) return tree;
2226
- return /* @__PURE__ */ jsx(StorefrontAuthProvider, { authClient, children: tree });
2227
- }
2228
- function EcomiqShellUi2() {
2229
- const [ui, setUi] = useState(null);
2230
- useEffect(() => {
2231
- void Promise.resolve().then(() => (init_ecomiq_shell_ui(), ecomiq_shell_ui_exports)).then((mod) => setUi(() => mod.EcomiqShellUi));
2232
- }, []);
2233
- return ui ? React2.createElement(ui) : null;
2234
- }
2235
-
2236
- // src/react/auth/ecomiq-oauth-password-constants.ts
2237
- var PLUGIN_ID = "ecomiq-oauth-password";
2238
- var ECOMIQ_OAUTH_TOKEN_URL = "https://auth.ecomiq.pe/connect/token";
2239
- var ECOMIQ_OAUTH_USERINFO_URL = "https://auth.ecomiq.pe/connect/userinfo";
2240
- var tokenResponseSchema = z.object({
2241
- access_token: z.string().min(1),
2242
- token_type: z.string().optional(),
2243
- /** Segundos hasta expiración (Ecomiq envía ej. `86399`). Sincroniza la sesión Better Auth con el bearer. */
2244
- expires_in: z.coerce.number().int().positive().optional()
2245
2545
  });
2246
- var userInfoSchema = z.object({
2247
- sub: z.string(),
2248
- email: z.string().email().optional(),
2249
- family_name: z.string().optional(),
2250
- given_name: z.string().optional(),
2251
- iss: z.string().optional(),
2252
- aud: z.union([z.string(), z.array(z.string())]).optional()
2546
+ z.object({
2547
+ paymentMethodCode: z.string().min(1),
2548
+ externalRef: z.string().min(1),
2549
+ receiptUrl: z.string().min(1).optional()
2550
+ });
2551
+ var CartCheckoutPaymentActionSchema = z.object({
2552
+ publicConfiguration: z.object({
2553
+ publishableKey: z.string().nullable().optional(),
2554
+ checkoutMode: z.string().nullable().optional(),
2555
+ phoneNumber: z.string().nullable().optional(),
2556
+ accountHolder: z.string().nullable().optional(),
2557
+ qrImageUrl: z.string().nullable().optional()
2558
+ }).passthrough().nullable().optional(),
2559
+ url: z.string().nullable().optional(),
2560
+ html: z.string().nullable().optional(),
2561
+ clientSecret: z.string().nullable().optional(),
2562
+ qrCode: z.string().nullable().optional(),
2563
+ expiresAt: z.string().nullable().optional()
2564
+ }).passthrough();
2565
+ var CartCheckoutPaymentSchema = z.object({
2566
+ transactionId: z.string(),
2567
+ paymentMethodCode: z.string(),
2568
+ providerId: z.string().nullable().optional(),
2569
+ status: z.string(),
2570
+ amount: z.number(),
2571
+ reference: z.string(),
2572
+ actionType: z.string(),
2573
+ receiptUrl: z.string().nullable().optional(),
2574
+ action: CartCheckoutPaymentActionSchema.nullable().optional()
2575
+ }).passthrough();
2576
+ z.object({
2577
+ publicKey: z.string().optional(),
2578
+ publishableKey: z.string().optional(),
2579
+ stripePublicKey: z.string().optional(),
2580
+ clientSecret: z.string().optional(),
2581
+ intentClientSecret: z.string().optional(),
2582
+ orderId: z.coerce.string().optional(),
2583
+ orderGroup: z.string().optional(),
2584
+ orderIds: z.array(z.coerce.string()).optional(),
2585
+ /** Payload de pago (embedded, redirect, etc.) */
2586
+ payment: CartCheckoutPaymentSchema.optional(),
2587
+ cart: z.unknown().optional()
2588
+ }).passthrough();
2589
+ z.object({
2590
+ id: z.string(),
2591
+ url: z.string()
2592
+ });
2593
+ var CartPaymentMethodSchema = z.object({
2594
+ code: z.string(),
2595
+ name: z.string(),
2596
+ description: z.string().nullable().optional(),
2597
+ kind: z.string(),
2598
+ isActive: z.boolean(),
2599
+ isDefault: z.boolean(),
2600
+ isManual: z.boolean(),
2601
+ sortOrder: z.number(),
2602
+ phoneNumber: z.string().nullable().optional(),
2603
+ accountHolder: z.string().nullable().optional(),
2604
+ qrImageUrl: z.string().nullable().optional()
2605
+ });
2606
+ var CartPaymentMethodsResponseSchema = z.object({
2607
+ methods: z.array(CartPaymentMethodSchema)
2608
+ });
2609
+ z.object({
2610
+ cart: CartResponseSchema2,
2611
+ paymentMethods: CartPaymentMethodsResponseSchema
2612
+ });
2613
+ var ShippingRateSchema = z.object({
2614
+ shippingMethodId: z.string(),
2615
+ name: z.string(),
2616
+ displayName: z.string().optional(),
2617
+ type: z.string().optional(),
2618
+ price: z.number(),
2619
+ currency: z.string().optional(),
2620
+ sortOrder: z.number().optional(),
2621
+ rateId: z.string(),
2622
+ description: z.string().nullable().optional(),
2623
+ deliveryLocationId: z.string().nullable().optional(),
2624
+ deliveryLocationName: z.string().nullable().optional(),
2625
+ estimatedDeliveryDays: z.number().nullable().optional(),
2626
+ serviceCode: z.string().nullable().optional(),
2627
+ metadata: z.record(z.string(), z.unknown()).optional()
2628
+ }).passthrough();
2629
+ var ShippingOptionGroupSchema = z.object({
2630
+ sellerId: z.string(),
2631
+ shippingProfileId: z.string().nullable().optional(),
2632
+ orderAmount: z.number().optional(),
2633
+ totalWeight: z.number().optional(),
2634
+ itemIds: z.array(z.string()).optional(),
2635
+ rates: z.array(ShippingRateSchema)
2636
+ }).passthrough();
2637
+ z.object({
2638
+ groups: z.array(ShippingOptionGroupSchema)
2639
+ });
2640
+ z.object({
2641
+ rateId: z.string().min(1),
2642
+ shippingMethodId: z.string().min(1),
2643
+ serviceCode: z.string().nullable().optional(),
2644
+ sellerId: z.string().nullable().optional(),
2645
+ shippingProfileId: z.string().nullable().optional(),
2646
+ locationId: z.string().nullable().optional(),
2647
+ pickupPointId: z.string().nullable().optional(),
2648
+ scheduledDate: z.string().nullable().optional(),
2649
+ scheduledTime: z.string().nullable().optional()
2253
2650
  });
2254
- var signInBody = z.object({
2255
- email: z.string().email(),
2256
- password: z.string().min(1),
2257
- callbackURL: z.string().optional(),
2258
- rememberMe: z.boolean().optional().default(true)
2651
+ var CONFIG_FILENAMES = [
2652
+ "ecomiq.config.js",
2653
+ "ecomiq.config.cjs",
2654
+ "ecomiq.config.mjs"
2655
+ ];
2656
+ var EcomiqConfigSchema = z.object({
2657
+ /**
2658
+ * Slug de tienda en Ecomiq (p. ej. `mi-tienda` para `mi-tienda.ecomiq.app`).
2659
+ * Si está definido, tiene prioridad sobre el `Host` de la request (útil en `localhost`).
2660
+ */
2661
+ slugStore: z.string().min(1).optional()
2259
2662
  });
2260
-
2261
- // src/react/auth/ecomiq-oauth-password-plugin.ts
2262
- function ecomiqOAuthPassword() {
2263
- const secureCookie = true;
2264
- const clearStorefrontOAuthCookieMiddleware = createAuthMiddleware(async (ctx) => {
2265
- ctx.setCookie(STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, "", {
2266
- path: STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH,
2267
- httpOnly: true,
2268
- sameSite: "lax",
2269
- secure: secureCookie,
2270
- maxAge: 0
2271
- });
2272
- });
2273
- return {
2274
- id: PLUGIN_ID,
2275
- schema: {
2276
- user: {
2277
- fields: {
2278
- firstName: { type: "string", required: false },
2279
- lastName: { type: "string", required: false },
2280
- phone: { type: "string", required: false }
2281
- }
2282
- }
2283
- },
2284
- hooks: {
2285
- after: [
2286
- {
2287
- matcher: (hookCtx) => hookCtx.path === "/sign-out",
2288
- handler: clearStorefrontOAuthCookieMiddleware
2289
- }
2290
- ]
2291
- },
2292
- endpoints: {
2293
- signIn: createAuthEndpoint(
2294
- "/ecomiq-oauth/sign-in",
2295
- {
2296
- method: "POST",
2297
- use: [formCsrfMiddleware],
2298
- body: signInBody
2299
- },
2300
- async (ctx) => {
2301
- const { email: loginEmail, password, callbackURL, rememberMe } = ctx.body;
2302
- const tokens = await exchangePasswordGrant(loginEmail, password, {
2303
- identityScope: ctx.getHeader("x-Identity-Scope"),
2304
- tenantId: ctx.getHeader("x-Tenant-Id"),
2305
- storeId: ctx.getHeader("x-Store-Id")
2306
- });
2307
- const profile = await fetchUserInfo(tokens.access_token);
2308
- const profileEmail = profile.email?.toLowerCase().trim();
2309
- const canonicalEmail = profileEmail ?? loginEmail.toLowerCase().trim();
2310
- if (profileEmail && profileEmail !== loginEmail.toLowerCase().trim()) {
2311
- throw APIError.from("UNAUTHORIZED", {
2312
- code: "ECOMIQ_EMAIL_MISMATCH",
2313
- message: "El correo del perfil OAuth no coincide con el inicio de sesi\xF3n"
2314
- });
2315
- }
2316
- const displayName = displayNameFromUserInfo(profile, canonicalEmail);
2317
- const existing = await ctx.context.internalAdapter.findUserByEmail(canonicalEmail);
2318
- let user = existing?.user;
2319
- if (!user) {
2320
- user = await ctx.context.internalAdapter.createUser({
2321
- email: canonicalEmail,
2322
- name: displayName,
2323
- emailVerified: true
2324
- });
2325
- } else if (user.name !== displayName) {
2326
- await ctx.context.internalAdapter.updateUser(user.id, { name: displayName });
2327
- user = { ...user, name: displayName };
2328
- }
2329
- const oauthSessionExpires = tokens.expires_in !== void 0 && tokens.expires_in > 0 ? new Date(Date.now() + tokens.expires_in * 1e3) : void 0;
2330
- const session = await ctx.context.internalAdapter.createSession(
2331
- user.id,
2332
- rememberMe === false,
2333
- oauthSessionExpires ? { expiresAt: oauthSessionExpires } : {},
2334
- Boolean(oauthSessionExpires)
2335
- );
2336
- if (!session) {
2337
- throw APIError.from("INTERNAL_SERVER_ERROR", {
2338
- code: "ECOMIQ_SESSION_FAILED",
2339
- message: "No se pudo crear la sesi\xF3n"
2340
- });
2341
- }
2342
- await setSessionCookie(ctx, { session, user }, rememberMe === false);
2343
- const oauthMaxAgeSec = oauthSessionExpires !== void 0 ? Math.max(60, Math.ceil((oauthSessionExpires.getTime() - Date.now()) / 1e3)) : tokens.expires_in !== void 0 && tokens.expires_in > 0 ? tokens.expires_in : 60 * 60 * 24;
2344
- await ctx.setCookie(STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, tokens.access_token, {
2345
- path: STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH,
2346
- httpOnly: true,
2347
- sameSite: "lax",
2348
- secure: secureCookie,
2349
- maxAge: oauthMaxAgeSec
2350
- });
2351
- if (callbackURL) ctx.setHeader("Location", callbackURL);
2352
- return ctx.json({
2353
- redirect: !!callbackURL,
2354
- token: session.token,
2355
- url: callbackURL,
2356
- user: parseUserOutput(ctx.context.options, user)
2357
- });
2358
- }
2359
- )
2360
- }
2361
- };
2362
- }
2363
- function displayNameFromUserInfo(profile, fallbackEmail) {
2364
- const parts = [profile.given_name?.trim(), profile.family_name?.trim()].filter(Boolean);
2365
- const joined = parts.join(" ").trim();
2366
- if (joined) return joined;
2367
- return fallbackEmail.split("@")[0] || "Cliente";
2368
- }
2369
- async function fetchUserInfo(accessToken) {
2370
- const res = await fetch(ECOMIQ_OAUTH_USERINFO_URL, {
2371
- method: "GET",
2372
- headers: {
2373
- Authorization: `Bearer ${accessToken}`,
2374
- accept: "application/json"
2375
- }
2376
- });
2377
- const text = await res.text();
2378
- let json;
2379
- try {
2380
- json = text ? JSON.parse(text) : {};
2381
- } catch {
2382
- throw APIError.from("UNAUTHORIZED", {
2383
- code: "ECOMIQ_USERINFO_INVALID_BODY",
2384
- message: "Respuesta inv\xE1lida del endpoint userinfo"
2385
- });
2386
- }
2387
- if (!res.ok) {
2388
- const err = json;
2389
- throw APIError.from("UNAUTHORIZED", {
2390
- code: "ECOMIQ_USERINFO_REJECTED",
2391
- message: err.error_description ?? err.error ?? "No se pudo obtener el perfil del usuario"
2392
- });
2393
- }
2394
- const parsed = userInfoSchema.safeParse(json);
2663
+ var cachedConfig;
2664
+ function parseExportedConfig(raw) {
2665
+ const candidate = raw && typeof raw === "object" && "default" in raw ? raw.default : raw;
2666
+ const parsed = EcomiqConfigSchema.safeParse(candidate);
2395
2667
  if (!parsed.success) {
2396
- throw APIError.from("UNAUTHORIZED", {
2397
- code: "ECOMIQ_USERINFO_SHAPE",
2398
- message: "Perfil OAuth con formato inv\xE1lido"
2399
- });
2400
- }
2401
- return parsed.data;
2402
- }
2403
- async function exchangePasswordGrant(username, password, context) {
2404
- const clientId = process.env.ECOMIQ_AUTH_CLIENT_ID ?? "";
2405
- const clientSecret = process.env.ECOMIQ_AUTH_CLIENT_SECRET ?? "";
2406
- const scope = process.env.ECOMIQ_AUTH_SCOPE ?? "";
2407
- if (!clientId || !clientSecret) {
2408
- throw APIError.from("INTERNAL_SERVER_ERROR", {
2409
- code: "ECOMIQ_AUTH_NOT_CONFIGURED",
2410
- message: "OAuth Ecomiq no configurado: ECOMIQ_AUTH_CLIENT_ID y ECOMIQ_AUTH_CLIENT_SECRET."
2411
- });
2412
- }
2413
- const body = new URLSearchParams({
2414
- grant_type: "password",
2415
- username,
2416
- password,
2417
- scope,
2418
- client_id: clientId,
2419
- client_secret: clientSecret
2420
- });
2421
- const identityScope = context.identityScope;
2422
- const tenantId = context.tenantId;
2423
- const storeId = context.storeId;
2424
- const headers = new Headers({
2425
- "content-type": "application/x-www-form-urlencoded",
2426
- accept: "application/json"
2427
- });
2428
- if (identityScope?.trim()) {
2429
- headers.set("x-Identity-Scope", identityScope.trim());
2430
- }
2431
- if (tenantId?.trim()) {
2432
- headers.set("x-Tenant-Id", tenantId.trim());
2433
- }
2434
- if (storeId?.trim()) {
2435
- headers.set("x-Store-Id", storeId.trim());
2436
- }
2437
- let res;
2438
- let text;
2439
- try {
2440
- res = await fetch(ECOMIQ_OAUTH_TOKEN_URL, {
2441
- method: "POST",
2442
- headers,
2443
- body
2444
- });
2445
- text = await res.text();
2446
- } catch (e) {
2447
- throw mapTokenEndpointFetchFailure(e);
2448
- }
2449
- const json = safeParseJson(text);
2450
- if (!res.ok) {
2451
- throwBadRequestFromOAuth(json, res.statusText || text || `HTTP ${res.status}`);
2668
+ console.warn(
2669
+ "[ecomiq] ecomiq.config.* inv\xE1lido:",
2670
+ parsed.error.flatten().fieldErrors
2671
+ );
2672
+ return null;
2452
2673
  }
2453
- const parsed = tokenResponseSchema.safeParse(json);
2454
- if (!parsed.success) {
2455
- throwBadRequestFromOAuth(json, "Token de acceso no recibido");
2674
+ const slugStore = parsed.data.slugStore?.trim();
2675
+ return slugStore ? { slugStore } : {};
2676
+ }
2677
+ function loadEcomiqConfig(cwd = process.cwd()) {
2678
+ if (cachedConfig !== void 0) return cachedConfig;
2679
+ for (const filename of CONFIG_FILENAMES) {
2680
+ const configPath = join(cwd, filename);
2681
+ if (!existsSync(configPath)) continue;
2682
+ try {
2683
+ const requireFromApp = createRequire(join(cwd, "package.json"));
2684
+ const loaded = requireFromApp(configPath);
2685
+ const parsed = parseExportedConfig(loaded);
2686
+ cachedConfig = parsed;
2687
+ return cachedConfig;
2688
+ } catch (error) {
2689
+ console.warn(`[ecomiq] No se pudo cargar ${configPath}:`, error);
2690
+ }
2456
2691
  }
2457
- return parsed.data;
2692
+ cachedConfig = null;
2693
+ return null;
2458
2694
  }
2459
- function safeParseJson(text) {
2460
- try {
2461
- return text ? JSON.parse(text) : {};
2462
- } catch {
2463
- return {};
2695
+ function resolvePublicStoreKey(hostHeader, cwd) {
2696
+ const slugFromConfig = loadEcomiqConfig(cwd)?.slugStore?.trim();
2697
+ if (slugFromConfig) return slugFromConfig;
2698
+ if (!hostHeader?.trim()) {
2699
+ throw Object.assign(
2700
+ new Error(
2701
+ "Host is required, o define slugStore en ecomiq.config.js en la ra\xEDz del proyecto"
2702
+ ),
2703
+ { status: 400 }
2704
+ );
2464
2705
  }
2706
+ return resolveStorefrontSettingsHost(hostHeader);
2465
2707
  }
2466
- function throwBadRequestFromOAuth(payload, fallbackMessage) {
2467
- const err = payload;
2468
- const errorCode = typeof err.error === "string" && err.error.trim() ? err.error.trim() : "invalid_grant";
2469
- const errorMessage = typeof err.error_description === "string" && err.error_description.trim() ? err.error_description.trim() : typeof err.error === "string" && err.error.trim() ? err.error.trim() : fallbackMessage.trim() || "Credenciales invalidas.";
2470
- throw APIError.from("BAD_REQUEST", {
2471
- code: errorCode,
2472
- message: errorMessage.slice(0, 500)
2473
- });
2708
+
2709
+ // src/core/server/request-origin.ts
2710
+ init_store_api_client();
2711
+ function applyServerRequestOriginFromHeaders(headerList) {
2712
+ const host = headerList.get("host")?.trim();
2713
+ if (!host) return;
2714
+ const proto = headerList.get("x-forwarded-proto") ?? headerList.get("x-forwarded-ssl") ?? "http";
2715
+ const secure = proto === "https" || (headerList.get("x-forwarded-ssl") ?? "") === "on";
2716
+ setServerRequestOrigin(`${secure ? "https" : "http"}://${host}`);
2474
2717
  }
2475
- function mapTokenEndpointFetchFailure(e) {
2476
- const codes = collectNetworkErrorCodes(e);
2477
- const msg = e instanceof Error ? e.message : String(e);
2478
- const isDnsError = codes.some((c) => c === "ENOTFOUND" || c === "EAI_AGAIN");
2479
- if (isDnsError) {
2480
- throw APIError.from("BAD_GATEWAY", {
2481
- code: "ECOMIQ_AUTH_DNS",
2482
- message: "No se pudo resolver el servidor de autenticacion."
2483
- });
2484
- }
2485
- const isConnectionRefused = codes.includes("ECONNREFUSED");
2486
- if (isConnectionRefused) {
2487
- throw APIError.from("BAD_GATEWAY", {
2488
- code: "ECOMIQ_AUTH_REFUSED",
2489
- message: "Conexion rechazada al servidor de autenticacion."
2490
- });
2718
+ function normalizeRequestHostname(headerList) {
2719
+ const host = headerList.get("host");
2720
+ return host?.replace(/^www\./, "") ?? null;
2721
+ }
2722
+
2723
+ // src/core/server/fetch-public-store.ts
2724
+ init_store_api_client();
2725
+
2726
+ // src/react/shell/lib/public-store-settings-source.ts
2727
+ var ENV_PUBLIC_STORE_SETTINGS_SOURCE = "PUBLIC_STORE_SETTINGS_SOURCE";
2728
+ function resolvePublicStoreSettingsSource(envValue = process.env[ENV_PUBLIC_STORE_SETTINGS_SOURCE]) {
2729
+ const v = (envValue ?? "api").trim().toLowerCase();
2730
+ return v === "kv" ? "kv" : "api";
2731
+ }
2732
+
2733
+ // src/core/server/fetch-public-store.ts
2734
+ async function fetchPublicStoreSettings(options) {
2735
+ let storeKey;
2736
+ try {
2737
+ storeKey = resolvePublicStoreKey(options.host);
2738
+ } catch (error) {
2739
+ const err = error;
2740
+ return {
2741
+ data: null,
2742
+ error: {
2743
+ message: err.message ?? "Host is required",
2744
+ statusCode: err.status ?? 400,
2745
+ isNotFound: true,
2746
+ subdomain: void 0
2747
+ }
2748
+ };
2491
2749
  }
2492
- const looksLikeAbortOrSocketClose = codes.some(
2493
- (c) => ["UND_ERR_SOCKET", "ECONNRESET", "EPIPE", "ECONNABORTED"].includes(c)
2494
- ) || /terminated|abort|closed|FIN|socket/i.test(msg);
2495
- if (looksLikeAbortOrSocketClose) {
2496
- throwBadRequestFromOAuth({}, "Credenciales invalidas o conexion cerrada por el servidor.");
2750
+ const source = options.source ?? resolvePublicStoreSettingsSource();
2751
+ try {
2752
+ setServerStoreId(null);
2753
+ const data = source === "kv" ? await getStorefrontSettingsFromKvByStoreKey(storeKey) : await getStorefrontSettings(
2754
+ storeKey,
2755
+ `storefront-settings-${storeKey}`
2756
+ );
2757
+ setServerStoreId(data.store.id);
2758
+ return { data, error: null };
2759
+ } catch (error) {
2760
+ const err = error;
2761
+ const statusCode = err.status ?? 500;
2762
+ return {
2763
+ data: null,
2764
+ error: {
2765
+ message: err.message ?? "Error fetching store settings",
2766
+ statusCode,
2767
+ isNotFound: statusCode === 404,
2768
+ subdomain: storeKey
2769
+ }
2770
+ };
2497
2771
  }
2498
- throw APIError.from("INTERNAL_SERVER_ERROR", {
2499
- code: "ECOMIQ_AUTH_REQUEST_FAILED",
2500
- message: msg.slice(0, 280) || "Error al contactar el servidor de autenticacion."
2501
- });
2502
- }
2503
- function collectNetworkErrorCodes(e) {
2504
- const out = [];
2505
- const visit = (x) => {
2506
- if (!x || typeof x !== "object") return;
2507
- const code = "code" in x && typeof x.code === "string" ? x.code : void 0;
2508
- if (code) out.push(code);
2509
- if ("cause" in x && x.cause) {
2510
- visit(x.cause);
2511
- }
2512
- };
2513
- visit(e);
2514
- return out;
2515
2772
  }
2516
2773
 
2517
- // src/react/auth/ecomiq-oauth-password-client.ts
2518
- function ecomiqOAuthPasswordClient() {
2774
+ // src/core/server/store-proxy-handler.ts
2775
+ var DEFAULT_API_BASE_URL = "https://storefront.ecomiq.pe";
2776
+ function jsonError(status, message, error) {
2777
+ return Response.json({ error, message, status }, { status });
2778
+ }
2779
+ async function ensureStoreContext(request) {
2780
+ const xStoreId = request.headers.get("x-store-id")?.trim();
2781
+ const xStoreDomain = request.headers.get("x-store-domain")?.trim();
2782
+ if (xStoreDomain) {
2783
+ return {
2784
+ ok: true,
2785
+ storeId: xStoreId || "",
2786
+ storeDomain: xStoreDomain || null
2787
+ };
2788
+ }
2789
+ if (!xStoreId) {
2790
+ return {
2791
+ ok: false,
2792
+ response: jsonError(
2793
+ 400,
2794
+ "X-Store-Id is required",
2795
+ "Store context required"
2796
+ )
2797
+ };
2798
+ }
2519
2799
  return {
2520
- id: PLUGIN_ID,
2521
- pathMethods: {
2522
- "/ecomiq-oauth/sign-in": "POST"
2523
- },
2524
- atomListeners: [
2525
- {
2526
- matcher: (path) => path === "/ecomiq-oauth/sign-in",
2527
- signal: "$sessionSignal"
2528
- }
2529
- ]
2800
+ ok: true,
2801
+ storeId: xStoreId || "",
2802
+ storeDomain: xStoreDomain || null
2530
2803
  };
2531
2804
  }
2532
-
2533
- // src/react/auth/ecomiq-storefront-sign-in.ts
2534
- async function signInWithEcomiqCredentials2(authClient, settings, credentials) {
2535
- const response = await authClient.$fetch("/ecomiq-oauth/sign-in", {
2536
- method: "POST",
2537
- headers: buildEcomiqOAuthIdentityHeaders(settings),
2538
- body: credentials
2539
- });
2540
- if (response.error) {
2541
- throw new Error(response.error.message ?? "Error al iniciar sesi\xF3n");
2805
+ var SKIP_FORWARD_HEADERS = /* @__PURE__ */ new Set([
2806
+ "host",
2807
+ "connection",
2808
+ "content-length",
2809
+ "transfer-encoding",
2810
+ "x-store-id",
2811
+ "x-store-domain",
2812
+ "authorization",
2813
+ "cookie",
2814
+ "cookie2",
2815
+ "set-cookie",
2816
+ "x-forwarded-for",
2817
+ "x-forwarded-proto",
2818
+ "x-forwarded-host",
2819
+ "x-real-ip",
2820
+ "forwarded",
2821
+ "cf-connecting-ip",
2822
+ "cf-connecting-ipv6",
2823
+ "true-client-ip",
2824
+ "cf-ipcountry",
2825
+ "cf-ray",
2826
+ "cf-visitor"
2827
+ ]);
2828
+ function getClientIp(request) {
2829
+ const candidates = [
2830
+ request.headers.get("cf-connecting-ip"),
2831
+ request.headers.get("true-client-ip"),
2832
+ request.headers.get("x-real-ip")
2833
+ ];
2834
+ for (const value of candidates) {
2835
+ const trimmed = value?.trim();
2836
+ if (trimmed) return trimmed;
2837
+ }
2838
+ const xff = request.headers.get("x-forwarded-for");
2839
+ if (xff?.trim()) {
2840
+ const first = xff.split(",")[0]?.trim();
2841
+ if (first) return first;
2542
2842
  }
2543
- return response;
2843
+ return null;
2544
2844
  }
2545
- function buildOptionGroups(variants) {
2546
- const map = /* @__PURE__ */ new Map();
2547
- for (const v of variants) {
2548
- for (const opt of v.options ?? []) {
2549
- const key = opt.key;
2550
- const name = opt.name ?? key;
2551
- if (!map.has(key)) map.set(key, /* @__PURE__ */ new Map());
2552
- map.get(key).set(opt.value, name);
2845
+ function getCookieValue(request, name) {
2846
+ const cookieHeader = request.headers.get("cookie");
2847
+ if (!cookieHeader) return void 0;
2848
+ for (const part of cookieHeader.split(";")) {
2849
+ const [rawKey, ...rest] = part.trim().split("=");
2850
+ if (rawKey?.trim() === name) {
2851
+ return decodeURIComponent(rest.join("="));
2553
2852
  }
2554
2853
  }
2555
- return Array.from(map.entries()).map(([key, valueMap]) => ({
2556
- key,
2557
- name: Array.from(valueMap.values())[0] ?? key,
2558
- values: Array.from(valueMap.keys())
2559
- }));
2854
+ return void 0;
2560
2855
  }
2561
- function findVariant(variants, selected, hasConfigurableOptions) {
2562
- if (!hasConfigurableOptions && variants.length > 0) {
2563
- return variants[0] ?? null;
2564
- }
2565
- if (Object.keys(selected).length === 0) return null;
2566
- for (const v of variants) {
2567
- const opts = v.options ?? [];
2568
- const match = opts.length > 0 && opts.every((o) => selected[o.key] === o.value);
2569
- if (match) return v;
2856
+ function buildUpstreamRequest(request, pathSegments, config, storeId, storeDomain) {
2857
+ const requestUrl = new URL(request.url);
2858
+ const base = (config.apiBaseUrl ?? DEFAULT_API_BASE_URL).replace(/\/$/, "");
2859
+ const userPath = pathSegments.length ? pathSegments.join("/") : "";
2860
+ const path = userPath ? `${STOREFRONT_API_PATH_PREFIX}/${userPath}` : STOREFRONT_API_PATH_PREFIX;
2861
+ const search = requestUrl.searchParams.toString();
2862
+ const url = search ? `${base}/${path}?${search}` : `${base}/${path}`;
2863
+ const headers = new Headers();
2864
+ request.headers.forEach((value, key) => {
2865
+ const lower = key.toLowerCase();
2866
+ if (!SKIP_FORWARD_HEADERS.has(lower)) {
2867
+ headers.set(key, value);
2868
+ }
2869
+ });
2870
+ headers.set("X-Store-Id", storeId);
2871
+ if (storeDomain) {
2872
+ headers.set("X-Store-domain", storeDomain);
2873
+ }
2874
+ const clientIp = getClientIp(request);
2875
+ if (clientIp) {
2876
+ headers.set("X-Forwarded-For", clientIp);
2877
+ }
2878
+ const forwardedProto = request.headers.get("cf-visitor")?.match(/"scheme":"(https?)"/)?.[1] ?? requestUrl.protocol.replace(":", "") ?? "https";
2879
+ headers.set("X-Forwarded-Proto", forwardedProto);
2880
+ const forwardedHost = request.headers.get("host") ?? requestUrl.host;
2881
+ if (forwardedHost) {
2882
+ headers.set("X-Forwarded-Host", forwardedHost);
2883
+ }
2884
+ const incomingAuth = request.headers.get("authorization")?.trim();
2885
+ const storefrontOAuth = getCookieValue(request, STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME)?.trim();
2886
+ if (incomingAuth && /^Bearer\s+\S+/i.test(incomingAuth)) {
2887
+ headers.set("Authorization", incomingAuth);
2888
+ } else if (storefrontOAuth) {
2889
+ headers.set("Authorization", `Bearer ${storefrontOAuth}`);
2890
+ }
2891
+ headers.set("Accept-Encoding", "identity");
2892
+ const init = {
2893
+ method: request.method,
2894
+ headers
2895
+ };
2896
+ const bodyMethods = ["POST", "PUT", "PATCH"];
2897
+ if (bodyMethods.includes(request.method) && request.body) {
2898
+ init.body = request.body;
2899
+ init.duplex = "half";
2570
2900
  }
2571
- return null;
2901
+ return { url, init };
2572
2902
  }
2573
- function getInitialOptions(variants, optionGroups) {
2574
- const first = variants[0];
2575
- if (!first) return {};
2576
- const opts = first.options ?? [];
2577
- const selected = {};
2578
- for (const g of optionGroups) {
2579
- const o = opts.find((x) => x.key === g.key);
2580
- if (o) selected[g.key] = o.value;
2581
- }
2582
- return selected;
2903
+ function isResponseBodyForbidden(status) {
2904
+ return status === 204 || status === 205 || status === 304;
2583
2905
  }
2584
- function ProductVariantSelector({
2585
- product,
2586
- currency = "USD",
2587
- features = [],
2588
- onVariantChange,
2589
- children
2590
- }) {
2591
- const variants = useMemo(() => product.variants ?? [], [product.variants]);
2592
- const optionGroups = useMemo(() => buildOptionGroups(variants), [variants]);
2593
- const hasConfigurableOptions = optionGroups.length > 0;
2594
- const [selectedOptions, setSelectedOptions] = useState(
2595
- () => getInitialOptions(variants, optionGroups)
2906
+ async function handleStoreProxyRequest(request, pathSegments, config = {}) {
2907
+ const storeContext = await ensureStoreContext(request);
2908
+ if (!storeContext.ok) {
2909
+ return storeContext.response;
2910
+ }
2911
+ const { storeId, storeDomain } = storeContext;
2912
+ const { url, init } = buildUpstreamRequest(
2913
+ request,
2914
+ pathSegments,
2915
+ config,
2916
+ storeId,
2917
+ storeDomain
2596
2918
  );
2597
- const selectedVariant = useMemo(
2598
- () => findVariant(variants, selectedOptions, hasConfigurableOptions),
2599
- [variants, selectedOptions, hasConfigurableOptions]
2600
- );
2601
- const displayPrice = selectedVariant?.price ?? product.price ?? 0;
2602
- const compareAtPrice = selectedVariant?.compareAtPrice ?? product.compareAtPrice;
2603
- const isAvailable = (selectedVariant ? (selectedVariant.quantity ?? 0) > 0 : product.isAvailable) ?? true;
2604
- useEffect(() => {
2605
- onVariantChange?.(selectedVariant, displayPrice);
2606
- }, [selectedVariant, displayPrice, onVariantChange]);
2607
- const setOption = useCallback((key, value) => {
2608
- setSelectedOptions((prev) => ({ ...prev, [key]: value }));
2609
- }, []);
2610
- const hasVariants = hasConfigurableOptions;
2611
- return /* @__PURE__ */ jsxs("div", { className: "space-y-5", children: [
2612
- /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2 flex-wrap", children: [
2613
- /* @__PURE__ */ jsx(
2614
- "span",
2615
- {
2616
- className: "inline-flex items-center rounded-md bg-primary/10 px-2.5 py-0.5 text-base font-semibold text-primary",
2617
- "data-testid": "product-display-price",
2618
- children: formatCurrency$1(displayPrice, currency)
2619
- }
2620
- ),
2621
- compareAtPrice != null && compareAtPrice > displayPrice && /* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground line-through", children: formatCurrency$1(compareAtPrice, currency) })
2622
- ] }),
2623
- hasVariants && optionGroups.map((group) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2624
- /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: group.name }),
2625
- /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: group.values.map((value) => {
2626
- const isSelected = selectedOptions[group.key] === value;
2627
- const isColorLike = group.key.toLowerCase().includes("color") || group.key.toLowerCase().includes("colour");
2628
- return /* @__PURE__ */ jsx(
2629
- "button",
2630
- {
2631
- type: "button",
2632
- onClick: () => setOption(group.key, value),
2633
- className: isColorLike ? `min-w-[72px] rounded-md border-2 px-3 py-2 text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 ${isSelected ? "border-primary bg-primary text-foreground" : "border-border bg-muted/30 text-foreground hover:border-muted-foreground/50"}` : `rounded-md border px-3 py-2 text-sm font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 ${isSelected ? "border-primary bg-muted ring-1 ring-primary" : "border-border bg-transparent text-muted-foreground hover:border-muted-foreground/50 hover:text-foreground"}`,
2634
- style: isColorLike && isSelected && value.toLowerCase() === "black" ? { backgroundColor: "#1a1a1a", borderColor: "#1a1a1a", color: "#fff" } : isColorLike && value.toLowerCase() === "white" ? { backgroundColor: "#fafafa", color: "#1a1a1a", borderColor: "#e5e5e5" } : void 0,
2635
- "data-testid": `variant-option-${group.key}-${value}`,
2636
- children: value
2637
- },
2638
- value
2639
- );
2640
- }) })
2641
- ] }, group.key)),
2642
- features.length > 0 && /* @__PURE__ */ jsx("ul", { className: "list-disc list-inside space-y-1 text-sm text-muted-foreground", children: features.map((f, i) => /* @__PURE__ */ jsx("li", { children: f }, i)) }),
2643
- children?.({
2644
- product,
2645
- selectedVariant,
2646
- displayPrice,
2647
- compareAtPrice,
2648
- isAvailable,
2649
- selectedOptions
2650
- })
2651
- ] });
2919
+ const upstream = await fetch(url, init);
2920
+ const responseHeaders = new Headers(upstream.headers);
2921
+ const status = upstream.status;
2922
+ if (isResponseBodyForbidden(status)) {
2923
+ responseHeaders.delete("content-length");
2924
+ responseHeaders.delete("content-type");
2925
+ return new Response(null, {
2926
+ status,
2927
+ statusText: upstream.statusText,
2928
+ headers: responseHeaders
2929
+ });
2930
+ }
2931
+ const body = await upstream.text();
2932
+ return new Response(body, {
2933
+ status,
2934
+ statusText: upstream.statusText,
2935
+ headers: responseHeaders
2936
+ });
2652
2937
  }
2653
- function isRenderableCmsPage(p) {
2654
- if (!p.status) return true;
2655
- return p.status === "published";
2938
+
2939
+ // src/react/frameworks/index.ts
2940
+ var usePublicStore = () => useStore.getState().data;
2941
+ async function getHostname() {
2942
+ const headerList = getRequestHeaders();
2943
+ applyServerRequestOriginFromHeaders(headerList);
2944
+ return normalizeRequestHostname(headerList);
2656
2945
  }
2657
- function findStorefrontCmsPageBySlug(settings, slug) {
2658
- const pages = settings?.cms?.pages;
2659
- if (!pages?.length) return null;
2660
- const raw = pages.find(
2661
- (p) => p.slug === slug && isRenderableCmsPage(p)
2662
- );
2663
- if (!raw) return null;
2664
- const parsed = StorefrontPageDetailSchema$1.safeParse(raw);
2665
- return parsed.success ? parsed.data : null;
2946
+ async function getPublicStore(options) {
2947
+ const headerList = getRequestHeaders();
2948
+ applyServerRequestOriginFromHeaders(headerList);
2949
+ return fetchPublicStoreSettings({
2950
+ host: headerList.get("host"),
2951
+ source: options?.source
2952
+ });
2953
+ }
2954
+ async function getPublicStoreFromHeaders(headerList, options) {
2955
+ applyServerRequestOriginFromHeaders(headerList);
2956
+ return fetchPublicStoreSettings({
2957
+ host: headerList.get("host"),
2958
+ ...options
2959
+ });
2666
2960
  }
2667
2961
 
2668
- export { CartAddressesRequestSchema, CartBuyerRequestSchema, CartCheckoutPaymentActionSchema, CartCheckoutPaymentSchema, CartCheckoutReadResponseSchema, CartCheckoutRequestSchema, CartCheckoutResponseSchema, CartCouponRequestSchema, CartCreateRequestSchema, CartItemModifierRequestSchema, CartItemRequestSchema, CartPaymentMethodSchema, CartPaymentMethodsResponseSchema, CartPaymentReceiptResponseSchema, CartResponseBundleItemSchema, CartResponseItemSchema, CartResponseSchema, CartShippingMethodPutRequestSchema, EcomiqConfigSchema, EcomiqProvider, ProductSchema, ProductVariantSchema, ProductVariantSelector, ProductsFiltersSchema, ProductsResponseSchema, QueryProvider, STOREFRONT_API_PATH_PREFIX, STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH, ShippingOptionGroupSchema, ShippingOptionsResponseSchema, ShippingRateSchema, StorefrontAuthProvider, StorefrontBundleItemSchema, StorefrontCheckoutSettingsSchema, StorefrontCollectionDetailSchema, StorefrontCollectionSchema, StorefrontCollectionsResponseSchema, StorefrontPageDetailSchema, StorefrontPageListItemSchema, StorefrontPriceTierSchema, StorefrontProductDetailSchema, StorefrontProductSchema, StorefrontProductsParamsSchema, StorefrontProductsResponseSchema, StorefrontSettingsLegacyFlatSchema, StorefrontSettingsSchema, StorefrontStoreSchema, apiClient, buildEcomiqOAuthIdentityHeaders, cartService, clearEcomiqConfigCache, collectionService, countryCurrency, customerOrderStatusTone, ecomiqOAuthPassword, ecomiqOAuthPasswordClient, fetchStorefrontGeoDistricts, fetchStorefrontGeoProvinces, findStorefrontCmsPageBySlug, formatCurrency, formatCustomerOrderStatus, formatOrderDate, formatOrderDateTime, hasEcomiqSlugStoreConfig, loadEcomiqConfig, loadStorefrontGeoDepartments, normalizeStorefrontSettingsPayload, pageService, productService, resolveIneiCodesFromLabels, resolvePublicStoreKey, signInWithEcomiqCredentials2 as signInWithEcomiqCredentials, storeService, storefrontAccessTokenNeedsRefresh, storefrontFaviconUrl, storefrontOgImageUrl, storefrontSessionEndsSoon, storefrontStoreRecord, toGeoItems, useCart, useCartAddresses, useCartCreate, useCartGet, useCollections, useConfig, usePages, useProducts, useStore, useStorefrontAuthClient, useStorefrontGeoInei, useStorefrontSession, useUser };
2669
- //# sourceMappingURL=react.js.map
2670
- //# sourceMappingURL=react.js.map
2962
+ export { CustomerAddressSchema, CustomerAddressUpsertSchema, CustomerMeSchema, CustomerOrderDetailSchema, CustomerOrderListItemSchema, CustomerProfilePatchSchema, CustomerRegisterRequestSchema, ECOMIQ_CLIENTS_STORE_KV_BINDING, EcomiqProvider, ProductVariantSelector, QueryProvider, StoreApiClient, StorefrontAuthProvider, StorefrontProductSchema, StorefrontProductsResponseSchema2 as StorefrontProductsResponseSchema, StorefrontSettingsSchema3 as StorefrontSettingsSchema, addCartCoupon, applyServerRequestOriginFromHeaders, buildStorefrontKvSnapshotKey, buildStorefrontKvSnapshotKeyFromStoreKey, checkoutCart, createCart, createCustomerAddress, createStoreApiClient, customerMeToProfilePatch, deleteCustomerAddress, ecomiqOAuthPassword, ecomiqOAuthPasswordClient, fetchPublicStoreSettings, findStorefrontCmsPageBySlug, formatCurrency2 as formatCurrency, getCart, getCartCheckout, getCartPaymentMethods, getCustomerAddresses, getCustomerMe, getCustomerOrder, getCustomerOrders, getHostname, getPublicStore, getPublicStoreFromHeaders, getSharedOrderDraft, getShippingOptions, getStoreApiBaseUrl, getStoreApiClient, getStorefrontCollectionBySlug, getStorefrontCollections, getStorefrontPageBySlug, getStorefrontPagePreview, getStorefrontPages, getStorefrontProductBySlug, getStorefrontProducts, getStorefrontSettings, getStorefrontSettingsFromKv, getStorefrontSettingsFromKvByStoreKey, handleStoreProxyRequest, isCartNotActiveApiError, normalizeStoreHost, patchCartAddresses, patchCartBuyer, patchCustomer, putCartShippingMethod, registerCustomer, removeCartCoupon, resolvePublicStoreSettingsSource, resolveStorefrontSettingsHost, setClientStoreId, setServerRequestOrigin, setServerStoreId, signInWithEcomiqCredentials2 as signInWithEcomiqCredentials, storeApiClient, storefrontAccessTokenNeedsRefresh, storefrontSessionEndsSoon, updateCustomerAddress, uploadPaymentReceipt, useCart2 as useCart, usePublicStore, useStore, useStoreCart, useStoreCollections, useStorePages, useStoreProducts, useStorefrontAuthClient, useStorefrontSession };
2963
+ //# sourceMappingURL=tanstack.js.map
2964
+ //# sourceMappingURL=tanstack.js.map