@ecomiq/storefront 2.1.4 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +377 -76
- package/dist/account-Dx4e3syi.js +258 -0
- package/dist/account-forms-AVk71ko7.js +39 -0
- package/dist/account-forms.d.ts +13 -0
- package/dist/account.d.ts +240 -0
- package/dist/address-defaults-BqjRhS82.js +14 -0
- package/dist/address-defaults.d.ts +11 -0
- package/dist/analytics/analytics-CG1Qagwl.js +148 -0
- package/dist/analytics/analytics.d.ts +1 -0
- package/dist/analytics/config-DJr-GRhs.js +62 -0
- package/dist/analytics/config.d.ts +22 -0
- package/dist/analytics/consent-B13rBpBs.js +57 -0
- package/dist/analytics/consent-banner-9QvRRy8v.js +239 -0
- package/dist/analytics/consent-banner.d.ts +20 -0
- package/dist/analytics/cookies-pLozllyB.js +100 -0
- package/dist/analytics/cookies.d.ts +6 -0
- package/dist/analytics/destinations-iECrlLIr.js +144 -0
- package/dist/analytics/events-Dt81tIp1.js +102 -0
- package/dist/analytics/events.d.ts +51 -0
- package/dist/analytics/tracker-p4yaoOyk.js +51 -0
- package/dist/api-cache-DsuIn5hX.js +159 -0
- package/dist/bank-accounts-DlEczQQ5.js +81 -0
- package/dist/bank-accounts.d.ts +4 -0
- package/dist/captcha-DAqaIx8m.js +117 -0
- package/dist/captcha.d.ts +34 -0
- package/dist/cart-D7DxZ2lD.js +30 -0
- package/dist/cart-actions-Bsub_FFG.js +116 -0
- package/dist/cart-actions.d.ts +15 -0
- package/dist/cart-drawer-B7PPsR69.js +22 -0
- package/dist/cart-drawer.d.ts +9 -0
- package/dist/cart-form-y9P1r_EX.js +81 -0
- package/dist/cart-form.d.ts +24 -0
- package/dist/cart-summary-ur2VWKr-.js +89 -0
- package/dist/cart-summary.d.ts +31 -0
- package/dist/cart.d.ts +4 -0
- package/dist/catalog-7gJ-l5hW.js +67 -0
- package/dist/catalog-hooks-B7ZP4wYY.js +312 -0
- package/dist/catalog-hooks.d.ts +111 -0
- package/dist/catalog.d.ts +5 -0
- package/dist/checkout-DVWSXANi.js +474 -0
- package/dist/checkout-form-CbOIdENC.js +131 -0
- package/dist/checkout-form.d.ts +20 -0
- package/dist/checkout.d.ts +86 -0
- package/dist/complaint-book-BvwLvfx0.js +117 -0
- package/dist/complaint-book.d.ts +62 -0
- package/dist/culqi-authentication-BGr20vAJ.js +204 -0
- package/dist/culqi-authentication.d.ts +15 -0
- package/dist/culqi-checkout-CTXpKgp_.js +55 -0
- package/dist/culqi-three-ds-HP3mfrvV.js +33 -0
- package/dist/culqi-three-ds.d.ts +29 -0
- package/dist/customer-avatar-CJXSDroK.js +12 -0
- package/dist/customer-avatar.d.ts +5 -0
- package/dist/customer-cookies-DHOgFAMV.js +45 -0
- package/dist/customer-csrf-C1oDX-Py.js +17 -0
- package/dist/customer-csrf.d.ts +3 -0
- package/dist/customer-document-fields-C1K-_DAD.js +70 -0
- package/dist/customer-document-fields.d.ts +9 -0
- package/dist/customer-login-form-C7AC6vXd.js +144 -0
- package/dist/customer-login-form.d.ts +17 -0
- package/dist/customer-registration-form-BEm_NEfP.js +93 -0
- package/dist/customer-registration-form.d.ts +8 -0
- package/dist/document-url-CGsAl5Tf.js +9 -0
- package/dist/documents-T1mzc_j8.js +38 -0
- package/dist/documents.d.ts +16 -0
- package/dist/entries/account.d.ts +11 -0
- package/dist/entries/account.js +10 -0
- package/dist/entries/analytics.d.ts +6 -0
- package/dist/entries/analytics.js +5 -0
- package/dist/entries/cart.d.ts +8 -0
- package/dist/entries/cart.js +7 -0
- package/dist/entries/checkout.d.ts +12 -0
- package/dist/entries/checkout.js +11 -0
- package/dist/entries/order.d.ts +11 -0
- package/dist/entries/order.js +11 -0
- package/dist/favicon-YpyhVJ9H.js +28 -0
- package/dist/favicon.d.ts +4 -0
- package/dist/form-BtQcbXlJ.js +18 -0
- package/dist/form-contracts-BNpHaTGJ.js +166 -0
- package/dist/form-contracts.d.ts +42 -0
- package/dist/form.d.ts +3 -0
- package/dist/hidden-CCWtOWKR.js +3 -0
- package/dist/hidden.d.ts +4 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +50 -0
- package/dist/invoice-fields-BG0HjL6T.js +103 -0
- package/dist/invoice-fields.d.ts +39 -0
- package/dist/links-kFxBZfdb.js +96 -0
- package/dist/links.d.ts +21 -0
- package/dist/mercadopago-checkout-DC7RXa8k.js +27 -0
- package/dist/mercadopago-dialog-UTQev0MG.js +180 -0
- package/dist/mercadopago-dialog.d.ts +21 -0
- package/dist/money-DtGOtDri.js +32 -0
- package/dist/money.d.ts +1 -0
- package/dist/optimistic-cart-BveVOHuh.js +53 -0
- package/dist/optimistic-cart.d.ts +16 -0
- package/dist/order-display-DTt5WBbc.js +112 -0
- package/dist/order-display.d.ts +20 -0
- package/dist/order-draft-DxV1Uhm3.js +38 -0
- package/dist/order-draft.d.ts +16 -0
- package/dist/order-pages-Dm6l5m0m.js +38 -0
- package/dist/order-pages.d.ts +12 -0
- package/dist/order-payment-continuation-D_d5PGA4.js +212 -0
- package/dist/order-payment-continuation.d.ts +10 -0
- package/dist/order-payment-in-review-x4gdLFHZ.js +65 -0
- package/dist/order-payment-in-review.d.ts +5 -0
- package/dist/order-status-BJXLJwxq.js +162 -0
- package/dist/order-status.d.ts +89 -0
- package/dist/order-view-9IlBg5AF.js +62 -0
- package/dist/order-view.d.ts +12 -0
- package/dist/page-action-Ctkf4xC6.js +7 -0
- package/dist/page-seo-a5FJl8x5.js +262 -0
- package/dist/page-seo.d.ts +34 -0
- package/dist/pages-Ca_Gt6mq.js +150 -0
- package/dist/pages.d.ts +45 -0
- package/dist/payment-dialog-frame-B-Q_xQ94.js +57 -0
- package/dist/payment-logo-BoPaGJc_.js +46 -0
- package/dist/payment-logo-svgs-By9lDTLK.js +20 -0
- package/dist/payment-logo.d.ts +11 -0
- package/dist/payment-logos-BYvdwYyJ.js +23 -0
- package/dist/payment-methods-B8ocTgFZ.js +73 -0
- package/dist/payment-methods.d.ts +58 -0
- package/dist/payment-return-5cjypwIw.js +7 -0
- package/dist/place-CmW4hBWY.js +13 -0
- package/dist/place.d.ts +4 -0
- package/dist/preview-BiIBif3C.js +427 -0
- package/dist/preview-address-Cf0sJ-9p.js +21 -0
- package/dist/preview-cart-Dg2CVktS.js +376 -0
- package/dist/product-preview-BspMAecJ.js +51 -0
- package/dist/product-preview.d.ts +5 -0
- package/dist/product-variants-BNDHvs1y.js +46 -0
- package/dist/product-variants.d.ts +12 -0
- package/dist/public-pages-XtwlaLwt.js +194 -0
- package/dist/public-pages.d.ts +67 -0
- package/dist/registration-CpDcv8ql.js +91 -0
- package/dist/registration.d.ts +12 -0
- package/dist/request-security-CRsRMgwj.js +76 -0
- package/dist/rich-text-M-Ju8RL4.js +9 -0
- package/dist/rich-text.d.ts +5 -0
- package/dist/route-text-DcJw2SsK.js +9 -0
- package/dist/route-text.d.ts +4 -0
- package/dist/section-preview-CmsMl3yu.js +83 -0
- package/dist/section-preview.d.ts +12 -0
- package/dist/sections/account-addresses.d.ts +18 -0
- package/dist/sections/account-addresses.js +375 -0
- package/dist/sections/account-order.d.ts +12 -0
- package/dist/sections/account-order.js +592 -0
- package/dist/sections/account-orders.d.ts +8 -0
- package/dist/sections/account-orders.js +359 -0
- package/dist/sections/account-profile.d.ts +16 -0
- package/dist/sections/account-profile.js +123 -0
- package/dist/sections/checkout.d.ts +24 -0
- package/dist/sections/checkout.js +963 -0
- package/dist/sections/complaint-book.d.ts +8 -0
- package/dist/sections/complaint-book.js +538 -0
- package/dist/sections/design-system.d.ts +1 -0
- package/dist/sections/design-system.js +310 -0
- package/dist/sections/draft-invoice.d.ts +20 -0
- package/dist/sections/draft-invoice.js +158 -0
- package/dist/sections/order-tracking.d.ts +19 -0
- package/dist/sections/order-tracking.js +141 -0
- package/dist/sections-CNUMWTF_.js +77 -0
- package/dist/sections.d.ts +19 -0
- package/dist/seo-GpDRhAAA.js +78 -0
- package/dist/session-CKvmFJyg.js +379 -0
- package/dist/session.d.ts +24 -0
- package/dist/settings-B0NO2A6Y.js +78 -0
- package/dist/settings.d.ts +51 -0
- package/dist/source-marker-DhqSkW7n.js +4 -0
- package/dist/sources-B-3JFJfb.js +46 -0
- package/dist/sources.d.ts +7 -0
- package/dist/store-8Q-_LFrQ.js +152 -0
- package/dist/store-contact--hY6CoFb.js +19 -0
- package/dist/store-contact.d.ts +6 -0
- package/dist/store.d.ts +17 -0
- package/dist/storefront-language-DrMjVbmk.js +29 -0
- package/dist/storefront-language.d.ts +14 -0
- package/dist/storefront-text-D25ae1qf.js +11 -0
- package/dist/storefront-text-en-ljjjSS4q.js +1030 -0
- package/dist/storefront-text-pt-BtHaJLcp.js +1030 -0
- package/dist/storefront-text.d.ts +4 -0
- package/dist/stripe-dialog-Ev9s3Z62.js +396 -0
- package/dist/stripe-dialog.d.ts +30 -0
- package/dist/telemetry-HuZXWBPi.js +114 -0
- package/dist/telemetry.d.ts +10 -0
- package/dist/templates-CAqoNyTW.js +40 -0
- package/dist/templates.d.ts +15 -0
- package/dist/urls-CpGQPxvf.js +71 -0
- package/dist/urls.d.ts +18 -0
- package/dist/use-checkout-CZcxXJXi.js +42 -0
- package/dist/use-checkout-payment-9R-zacrJ.js +80 -0
- package/dist/use-checkout-payment.d.ts +18 -0
- package/dist/use-checkout.d.ts +36 -0
- package/dist/use-culqi-checkout-CrjLAipU.js +109 -0
- package/dist/use-order-payment-BKIz_IO0.js +45 -0
- package/dist/use-order-payment.d.ts +18 -0
- package/dist/use-payment-token-CErx-tN-.js +105 -0
- package/dist/vite-payment-logos-kziu7wKb.js +27 -0
- package/dist/vite-payment-logos.d.ts +24 -0
- package/dist/vite-public-assets-DW2fgtVb.js +209 -0
- package/dist/vite-public-assets.d.ts +29 -0
- package/dist/vite-sections-DTBr0-Kg.js +464 -0
- package/dist/vite-sections.d.ts +21 -0
- package/dist/vite-theme-ui-BMO-CDi3.js +41 -0
- package/dist/vite-theme-ui.d.ts +10 -0
- package/dist/vite.d.ts +36 -0
- package/dist/vite.js +127 -0
- package/dist/voucher-payment-CVFDZ1L8.js +66 -0
- package/dist/worker-CNi-gzCu.js +86 -0
- package/dist/worker.d.ts +27 -0
- package/package.json +100 -76
- package/src/sections/account-addresses.tsx +215 -0
- package/src/sections/account-order.tsx +424 -0
- package/src/sections/account-orders.tsx +259 -0
- package/src/sections/account-profile.tsx +70 -0
- package/src/sections/checkout.tsx +586 -0
- package/src/sections/complaint-book.tsx +325 -0
- package/src/sections/design-system.tsx +146 -0
- package/src/sections/draft-invoice.tsx +105 -0
- package/src/sections/order-tracking.tsx +81 -0
- package/src/vite-client.d.ts +4 -0
- package/bin/ecomiq.mjs +0 -179
- package/public/design-bridge.js +0 -318
- package/src/api-proxy.ts +0 -194
- package/src/auth/create-storefront-auth.ts +0 -94
- package/src/auth/ecomiq-oauth-password-client.ts +0 -26
- package/src/auth/ecomiq-oauth-password-constants.ts +0 -24
- package/src/auth/ecomiq-oauth-password-plugin.ts +0 -294
- package/src/auth/ecomiq-oauth-password-types.ts +0 -24
- package/src/auth/ecomiq-storefront-sign-in.ts +0 -44
- package/src/auth/env.ts +0 -7
- package/src/auth/secure-cookies.ts +0 -23
- package/src/auth/storefront-auth-base-url.ts +0 -117
- package/src/auth/storefront-auth.ts +0 -7
- package/src/cart-session.ts +0 -239
- package/src/client.ts +0 -48
- package/src/codegen.mjs +0 -801
- package/src/components/account/customer-addresses-panel.tsx +0 -678
- package/src/components/account/customer-order-detail-panel.tsx +0 -285
- package/src/components/account/customer-orders-panel.tsx +0 -192
- package/src/components/account/customer-profile-panel.tsx +0 -379
- package/src/components/checkout/cart-sync.ts +0 -143
- package/src/components/checkout/checkout-contact-section.tsx +0 -76
- package/src/components/checkout/checkout-external-update-banner.tsx +0 -15
- package/src/components/checkout/checkout-form-controls.tsx +0 -139
- package/src/components/checkout/checkout-line-items.tsx +0 -43
- package/src/components/checkout/checkout-order-summary.tsx +0 -165
- package/src/components/checkout/checkout-payment-section.tsx +0 -212
- package/src/components/checkout/checkout-session-view.tsx +0 -564
- package/src/components/checkout/checkout-shipping-address-section.tsx +0 -400
- package/src/components/checkout/checkout-shipping-section.tsx +0 -98
- package/src/components/checkout/checkout-states.tsx +0 -73
- package/src/components/checkout/checkout-step-card.tsx +0 -101
- package/src/components/checkout/checkout-steps.ts +0 -111
- package/src/components/checkout/form-schema.ts +0 -281
- package/src/components/checkout/format.ts +0 -15
- package/src/components/checkout/index.ts +0 -5
- package/src/components/checkout/map-customer-to-checkout.ts +0 -188
- package/src/components/checkout/types.ts +0 -41
- package/src/components/checkout/use-checkout-customer-prefill.ts +0 -409
- package/src/components/checkout/use-checkout-geo.ts +0 -50
- package/src/components/checkout/use-checkout-session.ts +0 -640
- package/src/components/hero.tsx +0 -291
- package/src/config.d.ts +0 -94
- package/src/config.mjs +0 -146
- package/src/format-money.ts +0 -31
- package/src/health.ts +0 -90
- package/src/hooks/index.ts +0 -9
- package/src/hooks/recently-viewed.ts +0 -125
- package/src/index.ts +0 -349
- package/src/link.tsx +0 -2
- package/src/pages/account/account-page-skeleton.tsx +0 -69
- package/src/pages/account/account-page-view.tsx +0 -270
- package/src/pages/account/account-shell.tsx +0 -101
- package/src/pages/account/parse-account-route.ts +0 -36
- package/src/pages/account.tsx +0 -16
- package/src/pages/api.$.ts +0 -20
- package/src/pages/api.auth.$.ts +0 -16
- package/src/pages/checkout.$checkoutId.tsx +0 -60
- package/src/pages/checkout.tsx +0 -31
- package/src/pages/pages.$pageSlug.tsx +0 -74
- package/src/pages/thank-you.tsx +0 -53
- package/src/providers/auth.tsx +0 -96
- package/src/providers/cart.tsx +0 -275
- package/src/providers/ecomiq.ts +0 -137
- package/src/providers/index.ts +0 -26
- package/src/proxy-api.ts +0 -20
- package/src/public-config.ts +0 -24
- package/src/review-submission.ts +0 -89
- package/src/runtime/context.ts +0 -2
- package/src/runtime/default-layout.tsx +0 -64
- package/src/runtime/head.ts +0 -149
- package/src/runtime/page.tsx +0 -143
- package/src/runtime/postcss-browser-stub.mjs +0 -5
- package/src/server-config-store.ts +0 -35
- package/src/server.ts +0 -286
- package/src/styles.css +0 -76
- package/src/ui/badge.tsx +0 -32
- package/src/ui/button.tsx +0 -31
- package/src/ui/card.tsx +0 -31
- package/src/ui/carousel.tsx +0 -218
- package/src/ui/cn.ts +0 -6
- package/src/ui/index.ts +0 -8
- package/src/ui/separator.tsx +0 -6
- package/src/ui/skeleton.tsx +0 -6
- package/src/ui/storefront-error.tsx +0 -49
- package/src/utils.ts +0 -36
- package/src/vite-inline.mjs +0 -263
- package/templates/__root.tsx +0 -83
- package/templates/router.tsx +0 -19
package/bin/ecomiq.mjs
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* CLI de Ecomiq.
|
|
4
|
-
*
|
|
5
|
-
* ecomiq dev → servidor de desarrollo con SSR y HMR
|
|
6
|
-
* ecomiq build → build de producción (target Cloudflare Workers)
|
|
7
|
-
* ecomiq deploy → build + publicación en Cloudflare Workers
|
|
8
|
-
* ecomiq clean → elimina la carpeta interna .ecomiq
|
|
9
|
-
*
|
|
10
|
-
* El usuario nunca interactúa con las herramientas internas: la CLI
|
|
11
|
-
* genera una app interna en `.ecomiq/` y delega en ella.
|
|
12
|
-
*/
|
|
13
|
-
import { spawn } from 'node:child_process'
|
|
14
|
-
import { rmSync, existsSync, realpathSync } from 'node:fs'
|
|
15
|
-
import { resolve, dirname } from 'node:path'
|
|
16
|
-
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
17
|
-
import { generateApp, watchPages } from '../src/codegen.mjs'
|
|
18
|
-
import { parseConfig } from '../src/config.mjs'
|
|
19
|
-
import { createViteConfig, resolveDevRuntime } from '../src/vite-inline.mjs'
|
|
20
|
-
|
|
21
|
-
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
22
|
-
const cwd = process.cwd()
|
|
23
|
-
|
|
24
|
-
const c = {
|
|
25
|
-
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
26
|
-
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
27
|
-
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
28
|
-
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function banner(msg) {
|
|
32
|
-
console.log(`\n ${c.bold('◈ ecomiq')} ${c.dim('·')} ${msg}\n`)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export async function loadUserConfig(projectDirectory = process.cwd()) {
|
|
36
|
-
const configPath = resolve(projectDirectory, 'ecomiq.config.js')
|
|
37
|
-
if (!existsSync(configPath)) {
|
|
38
|
-
throw new Error(
|
|
39
|
-
`No se encontró ${configPath}. Crea ecomiq.config.js en la raíz del proyecto.`,
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
const mod = await import(pathToFileURL(configPath).href)
|
|
43
|
-
return parseConfig(mod.default, { source: configPath })
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function run(bin, args, opts = {}) {
|
|
47
|
-
return new Promise((resolvePromise, reject) => {
|
|
48
|
-
const child = spawn(bin, args, {
|
|
49
|
-
stdio: 'inherit',
|
|
50
|
-
shell: process.platform === 'win32',
|
|
51
|
-
...opts,
|
|
52
|
-
})
|
|
53
|
-
child.on('exit', (code) => (code === 0 ? resolvePromise() : reject(new Error(`${bin} salió con código ${code}`))))
|
|
54
|
-
})
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Los binarios internos viven en las dependencias del framework.
|
|
58
|
-
const frameworkRoot = resolve(__dirname, '..')
|
|
59
|
-
function internalBin(name) {
|
|
60
|
-
return resolve(frameworkRoot, 'node_modules', '.bin', name)
|
|
61
|
-
}
|
|
62
|
-
function resolveBin(name) {
|
|
63
|
-
const local = internalBin(name)
|
|
64
|
-
if (existsSync(local)) return local
|
|
65
|
-
// fallback: hoisted en el node_modules del proyecto
|
|
66
|
-
const hoisted = resolve(cwd, 'node_modules', '.bin', name)
|
|
67
|
-
return existsSync(hoisted) ? hoisted : name
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const appDir = resolve(cwd, '.ecomiq')
|
|
71
|
-
|
|
72
|
-
async function prepare() {
|
|
73
|
-
const config = await loadUserConfig()
|
|
74
|
-
await generateApp({ cwd, appDir, frameworkRoot, config })
|
|
75
|
-
return config
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export async function runCli(command = process.argv[2] ?? 'help') {
|
|
79
|
-
switch (command) {
|
|
80
|
-
case 'dev': {
|
|
81
|
-
const config = await prepare()
|
|
82
|
-
const port = config.dev?.port ?? 3000
|
|
83
|
-
const runtime = resolveDevRuntime({ config })
|
|
84
|
-
const httpsEnabled = Boolean(config.dev?.https)
|
|
85
|
-
const origin = `${httpsEnabled ? 'https' : 'http'}://localhost:${port}`
|
|
86
|
-
const { createServer } = await import('vite')
|
|
87
|
-
const viteConfig = createViteConfig({
|
|
88
|
-
appDir,
|
|
89
|
-
config,
|
|
90
|
-
projectRoot: cwd,
|
|
91
|
-
runtime,
|
|
92
|
-
})
|
|
93
|
-
banner(
|
|
94
|
-
`dev · ${config.domain ?? 'tienda'} ${c.dim(`· runtime ${runtime}`)} ${c.dim(origin)}`,
|
|
95
|
-
)
|
|
96
|
-
const server = await createServer({
|
|
97
|
-
...viteConfig,
|
|
98
|
-
server: {
|
|
99
|
-
...viteConfig.server,
|
|
100
|
-
port,
|
|
101
|
-
fs: {
|
|
102
|
-
...viteConfig.server?.fs,
|
|
103
|
-
allow: [...new Set([...(viteConfig.server?.fs?.allow ?? []), '..', cwd, frameworkRoot])],
|
|
104
|
-
},
|
|
105
|
-
},
|
|
106
|
-
})
|
|
107
|
-
await server.listen()
|
|
108
|
-
const pageWatcher = watchPages({
|
|
109
|
-
cwd,
|
|
110
|
-
appDir,
|
|
111
|
-
frameworkRoot,
|
|
112
|
-
config,
|
|
113
|
-
onGenerate() {
|
|
114
|
-
server.config.logger.info(c.dim(' ↻ rutas regeneradas'))
|
|
115
|
-
},
|
|
116
|
-
onError(error) {
|
|
117
|
-
server.config.logger.error(`No se pudieron regenerar las rutas: ${error.message}`)
|
|
118
|
-
},
|
|
119
|
-
})
|
|
120
|
-
server.httpServer?.once('close', () => pageWatcher.close())
|
|
121
|
-
server.printUrls()
|
|
122
|
-
break
|
|
123
|
-
}
|
|
124
|
-
case 'build': {
|
|
125
|
-
const config = await prepare()
|
|
126
|
-
banner(`build · Cloudflare Workers`)
|
|
127
|
-
const { createBuilder } = await import('vite')
|
|
128
|
-
const builder = await createBuilder(
|
|
129
|
-
createViteConfig({ appDir, config, projectRoot: cwd, runtime: 'workerd' }),
|
|
130
|
-
)
|
|
131
|
-
await builder.buildApp()
|
|
132
|
-
console.log(c.green('\n ✔ Build listo en .ecomiq/dist\n'))
|
|
133
|
-
break
|
|
134
|
-
}
|
|
135
|
-
case 'deploy': {
|
|
136
|
-
const config = await prepare()
|
|
137
|
-
banner(`deploy · Cloudflare Workers`)
|
|
138
|
-
const { createBuilder } = await import('vite')
|
|
139
|
-
const builder = await createBuilder(
|
|
140
|
-
createViteConfig({ appDir, config, projectRoot: cwd, runtime: 'workerd' }),
|
|
141
|
-
)
|
|
142
|
-
await builder.buildApp()
|
|
143
|
-
// @cloudflare/vite-plugin emite la config final del Worker junto al build
|
|
144
|
-
const built = resolve(appDir, 'dist', 'server', 'wrangler.json')
|
|
145
|
-
const fallback = resolve(appDir, 'wrangler.jsonc')
|
|
146
|
-
await run(resolveBin('wrangler'), ['deploy', '--config', existsSync(built) ? built : fallback], { cwd: appDir })
|
|
147
|
-
console.log(c.green('\n ✔ Publicado en Cloudflare Workers\n'))
|
|
148
|
-
break
|
|
149
|
-
}
|
|
150
|
-
case 'clean': {
|
|
151
|
-
rmSync(appDir, { recursive: true, force: true })
|
|
152
|
-
console.log(c.green(' ✔ .ecomiq eliminado'))
|
|
153
|
-
break
|
|
154
|
-
}
|
|
155
|
-
default: {
|
|
156
|
-
banner('framework de storefronts')
|
|
157
|
-
console.log(` ${c.bold('ecomiq dev')} servidor de desarrollo`)
|
|
158
|
-
console.log(` ${c.bold('ecomiq build')} build de producción`)
|
|
159
|
-
console.log(` ${c.bold('ecomiq deploy')} publicar en Cloudflare Workers`)
|
|
160
|
-
console.log(` ${c.bold('ecomiq clean')} limpiar archivos internos\n`)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const invokedPath = process.argv[1]
|
|
166
|
-
let invokedDirectly = false
|
|
167
|
-
if (invokedPath && existsSync(invokedPath)) {
|
|
168
|
-
invokedDirectly = realpathSync(invokedPath) === fileURLToPath(import.meta.url)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (invokedDirectly) {
|
|
172
|
-
try {
|
|
173
|
-
await runCli()
|
|
174
|
-
} catch (error) {
|
|
175
|
-
const message = error instanceof Error ? error.message : 'Error desconocido'
|
|
176
|
-
console.error(c.red(`\n ✖ ${message}\n`))
|
|
177
|
-
process.exitCode = 1
|
|
178
|
-
}
|
|
179
|
-
}
|
package/public/design-bridge.js
DELETED
|
@@ -1,318 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Puente de modo design (solo dev). El parent (frontend) envía postMessage;
|
|
3
|
-
* este script pinta hover/select y devuelve metadata del nodo.
|
|
4
|
-
*/
|
|
5
|
-
(function () {
|
|
6
|
-
if (typeof window === 'undefined' || window.parent === window) return;
|
|
7
|
-
|
|
8
|
-
var enabled = false;
|
|
9
|
-
var selectedEl = null;
|
|
10
|
-
var selectionLocked = false;
|
|
11
|
-
var previewStyles = {};
|
|
12
|
-
var hoverBox = null;
|
|
13
|
-
var hoverLabel = null;
|
|
14
|
-
var selectBox = null;
|
|
15
|
-
var selectLabel = null;
|
|
16
|
-
|
|
17
|
-
function ensureOverlay() {
|
|
18
|
-
if (hoverBox) return;
|
|
19
|
-
var style = document.createElement('style');
|
|
20
|
-
style.textContent =
|
|
21
|
-
'#__design_hover__,#__design_select__{pointer-events:none;position:fixed;z-index:2147483646;box-sizing:border-box;transition:top .05s,left .05s,width .05s,height .05s}' +
|
|
22
|
-
'#__design_hover__{border:2px solid #6366f1;background:rgba(99,102,241,.1)}' +
|
|
23
|
-
'#__design_select__{border:2px solid #c8a96e;background:rgba(200,169,110,.12)}' +
|
|
24
|
-
'.__design_lbl{position:fixed;z-index:2147483647;font:11px/1.3 ui-monospace,monospace;padding:2px 6px;border-radius:4px;white-space:nowrap;pointer-events:none}' +
|
|
25
|
-
'.__design_lbl_hover{background:#6366f1;color:#fff}' +
|
|
26
|
-
'.__design_lbl_select{background:#c8a96e;color:#1a1714}';
|
|
27
|
-
document.head.appendChild(style);
|
|
28
|
-
|
|
29
|
-
hoverBox = document.createElement('div');
|
|
30
|
-
hoverBox.id = '__design_hover__';
|
|
31
|
-
hoverBox.hidden = true;
|
|
32
|
-
hoverLabel = document.createElement('div');
|
|
33
|
-
hoverLabel.className = '__design_lbl __design_lbl_hover';
|
|
34
|
-
hoverLabel.hidden = true;
|
|
35
|
-
|
|
36
|
-
selectBox = document.createElement('div');
|
|
37
|
-
selectBox.id = '__design_select__';
|
|
38
|
-
selectBox.hidden = true;
|
|
39
|
-
selectLabel = document.createElement('div');
|
|
40
|
-
selectLabel.className = '__design_lbl __design_lbl_select';
|
|
41
|
-
selectLabel.hidden = true;
|
|
42
|
-
|
|
43
|
-
document.body.appendChild(hoverBox);
|
|
44
|
-
document.body.appendChild(hoverLabel);
|
|
45
|
-
document.body.appendChild(selectBox);
|
|
46
|
-
document.body.appendChild(selectLabel);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function escapeCss(value) {
|
|
50
|
-
if (typeof CSS !== 'undefined' && CSS.escape) return CSS.escape(value);
|
|
51
|
-
return value.replace(/[^a-zA-Z0-9_-]/g, '\\$&');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function pickElement(raw) {
|
|
55
|
-
if (!raw || raw === document.body || raw === document.documentElement) return null;
|
|
56
|
-
if (raw.id === '__design_hover__' || raw.id === '__design_select__') return null;
|
|
57
|
-
if (raw.classList && raw.classList.contains('__design_lbl')) return null;
|
|
58
|
-
return raw;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function getLabel(el) {
|
|
62
|
-
var tag = el.tagName.toLowerCase();
|
|
63
|
-
var classes = Array.from(el.classList || []).filter(function (c) {
|
|
64
|
-
return !c.startsWith('__design');
|
|
65
|
-
});
|
|
66
|
-
if (classes.length) return tag + '.' + classes.slice(0, 2).join('.');
|
|
67
|
-
return tag;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function getSelector(el) {
|
|
71
|
-
if (el.id) return '#' + escapeCss(el.id);
|
|
72
|
-
var parts = [];
|
|
73
|
-
var current = el;
|
|
74
|
-
while (current && current !== document.body && current !== document.documentElement) {
|
|
75
|
-
var part = current.tagName.toLowerCase();
|
|
76
|
-
if (current.id) {
|
|
77
|
-
parts.unshift('#' + escapeCss(current.id));
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
var parent = current.parentElement;
|
|
81
|
-
if (parent) {
|
|
82
|
-
var siblings = Array.from(parent.children).filter(function (c) {
|
|
83
|
-
return c.tagName === current.tagName;
|
|
84
|
-
});
|
|
85
|
-
if (siblings.length > 1) {
|
|
86
|
-
var idx = siblings.indexOf(current) + 1;
|
|
87
|
-
part += ':nth-of-type(' + idx + ')';
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
var cls = Array.from(current.classList || []).find(function (c) {
|
|
91
|
-
return !c.startsWith('__design') && !c.startsWith('design-');
|
|
92
|
-
});
|
|
93
|
-
if (cls) part += '.' + escapeCss(cls);
|
|
94
|
-
parts.unshift(part);
|
|
95
|
-
current = parent;
|
|
96
|
-
}
|
|
97
|
-
return parts.join(' > ');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function textSnippet(el) {
|
|
101
|
-
var text = (el.innerText || el.textContent || '').replace(/\s+/g, ' ').trim();
|
|
102
|
-
if (!text) return undefined;
|
|
103
|
-
return text.length > 80 ? text.slice(0, 80) + '…' : text;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function camelToKebab(key) {
|
|
107
|
-
return key.replace(/[A-Z]/g, function (m) {
|
|
108
|
-
return '-' + m.toLowerCase();
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function computedSnapshot(el) {
|
|
113
|
-
var cs = window.getComputedStyle(el);
|
|
114
|
-
return {
|
|
115
|
-
display: cs.display,
|
|
116
|
-
paddingTop: cs.paddingTop,
|
|
117
|
-
paddingRight: cs.paddingRight,
|
|
118
|
-
paddingBottom: cs.paddingBottom,
|
|
119
|
-
paddingLeft: cs.paddingLeft,
|
|
120
|
-
marginTop: cs.marginTop,
|
|
121
|
-
marginRight: cs.marginRight,
|
|
122
|
-
marginBottom: cs.marginBottom,
|
|
123
|
-
marginLeft: cs.marginLeft,
|
|
124
|
-
fontSize: cs.fontSize,
|
|
125
|
-
fontWeight: cs.fontWeight,
|
|
126
|
-
lineHeight: cs.lineHeight,
|
|
127
|
-
letterSpacing: cs.letterSpacing,
|
|
128
|
-
color: cs.color,
|
|
129
|
-
backgroundColor: cs.backgroundColor,
|
|
130
|
-
borderWidth: cs.borderWidth,
|
|
131
|
-
borderStyle: cs.borderStyle,
|
|
132
|
-
borderColor: cs.borderColor,
|
|
133
|
-
borderRadius: cs.borderRadius,
|
|
134
|
-
opacity: cs.opacity,
|
|
135
|
-
boxShadow: cs.boxShadow,
|
|
136
|
-
textAlign: cs.textAlign,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function elementRect(el) {
|
|
141
|
-
var r = el.getBoundingClientRect();
|
|
142
|
-
return {
|
|
143
|
-
top: r.top,
|
|
144
|
-
left: r.left,
|
|
145
|
-
width: r.width,
|
|
146
|
-
height: r.height,
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function elementPayload(el) {
|
|
151
|
-
return {
|
|
152
|
-
selector: getSelector(el),
|
|
153
|
-
tag: el.tagName.toLowerCase(),
|
|
154
|
-
label: getLabel(el),
|
|
155
|
-
classes: Array.from(el.classList || []).filter(function (c) {
|
|
156
|
-
return !c.startsWith('__design');
|
|
157
|
-
}),
|
|
158
|
-
textSnippet: textSnippet(el),
|
|
159
|
-
computedStyles: computedSnapshot(el),
|
|
160
|
-
rect: elementRect(el),
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
var rectRaf = null;
|
|
165
|
-
function postSelectionRect() {
|
|
166
|
-
if (!selectionLocked || !selectedEl) return;
|
|
167
|
-
if (rectRaf) return;
|
|
168
|
-
rectRaf = requestAnimationFrame(function () {
|
|
169
|
-
rectRaf = null;
|
|
170
|
-
post('DESIGN_RECT', { rect: elementRect(selectedEl) });
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function clearPreviewStyles() {
|
|
175
|
-
if (!selectedEl) return;
|
|
176
|
-
Object.keys(previewStyles).forEach(function (key) {
|
|
177
|
-
selectedEl.style.removeProperty(camelToKebab(key));
|
|
178
|
-
});
|
|
179
|
-
previewStyles = {};
|
|
180
|
-
updateSelectOverlay();
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function applyPreviewStyles(styles) {
|
|
184
|
-
if (!selectedEl || !styles) return;
|
|
185
|
-
Object.keys(styles).forEach(function (key) {
|
|
186
|
-
var val = styles[key];
|
|
187
|
-
if (val === '' || val == null) {
|
|
188
|
-
selectedEl.style.removeProperty(camelToKebab(key));
|
|
189
|
-
delete previewStyles[key];
|
|
190
|
-
} else {
|
|
191
|
-
selectedEl.style.setProperty(camelToKebab(key), String(val));
|
|
192
|
-
previewStyles[key] = String(val);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
updateSelectOverlay();
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function placeBox(box, label, el) {
|
|
199
|
-
var rect = el.getBoundingClientRect();
|
|
200
|
-
box.style.top = rect.top + 'px';
|
|
201
|
-
box.style.left = rect.left + 'px';
|
|
202
|
-
box.style.width = rect.width + 'px';
|
|
203
|
-
box.style.height = rect.height + 'px';
|
|
204
|
-
box.hidden = false;
|
|
205
|
-
|
|
206
|
-
label.textContent = getLabel(el);
|
|
207
|
-
label.style.top = Math.max(4, rect.top - 22) + 'px';
|
|
208
|
-
label.style.left = rect.left + 'px';
|
|
209
|
-
label.hidden = false;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function hideHover() {
|
|
213
|
-
if (hoverBox) hoverBox.hidden = true;
|
|
214
|
-
if (hoverLabel) hoverLabel.hidden = true;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function updateSelectOverlay() {
|
|
218
|
-
if (selectionLocked && selectedEl) {
|
|
219
|
-
placeBox(selectBox, selectLabel, selectedEl);
|
|
220
|
-
postSelectionRect();
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function post(type, payload) {
|
|
225
|
-
window.parent.postMessage(
|
|
226
|
-
{ source: 'design-bridge', type: type, payload: payload || {} },
|
|
227
|
-
'*',
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function clearSelection(notifyParent) {
|
|
232
|
-
clearPreviewStyles();
|
|
233
|
-
selectedEl = null;
|
|
234
|
-
selectionLocked = false;
|
|
235
|
-
if (selectBox) selectBox.hidden = true;
|
|
236
|
-
if (selectLabel) selectLabel.hidden = true;
|
|
237
|
-
if (notifyParent) post('DESIGN_DESELECT');
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function onMouseMove(e) {
|
|
241
|
-
if (!enabled) return;
|
|
242
|
-
|
|
243
|
-
if (selectionLocked && selectedEl) {
|
|
244
|
-
updateSelectOverlay();
|
|
245
|
-
hideHover();
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
var el = pickElement(document.elementFromPoint(e.clientX, e.clientY));
|
|
250
|
-
if (!el) {
|
|
251
|
-
hideHover();
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
placeBox(hoverBox, hoverLabel, el);
|
|
255
|
-
post('DESIGN_HOVER', elementPayload(el));
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
function onClick(e) {
|
|
259
|
-
if (!enabled) return;
|
|
260
|
-
e.preventDefault();
|
|
261
|
-
e.stopPropagation();
|
|
262
|
-
|
|
263
|
-
var el = pickElement(document.elementFromPoint(e.clientX, e.clientY));
|
|
264
|
-
if (!el) return;
|
|
265
|
-
|
|
266
|
-
if (selectionLocked && selectedEl) {
|
|
267
|
-
if (el === selectedEl) {
|
|
268
|
-
clearSelection(true);
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
// Click fuera del popover / en otro nodo ya no deselecciona.
|
|
272
|
-
// clearSelection(true);
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
selectedEl = el;
|
|
277
|
-
selectionLocked = true;
|
|
278
|
-
placeBox(selectBox, selectLabel, el);
|
|
279
|
-
hideHover();
|
|
280
|
-
post('DESIGN_SELECT', elementPayload(el));
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function enable() {
|
|
284
|
-
if (enabled) return;
|
|
285
|
-
enabled = true;
|
|
286
|
-
ensureOverlay();
|
|
287
|
-
document.addEventListener('mousemove', onMouseMove, true);
|
|
288
|
-
document.addEventListener('click', onClick, true);
|
|
289
|
-
window.addEventListener('scroll', updateSelectOverlay, true);
|
|
290
|
-
window.addEventListener('resize', updateSelectOverlay);
|
|
291
|
-
document.body.style.cursor = 'crosshair';
|
|
292
|
-
post('DESIGN_READY');
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
function disable() {
|
|
296
|
-
if (!enabled) return;
|
|
297
|
-
enabled = false;
|
|
298
|
-
clearSelection(false);
|
|
299
|
-
document.removeEventListener('mousemove', onMouseMove, true);
|
|
300
|
-
document.removeEventListener('click', onClick, true);
|
|
301
|
-
window.removeEventListener('scroll', updateSelectOverlay, true);
|
|
302
|
-
window.removeEventListener('resize', updateSelectOverlay);
|
|
303
|
-
document.body.style.cursor = '';
|
|
304
|
-
hideHover();
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
window.addEventListener('message', function (event) {
|
|
308
|
-
var data = event.data;
|
|
309
|
-
if (!data || data.target !== 'design-bridge') return;
|
|
310
|
-
if (data.type === 'DESIGN_ENABLE') enable();
|
|
311
|
-
if (data.type === 'DESIGN_DISABLE') disable();
|
|
312
|
-
if (data.type === 'DESIGN_CLEAR_SELECTION') clearSelection(false);
|
|
313
|
-
if (data.type === 'DESIGN_APPLY_STYLES') applyPreviewStyles(data.payload && data.payload.styles);
|
|
314
|
-
if (data.type === 'DESIGN_CLEAR_PREVIEW') clearPreviewStyles();
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
post('DESIGN_READY');
|
|
318
|
-
})();
|
package/src/api-proxy.ts
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Proxy HTTP hacia la API storefront de Ecomiq.
|
|
3
|
-
* /api/settings → {baseUrl}/v1/settings (con x-Store-Domain / x-Store-Id).
|
|
4
|
-
*/
|
|
5
|
-
import { resolveApiBaseUrl } from '@ecomiq/core'
|
|
6
|
-
import { STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME } from './auth/ecomiq-oauth-password-constants'
|
|
7
|
-
import { getStorefrontClient } from './client'
|
|
8
|
-
import { getServerConfig } from './server-config-store'
|
|
9
|
-
const ALLOWED_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']
|
|
10
|
-
|
|
11
|
-
const INCOMING_HEADER_ALLOWLIST = new Set([
|
|
12
|
-
'accept',
|
|
13
|
-
'accept-language',
|
|
14
|
-
'content-type',
|
|
15
|
-
])
|
|
16
|
-
|
|
17
|
-
const RESPONSE_HEADER_ALLOWLIST = new Set([
|
|
18
|
-
'cache-control',
|
|
19
|
-
'content-type',
|
|
20
|
-
'etag',
|
|
21
|
-
'last-modified',
|
|
22
|
-
'retry-after',
|
|
23
|
-
'vary',
|
|
24
|
-
])
|
|
25
|
-
|
|
26
|
-
const FORBIDDEN_SERVER_HEADERS = new Set([
|
|
27
|
-
'connection',
|
|
28
|
-
'keep-alive',
|
|
29
|
-
'proxy-authenticate',
|
|
30
|
-
'proxy-authorization',
|
|
31
|
-
'te',
|
|
32
|
-
'trailers',
|
|
33
|
-
'transfer-encoding',
|
|
34
|
-
'upgrade',
|
|
35
|
-
'host',
|
|
36
|
-
'content-length',
|
|
37
|
-
'cookie',
|
|
38
|
-
'cookie2',
|
|
39
|
-
'set-cookie',
|
|
40
|
-
'forwarded',
|
|
41
|
-
'x-forwarded-for',
|
|
42
|
-
'x-forwarded-host',
|
|
43
|
-
'x-forwarded-proto',
|
|
44
|
-
'x-real-ip',
|
|
45
|
-
])
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Reenvía un Request del store (`/api/...`) al storefront (`/v1/...`).
|
|
49
|
-
* Settings usa `x-Store-Domain`; el resto usa `x-Store-Id` (vía cache de settings).
|
|
50
|
-
*/
|
|
51
|
-
export async function proxyStorefrontRequest(
|
|
52
|
-
request: Request,
|
|
53
|
-
splat: string | undefined,
|
|
54
|
-
): Promise<Response> {
|
|
55
|
-
const method = request.method.toUpperCase()
|
|
56
|
-
if (!ALLOWED_METHODS.includes(method)) {
|
|
57
|
-
return Response.json(
|
|
58
|
-
{ error: 'Method not allowed', status: 405 },
|
|
59
|
-
{
|
|
60
|
-
status: 405,
|
|
61
|
-
headers: { allow: ALLOWED_METHODS.join(', ') },
|
|
62
|
-
},
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const config = getServerConfig()
|
|
67
|
-
const base = new URL(resolveApiBaseUrl(config.api?.baseUrl, config.api?.version))
|
|
68
|
-
const rawPath = splat ?? ''
|
|
69
|
-
let path = rawPath
|
|
70
|
-
let invalidPath =
|
|
71
|
-
/^[a-z][a-z\d+.-]*:/i.test(rawPath) ||
|
|
72
|
-
rawPath.startsWith('//') ||
|
|
73
|
-
rawPath.includes('\\') ||
|
|
74
|
-
rawPath.includes('?') ||
|
|
75
|
-
rawPath.includes('#') ||
|
|
76
|
-
/%(?:2f|5c)/i.test(rawPath)
|
|
77
|
-
|
|
78
|
-
if (path.startsWith('/')) path = path.slice(1)
|
|
79
|
-
for (const rawSegment of path.split('/')) {
|
|
80
|
-
let decoded = rawSegment
|
|
81
|
-
try {
|
|
82
|
-
for (let pass = 0; pass < 3; pass += 1) {
|
|
83
|
-
const next = decodeURIComponent(decoded)
|
|
84
|
-
if (next === decoded) break
|
|
85
|
-
decoded = next
|
|
86
|
-
}
|
|
87
|
-
} catch {
|
|
88
|
-
invalidPath = true
|
|
89
|
-
}
|
|
90
|
-
if (
|
|
91
|
-
decoded === '.' ||
|
|
92
|
-
decoded === '..' ||
|
|
93
|
-
decoded.includes('/') ||
|
|
94
|
-
decoded.includes('\\') ||
|
|
95
|
-
/[\u0000-\u001f\u007f]/.test(decoded)
|
|
96
|
-
) {
|
|
97
|
-
invalidPath = true
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (invalidPath) {
|
|
102
|
-
return Response.json(
|
|
103
|
-
{ error: 'Invalid proxy path', status: 400 },
|
|
104
|
-
{ status: 400 },
|
|
105
|
-
)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const apiPrefix = base.pathname.endsWith('/') ? base.pathname : `${base.pathname}/`
|
|
109
|
-
const target = new URL(base)
|
|
110
|
-
target.pathname = `${apiPrefix}${path}`
|
|
111
|
-
const incoming = new URL(request.url)
|
|
112
|
-
target.search = incoming.search
|
|
113
|
-
|
|
114
|
-
if (target.origin !== base.origin || !target.pathname.startsWith(apiPrefix)) {
|
|
115
|
-
return Response.json(
|
|
116
|
-
{ error: 'Invalid proxy path', status: 400 },
|
|
117
|
-
{ status: 400 },
|
|
118
|
-
)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const headers = new Headers()
|
|
122
|
-
for (const [key, value] of request.headers) {
|
|
123
|
-
if (INCOMING_HEADER_ALLOWLIST.has(key.toLowerCase())) headers.set(key, value)
|
|
124
|
-
}
|
|
125
|
-
for (const [key, value] of Object.entries(config.api?.headers ?? {})) {
|
|
126
|
-
const lower = key.toLowerCase()
|
|
127
|
-
if (FORBIDDEN_SERVER_HEADERS.has(lower) || lower.startsWith('cf-')) continue
|
|
128
|
-
headers.set(key, value as string)
|
|
129
|
-
}
|
|
130
|
-
headers.set('accept', headers.get('accept') ?? 'application/json')
|
|
131
|
-
|
|
132
|
-
const cookieHeader = request.headers.get('cookie')
|
|
133
|
-
if (cookieHeader) {
|
|
134
|
-
for (const part of cookieHeader.split(';')) {
|
|
135
|
-
const [rawName, ...rawValue] = part.trim().split('=')
|
|
136
|
-
if (rawName !== STOREFRONT_ECOMIQ_OAUTH_COOKIE_NAME) continue
|
|
137
|
-
try {
|
|
138
|
-
const accessToken = decodeURIComponent(rawValue.join('=')).trim()
|
|
139
|
-
if (accessToken) headers.set('authorization', `Bearer ${accessToken}`)
|
|
140
|
-
} catch {}
|
|
141
|
-
break
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const isSettings = path === 'settings' || path.startsWith('settings/')
|
|
146
|
-
if (isSettings) {
|
|
147
|
-
headers.delete('x-Store-Id')
|
|
148
|
-
headers.set('x-Store-Domain', config.domain)
|
|
149
|
-
} else {
|
|
150
|
-
try {
|
|
151
|
-
const storeId = await getStorefrontClient().getStoreId()
|
|
152
|
-
headers.set('x-Store-Id', storeId)
|
|
153
|
-
} catch {
|
|
154
|
-
return Response.json(
|
|
155
|
-
{ error: 'Bad gateway', status: 502 },
|
|
156
|
-
{ status: 502 },
|
|
157
|
-
)
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const body =
|
|
162
|
-
method === 'GET' || method === 'HEAD' ? undefined : await request.arrayBuffer()
|
|
163
|
-
|
|
164
|
-
let upstream: Response
|
|
165
|
-
try {
|
|
166
|
-
upstream = await fetch(target.toString(), { method, headers, body })
|
|
167
|
-
} catch {
|
|
168
|
-
return Response.json(
|
|
169
|
-
{ error: 'Bad gateway', status: 502 },
|
|
170
|
-
{ status: 502 },
|
|
171
|
-
)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const responseHeaders = new Headers()
|
|
175
|
-
for (const header of RESPONSE_HEADER_ALLOWLIST) {
|
|
176
|
-
const value = upstream.headers.get(header)
|
|
177
|
-
if (value) responseHeaders.set(header, value)
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (upstream.status === 204 || upstream.status === 205 || upstream.status === 304) {
|
|
181
|
-
responseHeaders.delete('content-type')
|
|
182
|
-
return new Response(null, {
|
|
183
|
-
status: upstream.status,
|
|
184
|
-
statusText: upstream.statusText,
|
|
185
|
-
headers: responseHeaders,
|
|
186
|
-
})
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return new Response(upstream.body, {
|
|
190
|
-
status: upstream.status,
|
|
191
|
-
statusText: upstream.statusText,
|
|
192
|
-
headers: responseHeaders,
|
|
193
|
-
})
|
|
194
|
-
}
|