@ecomiq/storefront 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +63 -17
  2. package/dist/chunk-PCTSWSTB.js +346 -0
  3. package/dist/chunk-PCTSWSTB.js.map +1 -0
  4. package/dist/chunk-PDK2VYWD.js +1598 -0
  5. package/dist/chunk-PDK2VYWD.js.map +1 -0
  6. package/dist/chunk-Q762YXCQ.js +175 -0
  7. package/dist/chunk-Q762YXCQ.js.map +1 -0
  8. package/dist/{index-C-xqLr1g.d.ts → chunks/client.d.ts} +6577 -4565
  9. package/dist/chunks/client.js +2046 -0
  10. package/dist/chunks/client.js.map +1 -0
  11. package/dist/chunks/config.js +3 -0
  12. package/dist/chunks/config.js.map +1 -0
  13. package/dist/chunks/server-nextjs.d.ts +33 -0
  14. package/dist/chunks/server-nextjs.js +30 -0
  15. package/dist/chunks/server-nextjs.js.map +1 -0
  16. package/dist/chunks/server-tanstack.d.ts +22 -0
  17. package/dist/chunks/server-tanstack.js +30 -0
  18. package/dist/chunks/server-tanstack.js.map +1 -0
  19. package/dist/ecomiq-shell-ui-SWIFLQVM.js +8 -0
  20. package/dist/ecomiq-shell-ui-SWIFLQVM.js.map +1 -0
  21. package/dist/format-currency-oJD9jGYW.d.ts +6751 -0
  22. package/dist/index.d.ts +20 -30
  23. package/dist/index.js +11 -103
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.server.d.ts +8 -0
  26. package/dist/index.server.js +7 -0
  27. package/dist/index.server.js.map +1 -0
  28. package/dist/nextjs/api.js +1 -174
  29. package/dist/nextjs/api.js.map +1 -1
  30. package/dist/nextjs.d.ts +13 -41
  31. package/dist/nextjs.js +11 -2964
  32. package/dist/nextjs.js.map +1 -1
  33. package/dist/nextjs.server.d.ts +1 -0
  34. package/dist/nextjs.server.js +1 -0
  35. package/dist/nextjs.server.js.map +1 -0
  36. package/dist/tanstack/api.js +3 -171
  37. package/dist/tanstack/api.js.map +1 -1
  38. package/dist/tanstack.d.ts +13 -30
  39. package/dist/tanstack.js +11 -2964
  40. package/dist/tanstack.js.map +1 -1
  41. package/dist/tanstack.server.d.ts +1 -0
  42. package/dist/tanstack.server.js +1 -0
  43. package/dist/tanstack.server.js.map +1 -0
  44. package/package.json +13 -1
  45. /package/dist/{..d.ts → chunks/config.d.ts} +0 -0
