@fayz-ai/storefront 0.80.0 → 0.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/app/prerender.d.ts +1 -9
  2. package/dist/app/prerender.d.ts.map +1 -1
  3. package/dist/app/sitemap.d.ts +10 -0
  4. package/dist/app/sitemap.d.ts.map +1 -0
  5. package/dist/chunk-2KCORAVB.js +1183 -0
  6. package/dist/chunk-2KCORAVB.js.map +1 -0
  7. package/dist/{chunk-V7CGLOEN.js → chunk-CWHGBPRP.js} +162 -2664
  8. package/dist/chunk-CWHGBPRP.js.map +1 -0
  9. package/dist/chunk-OIPNINZQ.js +1336 -0
  10. package/dist/chunk-OIPNINZQ.js.map +1 -0
  11. package/dist/chunk-WCAQRATH.js +30 -0
  12. package/dist/chunk-WCAQRATH.js.map +1 -0
  13. package/dist/data/menu-needs.d.ts +30 -0
  14. package/dist/data/menu-needs.d.ts.map +1 -0
  15. package/dist/edge.d.ts +1 -0
  16. package/dist/edge.d.ts.map +1 -1
  17. package/dist/edge.js +80 -1
  18. package/dist/edge.js.map +1 -1
  19. package/dist/host/edge-handler.d.ts +38 -0
  20. package/dist/host/edge-handler.d.ts.map +1 -0
  21. package/dist/host/image-origin.d.ts +16 -0
  22. package/dist/host/image-origin.d.ts.map +1 -0
  23. package/dist/host/store-host.d.ts +131 -0
  24. package/dist/host/store-host.d.ts.map +1 -0
  25. package/dist/host.d.ts +7 -0
  26. package/dist/host.d.ts.map +1 -0
  27. package/dist/host.js +223 -0
  28. package/dist/host.js.map +1 -0
  29. package/dist/index.js +6 -2
  30. package/dist/index.js.map +1 -1
  31. package/dist/render.js +6 -27
  32. package/dist/render.js.map +1 -1
  33. package/dist/tanstack.d.ts +35 -0
  34. package/dist/tanstack.d.ts.map +1 -0
  35. package/dist/tanstack.js +115 -0
  36. package/dist/tanstack.js.map +1 -0
  37. package/dist/views/MenuPage.d.ts +21 -6
  38. package/dist/views/MenuPage.d.ts.map +1 -1
  39. package/package.json +17 -2
  40. package/dist/chunk-V7CGLOEN.js.map +0 -1
@@ -1,9 +1,10 @@
1
+ import { Link, useStorefrontConfigOptional, useStorefrontConfig, useBlockData, BlockDataError, navigateTo, useRoutePath, toBlockNodes, defaultPageBlocks, PageDataScope, getStorefrontComponents, useLoader, currentStaticRenderPass, matchPath, translate, productSeo, StorefrontConfigProvider, mergePageTheme, pageThemeSelector, MENU_DATA_NEEDS, resolveConfig, useRouterAdapter, shellRouterAdapter, StorefrontRouterProvider, useScrollToTopOnNavigate, checkPageBlocks, normalizeLanguage, useHashPath, resolveStorefrontRoute, matchContentPage } from './chunk-2KCORAVB.js';
1
2
  import { create } from 'zustand';
2
3
  import { persist } from 'zustand/middleware';
3
- import { normalizePostalCode, getCountrySchema, lookupPostalCode, defaultRouterAdapter, defineLoader, staticRouterAdapter, isLoaderParamRef, isLoaderPropRef, resolveLoader, errorMessage, dataNeedKey, getBlockMeta, defaultPropsFromSettings, getBlockErrorVisibility, isBlockEnabledOn, checkBlockConstraints, checkBlockContext, repairBlockTree, renderBlocks, clearExtensionPoints, defineExtensionPoint, runExtensionPoint, runEscapeValve, breadcrumbJsonLd, hasEntityDeclaration, resolveEntityDeclaration, defineBlock, formatPostalCode, countryName, defineEntity, listEntityDeclarations, resolveHandle, seoOrigin, describeError, RESERVED_ENTITY_FIELDS, ENTITY_FIELD_TYPES, handleNameFor, registerHandle, validateAddress, hasHandle, listHandles, blockRegistry, loaderRegistry, listLoaders } from '@fayz-ai/core';
4
+ import { normalizePostalCode, getCountrySchema, lookupPostalCode, defineLoader, repairBlockTree, renderBlocks, clearExtensionPoints, defineExtensionPoint, runExtensionPoint, runEscapeValve, errorMessage, hasEntityDeclaration, resolveEntityDeclaration, defineBlock, formatPostalCode, countryName, defineEntity, defaultRouterAdapter, describeError, validateAddress } from '@fayz-ai/core';
4
5
  import { getShopProvider, setShopProvider } from '@fayz-ai/shop/runtime';
5
- import * as React39 from 'react';
6
- import React39__default, { createContext, useContext, useEffect, useRef, useState, useSyncExternalStore, useMemo, useCallback } from 'react';
6
+ import * as React36 from 'react';
7
+ import React36__default, { createContext, useRef, useState, useEffect, useMemo, useContext, useCallback } from 'react';
7
8
  import { createMockAuthAdapter } from '@fayz-ai/auth';
8
9
  import { createAuthRuntime } from '@fayz-ai/auth/lib/runtime';
9
10
  import { setShopCarrierQuotesResolver, setShopAccessTokenResolver, setShopShippingItemsResolver } from '@fayz-ai/sdk/shop';
@@ -11,16 +12,15 @@ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
11
12
  import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, supportsCard, formatDocument, isValidDocument, gatewayLabel, isValidCpf } from '@fayz-ai/shop';
12
13
  import { ChevronLeft, ChevronRight, ShoppingBag, X, Minus, Plus, Send, MessageCircle, Mail, Truck, RefreshCcw, ShieldCheck, ChevronDown, Check, Search, Menu, Trash2, MapPin, Lock, CreditCard, UserRound, Store, Bike, Clock, Pencil, Star, Phone, User, UserCircle, Package, LogOut, QrCode, Copy, XCircle, RotateCcw, PackageCheck, ChefHat, Info, AlertCircle } from 'lucide-react';
13
14
  import { getLucideIcon } from '@fayz-ai/ui/icons';
14
- import { storefrontDiscountToPromotion, previewCouponPercent, discountToPromotion, PROMOTION_TYPES, PROMOTION_STATUSES, APPLICATION_METHOD_TYPES, APPLICATION_METHOD_TARGET_TYPES, APPLICATION_METHOD_ALLOCATIONS, hasRuleAttribute, listRuleAttributeKeys, RULE_OPERATORS, resolveRuleAttribute } from '@fayz-ai/shop/rules';
15
+ import { storefrontDiscountToPromotion, previewCouponPercent, discountToPromotion } from '@fayz-ai/shop/rules';
15
16
  import { createMockShopProvider } from '@fayz-ai/shop/mock';
16
17
 
