@ecomiq/storefront 0.1.0 → 0.1.2
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.
- package/README.md +183 -78
- package/dist/..d.ts +30 -0
- package/dist/{store-CYBCpY6v.d.ts → collection-anMkdWa7.d.ts} +2667 -2667
- package/dist/core.d.ts +47 -51
- package/dist/core.js +324 -212
- package/dist/core.js.map +1 -1
- package/dist/find-storefront-cms-page-DNwLo1iV.d.ts +178 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +103 -0
- package/dist/index.js.map +1 -0
- package/dist/nextjs/globals.css +3 -4
- package/dist/nextjs.d.ts +59 -54
- package/dist/nextjs.js +871 -1483
- package/dist/nextjs.js.map +1 -1
- package/dist/react.d.ts +50 -130
- package/dist/react.js +1019 -1548
- package/dist/react.js.map +1 -1
- package/package.json +5 -1
- package/dist/find-storefront-cms-page-Bo0-G1FK.d.ts +0 -119
package/dist/react.js
CHANGED
|
@@ -1,15 +1,394 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
1
|
import { z } from 'zod';
|
|
2
|
+
import { Modal } from '@ecomiq/ui/components/modal';
|
|
3
|
+
import { formatCurrency as formatCurrency$1, StorefrontPageDetailSchema as StorefrontPageDetailSchema$1, useCart as useCart$1, useStore as useStore$1, useStorefrontAuthClient as useStorefrontAuthClient$1, useStorefrontSession as useStorefrontSession$1, SignInForm, SignUpForm, signInWithEcomiqCredentials } from '@ecomiq/storefront/react';
|
|
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 axios from 'axios';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
import { createRequire } from 'module';
|
|
10
|
+
import { join } from 'path';
|
|
11
|
+
import '@opennextjs/cloudflare';
|
|
12
|
+
import '@ecomiq/storefront/core';
|
|
3
13
|
import { QueryClient, hydrate, QueryClientProvider, useMutation, useQuery, useQueryClient, useInfiniteQuery } from '@tanstack/react-query';
|
|
4
|
-
import { createContext, useRef, useEffect, useContext, useState, useMemo, useCallback } from 'react';
|
|
5
|
-
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
14
|
+
import React2, { createContext, useRef, useEffect, useContext, useState, useMemo, useCallback } from 'react';
|
|
6
15
|
import { create } from 'zustand';
|
|
7
16
|
import { persist } from 'zustand/middleware';
|
|
8
17
|
import { createAuthMiddleware, createAuthEndpoint, formCsrfMiddleware } from 'better-auth/api';
|
|
9
18
|
import { APIError } from 'better-auth';
|
|
10
19
|
import { setSessionCookie } from 'better-auth/cookies';
|
|
11
20
|
import { parseUserOutput } from 'better-auth/db';
|
|
12
|
-
|
|
21
|
+
|
|
22
|
+
var __defProp = Object.defineProperty;
|
|
23
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
24
|
+
var __esm = (fn, res) => function __init() {
|
|
25
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
26
|
+
};
|
|
27
|
+
var __export = (target, all) => {
|
|
28
|
+
for (var name in all)
|
|
29
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/core/client/store-api-client.ts
|
|
33
|
+
function setClientStoreId(storeId) {
|
|
34
|
+
if (typeof window === "undefined") return;
|
|
35
|
+
clientStoreIdGetter = storeId?.trim() || null;
|
|
36
|
+
}
|
|
37
|
+
async function getStoreApiBaseUrl() {
|
|
38
|
+
if (typeof window !== "undefined") {
|
|
39
|
+
return STORE_API_PATH;
|
|
40
|
+
}
|
|
41
|
+
if (serverRequestOriginGetter) {
|
|
42
|
+
return `${serverRequestOriginGetter.replace(/\/$/, "")}/${STORE_API_PATH.replace(/^\//, "")}`;
|
|
43
|
+
}
|
|
44
|
+
return STORE_API_PATH;
|
|
45
|
+
}
|
|
46
|
+
async function getStoreApiClient() {
|
|
47
|
+
const baseUrl = await getStoreApiBaseUrl();
|
|
48
|
+
return new StoreApiClient(baseUrl);
|
|
49
|
+
}
|
|
50
|
+
var STORE_API_PATH, serverRequestOriginGetter, serverStoreIdGetter, clientStoreIdGetter, StoreApiClient;
|
|
51
|
+
var init_store_api_client = __esm({
|
|
52
|
+
"src/core/client/store-api-client.ts"() {
|
|
53
|
+
STORE_API_PATH = "/api/store";
|
|
54
|
+
serverRequestOriginGetter = null;
|
|
55
|
+
serverStoreIdGetter = null;
|
|
56
|
+
clientStoreIdGetter = null;
|
|
57
|
+
StoreApiClient = class {
|
|
58
|
+
baseUrl;
|
|
59
|
+
constructor(baseUrl = STORE_API_PATH) {
|
|
60
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
61
|
+
}
|
|
62
|
+
async request(path, init, options) {
|
|
63
|
+
const pathNorm = path.replace(/^\/+/, "");
|
|
64
|
+
const url = path.startsWith("http") ? path : `${this.baseUrl}/${pathNorm}`;
|
|
65
|
+
const headers = new Headers(init.headers ?? {});
|
|
66
|
+
headers.set("Content-Type", "application/json");
|
|
67
|
+
headers.set("Accept-Encoding", "identity");
|
|
68
|
+
const explicitStoreId = options?.xStoreId?.trim();
|
|
69
|
+
const runtimeStoreId = explicitStoreId || (typeof window === "undefined" ? serverStoreIdGetter : clientStoreIdGetter);
|
|
70
|
+
if (runtimeStoreId && !headers.has("x-store-id")) {
|
|
71
|
+
headers.set("X-Store-Id", runtimeStoreId);
|
|
72
|
+
}
|
|
73
|
+
if (options?.xStoreDomain) {
|
|
74
|
+
headers.set("X-Store-Domain", options.xStoreDomain);
|
|
75
|
+
}
|
|
76
|
+
if (options?.xCartId) {
|
|
77
|
+
headers.set("X-Cart-Token", options.xCartId);
|
|
78
|
+
}
|
|
79
|
+
const bearer = typeof options?.bearerToken === "string" && options.bearerToken.trim().length > 0 ? options.bearerToken.trim() : void 0;
|
|
80
|
+
if (bearer) {
|
|
81
|
+
headers.set(
|
|
82
|
+
"Authorization",
|
|
83
|
+
bearer.toLowerCase().startsWith("bearer ") ? bearer : `Bearer ${bearer}`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const isServer = typeof window === "undefined";
|
|
87
|
+
const res = await fetch(url, {
|
|
88
|
+
...init,
|
|
89
|
+
headers,
|
|
90
|
+
credentials: isServer ? "same-origin" : "include",
|
|
91
|
+
...options?.noStore ? { cache: "no-store" } : {},
|
|
92
|
+
...options?.cacheKey && isServer && !options?.noStore ? {
|
|
93
|
+
next: {
|
|
94
|
+
revalidate: 60,
|
|
95
|
+
tags: [options.cacheKey]
|
|
96
|
+
}
|
|
97
|
+
} : {}
|
|
98
|
+
});
|
|
99
|
+
if (!res.ok) {
|
|
100
|
+
let body;
|
|
101
|
+
try {
|
|
102
|
+
const errorText = await res.text();
|
|
103
|
+
body = errorText ? JSON.parse(errorText) : void 0;
|
|
104
|
+
} catch {
|
|
105
|
+
body = void 0;
|
|
106
|
+
}
|
|
107
|
+
const msg = typeof body === "object" && body !== null && "title" in body && typeof body.title === "string" ? body.title : res.statusText || "Store API error";
|
|
108
|
+
const err = new Error(msg);
|
|
109
|
+
err.status = res.status;
|
|
110
|
+
err.body = body;
|
|
111
|
+
throw err;
|
|
112
|
+
}
|
|
113
|
+
const text = await res.text();
|
|
114
|
+
if (!text) return void 0;
|
|
115
|
+
return JSON.parse(text);
|
|
116
|
+
}
|
|
117
|
+
get(path, options) {
|
|
118
|
+
return this.request(path, { method: "GET" }, options);
|
|
119
|
+
}
|
|
120
|
+
post(path, data, options) {
|
|
121
|
+
return this.request(
|
|
122
|
+
path,
|
|
123
|
+
{
|
|
124
|
+
method: "POST",
|
|
125
|
+
body: data != null ? JSON.stringify(data) : void 0
|
|
126
|
+
},
|
|
127
|
+
options
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
patch(path, data, options) {
|
|
131
|
+
return this.request(path, {
|
|
132
|
+
method: "PATCH",
|
|
133
|
+
body: data != null ? JSON.stringify(data) : void 0
|
|
134
|
+
}, options);
|
|
135
|
+
}
|
|
136
|
+
put(path, data, options) {
|
|
137
|
+
return this.request(
|
|
138
|
+
path,
|
|
139
|
+
{
|
|
140
|
+
method: "PUT",
|
|
141
|
+
body: data != null ? JSON.stringify(data) : void 0
|
|
142
|
+
},
|
|
143
|
+
options
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
delete(path, options) {
|
|
147
|
+
return this.request(path, { method: "DELETE" }, options);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
new StoreApiClient(STORE_API_PATH);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
function customerAuthOptions(accessToken) {
|
|
154
|
+
const token = typeof accessToken === "string" && accessToken.trim().length > 0 ? accessToken.trim() : void 0;
|
|
155
|
+
return token ? { bearerToken: token } : {};
|
|
156
|
+
}
|
|
157
|
+
async function registerCustomer(data) {
|
|
158
|
+
const payload = CustomerRegisterRequestSchema.parse(data);
|
|
159
|
+
const client = await getStoreApiClient();
|
|
160
|
+
return client.post("customer/register", payload);
|
|
161
|
+
}
|
|
162
|
+
async function getCustomerMe(accessToken) {
|
|
163
|
+
const client = await getStoreApiClient();
|
|
164
|
+
const response = await client.get("customer", customerAuthOptions(accessToken));
|
|
165
|
+
return CustomerMeSchema.parse(response);
|
|
166
|
+
}
|
|
167
|
+
var CustomerRegisterRequestSchema, CustomerAddressSchema, CustomerMeSchema;
|
|
168
|
+
var init_store_api_customer_service = __esm({
|
|
169
|
+
"src/core/client/store-api-customer.service.ts"() {
|
|
170
|
+
init_store_api_client();
|
|
171
|
+
CustomerRegisterRequestSchema = z.object({
|
|
172
|
+
email: z.string().email(),
|
|
173
|
+
firstName: z.string().trim().min(1),
|
|
174
|
+
lastName: z.string().trim().min(1),
|
|
175
|
+
countryIsoCode: z.string().trim().length(2),
|
|
176
|
+
password: z.string(),
|
|
177
|
+
phone: z.string().trim().optional()
|
|
178
|
+
});
|
|
179
|
+
CustomerAddressSchema = z.object({
|
|
180
|
+
/** Presente en listados cuando el upstream expone el id para PUT/DELETE. */
|
|
181
|
+
id: z.string().optional(),
|
|
182
|
+
addressKey: z.string(),
|
|
183
|
+
countryIsoCode: z.string(),
|
|
184
|
+
addressLine: z.string(),
|
|
185
|
+
addressNumber: z.string(),
|
|
186
|
+
department: z.string(),
|
|
187
|
+
province: z.string(),
|
|
188
|
+
district: z.string(),
|
|
189
|
+
phone: z.string(),
|
|
190
|
+
cellPhone: z.string(),
|
|
191
|
+
postalCode: z.string(),
|
|
192
|
+
reference: z.string(),
|
|
193
|
+
latitude: z.number().nullable(),
|
|
194
|
+
longitude: z.number().nullable(),
|
|
195
|
+
isDefault: z.boolean()
|
|
196
|
+
});
|
|
197
|
+
CustomerAddressSchema.omit({ id: true });
|
|
198
|
+
CustomerMeSchema = z.object({
|
|
199
|
+
id: z.string(),
|
|
200
|
+
storeId: z.string(),
|
|
201
|
+
email: z.string().email(),
|
|
202
|
+
firstName: z.string(),
|
|
203
|
+
lastName: z.string(),
|
|
204
|
+
phone: z.string(),
|
|
205
|
+
identificationNumber: z.string().nullable(),
|
|
206
|
+
identificationType: z.string().nullable(),
|
|
207
|
+
entityName: z.string().nullable(),
|
|
208
|
+
dateOfBirth: z.string().nullable(),
|
|
209
|
+
gender: z.string().nullable(),
|
|
210
|
+
countryIsoCode: z.string(),
|
|
211
|
+
role: z.string().nullable(),
|
|
212
|
+
companyName: z.string().nullable(),
|
|
213
|
+
consent: z.boolean(),
|
|
214
|
+
userId: z.string(),
|
|
215
|
+
customerType: z.string(),
|
|
216
|
+
status: z.string(),
|
|
217
|
+
entityIdentificationNumber: z.string().nullable(),
|
|
218
|
+
defaultAddressId: z.string().nullable(),
|
|
219
|
+
metadata: z.unknown().nullable(),
|
|
220
|
+
totalOrders: z.number(),
|
|
221
|
+
avgOrders: z.number(),
|
|
222
|
+
lastOrderId: z.string().nullable(),
|
|
223
|
+
lastOrderDate: z.string().nullable(),
|
|
224
|
+
loyaltyPoints: z.number(),
|
|
225
|
+
addresses: z.array(CustomerAddressSchema),
|
|
226
|
+
createdOn: z.string(),
|
|
227
|
+
updatedOn: z.string().nullable()
|
|
228
|
+
});
|
|
229
|
+
z.object({
|
|
230
|
+
firstName: z.string().trim().min(1),
|
|
231
|
+
lastName: z.string().trim().min(1),
|
|
232
|
+
phone: z.string().trim(),
|
|
233
|
+
identificationNumber: z.string().nullable(),
|
|
234
|
+
identificationType: z.string().nullable(),
|
|
235
|
+
entityName: z.string().nullable(),
|
|
236
|
+
entityIdentificationNumber: z.string().nullable(),
|
|
237
|
+
gender: z.string().nullable(),
|
|
238
|
+
role: z.string().nullable(),
|
|
239
|
+
companyName: z.string().nullable(),
|
|
240
|
+
dateOfBirth: z.string().nullable(),
|
|
241
|
+
consent: z.boolean(),
|
|
242
|
+
countryIsoCode: z.string().trim().length(2)
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
var ModalsFactory;
|
|
247
|
+
var init_modals_factory = __esm({
|
|
248
|
+
"src/react/shell/components/modals-factory.tsx"() {
|
|
249
|
+
"use client";
|
|
250
|
+
init_store_api_customer_service();
|
|
251
|
+
ModalsFactory = () => {
|
|
252
|
+
const cart = useCart$1();
|
|
253
|
+
const store = useStore$1();
|
|
254
|
+
const authClient = useStorefrontAuthClient$1();
|
|
255
|
+
const { refetch } = useStorefrontSession$1();
|
|
256
|
+
const handlerLogin = async (values) => {
|
|
257
|
+
try {
|
|
258
|
+
await signInWithEcomiqCredentials(authClient, store.data, values);
|
|
259
|
+
const me = await getCustomerMe();
|
|
260
|
+
const displayName = `${me.firstName} ${me.lastName}`.trim() || me.email;
|
|
261
|
+
const updateUserResponse = await authClient.$fetch("/update-user", {
|
|
262
|
+
method: "POST",
|
|
263
|
+
body: {
|
|
264
|
+
name: displayName,
|
|
265
|
+
firstName: me.firstName,
|
|
266
|
+
lastName: me.lastName,
|
|
267
|
+
phone: me.phone
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
if (updateUserResponse.error) {
|
|
271
|
+
throw new Error(updateUserResponse.error?.message ?? "No se pudo sincronizar el perfil");
|
|
272
|
+
}
|
|
273
|
+
if (me.email) {
|
|
274
|
+
cart.setCheckoutCustomerLocal({
|
|
275
|
+
email: me.email,
|
|
276
|
+
firstName: me.firstName,
|
|
277
|
+
lastName: me.lastName,
|
|
278
|
+
phone: me.phone ?? ""
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
await refetch();
|
|
282
|
+
toast.success("Sesi\xF3n iniciada correctamente");
|
|
283
|
+
store.closeModal("login");
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error("Error al iniciar sesion:", error);
|
|
286
|
+
toast.error("Error al iniciar sesion");
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
const handlerSignup = async (values) => {
|
|
290
|
+
try {
|
|
291
|
+
await registerCustomer({
|
|
292
|
+
email: values.email,
|
|
293
|
+
firstName: values.firstName,
|
|
294
|
+
lastName: values.lastName,
|
|
295
|
+
countryIsoCode: values.countryIsoCode,
|
|
296
|
+
password: values.password,
|
|
297
|
+
phone: values.phone
|
|
298
|
+
});
|
|
299
|
+
toast.success("Cuenta creada correctamente");
|
|
300
|
+
store.closeModal("signup");
|
|
301
|
+
setTimeout(() => {
|
|
302
|
+
store.openModal("login");
|
|
303
|
+
}, 1e3);
|
|
304
|
+
} catch (error) {
|
|
305
|
+
console.error("Error al registrarse:", error);
|
|
306
|
+
toast.error("Error al registrarse");
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
return /* @__PURE__ */ jsxs(
|
|
310
|
+
Modal,
|
|
311
|
+
{
|
|
312
|
+
isOpen: store.modals.login || store.modals.signup,
|
|
313
|
+
onClose: () => store.closeAllModals(),
|
|
314
|
+
children: [
|
|
315
|
+
store.modals.login && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
316
|
+
/* @__PURE__ */ jsx(SignInForm, { onSubmit: (values) => handlerLogin(values) }),
|
|
317
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-center items-center mt-4", children: [
|
|
318
|
+
/* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "No tienes cuenta?" }),
|
|
319
|
+
/* @__PURE__ */ jsx(
|
|
320
|
+
"button",
|
|
321
|
+
{
|
|
322
|
+
type: "button",
|
|
323
|
+
onClick: () => store.openModal("signup"),
|
|
324
|
+
className: "text-primary hover:underline ml-2 cursor-pointer",
|
|
325
|
+
children: "Registrate"
|
|
326
|
+
}
|
|
327
|
+
)
|
|
328
|
+
] })
|
|
329
|
+
] }),
|
|
330
|
+
store.modals.signup && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
331
|
+
/* @__PURE__ */ jsx(SignUpForm, { onSubmit: (values) => handlerSignup(values) }),
|
|
332
|
+
/* @__PURE__ */ jsxs("div", { className: "flex justify-center items-center mt-4", children: [
|
|
333
|
+
/* @__PURE__ */ jsx("p", { className: "text-gray-500", children: "Ya tienes cuenta?" }),
|
|
334
|
+
/* @__PURE__ */ jsx(
|
|
335
|
+
"button",
|
|
336
|
+
{
|
|
337
|
+
type: "button",
|
|
338
|
+
onClick: () => store.openModal("login"),
|
|
339
|
+
className: "text-primary hover:underline ml-2 cursor-pointer",
|
|
340
|
+
children: "Inicia sesion"
|
|
341
|
+
}
|
|
342
|
+
)
|
|
343
|
+
] })
|
|
344
|
+
] })
|
|
345
|
+
]
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
var Toaster;
|
|
352
|
+
var init_Toaster = __esm({
|
|
353
|
+
"src/react/shell/components/Toaster.tsx"() {
|
|
354
|
+
"use client";
|
|
355
|
+
Toaster = ({ ...props }) => {
|
|
356
|
+
const { theme = "system" } = useTheme();
|
|
357
|
+
return /* @__PURE__ */ jsx(
|
|
358
|
+
Toaster$1,
|
|
359
|
+
{
|
|
360
|
+
theme,
|
|
361
|
+
className: "toaster group",
|
|
362
|
+
style: {
|
|
363
|
+
"--normal-bg": "var(--popover)",
|
|
364
|
+
"--normal-text": "var(--popover-foreground)",
|
|
365
|
+
"--normal-border": "var(--border)"
|
|
366
|
+
},
|
|
367
|
+
...props
|
|
368
|
+
}
|
|
369
|
+
);
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// src/react/shell/providers/ecomiq-shell-ui.tsx
|
|
375
|
+
var ecomiq_shell_ui_exports = {};
|
|
376
|
+
__export(ecomiq_shell_ui_exports, {
|
|
377
|
+
EcomiqShellUi: () => EcomiqShellUi
|
|
378
|
+
});
|
|
379
|
+
function EcomiqShellUi() {
|
|
380
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
381
|
+
/* @__PURE__ */ jsx(ModalsFactory, {}),
|
|
382
|
+
/* @__PURE__ */ jsx(Toaster, { position: "bottom-right" })
|
|
383
|
+
] });
|
|
384
|
+
}
|
|
385
|
+
var init_ecomiq_shell_ui = __esm({
|
|
386
|
+
"src/react/shell/providers/ecomiq-shell-ui.tsx"() {
|
|
387
|
+
"use client";
|
|
388
|
+
init_modals_factory();
|
|
389
|
+
init_Toaster();
|
|
390
|
+
}
|
|
391
|
+
});
|
|
13
392
|
|
|
14
393
|
// src/core/constants/api-paths.ts
|
|
15
394
|
var STOREFRONT_API_PATH_PREFIX = "v1";
|
|
@@ -34,46 +413,272 @@ function formatCurrency(amount, currency = "USD") {
|
|
|
34
413
|
currency
|
|
35
414
|
}).format(amount);
|
|
36
415
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
416
|
+
var StorefrontCheckoutSettingsSchema = z.object({
|
|
417
|
+
allowGuestCheckout: z.boolean().optional(),
|
|
418
|
+
identityScope: z.enum(["store", "tenant", "global"]).optional(),
|
|
419
|
+
signInMethods: z.array(z.string()).optional()
|
|
420
|
+
});
|
|
421
|
+
var looseRecord = z.record(z.string(), z.unknown());
|
|
422
|
+
var StorefrontThemeConfigSchema = z.object({
|
|
423
|
+
name: z.string().nullable().optional(),
|
|
424
|
+
mode: z.string().nullable().optional(),
|
|
425
|
+
colors: looseRecord.optional(),
|
|
426
|
+
fonts: looseRecord.optional(),
|
|
427
|
+
assets: looseRecord.optional()
|
|
428
|
+
}).passthrough();
|
|
429
|
+
var StorefrontFeaturesEnabledSchema = z.object({
|
|
430
|
+
flags: looseRecord.optional()
|
|
431
|
+
}).passthrough();
|
|
432
|
+
var StorefrontCmsBrandingSchema = z.object({
|
|
433
|
+
logoUrl: z.string().nullable().optional(),
|
|
434
|
+
logoDarkUrl: z.string().nullable().optional(),
|
|
435
|
+
faviconUrl: z.string().nullable().optional(),
|
|
436
|
+
socialImageUrl: z.string().nullable().optional()
|
|
437
|
+
});
|
|
438
|
+
var StorefrontCmsSeoSchema = z.object({
|
|
439
|
+
siteName: z.string().nullable().optional(),
|
|
440
|
+
metaTitle: z.string().nullable().optional(),
|
|
441
|
+
metaDescription: z.string().nullable().optional(),
|
|
442
|
+
titleTemplate: z.string().nullable().optional(),
|
|
443
|
+
robotsIndex: z.boolean().optional()
|
|
444
|
+
});
|
|
445
|
+
var StorefrontCmsSocialLinksSchema = z.object({
|
|
446
|
+
instagram: z.string().nullable().optional(),
|
|
447
|
+
facebook: z.string().nullable().optional(),
|
|
448
|
+
tiktok: z.string().nullable().optional(),
|
|
449
|
+
youtube: z.string().nullable().optional(),
|
|
450
|
+
x: z.string().nullable().optional()
|
|
451
|
+
});
|
|
452
|
+
var StorefrontCmsContactSchema = z.object({
|
|
453
|
+
supportEmail: z.string().nullable().optional(),
|
|
454
|
+
phone: z.string().nullable().optional(),
|
|
455
|
+
whatsapp: z.string().nullable().optional(),
|
|
456
|
+
address: z.string().nullable().optional(),
|
|
457
|
+
socialLinks: StorefrontCmsSocialLinksSchema.optional()
|
|
458
|
+
});
|
|
459
|
+
var StorefrontCmsTrackingSchema = z.object({
|
|
460
|
+
googleAnalyticsMeasurementId: z.string().nullable().optional(),
|
|
461
|
+
metaPixelId: z.string().nullable().optional(),
|
|
462
|
+
googleTagManagerContainerId: z.string().nullable().optional()
|
|
463
|
+
});
|
|
464
|
+
var StorefrontCmsCustomScriptsSchema = z.object({
|
|
465
|
+
enabled: z.boolean().optional(),
|
|
466
|
+
head: z.string().nullable().optional(),
|
|
467
|
+
bodyEnd: z.string().nullable().optional()
|
|
468
|
+
});
|
|
469
|
+
var StorefrontCmsSettingsSchema = z.object({
|
|
470
|
+
themeKey: z.string().optional(),
|
|
471
|
+
branding: StorefrontCmsBrandingSchema.optional(),
|
|
472
|
+
seo: StorefrontCmsSeoSchema.optional(),
|
|
473
|
+
contact: StorefrontCmsContactSchema.optional(),
|
|
474
|
+
tracking: StorefrontCmsTrackingSchema.optional(),
|
|
475
|
+
customScripts: StorefrontCmsCustomScriptsSchema.optional(),
|
|
476
|
+
updatedOn: z.string().nullable().optional()
|
|
477
|
+
});
|
|
478
|
+
var StorefrontCmsPageSchema = z.object({
|
|
479
|
+
id: z.string(),
|
|
480
|
+
name: z.string(),
|
|
481
|
+
slug: z.string(),
|
|
482
|
+
layout: z.string().optional(),
|
|
483
|
+
version: z.number().optional(),
|
|
484
|
+
settings: z.record(z.string(), z.unknown()).optional().nullable(),
|
|
485
|
+
sections: z.array(z.unknown()).optional(),
|
|
486
|
+
status: z.string().optional(),
|
|
487
|
+
hasPublishedVersion: z.boolean().optional(),
|
|
488
|
+
publishedOn: z.string().nullable().optional(),
|
|
489
|
+
publishedBy: z.string().nullable().optional(),
|
|
490
|
+
createdOn: z.string().nullable().optional(),
|
|
491
|
+
updatedOn: z.string().nullable().optional(),
|
|
492
|
+
createdBy: z.string().nullable().optional(),
|
|
493
|
+
updatedBy: z.string().nullable().optional(),
|
|
494
|
+
lastModifiedBy: z.string().nullable().optional()
|
|
495
|
+
}).passthrough();
|
|
496
|
+
var StorefrontSettingsLegacyFlatSchema = z.object({
|
|
497
|
+
id: z.coerce.string(),
|
|
498
|
+
tenantId: z.string().nullable().optional(),
|
|
499
|
+
name: z.string(),
|
|
500
|
+
slug: z.coerce.string().optional(),
|
|
501
|
+
description: z.string().nullable().optional(),
|
|
502
|
+
visibility: z.string().nullable().optional(),
|
|
503
|
+
logo: z.string().nullable().optional(),
|
|
504
|
+
favicon: z.string().nullable().optional(),
|
|
505
|
+
icon: z.string().nullable().optional(),
|
|
506
|
+
currency: z.string().nullable().optional(),
|
|
507
|
+
language: z.string().nullable().optional(),
|
|
508
|
+
themeConfig: z.unknown().optional().nullable(),
|
|
509
|
+
featuresEnabled: z.unknown().optional().nullable(),
|
|
510
|
+
checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
|
|
511
|
+
}).passthrough();
|
|
512
|
+
function unwrapSettingsResponseBody(v) {
|
|
513
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return v;
|
|
514
|
+
const o = v;
|
|
515
|
+
if ("data" in o && o.data != null && typeof o.data === "object" && !Array.isArray(o.data)) {
|
|
516
|
+
return o.data;
|
|
517
|
+
}
|
|
518
|
+
return v;
|
|
56
519
|
}
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
if (s.includes("confirm") || s.includes("paid") || s.includes("capture")) return "success";
|
|
63
|
-
if (s.includes("pending") || s.includes("new") || s.includes("process")) return "warning";
|
|
64
|
-
return "default";
|
|
520
|
+
function isLegacyFlatSettingsPayload(v) {
|
|
521
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return false;
|
|
522
|
+
const o = v;
|
|
523
|
+
if ("store" in o || "schemaVersion" in o || "cms" in o) return false;
|
|
524
|
+
return (typeof o.id === "string" || typeof o.id === "number") && typeof o.name === "string";
|
|
65
525
|
}
|
|
66
|
-
function
|
|
67
|
-
const
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
526
|
+
function normalizeStorefrontSettingsPayload(v) {
|
|
527
|
+
const body = unwrapSettingsResponseBody(v);
|
|
528
|
+
if (!isLegacyFlatSettingsPayload(body)) return body;
|
|
529
|
+
const raw = body;
|
|
530
|
+
const parsed = StorefrontSettingsLegacyFlatSchema.safeParse(raw);
|
|
531
|
+
if (!parsed.success) return body;
|
|
532
|
+
const l = parsed.data;
|
|
533
|
+
const currency = l.currency?.trim() ? l.currency : "PEN";
|
|
534
|
+
const language = l.language?.trim() ? l.language : "es";
|
|
535
|
+
const slug = l.slug?.trim() ? l.slug : l.id;
|
|
536
|
+
return {
|
|
537
|
+
schemaVersion: 0,
|
|
538
|
+
generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
539
|
+
store: {
|
|
540
|
+
id: l.id,
|
|
541
|
+
tenantId: l.tenantId ?? void 0,
|
|
542
|
+
name: l.name,
|
|
543
|
+
slug,
|
|
544
|
+
description: l.description ?? null,
|
|
545
|
+
logo: l.logo ?? null,
|
|
546
|
+
icon: l.icon ?? null,
|
|
547
|
+
visibility: l.visibility ?? void 0,
|
|
548
|
+
currency,
|
|
549
|
+
language,
|
|
550
|
+
themeConfig: l.themeConfig ?? void 0,
|
|
551
|
+
featuresEnabled: l.featuresEnabled ?? void 0,
|
|
552
|
+
checkoutSettings: l.checkoutSettings ?? void 0
|
|
553
|
+
},
|
|
554
|
+
cms: {
|
|
555
|
+
settings: {
|
|
556
|
+
branding: {
|
|
557
|
+
faviconUrl: l.favicon ?? null,
|
|
558
|
+
logoUrl: l.logo ?? null,
|
|
559
|
+
logoDarkUrl: null,
|
|
560
|
+
socialImageUrl: null
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
pages: []
|
|
564
|
+
}
|
|
565
|
+
};
|
|
74
566
|
}
|
|
75
|
-
|
|
76
|
-
|
|
567
|
+
var StorefrontStoreSchema = z.object({
|
|
568
|
+
id: z.string(),
|
|
569
|
+
tenantId: z.string().optional(),
|
|
570
|
+
sellerId: z.string().optional(),
|
|
571
|
+
plan: z.string().optional(),
|
|
572
|
+
storageLimitBytes: z.number().optional(),
|
|
573
|
+
monthlyTransferLimitBytes: z.number().optional(),
|
|
574
|
+
maxUploadSizeBytes: z.number().optional(),
|
|
575
|
+
maxStores: z.number().optional(),
|
|
576
|
+
maxMembers: z.number().optional(),
|
|
577
|
+
maxProducts: z.number().optional(),
|
|
578
|
+
maxCategories: z.number().optional(),
|
|
579
|
+
maxBrands: z.number().optional(),
|
|
580
|
+
maxAttributes: z.number().optional(),
|
|
581
|
+
maxCollections: z.number().optional(),
|
|
582
|
+
enableApi: z.boolean().optional(),
|
|
583
|
+
isActive: z.boolean().optional(),
|
|
584
|
+
name: z.string(),
|
|
585
|
+
description: z.string().nullable().optional(),
|
|
586
|
+
avatarUrl: z.string().nullable().optional(),
|
|
587
|
+
logo: z.string().nullable().optional(),
|
|
588
|
+
icon: z.string().nullable().optional(),
|
|
589
|
+
slug: z.string(),
|
|
590
|
+
domain: z.string().nullable().optional(),
|
|
591
|
+
domains: z.array(z.string()).optional(),
|
|
592
|
+
timeZone: z.string().nullable().optional(),
|
|
593
|
+
currency: z.string(),
|
|
594
|
+
language: z.string(),
|
|
595
|
+
visibility: z.string().optional(),
|
|
596
|
+
privateAccessHash: z.string().nullable().optional(),
|
|
597
|
+
privateAccessVersion: z.number().optional(),
|
|
598
|
+
themeConfig: StorefrontThemeConfigSchema.optional(),
|
|
599
|
+
featuresEnabled: StorefrontFeaturesEnabledSchema.optional(),
|
|
600
|
+
checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
|
|
601
|
+
}).passthrough();
|
|
602
|
+
var StorefrontSettingsEnvelopeSchema = z.object({
|
|
603
|
+
schemaVersion: z.number(),
|
|
604
|
+
generatedAt: z.string(),
|
|
605
|
+
store: StorefrontStoreSchema,
|
|
606
|
+
cms: z.object({
|
|
607
|
+
settings: StorefrontCmsSettingsSchema,
|
|
608
|
+
pages: z.array(StorefrontCmsPageSchema)
|
|
609
|
+
})
|
|
610
|
+
}).passthrough();
|
|
611
|
+
var StorefrontSettingsSchema = z.preprocess(
|
|
612
|
+
normalizeStorefrontSettingsPayload,
|
|
613
|
+
StorefrontSettingsEnvelopeSchema
|
|
614
|
+
);
|
|
615
|
+
function storefrontStoreRecord(settings) {
|
|
616
|
+
return settings?.store ?? null;
|
|
617
|
+
}
|
|
618
|
+
function storefrontFaviconUrl(settings) {
|
|
619
|
+
const b = settings?.cms?.settings?.branding;
|
|
620
|
+
return b?.faviconUrl ?? settings?.store?.logo ?? settings?.store?.icon ?? null;
|
|
621
|
+
}
|
|
622
|
+
function storefrontOgImageUrl(settings) {
|
|
623
|
+
const b = settings?.cms?.settings?.branding;
|
|
624
|
+
return b?.socialImageUrl ?? settings?.store?.logo ?? null;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// src/core/lib/ecomiq-oauth-identity.ts
|
|
628
|
+
function buildEcomiqOAuthIdentityHeaders(settings) {
|
|
629
|
+
const record = storefrontStoreRecord(settings);
|
|
630
|
+
if (!record?.id) {
|
|
631
|
+
throw new Error("Tienda no disponible para iniciar sesi\xF3n");
|
|
632
|
+
}
|
|
633
|
+
const checkout = record.checkoutSettings;
|
|
634
|
+
const identityScope = checkout?.identityScope === "tenant" ? "tenant" : "store";
|
|
635
|
+
const headers = {
|
|
636
|
+
"x-Identity-Scope": identityScope,
|
|
637
|
+
"x-Store-Id": record.id
|
|
638
|
+
};
|
|
639
|
+
if (record.tenantId) headers["x-Tenant-Id"] = record.tenantId;
|
|
640
|
+
return headers;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// src/core/lib/customer-order-labels.ts
|
|
644
|
+
var ORDER_STATUS_LABELS = {
|
|
645
|
+
New: "Pedido realizado",
|
|
646
|
+
Confirmed: "Confirmado",
|
|
647
|
+
Processing: "En preparaci\xF3n",
|
|
648
|
+
InTransit: "En camino",
|
|
649
|
+
Delivered: "Entregado",
|
|
650
|
+
Cancelled: "Cancelado",
|
|
651
|
+
Canceled: "Cancelado",
|
|
652
|
+
Refunded: "Reembolsado",
|
|
653
|
+
Pending: "Pendiente",
|
|
654
|
+
Paid: "Pagado",
|
|
655
|
+
Captured: "Pago confirmado"
|
|
656
|
+
};
|
|
657
|
+
function formatCustomerOrderStatus(status) {
|
|
658
|
+
const trimmed = status.trim();
|
|
659
|
+
if (!trimmed) return "Desconocido";
|
|
660
|
+
return ORDER_STATUS_LABELS[trimmed] ?? trimmed.replace(/([A-Z])/g, " $1").trim();
|
|
661
|
+
}
|
|
662
|
+
function customerOrderStatusTone(status) {
|
|
663
|
+
const s = status.toLowerCase();
|
|
664
|
+
if (s.includes("cancel") || s.includes("refund")) return "danger";
|
|
665
|
+
if (s.includes("deliver")) return "success";
|
|
666
|
+
if (s.includes("transit") || s.includes("ship")) return "info";
|
|
667
|
+
if (s.includes("confirm") || s.includes("paid") || s.includes("capture")) return "success";
|
|
668
|
+
if (s.includes("pending") || s.includes("new") || s.includes("process")) return "warning";
|
|
669
|
+
return "default";
|
|
670
|
+
}
|
|
671
|
+
function formatOrderDate(iso, locale = "es-PE") {
|
|
672
|
+
const d = new Date(iso);
|
|
673
|
+
if (Number.isNaN(d.getTime())) return iso;
|
|
674
|
+
return new Intl.DateTimeFormat(locale, {
|
|
675
|
+
day: "numeric",
|
|
676
|
+
month: "long",
|
|
677
|
+
year: "numeric"
|
|
678
|
+
}).format(d);
|
|
679
|
+
}
|
|
680
|
+
function formatOrderDateTime(iso, locale = "es-PE") {
|
|
681
|
+
const d = new Date(iso);
|
|
77
682
|
if (Number.isNaN(d.getTime())) return iso;
|
|
78
683
|
return new Intl.DateTimeFormat(locale, {
|
|
79
684
|
day: "numeric",
|
|
@@ -608,293 +1213,83 @@ var PageService = class _PageService {
|
|
|
608
1213
|
}
|
|
609
1214
|
};
|
|
610
1215
|
var pageService = PageService.getInstance();
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
1216
|
+
|
|
1217
|
+
// src/core/services/store.service.ts
|
|
1218
|
+
var StoreService = class _StoreService {
|
|
1219
|
+
static instance;
|
|
1220
|
+
constructor() {
|
|
1221
|
+
}
|
|
1222
|
+
static getInstance() {
|
|
1223
|
+
if (!_StoreService.instance) {
|
|
1224
|
+
_StoreService.instance = new _StoreService();
|
|
1225
|
+
}
|
|
1226
|
+
return _StoreService.instance;
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Obtiene la configuración de la tienda por subdominio (GET /v1/settings).
|
|
1230
|
+
* Usa el header X-Store-Domain. Si se pasa domain, se configura antes de la petición.
|
|
1231
|
+
*/
|
|
1232
|
+
async getStorefrontSettings(domain) {
|
|
1233
|
+
if (domain) {
|
|
1234
|
+
apiClient.setStoreDomain(domain);
|
|
1235
|
+
}
|
|
1236
|
+
const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/settings`);
|
|
1237
|
+
return StorefrontSettingsSchema.parse(response);
|
|
1238
|
+
}
|
|
1239
|
+
};
|
|
1240
|
+
var storeService = StoreService.getInstance();
|
|
1241
|
+
var CartBuyerRequestSchema = z.object({
|
|
1242
|
+
email: z.string().email(),
|
|
1243
|
+
firstName: z.string().min(1),
|
|
1244
|
+
lastName: z.string().min(1),
|
|
1245
|
+
phone: z.string().min(1)
|
|
615
1246
|
});
|
|
616
|
-
var
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
colors: looseRecord.optional(),
|
|
621
|
-
fonts: looseRecord.optional(),
|
|
622
|
-
assets: looseRecord.optional()
|
|
623
|
-
}).passthrough();
|
|
624
|
-
var StorefrontFeaturesEnabledSchema = z.object({
|
|
625
|
-
flags: looseRecord.optional()
|
|
626
|
-
}).passthrough();
|
|
627
|
-
var StorefrontCmsBrandingSchema = z.object({
|
|
628
|
-
logoUrl: z.string().nullable().optional(),
|
|
629
|
-
logoDarkUrl: z.string().nullable().optional(),
|
|
630
|
-
faviconUrl: z.string().nullable().optional(),
|
|
631
|
-
socialImageUrl: z.string().nullable().optional()
|
|
1247
|
+
var CartCreateRequestSchema = z.object({
|
|
1248
|
+
currencyCode: z.string(),
|
|
1249
|
+
salesChannelId: z.string(),
|
|
1250
|
+
email: z.string().email()
|
|
632
1251
|
});
|
|
633
|
-
var
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
1252
|
+
var CartAddressSchema = z.object({
|
|
1253
|
+
name: z.string().min(1),
|
|
1254
|
+
address1: z.string().min(1),
|
|
1255
|
+
city: z.string().min(1),
|
|
1256
|
+
countryCode: z.string().min(2),
|
|
1257
|
+
company: z.string().nullable().optional(),
|
|
1258
|
+
address2: z.string().nullable().optional(),
|
|
1259
|
+
province: z.string().nullable().optional(),
|
|
1260
|
+
postalCode: z.string().nullable().optional(),
|
|
1261
|
+
district: z.string().nullable().optional(),
|
|
1262
|
+
phone: z.string().nullable().optional(),
|
|
1263
|
+
latitude: z.number().nullable().optional(),
|
|
1264
|
+
longitude: z.number().nullable().optional(),
|
|
1265
|
+
geo: z.object({
|
|
1266
|
+
departmentCode: z.string().nullable().optional(),
|
|
1267
|
+
provinceCode: z.string().nullable().optional(),
|
|
1268
|
+
districtCode: z.string().nullable().optional()
|
|
1269
|
+
}).nullable().optional()
|
|
639
1270
|
});
|
|
640
|
-
var
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
tiktok: z.string().nullable().optional(),
|
|
644
|
-
youtube: z.string().nullable().optional(),
|
|
645
|
-
x: z.string().nullable().optional()
|
|
1271
|
+
var CartAddressesRequestSchema = z.object({
|
|
1272
|
+
shippingAddress: CartAddressSchema,
|
|
1273
|
+
billingAddress: CartAddressSchema
|
|
646
1274
|
});
|
|
647
|
-
var
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
whatsapp: z.string().nullable().optional(),
|
|
651
|
-
address: z.string().nullable().optional(),
|
|
652
|
-
socialLinks: StorefrontCmsSocialLinksSchema.optional()
|
|
1275
|
+
var CartItemModifierRequestSchema = z.object({
|
|
1276
|
+
modifierGroupId: z.coerce.string().min(1),
|
|
1277
|
+
optionIds: z.array(z.coerce.string().min(1)).optional().default([])
|
|
653
1278
|
});
|
|
654
|
-
var
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
1279
|
+
var CartItemRequestSchema = z.object({
|
|
1280
|
+
variantId: z.coerce.string().min(1),
|
|
1281
|
+
quantity: z.number().int().positive(),
|
|
1282
|
+
modifiers: z.array(CartItemModifierRequestSchema).optional()
|
|
658
1283
|
});
|
|
659
|
-
var
|
|
660
|
-
|
|
661
|
-
head: z.string().nullable().optional(),
|
|
662
|
-
bodyEnd: z.string().nullable().optional()
|
|
1284
|
+
var CartCouponRequestSchema = z.object({
|
|
1285
|
+
code: z.string().min(1)
|
|
663
1286
|
});
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
customScripts: StorefrontCmsCustomScriptsSchema.optional(),
|
|
671
|
-
updatedOn: z.string().nullable().optional()
|
|
672
|
-
});
|
|
673
|
-
var StorefrontCmsPageSchema = z.object({
|
|
674
|
-
id: z.string(),
|
|
675
|
-
name: z.string(),
|
|
676
|
-
slug: z.string(),
|
|
677
|
-
layout: z.string().optional(),
|
|
678
|
-
version: z.number().optional(),
|
|
679
|
-
settings: z.record(z.string(), z.unknown()).optional().nullable(),
|
|
680
|
-
sections: z.array(z.unknown()).optional(),
|
|
681
|
-
status: z.string().optional(),
|
|
682
|
-
hasPublishedVersion: z.boolean().optional(),
|
|
683
|
-
publishedOn: z.string().nullable().optional(),
|
|
684
|
-
publishedBy: z.string().nullable().optional(),
|
|
685
|
-
createdOn: z.string().nullable().optional(),
|
|
686
|
-
updatedOn: z.string().nullable().optional(),
|
|
687
|
-
createdBy: z.string().nullable().optional(),
|
|
688
|
-
updatedBy: z.string().nullable().optional(),
|
|
689
|
-
lastModifiedBy: z.string().nullable().optional()
|
|
690
|
-
}).passthrough();
|
|
691
|
-
var StorefrontSettingsLegacyFlatSchema = z.object({
|
|
692
|
-
id: z.coerce.string(),
|
|
693
|
-
tenantId: z.string().nullable().optional(),
|
|
694
|
-
name: z.string(),
|
|
695
|
-
slug: z.coerce.string().optional(),
|
|
696
|
-
description: z.string().nullable().optional(),
|
|
697
|
-
visibility: z.string().nullable().optional(),
|
|
698
|
-
logo: z.string().nullable().optional(),
|
|
699
|
-
favicon: z.string().nullable().optional(),
|
|
700
|
-
icon: z.string().nullable().optional(),
|
|
701
|
-
currency: z.string().nullable().optional(),
|
|
702
|
-
language: z.string().nullable().optional(),
|
|
703
|
-
themeConfig: z.unknown().optional().nullable(),
|
|
704
|
-
featuresEnabled: z.unknown().optional().nullable(),
|
|
705
|
-
checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
|
|
706
|
-
}).passthrough();
|
|
707
|
-
function unwrapSettingsResponseBody(v) {
|
|
708
|
-
if (!v || typeof v !== "object" || Array.isArray(v)) return v;
|
|
709
|
-
const o = v;
|
|
710
|
-
if ("data" in o && o.data != null && typeof o.data === "object" && !Array.isArray(o.data)) {
|
|
711
|
-
return o.data;
|
|
712
|
-
}
|
|
713
|
-
return v;
|
|
714
|
-
}
|
|
715
|
-
function isLegacyFlatSettingsPayload(v) {
|
|
716
|
-
if (!v || typeof v !== "object" || Array.isArray(v)) return false;
|
|
717
|
-
const o = v;
|
|
718
|
-
if ("store" in o || "schemaVersion" in o || "cms" in o) return false;
|
|
719
|
-
return (typeof o.id === "string" || typeof o.id === "number") && typeof o.name === "string";
|
|
720
|
-
}
|
|
721
|
-
function normalizeStorefrontSettingsPayload(v) {
|
|
722
|
-
const body = unwrapSettingsResponseBody(v);
|
|
723
|
-
if (!isLegacyFlatSettingsPayload(body)) return body;
|
|
724
|
-
const raw = body;
|
|
725
|
-
const parsed = StorefrontSettingsLegacyFlatSchema.safeParse(raw);
|
|
726
|
-
if (!parsed.success) return body;
|
|
727
|
-
const l = parsed.data;
|
|
728
|
-
const currency = l.currency?.trim() ? l.currency : "PEN";
|
|
729
|
-
const language = l.language?.trim() ? l.language : "es";
|
|
730
|
-
const slug = l.slug?.trim() ? l.slug : l.id;
|
|
731
|
-
return {
|
|
732
|
-
schemaVersion: 0,
|
|
733
|
-
generatedAt: (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
734
|
-
store: {
|
|
735
|
-
id: l.id,
|
|
736
|
-
tenantId: l.tenantId ?? void 0,
|
|
737
|
-
name: l.name,
|
|
738
|
-
slug,
|
|
739
|
-
description: l.description ?? null,
|
|
740
|
-
logo: l.logo ?? null,
|
|
741
|
-
icon: l.icon ?? null,
|
|
742
|
-
visibility: l.visibility ?? void 0,
|
|
743
|
-
currency,
|
|
744
|
-
language,
|
|
745
|
-
themeConfig: l.themeConfig ?? void 0,
|
|
746
|
-
featuresEnabled: l.featuresEnabled ?? void 0,
|
|
747
|
-
checkoutSettings: l.checkoutSettings ?? void 0
|
|
748
|
-
},
|
|
749
|
-
cms: {
|
|
750
|
-
settings: {
|
|
751
|
-
branding: {
|
|
752
|
-
faviconUrl: l.favicon ?? null,
|
|
753
|
-
logoUrl: l.logo ?? null,
|
|
754
|
-
logoDarkUrl: null,
|
|
755
|
-
socialImageUrl: null
|
|
756
|
-
}
|
|
757
|
-
},
|
|
758
|
-
pages: []
|
|
759
|
-
}
|
|
760
|
-
};
|
|
761
|
-
}
|
|
762
|
-
var StorefrontStoreSchema = z.object({
|
|
763
|
-
id: z.string(),
|
|
764
|
-
tenantId: z.string().optional(),
|
|
765
|
-
sellerId: z.string().optional(),
|
|
766
|
-
plan: z.string().optional(),
|
|
767
|
-
storageLimitBytes: z.number().optional(),
|
|
768
|
-
monthlyTransferLimitBytes: z.number().optional(),
|
|
769
|
-
maxUploadSizeBytes: z.number().optional(),
|
|
770
|
-
maxStores: z.number().optional(),
|
|
771
|
-
maxMembers: z.number().optional(),
|
|
772
|
-
maxProducts: z.number().optional(),
|
|
773
|
-
maxCategories: z.number().optional(),
|
|
774
|
-
maxBrands: z.number().optional(),
|
|
775
|
-
maxAttributes: z.number().optional(),
|
|
776
|
-
maxCollections: z.number().optional(),
|
|
777
|
-
enableApi: z.boolean().optional(),
|
|
778
|
-
isActive: z.boolean().optional(),
|
|
779
|
-
name: z.string(),
|
|
780
|
-
description: z.string().nullable().optional(),
|
|
781
|
-
avatarUrl: z.string().nullable().optional(),
|
|
782
|
-
logo: z.string().nullable().optional(),
|
|
783
|
-
icon: z.string().nullable().optional(),
|
|
784
|
-
slug: z.string(),
|
|
785
|
-
domain: z.string().nullable().optional(),
|
|
786
|
-
domains: z.array(z.string()).optional(),
|
|
787
|
-
timeZone: z.string().nullable().optional(),
|
|
788
|
-
currency: z.string(),
|
|
789
|
-
language: z.string(),
|
|
790
|
-
visibility: z.string().optional(),
|
|
791
|
-
privateAccessHash: z.string().nullable().optional(),
|
|
792
|
-
privateAccessVersion: z.number().optional(),
|
|
793
|
-
themeConfig: StorefrontThemeConfigSchema.optional(),
|
|
794
|
-
featuresEnabled: StorefrontFeaturesEnabledSchema.optional(),
|
|
795
|
-
checkoutSettings: StorefrontCheckoutSettingsSchema.optional().nullable()
|
|
796
|
-
}).passthrough();
|
|
797
|
-
var StorefrontSettingsEnvelopeSchema = z.object({
|
|
798
|
-
schemaVersion: z.number(),
|
|
799
|
-
generatedAt: z.string(),
|
|
800
|
-
store: StorefrontStoreSchema,
|
|
801
|
-
cms: z.object({
|
|
802
|
-
settings: StorefrontCmsSettingsSchema,
|
|
803
|
-
pages: z.array(StorefrontCmsPageSchema)
|
|
804
|
-
})
|
|
805
|
-
}).passthrough();
|
|
806
|
-
var StorefrontSettingsSchema = z.preprocess(
|
|
807
|
-
normalizeStorefrontSettingsPayload,
|
|
808
|
-
StorefrontSettingsEnvelopeSchema
|
|
809
|
-
);
|
|
810
|
-
function storefrontStoreRecord(settings) {
|
|
811
|
-
return settings?.store ?? null;
|
|
812
|
-
}
|
|
813
|
-
function storefrontFaviconUrl(settings) {
|
|
814
|
-
const b = settings?.cms?.settings?.branding;
|
|
815
|
-
return b?.faviconUrl ?? settings?.store?.logo ?? settings?.store?.icon ?? null;
|
|
816
|
-
}
|
|
817
|
-
function storefrontOgImageUrl(settings) {
|
|
818
|
-
const b = settings?.cms?.settings?.branding;
|
|
819
|
-
return b?.socialImageUrl ?? settings?.store?.logo ?? null;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
// src/core/services/store.service.ts
|
|
823
|
-
var StoreService = class _StoreService {
|
|
824
|
-
static instance;
|
|
825
|
-
constructor() {
|
|
826
|
-
}
|
|
827
|
-
static getInstance() {
|
|
828
|
-
if (!_StoreService.instance) {
|
|
829
|
-
_StoreService.instance = new _StoreService();
|
|
830
|
-
}
|
|
831
|
-
return _StoreService.instance;
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* Obtiene la configuración de la tienda por subdominio (GET /v1/settings).
|
|
835
|
-
* Usa el header X-Store-Domain. Si se pasa domain, se configura antes de la petición.
|
|
836
|
-
*/
|
|
837
|
-
async getStorefrontSettings(domain) {
|
|
838
|
-
if (domain) {
|
|
839
|
-
apiClient.setStoreDomain(domain);
|
|
840
|
-
}
|
|
841
|
-
const response = await apiClient.get(`/${STOREFRONT_API_PATH_PREFIX}/settings`);
|
|
842
|
-
return StorefrontSettingsSchema.parse(response);
|
|
843
|
-
}
|
|
844
|
-
};
|
|
845
|
-
var storeService = StoreService.getInstance();
|
|
846
|
-
var CartBuyerRequestSchema = z.object({
|
|
847
|
-
email: z.string().email(),
|
|
848
|
-
firstName: z.string().min(1),
|
|
849
|
-
lastName: z.string().min(1),
|
|
850
|
-
phone: z.string().min(1)
|
|
851
|
-
});
|
|
852
|
-
var CartCreateRequestSchema = z.object({
|
|
853
|
-
currencyCode: z.string(),
|
|
854
|
-
salesChannelId: z.string(),
|
|
855
|
-
email: z.string().email()
|
|
856
|
-
});
|
|
857
|
-
var CartAddressSchema = z.object({
|
|
858
|
-
name: z.string().min(1),
|
|
859
|
-
address1: z.string().min(1),
|
|
860
|
-
city: z.string().min(1),
|
|
861
|
-
countryCode: z.string().min(2),
|
|
862
|
-
company: z.string().nullable().optional(),
|
|
863
|
-
address2: z.string().nullable().optional(),
|
|
864
|
-
province: z.string().nullable().optional(),
|
|
865
|
-
postalCode: z.string().nullable().optional(),
|
|
866
|
-
district: z.string().nullable().optional(),
|
|
867
|
-
phone: z.string().nullable().optional(),
|
|
868
|
-
latitude: z.number().nullable().optional(),
|
|
869
|
-
longitude: z.number().nullable().optional(),
|
|
870
|
-
geo: z.object({
|
|
871
|
-
departmentCode: z.string().nullable().optional(),
|
|
872
|
-
provinceCode: z.string().nullable().optional(),
|
|
873
|
-
districtCode: z.string().nullable().optional()
|
|
874
|
-
}).nullable().optional()
|
|
875
|
-
});
|
|
876
|
-
var CartAddressesRequestSchema = z.object({
|
|
877
|
-
shippingAddress: CartAddressSchema,
|
|
878
|
-
billingAddress: CartAddressSchema
|
|
879
|
-
});
|
|
880
|
-
var CartItemModifierRequestSchema = z.object({
|
|
881
|
-
modifierGroupId: z.coerce.string().min(1),
|
|
882
|
-
optionIds: z.array(z.coerce.string().min(1)).optional().default([])
|
|
883
|
-
});
|
|
884
|
-
var CartItemRequestSchema = z.object({
|
|
885
|
-
variantId: z.coerce.string().min(1),
|
|
886
|
-
quantity: z.number().int().positive(),
|
|
887
|
-
modifiers: z.array(CartItemModifierRequestSchema).optional()
|
|
888
|
-
});
|
|
889
|
-
var CartCouponRequestSchema = z.object({
|
|
890
|
-
code: z.string().min(1)
|
|
891
|
-
});
|
|
892
|
-
z.object({
|
|
893
|
-
subtotal: z.number(),
|
|
894
|
-
discount: z.number(),
|
|
895
|
-
tax: z.number(),
|
|
896
|
-
warranty: z.number().optional().default(0),
|
|
897
|
-
total: z.number()
|
|
1287
|
+
z.object({
|
|
1288
|
+
subtotal: z.number(),
|
|
1289
|
+
discount: z.number(),
|
|
1290
|
+
tax: z.number(),
|
|
1291
|
+
warranty: z.number().optional().default(0),
|
|
1292
|
+
total: z.number()
|
|
898
1293
|
});
|
|
899
1294
|
z.object({
|
|
900
1295
|
name: z.string().nullable().optional(),
|
|
@@ -1131,6 +1526,97 @@ var CartService = class _CartService {
|
|
|
1131
1526
|
}
|
|
1132
1527
|
};
|
|
1133
1528
|
var cartService = CartService.getInstance();
|
|
1529
|
+
var ECOMIQ_APP_APEX = "ecomiq.app";
|
|
1530
|
+
var ECOMIQ_APP_SUFFIX = [`.${ECOMIQ_APP_APEX}`, `.localhost`];
|
|
1531
|
+
function normalizeStoreHost(hostHeader) {
|
|
1532
|
+
let h = hostHeader.trim().toLowerCase();
|
|
1533
|
+
const colon = h.indexOf(":");
|
|
1534
|
+
if (colon !== -1) h = h.slice(0, colon);
|
|
1535
|
+
if (h.startsWith("www.")) h = h.slice(4);
|
|
1536
|
+
return h;
|
|
1537
|
+
}
|
|
1538
|
+
function resolveStorefrontSettingsHost(hostHeader) {
|
|
1539
|
+
const host = normalizeStoreHost(hostHeader);
|
|
1540
|
+
if (!host) {
|
|
1541
|
+
throw Object.assign(new Error("Host inv\xE1lido para tienda"), { status: 400 });
|
|
1542
|
+
}
|
|
1543
|
+
if (host === ECOMIQ_APP_APEX) {
|
|
1544
|
+
throw Object.assign(new Error("Host apex ecomiq.app sin slug de tienda"), { status: 400 });
|
|
1545
|
+
}
|
|
1546
|
+
if (ECOMIQ_APP_SUFFIX.some((suffix) => host.endsWith(suffix))) {
|
|
1547
|
+
const slug = host.slice(0, -(ECOMIQ_APP_SUFFIX.find((suffix) => host.endsWith(suffix))?.length ?? 0));
|
|
1548
|
+
if (!slug) {
|
|
1549
|
+
throw Object.assign(new Error("Host sin slug para ecomiq.app"), { status: 400 });
|
|
1550
|
+
}
|
|
1551
|
+
return slug;
|
|
1552
|
+
}
|
|
1553
|
+
return host;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
// src/core/config/ecomiq-config.ts
|
|
1557
|
+
var CONFIG_FILENAMES = [
|
|
1558
|
+
"ecomiq.config.js",
|
|
1559
|
+
"ecomiq.config.cjs",
|
|
1560
|
+
"ecomiq.config.mjs"
|
|
1561
|
+
];
|
|
1562
|
+
var EcomiqConfigSchema = z.object({
|
|
1563
|
+
/**
|
|
1564
|
+
* Slug de tienda en Ecomiq (p. ej. `mi-tienda` para `mi-tienda.ecomiq.app`).
|
|
1565
|
+
* Si está definido, tiene prioridad sobre el `Host` de la request (útil en `localhost`).
|
|
1566
|
+
*/
|
|
1567
|
+
slugStore: z.string().min(1).optional()
|
|
1568
|
+
});
|
|
1569
|
+
var cachedConfig;
|
|
1570
|
+
function parseExportedConfig(raw) {
|
|
1571
|
+
const candidate = raw && typeof raw === "object" && "default" in raw ? raw.default : raw;
|
|
1572
|
+
const parsed = EcomiqConfigSchema.safeParse(candidate);
|
|
1573
|
+
if (!parsed.success) {
|
|
1574
|
+
console.warn(
|
|
1575
|
+
"[ecomiq] ecomiq.config.* inv\xE1lido:",
|
|
1576
|
+
parsed.error.flatten().fieldErrors
|
|
1577
|
+
);
|
|
1578
|
+
return null;
|
|
1579
|
+
}
|
|
1580
|
+
const slugStore = parsed.data.slugStore?.trim();
|
|
1581
|
+
return slugStore ? { slugStore } : {};
|
|
1582
|
+
}
|
|
1583
|
+
function loadEcomiqConfig(cwd = process.cwd()) {
|
|
1584
|
+
if (cachedConfig !== void 0) return cachedConfig;
|
|
1585
|
+
for (const filename of CONFIG_FILENAMES) {
|
|
1586
|
+
const configPath = join(cwd, filename);
|
|
1587
|
+
if (!existsSync(configPath)) continue;
|
|
1588
|
+
try {
|
|
1589
|
+
const requireFromApp = createRequire(join(cwd, "package.json"));
|
|
1590
|
+
const loaded = requireFromApp(configPath);
|
|
1591
|
+
const parsed = parseExportedConfig(loaded);
|
|
1592
|
+
cachedConfig = parsed;
|
|
1593
|
+
return cachedConfig;
|
|
1594
|
+
} catch (error) {
|
|
1595
|
+
console.warn(`[ecomiq] No se pudo cargar ${configPath}:`, error);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
cachedConfig = null;
|
|
1599
|
+
return null;
|
|
1600
|
+
}
|
|
1601
|
+
function clearEcomiqConfigCache() {
|
|
1602
|
+
cachedConfig = void 0;
|
|
1603
|
+
}
|
|
1604
|
+
function resolvePublicStoreKey(hostHeader, cwd) {
|
|
1605
|
+
const slugFromConfig = loadEcomiqConfig(cwd)?.slugStore?.trim();
|
|
1606
|
+
if (slugFromConfig) return slugFromConfig;
|
|
1607
|
+
if (!hostHeader?.trim()) {
|
|
1608
|
+
throw Object.assign(
|
|
1609
|
+
new Error(
|
|
1610
|
+
"Host is required, o define slugStore en ecomiq.config.js en la ra\xEDz del proyecto"
|
|
1611
|
+
),
|
|
1612
|
+
{ status: 400 }
|
|
1613
|
+
);
|
|
1614
|
+
}
|
|
1615
|
+
return resolveStorefrontSettingsHost(hostHeader);
|
|
1616
|
+
}
|
|
1617
|
+
function hasEcomiqSlugStoreConfig(cwd) {
|
|
1618
|
+
return Boolean(loadEcomiqConfig(cwd)?.slugStore?.trim());
|
|
1619
|
+
}
|
|
1134
1620
|
var defaultOptions = {
|
|
1135
1621
|
queries: {
|
|
1136
1622
|
staleTime: 60 * 1e3
|
|
@@ -1719,6 +2205,33 @@ var useCart = create()(
|
|
|
1719
2205
|
{ name: "cart-storage" }
|
|
1720
2206
|
)
|
|
1721
2207
|
);
|
|
2208
|
+
init_store_api_client();
|
|
2209
|
+
function EcomiqProvider({
|
|
2210
|
+
store,
|
|
2211
|
+
authClient,
|
|
2212
|
+
children,
|
|
2213
|
+
withShellUi = false
|
|
2214
|
+
}) {
|
|
2215
|
+
useStore.setState({ data: store ?? null });
|
|
2216
|
+
useEffect(() => {
|
|
2217
|
+
setClientStoreId(store?.store.id ?? null);
|
|
2218
|
+
return () => setClientStoreId(null);
|
|
2219
|
+
}, [store]);
|
|
2220
|
+
const [queryClient] = useState(() => new QueryClient());
|
|
2221
|
+
const tree = /* @__PURE__ */ jsxs(QueryClientProvider, { client: queryClient, children: [
|
|
2222
|
+
children,
|
|
2223
|
+
withShellUi ? /* @__PURE__ */ jsx(EcomiqShellUi2, {}) : null
|
|
2224
|
+
] });
|
|
2225
|
+
if (!authClient) return tree;
|
|
2226
|
+
return /* @__PURE__ */ jsx(StorefrontAuthProvider, { authClient, children: tree });
|
|
2227
|
+
}
|
|
2228
|
+
function EcomiqShellUi2() {
|
|
2229
|
+
const [ui, setUi] = useState(null);
|
|
2230
|
+
useEffect(() => {
|
|
2231
|
+
void Promise.resolve().then(() => (init_ecomiq_shell_ui(), ecomiq_shell_ui_exports)).then((mod) => setUi(() => mod.EcomiqShellUi));
|
|
2232
|
+
}, []);
|
|
2233
|
+
return ui ? React2.createElement(ui) : null;
|
|
2234
|
+
}
|
|
1722
2235
|
|
|
1723
2236
|
// src/react/auth/ecomiq-oauth-password-constants.ts
|
|
1724
2237
|
var PLUGIN_ID = "ecomiq-oauth-password";
|
|
@@ -1824,1170 +2337,210 @@ function ecomiqOAuthPassword() {
|
|
|
1824
2337
|
throw APIError.from("INTERNAL_SERVER_ERROR", {
|
|
1825
2338
|
code: "ECOMIQ_SESSION_FAILED",
|
|
1826
2339
|
message: "No se pudo crear la sesi\xF3n"
|
|
1827
|
-
});
|
|
1828
|
-
}
|
|
1829
|
-
await setSessionCookie(ctx, { session, user }, rememberMe === false);
|
|
1830
|
-
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;
|
|
1831
|
-
await ctx.setCookie(STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, tokens.access_token, {
|
|
1832
|
-
path: STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH,
|
|
1833
|
-
httpOnly: true,
|
|
1834
|
-
sameSite: "lax",
|
|
1835
|
-
secure: secureCookie,
|
|
1836
|
-
maxAge: oauthMaxAgeSec
|
|
1837
|
-
});
|
|
1838
|
-
if (callbackURL) ctx.setHeader("Location", callbackURL);
|
|
1839
|
-
return ctx.json({
|
|
1840
|
-
redirect: !!callbackURL,
|
|
1841
|
-
token: session.token,
|
|
1842
|
-
url: callbackURL,
|
|
1843
|
-
user: parseUserOutput(ctx.context.options, user)
|
|
1844
|
-
});
|
|
1845
|
-
}
|
|
1846
|
-
)
|
|
1847
|
-
}
|
|
1848
|
-
};
|
|
1849
|
-
}
|
|
1850
|
-
function displayNameFromUserInfo(profile, fallbackEmail) {
|
|
1851
|
-
const parts = [profile.given_name?.trim(), profile.family_name?.trim()].filter(Boolean);
|
|
1852
|
-
const joined = parts.join(" ").trim();
|
|
1853
|
-
if (joined) return joined;
|
|
1854
|
-
return fallbackEmail.split("@")[0] || "Cliente";
|
|
1855
|
-
}
|
|
1856
|
-
async function fetchUserInfo(accessToken) {
|
|
1857
|
-
const res = await fetch(ECOMIQ_OAUTH_USERINFO_URL, {
|
|
1858
|
-
method: "GET",
|
|
1859
|
-
headers: {
|
|
1860
|
-
Authorization: `Bearer ${accessToken}`,
|
|
1861
|
-
accept: "application/json"
|
|
1862
|
-
}
|
|
1863
|
-
});
|
|
1864
|
-
const text = await res.text();
|
|
1865
|
-
let json;
|
|
1866
|
-
try {
|
|
1867
|
-
json = text ? JSON.parse(text) : {};
|
|
1868
|
-
} catch {
|
|
1869
|
-
throw APIError.from("UNAUTHORIZED", {
|
|
1870
|
-
code: "ECOMIQ_USERINFO_INVALID_BODY",
|
|
1871
|
-
message: "Respuesta inv\xE1lida del endpoint userinfo"
|
|
1872
|
-
});
|
|
1873
|
-
}
|
|
1874
|
-
if (!res.ok) {
|
|
1875
|
-
const err = json;
|
|
1876
|
-
throw APIError.from("UNAUTHORIZED", {
|
|
1877
|
-
code: "ECOMIQ_USERINFO_REJECTED",
|
|
1878
|
-
message: err.error_description ?? err.error ?? "No se pudo obtener el perfil del usuario"
|
|
1879
|
-
});
|
|
1880
|
-
}
|
|
1881
|
-
const parsed = userInfoSchema.safeParse(json);
|
|
1882
|
-
if (!parsed.success) {
|
|
1883
|
-
throw APIError.from("UNAUTHORIZED", {
|
|
1884
|
-
code: "ECOMIQ_USERINFO_SHAPE",
|
|
1885
|
-
message: "Perfil OAuth con formato inv\xE1lido"
|
|
1886
|
-
});
|
|
1887
|
-
}
|
|
1888
|
-
return parsed.data;
|
|
1889
|
-
}
|
|
1890
|
-
async function exchangePasswordGrant(username, password, context) {
|
|
1891
|
-
const clientId = process.env.ECOMIQ_AUTH_CLIENT_ID ?? "";
|
|
1892
|
-
const clientSecret = process.env.ECOMIQ_AUTH_CLIENT_SECRET ?? "";
|
|
1893
|
-
const scope = process.env.ECOMIQ_AUTH_SCOPE ?? "";
|
|
1894
|
-
if (!clientId || !clientSecret) {
|
|
1895
|
-
throw APIError.from("INTERNAL_SERVER_ERROR", {
|
|
1896
|
-
code: "ECOMIQ_AUTH_NOT_CONFIGURED",
|
|
1897
|
-
message: "OAuth Ecomiq no configurado: ECOMIQ_AUTH_CLIENT_ID y ECOMIQ_AUTH_CLIENT_SECRET."
|
|
1898
|
-
});
|
|
1899
|
-
}
|
|
1900
|
-
const body = new URLSearchParams({
|
|
1901
|
-
grant_type: "password",
|
|
1902
|
-
username,
|
|
1903
|
-
password,
|
|
1904
|
-
scope,
|
|
1905
|
-
client_id: clientId,
|
|
1906
|
-
client_secret: clientSecret
|
|
1907
|
-
});
|
|
1908
|
-
const identityScope = context.identityScope;
|
|
1909
|
-
const tenantId = context.tenantId;
|
|
1910
|
-
const storeId = context.storeId;
|
|
1911
|
-
const headers = new Headers({
|
|
1912
|
-
"content-type": "application/x-www-form-urlencoded",
|
|
1913
|
-
accept: "application/json"
|
|
1914
|
-
});
|
|
1915
|
-
if (identityScope?.trim()) {
|
|
1916
|
-
headers.set("x-Identity-Scope", identityScope.trim());
|
|
1917
|
-
}
|
|
1918
|
-
if (tenantId?.trim()) {
|
|
1919
|
-
headers.set("x-Tenant-Id", tenantId.trim());
|
|
1920
|
-
}
|
|
1921
|
-
if (storeId?.trim()) {
|
|
1922
|
-
headers.set("x-Store-Id", storeId.trim());
|
|
1923
|
-
}
|
|
1924
|
-
let res;
|
|
1925
|
-
let text;
|
|
1926
|
-
try {
|
|
1927
|
-
res = await fetch(ECOMIQ_OAUTH_TOKEN_URL, {
|
|
1928
|
-
method: "POST",
|
|
1929
|
-
headers,
|
|
1930
|
-
body
|
|
1931
|
-
});
|
|
1932
|
-
text = await res.text();
|
|
1933
|
-
} catch (e) {
|
|
1934
|
-
throw mapTokenEndpointFetchFailure(e);
|
|
1935
|
-
}
|
|
1936
|
-
const json = safeParseJson(text);
|
|
1937
|
-
if (!res.ok) {
|
|
1938
|
-
throwBadRequestFromOAuth(json, res.statusText || text || `HTTP ${res.status}`);
|
|
1939
|
-
}
|
|
1940
|
-
const parsed = tokenResponseSchema.safeParse(json);
|
|
1941
|
-
if (!parsed.success) {
|
|
1942
|
-
throwBadRequestFromOAuth(json, "Token de acceso no recibido");
|
|
1943
|
-
}
|
|
1944
|
-
return parsed.data;
|
|
1945
|
-
}
|
|
1946
|
-
function safeParseJson(text) {
|
|
1947
|
-
try {
|
|
1948
|
-
return text ? JSON.parse(text) : {};
|
|
1949
|
-
} catch {
|
|
1950
|
-
return {};
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
1953
|
-
function throwBadRequestFromOAuth(payload, fallbackMessage) {
|
|
1954
|
-
const err = payload;
|
|
1955
|
-
const errorCode = typeof err.error === "string" && err.error.trim() ? err.error.trim() : "invalid_grant";
|
|
1956
|
-
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.";
|
|
1957
|
-
throw APIError.from("BAD_REQUEST", {
|
|
1958
|
-
code: errorCode,
|
|
1959
|
-
message: errorMessage.slice(0, 500)
|
|
1960
|
-
});
|
|
1961
|
-
}
|
|
1962
|
-
function mapTokenEndpointFetchFailure(e) {
|
|
1963
|
-
const codes = collectNetworkErrorCodes(e);
|
|
1964
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
1965
|
-
const isDnsError = codes.some((c) => c === "ENOTFOUND" || c === "EAI_AGAIN");
|
|
1966
|
-
if (isDnsError) {
|
|
1967
|
-
throw APIError.from("BAD_GATEWAY", {
|
|
1968
|
-
code: "ECOMIQ_AUTH_DNS",
|
|
1969
|
-
message: "No se pudo resolver el servidor de autenticacion."
|
|
1970
|
-
});
|
|
1971
|
-
}
|
|
1972
|
-
const isConnectionRefused = codes.includes("ECONNREFUSED");
|
|
1973
|
-
if (isConnectionRefused) {
|
|
1974
|
-
throw APIError.from("BAD_GATEWAY", {
|
|
1975
|
-
code: "ECOMIQ_AUTH_REFUSED",
|
|
1976
|
-
message: "Conexion rechazada al servidor de autenticacion."
|
|
1977
|
-
});
|
|
1978
|
-
}
|
|
1979
|
-
const looksLikeAbortOrSocketClose = codes.some(
|
|
1980
|
-
(c) => ["UND_ERR_SOCKET", "ECONNRESET", "EPIPE", "ECONNABORTED"].includes(c)
|
|
1981
|
-
) || /terminated|abort|closed|FIN|socket/i.test(msg);
|
|
1982
|
-
if (looksLikeAbortOrSocketClose) {
|
|
1983
|
-
throwBadRequestFromOAuth({}, "Credenciales invalidas o conexion cerrada por el servidor.");
|
|
1984
|
-
}
|
|
1985
|
-
throw APIError.from("INTERNAL_SERVER_ERROR", {
|
|
1986
|
-
code: "ECOMIQ_AUTH_REQUEST_FAILED",
|
|
1987
|
-
message: msg.slice(0, 280) || "Error al contactar el servidor de autenticacion."
|
|
1988
|
-
});
|
|
1989
|
-
}
|
|
1990
|
-
function collectNetworkErrorCodes(e) {
|
|
1991
|
-
const out = [];
|
|
1992
|
-
const visit = (x) => {
|
|
1993
|
-
if (!x || typeof x !== "object") return;
|
|
1994
|
-
const code = "code" in x && typeof x.code === "string" ? x.code : void 0;
|
|
1995
|
-
if (code) out.push(code);
|
|
1996
|
-
if ("cause" in x && x.cause) {
|
|
1997
|
-
visit(x.cause);
|
|
1998
|
-
}
|
|
1999
|
-
};
|
|
2000
|
-
visit(e);
|
|
2001
|
-
return out;
|
|
2002
|
-
}
|
|
2003
|
-
|
|
2004
|
-
// src/react/auth/ecomiq-oauth-password-client.ts
|
|
2005
|
-
function ecomiqOAuthPasswordClient() {
|
|
2006
|
-
return {
|
|
2007
|
-
id: PLUGIN_ID,
|
|
2008
|
-
pathMethods: {
|
|
2009
|
-
"/ecomiq-oauth/sign-in": "POST"
|
|
2010
|
-
},
|
|
2011
|
-
atomListeners: [
|
|
2012
|
-
{
|
|
2013
|
-
matcher: (path) => path === "/ecomiq-oauth/sign-in",
|
|
2014
|
-
signal: "$sessionSignal"
|
|
2015
|
-
}
|
|
2016
|
-
]
|
|
2017
|
-
};
|
|
2018
|
-
}
|
|
2019
|
-
|
|
2020
|
-
// src/react/components/cms-sections/utils.ts
|
|
2021
|
-
var PRODUCT_SORTS = /* @__PURE__ */ new Set([
|
|
2022
|
-
"price_asc",
|
|
2023
|
-
"price_desc",
|
|
2024
|
-
"name_asc",
|
|
2025
|
-
"name_desc",
|
|
2026
|
-
"newest"
|
|
2027
|
-
]);
|
|
2028
|
-
function orderedBlocks(blocks) {
|
|
2029
|
-
return [...blocks ?? []].sort((a, b) => a.order - b.order);
|
|
2030
|
-
}
|
|
2031
|
-
function getCmsSectionKey(section, index) {
|
|
2032
|
-
return section.id ?? `${canonicalSectionType(section.type)}-${section.order}-${index}`;
|
|
2033
|
-
}
|
|
2034
|
-
function getCmsBlockKey(block, index) {
|
|
2035
|
-
return block.id ?? `${block.type}-${block.order}-${index}`;
|
|
2036
|
-
}
|
|
2037
|
-
function canonicalSectionType(type) {
|
|
2038
|
-
if (type === "page-hero") {
|
|
2039
|
-
return "hero";
|
|
2040
|
-
}
|
|
2041
|
-
if (type === "featured-products") {
|
|
2042
|
-
return "product-list";
|
|
2043
|
-
}
|
|
2044
|
-
return type;
|
|
2045
|
-
}
|
|
2046
|
-
function storefrontHref(value) {
|
|
2047
|
-
const href = value.trim();
|
|
2048
|
-
if (!href) {
|
|
2049
|
-
return "#";
|
|
2050
|
-
}
|
|
2051
|
-
if (href === "#" || href.startsWith("http://") || href.startsWith("https://") || href.startsWith("mailto:") || href.startsWith("tel:")) {
|
|
2052
|
-
return href;
|
|
2053
|
-
}
|
|
2054
|
-
if (href === "/") {
|
|
2055
|
-
return "/store";
|
|
2056
|
-
}
|
|
2057
|
-
if (href.startsWith("/store") || href.startsWith("/product")) {
|
|
2058
|
-
return href;
|
|
2059
|
-
}
|
|
2060
|
-
if (href.startsWith("/collections") || href.startsWith("/pages") || href.startsWith("/account")) {
|
|
2061
|
-
return `/store${href}`;
|
|
2062
|
-
}
|
|
2063
|
-
return href;
|
|
2064
|
-
}
|
|
2065
|
-
function sectionTitleContent(section) {
|
|
2066
|
-
return settingContent(section.settings, "title") || settingContent(section.settings, "name");
|
|
2067
|
-
}
|
|
2068
|
-
function settingString(settings, key) {
|
|
2069
|
-
const value = settings?.[key];
|
|
2070
|
-
return typeof value === "string" ? value : "";
|
|
2071
|
-
}
|
|
2072
|
-
function settingContent(settings, key) {
|
|
2073
|
-
const value = settings?.[key];
|
|
2074
|
-
if (typeof value === "string" || typeof value === "number") {
|
|
2075
|
-
return value;
|
|
2076
|
-
}
|
|
2077
|
-
if (value == null || typeof value === "boolean") {
|
|
2078
|
-
return "";
|
|
2079
|
-
}
|
|
2080
|
-
return value;
|
|
2081
|
-
}
|
|
2082
|
-
function settingNumber(settings, key, fallback) {
|
|
2083
|
-
const value = settings?.[key];
|
|
2084
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2085
|
-
return value;
|
|
2086
|
-
}
|
|
2087
|
-
if (typeof value === "string") {
|
|
2088
|
-
const parsed = Number(value);
|
|
2089
|
-
return Number.isFinite(parsed) ? parsed : fallback;
|
|
2090
|
-
}
|
|
2091
|
-
return fallback;
|
|
2092
|
-
}
|
|
2093
|
-
function layoutChildren(settings, key) {
|
|
2094
|
-
const children = settings.children;
|
|
2095
|
-
if (typeof children !== "object" || children === null || Array.isArray(children)) {
|
|
2096
|
-
return [];
|
|
2097
|
-
}
|
|
2098
|
-
const value = children[key];
|
|
2099
|
-
return Array.isArray(value) ? value : [];
|
|
2100
|
-
}
|
|
2101
|
-
function layoutPadding(value) {
|
|
2102
|
-
switch (value) {
|
|
2103
|
-
case "none":
|
|
2104
|
-
return "py-0";
|
|
2105
|
-
case "small":
|
|
2106
|
-
return "py-6";
|
|
2107
|
-
case "large":
|
|
2108
|
-
return "py-16";
|
|
2109
|
-
default:
|
|
2110
|
-
return "py-10";
|
|
2111
|
-
}
|
|
2112
|
-
}
|
|
2113
|
-
function layoutMaxWidth(value) {
|
|
2114
|
-
switch (value) {
|
|
2115
|
-
case "full":
|
|
2116
|
-
return "max-w-none";
|
|
2117
|
-
case "narrow":
|
|
2118
|
-
return "max-w-3xl";
|
|
2119
|
-
default:
|
|
2120
|
-
return "max-w-7xl";
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
function layoutBackground(value) {
|
|
2124
|
-
switch (value) {
|
|
2125
|
-
case "muted":
|
|
2126
|
-
return "bg-neutral-50";
|
|
2127
|
-
case "dark":
|
|
2128
|
-
return "bg-neutral-950 text-white";
|
|
2129
|
-
default:
|
|
2130
|
-
return "bg-white";
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
function layoutGap(value) {
|
|
2134
|
-
switch (value) {
|
|
2135
|
-
case "none":
|
|
2136
|
-
return "gap-0";
|
|
2137
|
-
case "small":
|
|
2138
|
-
return "gap-3";
|
|
2139
|
-
case "large":
|
|
2140
|
-
return "gap-8";
|
|
2141
|
-
default:
|
|
2142
|
-
return "gap-5";
|
|
2143
|
-
}
|
|
2144
|
-
}
|
|
2145
|
-
function layoutAlign(value) {
|
|
2146
|
-
switch (value) {
|
|
2147
|
-
case "start":
|
|
2148
|
-
return "items-start";
|
|
2149
|
-
case "center":
|
|
2150
|
-
return "items-center";
|
|
2151
|
-
case "end":
|
|
2152
|
-
return "items-end";
|
|
2153
|
-
default:
|
|
2154
|
-
return "items-stretch";
|
|
2155
|
-
}
|
|
2156
|
-
}
|
|
2157
|
-
function layoutJustify(value) {
|
|
2158
|
-
switch (value) {
|
|
2159
|
-
case "center":
|
|
2160
|
-
return "justify-center";
|
|
2161
|
-
case "end":
|
|
2162
|
-
return "justify-end";
|
|
2163
|
-
case "between":
|
|
2164
|
-
return "justify-between";
|
|
2165
|
-
default:
|
|
2166
|
-
return "justify-start";
|
|
2167
|
-
}
|
|
2168
|
-
}
|
|
2169
|
-
function productSortValue(value) {
|
|
2170
|
-
return PRODUCT_SORTS.has(value) ? value : "newest";
|
|
2171
|
-
}
|
|
2172
|
-
function sanitizeHtml(html) {
|
|
2173
|
-
return html.replace(/<script[\s\S]*?>[\s\S]*?<\/script>/gi, "").replace(/<style[\s\S]*?>[\s\S]*?<\/style>/gi, "").replace(/<(iframe|object|embed|link|meta)[\s\S]*?>/gi, "").replace(/\son\w+\s*=\s*(['"]).*?\1/gi, "").replace(/\s(href|src)\s*=\s*(['"])\s*javascript:[\s\S]*?\2/gi, "");
|
|
2174
|
-
}
|
|
2175
|
-
var DEFAULT_CMS_IMAGE_URL = "data:image/svg+xml;charset=UTF-8," + encodeURIComponent(`
|
|
2176
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="640" height="360" viewBox="0 0 640 360">
|
|
2177
|
-
<rect width="640" height="360" fill="#f4f4f5"/>
|
|
2178
|
-
<rect x="40" y="36" width="560" height="288" rx="20" fill="#ffffff" stroke="#d4d4d8"/>
|
|
2179
|
-
<path d="M148 246l102-102 78 78 48-48 120 120H148z" fill="#d4d4d8"/>
|
|
2180
|
-
<circle cx="456" cy="118" r="32" fill="#e4e4e7"/>
|
|
2181
|
-
</svg>
|
|
2182
|
-
`);
|
|
2183
|
-
function SectionHeading({ section }) {
|
|
2184
|
-
const title = sectionTitleContent(section);
|
|
2185
|
-
const subtitle = settingContent(section.settings, "subtitle");
|
|
2186
|
-
if (!title && !subtitle) {
|
|
2187
|
-
return null;
|
|
2188
|
-
}
|
|
2189
|
-
return /* @__PURE__ */ jsxs("div", { className: "mb-6", children: [
|
|
2190
|
-
title ? /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold tracking-tight text-neutral-950", children: title }) : null,
|
|
2191
|
-
subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-neutral-600", children: subtitle }) : null
|
|
2192
|
-
] });
|
|
2193
|
-
}
|
|
2194
|
-
function EmptyState({ children }) {
|
|
2195
|
-
return /* @__PURE__ */ jsx("p", { className: "rounded-lg border border-dashed p-6 text-center text-sm text-neutral-500", children });
|
|
2196
|
-
}
|
|
2197
|
-
function DefaultLink({ href, className, children }) {
|
|
2198
|
-
return /* @__PURE__ */ jsx("a", { href, className, children });
|
|
2199
|
-
}
|
|
2200
|
-
function CmsImage({
|
|
2201
|
-
src,
|
|
2202
|
-
fallbackSrc = DEFAULT_CMS_IMAGE_URL,
|
|
2203
|
-
onError,
|
|
2204
|
-
...props
|
|
2205
|
-
}) {
|
|
2206
|
-
const imageSrc = src?.trim() || fallbackSrc;
|
|
2207
|
-
return /* @__PURE__ */ jsx(
|
|
2208
|
-
"img",
|
|
2209
|
-
{
|
|
2210
|
-
src: imageSrc,
|
|
2211
|
-
onError: (event) => {
|
|
2212
|
-
onError?.(event);
|
|
2213
|
-
const image = event.currentTarget;
|
|
2214
|
-
if (image.dataset.cmsFallback === "true") {
|
|
2215
|
-
return;
|
|
2216
|
-
}
|
|
2217
|
-
image.dataset.cmsFallback = "true";
|
|
2218
|
-
image.src = fallbackSrc;
|
|
2219
|
-
},
|
|
2220
|
-
...props
|
|
2221
|
-
}
|
|
2222
|
-
);
|
|
2223
|
-
}
|
|
2224
|
-
function RichTextSection({ section }) {
|
|
2225
|
-
const html = settingString(section.settings, "html") || settingString(section.settings, "content") || settingString(section.settings, "richText");
|
|
2226
|
-
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-10", children: [
|
|
2227
|
-
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2228
|
-
html ? /* @__PURE__ */ jsx(
|
|
2229
|
-
"div",
|
|
2230
|
-
{
|
|
2231
|
-
className: "prose prose-neutral max-w-none",
|
|
2232
|
-
dangerouslySetInnerHTML: { __html: sanitizeHtml(html) }
|
|
2233
|
-
}
|
|
2234
|
-
) : null
|
|
2235
|
-
] });
|
|
2236
|
-
}
|
|
2237
|
-
function CustomHtmlSection({ section }) {
|
|
2238
|
-
const html = settingString(section.settings, "html") || settingString(section.settings, "content");
|
|
2239
|
-
if (!html) {
|
|
2240
|
-
return null;
|
|
2241
|
-
}
|
|
2242
|
-
return /* @__PURE__ */ jsx(
|
|
2243
|
-
"section",
|
|
2244
|
-
{
|
|
2245
|
-
className: "cms-custom-html",
|
|
2246
|
-
dangerouslySetInnerHTML: { __html: sanitizeHtml(html) }
|
|
2247
|
-
}
|
|
2248
|
-
);
|
|
2249
|
-
}
|
|
2250
|
-
function FloatingBlockSection({
|
|
2251
|
-
section,
|
|
2252
|
-
linkComponent: LinkComponent
|
|
2253
|
-
}) {
|
|
2254
|
-
const settings = section.settings ?? {};
|
|
2255
|
-
const title = settingContent(settings, "title");
|
|
2256
|
-
const text = settingContent(settings, "text");
|
|
2257
|
-
const imageUrl = settingString(settings, "imageUrl");
|
|
2258
|
-
const linkText = settingContent(settings, "linkText");
|
|
2259
|
-
const linkUrl = storefrontHref(settingString(settings, "linkUrl"));
|
|
2260
|
-
const x = boundedPercent(settingNumber(settings, "x", 8));
|
|
2261
|
-
const y = boundedPercent(settingNumber(settings, "y", 12));
|
|
2262
|
-
const width = Math.min(
|
|
2263
|
-
Math.max(boundedPercent(settingNumber(settings, "width", 28)), 12),
|
|
2264
|
-
90
|
|
2265
|
-
);
|
|
2266
|
-
const zIndex = Math.max(Math.round(settingNumber(settings, "zIndex", 20)), 1);
|
|
2267
|
-
if (!title && !text && !imageUrl) {
|
|
2268
|
-
return null;
|
|
2269
|
-
}
|
|
2270
|
-
const content = /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-lg border border-black/10 bg-white text-neutral-950 shadow-lg", children: [
|
|
2271
|
-
imageUrl ? /* @__PURE__ */ jsx("div", { className: "aspect-[16/9] bg-neutral-100", children: /* @__PURE__ */ jsx(
|
|
2272
|
-
CmsImage,
|
|
2273
|
-
{
|
|
2274
|
-
src: imageUrl,
|
|
2275
|
-
alt: "",
|
|
2276
|
-
className: "h-full w-full object-cover",
|
|
2277
|
-
loading: "lazy"
|
|
2278
|
-
}
|
|
2279
|
-
) }) : null,
|
|
2280
|
-
/* @__PURE__ */ jsxs("div", { className: "p-4", children: [
|
|
2281
|
-
title ? /* @__PURE__ */ jsx("p", { className: "text-base font-semibold leading-6", children: title }) : null,
|
|
2282
|
-
text ? /* @__PURE__ */ jsx("p", { className: "mt-1 text-sm leading-5 text-neutral-600", children: text }) : null,
|
|
2283
|
-
linkText && linkUrl !== "#" ? /* @__PURE__ */ jsx("span", { className: "mt-3 inline-flex text-sm font-medium underline underline-offset-4", children: linkText }) : null
|
|
2284
|
-
] })
|
|
2285
|
-
] });
|
|
2286
|
-
return /* @__PURE__ */ jsx(
|
|
2287
|
-
"div",
|
|
2288
|
-
{
|
|
2289
|
-
className: "absolute",
|
|
2290
|
-
style: {
|
|
2291
|
-
left: `${x}%`,
|
|
2292
|
-
top: `${y}%`,
|
|
2293
|
-
width: `${width}%`,
|
|
2294
|
-
zIndex
|
|
2295
|
-
},
|
|
2296
|
-
children: linkText && linkUrl !== "#" ? /* @__PURE__ */ jsx(LinkComponent, { href: linkUrl, children: content }) : content
|
|
2297
|
-
}
|
|
2298
|
-
);
|
|
2299
|
-
}
|
|
2300
|
-
function FaqSection({ section }) {
|
|
2301
|
-
const items = orderedBlocks(section.blocks);
|
|
2302
|
-
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2303
|
-
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2304
|
-
/* @__PURE__ */ jsx("div", { className: "divide-y rounded-lg border bg-white", children: items.map((item, index) => /* @__PURE__ */ jsxs("details", { className: "group p-4", children: [
|
|
2305
|
-
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-sm font-medium text-neutral-950", children: settingContent(item.settings, "question") || settingContent(item.settings, "title") }),
|
|
2306
|
-
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm leading-6 text-neutral-600", children: settingContent(item.settings, "answer") || settingContent(item.settings, "content") })
|
|
2307
|
-
] }, getCmsBlockKey(item, index))) })
|
|
2308
|
-
] });
|
|
2309
|
-
}
|
|
2310
|
-
function boundedPercent(value) {
|
|
2311
|
-
if (!Number.isFinite(value)) {
|
|
2312
|
-
return 0;
|
|
2313
|
-
}
|
|
2314
|
-
return Math.min(Math.max(value, 0), 100);
|
|
2315
|
-
}
|
|
2316
|
-
function NewsletterSection({ section }) {
|
|
2317
|
-
const title = sectionTitleContent(section) || "Recibe novedades";
|
|
2318
|
-
const subtitle = settingContent(section.settings, "subtitle");
|
|
2319
|
-
const placeholder = settingString(section.settings, "placeholder") || "tu@email.com";
|
|
2320
|
-
const buttonText = settingContent(section.settings, "buttonText") || "Suscribirme";
|
|
2321
|
-
return /* @__PURE__ */ jsx("section", { className: "bg-neutral-950 px-4 py-14 text-white", children: /* @__PURE__ */ jsxs("div", { className: "mx-auto max-w-2xl text-center", children: [
|
|
2322
|
-
/* @__PURE__ */ jsx("h2", { className: "text-3xl font-semibold", children: title }),
|
|
2323
|
-
subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-3 text-white/70", children: subtitle }) : null,
|
|
2324
|
-
/* @__PURE__ */ jsxs("form", { className: "mt-6 flex flex-col gap-2 sm:flex-row", children: [
|
|
2325
|
-
/* @__PURE__ */ jsx(
|
|
2326
|
-
"input",
|
|
2327
|
-
{
|
|
2328
|
-
type: "email",
|
|
2329
|
-
placeholder,
|
|
2330
|
-
className: "h-10 flex-1 rounded-md border border-white/20 bg-white px-3 text-sm text-neutral-950 outline-none"
|
|
2331
|
-
}
|
|
2332
|
-
),
|
|
2333
|
-
/* @__PURE__ */ jsx(
|
|
2334
|
-
"button",
|
|
2335
|
-
{
|
|
2336
|
-
type: "submit",
|
|
2337
|
-
className: "h-10 rounded-md bg-white px-5 text-sm font-medium text-neutral-950",
|
|
2338
|
-
children: buttonText
|
|
2339
|
-
}
|
|
2340
|
-
)
|
|
2341
|
-
] })
|
|
2342
|
-
] }) });
|
|
2343
|
-
}
|
|
2344
|
-
function IconRowSection({
|
|
2345
|
-
section,
|
|
2346
|
-
linkComponent: LinkComponent
|
|
2347
|
-
}) {
|
|
2348
|
-
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-10", children: [
|
|
2349
|
-
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2350
|
-
/* @__PURE__ */ jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: orderedBlocks(section.blocks).map((block, index) => {
|
|
2351
|
-
const settings = block.settings ?? {};
|
|
2352
|
-
const href = storefrontHref(settingString(settings, "linkUrl"));
|
|
2353
|
-
const content = /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-white p-4", children: [
|
|
2354
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-neutral-950", children: settingContent(settings, "title") || settingContent(settings, "label") }),
|
|
2355
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-neutral-600", children: settingContent(settings, "subtitle") || settingContent(settings, "description") })
|
|
2356
|
-
] });
|
|
2357
|
-
return href === "#" ? /* @__PURE__ */ jsx("div", { children: content }, getCmsBlockKey(block, index)) : /* @__PURE__ */ jsx(LinkComponent, { href, children: content }, getCmsBlockKey(block, index));
|
|
2358
|
-
}) })
|
|
2359
|
-
] });
|
|
2360
|
-
}
|
|
2361
|
-
function TestimonialsSection({
|
|
2362
|
-
section
|
|
2363
|
-
}) {
|
|
2364
|
-
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2365
|
-
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2366
|
-
/* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-3", children: orderedBlocks(section.blocks).map((block, index) => /* @__PURE__ */ jsxs(
|
|
2367
|
-
"blockquote",
|
|
2368
|
-
{
|
|
2369
|
-
className: "rounded-lg border bg-white p-5",
|
|
2370
|
-
children: [
|
|
2371
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm leading-6 text-neutral-700", children: settingString(block.settings, "quote") || settingContent(block.settings, "content") || settingContent(block.settings, "text") }),
|
|
2372
|
-
/* @__PURE__ */ jsx("footer", { className: "mt-4 text-sm font-medium text-neutral-950", children: settingContent(block.settings, "author") || settingContent(block.settings, "name") })
|
|
2373
|
-
]
|
|
2374
|
-
},
|
|
2375
|
-
getCmsBlockKey(block, index)
|
|
2376
|
-
)) })
|
|
2377
|
-
] });
|
|
2378
|
-
}
|
|
2379
|
-
function StatsSection({ section }) {
|
|
2380
|
-
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2381
|
-
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2382
|
-
/* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: orderedBlocks(section.blocks).map((block, index) => /* @__PURE__ */ jsxs(
|
|
2383
|
-
"div",
|
|
2384
|
-
{
|
|
2385
|
-
className: "rounded-lg border bg-white p-5",
|
|
2386
|
-
children: [
|
|
2387
|
-
/* @__PURE__ */ jsx("p", { className: "text-3xl font-semibold text-neutral-950", children: settingContent(block.settings, "value") }),
|
|
2388
|
-
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-neutral-600", children: settingContent(block.settings, "label") || settingContent(block.settings, "title") })
|
|
2389
|
-
]
|
|
2390
|
-
},
|
|
2391
|
-
getCmsBlockKey(block, index)
|
|
2392
|
-
)) })
|
|
2393
|
-
] });
|
|
2394
|
-
}
|
|
2395
|
-
function TimelineSection({ section }) {
|
|
2396
|
-
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2397
|
-
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2398
|
-
/* @__PURE__ */ jsx("div", { className: "space-y-4 border-l pl-5", children: orderedBlocks(section.blocks).map((block, index) => /* @__PURE__ */ jsxs("article", { className: "relative", children: [
|
|
2399
|
-
/* @__PURE__ */ jsx("span", { className: "absolute -left-[27px] top-1 size-3 rounded-full bg-neutral-950" }),
|
|
2400
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-neutral-950", children: settingContent(block.settings, "title") }),
|
|
2401
|
-
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-neutral-600", children: settingContent(block.settings, "description") || settingContent(block.settings, "content") })
|
|
2402
|
-
] }, getCmsBlockKey(block, index))) })
|
|
2403
|
-
] });
|
|
2404
|
-
}
|
|
2405
|
-
function ContactFormSection({ section }) {
|
|
2406
|
-
const fields = orderedBlocks(section.blocks);
|
|
2407
|
-
const submitText = settingString(section.settings, "submitText") || "Enviar";
|
|
2408
|
-
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2409
|
-
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2410
|
-
/* @__PURE__ */ jsxs("form", { className: "mx-auto grid max-w-2xl gap-3", children: [
|
|
2411
|
-
(fields.length > 0 ? fields : defaultContactFields()).map(
|
|
2412
|
-
(field, index) => /* @__PURE__ */ jsx(ContactField, { field }, getCmsBlockKey(field, index))
|
|
2413
|
-
),
|
|
2414
|
-
/* @__PURE__ */ jsx("button", { className: "h-10 rounded-md bg-neutral-950 px-4 text-sm font-medium text-white", children: submitText })
|
|
2415
|
-
] })
|
|
2416
|
-
] });
|
|
2417
|
-
}
|
|
2418
|
-
function ContactField({ field }) {
|
|
2419
|
-
const type = settingString(field.settings, "type") || "text";
|
|
2420
|
-
const label = settingString(field.settings, "label");
|
|
2421
|
-
const placeholder = settingString(field.settings, "placeholder");
|
|
2422
|
-
const name = settingString(field.settings, "name");
|
|
2423
|
-
const className = "h-10 rounded-md border px-3 text-sm";
|
|
2424
|
-
if (type === "textarea") {
|
|
2425
|
-
return /* @__PURE__ */ jsx(
|
|
2426
|
-
"textarea",
|
|
2427
|
-
{
|
|
2428
|
-
name,
|
|
2429
|
-
"aria-label": label || placeholder,
|
|
2430
|
-
className: "min-h-32 rounded-md border px-3 py-2 text-sm",
|
|
2431
|
-
placeholder: placeholder || label
|
|
2432
|
-
}
|
|
2433
|
-
);
|
|
2434
|
-
}
|
|
2435
|
-
if (type === "select") {
|
|
2436
|
-
const rawOptions = field.settings?.options;
|
|
2437
|
-
const options = Array.isArray(rawOptions) ? rawOptions.filter((item) => typeof item === "string") : settingString(field.settings, "options").split("\n").map((item) => item.trim()).filter(Boolean);
|
|
2438
|
-
return /* @__PURE__ */ jsxs("select", { name, "aria-label": label, className, children: [
|
|
2439
|
-
/* @__PURE__ */ jsx("option", { value: "", children: placeholder || label }),
|
|
2440
|
-
options.map((option) => /* @__PURE__ */ jsx("option", { value: option, children: option }, option))
|
|
2441
|
-
] });
|
|
2442
|
-
}
|
|
2443
|
-
return /* @__PURE__ */ jsx(
|
|
2444
|
-
"input",
|
|
2445
|
-
{
|
|
2446
|
-
name,
|
|
2447
|
-
type,
|
|
2448
|
-
"aria-label": label || placeholder,
|
|
2449
|
-
className,
|
|
2450
|
-
placeholder: placeholder || label
|
|
2451
|
-
}
|
|
2452
|
-
);
|
|
2453
|
-
}
|
|
2454
|
-
function defaultContactFields() {
|
|
2455
|
-
return [
|
|
2456
|
-
{
|
|
2457
|
-
type: "field",
|
|
2458
|
-
order: 1,
|
|
2459
|
-
settings: { name: "fullName", type: "text", label: "Nombre" }
|
|
2460
|
-
},
|
|
2461
|
-
{
|
|
2462
|
-
type: "field",
|
|
2463
|
-
order: 2,
|
|
2464
|
-
settings: { name: "email", type: "email", label: "Email" }
|
|
2465
|
-
},
|
|
2466
|
-
{
|
|
2467
|
-
type: "field",
|
|
2468
|
-
order: 3,
|
|
2469
|
-
settings: { name: "message", type: "textarea", label: "Mensaje" }
|
|
2470
|
-
}
|
|
2471
|
-
];
|
|
2472
|
-
}
|
|
2473
|
-
function UnknownSection({ section }) {
|
|
2474
|
-
return /* @__PURE__ */ jsx("section", { className: "container mx-auto px-4 py-8", children: /* @__PURE__ */ jsxs("div", { className: "rounded border border-dashed p-4 text-sm text-neutral-500", children: [
|
|
2475
|
-
'Seccion tipo "',
|
|
2476
|
-
section.type,
|
|
2477
|
-
'" pendiente de renderer.'
|
|
2478
|
-
] }) });
|
|
2479
|
-
}
|
|
2480
|
-
function AnnouncementBarSection({
|
|
2481
|
-
section,
|
|
2482
|
-
linkComponent: LinkComponent
|
|
2483
|
-
}) {
|
|
2484
|
-
const text = settingContent(section.settings, "text") || sectionTitleContent(section);
|
|
2485
|
-
const linkText = settingContent(section.settings, "linkText");
|
|
2486
|
-
const href = storefrontHref(settingString(section.settings, "linkUrl"));
|
|
2487
|
-
if (!text) {
|
|
2488
|
-
return null;
|
|
2489
|
-
}
|
|
2490
|
-
return /* @__PURE__ */ jsx("section", { className: "bg-neutral-950 px-4 py-2 text-white", children: /* @__PURE__ */ jsxs("div", { className: "container mx-auto flex flex-wrap items-center justify-center gap-2 text-center text-sm", children: [
|
|
2491
|
-
/* @__PURE__ */ jsx("span", { children: text }),
|
|
2492
|
-
linkText && href !== "#" ? /* @__PURE__ */ jsx(
|
|
2493
|
-
LinkComponent,
|
|
2494
|
-
{
|
|
2495
|
-
href,
|
|
2496
|
-
className: "font-medium underline underline-offset-4",
|
|
2497
|
-
children: linkText
|
|
2498
|
-
}
|
|
2499
|
-
) : null
|
|
2500
|
-
] }) });
|
|
2501
|
-
}
|
|
2502
|
-
function HeroSection({
|
|
2503
|
-
section,
|
|
2504
|
-
linkComponent: LinkComponent
|
|
2505
|
-
}) {
|
|
2506
|
-
const slides = orderedBlocks(section.blocks);
|
|
2507
|
-
const fallbackSlide = {
|
|
2508
|
-
id: `${section.id ?? "section"}-fallback`,
|
|
2509
|
-
type: "slide",
|
|
2510
|
-
order: 1,
|
|
2511
|
-
settings: section.settings ?? {}
|
|
2512
|
-
};
|
|
2513
|
-
const visibleSlides = slides.length > 0 ? slides : [fallbackSlide];
|
|
2514
|
-
return /* @__PURE__ */ jsx("section", { className: "bg-neutral-950 text-white", children: /* @__PURE__ */ jsx("div", { className: "flex snap-x overflow-x-auto", children: visibleSlides.map((slide, index) => {
|
|
2515
|
-
const settings = slide.settings ?? {};
|
|
2516
|
-
const imageUrl = settingString(settings, "imageUrl") || settingString(section.settings, "imageUrl") || DEFAULT_CMS_IMAGE_URL;
|
|
2517
|
-
const title = settingContent(settings, "title") || settingContent(section.settings, "title") || sectionTitleContent(section);
|
|
2518
|
-
const subtitle = settingContent(settings, "subtitle") || settingContent(section.settings, "subtitle");
|
|
2519
|
-
const ctaText = settingContent(settings, "ctaText") || settingContent(section.settings, "ctaText");
|
|
2520
|
-
const ctaUrl = settingString(settings, "ctaUrl") || settingString(section.settings, "ctaUrl");
|
|
2521
|
-
const href = storefrontHref(ctaUrl);
|
|
2522
|
-
return /* @__PURE__ */ jsxs(
|
|
2523
|
-
"article",
|
|
2524
|
-
{
|
|
2525
|
-
className: "relative min-h-[520px] w-full shrink-0 snap-start overflow-hidden",
|
|
2526
|
-
children: [
|
|
2527
|
-
/* @__PURE__ */ jsx(
|
|
2528
|
-
CmsImage,
|
|
2529
|
-
{
|
|
2530
|
-
src: imageUrl,
|
|
2531
|
-
alt: "",
|
|
2532
|
-
className: "absolute inset-0 h-full w-full object-cover opacity-75"
|
|
2533
|
-
}
|
|
2534
|
-
),
|
|
2535
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-gradient-to-r from-black/70 via-black/35 to-transparent" }),
|
|
2536
|
-
/* @__PURE__ */ jsx("div", { className: "container relative z-10 mx-auto flex min-h-[520px] items-center px-4", children: /* @__PURE__ */ jsxs("div", { className: "max-w-2xl py-16", children: [
|
|
2537
|
-
/* @__PURE__ */ jsx("h1", { className: "text-4xl font-semibold tracking-tight md:text-6xl", children: title }),
|
|
2538
|
-
subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-4 max-w-xl text-base text-white/85 md:text-lg", children: subtitle }) : null,
|
|
2539
|
-
ctaText && href !== "#" ? /* @__PURE__ */ jsx(
|
|
2540
|
-
LinkComponent,
|
|
2541
|
-
{
|
|
2542
|
-
href,
|
|
2543
|
-
className: "mt-8 inline-flex h-10 items-center rounded-md bg-white px-5 text-sm font-medium text-neutral-950 transition hover:bg-white/90",
|
|
2544
|
-
children: ctaText
|
|
2545
|
-
}
|
|
2546
|
-
) : null
|
|
2547
|
-
] }) })
|
|
2548
|
-
]
|
|
2549
|
-
},
|
|
2550
|
-
getCmsBlockKey(slide, index)
|
|
2551
|
-
);
|
|
2552
|
-
}) }) });
|
|
2553
|
-
}
|
|
2554
|
-
function ProductsSection({
|
|
2555
|
-
section,
|
|
2556
|
-
products,
|
|
2557
|
-
carousel,
|
|
2558
|
-
linkComponent,
|
|
2559
|
-
currency,
|
|
2560
|
-
preview
|
|
2561
|
-
}) {
|
|
2562
|
-
const placeholders = preview && products.length === 0;
|
|
2563
|
-
const count = Math.min(
|
|
2564
|
-
productPreviewCount(section, carousel),
|
|
2565
|
-
carousel ? 5 : 8
|
|
2566
|
-
);
|
|
2567
|
-
return /* @__PURE__ */ jsxs("section", { className: carousel ? "py-12" : "container mx-auto px-4 py-12", children: [
|
|
2568
|
-
carousel ? /* @__PURE__ */ jsx("div", { className: "container mx-auto px-4", children: /* @__PURE__ */ jsx(SectionHeading, { section }) }) : /* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2569
|
-
/* @__PURE__ */ jsx("div", { className: carousel ? "container mx-auto overflow-x-auto px-4" : "", children: /* @__PURE__ */ jsx(
|
|
2570
|
-
"div",
|
|
2571
|
-
{
|
|
2572
|
-
className: carousel ? "flex min-w-full gap-4 pb-2" : "grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4",
|
|
2573
|
-
children: placeholders ? Array.from({ length: count }).map((_, index) => /* @__PURE__ */ jsx(ProductPlaceholder, { carousel }, index)) : products.map((product) => /* @__PURE__ */ jsx(
|
|
2574
|
-
ProductCard,
|
|
2575
|
-
{
|
|
2576
|
-
product,
|
|
2577
|
-
carousel,
|
|
2578
|
-
linkComponent,
|
|
2579
|
-
currency
|
|
2580
|
-
},
|
|
2581
|
-
product.id
|
|
2582
|
-
))
|
|
2583
|
-
}
|
|
2584
|
-
) }),
|
|
2585
|
-
!placeholders && products.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { children: "No hay productos para mostrar." }) : null
|
|
2586
|
-
] });
|
|
2587
|
-
}
|
|
2588
|
-
function CategoryGridSection({
|
|
2589
|
-
section,
|
|
2590
|
-
collections,
|
|
2591
|
-
linkComponent: LinkComponent,
|
|
2592
|
-
preview
|
|
2593
|
-
}) {
|
|
2594
|
-
const blockItems = orderedBlocks(section.blocks).map((block) => {
|
|
2595
|
-
const settings = block.settings ?? {};
|
|
2596
|
-
const name = settingContent(settings, "name") || settingContent(settings, "title");
|
|
2597
|
-
const url = settingString(settings, "url") || settingString(settings, "linkUrl");
|
|
2598
|
-
const imageUrl = settingString(settings, "imageUrl");
|
|
2599
|
-
if (!name) {
|
|
2600
|
-
return null;
|
|
2601
|
-
}
|
|
2602
|
-
return {
|
|
2603
|
-
id: getCmsBlockKey(block, block.order),
|
|
2604
|
-
name,
|
|
2605
|
-
href: storefrontHref(url || "/collections"),
|
|
2606
|
-
imageUrl: imageUrl || DEFAULT_CMS_IMAGE_URL
|
|
2607
|
-
};
|
|
2608
|
-
}).filter(Boolean);
|
|
2609
|
-
const collectionItems = collections.map((collection) => ({
|
|
2610
|
-
id: collection.id,
|
|
2611
|
-
name: collection.name,
|
|
2612
|
-
href: `/store/collections/${collection.slug}`,
|
|
2613
|
-
imageUrl: collection.imageUrl || DEFAULT_CMS_IMAGE_URL
|
|
2614
|
-
}));
|
|
2615
|
-
const previewItems = preview ? createPreviewCollections(section) : [];
|
|
2616
|
-
const items = blockItems.length > 0 ? blockItems : collectionItems.length > 0 ? collectionItems : previewItems;
|
|
2617
|
-
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2618
|
-
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2619
|
-
items.length > 0 ? /* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3", children: items.map((item) => /* @__PURE__ */ jsxs(
|
|
2620
|
-
LinkComponent,
|
|
2621
|
-
{
|
|
2622
|
-
href: item.href,
|
|
2623
|
-
className: "group overflow-hidden rounded-lg border bg-white",
|
|
2624
|
-
children: [
|
|
2625
|
-
/* @__PURE__ */ jsx("div", { className: "aspect-[4/3] overflow-hidden bg-neutral-100", children: /* @__PURE__ */ jsx(
|
|
2626
|
-
CmsImage,
|
|
2627
|
-
{
|
|
2628
|
-
src: item.imageUrl,
|
|
2629
|
-
alt: "",
|
|
2630
|
-
className: "h-full w-full object-cover transition duration-300 group-hover:scale-105"
|
|
2631
|
-
}
|
|
2632
|
-
) }),
|
|
2633
|
-
/* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsx("h3", { className: "text-base font-medium text-neutral-950", children: item.name }) })
|
|
2634
|
-
]
|
|
2635
|
-
},
|
|
2636
|
-
item.id
|
|
2637
|
-
)) }) : /* @__PURE__ */ jsx(EmptyState, { children: "No hay categorias para mostrar." })
|
|
2638
|
-
] });
|
|
2639
|
-
}
|
|
2640
|
-
function PromoCardsSection({
|
|
2641
|
-
section,
|
|
2642
|
-
linkComponent: LinkComponent
|
|
2643
|
-
}) {
|
|
2644
|
-
const cards = orderedBlocks(section.blocks);
|
|
2645
|
-
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-12", children: [
|
|
2646
|
-
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2647
|
-
/* @__PURE__ */ jsx("div", { className: "grid gap-4 md:grid-cols-2", children: cards.map((card, index) => {
|
|
2648
|
-
const settings = card.settings ?? {};
|
|
2649
|
-
const title = settingContent(settings, "title");
|
|
2650
|
-
const subtitle = settingContent(settings, "subtitle");
|
|
2651
|
-
const imageUrl = settingString(settings, "imageUrl") || DEFAULT_CMS_IMAGE_URL;
|
|
2652
|
-
const ctaText = settingContent(settings, "ctaText");
|
|
2653
|
-
const ctaUrl = storefrontHref(
|
|
2654
|
-
settingString(settings, "ctaUrl") || settingString(settings, "url")
|
|
2655
|
-
);
|
|
2656
|
-
return /* @__PURE__ */ jsxs(
|
|
2657
|
-
LinkComponent,
|
|
2658
|
-
{
|
|
2659
|
-
href: ctaUrl,
|
|
2660
|
-
className: "group relative min-h-[260px] overflow-hidden rounded-lg bg-neutral-900 text-white",
|
|
2661
|
-
children: [
|
|
2662
|
-
/* @__PURE__ */ jsx(
|
|
2663
|
-
CmsImage,
|
|
2664
|
-
{
|
|
2665
|
-
src: imageUrl,
|
|
2666
|
-
alt: "",
|
|
2667
|
-
className: "absolute inset-0 h-full w-full object-cover opacity-75 transition duration-300 group-hover:scale-105"
|
|
2668
|
-
}
|
|
2669
|
-
),
|
|
2670
|
-
/* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/35" }),
|
|
2671
|
-
/* @__PURE__ */ jsxs("div", { className: "relative z-10 flex min-h-[260px] flex-col justify-end p-6", children: [
|
|
2672
|
-
/* @__PURE__ */ jsx("h3", { className: "text-2xl font-semibold", children: title }),
|
|
2673
|
-
subtitle ? /* @__PURE__ */ jsx("p", { className: "mt-2 text-white/85", children: subtitle }) : null,
|
|
2674
|
-
ctaText ? /* @__PURE__ */ jsx("span", { className: "mt-4 text-sm font-medium", children: ctaText }) : null
|
|
2675
|
-
] })
|
|
2676
|
-
]
|
|
2677
|
-
},
|
|
2678
|
-
getCmsBlockKey(card, index)
|
|
2679
|
-
);
|
|
2680
|
-
}) })
|
|
2681
|
-
] });
|
|
2682
|
-
}
|
|
2683
|
-
function LogoSliderSection({
|
|
2684
|
-
section,
|
|
2685
|
-
linkComponent: LinkComponent
|
|
2686
|
-
}) {
|
|
2687
|
-
return /* @__PURE__ */ jsxs("section", { className: "container mx-auto px-4 py-10", children: [
|
|
2688
|
-
/* @__PURE__ */ jsx(SectionHeading, { section }),
|
|
2689
|
-
/* @__PURE__ */ jsx("div", { className: "flex gap-4 overflow-x-auto", children: orderedBlocks(section.blocks).map((block, index) => {
|
|
2690
|
-
const settings = block.settings ?? {};
|
|
2691
|
-
const imageUrl = settingString(settings, "imageUrl") || DEFAULT_CMS_IMAGE_URL;
|
|
2692
|
-
const alt = settingString(settings, "alt") || "Logo";
|
|
2693
|
-
const href = storefrontHref(settingString(settings, "linkUrl"));
|
|
2694
|
-
const logo = /* @__PURE__ */ jsx("div", { className: "flex h-24 w-40 shrink-0 items-center justify-center rounded-lg border bg-white p-4", children: /* @__PURE__ */ jsx(
|
|
2695
|
-
CmsImage,
|
|
2696
|
-
{
|
|
2697
|
-
src: imageUrl,
|
|
2698
|
-
alt,
|
|
2699
|
-
className: "max-h-full max-w-full object-contain"
|
|
2700
|
-
}
|
|
2701
|
-
) });
|
|
2702
|
-
return href !== "#" ? /* @__PURE__ */ jsx(LinkComponent, { href, children: logo }, getCmsBlockKey(block, index)) : /* @__PURE__ */ jsx("div", { children: logo }, getCmsBlockKey(block, index));
|
|
2703
|
-
}) })
|
|
2704
|
-
] });
|
|
2705
|
-
}
|
|
2706
|
-
function ProductCard({
|
|
2707
|
-
product,
|
|
2708
|
-
carousel,
|
|
2709
|
-
linkComponent: LinkComponent,
|
|
2710
|
-
currency
|
|
2711
|
-
}) {
|
|
2712
|
-
const onSale = product.compareAtPrice != null && product.compareAtPrice > product.price;
|
|
2713
|
-
return /* @__PURE__ */ jsxs(
|
|
2714
|
-
LinkComponent,
|
|
2715
|
-
{
|
|
2716
|
-
href: `/product/${product.slug}`,
|
|
2717
|
-
className: carousel ? "group w-[220px] shrink-0 sm:w-[250px] md:w-[280px]" : "group",
|
|
2718
|
-
children: [
|
|
2719
|
-
/* @__PURE__ */ jsx("div", { className: "aspect-square overflow-hidden rounded-lg border border-neutral-200 bg-neutral-100 transition-all duration-300 group-hover:border-neutral-300", children: /* @__PURE__ */ jsx(
|
|
2720
|
-
CmsImage,
|
|
2721
|
-
{
|
|
2722
|
-
src: product.imageUrl || DEFAULT_CMS_IMAGE_URL,
|
|
2723
|
-
alt: product.name,
|
|
2724
|
-
className: "h-full w-full object-cover object-center transition-transform duration-500 group-hover:scale-105"
|
|
2340
|
+
});
|
|
2725
2341
|
}
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
/* @__PURE__ */ jsx("div", { className: "aspect-square rounded-lg bg-neutral-100" }),
|
|
2745
|
-
/* @__PURE__ */ jsx("div", { className: "mt-4 h-3 w-3/4 rounded bg-neutral-200" }),
|
|
2746
|
-
/* @__PURE__ */ jsx("div", { className: "mt-2 h-3 w-1/2 rounded bg-neutral-100" })
|
|
2747
|
-
]
|
|
2748
|
-
}
|
|
2749
|
-
);
|
|
2750
|
-
}
|
|
2751
|
-
function productPreviewCount(section, carousel) {
|
|
2752
|
-
const configuredBlocks = orderedBlocks(section.blocks).length;
|
|
2753
|
-
if (configuredBlocks > 0) {
|
|
2754
|
-
return configuredBlocks;
|
|
2755
|
-
}
|
|
2756
|
-
return settingNumber(section.settings, "limit", carousel ? 5 : 8);
|
|
2757
|
-
}
|
|
2758
|
-
function createPreviewCollections(section) {
|
|
2759
|
-
const count = Math.min(settingNumber(section.settings, "limit", 6), 6);
|
|
2760
|
-
return Array.from({ length: count }, (_, index) => ({
|
|
2761
|
-
id: `preview-collection-${index + 1}`,
|
|
2762
|
-
name: `Categoria ${index + 1}`,
|
|
2763
|
-
href: "/store/collections/all",
|
|
2764
|
-
imageUrl: DEFAULT_CMS_IMAGE_URL
|
|
2765
|
-
}));
|
|
2766
|
-
}
|
|
2767
|
-
function LayoutSection({ section, renderSections }) {
|
|
2768
|
-
const settings = section.settings ?? {};
|
|
2769
|
-
const paddingY = settingString(settings, "paddingY") || "medium";
|
|
2770
|
-
const maxWidth = settingString(settings, "maxWidth") || "container";
|
|
2771
|
-
const background = settingString(settings, "background") || "default";
|
|
2772
|
-
return /* @__PURE__ */ jsx(
|
|
2773
|
-
"section",
|
|
2774
|
-
{
|
|
2775
|
-
className: `${layoutBackground(background)} ${layoutPadding(paddingY)}`,
|
|
2776
|
-
children: /* @__PURE__ */ jsx("div", { className: `mx-auto px-4 ${layoutMaxWidth(maxWidth)}`, children: renderSections(layoutChildren(settings, "content")) })
|
|
2777
|
-
}
|
|
2778
|
-
);
|
|
2779
|
-
}
|
|
2780
|
-
function LayoutGrid({ section, renderSections }) {
|
|
2781
|
-
const settings = section.settings ?? {};
|
|
2782
|
-
const columnCount = Math.min(
|
|
2783
|
-
Math.max(Math.round(settingNumber(settings, "columnCount", 2)), 1),
|
|
2784
|
-
6
|
|
2785
|
-
);
|
|
2786
|
-
return /* @__PURE__ */ jsx(
|
|
2787
|
-
"div",
|
|
2788
|
-
{
|
|
2789
|
-
className: `grid ${layoutGap(settingString(settings, "gap"))}`,
|
|
2790
|
-
style: {
|
|
2791
|
-
gridTemplateColumns: `repeat(${columnCount}, minmax(0, 1fr))`
|
|
2792
|
-
},
|
|
2793
|
-
children: renderSections(layoutChildren(settings, "content"))
|
|
2794
|
-
}
|
|
2795
|
-
);
|
|
2796
|
-
}
|
|
2797
|
-
function LayoutFlex({ section, renderSections }) {
|
|
2798
|
-
const settings = section.settings ?? {};
|
|
2799
|
-
return /* @__PURE__ */ jsx(
|
|
2800
|
-
"div",
|
|
2801
|
-
{
|
|
2802
|
-
className: [
|
|
2803
|
-
"flex",
|
|
2804
|
-
settingString(settings, "direction") === "column" ? "flex-col" : "flex-col md:flex-row",
|
|
2805
|
-
settingString(settings, "wrap") === "nowrap" ? "flex-nowrap" : "flex-wrap",
|
|
2806
|
-
layoutGap(settingString(settings, "gap")),
|
|
2807
|
-
layoutAlign(settingString(settings, "align")),
|
|
2808
|
-
layoutJustify(settingString(settings, "justify"))
|
|
2809
|
-
].join(" "),
|
|
2810
|
-
children: renderSections(layoutChildren(settings, "content"))
|
|
2811
|
-
}
|
|
2812
|
-
);
|
|
2813
|
-
}
|
|
2814
|
-
function LayoutSpace({ section }) {
|
|
2815
|
-
const settings = section.settings ?? {};
|
|
2816
|
-
const size = settingString(settings, "size") || "24px";
|
|
2817
|
-
const direction = settingString(settings, "direction") || "vertical";
|
|
2818
|
-
const isHorizontal = direction === "horizontal";
|
|
2819
|
-
const isBoth = direction === "both";
|
|
2820
|
-
return /* @__PURE__ */ jsx(
|
|
2821
|
-
"div",
|
|
2822
|
-
{
|
|
2823
|
-
"aria-hidden": "true",
|
|
2824
|
-
style: {
|
|
2825
|
-
display: "block",
|
|
2826
|
-
width: isHorizontal || isBoth ? size : "100%",
|
|
2827
|
-
height: isHorizontal ? "100%" : size
|
|
2828
|
-
}
|
|
2342
|
+
await setSessionCookie(ctx, { session, user }, rememberMe === false);
|
|
2343
|
+
const oauthMaxAgeSec = oauthSessionExpires !== void 0 ? Math.max(60, Math.ceil((oauthSessionExpires.getTime() - Date.now()) / 1e3)) : tokens.expires_in !== void 0 && tokens.expires_in > 0 ? tokens.expires_in : 60 * 60 * 24;
|
|
2344
|
+
await ctx.setCookie(STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, tokens.access_token, {
|
|
2345
|
+
path: STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH,
|
|
2346
|
+
httpOnly: true,
|
|
2347
|
+
sameSite: "lax",
|
|
2348
|
+
secure: secureCookie,
|
|
2349
|
+
maxAge: oauthMaxAgeSec
|
|
2350
|
+
});
|
|
2351
|
+
if (callbackURL) ctx.setHeader("Location", callbackURL);
|
|
2352
|
+
return ctx.json({
|
|
2353
|
+
redirect: !!callbackURL,
|
|
2354
|
+
token: session.token,
|
|
2355
|
+
url: callbackURL,
|
|
2356
|
+
user: parseUserOutput(ctx.context.options, user)
|
|
2357
|
+
});
|
|
2358
|
+
}
|
|
2359
|
+
)
|
|
2829
2360
|
}
|
|
2830
|
-
|
|
2361
|
+
};
|
|
2831
2362
|
}
|
|
2832
|
-
function
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
preview = false,
|
|
2838
|
-
wrap = true
|
|
2839
|
-
}) {
|
|
2840
|
-
const LinkComponent = linkComponent ?? DefaultLink;
|
|
2841
|
-
const sortedSections = [...sections].sort((a, b) => a.order - b.order);
|
|
2842
|
-
const content = /* @__PURE__ */ jsx(Fragment, { children: sortedSections.map((section, index) => {
|
|
2843
|
-
const sectionKey = getCmsSectionKey(section, index);
|
|
2844
|
-
return /* @__PURE__ */ jsx(
|
|
2845
|
-
CmsSection,
|
|
2846
|
-
{
|
|
2847
|
-
section,
|
|
2848
|
-
data: sectionData?.[sectionKey],
|
|
2849
|
-
linkComponent: LinkComponent,
|
|
2850
|
-
currency,
|
|
2851
|
-
preview
|
|
2852
|
-
},
|
|
2853
|
-
sectionKey
|
|
2854
|
-
);
|
|
2855
|
-
}) });
|
|
2856
|
-
return wrap ? /* @__PURE__ */ jsx("div", { className: "relative", children: content }) : content;
|
|
2363
|
+
function displayNameFromUserInfo(profile, fallbackEmail) {
|
|
2364
|
+
const parts = [profile.given_name?.trim(), profile.family_name?.trim()].filter(Boolean);
|
|
2365
|
+
const joined = parts.join(" ").trim();
|
|
2366
|
+
if (joined) return joined;
|
|
2367
|
+
return fallbackEmail.split("@")[0] || "Cliente";
|
|
2857
2368
|
}
|
|
2858
|
-
function
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
}) {
|
|
2865
|
-
const type = canonicalSectionType(section.type);
|
|
2866
|
-
const renderSections = (sections) => /* @__PURE__ */ jsx(
|
|
2867
|
-
CmsSectionsRenderer,
|
|
2868
|
-
{
|
|
2869
|
-
sections,
|
|
2870
|
-
linkComponent,
|
|
2871
|
-
currency,
|
|
2872
|
-
preview,
|
|
2873
|
-
wrap: false
|
|
2369
|
+
async function fetchUserInfo(accessToken) {
|
|
2370
|
+
const res = await fetch(ECOMIQ_OAUTH_USERINFO_URL, {
|
|
2371
|
+
method: "GET",
|
|
2372
|
+
headers: {
|
|
2373
|
+
Authorization: `Bearer ${accessToken}`,
|
|
2374
|
+
accept: "application/json"
|
|
2874
2375
|
}
|
|
2875
|
-
);
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
}
|
|
2886
|
-
);
|
|
2887
|
-
}
|
|
2888
|
-
if (type === "layout-grid") {
|
|
2889
|
-
return /* @__PURE__ */ jsx(
|
|
2890
|
-
LayoutGrid,
|
|
2891
|
-
{
|
|
2892
|
-
section,
|
|
2893
|
-
linkComponent,
|
|
2894
|
-
currency,
|
|
2895
|
-
preview,
|
|
2896
|
-
renderSections
|
|
2897
|
-
}
|
|
2898
|
-
);
|
|
2899
|
-
}
|
|
2900
|
-
if (type === "layout-flex") {
|
|
2901
|
-
return /* @__PURE__ */ jsx(
|
|
2902
|
-
LayoutFlex,
|
|
2903
|
-
{
|
|
2904
|
-
section,
|
|
2905
|
-
linkComponent,
|
|
2906
|
-
currency,
|
|
2907
|
-
preview,
|
|
2908
|
-
renderSections
|
|
2909
|
-
}
|
|
2910
|
-
);
|
|
2911
|
-
}
|
|
2912
|
-
if (type === "layout-space") {
|
|
2913
|
-
return /* @__PURE__ */ jsx(
|
|
2914
|
-
LayoutSpace,
|
|
2915
|
-
{
|
|
2916
|
-
section,
|
|
2917
|
-
linkComponent,
|
|
2918
|
-
currency,
|
|
2919
|
-
preview,
|
|
2920
|
-
renderSections
|
|
2921
|
-
}
|
|
2922
|
-
);
|
|
2923
|
-
}
|
|
2924
|
-
if (type === "hero") {
|
|
2925
|
-
return /* @__PURE__ */ jsx(HeroSection, { section, linkComponent });
|
|
2926
|
-
}
|
|
2927
|
-
if (type === "announcement-bar") {
|
|
2928
|
-
return /* @__PURE__ */ jsx(AnnouncementBarSection, { section, linkComponent });
|
|
2376
|
+
});
|
|
2377
|
+
const text = await res.text();
|
|
2378
|
+
let json;
|
|
2379
|
+
try {
|
|
2380
|
+
json = text ? JSON.parse(text) : {};
|
|
2381
|
+
} catch {
|
|
2382
|
+
throw APIError.from("UNAUTHORIZED", {
|
|
2383
|
+
code: "ECOMIQ_USERINFO_INVALID_BODY",
|
|
2384
|
+
message: "Respuesta inv\xE1lida del endpoint userinfo"
|
|
2385
|
+
});
|
|
2929
2386
|
}
|
|
2930
|
-
if (
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
carousel: type === "product-carousel",
|
|
2937
|
-
linkComponent,
|
|
2938
|
-
currency,
|
|
2939
|
-
preview
|
|
2940
|
-
}
|
|
2941
|
-
);
|
|
2387
|
+
if (!res.ok) {
|
|
2388
|
+
const err = json;
|
|
2389
|
+
throw APIError.from("UNAUTHORIZED", {
|
|
2390
|
+
code: "ECOMIQ_USERINFO_REJECTED",
|
|
2391
|
+
message: err.error_description ?? err.error ?? "No se pudo obtener el perfil del usuario"
|
|
2392
|
+
});
|
|
2942
2393
|
}
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
linkComponent,
|
|
2950
|
-
preview
|
|
2951
|
-
}
|
|
2952
|
-
);
|
|
2394
|
+
const parsed = userInfoSchema.safeParse(json);
|
|
2395
|
+
if (!parsed.success) {
|
|
2396
|
+
throw APIError.from("UNAUTHORIZED", {
|
|
2397
|
+
code: "ECOMIQ_USERINFO_SHAPE",
|
|
2398
|
+
message: "Perfil OAuth con formato inv\xE1lido"
|
|
2399
|
+
});
|
|
2953
2400
|
}
|
|
2954
|
-
|
|
2955
|
-
|
|
2401
|
+
return parsed.data;
|
|
2402
|
+
}
|
|
2403
|
+
async function exchangePasswordGrant(username, password, context) {
|
|
2404
|
+
const clientId = process.env.ECOMIQ_AUTH_CLIENT_ID ?? "";
|
|
2405
|
+
const clientSecret = process.env.ECOMIQ_AUTH_CLIENT_SECRET ?? "";
|
|
2406
|
+
const scope = process.env.ECOMIQ_AUTH_SCOPE ?? "";
|
|
2407
|
+
if (!clientId || !clientSecret) {
|
|
2408
|
+
throw APIError.from("INTERNAL_SERVER_ERROR", {
|
|
2409
|
+
code: "ECOMIQ_AUTH_NOT_CONFIGURED",
|
|
2410
|
+
message: "OAuth Ecomiq no configurado: ECOMIQ_AUTH_CLIENT_ID y ECOMIQ_AUTH_CLIENT_SECRET."
|
|
2411
|
+
});
|
|
2956
2412
|
}
|
|
2957
|
-
|
|
2958
|
-
|
|
2413
|
+
const body = new URLSearchParams({
|
|
2414
|
+
grant_type: "password",
|
|
2415
|
+
username,
|
|
2416
|
+
password,
|
|
2417
|
+
scope,
|
|
2418
|
+
client_id: clientId,
|
|
2419
|
+
client_secret: clientSecret
|
|
2420
|
+
});
|
|
2421
|
+
const identityScope = context.identityScope;
|
|
2422
|
+
const tenantId = context.tenantId;
|
|
2423
|
+
const storeId = context.storeId;
|
|
2424
|
+
const headers = new Headers({
|
|
2425
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
2426
|
+
accept: "application/json"
|
|
2427
|
+
});
|
|
2428
|
+
if (identityScope?.trim()) {
|
|
2429
|
+
headers.set("x-Identity-Scope", identityScope.trim());
|
|
2959
2430
|
}
|
|
2960
|
-
if (
|
|
2961
|
-
|
|
2431
|
+
if (tenantId?.trim()) {
|
|
2432
|
+
headers.set("x-Tenant-Id", tenantId.trim());
|
|
2962
2433
|
}
|
|
2963
|
-
if (
|
|
2964
|
-
|
|
2434
|
+
if (storeId?.trim()) {
|
|
2435
|
+
headers.set("x-Store-Id", storeId.trim());
|
|
2965
2436
|
}
|
|
2966
|
-
|
|
2967
|
-
|
|
2437
|
+
let res;
|
|
2438
|
+
let text;
|
|
2439
|
+
try {
|
|
2440
|
+
res = await fetch(ECOMIQ_OAUTH_TOKEN_URL, {
|
|
2441
|
+
method: "POST",
|
|
2442
|
+
headers,
|
|
2443
|
+
body
|
|
2444
|
+
});
|
|
2445
|
+
text = await res.text();
|
|
2446
|
+
} catch (e) {
|
|
2447
|
+
throw mapTokenEndpointFetchFailure(e);
|
|
2968
2448
|
}
|
|
2969
|
-
|
|
2970
|
-
|
|
2449
|
+
const json = safeParseJson(text);
|
|
2450
|
+
if (!res.ok) {
|
|
2451
|
+
throwBadRequestFromOAuth(json, res.statusText || text || `HTTP ${res.status}`);
|
|
2971
2452
|
}
|
|
2972
|
-
|
|
2973
|
-
|
|
2453
|
+
const parsed = tokenResponseSchema.safeParse(json);
|
|
2454
|
+
if (!parsed.success) {
|
|
2455
|
+
throwBadRequestFromOAuth(json, "Token de acceso no recibido");
|
|
2974
2456
|
}
|
|
2975
|
-
|
|
2976
|
-
|
|
2457
|
+
return parsed.data;
|
|
2458
|
+
}
|
|
2459
|
+
function safeParseJson(text) {
|
|
2460
|
+
try {
|
|
2461
|
+
return text ? JSON.parse(text) : {};
|
|
2462
|
+
} catch {
|
|
2463
|
+
return {};
|
|
2977
2464
|
}
|
|
2978
|
-
|
|
2979
|
-
|
|
2465
|
+
}
|
|
2466
|
+
function throwBadRequestFromOAuth(payload, fallbackMessage) {
|
|
2467
|
+
const err = payload;
|
|
2468
|
+
const errorCode = typeof err.error === "string" && err.error.trim() ? err.error.trim() : "invalid_grant";
|
|
2469
|
+
const errorMessage = typeof err.error_description === "string" && err.error_description.trim() ? err.error_description.trim() : typeof err.error === "string" && err.error.trim() ? err.error.trim() : fallbackMessage.trim() || "Credenciales invalidas.";
|
|
2470
|
+
throw APIError.from("BAD_REQUEST", {
|
|
2471
|
+
code: errorCode,
|
|
2472
|
+
message: errorMessage.slice(0, 500)
|
|
2473
|
+
});
|
|
2474
|
+
}
|
|
2475
|
+
function mapTokenEndpointFetchFailure(e) {
|
|
2476
|
+
const codes = collectNetworkErrorCodes(e);
|
|
2477
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
2478
|
+
const isDnsError = codes.some((c) => c === "ENOTFOUND" || c === "EAI_AGAIN");
|
|
2479
|
+
if (isDnsError) {
|
|
2480
|
+
throw APIError.from("BAD_GATEWAY", {
|
|
2481
|
+
code: "ECOMIQ_AUTH_DNS",
|
|
2482
|
+
message: "No se pudo resolver el servidor de autenticacion."
|
|
2483
|
+
});
|
|
2980
2484
|
}
|
|
2981
|
-
|
|
2982
|
-
|
|
2485
|
+
const isConnectionRefused = codes.includes("ECONNREFUSED");
|
|
2486
|
+
if (isConnectionRefused) {
|
|
2487
|
+
throw APIError.from("BAD_GATEWAY", {
|
|
2488
|
+
code: "ECOMIQ_AUTH_REFUSED",
|
|
2489
|
+
message: "Conexion rechazada al servidor de autenticacion."
|
|
2490
|
+
});
|
|
2983
2491
|
}
|
|
2984
|
-
|
|
2985
|
-
|
|
2492
|
+
const looksLikeAbortOrSocketClose = codes.some(
|
|
2493
|
+
(c) => ["UND_ERR_SOCKET", "ECONNRESET", "EPIPE", "ECONNABORTED"].includes(c)
|
|
2494
|
+
) || /terminated|abort|closed|FIN|socket/i.test(msg);
|
|
2495
|
+
if (looksLikeAbortOrSocketClose) {
|
|
2496
|
+
throwBadRequestFromOAuth({}, "Credenciales invalidas o conexion cerrada por el servidor.");
|
|
2986
2497
|
}
|
|
2987
|
-
|
|
2988
|
-
|
|
2498
|
+
throw APIError.from("INTERNAL_SERVER_ERROR", {
|
|
2499
|
+
code: "ECOMIQ_AUTH_REQUEST_FAILED",
|
|
2500
|
+
message: msg.slice(0, 280) || "Error al contactar el servidor de autenticacion."
|
|
2501
|
+
});
|
|
2502
|
+
}
|
|
2503
|
+
function collectNetworkErrorCodes(e) {
|
|
2504
|
+
const out = [];
|
|
2505
|
+
const visit = (x) => {
|
|
2506
|
+
if (!x || typeof x !== "object") return;
|
|
2507
|
+
const code = "code" in x && typeof x.code === "string" ? x.code : void 0;
|
|
2508
|
+
if (code) out.push(code);
|
|
2509
|
+
if ("cause" in x && x.cause) {
|
|
2510
|
+
visit(x.cause);
|
|
2511
|
+
}
|
|
2512
|
+
};
|
|
2513
|
+
visit(e);
|
|
2514
|
+
return out;
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
// src/react/auth/ecomiq-oauth-password-client.ts
|
|
2518
|
+
function ecomiqOAuthPasswordClient() {
|
|
2519
|
+
return {
|
|
2520
|
+
id: PLUGIN_ID,
|
|
2521
|
+
pathMethods: {
|
|
2522
|
+
"/ecomiq-oauth/sign-in": "POST"
|
|
2523
|
+
},
|
|
2524
|
+
atomListeners: [
|
|
2525
|
+
{
|
|
2526
|
+
matcher: (path) => path === "/ecomiq-oauth/sign-in",
|
|
2527
|
+
signal: "$sessionSignal"
|
|
2528
|
+
}
|
|
2529
|
+
]
|
|
2530
|
+
};
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
// src/react/auth/ecomiq-storefront-sign-in.ts
|
|
2534
|
+
async function signInWithEcomiqCredentials2(authClient, settings, credentials) {
|
|
2535
|
+
const response = await authClient.$fetch("/ecomiq-oauth/sign-in", {
|
|
2536
|
+
method: "POST",
|
|
2537
|
+
headers: buildEcomiqOAuthIdentityHeaders(settings),
|
|
2538
|
+
body: credentials
|
|
2539
|
+
});
|
|
2540
|
+
if (response.error) {
|
|
2541
|
+
throw new Error(response.error.message ?? "Error al iniciar sesi\xF3n");
|
|
2989
2542
|
}
|
|
2990
|
-
return
|
|
2543
|
+
return response;
|
|
2991
2544
|
}
|
|
2992
2545
|
function buildOptionGroups(variants) {
|
|
2993
2546
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -3097,88 +2650,6 @@ function ProductVariantSelector({
|
|
|
3097
2650
|
})
|
|
3098
2651
|
] });
|
|
3099
2652
|
}
|
|
3100
|
-
function SafeThemeInjector({ theme, className }) {
|
|
3101
|
-
try {
|
|
3102
|
-
if (!theme || typeof theme !== "object") {
|
|
3103
|
-
console.warn("ThemeInjector: Invalid theme provided");
|
|
3104
|
-
return null;
|
|
3105
|
-
}
|
|
3106
|
-
if (!theme.colors || typeof theme.colors !== "object") {
|
|
3107
|
-
console.warn("ThemeInjector: Theme colors are required");
|
|
3108
|
-
return null;
|
|
3109
|
-
}
|
|
3110
|
-
const generateSafeCSSVariables = () => {
|
|
3111
|
-
const cssRules = [":root {"];
|
|
3112
|
-
const toKebabCase = (input) => input.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
|
|
3113
|
-
const sanitizeCSSValue = (value) => {
|
|
3114
|
-
if (typeof value !== "string") return null;
|
|
3115
|
-
const trimmed = value.trim();
|
|
3116
|
-
if (!trimmed) return null;
|
|
3117
|
-
const isValidCSSValue = /^[a-zA-Z0-9\s,()#.-]+$/.test(trimmed);
|
|
3118
|
-
return isValidCSSValue ? trimmed : null;
|
|
3119
|
-
};
|
|
3120
|
-
if (theme.colors && typeof theme.colors === "object") {
|
|
3121
|
-
Object.entries(theme.colors).forEach(([key, value]) => {
|
|
3122
|
-
const sanitizedValue = sanitizeCSSValue(value);
|
|
3123
|
-
if (sanitizedValue) {
|
|
3124
|
-
cssRules.push(` --color-${key}: ${sanitizedValue};`);
|
|
3125
|
-
cssRules.push(` --theme-${key}: ${sanitizedValue};`);
|
|
3126
|
-
cssRules.push(` --${key}: ${sanitizedValue};`);
|
|
3127
|
-
cssRules.push(` --${toKebabCase(key)}: ${sanitizedValue};`);
|
|
3128
|
-
}
|
|
3129
|
-
});
|
|
3130
|
-
}
|
|
3131
|
-
if (theme.fonts && typeof theme.fonts === "object") {
|
|
3132
|
-
Object.entries(theme.fonts).forEach(([key, value]) => {
|
|
3133
|
-
const sanitizedValue = sanitizeCSSValue(value);
|
|
3134
|
-
if (sanitizedValue) {
|
|
3135
|
-
cssRules.push(` --font-${key}: ${sanitizedValue};`);
|
|
3136
|
-
}
|
|
3137
|
-
});
|
|
3138
|
-
}
|
|
3139
|
-
if (theme.spacing && typeof theme.spacing === "object") {
|
|
3140
|
-
Object.entries(theme.spacing).forEach(([key, value]) => {
|
|
3141
|
-
const sanitizedValue = sanitizeCSSValue(value);
|
|
3142
|
-
if (sanitizedValue) {
|
|
3143
|
-
cssRules.push(` --spacing-${key}: ${sanitizedValue};`);
|
|
3144
|
-
}
|
|
3145
|
-
});
|
|
3146
|
-
}
|
|
3147
|
-
if (theme.borderRadius && typeof theme.borderRadius === "object") {
|
|
3148
|
-
Object.entries(theme.borderRadius).forEach(([key, value]) => {
|
|
3149
|
-
const sanitizedValue = sanitizeCSSValue(value);
|
|
3150
|
-
if (sanitizedValue) {
|
|
3151
|
-
cssRules.push(` --radius-${key}: ${sanitizedValue};`);
|
|
3152
|
-
}
|
|
3153
|
-
});
|
|
3154
|
-
}
|
|
3155
|
-
if (theme.shadows && typeof theme.shadows === "object") {
|
|
3156
|
-
Object.entries(theme.shadows).forEach(([key, value]) => {
|
|
3157
|
-
const sanitizedValue = sanitizeCSSValue(value);
|
|
3158
|
-
if (sanitizedValue) {
|
|
3159
|
-
cssRules.push(` --shadow-${key}: ${sanitizedValue};`);
|
|
3160
|
-
}
|
|
3161
|
-
});
|
|
3162
|
-
}
|
|
3163
|
-
cssRules.push("}");
|
|
3164
|
-
return cssRules.join("\n");
|
|
3165
|
-
};
|
|
3166
|
-
const cssVariables = generateSafeCSSVariables();
|
|
3167
|
-
return /* @__PURE__ */ jsx(
|
|
3168
|
-
"style",
|
|
3169
|
-
{
|
|
3170
|
-
dangerouslySetInnerHTML: { __html: cssVariables },
|
|
3171
|
-
"data-theme-injector": theme.id,
|
|
3172
|
-
"data-theme-name": theme.name,
|
|
3173
|
-
className,
|
|
3174
|
-
suppressHydrationWarning: true
|
|
3175
|
-
}
|
|
3176
|
-
);
|
|
3177
|
-
} catch (error) {
|
|
3178
|
-
console.error("ThemeInjector: Error generating theme styles", error);
|
|
3179
|
-
return null;
|
|
3180
|
-
}
|
|
3181
|
-
}
|
|
3182
2653
|
function isRenderableCmsPage(p) {
|
|
3183
2654
|
if (!p.status) return true;
|
|
3184
2655
|
return p.status === "published";
|
|
@@ -3194,6 +2665,6 @@ function findStorefrontCmsPageBySlug(settings, slug) {
|
|
|
3194
2665
|
return parsed.success ? parsed.data : null;
|
|
3195
2666
|
}
|
|
3196
2667
|
|
|
3197
|
-
export { CartAddressesRequestSchema, CartBuyerRequestSchema, CartCheckoutPaymentActionSchema, CartCheckoutPaymentSchema, CartCheckoutReadResponseSchema, CartCheckoutRequestSchema, CartCheckoutResponseSchema, CartCouponRequestSchema, CartCreateRequestSchema, CartItemModifierRequestSchema, CartItemRequestSchema, CartPaymentMethodSchema, CartPaymentMethodsResponseSchema, CartPaymentReceiptResponseSchema, CartResponseBundleItemSchema, CartResponseItemSchema, CartResponseSchema, CartShippingMethodPutRequestSchema,
|
|
2668
|
+
export { CartAddressesRequestSchema, CartBuyerRequestSchema, CartCheckoutPaymentActionSchema, CartCheckoutPaymentSchema, CartCheckoutReadResponseSchema, CartCheckoutRequestSchema, CartCheckoutResponseSchema, CartCouponRequestSchema, CartCreateRequestSchema, CartItemModifierRequestSchema, CartItemRequestSchema, CartPaymentMethodSchema, CartPaymentMethodsResponseSchema, CartPaymentReceiptResponseSchema, CartResponseBundleItemSchema, CartResponseItemSchema, CartResponseSchema, CartShippingMethodPutRequestSchema, EcomiqConfigSchema, EcomiqProvider, ProductSchema, ProductVariantSchema, ProductVariantSelector, ProductsFiltersSchema, ProductsResponseSchema, QueryProvider, STOREFRONT_API_PATH_PREFIX, STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH, ShippingOptionGroupSchema, ShippingOptionsResponseSchema, ShippingRateSchema, StorefrontAuthProvider, StorefrontBundleItemSchema, StorefrontCheckoutSettingsSchema, StorefrontCollectionDetailSchema, StorefrontCollectionSchema, StorefrontCollectionsResponseSchema, StorefrontPageDetailSchema, StorefrontPageListItemSchema, StorefrontPriceTierSchema, StorefrontProductDetailSchema, StorefrontProductSchema, StorefrontProductsParamsSchema, StorefrontProductsResponseSchema, StorefrontSettingsLegacyFlatSchema, StorefrontSettingsSchema, StorefrontStoreSchema, apiClient, buildEcomiqOAuthIdentityHeaders, cartService, clearEcomiqConfigCache, collectionService, countryCurrency, customerOrderStatusTone, ecomiqOAuthPassword, ecomiqOAuthPasswordClient, fetchStorefrontGeoDistricts, fetchStorefrontGeoProvinces, findStorefrontCmsPageBySlug, formatCurrency, formatCustomerOrderStatus, formatOrderDate, formatOrderDateTime, hasEcomiqSlugStoreConfig, loadEcomiqConfig, loadStorefrontGeoDepartments, normalizeStorefrontSettingsPayload, pageService, productService, resolveIneiCodesFromLabels, resolvePublicStoreKey, signInWithEcomiqCredentials2 as signInWithEcomiqCredentials, storeService, storefrontAccessTokenNeedsRefresh, storefrontFaviconUrl, storefrontOgImageUrl, storefrontSessionEndsSoon, storefrontStoreRecord, toGeoItems, useCart, useCartAddresses, useCartCreate, useCartGet, useCollections, useConfig, usePages, useProducts, useStore, useStorefrontAuthClient, useStorefrontGeoInei, useStorefrontSession, useUser };
|
|
3198
2669
|
//# sourceMappingURL=react.js.map
|
|
3199
2670
|
//# sourceMappingURL=react.js.map
|