@ecomiq/storefront 2.0.12 → 2.0.15
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/bin/ecomiq.mjs +3 -1
- package/package.json +4 -2
- package/src/auth/create-storefront-auth.ts +65 -6
- package/src/auth/ecomiq-oauth-password-constants.ts +1 -3
- package/src/auth/ecomiq-oauth-password-plugin.ts +12 -17
- package/src/auth/ecomiq-storefront-sign-in.ts +0 -3
- package/src/auth/secure-cookies.ts +23 -0
- package/src/auth/storefront-auth-base-url.ts +117 -0
- package/src/codegen.mjs +27 -1
- package/src/components/account/customer-addresses-panel.tsx +678 -0
- package/src/components/account/customer-order-detail-panel.tsx +285 -0
- package/src/components/account/customer-orders-panel.tsx +192 -0
- package/src/components/account/customer-profile-panel.tsx +379 -0
- package/src/components/checkout/checkout-contact-section.tsx +17 -11
- package/src/components/checkout/checkout-session-view.tsx +83 -2
- package/src/components/checkout/checkout-shipping-address-section.tsx +107 -2
- package/src/components/checkout/checkout-steps.ts +15 -0
- package/src/components/checkout/map-customer-to-checkout.ts +188 -0
- package/src/components/checkout/use-checkout-customer-prefill.ts +409 -0
- package/src/components/checkout/use-checkout-session.ts +5 -4
- package/src/config.d.ts +4 -0
- package/src/config.mjs +14 -0
- package/src/index.ts +54 -0
- package/src/pages/account/account-page-skeleton.tsx +69 -0
- package/src/pages/account/account-page-view.tsx +270 -0
- package/src/pages/account/account-shell.tsx +101 -0
- package/src/pages/account/parse-account-route.ts +36 -0
- package/src/pages/account.tsx +16 -0
- package/src/pages/checkout.$checkoutId.tsx +1 -1
- package/src/providers/auth.tsx +11 -2
- package/src/proxy-api.ts +20 -0
- package/src/vite-inline.mjs +54 -1
package/bin/ecomiq.mjs
CHANGED
|
@@ -81,6 +81,8 @@ export async function runCli(command = process.argv[2] ?? 'help') {
|
|
|
81
81
|
const config = await prepare()
|
|
82
82
|
const port = config.dev?.port ?? 3000
|
|
83
83
|
const runtime = resolveDevRuntime({ config })
|
|
84
|
+
const httpsEnabled = Boolean(config.dev?.https)
|
|
85
|
+
const origin = `${httpsEnabled ? 'https' : 'http'}://localhost:${port}`
|
|
84
86
|
const { createServer } = await import('vite')
|
|
85
87
|
const viteConfig = createViteConfig({
|
|
86
88
|
appDir,
|
|
@@ -89,7 +91,7 @@ export async function runCli(command = process.argv[2] ?? 'help') {
|
|
|
89
91
|
runtime,
|
|
90
92
|
})
|
|
91
93
|
banner(
|
|
92
|
-
`dev · ${config.domain ?? 'tienda'} ${c.dim(`· runtime ${runtime}`)} ${c.dim(
|
|
94
|
+
`dev · ${config.domain ?? 'tienda'} ${c.dim(`· runtime ${runtime}`)} ${c.dim(origin)}`,
|
|
93
95
|
)
|
|
94
96
|
const server = await createServer({
|
|
95
97
|
...viteConfig,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecomiq/storefront",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.15",
|
|
4
4
|
"description": "Micro framework SSR de Ecomiq para storefronts. Páginas, datos y deploy sin configurar nada.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"./internal/checkout-session": "./src/pages/checkout.$checkoutId.tsx",
|
|
43
43
|
"./internal/thank-you": "./src/pages/thank-you.tsx",
|
|
44
44
|
"./internal/cms-page": "./src/pages/pages.$pageSlug.tsx",
|
|
45
|
+
"./internal/account": "./src/pages/account.tsx",
|
|
45
46
|
"./package.json": "./package.json"
|
|
46
47
|
},
|
|
47
48
|
"files": [
|
|
@@ -63,6 +64,7 @@
|
|
|
63
64
|
"@tanstack/react-query": "^5.101.0",
|
|
64
65
|
"@tanstack/react-router": "^1.170.0",
|
|
65
66
|
"@tanstack/react-start": "^1.168.0",
|
|
67
|
+
"@vitejs/plugin-basic-ssl": "^2.3.0",
|
|
66
68
|
"@vitejs/plugin-react": "^6.0.0",
|
|
67
69
|
"better-auth": "^1.6.23",
|
|
68
70
|
"class-variance-authority": "^0.7.1",
|
|
@@ -76,7 +78,7 @@
|
|
|
76
78
|
"vite": "^8.1.0",
|
|
77
79
|
"wrangler": "^4.100.0",
|
|
78
80
|
"zod": "^3.25.0",
|
|
79
|
-
"@ecomiq/core": "^0.1.
|
|
81
|
+
"@ecomiq/core": "^0.1.5"
|
|
80
82
|
},
|
|
81
83
|
"peerDependencies": {
|
|
82
84
|
"react": "^19.0.0",
|
|
@@ -1,30 +1,41 @@
|
|
|
1
1
|
import { betterAuth } from 'better-auth'
|
|
2
2
|
import type { BetterAuthPlugin } from 'better-auth'
|
|
3
|
+
import { createCookieGetter, getCookies } from 'better-auth/cookies'
|
|
3
4
|
import { tanstackStartCookies } from 'better-auth/tanstack-start'
|
|
5
|
+
import { getStorefrontClient } from '../client'
|
|
4
6
|
import { ecomiqOAuthPassword } from './ecomiq-oauth-password-plugin'
|
|
5
7
|
import { readProcessEnv } from './env'
|
|
8
|
+
import { shouldUseSecureCookies } from './secure-cookies'
|
|
9
|
+
import {
|
|
10
|
+
mergeSettingsHostsIntoBaseURL,
|
|
11
|
+
resolveStorefrontAuthBaseURL,
|
|
12
|
+
type StorefrontDynamicBaseURLConfig,
|
|
13
|
+
} from './storefront-auth-base-url'
|
|
6
14
|
|
|
7
15
|
export type CreateStorefrontAuthOptions = {
|
|
8
16
|
secret?: string
|
|
9
|
-
baseURL?: string
|
|
10
17
|
/** Opciones adicionales pasadas a `betterAuth` (p. ej. `database`). */
|
|
11
18
|
[key: string]: unknown
|
|
12
19
|
}
|
|
13
20
|
|
|
14
21
|
/**
|
|
15
22
|
* Instancia Better Auth del storefront (servidor).
|
|
16
|
-
* Usa el plugin `ecomiqOAuthPassword` + cookies de TanStack Start.
|
|
17
23
|
*
|
|
18
|
-
*
|
|
24
|
+
* allowedHosts = `BETTER_AUTH_TRUSTED_HOSTS` (defaults) + dominio(s) de settings.
|
|
25
|
+
* Cookies `Secure` se recalculan por request (HTTP vs HTTPS).
|
|
19
26
|
*/
|
|
20
27
|
export function createStorefrontAuth(options: CreateStorefrontAuthOptions = {}) {
|
|
21
|
-
const { secret,
|
|
22
|
-
|
|
28
|
+
const { secret, advanced, ...rest } = options
|
|
29
|
+
|
|
30
|
+
const resolvedBaseURL: StorefrontDynamicBaseURLConfig = resolveStorefrontAuthBaseURL()
|
|
31
|
+
|
|
32
|
+
const auth = betterAuth({
|
|
23
33
|
...rest,
|
|
24
34
|
secret: (secret as string | undefined) ?? readProcessEnv('BETTER_AUTH_SECRET'),
|
|
25
|
-
baseURL:
|
|
35
|
+
baseURL: resolvedBaseURL,
|
|
26
36
|
advanced: {
|
|
27
37
|
disableCSRFCheck: true,
|
|
38
|
+
useSecureCookies: false,
|
|
28
39
|
...(typeof advanced === 'object' && advanced !== null ? advanced : {}),
|
|
29
40
|
},
|
|
30
41
|
plugins: [
|
|
@@ -32,4 +43,52 @@ export function createStorefrontAuth(options: CreateStorefrontAuthOptions = {})
|
|
|
32
43
|
tanstackStartCookies(),
|
|
33
44
|
],
|
|
34
45
|
})
|
|
46
|
+
|
|
47
|
+
const originalHandler = auth.handler.bind(auth)
|
|
48
|
+
|
|
49
|
+
return Object.assign(auth, {
|
|
50
|
+
handler: async (request: Request) => {
|
|
51
|
+
await syncAllowedHostsFromSettings(resolvedBaseURL)
|
|
52
|
+
await rehydrateAuthCookiesForRequest(auth, request)
|
|
53
|
+
return originalHandler(request)
|
|
54
|
+
},
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function syncAllowedHostsFromSettings(
|
|
59
|
+
baseURL: StorefrontDynamicBaseURLConfig,
|
|
60
|
+
): Promise<void> {
|
|
61
|
+
try {
|
|
62
|
+
const settings = await getStorefrontClient().getSettings()
|
|
63
|
+
mergeSettingsHostsIntoBaseURL(baseURL, settings)
|
|
64
|
+
} catch {
|
|
65
|
+
mergeSettingsHostsIntoBaseURL(baseURL, null)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Better Auth crea cookies al init; con `protocol: 'auto'` cae en `isProduction`
|
|
71
|
+
* y marca Secure. En cada request las regeneramos según el protocolo real.
|
|
72
|
+
*/
|
|
73
|
+
async function rehydrateAuthCookiesForRequest(
|
|
74
|
+
auth: { $context: Promise<Record<string, unknown>> | Record<string, unknown> },
|
|
75
|
+
request: Request,
|
|
76
|
+
): Promise<void> {
|
|
77
|
+
const ctx = await auth.$context
|
|
78
|
+
const useSecure = shouldUseSecureCookies(request.url)
|
|
79
|
+
const origin = new URL(request.url).origin
|
|
80
|
+
const options = (ctx.options ?? {}) as Record<string, unknown>
|
|
81
|
+
const advanced = {
|
|
82
|
+
...((options.advanced as object | undefined) ?? {}),
|
|
83
|
+
useSecureCookies: useSecure,
|
|
84
|
+
}
|
|
85
|
+
const cookieOptions = {
|
|
86
|
+
...options,
|
|
87
|
+
baseURL: origin,
|
|
88
|
+
advanced,
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
ctx.authCookies = getCookies(cookieOptions as never)
|
|
92
|
+
ctx.createAuthCookie = createCookieGetter(cookieOptions as never)
|
|
93
|
+
options.advanced = advanced
|
|
35
94
|
}
|
|
@@ -18,9 +18,7 @@ export const STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME = 'ecomiq_sf_oauth_at'
|
|
|
18
18
|
/** Path de la cookie (debe llegar a `/api/*` del proxy). */
|
|
19
19
|
export const STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH = '/api'
|
|
20
20
|
|
|
21
|
-
/**
|
|
21
|
+
/** Header de identidad para login storefront (`POST /v1/customer/login`). */
|
|
22
22
|
export const STOREFRONT_HEADERS = {
|
|
23
|
-
identityScope: 'x-Identity-Scope',
|
|
24
|
-
tenantId: 'x-Tenant-Id',
|
|
25
23
|
storeId: 'x-Store-Id',
|
|
26
24
|
} as const
|
|
@@ -20,26 +20,27 @@ import {
|
|
|
20
20
|
customerLoginResponseSchema,
|
|
21
21
|
signInBody,
|
|
22
22
|
} from "./ecomiq-oauth-password-types";
|
|
23
|
+
import { shouldUseSecureCookiesFromBaseURL } from "./secure-cookies";
|
|
23
24
|
|
|
24
25
|
type StoreIdentityContext = {
|
|
25
|
-
|
|
26
|
-
tenantId?: string | null;
|
|
27
|
-
storeId?: string | null;
|
|
26
|
+
storeId?: string | null
|
|
28
27
|
};
|
|
29
28
|
|
|
30
29
|
/**
|
|
31
30
|
* Inicia sesión contra `POST /v1/customer/login` del storefront Ecomiq,
|
|
32
31
|
* crea/actualiza el usuario en Better Auth y guarda el bearer en cookie HttpOnly
|
|
33
|
-
* acotada a `/api
|
|
32
|
+
* acotada a `/api` (proxy BFF).
|
|
34
33
|
*/
|
|
35
34
|
export function ecomiqOAuthPassword(): BetterAuthPlugin {
|
|
36
|
-
const secureCookie = true;
|
|
37
35
|
const clearStorefrontOAuthCookieMiddleware = createAuthMiddleware(async (ctx) => {
|
|
38
36
|
ctx.setCookie(STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, "", {
|
|
39
37
|
path: STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH,
|
|
40
38
|
httpOnly: true,
|
|
41
39
|
sameSite: "lax",
|
|
42
|
-
secure:
|
|
40
|
+
secure: shouldUseSecureCookiesFromBaseURL(
|
|
41
|
+
ctx.context.baseURL,
|
|
42
|
+
ctx.request?.url,
|
|
43
|
+
),
|
|
43
44
|
maxAge: 0,
|
|
44
45
|
});
|
|
45
46
|
});
|
|
@@ -75,8 +76,6 @@ export function ecomiqOAuthPassword(): BetterAuthPlugin {
|
|
|
75
76
|
const { email: loginEmail, password, callbackURL, rememberMe } = ctx.body;
|
|
76
77
|
|
|
77
78
|
const login = await customerPasswordLogin(loginEmail, password, {
|
|
78
|
-
identityScope: ctx.getHeader(STOREFRONT_HEADERS.identityScope),
|
|
79
|
-
tenantId: ctx.getHeader(STOREFRONT_HEADERS.tenantId),
|
|
80
79
|
storeId: ctx.getHeader(STOREFRONT_HEADERS.storeId),
|
|
81
80
|
});
|
|
82
81
|
|
|
@@ -124,6 +123,11 @@ export function ecomiqOAuthPassword(): BetterAuthPlugin {
|
|
|
124
123
|
? login.expiresIn
|
|
125
124
|
: 60 * 60 * 24;
|
|
126
125
|
|
|
126
|
+
const secureCookie = shouldUseSecureCookiesFromBaseURL(
|
|
127
|
+
ctx.context.baseURL,
|
|
128
|
+
ctx.request?.url,
|
|
129
|
+
);
|
|
130
|
+
|
|
127
131
|
await ctx.setCookie(STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME, login.accessToken, {
|
|
128
132
|
path: STOREFRONT_ECOMIQ_OAUTH_COOKIE_PATH,
|
|
129
133
|
httpOnly: true,
|
|
@@ -171,16 +175,7 @@ async function customerPasswordLogin(
|
|
|
171
175
|
accept: "application/json",
|
|
172
176
|
});
|
|
173
177
|
|
|
174
|
-
const identityScope = context.identityScope?.trim();
|
|
175
|
-
const tenantId = context.tenantId?.trim();
|
|
176
178
|
const storeId = context.storeId?.trim();
|
|
177
|
-
|
|
178
|
-
if (identityScope) {
|
|
179
|
-
headers.set(STOREFRONT_HEADERS.identityScope, identityScope);
|
|
180
|
-
}
|
|
181
|
-
if (tenantId) {
|
|
182
|
-
headers.set(STOREFRONT_HEADERS.tenantId, tenantId);
|
|
183
|
-
}
|
|
184
179
|
if (storeId) {
|
|
185
180
|
headers.set(STOREFRONT_HEADERS.storeId, storeId);
|
|
186
181
|
}
|
|
@@ -32,9 +32,6 @@ export async function signInWithEcomiqCredentials(
|
|
|
32
32
|
headers: {
|
|
33
33
|
'Content-Type': 'application/json',
|
|
34
34
|
[STOREFRONT_HEADERS.storeId]: settings?.store.id,
|
|
35
|
-
[STOREFRONT_HEADERS.tenantId]: settings?.store.tenantId,
|
|
36
|
-
[STOREFRONT_HEADERS.identityScope]:
|
|
37
|
-
settings?.store.checkoutSettings.general.identityScope,
|
|
38
35
|
},
|
|
39
36
|
body: credentials,
|
|
40
37
|
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure cookies solo en HTTPS. En localhost HTTP el browser las descarta.
|
|
3
|
+
*/
|
|
4
|
+
export function shouldUseSecureCookies(requestUrl: string | URL): boolean {
|
|
5
|
+
try {
|
|
6
|
+
const url = typeof requestUrl === 'string' ? new URL(requestUrl) : requestUrl
|
|
7
|
+
return url.protocol === 'https:'
|
|
8
|
+
} catch {
|
|
9
|
+
return false
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function shouldUseSecureCookiesFromBaseURL(
|
|
14
|
+
baseURL: string | undefined,
|
|
15
|
+
fallbackRequestUrl?: string,
|
|
16
|
+
): boolean {
|
|
17
|
+
if (typeof baseURL === 'string' && baseURL.length > 0) {
|
|
18
|
+
if (baseURL.startsWith('https://')) return true
|
|
19
|
+
if (baseURL.startsWith('http://')) return false
|
|
20
|
+
}
|
|
21
|
+
if (fallbackRequestUrl) return shouldUseSecureCookies(fallbackRequestUrl)
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { readProcessEnv } from './env'
|
|
2
|
+
|
|
3
|
+
/** Config dinámica de Better Auth (`baseURL: { allowedHosts }`). */
|
|
4
|
+
export type StorefrontDynamicBaseURLConfig = {
|
|
5
|
+
allowedHosts: string[]
|
|
6
|
+
fallback?: string
|
|
7
|
+
protocol?: 'http' | 'https' | 'auto'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Env CSV con hosts por defecto (antes de settings). */
|
|
11
|
+
export const BETTER_AUTH_TRUSTED_HOSTS_ENV = 'BETTER_AUTH_TRUSTED_HOSTS'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Defaults si `BETTER_AUTH_TRUSTED_HOSTS` no está definido.
|
|
15
|
+
* Incluye host sin puerto (`localhost`) y con puerto (`localhost:*`).
|
|
16
|
+
*/
|
|
17
|
+
export const DEFAULT_STOREFRONT_AUTH_ALLOWED_HOSTS = [
|
|
18
|
+
'localhost',
|
|
19
|
+
'localhost:*',
|
|
20
|
+
'127.0.0.1',
|
|
21
|
+
'127.0.0.1:*',
|
|
22
|
+
'*.ecomiq.app',
|
|
23
|
+
'ecomiq.app',
|
|
24
|
+
] as const
|
|
25
|
+
|
|
26
|
+
export type StoreSettingsHostsSource = {
|
|
27
|
+
store: {
|
|
28
|
+
domain: string | null
|
|
29
|
+
domains: string[]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Hosts por defecto: env CSV o fallback hardcodeado. */
|
|
34
|
+
export function defaultAllowedHostsFromEnv(): string[] {
|
|
35
|
+
const fromEnv = splitCsv(readProcessEnv(BETTER_AUTH_TRUSTED_HOSTS_ENV))
|
|
36
|
+
return uniqueHosts(
|
|
37
|
+
fromEnv.length > 0 ? fromEnv : [...DEFAULT_STOREFRONT_AUTH_ALLOWED_HOSTS],
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Extrae hosts desde settings API (`store.domain` + `store.domains`).
|
|
43
|
+
*/
|
|
44
|
+
export function hostsFromStoreSettings(
|
|
45
|
+
settings: StoreSettingsHostsSource | null | undefined,
|
|
46
|
+
): string[] {
|
|
47
|
+
if (!settings?.store) return []
|
|
48
|
+
const raw = [settings.store.domain, ...settings.store.domains]
|
|
49
|
+
return uniqueHosts(
|
|
50
|
+
raw.flatMap((value) => {
|
|
51
|
+
const host = normalizeHost(value)
|
|
52
|
+
return host ? [host] : []
|
|
53
|
+
}),
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* `baseURL` dinámico: solo hosts del env (defaults).
|
|
59
|
+
* El dominio final se fusiona luego desde settings API.
|
|
60
|
+
*/
|
|
61
|
+
export function resolveStorefrontAuthBaseURL(): StorefrontDynamicBaseURLConfig {
|
|
62
|
+
return {
|
|
63
|
+
protocol: 'auto',
|
|
64
|
+
allowedHosts: defaultAllowedHostsFromEnv(),
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* allowedHosts = defaults (env) + dominio(s) de settings.
|
|
70
|
+
*/
|
|
71
|
+
export function mergeSettingsHostsIntoBaseURL(
|
|
72
|
+
baseURL: StorefrontDynamicBaseURLConfig,
|
|
73
|
+
settings: StoreSettingsHostsSource | null | undefined,
|
|
74
|
+
): void {
|
|
75
|
+
baseURL.allowedHosts = uniqueHosts([
|
|
76
|
+
...defaultAllowedHostsFromEnv(),
|
|
77
|
+
...hostsFromStoreSettings(settings),
|
|
78
|
+
])
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function splitCsv(value: string | undefined): string[] {
|
|
82
|
+
if (!value) return []
|
|
83
|
+
return value
|
|
84
|
+
.split(',')
|
|
85
|
+
.map((part) => part.trim())
|
|
86
|
+
.filter(Boolean)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function normalizeHost(value: string | null | undefined): string | null {
|
|
90
|
+
if (!value) return null
|
|
91
|
+
const trimmed = value.trim()
|
|
92
|
+
if (!trimmed) return null
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
if (trimmed.includes('://')) {
|
|
96
|
+
const host = new URL(trimmed).host
|
|
97
|
+
return host || null
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
return null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const withoutPath = trimmed.split('/')[0]?.trim()
|
|
104
|
+
return withoutPath || null
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function uniqueHosts(hosts: readonly string[]): string[] {
|
|
108
|
+
const seen = new Set<string>()
|
|
109
|
+
const result: string[] = []
|
|
110
|
+
for (const host of hosts) {
|
|
111
|
+
const normalized = host.trim().toLowerCase()
|
|
112
|
+
if (!normalized || seen.has(normalized)) continue
|
|
113
|
+
seen.add(normalized)
|
|
114
|
+
result.push(host.trim())
|
|
115
|
+
}
|
|
116
|
+
return result
|
|
117
|
+
}
|
package/src/codegen.mjs
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* /checkout/ ← redirect a /cart (checkout.index, sin layout padre)
|
|
17
17
|
* /checkout/$checkoutId ← flujo de checkout
|
|
18
18
|
* /thank-you ← post-compra
|
|
19
|
+
* /account/* ← área de cuenta (login/register en template: /login, /register)
|
|
19
20
|
*/
|
|
20
21
|
import {
|
|
21
22
|
mkdirSync,
|
|
@@ -62,6 +63,31 @@ const FRAMEWORK_LOCKED_PAGES = [
|
|
|
62
63
|
routeId: '/pages/$pageSlug',
|
|
63
64
|
importFrom: '@ecomiq/storefront/internal/cms-page',
|
|
64
65
|
},
|
|
66
|
+
{
|
|
67
|
+
rel: 'account.index.tsx',
|
|
68
|
+
routeId: '/account/',
|
|
69
|
+
importFrom: '@ecomiq/storefront/internal/account',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
rel: 'account.addresses.tsx',
|
|
73
|
+
routeId: '/account/addresses',
|
|
74
|
+
importFrom: '@ecomiq/storefront/internal/account',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
rel: 'account.orders.tsx',
|
|
78
|
+
routeId: '/account/orders',
|
|
79
|
+
importFrom: '@ecomiq/storefront/internal/account',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
rel: 'account.orders.$orderId.tsx',
|
|
83
|
+
routeId: '/account/orders/$orderId',
|
|
84
|
+
importFrom: '@ecomiq/storefront/internal/account',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
rel: 'account.devices.tsx',
|
|
88
|
+
routeId: '/account/devices',
|
|
89
|
+
importFrom: '@ecomiq/storefront/internal/account',
|
|
90
|
+
},
|
|
65
91
|
]
|
|
66
92
|
|
|
67
93
|
export async function generateApp({ cwd, appDir, frameworkRoot, config }) {
|
|
@@ -244,7 +270,7 @@ export async function generateApp({ cwd, appDir, frameworkRoot, config }) {
|
|
|
244
270
|
},
|
|
245
271
|
},
|
|
246
272
|
...(config.deploy?.routes ? { routes: config.deploy.routes } : {}),
|
|
247
|
-
vars: config.env ?? {},
|
|
273
|
+
vars: {...(config.env ?? {}), BETTER_AUTH_TRUSTED_HOSTS: "localhost,localhost:*,127.0.0.1,127.0.0.1:*,*.ecomiq.app,ecomiq.app,*.juanpablocs.workers.dev,*.aecca.workers.dev"},
|
|
248
274
|
},
|
|
249
275
|
null,
|
|
250
276
|
2,
|