17
- // src/stores/market.store.ts
18
18
  var useMarketStore = create()((set) => ({
19
19
  markets: [],
20
20
  active: null,
21
21
  prices: {},
22
22
  setMarkets: (markets) => set({ markets }),
23
- setActive: (active2) => set({ active: active2 }),
23
+ setActive: (active) => set({ active }),
24
24
  setPrices: (code, list) => set((state) => ({
25
25
  prices: {
26
26
  ...state.prices,
@@ -698,19 +698,19 @@ function StorefrontAnalytics({ config, path }) {
698
698
  const metaPixel = pixelId && META_PIXEL_ID.test(pixelId) ? pixelId : null;
699
699
  const reporting = Boolean(posthog || metaPixel);
700
700
  const menuPath = config.delivery?.menuPath;
701
- const previous = React39.useRef(null);
702
- React39.useEffect(() => {
701
+ const previous = React36.useRef(null);
702
+ React36.useEffect(() => {
703
703
  if (!posthog) return;
704
704
  startStorefrontPostHog(posthog, { storeName: config.name, commerceMode: config.commerceMode });
705
705
  }, [posthog, config.name, config.commerceMode]);
706
- React39.useEffect(() => {
706
+ React36.useEffect(() => {
707
707
  if (!metaPixel) return;
708
708
  startStorefrontMetaPixel({ pixelId: metaPixel }, { currency: config.currency ?? "BRL" });
709
709
  }, [metaPixel, config.currency]);
710
- React39.useEffect(() => {
710
+ React36.useEffect(() => {
711
711
  if (metaPixel) trackMetaPageView();
712
712
  }, [metaPixel, path]);
713
- React39.useEffect(() => {
713
+ React36.useEffect(() => {
714
714
  if (!reporting) return;
715
715
  let ready = useCartStore.persist?.hasHydrated?.() ?? true;
716
716
  const unhydrated = useCartStore.persist?.onFinishHydration?.(() => {
@@ -741,7 +741,7 @@ function StorefrontAnalytics({ config, path }) {
741
741
  unhydrated?.();
742
742
  };
743
743
  }, [reporting]);
744
- React39.useEffect(() => {
744
+ React36.useEffect(() => {
745
745
  if (!reporting) return;
746
746
  const from = previous.current;
747
747
  previous.current = path;
@@ -1230,543 +1230,6 @@ function productPlaceholder(label, w = PLACEHOLDER_ASPECTS.product[0], h = PLACE
1230
1230
  function escapeXml(text) {
1231
1231
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
1232
1232
  }
1233
-
1234
- // src/locales/messages.ts
1235
- var ptBR = {
1236
- // Checkout shell
1237
- "checkout.title": "Checkout \u2014 {{store}}",
1238
- "checkout.backToStore": "Voltar \xE0 loja",
1239
- "checkout.secure": "Checkout seguro",
1240
- "checkout.help": "Ajuda",
1241
- "checkout.steps.label": "Etapas do checkout",
1242
- "checkout.steps.1": "Dados",
1243
- "checkout.steps.2": "Entrega",
1244
- "checkout.steps.3": "Pagamento",
1245
- "checkout.steps.4": "Pronto",
1246
- // Step 1 — contact
1247
- "checkout.contact.title": "Informa\xE7\xF5es de contato",
1248
- "checkout.contact.signedInAs": "Conectado como {{email}}",
1249
- "checkout.contact.edit": "Alterar",
1250
- "checkout.contact.notYou": "N\xE3o \xE9 voc\xEA?",
1251
- "checkout.contact.signOut": "Sair",
1252
- "checkout.contact.emailLocked": "O e-mail \xE9 o da sua conta.",
1253
- "checkout.contact.haveAccount": "J\xE1 tem conta? Entrar",
1254
- "checkout.contact.email": "E-mail",
1255
- "checkout.contact.name": "Nome completo",
1256
- "checkout.contact.phone": "Telefone",
1257
- "checkout.contact.phoneOptional": "Telefone (opcional)",
1258
- "checkout.contact.document": "CPF ou CNPJ",
1259
- "checkout.contact.documentOptional": "CPF ou CNPJ (opcional)",
1260
- "checkout.contact.requiresAccount": "Esta loja pede uma conta para finalizar a compra.",
1261
- "checkout.contact.signInOrCreate": "Entrar ou criar conta",
1262
- // Step 2 — address
1263
- "checkout.address.title": "Endere\xE7o de entrega",
1264
- "checkout.address.loadingSaved": "Buscando seus endere\xE7os salvos",
1265
- "checkout.address.selected": "Selecionado",
1266
- "checkout.address.addNew": "+ Adicionar novo endere\xE7o",
1267
- "checkout.address.enter": "Informe o endere\xE7o de entrega",
1268
- "checkout.address.enterHint": "Preencher outro endere\xE7o para esta compra",
1269
- "checkout.address.lookingUp": "Buscando o endere\xE7o deste CEP",
1270
- "checkout.address.notFound": "CEP n\xE3o encontrado \u2014 preencha o endere\xE7o \xE0 m\xE3o.",
1271
- "checkout.address.filled": "Preenchemos o endere\xE7o para voc\xEA.",
1272
- "checkout.address.regionFromPostal": "Prov\xEDncia preenchida pelo c\xF3digo postal.",
1273
- "checkout.address.optional": "{{label}} (opcional)",
1274
- "checkout.address.choose": "Selecione",
1275
- "checkout.address.shipTo": "Enviar para",
1276
- // Step 3 — payment
1277
- "checkout.confirming.title": "Confirmando seu pedido",
1278
- "checkout.confirming.label": "Criando seu pedido",
1279
- "checkout.confirming.keepOpen": "N\xE3o feche esta p\xE1gina \u2014 estamos registrando seu pedido na loja.",
1280
- "checkout.payment.title": "Pagamento",
1281
- "checkout.payment.label": "Forma de pagamento",
1282
- "checkout.payment.cardOnline": "Voc\xEA paga na p\xE1gina segura do provedor e volta para a loja",
1283
- "checkout.payment.placeOrder": "Fazer pedido - {{total}}",
1284
- "checkout.payment.pendingNote": "O pedido fica aguardando pagamento at\xE9 a loja confirmar.",
1285
- "checkout.payment.unavailableCountry": "Esta forma de pagamento n\xE3o est\xE1 dispon\xEDvel para {{country}}.",
1286
- "payment.pix.label": "Pix",
1287
- "payment.pix.hint": "Voc\xEA recebe a chave para pagar ap\xF3s confirmar o pedido",
1288
- "payment.credit_card.label": "Cart\xE3o de cr\xE9dito",
1289
- "payment.credit_card.hint": "Maquininha na entrega",
1290
- "payment.debit_card.label": "Cart\xE3o de d\xE9bito",
1291
- "payment.debit_card.hint": "Maquininha na entrega",
1292
- "payment.boleto.label": "Boleto",
1293
- "payment.boleto.hint": "Enviado por e-mail ap\xF3s a confirma\xE7\xE3o",
1294
- "payment.cash.label": "Dinheiro",
1295
- "payment.cash.hint": "Pagamento na entrega",
1296
- "payment.other.label": "Combinar com a loja",
1297
- "payment.other.hint": "A loja entra em contato para acertar o pagamento",
1298
- // Step 4
1299
- "checkout.done.title": "Pagamento confirmado!",
1300
- "checkout.done.text": "Seu pedido foi criado e a loja j\xE1 foi avisada.",
1301
- "checkout.done.viewOrder": "Ver meu pedido",
1302
- // Navigation
1303
- "checkout.continueToDelivery": "Continuar para a entrega",
1304
- "checkout.goToPayment": "Ir para o pagamento - {{total}}",
1305
- "checkout.backToContact": "Voltar aos dados",
1306
- "checkout.backToCart": "Voltar ao carrinho",
1307
- // Summary
1308
- "summary.title": "Resumo do pedido",
1309
- "summary.subtotal": "Subtotal",
1310
- "summary.discount": "Desconto",
1311
- "summary.delivery": "Entrega",
1312
- "summary.pickup": "Retirada na loja",
1313
- "summary.noFee": "Sem taxa",
1314
- "summary.free": "Gr\xE1tis",
1315
- "summary.total": "Total",
1316
- "summary.protected": "Compra protegida e dados criptografados.",
1317
- "summary.shipping": "Frete",
1318
- // Discount
1319
- "discount.placeholder": "Cupom de desconto",
1320
- "discount.apply": "Aplicar",
1321
- "discount.freeShipping": "frete gr\xE1tis",
1322
- "discount.percentOff": "{{percent}}% de desconto",
1323
- "discount.applied": "{{code}} aplicado: {{effect}}.",
1324
- "discount.appliedToast": "Cupom aplicado!",
1325
- "discount.invalid": "Cupom inv\xE1lido.",
1326
- "discount.invalidToast": "Cupom inv\xE1lido",
1327
- "discount.checkCode": "Verifique o c\xF3digo e tente novamente.",
1328
- "discount.cannotValidate": "N\xE3o conseguimos validar esse cupom agora.",
1329
- "discount.cannotValidateToast": "N\xE3o conseguimos validar o cupom",
1330
- "discount.tryLater": "Tente de novo em alguns instantes.",
1331
- // Legal
1332
- "legal.privacy": "Privacidade",
1333
- "legal.terms": "Termos",
1334
- "legal.refunds": "Trocas e devolu\xE7\xF5es",
1335
- // Validation
1336
- "error.requiresAccount": "Esta loja pede uma conta para finalizar a compra. Entre ou crie a sua.",
1337
- "error.email": "Informe um e-mail v\xE1lido.",
1338
- "error.name": "Informe seu nome completo.",
1339
- "error.phone": "Informe um telefone de contato.",
1340
- "error.documentInvalid": "CPF ou CNPJ inv\xE1lido \u2014 confira os n\xFAmeros.",
1341
- "error.documentMissing": "Informe o CPF ou CNPJ do comprador.",
1342
- "error.taxIdInvalid": "NIF/NIE inv\xE1lido \u2014 confira o n\xFAmero.",
1343
- "error.address": "Preencha ou selecione o endere\xE7o de entrega.",
1344
- "error.number": "Falta o n\xFAmero do endere\xE7o.",
1345
- "error.complement": "Informe o complemento (apto, bloco).",
1346
- "error.state": "Informe a UF com duas letras (ex.: RJ).",
1347
- "error.postalInvalid": "Confira o c\xF3digo postal (ex.: {{example}}).",
1348
- "error.region": "Selecione a {{label}}.",
1349
- "error.refusedZone": "Esta loja n\xE3o entrega nesse endere\xE7o. Tente outro.",
1350
- "error.unserved": "Ainda n\xE3o entregamos nesse CEP. Tente outro endere\xE7o.",
1351
- "error.sessionMismatch": "Sua sess\xE3o ficou presa a outro cadastro. Recarregue a p\xE1gina e tente de novo.",
1352
- "error.outOfStock": "Um item do carrinho ficou sem estoque. Revise o carrinho e tente de novo.",
1353
- "error.placeOrder": "N\xE3o foi poss\xEDvel concluir o pedido.",
1354
- // Delivery estimator
1355
- "delivery.title": "Calcular entrega",
1356
- "delivery.calculate": "Calcular",
1357
- "delivery.postalLabel": "CEP",
1358
- "delivery.change": "Trocar CEP",
1359
- "delivery.unserved": "Ainda n\xE3o entregamos nesse CEP.",
1360
- "delivery.refused": "Esta loja n\xE3o entrega nesse endere\xE7o.",
1361
- "delivery.review": "Entregamos nessa regi\xE3o, mas confirmamos com voc\xEA antes de sair.",
1362
- "delivery.etaSoon": "hoje ou amanh\xE3",
1363
- "delivery.etaRange": "{{min}} a {{max}} dias \xFAteis",
1364
- "delivery.etaDays": "{{days}} dia(s) \xFAtil(eis)",
1365
- "delivery.flatRate": "O frete \xE9 calculado no checkout.",
1366
- "delivery.error.digits": "Digite os 8 d\xEDgitos do CEP.",
1367
- "delivery.error.postal": "Confira o c\xF3digo postal (ex.: {{example}}).",
1368
- "delivery.error.quote": "N\xE3o foi poss\xEDvel calcular o frete agora. Tente de novo.",
1369
- "delivery.error.notFound": "CEP n\xE3o encontrado. Confira os n\xFAmeros.",
1370
- // Cart
1371
- "cart.title": "Carrinho",
1372
- "cart.close": "Fechar carrinho",
1373
- "cart.empty": "Seu carrinho est\xE1 vazio.",
1374
- "cart.remove": "Remover {{name}}",
1375
- "cart.checkout": "Finalizar compra",
1376
- "cart.missingForFree": "Faltam {{amount}} para frete gr\xE1tis",
1377
- "cart.wonFree": "Voc\xEA ganhou frete gr\xE1tis!",
1378
- "cart.minimumOrder": "Pedido m\xEDnimo para entrega: {{amount}}. Faltam {{missing}}.",
1379
- "delivery.eta": "Entrega em ~{{duration}}",
1380
- "delivery.etaUpTo": "Entrega em at\xE9 {{duration}}",
1381
- "delivery.paused": "Delivery fechado no momento",
1382
- "cart.deliveryPaused": "O delivery est\xE1 fechado no momento. Volte mais tarde para finalizar.",
1383
- // Deliver to
1384
- "country.deliverTo": "Enviar para",
1385
- "country.change": "Trocar pa\xEDs",
1386
- "country.label": "Pa\xEDs de entrega"
1387
- };
1388
- var en = {
1389
- "checkout.backToStore": "Back to store",
1390
- "checkout.secure": "Secure checkout",
1391
- "checkout.help": "Help",
1392
- "checkout.steps.label": "Checkout steps",
1393
- "checkout.steps.1": "Details",
1394
- "checkout.steps.2": "Delivery",
1395
- "checkout.steps.3": "Payment",
1396
- "checkout.steps.4": "Done",
1397
- "checkout.contact.title": "Contact information",
1398
- "checkout.contact.signedInAs": "Signed in as {{email}}",
1399
- "checkout.contact.edit": "Change",
1400
- "checkout.contact.notYou": "Not you?",
1401
- "checkout.contact.signOut": "Sign out",
1402
- "checkout.contact.emailLocked": "This is your account e-mail.",
1403
- "checkout.contact.haveAccount": "Have an account? Sign in",
1404
- "checkout.contact.email": "Email",
1405
- "checkout.contact.name": "Full name",
1406
- "checkout.contact.phone": "Phone",
1407
- "checkout.contact.phoneOptional": "Phone (optional)",
1408
- "checkout.contact.document": "Tax ID",
1409
- "checkout.contact.documentOptional": "Tax ID (optional)",
1410
- "checkout.contact.requiresAccount": "This store needs an account to complete the purchase.",
1411
- "checkout.contact.signInOrCreate": "Sign in or create an account",
1412
- "checkout.address.title": "Delivery address",
1413
- "checkout.address.loadingSaved": "Loading your saved addresses",
1414
- "checkout.address.selected": "Selected",
1415
- "checkout.address.addNew": "+ Add a new address",
1416
- "checkout.address.enter": "Enter the delivery address",
1417
- "checkout.address.enterHint": "Use a different address for this order",
1418
- "checkout.address.lookingUp": "Looking up this postal code",
1419
- "checkout.address.notFound": "Postal code not found \u2014 fill in the address by hand.",
1420
- "checkout.address.filled": "We filled in the address for you.",
1421
- "checkout.address.regionFromPostal": "Province filled in from the postcode.",
1422
- "checkout.address.optional": "{{label}} (optional)",
1423
- "checkout.address.choose": "Select",
1424
- "checkout.address.shipTo": "Ship to",
1425
- "checkout.confirming.title": "Confirming your order",
1426
- "checkout.confirming.label": "Creating your order",
1427
- "checkout.confirming.keepOpen": "Don\u2019t close this page \u2014 we\u2019re registering your order with the store.",
1428
- "checkout.payment.title": "Payment",
1429
- "checkout.payment.label": "Payment method",
1430
- "checkout.payment.cardOnline": "You pay on the provider\u2019s secure page and come back to the store",
1431
- "checkout.payment.placeOrder": "Place order - {{total}}",
1432
- "checkout.payment.pendingNote": "The order awaits payment until the store confirms it.",
1433
- "checkout.payment.unavailableCountry": "This payment method isn\u2019t available for {{country}}.",
1434
- "payment.pix.hint": "You get the key to pay after confirming the order",
1435
- "payment.credit_card.label": "Credit card",
1436
- "payment.credit_card.hint": "Card machine on delivery",
1437
- "payment.debit_card.label": "Debit card",
1438
- "payment.debit_card.hint": "Card machine on delivery",
1439
- "payment.boleto.hint": "Sent by email after confirmation",
1440
- "payment.cash.label": "Cash",
1441
- "payment.cash.hint": "Pay on delivery",
1442
- "payment.other.label": "Arrange with the store",
1443
- "payment.other.hint": "The store will contact you to arrange payment",
1444
- "checkout.done.title": "Payment confirmed!",
1445
- "checkout.done.text": "Your order was created and the store has been notified.",
1446
- "checkout.done.viewOrder": "View my order",
1447
- "checkout.continueToDelivery": "Continue to delivery",
1448
- "checkout.goToPayment": "Go to payment - {{total}}",
1449
- "checkout.backToContact": "Back to details",
1450
- "checkout.backToCart": "Back to cart",
1451
- "summary.title": "Order summary",
1452
- "summary.discount": "Discount",
1453
- "summary.delivery": "Delivery",
1454
- "summary.pickup": "Store pickup",
1455
- "summary.noFee": "No fee",
1456
- "summary.free": "Free",
1457
- "summary.protected": "Protected purchase, encrypted data.",
1458
- "summary.shipping": "Shipping",
1459
- "discount.placeholder": "Discount code",
1460
- "discount.apply": "Apply",
1461
- "discount.freeShipping": "free shipping",
1462
- "discount.percentOff": "{{percent}}% off",
1463
- "discount.applied": "{{code}} applied: {{effect}}.",
1464
- "discount.appliedToast": "Code applied!",
1465
- "discount.invalid": "Invalid code.",
1466
- "discount.invalidToast": "Invalid code",
1467
- "discount.checkCode": "Check the code and try again.",
1468
- "discount.cannotValidate": "We couldn\u2019t check this code right now.",
1469
- "discount.cannotValidateToast": "We couldn\u2019t check the code",
1470
- "discount.tryLater": "Try again in a moment.",
1471
- "legal.privacy": "Privacy",
1472
- "legal.terms": "Terms",
1473
- "legal.refunds": "Returns",
1474
- "error.requiresAccount": "This store needs an account to complete the purchase. Sign in or create one.",
1475
- "error.email": "Enter a valid email.",
1476
- "error.name": "Enter your full name.",
1477
- "error.phone": "Enter a contact phone number.",
1478
- "error.documentInvalid": "Invalid tax ID \u2014 check the numbers.",
1479
- "error.documentMissing": "Enter the buyer\u2019s tax ID.",
1480
- "error.taxIdInvalid": "Invalid NIF/NIE \u2014 check the number.",
1481
- "error.address": "Fill in or select the delivery address.",
1482
- "error.number": "The street number is missing.",
1483
- "error.complement": "Enter the apartment or unit.",
1484
- "error.state": "Enter the two-letter state code (e.g. RJ).",
1485
- "error.postalInvalid": "Check the postal code (e.g. {{example}}).",
1486
- "error.region": "Select the {{label}}.",
1487
- "error.refusedZone": "This store doesn\u2019t deliver to this address. Try another.",
1488
- "error.unserved": "We don\u2019t deliver to this postal code yet. Try another address.",
1489
- "error.sessionMismatch": "Your session got attached to another account. Reload the page and try again.",
1490
- "error.outOfStock": "An item in your cart is out of stock. Review the cart and try again.",
1491
- "error.placeOrder": "We couldn\u2019t complete the order.",
1492
- "delivery.title": "Estimate delivery",
1493
- "delivery.calculate": "Estimate",
1494
- "delivery.postalLabel": "Postal code",
1495
- "delivery.change": "Change postal code",
1496
- "delivery.unserved": "We don\u2019t deliver to this postal code yet.",
1497
- "delivery.refused": "This store doesn\u2019t deliver to this address.",
1498
- "delivery.review": "We deliver to this area, but we\u2019ll confirm with you before shipping.",
1499
- "delivery.etaSoon": "today or tomorrow",
1500
- "delivery.etaRange": "{{min}} to {{max}} business days",
1501
- "delivery.etaDays": "{{days}} business day(s)",
1502
- "delivery.flatRate": "Shipping is calculated at checkout.",
1503
- "delivery.error.digits": "Enter all 8 digits of the CEP.",
1504
- "delivery.error.postal": "Check the postal code (e.g. {{example}}).",
1505
- "delivery.error.quote": "We couldn\u2019t calculate shipping right now. Try again.",
1506
- "delivery.error.notFound": "Postal code not found. Check the numbers.",
1507
- "cart.title": "Cart",
1508
- "cart.close": "Close cart",
1509
- "cart.empty": "Your cart is empty.",
1510
- "cart.remove": "Remove {{name}}",
1511
- "cart.checkout": "Checkout",
1512
- "cart.missingForFree": "{{amount}} away from free shipping",
1513
- "cart.wonFree": "You got free shipping!",
1514
- "cart.minimumOrder": "Minimum order for delivery: {{amount}}. {{missing}} to go.",
1515
- "delivery.eta": "Delivery in ~{{duration}}",
1516
- "delivery.etaUpTo": "Delivery within {{duration}}",
1517
- "delivery.paused": "Delivery closed right now",
1518
- "cart.deliveryPaused": "Delivery is closed right now. Come back later to check out.",
1519
- "country.deliverTo": "Deliver to",
1520
- "country.change": "Change country",
1521
- "country.label": "Delivery country"
1522
- };
1523
- var es = {
1524
- "checkout.backToStore": "Volver a la tienda",
1525
- "checkout.secure": "Pago seguro",
1526
- "checkout.help": "Ayuda",
1527
- "checkout.steps.label": "Pasos del pago",
1528
- "checkout.steps.1": "Datos",
1529
- "checkout.steps.2": "Env\xEDo",
1530
- "checkout.steps.3": "Pago",
1531
- "checkout.steps.4": "Listo",
1532
- "checkout.contact.title": "Datos de contacto",
1533
- "checkout.contact.signedInAs": "Has iniciado sesi\xF3n como {{email}}",
1534
- "checkout.contact.edit": "Cambiar",
1535
- "checkout.contact.notYou": "\xBFNo eres t\xFA?",
1536
- "checkout.contact.signOut": "Salir",
1537
- "checkout.contact.emailLocked": "Es el correo de tu cuenta.",
1538
- "checkout.contact.haveAccount": "\xBFYa tienes cuenta? Entrar",
1539
- "checkout.contact.email": "Email",
1540
- "checkout.contact.name": "Nombre completo",
1541
- "checkout.contact.phone": "Tel\xE9fono",
1542
- "checkout.contact.phoneOptional": "Tel\xE9fono (opcional)",
1543
- "checkout.contact.document": "NIF/NIE",
1544
- "checkout.contact.documentOptional": "NIF/NIE (opcional)",
1545
- "checkout.contact.requiresAccount": "Esta tienda pide una cuenta para finalizar la compra.",
1546
- "checkout.contact.signInOrCreate": "Entrar o crear cuenta",
1547
- "checkout.address.title": "Direcci\xF3n de env\xEDo",
1548
- "checkout.address.loadingSaved": "Buscando tus direcciones guardadas",
1549
- "checkout.address.selected": "Seleccionada",
1550
- "checkout.address.addNew": "+ A\xF1adir una direcci\xF3n nueva",
1551
- "checkout.address.enter": "Indica la direcci\xF3n de env\xEDo",
1552
- "checkout.address.enterHint": "Usar otra direcci\xF3n para este pedido",
1553
- "checkout.address.lookingUp": "Buscando este c\xF3digo postal",
1554
- "checkout.address.notFound": "C\xF3digo postal no encontrado: rellena la direcci\xF3n a mano.",
1555
- "checkout.address.filled": "Hemos rellenado la direcci\xF3n por ti.",
1556
- "checkout.address.regionFromPostal": "Provincia rellenada a partir del c\xF3digo postal.",
1557
- "checkout.address.optional": "{{label}} (opcional)",
1558
- "checkout.address.choose": "Selecciona",
1559
- "checkout.address.shipTo": "Enviar a",
1560
- "checkout.confirming.title": "Confirmando tu pedido",
1561
- "checkout.confirming.label": "Creando tu pedido",
1562
- "checkout.confirming.keepOpen": "No cierres esta p\xE1gina: estamos registrando tu pedido en la tienda.",
1563
- "checkout.payment.title": "Pago",
1564
- "checkout.payment.label": "Forma de pago",
1565
- "checkout.payment.cardOnline": "Pagas en la p\xE1gina segura del proveedor y vuelves a la tienda",
1566
- "checkout.payment.placeOrder": "Hacer pedido - {{total}}",
1567
- "checkout.payment.pendingNote": "El pedido queda pendiente de pago hasta que la tienda lo confirme.",
1568
- "checkout.payment.unavailableCountry": "Esta forma de pago no est\xE1 disponible para {{country}}.",
1569
- "payment.pix.hint": "Recibes la clave para pagar al confirmar el pedido",
1570
- "payment.credit_card.label": "Tarjeta de cr\xE9dito",
1571
- "payment.credit_card.hint": "Dat\xE1fono en la entrega",
1572
- "payment.debit_card.label": "Tarjeta de d\xE9bito",
1573
- "payment.debit_card.hint": "Dat\xE1fono en la entrega",
1574
- "payment.boleto.hint": "Enviado por email tras la confirmaci\xF3n",
1575
- "payment.cash.label": "Efectivo",
1576
- "payment.cash.hint": "Pago en la entrega",
1577
- "payment.other.label": "Acordar con la tienda",
1578
- "payment.other.hint": "La tienda te contactar\xE1 para acordar el pago",
1579
- "checkout.done.title": "\xA1Pago confirmado!",
1580
- "checkout.done.text": "Tu pedido se ha creado y la tienda ya ha sido avisada.",
1581
- "checkout.done.viewOrder": "Ver mi pedido",
1582
- "checkout.continueToDelivery": "Continuar al env\xEDo",
1583
- "checkout.goToPayment": "Ir al pago - {{total}}",
1584
- "checkout.backToContact": "Volver a los datos",
1585
- "checkout.backToCart": "Volver al carrito",
1586
- "summary.title": "Resumen del pedido",
1587
- "summary.discount": "Descuento",
1588
- "summary.delivery": "Env\xEDo",
1589
- "summary.pickup": "Recogida en tienda",
1590
- "summary.noFee": "Sin coste",
1591
- "summary.free": "Gratis",
1592
- "summary.protected": "Compra protegida y datos cifrados.",
1593
- "summary.shipping": "Env\xEDo",
1594
- "discount.placeholder": "C\xF3digo de descuento",
1595
- "discount.apply": "Aplicar",
1596
- "discount.freeShipping": "env\xEDo gratis",
1597
- "discount.percentOff": "{{percent}}% de descuento",
1598
- "discount.applied": "{{code}} aplicado: {{effect}}.",
1599
- "discount.appliedToast": "\xA1C\xF3digo aplicado!",
1600
- "discount.invalid": "C\xF3digo no v\xE1lido.",
1601
- "discount.invalidToast": "C\xF3digo no v\xE1lido",
1602
- "discount.checkCode": "Revisa el c\xF3digo e int\xE9ntalo de nuevo.",
1603
- "discount.cannotValidate": "No hemos podido validar este c\xF3digo ahora.",
1604
- "discount.cannotValidateToast": "No hemos podido validar el c\xF3digo",
1605
- "discount.tryLater": "Int\xE9ntalo de nuevo en unos instantes.",
1606
- "legal.privacy": "Privacidad",
1607
- "legal.terms": "T\xE9rminos",
1608
- "legal.refunds": "Devoluciones",
1609
- "error.requiresAccount": "Esta tienda pide una cuenta para finalizar la compra. Entra o crea la tuya.",
1610
- "error.email": "Indica un email v\xE1lido.",
1611
- "error.name": "Indica tu nombre completo.",
1612
- "error.phone": "Indica un tel\xE9fono de contacto.",
1613
- "error.documentInvalid": "Documento no v\xE1lido: revisa los n\xFAmeros.",
1614
- "error.documentMissing": "Indica el documento del comprador.",
1615
- "error.taxIdInvalid": "NIF/NIE no v\xE1lido: revisa el n\xFAmero.",
1616
- "error.address": "Rellena o selecciona la direcci\xF3n de env\xEDo.",
1617
- "error.number": "Falta el n\xFAmero de la direcci\xF3n.",
1618
- "error.complement": "Indica el piso o la puerta.",
1619
- "error.state": "Indica el estado con dos letras (ej.: RJ).",
1620
- "error.postalInvalid": "Revisa el c\xF3digo postal (ej.: {{example}}).",
1621
- "error.region": "Selecciona la {{label}}.",
1622
- "error.refusedZone": "Esta tienda no env\xEDa a esta direcci\xF3n. Prueba con otra.",
1623
- "error.unserved": "Todav\xEDa no enviamos a este c\xF3digo postal. Prueba con otra direcci\xF3n.",
1624
- "error.sessionMismatch": "Tu sesi\xF3n qued\xF3 vinculada a otra cuenta. Recarga la p\xE1gina e int\xE9ntalo de nuevo.",
1625
- "error.outOfStock": "Un producto del carrito se ha agotado. Revisa el carrito e int\xE9ntalo de nuevo.",
1626
- "error.placeOrder": "No se ha podido completar el pedido.",
1627
- "delivery.title": "Calcular env\xEDo",
1628
- "delivery.calculate": "Calcular",
1629
- "delivery.postalLabel": "C\xF3digo postal",
1630
- "delivery.change": "Cambiar c\xF3digo postal",
1631
- "delivery.unserved": "Todav\xEDa no enviamos a este c\xF3digo postal.",
1632
- "delivery.refused": "Esta tienda no env\xEDa a esta direcci\xF3n.",
1633
- "delivery.review": "Enviamos a esta zona, pero lo confirmamos contigo antes de salir.",
1634
- "delivery.etaSoon": "hoy o ma\xF1ana",
1635
- "delivery.etaRange": "de {{min}} a {{max}} d\xEDas laborables",
1636
- "delivery.etaDays": "{{days}} d\xEDa(s) laborable(s)",
1637
- "delivery.flatRate": "El env\xEDo se calcula en el pago.",
1638
- "delivery.error.digits": "Escribe los 8 d\xEDgitos del CEP.",
1639
- "delivery.error.postal": "Revisa el c\xF3digo postal (ej.: {{example}}).",
1640
- "delivery.error.quote": "No hemos podido calcular el env\xEDo ahora. Int\xE9ntalo de nuevo.",
1641
- "delivery.error.notFound": "C\xF3digo postal no encontrado. Revisa los n\xFAmeros.",
1642
- "cart.title": "Carrito",
1643
- "cart.close": "Cerrar carrito",
1644
- "cart.empty": "Tu carrito est\xE1 vac\xEDo.",
1645
- "cart.remove": "Quitar {{name}}",
1646
- "cart.checkout": "Finalizar compra",
1647
- "cart.missingForFree": "Te faltan {{amount}} para el env\xEDo gratis",
1648
- "cart.wonFree": "\xA1Tienes env\xEDo gratis!",
1649
- "cart.minimumOrder": "Pedido m\xEDnimo para entrega: {{amount}}. Te faltan {{missing}}.",
1650
- "delivery.eta": "Entrega en ~{{minutes}} min",
1651
- "country.deliverTo": "Enviar a",
1652
- "country.change": "Cambiar pa\xEDs",
1653
- "country.label": "Pa\xEDs de env\xEDo"
1654
- };
1655
- var MESSAGES = { "pt-BR": ptBR, en, es };
1656
- function normalizeLanguage(value) {
1657
- const base = (value || "").toLowerCase().split(/[-_]/)[0];
1658
- if (base === "pt") return "pt-BR";
1659
- if (base === "en") return "en";
1660
- if (base === "es") return "es";
1661
- return null;
1662
- }
1663
- function translate(language, key, vars, overrides) {
1664
- let text = overrides?.[language]?.[key] ?? MESSAGES[language]?.[key] ?? overrides?.["pt-BR"]?.[key] ?? ptBR[key];
1665
- if (vars) for (const [name, value] of Object.entries(vars)) text = text.split(`{{${name}}}`).join(String(value));
1666
- return text;
1667
- }
1668
- function resolveCountries(config) {
1669
- const countries = [...new Set((config.countries ?? []).map((c) => c.trim().toUpperCase()).filter(Boolean))];
1670
- if (countries.length === 0) countries.push("BR");
1671
- const wanted = config.defaultCountry?.trim().toUpperCase();
1672
- return { countries, defaultCountry: wanted && countries.includes(wanted) ? wanted : countries[0] };
1673
- }
1674
- function resolveConfig(config) {
1675
- const homePage = config.pages?.home ?? (config.home ? { blocks: config.home.sections } : void 0);
1676
- const commerceMode = config.commerceMode ?? "checkout";
1677
- const catalogPath = commerceMode === "delivery" ? config.delivery?.menuPath ?? "/menu" : homePage ? "/catalog" : "/";
1678
- const checkoutEnabled = commerceMode === "checkout" || commerceMode === "delivery";
1679
- return {
1680
- ...config,
1681
- pages: { ...config.pages, ...homePage ? { home: homePage } : {} },
1682
- currency: config.currency ?? "BRL",
1683
- locale: config.locale ?? "pt-BR",
1684
- language: normalizeLanguage(config.language) ?? "pt-BR",
1685
- ...resolveCountries(config),
1686
- shipping: { flatRate: config.shipping?.flatRate ?? 0, freeAbove: config.shipping?.freeAbove },
1687
- payments: {
1688
- mode: config.payments?.mode ?? "mock",
1689
- methods: config.payments?.methods?.length ? config.payments.methods : ["pix", "credit_card", "cash"],
1690
- // Rebuilding `payments` key by key silently dropped `terms`, so the Pix
1691
- // price and the instalment line never reached a component even when the
1692
- // store had configured them.
1693
- terms: config.payments?.terms
1694
- },
1695
- commerceMode,
1696
- // Só existe no modo delivery. Fora dele o objeto inteiro é undefined, e é
1697
- // isso que a rota /menu consulta para decidir se existe.
1698
- delivery: commerceMode === "delivery" ? {
1699
- menuPath: config.delivery?.menuPath ?? "/menu",
1700
- coverImage: config.delivery?.coverImage,
1701
- logoImage: config.delivery?.logoImage,
1702
- locality: config.delivery?.locality,
1703
- highlightSlugs: config.delivery?.highlightSlugs,
1704
- // A ORDEM é a do seletor na tela. Um Set aqui perderia isso.
1705
- fulfillmentModes: config.delivery?.fulfillmentModes?.length ? config.delivery.fulfillmentModes : ["delivery"].slice(),
1706
- // Agendamento é opt-in duas vezes: aqui e na loja (0094 devolve zero
1707
- // slots quando scheduling_enabled é falso). A tela só oferece quando
1708
- // as duas concordam.
1709
- scheduling: config.delivery?.scheduling ?? false,
1710
- pickupAddress: config.delivery?.pickupAddress
1711
- } : void 0,
1712
- enquiry: {
1713
- label: config.enquiry?.label ?? "Contact me",
1714
- successMessage: config.enquiry?.successMessage ?? "Thanks. We received your enquiry.",
1715
- subjectPrefix: config.enquiry?.subjectPrefix ?? "Product enquiry",
1716
- email: config.enquiry?.email,
1717
- whatsappUrl: config.enquiry?.whatsappUrl,
1718
- requirePhone: config.enquiry?.requirePhone
1719
- },
1720
- features: {
1721
- // Auto-enable the coupon UI when the store actually ships discount codes
1722
- // (config.discounts, a seeded catalog, or a rule-engine promotion with a
1723
- // code — M6), unless explicitly overridden — otherwise a store can
1724
- // advertise a coupon with no field to enter it, which is exactly the
1725
- // figurinhas pilot failure this milestone exists to end.
1726
- discounts: config.features?.discounts ?? Boolean(
1727
- config.discounts?.length || config.catalog?.discounts?.length || config.promotions?.some((p) => p.code) || config.catalog?.promotions?.some((p) => p.code)
1728
- ),
1729
- accounts: config.features?.accounts ?? checkoutEnabled,
1730
- cart: config.features?.cart ?? checkoutEnabled,
1731
- checkout: config.features?.checkout ?? checkoutEnabled
1732
- },
1733
- imageLoading: {
1734
- mode: config.imageLoading?.mode ?? "fade",
1735
- durationMs: config.imageLoading?.durationMs ?? 420,
1736
- easing: config.imageLoading?.easing ?? "cubic-bezier(0.22, 1, 0.36, 1)",
1737
- blur: config.imageLoading?.blur ?? true,
1738
- transform: config.imageLoading?.transform ?? "none"
1739
- },
1740
- catalogPath,
1741
- search: {
1742
- mode: config.search?.mode ?? "inline",
1743
- placeholder: config.search?.placeholder ?? "Buscar produtos...",
1744
- resultsPath: config.search?.resultsPath ?? "/search",
1745
- suggestionsLimit: config.search?.suggestionsLimit ?? 4,
1746
- minChars: config.search?.minChars ?? 2,
1747
- ctaLabel: config.search?.ctaLabel ?? "Ver todos resultados",
1748
- emptyLabel: config.search?.emptyLabel ?? "Nada encontrado para",
1749
- renderSuggestion: config.search?.renderSuggestion
1750
- },
1751
- nav: config.nav ?? (homePage ? [
1752
- { label: "In\xEDcio", to: "/" },
1753
- { label: "Loja", to: "/catalog" }
1754
- ] : [{ label: "Loja", to: "/" }])
1755
- };
1756
- }
1757
- var StorefrontConfigContext = createContext(null);
1758
- var StorefrontConfigProvider = StorefrontConfigContext.Provider;
1759
- function useStorefrontConfig() {
1760
- const ctx = useContext(StorefrontConfigContext);
1761
- if (!ctx) throw new Error("useStorefrontConfig must be used inside createStorefrontApp");
1762
- return ctx;
1763
- }
1764
- function useStorefrontConfigOptional() {
1765
- return useContext(StorefrontConfigContext);
1766
- }
1767
- function getStorefrontComponents(config) {
1768
- return config.components ?? {};
1769
- }
1770
1233
  function prefersReducedMotion() {
1771
1234
  if (typeof window === "undefined" || !window.matchMedia) return false;
1772
1235
  return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
@@ -1858,84 +1321,6 @@ function usePopOnChange(value) {
1858
1321
  });
1859
1322
  return pop;
1860
1323
  }
1861
- var RouterAdapterContext = createContext(null);
1862
- var StorefrontRouterProvider = RouterAdapterContext.Provider;
1863
- var _activeAdapter = null;
1864
- var _fallback = null;
1865
- function fallbackAdapter() {
1866
- if (!_fallback) _fallback = defaultRouterAdapter("hash");
1867
- return _fallback;
1868
- }
1869
- function useRouterAdapter() {
1870
- const injected = useContext(RouterAdapterContext);
1871
- const adapter = injected ?? fallbackAdapter();
1872
- useEffect(() => {
1873
- if (injected) _activeAdapter = injected;
1874
- }, [injected]);
1875
- return adapter;
1876
- }
1877
- function useRoutePath() {
1878
- const adapter = useRouterAdapter();
1879
- return useSyncExternalStore(
1880
- (onChange) => adapter.onPathChange(onChange),
1881
- () => adapter.getCurrentPath() || "/",
1882
- () => adapter.getCurrentPath() || "/"
1883
- );
1884
- }
1885
- function useScrollToTopOnNavigate(path) {
1886
- const mounted = useRef(false);
1887
- useEffect(() => {
1888
- if (!mounted.current) {
1889
- mounted.current = true;
1890
- return;
1891
- }
1892
- if (typeof window !== "undefined") window.scrollTo(0, 0);
1893
- }, [path]);
1894
- }
1895
- function useNavigate() {
1896
- const adapter = useRouterAdapter();
1897
- return adapter.navigate.bind(adapter);
1898
- }
1899
- var useHashPath = useRoutePath;
1900
- function navigateTo(to) {
1901
- (_activeAdapter ?? fallbackAdapter()).navigate(to);
1902
- }
1903
- function shellRouterAdapter(pathOverride, live) {
1904
- if (pathOverride == null) return live;
1905
- return staticRouterAdapter(pathOverride, { href: (to) => live.href(to) });
1906
- }
1907
- function matchPath(pattern, path) {
1908
- const cleanPath = (path.split("?")[0] ?? "").replace(/\/+$/, "") || "/";
1909
- const patternParts = pattern.split("/").filter(Boolean);
1910
- const pathParts = cleanPath.split("/").filter(Boolean);
1911
- if (patternParts.length !== pathParts.length) return null;
1912
- const params = {};
1913
- for (let i = 0; i < patternParts.length; i++) {
1914
- const pat = patternParts[i];
1915
- const part = pathParts[i];
1916
- if (pat.startsWith(":")) params[pat.slice(1)] = decodeURIComponent(part);
1917
- else if (pat !== part) return null;
1918
- }
1919
- return params;
1920
- }
1921
- function Link({ to, children, onClick, target, ...rest }) {
1922
- const adapter = useRouterAdapter();
1923
- const handleClick = (event) => {
1924
- onClick?.(event);
1925
- if (!adapter.interceptsLinkClicks) return;
1926
- if (event.defaultPrevented) return;
1927
- if (target && target !== "_self") return;
1928
- if (event.button !== 0) return;
1929
- if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
1930
- event.preventDefault();
1931
- adapter.navigate(to);
1932
- };
1933
- return React39__default.createElement(
1934
- "a",
1935
- { href: adapter.href(to), onClick: handleClick, target, ...rest },
1936
- children
1937
- );
1938
- }
1939
1324
 
1940
1325
  // src/lib/testids.ts
1941
1326
  var TID = {
@@ -2170,9 +1555,9 @@ function SmoothImage({
2170
1555
  const easing = resolved.easing ?? "cubic-bezier(0.22, 1, 0.36, 1)";
2171
1556
  const blur = resolved.blur ?? true;
2172
1557
  const transform = resolved.transform ?? "none";
2173
- const ref = React39__default.useRef(null);
2174
- const [loaded, setLoaded] = React39__default.useState(() => mode === "none" || !clientMounted);
2175
- const delivered = React39__default.useMemo(() => {
1558
+ const ref = React36__default.useRef(null);
1559
+ const [loaded, setLoaded] = React36__default.useState(() => mode === "none" || !clientMounted);
1560
+ const delivered = React36__default.useMemo(() => {
2176
1561
  if (transform !== "supabase" || !src || srcSet || !isStorageImageUrl(src)) return { src, srcSet, sizes };
2177
1562
  if (variant?.width) {
2178
1563
  const w = variant.width;
@@ -2190,10 +1575,10 @@ function SmoothImage({
2190
1575
  sizes: variant?.sizes ?? sizes ?? "100vw"
2191
1576
  };
2192
1577
  }, [transform, src, srcSet, sizes, variant?.width, variant?.sizes, variant?.widths, variant?.quality]);
2193
- React39__default.useEffect(() => {
1578
+ React36__default.useEffect(() => {
2194
1579
  clientMounted = true;
2195
1580
  }, []);
2196
- React39__default.useEffect(() => {
1581
+ React36__default.useEffect(() => {
2197
1582
  if (mode === "none") {
2198
1583
  setLoaded(true);
2199
1584
  return;
@@ -2227,8 +1612,8 @@ function SmoothImage({
2227
1612
  function slideImage(slide, w = 1600, h = 700) {
2228
1613
  return slide.image ?? bannerPlaceholder(slide.title, slide.hue ?? 200, (slide.hue ?? 200) + 40, w, h);
2229
1614
  }
2230
- function SlideCopy({ slide, active: active2 }) {
2231
- const stagger = (i) => active2 ? { className: "animate-fade-up", style: { animationDelay: `${i * 120}ms` } } : { className: "opacity-0" };
1615
+ function SlideCopy({ slide, active }) {
1616
+ const stagger = (i) => active ? { className: "animate-fade-up", style: { animationDelay: `${i * 120}ms` } } : { className: "opacity-0" };
2232
1617
  const inner = /* @__PURE__ */ jsxs(Fragment, { children: [
2233
1618
  /* @__PURE__ */ jsx("h2", { className: `sf-heading text-3xl font-bold leading-tight tracking-tight sm:text-5xl ${stagger(0).className}`, style: stagger(0).style, children: slide.title }),
2234
1619
  slide.subtitle && /* @__PURE__ */ jsx("p", { className: `mt-3 max-w-md text-base sm:text-lg ${stagger(1).className}`, style: stagger(1).style, children: slide.subtitle }),
@@ -2309,7 +1694,7 @@ function HeroSection({
2309
1694
  i
2310
1695
  )) });
2311
1696
  }
2312
- const active2 = slides[Math.min(index, slides.length - 1)];
1697
+ const active = slides[Math.min(index, slides.length - 1)];
2313
1698
  return /* @__PURE__ */ jsxs("section", { "data-testid": TID.hero, className: `relative w-full overflow-hidden ${hClass}`, children: [
2314
1699
  slides.map((slide, i) => /* @__PURE__ */ jsx(
2315
1700
  "img",
@@ -2328,8 +1713,8 @@ function HeroSection({
2328
1713
  /* @__PURE__ */ jsx(
2329
1714
  "div",
2330
1715
  {
2331
- className: `absolute inset-0 flex items-end p-6 sm:p-12 ${active2.boxed ? "" : "bg-gradient-to-t from-black/60 via-black/20 to-transparent"}`,
2332
- children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-7xl", children: /* @__PURE__ */ jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsx(SlideCopy, { slide: active2, active: true }, index) }) })
1716
+ className: `absolute inset-0 flex items-end p-6 sm:p-12 ${active.boxed ? "" : "bg-gradient-to-t from-black/60 via-black/20 to-transparent"}`,
1717
+ children: /* @__PURE__ */ jsx("div", { className: "mx-auto w-full max-w-7xl", children: /* @__PURE__ */ jsx("div", { className: "max-w-xl", children: /* @__PURE__ */ jsx(SlideCopy, { slide: active, active: true }, index) }) })
2333
1718
  }
2334
1719
  ),
2335
1720
  variant === "slider" && slides.length > 1 && /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -2495,196 +1880,6 @@ var useCatalogStore = create()((set) => ({
2495
1880
  setSort: (sort) => set({ sort }),
2496
1881
  reset: () => set(initial)
2497
1882
  }));
2498
-
2499
- // src/app/static-render.ts
2500
- var active = null;
2501
- function currentStaticRenderPass() {
2502
- return active;
2503
- }
2504
- function withStaticRenderPass(pass, render) {
2505
- const previous = active;
2506
- active = pass;
2507
- try {
2508
- return render();
2509
- } finally {
2510
- active = previous;
2511
- }
2512
- }
2513
- function resolveDataParams(need, context) {
2514
- const out = {};
2515
- for (const [name, value] of Object.entries(need.params ?? {})) {
2516
- let resolved = value;
2517
- if (isLoaderParamRef(value)) resolved = context.params[value.$param];
2518
- else if (isLoaderPropRef(value)) resolved = context.props[value.$prop];
2519
- if (resolved !== void 0) out[name] = resolved;
2520
- }
2521
- return out;
2522
- }
2523
- function needsForNode(node) {
2524
- const meta = getBlockMeta(node.type);
2525
- return { ...meta?.data, ...node.data };
2526
- }
2527
- function collectDataNeeds(nodes, routeParams = {}) {
2528
- const found = /* @__PURE__ */ new Map();
2529
- const visit = (node) => {
2530
- const meta = getBlockMeta(node.type);
2531
- const needs = needsForNode(node);
2532
- if (Object.keys(needs).length > 0) {
2533
- const props = { ...defaultPropsFromSettings(meta?.settings), ...node.props };
2534
- for (const need of Object.values(needs)) {
2535
- if (!need || typeof need.loader !== "string" || !need.loader) continue;
2536
- const params = resolveDataParams(need, { params: routeParams, props });
2537
- const key = dataNeedKey(need.loader, params);
2538
- if (!found.has(key)) found.set(key, { key, loader: need.loader, params });
2539
- }
2540
- }
2541
- for (const child of node.children ?? []) visit(child);
2542
- };
2543
- for (const node of nodes) visit(node);
2544
- return [...found.values()];
2545
- }
2546
- async function resolvePageDataNeed(need) {
2547
- try {
2548
- const impl = resolveLoader(need.loader);
2549
- const data = await impl(need.params, { shop: getShopProvider() });
2550
- return { status: "ready", data };
2551
- } catch (err) {
2552
- const message = errorMessage(err);
2553
- console.error(`[storefront] loader "${need.loader}" failed:`, err);
2554
- return { status: "error", error: message };
2555
- }
2556
- }
2557
- async function resolvePageData(needs) {
2558
- const settled = await Promise.all(
2559
- needs.map(async (need) => [need.key, await resolvePageDataNeed(need)])
2560
- );
2561
- return Object.fromEntries(settled);
2562
- }
2563
- var PageDataContext = createContext(null);
2564
- function PageDataScope({ nodes, params, initial: initial2, children }) {
2565
- const parent = useContext(PageDataContext);
2566
- const routeParams = useMemo(() => params ?? parent?.params ?? {}, [params, parent]);
2567
- const needs = useMemo(() => collectDataNeeds(nodes, routeParams), [nodes, routeParams]);
2568
- const own = useMemo(
2569
- () => needs.filter((need) => !parent || !(need.key in parent.entries)),
2570
- [needs, parent]
2571
- );
2572
- const staticPass = currentStaticRenderPass();
2573
- if (staticPass) {
2574
- staticPass.tree(nodes);
2575
- staticPass.needs(own);
2576
- }
2577
- const [entries, setEntries] = useState(() => ({
2578
- // Everything handed in is published, not only the needs THIS scope
2579
- // collected. That is what lets a host framework resolve a page's data in
2580
- // its own loader and wrap the shell in a seeding scope: the page's own
2581
- // scope then finds those keys already answered on its parent and fetches
2582
- // nothing. Without it, seeding only works when the seeding scope happens to
2583
- // render the same block tree.
2584
- ...initial2,
2585
- ...Object.fromEntries(
2586
- own.map((need) => [
2587
- need.key,
2588
- initial2?.[need.key] ?? staticPass?.entries[need.key] ?? { status: "loading" }
2589
- ])
2590
- )
2591
- }));
2592
- const signature = own.map((need) => need.key).join("\n");
2593
- useEffect(() => {
2594
- const pending2 = own.filter((need) => initial2?.[need.key]?.status !== "ready");
2595
- if (pending2.length === 0) return;
2596
- let cancelled = false;
2597
- setEntries((prev) => {
2598
- const next = { ...prev };
2599
- for (const need of pending2) {
2600
- if (next[need.key]?.status !== "ready") next[need.key] = { status: "loading" };
2601
- }
2602
- return next;
2603
- });
2604
- for (const need of pending2) {
2605
- void resolvePageDataNeed(need).then((entry) => {
2606
- if (!cancelled) setEntries((prev) => ({ ...prev, [need.key]: entry }));
2607
- });
2608
- }
2609
- return () => {
2610
- cancelled = true;
2611
- };
2612
- }, [signature]);
2613
- const value = useMemo(
2614
- () => ({ entries: { ...parent?.entries, ...entries, ...initial2 }, params: routeParams }),
2615
- [parent, entries, initial2, routeParams]
2616
- );
2617
- return /* @__PURE__ */ jsx(PageDataContext.Provider, { value, children });
2618
- }
2619
- function useLoader(loader, params) {
2620
- const scope = useContext(PageDataContext);
2621
- const key = params === null ? null : dataNeedKey(loader, params);
2622
- const [nonce, setNonce] = useState(0);
2623
- const scoped = nonce === 0 && key !== null && scope ? scope.entries[key] : void 0;
2624
- const [local, setLocal] = useState(null);
2625
- const staticPass = currentStaticRenderPass();
2626
- const staticEntry = staticPass && key !== null && scoped === void 0 ? staticPass.entries[key] : void 0;
2627
- if (staticPass && key !== null && scoped === void 0 && staticEntry === void 0) {
2628
- staticPass.needs([{ key, loader, params }]);
2629
- }
2630
- const paramsKey = params === null ? null : JSON.stringify(params);
2631
- useEffect(() => {
2632
- if (key === null || scoped !== void 0) return;
2633
- let cancelled = false;
2634
- setLocal({ key, entry: { status: "loading" } });
2635
- void resolvePageDataNeed({ loader, params }).then((entry2) => {
2636
- if (!cancelled) setLocal({ key, entry: entry2 });
2637
- });
2638
- return () => {
2639
- cancelled = true;
2640
- };
2641
- }, [loader, paramsKey, nonce, scoped !== void 0]);
2642
- const entry = scoped ?? staticEntry ?? (local && local.key === key ? local.entry : key !== null ? { status: "loading" } : null);
2643
- return {
2644
- status: entry?.status ?? "idle",
2645
- data: entry?.status === "ready" ? entry.data : null,
2646
- error: entry?.status === "error" ? entry.error ?? "unknown error" : null,
2647
- reload: () => setNonce((n) => n + 1)
2648
- };
2649
- }
2650
- function useBlockData(node, name, fallback) {
2651
- const scope = useContext(PageDataContext);
2652
- let loader = fallback.loader;
2653
- let params = fallback.params;
2654
- if (node) {
2655
- const need = needsForNode(node)[name];
2656
- if (need && typeof need.loader === "string" && need.loader) {
2657
- const meta = getBlockMeta(node.type);
2658
- loader = need.loader;
2659
- params = resolveDataParams(need, {
2660
- params: scope?.params ?? {},
2661
- props: { ...defaultPropsFromSettings(meta?.settings), ...node.props }
2662
- });
2663
- }
2664
- }
2665
- const result = useLoader(loader, params);
2666
- return { ...result, loader };
2667
- }
2668
- function BlockDataError({ loader, message }) {
2669
- if (getBlockErrorVisibility() === "silent") return null;
2670
- return /* @__PURE__ */ jsxs(
2671
- "div",
2672
- {
2673
- "data-block-error": `loader:${loader}`,
2674
- style: {
2675
- border: "1px dashed #dc2626",
2676
- color: "#b91c1c",
2677
- padding: "8px 12px",
2678
- font: "12px ui-monospace, monospace",
2679
- borderRadius: 6
2680
- },
2681
- children: [
2682
- `Data for this block failed (loader "${loader}")`,
2683
- message ? /* @__PURE__ */ jsx("div", { style: { opacity: 0.8, marginTop: 4 }, children: message }) : null
2684
- ]
2685
- }
2686
- );
2687
- }
2688
1883
  function CategoryShowcase({
2689
1884
  style,
2690
1885
  title,
@@ -2801,11 +1996,11 @@ function useStorefrontActions() {
2801
1996
  };
2802
1997
  }
2803
1998
  function useMarketProduct(product) {
2804
- const active2 = useMarketStore((s2) => s2.active);
1999
+ const active = useMarketStore((s2) => s2.active);
2805
2000
  const prices = useMarketStore((s2) => s2.prices);
2806
2001
  return useMemo(
2807
- () => product ? withMarketPrice(product, { active: active2, prices }) : product,
2808
- [product, active2, prices]
2002
+ () => product ? withMarketPrice(product, { active, prices }) : product,
2003
+ [product, active, prices]
2809
2004
  );
2810
2005
  }
2811
2006
  function Price({ value, compareAt, testId, compareTestId, className }) {
@@ -2845,12 +2040,12 @@ function PaymentTerms({ price, metadata, variant = "card", className = "" }) {
2845
2040
  if (terms.pixPrice == null && terms.installments === 0) return null;
2846
2041
  const currency = config.currency;
2847
2042
  const locale = config.locale;
2848
- const compact2 = variant === "card";
2043
+ const compact = variant === "card";
2849
2044
  return /* @__PURE__ */ jsxs(
2850
2045
  "div",
2851
2046
  {
2852
2047
  "data-testid": "payment-terms",
2853
- className: `${compact2 ? "mt-0.5 space-y-0.5 text-[11px]" : "mt-3 space-y-1 text-sm"} leading-tight text-muted-foreground ${className}`,
2048
+ className: `${compact ? "mt-0.5 space-y-0.5 text-[11px]" : "mt-3 space-y-1 text-sm"} leading-tight text-muted-foreground ${className}`,
2854
2049
  children: [
2855
2050
  terms.pixPrice != null && /* @__PURE__ */ jsxs("p", { "data-testid": "payment-terms-pix", children: [
2856
2051
  /* @__PURE__ */ jsx("strong", { className: "font-semibold text-foreground", children: formatMoney(terms.pixPrice, currency, locale) }),
@@ -2890,150 +2085,6 @@ var storefrontComponentContracts = {
2890
2085
  enquiryForm: { "data-testid": TID.enquiryForm }
2891
2086
  }
2892
2087
  };
2893
- function mergePageTheme(base, overlay) {
2894
- if (!base && !overlay) return void 0;
2895
- if (!overlay) return base;
2896
- const name = overlay.name ?? (base ? `${base.name}-page` : "page");
2897
- const font = base?.font ? { ...base.font, ...overlay.font } : overlay.font;
2898
- return {
2899
- ...base,
2900
- ...overlay,
2901
- name,
2902
- colors: { ...base?.colors, ...overlay.colors },
2903
- font,
2904
- tokens: { ...base?.tokens, ...overlay.tokens },
2905
- header: { ...base?.header, ...overlay.header },
2906
- productCard: { ...base?.productCard, ...overlay.productCard }
2907
- };
2908
- }
2909
- function pageThemeSelector(slug) {
2910
- return `[data-page="${slug}"]`;
2911
- }
2912
- function routePathParams(path) {
2913
- return path.split("/").filter((segment) => segment.startsWith(":")).map((segment) => segment.slice(1));
2914
- }
2915
- function contentPagePath(slug, page) {
2916
- return page.path ?? `/${slug}`;
2917
- }
2918
- function matchContentPage(pages, path) {
2919
- for (const [slug, page] of Object.entries(pages?.content ?? {})) {
2920
- const params = matchPath(contentPagePath(slug, page), path);
2921
- if (params) return { slug, page, params };
2922
- }
2923
- return null;
2924
- }
2925
- var CATALOG_BODY_BLOCK = "catalogBody";
2926
- var PRODUCT_BODY_BLOCK = "productBody";
2927
- var BODY_BLOCK_BY_KIND = {
2928
- catalog: CATALOG_BODY_BLOCK,
2929
- product: PRODUCT_BODY_BLOCK
2930
- };
2931
- var BLOCK_STRUCTURAL_KEYS = /* @__PURE__ */ new Set([
2932
- "type",
2933
- "id",
2934
- "props",
2935
- "children",
2936
- "data"
2937
- ]);
2938
- var STRUCTURAL_KEYS = BLOCK_STRUCTURAL_KEYS;
2939
- function isNestedBlockRef(entry) {
2940
- return isNestedRef(entry);
2941
- }
2942
- function isNestedRef(entry) {
2943
- const record = entry;
2944
- if ("props" in record) return true;
2945
- return Object.keys(record).every((key) => STRUCTURAL_KEYS.has(key));
2946
- }
2947
- function blockInstanceId(entry, index) {
2948
- const record = entry;
2949
- if (record && typeof record.id === "string" && record.id) return record.id;
2950
- return `${String(record?.type)}-${index}`;
2951
- }
2952
- function toBlockNode(entry, index) {
2953
- const record = entry;
2954
- const type = String(record.type);
2955
- const id = blockInstanceId(entry, index);
2956
- const data = record.data;
2957
- if (isNestedRef(entry)) {
2958
- const children = record.children ?? [];
2959
- return {
2960
- type,
2961
- id,
2962
- props: record.props ?? {},
2963
- ...children.length ? { children: children.map((child, i) => toBlockNode(child, i)) } : {},
2964
- ...data ? { data } : {}
2965
- };
2966
- }
2967
- const props = {};
2968
- for (const [key, value] of Object.entries(record)) {
2969
- if (!STRUCTURAL_KEYS.has(key)) props[key] = value;
2970
- }
2971
- return { type, id, props, ...data ? { data } : {} };
2972
- }
2973
- function toBlockNodes(blocks) {
2974
- return blocks.map(toBlockNode);
2975
- }
2976
- function defaultPageBlocks(kind) {
2977
- const body = BODY_BLOCK_BY_KIND[kind];
2978
- return body ? [{ type: body, id: body, props: {} }] : [];
2979
- }
2980
- function checkPageBlocks(kind, nodes) {
2981
- const found = [];
2982
- const seenIds = /* @__PURE__ */ new Set();
2983
- const expectedBody = BODY_BLOCK_BY_KIND[kind];
2984
- let hasBody = false;
2985
- for (const node of nodes) {
2986
- if (node.type === expectedBody) hasBody = true;
2987
- if (node.id) {
2988
- if (seenIds.has(node.id)) {
2989
- found.push({
2990
- level: "warning",
2991
- rule: "duplicate-block-id",
2992
- detail: `two blocks on the ${kind} page share the id "${node.id}" \u2014 an editor or a generated diff cannot tell them apart`
2993
- });
2994
- }
2995
- seenIds.add(node.id);
2996
- }
2997
- const meta = getBlockMeta(node.type);
2998
- if (!meta) {
2999
- found.push({
3000
- level: "error",
3001
- rule: "unknown-block",
3002
- detail: `the ${kind} page references block "${node.type}", which is not registered \u2014 register it before the storefront mounts`
3003
- });
3004
- continue;
3005
- }
3006
- if (!isBlockEnabledOn({ enabledOn: meta.enabledOn ?? [] }, kind)) {
3007
- found.push({
3008
- level: "warning",
3009
- rule: "block-not-enabled-on-page",
3010
- detail: `block "${node.type}" declares enabledOn [${(meta.enabledOn ?? []).join(", ")}] and is placed on the ${kind} page`
3011
- });
3012
- }
3013
- }
3014
- if (expectedBody && !hasBody) {
3015
- found.push({
3016
- level: "warning",
3017
- rule: "missing-page-body",
3018
- detail: `the ${kind} page tree omits "${expectedBody}", so the page renders no ${kind === "product" ? "product detail" : "product list"} \u2014 add it back unless the replacement is deliberate`
3019
- });
3020
- }
3021
- for (const violation of checkBlockConstraints(nodes)) {
3022
- found.push({
3023
- level: "error",
3024
- rule: violation.rule,
3025
- detail: `${kind} page ${violation.path}: ${violation.detail}`
3026
- });
3027
- }
3028
- for (const finding of checkBlockContext(nodes)) {
3029
- found.push({
3030
- level: "warning",
3031
- rule: "context-not-provided",
3032
- detail: `block "${finding.type}" at ${kind} page ${finding.path} uses context [${finding.missing.join(", ")}] that no ancestor provides`
3033
- });
3034
- }
3035
- return found;
3036
- }
3037
2088
 
3038
2089
  // src/app/hydration.ts
3039
2090
  var PAGE_DATA_SCRIPT_ID = "__fayz_page_data__";
@@ -3469,8 +2520,8 @@ var BADGE_TONE_CLASSES = {
3469
2520
  warning: "bg-amber-500 text-white"
3470
2521
  };
3471
2522
  function useExtensionBadges(product) {
3472
- const [badges, setBadges] = React39__default.useState([]);
3473
- React39__default.useEffect(() => {
2523
+ const [badges, setBadges] = React36__default.useState([]);
2524
+ React36__default.useEffect(() => {
3474
2525
  let cancelled = false;
3475
2526
  getProductCardBadges(product).then((next) => {
3476
2527
  if (!cancelled && next.length > 0) setBadges(next);
@@ -3792,7 +2843,7 @@ function MediaCarousel({
3792
2843
  return () => clearInterval(timer);
3793
2844
  }, [autoplayMs, items.length]);
3794
2845
  if (items.length === 0) return null;
3795
- const active2 = items[Math.min(index, items.length - 1)];
2846
+ const active = items[Math.min(index, items.length - 1)];
3796
2847
  const goTo = (next) => {
3797
2848
  interacted.current = true;
3798
2849
  setIndex((next + items.length) % items.length);
@@ -3814,16 +2865,16 @@ function MediaCarousel({
3814
2865
  `${item.title}-${i}`
3815
2866
  )),
3816
2867
  /* @__PURE__ */ jsx("div", { className: `absolute inset-0 -z-10 ${overlayClass}` }),
3817
- /* @__PURE__ */ jsx("div", { className: `flex h-full px-5 py-16 sm:px-10 lg:px-16 ${alignClass[active2.align ?? "start"]}`, children: /* @__PURE__ */ jsxs("div", { className: "my-auto max-w-2xl text-white drop-shadow-md", children: [
3818
- active2.eyebrow && /* @__PURE__ */ jsx("p", { className: "mb-4 text-xs font-semibold uppercase tracking-[0.24em] text-white/80", children: active2.eyebrow }),
3819
- /* @__PURE__ */ jsx("h1", { className: "sf-heading text-5xl font-normal leading-[0.95] sm:text-7xl lg:text-8xl", children: active2.title }),
3820
- active2.subtitle && /* @__PURE__ */ jsx("p", { className: "mt-5 max-w-xl text-base leading-8 text-white/88 sm:text-lg", children: active2.subtitle }),
3821
- active2.cta && /* @__PURE__ */ jsx(
2868
+ /* @__PURE__ */ jsx("div", { className: `flex h-full px-5 py-16 sm:px-10 lg:px-16 ${alignClass[active.align ?? "start"]}`, children: /* @__PURE__ */ jsxs("div", { className: "my-auto max-w-2xl text-white drop-shadow-md", children: [
2869
+ active.eyebrow && /* @__PURE__ */ jsx("p", { className: "mb-4 text-xs font-semibold uppercase tracking-[0.24em] text-white/80", children: active.eyebrow }),
2870
+ /* @__PURE__ */ jsx("h1", { className: "sf-heading text-5xl font-normal leading-[0.95] sm:text-7xl lg:text-8xl", children: active.title }),
2871
+ active.subtitle && /* @__PURE__ */ jsx("p", { className: "mt-5 max-w-xl text-base leading-8 text-white/88 sm:text-lg", children: active.subtitle }),
2872
+ active.cta && /* @__PURE__ */ jsx(
3822
2873
  Link,
3823
2874
  {
3824
- to: active2.href ?? "/catalog",
2875
+ to: active.href ?? "/catalog",
3825
2876
  className: "mt-8 inline-flex border border-white/75 px-6 py-3 text-xs font-semibold uppercase tracking-[0.18em] text-white transition hover:bg-white hover:text-black",
3826
- children: active2.cta
2877
+ children: active.cta
3827
2878
  }
3828
2879
  )
3829
2880
  ] }) }),
@@ -4232,12 +3283,12 @@ function FiltersPanel() {
4232
3283
  ] })
4233
3284
  ] }),
4234
3285
  facets.map((facet) => {
4235
- const active2 = catalog.facets[facet.key];
3286
+ const active = catalog.facets[facet.key];
4236
3287
  const swatched = facet.values.some((v) => v.swatch);
4237
3288
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
4238
3289
  /* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold", children: facet.label }),
4239
3290
  /* @__PURE__ */ jsx("div", { className: swatched ? "flex flex-wrap gap-2" : "space-y-1", children: facet.values.map((v) => {
4240
- const on = active2 === v.value;
3291
+ const on = active === v.value;
4241
3292
  const label = v.label ?? v.value;
4242
3293
  const toggle = () => catalog.setFacet(facet.key, on ? null : v.value);
4243
3294
  if (v.swatch) {
@@ -4486,163 +3537,6 @@ function useProduct(slug) {
4486
3537
  error
4487
3538
  };
4488
3539
  }
4489
- function absolute(ctx, path = ctx.path) {
4490
- const origin = (ctx.origin ?? currentStaticRenderPass()?.origin ?? seoOrigin()).replace(/\/$/, "");
4491
- if (!origin) return void 0;
4492
- return `${origin}${path.startsWith("/") ? path : `/${path}`}`;
4493
- }
4494
- function primaryImageUrl(product) {
4495
- return (product.images?.find((i) => i.isPrimary) ?? product.images?.[0])?.url;
4496
- }
4497
- function shareImageUrl(product, ctx) {
4498
- const url = primaryImageUrl(product);
4499
- if (!url) return void 0;
4500
- return ctx.config.imageLoading.transform === "supabase" ? imageVariantUrl(url, { width: 1200, quality: 82 }) : url;
4501
- }
4502
- function productJsonLd(product, ctx) {
4503
- const url = absolute(ctx);
4504
- const image = shareImageUrl(product, ctx);
4505
- return {
4506
- "@context": "https://schema.org",
4507
- "@type": "Product",
4508
- name: product.name,
4509
- ...product.description ? { description: product.description } : {},
4510
- ...product.sku ? { sku: product.sku } : {},
4511
- ...image ? { image: [image] } : {},
4512
- offers: {
4513
- "@type": "Offer",
4514
- ...url ? { url } : {},
4515
- price: product.price,
4516
- priceCurrency: product.currency ?? ctx.config.currency,
4517
- availability: (product.inventoryCount ?? 0) > 0 ? "https://schema.org/InStock" : "https://schema.org/OutOfStock"
4518
- }
4519
- };
4520
- }
4521
- function productSeo(product, ctx) {
4522
- const url = absolute(ctx);
4523
- const home = absolute(ctx, "/");
4524
- const catalog = absolute(ctx, ctx.config.catalogPath);
4525
- return {
4526
- title: `${product.name} \u2014 ${ctx.config.name}`,
4527
- description: product.description?.slice(0, 160),
4528
- canonical: url,
4529
- image: shareImageUrl(product, ctx),
4530
- type: "product",
4531
- jsonLd: [
4532
- productJsonLd(product, ctx),
4533
- ...home && catalog && url ? [
4534
- breadcrumbJsonLd([
4535
- { name: ctx.config.name, url: home },
4536
- { name: "Loja", url: catalog },
4537
- { name: product.name, url }
4538
- ])
4539
- ] : []
4540
- ]
4541
- };
4542
- }
4543
- function pageSeo(ctx, input) {
4544
- return { ...input, canonical: absolute(ctx), type: "website" };
4545
- }
4546
- function menuSections(products, categories) {
4547
- const byCategory = /* @__PURE__ */ new Map();
4548
- const loose = [];
4549
- for (const p of products) {
4550
- const key = p.categoryId ?? p.categoryName ?? "";
4551
- if (!key) {
4552
- loose.push(p);
4553
- continue;
4554
- }
4555
- byCategory.set(key, [...byCategory.get(key) ?? [], p]);
4556
- }
4557
- const sections = categories.map((c) => ({ name: c.name, description: c.description, products: byCategory.get(c.id) ?? byCategory.get(c.name) ?? [] })).filter((s2) => s2.products.length > 0);
4558
- if (loose.length) sections.push({ name: "Outros", description: null, products: loose });
4559
- if (!sections.length && products.length) return [{ name: "Card\xE1pio", description: null, products }];
4560
- return sections;
4561
- }
4562
- function menuJsonLd(input, ctx) {
4563
- const url = absolute(ctx);
4564
- const home = absolute(ctx, "/");
4565
- const b = input.business ?? {};
4566
- const currency = ctx.config.currency;
4567
- const address = b.address ? {
4568
- "@type": "PostalAddress",
4569
- ...b.address.streetAddress ? { streetAddress: b.address.streetAddress } : {},
4570
- ...b.address.locality ? { addressLocality: b.address.locality } : {},
4571
- ...b.address.region ? { addressRegion: b.address.region } : {},
4572
- ...b.address.postalCode ? { postalCode: b.address.postalCode } : {},
4573
- addressCountry: b.address.country ?? "BR"
4574
- } : void 0;
4575
- return {
4576
- "@context": "https://schema.org",
4577
- "@type": b.type ?? "Restaurant",
4578
- ...home ? { "@id": `${home.replace(/\/$/, "")}/#business` } : {},
4579
- name: ctx.config.name,
4580
- ...home ? { url: home } : {},
4581
- ...b.description ? { description: b.description } : {},
4582
- ...b.image ? { image: [b.image] } : {},
4583
- ...b.logo ? { logo: b.logo } : {},
4584
- ...b.telephone ? { telephone: b.telephone } : {},
4585
- ...b.email ? { email: b.email } : {},
4586
- ...b.servesCuisine ? { servesCuisine: b.servesCuisine } : {},
4587
- ...b.priceRange ? { priceRange: b.priceRange } : {},
4588
- ...address ? { address } : {},
4589
- ...b.areaServed?.length ? { areaServed: b.areaServed.map((name) => ({ "@type": "Place", name })) } : {},
4590
- ...b.openingHours?.length ? { openingHours: b.openingHours } : {},
4591
- ...b.sameAs?.length ? { sameAs: b.sameAs } : {},
4592
- ...url ? { hasMenu: url } : {},
4593
- ...url ? {
4594
- potentialAction: {
4595
- "@type": "OrderAction",
4596
- target: { "@type": "EntryPoint", urlTemplate: url, actionPlatform: ["https://schema.org/DesktopWebPlatform", "https://schema.org/MobileWebPlatform"] },
4597
- deliveryMethod: "http://purl.org/goodrelations/v1#DeliveryModeOwnFleet"
4598
- }
4599
- } : {},
4600
- menu: {
4601
- "@type": "Menu",
4602
- name: `Card\xE1pio \u2014 ${ctx.config.name}`,
4603
- ...url ? { url } : {},
4604
- inLanguage: "pt-BR",
4605
- hasMenuSection: menuSections(input.products, input.categories).map((section) => ({
4606
- "@type": "MenuSection",
4607
- name: section.name,
4608
- ...section.description ? { description: section.description } : {},
4609
- hasMenuItem: section.products.map((p) => {
4610
- const image = shareImageUrl(p, ctx);
4611
- const itemUrl = absolute(ctx, `/product/${p.slug}`);
4612
- return {
4613
- "@type": "MenuItem",
4614
- name: p.name,
4615
- ...p.description ? { description: p.description.slice(0, 300) } : {},
4616
- ...image ? { image } : {},
4617
- ...itemUrl ? { url: itemUrl } : {},
4618
- offers: {
4619
- "@type": "Offer",
4620
- price: p.price,
4621
- priceCurrency: p.currency ?? currency,
4622
- availability: (p.inventoryCount ?? 0) > 0 ? "https://schema.org/InStock" : "https://schema.org/OutOfStock"
4623
- }
4624
- };
4625
- })
4626
- }))
4627
- }
4628
- };
4629
- }
4630
- function menuSeo(input, ctx) {
4631
- const url = absolute(ctx);
4632
- const home = absolute(ctx, "/");
4633
- const names = input.products.slice(0, 4).map((p) => p.name).join(", ");
4634
- return {
4635
- title: input.title ?? `Delivery ${ctx.config.name} \u2014 pe\xE7a online`,
4636
- description: (input.description ?? (names ? `Pe\xE7a online: ${names} e mais. Card\xE1pio completo com pre\xE7os.` : void 0))?.slice(0, 160),
4637
- canonical: url,
4638
- image: input.business?.image,
4639
- type: "website",
4640
- jsonLd: [
4641
- menuJsonLd(input, ctx),
4642
- ...home && url ? [breadcrumbJsonLd([{ name: ctx.config.name, url: home }, { name: "Delivery", url }])] : []
4643
- ]
4644
- };
4645
- }
4646
3540
  function QuantityInput({ value, onChange, min = 1, max, testId, incTestId, decTestId }) {
4647
3541
  const clamp = (n) => Math.max(min, max != null ? Math.min(n, max) : n);
4648
3542
  return /* @__PURE__ */ jsxs("div", { className: "inline-flex items-center rounded-lg border", children: [
@@ -4767,7 +3661,7 @@ function scalarToString(value) {
4767
3661
  }
4768
3662
  function ProductSpecs({ product }) {
4769
3663
  const config = useStorefrontConfig();
4770
- const extraExcluded = React39__default.useMemo(
3664
+ const extraExcluded = React36__default.useMemo(
4771
3665
  () => new Set(config.productSpecs?.exclude ?? []),
4772
3666
  [config.productSpecs?.exclude]
4773
3667
  );
@@ -5270,7 +4164,7 @@ function RelatedProducts({ product }) {
5270
4164
  )) })
5271
4165
  ] });
5272
4166
  }
5273
- function DeliveryEstimator({ compact: compact2 = false }) {
4167
+ function DeliveryEstimator({ compact = false }) {
5274
4168
  const config = useStorefrontConfig();
5275
4169
  const cart = useCartStore();
5276
4170
  const delivery = useDeliveryStore();
@@ -5297,7 +4191,7 @@ function DeliveryEstimator({ compact: compact2 = false }) {
5297
4191
  "section",
5298
4192
  {
5299
4193
  "data-testid": TID.deliveryEstimator,
5300
- className: compact2 ? "rounded-lg border p-3" : "mt-6 rounded-lg border p-4",
4194
+ className: compact ? "rounded-lg border p-3" : "mt-6 rounded-lg border p-4",
5301
4195
  children: [
5302
4196
  !resolved && /* @__PURE__ */ jsxs(Fragment, { children: [
5303
4197
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm font-semibold", children: [
@@ -5633,11 +4527,11 @@ function ProductDetailPage({ slug }) {
5633
4527
  ] });
5634
4528
  }
5635
4529
  function buildEnquiryFromForm(fields, values, subject, sourceUrl) {
5636
- const emailField = fields.find((f2) => f2.type === "email");
5637
- const phoneField = fields.find((f2) => f2.type === "phone");
5638
- const nameField = fields.find((f2) => f2.id === "name") ?? fields.find((f2) => (f2.type ?? "text") === "text" && f2 !== emailField && f2 !== phoneField);
4530
+ const emailField = fields.find((f) => f.type === "email");
4531
+ const phoneField = fields.find((f) => f.type === "phone");
4532
+ const nameField = fields.find((f) => f.id === "name") ?? fields.find((f) => (f.type ?? "text") === "text" && f !== emailField && f !== phoneField);
5639
4533
  const identity = /* @__PURE__ */ new Set([emailField?.id, phoneField?.id, nameField?.id]);
5640
- const lines = fields.filter((f2) => !identity.has(f2.id)).map((f2) => ({ field: f2, value: (values[f2.id] ?? "").trim() })).filter((entry) => entry.value).map(({ field: field2, value }) => field2.type === "textarea" ? value : `${field2.label}: ${value}`);
4534
+ const lines = fields.filter((f) => !identity.has(f.id)).map((f) => ({ field: f, value: (values[f.id] ?? "").trim() })).filter((entry) => entry.value).map(({ field: field2, value }) => field2.type === "textarea" ? value : `${field2.label}: ${value}`);
5641
4535
  return {
5642
4536
  productName: subject,
5643
4537
  customerName: nameField && values[nameField.id]?.trim() || "Visitante",
@@ -6492,7 +5386,7 @@ function CollectionHero({
6492
5386
  {
6493
5387
  className: `absolute inset-0 flex flex-col justify-center p-6 text-white sm:p-12 ${OVERLAY_CLASS[overlay]} ${centered ? "items-center text-center" : "items-start text-left"}`,
6494
5388
  children: /* @__PURE__ */ jsxs(Reveal, { className: centered ? "max-w-3xl" : "max-w-2xl", children: [
6495
- logos && logos.length > 0 && /* @__PURE__ */ jsx("div", { className: `mb-6 flex items-center gap-5 ${centered ? "justify-center" : ""}`, children: logos.map((logo, i) => /* @__PURE__ */ jsxs(React39__default.Fragment, { children: [
5389
+ logos && logos.length > 0 && /* @__PURE__ */ jsx("div", { className: `mb-6 flex items-center gap-5 ${centered ? "justify-center" : ""}`, children: logos.map((logo, i) => /* @__PURE__ */ jsxs(React36__default.Fragment, { children: [
6496
5390
  i > 0 && /* @__PURE__ */ jsx("span", { className: "text-2xl font-light opacity-60", "aria-hidden": true, children: "\xD7" }),
6497
5391
  /* @__PURE__ */ jsx("img", { src: logo.src, alt: logo.alt, className: "h-10 w-auto object-contain sm:h-14" })
6498
5392
  ] }, logo.src)) }),
@@ -7274,10 +6168,10 @@ function StorefrontConfigHost({
7274
6168
  buyer,
7275
6169
  children
7276
6170
  }) {
7277
- const [policy, setPolicy] = React39__default.useState(null);
7278
- const [shipping, setShipping] = React39__default.useState(null);
7279
- const [delivery, setDelivery] = React39__default.useState(null);
7280
- React39__default.useEffect(() => {
6171
+ const [policy, setPolicy] = React36__default.useState(null);
6172
+ const [shipping, setShipping] = React36__default.useState(null);
6173
+ const [delivery, setDelivery] = React36__default.useState(null);
6174
+ React36__default.useEffect(() => {
7281
6175
  let cancelled = false;
7282
6176
  let provider;
7283
6177
  try {
@@ -7314,7 +6208,7 @@ function StorefrontConfigHost({
7314
6208
  cancelled = true;
7315
6209
  };
7316
6210
  }, [config]);
7317
- const resolved = React39__default.useMemo(
6211
+ const resolved = React36__default.useMemo(
7318
6212
  () => applyBuyer(applyDeliveryPolicy(applyShippingSettings(applyStoreSettings(config, policy), shipping), delivery), buyer),
7319
6213
  [config, policy, shipping, delivery, buyer?.language, buyer?.country]
7320
6214
  );
@@ -7326,7 +6220,7 @@ function MarketScope({ children }) {
7326
6220
  const markets = useMarketStore((s2) => s2.markets);
7327
6221
  const market = markets.length ? marketForCountry(markets, country) : null;
7328
6222
  const prices = useMarketStore((s2) => market ? s2.prices[market.code] : void 0);
7329
- React39__default.useEffect(() => {
6223
+ React36__default.useEffect(() => {
7330
6224
  useMarketStore.getState().setActive(market);
7331
6225
  if (!market || market.isDefault || prices) return;
7332
6226
  let provider;
@@ -7338,11 +6232,11 @@ function MarketScope({ children }) {
7338
6232
  void provider.getMarketPrices?.(market.code).then((list) => useMarketStore.getState().setPrices(market.code, list)).catch(() => {
7339
6233
  });
7340
6234
  }, [market?.code, prices]);
7341
- React39__default.useEffect(() => {
6235
+ React36__default.useEffect(() => {
7342
6236
  if (!market || !market.isDefault && !prices) return;
7343
6237
  useCartStore.getState().repriceForMarket();
7344
6238
  }, [market?.code, prices]);
7345
- const value = React39__default.useMemo(() => {
6239
+ const value = React36__default.useMemo(() => {
7346
6240
  if (!market) return base;
7347
6241
  return {
7348
6242
  ...base,
@@ -7445,10 +6339,10 @@ function themeToCss(theme, options = {}) {
7445
6339
  function googleFontsHref(theme) {
7446
6340
  if (!theme.font) return null;
7447
6341
  const families = theme.font.googleFonts ?? [theme.font.heading, theme.font.body, theme.font.display, theme.font.serif].filter(
7448
- (f2) => Boolean(f2)
6342
+ (f) => Boolean(f)
7449
6343
  );
7450
6344
  const unique = [...new Set(families)];
7451
- const params = unique.map((f2) => `family=${encodeURIComponent(f2).replace(/%20/g, "+")}:wght@300;400;500;600;700`).join("&");
6345
+ const params = unique.map((f) => `family=${encodeURIComponent(f).replace(/%20/g, "+")}:wght@300;400;500;600;700`).join("&");
7452
6346
  return `https://fonts.googleapis.com/css2?${params}&display=swap`;
7453
6347
  }
7454
6348
  function StorefrontThemeStyle({
@@ -7472,7 +6366,7 @@ function StorefrontThemeStyle({
7472
6366
  document.getElementById(linkId)?.remove();
7473
6367
  };
7474
6368
  }, [fontsHref, linkId, selector]);
7475
- return React39__default.createElement(
6369
+ return React36__default.createElement(
7476
6370
  "style",
7477
6371
  { "data-sf-theme": theme.name },
7478
6372
  themeToCss(theme, { selector })
@@ -7500,13 +6394,13 @@ function SearchOverlay({ onClose }) {
7500
6394
  const id = setTimeout(() => setQuery(term.trim()), 220);
7501
6395
  return () => clearTimeout(id);
7502
6396
  }, [term]);
7503
- const active2 = query.length >= searchConfig.minChars;
6397
+ const active = query.length >= searchConfig.minChars;
7504
6398
  const { products, loading } = useProducts(
7505
- active2 ? { status: "active", search: query, limit: searchConfig.suggestionsLimit } : { status: "active", limit: 0 }
6399
+ active ? { status: "active", search: query, limit: searchConfig.suggestionsLimit } : { status: "active", limit: 0 }
7506
6400
  );
7507
6401
  const suggestions = useMemo(
7508
- () => active2 ? products.slice(0, searchConfig.suggestionsLimit) : [],
7509
- [active2, products, searchConfig.suggestionsLimit]
6402
+ () => active ? products.slice(0, searchConfig.suggestionsLimit) : [],
6403
+ [active, products, searchConfig.suggestionsLimit]
7510
6404
  );
7511
6405
  const submit = (value) => {
7512
6406
  const q = value.trim();
@@ -7564,14 +6458,14 @@ function SearchOverlay({ onClose }) {
7564
6458
  }
7565
6459
  )
7566
6460
  ] }),
7567
- active2 && /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-5xl px-4 pb-4 sm:px-6", children: loading && suggestions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "grid gap-4 pb-2 sm:grid-cols-2 lg:grid-cols-4", children: Array.from({ length: Math.min(searchConfig.suggestionsLimit, 4) }).map((_, i) => /* @__PURE__ */ jsx("div", { className: "h-40 animate-pulse rounded-xl bg-muted" }, i)) }) : suggestions.length === 0 ? /* @__PURE__ */ jsxs("p", { className: "py-6 text-center text-sm text-muted-foreground", children: [
6461
+ active && /* @__PURE__ */ jsx("div", { className: "mx-auto max-w-5xl px-4 pb-4 sm:px-6", children: loading && suggestions.length === 0 ? /* @__PURE__ */ jsx("div", { className: "grid gap-4 pb-2 sm:grid-cols-2 lg:grid-cols-4", children: Array.from({ length: Math.min(searchConfig.suggestionsLimit, 4) }).map((_, i) => /* @__PURE__ */ jsx("div", { className: "h-40 animate-pulse rounded-xl bg-muted" }, i)) }) : suggestions.length === 0 ? /* @__PURE__ */ jsxs("p", { className: "py-6 text-center text-sm text-muted-foreground", children: [
7568
6462
  searchConfig.emptyLabel,
7569
6463
  " \u201C",
7570
6464
  query,
7571
6465
  "\u201D."
7572
6466
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7573
6467
  /* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: suggestions.map(
7574
- (product) => searchConfig.renderSuggestion ? /* @__PURE__ */ jsx(React39__default.Fragment, { children: searchConfig.renderSuggestion(product) }, product.id) : /* @__PURE__ */ jsx(SuggestionCard, { product, onNavigate: onClose }, product.id)
6468
+ (product) => searchConfig.renderSuggestion ? /* @__PURE__ */ jsx(React36__default.Fragment, { children: searchConfig.renderSuggestion(product) }, product.id) : /* @__PURE__ */ jsx(SuggestionCard, { product, onNavigate: onClose }, product.id)
7575
6469
  ) }),
7576
6470
  /* @__PURE__ */ jsx(
7577
6471
  "button",
@@ -7778,11 +6672,11 @@ function HeaderActions({ onMenuClick }) {
7778
6672
  const openDrawer = useCartStore((s2) => s2.openDrawer);
7779
6673
  const session = useSessionStore();
7780
6674
  const [accountOpen, setAccountOpen] = useState(false);
7781
- const accountRef = React39__default.useRef(null);
6675
+ const accountRef = React36__default.useRef(null);
7782
6676
  const pop = usePopOnChange(count);
7783
6677
  const firstName = session.name?.split(/\s+/)[0];
7784
6678
  const initial2 = (firstName ?? session.email ?? "C").slice(0, 1).toUpperCase();
7785
- React39__default.useEffect(() => {
6679
+ React36__default.useEffect(() => {
7786
6680
  if (!accountOpen) return;
7787
6681
  const onPointerDown = (event) => {
7788
6682
  if (!accountRef.current?.contains(event.target)) setAccountOpen(false);
@@ -7949,7 +6843,7 @@ function MobileMenuDrawer({ open, onClose }) {
7949
6843
  navigateTo(config.catalogPath);
7950
6844
  onClose();
7951
6845
  };
7952
- React39__default.useEffect(() => {
6846
+ React36__default.useEffect(() => {
7953
6847
  if (!open) return;
7954
6848
  const onKey = (e) => {
7955
6849
  if (e.key === "Escape") onClose();
@@ -8021,7 +6915,7 @@ function MobileMenuDrawer({ open, onClose }) {
8021
6915
  }
8022
6916
  function StorefrontHeader({ chrome } = {}) {
8023
6917
  const config = useStorefrontConfig();
8024
- const compact2 = chrome === "minimal";
6918
+ const compact = chrome === "minimal";
8025
6919
  const variant = config.theme?.header?.variant ?? "classic";
8026
6920
  const scrolled = useScrolled();
8027
6921
  const showSearch = config.theme?.header?.showSearch !== false;
@@ -8035,8 +6929,8 @@ function StorefrontHeader({ chrome } = {}) {
8035
6929
  style: headerStyle,
8036
6930
  children: [
8037
6931
  /* @__PURE__ */ jsx(AnnouncementBar, {}),
8038
- !compact2 && /* @__PURE__ */ jsx(UtilityBar, {}),
8039
- compact2 ? (
6932
+ !compact && /* @__PURE__ */ jsx(UtilityBar, {}),
6933
+ compact ? (
8040
6934
  // O cabeçalho de um app de pedido: marca, busca, carrinho — e o resto da
8041
6935
  // navegação atrás do menu, alcançável e fora do caminho.
8042
6936
  /* @__PURE__ */ jsxs("div", { className: "mx-auto flex h-14 max-w-7xl items-center gap-3 px-4 sm:px-6", children: [
@@ -8618,66 +7512,6 @@ function ContentPage({ slug, page, params }) {
8618
7512
  ] });
8619
7513
  }
8620
7514
 
8621
- // src/app/serving.ts
8622
- function resolveStorefrontRoute(config, rawPath) {
8623
- const resolved = ensureResolved(config);
8624
- const path = rawPath.split("?")[0] || "/";
8625
- for (const route of resolved.routes ?? []) {
8626
- const params = matchPath(route.path, path);
8627
- if (params) return { kind: "custom", route, params };
8628
- }
8629
- const product = matchPath("/product/:slug", path);
8630
- if (product?.slug) return { kind: "product", params: product };
8631
- const order = matchPath("/order/:id", path);
8632
- if (order?.id) return { kind: "order", params: order };
8633
- if (matchPath("/checkout", path)) return { kind: "checkout" };
8634
- if (matchPath("/account", path)) return { kind: "account" };
8635
- if (matchPath("/catalog", path)) return { kind: "catalog" };
8636
- if (resolved.delivery && matchPath(resolved.delivery.menuPath, path)) return { kind: "menu" };
8637
- if (resolved.search.mode === "overlay" && matchPath(resolved.search.resultsPath, path)) {
8638
- return { kind: "searchResults" };
8639
- }
8640
- if (matchPath("/privacy", path)) return { kind: "policy", policy: "privacy" };
8641
- if (matchPath("/terms", path)) return { kind: "policy", policy: "terms" };
8642
- if (matchPath("/refunds", path)) return { kind: "policy", policy: "returns" };
8643
- const content = matchContentPage(resolved.pages, path);
8644
- if (content) return { kind: "content", slug: content.slug, params: content.params };
8645
- if (path === "/" || path === "") return { kind: "home" };
8646
- return { kind: "notFound" };
8647
- }
8648
- function isKnownPath(config, path) {
8649
- return resolveStorefrontRoute(config, path).kind !== "notFound";
8650
- }
8651
- var STATIC_PATTERNS = ["/", "/catalog", "/privacy", "/terms", "/refunds"];
8652
- function ensureResolved(config) {
8653
- return "features" in config && "pages" in config ? config : resolveConfig(config);
8654
- }
8655
- function isPublicPath(config, path) {
8656
- const match = resolveStorefrontRoute(config, path);
8657
- switch (match.kind) {
8658
- case "checkout":
8659
- case "account":
8660
- case "order":
8661
- return false;
8662
- case "custom":
8663
- return match.route.kind !== "checkout" && match.route.kind !== "account" && match.route.chrome !== "focused";
8664
- default:
8665
- return true;
8666
- }
8667
- }
8668
- async function storefrontPaths(input) {
8669
- const resolved = ensureResolved(input.config);
8670
- const paths = [...STATIC_PATTERNS];
8671
- if (resolved.delivery) paths.push(resolved.delivery.menuPath);
8672
- for (const route of resolved.routes ?? []) {
8673
- if (!route.path.includes(":")) paths.push(route.path);
8674
- }
8675
- const products = await input.provider.listProducts({ status: "active" });
8676
- for (const product of products) paths.push(`/product/${product.slug}`);
8677
- const unique = Array.from(new Set(paths));
8678
- return input.includePrivate ? unique : unique.filter((p) => isPublicPath(resolved, p));
8679
- }
8680
-
8681
7515
  // src/data/local-orders.ts
8682
7516
  var KEY = "fayz.storefront.orders.v1";
8683
7517
  var MAX = 25;
@@ -8703,7 +7537,7 @@ function listLocalOrderIds() {
8703
7537
  }
8704
7538
 
8705
7539
  // src/lib/errors.ts
8706
- function errorMessage5(err) {
7540
+ function errorMessage4(err) {
8707
7541
  if (err instanceof Error) return err.message;
8708
7542
  if (err && typeof err === "object" && typeof err.message === "string") {
8709
7543
  return err.message;
@@ -8720,7 +7554,7 @@ function formatDeliveryNotes(address, shippingAddress) {
8720
7554
  return parts.length > 0 ? `Entrega: ${parts.join(", ")}` : void 0;
8721
7555
  }
8722
7556
  function isStaleCustomerError(err) {
8723
- const message = errorMessage5(err).toLowerCase();
7557
+ const message = errorMessage4(err).toLowerCase();
8724
7558
  return message.includes("customer email mismatch") || message.includes("customer does not belong to this store") || message.includes("customer belongs to another account");
8725
7559
  }
8726
7560
  async function placeStorefrontOrder({
@@ -8983,8 +7817,8 @@ function AddressForm({ country, language, value, onChange, onPostalCode, lookup,
8983
7817
  postalHint()
8984
7818
  ] }, "postalCode");
8985
7819
  }
8986
- if (row.length === 1) return /* @__PURE__ */ jsx(React39__default.Fragment, { children: input(specs.get(cells[0])) }, cells[0]);
8987
- return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: cells.map((key) => /* @__PURE__ */ jsx(React39__default.Fragment, { children: input(specs.get(key)) }, key)) }, cells.join("-"));
7820
+ if (row.length === 1) return /* @__PURE__ */ jsx(React36__default.Fragment, { children: input(specs.get(cells[0])) }, cells[0]);
7821
+ return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: cells.map((key) => /* @__PURE__ */ jsx(React36__default.Fragment, { children: input(specs.get(key)) }, key)) }, cells.join("-"));
8988
7822
  }) });
8989
7823
  }
8990
7824
  function flag(iso2) {
@@ -9160,7 +7994,7 @@ function CheckoutSteps({ current, onGoBackTo, omit }) {
9160
7994
  return /* @__PURE__ */ jsxs("nav", { "data-testid": TID.checkoutSteps, "aria-label": t("checkout.steps.label"), className: "mb-8", children: [
9161
7995
  /* @__PURE__ */ jsx("ol", { className: "flex items-center gap-1.5 sm:gap-2", children: steps.map((step, index) => {
9162
7996
  const done = step < current;
9163
- const active2 = step === current;
7997
+ const active = step === current;
9164
7998
  const canGoBack = done && !!onGoBackTo;
9165
7999
  const Tag = canGoBack ? "button" : "div";
9166
8000
  return (
@@ -9179,12 +8013,12 @@ function CheckoutSteps({ current, onGoBackTo, omit }) {
9179
8013
  {
9180
8014
  ...canGoBack ? { type: "button", onClick: () => onGoBackTo(step) } : {},
9181
8015
  "data-testid": TID.checkoutStep(step),
9182
- "data-state": done ? "done" : active2 ? "current" : "pending",
9183
- "aria-current": active2 ? "step" : void 0,
8016
+ "data-state": done ? "done" : active ? "current" : "pending",
8017
+ "aria-current": active ? "step" : void 0,
9184
8018
  className: [
9185
8019
  "flex min-w-0 items-center gap-2 rounded-lg px-2 py-1.5 text-left transition",
9186
8020
  canGoBack ? "hover:bg-muted" : "",
9187
- active2 ? "text-foreground" : done ? "text-foreground" : "text-muted-foreground"
8021
+ active ? "text-foreground" : done ? "text-foreground" : "text-muted-foreground"
9188
8022
  ].join(" "),
9189
8023
  children: [
9190
8024
  /* @__PURE__ */ jsx(
@@ -9192,12 +8026,12 @@ function CheckoutSteps({ current, onGoBackTo, omit }) {
9192
8026
  {
9193
8027
  className: [
9194
8028
  "grid h-7 w-7 shrink-0 place-items-center rounded-full border text-xs font-semibold",
9195
- done ? "border-primary bg-primary text-primary-foreground" : active2 ? "border-primary bg-background text-primary" : "border-muted-foreground/30 bg-background"
8029
+ done ? "border-primary bg-primary text-primary-foreground" : active ? "border-primary bg-background text-primary" : "border-muted-foreground/30 bg-background"
9196
8030
  ].join(" "),
9197
8031
  children: done ? /* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5" }) : index + 1
9198
8032
  }
9199
8033
  ),
9200
- /* @__PURE__ */ jsx("span", { className: `hidden truncate text-sm sm:inline ${active2 ? "font-semibold" : ""}`, children: t(LABELS2[step]) })
8034
+ /* @__PURE__ */ jsx("span", { className: `hidden truncate text-sm sm:inline ${active ? "font-semibold" : ""}`, children: t(LABELS2[step]) })
9201
8035
  ]
9202
8036
  }
9203
8037
  ),
@@ -9340,13 +8174,13 @@ function CardBrick({ publicKey, amount, email, onSubmit, onError }) {
9340
8174
  var POLL_MS = 3e3;
9341
8175
  var RESUME_KEY = "fz.checkout.resume";
9342
8176
  function useExpiry(expiresAt) {
9343
- const target = React39__default.useMemo(() => {
8177
+ const target = React36__default.useMemo(() => {
9344
8178
  if (!expiresAt) return null;
9345
8179
  const t = new Date(expiresAt).getTime();
9346
8180
  return Number.isFinite(t) ? t : null;
9347
8181
  }, [expiresAt]);
9348
- const [now, setNow] = React39__default.useState(() => Date.now());
9349
- React39__default.useEffect(() => {
8182
+ const [now, setNow] = React36__default.useState(() => Date.now());
8183
+ React36__default.useEffect(() => {
9350
8184
  if (target === null) return;
9351
8185
  const id = setInterval(() => setNow(Date.now()), 1e3);
9352
8186
  return () => clearInterval(id);
@@ -9936,7 +8770,7 @@ function ContactSummary({ name, email, phone, document: document2, onEdit, onSig
9936
8770
  function toShippingAddress(form, country) {
9937
8771
  const schema = getCountrySchema(country);
9938
8772
  const isBrazil = schema.iso2 === "BR";
9939
- const has = (key) => schema.fields.some((f2) => f2.key === key);
8773
+ const has = (key) => schema.fields.some((f) => f.key === key);
9940
8774
  return {
9941
8775
  postalCode: isBrazil ? form.zip.trim() : normalizePostalCode(form.zip, country),
9942
8776
  street: form.street.trim(),
@@ -9965,7 +8799,7 @@ var PAYMENT_LABELS = {
9965
8799
  };
9966
8800
  var BRAZIL_ONLY = ["pix", "boleto"];
9967
8801
  function placeOrderMessage(err, t) {
9968
- const message = errorMessage5(err);
8802
+ const message = errorMessage4(err);
9969
8803
  if (/customer (email mismatch|does not belong|belongs to another)/i.test(message)) {
9970
8804
  return t("error.sessionMismatch");
9971
8805
  }
@@ -10042,7 +8876,7 @@ function CheckoutPage() {
10042
8876
  district: "",
10043
8877
  state: ""
10044
8878
  });
10045
- React39__default.useEffect(() => {
8879
+ React36__default.useEffect(() => {
10046
8880
  if (!known.ready) return;
10047
8881
  setForm((current) => ({
10048
8882
  ...current,
@@ -10058,7 +8892,7 @@ function CheckoutPage() {
10058
8892
  }));
10059
8893
  }, [known.ready, known.phone, known.document, known.address]);
10060
8894
  const [step, setStep] = useState(resume ? 3 : 1);
10061
- const reportedStart = React39__default.useRef(false);
8895
+ const reportedStart = React36__default.useRef(false);
10062
8896
  useEffect(() => {
10063
8897
  if (reportedStart.current) return;
10064
8898
  reportedStart.current = true;
@@ -10071,7 +8905,7 @@ function CheckoutPage() {
10071
8905
  });
10072
8906
  }
10073
8907
  }, []);
10074
- const reportedStep = React39__default.useRef(null);
8908
+ const reportedStep = React36__default.useRef(null);
10075
8909
  useEffect(() => {
10076
8910
  if (reportedStep.current === step) return;
10077
8911
  reportedStep.current = step;
@@ -10080,7 +8914,7 @@ function CheckoutPage() {
10080
8914
  }, [step]);
10081
8915
  const [contactKnown, setContactKnown] = useState(false);
10082
8916
  const [editingContact, setEditingContact] = useState(false);
10083
- const skippedContact = React39__default.useRef(false);
8917
+ const skippedContact = React36__default.useRef(false);
10084
8918
  const fulfillmentType = useDeliveryStore((s2) => s2.fulfillmentType);
10085
8919
  const scheduledFor = useDeliveryStore((s2) => s2.scheduledFor);
10086
8920
  const deliveryReference = useDeliveryStore((s2) => {
@@ -10109,7 +8943,7 @@ function CheckoutPage() {
10109
8943
  const [applyingDiscount, setApplyingDiscount] = useState(false);
10110
8944
  const [showSignin, setShowSignin] = useState(false);
10111
8945
  const [placing, setPlacing] = useState(false);
10112
- const leaving = React39__default.useRef(false);
8946
+ const leaving = React36__default.useRef(false);
10113
8947
  const [zipLookup, setZipLookup] = useState("idle");
10114
8948
  const subtotal = selectSubtotal(cart);
10115
8949
  const discountTotal = selectDiscountTotal(cart);
@@ -10117,7 +8951,7 @@ function CheckoutPage() {
10117
8951
  const shipping = isPickup ? 0 : shippingRaw;
10118
8952
  const total = selectTotal(cart, config) - (isPickup ? shippingRaw : 0);
10119
8953
  const checkoutSlotContext = { subtotal, total };
10120
- const checkoutSessionInput = React39__default.useMemo(() => ({
8954
+ const checkoutSessionInput = React36__default.useMemo(() => ({
10121
8955
  items: cart.lines.map((line) => ({
10122
8956
  productId: line.productId,
10123
8957
  variantId: line.variantId ?? null,
@@ -10294,7 +9128,7 @@ function CheckoutPage() {
10294
9128
  cancelled = true;
10295
9129
  };
10296
9130
  }, [session.customerId]);
10297
- const shownCountry = React39__default.useRef(country);
9131
+ const shownCountry = React36__default.useRef(country);
10298
9132
  useEffect(() => {
10299
9133
  if (shownCountry.current === country) return;
10300
9134
  shownCountry.current = country;
@@ -10445,7 +9279,7 @@ function CheckoutPage() {
10445
9279
  if (errors.postalCode || errors.street || errors.city) return fail(t("error.address"), errors.postalCode ? TID.checkoutZip : TID.checkoutStreet);
10446
9280
  if (errors.complement) return fail(t("error.complement"), "checkout-complement");
10447
9281
  if (errors.region) {
10448
- const label = countrySchema.fields.find((f2) => f2.key === "region")?.label[config.language] ?? "";
9282
+ const label = countrySchema.fields.find((f) => f.key === "region")?.label[config.language] ?? "";
10449
9283
  return fail(t("error.region", { label: label.toLowerCase() }), "checkout-state");
10450
9284
  }
10451
9285
  return true;
@@ -11161,15 +9995,15 @@ function StoreCover({ onShowHours, onOpenAccount }) {
11161
9995
  ] })
11162
9996
  ] }),
11163
9997
  modes.length > 1 && /* @__PURE__ */ jsx("div", { className: "mt-4 flex gap-1", children: modes.map((mode) => {
11164
- const active2 = type === mode;
9998
+ const active = type === mode;
11165
9999
  return /* @__PURE__ */ jsx(
11166
10000
  "button",
11167
10001
  {
11168
10002
  type: "button",
11169
10003
  "data-testid": TID.fulfillmentMode(mode),
11170
- "aria-pressed": active2,
10004
+ "aria-pressed": active,
11171
10005
  onClick: () => choose(mode),
11172
- className: `rounded-full px-5 py-2 text-sm font-semibold transition ${active2 ? "bg-white text-neutral-900" : "text-white/80"}`,
10006
+ className: `rounded-full px-5 py-2 text-sm font-semibold transition ${active ? "bg-white text-neutral-900" : "text-white/80"}`,
11173
10007
  children: mode === "pickup" ? "Retirada" : "Entrega"
11174
10008
  },
11175
10009
  mode
@@ -11207,8 +10041,8 @@ function AddressStrip({
11207
10041
  const money = (v) => formatMoney(v, config.currency, config.locale);
11208
10042
  const subtotal = selectSubtotal(useCartStore());
11209
10043
  const resolve = useDeliveryStore((s2) => s2.resolve);
11210
- const quotedOnce = React39__default.useRef(false);
11211
- React39__default.useEffect(() => {
10044
+ const quotedOnce = React36__default.useRef(false);
10045
+ React36__default.useEffect(() => {
11212
10046
  if (quotedOnce.current || isPickup) return;
11213
10047
  if (delivery.status !== "idle" || delivery.options.length > 0 || !delivery.postalCode) return;
11214
10048
  quotedOnce.current = true;
@@ -11270,17 +10104,17 @@ function MenuToolbar({
11270
10104
  onQuery,
11271
10105
  autoFocusSearch
11272
10106
  }) {
11273
- const inputRef = React39__default.useRef(null);
11274
- const [active2, setActive] = React39__default.useState(null);
11275
- React39__default.useEffect(() => {
10107
+ const inputRef = React36__default.useRef(null);
10108
+ const [active, setActive] = React36__default.useState(null);
10109
+ React36__default.useEffect(() => {
11276
10110
  setActive(
11277
10111
  (current) => current && sections.some((s2) => s2.slug === current) ? current : sections[0]?.slug ?? null
11278
10112
  );
11279
10113
  }, [sections]);
11280
- React39__default.useEffect(() => {
10114
+ React36__default.useEffect(() => {
11281
10115
  if (autoFocusSearch) inputRef.current?.focus();
11282
10116
  }, [autoFocusSearch]);
11283
- React39__default.useEffect(() => {
10117
+ React36__default.useEffect(() => {
11284
10118
  if (typeof IntersectionObserver === "undefined") return;
11285
10119
  const seen = /* @__PURE__ */ new Map();
11286
10120
  const observer = new IntersectionObserver(
@@ -11348,7 +10182,7 @@ function MenuToolbar({
11348
10182
  "aria-label": "Categorias",
11349
10183
  className: "mx-auto w-full max-w-3xl overflow-x-auto pb-3 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
11350
10184
  children: /* @__PURE__ */ jsx("ul", { className: "flex w-max gap-2 px-4", children: sections.map((section) => {
11351
- const on = active2 === section.slug;
10185
+ const on = active === section.slug;
11352
10186
  return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
11353
10187
  "button",
11354
10188
  {
@@ -11467,10 +10301,10 @@ function ItemSheet({
11467
10301
  }) {
11468
10302
  const config = useStorefrontConfig();
11469
10303
  const money = (v) => formatMoney(v, config.currency, config.locale);
11470
- const groups = React39__default.useMemo(() => getProductOptionGroups(product), [product]);
11471
- const [options, setOptions] = React39__default.useState({});
11472
- const [notes, setNotes] = React39__default.useState("");
11473
- const [quantity, setQuantity] = React39__default.useState(1);
10304
+ const groups = React36__default.useMemo(() => getProductOptionGroups(product), [product]);
10305
+ const [options, setOptions] = React36__default.useState({});
10306
+ const [notes, setNotes] = React36__default.useState("");
10307
+ const [quantity, setQuantity] = React36__default.useState(1);
11474
10308
  const image = product.images?.find((i) => i.isPrimary) ?? product.images?.[0];
11475
10309
  const stock = product.inventoryCount;
11476
10310
  const missing = groups.filter((g) => !options[g.label]);
@@ -11664,8 +10498,8 @@ function ScheduleSheet({ onClose }) {
11664
10498
  const scheduledFor = useDeliveryStore((s2) => s2.scheduledFor);
11665
10499
  const setScheduledFor = useDeliveryStore((s2) => s2.setScheduledFor);
11666
10500
  const timezone = useServiceStore((s2) => s2.service?.timezone) ?? "America/Sao_Paulo";
11667
- const [slots, setSlots] = React39__default.useState(null);
11668
- React39__default.useEffect(() => {
10501
+ const [slots, setSlots] = React36__default.useState(null);
10502
+ React36__default.useEffect(() => {
11669
10503
  let alive = true;
11670
10504
  void (async () => {
11671
10505
  const rows = await getShopProvider()?.listScheduleSlots?.(fulfillmentType) ?? [];
@@ -11675,7 +10509,7 @@ function ScheduleSheet({ onClose }) {
11675
10509
  alive = false;
11676
10510
  };
11677
10511
  }, [fulfillmentType]);
11678
- const days = React39__default.useMemo(() => {
10512
+ const days = React36__default.useMemo(() => {
11679
10513
  const fmtDay = new Intl.DateTimeFormat("pt-BR", {
11680
10514
  weekday: "long",
11681
10515
  day: "2-digit",
@@ -11728,18 +10562,18 @@ function ScheduleSheet({ onClose }) {
11728
10562
  days.map(([day, daySlots]) => /* @__PURE__ */ jsxs("div", { className: "mb-5", children: [
11729
10563
  /* @__PURE__ */ jsx("h3", { className: "mb-2 text-sm font-semibold capitalize", children: day }),
11730
10564
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-2", children: daySlots.map((slot) => {
11731
- const active2 = scheduledFor === slot.startsAt;
10565
+ const active = scheduledFor === slot.startsAt;
11732
10566
  return /* @__PURE__ */ jsxs(
11733
10567
  "button",
11734
10568
  {
11735
10569
  type: "button",
11736
10570
  "data-testid": TID.scheduleSlot(slot.startsAt),
11737
- "aria-pressed": active2,
10571
+ "aria-pressed": active,
11738
10572
  onClick: () => {
11739
10573
  setScheduledFor(slot.startsAt);
11740
10574
  onClose();
11741
10575
  },
11742
- className: `rounded-lg border px-3 py-2 text-sm ${active2 ? "border-primary font-medium" : "border-border"}`,
10576
+ className: `rounded-lg border px-3 py-2 text-sm ${active ? "border-primary font-medium" : "border-border"}`,
11743
10577
  children: [
11744
10578
  fmtTime.format(new Date(slot.startsAt)),
11745
10579
  " \u2013 ",
@@ -11761,8 +10595,8 @@ function hhmm(time) {
11761
10595
  }
11762
10596
  function ServiceHoursModal({ onClose }) {
11763
10597
  const fulfillmentType = useServiceStore((s2) => s2.fulfillmentType);
11764
- const [hours, setHours] = React39__default.useState(null);
11765
- React39__default.useEffect(() => {
10598
+ const [hours, setHours] = React36__default.useState(null);
10599
+ React36__default.useEffect(() => {
11766
10600
  let alive = true;
11767
10601
  void (async () => {
11768
10602
  const rows = await getShopProvider()?.listServiceHours?.(fulfillmentType) ?? [];
@@ -11772,7 +10606,7 @@ function ServiceHoursModal({ onClose }) {
11772
10606
  alive = false;
11773
10607
  };
11774
10608
  }, [fulfillmentType]);
11775
- const byDay = React39__default.useMemo(() => {
10609
+ const byDay = React36__default.useMemo(() => {
11776
10610
  const map = /* @__PURE__ */ new Map();
11777
10611
  for (const h of hours ?? []) {
11778
10612
  const list = map.get(h.weekday) ?? [];
@@ -11857,7 +10691,7 @@ function AddressSheet({ onClose, onSignIn }) {
11857
10691
  const unsavedCurrent = current && !saved.some((a) => a.id === selectedId) ? current : null;
11858
10692
  const fromAccount = accountBook.filter((a) => !saved.some((b) => normalizePostalCode(b.postalCode) === normalizePostalCode(a.postalCode) && b.number.trim().toLowerCase() === (a.number ?? "").trim().toLowerCase()));
11859
10693
  const nothingToList = saved.length === 0 && !unsavedCurrent && fromAccount.length === 0 && !customerId;
11860
- const [editing, setEditing] = React39__default.useState(
10694
+ const [editing, setEditing] = React36__default.useState(
11861
10695
  nothingToList && !onSignIn ? {} : null
11862
10696
  );
11863
10697
  function pickAccountAddress(a) {
@@ -11876,13 +10710,13 @@ function AddressSheet({ onClose, onSignIn }) {
11876
10710
  void selectAddress(id, subtotal);
11877
10711
  onClose();
11878
10712
  }
11879
- const closeRef = React39__default.useRef(() => {
10713
+ const closeRef = React36__default.useRef(() => {
11880
10714
  });
11881
10715
  closeRef.current = () => {
11882
10716
  if (editing && !nothingToList) setEditing(null);
11883
10717
  else onClose();
11884
10718
  };
11885
- React39__default.useEffect(() => {
10719
+ React36__default.useEffect(() => {
11886
10720
  const onKey = (e) => {
11887
10721
  if (e.key === "Escape") closeRef.current();
11888
10722
  };
@@ -12063,8 +10897,8 @@ function AddressLines({ address }) {
12063
10897
  ] });
12064
10898
  }
12065
10899
  function useAccountAddresses(customerId) {
12066
- const [rows, setRows] = React39__default.useState([]);
12067
- React39__default.useEffect(() => {
10900
+ const [rows, setRows] = React36__default.useState([]);
10901
+ React36__default.useEffect(() => {
12068
10902
  if (!customerId) {
12069
10903
  setRows([]);
12070
10904
  return;
@@ -12092,24 +10926,24 @@ function AddressForm2({ onDone, initial: initial2, replaces }) {
12092
10926
  const storeError = useDeliveryStore((s2) => s2.error);
12093
10927
  const refusedZone = useDeliveryStore((s2) => s2.refusedZone);
12094
10928
  const subtotal = selectSubtotal(useCartStore());
12095
- const [cep, setCep] = React39__default.useState(initial2?.postalCode ? formatPostalCode(initial2.postalCode) : "");
12096
- const [number, setNumber] = React39__default.useState(initial2?.number ?? "");
12097
- const [complement, setComplement] = React39__default.useState(initial2?.complement ?? "");
12098
- const [reference, setReference] = React39__default.useState(initial2?.reference ?? "");
12099
- const [label, setLabel] = React39__default.useState(initial2?.label ?? "");
12100
- const [touched, setTouched] = React39__default.useState(false);
12101
- const numberRef = React39__default.useRef(null);
10929
+ const [cep, setCep] = React36__default.useState(initial2?.postalCode ? formatPostalCode(initial2.postalCode) : "");
10930
+ const [number, setNumber] = React36__default.useState(initial2?.number ?? "");
10931
+ const [complement, setComplement] = React36__default.useState(initial2?.complement ?? "");
10932
+ const [reference, setReference] = React36__default.useState(initial2?.reference ?? "");
10933
+ const [label, setLabel] = React36__default.useState(initial2?.label ?? "");
10934
+ const [touched, setTouched] = React36__default.useState(false);
10935
+ const numberRef = React36__default.useRef(null);
12102
10936
  const digits = normalizePostalCode(cep);
12103
10937
  const found = Boolean(looked) && normalizePostalCode(looked.postalCode) === digits;
12104
- React39__default.useEffect(() => {
10938
+ React36__default.useEffect(() => {
12105
10939
  if (found) numberRef.current?.focus();
12106
10940
  }, [found]);
12107
10941
  async function lookUp() {
12108
10942
  if (digits.length !== 8) return;
12109
10943
  await resolve(digits, subtotal);
12110
10944
  }
12111
- const prefilled = React39__default.useRef(false);
12112
- React39__default.useEffect(() => {
10945
+ const prefilled = React36__default.useRef(false);
10946
+ React36__default.useEffect(() => {
12113
10947
  if (prefilled.current || !initial2?.postalCode) return;
12114
10948
  prefilled.current = true;
12115
10949
  if (!found) void lookUp();
@@ -12325,7 +11159,7 @@ function AccountDrawer({ onClose, onSignIn, onAddresses, onShowHours }) {
12325
11159
  const session = useSessionStore();
12326
11160
  const signedIn = Boolean(session.email);
12327
11161
  const name = session.name || session.email?.split("@")[0] || "";
12328
- React39__default.useEffect(() => {
11162
+ React36__default.useEffect(() => {
12329
11163
  const onKey = (event) => {
12330
11164
  if (event.key === "Escape") onClose();
12331
11165
  };
@@ -12406,19 +11240,11 @@ function AccountDrawer({ onClose, onSignIn, onAddresses, onShowHours }) {
12406
11240
  ] })
12407
11241
  ] });
12408
11242
  }
12409
- var MENU_DATA_NEEDS = {
12410
- products: { loader: "products.list", params: {} },
12411
- categories: { loader: "categories.list", params: {} },
12412
- featured: { loader: "products.featured", params: {} }
12413
- };
12414
- function menuDataNeeds() {
12415
- return Object.values(MENU_DATA_NEEDS).map(({ loader, params }) => ({ key: dataNeedKey(loader, params), loader, params }));
12416
- }
12417
11243
  function MenuPage() {
12418
11244
  const config = useStorefrontConfig();
12419
11245
  const addItem = useCartStore((s2) => s2.addItem);
12420
- const [openProduct, setOpenProduct] = React39__default.useState(null);
12421
- React39__default.useEffect(() => {
11246
+ const [openProduct, setOpenProduct] = React36__default.useState(null);
11247
+ React36__default.useEffect(() => {
12422
11248
  if (!openProduct) return;
12423
11249
  trackStorefront("product_viewed", {
12424
11250
  product_id: openProduct.id,
@@ -12429,18 +11255,18 @@ function MenuPage() {
12429
11255
  surface: "menu_sheet"
12430
11256
  });
12431
11257
  }, [openProduct?.id]);
12432
- const [showHours, setShowHours] = React39__default.useState(false);
12433
- const [showClosed, setShowClosed] = React39__default.useState(false);
12434
- const [showAddress, setShowAddress] = React39__default.useState(false);
12435
- const [showAccount, setShowAccount] = React39__default.useState(false);
12436
- const [showSignIn, setShowSignIn] = React39__default.useState(false);
12437
- const [showSchedule, setShowSchedule] = React39__default.useState(false);
12438
- const [query, setQuery] = React39__default.useState("");
11258
+ const [showHours, setShowHours] = React36__default.useState(false);
11259
+ const [showClosed, setShowClosed] = React36__default.useState(false);
11260
+ const [showAddress, setShowAddress] = React36__default.useState(false);
11261
+ const [showAccount, setShowAccount] = React36__default.useState(false);
11262
+ const [showSignIn, setShowSignIn] = React36__default.useState(false);
11263
+ const [showSchedule, setShowSchedule] = React36__default.useState(false);
11264
+ const [query, setQuery] = React36__default.useState("");
12439
11265
  const serviceState = useServiceStore();
12440
11266
  const refreshService = useServiceStore((s2) => s2.refresh);
12441
11267
  const paused = Boolean(config.delivery?.paused);
12442
11268
  const isOpen = selectIsOpen(serviceState) && !paused;
12443
- React39__default.useEffect(() => {
11269
+ React36__default.useEffect(() => {
12444
11270
  void refreshService();
12445
11271
  }, [refreshService]);
12446
11272
  const cart = useCartStore();
@@ -12462,7 +11288,7 @@ function MenuPage() {
12462
11288
  const loading = products.status === "loading" || products.status === "idle";
12463
11289
  const items = products.data ?? [];
12464
11290
  const cats = categories.data ?? [];
12465
- const allSections = React39__default.useMemo(() => {
11291
+ const allSections = React36__default.useMemo(() => {
12466
11292
  const byCategory = /* @__PURE__ */ new Map();
12467
11293
  const loose = [];
12468
11294
  for (const p of items) {
@@ -12490,7 +11316,7 @@ function MenuPage() {
12490
11316
  }
12491
11317
  return ordered;
12492
11318
  }, [items, cats]);
12493
- const highlights = React39__default.useMemo(
11319
+ const highlights = React36__default.useMemo(
12494
11320
  () => pickHighlights(items, {
12495
11321
  listingFeaturedIds: featured.data?.listing,
12496
11322
  menuFeaturedIds: featured.data?.menu,
@@ -12499,7 +11325,7 @@ function MenuPage() {
12499
11325
  [items, featured.data, config.delivery?.highlightSlugs]
12500
11326
  );
12501
11327
  const normalized = query.trim().toLowerCase();
12502
- const sections = React39__default.useMemo(() => {
11328
+ const sections = React36__default.useMemo(() => {
12503
11329
  if (!normalized) return allSections;
12504
11330
  return allSections.map((section) => ({
12505
11331
  ...section,
@@ -12672,7 +11498,7 @@ function MenuPage() {
12672
11498
  );
12673
11499
  }
12674
11500
  function BottomBarSpace() {
12675
- React39__default.useEffect(() => {
11501
+ React36__default.useEffect(() => {
12676
11502
  const root = document.documentElement;
12677
11503
  root.style.setProperty("--fayz-bottom-bar", "4.5rem");
12678
11504
  return () => {
@@ -12813,20 +11639,20 @@ var GRID_COLS = {
12813
11639
  3: "sm:grid-cols-3",
12814
11640
  4: "sm:grid-cols-4"
12815
11641
  };
12816
- function OrderTrackingTimeline({ order, compact: compact2 = false }) {
11642
+ function OrderTrackingTimeline({ order, compact = false }) {
12817
11643
  const steps = orderTrackingSteps(order);
12818
11644
  return /* @__PURE__ */ jsx(
12819
11645
  "ol",
12820
11646
  {
12821
11647
  "data-testid": TID.orderTracking,
12822
- className: `grid ${compact2 ? "gap-2" : "gap-3"} ${GRID_COLS[steps.length] ?? "sm:grid-cols-4"}`,
11648
+ className: `grid ${compact ? "gap-2" : "gap-3"} ${GRID_COLS[steps.length] ?? "sm:grid-cols-4"}`,
12823
11649
  "aria-label": "Acompanhamento do pedido",
12824
11650
  children: steps.map((step) => {
12825
11651
  const Icon2 = step.icon;
12826
11652
  const cancelled = step.state === "cancelled";
12827
11653
  const done = step.state === "complete";
12828
11654
  const current = step.state === "current";
12829
- const active2 = done || current;
11655
+ const active = done || current;
12830
11656
  return /* @__PURE__ */ jsx(
12831
11657
  "li",
12832
11658
  {
@@ -12834,8 +11660,8 @@ function OrderTrackingTimeline({ order, compact: compact2 = false }) {
12834
11660
  "data-state": step.state,
12835
11661
  className: [
12836
11662
  "relative min-w-0 rounded-xl border p-3",
12837
- cancelled ? "border-destructive/40 bg-destructive/10" : active2 ? "border-primary/35 bg-primary/5" : "bg-muted/20 text-muted-foreground",
12838
- compact2 ? "text-xs" : "text-sm"
11663
+ cancelled ? "border-destructive/40 bg-destructive/10" : active ? "border-primary/35 bg-primary/5" : "bg-muted/20 text-muted-foreground",
11664
+ compact ? "text-xs" : "text-sm"
12839
11665
  ].join(" "),
12840
11666
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
12841
11667
  /* @__PURE__ */ jsx(
@@ -12867,7 +11693,7 @@ var menuItems = [
12867
11693
  { id: "addresses", label: "Endere\xE7os", icon: MapPin },
12868
11694
  { id: "payments", label: "Pagamentos", icon: CreditCard }
12869
11695
  ];
12870
- function CustomerAccountShell({ title, subtitle, active: active2, onSelect, children }) {
11696
+ function CustomerAccountShell({ title, subtitle, active, onSelect, children }) {
12871
11697
  const config = useStorefrontConfig();
12872
11698
  const session = useSessionStore();
12873
11699
  const displayName = session.name || session.email?.split("@")[0] || "Cliente";
@@ -12892,7 +11718,7 @@ function CustomerAccountShell({ title, subtitle, active: active2, onSelect, chil
12892
11718
  ] }),
12893
11719
  /* @__PURE__ */ jsx("nav", { "data-testid": TID.customerAccountMenu, className: "mt-4 space-y-1", "aria-label": "\xC1rea do cliente", children: menuItems.map((item) => {
12894
11720
  const Icon2 = item.icon;
12895
- const selected = item.id === active2;
11721
+ const selected = item.id === active;
12896
11722
  return /* @__PURE__ */ jsxs(
12897
11723
  Link,
12898
11724
  {
@@ -12963,7 +11789,7 @@ function OrderConfirmationPage({ orderId }) {
12963
11789
  const [loading, setLoading] = useState(true);
12964
11790
  const money = (v) => formatMoney(v, config.currency, config.locale);
12965
11791
  useStorefrontHead({ title: order ? `Pedido #${order.orderNumber} \u2014 ${config.name}` : config.name });
12966
- const reload = React39__default.useCallback(() => {
11792
+ const reload = React36__default.useCallback(() => {
12967
11793
  let cancelled = false;
12968
11794
  getShopProvider().getOrder(orderId).then((o) => {
12969
11795
  if (!cancelled) setOrder(o);
@@ -12992,7 +11818,7 @@ function OrderConfirmationPage({ orderId }) {
12992
11818
  ] }, column)) }),
12993
11819
  /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
12994
11820
  /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-32" }),
12995
- /* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React39__default.Fragment, { children: [
11821
+ /* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React36__default.Fragment, { children: [
12996
11822
  /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-7 shrink-0 rounded-full" }),
12997
11823
  node < 3 && /* @__PURE__ */ jsx(Skeleton, { className: "h-px flex-1" })
12998
11824
  ] }, node)) })
@@ -13279,7 +12105,7 @@ function OrdersPanel() {
13279
12105
  /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-24 rounded-full" })
13280
12106
  ] }),
13281
12107
  /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3 w-20" }),
13282
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React39__default.Fragment, { children: [
12108
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React36__default.Fragment, { children: [
13283
12109
  /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-6 shrink-0 rounded-full" }),
13284
12110
  node < 3 && /* @__PURE__ */ jsx(Skeleton, { className: "h-px flex-1" })
13285
12111
  ] }, node)) }),
@@ -13358,7 +12184,7 @@ function ProfilePanel() {
13358
12184
  const [saving, setSaving] = useState(false);
13359
12185
  const [saved, setSaved] = useState(false);
13360
12186
  const [error, setError] = useState(null);
13361
- React39__default.useEffect(() => {
12187
+ React36__default.useEffect(() => {
13362
12188
  if (!supported) return;
13363
12189
  let cancelled = false;
13364
12190
  provider.getMyProfile().then((p) => {
@@ -13651,7 +12477,7 @@ function PolicyPage({ kind }) {
13651
12477
  ] }) })
13652
12478
  ] });
13653
12479
  }
13654
- var StorefrontErrorBoundary = class extends React39__default.Component {
12480
+ var StorefrontErrorBoundary = class extends React36__default.Component {
13655
12481
  constructor() {
13656
12482
  super(...arguments);
13657
12483
  this.state = { error: null };
@@ -13940,1334 +12766,6 @@ function createStorefront(options) {
13940
12766
  return createStorefrontApp(config);
13941
12767
  }
13942
12768
 
13943
- // src/document/sections.ts
13944
- var STORE_DOCUMENT_KIND = "fayz.store";
13945
- var STORE_COMMERCE_MODES = ["checkout", "catalog", "enquiry", "delivery"];
13946
- var STORE_PAYMENT_MODES = ["mock", "pix-mercadopago", "gateway"];
13947
- var STORE_PAYMENT_METHOD_KINDS = [
13948
- "pix",
13949
- "credit_card",
13950
- "debit_card",
13951
- "boleto",
13952
- "cash",
13953
- "other"
13954
- ];
13955
- var STORE_BACKEND_PROVIDERS = ["mock", "fayz-api", "fayz-shop", "custom"];
13956
- var STORE_ROUTE_KINDS = [
13957
- "home",
13958
- "catalog",
13959
- "product",
13960
- "checkout",
13961
- "account",
13962
- "order",
13963
- "custom"
13964
- ];
13965
- var STORE_ROUTE_CHROMES = ["default", "minimal", "focused"];
13966
- var STORE_THEME_RADII = ["none", "soft", "round", "pill"];
13967
- var f = (type, description, extra = {}) => ({ type, description, ...extra });
13968
- var STORE_SECTIONS = {
13969
- store: {
13970
- description: "Store identity: name, currency, locale.",
13971
- versions: [1],
13972
- fields: {
13973
- name: f("string", "Store display name (header, page title).", { required: true }),
13974
- currency: f("string", "ISO 4217 currency code \u2014 default 'BRL'."),
13975
- locale: f("string", "Intl locale for money/date formatting \u2014 default 'pt-BR'.")
13976
- }
13977
- },
13978
- theme: {
13979
- description: "Visual identity: colors, fonts, radius, header/card personality.",
13980
- versions: [1],
13981
- fields: {
13982
- name: f("string", "Theme name.", { required: true }),
13983
- colors: f("object", "HSL token triplets (background, primary, \u2026)."),
13984
- font: f("object", "Google Fonts pairing (heading, body, display, serif)."),
13985
- radius: f("string", "Corner radius scale.", { enum: STORE_THEME_RADII }),
13986
- header: f("object", "Header treatment (variant, uppercaseNav, search)."),
13987
- productCard: f("object", "Card style and image aspect."),
13988
- uppercaseButtons: f("boolean", "Uppercase CTA buttons with letter-spacing."),
13989
- spacing: f("object", "Spacing scale (key \u2192 CSS length), emitted as --sf-space-<key>. e.g. {sm:'8px', md:'16px'}."),
13990
- typeScale: f("object", "Type scale (key \u2192 CSS font-size), emitted as --sf-text-<key>. e.g. {body:'1rem', h1:'clamp(40px,6vw,66px)'}."),
13991
- breakpoints: f("object", "Layout breakpoints (key \u2192 CSS length), emitted as --sf-breakpoint-<key> for JS/generated-style consumers."),
13992
- motion: f("object", "Motion tokens (key \u2192 duration or easing), emitted as --sf-motion-<key>. e.g. {fast:'150ms', reveal:'cubic-bezier(0.22,1,0.36,1)'}."),
13993
- tokens: f("object", "Free-form brand-token passthrough, emitted verbatim as CSS custom properties.")
13994
- }
13995
- },
13996
- commerce: {
13997
- description: "Commercial behavior: mode, shipping, payments, discounts, enquiry, feature toggles.",
13998
- // v2 = the legacy `discounts` coupon list has been migrated onto the rule
13999
- // engine (codemod commerce.discounts-to-promotions). Both versions are
14000
- // understood, which is the whole point: the fleet migrates store by store.
14001
- versions: [1, 2],
14002
- fields: {
14003
- commerceMode: f("string", "Checkout-first, catalog-only browsing, or product enquiry.", {
14004
- enum: STORE_COMMERCE_MODES
14005
- }),
14006
- shipping: f("object", "Flat rate and free-above threshold."),
14007
- payments: f("object", "Payment mode and offered methods."),
14008
- discounts: f("array", "DEPRECATED \u2014 store-level discount codes ({code, percent, title?}). Use promotions.promotions.", {
14009
- deprecated: {
14010
- id: "storefront.commerce.discounts",
14011
- removedAtVersion: 2,
14012
- replacement: "promotions.promotions"
14013
- }
14014
- }),
14015
- enquiry: f("object", "Product enquiry behavior for catalog/enquiry stores."),
14016
- features: f("object", "Feature toggles (discounts, accounts, cart, checkout).")
14017
- }
14018
- },
14019
- presentation: {
14020
- description: "What the shopper sees: composed pages, slots, nav, footer, chrome.",
14021
- versions: [1],
14022
- fields: {
14023
- announcement: f("string", "Promo message above the header."),
14024
- logo: f("string", "Text logo. A JSX logo is code and lives at code.logo."),
14025
- home: f("object", "Home page blueprint (legacy short form of pages.home)."),
14026
- pages: f("object", "Pages composed from blocks, keyed by page kind."),
14027
- slots: f("object", "Blocks grafted into named positions inside SDK pages."),
14028
- nav: f("array", "Header nav links ({label, to})."),
14029
- footer: f("object", "Footer content (about, contact, social, labels)."),
14030
- imageLoading: f("object", "Global image reveal behavior."),
14031
- catalogFacets: f(
14032
- "array",
14033
- "Catalog refinements over product.metadata ({key, label, values[]}), rendered in the filters panel and mirrored into ?<key>=<value>."
14034
- ),
14035
- productSpecs: f(
14036
- "object",
14037
- "PDP specification table rules: `exclude` hides metadata keys, `labels` renames the rest."
14038
- ),
14039
- search: f(
14040
- "object",
14041
- "Header search: mode ('inline' live filter, the default, or 'overlay'), plus placeholder, resultsPath, suggestionsLimit, minChars and labels. A custom suggestion renderer is code and lives at code.searchRenderSuggestion."
14042
- )
14043
- }
14044
- },
14045
- content: {
14046
- description: "Long-form content: legal/institutional pages, product reviews.",
14047
- versions: [1],
14048
- fields: {
14049
- legal: f("object", "Privacy / terms / returns page text."),
14050
- reviews: f(
14051
- "object",
14052
- "Store-supplied product reviews ({items, enabled, emptyText}). Nothing is invented \u2014 with no items the PDP renders an honest empty state."
14053
- )
14054
- }
14055
- },
14056
- catalog: {
14057
- description: "Mock catalog seed for stores without a live backend.",
14058
- versions: [1],
14059
- fields: {
14060
- products: f("array", "Seed products."),
14061
- categories: f("array", "Seed categories."),
14062
- discounts: f("array", "Seed discounts."),
14063
- promotions: f("array", "Seed rule-engine promotions for the mock provider. Prefer the top-level promotions section.")
14064
- }
14065
- },
14066
- entities: {
14067
- description: "Custom entity declarations (defineEntity inputs), keyed by entity key.",
14068
- versions: [1],
14069
- fields: {
14070
- definitions: f("object", "Entity key \u2192 declaration ({fields, scope, access, indexes, \u2026}).")
14071
- }
14072
- },
14073
- promotions: {
14074
- description: "Rule-engine promotions: eligibility rules + application method, as pure data (spine M6).",
14075
- versions: [1],
14076
- fields: {
14077
- promotions: f("array", "Promotions ({id, code?, isAutomatic?, rules?, applicationMethod}). Rule attributes come from the rule_attribute vocabulary.")
14078
- }
14079
- },
14080
- backend: {
14081
- description: "Backend descriptor: which provider serves the store.",
14082
- // v2 = the legacy supabaseUrl/supabaseAnonKey pair has moved to
14083
- // auth.supabase (codemod backend.supabase-to-auth).
14084
- versions: [1, 2],
14085
- fields: {
14086
- provider: f("string", "Backend provider family.", { enum: STORE_BACKEND_PROVIDERS }),
14087
- url: f("string", "Backend URL, when the provider needs one."),
14088
- supabaseUrl: f("string", "DEPRECATED legacy field, kept for lossless round-trip. Use auth.supabase.url.", {
14089
- deprecated: {
14090
- id: "storefront.backend.supabaseUrl",
14091
- removedAtVersion: 2,
14092
- replacement: "auth.supabase.url"
14093
- }
14094
- }),
14095
- supabaseAnonKey: f("string", "DEPRECATED legacy field, kept for lossless round-trip. Use auth.supabase.anonKey.", {
14096
- deprecated: {
14097
- id: "storefront.backend.supabaseAnonKey",
14098
- removedAtVersion: 2,
14099
- replacement: "auth.supabase.anonKey"
14100
- }
14101
- })
14102
- }
14103
- },
14104
- auth: {
14105
- description: "Customer auth, when expressible as data. Code-bearing auth lives at code.auth.",
14106
- versions: [1],
14107
- fields: {
14108
- adapter: f("string", "Adapter id ('mock' | 'supabase')."),
14109
- provider: f("string", "Provider id ('mock' | 'supabase')."),
14110
- routes: f("object", "Auth route overrides."),
14111
- supabase: f("object", "Supabase connection (url, anonKey, callback urls).")
14112
- }
14113
- },
14114
- code: {
14115
- description: "The code sidecar: config fields that hold code, referenced by registered handle name.",
14116
- versions: [1],
14117
- fields: {
14118
- logo: f("string", "Handle of the JSX logo node."),
14119
- provider: f("string", "Handle of the explicit ShopProvider."),
14120
- auth: f("string", "Handle of a code-bearing auth config."),
14121
- footerCredit: f("string", "Handle of the footer credit node."),
14122
- searchRenderSuggestion: f("string", "Handle of the custom search-suggestion renderer."),
14123
- components: f("object", "Component-slot name \u2192 handle of its override."),
14124
- routes: f("array", "Custom routes; each component is a handle name.")
14125
- }
14126
- }
14127
- };
14128
- var STORE_SECTION_NAMES = Object.keys(STORE_SECTIONS);
14129
- function sectionToJsonSchema(name) {
14130
- const spec = STORE_SECTIONS[name];
14131
- const properties = {
14132
- version: {
14133
- type: "integer",
14134
- description: `Schema version of the ${name} section. Supported: ${spec.versions.join(", ")}.`,
14135
- enum: [...spec.versions]
14136
- }
14137
- };
14138
- const required = ["version"];
14139
- for (const [field2, fieldSpec] of Object.entries(spec.fields)) {
14140
- const node = { type: fieldSpec.type, description: fieldSpec.description };
14141
- if (fieldSpec.enum) node.enum = [...fieldSpec.enum];
14142
- if (fieldSpec.deprecated) {
14143
- node.deprecated = true;
14144
- node["x-fayz-deprecation"] = fieldSpec.deprecated.id;
14145
- node["x-fayz-replacement"] = fieldSpec.deprecated.replacement;
14146
- node["x-fayz-removed-at-section-version"] = fieldSpec.deprecated.removedAtVersion;
14147
- }
14148
- properties[field2] = node;
14149
- if (fieldSpec.required) required.push(field2);
14150
- }
14151
- return {
14152
- type: "object",
14153
- description: spec.description,
14154
- properties,
14155
- required
14156
- };
14157
- }
14158
- function isJsonValue(value) {
14159
- if (value === null) return true;
14160
- const t = typeof value;
14161
- if (t === "string" || t === "number" || t === "boolean") return true;
14162
- if (Array.isArray(value)) return value.every(isJsonValue);
14163
- if (t === "object") {
14164
- const record = value;
14165
- if ("$$typeof" in record) return false;
14166
- const proto = Object.getPrototypeOf(record);
14167
- if (proto !== Object.prototype && proto !== null) return false;
14168
- return Object.values(record).every((v) => v === void 0 || isJsonValue(v));
14169
- }
14170
- return false;
14171
- }
14172
- function isRecord(value) {
14173
- return typeof value === "object" && value !== null && !Array.isArray(value);
14174
- }
14175
- function compact(obj) {
14176
- const out = {};
14177
- for (const [key, value] of Object.entries(obj)) {
14178
- if (value !== void 0) out[key] = value;
14179
- }
14180
- return out;
14181
- }
14182
-
14183
- // src/extend/component-contracts.ts
14184
- var STOREFRONT_COMPONENT_KEYS = [
14185
- "ProductCard",
14186
- "ProductDetail",
14187
- "ProductGallery",
14188
- "ProductPrice",
14189
- "ProductActions",
14190
- "ProductEnquiryForm",
14191
- "CategoryCard",
14192
- "CollectionSection",
14193
- "HeroSection",
14194
- "MediaCarousel",
14195
- "ProductSlider",
14196
- "Header",
14197
- "Footer",
14198
- "Shell",
14199
- "EmptyState",
14200
- "LoadingState",
14201
- "ErrorState",
14202
- "CartDrawerFooterExtra"
14203
- ];
14204
- var STOREFRONT_PAGE_KINDS = ["home", "catalog", "product", "collection", "content"];
14205
- var STRUCTURAL_BLOCK_KEYS = /* @__PURE__ */ new Set(["type", "id", "props", "children", "data"]);
14206
- var DATA_NEED_KEYS = ["loader", "params"];
14207
- var CODE_ROUTE_KEYS = ["id", "path", "kind", "chrome", "component"];
14208
- var SLOT_AREAS = [...new Set(STOREFRONT_SLOTS.map((slot) => slot.area))];
14209
- function slotNamesFor(area) {
14210
- return STOREFRONT_SLOTS.filter((slot) => slot.area === area).map((slot) => slot.name);
14211
- }
14212
- var PAGE_KIND_PARAMS = {
14213
- home: [],
14214
- catalog: [],
14215
- product: ["slug"],
14216
- collection: ["slug"]
14217
- };
14218
- var SLOT_AREA_PARAMS = {
14219
- productDetail: ["slug"]
14220
- };
14221
- var knownEntities = /* @__PURE__ */ new Set();
14222
- function checkEntityRef(errors, path, value) {
14223
- if (typeof value !== "string" || !value) return;
14224
- if (!knownEntities.has(value)) {
14225
- push(
14226
- errors,
14227
- path,
14228
- "unknown-entity",
14229
- `entity "${value}" is not declared (defineEntity or the entities section)`,
14230
- [...knownEntities].sort()
14231
- );
14232
- }
14233
- }
14234
- function push(errors, path, code, message, valid) {
14235
- errors.push(valid ? { path, code, message, valid: [...valid] } : { path, code, message });
14236
- }
14237
- function blockPropKeys(entry) {
14238
- if ("props" in entry) {
14239
- const props = entry.props;
14240
- return isRecord(props) ? Object.keys(props) : [];
14241
- }
14242
- return Object.keys(entry).filter((key) => !STRUCTURAL_BLOCK_KEYS.has(key));
14243
- }
14244
- function validateSettingValues(errors, valuesPath, settings, values, owner, labelPrefix = "") {
14245
- for (const setting of settings) {
14246
- const value = values[setting.id];
14247
- if (value === void 0) continue;
14248
- const valuePath = `${valuesPath}.${setting.id}`;
14249
- const label = `${labelPrefix}${setting.id}`;
14250
- if (setting.type === "entity") {
14251
- checkEntityRef(errors, valuePath, value);
14252
- continue;
14253
- }
14254
- if (setting.type !== "list" || !setting.of?.length || !Array.isArray(value)) continue;
14255
- const of = setting.of;
14256
- const declared = collectSettingIds(of);
14257
- value.forEach((item, index) => {
14258
- if (!isRecord(item)) return;
14259
- const itemPath = `${valuePath}[${index}]`;
14260
- for (const key of Object.keys(item)) {
14261
- if (!declared.has(key)) {
14262
- push(
14263
- errors,
14264
- `${itemPath}.${key}`,
14265
- owner.code,
14266
- `${owner.subject} declares no ${owner.noun} "${label}[].${key}"`,
14267
- [...declared].sort()
14268
- );
14269
- }
14270
- }
14271
- validateSettingValues(errors, itemPath, of, item, owner, `${label}[].`);
14272
- });
14273
- }
14274
- }
14275
- function checkLiteralParam(errors, path, containerPath, loaderId, setting, value) {
14276
- const expected = setting.type === "number" ? "number" : setting.type === "boolean" ? "boolean" : setting.type === "list" ? "array" : "string";
14277
- const actual = Array.isArray(value) ? "array" : typeof value;
14278
- if (actual !== expected) {
14279
- push(
14280
- errors,
14281
- path,
14282
- "invalid-value",
14283
- `loader "${loaderId}" param "${setting.id}" expects ${expected}, got ${actual}`
14284
- );
14285
- return;
14286
- }
14287
- if (setting.type === "select" && setting.options?.length && typeof value === "string") {
14288
- const allowed = setting.options.map((option) => option.value);
14289
- if (!allowed.includes(value)) {
14290
- push(errors, path, "invalid-value", `"${value}" is not a valid ${setting.id}`, allowed);
14291
- }
14292
- }
14293
- if (setting.type === "entity") checkEntityRef(errors, path, value);
14294
- if (setting.type === "list") {
14295
- validateSettingValues(
14296
- errors,
14297
- containerPath,
14298
- [setting],
14299
- { [setting.id]: value },
14300
- { subject: `loader "${loaderId}"`, noun: "param", code: "unknown-loader-param" }
14301
- );
14302
- }
14303
- }
14304
- function validateDataNeeds(errors, entryPath, blockType, value, declaredParams) {
14305
- if (!isRecord(value)) {
14306
- push(errors, `${entryPath}.data`, "invalid-value", "`data` maps need names to {loader, params?}");
14307
- return;
14308
- }
14309
- const blockSettings = getBlockMeta(blockType)?.settings;
14310
- for (const [name, need] of Object.entries(value)) {
14311
- const needPath = `${entryPath}.data.${name}`;
14312
- if (!isRecord(need) || typeof need.loader !== "string" || !need.loader) {
14313
- push(errors, needPath, "invalid-value", "a data need is {loader: string, params?: object}");
14314
- continue;
14315
- }
14316
- if (!loaderRegistry.has(need.loader)) {
14317
- push(errors, `${needPath}.loader`, "unknown-loader", `loader "${need.loader}" is not registered`, listLoaders());
14318
- continue;
14319
- }
14320
- for (const key of Object.keys(need)) {
14321
- if (!DATA_NEED_KEYS.includes(key)) {
14322
- push(errors, `${needPath}.${key}`, "unknown-field", `a data need has no field "${key}"`, DATA_NEED_KEYS);
14323
- }
14324
- }
14325
- if (need.params === void 0) continue;
14326
- if (!isRecord(need.params)) {
14327
- push(errors, `${needPath}.params`, "invalid-value", "loader params are an object");
14328
- continue;
14329
- }
14330
- const loaderSettings = loaderRegistry.getEntry(need.loader)?.meta.settings;
14331
- const declaredLoaderParams = loaderSettings ? collectSettingIds(loaderSettings) : null;
14332
- for (const [param, paramValue] of Object.entries(need.params)) {
14333
- const paramPath = `${needPath}.params.${param}`;
14334
- const setting = loaderSettings?.find((s2) => s2.id === param);
14335
- if (declaredLoaderParams && !declaredLoaderParams.has(param)) {
14336
- push(
14337
- errors,
14338
- paramPath,
14339
- "unknown-loader-param",
14340
- `loader "${need.loader}" declares no param "${param}"`,
14341
- [...declaredLoaderParams].sort()
14342
- );
14343
- continue;
14344
- }
14345
- if (isLoaderParamRef(paramValue)) {
14346
- if (!declaredParams.includes(paramValue.$param)) {
14347
- push(
14348
- errors,
14349
- paramPath,
14350
- "unbound-route-param",
14351
- declaredParams.length ? `$param "${paramValue.$param}" is not a route param of this page` : `$param "${paramValue.$param}" cannot bind \u2014 this page declares no route params`,
14352
- declaredParams
14353
- );
14354
- }
14355
- continue;
14356
- }
14357
- if (isLoaderPropRef(paramValue)) {
14358
- const settingIds = blockSettings ? collectSettingIds(blockSettings) : null;
14359
- if (settingIds && !settingIds.has(paramValue.$prop)) {
14360
- push(
14361
- errors,
14362
- paramPath,
14363
- "unknown-prop-binding",
14364
- `$prop "${paramValue.$prop}" is not a setting of block "${blockType}"`,
14365
- [...settingIds].sort()
14366
- );
14367
- }
14368
- continue;
14369
- }
14370
- if (setting) {
14371
- checkLiteralParam(errors, paramPath, `${needPath}.params`, need.loader, setting, paramValue);
14372
- }
14373
- }
14374
- }
14375
- }
14376
- function validateBlockList(errors, path, value, declaredParams) {
14377
- if (!Array.isArray(value)) {
14378
- push(errors, path, "invalid-value", `expected an array of blocks, got ${typeof value}`);
14379
- return;
14380
- }
14381
- value.forEach((entry, index) => {
14382
- const entryPath = `${path}[${index}]`;
14383
- if (!isRecord(entry)) {
14384
- push(errors, entryPath, "invalid-value", "a block entry must be an object with a `type`");
14385
- return;
14386
- }
14387
- const type = entry.type;
14388
- if (typeof type !== "string" || !type) {
14389
- push(errors, `${entryPath}.type`, "invalid-value", "a block entry must declare a string `type`");
14390
- return;
14391
- }
14392
- if (!blockRegistry.has(type)) {
14393
- push(
14394
- errors,
14395
- `${entryPath}.type`,
14396
- "unknown-block",
14397
- `block "${type}" is not registered`,
14398
- blockRegistry.ids().sort()
14399
- );
14400
- return;
14401
- }
14402
- const settings = getBlockMeta(type)?.settings;
14403
- if (settings) {
14404
- const declared = collectSettingIds(settings);
14405
- for (const key of blockPropKeys(entry)) {
14406
- if (!declared.has(key)) {
14407
- push(
14408
- errors,
14409
- `${entryPath}.props.${key}`,
14410
- "unknown-setting",
14411
- `block "${type}" declares no setting "${key}"`,
14412
- [...declared].sort()
14413
- );
14414
- }
14415
- }
14416
- const props = isRecord(entry.props) ? entry.props : entry;
14417
- validateSettingValues(errors, `${entryPath}.props`, settings, props, {
14418
- subject: `block "${type}"`,
14419
- noun: "setting",
14420
- code: "unknown-setting"
14421
- });
14422
- }
14423
- if ("data" in entry && entry.data !== void 0) {
14424
- validateDataNeeds(errors, entryPath, type, entry.data, declaredParams);
14425
- }
14426
- if ("children" in entry && entry.children !== void 0) {
14427
- validateBlockList(errors, `${entryPath}.children`, entry.children, declaredParams);
14428
- }
14429
- });
14430
- }
14431
- function validateBlockTree(errors, path, value, declaredParams = []) {
14432
- validateBlockList(errors, path, value, declaredParams);
14433
- if (!Array.isArray(value)) return;
14434
- const nodes = toBlockNodes(value);
14435
- for (const violation of checkBlockConstraints(nodes)) {
14436
- push(errors, `${path}${violation.path}`, violation.rule, violation.detail, violation.valid);
14437
- }
14438
- }
14439
- function collectSettingIds(settings) {
14440
- return new Set(settings.map((setting) => setting.id));
14441
- }
14442
- var TOKEN_KEY = /^[a-zA-Z][a-zA-Z0-9-]*$/;
14443
- function validateTheme(errors, section) {
14444
- for (const field2 of THEME_SCALE_FIELDS) {
14445
- const scale = section[field2];
14446
- if (scale === void 0) continue;
14447
- if (!isRecord(scale)) continue;
14448
- for (const [key, value] of Object.entries(scale)) {
14449
- const path = `theme.${field2}.${key}`;
14450
- if (!TOKEN_KEY.test(key)) {
14451
- push(
14452
- errors,
14453
- path,
14454
- "invalid-token-key",
14455
- `"${key}" cannot become the CSS custom property ${THEME_SCALE_VAR_PREFIX[field2]}-${key} \u2014 token keys match ${TOKEN_KEY}`
14456
- );
14457
- }
14458
- if (typeof value !== "string") {
14459
- push(errors, path, "invalid-value", `a ${field2} token is a CSS value string, got ${typeof value}`);
14460
- }
14461
- }
14462
- }
14463
- }
14464
- function validateSectionEnvelope(errors, name, section) {
14465
- const spec = STORE_SECTIONS[name];
14466
- const version = section.version;
14467
- if (typeof version !== "number" || !spec.versions.includes(version)) {
14468
- push(
14469
- errors,
14470
- `${name}.version`,
14471
- "unsupported-section-version",
14472
- `section "${name}" declares version ${JSON.stringify(version)}, which this SDK does not understand`,
14473
- spec.versions.map(String)
14474
- );
14475
- return false;
14476
- }
14477
- const fieldNames = Object.keys(spec.fields);
14478
- for (const key of Object.keys(section)) {
14479
- if (key === "version") continue;
14480
- const fieldSpec = spec.fields[key];
14481
- if (!fieldSpec) {
14482
- push(errors, `${name}.${key}`, "unknown-field", `section "${name}" has no field "${key}"`, fieldNames);
14483
- continue;
14484
- }
14485
- const deprecated = fieldSpec.deprecated;
14486
- if (deprecated && version >= deprecated.removedAtVersion) {
14487
- push(
14488
- errors,
14489
- `${name}.${key}`,
14490
- "removed-field",
14491
- `field "${name}.${key}" was removed at ${name} version ${deprecated.removedAtVersion} (deprecation ${deprecated.id}); this section declares version ${version}`,
14492
- [deprecated.replacement]
14493
- );
14494
- continue;
14495
- }
14496
- const value = section[key];
14497
- const actual = Array.isArray(value) ? "array" : typeof value;
14498
- if (actual !== fieldSpec.type) {
14499
- push(
14500
- errors,
14501
- `${name}.${key}`,
14502
- "invalid-value",
14503
- `field "${name}.${key}" expects ${fieldSpec.type}, got ${actual}`
14504
- );
14505
- continue;
14506
- }
14507
- if (fieldSpec.enum && typeof value === "string" && !fieldSpec.enum.includes(value)) {
14508
- push(
14509
- errors,
14510
- `${name}.${key}`,
14511
- "invalid-value",
14512
- `"${value}" is not a valid ${name}.${key}`,
14513
- fieldSpec.enum
14514
- );
14515
- }
14516
- }
14517
- for (const [field2, fieldSpec] of Object.entries(spec.fields)) {
14518
- if (fieldSpec.required && section[field2] === void 0) {
14519
- push(errors, `${name}.${field2}`, "missing-field", `section "${name}" requires "${field2}"`);
14520
- }
14521
- }
14522
- return true;
14523
- }
14524
- function validateCommerce(errors, section) {
14525
- const payments = section.payments;
14526
- if (isRecord(payments)) {
14527
- if (payments.mode !== void 0) {
14528
- if (typeof payments.mode !== "string" || !STORE_PAYMENT_MODES.includes(payments.mode)) {
14529
- push(
14530
- errors,
14531
- "commerce.payments.mode",
14532
- "invalid-value",
14533
- `"${String(payments.mode)}" is not a payment mode`,
14534
- STORE_PAYMENT_MODES
14535
- );
14536
- }
14537
- }
14538
- if (payments.methods !== void 0) {
14539
- if (!Array.isArray(payments.methods)) {
14540
- push(errors, "commerce.payments.methods", "invalid-value", "payments.methods must be an array");
14541
- } else {
14542
- payments.methods.forEach((method, index) => {
14543
- if (typeof method !== "string" || !STORE_PAYMENT_METHOD_KINDS.includes(method)) {
14544
- push(
14545
- errors,
14546
- `commerce.payments.methods[${index}]`,
14547
- "invalid-value",
14548
- `"${String(method)}" is not a payment method`,
14549
- STORE_PAYMENT_METHOD_KINDS
14550
- );
14551
- }
14552
- });
14553
- }
14554
- }
14555
- }
14556
- const discounts = section.discounts;
14557
- if (Array.isArray(discounts)) {
14558
- discounts.forEach((discount, index) => {
14559
- if (!isRecord(discount) || typeof discount.code !== "string" || typeof discount.percent !== "number") {
14560
- push(
14561
- errors,
14562
- `commerce.discounts[${index}]`,
14563
- "invalid-value",
14564
- "a discount is {code: string, percent: number, title?: string}"
14565
- );
14566
- }
14567
- });
14568
- }
14569
- }
14570
- var CONTENT_SLUG = /^[a-z0-9][a-z0-9-]*$/;
14571
- function validateContentPages(errors, basePath, value) {
14572
- if (!isRecord(value)) {
14573
- push(errors, basePath, "invalid-value", "pages.content maps slugs to {title?, path?, blocks: [...]}");
14574
- return;
14575
- }
14576
- const pathOwners = /* @__PURE__ */ new Map();
14577
- for (const [slug, page] of Object.entries(value)) {
14578
- const pagePath = `${basePath}.${slug}`;
14579
- if (!CONTENT_SLUG.test(slug)) {
14580
- push(
14581
- errors,
14582
- pagePath,
14583
- "invalid-value",
14584
- `"${slug}" cannot become the route "/${slug}" \u2014 content slugs match ${CONTENT_SLUG}`
14585
- );
14586
- }
14587
- if (!isRecord(page) || page.blocks === void 0) {
14588
- push(errors, pagePath, "invalid-value", "a content page is {title?, path?, blocks: [...]}");
14589
- continue;
14590
- }
14591
- if (page.title !== void 0 && typeof page.title !== "string") {
14592
- push(errors, `${pagePath}.title`, "invalid-value", `title expects string, got ${typeof page.title}`);
14593
- }
14594
- let routePath = `/${slug}`;
14595
- if (page.path !== void 0) {
14596
- if (typeof page.path !== "string" || !page.path.startsWith("/")) {
14597
- push(errors, `${pagePath}.path`, "invalid-value", `path is an absolute route ('/${slug}'), got ${JSON.stringify(page.path)}`);
14598
- } else {
14599
- routePath = page.path;
14600
- }
14601
- }
14602
- const owner = pathOwners.get(routePath);
14603
- if (owner) {
14604
- push(
14605
- errors,
14606
- `${pagePath}.path`,
14607
- "duplicate-content-path",
14608
- `content pages "${owner}" and "${slug}" both resolve to "${routePath}" \u2014 one of them can never render`
14609
- );
14610
- } else {
14611
- pathOwners.set(routePath, slug);
14612
- }
14613
- validateBlockTree(errors, `${pagePath}.blocks`, page.blocks, routePathParams(routePath));
14614
- }
14615
- }
14616
- function validatePresentation(errors, section) {
14617
- const home = section.home;
14618
- if (isRecord(home) && home.sections !== void 0) {
14619
- validateBlockTree(errors, "presentation.home.sections", home.sections);
14620
- }
14621
- const pages = section.pages;
14622
- if (isRecord(pages)) {
14623
- const validKinds = [...STOREFRONT_PAGE_KINDS];
14624
- for (const [kind, page] of Object.entries(pages)) {
14625
- const pagePath = `presentation.pages.${kind}`;
14626
- if (!validKinds.includes(kind)) {
14627
- push(errors, pagePath, "unknown-page-kind", `"${kind}" is not a composable page kind`, validKinds);
14628
- continue;
14629
- }
14630
- if (kind === "content") {
14631
- validateContentPages(errors, pagePath, page);
14632
- continue;
14633
- }
14634
- if (!isRecord(page) || page.blocks === void 0) {
14635
- push(errors, pagePath, "invalid-value", "a composed page is {blocks: [...]}");
14636
- continue;
14637
- }
14638
- validateBlockTree(errors, `${pagePath}.blocks`, page.blocks, PAGE_KIND_PARAMS[kind] ?? []);
14639
- }
14640
- }
14641
- const slots = section.slots;
14642
- if (isRecord(slots)) {
14643
- for (const [area, areaSlots] of Object.entries(slots)) {
14644
- const areaPath = `presentation.slots.${area}`;
14645
- if (!SLOT_AREAS.includes(area)) {
14646
- push(errors, areaPath, "unknown-slot-area", `"${area}" is not a slot area`, SLOT_AREAS);
14647
- continue;
14648
- }
14649
- if (!isRecord(areaSlots)) {
14650
- push(errors, areaPath, "invalid-value", "a slot area maps slot names to block lists");
14651
- continue;
14652
- }
14653
- const validNames = slotNamesFor(area);
14654
- for (const [slotName, blocks] of Object.entries(areaSlots)) {
14655
- const slotPath = `${areaPath}.${slotName}`;
14656
- if (!validNames.includes(slotName)) {
14657
- push(errors, slotPath, "unknown-slot", `"${area}.${slotName}" is not a slot`, validNames);
14658
- continue;
14659
- }
14660
- validateBlockTree(errors, slotPath, blocks, SLOT_AREA_PARAMS[area] ?? []);
14661
- }
14662
- }
14663
- }
14664
- }
14665
- var ENTITY_KEY_RE = /^[a-z][a-z0-9_]*$/;
14666
- var ENTITY_FIELD_RE = /^[a-z][a-z0-9_]*$/;
14667
- function validateEntitiesSection(errors, section) {
14668
- const definitions = section.definitions;
14669
- if (definitions === void 0 || !isRecord(definitions)) return;
14670
- for (const [key, declaration] of Object.entries(definitions)) {
14671
- const path = `entities.definitions.${key}`;
14672
- if (!ENTITY_KEY_RE.test(key)) {
14673
- push(errors, path, "invalid-value", `"${key}" is not a valid entity key \u2014 keys are snake_case`);
14674
- }
14675
- if (!isRecord(declaration) || !isRecord(declaration.fields) || Object.keys(declaration.fields).length === 0) {
14676
- push(errors, path, "invalid-value", "an entity declaration is {fields: {<name>: {type, \u2026}}, scope?, access?, indexes?}");
14677
- continue;
14678
- }
14679
- const fields = declaration.fields;
14680
- const fieldNames = Object.keys(fields);
14681
- for (const [name, field2] of Object.entries(fields)) {
14682
- const fieldPath = `${path}.fields.${name}`;
14683
- if (!ENTITY_FIELD_RE.test(name)) {
14684
- push(errors, fieldPath, "invalid-value", `"${name}" is not a valid field name \u2014 fields are snake_case`);
14685
- }
14686
- if (RESERVED_ENTITY_FIELDS.includes(name)) {
14687
- push(errors, fieldPath, "invalid-value", `"${name}" is a structural record column`, RESERVED_ENTITY_FIELDS);
14688
- continue;
14689
- }
14690
- if (!isRecord(field2) || typeof field2.type !== "string") {
14691
- push(errors, fieldPath, "invalid-value", "a field is {type: <entity field type>, label?, required?, \u2026}");
14692
- continue;
14693
- }
14694
- if (!ENTITY_FIELD_TYPES.includes(field2.type)) {
14695
- push(errors, `${fieldPath}.type`, "unknown-entity-field-type", `"${field2.type}" is not an entity field type`, ENTITY_FIELD_TYPES);
14696
- continue;
14697
- }
14698
- if (field2.type === "ref") {
14699
- if (typeof field2.entity !== "string" || !field2.entity) {
14700
- push(errors, fieldPath, "invalid-value", `a ref field names its target: {type: 'ref', entity: '<key>'}`);
14701
- } else {
14702
- checkEntityRef(errors, `${fieldPath}.entity`, field2.entity);
14703
- }
14704
- }
14705
- }
14706
- const scope = declaration.scope;
14707
- if (scope !== void 0 && scope !== "tenant") {
14708
- push(errors, `${path}.scope`, "invalid-value", `"${String(scope)}" is not an entity scope`, ["tenant"]);
14709
- }
14710
- const access = declaration.access;
14711
- if (access !== void 0) {
14712
- if (!isRecord(access)) {
14713
- push(errors, `${path}.access`, "invalid-value", "access is {read: 'public'|'staff', write: 'staff'}");
14714
- } else {
14715
- if (access.read !== void 0 && access.read !== "public" && access.read !== "staff") {
14716
- push(errors, `${path}.access.read`, "invalid-value", `"${String(access.read)}" is not a read access level`, ["public", "staff"]);
14717
- }
14718
- if (access.write !== void 0 && access.write !== "staff") {
14719
- push(errors, `${path}.access.write`, "invalid-value", `"${String(access.write)}" is not a write access level \u2014 shopper writes go through actions (M7), not RLS`, ["staff"]);
14720
- }
14721
- }
14722
- }
14723
- const references = (where, name) => {
14724
- if (typeof name !== "string" || !fieldNames.includes(name)) {
14725
- push(errors, `${path}.${where}`, "invalid-value", `${where} references undeclared field "${String(name)}"`, fieldNames);
14726
- }
14727
- };
14728
- if (Array.isArray(declaration.indexes)) {
14729
- declaration.indexes.forEach((tuple, i) => {
14730
- if (!Array.isArray(tuple)) {
14731
- push(errors, `${path}.indexes[${i}]`, "invalid-value", "an index is an array of declared field names");
14732
- return;
14733
- }
14734
- for (const name of tuple) references(`indexes[${i}]`, name);
14735
- });
14736
- }
14737
- if (declaration.titleField !== void 0) references("titleField", declaration.titleField);
14738
- if (Array.isArray(declaration.displayFields)) {
14739
- for (const name of declaration.displayFields) references("displayFields", name);
14740
- }
14741
- }
14742
- }
14743
- function validatePromotionRule(errors, path, rule) {
14744
- if (!isRecord(rule) || typeof rule.attribute !== "string" || typeof rule.operator !== "string") {
14745
- push(errors, path, "invalid-value", "a rule is {attribute, operator, values: [...]}");
14746
- return;
14747
- }
14748
- if (!hasRuleAttribute(rule.attribute)) {
14749
- push(
14750
- errors,
14751
- `${path}.attribute`,
14752
- "unknown-rule-attribute",
14753
- `"${rule.attribute}" is not in the rule attribute vocabulary`,
14754
- listRuleAttributeKeys()
14755
- );
14756
- return;
14757
- }
14758
- if (!RULE_OPERATORS.includes(rule.operator)) {
14759
- push(errors, `${path}.operator`, "unknown-rule-operator", `"${rule.operator}" is not a rule operator`, RULE_OPERATORS);
14760
- return;
14761
- }
14762
- const attribute = resolveRuleAttribute(rule.attribute);
14763
- if (!attribute.operators.includes(rule.operator)) {
14764
- push(
14765
- errors,
14766
- `${path}.operator`,
14767
- "unsupported-rule-operator",
14768
- `attribute "${rule.attribute}" does not support operator "${rule.operator}"`,
14769
- attribute.operators
14770
- );
14771
- }
14772
- if (!Array.isArray(rule.values) || rule.values.length === 0) {
14773
- push(errors, `${path}.values`, "invalid-value", "rule values are a non-empty array of scalars");
14774
- return;
14775
- }
14776
- rule.values.forEach((value, index) => {
14777
- const t = typeof value;
14778
- if (t !== "string" && t !== "number" && t !== "boolean") {
14779
- push(errors, `${path}.values[${index}]`, "invalid-value", `a rule value is a JSON scalar, got ${t}`);
14780
- }
14781
- });
14782
- }
14783
- function validateRuleList(errors, path, value) {
14784
- if (value === void 0) return;
14785
- if (!Array.isArray(value)) {
14786
- push(errors, path, "invalid-value", `expected an array of rules, got ${typeof value}`);
14787
- return;
14788
- }
14789
- value.forEach((rule, index) => validatePromotionRule(errors, `${path}[${index}]`, rule));
14790
- }
14791
- function validatePromotionsSection(errors, section) {
14792
- const promotions = section.promotions;
14793
- if (promotions === void 0 || !Array.isArray(promotions)) return;
14794
- promotions.forEach((promotion, index) => {
14795
- const path = `promotions.promotions[${index}]`;
14796
- if (!isRecord(promotion) || typeof promotion.id !== "string" || !promotion.id) {
14797
- push(errors, path, "invalid-value", "a promotion is {id, code?, isAutomatic?, rules?, applicationMethod}");
14798
- return;
14799
- }
14800
- if (promotion.type !== void 0 && !PROMOTION_TYPES.includes(promotion.type)) {
14801
- push(errors, `${path}.type`, "invalid-value", `"${String(promotion.type)}" is not a promotion type`, PROMOTION_TYPES);
14802
- }
14803
- if (promotion.status !== void 0 && !PROMOTION_STATUSES.includes(promotion.status)) {
14804
- push(errors, `${path}.status`, "invalid-value", `"${String(promotion.status)}" is not a promotion status`, PROMOTION_STATUSES);
14805
- }
14806
- if (promotion.code === void 0 && promotion.isAutomatic !== true) {
14807
- push(
14808
- errors,
14809
- `${path}.code`,
14810
- "invalid-value",
14811
- "a promotion needs a code or isAutomatic: true \u2014 otherwise nothing can ever trigger it"
14812
- );
14813
- }
14814
- validateRuleList(errors, `${path}.rules`, promotion.rules);
14815
- const method = promotion.applicationMethod;
14816
- if (!isRecord(method)) {
14817
- push(errors, `${path}.applicationMethod`, "invalid-value", "a promotion carries an applicationMethod ({type, value, targetType, \u2026})");
14818
- return;
14819
- }
14820
- const methodPath = `${path}.applicationMethod`;
14821
- if (typeof method.type !== "string" || !APPLICATION_METHOD_TYPES.includes(method.type)) {
14822
- push(errors, `${methodPath}.type`, "invalid-value", `"${String(method.type)}" is not an application method type`, APPLICATION_METHOD_TYPES);
14823
- }
14824
- if (typeof method.value !== "number" || method.value < 0) {
14825
- push(errors, `${methodPath}.value`, "invalid-value", "applicationMethod.value is a non-negative number");
14826
- }
14827
- if (typeof method.targetType !== "string" || !APPLICATION_METHOD_TARGET_TYPES.includes(method.targetType)) {
14828
- push(errors, `${methodPath}.targetType`, "invalid-value", `"${String(method.targetType)}" is not a target type`, APPLICATION_METHOD_TARGET_TYPES);
14829
- }
14830
- if (method.allocation !== void 0 && !APPLICATION_METHOD_ALLOCATIONS.includes(method.allocation)) {
14831
- push(errors, `${methodPath}.allocation`, "invalid-value", `"${String(method.allocation)}" is not an allocation`, APPLICATION_METHOD_ALLOCATIONS);
14832
- }
14833
- for (const field2 of ["maxQuantity", "applyToQuantity", "buyRulesMinQuantity"]) {
14834
- const value = method[field2];
14835
- if (value !== void 0 && value !== null && (typeof value !== "number" || value < 1)) {
14836
- push(errors, `${methodPath}.${field2}`, "invalid-value", `${field2} is a positive integer when set`);
14837
- }
14838
- }
14839
- validateRuleList(errors, `${methodPath}.targetRules`, method.targetRules);
14840
- validateRuleList(errors, `${methodPath}.buyRules`, method.buyRules);
14841
- });
14842
- }
14843
- function validateHandleRef(errors, path, name) {
14844
- if (typeof name !== "string" || !name) {
14845
- push(errors, path, "invalid-value", "a code reference is a registered handle name (string)");
14846
- return;
14847
- }
14848
- if (!hasHandle(name)) {
14849
- push(errors, path, "unknown-handle", `handle "${name}" is not registered`, listHandles());
14850
- }
14851
- }
14852
- function validateCode(errors, section) {
14853
- for (const field2 of ["logo", "provider", "auth", "footerCredit"]) {
14854
- if (section[field2] !== void 0) validateHandleRef(errors, `code.${field2}`, section[field2]);
14855
- }
14856
- const components = section.components;
14857
- if (isRecord(components)) {
14858
- for (const [slot, handle] of Object.entries(components)) {
14859
- const slotPath = `code.components.${slot}`;
14860
- if (!STOREFRONT_COMPONENT_KEYS.includes(slot)) {
14861
- push(
14862
- errors,
14863
- slotPath,
14864
- "unknown-component-slot",
14865
- `"${slot}" is not an overridable storefront component`,
14866
- STOREFRONT_COMPONENT_KEYS
14867
- );
14868
- continue;
14869
- }
14870
- validateHandleRef(errors, slotPath, handle);
14871
- }
14872
- }
14873
- const routes = section.routes;
14874
- if (Array.isArray(routes)) {
14875
- routes.forEach((route, index) => {
14876
- const routePath = `code.routes[${index}]`;
14877
- if (!isRecord(route)) {
14878
- push(errors, routePath, "invalid-value", "a route is {id, path, kind?, chrome?, component}");
14879
- return;
14880
- }
14881
- for (const required of ["id", "path"]) {
14882
- if (typeof route[required] !== "string" || !route[required]) {
14883
- push(errors, `${routePath}.${required}`, "missing-field", `route requires a string "${required}"`);
14884
- }
14885
- }
14886
- for (const key of Object.keys(route)) {
14887
- if (!CODE_ROUTE_KEYS.includes(key)) {
14888
- push(errors, `${routePath}.${key}`, "unknown-field", `a route has no field "${key}"`, CODE_ROUTE_KEYS);
14889
- }
14890
- }
14891
- if (route.kind !== void 0 && !STORE_ROUTE_KINDS.includes(route.kind)) {
14892
- push(
14893
- errors,
14894
- `${routePath}.kind`,
14895
- "invalid-value",
14896
- `"${String(route.kind)}" is not a route kind`,
14897
- STORE_ROUTE_KINDS
14898
- );
14899
- }
14900
- if (route.chrome !== void 0 && !STORE_ROUTE_CHROMES.includes(route.chrome)) {
14901
- push(
14902
- errors,
14903
- `${routePath}.chrome`,
14904
- "invalid-value",
14905
- `"${String(route.chrome)}" is not a route chrome`,
14906
- STORE_ROUTE_CHROMES
14907
- );
14908
- }
14909
- validateHandleRef(errors, `${routePath}.component`, route.component);
14910
- });
14911
- }
14912
- }
14913
- function validateStore(doc) {
14914
- registerStorefrontBlocks();
14915
- const errors = [];
14916
- knownEntities = new Set(listEntityDeclarations());
14917
- if (isRecord(doc)) {
14918
- const entitiesSection = doc.entities;
14919
- if (isRecord(entitiesSection) && isRecord(entitiesSection.definitions)) {
14920
- for (const key of Object.keys(entitiesSection.definitions)) knownEntities.add(key);
14921
- }
14922
- }
14923
- if (!isRecord(doc)) {
14924
- push(errors, "", "invalid-document", `a store document is an object, got ${doc === null ? "null" : typeof doc}`);
14925
- return { ok: false, errors };
14926
- }
14927
- if (doc.$kind !== STORE_DOCUMENT_KIND) {
14928
- push(
14929
- errors,
14930
- "$kind",
14931
- "invalid-document",
14932
- `expected $kind "${STORE_DOCUMENT_KIND}", got ${JSON.stringify(doc.$kind)}`,
14933
- [STORE_DOCUMENT_KIND]
14934
- );
14935
- }
14936
- if (doc.store === void 0) {
14937
- push(errors, "store", "missing-section", 'the "store" section (name/currency/locale) is required', [
14938
- ...STORE_SECTION_NAMES
14939
- ]);
14940
- }
14941
- for (const [name, section] of Object.entries(doc)) {
14942
- if (name === "$kind") continue;
14943
- if (!STORE_SECTION_NAMES.includes(name)) {
14944
- push(errors, name, "unknown-section", `"${name}" is not a document section`, STORE_SECTION_NAMES);
14945
- continue;
14946
- }
14947
- if (!isRecord(section)) {
14948
- push(errors, name, "invalid-value", `section "${name}" must be an object with a version`);
14949
- continue;
14950
- }
14951
- const sectionName = name;
14952
- if (!validateSectionEnvelope(errors, sectionName, section)) continue;
14953
- if (sectionName === "theme") validateTheme(errors, section);
14954
- if (sectionName === "entities") validateEntitiesSection(errors, section);
14955
- if (sectionName === "promotions") validatePromotionsSection(errors, section);
14956
- if (sectionName === "commerce") validateCommerce(errors, section);
14957
- if (sectionName === "presentation") validatePresentation(errors, section);
14958
- if (sectionName === "code") validateCode(errors, section);
14959
- }
14960
- return { ok: errors.length === 0, errors };
14961
- }
14962
- function slugifyStoreName(name) {
14963
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "app";
14964
- }
14965
- function codeRef(value, configPath, handleSuffix, ctx) {
14966
- const existing = handleNameFor(value);
14967
- if (existing) return existing;
14968
- const name = `${ctx.appId}.${handleSuffix}`;
14969
- if (!ctx.autoRegister) {
14970
- throw new Error(
14971
- `exportStore: config.${configPath} holds code that is not a registered handle. Call registerHandle('${name}', value) before exporting, or export with { registerMissingHandles: true } (defineStorefront does).`
14972
- );
14973
- }
14974
- registerHandle(
14975
- name,
14976
- value,
14977
- { description: `Auto-registered from config.${configPath}`, source: "app" },
14978
- // The app re-declaring its config (module re-evaluation, HMR) re-derives
14979
- // the same name for a fresh value; replacing is the correct semantics.
14980
- { replace: true }
14981
- );
14982
- return name;
14983
- }
14984
- function findNonJsonPath(value, path) {
14985
- if (value === null || value === void 0) return null;
14986
- const t = typeof value;
14987
- if (t === "string" || t === "number" || t === "boolean") return null;
14988
- if (Array.isArray(value)) {
14989
- for (let i = 0; i < value.length; i++) {
14990
- const found = findNonJsonPath(value[i], `${path}[${i}]`);
14991
- if (found) return found;
14992
- }
14993
- return null;
14994
- }
14995
- if (t === "object") {
14996
- const record = value;
14997
- if ("$$typeof" in record) return path;
14998
- const proto = Object.getPrototypeOf(record);
14999
- if (proto !== Object.prototype && proto !== null) return path;
15000
- for (const [key, child] of Object.entries(record)) {
15001
- const found = findNonJsonPath(child, `${path}.${key}`);
15002
- if (found) return found;
15003
- }
15004
- return null;
15005
- }
15006
- return path;
15007
- }
15008
- function hasContent(section) {
15009
- return Object.keys(section).some((key) => key !== "version");
15010
- }
15011
- function exportStore(config, options = {}) {
15012
- const ctx = {
15013
- appId: options.appId ?? slugifyStoreName(config.name),
15014
- autoRegister: options.registerMissingHandles ?? false
15015
- };
15016
- const code = { version: 1 };
15017
- let presentationLogo;
15018
- if (config.logo !== void 0) {
15019
- if (typeof config.logo === "string") presentationLogo = config.logo;
15020
- else code.logo = codeRef(config.logo, "logo", "logo", ctx);
15021
- }
15022
- let footerData;
15023
- if (config.footer !== void 0) {
15024
- const { credit, ...rest } = config.footer;
15025
- if (credit === void 0 || typeof credit === "string") {
15026
- footerData = config.footer;
15027
- } else {
15028
- footerData = rest;
15029
- code.footerCredit = codeRef(credit, "footer.credit", "footer-credit", ctx);
15030
- }
15031
- }
15032
- let searchData;
15033
- if (config.search !== void 0) {
15034
- const { renderSuggestion, ...rest } = config.search;
15035
- searchData = rest;
15036
- if (renderSuggestion !== void 0) {
15037
- code.searchRenderSuggestion = codeRef(
15038
- renderSuggestion,
15039
- "search.renderSuggestion",
15040
- "search-render-suggestion",
15041
- ctx
15042
- );
15043
- }
15044
- }
15045
- let authData;
15046
- if (config.auth !== void 0) {
15047
- if (isJsonValue(config.auth)) authData = config.auth;
15048
- else code.auth = codeRef(config.auth, "auth", "auth", ctx);
15049
- }
15050
- if (config.provider !== void 0) {
15051
- code.provider = codeRef(config.provider, "provider", "provider", ctx);
15052
- }
15053
- if (config.components !== void 0) {
15054
- const componentRefs = {};
15055
- for (const [key, override] of Object.entries(config.components)) {
15056
- if (override === void 0) continue;
15057
- componentRefs[key] = codeRef(override, `components.${key}`, `components.${key}`, ctx);
15058
- }
15059
- if (Object.keys(componentRefs).length > 0) code.components = componentRefs;
15060
- }
15061
- if (config.routes !== void 0 && config.routes.length > 0) {
15062
- code.routes = config.routes.map(
15063
- (route) => compact({
15064
- id: route.id,
15065
- path: route.path,
15066
- kind: route.kind,
15067
- chrome: route.chrome,
15068
- component: codeRef(route.component, `routes[${route.id}].component`, `routes.${route.id}`, ctx)
15069
- })
15070
- );
15071
- }
15072
- const sections = {
15073
- store: compact({
15074
- version: 1,
15075
- name: config.name,
15076
- currency: config.currency,
15077
- locale: config.locale
15078
- }),
15079
- theme: config.theme ? { version: 1, ...compact(config.theme) } : { version: 1 },
15080
- commerce: compact({
15081
- version: 1,
15082
- commerceMode: config.commerceMode,
15083
- shipping: config.shipping,
15084
- payments: config.payments,
15085
- discounts: config.discounts,
15086
- enquiry: config.enquiry,
15087
- features: config.features
15088
- }),
15089
- presentation: compact({
15090
- version: 1,
15091
- announcement: config.announcement,
15092
- logo: presentationLogo,
15093
- home: config.home,
15094
- pages: config.pages,
15095
- slots: config.slots,
15096
- nav: config.nav,
15097
- footer: footerData,
15098
- imageLoading: config.imageLoading,
15099
- catalogFacets: config.catalogFacets,
15100
- productSpecs: config.productSpecs,
15101
- search: searchData
15102
- }),
15103
- content: compact({ version: 1, legal: config.legal, reviews: config.reviews }),
15104
- catalog: config.catalog ? { version: 1, ...compact(config.catalog) } : { version: 1 },
15105
- entities: config.entities ? { version: 1, definitions: config.entities } : { version: 1 },
15106
- promotions: config.promotions ? { version: 1, promotions: config.promotions } : { version: 1 },
15107
- backend: compact({
15108
- version: 1,
15109
- provider: config.backend?.provider,
15110
- url: config.backend?.url,
15111
- supabaseUrl: config.supabaseUrl,
15112
- supabaseAnonKey: config.supabaseAnonKey
15113
- }),
15114
- auth: authData ? { version: 1, ...compact(authData) } : { version: 1 },
15115
- code: compact(code)
15116
- };
15117
- const include = {
15118
- theme: config.theme !== void 0,
15119
- catalog: config.catalog !== void 0,
15120
- entities: config.entities !== void 0,
15121
- promotions: config.promotions !== void 0,
15122
- auth: authData !== void 0,
15123
- commerce: hasContent(sections.commerce),
15124
- presentation: hasContent(sections.presentation),
15125
- content: hasContent(sections.content),
15126
- backend: hasContent(sections.backend),
15127
- code: hasContent(sections.code)
15128
- };
15129
- const doc = { $kind: STORE_DOCUMENT_KIND, store: sections.store };
15130
- for (const name of ["theme", "commerce", "presentation", "content", "catalog", "entities", "promotions", "backend", "auth", "code"]) {
15131
- if (include[name]) doc[name] = sections[name];
15132
- }
15133
- for (const [name, section] of Object.entries(doc)) {
15134
- if (name === "$kind") continue;
15135
- const offending = findNonJsonPath(section, name);
15136
- if (offending) {
15137
- throw new Error(
15138
- `exportStore: ${offending} holds a non-serializable value. Code belongs in a registered handle (registerHandle) referenced from the document's code section \u2014 data sections must be pure JSON.`
15139
- );
15140
- }
15141
- }
15142
- return doc;
15143
- }
15144
- function formatErrors(errors) {
15145
- return errors.map((e) => ` - ${e.path || "(document)"}: ${e.message}${e.valid ? ` (valid: ${e.valid.join(", ")})` : ""}`).join("\n");
15146
- }
15147
- function hydrateStoreDocument(input, options = {}) {
15148
- const onError = options.onError ?? "throw";
15149
- const report = validateStore(input);
15150
- if (!report.ok) {
15151
- const message = `Store document failed validation:
15152
- ${formatErrors(report.errors)}`;
15153
- if (onError === "throw") throw new Error(message);
15154
- console.error(`[storefront] ${message}`);
15155
- }
15156
- const doc = input;
15157
- const resolve = (name, path) => {
15158
- try {
15159
- return resolveHandle(name);
15160
- } catch (err) {
15161
- if (onError === "throw") throw err;
15162
- console.error(`[storefront] dropping ${path}: ${errorMessage(err)}`);
15163
- return void 0;
15164
- }
15165
- };
15166
- const config = { name: doc.store?.name ?? "" };
15167
- const set = (key, value) => {
15168
- if (value !== void 0) config[key] = value;
15169
- };
15170
- set("currency", doc.store?.currency);
15171
- set("locale", doc.store?.locale);
15172
- if (doc.theme) {
15173
- const { version: _v, ...theme } = doc.theme;
15174
- set("theme", theme);
15175
- }
15176
- if (doc.commerce) {
15177
- set("commerceMode", doc.commerce.commerceMode);
15178
- set("shipping", doc.commerce.shipping);
15179
- set("payments", doc.commerce.payments);
15180
- set("discounts", doc.commerce.discounts);
15181
- set("enquiry", doc.commerce.enquiry);
15182
- set("features", doc.commerce.features);
15183
- }
15184
- if (doc.presentation) {
15185
- set("announcement", doc.presentation.announcement);
15186
- set("home", doc.presentation.home);
15187
- set("pages", doc.presentation.pages);
15188
- set("slots", doc.presentation.slots);
15189
- set("nav", doc.presentation.nav);
15190
- set("imageLoading", doc.presentation.imageLoading);
15191
- set("catalogFacets", doc.presentation.catalogFacets);
15192
- set("productSpecs", doc.presentation.productSpecs);
15193
- set("search", doc.presentation.search);
15194
- if (doc.presentation.logo !== void 0) set("logo", doc.presentation.logo);
15195
- }
15196
- if (doc.content) {
15197
- set("legal", doc.content.legal);
15198
- set("reviews", doc.content.reviews);
15199
- }
15200
- if (doc.catalog) {
15201
- const { version: _v, ...seed } = doc.catalog;
15202
- set("catalog", seed);
15203
- }
15204
- if (doc.entities?.definitions) set("entities", doc.entities.definitions);
15205
- if (doc.promotions?.promotions) set("promotions", doc.promotions.promotions);
15206
- if (doc.backend) {
15207
- const { provider, url, supabaseUrl, supabaseAnonKey } = doc.backend;
15208
- if (provider !== void 0 || url !== void 0) set("backend", compact({ provider, url }));
15209
- set("supabaseUrl", supabaseUrl);
15210
- set("supabaseAnonKey", supabaseAnonKey);
15211
- }
15212
- if (doc.auth) {
15213
- const { version: _v, ...auth } = doc.auth;
15214
- set("auth", auth);
15215
- }
15216
- const code = doc.code;
15217
- if (code) {
15218
- if (code.logo) set("logo", resolve(code.logo, "code.logo"));
15219
- if (code.provider) set("provider", resolve(code.provider, "code.provider"));
15220
- if (code.auth) set("auth", resolve(code.auth, "code.auth"));
15221
- if (code.components) {
15222
- const components = {};
15223
- for (const [key, handle] of Object.entries(code.components)) {
15224
- const value = resolve(handle, `code.components.${key}`);
15225
- if (value !== void 0) components[key] = value;
15226
- }
15227
- if (Object.keys(components).length > 0) set("components", components);
15228
- }
15229
- if (code.routes) {
15230
- const routes = [];
15231
- for (const route of code.routes) {
15232
- const component = resolve(
15233
- route.component,
15234
- `code.routes[${route.id}].component`
15235
- );
15236
- if (component === void 0) continue;
15237
- routes.push(
15238
- compact({
15239
- id: route.id,
15240
- path: route.path,
15241
- kind: route.kind,
15242
- chrome: route.chrome,
15243
- component
15244
- })
15245
- );
15246
- }
15247
- if (routes.length > 0) set("routes", routes);
15248
- }
15249
- if (code.searchRenderSuggestion) {
15250
- const renderSuggestion = resolve(
15251
- code.searchRenderSuggestion,
15252
- "code.searchRenderSuggestion"
15253
- );
15254
- if (renderSuggestion !== void 0) {
15255
- set("search", { ...doc.presentation?.search ?? {}, renderSuggestion });
15256
- }
15257
- }
15258
- if (code.footerCredit) {
15259
- const credit = resolve(code.footerCredit, "code.footerCredit");
15260
- if (credit !== void 0) {
15261
- set("footer", { ...doc.presentation?.footer ?? {}, credit });
15262
- }
15263
- }
15264
- }
15265
- if (config.footer === void 0 && doc.presentation?.footer !== void 0) {
15266
- set("footer", doc.presentation.footer);
15267
- }
15268
- return config;
15269
- }
15270
-
15271
- export { AddressForm, AddressSheet, AddressStrip, BEFORE_PLACE_ORDER_VALVE, BLOCK_STRUCTURAL_KEYS, BUYER_COUNTRY_COOKIE, BenefitsRow, BlockDataError, CART_LINE_ANNOTATION_POINT, CATALOG_BODY_BLOCK, CHECKOUT_FIELD_POINT, CartDrawer, CatalogPage, CategoryShowcase, CheckoutPage, ClosedStoreDialog, CollectionCta, CollectionHero, ContentPage, CountdownBand, CountrySelect, DeliverToPicker, EmailConfirmationRequiredError, EntityListBlock, FaqSection, FiltersPanel, FormBlock, HeroSection, ImageTiles, ItemSheet, Link, MESSAGES, ManifestoBlock, MediaCarousel, MenuItemRow, MenuPage, MenuToolbar, MotifStrip, MyPurchasesPage, NewsletterBand, ORDER_METADATA_POINT, OrderConfirmationPage, OrderTrackingTimeline, PAGE_DATA_SCRIPT_ID, PLACEHOLDER_ASPECTS, PRODUCT_BODY_BLOCK, PRODUCT_CARD_BADGE_POINT, PageDataScope, PaymentTerms, Price, ProductCard, ProductDetailPage, ProductEnquiryForm, ProductGallery, ProductGrid, ProductOptionSelector, ProductRail, ProductReviews, ProductSlider, ProductSpecs, ProductSpotlight, PromoBanner, QuantityInput, Reveal, STOREFRONT_COMPONENT_KEYS, STOREFRONT_PAGE_KINDS, STOREFRONT_SLOTS, STORE_BACKEND_PROVIDERS, STORE_COMMERCE_MODES, STORE_DOCUMENT_KIND, STORE_PAYMENT_METHOD_KINDS, STORE_PAYMENT_MODES, STORE_ROUTE_CHROMES, STORE_ROUTE_KINDS, STORE_SECTIONS, STORE_SECTION_NAMES, ScheduleSheet, SealsBand, SearchOverlay, ServiceHoursModal, Slot, SmoothImage, StepsSection, StoreCover, StorefrontAnalytics, StorefrontConfigHost, StorefrontConfigProvider, StorefrontFooter, StorefrontHeader, StorefrontPage, StorefrontRouterProvider, StorefrontShell, StorefrontThemeStyle, StoryQuote, THEME_SCALE_FIELDS, THEME_SCALE_VAR_PREFIX, TID, Testimonials, TierCards, applyDeliveryPolicy, applyStoreSettings, bannerPlaceholder, blockInstanceId, buildEnquiryFromForm, checkPageBlocks, collectDataNeeds, collectOrderMetadata, contentPagePath, createStorefront, createStorefrontApp, currentStaticRenderPass, defaultPageBlocks, entityListBlockMeta, establishCustomerSession, exportStore, formatMoney, formatProductOptionSelection, getCartLineAnnotations, getCheckoutFieldContributions, getCustomerAuthAdapter, getProductCardBadges, getProductOptionGroups, hydrateStoreDocument, hydratedEntriesFor, identifyStorefrontBuyer, initStorefrontRuntime, isJsonValue, isKnownPath, isNestedBlockRef, isPublicPath, isRecord, listSlots, marketForCountry, marketUnitPrice, matchContentPage, matchPath, matchesFacets, menuDataNeeds, menuJsonLd, menuSeo, mergeCollectionFacet, mergePageTheme, navigateTo, nextMilestone, normalizeLanguage, normalizeProductOptionSelection, onStorefrontEvent, orderGalleryImages, overrideComponent, overrideProps, pageSeo, pageThemeSelector, pickProductCardImage, placeStorefrontOrder, prefersReducedMotion, primaryImageUrl, productCardComponentContract, productJsonLd, productOptionSelectionKey, productPlaceholder, productSeo, readHydratedPageData, registerStorefrontBlocks, registerStorefrontEntities, registerStorefrontExtensionPoints, registerStorefrontLoaders, resetPageDiagnostics, resetProductOptionsDeprecationWarnings, resetStorefrontExtensionPoints, resolveAuthAdapter, resolveConfig, resolveDataParams, resolveOverride, resolvePageData, resolvePageDataNeed, resolvePaymentTerms, resolveStorefrontProvider, resolveStorefrontRoute, resolveVariantForSelection, roundCents, routePathParams, runBeforePlaceOrderValve, sectionToJsonSchema, sectionsToBlocks, selectCount, selectDiscountTotal, selectIsOpen, selectRequiresShipping, selectShipping, selectShowsHours, selectSubtotal, selectTotal, selectionPrice, serializePageData, shellRouterAdapter, signInByEmail, signOutCustomer, signUpCustomer, slugifyStoreName, startStorefrontPostHog, storeBuyerId, storefrontComponentContracts, storefrontPaths, themeToCss, toBlockNodes, toFacetMap, trackStorefront, translate, useBlockData, useBuyerCountry, useBuyerStore, useCartStore, useCatalogStore, useCategories, useDeliveryStore, useDiscountValidator, useEnquiry, useHashPath, useInView, useLoader, useMarketProduct, useMarketStore, useMyOrders, useNavigate, usePopOnChange, useProduct, useProducts, useRoutePath, useRouterAdapter, useScrollToTopOnNavigate, useScrolled, useServiceStore, useSessionStore, useSlotContext, useStorefrontActions, useStorefrontConfig, useStorefrontConfigOptional, useStorefrontHead, useStorefrontPage, useStorefrontPageOptional, useT, usedSlots, validateStore, withFacet, withMarketPrice, withStaticRenderPass };
15272
- //# sourceMappingURL=chunk-V7CGLOEN.js.map
15273
- //# sourceMappingURL=chunk-V7CGLOEN.js.map
12769
+ export { AddressForm, AddressSheet, AddressStrip, BEFORE_PLACE_ORDER_VALVE, BUYER_COUNTRY_COOKIE, BenefitsRow, CART_LINE_ANNOTATION_POINT, CHECKOUT_FIELD_POINT, CartDrawer, CatalogPage, CategoryShowcase, CheckoutPage, ClosedStoreDialog, CollectionCta, CollectionHero, ContentPage, CountdownBand, CountrySelect, DeliverToPicker, EmailConfirmationRequiredError, EntityListBlock, FaqSection, FiltersPanel, FormBlock, HeroSection, ImageTiles, ItemSheet, ManifestoBlock, MediaCarousel, MenuItemRow, MenuPage, MenuToolbar, MotifStrip, MyPurchasesPage, NewsletterBand, ORDER_METADATA_POINT, OrderConfirmationPage, OrderTrackingTimeline, PAGE_DATA_SCRIPT_ID, PLACEHOLDER_ASPECTS, PRODUCT_CARD_BADGE_POINT, PaymentTerms, Price, ProductCard, ProductDetailPage, ProductEnquiryForm, ProductGallery, ProductGrid, ProductOptionSelector, ProductRail, ProductReviews, ProductSlider, ProductSpecs, ProductSpotlight, PromoBanner, QuantityInput, Reveal, STOREFRONT_SLOTS, ScheduleSheet, SealsBand, SearchOverlay, ServiceHoursModal, Slot, SmoothImage, StepsSection, StoreCover, StorefrontAnalytics, StorefrontConfigHost, StorefrontFooter, StorefrontHeader, StorefrontPage, StorefrontShell, StorefrontThemeStyle, StoryQuote, THEME_SCALE_FIELDS, THEME_SCALE_VAR_PREFIX, TID, Testimonials, TierCards, applyDeliveryPolicy, applyStoreSettings, bannerPlaceholder, buildEnquiryFromForm, collectOrderMetadata, createStorefront, createStorefrontApp, entityListBlockMeta, establishCustomerSession, formatMoney, formatProductOptionSelection, getCartLineAnnotations, getCheckoutFieldContributions, getCustomerAuthAdapter, getProductCardBadges, getProductOptionGroups, hydratedEntriesFor, identifyStorefrontBuyer, initStorefrontRuntime, listSlots, marketForCountry, marketUnitPrice, matchesFacets, mergeCollectionFacet, nextMilestone, normalizeProductOptionSelection, onStorefrontEvent, orderGalleryImages, overrideComponent, overrideProps, pickProductCardImage, placeStorefrontOrder, prefersReducedMotion, productCardComponentContract, productOptionSelectionKey, productPlaceholder, readHydratedPageData, registerStorefrontBlocks, registerStorefrontEntities, registerStorefrontExtensionPoints, registerStorefrontLoaders, resetPageDiagnostics, resetProductOptionsDeprecationWarnings, resetStorefrontExtensionPoints, resolveAuthAdapter, resolveOverride, resolvePaymentTerms, resolveStorefrontProvider, resolveVariantForSelection, roundCents, runBeforePlaceOrderValve, sectionsToBlocks, selectCount, selectDiscountTotal, selectIsOpen, selectRequiresShipping, selectShipping, selectShowsHours, selectSubtotal, selectTotal, selectionPrice, serializePageData, signInByEmail, signOutCustomer, signUpCustomer, startStorefrontPostHog, storeBuyerId, storefrontComponentContracts, themeToCss, toFacetMap, trackStorefront, useBuyerCountry, useBuyerStore, useCartStore, useCatalogStore, useCategories, useDeliveryStore, useDiscountValidator, useEnquiry, useInView, useMarketProduct, useMarketStore, useMyOrders, usePopOnChange, useProduct, useProducts, useScrolled, useServiceStore, useSessionStore, useSlotContext, useStorefrontActions, useStorefrontHead, useStorefrontPage, useStorefrontPageOptional, useT, usedSlots, withFacet, withMarketPrice };
12770
+ //# sourceMappingURL=chunk-CWHGBPRP.js.map
12771
+ //# sourceMappingURL=chunk-CWHGBPRP.js.map