package/dist/tanstack.js CHANGED
@@ -1,2964 +1,11 @@
1
- import { z } from 'zod';
2
- import { Modal } from '@ecomiq/ui/components/modal';
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
- import { toast, Toaster as Toaster$1 } from 'sonner';
5
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
- import { useTheme } from 'next-themes';
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';
9
- import { QueryClient, hydrate, QueryClientProvider, useMutation, useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
10
- import React2, { createContext, useRef, useEffect, useContext, useState, useMemo, useCallback } from 'react';
11
- import { create } from 'zustand';
12
- import { persist } from 'zustand/middleware';
13
- import { createAuthMiddleware, createAuthEndpoint, formCsrfMiddleware } from 'better-auth/api';
14
- import { APIError } from 'better-auth';
15
- import { setSessionCookie } from 'better-auth/cookies';
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';
22
-
23
- var __defProp = Object.defineProperty;
24
- var __getOwnPropNames = Object.getOwnPropertyNames;
25
- var __esm = (fn, res) => function __init() {
26
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
27
- };
28
- var __export = (target, all) => {
29
- for (var name in all)
30
- __defProp(target, name, { get: all[name], enumerable: true });
31
- };
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
- }
40
- function setClientStoreId(storeId) {
41
- if (typeof window === "undefined") return;
42
- clientStoreIdGetter = storeId?.trim() || null;
43
- }
44
- async function getStoreApiBaseUrl() {
45
- if (typeof window !== "undefined") {
46
- return STORE_API_PATH;
47
- }
48
- if (serverRequestOriginGetter) {
49
- return `${serverRequestOriginGetter.replace(/\/$/, "")}/${STORE_API_PATH.replace(/^\//, "")}`;
50
- }
51
- return STORE_API_PATH;
52
- }
53
- function createStoreApiClient(baseUrl) {
54
- return new StoreApiClient(baseUrl);
55
- }
56
- async function getStoreApiClient() {
57
- const baseUrl = await getStoreApiBaseUrl();
58
- return new StoreApiClient(baseUrl);
59
- }
60
- var STORE_API_PATH, serverRequestOriginGetter, serverStoreIdGetter, clientStoreIdGetter, StoreApiClient, storeApiClient;
61
- var init_store_api_client = __esm({
62
- "src/core/client/store-api-client.ts"() {
63
- STORE_API_PATH = "/api/store";
64
- serverRequestOriginGetter = null;
65
- serverStoreIdGetter = null;
66
- clientStoreIdGetter = null;
67
- StoreApiClient = class {
68
- baseUrl;
69
- constructor(baseUrl = STORE_API_PATH) {
70
- this.baseUrl = baseUrl.replace(/\/$/, "");
71
- }
72
- async request(path, init, options) {
73
- const pathNorm = path.replace(/^\/+/, "");
74
- const url = path.startsWith("http") ? path : `${this.baseUrl}/${pathNorm}`;
75
- const headers = new Headers(init.headers ?? {});
76
- headers.set("Content-Type", "application/json");
77
- headers.set("Accept-Encoding", "identity");
78
- const explicitStoreId = options?.xStoreId?.trim();
79
- const runtimeStoreId = explicitStoreId || (typeof window === "undefined" ? serverStoreIdGetter : clientStoreIdGetter);
80
- if (runtimeStoreId && !headers.has("x-store-id")) {
81
- headers.set("X-Store-Id", runtimeStoreId);
82
- }
83
- if (options?.xStoreDomain) {
84
- headers.set("X-Store-Domain", options.xStoreDomain);
85
- }
86
- if (options?.xCartId) {
87
- headers.set("X-Cart-Token", options.xCartId);
88
- }
89
- const bearer = typeof options?.bearerToken === "string" && options.bearerToken.trim().length > 0 ? options.bearerToken.trim() : void 0;
90
- if (bearer) {
91
- headers.set(
92
- "Authorization",
93
- bearer.toLowerCase().startsWith("bearer ") ? bearer : `Bearer ${bearer}`
94
- );
95
- }
96
- const isServer = typeof window === "undefined";
97
- const res = await fetch(url, {
98
- ...init,
99
- headers,
100
- credentials: isServer ? "same-origin" : "include",
101
- ...options?.noStore ? { cache: "no-store" } : {},
102
- ...options?.cacheKey && isServer && !options?.noStore ? {
103
- next: {
104
- revalidate: 60,
105
- tags: [options.cacheKey]
106
- }
107
- } : {}
108
- });
109
- if (!res.ok) {
110
- let body;
111
- try {
112
- const errorText = await res.text();
113
- body = errorText ? JSON.parse(errorText) : void 0;
114
- } catch {
115
- body = void 0;
116
- }
117
- const msg = typeof body === "object" && body !== null && "title" in body && typeof body.title === "string" ? body.title : res.statusText || "Store API error";
118
- const err = new Error(msg);
119
- err.status = res.status;
120
- err.body = body;
121
- throw err;
122
- }
123
- const text = await res.text();
124
- if (!text) return void 0;
125
- return JSON.parse(text);
126
- }
127
- get(path, options) {
128
- return this.request(path, { method: "GET" }, options);
129
- }
130
- post(path, data, options) {
131
- return this.request(
132
- path,
133
- {
134
- method: "POST",
135
- body: data != null ? JSON.stringify(data) : void 0
136
- },
137
- options
138
- );
139
- }
140
- patch(path, data, options) {
141
- return this.request(path, {
142
- method: "PATCH",
143
- body: data != null ? JSON.stringify(data) : void 0
144
- }, options);
145
- }
146
- put(path, data, options) {
147
- return this.request(
148
- path,
149
- {
150
- method: "PUT",
151
- body: data != null ? JSON.stringify(data) : void 0
152
- },
153
- options
154
- );
155
- }
156
- delete(path, options) {
157
- return this.request(path, { method: "DELETE" }, options);
158
- }
159
- };
160
- storeApiClient = new StoreApiClient(STORE_API_PATH);
161
- }
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
- }
180
- function customerAuthOptions(accessToken) {
181
- const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
182
- return token ? { bearerToken: token } : {};
183
- }
184
- async function registerCustomer(data) {
185
- const payload = CustomerRegisterRequestSchema.parse(data);
186
- const client = await getStoreApiClient();
187
- return client.post("customer/register", payload);
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
- }
224
- async function getCustomerMe(accessToken) {
225
- const client = await getStoreApiClient();
226
- const response = await client.get("customer", customerAuthOptions(accessToken));
227
- return CustomerMeSchema.parse(response);
228
- }
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;
235
- var init_store_api_customer_service = __esm({
236
- "src/core/client/store-api-customer.service.ts"() {
237
- init_store_api_client();
238
- CustomerRegisterRequestSchema = z.object({
239
- email: z.string().email(),
240
- firstName: z.string().trim().min(1),
241
- lastName: z.string().trim().min(1),
242
- countryIsoCode: z.string().trim().length(2),
243
- password: z.string(),
244
- phone: z.string().trim().optional()
245
- });
246
- CustomerAddressSchema = z.object({
247
- /** Presente en listados cuando el upstream expone el id para PUT/DELETE. */
248
- id: z.string().optional(),
249
- addressKey: z.string(),
250
- countryIsoCode: z.string(),
251
- addressLine: z.string(),
252
- addressNumber: z.string(),
253
- department: z.string(),
254
- province: z.string(),
255
- district: z.string(),
256
- phone: z.string(),
257
- cellPhone: z.string(),
258
- postalCode: z.string(),
259
- reference: z.string(),
260
- latitude: z.number().nullable(),
261
- longitude: z.number().nullable(),
262
- isDefault: z.boolean()
263
- });
264
- CustomerAddressUpsertSchema = CustomerAddressSchema.omit({ id: true });
265
- CustomerMeSchema = z.object({
266
- id: z.string(),
267
- storeId: z.string(),
268
- email: z.string().email(),
269
- firstName: z.string(),
270
- lastName: z.string(),
271
- phone: z.string(),
272
- identificationNumber: z.string().nullable(),
273
- identificationType: z.string().nullable(),
274
- entityName: z.string().nullable(),
275
- dateOfBirth: z.string().nullable(),
276
- gender: z.string().nullable(),
277
- countryIsoCode: z.string(),
278
- role: z.string().nullable(),
279
- companyName: z.string().nullable(),
280
- consent: z.boolean(),
281
- userId: z.string(),
282
- customerType: z.string(),
283
- status: z.string(),
284
- entityIdentificationNumber: z.string().nullable(),
285
- defaultAddressId: z.string().nullable(),
286
- metadata: z.unknown().nullable(),
287
- totalOrders: z.number(),
288
- avgOrders: z.number(),
289
- lastOrderId: z.string().nullable(),
290
- lastOrderDate: z.string().nullable(),
291
- loyaltyPoints: z.number(),
292
- addresses: z.array(CustomerAddressSchema),
293
- createdOn: z.string(),
294
- updatedOn: z.string().nullable()
295
- });
296
- CustomerProfilePatchSchema = z.object({
297
- firstName: z.string().trim().min(1),
298
- lastName: z.string().trim().min(1),
299
- phone: z.string().trim(),
300
- identificationNumber: z.string().nullable(),
301
- identificationType: z.string().nullable(),
302
- entityName: z.string().nullable(),
303
- entityIdentificationNumber: z.string().nullable(),
304
- gender: z.string().nullable(),
305
- role: z.string().nullable(),
306
- companyName: z.string().nullable(),
307
- dateOfBirth: z.string().nullable(),
308
- consent: z.boolean(),
309
- countryIsoCode: z.string().trim().length(2)
310
- });
311
- }
312
- });
313
- var ModalsFactory;
314
- var init_modals_factory = __esm({
315
- "src/react/shell/components/modals-factory.tsx"() {
316
- "use client";
317
- init_store_api_customer_service();
318
- ModalsFactory = () => {
319
- const cart = useCart();
320
- const store = useStore$1();
321
- const authClient = useStorefrontAuthClient$1();
322
- const { refetch } = useStorefrontSession$1();
323
- const handlerLogin = async (values) => {
324
- try {
325
- await signInWithEcomiqCredentials(authClient, store.data, values);
326
- const me = await getCustomerMe();
327
- const displayName = `${me.firstName} ${me.lastName}`.trim() || me.email;
328
- const updateUserResponse = await authClient.$fetch("/update-user", {
329
- method: "POST",
330
- body: {
331
- name: displayName,
332
- firstName: me.firstName,
333
- lastName: me.lastName,
334
- phone: me.phone
335
- }
336
- });
337
- if (updateUserResponse.error) {
338
- throw new Error(updateUserResponse.error?.message ?? "No se pudo sincronizar el perfil");
339
- }
340
- if (me.email) {
341
- cart.setCheckoutCustomerLocal({
342
- email: me.email,
343
- firstName: me.firstName,
344
- lastName: me.lastName,
345
- phone: me.phone ?? ""
346
- });
347
- }
348
- await refetch();
349
- toast.success("Sesi\xF3n iniciada correctamente");
350
- store.closeModal("login");
351
- } catch (error) {
352
- console.error("Error al iniciar sesion:", error);
353
- toast.error("Error al iniciar sesion");
354
- }
355
- };
356
- const handlerSignup = async (values) => {
357
- try {
358
- await registerCustomer({
359
- email: values.email,
360
- firstName: values.firstName,
361
- lastName: values.lastName,
362
- countryIsoCode: values.countryIsoCode,
363
- password: values.password,
364
- phone: values.phone
365
- });
366
- toast.success("Cuenta creada correctamente");
367
- store.closeModal("signup");
368
- setTimeout(() => {
369
- store.openModal("login");
370
- }, 1e3);
371
- } catch (error) {
372
- console.error("Error al registrarse:", error);
373
- toast.error("Error al registrarse");
374
- }
375
- };
376
- return /* @__PURE__ */ jsxs(
377
- Modal,
378
- {
379
- isOpen: store.modals.login || store.modals.signup,
380
- onClose: () => store.closeAllModals(),
381
- children: [
382
- store.modals.login && /* @__PURE__ */ jsxs(Fragment, { children: [
383
- /* @__PURE__ */ jsx(SignInForm, { onSubmit: (values) => handlerLogin(values) }),
384
- /* @__PURE__ */ jsxs("div", { className: "flex justify-center items-center mt-4", children: [
385
- /* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "No tienes cuenta?" }),
386
- /* @__PURE__ */ jsx(
387
- "button",
388
- {
389
- type: "button",
390
- onClick: () => store.openModal("signup"),
391
- className: "text-primary hover:underline ml-2 cursor-pointer",
392
- children: "Registrate"
393
- }
394
- )
395
- ] })
396
- ] }),
397
- store.modals.signup && /* @__PURE__ */ jsxs(Fragment, { children: [
398
- /* @__PURE__ */ jsx(SignUpForm, { onSubmit: (values) => handlerSignup(values) }),
399
- /* @__PURE__ */ jsxs("div", { className: "flex justify-center items-center mt-4", children: [
400
- /* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "Ya tienes cuenta?" }),
401
- /* @__PURE__ */ jsx(
402
- "button",
403
- {
404
- type: "button",
405
- onClick: () => store.openModal("login"),
406
- className: "text-primary hover:underline ml-2 cursor-pointer",
407
- children: "Inicia sesion"
408
- }
409
- )
410
- ] })
411
- ] })
412
- ]
413
- }
414
- );
415
- };
416
- }
417
- });
418
- var Toaster;
419
- var init_Toaster = __esm({
420
- "src/react/shell/components/Toaster.tsx"() {
421
- "use client";
422
- Toaster = ({ ...props }) => {
423
- const { theme = "system" } = useTheme();
424
- return /* @__PURE__ */ jsx(
425
- Toaster$1,
426
- {
427
- theme,
428
- className: "toaster group",
429
- style: {
430
- "--normal-bg": "var(--popover)",
431
- "--normal-text": "var(--popover-foreground)",
432
- "--normal-border": "var(--border)"
433
- },
434
- ...props
435
- }
436
- );
437
- };
438
- }
439
- });
440
-
441
- // src/react/shell/providers/ecomiq-shell-ui.tsx
442
- var ecomiq_shell_ui_exports = {};
443
- __export(ecomiq_shell_ui_exports, {
444
- EcomiqShellUi: () => EcomiqShellUi
445
- });
446
- function EcomiqShellUi() {
447
- return /* @__PURE__ */ jsxs(Fragment, { children: [
448
- /* @__PURE__ */ jsx(ModalsFactory, {}),
449
- /* @__PURE__ */ jsx(Toaster, { position: "bottom-right" })
450
- ] });
451
- }
452
- var init_ecomiq_shell_ui = __esm({
453
- "src/react/shell/providers/ecomiq-shell-ui.tsx"() {
454
- "use client";
455
- init_modals_factory();
456
- init_Toaster();
457
- }
458
- });
459
-
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
- }
469
-
470
- // src/core/client/index.ts
471
- init_store_api_client();
472
-
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
- }
553
-
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);
577
- }
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({
773
- name: z.string().nullable().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()
786
- }).passthrough();
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()
801
- });
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)
818
- });
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()
827
- });
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()
835
- });
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)
862
- });
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({})
913
- });
914
- var OrderDraftShippingMethodSchema = z.object({
915
- id: z.string(),
916
- name: z.string().optional().default(""),
917
- description: z.string().nullable().optional(),
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);
993
- }
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;
1010
- }
1011
- }, [queryClient, dehydratedState]);
1012
- return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children });
1013
- }
1014
- var StorefrontAuthContext = createContext(null);
1015
- function StorefrontAuthProvider({
1016
- authClient,
1017
- children
1018
- }) {
1019
- return /* @__PURE__ */ jsx(StorefrontAuthContext.Provider, { value: authClient, children });
1020
- }
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;
1029
- }
1030
- function storefrontSessionEndsSoon(expiresAt, skewMs = 12e4) {
1031
- if (!expiresAt) return false;
1032
- return Date.now() + skewMs >= expiresAt.getTime();
1033
- }
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;
1041
- }
1042
- return void 0;
1043
- }
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) {
1050
- return {
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
1057
- };
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+/) : [];
1062
- return {
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
1069
- };
1070
- }
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"] });
1116
- }
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"] });
1146
- }
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)
1491
- });
1492
-
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
- )
1592
- }
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"
1607
- }
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
- });
1618
- }
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
- });
1625
- }
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
- });
1632
- }
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
- });
1644
- }
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());
1662
- }
1663
- if (tenantId?.trim()) {
1664
- headers.set("x-Tenant-Id", tenantId.trim());
1665
- }
1666
- if (storeId?.trim()) {
1667
- headers.set("x-Store-Id", storeId.trim());
1668
- }
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);
1680
- }
1681
- const json = safeParseJson(text);
1682
- if (!res.ok) {
1683
- throwBadRequestFromOAuth(json, res.statusText || text || `HTTP ${res.status}`);
1684
- }
1685
- const parsed = tokenResponseSchema.safeParse(json);
1686
- if (!parsed.success) {
1687
- throwBadRequestFromOAuth(json, "Token de acceso no recibido");
1688
- }
1689
- return parsed.data;
1690
- }
1691
- function safeParseJson(text) {
1692
- try {
1693
- return text ? JSON.parse(text) : {};
1694
- } catch {
1695
- return {};
1696
- }
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
- });
1716
- }
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
- });
1723
- }
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.");
1729
- }
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);
1743
- }
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()
1768
- });
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()
1785
- });
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()
1792
- });
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()
1799
- });
1800
- var StorefrontCmsContactSchema = z.object({
1801
- supportEmail: z.string().nullable().optional(),
1802
- phone: z.string().nullable().optional(),
1803
- whatsapp: z.string().nullable().optional(),
1804
- address: z.string().nullable().optional(),
1805
- socialLinks: StorefrontCmsSocialLinksSchema.optional()
1806
- });
1807
- var StorefrontCmsTrackingSchema = z.object({
1808
- googleAnalyticsMeasurementId: z.string().nullable().optional(),
1809
- metaPixelId: z.string().nullable().optional(),
1810
- googleTagManagerContainerId: z.string().nullable().optional()
1811
- });
1812
- var StorefrontCmsCustomScriptsSchema = z.object({
1813
- enabled: z.boolean().optional(),
1814
- head: z.string().nullable().optional(),
1815
- bodyEnd: z.string().nullable().optional()
1816
- });
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({
1827
- id: z.string(),
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(),
1849
- description: z.string().nullable().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()
1859
- }).passthrough();
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({
1916
- id: 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(),
1932
- name: z.string(),
1933
- description: z.string().nullable().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()
1949
- }).passthrough();
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
- })
1958
- }).passthrough();
1959
- var StorefrontSettingsSchema3 = z.preprocess(
1960
- normalizeStorefrontSettingsPayload,
1961
- StorefrontSettingsEnvelopeSchema
1962
- );
1963
- function storefrontStoreRecord(settings) {
1964
- return settings?.store ?? null;
1965
- }
1966
-
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");
1972
- }
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;
1981
- }
1982
-
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");
1992
- }
1993
- return response;
1994
- }
1995
- function isRenderableCmsPage(p) {
1996
- if (!p.status) return true;
1997
- return p.status === "published";
1998
- }
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;
2008
- }
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
- }
2018
- }
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
- }));
2024
- }
2025
- function findVariant(variants, selected, hasConfigurableOptions) {
2026
- if (!hasConfigurableOptions && variants.length > 0) {
2027
- return variants[0] ?? null;
2028
- }
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;
2034
- }
2035
- return null;
2036
- }
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;
2045
- }
2046
- return selected;
2047
- }
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
- ] });
2116
- }
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);
2136
- }
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"
2147
- }
2148
- });
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;
2156
- }
2157
- );
2158
- this.client.interceptors.response.use(
2159
- (response) => response,
2160
- (error) => {
2161
- console.error("API Error:", error);
2162
- return Promise.reject(error);
2163
- }
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);
2187
- }
2188
- };
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()
2544
- })
2545
- });
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()
2650
- });
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()
2662
- });
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);
2667
- if (!parsed.success) {
2668
- console.warn(
2669
- "[ecomiq] ecomiq.config.* inv\xE1lido:",
2670
- parsed.error.flatten().fieldErrors
2671
- );
2672
- return null;
2673
- }
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
- }
2691
- }
2692
- cachedConfig = null;
2693
- return null;
2694
- }
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
- );
2705
- }
2706
- return resolveStorefrontSettingsHost(hostHeader);
2707
- }
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}`);
2717
- }
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
- };
2749
- }
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
- };
2771
- }
2772
- }
2773
-
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
- }
2799
- return {
2800
- ok: true,
2801
- storeId: xStoreId || "",
2802
- storeDomain: xStoreDomain || null
2803
- };
2804
- }
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;
2842
- }
2843
- return null;
2844
- }
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("="));
2852
- }
2853
- }
2854
- return void 0;
2855
- }
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";
2900
- }
2901
- return { url, init };
2902
- }
2903
- function isResponseBodyForbidden(status) {
2904
- return status === 204 || status === 205 || status === 304;
2905
- }
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
2918
- );
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
- });
2937
- }
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);
2945
- }
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
- });
2960
- }
2961
-
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
1
+ export {
2
+ EcomiqProvider,
3
+ useStoreProducts,
4
+ useStoreCollections,
5
+ useStorePages,
6
+ useStoreCart,
7
+ useStore,
8
+ useCart,
9
+ useStorefrontSession,
10
+ useStorefrontAuthClient,
11
+ } from "./chunks/client.js";